diff --git a/game/daemons.go b/game/daemons.go index e78307c..4909706 100644 --- a/game/daemons.go +++ b/game/daemons.go @@ -5,38 +5,14 @@ package game // runDaemon invokes the callback named by id (the call through d_func in C). func (g *RogueGame) runDaemon(id DaemonID, arg int) { - switch id { - case DRollwand: - g.rollwand(arg) - case DDoctor: - g.doctor(arg) - case DStomach: - g.stomach(arg) - case DRunners: - g.runners(arg) - case DSwander: - g.swander(arg) - case DNohaste: - g.nohaste(arg) - case DUnconfuse: - g.unconfuse(arg) - case DUnsee: - g.unsee(arg) - case DSight: - g.sight(arg) - case DVisuals: - g.visuals(arg) - case DComeDown: - g.comeDown(arg) - case DLand: - g.land(arg) - case DTurnSee: - g.turnSee(arg != 0) - default: - // Callbacks are added to this switch as their subsystems are - // ported; reaching one that isn't here is a porting bug. + h := g.data.daemonHandlers[id] + if h == nil { + // Handlers are added to the table as their subsystems are + // ported; reaching one that isn't there is a porting bug. panic("daemon not yet ported") } + + h(g, arg) } // doctor is the healing daemon that restores hit points after rest @@ -141,50 +117,9 @@ func (g *RogueGame) stomach(int) { origHungry := p.HungryState if p.FoodLeft <= 0 { - if p.FoodLeft--; p.FoodLeft < -StarveTime { - g.death('s') - } - // the hero is fainting - if g.NoCommand != 0 || g.rnd(5) != 0 { - return - } - - g.NoCommand += g.rnd(8) + 4 - p.HungryState = 3 - - if !g.Options.Terse { - g.addmsgf("%s", g.chooseStr( - "the munchies overpower your motor capabilities. ", - "you feel too weak from lack of food. ")) - } - - g.msg("%s", g.chooseStr("You freak out", "You faint")) + g.stomachFaint() } else { - oldfood := p.FoodLeft - - amulet := 0 - if g.HasAmulet { - amulet = 1 - } - - p.FoodLeft -= g.ringEat(Left) + g.ringEat(Right) + 1 - amulet - - if p.FoodLeft < MoreTime && oldfood >= MoreTime { - p.HungryState = 2 - - g.msg("%s", g.chooseStr( - "the munchies are interfering with your motor capabilities", - "you are starting to feel weak")) - } else if p.FoodLeft < 2*MoreTime && oldfood >= 2*MoreTime { - p.HungryState = 1 - - if g.Options.Terse { - g.msg("%s", g.chooseStr("getting the munchies", "getting hungry")) - } else { - g.msg("%s", g.chooseStr("you are getting the munchies", - "you are starting to get hungry")) - } - } + g.stomachDigest() } if p.HungryState != origHungry { @@ -196,6 +131,61 @@ func (g *RogueGame) stomach(int) { } } +// stomachFaint starves and possibly faints an empty-stomached hero (the +// no-food arm of daemons.c stomach). +func (g *RogueGame) stomachFaint() { + p := &g.Player + if p.FoodLeft--; p.FoodLeft < -StarveTime { + g.death('s') + } + // the hero is fainting + if g.NoCommand != 0 || g.rnd(5) != 0 { + return + } + + g.NoCommand += g.rnd(8) + 4 + p.HungryState = 3 + + if !g.Options.Terse { + g.addmsgf("%s", g.chooseStr( + "the munchies overpower your motor capabilities. ", + "you feel too weak from lack of food. ")) + } + + g.msg("%s", g.chooseStr("You freak out", "You faint")) +} + +// stomachDigest burns food and reports growing hunger (the fed arm of +// daemons.c stomach). +func (g *RogueGame) stomachDigest() { + p := &g.Player + oldfood := p.FoodLeft + + amulet := 0 + if g.HasAmulet { + amulet = 1 + } + + p.FoodLeft -= g.ringEat(Left) + g.ringEat(Right) + 1 - amulet + + if p.FoodLeft < MoreTime && oldfood >= MoreTime { + p.HungryState = 2 + + g.msg("%s", g.chooseStr( + "the munchies are interfering with your motor capabilities", + "you are starting to feel weak")) + } else if p.FoodLeft < 2*MoreTime && oldfood >= 2*MoreTime { + p.HungryState = 1 + + if g.Options.Terse { + g.msg("%s", g.chooseStr("getting the munchies", "getting hungry")) + } else { + g.msg("%s", g.chooseStr("you are getting the munchies", + "you are starting to get hungry")) + } + } +} + // comeDown takes the hero down off her acid trip (daemons.c come_down). func (g *RogueGame) comeDown(int) { p := &g.Player @@ -242,7 +232,6 @@ func (g *RogueGame) comeDown(int) { // visuals changes the characters for the player while hallucinating // (daemons.c visuals). func (g *RogueGame) visuals(int) { - p := &g.Player if !g.After || (g.Running && g.Options.Jump) { return } @@ -259,7 +248,13 @@ func (g *RogueGame) visuals(int) { } // change the monsters - seemonst := p.On(SenseMonsters) + g.visualMonsters() +} + +// visualMonsters redraws the monsters through the hallucination (the +// monster loop of daemons.c visuals). +func (g *RogueGame) visualMonsters() { + seemonst := g.Player.On(SenseMonsters) for _, tp := range g.Level.Monsters { g.move(tp.Pos.Y, tp.Pos.X) diff --git a/game/tables.go b/game/tables.go index 7455d7e..94934e3 100644 --- a/game/tables.go +++ b/game/tables.go @@ -151,6 +151,10 @@ type gameData struct { // trapHandlers dispatches each sprung trap to its effect method: // the cases of the move.c be_trapped switch. trapHandlers [NumTrapTypes]func(g *RogueGame, tc Coord) + + // daemonHandlers dispatches DaemonIDs to their callbacks: the C + // d_func function pointers (daemons.c / daemon.c). + daemonHandlers [DTurnSee + 1]func(g *RogueGame, arg int) } // ripWall is the repeated blank wall line of the tombstone art. @@ -826,6 +830,24 @@ func newGameData() *gameData { TrapRust: (*RogueGame).trapRust, TrapMystery: (*RogueGame).trapMystery, }, + + daemonHandlers: [DTurnSee + 1]func(*RogueGame, int){ + DRollwand: (*RogueGame).rollwand, + DDoctor: (*RogueGame).doctor, + DStomach: (*RogueGame).stomach, + DRunners: (*RogueGame).runners, + DSwander: (*RogueGame).swander, + DNohaste: (*RogueGame).nohaste, + DUnconfuse: (*RogueGame).unconfuse, + DUnsee: (*RogueGame).unsee, + DSight: (*RogueGame).sight, + DVisuals: (*RogueGame).visuals, + DComeDown: (*RogueGame).comeDown, + DLand: (*RogueGame).land, + DTurnSee: func(g *RogueGame, arg int) { + g.turnSee(arg != 0) + }, + }, } }