Files
rgoue/game/creature.go
sneak 63d1e797e2 chore(lint): adopt canonical golangci-lint config
Replace .golangci.yml with the shared canonical config. The old
config's top-level linters-settings block was silently ignored under
the v2 schema, so the lll/funlen/cyclop/dupl thresholds now actually
apply. The four repo-specific disables (mnd, exhaustive, paralleltest,
testpackage) move out of the config into targeted in-code nolint
directives carrying their original approval dates, keeping the config
byte-identical to the canonical one.

Fixes surfaced by the stricter settings: t.Parallel() added to all 32
tests, 24 overlong lines wrapped or their comments tightened, tcell
control-code returns rewritten as character literals, dupl markers on
the identically-shaped item data tables, and two wsl_v5 defer cuddles.

No behavior changes. The repo has no golangci-lint version pin (no
Dockerfile or CI; make lint runs the host binary, currently v2.12.2),
so there was nothing to bump.
2026-08-07 20:45:02 +00:00

111 lines
3.2 KiB
Go

package game
// Creature is the _t arm of the C THING union: the player or a monster.
type Creature struct {
Pos Coord // position
Turn bool // if slowed, is it a turn to move
Type byte // what it is: 'A'..'Z' for monsters, '@' for the player
Disguise byte // what mimic looks like
OldCh byte // character that was where it was
// Dest is where it is running to — aliases live coords (hero pos,
// room gold, another monster's pos).
Dest *Coord
Flags CreatureFlags
Stats Stats
Room *Room // current room for thing
Pack []*Object // what the thing is carrying
}
// Monster is a hostile creature on the level.
type Monster struct {
Creature
}
// Player embeds Creature and owns the player-only state that was global
// in the C sources (cur_armor, purse, food_left, ...).
type Player struct {
Creature
CurArmor *Object // what he is wearing
CurWeapon *Object // which weapon he is wielding
CurRing [2]*Object // which rings are being worn (Left/Right)
PackUsed [26]bool // is the character used in the pack?
Inpack int // number of things in pack
Purse int // how much gold he has
FoodLeft int // amount of food in hero's stomach
HungryState int // how hungry is he (0..3)
NoFood int // number of levels without food
MaxStats Stats // the maximum for the player
VfHit int // number of times the flytrap has hit
}
// On is the C on(thing, flag) macro.
func (c *Creature) On(f CreatureFlags) bool { return c.Flags.Has(f) }
// IsRing is the C ISRING(hand, ring) macro.
func (p *Player) IsRing(hand int, ring RingKind) bool {
return p.CurRing[hand] != nil && p.CurRing[hand].RingKind() == ring
}
// IsWearing is the C ISWEARING(ring) macro: is the ring on either hand.
func (p *Player) IsWearing(ring RingKind) bool {
return p.IsRing(Left, ring) || p.IsRing(Right, ring)
}
// nextPackChar claims and returns the next unused pack character (pack.c
// pack_char).
func (p *Player) nextPackChar() byte {
for i := range p.PackUsed {
if !p.PackUsed[i] {
p.PackUsed[i] = true
return byte(i) + 'a'
}
}
return byte(len(p.PackUsed)) + 'a' // C would walk off the array here
}
// removeFromPack takes an item out of the pack: the whole entry, or one
// of a stack when all is false (the bookkeeping half of pack.c
// leave_pack). It returns the object that left the pack — a copy when
// newobj asks for a split.
func (p *Player) removeFromPack(obj *Object, newobj, all bool) *Object {
p.Inpack--
nobj := obj
if obj.Count > 1 && !all {
obj.Count--
if obj.Group != 0 {
p.Inpack++
}
if newobj {
copied := *obj
nobj = &copied
nobj.Count = 1
}
} else {
p.PackUsed[obj.PackCh-'a'] = false
detachObj(&p.Pack, obj)
}
return nobj
}
// attachMon pushes a monster onto the front of a list (list.c attach).
func attachMon(list *[]*Monster, item *Monster) {
*list = append([]*Monster{item}, *list...)
}
// detachMon removes a monster (by identity) from a list (list.c detach).
func detachMon(list *[]*Monster, item *Monster) {
for i, m := range *list {
if m == item {
*list = append((*list)[:i], (*list)[i+1:]...)
return
}
}
}