feat: eslint 적용 및 관련 코드 일괄 수정
This commit is contained in:
@@ -10,8 +10,8 @@ Command keys match class names and file names; they are the values stored in
|
||||
- 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)
|
||||
- `next_execute` KV (per general)
|
||||
- `nation_env` KV (per nation)
|
||||
|
||||
## Execution Semantics (BaseCommand)
|
||||
|
||||
@@ -29,106 +29,106 @@ which commands are available via `GameConst` overrides. See
|
||||
|
||||
## 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_맹훈련` | `맹훈련` |
|
||||
| `휴식` | `휴식` |
|
||||
| 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_화시병연구` | `화시병 연구` |
|
||||
| `휴식` | `휴식` |
|
||||
| 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
|
||||
|
||||
|
||||
@@ -110,18 +110,18 @@ Nation-level choices run only for NPCs (`npc >= 2`) or for autorun users:
|
||||
### Major Action Groups
|
||||
|
||||
- **Troop movement**
|
||||
- `do부대전방발령`, `do부대후방발령`, `do부대구출발령`
|
||||
- user/NPC versions to move generals between front/back/supply cities
|
||||
- checks `frontCities`, `supplyCities`, `last발령`, and war route.
|
||||
- `do부대전방발령`, `do부대후방발령`, `do부대구출발령`
|
||||
- user/NPC versions to move generals between front/back/supply cities
|
||||
- checks `frontCities`, `supplyCities`, `last발령`, and war route.
|
||||
- **Resource distribution**
|
||||
- `do유저장포상`, `doNPC포상`, `doNPC몰수`
|
||||
- uses resource floors (`reqNation*`, `reqNPC*`, `reqHuman*`)
|
||||
- weighted by target general's deficit and recent activity.
|
||||
- `do유저장포상`, `doNPC포상`, `doNPC몰수`
|
||||
- uses resource floors (`reqNation*`, `reqNPC*`, `reqHuman*`)
|
||||
- weighted by target general's deficit and recent activity.
|
||||
- **Diplomacy**
|
||||
- `do불가침제의`: respond to assistance requests with NAP offer.
|
||||
- `do선전포고`: probabilistic declaration when strong enough.
|
||||
- `do불가침제의`: respond to assistance requests with NAP offer.
|
||||
- `do선전포고`: probabilistic declaration when strong enough.
|
||||
- **Capital relocation**
|
||||
- `do천도`: moves capital based on population, dev, and connectivity.
|
||||
- `do천도`: moves capital based on population, dev, and connectivity.
|
||||
|
||||
## General Turn Behavior (`chooseGeneralTurn`)
|
||||
|
||||
@@ -131,26 +131,26 @@ General-level decisions are layered:
|
||||
2. Reserved command is honored if valid (unless `휴식`).
|
||||
3. Immediate recovery if `injury > cureThreshold`.
|
||||
4. Special cases:
|
||||
- NPC troop leaders (type 5) always `집합`.
|
||||
- wanderers decide on founding / moving / disbanding.
|
||||
- NPC troop leaders (type 5) always `집합`.
|
||||
- wanderers decide on founding / moving / disbanding.
|
||||
5. Iterate policy `priority`, invoking `do{Action}`.
|
||||
6. Fallback to `do중립`.
|
||||
|
||||
### Major Action Groups
|
||||
|
||||
- **Domestic development**
|
||||
- `do일반내정`, `do전쟁내정`, `do긴급내정`
|
||||
- weighted by `city` dev rates and general type flags.
|
||||
- `do일반내정`, `do전쟁내정`, `do긴급내정`
|
||||
- weighted by `city` dev rates and general type flags.
|
||||
- **War preparation**
|
||||
- `do징병`, `do전투준비`, `do출병`
|
||||
- strict checks on crew, train, atmos, population and diplomacy state.
|
||||
- `do징병`, `do전투준비`, `do출병`
|
||||
- strict checks on crew, train, atmos, population and diplomacy state.
|
||||
- **Mobility**
|
||||
- `do전방워프`, `do후방워프`, `do내정워프`, `do귀환`
|
||||
- uses `front/supply/backup` cities and population thresholds.
|
||||
- `do전방워프`, `do후방워프`, `do내정워프`, `do귀환`
|
||||
- uses `front/supply/backup` cities and population thresholds.
|
||||
- **Resource handling**
|
||||
- `do금쌀구매` (trade), `doNPC헌납` (donation).
|
||||
- `do금쌀구매` (trade), `doNPC헌납` (donation).
|
||||
- **Neutral behavior**
|
||||
- `do중립` selects between `물자조달`, `인재탐색`, `견문`.
|
||||
- `do중립` selects between `물자조달`, `인재탐색`, `견문`.
|
||||
|
||||
## Data Fields Accessed (Representative)
|
||||
|
||||
@@ -171,21 +171,21 @@ GeneralAI reads or writes:
|
||||
To port the AI to an in-memory state model without behavior drift:
|
||||
|
||||
- **Snapshot-first**
|
||||
- Build a per-turn `GameSnapshot` containing env, nation, cities, generals,
|
||||
diplomacy, and nation_env. `GeneralAI` should read only from this snapshot.
|
||||
- Build a per-turn `GameSnapshot` containing env, nation, cities, generals,
|
||||
diplomacy, and nation_env. `GeneralAI` should read only from this snapshot.
|
||||
- **Derived caches**
|
||||
- Cache `DiplomacyState`, `CityBuckets`, `GeneralBuckets`, and `WarRoute`.
|
||||
- Use lazy recalculation and invalidate only the affected region/city/general
|
||||
after a command is applied.
|
||||
- Cache `DiplomacyState`, `CityBuckets`, `GeneralBuckets`, and `WarRoute`.
|
||||
- Use lazy recalculation and invalidate only the affected region/city/general
|
||||
after a command is applied.
|
||||
- **Deterministic ordering**
|
||||
- For candidate lists, sort by ID before weighted RNG to preserve parity.
|
||||
- RNG seeding should keep the exact per-turn seed scheme to ensure replay.
|
||||
- For candidate lists, sort by ID before weighted RNG to preserve parity.
|
||||
- RNG seeding should keep the exact per-turn seed scheme to ensure replay.
|
||||
- **Command evaluation**
|
||||
- Keep `hasFullConditionMet()` semantics intact by providing the same
|
||||
generalized context (`general`, `city`, `nation`, `dest*`).
|
||||
- Keep `hasFullConditionMet()` semantics intact by providing the same
|
||||
generalized context (`general`, `city`, `nation`, `dest*`).
|
||||
- **Policy snapshots**
|
||||
- Cache policy values per turn and avoid reading KVStorage per action.
|
||||
- When policies change, treat it as an explicit state transition.
|
||||
- Cache policy values per turn and avoid reading KVStorage per action.
|
||||
- When policies change, treat it as an explicit state transition.
|
||||
|
||||
These guidelines mirror the current "derive once, then select via priority"
|
||||
pattern and minimize resimulation deltas in the rewrite.
|
||||
|
||||
@@ -27,18 +27,18 @@ The `AuctionInfo` and `AuctionInfoDetail` DTOs are serialized into
|
||||
## Core Auction Flow
|
||||
|
||||
1. **Open**
|
||||
- `AuctionBasicResource::openResourceAuction()` validates amounts and
|
||||
host resources, then inserts `ng_auction`.
|
||||
- `AuctionUniqueItem::openItemAuction()` checks availability, reserves
|
||||
unique items, and posts a global history notice.
|
||||
- `AuctionBasicResource::openResourceAuction()` validates amounts and
|
||||
host resources, then inserts `ng_auction`.
|
||||
- `AuctionUniqueItem::openItemAuction()` checks availability, reserves
|
||||
unique items, and posts a global history notice.
|
||||
2. **Bid**
|
||||
- Bids are inserted into `ng_auction_bid` and can extend the close date.
|
||||
- Reverse auctions (when `detail->isReverse`) sort by lowest bid.
|
||||
- Bids are inserted into `ng_auction_bid` and can extend the close date.
|
||||
- Reverse auctions (when `detail->isReverse`) sort by lowest bid.
|
||||
3. **Close** (`tryFinish()` from the concrete auction)
|
||||
- If no bids: `rollbackAuction()` returns resources to host and logs.
|
||||
- With bids: `finishAuction()` transfers resources, logs, and sends messages.
|
||||
- If no bids: `rollbackAuction()` returns resources to host and logs.
|
||||
- With bids: `finishAuction()` transfers resources, logs, and sends messages.
|
||||
4. **Processing**
|
||||
- `processAuction()` scans auctions past `close_date` and finishes them.
|
||||
- `processAuction()` scans auctions past `close_date` and finishes them.
|
||||
|
||||
## Unique Item Auctions
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ engine. References include `legacy/hwe/sammo/CityConstBase.php`,
|
||||
`CityConstBase` defines default city data and lookup helpers:
|
||||
|
||||
- `CityConstBase::$initCity` includes:
|
||||
- id, name, level, population, agri/comm/secu/def/wall,
|
||||
region, coordinates, and path connections.
|
||||
- id, name, level, population, agri/comm/secu/def/wall,
|
||||
region, coordinates, and path connections.
|
||||
- Region and level maps convert labels to numeric codes.
|
||||
- `CityConstBase::byID()` and `byName()` return `CityInitialDetail` objects.
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ Constraints declare required inputs using bit flags:
|
||||
- `REQ_GENERAL`, `REQ_CITY`, `REQ_NATION`
|
||||
- `REQ_DEST_GENERAL`, `REQ_DEST_CITY`, `REQ_DEST_NATION`
|
||||
- `REQ_ARG` with typed sub-flags:
|
||||
- `REQ_STRING_ARG`, `REQ_INT_ARG`, `REQ_NUMERIC_ARG`, `REQ_BOOLEAN_ARG`,
|
||||
`REQ_ARRAY_ARG`, `REQ_BACKED_ENUM_ARG`
|
||||
- `REQ_STRING_ARG`, `REQ_INT_ARG`, `REQ_NUMERIC_ARG`, `REQ_BOOLEAN_ARG`,
|
||||
`REQ_ARRAY_ARG`, `REQ_BACKED_ENUM_ARG`
|
||||
|
||||
`Constraint::checkInputValues()` enforces these expectations and throws if
|
||||
inputs are missing or malformed.
|
||||
@@ -51,7 +51,6 @@ Constraints are organized by domain:
|
||||
|
||||
Each constraint sets a failure reason string used by UI and logs.
|
||||
|
||||
|
||||
## Rewrite References
|
||||
|
||||
Rewrite constraint contracts and runtime split details live in
|
||||
|
||||
@@ -22,23 +22,23 @@ and `diplomacy`.
|
||||
- `Message::getMessagesFromMailBox()` reads by mailbox/type with validity
|
||||
filtering (`valid_until > now`).
|
||||
- `Message::buildFromArray()` instantiates:
|
||||
- `DiplomaticMessage` when type is diplomacy.
|
||||
- `ScoutMessage` or `RaiseInvaderMessage` when `option.action` matches.
|
||||
- `DiplomaticMessage` when type is diplomacy.
|
||||
- `ScoutMessage` or `RaiseInvaderMessage` when `option.action` matches.
|
||||
|
||||
## DiplomaticMessage Flow
|
||||
|
||||
`DiplomaticMessage` wraps diplomacy requests and accepts/rejects them:
|
||||
|
||||
- Supported actions:
|
||||
- `TYPE_NO_AGGRESSION` (불가침)
|
||||
- `TYPE_CANCEL_NA` (불가침 파기)
|
||||
- `TYPE_STOP_WAR` (종전)
|
||||
- `TYPE_NO_AGGRESSION` (불가침)
|
||||
- `TYPE_CANCEL_NA` (불가침 파기)
|
||||
- `TYPE_STOP_WAR` (종전)
|
||||
- `agreeMessage()` validates:
|
||||
- message is still valid
|
||||
- receiver is a valid diplomacy officer
|
||||
- message is still valid
|
||||
- receiver is a valid diplomacy officer
|
||||
- On accept, builds and runs the matching nation command:
|
||||
- `che_불가침수락`, `che_불가침파기수락`, `che_종전수락`
|
||||
- Uses `NoRNG` to avoid randomness in acceptance.
|
||||
- `che_불가침수락`, `che_불가침파기수락`, `che_종전수락`
|
||||
- Uses `NoRNG` to avoid randomness in acceptance.
|
||||
|
||||
Each acceptance updates `diplomacyDetail` with command briefs and writes logs.
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ updates. References include `legacy/hwe/func_time_event.php`,
|
||||
## Entry Points
|
||||
|
||||
- `TurnExecutionHelper::executeAllCommand()`
|
||||
- Calls `runEventHandler(PRE_MONTH)` → `preUpdateMonthly()` → `turnDate()` →
|
||||
`runEventHandler(MONTH)` → `postUpdateMonthly()`.
|
||||
- Calls `runEventHandler(PRE_MONTH)` → `preUpdateMonthly()` → `turnDate()` →
|
||||
`runEventHandler(MONTH)` → `postUpdateMonthly()`.
|
||||
- Event actions under `legacy/hwe/sammo/Event/Action/` execute concrete
|
||||
economic updates.
|
||||
|
||||
@@ -19,13 +19,14 @@ updates. References include `legacy/hwe/func_time_event.php`,
|
||||
|
||||
- Collects all nations and cities, groups generals per nation.
|
||||
- Computes income using:
|
||||
- `getGoldIncome()` / `getRiceIncome()` from `func_time_event.php`.
|
||||
- `getWallIncome()` for rice from walls (same file).
|
||||
- `getGoldIncome()` / `getRiceIncome()` from `func_time_event.php`.
|
||||
- `getWallIncome()` for rice from walls (same file).
|
||||
- Applies nation tax rate (`rate_tmp`) and salary ratio (`bill`).
|
||||
- Pays generals by `dedication` via `getBill()`.
|
||||
- Updates `nation_env.prev_income_{gold|rice}` and logs to history.
|
||||
|
||||
Key dependencies:
|
||||
|
||||
- `GameConst::$basegold`, `GameConst::$baserice` for minimum reserves.
|
||||
- `GameConst::$resourceActionAmountGuide` for action amounts.
|
||||
- `iAction::onCalcNationalIncome()` for nation-type modifiers.
|
||||
@@ -36,8 +37,8 @@ Key dependencies:
|
||||
|
||||
- City stats decay by 1% (agri/comm/secu/def/wall).
|
||||
- Population growth via `popIncrease()`:
|
||||
- Uses tax rate (`rate_tmp`) and security.
|
||||
- Nation type can adjust via `onCalcNationalIncome('pop', ...)`.
|
||||
- Uses tax rate (`rate_tmp`) and security.
|
||||
- Nation type can adjust via `onCalcNationalIncome('pop', ...)`.
|
||||
- General and nation resources decay (1–5% bands based on thresholds).
|
||||
|
||||
## War Income and Casualties (ProcessWarIncome)
|
||||
@@ -62,16 +63,16 @@ Key dependencies:
|
||||
|
||||
- Nation level increases based on number of level≥4 cities.
|
||||
- On level-up:
|
||||
- Grants gold/rice bonus.
|
||||
- Logs global and national history.
|
||||
- Initializes `nation_turn` rows for new chief levels.
|
||||
- Runs a unique-item lottery (deterministic RNG tagged `nationLevelUp`).
|
||||
- Grants gold/rice bonus.
|
||||
- Logs global and national history.
|
||||
- Initializes `nation_turn` rows for new chief levels.
|
||||
- Runs a unique-item lottery (deterministic RNG tagged `nationLevelUp`).
|
||||
|
||||
## City Trade Rates (RandomizeCityTradeRate)
|
||||
|
||||
- Once per month, adjusts `city.trade` with deterministic RNG:
|
||||
- Probability depends on city level.
|
||||
- Trade rate ranges 95–105 when triggered.
|
||||
- Probability depends on city level.
|
||||
- Trade rate ranges 95–105 when triggered.
|
||||
|
||||
## RNG Notes
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@ references include `legacy/hwe/sammo/TurnExecutionHelper.php`,
|
||||
## Entry Points
|
||||
|
||||
- `TurnExecutionHelper::runEventHandler(EventTarget $eventTarget)`
|
||||
- Loads `event` table rows by target and priority, evaluates conditions, and
|
||||
runs actions.
|
||||
- Loads `event` table rows by target and priority, evaluates conditions, and
|
||||
runs actions.
|
||||
- `StaticEventHandler::handleEvent(...)`
|
||||
- Invoked by many commands and API handlers to run per-action static hooks.
|
||||
- Invoked by many commands and API handlers to run per-action static hooks.
|
||||
|
||||
## Event Table Schema
|
||||
|
||||
@@ -46,18 +46,18 @@ city occupation (`EventTarget::OCCUPY_CITY`, called by some commands).
|
||||
class instances:
|
||||
|
||||
- **Condition**
|
||||
- Supports logic combinators (`and`, `or`, `xor`, `not`) via
|
||||
`Event\Condition\Logic`.
|
||||
- Built-in condition types include:
|
||||
- `Date`, `DateRelative`, `Interval`
|
||||
- `RemainNation`
|
||||
- `ConstBool`
|
||||
- Conditions return `{ value, chain }` for tracing.
|
||||
- Supports logic combinators (`and`, `or`, `xor`, `not`) via
|
||||
`Event\Condition\Logic`.
|
||||
- Built-in condition types include:
|
||||
- `Date`, `DateRelative`, `Interval`
|
||||
- `RemainNation`
|
||||
- `ConstBool`
|
||||
- Conditions return `{ value, chain }` for tracing.
|
||||
|
||||
- **Action**
|
||||
- Actions are classes under `Event/Action/` with `run(array $env)`.
|
||||
- The dispatcher instantiates them from `action` arrays like
|
||||
`['ProcessIncome', 'gold']`.
|
||||
- Actions are classes under `Event/Action/` with `run(array $env)`.
|
||||
- The dispatcher instantiates them from `action` arrays like
|
||||
`['ProcessIncome', 'gold']`.
|
||||
|
||||
## Common Event Actions (Examples)
|
||||
|
||||
@@ -90,8 +90,8 @@ Static events are hooks triggered directly by commands/APIs:
|
||||
`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_부대발령즉시집합`
|
||||
- `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).
|
||||
|
||||
@@ -16,32 +16,32 @@ based on `legacy/hwe/sammo/API/Global/ExecuteEngine.php`,
|
||||
## Global Turn Loop (`TurnExecutionHelper::executeAllCommand`)
|
||||
|
||||
1. **Time gate**
|
||||
- If `now < game_env.turntime`, return without executing.
|
||||
- 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).
|
||||
- `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()`.
|
||||
- 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`.
|
||||
- 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)`
|
||||
- `turnDate(prevTurn)`
|
||||
- `executeGeneralCommandUntil(now, limitActionTime, year, month)`
|
||||
6. **Post-turn maintenance**
|
||||
- `processTournament()`
|
||||
- `processAuction()`
|
||||
- Reset cache, `unlock()`.
|
||||
- `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
|
||||
@@ -52,36 +52,36 @@ configured limit). If time runs out mid-loop, it returns early and keeps
|
||||
For each general with `turntime < targetDate` (ordered by `turntime, no`):
|
||||
|
||||
1. **Load state**
|
||||
- `General::createObjFromDB()` and `KVStorage` for `game_env`.
|
||||
- `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`.
|
||||
- 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.
|
||||
- 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_병력군량소모`.
|
||||
- RNG seed: `hiddenSeed + 'preprocess' + year + month + generalID`.
|
||||
- `preprocessCommand()` merges action triggers + `che_부상경감`, `che_병력군량소모`.
|
||||
5. **Blocked users**
|
||||
- `processBlocked()` consumes `killturn` and logs if `block >= 2`.
|
||||
- `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.
|
||||
- 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 `휴식`.
|
||||
- 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.
|
||||
- `pullNationCommand()` / `pullGeneralCommand()` advance queues.
|
||||
- `updateTurnTime()` handles deletion/retirement and sets next `turntime`.
|
||||
- Persist via `General::applyDB()`.
|
||||
9. **LastTurn persistence**
|
||||
- General `LastTurn` lives in `general.last_turn` JSON.
|
||||
- Nation `LastTurn` is stored in `nation_env` under `turn_last_{officer_level}`.
|
||||
- `LastTurn.term` only advances when the same command + arg repeats across turns.
|
||||
- General `LastTurn` lives in `general.last_turn` JSON.
|
||||
- Nation `LastTurn` is stored in `nation_env` under `turn_last_{officer_level}`.
|
||||
- `LastTurn.term` only advances when the same command + arg repeats across turns.
|
||||
|
||||
## Command Semantics (BaseCommand)
|
||||
|
||||
@@ -97,8 +97,8 @@ For each general with `turntime < targetDate` (ordered by `turntime, no`):
|
||||
## Turntime & Lifecycle (`updateTurnTime`)
|
||||
|
||||
- **Inactivity**: if `killturn <= 0`:
|
||||
- NPC-owned characters can detach (owner -> NPC) if `deadyear` not reached.
|
||||
- Otherwise the general is deleted (`kill()`).
|
||||
- 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
|
||||
|
||||
@@ -11,9 +11,9 @@ exposes trigger hooks. The main reference is `legacy/hwe/sammo/General.php`.
|
||||
- `penalty` JSON is decoded into `PenaltyKey -> value` map.
|
||||
- `aux` JSON is lazily decoded and only written when aux values change.
|
||||
- Rank data is tracked with:
|
||||
- `rankVarRead` (current read view)
|
||||
- `rankVarIncrease` (increment queue)
|
||||
- `rankVarSet` (explicit set queue)
|
||||
- `rankVarRead` (current read view)
|
||||
- `rankVarIncrease` (increment queue)
|
||||
- `rankVarSet` (explicit set queue)
|
||||
|
||||
## Action Objects (`iAction`)
|
||||
|
||||
@@ -44,6 +44,7 @@ modifiers and triggers.
|
||||
- Cached by `(statName, injury, action, adjust)` tuple
|
||||
|
||||
Convenience wrappers:
|
||||
|
||||
- `getLeadership()`, `getStrength()`, `getIntel()`
|
||||
|
||||
## Turn Reservation and LastTurn
|
||||
@@ -83,10 +84,10 @@ 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.
|
||||
- `che_필살시도`, `che_필살발동`
|
||||
- `che_회피시도`, `che_회피발동`
|
||||
- `che_계략시도`, `che_계략발동`, `che_계략실패`
|
||||
- plus any action-specific additions.
|
||||
|
||||
## Rank and Access Log Updates
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ They can:
|
||||
## Item System
|
||||
|
||||
- Base class: `BaseItem` implements `iAction` and exposes:
|
||||
- `getCost()`, `isConsumable()`, `isBuyable()`, `getReqSecu()`.
|
||||
- `getCost()`, `isConsumable()`, `isBuyable()`, `getReqSecu()`.
|
||||
- Stat items inherit `BaseStatItem` and apply a fixed stat bonus in
|
||||
`onCalcStat()` based on class name tokens.
|
||||
- Item instances live on the general (`General::getItem()`); items can also
|
||||
@@ -36,8 +36,8 @@ Items are configured via `GameConst::$allItems` and scenario overrides.
|
||||
(`onCalcDomestic`), e.g., cost/success/score adjustments.
|
||||
- `ActionSpecialWar/*` injects battle triggers or stat modifiers.
|
||||
- Weighting and eligibility are managed by `SpecialityHelper`:
|
||||
- Uses `selectWeight` + stat/arm constraints to choose specials.
|
||||
- Deterministic RNG affects special selection for NPCs or resets.
|
||||
- Uses `selectWeight` + stat/arm constraints to choose specials.
|
||||
- Deterministic RNG affects special selection for NPCs or resets.
|
||||
|
||||
## Personalities
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ and `legacy/hwe/sammo/VersionGitDynamic.php`.
|
||||
`ActionLogger` aggregates logs for a general, nation, and global context:
|
||||
|
||||
- Buffers multiple log channels:
|
||||
- General history/action/battle logs
|
||||
- National history logs
|
||||
- Global history/action logs
|
||||
- General history/action/battle logs
|
||||
- National history logs
|
||||
- Global history/action logs
|
||||
- Supports formatted prefixes (`PLAIN`, `YEAR_MONTH`, `NOTICE`, etc.).
|
||||
- `flush()` emits buffered logs via helper functions
|
||||
(`pushGeneralHistoryLog`, `pushGlobalHistoryLog`, etc.).
|
||||
|
||||
@@ -7,25 +7,25 @@ and event-driven recruitment. References include `legacy/hwe/sammo/AbsGeneralPoo
|
||||
## Core Abstractions
|
||||
|
||||
- `AbsGeneralPool`
|
||||
- Wraps a `Scenario\GeneralBuilder` and a raw `info` payload.
|
||||
- Provides `getGeneralBuilder()`, `getInfo()`, and `occupyGeneralName()`.
|
||||
- Abstract method: `pickGeneralFromPool(...)`.
|
||||
- Wraps a `Scenario\GeneralBuilder` and a raw `info` payload.
|
||||
- Provides `getGeneralBuilder()`, `getInfo()`, and `occupyGeneralName()`.
|
||||
- Abstract method: `pickGeneralFromPool(...)`.
|
||||
|
||||
- `AbsFromUserPool`
|
||||
- Implements reservation logic backed by the `select_pool` table.
|
||||
- Reserves candidates for a user (`owner`) until `reserved_until`.
|
||||
- On selection, clears reservation and binds `general_id`.
|
||||
- Implements reservation logic backed by the `select_pool` table.
|
||||
- Reserves candidates for a user (`owner`) until `reserved_until`.
|
||||
- On selection, clears reservation and binds `general_id`.
|
||||
|
||||
## Pool Implementations
|
||||
|
||||
- `GeneralPool/RandomNameGeneral`
|
||||
- Generates random names using `GameConst::$randGen*` lists.
|
||||
- Checks duplicate counts and appends suffixes if needed.
|
||||
- Inserts reservation rows into `select_pool` for user selection.
|
||||
- Generates random names using `GameConst::$randGen*` lists.
|
||||
- Checks duplicate counts and appends suffixes if needed.
|
||||
- Inserts reservation rows into `select_pool` for user selection.
|
||||
|
||||
- `GeneralPool/SPoolUnderU30`
|
||||
- Loads a curated pool from `GeneralPool/Pool/UnderS30.json`.
|
||||
- Inserts rows into `select_pool` with pre-defined stats and specials.
|
||||
- Loads a curated pool from `GeneralPool/Pool/UnderS30.json`.
|
||||
- Inserts rows into `select_pool` with pre-defined stats and specials.
|
||||
|
||||
## Data Model
|
||||
|
||||
|
||||
@@ -122,8 +122,8 @@ Used for base stats and battle-derived parameters. Common `statName` keys:
|
||||
|
||||
1. `General::getPreTurnExecuteTriggerList()` merges triggers from all actions.
|
||||
2. Base triggers are appended:
|
||||
- `GeneralTrigger/che_부상경감` (priority 10000 / BEGIN)
|
||||
- `GeneralTrigger/che_병력군량소모` (priority 50000 / FINAL)
|
||||
- `GeneralTrigger/che_부상경감` (priority 10000 / BEGIN)
|
||||
- `GeneralTrigger/che_병력군량소모` (priority 50000 / FINAL)
|
||||
3. `TriggerCaller::fire()` executes them before the command runs.
|
||||
|
||||
General triggers use `General::activateSkill()` for logging and gating.
|
||||
@@ -146,10 +146,10 @@ Every phase:
|
||||
|
||||
1. `WarUnit::beginPhase()` clears activated skills and recomputes war power.
|
||||
2. `General::getBattlePhaseSkillTriggerList()` builds the trigger list.
|
||||
- Base triggers (always included):
|
||||
- `che_필살시도`, `che_필살발동`
|
||||
- `che_회피시도`, `che_회피발동`
|
||||
- `che_계략시도`, `che_계략발동`, `che_계략실패`
|
||||
- Base triggers (always included):
|
||||
- `che_필살시도`, `che_필살발동`
|
||||
- `che_회피시도`, `che_회피발동`
|
||||
- `che_계략시도`, `che_계략발동`, `che_계략실패`
|
||||
3. Attacker/defender trigger lists are merged and fired.
|
||||
4. Damage is calculated using `getWarPower()` (after trigger multipliers).
|
||||
|
||||
|
||||
@@ -31,9 +31,9 @@ For defender generals:
|
||||
- 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`
|
||||
- `totalStat = (realStat + fullStat) / 2`
|
||||
- `totalCrew = crew / 1_000_000 * (train * atmos) ^ 1.5`
|
||||
- `totalStat + totalCrew / 100`
|
||||
|
||||
For cities:
|
||||
|
||||
@@ -44,24 +44,24 @@ For cities:
|
||||
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
|
||||
- `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
|
||||
- `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)
|
||||
- `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
|
||||
- `logBattleResult()` for last phase if needed
|
||||
- `finishBattle()` for attacker/defender
|
||||
- City conflict tracking and history logs
|
||||
|
||||
## Post-Battle Updates (`processWar`)
|
||||
|
||||
@@ -118,9 +118,9 @@ Triggered when the defender nation owns exactly one city (the captured city):
|
||||
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).
|
||||
- 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
|
||||
@@ -128,14 +128,14 @@ Triggered when the defender nation owns exactly one city (the captured city):
|
||||
If the defender nation still has other cities:
|
||||
|
||||
- Demotes city officers (태수/군사/종사) to general:
|
||||
- `officer_level = 1`, `officer_city = 0`.
|
||||
- `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.
|
||||
- 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
|
||||
|
||||
@@ -149,8 +149,8 @@ City stats are reset after ownership is settled:
|
||||
`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`.
|
||||
- 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
|
||||
@@ -168,10 +168,10 @@ Used for:
|
||||
|
||||
- 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
|
||||
- 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
|
||||
@@ -183,8 +183,8 @@ Used for:
|
||||
- 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
|
||||
- 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
|
||||
|
||||
|
||||
@@ -23,27 +23,27 @@ interact, and where their state lives. The active runtime lives in
|
||||
- Class: `legacy/hwe/sammo/General.php` (base: `legacy/hwe/sammo/GeneralBase.php`)
|
||||
- Tables: `general`, `general_turn`, `rank_data`, `general_access_log`
|
||||
- Interaction highlights:
|
||||
- Command execution: `legacy/hwe/sammo/Command/*` and
|
||||
`legacy/hwe/sammo/TurnExecutionHelper.php`
|
||||
- Turn reservation: `legacy/hwe/sammo/LastTurn.php`
|
||||
- Combat adapter: `legacy/hwe/sammo/WarUnitGeneral.php`
|
||||
- Modifiers/triggers via `iAction` modules (items, specials, traits)
|
||||
- Logging: `legacy/hwe/sammo/ActionLogger.php`
|
||||
- Command execution: `legacy/hwe/sammo/Command/*` and
|
||||
`legacy/hwe/sammo/TurnExecutionHelper.php`
|
||||
- Turn reservation: `legacy/hwe/sammo/LastTurn.php`
|
||||
- Combat adapter: `legacy/hwe/sammo/WarUnitGeneral.php`
|
||||
- Modifiers/triggers via `iAction` modules (items, specials, traits)
|
||||
- Logging: `legacy/hwe/sammo/ActionLogger.php`
|
||||
- DB fields (schema):
|
||||
- `general`: no, owner, npcmsg, npc, npc_org, affinity, bornyear, deadyear,
|
||||
newmsg, picture, imgsvr, name, owner_name, nation, city, troop, leadership,
|
||||
leadership_exp, strength, strength_exp, intel, intel_exp, injury,
|
||||
experience, dedication, dex1, dex2, dex3, dex4, dex5, officer_level,
|
||||
officer_city, permission, gold, rice, crew, crewtype, train, atmos, weapon,
|
||||
book, horse, item, turntime, recent_war, makelimit, killturn, block,
|
||||
dedlevel, explevel, age, startage, belong, betray, personal, special,
|
||||
specage, special2, specage2, defence_train, tnmt, myset, tournament,
|
||||
newvote, last_turn, aux, penalty
|
||||
- `general_turn`: id, general_id, turn_idx, action, arg, brief
|
||||
- `general_access_log`: id, general_id, user_id, last_refresh, refresh,
|
||||
refresh_total, refresh_score, refresh_score_total
|
||||
- `rank_data`: id, nation_id, general_id, type, value
|
||||
- JSON columns: `general.last_turn`, `general.aux`, `general.penalty`
|
||||
- `general`: no, owner, npcmsg, npc, npc_org, affinity, bornyear, deadyear,
|
||||
newmsg, picture, imgsvr, name, owner_name, nation, city, troop, leadership,
|
||||
leadership_exp, strength, strength_exp, intel, intel_exp, injury,
|
||||
experience, dedication, dex1, dex2, dex3, dex4, dex5, officer_level,
|
||||
officer_city, permission, gold, rice, crew, crewtype, train, atmos, weapon,
|
||||
book, horse, item, turntime, recent_war, makelimit, killturn, block,
|
||||
dedlevel, explevel, age, startage, belong, betray, personal, special,
|
||||
specage, special2, specage2, defence_train, tnmt, myset, tournament,
|
||||
newvote, last_turn, aux, penalty
|
||||
- `general_turn`: id, general_id, turn_idx, action, arg, brief
|
||||
- `general_access_log`: id, general_id, user_id, last_refresh, refresh,
|
||||
refresh_total, refresh_score, refresh_score_total
|
||||
- `rank_data`: id, nation_id, general_id, type, value
|
||||
- JSON columns: `general.last_turn`, `general.aux`, `general.penalty`
|
||||
|
||||
### Nation (국가)
|
||||
|
||||
@@ -51,18 +51,18 @@ interact, and where their state lives. The active runtime lives in
|
||||
- Nation-type actions: `legacy/hwe/sammo/ActionNationType/*`,
|
||||
base in `legacy/hwe/sammo/BaseNation.php`
|
||||
- Interaction highlights:
|
||||
- Nation commands: `legacy/hwe/sammo/Command/Nation/*`
|
||||
- Diplomacy: `diplomacy`, `ng_diplomacy`, and
|
||||
`legacy/hwe/sammo/DiplomaticMessage.php`
|
||||
- Monthly economy updates: `legacy/hwe/sammo/Event/Action/*`
|
||||
- Nation commands: `legacy/hwe/sammo/Command/Nation/*`
|
||||
- Diplomacy: `diplomacy`, `ng_diplomacy`, and
|
||||
`legacy/hwe/sammo/DiplomaticMessage.php`
|
||||
- Monthly economy updates: `legacy/hwe/sammo/Event/Action/*`
|
||||
- DB fields (schema):
|
||||
- `nation`: nation, name, color, capital, capset, gennum, gold, rice, bill,
|
||||
rate, rate_tmp, secretlimit, chief_set, scout, war, strategic_cmd_limit,
|
||||
surlimit, tech, power, spy, level, type, aux
|
||||
- `nation_turn`: id, nation_id, officer_level, turn_idx, action, arg, brief
|
||||
- `nation_env`: id, namespace, key, value
|
||||
- JSON columns: `nation.spy`, `nation.aux`, `nation_turn.arg`,
|
||||
`nation_env.value`
|
||||
- `nation`: nation, name, color, capital, capset, gennum, gold, rice, bill,
|
||||
rate, rate_tmp, secretlimit, chief_set, scout, war, strategic_cmd_limit,
|
||||
surlimit, tech, power, spy, level, type, aux
|
||||
- `nation_turn`: id, nation_id, officer_level, turn_idx, action, arg, brief
|
||||
- `nation_env`: id, namespace, key, value
|
||||
- JSON columns: `nation.spy`, `nation.aux`, `nation_turn.arg`,
|
||||
`nation_env.value`
|
||||
|
||||
### City (도시)
|
||||
|
||||
@@ -71,22 +71,22 @@ interact, and where their state lives. The active runtime lives in
|
||||
`legacy/hwe/sammo/CityInitialDetail.php`
|
||||
- Live cache: `legacy/hwe/sammo/CityHelper.php`
|
||||
- Interaction highlights:
|
||||
- Supply and isolation updates via `Event/Action/UpdateCitySupply`
|
||||
- Conquest/war defender: `legacy/hwe/sammo/WarUnitCity.php`
|
||||
- Supply and isolation updates via `Event/Action/UpdateCitySupply`
|
||||
- Conquest/war defender: `legacy/hwe/sammo/WarUnitCity.php`
|
||||
- DB fields (schema):
|
||||
- `city`: city, name, level, nation, supply, front, pop, pop_max, agri,
|
||||
agri_max, comm, comm_max, secu, secu_max, trust, trade, dead, def, def_max,
|
||||
wall, wall_max, officer_set, state, region, term, conflict
|
||||
- JSON columns: `city.conflict`
|
||||
- `city`: city, name, level, nation, supply, front, pop, pop_max, agri,
|
||||
agri_max, comm, comm_max, secu, secu_max, trust, trade, dead, def, def_max,
|
||||
wall, wall_max, officer_set, state, region, term, conflict
|
||||
- JSON columns: `city.conflict`
|
||||
|
||||
### Troop (부대)
|
||||
|
||||
- Data rows: `troop`
|
||||
- Interaction highlights:
|
||||
- Join/leave flows in `legacy/hwe/sammo/API/Troop/*`
|
||||
- Static event hooks from `legacy/hwe/sammo/StaticEvent/*`
|
||||
- Join/leave flows in `legacy/hwe/sammo/API/Troop/*`
|
||||
- Static event hooks from `legacy/hwe/sammo/StaticEvent/*`
|
||||
- DB fields (schema):
|
||||
- `troop`: troop_leader, nation, name
|
||||
- `troop`: troop_leader, nation, name
|
||||
|
||||
### Command / Turn (턴 예약과 실행)
|
||||
|
||||
@@ -96,8 +96,8 @@ interact, and where their state lives. The active runtime lives in
|
||||
- Execution entry: `legacy/hwe/sammo/TurnExecutionHelper.php` and
|
||||
`legacy/hwe/proc.php`
|
||||
- DB fields (schema):
|
||||
- `general_turn`: id, general_id, turn_idx, action, arg, brief
|
||||
- `nation_turn`: id, nation_id, officer_level, turn_idx, action, arg, brief
|
||||
- `general_turn`: id, general_id, turn_idx, action, arg, brief
|
||||
- `nation_turn`: id, nation_id, officer_level, turn_idx, action, arg, brief
|
||||
|
||||
### War Units (전투 단위)
|
||||
|
||||
@@ -105,8 +105,8 @@ interact, and where their state lives. The active runtime lives in
|
||||
- General combat: `legacy/hwe/sammo/WarUnitGeneral.php`
|
||||
- City combat: `legacy/hwe/sammo/WarUnitCity.php`
|
||||
- Interaction highlights:
|
||||
- Battle flow and resolution: `legacy/hwe/process_war.php`
|
||||
- Uses General/Nation/City snapshots for deterministic resolution
|
||||
- Battle flow and resolution: `legacy/hwe/process_war.php`
|
||||
- Uses General/Nation/City snapshots for deterministic resolution
|
||||
|
||||
## Rule Modules and Modifiers
|
||||
|
||||
@@ -114,13 +114,13 @@ interact, and where their state lives. The active runtime lives in
|
||||
|
||||
- Interface: `legacy/hwe/sammo/iAction.php`
|
||||
- Modules:
|
||||
- Items: `legacy/hwe/sammo/ActionItem/*`
|
||||
- Domestic specials: `legacy/hwe/sammo/ActionSpecialDomestic/*`
|
||||
- War specials: `legacy/hwe/sammo/ActionSpecialWar/*`
|
||||
- Personalities: `legacy/hwe/sammo/ActionPersonality/*`
|
||||
- Nation types: `legacy/hwe/sammo/ActionNationType/*`
|
||||
- Crew types: `legacy/hwe/sammo/ActionCrewType/*`
|
||||
- Scenario effects: `legacy/hwe/sammo/ActionScenarioEffect/*`
|
||||
- Items: `legacy/hwe/sammo/ActionItem/*`
|
||||
- Domestic specials: `legacy/hwe/sammo/ActionSpecialDomestic/*`
|
||||
- War specials: `legacy/hwe/sammo/ActionSpecialWar/*`
|
||||
- Personalities: `legacy/hwe/sammo/ActionPersonality/*`
|
||||
- Nation types: `legacy/hwe/sammo/ActionNationType/*`
|
||||
- Crew types: `legacy/hwe/sammo/ActionCrewType/*`
|
||||
- Scenario effects: `legacy/hwe/sammo/ActionScenarioEffect/*`
|
||||
- Applied by `General::getActionList()` and used by triggers, stat calculation,
|
||||
and combat phases.
|
||||
|
||||
@@ -146,8 +146,8 @@ interact, and where their state lives. The active runtime lives in
|
||||
- Static hooks: `legacy/hwe/sammo/StaticEvent/*`,
|
||||
wired via `GameConst::$staticEventHandlers`
|
||||
- DB fields (schema):
|
||||
- `event`: id, target, priority, condition, action
|
||||
- JSON columns: `event.condition`, `event.action`
|
||||
- `event`: id, target, priority, condition, action
|
||||
- JSON columns: `event.condition`, `event.action`
|
||||
|
||||
### Messaging and Diplomacy
|
||||
|
||||
@@ -157,11 +157,11 @@ interact, and where their state lives. The active runtime lives in
|
||||
- Diplomacy wrapper: `legacy/hwe/sammo/DiplomaticMessage.php`
|
||||
- Table: `message`
|
||||
- DB fields (schema):
|
||||
- `message`: id, mailbox, type, src, dest, time, valid_until, message
|
||||
- `diplomacy`: no, me, you, state, term, dead, showing
|
||||
- `ng_diplomacy`: no, src_nation_id, dest_nation_id, prev_no, state,
|
||||
text_brief, text_detail, date, src_signer, dest_signer, aux
|
||||
- JSON columns: `message.message`, `ng_diplomacy.aux`
|
||||
- `message`: id, mailbox, type, src, dest, time, valid_until, message
|
||||
- `diplomacy`: no, me, you, state, term, dead, showing
|
||||
- `ng_diplomacy`: no, src_nation_id, dest_nation_id, prev_no, state,
|
||||
text_brief, text_detail, date, src_signer, dest_signer, aux
|
||||
- JSON columns: `message.message`, `ng_diplomacy.aux`
|
||||
|
||||
### Economy and World State
|
||||
|
||||
@@ -170,10 +170,10 @@ interact, and where their state lives. The active runtime lives in
|
||||
- Trade and supply: `RandomizeCityTradeRate`, `UpdateCitySupply`,
|
||||
`UpdateNationLevel`
|
||||
- DB fields (schema):
|
||||
- `nation_env`: id, namespace, key, value
|
||||
- `statistic`: no, year, month, nation_count, nation_name, nation_hist,
|
||||
gen_count, personal_hist, special_hist, power_hist, crewtype, etc, aux
|
||||
- JSON columns: `statistic.aux`, `nation_env.value`
|
||||
- `nation_env`: id, namespace, key, value
|
||||
- `statistic`: no, year, month, nation_count, nation_name, nation_hist,
|
||||
gen_count, personal_hist, special_hist, power_hist, crewtype, etc, aux
|
||||
- JSON columns: `statistic.aux`, `nation_env.value`
|
||||
|
||||
### Auctions, Betting, and Votes
|
||||
|
||||
@@ -181,17 +181,17 @@ interact, and where their state lives. The active runtime lives in
|
||||
- Betting: `legacy/hwe/sammo/Betting.php` and `ng_betting`
|
||||
- Votes and tournaments: `vote`, `vote_comment`, `tournament`
|
||||
- DB fields (schema):
|
||||
- `ng_auction`: id, type, finished, target, host_general_id, req_resource,
|
||||
open_date, close_date, detail
|
||||
- `ng_auction_bid`: no, auction_id, owner, general_id, amount, date, aux
|
||||
- `ng_betting`: id, betting_id, general_id, user_id, betting_type, amount
|
||||
- `vote`: id, vote_id, general_id, nation_id, selection
|
||||
- `vote_comment`: id, vote_id, general_id, nation_id, general_name,
|
||||
nation_name, text, date
|
||||
- `tournament`: seq, no, npc, name, w, b, h, leadership, strength, intel, lvl,
|
||||
grp, grp_no, win, draw, lose, gl, prmt
|
||||
- JSON columns: `ng_auction.detail`, `ng_auction_bid.aux`, `ng_betting.betting_type`,
|
||||
`vote.selection`
|
||||
- `ng_auction`: id, type, finished, target, host_general_id, req_resource,
|
||||
open_date, close_date, detail
|
||||
- `ng_auction_bid`: no, auction_id, owner, general_id, amount, date, aux
|
||||
- `ng_betting`: id, betting_id, general_id, user_id, betting_type, amount
|
||||
- `vote`: id, vote_id, general_id, nation_id, selection
|
||||
- `vote_comment`: id, vote_id, general_id, nation_id, general_name,
|
||||
nation_name, text, date
|
||||
- `tournament`: seq, no, npc, name, w, b, h, leadership, strength, intel, lvl,
|
||||
grp, grp_no, win, draw, lose, gl, prmt
|
||||
- JSON columns: `ng_auction.detail`, `ng_auction_bid.aux`, `ng_betting.betting_type`,
|
||||
`vote.selection`
|
||||
|
||||
### Logs and Records
|
||||
|
||||
@@ -199,14 +199,14 @@ interact, and where their state lives. The active runtime lives in
|
||||
- User logs: `legacy/hwe/sammo/UserLogger.php`
|
||||
- Tables: `ng_history`, `world_history`, `general_record`, `user_record`, `hall`
|
||||
- DB fields (schema):
|
||||
- `ng_history`: no, server_id, year, month, map, global_history, global_action,
|
||||
nations
|
||||
- `world_history`: id, nation_id, year, month, text
|
||||
- `general_record`: id, general_id, log_type, year, month, text
|
||||
- `user_record`: id, user_id, server_id, log_type, year, month, date, text
|
||||
- `hall`: id, server_id, season, scenario, general_no, type, value, owner, aux
|
||||
- JSON columns: `ng_history.map`, `ng_history.global_history`,
|
||||
`ng_history.global_action`, `ng_history.nations`, `hall.aux`
|
||||
- `ng_history`: no, server_id, year, month, map, global_history, global_action,
|
||||
nations
|
||||
- `world_history`: id, nation_id, year, month, text
|
||||
- `general_record`: id, general_id, log_type, year, month, text
|
||||
- `user_record`: id, user_id, server_id, log_type, year, month, date, text
|
||||
- `hall`: id, server_id, season, scenario, general_no, type, value, owner, aux
|
||||
- JSON columns: `ng_history.map`, `ng_history.global_history`,
|
||||
`ng_history.global_action`, `ng_history.nations`, `hall.aux`
|
||||
|
||||
### Boards, Locks, and Storage
|
||||
|
||||
@@ -214,13 +214,13 @@ interact, and where their state lives. The active runtime lives in
|
||||
- Locks: `plock`
|
||||
- KV stores: `storage`, `nation_env`
|
||||
- DB fields (schema):
|
||||
- `board`: no, nation_no, is_secret, date, general_no, author, author_icon,
|
||||
title, text
|
||||
- `comment`: no, nation_no, is_secret, date, document_no, general_no, author,
|
||||
text
|
||||
- `plock`: no, type, plock, locktime
|
||||
- `storage`: id, namespace, key, value
|
||||
- JSON columns: `storage.value`
|
||||
- `board`: no, nation_no, is_secret, date, general_no, author, author_icon,
|
||||
title, text
|
||||
- `comment`: no, nation_no, is_secret, date, document_no, general_no, author,
|
||||
text
|
||||
- `plock`: no, type, plock, locktime
|
||||
- `storage`: id, namespace, key, value
|
||||
- JSON columns: `storage.value`
|
||||
|
||||
### Archive and Lifecycle Tables
|
||||
|
||||
@@ -230,24 +230,24 @@ interact, and where their state lives. The active runtime lives in
|
||||
- Selection pools: `select_npc_token`, `select_pool`
|
||||
- Inheritance: `inheritance_result`
|
||||
- DB fields (schema):
|
||||
- `ng_games`: id, server_id, date, winner_nation, map, season, scenario,
|
||||
scenario_name, env
|
||||
- `ng_old_nations`: id, server_id, nation, data, date
|
||||
- `ng_old_generals`: id, server_id, general_no, owner, name, last_yearmonth,
|
||||
turntime, data
|
||||
- `emperior`: no, server_id, phase, nation_count, nation_name, nation_hist,
|
||||
gen_count, personal_hist, special_hist, name, type, color, year, month,
|
||||
power, gennum, citynum, pop, poprate, gold, rice, l12name, l12pic, l11name,
|
||||
l11pic, l10name, l10pic, l9name, l9pic, l8name, l8pic, l7name, l7pic,
|
||||
l6name, l6pic, l5name, l5pic, tiger, eagle, gen, history, aux
|
||||
- `reserved_open`: id, options, date
|
||||
- `select_npc_token`: id, owner, valid_until, pick_more_from, pick_result,
|
||||
nonce
|
||||
- `select_pool`: id, unique_name, owner, general_id, reserved_until, info
|
||||
- `inheritance_result`: id, server_id, owner, general_id, year, month, value
|
||||
- JSON columns: `ng_games.env`, `ng_old_nations.data`, `ng_old_generals.data`,
|
||||
`emperior.history`, `emperior.aux`, `reserved_open.options`,
|
||||
`select_npc_token.pick_result`, `inheritance_result.value`
|
||||
- `ng_games`: id, server_id, date, winner_nation, map, season, scenario,
|
||||
scenario_name, env
|
||||
- `ng_old_nations`: id, server_id, nation, data, date
|
||||
- `ng_old_generals`: id, server_id, general_no, owner, name, last_yearmonth,
|
||||
turntime, data
|
||||
- `emperior`: no, server_id, phase, nation_count, nation_name, nation_hist,
|
||||
gen_count, personal_hist, special_hist, name, type, color, year, month,
|
||||
power, gennum, citynum, pop, poprate, gold, rice, l12name, l12pic, l11name,
|
||||
l11pic, l10name, l10pic, l9name, l9pic, l8name, l8pic, l7name, l7pic,
|
||||
l6name, l6pic, l5name, l5pic, tiger, eagle, gen, history, aux
|
||||
- `reserved_open`: id, options, date
|
||||
- `select_npc_token`: id, owner, valid_until, pick_more_from, pick_result,
|
||||
nonce
|
||||
- `select_pool`: id, unique_name, owner, general_id, reserved_until, info
|
||||
- `inheritance_result`: id, server_id, owner, general_id, year, month, value
|
||||
- JSON columns: `ng_games.env`, `ng_old_nations.data`, `ng_old_generals.data`,
|
||||
`emperior.history`, `emperior.aux`, `reserved_open.options`,
|
||||
`select_npc_token.pick_result`, `inheritance_result.value`
|
||||
|
||||
## Aux and JSON Payloads
|
||||
|
||||
@@ -259,17 +259,17 @@ not enforced by DB constraints.
|
||||
- Storage layer: `legacy/hwe/sammo/LazyVarAndAuxUpdater.php`
|
||||
- Access pattern: `getAuxVar()` / `setAuxVar()` on `General`
|
||||
- Literal keys observed in code (not exhaustive):
|
||||
- `armType`, `autorun_limit`, `inheritBuff`, `inheritRandomUnique`,
|
||||
`inheritResetSpecialWar`, `inheritResetTurnTime`,
|
||||
`inheritSpecificSpecialWar`, `last발령`, `max_domestic_critical`,
|
||||
`movingTargetCityID`, `nextTurnTimeBase`, `pickYearMonth`,
|
||||
`use_auto_nation_turn`, `use_treatment`
|
||||
- `armType`, `autorun_limit`, `inheritBuff`, `inheritRandomUnique`,
|
||||
`inheritResetSpecialWar`, `inheritResetTurnTime`,
|
||||
`inheritSpecificSpecialWar`, `last발령`, `max_domestic_critical`,
|
||||
`movingTargetCityID`, `nextTurnTimeBase`, `pickYearMonth`,
|
||||
`use_auto_nation_turn`, `use_treatment`
|
||||
- Key sources:
|
||||
- Turn execution timing: `legacy/hwe/sammo/TurnExecutionHelper.php`
|
||||
- AI state and movement: `legacy/hwe/sammo/GeneralAI.php`
|
||||
- Inheritance actions: `legacy/hwe/sammo/API/InheritAction/*`
|
||||
- Domestic critical resets: `legacy/hwe/sammo/Command/General/*`
|
||||
- Troop dispatch markers: `legacy/hwe/sammo/Command/Nation/che_발령.php`
|
||||
- Turn execution timing: `legacy/hwe/sammo/TurnExecutionHelper.php`
|
||||
- AI state and movement: `legacy/hwe/sammo/GeneralAI.php`
|
||||
- Inheritance actions: `legacy/hwe/sammo/API/InheritAction/*`
|
||||
- Domestic critical resets: `legacy/hwe/sammo/Command/General/*`
|
||||
- Troop dispatch markers: `legacy/hwe/sammo/Command/Nation/che_발령.php`
|
||||
- Item or trigger-specific keys are stored via constants (e.g.
|
||||
`ActionItem/event_충차.php`, `WarUnitTrigger/event_충차아이템소모.php`) and are
|
||||
not visible in literal scans.
|
||||
@@ -277,10 +277,10 @@ not enforced by DB constraints.
|
||||
### Nation `aux`
|
||||
|
||||
- Enum keys: `legacy/hwe/sammo/Enums/NationAuxKey.php`
|
||||
- `can_국기변경`, `can_국호변경`, `did_특성초토화`, `can_무작위수도이전`,
|
||||
`can_대검병사용`, `can_극병사용`, `can_화시병사용`, `can_원융노병사용`,
|
||||
`can_산저병사용`, `can_상병사용`, `can_음귀병사용`, `can_무희사용`,
|
||||
`can_화륜차사용`
|
||||
- `can_국기변경`, `can_국호변경`, `did_특성초토화`, `can_무작위수도이전`,
|
||||
`can_대검병사용`, `can_극병사용`, `can_화시병사용`, `can_원융노병사용`,
|
||||
`can_산저병사용`, `can_상병사용`, `can_음귀병사용`, `can_무희사용`,
|
||||
`can_화륜차사용`
|
||||
- Used by constraints and nation commands, especially unit unlock logic.
|
||||
|
||||
### Other JSON Columns
|
||||
@@ -372,18 +372,18 @@ This index focuses on primary runtime touch points and omits view-only pages.
|
||||
## Interaction Sketch
|
||||
|
||||
- Turn execution (`TurnExecutionHelper`):
|
||||
- Reads `general_turn` / `nation_turn`
|
||||
- Builds General/Nation/City context
|
||||
- Applies constraints → runs command → triggers → logs
|
||||
- Runs monthly events and world updates
|
||||
- Reads `general_turn` / `nation_turn`
|
||||
- Builds General/Nation/City context
|
||||
- Applies constraints → runs command → triggers → logs
|
||||
- Runs monthly events and world updates
|
||||
- Battle (`process_war.php`):
|
||||
- Builds `WarUnitGeneral` and `WarUnitCity`
|
||||
- Resolves phases and damage with triggers
|
||||
- Applies city conquest and nation collapse rules
|
||||
- Builds `WarUnitGeneral` and `WarUnitCity`
|
||||
- Resolves phases and damage with triggers
|
||||
- Applies city conquest and nation collapse rules
|
||||
- Diplomacy:
|
||||
- `Message` delivers a diplomacy request
|
||||
- `DiplomaticMessage` accepts/rejects
|
||||
- Nation command executes and updates diplomacy tables
|
||||
- `Message` delivers a diplomacy request
|
||||
- `DiplomaticMessage` accepts/rejects
|
||||
- Nation command executes and updates diplomacy tables
|
||||
|
||||
## Entity Relationships (Mermaid ERD)
|
||||
|
||||
|
||||
@@ -43,11 +43,11 @@ Directly stored keys (`storeType = true`):
|
||||
|
||||
Computed keys (`storeType = false` or derived):
|
||||
|
||||
- `combat`: from `rank_data.warnum` (war engagements) * 5.
|
||||
- `sabotage`: from `rank_data.firenum` (strategy success) * 20.
|
||||
- `dex`: sum of arm-type dex, with overflow reduction, * 0.001.
|
||||
- `combat`: from `rank_data.warnum` (war engagements) \* 5.
|
||||
- `sabotage`: from `rank_data.firenum` (strategy success) \* 20.
|
||||
- `dex`: sum of arm-type dex, with overflow reduction, \* 0.001.
|
||||
- `betting`: `betwin * 10 * (betwingold / betgold)^2`.
|
||||
- `max_belong`: max of `general.belong` and aux `max_belong`, * 10.
|
||||
- `max_belong`: max of `general.belong` and aux `max_belong`, \* 10.
|
||||
|
||||
Notes:
|
||||
|
||||
@@ -60,11 +60,11 @@ Notes:
|
||||
The system uses a two-step merge:
|
||||
|
||||
1. **Merge** (`mergeTotalInheritancePoint`)
|
||||
- Computes derived keys and stores them into `inheritance_{userID}`.
|
||||
- Records a snapshot into `inheritance_result`.
|
||||
- Computes derived keys and stores them into `inheritance_{userID}`.
|
||||
- Records a snapshot into `inheritance_result`.
|
||||
2. **Apply** (`applyInheritanceUser`)
|
||||
- Sums all keys into a total, logs to `user_record`, resets storage to only
|
||||
`previous` (plus any rebirth-kept keys).
|
||||
- Sums all keys into a total, logs to `user_record`, resets storage to only
|
||||
`previous` (plus any rebirth-kept keys).
|
||||
|
||||
This merge/apply is triggered in these places:
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ rule set, commands, and effects. Core references include
|
||||
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`
|
||||
- `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.
|
||||
|
||||
@@ -39,7 +39,7 @@ Notes:
|
||||
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`.
|
||||
officerLevel, birth, death, ego, char, text`.
|
||||
|
||||
## How Scenario Chooses Commands and Effects
|
||||
|
||||
@@ -77,6 +77,7 @@ 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`
|
||||
@@ -85,6 +86,7 @@ Map sets (`scenario/map/*.php`):
|
||||
- `ludo_rathowm`
|
||||
|
||||
Unit sets (`scenario/unit/*.php`):
|
||||
|
||||
- `che` (default)
|
||||
- `che_except_siege`
|
||||
- `cr`
|
||||
@@ -94,6 +96,7 @@ Unit sets (`scenario/unit/*.php`):
|
||||
- `ludo_rathowm`
|
||||
|
||||
Scenario effects (`sammo/ActionScenarioEffect/*`):
|
||||
|
||||
- `event_StrongAttacker`
|
||||
- `event_UnlimitedDefenceThresholdChange`
|
||||
- `event_MoreEffect`
|
||||
@@ -106,4 +109,3 @@ Scenario events are stored in the `event` table and executed via
|
||||
|
||||
Most scenario JSON uses lowercase targets (e.g. `"month"`). The DB enum uses
|
||||
uppercase values but is case-insensitive, so lowercase targets still match.
|
||||
|
||||
|
||||
@@ -58,16 +58,12 @@ export interface Constraint {
|
||||
- `ConstraintPlanner` collects requirements across constraints.
|
||||
- `StateView` loads those requirements (daemon: in-memory, API: DB).
|
||||
- `test()` returns:
|
||||
- `allow` if constraint passes.
|
||||
- `deny` with a stable reason/code for UI.
|
||||
- `unknown` if required data is missing and `mode === 'precheck'`.
|
||||
- `allow` if constraint passes.
|
||||
- `deny` with a stable reason/code for UI.
|
||||
- `unknown` if required data is missing and `mode === 'precheck'`.
|
||||
|
||||
```ts
|
||||
function evaluateConstraints(
|
||||
constraints: Constraint[],
|
||||
ctx: ConstraintContext,
|
||||
view: StateView,
|
||||
): ConstraintResult {
|
||||
function evaluateConstraints(constraints: Constraint[], ctx: ConstraintContext, view: StateView): ConstraintResult {
|
||||
for (const constraint of constraints) {
|
||||
const missing = constraint.requires(ctx).filter((req) => !view.has(req));
|
||||
if (missing.length && ctx.mode === 'precheck') {
|
||||
|
||||
@@ -50,16 +50,17 @@ Gateway loads the profile table on boot, then reconciles PM2 to match.
|
||||
|
||||
### Boot Reconciliation
|
||||
|
||||
1) Load profile rows from DB.
|
||||
2) List PM2 processes and map `profileName -> running state`.
|
||||
3) For each profile:
|
||||
- If desired `RUNNING/PREOPEN/PAUSED/COMPLETED` and any process is missing, start.
|
||||
- If desired `RESERVED/STOPPED/DISABLED` and any process is running, stop both.
|
||||
4) Persist errors to DB for audit.
|
||||
1. Load profile rows from DB.
|
||||
2. List PM2 processes and map `profileName -> running state`.
|
||||
3. For each profile:
|
||||
- If desired `RUNNING/PREOPEN/PAUSED/COMPLETED` and any process is missing, start.
|
||||
- If desired `RESERVED/STOPPED/DISABLED` and any process is running, stop both.
|
||||
4. Persist errors to DB for audit.
|
||||
|
||||
### Internal Scheduler (Gateway Cron)
|
||||
|
||||
Gateway runs a lightweight cron loop (setInterval) that:
|
||||
|
||||
- When `RESERVED` and `preopenAt <= now`, queue a build for the reserved commit.
|
||||
- When build succeeds, status becomes `PREOPEN` (daemon paused).
|
||||
- When `openAt <= now`, status becomes `RUNNING` and daemon resumes.
|
||||
@@ -102,15 +103,15 @@ replay while pub/sub keeps live updates simple and low-latency.
|
||||
### Recommended Split
|
||||
|
||||
- Redis Streams:
|
||||
- API server -> daemon: mutation requests, turn-run commands.
|
||||
- Daemon -> API server: run status events, job results, error reports.
|
||||
- Use consumer groups for daemon workers and API server listeners.
|
||||
- Require `requestId` for correlation and idempotency.
|
||||
- Ack on success; move failed items to a dead-letter stream after retry.
|
||||
- API server -> daemon: mutation requests, turn-run commands.
|
||||
- Daemon -> API server: run status events, job results, error reports.
|
||||
- Use consumer groups for daemon workers and API server listeners.
|
||||
- Require `requestId` for correlation and idempotency.
|
||||
- Ack on success; move failed items to a dead-letter stream after retry.
|
||||
- Redis pub/sub:
|
||||
- Daemon -> API server: low-stakes live update signals (run started/ended).
|
||||
- API server -> frontend: SSE fan-out triggered by pub/sub updates.
|
||||
- Do not use pub/sub for data that must be replayed or audited.
|
||||
- Daemon -> API server: low-stakes live update signals (run started/ended).
|
||||
- API server -> frontend: SSE fan-out triggered by pub/sub updates.
|
||||
- Do not use pub/sub for data that must be replayed or audited.
|
||||
|
||||
### Operational Notes
|
||||
|
||||
@@ -158,12 +159,12 @@ also supports local ID/password login for users who cannot use Kakao.
|
||||
- The turn daemon runs as a single-threaded loop.
|
||||
- The daemon engine uses in-memory state as the primary working set.
|
||||
- The daemon waits on two conditions during the event loop.
|
||||
- Query/command requests from the external API server.
|
||||
- The scheduled start time of the next turn.
|
||||
- Query/command requests from the external API server.
|
||||
- The scheduled start time of the next turn.
|
||||
- External requests are processed until the next turn start time is reached.
|
||||
- If no requests arrive, the daemon waits until the next turn start time.
|
||||
- When the next turn start time arrives, the daemon starts turn processing
|
||||
immediately even if requests remain queued.
|
||||
- If no requests arrive, the daemon waits until the next turn start time.
|
||||
- When the next turn start time arrives, the daemon starts turn processing
|
||||
immediately even if requests remain queued.
|
||||
- While the daemon is resolving a turn, the API server queues incoming requests.
|
||||
|
||||
Note: the current implementation does not yet process API mutation requests
|
||||
@@ -203,16 +204,16 @@ export type DaemonEvent =
|
||||
- API server requests are delivered to the daemon via Redis Streams or
|
||||
Redis pub/sub.
|
||||
- Redis Stream mutation requests are rate-limited per user.
|
||||
- Each user can have up to 30 pending mutation requests.
|
||||
- Additional requests are rejected once the limit is exceeded.
|
||||
- Each user can have up to 30 pending mutation requests.
|
||||
- Additional requests are rejected once the limit is exceeded.
|
||||
|
||||
### In-Memory and DBMS Flush
|
||||
|
||||
- The daemon processes actions against in-memory state by default.
|
||||
- DBMS writes are flushed in bulk after turn processing completes.
|
||||
- Frequently changing "next-turn intent" data is stored separately.
|
||||
- The API server persists this data in the DBMS.
|
||||
- The daemon loads only this data when the next turn begins.
|
||||
- The API server persists this data in the DBMS.
|
||||
- The daemon loads only this data when the next turn begins.
|
||||
|
||||
## Turn Daemon vs API Query Priority (Outline)
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ Move items into the main docs once they are finalized.
|
||||
- Deterministic RNG test harness guidelines
|
||||
- Output comparison rules (sorting, tolerances, diff granularity)
|
||||
- Unit test vs simulation test split and responsibilities
|
||||
- [AI suggestion] Document che_출병 parity gaps vs legacy (city state/term=43, fallback to che_이동 when friendly, nation.war/AllowWar check, post-war static events/unique-item lottery, missing route data when map/diplomacy not provided).
|
||||
- [AI suggestion] Document che*출병 parity gaps vs legacy (city state/term=43, fallback to che*이동 when friendly, nation.war/AllowWar check, post-war static events/unique-item lottery, missing route data when map/diplomacy not provided).
|
||||
- [AI suggestion] Verify that "이호경식" followed by "출병" is correctly blocked with the new reserved-turn overlay (diplomacy state sync).
|
||||
|
||||
## Trigger System
|
||||
|
||||
@@ -5,9 +5,10 @@ The key is to separate "DB behavior emulation" from "state/logic/flow validation
|
||||
so each layer is tested with the right scope.
|
||||
|
||||
## Core Principles
|
||||
|
||||
- Prefer Repository/DB Port interfaces over ORM mocks; split implementations:
|
||||
- InMemory Repository (Fake)
|
||||
- Real DB Repository (e.g., Prisma)
|
||||
- InMemory Repository (Fake)
|
||||
- Real DB Repository (e.g., Prisma)
|
||||
- Validate domain constraints in the logic layer where possible; DB constraints
|
||||
act as a secondary safety net.
|
||||
- Use deterministic seeds for all gameplay-impacting RNG.
|
||||
@@ -15,6 +16,7 @@ so each layer is tested with the right scope.
|
||||
## Test Layers
|
||||
|
||||
### 1) Constraint Tests
|
||||
|
||||
Goal: ensure constraints (unique/foreign key/check) behave consistently in
|
||||
both InMemory state and the DB.
|
||||
|
||||
@@ -24,6 +26,7 @@ both InMemory state and the DB.
|
||||
- Use real DB only in integration tests.
|
||||
|
||||
### 2) Game Logic / Command Tests
|
||||
|
||||
Goal: verify state input -> state output and that flush behaves as expected.
|
||||
|
||||
- Unit tests: run logic against InMemory state and assert outputs.
|
||||
@@ -32,6 +35,7 @@ Goal: verify state input -> state output and that flush behaves as expected.
|
||||
- "Send to DB" behavior is validated via real DB tests.
|
||||
|
||||
### 3) Turn Flow Tests
|
||||
|
||||
Goal: verify the end-to-end scheduler/turn processing flow.
|
||||
|
||||
- Nature: integration/system tests.
|
||||
@@ -40,16 +44,19 @@ Goal: verify the end-to-end scheduler/turn processing flow.
|
||||
- Keep a small set of smoke/regression scenarios due to cost.
|
||||
|
||||
### 4) Scenario Build Tests
|
||||
|
||||
Goal: ensure scenario parsing and DB application are correct.
|
||||
|
||||
- Unit tests: parse/validate scenario files (map size, ID collisions, ranges).
|
||||
- Integration tests: load scenarios into a test DB and verify key tables.
|
||||
|
||||
## Result Composition Guidelines
|
||||
|
||||
- Unit tests: fast, wide coverage.
|
||||
- Integration tests: focus on real DB/Redis behavior.
|
||||
- Smoke tests: minimal coverage of turn flow/build/scenario loading.
|
||||
|
||||
## MockDB Conclusion
|
||||
|
||||
- "InMemory Repository (Fake)" is more practical than an ORM mock.
|
||||
- DB-level behavior (constraints/transactions/locks) belongs to integration tests.
|
||||
|
||||
Reference in New Issue
Block a user