extends CharacterBody3D enum State { IDLE, CHASE, ATTACK, RETURN } var state: int = State.IDLE var target: Node3D = null var spawn_position: Vector3 var portal: Node3D = null var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity") @onready var health: Node = $Health func _ready() -> void: spawn_position = global_position add_to_group("enemies") EventBus.entity_died.connect(_on_entity_died) func _on_entity_died(entity: Node) -> void: if entity == self: queue_free() elif entity == target: target = null state = State.RETURN func _physics_process(delta: float) -> void: if not is_on_floor(): velocity.y -= gravity * delta move_and_slide() func _engage(new_target: Node3D) -> void: if state == State.CHASE or state == State.ATTACK: return target = new_target state = State.CHASE var aggro: Node = get_node_or_null("EnemyAggro") if aggro: aggro.add_aggro(new_target, 1.0) _alert_nearby() func _alert_nearby() -> void: var enemies := get_tree().get_nodes_in_group("enemies") for enemy in enemies: if enemy != self and is_instance_valid(enemy) and "state" in enemy: if enemy.state == enemy.State.IDLE: var dist: float = global_position.distance_to(enemy.global_position) if dist <= 3.0: enemy._engage(target) func _on_detection_area_body_entered(body: Node3D) -> void: if body is CharacterBody3D and body.name == "Player": _engage(body) EventBus.enemy_engaged.emit(self, body) func _on_detection_area_body_exited(body: Node3D) -> void: if body == target and state == State.CHASE: state = State.RETURN target = null