From 174e9dfb08463fae90810ef1932c72d21bae253a Mon Sep 17 00:00:00 2001 From: Nikolai Fedorov Date: Wed, 22 Apr 2026 23:29:29 +0300 Subject: [PATCH] got kicked by stone with cooldown --- scripts/Boulder.gd | 5 +++ scripts/Enemy.gd | 105 ++++++++++++++++++++++++--------------------- scripts/Iron.gd | 5 +++ scripts/Rock.gd | 5 +++ scripts/Stick.gd | 5 +++ 5 files changed, 75 insertions(+), 50 deletions(-) diff --git a/scripts/Boulder.gd b/scripts/Boulder.gd index 863233b..2b2d3a6 100644 --- a/scripts/Boulder.gd +++ b/scripts/Boulder.gd @@ -63,6 +63,11 @@ func _fly(delta: float) -> void: _take_damage(speed_now * WALL_SELF_DMG) handled = true break + elif col3d.is_in_group("player"): + col3d.call("take_damage", int(speed_now * damage_modifier)) + fly_vel *= 0.3 + handled = true + break elif col3d.is_in_group("enemies") or col3d.is_in_group("kickable"): if col3d == self: continue diff --git a/scripts/Enemy.gd b/scripts/Enemy.gd index 4ad481c..886fc2b 100644 --- a/scripts/Enemy.gd +++ b/scripts/Enemy.gd @@ -30,8 +30,10 @@ var base_scale: float = 1.0 var wave_num: int = 1 var damage_modifier: float = 0.75 var enemy_kick_timer: float = 0.0 -const ENEMY_KICK_COOLDOWN := 1.2 -const ENEMY_KICK_RANGE := 2.2 +var kickable_kick_timer: float = 0.0 +const ENEMY_KICK_COOLDOWN := 1.2 +const KICKABLE_KICK_COOLDOWN := 2.5 +const ENEMY_KICK_RANGE := 2.2 var state: State = State.CHASING var fly_vel: Vector3 = Vector3.ZERO @@ -102,6 +104,7 @@ func _chase(delta: float) -> void: return contact_timer = max(0.0, contact_timer - delta) enemy_kick_timer = max(0.0, enemy_kick_timer - delta) + kickable_kick_timer = max(0.0, kickable_kick_timer - delta) var diff := target.global_position - global_position diff.y = 0.0 var dist := diff.length() @@ -109,11 +112,10 @@ func _chase(delta: float) -> void: contact_timer = CONTACT_CD if target.has_method("take_damage"): target.take_damage(damage_to_player) - if tier > 0 and enemy_kick_timer <= 0.0: + if enemy_kick_timer <= 0.0: _try_enemy_kick() if dist > 0.05: var dir := diff.normalized() - dir = _avoid_rocks(dir) velocity.x = dir.x * move_speed velocity.z = dir.z * move_speed rotation.y = lerp_angle(rotation.y, atan2(dir.x, dir.z), 8.0 * delta) @@ -121,54 +123,57 @@ func _chase(delta: float) -> void: move_and_slide() func _try_enemy_kick() -> void: - var kicked := false - for node in get_tree().get_nodes_in_group("enemies"): - var en := node as Node3D - if en == null or en == self or not is_instance_valid(en): - continue - var other_tier: int = en.get("tier") if en.get("tier") != null else 0 - if other_tier >= tier: - continue - var away := en.global_position - global_position - away.y = 0.0 - if away.length() > ENEMY_KICK_RANGE: - continue - var dir := away.normalized() - var player_pos := target.global_position if is_instance_valid(target) else global_position - var to_player := (player_pos - global_position) - to_player.y = 0.0 - if to_player.length() > 0.01: - dir = to_player.normalized() - en.call("receive_kick", dir, 40.0 + tier * 10.0) - kicked = true - if not kicked and is_instance_valid(target): - var to_player := target.global_position - global_position - to_player.y = 0.0 - if to_player.length() < ENEMY_KICK_RANGE: - var player_tier: int = target.get("tier") if target.get("tier") != null else 0 - if player_tier < tier: - target.call("receive_kick", to_player.normalized(), 35.0 + tier * 8.0) - kicked = true - if kicked: - enemy_kick_timer = ENEMY_KICK_COOLDOWN + if not is_instance_valid(target): + return + var player_pos := target.global_position + var to_player := player_pos - global_position + to_player.y = 0.0 + var kick_dir := to_player.normalized() if to_player.length() > 0.01 else -global_transform.basis.z -const AVOID_RADIUS := 1.6 -const AVOID_STRENGTH := 2.2 + # 1. Kick nearest kickable towards player + if kickable_kick_timer <= 0.0: + var nearest_kickable: Node3D = null + var nearest_dist := ENEMY_KICK_RANGE + for node in get_tree().get_nodes_in_group("kickable"): + var k := node as Node3D + if k == null or not is_instance_valid(k): + continue + var d := (k.global_position - global_position) + d.y = 0.0 + if d.length() < nearest_dist: + nearest_dist = d.length() + nearest_kickable = k + if nearest_kickable != null: + nearest_kickable.call("receive_kick", kick_dir, 35.0 + tier * 8.0) + kickable_kick_timer = KICKABLE_KICK_COOLDOWN + return -func _avoid_rocks(desired: Vector3) -> Vector3: - var push := Vector3.ZERO - for rock in get_tree().get_nodes_in_group("kickable"): - if not is_instance_valid(rock): - continue - var away := global_position - (rock as Node3D).global_position - away.y = 0.0 - var d := away.length() - if d < AVOID_RADIUS and d > 0.01: - push += away.normalized() * (1.0 - d / AVOID_RADIUS) - if push.length() < 0.01: - return desired - var steered := desired + push * AVOID_STRENGTH - return steered.normalized() if steered.length() > 0.01 else desired + # 2. Kick lower-tier enemy nearest to player direction + if tier > 0: + var nearest_enemy: Node3D = null + var nearest_enemy_dist := ENEMY_KICK_RANGE + for node in get_tree().get_nodes_in_group("enemies"): + var en := node as Node3D + if en == null or en == self or not is_instance_valid(en): + continue + if (en.get("tier") if en.get("tier") != null else 0) >= tier: + continue + var d := (en.global_position - global_position) + d.y = 0.0 + if d.length() < nearest_enemy_dist: + nearest_enemy_dist = d.length() + nearest_enemy = en + if nearest_enemy != null: + nearest_enemy.call("receive_kick", kick_dir, 40.0 + tier * 10.0) + enemy_kick_timer = ENEMY_KICK_COOLDOWN + return + + # 3. Kick player directly if lower tier and in range + if tier > 0 and to_player.length() < ENEMY_KICK_RANGE: + var player_tier: int = target.get("tier") if target.get("tier") != null else 0 + if player_tier < tier: + target.call("receive_kick", kick_dir, 35.0 + tier * 8.0) + enemy_kick_timer = ENEMY_KICK_COOLDOWN func _fly(delta: float) -> void: var speed_now := Vector2(fly_vel.x, fly_vel.z).length() diff --git a/scripts/Iron.gd b/scripts/Iron.gd index 29477ab..95170f6 100644 --- a/scripts/Iron.gd +++ b/scripts/Iron.gd @@ -68,6 +68,11 @@ func _fly(delta: float) -> void: _take_damage(speed_now * WALL_SELF_DMG) handled = true break + elif col3d.is_in_group("player"): + col3d.call("take_damage", int(speed_now * damage_modifier)) + fly_vel *= 0.3 + handled = true + break elif col3d.is_in_group("enemies") or col3d.is_in_group("kickable"): if col3d == self: continue diff --git a/scripts/Rock.gd b/scripts/Rock.gd index dd30b1a..01ee075 100644 --- a/scripts/Rock.gd +++ b/scripts/Rock.gd @@ -66,6 +66,11 @@ func _fly(delta: float) -> void: _take_damage(speed_now * WALL_SELF_DMG) handled = true break + elif col3d.is_in_group("player"): + col3d.call("take_damage", int(speed_now * damage_modifier)) + fly_vel *= 0.3 + handled = true + break elif col3d.is_in_group("enemies") or col3d.is_in_group("kickable"): if col3d == self: continue diff --git a/scripts/Stick.gd b/scripts/Stick.gd index 42f7d14..73192aa 100644 --- a/scripts/Stick.gd +++ b/scripts/Stick.gd @@ -63,6 +63,11 @@ func _fly(delta: float) -> void: _take_damage(speed_now * WALL_SELF_DMG) handled = true break + elif col3d.is_in_group("player"): + col3d.call("take_damage", int(speed_now * damage_modifier)) + fly_vel *= 0.3 + handled = true + break elif col3d.is_in_group("enemies") or col3d.is_in_group("kickable"): if col3d == self: continue