From 4c82155cf3280f85c0416f8e4bb7dd84f357e560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Wisniewski?= Date: Thu, 13 Aug 2026 22:17:24 +0200 Subject: [PATCH] Support gas cargo transfers --- BuildController.gd | 13 +++++++++++++ GameState.gd | 27 +++++++++++++++++++++++++++ GasVentField.gd | 2 +- IconButton.gd | 12 ++++++++++++ Main.tscn | 32 ++++++++++++++++++++++++++++++++ ResourceBar.gd | 2 +- tests/test_gas_system.gd | 5 +++++ 7 files changed, 91 insertions(+), 2 deletions(-) diff --git a/BuildController.gd b/BuildController.gd index 8e7bc3d..a317240 100644 --- a/BuildController.gd +++ b/BuildController.gd @@ -133,6 +133,8 @@ var lab_building_id: int = 0 @onready var to_fleet_batch_button: IconButton = get_node("../UI/TransferMenu/ToFleetBatchButton") @onready var to_fleet_batch_label: Label = get_node("../UI/TransferMenu/ToFleetBatchLabel") @onready var to_fleet_all_button: IconButton = get_node("../UI/TransferMenu/ToFleetAllButton") +@onready var gas_to_building_button: IconButton = get_node("../UI/TransferMenu/GasToBuildingButton") +@onready var gas_to_fleet_button: IconButton = get_node("../UI/TransferMenu/GasToFleetButton") # Every building menu carries the same header (#24). Held as a list because # the only thing any of them needs is to be told which building it is @@ -253,6 +255,8 @@ func _ready() -> void: to_building_all_button.pressed.connect(_on_transfer.bind(true, ALL)) to_fleet_batch_button.pressed.connect(_on_transfer.bind(false, GameState.CARGO_LOAD_BATCH)) to_fleet_all_button.pressed.connect(_on_transfer.bind(false, ALL)) + gas_to_building_button.pressed.connect(_on_gas_transfer.bind(true)) + gas_to_fleet_button.pressed.connect(_on_gas_transfer.bind(false)) formation_close_button.pressed.connect(func(): formation_menu.visible = false) formation_reset_button.pressed.connect(_on_reset_formation) @@ -1002,6 +1006,11 @@ func _on_transfer(to_building: bool, amount: int) -> void: transfer_status.text = "Loaded %d ore into the fleet" % moved _refresh_transfer() +func _on_gas_transfer(to_building: bool) -> void: + var moved: int = GameState.transfer_gas_to_building(transfer_building_id, ALL) if to_building else GameState.transfer_gas_to_fleet(transfer_building_id, ALL) + transfer_status.text = "Moved %d gas" % moved if moved > 0 else "No gas available on that side" + _refresh_transfer() + func _transfer_place_name() -> String: var b: Dictionary = GameState.find_building(transfer_building_id) @@ -1037,6 +1046,10 @@ func _refresh_transfer() -> void: for button in [to_building_batch_button, to_building_all_button, to_fleet_batch_button, to_fleet_all_button]: button.queue_redraw() + gas_to_building_button.enabled = GameState.fleet_gas_cargo > 0 + gas_to_fleet_button.enabled = GameState.building_gas_holdings(transfer_building_id) > 0 + gas_to_building_button.queue_redraw() + gas_to_fleet_button.queue_redraw() func _refresh_queue() -> void: diff --git a/GameState.gd b/GameState.gd index 0c0ae7d..27f9242 100644 --- a/GameState.gd +++ b/GameState.gd @@ -42,10 +42,14 @@ var gas: int = 0 # down and rebuilt on every trip to a planet's surface - and cargo mined ON a # surface would otherwise be dropped the moment the player took off. var fleet_cargo: int = 0 +var fleet_gas_cargo: int = 0 func collect_cargo(amount: int = 1) -> void: fleet_cargo += amount +func collect_gas_cargo(amount: int = 1) -> void: + fleet_gas_cargo += amount + # The batch size the transfer menu offers, next to "All". A batch rather # than only all-or-nothing: the hold is the part that can be lost, and @@ -73,6 +77,11 @@ func building_holdings(id: int) -> int: return rocks return int(b.get("stock", 0)) +func building_gas_holdings(id: int) -> int: + var b: Dictionary = find_building(id) + if b.is_empty(): return 0 + return gas if b.type == BUILDING_MOTHERSHIP else int(b.get("gas_stock", 0)) + func transfer_to_building(id: int, amount: int) -> int: # Hold -> this building. Returns how much actually moved, which is capped @@ -108,6 +117,24 @@ func transfer_to_fleet(id: int, amount: int) -> int: fleet_cargo += moved return moved +func transfer_gas_to_building(id: int, amount: int) -> int: + var b: Dictionary = find_building(id) + if b.is_empty(): return 0 + var moved := mini(amount, fleet_gas_cargo) + fleet_gas_cargo -= moved + if b.type == BUILDING_MOTHERSHIP: gas += moved + else: b.gas_stock = int(b.get("gas_stock", 0)) + moved + return moved + +func transfer_gas_to_fleet(id: int, amount: int) -> int: + var b: Dictionary = find_building(id) + if b.is_empty(): return 0 + var moved := mini(amount, building_gas_holdings(id)) + if b.type == BUILDING_MOTHERSHIP: gas -= moved + else: b.gas_stock = int(b.get("gas_stock", 0)) - moved + fleet_gas_cargo += moved + return moved + const MOTHERSHIP_COST: int = 20 const SHIP_CRAFTER_COST: int = 12 const SHIP_COST: int = 6 diff --git a/GasVentField.gd b/GasVentField.gd index 3976287..908a664 100644 --- a/GasVentField.gd +++ b/GasVentField.gd @@ -12,7 +12,7 @@ func _process(delta: float) -> void: if fleet.get_centroid().distance_to(vent) < 90.0: progress += delta if progress >= 1.0: - GameState.gas += int(progress) + GameState.collect_gas_cargo(int(progress)) progress = fmod(progress, 1.0) return progress = 0.0 diff --git a/IconButton.gd b/IconButton.gd index d89a0a7..9e61c71 100644 --- a/IconButton.gd +++ b/IconButton.gd @@ -26,6 +26,7 @@ enum Icon { UPGRADE_SHIELD_HITS, UPGRADE_SHIELD_RECHARGE, UPGRADE_CARGO, UPGRADE_ENGINES, UPGRADE_UNLOCK_SHIELD, ACTION_MENU, + GAS, } # Size the glyphs were originally drawn against. Every glyph dimension is @@ -200,6 +201,8 @@ func _draw() -> void: _draw_upgrade_unlock_shield(center, pulse, s) Icon.ACTION_MENU: _draw_action_menu(center, pulse, s) + Icon.GAS: + _draw_gas(center, pulse, s) func _draw_close(center: Vector2, pulse: float, s: float) -> void: @@ -334,6 +337,15 @@ func _draw_action_menu(center: Vector2, pulse: float, s: float) -> void: center + Vector2(-15, y + 2) * s, ]), _active_color(), pulse, core_color) +func _draw_gas(center: Vector2, pulse: float, s: float) -> void: + # Three drifting bubbles: the visual language for gaseous resources. + for data in [[Vector2(-6,-3), 6.0], [Vector2(6,4), 8.0], [Vector2(4,-9), 4.0]]: + var ring := PackedVector2Array() + for i in range(10): + var a := TAU * float(i) / 10.0 + ring.append(center + (data[0] + Vector2(cos(a), sin(a)) * data[1]) * s) + NeonDraw.draw_glowing_polygon(self, ring, _active_color(), pulse, core_color) + func _draw_build(center: Vector2, pulse: float, s: float) -> void: # A plus inside a frame - "add a structure". diff --git a/Main.tscn b/Main.tscn index 9493281..782610d 100644 --- a/Main.tscn +++ b/Main.tscn @@ -1615,6 +1615,38 @@ script = ExtResource("10") icon = 1 glow_color = Color(1, 0.78, 0.25, 1) +[node name="GasToBuildingButton" type="Control" parent="UI/TransferMenu"] +anchor_left = 0.5 +anchor_right = 0.5 +offset_left = -180 +offset_right = -32 +offset_top = 1020 +offset_bottom = 1168 +script = ExtResource("10") +icon = 25 +glow_color = Color(0.85, 0.52, 1, 1) + +[node name="GasToFleetButton" type="Control" parent="UI/TransferMenu"] +anchor_left = 0.5 +anchor_right = 0.5 +offset_left = 32 +offset_right = 180 +offset_top = 1020 +offset_bottom = 1168 +script = ExtResource("10") +icon = 25 +glow_color = Color(0.85, 0.52, 1, 1) + +[node name="GasTransferLabel" type="Label" parent="UI/TransferMenu"] +mouse_filter = 2 +anchor_right = 1.0 +offset_top = 1172 +offset_bottom = 1222 +text = "GAS: unload all load all" +horizontal_alignment = 1 +theme_override_colors/font_color = Color(0.85, 0.52, 1, 1) +theme_override_font_sizes/font_size = 22 + [node name="FormationMenu" type="Control" parent="UI" groups=["modal_menus"]] visible = false mouse_filter = 2 diff --git a/ResourceBar.gd b/ResourceBar.gd index 9880c5c..b23eb46 100644 --- a/ResourceBar.gd +++ b/ResourceBar.gd @@ -93,7 +93,7 @@ func _layout() -> void: func _process(_delta: float) -> void: - _gas_caption.text = "GAS %d" % GameState.gas + _gas_caption.text = "GAS %d / %d / %d" % [GameState.gas, GameState.fleet_gas_cargo, GameState.building_gas_holdings(building_id)] _numbers[0].set_amount(GameState.rocks) _numbers[1].set_amount(GameState.fleet_cargo) diff --git a/tests/test_gas_system.gd b/tests/test_gas_system.gd index d690b9e..ac33780 100644 --- a/tests/test_gas_system.gd +++ b/tests/test_gas_system.gd @@ -51,6 +51,11 @@ func _process(delta: float) -> bool: game_state._arrive(game_state.transporters[0]) if game_state.gas != game_state.transporter_load_limit() or game_state.rocks != 0: return _fail("gas delivery banked gas=%d ore=%d" % [game_state.gas, game_state.rocks]) + var mothership_id: int = int(game_state.buildings[0].id) + if game_state.transfer_gas_to_fleet(mothership_id, 7) != 7 or game_state.fleet_gas_cargo != 7: + return _fail("could not load banked gas into fleet cargo") + if game_state.transfer_gas_to_building(2, 7) != 7 or game_state.building_gas_holdings(2) != 7: + return _fail("could not unload fleet gas into a building") print("gas giant animated; transporter banked %d gas without creating ore" % game_state.gas) print("TEST_GAS_SYSTEM: PASS") quit(0)