From 0c1f50a2fff4e6d29d19d11ee32be0b33d16f8b2 Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Tue, 21 Jan 2014 20:07:29 +0000
Subject: [PATCH] [Change] Improved outfit loading somewhat.

---
 src/outfit.c | 59 ++++++++++++++++++++++++++++++++--------------------
 src/outfit.h | 12 +++++++----
 src/pause.c  | 14 ++++++++++---
 src/pilot.c  | 14 ++++++-------
 4 files changed, 62 insertions(+), 37 deletions(-)

diff --git a/src/outfit.c b/src/outfit.c
index b089dea..a261e4b 100644
--- a/src/outfit.c
+++ b/src/outfit.c
@@ -18,6 +18,8 @@
 #define OUTFIT_DATA     "../dat/outfit.xml"
 #define OUTFIT_GFX      "../gfx/outfit/"
 
+#define CHUNK_SIZE      64 /** Size to reallocate by. */
+
 /* The Stack. */
 static Outfit* outfit_stack = NULL;
 static int outfit_nstack    = 0;
@@ -27,7 +29,7 @@ static DamageType outfit_strToDamageType(char* buf);
 static OutfitType outfit_strToOutfitType(char* buf);
 /* Parsing. */
 static int outfit_parseDamage(DamageType* dtype, double* dmg, xmlNodePtr node);
-static Outfit* outfit_parse(const xmlNodePtr parent);
+static int outfit_parse(Outfit* tmp, const xmlNodePtr parent);
 static void outfit_parseSBolt(Outfit* tmp, const xmlNodePtr parent);
 static void outfit_parseSBeam(Outfit* tmp, const xmlNodePtr parent);
 static void outfit_parseSLauncher(Outfit* tmp, const xmlNodePtr parent);
@@ -368,12 +370,10 @@ int outfit_delay(const Outfit* o) {
 }
 
 /**
- * @fn char* outfit_ammo(const Outfit* o)
- *
  * @brief Get the outfits ammo.
  *    @param o Outfit to get information from.
  */
