Files
rgoue/game/dice_test.go
sneak 2eff377a73 Un-overload Object fields and pre-parse damage dice (refactor step 3)
Object.Arm carried four meanings in C (o_arm/o_charges/o_goldval plus
ring bonuses); it is now four fields: ArmorClass, Charges, GoldValue,
and Bonus. Stats.Arm becomes Stats.ArmorClass. The Charges()/GoldVal()
accessor pair is gone.

Damage dice strings ("1x4/1x2") are parsed once into DiceSpec — at
table definition for the bestiary and weapon tables, at creation for
items — instead of re-parsed with atoi on every swing as fight.c
roll_em did. ParseDice preserves the C parse semantics exactly,
including the junk-tolerant "%%%x0" bestiary placeholder and the
"000x0" flytrap reset (regression-tested in dice_test.go); the
flytrap's growing grip becomes DiceSpec{{VfHit, 1}}.

Save format bumps to 5.4.4-go3 (field renames and retypes would
silently zero under gob's match-by-name decoding).

No behavior change; full suite green.
2026-07-06 23:07:57 +02:00

46 lines
1.2 KiB
Go

package game
import "testing"
// ParseDice must keep the exact semantics of the C roll_em parse loop,
// including its junk-tolerant edges: the bestiary placeholder "%%%x0" and
// the flytrap reset "000x0" both mean a single 0x0 attack.
func TestParseDice(t *testing.T) {
cases := []struct {
in string
want string
len int
}{
{"1x4", "1x4", 1},
{"1x2/1x5/1x5", "1x2/1x5/1x5", 3},
{"2x12/2x4", "2x12/2x4", 2},
{"0x0", "0x0", 1},
{"000x0", "0x0", 1},
{"%%%x0", "0x0", 1},
{"", "", 0},
{"3", "", 0}, // no 'x': C parses nothing
}
for _, c := range cases {
got := ParseDice(c.in)
if len(got) != c.len || got.String() != c.want {
t.Errorf("ParseDice(%q) = %v (len %d), want %q (len %d)",
c.in, got, len(got), c.want, c.len)
}
}
}
// The bestiary and weapon tables must parse to at least one attack each so
// every creature and weapon actually swings.
func TestTablesHaveDice(t *testing.T) {
for i, m := range monsterTable {
if len(m.Stats.Dmg) == 0 {
t.Errorf("monster %c (%s) has no attacks", 'A'+i, m.Name)
}
}
for w, iw := range initWeaps {
if len(iw.dam) == 0 || len(iw.hrl) == 0 {
t.Errorf("weapon %v has empty dice", WeaponKind(w))
}
}
}