209 lines
6.7 KiB
C
209 lines
6.7 KiB
C
#include <string.h>
|
|
|
|
#include "main.h"
|
|
#include "log.h"
|
|
#include "pack.h"
|
|
#include "xml.h"
|
|
#include "ship.h"
|
|
|
|
#define XML_ID "Ships" // XML section identifier.
|
|
#define XML_SHIP "ship"
|
|
|
|
#define SHIP_DATA "../dat/ship.xml"
|
|
#define SHIP_GFX "../gfx/ship/"
|
|
#define SHIP_EXT ".png"
|
|
#define SHIP_TARGET "_target"
|
|
|
|
static Ship* ship_stack = NULL;
|
|
static int ships = 0;
|
|
|
|
static Ship* ship_parse(xmlNodePtr parent);
|
|
|
|
// Get a ship based on it's name.
|
|
Ship* ship_get(const char* name) {
|
|
Ship* tmp = ship_stack;
|
|
int i;
|
|
for(i = 0; i < ships; i++)
|
|
if(strcmp((tmp+i)->name, name)==0) break;
|
|
|
|
if(i == ships) // Ship doesn't exist, game will probably crash now.
|
|
WARN("Ship %s does not exist", name);
|
|
|
|
return tmp+i;
|
|
}
|
|
|
|
static Ship* ship_parse(xmlNodePtr parent) {
|
|
xmlNodePtr cur, node;
|
|
Ship* tmp = CALLOC_L(Ship);
|
|
ShipOutfit* otmp, *ocur;
|
|
|
|
char str[PATH_MAX] = "\0";
|
|
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;
|
|
|
|
do {
|
|
// Load all the data.
|
|
if(strcmp((char*)node->name, "GFX")==0) {
|
|
snprintf(str, strlen((char*)node->children->content)+sizeof(SHIP_GFX)+sizeof(SHIP_EXT),
|
|
SHIP_GFX"%s"SHIP_EXT, (char*)node->children->content);
|
|
tmp->gfx_space = gl_newSprite(str, 6, 6);
|
|
// Target.
|
|
snprintf(str, strlen((char*)node->children->content)+sizeof(SHIP_GFX)+sizeof(SHIP_TARGET)+sizeof(SHIP_EXT),
|
|
SHIP_GFX"%s"SHIP_TARGET SHIP_EXT, (char*)node->children->content);
|
|
tmp->gfx_target = gl_newImage(str);
|
|
|
|
}
|
|
else if(strcmp((char*)node->name, "GUI")==0)
|
|
tmp->gui = strdup((char*)node->children->content);
|
|
else if(strcmp((char*)node->name, "class")==0)
|
|
tmp->class = atoi((char*)node->children->content);
|
|
else if(strcmp((char*)node->name, "movement")==0) {
|
|
cur = node->children;
|
|
do {
|
|
if(strcmp((char*)cur->name, "thrust")==0)
|
|
tmp->thrust = atoi((char*)cur->children->content);
|
|
else if(strcmp((char*)cur->name, "turn")==0)
|
|
tmp->turn = atoi((char*)cur->children->content);
|
|
else if(strcmp((char*)cur->name, "speed")==0)
|
|
tmp->speed = atoi((char*)cur->children->content);
|
|
} while((cur = cur->next));
|
|
}
|
|
else if(strcmp((char*)node->name, "health")==0) {
|
|
cur = node->children;
|
|
do {
|
|
if(strcmp((char*)cur->name, "armor")==0)
|
|
tmp->armor = (double)atoi((char*)cur->children->content);
|
|
else if(strcmp((char*)cur->name, "shield")==0)
|
|
tmp->shield = (double)atoi((char*)cur->children->content);
|
|
else if(strcmp((char*)cur->name, "energy")==0)
|
|
tmp->energy = (double)atoi((char*)cur->children->content);
|
|
else if(strcmp((char*)cur->name, "armor_regen")==0)
|
|
tmp->armor_regen = (double)(atoi((char*)cur->children->content))/60.0;
|
|
else if(strcmp((char*)cur->name, "shield_regen")==0)
|
|
tmp->shield_regen = (double)(atoi((char*)cur->children->content))/60.0;
|
|
else if(strcmp((char*)cur->name, "energy_regen")==0)
|
|
tmp->energy_regen = (double)(atoi((char*)cur->children->content))/60.0;
|
|
} while((cur = cur->next));
|
|
}
|
|
else if(strcmp((char*)node->name, "characteristics")==0) {
|
|
cur = node->children;
|
|
do {
|
|
if(strcmp((char*)cur->name, "crew")==0)
|
|
tmp->crew = atoi((char*)cur->children->content);
|
|
else if(strcmp((char*)cur->name, "mass")==0)
|
|
tmp->mass = (double)atoi((char*)cur->children->content);
|
|
else if(strcmp((char*)cur->name, "cap_weapon")==0)
|
|
tmp->cap_weapon = atoi((char*)cur->children->content);
|
|
else if(strcmp((char*)cur->name, "cap_cargo")==0)
|
|
tmp->cap_cargo = atoi((char*)cur->children->content);
|
|
} while((cur = cur->next));
|
|
}
|
|
else if(strcmp((char*)node->name, "outfits")==0) {
|
|
cur = node->children;
|
|
do {
|
|
if(strcmp((char*)cur->name, "outfit")==0) {
|
|
otmp = MALLOC_L(ShipOutfit);
|
|
otmp->data = outfit_get((char*)cur->children->content);
|
|
xstr = xmlGetProp(cur, (xmlChar*)"quantity");
|
|
if(!xstr)
|
|
WARN("Ship '%s' is missing tag 'quantity for outfit '%s'", tmp->name, otmp->data->name);
|
|
otmp->quantity = atoi((char*)xstr);
|
|
free(xstr);
|
|
otmp->next = NULL;
|
|
|
|
if((ocur = tmp->outfit) == NULL) tmp->outfit = otmp;
|
|
else {
|
|
while(ocur->next);
|
|
ocur->next = otmp;
|
|
}
|
|
}
|
|
} while((cur = cur->next));
|
|
}
|
|
} while((node = node->next));
|
|
|
|
tmp->thrust *= tmp->mass; // Helps keep number sane.
|
|
|
|
#define MELEMENT(o,s) if(o == 0) WARN("Ship '%s' missing '"s"' element", tmp->name)
|
|
if(tmp->name == NULL) WARN("Ship '%s' missing 'name' tag", tmp->name);
|
|
if(tmp->gfx_space == NULL) WARN("Ship '%s' missing 'GFX' element", tmp->name);
|
|
MELEMENT(tmp->thrust, "thrust");
|
|
MELEMENT(tmp->turn, "turn");
|
|
MELEMENT(tmp->speed, "speed");
|
|
MELEMENT(tmp->crew, "crew");
|
|
MELEMENT(tmp->mass, "mass");
|
|
MELEMENT(tmp->armor, "armor");
|
|
MELEMENT(tmp->armor_regen, "armor_regen");
|
|
MELEMENT(tmp->shield, "shield");
|
|
MELEMENT(tmp->shield_regen, "shield_regen");
|
|
MELEMENT(tmp->energy, "energy");
|
|
MELEMENT(tmp->energy_regen, "energt_regen");
|
|
MELEMENT(tmp->cap_cargo, "cap_cargo");
|
|
MELEMENT(tmp->cap_weapon, "cap_weapon");
|
|
#undef MELEMENT
|
|
|
|
DEBUG("Loaded ship '%s'", tmp->name);
|
|
return tmp;
|
|
|
|
}
|
|
|
|
int ships_load(void) {
|
|
uint32_t bufsize;
|
|
char* buf = pack_readfile(DATA, SHIP_DATA, &bufsize);
|
|
|
|
xmlNodePtr node;
|
|
xmlDocPtr doc = xmlParseMemory(buf, bufsize);
|
|
|
|
Ship* tmp = NULL;
|
|
|
|
node = doc->xmlChildrenNode; // Ships node.
|
|
if(strcmp((char*)node->name, XML_ID)) {
|
|
ERR("Malformed "SHIP_DATA" file: missing root element '"XML_ID"'");
|
|
return -1;
|
|
}
|
|
|
|
node = node->xmlChildrenNode; // First ship node.
|
|
if(node == NULL) {
|
|
ERR("Malformed "SHIP_DATA" file: Does not contain elements");
|
|
return -1;
|
|
}
|
|
|
|
do {
|
|
if(node->type == XML_NODE_START && strcmp((char*)node->name, XML_SHIP)==0) {
|
|
tmp = ship_parse(node);
|
|
ship_stack = realloc(ship_stack, sizeof(Ship)*(++ships));
|
|
memcpy(ship_stack+ships-1, tmp, sizeof(Ship));
|
|
free(tmp);
|
|
}
|
|
} while((node = node->next));
|
|
|
|
xmlFreeDoc(doc);
|
|
free(buf);
|
|
xmlCleanupParser();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ships_free(void) {
|
|
ShipOutfit* so, *sot;
|
|
int i;
|
|
for(i = 0; i < ships; i++) {
|
|
if((ship_stack+i)->name) // Free the name.
|
|
free((ship_stack+i)->name);
|
|
so = (ship_stack+i)->outfit;
|
|
while(so) { // free the ship outfit.
|
|
sot = so;
|
|
so = so->next;
|
|
free(sot);
|
|
}
|
|
gl_freeTexture((ship_stack+i)->gfx_space);
|
|
gl_freeTexture((ship_stack+i)->gfx_target);
|
|
}
|
|
free(ship_stack);
|
|
ship_stack = NULL;
|
|
}
|
|
|