Store resources in generic inventories
This commit is contained in:
parent
02643c76c4
commit
1721edd123
24 changed files with 385 additions and 172 deletions
236
GameState.gd
236
GameState.gd
|
|
@ -1,5 +1,8 @@
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
|
const INVENTORY = preload("res://Inventory.gd")
|
||||||
|
const RESOURCE_DEFINITIONS = preload("res://ResourceDefinitions.gd")
|
||||||
|
|
||||||
|
|
||||||
# Autoload singleton - the one thing that survives change_scene_to_file()
|
# Autoload singleton - the one thing that survives change_scene_to_file()
|
||||||
# scene swaps between space (Main.tscn) and a planet's surface
|
# scene swaps between space (Main.tscn) and a planet's surface
|
||||||
|
|
@ -23,126 +26,101 @@ var explored_chunks: Dictionary = {}
|
||||||
|
|
||||||
# --- Resources -------------------------------------------------------------
|
# --- Resources -------------------------------------------------------------
|
||||||
|
|
||||||
# Ore that has been BANKED at the mothership. This is the only pool anything
|
const RESOURCE_ORE: String = RESOURCE_DEFINITIONS.ORE_ID
|
||||||
# can be bought with.
|
const RESOURCE_GAS: String = RESOURCE_DEFINITIONS.GAS_ID
|
||||||
# Starts stocked for play-testing so buildings can be tried without mining
|
const RESOURCE_TYPES: PackedStringArray = RESOURCE_DEFINITIONS.ORDER
|
||||||
# first - drop this back to 0 for a real playthrough.
|
|
||||||
var rocks: int = 500
|
|
||||||
|
|
||||||
# Gas is a second, banked resource. It is deliberately separate from ore:
|
# All resource-bearing locations use the same container. The old public
|
||||||
# construction still spends ore, while future gas technologies can consume
|
# names below are computed compatibility accessors, not separate storage.
|
||||||
# gas without making the two materials silently interchangeable.
|
var bank_inventory: RefCounted = INVENTORY.new({RESOURCE_ORE: 500})
|
||||||
var gas: int = 0
|
var fleet_inventory: RefCounted = INVENTORY.new()
|
||||||
|
|
||||||
# Ore the fleet is physically carrying and has not delivered yet (#14). Mining
|
var rocks: int:
|
||||||
# fills this, not `rocks`: ore is cargo until the fleet brings it home, so a
|
get: return bank_inventory.amount(RESOURCE_ORE)
|
||||||
# long mining run is a real trip with something to lose rather than instant
|
set(value): bank_inventory.set_amount(RESOURCE_ORE, value)
|
||||||
# income from anywhere on the map.
|
|
||||||
#
|
|
||||||
# Lives here, like everything else that has to survive Main.tscn being torn
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# Resource-facing UI and logistics iterate this list instead of growing a
|
var gas: int:
|
||||||
# second set of controls and controller branches every time a material is
|
get: return bank_inventory.amount(RESOURCE_GAS)
|
||||||
# introduced. Keep presentation data here with the state it describes so a
|
set(value): bank_inventory.set_amount(RESOURCE_GAS, value)
|
||||||
# resource has one name and colour everywhere it appears.
|
|
||||||
const RESOURCE_ORE: String = "ore"
|
var fleet_cargo: int:
|
||||||
const RESOURCE_GAS: String = "gas"
|
get: return fleet_inventory.amount(RESOURCE_ORE)
|
||||||
const RESOURCE_TYPES: PackedStringArray = [RESOURCE_ORE, RESOURCE_GAS]
|
set(value): fleet_inventory.set_amount(RESOURCE_ORE, value)
|
||||||
const RESOURCE_NAMES: Dictionary = {
|
|
||||||
RESOURCE_ORE: "Ore",
|
var fleet_gas_cargo: int:
|
||||||
RESOURCE_GAS: "Gas",
|
get: return fleet_inventory.amount(RESOURCE_GAS)
|
||||||
}
|
set(value): fleet_inventory.set_amount(RESOURCE_GAS, value)
|
||||||
const RESOURCE_COLORS: Dictionary = {
|
|
||||||
RESOURCE_ORE: Color(0.0, 0.72, 0.82),
|
|
||||||
RESOURCE_GAS: Color(0.85, 0.52, 1.0),
|
|
||||||
}
|
|
||||||
|
|
||||||
func collect_cargo(amount: int = 1) -> void:
|
func collect_cargo(amount: int = 1) -> void:
|
||||||
fleet_cargo += amount
|
fleet_inventory.deposit(RESOURCE_ORE, amount)
|
||||||
|
|
||||||
func collect_gas_cargo(amount: int = 1) -> void:
|
func collect_gas_cargo(amount: int = 1) -> void:
|
||||||
fleet_gas_cargo += amount
|
fleet_inventory.deposit(RESOURCE_GAS, amount)
|
||||||
|
|
||||||
|
|
||||||
|
func resource_types() -> PackedStringArray:
|
||||||
|
return RESOURCE_DEFINITIONS.ids()
|
||||||
|
|
||||||
|
|
||||||
|
func resource_definition(resource_type: String) -> Resource:
|
||||||
|
return RESOURCE_DEFINITIONS.get_definition(resource_type)
|
||||||
|
|
||||||
|
|
||||||
func resource_name(resource_type: String) -> String:
|
func resource_name(resource_type: String) -> String:
|
||||||
return String(RESOURCE_NAMES.get(resource_type, resource_type.capitalize()))
|
var definition: Resource = resource_definition(resource_type)
|
||||||
|
return String(definition.display_name) if definition != null else resource_type.capitalize()
|
||||||
|
|
||||||
|
|
||||||
func resource_color(resource_type: String) -> Color:
|
func resource_color(resource_type: String) -> Color:
|
||||||
return RESOURCE_COLORS.get(resource_type, Color.WHITE)
|
var definition: Resource = resource_definition(resource_type)
|
||||||
|
return definition.color if definition != null else Color.WHITE
|
||||||
|
|
||||||
|
|
||||||
func banked_resource(resource_type: String) -> int:
|
func banked_resource(resource_type: String) -> int:
|
||||||
match resource_type:
|
return bank_inventory.amount(resource_type)
|
||||||
RESOURCE_ORE: return rocks
|
|
||||||
RESOURCE_GAS: return gas
|
|
||||||
_: return 0
|
|
||||||
|
|
||||||
|
|
||||||
func fleet_resource(resource_type: String) -> int:
|
func fleet_resource(resource_type: String) -> int:
|
||||||
match resource_type:
|
return fleet_inventory.amount(resource_type)
|
||||||
RESOURCE_ORE: return fleet_cargo
|
|
||||||
RESOURCE_GAS: return fleet_gas_cargo
|
|
||||||
_: return 0
|
func _inventory_for_record(record: Dictionary) -> RefCounted:
|
||||||
|
var inventory: RefCounted = record.get("inventory") as RefCounted
|
||||||
|
if inventory == null:
|
||||||
|
inventory = INVENTORY.new()
|
||||||
|
record.inventory = inventory
|
||||||
|
# Compatibility migration for state made before #33. Erase each legacy
|
||||||
|
# field once absorbed so it cannot drift out of step with the inventory.
|
||||||
|
if record.has("stock"):
|
||||||
|
inventory.set_amount(RESOURCE_ORE, int(record.stock))
|
||||||
|
record.erase("stock")
|
||||||
|
if record.has("gas_stock"):
|
||||||
|
inventory.set_amount(RESOURCE_GAS, int(record.gas_stock))
|
||||||
|
record.erase("gas_stock")
|
||||||
|
return inventory
|
||||||
|
|
||||||
|
|
||||||
|
func building_inventory(id: int) -> RefCounted:
|
||||||
|
var building: Dictionary = find_building(id)
|
||||||
|
if building.is_empty():
|
||||||
|
return null
|
||||||
|
if building.type == BUILDING_MOTHERSHIP:
|
||||||
|
return bank_inventory
|
||||||
|
return _inventory_for_record(building)
|
||||||
|
|
||||||
|
|
||||||
func building_resource(id: int, resource_type: String) -> int:
|
func building_resource(id: int, resource_type: String) -> int:
|
||||||
var building: Dictionary = find_building(id)
|
var inventory: RefCounted = building_inventory(id)
|
||||||
if building.is_empty():
|
return 0 if inventory == null else inventory.amount(resource_type)
|
||||||
return 0
|
|
||||||
if building.type == BUILDING_MOTHERSHIP:
|
|
||||||
return banked_resource(resource_type)
|
|
||||||
match resource_type:
|
|
||||||
RESOURCE_ORE: return int(building.get("stock", 0))
|
|
||||||
RESOURCE_GAS: return int(building.get("gas_stock", 0))
|
|
||||||
_: return 0
|
|
||||||
|
|
||||||
|
|
||||||
func transfer_resource_to_building(id: int, resource_type: String, amount: int) -> int:
|
func transfer_resource_to_building(id: int, resource_type: String, amount: int) -> int:
|
||||||
var building: Dictionary = find_building(id)
|
return fleet_inventory.transfer_to(building_inventory(id), resource_type, amount)
|
||||||
if building.is_empty():
|
|
||||||
return 0
|
|
||||||
var moved: int = mini(maxi(amount, 0), fleet_resource(resource_type))
|
|
||||||
if moved <= 0:
|
|
||||||
return 0
|
|
||||||
match resource_type:
|
|
||||||
RESOURCE_ORE: fleet_cargo -= moved
|
|
||||||
RESOURCE_GAS: fleet_gas_cargo -= moved
|
|
||||||
_: return 0
|
|
||||||
if building.type == BUILDING_MOTHERSHIP:
|
|
||||||
match resource_type:
|
|
||||||
RESOURCE_ORE: rocks += moved
|
|
||||||
RESOURCE_GAS: gas += moved
|
|
||||||
else:
|
|
||||||
match resource_type:
|
|
||||||
RESOURCE_ORE: building.stock = int(building.get("stock", 0)) + moved
|
|
||||||
RESOURCE_GAS: building.gas_stock = int(building.get("gas_stock", 0)) + moved
|
|
||||||
return moved
|
|
||||||
|
|
||||||
|
|
||||||
func transfer_resource_to_fleet(id: int, resource_type: String, amount: int) -> int:
|
func transfer_resource_to_fleet(id: int, resource_type: String, amount: int) -> int:
|
||||||
var building: Dictionary = find_building(id)
|
var source: RefCounted = building_inventory(id)
|
||||||
if building.is_empty():
|
return 0 if source == null else source.transfer_to(fleet_inventory, resource_type, amount)
|
||||||
return 0
|
|
||||||
var moved: int = mini(maxi(amount, 0), building_resource(id, resource_type))
|
|
||||||
if moved <= 0:
|
|
||||||
return 0
|
|
||||||
if building.type == BUILDING_MOTHERSHIP:
|
|
||||||
match resource_type:
|
|
||||||
RESOURCE_ORE: rocks -= moved
|
|
||||||
RESOURCE_GAS: gas -= moved
|
|
||||||
else:
|
|
||||||
match resource_type:
|
|
||||||
RESOURCE_ORE: building.stock = int(building.get("stock", 0)) - moved
|
|
||||||
RESOURCE_GAS: building.gas_stock = int(building.get("gas_stock", 0)) - moved
|
|
||||||
match resource_type:
|
|
||||||
RESOURCE_ORE: fleet_cargo += moved
|
|
||||||
RESOURCE_GAS: fleet_gas_cargo += moved
|
|
||||||
return moved
|
|
||||||
|
|
||||||
|
|
||||||
# The batch size the transfer menu offers, next to "All". A batch rather
|
# The batch size the transfer menu offers, next to "All". A batch rather
|
||||||
|
|
@ -401,8 +379,8 @@ func add_building(type: String, at_position: Vector2) -> int:
|
||||||
var id: int = next_building_id
|
var id: int = next_building_id
|
||||||
next_building_id += 1
|
next_building_id += 1
|
||||||
buildings.append({
|
buildings.append({
|
||||||
"id": id, "type": type, "position": at_position, "stock": 0,
|
"id": id, "type": type, "position": at_position,
|
||||||
"gas_stock": 0, "orders": [],
|
"inventory": INVENTORY.new(), "orders": [],
|
||||||
})
|
})
|
||||||
return id
|
return id
|
||||||
|
|
||||||
|
|
@ -655,8 +633,7 @@ func can_produce(type: String) -> bool:
|
||||||
|
|
||||||
|
|
||||||
func building_stock(id: int) -> int:
|
func building_stock(id: int) -> int:
|
||||||
var b: Dictionary = find_building(id)
|
return building_resource(id, RESOURCE_ORE)
|
||||||
return 0 if b.is_empty() else int(b.get("stock", 0))
|
|
||||||
|
|
||||||
|
|
||||||
func pending_orders(id: int) -> int:
|
func pending_orders(id: int) -> int:
|
||||||
|
|
@ -703,7 +680,7 @@ func cancel_order(id: int, index: int) -> bool:
|
||||||
return false
|
return false
|
||||||
var order: Dictionary = orders[index]
|
var order: Dictionary = orders[index]
|
||||||
if bool(order.started):
|
if bool(order.started):
|
||||||
b.stock = int(b.get("stock", 0)) + product_cost(String(order.product))
|
_inventory_for_record(b).deposit(RESOURCE_ORE, product_cost(String(order.product)))
|
||||||
orders.remove_at(index)
|
orders.remove_at(index)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
@ -718,7 +695,7 @@ func outstanding_cost(id: int) -> int:
|
||||||
# A started build has already paid, so it is not still owed.
|
# A started build has already paid, so it is not still owed.
|
||||||
if not bool(o.started):
|
if not bool(o.started):
|
||||||
need += product_cost(String(o.product))
|
need += product_cost(String(o.product))
|
||||||
return maxi(need - int(b.get("stock", 0)), 0)
|
return maxi(need - _inventory_for_record(b).amount(RESOURCE_ORE), 0)
|
||||||
|
|
||||||
|
|
||||||
func deposit_to_building(id: int, amount: int) -> int:
|
func deposit_to_building(id: int, amount: int) -> int:
|
||||||
|
|
@ -727,8 +704,7 @@ func deposit_to_building(id: int, amount: int) -> int:
|
||||||
var b: Dictionary = find_building(id)
|
var b: Dictionary = find_building(id)
|
||||||
if b.is_empty():
|
if b.is_empty():
|
||||||
return 0
|
return 0
|
||||||
b.stock = int(b.get("stock", 0)) + amount
|
return _inventory_for_record(b).deposit(RESOURCE_ORE, amount)
|
||||||
return amount
|
|
||||||
|
|
||||||
|
|
||||||
func queue_order(id: int, product: String = PRODUCT_SHIP) -> bool:
|
func queue_order(id: int, product: String = PRODUCT_SHIP) -> bool:
|
||||||
|
|
@ -763,9 +739,10 @@ func _advance_production(delta: float) -> void:
|
||||||
var order: Dictionary = orders[0]
|
var order: Dictionary = orders[0]
|
||||||
var product: String = String(order.product)
|
var product: String = String(order.product)
|
||||||
var cost: int = product_cost(product)
|
var cost: int = product_cost(product)
|
||||||
|
var inventory: RefCounted = _inventory_for_record(b)
|
||||||
|
|
||||||
if not bool(order.started):
|
if not bool(order.started):
|
||||||
if int(b.get("stock", 0)) < cost:
|
if inventory.amount(RESOURCE_ORE) < cost:
|
||||||
continue
|
continue
|
||||||
if product == PRODUCT_TRANSPORTER and transporters.size() >= transport_capacity():
|
if product == PRODUCT_TRANSPORTER and transporters.size() >= transport_capacity():
|
||||||
# A hub was demolished after this was ordered, so the berth it
|
# A hub was demolished after this was ordered, so the berth it
|
||||||
|
|
@ -773,7 +750,7 @@ func _advance_production(delta: float) -> void:
|
||||||
continue
|
continue
|
||||||
if product == PRODUCT_TRANSPORTER and nearest_hub_to(b.position).is_empty():
|
if product == PRODUCT_TRANSPORTER and nearest_hub_to(b.position).is_empty():
|
||||||
continue
|
continue
|
||||||
b.stock = int(b.stock) - cost
|
inventory.withdraw(RESOURCE_ORE, cost)
|
||||||
order.started = true
|
order.started = true
|
||||||
|
|
||||||
order.elapsed = float(order.elapsed) + delta
|
order.elapsed = float(order.elapsed) + delta
|
||||||
|
|
@ -826,10 +803,11 @@ func _advance_lab_research(delta: float) -> void:
|
||||||
var order: Dictionary = orders[0]
|
var order: Dictionary = orders[0]
|
||||||
var id: String = String(order.id)
|
var id: String = String(order.id)
|
||||||
var cost: int = UNLOCK_SHIELD_COST if id == UNLOCK_SHIELD_VESSEL else upgrade_cost(id)
|
var cost: int = UNLOCK_SHIELD_COST if id == UNLOCK_SHIELD_VESSEL else upgrade_cost(id)
|
||||||
|
var inventory: RefCounted = _inventory_for_record(lab)
|
||||||
if not bool(order.started):
|
if not bool(order.started):
|
||||||
if int(lab.get("stock", 0)) < cost:
|
if inventory.amount(RESOURCE_ORE) < cost:
|
||||||
continue
|
continue
|
||||||
lab.stock = int(lab.stock) - cost
|
inventory.withdraw(RESOURCE_ORE, cost)
|
||||||
order.started = true
|
order.started = true
|
||||||
order.elapsed = float(order.elapsed) + delta
|
order.elapsed = float(order.elapsed) + delta
|
||||||
if float(order.elapsed) < lab_research_time():
|
if float(order.elapsed) < lab_research_time():
|
||||||
|
|
@ -918,7 +896,7 @@ func rotate_formation(radians: float) -> void:
|
||||||
# Extractors mine into their OWN local stock. They do not own a magical
|
# Extractors mine into their OWN local stock. They do not own a magical
|
||||||
# hauler: ore becomes spendable only when a hub-stationed transporter picks
|
# hauler: ore becomes spendable only when a hub-stationed transporter picks
|
||||||
# up a full load and physically delivers it to the mothership. Entries are
|
# up a full load and physically delivers it to the mothership. Entries are
|
||||||
# {"position", "planet_name", "resource_type", "stock", "mining_progress"}.
|
# {"position", "planet_name", "resource_type", "inventory", "mining_progress"}.
|
||||||
const EXTRACTOR_RATE: float = 2.0 # ore per second
|
const EXTRACTOR_RATE: float = 2.0 # ore per second
|
||||||
|
|
||||||
var extractors: Array = []
|
var extractors: Array = []
|
||||||
|
|
@ -939,7 +917,7 @@ func add_extractor(planet_name: String, at_position: Vector2, resource_type: Str
|
||||||
"position": at_position,
|
"position": at_position,
|
||||||
"planet_name": planet_name,
|
"planet_name": planet_name,
|
||||||
"resource_type": resource_type,
|
"resource_type": resource_type,
|
||||||
"stock": 0,
|
"inventory": INVENTORY.new(),
|
||||||
"mining_progress": 0.0,
|
"mining_progress": 0.0,
|
||||||
})
|
})
|
||||||
# An extractor is built from SPACE, with the fleet parked on the planet -
|
# An extractor is built from SPACE, with the fleet parked on the planet -
|
||||||
|
|
@ -952,7 +930,21 @@ func add_extractor(planet_name: String, at_position: Vector2, resource_type: Str
|
||||||
func extractor_stock(index: int) -> int:
|
func extractor_stock(index: int) -> int:
|
||||||
if index < 0 or index >= extractors.size():
|
if index < 0 or index >= extractors.size():
|
||||||
return 0
|
return 0
|
||||||
return int(extractors[index].get("stock", 0))
|
var extractor: Dictionary = extractors[index]
|
||||||
|
return _extractor_inventory(extractor).amount(String(extractor.get("resource_type", RESOURCE_ORE)))
|
||||||
|
|
||||||
|
|
||||||
|
func _extractor_inventory(extractor: Dictionary) -> RefCounted:
|
||||||
|
var inventory: RefCounted = extractor.get("inventory") as RefCounted
|
||||||
|
if inventory == null:
|
||||||
|
inventory = INVENTORY.new()
|
||||||
|
extractor.inventory = inventory
|
||||||
|
# Old extractor state had one stock field whose material was described by
|
||||||
|
# resource_type. Absorb it into that key on first access.
|
||||||
|
if extractor.has("stock"):
|
||||||
|
inventory.set_amount(String(extractor.get("resource_type", RESOURCE_ORE)), int(extractor.stock))
|
||||||
|
extractor.erase("stock")
|
||||||
|
return inventory
|
||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
|
|
@ -965,7 +957,7 @@ func _process(delta: float) -> void:
|
||||||
e.mining_progress = float(e.get("mining_progress", 0.0)) + delta * EXTRACTOR_RATE
|
e.mining_progress = float(e.get("mining_progress", 0.0)) + delta * EXTRACTOR_RATE
|
||||||
var whole: int = int(floor(float(e.mining_progress)))
|
var whole: int = int(floor(float(e.mining_progress)))
|
||||||
if whole > 0:
|
if whole > 0:
|
||||||
e.stock = int(e.get("stock", 0)) + whole
|
_extractor_inventory(e).deposit(String(e.get("resource_type", RESOURCE_ORE)), whole)
|
||||||
e.mining_progress = float(e.mining_progress) - whole
|
e.mining_progress = float(e.mining_progress) - whole
|
||||||
_advance_transporters(delta)
|
_advance_transporters(delta)
|
||||||
|
|
||||||
|
|
@ -1127,7 +1119,8 @@ func _dispatch_transporters() -> void:
|
||||||
var load: int = transporter_load_limit()
|
var load: int = transporter_load_limit()
|
||||||
for i in range(extractors.size()):
|
for i in range(extractors.size()):
|
||||||
var extractor: Dictionary = extractors[i]
|
var extractor: Dictionary = extractors[i]
|
||||||
if int(extractor.get("stock", 0)) < load or _transporter_inbound_to_extractor(i):
|
var resource_id: String = String(extractor.get("resource_type", RESOURCE_ORE))
|
||||||
|
if _extractor_inventory(extractor).amount(resource_id) < load or _transporter_inbound_to_extractor(i):
|
||||||
continue
|
continue
|
||||||
var chosen_extractor: Dictionary = {}
|
var chosen_extractor: Dictionary = {}
|
||||||
var best_extractor_distance: float = INF
|
var best_extractor_distance: float = INF
|
||||||
|
|
@ -1141,7 +1134,7 @@ func _dispatch_transporters() -> void:
|
||||||
if chosen_extractor.is_empty():
|
if chosen_extractor.is_empty():
|
||||||
return
|
return
|
||||||
chosen_extractor.extractor_index = i
|
chosen_extractor.extractor_index = i
|
||||||
chosen_extractor.resource_type = String(extractor.get("resource_type", "ore"))
|
chosen_extractor.resource_type = resource_id
|
||||||
chosen_extractor.target_id = 0
|
chosen_extractor.target_id = 0
|
||||||
_begin_leg(chosen_extractor, transporter_position(chosen_extractor), extractor.position,
|
_begin_leg(chosen_extractor, transporter_position(chosen_extractor), extractor.position,
|
||||||
TRANSPORTER_TO_EXTRACTOR)
|
TRANSPORTER_TO_EXTRACTOR)
|
||||||
|
|
@ -1192,13 +1185,13 @@ func _arrive(t: Dictionary) -> void:
|
||||||
TRANSPORTER_TO_MOTHERSHIP:
|
TRANSPORTER_TO_MOTHERSHIP:
|
||||||
var target: Dictionary = find_building(int(t.target_id))
|
var target: Dictionary = find_building(int(t.target_id))
|
||||||
var want: int = outstanding_cost(int(t.target_id))
|
var want: int = outstanding_cost(int(t.target_id))
|
||||||
var take: int = mini(mini(want, rocks), transporter_load_limit())
|
var take: int = mini(mini(want, bank_inventory.amount(RESOURCE_ORE)), transporter_load_limit())
|
||||||
if take <= 0 or target.is_empty():
|
if take <= 0 or target.is_empty():
|
||||||
# Nothing to carry, or the building is gone. Go home empty.
|
# Nothing to carry, or the building is gone. Go home empty.
|
||||||
t.target_id = 0
|
t.target_id = 0
|
||||||
_begin_leg(t, here, hub_pos if hub_pos != null else here, TRANSPORTER_RETURNING)
|
_begin_leg(t, here, hub_pos if hub_pos != null else here, TRANSPORTER_RETURNING)
|
||||||
return
|
return
|
||||||
rocks -= take
|
bank_inventory.withdraw(RESOURCE_ORE, take)
|
||||||
t.carrying = take
|
t.carrying = take
|
||||||
_begin_leg(t, here, target.position, TRANSPORTER_TO_BUILDING)
|
_begin_leg(t, here, target.position, TRANSPORTER_TO_BUILDING)
|
||||||
TRANSPORTER_TO_BUILDING:
|
TRANSPORTER_TO_BUILDING:
|
||||||
|
|
@ -1206,7 +1199,7 @@ func _arrive(t: Dictionary) -> void:
|
||||||
if deposit_to_building(int(t.target_id), int(t.carrying)) <= 0:
|
if deposit_to_building(int(t.target_id), int(t.carrying)) <= 0:
|
||||||
# Building demolished in transit - put the ore back rather
|
# Building demolished in transit - put the ore back rather
|
||||||
# than quietly destroying it.
|
# than quietly destroying it.
|
||||||
rocks += int(t.carrying)
|
bank_inventory.deposit(RESOURCE_ORE, int(t.carrying))
|
||||||
t.carrying = 0
|
t.carrying = 0
|
||||||
t.target_id = 0
|
t.target_id = 0
|
||||||
_begin_leg(t, here, hub_pos if hub_pos != null else here, TRANSPORTER_RETURNING)
|
_begin_leg(t, here, hub_pos if hub_pos != null else here, TRANSPORTER_RETURNING)
|
||||||
|
|
@ -1217,20 +1210,19 @@ func _arrive(t: Dictionary) -> void:
|
||||||
return
|
return
|
||||||
var extractor: Dictionary = extractors[extractor_index]
|
var extractor: Dictionary = extractors[extractor_index]
|
||||||
var load: int = transporter_load_limit()
|
var load: int = transporter_load_limit()
|
||||||
if int(extractor.get("stock", 0)) < load:
|
var resource_id: String = String(extractor.get("resource_type", RESOURCE_ORE))
|
||||||
|
var extractor_inventory: RefCounted = _extractor_inventory(extractor)
|
||||||
|
if extractor_inventory.amount(resource_id) < load:
|
||||||
t.extractor_index = -1
|
t.extractor_index = -1
|
||||||
_begin_leg(t, here, hub_pos if hub_pos != null else here, TRANSPORTER_RETURNING)
|
_begin_leg(t, here, hub_pos if hub_pos != null else here, TRANSPORTER_RETURNING)
|
||||||
return
|
return
|
||||||
extractor.stock = int(extractor.stock) - load
|
extractor_inventory.withdraw(resource_id, load)
|
||||||
t.carrying = load
|
t.carrying = load
|
||||||
t.resource_type = String(extractor.get("resource_type", "ore"))
|
t.resource_type = resource_id
|
||||||
_begin_leg(t, here, get_mothership_position(), TRANSPORTER_TO_MOTHERSHIP_FROM_EXTRACTOR)
|
_begin_leg(t, here, get_mothership_position(), TRANSPORTER_TO_MOTHERSHIP_FROM_EXTRACTOR)
|
||||||
TRANSPORTER_TO_MOTHERSHIP_FROM_EXTRACTOR:
|
TRANSPORTER_TO_MOTHERSHIP_FROM_EXTRACTOR:
|
||||||
# Bank only on arrival; cargo retains the extractor's resource type.
|
# Bank only on arrival; cargo retains the extractor's resource type.
|
||||||
if String(t.get("resource_type", "ore")) == "gas":
|
bank_inventory.deposit(String(t.get("resource_type", RESOURCE_ORE)), int(t.carrying))
|
||||||
gas += int(t.carrying)
|
|
||||||
else:
|
|
||||||
rocks += int(t.carrying)
|
|
||||||
t.carrying = 0
|
t.carrying = 0
|
||||||
t.extractor_index = -1
|
t.extractor_index = -1
|
||||||
_begin_leg(t, here, hub_pos if hub_pos != null else here, TRANSPORTER_RETURNING)
|
_begin_leg(t, here, hub_pos if hub_pos != null else here, TRANSPORTER_RETURNING)
|
||||||
|
|
@ -1240,11 +1232,11 @@ func _arrive(t: Dictionary) -> void:
|
||||||
|
|
||||||
|
|
||||||
func can_afford(cost: int) -> bool:
|
func can_afford(cost: int) -> bool:
|
||||||
return rocks >= cost
|
return bank_inventory.amount(RESOURCE_ORE) >= cost
|
||||||
|
|
||||||
|
|
||||||
func spend(cost: int) -> bool:
|
func spend(cost: int) -> bool:
|
||||||
if not can_afford(cost):
|
if not can_afford(cost):
|
||||||
return false
|
return false
|
||||||
rocks -= cost
|
bank_inventory.withdraw(RESOURCE_ORE, cost)
|
||||||
return true
|
return true
|
||||||
|
|
|
||||||
11
GasResourceDefinition.tres
Normal file
11
GasResourceDefinition.tres
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
[gd_resource type="Resource" script_class="ResourceDefinition" load_steps=3 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://ResourceDefinition.gd" id="1"]
|
||||||
|
[ext_resource type="PackedScene" path="res://GasResourceGlyph.tscn" id="2"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("1")
|
||||||
|
resource_id = "gas"
|
||||||
|
display_name = "Gas"
|
||||||
|
color = Color(0.85, 0.52, 1, 1)
|
||||||
|
glyph_scene = ExtResource("2")
|
||||||
19
GasResourceGlyph.gd
Normal file
19
GasResourceGlyph.gd
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
@export var colour: Color = Color(0.85, 0.52, 1.0)
|
||||||
|
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
var centre: Vector2 = size * 0.5
|
||||||
|
var radius: float = minf(size.x, size.y) * 0.34
|
||||||
|
var bubbles: Array = [
|
||||||
|
[centre + Vector2(-radius * 0.38, radius * 0.12), radius * 0.46],
|
||||||
|
[centre + Vector2(radius * 0.34, radius * 0.26), radius * 0.58],
|
||||||
|
[centre + Vector2(radius * 0.38, -radius * 0.48), radius * 0.32],
|
||||||
|
]
|
||||||
|
for bubble in bubbles:
|
||||||
|
var ring := PackedVector2Array()
|
||||||
|
for i in range(12):
|
||||||
|
var angle: float = TAU * float(i) / 12.0
|
||||||
|
ring.append(bubble[0] + Vector2(cos(angle), sin(angle)) * float(bubble[1]))
|
||||||
|
NeonDraw.draw_glowing_polygon(self, ring, colour, 1.0, colour.darkened(0.78), maxf(0.5, radius * 0.035))
|
||||||
1
GasResourceGlyph.gd.uid
Normal file
1
GasResourceGlyph.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://d1ko6yhtjjavx
|
||||||
13
GasResourceGlyph.tscn
Normal file
13
GasResourceGlyph.tscn
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://GasResourceGlyph.gd" id="1"]
|
||||||
|
|
||||||
|
[node name="GlyphVisual" type="Control"]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
mouse_filter = 2
|
||||||
|
script = ExtResource("1")
|
||||||
79
Inventory.gd
Normal file
79
Inventory.gd
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
class_name Inventory
|
||||||
|
extends RefCounted
|
||||||
|
|
||||||
|
var total_capacity: int = -1
|
||||||
|
var resource_capacities: Dictionary = {}
|
||||||
|
var _amounts: Dictionary = {}
|
||||||
|
|
||||||
|
|
||||||
|
func _init(initial: Dictionary = {}, capacity: int = -1) -> void:
|
||||||
|
total_capacity = capacity
|
||||||
|
for resource_id in initial:
|
||||||
|
set_amount(String(resource_id), int(initial[resource_id]))
|
||||||
|
|
||||||
|
|
||||||
|
func amount(resource_id: String) -> int:
|
||||||
|
return int(_amounts.get(resource_id, 0))
|
||||||
|
|
||||||
|
|
||||||
|
func total() -> int:
|
||||||
|
var result: int = 0
|
||||||
|
for value in _amounts.values():
|
||||||
|
result += int(value)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
func capacity_for(resource_id: String) -> int:
|
||||||
|
return int(resource_capacities.get(resource_id, -1))
|
||||||
|
|
||||||
|
|
||||||
|
func space_for(resource_id: String) -> int:
|
||||||
|
var space: int = 1 << 30
|
||||||
|
if total_capacity >= 0:
|
||||||
|
space = maxi(total_capacity - total(), 0)
|
||||||
|
var resource_capacity: int = capacity_for(resource_id)
|
||||||
|
if resource_capacity >= 0:
|
||||||
|
space = mini(space, maxi(resource_capacity - amount(resource_id), 0))
|
||||||
|
return space
|
||||||
|
|
||||||
|
|
||||||
|
func set_amount(resource_id: String, value: int) -> int:
|
||||||
|
_amounts.erase(resource_id)
|
||||||
|
var accepted: int = mini(maxi(value, 0), space_for(resource_id))
|
||||||
|
if accepted > 0:
|
||||||
|
_amounts[resource_id] = accepted
|
||||||
|
return amount(resource_id)
|
||||||
|
|
||||||
|
|
||||||
|
func deposit(resource_id: String, requested: int) -> int:
|
||||||
|
var moved: int = mini(maxi(requested, 0), space_for(resource_id))
|
||||||
|
if moved > 0:
|
||||||
|
_amounts[resource_id] = amount(resource_id) + moved
|
||||||
|
return moved
|
||||||
|
|
||||||
|
|
||||||
|
func withdraw(resource_id: String, requested: int) -> int:
|
||||||
|
var moved: int = mini(maxi(requested, 0), amount(resource_id))
|
||||||
|
if moved <= 0:
|
||||||
|
return 0
|
||||||
|
var remaining: int = amount(resource_id) - moved
|
||||||
|
if remaining > 0:
|
||||||
|
_amounts[resource_id] = remaining
|
||||||
|
else:
|
||||||
|
_amounts.erase(resource_id)
|
||||||
|
return moved
|
||||||
|
|
||||||
|
|
||||||
|
func transfer_to(destination: Inventory, resource_id: String, requested: int) -> int:
|
||||||
|
if destination == null:
|
||||||
|
return 0
|
||||||
|
var moved: int = mini(mini(maxi(requested, 0), amount(resource_id)), destination.space_for(resource_id))
|
||||||
|
if moved <= 0:
|
||||||
|
return 0
|
||||||
|
withdraw(resource_id, moved)
|
||||||
|
destination.deposit(resource_id, moved)
|
||||||
|
return moved
|
||||||
|
|
||||||
|
|
||||||
|
func snapshot() -> Dictionary:
|
||||||
|
return _amounts.duplicate()
|
||||||
1
Inventory.gd.uid
Normal file
1
Inventory.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://celx1yj6cp2rf
|
||||||
11
OreResourceDefinition.tres
Normal file
11
OreResourceDefinition.tres
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
[gd_resource type="Resource" script_class="ResourceDefinition" load_steps=3 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://ResourceDefinition.gd" id="1"]
|
||||||
|
[ext_resource type="PackedScene" path="res://OreResourceGlyph.tscn" id="2"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("1")
|
||||||
|
resource_id = "ore"
|
||||||
|
display_name = "Ore"
|
||||||
|
color = Color(0, 0.72, 0.82, 1)
|
||||||
|
glyph_scene = ExtResource("2")
|
||||||
14
OreResourceGlyph.gd
Normal file
14
OreResourceGlyph.gd
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
@export var colour: Color = Color(0.0, 0.72, 0.82)
|
||||||
|
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
var centre: Vector2 = size * 0.5
|
||||||
|
var radius: float = minf(size.x, size.y) * 0.34
|
||||||
|
var points := PackedVector2Array()
|
||||||
|
for i in range(6):
|
||||||
|
var angle: float = TAU * float(i) / 6.0 - PI * 0.5
|
||||||
|
points.append(centre + Vector2(cos(angle), sin(angle)) * radius)
|
||||||
|
NeonDraw.draw_glowing_polygon(self, points, colour, 1.0, colour.darkened(0.78), maxf(0.5, radius * 0.035))
|
||||||
|
NeonDraw.draw_glowing_line(self, points[5], points[2], colour, 0.55, maxf(0.4, radius * 0.025), colour.darkened(0.78))
|
||||||
1
OreResourceGlyph.gd.uid
Normal file
1
OreResourceGlyph.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://cwgkhqo4ev5ao
|
||||||
13
OreResourceGlyph.tscn
Normal file
13
OreResourceGlyph.tscn
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://OreResourceGlyph.gd" id="1"]
|
||||||
|
|
||||||
|
[node name="GlyphVisual" type="Control"]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
mouse_filter = 2
|
||||||
|
script = ExtResource("1")
|
||||||
|
|
@ -3,7 +3,7 @@ extends Control
|
||||||
|
|
||||||
# Compact resource table shared by crafting, research and the ship lab.
|
# Compact resource table shared by crafting, research and the ship lab.
|
||||||
# Rows are resources; columns are locations. Adding another material to
|
# Rows are resources; columns are locations. Adding another material to
|
||||||
# GameState.RESOURCE_TYPES automatically gives it a row here.
|
# The resource-definition catalog automatically gives each material a row.
|
||||||
|
|
||||||
var building_id: int = 0
|
var building_id: int = 0
|
||||||
|
|
||||||
|
|
@ -24,7 +24,7 @@ func _ready() -> void:
|
||||||
add_child(label)
|
add_child(label)
|
||||||
_header_labels.append(label)
|
_header_labels.append(label)
|
||||||
|
|
||||||
for resource_type in GameState.RESOURCE_TYPES:
|
for resource_type in GameState.resource_types():
|
||||||
var glyph := ResourceGlyph.new()
|
var glyph := ResourceGlyph.new()
|
||||||
glyph.resource_type = resource_type
|
glyph.resource_type = resource_type
|
||||||
add_child(glyph)
|
add_child(glyph)
|
||||||
|
|
@ -78,7 +78,7 @@ func _layout() -> void:
|
||||||
|
|
||||||
var row_height: float = (size.y - HEADER_HEIGHT - 4.0) / maxf(1.0, float(_rows.size()))
|
var row_height: float = (size.y - HEADER_HEIGHT - 4.0) / maxf(1.0, float(_rows.size()))
|
||||||
var row_index: int = 0
|
var row_index: int = 0
|
||||||
for resource_type in GameState.RESOURCE_TYPES:
|
for resource_type in GameState.resource_types():
|
||||||
var row: Dictionary = _rows[resource_type]
|
var row: Dictionary = _rows[resource_type]
|
||||||
var y: float = HEADER_HEIGHT + float(row_index) * row_height
|
var y: float = HEADER_HEIGHT + float(row_index) * row_height
|
||||||
row.glyph.position = Vector2(2.0, y + 2.0)
|
row.glyph.position = Vector2(2.0, y + 2.0)
|
||||||
|
|
@ -94,7 +94,7 @@ func _layout() -> void:
|
||||||
|
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
func _process(_delta: float) -> void:
|
||||||
for resource_type in GameState.RESOURCE_TYPES:
|
for resource_type in GameState.resource_types():
|
||||||
var row: Dictionary = _rows.get(resource_type, {})
|
var row: Dictionary = _rows.get(resource_type, {})
|
||||||
if row.is_empty():
|
if row.is_empty():
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
7
ResourceDefinition.gd
Normal file
7
ResourceDefinition.gd
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
class_name ResourceDefinition
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
@export var resource_id: String = "ore"
|
||||||
|
@export var display_name: String = "Ore"
|
||||||
|
@export var color: Color = Color.WHITE
|
||||||
|
@export var glyph_scene: PackedScene
|
||||||
1
ResourceDefinition.gd.uid
Normal file
1
ResourceDefinition.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://kvy02iu7pbyu
|
||||||
18
ResourceDefinitions.gd
Normal file
18
ResourceDefinitions.gd
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
class_name ResourceDefinitions
|
||||||
|
extends RefCounted
|
||||||
|
|
||||||
|
const ORE_ID: String = "ore"
|
||||||
|
const GAS_ID: String = "gas"
|
||||||
|
const ORDER: PackedStringArray = [ORE_ID, GAS_ID]
|
||||||
|
const DEFINITIONS: Dictionary = {
|
||||||
|
ORE_ID: preload("res://OreResourceDefinition.tres"),
|
||||||
|
GAS_ID: preload("res://GasResourceDefinition.tres"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static func get_definition(resource_id: String) -> Resource:
|
||||||
|
return DEFINITIONS.get(resource_id)
|
||||||
|
|
||||||
|
|
||||||
|
static func ids() -> PackedStringArray:
|
||||||
|
return ORDER
|
||||||
1
ResourceDefinitions.gd.uid
Normal file
1
ResourceDefinitions.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://ci7yyyxyd3o67
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
class_name ResourceGlyph
|
class_name ResourceGlyph
|
||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
|
const RESOURCE_DEFINITIONS = preload("res://ResourceDefinitions.gd")
|
||||||
|
|
||||||
# A small, non-interactive resource mark shared by tables and transfer rows.
|
# A small, non-interactive resource mark shared by tables and transfer rows.
|
||||||
# Resource buttons used to borrow IconButton, which made decorative icons
|
# Resource buttons used to borrow IconButton, which made decorative icons
|
||||||
# look tappable and encouraged each screen to invent its own version.
|
# look tappable and encouraged each screen to invent its own version.
|
||||||
|
|
@ -12,43 +14,21 @@ func set_resource_type(value: String) -> void:
|
||||||
if resource_type == value:
|
if resource_type == value:
|
||||||
return
|
return
|
||||||
resource_type = value
|
resource_type = value
|
||||||
queue_redraw()
|
if is_node_ready():
|
||||||
|
_rebuild_visual()
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
queue_redraw()
|
_rebuild_visual()
|
||||||
|
|
||||||
|
|
||||||
func _draw() -> void:
|
func _rebuild_visual() -> void:
|
||||||
var colour: Color = GameState.resource_color(resource_type)
|
for child in get_children():
|
||||||
var centre: Vector2 = size * 0.5
|
child.queue_free()
|
||||||
var radius: float = minf(size.x, size.y) * 0.34
|
var definition: Resource = RESOURCE_DEFINITIONS.get_definition(resource_type)
|
||||||
match resource_type:
|
if definition == null or definition.glyph_scene == null:
|
||||||
GameState.RESOURCE_GAS:
|
return
|
||||||
_draw_gas(centre, radius, colour)
|
var visual: Control = definition.glyph_scene.instantiate()
|
||||||
_:
|
visual.colour = definition.color
|
||||||
_draw_ore(centre, radius, colour)
|
add_child(visual)
|
||||||
|
|
||||||
|
|
||||||
func _draw_ore(centre: Vector2, radius: float, colour: Color) -> void:
|
|
||||||
var points := PackedVector2Array()
|
|
||||||
for i in range(6):
|
|
||||||
var angle: float = TAU * float(i) / 6.0 - PI * 0.5
|
|
||||||
points.append(centre + Vector2(cos(angle), sin(angle)) * radius)
|
|
||||||
NeonDraw.draw_glowing_polygon(self, points, colour, 1.0, colour.darkened(0.78), maxf(0.5, radius * 0.035))
|
|
||||||
NeonDraw.draw_glowing_line(self, points[5], points[2], colour, 0.55, maxf(0.4, radius * 0.025), colour.darkened(0.78))
|
|
||||||
|
|
||||||
|
|
||||||
func _draw_gas(centre: Vector2, radius: float, colour: Color) -> void:
|
|
||||||
var bubbles: Array = [
|
|
||||||
[centre + Vector2(-radius * 0.38, radius * 0.12), radius * 0.46],
|
|
||||||
[centre + Vector2(radius * 0.34, radius * 0.26), radius * 0.58],
|
|
||||||
[centre + Vector2(radius * 0.38, -radius * 0.48), radius * 0.32],
|
|
||||||
]
|
|
||||||
for bubble in bubbles:
|
|
||||||
var ring := PackedVector2Array()
|
|
||||||
for i in range(12):
|
|
||||||
var angle: float = TAU * float(i) / 12.0
|
|
||||||
ring.append(bubble[0] + Vector2(cos(angle), sin(angle)) * float(bubble[1]))
|
|
||||||
NeonDraw.draw_glowing_polygon(self, ring, colour, 1.0, colour.darkened(0.78), maxf(0.5, radius * 0.035))
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ func _ready() -> void:
|
||||||
_destination_heading.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
_destination_heading.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
add_child(_destination_heading)
|
add_child(_destination_heading)
|
||||||
|
|
||||||
for resource_type in GameState.RESOURCE_TYPES:
|
for resource_type in GameState.resource_types():
|
||||||
var colour: Color = GameState.resource_color(resource_type)
|
var colour: Color = GameState.resource_color(resource_type)
|
||||||
var glyph := ResourceGlyph.new()
|
var glyph := ResourceGlyph.new()
|
||||||
glyph.resource_type = resource_type
|
glyph.resource_type = resource_type
|
||||||
|
|
@ -140,7 +140,7 @@ func set_destination(id: int, heading: String) -> void:
|
||||||
|
|
||||||
|
|
||||||
func refresh() -> void:
|
func refresh() -> void:
|
||||||
for resource_type in GameState.RESOURCE_TYPES:
|
for resource_type in GameState.resource_types():
|
||||||
var row: Dictionary = _rows.get(resource_type, {})
|
var row: Dictionary = _rows.get(resource_type, {})
|
||||||
if row.is_empty():
|
if row.is_empty():
|
||||||
continue
|
continue
|
||||||
|
|
@ -169,7 +169,7 @@ func _layout() -> void:
|
||||||
|
|
||||||
var row_height: float = (size.y - HEADER_HEIGHT) / maxf(1.0, float(_rows.size()))
|
var row_height: float = (size.y - HEADER_HEIGHT) / maxf(1.0, float(_rows.size()))
|
||||||
var row_index: int = 0
|
var row_index: int = 0
|
||||||
for resource_type in GameState.RESOURCE_TYPES:
|
for resource_type in GameState.resource_types():
|
||||||
var row: Dictionary = _rows[resource_type]
|
var row: Dictionary = _rows[resource_type]
|
||||||
var y: float = HEADER_HEIGHT + float(row_index) * row_height
|
var y: float = HEADER_HEIGHT + float(row_index) * row_height
|
||||||
var glyph_size: float = minf(66.0, row_height * 0.23)
|
var glyph_size: float = minf(66.0, row_height * 0.23)
|
||||||
|
|
|
||||||
48
tests/test_generic_inventory.gd
Normal file
48
tests/test_generic_inventory.gd
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
extends SceneTree
|
||||||
|
|
||||||
|
const INVENTORY = preload("res://Inventory.gd")
|
||||||
|
const TEST_RESOURCE: String = "crystal"
|
||||||
|
|
||||||
|
|
||||||
|
func _initialize() -> void:
|
||||||
|
var game_state: Node = root.get_node("GameState")
|
||||||
|
game_state.buildings.clear()
|
||||||
|
game_state.bank_inventory.set_amount(TEST_RESOURCE, 40)
|
||||||
|
game_state.fleet_inventory.set_amount(TEST_RESOURCE, 0)
|
||||||
|
|
||||||
|
var mothership_id: int = game_state.add_building(GameState.BUILDING_MOTHERSHIP, Vector2.ZERO)
|
||||||
|
var crafter_id: int = game_state.add_building(GameState.BUILDING_SHIP_CRAFTER, Vector2(100, 0))
|
||||||
|
if game_state.transfer_resource_to_fleet(mothership_id, TEST_RESOURCE, 15) != 15:
|
||||||
|
return _fail("third resource could not move from bank to fleet")
|
||||||
|
if game_state.transfer_resource_to_building(crafter_id, TEST_RESOURCE, 9) != 9:
|
||||||
|
return _fail("third resource could not move from fleet to building")
|
||||||
|
if game_state.transfer_resource_to_fleet(crafter_id, TEST_RESOURCE, 4) != 4:
|
||||||
|
return _fail("third resource could not move back out of building")
|
||||||
|
if game_state.banked_resource(TEST_RESOURCE) != 25 \
|
||||||
|
or game_state.fleet_resource(TEST_RESOURCE) != 10 \
|
||||||
|
or game_state.building_resource(crafter_id, TEST_RESOURCE) != 5:
|
||||||
|
return _fail("third-resource amounts were not conserved")
|
||||||
|
|
||||||
|
var limited: RefCounted = INVENTORY.new({}, 10)
|
||||||
|
limited.resource_capacities[TEST_RESOURCE] = 6
|
||||||
|
if limited.deposit(TEST_RESOURCE, 99) != 6 or limited.deposit("water", 99) != 4:
|
||||||
|
return _fail("total or per-resource capacity was not enforced")
|
||||||
|
|
||||||
|
var legacy_id: int = game_state.next_building_id
|
||||||
|
game_state.next_building_id += 1
|
||||||
|
game_state.buildings.append({"id": legacy_id, "type": GameState.BUILDING_SHIP_CRAFTER,
|
||||||
|
"position": Vector2.ZERO, "stock": 7, "gas_stock": 3, "orders": []})
|
||||||
|
if game_state.building_resource(legacy_id, GameState.RESOURCE_ORE) != 7 \
|
||||||
|
or game_state.building_resource(legacy_id, GameState.RESOURCE_GAS) != 3:
|
||||||
|
return _fail("legacy building stock was not migrated")
|
||||||
|
var migrated: Dictionary = game_state.find_building(legacy_id)
|
||||||
|
if migrated.has("stock") or migrated.has("gas_stock") or not migrated.has("inventory"):
|
||||||
|
return _fail("legacy fields remained after migration")
|
||||||
|
|
||||||
|
print("TEST_GENERIC_INVENTORY: PASS")
|
||||||
|
quit(0)
|
||||||
|
|
||||||
|
|
||||||
|
func _fail(message: String) -> void:
|
||||||
|
print("TEST_GENERIC_INVENTORY: FAIL (%s)" % message)
|
||||||
|
quit(1)
|
||||||
1
tests/test_generic_inventory.gd.uid
Normal file
1
tests/test_generic_inventory.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://53pexhmp3ns0
|
||||||
|
|
@ -42,7 +42,8 @@ const CRAFTER_AT: Vector2 = Vector2(3000.0, 0.0)
|
||||||
func _total() -> int:
|
func _total() -> int:
|
||||||
var sum: int = game_state.rocks + game_state.fleet_cargo
|
var sum: int = game_state.rocks + game_state.fleet_cargo
|
||||||
for b in game_state.buildings:
|
for b in game_state.buildings:
|
||||||
sum += int(b.get("stock", 0))
|
if b.type != GameState.BUILDING_MOTHERSHIP:
|
||||||
|
sum += game_state.building_resource(int(b.id), GameState.RESOURCE_ORE)
|
||||||
return sum
|
return sum
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ func _total() -> int:
|
||||||
var sum: int = game_state.rocks + game_state.fleet_cargo
|
var sum: int = game_state.rocks + game_state.fleet_cargo
|
||||||
for b in game_state.buildings:
|
for b in game_state.buildings:
|
||||||
if b.type != GameState.BUILDING_MOTHERSHIP:
|
if b.type != GameState.BUILDING_MOTHERSHIP:
|
||||||
sum += int(b.get("stock", 0))
|
sum += game_state.building_resource(int(b.id), GameState.RESOURCE_ORE)
|
||||||
return sum
|
return sum
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ func _process(delta: float) -> bool:
|
||||||
match stage:
|
match stage:
|
||||||
0:
|
0:
|
||||||
# --- gather a rock -------------------------------------------
|
# --- gather a rock -------------------------------------------
|
||||||
scene.get_node("RockField").set_process(false)
|
scene.get_node("SurfaceFeatures/ResourceProvider").set_process(false)
|
||||||
rock = load("res://Rock.tscn").instantiate()
|
rock = load("res://Rock.tscn").instantiate()
|
||||||
rock.build_shape(1)
|
rock.build_shape(1)
|
||||||
# Placed OUTSIDE the pickup shape but inside attract_radius, so
|
# Placed OUTSIDE the pickup shape but inside attract_radius, so
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,8 @@ const CRAFTER_AT: Vector2 = Vector2(900.0, -300.0)
|
||||||
func _total() -> int:
|
func _total() -> int:
|
||||||
var sum: int = game_state.rocks + game_state.fleet_cargo
|
var sum: int = game_state.rocks + game_state.fleet_cargo
|
||||||
for b in game_state.buildings:
|
for b in game_state.buildings:
|
||||||
sum += int(b.get("stock", 0))
|
if b.type != GameState.BUILDING_MOTHERSHIP:
|
||||||
|
sum += game_state.building_resource(int(b.id), GameState.RESOURCE_ORE)
|
||||||
for t in game_state.transporters:
|
for t in game_state.transporters:
|
||||||
sum += int(t.get("carrying", 0))
|
sum += int(t.get("carrying", 0))
|
||||||
# Ore inside a build that has STARTED but not finished (#23). It has left
|
# Ore inside a build that has STARTED but not finished (#23). It has left
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue