extends CharacterBody2D @onready var earthaligner = $EarthAligner @onready var player = get_tree().get_root().get_node("main/Player") var moves = ["slam", "wave", "water_rise", "splash"] @export var big_blob : PackedScene @onready var water : Water = get_tree().get_root().get_node("main/Water") var risen = 0 var attack_ready = true var idle_dir : Vector2 = Vector2.ZERO var idle_dir_remaining = 0 var idle_move = true var target_pos = Vector2.ZERO var damage = 1 var dead = false signal grounded signal slam_step_finished func choose_next_move() -> String: if $EnemyHurtbox.hp <= 3 * $EnemyHurtbox.max_hp / 4 and risen == 0: risen += 1 return "water_rise" if $EnemyHurtbox.hp <= $EnemyHurtbox.max_hp / 2 and risen == 1: risen += 1 return "water_rise" var pool = ["splash"] if not (position.length() - water.radius < 300 and randf()<0.75): pool.append("slam") if not (player.position.length() > water.radius + 900 and randf()<0.75): pool.append("wave") return ["slam", "wave", "splash"].pick_random() func _process(_delta: float) -> void: if dead: return if attack_ready: attack_ready = false call(choose_next_move()) func _physics_process(delta: float) -> void: if dead: return up_direction = earthaligner.global_from_local(Vector2.UP) if(is_on_floor()): grounded.emit() if idle_move: move_idle(delta) if($Hitbox.overlaps_body(player)): player.hurt(damage, self.position - player.position) move_and_slide() func move_idle(delta : float): idle_dir_remaining -= delta if(idle_dir_remaining <= 0): target_pos = player.position + player.earth_aligner.global_from_local(Vector2.UP) * 400 target_pos += randf_range(0, max(200, (target_pos - global_position).length())*0.25) * Vector2.from_angle(randf_range(0,TAU)) idle_dir = (target_pos - global_position).normalized()* max(200, (target_pos - global_position).length()) * 0.4 idle_dir_remaining = 0.5 velocity = idle_dir func slam(): idle_move = false velocity = up_direction * 500 await get_tree().create_timer(0.6).timeout await slam_step() damage = 1 velocity = up_direction * 500 await get_tree().create_timer(0.3).timeout await slam_step() velocity = up_direction * 35 await get_tree().create_timer(3).timeout idle_move = true attack_ready = true func slam_step(): damage = 2 velocity = up_direction * -1500 grounded.connect(func(): slam_step_finished.emit()) get_tree().create_timer(1.5).timeout.connect(func(): slam_step_finished.emit()) await slam_step_finished $SoundSlam.play() destroy_below() damage = 1 func destroy_below(): if dead: return for body in $DestructionChecker.get_overlapping_bodies(): if(body.has_method("destroy")): body.destroy() func wave(): var angle = atan2(player.position.y, player.position.x) var dir = randi_range(0, 1) * 2 - 1 var speed = 3000/water.radius_base water.create_tsunami(angle - speed * dir*TAU/30, dir, speed) await get_tree().create_timer(0.5).timeout $Wave.play() await get_tree().create_timer(3.5).timeout attack_ready = true func water_rise(): water.rise_water() await get_tree().create_timer(5).timeout attack_ready = true func splash(): var blob_instance = big_blob.instantiate() get_tree().get_root().get_node("main").add_child(blob_instance) blob_instance.position = player.position blob_instance.rotation = randf_range(0, TAU) await get_tree().create_timer(5).timeout attack_ready = true func die(): dead = true for child in get_children(): if not child is AudioStreamPlayer2D: child.queue_free() $DeathSound.play() await $DeathSound.finished await get_tree().create_timer(3).timeout get_tree().change_scene_to_file("res://ui/victory_screen/victory_screen.tscn") queue_free() func _on_enemy_hurtbox_damage_taken(_damage, _dir, _id) -> void: if dead: return $AudioStreamPlayer2D.play()