extends Node var aggro_tables: Dictionary = {} var players_in_range: Dictionary = {} func add_aggro(enemy: Node, player: Node, amount: float) -> void: if enemy not in aggro_tables: aggro_tables[enemy] = {} if player in aggro_tables[enemy]: aggro_tables[enemy][player] += amount else: aggro_tables[enemy][player] = amount func remove_aggro(enemy: Node, player: Node, amount: float) -> void: if enemy in aggro_tables and player in aggro_tables[enemy]: aggro_tables[enemy][player] -= amount if aggro_tables[enemy][player] <= 0: aggro_tables[enemy].erase(player) func add_player_in_range(enemy: Node, player: Node) -> void: if enemy not in players_in_range: players_in_range[enemy] = [] if player not in players_in_range[enemy]: players_in_range[enemy].append(player) func remove_player_in_range(enemy: Node, player: Node) -> void: if enemy in players_in_range: players_in_range[enemy].erase(player) func is_player_in_any_range(player: Node) -> bool: for enemy in players_in_range: if is_instance_valid(enemy) and player in players_in_range[enemy]: return true return false func get_top_target(table: Dictionary) -> Node: var top: Node = null var top_val := 0.0 for player in table: if is_instance_valid(player) and table[player] > top_val: top_val = table[player] top = player return top func update_target(enemy: Node) -> void: if not "state" in enemy: return var table: Dictionary = aggro_tables[enemy] var top: Node = get_top_target(table) if top and top != enemy.target: enemy.target = top if enemy.state == enemy.State.IDLE or enemy.state == enemy.State.RETURN: enemy.state = enemy.State.CHASE elif not top and enemy.state != enemy.State.IDLE and enemy.state != enemy.State.RETURN: enemy.target = null enemy.state = enemy.State.RETURN func get_enemies_in_radius(source: Node, radius: float) -> Array: var result: Array = [] for enemy in get_tree().get_nodes_in_group("enemies"): if enemy != source and is_instance_valid(enemy): var dist: float = source.global_position.distance_to(enemy.global_position) if dist <= radius: result.append(enemy) return result func get_alert_radius(entity: Node) -> float: var base: BaseStats = Stats.get_base(entity) return base.alert_radius if base is EnemyStats else 10.0 func erase_entity(entity: Node) -> void: aggro_tables.erase(entity) players_in_range.erase(entity) for enemy in aggro_tables: if is_instance_valid(enemy): aggro_tables[enemy].erase(entity) if "target" in enemy and entity == enemy.target: enemy.target = null enemy.state = enemy.State.RETURN for enemy in players_in_range: if is_instance_valid(enemy): players_in_range[enemy].erase(entity)