Randoloot/scripts/game/deployed_turret.gd
2026-10-26 19:33:45 +01:00

86 lines
3.6 KiB
GDScript

extends Node2D
const PROJECTILE := preload("res://scenes/game/weapon_projectile.tscn")
const ARTWORK := preload("res://assets/Ships/external_turret.png")
const AUDIO := preload("res://scripts/game/weapon_audio.gd")
static var _sprite: Texture2D
var mother: CharacterBody2D
var weapon: ItemInstance
var ammunition := 50
var _fire_timer := 0.35
var _age := 0.0
var _flash := 0.0
func _ready() -> void:
if _sprite == null:
var image := ARTWORK.get_image()
image.resize(256,256,Image.INTERPOLATE_LANCZOS)
image.generate_mipmaps()
_sprite = ImageTexture.create_from_image(image)
add_to_group("player_external_turrets")
z_index = 5
texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS
func _physics_process(delta: float) -> void:
if not is_instance_valid(mother) or bool(mother.get("_is_destroyed")) or bool(mother.get("is_docked")) or ammunition <= 0:
queue_free()
return
_age += delta
_flash = maxf(0.0,_flash-delta)
_fire_timer = maxf(0.0,_fire_timer-delta)
var target := _find_target()
if target != null:
var direction := target.global_position-global_position
rotation = rotate_toward(rotation,direction.angle()+PI*0.5,8.0*delta)
if _fire_timer <= 0.0 and absf(angle_difference(rotation,direction.angle()+PI*0.5)) < 0.12:
_fire(target)
queue_redraw()
func _find_target() -> Node2D:
var closest: Node2D
var distance := weapon.definition.weapon_range
for enemy in get_tree().get_nodes_in_group("enemies"):
if enemy.is_queued_for_deletion() or float(enemy.get("hull")) <= 0.0 or bool(enemy.get("virus_controlled")):
continue
var candidate := global_position.distance_to(enemy.global_position)
if candidate < distance and _clear_shot(enemy):
distance = candidate
closest = enemy
return closest
func _clear_shot(target: Node2D) -> bool:
var query := PhysicsRayQueryParameters2D.create(global_position,target.global_position,77,[mother.get_rid()])
var hit := get_world_2d().direct_space_state.intersect_ray(query)
return hit.is_empty() or hit.get("collider") == target
func _fire(target: Node2D) -> void:
if ammunition <= 0 or is_queued_for_deletion() or not is_instance_valid(target): return
var direction := (target.global_position-global_position).normalized()
var hit: Dictionary = mother.call("roll_weapon_hit",weapon)
var bullet := PROJECTILE.instantiate()
bullet.configure(global_position+direction*25.0,direction,ItemDefinition.WeaponKind.MACHINE_GUN,weapon.definition.projectile_speed,float(hit.damage),weapon.definition.weapon_range,null,bool(hit.critical))
bullet.shield_piercing = weapon.shield_piercing()
bullet.damage_type_override = weapon.get_damage_type()
bullet.source_ship = mother
get_parent().add_child(bullet)
ammunition -= 1
_fire_timer = weapon.get_turret_fire_interval()
_flash = 0.05
AUDIO.play(get_parent(),global_position,ItemDefinition.WeaponKind.MACHINE_GUN,-8.0)
mother.get_node("WeaponController").call("_break_cloak_on_fire")
if ammunition == 0: queue_free()
func _draw() -> void:
var bob := Vector2(0,sin(_age*2.5)*2.0)
var appear := smoothstep(0.0,0.3,_age)
draw_circle(Vector2.ZERO,19.0,Color(0.1,0.7,1.0,0.08))
draw_arc(Vector2.ZERO,30.0,-PI*0.5,-PI*0.5+TAU*float(ammunition)/50.0,48,Color("70dfff"),1.6,true)
draw_set_transform(bob,0.0,Vector2.ONE*lerpf(0.4,1.0,appear))
draw_texture_rect(_sprite,Rect2(-30,-30,60,60),false)
if _flash > 0.0:
for x in [-7.0,7.0]:
draw_line(Vector2(x,-24),Vector2(x,-38),Color("ffdb86"),3.0,true)
draw_circle(Vector2(x,-28),5.0,Color(1.0,0.65,0.2,0.45))
draw_set_transform(Vector2.ZERO,-rotation)
draw_string(ThemeDB.fallback_font,Vector2(-11,43),str(ammunition),HORIZONTAL_ALIGNMENT_CENTER,22,11,Color("b9e7f5"))