86 lines
3.6 KiB
GDScript
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"))
|