LPC Events Inherit
Event driven programming in LPC
Before I start: My examples/text are based around the DUNE lib’s way of doing things. They are just examples, you should be able to understand anyway, but please don’t think that just because I used modify_damage() that it’ll work in your code for real ;)
I have created a quick new inherit that allows for something called event driven programming. My hope is that this inherit will allow people to create more light weight lib files for things like guild objects and monster inherits.
The idea behind it is simple: most of these big objects contain a ton of code specific to external concerns. Stuff like code inside of guild objects modify_damage() where you’ll find all sorts of code checking to see if the player is using guildskill x,y,z so that it can reduce/modify/mangle/farble the arguments. This code is more related to the guildskills that it is based on, wouldn’t you think?
The idea to fix this is to use event driven programming. Instead of having all of that code inside of the soul’s modify damage, you instead make it fire an event that indicates modify_damage stuff should happen. Other objects can listen for that event and be notified when it occurs. They’ll be given all of the arguments that the actual gsoul/function/firing code gets, and can be allowed a chance to modify them.
You can quickly see how we could eliminate code (or rather move out and modularize) from all over a guild soul or lib file. heart_beat() could fire a “heart_beat” event, your guild soul queue could fire a “gskill_ready” event when a skill is dequeued. There are all sorts of examples if you start to think creatively.
Interestingly enough, we can further tweak this idea by including the concept of notification conditions. I.e. we can add some arbitrary rules that say when objects even care about hearing the event that is fired. This can allow us to add event handlers that only operate under certain conditions.
An example of this is provided with the code that shows a modify_damage() event listener setup that fires a specific “boy damage reduction” function when the enemy is a boy and a “girl damage reduction” function when the enemy is a female. It’s a stupid example game-play wise but it shows how you can create abitrary conditions based on code.
The relevant files are:
event_system.c :
This is the event subscription/firing inherit. The code that will be using the event system (i.e. the central lib-file) needs to inherit this.
It has methods for adding listeners, querying the listenrs, firing an event, adding guard functions and removing guard functions.
The entire file is well commented. For actual usage instructions I recommend you give this file a quick read-over a couple of times.
test_soul.c :
This is a sample of an event driven object. It’s meant to be the worlds simplest mock up of a typical guild soul. It has a heart_beat() and a simple modify_damage() function.
The heart_beat() fires a “heart_beat” event and is an example of an event that has no arguments.
The modify_damage() function fires a “modify_damage” event and shows an example of how you can pass your function’s arguments to an event handler, and how you can allow that function to update these variables.
test_soul_ob.c :
This is a simple example of an object that is interested in some of test_soul’s events. It could be a starting point for a guild weapon or a bin command or anything really. It has a tick() function that listens for a heart_beat() and spams some text.
The more interesting handler is the one watching for the “modify_damage” event. There are two such handlers; one that does the boy-enemy-based damage reduction and one that does the girl-enemy-based damage reduction. These are examples of event listeners that modify the arguments to the lib object.
Finally, this file also has an example of a guard listener. It only allows the modify_damage listeners to fire when the enemy parameter’s gender is the same as a configuration variable for the event listener.
Interesting note: You can see how with this event driven system and creating a heart_beat() event you can actually sort of “daemonize” things very quickly. An often repeated LPC design pattern I’ve encountered is to create a central daemon with one heart_beat() / call_out() that iterates a structure of other objects in which it calls a fake heart_beat() in order to remove the need for each clone to have a heart_beat() / call_out().
We’ve created the same thing just by inheriting a file and adding a “heart_beat” event fire. Pretty neat huh?
Transmissions:
