#include #include #include #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); }