fix(inventory-go): OD variance orientation per UB source; exact SpellInfo change/bonus semantics; missile golden test
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
16077633c5
commit
f75a236f54
2 changed files with 105 additions and 46 deletions
|
|
@ -66,8 +66,12 @@ func TestOD_MeleeRetailMaxIsZero(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Melee with tighter variance (0.376 = one granite tink below 0.47):
|
||||
// varianceTinks = round(log(0.47/0.376)/log(0.8), 2) = round(1.00,2)=1 → OD = 71-1-71 = -1.
|
||||
// Melee with tighter variance (0.376 = one granite tink below the 0.47 baseline):
|
||||
// the table MaxVar is the BASELINE variance for the tier, and lower variance than
|
||||
// baseline is better — it contributes positively to OD. Per UB ItemInfo.cs:1096
|
||||
// (Math.Log(perfectVariance / Variance, 0.8)):
|
||||
// varianceTinks = round(log(0.47/0.376)/log(0.8), 2) = round(-1.00,2) = -1
|
||||
// → OD = 71 - (-1) - 71 = +1.
|
||||
func TestOD_MeleeOneTinkVariance(t *testing.T) {
|
||||
raw := map[string]any{
|
||||
"ObjectClass": 1.0,
|
||||
|
|
@ -76,8 +80,8 @@ func TestOD_MeleeOneTinkVariance(t *testing.T) {
|
|||
"Spells": []any{}, "ActiveSpells": []any{},
|
||||
}
|
||||
od, ok := computeOD(raw)
|
||||
if !ok || !approx(od, -1.0) {
|
||||
t.Fatalf("melee OD = %v ok=%v, want -1", od, ok)
|
||||
if !ok || !approx(od, 1.0) {
|
||||
t.Fatalf("melee OD = %v ok=%v, want +1", od, ok)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -95,3 +99,50 @@ func TestOD_MeleeBuffedByBloodThirst(t *testing.T) {
|
|||
t.Fatalf("melee buffed OD = %v ok=%v, want 0", od, ok)
|
||||
}
|
||||
}
|
||||
|
||||
// Exact SpellInfo(change, bonus) semantics (UB Dictionaries.cs:356): innate
|
||||
// Spells add `bonus`, ActiveSpells subtract `change`. Incantation of Blood
|
||||
// Drinker (5183) has change=24 but bonus=0 (the 2012 aura conversion), so:
|
||||
// - innate 5183 grants NOTHING → maxDmg 71 + 0 = 71 → OD 0;
|
||||
// - active 5183 on an enchanted maxDmg 95 (71+24) subtracts 24 → 71 → OD 0.
|
||||
func TestOD_MeleeInnateIncantBDGrantsNothing(t *testing.T) {
|
||||
innate := map[string]any{
|
||||
"ObjectClass": 1.0,
|
||||
"IntValues": map[string]any{"159": 44.0, "353": 2.0, "160": 430.0, "218103842": 71.0},
|
||||
"DoubleValues": map[string]any{"167772171": 0.47, "167772169": 10.0},
|
||||
"Spells": []any{5183.0}, "ActiveSpells": []any{},
|
||||
}
|
||||
od, ok := computeOD(innate)
|
||||
if !ok || !approx(od, 0.0) {
|
||||
t.Fatalf("innate Incant BD OD = %v ok=%v, want 0 (bonus is 0)", od, ok)
|
||||
}
|
||||
|
||||
active := map[string]any{
|
||||
"ObjectClass": 1.0,
|
||||
"IntValues": map[string]any{"159": 44.0, "353": 2.0, "160": 430.0, "218103842": 95.0},
|
||||
"DoubleValues": map[string]any{"167772171": 0.47, "167772169": 10.0},
|
||||
"Spells": []any{}, "ActiveSpells": []any{5183.0},
|
||||
}
|
||||
od, ok = computeOD(active)
|
||||
if !ok || !approx(od, 0.0) {
|
||||
t.Fatalf("active Incant BD OD = %v ok=%v, want 0 (change 24 subtracted)", od, ok)
|
||||
}
|
||||
}
|
||||
|
||||
// Missile golden test, modeled on the live Fire Compound Bow:
|
||||
// bow (mastery 8), wieldreq 385, maxDmg 32, elem bonus 21, DamageBonus 2.73,
|
||||
// no "171" key → tinks 0 → remaining 9 (the imbue tink is reserved).
|
||||
// dmgMod = 2.73·100−100 = 173; arrowMax = 40; maxMod = (140+136)/100 = 2.76;
|
||||
// OD = (1+(173+4·9)/100)·(21+32+40)/2.76 − (22+24+40) = 3.09·93/2.76 − 86 ≈ 18.12.
|
||||
func TestOD_MissileBow(t *testing.T) {
|
||||
raw := map[string]any{
|
||||
"ObjectClass": 9.0,
|
||||
"IntValues": map[string]any{"159": 47.0, "353": 8.0, "160": 385.0, "218103842": 32.0, "204": 21.0},
|
||||
"DoubleValues": map[string]any{"167772174": 2.73, "167772169": 6.0},
|
||||
"Spells": []any{}, "ActiveSpells": []any{},
|
||||
}
|
||||
od, ok := computeOD(raw)
|
||||
if !ok || !approx(od, 18.12) {
|
||||
t.Fatalf("missile bow OD = %v ok=%v, want 18.12", od, ok)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue