From 8895db530d0308722b7364173769c1bfc1382054 Mon Sep 17 00:00:00 2001 From: sneak Date: Wed, 22 Jul 2026 22:01:03 +0700 Subject: [PATCH] Decompose score and wakeMonster (refactor step 7) score splits into scoreInsert/scoreLines/showScores; wakeMonster gains meanWakes/medusaCatches/medusaGaze predicates and effect. Behavior and RNG call order unchanged. --- game/monsters.go | 86 ++++++++++++++++++--------- game/score.go | 151 +++++++++++++++++++++++++++-------------------- 2 files changed, 144 insertions(+), 93 deletions(-) diff --git a/game/monsters.go b/game/monsters.go index 06c81fa..d371450 100644 --- a/game/monsters.go +++ b/game/monsters.go @@ -124,40 +124,14 @@ func (g *RogueGame) wakeMonster(y, x int) *Monster { panic("can't find monster in wake_monster") } - ch := tp.Type // Every time he sees a mean monster, it might start chasing him - if !tp.On(Awake) && g.rnd(3) != 0 && tp.On(Mean) && !tp.On(Held) && - !p.IsWearing(RingStealth) && !p.On(Levitating) { + if g.meanWakes(tp) { tp.Dest = &p.Pos tp.Flags.Set(Awake) } - if ch == 'M' && !p.On(Blind) && !p.On(Hallucinating) && - !tp.On(Found) && !tp.On(Cancelled) && tp.On(Awake) { - rp := p.Room - if (rp != nil && !rp.Flags.Has(Dark)) || - distance(y, x, p.Pos.Y, p.Pos.X) < LampDist { - tp.Flags.Set(Found) - - if !g.save(VsMagic) { - if p.On(Confused) { - g.Lengthen(DUnconfuse, g.spread(HuhDuration)) - } else { - g.Fuse(DUnconfuse, 0, g.spread(HuhDuration), After) - } - - p.Flags.Set(Confused) - - mname := g.setMname(tp) - g.addmsgf("%s", mname) - - if mname != "it" { - g.addmsgf("'") - } - - g.msg("s gaze has confused you") - } - } + if g.medusaCatches(tp) { + g.medusaGaze(tp, y, x) } // Let greedy ones guard gold if tp.On(Greedy) && !tp.On(Awake) { @@ -173,6 +147,60 @@ func (g *RogueGame) wakeMonster(y, x int) *Monster { return tp } +// meanWakes decides whether a sleeping mean monster starts the chase +// (monsters.c wake_monster). The waking roll happens for any sleeping +// monster, as in C. +func (g *RogueGame) meanWakes(tp *Monster) bool { + p := &g.Player + + return !tp.On(Awake) && g.rnd(3) != 0 && tp.On(Mean) && !tp.On(Held) && + !p.IsWearing(RingStealth) && !p.On(Levitating) +} + +// medusaCatches reports an uncovered, awake medusa the hero can see +// (monsters.c wake_monster). +func (g *RogueGame) medusaCatches(tp *Monster) bool { + p := &g.Player + + return tp.Type == 'M' && !p.On(Blind) && !p.On(Hallucinating) && + !tp.On(Found) && !tp.On(Cancelled) && tp.On(Awake) +} + +// medusaGaze confuses the hero when the medusa's gaze lands (the M +// block of monsters.c wake_monster). +func (g *RogueGame) medusaGaze(tp *Monster, y, x int) { + p := &g.Player + + rp := p.Room + if (rp == nil || rp.Flags.Has(Dark)) && + distance(y, x, p.Pos.Y, p.Pos.X) >= LampDist { + return + } + + tp.Flags.Set(Found) + + if g.save(VsMagic) { + return + } + + if p.On(Confused) { + g.Lengthen(DUnconfuse, g.spread(HuhDuration)) + } else { + g.Fuse(DUnconfuse, 0, g.spread(HuhDuration), After) + } + + p.Flags.Set(Confused) + + mname := g.setMname(tp) + g.addmsgf("%s", mname) + + if mname != "it" { + g.addmsgf("'") + } + + g.msg("s gaze has confused you") +} + // givePack gives a pack to a monster if it deserves one (monsters.c // give_pack). func (g *RogueGame) givePack(tp *Monster) { diff --git a/game/score.go b/game/score.go index 8d07364..6f715a0 100644 --- a/game/score.go +++ b/game/score.go @@ -107,61 +107,81 @@ func (g *RogueGame) score(amount, flags int, monst byte) { topTen := g.rdScore() // Insert her in list if need be ins := -1 - if !g.NoScore && flags >= 0 { - uid := os.Getuid() + ins = g.scoreInsert(topTen, amount, flags, monst) + } - scp := len(topTen) - for i := range topTen { - if amount > topTen[i].Score { - scp = i + lines, highlight := g.scoreLines(topTen, ins) + g.showScores(lines, highlight) - break - } else if !g.AllScore && flags != 2 && - topTen[i].UID == uid && topTen[i].Flags != 2 { - // only one score per nowin uid - scp = len(topTen) + // Update the list file + if ins >= 0 { + g.wrScore(topTen) + } +} - break - } - } +// scoreInsert slots the new score into the top ten, honoring the +// one-score-per-losing-uid rule; -1 means it did not place (the +// insertion half of rip.c score). +func (g *RogueGame) scoreInsert(topTen []ScoreEnt, amount, flags int, monst byte) int { + uid := os.Getuid() - if scp < len(topTen) { - sc2 := len(topTen) - 1 - if flags != 2 && !g.AllScore { - for i := scp; i < len(topTen); i++ { - if topTen[i].UID == uid && topTen[i].Flags != 2 { - sc2 = i + scp := len(topTen) + for i := range topTen { + if amount > topTen[i].Score { + scp = i - break - } - } - } + break + } else if !g.AllScore && flags != 2 && + topTen[i].UID == uid && topTen[i].Flags != 2 { + // only one score per nowin uid + scp = len(topTen) - for sc2 > scp { - topTen[sc2] = topTen[sc2-1] - sc2-- - } - - lvl := g.Depth - if flags == 2 { - lvl = g.MaxDepth - } - - topTen[scp] = ScoreEnt{ - UID: uid, - Score: amount, - Flags: flags, - Monster: monst, - Name: g.Whoami, - Level: lvl, - Time: time.Now().Unix(), - } - ins = scp + break } } - // Build the list display + if scp >= len(topTen) { + return -1 + } + + sc2 := len(topTen) - 1 + if flags != 2 && !g.AllScore { + for i := scp; i < len(topTen); i++ { + if topTen[i].UID == uid && topTen[i].Flags != 2 { + sc2 = i + + break + } + } + } + + for sc2 > scp { + topTen[sc2] = topTen[sc2-1] + sc2-- + } + + lvl := g.Depth + if flags == 2 { + lvl = g.MaxDepth + } + + topTen[scp] = ScoreEnt{ + UID: uid, + Score: amount, + Flags: flags, + Monster: monst, + Name: g.Whoami, + Level: lvl, + Time: time.Now().Unix(), + } + + return scp +} + +// scoreLines formats the scoreboard, noting which display line holds +// the freshly inserted score (the display half of rip.c score). +func (g *RogueGame) scoreLines(topTen []ScoreEnt, ins int) ([]string, int) { label := "Rogueists" if g.AllScore { label = "Scores" @@ -194,32 +214,35 @@ func (g *RogueGame) score(amount, flags int, monst byte) { lines = append(lines, line) } - if g.scr != nil && g.scr.term != nil { - g.clear() + return lines, highlight +} - for i, line := range lines { - if i == highlight { - g.standout() - } - - g.mvaddstr(i, 0, line) - - if i == highlight { - g.standend() - } - } - - g.refresh() - } else { +// showScores prints the scoreboard on the screen when there is one, +// else to standard output (rip.c score). +func (g *RogueGame) showScores(lines []string, highlight int) { + if g.scr == nil || g.scr.term == nil { for _, line := range lines { _, _ = fmt.Fprintln(os.Stdout, line) // CLI output } + + return } - // Update the list file - if ins >= 0 { - g.wrScore(topTen) + g.clear() + + for i, line := range lines { + if i == highlight { + g.standout() + } + + g.mvaddstr(i, 0, line) + + if i == highlight { + g.standend() + } } + + g.refresh() } // ShowScores implements the -s command line option: print the scoreboard