Sunday, April 30, 2017

The ADOM event system

This week I've been working on adding more ADOM soundtracks by Lucas, and thought you might want to know what triggers them to be played in-game. There's a cool yet simple (or complex? :p) underlying mechanic called the event system.

During the early integration phase of ADOM and NotEye (which was around the end of 2012) we needed to find a way to control NotEye from ADOM (e.g. to show a specific screen or play a sound effect). We also decided to integrate ADOM and NotEye very loosely, so that we could easily switch to other frontends (if required).

NotEye provides a Curses like interface which is used by ADOM to deliver the screen contents (text and colors) which NotEye then renders (in ASCII mode). It also provides a keyboard/mouse interface which ADOM uses to get the player input.

Additionally ADOM provides a (quite complex) JSON data structure which NotEye can access to retrieve information about the whole game map (e.g. monsters, items, tiles, traps) that is used in "graphical" mode.

But this still wasn't enough. What if we wanted to play an animation or sound effect when the player used his weapon? After some discussion we decided to use an event system: the idea was to trigger events from ADOM and then let NotEye decide how to react to them.

We use events for a lot of things (e.g. to control NotEye, play music/sound effects, show animations). You can find all event definitions in the file <ADOM>/games/adom-tables.noe ("gameeventids").

Each event is represented by a JSON object (we really like JSON) with one or more properties.

For example, this is an event that is triggered whenever the player uses his weapon:

It contains the weapon type, the hit type (either a hit or a miss), the direction of the attack and other values that might be useful (the game_event_id is required for all events).

So, how is this event handled by NotEye once it is triggered from ADOM? NotEye loops over every event it receives and hands it over to every "module" (e.g. the animation module, the sound module). Each module then can decide to either react to the event or to ignore it.

The animation module reacts to the weapon event, we use it to play a "swish" animation to indicate the attack (the line is taken from the <ADOM>/gfx/adom/anim.cfg configuration file):

event=GE_WEAPON_USED, direction=SE, hit-type=NORMAL_HIT | CRITICAL_HIT, ...

This line describes what animation should be played once the GE_WEAPON_USED event is received (more on that in another article).

Additionally the sound module reacts to it, we play a sound effect (taken from the <ADOM>/sound/sound.cfg configuration file):

event=GE_WEAPON_USED, item-weapon-type=IWT_SWORD, file=weapon/sword_1.wav

So one event triggered from ADOM results in two actions: an animation is shown and a sound effect is played. As you can see, the event system is very flexible and extendable.

With all this in place handling new events, like playing a sound after loading a game, or triggering animations is a breeze. Hopefully we'll get more of those soon :)

Until next time!

No comments:

Post a Comment