diff --git a/docs/architecture/legacy-engine-events.md b/docs/architecture/legacy-engine-events.md index c5d4380..7cf99fb 100644 --- a/docs/architecture/legacy-engine-events.md +++ b/docs/architecture/legacy-engine-events.md @@ -13,6 +13,19 @@ references include `legacy/hwe/sammo/TurnExecutionHelper.php`, - `StaticEventHandler::handleEvent(...)` - Invoked by many commands and API handlers to run per-action static hooks. +## Event Table Schema + +`event` rows are stored in the legacy DB schema (`legacy/hwe/sql/schema.sql`): + +- `id`: auto-increment primary key +- `target`: enum of `PRE_MONTH`, `MONTH`, `OCCUPY_CITY`, `DESTROY_NATION`, `UNITED` +- `priority`: higher first (default 1000) +- `condition`: JSON array (condition DSL) +- `action`: JSON array (action DSL) + +Indexes: `(target, priority, id)` for dispatch ordering. Both `condition` and +`action` are JSON-validated by DB constraints. + ## Event Table Dispatch `runEventHandler()` drives the dynamic event pipeline: @@ -71,6 +84,18 @@ Static events are hooks triggered directly by commands/APIs: - These hooks are used to extend command behavior without modifying the command code itself (e.g., troop join/exit side effects). +### Static Handler Map Sources + +`GameConst::$staticEventHandlers` defaults to an empty array in +`legacy/hwe/sammo/GameConstBase.php`. Scenario JSON can override it: + +- `legacy/hwe/scenario/scenario_911.json` (only observed override in repo) + - `sammo\\API\\Troop\\JoinTroop` → `event_부대탑승즉시이동` + - `sammo\\Command\\Nation\\che_발령` → `event_부대발령즉시집합` + +Static handler names should map to classes in `legacy/hwe/sammo/StaticEvent/` +(class name matches handler key). + ## RNG Notes Dynamic event actions can use deterministic RNG by constructing @@ -81,6 +106,5 @@ Examples include `RandomizeCityTradeRate` and `UpdateNationLevel`. - `Event\Engine` is a stub with a TODO; it is not currently used in the main turn pipeline. -- The full mapping of `GameConst::$staticEventHandlers` to events should be - extracted from scenario configs and command usage when documenting specific - rule packs. +- Verify whether any runtime code injects additional static handlers beyond + scenario JSON overrides. diff --git a/docs/architecture/legacy-engine-war.md b/docs/architecture/legacy-engine-war.md index e59b3d5..b474b2c 100644 --- a/docs/architecture/legacy-engine-war.md +++ b/docs/architecture/legacy-engine-war.md @@ -74,6 +74,96 @@ After `processWar_NG()`: - Update `diplomacy.dead` for both sides - If city conquered: call `ConquerCity()` +## Conflict Tracking (`city.conflict`) + +City conflict tracks which nations contributed to siege damage, used to +resolve post-war ownership when multiple attackers participate. + +Source: `WarUnitCity::addConflict()` in `legacy/hwe/sammo/WarUnitCity.php`. + +- `city.conflict` is a JSON map `{ nationID: deadContribution }`. +- Contribution amount is based on city `dead` (minimum 1). +- First/last hit bonus: if no conflict exists yet or city HP is 0, `dead` is + multiplied by 1.05 ("선타, 막타 보너스"). +- Contributions are sorted descending via `arsort()` after updates. +- `addConflict()` returns `true` when a new nation enters the conflict, which + triggers the global "분쟁" log in `processWar()`. +- `getConquerNation()` returns the first key of the sorted map to select the + final owner. +- `DeleteConflict($nation)` removes a nation from all city conflicts, used on + nation deletion and on the `che_방랑` flow. + +## City Conquest Resolution (`ConquerCity`) + +`ConquerCity()` finalizes city ownership, handles nation collapse, and applies +post-siege side effects. It is deterministic with the conquest RNG seed noted +below. + +### Common Flow + +- Logs conquest to attacker (general/nation/global) and defender nation history. +- Runs `EventTarget::OCCUPY_CITY` handlers via `TurnExecutionHelper::runEventHandler()`. +- Calls `onArbitraryAction(..., 'ConquerCity')` for each defender general in + the city, then persists them. + +### Nation Collapse Path + +Triggered when the defender nation owns exactly one city (the captured city): + +- Calls `deleteNation()` using the defender lord (officer level 12). +- All defender generals lose 20–50% of gold and rice, -10% experience, and + -50% dedication, with action logs. Loss amounts are aggregated. +- Optionally issues scout messages to fleeing generals (when `join_mode` allows). +- NPC defenders (NPC type 2–8 except 5) can auto-queue `che_임관` to the + attacker nation with a random delay (0–12 turns), gated by + `GameConst::$joinRuinedNPCProp`. +- Attacker reward: + - Half of defender nation gold/rice above base (`GameConst::$basegold`, + `GameConst::$baserice`) plus half of the aggregated general losses. + - Credited to attacker nation and logged to all chiefs (officer level >= 5). +- Runs `EventTarget::DESTROY_NATION` handlers. + +### Nation Survives Path + +If the defender nation still has other cities: + +- Demotes city officers (태수/군사/종사) to general: + - `officer_level = 1`, `officer_city = 0`. +- If the city was the capital: + - Picks a new capital via `findNextCapital()` (closest distance, highest pop). + - Logs an emergency relocation message to global and all nation generals. + - Sets `nation.capital` to new city and halves nation gold/rice. + - Marks new capital as supply city; moves chiefs to it. + - Applies 20% morale loss to all generals (`atmos *= 0.8`). + - Refreshes cached nation static info. + +### Final Ownership + City Reset + +`getConquerNation()` inspects `city.conflict` to decide final owner. If the +attacker loses arbitration, the city is transferred to the conflict winner +and logs are emitted for both nations. + +City stats are reset after ownership is settled: + +- `supply = 1`, `term = 0`, `conflict = {}`, `nation = conquerNation`, + `officer_set = 0`. +- `agri/comm/secu` multiplied by 0.7. +- `def/wall` reset: + - If `level > 3`: both set to `GameConst::$defaultCityWall`. + - Else: set to `def_max/2`, `wall_max/2`. +- Frontline status recalculated for all nearby nations (`SetNationFront()`). + +### Deterministic RNG + +Conquest RNG seed: +`hiddenSeed + 'ConquerCity' + year + month + attackerNationID + attackerID + cityID`. + +Used for: + +- Defender general loss ratios (20–50%). +- Scout message chance and NPC auto-join chance. +- Randomized join turn delay (0–12). + ## `WarUnitGeneral` Highlights - Train/atmos bonuses depend on city level and attacker/defender role. @@ -105,5 +195,5 @@ After `processWar_NG()`: ## Open Questions / Follow-ups -- Detailed conquest outcomes (nation collapse, officer handling) extend beyond - the summary here; see `ConquerCity()` in `legacy/hwe/process_war.php`. +- No automatic decay for `city.conflict` is visible; confirm if any scheduled + cleanup exists outside explicit reset paths. diff --git a/docs/architecture/todo.md b/docs/architecture/todo.md index fdee661..aa9ac3e 100644 --- a/docs/architecture/todo.md +++ b/docs/architecture/todo.md @@ -21,8 +21,6 @@ Move items into the main docs once they are finalized. ## Trigger System -- Trigger evaluation order and priority conflicts -- Composition rules across traits, specials, and scenario effects - Example trigger sets per scenario or rule pack ## Data and Profiles @@ -34,6 +32,11 @@ Move items into the main docs once they are finalized. - [AI suggestion] Expand monthly pipeline details (`preUpdateMonthly`, `postUpdateMonthly`, `turnDate`, `checkStatistic`) with concrete side effects and tables touched. - [AI suggestion] Document `ConquerCity()` resolution paths (nation collapse, officer handling, reward/penalty rules). -- [AI suggestion] Clarify command prefix semantics (`che_`, `cr_`, `event_`) and add per-command effect summaries. +- [AI suggestion] Add per-command effect summaries (inputs, resource deltas, logs). - [AI suggestion] Document `event` table schema and the static event handler map (`GameConst::$staticEventHandlers`) with command hook examples. - [AI suggestion] Document auction scheduling (`registerAuction` call sites) and lifecycle timing rules. +- [AI suggestion] Document scenario-specific unit/map overrides and per-map city deltas. +- [AI suggestion] Document per-command `Constraint` env payload keys and lifecycle. +- [AI suggestion] Document `MessageType` values and message table schema used by diplomacy/mailbox flows. +- [AI suggestion] Document `PenaltyKey` effects and the `GeneralBase` / `LazyVarAndAuxUpdater` state conventions. +- [AI suggestion] Document personality/special selection RNG thresholds and scenario overrides.