Add manual extractor resource transfers
This commit is contained in:
parent
e2d4297ee5
commit
db0e6a0ec2
7 changed files with 180 additions and 14 deletions
|
|
@ -159,9 +159,12 @@ var craft_message_until: int = 0
|
|||
# current_building while any menu is open, so by the next frame the panel
|
||||
# would not know which building it belongs to.
|
||||
var transfer_building_id: int = 0
|
||||
var transfer_extractor_index: int = -1
|
||||
|
||||
var current_building: Node2D = null
|
||||
var pending_building: Node2D = null
|
||||
var current_extractor_index: int = -1
|
||||
var pending_extractor_index: int = -1
|
||||
var pending_time: float = 0.0
|
||||
var context_actions_expanded: bool = false
|
||||
|
||||
|
|
@ -304,6 +307,8 @@ func _process(delta: float) -> void:
|
|||
or transfer_menu.visible or hangar_menu.visible:
|
||||
current_building = null
|
||||
pending_building = null
|
||||
current_extractor_index = -1
|
||||
pending_extractor_index = -1
|
||||
action_button.visible = false
|
||||
building_action_button.visible = false
|
||||
transfer_button.visible = false
|
||||
|
|
@ -314,17 +319,25 @@ func _process(delta: float) -> void:
|
|||
# Debounced exactly like the enter-atmosphere prompt, so the action
|
||||
# button can't flicker while the fleet drifts on the interact boundary.
|
||||
var detected: Node2D = building_field.get_building_fleet_is_on()
|
||||
var detected_extractor: int = -1
|
||||
if detected == null:
|
||||
var planet: Node2D = _planet_under_fleet()
|
||||
if planet != null:
|
||||
detected_extractor = GameState.extractor_index_at(planet.planet_id)
|
||||
|
||||
if detected != pending_building:
|
||||
if detected != pending_building or detected_extractor != pending_extractor_index:
|
||||
pending_building = detected
|
||||
pending_extractor_index = detected_extractor
|
||||
pending_time = 0.0
|
||||
else:
|
||||
pending_time += delta
|
||||
|
||||
if pending_time < prompt_debounce_time or pending_building == current_building:
|
||||
if pending_time < prompt_debounce_time or (pending_building == current_building \
|
||||
and pending_extractor_index == current_extractor_index):
|
||||
return
|
||||
|
||||
current_building = pending_building
|
||||
current_extractor_index = pending_extractor_index
|
||||
context_actions_expanded = false
|
||||
hangar_button.visible = false
|
||||
# Every building can hold ore, so the transfer button rides alongside the
|
||||
|
|
@ -332,13 +345,16 @@ func _process(delta: float) -> void:
|
|||
# turns into - the two are independent choices at the same structure.
|
||||
transfer_button.visible = false
|
||||
building_action_button.visible = false
|
||||
action_button.visible = current_building != null
|
||||
action_button.visible = current_building != null or current_extractor_index >= 0
|
||||
if current_building != null:
|
||||
var actions: Array = _context_action_buttons()
|
||||
building_action_button.icon = int(current_building.definition.action_icon)
|
||||
building_action_button.queue_redraw()
|
||||
action_button.icon = building_action_button.icon if actions.size() == 1 else IconButton.Icon.ACTION_MENU
|
||||
action_button.queue_redraw()
|
||||
elif current_extractor_index >= 0:
|
||||
action_button.icon = IconButton.Icon.TRANSFER
|
||||
action_button.queue_redraw()
|
||||
_layout_context_buttons()
|
||||
|
||||
|
||||
|
|
@ -365,6 +381,8 @@ func _layout_context_buttons() -> void:
|
|||
|
||||
|
||||
func _context_action_buttons() -> Array:
|
||||
if current_extractor_index >= 0:
|
||||
return [transfer_button]
|
||||
if current_building == null:
|
||||
return []
|
||||
var buttons: Array = []
|
||||
|
|
@ -384,7 +402,7 @@ func _button_for_building_action(action: String) -> IconButton:
|
|||
|
||||
|
||||
func _on_context_action_pressed() -> void:
|
||||
if current_building == null:
|
||||
if current_building == null and current_extractor_index < 0:
|
||||
return
|
||||
var actions: Array = _context_action_buttons()
|
||||
if actions.size() == 1:
|
||||
|
|
@ -877,9 +895,10 @@ const ALL: int = 1 << 30
|
|||
|
||||
|
||||
func _on_transfer_pressed() -> void:
|
||||
if current_building == null:
|
||||
if current_building == null and current_extractor_index < 0:
|
||||
return
|
||||
transfer_building_id = current_building.building_id
|
||||
transfer_building_id = current_building.building_id if current_building != null else 0
|
||||
transfer_extractor_index = current_extractor_index
|
||||
for bar in resource_bars:
|
||||
bar.building_id = transfer_building_id
|
||||
transfer_menu.visible = true
|
||||
|
|
@ -892,15 +911,17 @@ func _on_transfer(to_building: bool, amount: int) -> void:
|
|||
|
||||
|
||||
func _on_resource_transfer(resource_type: String, to_building: bool, amount: int = ALL) -> void:
|
||||
if transfer_building_id == 0:
|
||||
transfer_status.text = "No building selected - reopen this panel from the building"
|
||||
if transfer_building_id == 0 and transfer_extractor_index < 0:
|
||||
transfer_status.text = "No resource store selected - reopen this panel from its action"
|
||||
return
|
||||
|
||||
var moved: int = GameState.transfer_resource_to_building(
|
||||
transfer_building_id, resource_type, amount
|
||||
) if to_building else GameState.transfer_resource_to_fleet(
|
||||
transfer_building_id, resource_type, amount
|
||||
)
|
||||
var moved: int
|
||||
if transfer_extractor_index >= 0:
|
||||
moved = GameState.transfer_resource_to_extractor(transfer_extractor_index, resource_type, amount) \
|
||||
if to_building else GameState.transfer_resource_from_extractor(transfer_extractor_index, resource_type, amount)
|
||||
else:
|
||||
moved = GameState.transfer_resource_to_building(transfer_building_id, resource_type, amount) \
|
||||
if to_building else GameState.transfer_resource_to_fleet(transfer_building_id, resource_type, amount)
|
||||
var resource_name: String = GameState.resource_name(resource_type).to_lower()
|
||||
|
||||
# Nothing moving is the common case at an empty end, and a silent no-op
|
||||
|
|
@ -922,6 +943,8 @@ func _on_gas_transfer(to_building: bool) -> void:
|
|||
|
||||
|
||||
func _transfer_place_name() -> String:
|
||||
if transfer_extractor_index >= 0:
|
||||
return "the extractor"
|
||||
var b: Dictionary = GameState.find_building(transfer_building_id)
|
||||
if b.is_empty():
|
||||
return "this building"
|
||||
|
|
@ -933,6 +956,9 @@ func _transfer_place_name() -> String:
|
|||
|
||||
|
||||
func _refresh_transfer() -> void:
|
||||
if transfer_extractor_index >= 0:
|
||||
transfer_list.set_extractor_destination(transfer_extractor_index, "Planet extractor")
|
||||
return
|
||||
var building: Dictionary = GameState.find_building(transfer_building_id)
|
||||
var heading: String = "This building"
|
||||
if not building.is_empty() and building.type == GameState.BUILDING_MOTHERSHIP:
|
||||
|
|
|
|||
26
GameState.gd
26
GameState.gd
|
|
@ -896,6 +896,14 @@ func has_extractor_at(planet_key: String) -> bool:
|
|||
return false
|
||||
|
||||
|
||||
func extractor_index_at(planet_key: String) -> int:
|
||||
for i in range(extractors.size()):
|
||||
var extractor: Dictionary = extractors[i]
|
||||
if String(extractor.get("planet_id", extractor.get("planet_name", ""))) == planet_key:
|
||||
return i
|
||||
return -1
|
||||
|
||||
|
||||
signal extractor_added(planet_name: String)
|
||||
|
||||
|
||||
|
|
@ -924,6 +932,24 @@ func extractor_stock(index: int) -> int:
|
|||
return _extractor_inventory(extractor).amount(String(extractor.get("resource_type", RESOURCE_ORE)))
|
||||
|
||||
|
||||
func extractor_resource(index: int, resource_type: String) -> int:
|
||||
if index < 0 or index >= extractors.size():
|
||||
return 0
|
||||
return _extractor_inventory(extractors[index]).amount(resource_type)
|
||||
|
||||
|
||||
func transfer_resource_to_extractor(index: int, resource_type: String, amount: int) -> int:
|
||||
if index < 0 or index >= extractors.size():
|
||||
return 0
|
||||
return fleet_inventory.transfer_to(_extractor_inventory(extractors[index]), resource_type, amount)
|
||||
|
||||
|
||||
func transfer_resource_from_extractor(index: int, resource_type: String, amount: int) -> int:
|
||||
if index < 0 or index >= extractors.size():
|
||||
return 0
|
||||
return _extractor_inventory(extractors[index]).transfer_to(fleet_inventory, resource_type, amount)
|
||||
|
||||
|
||||
func _extractor_inventory(extractor: Dictionary) -> RefCounted:
|
||||
var inventory: RefCounted = extractor.get("inventory") as RefCounted
|
||||
if inventory == null:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ const ALL_AMOUNT: int = 1 << 30
|
|||
const AMOUNT_OPTIONS: Array[int] = [1, 5, 25, ALL_AMOUNT]
|
||||
|
||||
var building_id: int = 0
|
||||
var extractor_index: int = -1
|
||||
var _destination_heading: Label
|
||||
var _rows: Dictionary = {}
|
||||
|
||||
|
|
@ -134,6 +135,15 @@ func _refresh_amount_controls(row: Dictionary) -> void:
|
|||
|
||||
func set_destination(id: int, heading: String) -> void:
|
||||
building_id = id
|
||||
extractor_index = -1
|
||||
if _destination_heading != null:
|
||||
_destination_heading.text = heading.to_upper()
|
||||
refresh()
|
||||
|
||||
|
||||
func set_extractor_destination(index: int, heading: String) -> void:
|
||||
building_id = 0
|
||||
extractor_index = index
|
||||
if _destination_heading != null:
|
||||
_destination_heading.text = heading.to_upper()
|
||||
refresh()
|
||||
|
|
@ -145,7 +155,8 @@ func refresh() -> void:
|
|||
if row.is_empty():
|
||||
continue
|
||||
var fleet_amount: int = GameState.fleet_resource(resource_type)
|
||||
var local_amount: int = GameState.building_resource(building_id, resource_type)
|
||||
var local_amount: int = GameState.extractor_resource(extractor_index, resource_type) \
|
||||
if extractor_index >= 0 else GameState.building_resource(building_id, resource_type)
|
||||
row.fleet_amount.text = str(fleet_amount)
|
||||
row.local_amount.text = str(local_amount)
|
||||
row.unload.enabled = fleet_amount > 0
|
||||
|
|
|
|||
24
tests/_extractor_transfer_preview.gd
Normal file
24
tests/_extractor_transfer_preview.gd
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
extends Node2D
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
GameState.extractors.clear()
|
||||
GameState.transporters.clear()
|
||||
GameState.fleet_cargo = 9
|
||||
GameState.fleet_gas_cargo = 4
|
||||
var main: Node = load("res://Main.tscn").instantiate()
|
||||
add_child(main)
|
||||
var planet: Node2D
|
||||
for planets in main.get_node("PlanetField").populated_chunks.values():
|
||||
if not planets.is_empty() and is_instance_valid(planets[0]):
|
||||
planet = planets[0]
|
||||
break
|
||||
if planet == null:
|
||||
return
|
||||
GameState.add_extractor(planet.planet_name, planet.position, planet.resource_type, planet.planet_id)
|
||||
var index: int = GameState.extractors.size() - 1
|
||||
GameState.extractors[index].inventory.deposit(planet.resource_type, 38)
|
||||
var controller: Node = main.get_node("BuildController")
|
||||
controller.transfer_extractor_index = index
|
||||
main.get_node("UI/TransferMenu").visible = true
|
||||
controller._refresh_transfer()
|
||||
4
tests/_extractor_transfer_preview.tscn
Normal file
4
tests/_extractor_transfer_preview.tscn
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[gd_scene load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://tests/_extractor_transfer_preview.gd" id="1"]
|
||||
[node name="ExtractorTransferPreview" type="Node2D"]
|
||||
script = ExtResource("1")
|
||||
74
tests/test_extractor_transfer.gd
Normal file
74
tests/test_extractor_transfer.gd
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
extends SceneTree
|
||||
|
||||
var state: Node
|
||||
var scene: Node
|
||||
var fleet: Node
|
||||
var controller: Node
|
||||
var planet: Node2D
|
||||
var extractor_index: int = -1
|
||||
var resource_type: String
|
||||
var stage: int = 0
|
||||
var elapsed: float = 0.0
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
state = root.get_node("GameState")
|
||||
state.extractors.clear()
|
||||
state.transporters.clear()
|
||||
state.fleet_cargo = 0
|
||||
state.fleet_gas_cargo = 0
|
||||
scene = load("res://Main.tscn").instantiate()
|
||||
root.add_child(scene)
|
||||
fleet = scene.get_node("Fleet")
|
||||
controller = scene.get_node("BuildController")
|
||||
|
||||
|
||||
func _process(delta: float) -> bool:
|
||||
elapsed += delta
|
||||
match stage:
|
||||
0:
|
||||
scene.get_node("AsteroidField").set_process(false)
|
||||
scene.get_node("EnemySpawner").set_process(false)
|
||||
for planets in scene.get_node("PlanetField").populated_chunks.values():
|
||||
if not planets.is_empty() and is_instance_valid(planets[0]):
|
||||
planet = planets[0]
|
||||
break
|
||||
if planet == null:
|
||||
return _fail("no nearby generated planet available")
|
||||
resource_type = planet.resource_type
|
||||
state.add_extractor(planet.planet_name, planet.position, resource_type, planet.planet_id)
|
||||
extractor_index = state.extractors.size() - 1
|
||||
state.extractors[extractor_index].inventory.deposit(resource_type, 12)
|
||||
for ship in fleet.ships:
|
||||
ship.position = planet.position
|
||||
fleet.move_to(planet.position)
|
||||
elapsed = 0.0
|
||||
stage = 1
|
||||
return false
|
||||
1:
|
||||
if elapsed < 1.2:
|
||||
return false
|
||||
if controller.current_extractor_index != extractor_index or not controller.action_button.visible:
|
||||
return _fail("extractor did not expose a contextual action")
|
||||
if not scene.get_node("UI/EnterAtmosphereButton").visible:
|
||||
return _fail("extractor action hid the separate landing action")
|
||||
controller._on_context_action_pressed()
|
||||
if not controller.transfer_menu.visible or controller.transfer_list.extractor_index != extractor_index:
|
||||
return _fail("transfer panel did not bind to the extractor")
|
||||
var before: int = state.fleet_resource(resource_type)
|
||||
controller._on_resource_transfer(resource_type, false, 5)
|
||||
if state.fleet_resource(resource_type) != before + 5:
|
||||
return _fail("fleet did not fetch five resources from extractor")
|
||||
if state.extractor_resource(extractor_index, resource_type) < 7:
|
||||
return _fail("extractor transfer removed too much stock")
|
||||
print("fleet fetched %s from extractor while landing remained available" % resource_type)
|
||||
print("TEST_EXTRACTOR_TRANSFER: PASS")
|
||||
quit(0)
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func _fail(message: String) -> bool:
|
||||
print("TEST_EXTRACTOR_TRANSFER: FAIL (%s)" % message)
|
||||
quit(1)
|
||||
return true
|
||||
1
tests/test_planet_unique_identity.gd.uid
Normal file
1
tests/test_planet_unique_identity.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://0ghcdnlq2vd2
|
||||
Loading…
Reference in a new issue