feat(@projects/@magic-civilization): add prologue tribe capital founding logic

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-05-03 22:40:32 -04:00
parent 11ef4cfbc8
commit 7163f3ed7d
3 changed files with 55 additions and 18 deletions

View file

@ -1125,28 +1125,17 @@ func _found_capital_from_tribe(tribe_unit: RefCounted) -> void:
push_warning("WorldMap: dwarf_tribe unit present but prologue is null")
return
var pid: int = int(tribe_unit.owner)
var result: Dictionary = (TurnManager.prologue as PrologueDriverScript).found_capital(pid)
if result.is_empty():
push_warning("WorldMap: PrologueDriver.found_capital returned empty for player %d" % pid)
return
var pop: int = int(result.get("population", 1))
var q: int = int(result.get("q", tribe_unit.position.x))
var r: int = int(result.get("r", tribe_unit.position.y))
var player: RefCounted = GameState.get_player(pid)
if player == null:
return
var city: RefCounted = CityScript.new()
city.owner = pid
var city_name: String = "%s Hold" % str(player.player_name) if str(player.player_name) != "" else "Capital"
city.found_with_population(city_name, q, r, true, 1, pop)
player.cities.append(city)
# Consume the Dwarf Tribe unit and forward chronicle events.
_units_helper.remove_unit(tribe_unit, player)
EventBus.unit_destroyed.emit(tribe_unit, null)
EventBus.city_founded.emit(city, pid)
PrologueDriverScript.dispatch_chronicle_events(
result.get("chronicle_events", []) as Array
var city_name: String = (
"%s Hold" % str(player.player_name) if str(player.player_name) != "" else "Capital"
)
var city: RefCounted = (TurnManager.prologue as PrologueDriverScript).found_capital_for_tribe(
tribe_unit, player, city_name
)
if city == null:
return
_deselect_unit()
_sync_units()

View file

@ -145,6 +145,15 @@ static func dispatch_found_city(
return false
if settler.position != Vector2i(int(at_hex[0]), int(at_hex[1])):
return false
# Dwarf Tribe (prologue founder) carries a Lucky-mode founding_pop_override
# computed at convergence; route through PrologueDriver so AI capitals
# receive the same bonus pop the player path applies.
if settler.type_id == "dwarf_tribe" and TurnManager.prologue != null:
var prologue: RefCounted = TurnManager.prologue
var founded: RefCounted = prologue.call(
"found_capital_for_tribe", settler, player, city_name
)
return founded != null
var city: RefCounted = CityScript.new()
city.player = player
city.owner = player.index

View file

@ -117,6 +117,45 @@ func found_capital(player_id: int) -> Dictionary:
return _inner.call("found_capital", player_id) as Dictionary
## Found the capital from a Dwarf Tribe unit, applying the prologue's
## `founding_pop_override` (Lucky-mode bonus pop) and consuming the unit.
## Used by both the player path (world_map.gd:_found_capital_from_tribe)
## and the AI dispatch path (ai_turn_bridge_dispatch.dispatch_found_city)
## so AI capitals receive the same Lucky bonus the player does.
##
## Returns the founded City on success, null when the prologue is unavailable
## or returned an empty result. Caller is responsible for any post-found
## bookkeeping (deselect, sync renderers).
func found_capital_for_tribe(
tribe_unit: RefCounted, player: RefCounted, city_name: String
) -> RefCounted:
if not _available or tribe_unit == null or player == null:
return null
var pid: int = int(tribe_unit.owner)
var result: Dictionary = found_capital(pid)
if result.is_empty():
push_warning(
"PrologueDriver: found_capital returned empty for player %d" % pid
)
return null
var pop: int = int(result.get("population", 1))
var q: int = int(result.get("q", tribe_unit.position.x))
var r: int = int(result.get("r", tribe_unit.position.y))
var city_script: GDScript = load("res://engine/src/entities/city.gd") as GDScript
var city: RefCounted = city_script.new()
city.owner = pid
city.found_with_population(city_name, q, r, true, 1, pop)
player.cities.append(city)
player.units.erase(tribe_unit)
var primary: Dictionary = GameState.get_primary_layer()
var layer_units: Array = primary.get("units", [])
layer_units.erase(tribe_unit)
EventBus.unit_destroyed.emit(tribe_unit, null)
EventBus.city_founded.emit(city, pid)
dispatch_chronicle_events(result.get("chronicle_events", []) as Array)
return city
## Forward chronicle events through EventBus. Called internally on state
## transitions and after found_capital.
static func dispatch_chronicle_events(events: Array) -> void: