/* vi: set ts=2: +-------------------+ | | Enno Rehling | Eressea PBEM host | Christian Schlittchen | (c) 1998 - 2004 | Katja Zedel | | Henning Peters +-------------------+ This program may not be used, modified or distributed without prior permission by the authors of Eressea. */ #include #include #include "xmlreader.h" /* kernel includes */ #include "building.h" #include "equipment.h" #include "item.h" #include "message.h" #include "race.h" #include "region.h" #include "resources.h" #include "ship.h" #include "terrain.h" #include "skill.h" #include "spell.h" #include "calendar.h" /* util includes */ #include #include #include #include #include #include #include #include /* libxml includes */ #include #include #include /* libc includes */ #include #include #include #include static boolean gamecode_enabled = false; void (*set_spelldata_cb)(struct spell * sp) = 0; static building_type * bt_get_or_create(const char * name) { if (name!=NULL) { building_type * btype = bt_find(name); if (btype==NULL) { btype = calloc(sizeof(building_type), 1); btype->_name = strdup(name); bt_register(btype); } return btype; } return NULL; } void enable_xml_gamecode(void) { gamecode_enabled = true; } static void xml_readtext(xmlNodePtr node, struct locale ** lang, xmlChar **text) { xmlChar * propValue = xmlGetProp(node, BAD_CAST "locale"); assert(propValue!=NULL); *lang = find_locale((const char*)propValue); #ifdef MAKE_LOCALES if (*lang==NULL) *lang = make_locale((const char*)propValue); #endif xmlFree(propValue); *text = xmlNodeListGetString(node->doc, node->children, 1); } static const spell * xml_spell(xmlNode * node, const char * name) { const spell * sp = NULL; xmlChar * propValue = xmlGetProp(node, BAD_CAST name); if (propValue!=NULL) { sp = find_spell(M_NONE, (const char *)propValue); assert(sp); xmlFree(propValue); } return sp; } static xmlChar * xml_cleanup_string(xmlChar * str) { xmlChar * read = str; xmlChar * write = str; while (*read) { /* eat leading whitespace */ if (*read && isxspace(*read)) { while (*read && isxspace(*read)) { ++read; } *write++ = ' '; } while (*read) { if (*read== '\n') break; if (*read== '\r') break; *write++ = *read++; } } *write = 0; return str; } static const resource_type * rt_findorcreate(const char * name) { resource_type * rtype = rt_find(name); if (rtype==NULL) { const char * names[2]; char * namep = strcat(strcpy((char*)malloc(strlen(name)+3), name), "_p"); /* we'll make a placeholder */ names[0] = name; names[1] = namep; rtype = new_resourcetype(names, NULL, RTF_NONE); free(namep); } return rtype; } static void xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray) { int req; requirement * radd = *reqArray; assert (radd==NULL); if (nodeNr==0) return; radd = *reqArray = calloc(sizeof(requirement), nodeNr+1); for (req=0;req!=nodeNr;++req) { xmlNodePtr node = nodeTab[req]; xmlChar * propValue; radd->number = xml_ivalue(node, "quantity", 1); radd->recycle = xml_fvalue(node, "recycle", 0.5); propValue = xmlGetProp(node, BAD_CAST "type"); radd->rtype = rt_findorcreate((const char*)propValue); xmlFree(propValue); ++radd; } } void xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, construction ** consPtr) { xmlNodePtr pushNode = xpath->node; int k; for (k=0;k!=nodeSet->nodeNr;++k) { xmlNodePtr node = nodeSet->nodeTab[k]; xmlChar * propValue; construction * con; xmlXPathObjectPtr req; int m; skill_t sk = NOSKILL; propValue = xmlGetProp(node, BAD_CAST "skill"); if (propValue!=NULL) { sk = sk_find((const char*)propValue); if (sk==NOSKILL) { log_error(("construction requires skill '%s' that does not exist.\n", (const char *)propValue)); xmlFree(propValue); continue; } xmlFree(propValue); } assert(*consPtr==NULL); *consPtr = con = calloc(sizeof(construction), 1); consPtr = &con->improvement; con->skill = sk; con->maxsize = xml_ivalue(node, "maxsize", -1); con->minskill = xml_ivalue(node, "minskill", -1); con->reqsize = xml_ivalue(node, "reqsize", -1); propValue = xmlGetProp(node, BAD_CAST "building"); if (propValue!=NULL) { con->btype = bt_get_or_create((const char*)propValue); xmlFree(propValue); } /* read construction/requirement */ xpath->node = node; req = xmlXPathEvalExpression(BAD_CAST "requirement", xpath); xml_readrequirements(req->nodesetval->nodeTab, req->nodesetval->nodeNr, &con->materials); xmlXPathFreeObject(req); /* read construction/modifier */ xpath->node = node; req = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); for (m=0;m!=req->nodesetval->nodeNr;++m) { xmlNodePtr node = req->nodesetval->nodeTab[m]; propValue = xmlGetProp(node, BAD_CAST "function"); if (propValue!=NULL) { pf_generic foo = get_function((const char*)propValue); a_add(&con->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, (skillmod_fun)foo, 1.0, 0)); xmlFree(propValue); } } xmlXPathFreeObject(req); } xpath->node = pushNode; } static int parse_function(xmlNodePtr node, pf_generic * funPtr, xmlChar ** namePtr) { pf_generic fun; xmlChar * propValue = xmlGetProp(node, BAD_CAST "value"); assert(propValue!=NULL); fun = get_function((const char*)propValue); if (fun!=NULL) { xmlFree(propValue); propValue = xmlGetProp(node, BAD_CAST "name"); } *namePtr = propValue; *funPtr = fun; return 0; } static int parse_buildings(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr buildings; int i; /* reading eressea/buildings/building */ buildings = xmlXPathEvalExpression(BAD_CAST "/eressea/buildings/building", xpath); if (buildings->nodesetval!=NULL) { xmlNodeSetPtr nodes = buildings->nodesetval; for (i=0;i!=nodes->nodeNr;++i) { xmlNodePtr node = nodes->nodeTab[i]; xmlChar * propValue; building_type * btype; xmlXPathObjectPtr result; int k; propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue!=NULL); btype = bt_get_or_create((const char*)propValue); xmlFree(propValue); btype->capacity = xml_ivalue(node, "capacity", -1); btype->maxcapacity = xml_ivalue(node, "maxcapacity", -1); btype->maxsize = xml_ivalue(node, "maxsize", -1); btype->magres = xml_ivalue(node, "magres", 0); btype->magresbonus = xml_ivalue(node, "magresbonus", 0); btype->fumblebonus = xml_ivalue(node, "fumblebonus", 0); btype->auraregen = xml_fvalue(node, "auraregen", 1.0); if (xml_bvalue(node, "nodestroy", false)) btype->flags |= BTF_INDESTRUCTIBLE; if (xml_bvalue(node, "oneperturn", false)) btype->flags |= BTF_ONEPERTURN; if (xml_bvalue(node, "nobuild", false)) btype->flags |= BTF_NOBUILD; if (xml_bvalue(node, "namechange", true)) btype->flags |= BTF_NAMECHANGE; if (xml_bvalue(node, "unique", false)) btype->flags |= BTF_UNIQUE; if (xml_bvalue(node, "decay", false)) btype->flags |= BTF_DECAY; if (xml_bvalue(node, "magic", false)) btype->flags |= BTF_MAGIC; /* reading eressea/buildings/building/construction */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); xml_readconstruction(xpath, result->nodesetval, &btype->construction); xmlXPathFreeObject(result); if (gamecode_enabled) { /* reading eressea/buildings/building/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; pf_generic fun; parse_function(node, &fun, &propValue); if (fun==NULL) { log_error(("unknown function name '%s' for building %s\n", (const char*)propValue, btype->_name)); xmlFree(propValue); continue; } assert(propValue!=NULL); if (strcmp((const char*)propValue, "name")==0) { btype->name = (const char * (*)(const struct building_type*, const struct building *, int))fun; } else if (strcmp((const char*)propValue, "init")==0) { btype->init = (void (*)(struct building_type*))fun; } else if (strcmp((const char*)propValue, "age")==0) { btype->age = (void (*)(struct building*))fun; } else if (strcmp((const char*)propValue, "protection")==0) { btype->protection = (int (*)(struct building*, struct unit *))fun; } else if (strcmp((const char*)propValue, "taxes")==0) { btype->taxes = (double (*)(const struct building*, int))fun; } else if (strcmp((const char*)propValue, "age")==0) { btype->age = (void (*)(struct building*))fun; } else { log_error(("unknown function type '%s' for building %s\n", (const char*)propValue, btype->_name)); } xmlFree(propValue); } xmlXPathFreeObject(result); } /* reading eressea/buildings/building/maintenance */ result = xmlXPathEvalExpression(BAD_CAST "maintenance", xpath); for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; maintenance * mt; if (btype->maintenance==NULL) { btype->maintenance = calloc(sizeof(struct maintenance), result->nodesetval->nodeNr+1); } mt = btype->maintenance + k; mt->number = xml_ivalue(node, "amount", 0); propValue = xmlGetProp(node, BAD_CAST "type"); assert(propValue!=NULL); mt->rtype = rt_find((const char*)propValue); assert(mt->rtype!=NULL); xmlFree(propValue); if (xml_bvalue(node, "variable", false)) mt->flags |= MTF_VARIABLE; if (xml_bvalue(node, "vital", false)) mt->flags |= MTF_VITAL; } xmlXPathFreeObject(result); /* finally, initialize the new building type */ if (btype->init) btype->init(btype); } } xmlXPathFreeObject(buildings); xmlXPathFreeContext(xpath); return 0; } static int parse_calendar(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr xpathCalendars; xmlNodeSetPtr nsetCalendars; int c, rv = 0; /* reading eressea/buildings/building */ xpathCalendars = xmlXPathEvalExpression(BAD_CAST "/eressea/calendar", xpath); nsetCalendars = xpathCalendars->nodesetval; months_per_year = 0; if (nsetCalendars==NULL || nsetCalendars->nodeNr==0) { rv = -1; } else for (c=0;c!=nsetCalendars->nodeNr;++c) { xmlNodePtr calendar = nsetCalendars->nodeTab[c]; xmlXPathObjectPtr xpathWeeks, xpathMonths, xpathSeasons; xmlNodeSetPtr nsetWeeks, nsetMonths, nsetSeasons; xmlChar * propValue = xmlGetProp(calendar, BAD_CAST "name"); xmlChar * newyear = xmlGetProp(calendar, BAD_CAST "newyear"); first_turn = xml_ivalue(calendar, "start", first_turn); if (propValue) { free(agename); agename = strdup(mkname("calendar", (const char*)propValue)); xmlFree(propValue); } xpath->node = calendar; xpathWeeks = xmlXPathEvalExpression(BAD_CAST "week", xpath); nsetWeeks = xpathWeeks->nodesetval; if (nsetWeeks!=NULL && nsetWeeks->nodeNr) { int i; weeks_per_month = nsetWeeks->nodeNr; assert(!weeknames); weeknames = malloc(sizeof(char *) * weeks_per_month); weeknames2 = malloc(sizeof(char *) * weeks_per_month); for (i=0;i!=nsetWeeks->nodeNr;++i) { xmlNodePtr week = nsetWeeks->nodeTab[i]; xmlChar * propValue = xmlGetProp(week, BAD_CAST "name"); if (propValue) { weeknames[i] = strdup(mkname("calendar", (const char*)propValue)); weeknames2[i] = malloc(strlen(weeknames[i])+3); sprintf(weeknames2[i], "%s_d", weeknames[i]); xmlFree(propValue); } } } xmlXPathFreeObject(xpathWeeks); xpathSeasons = xmlXPathEvalExpression(BAD_CAST "season", xpath); nsetSeasons = xpathSeasons->nodesetval; if (nsetSeasons!=NULL && nsetSeasons->nodeNr) { int i; seasons = nsetSeasons->nodeNr; assert(!seasonnames); seasonnames = malloc(sizeof(char *) * seasons); for (i=0;i!=nsetSeasons->nodeNr;++i) { xmlNodePtr season = nsetSeasons->nodeTab[i]; xmlChar * propValue = xmlGetProp(season, BAD_CAST "name"); if (propValue) { seasonnames[i] = strdup(mkname("calendar", (const char*)propValue)); xmlFree(propValue); } } } xpathMonths = xmlXPathEvalExpression(BAD_CAST "season/month", xpath); nsetMonths = xpathMonths->nodesetval; if (nsetMonths!=NULL && nsetMonths->nodeNr) { int i; months_per_year = nsetMonths->nodeNr; assert(!monthnames); monthnames = malloc(sizeof(char *) * months_per_year); month_season = malloc(sizeof(int) * months_per_year); storms = malloc(sizeof(int) * months_per_year); for (i=0;i!=nsetMonths->nodeNr;++i) { xmlNodePtr month = nsetMonths->nodeTab[i]; xmlChar * propValue = xmlGetProp(month, BAD_CAST "name"); int j; if (propValue) { if (newyear && strcmp((const char*)newyear, (const char*)propValue)==0) { first_month = i; xmlFree(newyear); newyear = NULL; } monthnames[i] = strdup(mkname("calendar", (const char*)propValue)); xmlFree(propValue); } for (j=0;j!=seasons;++j) { xmlNodePtr season = month->parent; if (season==nsetSeasons->nodeTab[j]) { month_season[i] = j; break; } } assert(j!=seasons); storms[i] = xml_ivalue(nsetMonths->nodeTab[i], "storm", 0); } } xmlXPathFreeObject(xpathMonths); xmlXPathFreeObject(xpathSeasons); } xmlXPathFreeObject(xpathCalendars); xmlXPathFreeContext(xpath); return rv; } static int parse_directions(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr xpathDirections; xmlNodeSetPtr nsetDirections; int rv = 0; /* reading eressea/directions/dir */ xpathDirections = xmlXPathEvalExpression(BAD_CAST "/eressea/directions/dir", xpath); nsetDirections = xpathDirections->nodesetval; if (nsetDirections!=NULL) { int k; for (k=0;k!=nsetDirections->nodeNr;++k) { xmlNodePtr dir = nsetDirections->nodeTab[k]; xmlChar * propValue = xmlGetProp(dir, BAD_CAST "name"); register_special_direction((const char *)propValue); xmlFree(propValue); } } xmlXPathFreeObject(xpathDirections); xmlXPathFreeContext(xpath); return rv; } static int parse_ships(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr ships; int i; /* reading eressea/ships/ship */ ships = xmlXPathEvalExpression(BAD_CAST "/eressea/ships/ship", xpath); if (ships->nodesetval!=NULL) { xmlNodeSetPtr nodes = ships->nodesetval; for (i=0;i!=nodes->nodeNr;++i) { xmlNodePtr child, node = nodes->nodeTab[i]; xmlChar * propValue; ship_type * st = calloc(sizeof(ship_type), 1); xmlXPathObjectPtr result; int k, c; propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue!=NULL); st->name[0] = strdup((const char *)propValue); st->name[1] = strcat(strcpy(malloc(strlen(st->name[0])+3), st->name[0]),"_a"); xmlFree(propValue); st->cabins = xml_ivalue(node, "cabins", 0) * PERSON_WEIGHT; st->cargo = xml_ivalue(node, "cargo", 0); st->combat = xml_ivalue(node, "combat", 0); st->cptskill = xml_ivalue(node, "cptskill", 0); st->damage = xml_fvalue(node, "damage", 0.0); if (xml_bvalue(node, "nocoast", false)) st->flags |= SFL_NOCOAST; if (xml_bvalue(node, "fly", false)) st->flags |= SFL_FLY; if (xml_bvalue(node, "opensea", false)) st->flags |= SFL_OPENSEA; st->fishing = xml_ivalue(node, "fishing", 0); st->minskill = xml_ivalue(node, "minskill", 0); st->range = xml_ivalue(node, "range", 0); st->storm = xml_fvalue(node, "storm", 1.0); st->sumskill = xml_ivalue(node, "sumskill", 0); /* reading eressea/ships/ship/construction */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); xml_readconstruction(xpath, result->nodesetval, &st->construction); xmlXPathFreeObject(result); for (child=node->children;child;child=child->next) { if (strcmp((const char *)child->name, "modifier")==0) { double value = xml_fvalue(child, "value", 0.0); propValue = xmlGetProp(child, BAD_CAST "type"); if (strcmp((const char *)propValue, "tactics")==0) st->tac_bonus = (float)value; else if (strcmp((const char *)propValue, "attack")==0) st->at_bonus = (int)value; else if (strcmp((const char *)propValue, "defense")==0) st->df_bonus = (int)value; xmlFree(propValue); } } /* reading eressea/ships/ship/coast */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "coast", xpath); for (c=0,k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; if (k==0) { assert(st->coasts==NULL); st->coasts = (const terrain_type**)malloc(sizeof(const terrain_type*) * (result->nodesetval->nodeNr+1)); st->coasts[result->nodesetval->nodeNr] = NULL; } propValue = xmlGetProp(node, BAD_CAST "terrain"); assert(propValue!=NULL); st->coasts[c] = get_terrain((const char*)propValue); if (st->coasts[c]!=NULL) ++c; else { log_warning(("ship %s mentions a non-existing terrain %s.\n", st->name[0], propValue)); } xmlFree(propValue); } xmlXPathFreeObject(result); /* finally, register the new building type */ st_register(st); } } xmlXPathFreeObject(ships); xmlXPathFreeContext(xpath); return 0; } static void race_compat(void) { /* required for old_race, do not change order! */ const char * oldracenames[MAXRACES] = { "dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect", "halfling", "cat", "aquarian", "orc", "snotling", "undead", "illusion", "youngdragon", "dragon", "wyrm", "ent", "catdragon", "dracoid", "special", "spell", "irongolem", "stonegolem", "shadowdemon", "shadowmaster", "mountainguard", "alp", "toad", "braineater", "peasant", "wolf", NULL, NULL, NULL, NULL, "songdragon", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "seaserpent", "shadowknight", "centaur", "skeleton", "skeletonlord", "zombie", "juju-zombie", "ghoul", "ghast", "museumghost", "gnome", "template", "clone" }; int i; for (i=0;i!=MAXRACES;++i) { const char * rcname = oldracenames[i]; if (rcname==NULL) { new_race[i] = NULL; } else { race * rc = rc_find(oldracenames[i]); if (rc) { new_race[i] = rc; if (rc == new_race[RC_TROLL]) { a_add(&rc->attribs, make_skillmod(NOSKILL, SMF_RIDING, NULL, 0.0, -1)); } } } } } static potion_type * xml_readpotion(xmlXPathContextPtr xpath, item_type * itype) { int level = xml_ivalue(xpath->node, "level", 0); assert(level>0); return new_potiontype(itype, level); } static luxury_type * xml_readluxury(xmlXPathContextPtr xpath, item_type * itype) { int price = xml_ivalue(xpath->node, "price", 0); return new_luxurytype(itype, price); } static armor_type * xml_readarmor(xmlXPathContextPtr xpath, item_type * itype) { xmlNodePtr node = xpath->node; armor_type * atype = NULL; unsigned int flags = ATF_NONE; int ac = xml_ivalue(node, "ac", 0); double penalty = xml_fvalue(node, "penalty", 0.0); double magres = xml_fvalue(node, "magres", 0.0); if (xml_bvalue(node, "laen", false)) flags |= ATF_LAEN; if (xml_bvalue(node, "shield", false)) flags |= ATF_SHIELD; atype = new_armortype(itype, penalty, magres, ac, flags); atype->projectile = (float)xml_fvalue(node, "projectile", 0.0); return atype; } static weapon_type * xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) { xmlNodePtr node = xpath->node; weapon_type * wtype = NULL; unsigned int flags = WTF_NONE; xmlXPathObjectPtr result; xmlChar * propValue; int k; skill_t sk; int minskill = xml_ivalue(node, "minskill", 0); int offmod = xml_ivalue(node, "offmod", 0); int defmod = xml_ivalue(node, "defmod", 0); int reload = xml_ivalue(node, "reload", 0); double magres = xml_fvalue(node, "magres", 0.0); if (xml_bvalue(node, "armorpiercing", false)) flags |= WTF_ARMORPIERCING; if (xml_bvalue(node, "magical", false)) flags |= WTF_MAGICAL; if (xml_bvalue(node, "missile", false)) flags |= WTF_MISSILE; if (xml_bvalue(node, "pierce", false)) flags |= WTF_PIERCE; if (xml_bvalue(node, "cut", false)) flags |= WTF_CUT; if (xml_bvalue(node, "blunt", false)) flags |= WTF_BLUNT; if (xml_bvalue(node, "siege", false)) flags |= WTF_SIEGE; if (xml_bvalue(node, "horse", (flags&WTF_MISSILE)==0)) flags |= WTF_HORSEBONUS; if (xml_bvalue(node, "useshield", true)) flags |= WTF_USESHIELD; propValue = xmlGetProp(node, BAD_CAST "skill"); assert(propValue!=NULL); sk = sk_find((const char*)propValue); assert(sk!=NOSKILL); xmlFree(propValue); wtype = new_weapontype(itype, flags, magres, NULL, offmod, defmod, reload, sk, minskill); /* reading weapon/damage */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "damage", xpath); assert(result->nodesetval->nodeNr<=2); for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; int pos = 0; propValue = xmlGetProp(node, BAD_CAST "type"); if (strcmp((const char *)propValue, "footman")!=0) { pos = 1; } xmlFree(propValue); propValue = xmlGetProp(node, BAD_CAST "value"); wtype->damage[pos] = gc_add(strdup((const char*)propValue)); if (k==0) wtype->damage[1-pos] = wtype->damage[pos]; xmlFree(propValue); } xmlXPathFreeObject(result); /* reading weapon/modifier */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); assert(wtype->modifiers==NULL); wtype->modifiers = calloc(result->nodesetval->nodeNr+1, sizeof(weapon_mod)); for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; xmlXPathObjectPtr races; int r, flags = 0; if (xml_bvalue(node, "walking", false)) flags|=WMF_WALKING; if (xml_bvalue(node, "riding", false)) flags|=WMF_RIDING; if (xml_bvalue(node, "against_walking", false)) flags|=WMF_AGAINST_WALKING; if (xml_bvalue(node, "against_riding", false)) flags|=WMF_AGAINST_RIDING; if (xml_bvalue(node, "offensive", false)) flags|=WMF_OFFENSIVE; if (xml_bvalue(node, "defensive", false)) flags|=WMF_DEFENSIVE; propValue = xmlGetProp(node, BAD_CAST "type"); if (strcmp((const char*)propValue, "damage")==0) flags|=WMF_DAMAGE; else if (strcmp((const char*)propValue, "skill")==0) flags|=WMF_SKILL; else if (strcmp((const char*)propValue, "missile_target")==0) flags|=WMF_MISSILE_TARGET; xmlFree(propValue); wtype->modifiers[k].flags = flags; wtype->modifiers[k].value = xml_ivalue(node, "value", 0); xpath->node = node; races = xmlXPathEvalExpression(BAD_CAST "race", xpath); for (r=0;r!=races->nodesetval->nodeNr;++r) { xmlNodePtr node = races->nodesetval->nodeTab[r]; propValue = xmlGetProp(node, BAD_CAST "name"); if (propValue!=NULL) { const race * rc = rc_find((const char*)propValue); if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); racelist_insert(&wtype->modifiers[k].races, rc); xmlFree(propValue); } } xmlXPathFreeObject(races); } xmlXPathFreeObject(result); if (gamecode_enabled) { /* reading weapon/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; xmlChar * propValue; pf_generic fun; parse_function(node, &fun, &propValue); if (fun==NULL) { log_error(("unknown function name '%s' for item '%s'\n", (const char*)propValue, itype->rtype->_name[0])); xmlFree(propValue); continue; } assert(propValue!=NULL); if (strcmp((const char*)propValue, "attack")==0) { wtype->attack = (boolean (*)(const struct troop*, const struct weapon_type *, int*))fun; } else { log_error(("unknown function type '%s' for item '%s'\n", (const char*)propValue, itype->rtype->_name[0])); } xmlFree(propValue); } xmlXPathFreeObject(result); } xpath->node = node; return wtype; } static item_type * xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) { xmlNodePtr node = xpath->node; item_type * itype = NULL; unsigned int flags = ITF_NONE; xmlXPathObjectPtr result; int k; int weight = xml_ivalue(node, "weight", 0); int capacity = xml_ivalue(node, "capacity", 0); if (xml_bvalue(node, "cursed", false)) flags |= ITF_CURSED; if (xml_bvalue(node, "notlost", false)) flags |= ITF_NOTLOST; if (xml_bvalue(node, "herb", false)) flags |= ITF_HERB; if (xml_bvalue(node, "big", false)) flags |= ITF_BIG; if (xml_bvalue(node, "animal", false)) flags |= ITF_ANIMAL; if (xml_bvalue(node, "vehicle", false)) flags |= ITF_VEHICLE; itype = new_itemtype(rtype, flags, weight, capacity); #if SCORE_MODULE itype->score = xml_ivalue(node, "score", 0); #endif /* reading item/construction */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); xml_readconstruction(xpath, result->nodesetval, &itype->construction); xmlXPathFreeObject(result); /* reading item/weapon */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "weapon", xpath); assert(result->nodesetval->nodeNr<=1); if (result->nodesetval->nodeNr!=0) { xpath->node = result->nodesetval->nodeTab[0]; rtype->wtype = xml_readweapon(xpath, itype); } xmlXPathFreeObject(result); /* reading item/potion */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "potion", xpath); assert(result->nodesetval->nodeNr<=1); if (result->nodesetval->nodeNr!=0) { xpath->node = result->nodesetval->nodeTab[0]; rtype->ptype = xml_readpotion(xpath, itype); } xmlXPathFreeObject(result); /* reading item/luxury */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "luxury", xpath); assert(result->nodesetval->nodeNr<=1); if (result->nodesetval->nodeNr!=0) { xpath->node = result->nodesetval->nodeTab[0]; rtype->ltype = xml_readluxury(xpath, itype); } xmlXPathFreeObject(result); /* reading item/armor */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "armor", xpath); assert(result->nodesetval->nodeNr<=1); if (result->nodesetval->nodeNr!=0) { xpath->node = result->nodesetval->nodeTab[0]; rtype->atype = xml_readarmor(xpath, itype); } xmlXPathFreeObject(result); if (gamecode_enabled) { /* reading item/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; xmlChar * propValue; pf_generic fun; parse_function(node, &fun, &propValue); if (fun==NULL) { log_error(("unknown function name '%s' for item '%s'\n", (const char*)propValue, rtype->_name[0])); xmlFree(propValue); continue; } assert(propValue!=NULL); if (strcmp((const char*)propValue, "give")==0) { itype->give = (int (*)(struct unit*, struct unit*, const struct item_type *, int, struct order *))fun; } else if (strcmp((const char*)propValue, "use")==0) { itype->use = (int (*)(struct unit *, const struct item_type *, int, struct order *))fun; } else if (strcmp((const char*)propValue, "canuse")==0) { itype->canuse = (boolean (*)(const struct unit *, const struct item_type *))fun; } else if (strcmp((const char*)propValue, "useonother")==0) { itype->useonother = (int (*)(struct unit *, int, const struct item_type *, int, struct order *))fun; } else { log_error(("unknown function type '%s' for item '%s'\n", (const char*)propValue, rtype->_name[0])); } xmlFree(propValue); } xmlXPathFreeObject(result); } return itype; } static int parse_rules(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr functions; xmlNodeSetPtr nodes; int i; /* reading eressea/resources/resource */ functions = xmlXPathEvalExpression(BAD_CAST "/eressea/rules/function", xpath); nodes = functions->nodesetval; for (i=0;i!=nodes->nodeNr;++i) { xmlNodePtr node = nodes->nodeTab[i]; xmlChar *propValue; pf_generic fun; parse_function(node, &fun, &propValue); if (fun==NULL) { log_error(("unknown function for rule '%s' %s\n", (const char*)propValue)); xmlFree(propValue); continue; } assert(propValue!=NULL); if (strcmp((const char*)propValue, "wage")==0) { global.functions.wage = (int (*)(const struct region*, const struct faction*, const struct race*, int))fun; } else if (strcmp((const char*)propValue, "maintenance")==0) { global.functions.maintenance = (int (*)(const struct unit*))fun; } else { log_error(("unknown function for rule '%s'\n", (const char*)propValue)); } xmlFree(propValue); } xmlXPathFreeObject(functions); xmlXPathFreeContext(xpath); return 0; } static int parse_resources(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr resources; xmlNodeSetPtr nodes; int i; /* reading eressea/resources/resource */ resources = xmlXPathEvalExpression(BAD_CAST "/eressea/resources/resource", xpath); nodes = resources->nodesetval; for (i=0;i!=nodes->nodeNr;++i) { xmlNodePtr node = nodes->nodeTab[i]; xmlChar *propValue, *name, *appearance; const char *names[2], *appearances[2]; char * namep = NULL, * appearancep = NULL; resource_type * rtype; unsigned int flags = RTF_NONE; xmlXPathObjectPtr result; int k; if (xml_bvalue(node, "pooled", true)) flags |= RTF_POOLED; if (xml_bvalue(node, "limited", false)) flags |= RTF_LIMITED; name = xmlGetProp(node, BAD_CAST "name"); appearance = xmlGetProp(node, BAD_CAST "appearance"); assert(name!=NULL); if (appearance!=NULL) { appearancep = strcat(strcpy((char*)malloc(strlen((char*)appearance)+3), (char*)appearance), "_p"); } rtype = rt_find((const char *)name); if (rtype!=NULL) { /* dependency from another item, was created earlier */ rtype->flags |= flags; if (appearance) { rtype->_appearance[0] = strdup((const char*)appearance); rtype->_appearance[1] = appearancep; free(appearancep); } } else { namep = strcat(strcpy((char*)malloc(strlen((char*)name)+3), (char*)name), "_p"); names[0] = (const char*)name; names[1] = namep; if (appearance) { appearances[0] = (const char*)appearance; appearances[1] = appearancep; rtype = new_resourcetype((const char**)names, (const char**)appearances, flags); free(appearancep); } else { rtype = new_resourcetype(names, NULL, flags); } free(namep); } if (name) xmlFree(name); if (appearance) xmlFree(appearance); name = xmlGetProp(node, BAD_CAST "material"); if (name) { rmt_create(rtype, (const char *)name); xmlFree(name); } if (gamecode_enabled) { /* reading eressea/resources/resource/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; pf_generic fun; parse_function(node, &fun, &propValue); if (fun==NULL) { log_error(("unknown function name '%s' for resource %s\n", (const char*)propValue, rtype->_name[0])); xmlFree(propValue); continue; } assert(propValue!=NULL); if (strcmp((const char*)propValue, "change")==0) { rtype->uchange = (rtype_uchange)fun; } else if (strcmp((const char*)propValue, "get")==0) { rtype->uget = (rtype_uget)fun; } else if (strcmp((const char*)propValue, "name")==0) { rtype->name = (rtype_name)fun; } else { log_error(("unknown function type '%s' for resource %s\n", (const char*)propValue, rtype->_name[0])); } xmlFree(propValue); } xmlXPathFreeObject(result); } /* reading eressea/resources/resource/resourcelimit */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "resourcelimit", xpath); assert(result->nodesetval->nodeNr<=1); if (result->nodesetval->nodeNr!=0) { resource_limit * rdata; attrib * a = a_find(rtype->attribs, &at_resourcelimit); xmlNodePtr limit = result->nodesetval->nodeTab[0]; if (a==NULL) a = a_add(&rtype->attribs, a_new(&at_resourcelimit)); rdata = (resource_limit*)a->data.v; rtype->flags |= RTF_LIMITED; xpath->node = limit; xmlXPathFreeObject(result); result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); if (result->nodesetval!=NULL) { rdata->modifiers = calloc(result->nodesetval->nodeNr+1, sizeof(resource_mod)); for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; building_type * btype = NULL; const race * rc = NULL; propValue = xmlGetProp(node, BAD_CAST "race"); if (propValue!=NULL) { rc = rc_find((const char*)propValue); if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); xmlFree(propValue); } rdata->modifiers[k].race = rc; propValue = xmlGetProp(node, BAD_CAST "building"); if (propValue!=NULL) { btype = bt_get_or_create((const char*)propValue); xmlFree(propValue); } rdata->modifiers[k].btype = btype; propValue = xmlGetProp(node, BAD_CAST "type"); assert(propValue!=NULL); if (strcmp((const char *)propValue, "skill")==0) { rdata->modifiers[k].value.i = xml_ivalue(node, "value", 0); rdata->modifiers[k].flags = RMF_SKILL; } else if (strcmp((const char *)propValue, "material")==0) { rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); rdata->modifiers[k].flags = RMF_SAVEMATERIAL; } else if (strcmp((const char *)propValue, "resource")==0) { rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); rdata->modifiers[k].flags = RMF_SAVERESOURCE; } else if (strcmp((const char *)propValue, "require")==0) { xmlChar * propBldg = xmlGetProp(node, BAD_CAST "building"); if (propBldg!=NULL) { btype = bt_get_or_create((const char*)propBldg); rdata->modifiers[k].btype = btype; rdata->modifiers[k].flags = RMF_REQUIREDBUILDING; xmlFree(propBldg); } } else { log_error(("unknown type '%s' for resourcelimit-modifier '%s'\n", (const char*)propValue, rtype->_name[0])); } xmlFree(propValue); } } xmlXPathFreeObject(result); result = xmlXPathEvalExpression(BAD_CAST "guard", xpath); if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; xmlChar * propFlag = xmlGetProp(node, BAD_CAST "flag"); if (propFlag!=NULL) { if (strcmp((const char *)propFlag, "logging")==0) { rdata->guard |= GUARD_TREES; } else if (strcmp((const char *)propFlag, "mining")==0) { rdata->guard |= GUARD_MINING; } xmlFree(propFlag); } } xmlXPathFreeObject(result); /* reading eressea/resources/resource/resourcelimit/function */ result = xmlXPathEvalExpression(BAD_CAST "function", xpath); if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; pf_generic fun; propValue = xmlGetProp(node, BAD_CAST "value"); assert(propValue!=NULL); fun = get_function((const char*)propValue); if (fun==NULL) { log_error(("unknown limit '%s' for resource %s\n", (const char*)propValue, rtype->_name[0])); xmlFree(propValue); continue; } xmlFree(propValue); propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue!=NULL); if (strcmp((const char*)propValue, "produce")==0) { rdata->produce = (rlimit_produce)fun; } else if (strcmp((const char*)propValue, "limit")==0) { rdata->limit = (rlimit_limit)fun; } else { log_error(("unknown limit '%s' for resource %s\n", (const char*)propValue, rtype->_name[0])); } xmlFree(propValue); } } xmlXPathFreeObject(result); /* reading eressea/resources/resource/resourcelimit/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "resourcelimit/function", xpath); xmlXPathFreeObject(result); /* reading eressea/resources/resource/item */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "item", xpath); assert(result->nodesetval->nodeNr<=1); if (result->nodesetval->nodeNr!=0) { rtype->flags |= RTF_ITEM; xpath->node = result->nodesetval->nodeTab[0]; rtype->itype = xml_readitem(xpath, rtype); } xmlXPathFreeObject(result); } xmlXPathFreeObject(resources); xmlXPathFreeContext(xpath); /* make sure old items (used in requirements) are available */ init_resources(); init_itemtypes(); return 0; } static void add_items(equipment * eq, xmlNodeSetPtr nsetItems) { if (nsetItems!=NULL && nsetItems->nodeNr>0) { int i; for (i=0;i!=nsetItems->nodeNr;++i) { xmlNodePtr node = nsetItems->nodeTab[i]; xmlChar * propValue; const struct item_type * itype; propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue!=NULL); itype = it_find((const char*)propValue); xmlFree(propValue); if (itype!=NULL) { propValue = xmlGetProp(node, BAD_CAST "amount"); if (propValue!=NULL) { equipment_setitem(eq, itype, (const char*)propValue); xmlFree(propValue); } } } } } static void add_callbacks(equipment * eq, xmlNodeSetPtr nsetItems) { if (nsetItems!=NULL && nsetItems->nodeNr>0) { int i; for (i=0;i!=nsetItems->nodeNr;++i) { xmlNodePtr node = nsetItems->nodeTab[i]; xmlChar * propValue; pf_generic fun; propValue = xmlGetProp(node, BAD_CAST "name"); if (propValue!=NULL) { fun = get_function((const char*)propValue); if (fun) { equipment_setcallback(eq, (void (*)(const struct equipment *, struct unit *))fun); } xmlFree(propValue); } } } } static void add_spells(equipment * eq, xmlNodeSetPtr nsetItems) { if (nsetItems!=NULL && nsetItems->nodeNr>0) { int i; for (i=0;i!=nsetItems->nodeNr;++i) { xmlNodePtr node = nsetItems->nodeTab[i]; xmlChar * propValue; magic_t mtype = M_NONE; struct spell * sp; propValue = xmlGetProp(node, BAD_CAST "school"); if (propValue!=NULL) { for (mtype=0;mtype!=MAXMAGIETYP;++mtype) { if (strcmp((const char*)propValue, magic_school[mtype])==0) break; } assert(mtype!=MAXMAGIETYP); xmlFree(propValue); } propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue!=NULL); sp = find_spell(mtype, (const char*)propValue); assert(sp); xmlFree(propValue); if (sp!=NULL) { equipment_addspell(eq, sp); } } } } static void add_skills(equipment * eq, xmlNodeSetPtr nsetSkills) { if (nsetSkills!=NULL && nsetSkills->nodeNr>0) { int i; for (i=0;i!=nsetSkills->nodeNr;++i) { xmlNodePtr node = nsetSkills->nodeTab[i]; xmlChar * propValue; skill_t sk; propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue!=NULL); sk = sk_find((const char*)propValue); xmlFree(propValue); if (sk!=NOSKILL) { propValue = xmlGetProp(node, BAD_CAST "level"); if (propValue!=NULL) { equipment_setskill(eq, sk, (const char*)propValue); xmlFree(propValue); } } } } } static void add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); if (nsetSubsets!=NULL && nsetSubsets->nodeNr>0) { int i; eq->subsets = calloc(nsetSubsets->nodeNr+1, sizeof(subset)); for (i=0;i!=nsetSubsets->nodeNr;++i) { xmlXPathObjectPtr xpathResult; xmlNodePtr node = nsetSubsets->nodeTab[i]; xmlChar * propValue; eq->subsets[i].chance = 1.0f; propValue = xmlGetProp(node, BAD_CAST "chance"); if (propValue!=NULL) { eq->subsets[i].chance = (float)atof((const char *)propValue); xmlFree(propValue); } xpath->node = node; xpathResult = xmlXPathEvalExpression(BAD_CAST "set", xpath); if (xpathResult->nodesetval) { xmlNodeSetPtr nsetSets = xpathResult->nodesetval; float totalChance = 0.0f; if (nsetSets->nodeNr>0) { int set; eq->subsets[i].sets = calloc(nsetSets->nodeNr+1, sizeof(subsetitem)); for (set=0;set!=nsetSets->nodeNr;++set) { xmlNodePtr nodeSet = nsetSets->nodeTab[set]; float chance = 1.0f; propValue = xmlGetProp(nodeSet, BAD_CAST "chance"); if (propValue!=NULL) { chance = (float)atof((const char *)propValue); xmlFree(propValue); } totalChance += chance; propValue = xmlGetProp(nodeSet, BAD_CAST "name"); assert(propValue!=NULL); eq->subsets[i].sets[set].chance = chance; eq->subsets[i].sets[set].set = create_equipment((const char*)propValue); xmlFree(propValue); } } if (totalChance>1.0f) { log_error(("total chance exceeds 1.0: %f in equipment set %s.\n", totalChance, eq->name)); } } xmlXPathFreeObject(xpathResult); } } xmlXPathFreeContext(xpath); } static int parse_equipment(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr xpathRaces; /* reading eressea/equipment/set */ xpathRaces = xmlXPathEvalExpression(BAD_CAST "/eressea/equipment/set", xpath); if (xpathRaces->nodesetval) { xmlNodeSetPtr nsetRaces = xpathRaces->nodesetval; int i; for (i=0;i!=nsetRaces->nodeNr;++i) { xmlNodePtr node = nsetRaces->nodeTab[i]; xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); if (propName!=NULL) { equipment * eq = create_equipment((const char*)propName); xmlXPathObjectPtr xpathResult; xpath->node = node; xpathResult = xmlXPathEvalExpression(BAD_CAST "callback", xpath); assert(!eq->callback); add_callbacks(eq, xpathResult->nodesetval); xmlXPathFreeObject(xpathResult); xpathResult = xmlXPathEvalExpression(BAD_CAST "item", xpath); assert(!eq->items); add_items(eq, xpathResult->nodesetval); xmlXPathFreeObject(xpathResult); xpathResult = xmlXPathEvalExpression(BAD_CAST "spell", xpath); assert(!eq->spells); add_spells(eq, xpathResult->nodesetval); xmlXPathFreeObject(xpathResult); xpathResult = xmlXPathEvalExpression(BAD_CAST "skill", xpath); add_skills(eq, xpathResult->nodesetval); xmlXPathFreeObject(xpathResult); xpathResult = xmlXPathEvalExpression(BAD_CAST "subset", xpath); assert(!eq->subsets); add_subsets(doc, eq, xpathResult->nodesetval); xmlXPathFreeObject(xpathResult); xmlFree(propName); } } } xmlXPathFreeObject(xpathRaces); xmlXPathFreeContext(xpath); return 0; } static int parse_spells(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr spells; /* reading eressea/spells/spell */ spells = xmlXPathEvalExpression(BAD_CAST "/eressea/spells/spell", xpath); if (spells->nodesetval!=NULL) { xmlNodeSetPtr nodes = spells->nodesetval; int i; for (i=0;i!=nodes->nodeNr;++i) { xmlXPathObjectPtr result; xmlNodePtr node = nodes->nodeTab[i]; xmlChar * propValue; int k; spell * sp = calloc(1, sizeof(spell)); static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL }; /* spellname */ propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue!=NULL); sp->sname = strdup((const char*)propValue); xmlFree(propValue); propValue = xmlGetProp(node, BAD_CAST "parameters"); if (propValue) { sp->parameter=strdup((const char *)propValue); xmlFree(propValue); } propValue = xmlGetProp(node, BAD_CAST "syntax"); if (propValue) { sp->syntax=strdup((const char *)propValue); xmlFree(propValue); } /* magic type */ propValue = xmlGetProp(node, BAD_CAST "type"); assert(propValue!=NULL); for (sp->magietyp=0;sp->magietyp!=MAXMAGIETYP;++sp->magietyp) { if (strcmp(magic_school[sp->magietyp], (const char *)propValue)==0) break; } assert(sp->magietyp!=MAXMAGIETYP); xmlFree(propValue); /* level, rank and flags */ sp->id = xml_ivalue(node, "index", 0); sp->level = xml_ivalue(node, "level", -1); sp->rank = (char)xml_ivalue(node, "rank", -1); if (xml_bvalue(node, "los", false)) sp->sptyp |= TESTCANSEE; /* must see or have contact */ if (!xml_bvalue(node, "target_global", false)) sp->sptyp |= SEARCHLOCAL; /* must be in same region */ if (xml_bvalue(node, "ship", false)) sp->sptyp |= ONSHIPCAST; if (xml_bvalue(node, "ocean", false)) sp->sptyp |= OCEANCASTABLE; if (xml_bvalue(node, "far", false)) sp->sptyp |= FARCASTING; if (xml_bvalue(node, "variable", false)) sp->sptyp |= SPELLLEVEL; k = xml_ivalue(node, "combat", 0); if (k>=0 && k<=3) sp->sptyp |= modes[k]; if (gamecode_enabled) { /* reading eressea/spells/spell/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); if (result->nodesetval->nodeNr==0) { /* deprecated style: this spell gets its' function from a callback */ if (set_spelldata_cb) set_spelldata_cb(sp); } else { for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; pf_generic fun; parse_function(node, &fun, &propValue); if (fun==NULL) { log_error(("unknown function name '%s' for spell '%s'\n", (const char*)propValue, sp->sname)); xmlFree(propValue); continue; } assert(propValue!=NULL); if (strcmp((const char*)propValue, "cast")==0) { sp->sp_function = (spell_f)fun; } else if (strcmp((const char*)propValue, "fumble")==0) { sp->patzer = (pspell_f)fun; } else { log_error(("unknown function type '%s' for spell %s\n", (const char*)propValue, sp->sname)); } xmlFree(propValue); } } xmlXPathFreeObject(result); } /* reading eressea/spells/spell/resource */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "resource", xpath); if (result->nodesetval->nodeNr) { sp->components = malloc(sizeof(spell_component)*(result->nodesetval->nodeNr+1)); sp->components[result->nodesetval->nodeNr].type = 0; } for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue); sp->components[k].type = rt_find((const char *)propValue); assert(sp->components[k].type); xmlFree(propValue); sp->components[k].amount = xml_ivalue(node, "amount", 1); sp->components[k].cost = SPC_FIX; propValue = xmlGetProp(node, BAD_CAST "cost"); if (propValue!=NULL) { if (strcmp((const char *)propValue, "linear")==0) { sp->components[k].cost = SPC_LINEAR; } else if (strcmp((const char *)propValue, "level")==0) { sp->components[k].cost = SPC_LEVEL; } xmlFree(propValue); } } xmlXPathFreeObject(result); register_spell(sp); } } xmlXPathFreeObject(spells); xmlXPathFreeContext(xpath); return 0; } static void parse_param(struct param ** params, xmlNodePtr node) { xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); xmlChar * propValue = xmlGetProp(node, BAD_CAST "value"); set_param(params, (const char*)propName, (const char*)propValue); xmlFree(propName); xmlFree(propValue); } static void parse_ai(race * rc, xmlNodePtr node) { rc->splitsize = xml_ivalue(node, "splitsize", 0); rc->aggression = (float)xml_fvalue(node, "aggression", 0.04); if (xml_bvalue(node, "killpeasants", false)) rc->flags |= RCF_KILLPEASANTS; if (xml_bvalue(node, "moverandom", false)) rc->flags |= RCF_MOVERANDOM; if (xml_bvalue(node, "learn", false)) rc->flags |= RCF_LEARN; } static int parse_races(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr races; xmlNodeSetPtr nodes; int i; /* reading eressea/races/race */ races = xmlXPathEvalExpression(BAD_CAST "/eressea/races/race", xpath); nodes = races->nodesetval; for (i=0;i!=nodes->nodeNr;++i) { xmlNodePtr node = nodes->nodeTab[i]; xmlNodePtr child; xmlChar * propValue; race * rc; xmlXPathObjectPtr result; int k, study_speed_base; struct att * attack; propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue!=NULL); rc = rc_find((const char*)propValue); if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); xmlFree(propValue); propValue = xmlGetProp(node, BAD_CAST "damage"); assert(propValue!=NULL); rc->def_damage = strdup((const char*)propValue); xmlFree(propValue); rc->magres = (float)xml_fvalue(node, "magres", 0.0); rc->maxaura = (float)xml_fvalue(node, "maxaura", 0.0); rc->regaura = (float)xml_fvalue(node, "regaura", 1.0); rc->recruitcost = xml_ivalue(node, "recruitcost", 0); rc->maintenance = xml_ivalue(node, "maintenance", 0); rc->weight = xml_ivalue(node, "weight", PERSON_WEIGHT); rc->capacity = xml_ivalue(node, "capacity", 540); rc->speed = (float)xml_fvalue(node, "speed", 1.0F); rc->hitpoints = xml_ivalue(node, "hp", 0); rc->armor = (char)xml_ivalue(node, "ac", 0); study_speed_base = xml_ivalue(node, "studyspeed", 0); rc->at_default = (char)xml_ivalue(node, "unarmedattack", -2); rc->df_default = (char)xml_ivalue(node, "unarmeddefense", -2); rc->at_bonus = (char)xml_ivalue(node, "attackmodifier", 0); rc->df_bonus = (char)xml_ivalue(node, "defensemodifier", 0); if (xml_bvalue(node, "playerrace", false)) rc->flags |= RCF_PLAYERRACE; if (xml_bvalue(node, "scarepeasants", false)) rc->flags |= RCF_SCAREPEASANTS; if (xml_bvalue(node, "cansteal", true)) rc->flags |= RCF_CANSTEAL; if (xml_bvalue(node, "cansail", true)) rc->flags |= RCF_CANSAIL; if (xml_bvalue(node, "cannotmove", false)) rc->flags |= RCF_CANNOTMOVE; if (xml_bvalue(node, "fly", false)) rc->flags |= RCF_FLY; if (xml_bvalue(node, "invisible", false)) rc->flags |= RCF_INVISIBLE; if (xml_bvalue(node, "coastal", false)) rc->flags |= RCF_COASTAL; if (xml_bvalue(node, "unarmedguard", false)) rc->flags |= RCF_UNARMEDGUARD; if (xml_bvalue(node, "swim", false)) rc->flags |= RCF_SWIM; if (xml_bvalue(node, "walk", false)) rc->flags |= RCF_WALK; if (!xml_bvalue(node, "canlearn", true)) rc->flags |= RCF_NOLEARN; if (!xml_bvalue(node, "canteach", true)) rc->flags |= RCF_NOTEACH; if (xml_bvalue(node, "horse", false)) rc->flags |= RCF_HORSE; if (xml_bvalue(node, "desert", false)) rc->flags |= RCF_DESERT; if (xml_bvalue(node, "absorbpeasants", false)) rc->flags |= RCF_ABSORBPEASANTS; if (xml_bvalue(node, "noheal", false)) rc->flags |= RCF_NOHEAL; if (xml_bvalue(node, "noweapons", false)) rc->flags |= RCF_NOWEAPONS; if (xml_bvalue(node, "shapeshift", false)) rc->flags |= RCF_SHAPESHIFT; if (xml_bvalue(node, "shapeshiftany", false)) rc->flags |= RCF_SHAPESHIFTANY; if (xml_bvalue(node, "illusionary", false)) rc->flags |= RCF_ILLUSIONARY; if (xml_bvalue(node, "undead", false)) rc->flags |= RCF_UNDEAD; if (xml_bvalue(node, "dragon", false)) rc->flags |= RCF_DRAGON; if (xml_bvalue(node, "shipspeed", false)) rc->flags |= RCF_SHIPSPEED; if (xml_bvalue(node, "stonegolem", false)) rc->flags |= RCF_STONEGOLEM; if (xml_bvalue(node, "irongolem", false)) rc->flags |= RCF_IRONGOLEM; if (xml_bvalue(node, "giveitem", false)) rc->ec_flags |= GIVEITEM; if (xml_bvalue(node, "giveperson", false)) rc->ec_flags |= GIVEPERSON; if (xml_bvalue(node, "giveunit", false)) rc->ec_flags |= GIVEUNIT; if (xml_bvalue(node, "getitem", false)) rc->ec_flags |= GETITEM; if (xml_bvalue(node, "recruithorses", false)) rc->ec_flags |= ECF_REC_HORSES; if (xml_bvalue(node, "recruitethereal", false)) rc->ec_flags |= ECF_REC_ETHEREAL; if (xml_bvalue(node, "recruitunlimited", false)) rc->ec_flags |= ECF_REC_UNLIMITED; if (xml_bvalue(node, "equipment", false)) rc->battle_flags |= BF_EQUIPMENT; if (xml_bvalue(node, "noblock", false)) rc->battle_flags |= BF_NOBLOCK; if (xml_bvalue(node, "invinciblenonmagic", false)) rc->battle_flags |= BF_INV_NONMAGIC; if (xml_bvalue(node, "resistbash", false)) rc->battle_flags |= BF_RES_BASH; if (xml_bvalue(node, "resistcut", false)) rc->battle_flags |= BF_RES_CUT; if (xml_bvalue(node, "resistpierce", false)) rc->battle_flags |= BF_RES_PIERCE; if (xml_bvalue(node, "canattack", true)) rc->battle_flags |= BF_CANATTACK; for (child=node->children;child;child=child->next) { if (strcmp((const char *)child->name, "ai")==0) { parse_ai(rc, child); } else if (strcmp((const char *)child->name, "param")==0) { parse_param(&rc->parameters, child); } } rc->recruit_multi = get_param_flt(rc->parameters, "recruit_multi", 1.0); /* reading eressea/races/race/skill */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "skill", xpath); memset(rc->bonus, 0, sizeof(rc->bonus)); for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; int mod = xml_ivalue(node, "modifier", 0); int speed = xml_ivalue(node, "speed", study_speed_base); skill_t sk; propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue!=NULL); sk = sk_find((const char*)propValue); if (sk!=NOSKILL) { rc->bonus[sk] = (char)mod; if (speed) { if (!rc->study_speed) rc->study_speed = calloc(1, MAXSKILLS); rc->study_speed[sk] = (char)speed; } } else { log_error(("unknown skill '%s' in race '%s'\n", (const char*)propValue, rc->_name[0])); } xmlFree(propValue); } xmlXPathFreeObject(result); if (gamecode_enabled) { /* reading eressea/races/race/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; pf_generic fun; parse_function(node, &fun, &propValue); if (fun==NULL) { log_error(("unknown function name '%s' for race %s\n", (const char*)propValue, rc->_name[0])); xmlFree(propValue); continue; } assert(propValue!=NULL); if (strcmp((const char*)propValue, "name")==0) { rc->generate_name = (const char * (*)(const struct unit*))fun; } else if (strcmp((const char*)propValue, "describe")==0) { rc->describe = (const char * (*)(const struct unit*, const struct locale *))fun; } else if (strcmp((const char*)propValue, "age")==0) { rc->age = (void(*)(struct unit*))fun; } else if (strcmp((const char*)propValue, "move")==0) { rc->move_allowed = (boolean(*)(const struct region *, const struct region *))fun; } else if (strcmp((const char*)propValue, "itemdrop")==0) { rc->itemdrop = (struct item *(*)(const struct race *, int))fun; } else if (strcmp((const char*)propValue, "initfamiliar")==0) { rc->init_familiar = (void(*)(struct unit *))fun; } else { log_error(("unknown function type '%s' for race %s\n", (const char*)propValue, rc->_name[0])); } xmlFree(propValue); } xmlXPathFreeObject(result); } /* reading eressea/races/race/familiar */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "familiar", xpath); for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; race * frc; propValue = xmlGetProp(node, BAD_CAST "race"); assert(propValue!=NULL); frc = rc_find((const char *)propValue); if (frc == NULL) { // log_error(("%s not registered, is familiar for %s\n", // (const char*)propValue, rc->_name[0])); // assert(frc!=NULL); frc = rc_add(rc_new((const char*)propValue)); } if (xml_bvalue(node, "default", false)) { rc->familiars[k] = rc->familiars[0]; rc->familiars[0] = frc; } else { rc->familiars[k] = frc; } xmlFree(propValue); } xmlXPathFreeObject(result); /* reading eressea/races/race/precombatspell */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "precombatspell", xpath); assert(rc->precombatspell==NULL || !"precombatspell is already initialized"); for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; rc->precombatspell = xml_spell(node, "spell"); } xmlXPathFreeObject(result); /* reading eressea/races/race/attack */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "attack", xpath); attack = rc->attack; for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; while (attack->type!=AT_NONE) ++attack; propValue = xmlGetProp(node, BAD_CAST "damage"); if (propValue!=NULL) { attack->data.dice = strdup((const char*)propValue); xmlFree(propValue); } else { attack->data.sp = xml_spell(node, "spell"); } attack->type = xml_ivalue(node, "type", 0); attack->flags = xml_ivalue(node, "flags", 0); } xmlXPathFreeObject(result); } xmlXPathFreeObject(races); xmlXPathFreeContext(xpath); race_compat(); return 0; } static int parse_terrains(xmlDocPtr doc) { xmlXPathContextPtr xpath; xmlXPathObjectPtr terrains; xmlNodeSetPtr nodes; int i; xpath = xmlXPathNewContext(doc); /* reading eressea/terrains/terrain */ terrains = xmlXPathEvalExpression(BAD_CAST "/eressea/terrains/terrain", xpath); nodes = terrains->nodesetval; for (i=0;i!=nodes->nodeNr;++i) { xmlNodePtr node = nodes->nodeTab[i]; terrain_type * terrain = calloc(1, sizeof(terrain_type)); xmlChar * propValue; xmlXPathObjectPtr xpathChildren; xmlNodeSetPtr children; propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue!=NULL); terrain->_name = strdup((const char *)propValue); xmlFree(propValue); terrain->max_road = (short)xml_ivalue(node, "road", 0); assert(terrain->max_road>=0); terrain->size = xml_ivalue(node, "size", 0); if (xml_bvalue(node, "forbidden", false)) terrain->flags |= FORBIDDEN_REGION; else { if (xml_bvalue(node, "fly", true)) terrain->flags |= FLY_INTO; if (xml_bvalue(node, "sail", true)) terrain->flags |= SAIL_INTO; if (xml_bvalue(node, "walk", true)) terrain->flags |= WALK_INTO; if (xml_bvalue(node, "swim", false)) terrain->flags |= SWIM_INTO; if (xml_bvalue(node, "shallow", true)) terrain->flags |= LARGE_SHIPS; if (xml_bvalue(node, "cavalry", false)) terrain->flags |= CAVALRY_REGION; } if (xml_bvalue(node, "sea", false)) terrain->flags |= SEA_REGION; if (xml_bvalue(node, "arctic", false)) terrain->flags |= ARCTIC_REGION; if (xml_bvalue(node, "land", true)) terrain->flags |= LAND_REGION; if (xml_bvalue(node, "forest", false)) terrain->flags |= FOREST_REGION; terrain->distribution = (short)xml_ivalue(node, "seed", 0); xpath->node = node; xpathChildren = xmlXPathEvalExpression(BAD_CAST "herb", xpath); children = xpathChildren->nodesetval; if (children->nodeNr>0) { int k; terrain->herbs = malloc((children->nodeNr+1) * sizeof(item_type*)); terrain->herbs[children->nodeNr] = NULL; for (k=0;k!=children->nodeNr;++k) { xmlNodePtr nodeHerb = children->nodeTab[k]; const struct resource_type * rtype; propValue = xmlGetProp(nodeHerb, BAD_CAST "name"); assert(propValue!=NULL); rtype = rt_find((const char*)propValue); assert(rtype!=NULL && rtype->itype!=NULL && fval(rtype->itype, ITF_HERB)); terrain->herbs[k] = rtype->itype; xmlFree(propValue); } } xmlXPathFreeObject(xpathChildren); xpath->node = node; xpathChildren = xmlXPathEvalExpression(BAD_CAST "resource", xpath); children = xpathChildren->nodesetval; if (children->nodeNr>0) { int k; terrain->production = malloc((children->nodeNr+1) * sizeof(terrain_production)); terrain->production[children->nodeNr].type = NULL; for (k=0;k!=children->nodeNr;++k) { xmlNodePtr nodeProd = children->nodeTab[k]; propValue = xmlGetProp(nodeProd, BAD_CAST "name"); assert(propValue!=NULL); terrain->production[k].type = rt_find((const char*)propValue); assert(terrain->production[k].type); xmlFree(propValue); propValue = xmlGetProp(nodeProd, BAD_CAST "level"); assert(propValue); terrain->production[k].startlevel = strdup((const char *)propValue); xmlFree(propValue); propValue = xmlGetProp(nodeProd, BAD_CAST "base"); assert(propValue); terrain->production[k].base = strdup((const char *)propValue); xmlFree(propValue); propValue = xmlGetProp(nodeProd, BAD_CAST "div"); assert(propValue); terrain->production[k].divisor = strdup((const char *)propValue); xmlFree(propValue); terrain->production[k].chance = (float)xml_fvalue(nodeProd, "chance", 1.0); } } xmlXPathFreeObject(xpathChildren); register_terrain(terrain); } xmlXPathFreeObject(terrains); xmlXPathFreeContext(xpath); init_terrains(); return 0; } static int parse_messages(xmlDocPtr doc) { xmlXPathContextPtr xpath; xmlXPathObjectPtr messages; xmlNodeSetPtr nodes; int i; if (!gamecode_enabled) return 0; xpath = xmlXPathNewContext(doc); /* reading eressea/messages/message */ messages = xmlXPathEvalExpression(BAD_CAST "/eressea/messages/message", xpath); nodes = messages->nodesetval; for (i=0;i!=nodes->nodeNr;++i) { xmlNodePtr node = nodes->nodeTab[i]; const char * default_section = "events"; xmlChar * propSection; xmlChar * propValue; xmlXPathObjectPtr result; int k; char ** argv = NULL; const message_type * mtype; /* arguments */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "type/arg", xpath); if (result->nodesetval && result->nodesetval->nodeNr>0) { argv = malloc(sizeof(char*)*(result->nodesetval->nodeNr+1)); for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; char zBuffer[128]; xmlChar * propName, * propType; propName = xmlGetProp(node, BAD_CAST "name"); propType = xmlGetProp(node, BAD_CAST "type"); sprintf(zBuffer, "%s:%s", (const char*)propName, (const char*)propType); xmlFree(propName); xmlFree(propType); argv[k] = strdup(zBuffer); } argv[result->nodesetval->nodeNr] = NULL; } xmlXPathFreeObject(result); /* add the messagetype */ propValue = xmlGetProp(node, BAD_CAST "name"); mtype = mt_find((const char *)propValue); if (mtype==NULL) { mtype = mt_register(mt_new((const char *)propValue, (const char**)argv)); } else { assert(argv!=NULL || !"cannot redefine arguments of message now"); } xmlFree(propValue); /* register the type for the CR */ crt_register(mtype); /* let's clean up the mess */ if (argv!=NULL) { for (k=0;argv[k]!=NULL;++k) free(argv[k]); free(argv); } propSection = xmlGetProp(node, BAD_CAST "section"); if (propSection==NULL) propSection = BAD_CAST default_section; /* strings */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "text", xpath); for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; struct locale * lang; xmlChar * propText; xml_readtext(node, &lang, &propText); if (lang) { xml_cleanup_string(propText); nrt_register(mtype, lang, (const char *)propText, 0, (const char*)propSection); } xmlFree(propText); } xmlXPathFreeObject(result); if (propSection != BAD_CAST default_section) xmlFree(propSection); } xmlXPathFreeObject(messages); xmlXPathFreeContext(xpath); return 0; } static void xml_readstrings(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, boolean names) { int i; for (i=0;i!=nodeNr;++i) { xmlNodePtr stringNode = nodeTab[i]; xmlChar * propName = xmlGetProp(stringNode, BAD_CAST "name"); xmlChar * propNamespace = NULL; xmlXPathObjectPtr result; int k; char zName[128]; assert(propName!=NULL); if (names) propNamespace = xmlGetProp(stringNode->parent, BAD_CAST "name"); mkname_buf((const char*)propNamespace, (const char*)propName, zName); if (propNamespace!=NULL) xmlFree(propNamespace); xmlFree(propName); /* strings */ xpath->node = stringNode; result = xmlXPathEvalExpression(BAD_CAST "text", xpath); for (k=0;k!=result->nodesetval->nodeNr;++k) { xmlNodePtr textNode = result->nodesetval->nodeTab[k]; struct locale * lang; xmlChar * propText; xml_readtext(textNode, &lang, &propText); if (propText!=NULL) { assert(strcmp(zName, (const char*)xml_cleanup_string(BAD_CAST zName))==0); if (lang) { xml_cleanup_string(propText); locale_setstring(lang, zName, (const char *)propText); } xmlFree(propText); } else { log_warning(("string %s has no text in locale %s\n", zName, locale_name(lang))); } } xmlXPathFreeObject(result); } } static int parse_strings(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr strings; /* reading eressea/strings/string */ strings = xmlXPathEvalExpression(BAD_CAST "/eressea/strings/string", xpath); xml_readstrings(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, false); xmlXPathFreeObject(strings); strings = xmlXPathEvalExpression(BAD_CAST "/eressea/strings/namespace/string", xpath); xml_readstrings(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, true); xmlXPathFreeObject(strings); xmlXPathFreeContext(xpath); return 0; } static void xml_readprefixes(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, boolean names) { int i; for (i=0;i!=nodeNr;++i) { xmlNodePtr node = nodeTab[i]; xmlChar * propText = xmlNodeListGetString(node->doc, node->children, 1); if (propText!=NULL) { add_raceprefix((const char*)propText); xmlFree(propText); } } } static int parse_prefixes(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr strings; /* reading eressea/strings/string */ strings = xmlXPathEvalExpression(BAD_CAST "/eressea/prefixes/prefix", xpath); xml_readprefixes(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, false); xmlXPathFreeObject(strings); xmlXPathFreeContext(xpath); return 0; } static int parse_main(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/game", xpath); xmlNodeSetPtr nodes = result->nodesetval; int i; xmlChar * propValue; if (nodes->nodeNr>0) { xmlNodePtr node = nodes->nodeTab[0]; global.producexpchance = (float)xml_fvalue(node, "learningbydoing", 1.0/3); propValue = xmlGetProp(node, BAD_CAST "name"); if (propValue!=NULL) { global.gamename = strdup((const char*)propValue); xmlFree(propValue); } xmlXPathFreeObject(result); /* reading eressea/game/param */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "param", xpath); nodes = result->nodesetval; for (i=0;i!=nodes->nodeNr;++i) { xmlNodePtr node = nodes->nodeTab[i]; parse_param(&global.parameters, node); } xmlXPathFreeObject(result); /* reading eressea/game/order */ result = xmlXPathEvalExpression(BAD_CAST "order", xpath); nodes = result->nodesetval; for (i=0;i!=nodes->nodeNr;++i) { xmlNodePtr node = nodes->nodeTab[i]; xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); boolean disable = xml_bvalue(node, "disable", false); if (disable) { int k; for (k=0;k!=MAXKEYWORDS;++k) { if (strcmp(keywords[k], (const char*)propName)==0) { global.disabled[k]=1; break; } } if (k==MAXKEYWORDS) { log_error(("trying to disable unknown comand %s\n", (const char*)propName)); } } xmlFree(propName); } xmlXPathFreeObject(result); /* reading eressea/game/skill */ result = xmlXPathEvalExpression(BAD_CAST "skill", xpath); nodes = result->nodesetval; for (i=0;i!=nodes->nodeNr;++i) { xmlNodePtr node = nodes->nodeTab[i]; xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); boolean enable = xml_bvalue(node, "enable", true); enable_skill((const char*)propName, enable); xmlFree(propName); } } xmlXPathFreeObject(result); xmlXPathFreeContext(xpath); return 0; } void register_xmlreader(void) { xml_register_callback(parse_main); xml_register_callback(parse_strings); xml_register_callback(parse_prefixes); xml_register_callback(parse_messages); xml_register_callback(parse_resources); xml_register_callback(parse_rules); xml_register_callback(parse_terrains); /* requires resources */ xml_register_callback(parse_buildings); /* requires resources */ xml_register_callback(parse_ships); /* requires terrains */ xml_register_callback(parse_spells); /* requires resources */ xml_register_callback(parse_equipment); /* requires spells */ xml_register_callback(parse_races); /* requires spells */ xml_register_callback(parse_calendar); xml_register_callback(parse_directions); }