-char* outfit_ammo(const Outfit* o) {
+Outfit* outfit_ammo(const Outfit* o) {
   if(outfit_isLauncher(o)) return o->u.lau.ammo;
   else if(outfit_isFighterBay(o)) return o->u.bay.ammo;
   return NULL;
@@ -671,12 +671,12 @@ static void outfit_parseSLauncher(Outfit* tmp, const xmlNodePtr parent) {
   do {
     /* Load the dataz. */
     xmlr_int(node, "delay", tmp->u.lau.delay);
-    xmlr_strd(node, "ammo", tmp->u.lau.ammo);
+    xmlr_strd(node, "ammo", tmp->u.lau.ammo_name);
   } while((node = node->next));
 
 #define MELEMENT(o,s) if(o) WARN("Outfit '%s' missing '"s"' element", tmp->name)
-  MELEMENT(tmp->u.lau.ammo == NULL, "ammo");
-  MELEMENT(tmp->u.lau.delay==0,   "delay");
+  MELEMENT(tmp->u.lau.ammo_name == NULL,  "ammo");
+  MELEMENT(tmp->u.lau.delay==0,           "delay");
 #undef MELEMENT
 }
 
@@ -792,13 +792,13 @@ static void outfit_parseSFighterBay(Outfit* tmp, const xmlNodePtr parent) {
 
   do {
     xmlr_int(node, "delay", tmp->u.bay.delay);
-    xmlr_strd(node, "ammo", tmp->u.bay.ammo);
+    xmlr_strd(node, "ammo", tmp->u.bay.ammo_name);
   } while(xml_nextNode(node));
 
 #define MELEMENT(o,s) \
 if(o) WARN("Outfit '%s' missing/invalid '"s"' element", tmp->name)
-  MELEMENT(tmp->u.bay.delay==0,   "delay");
-  MELEMENT(tmp->u.bay.ammo==NULL, "ammo");
+  MELEMENT(tmp->u.bay.delay==0,         "delay");
+  MELEMENT(tmp->u.bay.ammo_name==NULL,  "ammo");
 #undef MELEMENT
 }
 
@@ -857,12 +857,14 @@ static void outfit_parseSJammer(Outfit* tmp, const xmlNodePtr parent) {
 }
 
 /* Parse and return Outfits from parent node. */
-static Outfit* outfit_parse(const xmlNodePtr parent) {
-  Outfit* tmp = CALLOC_L(Outfit);
+static int outfit_parse(Outfit* tmp, const xmlNodePtr parent) {
   xmlNodePtr cur, node;
   char* prop;
   char str[PATH_MAX] = "\0";
 
+  /* Clear data. */
+  memset(tmp, 0, sizeof(Outfit));
+
   tmp->name = xml_nodeProp(parent, "name"); /* Already malloced. */
   if(tmp->name == NULL) WARN("Outfit in "OUTFIT_DATA" has invalid or no name");
 
@@ -934,16 +936,15 @@ static Outfit* outfit_parse(const xmlNodePtr parent) {
   MELEMENT(tmp->description==NULL,  "description");
 #undef MELEMENT
 
-  return tmp;
+  return 0;
 }
 
 /* Load all the outfits into the outfit stack. */
 int outfit_load(void) {
+  int i, mem;
   uint32_t bufsize;
   char* buf = pack_readfile(DATA, OUTFIT_DATA, &bufsize);
 
-  Outfit* tmp;
-
   xmlNodePtr node;
   xmlDocPtr doc = xmlParseMemory(buf, bufsize);
 
@@ -959,15 +960,27 @@ int outfit_load(void) {
     return -1;
   }
 
+  /* First pass, load up ammunition. */
+  mem = 0;
   do {
     if(xml_isNode(node,  XML_OUTFIT_TAG)) {
-      tmp = outfit_parse(node);
-      outfit_stack = realloc(outfit_stack, sizeof(Outfit)*(++outfit_nstack));
-      memmove(outfit_stack+outfit_nstack-1, tmp, sizeof(Outfit));
-      free(tmp);
+      outfit_nstack++;
+      if(outfit_nstack > mem) {
+        mem += CHUNK_SIZE;
+        outfit_stack = realloc(outfit_stack, sizeof(Outfit)*mem);
+      }
+      outfit_parse(&outfit_stack[outfit_nstack-1], node);
     }
   } while((node = node->next));
 
+  /* Second pass, set up ammunition relationships. */
+  for(i = 0; i < outfit_nstack; i++) {
+    if(outfit_isLauncher(&outfit_stack[i]))
+      outfit_stack[i].u.lau.ammo = outfit_get(outfit_stack[i].u.lau.ammo_name);
+    else if(outfit_isFighterBay(&outfit_stack[i]))
+      outfit_stack[i].u.bay.ammo = outfit_get(outfit_stack[i].u.bay.ammo_name);
+  }
+
   xmlFreeDoc(doc);
   free(buf);
 
@@ -988,10 +1001,10 @@ void outfit_free(void) {
       gl_freeTexture(outfit_gfx(&outfit_stack[i]));
 
     /* Type specification. */
-    if(outfit_isLauncher(o) && o->u.lau.ammo)
-      free(o->u.lau.ammo);
-    if(outfit_isFighterBay(o) && o->u.bay.ammo)
-      free(o->u.bay.ammo);
+    if(outfit_isLauncher(o) && o->u.lau.ammo_name)
+      free(o->u.lau.ammo_name);
+    if(outfit_isFighterBay(o) && o->u.bay.ammo_name)
+      free(o->u.bay.ammo_name);
     if(outfit_isFighter(o) && o->u.fig.ship)
       free(o->u.fig.ship);
 
diff --git a/src/outfit.h b/src/outfit.h
index d9b1267..b6ea718 100644
--- a/src/outfit.h
+++ b/src/outfit.h
@@ -6,6 +6,8 @@
 /* Property flags. */
 #define OUTFIT_PROP_WEAP_SECONDARY (1<<0) /**< Is a secondary weapon? */
 
+struct Outfit_;
+
 /**
  * @enum OutfitType
  *
@@ -107,7 +109,8 @@ typedef struct OutfitBeamData_ {
  */
 typedef struct OutfitLauncherData_ {
   unsigned int delay;   /**< Delay between shots. */
-  char* ammo;           /**< The ammo to use. */
+  char* ammo_name;      /**< The ammo to use. */
+  struct Outfit_* ammo; /**< Ammo to use. */
 } OutfitLauncherData;
 
 /**
@@ -179,8 +182,9 @@ typedef struct OutfitAfterburnerData_ {
  * @brief Represents a fighter bay.
  */
 typedef struct OutfitFighterBayData_ {
-  char* ammo;     /**< Ships to use as ammo. */
-  double delay;   /**< Delay between launches. */
+  char* ammo_name;        /**< Ships to use as ammo. */
+  struct Outfit_* ammo;   /**< Ships to use as ammo. */
+  double delay;           /**< Delay between launches. */
 } OutfitFighterBayData;
 
 /**
@@ -282,7 +286,7 @@ int outfit_spfx(const Outfit* o);
 double outfit_damage(const Outfit* o);
 DamageType outfit_damageType(const Outfit* o);
 int outfit_delay(const Outfit* o);
-char* outfit_ammo(const Outfit* o);
+Outfit* outfit_ammo(const Outfit* o);
 double outfit_energy(const Outfit* o);
 double outfit_range(const Outfit* o);
 double outfit_speed(const Outfit* o);
diff --git a/src/pause.c b/src/pause.c
index 240fff5..c46020b 100644
--- a/src/pause.c
+++ b/src/pause.c
@@ -1,9 +1,17 @@
+/**
+ * @file pause.c
+ *
+ * @brief Handles pausing and resuming the game.
+ *
+ * Main trick to pausing/unpausing is to allow things based on time
+ * to behave properly when the toolkit opens a window.
+ *
+ * @todo Should probably be eliminated by making everything use the dt system.
+ */
+
 #include "pilot.h"
 #include "pause.h"
 
-/* Main thing with pausing is to allow things based on time to */
-/* work properly when the toolkit opens a window. */
-
 int paused = 0; /* Are we paused. */
 
 /* From pilot.c */
diff --git a/src/pilot.c b/src/pilot.c
index 635af8d..f4806ab 100644
--- a/src/pilot.c
+++ b/src/pilot.c
@@ -548,7 +548,7 @@ void pilot_setSecondary(Pilot* p, const char* secondary) {
  */
 void pilot_setAmmo(Pilot* p) {
   int i;
-  char* name;
+  Outfit* ammo;
 
   /* Weapon must use ammo. */
   if((p->secondary == NULL) || (outfit_ammo(p->secondary->outfit)==NULL)) {
@@ -557,9 +557,9 @@ void pilot_setAmmo(Pilot* p) {
   }
 
   /* Find the ammo and set it. */
-  name = outfit_ammo(p->secondary->outfit);
+  ammo = outfit_ammo(p->secondary->outfit);
   for(i = 0; i < p->noutfits; i++)
-    if(strcmp(p->outfits[i].outfit->name, name)==0) {
+    if(p->outfits[i].outfit == ammo) {
       p->ammo = &p->outfits[i];
       return;
     }
@@ -576,16 +576,16 @@ void pilot_setAmmo(Pilot* p) {
  */
 int pilot_getAmmo(Pilot* p, Outfit* o) {
   int i;
-  char* name;
+  Outfit* ammo;
 
   /* Must be a launcher. */
   if(!outfit_isLauncher(o))
     return 0;
 
   /* Try to find the ammo. */
-  name = o->u.lau.ammo;
+  ammo = o->u.lau.ammo;
   for(i = 0; i < p->noutfits; i++)
-    if(strcmp(p->outfits[i].outfit->name, name)==0)
+    if(p->outfits[i].outfit == ammo)
       return p->outfits[i].quantity;
 
   /* Assume none. */
@@ -632,7 +632,7 @@ int pilot_dock(Pilot* p, Pilot* target) {
   /* Check to see if target has an available bay. */
   for(i = 0; i < target->noutfits; i++) {
     if(outfit_isFighterBay(target->outfits[i].outfit)) {
-      o = outfit_get(outfit_ammo(target->outfits[i].outfit));
+      o = outfit_ammo(target->outfits[i].outfit);
       if(outfit_isFighter(o) &&
           (strcmp(p->ship->name, o->u.fig.ship)==0))
         break;