Pure rename, no behavior change; the full suite (RNG goldens,
generation invariants, scripted sessions, save round trip) is
unchanged and green.
- Creature flags: IsHuh→Confused, IsHalu→Hallucinating,
CanHuh→CanConfuse, CanSee→CanSeeInvisible, IsRun→Awake,
SeeMonst→SenseMonsters, IsCanc→Cancelled, IsLevit→Levitating,
IsBlind/IsGreed/IsHaste/IsTarget/IsHeld/IsInvis/IsMean/IsRegen/
IsFly/IsSlow → Blind/Greedy/Hasted/Targeted/Held/Invisible/Mean/
Regenerates/Flying/Slowed, IsFound→Found
- Object flags: IsCursed→Cursed, IsKnow→Known, IsMissl→Missile,
IsMany→Stackable, ObjIsFound→WasFound, IsProt→Protected
- Room flags: IsDark/IsGone/IsMaze → Dark/Gone/Maze; place flags:
FPass→FPassage, FPNum→FPassNum, FTMask→FTrapMask
- Trap types: TDoor→TrapDoor ... TMyst→TrapMystery
- Item subtypes: P*→Potion* (PLSD→PotionLSD, PMFind→
PotionDetectMonsters, ...), S*→Scroll* (SIDRorS→
ScrollIdentifyRingOrStick, ...), R*→Ring* (RAddHit→RingDexterity,
RNop→RingAdornment, ...), Ws*→Wand* (WsElect→WandLightning, ...),
weapons (TwoSword→WeaponTwoHandedSword, Shiraken→WeaponShuriken,
...), armor (RingMail→ArmorRingMail, ...)
- Counts: Max{Potions,Scrolls,Rings,Sticks,Weapons,Armors} →
Num{Potion,Scroll,Ring,Wand,Weapon,Armor}Types; NTraps→NumTrapTypes
- Level.NTraps field → TrapCount (also in the save snapshot)
- Original C constant names preserved as comment breadcrumbs in
types.go so the lineage stays greppable
TODO.md: step 1 moved to Completed, step 2 (typed kinds) promoted to
Next Step.
87 lines
2.2 KiB
Go
87 lines
2.2 KiB
Go
package game
|
|
|
|
import "testing"
|
|
|
|
// badcheck from init.c: every probability table must sum to exactly 100.
|
|
func TestProbabilitiesSumTo100(t *testing.T) {
|
|
sum := func(info []ObjInfo) int {
|
|
s := 0
|
|
for _, oi := range info {
|
|
s += oi.Prob
|
|
}
|
|
return s
|
|
}
|
|
tables := map[string][]ObjInfo{
|
|
"things": baseThings[:],
|
|
"potions": basePotInfo[:],
|
|
"scrolls": baseScrInfo[:],
|
|
"rings": baseRingInfo[:],
|
|
"sticks": baseWsInfo[:],
|
|
"weapons": baseWeapInfo[:NumWeaponTypes], // excludes the flame entry
|
|
"armor": baseArmInfo[:],
|
|
}
|
|
for name, tab := range tables {
|
|
if s := sum(tab); s != 100 {
|
|
t.Errorf("bad percentages for %s: sum = %d, want 100", name, s)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestInitProbsCumulative(t *testing.T) {
|
|
g := NewGame(Config{Seed: 1})
|
|
last := g.Items.Potions[NumPotionTypes-1].Prob
|
|
if last != 100 {
|
|
t.Errorf("cumulative potion probability ends at %d, want 100", last)
|
|
}
|
|
for i := 1; i < NumPotionTypes; i++ {
|
|
if g.Items.Potions[i].Prob < g.Items.Potions[i-1].Prob {
|
|
t.Errorf("potion probs not nondecreasing at %d", i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNewGameRandomizesAppearances(t *testing.T) {
|
|
g := NewGame(Config{Seed: 12345})
|
|
seen := map[string]bool{}
|
|
for i, c := range g.Items.PotColors {
|
|
if c == "" {
|
|
t.Fatalf("potion %d has no color", i)
|
|
}
|
|
if seen[c] {
|
|
t.Errorf("potion color %q assigned twice", c)
|
|
}
|
|
seen[c] = true
|
|
}
|
|
for i, n := range g.Items.ScrNames {
|
|
if n == "" {
|
|
t.Fatalf("scroll %d has no name", i)
|
|
}
|
|
if len(n) > MaxNameLen+1 {
|
|
t.Errorf("scroll name %q longer than C buffer allows", n)
|
|
}
|
|
}
|
|
for i := range g.Items.WandType {
|
|
if g.Items.WandType[i] != "wand" && g.Items.WandType[i] != "staff" {
|
|
t.Errorf("stick %d has type %q", i, g.Items.WandType[i])
|
|
}
|
|
if g.Items.WandMade[i] == "" {
|
|
t.Errorf("stick %d has no material", i)
|
|
}
|
|
}
|
|
|
|
// Determinism: same seed, same appearances.
|
|
h := NewGame(Config{Seed: 12345})
|
|
if h.Items != g.Items {
|
|
t.Error("two games with the same seed produced different item lore")
|
|
}
|
|
}
|
|
|
|
func TestMonsterTable(t *testing.T) {
|
|
if monsterTable[0].Name != "aquator" || monsterTable[25].Name != "zombie" {
|
|
t.Error("monster table order broken")
|
|
}
|
|
if monsterTable['D'-'A'].Name != "dragon" {
|
|
t.Error("letter indexing broken")
|
|
}
|
|
}
|