Lephisto/src/fleet.c
2014-10-18 22:26:05 +01:00

208 lines
5.3 KiB
C

/**
* @file pilot.c
*
* @brief Handles the pilot stuff.
*/
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <limits.h>
#include "lxml.h"
#include "lephisto.h"
#include "log.h"
#include "weapon.h"
#include "ldata.h"
#include "spfx.h"
#include "rng.h"
#include "hook.h"
#include "map.h"
#include "explosion.h"
#include "escort.h"
#include "music.h"
#include "pilot.h"
#define XML_ID "Fleets" /**< XML document identifier. */
#define XML_FLEET "fleet" /**< XML individual fleet identifier. */
#define FLEET_DATA "../dat/fleet.xml" /**< Where to find fleet data. */
#define CHUNK_SIZE 32 /**< Size to allocate memory by. */
/* Stack of fleets. */
static Fleet* fleet_stack = NULL; /**< Fleet stack. */
static int nfleets = 0; /**< Number of fleets. */
/**
* @brief Grabs a fleet out of the stack.
* @param name Name of the fleet to match.
* @return The fleet mactching name or NULL if not found.
*/
Fleet* fleet_get(const char* name) {
int i;
for(i = 0; i < nfleets; i++)
if(strcmp(fleet_stack[i].name, name)==0)
return &fleet_stack[i];
WARN("Fleet '%s' not found in stack", name);
return NULL;
}
/**
* @brief Parses the fleet node.
* @param tmp Fleet to load.
* @param parent Parent xml node of the fleet in question.
* @return A newly allocated fleet loaded with data in parent node.
*/
static int fleet_parse(Fleet* tmp, const xmlNodePtr parent) {
xmlNodePtr cur, node;
FleetPilot* pilot;
char* c;
int mem;
node = parent->xmlChildrenNode;
/* Sane defaults and clean up. */
memset(tmp, 0, sizeof(Fleet));
tmp->faction = -1;
tmp->name = (char*)xmlGetProp(parent, (xmlChar*)"name"); /* Already mallocs. */
if(tmp->name == NULL) WARN("Fleet in "FLEET_DATA" has invalid or no name");
do { /* Load all the data. */
if(xml_isNode(node, "faction"))
tmp->faction = faction_get(xml_get(node));
else if(xml_isNode(node, "ai"))
tmp->ai = xml_getStrd(node);
else if(xml_isNode(node, "pilots")) {
cur = node->children;
mem = 0;
do {
if(xml_isNode(cur, "pilot")) {
/* See if must grow. */
tmp->npilots++;
if(tmp->npilots > mem) {
mem += CHUNK_SIZE;
tmp->pilots = realloc(tmp->pilots, mem * sizeof(FleetPilot));
}
pilot = &tmp->pilots[tmp->npilots-1];
/* Clear memory. */
memset(pilot, 0, sizeof(FleetPilot));
/* Check for name override. */
xmlr_attr(cur, "name", c);
pilot->name = c; /* No need to free since it will have later. */
/* Check for ai override. */
xmlr_attr(cur, "ai", pilot->ai);
/* Load pilots ship. */
pilot->ship = ship_get(xml_get(cur));
if(pilot->ship == NULL)
WARN("Pilot %s in Fleet %s has null ship", pilot->name, tmp->name);
/* Load chance. */
xmlr_attr(cur, "chance", c);
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 != NULL)
free(c); /* Free the external malloc. */
}
} while(xml_nextNode(cur));
/* Resize to minimum. */
tmp->pilots = realloc(tmp->pilots, sizeof(FleetPilot)*tmp->npilots);
}
} while(xml_nextNode(node));
#define MELEMENT(o,s) \
if(o) WARN("Fleet '%s' missing '"s"' element", tmp->name)
/**< Hack to check for missing fields. */
MELEMENT(tmp->ai == NULL, "ai");
MELEMENT(tmp->faction == -1, "faction");
MELEMENT(tmp->pilots == NULL, "pilots");
#undef MELEMENT
return 0;
}
/**
* @brief Loads all the fleets.
* @return 0 on success.
*/
int fleet_load(void) {
int mem;
uint32_t bufsize;
char* buf = ldata_read(FLEET_DATA, &bufsize);
xmlNodePtr node;
xmlDocPtr doc = xmlParseMemory(buf, bufsize);
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;
}
mem = 0;
do {
if(xml_isNode(node, XML_FLEET)) {
/* See if memory must grow. */
nfleets++;
if(nfleets > mem) {
mem += CHUNK_SIZE;
fleet_stack = realloc(fleet_stack, sizeof(Fleet) * mem);
}
/* Load the fleet. */
fleet_parse(&fleet_stack[nfleets-1], node);
}
} while(xml_nextNode(node));
/* Shrink to minimum. */
fleet_stack = realloc(fleet_stack, sizeof(Fleet) * nfleets);
xmlFreeDoc(doc);
free(buf);
DEBUG("Loaded %d Fleets%s", nfleets, (nfleets == 1) ? "" : "s");
return 0;
}
/**
* @brief Cleans up by freeing all the fleet data.
*/
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);
if(fleet_stack[i].pilots[j].ai)
free(fleet_stack[i].pilots[j].ai);
}
free(fleet_stack[i].name);
free(fleet_stack[i].pilots);
free(fleet_stack[i].ai);
}
free(fleet_stack);
fleet_stack = NULL;
}
nfleets = 0;
}