문서 업데이트: 레거시 엔진 아키텍처 및 명령 카탈로그 추가
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
# Legacy Command Catalog
|
||||
|
||||
This file lists the command keys available under `legacy/hwe/sammo/Command/`.
|
||||
Command keys match class names and file names; they are the values stored in
|
||||
`general_turn.action` and `nation_turn.action`.
|
||||
|
||||
## Command Resolution
|
||||
|
||||
- General: `buildGeneralCommandClass($type)` in `legacy/hwe/func_converter.php`
|
||||
- Nation: `buildNationCommandClass($type)` in `legacy/hwe/func_converter.php`
|
||||
- `null` or empty `type` defaults to `휴식`
|
||||
- Post-req turn cooldowns are stored in:
|
||||
- `next_execute` KV (per general)
|
||||
- `nation_env` KV (per nation)
|
||||
|
||||
## Execution Semantics (BaseCommand)
|
||||
|
||||
- Conditions are checked via constraint sets (permission/min/full).
|
||||
- `getPreReqTurn()` is enforced by `LastTurn` term stacking.
|
||||
- `getPostReqTurn()` is enforced by `next_execute` (cooldown).
|
||||
- If `run()` returns `false`, `getAlternativeCommand()` may be used.
|
||||
|
||||
## Command Prefixes and Scenarios
|
||||
|
||||
Command keys are scenario-driven. The prefixes (e.g. `che_`, `cr_`, `event_`)
|
||||
identify the rule set or scenario extension, and the active scenario chooses
|
||||
which commands are available via `GameConst` overrides. See
|
||||
`docs/architecture/legacy-scenarios.md` for details.
|
||||
|
||||
## General Commands (`legacy/hwe/sammo/Command/General/`)
|
||||
|
||||
| Key | Display name (actionName) |
|
||||
| --- | --- |
|
||||
| `che_NPC능동` | `NPC능동` |
|
||||
| `che_강행` | `강행` |
|
||||
| `che_거병` | `거병` |
|
||||
| `che_건국` | `건국` |
|
||||
| `che_견문` | `견문` |
|
||||
| `che_군량매매` | `군량매매` |
|
||||
| `che_귀환` | `귀환` |
|
||||
| `che_기술연구` | `기술 연구` |
|
||||
| `che_내정특기초기화` | `내정 특기 초기화` |
|
||||
| `che_농지개간` | `농지 개간` |
|
||||
| `che_단련` | `단련` |
|
||||
| `che_등용` | `등용` |
|
||||
| `che_등용수락` | `등용 수락` |
|
||||
| `che_랜덤임관` | `무작위 국가로 임관` |
|
||||
| `che_모반시도` | `모반시도` |
|
||||
| `che_모병` | `모병` |
|
||||
| `che_무작위건국` | `무작위 도시 건국` |
|
||||
| `che_물자조달` | `물자조달` |
|
||||
| `che_방랑` | `방랑` |
|
||||
| `che_사기진작` | `사기진작` |
|
||||
| `che_상업투자` | `상업 투자` |
|
||||
| `che_선동` | `선동` |
|
||||
| `che_선양` | `선양` |
|
||||
| `che_성벽보수` | `성벽 보수` |
|
||||
| `che_소집해제` | `소집해제` |
|
||||
| `che_수비강화` | `수비 강화` |
|
||||
| `che_숙련전환` | `숙련전환` |
|
||||
| `che_요양` | `요양` |
|
||||
| `che_은퇴` | `은퇴` |
|
||||
| `che_이동` | `이동` |
|
||||
| `che_인재탐색` | `인재탐색` |
|
||||
| `che_임관` | `임관` |
|
||||
| `che_장비매매` | `장비매매` |
|
||||
| `che_장수대상임관` | `장수를 따라 임관` |
|
||||
| `che_전투태세` | `전투태세` |
|
||||
| `che_전투특기초기화` | `전투 특기 초기화` |
|
||||
| `che_접경귀환` | `접경귀환` |
|
||||
| `che_정착장려` | `정착 장려` |
|
||||
| `che_주민선정` | `주민 선정` |
|
||||
| `che_증여` | `증여` |
|
||||
| `che_집합` | `집합` |
|
||||
| `che_징병` | `징병` |
|
||||
| `che_첩보` | `첩보` |
|
||||
| `che_출병` | `출병` |
|
||||
| `che_치안강화` | `치안 강화` |
|
||||
| `che_탈취` | `탈취` |
|
||||
| `che_파괴` | `파괴` |
|
||||
| `che_하야` | `하야` |
|
||||
| `che_해산` | `해산` |
|
||||
| `che_헌납` | `헌납` |
|
||||
| `che_화계` | `화계` |
|
||||
| `che_훈련` | `훈련` |
|
||||
| `cr_건국` | `건국` |
|
||||
| `cr_맹훈련` | `맹훈련` |
|
||||
| `휴식` | `휴식` |
|
||||
|
||||
## Nation Commands (`legacy/hwe/sammo/Command/Nation/`)
|
||||
|
||||
| Key | Display name (actionName) |
|
||||
| --- | --- |
|
||||
| `che_감축` | `감축` |
|
||||
| `che_국기변경` | `국기변경` |
|
||||
| `che_국호변경` | `국호변경` |
|
||||
| `che_급습` | `급습` |
|
||||
| `che_몰수` | `몰수` |
|
||||
| `che_무작위수도이전` | `무작위 수도 이전` |
|
||||
| `che_물자원조` | `원조` |
|
||||
| `che_발령` | `발령` |
|
||||
| `che_백성동원` | `백성동원` |
|
||||
| `che_부대탈퇴지시` | `부대 탈퇴 지시` |
|
||||
| `che_불가침수락` | `불가침 수락` |
|
||||
| `che_불가침제의` | `불가침 제의` |
|
||||
| `che_불가침파기수락` | `불가침 파기 수락` |
|
||||
| `che_불가침파기제의` | `불가침 파기 제의` |
|
||||
| `che_선전포고` | `선전포고` |
|
||||
| `che_수몰` | `수몰` |
|
||||
| `che_의병모집` | `의병모집` |
|
||||
| `che_이호경식` | `이호경식` |
|
||||
| `che_종전수락` | `종전 수락` |
|
||||
| `che_종전제의` | `종전 제의` |
|
||||
| `che_증축` | `증축` |
|
||||
| `che_천도` | `천도` |
|
||||
| `che_초토화` | `초토화` |
|
||||
| `che_포상` | `포상` |
|
||||
| `che_피장파장` | `피장파장` |
|
||||
| `che_필사즉생` | `필사즉생` |
|
||||
| `che_허보` | `허보` |
|
||||
| `cr_인구이동` | `인구이동` |
|
||||
| `event_극병연구` | `극병 연구` |
|
||||
| `event_대검병연구` | `대검병 연구` |
|
||||
| `event_무희연구` | `무희 연구` |
|
||||
| `event_산저병연구` | `산저병 연구` |
|
||||
| `event_상병연구` | `상병 연구` |
|
||||
| `event_원융노병연구` | `원융노병 연구` |
|
||||
| `event_음귀병연구` | `음귀병 연구` |
|
||||
| `event_화륜차연구` | `화륜차 연구` |
|
||||
| `event_화시병연구` | `화시병 연구` |
|
||||
| `휴식` | `휴식` |
|
||||
|
||||
## Open Questions / Follow-ups
|
||||
|
||||
- Prefix semantics (`che_`, `cr_`, `event_`) are not documented here and may be
|
||||
scenario- or mode-specific.
|
||||
@@ -0,0 +1,121 @@
|
||||
# Legacy Engine Execution Flow
|
||||
|
||||
This document summarizes how the legacy engine advances turns and executes
|
||||
commands. It focuses on the execution pipeline, RNG seeding, and state writes
|
||||
based on `legacy/hwe/sammo/API/Global/ExecuteEngine.php`,
|
||||
`legacy/hwe/sammo/TurnExecutionHelper.php`, and `legacy/hwe/sammo/Command/BaseCommand.php`.
|
||||
|
||||
## Entry Point: ExecuteEngine API
|
||||
|
||||
- Endpoint: `legacy/hwe/sammo/API/Global/ExecuteEngine.php`
|
||||
- Session: no session required (`NO_SESSION`)
|
||||
- Optional `serverID` guard via `UniqueConst::$serverID`
|
||||
- Calls `TurnExecutionHelper::executeAllCommand($updated, $locked)`
|
||||
- Returns `{ updated, locked, lastExecuted }`
|
||||
|
||||
## Global Turn Loop (`TurnExecutionHelper::executeAllCommand`)
|
||||
|
||||
1. **Time gate**
|
||||
- If `now < game_env.turntime`, return without executing.
|
||||
2. **Locking**
|
||||
- `tryLock()` on `plock` row (`type='GAME'`).
|
||||
- If locked or `isunited` in `2|3`, return (frozen state).
|
||||
3. **Pre-turn maintenance**
|
||||
- Cache game env, `checkDelay()`, `updateOnline()`, `CheckOverhead()`.
|
||||
4. **Catch-up monthly loop**
|
||||
- Compute `prevTurn = cutTurn(turntime, turnterm)` and `nextTurn = addTurn(prevTurn)`.
|
||||
- While `nextTurn <= now`:
|
||||
- `executeGeneralCommandUntil(nextTurn, limitActionTime, year, month)`
|
||||
- `updateTraffic()`
|
||||
- Monthly pipeline:
|
||||
- `runEventHandler(PreMonth)`
|
||||
- `preUpdateMonthly()`
|
||||
- `turnDate(nextTurn)`
|
||||
- `checkStatistic()` (only if `month == 1`)
|
||||
- `runEventHandler(Month)`
|
||||
- `postUpdateMonthly($monthlyRng)`
|
||||
- Advance `prevTurn`, `nextTurn`, update `game_env.turntime`.
|
||||
5. **Current partial month**
|
||||
- `turnDate(prevTurn)`
|
||||
- `executeGeneralCommandUntil(now, limitActionTime, year, month)`
|
||||
6. **Post-turn maintenance**
|
||||
- `processTournament()`
|
||||
- `processAuction()`
|
||||
- Reset cache, `unlock()`.
|
||||
|
||||
`limitActionTime` is derived from `max_execution_time` (roughly 2/3 of the
|
||||
configured limit). If time runs out mid-loop, it returns early and keeps
|
||||
`game_env.turntime` at the most recent executed value.
|
||||
|
||||
## Per-General Execution (`executeGeneralCommandUntil`)
|
||||
|
||||
For each general with `turntime < targetDate` (ordered by `turntime, no`):
|
||||
|
||||
1. **Load state**
|
||||
- `General::createObjFromDB()` and `KVStorage` for `game_env`.
|
||||
2. **Nation command (if officer_level >= 5)**
|
||||
- Pull `nation_turn` row for `turn_idx = 0`.
|
||||
- Build `NationCommand` with `LastTurn` stored in `nation_env`.
|
||||
3. **AI/autorun**
|
||||
- NPCs (`npc >= 2`) or players past `autorun_limit` use `GeneralAI`.
|
||||
- AI can replace both nation and general commands.
|
||||
4. **Preprocess triggers**
|
||||
- RNG seed: `hiddenSeed + 'preprocess' + year + month + generalID`.
|
||||
- `preprocessCommand()` merges action triggers + `che_부상경감`, `che_병력군량소모`.
|
||||
5. **Blocked users**
|
||||
- `processBlocked()` consumes `killturn` and logs if `block >= 2`.
|
||||
6. **Execute nation command**
|
||||
- RNG seed: `hiddenSeed + 'nationCommand' + year + month + generalID + commandKey`.
|
||||
- `processNationCommand()` checks conditions, term stack, `run()`.
|
||||
- If `run()` fails and `getAlternativeCommand()` exists, it retries.
|
||||
- Updates `nation_env` with `LastTurn` result.
|
||||
7. **Execute general command**
|
||||
- Load from `general_turn` (`turn_idx = 0`), default to `휴식`.
|
||||
- RNG seed: `hiddenSeed + 'generalCommand' + year + month + generalID + commandKey`.
|
||||
- `processCommand()` checks conditions, term stack, `run()`.
|
||||
- Updates `killturn` based on NPC status, autorun, or `휴식`.
|
||||
8. **Queue maintenance & turntime**
|
||||
- `pullNationCommand()` / `pullGeneralCommand()` advance queues.
|
||||
- `updateTurnTime()` handles deletion/retirement and sets next `turntime`.
|
||||
- Persist via `General::applyDB()`.
|
||||
|
||||
## Command Semantics (BaseCommand)
|
||||
|
||||
- **Constraints**: permission/min/full conditions are evaluated via
|
||||
`Constraint::testAll()` with `general/city/nation/dest*` context.
|
||||
- **Pre-turn requirement**: `getPreReqTurn()` uses `LastTurn` to accumulate
|
||||
term stack (`addTermStack()`), logging "수행중" until the term completes.
|
||||
- **Post-turn requirement**: `getPostReqTurn()` uses `next_execute` storage
|
||||
(general: `next_execute`, nation: `nation_env`) to block early execution.
|
||||
- **Run flow**: `run($rng)` returns `true` when completed; `false` can chain to
|
||||
`getAlternativeCommand()`.
|
||||
|
||||
## Turntime & Lifecycle (`updateTurnTime`)
|
||||
|
||||
- **Inactivity**: if `killturn <= 0`:
|
||||
- NPC-owned characters can detach (owner -> NPC) if `deadyear` not reached.
|
||||
- Otherwise the general is deleted (`kill()`).
|
||||
- **Retirement**: if `age >= retirementYear` and not NPC, `CheckHall()` and
|
||||
`rebirth()` are invoked.
|
||||
- **Scheduling**: next `turntime` is `addTurn(current, turnterm)` with
|
||||
optional `nextTurnTimeBase` override (aux var).
|
||||
|
||||
## Deterministic RNG Seeds
|
||||
|
||||
RNG uses `LiteHashDRBG` with `UniqueConst::$hiddenSeed`:
|
||||
|
||||
- Preprocess: `('preprocess', year, month, generalID)`
|
||||
- Nation command: `('nationCommand', year, month, generalID, commandKey)`
|
||||
- General command: `('generalCommand', year, month, generalID, commandKey)`
|
||||
- Monthly: `('monthly', year, month)`
|
||||
|
||||
These seeds make command outcomes and monthly updates reproducible for
|
||||
validation.
|
||||
|
||||
## Open Questions / Follow-ups
|
||||
|
||||
- `preUpdateMonthly()`, `postUpdateMonthly()`, `turnDate()`, `checkStatistic()`
|
||||
are defined outside this flow; see `legacy/hwe/func_time_event.php` for
|
||||
economic updates and population calculations.
|
||||
- `updateTraffic()`, `checkDelay()`, `updateOnline()` logic lives in
|
||||
`legacy/hwe/func.php` and related utility files.
|
||||
@@ -0,0 +1,91 @@
|
||||
# Legacy General Model and Action Stack
|
||||
|
||||
This document captures how `General` aggregates modifiers, computes stats, and
|
||||
exposes trigger hooks. The main reference is `legacy/hwe/sammo/General.php`.
|
||||
|
||||
## Construction and Core State
|
||||
|
||||
- `General` builds from raw DB rows (general, city, nation, rank, access log).
|
||||
- `last_turn` is parsed into `LastTurn`, and a separate `resultTurn` is
|
||||
maintained for updates.
|
||||
- `penalty` JSON is decoded into `PenaltyKey -> value` map.
|
||||
- Rank data is tracked with:
|
||||
- `rankVarRead` (current read view)
|
||||
- `rankVarIncrease` (increment queue)
|
||||
- `rankVarSet` (explicit set queue)
|
||||
|
||||
## Action Objects (`iAction`)
|
||||
|
||||
`General` composes action sources into a single list:
|
||||
|
||||
1. Nation type (`buildNationTypeClass`)
|
||||
2. Officer level (`TriggerOfficerLevel`)
|
||||
3. Domestic special (`buildGeneralSpecialDomesticClass`)
|
||||
4. War special (`buildGeneralSpecialWarClass`)
|
||||
5. Personality (`buildPersonalityClass`)
|
||||
6. Crew type (`GameUnitConst::byID`)
|
||||
7. Inheritance buff (`TriggerInheritBuff`)
|
||||
8. Scenario effect (`buildScenarioEffectClass`)
|
||||
9. Items: horse / weapon / book / item (`buildItemClass`)
|
||||
|
||||
`getActionList()` returns this merged list and is the core entry point for
|
||||
modifiers and triggers.
|
||||
|
||||
## Stat Computation
|
||||
|
||||
`getStatValue()` applies layered modifiers:
|
||||
|
||||
- Base stat from raw value
|
||||
- Injury multiplier
|
||||
- Cross-stat adjust (strength/intel + 1/4 of the other stat)
|
||||
- Clamp to `GameConst::$maxLevel`
|
||||
- `onCalcStat()` from every action object
|
||||
- Cached by `(statName, injury, action, adjust)` tuple
|
||||
|
||||
Convenience wrappers:
|
||||
- `getLeadership()`, `getStrength()`, `getIntel()`
|
||||
|
||||
## Turn Reservation and LastTurn
|
||||
|
||||
- `getReservedTurn(turnIdx)` reads from `general_turn`.
|
||||
- When no entry exists, `buildGeneralCommandClass(null)` creates `휴식`.
|
||||
- `LastTurn` holds `{ command, arg, term, seq }` and is used by
|
||||
`BaseCommand::addTermStack()` to advance multi-turn commands.
|
||||
- `applyDB()` persists updated fields and writes `last_turn` if it changed.
|
||||
|
||||
## Trigger and Modifier Hooks
|
||||
|
||||
`General` delegates calculations and trigger lists through action objects:
|
||||
|
||||
- Economy/strategy: `onCalcDomestic`, `onCalcStrategic`,
|
||||
`onCalcNationalIncome`
|
||||
- Combat modifiers: `onCalcStat`, `onCalcOpposeStat`, `getWarPowerMultiplier`
|
||||
- Arbitrary actions: `onArbitraryAction` (used in city conquest)
|
||||
|
||||
Turn-prep triggers:
|
||||
|
||||
- `getPreTurnExecuteTriggerList()` merges trigger lists from every action
|
||||
object. `TurnExecutionHelper::preprocessCommand()` adds
|
||||
`che_부상경감` + `che_병력군량소모` on top.
|
||||
|
||||
Battle triggers:
|
||||
|
||||
- `getBattleInitSkillTriggerList()` merges per-action battle-init triggers.
|
||||
- `getBattlePhaseSkillTriggerList()` includes base phase triggers:
|
||||
- `che_필살시도`, `che_필살발동`
|
||||
- `che_회피시도`, `che_회피발동`
|
||||
- `che_계략시도`, `che_계략발동`, `che_계략실패`
|
||||
- plus any action-specific additions.
|
||||
|
||||
## Rank and Access Log Updates
|
||||
|
||||
- `increaseRankVar()` / `setRankVar()` queue updates until `applyDB()`.
|
||||
- `applyDB()` updates `general` and `rank_data`, then flushes logs.
|
||||
- `checkStatChange()` uses `*_exp` thresholds to increase/decrease stats and
|
||||
logs level changes.
|
||||
|
||||
## Open Questions / Follow-ups
|
||||
|
||||
- `PenaltyKey` effects and how penalties are applied are outside this file.
|
||||
- `GeneralBase` and `LazyVarAndAuxUpdater` may contain additional state
|
||||
conventions for new code to mirror.
|
||||
@@ -0,0 +1,109 @@
|
||||
# Legacy Battle and War Resolution
|
||||
|
||||
This document summarizes the legacy battle pipeline centered on
|
||||
`legacy/hwe/process_war.php`, `legacy/hwe/sammo/WarUnit.php`,
|
||||
`legacy/hwe/sammo/WarUnitGeneral.php`, and `legacy/hwe/sammo/WarUnitCity.php`.
|
||||
|
||||
## Entry Point: `processWar`
|
||||
|
||||
Inputs:
|
||||
|
||||
- `warSeed` (string): battle RNG seed
|
||||
- `attackerGeneral`: `General`
|
||||
- `rawAttackerNation`: nation row (snapshot)
|
||||
- `rawDefenderCity`: city row (snapshot)
|
||||
|
||||
Setup steps:
|
||||
|
||||
1. Initialize RNG with `warSeed` (`LiteHashDRBG`).
|
||||
2. Load defender nation row (or default neutral nation if `nation = 0`).
|
||||
3. Build `WarUnitGeneral` (attacker) and `WarUnitCity` (defender city).
|
||||
4. Collect defender generals in the city, filter with `extractBattleOrder()`.
|
||||
5. Optionally append city as defender if city order > 0.
|
||||
6. Sort defenders by battle order, iterate via `getNextDefender()`.
|
||||
7. Run `processWar_NG()`; update DB and nation/city stats.
|
||||
|
||||
## Battle Order (`extractBattleOrder`)
|
||||
|
||||
For defender generals:
|
||||
|
||||
- Must have crew > 0
|
||||
- Must have rice > crew/100
|
||||
- `train` and `atmos` must meet `defence_train`
|
||||
- Battle order uses:
|
||||
- `totalStat = (realStat + fullStat) / 2`
|
||||
- `totalCrew = crew / 1_000_000 * (train * atmos) ^ 1.5`
|
||||
- `totalStat + totalCrew / 100`
|
||||
|
||||
For cities:
|
||||
|
||||
- Uses attacker `onCalcOpposeStat('cityBattleOrder', -1)`.
|
||||
|
||||
## Battle Loop (`processWar_NG`)
|
||||
|
||||
1. Log start, include seed in battle logs.
|
||||
2. If no defenders remain, set defender = city and switch to siege.
|
||||
3. **Initial engagement**
|
||||
- `setOppose()` for attacker/defender
|
||||
- `addTrain(1)` for both
|
||||
- Fire battle-init triggers
|
||||
4. **Per phase**
|
||||
- `beginPhase()` computes war power
|
||||
- Fire battle-phase triggers
|
||||
- `calcDamage()` on both sides
|
||||
- Clamp damage if it exceeds HP ratios
|
||||
- Apply damage, increase killed/dead counters
|
||||
- Log phase results
|
||||
5. **Continuation checks**
|
||||
- `continueWar()` fails on no rice or HP <= 0
|
||||
- On retreat/defeat: log, apply win/lose, try wound
|
||||
- If defender removed, move to next defender (or city siege)
|
||||
6. **Finish**
|
||||
- `logBattleResult()` for last phase if needed
|
||||
- `finishBattle()` for attacker/defender
|
||||
- City conflict tracking and history logs
|
||||
|
||||
## Post-Battle Updates (`processWar`)
|
||||
|
||||
After `processWar_NG()`:
|
||||
|
||||
- Apply attacker DB updates
|
||||
- Update nation rice (supply and siege rules)
|
||||
- Distribute city `dead` counts (40% attacker city, 60% defender city)
|
||||
- Increase nation tech based on killed/dead and nation size adjustments
|
||||
- Update `diplomacy.dead` for both sides
|
||||
- If city conquered: call `ConquerCity()`
|
||||
|
||||
## `WarUnitGeneral` Highlights
|
||||
|
||||
- Train/atmos bonuses depend on city level and attacker/defender role.
|
||||
- War power:
|
||||
- Base attack/defence from crew type + tech
|
||||
- Adjusted by train/atmos, dex (`getDex()`), crew type coefficients
|
||||
- Experience level scales war power and counter-scales opponent
|
||||
- `General::getWarPowerMultiplier()` applies special multipliers
|
||||
- Rice consumption on kills: proportional to damage, tech cost, unit rice
|
||||
- Wound chance: 5% unless `부상무효` / `퇴각부상무효` triggered
|
||||
- `finishBattle()` updates rank stats, rounds values, and checks stat changes
|
||||
|
||||
## `WarUnitCity` Highlights
|
||||
|
||||
- Uses `DummyGeneral` with `CREWTYPE_CASTLE`
|
||||
- HP = `def * 10`
|
||||
- Computed attack/defence = `(def + wall * 9) / 500 + 200`
|
||||
- City train/atmos scales with elapsed years since `startYear`
|
||||
- Siege state:
|
||||
- Non-siege battle ends after one exchange
|
||||
- Siege continues until HP <= 0
|
||||
- `heavyDecreaseWealth()` halves `agri/comm/secu` on supply-based rout
|
||||
- `addConflict()` records contribution in `city.conflict` JSON
|
||||
|
||||
## Deterministic RNG
|
||||
|
||||
- Main battle uses `warSeed` directly.
|
||||
- City conquest uses `hiddenSeed + 'ConquerCity' + year + month + nationID + generalID + cityID`.
|
||||
|
||||
## Open Questions / Follow-ups
|
||||
|
||||
- Detailed conquest outcomes (nation collapse, officer handling) extend beyond
|
||||
the summary here; see `ConquerCity()` in `legacy/hwe/process_war.php`.
|
||||
@@ -34,3 +34,11 @@ organization rather than endpoint-first routing.
|
||||
- "attempt" then "execute" phases
|
||||
- Common trigger categories (traits, specials, scenario effects)
|
||||
- How triggers combine when multiple sources apply
|
||||
|
||||
## Detailed Notes
|
||||
|
||||
- Turn execution pipeline: `docs/architecture/legacy-engine-execution.md`
|
||||
- General model and action stack: `docs/architecture/legacy-engine-general.md`
|
||||
- Battle and war resolution: `docs/architecture/legacy-engine-war.md`
|
||||
- Command catalog: `docs/architecture/legacy-commands.md`
|
||||
- Scenario system and rule sets: `docs/architecture/legacy-scenarios.md`
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
# Legacy Scenario System
|
||||
|
||||
This document explains how scenarios are loaded and how they define the active
|
||||
rule set, commands, and effects. Core references include
|
||||
`legacy/hwe/sammo/Scenario.php`, `legacy/hwe/sammo/ResetHelper.php`, and
|
||||
`legacy/hwe/sammo/GameConstBase.php`.
|
||||
|
||||
## Scenario Loading Flow
|
||||
|
||||
1. Server reset/init calls `ResetHelper::buildScenario()`.
|
||||
2. `Scenario` loads `scenario_{id}.json` and merges defaults (`default.json`).
|
||||
3. `Scenario::buildConf()` generates runtime constants:
|
||||
- `d_setting/GameConst.php` from `GameConstBase + scenario.const/map/stat`
|
||||
- `d_setting/CityConst.php` from `scenario/map/{mapName}.php`
|
||||
- `d_setting/GameUnitConst.php` from `scenario/unit/{unitSet}.php`
|
||||
4. `Scenario::build()` inserts nations, generals, and events into DB and runs
|
||||
`initialEvents` immediately.
|
||||
|
||||
`Scenario::getAllScenarios()` is used for listing scenarios without fully
|
||||
building them (lazy init).
|
||||
|
||||
## Scenario JSON Structure (Observed)
|
||||
|
||||
Common top-level keys (see `legacy/hwe/scenario/frame.json` and actual
|
||||
`scenario_*.json` files):
|
||||
|
||||
- `title`, `startYear`, `history`, `iconPath`
|
||||
- `stat`: default stat totals and bounds
|
||||
- `map`: `mapName`, `unitSet`, `scenarioEffect`
|
||||
- `const`: overrides for `GameConst` (commands, items, limits, etc.)
|
||||
- `nation`, `diplomacy`
|
||||
- `general`, `general_ex`, `general_neutral`
|
||||
- `events`, `initialEvents`
|
||||
- `ignoreDefaultEvents` (skip `GameConst::$defaultInitialEvents/$defaultEvents`)
|
||||
|
||||
Notes:
|
||||
|
||||
- A few files still use `initialActions` or `defaultInitialEvents` keys. The
|
||||
engine currently reads `initialEvents` only.
|
||||
- `general` rows use the tuple format from `Scenario::generateGeneral()`:
|
||||
`affinity, name, picture, nationName, city, leadership, strength, intel,
|
||||
officerLevel, birth, death, ego, char, text`.
|
||||
|
||||
## How Scenario Chooses Commands and Effects
|
||||
|
||||
Scenario config influences runtime rules via `GameConst` and `ScenarioEffect`:
|
||||
|
||||
- `const.availableGeneralCommand` / `const.availableChiefCommand` define the
|
||||
commands that appear in UI and can be executed.
|
||||
- `const.availableSpecialDomestic/War`, `const.availablePersonality`,
|
||||
`const.allItems`, `const.availableNationType` control selectable traits/items.
|
||||
- `map.scenarioEffect` or `const.scenarioEffect` sets
|
||||
`GameConst::$scenarioEffect`, which is injected into each `General` as an
|
||||
`iAction` (`General::getActionList()`).
|
||||
- `const.availableInstantAction` merges into
|
||||
`GameConst::$availableInstantAction`.
|
||||
|
||||
Because `GameConst` is generated from scenario data, a scenario can swap
|
||||
available commands or replace the action pool entirely.
|
||||
|
||||
## Command Prefix Conventions
|
||||
|
||||
Prefixes are used to separate rule packs and assets:
|
||||
|
||||
- `che_`: default rule set (base commands, specials, items, nation types).
|
||||
- `cr_`: alternate rule set used by specific scenarios (e.g. `scenario_910`).
|
||||
- `event_`: scenario-specific extensions (research, extra unit sets, or special
|
||||
effects).
|
||||
|
||||
Example: `scenario_910.json` uses `mapName=cr` and `unitSet=cr` and overrides
|
||||
`availableGeneralCommand/availableChiefCommand` to include `cr_건국`,
|
||||
`cr_맹훈련`, and `cr_인구이동` alongside `che_` commands.
|
||||
|
||||
## Scenario Environment Variants (Current Repo)
|
||||
|
||||
These are the map/unit/effect variants referenced by existing scenario files.
|
||||
Defaults are `mapName=che` and `unitSet=che` when not specified.
|
||||
|
||||
Map sets (`scenario/map/*.php`):
|
||||
- `che` (default)
|
||||
- `miniche`, `miniche_b`, `miniche_clean`
|
||||
- `cr`
|
||||
- `chess`
|
||||
- `pokemon_v1`
|
||||
- `ludo_rathowm`
|
||||
|
||||
Unit sets (`scenario/unit/*.php`):
|
||||
- `che` (default)
|
||||
- `che_except_siege`
|
||||
- `cr`
|
||||
- `basic`
|
||||
- `siegetank`
|
||||
- `event_more_crewtype`
|
||||
- `ludo_rathowm`
|
||||
|
||||
Scenario effects (`sammo/ActionScenarioEffect/*`):
|
||||
- `event_StrongAttacker`
|
||||
- `event_UnlimitedDefenceThresholdChange`
|
||||
- `event_MoreEffect`
|
||||
|
||||
## Event Targets
|
||||
|
||||
Scenario events are stored in the `event` table and executed via
|
||||
`TurnExecutionHelper::runEventHandler()` using `EventTarget` values:
|
||||
`PRE_MONTH`, `MONTH`, `OCCUPY_CITY`, `DESTROY_NATION`, `UNITED`.
|
||||
|
||||
Most scenario JSON uses lowercase targets (e.g. `"month"`). The DB enum uses
|
||||
uppercase values but is case-insensitive, so lowercase targets still match.
|
||||
|
||||
@@ -28,3 +28,9 @@ Move items into the main docs once they are finalized.
|
||||
|
||||
- "Next-turn intent" (예턴) data schema and lifecycle
|
||||
- Profile selection workflow and deployment mapping
|
||||
|
||||
## Legacy Engine Docs
|
||||
|
||||
- [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.
|
||||
|
||||
Reference in New Issue
Block a user