File: event.dxt

package info (click to toggle)
adonthell 0.3.8-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 5,416 kB
  • sloc: cpp: 50,659; sh: 5,142; python: 3,307; makefile: 338; lex: 216; sed: 16
file content (296 lines) | stat: -rw-r--r-- 11,988 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
/*
   $Id$

   Copyright (C) 2001/2002 Kai Sterker <kaisterker@linuxgames.com>
   Part of the Adonthell Project http://adonthell.linuxgames.com

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/

/*! \page page3 The Event System
 
 The %event system is divided into three parts. The \ref event_sec1 
 keeps track of all registered %event scripts. 
 Whenever an %event occurs, the %event handler is notified and executes
 all scripts registered for that particular %event. The \ref event_sec2
 keeps track of the %events registered by a certain
 %object, (e.g. a NPC, a maptile or item) and automatically unregisters
 these %events when this %object is deleted. Finally, there are the 
 \ref event_sec3 themself, used both as  message 
 sent to the %event handler whenever an %event occurs and to register 
 an %event script. Each %event has its own data structure with
 parameters corresponding to its type. These parameters are
 passed to the %event script, so all infomation regarding
 an %event is available from within the script as well. The
 parameters can further be used to specialize the script so it
 reacts to a smaller range of %events.


 \section event_sec1 Event Handler

 The %event handler is the core component of the %event system.
 It provides a method to initialize the %event system and allows
 global access to the specialized handlers for individual events.
 For that purpose, it stores a list of event_handler_base %objects,
 the virtual base class for the specialized handlers, and passes
 any %event it receives to the right handler.
 
 The %event_handler_base class provides three pure virtual methods
 that need to be implemented by each specialized handler:
 
 - register_event() to pass a new %event to the handler. %Events
   need to be registered with the handler before they can take
   place
   
 - remove_event() to remove a previously registered %event from
   the handler
    
 - raise_event() to send a message to the handler that will trigger
   matching events. 
 
 
 \section event_sec2 Event List

 The event_list is a convenience class for %objects that register
 events with the handler. As it is up to each object to save the
 events it registers, and to load and re-register them, the %event
 list has been written to take care of that.
 
 To make the %event list independent from specific %event types,
 it only works on pointers to the %event base class. That works fine
 in all cases, except one. When loading events, the %event list needs
 to instanciate the proper %event subclass. For that purpose, the %event
 list stores a list of callbacks that return a newly instanciated %event
 subclass of a given type. Two macros have been written that take care
 of most of the work.

\code
NEW_EVENT (subclass)
REGISTER_EVENT (type, subclass)
\endcode

 %NEW_EVENT provides the function that will return a newly allocated 
 %event. %REGISTER_EVENT will pass this function to the %event list.
 For each %event type, these two macros should be added to 
 event_handler::init(), the %event system's init method. 

 The %event list provides the following methods:
 
 - event_list::add_event() adds an %event to the list and registers it 
   with the %event handler.
 
 - event_list::put_state() saves the list with all events inside.
 
 - event_list::get_state() restores the list with all events and registers 
   them with the %event handler.
 
 
 \section event_sec3 Events
 
 Events have two main purposes. Registered with the %event handler,
 they allow to execute either a %python script, a %python or a C/C++
 callback in case that %event takes place. But they are also sent
 as messages to the handler, to trigger matching events.
 
 Each specific %event may have its own %data fields and methods,
 depending on its purpose. However, all events share a number of
 common features, which are implemented by the %event base class.
 
 The first feature is the %event's action, i.e. what happens if that
 %event is triggered. The %event class allows to attach a \link py_object
 python script \endlink, a \link py_callback python callback \endlink 
 or a C/C++ callback.
 
 C/C++ callbacks are only useful when the %game engine wants to make
 use of the %event system internally. %Python callbacks allow scripts
 like \link schedule character schedules \endlink to use the %event 
 system. %Event scripts usually define the action of a certain class of 
 events. For example an %event script might implement a trap that is 
 activated whenever a %character steps on it. This 'trap' script can then 
 be used by traps all over the place.
  
 Apart from the %event's action, the base %event class also provides
 means to repeat events or prevent them from repeating. For example,
 a trap might only work once. event::set_repeat() allows to specify
 how often an %event can be executed. Once that repeat count reaches
 zero, executing the event will automatically delete it. This will
 also remove it from the %event_handler and %event_list. That way,
 events that are used up vanish from the game, just as one would expect.
 
 Further, the %event class has two pure virtual methods that need
 to be implemented by the specific events. They are provided so
 that (not so) specialized %event handlers may take care of different
 %event types.
 
 - equals() is used to compare two events for 'equality'. The message
   sent to the handler is compared to all registered events to see if
   they match.
   
 - execute() is used once the %event is triggered and should executed
   the %event's action.
 
 
 \section event_sec4 Using the Event System
 
 The %event handler is implemented in the event_handler class.
 It totally consists of static members and methods, to make it
 easily accessible from any part of the code. Just include
 the event_handler.h file. To register a script with the handler 
 that is executed whenever the player arrives at the coordinates 
 (20, 20) of a map, you'd write:

\code
// Create the filter and set it's parameters
event *filter = new enter_event;
 
filter->x = 20;
filter->y = 20;
filter->c = data::the_player;

// Set the script to be executed when the event occurs
filter->set_script ("a_script");

// Finally add the filter to the event list. This will register it with the event handler
add_event (filter);
\endcode
 
 For a list of available events with their corresponding parameters
 see the \link event API documentation \endlink.

 The %event script in that example could look as follows:
 
\verbatim
class a_script:
    # -- constructor
    def __init__ (self, event, <additional arguments>):
        # -- the event the script belongs to
        self.myself = event
        ...

    # -- method called when the event occurs, the parameters
    #    depend on the type of the event
    def run (self, submap, x, y, direction, character):
        print "%s arrived at %i, %i" % (character, x, y)
\endverbatim

 As you can see, you have the possibility to pass extra parameters
 to the script constructor. This is limited to strings and integers
 though. When you set the argument list from C++, you have to manually 
 create a %Python tuple, and you should not forget to decrement its 
 reference count when you are done with it. The following code could
 be used for the example above:

\code
// Create our argument tuple that will be passed to the script constructor
PyObject * args = PyTuple_New (2);
PyTuple_SetItem (args, 0, PyInt_FromLong (10));
PyTuple_SetItem (args, 0, PyString_FromString ("2nd argument"));

// Set the script to be executed when the event occurs
filter->set_script ("a_script", args);

// We don't need our reference to the tuple anymore
Py_DECREF (args);
\endcode
 
 The script constructor would then receive two additional arguments. 
 This is useful to create generic scripts that can be customized at
 runtime. To return to our old trap example, the amount of damage the
 trap does could be specified for each trap in this way.
 
 Now we have registered an %event with the %event handler. But that alone
 won't get the %event triggered. So depending on its type, you'll have to
 notify the %event handler of an %event's occurance. In case of the \link
 enter_event enter event \endlink , you'll want to send a message to the
 %event handler whenever a %character reaches a new position on the map.
         
 \code
// Event structures are also used to pass messages to the event_handler
enter_event message;

// Fill in the parameters
message.x = mapcharacter::posx ();
message.y = mapcharacter::posy ();
message.submap = mapcharacter::submap ();
message.c = this;

// Notify the event handler
event_handler::raise_event (&message);
\endcode

The %event handler will then compare all %events of the given type with the
message it received and execute the %event action of events that match.         


\section event_sec5 The Different Event Types

Various types of events are defined by the %game engine, all
inheriting from the event class defined in event.h.

\subsection mapevents Map Events

There are 3 types of map events:
\li enter_event, which are triggered whenever a %character enters a
square,
\li leave_event, which are triggered whenever a %character leaves a
square,
\li action_event, which are triggered when the main %character "acts"
on a given square.

All these map events inherits from the map_event class, which
contains all the parameters they need:
\li x, the X coordinate of the square the %event happened on,
\li y, the Y coordinate of the square the %event happened on,
\li submap, the number of the submap where the %event happened on,
\li c, a pointer to the %mapcharacter that triggered the %event,
\li dir, the direction the %mapcharacter is facing when the %event
    is triggered.

When a map %event is triggered, the run ()method of the Python script
is called, with the arguments \e submap, \e x, \e y and \e name, which
is the name of the mapcharacter that triggered the %event.

Map events are repeated forever by default.

\subsection timeevent Time Event

The time_event can be used to track relative or absolute %game time.
Relative means, the %event will be triggered after a given amount of time
has passed, starting at the moment it is created. Absolute means a fixed
point in time, i.e. a certain hour at a certain day.

Time events are not repeated by default. They can be told to repeat though,
and it is also possible to specify the delay between two occurances.

Time events pass no arguments to the run() method of the Python script.
The script can easily get the current %game time from the gamedate class. 


\section event_sec6 Saving and Restoring Events

As described in the \ref event_sec2 section, events can be saved to disk
and restored at a later point. For this to work, a few restrictions have
to be made, especially regarding any %python arguments that get passed to
script or callback. Events that contain a C/C++ callback cannot be saved
at all, as it is not possible to restore that callback.

For events with an attached %python script, the only restriction is that
the argument needs to be a tuple, containing only string and/or integer 
%objects. On saving, the name of the script and this argument tuple are 
saved to disk. On loading, the arguments are loaded, and the script is
instanciated with those arguments.

The same restriction concerning arguments applies to events with an
attached %python callback. However, when saving the callback, only the 
name of the function or method is saved, but not the instance it belongs
to. To restore the callback, it is neccessary to restore that instance 
first. Then a pointer to it needs to be assigned to py_callback::instance,
which is a static member of the %py_callback class. Only then can the
callback be restored properly.

*/