309 lines
8 KiB
GDScript
309 lines
8 KiB
GDScript
class_name NewGameSetupPage
|
|
extends Control
|
|
|
|
signal start_requested(world_layout: StringName, world_seed: int)
|
|
signal back_requested
|
|
|
|
const WorldLayoutType = preload("res://world/world_layout.gd")
|
|
const SaveManagerType = preload("res://save/player_save_manager.gd")
|
|
const ControllerFocusNavigationType = preload(
|
|
"res://ui/controller_focus_navigation.gd"
|
|
)
|
|
|
|
enum SeedMode {
|
|
RANDOM,
|
|
CUSTOM,
|
|
}
|
|
|
|
@onready var _paper: PanelContainer = %Paper
|
|
@onready var _generated_button: Button = %GeneratedButton
|
|
@onready var _starter_button: Button = %StarterButton
|
|
@onready var _world_description: Label = %WorldDescription
|
|
@onready var _seed_section: VBoxContainer = %SeedSection
|
|
@onready var _random_seed_button: Button = %RandomSeedButton
|
|
@onready var _custom_seed_button: Button = %CustomSeedButton
|
|
@onready var _seed_edit: LineEdit = %SeedEdit
|
|
@onready var _seed_help: Label = %SeedHelp
|
|
@onready var _overwrite_warning: Label = %OverwriteWarning
|
|
@onready var _status: Label = %Status
|
|
@onready var _start_button: Button = %StartButton
|
|
@onready var _back_button: Button = %BackButton
|
|
|
|
var _world_layout: StringName = WorldLayoutType.GENERATED
|
|
var _seed_mode: SeedMode = SeedMode.RANDOM
|
|
var _random_seed: int = SaveManagerType.DEFAULT_WORLD_SEED
|
|
|
|
|
|
func _ready() -> void:
|
|
UtilityPageStyle.apply_page(self)
|
|
_paper.add_theme_stylebox_override(
|
|
"panel", UtilityPageStyle.panel_style()
|
|
)
|
|
for button: Button in [
|
|
_generated_button,
|
|
_starter_button,
|
|
_random_seed_button,
|
|
_custom_seed_button,
|
|
_start_button,
|
|
_back_button,
|
|
]:
|
|
UtilityPageStyle.apply_ocean_button(button)
|
|
UtilityPageStyle.apply_ocean_line_edit(_seed_edit)
|
|
_generated_button.pressed.connect(
|
|
_set_world_layout.bind(WorldLayoutType.GENERATED)
|
|
)
|
|
_starter_button.pressed.connect(
|
|
_set_world_layout.bind(WorldLayoutType.STARTER_ISLAND)
|
|
)
|
|
_random_seed_button.pressed.connect(_choose_random_seed)
|
|
_custom_seed_button.pressed.connect(_choose_custom_seed)
|
|
_seed_edit.text_changed.connect(_on_seed_text_changed)
|
|
_seed_edit.text_submitted.connect(_on_seed_submitted)
|
|
_start_button.pressed.connect(_request_start)
|
|
_back_button.pressed.connect(back_requested.emit)
|
|
hide()
|
|
|
|
|
|
func open_page(has_existing_progression: bool) -> void:
|
|
_world_layout = WorldLayoutType.GENERATED
|
|
_seed_mode = SeedMode.RANDOM
|
|
_roll_random_seed()
|
|
_overwrite_warning.visible = has_existing_progression
|
|
_status.text = ""
|
|
_refresh_presentation()
|
|
show()
|
|
UtilityPageStyle.animate_in(self)
|
|
_generated_button.grab_focus.call_deferred()
|
|
|
|
|
|
func close_page() -> void:
|
|
var focus_owner: Control = get_viewport().gui_get_focus_owner()
|
|
if focus_owner != null and is_ancestor_of(focus_owner):
|
|
focus_owner.release_focus()
|
|
hide()
|
|
|
|
|
|
func request_back() -> void:
|
|
back_requested.emit()
|
|
|
|
|
|
func get_selected_world_layout() -> StringName:
|
|
return _world_layout
|
|
|
|
|
|
func get_selected_world_seed() -> int:
|
|
return (
|
|
_random_seed
|
|
if _seed_mode == SeedMode.RANDOM
|
|
else parse_seed_text(_seed_edit.text)
|
|
)
|
|
|
|
|
|
static func parse_seed_text(text: String) -> int:
|
|
var normalized: String = text.strip_edges()
|
|
if normalized.is_empty():
|
|
return 0
|
|
if normalized.is_valid_int():
|
|
var numeric_seed: int = int(normalized)
|
|
if (
|
|
numeric_seed <= 0
|
|
or numeric_seed > SaveManagerType.MAX_WORLD_SEED
|
|
):
|
|
return 0
|
|
return numeric_seed
|
|
var digest: PackedByteArray = normalized.sha256_buffer()
|
|
var hashed_seed: int = (
|
|
(int(digest[0]) << 24)
|
|
| (int(digest[1]) << 16)
|
|
| (int(digest[2]) << 8)
|
|
| int(digest[3])
|
|
) & 0x7fffffff
|
|
return (hashed_seed % SaveManagerType.MAX_WORLD_SEED) + 1
|
|
|
|
|
|
func _set_world_layout(layout: StringName) -> void:
|
|
if not WorldLayoutType.is_valid(layout):
|
|
return
|
|
_world_layout = layout
|
|
_status.text = ""
|
|
_refresh_presentation()
|
|
if layout == WorldLayoutType.GENERATED:
|
|
_random_seed_button.grab_focus.call_deferred()
|
|
else:
|
|
_start_button.grab_focus.call_deferred()
|
|
|
|
|
|
func _choose_random_seed() -> void:
|
|
_seed_mode = SeedMode.RANDOM
|
|
_roll_random_seed()
|
|
_status.text = ""
|
|
_refresh_presentation()
|
|
|
|
|
|
func _choose_custom_seed() -> void:
|
|
_seed_mode = SeedMode.CUSTOM
|
|
if parse_seed_text(_seed_edit.text) == _random_seed:
|
|
_seed_edit.text = ""
|
|
_status.text = ""
|
|
_refresh_presentation()
|
|
_seed_edit.grab_focus.call_deferred()
|
|
_seed_edit.select_all.call_deferred()
|
|
|
|
|
|
func _roll_random_seed() -> void:
|
|
_random_seed = SaveManagerType.roll_world_seed()
|
|
_seed_edit.text = str(_random_seed)
|
|
|
|
|
|
func _on_seed_text_changed(_text: String) -> void:
|
|
if _seed_mode != SeedMode.CUSTOM:
|
|
return
|
|
_status.text = ""
|
|
_refresh_start_state()
|
|
|
|
|
|
func _on_seed_submitted(_text: String) -> void:
|
|
_request_start()
|
|
|
|
|
|
func _request_start() -> void:
|
|
var seed: int = get_selected_world_seed()
|
|
if _world_layout == WorldLayoutType.GENERATED and seed == 0:
|
|
_status.text = (
|
|
"enter some text or a whole number from 1 to %d."
|
|
% SaveManagerType.MAX_WORLD_SEED
|
|
)
|
|
_seed_edit.grab_focus()
|
|
_seed_edit.select_all()
|
|
return
|
|
if seed == 0:
|
|
seed = SaveManagerType.roll_world_seed()
|
|
_start_button.disabled = true
|
|
start_requested.emit(_world_layout, seed)
|
|
|
|
|
|
func _refresh_presentation() -> void:
|
|
var generated: bool = _world_layout == WorldLayoutType.GENERATED
|
|
_generated_button.set_pressed_no_signal(generated)
|
|
_starter_button.set_pressed_no_signal(not generated)
|
|
_world_description.text = (
|
|
"build a new island from terrain chunks.\n"
|
|
+ "the same seed always builds the same world."
|
|
if generated
|
|
else "play on the starter island."
|
|
)
|
|
_seed_section.visible = generated
|
|
_random_seed_button.set_pressed_no_signal(
|
|
_seed_mode == SeedMode.RANDOM
|
|
)
|
|
_custom_seed_button.set_pressed_no_signal(
|
|
_seed_mode == SeedMode.CUSTOM
|
|
)
|
|
_seed_edit.editable = _seed_mode == SeedMode.CUSTOM
|
|
_seed_edit.focus_mode = (
|
|
Control.FOCUS_ALL
|
|
if _seed_mode == SeedMode.CUSTOM
|
|
else Control.FOCUS_NONE
|
|
)
|
|
_seed_help.text = (
|
|
"press random seed again to roll another world."
|
|
if _seed_mode == SeedMode.RANDOM
|
|
else "enter text or a number from 1 to %d. the same entry makes the same world."
|
|
% SaveManagerType.MAX_WORLD_SEED
|
|
)
|
|
_refresh_start_state()
|
|
_configure_controller_focus()
|
|
|
|
|
|
func _refresh_start_state() -> void:
|
|
_start_button.disabled = (
|
|
_world_layout == WorldLayoutType.GENERATED
|
|
and _seed_mode == SeedMode.CUSTOM
|
|
and parse_seed_text(_seed_edit.text) == 0
|
|
)
|
|
|
|
|
|
func _configure_controller_focus() -> void:
|
|
var generated: bool = _world_layout == WorldLayoutType.GENERATED
|
|
var custom: bool = generated and _seed_mode == SeedMode.CUSTOM
|
|
_set_neighbors(
|
|
_generated_button,
|
|
_generated_button,
|
|
_starter_button,
|
|
_generated_button,
|
|
_random_seed_button if generated else _start_button,
|
|
)
|
|
_set_neighbors(
|
|
_starter_button,
|
|
_generated_button,
|
|
_starter_button,
|
|
_starter_button,
|
|
_custom_seed_button if generated else _back_button,
|
|
)
|
|
_set_neighbors(
|
|
_random_seed_button,
|
|
_random_seed_button,
|
|
_custom_seed_button,
|
|
_generated_button,
|
|
_seed_edit if custom else _start_button,
|
|
)
|
|
_set_neighbors(
|
|
_custom_seed_button,
|
|
_random_seed_button,
|
|
_custom_seed_button,
|
|
_starter_button,
|
|
_seed_edit if custom else _back_button,
|
|
)
|
|
_set_neighbors(
|
|
_seed_edit,
|
|
_seed_edit,
|
|
_seed_edit,
|
|
_custom_seed_button,
|
|
_start_button,
|
|
)
|
|
var action_top: Control = (
|
|
_seed_edit
|
|
if custom
|
|
else _random_seed_button
|
|
if generated
|
|
else _generated_button
|
|
)
|
|
_set_neighbors(
|
|
_start_button,
|
|
_start_button,
|
|
_back_button,
|
|
action_top,
|
|
_start_button,
|
|
)
|
|
_set_neighbors(
|
|
_back_button,
|
|
_start_button,
|
|
_back_button,
|
|
action_top,
|
|
_back_button,
|
|
)
|
|
var traversal: Array[Control] = [
|
|
_generated_button,
|
|
_starter_button,
|
|
]
|
|
if generated:
|
|
traversal.append(_random_seed_button)
|
|
traversal.append(_custom_seed_button)
|
|
if custom:
|
|
traversal.append(_seed_edit)
|
|
traversal.append(_start_button)
|
|
traversal.append(_back_button)
|
|
ControllerFocusNavigationType.configure_traversal(traversal)
|
|
|
|
|
|
func _set_neighbors(
|
|
control: Control,
|
|
left: Control,
|
|
right: Control,
|
|
top: Control,
|
|
bottom: Control,
|
|
) -> void:
|
|
control.focus_neighbor_left = control.get_path_to(left)
|
|
control.focus_neighbor_right = control.get_path_to(right)
|
|
control.focus_neighbor_top = control.get_path_to(top)
|
|
control.focus_neighbor_bottom = control.get_path_to(bottom)
|