For efficiency, all game related tasks performed by scripts or the engine itself should be event-driven. That way, actions â€“ which are usually written in Python â€“ are only executed when needed. Given that it is rather costly to call a Python method from C++ only to check a condition or to increase a counter, an integrated event dispatcher is a must to improve overall performance.
To make event handling even more efficient, there isnâ€™t a single event manager to take care of all events. Instead, one can write specialized manager classes for each type of event. These must be derived from manager_base and registered with the generic manager that will pass on events accordingly. This generic manager also provides the interface other modules require to dispatch events, completely hiding the specialized managers to the outside.
In order to get notified of events, a listener needs to be created and registered with the manager. If an event occurs, all matching listeners are activated, resulting in the execution of the Python callbacks they provide. Each callback will receive a pointer to the listener itself, to the triggering event and, optionally, further user defined arguments. Latter are specified when connecting the callback to the listener, but can be easily changed from within the callback â€“ as the callback itself. User defined arguments are currently limited to integers and strings, as more complex ob jects cannot be saved when serializing a listener.
If an ob ject does not want to receive any events temporariliy, it can pause its listeners, thus avoiding the need to destroy them completely. Listeners can further have a repeat count, meaning they will destroy themselves after receiving a certain number of events.
Since objects will often have several listeners for different events, a factory can be used to group them together. Via the factory, all listeners can be paused or resumed, saved and loaded, thus removing the need to keep track of each individual listener.
To avoid cyclic dependencies of modules, actual events are located in the module they best fit in. The event module itself is written in such a way that it needs not know about other events at compile time. Instead, other modules may register their events with the event system at runtime. Currently, the following events are implemented/planned:
- time events are triggered when a second of gametime has passed and allow to schedule events that are either repetitive or should take place at a specific time. They are located in the event module itself, as they depend on the date and time implementation.
- quest events are triggered whenever the state of a quest step changes. This is useful to exchange schedules of NPCs to match the players progress in the game. They are implemented in the Rpg Module.
- audio events mark the end of a piece of background music or sfx. They allow for a more dynamic audio system and are implemented by the Audio Module.
- map events are triggered when characters reach certain positions on the map. They can be used to build telporters, traps, trigger dialogues of party members and many other things to make the gameworld more dynamic. They will be implemented by the Map Module.
- action events are triggered when the player presses certain keys. They will initiate dialogue or battle, open doors or pick up items. They are implemented by the Map Module.
- ui events are triggered whenever actions on the user interface are performed, such as button presses, list item selections or the closing of a dialog. They are implemented by the GUI Module.
Date and Time
Closely related to the event system is the game time, because many events in the game will be time based â€“ especially those required for implementing NPC behaviour.
Time in the game will usually differ from real world time and is measured by game cycles. As the number of cycles per second is constant, game time will progress at a constant rate too. For that, a call to date::update after each cycle is required. Whenever a second of game time has passed (which is currently defined as five game cycles), a time event is dispatched.
The date class also provides fixed conversion methods to get the current weekday, day, hour, minute and second, based on a 7 day week, 24 hour day. In future, custom conversion rules might be made available to allow more unusual in-game date and time.