naev 0.12.6
event.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
14#include "nstring.h"
15#include <stdlib.h>
16
17#include "SDL_timer.h"
18
19#include "naev.h"
21
22#include "event.h"
23
24#include "array.h"
25#include "cond.h"
26#include "conf.h"
27#include "hook.h"
28#include "land.h"
29#include "log.h"
30#include "ndata.h"
31#include "nlua.h"
32#include "nlua_bkg.h"
33#include "nlua_camera.h"
34#include "nlua_evt.h"
35#include "nlua_hook.h"
36#include "nlua_music.h"
37#include "nlua_tex.h"
38#include "nlua_tk.h"
39#include "npc.h"
40#include "nxml.h"
41#include "nxml_lua.h"
42#include "player.h"
43#include "rng.h"
44
45#define XML_EVENT_ID "Events"
46#define XML_EVENT_TAG "event"
47
48#define EVENT_FLAG_UNIQUE ( 1 << 0 )
49
53typedef struct EventData_ {
54 char *name;
55 char *sourcefile;
56 char *lua;
57 int chunk;
58 unsigned int flags;
59
60 /* For specific cases. */
61 char *spob;
62 char *system;
63 char *chapter;
64 int *factions;
65 pcre2_code *chapter_re;
66
67 EventTrigger_t trigger;
68 char *cond;
70 double chance;
73
74 char **tags;
75} EventData;
76
77/*
78 * Event data.
79 */
80static EventData *event_data = NULL;
81
82/*
83 * Active events.
84 */
85static unsigned int event_genid = 0;
86static Event_t *event_active = NULL;
87
88/*
89 * Prototypes.
90 */
91static unsigned int event_genID( void );
92static int event_cmp( const void *a, const void *b );
93static int event_parseFile( const char *file, EventData *temp );
94static int event_parseXML( EventData *temp, const xmlNodePtr parent );
95static void event_freeData( EventData *event );
96static int event_create( int dataid, unsigned int *id );
97int events_saveActive( xmlTextWriterPtr writer );
98int events_loadActive( xmlNodePtr parent );
99static int events_parseActive( xmlNodePtr parent );
100
104Event_t *event_get( unsigned int eventid )
105{
106 /* Iterate. */
107 for ( int i = 0; i < array_size( event_active ); i++ ) {
108 Event_t *ev = &event_active[i];
109 if ( ev->id == eventid )
110 return ev;
111 }
112
113 return NULL;
114}
115
123int event_start( const char *name, unsigned int *id )
124{
125 int ret, edat;
126 unsigned int eid;
127
128 edat = event_dataID( name );
129 if ( edat < 0 )
130 return -1;
131 eid = 0;
132 ret = event_create( edat, &eid );
133
134 if ( ( ret == 0 ) && ( id != NULL ) )
135 *id = eid;
136 return ret;
137}
138
145const char *event_getData( unsigned int eventid )
146{
147 const Event_t *ev = event_get( eventid );
148 if ( ev == NULL )
149 return NULL;
150 return event_data[ev->data].name;
151}
152
159int event_isUnique( unsigned int eventid )
160{
161 const Event_t *ev = event_get( eventid );
162 if ( ev == NULL )
163 return -1;
164 return !!( event_data[ev->data].flags & EVENT_FLAG_UNIQUE );
165}
166
170static unsigned int event_genID( void )
171{
172 unsigned int id;
173 do {
174 id = ++event_genid; /* Create unique ID. */
175 } while ( event_get( id ) != NULL );
176 return id;
177}
178
186static int event_create( int dataid, unsigned int *id )
187{
188 Event_t *ev;
189 EventData *data;
190 unsigned int eid;
191
192 if ( event_active == NULL )
194
195 /* Create the event. */
196 ev = &array_grow( &event_active );
197 memset( ev, 0, sizeof( Event_t ) );
198 if ( ( id != NULL ) && ( *id != 0 ) )
199 eid = *id;
200 else
201 eid = event_genID();
202 ev->id = eid;
203
204 /* Add the data. */
205 ev->data = dataid;
206 data = &event_data[dataid];
207
208 /* Open the new state. */
209 ev->env = nlua_newEnv( data->sourcefile );
210 nlua_loadStandard( ev->env );
211 nlua_loadEvt( ev->env );
212 nlua_loadHook( ev->env );
213 nlua_loadCamera( ev->env );
214 nlua_loadTex( ev->env );
216 nlua_loadMusic( ev->env );
217 nlua_loadTk( ev->env );
218
219 /* Create the "mem" table for persistence. */
220 lua_newtable( naevL );
221 nlua_setenv( naevL, ev->env, "mem" );
222
223 /* Load file. */
224 if ( nlua_dochunkenv( ev->env, data->chunk, data->sourcefile ) != 0 ) {
225 WARN( _( "Error loading event file: %s\n"
226 "%s\n"
227 "Most likely Lua file has improper syntax, please check" ),
228 data->sourcefile, lua_tostring( naevL, -1 ) );
229 return -1;
230 }
231
232 /* Run Lua. */
233 if ( ( id == NULL ) || ( *id == 0 ) )
234 event_run( ev->id, "create" );
235 if ( id != NULL )
236 *id = eid; /* The ev pointer can change and be invalidated in event_run,
237 so we pass eid instead of ev->id. */
238
239 return 0;
240}
241
247static void event_cleanup( Event_t *ev )
248{
249 /* Free lua env. */
250 nlua_freeEnv( ev->env );
251
252 /* Free hooks. */
253 hook_rmEventParent( ev->id );
254
255 /* Free NPC. */
256 npc_rm_parentEvent( ev->id );
257
258 /* Free claims. */
259 if ( ev->claims != NULL )
260 claim_destroy( ev->claims );
261}
262
268void event_remove( unsigned int eventid )
269{
270 /* Find the event. */
271 for ( int i = 0; i < array_size( event_active ); i++ ) {
272 Event_t *ev = &event_active[i];
273 if ( ev->id == eventid ) {
274 /* Clean up event. */
275 event_cleanup( ev );
276
277 /* Move memory. */
279 return;
280 }
281 }
282
283 WARN( _( "Event ID '%u' not valid." ), eventid );
284}
285
289int event_save( unsigned int eventid )
290{
291 const Event_t *ev = event_get( eventid );
292 if ( ev == NULL )
293 return 0;
294 return ev->save;
295}
296
302int event_alreadyRunning( int data )
303{
304 /* Find events. */
305 for ( int i = 0; i < array_size( event_active ); i++ ) {
306 const Event_t *ev = &event_active[i];
307 if ( ev->data == data )
308 return 1;
309 }
310
311 return 0;
312}
313
319void events_trigger( EventTrigger_t trigger )
320{
321 int created = 0;
322 for ( int i = 0; i < array_size( event_data ); i++ ) {
323 EventData *ed = &event_data[i];
324
325 if ( naev_isQuit() )
326 return;
327
328 /* Make sure trigger matches. */
329 if ( ed->trigger != trigger )
330 continue;
331
332 /* Spob. */
333 if ( ( trigger == EVENT_TRIGGER_LAND || trigger == EVENT_TRIGGER_LOAD ) &&
334 ( ed->spob != NULL ) &&
335 ( strcmp( ed->spob, land_spob->name ) != 0 ) )
336 continue;
337
338 /* System. */
339 if ( ( ed->system != NULL ) &&
340 ( strcmp( ed->system, cur_system->name ) != 0 ) )
341 continue;
342
343 /* Make sure chance is succeeded. */
344 if ( RNGF() > ed->chance )
345 continue;
346
347 /* Test uniqueness. */
348 if ( ( ed->flags & EVENT_FLAG_UNIQUE ) &&
350 continue;
351
352 /* Test factions. */
353 if ( ed->factions != NULL ) {
354 int fct, match = 0;
355 if ( trigger == EVENT_TRIGGER_ENTER )
356 fct = cur_system->faction;
357 else if ( trigger == EVENT_TRIGGER_LOAD ||
358 trigger == EVENT_TRIGGER_LAND )
359 fct = land_spob->presence.faction;
360 else {
361 fct = -1;
362 match = -1; /* Don't hae to check factions. */
363 }
364
365 if ( match == 0 ) {
366 for ( int j = 0; j < array_size( ed->factions ); j++ ) {
367 if ( fct == ed->factions[j] ) {
368 match = 1;
369 break;
370 }
371 }
372 if ( !match )
373 continue;
374 }
375 }
376
377 /* If chapter, must match chapter regex. */
378 if ( ed->chapter_re != NULL ) {
379 pcre2_match_data *match_data =
380 pcre2_match_data_create_from_pattern( ed->chapter_re, NULL );
381 int rc =
382 pcre2_match( ed->chapter_re, (PCRE2_SPTR)player.chapter,
383 strlen( player.chapter ), 0, 0, match_data, NULL );
384 pcre2_match_data_free( match_data );
385 if ( rc < 0 ) {
386 switch ( rc ) {
387 case PCRE2_ERROR_NOMATCH:
388 continue;
389 default:
390 WARN( _( "Matching error %d" ), rc );
391 break;
392 }
393 continue;
394 } else if ( rc == 0 )
395 continue;
396 }
397
398 /* Test conditional. */
399 if ( ed->cond != NULL ) {
400 int c = cond_checkChunk( ed->cond_chunk, ed->cond );
401 if ( c < 0 ) {
402 WARN( _( "Conditional for event '%s' failed to run." ), ed->name );
403 continue;
404 } else if ( !c )
405 continue;
406 }
407
408 /* Create the event. */
409 event_create( i, NULL );
410 created++;
411 }
412
413 /* Run claims if necessary. */
414 if ( created )
416}
417
425static int event_parseXML( EventData *temp, const xmlNodePtr parent )
426{
427 xmlNodePtr node;
428
429 memset( temp, 0, sizeof( EventData ) );
430
431 /* Defaults. */
432 temp->chunk = LUA_NOREF;
433 temp->trigger = EVENT_TRIGGER_NULL;
434 temp->cond_chunk = LUA_NOREF;
435
436 /* get the name */
437 xmlr_attr_strd( parent, "name", temp->name );
438 if ( temp->name == NULL )
439 WARN( _( "Event in %s has invalid or no name" ), EVENT_DATA_PATH );
440
441 node = parent->xmlChildrenNode;
442 do { /* load all the data */
443 /* Only check nodes. */
444 xml_onlyNodes( node );
445
446 xmlr_strd( node, "spob", temp->spob );
447 xmlr_strd( node, "system", temp->system );
448 xmlr_strd( node, "chapter", temp->chapter );
449
450 xmlr_strd( node, "cond", temp->cond );
451 xmlr_float( node, "chance", temp->chance );
452 xmlr_int( node, "priority", temp->priority );
453
454 if ( xml_isNode( node, "faction" ) ) {
455 if ( temp->factions == NULL )
456 temp->factions = array_create( int );
457 array_push_back( &temp->factions, faction_get( xml_get( node ) ) );
458 continue;
459 }
460
461 /* Trigger. */
462 if ( xml_isNode( node, "location" ) ) {
463 char *buf = xml_get( node );
464 if ( buf == NULL )
465 WARN( _( "Event '%s': Null trigger type." ), temp->name );
466 else if ( strcmp( buf, "enter" ) == 0 )
467 temp->trigger = EVENT_TRIGGER_ENTER;
468 else if ( strcmp( buf, "land" ) == 0 )
469 temp->trigger = EVENT_TRIGGER_LAND;
470 else if ( strcmp( buf, "load" ) == 0 )
471 temp->trigger = EVENT_TRIGGER_LOAD;
472 else if ( strcmp( buf, "none" ) == 0 )
473 temp->trigger = EVENT_TRIGGER_NONE;
474 else
475 WARN( _( "Event '%s' has invalid 'trigger' parameter: %s" ),
476 temp->name, buf );
477
478 continue;
479 }
480
481 /* Flags. */
482 else if ( xml_isNode( node, "unique" ) ) { /* unique event. */
483 temp->flags |= EVENT_FLAG_UNIQUE;
484 continue;
485 }
486
487 /* Tags. */
488 if ( xml_isNode( node, "tags" ) ) {
489 xmlNodePtr cur = node->children;
490 temp->tags = array_create( char *);
491 do {
492 xml_onlyNodes( cur );
493 if ( xml_isNode( cur, "tag" ) ) {
494 const char *tmp = xml_get( cur );
495 if ( tmp != NULL )
496 array_push_back( &temp->tags, strdup( tmp ) );
497 continue;
498 }
499 WARN( _( "Event '%s' has unknown node in tags '%s'." ), temp->name,
500 cur->name );
501 } while ( xml_nextNode( cur ) );
502 continue;
503 }
504
505 /* Notes for the python mission mapping script. */
506 else if ( xml_isNode( node, "notes" ) )
507 continue;
508
509 WARN( _( "Unknown node '%s' in event '%s'" ), node->name, temp->name );
510 } while ( xml_nextNode( node ) );
511
512 /* Process. */
513 temp->chance /= 100.;
514
515 /* Compile conditional chunk. */
516 if ( temp->cond != NULL ) {
517 temp->cond_chunk = cond_compile( temp->cond );
518 if ( temp->cond_chunk == LUA_NOREF || temp->cond_chunk == LUA_REFNIL )
519 WARN( _( "Event '%s' failed to compile Lua conditional!" ),
520 temp->name );
521 }
522
523 /* Compile regex for chapter matching. */
524 if ( temp->chapter != NULL ) {
525 int errornumber;
526 PCRE2_SIZE erroroffset;
527 temp->chapter_re =
528 pcre2_compile( (PCRE2_SPTR)temp->chapter, PCRE2_ZERO_TERMINATED, 0,
529 &errornumber, &erroroffset, NULL );
530 if ( temp->chapter_re == NULL ) {
531 PCRE2_UCHAR buffer[256];
532 pcre2_get_error_message( errornumber, buffer, sizeof( buffer ) );
533 WARN( _( "Mission '%s' chapter PCRE2 compilation failed at offset %d: "
534 "%s" ),
535 temp->name, (int)erroroffset, buffer );
536 }
537 }
538
539#define MELEMENT( o, s ) \
540 if ( o ) \
541 WARN( _( "Event '%s' missing/invalid '%s' element" ), temp->name, s )
542 MELEMENT( temp->trigger == EVENT_TRIGGER_NULL, "location" );
543 MELEMENT( ( temp->trigger != EVENT_TRIGGER_NONE ) && ( temp->chance == 0. ),
544 "chance" );
545#undef MELEMENT
546
547 return 0;
548}
549
550static int event_cmp( const void *a, const void *b )
551{
552 const EventData *ea, *eb;
553 ea = (const EventData *)a;
554 eb = (const EventData *)b;
555 if ( ea->priority < eb->priority )
556 return -1;
557 else if ( ea->priority > eb->priority )
558 return +1;
559 return strcmp( ea->name, eb->name );
560}
561
567int events_load( void )
568{
569#if DEBUGGING
570 Uint32 time = SDL_GetTicks();
571#endif /* DEBUGGING */
572 char **event_files = ndata_listRecursive( EVENT_DATA_PATH );
573
574 /* Run over events. */
576 for ( int i = 0; i < array_size( event_files ); i++ ) {
577 event_parseFile( event_files[i], NULL );
578 free( event_files[i] );
579 }
580 array_free( event_files );
582
583#ifdef DEBUGGING
584 for ( int i = 0; i < array_size( event_data ); i++ ) {
585 EventData *ed = &event_data[i];
586 for ( int j = i + 1; j < array_size( event_data ); j++ )
587 if ( strcmp( ed->name, event_data[j].name ) == 0 )
588 WARN( _( "Duplicate event '%s'!" ), ed->name );
589 }
590#endif /* DEBUGGING */
591
592 /* Sort based on priority so higher priority missions can establish claims
593 * first. */
594 qsort( event_data, array_size( event_data ), sizeof( EventData ),
595 event_cmp );
596
597#if DEBUGGING
598 if ( conf.devmode ) {
599 time = SDL_GetTicks() - time;
600 DEBUG( n_( "Loaded %d Event in %.3f s", "Loaded %d Events in %.3f s",
602 array_size( event_data ), time / 1000. );
603 } else
604 DEBUG(
605 n_( "Loaded %d Event", "Loaded %d Events", array_size( event_data ) ),
607#endif /* DEBUGGING */
608
609 return 0;
610}
611
618static int event_parseFile( const char *file, EventData *temp )
619{
620 size_t bufsize;
621 xmlNodePtr node;
622 xmlDocPtr doc;
623 char *filebuf;
624 const char *pos, *start_pos;
625 int ret;
626
627 /* Load string. */
628 filebuf = ndata_read( file, &bufsize );
629 if ( filebuf == NULL ) {
630 WARN( _( "Unable to read data from '%s'" ), file );
631 return -1;
632 }
633 if ( bufsize == 0 ) {
634 free( filebuf );
635 return -1;
636 }
637
638 /* Skip if no XML. */
639 pos = strnstr( filebuf, "</event>", bufsize );
640 if ( pos == NULL ) {
641 pos = strnstr( filebuf, "function create", bufsize );
642 if ( ( pos != NULL ) && !strncmp( pos, "--common", bufsize ) )
643 WARN( _( "Event '%s' has create function but no XML header!" ), file );
644 free( filebuf );
645 return 0;
646 }
647
648 /* Separate XML header and Lua. */
649 start_pos = strnstr( filebuf, "<?xml ", bufsize );
650 pos = strnstr( filebuf, "--]]", bufsize );
651 if ( pos == NULL || start_pos == NULL ) {
652 WARN( _( "Event file '%s' has missing XML header!" ), file );
653 return -1;
654 }
655
656 /* Parse the header. */
657 doc = xmlParseMemory( start_pos, pos - start_pos );
658 if ( doc == NULL ) {
659 WARN( _( "Unable to parse document XML header for Event '%s'" ), file );
660 return -1;
661 }
662
663 /* Get the root node. */
664 node = doc->xmlChildrenNode;
665 if ( !xml_isNode( node, XML_EVENT_TAG ) ) {
666 WARN( _( "Malformed '%s' file: missing root element '%s'" ), file,
668 return -1;
669 }
670
671 if ( temp == NULL )
672 temp = &array_grow( &event_data );
673 event_parseXML( temp, node );
674 temp->lua = strdup( filebuf );
675 temp->sourcefile = strdup( file );
676
677 /* Clear chunk if already loaded. */
678 if ( temp->chunk != LUA_NOREF ) {
679 luaL_unref( naevL, LUA_REGISTRYINDEX, temp->chunk );
680 temp->chunk = LUA_NOREF;
681 }
682
683 /* Check to see if syntax is valid. */
684 ret = luaL_loadbuffer( naevL, temp->lua, strlen( temp->lua ), temp->name );
685 if ( ret == LUA_ERRSYNTAX )
686 WARN( _( "Event Lua '%s' syntax error: %s" ), file,
687 lua_tostring( naevL, -1 ) );
688 else
689 temp->chunk = luaL_ref( naevL, LUA_REGISTRYINDEX );
690
691 /* Clean up. */
692 xmlFreeDoc( doc );
693 free( filebuf );
694
695 return 0;
696}
697
703static void event_freeData( EventData *event )
704{
705 free( event->name );
706 free( event->sourcefile );
707 free( event->lua );
708
709 free( event->spob );
710 free( event->system );
711 free( event->chapter );
712 pcre2_code_free( event->chapter_re );
713
714 array_free( event->factions );
715
716 free( event->cond );
717
718 if ( event->chunk != LUA_NOREF )
719 luaL_unref( naevL, LUA_REGISTRYINDEX, event->chunk );
720
721 if ( event->cond_chunk != LUA_NOREF )
722 luaL_unref( naevL, LUA_REGISTRYINDEX, event->cond_chunk );
723
724 for ( int i = 0; i < array_size( event->tags ); i++ )
725 free( event->tags[i] );
726 array_free( event->tags );
727
728 /* Clear the memory. */
729#if DEBUGGING
730 memset( event, 0, sizeof( EventData ) );
731#endif /* DEBUGGING */
732}
733
737void events_cleanup( void )
738{
739 /* Free active events. */
740 for ( int i = 0; i < array_size( event_active ); i++ )
743 event_active = NULL;
744}
745
749void events_exit( void )
750{
752
753 /* Free data. */
754 for ( int i = 0; i < array_size( event_data ); i++ )
757 event_data = NULL;
758}
759
766int event_dataID( const char *evdata )
767{
768 for ( int i = 0; i < array_size( event_data ); i++ )
769 if ( strcmp( event_data[i].name, evdata ) == 0 )
770 return i;
771 WARN( _( "No event data found matching name '%s'." ), evdata );
772 return -1;
773}
774
781const char *event_dataName( int dataid )
782{
783 return event_data[dataid].name;
784}
785
790{
791 /* Free active events. */
792 for ( int i = 0; i < array_size( event_active ); i++ )
793 if ( event_active[i].claims != NULL )
794 claim_activate( event_active[i].claims );
795}
796
800int event_testClaims( unsigned int eventid, int sys )
801{
802 const Event_t *ev = event_get( eventid );
803 if ( ev == NULL ) {
804 WARN( _( "Trying to test claims of unknown event with id '%d'!" ),
805 eventid );
806 return 0;
807 }
808 return claim_testSys( ev->claims, sys );
809}
810
815{
816 /* Iterate. */
817 for ( int i = 0; i < array_size( event_active ); i++ ) {
818 const Event_t *ev = &event_active[i];
819
820 /* Check if has children. */
821 if ( hook_hasEventParent( ev->id ) > 0 )
822 continue;
823
824 /* Must delete. */
825 WARN( _( "Detected event '%s' without any hooks and is therefore "
826 "invalid. Removing event." ),
827 event_dataName( ev->data ) );
828 event_remove( ev->id );
829 i--; /* Keep iteration safe. */
830 }
831}
832
839int events_saveActive( xmlTextWriterPtr writer )
840{
841 xmlw_startElem( writer, "events" );
842
843 for ( int i = 0; i < array_size( event_active ); i++ ) {
844 Event_t *ev = &event_active[i];
845 if ( !ev->save ) /* Only save events that want to be saved. */
846 continue;
847
848 xmlw_startElem( writer, "event" );
849
850 xmlw_attr( writer, "name", "%s", event_dataName( ev->data ) );
851 xmlw_attr( writer, "id", "%u", ev->id );
852
853 /* Claims. */
854 xmlw_startElem( writer, "claims" );
855 claim_xmlSave( writer, ev->claims );
856 xmlw_endElem( writer ); /* "claims" */
857
858 /* Write Lua magic */
859 xmlw_startElem( writer, "lua" );
860 nxml_persistLua( ev->env, writer );
861 xmlw_endElem( writer ); /* "lua" */
862
863 xmlw_endElem( writer ); /* "event" */
864 }
865
866 xmlw_endElem( writer ); /* "events" */
867
868 return 0;
869}
870
877int events_loadActive( xmlNodePtr parent )
878{
879 int failed = 0;
880 xmlNodePtr node = parent->xmlChildrenNode;
881
882 /* cleanup old events */
884
885 do {
886 if ( xml_isNode( node, "events" ) ) {
887 int ret = events_parseActive( node );
888 failed |= ret;
889 }
890 } while ( xml_nextNode( node ) );
891
892 return failed;
893}
894
901static int events_parseActive( xmlNodePtr parent )
902{
903 xmlNodePtr node = parent->xmlChildrenNode;
904 do {
905 char *buf;
906 unsigned int id;
907 int data;
908 xmlNodePtr cur;
909 Event_t *ev;
910
911 if ( !xml_isNode( node, "event" ) )
912 continue;
913
914 xmlr_attr_strd( node, "name", buf );
915 if ( buf == NULL ) {
916 WARN( _( "Event has missing 'name' attribute, skipping." ) );
917 continue;
918 }
919 data = event_dataID( buf );
920 if ( data < 0 ) {
921 WARN( _( "Event in save has name '%s' but event data not found "
922 "matching name. Skipping." ),
923 buf );
924 free( buf );
925 continue;
926 }
927 free( buf );
928 xmlr_attr_uint( node, "id", id );
929 if ( id == 0 ) {
930 WARN(
931 _( "Event with data '%s' has invalid 'id' attribute, skipping." ),
932 event_dataName( data ) );
933 continue;
934 }
935
936 /* Create the event. */
937 event_create( data, &id );
938 ev = event_get( id );
939 if ( ev == NULL ) {
940 WARN( _( "Event with data '%s' was not created, skipping." ),
941 event_dataName( data ) );
942 continue;
943 }
944 ev->save = 1; /* Should save by default again. */
945
946 /* Get the data. */
947 cur = node->xmlChildrenNode;
948 do {
949 if ( xml_isNode( cur, "lua" ) ) {
950 int ret = nxml_unpersistLua( ev->env, cur );
951 if ( ret ) {
952 WARN( _( "Event with data '%s' failed to unpersist Lua, "
953 "skipping." ),
954 event_dataName( data ) );
955 event_remove( id );
956 return -1;
957 }
958 }
959 } while ( xml_nextNode( cur ) );
960
961 /* Claims. */
962 if ( xml_isNode( node, "claims" ) )
963 ev->claims = claim_xmlLoad( node );
964 } while ( xml_nextNode( node ) );
965
966 return 0;
967}
968
969int event_reload( const char *name )
970{
971 int res, edat = event_dataID( name );
972 EventData save, *temp = edat < 0 ? NULL : &event_data[edat];
973 if ( temp == NULL )
974 return -1;
975 save = *temp;
976 res = event_parseFile( save.sourcefile, temp );
977 if ( res == 0 )
978 event_freeData( &save );
979 else
980 *temp = save;
981 return res;
982}
983
984void event_toLuaTable( lua_State *L, int eventid )
985{
986 const EventData *data = &event_data[eventid];
987
988 lua_newtable( L );
989
990 lua_pushstring( L, data->name );
991 lua_setfield( L, -2, "name" );
992
993 lua_pushboolean( L, ( data->flags & EVENT_FLAG_UNIQUE ) );
994 lua_setfield( L, -2, "unique" );
995
996 lua_newtable( L );
997 for ( int j = 0; j < array_size( data->tags ); j++ ) {
998 lua_pushboolean( L, 1 );
999 lua_setfield( L, -2, data->tags[j] );
1000 }
1001 lua_setfield( L, -2, "tags" );
1002}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
Definition array.h:102
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
Definition array.h:148
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:122
#define array_shrink(ptr_array)
Shrinks memory to fit only ‘size’ elements.
Definition array.h:160
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:134
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
void claim_destroy(Claim_t *claim)
Destroys a system claim.
Definition claim.c:189
void claim_activate(Claim_t *claim)
Activates a claim on a system.
Definition claim.c:252
int claim_testSys(const Claim_t *claim, int sys)
Tests to see if a system is claimed by a system claim.
Definition claim.c:170
Claim_t * claim_xmlLoad(xmlNodePtr parent)
Loads a claim.
Definition claim.c:306
int claim_xmlSave(xmlTextWriterPtr writer, const Claim_t *claim)
Saves all the systems in a claim in XML.
Definition claim.c:279
void claim_activateAll(void)
Activates all the claims.
Definition claim.c:240
int cond_compile(const char *cond)
Compiles a conditional statement that can then be used as a reference.
Definition cond.c:52
static unsigned int event_genid
Definition event.c:85
int event_start(const char *name, unsigned int *id)
Starts an event.
Definition event.c:123
const char * event_dataName(int dataid)
Gets the event data name from id.
Definition event.c:781
void events_exit(void)
Exits the event subsystem.
Definition event.c:749
int event_alreadyRunning(int data)
Check to see if an event is already running.
Definition event.c:302
static int event_parseFile(const char *file, EventData *temp)
Parses an event file.
Definition event.c:618
const char * event_getData(unsigned int eventid)
Gets the name of the event data.
Definition event.c:145
int events_loadActive(xmlNodePtr parent)
Loads the player's active events from a save.
Definition event.c:877
void event_remove(unsigned int eventid)
Removes an event by ID.
Definition event.c:268
Event_t * event_get(unsigned int eventid)
Gets an event.
Definition event.c:104
static Event_t * event_active
Definition event.c:86
void events_cleanup(void)
Cleans up and removes active events.
Definition event.c:737
int event_dataID(const char *evdata)
Gets the event data id from name.
Definition event.c:766
static void event_cleanup(Event_t *ev)
Cleans up an event.
Definition event.c:247
static void event_freeData(EventData *event)
Frees an EventData structure.
Definition event.c:703
int event_save(unsigned int eventid)
Checks to see if an event should be saved.
Definition event.c:289
static int events_parseActive(xmlNodePtr parent)
Parses the actual individual event nodes.
Definition event.c:901
#define XML_EVENT_TAG
Definition event.c:46
int event_isUnique(unsigned int eventid)
Checks to see if an event is unique.
Definition event.c:159
int events_load(void)
Loads all the events.
Definition event.c:567
void event_activateClaims(void)
Activates all the active event claims.
Definition event.c:789
void event_checkValidity(void)
Checks the event validity and cleans up after them.
Definition event.c:814
void events_trigger(EventTrigger_t trigger)
Runs all the events matching a trigger.
Definition event.c:319
int events_saveActive(xmlTextWriterPtr writer)
Saves the player's active events.
Definition event.c:839
static int event_parseXML(EventData *temp, const xmlNodePtr parent)
Loads up an event from an XML node.
Definition event.c:425
static unsigned int event_genID(void)
Generates a new event ID.
Definition event.c:170
int event_testClaims(unsigned int eventid, int sys)
Tests to see if an event has claimed a system.
Definition event.c:800
static EventData * event_data
Definition event.c:80
#define EVENT_FLAG_UNIQUE
Definition event.c:48
static int event_create(int dataid, unsigned int *id)
Creates an event.
Definition event.c:186
int faction_get(const char *name)
Gets a faction ID by name.
Definition faction.c:209
int hook_hasEventParent(unsigned int parent)
Checks to see how many hooks there are with the same event parent.
Definition hook.c:910
void hook_rmEventParent(unsigned int parent)
Removes all hooks belonging to parent event.
Definition hook.c:881
Spob * land_spob
Definition land.c:87
int naev_isQuit(void)
Get if Naev is trying to quit.
Definition naev.c:153
Header file with generic functions and naev-specifics.
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
Definition ndata.c:207
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition ndata.c:286
int nlua_loadStandard(nlua_env env)
Loads the standard Naev Lua API.
Definition nlua.c:914
lua_State * naevL
Definition nlua.c:54
int nlua_loadBackground(nlua_env env)
Loads the graphics library.
Definition nlua_bkg.c:33
int nlua_loadCamera(nlua_env env)
Loads the camera library.
Definition nlua_camera.c:48
int event_run(unsigned int eventid, const char *func)
Runs the event function.
Definition nlua_evt.c:90
int nlua_loadEvt(nlua_env env)
Loads the event Lua library.
Definition nlua_evt.c:58
int nlua_loadHook(nlua_env env)
Loads the hook Lua library.
Definition nlua_hook.c:125
int nlua_loadMusic(nlua_env env)
Music Lua module.
Definition nlua_music.c:52
int nlua_loadTex(nlua_env env)
Loads the texture library.
Definition nlua_tex.c:59
int nlua_loadTk(nlua_env env)
Loads the Toolkit Lua library.
Definition nlua_tk.c:98
int npc_rm_parentEvent(unsigned int id)
Removes all the npc belonging to an event.
Definition npc.c:279
char * strnstr(const char *haystack, const char *needle, size_t size)
A bounded version of strstr. Conforms to BSD semantics.
Definition nstring.c:26
int nxml_persistLua(nlua_env env, xmlTextWriterPtr writer)
Persists all the nxml Lua data.
Definition nxml_lua.c:374
int nxml_unpersistLua(nlua_env env, xmlNodePtr parent)
Unpersists Lua data into a table named "mem".
Definition nxml_lua.c:530
int player_eventAlreadyDone(int id)
Checks to see if player has already completed a event.
Definition player.c:3180
Player_t player
Definition player.c:77
static const double c[]
Definition rng.c:256
StarSystem * cur_system
Definition space.c:110
Event data structure.
Definition event.c:53
char * chapter
Definition event.c:63
char * name
Definition event.c:54
char * cond
Definition event.c:68
int cond_chunk
Definition event.c:69
char ** tags
Definition event.c:74
int chunk
Definition event.c:57
double chance
Definition event.c:70
char * lua
Definition event.c:56
int * factions
Definition event.c:64
int priority
Definition event.c:71
EventTrigger_t trigger
Definition event.c:67
pcre2_code * chapter_re
Definition event.c:65
unsigned int flags
Definition event.c:58
char * spob
Definition event.c:61
char * system
Definition event.c:62
char * sourcefile
Definition event.c:55
Activated event structure.
Definition event.h:12
unsigned int id
Definition event.h:13
int save
Definition event.h:16
int data
Definition event.h:14
nlua_env env
Definition event.h:15
Claim_t * claims
Definition event.h:17