Add the planet setup map editor (#48)

PlanetSetupEditor authors PlanetSetup resources: pick a surface
profile (drives the real lunar_surface background, not a blank
sheet), place/move/delete capture points and enemies from a palette
generated straight off EnemyDefinitions.all() (a new enemy definition
shows up with no editor change), pan/pinch-zoom the canvas with the
same touch idiom as GameController, then save to
res://PlanetSetups/<id>.tres via ResourceSaver - reachable now from
the main menu's Map Editor button. The mutation methods
(new_setup/load_setup/add_*/move_*/remove_*/save_setup) are the whole
model and work standalone, which is what lets
tests/test_setup_editor.gd drive placement/move/delete/save/reload
directly without simulating touch input.

Every cross-file reference is a preloaded script const rather than a
bare global class name, matching #42/#44's load-order notes - this
file is instantiated from other scripts' function bodies, never as a
script-mode test entry point itself, so it wasn't at risk the same way
the test files were, but the pattern is kept consistent throughout.

Part of the #40 conquest-mechanic breakdown. This closes out the
breakdown: #41-#48 are now all implemented, tested, and merged.
This commit is contained in:
Loïc Wisniewski 2026-08-15 21:24:28 +02:00
commit df2f252970
12 changed files with 876 additions and 15 deletions

View file

@ -3,8 +3,8 @@ extends SceneTree
# Headless gameplay test: run with
# godot --headless -s res://tests/test_main_menu.gd
# Verifies:
# 1. the menu loads with Play/Map Editor/Quit, the editor button starts
# disabled and explains itself instead of silently doing nothing
# 1. the menu loads with Play/Map Editor/Quit; Map Editor is enabled and
# reaches PlanetSetupEditor.tscn (#48)
# 2. Quit's visibility follows OS.has_feature("web") (this platform is
# not a web export, so this run exercises the "visible" branch; the
# condition itself is what's under test, not the concrete boolean)
@ -33,8 +33,8 @@ func _process(delta: float) -> bool:
# frame has actually processed.
if elapsed < 0.1:
return false
if menu.editor_button.enabled:
return _fail("map editor button is not disabled ahead of #48")
if not menu.editor_button.enabled:
return _fail("map editor button is not enabled (#48 shipped)")
if menu.quit_button.visible != (not OS.has_feature("web")):
return _fail("quit button visibility did not follow OS.has_feature('web')")
@ -43,13 +43,22 @@ func _process(delta: float) -> bool:
stage = 1
return false
1:
if elapsed < 0.2:
return false
var on_editor: bool = current_scene != null and current_scene.name == "PlanetSetupEditor"
if not on_editor:
return _fail("pressing Map Editor did not reach PlanetSetupEditor.tscn")
# Return to the menu the same way the player would, then test Play.
menu = load("res://MainMenu.tscn").instantiate()
root.add_child(menu)
current_scene = menu
elapsed = 0.0
stage = 2
return false
2:
if elapsed < 0.1:
return false
if "coming soon" not in menu.status_label.text.to_lower():
return _fail("disabled editor button press did not explain itself")
if current_scene != menu:
return _fail("pressing the disabled editor button changed scenes")
# Dirty the game state exactly like an in-progress run would,
# so a genuine reset is distinguishable from a coincidental match.
game_state.bank_inventory.set_amount(GameState.RESOURCE_ORE, 999)
@ -59,9 +68,9 @@ func _process(delta: float) -> bool:
_press(menu.play_button)
elapsed = 0.0
stage = 2
stage = 3
return false
2:
3:
if elapsed < 0.3:
return false
var on_main: bool = current_scene != null and current_scene.name == "Main"