extends BaseUnit class_name BaseEnemy ## Base class for all enemies in the game ## Provides common enemy functionality like AI, pathfinding, and targeting signal target_changed(new_target: Node) ## Current target (usually a player) var current_target: Node = null ## Enemy detection/aggro range @export var detection_range: float = 10.0 ## Whether this enemy is aggressive (will attack players) @export var is_aggressive: bool = true func _ready(): super._ready() # Enemies should respawn by default can_respawn = true # Connect to health signals for AI reactions health_changed.connect(_on_enemy_health_changed) died.connect(_on_enemy_died) respawned.connect(_on_enemy_respawned) func _physics_process(delta): # Only server handles enemy AI if not multiplayer.is_server(): return if is_dead: return # Update target if needed _update_target() ## Find and update current target func _update_target(): # Subclasses can override this to implement custom targeting logic pass ## Get all players in range func get_players_in_range(range_dist: float) -> Array[Node]: var players_in_range: Array[Node] = [] # Find the players container var level = get_tree().get_current_scene() if not level or not level.has_node("PlayersContainer"): return players_in_range var players_container = level.get_node("PlayersContainer") for player in players_container.get_children(): if player is Character and not player.is_dead: var distance = global_position.distance_to(player.global_position) if distance <= range_dist: players_in_range.append(player) return players_in_range ## Get nearest player func get_nearest_player() -> Node: var players = get_players_in_range(detection_range) if players.is_empty(): return null var nearest_player = null var nearest_distance = INF for player in players: var distance = global_position.distance_to(player.global_position) if distance < nearest_distance: nearest_distance = distance nearest_player = player return nearest_player ## Health changed callback func _on_enemy_health_changed(old_health: float, new_health: float): # Subclasses can override to react to damage pass ## Death callback func _on_enemy_died(killer_id: int): print("[Enemy ", name, "] died. Killer ID: ", killer_id) # Subclasses can override for death effects pass ## Respawn callback func _on_enemy_respawned(): print("[Enemy ", name, "] respawned at ", global_position) # Clear target on respawn current_target = null target_changed.emit(null) # Subclasses can override for respawn effects pass ## Override hurt animation @rpc("any_peer", "call_local", "reliable") func _play_hurt_animation(): # Flash red or play hurt animation # Subclasses should implement this with their specific animations pass