naev 0.10.4
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#ifdef DEBUGGING
96static int systemstack_changed = 0;
97static int spobstack_changed = 0;
98#endif /* DEBUGGING */
99static MapShader **mapshaders = NULL;
101/*
102 * Misc.
103 */
104static int systems_loading = 1;
105StarSystem *cur_system = NULL;
107static glTexture *jumpbuoy_gfx = NULL;
108static int space_fchg = 0;
109static int space_simulating = 0;
111static Spob *space_landQueueSpob = NULL;
112
113/*
114 * Fleet spawning.
115 */
116int space_spawn = 1;
118/*
119 * Internal Prototypes.
120 */
121/* spob load */
122static int spob_parse( Spob *spob, const char *filename, Commodity **stdList );
123static int space_parseSpobs( xmlNodePtr parent, StarSystem* sys );
124static int spob_parsePresence( xmlNodePtr node, SpobPresence *ap );
125/* system load */
126static void system_init( StarSystem *sys );
127static int systems_load (void);
128static int system_parse( StarSystem *system, const char *filename );
129static int system_parseJumpPoint( const xmlNodePtr node, StarSystem *sys );
130static int system_parseJumpPointDiff( const xmlNodePtr node, StarSystem *sys );
131static int system_parseJumps( StarSystem *sys );
132static int system_parseAsteroidField( const xmlNodePtr node, StarSystem *sys );
133static int system_parseAsteroidExclusion( const xmlNodePtr node, StarSystem *sys );
134/* misc */
135static int getPresenceIndex( StarSystem *sys, int faction );
136static void system_scheduler( double dt, int init );
137/* Markers. */
138static int space_addMarkerSystem( int sysid, MissionMarkerType type );
139static int space_addMarkerSpob( int pntid, MissionMarkerType type );
140static int space_rmMarkerSystem( int sysid, MissionMarkerType type );
141static int space_rmMarkerSpob( int pntid, MissionMarkerType type );
142/* Render. */
143static void space_renderJumpPoint( const JumpPoint *jp, int i );
144static void space_renderSpob( const Spob *p );
145static void space_updateSpob( const Spob *p, double dt, double real_dt );
146/* Map shaders. */
147static const MapShader *mapshader_get( const char *name );
148/* Lua stuff. */
149static int spob_lua_cmp( const void *a, const void *b );
150static nlua_env spob_lua_get( int *mem, const char *filename );
151static void spob_lua_free( spob_lua_file *lf );
152/*
153 * Externed prototypes.
154 */
155int space_sysSave( xmlTextWriterPtr writer );
156int space_sysLoad( xmlNodePtr parent );
157
165const char* spob_getServiceName( int service )
166{
167 switch (service) {
168 case SPOB_SERVICE_LAND: return N_("Land");
169 case SPOB_SERVICE_INHABITED: return N_("Inhabited");
170 case SPOB_SERVICE_REFUEL: return N_("Refuel");
171 case SPOB_SERVICE_BAR: return N_("Bar");
172 case SPOB_SERVICE_MISSIONS: return N_("Missions");
173 case SPOB_SERVICE_COMMODITY: return N_("Commodity");
174 case SPOB_SERVICE_OUTFITS: return N_("Outfits");
175 case SPOB_SERVICE_SHIPYARD: return N_("Shipyard");
176 case SPOB_SERVICE_BLACKMARKET: return N_("Blackmarket");
177 }
178 return NULL;
179}
180
184int spob_getService( const char *name )
185{
186 if (strcasecmp(name,"Land")==0)
187 return SPOB_SERVICE_LAND;
188 else if (strcasecmp(name,"Inhabited")==0)
189 return SPOB_SERVICE_INHABITED;
190 else if (strcasecmp(name,"Refuel")==0)
191 return SPOB_SERVICE_REFUEL;
192 else if (strcasecmp(name,"Bar")==0)
193 return SPOB_SERVICE_BAR;
194 else if (strcasecmp(name,"Missions")==0)
195 return SPOB_SERVICE_MISSIONS;
196 else if (strcasecmp(name,"Commodity")==0)
197 return SPOB_SERVICE_COMMODITY;
198 else if (strcasecmp(name,"Outfits")==0)
199 return SPOB_SERVICE_OUTFITS;
200 else if (strcasecmp(name,"Shipyard")==0)
201 return SPOB_SERVICE_SHIPYARD;
202 else if (strcasecmp(name,"Blackmarket")==0)
203 return SPOB_SERVICE_BLACKMARKET;
204 return -1;
205}
206
213const char* spob_getClassName( const char *class )
214{
215 if (strcmp(class,"0")==0)
216 return _("Civilian Station");
217 else if (strcmp(class,"1")==0)
218 return _("Military Station");
219 else if (strcmp(class,"2")==0)
220 return _("Pirate Station");
221 else if (strcmp(class,"3")==0)
222 return _("Robotic Station");
223 else if (strcmp(class,"A")==0)
224 return _("Geothermal");
225 else if (strcmp(class,"B")==0)
226 return _("Geomorteus");
227 else if (strcmp(class,"C")==0)
228 return _("Geoinactive");
229 else if (strcmp(class,"D")==0)
230 return _("Asteroid/Moon");
231 else if (strcmp(class,"E")==0)
232 return _("Geoplastic");
233 else if (strcmp(class,"F")==0)
234 return _("Geometallic");
235 else if (strcmp(class,"G")==0)
236 return _("Geocrystaline");
237 else if (strcmp(class,"H")==0)
238 return _("Desert");
239 else if (strcmp(class,"I")==0)
240 return _("Gas Supergiant");
241 else if (strcmp(class,"J")==0)
242 return _("Gas Giant");
243 else if (strcmp(class,"K")==0)
244 return _("Adaptable");
245 else if (strcmp(class,"L")==0)
246 return _("Marginal");
247 else if (strcmp(class,"M")==0)
248 return _("Terrestrial");
249 else if (strcmp(class,"N")==0)
250 return _("Reducing");
251 else if (strcmp(class,"O")==0)
252 return _("Pelagic");
253 else if (strcmp(class,"P")==0)
254 return _("Glaciated");
255 else if (strcmp(class,"Q")==0)
256 return _("Variable");
257 else if (strcmp(class,"R")==0)
258 return _("Rogue");
259 else if (strcmp(class,"S")==0 || strcmp(class,"T")==0)
260 return _("Ultragiants");
261 else if (strcmp(class,"X")==0 || strcmp(class,"Y")==0 || strcmp(class,"Z")==0)
262 return _("Demon");
263 return class;
264}
265
272credits_t spob_commodityPrice( const Spob *p, const Commodity *c )
273{
274 char *sysname = spob_getSystem( p->name );
275 StarSystem *sys = system_get( sysname );
276 return economy_getPrice( c, sys, p );
277}
278
286credits_t spob_commodityPriceAtTime( const Spob *p, const Commodity *c, ntime_t t )
287{
288 char *sysname = spob_getSystem( p->name );
289 StarSystem *sys = system_get( sysname );
290 return economy_getPriceAtTime( c, sys, p, t );
291}
292
299void spob_averageSeenPricesAtTime( const Spob *p, const ntime_t tupdate )
300{
301 economy_averageSeenPricesAtTime( p, tupdate );
302}
303
312int spob_averageSpobPrice( const Spob *p, const Commodity *c, credits_t *mean, double *std)
313{
314 return economy_getAverageSpobPrice( c, p, mean, std );
315}
316
322void system_updateAsteroids( StarSystem *sys )
323{
324 double density = 0.;
325 for (int i=0; i<array_size(sys->asteroids); i++) {
326 AsteroidAnchor *ast = &sys->asteroids[i];
327 density += ast->area * ast->density / ASTEROID_REF_AREA;
328
329 /* Have to subtract excluded area. */
330 for (int j=0; j<array_size(sys->astexclude); j++) {
331 AsteroidExclusion *exc = &sys->astexclude[j];
332 density -= CollideCircleIntersection( &ast->pos, ast->radius, &exc->pos, exc->radius ) * ast->density / ASTEROID_REF_AREA;
333 }
334 }
335 sys->asteroid_density = density;
336}
337
345int spob_setFaction( Spob *p, int faction )
346{
347 p->presence.faction = faction;
348 return 0;
349}
350
359{
360 array_grow( &p->commodities ) = c;
361 array_grow( &p->commodityPrice ).price = c->price;
362 return 0;
363}
364
372int spob_addService( Spob *p, int service )
373{
374 p->services |= service;
375
376 if (service & SPOB_SERVICE_COMMODITY) {
377 const char *sysname;
378 StarSystem *sys;
379
380 /* Only try to add standard commodities if there aren't any. */
381 if (p->commodities!=NULL)
382 return 0;
383 Commodity **stdList = standard_commodities();
384 p->commodities = array_create( Commodity* );
385 p->commodityPrice = array_create( CommodityPrice );
386 for (int i=0; i<array_size(stdList); i++)
387 spob_addCommodity( p, stdList[i] );
388 array_free( stdList );
389
390 /* Clean up economy status. */
393
394 /* Try to figure out the system. */
395 sysname = spob_getSystem( p->name );
396 if (sysname==NULL) {
397 DEBUG(_("Spob '%s' not in system. Not initializing economy."), p->name);
398 return 0;
399 }
400 sys = system_get( sysname );
401 economy_initialiseSingleSystem( sys, p );
402 }
403
404 return 0;
405}
406
414int spob_rmService( Spob *p, int service )
415{
416 p->services &= ~service;
417 return 0;
418}
419
423int space_jumpDistance( const Pilot *p, const JumpPoint *jp )
424{
425 double r = jp->radius * p->stats.jump_distance;
426 if (pilot_isFlag( p, PILOT_STEALTH )) /* Stealth gives a jump distance bonus. */
427 r *= 3.;
428 return r;
429}
430
438{
439 double d, r;
440 JumpPoint *jp;
441
442 /* Must not have the nojump flag. */
443 if (pilot_isFlag(p, PILOT_NOJUMP))
444 return 0;
445
446 /* Must have fuel. */
447 if (p->fuel < p->fuel_consumption)
448 return 0;
449
450 /* Must have hyperspace target. */
451 if (0 > p->nav_hyperspace || p->nav_hyperspace >= array_size(cur_system->jumps))
452 return 0;
453
454 /* Get the jump. */
455 jp = &cur_system->jumps[ p->nav_hyperspace ];
456
457 /* Check distance. */
458 r = space_jumpDistance( p, jp );
459 d = vec2_dist2( &p->solid->pos, &jp->pos );
460 if (d > pow2(r))
461 return 0;
462 return 1;
463}
464
472{
473 if (pilot_isFlag(p, PILOT_NOJUMP))
474 return -2;
475 if (p->fuel < p->fuel_consumption)
476 return -3;
477 if (!space_canHyperspace(p))
478 return -1;
479
480 /* pilot is now going to get automatically ready for hyperspace */
481 pilot_setFlag(p, PILOT_HYP_PREP);
482 return 0;
483}
484
495int space_calcJumpInPos( const StarSystem *in, const StarSystem *out, vec2 *pos, vec2 *vel, double *dir, const Pilot *p )
496{
497 JumpPoint *jp;
498 double a, d, x, y;
499 double ea, ed;
500
501 /* Find the entry system. */
502 jp = NULL;
503 for (int i=0; i<array_size(in->jumps); i++)
504 if (in->jumps[i].target == out)
505 jp = &in->jumps[i];
506
507 /* Must have found the jump. */
508 if (jp == NULL) {
509 WARN(_("Unable to find jump in point for '%s' in '%s': not connected"), out->name, in->name);
510 return -1;
511 }
512
513 /* Base position target. */
514 x = jp->pos.x;
515 y = jp->pos.y;
516
517 /* Calculate offset from target position. */
518 a = 2.*M_PI - jp->angle;
519 d = RNGF()*(HYPERSPACE_ENTER_MAX-HYPERSPACE_ENTER_MIN) + HYPERSPACE_ENTER_MIN;
520 if ((p!=NULL) && pilot_isFlag(p, PILOT_STEALTH))
521 d *= 1.4; /* Jump in from further out when coming in from stealth. */
522
523 /* Calculate new position. */
524 x += d*cos(a);
525 y += d*sin(a);
526
527 /* Add some error. */
528 ea = 2.*M_PI*RNGF();
529 ed = jp->radius/2.;
530 if (p != NULL) {
531 ed *= p->stats.jump_distance; /* larger variability. */
532 if (pilot_isFlag(p, PILOT_STEALTH))
533 ed *= 2.;
534 }
535 x += ed*cos(ea);
536 y += ed*sin(ea);
537
538 /* Set new position. */
539 vec2_cset( pos, x, y );
540
541 /* Set new velocity. */
542 a += M_PI;
543 vec2_cset( vel, HYPERSPACE_VEL*cos(a), HYPERSPACE_VEL*sin(a) );
544
545 /* Set direction. */
546 *dir = a;
547
548 return 0;
549}
550
558char** space_getFactionSpob( int *factions, int landable )
559{
560 char **tmp = array_create( char* );
561 for (int i=0; i<array_size(systems_stack); i++) {
562 for (int j=0; j<array_size(systems_stack[i].spobs); j++) {
563 Spob *spob = systems_stack[i].spobs[j];
564 int f = 0;
565 for (int k=0; k<array_size(factions); k++) {
566 if (spob->presence.faction == factions[k]) {
567 f = 1;
568 break;
569 }
570 }
571 if (!f)
572 continue;
573
574 /* Check landable. */
575 if (landable) {
576 spob_updateLand( spob );
577 if (!spob->can_land)
578 continue;
579 }
580
581 /* This is expensive so we probably want to do it last. */
583 continue;
584
585 array_push_back( &tmp, spob->name );
586 break; /* no need to check all factions */
587 }
588 }
589
590 return tmp;
591}
592
601const char* space_getRndSpob( int landable, unsigned int services,
602 int (*filter)(Spob *p))
603{
604 char *res = NULL;
605 Spob **tmp = array_create( Spob* );
606
607 for (int i=0; i<array_size(systems_stack); i++) {
608 for (int j=0; j<array_size(systems_stack[i].spobs); j++) {
609 Spob *pnt = systems_stack[i].spobs[j];
610
611 if (services && spob_hasService(pnt, services) != services)
612 continue;
613
614 if (filter != NULL && !filter(pnt))
615 continue;
616
617 array_push_back( &tmp, pnt );
618 }
619 }
620
621 /* Second filter. */
622 arrayShuffle( (void**)tmp );
623 for (int i=0; i < array_size(tmp); i++) {
624 Spob *pnt = tmp[i];
625
626 /* We put expensive calculations here to minimize executions. */
627 if (landable) {
628 spob_updateLand( pnt );
629 if (!pnt->can_land)
630 continue;
631 }
633 continue;
634
635 /* We want the name, not the actual spob. */
636 res = tmp[i]->name;
637 break;
638 }
639 array_free(tmp);
640
641 return res;
642}
643
655double system_getClosest( const StarSystem *sys, int *pnt, int *jp, int *ast, int *fie, double x, double y )
656{
657 double d = HUGE_VAL;
658
659 /* Default output. */
660 *pnt = -1;
661 *jp = -1;
662 *ast = -1;
663 *fie = -1;
664
665 /* Spobs. */
666 for (int i=0; i<array_size(sys->spobs); i++) {
667 double td;
668 Spob *p = sys->spobs[i];
669 if (!spob_isKnown(p))
670 continue;
671 td = pow2(x-p->pos.x) + pow2(y-p->pos.y);
672 if (td < d) {
673 *pnt = i;
674 d = td;
675 }
676 }
677
678 /* Asteroids. */
679 for (int i=0; i<array_size(sys->asteroids); i++) {
680 AsteroidAnchor *f = &sys->asteroids[i];
681 for (int k=0; k<f->nb; k++) {
682 double td;
683 Asteroid *as = &f->asteroids[k];
684
685 /* Skip non-interactive asteroids. */
686 if (as->state != ASTEROID_FG)
687 continue;
688
689 /* Skip out of range asteroids */
690 if (!pilot_inRangeAsteroid( player.p, k, i ))
691 continue;
692
693 td = pow2(x-as->pos.x) + pow2(y-as->pos.y);
694 if (td < d) {
695 *pnt = -1; /* We must clear spob target as asteroid is closer. */
696 *ast = k;
697 *fie = i;
698 d = td;
699 }
700 }
701 }
702
703 /* Jump points. */
704 for (int i=0; i<array_size(sys->jumps); i++) {
705 double td;
706 JumpPoint *j = &sys->jumps[i];
707 if (!jp_isUsable(j))
708 continue;
709 td = pow2(x-j->pos.x) + pow2(y-j->pos.y);
710 if (td < d) {
711 *pnt = -1; /* We must clear spob target as jump point is closer. */
712 *ast = -1;
713 *fie = -1;
714 *jp = i;
715 d = td;
716 }
717 }
718 return d;
719}
720
734double system_getClosestAng( const StarSystem *sys, int *pnt, int *jp, int *ast, int *fie, double x, double y, double ang )
735{
736 double a;
737
738 /* Default output. */
739 *pnt = -1;
740 *jp = -1;
741 a = ang + M_PI;
742
743 /* Spobs. */
744 for (int i=0; i<array_size(sys->spobs); i++) {
745 Spob *p = sys->spobs[i];
746 double ta = atan2( y - p->pos.y, x - p->pos.x);
747 if ( ABS(angle_diff(ang, ta)) < ABS(angle_diff(ang, a))) {
748 *pnt = i;
749 a = ta;
750 }
751 }
752
753 /* Asteroids. */
754 for (int i=0; i<array_size(sys->asteroids); i++) {
755 AsteroidAnchor *f = &sys->asteroids[i];
756 for (int k=0; k<f->nb; k++) {
757 double ta;
758 Asteroid *as = &f->asteroids[k];
759
760 /* Skip non-interactive asteroids. */
761 if (as->state != ASTEROID_FG)
762 continue;
763
764 ta = atan2( y - as->pos.y, x - as->pos.x);
765 if ( ABS(angle_diff(ang, ta)) < ABS(angle_diff(ang, a))) {
766 *pnt = -1; /* We must clear spob target as asteroid is closer. */
767 *ast = k;
768 *fie = i;
769 a = ta;
770 }
771 }
772 }
773
774 /* Jump points. */
775 for (int i=0; i<array_size(sys->jumps); i++) {
776 JumpPoint *j = &sys->jumps[i];
777 double ta = atan2( y - j->pos.y, x - j->pos.x);
778 if ( ABS(angle_diff(ang, ta)) < ABS(angle_diff(ang, a))) {
779 *ast = -1;
780 *fie = -1;
781 *pnt = -1; /* We must clear the rest as jump point is closer. */
782 *jp = i;
783 a = ta;
784 }
785 }
786 return a;
787}
788
794int space_sysReachable( const StarSystem *sys )
795{
796 if (sys_isKnown(sys))
797 return 1; /* it is known */
798
799 /* check to see if it is adjacent to known */
800 for (int i=0; i<array_size(sys->jumps); i++) {
801 JumpPoint *jp = sys->jumps[i].returnJump;
802 if (jp && jp_isUsable( jp ))
803 return 1;
804 }
805
806 return 0;
807}
808
814int space_sysReallyReachable( char* sysname )
815{
816 StarSystem** path;
817
818 if (strcmp(sysname,cur_system->name)==0)
819 return 1;
820 path = map_getJumpPath( cur_system->name, sysname, 1, 1, NULL );
821 if (path != NULL) {
822 array_free(path);
823 return 1;
824 }
825 return 0;
826}
827
833int space_sysReachableFromSys( const StarSystem *target, const StarSystem *sys )
834{
835 /* check to see if sys contains a known jump point to target */
836 JumpPoint *jp = jump_getTarget( target, sys );
837 if (jp == NULL)
838 return 0;
839 else if (jp_isUsable( jp ))
840 return 1;
841 return 0;
842}
843
847StarSystem* system_getAll (void)
848{
849 return systems_stack;
850}
851
858const char *system_existsCase( const char* sysname )
859{
860 for (int i=0; i<array_size(systems_stack); i++)
861 if (strcasecmp(sysname, systems_stack[i].name)==0)
862 return systems_stack[i].name;
863 return NULL;
864}
865
869char **system_searchFuzzyCase( const char* sysname, int *n )
870{
871 int len;
872 char **names;
873
874 /* Overallocate to maximum. */
875 names = malloc( sizeof(char*) * array_size(systems_stack) );
876
877 /* Do fuzzy search. */
878 len = 0;
879 for (int i=0; i<array_size(systems_stack); i++) {
880 StarSystem *sys = &systems_stack[i];
881 if (strcasestr( _(sys->name), sysname ) != NULL) {
882 names[len] = sys->name;
883 len++;
884 }
885 }
886
887 /* Free if empty. */
888 if (len == 0) {
889 free(names);
890 names = NULL;
891 }
892
893 *n = len;
894 return names;
895}
896
900static int system_cmp( const void *p1, const void *p2 )
901{
902 const StarSystem *s1, *s2;
903 s1 = (const StarSystem*) p1;
904 s2 = (const StarSystem*) p2;
905 return strcmp(s1->name,s2->name);
906}
907
914StarSystem* system_get( const char* sysname )
915{
916 if (sysname == NULL)
917 return NULL;
918
919#ifdef DEBUGGING
920 if (systemstack_changed) {
921 for (int i=0; i<array_size(systems_stack); i++)
922 if (strcmp(systems_stack[i].name, sysname)==0)
923 return &systems_stack[i];
924 WARN(_("System '%s' not found in stack"), sysname);
925 return NULL;
926 }
927#endif /* DEBUGGING */
928
929 const StarSystem s = {.name = (char*)sysname};
930 StarSystem *found = bsearch( &s, systems_stack, array_size(systems_stack), sizeof(StarSystem), system_cmp );
931 if (found != NULL)
932 return found;
933
934 WARN(_("System '%s' not found in stack"), sysname);
935 return NULL;
936}
937
944StarSystem* system_getIndex( int id )
945{
946 return &systems_stack[ id ];
947}
948
955int system_index( const StarSystem *sys )
956{
957 return sys->id;
958}
959
966int spob_hasSystem( const Spob *spb )
967{
968 for (int i=0; i<array_size(spobname_stack); i++)
969 if (strcmp(spobname_stack[i],spb->name)==0)
970 return 1;
971 return 0;
972}
973
980char* spob_getSystem( const char* spobname )
981{
982 for (int i=0; i<array_size(spobname_stack); i++)
983 if (strcmp(spobname_stack[i],spobname)==0)
984 return systemname_stack[i];
985 LOG(_("Spob '%s' is not placed in a system"), spobname);
986 return NULL;
987}
988
992static int spob_cmp( const void *p1, const void *p2 )
993{
994 const Spob *pnt1, *pnt2;
995 pnt1 = (const Spob*) p1;
996 pnt2 = (const Spob*) p2;
997 return strcmp(pnt1->name,pnt2->name);
998}
999
1006Spob* spob_get( const char* spobname )
1007{
1008 if (spobname==NULL) {
1009 WARN(_("Trying to find NULL spob…"));
1010 return NULL;
1011 }
1012
1013#ifdef DEBUGGING
1014 if (spobstack_changed) {
1015 for (int i=0; i<array_size(spob_stack); i++)
1016 if (strcmp(spob_stack[i].name, spobname)==0)
1017 return &spob_stack[i];
1018 WARN(_("Spob '%s' not found in the universe"), spobname);
1019 return NULL;
1020 }
1021#endif /* DEBUGGING */
1022
1023 const Spob p = {.name = (char*)spobname};
1024 Spob *found = bsearch( &p, spob_stack, array_size(spob_stack), sizeof(Spob), spob_cmp );
1025 if (found != NULL)
1026 return found;
1027
1028 WARN(_("Spob '%s' not found in the universe"), spobname);
1029 return NULL;
1030}
1031
1039{
1040 /* Validity check. */
1041 if ((ind < 0) || (ind >= array_size(spob_stack))) {
1042 WARN(_("Spob index '%d' out of range (max %d)"), ind, array_size(spob_stack));
1043 return NULL;
1044 }
1045
1046 return &spob_stack[ ind ];
1047}
1048
1055int spob_index( const Spob *p )
1056{
1057 return p->id;
1058}
1059
1064{
1065 return spob_stack;
1066}
1067
1072{
1073 spob_setFlag(p, SPOB_KNOWN);
1074}
1075
1082int spob_exists( const char* spobname )
1083{
1084 for (int i=0; i<array_size(spob_stack); i++)
1085 if (strcmp(spob_stack[i].name,spobname)==0)
1086 return 1;
1087 return 0;
1088}
1089
1096const char* spob_existsCase( const char* spobname )
1097{
1098 for (int i=0; i<array_size(spob_stack); i++)
1099 if (strcasecmp(spob_stack[i].name,spobname)==0)
1100 return spob_stack[i].name;
1101 return NULL;
1102}
1103
1107char **spob_searchFuzzyCase( const char* spobname, int *n )
1108{
1109 int len;
1110 char **names;
1111
1112 /* Overallocate to maximum. */
1113 names = malloc( sizeof(char*) * array_size(spob_stack) );
1114
1115 /* Do fuzzy search. */
1116 len = 0;
1117 for (int i=0; i<array_size(spob_stack); i++) {
1118 Spob *spob = &spob_stack[i];
1119 if (strcasestr( spob_name(spob), spobname ) != NULL) {
1120 names[len] = spob->name;
1121 len++;
1122 }
1123 }
1124
1125 /* Free if empty. */
1126 if (len == 0) {
1127 free(names);
1128 names = NULL;
1129 }
1130
1131 *n = len;
1132 return names;
1133}
1134
1139{
1140 return vspob_stack;
1141}
1142
1146static int virtualspob_cmp( const void *p1, const void *p2 )
1147{
1148 const VirtualSpob *v1, *v2;
1149 v1 = (const VirtualSpob*) p1;
1150 v2 = (const VirtualSpob*) p2;
1151 return strcmp(v1->name,v2->name);
1152}
1153
1157VirtualSpob* virtualspob_get( const char *name )
1158{
1159 const VirtualSpob va = {.name = (char*)name};
1160 VirtualSpob *found = bsearch( &va, vspob_stack, array_size(vspob_stack), sizeof(VirtualSpob), virtualspob_cmp );
1161 if (found != NULL)
1162 return found;
1163 WARN(_("Virtual Spob '%s' not found in the universe"), name);
1164 return NULL;
1165}
1166
1174JumpPoint* jump_get( const char* jumpname, const StarSystem* sys )
1175{
1176 if (jumpname==NULL) {
1177 WARN(_("Trying to find NULL jump point..."));
1178 return NULL;
1179 }
1180
1181 for (int i=0; i<array_size(sys->jumps); i++) {
1182 JumpPoint *jp = &sys->jumps[i];
1183 if (strcmp(jp->target->name,jumpname)==0)
1184 return jp;
1185 }
1186
1187 WARN(_("Jump point '%s' not found in %s"), jumpname, sys->name);
1188 return NULL;
1189}
1190
1198JumpPoint* jump_getTarget( const StarSystem* target, const StarSystem* sys )
1199{
1200 for (int i=0; i<array_size(sys->jumps); i++) {
1201 JumpPoint *jp = &sys->jumps[i];
1202 if (jp->target == target)
1203 return jp;
1204 }
1205 WARN(_("Jump point to '%s' not found in %s"), target->name, sys->name);
1206 return NULL;
1207}
1208
1212const char *jump_getSymbol( const JumpPoint *jp )
1213{
1214 if (jp_isFlag(jp, JP_HIDDEN))
1215 return "* ";
1216 return "";
1217}
1218
1225static void system_scheduler( double dt, int init )
1226{
1227 /* Go through all the factions and reduce the timer. */
1228 for (int i=0; i < array_size(cur_system->presence); i++) {
1229 int n;
1230 nlua_env env;
1231 SystemPresence *p = &cur_system->presence[i];
1232 if (p->value <= 0.)
1233 continue;
1234
1235 env = faction_getScheduler( p->faction );
1236
1237 /* Must have a valid scheduler. */
1238 if (env==LUA_NOREF)
1239 continue;
1240
1241 /* Spawning is disabled for this faction. */
1242 if (p->disabled)
1243 continue;
1244
1245 /* Run the appropriate function. */
1246 if (init) {
1247 nlua_getenv( naevL, env, "create" ); /* f */
1248 if (lua_isnil(naevL,-1)) {
1249 WARN(_("Lua Spawn script for faction '%s' missing obligatory entry point 'create'."),
1250 faction_name( p->faction ) );
1251 lua_pop(naevL,1);
1252 continue;
1253 }
1254 n = 0;
1255 }
1256 else {
1257 /* Decrement dt, only continue */
1258 p->timer -= dt;
1259 if (p->timer >= 0.)
1260 continue;
1261
1262 nlua_getenv( naevL, env, "spawn" ); /* f */
1263 if (lua_isnil(naevL,-1)) {
1264 WARN(_("Lua Spawn script for faction '%s' missing obligatory entry point 'spawn'."),
1265 faction_name( p->faction ) );
1266 lua_pop(naevL,1);
1267 continue;
1268 }
1269 lua_pushnumber( naevL, p->curUsed ); /* f, presence */
1270 n = 1;
1271 }
1272 lua_pushnumber( naevL, p->value ); /* f, [arg,], max */
1273
1274 /* Actually run the function. */
1275 if (nlua_pcall(env, n+1, 2)) { /* error has occurred */
1276 WARN(_("Lua Spawn script for faction '%s' : %s"),
1277 faction_name( p->faction ), lua_tostring(naevL,-1));
1278 lua_pop(naevL,1);
1279 continue;
1280 }
1281
1282 /* Output is handled the same way. */
1283 if (!lua_isnumber(naevL,-2)) {
1284 WARN(_("Lua spawn script for faction '%s' failed to return timer value."),
1285 faction_name( p->faction ) );
1286 lua_pop(naevL,2);
1287 continue;
1288 }
1289 p->timer += lua_tonumber(naevL,-2);
1290 /* Handle table if it exists. */
1291 if (lua_istable(naevL,-1)) {
1292 lua_pushnil(naevL); /* tk, k */
1293 while (lua_next(naevL,-2) != 0) { /* tk, k, v */
1294 Pilot *pilot;
1295
1296 /* Must be table. */
1297 if (!lua_istable(naevL,-1)) {
1298 WARN(_("Lua spawn script for faction '%s' returns invalid data (not a table)."),
1299 faction_name( p->faction ) );
1300 lua_pop(naevL,2); /* tk, k */
1301 continue;
1302 }
1303
1304 lua_getfield( naevL, -1, "pilot" ); /* tk, k, v, p */
1305 if (!lua_ispilot(naevL,-1)) {
1306 WARN(_("Lua spawn script for faction '%s' returns invalid data (not a pilot)."),
1307 faction_name( p->faction ) );
1308 lua_pop(naevL,2); /* tk, k */
1309 continue;
1310 }
1311 pilot = pilot_get( lua_topilot(naevL,-1) );
1312 if (pilot == NULL) {
1313 lua_pop(naevL,2); /* tk, k */
1314 continue;
1315 }
1316 lua_pop(naevL,1); /* tk, k, v */
1317 lua_getfield( naevL, -1, "presence" ); /* tk, k, v, p */
1318 if (!lua_isnumber(naevL,-1)) {
1319 WARN(_("Lua spawn script for faction '%s' returns invalid data (not a number)."),
1320 faction_name( p->faction ) );
1321 lua_pop(naevL,2); /* tk, k */
1322 continue;
1323 }
1324 pilot->presence = lua_tonumber(naevL,-1);
1325 if (pilot->faction != p->faction) {
1326 int pi;
1327 WARN( _("Lua spawn script for faction '%s' actually spawned a '%s' pilot."),
1328 faction_name( p->faction ),
1329 faction_name( pilot->faction ) );
1330 pi = getPresenceIndex( cur_system, pilot->faction );
1331 p = &cur_system->presence[pi];
1332 }
1333 p->curUsed += pilot->presence;
1334 lua_pop(naevL,2); /* tk, k */
1335 }
1336 }
1337 lua_pop(naevL,2);
1338 }
1339}
1340
1345{
1346 space_fchg = 1;
1347}
1348
1353{
1354 if (space_landQueueSpob != NULL) {
1355 land( space_landQueueSpob, 0 );
1356 space_landQueueSpob = NULL;
1357 }
1358}
1359
1366void space_update( double dt, double real_dt )
1367{
1368 /* Needs a current system. */
1369 if (cur_system == NULL)
1370 return;
1371
1372 /* If spawning is enabled, call the scheduler. */
1373 if (space_spawn)
1374 system_scheduler( dt, 0 );
1375
1376 /*
1377 * Nebula.
1378 */
1379 nebu_update( dt );
1380 if (cur_system->nebu_volatility > 0.) {
1381 Pilot *const* pilot_stack;
1382 Damage dmg;
1383 dmg.type = dtype_get("nebula");
1384 dmg.damage = cur_system->nebu_volatility * dt;
1385 dmg.penetration = 1.; /* Full penetration. */
1386 dmg.disable = 0.;
1387
1388 /* Damage pilots in volatile systems. */
1390 for (int i=0; i<array_size(pilot_stack); i++)
1391 pilot_hit( pilot_stack[i], NULL, NULL, &dmg, NULL, LUA_NOREF, 0 );
1392 }
1393
1394 /* Faction updates. */
1395 if (space_fchg) {
1396 for (int i=0; i<array_size(cur_system->spobs); i++)
1397 spob_updateLand( cur_system->spobs[i] );
1398
1399 /* Verify land authorization is still valid. */
1400 if ((player.p != NULL) && (player.p->nav_spob >= 0) && player_isFlag(PLAYER_LANDACK))
1402
1404 space_fchg = 0;
1405 }
1406
1407 if (!space_simulating) {
1408 int found_something = 0;
1409 /* Spob updates */
1410 for (int i=0; i<array_size(cur_system->spobs); i++) {
1411 HookParam hparam[3];
1412 Spob *pnt = cur_system->spobs[i];
1413
1414 /* Must update in some cases. */
1415 space_updateSpob( pnt, dt, real_dt );
1416
1417 /* Discovering is disabled. */
1418 if (player.discover_off)
1419 continue;
1420
1421 /* Handle discoveries. */
1422 if (spob_isKnown( pnt ) || !pilot_inRangeSpob( player.p, i ))
1423 continue;
1424
1425 spob_setKnown( pnt );
1426 player_message( _("You discovered #%c%s#0."),
1427 spob_getColourChar( pnt ),
1428 spob_name( pnt ) );
1429 hparam[0].type = HOOK_PARAM_STRING;
1430 hparam[0].u.str = "spob";
1431 hparam[1].type = HOOK_PARAM_SPOB;
1432 hparam[1].u.la = pnt->id;
1433 hparam[2].type = HOOK_PARAM_SENTINEL;
1434 hooks_runParam( "discover", hparam );
1435 found_something = 1;
1436 pnt->map_alpha = 0.;
1437 }
1438
1439 /* Jump point updates */
1440 for (int i=0; i<array_size(cur_system->jumps); i++) {
1441 HookParam hparam[3];
1442 JumpPoint *jp = &cur_system->jumps[i];
1443
1444 /* Discovering is disabled. */
1445 if (player.discover_off)
1446 continue;
1447
1448 if (jp_isKnown(jp))
1449 continue;
1450 if (jp_isFlag(jp,JP_EXITONLY))
1451 continue;
1452 if (!(pilot_inRangeJump( player.p, i )))
1453 continue;
1454
1455 jp_setFlag( jp, JP_KNOWN );
1456 player_message( _("You discovered a Jump Point.") );
1457 hparam[0].type = HOOK_PARAM_STRING;
1458 hparam[0].u.str = "jump";
1459 hparam[1].type = HOOK_PARAM_JUMP;
1460 hparam[1].u.lj.srcid = cur_system->id;
1461 hparam[1].u.lj.destid = jp->target->id;
1462 hparam[2].type = HOOK_PARAM_SENTINEL;
1463 hooks_runParam( "discover", hparam );
1464 found_something = 1;
1465 jp->map_alpha = 0.;
1466 }
1467
1468 if (found_something)
1469 ovr_refresh();
1470 }
1471
1472 /* Update the gatherable objects. */
1473 gatherable_update( dt );
1474
1475 /* Asteroids/Debris update */
1476 asteroids_update( dt );
1477}
1478
1483{
1484 return space_simulating;
1485}
1486
1491{
1493}
1494
1501void space_init( const char* sysname, int do_simulate )
1502{
1503 int n, s;
1504 const double fps_min_simulation = fps_min * 2.;
1505 StarSystem *oldsys = cur_system;
1506
1507 /* cleanup some stuff */
1508 player_clear(); /* clears targets */
1509 ovr_mrkClear(); /* Clear markers when jumping. */
1510 pilots_clean(1); /* destroy non-persistent pilots */
1511 weapon_clear(); /* get rid of all the weapons */
1512 spfx_clear(); /* get rid of the explosions */
1513 gatherable_free(); /* get rid of gatherable stuff. */
1514 background_clear(); /* Get rid of the background. */
1515 factions_clearDynamic(); /* get rid of dynamic factions. */
1516 space_spawn = 1; /* spawn is enabled by default. */
1517
1518 /* Clear persistent pilot stuff. */
1519 if (player.p != NULL) {
1520 Pilot *const* pilot_stack = pilot_getAll();
1521 for (int i=0; i<array_size(pilot_stack); i++) {
1522 Pilot *p = pilot_stack[i];
1523 pilot_lockClear( p );
1524 pilot_clearTimers( p ); /* Clear timers. */
1525 }
1526 }
1527
1528 if ((sysname==NULL) && (cur_system==NULL))
1529 ERR(_("Cannot reinit system if there is no system previously loaded"));
1530 else if (sysname!=NULL) {
1531 cur_system = system_get( sysname );
1532 if (cur_system == NULL) {
1533 WARN(_("System '%s' not found, trying random system!"),sysname);
1535 }
1536 char *nt = ntime_pretty(0, 2);
1537
1538 player_message(_("#oEntering System %s on %s."), _(sysname), nt);
1539 if (cur_system->nebu_volatility > 0.)
1540 player_message(_("#rWARNING - Volatile nebula detected in %s! Taking %.1f MW damage!"), _(sysname), cur_system->nebu_volatility);
1541 free(nt);
1542
1543 /* Handle background */
1544 if (cur_system->nebu_density > 0.) {
1545 /* Background is Nebula */
1546 nebu_prep( cur_system->nebu_density, cur_system->nebu_volatility, cur_system->nebu_hue );
1547
1548 /* Set up sound. */
1549 sound_env( SOUND_ENV_NEBULA, cur_system->nebu_density );
1550 }
1551 else {
1552 /* Background is starry */
1554
1555 /* Set up sound. */
1556 sound_env( SOUND_ENV_NORMAL, 0. );
1557 }
1558 }
1559
1560 /* Update after setting cur_system. */
1561 if ((oldsys != NULL && oldsys->stats != NULL) || cur_system->stats != NULL) {
1562 Pilot *const* pilot_stack = pilot_getAll();
1563 for (int i=0; i<array_size(pilot_stack); i++) {
1564 Pilot *p = pilot_stack[i];
1565 pilot_calcStats( p );
1566 if (pilot_isWithPlayer(p))
1567 pilot_setFlag( p, PILOT_HIDE );
1568 }
1569 }
1570
1571 /* Set up spobs. */
1572 for (int i=0; i<array_size(cur_system->spobs); i++) {
1573 Spob *pnt = cur_system->spobs[i];
1574 pnt->land_override = 0;
1575 spob_updateLand( pnt );
1576 }
1577
1578 /* See if we should get a new music song. */
1579 if ((player.p != NULL) && do_simulate)
1580 music_choose(NULL);
1581
1582 /* Reset new trails. */
1584
1585 /* Reset any schedules and used presence. */
1586 for (int i=0; i<array_size(cur_system->presence); i++) {
1587 cur_system->presence[i].curUsed = 0;
1588 cur_system->presence[i].timer = 0.;
1589 cur_system->presence[i].disabled = 0;
1590 }
1591
1592 /* Load graphics. */
1594
1595 /* Call the scheduler. */
1596 system_scheduler( 0., 1 );
1597
1598 /* we now know this system */
1599 sys_setFlag(cur_system,SYSTEM_KNOWN);
1600
1601 /* Simulate system. */
1602 space_simulating = 1;
1604 asteroids_init(); /* Set up asteroids. */
1605 if (player.p != NULL) {
1606 Pilot *const* pilot_stack = pilot_getAll();
1607 pilot_setFlag( player.p, PILOT_HIDE );
1608 for (int i=0; i<array_size(pilot_stack); i++) {
1609 Pilot *p = pilot_stack[i];
1610 if (pilot_isWithPlayer(p))
1611 pilot_setFlag( p, PILOT_HIDE );
1612 }
1613 }
1615 if (do_simulate) {
1616 /* Uint32 time = SDL_GetTicks(); */
1617 s = sound_disabled;
1618 sound_disabled = 1;
1619 ntime_allowUpdate( 0 );
1620 n = SYSTEM_SIMULATE_TIME_PRE / fps_min_simulation;
1621 for (int i=0; i<n; i++)
1622 update_routine( fps_min_simulation, 1 );
1624 n = SYSTEM_SIMULATE_TIME_POST / fps_min_simulation;
1625 for (int i=0; i<n; i++)
1626 update_routine( fps_min_simulation, 1 );
1627 ntime_allowUpdate( 1 );
1628 sound_disabled = s;
1629 /*
1630 if (conf.devmode)
1631 DEBUG(_("System simulated in %.3f s"), (SDL_GetTicks()-time)/1000.);
1632 */
1633 }
1635 if (player.p != NULL) {
1636 Pilot *const* pilot_stack = pilot_getAll();
1637 pilot_rmFlag( player.p, PILOT_HIDE );
1638 for (int i=0; i<array_size(pilot_stack); i++) {
1639 Pilot *p = pilot_stack[i];
1640 if (pilot_isWithPlayer(p))
1641 pilot_rmFlag( p, PILOT_HIDE );
1642 }
1643 }
1644 space_simulating = 0;
1645
1646 /* Refresh overlay if necessary (player kept it open). */
1647 ovr_refresh();
1648
1649 /* Update gui. */
1650 gui_setSystem();
1651
1652 /* Start background. */
1653 background_load( cur_system->background );
1654}
1655
1660{
1661 Spob *p, *old_stack;
1662 int realloced;
1663
1664#if DEBUGGING
1665 if (!systems_loading)
1666 spobstack_changed = 1;
1667#else /* DEBUGGING */
1668 if (!systems_loading)
1669 WARN(_("Creating new spob in non-debugging mode. Things are probably going to break horribly."));
1670#endif /* DEBUGGING */
1671
1672 /* Grow and initialize memory. */
1673 old_stack = spob_stack;
1674 p = &array_grow( &spob_stack );
1675 realloced = (old_stack!=spob_stack);
1676 memset( p, 0, sizeof(Spob) );
1677 p->id = array_size(spob_stack)-1;
1678 p->presence.faction = -1;
1679
1680 /* Lua doesn't default to 0 as a safe value... */
1681 p->lua_env = LUA_NOREF;
1682 p->lua_mem = LUA_NOREF;
1683 p->lua_init = LUA_NOREF;
1684 p->lua_load = LUA_NOREF;
1685 p->lua_unload = LUA_NOREF;
1686 p->lua_can_land= LUA_NOREF;
1687 p->lua_land = LUA_NOREF;
1688 p->lua_render = LUA_NOREF;
1689 p->lua_update = LUA_NOREF;
1690 p->lua_comm = LUA_NOREF;
1691
1692 /* Reconstruct the jumps. */
1693 if (!systems_loading && realloced)
1695
1696 return p;
1697}
1698
1705const char *spob_name( const Spob *p )
1706{
1707 if (p->display)
1708 return _(p->display);
1709 return _(p->name);
1710}
1711
1717static int spobs_load (void)
1718{
1719 char **spob_files;
1720 Commodity **stdList;
1721
1722 /* Initialize stack if needed. */
1723 if (spob_stack == NULL)
1725
1726 /* Extract the list of standard commodities. */
1727 stdList = standard_commodities();
1728
1729 /* Load XML stuff. */
1730 spob_files = ndata_listRecursive( SPOB_DATA_PATH );
1731 for (int i=0; i<array_size(spob_files); i++) {
1732 if (ndata_matchExt( spob_files[i], "xml" )) {
1733 Spob s;
1734 int ret = spob_parse( &s, spob_files[i], stdList );
1735 if (ret == 0) {
1736 s.id = array_size( spob_stack );
1738 }
1739
1740 /* Render if necessary. */
1742 }
1743
1744 /* Clean up. */
1745 free( spob_files[i] );
1746 }
1747 qsort( spob_stack, array_size(spob_stack), sizeof(Spob), spob_cmp );
1748 for (int j=0; j<array_size(spob_stack); j++)
1749 spob_stack[j].id = j;
1750
1751 /* Clean up. */
1752 array_free( spob_files );
1753 array_free( stdList );
1754
1755 return 0;
1756}
1757
1763static int virtualspobs_load (void)
1764{
1765 char **spob_files;
1766
1767 /* Initialize stack if needed. */
1768 if (vspob_stack == NULL)
1770
1771 /* Load XML stuff. */
1772 spob_files = ndata_listRecursive( VIRTUALSPOB_DATA_PATH );
1773 for (int i=0; i<array_size(spob_files); i++) {
1774 xmlDocPtr doc;
1775 xmlNodePtr node;
1776
1777 if (!ndata_matchExt( spob_files[i], "xml" )) {
1778 free( spob_files[i] );
1779 continue;
1780 }
1781
1782 doc = xml_parsePhysFS( spob_files[i] );
1783 if (doc == NULL) {
1784 free( spob_files[i] );
1785 continue;
1786 }
1787
1788 node = doc->xmlChildrenNode; /* first spob node */
1789 if (node == NULL) {
1790 WARN(_("Malformed %s file: does not contain elements"), spob_files[i]);
1791 free( spob_files[i] );
1792 xmlFreeDoc(doc);
1793 continue;
1794 }
1795
1796 if (xml_isNode(node,XML_SPOB_TAG)) {
1797 xmlNodePtr cur;
1798 VirtualSpob va;
1799 memset( &va, 0, sizeof(va) );
1800 xmlr_attr_strd( node, "name", va.name );
1802
1803 cur = node->children;
1804 do {
1805 xml_onlyNodes(cur);
1806 if (xml_isNode(cur,"presence")) {
1807 SpobPresence ap;
1808 spob_parsePresence( cur, &ap );
1809 array_push_back( &va.presences, ap );
1810 continue;
1811 }
1812
1813 WARN(_("Unknown node '%s' in virtual spob '%s'"),cur->name,va.name);
1814 } while (xml_nextNode(cur));
1815
1817 }
1818
1819 /* Clean up. */
1820 free( spob_files[i] );
1821 xmlFreeDoc(doc);
1822 }
1824
1825 /* Clean up. */
1826 array_free( spob_files );
1827
1828 return 0;
1829}
1830
1834char spob_getColourChar( const Spob *p )
1835{
1836 if (!spob_hasService( p, SPOB_SERVICE_INHABITED ))
1837 return 'I';
1838
1839 if (p->can_land) {
1840 if (areAllies(FACTION_PLAYER,p->presence.faction))
1841 return 'F';
1842 return 'N';
1843 }
1844
1845 if (areEnemies(FACTION_PLAYER,p->presence.faction))
1846 return 'H';
1847 return 'R';
1848}
1849
1853const char *spob_getSymbol( const Spob *p )
1854{
1855 if (!spob_hasService( p, SPOB_SERVICE_INHABITED )) {
1856 if (spob_hasService( p, SPOB_SERVICE_LAND ))
1857 return "= ";
1858 return "";
1859 }
1860
1861 if (p->can_land) {
1862 if (areAllies(FACTION_PLAYER,p->presence.faction))
1863 return "+ ";
1864 return "~ ";
1865 }
1866
1867 if (areEnemies(FACTION_PLAYER,p->presence.faction))
1868 return "!! ";
1869 return "* ";
1870}
1871
1875const glColour* spob_getColour( const Spob *p )
1876{
1877 if (!spob_hasService( p, SPOB_SERVICE_INHABITED ))
1878 return &cInert;
1879
1880 if (p->can_land) {
1881 if (areAllies(FACTION_PLAYER,p->presence.faction))
1882 return &cFriend;
1883 return &cNeutral;
1884 }
1885
1886 if (areEnemies(FACTION_PLAYER,p->presence.faction))
1887 return &cHostile;
1888 return &cRestricted;
1889}
1890
1897{
1898 /* Clean up old stuff. */
1899 free( p->land_msg );
1900 p->can_land = 0;
1901 p->land_msg = NULL;
1902
1903 /* Run custom Lua. */
1904 if (p->lua_can_land != LUA_NOREF) {
1905 spob_luaInitMem( p );
1906 lua_rawgeti(naevL, LUA_REGISTRYINDEX, p->lua_can_land); /* f */
1907 if (nlua_pcall( p->lua_env, 0, 2 )) {
1908 WARN(_("Spob '%s' failed to run '%s':\n%s"), p->name, "can_land", lua_tostring(naevL,-1));
1909 lua_pop(naevL,1);
1910 return;
1911 }
1912
1913 p->can_land = lua_toboolean(naevL,-2);
1914 if (lua_isstring(naevL,-1))
1915 p->land_msg = strdup( lua_tostring(naevL,-1) );
1916 lua_pop(naevL,2);
1917
1918 return;
1919 }
1920
1921 /* Some defaults. */
1922 if (spob_hasService( p, SPOB_SERVICE_LAND )) {
1923 p->can_land = 1;
1924 p->land_msg = strdup(_("Landing permission granted."));
1925 }
1926}
1927
1931void spob_luaInitMem( const Spob *spob )
1932{
1933 lua_rawgeti( naevL, LUA_REGISTRYINDEX, spob->lua_mem );
1934 nlua_setenv( naevL, spob->lua_env, "mem" );
1935}
1936
1942int spob_luaInit( Spob *spob )
1943{
1944 int mem;
1945
1946 /* Just clear everything. */
1947#define UNREF( x ) \
1948 do { if ((x) != LUA_NOREF) { \
1949 luaL_unref( naevL, LUA_REGISTRYINDEX, (x) ); \
1950 (x) = LUA_NOREF; \
1951 } } while (0)
1952 spob->lua_env = LUA_NOREF; /* Just a pointer to some Lua index. */
1953 UNREF( spob->lua_init );
1954 UNREF( spob->lua_load );
1955 UNREF( spob->lua_unload );
1956 UNREF( spob->lua_land );
1957 UNREF( spob->lua_can_land );
1958 UNREF( spob->lua_render );
1959 UNREF( spob->lua_update );
1960 UNREF( spob->lua_comm );
1961 UNREF( spob->lua_mem );
1962#undef UNREF
1963
1964 /* Initialize. */
1965 if (spob->lua_file == NULL)
1966 return 0;
1967
1968 /* Try to get the environment, will create a new one as necessary. */
1969 nlua_env env = spob_lua_get( &mem, spob->lua_file );
1970 if (env==LUA_NOREF)
1971 return -1;
1972
1973 spob->lua_env = env;
1974
1975 /* Grab functions as applicable. */
1976 spob->lua_init = nlua_refenvtype( env, "init", LUA_TFUNCTION );
1977 spob->lua_load = nlua_refenvtype( env, "load", LUA_TFUNCTION );
1978 spob->lua_unload = nlua_refenvtype( env, "unload", LUA_TFUNCTION );
1979 spob->lua_can_land = nlua_refenvtype( env, "can_land", LUA_TFUNCTION );
1980 spob->lua_land = nlua_refenvtype( env, "land", LUA_TFUNCTION );
1981 spob->lua_render = nlua_refenvtype( env, "render", LUA_TFUNCTION );
1982 spob->lua_update = nlua_refenvtype( env, "update", LUA_TFUNCTION );
1983 spob->lua_comm = nlua_refenvtype( env, "comm", LUA_TFUNCTION );
1984
1985 /* Set up local memory. */
1986 lua_newtable( naevL ); /* m */
1987 lua_pushvalue( naevL, -1 ); /* m, m */
1988 spob->lua_mem = luaL_ref( naevL, LUA_REGISTRYINDEX ); /* m */
1989
1990 /* Copy over global memory. */
1991 lua_rawgeti( naevL, LUA_REGISTRYINDEX, mem ); /* m, d */
1992 lua_pushnil( naevL ); /* m, d, nil */
1993 while (lua_next(naevL,-2) != 0) { /* m, d, k, v */
1994 lua_pushvalue( naevL, -2 );/* m, d, k, v, k */
1995 lua_pushvalue( naevL, -2 );/* m, d, k, v, k, v */
1996 lua_remove( naevL, -3 ); /* m, d, k, k, v */
1997 lua_settable( naevL, -5 ); /* m, d, k */
1998 } /* m, d */
1999 lua_pop( naevL, 2 ); /* */
2000
2001 /* Run init if applicable. */
2002 if (spob->lua_init != LUA_NOREF) {
2003 spob_luaInitMem( spob );
2004 lua_rawgeti(naevL, LUA_REGISTRYINDEX, spob->lua_init); /* f */
2005 lua_pushspob(naevL, spob_index(spob));
2006 if (nlua_pcall( spob->lua_env, 1, 0 )) {
2007 WARN(_("Spob '%s' failed to run '%s':\n%s"), spob->name, "init", lua_tostring(naevL,-1));
2008 lua_pop(naevL,1);
2009 return -1;
2010 }
2011 }
2012
2013 return 0;
2014}
2015
2019void spob_gfxLoad( Spob *spob )
2020{
2021 if (spob->lua_load != LUA_NOREF) {
2022 spob_luaInitMem( spob );
2023 lua_rawgeti(naevL, LUA_REGISTRYINDEX, spob->lua_load); /* f */
2024 if (nlua_pcall( spob->lua_env, 0, 2 )) {
2025 WARN(_("Spob '%s' failed to run '%s':\n%s"), spob->name, "load", lua_tostring(naevL,-1));
2026 lua_pop(naevL,1);
2027 return;
2028 }
2029 if (lua_istex(naevL,-2)) {
2030 if (spob->gfx_space)
2031 gl_freeTexture( spob->gfx_space );
2032 spob->gfx_space = gl_dupTexture( lua_totex(naevL,-2) );
2033 }
2034 else if (lua_isnil(naevL,-2)) {
2035 /* Have the engine handle it if nil. */
2036 }
2037 else
2038 WARN(_("Spob '%s' ran '%s' but got non-texture or nil return value!"), spob->name, "load" );
2039 spob->radius = luaL_optnumber(naevL,-1,-1.);
2040 lua_pop(naevL,2);
2041 }
2042
2043 if (spob->gfx_space==NULL) {
2044 if (spob->gfx_spaceName != NULL)
2045 spob->gfx_space = gl_newImage( spob->gfx_spaceName, OPENGL_TEX_MIPMAPS );
2046 }
2047 /* Set default size if applicable. */
2048 if ((spob->gfx_space!=NULL) && (spob->radius < 0.))
2049 spob->radius = (spob->gfx_space->w + spob->gfx_space->h)/4.;
2050}
2051
2057void space_gfxLoad( StarSystem *sys )
2058{
2059 for (int i=0; i<array_size(sys->spobs); i++)
2060 spob_gfxLoad( sys->spobs[i] );
2061}
2062
2068void space_gfxUnload( StarSystem *sys )
2069{
2070 for (int i=0; i<array_size(sys->spobs); i++) {
2071 Spob *spob = sys->spobs[i];
2072
2073 if (spob->lua_unload != LUA_NOREF) {
2074 spob_luaInitMem( spob );
2075 lua_rawgeti(naevL, LUA_REGISTRYINDEX, spob->lua_unload); /* f */
2076 if (nlua_pcall( spob->lua_env, 0, 0 )) {
2077 WARN(_("Spob '%s' failed to run '%s':\n%s"), spob->name, "unload", lua_tostring(naevL,-1));
2078 lua_pop(naevL,1);
2079 }
2080 }
2081
2082 gl_freeTexture( spob->gfx_space );
2083 spob->gfx_space = NULL;
2084 }
2085}
2086
2093static int spob_parsePresence( xmlNodePtr node, SpobPresence *ap )
2094{
2095 xmlNodePtr cur = node->children;
2096 memset( ap, 0, sizeof(SpobPresence) );
2097 ap->faction = -1;
2098 do {
2099 xml_onlyNodes(cur);
2100 xmlr_float(cur, "base", ap->base);
2101 xmlr_float(cur, "bonus", ap->bonus);
2102 xmlr_int(cur, "range", ap->range);
2103 if (xml_isNode(cur,"faction")) {
2104 ap->faction = faction_get( xml_get(cur) );
2105 continue;
2106 }
2107 } while (xml_nextNode(cur));
2108 return 0;
2109}
2110
2119static int spob_parse( Spob *spob, const char *filename, Commodity **stdList )
2120{
2121 xmlDocPtr doc;
2122 xmlNodePtr node, parent;
2123 unsigned int flags;
2124 Commodity **comms;
2125
2126 doc = xml_parsePhysFS( filename );
2127 if (doc == NULL)
2128 return -1;
2129
2130 parent = doc->xmlChildrenNode; /* first spob node */
2131 if (parent == NULL) {
2132 WARN(_("Malformed %s file: does not contain elements"), filename);
2133 xmlFreeDoc(doc);
2134 return -1;
2135 }
2136
2137 /* Clear up memory for safe defaults. */
2138 memset( spob, 0, sizeof(Spob) );
2139 flags = 0;
2140 spob->hide = 0.01;
2141 spob->radius = -1.;
2142 spob->presence.faction = -1;
2143 comms = array_create( Commodity* );
2144 /* Lua stuff. */
2145 spob->lua_env = LUA_NOREF;
2146 spob->lua_init = LUA_NOREF;
2147 spob->lua_load = LUA_NOREF;
2148 spob->lua_unload = LUA_NOREF;
2149 spob->lua_land = LUA_NOREF;
2150 spob->lua_can_land= LUA_NOREF;
2151 spob->lua_render = LUA_NOREF;
2152 spob->lua_update = LUA_NOREF;
2153 spob->lua_comm = LUA_NOREF;
2154
2155 /* Get the name. */
2156 xmlr_attr_strd( parent, "name", spob->name );
2157
2158 node = parent->xmlChildrenNode;
2159 do {
2160 /* Only handle nodes. */
2161 xml_onlyNodes(node);
2162
2163 xmlr_strd(node, "display", spob->display);
2164 xmlr_strd(node, "feature", spob->feature);
2165 xmlr_strd(node, "lua", spob->lua_file);
2166 xmlr_float(node, "radius", spob->radius);
2167 if (xml_isNode(node, "marker")) {
2168 const char *s = xml_get(node);
2169 spob->marker = shaders_getSimple( s );
2170 if (spob->marker == NULL)
2171 WARN(_("Spob '%s' has unknown marker shader '%s'!"), spob->name, s );
2172 continue;
2173 }
2174
2175 if (xml_isNode(node,"GFX")) {
2176 xmlNodePtr cur = node->children;
2177 do {
2178 xml_onlyNodes(cur);
2179 if (xml_isNode(cur,"space")) { /* load space gfx */
2180 char str[PATH_MAX];
2181 snprintf( str, sizeof(str), SPOB_GFX_SPACE_PATH"%s", xml_get(cur));
2182 spob->gfx_spaceName = strdup(str);
2183 spob->gfx_spacePath = xml_getStrd(cur);
2184 continue;
2185 }
2186 if (xml_isNode(cur,"exterior")) { /* load land gfx */
2187 char str[PATH_MAX];
2188 snprintf( str, sizeof(str), SPOB_GFX_EXTERIOR_PATH"%s", xml_get(cur));
2189 spob->gfx_exterior = strdup(str);
2190 spob->gfx_exteriorPath = xml_getStrd(cur);
2191 continue;
2192 }
2193 WARN(_("Unknown node '%s' in spob '%s'"),node->name,spob->name);
2194 } while (xml_nextNode(cur));
2195 continue;
2196 }
2197 else if (xml_isNode(node,"pos")) {
2198 xmlr_attr_float( node, "x", spob->pos.x );
2199 xmlr_attr_float( node, "y", spob->pos.y );
2200 flags |= FLAG_POSSET;
2201 continue;
2202 }
2203 else if (xml_isNode(node, "presence")) {
2204 spob_parsePresence( node, &spob->presence );
2205 if (spob->presence.faction>=0)
2206 flags |= FLAG_FACTIONSET;
2207 continue;
2208 }
2209 else if (xml_isNode(node,"general")) {
2210 xmlNodePtr cur = node->children;
2211 do {
2212 xml_onlyNodes(cur);
2213 /* Direct reads. */
2214 xmlr_strd(cur, "class", spob->class);
2215 xmlr_strd(cur, "bar", spob->bar_description);
2216 xmlr_strd(cur, "description", spob->description );
2217 xmlr_float(cur, "population", spob->population );
2218 xmlr_float(cur, "hide", spob->hide );
2219
2220 if (xml_isNode(cur, "services")) {
2221 xmlNodePtr ccur = cur->children;
2222 flags |= FLAG_SERVICESSET;
2223 spob->services = 0;
2224 do {
2225 xml_onlyNodes(ccur);
2226
2227 if (xml_isNode(ccur, "land"))
2228 spob->services |= SPOB_SERVICE_LAND;
2229 else if (xml_isNode(ccur, "refuel"))
2230 spob->services |= SPOB_SERVICE_REFUEL | SPOB_SERVICE_INHABITED;
2231 else if (xml_isNode(ccur, "bar"))
2232 spob->services |= SPOB_SERVICE_BAR | SPOB_SERVICE_INHABITED;
2233 else if (xml_isNode(ccur, "missions"))
2234 spob->services |= SPOB_SERVICE_MISSIONS | SPOB_SERVICE_INHABITED;
2235 else if (xml_isNode(ccur, "commodity"))
2236 spob->services |= SPOB_SERVICE_COMMODITY | SPOB_SERVICE_INHABITED;
2237 else if (xml_isNode(ccur, "outfits"))
2238 spob->services |= SPOB_SERVICE_OUTFITS | SPOB_SERVICE_INHABITED;
2239 else if (xml_isNode(ccur, "shipyard"))
2240 spob->services |= SPOB_SERVICE_SHIPYARD | SPOB_SERVICE_INHABITED;
2241 else if (xml_isNode(ccur, "nomissionspawn"))
2242 spob->flags |= SPOB_NOMISNSPAWN;
2243 else if (xml_isNode(ccur, "uninhabited"))
2244 spob->flags |= SPOB_UNINHABITED;
2245 else if (xml_isNode(ccur, "blackmarket"))
2246 spob->services |= SPOB_SERVICE_BLACKMARKET;
2247 else
2248 WARN(_("Spob '%s' has unknown services tag '%s'"), spob->name, ccur->name);
2249 } while (xml_nextNode(ccur));
2250 }
2251
2252 else if (xml_isNode(cur, "commodities")) {
2253 xmlNodePtr ccur = cur->children;
2254 do {
2255 if (xml_isNode(ccur,"commodity")) {
2256 /* If the commodity is standard, don't re-add it. */
2257 Commodity *com = commodity_get( xml_get(ccur) );
2258 if (commodity_isFlag(com, COMMODITY_FLAG_STANDARD))
2259 continue;
2260
2261 array_push_back( &comms, com );
2262 }
2263 } while (xml_nextNode(ccur));
2264 }
2265 else if (xml_isNode(cur, "blackmarket")) {
2266 spob_addService(spob, SPOB_SERVICE_BLACKMARKET);
2267 continue;
2268 }
2269 } while (xml_nextNode(cur));
2270 continue;
2271 }
2272 else if (xml_isNode(node, "tech")) {
2273 spob->tech = tech_groupCreateXML( node );
2274 continue;
2275 }
2276 else if (xml_isNode(node, "tags")) {
2277 xmlNodePtr cur = node->children;
2278 if (spob->tags != NULL)
2279 WARN(_("Spob '%s' has duplicate '%s' node!"), spob->name, "tags");
2280 else
2281 spob->tags = array_create( char* );
2282 do {
2283 xml_onlyNodes(cur);
2284 if (xml_isNode(cur, "tag")) {
2285 char *tmp = xml_get(cur);
2286 if (tmp != NULL)
2287 array_push_back( &spob->tags, strdup(tmp) );
2288 continue;
2289 }
2290 WARN(_("Spob '%s' has unknown node in tags '%s'."), spob->name, cur->name );
2291 } while (xml_nextNode(cur));
2292 continue;
2293 }
2294 WARN(_("Unknown node '%s' in spob '%s'"),node->name,spob->name);
2295 } while (xml_nextNode(node));
2296
2297 /* Allow forcing to be uninhabited. */
2298 if (spob_isFlag(spob, SPOB_UNINHABITED))
2299 spob->services &= ~SPOB_SERVICE_INHABITED;
2300
2301 if (spob->radius > 0.)
2302 spob_setFlag(spob, SPOB_RADIUS);
2303
2304 /* Set defaults if not set. */
2305 if (spob->lua_file == NULL) {
2306 const char *str = start_spob_lua_default();
2307 if (str != NULL)
2308 spob->lua_file = strdup( str );
2309 }
2310
2311/*
2312 * Verification
2313 */
2314#define MELEMENT(o,s) if (o) WARN(_("Spob '%s' missing '%s' element"), spob->name, s)
2315 //MELEMENT(spob->gfx_spaceName==NULL,"GFX space");
2316 MELEMENT( spob_hasService(spob,SPOB_SERVICE_LAND) &&
2317 spob->gfx_exterior==NULL,"GFX exterior");
2318 MELEMENT( spob_hasService(spob,SPOB_SERVICE_INHABITED) &&
2319 (spob->population==0), "population");
2320 MELEMENT((flags&FLAG_POSSET)==0,"pos");
2321 MELEMENT(spob->class==NULL,"class");
2322 MELEMENT( spob_hasService(spob,SPOB_SERVICE_LAND) &&
2323 spob->description==NULL,"description");
2324 MELEMENT( spob_hasService(spob,SPOB_SERVICE_BAR) &&
2325 spob->bar_description==NULL,"bar");
2326 MELEMENT( spob_hasService(spob,SPOB_SERVICE_INHABITED) &&
2327 (flags&FLAG_FACTIONSET)==0,"faction");
2328 MELEMENT((flags&FLAG_SERVICESSET)==0,"services");
2329 MELEMENT( spob_hasService(spob,SPOB_SERVICE_INHABITED) && (spob_hasService(spob,SPOB_SERVICE_OUTFITS) ||
2330 spob_hasService(spob,SPOB_SERVICE_SHIPYARD)) &&
2331 (spob->tech==NULL), "tech" );
2332 /*MELEMENT( spob_hasService(spob,SPOB_SERVICE_COMMODITY) &&
2333 (array_size(spob->commodities)==0),"commodity" );*/
2334 /*MELEMENT( (flags&FLAG_FACTIONSET) && (spob->presenceAmount == 0.),
2335 "presence" );*/
2336#undef MELEMENT
2337
2338 /* Build commodities list */
2339 if (spob_hasService(spob, SPOB_SERVICE_COMMODITY)) {
2342
2343 /* First, store all the standard commodities and prices. */
2344 if (array_size(stdList) > 0) {
2345 for (int i=0; i<array_size(stdList); i++)
2346 spob_addCommodity( spob, stdList[i] );
2347 }
2348
2349 /* Now add extra commodities */
2350 for (int i=0; i<array_size(comms); i++)
2351 spob_addCommodity( spob, comms[i] );
2352
2353 /* Shrink to minimum size. */
2354 array_shrink( &spob->commodities );
2355 array_shrink( &spob->commodityPrice );
2356 }
2357 /* Free temporary comms list. */
2358 array_free(comms);
2359
2360 xmlFreeDoc(doc);
2361
2362 return 0;
2363}
2364
2372int system_addSpob( StarSystem *sys, const char *spobname )
2373{
2374 Spob *spob;
2375
2376 if (sys == NULL)
2377 return -1;
2378
2379 spob = spob_get( spobname );
2380 if (spob == NULL)
2381 return -1;
2382 array_push_back( &sys->spobs, spob );
2383 array_push_back( &sys->spobsid, spob->id );
2384
2385 /* add spob <-> star system to name stack */
2387 array_push_back( &systemname_stack, sys->name );
2388
2390 /* This is required to clear the player statistics for this spob */
2392
2393 /* Reload graphics if necessary. */
2394 if (cur_system != NULL)
2396
2397 /* Initialize economy if applicable. */
2398 if (spob_hasService( spob, SPOB_SERVICE_COMMODITY ))
2399 economy_initialiseSingleSystem( sys, spob );
2400
2401 return 0;
2402}
2403
2411int system_rmSpob( StarSystem *sys, const char *spobname )
2412{
2413 int i, found;
2414 Spob *spob;
2415
2416 if (sys == NULL) {
2417 WARN(_("Unable to remove spob '%s' from NULL system."), spobname);
2418 return -1;
2419 }
2420
2421 /* Try to find spob. */
2422 spob = spob_get( spobname );
2423 for (i=0; i<array_size(sys->spobs); i++)
2424 if (sys->spobs[i] == spob)
2425 break;
2426
2427 /* Spob not found. */
2428 if (i>=array_size(sys->spobs)) {
2429 WARN(_("Spob '%s' not found in system '%s' for removal."), spobname, sys->name);
2430 return -1;
2431 }
2432
2433 /* Remove spob from system. */
2434 array_erase( &sys->spobs, &sys->spobs[i], &sys->spobs[i+1] );
2435 array_erase( &sys->spobsid, &sys->spobsid[i], &sys->spobsid[i+1] );
2436
2437 /* Remove the presence. */
2438 space_reconstructPresences(); /* TODO defer this if removing multiple spobs at once. */
2439
2440 /* Remove from the name stack thingy. */
2441 found = 0;
2442 for (i=0; i<array_size(spobname_stack); i++)
2443 if (strcmp(spobname, spobname_stack[i])==0) {
2446 found = 1;
2447 break;
2448 }
2449 if (found == 0)
2450 WARN(_("Unable to find spob '%s' and system '%s' in spob<->system stack."),
2451 spobname, sys->name );
2452
2453 system_setFaction(sys);
2454
2456
2457 return 0;
2458}
2459
2466int system_addVirtualSpob( StarSystem *sys, const char *spobname )
2467{
2468 VirtualSpob *va;
2469
2470 if (sys == NULL)
2471 return -1;
2472
2473 va = virtualspob_get( spobname );
2474 if (va == NULL)
2475 return -1;
2476 array_push_back( &sys->spobs_virtual, va );
2477
2478 /* Economy is affected by presence. */
2480
2481 return 0;
2482}
2483
2490int system_rmVirtualSpob( StarSystem *sys, const char *spobname )
2491{
2492 int i;
2493
2494 if (sys == NULL) {
2495 WARN(_("Unable to remove virtual spob '%s' from NULL system."), spobname);
2496 return -1;
2497 }
2498
2499 /* Try to find virtual spob. */
2500 for (i=0; i<array_size(sys->spobs_virtual); i++)
2501 if (strcmp(sys->spobs_virtual[i]->name, spobname)==0)
2502 break;
2503
2504 /* Virtual spob not found. */
2505 if (i>=array_size(sys->spobs_virtual)) {
2506 WARN(_("Virtual spob '%s' not found in system '%s' for removal."), spobname, sys->name);
2507 return -1;
2508 }
2509
2510 /* Remove virtual spob. */
2511 array_erase( &sys->spobs_virtual, &sys->spobs_virtual[i], &sys->spobs_virtual[i+1] );
2512
2513 /* Remove the presence. */
2514 space_reconstructPresences(); /* TODO defer this if removing multiple spobs at once. */
2515 system_setFaction(sys);
2516
2518
2519 return 0;
2520}
2521
2531int system_addJumpDiff( StarSystem *sys, xmlNodePtr node )
2532{
2533 if (system_parseJumpPointDiff(node, sys) <= -1)
2534 return 0;
2537
2538 return 1;
2539}
2540
2550int system_rmJump( StarSystem *sys, const char *jumpname )
2551{
2552 int i;
2553 JumpPoint *jump;
2554
2555 if (sys == NULL) {
2556 WARN(_("Unable to remove jump point '%s' from NULL system."), jumpname);
2557 return -1;
2558 }
2559
2560 /* Try to find spob. */
2561 jump = jump_get( jumpname, sys );
2562 for (i=0; i<array_size(sys->jumps); i++)
2563 if (&sys->jumps[i] == jump)
2564 break;
2565
2566 /* Spob not found. */
2567 if (i>=array_size(sys->jumps)) {
2568 WARN(_("Jump point '%s' not found in system '%s' for removal."), jumpname, sys->name);
2569 return -1;
2570 }
2571
2572 /* Remove jump from system. */
2573 array_erase( &sys->jumps, &sys->jumps[i], &sys->jumps[i+1] );
2574
2575 /* Refresh presence */
2576 system_setFaction(sys);
2577
2579
2580 return 0;
2581}
2582
2586static void system_init( StarSystem *sys )
2587{
2588 memset( sys, 0, sizeof(StarSystem) );
2589 sys->spobs = array_create( Spob* );
2590 sys->spobs_virtual = array_create( VirtualSpob* );
2591 sys->spobsid = array_create( int );
2592 sys->jumps = array_create( JumpPoint );
2593 sys->asteroids = array_create( AsteroidAnchor );
2594 sys->astexclude= array_create( AsteroidExclusion );
2595 sys->faction = -1;
2596}
2597
2601StarSystem *system_new (void)
2602{
2603 StarSystem *sys;
2604 int id;
2605
2606#if DEBUGGING
2607 if (!systems_loading)
2608 systemstack_changed = 1;
2609#else /* DEBUGGING */
2610 if (!systems_loading)
2611 WARN(_("Creating new system in non-debugging mode. Things are probably going to break horribly."));
2612#endif /* DEBUGGING */
2613
2614 /* Protect current system in case of realloc. */
2615 id = -1;
2616 if (cur_system != NULL)
2617 id = system_index( cur_system );
2618
2619 /* Grow array. */
2620 sys = &array_grow( &systems_stack );
2621
2622 /* Reset cur_system. */
2623 if (id >= 0)
2625
2626 /* Initialize system and id. */
2627 system_init( sys );
2628 sys->id = array_size(systems_stack)-1;
2629
2630 /* Reconstruct the jumps, only truely necessary if the systems realloced. */
2631 if (!systems_loading)
2633
2634 return sys;
2635}
2636
2640void system_reconstructJumps (StarSystem *sys)
2641{
2642 for (int j=0; j<array_size(sys->jumps); j++) {
2643 double dx, dy, a;
2644 JumpPoint *jp = &sys->jumps[j];
2645 jp->from = sys;
2646 jp->target = system_getIndex( jp->targetid );
2647 jp->returnJump = jump_getTarget( sys, jp->target );
2648
2649 /* Get heading. */
2650 dx = jp->target->pos.x - sys->pos.x;
2651 dy = jp->target->pos.y - sys->pos.y;
2652 a = atan2( dy, dx );
2653 if (a < 0.)
2654 a += 2.*M_PI;
2655
2656 /* Update position if needed.. */
2657 if (jp->flags & JP_AUTOPOS)
2658 vec2_pset( &jp->pos, sys->radius, a );
2659
2660 /* Update jump specific data. */
2661 gl_getSpriteFromDir( &jp->sx, &jp->sy, jumppoint_gfx, a );
2662 jp->angle = 2.*M_PI-a;
2663 jp->cosa = cos(jp->angle);
2664 jp->sina = sin(jp->angle);
2665 }
2666}
2667
2672{
2673 /* So we need to calculate the shortest jump. */
2674 for (int i=0; i<array_size(systems_stack); i++) {
2675 StarSystem *sys = &systems_stack[i];
2677 }
2678}
2679
2684{
2685 for (int i=0; i<array_size(systems_stack); i++) {
2686 StarSystem *sys = &systems_stack[i];
2687 for (int j=0; j<array_size(sys->spobsid); j++)
2688 sys->spobs[j] = &spob_stack[ sys->spobsid[j] ];
2689 }
2690}
2691
2699static int system_parseAsteroidField( const xmlNodePtr node, StarSystem *sys )
2700{
2702 xmlNodePtr cur;
2703 int pos;
2704
2705 /* Allocate more space. */
2706 a = &array_grow( &sys->asteroids );
2707 memset( a, 0, sizeof(AsteroidAnchor) );
2708
2709 /* Initialize stuff. */
2710 pos = 1;
2711 a->density = ASTEROID_DEFAULT_DENSITY;
2712 a->groups = array_create( AsteroidTypeGroup* );
2713 a->groupsw = array_create( double );
2714 a->radius = 0.;
2715 a->maxspeed = ASTEROID_DEFAULT_MAXSPEED;
2716 a->maxspin = ASTEROID_DEFAULT_MAXSPIN;
2717 a->thrust = ASTEROID_DEFAULT_THRUST;
2718
2719 /* Parse label if available. */
2720 xmlr_attr_strd( node, "label", a->label );
2721
2722 /* Parse data. */
2723 cur = node->xmlChildrenNode;
2724 do {
2725 xml_onlyNodes(cur);
2726
2727 xmlr_float( cur, "density", a->density );
2728 xmlr_float( cur, "radius", a->radius );
2729 xmlr_float( cur, "maxspeed", a->maxspeed );
2730 xmlr_float( cur, "thrust", a->thrust );
2731
2732 /* Handle types of asteroids. */
2733 if (xml_isNode(cur,"group")) {
2734 double w;
2735 const char *name = xml_get(cur);
2736 xmlr_attr_float_def(cur,"weight",w,1.);
2737 array_push_back( &a->groups, astgroup_getName(name) );
2738 array_push_back( &a->groupsw, w );
2739 continue;
2740 }
2741
2742 /* Handle position. */
2743 if (xml_isNode(cur,"pos")) {
2744 double x, y;
2745 pos = 1;
2746 xmlr_attr_float( cur, "x", x );
2747 xmlr_attr_float( cur, "y", y );
2748
2749 /* Set position. */
2750 vec2_cset( &a->pos, x, y );
2751 continue;
2752 }
2753
2754 WARN(_("Asteroid Field in Star System '%s' has unknown node '%s'"), sys->name, node->name);
2755 } while (xml_nextNode(cur));
2756
2757 /* Update internals. */
2759
2760#define MELEMENT(o,s) \
2761if (o) WARN(_("Asteroid Field in Star System '%s' has missing/invalid '%s' element"), sys->name, s)
2762 MELEMENT(!pos,"pos");
2763 MELEMENT(a->radius<=0.,"radius");
2764 MELEMENT(array_size(a->groups)==0,"groups");
2765#undef MELEMENT
2766
2767 return 0;
2768}
2769
2777static int system_parseAsteroidExclusion( const xmlNodePtr node, StarSystem *sys )
2778{
2780 xmlNodePtr cur;
2781 double x, y;
2782 int pos;
2783
2784 /* Allocate more space. */
2785 a = &array_grow( &sys->astexclude );
2786 memset( a, 0, sizeof(*a) );
2787
2788 /* Initialize stuff. */
2789 pos = 0;
2790
2791 /* Parse data. */
2792 cur = node->xmlChildrenNode;
2793 do {
2794 xml_onlyNodes( cur );
2795
2796 xmlr_float( cur, "radius", a->radius );
2797
2798 /* Handle position. */
2799 if (xml_isNode(cur,"pos")) {
2800 pos = 1;
2801 xmlr_attr_float( cur, "x", x );
2802 xmlr_attr_float( cur, "y", y );
2803
2804 /* Set position. */
2805 vec2_cset( &a->pos, x, y );
2806 continue;
2807 }
2808 WARN(_("Asteroid Exclusion Zone in Star System '%s' has unknown node '%s'"), sys->name, node->name);
2809 } while (xml_nextNode(cur));
2810
2811#define MELEMENT(o,s) \
2812if (o) WARN(_("Asteroid Exclusion Zone in Star System '%s' has missing/invalid '%s' element"), sys->name, s)
2813 MELEMENT(!pos,"pos");
2814 MELEMENT(a->radius<=0.,"radius");
2815#undef MELEMENT
2816
2817 return 0;
2818}
2819
2827static int system_parse( StarSystem *sys, const char *filename )
2828{
2829 xmlNodePtr node, parent;
2830 xmlDocPtr doc;
2831 uint32_t flags;
2832
2833 /* Load the file. */
2834 doc = xml_parsePhysFS( filename );
2835 if (doc == NULL)
2836 return -1;
2837
2838 parent = doc->xmlChildrenNode; /* first spob node */
2839 if (parent == NULL) {
2840 WARN(_("Malformed %s file: does not contain elements"), filename);
2841 xmlFreeDoc(doc);
2842 return -1;
2843 }
2844
2845 /* Clear memory for safe defaults. */
2846 system_init( sys );
2847 flags = 0;
2848 sys->presence = array_create( SystemPresence );
2849 sys->ownerpresence = 0.;
2850 sys->nebu_hue = NEBULA_DEFAULT_HUE;
2851 sys->stars = -1;
2852
2853 xmlr_attr_strd( parent, "name", sys->name );
2854
2855 node = parent->xmlChildrenNode;
2856 do { /* load all the data */
2857 /* Only handle nodes. */
2858 xml_onlyNodes(node);
2859
2860 if (xml_isNode(node,"pos")) {
2861 flags |= FLAG_POSSET;
2862 xmlr_attr_float( node, "x", sys->pos.x );
2863 xmlr_attr_float( node, "y", sys->pos.y );
2864 continue;
2865 }
2866 else if (xml_isNode(node,"general")) {
2867 xmlNodePtr cur = node->children;
2868 do {
2869 xml_onlyNodes(cur);
2870 xmlr_strd( cur, "background", sys->background );
2871 xmlr_strd( cur, "map_shader", sys->map_shader );
2872 xmlr_strd( cur, "features", sys->features );
2873 xmlr_int( cur, "stars", sys->stars );
2874 xmlr_float( cur, "radius", sys->radius );
2875 if (xml_isNode(cur,"interference")) {
2876 flags |= FLAG_INTERFERENCESET;
2877 sys->interference = xml_getFloat(cur);
2878 continue;
2879 }
2880 if (xml_isNode(cur,"nebula")) {
2881 xmlr_attr_float( cur, "volatility", sys->nebu_volatility );
2882 xmlr_attr_float_def( cur, "hue", sys->nebu_hue, NEBULA_DEFAULT_HUE );
2883 sys->nebu_density = xml_getFloat(cur);
2884 continue;
2885 }
2886 if (xml_isNode(cur,"nolanes")) {
2887 sys_setFlag( sys, SYSTEM_NOLANES );
2888 continue;
2889 }
2890 DEBUG(_("Unknown node '%s' in star system '%s'"),node->name,sys->name);
2891 } while (xml_nextNode(cur));
2892 continue;
2893 }
2894 /* Loads all the spobs. */
2895 else if (xml_isNode(node,"spobs")) {
2896 xmlNodePtr cur = node->children;
2897 do {
2898 xml_onlyNodes(cur);
2899 if (xml_isNode(cur,"spob")) {
2900 system_addSpob( sys, xml_get(cur) );
2901 continue;
2902 }
2903 if (xml_isNode(cur,"spob_virtual")) {
2904 system_addVirtualSpob( sys, xml_get(cur) );
2905 continue;
2906 }
2907 DEBUG(_("Unknown node '%s' in star system '%s'"),node->name,sys->name);
2908 } while (xml_nextNode(cur));
2909 continue;
2910 }
2911
2912 if (xml_isNode(node,"asteroids")) {
2913 xmlNodePtr cur = node->children;
2914 do {
2915 xml_onlyNodes(cur);
2916 if (xml_isNode(cur,"asteroid"))
2917 system_parseAsteroidField( cur, sys );
2918 else if (xml_isNode(cur,"exclusion"))
2920 } while (xml_nextNode(cur));
2921 }
2922
2923 if (xml_isNode(node, "stats")) {
2924 xmlNodePtr cur = node->children;
2925 do {
2926 xml_onlyNodes(cur);
2927 ShipStatList *ll = ss_listFromXML( cur );
2928 if (ll != NULL) {
2929 ll->next = sys->stats;
2930 sys->stats = ll;
2931 continue;
2932 }
2933 WARN(_("System '%s' has unknown stat '%s'."), sys->name, cur->name);
2934 } while (xml_nextNode(cur));
2935 continue;
2936 }
2937
2938 if (xml_isNode(node, "tags")) {
2939 xmlNodePtr cur = node->children;
2940 sys->tags = array_create( char* );
2941 do {
2942 xml_onlyNodes(cur);
2943 if (xml_isNode(cur, "tag")) {
2944 char *tmp = xml_get(cur);
2945 if (tmp != NULL)
2946 array_push_back( &sys->tags, strdup(tmp) );
2947 continue;
2948 }
2949 WARN(_("System '%s' has unknown node in tags '%s'."), sys->name, cur->name );
2950 } while (xml_nextNode(cur));
2951 continue;
2952 }
2953
2954 /* Avoid warnings. */
2955 if (xml_isNode(node,"jumps") || xml_isNode(node,"asteroids"))
2956 continue;
2957
2958 DEBUG(_("Unknown node '%s' in star system '%s'"),node->name,sys->name);
2959 } while (xml_nextNode(node));
2960
2961 ss_sort( &sys->stats );
2962 array_shrink( &sys->spobs );
2963 array_shrink( &sys->spobsid );
2964 array_shrink( &sys->asteroids );
2965 array_shrink( &sys->astexclude );
2966
2967 /* Convert hue from 0 to 359 value to 0 to 1 value. */
2968 sys->nebu_hue /= 360.;
2969
2970 /* Load the shader. */
2971 if (sys->map_shader != NULL)
2972 sys->ms = mapshader_get( sys->map_shader );
2973
2974#define MELEMENT(o,s) if (o) WARN(_("Star System '%s' missing '%s' element"), sys->name, s)
2975 if (sys->name == NULL) WARN(_("Star System '%s' missing 'name' tag"), sys->name);
2976 MELEMENT((flags&FLAG_POSSET)==0,"pos");
2977 MELEMENT(sys->stars<0,"stars");
2978 MELEMENT(sys->radius==0.,"radius");
2979 MELEMENT((flags&FLAG_INTERFERENCESET)==0,"inteference");
2980#undef MELEMENT
2981
2982 xmlFreeDoc( doc );
2983
2984 return 0;
2985}
2986
2990static int sys_cmpSysFaction( const void *a, const void *b )
2991{
2992 SystemPresence *spa, *spb;
2993
2994 spa = (SystemPresence*) a;
2995 spb = (SystemPresence*) b;
2996
2997 /* Compare value. */
2998 if (spa->value < spb->value)
2999 return +1;
3000 else if (spa->value > spb->value)
3001 return -1;
3002
3003 /* Compare faction id. */
3004 if (spa->faction < spb->faction)
3005 return +1;
3006 else if (spa->faction > spb->faction)
3007 return -1;
3008
3009 return 0;
3010}
3011
3017void system_setFaction( StarSystem *sys )
3018{
3019 /* Sort presences in descending order. */
3020 if (array_size(sys->presence) != 0)
3021 qsort( sys->presence, array_size(sys->presence), sizeof(SystemPresence), sys_cmpSysFaction );
3022
3023 sys->faction = -1;
3024 for (int i=0; i<array_size(sys->presence); i++) {
3025 for (int j=0; j<array_size(sys->spobs); j++) {
3026 Spob *pnt = sys->spobs[j];
3027
3028 if (pnt->presence.faction != sys->presence[i].faction)
3029 continue;
3030
3031 sys->faction = pnt->presence.faction;
3032 return;
3033 }
3034 }
3035}
3036
3044static int system_parseJumpPointDiff( const xmlNodePtr node, StarSystem *sys )
3045{
3046 JumpPoint *j;
3047 char *buf;
3048 double x, y;
3049 StarSystem *target;
3050
3051 /* Get target. */
3052 xmlr_attr_strd( node, "target", buf );
3053 if (buf == NULL) {
3054 WARN(_("JumpPoint node for system '%s' has no target attribute."), sys->name);
3055 return -1;
3056 }
3057 target = system_get(buf);
3058 if (target == NULL) {
3059 WARN(_("JumpPoint node for system '%s' has invalid target '%s'."), sys->name, buf );
3060 free(buf);
3061 return -1;
3062 }
3063 free(buf);
3064
3065#ifdef DEBUGGING
3066 for (int i=0; i<array_size(sys->jumps); i++) {
3067 JumpPoint *jp = &sys->jumps[i];
3068 if (jp->targetid != target->id)
3069 continue;
3070
3071 WARN(_("Star System '%s' has duplicate jump point to '%s'."),
3072 sys->name, target->name );
3073 break;
3074 }
3075#endif /* DEBUGGING */
3076
3077 /* Allocate more space. */
3078 j = &array_grow( &sys->jumps );
3079 memset( j, 0, sizeof(JumpPoint) );
3080
3081 /* Handle jump point position. We want both x and y, or we autoposition the jump point. */
3082 xmlr_attr_float_def( node, "x", x, HUGE_VAL );
3083 xmlr_attr_float_def( node, "y", y, HUGE_VAL );
3084
3085 /* Handle jump point type. */
3086 xmlr_attr_strd( node, "type", buf );
3087 if (buf == NULL);
3088 else if (strcmp(buf, "hidden") == 0)
3089 jp_setFlag(j,JP_HIDDEN);
3090 else if (strcmp(buf, "exitonly") == 0)
3091 jp_setFlag(j,JP_EXITONLY);
3092 free( buf );
3093
3094 xmlr_attr_float_def( node, "hide", j->hide, HIDE_DEFAULT_JUMP);
3095
3096 /* Set some stuff. */
3097 j->target = target;
3098 j->targetid = j->target->id;
3099 j->radius = 200.;
3100
3101 if (x < HUGE_VAL && y < HUGE_VAL)
3102 vec2_cset( &j->pos, x, y );
3103 else
3104 jp_setFlag(j,JP_AUTOPOS);
3105
3106 return 0;
3107}
3108
3116static int system_parseJumpPoint( const xmlNodePtr node, StarSystem *sys )
3117{
3118 JumpPoint *j;
3119 char *buf;
3120 xmlNodePtr cur;
3121 double x, y;
3122 StarSystem *target;
3123 int pos;
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 /* Set some stuff. */
3156 j->from = sys;
3157 j->target = target;
3158 j->targetid = j->target->id;
3159 j->radius = 200.;
3160
3161 pos = 0;
3162
3163 /* Parse data. */
3164 cur = node->xmlChildrenNode;
3165 do {
3166 xmlr_float( cur, "radius", j->radius );
3167
3168 /* Handle position. */
3169 if (xml_isNode(cur,"pos")) {
3170 pos = 1;
3171 xmlr_attr_float( cur, "x", x );
3172 xmlr_attr_float( cur, "y", y );
3173
3174 /* Set position. */
3175 vec2_cset( &j->pos, x, y );
3176 }
3177 else if (xml_isNode(cur,"autopos"))
3178 jp_setFlag(j,JP_AUTOPOS);
3179 else if (xml_isNode(cur,"hidden"))
3180 jp_setFlag(j,JP_HIDDEN);
3181 else if (xml_isNode(cur,"exitonly"))
3182 jp_setFlag(j,JP_EXITONLY);
3183 else if (xml_isNode(cur,"hide")) {
3184 xmlr_float( cur,"hide", j->hide );
3185 }
3186 } while (xml_nextNode(cur));
3187
3188 if (!jp_isFlag(j,JP_AUTOPOS) && !pos)
3189 WARN(_("JumpPoint in system '%s' is missing pos element but does not have autopos flag."), sys->name);
3190
3191 return 0;
3192}
3193
3200static int system_parseJumps( StarSystem *sys )
3201{
3202 xmlNodePtr parent, node;
3203 xmlDocPtr doc;
3204
3205 doc = xml_parsePhysFS( sys->filename );
3206 if (doc == NULL)
3207 return -1;
3208
3209 parent = doc->xmlChildrenNode; /* first spob node */
3210 if (parent == NULL) {
3211 xmlFreeDoc(doc);
3212 return -1;
3213 }
3214
3215 node = parent->xmlChildrenNode;
3216 do { /* load all the data */
3217 if (xml_isNode(node,"jumps")) {
3218 xmlNodePtr cur = node->children;
3219 do {
3220 if (xml_isNode(cur,"jump"))
3221 system_parseJumpPoint( cur, sys );
3222 } while (xml_nextNode(cur));
3223 }
3224 } while (xml_nextNode(node));
3225
3226 array_shrink( &sys->jumps );
3227
3228 xmlFreeDoc(doc);
3229 return 0;
3230}
3231
3237int space_load (void)
3238{
3239 int ret;
3240
3241 /* Loading. */
3242 systems_loading = 1;
3243
3244 /* Create some arrays. */
3245 spobname_stack = array_create( char* );
3246 systemname_stack = array_create( char* );
3247
3248 /* Load jump point graphic - must be before systems_load(). */
3249 jumppoint_gfx = gl_newSprite( SPOB_GFX_SPACE_PATH"jumppoint.webp", 4, 4, OPENGL_TEX_MIPMAPS );
3250 jumpbuoy_gfx = gl_newImage( SPOB_GFX_SPACE_PATH"jumpbuoy.webp", 0 );
3251
3252 /* Load spobs. */
3253 ret = spobs_load();
3254 if (ret < 0)
3255 return ret;
3256
3257 /* Load virtual spobs. */
3258 ret = virtualspobs_load();
3259 if (ret < 0)
3260 return ret;
3261
3262 /* Load asteroid stuff. */
3263 ret = asteroids_load ();
3264 if (ret < 0)
3265 return ret;
3266
3267 /* Load systems. */
3268 ret = systems_load();
3269 if (ret < 0)
3270 return ret;
3271
3272 /* Done loading. */
3273 systems_loading = 0;
3274
3275 /* Apply all the presences. */
3276 for (int i=0; i<array_size(systems_stack); i++)
3278
3279 /* Determine dominant faction. */
3280 for (int i=0; i<array_size(systems_stack); i++)
3282
3283 /* Reconstruction. */
3286
3287 /* Fine tuning. */
3288 for (int i=0; i<array_size(systems_stack); i++) {
3289 StarSystem *sys = &systems_stack[i];
3290
3291 /* Save jump indexes. */
3292 for (int j=0; j<array_size(sys->jumps); j++)
3293 sys->jumps[j].targetid = sys->jumps[j].target->id;
3294 sys->ownerpresence = system_getPresence( sys, sys->faction );
3295 }
3296
3297 /* Calculate commodity prices (sinusoidal model). */
3299
3300 return 0;
3301}
3302
3307{
3308 int ret = 0;
3309 for (int i=0; i<array_size(spob_stack); i++)
3310 ret |= spob_luaInit( &spob_stack[i] );
3311 return ret;
3312}
3313
3324static int systems_load (void)
3325{
3326 char **system_files;
3327 Uint32 time = SDL_GetTicks();
3328
3329 /* Allocate if needed. */
3330 if (systems_stack == NULL)
3331 systems_stack = array_create( StarSystem );
3332
3333 system_files = ndata_listRecursive( SYSTEM_DATA_PATH );
3334
3335 /*
3336 * First pass - loads all the star systems_stack.
3337 */
3338 for (int i=0; i<array_size(system_files); i++) {
3339 StarSystem sys;
3340
3341 if (!ndata_matchExt( system_files[i], "xml" ))
3342 continue;
3343
3344 int ret = system_parse( &sys, system_files[i] );
3345 if (ret == 0) {
3346 sys.filename = system_files[i];
3347 sys.id = array_size(systems_stack);
3348
3349 /* Update asteroid info. */
3350 system_updateAsteroids( &sys );
3351
3353
3354 /* Render if necessary. */
3356 }
3357 }
3358 qsort( systems_stack, array_size(systems_stack), sizeof(StarSystem), system_cmp );
3359 for (int j=0; j<array_size(systems_stack); j++) {
3360 systems_stack[j].id = j;
3361 systems_stack[j].note = NULL; /* just to be sure */
3362 }
3363
3364 /*
3365 * Second pass - loads all the jump routes.
3366 */
3367 for (int i=0; i<array_size(systems_stack); i++)
3369
3370 /* Clean up. */
3371 array_free( system_files );
3372
3373 if (conf.devmode) {
3374 time = SDL_GetTicks() - time;
3375 DEBUG( n_( "Loaded %d Star System",
3376 "Loaded %d Star Systems", array_size(systems_stack) ), array_size(systems_stack) );
3377 DEBUG( n_( " with %d Space Object in %.3f s",
3378 " with %d Space Objects in %.3f s", array_size(spob_stack) ), array_size(spob_stack), time/1000. );
3379 }
3380 else {
3381 DEBUG( n_( "Loaded %d Star System",
3382 "Loaded %d Star Systems", array_size(systems_stack) ), array_size(systems_stack) );
3383 DEBUG( n_( " with %d Space Object",
3384 " with %d Space Objects", array_size(spob_stack) ), array_size(spob_stack) );
3385 }
3386
3387 return 0;
3388}
3389
3395void space_render( const double dt )
3396{
3397 if (cur_system == NULL)
3398 return;
3399
3400 if (cur_system->nebu_density > 0.)
3401 nebu_render(dt);
3402 else
3404}
3405
3411void space_renderOverlay( const double dt )
3412{
3413 if (cur_system == NULL)
3414 return;
3415
3416 /* Render the debris. */
3418
3419 /* Render overlay if necessary. */
3421
3422 if ((cur_system->nebu_density > 0.) &&
3425}
3426
3430void spobs_render (void)
3431{
3432 /* Must be a system. */
3433 if (cur_system==NULL)
3434 return;
3435
3436 /* Render the jumps. */
3437 for (int i=0; i < array_size(cur_system->jumps); i++)
3438 space_renderJumpPoint( &cur_system->jumps[i], i );
3439
3440 /* Render the spobs. */
3441 for (int i=0; i < array_size(cur_system->spobs); i++)
3442 space_renderSpob( cur_system->spobs[i] );
3443
3444 /* Render the asteroids & debris. */
3446
3447 /* Render gatherable stuff. */
3449
3450}
3451
3455static void space_renderJumpPoint( const JumpPoint *jp, int i )
3456{
3457 const glColour *c;
3458
3459 if (!jp_isUsable(jp))
3460 return;
3461
3462 if ((player.p != NULL) && (i==player.p->nav_hyperspace) &&
3463 (pilot_isFlag(player.p, PILOT_HYPERSPACE) || space_canHyperspace(player.p)))
3464 c = &cGreen;
3465 else if (jp_isFlag(jp, JP_HIDDEN))
3466 c = &cRed;
3467 else
3468 c = NULL;
3469
3470 gl_renderSprite( jumppoint_gfx, jp->pos.x, jp->pos.y, jp->sx, jp->sy, c );
3471
3472 /* Draw buoys next to "highway" jump points. */
3473 if (jp->hide == 0.) {
3474 gl_renderSprite( jumpbuoy_gfx, jp->pos.x + 200 * jp->sina, jp->pos.y + 200 * jp->cosa, 0, 0, NULL ); /* Left */
3475 gl_renderSprite( jumpbuoy_gfx, jp->pos.x + -200 * jp->sina, jp->pos.y + -200 * jp->cosa, 0, 0, NULL ); /* Right */
3476 }
3477}
3478
3482static void space_renderSpob( const Spob *p )
3483{
3484 if (p->lua_render != LUA_NOREF) {
3485 spob_luaInitMem( p );
3486 /* TODO do a clip test first. */
3487 lua_rawgeti(naevL, LUA_REGISTRYINDEX, p->lua_render); /* f */
3488 if (nlua_pcall( p->lua_env, 0, 0 )) {
3489 WARN(_("Spob '%s' failed to run '%s':\n%s"), p->name, "render", lua_tostring(naevL,-1));
3490 lua_pop(naevL,1);
3491 }
3492 }
3493 else if (p->gfx_space)
3494 gl_renderSprite( p->gfx_space, p->pos.x, p->pos.y, 0, 0, NULL );
3495}
3496
3500static void space_updateSpob( const Spob *p, double dt, double real_dt )
3501{
3502 if (p->lua_update == LUA_NOREF)
3503 return;
3504 /* TODO do a clip test first. */
3505 spob_luaInitMem( p );
3506 lua_rawgeti(naevL, LUA_REGISTRYINDEX, p->lua_update); /* f */
3507 lua_pushnumber(naevL, dt); /* f, dt */
3508 lua_pushnumber(naevL, real_dt); /* f, real_dt */
3509 if (nlua_pcall( p->lua_env, 2, 0 )) {
3510 WARN(_("Spob '%s' failed to run '%s':\n%s"), p->name, "update", lua_tostring(naevL,-1));
3511 lua_pop(naevL,1);
3512 }
3513}
3514
3518void space_exit (void)
3519{
3520 /* Free standalone graphic textures */
3522 jumppoint_gfx = NULL;
3524 jumpbuoy_gfx = NULL;
3525
3526 /* Free the names. */
3529
3530 /* Free the spobs. */
3531 for (int i=0; i < array_size(spob_stack); i++) {
3532 Spob *spb = &spob_stack[i];
3533
3534 free(spb->name);
3535 free(spb->display);
3536 free(spb->feature);
3537 free(spb->lua_file);
3538 free(spb->class);
3539 free(spb->description);
3540 free(spb->bar_description);
3541 for (int j=0; j<array_size(spb->tags); j++)
3542 free( spb->tags[j] );
3543 array_free(spb->tags);
3544
3545 /* graphics */
3546 if (spb->gfx_spaceName != NULL) {
3547 gl_freeTexture( spb->gfx_space );
3548 free(spb->gfx_spaceName);
3549 free(spb->gfx_spacePath);
3550 }
3551 if (spb->gfx_exterior != NULL) {
3552 free(spb->gfx_exterior);
3553 free(spb->gfx_exteriorPath);
3554 }
3555
3556 /* Landing. */
3557 free(spb->land_msg);
3558
3559 /* tech */
3560 if (spb->tech != NULL)
3561 tech_groupDestroy( spb->tech );
3562
3563 /* commodities */
3564 array_free(spb->commodities);
3566
3567 /* Lua. */
3568 nlua_freeEnv( spb->lua_env );
3569 }
3571
3572 for (int i=0; i<array_size(spob_lua_stack); i++)
3573 spob_lua_free( &spob_lua_stack[i] );
3575
3576 for (int i=0; i<array_size(vspob_stack); i++) {
3577 VirtualSpob *va = &vspob_stack[i];
3578 free( va->name );
3579 array_free( va->presences );
3580 }
3582
3583 /* Free the systems. */
3584 for (int i=0; i < array_size(systems_stack); i++) {
3585 StarSystem *sys = &systems_stack[i];
3586
3587 free(sys->filename);
3588 free(sys->name);
3589 free(sys->background);
3590 free(sys->map_shader);
3591 free(sys->features);
3592 free(sys->note);
3593 array_free(sys->jumps);
3594 array_free(sys->presence);
3595 array_free(sys->spobs);
3596 array_free(sys->spobsid);
3597 array_free(sys->spobs_virtual);
3598
3599 for (int j=0; j<array_size(sys->tags); j++)
3600 free( sys->tags[j] );
3601 array_free(sys->tags);
3602
3603 /* Free the asteroids. */
3604 for (int j=0; j < array_size(sys->asteroids); j++)
3605 asteroid_free( &sys->asteroids[j] );
3606 array_free(sys->asteroids);
3607 array_free(sys->astexclude);
3608
3609 ss_free( sys->stats );
3610 }
3612 systems_stack = NULL;
3613
3614 /* Free asteroids stuff. */
3616
3617 /* Free the gatherable stack. */
3619
3620 /* Free the map shaders. */
3621 for (int i=0; i<array_size(mapshaders); i++) {
3622 MapShader *ms = mapshaders[i];
3623 free( ms->name );
3624 glDeleteProgram( ms->program );
3625 free(ms);
3626 }
3628}
3629
3634{
3635 for (int i=0; i<array_size(systems_stack); i++) {
3636 StarSystem *sys = &systems_stack[i];
3637 sys_rmFlag(sys,SYSTEM_KNOWN);
3638 sys_rmFlag(sys,SYSTEM_HIDDEN);
3639 sys_rmFlag(sys,SYSTEM_PMARKED);
3640 for (int j=0; j<array_size(sys->jumps); j++)
3641 jp_rmFlag(&sys->jumps[j],JP_KNOWN);
3642 free(sys->note);
3643 sys->note=NULL;
3644 }
3645 for (int j=0; j<array_size(spob_stack); j++)
3646 spob_rmFlag(&spob_stack[j],SPOB_KNOWN);
3647}
3648
3653{
3654 for (int i=0; i<array_size(systems_stack); i++) {
3655 StarSystem *sys = &systems_stack[i];
3656 sys_rmFlag( sys, SYSTEM_MARKED );
3657 sys->markers_computer = 0;
3658 sys->markers_plot = 0;
3659 sys->markers_high = 0;
3660 sys->markers_low = 0;
3661 }
3662 for (int i=0; i<array_size(spob_stack); i++) {
3663 Spob *pnt = &spob_stack[i];
3664 spob_rmFlag( pnt, SPOB_MARKED );
3665 pnt->markers = 0;
3666 }
3667}
3668
3673{
3674 for (int i=0; i<array_size(systems_stack); i++)
3675 sys_rmFlag(&systems_stack[i],SYSTEM_CMARKED);
3676}
3677
3678static int space_addMarkerSystem( int sysid, MissionMarkerType type )
3679{
3680 StarSystem *ssys;
3681 int *markers;
3682
3683 /* Get the system. */
3684 ssys = system_getIndex(sysid);
3685 if (ssys == NULL)
3686 return -1;
3687
3688 /* Get the marker. */
3689 switch (type) {
3690 case SYSMARKER_COMPUTER:
3691 markers = &ssys->markers_computer;
3692 break;
3693 case SYSMARKER_LOW:
3694 markers = &ssys->markers_low;
3695 break;
3696 case SYSMARKER_HIGH:
3697 markers = &ssys->markers_high;
3698 break;
3699 case SYSMARKER_PLOT:
3700 markers = &ssys->markers_plot;
3701 break;
3702 default:
3703 WARN(_("Unknown marker type."));
3704 return -1;
3705 }
3706
3707 /* Decrement markers. */
3708 (*markers)++;
3709 sys_setFlag(ssys, SYSTEM_MARKED);
3710
3711 return 0;
3712}
3713
3714static int space_addMarkerSpob( int pntid, MissionMarkerType type )
3715{
3716 const char *sys;
3717 MissionMarkerType stype;
3718 Spob *pnt = spob_getIndex( pntid );
3719 if (pnt==NULL)
3720 return -1;
3721
3722 /* Mark spob. */
3723 pnt->markers++;
3724 spob_setFlag( pnt, SPOB_MARKED );
3725
3726 /* Now try to mark system. */
3727 sys = spob_getSystem( pnt->name );
3728 if (sys == NULL) {
3729 WARN(_("Marking spob '%s' that is not in any system!"), pnt->name);
3730 return 0;
3731 }
3732 stype = mission_markerTypeSpobToSystem( type );
3733 return space_addMarkerSystem( system_index( system_get(sys) ), stype );
3734}
3735
3743int space_addMarker( int objid, MissionMarkerType type )
3744{
3745 switch (type) {
3746 case SYSMARKER_COMPUTER:
3747 case SYSMARKER_LOW:
3748 case SYSMARKER_HIGH:
3749 case SYSMARKER_PLOT:
3750 return space_addMarkerSystem( objid, type );
3751 case SPOBMARKER_COMPUTER:
3752 case SPOBMARKER_LOW:
3753 case SPOBMARKER_HIGH:
3754 case SPOBMARKER_PLOT:
3755 return space_addMarkerSpob( objid, type );
3756 default:
3757 WARN(_("Unknown marker type."));
3758 return -1;
3759 }
3760 return 0;
3761}
3762
3763static int space_rmMarkerSystem( int sys, MissionMarkerType type )
3764{
3765 StarSystem *ssys;
3766 int *markers;
3767
3768 /* Get the system. */
3769 ssys = system_getIndex(sys);
3770 if (ssys == NULL)
3771 return -1;
3772
3773 /* Get the marker. */
3774 switch (type) {
3775 case SYSMARKER_COMPUTER:
3776 markers = &ssys->markers_computer;
3777 break;
3778 case SYSMARKER_LOW:
3779 markers = &ssys->markers_low;
3780 break;
3781 case SYSMARKER_HIGH:
3782 markers = &ssys->markers_high;
3783 break;
3784 case SYSMARKER_PLOT:
3785 markers = &ssys->markers_plot;
3786 break;
3787 default:
3788 WARN(_("Unknown marker type."));
3789 return -1;
3790 }
3791
3792 /* Decrement markers. */
3793 (*markers)--;
3794 if (*markers <= 0) {
3795 sys_rmFlag(ssys, SYSTEM_MARKED);
3796 (*markers) = 0;
3797 }
3798
3799 return 0;
3800}
3801
3802static int space_rmMarkerSpob( int pntid, MissionMarkerType type )
3803{
3804 (void) type;
3805 const char *sys;
3806 MissionMarkerType stype;
3807 Spob *pnt = spob_getIndex( pntid );
3808
3809 /* Remove spob marker. */
3810 pnt->markers--;
3811 if (pnt->markers <= 0)
3812 spob_rmFlag( pnt, SPOB_MARKED );
3813
3814 /* Now try to remove system. */
3815 sys = spob_getSystem( pnt->name );
3816 if (sys == NULL)
3817 return 0;
3818 stype = mission_markerTypeSpobToSystem( type );
3819 return space_rmMarkerSystem( system_index( system_get(sys) ), stype );
3820}
3821
3829int space_rmMarker( int objid, MissionMarkerType type )
3830{
3831 switch (type) {
3832 case SYSMARKER_COMPUTER:
3833 case SYSMARKER_LOW:
3834 case SYSMARKER_HIGH:
3835 case SYSMARKER_PLOT:
3836 return space_rmMarkerSystem( objid, type );
3837 case SPOBMARKER_COMPUTER:
3838 case SPOBMARKER_LOW:
3839 case SPOBMARKER_HIGH:
3840 case SPOBMARKER_PLOT:
3841 return space_rmMarkerSpob( objid, type );
3842 default:
3843 WARN(_("Unknown marker type."));
3844 return -1;
3845 }
3846}
3847
3854int space_sysSave( xmlTextWriterPtr writer )
3855{
3856 xmlw_startElem(writer,"space");
3857 for (int i=0; i<array_size(systems_stack); i++) {
3858 StarSystem *sys = &systems_stack[i];
3859
3860 if (!sys_isKnown(sys))
3861 continue; /* not known */
3862
3863 xmlw_startElem(writer,"known");
3864 xmlw_attr(writer,"sys","%s",sys->name);
3865 if (sys_isFlag(sys, SYSTEM_PMARKED))
3866 xmlw_attr(writer,"pmarked","%s","true");
3867 if (sys->note != NULL)
3868 xmlw_attr(writer,"note","%s",sys->note);
3869 for (int j=0; j<array_size(sys->spobs); j++) {
3870 if (!spob_isKnown(sys->spobs[j]))
3871 continue; /* not known */
3872 xmlw_elem(writer, "spob", "%s", sys->spobs[j]->name);
3873 }
3874
3875 for (int j=0; j<array_size(sys->jumps); j++) {
3876 if (!jp_isKnown(&sys->jumps[j]))
3877 continue; /* not known */
3878 xmlw_elem(writer,"jump","%s",(&sys->jumps[j])->target->name);
3879 }
3880
3881 xmlw_endElem(writer);
3882 }
3883 xmlw_endElem(writer); /* "space" */
3884
3885 return 0;
3886}
3887
3894int space_sysLoad( xmlNodePtr parent )
3895{
3896 xmlNodePtr node;
3897
3899
3900 node = parent->xmlChildrenNode;
3901 do {
3902 xmlNodePtr cur;
3903
3904 xml_onlyNodes(node);
3905 if (!xml_isNode(node,"space"))
3906 continue;
3907
3908 cur = node->xmlChildrenNode;
3909 do {
3910 char *str;
3911 StarSystem *sys;
3912
3913 xml_onlyNodes( cur );
3914 if (!xml_isNode(cur,"known"))
3915 continue;
3916
3917 xmlr_attr_strd(cur,"sys",str);
3918 if (str != NULL) { /* check for 0.5.0 saves */
3919 sys = system_get(str);
3920 free(str);
3921 }
3922 else /* load from 0.5.0 saves */
3923 sys = system_get(xml_get(cur));
3924
3925 if (sys != NULL) { /* Must exist */
3926 sys_setFlag(sys,SYSTEM_KNOWN);
3927
3928 xmlr_attr_strd(cur,"pmarked",str);
3929 if (str != NULL) {
3930 sys_setFlag(sys,SYSTEM_PMARKED);
3931 free(str);
3932 }
3933
3934 xmlr_attr_strd(cur,"note",str);
3935 if (str != NULL) {
3936 xmlr_attr_strd(cur,"note",sys->note);
3937 free(str);
3938 }
3939 space_parseSpobs(cur, sys);
3940 }
3941 } while (xml_nextNode(cur));
3942 } while (xml_nextNode(node));
3943
3944 return 0;
3945}
3946
3954static int space_parseSpobs( xmlNodePtr parent, StarSystem* sys )
3955{
3956 xmlNodePtr node = parent->xmlChildrenNode;
3957 do {
3958 if (xml_isNode(node,"spob") || xml_isNode(node,"planet")) { /* TODO remove "planet" check in 0.11.0 */
3959 Spob *spob = spob_get(xml_get(node));
3960 if (spob != NULL) /* Must exist */
3961 spob_setKnown(spob);
3962 }
3963 else if (xml_isNode(node,"jump")) {
3964 JumpPoint *jp = jump_get(xml_get(node), sys);
3965 if (jp != NULL) /* Must exist */
3966 jp_setFlag(jp,JP_KNOWN);
3967 }
3968 } while (xml_nextNode(node));
3969
3970 return 0;
3971}
3972
3981static int getPresenceIndex( StarSystem *sys, int faction )
3982{
3983 int n;
3984
3985 /* Check for NULL and display a warning. */
3986 if (sys == NULL) {
3987 WARN("sys == NULL");
3988 return 0;
3989 }
3990
3991 /* Go through the array (if created), looking for the faction. */
3992 for (int i=0; i < array_size(sys->presence); i++)
3993 if (sys->presence[i].faction == faction)
3994 return i;
3995
3996 /* Grow the array. */
3997 n = array_size(sys->presence);
3998 memset(&array_grow(&sys->presence), 0, sizeof(SystemPresence));
3999 sys->presence[n].faction = faction;
4000
4001 return n;
4002}
4003
4010void system_presenceAddSpob( StarSystem *sys, const SpobPresence *ap )
4011{
4012 int id, curSpill;
4013 Queue q, qn;
4014 double spillfactor;
4015 int faction = ap->faction;
4016 double base = ap->base;
4017 double bonus = ap->bonus;
4018 double range = ap->range;
4019 int usehidden = faction_usesHiddenJumps( faction );
4020 const FactionGenerator *fgens;
4021
4022 /* Check for NULL and display a warning. */
4023 if (sys == NULL) {
4024 WARN("sys == NULL");
4025 return;
4026 }
4027
4028 /* Check that we have a valid faction. */
4029 if (faction_isFaction(faction) == 0)
4030 return;
4031
4032 /* Check that we're actually adding any. */
4033 if ((base == 0.) && (bonus == 0.))
4034 return;
4035
4036 /* Get secondary if applicable. */
4037 fgens = faction_generators( faction );
4038
4039 /* Add the presence to the current system. */
4040 id = getPresenceIndex(sys, faction);
4041 sys->presence[id].base = MAX( sys->presence[id].base, base );
4042 sys->presence[id].bonus += bonus;
4043 sys->presence[id].value = sys->presence[id].base + sys->presence[id].bonus;
4044 for (int i=0; i<array_size(fgens); i++) {
4045 int x = getPresenceIndex(sys, fgens[i].id);
4046 sys->presence[x].base = MAX( sys->presence[x].base, MAX(0., base*fgens[i].weight) );
4047 sys->presence[x].bonus += MAX(0., bonus*fgens[i].weight);
4048 sys->presence[x].value = sys->presence[x].base + sys->presence[x].bonus;
4049 }
4050
4051 /* If there's no range, we're done here. */
4052 if (range < 1)
4053 return;
4054
4055 /* Add the spill. */
4056 sys->spilled = 1;
4057 curSpill = 0;
4058 q = q_create();
4059 qn = q_create();
4060
4061 /* Create the initial queue consisting of sys adjacencies. */
4062 for (int i=0; i < array_size(sys->jumps); i++) {
4063 if (sys->jumps[i].target->spilled == 0 && (usehidden || !jp_isFlag( &sys->jumps[i], JP_HIDDEN )) && !jp_isFlag( &sys->jumps[i], JP_EXITONLY )) {
4064 q_enqueue( q, sys->jumps[i].target );
4065 sys->jumps[i].target->spilled = 1;
4066 }
4067 }
4068
4069 /* If it's empty, something's wrong. */
4070 if (q_isEmpty(q)) {
4071 /* Means system isn't connected. */
4072 /*WARN(_("q is empty after getting adjacencies of %s."), sys->name);*/
4073 q_destroy(q);
4074 q_destroy(qn);
4075 goto sys_cleanup;
4076 return;
4077 }
4078
4079 while (curSpill < range) {
4080 int x;
4081
4082 /* Pull one off the current range queue. */
4083 StarSystem *cur = q_dequeue(q);
4084
4085 /* Ran out of candidates before running out of spill range! */
4086 if (cur == NULL)
4087 break;
4088
4089 /* Enqueue all its adjacencies to the next range queue. */
4090 for (int i=0; i<array_size(cur->jumps); i++) {
4091 if (cur->jumps[i].target->spilled == 0 && (usehidden || !jp_isFlag( &cur->jumps[i], JP_HIDDEN )) && !jp_isFlag( &cur->jumps[i], JP_EXITONLY )) {
4092 q_enqueue( qn, cur->jumps[i].target );
4093 cur->jumps[i].target->spilled = 1;
4094 }
4095 }
4096
4097 /* Spill some presence. */
4098 x = getPresenceIndex(cur, faction);
4099 spillfactor = 1. / (2. + (double)curSpill);
4100 cur->presence[x].base = MAX( cur->presence[x].base, base * spillfactor );
4101 cur->presence[x].bonus += bonus * spillfactor;
4102 cur->presence[x].value = cur->presence[x].base + cur->presence[x].bonus;
4103
4104 for (int i=0; i<array_size(fgens); i++) {
4105 int y = getPresenceIndex(cur, fgens[i].id);
4106 cur->presence[y].base = MAX( cur->presence[y].base, MAX(0., base*spillfactor*fgens[i].weight) );
4107 cur->presence[y].bonus += MAX(0., bonus*spillfactor*fgens[i].weight );
4108 cur->presence[y].value = cur->presence[y].base + cur->presence[y].bonus;
4109 }
4110
4111 /* Check to see if we've finished this range and grab the next queue. */
4112 if (q_isEmpty(q)) {
4113 curSpill++;
4114 q_destroy(q);
4115 q = qn;
4116 qn = q_create();
4117 }
4118 }
4119
4120 /* Destroy the queues. */
4121 q_destroy(q);
4122 q_destroy(qn);
4123
4124sys_cleanup:
4125 /* Clean up our mess. */
4126 for (int i=0; i < array_size(systems_stack); i++)
4127 systems_stack[i].spilled = 0;
4128 return;
4129}
4130
4138double system_getPresence( const StarSystem *sys, int faction )
4139{
4140 /* Check for NULL and display a warning. */
4141#if DEBUGGING
4142 if (sys == NULL) {
4143 WARN("sys == NULL");
4144 return 0;
4145 }
4146#endif /* DEBUGGING */
4147
4148 /* Go through the array, looking for the faction. */
4149 for (int i=0; i < array_size(sys->presence); i++) {
4150 if (sys->presence[i].faction == faction)
4151 return MAX(sys->presence[i].value, 0);
4152 }
4153
4154 /* If it's not in there, it's zero. */
4155 return 0.;
4156}
4157
4167double system_getPresenceFull( const StarSystem *sys, int faction, double *base, double *bonus )
4168{
4169 /* Check for NULL and display a warning. */
4170#if DEBUGGING
4171 if (sys == NULL) {
4172 WARN("sys == NULL");
4173 return 0;
4174 }
4175#endif /* DEBUGGING */
4176
4177 /* Go through the array, looking for the faction. */
4178 for (int i=0; i < array_size(sys->presence); i++) {
4179 if (sys->presence[i].faction == faction) {
4180 *base = sys->presence[i].base;
4181 *bonus = sys->presence[i].bonus;
4182 return MAX(sys->presence[i].value, 0);
4183 }
4184 }
4185
4186 /* If it's not in there, it's zero. */
4187 *base = 0.;
4188 *bonus = 0.;
4189 return 0.;
4190}
4191
4197void system_addAllSpobsPresence( StarSystem *sys )
4198{
4199 /* Check for NULL and display a warning. */
4200#if DEBUGGING
4201 if (sys == NULL) {
4202 WARN("sys == NULL");
4203 return;
4204 }
4205#endif /* DEBUGGING */
4206
4207 /* Real spobs. */
4208 for (int i=0; i<array_size(sys->spobs); i++)
4209 system_presenceAddSpob(sys, &sys->spobs[i]->presence );
4210
4211 /* Virtual spobs. */
4212 for (int i=0; i<array_size(sys->spobs_virtual); i++)
4213 for (int j=0; j<array_size(sys->spobs_virtual[i]->presences); j++)
4214 system_presenceAddSpob(sys, &sys->spobs_virtual[i]->presences[j] );
4215}
4216
4221{
4222 /* Reset the presence in each system. */
4223 for (int i=0; i<array_size(systems_stack); i++) {
4224 array_free(systems_stack[i].presence);
4225 systems_stack[i].presence = array_create( SystemPresence );
4226 systems_stack[i].ownerpresence = 0.;
4227 }
4228
4229 /* Re-add presence to each system. */
4230 for (int i=0; i<array_size(systems_stack); i++)
4232
4233 /* Determine dominant faction. */
4234 for (int i=0; i<array_size(systems_stack); i++) {
4236 systems_stack[i].ownerpresence = system_getPresence( &systems_stack[i], systems_stack[i].faction );
4237 }
4238
4239 /* Have to redo the scheduler because everything changed. */
4240 /* TODO this actually ignores existing presence and will temporarily increase system presence more than normal... */
4241 if (cur_system != NULL)
4242 system_scheduler( 0., 1 );
4243}
4244
4251int system_hasSpob( const StarSystem *sys )
4252{
4253 /* Check for NULL and display a warning. */
4254 if (sys == NULL) {
4255 WARN("sys == NULL");
4256 return 0;
4257 }
4258
4259 /* Go through all the spobs and look for a real one. */
4260 for (int i=0; i < array_size(sys->spobs); i++)
4261 return 1;
4262
4263 return 0;
4264}
4265
4269void system_rmCurrentPresence( StarSystem *sys, int faction, double amount )
4270{
4271 int id;
4272 nlua_env env;
4273 SystemPresence *presence;
4274
4275 /* Remove the presence. */
4276 id = getPresenceIndex( cur_system, faction );
4277 sys->presence[id].curUsed -= amount;
4278
4279 /* Safety. */
4280 presence = &sys->presence[id];
4281 presence->curUsed = MAX( 0, sys->presence[id].curUsed );
4282
4283 /* Run lower hook. */
4284 env = faction_getScheduler( faction );
4285
4286 /* Run decrease function if applicable. */
4287 nlua_getenv( naevL, env, "decrease" ); /* f */
4288 if (lua_isnil(naevL,-1)) {
4289 lua_pop(naevL,1);
4290 return;
4291 }
4292 lua_pushnumber( naevL, presence->curUsed ); /* f, cur */
4293 lua_pushnumber( naevL, presence->value ); /* f, cur, max */
4294 lua_pushnumber( naevL, presence->timer ); /* f, cur, max, timer */
4295
4296 /* Actually run the function. */
4297 if (nlua_pcall(env, 3, 1)) { /* error has occurred */
4298 WARN(_("Lua decrease script for faction '%s' : %s"),
4299 faction_name( faction ), lua_tostring(naevL,-1));
4300 lua_pop(naevL,1);
4301 return;
4302 }
4303
4304 /* Output is handled the same way. */
4305 if (!lua_isnumber(naevL,-1)) {
4306 WARN(_("Lua spawn script for faction '%s' failed to return timer value."),
4307 faction_name( presence->faction ) );
4308 lua_pop(naevL,1);
4309 return;
4310 }
4311 presence->timer = lua_tonumber(naevL,-1);
4312 lua_pop(naevL,1);
4313}
4314
4322{
4323 space_landQueueSpob = pnt;
4324}
4325
4332const char *space_populationStr( uint64_t population )
4333{
4334 static char pop[STRMAX_SHORT];
4335 double p = (double)population;
4336
4337 /* Out of respect for the first version of this, do something fancy and human-oriented.
4338 * However, specifying a thousand/million/billion system failed in a few ways: needing 2x as many cases as
4339 * intended to avoid silliness (1.0e10 -> 10000 million), and not being gettext-translatable to other number
4340 * systems like the Japanese one. */
4341
4342 if (p < 1.0e3)
4343 snprintf( pop, sizeof(pop), "%.0f", p );
4344 else {
4345 char scratch[STRMAX_SHORT];
4346 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"};
4347 int state = 0, COEF = 0, E = 1, EXP = 4;
4348 size_t l = 0;
4349 snprintf( scratch, sizeof(scratch), "%.1e", p );
4350 for (const char *c = scratch; *c; c++) {
4351 if (state == COEF && *c != 'e')
4352 l += scnprintf( &pop[l], sizeof(pop)-l, "%c", *c );
4353 else if (state == COEF ) {
4354 l += scnprintf( &pop[l], sizeof(pop)-l, "%s", "\xc2\xb7" "10" );
4355 state = E;
4356 }
4357 else if (state == E && (*c == '+' || *c == '0'))
4358 state = E;
4359 else {
4360 state = EXP;
4361 l += scnprintf( &pop[l], sizeof(pop)-l, "%s", digits[*c-'0'] );
4362 }
4363 }
4364 }
4365
4366 return pop;
4367}
4368
4375static const MapShader *mapshader_get( const char *name )
4376{
4377 MapShader *ms;
4378
4379 if (mapshaders==NULL)
4381
4382 for (int i=0; i<array_size(mapshaders); i++) {
4383 MapShader *t = mapshaders[i];
4384 if (strcmp(t->name,name)==0)
4385 return t;
4386 }
4387
4388 /* Allocate and set up. */
4389 ms = malloc( sizeof(MapShader) );
4391
4392 ms->name = strdup( name );
4393 ms->program = gl_program_vert_frag( "system_map.vert", name );
4394 ms->vertex = glGetAttribLocation( ms->program, "vertex" );
4395 ms->projection= glGetUniformLocation( ms->program, "projection" );
4396 ms->time = glGetUniformLocation( ms->program, "time" );
4397 ms->globalpos = glGetUniformLocation( ms->program, "globalpos" );
4398 ms->alpha = glGetUniformLocation( ms->program, "alpha" );
4399
4400 return ms;
4401}
4402
4403static int spob_lua_cmp( const void *a, const void *b )
4404{
4405 const spob_lua_file *la = (const spob_lua_file*) a;
4406 const spob_lua_file *lb = (const spob_lua_file*) b;
4407 return strcmp( la->filename, lb->filename );
4408}
4409
4410static nlua_env spob_lua_get( int *mem, const char *filename )
4411{
4412 size_t sz;
4413 char *dat;
4414 spob_lua_file *lf;
4415 const spob_lua_file key = { .filename=filename };
4416
4417 if (spob_lua_stack == NULL)
4419
4420 lf = bsearch( &key, spob_lua_stack, array_size(spob_lua_stack), sizeof(spob_lua_file), spob_lua_cmp );
4421 if (lf != NULL) {
4422 *mem = lf->lua_mem;
4423 return lf->env;
4424 }
4425
4426 dat = ndata_read( filename, &sz );
4427 if (dat==NULL) {
4428 WARN(_("Failed to read spob Lua '%s'!"), filename );
4429 return LUA_NOREF;
4430 }
4431
4432 nlua_env env = nlua_newEnv();
4433 nlua_loadStandard( env );
4434 nlua_loadGFX( env );
4435 nlua_loadCamera( env );
4436
4437 /* Add new entry and sort. */
4438 lf = &array_grow( &spob_lua_stack );
4439 lf->filename = strdup( filename );
4440 lf->env = env;
4441
4442 /* Add the spob memory table. */
4443 lua_newtable(naevL); /* m */
4444 lua_pushvalue(naevL, -1); /* m, m */
4445 lf->lua_mem = luaL_ref( naevL, LUA_REGISTRYINDEX ); /* m */
4446 nlua_setenv(naevL, env, "mem"); /* */
4447 *mem = lf->lua_mem;
4448
4449 if (nlua_dobufenv(env, dat, sz, filename) != 0) {
4450 int n;
4451 WARN(_("Lua Spob '%s' error:\n%s"), filename, lua_tostring(naevL,-1));
4452 lua_pop(naevL,1);
4453 spob_lua_free( lf );
4454 free( dat );
4457 return LUA_NOREF;
4458 }
4459 free(dat);
4460
4461 qsort( spob_lua_stack, array_size(spob_lua_stack), sizeof(spob_lua_file), spob_lua_cmp );
4462 return env;
4463}
4464
4465static void spob_lua_free( spob_lua_file *lf )
4466{
4467 free( (char *) lf->filename );
4468 nlua_freeEnv( lf->env );
4469 luaL_unref( naevL, LUA_REGISTRYINDEX, lf->lua_mem );
4470}
#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:785
void asteroids_computeInternals(AsteroidAnchor *a)
Updates internal alues of an asteroid field.
Definition: asteroid.c:407
void asteroids_free(void)
Cleans up the system.
Definition: asteroid.c:902
int asteroids_load(void)
Loads the asteroids.
Definition: asteroid.c:429
void asteroid_free(AsteroidAnchor *ast)
Frees an asteroid anchor.
Definition: asteroid.c:891
AsteroidTypeGroup * astgroup_getName(const char *name)
Gets an asteroid type group by name.
Definition: asteroid.c:1014
void asteroids_init(void)
Initializes the system.
Definition: asteroid.c:238
void asteroids_renderOverlay(void)
Renders the system overlay.
Definition: asteroid.c:767
void asteroids_update(double dt)
Controls fleet spawning.
Definition: asteroid.c:74
void background_clear(void)
Cleans up the background stuff.
Definition: background.c:509
void background_initDust(int n)
Initializes background stars.
Definition: background.c:90
void background_renderOverlay(double dt)
Renders the background overlay.
Definition: background.c:287
void background_render(double dt)
Render the background.
Definition: background.c:249
int background_load(const char *name)
Loads a background script by name.
Definition: background.c:447
int dtype_get(const char *name)
Gets the id of a dtype based on name.
Definition: damagetype.c:144
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:1246
int areEnemies(int a, int b)
Checks whether two factions are enemies.
Definition: faction.c:1197
void factions_clearDynamic(void)
Clears dynamic factions.
Definition: faction.c:1858
const char * faction_name(int f)
Gets a factions "real" (internal) name.
Definition: faction.c:304
const FactionGenerator * faction_generators(int f)
Gets the faction's generators.
Definition: faction.c:1848
int faction_usesHiddenJumps(int f)
Checks to see if a faction uses hidden jumps.
Definition: faction.c:1838
nlua_env faction_getScheduler(int f)
Gets the state associated to the faction scheduler.
Definition: faction.c:726
int faction_get(const char *name)
Gets a faction ID by name.
Definition: faction.c:182
int areAllies(int a, int b)
Checks whether two factions are allies or not.
Definition: faction.c:1222
void gatherable_free(void)
Frees all the gatherables.
Definition: gatherable.c:99
void gatherable_update(double dt)
Updates all gatherable objects.
Definition: gatherable.c:77
void gatherable_render(void)
Renders all the gatherables.
Definition: gatherable.c:107
void gui_setSystem(void)
Player just changed their system.
Definition: gui.c:1773
void gui_updateFaction(void)
Player's relationship with a faction was modified.
Definition: gui.c:1781
void player_message(const char *fmt,...)
Adds a mesg to the queue to be displayed on screen.
Definition: gui.c:330
void player_messageToggle(int enable)
Toggles if player should receive messages.
Definition: gui.c:283
int hooks_runParam(const char *stack, const HookParam *param)
Runs all the hooks of stack.
Definition: hook.c:967
void land(Spob *p, int load)
Opens up all the land dialogue stuff.
Definition: land.c:1201
Handles the important game menus.
#define MENU_MAIN
Definition: menu.h:9
#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:413
void naev_renderLoadscreen(void)
Renders the loadscreen if necessary.
Definition: naev.c:549
void update_routine(double dt, int enter_sys)
Actually runs the updates.
Definition: naev.c:998
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:366
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition: ndata.c:232
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
static char buf[NEWS_MAX_LENGTH]
Definition: news.c:45
int nlua_loadStandard(nlua_env env)
Loads the standard Naev Lua API.
Definition: nlua.c:760
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:873
int nlua_loadCamera(nlua_env env)
Loads the camera library.
Definition: nlua_camera.c:47
int nlua_loadGFX(nlua_env env)
Loads the graphics library.
Definition: nlua_gfx.c:97
LuaPilot lua_topilot(lua_State *L, int ind)
Lua bindings to interact with pilots.
Definition: nlua_pilot.c:453
int lua_ispilot(lua_State *L, int ind)
Checks to see if ind is a pilot.
Definition: nlua_pilot.c:510
LuaSpob * lua_pushspob(lua_State *L, LuaSpob spob)
Pushes a spob on the stack.
Definition: nlua_spob.c:192
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:70
char * strcasestr(const char *haystack, const char *needle)
Finds a string inside another string case insensitively.
Definition: nstring.c:68
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:178
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:809
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:684
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition: opengl_tex.c:570
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:857
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition: opengl_tex.c:755
void pilots_clean(int persist)
Cleans up the pilot stack - leaves the player.
Definition: pilot.c:3555
void pilot_clearTimers(Pilot *pilot)
Clears the pilot's timers.
Definition: pilot.c:3767
Pilot * pilot_get(unsigned int id)
Pulls a pilot out of the pilot_stack based on ID.
Definition: pilot.c:589
static Pilot ** pilot_stack
Definition: pilot.c:57
Pilot *const * pilot_getAll(void)
Gets the pilot stack.
Definition: pilot.c:83
void pilots_newSystem(void)
Updates pilot state which depends on the system (sensor range, nebula trails...)
Definition: pilot.c:3614
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:1381
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:277
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:342
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:307
void pilot_calcStats(Pilot *pilot)
Recalculates the pilot's stats based on his outfits.
Definition: pilot_outfit.c:877
void pilot_lockClear(Pilot *p)
Clears pilot's missile lockon timers.
Definition: pilot_outfit.c:121
void player_checkLandAck(void)
Revokes landing authorization if the player's reputation is too low.
Definition: player.c:1703
void player_clear(void)
Clears the targets.
Definition: player.c:919
Player_t player
Definition: player.c:73
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 a[]
Definition: rng.c:247
static const double d[]
Definition: rng.c:273
void ss_free(ShipStatList *ll)
Frees a list of ship stats.
Definition: shipstats.c:807
ShipStatList * ss_listFromXML(xmlNodePtr node)
Creates a shipstat list element from an xml node.
Definition: shipstats.c:209
int ss_sort(ShipStatList **ll)
Sorts the ship stats, useful if doing saving stuff.
Definition: shipstats.c:298
int sound_disabled
Definition: sound.c:133
int sound_env(SoundEnv_t env_type, double param)
Sets up the sound environment.
Definition: sound.c:1660
static int spob_cmp(const void *p1, const void *p2)
Comparison function for qsort'ing Spob by name.
Definition: space.c:992
void space_reconstructPresences(void)
Reset the presence of all systems.
Definition: space.c:4220
void space_init(const char *sysname, int do_simulate)
Initializes the system.
Definition: space.c:1501
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:734
int system_addJumpDiff(StarSystem *sys, xmlNodePtr node)
Adds a jump point to a star system from a diff.
Definition: space.c:2531
static int spobs_load(void)
Loads all the spobs in the game.
Definition: space.c:1717
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:299
static int system_cmp(const void *p1, const void *p2)
Comparison function for qsort'ing StarSystem by name.
Definition: space.c:900
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:655
int spob_exists(const char *spobname)
Check to see if a spob exists.
Definition: space.c:1082
void system_rmCurrentPresence(StarSystem *sys, int faction, double amount)
Removes active presence.
Definition: space.c:4269
void space_gfxUnload(StarSystem *sys)
Unloads all the graphics for a star system.
Definition: space.c:2068
#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:437
void space_render(const double dt)
Renders the system.
Definition: space.c:3395
static void space_renderSpob(const Spob *p)
Renders a spob.
Definition: space.c:3482
static int sys_cmpSysFaction(const void *a, const void *b)
Compares two system presences.
Definition: space.c:2990
int spob_luaInit(Spob *spob)
Updatse the spob's internal Lua stuff.
Definition: space.c:1942
static void system_init(StarSystem *sys)
Initializes a new star system with null memory.
Definition: space.c:2586
void systems_reconstructJumps(void)
Reconstructs the jumps.
Definition: space.c:2671
int space_jumpDistance(const Pilot *p, const JumpPoint *jp)
Distance at which a pilot can jump.
Definition: space.c:423
const glColour * spob_getColour(const Spob *p)
Gets the spob colour.
Definition: space.c:1875
int space_rmMarker(int objid, MissionMarkerType type)
Removes a marker from a system.
Definition: space.c:3829
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:312
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:4167
int space_isSimulationEffects(void)
returns whether or not we're simulating with effects.
Definition: space.c:1490
static int spob_parse(Spob *spob, const char *filename, Commodity **stdList)
Parses a spob from an xml node.
Definition: space.c:2119
Spob * spob_getAll(void)
Gets an array (array.h) of all spobs.
Definition: space.c:1063
int space_sysLoad(xmlNodePtr parent)
Loads player's space properties from an XML node.
Definition: space.c:3894
int space_sysReallyReachable(char *sysname)
Sees if a system can be reached via jumping.
Definition: space.c:814
#define XML_SPOB_TAG
Definition: space.c:61
int spob_getService(const char *name)
Converts name to spob service flag.
Definition: space.c:184
void system_setFaction(StarSystem *sys)
Sets the system faction based on the spobs it has.
Definition: space.c:3017
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
Definition: space.c:1006
void space_factionChange(void)
Mark when a faction changes.
Definition: space.c:1344
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:2466
static int system_parseJumpPointDiff(const xmlNodePtr node, StarSystem *sys)
Parses a single jump point for a system, from unidiff.
Definition: space.c:3044
const char * space_getRndSpob(int landable, unsigned int services, int(*filter)(Spob *p))
Gets the name of a random spob.
Definition: space.c:601
int system_rmJump(StarSystem *sys, const char *jumpname)
Removes a jump point from a star system.
Definition: space.c:2550
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:1366
static int systems_load(void)
Loads the entire systems, needs to be called after spobs_load.
Definition: space.c:3324
StarSystem * system_getIndex(int id)
Get the system by its index.
Definition: space.c:944
int spob_index(const Spob *p)
Gets the ID of a spob.
Definition: space.c:1055
int spob_hasSystem(const Spob *spb)
Get whether or not a spob has a system (i.e. is on the map).
Definition: space.c:966
static int space_simulating
Definition: space.c:109
#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:1212
const char * spob_getSymbol(const Spob *p)
Gets the spob symbol.
Definition: space.c:1853
void space_renderOverlay(const double dt)
Renders the system overlay.
Definition: space.c:3411
int spob_setFaction(Spob *p, int faction)
Changes the spobs faction.
Definition: space.c:345
char spob_getColourChar(const Spob *p)
Gets the spob colour char.
Definition: space.c:1834
StarSystem * system_new(void)
Creates a new star system.
Definition: space.c:2601
static glTexture * jumpbuoy_gfx
Definition: space.c:107
int space_sysReachable(const StarSystem *sys)
Sees if a system is reachable.
Definition: space.c:794
JumpPoint * jump_getTarget(const StarSystem *target, const StarSystem *sys)
Less safe version of jump_get that works with pointers.
Definition: space.c:1198
const char * system_existsCase(const char *sysname)
Checks to see if a system exists case insensitively.
Definition: space.c:858
StarSystem * system_getAll(void)
Gets an array (array.h) of all star systems.
Definition: space.c:847
char ** spob_searchFuzzyCase(const char *spobname, int *n)
Does a fuzzy case matching. Searches spob_name() but returns internal names.
Definition: space.c:1107
int space_sysSave(xmlTextWriterPtr writer)
Saves what is needed to be saved for space.
Definition: space.c:3854
int space_sysReachableFromSys(const StarSystem *target, const StarSystem *sys)
Sees if a system is reachable from another system.
Definition: space.c:833
char ** system_searchFuzzyCase(const char *sysname, int *n)
Does a fuzzy case matching. Searches translated names but returns internal names.
Definition: space.c:869
StarSystem * system_get(const char *sysname)
Get the system from its name.
Definition: space.c:914
char * spob_getSystem(const char *spobname)
Get the name of a system from a spobname.
Definition: space.c:980
int space_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:495
int spob_rmService(Spob *p, int service)
Removes a service from a spob.
Definition: space.c:414
static MapShader ** mapshaders
Definition: space.c:99
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:322
void spob_setKnown(Spob *p)
Sets a spob's known status, if it's real.
Definition: space.c:1071
static void system_scheduler(double dt, int init)
Controls fleet spawning.
Definition: space.c:1225
void spobs_render(void)
Renders the current systems' spobs.
Definition: space.c:3430
StarSystem * cur_system
Definition: space.c:105
const char * spob_existsCase(const char *spobname)
Check to see if a spob exists (case insensitive).
Definition: space.c:1096
int system_addSpob(StarSystem *sys, const char *spobname)
Adds a spob to a star system.
Definition: space.c:2372
void space_exit(void)
Cleans up the system.
Definition: space.c:3518
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:3981
int space_addMarker(int objid, MissionMarkerType type)
Adds a marker to a system.
Definition: space.c:3743
static int spob_parsePresence(xmlNodePtr node, SpobPresence *ap)
Parsess an spob presence from xml.
Definition: space.c:2093
double system_getPresence(const StarSystem *sys, int faction)
Get the presence of a faction in a system.
Definition: space.c:4138
void spob_updateLand(Spob *p)
Updates the land possibilities of a spob.
Definition: space.c:1896
static int space_simulating_effects
Definition: space.c:110
static void space_renderJumpPoint(const JumpPoint *jp, int i)
Renders a jump point.
Definition: space.c:3455
void spob_gfxLoad(Spob *spob)
Loads a spob's graphics (and radius).
Definition: space.c:2019
int system_rmVirtualSpob(StarSystem *sys, const char *spobname)
Removes a virtual spob from a system.
Definition: space.c:2490
void space_clearMarkers(void)
Clears all system markers.
Definition: space.c:3652
static int virtualspobs_load(void)
Loads all the virtual spobs.
Definition: space.c:1763
VirtualSpob * virtualspob_getAll(void)
Gets all the virtual spobs.
Definition: space.c:1138
Spob * spob_getIndex(int ind)
Gets spob by index.
Definition: space.c:1038
void system_presenceAddSpob(StarSystem *sys, const SpobPresence *ap)
Adds (or removes) some presence to a system.
Definition: space.c:4010
VirtualSpob * virtualspob_get(const char *name)
Gets a virtual spob by matching name.
Definition: space.c:1157
static int space_parseSpobs(xmlNodePtr parent, StarSystem *sys)
Parses spobs in a system.
Definition: space.c:3954
void space_clearKnown(void)
Clears all system knowledge.
Definition: space.c:3633
StarSystem * systems_stack
Definition: space.c:92
static int space_fchg
Definition: space.c:108
void system_addAllSpobsPresence(StarSystem *sys)
Go through all the spobs and call system_addPresence().
Definition: space.c:4197
int spob_addCommodity(Spob *p, Commodity *c)
Adds a commodity to a spob.
Definition: space.c:358
static int system_parseJumps(StarSystem *sys)
Loads the jumps into a system.
Definition: space.c:3200
const char * space_populationStr(uint64_t population)
Gets the population in an approximated string. Note this function changes the string value each call,...
Definition: space.c:4332
static const MapShader * mapshader_get(const char *name)
Gets the map shader by name.
Definition: space.c:4375
int system_hasSpob(const StarSystem *sys)
See if the system has a spob.
Definition: space.c:4251
int spob_addService(Spob *p, int service)
Removes a service from a spob.
Definition: space.c:372
static int systems_loading
Definition: space.c:104
const char * spob_name(const Spob *p)
Gets the translated name of a spob.
Definition: space.c:1705
static int virtualspob_cmp(const void *p1, const void *p2)
Comparison function for qsort'ing VirtuaSpob by name.
Definition: space.c:1146
const char * spob_getClassName(const char *class)
Gets the long class name for a spob.
Definition: space.c:213
static int system_parseAsteroidExclusion(const xmlNodePtr node, StarSystem *sys)
Parses a single asteroid exclusion zone for a system.
Definition: space.c:2777
void space_clearComputerMarkers(void)
Clears all the system computer markers.
Definition: space.c:3672
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:4321
static void space_updateSpob(const Spob *p, double dt, double real_dt)
Renders a spob.
Definition: space.c:3500
char ** space_getFactionSpob(int *factions, int landable)
Gets the name of all the spobs that belong to factions.
Definition: space.c:558
int space_spawn
Definition: space.c:116
static int system_parseAsteroidField(const xmlNodePtr node, StarSystem *sys)
Parses a single asteroid field for a system.
Definition: space.c:2699
credits_t spob_commodityPrice(const Spob *p, const Commodity *c)
Gets the price of a commodity at a spob.
Definition: space.c:272
const char * spob_getServiceName(int service)
Gets the (English) name for a service code.
Definition: space.c:165
void systems_reconstructSpobs(void)
Updates the system spob pointers.
Definition: space.c:2683
Spob * spob_new(void)
Creates a new spob.
Definition: space.c:1659
#define FLAG_FACTIONSET
Definition: space.c:71
void spob_luaInitMem(const Spob *spob)
Initializes the memory fo a spob.
Definition: space.c:1931
JumpPoint * jump_get(const char *jumpname, const StarSystem *sys)
Gets a jump point based on its target and system.
Definition: space.c:1174
void space_checkLand(void)
Handles landing if necessary.
Definition: space.c:1352
glTexture * jumppoint_gfx
Definition: space.c:106
void space_gfxLoad(StarSystem *sys)
Loads all the graphics for a star system.
Definition: space.c:2057
int space_hyperspace(Pilot *p)
Tries to get the pilot into hyperspace.
Definition: space.c:471
int space_load(void)
Loads the entire universe into ram - pretty big feat eh?
Definition: space.c:3237
int space_isSimulation(void)
returns whether we're just simulating.
Definition: space.c:1482
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:286
int system_index(const StarSystem *sys)
Gets the index of a star system.
Definition: space.c:955
int system_rmSpob(StarSystem *sys, const char *spobname)
Removes a spob from a star system.
Definition: space.c:2411
int space_loadLua(void)
initializes the Lua for all the spobs.
Definition: space.c:3306
static int system_parseJumpPoint(const xmlNodePtr node, StarSystem *sys)
Parses a single jump point for a system.
Definition: space.c:3116
static int system_parse(StarSystem *system, const char *filename)
Creates a system from an XML node.
Definition: space.c:2827
void system_reconstructJumps(StarSystem *sys)
Reconstructs the jumps for a single system.
Definition: space.c:2640
#define FLAG_SERVICESSET
Definition: space.c:70
void spfx_clear(void)
Clears all the currently running effects.
Definition: spfx.c:509
const char * start_spob_lua_default(void)
Gets the default spob Lua file.
Definition: start.c:266
Represents an asteroid field anchor.
Definition: asteroid.h:100
double area
Definition: asteroid.h:108
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:121
Represents a group of asteroids.
Definition: asteroid.h:66
Represents a single asteroid.
Definition: asteroid.h:76
int state
Definition: asteroid.h:80
vec2 pos
Definition: asteroid.h:86
Represents a commodity.
Definition: commodity.h:43
Core damage that an outfit does.
Definition: outfit.h:111
int type
Definition: outfit.h:112
double disable
Definition: outfit.h:115
double penetration
Definition: outfit.h:113
double damage
Definition: outfit.h:114
The actual hook parameter.
Definition: hook.h:35
const char * str
Definition: hook.h:39
union HookParam::@4 u
HookParamType type
Definition: hook.h:36
LuaSpob la
Definition: hook.h:43
LuaJump lj
Definition: hook.h:44
int destid
Definition: nlua_jump.h:16
int srcid
Definition: nlua_jump.h:15
Map shader.
Definition: space.h:219
char * name
Definition: space.h:220
GLuint time
Definition: space.h:225
GLuint globalpos
Definition: space.h:226
GLuint projection
Definition: space.h:223
GLuint alpha
Definition: space.h:224
GLuint program
Definition: space.h:221
GLuint vertex
Definition: space.h:222
The representation of an in-game pilot.
Definition: pilot.h:210
int presence
Definition: pilot.h:216
int nav_hyperspace
Definition: pilot.h:337
int faction
Definition: pilot.h:215
int nav_spob
Definition: pilot.h:336
int devmode
Definition: conf.h:158
Pilot * p
Definition: player.h:101
int discover_off
Definition: player.h:118
Represents relative ship statistics as a linked list.
Definition: shipstats.h:167
struct ShipStatList_ * next
Definition: shipstats.h:168
Represents the presence of a spob.
Definition: space.h:65
double bonus
Definition: space.h:68
int range
Definition: space.h:69
double base
Definition: space.h:67
int faction
Definition: space.h:66
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition: space.h:88
int can_land
Definition: space.h:106
Commodity ** commodities
Definition: space.h:114
glTexture * gfx_space
Definition: space.h:119
char * land_msg
Definition: space.h:108
unsigned int services
Definition: space.h:113
int lua_update
Definition: space.h:142
int land_override
Definition: space.h:107
char * gfx_spacePath
Definition: space.h:121
char * gfx_spaceName
Definition: space.h:120
int lua_land
Definition: space.h:140
double radius
Definition: space.h:94
int markers
Definition: space.h:130
char * feature
Definition: space.h:92
char * bar_description
Definition: space.h:112
int lua_comm
Definition: space.h:143
int lua_render
Definition: space.h:141
const SimpleShader * marker
Definition: space.h:95
char * description
Definition: space.h:111
char * class
Definition: space.h:98
char ** tags
Definition: space.h:126
int lua_mem
Definition: space.h:135
int lua_init
Definition: space.h:136
int lua_load
Definition: space.h:137
tech_group_t * tech
Definition: space.h:116
double map_alpha
Definition: space.h:129
uint64_t population
Definition: space.h:99
char * gfx_exterior
Definition: space.h:122
nlua_env lua_env
Definition: space.h:134
char * name
Definition: space.h:90
char * gfx_exteriorPath
Definition: space.h:123
vec2 pos
Definition: space.h:93
int id
Definition: space.h:89
CommodityPrice * commodityPrice
Definition: space.h:115
double hide
Definition: space.h:103
int lua_can_land
Definition: space.h:139
int lua_unload
Definition: space.h:138
SpobPresence presence
Definition: space.h:102
char * display
Definition: space.h:91
unsigned int flags
Definition: space.h:127
Represents presence in a system.
Definition: space.h:169
double curUsed
Definition: space.h:174
double value
Definition: space.h:173
double timer
Definition: space.h:175
int faction
Definition: space.h:170
Basically modifies system parameters without creating any real objects.
Definition: space.h:77
SpobPresence * presences
Definition: space.h:79
char * name
Definition: space.h:78
Abstraction for rendering sprite sheets.
Definition: opengl_tex.h:34
double w
Definition: opengl_tex.h:38
double sx
Definition: opengl_tex.h:42
double h
Definition: opengl_tex.h:39
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:162
void tech_groupDestroy(tech_group_t *grp)
Frees a tech group.
Definition: tech.c:182
void weapon_clear(void)
Clears all the weapons, does NOT free the layers.
Definition: weapon.c:2161