go: port foundation — types, RNG, tables, daemon scheduler
Module sneak.berlin/go/rogue, package game: - types.go: all rogue.h constants, flag types, Coord/Stats/Room/ObjInfo - creature.go/object.go: the THING union split into Creature (Player/ Monster) and Object; slices replace the C linked lists - level.go: Place map with the C column-major layout and chat/flat/moat/ winat access methods - tables.go: extern.c + init.c data (bestiary, item tables, name pools) - rng.go: the exact C LCG (seed*11109+13849), golden-tested against a compiled C reference for seed compatibility - init.go: per-game item appearance randomization (init.c) - daemon.go/daemons.go: scheduler with DaemonID replacing function pointers (ids match the C save format's mapping) - game.go: RogueGame holds all former globals; NewGame constructor
This commit is contained in:
138
game/daemon.go
Normal file
138
game/daemon.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package game
|
||||
|
||||
// daemon.c — the daemon/fuse scheduler.
|
||||
//
|
||||
// C identifies daemons and fuses by function pointer; the port uses DaemonID
|
||||
// (which the C save format itself resorted to when serializing d_list), and
|
||||
// dispatches through one switch in daemons.go.
|
||||
|
||||
// DaemonID names a daemon/fuse callback. The numeric values match the
|
||||
// function-pointer-to-int mapping in state.c rs_write_daemons.
|
||||
type DaemonID int
|
||||
|
||||
const (
|
||||
DNone DaemonID = 0
|
||||
DRollwand DaemonID = 1
|
||||
DDoctor DaemonID = 2
|
||||
DStomach DaemonID = 3
|
||||
DRunners DaemonID = 4
|
||||
DSwander DaemonID = 5
|
||||
DNohaste DaemonID = 6
|
||||
DUnconfuse DaemonID = 7
|
||||
DUnsee DaemonID = 8
|
||||
DSight DaemonID = 9
|
||||
// Fuses beyond the C save map (state.c never saved these; the Go save
|
||||
// format handles them uniformly).
|
||||
DVisuals DaemonID = 10
|
||||
DComeDown DaemonID = 11
|
||||
DLand DaemonID = 12
|
||||
)
|
||||
|
||||
// Scheduling phases and slot states (daemon.c).
|
||||
const (
|
||||
dEmpty = 0
|
||||
Before = 1 // run before the player's command
|
||||
After = 2 // run after the player's command
|
||||
daemonTime = -1 // d_time sentinel: a recurring daemon, not a fuse
|
||||
)
|
||||
|
||||
// delayedAction is rogue.h struct delayed_action.
|
||||
type delayedAction struct {
|
||||
Type int // dEmpty, Before or After
|
||||
Func DaemonID
|
||||
Arg int
|
||||
Time int // daemonTime for daemons; remaining turns for fuses
|
||||
}
|
||||
|
||||
// DaemonList is the C d_list[MAXDAEMONS] plus the file statics that ride
|
||||
// along with the daemon system.
|
||||
type DaemonList struct {
|
||||
List [MaxDaemons]delayedAction
|
||||
Between int // daemons.c rollwand static `between`
|
||||
}
|
||||
|
||||
// dSlot finds an empty slot in the daemon/fuse list (daemon.c d_slot).
|
||||
func (g *RogueGame) dSlot() *delayedAction {
|
||||
for i := range g.Daemons.List {
|
||||
if g.Daemons.List[i].Type == dEmpty {
|
||||
return &g.Daemons.List[i]
|
||||
}
|
||||
}
|
||||
panic("ran out of fuse slots") // C: debug message in MASTER, NULL deref otherwise
|
||||
}
|
||||
|
||||
// findSlot finds a particular slot in the table (daemon.c find_slot).
|
||||
func (g *RogueGame) findSlot(f DaemonID) *delayedAction {
|
||||
for i := range g.Daemons.List {
|
||||
d := &g.Daemons.List[i]
|
||||
if d.Type != dEmpty && d.Func == f {
|
||||
return d
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartDaemon starts a recurring daemon (daemon.c start_daemon).
|
||||
func (g *RogueGame) StartDaemon(f DaemonID, arg, typ int) {
|
||||
dev := g.dSlot()
|
||||
dev.Type = typ
|
||||
dev.Func = f
|
||||
dev.Arg = arg
|
||||
dev.Time = daemonTime
|
||||
}
|
||||
|
||||
// KillDaemon removes a daemon from the list (daemon.c kill_daemon).
|
||||
func (g *RogueGame) KillDaemon(f DaemonID) {
|
||||
if dev := g.findSlot(f); dev != nil {
|
||||
dev.Type = dEmpty
|
||||
}
|
||||
}
|
||||
|
||||
// DoDaemons runs all the daemons that are active with the current flag
|
||||
// (daemon.c do_daemons).
|
||||
func (g *RogueGame) DoDaemons(flag int) {
|
||||
for i := range g.Daemons.List {
|
||||
dev := &g.Daemons.List[i]
|
||||
if dev.Type == flag && dev.Time == daemonTime {
|
||||
g.runDaemon(dev.Func, dev.Arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fuse starts a countdown fuse (daemon.c fuse).
|
||||
func (g *RogueGame) Fuse(f DaemonID, arg, time, typ int) {
|
||||
wire := g.dSlot()
|
||||
wire.Type = typ
|
||||
wire.Func = f
|
||||
wire.Arg = arg
|
||||
wire.Time = time
|
||||
}
|
||||
|
||||
// Lengthen extends a fuse's countdown (daemon.c lengthen).
|
||||
func (g *RogueGame) Lengthen(f DaemonID, xtime int) {
|
||||
if wire := g.findSlot(f); wire != nil {
|
||||
wire.Time += xtime
|
||||
}
|
||||
}
|
||||
|
||||
// Extinguish puts out a fuse (daemon.c extinguish).
|
||||
func (g *RogueGame) Extinguish(f DaemonID) {
|
||||
if wire := g.findSlot(f); wire != nil {
|
||||
wire.Type = dEmpty
|
||||
}
|
||||
}
|
||||
|
||||
// DoFuses decrements all fuses in the given phase and fires any that burn
|
||||
// down (daemon.c do_fuses).
|
||||
func (g *RogueGame) DoFuses(flag int) {
|
||||
for i := range g.Daemons.List {
|
||||
wire := &g.Daemons.List[i]
|
||||
if wire.Type == flag && wire.Time > 0 {
|
||||
wire.Time--
|
||||
if wire.Time == 0 {
|
||||
wire.Type = dEmpty
|
||||
g.runDaemon(wire.Func, wire.Arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user