From 943cbecf704663906658f9c1faa1403fedd63c36 Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Fri, 8 Feb 2013 14:26:53 +0000
Subject: [PATCH] [Add] Fleets. Not actually making use of them yet though.
 [Add] More error checking for XML files

---
 dat/faction.xml |   2 +
 dat/fleet.xml   |   6 +-
 dat/planet.xml  |   6 +-
 dat/ssys.xml    |   2 -
 src/ai.c        |   4 +-
 src/faction.c   |  10 +++-
 src/faction.h   |   2 +-
 src/main.c      |   6 +-
 src/outfit.c    |   1 +
 src/pilot.c     | 145 ++++++++++++++++++++++++++++++++++++++++++++++--
 src/pilot.h     |  27 +++++++--
 src/player.c    |   2 +-
 src/ship.c      |   3 +-
 src/ship.h      |   2 +-
 src/space.c     |  93 +++++++++++++++++++++++++++----
 15 files changed, 273 insertions(+), 38 deletions(-)

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 @@
 <Factions>
   <faction name = "Player">
 	</faction>
+  <faction name = "Independent">
+  </faction>
   <faction name = "Merchant">
   </faction>
   <faction name = "Pirate">
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 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Fleets>
   <fleet name="Test">
-    <faction>2</faction>
+    <faction>Independent</faction>
       <pilots>
         <pilot chance='100'>Test</pilot>
       </pilots>
   </fleet>
   <fleet name="Merchant Ship">
-  <faction>2</faction>
+  <faction>Merchant</faction>
     <pilots>
       <pilot chance='100'>Ship</pilot>
     </pilots>
   </fleet>
   <fleet name="Sml Merchant Convoy">
-    <faction>2</faction>
+    <faction>Merchant</faction>
     <pilots>
       <pilot chance='80'>Ship</pilot>
       <pilot chance='80'>Ship</pilot>
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 @@
 			<y>15</y>
 		</pos>
 		<general>
-			<class>1</class>
+			<class>A</class>
+      <faction>Independent</faction>
 			<services>1</services>
 			<tech>0</tech>
 			<commodities>1</commodities>
@@ -19,7 +20,8 @@
 			<y>-345</y>
 		</pos>
 		<general>
-			<class>1</class>
+			<class>A</class>
+      <faction>Independent</faction>
 			<services>1</services>
 			<tech>0</tech>
 			<commodities>1</commodities>
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 @@
 			<stars>500</stars>
 			<asteroids>0</asteroids>
 			<interference>0</interference>
-			<faction>2</faction>
 		</general>
 		<planets>
 			<planet>KonoSphere</planet>
@@ -32,7 +31,6 @@
 			<stars>27</stars>
 			<asteroids>0</asteroids>
 			<interference>0</interference>
-			<faction>2</faction>
 		</general>
 		<planets>
 			<planet>SaraCraft</planet>
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 <string.h>
 #include <math.h>
 #include <stdlib.h>
-#include <assert.h>
+#include <assert.h> // We don't need this?
+
+#include <libxml/parser.h>
 
 #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)<w/2. && ABS(y)<h/2.) glVertex2i((x),(y))
 void planets_minimap(double res, double w, double h) {
   int i;
@@ -151,6 +163,36 @@ void planets_minimap(double res, double w, double h) {
 }
 #undef PIXEL
 
+static PlanetClass planetclass_get(const char a) {
+  switch(a) {
+    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;
+
+    default: return PLANET_CLASS_NULL;
+  };
+}
+
 // Init the system.
 void space_init(const char* sysname) {
   int i;
@@ -231,7 +273,9 @@ static Planet* planet_get(const char* name) {
             cur = node->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);
   }