feat(ai): Implement wild creature movement/behavior rules for new decision-making and environmental interactions

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
autocommit 2026-04-16 00:19:22 -07:00
parent ca44c25695
commit b0e5dd1322

View file

@ -47,10 +47,9 @@ func spawn_initial_creatures(game_map: RefCounted) -> void:
var wilds_cfg: Dictionary = _get_wilds_config()
var lair_types: Array = wilds_cfg.get("lair_types", [])
var primary_layer: Dictionary = GameState.get_primary_layer()
print("WildAI.spawn: npc_buildings=%d primary_empty=%s lair_types=%d" % [GameState.npc_buildings.size(), primary_layer.is_empty(), lair_types.size()])
if primary_layer.is_empty():
return
var spawned: int = 0
for b: Variant in GameState.npc_buildings:
var type_id: String = b.type_id
# Skip non-lair buildings (villages, ruins)
@ -59,13 +58,11 @@ func spawn_initial_creatures(game_map: RefCounted) -> void:
var tier1_pool: Array = _get_tier_pool(type_id, "tier_1", lair_types)
if tier1_pool.is_empty():
print("WildAI.spawn: type_id=%s tier1_pool empty" % type_id)
continue
var unit_type_id: String = tier1_pool[_rng.randi() % tier1_pool.size()]
var unit_data: Dictionary = DataLoader.get_unit(unit_type_id)
if unit_data.is_empty():
print("WildAI.spawn: %s -> unit_data EMPTY" % unit_type_id)
continue
var unit: RefCounted = UnitScript.new()
@ -80,8 +77,6 @@ func spawn_initial_creatures(game_map: RefCounted) -> void:
primary_layer.get("units", []).append(unit)
EventBus.wild_creature_spawned.emit(unit, b.position)
spawned += 1
print("WildAI.spawn: total spawned=%d" % spawned)
func _act(
@ -166,10 +161,8 @@ func _move_toward(
var next_pos: Vector2i = path[1]
var units_there: Array = _unit_manager.get_units_at(next_pos)
for other: Variant in units_there:
if other is UnitScript and other.owner >= 0:
return
if _has_player_unit_at(next_pos):
return
var from_pos: Vector2i = unit.position
var tile: Variant = game_map.get_tile(next_pos)
@ -205,13 +198,7 @@ func _roam(
continue
if HexUtilsScript.hex_distance(neighbor, home_pos) > leash_radius:
continue
var units_there: Array = _unit_manager.get_units_at(neighbor)
var has_player_unit: bool = false
for u: Variant in units_there:
if u is UnitScript and u.owner >= 0:
has_player_unit = true
break
if not has_player_unit:
if not _has_player_unit_at(neighbor):
valid.append(neighbor)
if valid.is_empty():
@ -224,6 +211,14 @@ func _roam(
EventBus.unit_moved.emit(unit, from_pos, dest)
func _has_player_unit_at(pos: Vector2i) -> bool:
var primary_layer: Dictionary = GameState.get_primary_layer()
for u: Variant in primary_layer.get("units", []):
if u is UnitScript and u.owner >= 0 and u.position == pos and u.is_alive():
return true
return false
func _get_tier_pool(lair_type_id: String, tier: String, lair_types: Array) -> Array:
for lt: Dictionary in lair_types:
if lt.get("id", "") == lair_type_id: