remove(entities): 🔥 Remove combat utility functions from GDScript after migration to Rust-based resolver
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
dc834d7363
commit
7aec731e80
2 changed files with 0 additions and 172 deletions
|
|
@ -1,171 +0,0 @@
|
|||
class_name CombatUtils
|
||||
extends RefCounted
|
||||
## Static utility functions for combat: unit/city lookup, death handling, siege capture.
|
||||
## No damage computation lives here — all combat math is in Rust (GdCombatResolver).
|
||||
|
||||
const UnitScript = preload("res://engine/src/entities/unit.gd")
|
||||
const CityScript = preload("res://engine/src/entities/city.gd")
|
||||
const HexUtilsScript = preload("res://engine/src/map/hex_utils.gd")
|
||||
const ItemSystemScript = preload("res://engine/src/modules/management/item_system.gd")
|
||||
|
||||
|
||||
## Get garrison combat unit at a city tile.
|
||||
static func get_garrison(pos: Vector2i, all_units: Array) -> RefCounted:
|
||||
for unit: RefCounted in all_units:
|
||||
if unit is UnitScript and unit.position == pos and unit.is_military():
|
||||
return unit
|
||||
return null
|
||||
|
||||
|
||||
## Get all units at a position.
|
||||
static func get_units_at(pos: Vector2i, all_units: Array) -> Array:
|
||||
var result: Array = []
|
||||
for unit: RefCounted in all_units:
|
||||
if unit is UnitScript and unit.position == pos:
|
||||
result.append(unit)
|
||||
return result
|
||||
|
||||
|
||||
## Get all specialist units at a position owned by non-attacker.
|
||||
static func get_specialists_at(pos: Vector2i, all_units: Array, attacker_owner: int) -> Array:
|
||||
var result: Array = []
|
||||
for unit: RefCounted in all_units:
|
||||
if unit is UnitScript and unit.position == pos and unit.owner != attacker_owner:
|
||||
if unit.is_specialist():
|
||||
result.append(unit)
|
||||
return result
|
||||
|
||||
|
||||
## Get all units adjacent to a position.
|
||||
static func get_adjacent_units(pos: Vector2i, all_units: Array) -> Array:
|
||||
var neighbors: Array[Vector2i] = HexUtilsScript.get_neighbors(pos)
|
||||
var result: Array = []
|
||||
for neighbor_pos: Vector2i in neighbors:
|
||||
for unit: RefCounted in all_units:
|
||||
if unit is UnitScript and unit.position == neighbor_pos:
|
||||
result.append(unit)
|
||||
return result
|
||||
|
||||
|
||||
## Get the city at a position (if any) from GameState.
|
||||
static func get_city_at(pos: Vector2i) -> RefCounted:
|
||||
for player: RefCounted in GameState.players:
|
||||
for city: RefCounted in player.cities:
|
||||
if city is CityScript and city.position == pos:
|
||||
return city
|
||||
return null
|
||||
|
||||
|
||||
## Whether this unit is a siege unit (gets bonus vs cities).
|
||||
static func is_siege_unit(unit: RefCounted) -> bool:
|
||||
if unit is UnitScript:
|
||||
return unit.get_combat_type() == "siege"
|
||||
return false
|
||||
|
||||
|
||||
## Handle a unit's death: check soul gem, drop loot, remove from game state, emit signal.
|
||||
static func handle_unit_death(unit: RefCounted, killer: RefCounted, all_units: Array) -> void:
|
||||
if not unit is UnitScript:
|
||||
return
|
||||
|
||||
# Soul Gem check: resurrect at 30% HP instead of dying.
|
||||
if ItemSystemScript.has_active_item(unit, "soul_gem"):
|
||||
ItemSystemScript.consume_charge(unit, "soul_gem")
|
||||
unit.hp = maxi(int(float(unit.get_max_hp()) * 0.3), 1)
|
||||
return
|
||||
|
||||
# Drop equipped items as ground loot before removing the unit.
|
||||
# ItemSystem.drop_all_loot wants the dying unit's tile, not the whole
|
||||
# map — passing the map used to Array-type-error the FFI and abort the
|
||||
# death handler before it could emit unit_destroyed.
|
||||
var primary_layer: Dictionary = GameState.get_primary_layer()
|
||||
if not primary_layer.is_empty():
|
||||
var game_map: RefCounted = primary_layer.get("map")
|
||||
if game_map != null:
|
||||
var tile: Resource = game_map.get_tile(unit.position) as Resource
|
||||
if tile != null:
|
||||
ItemSystemScript.drop_all_loot(unit, tile)
|
||||
|
||||
if unit.owner == -1 and killer != null and killer is UnitScript and killer.owner >= 0:
|
||||
_roll_wild_creature_loot(unit, killer)
|
||||
|
||||
all_units.erase(unit)
|
||||
|
||||
if unit.owner >= 0 and unit.owner < GameState.players.size():
|
||||
var player: RefCounted = GameState.players[unit.owner]
|
||||
player.units.erase(unit)
|
||||
|
||||
if not primary_layer.is_empty():
|
||||
primary_layer.get("units", []).erase(unit)
|
||||
|
||||
EventBus.unit_destroyed.emit(unit, killer)
|
||||
|
||||
|
||||
## Handle city capture: transfer ownership, emit signals, destroy High Archon if capital.
|
||||
static func capture_city(
|
||||
city: RefCounted,
|
||||
attacker: RefCounted,
|
||||
old_owner: int,
|
||||
all_units: Array,
|
||||
) -> void:
|
||||
var old_player: RefCounted = GameState.get_player(old_owner)
|
||||
var new_player: RefCounted = GameState.get_player(attacker.owner)
|
||||
if old_player != null:
|
||||
old_player.cities.erase(city)
|
||||
# p1-29a — increment cumulative city-loss counter on the dispossessed
|
||||
# player. Drives last-stand defense multiplier when they reach 1 city
|
||||
# remaining. Never decremented (persists even on recapture).
|
||||
old_player.cities_lost_total += 1
|
||||
if new_player != null and city not in new_player.cities:
|
||||
new_player.cities.append(city)
|
||||
|
||||
city.owner = attacker.owner
|
||||
city.is_capital = false
|
||||
city.captured_turn = GameState.turn_number
|
||||
|
||||
for tile_pos: Vector2i in city.owned_tiles:
|
||||
var layer: Dictionary = GameState.get_primary_layer()
|
||||
if layer.is_empty():
|
||||
continue
|
||||
var map_ref: RefCounted = layer.get("map")
|
||||
if map_ref == null:
|
||||
continue
|
||||
var t: RefCounted = map_ref.get_tile(tile_pos)
|
||||
if t != null:
|
||||
t.owner = attacker.owner
|
||||
|
||||
if old_player != null:
|
||||
_destroy_high_archon(old_player, all_units)
|
||||
|
||||
EventBus.city_captured.emit(city, old_owner, attacker.owner)
|
||||
|
||||
if old_player != null and old_player.cities.is_empty() and not old_player.is_eliminated:
|
||||
# Latch dedupes against victory_manager._reconcile_eliminations,
|
||||
# which sweeps the same condition each turn.
|
||||
old_player.is_eliminated = true
|
||||
EventBus.player_eliminated.emit(old_owner)
|
||||
|
||||
|
||||
static func _roll_wild_creature_loot(victim: RefCounted, killer: RefCounted) -> void:
|
||||
if killer.owner < 0 or killer.owner >= GameState.players.size():
|
||||
return
|
||||
var killer_player: RefCounted = GameState.players[killer.owner]
|
||||
var creature_type: String = victim.type_id if victim.type_id != "" else victim.unit_id
|
||||
var turn_seed: int = GameState.game_rng.seed ^ GameState.turn_number
|
||||
var killer_id: int = hash(killer.id)
|
||||
var victim_id: int = hash(victim.id)
|
||||
ItemSystemScript.roll_fauna_drops(creature_type, killer_player, turn_seed, killer_id, victim_id)
|
||||
|
||||
|
||||
## Destroy the High Archon of a player (capital capture penalty).
|
||||
static func _destroy_high_archon(player: RefCounted, all_units: Array) -> void:
|
||||
for unit: RefCounted in player.units:
|
||||
if unit is UnitScript and unit.type_id == "high_archon":
|
||||
unit.hp = 0
|
||||
all_units.erase(unit)
|
||||
player.units.erase(unit)
|
||||
var primary_layer: Dictionary = GameState.get_primary_layer()
|
||||
if not primary_layer.is_empty():
|
||||
primary_layer.get("units", []).erase(unit)
|
||||
EventBus.unit_destroyed.emit(unit, null)
|
||||
break
|
||||
|
|
@ -1 +0,0 @@
|
|||
uid://e7rxe1g4o8hn
|
||||
Loading…
Add table
Reference in a new issue