diff --git a/docs/architecture/legacy-engine.md b/docs/architecture/legacy-engine.md index 2f1a3bc..0f60b44 100644 --- a/docs/architecture/legacy-engine.md +++ b/docs/architecture/legacy-engine.md @@ -42,3 +42,4 @@ organization rather than endpoint-first routing. - 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` +- Inheritance points (유산 포인트): `docs/architecture/legacy-inherit-points.md` diff --git a/docs/architecture/legacy-inherit-points.md b/docs/architecture/legacy-inherit-points.md new file mode 100644 index 0000000..2c5c79c --- /dev/null +++ b/docs/architecture/legacy-inherit-points.md @@ -0,0 +1,161 @@ +# Legacy Inheritance Points (유산 포인트) + +This document describes the cross-season inheritance point system, how points +are accumulated, merged, and spent, and which gameplay effects they unlock. +References include `legacy/hwe/sammo/InheritancePointManager.php`, +`legacy/hwe/sammo/API/InheritAction/*`, `legacy/hwe/sammo/TriggerInheritBuff.php`, +`legacy/hwe/sammo/API/General/Join.php`, and `legacy/hwe/sql/schema.sql`. + +## Overview + +- Inheritance points are **user-level, cross-game currency**. +- Points are stored in KV storage under `inheritance_{userID}` and are **not + cleared on season reset** (`legacy/hwe/sql/reset.sql` does not drop + `storage`). +- The current spendable balance is stored in the `previous` key. + +## Storage and Persistence + +- KV storage: `storage` table with `namespace = inheritance_{userID}`. +- Snapshot table: `inheritance_result` records per-season snapshots + `{server_id, owner, general_id, year, month, value}`. +- Logs: `user_record` with `log_type = inheritPoint`. + +`InheritancePointManager::applyInheritanceUser()` merges all stored point +entries into a single total and writes it back to `previous`. + +## Point Types and Sources + +The key list is defined in `InheritanceKey` and configured in +`InheritancePointManager`. Each key has a source and a coefficient. + +Directly stored keys (`storeType = true`): + +- `previous` (기존 보유): current spendable balance. +- `lived_month`: +1 per executed turn (`TurnExecutionHelper::executeGeneralCommandUntil`). +- `max_domestic_critical`: updated via `updateMaxDomesticCritical()` in + `legacy/hwe/func_gamerule.php`. +- `active_action`: incremented by many commands (e.g. `che_출병`, `che_거병`, + `che_건국`, various nation commands). Coefficient = 3. +- `unifier`: points from unification events (e.g. `che_건국` +250, + `check_united()` awards +2000 for high officers).
+- `tournament`: awarded in tournament routines (`legacy/hwe/func_tournament.php`). + +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. +- `betting`: `betwin * 10 * (betwingold / betgold)^2`. +- `max_belong`: max of `general.belong` and aux `max_belong`, * 10. + +Notes: + +- NPCs (`npc >= 2`) do not earn points. +- If `game_env.isunited != 0`, only `previous` remains available; other keys + are suppressed for calculation/spending. + +## Merge and Apply Lifecycle + +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`. +2. **Apply** (`applyInheritanceUser`) + - 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: + +- **End of season**: `check_united()` calls merge/apply for all player + generals when the game is unified. +- **Death**: `General::kill()` merges and applies for the owner and refunds + pending inherit actions (random unique, reserved special war). +- **Rebirth**: `General::rebirth()` merges and applies with reduced retention + (`rebirthStoreCoeff`). + +## Spending and Effects + +### Join-time bonuses (`API/General/Join.php`) + +Players can spend points during character creation: + +- Choose a war special (`inheritSpecial`) +- Select a starting city (`inheritCity`) +- Set a turn-time zone (`inheritTurntimeZone`) +- Add bonus stats (`inheritBonusStat`) + +Costs are defined in `GameConst`: + +- `inheritBornSpecialPoint` +- `inheritBornCityPoint` +- `inheritBornTurntimePoint` +- `inheritBornStatPoint` + +### InheritAction APIs (`API/InheritAction/*`) + +- `BuyHiddenBuff`: buys a hidden buff level (1..5) stored in aux + `inheritBuff` (cost curve `inheritBuffPoints`). +- `SetNextSpecialWar`: reserves the next war special (`inheritSpecificSpecialWar`). +- `ResetSpecialWar`: clears current war special (cost grows by + `inheritResetAttrPointBase`, Fibonacci-extended). +- `ResetTurnTime`: randomizes turn time offset for future turns + (`nextTurnTimeBase`). +- `ResetStat`: reassigns base stats; optional bonus stats cost + `inheritBornStatPoint`. +- `BuyRandomUnique`: flags `inheritRandomUnique` to guarantee a unique drop + once unique items become available (see below). +- `CheckOwner`: reveals another general's owner name (cost + `inheritCheckOwnerPoint`). + +All of these are disabled once `game_env.isunited` is set. + +### Unique items and auctions + +- **Random unique**: `inheritRandomUnique` is consumed in + `tryUniqueItemLottery()` when unique items are available. If no items are + available, points are refunded. +- **Unique auctions**: `AuctionUniqueItem` uses `inheritPoint` as the bid + currency. Opening an auction requires `inheritItemUniqueMinPoint`. + +### Betting rewards + +When betting is configured with `reqInheritancePoint`, rewards are paid +directly into `previous` (`Betting::giveReward()`), and logged to +`user_record`. + +## Hidden Buff System (inheritBuff) + +The `inheritBuff` aux value is injected into `General` as a `TriggerInheritBuff` +action. It modifies: + +- Combat chances: avoid/critical/strategy trial ratios +- Domestic success/fail probabilities +- Opponent combat chances (negative modifiers) + +Buff levels are 0..5 and multiply coefficients by 0.01 per level. + +## Rank Tracking + +`MergeInheritPointRank` event aggregates all keys (except `previous`) into +`rank_data.inherit_earned_dyn`, and then updates: + +- `inherit_earned` (sum of earned) +- `inherit_spent` (from `inherit_spent_dyn`) + +This is used for leaderboard-style tracking. + +## Related Constants + +Key cost and limits (from `GameConstBase` / scenario overrides): + +- `inheritBuffPoints` (level costs) +- `inheritSpecificSpecialPoint` +- `inheritResetAttrPointBase` +- `inheritCheckOwnerPoint` +- `inheritItemRandomPoint` +- `inheritItemUniqueMinPoint` +- `minMonthToAllowInheritItem` + +Scenario files can override these via `const` in `scenario_*.json`.