#include #include #include #include "lephisto.h" #include "xml.h" #include "pack.h" #include "log.h" #include "spfx.h" #include "pilot.h" #include "rng.h" #include "economy.h" #define XML_COMMODITY_ID "Commodities" /* XML section identifier. */ #define XML_COMMODITY_TAG "commodity" #define COMMODITY_DATA "../dat/commodity.xml" /* Commodity stack. */ static Commodity* commodity_stack = NULL; static int commodity_nstack = 0; static void commodity_freeOne(Commodity* com); static Commodity* commodity_parse(xmlNodePtr parent); /* Convert credits to a usable string for displaying. */ /* str must have 10 characters allocated. */ void credits2str(char* str, unsigned int credits, int decimals) { if(decimals < 0) snprintf(str, 32, "%d", credits); else if(credits >= 1000000000) snprintf(str, 16, "%.*fB", decimals, (double)credits / 1000000000.); else if(credits >= 1000000) snprintf(str, 16, "%*fM", decimals, (double)credits / 1000000.); else if(credits >= 1000) snprintf(str, 16, "%.*fK", decimals, (double)credits / 1000.); else snprintf(str, 16, "%d", credits); } /* Get a commodity. */ Commodity* commodity_get(const char* name) { int i; for(i = 0; i < commodity_nstack; i++) if(strcmp(commodity_stack[i].name, name)==0) return &commodity_stack[i]; WARN("Commodity '%s' not found in stack", name); return NULL; } /* Free a commodity. */ static void commodity_freeOne(Commodity* com) { if(com->name) free(com->name); if(com->description) free(com->description); } static Commodity* commodity_parse(xmlNodePtr parent) { xmlNodePtr node; Commodity* tmp = CALLOC_L(Commodity); tmp->name = (char*)xmlGetProp(parent, (xmlChar*)"name"); if(tmp->name == NULL) WARN("Commodity from "COMMODITY_DATA" has invalid or noname"); node = parent->xmlChildrenNode; do { if(xml_isNode(node, "description")) tmp->description = strdup(xml_get(node)); else if(xml_isNode(node, "high")) tmp->high = xml_getInt(node); else if(xml_isNode(node, "medium")) tmp->medium = xml_getInt(node); else if(xml_isNode(node, "low")) tmp->low = xml_getInt(node); } while((node = node->next)); #if 0 /* Let's kill this for now. */ #define MELEMENT(o,s)if(o)WARN("Commodity '%s' missing '"s"' element",tmp->name) MELEMENT(tmp->high==0, "high"); MELEMENT(tmp->description==NULL, "description"); MELEMENT(tmp->medium==0, "medium"); MELEMENT(tmp->low==0, "low"); #undef MELEMENT #endif return tmp; } /* Throw cargo out into space (graphically). */ void commodity_Jettison(int pilot, Commodity* com, int quantity) { (void)com; int i; Pilot* p; int n, effect; double px, py, bvx, bvy, r, a, vx, vy; p = pilot_get(pilot); n = MAX(1, RNG(quantity/10, quantity/5)); px = p->solid->pos.x; py = p->solid->pos.y; bvx = p->solid->vel.x; bvy = p->solid->vel.y; for(i = 0; i < n; i++) { effect = spfx_get("cargo"); /* Radial distribution gives much nicer results. */ r = RNGF()*25 - 12.5; a = (double)RNG(0,259); vx = bvx + r*cos(a); vy = bvy + r*sin(a); /* Add the cargo effect. */ spfx_add(effect, px, py, vx, vy, SPFX_LAYER_BACK); } } /* Init/exit */ int commodity_load(void) { uint32_t bufsize; char* buf = pack_readfile(DATA, COMMODITY_DATA, &bufsize); xmlNodePtr node; xmlDocPtr doc = xmlParseMemory(buf, bufsize); Commodity* tmp = NULL; node = doc->xmlChildrenNode; /* Commoditys node. */ if(strcmp((char*)node->name, XML_COMMODITY_ID)) { ERR("Malformed "COMMODITY_DATA " file: Missing root element '"XML_COMMODITY_ID"'"); return -1; } node = node->xmlChildrenNode; /* First faction node. */ if(node == NULL) { ERR("Malformed "COMMODITY_DATA" file: does not contain elements"); return -1; } do { if(node->type == XML_NODE_START) { if(strcmp((char*)node->name, XML_COMMODITY_TAG)==0) { tmp = commodity_parse(node); commodity_stack = realloc(commodity_stack, sizeof(Commodity)*(++commodity_nstack)); memcpy(commodity_stack+commodity_nstack-1, tmp, sizeof(Commodity)); free(tmp); } } } while((node = node->next)); xmlFreeDoc(doc); free(buf); xmlCleanupParser(); DEBUG("Loaded %d commodit%s", commodity_nstack, (commodity_nstack==1) ? "y" : "ies"); return 0; } void commodity_free(void) { int i; for(i = 0; i < commodity_nstack; i++) commodity_freeOne(&commodity_stack[i]); free(commodity_stack); commodity_stack = NULL; commodity_nstack = 0; }