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

@@ -62,12 +62,6 @@ const (
Stick byte = '/'
)
// Pseudo-types for item-selection prompts (rogue.h)
const (
Callable = -1
RorS = -2
)
// Various constants (rogue.h)
const (
HealTime = 30
@@ -173,22 +167,37 @@ func (f PlaceFlags) Has(b PlaceFlags) bool { return f&b != 0 }
func (f *PlaceFlags) Set(b PlaceFlags) { *f |= b }
func (f *PlaceFlags) Clear(b PlaceFlags) { *f &^= b }
// Trap types (rogue.h)
// TrapKind identifies a trap (rogue.h trap types). The kind is stored in
// the low bits of a map cell's PlaceFlags (FTrapMask).
type TrapKind int
const (
TrapDoor = 0
TrapArrow = 1
TrapSleep = 2
TrapBear = 3
TrapTeleport = 4
TrapDart = 5
TrapRust = 6
TrapMystery = 7
NumTrapTypes = 8
TrapDoor TrapKind = 0
TrapArrow TrapKind = 1
TrapSleep TrapKind = 2
TrapBear TrapKind = 3
TrapTeleport TrapKind = 4
TrapDart TrapKind = 5
TrapRust TrapKind = 6
TrapMystery TrapKind = 7
NumTrapTypes = 8
)
// Potion types (rogue.h)
// String returns the trap's display name, article included, as the C
// tr_name table had it.
func (t TrapKind) String() string {
if t < 0 || t >= NumTrapTypes {
return "a bizarre trap"
}
return trName[t]
}
// PotionKind identifies a potion (rogue.h potion types).
type PotionKind int
// Potion kinds (rogue.h)
const (
PotionConfusion = iota
PotionConfusion PotionKind = iota
PotionLSD
PotionPoison
PotionGainStrength
@@ -205,9 +214,20 @@ const (
NumPotionTypes
)
// Scroll types (rogue.h)
// String returns the potion's true name ("healing", "haste self", ...).
func (p PotionKind) String() string {
if p < 0 || p >= NumPotionTypes {
return "strange potion"
}
return basePotInfo[p].Name
}
// ScrollKind identifies a scroll (rogue.h scroll types).
type ScrollKind int
// Scroll kinds (rogue.h)
const (
ScrollMonsterConfusion = iota
ScrollMonsterConfusion ScrollKind = iota
ScrollMagicMapping
ScrollHoldMonster
ScrollSleep
@@ -228,9 +248,20 @@ const (
NumScrollTypes
)
// Weapon types (rogue.h)
// String returns the scroll's true name ("magic mapping", ...).
func (s ScrollKind) String() string {
if s < 0 || s >= NumScrollTypes {
return "strange scroll"
}
return baseScrInfo[s].Name
}
// WeaponKind identifies a weapon (rogue.h weapon types).
type WeaponKind int
// Weapon kinds (rogue.h)
const (
WeaponMace = iota
WeaponMace WeaponKind = iota
WeaponLongSword
WeaponBow
WeaponArrow
@@ -243,9 +274,20 @@ const (
NumWeaponTypes = WeaponFlame
)
// Armor types (rogue.h)
// String returns the weapon's name ("mace", "two handed sword", ...).
func (w WeaponKind) String() string {
if w < 0 || w > WeaponFlame {
return "strange weapon"
}
return baseWeapInfo[w].Name
}
// ArmorKind identifies a suit of armor (rogue.h armor types).
type ArmorKind int
// Armor kinds (rogue.h)
const (
ArmorLeather = iota
ArmorLeather ArmorKind = iota
ArmorRingMail
ArmorStuddedLeather
ArmorScaleMail
@@ -256,9 +298,20 @@ const (
NumArmorTypes
)
// Ring types (rogue.h)
// String returns the armor's name ("ring mail", "plate mail", ...).
func (a ArmorKind) String() string {
if a < 0 || a >= NumArmorTypes {
return "strange armor"
}
return baseArmInfo[a].Name
}
// RingKind identifies a ring (rogue.h ring types).
type RingKind int
// Ring kinds (rogue.h)
const (
RingProtection = iota
RingProtection RingKind = iota
RingAddStrength
RingSustainStrength
RingSearching
@@ -275,9 +328,20 @@ const (
NumRingTypes
)
// Rod/Wand/Staff types (rogue.h)
// String returns the ring's true name ("add strength", "stealth", ...).
func (r RingKind) String() string {
if r < 0 || r >= NumRingTypes {
return "strange ring"
}
return baseRingInfo[r].Name
}
// WandKind identifies a wand or staff (rogue.h rod/wand/staff types).
type WandKind int
// Wand kinds (rogue.h)
const (
WandLight = iota
WandLight WandKind = iota
WandInvisibility
WandLightning
WandFire
@@ -294,6 +358,14 @@ const (
NumWandTypes
)
// String returns the wand/staff's true name ("lightning", ...).
func (w WandKind) String() string {
if w < 0 || w >= NumWandTypes {
return "strange stick"
}
return baseWsInfo[w].Name
}
// Coord is a position on the level (rogue.h coord). A value type: the C
// ce(a,b) macro is plain == here.
type Coord struct {
@@ -349,9 +421,6 @@ type Stone struct {
// CTRL maps a letter to its control character, as the C CTRL() macro.
func CTRL(c byte) byte { return c & 0o37 }
// IsMult reports whether an object type stacks in the pack (rogue.h ISMULT).
func IsMult(typ byte) bool { return typ == Potion || typ == Scroll || typ == Food }
// distance returns the squared distance between two points (chase.c dist).
func distance(y1, x1, y2, x2 int) int {
dx := x2 - x1