2026-08-15 04:45:15 +02:00
|
|
|
class_name GasBombController
|
2026-08-16 21:38:07 +02:00
|
|
|
extends "res://AimedFleetAbilityController.gd"
|
2026-08-15 04:45:15 +02:00
|
|
|
|
|
|
|
|
const BOMB_COLOR := Color(0.96, 0.22, 0.72)
|
|
|
|
|
const TARGET_COLOR := Color(0.78, 0.32, 1.0)
|
|
|
|
|
const MAX_RANGE := 950.0
|
|
|
|
|
const AOE_RADIUS := 180.0
|
|
|
|
|
const DRAG_RADIUS := 260.0
|
|
|
|
|
const PROJECTILE_SPEED := 720.0
|
|
|
|
|
const DAMAGE := 3
|
|
|
|
|
const COOLDOWN := 5.0
|
2026-08-16 18:54:44 +02:00
|
|
|
const GAS_PER_SHOT: int = 5
|
2026-08-15 04:45:15 +02:00
|
|
|
|
2026-08-15 10:12:33 +02:00
|
|
|
var projectiles: Array = []
|
|
|
|
|
var explosions: Array = []
|
2026-08-16 21:38:07 +02:00
|
|
|
var last_hit_count: int = 0
|
2026-08-15 04:45:15 +02:00
|
|
|
|
2026-08-15 10:12:33 +02:00
|
|
|
var projectile_active: bool:
|
|
|
|
|
get: return not projectiles.is_empty()
|
|
|
|
|
|
|
|
|
|
var explosion_time: float:
|
|
|
|
|
get:
|
2026-08-16 21:38:07 +02:00
|
|
|
var longest: float = 0.0
|
2026-08-15 10:12:33 +02:00
|
|
|
for explosion in explosions:
|
|
|
|
|
longest = maxf(longest, float(explosion.time))
|
|
|
|
|
return longest
|
|
|
|
|
|
2026-08-15 04:45:15 +02:00
|
|
|
|
2026-08-16 21:38:07 +02:00
|
|
|
func _button_path() -> NodePath: return "../UI/GasBombButton"
|
|
|
|
|
func _status_path() -> NodePath: return "../UI/GasBombStatus"
|
|
|
|
|
func _component_id() -> String: return "gas_bomber"
|
|
|
|
|
func _ammo_resource() -> String: return GameState.RESOURCE_GAS
|
|
|
|
|
func _ammo_cost() -> int: return GAS_PER_SHOT
|
|
|
|
|
func _aim_padding() -> float: return AOE_RADIUS
|
|
|
|
|
func _has_effect_visuals() -> bool: return not projectiles.is_empty() or not explosions.is_empty()
|
2026-08-15 04:45:15 +02:00
|
|
|
|
|
|
|
|
|
2026-08-16 21:38:07 +02:00
|
|
|
func _calculate_aim_target(drag: Vector2, origin: Vector2) -> Vector2:
|
|
|
|
|
if drag.length() < 0.001:
|
|
|
|
|
return origin
|
|
|
|
|
var distance: float = minf(drag.length() / DRAG_RADIUS, 1.0) * MAX_RANGE
|
|
|
|
|
return origin + drag.normalized() * distance
|
2026-08-16 18:54:44 +02:00
|
|
|
|
|
|
|
|
|
2026-08-16 21:38:07 +02:00
|
|
|
func _consume_shot(component: Node) -> bool:
|
|
|
|
|
return component.consume_shot(COOLDOWN)
|
2026-08-16 18:54:44 +02:00
|
|
|
|
|
|
|
|
|
2026-08-16 21:38:07 +02:00
|
|
|
func _perform_shot(ship: Node2D, _component: Node) -> void:
|
|
|
|
|
projectiles.append({
|
|
|
|
|
"position": ship.global_position,
|
|
|
|
|
"target": aim_target,
|
|
|
|
|
"trail": PackedVector2Array([ship.global_position]),
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _next_ready_bomber() -> Node2D:
|
|
|
|
|
return _next_ready_ship()
|
2026-08-15 04:45:15 +02:00
|
|
|
|
|
|
|
|
|
2026-08-16 21:38:07 +02:00
|
|
|
func _advance_effects(delta: float) -> void:
|
2026-08-15 10:12:33 +02:00
|
|
|
for i in range(projectiles.size() - 1, -1, -1):
|
|
|
|
|
var projectile: Dictionary = projectiles[i]
|
|
|
|
|
var distance: float = (projectile.position as Vector2).distance_to(projectile.target)
|
2026-08-15 04:45:15 +02:00
|
|
|
if distance <= PROJECTILE_SPEED * delta:
|
2026-08-15 10:12:33 +02:00
|
|
|
projectile.position = projectile.target
|
|
|
|
|
_explode(projectile.target)
|
|
|
|
|
projectiles.remove_at(i)
|
2026-08-15 04:45:15 +02:00
|
|
|
else:
|
2026-08-16 21:38:07 +02:00
|
|
|
projectile.position = (projectile.position as Vector2).move_toward(
|
|
|
|
|
projectile.target, PROJECTILE_SPEED * delta)
|
2026-08-15 10:12:33 +02:00
|
|
|
var trail: PackedVector2Array = projectile.trail
|
|
|
|
|
trail.append(projectile.position)
|
|
|
|
|
while trail.size() > 12:
|
|
|
|
|
trail.remove_at(0)
|
|
|
|
|
projectile.trail = trail
|
|
|
|
|
for i in range(explosions.size() - 1, -1, -1):
|
|
|
|
|
var explosion: Dictionary = explosions[i]
|
|
|
|
|
explosion.time = maxf(float(explosion.time) - delta, 0.0)
|
|
|
|
|
if float(explosion.time) <= 0.0:
|
|
|
|
|
explosions.remove_at(i)
|
2026-08-15 04:45:15 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
func _explode(at: Vector2) -> void:
|
2026-08-15 10:12:33 +02:00
|
|
|
explosions.append({"position": at, "time": 0.8})
|
2026-08-15 04:45:15 +02:00
|
|
|
last_hit_count = 0
|
|
|
|
|
for enemy in get_tree().get_nodes_in_group("enemies"):
|
|
|
|
|
if is_instance_valid(enemy) and enemy is Node2D \
|
|
|
|
|
and enemy.global_position.distance_to(at) <= AOE_RADIUS:
|
|
|
|
|
enemy.take_damage(DAMAGE)
|
|
|
|
|
last_hit_count += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _draw() -> void:
|
|
|
|
|
if aiming:
|
2026-08-16 21:38:07 +02:00
|
|
|
NeonDraw.draw_glowing_line(self, _aim_origin(), aim_target, TARGET_COLOR, 0.7, 0.8)
|
2026-08-15 04:45:15 +02:00
|
|
|
_draw_ring(aim_target, AOE_RADIUS, TARGET_COLOR, 0.8)
|
|
|
|
|
_draw_ring(aim_target, 18.0, BOMB_COLOR, 1.0)
|
2026-08-15 10:12:33 +02:00
|
|
|
for projectile in projectiles:
|
|
|
|
|
var trail: PackedVector2Array = projectile.trail
|
|
|
|
|
if trail.size() >= 2:
|
|
|
|
|
for i in range(1, trail.size()):
|
2026-08-16 21:38:07 +02:00
|
|
|
var alpha: float = float(i) / trail.size()
|
|
|
|
|
draw_line(trail[i - 1], trail[i], Color(BOMB_COLOR, alpha * 0.65),
|
|
|
|
|
4.0 + alpha * 4.0, true)
|
2026-08-15 10:12:33 +02:00
|
|
|
draw_circle(projectile.position, 12.0, Color(BOMB_COLOR, 0.35))
|
|
|
|
|
NeonDraw.draw_glowing_circle(self, projectile.position, 7.0, BOMB_COLOR, 1.0)
|
|
|
|
|
for explosion in explosions:
|
2026-08-16 21:38:07 +02:00
|
|
|
var progress: float = 1.0 - float(explosion.time) / 0.8
|
|
|
|
|
var radius: float = lerpf(24.0, AOE_RADIUS, minf(progress * 1.5, 1.0))
|
2026-08-15 10:12:33 +02:00
|
|
|
draw_circle(explosion.position, radius, Color(BOMB_COLOR, (1.0 - progress) * 0.16))
|
|
|
|
|
_draw_ring(explosion.position, radius, BOMB_COLOR, 1.0 - progress)
|
2026-08-15 04:45:15 +02:00
|
|
|
for i in range(7):
|
2026-08-16 21:38:07 +02:00
|
|
|
var angle: float = TAU * float(i) / 7.0 + progress
|
|
|
|
|
var cloud_at: Vector2 = explosion.position \
|
|
|
|
|
+ Vector2(cos(angle), sin(angle)) * radius * 0.55
|
|
|
|
|
draw_circle(cloud_at, 18.0 + 14.0 * progress,
|
|
|
|
|
Color(BOMB_COLOR, (1.0 - progress) * 0.22))
|
2026-08-15 04:45:15 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
func _draw_ring(center: Vector2, radius: float, color: Color, alpha: float) -> void:
|
|
|
|
|
draw_arc(center, radius, 0.0, TAU, 64, Color(color, 0.16 * alpha), 16.0, true)
|
|
|
|
|
draw_arc(center, radius, 0.0, TAU, 64, Color(color, 0.5 * alpha), 6.0, true)
|
|
|
|
|
draw_arc(center, radius, 0.0, TAU, 64, Color(1.0, 0.86, 0.96, 0.9 * alpha), 2.0, true)
|