2 $Id: event.dxt,v 1.3 2002/12/15 17:23:30 ksterker Exp $
4 Copyright (C) 2001/2002 Kai Sterker <kaisterker@linuxgames.com>
5 Part of the Adonthell Project http://adonthell.linuxgames.com
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY.
12 See the COPYING file for more details.
15 /*! \page page3 The Event System
17 The %event system is divided into three parts. The \ref event_sec1
18 keeps track of all registered %event scripts.
19 Whenever an %event occurs, the %event handler is notified and executes
20 all scripts registered for that particular %event. The \ref event_sec2
21 keeps track of the %events registered by a certain
22 %object, (e.g. a NPC, a maptile or item) and automatically unregisters
23 these %events when this %object is deleted. Finally, there are the
24 \ref event_sec3 themself, used both as message
25 sent to the %event handler whenever an %event occurs and to register
26 an %event script. Each %event has its own data structure with
27 parameters corresponding to its type. These parameters are
28 passed to the %event script, so all infomation regarding
29 an %event is available from within the script as well. The
30 parameters can further be used to specialize the script so it
31 reacts to a smaller range of %events.
34 \section event_sec1 Event Handler
36 The %event handler is the core component of the %event system.
37 It provides a method to initialize the %event system and allows
38 global access to the specialized handlers for individual events.
39 For that purpose, it stores a list of event_handler_base %objects,
40 the virtual base class for the specialized handlers, and passes
41 any %event it receives to the right handler.
43 The %event_handler_base class provides three pure virtual methods
44 that need to be implemented by each specialized handler:
46 - register_event() to pass a new %event to the handler. %Events
47 need to be registered with the handler before they can take
50 - remove_event() to remove a previously registered %event from
53 - raise_event() to send a message to the handler that will trigger
57 \section event_sec2 Event List
59 The event_list is a convenience class for %objects that register
60 events with the handler. As it is up to each object to save the
61 events it registers, and to load and re-register them, the %event
62 list has been written to take care of that.
64 To make the %event list independent from specific %event types,
65 it only works on pointers to the %event base class. That works fine
66 in all cases, except one. When loading events, the %event list needs
67 to instanciate the proper %event subclass. For that purpose, the %event
68 list stores a list of callbacks that return a newly instanciated %event
69 subclass of a given type. Two macros have been written that take care
74 REGISTER_EVENT (type, subclass)
77 %NEW_EVENT provides the function that will return a newly allocated
78 %event. %REGISTER_EVENT will pass this function to the %event list.
79 For each %event type, these two macros should be added to
80 event_handler::init(), the %event system's init method.
82 The %event list provides the following methods:
84 - event_list::add_event() adds an %event to the list and registers it
85 with the %event handler.
87 - event_list::put_state() saves the list with all events inside.
89 - event_list::get_state() restores the list with all events and registers
90 them with the %event handler.
93 \section event_sec3 Events
95 Events have two main purposes. Registered with the %event handler,
96 they allow to execute either a %python script, a %python or a C/C++
97 callback in case that %event takes place. But they are also sent
98 as messages to the handler, to trigger matching events.
100 Each specific %event may have its own %data fields and methods,
101 depending on its purpose. However, all events share a number of
102 common features, which are implemented by the %event base class.
104 The first feature is the %event's action, i.e. what happens if that
105 %event is triggered. The %event class allows to attach a \link py_object
106 python script \endlink, a \link py_callback python callback \endlink
109 C/C++ callbacks are only useful when the %game engine wants to make
110 use of the %event system internally. %Python callbacks allow scripts
111 like \link schedule character schedules \endlink to use the %event
112 system. %Event scripts usually define the action of a certain class of
113 events. For example an %event script might implement a trap that is
114 activated whenever a %character steps on it. This 'trap' script can then
115 be used by traps all over the place.
117 Apart from the %event's action, the base %event class also provides
118 means to repeat events or prevent them from repeating. For example,
119 a trap might only work once. event::set_repeat() allows to specify
120 how often an %event can be executed. Once that repeat count reaches
121 zero, executing the event will automatically delete it. This will
122 also remove it from the %event_handler and %event_list. That way,
123 events that are used up vanish from the game, just as one would expect.
125 Further, the %event class has two pure virtual methods that need
126 to be implemented by the specific events. They are provided so
127 that (not so) specialized %event handlers may take care of different
130 - equals() is used to compare two events for 'equality'. The message
131 sent to the handler is compared to all registered events to see if
134 - execute() is used once the %event is triggered and should executed
138 \section event_sec4 Using the Event System
140 The %event handler is implemented in the event_handler class.
141 It totally consists of static members and methods, to make it
142 easily accessible from any part of the code. Just include
143 the event_handler.h file. To register a script with the handler
144 that is executed whenever the player arrives at the coordinates
145 (20, 20) of a map, you'd write:
148 // Create the filter and set it's parameters
149 event *filter = new enter_event;
153 filter->c = data::the_player;
155 // Set the script to be executed when the event occurs
156 filter->set_script ("a_script");
158 // Finally add the filter to the event list. This will register it with the event handler
162 For a list of available events with their corresponding parameters
163 see the \link event API documentation \endlink.
165 The %event script in that example could look as follows:
170 def __init__ (self, event, <additional arguments>):
171 # -- the event the script belongs to
175 # -- method called when the event occurs, the parameters
176 # depend on the type of the event
177 def run (self, submap, x, y, direction, character):
178 print "%s arrived at %i, %i" % (character, x, y)
181 As you can see, you have the possibility to pass extra parameters
182 to the script constructor. This is limited to strings and integers
183 though. When you set the argument list from C++, you have to manually
184 create a %Python tuple, and you should not forget to decrement its
185 reference count when you are done with it. The following code could
186 be used for the example above:
189 // Create our argument tuple that will be passed to the script constructor
190 PyObject * args = PyTuple_New (2);
191 PyTuple_SetItem (args, 0, PyInt_FromLong (10));
192 PyTuple_SetItem (args, 0, PyString_FromString ("2nd argument"));
194 // Set the script to be executed when the event occurs
195 filter->set_script ("a_script", args);
197 // We don't need our reference to the tuple anymore
201 The script constructor would then receive two additional arguments.
202 This is useful to create generic scripts that can be customized at
203 runtime. To return to our old trap example, the amount of damage the
204 trap does could be specified for each trap in this way.
206 Now we have registered an %event with the %event handler. But that alone
207 won't get the %event triggered. So depending on its type, you'll have to
208 notify the %event handler of an %event's occurance. In case of the \link
209 enter_event enter event \endlink , you'll want to send a message to the
210 %event handler whenever a %character reaches a new position on the map.
213 // Event structures are also used to pass messages to the event_handler
216 // Fill in the parameters
217 message.x = mapcharacter::posx ();
218 message.y = mapcharacter::posy ();
219 message.submap = mapcharacter::submap ();
222 // Notify the event handler
223 event_handler::raise_event (&message);
226 The %event handler will then compare all %events of the given type with the
227 message it received and execute the %event action of events that match.
230 \section event_sec5 The Different Event Types
232 Various types of events are defined by the %game engine, all
233 inheriting from the event class defined in event.h.
235 \subsection mapevents Map Events
237 There are 3 types of map events:
238 \li enter_event, which are triggered whenever a %character enters a
240 \li leave_event, which are triggered whenever a %character leaves a
242 \li action_event, which are triggered when the main %character "acts"
245 All these map events inherits from the map_event class, which
246 contains all the parameters they need:
247 \li x, the X coordinate of the square the %event happened on,
248 \li y, the Y coordinate of the square the %event happened on,
249 \li submap, the number of the submap where the %event happened on,
250 \li c, a pointer to the %mapcharacter that triggered the %event,
251 \li dir, the direction the %mapcharacter is facing when the %event
254 When a map %event is triggered, the run ()method of the Python script
255 is called, with the arguments \e submap, \e x, \e y and \e name, which
256 is the name of the mapcharacter that triggered the %event.
258 Map events are repeated forever by default.
260 \subsection timeevent Time Event
262 The time_event can be used to track relative or absolute %game time.
263 Relative means, the %event will be triggered after a given amount of time
264 has passed, starting at the moment it is created. Absolute means a fixed
265 point in time, i.e. a certain hour at a certain day.
267 Time events are not repeated by default. They can be told to repeat though,
268 and it is also possible to specify the delay between two occurances.
270 Time events pass no arguments to the run() method of the Python script.
271 The script can easily get the current %game time from the gamedate class.
274 \section event_sec6 Saving and Restoring Events
276 As described in the \ref event_sec2 section, events can be saved to disk
277 and restored at a later point. For this to work, a few restrictions have
278 to be made, especially regarding any %python arguments that get passed to
279 script or callback. Events that contain a C/C++ callback cannot be saved
280 at all, as it is not possible to restore that callback.
282 For events with an attached %python script, the only restriction is that
283 the argument needs to be a tuple, containing only string and/or integer
284 %objects. On saving, the name of the script and this argument tuple are
285 saved to disk. On loading, the arguments are loaded, and the script is
286 instanciated with those arguments.
288 The same restriction concerning arguments applies to events with an
289 attached %python callback. However, when saving the callback, only the
290 name of the function or method is saved, but not the instance it belongs
291 to. To restore the callback, it is neccessary to restore that instance
292 first. Then a pointer to it needs to be assigned to py_callback::instance,
293 which is a static member of the %py_callback class. Only then can the
294 callback be restored properly.