Lephisto/src/outfit.c
2013-02-04 17:44:53 +00:00

191 lines
5.4 KiB
C

#include <libxml/parser.h>
#include <math.h>
#include <string.h>
#include "main.h"
#include "log.h"
#include "outfit.h"
#define XML_NODE_START 1
#define XML_NODE_TEXT 3
#define XML_OUTFIT_ID "Outfits"
#define XML_OUTFIT_TAG "outfit"
#define OUTFIT_DATA "../dat/outfit.xml"
#define OUTFIT_GFX "../gfx/outfit/"
static Outfit* outfit_stack = NULL;
static int outfits = 0;
static Outfit* outfit_parse(const xmlNodePtr parent);
static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent);
// Return an outfit.
Outfit* outfit_get(const char* name) {
int i;
for(i = 0; i < outfits; i++)
if(strcmp(name, outfit_stack[i].name)==0)
return &outfit_stack[i];
return NULL;
}
// Return 1 if outfit is a weapon.
int outfit_isweapon(const Outfit* o) {
return (o->type > OUTFIT_TYPE_NULL && o->type <= OUTFIT_TYPE_MISSILE_SWARM_SMART);
}
const char* outfit_typename[] = {
"NULL",
"Bolt Cannon",
"Beam Cannon",
"Dumb Missile",
"Seeker Missile",
"Smart Missile",
"Swam Missile",
"Smart Swarm Missile"
};
const char* outfit_getType(const Outfit* o) {
return outfit_typename[o->type];
}
// Parses the specific area for a weapon and loads it into outfit.
static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent) {
xmlNodePtr cur, node;
node = parent->xmlChildrenNode;
char str[PATH_MAX] = "\0";
while((node = node->next)) {
// Load all the things.
if(strcmp((char*)node->name, "speed")==0)
tmp->speed = (double)atoi((char*)node->children->content);
else if(strcmp((char*)node->name, "accuracy")==0)
tmp->accuracy = atof((char*)node->children->content)*M_PI/180.; // to rad.
else if(strcmp((char*)node->name, "gfx")==0) {
snprintf(str, strlen((char*)node->children->content)+sizeof(OUTFIT_GFX),
OUTFIT_GFX"%s", (char*)node->children->content);
tmp->gfx_space = gl_newSprite(str, 6, 6);
}
if(strcmp((char*)node->name, "damage")==0) {
cur = node->children;
while((cur = cur->next)) {
if(strcmp((char*)cur->name, "armor")==0)
tmp->damage_armor = atof((char*)cur->children->content);
else if(strcmp((char*)cur->name, "shield")==0)
tmp->damage_shield = atof((char*)cur->children->content);
}
}
}
#define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name)
MELEMENT(tmp->speed, "speed");
MELEMENT(tmp->accuracy, "tech");
MELEMENT(tmp->damage_armor, "armor' from element 'damage");
MELEMENT(tmp->damage_shield, "shield' from element 'damage");
#undef MELEMENT
}
// Parse and return Outfits from parent node.
static Outfit* outfit_parse(const xmlNodePtr parent) {
Outfit* tmp = CALLOC_L(Outfit);
xmlNodePtr cur, node;
xmlChar* prop;
tmp->name = (char*)xmlGetProp(parent, (xmlChar*)"name"); // Already mallocs.
node = parent->xmlChildrenNode;
while((node = node->next)) {
// Load all the things.
if(strcmp((char*)node->name, "general")==0) {
cur = node->children;
while((cur = cur->next)) {
if(strcmp((char*)cur->name, "max")==0)
tmp->max = atoi((char*)cur->children->content);
else if(strcmp((char*)cur->name, "tech")==0)
tmp->tech = atoi((char*)cur->children->content);
else if(strcmp((char*)cur->name, "mass")== 0)
tmp->mass = atoi((char*)cur->children->content);
}
}
else if(strcmp((char*)node->name, "specific")==0) {
// Has to be processed seperately.
prop = xmlGetProp(node,(xmlChar*)"type");
if(prop == NULL)
ERR("Outfit '%s' element 'specific' missing property 'type'", tmp->name);
tmp->type = atoi((char*)prop);
free(prop);
switch(tmp->type) {
case OUTFIT_TYPE_NULL:
WARN("Outfit '%s' is of type NONE", tmp->name);
break;
case OUTFIT_TYPE_BOLT:
outfit_parseSWeapon(tmp, node);
break;
default:
break;
}
}
}
#define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name)
MELEMENT(tmp->max, "max");
MELEMENT(tmp->tech, "tech");
MELEMENT(tmp->mass, "mass");
MELEMENT(tmp->type, "type");
#undef MELEMENT
DEBUG("Loaded outfit '%s' of type '%s'", tmp->name, outfit_getType(tmp));
return tmp;
}
// Load all the outfits into the outfit stack.
int outfit_load(void) {
uint32_t bufsize;
char* buf = pack_readfile(DATA, OUTFIT_DATA, &bufsize);
Outfit* tmp;
xmlNodePtr node;
xmlDocPtr doc = xmlParseMemory(buf, bufsize);
node = doc->xmlChildrenNode;
if(strcmp((char*)node->name, XML_OUTFIT_ID)) {
ERR("Malformed "OUTFIT_DATA" file: missing root element '"XML_OUTFIT_ID"'");
return -1;
}
node = node->xmlChildrenNode; // First system node.
if(node == NULL) {
ERR("Malformed "OUTFIT_DATA" file: does not contain elements");
return -1;
}
do {
if(node->type == XML_NODE_START && strcmp((char*)node->name, XML_OUTFIT_TAG)==0) {
tmp = outfit_parse(node);
outfit_stack = realloc(outfit_stack, sizeof(Outfit)*(++outfits));
memcpy(outfit_stack+outfits-1, tmp, sizeof(Outfit));
free(tmp);
}
} while((node = node->next));
xmlFreeDoc(doc);
free(buf);
xmlCleanupParser();
return 0;
}
// Frees the outfit stack.
void outfit_free(void) {
int i;
for(i = 0; i < outfits; i++) {
if(outfit_isweapon(&outfit_stack[i]) && outfit_stack[i].gfx_space)
gl_freeTexture(outfit_stack[i].gfx_space);
free(outfit_stack[i].name);
}
free(outfit_stack);
}