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:
160
game/fight.go
160
game/fight.go
@@ -48,20 +48,27 @@ func (g *RogueGame) setMname(tp *Monster) string {
|
||||
if g.Options.Terse {
|
||||
return "it"
|
||||
}
|
||||
|
||||
return "something"
|
||||
}
|
||||
|
||||
var mname string
|
||||
|
||||
if g.Player.On(Hallucinating) {
|
||||
ch := int(g.mvinch(tp.Pos.Y, tp.Pos.X))
|
||||
if !isUpper(byte(ch)) {
|
||||
ch = g.rnd(26)
|
||||
var idx int
|
||||
|
||||
ch := g.mvinch(tp.Pos.Y, tp.Pos.X)
|
||||
if isUpper(ch) {
|
||||
idx = int(ch - 'A')
|
||||
} else {
|
||||
ch -= 'A'
|
||||
idx = g.rnd(26)
|
||||
}
|
||||
mname = g.Monsters[ch].Name
|
||||
|
||||
mname = g.Monsters[idx].Name
|
||||
} else {
|
||||
mname = g.Monsters[tp.Type-'A'].Name
|
||||
}
|
||||
|
||||
return "the " + mname
|
||||
}
|
||||
|
||||
@@ -82,37 +89,46 @@ func (g *RogueGame) fight(mp Coord, weap *Object, thrown bool) bool {
|
||||
if tp.Type == 'X' && tp.Disguise != 'X' && !p.On(Blind) {
|
||||
tp.Disguise = 'X'
|
||||
if p.On(Hallucinating) {
|
||||
g.mvaddch(tp.Pos.Y, tp.Pos.X, byte(g.rnd(26)+'A'))
|
||||
g.mvaddch(tp.Pos.Y, tp.Pos.X, g.randomMonsterLetter())
|
||||
}
|
||||
|
||||
g.msg("%s", g.chooseStr("heavy! That's a nasty critter!",
|
||||
"wait! That's a xeroc!"))
|
||||
|
||||
if !thrown {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
mname := g.setMname(tp)
|
||||
didHit := false
|
||||
|
||||
g.HasHit = g.Options.Terse && !g.ToDeath
|
||||
if g.rollEm(&p.Creature, &tp.Creature, weap, thrown) {
|
||||
didHit = false
|
||||
|
||||
if thrown {
|
||||
g.thunk(weap, mname, g.Options.Terse)
|
||||
} else {
|
||||
g.hit("", mname, g.Options.Terse)
|
||||
}
|
||||
|
||||
if p.On(CanConfuse) {
|
||||
didHit = true
|
||||
|
||||
tp.Flags.Set(Confused)
|
||||
p.Flags.Clear(CanConfuse)
|
||||
g.endmsg()
|
||||
g.HasHit = false
|
||||
g.msg("your hands stop glowing %s", g.pickColor("red"))
|
||||
}
|
||||
|
||||
if tp.Stats.HP <= 0 {
|
||||
g.killed(tp, true)
|
||||
} else if didHit && !p.On(Blind) {
|
||||
g.msg("%s appears confused", mname)
|
||||
}
|
||||
|
||||
didHit = true
|
||||
} else {
|
||||
if thrown {
|
||||
@@ -121,6 +137,7 @@ func (g *RogueGame) fight(mp Coord, weap *Object, thrown bool) bool {
|
||||
g.miss("", mname, g.Options.Terse)
|
||||
}
|
||||
}
|
||||
|
||||
return didHit
|
||||
}
|
||||
|
||||
@@ -132,29 +149,35 @@ func (g *RogueGame) attack(mp *Monster) int {
|
||||
// going on at the time.
|
||||
g.Running = false
|
||||
g.Count = 0
|
||||
|
||||
g.Quiet = 0
|
||||
if g.ToDeath && !mp.On(Targeted) {
|
||||
g.ToDeath = false
|
||||
g.Kamikaze = false
|
||||
}
|
||||
|
||||
if mp.Type == 'X' && mp.Disguise != 'X' && !p.On(Blind) {
|
||||
mp.Disguise = 'X'
|
||||
if p.On(Hallucinating) {
|
||||
g.mvaddch(mp.Pos.Y, mp.Pos.X, byte(g.rnd(26)+'A'))
|
||||
g.mvaddch(mp.Pos.Y, mp.Pos.X, g.randomMonsterLetter())
|
||||
}
|
||||
}
|
||||
|
||||
mname := g.setMname(mp)
|
||||
oldhp := p.Stats.HP
|
||||
removed := false
|
||||
|
||||
if g.rollEm(&mp.Creature, &p.Creature, nil, false) {
|
||||
if mp.Type != 'I' {
|
||||
if g.HasHit {
|
||||
g.addmsg(". ")
|
||||
g.addmsgf(". ")
|
||||
}
|
||||
|
||||
g.hit(mname, "", false)
|
||||
} else if g.HasHit {
|
||||
g.endmsg()
|
||||
}
|
||||
|
||||
g.HasHit = false
|
||||
if p.Stats.HP <= 0 {
|
||||
g.death(mp.Type) // Bye bye life ...
|
||||
@@ -163,10 +186,12 @@ func (g *RogueGame) attack(mp *Monster) int {
|
||||
if oldhp > g.MaxHit {
|
||||
g.MaxHit = oldhp
|
||||
}
|
||||
|
||||
if p.Stats.HP <= g.MaxHit {
|
||||
g.ToDeath = false
|
||||
}
|
||||
}
|
||||
|
||||
if !mp.On(Cancelled) {
|
||||
switch mp.Type {
|
||||
case 'A':
|
||||
@@ -175,13 +200,17 @@ func (g *RogueGame) attack(mp *Monster) int {
|
||||
case 'I':
|
||||
// The ice monster freezes you
|
||||
p.Flags.Clear(Awake)
|
||||
|
||||
if g.NoCommand == 0 {
|
||||
g.addmsg("you are frozen")
|
||||
g.addmsgf("you are frozen")
|
||||
|
||||
if !g.Options.Terse {
|
||||
g.addmsg(" by the %s", mname)
|
||||
g.addmsgf(" by the %s", mname)
|
||||
}
|
||||
|
||||
g.endmsg()
|
||||
}
|
||||
|
||||
g.NoCommand += g.rnd(2) + 2
|
||||
if g.NoCommand > BoreLevel {
|
||||
g.death('h')
|
||||
@@ -191,6 +220,7 @@ func (g *RogueGame) attack(mp *Monster) int {
|
||||
if !g.save(VsPoison) {
|
||||
if !p.IsWearing(RingSustainStrength) {
|
||||
g.chgStr(-1)
|
||||
|
||||
if !g.Options.Terse {
|
||||
g.msg("you feel a bite in your leg and now feel weaker")
|
||||
} else {
|
||||
@@ -211,36 +241,45 @@ func (g *RogueGame) attack(mp *Monster) int {
|
||||
if mp.Type == 'W' {
|
||||
chance = 15
|
||||
}
|
||||
|
||||
if g.rnd(100) < chance {
|
||||
var fewer int
|
||||
|
||||
if mp.Type == 'W' {
|
||||
if p.Stats.Exp == 0 {
|
||||
g.death('W') // All levels gone
|
||||
}
|
||||
|
||||
if p.Stats.Lvl--; p.Stats.Lvl == 0 {
|
||||
p.Stats.Exp = 0
|
||||
p.Stats.Lvl = 1
|
||||
} else {
|
||||
p.Stats.Exp = eLevels[p.Stats.Lvl-1] + 1
|
||||
}
|
||||
|
||||
fewer = g.roll(1, 10)
|
||||
} else {
|
||||
fewer = g.roll(1, 3)
|
||||
}
|
||||
|
||||
p.Stats.HP -= fewer
|
||||
|
||||
p.Stats.MaxHP -= fewer
|
||||
if p.Stats.HP <= 0 {
|
||||
p.Stats.HP = 1
|
||||
}
|
||||
|
||||
if p.Stats.MaxHP <= 0 {
|
||||
g.death(mp.Type)
|
||||
}
|
||||
|
||||
g.msg("you suddenly feel weaker")
|
||||
}
|
||||
case 'F':
|
||||
// Venus Flytrap stops the poor guy from moving
|
||||
p.Flags.Set(Held)
|
||||
p.VfHit++
|
||||
|
||||
g.Monsters['F'-'A'].Stats.Dmg = DiceSpec{{Count: p.VfHit, Sides: 1}}
|
||||
if p.Stats.HP--; p.Stats.HP <= 0 {
|
||||
g.death('F')
|
||||
@@ -248,15 +287,20 @@ func (g *RogueGame) attack(mp *Monster) int {
|
||||
case 'L':
|
||||
// Leprechaun steals some gold
|
||||
lastpurse := p.Purse
|
||||
|
||||
p.Purse -= g.goldCalc()
|
||||
if !g.save(VsMagic) {
|
||||
p.Purse -= g.goldCalc() + g.goldCalc() + g.goldCalc() + g.goldCalc()
|
||||
}
|
||||
|
||||
if p.Purse < 0 {
|
||||
p.Purse = 0
|
||||
}
|
||||
|
||||
g.removeMon(mp.Pos, mp, false)
|
||||
|
||||
removed = true
|
||||
|
||||
if p.Purse != lastpurse {
|
||||
g.msg("your purse feels lighter")
|
||||
}
|
||||
@@ -264,7 +308,9 @@ func (g *RogueGame) attack(mp *Monster) int {
|
||||
// Nymphs steal a magic item; look through the pack and
|
||||
// pick out one we like.
|
||||
var steal *Object
|
||||
|
||||
nobj := 0
|
||||
|
||||
for _, obj := range p.Pack {
|
||||
if obj != p.CurArmor && obj != p.CurWeapon &&
|
||||
obj != p.CurRing[Left] && obj != p.CurRing[Right] &&
|
||||
@@ -274,9 +320,12 @@ func (g *RogueGame) attack(mp *Monster) int {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if steal != nil {
|
||||
g.removeMon(mp.Pos, g.Level.MonsterAt(mp.Pos.Y, mp.Pos.X), false)
|
||||
|
||||
removed = true
|
||||
|
||||
g.leavePack(steal, false, false)
|
||||
g.msg("she stole %s!", g.invName(steal, true))
|
||||
}
|
||||
@@ -284,25 +333,31 @@ func (g *RogueGame) attack(mp *Monster) int {
|
||||
}
|
||||
} else if mp.Type != 'I' {
|
||||
if g.HasHit {
|
||||
g.addmsg(". ")
|
||||
g.addmsgf(". ")
|
||||
g.HasHit = false
|
||||
}
|
||||
|
||||
if mp.Type == 'F' {
|
||||
p.Stats.HP -= p.VfHit
|
||||
if p.Stats.HP <= 0 {
|
||||
g.death(mp.Type) // Bye bye life ...
|
||||
}
|
||||
}
|
||||
|
||||
g.miss(mname, "", false)
|
||||
}
|
||||
|
||||
if g.Options.FightFlush && !g.ToDeath {
|
||||
g.flushType()
|
||||
}
|
||||
|
||||
g.Count = 0
|
||||
g.status()
|
||||
|
||||
if removed {
|
||||
return -1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -310,6 +365,7 @@ func (g *RogueGame) attack(mp *Monster) int {
|
||||
func (g *RogueGame) swing(atLvl, opArm, wplus int) bool {
|
||||
res := g.rnd(20)
|
||||
need := (20 - atLvl) - opArm
|
||||
|
||||
return res+wplus >= need
|
||||
}
|
||||
|
||||
@@ -318,12 +374,17 @@ func (g *RogueGame) rollEm(thatt, thdef *Creature, weap *Object, hurl bool) bool
|
||||
p := &g.Player
|
||||
att := &thatt.Stats
|
||||
def := &thdef.Stats
|
||||
var attacks DiceSpec
|
||||
var hplus, dplus int
|
||||
|
||||
var (
|
||||
attacks DiceSpec
|
||||
hplus, dplus int
|
||||
)
|
||||
|
||||
if weap == nil {
|
||||
attacks = att.Dmg
|
||||
} else {
|
||||
hplus = weap.HPlus
|
||||
|
||||
dplus = weap.DPlus
|
||||
if weap == p.CurWeapon {
|
||||
if p.IsRing(Left, RingIncreaseDamage) {
|
||||
@@ -331,12 +392,14 @@ func (g *RogueGame) rollEm(thatt, thdef *Creature, weap *Object, hurl bool) bool
|
||||
} else if p.IsRing(Left, RingDexterity) {
|
||||
hplus += p.CurRing[Left].Bonus
|
||||
}
|
||||
|
||||
if p.IsRing(Right, RingIncreaseDamage) {
|
||||
dplus += p.CurRing[Right].Bonus
|
||||
} else if p.IsRing(Right, RingDexterity) {
|
||||
hplus += p.CurRing[Right].Bonus
|
||||
}
|
||||
}
|
||||
|
||||
attacks = weap.Damage
|
||||
if hurl {
|
||||
if weap.Flags.Has(Missile) && p.CurWeapon != nil &&
|
||||
@@ -354,29 +417,37 @@ func (g *RogueGame) rollEm(thatt, thdef *Creature, weap *Object, hurl bool) bool
|
||||
if !thdef.Flags.Has(Awake) {
|
||||
hplus += 4
|
||||
}
|
||||
|
||||
defArm := def.ArmorClass
|
||||
if def == &p.Stats {
|
||||
if p.CurArmor != nil {
|
||||
defArm = p.CurArmor.ArmorClass
|
||||
}
|
||||
|
||||
if p.IsRing(Left, RingProtection) {
|
||||
defArm -= p.CurRing[Left].Bonus
|
||||
}
|
||||
|
||||
if p.IsRing(Right, RingProtection) {
|
||||
defArm -= p.CurRing[Right].Bonus
|
||||
}
|
||||
}
|
||||
|
||||
didHit := false
|
||||
|
||||
for _, atk := range attacks {
|
||||
if g.swing(att.Lvl, defArm, hplus+strPlus[att.Str]) {
|
||||
proll := g.roll(atk.Count, atk.Sides)
|
||||
|
||||
damage := dplus + proll + addDam[att.Str]
|
||||
if damage > 0 {
|
||||
def.HP -= damage
|
||||
}
|
||||
|
||||
didHit = true
|
||||
}
|
||||
}
|
||||
|
||||
return didHit
|
||||
}
|
||||
|
||||
@@ -387,7 +458,9 @@ func cAtoi(s string) int {
|
||||
for i < len(s) && s[i] >= '0' && s[i] <= '9' {
|
||||
i++
|
||||
}
|
||||
|
||||
n, _ := strconv.Atoi(s[:i])
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -398,9 +471,11 @@ func prname(mname string, upper bool) string {
|
||||
if out == "" {
|
||||
out = "you"
|
||||
}
|
||||
|
||||
if upper {
|
||||
out = string(toUpper(out[0])) + out[1:]
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -409,12 +484,15 @@ func (g *RogueGame) thunk(weap *Object, mname string, noend bool) {
|
||||
if g.ToDeath {
|
||||
return
|
||||
}
|
||||
|
||||
if weap.Kind == KindWeapon {
|
||||
g.addmsg("the %s hits ", g.Items.Weapons[weap.Which].Name)
|
||||
g.addmsgf("the %s hits ", g.Items.Weapons[weap.Which].Name)
|
||||
} else {
|
||||
g.addmsg("you hit ")
|
||||
g.addmsgf("you hit ")
|
||||
}
|
||||
g.addmsg("%s", mname)
|
||||
|
||||
g.addmsgf("%s", mname)
|
||||
|
||||
if !noend {
|
||||
g.endmsg()
|
||||
}
|
||||
@@ -425,7 +503,9 @@ func (g *RogueGame) hit(er, ee string, noend bool) {
|
||||
if g.ToDeath {
|
||||
return
|
||||
}
|
||||
g.addmsg("%s", prname(er, true))
|
||||
|
||||
g.addmsgf("%s", prname(er, true))
|
||||
|
||||
var s string
|
||||
if g.Options.Terse {
|
||||
s = " hit"
|
||||
@@ -434,12 +514,16 @@ func (g *RogueGame) hit(er, ee string, noend bool) {
|
||||
if er != "" {
|
||||
i += 4
|
||||
}
|
||||
|
||||
s = hNames[i]
|
||||
}
|
||||
g.addmsg("%s", s)
|
||||
|
||||
g.addmsgf("%s", s)
|
||||
|
||||
if !g.Options.Terse {
|
||||
g.addmsg("%s", prname(ee, false))
|
||||
g.addmsgf("%s", prname(ee, false))
|
||||
}
|
||||
|
||||
if !noend {
|
||||
g.endmsg()
|
||||
}
|
||||
@@ -450,18 +534,24 @@ func (g *RogueGame) miss(er, ee string, noend bool) {
|
||||
if g.ToDeath {
|
||||
return
|
||||
}
|
||||
g.addmsg("%s", prname(er, true))
|
||||
|
||||
g.addmsgf("%s", prname(er, true))
|
||||
|
||||
i := 0
|
||||
if !g.Options.Terse {
|
||||
i = g.rnd(4)
|
||||
}
|
||||
|
||||
if er != "" {
|
||||
i += 4
|
||||
}
|
||||
g.addmsg("%s", mNames[i])
|
||||
|
||||
g.addmsgf("%s", mNames[i])
|
||||
|
||||
if !g.Options.Terse {
|
||||
g.addmsg(" %s", prname(ee, false))
|
||||
g.addmsgf(" %s", prname(ee, false))
|
||||
}
|
||||
|
||||
if !noend {
|
||||
g.endmsg()
|
||||
}
|
||||
@@ -472,12 +562,15 @@ func (g *RogueGame) bounce(weap *Object, mname string, noend bool) {
|
||||
if g.ToDeath {
|
||||
return
|
||||
}
|
||||
|
||||
if weap.Kind == KindWeapon {
|
||||
g.addmsg("the %s misses ", g.Items.Weapons[weap.Which].Name)
|
||||
g.addmsgf("the %s misses ", g.Items.Weapons[weap.Which].Name)
|
||||
} else {
|
||||
g.addmsg("you missed ")
|
||||
g.addmsgf("you missed ")
|
||||
}
|
||||
g.addmsg("%s", mname)
|
||||
|
||||
g.addmsgf("%s", mname)
|
||||
|
||||
if !noend {
|
||||
g.endmsg()
|
||||
}
|
||||
@@ -489,15 +582,19 @@ func (g *RogueGame) removeMon(mp Coord, tp *Monster, waskill bool) {
|
||||
for _, obj := range pack {
|
||||
obj.Pos = tp.Pos
|
||||
detachObj(&tp.Pack, obj)
|
||||
|
||||
if waskill {
|
||||
g.fall(obj, false)
|
||||
}
|
||||
}
|
||||
|
||||
g.Level.SetMonsterAt(mp.Y, mp.X, nil)
|
||||
g.mvaddch(mp.Y, mp.X, tp.OldCh)
|
||||
detachMon(&g.Level.Monsters, tp)
|
||||
|
||||
if tp.On(Targeted) {
|
||||
g.Kamikaze = false
|
||||
|
||||
g.ToDeath = false
|
||||
if g.Options.FightFlush {
|
||||
g.flushType()
|
||||
@@ -521,33 +618,40 @@ func (g *RogueGame) killed(tp *Monster, pr bool) {
|
||||
if ok {
|
||||
tp.Room.Gold = pos
|
||||
}
|
||||
|
||||
if ok && g.Depth >= g.MaxDepth {
|
||||
gold := newObject()
|
||||
gold.Kind = KindGold
|
||||
|
||||
gold.GoldValue = g.goldCalc()
|
||||
if g.save(VsMagic) {
|
||||
gold.GoldValue += g.goldCalc() + g.goldCalc() + g.goldCalc() + g.goldCalc()
|
||||
}
|
||||
|
||||
attachObj(&tp.Pack, gold)
|
||||
}
|
||||
}
|
||||
// Get rid of the monster.
|
||||
mname := g.setMname(tp)
|
||||
g.removeMon(tp.Pos, tp, true)
|
||||
|
||||
if pr {
|
||||
if g.HasHit {
|
||||
g.addmsg(". Defeated ")
|
||||
g.addmsgf(". Defeated ")
|
||||
g.HasHit = false
|
||||
} else {
|
||||
if !g.Options.Terse {
|
||||
g.addmsg("you have ")
|
||||
g.addmsgf("you have ")
|
||||
}
|
||||
g.addmsg("defeated ")
|
||||
|
||||
g.addmsgf("defeated ")
|
||||
}
|
||||
|
||||
g.msg("%s", mname)
|
||||
}
|
||||
// Do adjustments if he went up a level
|
||||
g.checkLevel()
|
||||
|
||||
if g.Options.FightFlush {
|
||||
g.flushType()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user