Adopt house golangci-lint config; fix all approved-linter findings
.golangci.yml is the prompts-repo standard verbatim plus one approved
exception (paralleltest, sneak 2026-07-06). Roughly 1,500 findings
fixed:
- autofix sweep (wsl_v5/nlreturn/intrange/modernize formatting), with
the misspell autofix REVERTED where it rewrote authentic C game text
("missle vanishes" stays, with nolint and a comment)
- error handling: errcheck sites get real handling — saveFile now
closes explicitly and removes corrupt saves, scoreboard writes are
documented best-effort, err113 sentinel errors (ErrSaveOutOfDate,
ErrScreenTooSmall); panics allowed for unrecoverable states per
MEMORY.md policy
- gosec: real fixes (ParseInt for SEED, 0600 scorefile) and justified
per-line nolints for provably-bounded conversions (randomMonsterLetter
helper collapses eight rnd(26)+'A' sites)
- API tidying from linters: pointer receivers on flag types
(recvcheck), msg helpers renamed addmsgf/doaddf/Printwf/MvPrintwf
(goprintffuncname), myExit()/findFloor(monst)/mkGameInput(t) drop
always-constant params (unparam), gameEnd carries no status
- gocritic/staticcheck: if-else chains to switches, the pack.c
inventory filter untangled into matchesFilter, main.go split so
defers run before exit (exitAfterDefer, funlen)
- revive doc comments on all exported flag types/consts/methods
Remaining findings are confined to linters pending sneak's exception
decision (mnd, gochecknoglobals, cyclop, nestif, gocognit, exhaustive,
goconst, testpackage); TODO.md records the state. MEMORY.md added at
repo root as the project's agent working notes.
This commit is contained in:
166
game/command.go
166
game/command.go
@@ -6,6 +6,7 @@ package game
|
||||
// bracketing (command.c command).
|
||||
func (g *RogueGame) command() {
|
||||
p := &g.Player
|
||||
|
||||
ntimes := 1 // number of player moves
|
||||
if p.On(Hasted) {
|
||||
ntimes++
|
||||
@@ -13,6 +14,7 @@ func (g *RogueGame) command() {
|
||||
// Let the daemons start up
|
||||
g.DoDaemons(Before)
|
||||
g.DoFuses(Before)
|
||||
|
||||
for ; ntimes > 0; ntimes-- {
|
||||
g.Again = false
|
||||
if g.HasHit {
|
||||
@@ -26,29 +28,37 @@ func (g *RogueGame) command() {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
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 {
|
||||
if g.Running || g.ToDeath {
|
||||
switch {
|
||||
case g.Running || g.ToDeath:
|
||||
ch = g.RunCh
|
||||
} else if g.Count != 0 {
|
||||
case g.Count != 0:
|
||||
ch = g.countCh
|
||||
} else {
|
||||
default:
|
||||
ch = g.readchar()
|
||||
|
||||
g.MoveOn = false
|
||||
if g.Msgs.Mpos != 0 { // erase message if its there
|
||||
g.msg("")
|
||||
@@ -57,6 +67,7 @@ func (g *RogueGame) command() {
|
||||
} else {
|
||||
ch = '.'
|
||||
}
|
||||
|
||||
if g.NoCommand != 0 {
|
||||
if g.NoCommand--; g.NoCommand == 0 {
|
||||
p.Flags.Set(Awake)
|
||||
@@ -67,14 +78,14 @@ func (g *RogueGame) command() {
|
||||
g.newCount = false
|
||||
if isDigit(ch) {
|
||||
g.Count = 0
|
||||
|
||||
g.newCount = true
|
||||
for isDigit(ch) {
|
||||
g.Count = g.Count*10 + int(ch-'0')
|
||||
if g.Count > 255 {
|
||||
g.Count = 255
|
||||
}
|
||||
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
|
||||
@@ -93,8 +104,9 @@ func (g *RogueGame) command() {
|
||||
if g.Count != 0 && !g.Running {
|
||||
g.Count--
|
||||
}
|
||||
|
||||
if ch != 'a' && ch != Escape &&
|
||||
!(g.Running || g.Count != 0 || g.ToDeath) {
|
||||
!g.Running && g.Count == 0 && !g.ToDeath {
|
||||
g.LLastComm = g.LastComm
|
||||
g.LLastDir = g.LastDir
|
||||
g.LLastPick = g.LastPick
|
||||
@@ -102,6 +114,7 @@ func (g *RogueGame) command() {
|
||||
g.LastDir = 0
|
||||
g.LastPick = nil
|
||||
}
|
||||
|
||||
g.dispatch(ch)
|
||||
// turn off flags if no longer needed
|
||||
if !g.Running {
|
||||
@@ -112,20 +125,25 @@ func (g *RogueGame) command() {
|
||||
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 {
|
||||
@@ -137,28 +155,35 @@ func (g *RogueGame) command() {
|
||||
// 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.addmsg("there is ")
|
||||
g.addmsgf("there is ")
|
||||
}
|
||||
g.addmsg("nothing here")
|
||||
|
||||
g.addmsgf("nothing here")
|
||||
|
||||
if !g.Options.Terse {
|
||||
g.addmsg(" to pick up")
|
||||
g.addmsgf(" to pick up")
|
||||
}
|
||||
|
||||
g.endmsg()
|
||||
}
|
||||
case '!':
|
||||
@@ -201,36 +226,46 @@ over:
|
||||
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.addmsg("I see ")
|
||||
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':
|
||||
@@ -246,6 +281,7 @@ over:
|
||||
} else {
|
||||
ch = g.LastComm
|
||||
g.Again = true
|
||||
|
||||
goto over
|
||||
}
|
||||
case 'q':
|
||||
@@ -327,15 +363,18 @@ over:
|
||||
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.addmsg("You have found ")
|
||||
g.addmsgf("You have found ")
|
||||
}
|
||||
if g.Level.Char(g.Delta.Y, g.Delta.X) != Trap {
|
||||
|
||||
switch {
|
||||
case g.Level.Char(g.Delta.Y, g.Delta.X) != Trap:
|
||||
g.msg("no trap there")
|
||||
} else if p.On(Hallucinating) {
|
||||
case p.On(Hallucinating):
|
||||
g.msg("%s", trName[g.rnd(NumTrapTypes)])
|
||||
} else {
|
||||
default:
|
||||
g.msg("%s", trName[*fp&FTrapMask])
|
||||
fp.Set(FSeen)
|
||||
}
|
||||
@@ -352,6 +391,7 @@ over:
|
||||
} else {
|
||||
ch = g.DirCh
|
||||
g.countCh = g.DirCh
|
||||
|
||||
goto over
|
||||
}
|
||||
case ')':
|
||||
@@ -381,6 +421,7 @@ over:
|
||||
// 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)
|
||||
@@ -452,62 +493,81 @@ 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.addmsg("you found ")
|
||||
g.addmsgf("you found ")
|
||||
}
|
||||
|
||||
if p.On(Hallucinating) {
|
||||
g.msg("%s", trName[g.rnd(NumTrapTypes)])
|
||||
} else {
|
||||
g.msg("%s", 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)
|
||||
}
|
||||
@@ -523,28 +583,35 @@ func (g *RogueGame) help() {
|
||||
// typed a funny character.
|
||||
if helpch != '*' {
|
||||
g.move(0, 0)
|
||||
|
||||
for _, strp := range 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 helpStr {
|
||||
if strp.Print {
|
||||
numprint++
|
||||
}
|
||||
}
|
||||
|
||||
if numprint&1 == 1 { // round odd numbers up
|
||||
numprint++
|
||||
}
|
||||
|
||||
numprint /= 2
|
||||
if numprint > NumLines-1 {
|
||||
numprint = NumLines - 1
|
||||
@@ -552,24 +619,32 @@ func (g *RogueGame) help() {
|
||||
|
||||
hw := g.scr.Hw
|
||||
hw.Clear()
|
||||
|
||||
cnt := 0
|
||||
|
||||
for _, strp := range 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(' ')
|
||||
@@ -603,23 +678,29 @@ var identList = []helpEntry{
|
||||
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 identList {
|
||||
if hp.Ch == ch {
|
||||
str = hp.Desc
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g.msg("'%s': %s", unctrl(ch), str)
|
||||
}
|
||||
|
||||
@@ -628,6 +709,7 @@ 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 {
|
||||
@@ -642,12 +724,14 @@ 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 {
|
||||
@@ -664,7 +748,9 @@ 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
|
||||
}
|
||||
|
||||
@@ -676,11 +762,16 @@ func (g *RogueGame) call() {
|
||||
if obj == nil {
|
||||
return
|
||||
}
|
||||
var op *ObjInfo
|
||||
var elsewise string
|
||||
var know *bool
|
||||
var guess *string
|
||||
|
||||
var (
|
||||
op *ObjInfo
|
||||
elsewise string
|
||||
know *bool
|
||||
guess *string
|
||||
)
|
||||
|
||||
it := &g.Items
|
||||
|
||||
switch obj.Kind {
|
||||
case KindRing:
|
||||
op = &it.Rings[obj.Which]
|
||||
@@ -696,14 +787,18 @@ func (g *RogueGame) call() {
|
||||
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
|
||||
@@ -712,16 +807,21 @@ func (g *RogueGame) call() {
|
||||
} else {
|
||||
fromGuess = elsewise != "" && elsewise == *guess
|
||||
}
|
||||
|
||||
if know != nil && *know {
|
||||
g.msg("that has already been identified")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if fromGuess {
|
||||
if !g.Options.Terse {
|
||||
g.addmsg("Was ")
|
||||
g.addmsgf("Was ")
|
||||
}
|
||||
|
||||
g.msg("called \"%s\"", elsewise)
|
||||
}
|
||||
|
||||
g.msg("%s", g.chooseTerse("call it: ", "what do you want to call it? "))
|
||||
|
||||
buf := elsewise
|
||||
@@ -735,23 +835,29 @@ func (g *RogueGame) current(cur *Object, how, where string) {
|
||||
g.After = false
|
||||
if cur != nil {
|
||||
if !g.Options.Terse {
|
||||
g.addmsg("you are %s (", how)
|
||||
g.addmsgf("you are %s (", how)
|
||||
}
|
||||
|
||||
g.InvDescribe = false
|
||||
g.addmsg("%c) %s", cur.PackCh, g.invName(cur, true))
|
||||
g.addmsgf("%c) %s", cur.PackCh, g.invName(cur, true))
|
||||
|
||||
g.InvDescribe = true
|
||||
if where != "" {
|
||||
g.addmsg(" %s", where)
|
||||
g.addmsgf(" %s", where)
|
||||
}
|
||||
|
||||
g.endmsg()
|
||||
} else {
|
||||
if !g.Options.Terse {
|
||||
g.addmsg("you are ")
|
||||
g.addmsgf("you are ")
|
||||
}
|
||||
g.addmsg("%s nothing", how)
|
||||
|
||||
g.addmsgf("%s nothing", how)
|
||||
|
||||
if where != "" {
|
||||
g.addmsg(" %s", where)
|
||||
g.addmsgf(" %s", where)
|
||||
}
|
||||
|
||||
g.endmsg()
|
||||
}
|
||||
}
|
||||
@@ -762,7 +868,9 @@ 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 {
|
||||
|
||||
Reference in New Issue
Block a user