Give item categories and subtypes real types (refactor step 2)

ObjectKind separates what an item is from how it draws: Object.Type
(a byte that doubled as the map character) becomes Kind ObjectKind,
with Glyph() producing the display character and objectKindForGlyph
converting back at the map boundary. KindWand covers the C 'stick'
category. The magic-missile bolt uses KindGold, matching C's literal
o_type='*' trick, with a comment.

PotionKind, ScrollKind, RingKind, WandKind, WeaponKind, ArmorKind and
TrapKind are now iota enums with Stringer (names come from the base
info tables); Object gains typed accessors (obj.RingKind(), ...) and
Launch is typed WeaponKind. beTrapped returns TrapKind. The
getItem/inventory/whatis prompt filters take ObjectKind, with
KindCallable/KindRingOrStick replacing the C CALLABLE/R_OR_S
sentinels; wizard.c's type_name table is subsumed by
ObjectKind.String(). IsRing/IsWearing/initWeapon/doPot signatures are
typed accordingly.

The save format version becomes 5.4.4-go2: the gob field rename would
otherwise silently zero Kind when reading old saves.

No behavior change; full suite green.
This commit is contained in:
2026-07-06 22:00:43 +02:00
parent 626f8c5a7d
commit b940cfc41f
27 changed files with 426 additions and 259 deletions

View File

@@ -22,8 +22,8 @@ func give(g *RogueGame, obj *Object) byte {
func TestQuaffHealingPotion(t *testing.T) {
g := mkGameInput(t, 5, "")
pot := newObject()
pot.Type = Potion
pot.Which = PotionHealing
pot.Kind = KindPotion
pot.Which = int(PotionHealing)
ch := give(g, pot)
g.scr.term.(*testTerm).input = []byte{ch}
@@ -43,8 +43,8 @@ func TestQuaffHealingPotion(t *testing.T) {
func TestQuaffConfusionSetsFlagAndFuse(t *testing.T) {
g := mkGameInput(t, 5, "")
pot := newObject()
pot.Type = Potion
pot.Which = PotionConfusion
pot.Kind = KindPotion
pot.Which = int(PotionConfusion)
ch := give(g, pot)
g.scr.term.(*testTerm).input = []byte{ch}
@@ -67,8 +67,8 @@ func TestQuaffConfusionSetsFlagAndFuse(t *testing.T) {
func TestReadEnchantArmor(t *testing.T) {
g := mkGameInput(t, 5, "")
scr := newObject()
scr.Type = Scroll
scr.Which = ScrollEnchantArmor
scr.Kind = KindScroll
scr.Which = int(ScrollEnchantArmor)
ch := give(g, scr)
g.scr.term.(*testTerm).input = []byte{ch}
@@ -90,8 +90,8 @@ func TestReadHoldMonsterFreezesAdjacent(t *testing.T) {
tp := spawnAdjacent(g, 'Z')
tp.Flags.Set(Awake)
scr := newObject()
scr.Type = Scroll
scr.Which = ScrollHoldMonster
scr.Kind = KindScroll
scr.Which = int(ScrollHoldMonster)
ch := give(g, scr)
g.scr.term.(*testTerm).input = []byte{ch}
@@ -111,8 +111,8 @@ func TestHoldScrollGreedyMonsterQuirk(t *testing.T) {
tp := spawnAdjacent(g, 'O')
tp.Flags.Set(Awake)
scr := newObject()
scr.Type = Scroll
scr.Which = ScrollHoldMonster
scr.Kind = KindScroll
scr.Which = int(ScrollHoldMonster)
ch := give(g, scr)
g.scr.term.(*testTerm).input = []byte{ch}
@@ -132,8 +132,8 @@ func TestZapSlowMonster(t *testing.T) {
g := mkGameInput(t, 5, "")
tp := spawnAdjacent(g, 'Z')
stick := newObject()
stick.Type = Stick
stick.Which = WandSlowMonster
stick.Kind = KindWand
stick.Which = int(WandSlowMonster)
g.fixStick(stick)
ch := give(g, stick)
g.scr.term.(*testTerm).input = []byte{ch}