delete files in nickes

This commit is contained in:
2026-01-11 03:34:14 +01:00
parent b692b4f39d
commit 9b55af2e67
46 changed files with 2237 additions and 654 deletions

View File

@@ -11,6 +11,7 @@ var current_health: float = 50.0
var is_dead: bool = false
var target_player: Node = null
var attack_timer: float = 0.0
var killer_player: Node = null # Track who killed this enemy (for kill credit)
# Knockback
var is_knocked_back: bool = false
@@ -48,7 +49,7 @@ func _ready():
# CRITICAL: Set collision mask to include interactable objects (layer 2) and walls (layer 7)
# This allows enemies to collide with interactable objects so they can path around them
# Walls are on layer 7 (bit 6 = 64), not layer 4!
collision_mask = 1 | 2 | 64 # Collide with players (layer 1), objects (layer 2), and walls (layer 7 = bit 6 = 64)
collision_mask = 1 | 2 | 64 # Collide with players (layer 1), objects (layer 2), and walls (layer 7 = bit 6 = 64)
func _physics_process(delta):
if is_dead:
@@ -162,18 +163,18 @@ func _check_interactable_object_collision():
# Try to path around the object by moving perpendicular to collision normal
# This creates a side-stepping behavior to go around obstacles
var perpendicular = Vector2(-collision_normal.y, collision_normal.x) # Rotate 90 degrees
var perpendicular = Vector2(-collision_normal.y, collision_normal.x) # Rotate 90 degrees
# Choose perpendicular direction that moves toward target (if we have one)
if target_player and is_instance_valid(target_player):
var to_target = (target_player.global_position - global_position).normalized()
# If perpendicular dot product with target direction is negative, flip it
if perpendicular.dot(to_target) < 0:
perpendicular = -perpendicular
perpendicular = - perpendicular
# Apply perpendicular movement (side-step around object)
var side_step_velocity = perpendicular * move_speed * 0.7 # 70% of move speed for side-step
velocity = velocity.lerp(side_step_velocity, 0.3) # Smoothly blend with existing velocity
var side_step_velocity = perpendicular * move_speed * 0.7 # 70% of move speed for side-step
velocity = velocity.lerp(side_step_velocity, 0.3) # Smoothly blend with existing velocity
# Also add some push-away from object to create clearance
var push_away = collision_normal * move_speed * 0.3
@@ -184,7 +185,7 @@ func _check_interactable_object_collision():
velocity = velocity.normalized() * move_speed
# For humanoid enemies, sometimes try to destroy the object
if has_method("_try_attack_object") and randf() < 0.1: # 10% chance per frame when blocked
if has_method("_try_attack_object") and randf() < 0.1: # 10% chance per frame when blocked
call("_try_attack_object", blocked_objects[0].object)
func _attack_player(player):
@@ -239,6 +240,25 @@ func _find_nearest_player_in_range(max_range: float) -> Node:
return nearest
func _find_nearest_player_to_position(pos: Vector2, max_range: float = 100.0) -> Node:
# Find the nearest player to a specific position (used to find attacker)
var players = get_tree().get_nodes_in_group("player")
if players.is_empty():
return null
var nearest: Node = null
var nearest_dist = max_range
for player in players:
if not is_instance_valid(player):
continue
var dist = pos.distance_to(player.global_position)
if dist <= max_range and dist < nearest_dist:
nearest_dist = dist
nearest = player
return nearest
func take_damage(amount: float, from_position: Vector2):
# Only process damage on server/authority
if not is_multiplayer_authority():
@@ -247,6 +267,12 @@ func take_damage(amount: float, from_position: Vector2):
if is_dead:
return
# Find the nearest player to the attack position (likely the attacker)
# This allows us to credit kills correctly
var nearest_player = _find_nearest_player_to_position(from_position)
if nearest_player:
killer_player = nearest_player # Update killer to the most recent attacker
current_health -= amount
print(name, " took ", amount, " damage! Health: ", current_health)
@@ -279,8 +305,20 @@ func take_damage(amount: float, from_position: Vector2):
_sync_damage_visual.rpc()
if current_health <= 0:
# Prevent multiple death triggers
if is_dead:
return # Already dying
# Don't set is_dead here - let _die() set it to avoid early return bug
# Mark as dead in _die() function instead of here
# Delay death slightly so knockback is visible
call_deferred("_die")
# Notify doors that an enemy has died (if spawned from spawner)
# This needs to happen after _die() sets is_dead, so defer it
if has_meta("spawned_from_spawner") and get_meta("spawned_from_spawner"):
call_deferred("_notify_doors_enemy_died")
@rpc("any_peer", "reliable")
func rpc_take_damage(amount: float, from_position: Vector2):
@@ -318,7 +356,7 @@ func _show_damage_number(amount: float, from_position: Vector2):
var entities_node = game_world.get_node_or_null("Entities")
if entities_node:
entities_node.add_child(damage_label)
damage_label.global_position = global_position + Vector2(0, -16) # Above enemy head
damage_label.global_position = global_position + Vector2(0, -16) # Above enemy head
else:
get_tree().current_scene.add_child(damage_label)
damage_label.global_position = global_position + Vector2(0, -16)
@@ -347,6 +385,27 @@ func _on_take_damage():
# Override in subclasses for custom damage reactions
pass
func _notify_doors_enemy_died():
# Notify all doors that require enemies to check puzzle state
# This ensures doors open immediately when the last enemy dies
if not has_meta("spawned_from_spawner") or not get_meta("spawned_from_spawner"):
return # Only notify if this enemy was spawned from a spawner
# Find all doors in the scene that require enemies
for door in get_tree().get_nodes_in_group("blocking_door"):
if not is_instance_valid(door):
continue
if not door.has_method("_check_puzzle_state"):
continue
# Check if this door requires enemies (requires_enemies is a property defined in door.gd)
# Access property directly - it's always defined in door.gd class
if door.requires_enemies:
# Trigger puzzle state check immediately (doors will verify if all enemies are dead)
door.call_deferred("_check_puzzle_state")
print("Enemy: Notified door ", door.name, " to check puzzle state after enemy death")
func _set_animation(_anim_name: String):
# Virtual function - override in subclasses that use animation state system
# (e.g., enemy_humanoid.gd uses player-like animation system)
@@ -359,6 +418,11 @@ func _die():
is_dead = true
print(name, " died!")
# Credit kill to the player who dealt the fatal damage
if killer_player and is_instance_valid(killer_player) and killer_player.character_stats:
killer_player.character_stats.kills += 1
print(name, " kill credited to ", killer_player.name, " (total kills: ", killer_player.character_stats.kills, ")")
# Spawn loot immediately (before death animation)
_spawn_loot()
@@ -465,7 +529,7 @@ func _sync_position(pos: Vector2, vel: Vector2, z_pos: float = 0.0, dir: int = 0
# Clients receive position and animation updates from server
# Only process if we're not the authority (i.e., we're a client)
if is_multiplayer_authority():
return # Server ignores its own updates
return # Server ignores its own updates
# Debug: Log when client receives position update (first few times)
if not has_meta("position_sync_count"):
@@ -474,7 +538,7 @@ func _sync_position(pos: Vector2, vel: Vector2, z_pos: float = 0.0, dir: int = 0
var sync_count = get_meta("position_sync_count") + 1
set_meta("position_sync_count", sync_count)
if sync_count <= 3: # Log first 3 syncs
if sync_count <= 3: # Log first 3 syncs
print("Enemy ", name, " (client) received position sync #", sync_count, ": pos=", pos)
# Update position and state
@@ -504,7 +568,7 @@ func _sync_damage_visual():
# Clients receive damage visual sync
# Only process if we're not the authority (i.e., we're a client)
if is_multiplayer_authority():
return # Server ignores its own updates
return # Server ignores its own updates
_flash_damage()
@@ -513,7 +577,7 @@ func _sync_death():
# Clients receive death sync and play death animation locally
# Only process if we're not the authority (i.e., we're a client)
if is_multiplayer_authority():
return # Server ignores its own updates
return # Server ignores its own updates
if not is_dead:
is_dead = true
@@ -521,7 +585,7 @@ func _sync_death():
# Remove collision layer so they don't collide with players, but still collide with walls
# This matches what happens on the server when rats/slimes die
set_collision_layer_value(2, false) # Remove from enemy collision layer (layer 2)
set_collision_layer_value(2, false) # Remove from enemy collision layer (layer 2)
# Immediately mark as dead and stop AI/physics
# This prevents "inactive" enemies that are already dead