naev 0.12.6
mission.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <stdlib.h>
11
12#include "SDL_timer.h"
13
14#include "naev.h"
16
17#include "mission.h"
18
19#include "array.h"
20#include "cond.h"
21#include "faction.h"
22#include "gui_osd.h"
23#include "hook.h"
24#include "land.h"
25#include "log.h"
26#include "ndata.h"
27#include "nlua.h"
28#include "nlua_misn.h"
29#include "npc.h"
30#include "nstring.h"
31#include "ntracing.h"
32#include "nxml.h"
33#include "nxml_lua.h"
34#include "player.h"
35#include "player_fleet.h"
36#include "rng.h"
37#include "space.h"
38
39#define XML_MISSION_TAG "mission"
40
41/*
42 * current player missions
43 */
44static unsigned int mission_id = 0;
47 NULL;
48
49/*
50 * mission stack
51 */
52static MissionData *mission_stack = NULL;
53
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,
61 int create, unsigned int *id );
62static void mission_freeData( MissionData *mission );
63/* Matching. */
64static int mission_meetConditionals( const MissionData *misn );
65static int mission_meetReq( const MissionData *misn, int faction,
66 const Spob *pnt, const StarSystem *sys );
67static int mission_matchFaction( const MissionData *misn, int faction );
68static int mission_location( const char *loc );
69/* Loading. */
70static int missions_cmp( const void *a, const void *b );
71static int mission_parseFile( const char *file, MissionData *temp );
72static int mission_parseXML( MissionData *temp, const xmlNodePtr parent );
73static int missions_parseActive( xmlNodePtr parent );
74/* Misc. */
75static const char *mission_markerTarget( const MissionMarker *m );
76static int mission_markerLoad( Mission *misn, xmlNodePtr node );
77
83static unsigned int mission_genID( void )
84{
85 unsigned int id = ++mission_id; /* default id, not safe if loading */
86 /* we save mission ids, so check for collisions with player's missions */
87 for ( int i = 0; i < array_size( player_missions ); i++ )
88 if ( id == player_missions[i]->id ) /* mission id was loaded from save */
89 return mission_genID(); /* recursively try again */
90 return id;
91}
92
99int mission_getID( const char *name )
100{
101 for ( int i = 0; i < array_size( mission_stack ); i++ )
102 if ( strcmp( name, mission_stack[i].name ) == 0 )
103 return i;
104
105 WARN( _( "Mission '%s' not found in stack" ), name );
106 return -1;
107}
108
115const MissionData *mission_get( int id )
116{
117 if ( ( id < 0 ) || ( id >= array_size( mission_stack ) ) )
118 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,
145 int create, unsigned int *id )
146{
147 if ( misn->chunk == LUA_NOREF ) {
148 WARN(
149 _( "Trying to initialize mission '%s' that has no loaded Lua chunk!" ),
150 misn->name );
151 return -1;
152 }
153
154 /* clear the mission */
155 memset( mission, 0, sizeof( Mission ) );
156 mission->env = LUA_NOREF;
157
158 /* Create id if needed. */
159 mission->id = ( genid ) ? mission_genID() : 0;
160
161 if ( id != NULL )
162 *id = mission->id;
163 mission->data = misn;
164 mission->osd_priority = misn->avail.priority;
165 if ( create ) {
166 mission->title = strdup( _( misn->name ) );
167 mission->desc = strdup( _( "No description." ) );
168 }
169
170 /* init Lua */
171 mission->env = nlua_newEnv( misn->name );
172
173 misn_loadLibs( mission->env ); /* load our custom libraries */
174
175 /* Create the "mem" table for persistence. */
176 lua_newtable( naevL );
177 nlua_setenv( naevL, mission->env, "mem" );
178
179 /* load the file */
180 if ( nlua_dochunkenv( mission->env, misn->chunk, misn->sourcefile ) != 0 ) {
181 WARN( _( "Error loading mission file: %s\n"
182 "%s\n"
183 "Most likely Lua file has improper syntax, please check" ),
184 misn->sourcefile, lua_tostring( naevL, -1 ) );
185 return -1;
186 }
187
188 /* run create function */
189 if ( create ) {
190 /* Failed to create. */
191 int ret = misn_run( mission, "create" );
192 if ( ret ) {
193 mission_cleanup( mission );
194 return ret;
195 }
196 }
197
198 return 0;
199}
200
210int mission_accept( Mission *mission )
211{
212 return misn_run( mission, "accept" );
213}
214
219{
220 return mission_stack;
221}
222
230{
231 int n = 0;
232 for ( int i = 0; i < array_size( player_missions ); i++ )
233 if ( player_missions[i]->data == misn )
234 n++;
235 return n;
236}
237
238static int mission_meetConditionals( const MissionData *misn )
239{
240 /* If chapter, must match chapter. */
241 if ( misn->avail.chapter_re != NULL ) {
242 pcre2_match_data *match_data =
243 pcre2_match_data_create_from_pattern( misn->avail.chapter_re, NULL );
244 int rc = pcre2_match( misn->avail.chapter_re, (PCRE2_SPTR)player.chapter,
245 strlen( player.chapter ), 0, 0, match_data, NULL );
246 pcre2_match_data_free( match_data );
247 if ( rc < 0 ) {
248 switch ( rc ) {
249 case PCRE2_ERROR_NOMATCH:
250 return -1;
251 default:
252 WARN( _( "Matching error %d" ), rc );
253 break;
254 }
255 } else if ( rc == 0 )
256 return 1;
257 }
258
259 /* Must not be already done or running if unique. */
260 if ( mis_isFlag( misn, MISSION_UNIQUE ) &&
262 mission_alreadyRunning( misn ) ) )
263 return 1;
264
265 /* Must meet Lua condition. */
266 if ( misn->avail.cond != NULL ) {
267 int c = cond_checkChunk( misn->avail.cond_chunk, misn->avail.cond );
268 if ( c < 0 ) {
269 WARN( _( "Conditional for mission '%s' failed to run" ), misn->name );
270 return 1;
271 } else if ( !c )
272 return 1;
273 }
274
275 /* Must meet previous mission requirements. */
276 if ( ( misn->avail.done != NULL ) &&
278 0 ) )
279 return 1;
280
281 return 0;
282}
283
293static int mission_meetReq( const MissionData *misn, int faction,
294 const Spob *pnt, const StarSystem *sys )
295{
296 if ( misn == NULL ) /* In case it doesn't exist */
297 return 0;
298
299 /* If spob, must match spob. */
300 if ( misn->avail.spob != NULL ) {
301 if ( ( pnt == NULL ) || strcmp( misn->avail.spob, pnt->name ) != 0 )
302 return 0;
303 } else if ( spob_isFlag( pnt, SPOB_NOMISNSPAWN ) )
304 return 0;
305
306 /* If system, must match system. */
307 if ( ( misn->avail.system != NULL ) &&
308 ( sys == NULL || ( strcmp( misn->avail.system, sys->name ) != 0 ) ) )
309 return 0;
310
311 /* Match faction. */
312 if ( ( faction >= 0 ) && !mission_matchFaction( misn, faction ) )
313 return 0;
314
315 return !mission_meetConditionals( misn );
316}
317
326void missions_run( MissionAvailability loc, int faction, const Spob *pnt,
327 const StarSystem *sys )
328{
329 for ( int i = 0; i < array_size( mission_stack ); i++ ) {
330 Mission mission;
331 double chance;
332 MissionData *misn = &mission_stack[i];
333
334 if ( naev_isQuit() )
335 return;
336
337 if ( misn->avail.loc != loc )
338 continue;
339
340 if ( !mission_meetReq( misn, faction, pnt, sys ) )
341 continue;
342
343 chance = (double)( misn->avail.chance % 100 ) / 100.;
344 if ( chance == 0. ) /* We want to consider 100 -> 100% not 0% */
345 chance = 1.;
346
347 if ( RNGF() < chance ) {
348 mission_init( &mission, misn, 1, 1, NULL );
350 &mission ); /* it better clean up for itself or we do it */
351 }
352 }
353}
354
365int mission_start( const char *name, unsigned int *id )
366{
367 Mission mission;
368 const MissionData *mdat;
369 int ret;
370
371 /* Try to get the mission. */
372 mdat = mission_get( mission_getID( name ) );
373 if ( mdat == NULL )
374 return -1;
375
376 /* Try to run the mission. */
377 ret = mission_init( &mission, mdat, 1, 1, id );
378 /* Add to mission giver if necessary. */
379 if ( landed && ( ret == 0 ) ) {
380 if ( mdat->avail.loc == MIS_AVAIL_BAR )
381 npc_patchMission( &mission );
382 else if ( mdat->avail.loc == MIS_AVAIL_COMPUTER )
383 misn_patchMission( &mission );
384 else
385 mission_cleanup( &mission );
386 } else
387 mission_cleanup( &mission ); /* Clean up in case not accepted. */
388
389 return ret;
390}
391
398int mission_test( const char *name )
399{
400 const MissionData *mdat;
401
402 /* Try to get the mission. */
403 mdat = mission_get( mission_getID( name ) );
404 if ( mdat == NULL )
405 return -1;
406
407 return mission_meetConditionals( mdat );
408}
409
410const char *mission_availabilityStr( MissionAvailability loc )
411{
412 switch ( loc ) {
413 case MIS_AVAIL_UNSET:
414 return "unset";
415 case MIS_AVAIL_NONE:
416 return "none";
417 case MIS_AVAIL_COMPUTER:
418 return "computer";
419 case MIS_AVAIL_BAR:
420 return "bar";
421 case MIS_AVAIL_LAND:
422 return "land";
423 case MIS_AVAIL_ENTER:
424 return "enter";
425 }
426 return NULL;
427}
428
432static const char *mission_markerTarget( const MissionMarker *m )
433{
434 switch ( m->type ) {
435 case SYSMARKER_COMPUTER:
436 case SYSMARKER_LOW:
437 case SYSMARKER_HIGH:
438 case SYSMARKER_PLOT:
439 return system_getIndex( m->objid )->name;
440 case SPOBMARKER_COMPUTER:
441 case SPOBMARKER_LOW:
442 case SPOBMARKER_HIGH:
443 case SPOBMARKER_PLOT:
444 return spob_getIndex( m->objid )->name;
445 default:
446 WARN( _( "Unknown marker type." ) );
447 return NULL;
448 }
449}
450
451MissionMarkerType mission_markerTypeSpobToSystem( MissionMarkerType t )
452{
453 switch ( t ) {
454 case SYSMARKER_COMPUTER:
455 case SYSMARKER_LOW:
456 case SYSMARKER_HIGH:
457 case SYSMARKER_PLOT:
458 return t;
459 case SPOBMARKER_COMPUTER:
460 return SYSMARKER_COMPUTER;
461 case SPOBMARKER_LOW:
462 return SYSMARKER_LOW;
463 case SPOBMARKER_HIGH:
464 return SYSMARKER_HIGH;
465 case SPOBMARKER_PLOT:
466 return SYSMARKER_PLOT;
467 default:
468 WARN( _( "Unknown marker type." ) );
469 return -1;
470 }
471}
472
473MissionMarkerType mission_markerTypeSystemToSpob( MissionMarkerType t )
474{
475 switch ( t ) {
476 case SYSMARKER_COMPUTER:
477 return SPOBMARKER_COMPUTER;
478 case SYSMARKER_LOW:
479 return SPOBMARKER_LOW;
480 case SYSMARKER_HIGH:
481 return SPOBMARKER_HIGH;
482 case SYSMARKER_PLOT:
483 return SPOBMARKER_PLOT;
484 case SPOBMARKER_COMPUTER:
485 case SPOBMARKER_LOW:
486 case SPOBMARKER_HIGH:
487 case SPOBMARKER_PLOT:
488 return t;
489 default:
490 WARN( _( "Unknown marker type." ) );
491 return -1;
492 }
493}
494
495void mission_toLuaTable( lua_State *L, const MissionData *m )
496{
497 lua_newtable( L );
498
499 lua_pushstring( L, m->name );
500 lua_setfield( L, -2, "name" );
501
502 lua_pushboolean( L, mis_isFlag( m, MISSION_UNIQUE ) );
503 lua_setfield( L, -2, "unique" );
504
505 lua_newtable( L );
506 for ( int j = 0; j < array_size( m->tags ); j++ ) {
507 lua_pushboolean( L, 1 );
508 lua_setfield( L, -2, m->tags[j] );
509 }
510 lua_setfield( L, -2, "tags" );
511}
512
513const char **mission_loadFailed( void )
514{
515 return (const char **)player_missions_failed;
516}
517
521void misn_osdSetHide( Mission *misn, int hide )
522{
523 misn->osd_hide = hide;
524 osd_setHide( misn->osd, hide );
525}
526
527int misn_osdGetHide( const Mission *misn )
528{
529 return misn->osd_hide;
530}
531void misn_osdSetPriority( Mission *misn, int priority )
532{
533 misn->osd_priority = priority;
534 osd_setPriority( misn->osd, priority );
535}
536int misn_osdGetPriority( const Mission *misn )
537{
538 return misn->osd_priority;
539}
540
544static int mission_markerLoad( Mission *misn, xmlNodePtr node )
545{
546 int id;
547 MissionMarkerType type;
548 StarSystem *ssys;
549 Spob *pnt;
550
551 xmlr_attr_int_def( node, "id", id, -1 );
552 xmlr_attr_int_def( node, "type", type, -1 );
553
554 switch ( type ) {
555 case SYSMARKER_COMPUTER:
556 case SYSMARKER_LOW:
557 case SYSMARKER_HIGH:
558 case SYSMARKER_PLOT:
559 ssys = system_get( xml_get( node ) );
560 if ( ssys == NULL ) {
561 WARN( _( "Mission Marker to system '%s' does not exist" ),
562 xml_get( node ) );
563 return -1;
564 }
565 return mission_addMarker( misn, id, system_index( ssys ), type );
566 case SPOBMARKER_COMPUTER:
567 case SPOBMARKER_LOW:
568 case SPOBMARKER_HIGH:
569 case SPOBMARKER_PLOT:
570 pnt = spob_get( xml_get( node ) );
571 if ( pnt == NULL ) {
572 WARN( _( "Mission Marker to spob '%s' does not exist" ),
573 xml_get( node ) );
574 return -1;
575 }
576 return mission_addMarker( misn, id, spob_index( pnt ), type );
577 default:
578 WARN( _( "Unknown marker type." ) );
579 return -1;
580 }
581}
582
586int mission_addMarker( Mission *misn, int id, int objid,
587 MissionMarkerType type )
588{
589 MissionMarker *marker;
590
591 /* Create array. */
592 if ( misn->markers == NULL )
594
595 /* Avoid ID collisions. */
596 if ( id < 0 ) {
597 int m = -1;
598 for ( int i = 0; i < array_size( misn->markers ); i++ )
599 if ( misn->markers[i].id > m )
600 m = misn->markers[i].id;
601 id = m + 1;
602 }
603
604 /* Create the marker. */
605 marker = &array_grow( &misn->markers );
606 marker->id = id;
607 marker->objid = objid;
608 marker->type = type;
609
610 return marker->id;
611}
612
616void mission_sysMark( void )
617{
618 /* Clear markers. */
620 for ( int i = 0; i < array_size( player_missions ); i++ ) {
621 /* Must be a valid player mission. */
622 if ( player_missions[i]->id == 0 )
623 continue;
624
625 for ( int j = 0; j < array_size( player_missions[i]->markers ); j++ ) {
626 const MissionMarker *m = &player_missions[i]->markers[j];
627
628 /* Add the individual markers. */
629 space_addMarker( m->objid, m->type );
630 }
631 }
632}
633
642const StarSystem *mission_sysComputerMark( const Mission *misn )
643{
644 StarSystem *firstsys = NULL;
645
646 /* Clear markers. */
648
649 /* Set all the markers. */
650 for ( int i = 0; i < array_size( misn->markers ); i++ ) {
651 StarSystem *sys;
652 Spob *pnt;
653 const char *sysname;
654 const MissionMarker *m = &misn->markers[i];
655
656 switch ( m->type ) {
657 case SYSMARKER_COMPUTER:
658 case SYSMARKER_LOW:
659 case SYSMARKER_HIGH:
660 case SYSMARKER_PLOT:
661 sys = system_getIndex( m->objid );
662 break;
663 case SPOBMARKER_COMPUTER:
664 case SPOBMARKER_LOW:
665 case SPOBMARKER_HIGH:
666 case SPOBMARKER_PLOT:
667 pnt = spob_getIndex( m->objid );
668 sysname = spob_getSystemName( pnt->name );
669 if ( sysname == NULL ) {
670 WARN( _( "Marked spob '%s' is not in any system!" ), pnt->name );
671 continue;
672 }
673 sys = system_get( sysname );
674 break;
675 default:
676 WARN( _( "Unknown marker type." ) );
677 continue;
678 }
679
680 if ( sys != NULL )
681 sys_setFlag( sys, SYSTEM_CMARKED );
682
683 if ( firstsys == NULL )
684 firstsys = sys;
685 }
686 return firstsys;
687}
688
695const StarSystem *mission_getSystemMarker( const Mission *misn )
696{
697 /* Set all the markers. */
698 for ( int i = 0; i < array_size( misn->markers ); i++ ) {
699 StarSystem *sys;
700 Spob *pnt;
701 const char *sysname;
702 const MissionMarker *m = &misn->markers[i];
703 ;
704
705 switch ( m->type ) {
706 case SYSMARKER_COMPUTER:
707 case SYSMARKER_LOW:
708 case SYSMARKER_HIGH:
709 case SYSMARKER_PLOT:
710 sys = system_getIndex( m->objid );
711 break;
712 case SPOBMARKER_COMPUTER:
713 case SPOBMARKER_LOW:
714 case SPOBMARKER_HIGH:
715 case SPOBMARKER_PLOT:
716 pnt = spob_getIndex( m->objid );
717 sysname = spob_getSystemName( pnt->name );
718 if ( sysname == NULL ) {
719 WARN( _( "Marked spob '%s' is not in any system!" ), pnt->name );
720 continue;
721 }
722 sys = system_get( sysname );
723 break;
724 default:
725 WARN( _( "Unknown marker type." ) );
726 continue;
727 }
728
729 return sys;
730 }
731 return NULL;
732}
733
741int mission_linkCargo( Mission *misn, unsigned int cargo_id )
742{
743 if ( misn->cargo == NULL )
744 misn->cargo = array_create( unsigned int );
745 array_push_back( &misn->cargo, cargo_id );
746 return 0;
747}
748
756int mission_unlinkCargo( Mission *misn, unsigned int cargo_id )
757{
758 int i;
759 for ( i = 0; i < array_size( misn->cargo ); i++ )
760 if ( misn->cargo[i] == cargo_id )
761 break;
762
763 if ( i >= array_size( misn->cargo ) ) { /* not found */
764 DEBUG( _( "Mission '%s' attempting to unlink nonexistent cargo %d." ),
765 misn->title, cargo_id );
766 return 1;
767 }
768
769 /* shrink cargo size. */
770 array_erase( &misn->cargo, &misn->cargo[i], &misn->cargo[i + 1] );
771 return 0;
772}
773
780{
781 /* Hooks and missions. */
782 if ( misn->id != 0 ) {
783 hook_rmMisnParent( misn->id ); /* remove existing hooks */
784 npc_rm_parentMission( misn->id ); /* remove existing npc */
785 }
786
787 /* Cargo. */
788 if ( ( player.p != NULL ) &&
789 !pilot_isFlag( player.p,
790 PILOT_DEAD ) ) { /* Only remove if player exists. */
791 for ( int i = 0; i < array_size( misn->cargo );
792 i++ ) { /* must unlink all the cargo */
793 int ret = pilot_rmMissionCargo( player.p, misn->cargo[i], 0 );
794 if ( ret )
795 WARN( _( "Failed to remove mission cargo '%d' for mission '%s'." ),
796 misn->cargo[i], misn->title );
797 }
798 }
799 array_free( misn->cargo );
800 if ( misn->osd > 0 )
801 osd_destroy( misn->osd );
802 /*
803 * XXX With the way the mission code works, this function is called on a
804 * Mission struct of all zeros. Looking at the implementation, luaL_ref()
805 * never returns 0, but this is probably undefined behavior.
806 */
807 if ( misn->env != LUA_NOREF )
808 nlua_freeEnv( misn->env );
809
810 /* Data. */
811 free( misn->title );
812 free( misn->desc );
813 free( misn->reward );
814 gl_freeTexture( misn->portrait );
815 free( misn->npc );
816 free( misn->npc_desc );
817
818 /* Markers. */
819 array_free( misn->markers );
820
821 /* Claims. */
822 if ( misn->claims != NULL )
823 claim_destroy( misn->claims );
824
825 /* Clear the memory. */
826 memset( misn, 0, sizeof( Mission ) );
827 misn->env = LUA_NOREF;
828}
829
835void mission_shift( int pos )
836{
837 Mission *misn;
838
839 if ( pos >= ( array_size( player_missions ) - 1 ) )
840 return;
841
842 /* Store specified mission. */
843 misn = player_missions[pos];
844
845 /* Move other missions down. */
846 memmove( &player_missions[pos], &player_missions[pos + 1],
847 sizeof( Mission * ) * ( array_size( player_missions ) - pos - 1 ) );
848
849 /* Put the specified mission at the end of the array. */
851}
852
858static void mission_freeData( MissionData *mission )
859{
860 free( mission->name );
861 free( mission->lua );
862 free( mission->sourcefile );
863 free( mission->avail.spob );
864 free( mission->avail.system );
865 free( mission->avail.chapter );
866 pcre2_code_free( mission->avail.chapter_re );
867 array_free( mission->avail.factions );
868 free( mission->avail.cond );
869 free( mission->avail.done );
870
871 if ( mission->chunk != LUA_NOREF )
872 luaL_unref( naevL, LUA_REGISTRYINDEX, mission->chunk );
873
874 if ( mission->avail.cond_chunk != LUA_NOREF )
875 luaL_unref( naevL, LUA_REGISTRYINDEX, mission->avail.cond_chunk );
876
877 for ( int i = 0; i < array_size( mission->tags ); i++ )
878 free( mission->tags[i] );
879 array_free( mission->tags );
880
881 /* Clear the memory. */
882#ifdef DEBUGGING
883 memset( mission, 0, sizeof( MissionData ) );
884#endif /* DEBUGGING */
885}
886
894static int mission_matchFaction( const MissionData *misn, int faction )
895{
896 /* No faction always accepted. */
897 if ( array_size( misn->avail.factions ) == 0 )
898 return 1;
899
900 /* Check factions. */
901 for ( int i = 0; i < array_size( misn->avail.factions ); i++ )
902 if ( faction == misn->avail.factions[i] )
903 return 1;
904
905 return 0;
906}
907
912{
913 for ( int i = 0; i < array_size( player_missions ); i++ )
914 if ( player_missions[i]->claims != NULL )
915 claim_activate( player_missions[i]->claims );
916}
917
921int mission_compare( const void *arg1, const void *arg2 )
922{
923 const Mission *m1 = (Mission *)arg1;
924 const Mission *m2 = (Mission *)arg2;
925
926 /* Check priority - lower is more important. */
927 if ( m1->data->avail.priority < m2->data->avail.priority )
928 return -1;
929 else if ( m1->data->avail.priority > m2->data->avail.priority )
930 return +1;
931
932 /* Compare NPC. */
933 if ( ( m1->npc != NULL ) && ( m2->npc != NULL ) )
934 return strcmp( m1->npc, m2->npc );
935
936 /* Compare title. */
937 if ( ( m1->title != NULL ) && ( m2->title != NULL ) )
938 return strcmp( m1->title, m2->title );
939
940 /* Tied. */
941 return strcmp( m1->data->name, m2->data->name );
942}
943
954Mission *missions_genList( int faction, const Spob *pnt, const StarSystem *sys,
955 MissionAvailability loc )
956{
957 int rep;
958 Mission *tmp = array_create( Mission );
959
960 NTracingZone( _ctx, 1 );
961
962 /* Find available missions. */
963 for ( int i = 0; i < array_size( mission_stack ); i++ ) {
964 double chance;
965 MissionData *misn = &mission_stack[i];
966 if ( misn->avail.loc != loc )
967 continue;
968
969 /* Must hit chance. */
970 chance = (double)( misn->avail.chance % 100 ) / 100.;
971 if ( chance == 0. ) /* We want to consider 100 -> 100% not 0% */
972 chance = 1.;
973 rep = MAX( 1, misn->avail.chance / 100 );
974
975 /* random chance of rep appearances */
976 for ( int j = 0; j < rep; j++ ) {
977 Mission newm;
978
979 if ( RNGF() > chance )
980 continue;
981
982 /* Must meet requirements. */
983 if ( !mission_meetReq( misn, faction, pnt, sys ) )
984 continue;
985
986 /* Initialize the mission. */
987 if ( mission_init( &newm, misn, 1, 1, NULL ) )
988 continue;
989 array_push_back( &tmp, newm );
990 }
991 }
992
993 /* Sort. */
994 if ( array_size( tmp ) > 0 )
995 qsort( tmp, array_size( tmp ), sizeof( Mission ), mission_compare );
996
997 NTracingZoneEnd( _ctx );
998
999 return tmp;
1000}
1001
1008static int mission_location( const char *loc )
1009{
1010 if ( loc != NULL ) {
1011 if ( strcasecmp( loc, "None" ) == 0 )
1012 return MIS_AVAIL_NONE;
1013 else if ( strcasecmp( loc, "Computer" ) == 0 )
1014 return MIS_AVAIL_COMPUTER;
1015 else if ( strcasecmp( loc, "Bar" ) == 0 )
1016 return MIS_AVAIL_BAR;
1017 else if ( strcasecmp( loc, "Land" ) == 0 )
1018 return MIS_AVAIL_LAND;
1019 else if ( strcasecmp( loc, "Enter" ) == 0 )
1020 return MIS_AVAIL_ENTER;
1021 }
1022 return -1;
1023}
1024
1032static int mission_parseXML( MissionData *temp, const xmlNodePtr parent )
1033{
1034 xmlNodePtr node;
1035
1036 /* Clear memory. */
1037 memset( temp, 0, sizeof( MissionData ) );
1038
1039 /* Defaults. */
1040 temp->chunk = LUA_NOREF;
1041 temp->avail.chance = -1.;
1042 temp->avail.priority = 5;
1043 temp->avail.loc = MIS_AVAIL_UNSET;
1044 temp->avail.cond_chunk = LUA_NOREF;
1045
1046 /* get the name */
1047 xmlr_attr_strd( parent, "name", temp->name );
1048 if ( temp->name == NULL )
1049 WARN( _( "Mission in %s has invalid or no name" ), MISSION_DATA_PATH );
1050
1051 node = parent->xmlChildrenNode;
1052
1053 do { /* load all the data */
1054 /* Only handle nodes. */
1055 xml_onlyNodes( node );
1056
1057 if ( xml_isNode( node, "unique" ) ) { /* Unique mission. */
1058 mis_setFlag( temp, MISSION_UNIQUE );
1059 continue;
1060 }
1061 if ( xml_isNode( node, "location" ) ) {
1062 temp->avail.loc = mission_location( xml_get( node ) );
1063 if ( temp->avail.loc < 0 )
1064 WARN( _( "Mission '%s' has unknown location '%s'!" ), temp->name,
1065 xml_get( node ) );
1066 continue;
1067 }
1068 xmlr_int( node, "chance", temp->avail.chance );
1069 xmlr_strd( node, "spob", temp->avail.spob );
1070 xmlr_strd( node, "system", temp->avail.system );
1071 xmlr_strd( node, "chapter", temp->avail.chapter );
1072 if ( xml_isNode( node, "faction" ) ) {
1073 if ( temp->avail.factions == NULL )
1074 temp->avail.factions = array_create( int );
1076 faction_get( xml_get( node ) ) );
1077 continue;
1078 }
1079 xmlr_strd( node, "cond", temp->avail.cond );
1080 xmlr_strd( node, "done", temp->avail.done );
1081 xmlr_int( node, "priority", temp->avail.priority );
1082
1083 if ( xml_isNode( node, "tags" ) ) {
1084 xmlNodePtr cur = node->children;
1085 temp->tags = array_create( char *);
1086 do {
1087 xml_onlyNodes( cur );
1088 if ( xml_isNode( cur, "tag" ) ) {
1089 const char *tmp = xml_get( cur );
1090 if ( tmp != NULL )
1091 array_push_back( &temp->tags, strdup( tmp ) );
1092 continue;
1093 }
1094 WARN( _( "Mission '%s' has unknown node in tags '%s'." ),
1095 temp->name, cur->name );
1096 } while ( xml_nextNode( cur ) );
1097 continue;
1098 } else if ( xml_isNode( node, "notes" ) )
1099 continue; /* Notes for the python mission mapping script */
1100
1101 // cppcheck-suppress nullPointerRedundantCheck
1102 WARN( _( "Unknown node '%s' in mission '%s'" ), node->name, temp->name );
1103 } while ( xml_nextNode( node ) );
1104
1105 /* Compile conditional chunk. */
1106 if ( temp->avail.cond != NULL ) {
1107 temp->avail.cond_chunk = cond_compile( temp->avail.cond );
1108 if ( temp->avail.cond_chunk == LUA_NOREF ||
1109 temp->avail.cond_chunk == LUA_REFNIL )
1110 WARN( _( "Mission '%s' failed to compile Lua conditional!" ),
1111 temp->name );
1112 }
1113
1114 /* Compile regex for chapter matching. */
1115 if ( temp->avail.chapter != NULL ) {
1116 int errornumber;
1117 PCRE2_SIZE erroroffset;
1118 temp->avail.chapter_re =
1119 pcre2_compile( (PCRE2_SPTR)temp->avail.chapter, PCRE2_ZERO_TERMINATED,
1120 0, &errornumber, &erroroffset, NULL );
1121 if ( temp->avail.chapter_re == NULL ) {
1122 PCRE2_UCHAR buffer[256];
1123 pcre2_get_error_message( errornumber, buffer, sizeof( buffer ) );
1124 WARN( _( "Mission '%s' chapter PCRE2 compilation failed at offset %d: "
1125 "%s" ),
1126 temp->name, (int)erroroffset, buffer );
1127 }
1128 }
1129
1130#define MELEMENT( o, s ) \
1131 if ( o ) \
1132 WARN( _( "Mission '%s' missing/invalid '%s' element" ), temp->name, s )
1133 MELEMENT( temp->avail.loc == MIS_AVAIL_UNSET, "location" );
1134 MELEMENT( ( temp->avail.loc != MIS_AVAIL_NONE ) &&
1135 ( temp->avail.chance < 0. ),
1136 "chance" );
1137 MELEMENT(
1138 ( ( temp->avail.spob != NULL ) && spob_get( temp->avail.spob ) == NULL ),
1139 "spob" );
1140 MELEMENT( ( ( temp->avail.system != NULL ) &&
1141 system_get( temp->avail.system ) == NULL ),
1142 "system" );
1143#undef MELEMENT
1144
1145 return 0;
1146}
1147
1151static int missions_cmp( const void *a, const void *b )
1152{
1153 const MissionData *ma, *mb;
1154 ma = (const MissionData *)a;
1155 mb = (const MissionData *)b;
1156 if ( ma->avail.priority < mb->avail.priority )
1157 return -1;
1158 else if ( ma->avail.priority > mb->avail.priority )
1159 return +1;
1160 return strcmp( ma->name, mb->name );
1161}
1162
1168int missions_load( void )
1169{
1170#if DEBUGGING
1171 Uint32 time = SDL_GetTicks();
1172#endif /* DEBUGGING */
1173 char **mission_files;
1174
1175 /* Run over missions. */
1176 mission_files = ndata_listRecursive( MISSION_DATA_PATH );
1178 array_create_size( MissionData, array_size( mission_files ) );
1179 for ( int i = 0; i < array_size( mission_files ); i++ ) {
1180 mission_parseFile( mission_files[i], NULL );
1181 free( mission_files[i] );
1182 }
1183 array_free( mission_files );
1185
1186#ifdef DEBUGGING
1187 for ( int i = 0; i < array_size( mission_stack ); i++ ) {
1188 MissionData *md = &mission_stack[i];
1189 for ( int j = i + 1; j < array_size( mission_stack ); j++ )
1190 if ( strcmp( md->name, mission_stack[j].name ) == 0 )
1191 WARN( _( "Duplicate event '%s'!" ), md->name );
1192 }
1193#endif /* DEBUGGING */
1194
1195 /* Sort based on priority so higher priority missions can establish claims
1196 * first. */
1197 qsort( mission_stack, array_size( mission_stack ), sizeof( MissionData ),
1198 missions_cmp );
1199
1200#if DEBUGGING
1201 if ( conf.devmode ) {
1202 time = SDL_GetTicks() - time;
1203 DEBUG( n_( "Loaded %d Mission in %.3f s", "Loaded %d Missions in %.3f s",
1205 array_size( mission_stack ), time / 1000. );
1206 } else
1207 DEBUG( n_( "Loaded %d Mission", "Loaded %d Missions",
1210#endif /* DEBUGGING */
1211
1212 return 0;
1213}
1214
1221static int mission_parseFile( const char *file, MissionData *temp )
1222{
1223 xmlDocPtr doc;
1224 xmlNodePtr node;
1225 size_t bufsize;
1226 char *filebuf;
1227 const char *pos, *start_pos;
1228
1229 /* Load string. */
1230 filebuf = ndata_read( file, &bufsize );
1231 if ( filebuf == NULL ) {
1232 WARN( _( "Unable to read data from '%s'" ), file );
1233 return -1;
1234 }
1235 if ( bufsize == 0 ) {
1236 free( filebuf );
1237 return -1;
1238 }
1239
1240 /* Skip if no XML. */
1241 pos = strnstr( filebuf, "</mission>", bufsize );
1242 if ( pos == NULL ) {
1243 pos = strnstr( filebuf, "function create", bufsize );
1244 if ( ( pos != NULL ) && !strncmp( pos, "--common", bufsize ) )
1245 WARN( _( "Mission '%s' has create function but no XML header!" ),
1246 file );
1247 free( filebuf );
1248 return -1;
1249 }
1250
1251 /* Separate XML header and Lua. */
1252 start_pos = strnstr( filebuf, "<?xml ", bufsize );
1253 pos = strnstr( filebuf, "--]]", bufsize );
1254 if ( pos == NULL || start_pos == NULL ) {
1255 WARN( _( "Mission file '%s' has missing XML header!" ), file );
1256 return -1;
1257 }
1258
1259 /* Parse the header. */
1260 doc = xmlParseMemory( start_pos, pos - start_pos );
1261 if ( doc == NULL ) {
1262 WARN( _( "Unable to parse document XML header for Mission '%s'" ), file );
1263 return -1;
1264 }
1265
1266 node = doc->xmlChildrenNode;
1267 if ( !xml_isNode( node, XML_MISSION_TAG ) ) {
1268 WARN( _( "Malformed XML header for '%s' mission: missing root element "
1269 "'%s'" ),
1270 file, XML_MISSION_TAG );
1271 return -1;
1272 }
1273
1274 if ( temp == NULL )
1275 temp = &array_grow( &mission_stack );
1276 mission_parseXML( temp, node );
1277 temp->lua = filebuf;
1278 temp->sourcefile = strdup( file );
1279
1280 /* Clear chunk if already loaded. */
1281 if ( temp->chunk != LUA_NOREF ) {
1282 luaL_unref( naevL, LUA_REGISTRYINDEX, temp->chunk );
1283 temp->chunk = LUA_NOREF;
1284 }
1285
1286 /* Load the chunk. */
1287 int ret =
1288 luaL_loadbuffer( naevL, temp->lua, strlen( temp->lua ), temp->name );
1289 if ( ret == LUA_ERRSYNTAX )
1290 WARN( _( "Mission Lua '%s' syntax error: %s" ), file,
1291 lua_tostring( naevL, -1 ) );
1292 else
1293 temp->chunk = luaL_ref( naevL, LUA_REGISTRYINDEX );
1294
1295 /* Clean up. */
1296 xmlFreeDoc( doc );
1297
1298 return 0;
1299}
1300
1304void missions_free( void )
1305{
1306 /* Free all the player missions. */
1308
1309 /* Free the mission data. */
1310 for ( int i = 0; i < array_size( mission_stack ); i++ )
1313 mission_stack = NULL;
1314
1315 /* Free the player mission stack. */
1317 player_missions = NULL;
1318
1319 /* Frees failed missions. */
1322}
1323
1328{
1329 for ( int i = 0; i < array_size( player_missions ); i++ ) {
1331 free( player_missions[i] );
1332 }
1335
1336 for ( int i = 0; i < array_size( player_missions_failed ); i++ )
1337 free( player_missions_failed[i] );
1340}
1341
1348int missions_saveActive( xmlTextWriterPtr writer )
1349{
1350 /* We also save specially created cargos here. */
1352 xmlw_startElem( writer, "temporary_cargo" );
1353 for ( int i = 0; i < array_size( pcom ); i++ ) {
1354 const Commodity *c = pcom[i].commodity;
1355 if ( !c->istemp )
1356 continue;
1357 xmlw_startElem( writer, "cargo" );
1358 missions_saveTempCommodity( writer, c );
1359 xmlw_endElem( writer ); /* "cargo" */
1360 }
1361 xmlw_endElem( writer ); /* "missions_cargo */
1362 array_free( pcom );
1363
1364 xmlw_startElem( writer, "missions" );
1365 for ( int i = 0; i < array_size( player_missions ); i++ ) {
1366 Mission *misn = player_missions[i];
1367 if ( misn->id == 0 )
1368 continue;
1369
1370 xmlw_startElem( writer, "mission" );
1371
1372 /* data and id are attributes because they must be loaded first */
1373 xmlw_attr( writer, "data", "%s", misn->data->name );
1374 xmlw_attr( writer, "id", "%u", misn->id );
1375
1376 xmlw_elem( writer, "title", "%s", misn->title );
1377 xmlw_elem( writer, "desc", "%s", misn->desc );
1378 xmlw_elem( writer, "reward", "%s", misn->reward );
1379 xmlw_elem( writer, "reward_value", "%" CREDITS_PRI, misn->reward_value );
1380
1381 /* Markers. */
1382 xmlw_startElem( writer, "markers" );
1383 for ( int j = 0; j < array_size( misn->markers ); j++ ) {
1384 MissionMarker *m = &misn->markers[j];
1385 xmlw_startElem( writer, "marker" );
1386 xmlw_attr( writer, "id", "%d", m->id );
1387 xmlw_attr( writer, "type", "%d", m->type );
1388 xmlw_str( writer, "%s", mission_markerTarget( m ) );
1389 xmlw_endElem( writer ); /* "marker" */
1390 }
1391 xmlw_endElem( writer ); /* "markers" */
1392
1393 /* Cargo */
1394 xmlw_startElem( writer, "cargos" );
1395 for ( int j = 0; j < array_size( misn->cargo ); j++ )
1396 xmlw_elem( writer, "cargo", "%u", misn->cargo[j] );
1397 xmlw_endElem( writer ); /* "cargos" */
1398
1399 /* OSD. */
1400 if ( misn->osd > 0 ) {
1401 char **items = osd_getItems( misn->osd );
1402
1403 xmlw_startElem( writer, "osd" );
1404
1405 /* Save attributes. */
1406 xmlw_attr( writer, "title", "%s", osd_getTitle( misn->osd ) );
1407 xmlw_attr( writer, "nitems", "%d", array_size( items ) );
1408 xmlw_attr( writer, "active", "%d", osd_getActive( misn->osd ) );
1409 xmlw_attr( writer, "hidden", "%d", misn->osd_hide );
1410 if ( misn->osd_priority != misn->data->avail.priority )
1411 xmlw_attr( writer, "priority", "%d", misn->osd_priority );
1412
1413 /* Save messages. */
1414 for ( int j = 0; j < array_size( items ); j++ )
1415 xmlw_elem( writer, "msg", "%s", items[j] );
1416
1417 xmlw_endElem( writer ); /* "osd" */
1418 }
1419
1420 /* Claims. */
1421 xmlw_startElem( writer, "claims" );
1422 claim_xmlSave( writer, misn->claims );
1423 xmlw_endElem( writer ); /* "claims" */
1424
1425 /* Write Lua magic */
1426 xmlw_startElem( writer, "lua" );
1427 nxml_persistLua( misn->env, writer );
1428 xmlw_endElem( writer ); /* "lua" */
1429
1430 xmlw_endElem( writer ); /* "mission" */
1431 }
1432 xmlw_endElem( writer ); /* "missions" */
1433
1434 return 0;
1435}
1436
1444int missions_saveTempCommodity( xmlTextWriterPtr writer, const Commodity *c )
1445{
1446 xmlw_attr( writer, "name", "%s", c->name );
1447 xmlw_attr( writer, "description", "%s", c->description );
1448 for ( int j = 0; j < array_size( c->illegalto ); j++ )
1449 xmlw_elem( writer, "illegalto", "%s", faction_name( c->illegalto[j] ) );
1450 return 0;
1451}
1452
1459int missions_loadCommodity( xmlNodePtr parent )
1460{
1461 xmlNodePtr node;
1462
1463 /* We have to ensure the temporary_cargo stuff is loaded first. */
1464 node = parent->xmlChildrenNode;
1465 do {
1466 xml_onlyNodes( node );
1467
1468 if ( xml_isNode( node, "temporary_cargo" ) ) {
1469 xmlNodePtr cur = node->xmlChildrenNode;
1470 do {
1471 xml_onlyNodes( cur );
1472 if ( xml_isNode( cur, "cargo" ) )
1473 (void)missions_loadTempCommodity( cur );
1474 } while ( xml_nextNode( cur ) );
1475 continue;
1476 }
1477 } while ( xml_nextNode( node ) );
1478
1479 return 0;
1480}
1481
1489{
1490 xmlNodePtr ccur;
1491 char *name, *desc;
1492 Commodity *c;
1493
1494 xmlr_attr_strd( cur, "name", name );
1495 if ( name == NULL ) {
1496 WARN( _( "Mission cargo without name!" ) );
1497 return NULL;
1498 }
1499
1500 c = commodity_getW( name );
1501 if ( c != NULL ) {
1502 free( name );
1503 return c;
1504 }
1505
1506 xmlr_attr_strd( cur, "description", desc );
1507 if ( desc == NULL ) {
1508 WARN( _( "Mission temporary cargo '%s' missing description!" ), name );
1509 free( name );
1510 return NULL;
1511 }
1512
1513 c = commodity_newTemp( name, desc );
1514
1515 ccur = cur->xmlChildrenNode;
1516 do {
1517 xml_onlyNodes( ccur );
1518 if ( xml_isNode( ccur, "illegalto" ) ) {
1519 int f = faction_get( xml_get( ccur ) );
1521 }
1522 } while ( xml_nextNode( ccur ) );
1523
1524 free( name );
1525 free( desc );
1526 return c;
1527}
1528
1535int missions_loadActive( xmlNodePtr parent )
1536{
1537 xmlNodePtr node;
1538
1539 /* cleanup old missions */
1541
1542 /* After load the normal missions. */
1543 node = parent->xmlChildrenNode;
1544 do {
1545 xml_onlyNodes( node );
1546 if ( xml_isNode( node, "missions" ) ) {
1547 if ( missions_parseActive( node ) < 0 )
1548 return -1;
1549 continue;
1550 }
1551 } while ( xml_nextNode( node ) );
1552
1553 return 0;
1554}
1555
1562static int missions_parseActive( xmlNodePtr parent )
1563{
1564 char *buf;
1565 char *title;
1566 const char **items;
1567 int nitems, active;
1568 xmlNodePtr node;
1569 int failed = 0;
1570
1571 if ( player_missions == NULL )
1573
1574 if ( player_missions_failed == NULL )
1576
1577 node = parent->xmlChildrenNode;
1578 do {
1579 if ( xml_isNode( node, "mission" ) ) {
1580 xmlNodePtr cur;
1581 const MissionData *data;
1582 int misn_failed = 0;
1583 Mission *misn = calloc( 1, sizeof( Mission ) );
1584
1585 /* process the attributes to create the mission */
1586 xmlr_attr_strd( node, "data", buf );
1587 data = mission_get( mission_getID( buf ) );
1588 if ( data == NULL ) {
1589 WARN( _( "Mission '%s' from saved game not found in game - "
1590 "ignoring." ),
1591 buf );
1592 array_push_back( &player_missions_failed, strdup( buf ) );
1593 free( buf );
1594 continue;
1595 } else {
1596 if ( mission_init( misn, data, 0, 0, NULL ) ) {
1597 WARN( _( "Mission '%s' from saved game failed to load properly "
1598 "- ignoring." ),
1599 buf );
1600 array_push_back( &player_missions_failed, strdup( buf ) );
1601 free( buf );
1602 continue;
1603 }
1604 misn->accepted = 1;
1605 }
1606 free( buf );
1607
1608 /* this will orphan an identifier */
1609 xmlr_attr_int( node, "id", misn->id );
1610
1611 cur = node->xmlChildrenNode;
1612 do {
1613 xmlr_strd( cur, "title", misn->title );
1614 xmlr_strd( cur, "desc", misn->desc );
1615 xmlr_strd( cur, "reward", misn->reward );
1616 xmlr_ulong( cur, "reward_value", misn->reward_value );
1617
1618 /* Get the markers. */
1619 if ( xml_isNode( cur, "markers" ) ) {
1620 xmlNodePtr nest = cur->xmlChildrenNode;
1621 do {
1622 if ( xml_isNode( nest, "marker" ) )
1623 mission_markerLoad( misn, nest );
1624 } while ( xml_nextNode( nest ) );
1625 }
1626
1627 /* Cargo. */
1628 if ( xml_isNode( cur, "cargos" ) ) {
1629 xmlNodePtr nest = cur->xmlChildrenNode;
1630 do {
1631 if ( xml_isNode( nest, "cargo" ) )
1632 mission_linkCargo( misn, xml_getLong( nest ) );
1633 } while ( xml_nextNode( nest ) );
1634 }
1635
1636 /* OSD. */
1637 if ( xml_isNode( cur, "osd" ) ) {
1638 xmlNodePtr nest;
1639 int i = 0;
1640 xmlr_attr_int_def( cur, "nitems", nitems, -1 );
1641 if ( nitems == -1 )
1642 continue;
1643 xmlr_attr_strd( cur, "title", title );
1644 items = malloc( nitems * sizeof( char * ) );
1645 nest = cur->xmlChildrenNode;
1646 do {
1647 if ( xml_isNode( nest, "msg" ) ) {
1648 if ( i > nitems ) {
1649 WARN(
1650 _( "Inconsistency with 'nitems' in save file." ) );
1651 break;
1652 }
1653 items[i] = xml_get( nest );
1654 i++;
1655 }
1656 } while ( xml_nextNode( nest ) );
1657
1658 /* Get priority if set differently. */
1659 xmlr_attr_int_def( cur, "priority", misn->osd_priority,
1660 data->avail.priority );
1661
1662 /* Create the OSD. */
1663 misn->osd = osd_create( title, nitems, items, misn->osd_priority,
1664 misn->osd_hide );
1665 free( items );
1666 free( title );
1667
1668 /* Set active. */
1669 xmlr_attr_int_def( cur, "active", active, -1 );
1670 if ( active != -1 )
1671 osd_active( misn->osd, active );
1672
1673 xmlr_attr_int_def( cur, "hidden", misn->osd_hide, 0 );
1674 osd_setHide( misn->osd, misn->osd_hide );
1675 }
1676
1677 /* Claims. */
1678 if ( xml_isNode( cur, "claims" ) )
1679 misn->claims = claim_xmlLoad( cur );
1680
1681 if ( xml_isNode( cur, "lua" ) ) {
1682 /* start the unpersist routine */
1683 int ret = nxml_unpersistLua( misn->env, cur );
1684 if ( ret ) {
1685 WARN( _( "Mission '%s' from saved game failed to unpersist "
1686 "Lua properly - ignoring." ),
1687 data->name );
1688 misn_failed = -1;
1689 }
1690 }
1691
1692 } while ( xml_nextNode( cur ) );
1693
1694 if ( misn_failed ) {
1695 array_push_back( &player_missions_failed, strdup( data->name ) );
1696 failed = -1;
1697 mission_cleanup( misn );
1698 } else
1700 }
1701 } while ( xml_nextNode( node ) );
1702
1703 return failed;
1704}
1705
1706int mission_reload( const char *name )
1707{
1708 int res, id;
1709 MissionData save, *temp;
1710
1711 /* Can't use mission_getFromName here. */
1712 id = mission_getID( name );
1713 if ( id < 0 )
1714 return -1;
1715 temp = &mission_stack[id];
1716
1717 if ( temp == NULL )
1718 return -1;
1719 save = *temp;
1720 res = mission_parseFile( save.sourcefile, temp );
1721 if ( res == 0 )
1722 mission_freeData( &save );
1723 else
1724 *temp = save;
1725 return res;
1726}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
#define array_end(array)
Returns a pointer to the end of the reserved memory space.
Definition array.h:214
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
Definition array.h:102
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
Definition array.h:148
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:122
#define array_shrink(ptr_array)
Shrinks memory to fit only ‘size’ elements.
Definition array.h:160
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:134
#define array_begin(array)
Returns a pointer to the beginning of the reserved memory space.
Definition array.h:206
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
void claim_destroy(Claim_t *claim)
Destroys a system claim.
Definition claim.c:189
void claim_activate(Claim_t *claim)
Activates a claim on a system.
Definition claim.c:252
Claim_t * claim_xmlLoad(xmlNodePtr parent)
Loads a claim.
Definition claim.c:306
int claim_xmlSave(xmlTextWriterPtr writer, const Claim_t *claim)
Saves all the systems in a claim in XML.
Definition claim.c:279
Commodity * commodity_newTemp(const char *name, const char *desc)
Creates a new temporary commodity.
Definition commodity.c:457
Commodity * commodity_getW(const char *name)
Gets a commodity by name without warning.
Definition commodity.c:166
int commodity_tempIllegalto(Commodity *com, int faction)
Makes a temporary commodity illegal to something.
Definition commodity.c:474
int cond_compile(const char *cond)
Compiles a conditional statement that can then be used as a reference.
Definition cond.c:52
const char * faction_name(int f)
Gets a factions "real" (internal) name.
Definition faction.c:331
int faction_get(const char *name)
Gets a faction ID by name.
Definition faction.c:209
void hook_rmMisnParent(unsigned int parent)
Removes all hooks belonging to parent mission.
Definition hook.c:869
void misn_patchMission(const Mission *misn)
Patches a mission into the mission computer.
Definition land.c:411
int landed
Definition land.c:78
int mission_accept(Mission *mission)
Small wrapper for misn_run.
Definition mission.c:210
int mission_compare(const void *arg1, const void *arg2)
Compares to missions to see which has more priority.
Definition mission.c:921
int missions_saveTempCommodity(xmlTextWriterPtr writer, const Commodity *c)
Saves a temporary commodity's defintion into the current node.
Definition mission.c:1444
Mission ** player_missions
Definition mission.c:45
static int mission_markerLoad(Mission *misn, xmlNodePtr node)
Loads a mission marker from xml.
Definition mission.c:544
const StarSystem * mission_getSystemMarker(const Mission *misn)
Gets the first system that has been marked by a mission.
Definition mission.c:695
void mission_cleanup(Mission *misn)
Cleans up a mission.
Definition mission.c:779
Mission * missions_genList(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:954
int mission_addMarker(Mission *misn, int id, int objid, MissionMarkerType type)
Adds a system marker to a mission.
Definition mission.c:586
const StarSystem * mission_sysComputerMark(const Mission *misn)
Marks the system of the computer mission to reflect where it will head to.
Definition mission.c:642
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:1304
int mission_alreadyRunning(const MissionData *misn)
Checks to see if mission is already running.
Definition mission.c:229
static const char * mission_markerTarget(const MissionMarker *m)
Gets the name of the mission marker target.
Definition mission.c:432
static int mission_matchFaction(const MissionData *misn, int faction)
Checks to see if a mission matches the faction requirements.
Definition mission.c:894
int mission_linkCargo(Mission *misn, unsigned int cargo_id)
Links cargo to the mission for posterior cleanup.
Definition mission.c:741
void missions_activateClaims(void)
Activates mission claims.
Definition mission.c:911
void mission_sysMark(void)
Marks all active systems that need marking.
Definition mission.c:616
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:326
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:1535
static int mission_parseFile(const char *file, MissionData *temp)
Parses a single mission.
Definition mission.c:1221
static int mission_parseXML(MissionData *temp, const xmlNodePtr parent)
Parses a node of a mission.
Definition mission.c:1032
static int missions_parseActive(xmlNodePtr parent)
Parses the actual individual mission nodes.
Definition mission.c:1562
static char ** player_missions_failed
Definition mission.c:46
void mission_shift(int pos)
Puts the specified mission at the end of the player_missions array.
Definition mission.c:835
int missions_load(void)
Loads all the mission data.
Definition mission.c:1168
static int missions_cmp(const void *a, const void *b)
Ordering function for missions.
Definition mission.c:1151
void misn_osdSetHide(Mission *misn, int hide)
Sets the hide state of the mission OSD.
Definition mission.c:521
Commodity * missions_loadTempCommodity(xmlNodePtr cur)
Loads a temporary commodity.
Definition mission.c:1488
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:293
int mission_start(const char *name, unsigned int *id)
Starts a mission.
Definition mission.c:365
int mission_getID(const char *name)
Gets id from mission name.
Definition mission.c:99
int missions_saveActive(xmlTextWriterPtr writer)
Saves the player's active missions.
Definition mission.c:1348
static unsigned int mission_genID(void)
Generates a new id for the mission.
Definition mission.c:83
static unsigned int mission_id
Definition mission.c:44
#define XML_MISSION_TAG
Definition mission.c:39
static void mission_freeData(MissionData *mission)
Frees MissionData.
Definition mission.c:858
static int mission_location(const char *loc)
Gets location based on a human readable string.
Definition mission.c:1008
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:756
const MissionData * mission_list(void)
Returns all the missions.
Definition mission.c:218
int missions_loadCommodity(xmlNodePtr parent)
Loads the player's special mission commodities.
Definition mission.c:1459
int mission_test(const char *name)
Tests the conditionals of a mission.
Definition mission.c:398
void missions_cleanup(void)
Cleans up all the player's active missions.
Definition mission.c:1327
const MissionData * mission_get(int id)
Gets a MissionData based on ID.
Definition mission.c:115
int naev_isQuit(void)
Get if Naev is trying to quit.
Definition naev.c:153
Header file with generic functions and naev-specifics.
#define MAX(x, y)
Definition naev.h:37
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
Definition ndata.c:207
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition ndata.c:286
lua_State * naevL
Definition nlua.c:54
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:427
int npc_rm_parentMission(unsigned int mid)
Removes all the npc belonging to a mission.
Definition npc.c:303
char * strnstr(const char *haystack, const char *needle, size_t size)
A bounded version of strstr. Conforms to BSD semantics.
Definition nstring.c:26
int nxml_persistLua(nlua_env env, xmlTextWriterPtr writer)
Persists all the nxml Lua data.
Definition nxml_lua.c:374
int nxml_unpersistLua(nlua_env env, xmlNodePtr parent)
Unpersists Lua data into a table named "mem".
Definition nxml_lua.c:530
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition opengl_tex.c:835
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:3125
Player_t player
Definition player.c:77
PilotCommodity * pfleet_cargoList(void)
Gets a list of all the cargo in the fleet.
static const double c[]
Definition rng.c:256
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
Definition space.c:1107
StarSystem * system_getIndex(int id)
Get the system by its index.
Definition space.c:1038
int spob_index(const Spob *p)
Gets the ID of a spob.
Definition space.c:1158
StarSystem * system_get(const char *sysname)
Get the system from its name.
Definition space.c:1007
int space_addMarker(int objid, MissionMarkerType type)
Adds a marker to a system.
Definition space.c:4055
void space_clearMarkers(void)
Clears all system markers.
Definition space.c:3964
Spob * spob_getIndex(int ind)
Gets spob by index.
Definition space.c:1140
const char * spob_getSystemName(const char *spobname)
Get the name of a system from a spobname.
Definition space.c:1082
void space_clearComputerMarkers(void)
Clears all the system computer markers.
Definition space.c:3984
int system_index(const StarSystem *sys)
Gets the index of a star system.
Definition space.c:1049
Represents a commodity.
Definition commodity.h:57
MissionAvailability loc
Definition mission.h:37
char * chapter
Definition mission.h:45
int * factions
Definition mission.h:49
char * done
Definition mission.h:53
char * spob
Definition mission.h:43
char * system
Definition mission.h:44
pcre2_code * chapter_re
Definition mission.h:46
char * cond
Definition mission.h:51
Static mission data.
Definition mission.h:64
char * name
Definition mission.h:65
MissionAvail_t avail
Definition mission.h:67
char * lua
Definition mission.h:70
char ** tags
Definition mission.h:75
char * sourcefile
Definition mission.h:71
int chunk
Definition mission.h:72
Mission system marker.
MissionMarkerType type
Represents an active mission.
Definition mission.h:83
Claim_t * claims
Definition mission.h:118
int osd_hide
Definition mission.h:114
unsigned int osd
Definition mission.h:112
char * npc_desc
Definition mission.h:97
unsigned int * cargo
Definition mission.h:106
unsigned int id
Definition mission.h:86
glTexture * portrait
Definition mission.h:93
nlua_env env
Definition mission.h:120
char * reward
Definition mission.h:92
char * desc
Definition mission.h:91
MissionMarker * markers
Definition mission.h:109
char * title
Definition mission.h:90
const MissionData * data
Definition mission.h:84
credits_t reward_value
Definition mission.h:100
int accepted
Definition mission.h:87
int osd_priority
Definition mission.h:115
char * npc
Definition mission.h:96
Stores a pilot commodity.
Definition pilot.h:223
const Commodity * commodity
Definition pilot.h:224
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:102
char * name
Definition space.h:105