1060 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1060 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <malloc.h>
 | |
| #include <math.h>
 | |
| 
 | |
| #include "xml.h"
 | |
| #include "lephisto.h"
 | |
| #include "opengl.h"
 | |
| #include "log.h"
 | |
| #include "physics.h"
 | |
| #include "rng.h"
 | |
| #include "pack.h"
 | |
| #include "space.h"
 | |
| #include "faction.h"
 | |
| #include "xml.h"
 | |
| #include "pause.h"
 | |
| #include "weapon.h"
 | |
| #include "toolkit.h"
 | |
| #include "spfx.h"
 | |
| #include "ltime.h"
 | |
| #include "nebulae.h"
 | |
| #include "player.h"
 | |
| 
 | |
| #define XML_PLANET_ID       "Planets"
 | |
| #define XML_PLANET_TAG      "planet"
 | |
| 
 | |
| #define XML_SYSTEM_ID       "Systems"
 | |
| #define XML_SYSTEM_TAG      "ssys"
 | |
| 
 | |
| #define PLANET_DATA         "../dat/planet.xml"
 | |
| #define SYSTEM_DATA         "../dat/ssys.xml"
 | |
| 
 | |
| #define PLANET_GFX_SPACE    "../gfx/planet/space/"
 | |
| #define PLANET_GFX_EXTERIOR "../gfx/planet/exterior/"
 | |
| 
 | |
| #define PLANET_GFX_EXTERIOR_W 400
 | |
| #define PLANET_GFX_EXTERIOR_H 400
 | |
| 
 | |
| /* Overcome warning due to zero value. */
 | |
| 
 | |
| #define FLAG_XSET           (1<<0)
 | |
| #define FLAG_YSET           (1<<1)
 | |
| #define FLAG_ASTEROIDSSET   (1<<2)
 | |
| #define FLAG_INTEFERENCESET (1<<3)
 | |
| #define FLAG_SERVICESET     (1<<4)
 | |
| #define FLAG_TECHSET        (1<<5)
 | |
| #define FLAG_FACTIONSET     (1<<6)
 | |
| 
 | |
| /* Planet <-> system name stack. */
 | |
| static char** planetname_stack  = NULL;
 | |
| static char** systemname_stack  = NULL;
 | |
| static int    spacename_nstack  = 0;
 | |
| 
 | |
| /* Star system stack and co. */
 | |
| StarSystem* systems_stack = NULL;   /* Star system stack. */
 | |
| int systems_nstack        = 0;      /* Number of star systems. */
 | |
| static int  total_planets = 0;      /* Total number of loaded planets - A little silly. */
 | |
| StarSystem* cur_system    = NULL;   /* Current star system. */
 | |
| 
 | |
| /* Fleet spawn rate. */
 | |
| unsigned int spawn_timer = 0; /* Controls spawn rate. */
 | |
| 
 | |
| /* Star stack and co. */
 | |
| #define STAR_BUF 100 /* Area to leave around screen, more = less repitition. */
 | |
| typedef struct Star_ {
 | |
|   double x, y; /* Position. It is simpler ligher to use two doubles than the physics. */
 | |
|   double brightness;
 | |
| } Star;
 | |
| 
 | |
| static Star* stars = NULL;  /* Star array. */
 | |
| static int nstars = 0;      /* Total stars. */
 | |
| static int mstars = 0;      /* Memory stars are taking. */
 | |
| 
 | |
| /* Intern. */
 | |
| static Planet* planet_pull(const char* name);
 | |
| static void space_renderStars(const double dt);
 | |
| static void space_addFleet(Fleet* fleet);
 | |
| static StarSystem* system_parse(const xmlNodePtr parent);
 | |
| static void system_parseJumps(const xmlNodePtr parent);
 | |
| static PlanetClass planetclass_get(const char a);
 | |
| /* Extern. */
 | |
| extern void player_message(const char* fmt, ...);
 | |
| void planets_minimap(const double res, const double w,
 | |
|     const double h, const RadarShape shape);
 | |
| int space_sysSave(xmlTextWriterPtr writer);
 | |
| int space_sysLoad(xmlNodePtr parent);
 | |
| 
 | |
| /* Draw the planet. Used in planet.c */
 | |
| /* Matrix mode is already displaced to center of the minimap. */
 | |
| #define PIXEL(x,y)  if((shape == RADAR_RECT && ABS(x)<w/2. && ABS(y)<h/2.) || \
 | |
|   (shape == RADAR_CIRCLE && (((x)*(x)+(y)*(y)) < rc))) glVertex2i((x),(y))
 | |
| void planets_minimap(const double res, const double w,
 | |
|     const double h, const RadarShape shape) {
 | |
|   int i;
 | |
|   int cx, cy, x, y, r, rc;
 | |
|   double p;
 | |
|   Planet* planet;
 | |
|   glColour* col;
 | |
| 
 | |
|   if(shape == RADAR_CIRCLE) rc = (int)(w*w);
 | |
| 
 | |
|   glBegin(GL_POINTS);
 | |
|   for(i = 0; i < cur_system->nplanets; i++) {
 | |
|     planet = &cur_system->planets[i];
 | |
| 
 | |
|     col = faction_getColour(planet->faction);
 | |
|     if((col != &cHostile) && !planet_hasService(planet, PLANET_SERVICE_BASIC))
 | |
|       col = &cInert;  /* Override non-hostile planets without services. */
 | |
|     COLOUR(*col);
 | |
| 
 | |
|     r = (int)(cur_system->planets[i].gfx_space->sw / res);
 | |
|     cx = (int)((cur_system->planets[i].pos.x - player->solid->pos.x) / res);
 | |
|     cy = (int)((cur_system->planets[i].pos.y - player->solid->pos.y) / res);
 | |
| 
 | |
|     x = 0;
 | |
|     y = r;
 | |
|     p = (5. - (double)(r*3)) / 4.;
 | |
| 
 | |
|     PIXEL(cx,   cy+y);
 | |
|     PIXEL(cx,   cy-y);
 | |
|     PIXEL(cx+y, cy);
 | |
|     PIXEL(cx-y, cy);
 | |
| 
 | |
|     while(x < y) {
 | |
|       x++;
 | |
|       if(p < 0) p += 2*(double)(x)+1;
 | |
|       else p += 2*(double)(x-(--y))+1;
 | |
| 
 | |
|       if(x == 0) {
 | |
|         PIXEL(cx,   cy+y);
 | |
|         PIXEL(cx,   cy-y);
 | |
|         PIXEL(cx+y, cy);
 | |
|         PIXEL(cx-y, cy);
 | |
|       } else
 | |
|         if(x == y) {
 | |
|           PIXEL(cx+x, cy+y);
 | |
|           PIXEL(cx-x, cy+y);
 | |
|           PIXEL(cx+x, cy-y);
 | |
|           PIXEL(cx-x, cy-y);
 | |
|         } else
 | |
|           if(x < y) {
 | |
|             PIXEL(cx+x, cy+y);
 | |
|             PIXEL(cx-x, cy+y);
 | |
|             PIXEL(cx+x, cy-y);
 | |
|             PIXEL(cx-x, cy-y);
 | |
|             PIXEL(cx+y, cy+x);
 | |
|             PIXEL(cx-y, cy+x);
 | |
|             PIXEL(cx+y, cy-x);
 | |
|             PIXEL(cx-y, cy-x);
 | |
|           }
 | |
|     }
 | |
|   }
 | |
|   glEnd();
 | |
| }
 | |
