#include #include #include #include "xml.h" #include "lephisto.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 "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 nplanets = 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 StarSystem* system_get(const char* sysname); static Planet* planet_pull(const char* name); 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, ...); // 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)nplanets; i++) { if(areEnemies(player->faction, cur_system->planets[i].faction)) COLOUR(cHostile); else if(areAllies(player->faction, cur_system->planets[i].faction)) COLOUR(cFriend); else COLOUR(cNeutral); 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 // A* Algorithm fo shortest path finding. // The node struct. typedef struct SysNode_ { struct SysNode_* next, *gnext; struct SysNode_* parent; StarSystem* sys; double r; // Ranking. int g; // Step. } SysNode; static SysNode* A_gc; // Prototypes. static SysNode* A_newNode(StarSystem* sys, SysNode* parent); static double A_h(StarSystem* n, StarSystem* g); static double A_g(SysNode* n); static SysNode* A_add(SysNode* first, SysNode* cur); static SysNode* A_rm(SysNode* first, StarSystem* cur); static int A_in(SysNode* first, StarSystem* cur); static SysNode* A_lowest(SysNode* first); static void A_freeList(SysNode* first); // Creates a new node link to star system. static SysNode* A_newNode(StarSystem* sys, SysNode* parent) { SysNode* n; n = malloc(sizeof(SysNode)); n->next = NULL; n->parent = parent; n->sys = sys; n->r = DBL_MAX; n->g = 0.; n->gnext = A_gc; A_gc = n; return n; } static double A_h(StarSystem* n, StarSystem* g) { // Euclidean distance. return sqrt(pow2(n->pos.x - g->pos.x) + pow2(n->pos.y - g->pos.y))/100.; } // Get the g from a node. static double A_g(SysNode* n) { return n->g; } // Add a node to the linkes list. static SysNode* A_add(SysNode* first, SysNode* cur) { SysNode* n; if(first == NULL) return cur; n = first; while(n->next != NULL) n = n->next; n->next = cur; return first; } // Remove a node from a linked list. static SysNode* A_rm(SysNode* first, StarSystem* cur) { SysNode* n, *p; if(first->sys == cur) { first->next = NULL; n = first->next; return n; } p = first; n = p->next; do { if(n->sys == cur) { n->next = NULL; p->next = n->next; break; } } while((n=n->next) != NULL); return first; } // Check if node is in linked list. static int A_in(SysNode* first, StarSystem* cur) { SysNode* n; if(first == NULL) return 0; n = first; do { if(n->sys == cur) return 1; } while((n=n->next) != NULL); return 0; } // Return the lowest ranking node from a linked list of nodes. static SysNode* A_lowest(SysNode* first) { SysNode* lowest, *n; if(first == NULL) return NULL; n = first; lowest = n; do { if(n->r < lowest->r) lowest = n; } while((n=n->next) != NULL); return lowest; } // Free a linked list. static void A_freeList(SysNode* first) { SysNode* p, *n; if(first == NULL) return; p = NULL; n = first; do { if(p != NULL) free(p); p = n; } while((n=n->gnext) != NULL); free(p); } StarSystem** system_getJumpPath(int* njumps, char* sysstart, char* sysend) { int i, cost; StarSystem* ssys, *esys, **res; SysNode* cur, *neighbour; SysNode* open, *closed; A_gc = NULL; // Initial and target systems. ssys = system_get(sysstart); // Start. esys = system_get(sysend); // End. // Start the linked lists. open = closed = NULL; cur = A_newNode(ssys, NULL); open = A_add(open, cur); // Initial open node is the start system. while((cur = A_lowest(open))->sys != esys) { // Get best from open and toss to closed. open = A_rm(open, cur->sys); closed = A_add(closed, cur); for(i = 0; i < cur->sys->njumps; i++) { neighbour = A_newNode(&systems_stack[cur->sys->jumps[i]], cur); cost = A_g(cur) + 1; if(A_in(open, neighbour->sys) && (cost < A_g(neighbour))) open = A_rm(open, neighbour->sys); // New path is better. if(A_in(closed, neighbour->sys) && (cost < A_g(neighbour))) closed = A_rm(closed, neighbour->sys); // Shouldn't happen. if(!A_in(open, neighbour->sys) && !A_in(closed, neighbour->sys)) { neighbour->g = cost; open = A_add(open, neighbour); neighbour->r = (double)A_g(neighbour) + A_h(neighbour->sys, esys); } } } // Build the path backwards. (*njumps) = A_g(cur); res = malloc(sizeof(StarSystem*) * (*njumps)); for(i = 0; i < (*njumps); i++) { res[(*njumps)-i-1] = cur->sys; cur = cur->parent; } // Free the linked list. //A_freeList(open); //A_freeList(closed); A_freeList(A_gc); return res; } 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; default: return PLANET_CLASS_NULL; }; } // Check distance to ensure we can go into hyperspace. int space_canHyperspace(Pilot* p) { int i; double d; 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(!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((faction_isFaction(factions[k]) && (planet->faction == factions[k])) || (faction_isAlliance(factions[k]) && faction_ofAlliance(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; } // Get the system from it's name. static 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* sys; StarSystem* system; sys = planet_getSystem(planetname); system = system_get(sys); for(i = 0; i < system->nplanets; i++) if(strcmp(planetname, system->planets[i].name)==0) return &system->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. 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) { int i; double a; Vec2 vv, vp, vn; // Simulate them coming from hyperspace. vect_pset(&vp, RNG(MIN_HYPERSPACE_DIST, MIN_HYPERSPACE_DIST*1.5), RNG(0, 360)*M_PI/180.); vectnull(&vn); for(i = 0; i < fleet->npilots; i++) if(RNG(0, 100) <= fleet->pilots[i].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); vectnull(&vv); pilot_create(fleet->pilots[i].ship, fleet->pilots[i].name, fleet->faction, fleet->ai, 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); // Set up stars. nstars = (cur_system->stars*gl_screen.w*gl_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, gl_screen.w + STAR_BUF); stars[i].y = (double)RNG(-STAR_BUF, gl_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); } // 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->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. snprintf(str, strlen(xml_get(cur))+sizeof(PLANET_GFX_EXTERIOR), PLANET_GFX_EXTERIOR"%s", xml_get(cur)); tmp->gfx_exterior = gl_newImage(str); } } while((cur = cur->next)); } 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((cur = cur->next)); } 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 tooo many" "'special tech' entries", tmp->name); } } while((ccur = ccur->next)); } 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((ccur = ccur->next)); } } while((cur = cur->next)); } } while((node = node->next)); break; } else free(tstr); // xmlGetProp mallocs the string. } } while((node = node->next)); 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((cur = cur->next)); } 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; } }while((cur = cur->next)); } // Load all the planets. else if(xml_isNode(node, "planets")) { cur = node->children; do { if(xml_isNode(cur, "planet")) { // Add planet to system. nplanets++; // 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((cur = cur->next)); } // Load all the fleets. else if(xml_isNode(node, "fleets")) { cur = node->children; do { if(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((cur = cur->next)); } } while((node = node->next)); // 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* system; 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) { system = &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) { system->njumps++; system->jumps = realloc(system->jumps, system->njumps*sizeof(int)); system->jumps[system->njumps-1] = i; break; } if(i == systems_nstack) WARN("System '%s' not found for jump linking", xml_get(cur)); } } while((cur = cur->next)); } } while((node = node->next)); } // 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((node = node->next)); // 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((node = node->next)); // Cleanup. xmlFreeDoc(doc); free(buf); xmlCleanupParser(); DEBUG("Loaded %d star system%s with %d planet%s", systems_nstack, (systems_nstack==1) ? "" : "s", nplanets, (nplanets==1) ? "" : "s"); return 0; } // Render the system. -- Just playing god now. void space_render(double dt) { int i; unsigned int t, timer; double x, y, m, b; glMatrixMode(GL_MODELVIEW); glPushMatrix(); // Translation matrix. glTranslated(-(double)gl_screen.w/2., -(double)gl_screen.h/2., 0); t = SDL_GetTicks(); if(!player_isFlag(PLAYER_DESTROYED) && pilot_isFlag(player, PILOT_HYPERSPACE) && // Hyperspace fancy effect. !paused && (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)) { // 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 > gl_screen.w + STAR_BUF) stars[i].x = -STAR_BUF; else if(stars[i].x < -STAR_BUF) stars[i].x = gl_screen.w + STAR_BUF; if(stars[i].y > gl_screen.h + STAR_BUF) stars[i].y = -STAR_BUF; else if(stars[i].y < -STAR_BUF) stars[i].y = gl_screen.h + STAR_BUF; // Render. glColor4d(1., 1., 1., stars[i].brightness); glVertex2d(stars[i].x, stars[i].y); } } else { // Just render. for(i = 0; i < nstars; i++) { 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) gl_freeTexture(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; }