feat(player): port retail augmentation stat chain
This commit is contained in:
parent
0cb60d98a0
commit
461a1fb7b4
22 changed files with 953 additions and 138 deletions
|
|
@ -158,7 +158,7 @@ cos(10°) with base 0.2); the jump chain end-to-end (`GetJumpHeight`
|
|||
0x006b09b0 exact incl. 1300/22.2/0.05/0.35, `InqJumpVelocity` 0x00592980
|
||||
`vz=sqrt(h*19.6)`, powerbar charge 1.0 s / 0.8 s dual-wield) — the user's
|
||||
"we jump too high" hypothesis is REFUTED, jump height is retail-parity
|
||||
(our eff skill is 5 lower pending #268's augmentation port). Retail has no
|
||||
(the former five-point effective-skill gap was closed by #268). Retail has no
|
||||
Sledding auto-toggle (P2 finding re-confirmed; no `state |= 0x800000`
|
||||
writer exists).
|
||||
|
||||
|
|
@ -175,27 +175,29 @@ alignment.
|
|||
|
||||
## #268 — Character panel: vitae color, buff coloring, and augmentation bonuses
|
||||
|
||||
**Status:** OPEN (user direction 2026-07-30, follow-up to #267)
|
||||
**Status:** IMPLEMENTED 2026-07-31 — closure pends the user visual/live gate.
|
||||
**Severity:** MEDIUM (presentation parity)
|
||||
**Component:** retained UI / character window
|
||||
|
||||
**User direction:** (a) the vitae parenthetical (text + number) renders in
|
||||
light blue — VERIFY the exact retail color from the decomp/DAT before
|
||||
hardcoding (the chat-color cdb recipe in
|
||||
`claude-memory/reference_retail_chat_colors.md` is the fallback method);
|
||||
(b) when a buff-like effect is active (including AUGMENTATIONS such as
|
||||
+Acdream's +5-all-skills), affected skills AND attributes render green
|
||||
(buff coloring) — #267's CurrentLevel/BaseLevel split made the green/red
|
||||
coloring live, but augmentation bonuses are not part of the effective
|
||||
value yet, so the color never triggers for them; (c) augmentation skill
|
||||
bonuses must be included in the displayed effective values.
|
||||
**Resolution:** the shared Core `PlayerSkillMath` now ports
|
||||
`CACQualities::InqSkill @ 0x00592660` in retail order for both the
|
||||
character panel and Runtime movement: intrinsic skill, positive
|
||||
`LumAugAllSkills` (0x16D), the authored +10 melee/missile/magic category
|
||||
augmentation, `EnchantSkill`, then +5 Jack of All Trades (0x146) and
|
||||
`2 × LumAugSkilledSpec` (0x158) for specialized skills. Live player
|
||||
PropertyInt updates recompute the Runtime snapshot, so the display and
|
||||
run/jump prediction cannot drift.
|
||||
|
||||
**Register link:** this PROMOTES AP-127 — the "two minor unmodeled retail
|
||||
bonus properties" (0x146/0x158 family — the all-skills augmentation
|
||||
terms feeding `CACQualities::InqRunRate`/`InqJumpVelocity` BEFORE
|
||||
`EnchantSkill`) are user-visible in both the panel and potentially
|
||||
movement speed. Port them into the CACQualities chain (movement) and the
|
||||
panel's effective-value computation together, decomp-first.
|
||||
`AttributeInfoRegion::Update @ 0x004F1910`,
|
||||
`Attribute2ndInfoRegion::Update @ 0x004F19E0`, and
|
||||
`SkillInfoRegion::Update @ 0x004F1AE0` now drive exact value coloring:
|
||||
green/red compare the non-vitae residual against the base, so a pure vitae
|
||||
penalty remains white. The selected-skill footer uses one shared inline-run
|
||||
text primitive matching retail `AppendTextWithFont`; its vitae fragment uses
|
||||
the authored LayoutDesc 0x2100002E / FooterTitle 0x1000024E palette index 3
|
||||
(#7FFFFF), while positive/negative buff fragments use palette indices 1/2
|
||||
(#00FF00/#FF0000). Attributes, secondary attributes, and skills share those
|
||||
exact colors. AP-127 and TS-8 are retired by the same stat-chain package.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -11080,7 +11082,13 @@ The remaining trailer sections (options / shortcuts / hotbars / inventory / equi
|
|||
**Commit:** `feat(net): #7 PlayerDescriptionParser — enchantment block walker + StatMod flow`
|
||||
**Resolution:** Closed alongside #7 in the same commit. `ActiveEnchantmentRecord` extended with optional `StatModType`, `StatModKey`, `StatModValue`, `Bucket` fields. `Spellbook` got an `OnEnchantmentAdded(ActiveEnchantmentRecord)` overload that accepts the full record. `EnchantmentMath.GetMod` aggregator now consumes the StatMod data: multiplicative bucket (1) → multiplier ×= val; additive bucket (2) → additive += val; vitae bucket (8) → multiplier ×= val (applied last, matching retail `CEnchantmentRegistry::EnchantAttribute` semantics). 5 new EnchantmentMath StatMod-aware tests cover: multiplicative buffs aggregate, additive buffs sum, stat-key mismatch is filtered out, vitae applies multiplicatively, family-stacking picks the higher spell-id buff.
|
||||
|
||||
`ParseMagicUpdateEnchantment` (the live-update opcode 0x02C2) is **not** yet extended — it still uses the 4-field summary. That's a separate refactor; PlayerDescription's enchantment block is the load-bearing path for issue #6, and that's now flowing.
|
||||
**2026-07-31 live-update closeout:** `ParseMagicUpdateEnchantment`
|
||||
(0x02C2) now parses the complete record, including start time, DegradeModifier,
|
||||
degrade limit, last time degraded, StatMod type/key/value, and bucket
|
||||
classification. `GameEventWiring` maps that immutable wire record into the
|
||||
same `ActiveEnchantmentRecord` shape as PlayerDescription. The end-to-end
|
||||
test sends an actual 0x02C2 payload through dispatch and proves the resulting
|
||||
StatMod changes the local player's effective skill without relogging.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -11090,7 +11098,9 @@ The remaining trailer sections (options / shortcuts / hotbars / inventory / equi
|
|||
**Commit:** `feat(player): #6 fold enchantment buffs into vital max via EnchantmentMath`
|
||||
**Resolution:** Ported `CEnchantmentRegistry::EnchantAttribute` (PDB `0x00594570`) as `EnchantmentMath.GetMod(IEnumerable<ActiveEnchantmentRecord>, SpellTable, statKey)` returning `(Multiplier, Additive)`. Family-stacking dedup via `SpellTable.Family` (only one buff per family bucket wins, by highest spell-id as a generation proxy). `Spellbook.GetVitalMod(statKey)` delegates. `LocalPlayerState.GetMaxApprox` reworked to apply `(unbuffed × mult) + add` with retail's min-vital clamp (`>= 5` if base ≥ 5 else `>= 1`, matches `CreatureVital::GetMaxValue` at PDB `0x0058F2DD`). Stat-key constants (`MaxHealth=1`, `MaxStamina=3`, `MaxMana=5`) verified against `docs/research/named-retail/acclient.h` line 37287-37301.
|
||||
|
||||
**Architecture in place; data still flat.** Until ISSUES.md #12 lands the wire-format extension that captures `StatMod (type/key/val)` on `ActiveEnchantmentRecord`, the per-enchantment modifier value isn't aggregated yet — `EnchantmentMath.GetMod` returns `Identity (1.0, 0.0)` for every stat key. Once #12 wires the data, the existing aggregator + formula light up automatically. Live `+Acdream` Stam/Mana percent will continue to read ~95% until #12 lands.
|
||||
**Data path complete:** both PlayerDescription and live 0x02C2 updates carry
|
||||
the full StatMod into `ActiveEnchantmentRecord`; the shared aggregator applies
|
||||
it immediately to attributes, vitals, skills, movement, and retained UI.
|
||||
|
||||
6 new EnchantmentMathTests cover: empty list returns Identity, no-table-entries returns Identity, stat-key constants match ACE enum, Identity is `(1, 0)`, family-stacking dedup, family=0 (no-bucket) treated as separate.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue