feat(inventory-go): Mag-Tools OD weapon rating calculation (od.go)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
f92d158fd0
commit
231e6e799f
2 changed files with 659 additions and 0 deletions
97
go-services/inventory-go/od_test.go
Normal file
97
go-services/inventory-go/od_test.go
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func approx(a, b float64) bool { return math.Abs(a-b) < 0.01 }
|
||||
|
||||
// Wand: OD = (buffedElemVsMonsters - tableMaxElemVsMonsters) * 100.
|
||||
// Live "Frost Baton": skill 34 (war), wieldreq 385, ElemVsMonsters 1.40,
|
||||
// no spirit-drinker spells. Table max for (34,*,*,385) = 1.18 → OD = +22.
|
||||
func TestOD_Wand(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.40, "167772169": 8.0},
|
||||
"Spells": []any{}, "ActiveSpells": []any{},
|
||||
}
|
||||
od, ok := computeOD(raw)
|
||||
if !ok || !approx(od, 22.0) {
|
||||
t.Fatalf("wand OD = %v ok=%v, want +22", od, ok)
|
||||
}
|
||||
}
|
||||
|
||||
// Non-loot (no workmanship) → no OD.
|
||||
func TestOD_NonLootNull(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.40},
|
||||
"Spells": []any{}, "ActiveSpells": []any{},
|
||||
}
|
||||
if _, ok := computeOD(raw); ok {
|
||||
t.Fatal("no-workmanship item must have no OD")
|
||||
}
|
||||
}
|
||||
|
||||
// Table lookup miss (unknown tier) → no OD.
|
||||
func TestOD_UnknownTierNull(t *testing.T) {
|
||||
raw := map[string]any{
|
||||
"ObjectClass": 31.0,
|
||||
"IntValues": map[string]any{"159": 34.0, "160": 999.0},
|
||||
"DoubleValues": map[string]any{"152": 1.40, "167772169": 8.0},
|
||||
"Spells": []any{}, "ActiveSpells": []any{},
|
||||
}
|
||||
if _, ok := computeOD(raw); ok {
|
||||
t.Fatal("unknown wieldreq tier must have no OD")
|
||||
}
|
||||
}
|
||||
|
||||
// Melee: OD = buffedMaxDmg - varianceTinks - tableMaxDmg,
|
||||
// varianceTinks = round(log(tableMaxVar/variance)/log(0.8), 2).
|
||||
// Heavy (44) sword (2) non-MS, wieldreq 430: tableMaxDmg=71, tableMaxVar=0.47.
|
||||
// A perfect retail-max item: maxDmg 71, variance 0.47 → varianceTinks=0 → OD 0.
|
||||
func TestOD_MeleeRetailMaxIsZero(t *testing.T) {
|
||||
raw := 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{}, "ActiveSpells": []any{},
|
||||
}
|
||||
od, ok := computeOD(raw)
|
||||
if !ok || !approx(od, 0.0) {
|
||||
t.Fatalf("melee retail-max OD = %v ok=%v, want 0", od, ok)
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
func TestOD_MeleeOneTinkVariance(t *testing.T) {
|
||||
raw := 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.376, "167772169": 10.0},
|
||||
"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)
|
||||
}
|
||||
}
|
||||
|
||||
// Melee buffed: innate Legendary Blood Thirst (id 6089, +10 MaxDamage).
|
||||
// maxDmg 61 + 10 = 71, variance 0.47 → OD 0 (vs 71 table).
|
||||
func TestOD_MeleeBuffedByBloodThirst(t *testing.T) {
|
||||
raw := map[string]any{
|
||||
"ObjectClass": 1.0,
|
||||
"IntValues": map[string]any{"159": 44.0, "353": 2.0, "160": 430.0, "218103842": 61.0},
|
||||
"DoubleValues": map[string]any{"167772171": 0.47, "167772169": 10.0},
|
||||
"Spells": []any{6089.0}, "ActiveSpells": []any{},
|
||||
}
|
||||
od, ok := computeOD(raw)
|
||||
if !ok || !approx(od, 0.0) {
|
||||
t.Fatalf("melee buffed OD = %v ok=%v, want 0", od, ok)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue