Time systems are controllers built into a roguelike engine which handle the order of interaction of the actors inside the world. There are many ways to handle the interactions and they are usually unique to each project; However, certain similarities allow to propose a categorization on the following:
Have the main game loop handle UI and call move_monsters() (or generally any other function that advances the whole world a turn) in the code for some of the player actions (the ones that consume a turn). Generally inflexible approach, although might seem appealing for animation-heavy and âmodernâ game.
Youâve got your main loop that iterates over all the âactorsâ (things that can act, be it the player character, the monster or self-closing door), asks them what they want to do and performs it if itâs possible. The actors might still be able to do some things by themselves, without consuming a turn.
This approach is better, but itâs a bit awkward to write the actorâs code, because every turn the function is called anew â youâve got to record all state information in the actorâs data, and probably do a switch statement at the beginning of the actorâs code⌠Note that âslowâ monster may wait once per several turns, and âfastâ monsters can perform some actions without returning, but itâs a little messy.
If you want an action like eating to take several turns, you just mark in the actorâs data that itâs eating, check for interrupts, update the counters and return.
In this approach youâve got a kind of priority queue, or other similar thing, that holds the actors. You remove actors from the queue, call their functions, perform their actions and then put them back into the a sorted position into the queue. The position depends on how much time the action took â you must keep track of it.
Interrupts can be handled in two ways â you can use small steps for long actions, exactly like in the previous approach, or you can use more accurate system:
Have the action separated into the preparation and the effect parts. When you add do queue an actor that decided to do a preparation action, add it with proper delay, but add it also to a special âwatchersâ lists. Every time any actor does something, all the actors in the âwatchersâ list are informed about it and have to decide whether continue the preparation (then nothing happens) or interrupt it (then they are moved to the beginning of the queue), then the âpreparationâ is cancelled and they are free to decide upon their own action. When you reach in the queue an actor that was âpreparingâ and didnât cancel it, it can do the âeffectâ part of itâs action, actually performing it.
The game time is separated into âticksâ â they are like turns in the âsimple turnsâ approach. A main loop iterates over all the actors every tick, increasing their âenergyâ counters. Every action has an energy cost. When an actor declares an action, itâs first checked whether it has enough energy for it â if yes, the energy is deducted and the action is performed instantly. If no, the actor waits until it accumulates enough. If he decides to interrupt the wait, he can use up the accumulated energy right away.
Alternatively, when the actor wishes to perform an action, given that the actor has greater than 0 energy, it performs it and has the actionâs cost deducted from its energy amount; depending on the current game speed (potentially customizable), a certain amount of energy is restored to every actor every tick. Games such as Dwarf Fortress use this approach.