Extract MessageLine, Player pack ops, and Level list management
Refactor step 6. MessageLine (was MsgLine) owns the msg/addmsg/endmsg machinery, wired to its screen, pre---More-- redraw, and input via attach(); RogueGame keeps one-line msg/addmsgf/endmsg shorthands so the ~400 call sites are unchanged. Player gains nextPackChar and removeFromPack (the state half of pack.c leave_pack); leavePack keeps only the LastPick repeat-command tracking. Level gains ObjectAt (misc.c find_obj) and AddObject/RemoveObject/AddMonster/RemoveMonster, replacing direct attach/detach calls on the level lists. Inventory and pickup UI flows stay on RogueGame: display and orchestration, not state surgery. Behavior and RNG order unchanged; suite green.
This commit is contained in:
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 {
|
||||
|
||||
Reference in New Issue
Block a user