Merge refactor/movement-renames (refactor step 4)

This commit is contained in:
2026-07-07 02:29:06 +02:00
21 changed files with 653 additions and 624 deletions

47
TODO.md
View File

@@ -29,14 +29,26 @@ Refactor ground rules:
# Next Step
Refactor step 4: method renames, movement/world subsystem
(doMove→moveHero, beTrapped→springTrap, rndmove→randomStep,
doRooms/doPassages/doMaze→digRooms/digPassages/digMaze,
chgStr→changeStrength, ...); remove the goto/label flows in doMove,
dispatch, and saveGame in favor of loops and helpers.
Refactor step 5: method renames, items/combat/UI subsystems
(invName→inventoryName, rollEm→rollAttacks, doPot→applyPotionFuse,
getItem→promptPackItem returning (obj, ok), getDir→promptDirection);
int status codes (attack returning -1) become named results. Two or
three commits, one subsystem each.
# Completed Steps
- 2026-07-07 Refactor step 4 (refactor/movement-renames): movement/world
renames (doMove→moveHero, beTrapped→springTrap, rndmove→randomStep,
doRooms/doPassages/doMaze→digRooms/digPassages/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
replaced with loops (moveHero retry loop + extracted passageTurn,
dispatch re-dispatch loop, chaseStep passage loop, saveGame labeled
prompt loop); C breadcrumbs kept in doc comments.
- 2026-07-07 Lint adoption finished (refactor/no-package-globals): all
37 package-level vars moved into `gameData` (built by `newGameData`,
hung on RogueGame as `g.data`, set in NewGame and Restore); ObjectKind
@@ -98,41 +110,36 @@ dispatch, and saveGame in favor of loops and helpers.
# Future Steps
1. Refactor step 5: method renames, items/combat/UI subsystems
(invName→inventoryName, rollEm→rollAttacks, doPot→applyPotionFuse,
getItem→promptPackItem returning (obj, ok), getDir→promptDirection);
int status codes (attack returning -1) become named results. Two or
three commits, one subsystem each.
2. Refactor step 6: extract types from the god object — MessageLine
1. Refactor step 6: extract types from the god object — MessageLine
owns the msg/addmsg/endmsg machinery; pack/inventory operations move
onto *Player; monster/object list management and map queries
consolidate onto *Level; RogueGame keeps turn orchestration and
cross-system effects only.
3. Refactor step 7: effects dispatch — the giant quaff/readScroll/doZap
2. Refactor step 7: effects dispatch — the giant quaff/readScroll/doZap
switches become per-kind handler tables of small named methods,
keeping effect order and RNG call sequence identical. This step also
clears the outstanding cyclop/gocognit/nestif lint findings.
4. Refactor step 8: constructor and style pass per the house
3. Refactor step 8: constructor and style pass per the house
styleguide — game.New(game.Params{...}) replacing NewGame(Config);
replace the gameEnd panic unwind with error-based turn results where
feasible; 77-column wrap sweep.
5. Docs refresh: update ARCHITECTURE.md Part 2 and README.md for the
4. Docs refresh: update ARCHITECTURE.md Part 2 and README.md for the
post-refactor names; add the C name → Go name rename table.
6. Playtest hardening pass: play several full games with the tcell
5. Playtest hardening pass: play several full games with the tcell
binary and extend run_test.go to script a deeper multi-level
playthrough (descend past level 5, use potions, scrolls, zapping,
save/restore). Fix any panics, message mismatches, or divergences
from the C behavior that this uncovers, with regression tests.
7. Verify the seed-compatibility claim against the C reference on
6. Verify the seed-compatibility claim against the C reference on
c-master: same seed, same dungeon, same item tables, for several
seeds.
8. Broaden unit test coverage where playtesting finds thin spots
7. Broaden unit test coverage where playtesting finds thin spots
(rings, sticks, wizard commands).
9. Tag a release once a full game (Amulet retrieval and score entry)
8. Tag a release once a full game (Amulet retrieval and score entry)
completes without defects.
10. Full-terminal-size support (deferred by explicit decision
9. Full-terminal-size support (deferred by explicit decision
2026-07-06): per-game dungeon dimensions instead of the 80x24
constants; open design questions are resize policy, gameplay
tuning at larger sizes, and a --classic 80x24 mode.
11. Note: this repo is exempt from the standard policy scaffold. Do not
10. Note: this repo is exempt from the standard policy scaffold. Do not
add Makefile, Dockerfile, or REPO_POLICIES.md.

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,16 +102,16 @@ 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.
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])
@@ -125,13 +125,13 @@ over:
rer = &g.Level.Passages[*g.Level.FlagsAt(th.Pos.Y, th.Pos.X)&FPassNum]
door = false
goto over
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.
// 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 &&
@@ -156,6 +156,9 @@ over:
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
if !g.chase(th, this) {
@@ -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,12 +151,12 @@ 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:
for {
switch ch {
case ',':
var found *Object
@@ -189,37 +189,37 @@ over:
case '!':
g.shell()
case 'h':
g.doMove(0, -1)
g.moveHero(0, -1)
case 'j':
g.doMove(1, 0)
g.moveHero(1, 0)
case 'k':
g.doMove(-1, 0)
g.moveHero(-1, 0)
case 'l':
g.doMove(0, 1)
g.moveHero(0, 1)
case 'y':
g.doMove(-1, -1)
g.moveHero(-1, -1)
case 'u':
g.doMove(-1, 1)
g.moveHero(-1, 1)
case 'b':
g.doMove(1, -1)
g.moveHero(1, -1)
case 'n':
g.doMove(1, 1)
g.moveHero(1, 1)
case 'H':
g.doRun('h')
g.startRun('h')
case 'J':
g.doRun('j')
g.startRun('j')
case 'K':
g.doRun('k')
g.startRun('k')
case 'L':
g.doRun('l')
g.startRun('l')
case 'Y':
g.doRun('y')
g.startRun('y')
case 'U':
g.doRun('u')
g.startRun('u')
case 'B':
g.doRun('b')
g.startRun('b')
case 'N':
g.doRun('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) {
@@ -234,7 +234,7 @@ over:
g.direction = ch
}
goto over
continue // the C goto over: re-dispatch as the run command
case 'F', 'f':
if ch == 'F' {
g.Kamikaze = true
@@ -266,7 +266,7 @@ over:
g.RunCh = g.DirCh
ch = g.DirCh
goto over
continue // the C goto over: fight by running at it
}
case 't':
if !g.getDir() {
@@ -282,7 +282,7 @@ over:
ch = g.LastComm
g.Again = true
goto over
continue // the C goto over: replay the last command
}
case 'q':
g.quaff()
@@ -392,7 +392,7 @@ over:
ch = g.DirCh
g.countCh = g.DirCh
goto over
continue // the C goto over: move onto it without pickup
}
case ')':
g.current(p.CurWeapon, "wielding", "")
@@ -416,6 +416,9 @@ over:
g.illcom(ch)
}
}
return
}
}
// wizardCommand handles the MASTER debug commands (command.c).

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,9 +37,9 @@ 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.
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 (
@@ -81,8 +82,76 @@ over:
switch ch {
case ' ', '|', '-':
if g.Options.PassGo && g.Running && p.Room.Flags.Has(Gone) &&
!p.On(Blind) {
if turn, ndy, ndx := g.passageTurn(dy, dx); turn {
dy, dx = ndy, ndx
g.turnRefresh()
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)
}
}
return
}
}
// 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 {
@@ -99,13 +168,7 @@ over:
dy = 1
}
dx = 0
g.turnref()
nh = Coord{Y: p.Pos.Y + dy, X: p.Pos.X + dx}
goto over
return true, dy, 0
}
case 'j', 'k':
b1 = p.Pos.X != 0 && g.turnOk(p.Pos.Y, p.Pos.X-1)
@@ -120,66 +183,15 @@ over:
dx = 1
}
dy = 0
g.turnref()
nh = Coord{Y: p.Pos.Y + dy, X: p.Pos.X + dx}
goto over
}
return true, 0, dx
}
}
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 false, dy, dx
}
// moveStuff is the move_stuff label in do_move: complete the step.
func (g *RogueGame) moveStuff(nh Coord, fl PlaceFlags) {
// 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,12 +449,14 @@ 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:
prompt:
for {
useDefault := false
if g.FileName != "" {
@@ -522,7 +524,7 @@ over:
}
if c == 'n' || c == 'N' {
goto over
continue prompt // the C goto over: start again
}
g.msg("Please answer Y or N")
@@ -541,7 +543,8 @@ over:
continue
}
break
break prompt
}
}
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)