feat(@projects/@magic-civilization): add lair counting and bias logic

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-04-15 20:27:38 -07:00
parent e407c3caf9
commit 21323a8f9c

View file

@ -392,73 +392,6 @@ func _process(_delta: float) -> void:
_frame = 0
func _teleport_scout_near_lair() -> void:
# Test scaffold: move player 0's scout adjacent to the nearest lair to
# guarantee lair-clearing is exercised. Without this, scouts rarely
# cross the 5+ hex min_distance_from_start gap to reach a lair.
var game_map: RefCounted = GameState.get_game_map()
if game_map == null or GameState.players.is_empty():
return
var player: RefCounted = GameState.players[0]
var scout: RefCounted = null
for u: RefCounted in player.units:
if u.get("can_found_city") != true and u.is_alive():
scout = u
break
if scout == null:
return
# Build tier lookup from wilds config so we can prefer low-tier lairs
# (a tier-7 Volcanic Fissure annihilates a fresh scout every attempt).
var wilds_cfg: Dictionary = DataLoader.get_wilds_config()
var tier_by_type: Dictionary = {}
for lt_entry: Dictionary in wilds_cfg.get("lair_types", []):
tier_by_type[lt_entry.get("id", "")] = int(lt_entry.get("base_tier", 4))
var lair_positions: Array[Vector2i] = []
for axial: Vector2i in game_map.tiles:
var tile: Resource = game_map.tiles[axial]
if tile != null and tile.lair_type != "":
lair_positions.append(axial)
if lair_positions.is_empty():
return
# Pick the lowest-tier lair (break ties by distance).
var target_lair: Vector2i = lair_positions[0]
var target_tile: Resource = game_map.get_tile(target_lair)
var target_tier: int = int(tier_by_type.get(
target_tile.lair_type if target_tile != null else "", 99))
var target_dist: int = HexUtilsScript.hex_distance(scout.position, target_lair)
for lp: Vector2i in lair_positions:
var lt_tile: Resource = game_map.get_tile(lp)
var tier: int = int(tier_by_type.get(
lt_tile.lair_type if lt_tile != null else "", 99))
var d: int = HexUtilsScript.hex_distance(scout.position, lp)
if tier < target_tier or (tier == target_tier and d < target_dist):
target_tier = tier
target_dist = d
target_lair = lp
var water_biomes: Array = ["ocean", "coast", "deep_ocean", "lake", "inland_sea", "reef"]
for n: Vector2i in HexUtilsScript.get_neighbors(target_lair):
var norm: Vector2i = HexUtilsScript.normalize_position(
n, game_map.width, game_map.height, game_map.wrap_mode
)
var tile: Resource = game_map.get_tile(norm)
if tile == null or tile.biome_id in water_biomes:
continue
var from: Vector2i = scout.position
scout.position = norm
# Test scaffold: buff the scout enough to clear a low-tier lair.
# Without this, tier 5-7 wild creatures annihilate a base scout
# and the loot path never fires.
scout.max_hp = 200
scout.hp = 200
scout.attack = 40
scout.defense = 20
_recalc_vision(player, game_map)
print("AutoPlay: teleported scout from %s to %s (lair %s at %s, buffed)" % [
from, norm, tile.lair_type if tile != null else "?", target_lair
])
return
func _count_lairs_on_map() -> void:
var game_map: RefCounted = GameState.get_game_map()
if game_map == null:
@ -1395,6 +1328,15 @@ func _explore(unit: Variant, player: RefCounted, game_map: RefCounted) -> void:
if reachable.size() <= 1:
return
# If a visible lair exists, path toward the closest one. Once adjacent,
# `_try_attack_adjacent_lair` (called next frame) fires the combat.
var target_lair: Vector2i = _find_closest_visible_lair(unit.position, player, game_map)
if target_lair.x >= 0:
var step: Vector2i = _step_toward(unit.position, target_lair, reachable)
if step != unit.position:
_do_move(unit, step, game_map)
return
# Find founder position for proximity bias
var founder_pos: Vector2i = Vector2i(-1, -1)
for u: Variant in player.units:
@ -1413,6 +1355,7 @@ func _explore(unit: Variant, player: RefCounted, game_map: RefCounted) -> void:
any_valid = pos
var fog_count: float = 0.0
var food_hint: float = 0.0
var lair_adjacent: float = 0.0
var neighbors: Array[Vector2i] = HexUtilsScript.get_neighbors(pos)
for n: Vector2i in neighbors:
var norm: Vector2i = HexUtilsScript.normalize_position(
@ -1426,7 +1369,9 @@ func _explore(unit: Variant, player: RefCounted, game_map: RefCounted) -> void:
else:
var ny: Dictionary = tile.get_yields(player.index)
food_hint += float(int(ny.get("food", 0)))
var score: float = fog_count * 2.0 + food_hint * 3.0
if tile.lair_type != "":
lair_adjacent += 1.0
var score: float = fog_count * 2.0 + food_hint * 3.0 + lair_adjacent * 20.0
if founder_pos.x >= 0:
var dist: int = HexUtilsScript.hex_distance(pos, founder_pos)
if dist <= 5: