diff --git a/dat/faction.xml b/dat/faction.xml index 836ff5a..95ca975 100644 --- a/dat/faction.xml +++ b/dat/faction.xml @@ -2,6 +2,8 @@ + + diff --git a/dat/fleet.xml b/dat/fleet.xml index 99dc561..a31e32e 100644 --- a/dat/fleet.xml +++ b/dat/fleet.xml @@ -1,19 +1,19 @@ - 2 + Independent Test - 2 + Merchant Ship - 2 + Merchant Ship Ship diff --git a/dat/planet.xml b/dat/planet.xml index 71834f0..a8c8f85 100644 --- a/dat/planet.xml +++ b/dat/planet.xml @@ -6,7 +6,8 @@ 15 - 1 + A + Independent 1 0 1 @@ -19,7 +20,8 @@ -345 - 1 + A + Independent 1 0 1 diff --git a/dat/ssys.xml b/dat/ssys.xml index a3b8a56..a3643cc 100644 --- a/dat/ssys.xml +++ b/dat/ssys.xml @@ -9,7 +9,6 @@ 500 0 0 - 2 KonoSphere @@ -32,7 +31,6 @@ 27 0 0 - 2 SaraCraft diff --git a/src/ai.c b/src/ai.c index d424085..60bce9c 100644 --- a/src/ai.c +++ b/src/ai.c @@ -266,7 +266,7 @@ static int ai_getdistance(lua_State* L) { // Get the pilots position. static int ai_getpos(lua_State* L) { Pilot* p; - if(lua_isnumber(L, 1)) p = get_pilot((int)lua_tonumber(L,1)); // Pilot ID. + if(lua_isnumber(L, 1)) p = pilot_get((int)lua_tonumber(L,1)); // Pilot ID. else if(lua_islightuserdata(L, 1)) p = (Pilot*)lua_topointer(L, 1); // Pilot pointer. else p = cur_pilot; // Default to ones self. @@ -324,7 +324,7 @@ static int ai_turn(lua_State* L) { static int ai_face(lua_State* L) { MIN_ARGS(1); Vec2* v; // Grab the position to face. - if(lua_isnumber(L,1)) v = &get_pilot((unsigned int)lua_tonumber(L,1))->solid->pos; + if(lua_isnumber(L,1)) v = &pilot_get((unsigned int)lua_tonumber(L,1))->solid->pos; else if(lua_islightuserdata(L,1)) v = (Vec2*)lua_topointer(L,1); double mod = -10; diff --git a/src/faction.c b/src/faction.c index 3c91d2e..0c7fdbe 100644 --- a/src/faction.c +++ b/src/faction.c @@ -21,7 +21,7 @@ int nfactions = 0; static Faction* faction_parse(xmlNodePtr parent); // Return the faction of name "name". -Faction* get_faction(const char* name) { +Faction* faction_get(const char* name) { int i; for(i = 0; i < nfactions; i++) if(strcmp(faction_stack[i].name, name)==0) @@ -54,6 +54,7 @@ int areAllies(Faction* a, Faction* b) { static Faction* faction_parse(xmlNodePtr parent) { Faction* tmp = CALLOC_L(Faction); tmp->name = (char*)xmlGetProp(parent, (xmlChar*)"name"); + if(tmp->name == NULL) WARN("Faction from "FACTION_DATA" has invalid or no name"); return tmp; } @@ -66,13 +67,13 @@ int factions_load(void) { Faction* tmp = NULL; - node = doc->xmlChildrenNode; // Ships node. + node = doc->xmlChildrenNode; // Faction node. if(strcmp((char*)node->name, XML_FACTION_ID)) { ERR("Malformed "FACTION_DATA" file: missing root element '"XML_FACTION_ID"'"); return -1; } - node = node->xmlChildrenNode; // First ship node. + node = node->xmlChildrenNode; // First faction node. if(node == NULL) { ERR("Malformed "FACTION_DATA" file: does not contain elements"); return -1; @@ -97,6 +98,9 @@ int factions_load(void) { } void factions_free(void) { + int i; + for(i = 0; i < nfactions; i++) + free(faction_stack[i].name); free(faction_stack); nfactions = 0; } diff --git a/src/faction.h b/src/faction.h index c0ff002..55cdf40 100644 --- a/src/faction.h +++ b/src/faction.h @@ -7,7 +7,7 @@ typedef struct Faction { struct Faction** allies; } Faction; -Faction* get_faction(const char* name); +Faction* faction_get(const char* name); int areEnemies(Faction* a, Faction* b); int areAllies(Faction* a, Faction* b); diff --git a/src/main.c b/src/main.c index 2679f6d..65a2d8e 100644 --- a/src/main.c +++ b/src/main.c @@ -249,14 +249,15 @@ int main(int argc, char** argv) { factions_load(); outfit_load(); ships_load(); + fleet_load(); space_load(); // Testing. - pilot_create(get_ship("Ship"), "Player", 0., NULL, NULL, PILOT_PLAYER); + pilot_create(ship_get("Ship"), "Player", 0., NULL, NULL, PILOT_PLAYER); gl_bindCamera(&player->solid->pos); space_init("SaraSys"); - pilot_create(get_ship("Test"), NULL, 2., NULL, NULL, 0); + pilot_create(ship_get("Test"), NULL, 2., NULL, NULL, 0); player_message("Welcome to "APPNAME"!"); player_message(" v%d.%d.%d", VMAJOR, VMINOR, VREV); @@ -282,6 +283,7 @@ int main(int argc, char** argv) { space_exit(); // Clean up the universe!!! pilots_free(); // Free the pilots, they where locked up D: gui_free(); // Free up the gui. + fleet_free(); ships_free(); outfit_free(); factions_free(); diff --git a/src/outfit.c b/src/outfit.c index a8367b3..c893934 100644 --- a/src/outfit.c +++ b/src/outfit.c @@ -125,6 +125,7 @@ static Outfit* outfit_parse(const xmlNodePtr parent) { xmlChar* prop; tmp->name = (char*)xmlGetProp(parent, (xmlChar*)"name"); // Already mallocs. + if(tmp->name == NULL) WARN("Outfit in "OUTFIT_DATA" has invalid or no name"); node = parent->xmlChildrenNode; diff --git a/src/pilot.c b/src/pilot.c index 8c77aff..bccc2ce 100644 --- a/src/pilot.c +++ b/src/pilot.c @@ -1,21 +1,36 @@ #include #include #include -#include +#include // We don't need this? + +#include #include "main.h" #include "log.h" #include "weapon.h" +#include "pack.h" #include "pilot.h" +#define XML_NODE_START 1 +#define XML_NODE_TEXT 3 + +#define XML_ID "Fleets" // XML section identifier. +#define XML_FLEET "fleet" + +#define FLEET_DATA "../dat/fleet.xml" + // Stack of pilot id's to assure uniqueness. static unsigned int pilot_id = 0; // Stack of pilots - yes, they come in stacks now. -Pilot** pilot_stack; +Pilot** pilot_stack = NULL; // Not static, it is used in player.c and weapon.c int pilots = 0; extern Pilot* player; +// Stack of fleets. +static Fleet* fleet_stack = NULL; +static int nfleets = 0; + // External. extern void ai_destroy(Pilot* p); // Ai. extern void player_think(Pilot* pilot); // Player.c @@ -24,9 +39,10 @@ extern void ai_think(Pilot* pilot); // Ai.c static void pilot_update(Pilot* pilot, const double dt); void pilot_render(Pilot* pilot); static void pilot_free(Pilot* p); +static Fleet* fleet_parse(const xmlNodePtr parent); // Get the next pilot based on player_id. -unsigned int pilot_getNext(unsigned int id) { +unsigned int pilot_getNext(const unsigned int id) { int i, n; for(i = 0, n = pilots/2; n > 0; n /= 2) i += (pilot_stack[i+n]->id > id) ? 0 : n; @@ -37,7 +53,7 @@ unsigned int pilot_getNext(unsigned int id) { } // Pull a pilot out of the pilot_stack based on id. -Pilot* get_pilot(unsigned int id) { +Pilot* pilot_get(const unsigned int id) { // Regular search. #if 0 for(int i = 0; i < pilots; i++) @@ -54,7 +70,7 @@ Pilot* get_pilot(unsigned int id) { } // Mkay, this is how we shoot. Listen up. -void pilot_shoot(Pilot* p, int secondary) { +void pilot_shoot(Pilot* p, const int secondary) { int i; if(!secondary) { // Primary weapons. @@ -79,7 +95,7 @@ void pilot_shoot(Pilot* p, int secondary) { } // Damage the pilot. -void pilot_hit(Pilot* p, double damage_shield, double damage_armor) { +void pilot_hit(Pilot* p, const double damage_shield, const double damage_armor) { if(p->shield - damage_shield > 0.) p->shield -= damage_shield; else if(p->shield > 0.) { @@ -262,3 +278,120 @@ void pilots_update(double dt) { } } +// Return the fleet based on 'name' +Fleet* fleet_get(const char* name) { + int i; + for(i = 0; i < nfleets; i++) + if(strcmp(name, fleet_stack[i].name)==0) + return fleet_stack+i; + + return NULL; +} + +// Parse the fleet node. +static Fleet* fleet_parse(const xmlNodePtr parent) { + xmlNodePtr cur, node; + FleetPilot* pilot; + char* c; + node = parent->xmlChildrenNode; + + Fleet* tmp = CALLOC_L(Fleet); + + tmp->name = (char*)xmlGetProp(parent, (xmlChar*)"name"); // Already mallocs. + if(tmp->name == NULL) WARN("Fleet in "FLEET_DATA" has invalid or no name"); + + while((node = node->next)) { + // Load all the data. + if(strcmp((char*)node->name, "faction")==0) + tmp->faction = faction_get((char*)node->children->content); + else if(strcmp((char*)node->name, "pilots")==0) { + cur = node->children; + while((cur = cur->next)) { + if(strcmp((char*)cur->name, "pilot")==0) { + tmp->npilots++; // Pilot count. + pilot = MALLOC_L(FleetPilot); + + // Name is not obligatory. Will only override ship name. + c = (char*)xmlGetProp(cur, (xmlChar*)"name"); // Mallocs. + pilot->name = c; // No need to free here however. + + pilot->ship = ship_get((char*)cur->children->content); + if(pilot->ship == NULL) + WARN("Pilot %s in Fleet %s has null ship", pilot->name, tmp->name); + + c = (char*)xmlGetProp(cur, (xmlChar*)"chance"); // Mallocs. + pilot->chance = atoi(c); + if(pilot->chance == 0) + WARN("Pilot %s in Fleet %s has 0%% chance of appearing", pilot->name, tmp->name); + if(c) free(c); // Free the external malloc. + + tmp->pilots = realloc(tmp->pilots, sizeof(FleetPilot)*tmp->npilots); + memcpy(tmp->pilots+(tmp->npilots-1), pilot, sizeof(FleetPilot)); + free(pilot); + } + } + } + } +#define MELEMENT(o,s) if((o) == NULL) WARN("Fleet '%s' missing '"s"' element", tmp->name) + MELEMENT(tmp->faction, "faction"); + MELEMENT(tmp->pilots, "pilots"); +#undef MELEMENT + + return tmp; +} + +// Load the fleets. +int fleet_load(void) { + uint32_t bufsize; + char* buf = pack_readfile(DATA, FLEET_DATA, &bufsize); + + xmlNodePtr node; + xmlDocPtr doc = xmlParseMemory(buf, bufsize); + + Fleet* tmp = NULL; + + node = doc->xmlChildrenNode; // Ships node. + if(strcmp((char*)node->name, XML_ID)) { + ERR("Malformed "FLEET_DATA" file: missing root element '"XML_ID"'"); + return -1; + } + node = node->xmlChildrenNode; // First ship node. + if(node == NULL) { + ERR("Malformed "FLEET_DATA" file: does not contain elements"); + return -1; + } + + do { + if(node->type == XML_NODE_START && strcmp((char*)node->name, XML_FLEET)==0) { + tmp = fleet_parse(node); + fleet_stack = realloc(fleet_stack, sizeof(Fleet)*(++nfleets)); + memcpy(fleet_stack+nfleets-1, tmp, sizeof(Fleet)); + free(tmp); + } + } while((node = node->next)); + + xmlFreeDoc(doc); + free(buf); + xmlCleanupParser(); + + DEBUG("Loaded %d fleets", nfleets); + + return 0; +} + +// Free the fleets. +void fleet_free(void) { + int i, j; + if(fleet_stack != NULL) { + for(i = 0; i < nfleets; i++) { + for(j = 0; j < fleet_stack[i].npilots; j++) + if(fleet_stack[i].pilots[j].name) + free(fleet_stack[i].pilots[j].name); + free(fleet_stack[i].name); + free(fleet_stack[i].pilots); + } + free(fleet_stack); + } + nfleets = 0; +} + diff --git a/src/pilot.h b/src/pilot.h index e86e388..c8aa366 100644 --- a/src/pilot.h +++ b/src/pilot.h @@ -3,6 +3,7 @@ #include "physics.h" #include "ai.h" #include "outfit.h" +#include "faction.h" #include "ship.h" // Aproximation for pilot size. @@ -44,14 +45,30 @@ typedef struct Pilot { Task* task; // Current action. } Pilot; +// Fleets. +typedef struct { + Ship* ship; // Ship that the pilot is flying. + char* name; // For special 'unique' names. + int chance; // Chance of this pilot appearing in the fleet. +} FleetPilot; + +typedef struct { + char* name; // Fleet name, used as an identifier. + Faction* faction; // Faction of the fleet. + + FleetPilot* pilots; // The pilots in the fleet. + int npilots; // Total number of pilots. +} Fleet; + // Grabing pilot crap. extern Pilot* player; // The player. -Pilot* get_pilot(unsigned int id); +Pilot* pilot_get(unsigned int id); unsigned int pilot_getNext(unsigned int id); +Fleet* fleet_get(const char* name); // MISC. -void pilot_shoot(Pilot* p, int secondary); -void pilot_hit(Pilot* p, double damage_shield, double damage_armor); +void pilot_shoot(Pilot* p, const int secondary); +void pilot_hit(Pilot* p, const double damage_shield, const double damage_armor); // Creation. void pilot_init(Pilot* dest, Ship* ship, char* name, const double dir, @@ -60,9 +77,11 @@ void pilot_init(Pilot* dest, Ship* ship, char* name, const double dir, unsigned int pilot_create(Ship* ship, char* name, const double dir, const Vec2* pos, const Vec2* vel, const int flags); -// Cleanup. +// Init/Cleanup. void pilot_destroy(Pilot* p); void pilots_free(void); +int fleet_load(void); +void fleet_free(void); // Update. void pilots_update(double dt); diff --git a/src/player.c b/src/player.c index f853d6b..69263d4 100644 --- a/src/player.c +++ b/src/player.c @@ -136,7 +136,7 @@ void player_render(void) { // Render the player target graphics. if(player_target) { - p = get_pilot(player_target); + p = pilot_get(player_target); vect_csetmin(&v, VX(p->solid->pos) - p->ship->gfx_space->sw * PILOT_SIZE_APROX/2., VY(p->solid->pos) + p->ship->gfx_space->sh * PILOT_SIZE_APROX/2.); diff --git a/src/ship.c b/src/ship.c index da6d260..417a121 100644 --- a/src/ship.c +++ b/src/ship.c @@ -23,7 +23,7 @@ static int ships = 0; static Ship* ship_parse(xmlNodePtr parent); // Get a ship based on it's name. -Ship* get_ship(const char* name) { +Ship* ship_get(const char* name) { Ship* tmp = ship_stack; int i; for(i = 0; i < ships; i++) @@ -44,6 +44,7 @@ static Ship* ship_parse(xmlNodePtr parent) { xmlChar* xstr; tmp->name = (char*)xmlGetProp(parent, (xmlChar*)"name"); + if(tmp->name == NULL) WARN("Ship in "SHIP_DATA" has invalid or no name"); node = parent->xmlChildrenNode; diff --git a/src/ship.h b/src/ship.h index 3c6cdb1..0e7cbcd 100644 --- a/src/ship.h +++ b/src/ship.h @@ -53,5 +53,5 @@ typedef struct { int ships_load(void); void ships_free(void); -Ship* get_ship(const char* name); +Ship* ship_get(const char* name); diff --git a/src/space.c b/src/space.c index 4123835..e39c2bc 100644 --- a/src/space.c +++ b/src/space.c @@ -8,6 +8,7 @@ #include "rng.h" #include "pilot.h" #include "pack.h" +#include "faction.h" #include "space.h" #define XML_NODE_START 1 @@ -33,6 +34,7 @@ // Planet types. I didn't take them from Star Trek, I promise. typedef enum { + PLANET_CLASS_NULL = 0, PLANET_CLASS_A, // Geothermal. PLANET_CLASS_B, // Geomorteus. PLANET_CLASS_C, // Geoinactive. @@ -55,34 +57,42 @@ typedef enum { PLANET_CLASS_T, // Ultragiant. PLANET_CLASS_X, // Demon. PLANET_CLASS_Y, // Demon. - PLANER_CLASS_Z // Demon. + PLANET_CLASS_Z // Demon. } PlanetClass; typedef struct { - char* name; + char* name; // Planet name Vec2 pos; // Position in star system. - PlanetClass class; + + PlanetClass class; // Planet type. + Faction* faction; // Planet faction. gl_texture* gfx_space; // Graphics in space. } Planet; +// Star systems. typedef struct { - char* name; + Fleet* fleet; // Fleet to appear. + int chance; // Chance of fleet appearing in the system. +} SystemFleet; + +typedef struct { + char* name; // Star system identifier. Vec2 pos; // Position. int stars, asteroids; // Un numero! double interference; // Un uh.. Percentage. - // Factions. Planet* planets; // Planets. - int nplanets; + int nplanets; // Total number of planets. - // TODO: Throw some fleets here. + SystemFleet* fleets; // Fleets that can appear in the current system. + int nfleets; // Total number of fleets. } StarSystem; static StarSystem* systems = NULL; static int nsystems = 0; static StarSystem* cur_system = NULL; // Current star system. -#define STAR_BUF 100 // Area to leave around screen. +#define STAR_BUF 100 // Area to leave around screen, more = less repitition. typedef struct { double x, y; // Position. It is simpler ligher to use two doubles than the physics. double brightness; @@ -93,8 +103,10 @@ static int nstars = 0; // Total stars. static Planet* planet_get(const char* name); static StarSystem* system_parse(const xmlNodePtr parent); +static PlanetClass planetclass_get(const char a); // Draw the planet. Used in planet.c +// Matrix mode is already displaced to center of the minimap. #define PIXEL(x,y) if(ABS(x)children; while((cur = cur->next)) { if(strcmp((char*)cur->name, "class")==0) - tmp->class = atoi((char*)cur->children->content); + tmp->class = planetclass_get(cur->children->content[0]); + else if(strcmp((char*)cur->name, "faction")==0) + tmp->faction = faction_get((char*)cur->children->content); } } } @@ -251,6 +295,7 @@ static Planet* planet_get(const char* name) { MELEMENT(flags&FLAG_XSET, "x"); MELEMENT(flags&FLAG_YSET, "y"); MELEMENT(tmp->class, "class"); + MELEMENT(tmp->faction, "faction"); #undef MELEMENT } else WARN("No planet found matching name '%s'", name); @@ -262,7 +307,9 @@ static Planet* planet_get(const char* name) { // 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; @@ -301,17 +348,41 @@ static StarSystem* system_parse(const xmlNodePtr parent) { } } } + // Load all the planets. else if(strcmp((char*)node->name, "planets")==0) { cur = node->children; while((cur = cur->next)) { if(strcmp((char*)cur->name, "planet")==0) { planet = planet_get((const char*)cur->children->content); tmp->planets = realloc(tmp->planets, sizeof(Planet)*(++tmp->nplanets)); - memcpy(tmp->planets+tmp->nplanets-1, planet, sizeof(Planet)); + memcpy(tmp->planets+(tmp->nplanets-1), planet, sizeof(Planet)); free(planet); } } } + // Load all the fleets. + else if(strcmp((char*)node->name, "fleets")==0) { + cur = node->children; + while((cur = cur->next)) { + if(strcmp((char*)cur->name, "fleet")==0) { + fleet = CALLOC_L(SystemFleet); + fleet->fleet = fleet_get((const char*)cur->children->content); + if(fleet->fleet == NULL) + WARN("Fleet %s for Star System %s not found", (char*)cur->children->content, tmp->name); + + ptrc = (char*)xmlGetProp(cur, (xmlChar*)"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); + } + } + } } // Check elements. #define MELEMENT(o,s) if((o) == 0) WARN("Star System '%s' missing '"s"' element", tmp->name) @@ -402,6 +473,8 @@ void space_exit(void) { free(systems[i].planets[j].name); if(systems[i].planets[j].gfx_space) gl_freeTexture(systems[i].planets[j].gfx_space); + if(systems[i].fleets) + free(systems[i].fleets); } free(systems[i].planets); }