gochecknoglobals: all 37 package-level tables consolidated into the gameData struct (game/tables.go), built by newGameData() and carried on RogueGame as g.data (set in NewGame and Restore). ObjectKind Glyph()/objectKindForGlyph are now switches; the table-reading subtype Stringer methods are gone; isMagic is a RogueGame method. goconst: repeated words named (potionName/scrollName/ringName/goldName in object.go, wandName/staffName in sticks.go, ripWall in tables.go). exhaustive, testpackage: disabled in .golangci.yml with sneak's approval (2026-07-07). Also reverts misspell's silent corruption of the "ther" scroll-name syllable (it had become "there", changing generated scroll names vs C). Remaining red: cyclop/gocognit/nestif until refactor step 7; mnd awaits a ruling. TODO.md rotated; MEMORY.md lint notes updated.
858 lines
15 KiB
Go
858 lines
15 KiB
Go
package game
|
|
|
|
// command.c — read and execute the user commands.
|
|
|
|
// command processes one player command, with its BEFORE/AFTER daemon
|
|
// bracketing (command.c command).
|
|
func (g *RogueGame) command() {
|
|
p := &g.Player
|
|
|
|
ntimes := 1 // number of player moves
|
|
if p.On(Hasted) {
|
|
ntimes++
|
|
}
|
|
// Let the daemons start up
|
|
g.DoDaemons(Before)
|
|
g.DoFuses(Before)
|
|
|
|
for ; ntimes > 0; ntimes-- {
|
|
g.Again = false
|
|
if g.HasHit {
|
|
g.endmsg()
|
|
g.HasHit = false
|
|
}
|
|
// these are illegal things for the player to be, so if any are
|
|
// set, someone's been poking in memory
|
|
if p.On(Slowed | Greedy | Invisible | Regenerates | Targeted) {
|
|
panic("player flags corrupted")
|
|
}
|
|
|
|
g.look(true)
|
|
|
|
if !g.Running {
|
|
g.DoorStop = false
|
|
}
|
|
|
|
g.status()
|
|
g.LastScore = p.Purse
|
|
g.move(p.Pos.Y, p.Pos.X)
|
|
|
|
if (!g.Running && g.Count == 0) || !g.Options.Jump {
|
|
g.refresh() // draw screen
|
|
}
|
|
|
|
g.Take = 0
|
|
g.After = true
|
|
// Read command or continue run
|
|
if g.Wizard {
|
|
g.NoScore = true
|
|
}
|
|
|
|
var ch byte
|
|
|
|
if g.NoCommand == 0 {
|
|
switch {
|
|
case g.Running || g.ToDeath:
|
|
ch = g.RunCh
|
|
case g.Count != 0:
|
|
ch = g.countCh
|
|
default:
|
|
ch = g.readchar()
|
|
|
|
g.MoveOn = false
|
|
if g.Msgs.Mpos != 0 { // erase message if its there
|
|
g.msg("")
|
|
}
|
|
}
|
|
} else {
|
|
ch = '.'
|
|
}
|
|
|
|
if g.NoCommand != 0 {
|
|
if g.NoCommand--; g.NoCommand == 0 {
|
|
p.Flags.Set(Awake)
|
|
g.msg("you can move again")
|
|
}
|
|
} else {
|
|
// check for prefixes
|
|
g.newCount = false
|
|
if isDigit(ch) {
|
|
g.Count = 0
|
|
|
|
g.newCount = true
|
|
for isDigit(ch) {
|
|
g.Count = min(g.Count*10+int(ch-'0'), 255)
|
|
|
|
ch = g.readchar()
|
|
}
|
|
|
|
g.countCh = ch
|
|
// turn off count for commands which don't make sense
|
|
// to repeat
|
|
switch ch {
|
|
case CTRL('B'), CTRL('H'), CTRL('J'), CTRL('K'),
|
|
CTRL('L'), CTRL('N'), CTRL('U'), CTRL('Y'),
|
|
'.', 'a', 'b', 'h', 'j', 'k', 'l', 'm', 'n', 'q',
|
|
'r', 's', 't', 'u', 'y', 'z', 'B', 'C', 'H', 'I',
|
|
'J', 'K', 'L', 'N', 'U', 'Y',
|
|
CTRL('D'), CTRL('A'):
|
|
default:
|
|
g.Count = 0
|
|
}
|
|
}
|
|
// execute a command
|
|
if g.Count != 0 && !g.Running {
|
|
g.Count--
|
|
}
|
|
|
|
if ch != 'a' && ch != Escape &&
|
|
!g.Running && g.Count == 0 && !g.ToDeath {
|
|
g.LLastComm = g.LastComm
|
|
g.LLastDir = g.LastDir
|
|
g.LLastPick = g.LastPick
|
|
g.LastComm = ch
|
|
g.LastDir = 0
|
|
g.LastPick = nil
|
|
}
|
|
|
|
g.dispatch(ch)
|
|
// turn off flags if no longer needed
|
|
if !g.Running {
|
|
g.DoorStop = false
|
|
}
|
|
}
|
|
// If he ran into something to take, let him pick it up.
|
|
if g.Take != 0 {
|
|
g.pickUp(g.Take)
|
|
}
|
|
|
|
if !g.Running {
|
|
g.DoorStop = false
|
|
}
|
|
|
|
if !g.After {
|
|
ntimes++
|
|
}
|
|
}
|
|
|
|
g.DoDaemons(After)
|
|
g.DoFuses(After)
|
|
|
|
if p.IsRing(Left, RingSearching) {
|
|
g.search()
|
|
} else if p.IsRing(Left, RingTeleportation) && g.rnd(50) == 0 {
|
|
g.teleport()
|
|
}
|
|
|
|
if p.IsRing(Right, RingSearching) {
|
|
g.search()
|
|
} else if p.IsRing(Right, RingTeleportation) && g.rnd(50) == 0 {
|
|
g.teleport()
|
|
}
|
|
}
|
|
|
|
// dispatch runs one command character (the big switch in command.c,
|
|
// including its `goto over` re-dispatch).
|
|
func (g *RogueGame) dispatch(ch byte) {
|
|
p := &g.Player
|
|
|
|
over:
|
|
switch ch {
|
|
case ',':
|
|
var found *Object
|
|
|
|
for _, obj := range g.Level.Objects {
|
|
if obj.Pos.Y == p.Pos.Y && obj.Pos.X == p.Pos.X {
|
|
found = obj
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
if found != nil {
|
|
if !g.levitCheck() {
|
|
g.pickUp(found.Kind.Glyph())
|
|
}
|
|
} else {
|
|
if !g.Options.Terse {
|
|
g.addmsgf("there is ")
|
|
}
|
|
|
|
g.addmsgf("nothing here")
|
|
|
|
if !g.Options.Terse {
|
|
g.addmsgf(" to pick up")
|
|
}
|
|
|
|
g.endmsg()
|
|
}
|
|
case '!':
|
|
g.shell()
|
|
case 'h':
|
|
g.doMove(0, -1)
|
|
case 'j':
|
|
g.doMove(1, 0)
|
|
case 'k':
|
|
g.doMove(-1, 0)
|
|
case 'l':
|
|
g.doMove(0, 1)
|
|
case 'y':
|
|
g.doMove(-1, -1)
|
|
case 'u':
|
|
g.doMove(-1, 1)
|
|
case 'b':
|
|
g.doMove(1, -1)
|
|
case 'n':
|
|
g.doMove(1, 1)
|
|
case 'H':
|
|
g.doRun('h')
|
|
case 'J':
|
|
g.doRun('j')
|
|
case 'K':
|
|
g.doRun('k')
|
|
case 'L':
|
|
g.doRun('l')
|
|
case 'Y':
|
|
g.doRun('y')
|
|
case 'U':
|
|
g.doRun('u')
|
|
case 'B':
|
|
g.doRun('b')
|
|
case 'N':
|
|
g.doRun('n')
|
|
case CTRL('H'), CTRL('J'), CTRL('K'), CTRL('L'),
|
|
CTRL('Y'), CTRL('U'), CTRL('B'), CTRL('N'):
|
|
if !p.On(Blind) {
|
|
g.DoorStop = true
|
|
g.Firstmove = true
|
|
}
|
|
|
|
if g.Count != 0 && !g.newCount {
|
|
ch = g.direction
|
|
} else {
|
|
ch += 'A' - CTRL('A')
|
|
g.direction = ch
|
|
}
|
|
|
|
goto over
|
|
case 'F', 'f':
|
|
if ch == 'F' {
|
|
g.Kamikaze = true
|
|
}
|
|
|
|
if !g.getDir() {
|
|
g.After = false
|
|
|
|
break
|
|
}
|
|
|
|
g.Delta.Y += p.Pos.Y
|
|
g.Delta.X += p.Pos.X
|
|
|
|
mp := g.Level.MonsterAt(g.Delta.Y, g.Delta.X)
|
|
if mp == nil || (!g.seeMonst(mp) && !p.On(SenseMonsters)) {
|
|
if !g.Options.Terse {
|
|
g.addmsgf("I see ")
|
|
}
|
|
|
|
g.msg("no monster there")
|
|
g.After = false
|
|
} else if g.diagOk(p.Pos, g.Delta) {
|
|
g.ToDeath = true
|
|
g.MaxHit = 0
|
|
|
|
mp.Flags.Set(Targeted)
|
|
|
|
g.RunCh = g.DirCh
|
|
ch = g.DirCh
|
|
|
|
goto over
|
|
}
|
|
case 't':
|
|
if !g.getDir() {
|
|
g.After = false
|
|
} else {
|
|
g.missile(g.Delta.Y, g.Delta.X)
|
|
}
|
|
case 'a':
|
|
if g.LastComm == 0 {
|
|
g.msg("you haven't typed a command yet")
|
|
g.After = false
|
|
} else {
|
|
ch = g.LastComm
|
|
g.Again = true
|
|
|
|
goto over
|
|
}
|
|
case 'q':
|
|
g.quaff()
|
|
case 'Q':
|
|
g.After = false
|
|
g.QComm = true
|
|
g.quit(0)
|
|
g.QComm = false
|
|
case 'i':
|
|
g.After = false
|
|
g.inventory(p.Pack, 0)
|
|
case 'I':
|
|
g.After = false
|
|
g.pickyInven()
|
|
case 'd':
|
|
g.dropIt()
|
|
case 'r':
|
|
g.readScroll()
|
|
case 'e':
|
|
g.eat()
|
|
case 'w':
|
|
g.wield()
|
|
case 'W':
|
|
g.wear()
|
|
case 'T':
|
|
g.takeOff()
|
|
case 'P':
|
|
g.ringOn()
|
|
case 'R':
|
|
g.ringOff()
|
|
case 'o':
|
|
g.option()
|
|
g.After = false
|
|
case 'c':
|
|
g.call()
|
|
g.After = false
|
|
case '>':
|
|
g.After = false
|
|
g.dLevel()
|
|
case '<':
|
|
g.After = false
|
|
g.uLevel()
|
|
case '?':
|
|
g.After = false
|
|
g.help()
|
|
case '/':
|
|
g.After = false
|
|
g.identify()
|
|
case 's':
|
|
g.search()
|
|
case 'z':
|
|
if g.getDir() {
|
|
g.doZap()
|
|
} else {
|
|
g.After = false
|
|
}
|
|
case 'D':
|
|
g.After = false
|
|
g.discovered()
|
|
case CTRL('P'):
|
|
g.After = false
|
|
g.msg("%s", g.Msgs.Huh)
|
|
case CTRL('R'):
|
|
g.After = false
|
|
g.refresh()
|
|
case 'v':
|
|
g.After = false
|
|
g.msg("version %s. (mctesq was here)", Release)
|
|
case 'S':
|
|
g.After = false
|
|
g.saveGame()
|
|
case '.':
|
|
// rest command
|
|
case ' ':
|
|
g.After = false // "legal" illegal command
|
|
case '^':
|
|
g.After = false
|
|
if g.getDir() {
|
|
g.Delta.Y += p.Pos.Y
|
|
g.Delta.X += p.Pos.X
|
|
|
|
fp := g.Level.FlagsAt(g.Delta.Y, g.Delta.X)
|
|
if !g.Options.Terse {
|
|
g.addmsgf("You have found ")
|
|
}
|
|
|
|
switch {
|
|
case g.Level.Char(g.Delta.Y, g.Delta.X) != Trap:
|
|
g.msg("no trap there")
|
|
case p.On(Hallucinating):
|
|
g.msg("%s", g.data.trName[g.rnd(NumTrapTypes)])
|
|
default:
|
|
g.msg("%s", g.data.trName[*fp&FTrapMask])
|
|
fp.Set(FSeen)
|
|
}
|
|
}
|
|
case Escape: // escape
|
|
g.DoorStop = false
|
|
g.Count = 0
|
|
g.After = false
|
|
g.Again = false
|
|
case 'm':
|
|
g.MoveOn = true
|
|
if !g.getDir() {
|
|
g.After = false
|
|
} else {
|
|
ch = g.DirCh
|
|
g.countCh = g.DirCh
|
|
|
|
goto over
|
|
}
|
|
case ')':
|
|
g.current(p.CurWeapon, "wielding", "")
|
|
case ']':
|
|
g.current(p.CurArmor, "wearing", "")
|
|
case '=':
|
|
g.current(p.CurRing[Left], "wearing",
|
|
g.chooseTerse("(L)", "on left hand"))
|
|
g.current(p.CurRing[Right], "wearing",
|
|
g.chooseTerse("(R)", "on right hand"))
|
|
case '@':
|
|
g.StatMsg = true
|
|
g.status()
|
|
g.StatMsg = false
|
|
g.After = false
|
|
default:
|
|
g.After = false
|
|
if g.Wizard {
|
|
g.wizardCommand(ch)
|
|
} else {
|
|
g.illcom(ch)
|
|
}
|
|
}
|
|
}
|
|
|
|
// wizardCommand handles the MASTER debug commands (command.c).
|
|
func (g *RogueGame) wizardCommand(ch byte) {
|
|
p := &g.Player
|
|
|
|
switch ch {
|
|
case '|':
|
|
g.msg("@ %d,%d", p.Pos.Y, p.Pos.X)
|
|
case 'C':
|
|
g.createObj()
|
|
case '$':
|
|
g.msg("inpack = %d", p.Inpack)
|
|
case CTRL('G'):
|
|
g.inventory(g.Level.Objects, 0)
|
|
case CTRL('W'):
|
|
g.whatis(false, 0)
|
|
case CTRL('D'):
|
|
g.Depth++
|
|
g.NewLevel()
|
|
case CTRL('A'):
|
|
g.Depth--
|
|
g.NewLevel()
|
|
case CTRL('F'):
|
|
g.showMap()
|
|
case CTRL('T'):
|
|
g.teleport()
|
|
case CTRL('E'):
|
|
g.msg("food left: %d", p.FoodLeft)
|
|
case CTRL('C'):
|
|
g.addPass()
|
|
case CTRL('X'):
|
|
g.turnSee(p.On(SenseMonsters))
|
|
case CTRL('~'):
|
|
if item := g.getItem("charge", KindWand); item != nil {
|
|
item.Charges = 10000
|
|
}
|
|
case CTRL('I'):
|
|
for range 9 {
|
|
g.raiseLevel()
|
|
}
|
|
// Give him a sword (+1,+1)
|
|
obj := newObject()
|
|
g.initWeapon(obj, WeaponTwoHandedSword)
|
|
obj.HPlus = 1
|
|
obj.DPlus = 1
|
|
g.addPack(obj, true)
|
|
p.CurWeapon = obj
|
|
// And his suit of armor
|
|
obj = newObject()
|
|
obj.Kind = KindArmor
|
|
obj.Which = int(ArmorPlateMail)
|
|
obj.ArmorClass = -5
|
|
obj.Flags.Set(Known)
|
|
obj.Count = 1
|
|
p.CurArmor = obj
|
|
g.addPack(obj, true)
|
|
case '*':
|
|
g.prList()
|
|
default:
|
|
g.illcom(ch)
|
|
}
|
|
}
|
|
|
|
// illcom reports an illegal command (command.c illcom).
|
|
func (g *RogueGame) illcom(ch byte) {
|
|
g.Msgs.SaveMsg = false
|
|
g.Count = 0
|
|
g.msg("illegal command '%s'", unctrl(ch))
|
|
g.Msgs.SaveMsg = true
|
|
}
|
|
|
|
// search gropes about to find hidden things (command.c search).
|
|
func (g *RogueGame) search() {
|
|
p := &g.Player
|
|
ey := p.Pos.Y + 1
|
|
ex := p.Pos.X + 1
|
|
|
|
probinc := 0
|
|
if p.On(Hallucinating) {
|
|
probinc = 3
|
|
}
|
|
|
|
if p.On(Blind) {
|
|
probinc += 2
|
|
}
|
|
|
|
found := false
|
|
|
|
for y := p.Pos.Y - 1; y <= ey; y++ {
|
|
for x := p.Pos.X - 1; x <= ex; x++ {
|
|
if y == p.Pos.Y && x == p.Pos.X {
|
|
continue
|
|
}
|
|
|
|
fp := g.Level.FlagsAt(y, x)
|
|
if fp.Has(FReal) {
|
|
continue
|
|
}
|
|
|
|
foundone := false
|
|
|
|
switch g.Level.Char(y, x) {
|
|
case '|', '-':
|
|
if g.rnd(5+probinc) != 0 {
|
|
break
|
|
}
|
|
|
|
g.Level.SetChar(y, x, Door)
|
|
g.msg("a secret door")
|
|
|
|
foundone = true
|
|
case Floor:
|
|
if g.rnd(2+probinc) != 0 {
|
|
break
|
|
}
|
|
|
|
g.Level.SetChar(y, x, Trap)
|
|
|
|
if !g.Options.Terse {
|
|
g.addmsgf("you found ")
|
|
}
|
|
|
|
if p.On(Hallucinating) {
|
|
g.msg("%s", g.data.trName[g.rnd(NumTrapTypes)])
|
|
} else {
|
|
g.msg("%s", g.data.trName[*fp&FTrapMask])
|
|
fp.Set(FSeen)
|
|
}
|
|
|
|
foundone = true
|
|
case ' ':
|
|
if g.rnd(3+probinc) != 0 {
|
|
break
|
|
}
|
|
|
|
g.Level.SetChar(y, x, Passage)
|
|
|
|
foundone = true
|
|
}
|
|
|
|
if foundone {
|
|
found = true
|
|
|
|
fp.Set(FReal)
|
|
|
|
g.Count = 0
|
|
g.Running = false
|
|
}
|
|
}
|
|
}
|
|
|
|
if found {
|
|
g.look(false)
|
|
}
|
|
}
|
|
|
|
// help gives single character help, or the whole mess if he wants it
|
|
// (command.c help).
|
|
func (g *RogueGame) help() {
|
|
g.msg("character you want help for (* for all): ")
|
|
helpch := g.readchar()
|
|
g.Msgs.Mpos = 0
|
|
// If it's not a *, print the right help string or an error if he
|
|
// typed a funny character.
|
|
if helpch != '*' {
|
|
g.move(0, 0)
|
|
|
|
for _, strp := range g.data.helpStr {
|
|
if strp.Ch == helpch {
|
|
g.Msgs.LowerMsg = true
|
|
g.msg("%s%s", unctrl(strp.Ch), strp.Desc)
|
|
g.Msgs.LowerMsg = false
|
|
|
|
return
|
|
}
|
|
}
|
|
|
|
g.msg("unknown character '%s'", unctrl(helpch))
|
|
|
|
return
|
|
}
|
|
// Here we print help for everything, then wait before we return to
|
|
// command mode.
|
|
numprint := 0
|
|
|
|
for _, strp := range g.data.helpStr {
|
|
if strp.Print {
|
|
numprint++
|
|
}
|
|
}
|
|
|
|
if numprint&1 == 1 { // round odd numbers up
|
|
numprint++
|
|
}
|
|
|
|
numprint /= 2
|
|
if numprint > NumLines-1 {
|
|
numprint = NumLines - 1
|
|
}
|
|
|
|
hw := g.scr.Hw
|
|
hw.Clear()
|
|
|
|
cnt := 0
|
|
|
|
for _, strp := range g.data.helpStr {
|
|
if !strp.Print {
|
|
continue
|
|
}
|
|
|
|
x := 0
|
|
if cnt >= numprint {
|
|
x = NumCols / 2
|
|
}
|
|
|
|
hw.Move(cnt%numprint, x)
|
|
|
|
if strp.Ch != 0 {
|
|
hw.AddStr(unctrl(strp.Ch))
|
|
}
|
|
|
|
hw.AddStr(strp.Desc)
|
|
|
|
if cnt++; cnt >= numprint*2 {
|
|
break
|
|
}
|
|
}
|
|
|
|
hw.MvAddStr(NumLines-1, 0, "--Press space to continue--")
|
|
g.scr.RefreshWin(hw)
|
|
g.waitFor(' ')
|
|
g.msg("")
|
|
g.refresh()
|
|
}
|
|
|
|
// identify tells the player what a certain thing is (command.c identify).
|
|
func (g *RogueGame) identify() {
|
|
g.msg("what do you want identified? ")
|
|
ch := g.readchar()
|
|
|
|
g.Msgs.Mpos = 0
|
|
if ch == Escape {
|
|
g.msg("")
|
|
|
|
return
|
|
}
|
|
|
|
var str string
|
|
if isUpper(ch) {
|
|
str = g.Monsters[ch-'A'].Name
|
|
} else {
|
|
str = "unknown character"
|
|
|
|
for _, hp := range g.data.identList {
|
|
if hp.Ch == ch {
|
|
str = hp.Desc
|
|
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
g.msg("'%s': %s", unctrl(ch), str)
|
|
}
|
|
|
|
// dLevel: he wants to go down a level (command.c d_level).
|
|
func (g *RogueGame) dLevel() {
|
|
if g.levitCheck() {
|
|
return
|
|
}
|
|
|
|
if g.Level.Char(g.Player.Pos.Y, g.Player.Pos.X) != Stairs {
|
|
g.msg("I see no way down")
|
|
} else {
|
|
g.Depth++
|
|
g.SeenStairs = false
|
|
g.NewLevel()
|
|
}
|
|
}
|
|
|
|
// uLevel: he wants to go up a level (command.c u_level).
|
|
func (g *RogueGame) uLevel() {
|
|
if g.levitCheck() {
|
|
return
|
|
}
|
|
|
|
if g.Level.Char(g.Player.Pos.Y, g.Player.Pos.X) == Stairs {
|
|
if g.HasAmulet {
|
|
g.Depth--
|
|
if g.Depth == 0 {
|
|
g.totalWinner()
|
|
}
|
|
|
|
g.NewLevel()
|
|
g.msg("you feel a wrenching sensation in your gut")
|
|
} else {
|
|
g.msg("your way is magically blocked")
|
|
}
|
|
} else {
|
|
g.msg("I see no way up")
|
|
}
|
|
}
|
|
|
|
// levitCheck checks whether she's levitating, and if she is, prints an
|
|
// appropriate message (command.c levit_check).
|
|
func (g *RogueGame) levitCheck() bool {
|
|
if !g.Player.On(Levitating) {
|
|
return false
|
|
}
|
|
|
|
g.msg("You can't. You're floating off the ground!")
|
|
|
|
return true
|
|
}
|
|
|
|
// call allows a user to call a potion, scroll, or ring something
|
|
// (command.c call).
|
|
func (g *RogueGame) call() {
|
|
obj := g.getItem("call", KindCallable)
|
|
// Make certain that it is something that we want to name
|
|
if obj == nil {
|
|
return
|
|
}
|
|
|
|
var (
|
|
op *ObjInfo
|
|
elsewise string
|
|
know *bool
|
|
guess *string
|
|
)
|
|
|
|
it := &g.Items
|
|
|
|
switch obj.Kind {
|
|
case KindRing:
|
|
op = &it.Rings[obj.Which]
|
|
elsewise = it.RingStones[obj.Which]
|
|
case KindPotion:
|
|
op = &it.Potions[obj.Which]
|
|
elsewise = it.PotColors[obj.Which]
|
|
case KindScroll:
|
|
op = &it.Scrolls[obj.Which]
|
|
elsewise = it.ScrNames[obj.Which]
|
|
case KindWand:
|
|
op = &it.Sticks[obj.Which]
|
|
elsewise = it.WandMade[obj.Which]
|
|
case KindFood:
|
|
g.msg("you can't call that anything")
|
|
|
|
return
|
|
default:
|
|
guess = &obj.Label
|
|
elsewise = obj.Label
|
|
}
|
|
|
|
fromGuess := false
|
|
|
|
if op != nil {
|
|
know = &op.Know
|
|
|
|
guess = &op.Guess
|
|
if *guess != "" {
|
|
elsewise = *guess
|
|
fromGuess = true
|
|
}
|
|
} else {
|
|
fromGuess = elsewise != "" && elsewise == *guess
|
|
}
|
|
|
|
if know != nil && *know {
|
|
g.msg("that has already been identified")
|
|
|
|
return
|
|
}
|
|
|
|
if fromGuess {
|
|
if !g.Options.Terse {
|
|
g.addmsgf("Was ")
|
|
}
|
|
|
|
g.msg("called \"%s\"", elsewise)
|
|
}
|
|
|
|
g.msg("%s", g.chooseTerse("call it: ", "what do you want to call it? "))
|
|
|
|
buf := elsewise
|
|
if g.getStr(&buf, g.scr.Std) == Norm {
|
|
*guess = buf
|
|
}
|
|
}
|
|
|
|
// current prints the current weapon/armor (command.c current).
|
|
func (g *RogueGame) current(cur *Object, how, where string) {
|
|
g.After = false
|
|
if cur != nil {
|
|
if !g.Options.Terse {
|
|
g.addmsgf("you are %s (", how)
|
|
}
|
|
|
|
g.InvDescribe = false
|
|
g.addmsgf("%c) %s", cur.PackCh, g.invName(cur, true))
|
|
|
|
g.InvDescribe = true
|
|
if where != "" {
|
|
g.addmsgf(" %s", where)
|
|
}
|
|
|
|
g.endmsg()
|
|
} else {
|
|
if !g.Options.Terse {
|
|
g.addmsgf("you are ")
|
|
}
|
|
|
|
g.addmsgf("%s nothing", how)
|
|
|
|
if where != "" {
|
|
g.addmsgf(" %s", where)
|
|
}
|
|
|
|
g.endmsg()
|
|
}
|
|
}
|
|
|
|
// shell lets them escape for a while (main.c shell). The terminal decides
|
|
// how to actually suspend; headless terminals just decline.
|
|
func (g *RogueGame) shell() {
|
|
g.After = false
|
|
if se, ok := g.scr.term.(interface{ ShellEscape() }); ok {
|
|
g.InShell = true
|
|
|
|
se.ShellEscape()
|
|
|
|
g.InShell = false
|
|
g.refresh()
|
|
} else {
|
|
g.msg("shell escape is not available")
|
|
}
|
|
}
|