Crossfire Server  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 price*/
199  op = va_arg(args, object *);
200  op2 = va_arg(args, object *);
201  uint64_t price = va_arg(args, uint64_t);
202  for (auto gh = global_handlers[eventcode].begin(); gh != global_handlers[eventcode].end(); gh++) {
203  (*(*gh).second)(&rt, eventcode, op, op2, price);
204  }
205  break;
206  }
207  va_end(args);
209 }
210 
211 static void ensure_bitmask(object *op) {
212  if ((op->event_bitmask & BITMASK_VALID) == BITMASK_VALID) {
213  return;
214  }
215 
216  object *inv = op->inv;
217  while (inv) {
218  if (inv->type == EVENT_CONNECTOR) {
219  op->event_bitmask |= BITMASK_EVENT(inv->subtype);
220  }
221  inv = inv->below;
222  }
224 }
225 
226 static int do_execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix, talk_info *talk) {
227  int rv = 0;
228  bool debug_events = (getenv("CF_DEBUG_EVENTS") != NULL);
229 
230  ensure_bitmask(op);
231  if ((op->event_bitmask & BITMASK_EVENT(eventcode)) == 0) {
232  return 0;
233  }
234 
235  FOR_INV_PREPARE(op, tmp) {
236  if (tmp->type == EVENT_CONNECTOR && tmp->subtype == eventcode) {
237  if (debug_events) {
238  LOG(llevDebug, "********** EVENT HANDLER **********\n");
239  LOG(llevDebug, " - Who am I :%s\n", op->name);
240  if (activator != NULL)
241  LOG(llevDebug, " - Activator :%s\n", activator->name);
242  if (third != NULL)
243  LOG(llevDebug, " - Other object :%s\n", third->name);
244  LOG(llevDebug, " - Event code :%d\n", tmp->subtype);
245  if (tmp->title != NULL)
246  LOG(llevDebug, " - Event plugin :%s\n", tmp->title);
247  if (tmp->slaying != NULL)
248  LOG(llevDebug, " - Event hook :%s\n", tmp->slaying);
249  if (tmp->name != NULL)
250  LOG(llevDebug, " - Event options :%s\n", tmp->name);
251  }
252 
253  if (tmp->title == NULL) {
254  object *env = object_get_env_recursive(tmp);
255  LOG(llevError, "Event object without title at %d/%d in map %s\n", env->x, env->y, env->map ? env->map->name : "(null map)");
256  object_remove(tmp);
258  } else if (tmp->slaying == NULL) {
259  object *env = object_get_env_recursive(tmp);
260  LOG(llevError, "Event object without slaying at %d/%d in map %s\n", env->x, env->y, env->map ? env->map->name : "(null map)");
261  object_remove(tmp);
263  } else {
264  auto handler = object_handlers.find(tmp->title);
265  if (handler == object_handlers.end()) {
266  object *env = object_get_env_recursive(tmp);
267  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)");
268  object_remove(tmp);
270  } else {
271  int rvt = 0;
272  int rv;
273 
274  tag_t oldtag = op->count;
275  rv = (*(*handler).second)(&rvt, op, activator, third, message, fix, tmp, talk);
276  if (object_was_destroyed(op, oldtag)) {
277  return rv;
278  }
279  if (QUERY_FLAG(tmp, FLAG_UNIQUE)) {
280  if (debug_events) {
281  LOG(llevDebug, "Removing unique event %s\n", tmp->slaying);
282  }
283  object_remove(tmp);
285  }
286  if (rv) {
287  // If non-zero return value, script wants us to stop
288  // applying other methods and return.
289  return rv;
290  }
291  }
292  }
293  }
294  } FOR_INV_FINISH();
295  events_total++;
296  return rv;
297 }
298 
299 void events_register_object_handler(const char *id, f_plug_event handler) {
300  object_handlers[id] = handler;
301  LOG(llevDebug, "events: registered object handler %s\n", id);
302 }
303 
304 void events_unregister_object_handler(const char *id) {
305  object_handlers.erase(id);
306  LOG(llevDebug, "events: unregistered object handler %s\n", id);
307 }
308 
309 int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix) {
310  return do_execute_event(op, eventcode, activator, third, message, fix, NULL);
311 }
312 
313 int events_execute_object_say(object *npc, talk_info *talk) {
314  return do_execute_event(npc, EVENT_SAY, talk->who, NULL, talk->text, SCRIPT_FIX_ALL, talk);
315 }
316 
317 int events_execute_object_user(object *op, object *activator, object *third, const char *message, int fix) {
318  return events_execute_object_event(op, EVENT_USER, activator, third, message, fix);
319 }
Error, serious thing.
Definition: logger.h:11
#define EVENT_SAY
Someone speaks.
Definition: events.h:37
void events_register_object_handler(const char *id, f_plug_event handler)
Register an object event handler.
Definition: events.cpp:299
#define EVENT_REMOVE
A Player character has been removed.
Definition: events.h:67
static int do_execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix, talk_info *talk)
Definition: events.cpp:226
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
#define EVENT_LOGOUT
Player logout.
Definition: events.h:58
#define EVENT_MAPUNLOAD
A map is freed (includes swapping out)
Definition: events.h:64
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
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:1818
object * below
Pointer to the object stacked below this one.
Definition: object.h:295
static event_registration eg
#define NR_EVENTS
Number of events, maximum code + 1.
Definition: events.h:74
#define EVENT_LOGIN
Player login.
Definition: events.h:57
int16_t y
Position in the map for this object.
Definition: object.h:335
#define FREE_OBJ_NO_DESTROY_CALLBACK
Do not run the destroy callback.
Definition: object.h:547
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
#define EVENT_KICK
A player was Kicked by a DM.
Definition: events.h:56
int16_t x
Definition: object.h:335
Global type definitions and header inclusions.
void events_execute_global_event(int eventcode,...)
Execute a global event.
Definition: events.cpp:30
static std::shared_ptr< inja::Environment > env
Rendering environment.
Definition: mapper.cpp:2222
int events_total
Definition: events.cpp:8
void object_free(object *ob, int flags)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.cpp:1577
#define BITMASK_VALID
Bit indicating if the event bitmask is valid or not.
Definition: events.h:79
#define EVENT_CRASH
Triggered when the server crashes.
Definition: events.h:54
unsigned long event_registration
Registration identifier type.
Definition: events.h:84
Structure used to build up dialog information when a player says something.
Definition: dialog.h:50
const char * text
What the player actually said.
Definition: dialog.h:52
#define QUERY_FLAG(xyz, p)
Definition: define.h:386
#define EVENT_MAPRESET
A map is resetting.
Definition: events.h:63
#define EVENT_BORN
A new character has been created.
Definition: events.h:52
#define EVENT_GKILL
Triggered when anything got killed by anyone.
Definition: events.h:55
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:700
#define EVENT_CLOCK
Global time event.
Definition: events.h:53
This is a game-map.
Definition: map.h:320
#define EVENT_MAPREADY
A map is ready, either first load or after reload.
Definition: events.h:62
uint64_t event_bitmask
Bitmask of events this object has a handler for, see events.h.
Definition: object.h:447
#define EVENT_TELL
A player &#39;tell&#39; something.
Definition: events.h:69
#define EVENT_MAPLEAVE
A player left a map.
Definition: events.h:60
object * object_get_env_recursive(object *op)
Utility function.
Definition: object.cpp:575
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
#define EVENT_PLAYER_DEATH
Global Death event.
Definition: events.h:66
#define EVENT_USER
User-defined event.
Definition: events.h:44
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
#define EVENT_GSOLD
Player sold object in shop, but global.
Definition: events.h:71
#define EVENT_MAPENTER
A player entered a map.
Definition: events.h:59
int(* f_plug_event)(int *type,...)
Function to call to handle global or object-related events.
Definition: events.h:82
static std::map< std::string, f_plug_event > object_handlers
Definition: events.cpp:17
sstring name
The name of the object, obviously...
Definition: object.h:319
#define SCRIPT_FIX_ALL
Definition: global.h:380
Only for debugging purposes.
Definition: logger.h:13
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
#define BITMASK_EVENT(evt)
Convert an event to its bit.
Definition: events.h:77
static void ensure_bitmask(object *op)
Definition: events.cpp:211
void events_unregister_global_handler(int eventcode, event_registration id)
Remove a global event handler.
Definition: events.cpp:26
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
struct object * who
Player saying something.
Definition: dialog.h:51
Lauwenmark: an invisible object holding a plugin event hook.
Definition: object.h:232
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:309
#define EVENT_MAPLOAD
A map is loaded (pristine state)
Definition: events.h:61
void events_unregister_object_handler(const char *id)
Remove an object event handler.
Definition: events.cpp:304
event_registration events_register_global_handler(int eventcode, f_plug_event hook)
Register a global event handler.
Definition: events.cpp:19
One player.
Definition: player.h:107
#define EVENT_MUZZLE
A player was Muzzled (no_shout set).
Definition: events.h:65
StringBuffer * buf
Definition: readable.cpp:1563
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:317
uint8_t subtype
Subtype of object.
Definition: object.h:349
#define EVENT_SHOUT
A player &#39;shout&#39; something.
Definition: events.h:68
tag_t count
Unique object number for this object.
Definition: object.h:307
#define FLAG_UNIQUE
Item is really unique (UNIQUE_ITEMS)
Definition: define.h:275
static event_registration next_event_registration
Definition: events.cpp:16
int global_events_total
Definition: events.cpp:7
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:693
char * name
Name of map as given by its creator.
Definition: map.h:323
#define EVENT_GBOUGHT
Player bought object in shop, but global.
Definition: events.h:70
int events_execute_object_say(object *npc, talk_info *talk)
Execute an EVENT_SAY on the specified object.
Definition: events.cpp:313