Rename movement/world methods to idiomatic Go; remove all gotos

Refactor step 4. Renames (C breadcrumbs kept in doc comments):
doMove→moveHero, beTrapped→springTrap, rndmove→randomStep,
doRooms→digRooms, doPassages→digPassages, doMaze→digMaze,
chgStr→changeStrength, doRun→startRun, moveStuff→finishMove,
turnref→turnRefresh, moveMonst→moveMonster, doChase→chaseStep,
setOldch→setOldChar, cansee→canSee, roomin→roomIn, runto→runTo,
conn→connectRooms, putpass→putPassage, passnum→numberPassages,
numpass→numberPassage, rndPos→randomPos, rndRoom→randomRoom,
treasRoom→treasureRoom, accntMaze→accountMaze.

All goto/label flows are gone: moveHero uses a retry loop with the
PASSGO corner logic extracted into passageTurn; dispatch re-dispatches
via a loop; chaseStep re-checks via a loop; saveGame uses a labeled
prompt loop. Control flow and RNG call order are unchanged; suite
green.
This commit is contained in:
2026-07-07 02:29:06 +02:00
parent 65a1cd68b8
commit 6850c87ae7
21 changed files with 653 additions and 624 deletions

View File

@@ -13,12 +13,12 @@ func (g *RogueGame) runners(int) {
origPos := tp.Pos
wastarget := tp.On(Targeted)
if g.moveMonst(tp) == -1 {
if g.moveMonster(tp) == -1 {
continue
}
if tp.On(Flying) && distCp(g.Player.Pos, tp.Pos) >= 3 {
if g.moveMonst(tp) == -1 {
if g.moveMonster(tp) == -1 {
continue
}
}
@@ -37,17 +37,17 @@ func (g *RogueGame) runners(int) {
}
}
// moveMonst executes a single turn of running for a monster (chase.c
// moveMonster executes a single turn of running for a monster (chase.c
// move_monst). Returns -1 if the monster died or left the level.
func (g *RogueGame) moveMonst(tp *Monster) int {
func (g *RogueGame) moveMonster(tp *Monster) int {
if !tp.On(Slowed) || tp.Turn {
if g.doChase(tp) == -1 {
if g.chaseStep(tp) == -1 {
return -1
}
}
if tp.On(Hasted) {
if g.doChase(tp) == -1 {
if g.chaseStep(tp) == -1 {
return -1
}
}
@@ -62,8 +62,8 @@ func (g *RogueGame) moveMonst(tp *Monster) int {
func (g *RogueGame) relocate(th *Monster, newLoc Coord) {
if newLoc != th.Pos {
g.mvaddch(th.Pos.Y, th.Pos.X, th.OldCh)
th.Room = g.roomin(newLoc)
g.setOldch(th, newLoc)
th.Room = g.roomIn(newLoc)
g.setOldChar(th, newLoc)
oroom := th.Room
g.Level.SetMonsterAt(th.Pos.Y, th.Pos.X, nil)
@@ -86,9 +86,9 @@ func (g *RogueGame) relocate(th *Monster, newLoc Coord) {
}
}
// doChase makes one thing chase another (chase.c do_chase). Returns -1 if
// the chaser died in the attempt.
func (g *RogueGame) doChase(th *Monster) int {
// chaseStep makes one thing chase another (chase.c do_chase). Returns -1
// if the chaser died in the attempt.
func (g *RogueGame) chaseStep(th *Monster) int {
p := &g.Player
stoprun := false // true means we are there
mindist := 32767
@@ -102,59 +102,62 @@ func (g *RogueGame) doChase(th *Monster) int {
if th.Dest == &p.Pos {
ree = p.Room
} else {
ree = g.roomin(*th.Dest)
ree = g.roomIn(*th.Dest)
}
// We don't count doors as inside rooms for this routine
door := g.Level.Char(th.Pos.Y, th.Pos.X) == Door
var this Coord
over:
// If the object of our desire is in a different room, and we are not
// in a corridor, run to the door nearest to our goal.
if rer != ree {
for i := range rer.Exits {
curdist := distCp(*th.Dest, rer.Exits[i])
if curdist < mindist {
this = rer.Exits[i]
mindist = curdist
for {
// If the object of our desire is in a different room, and we are
// not in a corridor, run to the door nearest to our goal.
if rer != ree {
for i := range rer.Exits {
curdist := distCp(*th.Dest, rer.Exits[i])
if curdist < mindist {
this = rer.Exits[i]
mindist = curdist
}
}
if door {
rer = &g.Level.Passages[*g.Level.FlagsAt(th.Pos.Y, th.Pos.X)&FPassNum]
door = false
continue // the C goto over: redo with the passage as room
}
} else {
this = *th.Dest
// For dragons check and see if (a) the hero is on a straight
// line from it, and (b) that it is within shooting distance,
// but outside of striking range.
if th.Type == 'D' && (th.Pos.Y == p.Pos.Y || th.Pos.X == p.Pos.X ||
abs(th.Pos.Y-p.Pos.Y) == abs(th.Pos.X-p.Pos.X)) &&
distCp(th.Pos, p.Pos) <= BoltLength*BoltLength &&
!th.On(Cancelled) && g.rnd(dragonShot) == 0 {
g.Delta.Y = sign(p.Pos.Y - th.Pos.Y)
g.Delta.X = sign(p.Pos.X - th.Pos.X)
if g.HasHit {
g.endmsg()
}
g.fireBolt(th.Pos, &g.Delta, "flame")
g.Running = false
g.Count = 0
g.Quiet = 0
if g.ToDeath && !th.On(Targeted) {
g.ToDeath = false
g.Kamikaze = false
}
return 0
}
}
if door {
rer = &g.Level.Passages[*g.Level.FlagsAt(th.Pos.Y, th.Pos.X)&FPassNum]
door = false
goto over
}
} else {
this = *th.Dest
// For dragons check and see if (a) the hero is on a straight line
// from it, and (b) that it is within shooting distance, but
// outside of striking range.
if th.Type == 'D' && (th.Pos.Y == p.Pos.Y || th.Pos.X == p.Pos.X ||
abs(th.Pos.Y-p.Pos.Y) == abs(th.Pos.X-p.Pos.X)) &&
distCp(th.Pos, p.Pos) <= BoltLength*BoltLength &&
!th.On(Cancelled) && g.rnd(dragonShot) == 0 {
g.Delta.Y = sign(p.Pos.Y - th.Pos.Y)
g.Delta.X = sign(p.Pos.X - th.Pos.X)
if g.HasHit {
g.endmsg()
}
g.fireBolt(th.Pos, &g.Delta, "flame")
g.Running = false
g.Count = 0
g.Quiet = 0
if g.ToDeath && !th.On(Targeted) {
g.ToDeath = false
g.Kamikaze = false
}
return 0
}
break
}
// This now contains what we want to run to this time so we run to it.
// If we hit it we either want to fight it or stop running
@@ -214,7 +217,7 @@ func (g *RogueGame) chase(tp *Monster, ee Coord) bool {
if (tp.On(Confused) && g.rnd(5) != 0) || (tp.Type == 'P' && g.rnd(5) == 0) ||
(tp.Type == 'B' && g.rnd(2) == 0) {
// get a valid random move
g.chRet = g.rndmove(&tp.Creature)
g.chRet = g.randomStep(&tp.Creature)
curdist = distCp(g.chRet, ee)
// Small chance that it will become un-confused
if g.rnd(20) == 0 {
@@ -294,8 +297,8 @@ func (g *RogueGame) chase(tp *Monster, ee Coord) bool {
return curdist != 0 && g.chRet != p.Pos
}
// setOldch sets the oldch character for the monster (chase.c set_oldch).
func (g *RogueGame) setOldch(tp *Monster, cp Coord) {
// setOldChar sets the oldch character for the monster (chase.c set_oldch).
func (g *RogueGame) setOldChar(tp *Monster, cp Coord) {
if tp.Pos == cp {
return
}
@@ -341,8 +344,8 @@ func (g *RogueGame) seeMonst(mp *Monster) bool {
return !mp.Room.Flags.Has(Dark)
}
// runto sets a monster running after the hero (chase.c runto).
func (g *RogueGame) runto(runner Coord) {
// runTo sets a monster running after the hero (chase.c runto).
func (g *RogueGame) runTo(runner Coord) {
tp := g.Level.MonsterAt(runner.Y, runner.X)
if tp == nil {
return
@@ -353,9 +356,9 @@ func (g *RogueGame) runto(runner Coord) {
tp.Dest = g.findDest(tp)
}
// roomin finds what room some coordinates are in; nil means they aren't in
// roomIn finds what room some coordinates are in; nil means they aren't in
// any room (chase.c roomin).
func (g *RogueGame) roomin(cp Coord) *Room {
func (g *RogueGame) roomIn(cp Coord) *Room {
fp := *g.Level.FlagsAt(cp.Y, cp.X)
if fp.Has(FPassage) {
return &g.Level.Passages[fp&FPassNum]
@@ -387,9 +390,9 @@ func (g *RogueGame) diagOk(sp, ep Coord) bool {
return stepOk(g.Level.Char(ep.Y, sp.X)) && stepOk(g.Level.Char(sp.Y, ep.X))
}
// cansee returns true if the hero can see a certain coordinate (chase.c
// canSee returns true if the hero can see a certain coordinate (chase.c
// cansee).
func (g *RogueGame) cansee(y, x int) bool {
func (g *RogueGame) canSee(y, x int) bool {
p := &g.Player
if p.On(Blind) {
return false
@@ -408,7 +411,7 @@ func (g *RogueGame) cansee(y, x int) bool {
}
// We can only see if the hero is in the same room as the coordinate
// and the room is lit, or if it is close.
rer := g.roomin(Coord{X: x, Y: y})
rer := g.roomIn(Coord{X: x, Y: y})
return rer == p.Room && !rer.Flags.Has(Dark)
}
@@ -426,7 +429,7 @@ func (g *RogueGame) findDest(tp *Monster) *Coord {
continue
}
if g.roomin(obj.Pos) == tp.Room && g.rnd(100) < prob {
if g.roomIn(obj.Pos) == tp.Room && g.rnd(100) < prob {
claimed := false
for _, other := range g.Level.Monsters {

View File

@@ -151,270 +151,273 @@ func (g *RogueGame) command() {
}
}
// dispatch runs one command character (the big switch in command.c,
// including its `goto over` re-dispatch).
// dispatch runs one command character (the big switch in command.c; the
// loop stands in for its `goto over` re-dispatch).
func (g *RogueGame) dispatch(ch byte) {
p := &g.Player
over:
switch ch {
case ',':
var found *Object
for {
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
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.moveHero(0, -1)
case 'j':
g.moveHero(1, 0)
case 'k':
g.moveHero(-1, 0)
case 'l':
g.moveHero(0, 1)
case 'y':
g.moveHero(-1, -1)
case 'u':
g.moveHero(-1, 1)
case 'b':
g.moveHero(1, -1)
case 'n':
g.moveHero(1, 1)
case 'H':
g.startRun('h')
case 'J':
g.startRun('j')
case 'K':
g.startRun('k')
case 'L':
g.startRun('l')
case 'Y':
g.startRun('y')
case 'U':
g.startRun('u')
case 'B':
g.startRun('b')
case 'N':
g.startRun('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
}
continue // the C goto over: re-dispatch as the run command
case 'F', 'f':
if ch == 'F' {
g.Kamikaze = true
}
if !g.getDir() {
g.After = false
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 ")
}
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 ")
}
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)
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
continue // the C goto over: fight by running at it
}
}
case Escape: // escape
g.DoorStop = false
g.Count = 0
g.After = false
g.Again = false
case 'm':
g.MoveOn = true
if !g.getDir() {
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
continue // the C goto over: replay the last command
}
case 'q':
g.quaff()
case 'Q':
g.After = false
} else {
ch = g.DirCh
g.countCh = g.DirCh
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
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)
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
continue // the C goto over: move onto it without pickup
}
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)
}
}
return
}
}

View File

@@ -212,7 +212,7 @@ func (g *RogueGame) comeDown(int) {
// undo the things
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.Kind.Glyph())
}
}
@@ -223,7 +223,7 @@ func (g *RogueGame) comeDown(int) {
for _, tp := range g.Level.Monsters {
g.move(tp.Pos.Y, tp.Pos.X)
if g.cansee(tp.Pos.Y, tp.Pos.X) {
if g.canSee(tp.Pos.Y, tp.Pos.X) {
if !tp.On(Invisible) || p.On(CanSeeInvisible) {
g.addch(tp.Disguise)
} else {
@@ -248,13 +248,13 @@ func (g *RogueGame) visuals(int) {
}
// change the things
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, g.rndThing())
}
}
// change the stairs
if !g.SeenStairs && g.cansee(g.Level.Stairs.Y, g.Level.Stairs.X) {
if !g.SeenStairs && g.canSee(g.Level.Stairs.Y, g.Level.Stairs.X) {
g.mvaddch(g.Level.Stairs.Y, g.Level.Stairs.X, g.rndThing())
}

View File

@@ -10,7 +10,7 @@ func mkGameInput(t *testing.T) *RogueGame {
g := NewGame(Config{Seed: 5, Term: &testTerm{}})
g.NewLevel()
g.Oldpos = g.Player.Pos
g.Oldrp = g.roomin(g.Player.Pos)
g.Oldrp = g.roomIn(g.Player.Pos)
return g
}

View File

@@ -47,7 +47,7 @@ func (g *RogueGame) fight(mp Coord, weap *Object, thrown bool) bool {
// place.
g.Count = 0
g.Quiet = 0
g.runto(mp)
g.runTo(mp)
// Let him know it was really a xeroc (if it was one).
if tp.Type == 'X' && tp.Disguise != 'X' && !p.On(Blind) {
tp.Disguise = 'X'
@@ -182,7 +182,7 @@ func (g *RogueGame) attack(mp *Monster) int {
// Rattlesnakes have poisonous bites
if !g.save(VsPoison) {
if !p.IsWearing(RingSustainStrength) {
g.chgStr(-1)
g.changeStrength(-1)
if !g.Options.Terse {
g.msg("you feel a bite in your leg and now feel weaker")

View File

@@ -10,7 +10,7 @@ func mkGame(t *testing.T, seed int32) *RogueGame {
g := NewGame(Config{Seed: seed, Term: &testTerm{}})
g.NewLevel()
g.Oldpos = g.Player.Pos
g.Oldrp = g.roomin(g.Player.Pos)
g.Oldrp = g.roomIn(g.Player.Pos)
return g
}

View File

@@ -242,7 +242,7 @@ func (g *RogueGame) playit() {
g.Oldpos = g.Player.Pos
g.Oldrp = g.roomin(g.Player.Pos)
g.Oldrp = g.roomIn(g.Player.Pos)
for g.Playing {
g.command() // command execution
}

View File

@@ -305,9 +305,9 @@ func (g *RogueGame) checkLevel() {
}
}
// chgStr modifies the player's strength, keeping track of the highest it
// has been (misc.c chg_str).
func (g *RogueGame) chgStr(amt int) {
// changeStrength modifies the player's strength, keeping track of the
// highest it has been (misc.c chg_str).
func (g *RogueGame) changeStrength(amt int) {
if amt == 0 {
return
}
@@ -362,10 +362,10 @@ func (g *RogueGame) addHaste(potion bool) bool {
// aggravate aggravates all the monsters on this level (misc.c aggravate).
func (g *RogueGame) aggravate() {
// runto() can splice the monster list while we walk it, so iterate a copy.
// runTo() can splice the monster list while we walk it, so iterate a copy.
monsters := append([]*Monster(nil), g.Level.Monsters...)
for _, mp := range monsters {
g.runto(mp.Pos)
g.runTo(mp.Pos)
}
}

View File

@@ -37,7 +37,7 @@ func (g *RogueGame) newMonster(tp *Monster, typ byte, cp Coord) {
tp.Pos = cp
g.move(cp.Y, cp.X)
tp.OldCh = g.inch()
tp.Room = g.roomin(cp)
tp.Room = g.roomIn(cp)
g.Level.SetMonsterAt(cp.Y, cp.X, tp)
mp := &g.Monsters[tp.Type-'A']
tp.Stats.Lvl = mp.Stats.Lvl + levAdd
@@ -57,7 +57,7 @@ func (g *RogueGame) newMonster(tp *Monster, typ byte, cp Coord) {
tp.Pack = nil
if g.Player.IsWearing(RingAggravateMonsters) {
g.runto(cp)
g.runTo(cp)
}
if typ == 'X' {
@@ -92,7 +92,7 @@ func (g *RogueGame) wanderer() {
var cp Coord
for {
cp, _ = g.findFloor(true)
if g.roomin(cp) != g.Player.Room {
if g.roomIn(cp) != g.Player.Room {
break
}
}
@@ -111,7 +111,7 @@ func (g *RogueGame) wanderer() {
g.standend()
}
g.runto(tp.Pos)
g.runTo(tp.Pos)
}
// wakeMonster is what to do when the hero steps next to a monster

View File

@@ -2,16 +2,17 @@ package game
// move.c — hero movement commands.
// doRun starts the hero running (move.c do_run).
func (g *RogueGame) doRun(ch byte) {
// startRun starts the hero running (move.c do_run).
func (g *RogueGame) startRun(ch byte) {
g.Running = true
g.After = false
g.RunCh = ch
}
// doMove checks that a move is legal and handles the consequences —
// fighting, picking up, etc. (move.c do_move).
func (g *RogueGame) doMove(dy, dx int) {
// moveHero checks that a move is legal and handles the consequences —
// fighting, picking up, etc. (move.c do_move). The C `goto over`
// re-check after a passage turn is the retry loop.
func (g *RogueGame) moveHero(dy, dx int) {
p := &g.Player
g.Firstmove = false
@@ -24,7 +25,7 @@ func (g *RogueGame) doMove(dy, dx int) {
// Do a confused move (maybe)
var nh Coord
if p.On(Confused) && g.rnd(5) != 0 {
nh = g.rndmove(&p.Creature)
nh = g.randomStep(&p.Creature)
if nh == p.Pos {
g.After = false
g.Running = false
@@ -36,150 +37,161 @@ func (g *RogueGame) doMove(dy, dx int) {
nh = Coord{Y: p.Pos.Y + dy, X: p.Pos.X + dx}
}
over:
// Check if he tried to move off the screen or make an illegal diagonal
// move, and stop him if he did.
hitBound := nh.X < 0 || nh.X >= NumCols || nh.Y <= 0 || nh.Y >= NumLines-1
for {
// Check if he tried to move off the screen or make an illegal
// diagonal move, and stop him if he did.
hitBound := nh.X < 0 || nh.X >= NumCols || nh.Y <= 0 || nh.Y >= NumLines-1
var (
ch byte
fl PlaceFlags
)
var (
ch byte
fl PlaceFlags
)
if !hitBound {
if !g.diagOk(p.Pos, nh) {
g.After = false
g.Running = false
if !hitBound {
if !g.diagOk(p.Pos, nh) {
g.After = false
g.Running = false
return
}
if g.Running && p.Pos == nh {
g.After = false
g.Running = false
}
fl = *g.Level.FlagsAt(nh.Y, nh.X)
ch = g.Level.VisibleChar(nh.Y, nh.X)
if !fl.Has(FReal) && ch == Floor {
if !p.On(Levitating) {
ch = Trap
g.Level.SetChar(nh.Y, nh.X, Trap)
g.Level.FlagsAt(nh.Y, nh.X).Set(FReal)
return
}
} else if p.On(Held) && ch != 'F' {
g.msg("you are being held")
return
}
}
if g.Running && p.Pos == nh {
g.After = false
g.Running = false
}
if hitBound {
ch = ' ' // fall into the wall case below
}
fl = *g.Level.FlagsAt(nh.Y, nh.X)
switch ch {
case ' ', '|', '-':
if g.Options.PassGo && g.Running && p.Room.Flags.Has(Gone) &&
!p.On(Blind) {
var b1, b2 bool
switch g.RunCh {
case 'h', 'l':
b1 = p.Pos.Y != 1 && g.turnOk(p.Pos.Y-1, p.Pos.X)
b2 = p.Pos.Y != NumLines-2 && g.turnOk(p.Pos.Y+1, p.Pos.X)
if b1 != b2 {
if b1 {
g.RunCh = 'k'
dy = -1
} else {
g.RunCh = 'j'
dy = 1
}
dx = 0
g.turnref()
nh = Coord{Y: p.Pos.Y + dy, X: p.Pos.X + dx}
goto over
ch = g.Level.VisibleChar(nh.Y, nh.X)
if !fl.Has(FReal) && ch == Floor {
if !p.On(Levitating) {
ch = Trap
g.Level.SetChar(nh.Y, nh.X, Trap)
g.Level.FlagsAt(nh.Y, nh.X).Set(FReal)
}
case 'j', 'k':
b1 = p.Pos.X != 0 && g.turnOk(p.Pos.Y, p.Pos.X-1)
} else if p.On(Held) && ch != 'F' {
g.msg("you are being held")
b2 = p.Pos.X != NumCols-1 && g.turnOk(p.Pos.Y, p.Pos.X+1)
if b1 != b2 {
if b1 {
g.RunCh = 'h'
dx = -1
} else {
g.RunCh = 'l'
dx = 1
}
return
}
}
dy = 0
if hitBound {
ch = ' ' // fall into the wall case below
}
g.turnref()
switch ch {
case ' ', '|', '-':
if turn, ndy, ndx := g.passageTurn(dy, dx); turn {
dy, dx = ndy, ndx
nh = Coord{Y: p.Pos.Y + dy, X: p.Pos.X + dx}
g.turnRefresh()
goto over
nh = Coord{Y: p.Pos.Y + dy, X: p.Pos.X + dx}
continue // the C goto over: re-check the turned move
}
g.Running = false
g.After = false
case Door:
g.Running = false
if g.Level.FlagsAt(p.Pos.Y, p.Pos.X).Has(FPassage) {
g.enterRoom(nh)
}
g.finishMove(nh, fl)
case Trap:
tr := g.springTrap(nh)
if tr == TrapDoor || tr == TrapTeleport {
return
}
g.finishMove(nh, fl)
case Passage:
// when you're in a corridor, you don't know if you're in a maze
// room or not, and there ain't no way to find out if you're
// leaving a maze room, so it is necessary to always recalculate
// proom.
p.Room = g.roomIn(p.Pos)
g.finishMove(nh, fl)
case Floor:
if !fl.Has(FReal) {
g.springTrap(p.Pos)
}
g.finishMove(nh, fl)
default:
if ch == Stairs {
g.SeenStairs = true
}
g.Running = false
if isUpper(ch) || g.Level.MonsterAt(nh.Y, nh.X) != nil {
g.fight(nh, p.CurWeapon, false)
} else {
if ch != Stairs {
g.Take = ch
}
g.finishMove(nh, fl)
}
}
g.Running = false
g.After = false
case Door:
g.Running = false
if g.Level.FlagsAt(p.Pos.Y, p.Pos.X).Has(FPassage) {
g.enterRoom(nh)
}
g.moveStuff(nh, fl)
case Trap:
tr := g.beTrapped(nh)
if tr == TrapDoor || tr == TrapTeleport {
return
}
g.moveStuff(nh, fl)
case Passage:
// when you're in a corridor, you don't know if you're in a maze
// room or not, and there ain't no way to find out if you're
// leaving a maze room, so it is necessary to always recalculate
// proom.
p.Room = g.roomin(p.Pos)
g.moveStuff(nh, fl)
case Floor:
if !fl.Has(FReal) {
g.beTrapped(p.Pos)
}
g.moveStuff(nh, fl)
default:
if ch == Stairs {
g.SeenStairs = true
}
g.Running = false
if isUpper(ch) || g.Level.MonsterAt(nh.Y, nh.X) != nil {
g.fight(nh, p.CurWeapon, false)
} else {
if ch != Stairs {
g.Take = ch
}
g.moveStuff(nh, fl)
}
return
}
}
// moveStuff is the move_stuff label in do_move: complete the step.
func (g *RogueGame) moveStuff(nh Coord, fl PlaceFlags) {
// passageTurn checks whether a runner in a gone-room passage should turn
// the corner instead of stopping at a wall (the PASSGO block of move.c
// do_move). It reports whether to turn and the new deltas, updating RunCh.
func (g *RogueGame) passageTurn(dy, dx int) (bool, int, int) {
p := &g.Player
if !g.Options.PassGo || !g.Running || !p.Room.Flags.Has(Gone) ||
p.On(Blind) {
return false, dy, dx
}
var b1, b2 bool
switch g.RunCh {
case 'h', 'l':
b1 = p.Pos.Y != 1 && g.turnOk(p.Pos.Y-1, p.Pos.X)
b2 = p.Pos.Y != NumLines-2 && g.turnOk(p.Pos.Y+1, p.Pos.X)
if b1 != b2 {
if b1 {
g.RunCh = 'k'
dy = -1
} else {
g.RunCh = 'j'
dy = 1
}
return true, dy, 0
}
case 'j', 'k':
b1 = p.Pos.X != 0 && g.turnOk(p.Pos.Y, p.Pos.X-1)
b2 = p.Pos.X != NumCols-1 && g.turnOk(p.Pos.Y, p.Pos.X+1)
if b1 != b2 {
if b1 {
g.RunCh = 'h'
dx = -1
} else {
g.RunCh = 'l'
dx = 1
}
return true, 0, dx
}
}
return false, dy, dx
}
// finishMove is the move_stuff label in do_move: complete the step.
func (g *RogueGame) finishMove(nh Coord, fl PlaceFlags) {
p := &g.Player
g.mvaddch(p.Pos.Y, p.Pos.X, g.floorAt())
@@ -198,8 +210,9 @@ func (g *RogueGame) turnOk(y, x int) bool {
return pp.Ch == Door || pp.Flags&(FReal|FPassage) == (FReal|FPassage)
}
// turnref decides whether to refresh at a passage turning (move.c turnref).
func (g *RogueGame) turnref() {
// turnRefresh decides whether to refresh at a passage turning (move.c
// turnref).
func (g *RogueGame) turnRefresh() {
p := &g.Player
pp := g.Level.At(p.Pos.Y, p.Pos.X)
@@ -228,8 +241,8 @@ 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) TrapKind {
// springTrap makes him pay for stepping on a trap (move.c be_trapped).
func (g *RogueGame) springTrap(tc Coord) TrapKind {
p := &g.Player
if p.On(Levitating) {
return TrapRust // anything that's not a door or teleport
@@ -313,7 +326,7 @@ func (g *RogueGame) beTrapped(tc Coord) TrapKind {
}
if !p.IsWearing(RingSustainStrength) && !g.save(VsPoison) {
g.chgStr(-1)
g.changeStrength(-1)
}
g.msg("a small dart just hit you in the shoulder")
@@ -328,9 +341,9 @@ func (g *RogueGame) beTrapped(tc Coord) TrapKind {
return tr
}
// rndmove moves in a random direction if the monster/person is confused
// (move.c rndmove).
func (g *RogueGame) rndmove(who *Creature) Coord {
// randomStep moves in a random direction if the monster/person is
// confused (move.c rndmove).
func (g *RogueGame) randomStep(who *Creature) Coord {
ret := Coord{
Y: who.Pos.Y + g.rnd(3) - 1,
X: who.Pos.X + g.rnd(3) - 1,

View File

@@ -27,8 +27,8 @@ func (g *RogueGame) NewLevel() {
// go with them (the garbage collector is our free_list).
g.Level.Monsters = nil
g.Level.Objects = nil
g.doRooms() // Draw rooms
g.doPassages() // Draw passages
g.digRooms() // Draw rooms
g.digPassages() // Draw passages
p.NoFood++
@@ -61,7 +61,7 @@ func (g *RogueGame) NewLevel() {
g.SeenStairs = false
for _, tp := range g.Level.Monsters {
tp.Room = g.roomin(tp.Pos)
tp.Room = g.roomIn(tp.Pos)
}
hero, _ := g.findFloor(true)
@@ -78,8 +78,8 @@ func (g *RogueGame) NewLevel() {
}
}
// rndRoom picks a room that is really there (new_level.c rnd_room).
func (g *RogueGame) rndRoom() int {
// randomRoom picks a room that is really there (new_level.c rnd_room).
func (g *RogueGame) randomRoom() int {
for {
rm := g.rnd(MaxRooms)
if !g.Level.Rooms[rm].Flags.Has(Gone) {
@@ -98,7 +98,7 @@ func (g *RogueGame) putThings() {
}
// check for treasure rooms, and if so, put it in.
if g.rnd(treasRoomChance) == 0 {
g.treasRoom()
g.treasureRoom()
}
// Do MAXOBJ attempts to put things on a level
for range MaxObj {
@@ -126,9 +126,9 @@ func (g *RogueGame) putThings() {
}
}
// treasRoom adds a treasure room (new_level.c treas_room).
func (g *RogueGame) treasRoom() {
rp := &g.Level.Rooms[g.rndRoom()]
// treasureRoom adds a treasure room (new_level.c treas_room).
func (g *RogueGame) treasureRoom() {
rp := &g.Level.Rooms[g.randomRoom()]
spots := min((rp.Max.Y-2)*(rp.Max.X-2)-minTreas, maxTreas-minTreas)

View File

@@ -2,8 +2,8 @@ package game
// passages.c — draw the connecting passages.
// doPassages draws all the passages on a level (passages.c do_passages).
func (g *RogueGame) doPassages() {
// digPassages draws all the passages on a level (passages.c do_passages).
func (g *RogueGame) digPassages() {
var (
isconn [MaxRooms][MaxRooms]bool
ingraph [MaxRooms]bool
@@ -41,7 +41,7 @@ func (g *RogueGame) doPassages() {
// otherwise, connect new room to the graph, and draw a tunnel
// to it
ingraph[r2] = true //nolint:gosec // G602: rnd(MaxRooms) bounded
g.conn(r1, r2)
g.connectRooms(r1, r2)
isconn[r1][r2] = true
isconn[r2][r1] = true //nolint:gosec // G602: rnd(MaxRooms) bounded
roomcount++
@@ -69,18 +69,18 @@ func (g *RogueGame) doPassages() {
}
// if there is one, connect it and look for the next added passage
if j != 0 {
g.conn(r1, r2)
g.connectRooms(r1, r2)
isconn[r1][r2] = true
isconn[r2][r1] = true //nolint:gosec // G602: rnd(MaxRooms) bounded
}
}
g.passnum()
g.numberPassages()
}
// conn draws a corridor from a room in a certain direction (passages.c
// conn).
func (g *RogueGame) conn(r1, r2 int) {
// connectRooms draws a corridor from a room in a certain direction
// (passages.c conn).
func (g *RogueGame) connectRooms(r1, r2 int) {
var (
rm int
direc byte
@@ -193,13 +193,13 @@ func (g *RogueGame) conn(r1, r2 int) {
if !rpf.Flags.Has(Gone) {
g.door(rpf, spos)
} else {
g.putpass(spos)
g.putPassage(spos)
}
if !rpt.Flags.Has(Gone) {
g.door(rpt, epos)
} else {
g.putpass(epos)
g.putPassage(epos)
}
// Get ready to move...
curr := spos
@@ -210,13 +210,13 @@ func (g *RogueGame) conn(r1, r2 int) {
// Check if we are at the turn place, if so do the turn
if distance == turnSpot {
for ; turnDistance > 0; turnDistance-- {
g.putpass(curr)
g.putPassage(curr)
curr.X += turnDelta.X
curr.Y += turnDelta.Y
}
}
// Continue digging along
g.putpass(curr)
g.putPassage(curr)
distance--
}
@@ -229,9 +229,9 @@ func (g *RogueGame) conn(r1, r2 int) {
}
}
// putpass adds a passage character or secret passage here (passages.c
// putPassage adds a passage character or secret passage here (passages.c
// putpass).
func (g *RogueGame) putpass(cp Coord) {
func (g *RogueGame) putPassage(cp Coord) {
pp := g.Level.At(cp.Y, cp.X)
pp.Flags.Set(FPassage)
@@ -302,8 +302,8 @@ func (g *RogueGame) addPass() {
}
}
// passnum assigns a number to each passageway (passages.c passnum).
func (g *RogueGame) passnum() {
// numberPassages assigns a number to each passageway (passages.c passnum).
func (g *RogueGame) numberPassages() {
g.pnum = 0
g.newpnum = false
@@ -315,14 +315,14 @@ func (g *RogueGame) passnum() {
rp := &g.Level.Rooms[i]
for j := range rp.Exits {
g.newpnum = true
g.numpass(rp.Exits[j].Y, rp.Exits[j].X)
g.numberPassage(rp.Exits[j].Y, rp.Exits[j].X)
}
}
}
// numpass numbers a passageway square and its brethren (passages.c
// numberPassage numbers a passageway square and its brethren (passages.c
// numpass).
func (g *RogueGame) numpass(y, x int) {
func (g *RogueGame) numberPassage(y, x int) {
if x >= NumCols || x < 0 || y >= NumLines || y <= 0 {
return
}
@@ -348,10 +348,10 @@ func (g *RogueGame) numpass(y, x int) {
*fp |= PlaceFlags(g.pnum) //nolint:gosec // G115: pnum < MaxPass=13
// recurse on the surrounding places
g.numpass(y+1, x)
g.numpass(y-1, x)
g.numpass(y, x+1)
g.numpass(y, x-1)
g.numberPassage(y+1, x)
g.numberPassage(y-1, x)
g.numberPassage(y, x+1)
g.numberPassage(y, x-1)
}
// abs is C abs() for ints.

View File

@@ -49,7 +49,7 @@ func (g *RogueGame) quaff() {
if p.IsWearing(RingSustainStrength) {
g.msg("you feel momentarily sick")
} else {
g.chgStr(-(g.rnd(3) + 1))
g.changeStrength(-(g.rnd(3) + 1))
g.msg("you feel very sick now")
g.comeDown(0)
}
@@ -64,7 +64,7 @@ func (g *RogueGame) quaff() {
g.msg("you begin to feel better")
case PotionGainStrength:
g.Items.Potions[PotionGainStrength].Know = true
g.chgStr(1)
g.changeStrength(1)
g.msg("you feel stronger, now. What bulging muscles!")
case PotionDetectMonsters:
p.Flags.Set(SenseMonsters)

View File

@@ -54,7 +54,7 @@ func (g *RogueGame) ringOn() {
// Calculate the effect it has on the poor guy.
switch obj.RingKind() {
case RingAddStrength:
g.chgStr(obj.Bonus)
g.changeStrength(obj.Bonus)
case RingSeeInvisible:
g.invisOn()
case RingAggravateMonsters:

View File

@@ -17,9 +17,9 @@ type mazeState struct {
const goldGrp = 1
// doRooms creates rooms and corridors with a connectivity graph (rooms.c
// digRooms creates rooms and corridors with a connectivity graph (rooms.c
// do_rooms).
func (g *RogueGame) doRooms() {
func (g *RogueGame) digRooms() {
var bsze Coord // maximum room size
bsze.X = NumCols / 3
@@ -34,7 +34,7 @@ func (g *RogueGame) doRooms() {
// Put the gone rooms, if any, on the level
leftOut := g.rnd(4)
for range leftOut {
g.Level.Rooms[g.rndRoom()].Flags.Set(Gone)
g.Level.Rooms[g.randomRoom()].Flags.Set(Gone)
}
// dig and populate all the rooms on the level
for i := range g.Level.Rooms {
@@ -126,7 +126,7 @@ func (g *RogueGame) doRooms() {
// rooms; for maze rooms, draws the maze (rooms.c draw_room).
func (g *RogueGame) drawRoom(rp *Room) {
if rp.Flags.Has(Maze) {
g.doMaze(rp)
g.digMaze(rp)
return
}
@@ -158,8 +158,8 @@ func (g *RogueGame) horiz(rp *Room, starty int) {
}
}
// doMaze digs a maze (rooms.c do_maze).
func (g *RogueGame) doMaze(rp *Room) {
// digMaze digs a maze (rooms.c do_maze).
func (g *RogueGame) digMaze(rp *Room) {
m := &g.maze
for y := range m.maze {
for x := range m.maze[y] {
@@ -175,7 +175,7 @@ func (g *RogueGame) doMaze(rp *Room) {
starty := (g.rnd(rp.Max.Y) / 2) * 2
startx := (g.rnd(rp.Max.X) / 2) * 2
pos := Coord{Y: starty + m.starty, X: startx + m.startx}
g.putpass(pos)
g.putPassage(pos)
g.dig(starty, startx)
}
@@ -211,8 +211,8 @@ func (g *RogueGame) dig(y, x int) {
return
}
g.accntMaze(y, x, nexty, nextx)
g.accntMaze(nexty, nextx, y, x)
g.accountMaze(y, x, nexty, nextx)
g.accountMaze(nexty, nextx, y, x)
var pos Coord
if nexty == y {
@@ -231,16 +231,16 @@ func (g *RogueGame) dig(y, x int) {
}
}
g.putpass(pos)
g.putPassage(pos)
pos.Y = nexty + m.starty
pos.X = nextx + m.startx
g.putpass(pos)
g.putPassage(pos)
g.dig(nexty, nextx)
}
}
// accntMaze accounts for maze exits (rooms.c accnt_maze).
func (g *RogueGame) accntMaze(y, x, ny, nx int) {
// accountMaze accounts for maze exits (rooms.c accnt_maze).
func (g *RogueGame) accountMaze(y, x, ny, nx int) {
sp := &g.maze.maze[y][x]
for i := range sp.nexits {
if sp.exits[i].Y == ny && sp.exits[i].X == nx {
@@ -255,8 +255,8 @@ func (g *RogueGame) accntMaze(y, x, ny, nx int) {
}
}
// rndPos picks a random spot in a room (rooms.c rnd_pos).
func (g *RogueGame) rndPos(rp *Room) Coord {
// randomPos picks a random spot in a room (rooms.c rnd_pos).
func (g *RogueGame) randomPos(rp *Room) Coord {
var cp Coord
cp.X = rp.Pos.X + g.rnd(rp.Max.X-2) + 1
@@ -296,7 +296,7 @@ func (g *RogueGame) findFloorImpl(rp *Room, limit int, monst, pickroom bool) (Co
}
if pickroom {
rp = &g.Level.Rooms[g.rndRoom()]
rp = &g.Level.Rooms[g.randomRoom()]
compchar = Floor
if rp.Flags.Has(Maze) {
@@ -304,7 +304,7 @@ func (g *RogueGame) findFloorImpl(rp *Room, limit int, monst, pickroom bool) (Co
}
}
cp := g.rndPos(rp)
cp := g.randomPos(rp)
pp := g.Level.At(cp.Y, cp.X)
if monst {
@@ -321,7 +321,7 @@ func (g *RogueGame) findFloorImpl(rp *Room, limit int, monst, pickroom bool) (Co
// enter_room).
func (g *RogueGame) enterRoom(cp Coord) {
p := &g.Player
rp := g.roomin(cp)
rp := g.roomIn(cp)
p.Room = rp
g.doorOpen(rp)

View File

@@ -449,99 +449,102 @@ func (g *RogueGame) applySnapshot(st *SaveState) {
g.scr.Std.SetContents(st.Screen)
}
// saveGame implements the "save game" command (save.c save_game). The C
// goto over/gotfile flow becomes the useDefault flag.
// saveGame implements the "save game" command (save.c save_game). The
// labeled prompt loop and the useDefault flag stand in for the C
// goto over/gotfile flow.
func (g *RogueGame) saveGame() {
g.Msgs.Mpos = 0
over:
useDefault := false
if g.FileName != "" {
var c byte
for {
g.msg("save file (%s)? ", g.FileName)
c = g.readchar()
g.Msgs.Mpos = 0
if c == Escape {
g.msg("")
return
}
if c == 'n' || c == 'N' || c == 'y' || c == 'Y' {
break
}
g.msg("please answer Y or N")
}
if c == 'y' || c == 'Y' {
g.addstr("Yes\n")
g.refresh()
useDefault = true
}
}
prompt:
for {
var buf string
if useDefault {
buf = g.FileName
useDefault = false
} else {
g.Msgs.Mpos = 0
g.msg("file name: ")
useDefault := false
if g.getStr(&buf, g.scr.Std) == Quit {
g.msg("")
if g.FileName != "" {
var c byte
return
}
g.Msgs.Mpos = 0
}
// test to see if the file exists
_, statErr := os.Stat(buf)
if statErr == nil {
for {
g.msg("File exists. Do you wish to overwrite it?")
g.Msgs.Mpos = 0
g.msg("save file (%s)? ", g.FileName)
c = g.readchar()
c := g.readchar()
g.Msgs.Mpos = 0
if c == Escape {
g.msg("")
return
}
if c == 'y' || c == 'Y' {
if c == 'n' || c == 'N' || c == 'y' || c == 'Y' {
break
}
if c == 'n' || c == 'N' {
goto over
}
g.msg("Please answer Y or N")
g.msg("please answer Y or N")
}
g.msg("file name: %s", buf)
_ = os.Remove(g.FileName) // best effort, as in C (md_unlink)
if c == 'y' || c == 'Y' {
g.addstr("Yes\n")
g.refresh()
useDefault = true
}
}
g.FileName = buf
for {
var buf string
if useDefault {
buf = g.FileName
useDefault = false
} else {
g.Msgs.Mpos = 0
g.msg("file name: ")
err := g.saveFile(g.FileName)
if err != nil {
g.msg("%s", err.Error())
if g.getStr(&buf, g.scr.Std) == Quit {
g.msg("")
continue
return
}
g.Msgs.Mpos = 0
}
// test to see if the file exists
_, statErr := os.Stat(buf)
if statErr == nil {
for {
g.msg("File exists. Do you wish to overwrite it?")
g.Msgs.Mpos = 0
c := g.readchar()
if c == Escape {
g.msg("")
return
}
if c == 'y' || c == 'Y' {
break
}
if c == 'n' || c == 'N' {
continue prompt // the C goto over: start again
}
g.msg("Please answer Y or N")
}
g.msg("file name: %s", buf)
_ = os.Remove(g.FileName) // best effort, as in C (md_unlink)
}
g.FileName = buf
err := g.saveFile(g.FileName)
if err != nil {
g.msg("%s", err.Error())
continue
}
break prompt
}
break
}
g.myExit()

View File

@@ -80,7 +80,7 @@ func (g *RogueGame) doZap() {
case WandInvisibility:
tp.Flags.Set(Invisible)
if g.cansee(y, x) {
if g.canSee(y, x) {
g.mvaddch(y, x, tp.OldCh)
}
case WandPolymorph:
@@ -186,7 +186,7 @@ func (g *RogueGame) doZap() {
g.Delta.Y = y
g.Delta.X = x
g.runto(g.Delta)
g.runTo(g.Delta)
}
case WandLightning, WandFire, WandCold:
var name string
@@ -243,7 +243,7 @@ func (g *RogueGame) drain() {
if mp.Stats.HP -= cnt; mp.Stats.HP <= 0 {
g.killed(mp, g.seeMonst(mp))
} else {
g.runto(mp.Pos)
g.runTo(mp.Pos)
}
}
}
@@ -339,7 +339,7 @@ func (g *RogueGame) fireBolt(start Coord, dir *Coord, name string) {
}
} else if ch != 'M' || tp.Disguise == 'M' {
if fromHero {
g.runto(pos)
g.runTo(pos)
}
if g.Options.Terse {

View File

@@ -201,7 +201,7 @@ func (g *RogueGame) dropCheck(obj *Object) bool {
switch obj.RingKind() {
case RingAddStrength:
g.chgStr(-obj.Bonus)
g.changeStrength(-obj.Bonus)
case RingSeeInvisible:
g.unsee(0)
g.Extinguish(DUnsee)

View File

@@ -36,7 +36,7 @@ func (g *RogueGame) doMotion(obj *Object, ydelta, xdelta int) {
obj.Pos = p.Pos
for {
// Erase the old one
if obj.Pos != p.Pos && g.cansee(obj.Pos.Y, obj.Pos.X) && !g.Options.Terse {
if obj.Pos != p.Pos && g.canSee(obj.Pos.Y, obj.Pos.X) && !g.Options.Terse {
ch := g.Level.Char(obj.Pos.Y, obj.Pos.X)
if ch == Floor && !g.showFloor() {
ch = ' '
@@ -51,7 +51,7 @@ func (g *RogueGame) doMotion(obj *Object, ydelta, xdelta int) {
ch := g.Level.VisibleChar(obj.Pos.Y, obj.Pos.X)
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 {
if g.canSee(obj.Pos.Y, obj.Pos.X) && !g.Options.Terse {
g.mvaddch(obj.Pos.Y, obj.Pos.X, obj.Kind.Glyph())
g.refresh()
}
@@ -70,7 +70,7 @@ func (g *RogueGame) fall(obj *Object, pr bool) {
pp.Ch = obj.Kind.Glyph()
obj.Pos = fpos
if g.cansee(fpos.Y, fpos.X) {
if g.canSee(fpos.Y, fpos.X) {
if pp.Monst != nil {
pp.Monst.OldCh = obj.Kind.Glyph()
} else {

View File

@@ -181,7 +181,7 @@ func (g *RogueGame) teleport() {
g.mvaddch(p.Pos.Y, p.Pos.X, g.floorAt())
c, _ := g.findFloor(true)
if g.roomin(c) != p.Room {
if g.roomIn(c) != p.Room {
g.leaveRoom(p.Pos)
p.Pos = c
g.enterRoom(p.Pos)