Compare commits
8 Commits
0554f5d4f1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| acef593288 | |||
| 0b56ac8019 | |||
| a094f7c6c3 | |||
| 0caaa14198 | |||
| d3ef07cfa7 | |||
| f432c8718c | |||
| ae79fd5e84 | |||
| 6d798c56ed |
53
TODO.md
53
TODO.md
@@ -29,14 +29,32 @@ Refactor ground rules:
|
||||
|
||||
# Next Step
|
||||
|
||||
Refactor step 5: method renames, items/combat/UI subsystems
|
||||
(invName→inventoryName, rollEm→rollAttacks, doPot→applyPotionFuse,
|
||||
getItem→promptPackItem returning (obj, ok), getDir→promptDirection);
|
||||
int status codes (attack returning -1) become named results. Two or
|
||||
three commits, one subsystem each.
|
||||
Refactor step 7: effects dispatch — the giant quaff/readScroll/doZap
|
||||
switches become per-kind handler tables of small named methods,
|
||||
keeping effect order and RNG call sequence identical. This step also
|
||||
clears the outstanding cyclop/gocognit/nestif lint findings.
|
||||
|
||||
# Completed Steps
|
||||
|
||||
- 2026-07-07 Refactor step 6 (refactor/god-object-extraction):
|
||||
MessageLine (was MsgLine) owns the msg/addmsg/endmsg machinery,
|
||||
wired to its screen/look/input needs via attach(); RogueGame keeps
|
||||
one-line msg/addmsgf/endmsg shorthands so call sites are unchanged.
|
||||
Player owns pack bookkeeping (nextPackChar, removeFromPack — the
|
||||
state half of leave_pack; leavePack keeps only LastPick tracking).
|
||||
Level owns object/monster list management and lookup (ObjectAt
|
||||
replaces findObj; AddObject/RemoveObject/AddMonster/RemoveMonster
|
||||
replace direct attachObj/detachObj/attachMon/detachMon on level
|
||||
lists). Inventory/pickup UI flows stay on RogueGame deliberately:
|
||||
they are display and turn orchestration, not state surgery.
|
||||
|
||||
- 2026-07-07 Refactor step 5 (refactor/item-combat-ui-renames, three
|
||||
commits, one subsystem each): items — getItem→promptPackItem now
|
||||
returning (obj, ok), invName→inventoryName, doPot→applyPotionFuse;
|
||||
combat — rollEm→rollAttacks, attack/moveMonster/chaseStep return
|
||||
(removed bool) instead of C -1/0 int codes; UI —
|
||||
getDir→promptDirection. C breadcrumbs kept; suite green.
|
||||
|
||||
- 2026-07-07 Refactor step 4 (refactor/movement-renames): movement/world
|
||||
renames (doMove→moveHero, beTrapped→springTrap, rndmove→randomStep,
|
||||
doRooms/doPassages/doMaze→digRooms/digPassages/digMaze,
|
||||
@@ -110,36 +128,27 @@ three commits, one subsystem each.
|
||||
|
||||
# Future Steps
|
||||
|
||||
1. Refactor step 6: extract types from the god object — MessageLine
|
||||
owns the msg/addmsg/endmsg machinery; pack/inventory operations move
|
||||
onto *Player; monster/object list management and map queries
|
||||
consolidate onto *Level; RogueGame keeps turn orchestration and
|
||||
cross-system effects only.
|
||||
2. Refactor step 7: effects dispatch — the giant quaff/readScroll/doZap
|
||||
switches become per-kind handler tables of small named methods,
|
||||
keeping effect order and RNG call sequence identical. This step also
|
||||
clears the outstanding cyclop/gocognit/nestif lint findings.
|
||||
3. Refactor step 8: constructor and style pass per the house
|
||||
1. Refactor step 8: constructor and style pass per the house
|
||||
styleguide — game.New(game.Params{...}) replacing NewGame(Config);
|
||||
replace the gameEnd panic unwind with error-based turn results where
|
||||
feasible; 77-column wrap sweep.
|
||||
4. Docs refresh: update ARCHITECTURE.md Part 2 and README.md for the
|
||||
2. Docs refresh: update ARCHITECTURE.md Part 2 and README.md for the
|
||||
post-refactor names; add the C name → Go name rename table.
|
||||
5. Playtest hardening pass: play several full games with the tcell
|
||||
3. Playtest hardening pass: play several full games with the tcell
|
||||
binary and extend run_test.go to script a deeper multi-level
|
||||
playthrough (descend past level 5, use potions, scrolls, zapping,
|
||||
save/restore). Fix any panics, message mismatches, or divergences
|
||||
from the C behavior that this uncovers, with regression tests.
|
||||
6. Verify the seed-compatibility claim against the C reference on
|
||||
4. Verify the seed-compatibility claim against the C reference on
|
||||
c-master: same seed, same dungeon, same item tables, for several
|
||||
seeds.
|
||||
7. Broaden unit test coverage where playtesting finds thin spots
|
||||
5. Broaden unit test coverage where playtesting finds thin spots
|
||||
(rings, sticks, wizard commands).
|
||||
8. Tag a release once a full game (Amulet retrieval and score entry)
|
||||
6. Tag a release once a full game (Amulet retrieval and score entry)
|
||||
completes without defects.
|
||||
9. Full-terminal-size support (deferred by explicit decision
|
||||
7. Full-terminal-size support (deferred by explicit decision
|
||||
2026-07-06): per-game dungeon dimensions instead of the 80x24
|
||||
constants; open design questions are resize policy, gameplay
|
||||
tuning at larger sizes, and a --classic 80x24 mode.
|
||||
10. Note: this repo is exempt from the standard policy scaffold. Do not
|
||||
8. Note: this repo is exempt from the standard policy scaffold. Do not
|
||||
add Makefile, Dockerfile, or REPO_POLICIES.md.
|
||||
|
||||
@@ -6,8 +6,8 @@ package game
|
||||
func (g *RogueGame) wear() {
|
||||
p := &g.Player
|
||||
|
||||
obj := g.getItem("wear", KindArmor)
|
||||
if obj == nil {
|
||||
obj, ok := g.promptPackItem("wear", KindArmor)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ func (g *RogueGame) wear() {
|
||||
|
||||
g.wasteTime()
|
||||
obj.Flags.Set(Known)
|
||||
sp := g.invName(obj, true)
|
||||
sp := g.inventoryName(obj, true)
|
||||
p.CurArmor = obj
|
||||
|
||||
if !g.Options.Terse {
|
||||
@@ -70,7 +70,7 @@ func (g *RogueGame) takeOff() {
|
||||
g.addmsgf("you used to be")
|
||||
}
|
||||
|
||||
g.msg(" wearing %c) %s", obj.PackCh, g.invName(obj, true))
|
||||
g.msg(" wearing %c) %s", obj.PackCh, g.inventoryName(obj, true))
|
||||
}
|
||||
|
||||
// wasteTime does nothing but let other things happen (armor.c waste_time).
|
||||
|
||||
@@ -13,12 +13,12 @@ func (g *RogueGame) runners(int) {
|
||||
origPos := tp.Pos
|
||||
|
||||
wastarget := tp.On(Targeted)
|
||||
if g.moveMonster(tp) == -1 {
|
||||
if removed := g.moveMonster(tp); removed {
|
||||
continue
|
||||
}
|
||||
|
||||
if tp.On(Flying) && distCp(g.Player.Pos, tp.Pos) >= 3 {
|
||||
if g.moveMonster(tp) == -1 {
|
||||
if removed := g.moveMonster(tp); removed {
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -38,23 +38,24 @@ func (g *RogueGame) runners(int) {
|
||||
}
|
||||
|
||||
// moveMonster executes a single turn of running for a monster (chase.c
|
||||
// move_monst). Returns -1 if the monster died or left the level.
|
||||
func (g *RogueGame) moveMonster(tp *Monster) int {
|
||||
// move_monst). The result reports that the monster died or left the
|
||||
// level (the C -1 return).
|
||||
func (g *RogueGame) moveMonster(tp *Monster) bool {
|
||||
if !tp.On(Slowed) || tp.Turn {
|
||||
if g.chaseStep(tp) == -1 {
|
||||
return -1
|
||||
if g.chaseStep(tp) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if tp.On(Hasted) {
|
||||
if g.chaseStep(tp) == -1 {
|
||||
return -1
|
||||
if g.chaseStep(tp) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
tp.Turn = !tp.Turn
|
||||
|
||||
return 0
|
||||
return false
|
||||
}
|
||||
|
||||
// relocate makes the monster's new location be the specified one, updating
|
||||
@@ -86,9 +87,10 @@ func (g *RogueGame) relocate(th *Monster, newLoc Coord) {
|
||||
}
|
||||
}
|
||||
|
||||
// chaseStep makes one thing chase another (chase.c do_chase). Returns -1
|
||||
// if the chaser died in the attempt.
|
||||
func (g *RogueGame) chaseStep(th *Monster) int {
|
||||
// chaseStep makes one thing chase another (chase.c do_chase). removed
|
||||
// reports that the chaser died or left the level in the attempt (the C
|
||||
// -1 return).
|
||||
func (g *RogueGame) chaseStep(th *Monster) (removed bool) {
|
||||
p := &g.Player
|
||||
stoprun := false // true means we are there
|
||||
mindist := 32767
|
||||
@@ -153,7 +155,7 @@ func (g *RogueGame) chaseStep(th *Monster) int {
|
||||
g.Kamikaze = false
|
||||
}
|
||||
|
||||
return 0
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +169,7 @@ func (g *RogueGame) chaseStep(th *Monster) int {
|
||||
} else if this == *th.Dest {
|
||||
for _, obj := range g.Level.Objects {
|
||||
if th.Dest == &obj.Pos {
|
||||
detachObj(&g.Level.Objects, obj)
|
||||
g.Level.RemoveObject(obj)
|
||||
attachObj(&th.Pack, obj)
|
||||
|
||||
if th.Room.Flags.Has(Gone) {
|
||||
@@ -188,7 +190,7 @@ func (g *RogueGame) chaseStep(th *Monster) int {
|
||||
}
|
||||
} else {
|
||||
if th.Type == 'F' {
|
||||
return 0
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +200,7 @@ func (g *RogueGame) chaseStep(th *Monster) int {
|
||||
th.Flags.Clear(Awake)
|
||||
}
|
||||
|
||||
return 0
|
||||
return false
|
||||
}
|
||||
|
||||
// chase finds the spot for the chaser to move closer to the chasee
|
||||
|
||||
@@ -240,7 +240,7 @@ func (g *RogueGame) dispatch(ch byte) {
|
||||
g.Kamikaze = true
|
||||
}
|
||||
|
||||
if !g.getDir() {
|
||||
if !g.promptDirection() {
|
||||
g.After = false
|
||||
|
||||
break
|
||||
@@ -269,7 +269,7 @@ func (g *RogueGame) dispatch(ch byte) {
|
||||
continue // the C goto over: fight by running at it
|
||||
}
|
||||
case 't':
|
||||
if !g.getDir() {
|
||||
if !g.promptDirection() {
|
||||
g.After = false
|
||||
} else {
|
||||
g.missile(g.Delta.Y, g.Delta.X)
|
||||
@@ -334,7 +334,7 @@ func (g *RogueGame) dispatch(ch byte) {
|
||||
case 's':
|
||||
g.search()
|
||||
case 'z':
|
||||
if g.getDir() {
|
||||
if g.promptDirection() {
|
||||
g.doZap()
|
||||
} else {
|
||||
g.After = false
|
||||
@@ -360,7 +360,7 @@ func (g *RogueGame) dispatch(ch byte) {
|
||||
g.After = false // "legal" illegal command
|
||||
case '^':
|
||||
g.After = false
|
||||
if g.getDir() {
|
||||
if g.promptDirection() {
|
||||
g.Delta.Y += p.Pos.Y
|
||||
g.Delta.X += p.Pos.X
|
||||
|
||||
@@ -386,7 +386,7 @@ func (g *RogueGame) dispatch(ch byte) {
|
||||
g.Again = false
|
||||
case 'm':
|
||||
g.MoveOn = true
|
||||
if !g.getDir() {
|
||||
if !g.promptDirection() {
|
||||
g.After = false
|
||||
} else {
|
||||
ch = g.DirCh
|
||||
@@ -453,7 +453,7 @@ func (g *RogueGame) wizardCommand(ch byte) {
|
||||
case CTRL('X'):
|
||||
g.turnSee(p.On(SenseMonsters))
|
||||
case CTRL('~'):
|
||||
if item := g.getItem("charge", KindWand); item != nil {
|
||||
if item, ok := g.promptPackItem("charge", KindWand); ok {
|
||||
item.Charges = 10000
|
||||
}
|
||||
case CTRL('I'):
|
||||
@@ -738,9 +738,9 @@ func (g *RogueGame) levitCheck() bool {
|
||||
// call allows a user to call a potion, scroll, or ring something
|
||||
// (command.c call).
|
||||
func (g *RogueGame) call() {
|
||||
obj := g.getItem("call", KindCallable)
|
||||
obj, ok := g.promptPackItem("call", KindCallable)
|
||||
// Make certain that it is something that we want to name
|
||||
if obj == nil {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -820,7 +820,7 @@ func (g *RogueGame) current(cur *Object, how, where string) {
|
||||
}
|
||||
|
||||
g.InvDescribe = false
|
||||
g.addmsgf("%c) %s", cur.PackCh, g.invName(cur, true))
|
||||
g.addmsgf("%c) %s", cur.PackCh, g.inventoryName(cur, true))
|
||||
|
||||
g.InvDescribe = true
|
||||
if where != "" {
|
||||
|
||||
@@ -50,6 +50,47 @@ 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...)
|
||||
|
||||
@@ -67,7 +67,7 @@ func (g *RogueGame) fight(mp Coord, weap *Object, thrown bool) bool {
|
||||
didHit := false
|
||||
|
||||
g.HasHit = g.Options.Terse && !g.ToDeath
|
||||
if g.rollEm(&p.Creature, &tp.Creature, weap, thrown) {
|
||||
if g.rollAttacks(&p.Creature, &tp.Creature, weap, thrown) {
|
||||
didHit = false
|
||||
|
||||
if thrown {
|
||||
@@ -104,9 +104,10 @@ func (g *RogueGame) fight(mp Coord, weap *Object, thrown bool) bool {
|
||||
return didHit
|
||||
}
|
||||
|
||||
// attack has the monster attack the player (fight.c attack). Returns -1 if
|
||||
// the monster removed itself from the level during its own attack.
|
||||
func (g *RogueGame) attack(mp *Monster) int {
|
||||
// attack has the monster attack the player (fight.c attack). removed
|
||||
// reports that the monster took itself off the level during its own
|
||||
// attack (the C -1 return).
|
||||
func (g *RogueGame) attack(mp *Monster) (removed bool) {
|
||||
p := &g.Player
|
||||
// Since this is an attack, stop running and any healing that was
|
||||
// going on at the time.
|
||||
@@ -128,9 +129,8 @@ func (g *RogueGame) attack(mp *Monster) int {
|
||||
|
||||
mname := g.setMname(mp)
|
||||
oldhp := p.Stats.HP
|
||||
removed := false
|
||||
|
||||
if g.rollEm(&mp.Creature, &p.Creature, nil, false) {
|
||||
if g.rollAttacks(&mp.Creature, &p.Creature, nil, false) {
|
||||
if mp.Type != 'I' {
|
||||
if g.HasHit {
|
||||
g.addmsgf(". ")
|
||||
@@ -290,7 +290,7 @@ func (g *RogueGame) attack(mp *Monster) int {
|
||||
removed = true
|
||||
|
||||
g.leavePack(steal, false, false)
|
||||
g.msg("she stole %s!", g.invName(steal, true))
|
||||
g.msg("she stole %s!", g.inventoryName(steal, true))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -317,11 +317,7 @@ func (g *RogueGame) attack(mp *Monster) int {
|
||||
g.Count = 0
|
||||
g.status()
|
||||
|
||||
if removed {
|
||||
return -1
|
||||
}
|
||||
|
||||
return 0
|
||||
return removed
|
||||
}
|
||||
|
||||
// swing returns true if the swing hits (fight.c swing).
|
||||
@@ -332,8 +328,8 @@ func (g *RogueGame) swing(atLvl, opArm, wplus int) bool {
|
||||
return res+wplus >= need
|
||||
}
|
||||
|
||||
// rollEm rolls several attacks (fight.c roll_em).
|
||||
func (g *RogueGame) rollEm(thatt, thdef *Creature, weap *Object, hurl bool) bool {
|
||||
// rollAttacks rolls several attacks (fight.c roll_em).
|
||||
func (g *RogueGame) rollAttacks(thatt, thdef *Creature, weap *Object, hurl bool) bool {
|
||||
p := &g.Player
|
||||
att := &thatt.Stats
|
||||
def := &thdef.Stats
|
||||
@@ -553,7 +549,7 @@ func (g *RogueGame) removeMon(mp Coord, tp *Monster, waskill bool) {
|
||||
|
||||
g.Level.SetMonsterAt(mp.Y, mp.X, nil)
|
||||
g.mvaddch(mp.Y, mp.X, tp.OldCh)
|
||||
detachMon(&g.Level.Monsters, tp)
|
||||
g.Level.RemoveMonster(tp)
|
||||
|
||||
if tp.On(Targeted) {
|
||||
g.Kamikaze = false
|
||||
|
||||
@@ -32,7 +32,7 @@ func TestRollEmParsesMultiAttackDice(t *testing.T) {
|
||||
// With attacker level 20 vs armor 10, swing always hits
|
||||
// (rnd(20)+wplus >= (20-20)-10 is always true), so three attacks of
|
||||
// 1x4 + str bonus 1 each must deal between 6 and 15 damage.
|
||||
if !g.rollEm(att, def, nil, false) {
|
||||
if !g.rollAttacks(att, def, nil, false) {
|
||||
t.Fatal("attack with guaranteed swing missed")
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ type RogueGame struct {
|
||||
|
||||
// screen / messages
|
||||
scr *Screen
|
||||
Msgs MsgLine
|
||||
Msgs MessageLine
|
||||
statusCache statusCache
|
||||
invPage invPage // things.c discovery-list pagination statics
|
||||
|
||||
@@ -169,6 +169,7 @@ func NewGame(cfg Config) *RogueGame {
|
||||
g.InvDescribe = true
|
||||
g.Msgs.SaveMsg = true
|
||||
g.scr = NewScreen(cfg.Term)
|
||||
g.Msgs.attach(g.scr, g.look, g.readchar)
|
||||
g.FileName = cfg.Home + "/rogue.save"
|
||||
|
||||
g.rogueOpts = cfg.RogueOpts
|
||||
|
||||
93
game/io.go
93
game/io.go
@@ -10,9 +10,11 @@ import (
|
||||
// maxMsg is io.c MAXMSG: how much message fits before --More--.
|
||||
const maxMsg = NumCols - len("--More--") - 1
|
||||
|
||||
// MsgLine is the io.c message machinery: the static msgbuf/newpos pair plus
|
||||
// the related globals (mpos, huh, and the message-behavior flags).
|
||||
type MsgLine struct {
|
||||
// MessageLine is the io.c message machinery: the static msgbuf/newpos
|
||||
// pair plus the related globals (mpos, huh, and the message-behavior
|
||||
// flags). It owns the top line of the screen; attach wires in the
|
||||
// display and input it needs.
|
||||
type MessageLine struct {
|
||||
buf strings.Builder // msgbuf
|
||||
newpos int
|
||||
Mpos int // where cursor is on top line
|
||||
@@ -20,49 +22,52 @@ type MsgLine struct {
|
||||
SaveMsg bool // remember last msg
|
||||
LowerMsg bool // messages should start w/lower case
|
||||
MsgEsc bool // check for ESC from msg's --More--
|
||||
|
||||
scr *Screen // the top line lives on scr.Std
|
||||
look func(wakeup bool) // redraw before a --More-- (misc.c look)
|
||||
readChar func() byte // input for --More-- prompts
|
||||
}
|
||||
|
||||
// Msg displays a message at the top of the screen (io.c msg). It returns
|
||||
// Escape if the player escaped out of a --More--, ^Escape otherwise (the C
|
||||
// convention: callers compare against ESCAPE).
|
||||
func (g *RogueGame) msg(format string, a ...any) int {
|
||||
// Escape if the player escaped out of a --More--, ^Escape otherwise (the
|
||||
// C convention: callers compare against ESCAPE).
|
||||
func (m *MessageLine) Msg(format string, a ...any) int {
|
||||
// if the string is "", just clear the line
|
||||
if format == "" {
|
||||
g.move(0, 0)
|
||||
g.clrtoeol()
|
||||
g.Msgs.Mpos = 0
|
||||
m.scr.Std.Move(0, 0)
|
||||
m.scr.Std.Clrtoeol()
|
||||
m.Mpos = 0
|
||||
|
||||
return ^Escape
|
||||
}
|
||||
// otherwise add to the message and flush it out
|
||||
g.doaddf(format, a...)
|
||||
m.doaddf(format, a...)
|
||||
|
||||
return g.endmsg()
|
||||
return m.End()
|
||||
}
|
||||
|
||||
// addmsgf adds things to the current message (io.c addmsg).
|
||||
func (g *RogueGame) addmsgf(format string, a ...any) {
|
||||
g.doaddf(format, a...)
|
||||
// Addf adds things to the current message (io.c addmsg).
|
||||
func (m *MessageLine) Addf(format string, a ...any) {
|
||||
m.doaddf(format, a...)
|
||||
}
|
||||
|
||||
// endmsg displays a new msg, giving the player a chance to see the previous
|
||||
// End displays a new msg, giving the player a chance to see the previous
|
||||
// one if it is up there with the --More-- (io.c endmsg).
|
||||
func (g *RogueGame) endmsg() int {
|
||||
m := &g.Msgs
|
||||
func (m *MessageLine) End() int {
|
||||
if m.SaveMsg {
|
||||
m.Huh = m.buf.String()
|
||||
}
|
||||
|
||||
if m.Mpos != 0 {
|
||||
g.look(false)
|
||||
g.mvaddstr(0, m.Mpos, "--More--")
|
||||
g.refresh()
|
||||
m.look(false)
|
||||
m.scr.Std.MvAddStr(0, m.Mpos, "--More--")
|
||||
m.scr.Refresh()
|
||||
|
||||
if !m.MsgEsc {
|
||||
g.waitFor(' ')
|
||||
m.waitForSpace()
|
||||
} else {
|
||||
for {
|
||||
ch := g.readchar()
|
||||
ch := m.readChar()
|
||||
if ch == ' ' {
|
||||
break
|
||||
}
|
||||
@@ -85,30 +90,60 @@ func (g *RogueGame) endmsg() int {
|
||||
out = string(toUpper(out[0])) + out[1:]
|
||||
}
|
||||
|
||||
g.mvaddstr(0, 0, out)
|
||||
g.clrtoeol()
|
||||
m.scr.Std.MvAddStr(0, 0, out)
|
||||
m.scr.Std.Clrtoeol()
|
||||
|
||||
m.Mpos = m.newpos
|
||||
m.newpos = 0
|
||||
m.buf.Reset()
|
||||
g.refresh()
|
||||
m.scr.Refresh()
|
||||
|
||||
return ^Escape
|
||||
}
|
||||
|
||||
// doaddf performs an add onto the message buffer (io.c doadd).
|
||||
func (g *RogueGame) doaddf(format string, a ...any) {
|
||||
m := &g.Msgs
|
||||
// attach wires the message line to its display and input; NewGame and
|
||||
// Restore call it once the screen and game exist.
|
||||
func (m *MessageLine) attach(scr *Screen, look func(bool), readChar func() byte) {
|
||||
m.scr = scr
|
||||
m.look = look
|
||||
m.readChar = readChar
|
||||
}
|
||||
|
||||
// waitForSpace absorbs input until the player types a space: the
|
||||
// --More-- acknowledgement (io.c wait_for).
|
||||
func (m *MessageLine) waitForSpace() {
|
||||
for {
|
||||
if m.readChar() == ' ' {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// doaddf performs an add onto the message buffer (io.c doadd).
|
||||
func (m *MessageLine) doaddf(format string, a ...any) {
|
||||
s := fmt.Sprintf(format, a...)
|
||||
if len(s)+m.newpos >= maxMsg {
|
||||
g.endmsg()
|
||||
m.End()
|
||||
}
|
||||
|
||||
m.buf.WriteString(s)
|
||||
m.newpos = m.buf.Len()
|
||||
}
|
||||
|
||||
// msg, addmsgf, and endmsg are the game-side shorthands for the message
|
||||
// line; the machinery lives on MessageLine.
|
||||
func (g *RogueGame) msg(format string, a ...any) int {
|
||||
return g.Msgs.Msg(format, a...)
|
||||
}
|
||||
|
||||
func (g *RogueGame) addmsgf(format string, a ...any) {
|
||||
g.Msgs.Addf(format, a...)
|
||||
}
|
||||
|
||||
func (g *RogueGame) endmsg() {
|
||||
g.Msgs.End()
|
||||
}
|
||||
|
||||
// stepOk returns true if it is ok to step on ch (io.c step_ok).
|
||||
func stepOk(ch byte) bool {
|
||||
switch ch {
|
||||
|
||||
@@ -51,6 +51,29 @@ func (l *Level) VisibleChar(y, x int) byte {
|
||||
return l.Char(y, x)
|
||||
}
|
||||
|
||||
// ObjectAt finds the unclaimed object at (y, x) (misc.c find_obj).
|
||||
func (l *Level) ObjectAt(y, x int) *Object {
|
||||
for _, obj := range l.Objects {
|
||||
if obj.Pos.Y == y && obj.Pos.X == x {
|
||||
return obj
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddObject puts an object on the level (list.c attach on lvl_obj).
|
||||
func (l *Level) AddObject(obj *Object) { attachObj(&l.Objects, obj) }
|
||||
|
||||
// RemoveObject takes an object off the level (list.c detach on lvl_obj).
|
||||
func (l *Level) RemoveObject(obj *Object) { detachObj(&l.Objects, obj) }
|
||||
|
||||
// AddMonster puts a monster on the level (list.c attach on mlist).
|
||||
func (l *Level) AddMonster(m *Monster) { attachMon(&l.Monsters, m) }
|
||||
|
||||
// RemoveMonster takes a monster off the level (list.c detach on mlist).
|
||||
func (l *Level) RemoveMonster(m *Monster) { detachMon(&l.Monsters, m) }
|
||||
|
||||
// goldCalc is the GOLDCALC macro: how much a gold pile is worth at depth.
|
||||
func (g *RogueGame) goldCalc() int {
|
||||
return g.rnd(50+10*g.Depth) + 2
|
||||
|
||||
21
game/misc.go
21
game/misc.go
@@ -223,21 +223,10 @@ func (g *RogueGame) showFloor() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// findObj finds the unclaimed object at (y, x) (misc.c find_obj).
|
||||
func (g *RogueGame) findObj(y, x int) *Object {
|
||||
for _, obj := range g.Level.Objects {
|
||||
if obj.Pos.Y == y && obj.Pos.X == x {
|
||||
return obj
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// eat lets her try to eat something (misc.c eat).
|
||||
func (g *RogueGame) eat() {
|
||||
obj := g.getItem("eat", KindFood)
|
||||
if obj == nil {
|
||||
obj, ok := g.promptPackItem("eat", KindFood)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -406,9 +395,9 @@ func (g *RogueGame) isCurrent(obj *Object) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// getDir sets up the direction coordinate for use in various "prefix"
|
||||
// commands (misc.c get_dir).
|
||||
func (g *RogueGame) getDir() bool {
|
||||
// promptDirection sets up the direction coordinate for use in various
|
||||
// "prefix" commands (misc.c get_dir).
|
||||
func (g *RogueGame) promptDirection() bool {
|
||||
if g.Again && g.LastDir != 0 {
|
||||
g.Delta = g.lastDelt
|
||||
g.DirCh = g.LastDir
|
||||
|
||||
@@ -31,7 +31,7 @@ func (g *RogueGame) randMonster(wander bool) byte {
|
||||
func (g *RogueGame) newMonster(tp *Monster, typ byte, cp Coord) {
|
||||
levAdd := max(g.Depth-AmuletLevel, 0)
|
||||
|
||||
attachMon(&g.Level.Monsters, tp)
|
||||
g.Level.AddMonster(tp)
|
||||
tp.Type = typ
|
||||
tp.Disguise = typ
|
||||
tp.Pos = cp
|
||||
|
||||
@@ -105,7 +105,7 @@ func (g *RogueGame) putThings() {
|
||||
if g.rnd(100) < 36 {
|
||||
// Pick a new object and link it in the list
|
||||
obj := g.newThing()
|
||||
attachObj(&g.Level.Objects, obj)
|
||||
g.Level.AddObject(obj)
|
||||
// Put it somewhere
|
||||
obj.Pos, _ = g.findFloor(false)
|
||||
g.Level.SetChar(obj.Pos.Y, obj.Pos.X, obj.Kind.Glyph())
|
||||
@@ -115,7 +115,7 @@ func (g *RogueGame) putThings() {
|
||||
// yet, put it somewhere on the ground
|
||||
if g.Depth >= AmuletLevel && !g.HasAmulet {
|
||||
obj := newObject()
|
||||
attachObj(&g.Level.Objects, obj)
|
||||
g.Level.AddObject(obj)
|
||||
obj.Damage = dice("0x0")
|
||||
obj.HurlDmg = dice("0x0")
|
||||
obj.ArmorClass = 11
|
||||
@@ -137,7 +137,7 @@ func (g *RogueGame) treasureRoom() {
|
||||
mp, _ := g.findFloorIn(rp, 2*maxTries, false)
|
||||
tp := g.newThing()
|
||||
tp.Pos = mp
|
||||
attachObj(&g.Level.Objects, tp)
|
||||
g.Level.AddObject(tp)
|
||||
g.Level.SetChar(mp.Y, mp.X, tp.Kind.Glyph())
|
||||
}
|
||||
|
||||
|
||||
78
game/pack.go
78
game/pack.go
@@ -9,7 +9,7 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
|
||||
fromFloor := false
|
||||
|
||||
if obj == nil {
|
||||
if obj = g.findObj(p.Pos.Y, p.Pos.X); obj == nil {
|
||||
if obj = g.Level.ObjectAt(p.Pos.Y, p.Pos.X); obj == nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
|
||||
|
||||
// Check for and deal with scare monster scrolls
|
||||
if obj.Kind == KindScroll && obj.ScrollKind() == ScrollScareMonster && obj.Flags.Has(WasFound) {
|
||||
detachObj(&g.Level.Objects, obj)
|
||||
g.Level.RemoveObject(obj)
|
||||
g.mvaddch(p.Pos.Y, p.Pos.X, g.floorCh())
|
||||
|
||||
if p.Room.Flags.Has(Gone) {
|
||||
@@ -34,7 +34,7 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
|
||||
|
||||
if len(p.Pack) == 0 {
|
||||
p.Pack = append(p.Pack, obj)
|
||||
obj.PackCh = g.packChar()
|
||||
obj.PackCh = p.nextPackChar()
|
||||
p.Inpack++
|
||||
} else {
|
||||
// Walk the pack looking for the insertion point, keeping items of
|
||||
@@ -112,7 +112,7 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
|
||||
return
|
||||
}
|
||||
|
||||
obj.PackCh = g.packChar()
|
||||
obj.PackCh = p.nextPackChar()
|
||||
p.Pack = append(p.Pack[:lp+1],
|
||||
append([]*Object{obj}, p.Pack[lp+1:]...)...)
|
||||
}
|
||||
@@ -137,7 +137,7 @@ func (g *RogueGame) addPack(obj *Object, silent bool) {
|
||||
g.addmsgf("you now have ")
|
||||
}
|
||||
|
||||
g.msg("%s (%c)", g.invName(obj, !g.Options.Terse), obj.PackCh)
|
||||
g.msg("%s (%c)", g.inventoryName(obj, !g.Options.Terse), obj.PackCh)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ func (g *RogueGame) packRoom(fromFloor bool, obj *Object) bool {
|
||||
}
|
||||
|
||||
if fromFloor {
|
||||
detachObj(&g.Level.Objects, obj)
|
||||
g.Level.RemoveObject(obj)
|
||||
g.mvaddch(p.Pos.Y, p.Pos.X, g.floorCh())
|
||||
|
||||
if p.Room.Flags.Has(Gone) {
|
||||
@@ -181,46 +181,17 @@ func (g *RogueGame) packRoom(fromFloor bool, obj *Object) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// leavePack takes an item out of the pack (pack.c leave_pack).
|
||||
// leavePack takes an item out of the pack (pack.c leave_pack), keeping
|
||||
// the repeat-command bookkeeping; the pack surgery is
|
||||
// Player.removeFromPack.
|
||||
func (g *RogueGame) leavePack(obj *Object, newobj, all bool) *Object {
|
||||
p := &g.Player
|
||||
p.Inpack--
|
||||
|
||||
nobj := obj
|
||||
if obj.Count > 1 && !all {
|
||||
g.LastPick = obj
|
||||
|
||||
obj.Count--
|
||||
if obj.Group != 0 {
|
||||
p.Inpack++
|
||||
}
|
||||
|
||||
if newobj {
|
||||
copied := *obj
|
||||
nobj = &copied
|
||||
nobj.Count = 1
|
||||
}
|
||||
} else {
|
||||
g.LastPick = nil
|
||||
p.PackUsed[obj.PackCh-'a'] = false
|
||||
detachObj(&p.Pack, obj)
|
||||
}
|
||||
|
||||
return nobj
|
||||
}
|
||||
|
||||
// packChar returns the next unused pack character (pack.c pack_char).
|
||||
func (g *RogueGame) packChar() byte {
|
||||
p := &g.Player
|
||||
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
|
||||
return g.Player.removeFromPack(obj, newobj, all)
|
||||
}
|
||||
|
||||
// inventory lists what is in the pack; returns true if there is something
|
||||
@@ -236,7 +207,7 @@ func (g *RogueGame) inventory(list []*Object, kind ObjectKind) bool {
|
||||
g.NObjs++
|
||||
g.Msgs.MsgEsc = true
|
||||
|
||||
line := string(item.PackCh) + ") " + g.invName(item, false)
|
||||
line := string(item.PackCh) + ") " + g.inventoryName(item, false)
|
||||
if g.addLine("%s", line) == Escape {
|
||||
g.Msgs.MsgEsc = false
|
||||
g.msg("")
|
||||
@@ -277,7 +248,7 @@ func (g *RogueGame) pickUp(ch byte) {
|
||||
return
|
||||
}
|
||||
|
||||
obj := g.findObj(p.Pos.Y, p.Pos.X)
|
||||
obj := g.Level.ObjectAt(p.Pos.Y, p.Pos.X)
|
||||
if g.MoveOn {
|
||||
g.moveMsg(obj)
|
||||
|
||||
@@ -291,7 +262,7 @@ func (g *RogueGame) pickUp(ch byte) {
|
||||
}
|
||||
|
||||
g.money(obj.GoldValue)
|
||||
detachObj(&g.Level.Objects, obj)
|
||||
g.Level.RemoveObject(obj)
|
||||
|
||||
p.Room.GoldVal = 0
|
||||
default:
|
||||
@@ -323,7 +294,7 @@ func (g *RogueGame) moveMsg(obj *Object) {
|
||||
g.addmsgf("you ")
|
||||
}
|
||||
|
||||
g.msg("moved onto %s", g.invName(obj, true))
|
||||
g.msg("moved onto %s", g.inventoryName(obj, true))
|
||||
}
|
||||
|
||||
// pickyInven allows the player to inventory a single item (pack.c
|
||||
@@ -337,7 +308,7 @@ func (g *RogueGame) pickyInven() {
|
||||
}
|
||||
|
||||
if len(p.Pack) == 1 {
|
||||
g.msg("a) %s", g.invName(p.Pack[0], false))
|
||||
g.msg("a) %s", g.inventoryName(p.Pack[0], false))
|
||||
|
||||
return
|
||||
}
|
||||
@@ -354,7 +325,7 @@ func (g *RogueGame) pickyInven() {
|
||||
|
||||
for _, obj := range p.Pack {
|
||||
if mch == obj.PackCh {
|
||||
g.msg("%c) %s", mch, g.invName(obj, false))
|
||||
g.msg("%c) %s", mch, g.inventoryName(obj, false))
|
||||
|
||||
return
|
||||
}
|
||||
@@ -363,23 +334,24 @@ func (g *RogueGame) pickyInven() {
|
||||
g.msg("'%s' not in pack", unctrl(mch))
|
||||
}
|
||||
|
||||
// getItem picks something out of a pack for a purpose (pack.c get_item).
|
||||
func (g *RogueGame) getItem(purpose string, kind ObjectKind) *Object {
|
||||
// promptPackItem picks something out of a pack for a purpose (pack.c
|
||||
// get_item); ok reports whether the player chose an item.
|
||||
func (g *RogueGame) promptPackItem(purpose string, kind ObjectKind) (obj *Object, ok bool) {
|
||||
p := &g.Player
|
||||
if len(p.Pack) == 0 {
|
||||
g.msg("you aren't carrying anything")
|
||||
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if g.Again {
|
||||
if g.LastPick != nil {
|
||||
return g.LastPick
|
||||
return g.LastPick, true
|
||||
}
|
||||
|
||||
g.msg("you ran out")
|
||||
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
|
||||
for {
|
||||
@@ -402,7 +374,7 @@ func (g *RogueGame) getItem(purpose string, kind ObjectKind) *Object {
|
||||
g.After = false
|
||||
g.msg("")
|
||||
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
|
||||
g.NObjs = 1 // normal case: person types one char
|
||||
@@ -411,7 +383,7 @@ func (g *RogueGame) getItem(purpose string, kind ObjectKind) *Object {
|
||||
if !g.inventory(p.Pack, kind) {
|
||||
g.After = false
|
||||
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
|
||||
continue
|
||||
@@ -419,7 +391,7 @@ func (g *RogueGame) getItem(purpose string, kind ObjectKind) *Object {
|
||||
|
||||
for _, obj := range p.Pack {
|
||||
if obj.PackCh == ch {
|
||||
return obj
|
||||
return obj, true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ type pact struct {
|
||||
// quaff drinks a potion from the pack (potions.c quaff).
|
||||
func (g *RogueGame) quaff() {
|
||||
p := &g.Player
|
||||
obj := g.getItem("quaff", KindPotion)
|
||||
obj, ok := g.promptPackItem("quaff", KindPotion)
|
||||
// Make certain that it is something that we want to drink
|
||||
if obj == nil {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func (g *RogueGame) quaff() {
|
||||
|
||||
switch obj.PotionKind() {
|
||||
case PotionConfusion:
|
||||
g.doPot(PotionConfusion, !trip)
|
||||
g.applyPotionFuse(PotionConfusion, !trip)
|
||||
case PotionPoison:
|
||||
g.Items.Potions[PotionPoison].Know = true
|
||||
if p.IsWearing(RingSustainStrength) {
|
||||
@@ -118,11 +118,11 @@ func (g *RogueGame) quaff() {
|
||||
g.SeenStairs = g.seenStairs()
|
||||
}
|
||||
|
||||
g.doPot(PotionLSD, true)
|
||||
g.applyPotionFuse(PotionLSD, true)
|
||||
case PotionSeeInvisible:
|
||||
show := p.On(CanSeeInvisible)
|
||||
|
||||
g.doPot(PotionSeeInvisible, false)
|
||||
g.applyPotionFuse(PotionSeeInvisible, false)
|
||||
|
||||
if !show {
|
||||
g.invisOn()
|
||||
@@ -177,9 +177,9 @@ func (g *RogueGame) quaff() {
|
||||
|
||||
g.msg("hey, this tastes great. It make you feel warm all over")
|
||||
case PotionBlindness:
|
||||
g.doPot(PotionBlindness, true)
|
||||
g.applyPotionFuse(PotionBlindness, true)
|
||||
case PotionLevitation:
|
||||
g.doPot(PotionLevitation, true)
|
||||
g.applyPotionFuse(PotionLevitation, true)
|
||||
}
|
||||
|
||||
g.status()
|
||||
@@ -194,9 +194,9 @@ func (g *RogueGame) raiseLevel() {
|
||||
g.checkLevel()
|
||||
}
|
||||
|
||||
// doPot does a potion with standard setup: it uses a fuse and turns on a
|
||||
// flag (potions.c do_pot).
|
||||
func (g *RogueGame) doPot(kind PotionKind, knowit bool) {
|
||||
// applyPotionFuse does a potion with standard setup: it uses a fuse and
|
||||
// turns on a flag (potions.c do_pot).
|
||||
func (g *RogueGame) applyPotionFuse(kind PotionKind, knowit bool) {
|
||||
pp := &g.data.pActions[kind]
|
||||
if !g.Items.Potions[kind].Know {
|
||||
g.Items.Potions[kind].Know = knowit
|
||||
|
||||
@@ -7,9 +7,9 @@ import "fmt"
|
||||
// ringOn puts a ring on a hand (rings.c ring_on).
|
||||
func (g *RogueGame) ringOn() {
|
||||
p := &g.Player
|
||||
obj := g.getItem("put on", KindRing)
|
||||
obj, ok := g.promptPackItem("put on", KindRing)
|
||||
// Make certain that it is something that we want to wear
|
||||
if obj == nil {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ func (g *RogueGame) ringOn() {
|
||||
g.addmsgf("you are now wearing ")
|
||||
}
|
||||
|
||||
g.msg("%s (%c)", g.invName(obj, true), obj.PackCh)
|
||||
g.msg("%s (%c)", g.inventoryName(obj, true), obj.PackCh)
|
||||
}
|
||||
|
||||
// ringOff takes off a ring (rings.c ring_off).
|
||||
@@ -103,7 +103,7 @@ func (g *RogueGame) ringOff() {
|
||||
}
|
||||
|
||||
if g.dropCheck(obj) {
|
||||
g.msg("was wearing %s(%c)", g.invName(obj, true), obj.PackCh)
|
||||
g.msg("was wearing %s(%c)", g.inventoryName(obj, true), obj.PackCh)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ func (g *RogueGame) totalWinner() {
|
||||
}
|
||||
|
||||
g.scr.Std.MvPrintwf(line, 0, "%c) %5d %s", obj.PackCh, worth,
|
||||
g.invName(obj, false))
|
||||
g.inventoryName(obj, false))
|
||||
line++
|
||||
p.Purse += worth
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ func (g *RogueGame) digRooms() {
|
||||
gold.Flags = Stackable
|
||||
gold.Group = goldGrp
|
||||
gold.Kind = KindGold
|
||||
attachObj(&g.Level.Objects, gold)
|
||||
g.Level.AddObject(gold)
|
||||
}
|
||||
// Put the monster in
|
||||
prob := 25
|
||||
|
||||
@@ -618,6 +618,7 @@ func Restore(path string, cfg Config) (*RogueGame, error) {
|
||||
restored: true,
|
||||
}
|
||||
g.scr = NewScreen(cfg.Term)
|
||||
g.Msgs.attach(g.scr, g.look, g.readchar)
|
||||
g.applySnapshot(&st)
|
||||
|
||||
// defeat multiple restarting from the same place
|
||||
|
||||
@@ -7,8 +7,8 @@ package game
|
||||
func (g *RogueGame) readScroll() {
|
||||
p := &g.Player
|
||||
|
||||
obj := g.getItem("read", KindScroll)
|
||||
if obj == nil {
|
||||
obj, ok := g.promptPackItem("read", KindScroll)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ func (g *RogueGame) readScroll() {
|
||||
// Or anything else nasty
|
||||
if ch := g.Level.VisibleChar(y, x); stepOk(ch) {
|
||||
if ch == Scroll {
|
||||
if fo := g.findObj(y, x); fo != nil && fo.ScrollKind() == ScrollScareMonster {
|
||||
if fo := g.Level.ObjectAt(y, x); fo != nil && fo.ScrollKind() == ScrollScareMonster {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ const (
|
||||
func (g *RogueGame) doZap() {
|
||||
p := &g.Player
|
||||
|
||||
obj := g.getItem("zap with", KindWand)
|
||||
if obj == nil {
|
||||
obj, ok := g.promptPackItem("zap with", KindWand)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ func (g *RogueGame) doZap() {
|
||||
}
|
||||
case WandPolymorph:
|
||||
pp := tp.Pack
|
||||
detachMon(&g.Level.Monsters, tp)
|
||||
g.Level.RemoveMonster(tp)
|
||||
|
||||
if g.seeMonst(tp) {
|
||||
g.mvaddch(y, x, g.Level.Char(y, x))
|
||||
|
||||
@@ -94,7 +94,7 @@ type gameData struct {
|
||||
initWeaps [NumWeaponTypes]weaponSetup
|
||||
|
||||
// pActions is potions.c p_actions[]. The P_SEEINVIS message is dynamic
|
||||
// (it names the fruit) and is computed in doPot.
|
||||
// (it names the fruit) and is computed in applyPotionFuse.
|
||||
pActions [NumPotionTypes]pact
|
||||
|
||||
// idType maps identify scrolls to the kind of item they identify
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
// invName returns the name of something as it would appear in an inventory
|
||||
// (things.c inv_name).
|
||||
func (g *RogueGame) invName(obj *Object, drop bool) string {
|
||||
func (g *RogueGame) inventoryName(obj *Object, drop bool) string {
|
||||
var pb strings.Builder
|
||||
|
||||
which := obj.Which
|
||||
@@ -142,8 +142,8 @@ func (g *RogueGame) dropIt() {
|
||||
return
|
||||
}
|
||||
|
||||
obj := g.getItem("drop", KindNone)
|
||||
if obj == nil {
|
||||
obj, ok := g.promptPackItem("drop", KindNone)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ func (g *RogueGame) dropIt() {
|
||||
|
||||
obj = g.leavePack(obj, true, !obj.Kind.MergesInPack())
|
||||
// Link it into the level object list
|
||||
attachObj(&g.Level.Objects, obj)
|
||||
g.Level.AddObject(obj)
|
||||
g.Level.SetChar(p.Pos.Y, p.Pos.X, obj.Kind.Glyph())
|
||||
g.Level.FlagsAt(p.Pos.Y, p.Pos.X).Set(FDropped)
|
||||
|
||||
@@ -162,7 +162,7 @@ func (g *RogueGame) dropIt() {
|
||||
g.HasAmulet = false
|
||||
}
|
||||
|
||||
g.msg("dropped %s", g.invName(obj, true))
|
||||
g.msg("dropped %s", g.inventoryName(obj, true))
|
||||
}
|
||||
|
||||
// dropCheck does special checks for dropping or unwielding|unwearing|
|
||||
@@ -392,7 +392,7 @@ func (g *RogueGame) printDisc(typ byte) {
|
||||
if info[order[i]].Know || info[order[i]].Guess != "" {
|
||||
obj.Kind = objectKindForGlyph(typ)
|
||||
obj.Which = order[i]
|
||||
g.addLine("%s", g.invName(&obj, false))
|
||||
g.addLine("%s", g.inventoryName(&obj, false))
|
||||
|
||||
numFound++
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ const noWeapon WeaponKind = -1
|
||||
// missile fires a missile in a given direction (weapons.c missile).
|
||||
func (g *RogueGame) missile(ydelta, xdelta int) {
|
||||
// Get which thing we are hurling
|
||||
obj := g.getItem("throw", KindWeapon)
|
||||
if obj == nil {
|
||||
obj, ok := g.promptPackItem("throw", KindWeapon)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ func (g *RogueGame) fall(obj *Object, pr bool) {
|
||||
}
|
||||
}
|
||||
|
||||
attachObj(&g.Level.Objects, obj)
|
||||
g.Level.AddObject(obj)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -113,8 +113,8 @@ func (g *RogueGame) wield() {
|
||||
|
||||
p.CurWeapon = oweapon
|
||||
|
||||
obj := g.getItem("wield", KindWeapon)
|
||||
if obj == nil {
|
||||
obj, ok := g.promptPackItem("wield", KindWeapon)
|
||||
if !ok {
|
||||
g.After = false
|
||||
|
||||
return
|
||||
@@ -133,7 +133,7 @@ func (g *RogueGame) wield() {
|
||||
return
|
||||
}
|
||||
|
||||
sp := g.invName(obj, true)
|
||||
sp := g.inventoryName(obj, true)
|
||||
p.CurWeapon = obj
|
||||
|
||||
if !g.Options.Terse {
|
||||
|
||||
@@ -119,7 +119,7 @@ func (g *RogueGame) whatis(insist bool, kind ObjectKind) {
|
||||
|
||||
var obj *Object
|
||||
for {
|
||||
obj = g.getItem("identify", kind)
|
||||
obj, _ = g.promptPackItem("identify", kind)
|
||||
|
||||
if !insist {
|
||||
break
|
||||
@@ -161,7 +161,7 @@ func (g *RogueGame) whatis(insist bool, kind ObjectKind) {
|
||||
setKnow(obj, g.Items.Rings[:])
|
||||
}
|
||||
|
||||
g.msg("%s", g.invName(obj, false))
|
||||
g.msg("%s", g.inventoryName(obj, false))
|
||||
}
|
||||
|
||||
// setKnow sets things up when we really know what a thing is (wizard.c
|
||||
|
||||
Reference in New Issue
Block a user