/** * @brief Parses an xml node containing a SPFX. * * @param temp Address to load SPFX into. * @param parent XML Node containing the SPFX data. * @return 0 on success. */ static int spfx_base_parse( SPFX_Base *temp, const xmlNodePtr parent ) { xmlNodePtr node; /* Clear data. */ memset( temp, 0, sizeof(SPFX_Base) ); /* Get the name (mallocs). */ temp->name = xml_nodeProp(parent,"name"); /* Extract the data. */ node = parent->xmlChildrenNode; do { xmlr_float(node, "anim", temp->anim); xmlr_float(node, "ttl", temp->ttl); if (xml_isNode(node,"gfx")) temp->gfx = xml_parseTexture( node, SPFX_GFX_PRE"%s"SPFX_GFX_SUF, 6, 5, 0 ); } while (xml_nextNode(node)); /* Convert from ms to s. */ temp->anim /= 1000.; temp->ttl /= 1000.; if (temp->ttl == 0.) temp->ttl = temp->anim; #define MELEMENT(o,s) \ if (o) WARN("SPFX '%s' missing/invalid '"s"' element", temp->name) /**< Define to help check for data errors. */ MELEMENT(temp->anim==0.,"anim"); MELEMENT(temp->ttl==0.,"ttl"); MELEMENT(temp->gfx==NULL,"gfx"); #undef MELEMENT return 0; }
/** * @brief Parses an xml node containing a DTYPE. * * @param temp Address to load DTYPE into. * @param parent XML Node containing the DTYPE data. * @return 0 on success. */ static int DTYPE_parse( DTYPE *temp, const xmlNodePtr parent ) { xmlNodePtr node; /* Clear data. */ memset( temp, 0, sizeof(DTYPE) ); /* Get the name (mallocs). */ temp->name = xml_nodeProp(parent,"name"); /* Extract the data. */ node = parent->xmlChildrenNode; do { xml_onlyNodes(node); xmlr_float(node, "shield", temp->sdam); xmlr_float(node, "armour", temp->adam); xmlr_float(node, "knockback", temp->knock); WARN("Unknown node of type '%s' in damage node '%s'.", node->name, temp->name); } while (xml_nextNode(node)); #define MELEMENT(o,s) \ if (o) WARN("DTYPE '%s' invalid '"s"' element", temp->name) /**< Define to help check for data errors. */ MELEMENT(temp->sdam<0.,"shield"); MELEMENT(temp->adam<0.,"armour"); MELEMENT(temp->knock<0.,"knockback"); #undef MELEMENT return 0; }
/** * @brief Parses the modification tidbits of the outfit. * * @param temp Outfit to finish loading. * @param parent Outfit's parent node. */ static void outfit_parseSMod( Outfit* temp, const xmlNodePtr parent ) { xmlNodePtr node; node = parent->children; do { /* load all the data */ /* movement */ xmlr_float(node,"thrust",temp->u.mod.thrust); xmlr_float(node,"turn",temp->u.mod.turn); xmlr_float(node,"speed",temp->u.mod.speed); /* health */ xmlr_float(node,"armour",temp->u.mod.armour); xmlr_float(node,"shield",temp->u.mod.shield); xmlr_float(node,"energy",temp->u.mod.energy); xmlr_float(node,"fuel",temp->u.mod.fuel); if (xml_isNode(node,"armour_regen")) temp->u.mod.armour_regen = xml_getFloat(node)/60.0; else if (xml_isNode(node,"shield_regen")) temp->u.mod.shield_regen = xml_getFloat(node)/60.0; else if (xml_isNode(node,"energy_regen")) temp->u.mod.energy_regen = xml_getFloat(node)/60.0; /* misc */ xmlr_int(node,"cargo",temp->u.mod.cargo); } while (xml_nextNode(node)); }
/** * @brief Parses the jammer tidbits of the outfit. * * @param temp Outfit to finish loading. * @param parent Outfit's parent node. */ static void outfit_parseSJammer( Outfit *temp, const xmlNodePtr parent ) { xmlNodePtr node; node = parent->children; do { xmlr_float(node,"range",temp->u.jam.range); xmlr_float(node,"chance",temp->u.jam.chance); xmlr_float(node,"energy",temp->u.jam.energy); } while (xml_nextNode(node)); temp->u.jam.chance /= 100.; /* Put in per one, instead of percent */ temp->u.jam.energy /= 60.; /* It's per minute */ #define MELEMENT(o,s) \ if (o) WARN("Outfit '%s' missing/invalid '"s"' element", temp->name) /**< Define to help check for data errors. */ MELEMENT(temp->u.jam.range==0.,"range"); MELEMENT(temp->u.jam.chance==0.,"chance"); #undef MELEMENT }
/** * @brief Parses the afterburner tidbits of the outfit. * * @param temp Outfit to finish loading. * @param parent Outfit's parent node. */ static void outfit_parseSAfterburner( Outfit* temp, const xmlNodePtr parent ) { xmlNodePtr node; node = parent->children; /* must be >= 1. */ temp->u.afb.thrust_perc = 1.; temp->u.afb.speed_perc = 1.; do { /* parse the data */ xmlr_float(node,"rumble",temp->u.afb.rumble); if (xml_isNode(node,"sound")) temp->u.afb.sound = sound_get( xml_get(node) ); if (xml_isNode(node,"thrust_perc")) temp->u.afb.thrust_perc = 1. + xml_getFloat(node)/100.; xmlr_float(node,"thrust_abs",temp->u.afb.thrust_abs); if (xml_isNode(node,"speed_perc")) temp->u.afb.speed_perc = 1. + xml_getFloat(node)/100.; xmlr_float(node,"speed_abs",temp->u.afb.speed_abs); xmlr_float(node,"energy",temp->u.afb.energy); } while (xml_nextNode(node)); }
/** * @brief Loads up an event from an XML node. * * @param temp Event to load up. * @param parent Event parent node. * @return 0 on success. */ static int event_parse( EventData_t *temp, const xmlNodePtr parent ) { xmlNodePtr node, cur; char str[PATH_MAX] = "\0"; char *buf; #ifdef DEBUGGING /* To check if mission is valid. */ lua_State *L; int ret; uint32_t len; #endif /* DEBUGGING */ memset( temp, 0, sizeof(EventData_t) ); /* get the name */ temp->name = xml_nodeProp(parent,"name"); if (temp->name == NULL) WARN("Event in "EVENT_DATA" has invalid or no name"); node = parent->xmlChildrenNode; do { /* load all the data */ /* Only check nodes. */ xml_onlyNodes(node); if (xml_isNode(node,"lua")) { snprintf( str, PATH_MAX, EVENT_LUA_PATH"%s.lua", xml_get(node) ); temp->lua = strdup( str ); str[0] = '\0'; #ifdef DEBUGGING /* Check to see if syntax is valid. */ L = luaL_newstate(); buf = ndata_read( temp->lua, &len ); ret = luaL_loadbuffer(L, buf, len, temp->name ); if (ret == LUA_ERRSYNTAX) { WARN("Event Lua '%s' of mission '%s' syntax error: %s", temp->name, temp->lua, lua_tostring(L,-1) ); } free(buf); lua_close(L); #endif /* DEBUGGING */ continue; } /* Trigger. */ else if (xml_isNode(node,"trigger")) { buf = xml_get(node); if (buf == NULL) WARN("Event '%s': Null trigger type.", temp->name); else if (strcmp(buf,"enter")==0) temp->trigger = EVENT_TRIGGER_ENTER; else if (strcmp(buf,"land")==0) temp->trigger = EVENT_TRIGGER_LAND; else WARN("Event '%s' has invalid 'trigger' parameter: %s", temp->name, buf); continue; } /* Flags. */ else if (xml_isNode(node,"flags")) { /* set the various flags */ cur = node->children; do { if (xml_isNode(cur,"unique")) temp->flags |= EVENT_FLAG_UNIQUE; } while (xml_nextNode(cur)); continue; } /* Condition. */ xmlr_strd(node,"cond",temp->cond); /* Get chance. */ xmlr_float(node,"chance",temp->chance); DEBUG("Unknown node '%s' in event '%s'", node->name, temp->name); } while (xml_nextNode(node)); /* Process. */ temp->chance /= 100.; #define MELEMENT(o,s) \ if (o) WARN("Mission '%s' missing/invalid '"s"' element", temp->name) MELEMENT(temp->lua==NULL,"lua"); MELEMENT(temp->chance==0.,"chance"); MELEMENT(temp->trigger==EVENT_TRIGGER_NULL,"trigger"); #undef MELEMENT return 0; }
/** * @brief Loads the module start data. * * @return 0 on success. */ int start_load (void) { uint32_t bufsize; char *buf; xmlNodePtr node, cur, tmp; xmlDocPtr doc; int scu, stp, stu; /* Defaults. */ scu = -1; stp = -1; stu = -1; /* Try to read the file. */ buf = ndata_read( START_DATA_PATH, &bufsize ); if (buf == NULL) return -1; /* Load the XML file. */ doc = xmlParseMemory( buf, bufsize ); node = doc->xmlChildrenNode; if (!xml_isNode(node,XML_START_ID)) { ERR("Malformed '"START_DATA_PATH"' file: missing root element '"XML_START_ID"'"); return -1; } node = node->xmlChildrenNode; /* first system node */ if (node == NULL) { ERR("Malformed '"START_DATA_PATH"' file: does not contain elements"); return -1; } do { xml_onlyNodes(node); xmlr_strd( node, "name", start_data.name ); if (xml_isNode(node, "player")) { /* we are interested in the player */ cur = node->children; do { xml_onlyNodes(cur); xmlr_uint( cur, "credits", start_data.credits ); xmlr_strd( cur, "mission", start_data.mission ); xmlr_strd( cur, "event", start_data.event ); if (xml_isNode(cur,"ship")) { xmlr_attr( cur, "name", start_data.shipname); xmlr_strd( cur, "ship", start_data.ship ); } else if (xml_isNode(cur,"system")) { tmp = cur->children; do { xml_onlyNodes(tmp); /** system name, @todo percent chance */ xmlr_strd( tmp, "name", start_data.system ); /* position */ xmlr_float( tmp, "x", start_data.x ); xmlr_float( tmp, "y", start_data.y ); WARN("'"START_DATA_PATH"' has unknown system node '%s'.", tmp->name); } while (xml_nextNode(tmp)); continue; } WARN("'"START_DATA_PATH"' has unknown player node '%s'.", cur->name); } while (xml_nextNode(cur)); continue; } if (xml_isNode(node,"date")) { cur = node->children; do { xml_onlyNodes(cur); xmlr_int( cur, "scu", scu ); xmlr_int( cur, "stp", stp ); xmlr_int( cur, "stu", stu ); WARN("'"START_DATA_PATH"' has unknown date node '%s'.", cur->name); } while (xml_nextNode(cur)); continue; } if (xml_isNode(node,"tutorial")) { cur = node->children; do { xml_onlyNodes(cur); xmlr_strd( cur, "mission", start_data.tutmisn ); xmlr_strd( cur, "event", start_data.tutevt ); if (xml_isNode(cur,"system")) { tmp = cur->children; do { xml_onlyNodes(tmp); /** system name, @todo percent chance */ xmlr_strd( tmp, "name", start_data.tutsys ); /* position */ xmlr_float( tmp, "x", start_data.tutx ); xmlr_float( tmp, "y", start_data.tuty ); WARN("'"START_DATA_PATH"' has unknown system node '%s'.", tmp->name); } while (xml_nextNode(tmp)); continue; } WARN("'"START_DATA_PATH"' has unknown tutorial node '%s'.", cur->name); } while (xml_nextNode(cur)); continue; } WARN("'"START_DATA_PATH"' has unknown node '%s'.", node->name); } while (xml_nextNode(node)); /* Clean up. */ xmlFreeDoc(doc); free(buf); /* Sanity checking. */ #define MELEMENT(o,s) \ if (o) WARN("Module start data missing/invalid '"s"' element") /**< Define to help check for data errors. */ MELEMENT( start_data.name==NULL, "name" ); MELEMENT( start_data.credits==0, "credits" ); MELEMENT( start_data.ship==NULL, "ship" ); MELEMENT( start_data.system==NULL, "player system" ); MELEMENT( start_data.tutsys==NULL, "tutorial system" ); MELEMENT( scu<0, "scu" ); MELEMENT( stp<0, "stp" ); MELEMENT( stu<0, "stu" ); #undef MELEMENT /* Post process. */ start_data.date = ntime_create( scu, stp, stu ); return 0; }
/** * @brief Parses the specific area for a weapon and loads it into Outfit. * * @param temp Outfit to finish loading. * @param parent Outfit's parent node. */ static void outfit_parseSAmmo( Outfit* temp, const xmlNodePtr parent ) { xmlNodePtr node; char *buf; node = parent->xmlChildrenNode; /* Defaults. */ temp->u.amm.spfx_armour = -1; temp->u.amm.spfx_shield = -1; temp->u.amm.sound = -1; do { /* load all the data */ /* Basic */ xmlr_float(node,"duration",temp->u.amm.duration); xmlr_float(node,"lockon",temp->u.amm.lockon); xmlr_float(node,"resist",temp->u.amm.resist); /* Movement */ xmlr_float(node,"thrust",temp->u.amm.thrust); xmlr_float(node,"turn",temp->u.amm.turn); xmlr_float(node,"speed",temp->u.amm.speed); xmlr_float(node,"accuracy",temp->u.amm.accuracy); xmlr_float(node,"energy",temp->u.amm.energy); if (xml_isNode(node,"gfx")) { temp->u.amm.gfx_space = xml_parseTexture( node, OUTFIT_GFX"space/%s.png", 6, 6, OPENGL_TEX_MAPTRANS ); xmlr_attr(node, "spin", buf); if (buf != NULL) { outfit_setProp( temp, OUTFIT_PROP_WEAP_SPIN ); temp->u.blt.spin = atof( buf ); free(buf); } continue; } else if (xml_isNode(node,"spfx_armour")) temp->u.amm.spfx_armour = spfx_get(xml_get(node)); else if (xml_isNode(node,"spfx_shield")) temp->u.amm.spfx_shield = spfx_get(xml_get(node)); else if (xml_isNode(node,"sound")) temp->u.amm.sound = sound_get( xml_get(node) ); else if (xml_isNode(node,"damage")) outfit_parseDamage( &temp->u.amm.dtype, &temp->u.amm.damage, node ); } while (xml_nextNode(node)); /* Post-processing */ temp->u.amm.resist /= 100.; /* Set it in per one */ #define MELEMENT(o,s) \ if (o) WARN("Outfit '%s' missing/invalid '"s"' element", temp->name) /**< Define to help check for data errors. */ MELEMENT(temp->u.amm.gfx_space==NULL,"gfx"); MELEMENT(temp->u.amm.spfx_shield==-1,"spfx_shield"); MELEMENT(temp->u.amm.spfx_armour==-1,"spfx_armour"); MELEMENT((sound_disabled!=0) && (temp->u.amm.sound<0),"sound"); /* MELEMENT(temp->u.amm.thrust==0,"thrust"); */ /* Dumb missiles don't need everything */ if (outfit_isSeeker(temp)) { MELEMENT(temp->u.amm.turn==0,"turn"); MELEMENT(temp->u.amm.lockon==0,"lockon"); } MELEMENT(temp->u.amm.speed==0,"speed"); MELEMENT(temp->u.amm.duration==0,"duration"); MELEMENT(temp->u.amm.damage==0,"damage"); #undef MELEMENT }
/** * @brief Parses the beam weapon specifics of an outfit. * * @param temp Outfit to finish loading. * @param parent Outfit's parent node. */ static void outfit_parseSBeam( Outfit* temp, const xmlNodePtr parent ) { xmlNodePtr node; /* Defaults. */ temp->u.bem.spfx_armour = -1; temp->u.bem.spfx_shield = -1; temp->u.bem.sound_warmup = -1; temp->u.bem.sound = -1; temp->u.bem.sound_off = -1; node = parent->xmlChildrenNode; do { /* load all the data */ xmlr_float(node,"range",temp->u.bem.range); xmlr_float(node,"turn",temp->u.bem.turn); xmlr_float(node,"energy",temp->u.bem.energy); xmlr_long(node,"delay",temp->u.bem.delay); xmlr_float(node,"warmup",temp->u.bem.warmup); xmlr_float(node,"duration",temp->u.bem.duration); if (xml_isNode(node,"damage")) { outfit_parseDamage( &temp->u.bem.dtype, &temp->u.bem.damage, node ); continue; } /* Graphic stuff. */ if (xml_isNode(node,"gfx")) { temp->u.bem.gfx = xml_parseTexture( node, OUTFIT_GFX"space/%s.png", 1, 1, 0 ); continue; } if (xml_isNode(node,"spfx_armour")) { temp->u.bem.spfx_armour = spfx_get(xml_get(node)); continue; } if (xml_isNode(node,"spfx_shield")) { temp->u.bem.spfx_shield = spfx_get(xml_get(node)); continue; } /* Sound stuff. */ if (xml_isNode(node,"sound_warmup")) { temp->u.bem.sound_warmup = sound_get( xml_get(node) ); continue; } if (xml_isNode(node,"sound")) { temp->u.bem.sound = sound_get( xml_get(node) ); continue; } if (xml_isNode(node,"sound_off")) { temp->u.bem.sound_off = sound_get( xml_get(node) ); continue; } } while (xml_nextNode(node)); #define MELEMENT(o,s) \ if (o) WARN("Outfit '%s' missing/invalid '"s"' element", temp->name) /**< Define to help check for data errors. */ MELEMENT(temp->u.bem.gfx==NULL,"gfx"); MELEMENT(temp->u.bem.spfx_shield==-1,"spfx_shield"); MELEMENT(temp->u.bem.spfx_armour==-1,"spfx_armour"); MELEMENT((sound_disabled!=0) && (temp->u.bem.warmup > 0.) && (temp->u.bem.sound<0),"sound_warmup"); MELEMENT((sound_disabled!=0) && (temp->u.bem.sound<0),"sound"); MELEMENT((sound_disabled!=0) && (temp->u.bem.sound_off<0),"sound_off"); MELEMENT(temp->u.bem.delay==0,"delay"); MELEMENT(temp->u.bem.duration==0,"duration"); MELEMENT(temp->u.bem.range==0,"range"); MELEMENT((temp->type!=OUTFIT_TYPE_BEAM) && (temp->u.bem.turn==0),"turn"); MELEMENT(temp->u.bem.energy==0,"energy"); MELEMENT(temp->u.bem.damage==0,"damage"); #undef MELEMENT }
/** * @brief Parses the specific area for a bolt weapon and loads it into Outfit. * * @param temp Outfit to finish loading. * @param parent Outfit's parent node. */ static void outfit_parseSBolt( Outfit* temp, const xmlNodePtr parent ) { xmlNodePtr node; char *buf; /* Defaults */ temp->u.blt.spfx_armour = -1; temp->u.blt.spfx_shield = -1; temp->u.blt.sound = -1; node = parent->xmlChildrenNode; do { /* load all the data */ xmlr_float(node,"speed",temp->u.blt.speed); xmlr_float(node,"delay",temp->u.blt.delay); xmlr_float(node,"range",temp->u.blt.range); xmlr_float(node,"accuracy",temp->u.blt.accuracy); xmlr_float(node,"energy",temp->u.blt.energy); if (xml_isNode(node,"gfx")) { temp->u.blt.gfx_space = xml_parseTexture( node, OUTFIT_GFX"space/%s.png", 6, 6, OPENGL_TEX_MAPTRANS ); xmlr_attr(node, "spin", buf); if (buf != NULL) { outfit_setProp( temp, OUTFIT_PROP_WEAP_SPIN ); temp->u.blt.spin = atof( buf ); free(buf); } continue; } if (xml_isNode(node,"spfx_shield")) { temp->u.blt.spfx_shield = spfx_get(xml_get(node)); continue; } if (xml_isNode(node,"spfx_armour")) { temp->u.blt.spfx_armour = spfx_get(xml_get(node)); continue; } if (xml_isNode(node,"sound")) { temp->u.blt.sound = sound_get( xml_get(node) ); continue; } if (xml_isNode(node,"damage")) { outfit_parseDamage( &temp->u.blt.dtype, &temp->u.blt.damage, node ); continue; } } while (xml_nextNode(node)); #define MELEMENT(o,s) \ if (o) WARN("Outfit '%s' missing/invalid '"s"' element", temp->name) /**< Define to help check for data errors. */ MELEMENT(temp->u.blt.gfx_space==NULL,"gfx"); MELEMENT(temp->u.blt.spfx_shield==-1,"spfx_shield"); MELEMENT(temp->u.blt.spfx_armour==-1,"spfx_armour"); MELEMENT((sound_disabled!=0) && (temp->u.blt.sound<0),"sound"); MELEMENT(temp->u.blt.delay==0,"delay"); MELEMENT(temp->u.blt.speed==0,"speed"); MELEMENT(temp->u.blt.range==0,"range"); MELEMENT(temp->u.blt.accuracy==0,"accuracy"); MELEMENT(temp->u.blt.damage==0,"damage"); #undef MELEMENT }