naev 0.11.5
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;
48static char **player_missions_failed = NULL;
50/*
51 * mission stack
52 */
53static MissionData *mission_stack = NULL;
55/*
56 * prototypes
57 */
58/* static */
59/* Generation. */
60static unsigned int mission_genID (void);
61static int mission_init( Mission* mission, const MissionData* misn, int genid, int create, unsigned int *id );
62static void mission_freeData( MissionData* mission );
63/* Matching. */
64static int mission_compare( const void* arg1, const void* arg2 );
65static int mission_meetConditionals( const MissionData *misn );
66static int mission_meetReq( const MissionData *misn, int faction,
67 const Spob *pnt, const StarSystem *sys );
68static int mission_matchFaction( const MissionData* misn, int faction );
69static int mission_location( const char *loc );
70/* Loading. */
71static int missions_cmp( const void *a, const void *b );
72static int mission_parseFile( const char* file, MissionData *temp );
73static int mission_parseXML( MissionData *temp, const xmlNodePtr parent );
74static int missions_parseActive( xmlNodePtr parent );
75/* Misc. */
76static const char* mission_markerTarget( const MissionMarker *m );
77static int mission_markerLoad( Mission *misn, xmlNodePtr node );
78
84static unsigned int mission_genID (void)
85{
86 unsigned int id = ++mission_id; /* default id, not safe if loading */
87 /* we save mission ids, so check for collisions with player's missions */
88 for (int i=0; i<array_size(player_missions); i++)
89 if (id == player_missions[i]->id) /* mission id was loaded from save */
90 return mission_genID(); /* recursively try again */
91 return id;
92}
93
100int mission_getID( const char* name )
101{
102 for (int i=0; i<array_size(mission_stack); i++)
103 if (strcmp(name,mission_stack[i].name)==0)
104 return i;
105
106 WARN(_("Mission '%s' not found in stack"), name);
107 return -1;
108}
109
116const MissionData* mission_get( int id )
117{
118 if ((id < 0) || (id >= array_size(mission_stack))) return NULL;
119 return &mission_stack[id];
120}
121
125const MissionData* mission_getFromName( const char* name )
126{
127 int id = mission_getID( name );
128 if (id < 0)
129 return NULL;
130
131 return mission_get( id );
132}
133
144static int mission_init( Mission* mission, const MissionData* misn, int genid, int create, unsigned int *id )
145{
146 if (misn->chunk == LUA_NOREF) {
147 WARN(_("Trying to initialize mission '%s' that has no loaded Lua chunk!"), misn->name);
148 return -1;
149 }
150
151 /* clear the mission */
152 memset( mission, 0, sizeof(Mission) );
153 mission->env = LUA_NOREF;
154
155 /* Create id if needed. */
156 mission->id = (genid) ? mission_genID() : 0;
157
158 if (id != NULL)
159 *id = mission->id;
160 mission->data = misn;
161 if (create) {
162 mission->title = strdup(_(misn->name));
163 mission->desc = strdup(_("No description."));
164 }
165
166 /* init Lua */
167 mission->env = nlua_newEnv();
168
169 misn_loadLibs( mission->env ); /* load our custom libraries */
170
171 /* Create the "mem" table for persistence. */
172 lua_newtable(naevL);
173 nlua_setenv(naevL, mission->env, "mem");
174
175 /* load the file */
176 if (nlua_dochunkenv(mission->env, misn->chunk, misn->sourcefile) != 0) {
177 WARN(_("Error loading mission file: %s\n"
178 "%s\n"
179 "Most likely Lua file has improper syntax, please check"),
180 misn->sourcefile, lua_tostring(naevL, -1));
181 return -1;
182 }
183
184 /* run create function */
185 if (create) {
186 /* Failed to create. */
187 int ret = misn_run( mission, "create");
188 if (ret) {
189 mission_cleanup(mission);
190 return ret;
191 }
192 }
193
194 return 0;
195}
196
206int mission_accept( Mission* mission )
207{
208 return misn_run( mission, "accept" );
209}
210
215{
216 return mission_stack;
217}
218
226{
227 int n = 0;
228 for (int i=0; i<array_size(player_missions); i++)
229 if (player_missions[i]->data == misn)
230 n++;
231 return n;
232}
233
234static int mission_meetConditionals( const MissionData *misn )
235{
236 /* If chapter, must match chapter. */
237 if (misn->avail.chapter_re != NULL) {
238 pcre2_match_data *match_data = pcre2_match_data_create_from_pattern( misn->avail.chapter_re, NULL );
239 int rc = pcre2_match( misn->avail.chapter_re, (PCRE2_SPTR)player.chapter, strlen(player.chapter), 0, 0, match_data, NULL );
240 pcre2_match_data_free( match_data );
241 if (rc < 0) {
242 switch (rc) {
243 case PCRE2_ERROR_NOMATCH:
244 return -1;
245 default:
246 WARN(_("Matching error %d"), rc );
247 break;
248 }
249 }
250 else if (rc == 0)
251 return 1;
252 }
253
254 /* Must not be already done or running if unique. */
255 if (mis_isFlag(misn,MISSION_UNIQUE) &&
258 return 1;
259
260 /* Must meet Lua condition. */
261 if (misn->avail.cond != NULL) {
262 int c = cond_checkChunk( misn->avail.cond_chunk, misn->avail.cond );
263 if (c < 0) {
264 WARN(_("Conditional for mission '%s' failed to run"), misn->name);
265 return 1;
266 }
267 else if (!c)
268 return 1;
269 }
270
271 /* Must meet previous mission requirements. */
272 if ((misn->avail.done != NULL) &&
274 return 1;
275
276 return 0;
277}
278
288static int mission_meetReq( const MissionData *misn, int faction,
289 const Spob *pnt, const StarSystem *sys )
290{
291 if (misn == NULL) /* In case it doesn't exist */
292 return 0;
293
294 /* If spob, must match spob. */
295 if (misn->avail.spob != NULL) {
296 if ((pnt==NULL) || strcmp(misn->avail.spob,pnt->name)!=0)
297 return 0;
298 }
299 else if (spob_isFlag(pnt, SPOB_NOMISNSPAWN))
300 return 0;
301
302 /* If system, must match system. */
303 if ((misn->avail.system != NULL) && (sys==NULL || (strcmp(misn->avail.system,sys->name)!=0)))
304 return 0;
305
306 /* Match faction. */
307 if ((faction >= 0) && !mission_matchFaction(misn,faction))
308 return 0;
309
310 return !mission_meetConditionals( misn );
311}
312
321void missions_run( MissionAvailability loc, int faction, const Spob *pnt, const StarSystem *sys )
322{
323 for (int i=0; i<array_size(mission_stack); i++) {
324 Mission mission;
325 double chance;
326 MissionData *misn = &mission_stack[i];
327
328 if (naev_isQuit())
329 return;
330
331 if (misn->avail.loc != loc)
332 continue;
333
334 if (!mission_meetReq( misn, faction, pnt, sys ))
335 continue;
336
337 chance = (double)(misn->avail.chance % 100)/100.;
338 if (chance == 0.) /* We want to consider 100 -> 100% not 0% */
339 chance = 1.;
340
341 if (RNGF() < chance) {
342 mission_init( &mission, misn, 1, 1, NULL );
343 mission_cleanup(&mission); /* it better clean up for itself or we do it */
344 }
345 }
346}
347
358int mission_start( const char *name, unsigned int *id )
359{
360 Mission mission;
361 const MissionData *mdat;
362 int ret;
363
364 /* Try to get the mission. */
365 mdat = mission_get( mission_getID(name) );
366 if (mdat == NULL)
367 return -1;
368
369 /* Try to run the mission. */
370 ret = mission_init( &mission, mdat, 1, 1, id );
371 /* Add to mission giver if necessary. */
372 if (landed && (ret==0) && (mdat->avail.loc==MIS_AVAIL_BAR))
373 npc_patchMission( &mission );
374 else
375 mission_cleanup( &mission ); /* Clean up in case not accepted. */
376
377 return ret;
378}
379
386int mission_test( const char *name )
387{
388 const MissionData *mdat;
389
390 /* Try to get the mission. */
391 mdat = mission_get( mission_getID(name) );
392 if (mdat == NULL)
393 return -1;
394
395 return mission_meetConditionals( mdat );
396}
397
398const char *mission_availabilityStr( MissionAvailability loc )
399{
400 switch (loc) {
401 case MIS_AVAIL_UNSET:
402 return "unset";
403 case MIS_AVAIL_NONE:
404 return "none";
405 case MIS_AVAIL_COMPUTER:
406 return "computer";
407 case MIS_AVAIL_BAR:
408 return "bar";
409 case MIS_AVAIL_LAND:
410 return "land";
411 case MIS_AVAIL_ENTER:
412 return "enter";
413 }
414 return NULL;
415}
416
420static const char* mission_markerTarget( const MissionMarker *m )
421{
422 switch (m->type) {
423 case SYSMARKER_COMPUTER:
424 case SYSMARKER_LOW:
425 case SYSMARKER_HIGH:
426 case SYSMARKER_PLOT:
427 return system_getIndex( m->objid )->name;
428 case SPOBMARKER_COMPUTER:
429 case SPOBMARKER_LOW:
430 case SPOBMARKER_HIGH:
431 case SPOBMARKER_PLOT:
432 return spob_getIndex( m->objid )->name;
433 default:
434 WARN(_("Unknown marker type."));
435 return NULL;
436 }
437}
438
439MissionMarkerType mission_markerTypeSpobToSystem( MissionMarkerType t )
440{
441 switch (t) {
442 case SYSMARKER_COMPUTER:
443 case SYSMARKER_LOW:
444 case SYSMARKER_HIGH:
445 case SYSMARKER_PLOT:
446 return t;
447 case SPOBMARKER_COMPUTER:
448 return SYSMARKER_COMPUTER;
449 case SPOBMARKER_LOW:
450 return SYSMARKER_LOW;
451 case SPOBMARKER_HIGH:
452 return SYSMARKER_HIGH;
453 case SPOBMARKER_PLOT:
454 return SYSMARKER_PLOT;
455 default:
456 WARN(_("Unknown marker type."));
457 return -1;
458 }
459}
460
461MissionMarkerType mission_markerTypeSystemToSpob( MissionMarkerType t )
462{
463 switch (t) {
464 case SYSMARKER_COMPUTER:
465 return SPOBMARKER_COMPUTER;
466 case SYSMARKER_LOW:
467 return SPOBMARKER_LOW;
468 case SYSMARKER_HIGH:
469 return SPOBMARKER_HIGH;
470 case SYSMARKER_PLOT:
471 return SPOBMARKER_PLOT;
472 case SPOBMARKER_COMPUTER:
473 case SPOBMARKER_LOW:
474 case SPOBMARKER_HIGH:
475 case SPOBMARKER_PLOT:
476 return t;
477 default:
478 WARN(_("Unknown marker type."));
479 return -1;
480 }
481}
482
483void mission_toLuaTable( lua_State *L , const MissionData *m )
484{
485 lua_newtable(L);
486
487 lua_pushstring(L, m->name);
488 lua_setfield(L,-2,"name");
489
490 lua_pushboolean(L,mis_isFlag(m,MISSION_UNIQUE));
491 lua_setfield(L,-2,"unique");
492
493 lua_newtable(L);
494 for (int j=0; j<array_size(m->tags); j++) {
495 lua_pushboolean(L,1);
496 lua_setfield(L,-2,m->tags[j]);
497 }
498 lua_setfield(L,-2,"tags");
499}
500
501const char **mission_loadFailed (void)
502{
503 return (const char**) player_missions_failed;
504}
505
509static int mission_markerLoad( Mission *misn, xmlNodePtr node )
510{
511 int id;
512 MissionMarkerType type;
513 StarSystem *ssys;
514 Spob *pnt;
515
516 xmlr_attr_int_def( node, "id", id, -1 );
517 xmlr_attr_int_def( node, "type", type, -1 );
518
519 switch (type) {
520 case SYSMARKER_COMPUTER:
521 case SYSMARKER_LOW:
522 case SYSMARKER_HIGH:
523 case SYSMARKER_PLOT:
524 ssys = system_get( xml_get( node ));
525 if (ssys == NULL) {
526 WARN( _("Mission Marker to system '%s' does not exist"), xml_get( node ) );
527 return -1;
528 }
529 return mission_addMarker( misn, id, system_index(ssys), type );
530 case SPOBMARKER_COMPUTER:
531 case SPOBMARKER_LOW:
532 case SPOBMARKER_HIGH:
533 case SPOBMARKER_PLOT:
534 pnt = spob_get( xml_get( node ));
535 if (pnt == NULL) {
536 WARN( _("Mission Marker to spob '%s' does not exist"), xml_get( node ) );
537 return -1;
538 }
539 return mission_addMarker( misn, id, spob_index(pnt), type );
540 default:
541 WARN(_("Unknown marker type."));
542 return -1;
543 }
544}
545
549int mission_addMarker( Mission *misn, int id, int objid, MissionMarkerType type )
550{
551 MissionMarker *marker;
552
553 /* Create array. */
554 if (misn->markers == NULL)
556
557 /* Avoid ID collisions. */
558 if (id < 0) {
559 int m = -1;
560 for (int i=0; i<array_size(misn->markers); i++)
561 if (misn->markers[i].id > m)
562 m = misn->markers[i].id;
563 id = m+1;
564 }
565
566 /* Create the marker. */
567 marker = &array_grow( &misn->markers );
568 marker->id = id;
569 marker->objid = objid;
570 marker->type = type;
571
572 return marker->id;
573}
574
579{
580 /* Clear markers. */
582 for (int i=0; i<array_size(player_missions); i++) {
583 /* Must be a valid player mission. */
584 if (player_missions[i]->id == 0)
585 continue;
586
587 for (int j=0; j<array_size(player_missions[i]->markers); j++) {
588 const MissionMarker *m = &player_missions[i]->markers[j];
589
590 /* Add the individual markers. */
591 space_addMarker( m->objid, m->type );
592 }
593 }
594}
595
603const StarSystem* mission_sysComputerMark( const Mission* misn )
604{
605 StarSystem *firstsys = NULL;
606
607 /* Clear markers. */
609
610 /* Set all the markers. */
611 for (int i=0; i<array_size(misn->markers); i++) {
612 StarSystem *sys;
613 Spob *pnt;
614 const char *sysname;
615 const MissionMarker *m = &misn->markers[i];
616
617 switch (m->type) {
618 case SYSMARKER_COMPUTER:
619 case SYSMARKER_LOW:
620 case SYSMARKER_HIGH:
621 case SYSMARKER_PLOT:
622 sys = system_getIndex( m->objid );
623 break;
624 case SPOBMARKER_COMPUTER:
625 case SPOBMARKER_LOW:
626 case SPOBMARKER_HIGH:
627 case SPOBMARKER_PLOT:
628 pnt = spob_getIndex( m->objid );
629 sysname = spob_getSystem( pnt->name );
630 if (sysname==NULL) {
631 WARN(_("Marked spob '%s' is not in any system!"), pnt->name);
632 continue;
633 }
634 sys = system_get( sysname );
635 break;
636 default:
637 WARN(_("Unknown marker type."));
638 continue;
639 }
640
641 if (sys != NULL)
642 sys_setFlag( sys, SYSTEM_CMARKED );
643
644 if (firstsys==NULL)
645 firstsys = sys;
646 }
647 return firstsys;
648}
649
656const StarSystem* mission_getSystemMarker( const Mission* misn )
657{
658 /* Set all the markers. */
659 for (int i=0; i<array_size(misn->markers); i++) {
660 StarSystem *sys;
661 Spob *pnt;
662 const char *sysname;
663 const MissionMarker *m = &misn->markers[i];;
664
665 switch (m->type) {
666 case SYSMARKER_COMPUTER:
667 case SYSMARKER_LOW:
668 case SYSMARKER_HIGH:
669 case SYSMARKER_PLOT:
670 sys = system_getIndex( m->objid );
671 break;
672 case SPOBMARKER_COMPUTER:
673 case SPOBMARKER_LOW:
674 case SPOBMARKER_HIGH:
675 case SPOBMARKER_PLOT:
676 pnt = spob_getIndex( m->objid );
677 sysname = spob_getSystem( pnt->name );
678 if (sysname==NULL) {
679 WARN(_("Marked spob '%s' is not in any system!"), pnt->name);
680 continue;
681 }
682 sys = system_get( sysname );
683 break;
684 default:
685 WARN(_("Unknown marker type."));
686 continue;
687 }
688
689 return sys;
690 }
691 return NULL;
692}
693
701int mission_linkCargo( Mission* misn, unsigned int cargo_id )
702{
703 if (misn->cargo == NULL)
704 misn->cargo = array_create( unsigned int );
705 array_push_back( &misn->cargo, cargo_id );
706 return 0;
707}
708
716int mission_unlinkCargo( Mission* misn, unsigned int cargo_id )
717{
718 int i;
719 for (i=0; i<array_size(misn->cargo); i++)
720 if (misn->cargo[i] == cargo_id)
721 break;
722
723 if (i>=array_size(misn->cargo)) { /* not found */
724 DEBUG(_("Mission '%s' attempting to unlink nonexistent cargo %d."),
725 misn->title, cargo_id);
726 return 1;
727 }
728
729 /* shrink cargo size. */
730 array_erase( &misn->cargo, &misn->cargo[i], &misn->cargo[i+1] );
731 return 0;
732}
733
740{
741 /* Hooks and missions. */
742 if (misn->id != 0) {
743 hook_rmMisnParent( misn->id ); /* remove existing hooks */
744 npc_rm_parentMission( misn->id ); /* remove existing npc */
745 }
746
747 /* Cargo. */
748 if ((player.p != NULL) && !pilot_isFlag(player.p, PILOT_DEAD)) { /* Only remove if player exists. */
749 for (int i=0; i<array_size(misn->cargo); i++) { /* must unlink all the cargo */
750 int ret = pilot_rmMissionCargo( player.p, misn->cargo[i], 0 );
751 if (ret)
752 WARN(_("Failed to remove mission cargo '%d' for mission '%s'."), misn->cargo[i], misn->title);
753 }
754 }
755 array_free(misn->cargo);
756 if (misn->osd > 0)
757 osd_destroy(misn->osd);
758 /*
759 * XXX With the way the mission code works, this function is called on a
760 * Mission struct of all zeros. Looking at the implementation, luaL_ref()
761 * never returns 0, but this is probably undefined behavior.
762 */
763 if (misn->env != LUA_NOREF)
764 nlua_freeEnv(misn->env);
765
766 /* Data. */
767 free(misn->title);
768 free(misn->desc);
769 free(misn->reward);
771 free(misn->npc);
772 free(misn->npc_desc);
773
774 /* Markers. */
775 array_free( misn->markers );
776
777 /* Claims. */
778 if (misn->claims != NULL)
779 claim_destroy( misn->claims );
780
781 /* Clear the memory. */
782 memset( misn, 0, sizeof(Mission) );
783 misn->env = LUA_NOREF;
784}
785
791void mission_shift( int pos )
792{
793 Mission *misn;
794
795 if (pos >= (array_size(player_missions)-1))
796 return;
797
798 /* Store specified mission. */
799 misn = player_missions[pos];
800
801 /* Move other missions down. */
802 memmove( &player_missions[pos], &player_missions[pos+1],
803 sizeof(Mission*) * (array_size(player_missions) - pos - 1) );
804
805 /* Put the specified mission at the end of the array. */
807}
808
814static void mission_freeData( MissionData* mission )
815{
816 free(mission->name);
817 free(mission->lua);
818 free(mission->sourcefile);
819 free(mission->avail.spob);
820 free(mission->avail.system);
821 free(mission->avail.chapter);
822 pcre2_code_free( mission->avail.chapter_re );
823 array_free(mission->avail.factions);
824 free(mission->avail.cond);
825 free(mission->avail.done);
826
827 if (mission->chunk != LUA_NOREF)
828 luaL_unref( naevL, LUA_REGISTRYINDEX, mission->chunk );
829
830 if (mission->avail.cond_chunk != LUA_NOREF)
831 luaL_unref( naevL, LUA_REGISTRYINDEX, mission->avail.cond_chunk );
832
833 for (int i=0; i<array_size(mission->tags); i++)
834 free(mission->tags[i]);
835 array_free(mission->tags);
836
837 /* Clear the memory. */
838#ifdef DEBUGGING
839 memset( mission, 0, sizeof(MissionData) );
840#endif /* DEBUGGING */
841}
842
850static int mission_matchFaction( const MissionData* misn, int faction )
851{
852 /* No faction always accepted. */
853 if (array_size(misn->avail.factions) == 0)
854 return 1;
855
856 /* Check factions. */
857 for (int i=0; i<array_size(misn->avail.factions); i++)
858 if (faction == misn->avail.factions[i])
859 return 1;
860
861 return 0;
862}
863
868{
869 for (int i=0; i<array_size(player_missions); i++)
870 if (player_missions[i]->claims != NULL)
871 claim_activate( player_missions[i]->claims );
872}
873
877static int mission_compare( const void* arg1, const void* arg2 )
878{
879 Mission *m1, *m2;
880
881 /* Get arguments. */
882 m1 = (Mission*) arg1;
883 m2 = (Mission*) arg2;
884
885 /* Check priority - lower is more important. */
886 if (m1->data->avail.priority < m2->data->avail.priority)
887 return -1;
888 else if (m1->data->avail.priority > m2->data->avail.priority)
889 return +1;
890
891 /* Compare NPC. */
892 if ((m1->npc != NULL) && (m2->npc != NULL))
893 return strcmp( m1->npc, m2->npc );
894
895 /* Compare title. */
896 if ((m1->title != NULL) && (m2->title != NULL))
897 return strcmp( m1->title, m2->title );
898
899 /* Tied. */
900 return strcmp(m1->data->name, m2->data->name);
901}
902
914Mission* missions_genList( int *n, int faction,
915 const Spob *pnt, const StarSystem *sys, MissionAvailability loc )
916{
917 int m, alloced;
918 int rep;
919 Mission* tmp;
920
921 /* Find available missions. */
922 tmp = NULL;
923 m = 0;
924 alloced = 0;
925 for (int i=0; i<array_size(mission_stack); i++) {
926 double chance;
927 MissionData *misn = &mission_stack[i];
928 if (misn->avail.loc != loc)
929 continue;
930
931 /* Must hit chance. */
932 chance = (double)(misn->avail.chance % 100)/100.;
933 if (chance == 0.) /* We want to consider 100 -> 100% not 0% */
934 chance = 1.;
935 rep = MAX(1, misn->avail.chance / 100);
936
937 /* random chance of rep appearances */
938 for (int j=0; j<rep; j++) {
939 if (RNGF() > chance)
940 continue;
941
942 /* Must meet requirements. */
943 if (!mission_meetReq( misn, faction, pnt, sys ))
944 continue;
945
946 m++;
947 /* Extra allocation. */
948 if (m > alloced) {
949 if (alloced == 0)
950 alloced = 32;
951 else
952 alloced *= 2;
953 tmp = realloc( tmp, sizeof(Mission) * alloced );
954 }
955 /* Initialize the mission. */
956 if (mission_init( &tmp[m-1], misn, 1, 1, NULL ))
957 m--;
958 }
959 }
960
961 /* Sort. */
962 if (tmp != NULL) {
963 qsort( tmp, m, sizeof(Mission), mission_compare );
964 (*n) = m;
965 }
966 else
967 (*n) = 0;
968
969 return tmp;
970}
971
978static int mission_location( const char *loc )
979{
980 if (loc != NULL) {
981 if (strcasecmp( loc, "None" ) == 0)
982 return MIS_AVAIL_NONE;
983 else if (strcasecmp( loc, "Computer" ) == 0)
984 return MIS_AVAIL_COMPUTER;
985 else if (strcasecmp( loc, "Bar" ) == 0)
986 return MIS_AVAIL_BAR;
987 else if (strcasecmp( loc, "Land" ) == 0)
988 return MIS_AVAIL_LAND;
989 else if (strcasecmp( loc, "Enter" ) == 0)
990 return MIS_AVAIL_ENTER;
991 }
992 return -1;
993}
994
1002static int mission_parseXML( MissionData *temp, const xmlNodePtr parent )
1003{
1004 xmlNodePtr node;
1005
1006 /* Clear memory. */
1007 memset( temp, 0, sizeof(MissionData) );
1008
1009 /* Defaults. */
1010 temp->chunk = LUA_NOREF;
1011 temp->avail.priority = 5;
1012 temp->avail.loc = MIS_AVAIL_UNSET;
1013 temp->avail.cond_chunk = LUA_NOREF;
1014
1015 /* get the name */
1016 xmlr_attr_strd(parent,"name",temp->name);
1017 if (temp->name == NULL)
1018 WARN( _("Mission in %s has invalid or no name"), MISSION_DATA_PATH );
1019
1020 node = parent->xmlChildrenNode;
1021
1022 do { /* load all the data */
1023 /* Only handle nodes. */
1024 xml_onlyNodes(node);
1025
1026 if (xml_isNode(node,"unique")) { /* Unique mission. */
1027 mis_setFlag(temp,MISSION_UNIQUE);
1028 continue;
1029 }
1030 if (xml_isNode(node,"location")) {
1031 temp->avail.loc = mission_location( xml_get(node) );
1032 if (temp->avail.loc < 0)
1033 WARN(_("Mission '%s' has unknown location '%s'!"), temp->name, xml_get(node) );
1034 continue;
1035 }
1036 xmlr_int(node,"chance",temp->avail.chance);
1037 xmlr_strd(node,"spob",temp->avail.spob);
1038 xmlr_strd(node,"system",temp->avail.system);
1039 xmlr_strd(node,"chapter",temp->avail.chapter);
1040 if (xml_isNode(node,"faction")) {
1041 if (temp->avail.factions == NULL)
1042 temp->avail.factions = array_create( int );
1043 array_push_back( &temp->avail.factions, faction_get( xml_get(node) ) );
1044 continue;
1045 }
1046 xmlr_strd(node,"cond",temp->avail.cond);
1047 xmlr_strd(node,"done",temp->avail.done);
1048 xmlr_int(node,"priority",temp->avail.priority);
1049
1050 if (xml_isNode(node,"tags")) {
1051 xmlNodePtr cur = node->children;
1052 temp->tags = array_create( char* );
1053 do {
1054 xml_onlyNodes(cur);
1055 if (xml_isNode(cur, "tag")) {
1056 const char *tmp = xml_get(cur);
1057 if (tmp != NULL)
1058 array_push_back( &temp->tags, strdup(tmp) );
1059 continue;
1060 }
1061 WARN(_("Mission '%s' has unknown node in tags '%s'."), temp->name, cur->name );
1062 } while (xml_nextNode(cur));
1063 continue;
1064 }
1065 else if (xml_isNode(node,"notes")) continue; /* Notes for the python mission mapping script */
1066
1067 WARN(_("Unknown node '%s' in mission '%s'"),node->name,temp->name);
1068 } while (xml_nextNode(node));
1069
1070 /* Compile conditional chunk. */
1071 if (temp->avail.cond != NULL) {
1072 temp->avail.cond_chunk = cond_compile( temp->avail.cond );
1073 if (temp->avail.cond_chunk == LUA_NOREF || temp->avail.cond_chunk == LUA_REFNIL)
1074 WARN(_("Mission '%s' failed to compile Lua conditional!"), temp->name);
1075 }
1076
1077 /* Compile regex for chapter matching. */
1078 if (temp->avail.chapter != NULL) {
1079 int errornumber;
1080 PCRE2_SIZE erroroffset;
1081 temp->avail.chapter_re = pcre2_compile( (PCRE2_SPTR)temp->avail.chapter, PCRE2_ZERO_TERMINATED, 0, &errornumber, &erroroffset, NULL );
1082 if (temp->avail.chapter_re == NULL) {
1083 PCRE2_UCHAR buffer[256];
1084 pcre2_get_error_message( errornumber, buffer, sizeof(buffer) );
1085 WARN(_("Mission '%s' chapter PCRE2 compilation failed at offset %d: %s"), temp->name, (int)erroroffset, buffer );
1086 }
1087 }
1088
1089#define MELEMENT(o,s) \
1090 if (o) WARN( _("Mission '%s' missing/invalid '%s' element"), temp->name, s)
1091 MELEMENT(temp->avail.loc==MIS_AVAIL_UNSET,"location");
1092 MELEMENT((temp->avail.loc!=MIS_AVAIL_NONE) && (temp->avail.chance==0),"chance");
1093 MELEMENT( ((temp->avail.spob!=NULL) && spob_get(temp->avail.spob)==NULL), "spob" );
1094 MELEMENT( ((temp->avail.system!=NULL) && system_get(temp->avail.system)==NULL), "system" );
1095#undef MELEMENT
1096
1097 return 0;
1098}
1099
1103static int missions_cmp( const void *a, const void *b )
1104{
1105 const MissionData *ma, *mb;
1106 ma = (const MissionData*) a;
1107 mb = (const MissionData*) b;
1108 if (ma->avail.priority < mb->avail.priority)
1109 return -1;
1110 else if (ma->avail.priority > mb->avail.priority)
1111 return +1;
1112 return strcmp( ma->name, mb->name );
1113}
1114
1121{
1122#if DEBUGGING
1123 Uint32 time = SDL_GetTicks();
1124#endif /* DEBUGGING */
1125 char **mission_files;
1126
1127 /* Run over missions. */
1128 mission_files = ndata_listRecursive( MISSION_DATA_PATH );
1130 for (int i=0; i < array_size( mission_files ); i++) {
1131 mission_parseFile( mission_files[i], NULL );
1132 free( mission_files[i] );
1133 }
1134 array_free( mission_files );
1136
1137#ifdef DEBUGGING
1138 for (int i=0; i<array_size(mission_stack); i++) {
1139 MissionData *md = &mission_stack[i];
1140 for (int j=i+1; j<array_size(mission_stack); j++)
1141 if (strcmp( md->name, mission_stack[j].name )==0)
1142 WARN(_("Duplicate event '%s'!"), md->name);
1143 }
1144#endif /* DEBUGGING */
1145
1146 /* Sort based on priority so higher priority missions can establish claims first. */
1148
1149#if DEBUGGING
1150 if (conf.devmode) {
1151 time = SDL_GetTicks() - time;
1152 DEBUG( n_("Loaded %d Mission in %.3f s", "Loaded %d Missions in %.3f s", array_size(mission_stack) ), array_size(mission_stack), time/1000. );
1153 }
1154 else
1155 DEBUG( n_("Loaded %d Mission", "Loaded %d Missions", array_size(mission_stack) ), array_size(mission_stack) );
1156#endif /* DEBUGGING */
1157
1158 return 0;
1159}
1160
1167static int mission_parseFile( const char* file, MissionData *temp )
1168{
1169 xmlDocPtr doc;
1170 xmlNodePtr node;
1171 size_t bufsize;
1172 char *filebuf;
1173 const char *pos, *start_pos;
1174
1175 /* Load string. */
1176 filebuf = ndata_read( file, &bufsize );
1177 if (filebuf == NULL) {
1178 WARN(_("Unable to read data from '%s'"), file);
1179 return -1;
1180 }
1181 if (bufsize==0) {
1182 free( filebuf );
1183 return -1;
1184 }
1185
1186 /* Skip if no XML. */
1187 pos = strnstr( filebuf, "</mission>", bufsize );
1188 if (pos==NULL) {
1189 pos = strnstr( filebuf, "function create", bufsize );
1190 if ((pos != NULL) && !strncmp(pos,"--common",bufsize))
1191 WARN(_("Mission '%s' has create function but no XML header!"), file);
1192 free(filebuf);
1193 return -1;
1194 }
1195
1196 /* Separate XML header and Lua. */
1197 start_pos = strnstr( filebuf, "<?xml ", bufsize );
1198 pos = strnstr( filebuf, "--]]", bufsize );
1199 if (pos == NULL || start_pos == NULL) {
1200 WARN(_("Mission file '%s' has missing XML header!"), file);
1201 return -1;
1202 }
1203
1204 /* Parse the header. */
1205 doc = xmlParseMemory( start_pos, pos-start_pos);
1206 if (doc == NULL) {
1207 WARN(_("Unable to parse document XML header for Mission '%s'"), file);
1208 return -1;
1209 }
1210
1211 node = doc->xmlChildrenNode;
1212 if (!xml_isNode(node,XML_MISSION_TAG)) {
1213 ERR( _("Malformed XML header for '%s' mission: missing root element '%s'"), file, XML_MISSION_TAG );
1214 return -1;
1215 }
1216
1217 if (temp == NULL)
1218 temp = &array_grow(&mission_stack);
1219 mission_parseXML( temp, node );
1220 temp->lua = filebuf;
1221 temp->sourcefile = strdup(file);
1222
1223 /* Clear chunk if already loaded. */
1224 if (temp->chunk != LUA_NOREF) {
1225 luaL_unref( naevL, LUA_REGISTRYINDEX, temp->chunk );
1226 temp->chunk = LUA_NOREF;
1227 }
1228
1229 /* Load the chunk. */
1230 int ret = luaL_loadbuffer(naevL, temp->lua, strlen(temp->lua), temp->name );
1231 if (ret == LUA_ERRSYNTAX)
1232 WARN(_("Mission Lua '%s' syntax error: %s"), file, lua_tostring(naevL,-1) );
1233 else
1234 temp->chunk = luaL_ref( naevL, LUA_REGISTRYINDEX );
1235
1236 /* Clean up. */
1237 xmlFreeDoc(doc);
1238
1239 return 0;
1240}
1241
1245void missions_free (void)
1246{
1247 /* Free all the player missions. */
1249
1250 /* Free the mission data. */
1251 for (int i=0; i<array_size(mission_stack); i++)
1254 mission_stack = NULL;
1255
1256 /* Free the player mission stack. */
1258 player_missions = NULL;
1259
1260 /* Frees failed missions. */
1263}
1264
1280
1287int missions_saveActive( xmlTextWriterPtr writer )
1288{
1289 /* We also save specially created cargos here. */
1291 xmlw_startElem(writer,"temporary_cargo");
1292 for (int i=0; i<array_size(pcom); i++) {
1293 const Commodity *c = pcom[i].commodity;
1294 if (!c->istemp)
1295 continue;
1296 xmlw_startElem(writer,"cargo");
1297 missions_saveTempCommodity( writer, c );
1298 xmlw_endElem(writer); /* "cargo" */
1299 }
1300 xmlw_endElem(writer); /* "missions_cargo */
1301 array_free(pcom);
1302
1303 xmlw_startElem(writer,"missions");
1304 for (int i=0; i<array_size(player_missions); i++) {
1305 Mission *misn = player_missions[i];
1306 if (misn->id == 0)
1307 continue;
1308
1309 xmlw_startElem(writer,"mission");
1310
1311 /* data and id are attributes because they must be loaded first */
1312 xmlw_attr(writer,"data","%s",misn->data->name);
1313 xmlw_attr(writer,"id","%u",misn->id);
1314
1315 xmlw_elem(writer,"title","%s",misn->title);
1316 xmlw_elem(writer,"desc","%s",misn->desc);
1317 xmlw_elem(writer,"reward","%s",misn->reward);
1318 xmlw_elem(writer,"reward_value","%"CREDITS_PRI,misn->reward_value);
1319
1320 /* Markers. */
1321 xmlw_startElem( writer, "markers" );
1322 for (int j=0; j<array_size( misn->markers ); j++) {
1323 MissionMarker *m = &misn->markers[j];
1324 xmlw_startElem(writer,"marker");
1325 xmlw_attr(writer,"id","%d",m->id);
1326 xmlw_attr(writer,"type","%d",m->type);
1327 xmlw_str(writer,"%s", mission_markerTarget( m ));
1328 xmlw_endElem(writer); /* "marker" */
1329 }
1330 xmlw_endElem( writer ); /* "markers" */
1331
1332 /* Cargo */
1333 xmlw_startElem(writer,"cargos");
1334 for (int j=0; j<array_size(misn->cargo); j++)
1335 xmlw_elem(writer,"cargo","%u", misn->cargo[j]);
1336 xmlw_endElem(writer); /* "cargos" */
1337
1338 /* OSD. */
1339 if (misn->osd > 0) {
1340 int priority;
1341 char **items = osd_getItems(misn->osd);
1342
1343 xmlw_startElem(writer,"osd");
1344
1345 /* Save attributes. */
1346 xmlw_attr(writer,"title","%s",osd_getTitle(misn->osd));
1347 xmlw_attr(writer,"nitems","%d",array_size(items));
1348 xmlw_attr(writer,"active","%d",osd_getActive(misn->osd));
1349 xmlw_attr(writer,"hidden","%d",osd_getHide(misn->osd));
1350 priority = osd_getPriority(misn->osd);
1351 if (priority != misn->data->avail.priority)
1352 xmlw_attr(writer,"priority","%d",osd_getPriority(misn->osd));
1353
1354 /* Save messages. */
1355 for (int j=0; j<array_size(items); j++)
1356 xmlw_elem(writer,"msg","%s",items[j]);
1357
1358 xmlw_endElem(writer); /* "osd" */
1359 }
1360
1361 /* Claims. */
1362 xmlw_startElem(writer,"claims");
1363 claim_xmlSave( writer, misn->claims );
1364 xmlw_endElem(writer); /* "claims" */
1365
1366 /* Write Lua magic */
1367 xmlw_startElem(writer,"lua");
1368 nxml_persistLua( misn->env, writer );
1369 xmlw_endElem(writer); /* "lua" */
1370
1371 xmlw_endElem(writer); /* "mission" */
1372 }
1373 xmlw_endElem(writer); /* "missions" */
1374
1375 return 0;
1376}
1377
1385int missions_saveTempCommodity( xmlTextWriterPtr writer, const Commodity *c )
1386{
1387 xmlw_attr( writer, "name", "%s", c->name );
1388 xmlw_attr( writer, "description", "%s", c->description );
1389 for (int j=0; j < array_size( c->illegalto ); j++)
1390 xmlw_elem( writer, "illegalto", "%s", faction_name( c->illegalto[ j ] ) );
1391 return 0;
1392}
1393
1400int missions_loadCommodity( xmlNodePtr parent )
1401{
1402 xmlNodePtr node;
1403
1404 /* We have to ensure the temporary_cargo stuff is loaded first. */
1405 node = parent->xmlChildrenNode;
1406 do {
1407 xml_onlyNodes(node);
1408
1409 /* TODO remove support for "mission_cargo" in the future (maybe 0.12.0?). 0.10.0 onwards uses "temporary_cargo" */
1410 if (xml_isNode(node,"temporary_cargo") || xml_isNode(node,"mission_cargo")) {
1411 xmlNodePtr cur = node->xmlChildrenNode;
1412 do {
1413 xml_onlyNodes(cur);
1414 if (xml_isNode( cur, "cargo" ))
1415 (void)missions_loadTempCommodity( cur );
1416 } while (xml_nextNode( cur ));
1417 continue;
1418 }
1419 } while (xml_nextNode( node ));
1420
1421 return 0;
1422}
1423
1431{
1432 xmlNodePtr ccur;
1433 char * name, *desc;
1434 Commodity *c;
1435
1436 xmlr_attr_strd( cur, "name", name );
1437 if ( name == NULL ) {
1438 WARN( _( "Mission cargo without name!" ) );
1439 return NULL;
1440 }
1441
1442 c = commodity_getW( name );
1443 if ( c != NULL ) {
1444 free( name );
1445 return c;
1446 }
1447
1448 xmlr_attr_strd( cur, "description", desc );
1449 if ( desc == NULL ) {
1450 WARN( _( "Mission temporary cargo '%s' missing description!" ), name );
1451 free( name );
1452 return NULL;
1453 }
1454
1455 c = commodity_newTemp( name, desc );
1456
1457 ccur = cur->xmlChildrenNode;
1458 do {
1459 xml_onlyNodes( ccur );
1460 if ( xml_isNode( ccur, "illegalto" ) ) {
1461 int f = faction_get( xml_get( ccur ) );
1463 }
1464 } while ( xml_nextNode( ccur ) );
1465
1466 free( name );
1467 free( desc );
1468 return c;
1469}
1470
1477int missions_loadActive( xmlNodePtr parent )
1478{
1479 xmlNodePtr node;
1480
1481 /* cleanup old missions */
1483
1484 /* After load the normal missions. */
1485 node = parent->xmlChildrenNode;
1486 do {
1487 xml_onlyNodes(node);
1488 if (xml_isNode(node,"missions")) {
1489 if (missions_parseActive( node ) < 0)
1490 return -1;
1491 continue;
1492 }
1493 } while (xml_nextNode(node));
1494
1495 return 0;
1496}
1497
1504static int missions_parseActive( xmlNodePtr parent )
1505{
1506 char *buf;
1507 char *title;
1508 const char **items;
1509 int nitems, active;
1510 xmlNodePtr node;
1511 int failed = 0;
1512
1513 if (player_missions == NULL)
1515
1516 if (player_missions_failed == NULL)
1518
1519 node = parent->xmlChildrenNode;
1520 do {
1521 if (xml_isNode(node, "mission")) {
1522 xmlNodePtr cur;
1523 const MissionData *data;
1524 int misn_failed = 0;
1525 Mission *misn = calloc( 1, sizeof(Mission) );
1526
1527 /* process the attributes to create the mission */
1528 xmlr_attr_strd(node, "data", buf);
1529 data = mission_get( mission_getID(buf) );
1530 if (data == NULL) {
1531 WARN(_("Mission '%s' from saved game not found in game - ignoring."), buf);
1532 array_push_back( &player_missions_failed, strdup(buf) );
1533 free(buf);
1534 continue;
1535 }
1536 else {
1537 if (mission_init( misn, data, 0, 0, NULL )) {
1538 WARN(_("Mission '%s' from saved game failed to load properly - ignoring."), buf);
1539 array_push_back( &player_missions_failed, strdup(buf) );
1540 free(buf);
1541 continue;
1542 }
1543 misn->accepted = 1;
1544 }
1545 free(buf);
1546
1547 /* this will orphan an identifier */
1548 xmlr_attr_int(node, "id", misn->id);
1549
1550 cur = node->xmlChildrenNode;
1551 do {
1552 xmlr_strd(cur,"title",misn->title);
1553 xmlr_strd(cur,"desc",misn->desc);
1554 xmlr_strd(cur,"reward",misn->reward);
1555 xmlr_ulong(cur,"reward_value",misn->reward_value);
1556
1557 /* Get the markers. */
1558 if (xml_isNode(cur,"markers")) {
1559 xmlNodePtr nest = cur->xmlChildrenNode;
1560 do {
1561 if (xml_isNode(nest,"marker"))
1562 mission_markerLoad( misn, nest );
1563 } while (xml_nextNode(nest));
1564 }
1565
1566 /* Cargo. */
1567 if (xml_isNode(cur,"cargos")) {
1568 xmlNodePtr nest = cur->xmlChildrenNode;
1569 do {
1570 if (xml_isNode(nest,"cargo"))
1571 mission_linkCargo( misn, xml_getLong(nest) );
1572 } while (xml_nextNode(nest));
1573 }
1574
1575 /* OSD. */
1576 if (xml_isNode(cur,"osd")) {
1577 int hidden, priority;
1578 xmlNodePtr nest;
1579 int i = 0;
1580 xmlr_attr_int_def( cur, "nitems", nitems, -1 );
1581 if (nitems == -1)
1582 continue;
1583 xmlr_attr_strd(cur,"title",title);
1584 items = malloc( nitems * sizeof(char*) );
1585 nest = cur->xmlChildrenNode;
1586 do {
1587 if (xml_isNode(nest,"msg")) {
1588 if (i > nitems) {
1589 WARN(_("Inconsistency with 'nitems' in save file."));
1590 break;
1591 }
1592 items[i] = xml_get(nest);
1593 i++;
1594 }
1595 } while (xml_nextNode(nest));
1596
1597 /* Get priority if set differently. */
1598 xmlr_attr_int_def( cur, "priority", priority, data->avail.priority );
1599
1600 /* Create the OSD. */
1601 misn->osd = osd_create( title, nitems, items, priority );
1602 free(items);
1603 free(title);
1604
1605 /* Set active. */
1606 xmlr_attr_int_def( cur, "active", active, -1 );
1607 if (active != -1)
1608 osd_active( misn->osd, active );
1609
1610 xmlr_attr_int_def( cur, "hidden", hidden, 0 );
1611 osd_setHide( misn->osd, hidden );
1612 }
1613
1614 /* Claims. */
1615 if (xml_isNode(cur,"claims"))
1616 misn->claims = claim_xmlLoad( cur );
1617
1618 if (xml_isNode(cur,"lua")) {
1619 /* start the unpersist routine */
1620 int ret = nxml_unpersistLua( misn->env, cur );
1621 if (ret) {
1622 WARN(_("Mission '%s' from saved game failed to unpersist Lua properly - ignoring."), data->name);
1623 misn_failed = -1;
1624 }
1625 }
1626
1627 } while (xml_nextNode(cur));
1628
1629 if (misn_failed) {
1630 array_push_back( &player_missions_failed, strdup(data->name) );
1631 failed = -1;
1632 mission_cleanup( misn );
1633 }
1634 else
1636 }
1637 } while (xml_nextNode(node));
1638
1639 return failed;
1640}
1641
1642int mission_reload( const char *name )
1643{
1644 int res, id;
1645 MissionData save, *temp;
1646
1647 /* Can't use mission_getFromName here. */
1648 id = mission_getID( name );
1649 if (id < 0)
1650 return -1;
1651 temp = &mission_stack[id];
1652
1653 if (temp == NULL)
1654 return -1;
1655 save = *temp;
1656 res = mission_parseFile( save.sourcefile, temp );
1657 if (res == 0)
1658 mission_freeData( &save );
1659 else
1660 *temp = save;
1661 return res;
1662}
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
Commodity * commodity_newTemp(const char *name, const char *desc)
Creates a new temporary commodity.
Definition commodity.c:419
Commodity * commodity_getW(const char *name)
Gets a commodity by name without warning.
Definition commodity.c:142
int commodity_tempIllegalto(Commodity *com, int faction)
Makes a temporary commodity illegal to something.
Definition commodity.c:436
int cond_compile(const char *cond)
Compiles a conditional statement that can then be used as a reference.
Definition cond.c:53
const char * faction_name(int f)
Gets a factions "real" (internal) name.
Definition faction.c:306
int faction_get(const char *name)
Gets a faction ID by name.
Definition faction.c:184
void hook_rmMisnParent(unsigned int parent)
Removes all hooks belonging to parent mission.
Definition hook.c:821
int landed
Definition land.c:75
int mission_accept(Mission *mission)
Small wrapper for misn_run.
Definition mission.c:206
int missions_saveTempCommodity(xmlTextWriterPtr writer, const Commodity *c)
Saves a temporary commodity's defintion into the current node.
Definition mission.c:1385
Mission ** player_missions
Definition mission.c:47
static int mission_markerLoad(Mission *misn, xmlNodePtr node)
Loads a mission marker from xml.
Definition mission.c:509
const StarSystem * mission_getSystemMarker(const Mission *misn)
Gets the first system that has been marked by a mission.
Definition mission.c:656
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:914
void mission_cleanup(Mission *misn)
Cleans up a mission.
Definition mission.c:739
int mission_addMarker(Mission *misn, int id, int objid, MissionMarkerType type)
Adds a system marker to a mission.
Definition mission.c:549
const StarSystem * mission_sysComputerMark(const Mission *misn)
Marks the system of the computer mission to reflect where it will head to.
Definition mission.c:603
const MissionData * mission_getFromName(const char *name)
Gets mission data from a name.
Definition mission.c:125
void missions_free(void)
Frees all the mission data.
Definition mission.c:1245
int mission_alreadyRunning(const MissionData *misn)
Checks to see if mission is already running.
Definition mission.c:225
static const char * mission_markerTarget(const MissionMarker *m)
Gets the name of the mission marker target.
Definition mission.c:420
static int mission_matchFaction(const MissionData *misn, int faction)
Checks to see if a mission matches the faction requirements.
Definition mission.c:850
int mission_linkCargo(Mission *misn, unsigned int cargo_id)
Links cargo to the mission for posterior cleanup.
Definition mission.c:701
void missions_activateClaims(void)
Activates mission claims.
Definition mission.c:867
void mission_sysMark(void)
Marks all active systems that need marking.
Definition mission.c:578
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:321
static MissionData * mission_stack
Definition mission.c:53
int missions_loadActive(xmlNodePtr parent)
Loads the player's active missions from a save.
Definition mission.c:1477
static int mission_parseFile(const char *file, MissionData *temp)
Parses a single mission.
Definition mission.c:1167
static int mission_parseXML(MissionData *temp, const xmlNodePtr parent)
Parses a node of a mission.
Definition mission.c:1002
static int missions_parseActive(xmlNodePtr parent)
Parses the actual individual mission nodes.
Definition mission.c:1504
static char ** player_missions_failed
Definition mission.c:48
void mission_shift(int pos)
Puts the specified mission at the end of the player_missions array.
Definition mission.c:791
int missions_load(void)
Loads all the mission data.
Definition mission.c:1120
static int missions_cmp(const void *a, const void *b)
Ordering function for missions.
Definition mission.c:1103
Commodity * missions_loadTempCommodity(xmlNodePtr cur)
Loads a temporary commodity.
Definition mission.c:1430
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:288
int mission_start(const char *name, unsigned int *id)
Starts a mission.
Definition mission.c:358
int mission_getID(const char *name)
Gets id from mission name.
Definition mission.c:100
int missions_saveActive(xmlTextWriterPtr writer)
Saves the player's active missions.
Definition mission.c:1287
static int mission_compare(const void *arg1, const void *arg2)
Compares to missions to see which has more priority.
Definition mission.c:877
static unsigned int mission_genID(void)
Generates a new id for the mission.
Definition mission.c:84
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:814
static int mission_location(const char *loc)
Gets location based on a human readable string.
Definition mission.c:978
static int mission_init(Mission *mission, const MissionData *misn, int genid, int create, unsigned int *id)
Initializes a mission.
Definition mission.c:144
int mission_unlinkCargo(Mission *misn, unsigned int cargo_id)
Unlinks cargo from the mission, removes it from the player.
Definition mission.c:716
const MissionData * mission_list(void)
Returns all the missions.
Definition mission.c:214
int missions_loadCommodity(xmlNodePtr parent)
Loads the player's special mission commodities.
Definition mission.c:1400
int mission_test(const char *name)
Tests the conditionals of a mission.
Definition mission.c:386
void missions_cleanup(void)
Cleans up all the player's active missions.
Definition mission.c:1268
const MissionData * mission_get(int id)
Gets a MissionData based on ID.
Definition mission.c:116
int naev_isQuit(void)
Get if Naev is trying to quit.
Definition naev.c:158
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:231
int misn_loadLibs(nlua_env env)
Registers all the mission libraries.
Definition nlua_misn.c:115
void npc_patchMission(Mission *misn)
Patches a new mission bar npc into the bar system.
Definition npc.c:420
int npc_rm_parentMission(unsigned int mid)
Removes all the npc belonging to a mission.
Definition npc.c:302
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:530
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition opengl_tex.c:862
int pilot_rmMissionCargo(Pilot *pilot, unsigned int cargo_id, int jettison)
Removes special mission cargo based on id.
int player_missionAlreadyDone(int id)
Checks to see if player has already completed a mission.
Definition player.c:2961
Player_t player
Definition player.c:74
PilotCommodity * pfleet_cargoList(void)
Gets a list of all the cargo in the fleet.
static const double c[]
Definition rng.c:264
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
Definition space.c:1051
StarSystem * system_getIndex(int id)
Get the system by its index.
Definition space.c:989
int spob_index(const Spob *p)
Gets the ID of a spob.
Definition space.c:1099
StarSystem * system_get(const char *sysname)
Get the system from its name.
Definition space.c:960
const char * spob_getSystem(const char *spobname)
Get the name of a system from a spobname.
Definition space.c:1025
int space_addMarker(int objid, MissionMarkerType type)
Adds a marker to a system.
Definition space.c:3787
void space_clearMarkers(void)
Clears all system markers.
Definition space.c:3696
Spob * spob_getIndex(int ind)
Gets spob by index.
Definition space.c:1082
void space_clearComputerMarkers(void)
Clears all the system computer markers.
Definition space.c:3716
int system_index(const StarSystem *sys)
Gets the index of a star system.
Definition space.c:1000
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
char * done
Definition mission.h:52
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:62
char * name
Definition mission.h:63
MissionAvail_t avail
Definition mission.h:65
char * lua
Definition mission.h:68
char ** tags
Definition mission.h:73
char * sourcefile
Definition mission.h:69
int chunk
Definition mission.h:70
Mission system marker.
MissionMarkerType type
Represents an active mission.
Definition mission.h:81
Claim_t * claims
Definition mission.h:105
unsigned int osd
Definition mission.h:101
char * npc_desc
Definition mission.h:92
unsigned int * cargo
Definition mission.h:95
unsigned int id
Definition mission.h:83
glTexture * portrait
Definition mission.h:90
nlua_env env
Definition mission.h:107
char * reward
Definition mission.h:88
char * desc
Definition mission.h:87
MissionMarker * markers
Definition mission.h:98
char * title
Definition mission.h:86
const MissionData * data
Definition mission.h:82
credits_t reward_value
Definition mission.h:89
int accepted
Definition mission.h:84
char * npc
Definition mission.h:91
Stores a pilot commodity.
Definition pilot.h:179
const Commodity * commodity
Definition pilot.h:180
int devmode
Definition conf.h:157
Pilot * p
Definition player.h:101
char * chapter
Definition player.h:111
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:89
char * name
Definition space.h:91