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

@@ -5,7 +5,7 @@ package game
// wear lets the player put armor on (armor.c wear). // wear lets the player put armor on (armor.c wear).
func (g *RogueGame) wear() { func (g *RogueGame) wear() {
p := &g.Player p := &g.Player
obj := g.getItem("wear", int(Armor)) obj := g.getItem("wear", KindArmor)
if obj == nil { if obj == nil {
return return
} }
@@ -18,7 +18,7 @@ func (g *RogueGame) wear() {
g.After = false g.After = false
return return
} }
if obj.Type != Armor { if obj.Kind != KindArmor {
g.msg("you can't wear that") g.msg("you can't wear that")
return return
} }

View File

@@ -233,7 +233,7 @@ func (g *RogueGame) chase(tp *Monster, ee Coord) bool {
break break
} }
} }
if found != nil && found.Which == ScrollScareMonster { if found != nil && found.ScrollKind() == ScrollScareMonster {
continue continue
} }
} }
@@ -375,7 +375,7 @@ func (g *RogueGame) findDest(tp *Monster) *Coord {
return &g.Player.Pos return &g.Player.Pos
} }
for _, obj := range g.Level.Objects { for _, obj := range g.Level.Objects {
if obj.Type == Scroll && obj.Which == ScrollScareMonster { if obj.Kind == KindScroll && obj.ScrollKind() == ScrollScareMonster {
continue continue
} }
if g.roomin(obj.Pos) == tp.Room && g.rnd(100) < prob { if g.roomin(obj.Pos) == tp.Room && g.rnd(100) < prob {

View File

@@ -149,7 +149,7 @@ over:
} }
if found != nil { if found != nil {
if !g.levitCheck() { if !g.levitCheck() {
g.pickUp(found.Type) g.pickUp(found.Kind.Glyph())
} }
} else { } else {
if !g.Options.Terse { if !g.Options.Terse {
@@ -409,7 +409,7 @@ func (g *RogueGame) wizardCommand(ch byte) {
case CTRL('X'): case CTRL('X'):
g.turnSee(p.On(SenseMonsters)) g.turnSee(p.On(SenseMonsters))
case CTRL('~'): case CTRL('~'):
if item := g.getItem("charge", int(Stick)); item != nil { if item := g.getItem("charge", KindWand); item != nil {
item.SetCharges(10000) item.SetCharges(10000)
} }
case CTRL('I'): case CTRL('I'):
@@ -425,8 +425,8 @@ func (g *RogueGame) wizardCommand(ch byte) {
p.CurWeapon = obj p.CurWeapon = obj
// And his suit of armor // And his suit of armor
obj = newObject() obj = newObject()
obj.Type = Armor obj.Kind = KindArmor
obj.Which = ArmorPlateMail obj.Which = int(ArmorPlateMail)
obj.Arm = -5 obj.Arm = -5
obj.Flags.Set(Known) obj.Flags.Set(Known)
obj.Count = 1 obj.Count = 1
@@ -671,7 +671,7 @@ func (g *RogueGame) levitCheck() bool {
// call allows a user to call a potion, scroll, or ring something // call allows a user to call a potion, scroll, or ring something
// (command.c call). // (command.c call).
func (g *RogueGame) call() { func (g *RogueGame) call() {
obj := g.getItem("call", Callable) obj := g.getItem("call", KindCallable)
// Make certain that it is something that we want to name // Make certain that it is something that we want to name
if obj == nil { if obj == nil {
return return
@@ -681,20 +681,20 @@ func (g *RogueGame) call() {
var know *bool var know *bool
var guess *string var guess *string
it := &g.Items it := &g.Items
switch obj.Type { switch obj.Kind {
case Ring: case KindRing:
op = &it.Rings[obj.Which] op = &it.Rings[obj.Which]
elsewise = it.RingStones[obj.Which] elsewise = it.RingStones[obj.Which]
case Potion: case KindPotion:
op = &it.Potions[obj.Which] op = &it.Potions[obj.Which]
elsewise = it.PotColors[obj.Which] elsewise = it.PotColors[obj.Which]
case Scroll: case KindScroll:
op = &it.Scrolls[obj.Which] op = &it.Scrolls[obj.Which]
elsewise = it.ScrNames[obj.Which] elsewise = it.ScrNames[obj.Which]
case Stick: case KindWand:
op = &it.Sticks[obj.Which] op = &it.Sticks[obj.Which]
elsewise = it.WandMade[obj.Which] elsewise = it.WandMade[obj.Which]
case Food: case KindFood:
g.msg("you can't call that anything") g.msg("you can't call that anything")
return return
default: default:

View File

@@ -40,12 +40,12 @@ type Player struct {
func (c *Creature) On(f CreatureFlags) bool { return c.Flags.Has(f) } func (c *Creature) On(f CreatureFlags) bool { return c.Flags.Has(f) }
// IsRing is the C ISRING(hand, ring) macro. // IsRing is the C ISRING(hand, ring) macro.
func (p *Player) IsRing(hand, ring int) bool { func (p *Player) IsRing(hand int, ring RingKind) bool {
return p.CurRing[hand] != nil && p.CurRing[hand].Which == ring return p.CurRing[hand] != nil && p.CurRing[hand].RingKind() == ring
} }
// IsWearing is the C ISWEARING(ring) macro: is the ring on either hand. // IsWearing is the C ISWEARING(ring) macro: is the ring on either hand.
func (p *Player) IsWearing(ring int) bool { func (p *Player) IsWearing(ring RingKind) bool {
return p.IsRing(Left, ring) || p.IsRing(Right, ring) return p.IsRing(Left, ring) || p.IsRing(Right, ring)
} }

View File

@@ -194,7 +194,7 @@ func (g *RogueGame) comeDown(int) {
// undo the things // undo the things
for _, tp := range g.Level.Objects { for _, tp := range g.Level.Objects {
if g.cansee(tp.Pos.Y, tp.Pos.X) { if g.cansee(tp.Pos.Y, tp.Pos.X) {
g.mvaddch(tp.Pos.Y, tp.Pos.X, tp.Type) g.mvaddch(tp.Pos.Y, tp.Pos.X, tp.Kind.Glyph())
} }
} }

View File

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

View File

@@ -344,7 +344,7 @@ func (g *RogueGame) rollEm(thatt, thdef *Creature, weap *Object, hurl bool) bool
cp = weap.Damage cp = weap.Damage
if hurl { if hurl {
if weap.Flags.Has(Missile) && p.CurWeapon != nil && if weap.Flags.Has(Missile) && p.CurWeapon != nil &&
p.CurWeapon.Which == weap.Launch { WeaponKind(p.CurWeapon.Which) == weap.Launch {
cp = weap.HurlDmg cp = weap.HurlDmg
hplus += p.CurWeapon.HPlus hplus += p.CurWeapon.HPlus
dplus += p.CurWeapon.DPlus dplus += p.CurWeapon.DPlus
@@ -425,7 +425,7 @@ func (g *RogueGame) thunk(weap *Object, mname string, noend bool) {
if g.ToDeath { if g.ToDeath {
return return
} }
if weap.Type == Weapon { if weap.Kind == KindWeapon {
g.addmsg("the %s hits ", g.Items.Weapons[weap.Which].Name) g.addmsg("the %s hits ", g.Items.Weapons[weap.Which].Name)
} else { } else {
g.addmsg("you hit ") g.addmsg("you hit ")
@@ -488,7 +488,7 @@ func (g *RogueGame) bounce(weap *Object, mname string, noend bool) {
if g.ToDeath { if g.ToDeath {
return return
} }
if weap.Type == Weapon { if weap.Kind == KindWeapon {
g.addmsg("the %s misses ", g.Items.Weapons[weap.Which].Name) g.addmsg("the %s misses ", g.Items.Weapons[weap.Which].Name)
} else { } else {
g.addmsg("you missed ") g.addmsg("you missed ")
@@ -539,7 +539,7 @@ func (g *RogueGame) killed(tp *Monster, pr bool) {
} }
if ok && g.Depth >= g.MaxDepth { if ok && g.Depth >= g.MaxDepth {
gold := newObject() gold := newObject()
gold.Type = Gold gold.Kind = KindGold
gold.SetGoldVal(g.goldCalc()) gold.SetGoldVal(g.goldCalc())
if g.save(VsMagic) { if g.save(VsMagic) {
gold.Arm += g.goldCalc() + g.goldCalc() + g.goldCalc() + g.goldCalc() gold.Arm += g.goldCalc() + g.goldCalc() + g.goldCalc() + g.goldCalc()

View File

@@ -13,13 +13,13 @@ func (g *RogueGame) initPlayer() {
p.FoodLeft = HungerTime p.FoodLeft = HungerTime
// Give him some food // Give him some food
obj := newObject() obj := newObject()
obj.Type = Food obj.Kind = KindFood
obj.Count = 1 obj.Count = 1
g.addPack(obj, true) g.addPack(obj, true)
// And his suit of armor // And his suit of armor
obj = newObject() obj = newObject()
obj.Type = Armor obj.Kind = KindArmor
obj.Which = ArmorRingMail obj.Which = int(ArmorRingMail)
obj.Arm = aClass[ArmorRingMail] - 1 obj.Arm = aClass[ArmorRingMail] - 1
obj.Flags.Set(Known) obj.Flags.Set(Known)
obj.Count = 1 obj.Count = 1
@@ -51,7 +51,7 @@ func (g *RogueGame) initPlayer() {
// (init.c init_colors). // (init.c init_colors).
func (g *RogueGame) initColors() { func (g *RogueGame) initColors() {
used := make([]bool, len(rainbow)) used := make([]bool, len(rainbow))
for i := 0; i < NumPotionTypes; i++ { for i := PotionKind(0); i < NumPotionTypes; i++ {
var j int var j int
for { for {
j = g.rnd(len(rainbow)) j = g.rnd(len(rainbow))
@@ -66,7 +66,7 @@ func (g *RogueGame) initColors() {
// initNames generates the names of the various scrolls (init.c init_names). // initNames generates the names of the various scrolls (init.c init_names).
func (g *RogueGame) initNames() { func (g *RogueGame) initNames() {
for i := 0; i < NumScrollTypes; i++ { for i := ScrollKind(0); i < NumScrollTypes; i++ {
var cp strings.Builder var cp strings.Builder
nwords := g.rnd(3) + 2 nwords := g.rnd(3) + 2
for ; nwords > 0; nwords-- { for ; nwords > 0; nwords-- {
@@ -88,7 +88,7 @@ func (g *RogueGame) initNames() {
// (init.c init_stones). // (init.c init_stones).
func (g *RogueGame) initStones() { func (g *RogueGame) initStones() {
used := make([]bool, len(stoneTable)) used := make([]bool, len(stoneTable))
for i := 0; i < NumRingTypes; i++ { for i := RingKind(0); i < NumRingTypes; i++ {
var j int var j int
for { for {
j = g.rnd(len(stoneTable)) j = g.rnd(len(stoneTable))
@@ -107,7 +107,7 @@ func (g *RogueGame) initStones() {
func (g *RogueGame) initMaterials() { func (g *RogueGame) initMaterials() {
used := make([]bool, len(woods)) used := make([]bool, len(woods))
metused := make([]bool, len(metals)) metused := make([]bool, len(metals))
for i := 0; i < NumWandTypes; i++ { for i := WandKind(0); i < NumWandTypes; i++ {
var str string var str string
for { for {
if g.rnd(2) == 0 { if g.rnd(2) == 0 {

View File

@@ -213,11 +213,11 @@ func (g *RogueGame) findObj(y, x int) *Object {
// eat lets her try to eat something (misc.c eat). // eat lets her try to eat something (misc.c eat).
func (g *RogueGame) eat() { func (g *RogueGame) eat() {
obj := g.getItem("eat", int(Food)) obj := g.getItem("eat", KindFood)
if obj == nil { if obj == nil {
return return
} }
if obj.Type != Food { if obj.Kind != KindFood {
if !g.Options.Terse { if !g.Options.Terse {
g.msg("ugh, you would get ill if you ate that") g.msg("ugh, you would get ill if you ate that")
} else { } else {

View File

@@ -192,7 +192,7 @@ func (g *RogueGame) doorOpen(rp *Room) {
} }
// beTrapped makes him pay for stepping on a trap (move.c be_trapped). // beTrapped makes him pay for stepping on a trap (move.c be_trapped).
func (g *RogueGame) beTrapped(tc Coord) int { func (g *RogueGame) beTrapped(tc Coord) TrapKind {
p := &g.Player p := &g.Player
if p.On(Levitating) { if p.On(Levitating) {
return TrapRust // anything that's not a door or teleport return TrapRust // anything that's not a door or teleport
@@ -201,7 +201,7 @@ func (g *RogueGame) beTrapped(tc Coord) int {
g.Count = 0 g.Count = 0
pp := g.Level.At(tc.Y, tc.X) pp := g.Level.At(tc.Y, tc.X)
pp.Ch = Trap pp.Ch = Trap
tr := int(pp.Flags & FTrapMask) tr := TrapKind(pp.Flags & FTrapMask)
pp.Flags.Set(FSeen) pp.Flags.Set(FSeen)
switch tr { switch tr {
case TrapDoor: case TrapDoor:
@@ -311,7 +311,7 @@ func (g *RogueGame) rndmove(who *Creature) Coord {
break break
} }
} }
if found != nil && found.Which == ScrollScareMonster { if found != nil && found.ScrollKind() == ScrollScareMonster {
return who.Pos return who.Pos
} }
} }
@@ -321,7 +321,7 @@ func (g *RogueGame) rndmove(who *Creature) Coord {
// rustArmor rusts the given armor, if it is a legal kind to rust, and we // rustArmor rusts the given armor, if it is a legal kind to rust, and we
// aren't wearing a magic ring (move.c rust_armor). // aren't wearing a magic ring (move.c rust_armor).
func (g *RogueGame) rustArmor(arm *Object) { func (g *RogueGame) rustArmor(arm *Object) {
if arm == nil || arm.Type != Armor || arm.Which == ArmorLeather || if arm == nil || arm.Kind != KindArmor || arm.ArmorKind() == ArmorLeather ||
arm.Arm >= 9 { arm.Arm >= 9 {
return return
} }

View File

@@ -103,7 +103,7 @@ func (g *RogueGame) putThings() {
attachObj(&g.Level.Objects, obj) attachObj(&g.Level.Objects, obj)
// Put it somewhere // Put it somewhere
obj.Pos, _ = g.findFloor(nil, 0, false) obj.Pos, _ = g.findFloor(nil, 0, false)
g.Level.SetChar(obj.Pos.Y, obj.Pos.X, obj.Type) g.Level.SetChar(obj.Pos.Y, obj.Pos.X, obj.Kind.Glyph())
} }
} }
// If he is really deep in the dungeon and he hasn't found the amulet // If he is really deep in the dungeon and he hasn't found the amulet
@@ -114,7 +114,7 @@ func (g *RogueGame) putThings() {
obj.Damage = "0x0" obj.Damage = "0x0"
obj.HurlDmg = "0x0" obj.HurlDmg = "0x0"
obj.Arm = 11 obj.Arm = 11
obj.Type = Amulet obj.Kind = KindAmulet
// Put it somewhere // Put it somewhere
obj.Pos, _ = g.findFloor(nil, 0, false) obj.Pos, _ = g.findFloor(nil, 0, false)
g.Level.SetChar(obj.Pos.Y, obj.Pos.X, Amulet) g.Level.SetChar(obj.Pos.Y, obj.Pos.X, Amulet)
@@ -134,7 +134,7 @@ func (g *RogueGame) treasRoom() {
tp := g.newThing() tp := g.newThing()
tp.Pos = mp tp.Pos = mp
attachObj(&g.Level.Objects, tp) attachObj(&g.Level.Objects, tp)
g.Level.SetChar(mp.Y, mp.X, tp.Type) g.Level.SetChar(mp.Y, mp.X, tp.Kind.Glyph())
} }
// fill up room with monsters from the next level down // fill up room with monsters from the next level down

View File

@@ -75,9 +75,10 @@ func TestNewLevelInvariants(t *testing.T) {
// share cells only with monsters standing on them). // share cells only with monsters standing on them).
for _, obj := range g.Level.Objects { for _, obj := range g.Level.Objects {
ch := g.Level.Char(obj.Pos.Y, obj.Pos.X) ch := g.Level.Char(obj.Pos.Y, obj.Pos.X)
if ch != obj.Type && g.Level.MonsterAt(obj.Pos.Y, obj.Pos.X) == nil { if ch != obj.Kind.Glyph() &&
t.Errorf("seed %d: object %q at (%d,%d) but map shows %q", g.Level.MonsterAt(obj.Pos.Y, obj.Pos.X) == nil {
seed, obj.Type, obj.Pos.Y, obj.Pos.X, ch) t.Errorf("seed %d: object %v at (%d,%d) but map shows %q",
seed, obj.Kind, obj.Pos.Y, obj.Pos.X, ch)
} }
} }
@@ -86,10 +87,12 @@ func TestNewLevelInvariants(t *testing.T) {
t.Errorf("seed %d: starting pack has %d items, want 5", t.Errorf("seed %d: starting pack has %d items, want 5",
seed, len(g.Player.Pack)) seed, len(g.Player.Pack))
} }
if g.Player.CurWeapon == nil || g.Player.CurWeapon.Which != WeaponMace { if g.Player.CurWeapon == nil ||
g.Player.CurWeapon.WeaponKind() != WeaponMace {
t.Errorf("seed %d: not wielding the starting mace", seed) t.Errorf("seed %d: not wielding the starting mace", seed)
} }
if g.Player.CurArmor == nil || g.Player.CurArmor.Which != ArmorRingMail { if g.Player.CurArmor == nil ||
g.Player.CurArmor.ArmorKind() != ArmorRingMail {
t.Errorf("seed %d: not wearing the starting ring mail", seed) t.Errorf("seed %d: not wearing the starting ring mail", seed)
} }
} }

View File

@@ -1,20 +1,111 @@
package game package game
// ObjectKind is the category of an item. In C this was the o_type byte,
// which doubled as the character drawn on the map; the port separates the
// category (ObjectKind) from its display character (Glyph).
type ObjectKind int
const (
KindNone ObjectKind = iota
KindPotion
KindScroll
KindFood
KindWeapon
KindArmor
KindRing
KindWand // a "stick": wand or staff
KindAmulet
KindGold
)
// Prompt-filter pseudo-kinds for item selection (rogue.h CALLABLE and
// R_OR_S): they never appear on an Object, only as getItem filters.
const (
KindCallable ObjectKind = -1
KindRingOrStick ObjectKind = -2
)
// kindGlyphs maps each kind to the character Rogue draws for it.
var kindGlyphs = [...]byte{
KindNone: ' ',
KindPotion: Potion,
KindScroll: Scroll,
KindFood: Food,
KindWeapon: Weapon,
KindArmor: Armor,
KindRing: Ring,
KindWand: Stick,
KindAmulet: Amulet,
KindGold: Gold,
}
// Glyph returns the map/display character for this kind of object.
func (k ObjectKind) Glyph() byte {
if k < 0 || int(k) >= len(kindGlyphs) {
return ' '
}
return kindGlyphs[k]
}
// String names the category the way the C type_name() did.
func (k ObjectKind) String() string {
switch k {
case KindPotion:
return "potion"
case KindScroll:
return "scroll"
case KindFood:
return "food"
case KindWeapon:
return "weapon"
case KindArmor:
return "suit of armor"
case KindRing:
return "ring"
case KindWand:
return "wand or staff"
case KindAmulet:
return "amulet"
case KindGold:
return "gold"
case KindRingOrStick:
return "ring, wand or staff"
}
return "bizarre thing"
}
// objectKindForGlyph is the reverse of Glyph: what category of item does a
// map character denote. Returns KindNone for non-item characters.
func objectKindForGlyph(ch byte) ObjectKind {
for k, g := range kindGlyphs {
if g == ch && ObjectKind(k) != KindNone {
return ObjectKind(k)
}
}
return KindNone
}
// MergesInPack reports whether picking up another of this kind merges into
// an existing pack entry's count (rogue.h ISMULT).
func (k ObjectKind) MergesInPack() bool {
return k == KindPotion || k == KindScroll || k == KindFood
}
// Object is the _o arm of the C THING union: anything that can lie on the // Object is the _o arm of the C THING union: anything that can lie on the
// floor or ride in a pack. // floor or ride in a pack.
type Object struct { type Object struct {
Type byte // what kind of object it is (Potion, Scroll, Weapon, ...) Kind ObjectKind // what kind of object it is (o_type)
Pos Coord // where it lives on the screen Pos Coord // where it lives on the screen
Text string // what it says if you read it Text string // what it says if you read it
Launch int // what you need to launch it (weapon index, -1 none) Launch WeaponKind // what you need to launch it (noWeapon if none)
PackCh byte // what character it is in the pack PackCh byte // what character it is in the pack
Damage string // damage if used like sword Damage string // damage if used like sword
HurlDmg string // damage if thrown HurlDmg string // damage if thrown
Count int // count for plural objects Count int // count for plural objects
Which int // which object of a type it is Which int // which object of a type it is (index for the Kind's table)
HPlus int // plusses to hit HPlus int // plusses to hit
DPlus int // plusses to damage DPlus int // plusses to damage
Arm int // armor protection — overloaded as in C (see Charges/GoldVal) Arm int // armor protection — overloaded as in C (see Charges/GoldVal)
Flags ObjFlags Flags ObjFlags
Group int // group number for this object Group int // group number for this object
Label string // label for object Label string // label for object
@@ -23,7 +114,7 @@ type Object struct {
// newObject is list.c new_item() for objects: a zeroed Object with the // newObject is list.c new_item() for objects: a zeroed Object with the
// same non-zero defaults the C code relies on. // same non-zero defaults the C code relies on.
func newObject() *Object { func newObject() *Object {
return &Object{Launch: -1} return &Object{Launch: noWeapon}
} }
// Charges is the o_charges alias for Arm on wands and staffs. // Charges is the o_charges alias for Arm on wands and staffs.
@@ -38,6 +129,24 @@ func (o *Object) GoldVal() int { return o.Arm }
// SetGoldVal stores a gold value in the overloaded Arm field. // SetGoldVal stores a gold value in the overloaded Arm field.
func (o *Object) SetGoldVal(n int) { o.Arm = n } func (o *Object) SetGoldVal(n int) { o.Arm = n }
// PotionKind returns Which as a potion kind; valid only for KindPotion.
func (o *Object) PotionKind() PotionKind { return PotionKind(o.Which) }
// ScrollKind returns Which as a scroll kind; valid only for KindScroll.
func (o *Object) ScrollKind() ScrollKind { return ScrollKind(o.Which) }
// RingKind returns Which as a ring kind; valid only for KindRing.
func (o *Object) RingKind() RingKind { return RingKind(o.Which) }
// WandKind returns Which as a wand kind; valid only for KindWand.
func (o *Object) WandKind() WandKind { return WandKind(o.Which) }
// WeaponKind returns Which as a weapon kind; valid only for KindWeapon.
func (o *Object) WeaponKind() WeaponKind { return WeaponKind(o.Which) }
// ArmorKind returns Which as an armor kind; valid only for KindArmor.
func (o *Object) ArmorKind() ArmorKind { return ArmorKind(o.Which) }
// attachObj is list.c attach(): push item onto the front of a list. // attachObj is list.c attach(): push item onto the front of a list.
func attachObj(list *[]*Object, item *Object) { func attachObj(list *[]*Object, item *Object) {
*list = append([]*Object{item}, *list...) *list = append([]*Object{item}, *list...)

View File

@@ -15,7 +15,7 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
} }
// Check for and deal with scare monster scrolls // Check for and deal with scare monster scrolls
if obj.Type == Scroll && obj.Which == ScrollScareMonster && obj.Flags.Has(WasFound) { if obj.Kind == KindScroll && obj.ScrollKind() == ScrollScareMonster && obj.Flags.Has(WasFound) {
detachObj(&g.Level.Objects, obj) detachObj(&g.Level.Objects, obj)
g.mvaddch(p.Pos.Y, p.Pos.X, g.floorCh()) g.mvaddch(p.Pos.Y, p.Pos.X, g.floorCh())
if p.Room.Flags.Has(Gone) { if p.Room.Flags.Has(Gone) {
@@ -39,12 +39,12 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
lp := -1 lp := -1
merged := false merged := false
for i := 0; i < len(p.Pack); i++ { for i := 0; i < len(p.Pack); i++ {
if p.Pack[i].Type != obj.Type { if p.Pack[i].Kind != obj.Kind {
lp = i lp = i
continue continue
} }
// found the group of our type: scan for matching subtype // found the group of our type: scan for matching subtype
for p.Pack[i].Type == obj.Type && p.Pack[i].Which != obj.Which { for p.Pack[i].Kind == obj.Kind && p.Pack[i].Which != obj.Which {
lp = i lp = i
if i+1 >= len(p.Pack) { if i+1 >= len(p.Pack) {
break break
@@ -52,8 +52,8 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
i++ i++
} }
op := p.Pack[i] op := p.Pack[i]
if op.Type == obj.Type && op.Which == obj.Which { if op.Kind == obj.Kind && op.Which == obj.Which {
if IsMult(op.Type) { if op.Kind.MergesInPack() {
if !g.packRoom(fromFloor, obj) { if !g.packRoom(fromFloor, obj) {
return return
} }
@@ -63,7 +63,7 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
merged = true merged = true
} else if obj.Group != 0 { } else if obj.Group != 0 {
lp = i lp = i
for p.Pack[i].Type == obj.Type && for p.Pack[i].Kind == obj.Kind &&
p.Pack[i].Which == obj.Which && p.Pack[i].Which == obj.Which &&
p.Pack[i].Group != obj.Group { p.Pack[i].Group != obj.Group {
lp = i lp = i
@@ -73,7 +73,7 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
i++ i++
} }
op = p.Pack[i] op = p.Pack[i]
if op.Type == obj.Type && op.Which == obj.Which && if op.Kind == obj.Kind && op.Which == obj.Which &&
op.Group == obj.Group { op.Group == obj.Group {
op.Count += obj.Count op.Count += obj.Count
p.Inpack-- p.Inpack--
@@ -111,7 +111,7 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
} }
} }
if obj.Type == Amulet { if obj.Kind == KindAmulet {
g.HasAmulet = true g.HasAmulet = true
} }
// Notify the user // Notify the user
@@ -193,12 +193,14 @@ func (g *RogueGame) packChar() byte {
// inventory lists what is in the pack; returns true if there is something // inventory lists what is in the pack; returns true if there is something
// of the given type (pack.c inventory). // of the given type (pack.c inventory).
func (g *RogueGame) inventory(list []*Object, typ int) bool { func (g *RogueGame) inventory(list []*Object, kind ObjectKind) bool {
g.NObjs = 0 g.NObjs = 0
for _, item := range list { for _, item := range list {
if typ != 0 && typ != int(item.Type) && if kind != KindNone && kind != item.Kind &&
!(typ == Callable && item.Type != Food && item.Type != Amulet) && !(kind == KindCallable && item.Kind != KindFood &&
!(typ == RorS && (item.Type == Ring || item.Type == Stick)) { item.Kind != KindAmulet) &&
!(kind == KindRingOrStick &&
(item.Kind == KindRing || item.Kind == KindWand)) {
continue continue
} }
g.NObjs++ g.NObjs++
@@ -213,13 +215,13 @@ func (g *RogueGame) inventory(list []*Object, typ int) bool {
} }
if g.NObjs == 0 { if g.NObjs == 0 {
if g.Options.Terse { if g.Options.Terse {
if typ == 0 { if kind == KindNone {
g.msg("empty handed") g.msg("empty handed")
} else { } else {
g.msg("nothing appropriate") g.msg("nothing appropriate")
} }
} else { } else {
if typ == 0 { if kind == KindNone {
g.msg("you are empty handed") g.msg("you are empty handed")
} else { } else {
g.msg("you don't have anything appropriate") g.msg("you don't have anything appropriate")
@@ -294,7 +296,7 @@ func (g *RogueGame) pickyInven() {
} }
// getItem picks something out of a pack for a purpose (pack.c get_item). // getItem picks something out of a pack for a purpose (pack.c get_item).
func (g *RogueGame) getItem(purpose string, typ int) *Object { func (g *RogueGame) getItem(purpose string, kind ObjectKind) *Object {
p := &g.Player p := &g.Player
if len(p.Pack) == 0 { if len(p.Pack) == 0 {
g.msg("you aren't carrying anything") g.msg("you aren't carrying anything")
@@ -328,7 +330,7 @@ func (g *RogueGame) getItem(purpose string, typ int) *Object {
g.NObjs = 1 // normal case: person types one char g.NObjs = 1 // normal case: person types one char
if ch == '*' { if ch == '*' {
g.Msgs.Mpos = 0 g.Msgs.Mpos = 0
if !g.inventory(p.Pack, typ) { if !g.inventory(p.Pack, kind) {
g.After = false g.After = false
return nil return nil
} }

View File

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

View File

@@ -7,12 +7,12 @@ import "fmt"
// ringOn puts a ring on a hand (rings.c ring_on). // ringOn puts a ring on a hand (rings.c ring_on).
func (g *RogueGame) ringOn() { func (g *RogueGame) ringOn() {
p := &g.Player p := &g.Player
obj := g.getItem("put on", int(Ring)) obj := g.getItem("put on", KindRing)
// Make certain that it is something that we want to wear // Make certain that it is something that we want to wear
if obj == nil { if obj == nil {
return return
} }
if obj.Type != Ring { if obj.Kind != KindRing {
if !g.Options.Terse { if !g.Options.Terse {
g.msg("it would be difficult to wrap that around a finger") g.msg("it would be difficult to wrap that around a finger")
} else { } else {
@@ -47,7 +47,7 @@ func (g *RogueGame) ringOn() {
p.CurRing[ring] = obj p.CurRing[ring] = obj
// Calculate the effect it has on the poor guy. // Calculate the effect it has on the poor guy.
switch obj.Which { switch obj.RingKind() {
case RingAddStrength: case RingAddStrength:
g.chgStr(obj.Arm) g.chgStr(obj.Arm)
case RingSeeInvisible: case RingSeeInvisible:
@@ -147,7 +147,7 @@ func (g *RogueGame) ringEat(hand int) int {
if ring == nil { if ring == nil {
return 0 return 0
} }
eat := ringUses[ring.Which] eat := ringUses[ring.RingKind()]
if eat < 0 { if eat < 0 {
if g.rnd(-eat) == 0 { if g.rnd(-eat) == 0 {
eat = 1 eat = 1
@@ -155,7 +155,7 @@ func (g *RogueGame) ringEat(hand int) int {
eat = 0 eat = 0
} }
} }
if ring.Which == RingSlowDigestion { if ring.RingKind() == RingSlowDigestion {
eat = -eat eat = -eat
} }
return eat return eat
@@ -166,7 +166,7 @@ func ringNum(g *RogueGame, obj *Object) string {
if !obj.Flags.Has(Known) { if !obj.Flags.Has(Known) {
return "" return ""
} }
switch obj.Which { switch obj.RingKind() {
case RingProtection, RingAddStrength, RingIncreaseDamage, RingDexterity: case RingProtection, RingAddStrength, RingIncreaseDamage, RingDexterity:
return fmt.Sprintf(" [%s]", num(obj.Arm, 0, Ring)) return fmt.Sprintf(" [%s]", num(obj.Arm, 0, Ring))
} }

View File

@@ -115,37 +115,37 @@ func (g *RogueGame) totalWinner() {
for _, obj := range p.Pack { for _, obj := range p.Pack {
worth := 0 worth := 0
it := &g.Items it := &g.Items
switch obj.Type { switch obj.Kind {
case Food: case KindFood:
worth = 2 * obj.Count worth = 2 * obj.Count
case Weapon: case KindWeapon:
worth = it.Weapons[obj.Which].Worth worth = it.Weapons[obj.Which].Worth
worth *= 3*(obj.HPlus+obj.DPlus) + obj.Count worth *= 3*(obj.HPlus+obj.DPlus) + obj.Count
obj.Flags.Set(Known) obj.Flags.Set(Known)
case Armor: case KindArmor:
worth = it.Armors[obj.Which].Worth worth = it.Armors[obj.Which].Worth
worth += (9 - obj.Arm) * 100 worth += (9 - obj.Arm) * 100
worth += 10 * (aClass[obj.Which] - obj.Arm) worth += 10 * (aClass[obj.Which] - obj.Arm)
obj.Flags.Set(Known) obj.Flags.Set(Known)
case Scroll: case KindScroll:
op := &it.Scrolls[obj.Which] op := &it.Scrolls[obj.Which]
worth = op.Worth * obj.Count worth = op.Worth * obj.Count
if !op.Know { if !op.Know {
worth /= 2 worth /= 2
} }
op.Know = true op.Know = true
case Potion: case KindPotion:
op := &it.Potions[obj.Which] op := &it.Potions[obj.Which]
worth = op.Worth * obj.Count worth = op.Worth * obj.Count
if !op.Know { if !op.Know {
worth /= 2 worth /= 2
} }
op.Know = true op.Know = true
case Ring: case KindRing:
op := &it.Rings[obj.Which] op := &it.Rings[obj.Which]
worth = op.Worth worth = op.Worth
if obj.Which == RingAddStrength || obj.Which == RingIncreaseDamage || if obj.RingKind() == RingAddStrength || obj.RingKind() == RingIncreaseDamage ||
obj.Which == RingProtection || obj.Which == RingDexterity { obj.RingKind() == RingProtection || obj.RingKind() == RingDexterity {
if obj.Arm > 0 { if obj.Arm > 0 {
worth += obj.Arm * 100 worth += obj.Arm * 100
} else { } else {
@@ -157,7 +157,7 @@ func (g *RogueGame) totalWinner() {
} }
obj.Flags.Set(Known) obj.Flags.Set(Known)
op.Know = true op.Know = true
case Stick: case KindWand:
op := &it.Sticks[obj.Which] op := &it.Sticks[obj.Which]
worth = op.Worth worth = op.Worth
worth += 20 * obj.Charges() worth += 20 * obj.Charges()
@@ -166,7 +166,7 @@ func (g *RogueGame) totalWinner() {
} }
obj.Flags.Set(Known) obj.Flags.Set(Known)
op.Know = true op.Know = true
case Amulet: case KindAmulet:
worth = 1000 worth = 1000
} }
if worth < 0 { if worth < 0 {

View File

@@ -94,7 +94,7 @@ func (g *RogueGame) doRooms() {
g.Level.SetChar(rp.Gold.Y, rp.Gold.X, Gold) g.Level.SetChar(rp.Gold.Y, rp.Gold.X, Gold)
gold.Flags = Stackable gold.Flags = Stackable
gold.Group = goldGrp gold.Group = goldGrp
gold.Type = Gold gold.Kind = KindGold
attachObj(&g.Level.Objects, gold) attachObj(&g.Level.Objects, gold)
} }
// Put the monster in // Put the monster in

View File

@@ -11,6 +11,11 @@ import (
// what state.c's rs_fix_thing did: pointers that alias other structures // what state.c's rs_fix_thing did: pointers that alias other structures
// (equipment, chase targets, room membership) are encoded as indices. // (equipment, chase targets, room membership) are encoded as indices.
// saveFormatVersion identifies the snapshot layout; it changes whenever a
// field rename or retype would make gob silently mis-decode an older
// save ("go2": Object.Type became Kind ObjectKind).
const saveFormatVersion = Release + "-go2"
// destRef encodes a monster's chase target (state.c rs_write_thing's // destRef encodes a monster's chase target (state.c rs_write_thing's
// (kind, index) pairs). // (kind, index) pairs).
type destRef struct { type destRef struct {
@@ -165,7 +170,7 @@ func (g *RogueGame) packIdx(obj *Object) int {
func (g *RogueGame) snapshot() *SaveState { func (g *RogueGame) snapshot() *SaveState {
p := &g.Player p := &g.Player
st := &SaveState{ st := &SaveState{
Version: Release, Version: saveFormatVersion,
Seed: g.Rng.Seed, Seed: g.Rng.Seed,
Dnum: g.Dnum, Dnum: g.Dnum,
Whoami: g.Whoami, Whoami: g.Whoami,
@@ -530,7 +535,7 @@ func Restore(path string, cfg Config) (*RogueGame, error) {
if err := gob.NewDecoder(f).Decode(&st); err != nil { if err := gob.NewDecoder(f).Decode(&st); err != nil {
return nil, fmt.Errorf("%s: corrupt or incompatible save file: %w", path, err) return nil, fmt.Errorf("%s: corrupt or incompatible save file: %w", path, err)
} }
if st.Version != Release { if st.Version != saveFormatVersion {
return nil, fmt.Errorf("sorry, saved game is out of date") return nil, fmt.Errorf("sorry, saved game is out of date")
} }

View File

@@ -83,7 +83,7 @@ func TestSaveRestoreRoundTrip(t *testing.T) {
len(h.Player.Pack)) len(h.Player.Pack))
found := false found := false
for i, o := range h.Player.Pack { for i, o := range h.Player.Pack {
t.Logf(" pack[%d]=%p type=%c which=%d", i, o, o.Type, o.Which) t.Logf(" pack[%d]=%p type=%v which=%d", i, o, o.Kind, o.Which)
if o == h.Player.CurWeapon { if o == h.Player.CurWeapon {
found = true found = true
} }

View File

@@ -2,25 +2,25 @@ package game
// scrolls.c — read a scroll and let it happen. // scrolls.c — read a scroll and let it happen.
// idType maps identify scrolls to the type they identify (scrolls.c // idType maps identify scrolls to the kind of item they identify
// static id_type). // (scrolls.c static id_type).
var idType = [ScrollIdentifyRingOrStick + 1]int{ var idType = [ScrollIdentifyRingOrStick + 1]ObjectKind{
ScrollIdentifyPotion: int(Potion), ScrollIdentifyPotion: KindPotion,
ScrollIdentifyScroll: int(Scroll), ScrollIdentifyScroll: KindScroll,
ScrollIdentifyWeapon: int(Weapon), ScrollIdentifyWeapon: KindWeapon,
ScrollIdentifyArmor: int(Armor), ScrollIdentifyArmor: KindArmor,
ScrollIdentifyRingOrStick: RorS, ScrollIdentifyRingOrStick: KindRingOrStick,
} }
// readScroll reads a scroll from the pack and does the appropriate thing // readScroll reads a scroll from the pack and does the appropriate thing
// (scrolls.c read_scroll). // (scrolls.c read_scroll).
func (g *RogueGame) readScroll() { func (g *RogueGame) readScroll() {
p := &g.Player p := &g.Player
obj := g.getItem("read", int(Scroll)) obj := g.getItem("read", KindScroll)
if obj == nil { if obj == nil {
return return
} }
if obj.Type != Scroll { if obj.Kind != KindScroll {
if !g.Options.Terse { if !g.Options.Terse {
g.msg("there is nothing on it to read") g.msg("there is nothing on it to read")
} else { } else {
@@ -35,7 +35,7 @@ func (g *RogueGame) readScroll() {
// Get rid of the thing // Get rid of the thing
g.leavePack(obj, false, false) g.leavePack(obj, false, false)
switch obj.Which { switch obj.ScrollKind() {
case ScrollMonsterConfusion: case ScrollMonsterConfusion:
// Scroll of monster confusion. Give him that power. // Scroll of monster confusion. Give him that power.
p.Flags.Set(CanConfuse) p.Flags.Set(CanConfuse)
@@ -99,7 +99,7 @@ func (g *RogueGame) readScroll() {
// Or anything else nasty // Or anything else nasty
if ch := g.Level.VisibleChar(y, x); stepOk(ch) { if ch := g.Level.VisibleChar(y, x); stepOk(ch) {
if ch == Scroll { if ch == Scroll {
if fo := g.findObj(y, x); fo != nil && fo.Which == ScrollScareMonster { if fo := g.findObj(y, x); fo != nil && fo.ScrollKind() == ScrollScareMonster {
continue continue
} }
} }
@@ -119,7 +119,7 @@ func (g *RogueGame) readScroll() {
// Identify, let him figure something out // Identify, let him figure something out
g.Items.Scrolls[obj.Which].Know = true g.Items.Scrolls[obj.Which].Know = true
g.msg("this scroll is an %s scroll", g.Items.Scrolls[obj.Which].Name) g.msg("this scroll is an %s scroll", g.Items.Scrolls[obj.Which].Name)
g.whatis(true, idType[obj.Which]) g.whatis(true, idType[obj.ScrollKind()])
case ScrollMagicMapping: case ScrollMagicMapping:
// Scroll of magic mapping. // Scroll of magic mapping.
g.Items.Scrolls[ScrollMagicMapping].Know = true g.Items.Scrolls[ScrollMagicMapping].Know = true
@@ -192,7 +192,7 @@ func (g *RogueGame) readScroll() {
found := false found := false
g.scr.Hw.Clear() g.scr.Hw.Clear()
for _, fo := range g.Level.Objects { for _, fo := range g.Level.Objects {
if fo.Type == Food { if fo.Kind == KindFood {
found = true found = true
g.scr.Hw.MvAddCh(fo.Pos.Y, fo.Pos.X, Food) g.scr.Hw.MvAddCh(fo.Pos.Y, fo.Pos.X, Food)
} }
@@ -211,7 +211,7 @@ func (g *RogueGame) readScroll() {
g.Items.Scrolls[ScrollTeleportation].Know = true g.Items.Scrolls[ScrollTeleportation].Know = true
} }
case ScrollEnchantWeapon: case ScrollEnchantWeapon:
if p.CurWeapon == nil || p.CurWeapon.Type != Weapon { if p.CurWeapon == nil || p.CurWeapon.Kind != KindWeapon {
g.msg("you feel a strange sense of loss") g.msg("you feel a strange sense of loss")
} else { } else {
p.CurWeapon.Flags.Clear(Cursed) p.CurWeapon.Flags.Clear(Cursed)

View File

@@ -7,11 +7,11 @@ import "fmt"
// doZap performs a zap with a wand (sticks.c do_zap). // doZap performs a zap with a wand (sticks.c do_zap).
func (g *RogueGame) doZap() { func (g *RogueGame) doZap() {
p := &g.Player p := &g.Player
obj := g.getItem("zap with", int(Stick)) obj := g.getItem("zap with", KindWand)
if obj == nil { if obj == nil {
return return
} }
if obj.Type != Stick { if obj.Kind != KindWand {
g.After = false g.After = false
g.msg("you can't zap with that!") g.msg("you can't zap with that!")
return return
@@ -20,7 +20,7 @@ func (g *RogueGame) doZap() {
g.msg("nothing happens") g.msg("nothing happens")
return return
} }
switch obj.Which { switch obj.WandKind() {
case WandLight: case WandLight:
// Reddy Kilowatt wand. Light up the room // Reddy Kilowatt wand. Light up the room
g.Items.Sticks[WandLight].Know = true g.Items.Sticks[WandLight].Know = true
@@ -57,7 +57,7 @@ func (g *RogueGame) doZap() {
if monster == 'F' { if monster == 'F' {
p.Flags.Clear(Held) p.Flags.Clear(Held)
} }
switch obj.Which { switch obj.WandKind() {
case WandInvisibility: case WandInvisibility:
tp.Flags.Set(Invisible) tp.Flags.Set(Invisible)
if g.cansee(y, x) { if g.cansee(y, x) {
@@ -91,7 +91,7 @@ func (g *RogueGame) doZap() {
} }
case WandTeleportAway, WandTeleportTo: case WandTeleportAway, WandTeleportTo:
var newPos Coord var newPos Coord
if obj.Which == WandTeleportAway { if obj.WandKind() == WandTeleportAway {
for { for {
newPos, _ = g.findFloor(nil, 0, true) newPos, _ = g.findFloor(nil, 0, true)
if newPos != p.Pos { if newPos != p.Pos {
@@ -110,13 +110,13 @@ func (g *RogueGame) doZap() {
case WandMagicMissile: case WandMagicMissile:
g.Items.Sticks[WandMagicMissile].Know = true g.Items.Sticks[WandMagicMissile].Know = true
bolt := newObject() bolt := newObject()
bolt.Type = '*' bolt.Kind = KindGold // C set o_type='*': draws a '*' and is not a weapon
bolt.HurlDmg = "1x4" bolt.HurlDmg = "1x4"
bolt.HPlus = 100 bolt.HPlus = 100
bolt.DPlus = 1 bolt.DPlus = 1
bolt.Flags = Missile bolt.Flags = Missile
if p.CurWeapon != nil { if p.CurWeapon != nil {
bolt.Launch = p.CurWeapon.Which bolt.Launch = WeaponKind(p.CurWeapon.Which)
} }
g.doMotion(bolt, g.Delta.Y, g.Delta.X) g.doMotion(bolt, g.Delta.Y, g.Delta.X)
if tp := g.Level.MonsterAt(bolt.Pos.Y, bolt.Pos.X); tp != nil && if tp := g.Level.MonsterAt(bolt.Pos.Y, bolt.Pos.X); tp != nil &&
@@ -135,7 +135,7 @@ func (g *RogueGame) doZap() {
x += g.Delta.X x += g.Delta.X
} }
if tp := g.Level.MonsterAt(y, x); tp != nil { if tp := g.Level.MonsterAt(y, x); tp != nil {
if obj.Which == WandHasteMonster { if obj.WandKind() == WandHasteMonster {
if tp.On(Slowed) { if tp.On(Slowed) {
tp.Flags.Clear(Slowed) tp.Flags.Clear(Slowed)
} else { } else {
@@ -155,7 +155,7 @@ func (g *RogueGame) doZap() {
} }
case WandLightning, WandFire, WandCold: case WandLightning, WandFire, WandCold:
var name string var name string
switch obj.Which { switch obj.WandKind() {
case WandLightning: case WandLightning:
name = "bolt" name = "bolt"
case WandFire: case WandFire:
@@ -211,8 +211,8 @@ func (g *RogueGame) fireBolt(start Coord, dir *Coord, name string) {
fromHero := start == p.Pos fromHero := start == p.Pos
bolt := newObject() bolt := newObject()
bolt.Type = Weapon bolt.Kind = KindWeapon
bolt.Which = WeaponFlame bolt.Which = int(WeaponFlame)
bolt.HurlDmg = "6x6" bolt.HurlDmg = "6x6"
bolt.HPlus = 100 bolt.HPlus = 100
bolt.DPlus = 0 bolt.DPlus = 0
@@ -328,7 +328,7 @@ func (g *RogueGame) fixStick(cur *Object) {
} }
cur.HurlDmg = "1x1" cur.HurlDmg = "1x1"
switch cur.Which { switch cur.WandKind() {
case WandLight: case WandLight:
cur.SetCharges(g.rnd(10) + 10) cur.SetCharges(g.rnd(10) + 10)
default: default:

View File

@@ -33,7 +33,7 @@ func TestInitProbsCumulative(t *testing.T) {
if last != 100 { if last != 100 {
t.Errorf("cumulative potion probability ends at %d, want 100", last) t.Errorf("cumulative potion probability ends at %d, want 100", last)
} }
for i := 1; i < NumPotionTypes; i++ { for i := PotionKind(1); i < NumPotionTypes; i++ {
if g.Items.Potions[i].Prob < g.Items.Potions[i-1].Prob { if g.Items.Potions[i].Prob < g.Items.Potions[i-1].Prob {
t.Errorf("potion probs not nondecreasing at %d", i) t.Errorf("potion probs not nondecreasing at %d", i)
} }

View File

@@ -13,14 +13,14 @@ func (g *RogueGame) invName(obj *Object, drop bool) string {
var pb strings.Builder var pb strings.Builder
which := obj.Which which := obj.Which
it := &g.Items it := &g.Items
switch obj.Type { switch obj.Kind {
case Potion: case KindPotion:
g.nameit(&pb, obj, "potion", it.PotColors[which], &it.Potions[which], nullstr) g.nameit(&pb, obj, "potion", it.PotColors[which], &it.Potions[which], nullstr)
case Ring: case KindRing:
g.nameit(&pb, obj, "ring", it.RingStones[which], &it.Rings[which], ringNum) g.nameit(&pb, obj, "ring", it.RingStones[which], &it.Rings[which], ringNum)
case Stick: case KindWand:
g.nameit(&pb, obj, it.WandType[which], it.WandMade[which], &it.Sticks[which], chargeStr) g.nameit(&pb, obj, it.WandType[which], it.WandMade[which], &it.Sticks[which], chargeStr)
case Scroll: case KindScroll:
if obj.Count == 1 { if obj.Count == 1 {
pb.WriteString("A scroll ") pb.WriteString("A scroll ")
} else { } else {
@@ -34,7 +34,7 @@ func (g *RogueGame) invName(obj *Object, drop bool) string {
} else { } else {
fmt.Fprintf(&pb, "titled '%s'", it.ScrNames[which]) fmt.Fprintf(&pb, "titled '%s'", it.ScrNames[which])
} }
case Food: case KindFood:
if which == 1 { if which == 1 {
if obj.Count == 1 { if obj.Count == 1 {
fmt.Fprintf(&pb, "A%s %s", vowelstr(g.Fruit), g.Fruit) fmt.Fprintf(&pb, "A%s %s", vowelstr(g.Fruit), g.Fruit)
@@ -48,7 +48,7 @@ func (g *RogueGame) invName(obj *Object, drop bool) string {
fmt.Fprintf(&pb, "%d rations of food", obj.Count) fmt.Fprintf(&pb, "%d rations of food", obj.Count)
} }
} }
case Weapon: case KindWeapon:
sp := it.Weapons[which].Name sp := it.Weapons[which].Name
if obj.Count > 1 { if obj.Count > 1 {
fmt.Fprintf(&pb, "%d ", obj.Count) fmt.Fprintf(&pb, "%d ", obj.Count)
@@ -66,7 +66,7 @@ func (g *RogueGame) invName(obj *Object, drop bool) string {
if obj.Label != "" { if obj.Label != "" {
fmt.Fprintf(&pb, " called %s", obj.Label) fmt.Fprintf(&pb, " called %s", obj.Label)
} }
case Armor: case KindArmor:
sp := it.Armors[which].Name sp := it.Armors[which].Name
if obj.Flags.Has(Known) { if obj.Flags.Has(Known) {
fmt.Fprintf(&pb, "%s %s [", num(aClass[which]-obj.Arm, 0, Armor), sp) fmt.Fprintf(&pb, "%s %s [", num(aClass[which]-obj.Arm, 0, Armor), sp)
@@ -80,9 +80,9 @@ func (g *RogueGame) invName(obj *Object, drop bool) string {
if obj.Label != "" { if obj.Label != "" {
fmt.Fprintf(&pb, " called %s", obj.Label) fmt.Fprintf(&pb, " called %s", obj.Label)
} }
case Amulet: case KindAmulet:
pb.WriteString("The Amulet of Yendor") pb.WriteString("The Amulet of Yendor")
case Gold: case KindGold:
fmt.Fprintf(&pb, "%d Gold pieces", obj.GoldVal()) fmt.Fprintf(&pb, "%d Gold pieces", obj.GoldVal())
} }
@@ -121,20 +121,20 @@ func (g *RogueGame) dropIt() {
g.msg("there is something there already") g.msg("there is something there already")
return return
} }
obj := g.getItem("drop", 0) obj := g.getItem("drop", KindNone)
if obj == nil { if obj == nil {
return return
} }
if !g.dropCheck(obj) { if !g.dropCheck(obj) {
return return
} }
obj = g.leavePack(obj, true, !IsMult(obj.Type)) obj = g.leavePack(obj, true, !obj.Kind.MergesInPack())
// Link it into the level object list // Link it into the level object list
attachObj(&g.Level.Objects, obj) attachObj(&g.Level.Objects, obj)
g.Level.SetChar(p.Pos.Y, p.Pos.X, obj.Type) g.Level.SetChar(p.Pos.Y, p.Pos.X, obj.Kind.Glyph())
g.Level.FlagsAt(p.Pos.Y, p.Pos.X).Set(FDropped) g.Level.FlagsAt(p.Pos.Y, p.Pos.X).Set(FDropped)
obj.Pos = p.Pos obj.Pos = p.Pos
if obj.Type == Amulet { if obj.Kind == KindAmulet {
g.HasAmulet = false g.HasAmulet = false
} }
g.msg("dropped %s", g.invName(obj, true)) g.msg("dropped %s", g.invName(obj, true))
@@ -166,7 +166,7 @@ func (g *RogueGame) dropCheck(obj *Object) bool {
hand = Left hand = Left
} }
p.CurRing[hand] = nil p.CurRing[hand] = nil
switch obj.Which { switch obj.RingKind() {
case RingAddStrength: case RingAddStrength:
g.chgStr(-obj.Arm) g.chgStr(-obj.Arm)
case RingSeeInvisible: case RingSeeInvisible:
@@ -195,13 +195,13 @@ func (g *RogueGame) newThing() *Object {
} }
switch kind { switch kind {
case 0: case 0:
cur.Type = Potion cur.Kind = KindPotion
cur.Which = pickOne(g, g.Items.Potions[:]) cur.Which = pickOne(g, g.Items.Potions[:])
case 1: case 1:
cur.Type = Scroll cur.Kind = KindScroll
cur.Which = pickOne(g, g.Items.Scrolls[:]) cur.Which = pickOne(g, g.Items.Scrolls[:])
case 2: case 2:
cur.Type = Food cur.Kind = KindFood
g.Player.NoFood = 0 g.Player.NoFood = 0
if g.rnd(10) != 0 { if g.rnd(10) != 0 {
cur.Which = 0 cur.Which = 0
@@ -209,7 +209,7 @@ func (g *RogueGame) newThing() *Object {
cur.Which = 1 cur.Which = 1
} }
case 3: case 3:
g.initWeapon(cur, pickOne(g, g.Items.Weapons[:NumWeaponTypes])) g.initWeapon(cur, WeaponKind(pickOne(g, g.Items.Weapons[:NumWeaponTypes])))
if r := g.rnd(100); r < 10 { if r := g.rnd(100); r < 10 {
cur.Flags.Set(Cursed) cur.Flags.Set(Cursed)
cur.HPlus -= g.rnd(3) + 1 cur.HPlus -= g.rnd(3) + 1
@@ -217,7 +217,7 @@ func (g *RogueGame) newThing() *Object {
cur.HPlus += g.rnd(3) + 1 cur.HPlus += g.rnd(3) + 1
} }
case 4: case 4:
cur.Type = Armor cur.Kind = KindArmor
cur.Which = pickOne(g, g.Items.Armors[:]) cur.Which = pickOne(g, g.Items.Armors[:])
cur.Arm = aClass[cur.Which] cur.Arm = aClass[cur.Which]
if r := g.rnd(100); r < 20 { if r := g.rnd(100); r < 20 {
@@ -227,9 +227,9 @@ func (g *RogueGame) newThing() *Object {
cur.Arm -= g.rnd(3) + 1 cur.Arm -= g.rnd(3) + 1
} }
case 5: case 5:
cur.Type = Ring cur.Kind = KindRing
cur.Which = pickOne(g, g.Items.Rings[:]) cur.Which = pickOne(g, g.Items.Rings[:])
switch cur.Which { switch cur.RingKind() {
case RingAddStrength, RingProtection, RingDexterity, RingIncreaseDamage: case RingAddStrength, RingProtection, RingDexterity, RingIncreaseDamage:
if cur.Arm = g.rnd(3); cur.Arm == 0 { if cur.Arm = g.rnd(3); cur.Arm == 0 {
cur.Arm = -1 cur.Arm = -1
@@ -239,7 +239,7 @@ func (g *RogueGame) newThing() *Object {
cur.Flags.Set(Cursed) cur.Flags.Set(Cursed)
} }
case 6: case 6:
cur.Type = Stick cur.Kind = KindWand
cur.Which = pickOne(g, g.Items.Sticks[:]) cur.Which = pickOne(g, g.Items.Sticks[:])
g.fixStick(cur) g.fixStick(cur)
} }
@@ -336,7 +336,7 @@ func (g *RogueGame) printDisc(typ byte) {
numFound := 0 numFound := 0
for i := range info { for i := range info {
if info[order[i]].Know || info[order[i]].Guess != "" { if info[order[i]].Know || info[order[i]].Guess != "" {
obj.Type = typ obj.Kind = objectKindForGlyph(typ)
obj.Which = order[i] obj.Which = order[i]
g.addLine("%s", g.invName(&obj, false)) g.addLine("%s", g.invName(&obj, false))
numFound++ numFound++

View File

@@ -62,12 +62,6 @@ const (
Stick byte = '/' Stick byte = '/'
) )
// Pseudo-types for item-selection prompts (rogue.h)
const (
Callable = -1
RorS = -2
)
// Various constants (rogue.h) // Various constants (rogue.h)
const ( const (
HealTime = 30 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) Set(b PlaceFlags) { *f |= b }
func (f *PlaceFlags) Clear(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 ( const (
TrapDoor = 0 TrapDoor TrapKind = 0
TrapArrow = 1 TrapArrow TrapKind = 1
TrapSleep = 2 TrapSleep TrapKind = 2
TrapBear = 3 TrapBear TrapKind = 3
TrapTeleport = 4 TrapTeleport TrapKind = 4
TrapDart = 5 TrapDart TrapKind = 5
TrapRust = 6 TrapRust TrapKind = 6
TrapMystery = 7 TrapMystery TrapKind = 7
NumTrapTypes = 8 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 ( const (
PotionConfusion = iota PotionConfusion PotionKind = iota
PotionLSD PotionLSD
PotionPoison PotionPoison
PotionGainStrength PotionGainStrength
@@ -205,9 +214,20 @@ const (
NumPotionTypes 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 ( const (
ScrollMonsterConfusion = iota ScrollMonsterConfusion ScrollKind = iota
ScrollMagicMapping ScrollMagicMapping
ScrollHoldMonster ScrollHoldMonster
ScrollSleep ScrollSleep
@@ -228,9 +248,20 @@ const (
NumScrollTypes 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 ( const (
WeaponMace = iota WeaponMace WeaponKind = iota
WeaponLongSword WeaponLongSword
WeaponBow WeaponBow
WeaponArrow WeaponArrow
@@ -243,9 +274,20 @@ const (
NumWeaponTypes = WeaponFlame 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 ( const (
ArmorLeather = iota ArmorLeather ArmorKind = iota
ArmorRingMail ArmorRingMail
ArmorStuddedLeather ArmorStuddedLeather
ArmorScaleMail ArmorScaleMail
@@ -256,9 +298,20 @@ const (
NumArmorTypes 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 ( const (
RingProtection = iota RingProtection RingKind = iota
RingAddStrength RingAddStrength
RingSustainStrength RingSustainStrength
RingSearching RingSearching
@@ -275,9 +328,20 @@ const (
NumRingTypes 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 ( const (
WandLight = iota WandLight WandKind = iota
WandInvisibility WandInvisibility
WandLightning WandLightning
WandFire WandFire
@@ -294,6 +358,14 @@ const (
NumWandTypes 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 // Coord is a position on the level (rogue.h coord). A value type: the C
// ce(a,b) macro is plain == here. // ce(a,b) macro is plain == here.
type Coord struct { type Coord struct {
@@ -349,9 +421,6 @@ type Stone struct {
// CTRL maps a letter to its control character, as the C CTRL() macro. // CTRL maps a letter to its control character, as the C CTRL() macro.
func CTRL(c byte) byte { return c & 0o37 } 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). // distance returns the squared distance between two points (chase.c dist).
func distance(y1, x1, y2, x2 int) int { func distance(y1, x1, y2, x2 int) int {
dx := x2 - x1 dx := x2 - x1

View File

@@ -4,12 +4,12 @@ import "fmt"
// weapons.c — functions for dealing with problems brought about by weapons. // weapons.c — functions for dealing with problems brought about by weapons.
const noWeapon = -1 const noWeapon WeaponKind = -1
// missile fires a missile in a given direction (weapons.c missile). // missile fires a missile in a given direction (weapons.c missile).
func (g *RogueGame) missile(ydelta, xdelta int) { func (g *RogueGame) missile(ydelta, xdelta int) {
// Get which thing we are hurling // Get which thing we are hurling
obj := g.getItem("throw", int(Weapon)) obj := g.getItem("throw", KindWeapon)
if obj == nil { if obj == nil {
return return
} }
@@ -48,7 +48,7 @@ func (g *RogueGame) doMotion(obj *Object, ydelta, xdelta int) {
if stepOk(ch) && ch != Door { if stepOk(ch) && ch != Door {
// It hasn't hit anything yet, so display it if it's alright. // It hasn't hit anything yet, so display it if it's alright.
if g.cansee(obj.Pos.Y, obj.Pos.X) && !g.Options.Terse { if g.cansee(obj.Pos.Y, obj.Pos.X) && !g.Options.Terse {
g.mvaddch(obj.Pos.Y, obj.Pos.X, obj.Type) g.mvaddch(obj.Pos.Y, obj.Pos.X, obj.Kind.Glyph())
g.refresh() g.refresh()
} }
continue continue
@@ -61,13 +61,13 @@ func (g *RogueGame) doMotion(obj *Object, ydelta, xdelta int) {
func (g *RogueGame) fall(obj *Object, pr bool) { func (g *RogueGame) fall(obj *Object, pr bool) {
if fpos, ok := g.fallpos(obj.Pos); ok { if fpos, ok := g.fallpos(obj.Pos); ok {
pp := g.Level.At(fpos.Y, fpos.X) pp := g.Level.At(fpos.Y, fpos.X)
pp.Ch = obj.Type pp.Ch = obj.Kind.Glyph()
obj.Pos = fpos obj.Pos = fpos
if g.cansee(fpos.Y, fpos.X) { if g.cansee(fpos.Y, fpos.X) {
if pp.Monst != nil { if pp.Monst != nil {
pp.Monst.OldCh = obj.Type pp.Monst.OldCh = obj.Kind.Glyph()
} else { } else {
g.mvaddch(fpos.Y, fpos.X, obj.Type) g.mvaddch(fpos.Y, fpos.X, obj.Kind.Glyph())
} }
} }
attachObj(&g.Level.Objects, obj) attachObj(&g.Level.Objects, obj)
@@ -98,12 +98,12 @@ func (g *RogueGame) wield() {
return return
} }
p.CurWeapon = oweapon p.CurWeapon = oweapon
obj := g.getItem("wield", int(Weapon)) obj := g.getItem("wield", KindWeapon)
if obj == nil { if obj == nil {
g.After = false g.After = false
return return
} }
if obj.Type == Armor { if obj.Kind == KindArmor {
g.msg("you can't wield armor") g.msg("you can't wield armor")
g.After = false g.After = false
return return
@@ -123,9 +123,9 @@ func (g *RogueGame) wield() {
// initWeaps is the weapons.c init_dam[] table. // initWeaps is the weapons.c init_dam[] table.
var initWeaps = [NumWeaponTypes]struct { var initWeaps = [NumWeaponTypes]struct {
dam string // damage when wielded dam string // damage when wielded
hrl string // damage when thrown hrl string // damage when thrown
launch int // launching weapon launch WeaponKind // launching weapon
flags ObjFlags flags ObjFlags
}{ }{
{"2x4", "1x3", noWeapon, 0}, // WeaponMace {"2x4", "1x3", noWeapon, 0}, // WeaponMace
@@ -140,10 +140,10 @@ var initWeaps = [NumWeaponTypes]struct {
} }
// initWeapon sets up a new weapon (weapons.c init_weapon). // initWeapon sets up a new weapon (weapons.c init_weapon).
func (g *RogueGame) initWeapon(weap *Object, which int) { func (g *RogueGame) initWeapon(weap *Object, which WeaponKind) {
iwp := &initWeaps[which] iwp := &initWeaps[which]
weap.Type = Weapon weap.Kind = KindWeapon
weap.Which = which weap.Which = int(which)
weap.Damage = iwp.dam weap.Damage = iwp.dam
weap.HurlDmg = iwp.hrl weap.HurlDmg = iwp.hrl
weap.Launch = iwp.launch weap.Launch = iwp.launch

View File

@@ -9,9 +9,9 @@ package game
func (g *RogueGame) createObj() { func (g *RogueGame) createObj() {
obj := newObject() obj := newObject()
g.msg("type of item: ") g.msg("type of item: ")
obj.Type = g.readchar() obj.Kind = objectKindForGlyph(g.readchar())
g.Msgs.Mpos = 0 g.Msgs.Mpos = 0
g.msg("which %c do you want? (0-f)", obj.Type) g.msg("which %c do you want? (0-f)", obj.Kind.Glyph())
ch := g.readchar() ch := g.readchar()
if isDigit(ch) { if isDigit(ch) {
obj.Which = int(ch - '0') obj.Which = int(ch - '0')
@@ -22,15 +22,15 @@ func (g *RogueGame) createObj() {
obj.Count = 1 obj.Count = 1
g.Msgs.Mpos = 0 g.Msgs.Mpos = 0
switch { switch {
case obj.Type == Weapon || obj.Type == Armor: case obj.Kind == KindWeapon || obj.Kind == KindArmor:
g.msg("blessing? (+,-,n)") g.msg("blessing? (+,-,n)")
bless := g.readchar() bless := g.readchar()
g.Msgs.Mpos = 0 g.Msgs.Mpos = 0
if bless == '-' { if bless == '-' {
obj.Flags.Set(Cursed) obj.Flags.Set(Cursed)
} }
if obj.Type == Weapon { if obj.Kind == KindWeapon {
g.initWeapon(obj, obj.Which) g.initWeapon(obj, WeaponKind(obj.Which))
if bless == '-' { if bless == '-' {
obj.HPlus -= g.rnd(3) + 1 obj.HPlus -= g.rnd(3) + 1
} }
@@ -46,8 +46,8 @@ func (g *RogueGame) createObj() {
obj.Arm -= g.rnd(3) + 1 obj.Arm -= g.rnd(3) + 1
} }
} }
case obj.Type == Ring: case obj.Kind == KindRing:
switch obj.Which { switch obj.RingKind() {
case RingProtection, RingAddStrength, RingDexterity, RingIncreaseDamage: case RingProtection, RingAddStrength, RingDexterity, RingIncreaseDamage:
g.msg("blessing? (+,-,n)") g.msg("blessing? (+,-,n)")
bless := g.readchar() bless := g.readchar()
@@ -61,9 +61,9 @@ func (g *RogueGame) createObj() {
case RingAggravateMonsters, RingTeleportation: case RingAggravateMonsters, RingTeleportation:
obj.Flags.Set(Cursed) obj.Flags.Set(Cursed)
} }
case obj.Type == Stick: case obj.Kind == KindWand:
g.fixStick(obj) g.fixStick(obj)
case obj.Type == Gold: case obj.Kind == KindGold:
g.msg("how much?") g.msg("how much?")
buf := "" buf := ""
if g.getStr(&buf, g.scr.Std) == Norm { if g.getStr(&buf, g.scr.Std) == Norm {
@@ -93,7 +93,7 @@ func (g *RogueGame) showMap() {
} }
// whatis identifies what a certain object is (wizard.c whatis). // whatis identifies what a certain object is (wizard.c whatis).
func (g *RogueGame) whatis(insist bool, typ int) { func (g *RogueGame) whatis(insist bool, kind ObjectKind) {
p := &g.Player p := &g.Player
if len(p.Pack) == 0 { if len(p.Pack) == 0 {
g.msg("you don't have anything in your pack to identify") g.msg("you don't have anything in your pack to identify")
@@ -102,7 +102,7 @@ func (g *RogueGame) whatis(insist bool, typ int) {
var obj *Object var obj *Object
for { for {
obj = g.getItem("identify", typ) obj = g.getItem("identify", kind)
if !insist { if !insist {
break break
} }
@@ -111,9 +111,10 @@ func (g *RogueGame) whatis(insist bool, typ int) {
} }
if obj == nil { if obj == nil {
g.msg("you must identify something") g.msg("you must identify something")
} else if typ != 0 && int(obj.Type) != typ && } else if kind != KindNone && obj.Kind != kind &&
!(typ == RorS && (obj.Type == Ring || obj.Type == Stick)) { !(kind == KindRingOrStick &&
g.msg("you must identify a %s", typeName(typ)) (obj.Kind == KindRing || obj.Kind == KindWand)) {
g.msg("you must identify a %s", kind)
} else { } else {
break break
} }
@@ -123,16 +124,16 @@ func (g *RogueGame) whatis(insist bool, typ int) {
return return
} }
switch obj.Type { switch obj.Kind {
case Scroll: case KindScroll:
setKnow(obj, g.Items.Scrolls[:]) setKnow(obj, g.Items.Scrolls[:])
case Potion: case KindPotion:
setKnow(obj, g.Items.Potions[:]) setKnow(obj, g.Items.Potions[:])
case Stick: case KindWand:
setKnow(obj, g.Items.Sticks[:]) setKnow(obj, g.Items.Sticks[:])
case Weapon, Armor: case KindWeapon, KindArmor:
obj.Flags.Set(Known) obj.Flags.Set(Known)
case Ring: case KindRing:
setKnow(obj, g.Items.Rings[:]) setKnow(obj, g.Items.Rings[:])
} }
g.msg("%s", g.invName(obj, false)) g.msg("%s", g.invName(obj, false))
@@ -146,30 +147,8 @@ func setKnow(obj *Object, info []ObjInfo) {
info[obj.Which].Guess = "" info[obj.Which].Guess = ""
} }
// typeNameTable is the wizard.c type_name static tlist. // The C type_name()/tlist table is gone: ObjectKind.String() carries the
var typeNameTable = []struct { // same vocabulary.
ch int
desc string
}{
{int(Potion), "potion"},
{int(Scroll), "scroll"},
{int(Food), "food"},
{RorS, "ring, wand or staff"},
{int(Ring), "ring"},
{int(Stick), "wand or staff"},
{int(Weapon), "weapon"},
{int(Armor), "suit of armor"},
}
// typeName returns the name of an object type (wizard.c type_name).
func typeName(typ int) string {
for _, hp := range typeNameTable {
if typ == hp.ch {
return hp.desc
}
}
return ""
}
// teleport bamfs the hero someplace else (wizard.c teleport). // teleport bamfs the hero someplace else (wizard.c teleport).
func (g *RogueGame) teleport() { func (g *RogueGame) teleport() {