Adonthell
0.4
|
00001 /* 00002 $Id: event.dxt,v 1.3 2002/12/15 17:23:30 ksterker Exp $ 00003 00004 Copyright (C) 2001/2002 Kai Sterker <kaisterker@linuxgames.com> 00005 Part of the Adonthell Project http://adonthell.linuxgames.com 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License. 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY. 00011 00012 See the COPYING file for more details. 00013 */ 00014 00015 /*! \page page3 The Event System 00016 00017 The %event system is divided into three parts. The \ref event_sec1 00018 keeps track of all registered %event scripts. 00019 Whenever an %event occurs, the %event handler is notified and executes 00020 all scripts registered for that particular %event. The \ref event_sec2 00021 keeps track of the %events registered by a certain 00022 %object, (e.g. a NPC, a maptile or item) and automatically unregisters 00023 these %events when this %object is deleted. Finally, there are the 00024 \ref event_sec3 themself, used both as message 00025 sent to the %event handler whenever an %event occurs and to register 00026 an %event script. Each %event has its own data structure with 00027 parameters corresponding to its type. These parameters are 00028 passed to the %event script, so all infomation regarding 00029 an %event is available from within the script as well. The 00030 parameters can further be used to specialize the script so it 00031 reacts to a smaller range of %events. 00032 00033 00034 \section event_sec1 Event Handler 00035 00036 The %event handler is the core component of the %event system. 00037 It provides a method to initialize the %event system and allows 00038 global access to the specialized handlers for individual events. 00039 For that purpose, it stores a list of event_handler_base %objects, 00040 the virtual base class for the specialized handlers, and passes 00041 any %event it receives to the right handler. 00042 00043 The %event_handler_base class provides three pure virtual methods 00044 that need to be implemented by each specialized handler: 00045 00046 - register_event() to pass a new %event to the handler. %Events 00047 need to be registered with the handler before they can take 00048 place 00049 00050 - remove_event() to remove a previously registered %event from 00051 the handler 00052 00053 - raise_event() to send a message to the handler that will trigger 00054 matching events. 00055 00056 00057 \section event_sec2 Event List 00058 00059 The event_list is a convenience class for %objects that register 00060 events with the handler. As it is up to each object to save the 00061 events it registers, and to load and re-register them, the %event 00062 list has been written to take care of that. 00063 00064 To make the %event list independent from specific %event types, 00065 it only works on pointers to the %event base class. That works fine 00066 in all cases, except one. When loading events, the %event list needs 00067 to instanciate the proper %event subclass. For that purpose, the %event 00068 list stores a list of callbacks that return a newly instanciated %event 00069 subclass of a given type. Two macros have been written that take care 00070 of most of the work. 00071 00072 \code 00073 NEW_EVENT (subclass) 00074 REGISTER_EVENT (type, subclass) 00075 \endcode 00076 00077 %NEW_EVENT provides the function that will return a newly allocated 00078 %event. %REGISTER_EVENT will pass this function to the %event list. 00079 For each %event type, these two macros should be added to 00080 event_handler::init(), the %event system's init method. 00081 00082 The %event list provides the following methods: 00083 00084 - event_list::add_event() adds an %event to the list and registers it 00085 with the %event handler. 00086 00087 - event_list::put_state() saves the list with all events inside. 00088 00089 - event_list::get_state() restores the list with all events and registers 00090 them with the %event handler. 00091 00092 00093 \section event_sec3 Events 00094 00095 Events have two main purposes. Registered with the %event handler, 00096 they allow to execute either a %python script, a %python or a C/C++ 00097 callback in case that %event takes place. But they are also sent 00098 as messages to the handler, to trigger matching events. 00099 00100 Each specific %event may have its own %data fields and methods, 00101 depending on its purpose. However, all events share a number of 00102 common features, which are implemented by the %event base class. 00103 00104 The first feature is the %event's action, i.e. what happens if that 00105 %event is triggered. The %event class allows to attach a \link py_object 00106 python script \endlink, a \link py_callback python callback \endlink 00107 or a C/C++ callback. 00108 00109 C/C++ callbacks are only useful when the %game engine wants to make 00110 use of the %event system internally. %Python callbacks allow scripts 00111 like \link schedule character schedules \endlink to use the %event 00112 system. %Event scripts usually define the action of a certain class of 00113 events. For example an %event script might implement a trap that is 00114 activated whenever a %character steps on it. This 'trap' script can then 00115 be used by traps all over the place. 00116 00117 Apart from the %event's action, the base %event class also provides 00118 means to repeat events or prevent them from repeating. For example, 00119 a trap might only work once. event::set_repeat() allows to specify 00120 how often an %event can be executed. Once that repeat count reaches 00121 zero, executing the event will automatically delete it. This will 00122 also remove it from the %event_handler and %event_list. That way, 00123 events that are used up vanish from the game, just as one would expect. 00124 00125 Further, the %event class has two pure virtual methods that need 00126 to be implemented by the specific events. They are provided so 00127 that (not so) specialized %event handlers may take care of different 00128 %event types. 00129 00130 - equals() is used to compare two events for 'equality'. The message 00131 sent to the handler is compared to all registered events to see if 00132 they match. 00133 00134 - execute() is used once the %event is triggered and should executed 00135 the %event's action. 00136 00137 00138 \section event_sec4 Using the Event System 00139 00140 The %event handler is implemented in the event_handler class. 00141 It totally consists of static members and methods, to make it 00142 easily accessible from any part of the code. Just include 00143 the event_handler.h file. To register a script with the handler 00144 that is executed whenever the player arrives at the coordinates 00145 (20, 20) of a map, you'd write: 00146 00147 \code 00148 // Create the filter and set it's parameters 00149 event *filter = new enter_event; 00150 00151 filter->x = 20; 00152 filter->y = 20; 00153 filter->c = data::the_player; 00154 00155 // Set the script to be executed when the event occurs 00156 filter->set_script ("a_script"); 00157 00158 // Finally add the filter to the event list. This will register it with the event handler 00159 add_event (filter); 00160 \endcode 00161 00162 For a list of available events with their corresponding parameters 00163 see the \link event API documentation \endlink. 00164 00165 The %event script in that example could look as follows: 00166 00167 \verbatim 00168 class a_script: 00169 # -- constructor 00170 def __init__ (self, event, <additional arguments>): 00171 # -- the event the script belongs to 00172 self.myself = event 00173 ... 00174 00175 # -- method called when the event occurs, the parameters 00176 # depend on the type of the event 00177 def run (self, submap, x, y, direction, character): 00178 print "%s arrived at %i, %i" % (character, x, y) 00179 \endverbatim 00180 00181 As you can see, you have the possibility to pass extra parameters 00182 to the script constructor. This is limited to strings and integers 00183 though. When you set the argument list from C++, you have to manually 00184 create a %Python tuple, and you should not forget to decrement its 00185 reference count when you are done with it. The following code could 00186 be used for the example above: 00187 00188 \code 00189 // Create our argument tuple that will be passed to the script constructor 00190 PyObject * args = PyTuple_New (2); 00191 PyTuple_SetItem (args, 0, PyInt_FromLong (10)); 00192 PyTuple_SetItem (args, 0, PyString_FromString ("2nd argument")); 00193 00194 // Set the script to be executed when the event occurs 00195 filter->set_script ("a_script", args); 00196 00197 // We don't need our reference to the tuple anymore 00198 Py_DECREF (args); 00199 \endcode 00200 00201 The script constructor would then receive two additional arguments. 00202 This is useful to create generic scripts that can be customized at 00203 runtime. To return to our old trap example, the amount of damage the 00204 trap does could be specified for each trap in this way. 00205 00206 Now we have registered an %event with the %event handler. But that alone 00207 won't get the %event triggered. So depending on its type, you'll have to 00208 notify the %event handler of an %event's occurance. In case of the \link 00209 enter_event enter event \endlink , you'll want to send a message to the 00210 %event handler whenever a %character reaches a new position on the map. 00211 00212 \code 00213 // Event structures are also used to pass messages to the event_handler 00214 enter_event message; 00215 00216 // Fill in the parameters 00217 message.x = mapcharacter::posx (); 00218 message.y = mapcharacter::posy (); 00219 message.submap = mapcharacter::submap (); 00220 message.c = this; 00221 00222 // Notify the event handler 00223 event_handler::raise_event (&message); 00224 \endcode 00225 00226 The %event handler will then compare all %events of the given type with the 00227 message it received and execute the %event action of events that match. 00228 00229 00230 \section event_sec5 The Different Event Types 00231 00232 Various types of events are defined by the %game engine, all 00233 inheriting from the event class defined in event.h. 00234 00235 \subsection mapevents Map Events 00236 00237 There are 3 types of map events: 00238 \li enter_event, which are triggered whenever a %character enters a 00239 square, 00240 \li leave_event, which are triggered whenever a %character leaves a 00241 square, 00242 \li action_event, which are triggered when the main %character "acts" 00243 on a given square. 00244 00245 All these map events inherits from the map_event class, which 00246 contains all the parameters they need: 00247 \li x, the X coordinate of the square the %event happened on, 00248 \li y, the Y coordinate of the square the %event happened on, 00249 \li submap, the number of the submap where the %event happened on, 00250 \li c, a pointer to the %mapcharacter that triggered the %event, 00251 \li dir, the direction the %mapcharacter is facing when the %event 00252 is triggered. 00253 00254 When a map %event is triggered, the run ()method of the Python script 00255 is called, with the arguments \e submap, \e x, \e y and \e name, which 00256 is the name of the mapcharacter that triggered the %event. 00257 00258 Map events are repeated forever by default. 00259 00260 \subsection timeevent Time Event 00261 00262 The time_event can be used to track relative or absolute %game time. 00263 Relative means, the %event will be triggered after a given amount of time 00264 has passed, starting at the moment it is created. Absolute means a fixed 00265 point in time, i.e. a certain hour at a certain day. 00266 00267 Time events are not repeated by default. They can be told to repeat though, 00268 and it is also possible to specify the delay between two occurances. 00269 00270 Time events pass no arguments to the run() method of the Python script. 00271 The script can easily get the current %game time from the gamedate class. 00272 00273 00274 \section event_sec6 Saving and Restoring Events 00275 00276 As described in the \ref event_sec2 section, events can be saved to disk 00277 and restored at a later point. For this to work, a few restrictions have 00278 to be made, especially regarding any %python arguments that get passed to 00279 script or callback. Events that contain a C/C++ callback cannot be saved 00280 at all, as it is not possible to restore that callback. 00281 00282 For events with an attached %python script, the only restriction is that 00283 the argument needs to be a tuple, containing only string and/or integer 00284 %objects. On saving, the name of the script and this argument tuple are 00285 saved to disk. On loading, the arguments are loaded, and the script is 00286 instanciated with those arguments. 00287 00288 The same restriction concerning arguments applies to events with an 00289 attached %python callback. However, when saving the callback, only the 00290 name of the function or method is saved, but not the instance it belongs 00291 to. To restore the callback, it is neccessary to restore that instance 00292 first. Then a pointer to it needs to be assigned to py_callback::instance, 00293 which is a static member of the %py_callback class. Only then can the 00294 callback be restored properly. 00295 00296 */