naev 0.11.5
space.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <float.h>
11#include <math.h>
12#include <stdlib.h>
13#include "physfs.h"
14
15#include "naev.h"
18#include "space.h"
19
20#include "background.h"
21#include "conf.h"
22#include "damagetype.h"
23#include "dev_uniedit.h"
24#include "economy.h"
25#include "gatherable.h"
26#include "gui.h"
27#include "hook.h"
28#include "land.h"
29#include "log.h"
30#include "map.h"
31#include "map_overlay.h"
32#include "menu.h"
33#include "mission.h"
34#include "music.h"
35#include "ndata.h"
36#include "nebula.h"
37#include "nfile.h"
38#include "nlua.h"
39#include "nlua_pilot.h"
40#include "nlua_spob.h"
41#include "nlua_gfx.h"
42#include "nlua_camera.h"
43#include "nlua_tex.h"
44#include "nluadef.h"
45#include "nmath.h"
46#include "nstring.h"
47#include "ntime.h"
48#include "nxml.h"
49#include "opengl.h"
50#include "pause.h"
51#include "pilot.h"
52#include "player.h"
53#include "queue.h"
54#include "rng.h"
55#include "sound.h"
56#include "spfx.h"
57#include "start.h"
58#include "toolkit.h"
59#include "weapon.h"
60
61#define XML_SPOB_TAG "spob"
62#define XML_SYSTEM_TAG "ssys"
64#define SPOB_GFX_EXTERIOR_PATH_W 400
65#define SPOB_GFX_EXTERIOR_PATH_H 400
67/* used to overcome warnings due to 0 values */
68#define FLAG_POSSET (1<<0)
69#define FLAG_INTERFERENCESET (1<<1)
70#define FLAG_SERVICESSET (1<<2)
71#define FLAG_FACTIONSET (1<<3)
73#define DEBRIS_BUFFER 1000
75typedef struct spob_lua_file_s {
76 const char *filename;
77 nlua_env env;
78 int lua_mem;
80
83/*
84 * spob <-> system name stack
85 */
86static char** spobname_stack = NULL;
87static char** systemname_stack = NULL;
89/*
90 * Arrays.
91 */
92StarSystem *systems_stack = NULL;
93static Spob *spob_stack = NULL;
94static VirtualSpob *vspob_stack = NULL;
95/* TODO get rid of the stack_changed stuff, and just redo all the id/pointer stuff.
96 * Main issue will be redoing the Lua system/spob modules to handle such a
97 * case, but can be done with the weapon module as a referenc. */
98static int systemstack_changed = 0;
99static int spobstack_changed = 0;
100static MapShader **mapshaders = NULL;
102/*
103 * Misc.
104 */
105static int systems_loading = 1;
106StarSystem *cur_system = NULL;
108static glTexture *jumpbuoy_gfx = NULL;
109static int space_fchg = 0;
110static int space_simulating = 0;
112static Spob *space_landQueueSpob = NULL;
113
114/*
115 * Fleet spawning.
116 */
117int space_spawn = 1;
119/*
120 * Internal Prototypes.
121 */
122/* spob load */
123static int spob_parse( Spob *spob, const char *filename, Commodity **stdList );
124static int space_parseSpobs( xmlNodePtr parent, StarSystem* sys );
125static int spob_parsePresence( xmlNodePtr node, SpobPresence *ap );
126/* system load */
127static void system_init( StarSystem *sys );
128static int systems_load (void);
129static int system_parse( StarSystem *system, const char *filename );
130static int system_parseJumpPoint( const xmlNodePtr node, StarSystem *sys );
131static int system_parseJumpPointDiff( const xmlNodePtr node, StarSystem *sys );
132static int system_parseJumps( StarSystem *sys );
133static int system_parseAsteroidField( const xmlNodePtr node, StarSystem *sys );
134static int system_parseAsteroidExclusion( const xmlNodePtr node, StarSystem *sys );
135/* misc */
136static int spob_cmp( const void *p1, const void *p2 );
137static int getPresenceIndex( StarSystem *sys, int faction );
138static void system_scheduler( double dt, int init );
139/* Markers. */
140static int space_addMarkerSystem( int sysid, MissionMarkerType type );
141static int space_addMarkerSpob( int pntid, MissionMarkerType type );
142static int space_rmMarkerSystem( int sysid, MissionMarkerType type );
143static int space_rmMarkerSpob( int pntid, MissionMarkerType type );
144/* Render. */
145static void space_renderJumpPoint( const JumpPoint *jp, int i );
146static void space_renderSpob( const Spob *p );
147static void space_updateSpob( const Spob *p, double dt, double real_dt );
148/* Map shaders. */
149static const MapShader *mapshader_get( const char *name );
150/* Lua stuff. */
151static int spob_lua_cmp( const void *a, const void *b );
152static nlua_env spob_lua_get( int *mem, const char *filename );
153static void spob_lua_free( spob_lua_file *lf );
154/*
155 * Externed prototypes.
156 */
157int space_sysSave( xmlTextWriterPtr writer );
158int space_sysLoad( xmlNodePtr parent );
159
167const char* spob_getServiceName( int service )
168{
169 switch (service) {
170 case SPOB_SERVICE_LAND: return N_("Land");
171 case SPOB_SERVICE_INHABITED: return N_("Inhabited");
172 case SPOB_SERVICE_REFUEL: return N_("Refuel");
173 case SPOB_SERVICE_BAR: return N_("Bar");
174 case SPOB_SERVICE_MISSIONS: return N_("Missions");
175 case SPOB_SERVICE_COMMODITY: return N_("Commodity");
176 case SPOB_SERVICE_OUTFITS: return N_("Outfits");
177 case SPOB_SERVICE_SHIPYARD: return N_("Shipyard");
178 case SPOB_SERVICE_BLACKMARKET: return N_("Blackmarket");
179 }
180 return NULL;
181}
182
186int spob_getService( const char *name )
187{
188 if (strcasecmp(name,"Land")==0)
189 return SPOB_SERVICE_LAND;
190 else if (strcasecmp(name,"Inhabited")==0)
191 return SPOB_SERVICE_INHABITED;
192 else if (strcasecmp(name,"Refuel")==0)
193 return SPOB_SERVICE_REFUEL;
194 else if (strcasecmp(name,"Bar")==0)
195 return SPOB_SERVICE_BAR;
196 else if (strcasecmp(name,"Missions")==0)
197 return SPOB_SERVICE_MISSIONS;
198 else if (strcasecmp(name,"Commodity")==0)
199 return SPOB_SERVICE_COMMODITY;
200 else if (strcasecmp(name,"Outfits")==0)
201 return SPOB_SERVICE_OUTFITS;
202 else if (strcasecmp(name,"Shipyard")==0)
203 return SPOB_SERVICE_SHIPYARD;
204 else if (strcasecmp(name,"Blackmarket")==0)
205 return SPOB_SERVICE_BLACKMARKET;
206 return -1;
207}
208
215const char* spob_getClassName( const char *class )
216{
217 if (strcmp(class,"0")==0)
218 return _("Civilian Station");
219 else if (strcmp(class,"1")==0)
220 return _("Military Station");
221 else if (strcmp(class,"2")==0)
222 return _("Pirate Station");
223 else if (strcmp(class,"3")==0)
224 return _("Robotic Station");
225 else if (strcmp(class,"4")==0)
226 return _("Artificial Ecosystem");
227 else if (strcmp(class,"A")==0)
228 return _("Geothermal");
229 else if (strcmp(class,"B")==0)
230 return _("Geomorteus");
231 else if (strcmp(class,"C")==0)
232 return _("Geoinactive");
233 else if (strcmp(class,"D")==0)
234 return _("Asteroid/Moon");
235 else if (strcmp(class,"E")==0)
236 return _("Geoplastic");
237 else if (strcmp(class,"F")==0)
238 return _("Geometallic");
239 else if (strcmp(class,"G")==0)
240 return _("Geocrystaline");
241 else if (strcmp(class,"H")==0)
242 return _("Desert");
243 else if (strcmp(class,"I")==0)
244 return _("Gas Supergiant");
245 else if (strcmp(class,"J")==0)
246 return _("Gas Giant");
247 else if (strcmp(class,"K")==0)
248 return _("Adaptable");
249 else if (strcmp(class,"L")==0)
250 return _("Marginal");
251 else if (strcmp(class,"M")==0)
252 return _("Terrestrial");
253 else if (strcmp(class,"N")==0)
254 return _("Reducing");
255 else if (strcmp(class,"O")==0)
256 return _("Pelagic");
257 else if (strcmp(class,"P")==0)
258 return _("Glaciated");
259 else if (strcmp(class,"Q")==0)
260 return _("Variable");
261 else if (strcmp(class,"R")==0)
262 return _("Rogue");
263 else if (strcmp(class,"S")==0 || strcmp(class,"T")==0)
264 return _("Ultragiants");
265 else if (strcmp(class,"X")==0 || strcmp(class,"Y")==0 || strcmp(class,"Z")==0)
266 return _("Demon");
267 return class;
268}
269
276credits_t spob_commodityPrice( const Spob *p, const Commodity *c )
277{
278 const char *sysname = spob_getSystem( p->name );
279 const StarSystem *sys = system_get( sysname );
280 return economy_getPrice( c, sys, p );
281}
282
290credits_t spob_commodityPriceAtTime( const Spob *p, const Commodity *c, ntime_t t )
291{
292 const char *sysname = spob_getSystem( p->name );
293 const StarSystem *sys = system_get( sysname );
294 return economy_getPriceAtTime( c, sys, p, t );
295}
296
303void spob_averageSeenPricesAtTime( const Spob *p, const ntime_t tupdate )
304{
305 economy_averageSeenPricesAtTime( p, tupdate );
306}
307
316int spob_averageSpobPrice( const Spob *p, const Commodity *c, credits_t *mean, double *std)
317{
318 return economy_getAverageSpobPrice( c, p, mean, std );
319}
320
326void system_updateAsteroids( StarSystem *sys )
327{
328 double density = 0.;
329 for (int i=0; i<array_size(sys->asteroids); i++) {
330 AsteroidAnchor *ast = &sys->asteroids[i];
331 density += ast->area * ast->density / ASTEROID_REF_AREA;
332
333 /* Have to subtract excluded area. */
334 for (int j=0; j<array_size(sys->astexclude); j++) {
335 AsteroidExclusion *exc = &sys->astexclude[j];
336 density -= CollideCircleIntersection( &ast->pos, ast->radius, &exc->pos, exc->radius ) * ast->density / ASTEROID_REF_AREA;
337 }
338 }
339 sys->asteroid_density = density;
340}
341
349int spob_setFaction( Spob *p, int faction )
350{
351 p->presence.faction = faction;
352 return 0;
353}
354
363{
364 array_grow( &p->commodities ) = c;
365 array_grow( &p->commodityPrice ).price = c->price;
366 return 0;
367}
368
376int spob_addService( Spob *p, int service )
377{
378 p->services |= service;
379
380 if (service & SPOB_SERVICE_COMMODITY) {
381 const char *sysname;
382 StarSystem *sys;
383
384 /* Only try to add standard commodities if there aren't any. */
385 if (p->commodities!=NULL)
386 return 0;
387 Commodity **stdList = standard_commodities();
388 p->commodities = array_create( Commodity* );
389 p->commodityPrice = array_create( CommodityPrice );
390 for (int i=0; i<array_size(stdList); i++)
391 spob_addCommodity( p, stdList[i] );
392 array_free( stdList );
393
394 /* Clean up economy status. */
397
398 /* Try to figure out the system. */
399 sysname = spob_getSystem( p->name );
400 if (sysname==NULL) {
401 DEBUG(_("Spob '%s' not in system. Not initializing economy."), p->name);
402 return 0;
403 }
404 sys = system_get( sysname );
405 economy_initialiseSingleSystem( sys, p );
406 }
407
408 return 0;
409}
410
418int spob_rmService( Spob *p, int service )
419{
420 p->services &= ~service;
421 return 0;
422}
423
431int spob_rename( Spob *p, char *newname )
432{
433 int found = 0;
434 for (int i=0; i<array_size(spobname_stack); i++) {
435 if (strcmp(spobname_stack[i], p->name)==0) {
436 spobname_stack[i] = newname;
437 found = 1;
438 break;
439 }
440 }
441 if (!found)
442 WARN(_("Renaming spob '%s', but not found in name stack!"),p->name);
443 free( p->name );
444 p->name = newname;
445
446 /* Order changed, so no more bsearch for us. */
448
449 return 0;
450}
451
455int space_jumpDistance( const Pilot *p, const JumpPoint *jp )
456{
457 double r = jp->radius * p->stats.jump_distance;
458 if (pilot_isFlag( p, PILOT_STEALTH )) /* Stealth gives a jump distance bonus. */
459 r *= 3.;
460 return r;
461}
462
470{
471 double d, r;
472 JumpPoint *jp;
473
474 /* Must not have the nojump flag. */
475 if (pilot_isFlag(p, PILOT_NOJUMP))
476 return 0;
477
478 /* Must have fuel. */
479 if (p->fuel < p->fuel_consumption)
480 return 0;
481
482 /* Must have hyperspace target. */
483 if (0 > p->nav_hyperspace || p->nav_hyperspace >= array_size(cur_system->jumps))
484 return 0;
485
486 /* Get the jump. */
487 jp = &cur_system->jumps[ p->nav_hyperspace ];
488
489 /* Check distance. */
490 r = space_jumpDistance( p, jp );
491 d = vec2_dist2( &p->solid.pos, &jp->pos );
492 if (d > pow2(r))
493 return 0;
494 return 1;
495}
496
504{
505 if (pilot_isFlag(p, PILOT_NOJUMP))
506 return -2;
507 if (p->fuel < p->fuel_consumption)
508 return -3;
509 if (!space_canHyperspace(p))
510 return -1;
511
512 /* pilot is now going to get automatically ready for hyperspace */
513 pilot_setFlag(p, PILOT_HYP_PREP);
514 return 0;
515}
516
527int space_calcJumpInPos( const StarSystem *in, const StarSystem *out, vec2 *pos, vec2 *vel, double *dir, const Pilot *p )
528{
529 JumpPoint *jp;
530 double a, d, x, y;
531 double ea, ed;
532
533 /* Find the entry system. */
534 jp = NULL;
535 for (int i=0; i<array_size(in->jumps); i++)
536 if (in->jumps[i].target == out)
537 jp = &in->jumps[i];
538
539 /* Must have found the jump. */
540 if (jp == NULL) {
541 WARN(_("Unable to find jump in point for '%s' in '%s': not connected"), out->name, in->name);
542 return -1;
543 }
544
545 /* Base position target. */
546 x = jp->pos.x;
547 y = jp->pos.y;
548
549 /* Calculate offset from target position. */
550 a = 2.*M_PI - jp->angle;
551 d = RNGF()*(HYPERSPACE_ENTER_MAX-HYPERSPACE_ENTER_MIN) + HYPERSPACE_ENTER_MIN;
552 if ((p!=NULL) && pilot_isFlag(p, PILOT_STEALTH))
553 d *= 1.4; /* Jump in from further out when coming in from stealth. */
554
555 /* Calculate new position. */
556 x += d*cos(a);
557 y += d*sin(a);
558
559 /* Add some error. */
560 ea = 2.*M_PI*RNGF();
561 ed = jp->radius/2.;
562 if (p != NULL) {
563 ed *= p->stats.jump_distance; /* larger variability. */
564 if (pilot_isFlag(p, PILOT_STEALTH))
565 ed *= 2.;
566 }
567 x += ed*cos(ea);
568 y += ed*sin(ea);
569
570 /* Set new position. */
571 vec2_cset( pos, x, y );
572
573 /* Set new velocity. */
574 a += M_PI;
575 vec2_cset( vel, HYPERSPACE_VEL*cos(a), HYPERSPACE_VEL*sin(a) );
576
577 /* Set direction. */
578 *dir = a;
579
580 return 0;
581}
582
590char** space_getFactionSpob( const int *factions, int landable )
591{
592 char **tmp = array_create( char* );
593 for (int i=0; i<array_size(systems_stack); i++) {
594 for (int j=0; j<array_size(systems_stack[i].spobs); j++) {
595 Spob *spob = systems_stack[i].spobs[j];
596 int f = 0;
597 for (int k=0; k<array_size(factions); k++) {
598 if (spob->presence.faction == factions[k]) {
599 f = 1;
600 break;
601 }
602 }
603 if (!f)
604 continue;
605
606 /* Check landable. */
607 if (landable) {
608 spob_updateLand( spob );
609 if (!spob->can_land)
610 continue;
611 }
612
613 /* This is expensive so we probably want to do it last. */
615 continue;
616
617 array_push_back( &tmp, spob->name );
618 break; /* no need to check all factions */
619 }
620 }
621
622 return tmp;
623}
624
633const char* space_getRndSpob( int landable, unsigned int services,
634 int (*filter)(Spob *p))
635{
636 char *res = NULL;
637 Spob **tmp = array_create( Spob* );
638
639 for (int i=0; i<array_size(systems_stack); i++) {
640 for (int j=0; j<array_size(systems_stack[i].spobs); j++) {
641 Spob *pnt = systems_stack[i].spobs[j];
642
643 if (services && (spob_hasService(pnt, services) != services))
644 continue;
645
646 if ((filter != NULL) && !filter(pnt))
647 continue;
648
649 array_push_back( &tmp, pnt );
650 }
651 }
652
653 /* Second filter. */
654 arrayShuffle( (void**)tmp );
655 for (int i=0; i < array_size(tmp); i++) {
656 Spob *pnt = tmp[i];
657
658 /* We put expensive calculations here to minimize executions. */
659 if (landable) {
660 spob_updateLand( pnt );
661 if (!pnt->can_land)
662 continue;
663 }
665 continue;
666
667 /* We want the name, not the actual spob. */
668 res = tmp[i]->name;
669 break;
670 }
671 array_free(tmp);
672
673 return res;
674}
675
687double system_getClosest( const StarSystem *sys, int *pnt, int *jp, int *ast, int *fie, double x, double y )
688{
689 double d = HUGE_VAL;
690
691 /* Default output. */
692 *pnt = -1;
693 *jp = -1;
694 *ast = -1;
695 *fie = -1;
696
697 /* Spobs. */
698 for (int i=0; i<array_size(sys->spobs); i++) {
699 double td;
700 Spob *p = sys->spobs[i];
701 if (!spob_isKnown(p))
702 continue;
703 td = pow2(x-p->pos.x) + pow2(y-p->pos.y);
704 if (td < d) {
705 *pnt = i;
706 d = td;
707 }
708 }
709
710 /* Asteroids. */
711 for (int i=0; i<array_size(sys->asteroids); i++) {
712 AsteroidAnchor *f = &sys->asteroids[i];
713 for (int k=0; k<f->nb; k++) {
714 double td;
715 Asteroid *as = &f->asteroids[k];
716
717 /* Skip non-interactive asteroids. */
718 if (as->state != ASTEROID_FG)
719 continue;
720
721 /* Skip out of range asteroids */
722 if (!pilot_inRangeAsteroid( player.p, k, i ))
723 continue;
724
725 td = pow2(x-as->sol.pos.x) + pow2(y-as->sol.pos.y);
726 if (td < d) {
727 *pnt = -1; /* We must clear spob target as asteroid is closer. */
728 *ast = k;
729 *fie = i;
730 d = td;
731 }
732 }
733 }
734
735 /* Jump points. */
736 for (int i=0; i<array_size(sys->jumps); i++) {
737 double td;
738 JumpPoint *j = &sys->jumps[i];
739 if (!jp_isUsable(j))
740 continue;
741 td = pow2(x-j->pos.x) + pow2(y-j->pos.y);
742 if (td < d) {
743 *pnt = -1; /* We must clear spob target as jump point is closer. */
744 *ast = -1;
745 *fie = -1;
746 *jp = i;
747 d = td;
748 }
749 }
750 return d;
751}
752
766double system_getClosestAng( const StarSystem *sys, int *pnt, int *jp, int *ast, int *fie, double x, double y, double ang )
767{
768 double a;
769
770 /* Default output. */
771 *pnt = -1;
772 *jp = -1;
773 a = ang + M_PI;
774
775 /* Spobs. */
776 for (int i=0; i<array_size(sys->spobs); i++) {
777 Spob *p = sys->spobs[i];
778 double ta = atan2( y - p->pos.y, x - p->pos.x);
779 if ( ABS(angle_diff(ang, ta)) < ABS(angle_diff(ang, a))) {
780 *pnt = i;
781 a = ta;
782 }
783 }
784
785 /* Asteroids. */
786 for (int i=0; i<array_size(sys->asteroids); i++) {
787 AsteroidAnchor *f = &sys->asteroids[i];
788 for (int k=0; k<f->nb; k++) {
789 double ta;
790 Asteroid *as = &f->asteroids[k];
791
792 /* Skip non-interactive asteroids. */
793 if (as->state != ASTEROID_FG)
794 continue;
795
796 ta = atan2( y - as->sol.pos.y, x - as->sol.pos.x);
797 if ( ABS(angle_diff(ang, ta)) < ABS(angle_diff(ang, a))) {
798 *pnt = -1; /* We must clear spob target as asteroid is closer. */
799 *ast = k;
800 *fie = i;
801 a = ta;
802 }
803 }
804 }
805
806 /* Jump points. */
807 for (int i=0; i<array_size(sys->jumps); i++) {
808 JumpPoint *j = &sys->jumps[i];
809 double ta = atan2( y - j->pos.y, x - j->pos.x);
810 if ( ABS(angle_diff(ang, ta)) < ABS(angle_diff(ang, a))) {
811 *ast = -1;
812 *fie = -1;
813 *pnt = -1; /* We must clear the rest as jump point is closer. */
814 *jp = i;
815 a = ta;
816 }
817 }
818 return a;
819}
820
826int space_sysReachable( const StarSystem *sys )
827{
828 if (sys_isKnown(sys))
829 return 1; /* it is known */
830
831 /* check to see if it is adjacent to known */
832 for (int i=0; i<array_size(sys->jumps); i++) {
833 const JumpPoint *jp = sys->jumps[i].returnJump;
834 if (jp && jp_isUsable( jp ))
835 return 1;
836 }
837
838 return 0;
839}
840
846int space_sysReallyReachable( const char* sysname )
847{
848 StarSystem** path;
849
850 if (strcmp(sysname,cur_system->name)==0)
851 return 1;
852 path = map_getJumpPath( cur_system->name, NULL, sysname, 1, 1, NULL, NULL );
853 if (path != NULL) {
854 array_free(path);
855 return 1;
856 }
857 return 0;
858}
859
865int space_sysReachableFromSys( const StarSystem *target, const StarSystem *sys )
866{
867 /* check to see if sys contains a known jump point to target */
868 const JumpPoint *jp = jump_getTarget( target, sys );
869 if (jp == NULL)
870 return 0;
871 else if (jp_isUsable( jp ))
872 return 1;
873 return 0;
874}
875
879StarSystem* system_getAll (void)
880{
881 return systems_stack;
882}
883
890const char *system_existsCase( const char* sysname )
891{
892 for (int i=0; i<array_size(systems_stack); i++)
893 if (strcasecmp(sysname, systems_stack[i].name)==0)
894 return systems_stack[i].name;
895 return NULL;
896}
897
901char **system_searchFuzzyCase( const char* sysname, int *n )
902{
903 int len;
904 char **names;
905
906 /* Overallocate to maximum. */
907 names = malloc( sizeof(char*) * array_size(systems_stack) );
908
909 /* Do fuzzy search. */
910 len = 0;
911 for (int i=0; i<array_size(systems_stack); i++) {
912 StarSystem *sys = &systems_stack[i];
913 if (SDL_strcasestr( _(sys->name), sysname ) != NULL) {
914 names[len] = sys->name;
915 len++;
916 }
917 else if ((sys->features!=NULL) && SDL_strcasestr( _(sys->features), sysname ) != NULL) {
918 names[len] = sys->name;
919 len++;
920 }
921 else {
922 for (int j=0; j<array_size(sys->spobs); j++) {
923 const Spob *spob = sys->spobs[j];
924 if ((spob->feature != NULL) && SDL_strcasestr( _(spob->feature), sysname ) != NULL) {
925 names[len] = sys->name;
926 len++;
927 break;
928 }
929 }
930 }
931 }
932
933 /* Free if empty. */
934 if (len == 0) {
935 free(names);
936 names = NULL;
937 }
938
939 *n = len;
940 return names;
941}
942
946static int system_cmp( const void *p1, const void *p2 )
947{
948 const StarSystem *s1, *s2;
949 s1 = (const StarSystem*) p1;
950 s2 = (const StarSystem*) p2;
951 return strcmp(s1->name,s2->name);
952}
953
960StarSystem* system_get( const char* sysname )
961{
962 if (sysname == NULL)
963 return NULL;
964
965 /* Somethig was added, and since we store IDs too, everything can't be sorted anymore by name... */
967 for (int i=0; i<array_size(systems_stack); i++)
968 if (strcmp(systems_stack[i].name, sysname)==0)
969 return &systems_stack[i];
970 WARN(_("System '%s' not found in stack"), sysname);
971 return NULL;
972 }
973
974 const StarSystem s = {.name = (char*)sysname};
975 StarSystem *found = bsearch( &s, systems_stack, array_size(systems_stack), sizeof(StarSystem), system_cmp );
976 if (found != NULL)
977 return found;
978
979 WARN(_("System '%s' not found in stack"), sysname);
980 return NULL;
981}
982
989StarSystem* system_getIndex( int id )
990{
991 return &systems_stack[ id ];
992}
993
1000int system_index( const StarSystem *sys )
1001{
1002 return sys->id;
1003}
1004
1011int spob_hasSystem( const Spob *spb )
1012{
1013 for (int i=0; i<array_size(spobname_stack); i++)
1014 if (strcmp(spobname_stack[i],spb->name)==0)
1015 return 1;
1016 return 0;
1017}
1018
1025const char* spob_getSystem( const char* spobname )
1026{
1027 for (int i=0; i<array_size(spobname_stack); i++)
1028 if (strcmp(spobname_stack[i],spobname)==0)
1029 return systemname_stack[i];
1030 DEBUG(_("Spob '%s' is not placed in a system"), spobname);
1031 return NULL;
1032}
1033
1037static int spob_cmp( const void *p1, const void *p2 )
1038{
1039 const Spob *pnt1, *pnt2;
1040 pnt1 = (const Spob*) p1;
1041 pnt2 = (const Spob*) p2;
1042 return strcmp(pnt1->name,pnt2->name);
1043}
1044
1051Spob* spob_get( const char* spobname )
1052{
1053 if (spobname==NULL) {
1054 WARN(_("Trying to find NULL spob…"));
1055 return NULL;
1056 }
1057
1058 /* Somethig was added, and since we store IDs too, everything can't be sorted anymore by name... */
1059 if (spobstack_changed) {
1060 for (int i=0; i<array_size(spob_stack); i++)
1061 if (strcmp(spob_stack[i].name, spobname)==0)
1062 return &spob_stack[i];
1063 WARN(_("Spob '%s' not found in the universe"), spobname);
1064 return NULL;
1065 }
1066
1067 const Spob p = {.name = (char*)spobname};
1068 Spob *found = bsearch( &p, spob_stack, array_size(spob_stack), sizeof(Spob), spob_cmp );
1069 if (found != NULL)
1070 return found;
1071
1072 WARN(_("Spob '%s' not found in the universe"), spobname);
1073 return NULL;
1074}
1075
1083{
1084 /* Validity check. */
1085 if ((ind < 0) || (ind >= array_size(spob_stack))) {
1086 WARN(_("Spob index '%d' out of range (max %d)"), ind, array_size(spob_stack));
1087 return NULL;
1088 }
1089
1090 return &spob_stack[ ind ];
1091}
1092
1099int spob_index( const Spob *p )
1100{
1101 return p->id;
1102}
1103
1108{
1109 return spob_stack;
1110}
1111
1116{
1117 spob_setFlag(p, SPOB_KNOWN);
1118}
1119
1126int spob_exists( const char* spobname )
1127{
1128 for (int i=0; i<array_size(spob_stack); i++)
1129 if (strcmp(spob_stack[i].name,spobname)==0)
1130 return 1;
1131 return 0;
1132}
1133
1140const char* spob_existsCase( const char* spobname )
1141{
1142 for (int i=0; i<array_size(spob_stack); i++)
1143 if (strcasecmp(spob_stack[i].name,spobname)==0)
1144 return spob_stack[i].name;
1145 return NULL;
1146}
1147
1151char **spob_searchFuzzyCase( const char* spobname, int *n )
1152{
1153 int len;
1154 char **names;
1155
1156 /* Overallocate to maximum. */
1157 names = malloc( sizeof(char*) * array_size(spob_stack) );
1158
1159 /* Do fuzzy search. */
1160 len = 0;
1161 for (int i=0; i<array_size(spob_stack); i++) {
1162 Spob *spob = &spob_stack[i];
1163 if (SDL_strcasestr( spob_name(spob), spobname ) != NULL) {
1164 names[len] = spob->name;
1165 len++;
1166 }
1167 else if ((spob->feature != NULL) && SDL_strcasestr( _(spob->feature), spobname ) != NULL) {
1168 names[len] = spob->name;
1169 len++;
1170 }
1171 }
1172
1173 /* Free if empty. */
1174 if (len == 0) {
1175 free(names);
1176 names = NULL;
1177 }
1178
1179 *n = len;
1180 return names;
1181}
1182
1187{
1188 return vspob_stack;
1189}
1190
1194static int virtualspob_cmp( const void *p1, const void *p2 )
1195{
1196 const VirtualSpob *v1, *v2;
1197 v1 = (const VirtualSpob*) p1;
1198 v2 = (const VirtualSpob*) p2;
1199 return strcmp(v1->name,v2->name);
1200}
1201
1205VirtualSpob* virtualspob_get( const char *name )
1206{
1207 const VirtualSpob va = {.name = (char*)name};
1208 VirtualSpob *found = bsearch( &va, vspob_stack, array_size(vspob_stack), sizeof(VirtualSpob), virtualspob_cmp );
1209 if (found != NULL)
1210 return found;
1211 WARN(_("Virtual Spob '%s' not found in the universe"), name);
1212 return NULL;
1213}
1214
1222JumpPoint* jump_get( const char* jumpname, const StarSystem* sys )
1223{
1224 if (jumpname==NULL) {
1225 WARN(_("Trying to find NULL jump point..."));
1226 return NULL;
1227 }
1228
1229 for (int i=0; i<array_size(sys->jumps); i++) {
1230 JumpPoint *jp = &sys->jumps[i];
1231 if (strcmp(jp->target->name,jumpname)==0)
1232 return jp;
1233 }
1234
1235 WARN(_("Jump point '%s' not found in %s"), jumpname, sys->name);
1236 return NULL;
1237}
1238
1246JumpPoint* jump_getTarget( const StarSystem* target, const StarSystem* sys )
1247{
1248 for (int i=0; i<array_size(sys->jumps); i++) {
1249 JumpPoint *jp = &sys->jumps[i];
1250 if (jp->target == target)
1251 return jp;
1252 }
1253 WARN(_("Jump point to '%s' not found in %s"), target->name, sys->name);
1254 return NULL;
1255}
1256
1260const char *jump_getSymbol( const JumpPoint *jp )
1261{
1262 if (jp_isFlag(jp, JP_HIDDEN))
1263 return "* ";
1264 return "";
1265}
1266
1273static void system_scheduler( double dt, int init )
1274{
1275 /* Go through all the factions and reduce the timer. */
1276 for (int i=0; i < array_size(cur_system->presence); i++) {
1277 int n;
1278 nlua_env env;
1279 SystemPresence *p = &cur_system->presence[i];
1280 if (p->value <= 0.)
1281 continue;
1282
1283 env = faction_getScheduler( p->faction );
1284
1285 /* Must have a valid scheduler. */
1286 if (env==LUA_NOREF)
1287 continue;
1288
1289 /* Spawning is disabled for this faction. */
1290 if (p->disabled)
1291 continue;
1292
1293 /* Run the appropriate function. */
1294 if (init) {
1295 nlua_getenv( naevL, env, "create" ); /* f */
1296 if (lua_isnil(naevL,-1)) {
1297 WARN(_("Lua Spawn script for faction '%s' missing obligatory entry point 'create'."),
1298 faction_name( p->faction ) );
1299 lua_pop(naevL,1);
1300 continue;
1301 }
1302 n = 0;
1303 }
1304 else {
1305 /* Decrement dt, only continue */
1306 p->timer -= dt;
1307 if (p->timer >= 0.)
1308 continue;
1309
1310 nlua_getenv( naevL, env, "spawn" ); /* f */
1311 if (lua_isnil(naevL,-1)) {
1312 WARN(_("Lua Spawn script for faction '%s' missing obligatory entry point 'spawn'."),
1313 faction_name( p->faction ) );
1314 lua_pop(naevL,1);
1315 continue;
1316 }
1317 lua_pushnumber( naevL, p->curUsed ); /* f, presence */
1318 n = 1;
1319 }
1320 lua_pushnumber( naevL, p->value ); /* f, [arg,], max */
1321
1322 /* Actually run the function. */
1323 if (nlua_pcall(env, n+1, 2)) { /* error has occurred */
1324 WARN(_("Lua Spawn script for faction '%s' : %s"),
1325 faction_name( p->faction ), lua_tostring(naevL,-1));
1326 lua_pop(naevL,1);
1327 continue;
1328 }
1329
1330 /* Output is handled the same way. */
1331 if (!lua_isnumber(naevL,-2)) {
1332 WARN(_("Lua spawn script for faction '%s' failed to return timer value."),
1333 faction_name( p->faction ) );
1334 lua_pop(naevL,2);
1335 continue;
1336 }
1337 p->timer += lua_tonumber(naevL,-2);
1338 /* Handle table if it exists. */
1339 if (lua_istable(naevL,-1)) {
1340 lua_pushnil(naevL); /* tk, k */
1341 while (lua_next(naevL,-2) != 0) { /* tk, k, v */
1342 Pilot *pilot;
1343
1344 /* Must be table. */
1345 if (!lua_istable(naevL,-1)) {
1346 WARN(_("Lua spawn script for faction '%s' returns invalid data (not a table)."),
1347 faction_name( p->faction ) );
1348 lua_pop(naevL,2); /* tk, k */
1349 continue;
1350 }
1351
1352 lua_getfield( naevL, -1, "pilot" ); /* tk, k, v, p */
1353 if (!lua_ispilot(naevL,-1)) {
1354 WARN(_("Lua spawn script for faction '%s' returns invalid data (not a pilot)."),
1355 faction_name( p->faction ) );
1356 lua_pop(naevL,2); /* tk, k */
1357 continue;
1358 }
1359 pilot = pilot_get( lua_topilot(naevL,-1) );
1360 if (pilot == NULL) {
1361 lua_pop(naevL,2); /* tk, k */
1362 continue;
1363 }
1364 lua_pop(naevL,1); /* tk, k, v */
1365 lua_getfield( naevL, -1, "presence" ); /* tk, k, v, p */
1366 if (!lua_isnumber(naevL,-1)) {
1367 WARN(_("Lua spawn script for faction '%s' returns invalid data (not a number)."),
1368 faction_name( p->faction ) );
1369 lua_pop(naevL,2); /* tk, k */
1370 continue;
1371 }
1372 pilot->presence = lua_tonumber(naevL,-1);
1373 if (pilot->faction != p->faction) {
1374 int pi;
1375 WARN( _("Lua spawn script for faction '%s' actually spawned a '%s' pilot."),
1376 faction_name( p->faction ),
1377 faction_name( pilot->faction ) );
1378 pi = getPresenceIndex( cur_system, pilot->faction );
1379 p = &cur_system->presence[pi];
1380 }
1381 p->curUsed += pilot->presence;
1382 lua_pop(naevL,2); /* tk, k */
1383 }
1384 }
1385 lua_pop(naevL,2);
1386 }
1387}
1388
1393{
1394 space_fchg = 1;
1395}
1396
1401{
1402 if (space_landQueueSpob != NULL) {
1403 land( space_landQueueSpob, 0 );
1404 space_landQueueSpob = NULL;
1405 }
1406}
1407
1414void space_update( double dt, double real_dt )
1415{
1416 /* Needs a current system. */
1417 if (cur_system == NULL)
1418 return;
1419
1420 /* If spawning is enabled, call the scheduler. */
1421 if (space_spawn)
1422 system_scheduler( dt, 0 );
1423
1424 /*
1425 * Nebula.
1426 */
1427 nebu_update( dt );
1428 if (cur_system->nebu_volatility > 0.) {
1429 Pilot *const* pilot_stack;
1430 Damage dmg;
1431 dmg.type = dtype_get("nebula");
1432 dmg.damage = cur_system->nebu_volatility * dt;
1433 dmg.penetration = 1.; /* Full penetration. */
1434 dmg.disable = 0.;
1435
1436 /* Damage pilots in volatile systems. */
1438 for (int i=0; i<array_size(pilot_stack); i++)
1439 pilot_hit( pilot_stack[i], NULL, NULL, &dmg, NULL, LUA_NOREF, 0 );
1440 }
1441
1442 /* Faction updates. */
1443 if (space_fchg) {
1444 for (int i=0; i<array_size(cur_system->spobs); i++)
1445 spob_updateLand( cur_system->spobs[i] );
1446
1447 /* Verify land authorization is still valid. */
1448 if ((player.p != NULL) && (player.p->nav_spob >= 0) && player_isFlag(PLAYER_LANDACK))
1450
1452 space_fchg = 0;
1453 }
1454
1455 if (!space_simulating) {
1456 int found_something = 0;
1457 /* Spob updates */
1458 for (int i=0; i<array_size(cur_system->spobs); i++) {
1459 HookParam hparam[3];
1460 Spob *pnt = cur_system->spobs[i];
1461
1462 /* Must update in some cases. */
1463 space_updateSpob( pnt, dt, real_dt );
1464
1465 /* Discovering is disabled. */
1466 if (player.discover_off)
1467 continue;
1468
1469 /* Handle discoveries. */
1470 if (spob_isKnown( pnt ) || !pilot_inRangeSpob( player.p, i ))
1471 continue;
1472
1473 spob_setKnown( pnt );
1474 player_message( _("You discovered #%c%s#0."),
1475 spob_getColourChar( pnt ),
1476 spob_name( pnt ) );
1477 hparam[0].type = HOOK_PARAM_STRING;
1478 hparam[0].u.str = "spob";
1479 hparam[1].type = HOOK_PARAM_SPOB;
1480 hparam[1].u.la = pnt->id;
1481 hparam[2].type = HOOK_PARAM_SENTINEL;
1482 hooks_runParam( "discover", hparam );
1483 found_something = 1;
1484 pnt->map_alpha = 0.;
1485 }
1486
1487 /* Jump point updates */
1488 for (int i=0; i<array_size(cur_system->jumps); i++) {
1489 HookParam hparam[3];
1490 JumpPoint *jp = &cur_system->jumps[i];
1491
1492 /* Discovering is disabled. */
1493 if (player.discover_off)
1494 continue;
1495
1496 if (jp_isKnown(jp))
1497 continue;
1498 if (jp_isFlag(jp,JP_EXITONLY))
1499 continue;
1500 if (!(pilot_inRangeJump( player.p, i )))
1501 continue;
1502
1503 jp_setFlag( jp, JP_KNOWN );
1504 player_message( _("You discovered a Jump Point.") );
1505 hparam[0].type = HOOK_PARAM_STRING;
1506 hparam[0].u.str = "jump";
1507 hparam[1].type = HOOK_PARAM_JUMP;
1508 hparam[1].u.lj.srcid = cur_system->id;
1509 hparam[1].u.lj.destid = jp->target->id;
1510 hparam[2].type = HOOK_PARAM_SENTINEL;
1511 hooks_runParam( "discover", hparam );
1512 found_something = 1;
1513 jp->map_alpha = 0.;
1514 }
1515
1516 if (found_something)
1517 ovr_refresh();
1518 }
1519
1520 /* Update the gatherable objects. */
1521 gatherable_update( dt );
1522
1523 /* Asteroids/Debris update */
1524 asteroids_update( dt );
1525}
1526
1531{
1532 return space_simulating;
1533}
1534
1539{
1541}
1542
1549void space_init( const char* sysname, int do_simulate )
1550{
1551 const double fps_min_simulation = fps_min;
1552 const StarSystem *oldsys = cur_system;
1553
1554 /* cleanup some stuff */
1555 player_clear(); /* clears targets */
1556 ovr_mrkClear(); /* Clear markers when jumping. */
1557 pilots_clean(1); /* destroy non-persistent pilots */
1558 weapon_clear(); /* get rid of all the weapons */
1559 spfx_clear(); /* get rid of the explosions */
1560 gatherable_free(); /* get rid of gatherable stuff. */
1561 background_clear(); /* Get rid of the background. */
1562 factions_clearDynamic(); /* get rid of dynamic factions. */
1563 space_spawn = 1; /* spawn is enabled by default. */
1564
1565 /* Clear persistent pilot stuff. */
1566 if (player.p != NULL) {
1567 Pilot *const* pilot_stack = pilot_getAll();
1568 for (int i=0; i<array_size(pilot_stack); i++) {
1569 Pilot *p = pilot_stack[i];
1570 pilot_lockClear( p );
1571 pilot_clearTimers( p ); /* Clear timers. */
1572 }
1573 }
1574
1575 if ((sysname==NULL) && (cur_system==NULL))
1576 ERR(_("Cannot reinit system if there is no system previously loaded"));
1577 else if (sysname!=NULL) {
1578 cur_system = system_get( sysname );
1579 if (cur_system == NULL) {
1580 WARN(_("System '%s' not found, trying random system!"),sysname);
1582 }
1583 char *nt = ntime_pretty(0, 2);
1584
1585 player_message(_("#oEntering System %s on %s."), _(sysname), nt);
1586 if (cur_system->nebu_volatility > 0.)
1587 player_message(_("#rWARNING - Volatile nebula detected in %s! Taking %.1f %s damage!"), _(sysname), cur_system->nebu_volatility, UNIT_POWER );
1588 free(nt);
1589
1590 /* Handle background */
1591 if (cur_system->nebu_density > 0.) {
1592 /* Background is Nebula */
1593 nebu_prep( cur_system->nebu_density, cur_system->nebu_volatility, cur_system->nebu_hue );
1594
1595 /* Set up sound. */
1596 sound_env( SOUND_ENV_NEBULA, cur_system->nebu_density );
1597 }
1598 else {
1599 /* Background is starry */
1600 background_initDust( cur_system->spacedust );
1601
1602 /* Set up sound. */
1603 sound_env( SOUND_ENV_NORMAL, 0. );
1604 }
1605 }
1606
1607 /* Update after setting cur_system. */
1608 if ((oldsys != NULL && oldsys->stats != NULL) || cur_system->stats != NULL) {
1609 Pilot *const* pilot_stack = pilot_getAll();
1610 for (int i=0; i<array_size(pilot_stack); i++) {
1611 Pilot *p = pilot_stack[i];
1612 pilot_calcStats( p );
1613 if (pilot_isWithPlayer(p))
1614 pilot_setFlag( p, PILOT_HIDE );
1615 }
1616 }
1617
1618 /* Set up spobs. */
1619 for (int i=0; i<array_size(cur_system->spobs); i++) {
1620 Spob *pnt = cur_system->spobs[i];
1621 pnt->land_override = 0;
1622 spob_updateLand( pnt );
1623 }
1624
1625 /* See if we should get a new music song. */
1626 if ((player.p != NULL) && do_simulate)
1627 music_choose(NULL);
1628
1629 /* Reset new trails and set up quadtrees. */
1632
1633 /* Reset any schedules and used presence. */
1634 for (int i=0; i<array_size(cur_system->presence); i++) {
1635 cur_system->presence[i].curUsed = 0;
1636 cur_system->presence[i].timer = 0.;
1637 cur_system->presence[i].disabled = 0;
1638 }
1639
1640 /* Load graphics. */
1642
1643 /* Call the scheduler. */
1644 system_scheduler( 0., 1 );
1645
1646 /* we now know this system */
1647 sys_setFlag(cur_system,SYSTEM_KNOWN);
1648
1649 /* Simulate system. */
1650 space_simulating = 1;
1652 asteroids_init(); /* Set up asteroids. */
1653 if (player.p != NULL) {
1654 Pilot *const* pilot_stack = pilot_getAll();
1655 pilot_setFlag( player.p, PILOT_HIDE );
1656 for (int i=0; i<array_size(pilot_stack); i++) {
1657 Pilot *p = pilot_stack[i];
1658 if (pilot_isWithPlayer(p))
1659 pilot_setFlag( p, PILOT_HIDE );
1660 }
1661 }
1663 if (do_simulate) {
1664 int n, s;
1665 /* Uint32 time = SDL_GetTicks(); */
1666 s = sound_disabled;
1667 sound_disabled = 1;
1668 ntime_allowUpdate( 0 );
1669 n = SYSTEM_SIMULATE_TIME_PRE / fps_min_simulation;
1670 for (int i=0; i<n; i++)
1671 update_routine( fps_min_simulation, 0 );
1673 n = SYSTEM_SIMULATE_TIME_POST / fps_min_simulation;
1674 for (int i=0; i<n; i++)
1675 update_routine( fps_min_simulation, 0 );
1676 ntime_allowUpdate( 1 );
1677 sound_disabled = s;
1678 /*
1679 if (conf.devmode)
1680 DEBUG(_("System simulated in %.3f s"), (SDL_GetTicks()-time)/1000.);
1681 */
1682 }
1684 if (player.p != NULL) {
1685 Pilot *const* pilot_stack = pilot_getAll();
1686 pilot_rmFlag( player.p, PILOT_HIDE );
1687 for (int i=0; i<array_size(pilot_stack); i++) {
1688 Pilot *p = pilot_stack[i];
1689 if (pilot_isWithPlayer(p))
1690 pilot_rmFlag( p, PILOT_HIDE );
1691 }
1692 }
1694 space_simulating = 0;
1695
1696 /* Refresh overlay if necessary (player kept it open). */
1697 ovr_refresh();
1698
1699 /* Update gui. */
1700 gui_setSystem();
1701
1702 /* Start background. */
1703 background_load( cur_system->background );
1704}
1705
1710{
1711 Spob *p, *old_stack;
1712 int realloced;
1713
1714 if (!systems_loading)
1716
1717 /* Grow and initialize memory. */
1718 old_stack = spob_stack;
1719 p = &array_grow( &spob_stack );
1720 realloced = (old_stack!=spob_stack);
1721 memset( p, 0, sizeof(Spob) );
1722 p->id = array_size(spob_stack)-1;
1723 p->presence.faction = -1;
1724
1725 /* Lua doesn't default to 0 as a safe value... */
1726 p->lua_env = LUA_NOREF;
1727 p->lua_mem = LUA_NOREF;
1728 p->lua_init = LUA_NOREF;
1729 p->lua_load = LUA_NOREF;
1730 p->lua_unload = LUA_NOREF;
1731 p->lua_can_land= LUA_NOREF;
1732 p->lua_land = LUA_NOREF;
1733 p->lua_render = LUA_NOREF;
1734 p->lua_update = LUA_NOREF;
1735 p->lua_comm = LUA_NOREF;
1736 p->lua_population = LUA_NOREF;
1737 p->lua_barbg = LUA_NOREF;
1738
1739 /* Reconstruct the jumps. */
1740 if (!systems_loading && realloced)
1742
1743 return p;
1744}
1745
1752const char *spob_name( const Spob *p )
1753{
1754 if (p->display)
1755 return _(p->display);
1756 return _(p->name);
1757}
1758
1764static int spobs_load (void)
1765{
1766 char **spob_files;
1767 Commodity **stdList;
1768
1769 /* Initialize stack if needed. */
1770 if (spob_stack == NULL)
1772
1773 /* Extract the list of standard commodities. */
1774 stdList = standard_commodities();
1775
1776 /* Load XML stuff. */
1777 spob_files = ndata_listRecursive( SPOB_DATA_PATH );
1778 for (int i=0; i<array_size(spob_files); i++) {
1779 if (ndata_matchExt( spob_files[i], "xml" )) {
1780 Spob s;
1781 int ret = spob_parse( &s, spob_files[i], stdList );
1782 if (ret == 0) {
1783 s.id = array_size( spob_stack );
1785 }
1786
1787 /* Render if necessary. */
1789 }
1790
1791 /* Clean up. */
1792 free( spob_files[i] );
1793 }
1794 qsort( spob_stack, array_size(spob_stack), sizeof(Spob), spob_cmp );
1795 for (int j=0; j<array_size(spob_stack); j++)
1796 spob_stack[j].id = j;
1797
1798 /* Clean up. */
1799 array_free( spob_files );
1800 array_free( stdList );
1801
1802 return 0;
1803}
1804
1810static int virtualspobs_load (void)
1811{
1812 char **spob_files;
1813
1814 /* Initialize stack if needed. */
1815 if (vspob_stack == NULL)
1817
1818 /* Load XML stuff. */
1819 spob_files = ndata_listRecursive( VIRTUALSPOB_DATA_PATH );
1820 for (int i=0; i<array_size(spob_files); i++) {
1821 xmlDocPtr doc;
1822 xmlNodePtr node;
1823
1824 if (!ndata_matchExt( spob_files[i], "xml" )) {
1825 free( spob_files[i] );
1826 continue;
1827 }
1828
1829 doc = xml_parsePhysFS( spob_files[i] );
1830 if (doc == NULL) {
1831 free( spob_files[i] );
1832 continue;
1833 }
1834
1835 node = doc->xmlChildrenNode; /* first spob node */
1836 if (node == NULL) {
1837 WARN(_("Malformed %s file: does not contain elements"), spob_files[i]);
1838 free( spob_files[i] );
1839 xmlFreeDoc(doc);
1840 continue;
1841 }
1842
1843 if (xml_isNode(node,XML_SPOB_TAG)) {
1844 xmlNodePtr cur;
1845 VirtualSpob va;
1846 memset( &va, 0, sizeof(va) );
1847 xmlr_attr_strd( node, "name", va.name );
1849
1850 cur = node->children;
1851 do {
1852 xml_onlyNodes(cur);
1853 if (xml_isNode(cur,"presence")) {
1854 SpobPresence ap;
1855 spob_parsePresence( cur, &ap );
1856 array_push_back( &va.presences, ap );
1857 continue;
1858 }
1859
1860 WARN(_("Unknown node '%s' in virtual spob '%s'"),cur->name,va.name);
1861 } while (xml_nextNode(cur));
1862
1864 }
1865
1866 /* Clean up. */
1867 free( spob_files[i] );
1868 xmlFreeDoc(doc);
1869 }
1871
1872 /* Clean up. */
1873 array_free( spob_files );
1874
1875 return 0;
1876}
1877
1881char spob_getColourChar( const Spob *p )
1882{
1883 if (!spob_hasService( p, SPOB_SERVICE_INHABITED ))
1884 return 'I';
1885
1886 if (p->can_land) {
1887 if (areAllies(FACTION_PLAYER,p->presence.faction))
1888 return 'F';
1889 return 'N';
1890 }
1891
1892 if (areEnemies(FACTION_PLAYER,p->presence.faction))
1893 return 'H';
1894 return 'R';
1895}
1896
1900const char *spob_getSymbol( const Spob *p )
1901{
1902 if (!spob_hasService( p, SPOB_SERVICE_INHABITED )) {
1903 if (spob_hasService( p, SPOB_SERVICE_LAND ))
1904 return "= ";
1905 return "";
1906 }
1907
1908 if (p->can_land) {
1909 if (areAllies(FACTION_PLAYER,p->presence.faction))
1910 return "+ ";
1911 return "~ ";
1912 }
1913
1914 if (areEnemies(FACTION_PLAYER,p->presence.faction))
1915 return "!! ";
1916 return "* ";
1917}
1918
1922const glColour* spob_getColour( const Spob *p )
1923{
1924 if (!spob_hasService( p, SPOB_SERVICE_INHABITED ))
1925 return &cInert;
1926
1927 if (p->can_land) {
1928 if (areAllies(FACTION_PLAYER,p->presence.faction))
1929 return &cFriend;
1930 return &cNeutral;
1931 }
1932
1933 if (areEnemies(FACTION_PLAYER,p->presence.faction))
1934 return &cHostile;
1935 return &cRestricted;
1936}
1937
1944{
1945 if (p->land_override && (p->land_msg!=NULL)) {
1946 p->can_land = (p->land_override > 0);
1947 return;
1948 }
1949
1950 /* Clean up old stuff. */
1951 free( p->land_msg );
1952 p->can_land = 0;
1953 p->land_msg = NULL;
1954
1955 /* Run custom Lua. */
1956 if (p->lua_can_land != LUA_NOREF) {
1957 spob_luaInitMem( p );
1958 lua_rawgeti(naevL, LUA_REGISTRYINDEX, p->lua_can_land); /* f */
1959 if (nlua_pcall( p->lua_env, 0, 2 )) {
1960 WARN(_("Spob '%s' failed to run '%s':\n%s"), p->name, "can_land", lua_tostring(naevL,-1));
1961 lua_pop(naevL,1);
1962 return;
1963 }
1964
1965 p->can_land = lua_toboolean(naevL,-2);
1966 if (lua_isstring(naevL,-1))
1967 p->land_msg = strdup( lua_tostring(naevL,-1) );
1968 lua_pop(naevL,2);
1969
1970 return;
1971 }
1972
1973 /* Some defaults. */
1974 if (p->land_override<0) {
1975 p->land_msg = strdup(_("Landing permission denied."));
1976 }
1977 else if (spob_hasService( p, SPOB_SERVICE_LAND ) || (p->land_override>0)) {
1978 p->can_land = 1;
1979 p->land_msg = strdup(_("Landing permission granted."));
1980 }
1981}
1982
1986void spob_luaInitMem( const Spob *spob )
1987{
1988 lua_rawgeti( naevL, LUA_REGISTRYINDEX, spob->lua_mem );
1989 nlua_setenv( naevL, spob->lua_env, "mem" );
1990}
1991
1997int spob_luaInit( Spob *spob )
1998{
1999 int mem;
2000
2001 /* Just clear everything. */
2002#define UNREF( x ) \
2003 do { if ((x) != LUA_NOREF) { \
2004 luaL_unref( naevL, LUA_REGISTRYINDEX, (x) ); \
2005 (x) = LUA_NOREF; \
2006 } } while (0)
2007 spob->lua_env = LUA_NOREF; /* Just a pointer to some Lua index. */
2008 UNREF( spob->lua_init );
2009 UNREF( spob->lua_load );
2010 UNREF( spob->lua_unload );
2011 UNREF( spob->lua_land );
2012 UNREF( spob->lua_can_land );
2013 UNREF( spob->lua_render );
2014 UNREF( spob->lua_update );
2015 UNREF( spob->lua_comm );
2016 UNREF( spob->lua_population );
2017 UNREF( spob->lua_barbg );
2018 UNREF( spob->lua_mem );
2019#undef UNREF
2020
2021 /* Initialize. */
2022 if (spob->lua_file == NULL)
2023 return 0;
2024
2025 /* Try to get the environment, will create a new one as necessary. */
2026 nlua_env env = spob_lua_get( &mem, spob->lua_file );
2027 if (env==LUA_NOREF)
2028 return -1;
2029
2030 spob->lua_env = env;
2031
2032 /* Grab functions as applicable. */
2033 spob->lua_init = nlua_refenvtype( env, "init", LUA_TFUNCTION );
2034 spob->lua_load = nlua_refenvtype( env, "load", LUA_TFUNCTION );
2035 spob->lua_unload = nlua_refenvtype( env, "unload", LUA_TFUNCTION );
2036 spob->lua_can_land= nlua_refenvtype( env, "can_land", LUA_TFUNCTION );
2037 spob->lua_land = nlua_refenvtype( env, "land", LUA_TFUNCTION );
2038 spob->lua_render = nlua_refenvtype( env, "render", LUA_TFUNCTION );
2039 spob->lua_update = nlua_refenvtype( env, "update", LUA_TFUNCTION );
2040 spob->lua_comm = nlua_refenvtype( env, "comm", LUA_TFUNCTION );
2041 spob->lua_population=nlua_refenvtype(env, "population",LUA_TFUNCTION );
2042 spob->lua_barbg = nlua_refenvtype( env, "barbg", LUA_TFUNCTION );
2043
2044 /* Set up local memory. */
2045 lua_newtable( naevL ); /* m */
2046 lua_pushvalue( naevL, -1 ); /* m, m */
2047 spob->lua_mem = luaL_ref( naevL, LUA_REGISTRYINDEX ); /* m */
2048
2049 /* Copy over global memory. */
2050 lua_rawgeti( naevL, LUA_REGISTRYINDEX, mem ); /* m, d */
2051 lua_pushnil( naevL ); /* m, d, nil */
2052 while (lua_next(naevL,-2) != 0) { /* m, d, k, v */
2053 lua_pushvalue( naevL, -2 );/* m, d, k, v, k */
2054 lua_pushvalue( naevL, -2 );/* m, d, k, v, k, v */
2055 lua_remove( naevL, -3 ); /* m, d, k, k, v */
2056 lua_settable( naevL, -5 ); /* m, d, k */
2057 } /* m, d */
2058 lua_pop( naevL, 2 ); /* */
2059
2060 /* Run init if applicable. */
2061 if (spob->lua_init != LUA_NOREF) {
2062 spob_luaInitMem( spob );
2063 lua_rawgeti(naevL, LUA_REGISTRYINDEX, spob->lua_init); /* f */
2064 lua_pushspob(naevL, spob_index(spob));
2065 if (nlua_pcall( spob->lua_env, 1, 0 )) {
2066 WARN(_("Spob '%s' failed to run '%s':\n%s"), spob->name, "init", lua_tostring(naevL,-1));
2067 lua_pop(naevL,1);
2068 return -1;
2069 }
2070 }
2071
2072 return 0;
2073}
2074
2078void spob_gfxLoad( Spob *spob )
2079{
2080 if (spob->lua_load != LUA_NOREF) {
2081 spob_luaInitMem( spob );
2082 lua_rawgeti(naevL, LUA_REGISTRYINDEX, spob->lua_load); /* f */
2083 if (nlua_pcall( spob->lua_env, 0, 2 )) {
2084 WARN(_("Spob '%s' failed to run '%s':\n%s"), spob->name, "load", lua_tostring(naevL,-1));
2085 lua_pop(naevL,1);
2086 return;
2087 }
2088 if (lua_istex(naevL,-2)) {
2089 if (spob->gfx_space)
2090 gl_freeTexture( spob->gfx_space );
2091 spob->gfx_space = gl_dupTexture( lua_totex(naevL,-2) );
2092 }
2093 else if (lua_isnil(naevL,-2)) {
2094 /* Have the engine handle it if nil. */
2095 }
2096 else
2097 WARN(_("Spob '%s' ran '%s' but got non-texture or nil return value!"), spob->name, "load" );
2098 spob->radius = luaL_optnumber(naevL,-1,-1.);
2099 lua_pop(naevL,2);
2100 }
2101
2102 if (spob->gfx_space==NULL) {
2103 if (spob->gfx_spaceName != NULL)
2104 spob->gfx_space = gl_newImage( spob->gfx_spaceName, OPENGL_TEX_MIPMAPS );
2105 }
2106 /* Set default size if applicable. */
2107 if ((spob->gfx_space!=NULL) && (spob->radius < 0.))
2108 spob->radius = (spob->gfx_space->w + spob->gfx_space->h)/4.;
2109}
2110
2116void space_gfxLoad( StarSystem *sys )
2117{
2118 for (int i=0; i<array_size(sys->spobs); i++)
2119 spob_gfxLoad( sys->spobs[i] );
2120}
2121
2127void space_gfxUnload( StarSystem *sys )
2128{
2129 for (int i=0; i<array_size(sys->spobs); i++) {
2130 Spob *spob = sys->spobs[i];
2131
2132 if (spob->lua_unload != LUA_NOREF) {
2133 spob_luaInitMem( spob );
2134 lua_rawgeti(naevL, LUA_REGISTRYINDEX, spob->lua_unload); /* f */
2135 if (nlua_pcall( spob->lua_env, 0, 0 )) {
2136 WARN(_("Spob '%s' failed to run '%s':\n%s"), spob->name, "unload", lua_tostring(naevL,-1));
2137 lua_pop(naevL,1);
2138 }
2139 }
2140
2141 gl_freeTexture( spob->gfx_space );
2142 spob->gfx_space = NULL;
2143 }
2144}
2145
2152static int spob_parsePresence( xmlNodePtr node, SpobPresence *ap )
2153{
2154 xmlNodePtr cur = node->children;
2155 memset( ap, 0, sizeof(SpobPresence) );
2156 ap->faction = -1;
2157 do {
2158 xml_onlyNodes(cur);
2159 xmlr_float(cur, "base", ap->base);
2160 xmlr_float(cur, "bonus", ap->bonus);
2161 xmlr_int(cur, "range", ap->range);
2162 if (xml_isNode(cur,"faction")) {
2163 ap->faction = faction_get( xml_get(cur) );
2164 continue;
2165 }
2166 } while (xml_nextNode(cur));
2167 return 0;
2168}
2169
2178static int spob_parse( Spob *spob, const char *filename, Commodity **stdList )
2179{
2180 xmlDocPtr doc;
2181 xmlNodePtr node, parent;
2182 unsigned int flags;
2183 Commodity **comms;
2184
2185 doc = xml_parsePhysFS( filename );
2186 if (doc == NULL)
2187 return -1;
2188
2189 parent = doc->xmlChildrenNode; /* first spob node */
2190 if (parent == NULL) {
2191 WARN(_("Malformed %s file: does not contain elements"), filename);
2192 xmlFreeDoc(doc);
2193 return -1;
2194 }
2195
2196 /* Clear up memory for safe defaults. */
2197 memset( spob, 0, sizeof(Spob) );
2198 flags = 0;
2199 spob->hide = 0.01;
2200 spob->radius = -1.;
2201 spob->presence.faction = -1;
2202 spob->marker_scale = 1.; /* Default scale. */
2203 comms = array_create( Commodity* );
2204 /* Lua stuff. */
2205 spob->lua_env = LUA_NOREF;
2206 spob->lua_init = LUA_NOREF;
2207 spob->lua_load = LUA_NOREF;
2208 spob->lua_unload = LUA_NOREF;
2209 spob->lua_land = LUA_NOREF;
2210 spob->lua_can_land= LUA_NOREF;
2211 spob->lua_render = LUA_NOREF;
2212 spob->lua_update = LUA_NOREF;
2213 spob->lua_comm = LUA_NOREF;
2214 spob->lua_population = LUA_NOREF;
2215 spob->lua_barbg = LUA_NOREF;
2216
2217 /* Get the name. */
2218 xmlr_attr_strd( parent, "name", spob->name );
2219
2220 node = parent->xmlChildrenNode;
2221 do {
2222 /* Only handle nodes. */
2223 xml_onlyNodes(node);
2224
2225 xmlr_strd(node, "display", spob->display);
2226 xmlr_strd(node, "feature", spob->feature);
2227 xmlr_strd(node, "lua", spob->lua_file);
2228 xmlr_float(node, "radius", spob->radius);
2229 if (xml_isNode(node, "marker")) {
2230 const char *s = xml_get(node);
2231 spob->marker = shaders_getSimple( s );
2232 xmlr_attr_float_def(node,"scale",spob->marker_scale,1.);
2233 if (spob->marker == NULL)
2234 WARN(_("Spob '%s' has unknown marker shader '%s'!"), spob->name, s );
2235 continue;
2236 }
2237
2238 if (xml_isNode(node,"GFX")) {
2239 xmlNodePtr cur = node->children;
2240 do {
2241 xml_onlyNodes(cur);
2242 if (xml_isNode(cur,"space")) { /* load space gfx */
2243 char str[PATH_MAX];
2244 snprintf( str, sizeof(str), SPOB_GFX_SPACE_PATH"%s", xml_get(cur));
2245 spob->gfx_spaceName = strdup(str);
2246 spob->gfx_spacePath = xml_getStrd(cur);
2247 continue;
2248 }
2249 if (xml_isNode(cur,"exterior")) { /* load land gfx */
2250 char str[PATH_MAX];
2251 snprintf( str, sizeof(str), SPOB_GFX_EXTERIOR_PATH"%s", xml_get(cur));
2252 spob->gfx_exterior = strdup(str);
2253 spob->gfx_exteriorPath = xml_getStrd(cur);
2254 continue;
2255 }
2256 if (xml_isNode(cur,"comm")) { /* communication gfx */
2257 char str[PATH_MAX];
2258 snprintf( str, sizeof(str), SPOB_GFX_COMM_PATH"%s", xml_get(cur));
2259 spob->gfx_comm = strdup(str);
2260 spob->gfx_commPath = xml_getStrd(cur);
2261 continue;
2262 }
2263 WARN(_("Unknown node '%s' in spob '%s'"),node->name,spob->name);
2264 } while (xml_nextNode(cur));
2265 continue;
2266 }
2267 else if (xml_isNode(node,"pos")) {
2268 xmlr_attr_float( node, "x", spob->pos.x );
2269 xmlr_attr_float( node, "y", spob->pos.y );
2270 flags |= FLAG_POSSET;
2271 continue;
2272 }
2273 else if (xml_isNode(node, "presence")) {
2274 spob_parsePresence( node, &spob->presence );
2275 if (spob->presence.faction>=0)
2276 flags |= FLAG_FACTIONSET;
2277 continue;
2278 }
2279 else if (xml_isNode(node,"general")) {
2280 xmlNodePtr cur = node->children;
2281 do {
2282 xml_onlyNodes(cur);
2283 /* Direct reads. */
2284 xmlr_strd(cur, "class", spob->class);
2285 xmlr_strd(cur, "bar", spob->bar_description);
2286 xmlr_strd(cur, "description", spob->description );
2287 xmlr_float(cur, "population", spob->population );
2288 xmlr_float(cur, "hide", spob->hide );
2289
2290 if (xml_isNode(cur, "services")) {
2291 xmlNodePtr ccur = cur->children;
2292 flags |= FLAG_SERVICESSET;
2293 spob->services = 0;
2294 do {
2295 xml_onlyNodes(ccur);
2296
2297 if (xml_isNode(ccur, "land"))
2298 spob->services |= SPOB_SERVICE_LAND;
2299 else if (xml_isNode(ccur, "refuel"))
2300 spob->services |= SPOB_SERVICE_REFUEL | SPOB_SERVICE_INHABITED;
2301 else if (xml_isNode(ccur, "bar"))
2302 spob->services |= SPOB_SERVICE_BAR | SPOB_SERVICE_INHABITED;
2303 else if (xml_isNode(ccur, "missions"))
2304 spob->services |= SPOB_SERVICE_MISSIONS | SPOB_SERVICE_INHABITED;
2305 else if (xml_isNode(ccur, "commodity"))
2306 spob->services |= SPOB_SERVICE_COMMODITY | SPOB_SERVICE_INHABITED;
2307 else if (xml_isNode(ccur, "outfits"))
2308 spob->services |= SPOB_SERVICE_OUTFITS | SPOB_SERVICE_INHABITED;
2309 else if (xml_isNode(ccur, "shipyard"))
2310 spob->services |= SPOB_SERVICE_SHIPYARD | SPOB_SERVICE_INHABITED;
2311 else if (xml_isNode(ccur, "nomissionspawn"))
2312 spob->flags |= SPOB_NOMISNSPAWN;
2313 else if (xml_isNode(ccur, "uninhabited"))
2314 spob->flags |= SPOB_UNINHABITED;
2315 else if (xml_isNode(ccur, "blackmarket"))
2316 spob->services |= SPOB_SERVICE_BLACKMARKET;
2317 else if (xml_isNode(ccur, "nolanes"))
2318 spob->flags |= SPOB_NOLANES;
2319 else
2320 WARN(_("Spob '%s' has unknown services tag '%s'"), spob->name, ccur->name);
2321 } while (xml_nextNode(ccur));
2322 }
2323
2324 else if (xml_isNode(cur, "commodities")) {
2325 xmlNodePtr ccur = cur->children;
2326 do {
2327 if (xml_isNode(ccur,"commodity")) {
2328 /* If the commodity is standard, don't re-add it. */
2329 Commodity *com = commodity_get( xml_get(ccur) );
2330 if (commodity_isFlag(com, COMMODITY_FLAG_STANDARD))
2331 continue;
2332
2333 array_push_back( &comms, com );
2334 }
2335 } while (xml_nextNode(ccur));
2336 }
2337 else if (xml_isNode(cur, "blackmarket")) {
2338 spob_addService(spob, SPOB_SERVICE_BLACKMARKET);
2339 continue;
2340 }
2341 } while (xml_nextNode(cur));
2342 continue;
2343 }
2344 else if (xml_isNode(node, "tech")) {
2345 spob->tech = tech_groupCreateXML( node );
2346 continue;
2347 }
2348 else if (xml_isNode(node, "tags")) {
2349 xmlNodePtr cur = node->children;
2350 if (spob->tags != NULL)
2351 WARN(_("Spob '%s' has duplicate '%s' node!"), spob->name, "tags");
2352 else
2353 spob->tags = array_create( char* );
2354 do {
2355 xml_onlyNodes(cur);
2356 if (xml_isNode(cur, "tag")) {
2357 const char *tmp = xml_get(cur);
2358 if (tmp != NULL)
2359 array_push_back( &spob->tags, strdup(tmp) );
2360 continue;
2361 }
2362 WARN(_("Spob '%s' has unknown node in tags '%s'."), spob->name, cur->name );
2363 } while (xml_nextNode(cur));
2364 continue;
2365 }
2366 WARN(_("Unknown node '%s' in spob '%s'"),node->name,spob->name);
2367 } while (xml_nextNode(node));
2368
2369 /* Allow forcing to be uninhabited. */
2370 if (spob_isFlag(spob, SPOB_UNINHABITED))
2371 spob->services &= ~SPOB_SERVICE_INHABITED;
2372
2373 if (spob->radius > 0.)
2374 spob_setFlag(spob, SPOB_RADIUS);
2375
2376 /* Set defaults if not set. */
2377 if (spob->lua_file == NULL) {
2378 const char *str = start_spob_lua_default();
2379 if (str != NULL)
2380 spob->lua_file = strdup( str );
2381 }
2382
2383#if DEBUGGING
2384 /* Check for graphics. */
2385 if ((spob->gfx_exterior != NULL) && !PHYSFS_exists(spob->gfx_exterior))
2386 WARN(_("Can not find exterior graphic '%s' for spob '%s'!"), spob->gfx_exterior, spob->name);
2387 if ((spob->gfx_comm != NULL) && !PHYSFS_exists(spob->gfx_comm))
2388 WARN(_("Can not find comm graphic '%s' for spob '%s'!"), spob->gfx_comm, spob->name);
2389#endif /* DEBUGGING */
2390
2391/*
2392 * Verification
2393 */
2394#define MELEMENT(o,s) if (o) WARN(_("Spob '%s' missing '%s' element"), spob->name, s)
2395 //MELEMENT(spob->gfx_spaceName==NULL,"GFX space");
2396 MELEMENT( spob_hasService(spob,SPOB_SERVICE_LAND) &&
2397 spob->gfx_exterior==NULL,"GFX exterior");
2398 MELEMENT( spob_hasService(spob,SPOB_SERVICE_INHABITED) &&
2399 (spob->population==0), "population");
2400 MELEMENT((flags&FLAG_POSSET)==0,"pos");
2401 MELEMENT(spob->class==NULL,"class");
2402 MELEMENT( spob_hasService(spob,SPOB_SERVICE_LAND) &&
2403 spob->description==NULL,"description");
2404 MELEMENT( spob_hasService(spob,SPOB_SERVICE_BAR) &&
2405 spob->bar_description==NULL,"bar");
2406 MELEMENT( spob_hasService(spob,SPOB_SERVICE_INHABITED) &&
2407 (flags&FLAG_FACTIONSET)==0,"faction");
2408 MELEMENT((flags&FLAG_SERVICESSET)==0,"services");
2409 MELEMENT( spob_hasService(spob,SPOB_SERVICE_INHABITED) && (spob_hasService(spob,SPOB_SERVICE_OUTFITS) ||
2410 spob_hasService(spob,SPOB_SERVICE_SHIPYARD)) &&
2411 (spob->tech==NULL), "tech" );
2412 /*MELEMENT( spob_hasService(spob,SPOB_SERVICE_COMMODITY) &&
2413 (array_size(spob->commodities)==0),"commodity" );*/
2414 /*MELEMENT( (flags&FLAG_FACTIONSET) && (spob->presenceAmount == 0.),
2415 "presence" );*/
2416#undef MELEMENT
2417
2418 /* Build commodities list */
2419 if (spob_hasService(spob, SPOB_SERVICE_COMMODITY)) {
2422
2423 /* First, store all the standard commodities and prices. */
2424 if (array_size(stdList) > 0) {
2425 for (int i=0; i<array_size(stdList); i++)
2426 spob_addCommodity( spob, stdList[i] );
2427 }
2428
2429 /* Now add extra commodities */
2430 for (int i=0; i<array_size(comms); i++)
2431 spob_addCommodity( spob, comms[i] );
2432
2433 /* Shrink to minimum size. */
2434 array_shrink( &spob->commodities );
2435 array_shrink( &spob->commodityPrice );
2436 }
2437 /* Free temporary comms list. */
2438 array_free(comms);
2439
2440 xmlFreeDoc(doc);
2441
2442 return 0;
2443}
2444
2452int system_addSpob( StarSystem *sys, const char *spobname )
2453{
2454 Spob *spob;
2455
2456 if (sys == NULL)
2457 return -1;
2458
2459 spob = spob_get( spobname );
2460 if (spob == NULL)
2461 return -1;
2462 array_push_back( &sys->spobs, spob );
2463 array_push_back( &sys->spobsid, spob->id );
2464
2465 /* add spob <-> star system to name stack */
2467 array_push_back( &systemname_stack, sys->name );
2468
2470 /* This is required to clear the player statistics for this spob */
2472
2473 /* Reload graphics if necessary. */
2474 if (cur_system != NULL)
2476
2477 /* Initialize economy if applicable. */
2478 if (spob_hasService( spob, SPOB_SERVICE_COMMODITY ))
2479 economy_initialiseSingleSystem( sys, spob );
2480
2481 return 0;
2482}
2483
2493int system_rmSpob( StarSystem *sys, const char *spobname )
2494{
2495 int i, found;
2496 Spob *spob;
2497
2498 if (sys == NULL) {
2499 WARN(_("Unable to remove spob '%s' from NULL system."), spobname);
2500 return -1;
2501 }
2502
2503 /* Try to find spob. */
2504 spob = spob_get( spobname );
2505 for (i=0; i<array_size(sys->spobs); i++)
2506 if (sys->spobs[i] == spob)
2507 break;
2508
2509 /* Spob not found. */
2510 if (i>=array_size(sys->spobs)) {
2511 WARN(_("Spob '%s' not found in system '%s' for removal."), spobname, sys->name);
2512 return -1;
2513 }
2514
2515 /* Remove spob from system. */
2516 array_erase( &sys->spobs, &sys->spobs[i], &sys->spobs[i+1] );
2517 array_erase( &sys->spobsid, &sys->spobsid[i], &sys->spobsid[i+1] );
2518
2519 /* Remove from the name stack thingy. */
2520 found = 0;
2521 for (i=0; i<array_size(spobname_stack); i++)
2522 if (strcmp(spobname, spobname_stack[i])==0) {
2525 found = 1;
2526 break;
2527 }
2528 if (found == 0)
2529 WARN(_("Unable to find spob '%s' and system '%s' in spob<->system stack."),
2530 spobname, sys->name );
2531
2532 system_setFaction(sys);
2533
2535
2536 return 0;
2537}
2538
2545int system_addVirtualSpob( StarSystem *sys, const char *spobname )
2546{
2547 VirtualSpob *va;
2548
2549 if (sys == NULL)
2550 return -1;
2551
2552 va = virtualspob_get( spobname );
2553 if (va == NULL)
2554 return -1;
2555 array_push_back( &sys->spobs_virtual, va );
2556
2557 /* Economy is affected by presence. */
2559
2560 return 0;
2561}
2562
2569int system_rmVirtualSpob( StarSystem *sys, const char *spobname )
2570{
2571 int i;
2572
2573 if (sys == NULL) {
2574 WARN(_("Unable to remove virtual spob '%s' from NULL system."), spobname);
2575 return -1;
2576 }
2577
2578 /* Try to find virtual spob. */
2579 for (i=0; i<array_size(sys->spobs_virtual); i++)
2580 if (strcmp(sys->spobs_virtual[i]->name, spobname)==0)
2581 break;
2582
2583 /* Virtual spob not found. */
2584 if (i>=array_size(sys->spobs_virtual)) {
2585 WARN(_("Virtual spob '%s' not found in system '%s' for removal."), spobname, sys->name);
2586 return -1;
2587 }
2588
2589 /* Remove virtual spob. */
2590 array_erase( &sys->spobs_virtual, &sys->spobs_virtual[i], &sys->spobs_virtual[i+1] );
2591
2593
2594 return 0;
2595}
2596
2606int system_addJumpDiff( StarSystem *sys, xmlNodePtr node )
2607{
2608 if (system_parseJumpPointDiff(node, sys) <= -1)
2609 return 0;
2612
2613 return 1;
2614}
2615
2625int system_rmJump( StarSystem *sys, const char *jumpname )
2626{
2627 int i;
2628 JumpPoint *jump;
2629
2630 if (sys == NULL) {
2631 WARN(_("Unable to remove jump point '%s' from NULL system."), jumpname);
2632 return -1;
2633 }
2634
2635 /* Try to find spob. */
2636 jump = jump_get( jumpname, sys );
2637 for (i=0; i<array_size(sys->jumps); i++)
2638 if (&sys->jumps[i] == jump)
2639 break;
2640
2641 /* Spob not found. */
2642 if (i>=array_size(sys->jumps)) {
2643 WARN(_("Jump point '%s' not found in system '%s' for removal."), jumpname, sys->name);
2644 return -1;
2645 }
2646
2647 /* Remove jump from system. */
2648 array_erase( &sys->jumps, &sys->jumps[i], &sys->jumps[i+1] );
2649
2651
2652 return 0;
2653}
2654
2658static void system_init( StarSystem *sys )
2659{
2660 memset( sys, 0, sizeof(StarSystem) );
2661 sys->spobs = array_create( Spob* );
2662 sys->spobs_virtual = array_create( VirtualSpob* );
2663 sys->spobsid = array_create( int );
2664 sys->jumps = array_create( JumpPoint );
2665 sys->asteroids = array_create( AsteroidAnchor );
2666 sys->astexclude= array_create( AsteroidExclusion );
2667 sys->faction = -1;
2668}
2669
2673StarSystem *system_new (void)
2674{
2675 StarSystem *sys;
2676 int id;
2677
2678 if (!systems_loading)
2680
2681 /* Protect current system in case of realloc. */
2682 id = -1;
2683 if (cur_system != NULL)
2684 id = system_index( cur_system );
2685
2686 /* Grow array. */
2687 sys = &array_grow( &systems_stack );
2688
2689 /* Reset cur_system. */
2690 if (id >= 0)
2692
2693 /* Initialize system and id. */
2694 system_init( sys );
2695 sys->id = array_size(systems_stack)-1;
2696
2697 /* Reconstruct the jumps, only truely necessary if the systems realloced. */
2698 if (!systems_loading)
2700
2701 return sys;
2702}
2703
2707void system_reconstructJumps( StarSystem *sys )
2708{
2709 for (int j=0; j<array_size(sys->jumps); j++) {
2710 double dx, dy, a;
2711 JumpPoint *jp = &sys->jumps[j];
2712 jp->from = sys;
2713 jp->target = system_getIndex( jp->targetid );
2714 jp->returnJump = jump_getTarget( sys, jp->target );
2715
2716 /* Get heading. */
2717 dx = jp->target->pos.x - sys->pos.x;
2718 dy = jp->target->pos.y - sys->pos.y;
2719 a = atan2( dy, dx );
2720 if (a < 0.)
2721 a += 2.*M_PI;
2722
2723 /* Update position if needed.. */
2724 if (jp->flags & JP_AUTOPOS)
2725 vec2_pset( &jp->pos, sys->radius, a );
2726
2727 /* Update jump specific data. */
2728 gl_getSpriteFromDir( &jp->sx, &jp->sy, jumppoint_gfx, a );
2729 jp->angle = 2.*M_PI-a;
2730 jp->cosa = cos(jp->angle);
2731 jp->sina = sin(jp->angle);
2732 }
2733}
2734
2739{
2740 /* So we need to calculate the shortest jump. */
2741 for (int i=0; i<array_size(systems_stack); i++) {
2742 StarSystem *sys = &systems_stack[i];
2744 /* Save jump indexes. */
2745 for (int j=0; j<array_size(sys->jumps); j++)
2746 sys->jumps[j].targetid = sys->jumps[j].target->id;
2747 }
2748}
2749
2754{
2755 for (int i=0; i<array_size(systems_stack); i++) {
2756 StarSystem *sys = &systems_stack[i];
2757 for (int j=0; j<array_size(sys->spobsid); j++)
2758 sys->spobs[j] = &spob_stack[ sys->spobsid[j] ];
2759 }
2760}
2761
2769static int system_parseAsteroidField( const xmlNodePtr node, StarSystem *sys )
2770{
2771 AsteroidAnchor *a;
2772 xmlNodePtr cur;
2773 int pos;
2774
2775 /* Allocate more space. */
2776 a = &array_grow( &sys->asteroids );
2777 memset( a, 0, sizeof(AsteroidAnchor) );
2778
2779 /* Initialize stuff. */
2780 pos = 1;
2781 a->density = ASTEROID_DEFAULT_DENSITY;
2782 a->groups = array_create( AsteroidTypeGroup* );
2783 a->groupsw = array_create( double );
2784 a->radius = 0.;
2785 a->maxspeed = ASTEROID_DEFAULT_MAXSPEED;
2786 a->maxspin = ASTEROID_DEFAULT_MAXSPIN;
2787 a->accel = ASTEROID_DEFAULT_ACCEL;
2788
2789 /* Parse label if available. */
2790 xmlr_attr_strd( node, "label", a->label );
2791
2792 /* Parse data. */
2793 cur = node->xmlChildrenNode;
2794 do {
2795 xml_onlyNodes(cur);
2796
2797 xmlr_float( cur, "density", a->density );
2798 xmlr_float( cur, "radius", a->radius );
2799 xmlr_float( cur, "maxspeed", a->maxspeed );
2800 xmlr_float( cur, "accel", a->accel );
2801
2802 /* Handle types of asteroids. */
2803 if (xml_isNode(cur,"group")) {
2804 double w;
2805 const char *name = xml_get(cur);
2806 xmlr_attr_float_def(cur,"weight",w,1.);
2807 array_push_back( &a->groups, astgroup_getName(name) );
2808 array_push_back( &a->groupsw, w );
2809 continue;
2810 }
2811
2812 /* Handle position. */
2813 if (xml_isNode(cur,"pos")) {
2814 double x, y;
2815 pos = 1;
2816 xmlr_attr_float( cur, "x", x );
2817 xmlr_attr_float( cur, "y", y );
2818
2819 /* Set position. */
2820 vec2_cset( &a->pos, x, y );
2821 continue;
2822 }
2823
2824 WARN(_("Asteroid Field in Star System '%s' has unknown node '%s'"), sys->name, node->name);
2825 } while (xml_nextNode(cur));
2826
2827 /* Update internals. */
2829
2830#define MELEMENT(o,s) \
2831if (o) WARN(_("Asteroid Field in Star System '%s' has missing/invalid '%s' element"), sys->name, s)
2832 MELEMENT(!pos,"pos");
2833 MELEMENT(a->radius<=0.,"radius");
2834 MELEMENT(array_size(a->groups)==0,"groups");
2835#undef MELEMENT
2836
2837 return 0;
2838}
2839
2847static int system_parseAsteroidExclusion( const xmlNodePtr node, StarSystem *sys )
2848{
2850 xmlNodePtr cur;
2851 double x, y;
2852 int pos;
2853
2854 /* Allocate more space. */
2855 a = &array_grow( &sys->astexclude );
2856 memset( a, 0, sizeof(*a) );
2857
2858 /* Initialize stuff. */
2859 pos = 0;
2860
2861 /* Parse data. */
2862 cur = node->xmlChildrenNode;
2863 do {
2864 xml_onlyNodes( cur );
2865
2866 xmlr_float( cur, "radius", a->radius );
2867
2868 /* Handle position. */
2869 if (xml_isNode(cur,"pos")) {
2870 pos = 1;
2871 xmlr_attr_float( cur, "x", x );
2872 xmlr_attr_float( cur, "y", y );
2873
2874 /* Set position. */
2875 vec2_cset( &a->pos, x, y );
2876 continue;
2877 }
2878 WARN(_("Asteroid Exclusion Zone in Star System '%s' has unknown node '%s'"), sys->name, node->name);
2879 } while (xml_nextNode(cur));
2880
2881#define MELEMENT(o,s) \
2882if (o) WARN(_("Asteroid Exclusion Zone in Star System '%s' has missing/invalid '%s' element"), sys->name, s)
2883 MELEMENT(!pos,"pos");
2884 MELEMENT(a->radius<=0.,"radius");
2885#undef MELEMENT
2886
2887 return 0;
2888}
2889
2897static int system_parse( StarSystem *sys, const char *filename )
2898{
2899 xmlNodePtr node, parent;
2900 xmlDocPtr doc;
2901 uint32_t flags;
2902
2903 /* Load the file. */
2904 doc = xml_parsePhysFS( filename );
2905 if (doc == NULL)
2906 return -1;
2907
2908 parent = doc->xmlChildrenNode; /* first spob node */
2909 if (parent == NULL) {
2910 WARN(_("Malformed %s file: does not contain elements"), filename);
2911 xmlFreeDoc(doc);
2912 return -1;
2913 }
2914
2915 /* Clear memory for safe defaults. */
2916 system_init( sys );
2917 flags = 0;
2918 sys->presence = array_create( SystemPresence );
2919 sys->ownerpresence = 0.;
2920 sys->nebu_hue = NEBULA_DEFAULT_HUE;
2921 sys->spacedust = -1;
2922
2923 xmlr_attr_strd( parent, "name", sys->name );
2924
2925 node = parent->xmlChildrenNode;
2926 do { /* load all the data */
2927 /* Only handle nodes. */
2928 xml_onlyNodes(node);
2929
2930 if (xml_isNode(node,"pos")) {
2931 flags |= FLAG_POSSET;
2932 xmlr_attr_float( node, "x", sys->pos.x );
2933 xmlr_attr_float( node, "y", sys->pos.y );
2934 continue;
2935 }
2936 else if (xml_isNode(node,"general")) {
2937 xmlNodePtr cur = node->children;
2938 do {
2939 xml_onlyNodes(cur);
2940 xmlr_strd( cur, "background", sys->background );
2941 xmlr_strd( cur, "map_shader", sys->map_shader );
2942 xmlr_strd( cur, "features", sys->features );
2943 xmlr_int( cur, "spacedust", sys->spacedust );
2944 if (xml_isNode( cur, "stars" )) { /* Rename to "spacedust" in 0.11.0. TODO remove sometime around 0.13.0. */
2945 sys->spacedust = xml_getInt(cur);
2946 WARN(_("System '%s' is using deprecated field 'stars'. Use 'spacedust' instead!"), sys->name);
2947 }
2948 xmlr_float( cur, "radius", sys->radius );
2949 if (xml_isNode(cur,"interference")) {
2950 flags |= FLAG_INTERFERENCESET;
2951 sys->interference = xml_getFloat(cur);
2952 continue;
2953 }
2954 if (xml_isNode(cur,"nebula")) {
2955 xmlr_attr_float( cur, "volatility", sys->nebu_volatility );
2956 xmlr_attr_float_def( cur, "hue", sys->nebu_hue, NEBULA_DEFAULT_HUE );
2957 sys->nebu_density = xml_getFloat(cur);
2958 continue;
2959 }
2960 if (xml_isNode(cur,"nolanes")) {
2961 sys_setFlag( sys, SYSTEM_NOLANES );
2962 continue;
2963 }
2964 DEBUG(_("Unknown node '%s' in star system '%s'"),node->name,sys->name);
2965 } while (xml_nextNode(cur));
2966 continue;
2967 }
2968 /* Loads all the spobs. */
2969 else if (xml_isNode(node,"spobs")) {
2970 xmlNodePtr cur = node->children;
2971 do {
2972 xml_onlyNodes(cur);
2973 if (xml_isNode(cur,"spob")) {
2974 system_addSpob( sys, xml_get(cur) );
2975 continue;
2976 }
2977 if (xml_isNode(cur,"spob_virtual")) {
2978 system_addVirtualSpob( sys, xml_get(cur) );
2979 continue;
2980 }
2981 DEBUG(_("Unknown node '%s' in star system '%s'"),node->name,sys->name);
2982 } while (xml_nextNode(cur));
2983 continue;
2984 }
2985
2986 if (xml_isNode(node,"asteroids")) {
2987 xmlNodePtr cur = node->children;
2988 do {
2989 xml_onlyNodes(cur);
2990 if (xml_isNode(cur,"asteroid"))
2991 system_parseAsteroidField( cur, sys );
2992 else if (xml_isNode(cur,"exclusion"))
2994 } while (xml_nextNode(cur));
2995 }
2996
2997 if (xml_isNode(node, "stats")) {
2998 xmlNodePtr cur = node->children;
2999 do {
3000 xml_onlyNodes(cur);
3001 ShipStatList *ll = ss_listFromXML( cur );
3002 if (ll != NULL) {
3003 ll->next = sys->stats;
3004 sys->stats = ll;
3005 continue;
3006 }
3007 WARN(_("System '%s' has unknown stat '%s'."), sys->name, cur->name);
3008 } while (xml_nextNode(cur));
3009 continue;
3010 }
3011
3012 if (xml_isNode(node, "tags")) {
3013 xmlNodePtr cur = node->children;
3014 sys->tags = array_create( char* );
3015 do {
3016 xml_onlyNodes(cur);
3017 if (xml_isNode(cur, "tag")) {
3018 const char *tmp = xml_get(cur);
3019 if (tmp != NULL)
3020 array_push_back( &sys->tags, strdup(tmp) );
3021 continue;
3022 }
3023 WARN(_("System '%s' has unknown node in tags '%s'."), sys->name, cur->name );
3024 } while (xml_nextNode(cur));
3025 continue;
3026 }
3027
3028 /* Avoid warnings. */
3029 if (xml_isNode(node,"jumps") || xml_isNode(node,"asteroids"))
3030 continue;
3031
3032 DEBUG(_("Unknown node '%s' in star system '%s'"),node->name,sys->name);
3033 } while (xml_nextNode(node));
3034
3035 ss_sort( &sys->stats );
3036 array_shrink( &sys->spobs );
3037 array_shrink( &sys->spobsid );
3038 array_shrink( &sys->asteroids );
3039 array_shrink( &sys->astexclude );
3040
3041 /* Convert hue from 0 to 359 value to 0 to 1 value. */
3042 sys->nebu_hue /= 360.;
3043
3044 /* Load the shader. */
3045 if (sys->map_shader != NULL)
3046 sys->ms = mapshader_get( sys->map_shader );
3047
3048#define MELEMENT(o,s) if (o) WARN(_("Star System '%s' missing '%s' element"), sys->name, s)
3049 if (sys->name == NULL) WARN(_("Star System '%s' missing 'name' tag"), sys->name);
3050 MELEMENT((flags&FLAG_POSSET)==0,"pos");
3051 MELEMENT(sys->spacedust<0,"spacedust");
3052 MELEMENT(sys->radius==0.,"radius");
3053 MELEMENT((flags&FLAG_INTERFERENCESET)==0,"inteference");
3054#undef MELEMENT
3055
3056 xmlFreeDoc( doc );
3057
3058 return 0;
3059}
3060
3064static int sys_cmpSysFaction( const void *a, const void *b )
3065{
3066 SystemPresence *spa, *spb;
3067
3068 spa = (SystemPresence*) a;
3069 spb = (SystemPresence*) b;
3070
3071 /* Compare value. */
3072 if (spa->value < spb->value)
3073 return +1;
3074 else if (spa->value > spb->value)
3075 return -1;
3076
3077 /* Compare faction id. */
3078 if (spa->faction < spb->faction)
3079 return +1;
3080 else if (spa->faction > spb->faction)
3081 return -1;
3082
3083 return 0;
3084}
3085
3091void system_setFaction( StarSystem *sys )
3092{
3093 /* Sort presences in descending order. */
3094 if (array_size(sys->presence) != 0)
3095 qsort( sys->presence, array_size(sys->presence), sizeof(SystemPresence), sys_cmpSysFaction );
3096
3097 sys->faction = -1;
3098 for (int i=0; i<array_size(sys->presence); i++) {
3099 for (int j=0; j<array_size(sys->spobs); j++) {
3100 Spob *pnt = sys->spobs[j];
3101
3102 if (pnt->presence.faction != sys->presence[i].faction)
3103 continue;
3104
3105 sys->faction = pnt->presence.faction;
3106 return;
3107 }
3108 }
3109}
3110
3118static int system_parseJumpPointDiff( const xmlNodePtr node, StarSystem *sys )
3119{
3120 JumpPoint *j;
3121 char *buf;
3122 double x, y;
3123 StarSystem *target;
3124
3125 /* Get target. */
3126 xmlr_attr_strd( node, "target", buf );
3127 if (buf == NULL) {
3128 WARN(_("JumpPoint node for system '%s' has no target attribute."), sys->name);
3129 return -1;
3130 }
3131 target = system_get(buf);
3132 if (target == NULL) {
3133 WARN(_("JumpPoint node for system '%s' has invalid target '%s'."), sys->name, buf );
3134 free(buf);
3135 return -1;
3136 }
3137 free(buf);
3138
3139#ifdef DEBUGGING
3140 for (int i=0; i<array_size(sys->jumps); i++) {
3141 JumpPoint *jp = &sys->jumps[i];
3142 if (jp->targetid != target->id)
3143 continue;
3144
3145 WARN(_("Star System '%s' has duplicate jump point to '%s'."),
3146 sys->name, target->name );
3147 break;
3148 }
3149#endif /* DEBUGGING */
3150
3151 /* Allocate more space. */
3152 j = &array_grow( &sys->jumps );
3153 memset( j, 0, sizeof(JumpPoint) );
3154
3155 /* Handle jump point position. We want both x and y, or we autoposition the jump point. */
3156 xmlr_attr_float_def( node, "x", x, HUGE_VAL );
3157 xmlr_attr_float_def( node, "y", y, HUGE_VAL );
3158
3159 /* Handle jump point type. */
3160 xmlr_attr_strd( node, "type", buf );
3161 if (buf == NULL);
3162 else if (strcmp(buf, "hidden") == 0)
3163 jp_setFlag(j,JP_HIDDEN);
3164 else if (strcmp(buf, "exitonly") == 0)
3165 jp_setFlag(j,JP_EXITONLY);
3166 free( buf );
3167
3168 xmlr_attr_float_def( node, "hide", j->hide, HIDE_DEFAULT_JUMP);
3169
3170 /* Set some stuff. */
3171 j->target = target;
3172 j->targetid = j->target->id;
3173 j->radius = 200.;
3174
3175 if (x < HUGE_VAL && y < HUGE_VAL)
3176 vec2_cset( &j->pos, x, y );
3177 else
3178 jp_setFlag(j,JP_AUTOPOS);
3179
3180 return 0;
3181}
3182
3190static int system_parseJumpPoint( const xmlNodePtr node, StarSystem *sys )
3191{
3192 JumpPoint *j;
3193 char *buf;
3194 xmlNodePtr cur;
3195 double x, y;
3196 StarSystem *target;
3197 int pos;
3198
3199 /* Get target. */
3200 xmlr_attr_strd( node, "target", buf );
3201 if (buf == NULL) {
3202 WARN(_("JumpPoint node for system '%s' has no target attribute."), sys->name);
3203 return -1;
3204 }
3205 target = system_get(buf);
3206 if (target == NULL) {
3207 WARN(_("JumpPoint node for system '%s' has invalid target '%s'."), sys->name, buf );
3208 free(buf);
3209 return -1;
3210 }
3211 free(buf);
3212
3213#ifdef DEBUGGING
3214 for (int i=0; i<array_size(sys->jumps); i++) {
3215 JumpPoint *jp = &sys->jumps[i];
3216 if (jp->targetid != target->id)
3217 continue;
3218
3219 WARN(_("Star System '%s' has duplicate jump point to '%s'."),
3220 sys->name, target->name );
3221 break;
3222 }
3223#endif /* DEBUGGING */
3224
3225 /* Allocate more space. */
3226 j = &array_grow( &sys->jumps );
3227 memset( j, 0, sizeof(JumpPoint) );
3228
3229 /* Set some stuff. */
3230 j->from = sys;
3231 j->target = target;
3232 j->targetid = j->target->id;
3233 j->radius = 200.;
3234
3235 pos = 0;
3236
3237 /* Parse data. */
3238 cur = node->xmlChildrenNode;
3239 do {
3240 xmlr_float( cur, "radius", j->radius );
3241
3242 /* Handle position. */
3243 if (xml_isNode(cur,"pos")) {
3244 pos = 1;
3245 xmlr_attr_float( cur, "x", x );
3246 xmlr_attr_float( cur, "y", y );
3247
3248 /* Set position. */
3249 vec2_cset( &j->pos, x, y );
3250 }
3251 else if (xml_isNode(cur,"autopos"))
3252 jp_setFlag(j,JP_AUTOPOS);
3253 else if (xml_isNode(cur,"hidden"))
3254 jp_setFlag(j,JP_HIDDEN);
3255 else if (xml_isNode(cur,"exitonly"))
3256 jp_setFlag(j,JP_EXITONLY);
3257 else if (xml_isNode(cur,"nolanes"))
3258 jp_setFlag(j,JP_NOLANES);
3259 else if (xml_isNode(cur,"hide")) {
3260 xmlr_float( cur,"hide", j->hide );
3261 }
3262 } while (xml_nextNode(cur));
3263
3264 if (!jp_isFlag(j,JP_AUTOPOS) && !pos)
3265 WARN(_("JumpPoint in system '%s' is missing pos element but does not have autopos flag."), sys->name);
3266
3267 return 0;
3268}
3269
3276static int system_parseJumps( StarSystem *sys )
3277{
3278 xmlNodePtr parent, node;
3279 xmlDocPtr doc;
3280
3281 doc = xml_parsePhysFS( sys->filename );
3282 if (doc == NULL)
3283 return -1;
3284
3285 parent = doc->xmlChildrenNode; /* first spob node */
3286 if (parent == NULL) {
3287 xmlFreeDoc(doc);
3288 return -1;
3289 }
3290
3291 node = parent->xmlChildrenNode;
3292 do { /* load all the data */
3293 if (xml_isNode(node,"jumps")) {
3294 xmlNodePtr cur = node->children;
3295 do {
3296 if (xml_isNode(cur,"jump"))
3297 system_parseJumpPoint( cur, sys );
3298 } while (xml_nextNode(cur));
3299 }
3300 } while (xml_nextNode(node));
3301
3302 array_shrink( &sys->jumps );
3303
3304 xmlFreeDoc(doc);
3305 return 0;
3306}
3307
3313int space_load (void)
3314{
3315 /* Loading. */
3316 systems_loading = 1;
3317
3318 /* Create some arrays. */
3319 spobname_stack = array_create( char* );
3320 systemname_stack = array_create( char* );
3321
3322 /* Load jump point graphic - must be before systems_load(). */
3323 jumppoint_gfx = gl_newSprite( SPOB_GFX_SPACE_PATH"jumppoint.webp", 4, 4, OPENGL_TEX_MIPMAPS );
3324 jumpbuoy_gfx = gl_newImage( SPOB_GFX_SPACE_PATH"jumpbuoy.webp", 0 );
3325
3326 /* Load data. */
3327 spobs_load();
3329 asteroids_load ();
3330 systems_load();
3331
3332 /* Done loading. */
3333 systems_loading = 0;
3334
3335 /* Reconstruction. */
3339
3340 /* Calculate commodity prices (sinusoidal model). */
3342
3343 return 0;
3344}
3345
3350{
3351 int ret = 0;
3352 for (int i=0; i<array_size(spob_stack); i++)
3353 ret |= spob_luaInit( &spob_stack[i] );
3354 return ret;
3355}
3356
3367static int systems_load (void)
3368{
3369#if DEBUGGING
3370 Uint32 time = SDL_GetTicks();
3371#endif /* DEBUGGING */
3372 char **system_files;
3373
3374 /* Allocate if needed. */
3375 if (systems_stack == NULL)
3376 systems_stack = array_create( StarSystem );
3377
3378 system_files = ndata_listRecursive( SYSTEM_DATA_PATH );
3379
3380 /*
3381 * First pass - loads all the star systems_stack.
3382 */
3383 for (int i=0; i<array_size(system_files); i++) {
3384 StarSystem sys;
3385
3386 if (!ndata_matchExt( system_files[i], "xml" ))
3387 continue;
3388
3389 int ret = system_parse( &sys, system_files[i] );
3390 if (ret == 0) {
3391 sys.filename = system_files[i];
3392 sys.id = array_size(systems_stack);
3393
3394 /* Update asteroid info. */
3395 system_updateAsteroids( &sys );
3396
3398
3399 /* Render if necessary. */
3401 }
3402 }
3403 qsort( systems_stack, array_size(systems_stack), sizeof(StarSystem), system_cmp );
3404 for (int j=0; j<array_size(systems_stack); j++) {
3405 systems_stack[j].id = j;
3406 systems_stack[j].note = NULL; /* just to be sure */
3407 }
3408
3409 /*
3410 * Second pass - loads all the jump routes.
3411 */
3412 for (int i=0; i<array_size(systems_stack); i++)
3414
3415 /* Clean up. */
3416 array_free( system_files );
3417
3418#if DEBUGGING
3419 if (conf.devmode) {
3420 DEBUG( n_( "Loaded %d Star System",
3421 "Loaded %d Star Systems", array_size(systems_stack) ), array_size(systems_stack) );
3422 DEBUG( n_( " with %d Space Object in %.3f s",
3423 " with %d Space Objects in %.3f s", array_size(spob_stack) ), array_size(spob_stack), (SDL_GetTicks()-time)/1000. );
3424 }
3425 else {
3426 DEBUG( n_( "Loaded %d Star System",
3427 "Loaded %d Star Systems", array_size(systems_stack) ), array_size(systems_stack) );
3428 DEBUG( n_( " with %d Space Object",
3429 " with %d Space Objects", array_size(spob_stack) ), array_size(spob_stack) );
3430 }
3431#endif /* DEBUGGING */
3432
3433 return 0;
3434}
3435
3441void space_render( const double dt )
3442{
3443 if (cur_system == NULL)
3444 return;
3445
3446 if (cur_system->nebu_density > 0.)
3447 nebu_render(dt);
3448 else
3450}
3451
3457void space_renderOverlay( const double dt )
3458{
3459 if (cur_system == NULL)
3460 return;
3461
3462 /* Render the debris. */
3464
3465 /* Render overlay if necessary. */
3467
3468 if ((cur_system->nebu_density > 0.) &&
3471}
3472
3476void spobs_render (void)
3477{
3478 /* Must be a system. */
3479 if (cur_system==NULL)
3480 return;
3481
3482 /* Render the jumps. */
3483 for (int i=0; i < array_size(cur_system->jumps); i++)
3484 space_renderJumpPoint( &cur_system->jumps[i], i );
3485
3486 /* Render the spobs. */
3487 for (int i=0; i < array_size(cur_system->spobs); i++)
3488 space_renderSpob( cur_system->spobs[i] );
3489
3490 /* Render the asteroids & debris. */
3492
3493 /* Render gatherable stuff. */
3495
3496}
3497
3501static void space_renderJumpPoint( const JumpPoint *jp, int i )
3502{
3503 const glColour *c;
3504
3505 if (!jp_isUsable(jp))
3506 return;
3507
3508 if ((player.p != NULL) && (i==player.p->nav_hyperspace) &&
3509 (pilot_isFlag(player.p, PILOT_HYPERSPACE) || space_canHyperspace(player.p)))
3510 c = &cGreen;
3511 else if (jp_isFlag(jp, JP_HIDDEN))
3512 c = &cRed;
3513 else
3514 c = NULL;
3515
3516 gl_renderSprite( jumppoint_gfx, jp->pos.x, jp->pos.y, jp->sx, jp->sy, c );
3517
3518 /* Draw buoys next to "highway" jump points. */
3519 if (jp->hide == 0.) {
3520 gl_renderSprite( jumpbuoy_gfx, jp->pos.x + 200 * jp->sina, jp->pos.y + 200 * jp->cosa, 0, 0, NULL ); /* Left */
3521 gl_renderSprite( jumpbuoy_gfx, jp->pos.x + -200 * jp->sina, jp->pos.y + -200 * jp->cosa, 0, 0, NULL ); /* Right */
3522 }
3523}
3524
3528static void space_renderSpob( const Spob *p )
3529{
3530 if (p->lua_render != LUA_NOREF) {
3531 spob_luaInitMem( p );
3532 /* TODO do a clip test first. */
3533 lua_rawgeti(naevL, LUA_REGISTRYINDEX, p->lua_render); /* f */
3534 if (nlua_pcall( p->lua_env, 0, 0 )) {
3535 WARN(_("Spob '%s' failed to run '%s':\n%s"), p->name, "render", lua_tostring(naevL,-1));
3536 lua_pop(naevL,1);
3537 }
3538 }
3539 else if (p->gfx_space)
3540 gl_renderSprite( p->gfx_space, p->pos.x, p->pos.y, 0, 0, NULL );
3541}
3542
3546static void space_updateSpob( const Spob *p, double dt, double real_dt )
3547{
3548 if (p->lua_update == LUA_NOREF)
3549 return;
3550 /* TODO do a clip test first. */
3551 spob_luaInitMem( p );
3552 lua_rawgeti(naevL, LUA_REGISTRYINDEX, p->lua_update); /* f */
3553 lua_pushnumber(naevL, dt); /* f, dt */
3554 lua_pushnumber(naevL, real_dt); /* f, real_dt */
3555 if (nlua_pcall( p->lua_env, 2, 0 )) {
3556 WARN(_("Spob '%s' failed to run '%s':\n%s"), p->name, "update", lua_tostring(naevL,-1));
3557 lua_pop(naevL,1);
3558 }
3559}
3560
3564void space_exit (void)
3565{
3566 /* Free standalone graphic textures */
3568 jumppoint_gfx = NULL;
3570 jumpbuoy_gfx = NULL;
3571
3572 /* Free the names. */
3575
3576 /* Free the spobs. */
3577 for (int i=0; i < array_size(spob_stack); i++) {
3578 Spob *spb = &spob_stack[i];
3579
3580 free(spb->name);
3581 free(spb->display);
3582 free(spb->feature);
3583 free(spb->lua_file);
3584 free(spb->class);
3585 free(spb->description);
3586 free(spb->bar_description);
3587 for (int j=0; j<array_size(spb->tags); j++)
3588 free( spb->tags[j] );
3589 array_free(spb->tags);
3590
3591 /* graphics */
3592 gl_freeTexture( spb->gfx_space );
3593 free(spb->gfx_spaceName);
3594 free(spb->gfx_spacePath);
3595 free(spb->gfx_exterior);
3596 free(spb->gfx_exteriorPath);
3597 free(spb->gfx_comm);
3598 free(spb->gfx_commPath);
3599
3600 /* Landing. */
3601 free(spb->land_msg);
3602
3603 /* tech */
3604 if (spb->tech != NULL)
3605 tech_groupDestroy( spb->tech );
3606
3607 /* commodities */
3608 array_free(spb->commodities);
3610
3611 /* Lua. */
3612 nlua_freeEnv( spb->lua_env );
3613 }
3615
3616 for (int i=0; i<array_size(spob_lua_stack); i++)
3617 spob_lua_free( &spob_lua_stack[i] );
3619
3620 for (int i=0; i<array_size(vspob_stack); i++) {
3621 VirtualSpob *va = &vspob_stack[i];
3622 free( va->name );
3623 array_free( va->presences );
3624 }
3626
3627 /* Free the systems. */
3628 for (int i=0; i < array_size(systems_stack); i++) {
3629 StarSystem *sys = &systems_stack[i];
3630
3631 free(sys->filename);
3632 free(sys->name);
3633 free(sys->background);
3634 free(sys->map_shader);
3635 free(sys->features);
3636 free(sys->note);
3637 array_free(sys->jumps);
3638 array_free(sys->presence);
3639 array_free(sys->spobs);
3640 array_free(sys->spobsid);
3641 array_free(sys->spobs_virtual);
3642
3643 for (int j=0; j<array_size(sys->tags); j++)
3644 free( sys->tags[j] );
3645 array_free(sys->tags);
3646
3647 /* Free the asteroids. */
3648 for (int j=0; j < array_size(sys->asteroids); j++)
3649 asteroid_free( &sys->asteroids[j] );
3650 array_free(sys->asteroids);
3651 array_free(sys->astexclude);
3652
3653 ss_free( sys->stats );
3654 }
3656 systems_stack = NULL;
3657
3658 /* Free asteroids stuff. */
3660
3661 /* Free the gatherable stack. */
3663
3664 /* Free the map shaders. */
3665 for (int i=0; i<array_size(mapshaders); i++) {
3666 MapShader *ms = mapshaders[i];
3667 free( ms->name );
3668 glDeleteProgram( ms->program );
3669 free(ms);
3670 }
3672}
3673
3678{
3679 for (int i=0; i<array_size(systems_stack); i++) {
3680 StarSystem *sys = &systems_stack[i];
3681 sys_rmFlag(sys,SYSTEM_KNOWN);
3682 sys_rmFlag(sys,SYSTEM_HIDDEN);
3683 sys_rmFlag(sys,SYSTEM_PMARKED);
3684 for (int j=0; j<array_size(sys->jumps); j++)
3685 jp_rmFlag(&sys->jumps[j],JP_KNOWN);
3686 free(sys->note);
3687 sys->note=NULL;
3688 }
3689 for (int j=0; j<array_size(spob_stack); j++)
3690 spob_rmFlag(&spob_stack[j],SPOB_KNOWN);
3691}
3692
3697{
3698 for (int i=0; i<array_size(systems_stack); i++) {
3699 StarSystem *sys = &systems_stack[i];
3700 sys_rmFlag( sys, SYSTEM_MARKED );
3701 sys->markers_computer = 0;
3702 sys->markers_plot = 0;
3703 sys->markers_high = 0;
3704 sys->markers_low = 0;
3705 }
3706 for (int i=0; i<array_size(spob_stack); i++) {
3707 Spob *pnt = &spob_stack[i];
3708 spob_rmFlag( pnt, SPOB_MARKED );
3709 pnt->markers = 0;
3710 }
3711}
3712
3717{
3718 for (int i=0; i<array_size(systems_stack); i++)
3719 sys_rmFlag(&systems_stack[i],SYSTEM_CMARKED);
3720}
3721
3722static int space_addMarkerSystem( int sysid, MissionMarkerType type )
3723{
3724 StarSystem *ssys;
3725 int *markers;
3726
3727 /* Get the system. */
3728 ssys = system_getIndex(sysid);
3729 if (ssys == NULL)
3730 return -1;
3731
3732 /* Get the marker. */
3733 switch (type) {
3734 case SYSMARKER_COMPUTER:
3735 markers = &ssys->markers_computer;
3736 break;
3737 case SYSMARKER_LOW:
3738 markers = &ssys->markers_low;
3739 break;
3740 case SYSMARKER_HIGH:
3741 markers = &ssys->markers_high;
3742 break;
3743 case SYSMARKER_PLOT:
3744 markers = &ssys->markers_plot;
3745 break;
3746 default:
3747 WARN(_("Unknown marker type."));
3748 return -1;
3749 }
3750
3751 /* Decrement markers. */
3752 (*markers)++;
3753 sys_setFlag(ssys, SYSTEM_MARKED);
3754
3755 return 0;
3756}
3757
3758static int space_addMarkerSpob( int pntid, MissionMarkerType type )
3759{
3760 const char *sys;
3761 MissionMarkerType stype;
3762 Spob *pnt = spob_getIndex( pntid );
3763 if (pnt==NULL)
3764 return -1;
3765
3766 /* Mark spob. */
3767 pnt->markers++;
3768 spob_setFlag( pnt, SPOB_MARKED );
3769
3770 /* Now try to mark system. */
3771 sys = spob_getSystem( pnt->name );
3772 if (sys == NULL) {
3773 WARN(_("Marking spob '%s' that is not in any system!"), pnt->name);
3774 return 0;
3775 }
3776 stype = mission_markerTypeSpobToSystem( type );
3777 return space_addMarkerSystem( system_index( system_get(sys) ), stype );
3778}
3779
3787int space_addMarker( int objid, MissionMarkerType type )
3788{
3789 switch (type) {
3790 case SYSMARKER_COMPUTER:
3791 case SYSMARKER_LOW:
3792 case SYSMARKER_HIGH:
3793 case SYSMARKER_PLOT:
3794 return space_addMarkerSystem( objid, type );
3795 case SPOBMARKER_COMPUTER:
3796 case SPOBMARKER_LOW:
3797 case SPOBMARKER_HIGH:
3798 case SPOBMARKER_PLOT:
3799 return space_addMarkerSpob( objid, type );
3800 default:
3801 WARN(_("Unknown marker type."));
3802 return -1;
3803 }
3804 return 0;
3805}
3806
3807static int space_rmMarkerSystem( int sys, MissionMarkerType type )
3808{
3809 StarSystem *ssys;
3810 int *markers;
3811
3812 /* Get the system. */
3813 ssys = system_getIndex(sys);
3814 if (ssys == NULL)
3815 return -1;
3816
3817 /* Get the marker. */
3818 switch (type) {
3819 case SYSMARKER_COMPUTER:
3820 markers = &ssys->markers_computer;
3821 break;
3822 case SYSMARKER_LOW:
3823 markers = &ssys->markers_low;
3824 break;
3825 case SYSMARKER_HIGH:
3826 markers = &ssys->markers_high;
3827 break;
3828 case SYSMARKER_PLOT:
3829 markers = &ssys->markers_plot;
3830 break;
3831 default:
3832 WARN(_("Unknown marker type."));
3833 return -1;
3834 }
3835
3836 /* Decrement markers. */
3837 (*markers)--;
3838 if (*markers <= 0) {
3839 sys_rmFlag(ssys, SYSTEM_MARKED);
3840 (*markers) = 0;
3841 }
3842
3843 return 0;
3844}
3845
3846static int space_rmMarkerSpob( int pntid, MissionMarkerType type )
3847{
3848 (void) type;
3849 const char *sys;
3850 MissionMarkerType stype;
3851 Spob *pnt = spob_getIndex( pntid );
3852
3853 /* Remove spob marker. */
3854 pnt->markers--;
3855 if (pnt->markers <= 0)
3856 spob_rmFlag( pnt, SPOB_MARKED );
3857
3858 /* Now try to remove system. */
3859 sys = spob_getSystem( pnt->name );
3860 if (sys == NULL)
3861 return 0;
3862 stype = mission_markerTypeSpobToSystem( type );
3863 return space_rmMarkerSystem( system_index( system_get(sys) ), stype );
3864}
3865
3873int space_rmMarker( int objid, MissionMarkerType type )
3874{
3875 switch (type) {
3876 case SYSMARKER_COMPUTER:
3877 case SYSMARKER_LOW:
3878 case SYSMARKER_HIGH:
3879 case SYSMARKER_PLOT:
3880 return space_rmMarkerSystem( objid, type );
3881 case SPOBMARKER_COMPUTER:
3882 case SPOBMARKER_LOW:
3883 case SPOBMARKER_HIGH:
3884 case SPOBMARKER_PLOT:
3885 return space_rmMarkerSpob( objid, type );
3886 default:
3887 WARN(_("Unknown marker type."));
3888 return -1;
3889 }
3890}
3891
3898int space_sysSave( xmlTextWriterPtr writer )
3899{
3900 xmlw_startElem(writer,"space");
3901 for (int i=0; i<array_size(systems_stack); i++) {
3902 StarSystem *sys = &systems_stack[i];
3903
3904 if (!sys_isKnown(sys))
3905 continue; /* not known */
3906
3907 xmlw_startElem(writer,"known");
3908 xmlw_attr(writer,"sys","%s",sys->name);
3909 if (sys_isFlag(sys, SYSTEM_PMARKED))
3910 xmlw_attr(writer,"pmarked","%s","true");
3911 if (sys->note != NULL)
3912 xmlw_attr(writer,"note","%s",sys->note);
3913 for (int j=0; j<array_size(sys->spobs); j++) {
3914 if (!spob_isKnown(sys->spobs[j]))
3915 continue; /* not known */
3916 xmlw_elem(writer, "spob", "%s", sys->spobs[j]->name);
3917 }
3918
3919 for (int j=0; j<array_size(sys->jumps); j++) {
3920 if (!jp_isKnown(&sys->jumps[j]))
3921 continue; /* not known */
3922 xmlw_elem(writer,"jump","%s",(&sys->jumps[j])->target->name);
3923 }
3924
3925 xmlw_endElem(writer);
3926 }
3927 xmlw_endElem(writer); /* "space" */
3928
3929 return 0;
3930}
3931
3938int space_sysLoad( xmlNodePtr parent )
3939{
3940 xmlNodePtr node;
3941
3943
3944 node = parent->xmlChildrenNode;
3945 do {
3946 xmlNodePtr cur;
3947
3948 xml_onlyNodes(node);
3949 if (!xml_isNode(node,"space"))
3950 continue;
3951
3952 cur = node->xmlChildrenNode;
3953 do {
3954 char *str;
3955 StarSystem *sys;
3956
3957 xml_onlyNodes( cur );
3958 if (!xml_isNode(cur,"known"))
3959 continue;
3960
3961 xmlr_attr_strd(cur,"sys",str);
3962 if (str != NULL) { /* check for 0.5.0 saves */
3963 sys = system_get(str);
3964 free(str);
3965 }
3966 else /* load from 0.5.0 saves */
3967 sys = system_get(xml_get(cur));
3968
3969 if (sys != NULL) { /* Must exist */
3970 sys_setFlag(sys,SYSTEM_KNOWN);
3971
3972 xmlr_attr_strd(cur,"pmarked",str);
3973 if (str != NULL) {
3974 sys_setFlag(sys,SYSTEM_PMARKED);
3975 free(str);
3976 }
3977
3978 xmlr_attr_strd(cur,"note",str);
3979 if (str != NULL) {
3980 xmlr_attr_strd(cur,"note",sys->note);
3981 free(str);
3982 }
3983 space_parseSpobs(cur, sys);
3984 }
3985 } while (xml_nextNode(cur));
3986 } while (xml_nextNode(node));
3987
3988 return 0;
3989}
3990
3998static int space_parseSpobs( xmlNodePtr parent, StarSystem* sys )
3999{
4000 xmlNodePtr node = parent->xmlChildrenNode;
4001 do {
4002 if (xml_isNode(node,"spob")) {
4003 Spob *spob = spob_get(xml_get(node));
4004 if (spob != NULL) /* Must exist */
4005 spob_setKnown(spob);
4006 }
4007 else if (xml_isNode(node,"jump")) {
4008 JumpPoint *jp = jump_get(xml_get(node), sys);
4009 if (jp != NULL) /* Must exist */
4010 jp_setFlag(jp,JP_KNOWN);
4011 }
4012 } while (xml_nextNode(node));
4013
4014 return 0;
4015}
4016
4025static int getPresenceIndex( StarSystem *sys, int faction )
4026{
4027 int n;
4028
4029 /* Check for NULL and display a warning. */
4030 if (sys == NULL) {
4031 WARN("sys == NULL");
4032 return 0;
4033 }
4034
4035 /* Go through the array (if created), looking for the faction. */
4036 for (int i=0; i < array_size(sys->presence); i++)
4037 if (sys->presence[i].faction == faction)
4038 return i;
4039
4040 /* Grow the array. */
4041 n = array_size(sys->presence);
4042 memset(&array_grow(&sys->presence), 0, sizeof(SystemPresence));
4043 sys->presence[n].faction = faction;
4044
4045 return n;
4046}
4047
4054void system_presenceAddSpob( StarSystem *sys, const SpobPresence *ap )
4055{
4056 int id, curSpill;
4057 Queue q, qn;
4058 double spillfactor;
4059 int faction = ap->faction;
4060 double base = ap->base;
4061 double bonus = ap->bonus;
4062 double range = ap->range;
4063 int usehidden = faction_usesHiddenJumps( faction );
4064 const FactionGenerator *fgens;
4065
4066 /* Check for NULL and display a warning. */
4067 if (sys == NULL) {
4068 WARN("sys == NULL");
4069 return;
4070 }
4071
4072 /* Check that we have a valid faction. */
4073 if (faction_isFaction(faction) == 0)
4074 return;
4075
4076 /* Check that we're actually adding any. */
4077 if ((base == 0.) && (bonus == 0.))
4078 return;
4079
4080 /* Get secondary if applicable. */
4081 fgens = faction_generators( faction );
4082
4083 /* Add the presence to the current system. */
4084 id = getPresenceIndex(sys, faction);
4085 sys->presence[id].base = MAX( sys->presence[id].base, base );
4086 sys->presence[id].bonus += bonus;
4087 sys->presence[id].value = sys->presence[id].base + sys->presence[id].bonus;
4088 for (int i=0; i<array_size(fgens); i++) {
4089 int x = getPresenceIndex(sys, fgens[i].id);
4090 sys->presence[x].base = MAX( sys->presence[x].base, MAX(0., base*fgens[i].weight) );
4091 sys->presence[x].bonus += MAX(0., bonus*fgens[i].weight);
4092 sys->presence[x].value = sys->presence[x].base + sys->presence[x].bonus;
4093 }
4094
4095 /* If there's no range, we're done here. */
4096 if (range < 1)
4097 return;
4098
4099 /* Add the spill. */
4100 sys->spilled = 1;
4101 curSpill = 0;
4102 q = q_create();
4103 qn = q_create();
4104
4105 /* Create the initial queue consisting of sys adjacencies. */
4106 for (int i=0; i < array_size(sys->jumps); i++) {
4107 if (sys->jumps[i].target->spilled == 0 && (usehidden || !jp_isFlag( &sys->jumps[i], JP_HIDDEN )) && !jp_isFlag( &sys->jumps[i], JP_EXITONLY )) {
4108 q_enqueue( q, sys->jumps[i].target );
4109 sys->jumps[i].target->spilled = 1;
4110 }
4111 }
4112
4113 /* If it's empty, something's wrong. */
4114 if (q_isEmpty(q)) {
4115 /* Means system isn't connected. */
4116 /*WARN(_("q is empty after getting adjacencies of %s."), sys->name);*/
4117 q_destroy(q);
4118 q_destroy(qn);
4119 goto sys_cleanup;
4120 }
4121
4122 while (curSpill < range) {
4123 int x;
4124
4125 /* Pull one off the current range queue. */
4126 StarSystem *cur = q_dequeue(q);
4127
4128 /* Ran out of candidates before running out of spill range! */
4129 if (cur == NULL)
4130 break;
4131
4132 /* Enqueue all its adjacencies to the next range queue. */
4133 for (int i=0; i<array_size(cur->jumps); i++) {
4134 if (cur->jumps[i].target->spilled == 0 && (usehidden || !jp_isFlag( &cur->jumps[i], JP_HIDDEN )) && !jp_isFlag( &cur->jumps[i], JP_EXITONLY )) {
4135 q_enqueue( qn, cur->jumps[i].target );
4136 cur->jumps[i].target->spilled = 1;
4137 }
4138 }
4139
4140 /* Spill some presence. */
4141 x = getPresenceIndex(cur, faction);
4142 spillfactor = 1. / (2. + (double)curSpill);
4143 cur->presence[x].base = MAX( cur->presence[x].base, base * spillfactor );
4144 cur->presence[x].bonus += bonus * spillfactor;
4145 cur->presence[x].value = cur->presence[x].base + cur->presence[x].bonus;
4146
4147 for (int i=0; i<array_size(fgens); i++) {
4148 int y = getPresenceIndex(cur, fgens[i].id);
4149 cur->presence[y].base = MAX( cur->presence[y].base, MAX(0., base*spillfactor*fgens[i].weight) );
4150 cur->presence[y].bonus += MAX(0., bonus*spillfactor*fgens[i].weight );
4151 cur->presence[y].value = cur->presence[y].base + cur->presence[y].bonus;
4152 }
4153
4154 /* Check to see if we've finished this range and grab the next queue. */
4155 if (q_isEmpty(q)) {
4156 curSpill++;
4157 q_destroy(q);
4158 q = qn;
4159 qn = q_create();
4160 }
4161 }
4162
4163 /* Destroy the queues. */
4164 q_destroy(q);
4165 q_destroy(qn);
4166
4167sys_cleanup:
4168 /* Clean up our mess. */
4169 for (int i=0; i < array_size(systems_stack); i++)
4170 systems_stack[i].spilled = 0;
4171 return;
4172}
4173
4181double system_getPresence( const StarSystem *sys, int faction )
4182{
4183 /* Check for NULL and display a warning. */
4184#if DEBUGGING
4185 if (sys == NULL) {
4186 WARN("sys == NULL");
4187 return 0.;
4188 }
4189#endif /* DEBUGGING */
4190
4191 /* Go through the array, looking for the faction. */
4192 for (int i=0; i < array_size(sys->presence); i++) {
4193 if (sys->presence[i].faction == faction)
4194 return MAX(sys->presence[i].value, 0.);
4195 }
4196
4197 /* If it's not in there, it's zero. */
4198 return 0.;
4199}
4200
4210double system_getPresenceFull( const StarSystem *sys, int faction, double *base, double *bonus )
4211{
4212 /* Check for NULL and display a warning. */
4213#if DEBUGGING
4214 if (sys == NULL) {
4215 WARN("sys == NULL");
4216 return 0;
4217 }
4218#endif /* DEBUGGING */
4219
4220 /* Go through the array, looking for the faction. */
4221 for (int i=0; i < array_size(sys->presence); i++) {
4222 if (sys->presence[i].faction == faction) {
4223 *base = sys->presence[i].base;
4224 *bonus = sys->presence[i].bonus;
4225 return MAX(sys->presence[i].value, 0);
4226 }
4227 }
4228
4229 /* If it's not in there, it's zero. */
4230 *base = 0.;
4231 *bonus = 0.;
4232 return 0.;
4233}
4234
4240void system_addAllSpobsPresence( StarSystem *sys )
4241{
4242 /* Check for NULL and display a warning. */
4243#if DEBUGGING
4244 if (sys == NULL) {
4245 WARN("sys == NULL");
4246 return;
4247 }
4248#endif /* DEBUGGING */
4249
4250 /* Real spobs. */
4251 for (int i=0; i<array_size(sys->spobs); i++)
4252 system_presenceAddSpob(sys, &sys->spobs[i]->presence );
4253
4254 /* Virtual spobs. */
4255 for (int i=0; i<array_size(sys->spobs_virtual); i++)
4256 for (int j=0; j<array_size(sys->spobs_virtual[i]->presences); j++)
4257 system_presenceAddSpob(sys, &sys->spobs_virtual[i]->presences[j] );
4258}
4259
4264{
4265 /* Reset the presence in each system. */
4266 for (int i=0; i<array_size(systems_stack); i++) {
4267 array_free(systems_stack[i].presence);
4268 systems_stack[i].presence = array_create( SystemPresence );
4269 systems_stack[i].ownerpresence = 0.;
4270 }
4271
4272 /* Re-add presence to each system. */
4273 for (int i=0; i<array_size(systems_stack); i++)
4275
4276 /* Determine dominant faction. */
4277 for (int i=0; i<array_size(systems_stack); i++) {
4279 systems_stack[i].ownerpresence = system_getPresence( &systems_stack[i], systems_stack[i].faction );
4280 }
4281
4282 /* Have to redo the scheduler because everything changed. */
4283 /* TODO this actually ignores existing presence and will temporarily increase system presence more than normal... */
4284 if (cur_system != NULL)
4285 system_scheduler( 0., 1 );
4286}
4287
4294int system_hasSpob( const StarSystem *sys )
4295{
4296 /* Check for NULL and display a warning. */
4297 if (sys == NULL) {
4298 WARN("sys == NULL");
4299 return 0;
4300 }
4301
4302 /* Go through all the spobs and look for a real one. */
4303 for (int i=0; i < array_size(sys->spobs); i++)
4304 return 1;
4305
4306 return 0;
4307}
4308
4312void system_rmCurrentPresence( StarSystem *sys, int faction, double amount )
4313{
4314 int id;
4315 nlua_env env;
4316 SystemPresence *presence;
4317
4318 /* Remove the presence. */
4319 id = getPresenceIndex( cur_system, faction );
4320 sys->presence[id].curUsed -= amount;
4321
4322 /* Safety. */
4323 presence = &sys->presence[id];
4324 presence->curUsed = MAX( 0, sys->presence[id].curUsed );
4325
4326 /* Run lower hook. */
4327 env = faction_getScheduler( faction );
4328
4329 /* Run decrease function if applicable. */
4330 nlua_getenv( naevL, env, "decrease" ); /* f */
4331 if (lua_isnil(naevL,-1)) {
4332 lua_pop(naevL,1);
4333 return;
4334 }
4335 lua_pushnumber( naevL, presence->curUsed ); /* f, cur */
4336 lua_pushnumber( naevL, presence->value ); /* f, cur, max */
4337 lua_pushnumber( naevL, presence->timer ); /* f, cur, max, timer */
4338
4339 /* Actually run the function. */
4340 if (nlua_pcall(env, 3, 1)) { /* error has occurred */
4341 WARN(_("Lua decrease script for faction '%s' : %s"),
4342 faction_name( faction ), lua_tostring(naevL,-1));
4343 lua_pop(naevL,1);
4344 return;
4345 }
4346
4347 /* Output is handled the same way. */
4348 if (!lua_isnumber(naevL,-1)) {
4349 WARN(_("Lua spawn script for faction '%s' failed to return timer value."),
4350 faction_name( presence->faction ) );
4351 lua_pop(naevL,1);
4352 return;
4353 }
4354 presence->timer = lua_tonumber(naevL,-1);
4355 lua_pop(naevL,1);
4356}
4357
4365{
4366 space_landQueueSpob = pnt;
4367}
4368
4375const char *space_populationStr( const Spob *spb )
4376{
4377 static char pop[STRMAX_SHORT];
4378 double p;
4379
4380 if (spb->lua_population != LUA_NOREF) {
4381 spob_luaInitMem( spb );
4382 lua_rawgeti(naevL, LUA_REGISTRYINDEX, spb->lua_population); /* f */
4383 if (nlua_pcall( spb->lua_env, 0, 1 )) {
4384 WARN(_("Spob '%s' failed to run '%s':\n%s"), spb->name, "population", lua_tostring(naevL,-1));
4385 lua_pop(naevL,1);
4386 return "";
4387 }
4388
4389 scnprintf( pop, sizeof(pop), "%s", luaL_checkstring(naevL,-1) );
4390 lua_pop(naevL,1);
4391 return pop;
4392 }
4393
4394 /* Out of respect for the first version of this, do something fancy and human-oriented.
4395 * However, specifying a thousand/million/billion system failed in a few ways: needing 2x as many cases as
4396 * intended to avoid silliness (1.0e10 -> 10000 million), and not being gettext-translatable to other number
4397 * systems like the Japanese one. */
4398 p = (double)spb->population;
4399 if (p < 1.0e3)
4400 snprintf( pop, sizeof(pop), "%.0f", p );
4401 else {
4402 char scratch[STRMAX_SHORT];
4403 const char *digits[] = {"\xe2\x81\xb0", "\xc2\xb9", "\xc2\xb2", "\xc2\xb3", "\xe2\x81\xb4", "\xe2\x81\xb5", "\xe2\x81\xb6", "\xe2\x81\xb7", "\xe2\x81\xb8", "\xe2\x81\xb9"};
4404 int state = 0, COEF = 0, E = 1, EXP = 4;
4405 size_t l = scnprintf( pop, sizeof(pop), _("roughly ") );
4406 snprintf( scratch, sizeof(scratch), "%.1e", p );
4407 for (const char *c = scratch; *c; c++) {
4408 if (state == COEF && *c != 'e')
4409 l += scnprintf( &pop[l], sizeof(pop)-l, "%c", *c );
4410 else if (state == COEF ) {
4411 l += scnprintf( &pop[l], sizeof(pop)-l, "%s", "\xc2\xb7" "10" );
4412 state = E;
4413 }
4414 else if (state == E && (*c == '+' || *c == '0'))
4415 state = E;
4416 else {
4417 state = EXP;
4418 l += scnprintf( &pop[l], sizeof(pop)-l, "%s", digits[*c-'0'] );
4419 }
4420 }
4421 }
4422
4423 return pop;
4424}
4425
4432static const MapShader *mapshader_get( const char *name )
4433{
4434 MapShader *ms;
4435
4436 if (mapshaders==NULL)
4438
4439 for (int i=0; i<array_size(mapshaders); i++) {
4440 MapShader *t = mapshaders[i];
4441 if (strcmp(t->name,name)==0)
4442 return t;
4443 }
4444
4445 /* Allocate and set up. */
4446 ms = malloc( sizeof(MapShader) );
4448
4449 ms->name = strdup( name );
4450 ms->program = gl_program_vert_frag( "system_map.vert", name, NULL );
4451 ms->vertex = glGetAttribLocation( ms->program, "vertex" );
4452 ms->projection= glGetUniformLocation( ms->program, "projection" );
4453 ms->time = glGetUniformLocation( ms->program, "time" );
4454 ms->globalpos = glGetUniformLocation( ms->program, "globalpos" );
4455 ms->alpha = glGetUniformLocation( ms->program, "alpha" );
4456
4457 return ms;
4458}
4459
4460static int spob_lua_cmp( const void *a, const void *b )
4461{
4462 const spob_lua_file *la = (const spob_lua_file*) a;
4463 const spob_lua_file *lb = (const spob_lua_file*) b;
4464 return strcmp( la->filename, lb->filename );
4465}
4466
4467static nlua_env spob_lua_get( int *mem, const char *filename )
4468{
4469 size_t sz;
4470 char *dat;
4471 spob_lua_file *lf;
4472 const spob_lua_file key = { .filename=filename };
4473
4474 if (spob_lua_stack == NULL)
4476
4477 lf = bsearch( &key, spob_lua_stack, array_size(spob_lua_stack), sizeof(spob_lua_file), spob_lua_cmp );
4478 if (lf != NULL) {
4479 *mem = lf->lua_mem;
4480 return lf->env;
4481 }
4482
4483 dat = ndata_read( filename, &sz );
4484 if (dat==NULL) {
4485 WARN(_("Failed to read spob Lua '%s'!"), filename );
4486 return LUA_NOREF;
4487 }
4488
4489 nlua_env env = nlua_newEnv();
4490 nlua_loadStandard( env );
4491 nlua_loadGFX( env );
4492 nlua_loadCamera( env );
4493
4494 /* Add new entry and sort. */
4495 lf = &array_grow( &spob_lua_stack );
4496 lf->filename = strdup( filename );
4497 lf->env = env;
4498
4499 /* Add the spob memory table. */
4500 lua_newtable(naevL); /* m */
4501 lua_pushvalue(naevL, -1); /* m, m */
4502 lf->lua_mem = luaL_ref( naevL, LUA_REGISTRYINDEX ); /* m */
4503 nlua_setenv(naevL, env, "mem"); /* */
4504 *mem = lf->lua_mem;
4505
4506 if (nlua_dobufenv(env, dat, sz, filename) != 0) {
4507 int n;
4508 WARN(_("Lua Spob '%s' error:\n%s"), filename, lua_tostring(naevL,-1));
4509 lua_pop(naevL,1);
4510 spob_lua_free( lf );
4511 free( dat );
4514 return LUA_NOREF;
4515 }
4516 free(dat);
4517
4518 qsort( spob_lua_stack, array_size(spob_lua_stack), sizeof(spob_lua_file), spob_lua_cmp );
4519 return env;
4520}
4521
4522static void spob_lua_free( spob_lua_file *lf )
4523{
4524 free( (char *) lf->filename );
4525 nlua_freeEnv( lf->env );
4526 luaL_unref( naevL, LUA_REGISTRYINDEX, lf->lua_mem );
4527}
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:158
#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_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
void asteroids_render(void)
Renders the current systems' spobs.
Definition asteroid.c:817
void asteroids_computeInternals(AsteroidAnchor *a)
Updates internal alues of an asteroid field.
Definition asteroid.c:439
void asteroids_free(void)
Cleans up the system.
Definition asteroid.c:947
int asteroids_load(void)
Loads the asteroids.
Definition asteroid.c:461
void asteroid_free(AsteroidAnchor *ast)
Frees an asteroid anchor.
Definition asteroid.c:934
AsteroidTypeGroup * astgroup_getName(const char *name)
Gets an asteroid type group by name.
Definition asteroid.c:1057
void asteroids_init(void)
Initializes the system.
Definition asteroid.c:253
void asteroids_renderOverlay(void)
Renders the system overlay.
Definition asteroid.c:799
void asteroids_update(double dt)
Controls fleet spawning.
Definition asteroid.c:73
void background_clear(void)
Cleans up the background stuff.
Definition background.c:489
void background_initDust(int n)
Initializes background dust.
Definition background.c:90
void background_renderOverlay(double dt)
Renders the background overlay.
Definition background.c:267
void background_render(double dt)
Render the background.
Definition background.c:229
int background_load(const char *name)
Loads a background script by name.
Definition background.c:427
double CollideCircleIntersection(const vec2 *p1, double r1, const vec2 *p2, double r2)
Calculates the area of intersection between two circles.
Definition collision.c:1071
Commodity * commodity_get(const char *name)
Gets a commodity by name.
Definition commodity.c:127
Commodity ** standard_commodities(void)
Return an array (array.h) of standard commodities. Free with array_free. (Don't free contents....
Definition commodity.c:240
int dtype_get(const char *name)
Gets the id of a dtype based on name.
Definition damagetype.c:159
void economy_addQueuedUpdate(void)
Increments the queued update counter.
Definition economy.c:475
credits_t economy_getPriceAtTime(const Commodity *com, const StarSystem *sys, const Spob *p, ntime_t tme)
Gets the price of a good on a spob in a system.
Definition economy.c:101
void economy_initialiseCommodityPrices(void)
Initialises commodity prices for the sinusoidal economy model.
Definition economy.c:859
void economy_clearSingleSpob(Spob *p)
Clears all economy knowledge of a given spob. Used by the unidiff system.
Definition economy.c:984
credits_t economy_getPrice(const Commodity *com, const StarSystem *sys, const Spob *p)
Gets the price of a good on a spob in a system.
Definition economy.c:85
int economy_getAverageSpobPrice(const Commodity *com, const Spob *p, credits_t *mean, double *std)
Gets the average price of a good on a spob in a system, using a rolling average over the times the pl...
Definition economy.c:172
int faction_isFaction(int f)
Checks whether or not a faction is valid.
Definition faction.c:1277
int areEnemies(int a, int b)
Checks whether two factions are enemies.
Definition faction.c:1227
void factions_clearDynamic(void)
Clears dynamic factions.
Definition faction.c:1893
const char * faction_name(int f)
Gets a factions "real" (internal) name.
Definition faction.c:306
const FactionGenerator * faction_generators(int f)
Gets the faction's generators.
Definition faction.c:1883
int faction_usesHiddenJumps(int f)
Checks to see if a faction uses hidden jumps.
Definition faction.c:1873
nlua_env faction_getScheduler(int f)
Gets the state associated to the faction scheduler.
Definition faction.c:728
int faction_get(const char *name)
Gets a faction ID by name.
Definition faction.c:184
int areAllies(int a, int b)
Checks whether two factions are allies or not.
Definition faction.c:1253
void gatherable_free(void)
Frees all the gatherables.
Definition gatherable.c:142
void gatherable_update(double dt)
Updates all gatherable objects.
Definition gatherable.c:92
void gatherable_render(void)
Renders all the gatherables.
Definition gatherable.c:150
void gui_setSystem(void)
Player just changed their system.
Definition gui.c:1799
void gui_updateFaction(void)
Player's relationship with a faction was modified.
Definition gui.c:1807
void player_message(const char *fmt,...)
Adds a mesg to the queue to be displayed on screen.
Definition gui.c:335
void player_messageToggle(int enable)
Toggles if player should receive messages.
Definition gui.c:288
int hooks_runParam(const char *stack, const HookParam *param)
Runs all the hooks of stack.
Definition hook.c:979
void land(Spob *p, int load)
Opens up all the land dialogue stuff.
Definition land.c:1124
Handles the important game menus.
#define MENU_MAIN
Definition menu.h:9
#define MENU_EDITORS
Definition menu.h:15
#define menu_isOpen(f)
Definition menu.h:16
int music_choose(const char *situation)
Actually runs the music stuff, based on situation.
Definition music.c:412
void naev_renderLoadscreen(void)
Renders the loadscreen if necessary.
Definition naev.c:597
void update_routine(double dt, int dohooks)
Actually runs the updates.
Definition naev.c:1038
const double fps_min
Definition naev.c:118
static double real_dt
Definition naev.c:113
Header file with generic functions and naev-specifics.
#define ABS(x)
Definition naev.h:36
#define pow2(x)
Definition naev.h:46
#define MAX(x, y)
Definition naev.h:39
#define PATH_MAX
Definition naev.h:50
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
Definition ndata.c:154
int ndata_matchExt(const char *path, const char *ext)
Sees if a file matches an extension.
Definition ndata.c:365
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition ndata.c:231
void nebu_update(double dt)
Updates visibility and stuff.
Definition nebula.c:224
void nebu_renderOverlay(const double dt)
Renders the nebula overlay (hides what player can't see).
Definition nebula.c:271
void nebu_render(const double dt)
Renders the nebula.
Definition nebula.c:147
void nebu_prep(double density, double volatility, double hue)
Prepares the nebualae to be rendered.
Definition nebula.c:379
int nlua_loadStandard(nlua_env env)
Loads the standard Naev Lua API.
Definition nlua.c:798
int nlua_refenvtype(nlua_env env, const char *name, int type)
Gets the reference of a global in a lua environment if it matches a type.
Definition nlua.c:920
int nlua_loadCamera(nlua_env env)
Loads the camera library.
Definition nlua_camera.c:49
int nlua_loadGFX(nlua_env env)
Loads the graphics library.
Definition nlua_gfx.c:98
LuaPilot lua_topilot(lua_State *L, int ind)
Lua bindings to interact with pilots.
Definition nlua_pilot.c:522
int lua_ispilot(lua_State *L, int ind)
Checks to see if ind is a pilot.
Definition nlua_pilot.c:578
LuaSpob * lua_pushspob(lua_State *L, LuaSpob spob)
Pushes a spob on the stack.
Definition nlua_spob.c:201
glTexture * lua_totex(lua_State *L, int ind)
Lua bindings to interact with OpenGL textures.
Definition nlua_tex.c:89
int lua_istex(lua_State *L, int ind)
Checks to see if ind is a texture.
Definition nlua_tex.c:145
void arrayShuffle(void **array)
Randomly sorts an array (array.h) of pointers in place with the Fisher-Yates shuffle.
Definition nmath.c:67
int scnprintf(char *text, size_t maxlen, const char *fmt,...)
Like snprintf(), but returns the number of characters ACTUALLY "printed" into the buffer....
Definition nstring.c:99
char * ntime_pretty(ntime_t t, int d)
Gets the time in a pretty human readable format.
Definition ntime.c:173
void ntime_allowUpdate(int enable)
Allows the time to update when the game is updating.
Definition ntime.c:251
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
Definition nxml.c:75
void gl_renderSprite(const glTexture *sprite, double bx, double by, int sx, int sy, const glColour *c)
Blits a sprite, position is relative to the player.
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
Definition opengl_tex.c:917
glTexture * gl_newSprite(const char *path, const int sx, const int sy, const unsigned int flags)
Loads the texture immediately, but also sets it as a sprite.
Definition opengl_tex.c:791
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition opengl_tex.c:675
void gl_getSpriteFromDir(int *x, int *y, const glTexture *t, const double dir)
Sets x and y to be the appropriate sprite for glTexture using dir.
Definition opengl_tex.c:967
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition opengl_tex.c:862
void pilots_clean(int persist)
Cleans up the pilot stack - leaves the player.
Definition pilot.c:3696
void pilot_clearTimers(Pilot *pilot)
Clears the pilot's timers.
Definition pilot.c:3945
Pilot * pilot_get(unsigned int id)
Pulls a pilot out of the pilot_stack based on ID.
Definition pilot.c:620
static Pilot ** pilot_stack
Definition pilot.c:61
Pilot *const * pilot_getAll(void)
Gets the pilot stack.
Definition pilot.c:94
void pilots_newSystem(void)
Updates pilot state which depends on the system (sensor range, nebula trails...)
Definition pilot.c:3755
double pilot_hit(Pilot *p, const Solid *w, const Pilot *pshooter, const Damage *dmg, const Outfit *outfit, int lua_mem, int reset)
Damages the pilot.
Definition pilot.c:1338
int pilot_inRangeSpob(const Pilot *p, int target)
Check to see if a spob is in sensor range of the pilot.
Definition pilot_ew.c:279
int pilot_inRangeJump(const Pilot *p, int i)
Check to see if a jump point is in sensor range of the pilot.
Definition pilot_ew.c:344
int pilot_inRangeAsteroid(const Pilot *p, int ast, int fie)
Check to see if an asteroid is in sensor range of the pilot.
Definition pilot_ew.c:309
void pilot_calcStats(Pilot *pilot)
Recalculates the pilot's stats based on his outfits.
void pilot_lockClear(Pilot *p)
Clears pilot's missile lockon timers.
void player_checkLandAck(void)
Revokes landing authorization if the player's reputation is too low.
Definition player.c:1713
void player_clear(void)
Clears the targets.
Definition player.c:947
Player_t player
Definition player.c:74
void * q_dequeue(Queue q)
Dequeues an item.
Definition queue.c:125
int q_isEmpty(Queue q)
Checks if the queue is empty.
Definition queue.c:158
void q_destroy(Queue q)
Destroys a queue.
Definition queue.c:69
Queue q_create(void)
Creates a queue.
Definition queue.c:43
void q_enqueue(Queue q, void *data)
Enqueues an item.
Definition queue.c:94
static const double c[]
Definition rng.c:264
static const double d[]
Definition rng.c:273
void ss_free(ShipStatList *ll)
Frees a list of ship stats.
Definition shipstats.c:887
ShipStatList * ss_listFromXML(xmlNodePtr node)
Creates a shipstat list element from an xml node.
Definition shipstats.c:292
int ss_sort(ShipStatList **ll)
Sorts the ship stats, useful if doing saving stuff.
Definition shipstats.c:381
int sound_disabled
Definition sound.c:133
int sound_env(SoundEnv_t env_type, double param)
Sets up the sound environment.
Definition sound.c:1649
static int spob_cmp(const void *p1, const void *p2)
Comparison function for qsort'ing Spob by name.
Definition space.c:1037
void space_reconstructPresences(void)
Reset the presence of all systems.
Definition space.c:4263
void space_init(const char *sysname, int do_simulate)
Initializes the system.
Definition space.c:1549
double system_getClosestAng(const StarSystem *sys, int *pnt, int *jp, int *ast, int *fie, double x, double y, double ang)
Gets the feature nearest to directly ahead of a position in the system.
Definition space.c:766
int system_addJumpDiff(StarSystem *sys, xmlNodePtr node)
Adds a jump point to a star system from a diff.
Definition space.c:2606
static int spobs_load(void)
Loads all the spobs in the game.
Definition space.c:1764
void spob_averageSeenPricesAtTime(const Spob *p, const ntime_t tupdate)
Adds cost of commodities on spob p to known statistics at time t.
Definition space.c:303
static int system_cmp(const void *p1, const void *p2)
Comparison function for qsort'ing StarSystem by name.
Definition space.c:946
double system_getClosest(const StarSystem *sys, int *pnt, int *jp, int *ast, int *fie, double x, double y)
Gets the closest feature to a position in the system.
Definition space.c:687
int spob_exists(const char *spobname)
Check to see if a spob exists.
Definition space.c:1126
void system_rmCurrentPresence(StarSystem *sys, int faction, double amount)
Removes active presence.
Definition space.c:4312
void space_gfxUnload(StarSystem *sys)
Unloads all the graphics for a star system.
Definition space.c:2127
#define FLAG_POSSET
Definition space.c:68
int space_canHyperspace(const Pilot *p)
Checks to make sure if pilot is far enough away to hyperspace.
Definition space.c:469
void space_render(const double dt)
Renders the system.
Definition space.c:3441
static void space_renderSpob(const Spob *p)
Renders a spob.
Definition space.c:3528
static int sys_cmpSysFaction(const void *a, const void *b)
Compares two system presences.
Definition space.c:3064
int spob_luaInit(Spob *spob)
Updatse the spob's internal Lua stuff.
Definition space.c:1997
static void system_init(StarSystem *sys)
Initializes a new star system with null memory.
Definition space.c:2658
void systems_reconstructJumps(void)
Reconstructs the jumps.
Definition space.c:2738
int space_jumpDistance(const Pilot *p, const JumpPoint *jp)
Distance at which a pilot can jump.
Definition space.c:455
const glColour * spob_getColour(const Spob *p)
Gets the spob colour.
Definition space.c:1922
int space_rmMarker(int objid, MissionMarkerType type)
Removes a marker from a system.
Definition space.c:3873
int spob_averageSpobPrice(const Spob *p, const Commodity *c, credits_t *mean, double *std)
Gets the average price of a commodity at a spob that has been seen so far.
Definition space.c:316
static char ** systemname_stack
Definition space.c:87
double system_getPresenceFull(const StarSystem *sys, int faction, double *base, double *bonus)
Get the presence of a faction in a system.
Definition space.c:4210
static int spob_parse(Spob *spob, const char *filename, Commodity **stdList)
Parses a spob from an xml node.
Definition space.c:2178
Spob * spob_getAll(void)
Gets an array (array.h) of all spobs.
Definition space.c:1107
int space_sysLoad(xmlNodePtr parent)
Loads player's space properties from an XML node.
Definition space.c:3938
int spob_rename(Spob *p, char *newname)
Renames a spob.
Definition space.c:431
#define XML_SPOB_TAG
Definition space.c:61
int spob_getService(const char *name)
Converts name to spob service flag.
Definition space.c:186
void system_setFaction(StarSystem *sys)
Sets the system faction based on the spobs it has.
Definition space.c:3091
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
Definition space.c:1051
void space_factionChange(void)
Mark when a faction changes.
Definition space.c:1392
static char ** spobname_stack
Definition space.c:86
int system_addVirtualSpob(StarSystem *sys, const char *spobname)
Adds a virtual spob to a system.
Definition space.c:2545
static int system_parseJumpPointDiff(const xmlNodePtr node, StarSystem *sys)
Parses a single jump point for a system, from unidiff.
Definition space.c:3118
const char * space_getRndSpob(int landable, unsigned int services, int(*filter)(Spob *p))
Gets the name of a random spob.
Definition space.c:633
int system_rmJump(StarSystem *sys, const char *jumpname)
Removes a jump point from a star system.
Definition space.c:2625
static spob_lua_file * spob_lua_stack
Definition space.c:81
void space_update(double dt, double real_dt)
Controls fleet spawning.
Definition space.c:1414
static int systems_load(void)
Loads the entire systems, needs to be called after spobs_load.
Definition space.c:3367
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
int spob_hasSystem(const Spob *spb)
Get whether or not a spob has a system (i.e. is on the map).
Definition space.c:1011
static int space_simulating
Definition space.c:110
#define FLAG_INTERFERENCESET
Definition space.c:69
static VirtualSpob * vspob_stack
Definition space.c:94
const char * jump_getSymbol(const JumpPoint *jp)
Gets the jump point symbol.
Definition space.c:1260
static int systemstack_changed
Definition space.c:98
const char * spob_getSymbol(const Spob *p)
Gets the spob symbol.
Definition space.c:1900
void space_renderOverlay(const double dt)
Renders the system overlay.
Definition space.c:3457
int spob_setFaction(Spob *p, int faction)
Changes the spobs faction.
Definition space.c:349
char spob_getColourChar(const Spob *p)
Gets the spob colour char.
Definition space.c:1881
StarSystem * system_new(void)
Creates a new star system.
Definition space.c:2673
static glTexture * jumpbuoy_gfx
Definition space.c:108
int space_sysReachable(const StarSystem *sys)
Sees if a system is reachable.
Definition space.c:826
JumpPoint * jump_getTarget(const StarSystem *target, const StarSystem *sys)
Less safe version of jump_get that works with pointers.
Definition space.c:1246
const char * system_existsCase(const char *sysname)
Checks to see if a system exists case insensitively.
Definition space.c:890
StarSystem * system_getAll(void)
Gets an array (array.h) of all star systems.
Definition space.c:879
char ** spob_searchFuzzyCase(const char *spobname, int *n)
Does a fuzzy case matching. Searches spob_name() but returns internal names.
Definition space.c:1151
int space_sysSave(xmlTextWriterPtr writer)
Saves what is needed to be saved for space.
Definition space.c:3898
int space_sysReachableFromSys(const StarSystem *target, const StarSystem *sys)
Sees if a system is reachable from another system.
Definition space.c:865
char ** system_searchFuzzyCase(const char *sysname, int *n)
Does a fuzzy case matching. Searches translated names but returns internal names.
Definition space.c:901
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_calcJumpInPos(const StarSystem *in, const StarSystem *out, vec2 *pos, vec2 *vel, double *dir, const Pilot *p)
Calculates the jump in pos for a pilot.
Definition space.c:527
int spob_rmService(Spob *p, int service)
Removes a service from a spob.
Definition space.c:418
static MapShader ** mapshaders
Definition space.c:100
static Spob * spob_stack
Definition space.c:93
void system_updateAsteroids(StarSystem *sys)
Updates some internal calculations about asteroids in a system.
Definition space.c:326
void spob_setKnown(Spob *p)
Sets a spob's known status, if it's real.
Definition space.c:1115
static void system_scheduler(double dt, int init)
Controls fleet spawning.
Definition space.c:1273
void spobs_render(void)
Renders the current systems' spobs.
Definition space.c:3476
StarSystem * cur_system
Definition space.c:106
const char * spob_existsCase(const char *spobname)
Check to see if a spob exists (case insensitive).
Definition space.c:1140
int system_addSpob(StarSystem *sys, const char *spobname)
Adds a spob to a star system.
Definition space.c:2452
void space_exit(void)
Cleans up the system.
Definition space.c:3564
static int getPresenceIndex(StarSystem *sys, int faction)
Gets the index of the presence element for a faction. Creates one if it doesn't exist.
Definition space.c:4025
int space_addMarker(int objid, MissionMarkerType type)
Adds a marker to a system.
Definition space.c:3787
static int spob_parsePresence(xmlNodePtr node, SpobPresence *ap)
Parsess an spob presence from xml.
Definition space.c:2152
double system_getPresence(const StarSystem *sys, int faction)
Get the presence of a faction in a system.
Definition space.c:4181
void spob_updateLand(Spob *p)
Updates the land possibilities of a spob.
Definition space.c:1943
int space_sysReallyReachable(const char *sysname)
Sees if a system can be reached via jumping.
Definition space.c:846
static int space_simulating_effects
Definition space.c:111
static void space_renderJumpPoint(const JumpPoint *jp, int i)
Renders a jump point.
Definition space.c:3501
void spob_gfxLoad(Spob *spob)
Loads a spob's graphics (and radius).
Definition space.c:2078
int system_rmVirtualSpob(StarSystem *sys, const char *spobname)
Removes a virtual spob from a system.
Definition space.c:2569
void space_clearMarkers(void)
Clears all system markers.
Definition space.c:3696
static int virtualspobs_load(void)
Loads all the virtual spobs.
Definition space.c:1810
VirtualSpob * virtualspob_getAll(void)
Gets all the virtual spobs.
Definition space.c:1186
Spob * spob_getIndex(int ind)
Gets spob by index.
Definition space.c:1082
void system_presenceAddSpob(StarSystem *sys, const SpobPresence *ap)
Adds (or removes) some presence to a system.
Definition space.c:4054
VirtualSpob * virtualspob_get(const char *name)
Gets a virtual spob by matching name.
Definition space.c:1205
static int space_parseSpobs(xmlNodePtr parent, StarSystem *sys)
Parses spobs in a system.
Definition space.c:3998
void space_clearKnown(void)
Clears all system knowledge.
Definition space.c:3677
StarSystem * systems_stack
Definition space.c:92
static int space_fchg
Definition space.c:109
void system_addAllSpobsPresence(StarSystem *sys)
Go through all the spobs and call system_addPresence().
Definition space.c:4240
int spob_addCommodity(Spob *p, Commodity *c)
Adds a commodity to a spob.
Definition space.c:362
static int system_parseJumps(StarSystem *sys)
Loads the jumps into a system.
Definition space.c:3276
static const MapShader * mapshader_get(const char *name)
Gets the map shader by name.
Definition space.c:4432
int system_hasSpob(const StarSystem *sys)
See if the system has a spob.
Definition space.c:4294
int spob_addService(Spob *p, int service)
Removes a service from a spob.
Definition space.c:376
static int systems_loading
Definition space.c:105
const char * spob_name(const Spob *p)
Gets the translated name of a spob.
Definition space.c:1752
static int spobstack_changed
Definition space.c:99
static int virtualspob_cmp(const void *p1, const void *p2)
Comparison function for qsort'ing VirtuaSpob by name.
Definition space.c:1194
const char * spob_getClassName(const char *class)
Gets the long class name for a spob.
Definition space.c:215
static int system_parseAsteroidExclusion(const xmlNodePtr node, StarSystem *sys)
Parses a single asteroid exclusion zone for a system.
Definition space.c:2847
const char * space_populationStr(const Spob *spb)
Gets the population in an approximated string. Note this function changes the string value each call,...
Definition space.c:4375
void space_clearComputerMarkers(void)
Clears all the system computer markers.
Definition space.c:3716
void space_queueLand(Spob *pnt)
Cues a spob to be landed on. This is not done immediately, but when the engine thinks it is ok to do.
Definition space.c:4364
static void space_updateSpob(const Spob *p, double dt, double real_dt)
Renders a spob.
Definition space.c:3546
int space_spawn
Definition space.c:117
static int system_parseAsteroidField(const xmlNodePtr node, StarSystem *sys)
Parses a single asteroid field for a system.
Definition space.c:2769
credits_t spob_commodityPrice(const Spob *p, const Commodity *c)
Gets the price of a commodity at a spob.
Definition space.c:276
const char * spob_getServiceName(int service)
Gets the (English) name for a service code.
Definition space.c:167
void systems_reconstructSpobs(void)
Updates the system spob pointers.
Definition space.c:2753
Spob * spob_new(void)
Creates a new spob.
Definition space.c:1709
int space_needsEffects(void)
returns whether or not we're simulating with effects.
Definition space.c:1538
char ** space_getFactionSpob(const int *factions, int landable)
Gets the name of all the spobs that belong to factions.
Definition space.c:590
#define FLAG_FACTIONSET
Definition space.c:71
void spob_luaInitMem(const Spob *spob)
Initializes the memory fo a spob.
Definition space.c:1986
JumpPoint * jump_get(const char *jumpname, const StarSystem *sys)
Gets a jump point based on its target and system.
Definition space.c:1222
void space_checkLand(void)
Handles landing if necessary.
Definition space.c:1400
glTexture * jumppoint_gfx
Definition space.c:107
void space_gfxLoad(StarSystem *sys)
Loads all the graphics for a star system.
Definition space.c:2116
int space_hyperspace(Pilot *p)
Tries to get the pilot into hyperspace.
Definition space.c:503
int space_load(void)
Loads the entire universe into ram - pretty big feat eh?
Definition space.c:3313
int space_isSimulation(void)
returns whether we're just simulating.
Definition space.c:1530
credits_t spob_commodityPriceAtTime(const Spob *p, const Commodity *c, ntime_t t)
Gets the price of a commodity at a spob at given time.
Definition space.c:290
int system_index(const StarSystem *sys)
Gets the index of a star system.
Definition space.c:1000
int system_rmSpob(StarSystem *sys, const char *spobname)
Removes a spob from a star system.
Definition space.c:2493
int space_loadLua(void)
initializes the Lua for all the spobs.
Definition space.c:3349
static int system_parseJumpPoint(const xmlNodePtr node, StarSystem *sys)
Parses a single jump point for a system.
Definition space.c:3190
static int system_parse(StarSystem *system, const char *filename)
Creates a system from an XML node.
Definition space.c:2897
void system_reconstructJumps(StarSystem *sys)
Reconstructs the jumps for a single system.
Definition space.c:2707
#define FLAG_SERVICESSET
Definition space.c:70
void spfx_clear(void)
Clears all the currently running effects.
Definition spfx.c:522
const char * start_spob_lua_default(void)
Gets the default spob Lua file.
Definition start.c:287
Represents an asteroid field anchor.
Definition asteroid.h:100
double radius
Definition asteroid.h:107
double density
Definition asteroid.h:104
Asteroid * asteroids
Definition asteroid.h:105
Represents an asteroid exclusion zone.
Definition asteroid.h:124
Represents a group of asteroids.
Definition asteroid.h:67
Represents a single asteroid.
Definition asteroid.h:77
int state
Definition asteroid.h:81
Solid sol
Definition asteroid.h:87
Represents a commodity.
Definition commodity.h:43
Core damage that an outfit does.
Definition outfit.h:138
int type
Definition outfit.h:139
double disable
Definition outfit.h:142
double penetration
Definition outfit.h:140
double damage
Definition outfit.h:141
The actual hook parameter.
Definition hook.h:38
const char * str
Definition hook.h:42
HookParamType type
Definition hook.h:39
union HookParam::@25 u
LuaSpob la
Definition hook.h:49
LuaJump lj
Definition hook.h:50
int destid
Definition nlua_jump.h:16
int srcid
Definition nlua_jump.h:15
Map shader.
Definition space.h:226
char * name
Definition space.h:227
GLuint time
Definition space.h:232
GLuint globalpos
Definition space.h:233
GLuint projection
Definition space.h:230
GLuint alpha
Definition space.h:231
GLuint program
Definition space.h:228
GLuint vertex
Definition space.h:229
The representation of an in-game pilot.
Definition pilot.h:217
int presence
Definition pilot.h:223
int nav_hyperspace
Definition pilot.h:345
int faction
Definition pilot.h:222
int nav_spob
Definition pilot.h:344
int devmode
Definition conf.h:157
Pilot * p
Definition player.h:101
int discover_off
Definition player.h:113
Represents relative ship statistics as a linked list.
Definition shipstats.h:167
struct ShipStatList_ * next
Definition shipstats.h:168
vec2 pos
Definition physics.h:49
Represents the presence of a spob.
Definition space.h:66
double bonus
Definition space.h:69
int range
Definition space.h:70
double base
Definition space.h:68
int faction
Definition space.h:67
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:89
int can_land
Definition space.h:108
char * gfx_commPath
Definition space.h:127
Commodity ** commodities
Definition space.h:116
glTexture * gfx_space
Definition space.h:121
char * land_msg
Definition space.h:110
unsigned int services
Definition space.h:115
int lua_update
Definition space.h:146
int land_override
Definition space.h:109
char * gfx_spacePath
Definition space.h:123
char * gfx_spaceName
Definition space.h:122
int lua_land
Definition space.h:144
double radius
Definition space.h:95
int markers
Definition space.h:134
double marker_scale
Definition space.h:97
char * feature
Definition space.h:93
char * bar_description
Definition space.h:114
int lua_comm
Definition space.h:147
int lua_render
Definition space.h:145
const SimpleShader * marker
Definition space.h:96
char * description
Definition space.h:113
char * class
Definition space.h:100
char ** tags
Definition space.h:130
int lua_mem
Definition space.h:139
int lua_barbg
Definition space.h:149
int lua_init
Definition space.h:140
int lua_load
Definition space.h:141
tech_group_t * tech
Definition space.h:118
double map_alpha
Definition space.h:133
uint64_t population
Definition space.h:101
char * gfx_exterior
Definition space.h:124
nlua_env lua_env
Definition space.h:138
char * name
Definition space.h:91
char * gfx_exteriorPath
Definition space.h:125
vec2 pos
Definition space.h:94
int id
Definition space.h:90
char * gfx_comm
Definition space.h:126
CommodityPrice * commodityPrice
Definition space.h:117
double hide
Definition space.h:105
int lua_can_land
Definition space.h:143
int lua_population
Definition space.h:148
int lua_unload
Definition space.h:142
SpobPresence presence
Definition space.h:104
char * display
Definition space.h:92
unsigned int flags
Definition space.h:131
Represents presence in a system.
Definition space.h:175
double curUsed
Definition space.h:180
double value
Definition space.h:179
double timer
Definition space.h:181
Basically modifies system parameters without creating any real objects.
Definition space.h:78
SpobPresence * presences
Definition space.h:80
char * name
Definition space.h:79
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:36
double w
Definition opengl_tex.h:40
double sx
Definition opengl_tex.h:44
double h
Definition opengl_tex.h:41
nlua_env env
Definition space.c:77
int lua_mem
Definition space.c:78
const char * filename
Definition space.c:76
Represents a 2d vector.
Definition vec2.h:32
double y
Definition vec2.h:34
double x
Definition vec2.h:33
tech_group_t * tech_groupCreateXML(xmlNodePtr node)
Creates a tech group from an XML node.
Definition tech.c:165
void tech_groupDestroy(tech_group_t *grp)
Frees a tech group.
Definition tech.c:185
void weapon_clear(void)
Clears all the weapons, does NOT free the layers.
Definition weapon.c:2680
void weapon_newSystem(void)
Sets up collision stuff for a new system.
Definition weapon.c:186