Crossfire Server, Trunk  1.75.0
events.cpp
Go to the documentation of this file.
1 #include "global.h"
2 #include "events.h"
3 #include <map>
4 
5 #include "stats.h"
6 
8 int events_total = 0;
9 
15 static std::map<event_registration, f_plug_event> global_handlers[NR_EVENTS];
17 static std::map<std::string, f_plug_event> object_handlers;
18 
22  global_handlers[eventcode][eg] = hook;
23  return eg;
24 }
25 
27  global_handlers[eventcode].erase(id);
28 }
29 
30 void events_execute_global_event(int eventcode, ...) {
31  va_list args;
32  mapstruct *map;
33  object *op;
34  object *op2;
35  player *pl;
36  const char *buf;
37  int i, rt;
38 
39  va_start(args, eventcode);
40 
41  switch (eventcode) {
42  case EVENT_BORN:
43  /*BORN: op*/
44  op = va_arg(args, object *);
45  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
46  (*(*gh).second)(&rt, eventcode, op);
47  }
48  break;
49 
50  case EVENT_CLOCK:
51  /*CLOCK: -*/
52  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
53  (*(*gh).second)(&rt, eventcode);
54  }
55  break;
56 
57  case EVENT_CRASH:
58  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
59  (*(*gh).second)(&rt, eventcode);
60  }
61  break;
62 
63  case EVENT_PLAYER_DEATH:
64  /*PLAYER_DEATH: op*/
65  op = va_arg(args, object *);
66  op2 = va_arg(args, object *);
67  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
68  (*(*gh).second)(&rt, eventcode, op, op2);
69  }
70  break;
71 
72  case EVENT_GKILL:
73  /*GKILL: op, hitter*/
74  op = va_arg(args, object *);
75  op2 = va_arg(args, object *);
76  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
77  (*(*gh).second)(&rt, eventcode, op, op2);
78  }
79  break;
80 
81  case EVENT_LOGIN:
82  /*LOGIN: pl, pl->socket.host*/
83  pl = va_arg(args, player *);
84  buf = va_arg(args, char *);
85  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
86  (*(*gh).second)(&rt, eventcode, pl, buf);
87  }
88  break;
89 
90  case EVENT_LOGOUT:
91  /*LOGOUT: pl, pl->socket.host*/
92  pl = va_arg(args, player *);
93  buf = va_arg(args, char *);
94  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
95  (*(*gh).second)(&rt, eventcode, pl, buf);
96  }
97  break;
98 
99  case EVENT_MAPENTER:
100  /*MAPENTER: op, map*/
101  op = va_arg(args, object *);
102  map = va_arg(args, mapstruct *);
103  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
104  (*(*gh).second)(&rt, eventcode, op, map);
105  }
106  break;
107 
108  case EVENT_MAPLEAVE:
109  /*MAPLEAVE: op, map*/
110  op = va_arg(args, object *);
111  map = va_arg(args, mapstruct *);
112  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
113  (*(*gh).second)(&rt, eventcode, op, map);
114  }
115  break;
116 
117  case EVENT_MAPRESET:
118  /*MAPRESET: map*/
119  map = va_arg(args, mapstruct *);
120  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
121  (*(*gh).second)(&rt, eventcode, map);
122  }
123  break;
124 
125  case EVENT_REMOVE:
126  /*REMOVE: op*/
127  op = va_arg(args, object *);
128  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
129  (*(*gh).second)(&rt, eventcode, op);
130  }
131  break;
132 
133  case EVENT_SHOUT:
134  /*SHOUT: op, parms, priority*/
135  op = va_arg(args, object *);
136  buf = va_arg(args, char *);
137  i = va_arg(args, int);
138  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
139  (*(*gh).second)(&rt, eventcode, op, buf, i);
140  }
141  break;
142 
143  case EVENT_TELL:
144  /* Tell: who, what, to who */
145  op = va_arg(args, object *);
146  buf = va_arg(args, const char *);
147  op2 = va_arg(args, object *);
148  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
149  (*(*gh).second)(&rt, eventcode, op, buf, op2);
150  }
151  break;
152 
153  case EVENT_MUZZLE:
154  /*MUZZLE: op, parms*/
155  op = va_arg(args, object *);
156  buf = va_arg(args, char *);
157  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
158  (*(*gh).second)(&rt, eventcode, op, buf);
159  }
160  break;
161 
162  case EVENT_KICK:
163  /*KICK: op, parms*/
164  op = va_arg(args, object *);
165  buf = va_arg(args, char *);
166  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
167  (*(*gh).second)(&rt, eventcode, op, buf);
168  }
169  break;
170 
171  case EVENT_MAPUNLOAD:
172  /*MAPUNLOAD: map*/
173  map = va_arg(args, mapstruct *);
174  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
175  (*(*gh).second)(&rt, eventcode, map);
176  }
177  break;
178 
179  case EVENT_MAPLOAD:
180  /*MAPLOAD: map*/
181  map = va_arg(args, mapstruct *);
182  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
183  (*(*gh).second)(&rt, eventcode, map);
184  }
185  break;
186 
187  case EVENT_MAPREADY:
188  /*MAPREADY: map*/
189  map = va_arg(args, mapstruct *);
190  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
191  (*(*gh).second)(&rt, eventcode, map);
192  }
193  break;
194 
195  case EVENT_GBOUGHT:
196  // fall through: these have the same arguments
197  case EVENT_GSOLD:
198  /*GBOUGHT/GSOLD: item activator*/
199  op = va_arg(args, object *);
200  op2 = va_arg(args, object *);
201  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
202  (*(*gh).second)(&rt, eventcode, op, op2);
203  }
204  break;
205  }
206  va_end(args);
208 }
209 
210 static void ensure_bitmask(object *op) {
211  if ((op->event_bitmask & BITMASK_VALID) == BITMASK_VALID) {
212  return;
213  }
214 
215  object *inv = op->inv;
216  while (inv) {
217  if (inv->type == EVENT_CONNECTOR) {
218  op->event_bitmask |= BITMASK_EVENT(inv->subtype);
219  }
220  inv = inv->below;
221  }
223 }
224 
225 static int do_execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix, talk_info *talk) {
226  int rv = 0;
227  bool debug_events = (getenv("CF_DEBUG_EVENTS") != NULL);
228 
229  ensure_bitmask(op);
230  if ((op->event_bitmask & BITMASK_EVENT(eventcode)) == 0) {
231  return 0;
232  }
233 
234  FOR_INV_PREPARE(op, tmp) {
235  if (tmp->type == EVENT_CONNECTOR && tmp->subtype == eventcode) {
236  if (debug_events) {
237  LOG(llevDebug, "********** EVENT HANDLER **********\n");
238  LOG(llevDebug, " - Who am I :%s\n", op->name);
239  if (activator != NULL)
240  LOG(llevDebug, " - Activator :%s\n", activator->name);
241  if (third != NULL)
242  LOG(llevDebug, " - Other object :%s\n", third->name);
243  LOG(llevDebug, " - Event code :%d\n", tmp->subtype);
244  if (tmp->title != NULL)
245  LOG(llevDebug, " - Event plugin :%s\n", tmp->title);
246  if (tmp->slaying != NULL)
247  LOG(llevDebug, " - Event hook :%s\n", tmp->slaying);
248  if (tmp->name != NULL)
249  LOG(llevDebug, " - Event options :%s\n", tmp->name);
250  }
251 
252  if (tmp->title == NULL) {
253  object *env = object_get_env_recursive(tmp);
254  LOG(llevError, "Event object without title at %d/%d in map %s\n", env->x, env->y, env->map ? env->map->name : "(null map)");
255  object_remove(tmp);
257  } else if (tmp->slaying == NULL) {
258  object *env = object_get_env_recursive(tmp);
259  LOG(llevError, "Event object without slaying at %d/%d in map %s\n", env->x, env->y, env->map ? env->map->name : "(null map)");
260  object_remove(tmp);
262  } else {
263  auto handler = object_handlers.find(tmp->title);
264  if (handler == object_handlers.end()) {
265  object *env = object_get_env_recursive(tmp);
266  LOG(llevError, "The requested handler doesn't exist: %s at %d/%d in map %s\n", tmp->title, env->x, env->y, env->map ? env->map->name : "(null map)");
267  object_remove(tmp);
269  } else {
270  int rvt = 0;
271  int rv;
272 
273  tag_t oldtag = op->count;
274  rv = (*(*handler).second)(&rvt, op, activator, third, message, fix, tmp, talk);
275  if (object_was_destroyed(op, oldtag)) {
276  return rv;
277  }
278  if (QUERY_FLAG(tmp, FLAG_UNIQUE)) {
279  if (debug_events) {
280  LOG(llevDebug, "Removing unique event %s\n", tmp->slaying);
281  }
282  object_remove(tmp);
284  }
285  if (rv) {
286  // If non-zero return value, script wants us to stop
287  // applying other methods and return.
288  return rv;
289  }
290  }
291  }
292  }
293  } FOR_INV_FINISH();
294  events_total++;
295  return rv;
296 }
297 
298 void events_register_object_handler(const char *id, f_plug_event handler) {
299  object_handlers[id] = handler;
300  LOG(llevDebug, "events: registered object handler %s\n", id);
301 }
302 
303 void events_unregister_object_handler(const char *id) {
304  object_handlers.erase(id);
305  LOG(llevDebug, "events: unregistered object handler %s\n", id);
306 }
307 
308 int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix) {
309  return do_execute_event(op, eventcode, activator, third, message, fix, NULL);
310 }
311 
312 int events_execute_object_say(object *npc, talk_info *talk) {
313  return do_execute_event(npc, EVENT_SAY, talk->who, NULL, talk->text, SCRIPT_FIX_ALL, talk);
314 }
315 
316 int events_execute_object_user(object *op, object *activator, object *third, const char *message, int fix) {
317  return events_execute_object_event(op, EVENT_USER, activator, third, message, fix);
318 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
EVENT_GSOLD
#define EVENT_GSOLD
Player sold object in shop, but global.
Definition: events.h:58
global.h
FREE_OBJ_NO_DESTROY_CALLBACK
#define FREE_OBJ_NO_DESTROY_CALLBACK
Do not run the destroy callback.
Definition: object.h:545
object_get_env_recursive
object * object_get_env_recursive(object *op)
Utility function.
Definition: object.cpp:590
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
EVENT_CONNECTOR
@ EVENT_CONNECTOR
Lauwenmark: an invisible object holding a plugin event hook.
Definition: object.h:232
NR_EVENTS
#define NR_EVENTS
Number of events, maximum code + 1.
Definition: events.h:61
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
player
One player.
Definition: player.h:105
object::inv
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
EVENT_GBOUGHT
#define EVENT_GBOUGHT
Player bought object in shop, but global.
Definition: events.h:57
BITMASK_EVENT
#define BITMASK_EVENT(evt)
Convert an event to its bit.
Definition: events.h:64
events_unregister_object_handler
void events_unregister_object_handler(const char *id)
Remove an object event handler.
Definition: events.cpp:303
FLAG_UNIQUE
#define FLAG_UNIQUE
Item is really unique (UNIQUE_ITEMS)
Definition: define.h:287
EVENT_MAPLOAD
#define EVENT_MAPLOAD
A map is loaded (pristine state)
Definition: events.h:48
object::count
tag_t count
Unique object number for this object.
Definition: object.h:307
EVENT_LOGOUT
#define EVENT_LOGOUT
Player logout.
Definition: events.h:45
EVENT_SAY
#define EVENT_SAY
Someone speaks.
Definition: events.h:29
events_execute_object_event
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Execute an event on the specified object.
Definition: events.cpp:308
buf
StringBuffer * buf
Definition: readable.cpp:1565
events_register_global_handler
event_registration events_register_global_handler(int eventcode, f_plug_event hook)
Register a global event handler.
Definition: events.cpp:19
events_register_object_handler
void events_register_object_handler(const char *id, f_plug_event handler)
Register an object event handler.
Definition: events.cpp:298
EVENT_LOGIN
#define EVENT_LOGIN
Player login.
Definition: events.h:44
events_total
int events_total
Definition: events.cpp:8
object::subtype
uint8_t subtype
Subtype of object.
Definition: object.h:349
events.h
EVENT_CLOCK
#define EVENT_CLOCK
Global time event.
Definition: events.h:40
EVENT_CRASH
#define EVENT_CRASH
Triggered when the server crashes.
Definition: events.h:41
stats.h
next_event_registration
static event_registration next_event_registration
Definition: events.cpp:16
events_unregister_global_handler
void events_unregister_global_handler(int eventcode, event_registration id)
Remove a global event handler.
Definition: events.cpp:26
EVENT_MAPENTER
#define EVENT_MAPENTER
A player entered a map.
Definition: events.h:46
object::below
object * below
Pointer to the object stacked below this one.
Definition: object.h:295
object::event_bitmask
uint64_t event_bitmask
Bitmask of events this object has a handler for, see events.h.
Definition: object.h:447
EVENT_MAPRESET
#define EVENT_MAPRESET
A map is resetting.
Definition: events.h:50
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:387
EVENT_BORN
#define EVENT_BORN
A new character has been created.
Definition: events.h:39
events_execute_object_user
int events_execute_object_user(object *op, object *activator, object *third, const char *message, int fix)
Execute an EVENT_USER on the specified object.
Definition: events.cpp:316
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
message
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your message
Definition: survival-guide.txt:34
EVENT_MAPUNLOAD
#define EVENT_MAPUNLOAD
A map is freed (includes swapping out)
Definition: events.h:51
object_free
void object_free(object *ob, int flags)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1592
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:671
ensure_bitmask
static void ensure_bitmask(object *op)
Definition: events.cpp:210
tag_t
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
EVENT_USER
#define EVENT_USER
User-defined event.
Definition: events.h:36
EVENT_SHOUT
#define EVENT_SHOUT
A player 'shout' something.
Definition: events.h:55
global_events_total
int global_events_total
Definition: events.cpp:7
env
static std::shared_ptr< inja::Environment > env
Rendering environment.
Definition: mapper.cpp:2222
eg
static event_registration eg
Definition: random_house_generator.cpp:205
talk_info::text
const char * text
What the player actually said.
Definition: dialog.h:52
EVENT_PLAYER_DEATH
#define EVENT_PLAYER_DEATH
Global Death event
Definition: events.h:53
BITMASK_VALID
#define BITMASK_VALID
Bit indicating if the event bitmask is valid or not.
Definition: events.h:66
EVENT_MUZZLE
#define EVENT_MUZZLE
A player was Muzzled (no_shout set).
Definition: events.h:52
EVENT_TELL
#define EVENT_TELL
A player 'tell' something.
Definition: events.h:56
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
event_registration
unsigned long event_registration
Registration identifier type.
Definition: events.h:71
global_handlers
static std::map< event_registration, f_plug_event > global_handlers[NR_EVENTS]
To turn on verbose messages about events in the debug log, set the CF_DEBUG_EVENTS environment variab...
Definition: events.cpp:15
mapstruct
This is a game-map.
Definition: map.h:315
f_plug_event
int(* f_plug_event)(int *type,...)
Function to call to handle global or object-related events.
Definition: events.h:69
EVENT_MAPLEAVE
#define EVENT_MAPLEAVE
A player left a map.
Definition: events.h:47
talk_info
Structure used to build up dialog information when a player says something.
Definition: dialog.h:50
EVENT_REMOVE
#define EVENT_REMOVE
A Player character has been removed.
Definition: events.h:54
object_remove
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to.
Definition: object.cpp:1833
EVENT_MAPREADY
#define EVENT_MAPREADY
A map is ready, either first load or after reload.
Definition: events.h:49
do_execute_event
static int do_execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix, talk_info *talk)
Definition: events.cpp:225
events_execute_object_say
int events_execute_object_say(object *npc, talk_info *talk)
Execute an EVENT_SAY on the specified object.
Definition: events.cpp:312
EVENT_GKILL
#define EVENT_GKILL
Triggered when anything got killed by anyone.
Definition: events.h:42
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:664
EVENT_KICK
#define EVENT_KICK
A player was Kicked by a DM
Definition: events.h:43
events_execute_global_event
void events_execute_global_event(int eventcode,...)
Execute a global event.
Definition: events.cpp:30
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
talk_info::who
struct object * who
Player saying something.
Definition: dialog.h:51
object_handlers
static std::map< std::string, f_plug_event > object_handlers
Definition: events.cpp:17