Decompose remaining effects-file hot spots (refactor step 7)

drain gains drainReaches; zapSpeed gains hasteTarget/slowTarget;
readHoldMonster gains holdMonstersNear; readCreateMonster gains
createMonsterSpot; revealSpot splits into revealChar/revealWall/
revealSolid/revealFloor; turnSee gains showSensed. potions.go,
scrolls.go, and sticks.go are complexity-clean. Behavior and RNG call
order unchanged.
This commit is contained in:
2026-07-07 02:53:09 +02:00
parent 1a25beead8
commit ebe477ba28
3 changed files with 176 additions and 99 deletions

View File

@@ -298,7 +298,24 @@ func (g *RogueGame) turnSee(turnOff bool) bool {
if !canSee { if !canSee {
g.addch(mp.OldCh) g.addch(mp.OldCh)
} }
} else if g.showSensed(mp, canSee) {
addNew = true
}
}
if turnOff {
g.Player.Flags.Clear(SenseMonsters)
} else { } else {
g.Player.Flags.Set(SenseMonsters)
}
return addNew
}
// showSensed draws one monster for monster sense, standout when it is
// otherwise invisible; it reports whether the monster was newly revealed
// (the turn-on arm of the C turn_see loop).
func (g *RogueGame) showSensed(mp *Monster, canSee bool) bool {
if !canSee { if !canSee {
g.standout() g.standout()
} }
@@ -312,18 +329,10 @@ func (g *RogueGame) turnSee(turnOff bool) bool {
if !canSee { if !canSee {
g.standend() g.standend()
addNew = true return true
}
}
} }
if turnOff { return false
g.Player.Flags.Clear(SenseMonsters)
} else {
g.Player.Flags.Set(SenseMonsters)
}
return addNew
} }
// seenStairs reports whether the player has seen the stairs (potions.c // seenStairs reports whether the player has seen the stairs (potions.c

View File

