202 lines
7.4 KiB
GDScript
202 lines
7.4 KiB
GDScript
extends Node
|
|
|
|
const WORLD_SIZE := preload("res://scripts/levels/system_generator.gd").WORLD_SIZE
|
|
const PULSE := preload("res://scripts/game/extension_pulse.gd")
|
|
var cooldowns: Dictionary = {}
|
|
var cloak_remaining := 0.0
|
|
var solar_remaining := 0.0
|
|
var drones_remaining := 0.0
|
|
var _drones: Array[Node2D] = []
|
|
var _cloak_material: ShaderMaterial
|
|
var _old_material: Material
|
|
var _shadow_was_visible := false
|
|
var _visual_colors: Dictionary = {}
|
|
var _destination := Vector2.ZERO
|
|
var _has_destination := false
|
|
@onready var ship: CharacterBody2D = get_parent()
|
|
|
|
func reset_combat_state() -> void:
|
|
cooldowns.clear()
|
|
ship.clear_auxiliary_shield()
|
|
_clear_drones()
|
|
solar_remaining = 0.0
|
|
if cloak_remaining > 0.0:
|
|
_end_cloak()
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
if drones_remaining > 0.0:
|
|
drones_remaining = maxf(0.0, drones_remaining - delta)
|
|
if drones_remaining <= 0.0 or bool(ship.get("_is_destroyed")) or bool(ship.get("is_docked")):
|
|
_clear_drones()
|
|
for id in cooldowns.keys():
|
|
cooldowns[id] = maxf(0.0, float(cooldowns[id]) - delta)
|
|
if cloak_remaining > 0.0:
|
|
cloak_remaining = maxf(0.0, cloak_remaining - delta)
|
|
if _cloak_material != null:
|
|
_cloak_material.set_shader_parameter("elapsed", 10.0 - cloak_remaining)
|
|
if cloak_remaining <= 0.0 or bool(ship.get("_is_destroyed")):
|
|
_end_cloak()
|
|
if solar_remaining > 0.0:
|
|
var available_time := minf(delta, solar_remaining)
|
|
solar_remaining = maxf(0.0, solar_remaining - delta)
|
|
if bool(ship.get("_is_destroyed")) or bool(ship.get("is_docked")) or float(ship.call("get_solar_regeneration")) <= 0.0 or GameState.captain.is_skill_active("power_redirect"):
|
|
solar_remaining = 0.0
|
|
return
|
|
var maximum := float(ship.get("max_shields"))
|
|
ship.set("shields", minf(maximum, float(ship.get("shields")) + maximum * available_time / 5.0))
|
|
ship.call("_update_shield_visual")
|
|
ship.get_node("ShieldVisual").call("flash_hit")
|
|
if float(ship.get("shields")) >= maximum:
|
|
solar_remaining = 0.0
|
|
|
|
func _safe_destination(point: Vector2) -> bool:
|
|
var query := PhysicsShapeQueryParameters2D.new()
|
|
var shape := CircleShape2D.new()
|
|
shape.radius = 65.0
|
|
query.shape = shape
|
|
query.transform = Transform2D(0.0, point)
|
|
query.collision_mask = 5
|
|
query.exclude = [ship.get_rid()]
|
|
return ship.get_world_2d().direct_space_state.intersect_shape(query, 1).is_empty()
|
|
|
|
func has_teleport_destination() -> bool:
|
|
if _has_destination and _destination.distance_to(ship.global_position) >= 400.0 and _safe_destination(_destination):
|
|
return true
|
|
var half := WORLD_SIZE * 0.5 - Vector2(160, 160)
|
|
for attempt in 48:
|
|
var candidate := Vector2(randf_range(-half.x, half.x), randf_range(-half.y, half.y))
|
|
if candidate.distance_to(ship.global_position) >= 400.0 and _safe_destination(candidate):
|
|
_destination = candidate
|
|
_has_destination = true
|
|
return true
|
|
_has_destination = false
|
|
return false
|
|
|
|
func activate(kind: int) -> void:
|
|
match kind:
|
|
5:
|
|
var inventory := ship.get_node("ShipInventory") as ShipInventory
|
|
if inventory.ammunition < 50 or drones_remaining > 0.0:
|
|
return
|
|
inventory.ammunition -= 50
|
|
inventory.ammunition_changed.emit()
|
|
drones_remaining = 10.0
|
|
break_cloak_on_fire()
|
|
var shared_dps := inventory.get_total_dps() * 0.5
|
|
for index in 3:
|
|
var drone := Node2D.new()
|
|
drone.set_script(preload("res://scripts/game/combat_drone.gd"))
|
|
drone.set("mother", ship)
|
|
drone.set("formation_index", index)
|
|
drone.set("damage_per_shot", shared_dps / 3.0 * 0.25)
|
|
drone.position = ship.position + Vector2.from_angle(TAU * index / 3.0) * 48.0
|
|
ship.get_parent().add_child(drone)
|
|
_drones.append(drone)
|
|
_deployment_effect(ship.position, Vector2.DOWN.rotated(ship.rotation), Color("70f5df"))
|
|
0:
|
|
if not has_teleport_destination():
|
|
return
|
|
_teleport_effect(ship.global_position, false)
|
|
ship.global_position = _destination
|
|
_has_destination = false
|
|
ship.velocity = Vector2.ZERO
|
|
ship.set("angular_velocity", 0.0)
|
|
ship.set("_boost_target", 0.0)
|
|
ship.set("_boost_speed", 0.0)
|
|
ship.set("_mini_boost_coast_speed", 0.0)
|
|
ship.set("energy", 0.0)
|
|
ship.reset_physics_interpolation()
|
|
ship.get_node("Camera2D").reset_smoothing()
|
|
_teleport_effect(ship.global_position, true)
|
|
1: _start_cloak()
|
|
2:
|
|
var mine := Node2D.new()
|
|
mine.set_script(preload("res://scripts/game/deployed_mine.gd"))
|
|
var drop_direction := Vector2.DOWN.rotated(ship.rotation)
|
|
mine.position = ship.position + drop_direction * 42.0
|
|
mine.set("drift", drop_direction * 36.0)
|
|
_deployment_effect(mine.position, drop_direction, Color("8ad7e7"))
|
|
ship.get_parent().add_child(mine)
|
|
3:
|
|
_deployment_effect(ship.position + Vector2.DOWN.rotated(ship.rotation) * 28.0, Vector2.DOWN.rotated(ship.rotation), Color("ffb15c"))
|
|
for index in 3:
|
|
var flare := StaticBody2D.new()
|
|
flare.set_script(preload("res://scripts/game/deployed_flare.gd"))
|
|
var direction := Vector2.DOWN.rotated(ship.rotation + (float(index) - 1.0) * 0.8)
|
|
flare.position = ship.position + direction * 48.0
|
|
flare.set("drift", direction * 90.0 + ship.velocity * 0.25)
|
|
ship.get_parent().add_child(flare)
|
|
4:
|
|
solar_remaining = 5.0
|
|
_pulse(ship.global_position, Color("70dfff"), 50.0)
|
|
|
|
func _clear_drones() -> void:
|
|
drones_remaining = 0.0
|
|
for drone in _drones:
|
|
if is_instance_valid(drone):
|
|
drone.queue_free()
|
|
_drones.clear()
|
|
|
|
func _exit_tree() -> void:
|
|
_clear_drones()
|
|
|
|
func _teleport_effect(point: Vector2, arriving: bool) -> void:
|
|
var effect := Node2D.new()
|
|
effect.set_script(preload("res://scripts/game/teleport_vortex.gd"))
|
|
effect.position = point
|
|
effect.set("arriving", arriving)
|
|
effect.set("ship_texture", ship.get_node("Sprite2D").get("texture"))
|
|
effect.set("ship_rotation", ship.rotation)
|
|
ship.get_parent().add_child(effect)
|
|
|
|
func _deployment_effect(point: Vector2, direction: Vector2, color: Color) -> void:
|
|
var effect := Node2D.new()
|
|
effect.set_script(preload("res://scripts/game/deployment_flash.gd"))
|
|
effect.position = point
|
|
effect.set("direction", direction)
|
|
effect.set("color", color)
|
|
ship.get_parent().add_child(effect)
|
|
|
|
func _start_cloak() -> void:
|
|
cloak_remaining = 10.0
|
|
var sprite := ship.get_node("Sprite2D") as Sprite2D
|
|
_old_material = sprite.material
|
|
_cloak_material = ShaderMaterial.new()
|
|
_cloak_material.shader = preload("res://resources/ui/cloak.gdshader")
|
|
sprite.material = _cloak_material
|
|
var shadow := sprite.get_node_or_null("ShipShadow") as CanvasItem
|
|
if shadow != null:
|
|
_shadow_was_visible = shadow.visible
|
|
shadow.hide()
|
|
for name in ["ShieldVisual", "AuxiliaryShieldVisual", "EngineVisual", "SolarEnergyEffect", "EnergyIndicator"]:
|
|
var visual := ship.get_node_or_null(name) as CanvasItem
|
|
if visual != null:
|
|
_visual_colors[name] = visual.modulate
|
|
visual.modulate = Color(visual.modulate, 0.08)
|
|
_pulse(ship.global_position, Color("81e4ef"), 40.0)
|
|
|
|
func break_cloak_on_fire() -> void:
|
|
if cloak_remaining > 0.0:
|
|
_end_cloak()
|
|
|
|
func _end_cloak() -> void:
|
|
cloak_remaining = 0.0
|
|
ship.get_node("Sprite2D").set("material", _old_material)
|
|
_cloak_material = null
|
|
var shadow := ship.get_node_or_null("Sprite2D/ShipShadow") as CanvasItem
|
|
if shadow != null:
|
|
shadow.visible = _shadow_was_visible
|
|
for name in _visual_colors:
|
|
var visual := ship.get_node_or_null(NodePath(name)) as CanvasItem
|
|
if visual != null:
|
|
visual.modulate = _visual_colors[name]
|
|
_visual_colors.clear()
|
|
|
|
func _pulse(point: Vector2, color: Color, radius: float) -> void:
|
|
var pulse := Node2D.new()
|
|
pulse.set_script(PULSE)
|
|
pulse.position = point
|
|
pulse.set("color", color)
|
|
pulse.set("radius", radius)
|
|
ship.get_parent().add_child(pulse)
|