| #undef PIXEL
 | |
| 
 | |
| /* Basically return a PlanetClass integer from a char. */
 | |
| static PlanetClass planetclass_get(const char a) {
 | |
|   switch(a) {
 | |
|     /* Planets use letters. */
 | |
|     case 'A': return PLANET_CLASS_A;
 | |
|     case 'B': return PLANET_CLASS_B;
 | |
|     case 'C': return PLANET_CLASS_C;
 | |
|     case 'D': return PLANET_CLASS_D;
 | |
|     case 'E': return PLANET_CLASS_E;
 | |
|     case 'F': return PLANET_CLASS_F;
 | |
|     case 'G': return PLANET_CLASS_G;
 | |
|     case 'H': return PLANET_CLASS_H;
 | |
|     case 'I': return PLANET_CLASS_I;
 | |
|     case 'J': return PLANET_CLASS_J;
 | |
|     case 'K': return PLANET_CLASS_K;
 | |
|     case 'L': return PLANET_CLASS_L;
 | |
|     case 'M': return PLANET_CLASS_M;
 | |
|     case 'N': return PLANET_CLASS_N;
 | |
|     case 'O': return PLANET_CLASS_O;
 | |
|     case 'P': return PLANET_CLASS_P;
 | |
|     case 'Q': return PLANET_CLASS_Q;
 | |
|     case 'R': return PLANET_CLASS_R;
 | |
|     case 'S': return PLANET_CLASS_S;
 | |
|     case 'T': return PLANET_CLASS_T;
 | |
|     case 'X': return PLANET_CLASS_X;
 | |
|     case 'Y': return PLANET_CLASS_Y;
 | |
|     case 'Z': return PLANET_CLASS_Z;
 | |
| 
 | |
|     /* Stations use numbers as there isn't as many. */
 | |
|     case '0' : return STATION_CLASS_A;
 | |
|     case '1' : return STATION_CLASS_B;
 | |
|     case '2' : return STATION_CLASS_C;
 | |
|     case '3' : return STATION_CLASS_D;
 | |
| 
 | |
|     default:
 | |
|       WARN("Invalid planet class.");
 | |
|       return PLANET_CLASS_NULL;
 | |
|   };
 | |
| }
 | |
| 
 | |
| char planet_getClass(Planet* p) {
 | |
|   switch(p->class) {
 | |
|     case PLANET_CLASS_A: return 'A';
 | |
|     case PLANET_CLASS_B: return 'B';
 | |
|     case PLANET_CLASS_C: return 'C';
 | |
|     case PLANET_CLASS_D: return 'D';
 | |
|     case PLANET_CLASS_E: return 'E';
 | |
|     case PLANET_CLASS_F: return 'F';
 | |
|     case PLANET_CLASS_G: return 'G';
 | |
|     case PLANET_CLASS_H: return 'H';
 | |
|     case PLANET_CLASS_I: return 'I';
 | |
|     case PLANET_CLASS_J: return 'J';
 | |
|     case PLANET_CLASS_K: return 'K';
 | |
|     case PLANET_CLASS_L: return 'L';
 | |
|     case PLANET_CLASS_M: return 'M';
 | |
|     case PLANET_CLASS_N: return 'N';
 | |
|     case PLANET_CLASS_O: return 'O';
 | |
|     case PLANET_CLASS_P: return 'P';
 | |
|     case PLANET_CLASS_Q: return 'Q';
 | |
|     case PLANET_CLASS_R: return 'R';
 | |
|     case PLANET_CLASS_S: return 'S';
 | |
|     case PLANET_CLASS_T: return 'T';
 | |
|     case PLANET_CLASS_X: return 'X';
 | |
|     case PLANET_CLASS_Y: return 'Y';
 | |
|     case PLANET_CLASS_Z: return 'Z';
 | |
| 
 | |
|     /* Stations. */
 | |
|     case STATION_CLASS_A: return '0';
 | |
|     case STATION_CLASS_B: return '1';
 | |
|     case STATION_CLASS_C: return '2';
 | |
|     case STATION_CLASS_D: return '3';
 | |
| 
 | |
|     default:
 | |
|       WARN("Invalid planet class.");
 | |
|       return 0;
 | |
|   };
 | |
| }
 | |
| 
 | |
| /* Check distance to ensure we can go into hyperspace. */
 | |
