spaceship/GasVentField.gd
Loïc Wisniewski f040327523 Cap fleet cargo capacity by composition (#56)
The fleet hold was unbounded - GameState.fleet_inventory had no
total_capacity, so a lone ship could carry unlimited resources. Capacity
is now data-driven: only vessels declaring the "cargo" capability
contribute their cargo_capacity stat (interceptor: 20; shield vessel and
gas bomber: 0, unarmed transporters are never in the fleet at all).
Fleet.gd recomputes it in the one place composition can change
(spawn_ships/add_ship/store_ship/_on_ship_destroyed), which also covers
the space<->surface scene-swap restore since that goes through
spawn_ships().

Rock.gd and GasVentField.gd (the two "fly over it to collect" pickup
paths) now check what collect_cargo()/collect_gas_cargo() actually
accepted before consuming their source, instead of assuming an
unlimited hold. The HUD's FLEET HOLD caption shows the live total/cap.

Also fixes test_resource_transfer.gd, which pushed more ore through a
2-ship fleet than the new cap allows - it now spawns the largest fleet
every unlocked doctrine permits, since that test is about the transfer
UI rather than the cap itself (test_fleet_cargo_limit.gd owns that).
2026-08-16 14:53:26 +02:00

65 lines
2.4 KiB
GDScript

extends Node2D
@export var fleet_path: NodePath = NodePath("../Fleet")
@onready var fleet: Node2D = get_node(fleet_path)
var vents: Array[Vector2] = []
var progress: float = 0.0
var emission_phase: float = 0.0
func _ready() -> void:
var rng := RandomNumberGenerator.new()
rng.seed = hash(GameState.planet_id if GameState.planet_id != "" else GameState.planet_name)
for i in range(6): vents.append(Vector2(rng.randf_range(-800,800), rng.randf_range(-650,650)))
queue_redraw()
func _process(delta: float) -> void:
emission_phase = fmod(emission_phase + delta * 0.55, 1.0)
queue_redraw()
for vent in vents:
if fleet.get_centroid().distance_to(vent) < 90.0:
progress += delta
if progress >= 1.0:
# #56: a full fleet hold rejects the deposit - keep the
# undelivered whole units in progress rather than discarding
# them, so gas is only ever lost by not gathering it.
var whole: int = int(progress)
progress -= float(GameState.collect_gas_cargo(whole))
return
progress = 0.0
func _draw() -> void:
for vent in vents:
_draw_gas_source(vent)
_draw_emission(vent)
func _draw_gas_source(centre: Vector2) -> void:
var colour := Color(0.85, 0.52, 1.0)
var core := Color(0.15, 0.03, 0.22)
var bubbles: Array = [
[centre + Vector2(-20.0, 8.0), 20.0],
[centre + Vector2(18.0, 14.0), 27.0],
[centre + Vector2(17.0, -22.0), 15.0],
]
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, 0.9, core, 0.6)
func _draw_emission(centre: Vector2) -> void:
# Small bubbles continuously rise out of every source. This remains
# animated even when the fleet is not collecting, so the vent reads as
# an active gas generator rather than a static decoration.
var core := Color(0.15, 0.03, 0.22)
for i in range(4):
var travel: float = fmod(emission_phase + float(i) * 0.25, 1.0)
var bubble_centre := centre + Vector2(
sin((travel + float(i)) * TAU) * 11.0,
-48.0 - travel * 92.0
)
var radius: float = lerpf(5.0, 14.0, travel)
var colour := Color(0.92, 0.68, 1.0, 1.0 - travel * 0.72)
var ring := PackedVector2Array()
for point in range(10):
var angle: float = TAU * float(point) / 10.0
ring.append(bubble_centre + Vector2(cos(angle), sin(angle)) * radius)
NeonDraw.draw_glowing_polygon(self, ring, colour, 0.75, core, 0.45)