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:
120
game/things.go
120
game/things.go
@@ -11,8 +11,10 @@ import (
|
||||
// (things.c inv_name).
|
||||
func (g *RogueGame) invName(obj *Object, drop bool) string {
|
||||
var pb strings.Builder
|
||||
|
||||
which := obj.Which
|
||||
it := &g.Items
|
||||
|
||||
switch obj.Kind {
|
||||
case KindPotion:
|
||||
g.nameit(&pb, obj, "potion", it.PotColors[which], &it.Potions[which], nullstr)
|
||||
@@ -26,12 +28,15 @@ func (g *RogueGame) invName(obj *Object, drop bool) string {
|
||||
} else {
|
||||
fmt.Fprintf(&pb, "%d scrolls ", obj.Count)
|
||||
}
|
||||
|
||||
op := &it.Scrolls[which]
|
||||
if op.Know {
|
||||
|
||||
switch {
|
||||
case op.Know:
|
||||
fmt.Fprintf(&pb, "of %s", op.Name)
|
||||
} else if op.Guess != "" {
|
||||
case op.Guess != "":
|
||||
fmt.Fprintf(&pb, "called %s", op.Guess)
|
||||
} else {
|
||||
default:
|
||||
fmt.Fprintf(&pb, "titled '%s'", it.ScrNames[which])
|
||||
}
|
||||
case KindFood:
|
||||
@@ -50,19 +55,23 @@ func (g *RogueGame) invName(obj *Object, drop bool) string {
|
||||
}
|
||||
case KindWeapon:
|
||||
sp := it.Weapons[which].Name
|
||||
|
||||
if obj.Count > 1 {
|
||||
fmt.Fprintf(&pb, "%d ", obj.Count)
|
||||
} else {
|
||||
fmt.Fprintf(&pb, "A%s ", vowelstr(sp))
|
||||
}
|
||||
|
||||
if obj.Flags.Has(Known) {
|
||||
fmt.Fprintf(&pb, "%s %s", num(obj.HPlus, obj.DPlus, Weapon), sp)
|
||||
} else {
|
||||
pb.WriteString(sp)
|
||||
}
|
||||
|
||||
if obj.Count > 1 {
|
||||
pb.WriteString("s")
|
||||
}
|
||||
|
||||
if obj.Label != "" {
|
||||
fmt.Fprintf(&pb, " called %s", obj.Label)
|
||||
}
|
||||
@@ -70,13 +79,16 @@ func (g *RogueGame) invName(obj *Object, drop bool) string {
|
||||
sp := it.Armors[which].Name
|
||||
if obj.Flags.Has(Known) {
|
||||
fmt.Fprintf(&pb, "%s %s [", num(aClass[which]-obj.ArmorClass, 0, Armor), sp)
|
||||
|
||||
if !g.Options.Terse {
|
||||
pb.WriteString("protection ")
|
||||
}
|
||||
|
||||
fmt.Fprintf(&pb, "%d]", 10-obj.ArmorClass)
|
||||
} else {
|
||||
pb.WriteString(sp)
|
||||
}
|
||||
|
||||
if obj.Label != "" {
|
||||
fmt.Fprintf(&pb, " called %s", obj.Label)
|
||||
}
|
||||
@@ -87,20 +99,25 @@ func (g *RogueGame) invName(obj *Object, drop bool) string {
|
||||
}
|
||||
|
||||
out := pb.String()
|
||||
|
||||
if g.InvDescribe {
|
||||
p := &g.Player
|
||||
if obj == p.CurArmor {
|
||||
out += " (being worn)"
|
||||
}
|
||||
|
||||
if obj == p.CurWeapon {
|
||||
out += " (weapon in hand)"
|
||||
}
|
||||
if obj == p.CurRing[Left] {
|
||||
|
||||
switch obj {
|
||||
case p.CurRing[Left]:
|
||||
out += " (on left hand)"
|
||||
} else if obj == p.CurRing[Right] {
|
||||
case p.CurRing[Right]:
|
||||
out += " (on right hand)"
|
||||
}
|
||||
}
|
||||
|
||||
if out != "" {
|
||||
if drop && isUpper(out[0]) {
|
||||
out = string(toLower(out[0])) + out[1:]
|
||||
@@ -108,6 +125,7 @@ func (g *RogueGame) invName(obj *Object, drop bool) string {
|
||||
out = string(toUpper(out[0])) + out[1:]
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -115,28 +133,35 @@ func (g *RogueGame) invName(obj *Object, drop bool) string {
|
||||
// leavePack/detach vocabulary collision).
|
||||
func (g *RogueGame) dropIt() {
|
||||
p := &g.Player
|
||||
|
||||
ch := g.Level.Char(p.Pos.Y, p.Pos.X)
|
||||
if ch != Floor && ch != Passage {
|
||||
g.After = false
|
||||
g.msg("there is something there already")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
obj := g.getItem("drop", KindNone)
|
||||
if obj == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !g.dropCheck(obj) {
|
||||
return
|
||||
}
|
||||
|
||||
obj = g.leavePack(obj, true, !obj.Kind.MergesInPack())
|
||||
// Link it into the level object list
|
||||
attachObj(&g.Level.Objects, obj)
|
||||
g.Level.SetChar(p.Pos.Y, p.Pos.X, obj.Kind.Glyph())
|
||||
g.Level.FlagsAt(p.Pos.Y, p.Pos.X).Set(FDropped)
|
||||
|
||||
obj.Pos = p.Pos
|
||||
if obj.Kind == KindAmulet {
|
||||
g.HasAmulet = false
|
||||
}
|
||||
|
||||
g.msg("dropped %s", g.invName(obj, true))
|
||||
}
|
||||
|
||||
@@ -146,26 +171,34 @@ func (g *RogueGame) dropCheck(obj *Object) bool {
|
||||
if obj == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
p := &g.Player
|
||||
if obj != p.CurArmor && obj != p.CurWeapon &&
|
||||
obj != p.CurRing[Left] && obj != p.CurRing[Right] {
|
||||
return true
|
||||
}
|
||||
|
||||
if obj.Flags.Has(Cursed) {
|
||||
g.msg("you can't. It appears to be cursed")
|
||||
|
||||
return false
|
||||
}
|
||||
if obj == p.CurWeapon {
|
||||
|
||||
switch obj {
|
||||
case p.CurWeapon:
|
||||
p.CurWeapon = nil
|
||||
} else if obj == p.CurArmor {
|
||||
case p.CurArmor:
|
||||
g.wasteTime()
|
||||
|
||||
p.CurArmor = nil
|
||||
} else {
|
||||
default:
|
||||
hand := Right
|
||||
if obj == p.CurRing[Left] {
|
||||
hand = Left
|
||||
}
|
||||
|
||||
p.CurRing[hand] = nil
|
||||
|
||||
switch obj.RingKind() {
|
||||
case RingAddStrength:
|
||||
g.chgStr(-obj.Bonus)
|
||||
@@ -174,6 +207,7 @@ func (g *RogueGame) dropCheck(obj *Object) bool {
|
||||
g.Extinguish(DUnsee)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -193,6 +227,7 @@ func (g *RogueGame) newThing() *Object {
|
||||
} else {
|
||||
kind = pickOne(g, g.Items.Things[:])
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case 0:
|
||||
cur.Kind = KindPotion
|
||||
@@ -202,6 +237,7 @@ func (g *RogueGame) newThing() *Object {
|
||||
cur.Which = pickOne(g, g.Items.Scrolls[:])
|
||||
case 2:
|
||||
cur.Kind = KindFood
|
||||
|
||||
g.Player.NoFood = 0
|
||||
if g.rnd(10) != 0 {
|
||||
cur.Which = 0
|
||||
@@ -210,6 +246,7 @@ func (g *RogueGame) newThing() *Object {
|
||||
}
|
||||
case 3:
|
||||
g.initWeapon(cur, WeaponKind(pickOne(g, g.Items.Weapons[:NumWeaponTypes])))
|
||||
|
||||
if r := g.rnd(100); r < 10 {
|
||||
cur.Flags.Set(Cursed)
|
||||
cur.HPlus -= g.rnd(3) + 1
|
||||
@@ -219,6 +256,7 @@ func (g *RogueGame) newThing() *Object {
|
||||
case 4:
|
||||
cur.Kind = KindArmor
|
||||
cur.Which = pickOne(g, g.Items.Armors[:])
|
||||
|
||||
cur.ArmorClass = aClass[cur.Which]
|
||||
if r := g.rnd(100); r < 20 {
|
||||
cur.Flags.Set(Cursed)
|
||||
@@ -228,6 +266,7 @@ func (g *RogueGame) newThing() *Object {
|
||||
}
|
||||
case 5:
|
||||
cur.Kind = KindRing
|
||||
|
||||
cur.Which = pickOne(g, g.Items.Rings[:])
|
||||
switch cur.RingKind() {
|
||||
case RingAddStrength, RingProtection, RingDexterity, RingIncreaseDamage:
|
||||
@@ -243,6 +282,7 @@ func (g *RogueGame) newThing() *Object {
|
||||
cur.Which = pickOne(g, g.Items.Sticks[:])
|
||||
g.fixStick(cur)
|
||||
}
|
||||
|
||||
return cur
|
||||
}
|
||||
|
||||
@@ -255,6 +295,7 @@ func pickOne(g *RogueGame, info []ObjInfo) int {
|
||||
return idx
|
||||
}
|
||||
}
|
||||
|
||||
return 0 // bad pick_one: C resets to the start of the table
|
||||
}
|
||||
|
||||
@@ -272,20 +313,27 @@ type invPage struct {
|
||||
// (things.c discovered).
|
||||
func (g *RogueGame) discovered() {
|
||||
var ch byte
|
||||
|
||||
for {
|
||||
discList := false
|
||||
|
||||
if !g.Options.Terse {
|
||||
g.addmsg("for ")
|
||||
g.addmsgf("for ")
|
||||
}
|
||||
g.addmsg("what type")
|
||||
|
||||
g.addmsgf("what type")
|
||||
|
||||
if !g.Options.Terse {
|
||||
g.addmsg(" of object do you want a list")
|
||||
g.addmsgf(" of object do you want a list")
|
||||
}
|
||||
|
||||
g.msg("? (* for all)")
|
||||
|
||||
ch = g.readchar()
|
||||
switch ch {
|
||||
case Escape:
|
||||
g.msg("")
|
||||
|
||||
return
|
||||
case Potion, Scroll, Ring, Stick, '*':
|
||||
discList = true
|
||||
@@ -297,10 +345,12 @@ func (g *RogueGame) discovered() {
|
||||
Potion, Scroll, Ring, Stick)
|
||||
}
|
||||
}
|
||||
|
||||
if discList {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ch == '*' {
|
||||
g.printDisc(Potion)
|
||||
g.addLine("")
|
||||
@@ -320,6 +370,7 @@ func (g *RogueGame) discovered() {
|
||||
// (things.c print_disc).
|
||||
func (g *RogueGame) printDisc(typ byte) {
|
||||
var info []ObjInfo
|
||||
|
||||
switch typ {
|
||||
case Scroll:
|
||||
info = g.Items.Scrolls[:]
|
||||
@@ -330,18 +381,23 @@ func (g *RogueGame) printDisc(typ byte) {
|
||||
case Stick:
|
||||
info = g.Items.Sticks[:]
|
||||
}
|
||||
|
||||
order := make([]int, len(info))
|
||||
g.setOrder(order)
|
||||
|
||||
obj := Object{Count: 1}
|
||||
numFound := 0
|
||||
|
||||
for i := range info {
|
||||
if info[order[i]].Know || info[order[i]].Guess != "" {
|
||||
obj.Kind = objectKindForGlyph(typ)
|
||||
obj.Which = order[i]
|
||||
g.addLine("%s", g.invName(&obj, false))
|
||||
|
||||
numFound++
|
||||
}
|
||||
}
|
||||
|
||||
if numFound == 0 {
|
||||
g.addLine("%s", g.nothing(typ))
|
||||
}
|
||||
@@ -353,6 +409,7 @@ func (g *RogueGame) setOrder(order []int) {
|
||||
for i := range order {
|
||||
order[i] = i
|
||||
}
|
||||
|
||||
for i := len(order); i > 0; i-- {
|
||||
r := g.rnd(i)
|
||||
order[i-1], order[r] = order[r], order[i-1]
|
||||
@@ -368,6 +425,7 @@ func (g *RogueGame) addLine(format string, a ...any) int {
|
||||
pg := &g.invPage
|
||||
prompt := "--Press space to continue--"
|
||||
isFlush := format == flushSentinel
|
||||
|
||||
var line string
|
||||
if !isFlush {
|
||||
line = fmt.Sprintf(format, a...)
|
||||
@@ -375,36 +433,43 @@ func (g *RogueGame) addLine(format string, a ...any) int {
|
||||
|
||||
if pg.lineCnt == 0 {
|
||||
g.scr.Hw.Clear()
|
||||
|
||||
if g.Options.InvType == InvSlow {
|
||||
g.Msgs.Mpos = 0
|
||||
}
|
||||
}
|
||||
|
||||
if g.Options.InvType == InvSlow {
|
||||
if !isFlush && line != "" {
|
||||
if g.msg("%s", line) == Escape {
|
||||
return Escape
|
||||
}
|
||||
}
|
||||
|
||||
pg.lineCnt++
|
||||
} else {
|
||||
if !pg.init {
|
||||
pg.maxlen = len(prompt)
|
||||
pg.init = true
|
||||
}
|
||||
|
||||
if pg.lineCnt >= NumLines-1 || isFlush {
|
||||
if g.Options.InvType == InvOver && isFlush && !pg.newpage {
|
||||
// Overlay the accumulated list in a box at the top right
|
||||
// of the screen, prompt, and restore what was beneath.
|
||||
g.msg("")
|
||||
g.refresh()
|
||||
|
||||
saved := NewWindow(NumLines, NumCols)
|
||||
saved.CopyFrom(g.scr.Std)
|
||||
|
||||
lx := NumCols - pg.maxlen - 2
|
||||
for y := 0; y <= pg.lineCnt; y++ {
|
||||
for x := 0; x <= pg.maxlen; x++ {
|
||||
g.scr.Std.MvAddCh(y, lx+x, g.scr.Hw.MvInch(y, x))
|
||||
}
|
||||
}
|
||||
|
||||
g.scr.Std.MvAddStr(pg.lineCnt, lx, prompt)
|
||||
g.refresh()
|
||||
g.waitFor(' ')
|
||||
@@ -417,19 +482,24 @@ func (g *RogueGame) addLine(format string, a ...any) int {
|
||||
g.scr.Hw.Clear()
|
||||
g.refresh()
|
||||
}
|
||||
|
||||
pg.newpage = true
|
||||
pg.lineCnt = 0
|
||||
pg.maxlen = len(prompt)
|
||||
}
|
||||
if !isFlush && !(pg.lineCnt == 0 && line == "") {
|
||||
|
||||
if !isFlush && (pg.lineCnt != 0 || line != "") {
|
||||
g.scr.Hw.MvAddStr(pg.lineCnt, 0, line)
|
||||
|
||||
pg.lineCnt++
|
||||
if pg.maxlen < len(line) {
|
||||
pg.maxlen = len(line)
|
||||
}
|
||||
|
||||
pg.lastLine = line
|
||||
}
|
||||
}
|
||||
|
||||
return ^Escape
|
||||
}
|
||||
|
||||
@@ -447,6 +517,7 @@ func (g *RogueGame) endLine() {
|
||||
g.flushLine()
|
||||
}
|
||||
}
|
||||
|
||||
pg.lineCnt = 0
|
||||
pg.newpage = false
|
||||
}
|
||||
@@ -459,8 +530,10 @@ func (g *RogueGame) nothing(typ byte) string {
|
||||
} else {
|
||||
out = "Haven't discovered anything"
|
||||
}
|
||||
|
||||
if typ != '*' {
|
||||
var tystr string
|
||||
|
||||
switch typ {
|
||||
case Potion:
|
||||
tystr = "potion"
|
||||
@@ -471,8 +544,10 @@ func (g *RogueGame) nothing(typ byte) string {
|
||||
case Stick:
|
||||
tystr = "stick"
|
||||
}
|
||||
|
||||
out += fmt.Sprintf(" about any %ss", tystr)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -480,20 +555,22 @@ func (g *RogueGame) nothing(typ byte) string {
|
||||
// (things.c nameit).
|
||||
func (g *RogueGame) nameit(pb *strings.Builder, obj *Object, typ, which string,
|
||||
op *ObjInfo, prfunc func(*RogueGame, *Object) string) {
|
||||
if op.Know || op.Guess != "" {
|
||||
switch {
|
||||
case op.Know || op.Guess != "":
|
||||
if obj.Count == 1 {
|
||||
fmt.Fprintf(pb, "A %s ", typ)
|
||||
} else {
|
||||
fmt.Fprintf(pb, "%d %ss ", obj.Count, typ)
|
||||
}
|
||||
|
||||
if op.Know {
|
||||
fmt.Fprintf(pb, "of %s%s(%s)", op.Name, prfunc(g, obj), which)
|
||||
} else {
|
||||
fmt.Fprintf(pb, "called %s%s(%s)", op.Guess, prfunc(g, obj), which)
|
||||
}
|
||||
} else if obj.Count == 1 {
|
||||
case obj.Count == 1:
|
||||
fmt.Fprintf(pb, "A%s %s %s", vowelstr(which), which, typ)
|
||||
} else {
|
||||
default:
|
||||
fmt.Fprintf(pb, "%d %s %ss", obj.Count, which, typ)
|
||||
}
|
||||
}
|
||||
@@ -505,13 +582,17 @@ func nullstr(*RogueGame, *Object) string { return "" }
|
||||
// pr_list).
|
||||
func (g *RogueGame) prList() {
|
||||
if !g.Options.Terse {
|
||||
g.addmsg("for ")
|
||||
g.addmsgf("for ")
|
||||
}
|
||||
g.addmsg("what type")
|
||||
|
||||
g.addmsgf("what type")
|
||||
|
||||
if !g.Options.Terse {
|
||||
g.addmsg(" of object do you want a list")
|
||||
g.addmsgf(" of object do you want a list")
|
||||
}
|
||||
|
||||
g.msg("? ")
|
||||
|
||||
ch := g.readchar()
|
||||
switch ch {
|
||||
case Potion:
|
||||
@@ -533,14 +614,17 @@ func (g *RogueGame) prList() {
|
||||
// (things.c pr_spec).
|
||||
func (g *RogueGame) prSpec(info []ObjInfo) {
|
||||
lastprob := 0
|
||||
|
||||
i := byte('0')
|
||||
for idx := range info {
|
||||
if i == '9'+1 {
|
||||
i = 'a'
|
||||
}
|
||||
|
||||
g.addLine("%c: %s (%d%%)", i, info[idx].Name, info[idx].Prob-lastprob)
|
||||
lastprob = info[idx].Prob
|
||||
i++
|
||||
}
|
||||
|
||||
g.endLine()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user