| int space_canHyperspace(Pilot* p) {
 | |
|   int i;
 | |
|   double d;
 | |
|   if(p->fuel < HYPERSPACE_FUEL) return 0;
 | |
| 
 | |
|   for(i = 0; i < cur_system->nplanets; i++) {
 | |
|     d = vect_dist(&p->solid->pos, &cur_system->planets[i].pos);
 | |
|     if(d < MIN_HYPERSPACE_DIST)
 | |
|       return 0;
 | |
|   }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /* Hyperspace, returns 0 if entering hyperspace, or the distance if not. */
 | |
| int space_hyperspace(Pilot* p) {
 | |
|   if(p->fuel < HYPERSPACE_FUEL) return -3;
 | |
|   if(!space_canHyperspace(p)) return -1;
 | |
| 
 | |
|   /* Pilot is now going to get automatically ready for hyperspace. */
 | |
|   pilot_setFlag(p, PILOT_HYP_PREP);
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* Return the name of all the planets that belong to factions. */
 | |
| char** space_getFactionPlanet(int* nplanets, int* factions, int nfactions) {
 | |
|   int i, j, k;
 | |
|   Planet* planet;
 | |
|   char** tmp;
 | |
|   int ntmp;
 | |
|   int mtmp;
 | |
| 
 | |
|   ntmp = 0;
 | |
|   mtmp = 25;
 | |
|   tmp = malloc(sizeof(char*) * mtmp);
 | |
| 
 | |
|   for(i = 0; i < systems_nstack; i++)
 | |
|     for(j = 0; j < systems_stack[i].nplanets; j++) {
 | |
|       planet = &systems_stack[i].planets[j];
 | |
|       for(k = 0; k < nfactions; k++)
 | |
|         if(planet->faction == factions[k]) {
 | |
|           ntmp++;
 | |
|           if(ntmp > mtmp) {
 | |
|             mtmp += 25;
 | |
|             tmp = realloc(tmp, sizeof(char*) * mtmp);
 | |
|           }
 | |
|           tmp[ntmp-1] = planet->name;
 | |
|           break; /* No need to check all factions. */
 | |
|         }
 | |
|     }
 | |
|   (*nplanets) = ntmp;
 | |
|   return tmp;
 | |
| }
 | |
| 
 | |
| /* Return the name of a random planet. */
 | |
| char* space_getRndPlanet(void) {
 | |
|   int i, j;
 | |
|   char** tmp;
 | |
|   int ntmp;
 | |
|   int mtmp;
 | |
|   char* res;
 | |
| 
 | |
|   ntmp = 0;
 | |
|   mtmp = 25;
 | |
|   tmp = malloc(sizeof(char)*mtmp);
 | |
| 
 | |
|   for(i = 0; i < systems_nstack; i++)
 | |
|     for(j = 0; j < systems_stack[i].nplanets; j++) {
 | |
|       ntmp++;
 | |
|       if(ntmp > mtmp) {
 | |
|         mtmp += 25;
 | |
|         tmp = realloc(tmp, sizeof(char*) * mtmp);
 | |
|       }
 | |
|       tmp[ntmp-1] = systems_stack[i].planets[j].name;
 | |
|     }
 | |
| 
 | |
|   res = tmp[RNG(0, ntmp-1)];
 | |
|   free(tmp);
 | |
| 
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| /* Return 1 if player can reach the system. */                                  
 | |
| int space_sysReachable(StarSystem* sys) {
 | |
|   int i;
 | |
| 
 | |
|   if(sys_isKnown(sys)) return 1; /* It is known. */
 | |
| 
 | |
|   /* Check to see if it is adjacent to known. */
 | |
|   for(i = 0; i < sys->njumps; i++)
 | |
|     if(sys_isKnown(&systems_stack[sys->jumps[i]]))
 | |
|       return 1;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* Get the system from it's name. */
 | |
| StarSystem* system_get(const char* sysname) {
 | |
|   int i;
 | |
| 
 | |
|   for(i = 0; i < systems_nstack; i++)
 | |
|     if(strcmp(sysname, systems_stack[i].name)==0)
 | |
|       return &systems_stack[i];
 | |
| 
 | |
|   DEBUG("System '%s' not found in stack", sysname);
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /* Get the name of a system from a planetname. */
 | |
| char* planet_getSystem(char* planetname) {
 | |
|   int i;
 | |
|   for(i = 0; i < spacename_nstack; i++)
 | |
|     if(strcmp(planetname_stack[i], planetname)==0)
 | |
|       return systemname_stack[i];
 | |
| 
 | |
|   DEBUG("Planet '%s' not found in planetname stack", planetname);
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /* Get a planet based on it's name. */
 | |
| Planet* planet_get(char* planetname) {
 | |
|   int i;
 | |
|   char* sysname;
 | |
|   StarSystem* sys;
 | |
| 
 | |
|   sysname = planet_getSystem(planetname);
 | |
|   sys = system_get(sysname);
 | |
| 
 | |
|   for(i = 0; i < sys->nplanets; i++)
 | |
|     if(strcmp(planetname, sys->planets[i].name)==0)
 | |
|       return &sys->planets[i];
 | |
|   DEBUG("Planet '%s' not found in the universe", planetname);
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /* Basically used for spawning fleets. */
 | |
| void space_update(const double dt) {
 | |
|   unsigned int t;
 | |
|   int i, j, f;
 | |
| 
 | |
|   (void)dt; /* Don't need it right now. */
 | |
| 
 | |
|   if(cur_system == NULL) return; /* Can't update a null system. */
 | |
| 
 | |
|   t = SDL_GetTicks();
 | |
| 
 | |
|   if(cur_system->nfleets == 0)
 | |
|     /* Please stop checking that there are no fleets. */
 | |
|     spawn_timer = t + 300000;
 | |
| 
 | |
|   if(spawn_timer < t) {
 | |
|     /* Time to possibly spawn. */
 | |
| 
 | |
|     /* Spawn chance is based on overall percentage. */
 | |
|     f = RNG(0, 100*cur_system->nfleets);
 | |
|     j = 0;
 | |
|     for(i = 0; i < cur_system->nfleets; i++) {
 | |
|       j += cur_system->fleets[i].chance;
 | |
|       if(f < j) {
 | |
|         /* Add one fleet. */
 | |
|         space_addFleet(cur_system->fleets[i].fleet);
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|     spawn_timer = t + 60000./(float)cur_system->nfleets;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* Crate a fleet. */
 | |
| static void space_addFleet(Fleet* fleet) {
 | |
|   FleetPilot* plt;
 | |
|   int i;
 | |
|   double a;
 | |
|   Vec2 vv, vp, vn;
 | |
| 
 | |
|   /* Simulate them coming from hyperspace. */
 | |
|   vect_pset(&vp, RNG(MIN_HYPERSPACE_DIST, MIN_HYPERSPACE_DIST*3),
 | |
|             RNG(0, 360)*M_PI/180.);
 | |
|   vectnull(&vn);
 | |
| 
 | |
|   for(i = 0; i < fleet->npilots; i++)
 | |
|     plt = &fleet->pilots[i];
 | |
|   if(RNG(0, 100) <= plt->chance) {
 | |
|       vect_cadd(&vp, RNG(75, 150) * (RNG(0,1) ? 1 : -1),
 | |
|                 RNG(75, 150) * (RNG(0,1) ? 1 : -1));
 | |
| 
 | |
|       a = vect_angle(&vp, &vn);
 | |
|       vect_pset(&vv, plt->ship->speed * 2., a);
 | |
| 
 | |
|       pilot_create(plt->ship,
 | |
|           plt->name,
 | |
|           fleet->faction,
 | |
|           (plt->ai != NULL) ? fleet->ai : fleet->ai, /* Pilot AI override. */
 | |
|           a,
 | |
|           &vp,
 | |
|           &vv,
 | |
|           0);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Init the system. */
 | |
| void space_init(const char* sysname) {
 | |
|   char* lt;
 | |
|   int i;
 | |
| 
 | |
|   /* Cleanup some stuff. */
 | |
|   player_clear(); /* Clears targets. */
 | |
|   pilots_clean(); /* Destroy all the current pilots, exept player. */
 | |
|   weapon_clear(); /* Get rid of all the weapons. */
 | |
|   spfx_clear();  /* Remove of explosions. */
 | |
| 
 | |
|   if((sysname == NULL) && (cur_system == NULL))
 | |
|     ERR("Cannot reinit system if there is no system previously loaded");
 | |
|   else if(sysname != NULL) {
 | |
|     for(i = 0; i < systems_nstack; i++)
 | |
|       if(strcmp(sysname, systems_stack[i].name)==0)
 | |
|         break;
 | |
|     if(i == systems_nstack) ERR("System %s not found in stack", sysname);
 | |
|     cur_system = systems_stack+i;
 | |
| 
 | |
|     lt = ltime_pretty(0);
 | |
|     player_message("Entering System %s on %s.", sysname, lt);
 | |
|     free(lt);
 | |
| 
 | |
|     /* Handle background. */
 | |
|     if(cur_system->nebu_density > 0.) {
 | |
|       /* Background is nebulae. */
 | |
|       nebu_prep(cur_system->nebu_density, cur_system->nebu_volatility);
 | |
|     } else {
 | |
|       /* Background is stary. */
 | |
|       nstars = (cur_system->stars*SCREEN_W*SCREEN_H+STAR_BUF*STAR_BUF)/(800*640);
 | |
|       if(mstars < nstars)
 | |
|         stars = realloc(stars, sizeof(Star)*nstars); /* Should realloc, not malloc. */
 | |
|       for(i = 0; i < nstars; i++) {
 | |
|         stars[i].brightness = (double)RNG(50, 200)/256.;
 | |
|         stars[i].x = (double)RNG(-STAR_BUF, SCREEN_W + STAR_BUF);
 | |
|         stars[i].y = (double)RNG(-STAR_BUF, SCREEN_H + STAR_BUF);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   /* Set up fleets -> pilots. */
 | |
|   for(i = 0; i < cur_system->nfleets; i++)
 | |
|     if(RNG(0,100) <= (cur_system->fleets[i].chance/2)) /* Fleet check (50% chance). */
 | |
|       space_addFleet(cur_system->fleets[i].fleet);
 | |
| 
 | |
|   /* Start the spawn timer. */
 | |
|   spawn_timer = SDL_GetTicks() + 120000./(float)(cur_system->nfleets+1);
 | |
| 
 | |
|   /* We now know this system. */
 | |
|   sys_setFlag(cur_system, SYSTEM_KNOWN);
 | |
| }
 | |
| 
 | |
| /* Load the planets of name 'name'. */
 | |
| static Planet* planet_pull(const char* name) {
 | |
|   int i;
 | |
| 
 | |
|   Planet* tmp = NULL;
 | |
| 
 | |
|   char str[PATH_MAX] = "\0";
 | |
|   char* tstr;
 | |
| 
 | |
|   uint32_t flags = 0;
 | |
| 
 | |
|   uint32_t bufsize;
 | |
|   char* buf = pack_readfile(DATA, PLANET_DATA, &bufsize);
 | |
| 
 | |
|   xmlNodePtr node, cur, ccur;
 | |
|   xmlDocPtr doc = xmlParseMemory(buf, bufsize);
 | |
| 
 | |
|   node = doc->xmlChildrenNode;
 | |
|   if(strcmp((char*)node->name, XML_PLANET_ID)) {
 | |
|     ERR("Malformed "PLANET_DATA" file: missing root element '"XML_PLANET_ID"'");
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   node = node->xmlChildrenNode; /* First system node. */
 | |
|   if(node == NULL) {
 | |
|     ERR("Malformed "PLANET_DATA" file: does not contain elements");
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   do {
 | |
|     if(xml_isNode(node, XML_PLANET_TAG)) {
 | |
|       tstr = xml_nodeProp(node, "name");
 | |
|       if(strcmp(tstr, name)==0) { /* Found. */
 | |
|         tmp = CALLOC_L(Planet);
 | |
|         tmp->faction = -1;        /* No faction. */
 | |
|         tmp->name = tstr;
 | |
| 
 | |
|         node = node->xmlChildrenNode;
 | |
| 
 | |
|         do {
 | |
|           if(xml_isNode(node, "GFX")) {
 | |
|             cur = node->children;
 | |
|             do {
 | |
|               if(xml_isNode(cur, "space")) {
 | |
|                 /* Load space gfx. */
 | |
|                 snprintf(str, strlen(xml_get(cur))+sizeof(PLANET_GFX_SPACE),
 | |
|                          PLANET_GFX_SPACE"%s", xml_get(cur));
 | |
|                 tmp->gfx_space = gl_newImage(str);
 | |
|               }
 | |
|               else if(xml_isNode(cur, "exterior")) {
 | |
|                 /* Load land gfx. */
 | |
|                 tmp->gfx_exterior = malloc(strlen(xml_get(cur))+sizeof(PLANET_GFX_EXTERIOR));
 | |
|                 snprintf(tmp->gfx_exterior, strlen(xml_get(cur))+sizeof(PLANET_GFX_EXTERIOR),
 | |
|                          PLANET_GFX_EXTERIOR"%s", xml_get(cur));
 | |
|               }
 | |
|             } while(xml_nextNode(cur));
 | |
|           }
 | |
|           else if(xml_isNode(node, "pos")) {
 | |
|             cur = node->children;
 | |
|             do {
 | |
|               if(xml_isNode(cur, "x")) {
 | |
|                 flags |= FLAG_XSET;
 | |
|                 tmp->pos.x = xml_getFloat(cur);
 | |
|               }
 | |
|               else if(xml_isNode(cur, "y")) {
 | |
|                 flags |= FLAG_YSET;
 | |
|                 tmp->pos.y = xml_getFloat(cur);
 | |
|               }
 | |
|             } while(xml_nextNode(cur));
 | |
|           }
 | |
|           else if(xml_isNode(node, "general")) {
 | |
|             cur = node->children;
 | |
|             do {
 | |
|               if(xml_isNode(cur, "class"))
 | |
|                 tmp->class = planetclass_get(cur->children->content[0]);
 | |
|               else if(xml_isNode(cur, "faction")) {
 | |
|                 flags |= FLAG_FACTIONSET;
 | |
|                 tmp->faction = faction_get(xml_get(cur));
 | |
|               }
 | |
|               else if(xml_isNode(cur, "description"))
 | |
|                 tmp->description = strdup(xml_get(cur));
 | |
|               else if(xml_isNode(cur, "bar"))
 | |
|                 tmp->bar_description = strdup(xml_get(cur));
 | |
|               else if(xml_isNode(cur, "services")) {
 | |
|                 flags |= FLAG_SERVICESET;
 | |
|                 tmp->services = xml_getInt(cur);
 | |
|               }
 | |
|               else if(xml_isNode(cur, "tech")) {
 | |
|                 ccur = cur->children;
 | |
|                 do {
 | |
|                   if(xml_isNode(ccur, "main")) {
 | |
|                     flags |= FLAG_TECHSET;
 | |
|                     tmp->tech[0] = xml_getInt(ccur);
 | |
|                   }
 | |
|                   else if(xml_isNode(ccur, "special")) {
 | |
|                     for(i = 1; i < PLANET_TECH_MAX; i++)
 | |
|                       if(tmp->tech[i]==0) {
 | |
|                         tmp->tech[i] = xml_getInt(ccur);
 | |
|                         break;
 | |
|                       }
 | |
|                     if(i == PLANET_TECH_MAX) WARN("Planet '%s' has too many"
 | |
|                                                   "'special tech' entries", tmp->name);
 | |
|                   }
 | |
|                 } while(xml_nextNode(ccur));
 | |
|               }
 | |
|               else if(xml_isNode(cur, "commodities")) {
 | |
|                 ccur = cur->children;
 | |
|                 do {
 | |
|                   if(xml_isNode(ccur, "commodity")) {
 | |
|                     tmp->commodities = realloc(tmp->commodities,
 | |
|                                                (tmp->ncommodities+1) * sizeof(Commodity*));
 | |
|                     tmp->commodities[tmp->ncommodities] =
 | |
|                         commodity_get(xml_get(ccur));
 | |
|                     tmp->ncommodities++;
 | |
|                   }
 | |
|                 } while(xml_nextNode(ccur));
 | |
|               }
 | |
|             } while(xml_nextNode(cur));
 | |
|           }
 | |
|         } while(xml_nextNode(node));
 | |
|         break;
 | |
|       } else
 | |
|         free(tstr); /* xmlGetProp mallocs the string. */
 | |
|     }
 | |
|   } while(xml_nextNode(node));
 | |
| 
 | |
|   xmlFreeDoc(doc);
 | |
|   free(buf);
 | |
|   xmlCleanupParser();
 | |
| 
 | |
|   /* Check elements. */
 | |
|   if(tmp) {
 | |
| #define MELEMENT(o,s) if(o) WARN("Planet '%s' missing '"s"' element", tmp->name)
 | |
|     MELEMENT(tmp->gfx_space==NULL,         "GFX_space");
 | |
|     MELEMENT(planet_hasService(tmp, PLANET_SERVICE_LAND) &&
 | |
|              tmp->gfx_exterior==NULL, "GFX exterior");
 | |
|     MELEMENT((flags&FLAG_XSET)==0,         "x");
 | |
|     MELEMENT((flags&FLAG_YSET)==0,         "y");
 | |
|     MELEMENT(tmp->class==PLANET_CLASS_NULL,   "class");
 | |
|     MELEMENT(planet_hasService(tmp, PLANET_SERVICE_LAND) &&
 | |
|              tmp->description==NULL, "description");
 | |
|     MELEMENT(planet_hasService(tmp, PLANET_SERVICE_BASIC) &&
 | |
|              tmp->bar_description==NULL, "bar");
 | |
|     MELEMENT(planet_hasService(tmp, PLANET_SERVICE_BASIC) &&
 | |
|              (flags & FLAG_FACTIONSET)==0, "faction");
 | |
|     MELEMENT((flags&FLAG_SERVICESET)==0,    "services");
 | |
| 
 | |
|     MELEMENT((planet_hasService(tmp, PLANET_SERVICE_OUTFITS) ||
 | |
|               planet_hasService(tmp, PLANET_SERVICE_SHIPYARD)) &&
 | |
|              (flags&FLAG_TECHSET)==0, "tech");
 | |
|     MELEMENT(planet_hasService(tmp, PLANET_SERVICE_COMMODITY) &&
 | |
|              (tmp->ncommodities==0), "commodity");
 | |
| #undef MELEMENT
 | |
|   } else
 | |
|     WARN("No planet found matching name '%s'", name);
 | |
| 
 | |
|   return tmp;
 | |
| }
 | |
| 
 | |
| /* Parse node 'parent' which should be the node of a system. */
 | |
| /* Return the StarSystem fully loaded. */
 | |
| static StarSystem* system_parse(const xmlNodePtr parent) {
 | |
|   Planet* planet = NULL;
 | |
|   SystemFleet* fleet = NULL;
 | |
|   StarSystem* tmp = CALLOC_L(StarSystem);
 | |
|   char* ptrc;
 | |
|   xmlNodePtr cur, node;
 | |
| 
 | |
|   uint32_t flags;
 | |
| 
 | |
|   tmp->name = xml_nodeProp(parent, "name"); /* Already mallocs. */
 | |
| 
 | |
|   node = parent->xmlChildrenNode;
 | |
| 
 | |
|   do {
 | |
|     /* Load all the things! */
 | |
|     if(xml_isNode(node, "pos")) {
 | |
|       cur = node->children;
 | |
|       do {
 | |
|         if(xml_isNode(cur, "x")) {
 | |
|           flags |= FLAG_XSET;
 | |
|           tmp->pos.x = xml_getFloat(cur);
 | |
|         }
 | |
|         if(xml_isNode(cur, "y")) {
 | |
|           flags |= FLAG_YSET;
 | |
|           tmp->pos.y = xml_getFloat(cur);
 | |
|         }
 | |
|       } while(xml_nextNode(cur));
 | |
|     }
 | |
|     else if(xml_isNode(node, "general")) {
 | |
|       cur = node->children;
 | |
|       do {
 | |
|         if(xml_isNode(cur, "stars")) /* Non-zero. */
 | |
|           tmp->stars = xml_getInt(cur);
 | |
|         else if(xml_isNode(cur, "asteroids")) {
 | |
|           flags |= FLAG_ASTEROIDSSET;
 | |
|           tmp->asteroids = xml_getInt(cur);
 | |
|         }
 | |
|         else if(xml_isNode(cur, "interference")) {
 | |
|           flags |= FLAG_INTEFERENCESET;
 | |
|           tmp->interference = xml_getFloat(cur)/100;
 | |
|         }
 | |
|         else if(xml_isNode(cur, "nebulae")) {
 | |
|           ptrc = xml_nodeProp(cur, "volatility");
 | |
|           if(ptrc != NULL) { /* Has volatility. */
 | |
|             tmp->nebu_volatility = atof(ptrc);
 | |
|             free(ptrc);
 | |
|           }
 | |
|           tmp->nebu_density = xml_getFloat(cur);
 | |
|         }
 | |
|       }while(xml_nextNode(cur));
 | |
|     }
 | |
|     /* Load all the planets. */
 | |
|     else if(xml_isNode(node, "planets")) {
 | |
|       cur = node->children;
 | |
|       do {
 | |
|         if(cur && xml_isNode(cur, "planet")) {
 | |
|           /* Add planet to system. */
 | |
|           total_planets++; /* Increase planet counter. */
 | |
|           planet = planet_pull(xml_get(cur));
 | |
|           tmp->planets = realloc(tmp->planets, sizeof(Planet)*(++tmp->nplanets));
 | |
|           memcpy(tmp->planets+(tmp->nplanets-1), planet, sizeof(Planet));
 | |
| 
 | |
|           /* Add planet <-> star system to name stack. */
 | |
|           spacename_nstack++;
 | |
|           planetname_stack = realloc(planetname_stack,
 | |
|               sizeof(char*)*spacename_nstack);
 | |
|           systemname_stack = realloc(systemname_stack,
 | |
|               sizeof(char*)*spacename_nstack);
 | |
|           planetname_stack[spacename_nstack-1] = planet->name;
 | |
|           systemname_stack[spacename_nstack-1] = tmp->name;
 | |
|           free(planet);
 | |
|         }
 | |
|       } while(xml_nextNode(cur));
 | |
|     }
 | |
|     /* Load all the fleets. */
 | |
|     else if(xml_isNode(node, "fleets")) {
 | |
|       cur = node->children;
 | |
|       do {
 | |
|         if(cur && xml_isNode(cur, "fleet")) {
 | |
|           fleet = CALLOC_L(SystemFleet);
 | |
|           fleet->fleet = fleet_get(xml_get(cur));
 | |
|           if(fleet->fleet == NULL)
 | |
|             WARN("Fleet %s for Star System %s not found", xml_get(cur), tmp->name);
 | |
| 
 | |
|           ptrc = xml_nodeProp(cur, "chance"); /* Malloc ptrc. */
 | |
|           fleet->chance = atoi(ptrc);
 | |
|           if(fleet->chance == 0)
 | |
|             WARN("Fleet %s for Star System %s has 0%% chance to appear",
 | |
|                  fleet->fleet->name, tmp->name);
 | |
|           if(ptrc) free(ptrc); /* Free the ptrc. */
 | |
| 
 | |
|           tmp->fleets = realloc(tmp->fleets, sizeof(SystemFleet)*(++tmp->nfleets));
 | |
|           memcpy(tmp->fleets+(tmp->nfleets-1), fleet, sizeof(SystemFleet));
 | |
|           free(fleet);
 | |
|         }
 | |
|       } while(xml_nextNode(cur));
 | |
|     }
 | |
|   } while(xml_nextNode(node));
 | |
| 
 | |
|   /* Check elements. */
 | |
| #define MELEMENT(o,s) if((o) == 0) WARN("Star System '%s' missing '"s"' element", tmp->name)
 | |
|   MELEMENT(flags&FLAG_XSET, "x");
 | |
|   MELEMENT(flags&FLAG_YSET, "y");
 | |
|   MELEMENT(tmp->stars, "stars");
 | |
|   MELEMENT(flags&FLAG_ASTEROIDSSET, "asteroids"); /* Can be 0. */
 | |
|   MELEMENT(flags&FLAG_INTEFERENCESET, "inteference");
 | |
| #undef MELEMENT
 | |
| 
 | |
|   /* Post processing. */
 | |
|   if(tmp->nplanets > 0)
 | |
|     /* TODO: Make dependant on overall planet faction. */
 | |
|     tmp->faction = tmp->planets[0].faction;
 | |
|   return tmp;
 | |
| }
 | |
| 
 | |
| /* Load the jumps into a system. */
 | |
| static void system_parseJumps(const xmlNodePtr parent) {
 | |
|   int i;
 | |
|   StarSystem* sys;
 | |
|   char* name;
 | |
|   xmlNodePtr cur, node;
 | |
| 
 | |
|   name = xml_nodeProp(parent, "name"); /* Already mallocs. */
 | |
|   for(i = 0; i < systems_nstack; i++)
 | |
|     if(strcmp(systems_stack[i].name, name)==0) {
 | |
|       sys = &systems_stack[i];
 | |
|       break;
 | |
|     }
 | |
|   if(i == systems_nstack)
 | |
|     WARN("System '%s' was not found in the stack for some reason", name);
 | |
|   free(name); /* No need for it now. */
 | |
| 
 | |
|   node = parent->xmlChildrenNode;
 | |
| 
 | |
|   do {
 | |
|     /* Load the data. */
 | |
|     if(xml_isNode(node, "jumps")) {
 | |
|       cur = node->children;
 | |
|       do {
 | |
|         if(xml_isNode(cur, "jump")) {
 | |
|           for(i = 0; i < systems_nstack; i++)
 | |
|             if(strcmp(systems_stack[i].name, xml_get(cur))==0) {
 | |
|               sys->njumps++;
 | |
|               sys->jumps = realloc(sys->jumps, sys->njumps*sizeof(int));
 | |
|               sys->jumps[sys->njumps-1] = i;
 | |
|               break;
 | |
|             }
 | |
|           if(i == systems_nstack)
 | |
|             WARN("System '%s' not found for jump linking", xml_get(cur));
 | |
|         }
 | |
|       } while(xml_nextNode(cur));
 | |
|     }
 | |
|   } while(xml_nextNode(node));
 | |
| }
 | |
| 
 | |
| /* Load the ENTIRE universe into RAM. -- WOAH! */
 | |
| /* -- Used a two system pass to first load the star systems_stack and then set jump routes. */
 | |
| int space_load(void) {
 | |
|   uint32_t bufsize;
 | |
|   char* buf = pack_readfile(DATA, SYSTEM_DATA, &bufsize);
 | |
| 
 | |
|   StarSystem* tmp;
 | |
| 
 | |
|   xmlNodePtr node;
 | |
|   xmlDocPtr doc = xmlParseMemory(buf, bufsize);
 | |
| 
 | |
|   node = doc->xmlChildrenNode;
 | |
|   if(!xml_isNode(node, XML_SYSTEM_ID)) {
 | |
|     ERR("Malformed "SYSTEM_DATA" file: missing root element '"XML_SYSTEM_ID"'");
 | |
|     return -1;
 | |
|   }
 | |
|   node = node->xmlChildrenNode; /* First system node. */
 | |
|   if(node == NULL) {
 | |
|     ERR("Malformed "SYSTEM_DATA" file: does not contain elements");
 | |
|     return -1;
 | |
|   }
 | |
|   /* Fist pass - Load all the star systems_stack. */
 | |
|   do {
 | |
|     if(xml_isNode(node, XML_SYSTEM_TAG)) {
 | |
|       tmp = system_parse(node);
 | |
|       systems_stack = realloc(systems_stack, sizeof(StarSystem)*(++systems_nstack));
 | |
|       memcpy(systems_stack+systems_nstack-1, tmp, sizeof(StarSystem));
 | |
|       free(tmp);
 | |
|     }
 | |
|   } while(xml_nextNode(node));
 | |
| 
 | |
|   /* Second pass - Load all the jump routes. */
 | |
|   node = doc->xmlChildrenNode->xmlChildrenNode;
 | |
|   do {
 | |
|     if(xml_isNode(node, XML_SYSTEM_TAG))
 | |
|       system_parseJumps(node); /* Automatically load the jumps into the system. */
 | |
|   } while(xml_nextNode(node));
 | |
| 
 | |
|   /* Cleanup. */
 | |
|   xmlFreeDoc(doc);
 | |
|   free(buf);
 | |
|   xmlCleanupParser();
 | |
| 
 | |
|   DEBUG("Loaded %d star system%s with %d planet%s",
 | |
|         systems_nstack, (systems_nstack==1) ? "" : "s",
 | |
|         total_planets, (total_planets==1) ? "" : "s");
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* Render the system. -- Just playing god now. */
 | |
| void space_render(const double dt) {
 | |
|   if(cur_system == NULL) return;
 | |
| 
 | |
|   if(cur_system->nebu_density > 0.)
 | |
|     nebu_render(dt);
 | |
|   else
 | |
|     space_renderStars(dt);
 | |
| }
 | |
| 
 | |
| /* Render the overlay. */
 | |
| void space_renderOverlay(const double dt) {
 | |
|   if(cur_system == NULL) return; 
 | |
| 
 | |
|   if(cur_system->nebu_density > 0.)
 | |
|     nebu_renderOverlay(dt);
 | |
| }
 | |
| 
 | |
| /* Render stars. */
 | |
| static void space_renderStars(const double dt) {
 | |
|   int i;
 | |
|   unsigned int t, timer;
 | |
|   double x, y, m, b;
 | |
| 
 | |
|   glMatrixMode(GL_MODELVIEW);
 | |
|   glPushMatrix(); /* Translation matrix. */
 | |
|   glTranslated(-(double)SCREEN_W/2., -(double)SCREEN_H/2., 0);
 | |
| 
 | |
|   t = SDL_GetTicks();
 | |
|   if(!player_isFlag(PLAYER_DESTROYED) && !player_isFlag(PLAYER_CREATING) &&
 | |
|      pilot_isFlag(player, PILOT_HYPERSPACE) && /* Hyperspace fancy effect. */
 | |
|      (player->ptimer-HYPERSPACE_STARS_BLUR < t)) {
 | |
| 
 | |
|     timer = player->ptimer - HYPERSPACE_STARS_BLUR;
 | |
| 
 | |
|     /* Fancy hyperspace effects. */
 | |
|     glShadeModel(GL_SMOOTH);
 | |
| 
 | |
|     glBegin(GL_LINES);
 | |
| 
 | |
|     /* Lines will be based on velocity. */
 | |
|     m = HYPERSPACE_STARS_LENGTH * (double)(t-timer) / (HYPERSPACE_STARS_BLUR);
 | |
|     x = m*cos(VANGLE(player->solid->vel)+M_PI);
 | |
|     y = m*sin(VANGLE(player->solid->vel)+M_PI);
 | |
| 
 | |
|     for(i = 0; i < nstars; i++) {
 | |
|       glColor4d(1., 1., 1., stars[i].brightness);
 | |
|       glVertex2d(stars[i].x, stars[i].y);
 | |
|       glColor4d(1., 1., 1., 0.);
 | |
|       glVertex2d(stars[i].x+x*stars[i].brightness,stars[i].y+y*stars[i].brightness);
 | |
|     }
 | |
|     glEnd();
 | |
| 
 | |
|     glShadeModel(GL_FLAT);
 | |
| 
 | |
|   } else {
 | |
|     glBegin(GL_POINTS); /* Normal rendering. */
 | |
|     if(!paused && !player_isFlag(PLAYER_DESTROYED) &&
 | |
|         !player_isFlag(PLAYER_CREATING)) { /* Update position. */
 | |
|       for(i = 0; i < nstars; i++) {
 | |
|         b = 13.-10.*stars[i].brightness;
 | |
|         stars[i].x -= player->solid->vel.x/b*dt;
 | |
|         stars[i].y -= player->solid->vel.y/b*dt;
 | |
|         
 | |
|         /* Check for boundaries. */
 | |
|         if(stars[i].x > SCREEN_W + STAR_BUF) stars[i].x = -STAR_BUF;
 | |
|         else if(stars[i].x < -STAR_BUF) stars[i].x = SCREEN_W + STAR_BUF;
 | |
|         if(stars[i].y > SCREEN_H + STAR_BUF) stars[i].y = -STAR_BUF;
 | |
|         else if(stars[i].y < -STAR_BUF) stars[i].y = SCREEN_H + STAR_BUF;
 | |
| 
 | |
|         /* Render. */
 | |
|         if((stars[i].x < SCREEN_W) && (stars[i].x > 0) &&
 | |
|             (stars[i].y < SCREEN_H) && (stars[i].y > 0)) {
 | |
|           glColor4d(1., 1., 1., stars[i].brightness);
 | |
|           glVertex2d(stars[i].x, stars[i].y);
 | |
|         }
 | |
|       }
 | |
|     } else { /* Just render. */
 | |
|       for(i = 0; i < nstars; i++) {
 | |
|         if((stars[i].x < SCREEN_W) && (stars[i].x > 0) &&
 | |
|             (stars[i].y < SCREEN_H) && (stars[i].y > 0)) {
 | |
|           glColor4d(1., 1., 1., stars[i].brightness);
 | |
|           glVertex2d(stars[i].x, stars[i].y);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     glEnd(); /* GL_POINTS */
 | |
|   }
 | |
|   glPopMatrix(); /* Translation matrix. */
 | |
| }
 | |
| 
 | |
| /* Render the planets. */
 | |
| void planets_render(void) {
 | |
|   if(cur_system == NULL) return;
 | |
| 
 | |
|   int i;
 | |
|   for(i = 0; i < cur_system->nplanets; i++)
 | |
|     gl_blitSprite(cur_system->planets[i].gfx_space,
 | |
|                   cur_system->planets[i].pos.x, cur_system->planets[i].pos.y, 0, 0, NULL);
 | |
| }
 | |
| 
 | |
| /* Clean up the system. */
 | |
| void space_exit(void) {
 | |
|   int i,j;
 | |
|   
 | |
|   /* Free the names. */
 | |
|   /*if(planetname_stack) free(planetname_stack); */
 | |
|   /*if(systemname_stack) free(systemname_stack); */
 | |
|   if(planetname_stack) {
 | |
|   	 free(planetname_stack);
 | |
|   	 planetname_stack = NULL;
 | |
|   }
 | |
|   if(systemname_stack) {
 | |
|    free(systemname_stack);
 | |
|    systemname_stack = NULL;
 | |
|   }
 | |
|   spacename_nstack = 0;
 | |
| 
 | |
|   /* Free the systems. */
 | |
|   for(i = 0; i < systems_nstack; i++) {
 | |
|     free(systems_stack[i].name);
 | |
|     if(systems_stack[i].fleets)
 | |
|       free(systems_stack[i].fleets);
 | |
|     if(systems_stack[i].jumps)
 | |
|       free(systems_stack[i].jumps);
 | |
| 
 | |
|     /* Free some planets. */
 | |
|     for(j = 0; j < systems_stack[i].nplanets; j++) {
 | |
|       free(systems_stack[i].planets[j].name);
 | |
|       if(systems_stack[i].planets[j].description)
 | |
|         free(systems_stack[i].planets[j].description);
 | |
|       if(systems_stack[i].planets[j].bar_description)
 | |
|         free(systems_stack[i].planets[j].bar_description);
 | |
| 
 | |
|       /* Graphics. */
 | |
|       if(systems_stack[i].planets[j].gfx_space)
 | |
|         gl_freeTexture(systems_stack[i].planets[j].gfx_space);
 | |
|       if(systems_stack[i].planets[j].gfx_exterior)
 | |
|         free(systems_stack[i].planets[j].gfx_exterior);
 | |
| 
 | |
|       /* Commodities. */
 | |
|       free(systems_stack[i].planets[j].commodities);
 | |
|     }
 | |
|     free(systems_stack[i].planets);
 | |
|   }
 | |
|   free(systems_stack);
 | |
|   systems_stack   = NULL;
 | |
|   systems_nstack  = 0;
 | |
| 
 | |
|   /* Stars must be set free too. */
 | |
|   if(stars) free(stars);
 | |
|   stars   = NULL;
 | |
|   nstars  = 0;
 | |
| }
 | |
| 
 | |
| /* Clear all system knowledge. */
 | |
| void space_clearKnown(void) {
 | |
|   int i;
 | |
|   for(i = 0; i < systems_nstack; i++)
 | |
|     sys_rmFlag(&systems_stack[i], SYSTEM_KNOWN);
 | |
| }
 | |
| 
 | |
| /* Clear all system markers. */
 | |
| void space_clearMarkers(void) {
 | |
|   int i;
 | |
|   for( i = 0; i < systems_nstack; i++)
 | |
|     sys_rmFlag(&systems_stack[i], SYSTEM_MARKED);
 | |
| }
 | |
| 
 | |
| /* Save what is needed to be saved for space. */
 | |
| int space_sysSave(xmlTextWriterPtr writer) {
 | |
|   int i;
 | |
| 
 | |
|   xmlw_startElem(writer, "space");
 | |
| 
 | |
|   for(i = 0; i < systems_nstack; i++) {
 | |
|     if(!sys_isKnown(&systems_stack[i])) continue; /* Not known. */
 | |
| 
 | |
|     xmlw_elem(writer, "known", "%s", systems_stack[i].name);
 | |
|   }
 | |
| 
 | |
|   xmlw_endElem(writer); /* Space. */
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* Load space. */
 | |
| int space_sysLoad(xmlNodePtr parent) {
 | |
|   xmlNodePtr node, cur;
 | |
|   StarSystem* sys;
 | |
| 
 | |
|   space_clearKnown();
 | |
|   
 | |
|   node = parent->xmlChildrenNode;
 | |
|   do {
 | |
|     if(xml_isNode(node, "space")) {
 | |
|       cur = node->xmlChildrenNode;
 | |
|       do {
 | |
|         if(xml_isNode(cur, "known")) {
 | |
|           sys = system_get(xml_get(cur));
 | |
|           if(sys != NULL) /* Must exist. */
 | |
|             sys_setFlag(sys, SYSTEM_KNOWN);
 | |
|         }
 | |
|       } while(xml_nextNode(cur));
 | |
|     }
 | |
|   } while(xml_nextNode(node));
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | 
