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 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 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
EVENT_REMOVE
#define EVENT_REMOVE
A Player character has been removed.
Definition: events.h:67
EVENT_GBOUGHT
#define EVENT_GBOUGHT
Player bought object in shop, but global.
Definition: events.h:70
global.h
FREE_OBJ_NO_DESTROY_CALLBACK
#define FREE_OBJ_NO_DESTROY_CALLBACK
Do not run the destroy callback.
Definition: object.h:545
EVENT_LOGOUT
#define EVENT_LOGOUT
Player logout.
Definition: events.h:58
object_get_env_recursive
object * object_get_env_recursive(object *op)
Utility function.
Definition: object.cpp:575
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
EVENT_MAPUNLOAD
#define EVENT_MAPUNLOAD
A map is freed (includes swapping out)
Definition: events.h:64
NR_EVENTS
#define NR_EVENTS
Number of events, maximum code + 1.
Definition: events.h:74
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
BITMASK_EVENT
#define BITMASK_EVENT(evt)
Convert an event to its bit.
Definition: events.h:77
events_unregister_object_handler
void events_unregister_object_handler(const char *id)
Remove an object event handler.
Definition: events.cpp:304
FLAG_UNIQUE
#define FLAG_UNIQUE
Item is really unique (UNIQUE_ITEMS)
Definition: define.h:287
object::count
tag_t count
Unique object number for this object.
Definition: object.h:307
EVENT_LOGIN
#define EVENT_LOGIN
Player login.
Definition: events.h:57
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:309
buf
StringBuffer * buf
Definition: readable.cpp:1565
EVENT_KICK
#define EVENT_KICK
A player was Kicked by a DM
Definition: events.h:56
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:299
EVENT_CRASH
#define EVENT_CRASH
Triggered when the server crashes.
Definition: events.h:54
events_total
int events_total
Definition: events.cpp:8
object::subtype
uint8_t subtype
Subtype of object.
Definition: object.h:349
events.h
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_GKILL
#define EVENT_GKILL
Triggered when anything got killed by anyone.
Definition: events.h:55
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
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:380
EVENT_USER
#define EVENT_USER
User-defined event.
Definition: events.h:44
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:317
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_CLOCK
#define EVENT_CLOCK
Global time event.
Definition: events.h:53
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:1577
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:671
EVENT_MAPRESET
#define EVENT_MAPRESET
A map is resetting.
Definition: events.h:63
ensure_bitmask
static void ensure_bitmask(object *op)
Definition: events.cpp:211
tag_t
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
EVENT_PLAYER_DEATH
#define EVENT_PLAYER_DEATH
Global Death event
Definition: events.h:66
EVENT_BORN
#define EVENT_BORN
A new character has been created.
Definition: events.h:52
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
EVENT_MAPREADY
#define EVENT_MAPREADY
A map is ready, either first load or after reload.
Definition: events.h:62
EVENT_MAPLEAVE
#define EVENT_MAPLEAVE
A player left a map.
Definition: events.h:60
eg
static event_registration eg
Definition: random_house_generator.cpp:206
talk_info::text
const char * text
What the player actually said.
Definition: dialog.h:52
EVENT_GSOLD
#define EVENT_GSOLD
Player sold object in shop, but global.
Definition: events.h:71
EVENT_SAY
#define EVENT_SAY
Someone speaks.
Definition: events.h:37
EVENT_TELL
#define EVENT_TELL
A player 'tell' something.
Definition: events.h:69
BITMASK_VALID
#define BITMASK_VALID
Bit indicating if the event bitmask is valid or not.
Definition: events.h:79
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:84
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:82
EVENT_MAPENTER
#define EVENT_MAPENTER
A player entered a map.
Definition: events.h:59
talk_info
Structure used to build up dialog information when a player says something.
Definition: dialog.h:50
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:1818
EVENT_MAPLOAD
#define EVENT_MAPLOAD
A map is loaded (pristine state)
Definition: events.h:61
EVENT_MUZZLE
#define EVENT_MUZZLE
A player was Muzzled (no_shout set).
Definition: events.h:65
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:226
EVENT_SHOUT
#define EVENT_SHOUT
A player 'shout' something.
Definition: events.h:68
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:313
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:664
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