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

@@ -34,12 +34,12 @@ var pActions = [NumPotionTypes]pact{
// quaff drinks a potion from the pack (potions.c quaff).
func (g *RogueGame) quaff() {
p := &g.Player
obj := g.getItem("quaff", int(Potion))
obj := g.getItem("quaff", KindPotion)
// Make certain that it is something that we want to drink
if obj == nil {
return
}
if obj.Type != Potion {
if obj.Kind != KindPotion {
if !g.Options.Terse {
g.msg("yuk! Why would you want to drink that?")
} else {
@@ -54,7 +54,7 @@ func (g *RogueGame) quaff() {
// Calculate the effect it has on the poor guy.
trip := p.On(Hallucinating)
g.leavePack(obj, false, false)
switch obj.Which {
switch obj.PotionKind() {
case PotionConfusion:
g.doPot(PotionConfusion, !trip)
case PotionPoison:
@@ -187,10 +187,10 @@ func (g *RogueGame) raiseLevel() {
// doPot does a potion with standard setup: it uses a fuse and turns on a
// flag (potions.c do_pot).
func (g *RogueGame) doPot(typ int, knowit bool) {
pp := &pActions[typ]
if !g.Items.Potions[typ].Know {
g.Items.Potions[typ].Know = knowit
func (g *RogueGame) doPot(kind PotionKind, knowit bool) {
pp := &pActions[kind]
if !g.Items.Potions[kind].Know {
g.Items.Potions[kind].Know = knowit
}
t := g.spread(pp.time)
if !g.Player.On(pp.flags) {
@@ -201,7 +201,7 @@ func (g *RogueGame) doPot(typ int, knowit bool) {
g.Lengthen(pp.daemon, t)
}
high, straight := pp.high, pp.straight
if typ == PotionSeeInvisible {
if kind == PotionSeeInvisible {
s := fmt.Sprintf("this potion tastes like %s juice", g.Fruit)
high, straight = s, s
}
@@ -210,12 +210,12 @@ func (g *RogueGame) doPot(typ int, knowit bool) {
// isMagic reports whether an object radiates magic (potions.c is_magic).
func (o *Object) isMagic() bool {
switch o.Type {
case Armor:
switch o.Kind {
case KindArmor:
return o.Flags.Has(Protected) || o.Arm != aClass[o.Which]
case Weapon:
case KindWeapon:
return o.HPlus != 0 || o.DPlus != 0
case Potion, Scroll, Stick, Ring, Amulet:
case KindPotion, KindScroll, KindWand, KindRing, KindAmulet:
return true
}
return false