From fe1c721d64852f5dc4a0215a7639865fa244f052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Wisniewski?= Date: Tue, 11 Aug 2026 23:55:12 +0200 Subject: [PATCH] Restore the crafter binding lost in an over-wide edit This is the actual cause of "the build a ship menu buttons do nothing", reported four times. Opening the crafter panel stopped recording WHICH crafter: when the auto-unload was replaced with an explicit store button, the replaced block reached one line further up than intended and took `craft_building_id = current_building.building_id` with it. Every handler in the panel then bailed out at its `if craft_building_id == 0` guard, while the panel itself still opened and Close still worked - because Close is the only button that does not need the binding. The silent `return` on that guard is what let it pass unnoticed, so it now says so instead. The test was complicit: it set craft_building_id by hand, which skipped the exact step that was broken. It now parks the fleet on the crafter, waits for the action button to debounce in, and presses it - the way the game does. Verified against the broken code: it fails with "opening the panel did not record which crafter". Co-Authored-By: Claude Opus 5 --- BuildController.gd | 10 ++++++++ tests/test_crafter_feedback.gd | 46 +++++++++++++++++++++++++++++++--- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/BuildController.gd b/BuildController.gd index aba4f36..8ac9ed7 100644 --- a/BuildController.gd +++ b/BuildController.gd @@ -297,6 +297,12 @@ func _on_action_pressed() -> void: _refresh_load_ore() _refresh_skill_menu() elif current_building.building_type == GameState.BUILDING_SHIP_CRAFTER: + # Remembered explicitly: _process() clears current_building while any + # menu is open, so by the next frame the panel would no longer know + # which crafter it belongs to. Losing this line makes every button in + # the panel bail out at its `== 0` guard while the panel itself still + # opens - which reads as "the buttons do nothing". + craft_building_id = current_building.building_id craft_menu.visible = true _refresh_craft_status() elif current_building.building_type == GameState.BUILDING_SHIP_LAB: @@ -640,6 +646,7 @@ func _refresh_craft_status() -> void: func _on_craft_interceptor() -> void: if craft_building_id == 0: + _say("No crafter selected - reopen this panel from the building") return # Still refused when there is nowhere to put the vessel - queueing an # order that can never be delivered would just bank vessels_owed forever. @@ -679,6 +686,7 @@ func _report_order(product: String) -> void: func _on_store_ore() -> void: if craft_building_id == 0: + _say("No crafter selected - reopen this panel from the building") return if GameState.fleet_cargo <= 0: _say("The fleet is carrying nothing - load ore at the mothership first") @@ -689,6 +697,7 @@ func _on_store_ore() -> void: func _on_craft_transporter() -> void: if craft_building_id == 0: + _say("No crafter selected - reopen this panel from the building") return if not GameState.queue_order(craft_building_id, GameState.PRODUCT_TRANSPORTER): # Two different refusals, and the player needs to know WHICH. @@ -801,6 +810,7 @@ func _refresh_lab() -> void: func _on_craft_shield() -> void: if craft_building_id == 0: + _say("No crafter selected - reopen this panel from the building") return if not GameState.shield_vessel_unlocked(): _say("Shield vessels must be unlocked at a ship lab first") diff --git a/tests/test_crafter_feedback.gd b/tests/test_crafter_feedback.gd index dad13d2..87f7d0b 100644 --- a/tests/test_crafter_feedback.gd +++ b/tests/test_crafter_feedback.gd @@ -20,11 +20,20 @@ extends SceneTree # overwritten on the very next frame, which is what made a working # button look dead # 5. the message is the FIRST line, not buried under the standing state +# 6. the panel is opened the way the GAME opens it - park the fleet on the +# crafter and press the action button - and every button then works +# +# Point 6 exists because this test used to set craft_building_id by hand. +# That skipped the one step that was actually broken: opening the panel +# stopped recording WHICH crafter, so every handler bailed out at its `== 0` +# guard while the panel still opened. Reported four times as "the buttons do +# nothing", and invisible to every test that set the id itself. var game_state: Node var scene: Node var controller: Node var crafter_id: int = 0 +var fleet: Node var stage: int = 0 var elapsed: float = 0.0 @@ -42,6 +51,15 @@ func _initialize() -> void: scene = load("res://Main.tscn").instantiate() root.add_child(scene) controller = scene.get_node("BuildController") + fleet = scene.get_node("Fleet") + + +func _tap(button: Control) -> void: + for pressed in [true, false]: + var ev: InputEventScreenTouch = InputEventScreenTouch.new() + ev.pressed = pressed + ev.position = button.size / 2.0 + button._gui_input(ev) func _first_line() -> String: @@ -54,17 +72,37 @@ func _process(delta: float) -> bool: 0: scene.get_node("AsteroidField").set_process(false) scene.get_node("EnemySpawner").set_process(false) + for a in get_nodes_in_group("asteroids"): + if is_instance_valid(a): + a.queue_free() scene.get_node("BuildingField").place(GameState.BUILDING_SHIP_CRAFTER, Vector2(500.0, 0.0)) crafter_id = int(game_state.buildings[-1].id) + # Park the fleet ON it and let the action button debounce in. + for ship in fleet.ships: + ship.position = Vector2(500.0, 0.0) + fleet.move_to(Vector2(500.0, 0.0)) elapsed = 0.0 stage = 1 return false 1: - if elapsed < 0.3: + if elapsed < 1.2: return false - controller.craft_building_id = crafter_id - controller.craft_menu.visible = true - controller._refresh_craft_status() + # --- 6. open it the way the game does ------------------------ + if controller.current_building == null: + print("TEST_CRAFTER_FEEDBACK: FAIL (fleet parked on the crafter never registered)") + quit(1) + return true + _tap(controller.action_button) + if not controller.craft_menu.visible: + print("TEST_CRAFTER_FEEDBACK: FAIL (the action button did not open the crafter panel)") + quit(1) + return true + if controller.craft_building_id != crafter_id: + print("craft_building_id=%d, crafter is %d" % [controller.craft_building_id, crafter_id]) + print("TEST_CRAFTER_FEEDBACK: FAIL (opening the panel did not record which crafter - every button will bail out)") + quit(1) + return true + print("panel opened from the building, bound to crafter %d" % controller.craft_building_id) # --- 1. store with an empty hold ---------------------------- controller._on_store_ore()