server/src/kernel/xmlreader.c

2181 lines
72 KiB
C
Raw Normal View History

2010-08-08 10:06:34 +02:00
/* vi: set ts=2:
+-------------------+
| | Enno Rehling <enno@eressea.de>
| Eressea PBEM host | Christian Schlittchen <corwin@amber.kn-bremen.de>
| (c) 1998 - 2004 | Katja Zedel <katze@felidae.kn-bremen.de>
| | Henning Peters <faroul@beyond.kn-bremen.de>
+-------------------+
This program may not be used, modified or distributed
without prior permission by the authors of Eressea.
*/
#include <platform.h>
#include <kernel/config.h>
#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 <util/attrib.h>
#include <util/crmessage.h>
#include <util/functions.h>
#include <util/language.h>
#include <util/log.h>
#include <util/message.h>
#include <util/nrmessage.h>
#include <util/xml.h>
/* libxml includes */
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/encoding.h>
/* libc includes */
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <string.h>
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);
}