@@ -59,6 +59,31 @@ func (g *RogueGame) readEnchantArmor(*Object) {
func (g *RogueGame) readHoldMonster(*Object) { func (g *RogueGame) readHoldMonster(*Object) {
// Hold monster scroll. Stop all monsters within two spaces from // Hold monster scroll. Stop all monsters within two spaces from
// chasing after the hero. // chasing after the hero.
held := g.holdMonstersNear()
if held > 0 {
g.addmsgf("the monster")
if held > 1 {
g.addmsgf("s around you")
}
g.addmsgf(" freeze")
if held == 1 {
g.addmsgf("s")
}
g.endmsg()
g.Items.Scrolls[ScrollHoldMonster].Know = true
} else {
g.msg("you feel a strange sense of loss")
}
}
// holdMonstersNear freezes every awake monster within two spaces of the
// hero and reports how many froze (the scan of the C S_HOLD case).
func (g *RogueGame) holdMonstersNear() int {
p := &g.Player p := &g.Player
held := 0 held := 0
@@ -81,24 +106,7 @@ func (g *RogueGame) readHoldMonster(*Object) {
} }
} }
if held > 0 { return held
g.addmsgf("the monster")
if held > 1 {
g.addmsgf("s around you")
}
g.addmsgf(" freeze")
if held == 1 {
g.addmsgf("s")
}
g.endmsg()
g.Items.Scrolls[ScrollHoldMonster].Know = true
} else {
g.msg("you feel a strange sense of loss")
}
} }
func (g *RogueGame) readSleep(*Object) { func (g *RogueGame) readSleep(*Object) {
@@ -113,6 +121,19 @@ func (g *RogueGame) readSleep(*Object) {
func (g *RogueGame) readCreateMonster(*Object) { func (g *RogueGame) readCreateMonster(*Object) {
// Create a monster: first look in a circle around him, next try // Create a monster: first look in a circle around him, next try
// his room, otherwise give up // his room, otherwise give up
mp, ok := g.createMonsterSpot()
if !ok {
g.msg("you hear a faint cry of anguish in the distance")
} else {
tp := &Monster{}
g.newMonster(tp, g.randMonster(false), mp)
}
}
// createMonsterSpot reservoir-samples a legal spot around the hero for a
// created monster; ok is false when every neighbor is blocked (the scan
// of the C S_CREATE case).
func (g *RogueGame) createMonsterSpot() (Coord, bool) {
p := &g.Player p := &g.Player
i := 0 i := 0
@@ -139,12 +160,7 @@ func (g *RogueGame) readCreateMonster(*Object) {
} }
} }
if i == 0 { return mp, i != 0
g.msg("you hear a faint cry of anguish in the distance")
} else {
tp := &Monster{}
g.newMonster(tp, g.randMonster(false), mp)
}
} }
func (g *RogueGame) readIdentify(obj *Object) { func (g *RogueGame) readIdentify(obj *Object) {
@@ -166,45 +182,41 @@ func (g *RogueGame) readMagicMapping(*Object) {
} }
} }
// revealSpot uncovers one map cell for magic mapping: secret doors and // revealSpot uncovers one map cell for magic mapping and draws it (the
// passages become real, hidden traps show, and the visible character is // loop body of the C SCR_MAP case).
// drawn (the loop body of the C SCR_MAP case).
func (g *RogueGame) revealSpot(y, x int) { func (g *RogueGame) revealSpot(y, x int) {
pp := g.Level.At(y, x) pp := g.Level.At(y, x)
ch := revealChar(pp)
if ch != ' ' {
if tp := pp.Monst; tp != nil {
tp.OldCh = ch
if !g.Player.On(SenseMonsters) {
g.mvaddch(y, x, ch)
}
} else {
g.mvaddch(y, x, ch)
}
}
}
// revealChar decides what magic mapping shows at a cell, making secret
// doors, hidden passages, and hidden traps real as a side effect; ' '
// means show nothing (the switch of the C SCR_MAP loop).
func revealChar(pp *Place) byte {
ch := pp.Ch ch := pp.Ch
pass := false pass := false
switch ch { switch ch {
case Door, Stairs: case Door, Stairs:
case '-', '|': case '-', '|':
if !pp.Flags.Has(FReal) { ch = revealWall(pp)
ch = Door
pp.Ch = Door
pp.Flags.Set(FReal)
}
case ' ': case ' ':
if pp.Flags.Has(FReal) { pass = revealSolid(pp)
// def: hidden things in walls stay hidden
if pp.Flags.Has(FPassage) {
pass = true
} else {
ch = ' '
}
} else {
pp.Flags.Set(FReal)
pp.Ch = Passage
pass = true
}
case Passage: case Passage:
pass = true pass = true
case Floor: case Floor:
if pp.Flags.Has(FReal) { ch = revealFloor(pp)
ch = ' '
} else {
ch = Trap
pp.Ch = Trap
pp.Flags.Set(FSeen | FReal)
}
default: default:
if pp.Flags.Has(FPassage) { if pp.Flags.Has(FPassage) {
pass = true pass = true
@@ -223,16 +235,47 @@ func (g *RogueGame) revealSpot(y, x int) {
ch = Passage ch = Passage
} }
if ch != ' ' { return ch
if tp := pp.Monst; tp != nil { }
tp.OldCh = ch
if !g.Player.On(SenseMonsters) { // revealWall handles a wall cell for magic mapping: a secret door
g.mvaddch(y, x, ch) // becomes a real door (the '-'/'|' arm).
func revealWall(pp *Place) byte {
if !pp.Flags.Has(FReal) {
pp.Ch = Door
pp.Flags.Set(FReal)
return Door
} }
} else {
g.mvaddch(y, x, ch) return pp.Ch
}
// revealSolid handles a blank cell for magic mapping, reporting whether
// it is passage: hidden passages become real; hidden things in walls
// stay hidden (the ' ' arm).
func revealSolid(pp *Place) bool {
if pp.Flags.Has(FReal) {
return pp.Flags.Has(FPassage)
} }
pp.Flags.Set(FReal)
pp.Ch = Passage
return true
}
// revealFloor handles a floor cell for magic mapping: a hidden trap
// becomes a real, seen trap; real floor shows nothing (the FLOOR arm).
func revealFloor(pp *Place) byte {
if pp.Flags.Has(FReal) {
return ' '
} }
pp.Ch = Trap
pp.Flags.Set(FSeen | FReal)
return Trap
} }
func (g *RogueGame) readFoodDetection(*Object) { func (g *RogueGame) readFoodDetection(*Object) {

View File

@@ -229,14 +229,37 @@ func (g *RogueGame) zapMagicMissile(*Object) bool {
} }
func (g *RogueGame) zapSpeed(obj *Object) bool { func (g *RogueGame) zapSpeed(obj *Object) bool {
if tp := g.zapRayMonster(); tp != nil { tp := g.zapRayMonster()
if tp == nil {
return true
}
if obj.WandKind() == WandHasteMonster { if obj.WandKind() == WandHasteMonster {
hasteTarget(tp)
} else {
slowTarget(tp)
}
g.Delta.Y = tp.Pos.Y
g.Delta.X = tp.Pos.X
g.runTo(g.Delta)
return true
}
// hasteTarget cancels a slow or applies a haste (the WS_HASTE_M arm of
// do_zap).
func hasteTarget(tp *Monster) {
if tp.On(Slowed) { if tp.On(Slowed) {
tp.Flags.Clear(Slowed) tp.Flags.Clear(Slowed)
} else { } else {
tp.Flags.Set(Hasted) tp.Flags.Set(Hasted)
} }
} else { }
// slowTarget cancels a haste or applies a slow (the WS_SLOW_M arm of
// do_zap).
func slowTarget(tp *Monster) {
if tp.On(Hasted) { if tp.On(Hasted) {
tp.Flags.Clear(Hasted) tp.Flags.Clear(Hasted)
} else { } else {
@@ -244,14 +267,6 @@ func (g *RogueGame) zapSpeed(obj *Object) bool {
} }
tp.Turn = true tp.Turn = true
}
g.Delta.Y = tp.Pos.Y
g.Delta.X = tp.Pos.X
g.runTo(g.Delta)
}
return true
} }
func (g *RogueGame) zapBolt(obj *Object) bool { func (g *RogueGame) zapBolt(obj *Object) bool {
@@ -286,9 +301,7 @@ func (g *RogueGame) drain() {
var drainee []*Monster var drainee []*Monster
for _, mp := range g.Level.Monsters { for _, mp := range g.Level.Monsters {
if mp.Room == p.Room || mp.Room == corp || if g.drainReaches(mp, corp, inpass) {
(inpass && g.Level.Char(mp.Pos.Y, mp.Pos.X) == Door &&
&g.Level.Passages[*g.Level.FlagsAt(mp.Pos.Y, mp.Pos.X)&FPassNum] == p.Room) {
drainee = append(drainee, mp) drainee = append(drainee, mp)
} }
} }
@@ -312,6 +325,18 @@ func (g *RogueGame) drain() {
} }
} }
// drainReaches reports whether the drain-life wand reaches this monster:
// the hero's room, the passage behind the door he stands on, or — when
// he is in a passage — a door of that same passage (the drainee
// condition of sticks.c drain).
func (g *RogueGame) drainReaches(mp *Monster, corp *Room, inpass bool) bool {
p := &g.Player
return mp.Room == p.Room || mp.Room == corp ||
(inpass && g.Level.Char(mp.Pos.Y, mp.Pos.X) == Door &&
&g.Level.Passages[*g.Level.FlagsAt(mp.Pos.Y, mp.Pos.X)&FPassNum] == p.Room)
}
// fireBolt fires a bolt in a given direction from a specific starting // fireBolt fires a bolt in a given direction from a specific starting
// place (sticks.c fire_bolt). // place (sticks.c fire_bolt).
func (g *RogueGame) fireBolt(start Coord, dir *Coord, name string) { func (g *RogueGame) fireBolt(start Coord, dir *Coord, name string) {