Merge refactor/typed-kinds (refactor step 2)

This commit is contained in:
2026-07-06 22:00:43 +02:00
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).
func (g *RogueGame) wear() {
p := &g.Player
obj := g.getItem("wear", int(Armor))
obj := g.getItem("wear", KindArmor)
if obj == nil {
return
}
@@ -18,7 +18,7 @@ func (g *RogueGame) wear() {
g.After = false
return
}
if obj.Type != Armor {
if obj.Kind != KindArmor {
g.msg("you can't wear that")
return
}

View File

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

View File

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

View File

@@ -40,12 +40,12 @@ type Player struct {
func (c *Creature) On(f CreatureFlags) bool { return c.Flags.Has(f) }
// IsRing is the C ISRING(hand, ring) macro.
func (p *Player) IsRing(hand, ring int) bool {
return p.CurRing[hand] != nil && p.CurRing[hand].Which == ring
func (p *Player) IsRing(hand int, ring RingKind) bool {
return p.CurRing[hand] != nil && p.CurRing[hand].RingKind() == ring
}
// 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)
}

View File

@@ -194,7 +194,7 @@ func (g *RogueGame) comeDown(int) {
// undo the things
for _, tp := range g.Level.Objects {
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) {
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}

View File

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

View File

@@ -13,13 +13,13 @@ func (g *RogueGame) initPlayer() {
p.FoodLeft = HungerTime
// Give him some food
obj := newObject()
obj.Type = Food
obj.Kind = KindFood
obj.Count = 1
g.addPack(obj, true)
// And his suit of armor
obj = newObject()
obj.Type = Armor
obj.Which = ArmorRingMail
obj.Kind = KindArmor
obj.Which = int(ArmorRingMail)
obj.Arm = aClass[ArmorRingMail] - 1
obj.Flags.Set(Known)
obj.Count = 1
@@ -51,7 +51,7 @@ func (g *RogueGame) initPlayer() {
// (init.c init_colors).
func (g *RogueGame) initColors() {
used := make([]bool, len(rainbow))
for i := 0; i < NumPotionTypes; i++ {
for i := PotionKind(0); i < NumPotionTypes; i++ {
var j int
for {
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).
func (g *RogueGame) initNames() {
for i := 0; i < NumScrollTypes; i++ {
for i := ScrollKind(0); i < NumScrollTypes; i++ {
var cp strings.Builder
nwords := g.rnd(3) + 2
for ; nwords > 0; nwords-- {
@@ -88,7 +88,7 @@ func (g *RogueGame) initNames() {
// (init.c init_stones).
func (g *RogueGame) initStones() {
used := make([]bool, len(stoneTable))
for i := 0; i < NumRingTypes; i++ {
for i := RingKind(0); i < NumRingTypes; i++ {
var j int
for {
j = g.rnd(len(stoneTable))
@@ -107,7 +107,7 @@ func (g *RogueGame) initStones() {
func (g *RogueGame) initMaterials() {
used := make([]bool, len(woods))
metused := make([]bool, len(metals))
for i := 0; i < NumWandTypes; i++ {
for i := WandKind(0); i < NumWandTypes; i++ {
var str string
for {
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).
func (g *RogueGame) eat() {
obj := g.getItem("eat", int(Food))
obj := g.getItem("eat", KindFood)
if obj == nil {
return
}
if obj.Type != Food {
if obj.Kind != KindFood {
if !g.Options.Terse {
g.msg("ugh, you would get ill if you ate that")
} 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).
func (g *RogueGame) beTrapped(tc Coord) int {
func (g *RogueGame) beTrapped(tc Coord) TrapKind {
p := &g.Player
if p.On(Levitating) {
return TrapRust // anything that's not a door or teleport
@@ -201,7 +201,7 @@ func (g *RogueGame) beTrapped(tc Coord) int {
g.Count = 0
pp := g.Level.At(tc.Y, tc.X)
pp.Ch = Trap
tr := int(pp.Flags & FTrapMask)
tr := TrapKind(pp.Flags & FTrapMask)
pp.Flags.Set(FSeen)
switch tr {
case TrapDoor:
@@ -311,7 +311,7 @@ func (g *RogueGame) rndmove(who *Creature) Coord {
break
}
}
if found != nil && found.Which == ScrollScareMonster {
if found != nil && found.ScrollKind() == ScrollScareMonster {
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
// aren't wearing a magic ring (move.c rust_armor).
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 {
return
}

View File

@@ -103,7 +103,7 @@ func (g *RogueGame) putThings() {
attachObj(&g.Level.Objects, obj)
// Put it somewhere
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
@@ -114,7 +114,7 @@ func (g *RogueGame) putThings() {
obj.Damage = "0x0"
obj.HurlDmg = "0x0"
obj.Arm = 11
obj.Type = Amulet
obj.Kind = KindAmulet
// Put it somewhere
obj.Pos, _ = g.findFloor(nil, 0, false)
g.Level.SetChar(obj.Pos.Y, obj.Pos.X, Amulet)
@@ -134,7 +134,7 @@ func (g *RogueGame) treasRoom() {
tp := g.newThing()
tp.Pos = mp
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

View File

@@ -75,9 +75,10 @@ func TestNewLevelInvariants(t *testing.T) {
// share cells only with monsters standing on them).
for _, obj := range g.Level.Objects {
ch := g.Level.Char(obj.Pos.Y, obj.Pos.X)
if ch != obj.Type && g.Level.MonsterAt(obj.Pos.Y, obj.Pos.X) == nil {
t.Errorf("seed %d: object %q at (%d,%d) but map shows %q",
seed, obj.Type, obj.Pos.Y, obj.Pos.X, ch)
if ch != obj.Kind.Glyph() &&
g.Level.MonsterAt(obj.Pos.Y, obj.Pos.X) == nil {
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",
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)
}
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)
}
}

View File

@@ -1,20 +1,111 @@
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
// floor or ride in a pack.
type Object struct {
Type byte // what kind of object it is (Potion, Scroll, Weapon, ...)
Pos Coord // where it lives on the screen
Text string // what it says if you read it
Launch int // what you need to launch it (weapon index, -1 none)
PackCh byte // what character it is in the pack
Damage string // damage if used like sword
HurlDmg string // damage if thrown
Count int // count for plural objects
Which int // which object of a type it is
HPlus int // plusses to hit
DPlus int // plusses to damage
Arm int // armor protection — overloaded as in C (see Charges/GoldVal)
Kind ObjectKind // what kind of object it is (o_type)
Pos Coord // where it lives on the screen
Text string // what it says if you read it
Launch WeaponKind // what you need to launch it (noWeapon if none)
PackCh byte // what character it is in the pack
Damage string // damage if used like sword
HurlDmg string // damage if thrown
Count int // count for plural objects
Which int // which object of a type it is (index for the Kind's table)
HPlus int // plusses to hit
DPlus int // plusses to damage
Arm int // armor protection — overloaded as in C (see Charges/GoldVal)
Flags ObjFlags
Group int // group number for this 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
// same non-zero defaults the C code relies on.
func newObject() *Object {
return &Object{Launch: -1}
return &Object{Launch: noWeapon}
}
// 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.
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.
func attachObj(list *[]*Object, item *Object) {
*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
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)
g.mvaddch(p.Pos.Y, p.Pos.X, g.floorCh())
if p.Room.Flags.Has(Gone) {
@@ -39,12 +39,12 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
lp := -1
merged := false
for i := 0; i < len(p.Pack); i++ {
if p.Pack[i].Type != obj.Type {
if p.Pack[i].Kind != obj.Kind {
lp = i
continue
}
// 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
if i+1 >= len(p.Pack) {
break
@@ -52,8 +52,8 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
i++
}
op := p.Pack[i]
if op.Type == obj.Type && op.Which == obj.Which {
if IsMult(op.Type) {
if op.Kind == obj.Kind && op.Which == obj.Which {
if op.Kind.MergesInPack() {
if !g.packRoom(fromFloor, obj) {
return
}
@@ -63,7 +63,7 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
merged = true
} else if obj.Group != 0 {
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].Group != obj.Group {
lp = i
@@ -73,7 +73,7 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
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.Count += obj.Count
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
}
// 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
// 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
for _, item := range list {
if typ != 0 && typ != int(item.Type) &&
!(typ == Callable && item.Type != Food && item.Type != Amulet) &&
!(typ == RorS && (item.Type == Ring || item.Type == Stick)) {
if kind != KindNone && kind != item.Kind &&
!(kind == KindCallable && item.Kind != KindFood &&
item.Kind != KindAmulet) &&
!(kind == KindRingOrStick &&
(item.Kind == KindRing || item.Kind == KindWand)) {
continue
}
g.NObjs++
@@ -213,13 +215,13 @@ func (g *RogueGame) inventory(list []*Object, typ int) bool {
}
if g.NObjs == 0 {
if g.Options.Terse {
if typ == 0 {
if kind == KindNone {
g.msg("empty handed")
} else {
g.msg("nothing appropriate")
}
} else {
if typ == 0 {
if kind == KindNone {
g.msg("you are empty handed")
} else {
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).
func (g *RogueGame) getItem(purpose string, typ int) *Object {
func (g *RogueGame) getItem(purpose string, kind ObjectKind) *Object {
p := &g.Player
if len(p.Pack) == 0 {
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
if ch == '*' {
g.Msgs.Mpos = 0
if !g.inventory(p.Pack, typ) {
if !g.inventory(p.Pack, kind) {
g.After = false
return nil
}

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

View File

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

View File

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

View File

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

View File

@@ -11,6 +11,11 @@ import (
// what state.c's rs_fix_thing did: pointers that alias other structures
// (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
// (kind, index) pairs).
type destRef struct {
@@ -165,7 +170,7 @@ func (g *RogueGame) packIdx(obj *Object) int {
func (g *RogueGame) snapshot() *SaveState {
p := &g.Player
st := &SaveState{
Version: Release,
Version: saveFormatVersion,
Seed: g.Rng.Seed,
Dnum: g.Dnum,
Whoami: g.Whoami,
@@ -530,7 +535,7 @@ func Restore(path string, cfg Config) (*RogueGame, error) {
if err := gob.NewDecoder(f).Decode(&st); err != nil {
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")
}

View File

@@ -83,7 +83,7 @@ func TestSaveRestoreRoundTrip(t *testing.T) {
len(h.Player.Pack))
found := false
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 {
found = true
}

View File

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

View File

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

View File

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

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

View File

@@ -4,12 +4,12 @@ import "fmt"
// 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).
func (g *RogueGame) missile(ydelta, xdelta int) {
// Get which thing we are hurling
obj := g.getItem("throw", int(Weapon))
obj := g.getItem("throw", KindWeapon)
if obj == nil {
return
}
@@ -48,7 +48,7 @@ func (g *RogueGame) doMotion(obj *Object, ydelta, xdelta int) {
if stepOk(ch) && ch != Door {
// 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 {
g.mvaddch(obj.Pos.Y, obj.Pos.X, obj.Type)
g.mvaddch(obj.Pos.Y, obj.Pos.X, obj.Kind.Glyph())
g.refresh()
}
continue
@@ -61,13 +61,13 @@ func (g *RogueGame) doMotion(obj *Object, ydelta, xdelta int) {
func (g *RogueGame) fall(obj *Object, pr bool) {
if fpos, ok := g.fallpos(obj.Pos); ok {
pp := g.Level.At(fpos.Y, fpos.X)
pp.Ch = obj.Type
pp.Ch = obj.Kind.Glyph()
obj.Pos = fpos
if g.cansee(fpos.Y, fpos.X) {
if pp.Monst != nil {
pp.Monst.OldCh = obj.Type
pp.Monst.OldCh = obj.Kind.Glyph()
} else {
g.mvaddch(fpos.Y, fpos.X, obj.Type)
g.mvaddch(fpos.Y, fpos.X, obj.Kind.Glyph())
}
}
attachObj(&g.Level.Objects, obj)
@@ -98,12 +98,12 @@ func (g *RogueGame) wield() {
return
}
p.CurWeapon = oweapon
obj := g.getItem("wield", int(Weapon))
obj := g.getItem("wield", KindWeapon)
if obj == nil {
g.After = false
return
}
if obj.Type == Armor {
if obj.Kind == KindArmor {
g.msg("you can't wield armor")
g.After = false
return
@@ -123,9 +123,9 @@ func (g *RogueGame) wield() {
// initWeaps is the weapons.c init_dam[] table.
var initWeaps = [NumWeaponTypes]struct {
dam string // damage when wielded
hrl string // damage when thrown
launch int // launching weapon
dam string // damage when wielded
hrl string // damage when thrown
launch WeaponKind // launching weapon
flags ObjFlags
}{
{"2x4", "1x3", noWeapon, 0}, // WeaponMace
@@ -140,10 +140,10 @@ var initWeaps = [NumWeaponTypes]struct {
}
// 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]
weap.Type = Weapon
weap.Which = which
weap.Kind = KindWeapon
weap.Which = int(which)
weap.Damage = iwp.dam
weap.HurlDmg = iwp.hrl
weap.Launch = iwp.launch

View File

@@ -9,9 +9,9 @@ package game
func (g *RogueGame) createObj() {
obj := newObject()
g.msg("type of item: ")
obj.Type = g.readchar()
obj.Kind = objectKindForGlyph(g.readchar())
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()
if isDigit(ch) {
obj.Which = int(ch - '0')
@@ -22,15 +22,15 @@ func (g *RogueGame) createObj() {
obj.Count = 1
g.Msgs.Mpos = 0
switch {
case obj.Type == Weapon || obj.Type == Armor:
case obj.Kind == KindWeapon || obj.Kind == KindArmor:
g.msg("blessing? (+,-,n)")
bless := g.readchar()
g.Msgs.Mpos = 0
if bless == '-' {
obj.Flags.Set(Cursed)
}
if obj.Type == Weapon {
g.initWeapon(obj, obj.Which)
if obj.Kind == KindWeapon {
g.initWeapon(obj, WeaponKind(obj.Which))
if bless == '-' {
obj.HPlus -= g.rnd(3) + 1
}
@@ -46,8 +46,8 @@ func (g *RogueGame) createObj() {
obj.Arm -= g.rnd(3) + 1
}
}
case obj.Type == Ring:
switch obj.Which {
case obj.Kind == KindRing:
switch obj.RingKind() {
case RingProtection, RingAddStrength, RingDexterity, RingIncreaseDamage:
g.msg("blessing? (+,-,n)")
bless := g.readchar()
@@ -61,9 +61,9 @@ func (g *RogueGame) createObj() {
case RingAggravateMonsters, RingTeleportation:
obj.Flags.Set(Cursed)
}
case obj.Type == Stick:
case obj.Kind == KindWand:
g.fixStick(obj)
case obj.Type == Gold:
case obj.Kind == KindGold:
g.msg("how much?")
buf := ""
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).
func (g *RogueGame) whatis(insist bool, typ int) {
func (g *RogueGame) whatis(insist bool, kind ObjectKind) {
p := &g.Player
if len(p.Pack) == 0 {
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
for {
obj = g.getItem("identify", typ)
obj = g.getItem("identify", kind)
if !insist {
break
}
@@ -111,9 +111,10 @@ func (g *RogueGame) whatis(insist bool, typ int) {
}
if obj == nil {
g.msg("you must identify something")
} else if typ != 0 && int(obj.Type) != typ &&
!(typ == RorS && (obj.Type == Ring || obj.Type == Stick)) {
g.msg("you must identify a %s", typeName(typ))
} else if kind != KindNone && obj.Kind != kind &&
!(kind == KindRingOrStick &&
(obj.Kind == KindRing || obj.Kind == KindWand)) {
g.msg("you must identify a %s", kind)
} else {
break
}
@@ -123,16 +124,16 @@ func (g *RogueGame) whatis(insist bool, typ int) {
return
}
switch obj.Type {
case Scroll:
switch obj.Kind {
case KindScroll:
setKnow(obj, g.Items.Scrolls[:])
case Potion:
case KindPotion:
setKnow(obj, g.Items.Potions[:])
case Stick:
case KindWand:
setKnow(obj, g.Items.Sticks[:])
case Weapon, Armor:
case KindWeapon, KindArmor:
obj.Flags.Set(Known)
case Ring:
case KindRing:
setKnow(obj, g.Items.Rings[:])
}
g.msg("%s", g.invName(obj, false))
@@ -146,30 +147,8 @@ func setKnow(obj *Object, info []ObjInfo) {
info[obj.Which].Guess = ""
}
// typeNameTable is the wizard.c type_name static tlist.
var typeNameTable = []struct {
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 ""
}
// The C type_name()/tlist table is gone: ObjectKind.String() carries the
// same vocabulary.
// teleport bamfs the hero someplace else (wizard.c teleport).
func (g *RogueGame) teleport() {