2026-08-15 10:12:33 +02:00
|
|
|
class_name VesselGasBomberComponent
|
|
|
|
|
extends Node2D
|
2026-08-15 04:45:15 +02:00
|
|
|
|
|
|
|
|
var capability_id := "gas_bomber"
|
2026-08-15 10:12:33 +02:00
|
|
|
var cooldown_duration := 5.0
|
|
|
|
|
var cooldown_left := 0.0
|
|
|
|
|
|
|
|
|
|
const READY_COLOR := Color(1.0, 0.25, 0.78)
|
|
|
|
|
const COOLING_COLOR := Color(0.38, 0.16, 0.32)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func setup() -> void:
|
2026-08-15 10:41:24 +02:00
|
|
|
# Keep the ship's normal neon outline above the charge fill.
|
|
|
|
|
show_behind_parent = true
|
2026-08-15 10:12:33 +02:00
|
|
|
queue_redraw()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func is_ready() -> bool:
|
|
|
|
|
return cooldown_left <= 0.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func consume_shot(duration: float) -> bool:
|
|
|
|
|
if not is_ready():
|
|
|
|
|
return false
|
|
|
|
|
cooldown_duration = maxf(duration, 0.001)
|
|
|
|
|
cooldown_left = cooldown_duration
|
|
|
|
|
queue_redraw()
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func tick(delta: float) -> void:
|
|
|
|
|
if cooldown_left <= 0.0:
|
|
|
|
|
return
|
|
|
|
|
cooldown_left = maxf(cooldown_left - delta, 0.0)
|
|
|
|
|
queue_redraw()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func cooldown_progress() -> float:
|
|
|
|
|
return 1.0 - cooldown_left / maxf(cooldown_duration, 0.001)
|
|
|
|
|
|
|
|
|
|
|
2026-08-15 10:41:24 +02:00
|
|
|
func _filled_hull(points: PackedVector2Array, progress: float) -> PackedVector2Array:
|
|
|
|
|
if points.size() < 3 or progress <= 0.001:
|
|
|
|
|
return PackedVector2Array()
|
|
|
|
|
if progress >= 0.999:
|
|
|
|
|
return points.duplicate()
|
|
|
|
|
var top := INF
|
|
|
|
|
var bottom := -INF
|
|
|
|
|
for point in points:
|
|
|
|
|
top = minf(top, point.y)
|
|
|
|
|
bottom = maxf(bottom, point.y)
|
|
|
|
|
var fill_y: float = lerpf(bottom, top, clampf(progress, 0.0, 1.0))
|
|
|
|
|
var clipped := PackedVector2Array()
|
|
|
|
|
var previous: Vector2 = points[-1]
|
|
|
|
|
var previous_inside := previous.y >= fill_y
|
|
|
|
|
for current in points:
|
|
|
|
|
var current_inside := current.y >= fill_y
|
|
|
|
|
if current_inside != previous_inside:
|
|
|
|
|
var amount: float = (fill_y - previous.y) / (current.y - previous.y)
|
|
|
|
|
clipped.append(previous.lerp(current, amount))
|
|
|
|
|
if current_inside:
|
|
|
|
|
clipped.append(current)
|
|
|
|
|
previous = current
|
|
|
|
|
previous_inside = current_inside
|
|
|
|
|
return clipped
|
|
|
|
|
|
|
|
|
|
|
2026-08-15 10:12:33 +02:00
|
|
|
func _draw() -> void:
|
|
|
|
|
var parent_ship: Node = get_parent()
|
2026-08-15 10:41:24 +02:00
|
|
|
if parent_ship == null or parent_ship.definition == null:
|
|
|
|
|
return
|
2026-08-15 10:12:33 +02:00
|
|
|
var core: Color = parent_ship.core_color if parent_ship != null else Color.WHITE
|
2026-08-15 10:41:24 +02:00
|
|
|
var hull: PackedVector2Array = parent_ship.definition.hull_points
|
2026-08-15 10:12:33 +02:00
|
|
|
if is_ready():
|
2026-08-15 10:41:24 +02:00
|
|
|
# A fully lit hull means this individual bomber owns an available shot.
|
|
|
|
|
draw_colored_polygon(hull, Color(READY_COLOR, 0.42))
|
|
|
|
|
NeonDraw.draw_glowing_polygon(self, hull, READY_COLOR, 0.75, core, 0.75)
|
2026-08-15 10:12:33 +02:00
|
|
|
return
|
2026-08-15 10:41:24 +02:00
|
|
|
# Rearming is shown inside the bomber instead of as a shield-like ring:
|
|
|
|
|
# the muted silhouette fills from its engines toward its nose.
|
|
|
|
|
draw_colored_polygon(hull, Color(COOLING_COLOR, 0.58))
|
|
|
|
|
var filled := _filled_hull(hull, cooldown_progress())
|
|
|
|
|
if filled.size() >= 3:
|
|
|
|
|
draw_colored_polygon(filled, Color(READY_COLOR, 0.68))
|