fix(inventory-go): add Prodigal Spirit Drinker effect; document dmgMod key substitution; test wand mastery fallback

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-15 08:00:22 +02:00
parent 99f394d1ef
commit 9b2f28d942
2 changed files with 44 additions and 5 deletions

View file

@ -416,6 +416,7 @@ var elemVsMonSpellEffects = map[int]odSpellEffect{
3250: {.03, .03}, // Major Spirit Thirst
4670: {.05, .05}, // Epic Spirit Thirst
6098: {.07, .07}, // Legendary Spirit Thirst
3735: {.15, 0}, // Prodigal Spirit Drinker
}
// buffedMaxDamage mirrors GetBuffedIntValueKey(218103842): base value minus
@ -497,11 +498,12 @@ func computeOD(raw map[string]any) (float64, bool) {
}
bv, ok := bestValues[key]
if !ok && oc == 31 {
// Wands: our probe showed some wands lack key 353 (mastery), which
// defaults to 0 via ivI — but retry explicitly with mastery 0 so the
// void VR wand row (43,12,...) stays reachable while items that
// genuinely carry a different mastery value still fall back to the
// normal (34|43, 0, ...) rows.
// Mastery-0 retry for wands: an ADDITION over UB (UB's
// DataTable.Select has no retry; our captured wands may carry a
// mastery key 353 while the table's wand rows use mastery 0).
// Keeps the void VR wand row (43,12,...) reachable on the first
// exact-match attempt while other mastery-carrying wands fall back
// to the normal (34|43, 0, ...) rows.
key.mastery = 0
bv, ok = bestValues[key]
}
@ -550,6 +552,11 @@ func computeOD(raw map[string]any) (float64, bool) {
remaining = 0
}
// NOTE: UB's literal CalcMissileDamage reads DoubleValues[63], but no
// DoubleValueKey ordinal 63 exists (verified against Decal.Adapter) —
// that line is a stale/bugged reference in the UB source. The correct
// populated key is 167772174 (DamageBonus), consistent with UB's own
// CalcedBuffedMissileDamage. Do NOT "fix" this back to 63.
dmgMod := dvF(dv, "167772174", 0)*100 - 100
bDmg := float64(buffedMaxDamage(raw, iv))
if bDmg <= 10 {

View file

@ -23,6 +23,38 @@ func TestOD_Wand(t *testing.T) {
}
}
// Wand with an ACTIVE Prodigal Spirit Drinker (3735, change .15, bonus 0):
// shown ElemVsMonsters 1.55 un-buffs to 1.55 .15 = 1.40 → OD +22, same
// underlying weapon as TestOD_Wand.
func TestOD_WandActiveProdigalSpiritDrinker(t *testing.T) {
raw := map[string]any{
"ObjectClass": 31.0,
"IntValues": map[string]any{"159": 34.0, "160": 385.0},
"DoubleValues": map[string]any{"152": 1.55, "167772169": 8.0},
"Spells": []any{}, "ActiveSpells": []any{3735.0},
}
od, ok := computeOD(raw)
if !ok || !approx(od, 22.0) {
t.Fatalf("wand w/ active Prodigal SD OD = %v ok=%v, want +22", od, ok)
}
}
// Wand carrying a mastery value (353) with no matching wand table row: the
// exact-match lookup on (34,5,0,385) misses, and the mastery-0 retry must hit
// the (34,0,0,385) row → OD +22 as in TestOD_Wand.
func TestOD_WandMasteryFallback(t *testing.T) {
raw := map[string]any{
"ObjectClass": 31.0,
"IntValues": map[string]any{"159": 34.0, "353": 5.0, "160": 385.0},
"DoubleValues": map[string]any{"152": 1.40, "167772169": 8.0},
"Spells": []any{}, "ActiveSpells": []any{},
}
od, ok := computeOD(raw)
if !ok || !approx(od, 22.0) {
t.Fatalf("wand mastery-fallback OD = %v ok=%v, want +22", od, ok)
}
}
// Non-loot (no workmanship) → no OD.
func TestOD_NonLootNull(t *testing.T) {
raw := map[string]any{