33#include "nlua_camera.h"
36#include "nlua_music.h"
45#define XML_EVENT_ID "Events"
46#define XML_EVENT_TAG "event"
48#define EVENT_FLAG_UNIQUE ( 1 << 0 )
53typedef struct EventData_ {
92static int event_cmp(
const void *a,
const void *b );
109 if ( ev->
id == eventid )
134 if ( ( ret == 0 ) && (
id != NULL ) )
197 memset( ev, 0,
sizeof(
Event_t ) );
198 if ( (
id != NULL ) && ( *
id != 0 ) )
209 ev->
env = nlua_newEnv( data->sourcefile );
220 lua_newtable(
naevL );
221 nlua_setenv(
naevL, ev->
env,
"mem" );
224 if ( nlua_dochunkenv( ev->
env, data->chunk, data->sourcefile ) != 0 ) {
225 WARN( _(
"Error loading event file: %s\n"
227 "Most likely Lua file has improper syntax, please check" ),
228 data->sourcefile, lua_tostring(
naevL, -1 ) );
233 if ( (
id == NULL ) || ( *
id == 0 ) )
250 nlua_freeEnv( ev->
env );
273 if ( ev->
id == eventid ) {
283 WARN( _(
"Event ID '%u' not valid." ), eventid );
307 if ( ev->
data == data )
333 if ( ( trigger == EVENT_TRIGGER_LAND || trigger == EVENT_TRIGGER_LOAD ) &&
334 ( ed->
spob != NULL ) &&
339 if ( ( ed->
system != NULL ) &&
344 if ( RNGF() > ed->
chance )
355 if ( trigger == EVENT_TRIGGER_ENTER )
357 else if ( trigger == EVENT_TRIGGER_LOAD ||
358 trigger == EVENT_TRIGGER_LAND )
379 pcre2_match_data *match_data =
380 pcre2_match_data_create_from_pattern( ed->
chapter_re, NULL );
383 strlen(
player.chapter ), 0, 0, match_data, NULL );
384 pcre2_match_data_free( match_data );
387 case PCRE2_ERROR_NOMATCH:
390 WARN( _(
"Matching error %d" ), rc );
394 }
else if ( rc == 0 )
399 if ( ed->
cond != NULL ) {
402 WARN( _(
"Conditional for event '%s' failed to run." ), ed->
name );
432 temp->
chunk = LUA_NOREF;
433 temp->
trigger = EVENT_TRIGGER_NULL;
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 );
441 node = parent->xmlChildrenNode;
444 xml_onlyNodes( node );
446 xmlr_strd( node,
"spob", temp->
spob );
447 xmlr_strd( node,
"system", temp->
system );
448 xmlr_strd( node,
"chapter", temp->
chapter );
450 xmlr_strd( node,
"cond", temp->
cond );
451 xmlr_float( node,
"chance", temp->
chance );
452 xmlr_int( node,
"priority", temp->
priority );
454 if ( xml_isNode( node,
"faction" ) ) {
462 if ( xml_isNode( node,
"location" ) ) {
463 char *buf = xml_get( node );
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;
475 WARN( _(
"Event '%s' has invalid 'trigger' parameter: %s" ),
482 else if ( xml_isNode( node,
"unique" ) ) {
488 if ( xml_isNode( node,
"tags" ) ) {
489 xmlNodePtr cur = node->children;
492 xml_onlyNodes( cur );
493 if ( xml_isNode( cur,
"tag" ) ) {
494 const char *tmp = xml_get( cur );
499 WARN( _(
"Event '%s' has unknown node in tags '%s'." ), temp->
name,
501 }
while ( xml_nextNode( cur ) );
506 else if ( xml_isNode( node,
"notes" ) )
509 WARN( _(
"Unknown node '%s' in event '%s'" ), node->name, temp->
name );
510 }
while ( xml_nextNode( node ) );
516 if ( temp->
cond != NULL ) {
519 WARN( _(
"Event '%s' failed to compile Lua conditional!" ),
526 PCRE2_SIZE erroroffset;
528 pcre2_compile( (PCRE2_SPTR)temp->
chapter, PCRE2_ZERO_TERMINATED, 0,
529 &errornumber, &erroroffset, 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: "
535 temp->
name, (
int)erroroffset, buffer );
539#define MELEMENT( o, s ) \
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. ),
550static int event_cmp(
const void *a,
const void *b )
559 return strcmp( ea->
name, eb->
name );
570 Uint32 time = SDL_GetTicks();
576 for (
int i = 0; i <
array_size( event_files ); i++ ) {
578 free( event_files[i] );
588 WARN( _(
"Duplicate event '%s'!" ), ed->
name );
598 if ( conf.devmode ) {
599 time = SDL_GetTicks() - time;
600 DEBUG( n_(
"Loaded %d Event in %.3f s",
"Loaded %d Events in %.3f s",
624 const char *pos, *start_pos;
629 if ( filebuf == NULL ) {
630 WARN( _(
"Unable to read data from '%s'" ), file );
633 if ( bufsize == 0 ) {
639 pos =
strnstr( filebuf,
"</event>", bufsize );
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 );
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 );
657 doc = xmlParseMemory( start_pos, pos - start_pos );
659 WARN( _(
"Unable to parse document XML header for Event '%s'" ), file );
664 node = doc->xmlChildrenNode;
666 WARN( _(
"Malformed '%s' file: missing root element '%s'" ), file,
674 temp->
lua = strdup( filebuf );
678 if ( temp->
chunk != LUA_NOREF ) {
679 luaL_unref(
naevL, LUA_REGISTRYINDEX, temp->
chunk );
680 temp->
chunk = LUA_NOREF;
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 ) );
689 temp->
chunk = luaL_ref(
naevL, LUA_REGISTRYINDEX );
718 if ( event->
chunk != LUA_NOREF )
719 luaL_unref(
naevL, LUA_REGISTRYINDEX, event->
chunk );
725 free( event->
tags[i] );
769 if ( strcmp(
event_data[i].name, evdata ) == 0 )
771 WARN( _(
"No event data found matching name '%s'." ), evdata );
804 WARN( _(
"Trying to test claims of unknown event with id '%d'!" ),
825 WARN( _(
"Detected event '%s' without any hooks and is therefore "
826 "invalid. Removing event." ),
841 xmlw_startElem( writer,
"events" );
848 xmlw_startElem( writer,
"event" );
851 xmlw_attr( writer,
"id",
"%u", ev->
id );
854 xmlw_startElem( writer,
"claims" );
856 xmlw_endElem( writer );
859 xmlw_startElem( writer,
"lua" );
861 xmlw_endElem( writer );
863 xmlw_endElem( writer );
866 xmlw_endElem( writer );
880 xmlNodePtr node = parent->xmlChildrenNode;
886 if ( xml_isNode( node,
"events" ) ) {
890 }
while ( xml_nextNode( node ) );
903 xmlNodePtr node = parent->xmlChildrenNode;
911 if ( !xml_isNode( node,
"event" ) )
914 xmlr_attr_strd( node,
"name", buf );
916 WARN( _(
"Event has missing 'name' attribute, skipping." ) );
921 WARN( _(
"Event in save has name '%s' but event data not found "
922 "matching name. Skipping." ),
928 xmlr_attr_uint( node,
"id",
id );
931 _(
"Event with data '%s' has invalid 'id' attribute, skipping." ),
940 WARN( _(
"Event with data '%s' was not created, skipping." ),
947 cur = node->xmlChildrenNode;
949 if ( xml_isNode( cur,
"lua" ) ) {
952 WARN( _(
"Event with data '%s' failed to unpersist Lua, "
959 }
while ( xml_nextNode( cur ) );
962 if ( xml_isNode( node,
"claims" ) )
964 }
while ( xml_nextNode( node ) );
969int event_reload(
const char *name )
984void event_toLuaTable( lua_State *L,
int eventid )
990 lua_pushstring( L, data->name );
991 lua_setfield( L, -2,
"name" );
994 lua_setfield( L, -2,
"unique" );
997 for (
int j = 0; j <
array_size( data->tags ); j++ ) {
998 lua_pushboolean( L, 1 );
999 lua_setfield( L, -2, data->tags[j] );
1001 lua_setfield( L, -2,
"tags" );
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
#define array_shrink(ptr_array)
Shrinks memory to fit only ‘size’ elements.
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
void claim_destroy(Claim_t *claim)
Destroys a system claim.
void claim_activate(Claim_t *claim)
Activates a claim on a system.
int claim_testSys(const Claim_t *claim, int sys)
Tests to see if a system is claimed by a system claim.
Claim_t * claim_xmlLoad(xmlNodePtr parent)
Loads a claim.
int claim_xmlSave(xmlTextWriterPtr writer, const Claim_t *claim)
Saves all the systems in a claim in XML.
void claim_activateAll(void)
Activates all the claims.
int cond_compile(const char *cond)
Compiles a conditional statement that can then be used as a reference.
static unsigned int event_genid
int event_start(const char *name, unsigned int *id)
Starts an event.
const char * event_dataName(int dataid)
Gets the event data name from id.
void events_exit(void)
Exits the event subsystem.
int event_alreadyRunning(int data)
Check to see if an event is already running.
static int event_parseFile(const char *file, EventData *temp)
Parses an event file.
const char * event_getData(unsigned int eventid)
Gets the name of the event data.
int events_loadActive(xmlNodePtr parent)
Loads the player's active events from a save.
void event_remove(unsigned int eventid)
Removes an event by ID.
Event_t * event_get(unsigned int eventid)
Gets an event.
static Event_t * event_active
void events_cleanup(void)
Cleans up and removes active events.
int event_dataID(const char *evdata)
Gets the event data id from name.
static void event_cleanup(Event_t *ev)
Cleans up an event.
static void event_freeData(EventData *event)
Frees an EventData structure.
int event_save(unsigned int eventid)
Checks to see if an event should be saved.
static int events_parseActive(xmlNodePtr parent)
Parses the actual individual event nodes.
int event_isUnique(unsigned int eventid)
Checks to see if an event is unique.
int events_load(void)
Loads all the events.
void event_activateClaims(void)
Activates all the active event claims.
void event_checkValidity(void)
Checks the event validity and cleans up after them.
void events_trigger(EventTrigger_t trigger)
Runs all the events matching a trigger.
int events_saveActive(xmlTextWriterPtr writer)
Saves the player's active events.
static int event_parseXML(EventData *temp, const xmlNodePtr parent)
Loads up an event from an XML node.
static unsigned int event_genID(void)
Generates a new event ID.
int event_testClaims(unsigned int eventid, int sys)
Tests to see if an event has claimed a system.
static EventData * event_data
#define EVENT_FLAG_UNIQUE
static int event_create(int dataid, unsigned int *id)
Creates an event.
int faction_get(const char *name)
Gets a faction ID by name.
int hook_hasEventParent(unsigned int parent)
Checks to see how many hooks there are with the same event parent.
void hook_rmEventParent(unsigned int parent)
Removes all hooks belonging to parent event.
int naev_isQuit(void)
Get if Naev is trying to quit.
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).
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
int nlua_loadStandard(nlua_env env)
Loads the standard Naev Lua API.
int nlua_loadBackground(nlua_env env)
Loads the graphics library.
int nlua_loadCamera(nlua_env env)
Loads the camera library.
int event_run(unsigned int eventid, const char *func)
Runs the event function.
int nlua_loadEvt(nlua_env env)
Loads the event Lua library.
int nlua_loadHook(nlua_env env)
Loads the hook Lua library.
int nlua_loadMusic(nlua_env env)
Music Lua module.
int nlua_loadTex(nlua_env env)
Loads the texture library.
int nlua_loadTk(nlua_env env)
Loads the Toolkit Lua library.
int npc_rm_parentEvent(unsigned int id)
Removes all the npc belonging to an event.
char * strnstr(const char *haystack, const char *needle, size_t size)
A bounded version of strstr. Conforms to BSD semantics.
int nxml_persistLua(nlua_env env, xmlTextWriterPtr writer)
Persists all the nxml Lua data.
int nxml_unpersistLua(nlua_env env, xmlNodePtr parent)
Unpersists Lua data into a table named "mem".
int player_eventAlreadyDone(int id)
Checks to see if player has already completed a event.
Activated event structure.