208 lines
5.3 KiB
C
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;
|
|
}
|
|
|