/** * @file pilot.c * * @brief Handles the pilot stuff. */ #include #include #include #include #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; }