extends CharacterBody2D class_name UFO @export var movement_speed: float = 800.0 @export var radius: float = 150.0 var max_velocity: float = movement_speed @onready var navigation_agent: NavigationAgent2D = $NavigationAgent2D @onready var plants: Node = $"../../Plants" var target: Plant = null var target2: Plant = null var announce_self: bool = false var dead = false @export_range(1.0, 1000.0) var dps: float = 10.0 @export var max_hp = 100.0 var hp: float var dead_timer: Timer = Timer.new() @export var wheat_out: int = 3 var Wheat = preload("res://scene/entity/wheat.tscn") @export var should_rotate: bool = true @onready var ray = $Plx/Ray @onready var ray2 = find_child("Ray2") var attack_range = 1000.0 var second_player = find_child("AudioStreamPlayer2D2") @onready var power_level: float = $"../../Waves".power_level @onready var ROOT = get_tree().get_root().get_child(0) func fuck(): return false func _ready(): # Workaround bug body->get_space() call_deferred("actor_setup") navigation_agent.connect("velocity_computed", move) max_hp *= power_level dps *= power_level * pow(power_level, 0.7) $RerollTimer.connect("timeout", roll_movement_target_2) $DamageTimer.connect("timeout", damage_target) navigation_agent.set_path_desired_distance(40.0) navigation_agent.set_target_desired_distance(attack_range) navigation_agent.set_path_max_distance(200.0) navigation_agent.set_avoidance_enabled(true) if ROOT.disable_ai: navigation_agent.set_radius(0) else: navigation_agent.set_radius(radius) navigation_agent.set_neighbor_distance(movement_speed * 2) navigation_agent.set_max_speed(movement_speed) $AudioStreamPlayer2D.set_bus("Music" + str(randi_range(0, 3))) $AudioStreamPlayer2D.play($"../../HomeSound".get_playback_position()) if second_player != null: second_player.set_bus("Music" + str(randi_range(0, 3))) second_player.play($"../../HomeSound".get_playback_position()) hp = max_hp $Plx/HP.set_max(max_hp) $Plx/HP.set_value(max_hp) func _process(delta): if dead: _process_dead(delta) return if target == null or target.dead or !is_instance_valid(target): if target2 != null: target = target2 target2 = null else: target = roll_movement_target() hide_ray(ray) if navigation_agent.is_target_reached() and target != null: enable_ray(ray, target) if ray2 != null: if target2 == null or target2.dead: target2 = roll_aux_target() if target2 != null: enable_ray(ray2, target2) else: hide_ray(ray2) if $DamageTimer.is_stopped(): $DamageTimer.start() else: hide_ray(ray) hide_ray(ray2) $DamageTimer.stop() func _process_dead(delta: float): var time_left = dead_timer.get_time_left() * 3.0 var scale = ease(time_left, 5) set_scale(Vector2(scale, scale)) $AudioStreamPlayer2D.set_volume_db($AudioStreamPlayer2D.get_volume_db() - delta * 30.0) if second_player != null: second_player.set_volume_db(second_player.get_volume_db() - delta * 30.0) if time_left == 0.0: get_parent().remove_child(self) queue_free() func _physics_process(delta): if fuck(): return if navigation_agent.is_target_reached(): var new_speed = velocity.length() - delta * movement_speed * 2.0 velocity = velocity.normalized() * new_speed move_and_slide() else: var current_agent_position: Vector2 = global_transform.origin var next_path_position: Vector2 = navigation_agent.get_next_location() var new_velocity: Vector2 = next_path_position - current_agent_position new_velocity = new_velocity.normalized() new_velocity = new_velocity * movement_speed navigation_agent.set_velocity(new_velocity) func actor_setup(): await get_tree().physics_frame target = roll_movement_target() func roll_movement_target_2(): target = roll_movement_target() func roll_movement_target(): var all_plants = plants.get_children() var count = all_plants.size() announce_self = true var res: UFO = null if count == 0: $RerollTimer.start() else: var i = 0 while (res == null or res.dead or !is_instance_valid(res)) and i < 10: res = all_plants[randi_range(0, count - 1)] i += 1 if i == 10: res = null $RerollTimer.start() else: navigation_agent.set_target_location(res.get_global_position()) return res func roll_aux_target(): var all_plants = plants.get_children() for plant in all_plants: if plant != target and plant.get_global_position().distance_to(get_global_position()) <= attack_range: return plant return null func damage_target(): if target != null: target.deal_damage(dps / 20.0, self if announce_self else null) if target2 != null: target2.deal_damage(dps / 20.0, self if announce_self else null) func move(velocity_: Vector2): velocity = velocity_ move_and_slide() if should_rotate: var top = find_child("Top") top.set_rotation(lerp_angle(top.get_rotation(), velocity.angle(), 10.0 * get_physics_process_delta_time())) func _on_area_2d_body_entered(body): if body.get_class() == "Bullet": deal_damage(body.damage) body.get_parent().remove_child(body) body.queue_free() func deal_damage(damage): hp -= damage $Plx/HP.set_value(hp) if hp <= 0 and not dead: dead = true $Coin.play() set_collision_layer_value(1, false) set_collision_mask_value(1, false) $Plx/HP.hide() dead_timer.set_wait_time(0.333) dead_timer.set_one_shot(true) add_child(dead_timer) dead_timer.start() $DamageTimer.stop() hide_ray(ray) hide_ray(ray2) call_deferred("spawn_wheat") func spawn_wheat(): if ROOT.disable_wheat: $"../../Economy".add(ceil(wheat_out * sqrt(power_level))) else: for i in range(0, ceil(wheat_out * sqrt(power_level))): var wheat = Wheat.instantiate() wheat.rotate(randf_range(-PI, PI)) wheat.set_position(get_global_position()) $"../../Wheat".add_child(wheat) func enable_ray(ray, target: Node2D): if ray != null: var diff = target.get_global_position() - get_global_position() var poly = ray.get_polygon() poly[1] = diff + Vector2(-80.0, target.body.texture.get_size().y / 2 + 30.0) poly[2] = diff + Vector2(80.0, target.body.texture.get_size().y / 2 + 30.0) ray.set_polygon(poly) ray.show() func hide_ray(r): if r != null: r.hide()