223 lines
6.6 KiB
C
223 lines
6.6 KiB
C
#include <libxml/parser.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
|
|
#include "main.h"
|
|
#include "log.h"
|
|
#include "pack.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_BOLT) || (o->type == OUTFIT_TYPE_BEAM));
|
|
}
|
|
|
|
// Return 1 if outfit is a launcher.
|
|
int outfit_isLauncher(const Outfit* o) {
|
|
return((o->type == OUTFIT_TYPE_MISSILE_DUMB) ||
|
|
(o->type == OUTFIT_TYPE_MISSILE_SEEK) ||
|
|
(o->type == OUTFIT_TYPE_MISSILE_SEEK_SMART) ||
|
|
(o->type == OUTFIT_TYPE_MISSILE_SWARM) ||
|
|
(o->type == OUTFIT_TYPE_MISSILE_SWARM_SMART));
|
|
}
|
|
|
|
// Return 1 if outfit is weapon ammunition.
|
|
int outfit_isAmmo(const Outfit* o) {
|
|
return((o->type == OUTFIT_TYPE_MISSILE_DUMB_AMMO) ||
|
|
(o->type == OUTFIT_TYPE_MISSILE_SEEK_AMMO) ||
|
|
(o->type == OUTFIT_TYPE_MISSILE_SEEK_SMART_AMMO) ||
|
|
(o->type == OUTFIT_TYPE_MISSILE_SWARM_AMMO) ||
|
|
(o->type == OUTFIT_TYPE_MISSILE_SWARM_SMART_AMMO));
|
|
|
|
}
|
|
|
|
const char* outfit_typename[] = {
|
|
"NULL",
|
|
"Bolt Cannon",
|
|
"Beam Cannon",
|
|
"Dumb Missile",
|
|
"Dumb Missile Ammunition",
|
|
"Seeker Missile",
|
|
"Seeker Missile Ammunition",
|
|
"Smart Seeker Missile",
|
|
"Smart Seeker Missile Ammunition",
|
|
"Swam Missile",
|
|
"Swarm Missile Ammunition Pack",
|
|
"Smart Swarm Missile",
|
|
"Smart Swarm Missile Ammunition Pack"
|
|
};
|
|
|
|
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, "delay")==0)
|
|
tmp->delay = atoi((char*)node->children->content);
|
|
else if(strcmp((char*)node->name, "range")==0)
|
|
tmp->range = atof((char*) node->children->content);
|
|
else if(strcmp((char*)node->name, "accuracy")==0)
|
|
tmp->accuracy = atof((char*)node->children->content);
|
|
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->accuracy, "tech");
|
|
MELEMENT(tmp->delay, "delay");
|
|
MELEMENT(tmp->speed, "speed");
|
|
MELEMENT(tmp->range, "range");
|
|
MELEMENT(tmp->accuracy, "accuracy");
|
|
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);
|
|
}
|
|
|