Compose buildings from definitions and capabilities

This commit is contained in:
Loïc Wisniewski 2026-08-14 21:44:28 +02:00
commit 0504b24d8d
46 changed files with 1091 additions and 878 deletions

View file

@ -2,6 +2,7 @@ extends Node
const INVENTORY = preload("res://Inventory.gd")
const RESOURCE_DEFINITIONS = preload("res://ResourceDefinitions.gd")
const BUILDING_DEFINITIONS = preload("res://BuildingDefinitions.gd")
# Autoload singleton - the one thing that survives change_scene_to_file()
@ -104,7 +105,7 @@ func building_inventory(id: int) -> RefCounted:
var building: Dictionary = find_building(id)
if building.is_empty():
return null
if building.type == BUILDING_MOTHERSHIP:
if building_has_capability(building, "bank"):
return bank_inventory
return _inventory_for_record(building)
@ -313,11 +314,6 @@ func unlock(id: String) -> bool:
func is_building_unlocked(type: String) -> bool:
# The mothership is always buildable: it is where research happens, so
# locking it would leave a player with no mothership unable to ever get
# one.
if type == BUILDING_MOTHERSHIP:
return true
for node in SKILL_TREE:
if node.get("unlocks", "") == type:
return is_unlocked(node.id)
@ -392,6 +388,13 @@ func find_building(id: int) -> Dictionary:
return {}
func building_has_capability(building: Dictionary, capability: String) -> bool:
if building.is_empty():
return false
var definition: Resource = BUILDING_DEFINITIONS.get_definition(String(building.type))
return definition != null and capability in definition.capabilities
# --- vessel types and their upgrades (#5) ---------------------------------
# The three things that can be flying around. The first and last double as
@ -494,7 +497,7 @@ signal vessel_upgraded(upgrade_id: String)
func has_ship_lab() -> bool:
for b in buildings:
if b.type == BUILDING_SHIP_LAB:
if building_has_capability(b, "vessel_research"):
return true
return false
@ -627,9 +630,8 @@ func product_cost(product: String) -> int:
func can_produce(type: String) -> bool:
# Only the ship crafter builds anything. The hub STATIONS transporters,
# it does not make them (#12).
return type == BUILDING_SHIP_CRAFTER
var definition: Resource = BUILDING_DEFINITIONS.get_definition(type)
return definition != null and "production" in definition.capabilities
func building_stock(id: int) -> int:
@ -777,7 +779,7 @@ func _advance_production(delta: float) -> void:
func queue_lab_research(lab_id: int, upgrade_id: String) -> bool:
var lab: Dictionary = find_building(lab_id)
if lab.is_empty() or lab.type != BUILDING_SHIP_LAB or upgrade_id == "":
if not building_has_capability(lab, "vessel_research") or upgrade_id == "":
return false
var orders: Array = lab.get("research_orders", [])
if not orders.is_empty() or (upgrade_id != UNLOCK_SHIELD_VESSEL and upgrade_maxed(upgrade_id)):
@ -795,7 +797,7 @@ func lab_research_order(lab_id: int) -> Dictionary:
func _advance_lab_research(delta: float) -> void:
for lab in buildings:
if lab.type != BUILDING_SHIP_LAB:
if not building_has_capability(lab, "vessel_research"):
continue
var orders: Array = lab.get("research_orders", [])
if orders.is_empty():
@ -841,6 +843,13 @@ func has_mothership() -> bool:
return get_mothership_position() != null
func has_building_of_type(type: String) -> bool:
for building in buildings:
if building.type == type:
return true
return false
func remove_buildings_of_type(type: String) -> int:
var kept: Array = []
var removed: int = 0
@ -857,7 +866,7 @@ func get_mothership_position() -> Variant:
# Where a wiped-out fleet gets rebuilt. Returns null when no mothership
# has been built yet, so the caller can fall back to the world origin.
for b in buildings:
if b.type == BUILDING_MOTHERSHIP:
if building_has_capability(b, "bank"):
return b.position
return null
@ -1017,7 +1026,7 @@ func hub_capacity() -> int:
func hub_count() -> int:
var n: int = 0
for b in buildings:
if b.type == BUILDING_TRANSPORT_HUB:
if building_has_capability(b, "transport_hub"):
n += 1
return n
@ -1056,7 +1065,7 @@ func nearest_hub_to(at: Vector2) -> Dictionary:
var best: Dictionary = {}
var best_d: float = INF
for b in buildings:
if b.type != BUILDING_TRANSPORT_HUB:
if not building_has_capability(b, "transport_hub"):
continue
var d: float = at.distance_squared_to(b.position)
if d < best_d: