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: var table: Dictionary = aggro_tables[enemy] var top: Node = get_top_target(table) var data_source: Node = _get_data_source(enemy) if not data_source: return var state: int = data_source.get_stat(enemy, "state") if top and top != data_source.get_stat(enemy, "target"): data_source.set_stat(enemy, "target", top) if state == 0 or state == 3: data_source.set_stat(enemy, "state", 1) elif not top and state != 0 and state != 3: data_source.set_stat(enemy, "target", null) data_source.set_stat(enemy, "state", 3) 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 data_source: Node = _get_data_source(entity) if data_source: var base: EnemyStats = data_source.get_base(entity) if base: return base.alert_radius return 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) var data_source: Node = _get_data_source(enemy) if data_source and data_source.get_stat(enemy, "target") == entity: data_source.set_stat(enemy, "target", null) data_source.set_stat(enemy, "state", 3) for enemy in players_in_range: if is_instance_valid(enemy): players_in_range[enemy].erase(entity) func _get_data_source(entity: Node) -> Node: if entity.is_in_group("boss"): return BossData elif entity.is_in_group("enemies"): return EnemyData return null