feat(ai): Add capital wall prioritization logic to prioritize early-game defense in SimpleHeuristicAI

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
autocommit 2026-04-16 13:23:52 -07:00
parent e40332e4d8
commit 093d52a7ab

View file

@ -503,6 +503,20 @@ static func _decide_production(
var threatened: bool = bool(threat.get("threatens_city", false))
var enemy_total: int = int(threat.get("total_count", 0))
# Capital walls interject: a 1-city capital that's >20 turns old with at
# least one defender gets walls slotted in BEFORE any other priority
# (including threat preemption). Walls were starved indefinitely during
# early harassment phases where threat-preempt locked us to warriors.
var capital_age: int = GameState.turn_number - int(city.turn_founded)
var capital_needs_walls: bool = (
city_count == 1 and city_index == 0
and military_count >= 1 and capital_age > 20
and not city.has_building("walls")
and city.can_build("walls", player)
)
if capital_needs_walls:
return _prod_building(city_index, "walls")
# Threat preemption: when an enemy stack is closing on a city, force
# military production over walls/happiness/founders until we can field
# at least enemy_total + 1 defenders (matches opponent's full army, not
@ -519,25 +533,11 @@ static func _decide_production(
# T100. After T80 the standard Priority 4 target takes over.
var early_mil_floor: int = 4 if GameState.turn_number <= 80 else 0
if military_count < maxi(1, early_mil_floor):
# Capital walls interject: once the capital has at least 1 defender
# and is >20 turns old, pause military top-up to slot walls in. Walls
# were being starved indefinitely by the mil-floor above; a T40-50
# wall hardens the capital before the opponent's full army arrives.
var capital_age: int = (
GameState.turn_number - int(city.turn_founded)
var emergency_unit: String = _pick_buildable_military_unit_id(
city, player
)
var capital_needs_walls: bool = (
city_count == 1 and city_index == 0
and military_count >= 1 and capital_age > 20
and not city.has_building("walls")
and city.can_build("walls", player)
)
if not capital_needs_walls:
var emergency_unit: String = _pick_buildable_military_unit_id(
city, player
)
if not emergency_unit.is_empty():
return _prod_unit(city_index, emergency_unit)
if not emergency_unit.is_empty():
return _prod_unit(city_index, emergency_unit)
# Priority 1: Build walls if city has none (defense first)
if not city.has_building("walls") and city.can_build("walls", player):