Adonthell  0.4
event.dxt
1 /*
2  $Id: event.dxt,v 1.3 2002/12/15 17:23:30 ksterker Exp $
3 
4  Copyright (C) 2001/2002 Kai Sterker <kaisterker@linuxgames.com>
5  Part of the Adonthell Project http://adonthell.linuxgames.com
6 
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.
11 
12  See the COPYING file for more details.
13 */
14 
15 /*! \page page3 The Event System
16 
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.
32 
33 
34  \section event_sec1 Event Handler
35 
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.
42 
43  The %event_handler_base class provides three pure virtual methods
44  that need to be implemented by each specialized handler:
45 
46  - register_event() to pass a new %event to the handler. %Events
47  need to be registered with the handler before they can take
48  place
49 
50  - remove_event() to remove a previously registered %event from
51  the handler
52 
53  - raise_event() to send a message to the handler that will trigger
54  matching events.
55 
56 
57  \section event_sec2 Event List
58 
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.
63 
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
70  of most of the work.
71 
72 \code
73 NEW_EVENT (subclass)
74 REGISTER_EVENT (type, subclass)
75 \endcode
76 
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.
81 
82  The %event list provides the following methods:
83 
84  - event_list::add_event() adds an %event to the list and registers it
85  with the %event handler.
86 
87  - event_list::put_state() saves the list with all events inside.
88 
89  - event_list::get_state() restores the list with all events and registers
90  them with the %event handler.
91 
92 
93  \section event_sec3 Events
94 
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.
99 
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.
103 
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
107  or a C/C++ callback.
108 
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.
116 
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.
124 
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
128  %event types.
129 
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
132  they match.
133 
134  - execute() is used once the %event is triggered and should executed
135  the %event's action.
136 
137 
138  \section event_sec4 Using the Event System
139 
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:
146 
147 \code
148 // Create the filter and set it's parameters
149 event *filter = new enter_event;
150 
151 filter->x = 20;
152 filter->y = 20;
153 filter->c = data::the_player;
154 
155 // Set the script to be executed when the event occurs
156 filter->set_script ("a_script");
157 
158 // Finally add the filter to the event list. This will register it with the event handler
159 add_event (filter);
160 \endcode
161 
162  For a list of available events with their corresponding parameters
163  see the \link event API documentation \endlink.
164 
165  The %event script in that example could look as follows:
166 
167 \verbatim
168 class a_script:
169  # -- constructor
170  def __init__ (self, event, <additional arguments>):
171  # -- the event the script belongs to
172  self.myself = event
173  ...
174 
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)
179 \endverbatim
180 
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:
187 
188 \code
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"));
193 
194 // Set the script to be executed when the event occurs
195 filter->set_script ("a_script", args);
196 
197 // We don't need our reference to the tuple anymore
198 Py_DECREF (args);
199 \endcode
200 
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.
205 
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.
211 
212  \code
213 // Event structures are also used to pass messages to the event_handler
214 enter_event message;
215 
216 // Fill in the parameters
217 message.x = mapcharacter::posx ();
218 message.y = mapcharacter::posy ();
219 message.submap = mapcharacter::submap ();
220 message.c = this;
221 
222 // Notify the event handler
223 event_handler::raise_event (&message);
224 \endcode
225 
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.
228 
229 
230 \section event_sec5 The Different Event Types
231 
232 Various types of events are defined by the %game engine, all
233 inheriting from the event class defined in event.h.
234 
235 \subsection mapevents Map Events
236 
237 There are 3 types of map events:
238 \li enter_event, which are triggered whenever a %character enters a
239 square,
240 \li leave_event, which are triggered whenever a %character leaves a
241 square,
242 \li action_event, which are triggered when the main %character "acts"
243 on a given square.
244 
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
252  is triggered.
253 
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.
257 
258 Map events are repeated forever by default.
259 
260 \subsection timeevent Time Event
261 
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.
266 
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.
269 
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.
272 
273 
274 \section event_sec6 Saving and Restoring Events
275 
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.
281 
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.
287 
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.
295 
296 */