Typed owed vessels, ship lab building type, shield vessel gate

Groundwork for #5. vessels_owed carries the VESSEL TYPE rather than a
bare count, so a shield vessel finishing while the player is on a planet
comes back as a shield vessel. Fleet.add_ship takes a type, and vessels
already flying are re-statted when an upgrade is researched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Loïc Wisniewski 2026-08-11 23:10:07 +02:00
commit 19ac758da1
9 changed files with 80 additions and 27 deletions

View file

@ -104,10 +104,13 @@ const BUILDING_EXTRACTOR: String = "extractor"
# Hosts the transport vessels that supply other buildings (#18). Built in
# space like the rest; it is the transporters (#19) that do the moving.
const BUILDING_TRANSPORT_HUB: String = "transport_hub"
# Where vessel types are researched and new ones unlocked (#5).
const BUILDING_SHIP_LAB: String = "ship_lab"
const COMMAND_CENTER_COST: int = 15
const EXTRACTOR_COST: int = 25
const TRANSPORT_HUB_COST: int = 30
const SHIP_LAB_COST: int = 35
var buildings: Array = []
@ -145,6 +148,11 @@ const SKILL_TREE: Array = [
"x": 0.18, "unlocks": BUILDING_TRANSPORT_HUB,
"desc": "Build transport hubs, which supply your other buildings with ore.",
},
{
"id": "vessel_science", "name": "Vessel Science", "cost": 35, "requires": "shipyards",
"x": 0.62, "unlocks": BUILDING_SHIP_LAB,
"desc": "Build ship labs, where each vessel type is upgraded and new ones unlocked.",
},
{
"id": "freight_yards", "name": "Freight Yards", "cost": 80, "requires": "freight",
"x": 0.05, "hub_bonus": 1,
@ -269,12 +277,12 @@ func reset_progression() -> void:
# on the same spot.
var next_building_id: int = 1
# Ships that have been paid for and built but not yet handed to the fleet.
# Production is simulated here, in the autoload, the same way extractor
# haulers are - so an order can complete while the player is down on a
# planet's surface, where there is no Fleet node to hand a ship to. The fleet
# claims them when it next can.
var ships_owed: int = 0
# Vessels that have been paid for and built but not yet handed to the fleet,
# as a list of VESSEL_* types - a shield vessel finishing while the player is
# on a planet must not come back as an interceptor. Production is simulated
# here, in the autoload, the same way extractor haulers are, so an order can
# complete where there is no Fleet node to hand a ship to.
var vessels_owed: Array = []
signal order_completed(building_id: int, type: String)
@ -372,6 +380,33 @@ var vessel_levels: Dictionary = {}
signal vessel_upgraded(upgrade_id: String)
func has_ship_lab() -> bool:
for b in buildings:
if b.type == BUILDING_SHIP_LAB:
return true
return false
func shield_vessel_unlocked() -> bool:
# Unlocked AT the lab, by paying for it there - a vessel type rather than
# a stat, so it is a one-off rather than a level.
return int(vessel_levels.get(UNLOCK_SHIELD_VESSEL, 0)) > 0
const UNLOCK_SHIELD_VESSEL: String = "unlock_shield"
const UNLOCK_SHIELD_COST: int = 45
func unlock_shield_vessel() -> bool:
if shield_vessel_unlocked() or not has_ship_lab():
return false
if not spend(UNLOCK_SHIELD_COST):
return false
vessel_levels[UNLOCK_SHIELD_VESSEL] = 1
vessel_upgraded.emit(UNLOCK_SHIELD_VESSEL)
return true
func upgrade_def(id: String) -> Dictionary:
for u in VESSEL_UPGRADES:
if u.id == id:
@ -404,7 +439,7 @@ func upgrade_cost(id: String) -> int:
func can_buy_upgrade(id: String) -> bool:
return not upgrade_maxed(id) and can_afford(upgrade_cost(id))
return has_ship_lab() and not upgrade_maxed(id) and can_afford(upgrade_cost(id))
func buy_upgrade(id: String) -> bool:
@ -531,6 +566,8 @@ func queue_order(id: int, product: String = PRODUCT_SHIP) -> bool:
var b: Dictionary = find_building(id)
if b.is_empty() or not can_produce(b.type):
return false
if product == VESSEL_SHIELD and not shield_vessel_unlocked():
return false
if product == PRODUCT_TRANSPORTER and not has_transport_hub():
# Nowhere to station it. Refused rather than queued, so the player is
# told now instead of watching an order sit forever.
@ -570,7 +607,7 @@ func _advance_production() -> void:
if product == PRODUCT_TRANSPORTER:
_station_transporter(b.position)
else:
ships_owed += 1
vessels_owed.append(product)
order_completed.emit(int(b.id), product)