96 lines
3.1 KiB
GDScript3
96 lines
3.1 KiB
GDScript3
|
|
extends Node2D
|
||
|
|
|
||
|
|
# #105 (#97g): keeps the vessels stationed at outposts in step with what
|
||
|
|
# GameState says is stationed there.
|
||
|
|
#
|
||
|
|
# Garrison vessels are NOT in Fleet.ships. They are spawned here, under a
|
||
|
|
# node of their own, so the formation, the fleet's speed fader and
|
||
|
|
# max_fleet_size() all continue to be about the fleet - a garrison that
|
||
|
|
# counted against the fleet's slots would mean stationing a vessel cost the
|
||
|
|
# player a place in their own wedge, which is the opposite of what an outpost
|
||
|
|
# is for.
|
||
|
|
#
|
||
|
|
# The record is the truth, as everywhere else: this node is rebuilt from
|
||
|
|
# GameState.garrison_crew() when the space scene loads, so a garrison
|
||
|
|
# survives a trip to a planet surface.
|
||
|
|
|
||
|
|
var ship_scene: PackedScene = preload("res://vessels/Ship.tscn")
|
||
|
|
const GARRISON_COMPONENT = preload("res://vessels/VesselGarrisonComponent.gd")
|
||
|
|
|
||
|
|
# {outpost_id: [ship, ...]}
|
||
|
|
var stationed: Dictionary = {}
|
||
|
|
|
||
|
|
|
||
|
|
func _ready() -> void:
|
||
|
|
add_to_group("garrison_field")
|
||
|
|
sync()
|
||
|
|
|
||
|
|
|
||
|
|
func _process(_delta: float) -> void:
|
||
|
|
sync()
|
||
|
|
|
||
|
|
|
||
|
|
func ships_at(outpost_id: int) -> Array:
|
||
|
|
var out: Array = []
|
||
|
|
for ship in stationed.get(outpost_id, []):
|
||
|
|
if is_instance_valid(ship) and not ship.is_queued_for_deletion():
|
||
|
|
out.append(ship)
|
||
|
|
return out
|
||
|
|
|
||
|
|
|
||
|
|
func all_ships() -> Array:
|
||
|
|
var out: Array = []
|
||
|
|
for outpost_id in stationed:
|
||
|
|
out.append_array(ships_at(outpost_id))
|
||
|
|
return out
|
||
|
|
|
||
|
|
|
||
|
|
func sync() -> void:
|
||
|
|
# Retire whole outposts that no longer exist, then reconcile the rest.
|
||
|
|
for outpost_id in stationed.keys():
|
||
|
|
if GameState.find_building(outpost_id).is_empty():
|
||
|
|
for ship in ships_at(outpost_id):
|
||
|
|
ship.queue_free()
|
||
|
|
stationed.erase(outpost_id)
|
||
|
|
|
||
|
|
for outpost_id in GameState.outpost_ids():
|
||
|
|
var record: Dictionary = GameState.find_building(outpost_id)
|
||
|
|
var crew: Array = GameState.garrison_crew(outpost_id)
|
||
|
|
var here: Array = ships_at(outpost_id)
|
||
|
|
stationed[outpost_id] = here
|
||
|
|
if here.size() == crew.size():
|
||
|
|
continue
|
||
|
|
if here.size() > crew.size():
|
||
|
|
# The record shrank under us - a vessel was released or lost
|
||
|
|
# while this node was not looking.
|
||
|
|
for i in range(crew.size(), here.size()):
|
||
|
|
here[i].queue_free()
|
||
|
|
stationed[outpost_id] = here.slice(0, crew.size())
|
||
|
|
continue
|
||
|
|
for i in range(here.size(), crew.size()):
|
||
|
|
here.append(_spawn(outpost_id, String(crew[i]), record.position, i))
|
||
|
|
|
||
|
|
|
||
|
|
func _spawn(outpost_id: int, vessel_type: String, at: Vector2, index: int) -> Node2D:
|
||
|
|
var ship: Area2D = ship_scene.instantiate()
|
||
|
|
# Before add_child, so Ship._ready() builds the right vessel - the same
|
||
|
|
# order Fleet.add_ship() relies on.
|
||
|
|
ship.vessel_type = vessel_type
|
||
|
|
var spread: float = TAU * float(index) / 4.0
|
||
|
|
ship.position = at + Vector2(cos(spread), sin(spread)) * 170.0
|
||
|
|
add_child(ship)
|
||
|
|
var component: Node = GARRISON_COMPONENT.new()
|
||
|
|
component.outpost_id = outpost_id
|
||
|
|
component.station = at
|
||
|
|
ship.add_child(component)
|
||
|
|
component.setup()
|
||
|
|
# A garrison vessel that dies frees its berth, so #104 sends another.
|
||
|
|
ship.destroyed.connect(_on_garrison_lost.bind(outpost_id, vessel_type))
|
||
|
|
return ship
|
||
|
|
|
||
|
|
|
||
|
|
func _on_garrison_lost(outpost_id: int, vessel_type: String) -> void:
|
||
|
|
var crew: Array = GameState.garrison_crew(outpost_id)
|
||
|
|
var index: int = crew.find(vessel_type)
|
||
|
|
if index >= 0:
|
||
|
|
crew.remove_at(index)
|