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:
2026-07-07 00:03:45 +02:00
parent 3ed7931676
commit 5ba9fe8f66
49 changed files with 1965 additions and 410 deletions

View File

@@ -17,25 +17,30 @@ var rdesConn = [MaxRooms][MaxRooms]bool{
// doPassages draws all the passages on a level (passages.c do_passages).
func (g *RogueGame) doPassages() {
var isconn [MaxRooms][MaxRooms]bool
var ingraph [MaxRooms]bool
var (
isconn [MaxRooms][MaxRooms]bool
ingraph [MaxRooms]bool
)
// starting with one room, connect it to a random adjacent room and
// then pick a new room to start with.
roomcount := 1
r1 := g.rnd(MaxRooms)
ingraph[r1] = true
for {
// find a room to connect with
j := 0
r2 := -1
for i := 0; i < MaxRooms; i++ {
for i := range MaxRooms {
if rdesConn[r1][i] && !ingraph[i] {
if j++; g.rnd(j) == 0 {
r2 = i
}
}
}
if j == 0 {
// if no adjacent rooms are outside the graph, pick a new room
// to look from
@@ -48,12 +53,13 @@ func (g *RogueGame) doPassages() {
} else {
// otherwise, connect new room to the graph, and draw a tunnel
// to it
ingraph[r2] = true
ingraph[r2] = true //nolint:gosec // G602: rnd(MaxRooms) bounded
g.conn(r1, r2)
isconn[r1][r2] = true
isconn[r2][r1] = true
isconn[r2][r1] = true //nolint:gosec // G602: rnd(MaxRooms) bounded
roomcount++
}
if roomcount >= MaxRooms {
break
}
@@ -66,7 +72,8 @@ func (g *RogueGame) doPassages() {
// find an adjacent room not already connected
j := 0
r2 := -1
for i := 0; i < MaxRooms; i++ {
for i := range MaxRooms {
if rdesConn[r1][i] && !isconn[r1][i] {
if j++; g.rnd(j) == 0 {
r2 = i
@@ -77,17 +84,21 @@ func (g *RogueGame) doPassages() {
if j != 0 {
g.conn(r1, r2)
isconn[r1][r2] = true
isconn[r2][r1] = true
isconn[r2][r1] = true //nolint:gosec // G602: rnd(MaxRooms) bounded
}
}
g.passnum()
}
// conn draws a corridor from a room in a certain direction (passages.c
// conn).
func (g *RogueGame) conn(r1, r2 int) {
var rm int
var direc byte
var (
rm int
direc byte
)
if r1 < r2 {
rm = r1
if r1+1 == r2 {
@@ -103,42 +114,52 @@ func (g *RogueGame) conn(r1, r2 int) {
direc = 'd'
}
}
rpf := &g.Level.Rooms[rm]
// Set up the movement variables, in two cases: first drawing one down.
var rpt *Room
var del, turnDelta, spos, epos Coord
var distance, turnDistance int
var (
rpt *Room
del, turnDelta, spos, epos Coord
distance, turnDistance int
)
if direc == 'd' {
rmt := rm + 3 // room # of dest
rpt = &g.Level.Rooms[rmt] // room pointer of dest
del = Coord{X: 0, Y: 1} // direction of move
spos = rpf.Pos // start of move
epos = rpt.Pos // end of move
if !rpf.Flags.Has(Gone) { // if not gone pick door pos
for {
spos.X = rpf.Pos.X + g.rnd(rpf.Max.X-2) + 1
spos.Y = rpf.Pos.Y + rpf.Max.Y - 1
if !(rpf.Flags.Has(Maze) && !g.Level.FlagsAt(spos.Y, spos.X).Has(FPassage)) {
if !rpf.Flags.Has(Maze) || g.Level.FlagsAt(spos.Y, spos.X).Has(FPassage) {
break
}
}
}
if !rpt.Flags.Has(Gone) {
for {
epos.X = rpt.Pos.X + g.rnd(rpt.Max.X-2) + 1
if !(rpt.Flags.Has(Maze) && !g.Level.FlagsAt(epos.Y, epos.X).Has(FPassage)) {
if !rpt.Flags.Has(Maze) || g.Level.FlagsAt(epos.Y, epos.X).Has(FPassage) {
break
}
}
}
distance = abs(spos.Y-epos.Y) - 1 // distance to move
turnDelta.Y = 0 // direction to turn
turnDelta.Y = 0 // direction to turn
if spos.X < epos.X {
turnDelta.X = 1
} else {
turnDelta.X = -1
}
turnDistance = abs(spos.X - epos.X) // how far to turn
} else { // setup for moving right
rmt := rm + 1
@@ -146,29 +167,34 @@ func (g *RogueGame) conn(r1, r2 int) {
del = Coord{X: 1, Y: 0}
spos = rpf.Pos
epos = rpt.Pos
if !rpf.Flags.Has(Gone) {
for {
spos.X = rpf.Pos.X + rpf.Max.X - 1
spos.Y = rpf.Pos.Y + g.rnd(rpf.Max.Y-2) + 1
if !(rpf.Flags.Has(Maze) && !g.Level.FlagsAt(spos.Y, spos.X).Has(FPassage)) {
if !rpf.Flags.Has(Maze) || g.Level.FlagsAt(spos.Y, spos.X).Has(FPassage) {
break
}
}
}
if !rpt.Flags.Has(Gone) {
for {
epos.Y = rpt.Pos.Y + g.rnd(rpt.Max.Y-2) + 1
if !(rpt.Flags.Has(Maze) && !g.Level.FlagsAt(epos.Y, epos.X).Has(FPassage)) {
if !rpt.Flags.Has(Maze) || g.Level.FlagsAt(epos.Y, epos.X).Has(FPassage) {
break
}
}
}
distance = abs(spos.X-epos.X) - 1
if spos.Y < epos.Y {
turnDelta.Y = 1
} else {
turnDelta.Y = -1
}
turnDelta.X = 0
turnDistance = abs(spos.Y - epos.Y)
}
@@ -182,6 +208,7 @@ func (g *RogueGame) conn(r1, r2 int) {
} else {
g.putpass(spos)
}
if !rpt.Flags.Has(Gone) {
g.door(rpt, epos)
} else {
@@ -203,9 +230,12 @@ func (g *RogueGame) conn(r1, r2 int) {
}
// Continue digging along
g.putpass(curr)
distance--
}
curr.X += del.X
curr.Y += del.Y
if curr != epos {
g.msg("warning, connectivity problem on this level")
@@ -217,6 +247,7 @@ func (g *RogueGame) conn(r1, r2 int) {
func (g *RogueGame) putpass(cp Coord) {
pp := g.Level.At(cp.Y, cp.X)
pp.Flags.Set(FPassage)
if g.rnd(10)+1 < g.Depth && g.rnd(40) == 0 {
pp.Flags.Clear(FReal)
} else {
@@ -240,6 +271,7 @@ func (g *RogueGame) door(rm *Room, cp Coord) {
} else {
pp.Ch = '|'
}
pp.Flags.Clear(FReal)
} else {
pp.Ch = Door
@@ -250,7 +282,7 @@ func (g *RogueGame) door(rm *Room, cp Coord) {
// (passages.c add_pass).
func (g *RogueGame) addPass() {
for y := 1; y < NumLines-1; y++ {
for x := 0; x < NumCols; x++ {
for x := range NumCols {
pp := g.Level.At(y, x)
if pp.Flags.Has(FPassage) || pp.Ch == Door ||
(!pp.Flags.Has(FReal) && (pp.Ch == '|' || pp.Ch == '-')) {
@@ -258,19 +290,24 @@ func (g *RogueGame) addPass() {
if pp.Flags.Has(FPassage) {
ch = Passage
}
pp.Flags.Set(FSeen)
g.move(y, x)
if pp.Monst != nil {
switch {
case pp.Monst != nil:
pp.Monst.OldCh = pp.Ch
} else if pp.Flags.Has(FReal) {
case pp.Flags.Has(FReal):
g.addch(ch)
} else {
default:
g.standout()
if pp.Flags.Has(FPassage) {
g.addch(Passage)
} else {
g.addch(Door)
}
g.standend()
}
}
@@ -281,10 +318,12 @@ func (g *RogueGame) addPass() {
// passnum assigns a number to each passageway (passages.c passnum).
func (g *RogueGame) passnum() {
g.pnum = 0
g.newpnum = false
for i := range g.Level.Passages {
g.Level.Passages[i].Exits = g.Level.Passages[i].Exits[:0]
}
for i := range g.Level.Rooms {
rp := &g.Level.Rooms[i]
for j := range rp.Exits {
@@ -300,10 +339,12 @@ func (g *RogueGame) numpass(y, x int) {
if x >= NumCols || x < 0 || y >= NumLines || y <= 0 {
return
}
fp := g.Level.FlagsAt(y, x)
if fp.Has(FPassNum) {
return
}
if g.newpnum {
g.pnum++
g.newpnum = false
@@ -317,7 +358,8 @@ func (g *RogueGame) numpass(y, x int) {
} else if !fp.Has(FPassage) {
return
}
*fp |= PlaceFlags(g.pnum)
*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)
@@ -330,5 +372,6 @@ func abs(n int) int {
if n < 0 {
return -n
}
return n
}