/** * @brief Parses the actual individual event nodes. * * @param parent Parent node to parse. * @return 0 on success. */ static int events_parseActive( xmlNodePtr parent ) { char *buf; unsigned int id; int data; xmlNodePtr node, cur; Event_t *ev; node = parent->xmlChildrenNode; do { if (!xml_isNode(node,"event")) continue; xmlr_attr(node,"name",buf); if (buf==NULL) { WARN("Event has missing 'name' attribute, skipping."); continue; } data = event_dataID( buf ); if (data < 0) { WARN("Event in save has name '%s' but event data not found matching name. Skipping.", buf); free(buf); continue; } free(buf); xmlr_attr(node,"id",buf); if (buf==NULL) { WARN("Event with data '%s' has missing 'id' attribute, skipping.", event_dataName(data)); continue; } id = atoi(buf); free(buf); if (id==0) { WARN("Event with data '%s' has invalid 'id' attribute, skipping.", event_dataName(data)); continue; } /* Create the event. */ event_create( data, &id ); ev = event_get( id ); if (ev == NULL) { WARN("Event with data '%s' was not created, skipping.", event_dataName(data)); continue; } ev->save = 1; /* Should save by default again. */ /* Get the data. */ cur = node->xmlChildrenNode; do { if (xml_isNode(cur,"lua")) nxml_unpersistLua( ev->L, cur ); } while (xml_nextNode(cur)); /* Claims. */ if (xml_isNode(node,"claims")) ev->claims = claim_xmlLoad( node ); } while (xml_nextNode(node)); return 0; }
/** * @brief Loads the player's faction standings. * * @param parent Parent xml node to read from. * @return 0 on success. */ int pfaction_load( xmlNodePtr parent ) { xmlNodePtr node, cur; char *str; int faction; node = parent->xmlChildrenNode; do { if (xml_isNode(node,"factions")) { cur = node->xmlChildrenNode; do { if (xml_isNode(cur,"faction")) { xmlr_attr(cur,"name",str); faction = faction_get(str); if (faction != -1) /* Faction is valid. */ faction_stack[faction].player = xml_getFloat(cur); free(str); } } while (xml_nextNode(cur)); } } while (xml_nextNode(node)); return 0; }
/** * @brief Loads the player's faction standings. * * @param parent Parent xml node to read from. * @return 0 on success. */ int pfaction_load( xmlNodePtr parent ) { xmlNodePtr node, cur; char *str; int faction; node = parent->xmlChildrenNode; do { if (xml_isNode(node,"factions")) { cur = node->xmlChildrenNode; do { if (xml_isNode(cur,"faction")) { xmlr_attr(cur,"name",str); faction = faction_get(str); if (faction != -1) { /* Faction is valid. */ /* Must not be static. */ if (!faction_isFlag( &faction_stack[faction], FACTION_STATIC )) faction_stack[faction].player = xml_getFloat(cur); } free(str); } } while (xml_nextNode(cur)); } } while (xml_nextNode(node)); return 0; }
/** * @brief Loads a commodity. * * @param temp Commodity to load data into. * @param parent XML node to load from. * @return Commodity loaded from parent. */ static int commodity_parse( Commodity *temp, xmlNodePtr parent ) { xmlNodePtr node; /* Clear memory. */ memset( temp, 0, sizeof(Commodity) ); /* Get name. */ xmlr_attr( parent, "name", temp->name ); if (temp->name == NULL) WARN("Commodity from "COMMODITY_DATA" has invalid or no name"); /* Parse body. */ node = parent->xmlChildrenNode; do { xml_onlyNodes(node); xmlr_strd(node, "description", temp->description); xmlr_int(node, "price", temp->price); WARN("Commodity '%s' has unknown node '%s'.", temp->name, node->name); } while (xml_nextNode(node)); #if 0 /* shouldn't be needed atm */ #define MELEMENT(o,s) if (o) WARN("Commodity '%s' missing '"s"' element", temp->name) MELEMENT(temp->description==NULL,"description"); MELEMENT(temp->high==0,"high"); MELEMENT(temp->medium==0,"medium"); MELEMENT(temp->low==0,"low"); #undef MELEMENT #endif return 0; }
/** * @brief Applies a diff to the universe. * * @param name Diff to apply. * @return 0 on success. */ int diff_apply( const char *name ) { xmlNodePtr node; xmlDocPtr doc; size_t bufsize; char *buf; char *diffname; /* Check if already applied. */ if (diff_isApplied(name)) return 0; buf = ndata_read( DIFF_DATA_PATH, &bufsize ); doc = xmlParseMemory( buf, bufsize ); node = doc->xmlChildrenNode; if (strcmp((char*)node->name,"unidiffs")) { ERR(_("Malformed unidiff file: missing root element 'unidiffs'")); return 0; } node = node->xmlChildrenNode; /* first system node */ if (node == NULL) { ERR(_("Malformed unidiff file: does not contain elements")); return 0; } do { if (xml_isNode(node,"unidiff")) { /* Check to see if it's the diff we're looking for. */ xmlr_attr(node,"name",diffname); if (strcmp(diffname,name)==0) { /* Apply it. */ diff_patch( node ); /* Clean up. */ free(diffname); xmlFreeDoc(doc); free(buf); economy_execQueued(); return 0; } free(diffname); } } while (xml_nextNode(node)); /* More clean up. */ xmlFreeDoc(doc); free(buf); WARN(_("UniDiff '%s' not found in %s."), name, DIFF_DATA_PATH); return -1; }
/** * @brief Parses an XML tech node. */ static int tech_parseNode( tech_group_t *tech, xmlNodePtr parent ) { /* Just in case. */ memset( tech, 0, sizeof(tech_group_t) ); /* Get name. */ xmlr_attr( parent, "name", tech->name); if (tech->name == NULL) { WARN("tech node does not have 'name' attribute"); return 1; } return 0; }
/** * @brief Allocates space for and populates a list of asset mods from a unistate xml tree. * * @param rootNode A node pointer to the root node of unistate tree * @return A pointer to the first node of the linked list. */ assetStatePtr unistate_populateList(xmlNodePtr root) { assetStatePtr listHead = NULL, curElement = NULL; xmlNodePtr elementNode = NULL, listNode = NULL; #ifdef UNISTATE_DEBUG char debugBuffer[PATH_MAX]; #endif //no root node? if(!root) return NULL; //root has no children? if(!(listNode = root->children)) return NULL; //iterate over assets do { //if the node is named right if(xml_isNode(listNode, "asset")) { elementNode = listNode->children; //set up list element curElement = malloc(sizeof(assetState)); curElement->next = listHead; listHead = curElement; curElement->name = curElement->faction = NULL; curElement->presence = -1; //get info from file xmlr_attr(listNode, "name", curElement->name); //debug stuff #ifdef UNISTATE_DEBUG snprintf(debugBuffer, sizeof(char) * (PATH_MAX - 1),\ "UniState Debug: Asset name '%s' parsed\n", curElement->name); logprintf(stdout, debugBuffer); #endif do { xml_onlyNodes(elementNode); xmlr_strd(elementNode, "faction", curElement->faction); xmlr_int(elementNode, "presence", curElement->presence); xmlr_int(elementNode, "presence_range", curElement->range); } while(xml_nextNode(elementNode)); //more debug stuff #ifdef UNISTATE_DEBUG snprintf(debugBuffer, sizeof(char) * (PATH_MAX - 1),\ "UniState Debug: Asset faction '%s' and Asset presence '%i' parsed\n",\ (curElement->faction == NULL ? "<Default>" : curElement->faction), curElement->presence); logprintf(stdout, debugBuffer); #endif } } while(xml_nextNode(listNode)); //return the list return listHead; }
/** * @brief Patches a asset. * * @param diff Diff that is doing the patching. * @param node Node containing the asset. * @return 0 on success. */ static int diff_patchAsset( UniDiff_t *diff, xmlNodePtr node ) { UniHunk_t base, hunk; xmlNodePtr cur; /* Set the target. */ memset(&base, 0, sizeof(UniHunk_t)); base.target.type = HUNK_TARGET_ASSET; xmlr_attr(node,"name",base.target.u.name); if (base.target.u.name==NULL) { WARN(_("Unidiff '%s' has an target node without a 'name' tag"), diff->name); return -1; } /* Now parse the possible changes. */ cur = node->xmlChildrenNode; do { xml_onlyNodes(cur); if (xml_isNode(cur,"faction")) { hunk.target.type = base.target.type; hunk.target.u.name = strdup(base.target.u.name); /* Outfit type is constant. */ hunk.type = HUNK_TYPE_ASSET_FACTION; /* Get the data. */ hunk.u.name = xml_getStrd(cur); /* Apply diff. */ if (diff_patchHunk( &hunk ) < 0) diff_hunkFailed( diff, &hunk ); else diff_hunkSuccess( diff, &hunk ); continue; } WARN(_("Unidiff '%s' has unknown node '%s'."), diff->name, node->name); } while (xml_nextNode(cur)); /* Clean up some stuff. */ free(base.target.u.name); base.target.u.name = NULL; return 0; }
/** * @brief Parses a damage node. * * Example damage node would be: * @code * <damage type="kinetic">10</damage> * @endcode * * @param[out] dtype Stores the damage type here. * @param[out] dmg Storse the damage here. * @param[in] node Node to parse damage from. * @return 0 on success. */ static int outfit_parseDamage( DamageType *dtype, double *dmg, xmlNodePtr node ) { char *buf; if (xml_isNode(node,"damage")) { /* Get type */ xmlr_attr(node,"type",buf); (*dtype) = outfit_strToDamageType(buf); if (buf) free(buf); /* Get damage */ (*dmg) = xml_getFloat(node); return 0; } /* Unknown type */ (*dtype) = DAMAGE_TYPE_NULL; (*dmg) = 0; WARN("Trying to parse non-damage node as damage node!"); return 1; }
/** * @brief Parses the actual individual mission nodes. * * @param parent Parent node to parse. * @return 0 on success. */ static int missions_parseActive( xmlNodePtr parent ) { Mission *misn; MissionData *data; int m, i; char *buf; char *title; const char **items; int nitems; int id, sys, type; StarSystem *ssys; xmlNodePtr node, cur, nest; m = 0; /* start with mission 0 */ node = parent->xmlChildrenNode; do { if (xml_isNode(node,"mission")) { misn = player_missions[m]; /* process the attributes to create the mission */ xmlr_attr(node,"data",buf); data = mission_get(mission_getID(buf)); if (data == NULL) { WARN("Mission '%s' from savegame not found in game - ignoring.", buf); free(buf); continue; } else { if (mission_init( misn, data, 0, 0, NULL )) { WARN("Mission '%s' from savegame failed to load properly - ignoring.", buf); free(buf); continue; } misn->accepted = 1; } free(buf); /* this will orphan an identifier */ xmlr_attr(node,"id",buf); misn->id = atol(buf); free(buf); cur = node->xmlChildrenNode; do { xmlr_strd(cur,"title",misn->title); xmlr_strd(cur,"desc",misn->desc); xmlr_strd(cur,"reward",misn->reward); /* Get the markers. */ if (xml_isNode(cur,"markers")) { nest = cur->xmlChildrenNode; do { if (xml_isNode(nest,"marker")) { /* Get ID. */ xmlr_attr(nest,"id",buf); id = (buf != NULL) ? atoi(buf) : -1; if (buf != NULL) free(buf); /* Get type. */ xmlr_attr(nest,"type",buf); type = (buf != NULL) ? atoi(buf) : -1; if (buf != NULL) free(buf); /* Get system. */ ssys = system_get( xml_get( nest )); if (ssys == NULL) { WARN( "System Marker to '%s' does not exist", xml_get( nest ) ); continue; } sys = system_index( ssys ); mission_addMarker( misn, id, sys, type ); } } while (xml_nextNode(nest)); } /* Cargo. */ if (xml_isNode(cur,"cargos")) { nest = cur->xmlChildrenNode; do { if (xml_isNode(nest,"cargo")) mission_linkCargo( misn, xml_getLong(nest) ); } while (xml_nextNode(nest)); } /* OSD. */ if (xml_isNode(cur,"osd")) { xmlr_attr(cur,"nitems",buf); if (buf != NULL) { nitems = atoi(buf); free(buf); } else continue; xmlr_attr(cur,"title",title); items = malloc( nitems * sizeof(char*) ); i = 0; nest = cur->xmlChildrenNode; do { if (xml_isNode(nest,"msg")) { if (i > nitems) { WARN("Inconsistency with 'nitems' in savefile."); break; } items[i] = xml_get(nest); i++; } } while (xml_nextNode(nest)); /* Create the osd. */ misn->osd = osd_create( title, nitems, items, data->avail.priority ); free(items); free(title); /* Set active. */ xmlr_attr(cur,"active",buf); if (buf != NULL) { osd_active( misn->osd, atoi(buf) ); free(buf); } } /* Claims. */ if (xml_isNode(cur,"claims")) misn->claims = claim_xmlLoad( cur ); if (xml_isNode(cur,"lua")) /* start the unpersist routine */ nxml_unpersistLua( misn->L, cur ); } while (xml_nextNode(cur)); m++; /* next mission */ if (m >= MISSION_MAX) break; /* full of missions, must be an error */ } } while (xml_nextNode(node)); return 0; }
/** * @brief Loads the tech information. */ int tech_load (void) { int i, ret, s; uint32_t bufsize; char *buf, *data; xmlNodePtr node, parent; xmlDocPtr doc; tech_group_t *tech; /* Load the data. */ data = ndata_read( TECH_DATA, &bufsize ); if (data == NULL) return -1; /* Load the document. */ doc = xmlParseMemory( data, bufsize ); if (doc == NULL) { WARN("'%s' is not a valid XML file.", TECH_DATA); return -1; } /* Load root element. */ parent = doc->xmlChildrenNode; if (!xml_isNode(parent,XML_TECH_ID)) { WARN("Malformed "TECH_DATA" file: missing root element '"XML_TECH_ID"'"); return -1; } /* Get first node. */ node = parent->xmlChildrenNode; if (node == NULL) { WARN("Malformed "TECH_DATA" file: does not contain elements"); return -1; } /* Create the array. */ tech_groups = array_create( tech_group_t ); /* First pass create the groups - needed to reference them later. */ ret = 0; tech = NULL; do { xml_onlyNodes(node); /* Must match tag. */ if (!xml_isNode(node, XML_TECH_TAG)) { WARN("'"XML_TECH_ID"' has unknown node '%s'.", node->name); continue; } if (ret==0) /* Write over failures. */ tech = &array_grow( &tech_groups ); ret = tech_parseNode( tech, node ); } while (xml_nextNode(node)); array_shrink( &tech_groups ); /* Now we load the data. */ node = parent->xmlChildrenNode; s = array_size( tech_groups ); do { /* Must match tag. */ if (!xml_isNode(node, XML_TECH_TAG)) continue; /* Must avoid warning by checking explicit NULL. */ xmlr_attr( node, "name", buf ); if (buf == NULL) continue; /* Load next tech. */ for (i=0; i<s; i++) { tech = &tech_groups[i]; if (strcmp(tech->name, buf)==0) tech_parseNodeData( tech, node ); } /* Free memory. */ free(buf); } while (xml_nextNode(node)); /* Info. */ DEBUG("Loaded %d tech group%s", s, (s == 1) ? "" : "s" ); /* Free memory. */ free(data); xmlFreeDoc(doc); return 0; }
/** * @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 }
/** * @brief Actually applies a diff in XML node form. * * @param parent Node containing the diff information. * @return 0 on success. */ static int diff_patch( xmlNodePtr parent ) { int i, univ_update; UniDiff_t *diff; UniHunk_t *fail; xmlNodePtr node; char *target; /* Prepare it. */ diff = diff_newDiff(); memset(diff, 0, sizeof(UniDiff_t)); xmlr_attr(parent,"name",diff->name); /* Whether or not we need to update the universe. */ univ_update = 0; node = parent->xmlChildrenNode; do { xml_onlyNodes(node); if (xml_isNode(node,"system")) { univ_update = 1; diff_patchSystem( diff, node ); } else if (xml_isNode(node, "tech")) diff_patchTech( diff, node ); else if (xml_isNode(node, "asset")) { univ_update = 1; diff_patchAsset( diff, node ); } else if (xml_isNode(node, "faction")) { univ_update = 1; diff_patchFaction( diff, node ); } else WARN(_("Unidiff '%s' has unknown node '%s'."), diff->name, node->name); } while (xml_nextNode(node)); if (diff->nfailed > 0) { WARN(_("Unidiff '%s' failed to apply %d hunks."), diff->name, diff->nfailed); for (i=0; i<diff->nfailed; i++) { fail = &diff->failed[i]; target = fail->target.u.name; switch (fail->type) { case HUNK_TYPE_ASSET_ADD: WARN(_(" [%s] asset add: '%s'"), target, fail->u.name); break; case HUNK_TYPE_ASSET_REMOVE: WARN(_(" [%s] asset remove: '%s'"), target, fail->u.name); break; case HUNK_TYPE_ASSET_BLACKMARKET: WARN(_(" [%s] asset blackmarket: '%s'"), target, fail->u.name); break; case HUNK_TYPE_ASSET_LEGALMARKET: WARN(_(" [%s] asset legalmarket: '%s'"), target, fail->u.name); break; case HUNK_TYPE_JUMP_ADD: WARN(_(" [%s] jump add: '%s'"), target, fail->u.name); break; case HUNK_TYPE_JUMP_REMOVE: WARN(_(" [%s] jump remove: '%s'"), target, fail->u.name); break; case HUNK_TYPE_TECH_ADD: WARN(_(" [%s] tech add: '%s'"), target, fail->u.name ); break; case HUNK_TYPE_TECH_REMOVE: WARN(_(" [%s] tech remove: '%s'"), target, fail->u.name ); break; case HUNK_TYPE_ASSET_FACTION: WARN(_(" [%s] asset faction: '%s'"), target, fail->u.name ); break; case HUNK_TYPE_ASSET_FACTION_REMOVE: WARN(_(" [%s] asset faction removal: '%s'"), target, fail->u.name ); break; case HUNK_TYPE_FACTION_VISIBLE: WARN(_(" [%s] faction visible: '%s'"), target, fail->u.name ); break; case HUNK_TYPE_FACTION_INVISIBLE: WARN(_(" [%s] faction invisible: '%s'"), target, fail->u.name ); break; case HUNK_TYPE_FACTION_ALLY: WARN(_(" [%s] faction set ally: '%s'"), target, fail->u.name ); break; case HUNK_TYPE_FACTION_ENEMY: WARN(_(" [%s] faction set enemy: '%s'"), target, fail->u.name ); break; case HUNK_TYPE_FACTION_NEUTRAL: WARN(_(" [%s] faction set neutral: '%s'"), target, fail->u.name ); break; case HUNK_TYPE_FACTION_REALIGN: WARN(_(" [%s] faction alignment reset: '%s'"), target, fail->u.name ); break; default: WARN(_(" unknown hunk '%d'"), fail->type); break; } } } /* Prune presences if necessary. */ if (univ_update) space_reconstructPresences(); /* Update overlay map just in case. */ ovr_refresh(); return 0; }
/** * @brief Patches a faction. * * @param diff Diff that is doing the patching. * @param node Node containing the asset. * @return 0 on success. */ static int diff_patchFaction( UniDiff_t *diff, xmlNodePtr node ) { UniHunk_t base, hunk; xmlNodePtr cur; char *buf; /* Set the target. */ memset(&base, 0, sizeof(UniHunk_t)); base.target.type = HUNK_TARGET_FACTION; xmlr_attr(node,"name",base.target.u.name); if (base.target.u.name==NULL) { WARN(_("Unidiff '%s' has an target node without a 'name' tag"), diff->name); return -1; } /* Now parse the possible changes. */ cur = node->xmlChildrenNode; do { xml_onlyNodes(cur); if (xml_isNode(cur,"visible")) { hunk.target.type = base.target.type; hunk.target.u.name = strdup(base.target.u.name); /* Faction type is constant. */ hunk.type = HUNK_TYPE_FACTION_VISIBLE; /* There is no name. */ hunk.u.name = NULL; /* Apply diff. */ if (diff_patchHunk( &hunk ) < 0) diff_hunkFailed( diff, &hunk ); else diff_hunkSuccess( diff, &hunk ); continue; } else if (xml_isNode(cur,"invisible")) { hunk.target.type = base.target.type; hunk.target.u.name = strdup(base.target.u.name); /* Faction type is constant. */ hunk.type = HUNK_TYPE_FACTION_INVISIBLE; /* There is no name. */ hunk.u.name = NULL; /* Apply diff. */ if (diff_patchHunk( &hunk ) < 0) diff_hunkFailed( diff, &hunk ); else diff_hunkSuccess( diff, &hunk ); continue; } else if (xml_isNode(cur,"faction")) { hunk.target.type = base.target.type; hunk.target.u.name = strdup(base.target.u.name); /* Get the faction to set the association of. */ xmlr_attr(cur,"name",hunk.u.name); /* Get the type. */ buf = xml_get(cur); if (buf==NULL) { WARN(_("Unidiff '%s': Null hunk type."), diff->name); continue; } if (strcmp(buf,"ally")==0) hunk.type = HUNK_TYPE_FACTION_ALLY; else if (strcmp(buf,"enemy")==0) hunk.type = HUNK_TYPE_FACTION_ENEMY; else if (strcmp(buf,"neutral")==0) hunk.type = HUNK_TYPE_FACTION_NEUTRAL; else WARN(_("Unidiff '%s': Unknown hunk type '%s' for faction '%s'."), diff->name, buf, hunk.u.name); /* Apply diff. */ if (diff_patchHunk( &hunk ) < 0) diff_hunkFailed( diff, &hunk ); else diff_hunkSuccess( diff, &hunk ); continue; } WARN(_("Unidiff '%s' has unknown node '%s'."), diff->name, node->name); } while (xml_nextNode(cur)); /* Clean up some stuff. */ free(base.target.u.name); base.target.u.name = NULL; return 0; }
/** * @brief Patches a system. * * @param diff Diff that is doing the patching. * @param node Node containing the system. * @return 0 on success. */ static int diff_patchSystem( UniDiff_t *diff, xmlNodePtr node ) { UniHunk_t base, hunk; xmlNodePtr cur; char *buf; /* Set the target. */ memset(&base, 0, sizeof(UniHunk_t)); base.target.type = HUNK_TARGET_SYSTEM; xmlr_attr(node,"name",base.target.u.name); if (base.target.u.name==NULL) { WARN(_("Unidiff '%s' has a system node without a 'name' tag, not applying."), diff->name); return -1; } /* Now parse the possible changes. */ cur = node->xmlChildrenNode; do { xml_onlyNodes(cur); if (xml_isNode(cur,"asset")) { hunk.target.type = base.target.type; hunk.target.u.name = strdup(base.target.u.name); /* Get the asset to modify. */ xmlr_attr(cur,"name",hunk.u.name); /* Get the type. */ buf = xml_get(cur); if (buf==NULL) { WARN(_("Unidiff '%s': Null hunk type."), diff->name); continue; } if (strcmp(buf,"add")==0) hunk.type = HUNK_TYPE_ASSET_ADD; else if (strcmp(buf,"remove")==0) hunk.type = HUNK_TYPE_ASSET_REMOVE; else if (strcmp(buf,"blackmarket")==0) hunk.type = HUNK_TYPE_ASSET_BLACKMARKET; else if (strcmp(buf,"legalmarket")==0) hunk.type = HUNK_TYPE_ASSET_LEGALMARKET; else WARN(_("Unidiff '%s': Unknown hunk type '%s' for asset '%s'."), diff->name, buf, hunk.u.name); /* Apply diff. */ if (diff_patchHunk( &hunk ) < 0) diff_hunkFailed( diff, &hunk ); else diff_hunkSuccess( diff, &hunk ); continue; } else if (xml_isNode(cur,"jump")) { hunk.target.type = base.target.type; hunk.target.u.name = strdup(base.target.u.name); /* Get the jump point to modify. */ xmlr_attr(cur,"target",hunk.u.name); /* Get the type. */ buf = xml_get(cur); if (buf==NULL) { WARN(_("Unidiff '%s': Null hunk type."), diff->name); continue; } if (strcmp(buf,"add")==0) hunk.type = HUNK_TYPE_JUMP_ADD; else if (strcmp(buf,"remove")==0) hunk.type = HUNK_TYPE_JUMP_REMOVE; else WARN(_("Unidiff '%s': Unknown hunk type '%s' for jump '%s'."), diff->name, buf, hunk.u.name); hunk.node = cur; /* Apply diff. */ if (diff_patchHunk( &hunk ) < 0) diff_hunkFailed( diff, &hunk ); else diff_hunkSuccess( diff, &hunk ); continue; } WARN(_("Unidiff '%s' has unknown node '%s'."), diff->name, node->name); } while (xml_nextNode(cur)); /* Clean up some stuff. */ free(base.target.u.name); base.target.u.name = NULL; return 0; }
/** * @brief Unpersists Lua data. * * @param L State to unperisist data into. * @param parent Node containing all the Lua persisted data. * @return 0 on success. */ static int nxml_unpersistDataNode( lua_State *L, xmlNodePtr parent ) { LuaPlanet p; LuaSystem s; LuaFaction f; LuaShip sh; LuaTime lt; Planet *pnt; StarSystem *ss; xmlNodePtr node; char *name, *type, *buf, *num; int keynum; node = parent->xmlChildrenNode; do { if (xml_isNode(node,"data")) { /* Get general info. */ xmlr_attr(node,"name",name); xmlr_attr(node,"type",type); /* Check to see if key is a number. */ xmlr_attr(node,"keynum",num); if (num != NULL) { keynum = 1; lua_pushnumber(L, atof(name)); free(num); } else lua_pushstring(L, name); /* handle data types */ /* Recursive tables. */ if (strcmp(type,"table")==0) { xmlr_attr(node,"name",buf); /* Create new table. */ lua_newtable(L); /* Save data. */ nxml_unpersistDataNode(L,node); /* Set table. */ free(buf); } else if (strcmp(type,"number")==0) lua_pushnumber(L,xml_getFloat(node)); else if (strcmp(type,"bool")==0) lua_pushboolean(L,xml_getInt(node)); else if (strcmp(type,"string")==0) lua_pushstring(L,xml_get(node)); else if (strcmp(type,"planet")==0) { pnt = planet_get(xml_get(node)); if (pnt != NULL) { p.id = planet_index(pnt); lua_pushplanet(L,p); } else WARN("Failed to load unexistent planet '%s'", xml_get(node)); } else if (strcmp(type,"system")==0) { ss = system_get(xml_get(node)); if (ss != NULL) { s.id = system_index( ss ); lua_pushsystem(L,s); } else WARN("Failed to load unexistent system '%s'", xml_get(node)); } else if (strcmp(type,"faction")==0) { f.f = faction_get(xml_get(node)); lua_pushfaction(L,f); } else if (strcmp(type,"ship")==0) { sh.ship = ship_get(xml_get(node)); lua_pushship(L,sh); } else if (strcmp(type,"time")==0) { lt.t = xml_getLong(node); lua_pushtime(L,lt); } else { WARN("Unknown lua data type!"); lua_pop(L,1); return -1; } /* Set field. */ lua_settable(L, -3); /* cleanup */ free(type); free(name); } } while (xml_nextNode(node)); 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 fleet node. * * @param temp Fleet to load. * @param parent Parent xml node of the fleet in question. * @return A newly allocated fleet loaded with data in parent node. */ static int fleet_parse( Fleet *temp, const xmlNodePtr parent ) { xmlNodePtr cur, node; FleetPilot* pilot; char* c; int mem; node = parent->xmlChildrenNode; /* Sane defaults and clean up. */ memset( temp, 0, sizeof(Fleet) ); temp->faction = -1; temp->name = (char*)xmlGetProp(parent,(xmlChar*)"name"); /* already mallocs */ if (temp->name == NULL) WARN("Fleet in "FLEET_DATA" has invalid or no name"); do { /* load all the data */ xml_onlyNodes(node); /* Set faction. */ if (xml_isNode(node,"faction")) { temp->faction = faction_get(xml_get(node)); continue; } /* Set AI. */ xmlr_strd(node,"ai",temp->ai); if (ai_getProfile ( temp->ai ) == NULL) WARN("Fleet '%s' has invalid AI '%s'.", temp->name, temp->ai ); /* Set flags. */ if (xml_isNode(node,"flags")){ cur = node->children; do { xml_onlyNodes(cur); WARN("Fleet '%s' has unknown flag node '%s'.", temp->name, cur->name); } while (xml_nextNode(cur)); continue; } /* Load pilots. */ else if (xml_isNode(node,"pilots")) { cur = node->children; mem = 0; do { xml_onlyNodes(cur); if (xml_isNode(cur,"pilot")) { /* See if must grow. */ temp->npilots++; if (temp->npilots > mem) { mem += CHUNK_SIZE; temp->pilots = realloc(temp->pilots, mem * sizeof(FleetPilot)); } pilot = &temp->pilots[temp->npilots-1]; /* Clear memory. */ memset( pilot, 0, sizeof(FleetPilot) ); /* Check for name override */ xmlr_attr(cur,"name",c); pilot->name = c; /* No need to free since it will have to later */ /* Check for AI override */ xmlr_attr(cur,"ai",pilot->ai); /* Load pilot's ship */ xmlr_attr(cur,"ship",c); if (c==NULL) WARN("Pilot %s in Fleet %s has null ship", pilot->name, temp->name); pilot->ship = ship_get(c); if (pilot->ship == NULL) WARN("Pilot %s in Fleet %s has invalid ship", pilot->name, temp->name); if (c!=NULL) free(c); continue; } WARN("Fleet '%s' has unknown pilot node '%s'.", temp->name, cur->name); } while (xml_nextNode(cur)); /* Resize to minimum. */ temp->pilots = realloc(temp->pilots, sizeof(FleetPilot)*temp->npilots); continue; } DEBUG("Unknown node '%s' in fleet '%s'",node->name,temp->name); } while (xml_nextNode(node)); #define MELEMENT(o,s) \ if (o) WARN("Fleet '%s' missing '"s"' element", temp->name) /**< Hack to check for missing fields. */ MELEMENT(temp->ai==NULL,"ai"); MELEMENT(temp->faction==-1,"faction"); MELEMENT(temp->pilots==NULL,"pilots"); #undef MELEMENT return 0; }
/** * @brief Parses a single faction, but doesn't set the allies/enemies bit. * * @param temp Faction to load data into. * @param parent Parent node to extract faction from. * @return Faction created from parent node. */ static int faction_parse( Faction* temp, xmlNodePtr parent ) { xmlNodePtr node; int player; char buf[PATH_MAX], *dat, *ctmp; glColour *col; uint32_t ndat; /* Clear memory. */ memset( temp, 0, sizeof(Faction) ); temp->name = xml_nodeProp(parent,"name"); if (temp->name == NULL) WARN("Faction from "FACTION_DATA_PATH" has invalid or no name"); player = 0; node = parent->xmlChildrenNode; do { /* Only care about nodes. */ xml_onlyNodes(node); /* Can be 0 or negative, so we have to take that into account. */ if (xml_isNode(node,"player")) { temp->player_def = xml_getFloat(node); player = 1; continue; } xmlr_strd(node,"longname",temp->longname); xmlr_strd(node,"display",temp->displayname); if (xml_isNode(node, "colour")) { ctmp = xml_getStrd(node); if (ctmp != NULL) temp->colour = col_fromName(xml_raw(node)); /* If no named colour is present, RGB attributes are used. */ else { /* Initialize in case a colour channel is absent. */ col = calloc( 1, sizeof(glColour*) ); xmlr_attr(node,"r",ctmp); if (ctmp != NULL) { col->r = atof(ctmp); free(ctmp); } xmlr_attr(node,"g",ctmp); if (ctmp != NULL) { col->g = atof(ctmp); free(ctmp); } xmlr_attr(node,"b",ctmp); if (ctmp != NULL) { col->b = atof(ctmp); free(ctmp); } col->a = 1.; temp->colour = col; } continue; } if (xml_isNode(node, "spawn")) { if (temp->sched_state != NULL) WARN("Faction '%s' has duplicate 'spawn' tag.", temp->name); nsnprintf( buf, sizeof(buf), "dat/factions/spawn/%s.lua", xml_raw(node) ); temp->sched_state = nlua_newState(); nlua_loadStandard( temp->sched_state, 0 ); dat = ndata_read( buf, &ndat ); if (luaL_dobuffer(temp->sched_state, dat, ndat, buf) != 0) { WARN("Failed to run spawn script: %s\n" "%s\n" "Most likely Lua file has improper syntax, please check", buf, lua_tostring(temp->sched_state,-1)); lua_close( temp->sched_state ); temp->sched_state = NULL; } free(dat); continue; } if (xml_isNode(node, "standing")) { if (temp->state != NULL) WARN("Faction '%s' has duplicate 'standing' tag.", temp->name); nsnprintf( buf, sizeof(buf), "dat/factions/standing/%s.lua", xml_raw(node) ); temp->state = nlua_newState(); nlua_loadStandard( temp->state, 0 ); dat = ndata_read( buf, &ndat ); if (luaL_dobuffer(temp->state, dat, ndat, buf) != 0) { WARN("Failed to run standing script: %s\n" "%s\n" "Most likely Lua file has improper syntax, please check", buf, lua_tostring(temp->state,-1)); lua_close( temp->state ); temp->state = NULL; } free(dat); continue; } if (xml_isNode(node, "known")) { faction_setFlag(temp, FACTION_KNOWN); continue; } if (xml_isNode(node, "equip")) { if (temp->equip_state != NULL) WARN("Faction '%s' has duplicate 'equip' tag.", temp->name); nsnprintf( buf, sizeof(buf), "dat/factions/equip/%s.lua", xml_raw(node) ); temp->equip_state = nlua_newState(); nlua_loadStandard( temp->equip_state, 0 ); dat = ndata_read( buf, &ndat ); if (luaL_dobuffer(temp->equip_state, dat, ndat, buf) != 0) { WARN("Failed to run equip script: %s\n" "%s\n" "Most likely Lua file has improper syntax, please check", buf, lua_tostring(temp->equip_state,-1)); lua_close( temp->equip_state ); temp->equip_state = NULL; } free(dat); continue; } if (xml_isNode(node,"logo")) { if (temp->logo_small != NULL) WARN("Faction '%s' has duplicate 'logo' tag.", temp->name); nsnprintf( buf, PATH_MAX, FACTION_LOGO_PATH"%s_small.png", xml_get(node)); temp->logo_small = gl_newImage(buf, 0); nsnprintf( buf, PATH_MAX, FACTION_LOGO_PATH"%s_tiny.png", xml_get(node)); temp->logo_tiny = gl_newImage(buf, 0); continue; } if (xml_isNode(node,"static")) { faction_setFlag(temp, FACTION_STATIC); continue; } if (xml_isNode(node,"invisible")) { faction_setFlag(temp, FACTION_INVISIBLE); continue; } /* Avoid warnings. */ if (xml_isNode(node,"allies") || xml_isNode(node,"enemies")) continue; DEBUG("Unknown node '%s' in faction '%s'",node->name,temp->name); } while (xml_nextNode(node)); if (player==0) DEBUG("Faction '%s' missing player tag.", temp->name); if ((temp->state!=NULL) && faction_isFlag( temp, FACTION_STATIC )) WARN("Faction '%s' has Lua and is static!", temp->name); if ((temp->state==NULL) && !faction_isFlag( temp, FACTION_STATIC )) WARN("Faction '%s' has no Lua and isn't static!", temp->name); 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 Loads an individual save. */ static int load_load( nsave_t *save, const char *path ) { xmlDocPtr doc; xmlNodePtr root, parent, node; char *version = NULL; memset( save, 0, sizeof(nsave_t) ); /* Load the XML. */ doc = xmlParseFile(path); if (doc == NULL) { WARN("Unable to parse save path '%s'.", path); return -1; } root = doc->xmlChildrenNode; /* base node */ if (root == NULL) { WARN("Unable to get child node of save '%s'.",path); xmlFreeDoc(doc); return -1; } /* Save path. */ save->path = strdup(path); /* Iterate inside the naev_save. */ parent = root->xmlChildrenNode; do { xml_onlyNodes(parent); /* Info. */ if (xml_isNode(parent,"version")) { node = parent->xmlChildrenNode; do { xmlr_strd(node,"naev",version); xmlr_strd(node,"data",save->data); } while (xml_nextNode(node)); continue; } if (xml_isNode(parent,"player")) { /* Get name. */ xmlr_attr(parent,"name",save->name); /* Parse rest. */ node = parent->xmlChildrenNode; do { xml_onlyNodes(node); /* Player info. */ xmlr_strd(node,"location",save->planet); xmlr_ulong(node,"credits",save->credits); /* Time. */ if (xml_isNode(node,"time")) { save->date = ntime_parseNode(node,path); continue; } /* Ship info. */ if (xml_isNode(node,"ship")) { xmlr_attr(node,"name",save->shipname); xmlr_attr(node,"model",save->shipmodel); continue; } } while (xml_nextNode(node)); continue; } } while (xml_nextNode(parent)); /* Handle version. */ if (version != NULL) { naev_versionParse( save->version, version, strlen(version) ); free(version); } /* Clean up. */ xmlFreeDoc(doc); return 0; }