Repair a broken working tree, and make every crafter press report
The crafter buttons doing nothing was not the crafter: Ship.gd was left mid-edit and failed to parse (undeclared SHIELD_COLOR/SHIELD_RADIUS, and a spawn() that only exists on the concrete VFX subclass). A script that does not compile takes Main.tscn's whole node tree with it, so every button in the game was dead. The project directory is the one being played from, so an unfinished edit there is a broken build - finish or revert before stopping. With that fixed, the real gap underneath: an order the crafter cannot pay for is ACCEPTED and queued (#16), which is indistinguishable from a dead button. Ordering now reports either "building now" or "queued - N more ore must be delivered here", and the transient message is rendered LAST so it is the first line read rather than buried under the standing fleet-capacity note. test_crafter_feedback covers all three presses and asserts the message survives the per-frame refresh, which is the specific way this looked broken before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
0e071877e2
commit
004808f067
6 changed files with 413 additions and 14 deletions
94
Ship.gd
94
Ship.gd
|
|
@ -17,6 +17,21 @@ signal destroyed
|
|||
@export var idle_rescan_interval: float = 0.25
|
||||
@export var projectile_damage: int = 1
|
||||
|
||||
# Which kind of vessel this is (GameState.VESSEL_*). Drives both its
|
||||
# researched statistics and whether it carries a shield (#5).
|
||||
@export var vessel_type: String = "interceptor"
|
||||
|
||||
# --- shield (#5) ----------------------------------------------------------
|
||||
const SHIELD_COLOR: Color = Color(0.45, 0.8, 1.0)
|
||||
const SHIELD_RADIUS: float = 30.0
|
||||
|
||||
# A shield vessel survives a hit that would destroy any other ship, and is
|
||||
# then defenceless until it cycles back up. Personal, not a bubble: it
|
||||
# protects the vessel carrying it and nothing else.
|
||||
var shield_charges: int = 0
|
||||
var shield_recharge_left: float = 0.0
|
||||
var _shield_ring: Node2D = null
|
||||
|
||||
# Neon colours, assigned by Fleet on spawn so a scene can tint its fleet.
|
||||
# The lunar surface is a bright grey, where the default near-white core all
|
||||
# but vanishes - PlanetSurface.tscn passes a dark core there. See NeonDraw.
|
||||
|
|
@ -46,6 +61,10 @@ func _ready() -> void:
|
|||
move_target = position
|
||||
add_to_group("player_ships")
|
||||
area_entered.connect(_on_area_entered)
|
||||
if vessel_type == GameState.VESSEL_SHIELD:
|
||||
_build_shield_ring()
|
||||
shield_charges = GameState.shield_max_charges()
|
||||
apply_vessel_stats()
|
||||
queue_redraw()
|
||||
|
||||
|
||||
|
|
@ -53,7 +72,49 @@ func set_move_target(world_pos: Vector2) -> void:
|
|||
move_target = world_pos
|
||||
|
||||
|
||||
func apply_vessel_stats() -> void:
|
||||
# Read from GameState rather than baked in at spawn, so researching an
|
||||
# upgrade improves the ships already flying and not just the next one
|
||||
# built. Fleet calls this on every vessel when something is bought.
|
||||
max_speed = GameState.ship_max_speed(vessel_type)
|
||||
acceleration = GameState.ship_acceleration(vessel_type)
|
||||
fire_range = GameState.ship_fire_range(vessel_type)
|
||||
fire_cooldown = GameState.ship_fire_cooldown(vessel_type)
|
||||
projectile_damage = GameState.ship_damage(vessel_type)
|
||||
if vessel_type == GameState.VESSEL_SHIELD:
|
||||
# Topping up a live shield with researched capacity, without
|
||||
# refilling one that is currently down and cycling.
|
||||
var was_up: bool = shield_charges > 0
|
||||
shield_charges = GameState.shield_max_charges() if was_up else shield_charges
|
||||
_update_shield_visual()
|
||||
|
||||
|
||||
func has_shield() -> bool:
|
||||
return vessel_type == GameState.VESSEL_SHIELD and shield_charges > 0
|
||||
|
||||
|
||||
func _update_shield_visual() -> void:
|
||||
if _shield_ring == null:
|
||||
return
|
||||
# visible only - per #10 the ring is rasterised once and never redrawn to
|
||||
# turn it on and off.
|
||||
_shield_ring.visible = has_shield()
|
||||
|
||||
|
||||
func _tick_shield(delta: float) -> void:
|
||||
if vessel_type != GameState.VESSEL_SHIELD:
|
||||
return
|
||||
if shield_charges >= GameState.shield_max_charges():
|
||||
return
|
||||
shield_recharge_left -= delta
|
||||
if shield_recharge_left <= 0.0:
|
||||
shield_charges += 1
|
||||
shield_recharge_left = GameState.shield_recharge_time()
|
||||
_update_shield_visual()
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
_tick_shield(delta)
|
||||
var to_target: Vector2 = move_target - position
|
||||
var distance: float = to_target.length()
|
||||
|
||||
|
|
@ -122,10 +183,35 @@ func _find_nearest_enemy() -> Node2D:
|
|||
|
||||
|
||||
func _on_area_entered(area: Area2D) -> void:
|
||||
if area.is_in_group("enemies") or area.is_in_group("asteroids"):
|
||||
ShipExplosionVFX.spawn(get_tree().root, position)
|
||||
destroyed.emit()
|
||||
queue_free()
|
||||
if not (area.is_in_group("enemies") or area.is_in_group("asteroids")):
|
||||
return
|
||||
if has_shield():
|
||||
# Absorbed. The thing that hit it is still destroyed - a shield stops
|
||||
# the vessel dying, it does not make the rock harmless - but the
|
||||
# vessel survives and is defenceless until the shield cycles back.
|
||||
shield_charges -= 1
|
||||
shield_recharge_left = GameState.shield_recharge_time()
|
||||
_update_shield_visual()
|
||||
if area.is_in_group("asteroids") and is_instance_valid(area):
|
||||
area.queue_free()
|
||||
return
|
||||
ShipExplosionVFX.spawn(get_tree().root, position)
|
||||
destroyed.emit()
|
||||
queue_free()
|
||||
|
||||
|
||||
func _build_shield_ring() -> void:
|
||||
# Its own child, drawn once, toggled with `visible` (#10). A shield that
|
||||
# came and went by redrawing the ship would re-tessellate the hull every
|
||||
# time it cycled.
|
||||
_shield_ring = NeonPiece.create(self, Vector2.ZERO, SHIELD_COLOR)
|
||||
var points: PackedVector2Array = PackedVector2Array()
|
||||
for i in range(14):
|
||||
var a: float = (float(i) / 14.0) * TAU
|
||||
points.append(Vector2(cos(a), sin(a)) * SHIELD_RADIUS)
|
||||
_shield_ring.add_polygon(points, 0.7)
|
||||
_shield_ring.queue_redraw()
|
||||
_shield_ring.visible = false
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
|
|
|
|||
Loading…
Reference in a new issue