If you are like me and found the need for an energy system to schedule your entity actions, you probably haven't found much clearly stated on the net (or I missed it in my searches). Implementing an energy system runs into two additional potential problems; multi-move jumps in display state, and possibly an unstable (unsaveable) game state when processing halts due to needing player input. It sounds like a thorny problem, but after you break it down, it isn't so bad, the following is, I believe, a fairly clean solution.
First, lets deal with the multi-move jumps in display state. This is where a mob takes two or more actions (typically moves) to the player's one. If you simply give the display a new state after each player move, you end up with 'teleporting' mobs, jerky actions. You can, of course, turn to something like a physics engine and do an animated display, interpolating the move over time so it looks good. However, why not eliminate the problem in the first place?
An energy system works by adding a value based on an entity's speed to the entity's energy state each turn. In simple systems, an entity with a positive energy level is free to take an action. The action's energy cost is subtracted from the entity's energy level.
If our display system is typical of today's frame rate driven loops, then instead of doing all the work at once, we can use a divisor to spread the work over multiple frames where each frame (or sequence of n-frames) receives a stable picture of the game state. The ideal divisor is one that is large enough to ensure that no entity can take two actions in one processing tick. That is, the fastest speed energy add amount divided by the divisor is smaller than twice the quickest action energy cost.
A nice side effect of using a divisor is that after each processing step we potentially have a stable game state so we can do 'save anytime' save games (useful for debugging at the very least). Potentially, because there is another wrinkle to the overall problem. Player entities can normally only act if input from the player is available.
Part of doing an energy system is ordering actions by entity energy. This isn't just an afterthought, it is a necessary part of making a consistent acting system. Typically this is done by sorting or by a priority queue. Sorting is simpler, and hey, we're doing roguelike, we have cycles to spare (although sorting in this case is probably *faster* than a reprioritizing priority queue).
Now though, we have a dilemma, halfway through our sorted list of entities by positive energy levels (descending), we run into our player entity. No problem, we say, we'll just grab the next player command out of the input queue and... oops... nothing there. We're stuck. We have to bail and return control to the user interface, but we have a half done list, an unstable state. Sure there are some coroutine hacks that might let us actually yield then resume later, but between the yield and resume we can't save the game state because it is not in a stable state.
There is a simple solution, one that doesn't require saving some sort of quirky interim state. Before we even start processing the tick, we check to see if A) there is player input in the queue, and if not B) that the player's next energy level won't be above zero. That is, we check to see if the player's entity is going to run into the stalling scenario above, and simply return from the process game function without doing anything to avoid it. Maybe that's why my google-fu failed, everyone that has done it considered it too simple to need writing up!
Ok, time for some pseudo code:
GameLoop:
GetInput => add command to player entity input queue if necessary
Update => call the engine's Process function
Render => do what I'm really bad at
Engine Process function:
if no commands waiting in player entity input queue:
player_tick_energy = player_speed / tick_divisor
if player_entity.energy + player_tick_energy > 0 then return "Hey I need input!"
otherwise // much better than else
pending_list = new list (or clear old one and reuse each tick)
foreach entity in actor_list: // actor_list includes anything that can act (mobs/some items/traps/unstable walls/etc)
add entity.speed / tick_divisior to entity.energy
if entity.energy > 0 then add to pending list
pending_list.Sort( on energy descending ) // highest energy levels first
foreach entity in pending_list:
do something and adjust entity energy level by subtracting cost of something action
// this is where we would've run into the stall problem if we hadn't made sure the player entity wouldn't hang
clean up and return
Simple.
Hope this helps,
Brian aka Omnivore
PS: There is a slightly more complicated, improved version that handles a number of possible additional cases, as well as ensuring that every action that could be taken before player stall is taken before halting. In C# it could be done using a custom struct that supports IComparable<T> in place of the raw entity for the pending list. The custom struct holds the entity.energy + entity_tick_energy in an additional field (that is sorted on). This allows any entity to abort the current process function without causing an unstable state.
PSPS: Slight error in the divisor calculation, the largest speed add divided by the divisor should be smaller than the lowest cost action.