feat(net): #7 PlayerDescriptionParser - enchantment block walker + StatMod flow
Extends PlayerDescriptionParser past the spell block to parse the
Enchantment trailer per holtburger events.rs:462-501 +
magic/types.rs:40. New EnchantmentEntry record carries the full
60-64 byte wire payload:
u16 spell_id, layer, spell_category, has_spell_set_id
u32 power_level
f64 start_time, duration
u32 caster_guid
f32 degrade_modifier, degrade_limit
f64 last_time_degraded
u32 stat_mod_type, stat_mod_key
f32 stat_mod_value
[u32 spell_set_id]?
+ EnchantmentBucket (Multiplicative / Additive / Cooldown / Vitae)
EnchantmentMask outer u32 selects which buckets follow; each bucket
(except Vitae) is u32 count + N records. Vitae is a singleton.
Parsed.Enchantments now exposed as IReadOnlyList<EnchantmentEntry>.
GameEventWiring routes each entry through Spellbook.OnEnchantmentAdded
with the full StatMod data + bucket. EnchantmentMath.GetMod consumes
StatMod records to produce real (Multiplier, Additive) per stat key:
Bucket 1 (Multiplicative): multiplier *= val
Bucket 2 (Additive): additive += val
Bucket 8 (Vitae): multiplier *= val (applied last)
Bucket 4 (Cooldown): skipped (not a vital mod)
ActiveEnchantmentRecord extended with optional StatModType /
StatModKey / StatModValue / Bucket fields. Existing 4-arg callers
stay compatible (defaults to null / 0). New OnEnchantmentAdded
overload accepts the full record from PlayerDescription path.
Tests: 7 new (834 -> 841):
- PlayerDescriptionParserTests (2): enchantment block schema with
multiplicative + additive buckets, Vitae singleton.
- EnchantmentMathTests (5): multiplicative buffs aggregate, additive
buffs sum, stat-key mismatch filters out, Vitae applied
multiplicatively, family-stacking picks higher spell-id.
Closes #7 (parser past spells, enchantment block parsed).
Closes #12 (StatMod flow architecture — data lights up #6's
aggregator). Files #13 (remaining trailer sections: options /
shortcuts / hotbars / desired_comps / spellbook_filters / options2 /
gameplay_options / inventory / equipped — needs the heuristic
gameplay_options walker per holtburger).
Note: ParseMagicUpdateEnchantment (live-update 0x02C2) NOT yet
extended — still uses 4-field summary. PlayerDescription is the
load-bearing path for #6; live updates can be folded in separately.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b153bbe5ad
commit
bb5003a849
7 changed files with 447 additions and 58 deletions
|
|
@ -237,6 +237,24 @@ public static class GameEventWiring
|
|||
|
||||
foreach (uint sid in p.Value.Spells.Keys)
|
||||
spellbook.OnSpellLearned(sid);
|
||||
|
||||
// Issue #7 — enchantment block: feed each entry into the
|
||||
// Spellbook with full StatMod data so EnchantmentMath can
|
||||
// aggregate buffs in vital-max calc (issue #6 lights up).
|
||||
foreach (var ench in p.Value.Enchantments)
|
||||
{
|
||||
spellbook.OnEnchantmentAdded(new AcDream.Core.Spells.ActiveEnchantmentRecord(
|
||||
SpellId: ench.SpellId,
|
||||
LayerId: ench.Layer,
|
||||
Duration: (float)ench.Duration,
|
||||
CasterGuid: ench.CasterGuid,
|
||||
StatModType: ench.StatModType,
|
||||
StatModKey: ench.StatModKey,
|
||||
StatModValue: ench.StatModValue,
|
||||
Bucket: (uint)ench.Bucket));
|
||||
if (dumpPd)
|
||||
Console.WriteLine($"vitals: PD-ench spell={ench.SpellId} layer={ench.Layer} bucket={ench.Bucket} key={ench.StatModKey} val={ench.StatModValue}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue