naev 0.10.4
mission.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <stdint.h>
11#include <stdlib.h>
12
13#include "naev.h"
16#include "mission.h"
17
18#include "array.h"
19#include "cond.h"
20#include "faction.h"
21#include "gui_osd.h"
22#include "hook.h"
23#include "land.h"
24#include "log.h"
25#include "ndata.h"
26#include "nlua.h"
27#include "nlua_faction.h"
28#include "nlua_misn.h"
29#include "nlua_ship.h"
30#include "nlua_shiplog.h"
31#include "nluadef.h"
32#include "npc.h"
33#include "nstring.h"
34#include "nxml.h"
35#include "nxml_lua.h"
36#include "player.h"
37#include "player_fleet.h"
38#include "rng.h"
39#include "space.h"
40
41#define XML_MISSION_TAG "mission"
43/*
44 * current player missions
45 */
46static unsigned int mission_id = 0;
49/*
50 * mission stack
51 */
52static MissionData *mission_stack = NULL;
54/*
55 * prototypes
56 */
57/* static */
58/* Generation. */
59static unsigned int mission_genID (void);
60static int mission_init( Mission* mission, const MissionData* misn, int genid, int create, unsigned int *id );
61static void mission_freeData( MissionData* mission );
62/* Matching. */
63static int mission_compare( const void* arg1, const void* arg2 );
64static int mission_meetReq( const MissionData *misn, int faction,
65 const Spob *pnt, const StarSystem *sys );
66static int mission_matchFaction( const MissionData* misn, int faction );
67static int mission_location( const char *loc );
68/* Loading. */
69static int missions_cmp( const void *a, const void *b );
70static int mission_parseFile( const char* file, MissionData *temp );
71static int mission_parseXML( MissionData *temp, const xmlNodePtr parent );
72static int missions_parseActive( xmlNodePtr parent );
73/* Misc. */
74static const char* mission_markerTarget( MissionMarker *m );
75static int mission_markerLoad( Mission *misn, xmlNodePtr node );
76
82static unsigned int mission_genID (void)
83{
84 unsigned int id = ++mission_id; /* default id, not safe if loading */
85 /* we save mission ids, so check for collisions with player's missions */
86 for (int i=0; i<array_size(player_missions); i++)
87 if (id == player_missions[i]->id) /* mission id was loaded from save */
88 return mission_genID(); /* recursively try again */
89 return id;
90}
91
98int mission_getID( const char* name )
99{
100 for (int i=0; i<array_size(mission_stack); i++)
101 if (strcmp(name,mission_stack[i].name)==0)
102 return i;
103
104 WARN(_("Mission '%s' not found in stack"), name);
105 return -1;
106}
107
114const MissionData* mission_get( int id )
115{
116 if ((id < 0) || (id >= array_size(mission_stack))) return NULL;
117 return &mission_stack[id];
118}
119
123const MissionData* mission_getFromName( const char* name )
124{
125 int id = mission_getID( name );
126 if (id < 0)
127 return NULL;
128
129 return mission_get( id );
130}
131
142static int mission_init( Mission* mission, const MissionData* misn, int genid, int create, unsigned int *id )
143{
144 /* clear the mission */
145 memset( mission, 0, sizeof(Mission) );
146 mission->env = LUA_NOREF;
147
148 /* Create id if needed. */
149 mission->id = (genid) ? mission_genID() : 0;
150
151 if (id != NULL)
152 *id = mission->id;
153 mission->data = misn;
154 if (create) {
155 mission->title = strdup(_(misn->name));
156 mission->desc = strdup(_("No description."));
157 }
158
159 /* init Lua */
160 mission->env = nlua_newEnv();
161
162 misn_loadLibs( mission->env ); /* load our custom libraries */
163
164 /* Create the "mem" table for persistence. */
165 lua_newtable(naevL);
166 nlua_setenv(naevL, mission->env, "mem");
167
168 /* load the file */
169 if (nlua_dobufenv(mission->env, misn->lua, strlen(misn->lua), misn->sourcefile) != 0) {
170 WARN(_("Error loading mission file: %s\n"
171 "%s\n"
172 "Most likely Lua file has improper syntax, please check"),
173 misn->sourcefile, lua_tostring(naevL, -1));
174 return -1;
175 }
176
177 /* run create function */
178 if (create) {
179 /* Failed to create. */
180 int ret = misn_run( mission, "create");
181 if (ret) {
182 mission_cleanup(mission);
183 return ret;
184 }
185 }
186
187 return 0;
188}
189
199int mission_accept( Mission* mission )
200{
201 return misn_run( mission, "accept" );
202}
203
211{
212 int n = 0;
213 for (int i=0; i<array_size(player_missions); i++)
214 if (player_missions[i]->data == misn)
215 n++;
216 return n;
217}
218
228static int mission_meetReq( const MissionData *misn, int faction,
229 const Spob *pnt, const StarSystem *sys )
230{
231 if (misn == NULL) /* In case it doesn't exist */
232 return 0;
233
234 /* If spob, must match spob. */
235 if (misn->avail.spob != NULL) {
236 if ((pnt==NULL) || strcmp(misn->avail.spob,pnt->name)!=0)
237 return 0;
238 }
239 else if (spob_isFlag(pnt, SPOB_NOMISNSPAWN))
240 return 0;
241
242 /* If system, must match system. */
243 if ((misn->avail.system != NULL) && (sys==NULL || (strcmp(misn->avail.system,sys->name)!=0)))
244 return 0;
245
246 /* If chapter, must match chapter. */
247 if (misn->avail.chapter_re != NULL) {
248 pcre2_match_data *match_data = pcre2_match_data_create_from_pattern( misn->avail.chapter_re, NULL );
249 int rc = pcre2_match( misn->avail.chapter_re, (PCRE2_SPTR)player.chapter, strlen(player.chapter), 0, 0, match_data, NULL );
250 pcre2_match_data_free( match_data );
251 if (rc < 0) {
252 switch (rc) {
253 case PCRE2_ERROR_NOMATCH:
254 return 0;
255 default:
256 WARN(_("Matching error %d"), rc );
257 break;
258 }
259 }
260 else if (rc == 0)
261 return 0;
262 }
263
264 /* Match faction. */
265 if ((faction >= 0) && !mission_matchFaction(misn,faction))
266 return 0;
267
268 /* Must not be already done or running if unique. */
269 if (mis_isFlag(misn,MISSION_UNIQUE) &&
272 return 0;
273
274 /* Must meet Lua condition. */
275 if (misn->avail.cond != NULL) {
276 int c = cond_check(misn->avail.cond);
277 if (c < 0) {
278 WARN(_("Conditional for mission '%s' failed to run"), misn->name);
279 return 0;
280 }
281 else if (!c)
282 return 0;
283 }
284
285 /* Must meet previous mission requirements. */
286 if ((misn->avail.done != NULL) &&
288 return 0;
289
290 return 1;
291}
292
301void missions_run( MissionAvailability loc, int faction, const Spob *pnt, const StarSystem *sys )
302{
303 for (int i=0; i<array_size(mission_stack); i++) {
304 Mission mission;
305 double chance;
306 MissionData *misn = &mission_stack[i];
307
308 if (naev_isQuit())
309 return;
310
311 if (misn->avail.loc != loc)
312 continue;
313
314 if (!mission_meetReq( misn, faction, pnt, sys ))
315 continue;
316
317 chance = (double)(misn->avail.chance % 100)/100.;
318 if (chance == 0.) /* We want to consider 100 -> 100% not 0% */
319 chance = 1.;
320
321 if (RNGF() < chance) {
322 mission_init( &mission, misn, 1, 1, NULL );
323 mission_cleanup(&mission); /* it better clean up for itself or we do it */
324 }
325 }
326}
327
338int mission_start( const char *name, unsigned int *id )
339{
340 Mission mission;
341 const MissionData *mdat;
342 int ret;
343
344 /* Try to get the mission. */
345 mdat = mission_get( mission_getID(name) );
346 if (mdat == NULL)
347 return -1;
348
349 /* Try to run the mission. */
350 ret = mission_init( &mission, mdat, 1, 1, id );
351 /* Add to mission giver if necessary. */
352 if (landed && (ret==0) && (mdat->avail.loc==MIS_AVAIL_BAR))
353 npc_patchMission( &mission );
354 else
355 mission_cleanup( &mission ); /* Clean up in case not accepted. */
356
357 return ret;
358}
359
363static const char* mission_markerTarget( MissionMarker *m )
364{
365 switch (m->type) {
366 case SYSMARKER_COMPUTER:
367 case SYSMARKER_LOW:
368 case SYSMARKER_HIGH:
369 case SYSMARKER_PLOT:
370 return system_getIndex( m->objid )->name;
371 case SPOBMARKER_COMPUTER:
372 case SPOBMARKER_LOW:
373 case SPOBMARKER_HIGH:
374 case SPOBMARKER_PLOT:
375 return spob_getIndex( m->objid )->name;
376 default:
377 WARN(_("Unknown marker type."));
378 return NULL;
379 }
380}
381
382MissionMarkerType mission_markerTypeSpobToSystem( MissionMarkerType t )
383{
384 switch (t) {
385 case SYSMARKER_COMPUTER:
386 case SYSMARKER_LOW:
387 case SYSMARKER_HIGH:
388 case SYSMARKER_PLOT:
389 return t;
390 case SPOBMARKER_COMPUTER:
391 return SYSMARKER_COMPUTER;
392 case SPOBMARKER_LOW:
393 return SYSMARKER_LOW;
394 case SPOBMARKER_HIGH:
395 return SYSMARKER_HIGH;
396 case SPOBMARKER_PLOT:
397 return SYSMARKER_PLOT;
398 default:
399 WARN(_("Unknown marker type."));
400 return -1;
401 }
402}
403
404MissionMarkerType mission_markerTypeSystemToSpob( MissionMarkerType t )
405{
406 switch (t) {
407 case SYSMARKER_COMPUTER:
408 return SPOBMARKER_COMPUTER;
409 case SYSMARKER_LOW:
410 return SPOBMARKER_LOW;
411 case SYSMARKER_HIGH:
412 return SPOBMARKER_HIGH;
413 case SYSMARKER_PLOT:
414 return SPOBMARKER_PLOT;
415 case SPOBMARKER_COMPUTER:
416 case SPOBMARKER_LOW:
417 case SPOBMARKER_HIGH:
418 case SPOBMARKER_PLOT:
419 return t;
420 default:
421 WARN(_("Unknown marker type."));
422 return -1;
423 }
424}
425
426void mission_toLuaTable( lua_State *L , const MissionData *m )
427{
428 lua_newtable(L);
429
430 lua_pushstring(L, m->name);
431 lua_setfield(L,-2,"name");
432
433 lua_pushboolean(L,mis_isFlag(m,MISSION_UNIQUE));
434 lua_setfield(L,-2,"unique");
435
436 lua_newtable(L);
437 for (int j=0; j<array_size(m->tags); j++) {
438 lua_pushboolean(L,1);
439 lua_setfield(L,-2,m->tags[j]);
440 }
441 lua_setfield(L,-2,"tags");
442}
443
447static int mission_markerLoad( Mission *misn, xmlNodePtr node )
448{
449 int id;
450 MissionMarkerType type;
451 StarSystem *ssys;
452 Spob *pnt;
453
454 xmlr_attr_int_def( node, "id", id, -1 );
455 xmlr_attr_int_def( node, "type", type, -1 );
456
457 switch (type) {
458 case SYSMARKER_COMPUTER:
459 case SYSMARKER_LOW:
460 case SYSMARKER_HIGH:
461 case SYSMARKER_PLOT:
462 ssys = system_get( xml_get( node ));
463 if (ssys == NULL) {
464 WARN( _("Mission Marker to system '%s' does not exist"), xml_get( node ) );
465 return -1;
466 }
467 return mission_addMarker( misn, id, system_index(ssys), type );
468 case SPOBMARKER_COMPUTER:
469 case SPOBMARKER_LOW:
470 case SPOBMARKER_HIGH:
471 case SPOBMARKER_PLOT:
472 pnt = spob_get( xml_get( node ));
473 if (pnt == NULL) {
474 WARN( _("Mission Marker to spob '%s' does not exist"), xml_get( node ) );
475 return -1;
476 }
477 return mission_addMarker( misn, id, spob_index(pnt), type );
478 default:
479 WARN(_("Unknown marker type."));
480 return -1;
481 }
482}
483
487int mission_addMarker( Mission *misn, int id, int objid, MissionMarkerType type )
488{
489 MissionMarker *marker;
490
491 /* Create array. */
492 if (misn->markers == NULL)
494
495 /* Avoid ID collisions. */
496 if (id < 0) {
497 int m = -1;
498 for (int i=0; i<array_size(misn->markers); i++)
499 if (misn->markers[i].id > m)
500 m = misn->markers[i].id;
501 id = m+1;
502 }
503
504 /* Create the marker. */
505 marker = &array_grow( &misn->markers );
506 marker->id = id;
507 marker->objid = objid;
508 marker->type = type;
509
510 return marker->id;
511}
512
517{
518 /* Clear markers. */
520 for (int i=0; i<array_size(player_missions); i++) {
521 /* Must be a valid player mission. */
522 if (player_missions[i]->id == 0)
523 continue;
524
525 for (int j=0; j<array_size(player_missions[i]->markers); j++) {
527
528 /* Add the individual markers. */
529 space_addMarker( m->objid, m->type );
530 }
531 }
532}
533
541const StarSystem* mission_sysComputerMark( const Mission* misn )
542{
543 StarSystem *firstsys = NULL;
544
545 /* Clear markers. */
547
548 /* Set all the markers. */
549 for (int i=0; i<array_size(misn->markers); i++) {
550 StarSystem *sys;
551 Spob *pnt;
552 const char *sysname;
553 MissionMarker *m = &misn->markers[i];
554
555 switch (m->type) {
556 case SYSMARKER_COMPUTER:
557 case SYSMARKER_LOW:
558 case SYSMARKER_HIGH:
559 case SYSMARKER_PLOT:
560 sys = system_getIndex( m->objid );
561 break;
562 case SPOBMARKER_COMPUTER:
563 case SPOBMARKER_LOW:
564 case SPOBMARKER_HIGH:
565 case SPOBMARKER_PLOT:
566 pnt = spob_getIndex( m->objid );
567 sysname = spob_getSystem( pnt->name );
568 if (sysname==NULL) {
569 WARN(_("Marked spob '%s' is not in any system!"), pnt->name);
570 continue;
571 }
572 sys = system_get( sysname );
573 break;
574 default:
575 WARN(_("Unknown marker type."));
576 continue;
577 }
578
579 if (sys != NULL)
580 sys_setFlag( sys, SYSTEM_CMARKED );
581
582 if (firstsys==NULL)
583 firstsys = sys;
584 }
585 return firstsys;
586}
587
594const StarSystem* mission_getSystemMarker( const Mission* misn )
595{
596 /* Set all the markers. */
597 for (int i=0; i<array_size(misn->markers); i++) {
598 StarSystem *sys;
599 Spob *pnt;
600 const char *sysname;
601 MissionMarker *m = &misn->markers[i];;
602
603 switch (m->type) {
604 case SYSMARKER_COMPUTER:
605 case SYSMARKER_LOW:
606 case SYSMARKER_HIGH:
607 case SYSMARKER_PLOT:
608 sys = system_getIndex( m->objid );
609 break;
610 case SPOBMARKER_COMPUTER:
611 case SPOBMARKER_LOW:
612 case SPOBMARKER_HIGH:
613 case SPOBMARKER_PLOT:
614 pnt = spob_getIndex( m->objid );
615 sysname = spob_getSystem( pnt->name );
616 if (sysname==NULL) {
617 WARN(_("Marked spob '%s' is not in any system!"), pnt->name);
618 continue;
619 }
620 sys = system_get( sysname );
621 break;
622 default:
623 WARN(_("Unknown marker type."));
624 continue;
625 }
626
627 return sys;
628 }
629 return NULL;
630}
631
639int mission_linkCargo( Mission* misn, unsigned int cargo_id )
640{
641 if (misn->cargo == NULL)
642 misn->cargo = array_create( unsigned int );
643 array_push_back( &misn->cargo, cargo_id );
644 return 0;
645}
646
654int mission_unlinkCargo( Mission* misn, unsigned int cargo_id )
655{
656 int i;
657 for (i=0; i<array_size(misn->cargo); i++)
658 if (misn->cargo[i] == cargo_id)
659 break;
660
661 if (i>=array_size(misn->cargo)) { /* not found */
662 DEBUG(_("Mission '%s' attempting to unlink nonexistent cargo %d."),
663 misn->title, cargo_id);
664 return 1;
665 }
666
667 /* shrink cargo size. */
668 array_erase( &misn->cargo, &misn->cargo[i], &misn->cargo[i+1] );
669 return 0;
670}
671
678{
679 /* Hooks and missions. */
680 if (misn->id != 0) {
681 hook_rmMisnParent( misn->id ); /* remove existing hooks */
682 npc_rm_parentMission( misn->id ); /* remove existing npc */
683 }
684
685 /* Cargo. */
686 if ((player.p != NULL) && !pilot_isFlag(player.p, PILOT_DEAD)) { /* Only remove if player exists. */
687 for (int i=0; i<array_size(misn->cargo); i++) { /* must unlink all the cargo */
688 int ret = pilot_rmMissionCargo( player.p, misn->cargo[i], 0 );
689 if (ret)
690 WARN(_("Failed to remove mission cargo '%d' for mission '%s'."), misn->cargo[i], misn->title);
691 }
692 }
693 array_free(misn->cargo);
694 if (misn->osd > 0)
695 osd_destroy(misn->osd);
696 /*
697 * XXX With the way the mission code works, this function is called on a
698 * Mission struct of all zeros. Looking at the implementation, luaL_ref()
699 * never returns 0, but this is probably undefined behavior.
700 */
701 if (misn->env != LUA_NOREF)
702 nlua_freeEnv(misn->env);
703
704 /* Data. */
705 free(misn->title);
706 free(misn->desc);
707 free(misn->reward);
709 free(misn->npc);
710 free(misn->npc_desc);
711
712 /* Markers. */
713 array_free( misn->markers );
714
715 /* Claims. */
716 if (misn->claims != NULL)
717 claim_destroy( misn->claims );
718
719 /* Clear the memory. */
720 memset( misn, 0, sizeof(Mission) );
721 misn->env = LUA_NOREF;
722}
723
729void mission_shift( int pos )
730{
731 Mission *misn;
732
733 if (pos >= (array_size(player_missions)-1))
734 return;
735
736 /* Store specified mission. */
737 misn = player_missions[pos];
738
739 /* Move other missions down. */
740 memmove( &player_missions[pos], &player_missions[pos+1],
741 sizeof(Mission*) * (array_size(player_missions) - pos - 1) );
742
743 /* Put the specified mission at the end of the array. */
745}
746
752static void mission_freeData( MissionData* mission )
753{
754 free(mission->name);
755 free(mission->lua);
756 free(mission->sourcefile);
757 free(mission->avail.spob);
758 free(mission->avail.system);
759 free(mission->avail.chapter);
760 pcre2_code_free( mission->avail.chapter_re );
761 array_free(mission->avail.factions);
762 free(mission->avail.cond);
763 free(mission->avail.done);
764
765 for (int i=0; i<array_size(mission->tags); i++)
766 free(mission->tags[i]);
767 array_free(mission->tags);
768
769 /* Clear the memory. */
770#ifdef DEBUGGING
771 memset( mission, 0, sizeof(MissionData) );
772#endif /* DEBUGGING */
773}
774
782static int mission_matchFaction( const MissionData* misn, int faction )
783{
784 /* No faction always accepted. */
785 if (array_size(misn->avail.factions) == 0)
786 return 1;
787
788 /* Check factions. */
789 for (int i=0; i<array_size(misn->avail.factions); i++)
790 if (faction == misn->avail.factions[i])
791 return 1;
792
793 return 0;
794}
795
800{
801 for (int i=0; i<array_size(player_missions); i++)
802 if (player_missions[i]->claims != NULL)
803 claim_activate( player_missions[i]->claims );
804}
805
809static int mission_compare( const void* arg1, const void* arg2 )
810{
811 Mission *m1, *m2;
812
813 /* Get arguments. */
814 m1 = (Mission*) arg1;
815 m2 = (Mission*) arg2;
816
817 /* Check priority - lower is more important. */
818 if (m1->data->avail.priority < m2->data->avail.priority)
819 return -1;
820 else if (m1->data->avail.priority > m2->data->avail.priority)
821 return +1;
822
823 /* Compare NPC. */
824 if ((m1->npc != NULL) && (m2->npc != NULL))
825 return strcmp( m1->npc, m2->npc );
826
827 /* Compare title. */
828 if ((m1->title != NULL) && (m2->title != NULL))
829 return strcmp( m1->title, m2->title );
830
831 /* Tied. */
832 return strcmp(m1->data->name, m2->data->name);
833}
834
846Mission* missions_genList( int *n, int faction,
847 const Spob *pnt, const StarSystem *sys, MissionAvailability loc )
848{
849 int m, alloced;
850 int rep;
851 Mission* tmp;
852
853 /* Find available missions. */
854 tmp = NULL;
855 m = 0;
856 alloced = 0;
857 for (int i=0; i<array_size(mission_stack); i++) {
858 double chance;
859 MissionData *misn = &mission_stack[i];
860 if (misn->avail.loc != loc)
861 continue;
862
863 /* Must meet requirements. */
864 if (!mission_meetReq( misn, faction, pnt, sys ))
865 continue;
866
867 /* Must hit chance. */
868 chance = (double)(misn->avail.chance % 100)/100.;
869 if (chance == 0.) /* We want to consider 100 -> 100% not 0% */
870 chance = 1.;
871 rep = MAX(1, misn->avail.chance / 100);
872
873 /* random chance of rep appearances */
874 for (int j=0; j<rep; j++) {
875 if (RNGF() > chance)
876 continue;
877 m++;
878 /* Extra allocation. */
879 if (m > alloced) {
880 if (alloced == 0)
881 alloced = 32;
882 else
883 alloced *= 2;
884 tmp = realloc( tmp, sizeof(Mission) * alloced );
885 }
886 /* Initialize the mission. */
887 if (mission_init( &tmp[m-1], misn, 1, 1, NULL ))
888 m--;
889 }
890 }
891
892 /* Sort. */
893 if (tmp != NULL) {
894 qsort( tmp, m, sizeof(Mission), mission_compare );
895 (*n) = m;
896 }
897 else
898 (*n) = 0;
899
900 return tmp;
901}
902
909static int mission_location( const char *loc )
910{
911 if (loc != NULL) {
912 if (strcasecmp( loc, "None" ) == 0)
913 return MIS_AVAIL_NONE;
914 else if (strcasecmp( loc, "Computer" ) == 0)
915 return MIS_AVAIL_COMPUTER;
916 else if (strcasecmp( loc, "Bar" ) == 0)
917 return MIS_AVAIL_BAR;
918 else if (strcasecmp( loc, "Land" ) == 0)
919 return MIS_AVAIL_LAND;
920 else if (strcasecmp( loc, "Enter" ) == 0)
921 return MIS_AVAIL_ENTER;
922 }
923 return -1;
924}
925
933static int mission_parseXML( MissionData *temp, const xmlNodePtr parent )
934{
935 xmlNodePtr node;
936
937 /* Clear memory. */
938 memset( temp, 0, sizeof(MissionData) );
939
940 /* Defaults. */
941 temp->avail.priority = 5;
942 temp->avail.loc = MIS_AVAIL_UNSET;
943
944 /* get the name */
945 xmlr_attr_strd(parent,"name",temp->name);
946 if (temp->name == NULL)
947 WARN( _("Mission in %s has invalid or no name"), MISSION_DATA_PATH );
948
949 node = parent->xmlChildrenNode;
950
951 do { /* load all the data */
952 /* Only handle nodes. */
953 xml_onlyNodes(node);
954
955 if (xml_isNode(node,"unique")) { /* Unique mission. */
956 mis_setFlag(temp,MISSION_UNIQUE);
957 continue;
958 }
959 if (xml_isNode(node,"location")) {
960 temp->avail.loc = mission_location( xml_get(node) );
961 if (temp->avail.loc < 0)
962 WARN(_("Mission '%s' has unknown location '%s'!"), temp->name, xml_get(node) );
963 continue;
964 }
965 xmlr_int(node,"chance",temp->avail.chance);
966 xmlr_strd(node,"spob",temp->avail.spob);
967 xmlr_strd(node,"system",temp->avail.system);
968 xmlr_strd(node,"chapter",temp->avail.chapter);
969 if (xml_isNode(node,"faction")) {
970 if (temp->avail.factions == NULL)
971 temp->avail.factions = array_create( int );
972 array_push_back( &temp->avail.factions, faction_get( xml_get(node) ) );
973 continue;
974 }
975 xmlr_strd(node,"cond",temp->avail.cond);
976 xmlr_strd(node,"done",temp->avail.done);
977 xmlr_int(node,"priority",temp->avail.priority);
978
979 if (xml_isNode(node,"tags")) {
980 xmlNodePtr cur = node->children;
981 temp->tags = array_create( char* );
982 do {
983 xml_onlyNodes(cur);
984 if (xml_isNode(cur, "tag")) {
985 char *tmp = xml_get(cur);
986 if (tmp != NULL)
987 array_push_back( &temp->tags, strdup(tmp) );
988 continue;
989 }
990 WARN(_("Mission '%s' has unknown node in tags '%s'."), temp->name, cur->name );
991 } while (xml_nextNode(cur));
992 continue;
993 }
994 else if (xml_isNode(node,"notes")) continue; /* Notes for the python mission mapping script */
995
996 WARN(_("Unknown node '%s' in mission '%s'"),node->name,temp->name);
997 } while (xml_nextNode(node));
998
999 if (temp->avail.chapter != NULL) {
1000 int errornumber;
1001 PCRE2_SIZE erroroffset;
1002 temp->avail.chapter_re = pcre2_compile( (PCRE2_SPTR)temp->avail.chapter, PCRE2_ZERO_TERMINATED, 0, &errornumber, &erroroffset, NULL );
1003 if (temp->avail.chapter_re == NULL) {
1004 PCRE2_UCHAR buffer[256];
1005 pcre2_get_error_message( errornumber, buffer, sizeof(buffer) );
1006 WARN(_("Mission '%s' chapter PCRE2 compilation failed at offset %d: %s"), temp->name, (int)erroroffset, buffer );
1007 }
1008 }
1009
1010#define MELEMENT(o,s) \
1011 if (o) WARN( _("Mission '%s' missing/invalid '%s' element"), temp->name, s)
1012 MELEMENT(temp->avail.loc==MIS_AVAIL_UNSET,"location");
1013 MELEMENT((temp->avail.loc!=MIS_AVAIL_NONE) && (temp->avail.chance==0),"chance");
1014 MELEMENT( ((temp->avail.spob!=NULL) && spob_get(temp->avail.spob)==NULL), "spob" );
1015 MELEMENT( ((temp->avail.system!=NULL) && system_get(temp->avail.system)==NULL), "system" );
1016#undef MELEMENT
1017
1018 return 0;
1019}
1020
1024static int missions_cmp( const void *a, const void *b )
1025{
1026 const MissionData *ma, *mb;
1027 ma = (const MissionData*) a;
1028 mb = (const MissionData*) b;
1029 if (ma->avail.priority < mb->avail.priority)
1030 return -1;
1031 else if (ma->avail.priority > mb->avail.priority)
1032 return +1;
1033 return strcmp( ma->name, mb->name );
1034}
1035
1042{
1043 char **mission_files;
1044 Uint32 time = SDL_GetTicks();
1045
1046 /* Run over missions. */
1047 mission_files = ndata_listRecursive( MISSION_DATA_PATH );
1049 for (int i=0; i < array_size( mission_files ); i++) {
1050 mission_parseFile( mission_files[i], NULL );
1051 free( mission_files[i] );
1052 }
1053 array_free( mission_files );
1055
1056#ifdef DEBUGGING
1057 for (int i=0; i<array_size(mission_stack); i++) {
1058 MissionData *md = &mission_stack[i];
1059 for (int j=i+1; j<array_size(mission_stack); j++)
1060 if (strcmp( md->name, mission_stack[j].name )==0)
1061 WARN(_("Duplicate event '%s'!"), md->name);
1062 }
1063#endif /* DEBUGGING */
1064
1065 /* Sort based on priority so higher priority missions can establish claims first. */
1067
1068 if (conf.devmode) {
1069 time = SDL_GetTicks() - time;
1070 DEBUG( n_("Loaded %d Mission in %.3f s", "Loaded %d Missions in %.3f s", array_size(mission_stack) ), array_size(mission_stack), time/1000. );
1071 }
1072 else
1073 DEBUG( n_("Loaded %d Mission", "Loaded %d Missions", array_size(mission_stack) ), array_size(mission_stack) );
1074
1075 return 0;
1076}
1077
1084static int mission_parseFile( const char* file, MissionData *temp )
1085{
1086 xmlDocPtr doc;
1087 xmlNodePtr node;
1088 size_t bufsize;
1089 char *filebuf;
1090 const char *pos, *start_pos;
1091
1092 /* Load string. */
1093 filebuf = ndata_read( file, &bufsize );
1094 if (filebuf == NULL) {
1095 WARN(_("Unable to read data from '%s'"), file);
1096 return -1;
1097 }
1098 if (bufsize==0) {
1099 free( filebuf );
1100 return -1;
1101 }
1102
1103 /* Skip if no XML. */
1104 pos = strnstr( filebuf, "</mission>", bufsize );
1105 if (pos==NULL) {
1106 pos = strnstr( filebuf, "function create", bufsize );
1107 if ((pos != NULL) && !strncmp(pos,"--common",bufsize))
1108 WARN(_("Mission '%s' has create function but no XML header!"), file);
1109 free(filebuf);
1110 return -1;
1111 }
1112
1113 /* Separate XML header and Lua. */
1114 start_pos = strnstr( filebuf, "<?xml ", bufsize );
1115 pos = strnstr( filebuf, "--]]", bufsize );
1116 if (pos == NULL || start_pos == NULL) {
1117 WARN(_("Mission file '%s' has missing XML header!"), file);
1118 return -1;
1119 }
1120
1121 /* Parse the header. */
1122 doc = xmlParseMemory( start_pos, pos-start_pos);
1123 if (doc == NULL) {
1124 WARN(_("Unable to parse document XML header for Mission '%s'"), file);
1125 return -1;
1126 }
1127
1128 node = doc->xmlChildrenNode;
1129 if (!xml_isNode(node,XML_MISSION_TAG)) {
1130 ERR( _("Malformed XML header for '%s' mission: missing root element '%s'"), file, XML_MISSION_TAG );
1131 return -1;
1132 }
1133
1134 if (temp == NULL)
1135 temp = &array_grow(&mission_stack);
1136 mission_parseXML( temp, node );
1137 temp->lua = filebuf;
1138 temp->sourcefile = strdup(file);
1139
1140#ifdef DEBUGGING
1141 /* Check to see if syntax is valid. */
1142 int ret = luaL_loadbuffer(naevL, temp->lua, strlen(temp->lua), temp->name );
1143 if (ret == LUA_ERRSYNTAX) {
1144 WARN(_("Mission Lua '%s' syntax error: %s"),
1145 file, lua_tostring(naevL,-1) );
1146 } else {
1147 lua_pop(naevL, 1);
1148 }
1149#endif /* DEBUGGING */
1150
1151 /* Clean up. */
1152 xmlFreeDoc(doc);
1153
1154 return 0;
1155}
1156
1160void missions_free (void)
1161{
1162 /* Free all the player missions. */
1164
1165 /* Free the mission data. */
1166 for (int i=0; i<array_size(mission_stack); i++)
1169 mission_stack = NULL;
1170
1171 /* Free the player mission stack. */
1173 player_missions = NULL;
1174}
1175
1180{
1181 for (int i=0; i<array_size(player_missions); i++) {
1183 free( player_missions[i] );
1184 }
1186}
1187
1194int missions_saveActive( xmlTextWriterPtr writer )
1195{
1196 /* We also save specially created cargos here. */
1198 xmlw_startElem(writer,"temporary_cargo");
1199 for (int i=0; i<array_size(pcom); i++) {
1200 const Commodity *c = pcom[i].commodity;
1201 if (!c->istemp)
1202 continue;
1203 xmlw_startElem(writer,"cargo");
1204 missions_saveTempCommodity( writer, c );
1205 xmlw_endElem(writer); /* "cargo" */
1206 }
1207 xmlw_endElem(writer); /* "missions_cargo */
1208 array_free(pcom);
1209
1210 xmlw_startElem(writer,"missions");
1211 for (int i=0; i<array_size(player_missions); i++) {
1212 if (player_missions[i]->id != 0) {
1213 xmlw_startElem(writer,"mission");
1214
1215 /* data and id are attributes because they must be loaded first */
1216 xmlw_attr(writer,"data","%s",player_missions[i]->data->name);
1217 xmlw_attr(writer,"id","%u",player_missions[i]->id);
1218
1219 xmlw_elem(writer,"title","%s",player_missions[i]->title);
1220 xmlw_elem(writer,"desc","%s",player_missions[i]->desc);
1221 xmlw_elem(writer,"reward","%s",player_missions[i]->reward);
1222
1223 /* Markers. */
1224 xmlw_startElem( writer, "markers" );
1225 for (int j=0; j<array_size( player_missions[i]->markers ); j++) {
1227 xmlw_startElem(writer,"marker");
1228 xmlw_attr(writer,"id","%d",m->id);
1229 xmlw_attr(writer,"type","%d",m->type);
1230 xmlw_str(writer,"%s", mission_markerTarget( m ));
1231 xmlw_endElem(writer); /* "marker" */
1232 }
1233 xmlw_endElem( writer ); /* "markers" */
1234
1235 /* Cargo */
1236 xmlw_startElem(writer,"cargos");
1237 for (int j=0; j<array_size(player_missions[i]->cargo); j++)
1238 xmlw_elem(writer,"cargo","%u", player_missions[i]->cargo[j]);
1239 xmlw_endElem(writer); /* "cargos" */
1240
1241 /* OSD. */
1242 if (player_missions[i]->osd > 0) {
1243 char **items = osd_getItems(player_missions[i]->osd);
1244
1245 xmlw_startElem(writer,"osd");
1246
1247 /* Save attributes. */
1248 xmlw_attr(writer,"title","%s",osd_getTitle(player_missions[i]->osd));
1249 xmlw_attr(writer,"nitems","%d",array_size(items));
1250 xmlw_attr(writer,"active","%d",osd_getActive(player_missions[i]->osd));
1251
1252 /* Save messages. */
1253 for (int j=0; j<array_size(items); j++)
1254 xmlw_elem(writer,"msg","%s",items[j]);
1255
1256 xmlw_endElem(writer); /* "osd" */
1257 }
1258
1259 /* Claims. */
1260 xmlw_startElem(writer,"claims");
1261 claim_xmlSave( writer, player_missions[i]->claims );
1262 xmlw_endElem(writer); /* "claims" */
1263
1264 /* Write Lua magic */
1265 xmlw_startElem(writer,"lua");
1266 nxml_persistLua( player_missions[i]->env, writer );
1267 xmlw_endElem(writer); /* "lua" */
1268
1269 xmlw_endElem(writer); /* "mission" */
1270 }
1271 }
1272 xmlw_endElem(writer); /* "missions" */
1273
1274 return 0;
1275}
1276
1284int missions_saveTempCommodity( xmlTextWriterPtr writer, const Commodity *c )
1285{
1286 xmlw_attr( writer, "name", "%s", c->name );
1287 xmlw_attr( writer, "description", "%s", c->description );
1288 for (int j=0; j < array_size( c->illegalto ); j++)
1289 xmlw_elem( writer, "illegalto", "%s", faction_name( c->illegalto[ j ] ) );
1290 return 0;
1291}
1292
1299int missions_loadCommodity( xmlNodePtr parent )
1300{
1301 xmlNodePtr node;
1302
1303 /* We have to ensure the temporary_cargo stuff is loaded first. */
1304 node = parent->xmlChildrenNode;
1305 do {
1306 xml_onlyNodes(node);
1307
1308 /* TODO remove support for "mission_cargo" in the future (maybe 0.12.0?). 0.10.0 onwards uses "temporary_cargo" */
1309 if (xml_isNode(node,"temporary_cargo") || xml_isNode(node,"mission_cargo")) {
1310 xmlNodePtr cur = node->xmlChildrenNode;
1311 do {
1312 xml_onlyNodes(cur);
1313 if (xml_isNode( cur, "cargo" ))
1314 (void)missions_loadTempCommodity( cur );
1315 } while (xml_nextNode( cur ));
1316 continue;
1317 }
1318 } while (xml_nextNode( node ));
1319
1320 return 0;
1321}
1322
1330{
1331 xmlNodePtr ccur;
1332 char * name, *desc;
1333 Commodity *c;
1334
1335 xmlr_attr_strd( cur, "name", name );
1336 if ( name == NULL ) {
1337 WARN( _( "Mission cargo without name!" ) );
1338 return NULL;
1339 }
1340
1341 c = commodity_getW( name );
1342 if ( c != NULL ) {
1343 free( name );
1344 return c;
1345 }
1346
1347 xmlr_attr_strd( cur, "description", desc );
1348 if ( desc == NULL ) {
1349 WARN( _( "Mission temporary cargo '%s' missing description!" ), name );
1350 free( name );
1351 return NULL;
1352 }
1353
1354 c = commodity_newTemp( name, desc );
1355
1356 ccur = cur->xmlChildrenNode;
1357 do {
1358 xml_onlyNodes( ccur );
1359 if ( xml_isNode( ccur, "illegalto" ) ) {
1360 int f = faction_get( xml_get( ccur ) );
1361 commodity_tempIllegalto( c, f );
1362 }
1363 } while ( xml_nextNode( ccur ) );
1364
1365 free( name );
1366 free( desc );
1367 return c;
1368}
1369
1376int missions_loadActive( xmlNodePtr parent )
1377{
1378 xmlNodePtr node;
1379
1380 /* cleanup old missions */
1382
1383 /* After load the normal missions. */
1384 node = parent->xmlChildrenNode;
1385 do {
1386 xml_onlyNodes(node);
1387 if (xml_isNode(node,"missions")) {
1388 if (missions_parseActive( node ) < 0)
1389 return -1;
1390 continue;
1391 }
1392 } while (xml_nextNode(node));
1393
1394 return 0;
1395}
1396
1403static int missions_parseActive( xmlNodePtr parent )
1404{
1405 char *buf;
1406 char *title;
1407 const char **items;
1408 int nitems, active;
1409 xmlNodePtr node;
1410
1411 if (player_missions == NULL)
1413
1414 node = parent->xmlChildrenNode;
1415 do {
1416 if (xml_isNode(node, "mission")) {
1417 xmlNodePtr cur;
1418 const MissionData *data;
1419 Mission *misn = calloc( 1, sizeof(Mission) );
1421
1422 /* process the attributes to create the mission */
1423 xmlr_attr_strd(node, "data", buf);
1424 data = mission_get( mission_getID(buf) );
1425 if (data == NULL) {
1426 WARN(_("Mission '%s' from saved game not found in game - ignoring."), buf);
1427 free(buf);
1428 continue;
1429 }
1430 else {
1431 if (mission_init( misn, data, 0, 0, NULL )) {
1432 WARN(_("Mission '%s' from saved game failed to load properly - ignoring."), buf);
1433 free(buf);
1434 continue;
1435 }
1436 misn->accepted = 1;
1437 }
1438 free(buf);
1439
1440 /* this will orphan an identifier */
1441 xmlr_attr_int(node, "id", misn->id);
1442
1443 cur = node->xmlChildrenNode;
1444 do {
1445 xmlr_strd(cur,"title",misn->title);
1446 xmlr_strd(cur,"desc",misn->desc);
1447 xmlr_strd(cur,"reward",misn->reward);
1448
1449 /* Get the markers. */
1450 if (xml_isNode(cur,"markers")) {
1451 xmlNodePtr nest = cur->xmlChildrenNode;
1452 do {
1453 if (xml_isNode(nest,"marker"))
1454 mission_markerLoad( misn, nest );
1455 } while (xml_nextNode(nest));
1456 }
1457
1458 /* Cargo. */
1459 if (xml_isNode(cur,"cargos")) {
1460 xmlNodePtr nest = cur->xmlChildrenNode;
1461 do {
1462 if (xml_isNode(nest,"cargo"))
1463 mission_linkCargo( misn, xml_getLong(nest) );
1464 } while (xml_nextNode(nest));
1465 }
1466
1467 /* OSD. */
1468 if (xml_isNode(cur,"osd")) {
1469 xmlNodePtr nest;
1470 int i = 0;
1471 xmlr_attr_int_def( cur, "nitems", nitems, -1 );
1472 if (nitems == -1)
1473 continue;
1474 xmlr_attr_strd(cur,"title",title);
1475 items = malloc( nitems * sizeof(char*) );
1476 nest = cur->xmlChildrenNode;
1477 do {
1478 if (xml_isNode(nest,"msg")) {
1479 if (i > nitems) {
1480 WARN(_("Inconsistency with 'nitems' in save file."));
1481 break;
1482 }
1483 items[i] = xml_get(nest);
1484 i++;
1485 }
1486 } while (xml_nextNode(nest));
1487
1488 /* Create the OSD. */
1489 misn->osd = osd_create( title, nitems, items, data->avail.priority );
1490 free(items);
1491 free(title);
1492
1493 /* Set active. */
1494 xmlr_attr_int_def( cur, "active", active, -1 );
1495 if (active != -1)
1496 osd_active( misn->osd, active );
1497 }
1498
1499 /* Claims. */
1500 if (xml_isNode(cur,"claims"))
1501 misn->claims = claim_xmlLoad( cur );
1502
1503 if (xml_isNode(cur,"lua"))
1504 /* start the unpersist routine */
1505 nxml_unpersistLua( misn->env, cur );
1506
1507 } while (xml_nextNode(cur));
1508 }
1509 } while (xml_nextNode(node));
1510
1511 return 0;
1512}
1513
1514int mission_reload( const char *name )
1515{
1516 int res, id;
1517 MissionData save, *temp;
1518
1519 /* Can't use mission_getFromName here. */
1520 id = mission_getID( name );
1521 if (id < 0)
1522 return -1;
1523 temp = &mission_stack[id];
1524
1525 if (temp == NULL)
1526 return -1;
1527 save = *temp;
1528 res = mission_parseFile( save.sourcefile, temp );
1529 if (res == 0)
1530 mission_freeData( &save );
1531 else
1532 *temp = save;
1533 return res;
1534}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition: array.h:158
#define array_end(array)
Returns a pointer to the end of the reserved memory space.
Definition: array.h:202
#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:140
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition: array.h:168
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition: array.h:119
#define array_shrink(ptr_array)
Shrinks memory to fit only ‘size’ elements.
Definition: array.h:149
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition: array.h:129
#define array_begin(array)
Returns a pointer to the beginning of the reserved memory space.
Definition: array.h:194
#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:251
Claim_t * claim_xmlLoad(xmlNodePtr parent)
Loads a claim.
Definition: claim.c:305
int claim_xmlSave(xmlTextWriterPtr writer, const Claim_t *claim)
Saves all the systems in a claim in XML.
Definition: claim.c:278
int cond_check(const char *cond)
Checks to see if a condition is true.
Definition: cond.c:53
const char * faction_name(int f)
Gets a factions "real" (internal) name.
Definition: faction.c:304
int faction_get(const char *name)
Gets a faction ID by name.
Definition: faction.c:182
void hook_rmMisnParent(unsigned int parent)
Removes all hooks belonging to parent mission.
Definition: hook.c:809
int landed
Definition: land.c:74
int mission_accept(Mission *mission)
Small wrapper for misn_run.
Definition: mission.c:199
int missions_saveTempCommodity(xmlTextWriterPtr writer, const Commodity *c)
Saves a temporary commodity's defintion into the current node.
Definition: mission.c:1284
Mission ** player_missions
Definition: mission.c:47
static int mission_markerLoad(Mission *misn, xmlNodePtr node)
Loads a mission marker from xml.
Definition: mission.c:447
const StarSystem * mission_getSystemMarker(const Mission *misn)
Gets the first system that has been marked by a mission.
Definition: mission.c:594
Mission * missions_genList(int *n, int faction, const Spob *pnt, const StarSystem *sys, MissionAvailability loc)
Generates a mission list. This runs create() so won't work with all missions.
Definition: mission.c:846
void mission_cleanup(Mission *misn)
Cleans up a mission.
Definition: mission.c:677
int mission_addMarker(Mission *misn, int id, int objid, MissionMarkerType type)
Adds a system marker to a mission.
Definition: mission.c:487
const StarSystem * mission_sysComputerMark(const Mission *misn)
Marks the system of the computer mission to reflect where it will head to.
Definition: mission.c:541
const MissionData * mission_getFromName(const char *name)
Gets mission data from a name.
Definition: mission.c:123
void missions_free(void)
Frees all the mission data.
Definition: mission.c:1160
int mission_alreadyRunning(const MissionData *misn)
Checks to see if mission is already running.
Definition: mission.c:210
static int mission_matchFaction(const MissionData *misn, int faction)
Checks to see if a mission matches the faction requirements.
Definition: mission.c:782
int mission_linkCargo(Mission *misn, unsigned int cargo_id)
Links cargo to the mission for posterior cleanup.
Definition: mission.c:639
void missions_activateClaims(void)
Activates mission claims.
Definition: mission.c:799
void mission_sysMark(void)
Marks all active systems that need marking.
Definition: mission.c:516
static const char * mission_markerTarget(MissionMarker *m)
Gets the name of the mission marker target.
Definition: mission.c:363
void missions_run(MissionAvailability loc, int faction, const Spob *pnt, const StarSystem *sys)
Runs missions matching location, all Lua side and one-shot.
Definition: mission.c:301
static MissionData * mission_stack
Definition: mission.c:52
int missions_loadActive(xmlNodePtr parent)
Loads the player's active missions from a save.
Definition: mission.c:1376
static int mission_parseFile(const char *file, MissionData *temp)
Parses a single mission.
Definition: mission.c:1084
static int mission_parseXML(MissionData *temp, const xmlNodePtr parent)
Parses a node of a mission.
Definition: mission.c:933
static int missions_parseActive(xmlNodePtr parent)
Parses the actual individual mission nodes.
Definition: mission.c:1403
void mission_shift(int pos)
Puts the specified mission at the end of the player_missions array.
Definition: mission.c:729
int missions_load(void)
Loads all the mission data.
Definition: mission.c:1041
static int missions_cmp(const void *a, const void *b)
Ordering function for missions.
Definition: mission.c:1024
Commodity * missions_loadTempCommodity(xmlNodePtr cur)
Loads a temporary commodity.
Definition: mission.c:1329
static int mission_meetReq(const MissionData *misn, int faction, const Spob *pnt, const StarSystem *sys)
Checks to see if a mission meets the requirements.
Definition: mission.c:228
int mission_start(const char *name, unsigned int *id)
Starts a mission.
Definition: mission.c:338
int mission_getID(const char *name)
Gets id from mission name.
Definition: mission.c:98
int missions_saveActive(xmlTextWriterPtr writer)
Saves the player's active missions.
Definition: mission.c:1194
static int mission_compare(const void *arg1, const void *arg2)
Compares to missions to see which has more priority.
Definition: mission.c:809
static unsigned int mission_genID(void)
Generates a new id for the mission.
Definition: mission.c:82
static unsigned int mission_id
Definition: mission.c:46
#define XML_MISSION_TAG
Definition: mission.c:41
static void mission_freeData(MissionData *mission)
Frees MissionData.
Definition: mission.c:752
static int mission_location(const char *loc)
Gets location based on a human readable string.
Definition: mission.c:909
static int mission_init(Mission *mission, const MissionData *misn, int genid, int create, unsigned int *id)
Initializes a mission.
Definition: mission.c:142
int mission_unlinkCargo(Mission *misn, unsigned int cargo_id)
Unlinks cargo from the mission, removes it from the player.
Definition: mission.c:654
int missions_loadCommodity(xmlNodePtr parent)
Loads the player's special mission commodities.
Definition: mission.c:1299
void missions_cleanup(void)
Cleans up all the player's active missions.
Definition: mission.c:1179
const MissionData * mission_get(int id)
Gets a MissionData based on ID.
Definition: mission.c:114
int naev_isQuit(void)
Get if Naev is trying to quit.
Definition: naev.c:155
Header file with generic functions and naev-specifics.
#define MAX(x, y)
Definition: naev.h:39
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
Definition: ndata.c:154
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition: ndata.c:232
static char buf[NEWS_MAX_LENGTH]
Definition: news.c:45
int misn_loadLibs(nlua_env env)
Registers all the mission libraries.
Definition: nlua_misn.c:115
int misn_run(Mission *misn, const char *func)
Runs a mission function.
Definition: nlua_misn.c:169
void npc_patchMission(Mission *misn)
Patches a new mission bar npc into the bar system.
Definition: npc.c:419
int npc_rm_parentMission(unsigned int mid)
Removes all the npc belonging to a mission.
Definition: npc.c:301
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:368
int nxml_unpersistLua(nlua_env env, xmlNodePtr parent)
Unpersists Lua data into a table named "mem".
Definition: nxml_lua.c:521
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition: opengl_tex.c:755
int pilot_rmMissionCargo(Pilot *pilot, unsigned int cargo_id, int jettison)
Removes special mission cargo based on id.
Definition: pilot_cargo.c:264
int player_missionAlreadyDone(int id)
Checks to see if player has already completed a mission.
Definition: player.c:2927
Player_t player
Definition: player.c:73
PilotCommodity * pfleet_cargoList(void)
Gets a list of all the cargo in the fleet.
Definition: player_fleet.c:373
static const double c[]
Definition: rng.c:264
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
Definition: space.c:1006
StarSystem * system_getIndex(int id)
Get the system by its index.
Definition: space.c:944
int spob_index(const Spob *p)
Gets the ID of a spob.
Definition: space.c:1055
StarSystem * system_get(const char *sysname)
Get the system from its name.
Definition: space.c:914
char * spob_getSystem(const char *spobname)
Get the name of a system from a spobname.
Definition: space.c:980
int space_addMarker(int objid, MissionMarkerType type)
Adds a marker to a system.
Definition: space.c:3743
void space_clearMarkers(void)
Clears all system markers.
Definition: space.c:3652
Spob * spob_getIndex(int ind)
Gets spob by index.
Definition: space.c:1038
void space_clearComputerMarkers(void)
Clears all the system computer markers.
Definition: space.c:3672
int system_index(const StarSystem *sys)
Gets the index of a star system.
Definition: space.c:955
Represents a commodity.
Definition: commodity.h:43
MissionAvailability loc
Definition: mission.h:38
char * chapter
Definition: mission.h:44
int * factions
Definition: mission.h:48
int priority
Definition: mission.h:53
char * done
Definition: mission.h:51
char * spob
Definition: mission.h:42
char * system
Definition: mission.h:43
pcre2_code * chapter_re
Definition: mission.h:45
char * cond
Definition: mission.h:50
Static mission data.
Definition: mission.h:61
char * name
Definition: mission.h:62
MissionAvail_t avail
Definition: mission.h:64
char * lua
Definition: mission.h:67
char ** tags
Definition: mission.h:71
char * sourcefile
Definition: mission.h:68
Mission system marker.
MissionMarkerType type
Represents an active mission.
Definition: mission.h:79
Claim_t * claims
Definition: mission.h:103
unsigned int osd
Definition: mission.h:99
char * npc_desc
Definition: mission.h:90
unsigned int * cargo
Definition: mission.h:93
unsigned int id
Definition: mission.h:81
glTexture * portrait
Definition: mission.h:88
nlua_env env
Definition: mission.h:105
char * reward
Definition: mission.h:86
char * desc
Definition: mission.h:85
MissionMarker * markers
Definition: mission.h:96
char * title
Definition: mission.h:84
const MissionData * data
Definition: mission.h:80
int accepted
Definition: mission.h:82
char * npc
Definition: mission.h:89
Stores a pilot commodity.
Definition: pilot.h:172
const Commodity * commodity
Definition: pilot.h:173
int devmode
Definition: conf.h:158
Pilot * p
Definition: player.h:101
char * chapter
Definition: player.h:116
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition: space.h:88
char * name
Definition: space.h:90