/** * @brief Parses an XML tech node. */ static int tech_parseNodeData( tech_group_t *tech, xmlNodePtr parent ) { xmlNodePtr node; char *buf, *name; int ret; /* Parse the data. */ node = parent->xmlChildrenNode; do { xml_onlyNodes(node); if (xml_isNode(node,"item")) { /* Must have name. */ name = xml_get( node ); if (name == NULL) { WARN("Tech group '%s' has an item without a value.", tech->name); continue; } /* Try to find hard-coded type. */ buf = xml_nodeProp( node, "type" ); if (buf == NULL) { ret = 1; if (ret) ret = tech_addItemGroup( tech, name ); if (ret) ret = tech_addItemOutfit( tech, name ); if (ret) ret = tech_addItemShip( tech, name ); if (ret) ret = tech_addItemCommodity( tech, name ); if (ret) { WARN("Generic item '%s' not found in tech group '%s'", name, tech->name ); continue; } } else if (strcmp(buf,"group")==0) { if (!tech_addItemGroup( tech, name )) { WARN("Group item '%s' not found in tech group '%s'.", name, tech->name ); continue; } } else if (strcmp(buf,"outfit")==0) { if (!tech_addItemGroup( tech, name )) { WARN("Outfit item '%s' not found in tech group '%s'.", name, tech->name ); continue; } } else if (strcmp(buf,"ship")==0) { if (!tech_addItemGroup( tech, name )) { WARN("Ship item '%s' not found in tech group '%s'.", name, tech->name ); continue; } } else if (strcmp(buf,"commodity")==0) { if (!tech_addItemGroup( tech, name )) { WARN("Commodity item '%s' not found in tech group '%s'.", name, tech->name ); continue; } } continue; } WARN("Tech group '%s' has unknown node '%s'.", tech->name, node->name); } while (xml_nextNode( node )); return 0; }
static int load_module(xml_node *config) { xml_node *params, *profile, *settings; char *key, *value = NULL; LNOTICE("Loaded %s", module_name); load_module_xml_config(); /* READ CONFIG */ profile = module_xml_config; /* reset profile */ profile_size = 0; while (profile) { profile = xml_get("profile", profile, 1); if (profile == NULL) break; if (!profile->attr[4] || strncmp(profile->attr[4], "enable", 6)) { goto nextprofile; } /* if not equals "true" */ if (!profile->attr[5] || strncmp(profile->attr[5], "true", 4)) { goto nextprofile; } /* set values */ profile_protocol[profile_size].name = strdup(profile->attr[1]); profile_protocol[profile_size].description = strdup(profile->attr[3]); profile_protocol[profile_size].serial = atoi(profile->attr[7]); profile_protocol[profile_size].dialog_type = 0; profile_protocol[profile_size].dialog_timeout = 180; /* SETTINGS */ settings = xml_get("settings", profile, 1); if (settings != NULL) { params = settings; while (params) { params = xml_get("param", params, 1); if (params == NULL) break; if (params->attr[0] != NULL) { /* bad parser */ if (strncmp(params->attr[0], "name", 4)) { LERR("bad keys in the config"); goto nextparam; } key = params->attr[1]; if (params->attr[2] && params->attr[3] && !strncmp(params->attr[2], "value", 5)) { value = params->attr[3]; } else { value = params->child->value; } if (key == NULL || value == NULL) { LERR("bad values in the config"); goto nextparam; } if (!strncmp(key, "ignore", 6)) profile_protocol[profile_size].ignore = strdup(value); else if (!strncmp(key, "dialog-type", 11)) profile_protocol[profile_size].dialog_type = atoi(value); else if (!strncmp(key, "dialog-timeout", 14)) profile_protocol[profile_size].dialog_timeout = atoi(value); } nextparam: params = params->next; } } profile_size++; nextprofile: profile = profile->next; } /* free it */ free_module_xml_config(); return 0; }
/** * Parse a MobileIP module configuration from a configuration XML * @param config * @return */ int client_rf_parse_config(str config) { xmlDocPtr doc=0; xmlDtdPtr dtd=0; xmlNodePtr root=0,i=0; xmlChar *xc=0; long int l; str config_dtd; config_dtd.s=CLIENT_RF_CONFIG_DTD; config_dtd.len = strlen(config_dtd.s); doc = xml_get(config); if (!doc){ LOG(L_ERR," The configuration does not contain a valid XML\n"); goto error; } dtd = xml_get_dtd(config_dtd); if (!dtd){ LOG(L_ERR," The DTD is not valid\n"); goto error; } if (xml_validate_dtd(doc,dtd)!=1){ LOG(L_ERR," Verification of configuration XML against DTD failed!\n"); goto error; } root = xmlDocGetRootElement(doc); if (!root){ LOG(L_ERR," Empty XML\n"); goto error; } while(root && (root->type!=XML_ELEMENT_NODE || strcasecmp((char*)root->name,"Client_Rf")!=0)){ root = root->next; } if (!root) { LOG(L_ERR," No <Client_Rf> found in configuration\n"); goto error; } for(i=root->children;i;i=i->next) if (i->type==XML_ELEMENT_NODE) { /* Rf */ if (strcasecmp((char*)i->name,"Rf")==0){ if (!xml_get_prop_as_int(i,"node_func",&l)||l<0 || l>10){ LOG(L_ERR,"node_role value between 0 and 10\n"); goto error; }else cfg.node_func = (int)l; xc = xmlGetProp(i,(xmlChar*)"origin_host"); if (xc){ char_dup_str(cfg.origin_host,xc,shm); xmlFree(xc); } xc = xmlGetProp(i,(xmlChar*)"origin_realm"); if (xc){ char_dup_str(cfg.origin_realm,xc,shm); xmlFree(xc); } xc = xmlGetProp(i,(xmlChar*)"destination_host"); if (xc){ char_dup_str(cfg.destination_host,xc,shm); xmlFree(xc); } xc = xmlGetProp(i,(xmlChar*)"destination_realm"); if (xc){ char_dup_str(cfg.destination_realm,xc,shm); xmlFree(xc); } xc = xmlGetProp(i,(xmlChar*)"service_context_id"); if (xc){ char_dup_str(cfg.service_context_id,xc,shm); xmlFree(xc); } } else if (strcasecmp((char*)i->name,"Hash")==0){ if (!xml_get_prop_as_int(i,"hash_size",&l)||l<0){ LOG(L_ERR,"invalid hash size, value >0 are accepted\n"); goto error; }else cfg.hash_table_size = (int)l; } } if (doc) xml_free(doc); if (dtd) xml_free_dtd(dtd); return 1; error: out_of_memory: if (xc) xmlFree(xc); if (doc) xml_free(doc); if (dtd) xml_free_dtd(dtd); return 0; }
/** * @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 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 event 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_PATH" has invalid or no name"); node = parent->xmlChildrenNode; do { /* load all the data */ /* Only check nodes. */ xml_onlyNodes(node); if (xml_isNode(node,"lua")) { nsnprintf( 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 event '%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 if (strcmp(buf,"load")==0) temp->trigger = EVENT_TRIGGER_LOAD; else if (strcmp(buf,"none")==0) temp->trigger = EVENT_TRIGGER_NONE; 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 { xml_onlyNodes(cur); if (xml_isNode(cur,"unique")) { temp->flags |= EVENT_FLAG_UNIQUE; continue; } WARN("Event '%s' has unknown flag node '%s'.", temp->name, cur->name); } 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->trigger!=EVENT_TRIGGER_NONE) && (temp->chance==0.),"chance"); MELEMENT(temp->trigger==EVENT_TRIGGER_NULL,"trigger"); #undef MELEMENT 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 }