Merge branch 'master' of git://github.com/BTAxis/naev into testmission
[naev.git] / src / event.c
blob2fb712e378e0e28fa6a935752b6799e33f176b91
1 /*
2 * See Licensing and Copyright notice in naev.h
3 */
5 /**
6 * @file event.c
8 * @brief Handles internal events.
10 * Events are a lot like missions except the player has no control over when
11 * or how they happen. They can simple do something simple or actually lead up
12 * to and open an entire set of missions.
16 #include "event.h"
18 #include "naev.h"
20 #include <stdint.h>
21 #include <string.h>
22 #include <stdlib.h>
24 #include "log.h"
25 #include "nlua.h"
26 #include "nluadef.h"
27 #include "nlua_evt.h"
28 #include "nlua_hook.h"
29 #include "nlua_tk.h"
30 #include "rng.h"
31 #include "ndata.h"
32 #include "nxml.h"
33 #include "cond.h"
34 #include "hook.h"
35 #include "player.h"
36 #include "npc.h"
39 #define XML_EVENT_ID "Events" /**< XML document identifier */
40 #define XML_EVENT_TAG "event" /**< XML mission tag. */
42 #define EVENT_DATA "dat/event.xml" /**< Path to missions XML. */
43 #define EVENT_LUA_PATH "dat/events/" /**< Path to Lua files. */
45 #define EVENT_CHUNK 32 /**< Size to grow event data by. */
48 #define EVENT_FLAG_UNIQUE (1<<0) /**< Unique event. */
51 /**
52 * @brief Event data structure.
54 typedef struct EventData_s {
55 char *name; /**< Name of the event. */
56 char *lua; /**< Name of Lua file to use. */
57 unsigned int flags; /**< Bit flags. */
59 EventTrigger_t trigger; /**< What triggers the event. */
60 char *cond; /**< Conditional Lua code to execute. */
61 double chance; /**< Chance of appearing. */
62 } EventData_t;
66 * Event data.
68 static EventData_t *event_data = NULL; /**< Allocated event data. */
69 static int event_ndata = 0; /**< Number of actual event data. */
73 * Active events.
75 static unsigned int event_genid = 0; /**< Event ID generator. */
76 static Event_t *event_active = NULL; /**< Active events. */
77 static int event_nactive = 0; /**< Number of active events. */
78 static int event_mactive = 0; /**< Allocated space for active events. */
82 * Prototypes.
84 static Event_t *event_get( unsigned int eventid );
85 static int event_alreadyRunning( int data );
86 static int event_parse( EventData_t *temp, const xmlNodePtr parent );
87 static void event_freeData( EventData_t *event );
88 static int event_create( int dataid );
91 /**
92 * @brief Gets an event.
94 static Event_t *event_get( unsigned int eventid )
96 int i;
97 Event_t *ev;
99 /* Iterate. */
100 for (i=0; i<event_nactive; i++) {
101 ev = &event_active[i];
102 if (ev->id == eventid)
103 return ev;
106 WARN( "Event '%u' not found in stack.", eventid );
107 return NULL;
112 * @brief Starts running a function, allows programmer to set up arguments.
114 lua_State *event_runStart( unsigned int eventid, const char *func )
116 Event_t *ev;
118 ev = event_get( eventid );
119 if (ev == NULL)
120 return NULL;
122 return event_setupLua( ev, func );
127 * @brief Runs a function previously set up with event_runStart.
129 int event_runFunc( unsigned int eventid, const char *func, int nargs )
131 Event_t *ev;
133 ev = event_get( eventid );
134 if (ev == NULL)
135 return 0;
137 return event_runLuaFunc( ev, func, nargs );
142 * @brief Runs the event function.
144 * @param eventid ID of the event to run Lua function on.
145 * @param func Name of the function to run.
146 * @return 0 on success.
148 int event_run( unsigned int eventid, const char *func )
150 Event_t *ev;
152 ev = event_get( eventid );
153 if (ev == NULL)
154 return -1;
156 return event_runLua( ev, func );
161 * @brief Gets the name of the event data.
163 * @param ev Event to get name of data from.
164 * @return Name of data ev has.
166 const char *event_getData( unsigned int eventid )
168 Event_t *ev;
170 ev = event_get( eventid );
171 if (ev == NULL)
172 return NULL;
174 return event_data[ ev->data ].name;
179 * @brief Checks to see if an event is unique.
181 * @param eventid ID of event to see if is unique.
182 * @return 0 if isn't unique, 1 if is.
184 int event_isUnique( unsigned int eventid )
186 Event_t *ev;
188 ev = event_get( eventid );
189 if (ev == NULL)
190 return -1;
192 return !!(event_data[ ev->data ].flags & EVENT_FLAG_UNIQUE);
197 * @brief Creates an event.
199 * @param data Data to base event off of.
201 static int event_create( int dataid )
203 lua_State *L;
204 uint32_t bufsize;
205 char *buf;
206 Event_t *ev;
207 EventData_t *data;
209 /* Create the event. */
210 event_nactive++;
211 if (event_nactive > event_mactive) {
212 event_mactive += EVENT_CHUNK;
213 event_active = realloc( event_active, sizeof(Event_t) * event_mactive );
215 ev = &event_active[ event_nactive-1 ];
216 memset( ev, 0, sizeof(Event_t) );
217 ev->id = ++event_genid; /* Create unique ID. */
219 /* Add the data. */
220 ev->data = dataid;
221 data = &event_data[dataid];
223 /* Open the new state. */
224 ev->L = nlua_newState();
225 L = ev->L;
226 nlua_loadStandard(L,0);
227 nlua_loadEvt(L);
228 nlua_loadHook(L);
229 nlua_loadTk(L);
231 /* Load file. */
232 buf = ndata_read( data->lua, &bufsize );
233 if (buf == NULL) {
234 WARN("Event '%s' Lua script not found.", data->lua );
235 return -1;
237 if (luaL_dobuffer(L, buf, bufsize, data->lua) != 0) {
238 WARN("Error loading event file: %s\n"
239 "%s\n"
240 "Most likely Lua file has improper syntax, please check",
241 data->lua, lua_tostring(L,-1));
242 return -1;
244 free(buf);
246 /* Run Lua. */
247 event_runLua( ev, "create" );
249 return 0;
254 * @brief Cleans up an event.
256 * @param ev Event to clean up.
258 static void event_cleanup( Event_t *ev )
260 int i;
262 /* Destroy Lua. */
263 lua_close(ev->L);
265 /* Free hooks. */
266 hook_rmEventParent(ev->id);
268 /* Free NPC. */
269 npc_rm_parentEvent(ev->id);
271 /* Free timers. */
272 for (i=0; i<EVENT_TIMER_MAX; i++) {
273 if (ev->tfunc[i] != NULL) {
274 free(ev->tfunc[i]);
275 ev->tfunc[i] = NULL;
282 * @brief Removes an event by ID.
284 * @param eventid ID of the event to remove.
286 void event_remove( unsigned int eventid )
288 int i;
289 Event_t *ev;
291 /* Find the event. */
292 for (i=0; i<event_nactive; i++) {
293 ev = &event_active[i];
294 if (ev->id == eventid) {
295 /* Clean up event. */
296 event_cleanup(ev);
298 /* Move memory. */
299 memmove( &event_active[i], &event_active[i+1],
300 sizeof(Event_t) * (event_nactive-i-1) );
301 event_nactive--;
302 return;
306 WARN("Event ID '%u' not valid.", eventid);
311 * @brief Runs event timer stuff.
313 void events_update( double dt )
315 int i, j;
316 Event_t *ev;
317 char *tfunc;
319 for (i=0; i<event_nactive; i++) {
320 ev = &event_active[i];
322 /* Decrement timers see if must run. */
323 for (j=0; j<EVENT_TIMER_MAX; j++) {
325 if (ev->timer[j] > 0.) {
327 ev->timer[j] -= dt;
329 /* Timer is up - trigger function. */
330 if (ev->timer[j] < 0.) {
332 /* Destroy timer. */
333 ev->timer[j] = 0.;
334 tfunc = ev->tfunc[j];
335 ev->tfunc[j] = NULL;
337 /* Run function. */
338 event_runLua( ev, tfunc );
340 /* Free remainder stuff. */
341 free(tfunc);
350 * @brief Check to see if an event is already running.
352 * @param data ID of data event to check if is already running.
354 static int event_alreadyRunning( int data )
356 int i;
357 Event_t *ev;
359 /* Find events. */
360 for (i=0; i<event_nactive; i++) {
361 ev = &event_active[i];
362 if (ev->data == data) {
363 return 1;
367 return 0;
372 * @brief Runs all the events matching a trigger.
374 * @param trigger Trigger to match.
376 void events_trigger( EventTrigger_t trigger )
378 int i, c;
380 for (i=0; i<event_ndata; i++) {
381 /* Make sure trigger matches. */
382 if (event_data[i].trigger != trigger)
383 continue;
385 /* Make sure chance is succeeded. */
386 if (RNGF() > event_data[i].chance)
387 continue;
389 /* Test uniqueness. */
390 if ((event_data[i].flags & EVENT_FLAG_UNIQUE) &&
391 (player_eventAlreadyDone( i ) || event_alreadyRunning(i)))
392 continue;
394 /* Test conditional. */
395 if (event_data[i].cond != NULL) {
396 c = cond_check(event_data[i].cond);
397 if (c<0) {
398 WARN("Conditional for event '%s' failed to run.", event_data[i].name);
399 continue;
401 else if (!c)
402 continue;
405 /* Create the event. */
406 event_create( i );
412 * @brief Loads up an event from an XML node.
414 * @param temp Event to load up.
415 * @param parent Event parent node.
416 * @return 0 on success.
418 static int event_parse( EventData_t *temp, const xmlNodePtr parent )
420 xmlNodePtr node, cur;
421 char str[PATH_MAX] = "\0";
422 char *buf;
424 #ifdef DEBUGGING
425 /* To check if mission is valid. */
426 lua_State *L;
427 int ret;
428 uint32_t len;
429 #endif /* DEBUGGING */
431 memset( temp, 0, sizeof(EventData_t) );
433 /* get the name */
434 temp->name = xml_nodeProp(parent,"name");
435 if (temp->name == NULL)
436 WARN("Event in "EVENT_DATA" has invalid or no name");
438 node = parent->xmlChildrenNode;
440 do { /* load all the data */
442 /* Only check nodes. */
443 xml_onlyNodes(node);
445 if (xml_isNode(node,"lua")) {
446 snprintf( str, PATH_MAX, EVENT_LUA_PATH"%s.lua", xml_get(node) );
447 temp->lua = strdup( str );
448 str[0] = '\0';
450 #ifdef DEBUGGING
451 /* Check to see if syntax is valid. */
452 L = luaL_newstate();
453 buf = ndata_read( temp->lua, &len );
454 ret = luaL_loadbuffer(L, buf, len, temp->name );
455 if (ret == LUA_ERRSYNTAX) {
456 WARN("Event Lua '%s' of mission '%s' syntax error: %s",
457 temp->name, temp->lua, lua_tostring(L,-1) );
459 free(buf);
460 lua_close(L);
461 #endif /* DEBUGGING */
463 continue;
466 /* Trigger. */
467 else if (xml_isNode(node,"trigger")) {
468 buf = xml_get(node);
469 if (buf == NULL)
470 WARN("Event '%s': Null trigger type.", temp->name);
471 else if (strcmp(buf,"enter")==0)
472 temp->trigger = EVENT_TRIGGER_ENTER;
473 else if (strcmp(buf,"land")==0)
474 temp->trigger = EVENT_TRIGGER_LAND;
475 else
476 WARN("Event '%s' has invalid 'trigger' parameter: %s", temp->name, buf);
478 continue;
481 /* Flags. */
482 else if (xml_isNode(node,"flags")) { /* set the various flags */
483 cur = node->children;
484 do {
485 if (xml_isNode(cur,"unique"))
486 temp->flags |= EVENT_FLAG_UNIQUE;
487 } while (xml_nextNode(cur));
488 continue;
491 /* Condition. */
492 xmlr_strd(node,"cond",temp->cond);
494 /* Get chance. */
495 xmlr_float(node,"chance",temp->chance);
497 DEBUG("Unknown node '%s' in event '%s'", node->name, temp->name);
498 } while (xml_nextNode(node));
500 /* Process. */
501 temp->chance /= 100.;
503 #define MELEMENT(o,s) \
504 if (o) WARN("Mission '%s' missing/invalid '"s"' element", temp->name)
505 MELEMENT(temp->lua==NULL,"lua");
506 MELEMENT(temp->chance==0.,"chance");
507 MELEMENT(temp->trigger==EVENT_TRIGGER_NULL,"trigger");
508 #undef MELEMENT
510 return 0;
515 * @brief Loads all the events.
517 * @return 0 on success.
519 int events_load (void)
521 int m;
522 uint32_t bufsize;
523 char *buf;
524 xmlNodePtr node;
525 xmlDocPtr doc;
527 /* Load the data. */
528 buf = ndata_read( EVENT_DATA, &bufsize );
529 if (buf == NULL) {
530 WARN("Unable to read data from '%s'", EVENT_DATA);
531 return -1;
534 /* Load the document. */
535 doc = xmlParseMemory( buf, bufsize );
536 if (doc == NULL) {
537 WARN("Unable to parse document '%s'", EVENT_DATA);
538 return -1;
541 /* Get the root node. */
542 node = doc->xmlChildrenNode;
543 if (!xml_isNode(node,XML_EVENT_ID)) {
544 WARN("Malformed '"EVENT_DATA"' file: missing root element '"XML_EVENT_ID"'");
545 return -1;
548 /* Get the first node. */
549 node = node->xmlChildrenNode; /* first mission node */
550 if (node == NULL) {
551 WARN("Malformed '"EVENT_DATA"' file: does not contain elements");
552 return -1;
555 m = 0;
556 do {
557 if (xml_isNode(node,XML_EVENT_TAG)) {
559 /* See if must grow. */
560 event_ndata++;
561 if (event_ndata > m) {
562 m += EVENT_CHUNK;
563 event_data = realloc(event_data, sizeof(EventData_t)*m);
566 /* Load it. */
567 event_parse( &event_data[event_ndata-1], node );
569 } while (xml_nextNode(node));
571 /* Shrink to minimum. */
572 event_data = realloc(event_data, sizeof(EventData_t)*event_ndata);
574 /* Clean up. */
575 xmlFreeDoc(doc);
576 free(buf);
578 DEBUG("Loaded %d Event%s", event_ndata, (event_ndata==1) ? "" : "s" );
580 return 0;
585 * @brief Frees an EventData structure.
587 * @param event Event Data to free.
589 static void event_freeData( EventData_t *event )
591 if (event->name) {
592 free(event->name);
593 event->name = NULL;
595 if (event->lua) {
596 free(event->lua);
597 event->lua = NULL;
599 if (event->cond) {
600 free(event->cond);
601 event->cond = NULL;
607 * @brief Cleans up and removes active events.
609 void events_cleanup (void)
611 int i;
613 /* Free active events. */
614 for (i=0; i<event_nactive; i++)
615 event_cleanup( &event_active[i] );
616 if (event_active != NULL) {
617 free(event_active);
619 event_active = NULL;
620 event_nactive = 0;
621 event_mactive = 0;
626 * @brief Exits the event subsystem.
628 void events_exit (void)
630 int i;
632 events_cleanup();
634 /* Free data. */
635 for (i=0; i<event_ndata; i++)
636 event_freeData(&event_data[i]);
637 if (event_data != NULL) {
638 event_freeData(event_data);
639 free(event_data);
641 event_data = NULL;
642 event_ndata = 0;
647 * @brief Gets the event data id from name.
649 * @param evdata Name of the data.
650 * @return ID matching dataname.
652 int event_dataID( const char *evdata )
654 int i;
656 for (i=0; i<event_ndata; i++)
657 if (strcmp(event_data[i].name, evdata)==0)
658 return i;
659 WARN("No event data found matching name '%s'.", evdata);
660 return -1;
665 * @brief Gets the event data name from id.
667 * @param dataid ID of the event data to get name of.
668 * @return Name of the event data.
670 const char *event_dataName( int dataid )
672 return event_data[dataid].name;