/* 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 #include /* libxml includes */ #include #include #include /* libc includes */ #include #include #include #include static boolean gamecode_enabled = false; 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((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 = (construction *)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 = (struct 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((const char *)propValue); if (!sp) { log_error(("no spell '%s' in school '%s' for equipment-set '%s'\n", (const char *)propValue, magic_school[mtype], eq->name)); } else { equipment_addspell(eq, sp); } xmlFree(propValue); } } } 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); if (sk == NOSKILL) { log_error(("unknown skill '%s' in equipment-set %s\n", (const char *)propValue, eq->name)); xmlFree(propValue); } else { xmlFree(propValue); 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; char zText[32]; strcpy(zText, "fumble_"); /* 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_component *component; spell *sp; int valid = 1; static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL }; /* spellname */ propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue != NULL); sp = create_spell((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 */ pf_generic cast = 0; pf_generic fumble = 0; xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); if (result->nodesetval->nodeNr == 0) { cast = get_function(sp->sname); if (!cast) { log_error(("no spell cast function registered for '%s'\n", sp->sname)); valid = 0; } strlcpy(zText+7, sp->sname, sizeof(zText)-7); fumble = get_function(zText); } else { for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; pf_generic fun; parse_function(node, &fun, &propValue); assert(propValue != NULL); if (strcmp((const char *)propValue, "cast") == 0) { if (fun) { cast = fun; valid = 1; } else { log_error(("unknown function name '%s' for spell '%s'\n", (const char *)propValue, sp->sname)); valid = 0; } } else if (fun && strcmp((const char *)propValue, "fumble") == 0) { fumble = fun; } else { log_error(("unknown function type '%s' for spell '%s'\n", (const char *)propValue, sp->sname)); } xmlFree(propValue); } } sp->cast = (spell_f)cast; sp->patzer = (fumble_f)fumble; xmlXPathFreeObject(result); } if (valid) { /* reading eressea/spells/spell/resource */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "resource", xpath); if (result->nodesetval->nodeNr) { sp->components = (spell_component *) malloc(sizeof(spell_component) * (result->nodesetval->nodeNr + 1)); sp->components[result->nodesetval->nodeNr].type = 0; } for (component = sp->components, k = 0; k != result->nodesetval->nodeNr; ++k) { const resource_type *rtype; xmlNodePtr node = result->nodesetval->nodeTab[k]; propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue); rtype = rt_find((const char *)propValue); if (!rtype) { log_error(("spell %s uses unknown component %s.\n", sp->sname, (const char *)propValue)); xmlFree(propValue); continue; } component->type = rtype; xmlFree(propValue); component->amount = xml_ivalue(node, "amount", 1); component->cost = SPC_FIX; propValue = xmlGetProp(node, BAD_CAST "cost"); if (propValue != NULL) { if (strcmp((const char *)propValue, "linear") == 0) { component->cost = SPC_LINEAR; } else if (strcmp((const char *)propValue, "level") == 0) { component->cost = SPC_LEVEL; } xmlFree(propValue); } component++; } xmlXPathFreeObject(result); } if (valid) { 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) { 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); }