From b27da8c0564fcc2f317f17193fea3ca5edcf2536 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 28 May 2007 16:03:48 +0000 Subject: [PATCH] Archetypes (WIP): "RECRUIT 15 knight" creates XML-configurable pre-skilled units for game variants with faster reinforcements. Speeding up locale-string lookup a little bit, and making it more unified for different classes of strings (so new ones are easily added). --- src/common/gamecode/archetype.c | 124 ++++++++++++++++++++++++++ src/common/gamecode/archetype.h | 40 +++++++++ src/common/gamecode/economy.c | 132 +++++++++++++++++++--------- src/common/gamecode/gamecode.vcproj | 6 ++ src/common/kernel/build.c | 86 ++++++++++-------- src/common/kernel/build.h | 2 +- src/common/kernel/eressea.c | 107 +++++++++------------- src/common/kernel/kernel.vcproj | 3 + src/common/kernel/xmlkernel.h | 28 ++++++ src/common/kernel/xmlreader.c | 28 +++--- src/common/kernel/xmlreader.h | 2 +- src/common/util/language.c | 24 +++++ src/common/util/language.h | 13 +++ src/common/util/language_struct.h | 2 + src/eressea/server.cpp | 3 + src/res/rts.xml | 115 ++++++++++++++++++++++++ src/res/rts/buildings.xml | 38 ++++++++ src/res/rts/equipment.xml | 27 ++++++ src/res/rts/units.xml | 30 +++++++ src/rts.txt | 24 +++++ src/scripts/rts-run.lua | 99 +++++++++++++++++++++ 21 files changed, 773 insertions(+), 160 deletions(-) create mode 100644 src/common/gamecode/archetype.c create mode 100644 src/common/gamecode/archetype.h create mode 100644 src/common/kernel/xmlkernel.h create mode 100644 src/res/rts.xml create mode 100644 src/res/rts/buildings.xml create mode 100644 src/res/rts/equipment.xml create mode 100644 src/res/rts/units.xml create mode 100644 src/rts.txt create mode 100644 src/scripts/rts-run.lua diff --git a/src/common/gamecode/archetype.c b/src/common/gamecode/archetype.c new file mode 100644 index 000000000..7b0a97450 --- /dev/null +++ b/src/common/gamecode/archetype.c @@ -0,0 +1,124 @@ +#include +#include "eressea.h" +#include "archetype.h" + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include + +/* libxml includes */ +#include +#include +#include + +/* libc includes */ +#include +#include + +static struct archetype * archetypes; + +const struct archetype * +find_archetype(const char * s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_ARCHETYPES); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (const struct archetype *)token.v; + } + return NULL; +} + +void +register_archetype(archetype * arch) +{ + arch->next = archetypes; + archetypes = arch; +} + +const archetype * +get_archetype(const char * name) +{ + const archetype * arch = archetypes; + for (;arch;arch=arch->next) { + if (strcmp(name, arch->name)==0) { + return arch; + } + } + return NULL; +} + +void +init_archetypes(void) +{ + const struct locale * lang = locales; + for (;lang;lang=nextlocale(lang)) { + variant var; + archetype * arch = archetypes; + struct tnode * tokens = get_translations(lang, UT_ARCHETYPES); + for (;arch;arch=arch->next) { + var.v = arch; + addtoken(tokens, LOC(lang, arch->name), var); + } + } +} + +static int +parse_archetypes(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/archetypes/archetype", xpath); + xmlNodeSetPtr nodes = result->nodesetval; + + xmlChar * property; + if (nodes && nodes->nodeNr>0) { + xmlNodePtr node = nodes->nodeTab[0]; + archetype * arch = calloc(1, sizeof(archetype)); + xmlXPathObjectPtr sub; + + property = xmlGetProp(node, BAD_CAST "name"); + assert(property!=NULL); + arch->name = strdup((const char *)property); + xmlFree(property); + + property = xmlGetProp(node, BAD_CAST "equip"); + if (property!=NULL) { + arch->equip = get_equipment((const char*)property); + xmlFree(property); + } else { + arch->equip = get_equipment(arch->name); + } + + property = xmlGetProp(node, BAD_CAST "building"); + if (property!=NULL) { + arch->btype = bt_find((const char*)property); + xmlFree(property); + } + + arch->size = xml_ivalue(node, "cost", 1); + + xpath->node = node; + sub = xmlXPathEvalExpression(BAD_CAST "construction", xpath); + if (sub->nodesetval) { + xml_readconstruction(xpath, sub->nodesetval, &arch->ctype); + } + xmlXPathFreeObject(sub); + } + xmlXPathFreeObject(result); + + xmlXPathFreeContext(xpath); + return 0; +} + +void +register_archetypes(void) +{ + xml_register_callback(parse_archetypes); +} \ No newline at end of file diff --git a/src/common/gamecode/archetype.h b/src/common/gamecode/archetype.h new file mode 100644 index 000000000..a966a7b15 --- /dev/null +++ b/src/common/gamecode/archetype.h @@ -0,0 +1,40 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2007 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_GC_ARCHETYPE +#define H_GC_ARCHETYPE + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct archetype { + char * name; + int size; + struct building_type * btype; + struct equipment * equip; + struct construction * ctype; + struct archetype * next; + } archetype; + + extern const struct archetype * find_archetype(const char * s, const struct locale * lang); + extern void init_archetypes(void); + extern const struct archetype * get_archetype(const char * name); + extern void register_archetype(struct archetype * arch); + extern void register_archetypes(void); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/gamecode/economy.c b/src/common/gamecode/economy.c index 6147bd819..48bf66075 100644 --- a/src/common/gamecode/economy.c +++ b/src/common/gamecode/economy.c @@ -26,11 +26,13 @@ /* gamecode includes */ #include "laws.h" #include "randenc.h" +#include "archetype.h" /* kernel includes */ #include #include #include +#include #include #include #include @@ -1053,6 +1055,80 @@ maintain_buildings(region * r, boolean crash) } } +static int +recruit_archetype(unit * u, order * ord) +{ + int n, id; + const char * s; + + init_tokens(ord); + skip_token(); + n = geti(); + s = getstrtoken(); + id = getid(); + if (n>0 && s && s[0]) { + const archetype * arch = find_archetype(s, u->faction->locale); + + if (u->number>0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_must_be_new", "")); + /* TODO: error message */ + return 0; + } + + if (arch==NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unknown_archetype", "name", s)); + /* TODO: error message */ + return 0; + } + if (arch->btype && u->building->type!=arch->btype) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_must_be_in_building", "type", arch->btype)); + /* TODO: error message */ + return 0; + } + + n = build(u, arch->ctype, 0, n); + if (n>0) { + scale_number(u, n); + equip_unit(u, arch->equip); + return n; + } else switch(n) { + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, arch->ctype)); + return 0; + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, ord, 50, MSG_PRODUCE); + return 0; + default: + assert(!"unhandled return value from build() in recruit_archetype"); + } + return 0; + } + return -1; +} + +static int +recruit_classic(void) +{ + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "recruit.classic"); + value = str?atoi(str):1; + } + return value; +} + +static int +recruit_archetypes(void) +{ + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "recruit.archetypes"); + value = str?atoi(str):0; + } + return value; +} void economics(region *r) @@ -1095,9 +1171,19 @@ economics(region *r) for (u = r->units; u; u = u->next) { order * ord; + if (!recruit_classic()) { + if (u->number>0) continue; + } for (ord = u->orders; ord; ord = ord->next) { if (get_keyword(ord) == K_RECRUIT) { - recruit(u, ord, &recruitorders); + if (recruit_archetypes()) { + if (recruit_archetype(u, ord)>=0) { + continue; + } + } + if (recruit_classic()) { + recruit(u, ord, &recruitorders); + } break; } } @@ -1142,26 +1228,8 @@ manufacture(unit * u, const item_type * itype, int want) sk, minskill, itype->rtype, 1)); return; case ENOMATERIALS: - /* something missing from the list of materials */ - strcpy(buf, "Dafür braucht man mindestens:"); - { - int c, n; - const construction * cons = itype->construction; - char * ch = buf+strlen(buf); - assert(cons); - for (c=0;cons->materials[c].number; c++) { - requirement * m = cons->materials+c; - if (c!=0) - strcat(ch++, ","); - n = m->number / cons->reqsize; - sprintf(ch, " %d %s", n?n:1, - locale_string(u->faction->locale, - resourcename(m->rtype, m->number!=1))); - ch = ch+strlen(ch); - } - mistake(u, u->thisorder, buf, MSG_PRODUCE); - return; - } + ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, itype->construction)); + return; } if (n>0) { i_change(&u->items, itype, n); @@ -1571,26 +1639,8 @@ create_potion(unit * u, const potion_type * ptype, int want) break; case ENOMATERIALS: /* something missing from the list of materials */ - strcpy(buf, "Dafür braucht man mindestens:"); - { - int c, n; - const construction * cons = ptype->itype->construction; - char * ch = buf+strlen(buf); - assert(cons); - for (c=0;cons->materials[c].number; c++) { - const requirement * m = cons->materials+c; - if (c!=0) - strcat(ch++, ","); - n = m->number / cons->reqsize; - sprintf(ch, " %d %s", n?n:1, - LOC(u->faction->locale, - resourcename(m->rtype, m->number!=1))); - ch = ch+strlen(ch); - } - strcat(ch,"."); - mistake(u, u->thisorder, buf, MSG_PRODUCE); - return; - } + ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, ptype->itype->construction)); + return; break; default: i_change(&u->items, ptype->itype, built); diff --git a/src/common/gamecode/gamecode.vcproj b/src/common/gamecode/gamecode.vcproj index 8fc509a57..da2682184 100644 --- a/src/common/gamecode/gamecode.vcproj +++ b/src/common/gamecode/gamecode.vcproj @@ -277,6 +277,9 @@ + + @@ -308,6 +311,9 @@ RelativePath=".\xmlreport.h"> + + diff --git a/src/common/kernel/build.c b/src/common/kernel/build.c index 6d9c0635f..b09d63a38 100644 --- a/src/common/kernel/build.c +++ b/src/common/kernel/build.c @@ -608,41 +608,45 @@ int build(unit * u, const construction * ctype, int completed, int want) { const construction * type = ctype; - int skills; /* number of skill points remainig */ - int dm = get_effect(u, oldpotiontype[P_DOMORE]); + int skills = INT_MAX; /* number of skill points remainig */ + int basesk = 0; int made = 0; - int basesk, effsk; - assert(u->number); if (want<=0) return 0; if (type==NULL) return 0; if (type->improvement==NULL && completed==type->maxsize) return ECOMPLETE; - basesk = effskill(u, type->skill); - if (basesk==0) return ENEEDSKILL; + if (type->skill!=NOSKILL) { + int effsk; + int dm = get_effect(u, oldpotiontype[P_DOMORE]); - effsk = basesk; - if (inside_building(u)) { - effsk = skillmod(u->building->type->attribs, u, u->region, type->skill, + assert(u->number); + basesk = effskill(u, type->skill); + if (basesk==0) return ENEEDSKILL; + + effsk = basesk; + if (inside_building(u)) { + effsk = skillmod(u->building->type->attribs, u, u->region, type->skill, + effsk, SMF_PRODUCTION); + } + effsk = skillmod(type->attribs, u, u->region, type->skill, effsk, SMF_PRODUCTION); - } - effsk = skillmod(type->attribs, u, u->region, type->skill, - effsk, SMF_PRODUCTION); - if (effsk<0) return effsk; /* pass errors to caller */ - if (effsk==0) return ENEEDSKILL; + if (effsk<0) return effsk; /* pass errors to caller */ + if (effsk==0) return ENEEDSKILL; - skills = effsk * u->number; + skills = effsk * u->number; - /* technically, nimblefinge and domore should be in a global set of - * "game"-attributes, (as at_skillmod) but for a while, we're leaving - * them in here. */ + /* technically, nimblefinge and domore should be in a global set of + * "game"-attributes, (as at_skillmod) but for a while, we're leaving + * them in here. */ - if (dm != 0) { - /* Auswirkung Schaffenstrunk */ - dm = min(dm, u->number); - change_effect(u, oldpotiontype[P_DOMORE], -dm); - skills += dm * effsk; + if (dm != 0) { + /* Auswirkung Schaffenstrunk */ + dm = min(dm, u->number); + change_effect(u, oldpotiontype[P_DOMORE], -dm); + skills += dm * effsk; + } } for (;want>0 && skills>0;) { int c, n; @@ -764,6 +768,23 @@ build(unit * u, const construction * ctype, int completed, int want) return made; } +message * +msg_materials_required(unit * u, order * ord, const construction * ctype) +{ + /* something missing from the list of materials */ + int c; + resource * reslist = NULL; + + for (c=0;ctype->materials[c].number; ++c) { + resource * res = malloc(sizeof(resource)); + res->number = ctype->materials[c].number / ctype->reqsize; + res->type = ctype->materials[c].rtype; + res->next = reslist; + reslist = res; + } + return msg_feedback(u, ord, "build_required", "required", reslist); +} + int maxbuild(const unit * u, const construction * cons) /* calculate maximum size that can be built from available material */ @@ -791,7 +812,7 @@ build_building(unit * u, const building_type * btype, int want, order * ord) { region * r = u->region; boolean newbuilding = false; - int c, built = 0, id; + int built = 0, id; building * b = NULL; /* einmalige Korrektur */ static char buffer[8 + IDSIZE + 1 + NAMESIZE + 1]; @@ -874,22 +895,9 @@ build_building(unit * u, const building_type * btype, int want, order * ord) /* the building is already complete */ cmistake(u, ord, 4, MSG_PRODUCE); return; - case ENOMATERIALS: { - /* something missing from the list of materials */ - const construction * cons = btype->construction; - resource * reslist = NULL; - assert(cons); - for (c=0;cons->materials[c].number; ++c) { - resource * res = malloc(sizeof(resource)); - res->number = cons->materials[c].number / cons->reqsize; - res->type = cons->materials[c].rtype; - res->next = reslist; - reslist = res; - } - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "build_required", - "required", reslist)); + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, btype->construction)); return; - } case ELOWSKILL: case ENEEDSKILL: /* no skill, or not enough skill points to build */ diff --git a/src/common/kernel/build.h b/src/common/kernel/build.h index 04fb20842..cf786296c 100644 --- a/src/common/kernel/build.h +++ b/src/common/kernel/build.h @@ -79,7 +79,7 @@ void sunhash(struct ship * sh); extern int build(struct unit * u, const construction * ctype, int completed, int want); extern int maxbuild(const struct unit *u, const construction *cons); - +extern struct message * msg_materials_required(struct unit * u, struct order * ord, const struct construction * ctype); /** error messages that build may return: */ #define ELOWSKILL -1 #define ENEEDSKILL -2 diff --git a/src/common/kernel/eressea.c b/src/common/kernel/eressea.c index 5171787da..27df9c55b 100644 --- a/src/common/kernel/eressea.c +++ b/src/common/kernel/eressea.c @@ -1489,53 +1489,13 @@ findstr(const char **v, const char *s, unsigned char n) return -1; } -enum { - UT_NONE, - UT_PARAM, - UT_ITEM, - UT_BUILDING, - UT_HERB, - UT_POTION, - UT_MAX -}; - -static struct lstr { - const struct locale * lang; - struct tnode tokens[UT_MAX]; - struct tnode skillnames; - struct tnode keywords; - struct tnode races; - struct tnode directions; - struct tnode options; - struct lstr * next; -} * lstrs; - -static struct lstr * -get_lnames(const struct locale * lang) -{ - static struct lstr * lnames = NULL; - static const struct locale * lastlang = NULL; - - if (lastlang!=lang || lnames==NULL) { - lnames = lstrs; - while (lnames && lnames->lang!=lang) lnames = lnames->next; - if (lnames==NULL) { - lnames = calloc(sizeof(struct lstr), 1); - lnames->lang = lang; - lnames->next = lstrs; - lstrs = lnames; - } - } - return lnames; -} - const struct race * findrace(const char * s, const struct locale * lang) { - struct lstr * lnames = get_lnames(lang); + struct tnode * tokens = get_translations(lang, UT_RACES); variant token; - if (findtoken(&lnames->races, s, &token)==E_TOK_SUCCESS) { + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { return (const struct race *)token.v; } return NULL; @@ -1544,10 +1504,10 @@ findrace(const char * s, const struct locale * lang) int findoption(const char *s, const struct locale * lang) { - struct lstr * lnames = get_lnames(lang); + struct tnode * tokens = get_translations(lang, UT_OPTIONS); variant token; - if (findtoken(&lnames->options, s, &token)==E_TOK_SUCCESS) { + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { return (direction_t)token.i; } return NODIRECTION; @@ -1556,22 +1516,23 @@ findoption(const char *s, const struct locale * lang) skill_t findskill(const char *s, const struct locale * lang) { - struct lstr * lnames = get_lnames(lang); + struct tnode * tokens = get_translations(lang, UT_SKILLS); variant token; - if (findtoken(&lnames->skillnames, s, &token)==E_TOK_NOMATCH) return NOSKILL; + if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) return NOSKILL; return (skill_t)token.i; } keyword_t findkeyword(const char *s, const struct locale * lang) { - struct lstr * lnames = get_lnames(lang); + struct tnode * tokens = get_translations(lang, UT_KEYWORDS); variant token; + #ifdef AT_PERSISTENT if (*s == '@') s++; #endif - if (findtoken(&lnames->keywords, s, &token)==E_TOK_NOMATCH) return NOKEYWORD; + if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) return NOKEYWORD; if (global.disabled[token.i]) return NOKEYWORD; return (keyword_t) token.i; } @@ -1579,12 +1540,11 @@ findkeyword(const char *s, const struct locale * lang) param_t findparam(const char *s, const struct locale * lang) { - struct lstr * lnames = get_lnames(lang); - const building_type * btype; + struct tnode * tokens = get_translations(lang, UT_PARAMS); variant token; - if (findtoken(&lnames->tokens[UT_PARAM], s, &token)==E_TOK_NOMATCH) { - btype = findbuildingtype(s, lang); + if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) { + const building_type * btype = findbuildingtype(s, lang); if (btype!=NULL) return (param_t) P_GEBAEUDE; return NOPARAM; } @@ -1943,6 +1903,11 @@ createunit(region * r, faction * f, int number, const struct race * rc) return create_unit(r, f, number, rc, 0, NULL, NULL); } +/** creates a new unit. + * + * @param dname: name, set to NULL to get a default. + * @param creator: unit to inherit stealth, group, building, ship, etc. from + */ unit * create_unit(region * r, faction * f, int number, const struct race *urace, int id, const char * dname, unit *creator) { @@ -2026,7 +1991,7 @@ create_unit(region * r, faction * f, int number, const struct race *urace, int i a->data.v = creator; } /* Monster sind grundsätzlich parteigetarnt */ - if(f->no <= 0) fset(u, UFL_PARTEITARNUNG); + if (f->no <= 0) fset(u, UFL_PARTEITARNUNG); return u; } @@ -2299,21 +2264,22 @@ init_directions(tnode * root, const struct locale * lang) { NULL, NODIRECTION} }; int i; - struct lstr * lnames = get_lnames(lang); + struct tnode * tokens = get_translations(lang, UT_DIRECTIONS); + for (i=0; dirs[i].direction!=NODIRECTION;++i) { variant token; token.i = dirs[i].direction; - addtoken(&lnames->directions, LOC(lang, dirs[i].name), token); + addtoken(tokens, LOC(lang, dirs[i].name), token); } } direction_t finddirection(const char *s, const struct locale * lang) { - struct lstr * lnames = get_lnames(lang); + struct tnode * tokens = get_translations(lang, UT_DIRECTIONS); variant token; - if (findtoken(&lnames->directions, s, &token)==E_TOK_SUCCESS) { + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { return (direction_t)token.i; } return NODIRECTION; @@ -2322,37 +2288,48 @@ finddirection(const char *s, const struct locale * lang) static void init_locale(const struct locale * lang) { - struct lstr * lnames = get_lnames(lang); variant var; int i; const struct race * rc; + struct tnode * tokens; - init_directions(&lnames->directions, lang); + tokens = get_translations(lang, UT_DIRECTIONS); + init_directions(tokens, lang); + + tokens = get_translations(lang, UT_RACES); for (rc=races;rc;rc=rc->next) { var.v = (void*)rc; - addtoken(&lnames->races, LOC(lang, rc_name(rc, 1)), var); - addtoken(&lnames->races, LOC(lang, rc_name(rc, 0)), var); + addtoken(tokens, LOC(lang, rc_name(rc, 1)), var); + addtoken(tokens, LOC(lang, rc_name(rc, 0)), var); } + + tokens = get_translations(lang, UT_PARAMS); for (i=0;i!=MAXPARAMS;++i) { var.i = i; - addtoken(&lnames->tokens[UT_PARAM], LOC(lang, parameters[i]), var); + addtoken(tokens, LOC(lang, parameters[i]), var); } + + tokens = get_translations(lang, UT_SKILLS); for (i=0;i!=MAXSKILLS;++i) { if (i!=SK_TRADE || !TradeDisabled()) { const char * skname = skillname((skill_t)i, lang); if (skname!=NULL) { var.i = i; - addtoken(&lnames->skillnames, skname, var); + addtoken(tokens, skname, var); } } } + + tokens = get_translations(lang, UT_KEYWORDS); for (i=0;i!=MAXKEYWORDS;++i) { var.i = i; - addtoken(&lnames->keywords, LOC(lang, keywords[i]), var); + addtoken(tokens, LOC(lang, keywords[i]), var); } + + tokens = get_translations(lang, UT_OPTIONS); for (i=0;i!=MAXOPTIONS;++i) { var.i = i; - addtoken(&lnames->options, LOC(lang, options[i]), var); + addtoken(tokens, LOC(lang, options[i]), var); } } diff --git a/src/common/kernel/kernel.vcproj b/src/common/kernel/kernel.vcproj index 0605b5dd6..847357e14 100644 --- a/src/common/kernel/kernel.vcproj +++ b/src/common/kernel/kernel.vcproj @@ -406,6 +406,9 @@ + + diff --git a/src/common/kernel/xmlkernel.h b/src/common/kernel/xmlkernel.h new file mode 100644 index 000000000..b2cb331c4 --- /dev/null +++ b/src/common/kernel/xmlkernel.h @@ -0,0 +1,28 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2007 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KRNL_XML +#define H_KRNL_XML + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern void xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, struct construction ** consPtr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/kernel/xmlreader.c b/src/common/kernel/xmlreader.c index d68ffd2af..737bd9312 100644 --- a/src/common/kernel/xmlreader.c +++ b/src/common/kernel/xmlreader.c @@ -159,13 +159,13 @@ xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray) } } -static void -xml_readconstruction(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, construction ** consPtr) +void +xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, construction ** consPtr) { xmlNodePtr pushNode = xpath->node; int k; - for (k=0;k!=nodeNr;++k) { - xmlNodePtr node = nodeTab[k]; + for (k=0;k!=nodeSet->nodeNr;++k) { + xmlNodePtr node = nodeSet->nodeTab[k]; xmlChar * property; construction * con; xmlXPathObjectPtr req; @@ -176,10 +176,13 @@ xml_readconstruction(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, consPtr = &con->improvement; property = xmlGetProp(node, BAD_CAST "skill"); - assert(property!=NULL); - con->skill = sk_find((const char*)property); - assert(con->skill!=NOSKILL); - xmlFree(property); + if (property!=NULL) { + con->skill = sk_find((const char*)property); + assert(con->skill!=NOSKILL); + xmlFree(property); + } else { + con->skill = NOSKILL; + } con->maxsize = xml_ivalue(node, "maxsize", -1); con->minskill = xml_ivalue(node, "minskill", -1); @@ -207,7 +210,6 @@ xml_readconstruction(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, } xmlXPathFreeObject(req); - } xpath->node = pushNode; } @@ -277,7 +279,7 @@ parse_buildings(xmlDocPtr doc) /* reading eressea/buildings/building/construction */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); - xml_readconstruction(xpath, result->nodesetval->nodeTab, result->nodesetval->nodeNr, &btype->construction); + xml_readconstruction(xpath, result->nodesetval, &btype->construction); xmlXPathFreeObject(result); if (gamecode_enabled) { @@ -494,7 +496,7 @@ parse_ships(xmlDocPtr doc) /* reading eressea/ships/ship/construction */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); - xml_readconstruction(xpath, result->nodesetval->nodeTab, result->nodesetval->nodeNr, &st->construction); + xml_readconstruction(xpath, result->nodesetval, &st->construction); xmlXPathFreeObject(result); /* reading eressea/ships/ship/coast */ @@ -754,7 +756,7 @@ xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) /* reading item/construction */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); - xml_readconstruction(xpath, result->nodesetval->nodeTab, result->nodesetval->nodeNr, &itype->construction); + xml_readconstruction(xpath, result->nodesetval, &itype->construction); xmlXPathFreeObject(result); /* reading item/weapon */ @@ -1206,7 +1208,7 @@ parse_equipment(xmlDocPtr doc) xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr xpathRaces; - /* reading eressea/races/race */ + /* reading eressea/equipment/set */ xpathRaces = xmlXPathEvalExpression(BAD_CAST "/eressea/equipment/set", xpath); if (xpathRaces->nodesetval) { xmlNodeSetPtr nsetRaces = xpathRaces->nodesetval; diff --git a/src/common/kernel/xmlreader.h b/src/common/kernel/xmlreader.h index 58fef6942..82264f264 100644 --- a/src/common/kernel/xmlreader.h +++ b/src/common/kernel/xmlreader.h @@ -2,7 +2,7 @@ +-------------------+ | | Enno Rehling | Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2004 | Katja Zedel +| (c) 1998 - 2007 | Katja Zedel | | Henning Peters +-------------------+ diff --git a/src/common/util/language.c b/src/common/util/language.c index 4c54776cf..f9adb1ce0 100644 --- a/src/common/util/language.c +++ b/src/common/util/language.c @@ -17,6 +17,7 @@ #include "log.h" #include "goodies.h" +#include "umlaut.h" #include #include @@ -44,6 +45,8 @@ find_locale(const char * name) return l; } +static int nextlocaleindex = 0; + locale * make_locale(const char * name) { @@ -57,6 +60,8 @@ make_locale(const char * name) l->hashkey = hkey; l->name = strdup(name); l->next = locales; + l->index = nextlocaleindex++; + assert(nextlocaleindex<=MAXLOCALES); locales = l; if (default_locale==NULL) default_locale = l; return l; @@ -219,3 +224,22 @@ nextlocale(const struct locale * lang) { return lang->next; } + +typedef struct lstr { + tnode tokens[UT_MAX]; +} lstr; + +static lstr lstrs[MAXLOCALES]; + +struct tnode * +get_translations(const struct locale * lang, int index) +{ + static struct lstr * lnames = NULL; + static const struct locale * lastlang = NULL; + + assert(lang->indexindexindex].tokens+index; + } + return lstrs[0].tokens+index; +} diff --git a/src/common/util/language.h b/src/common/util/language.h index 78580e569..5c60e36b6 100644 --- a/src/common/util/language.h +++ b/src/common/util/language.h @@ -42,6 +42,19 @@ extern struct locale * default_locale; extern struct locale * locales; extern struct locale * nextlocale(const struct locale * lang); +enum { + UT_PARAMS, + UT_KEYWORDS, + UT_SKILLS, + UT_RACES, + UT_OPTIONS, + UT_DIRECTIONS, + UT_ARCHETYPES, + UT_MAX +}; + +struct tnode * get_translations(const struct locale * lang, int index); + #ifdef __cplusplus } #endif diff --git a/src/common/util/language_struct.h b/src/common/util/language_struct.h index a4f0fe65a..1f09a071b 100644 --- a/src/common/util/language_struct.h +++ b/src/common/util/language_struct.h @@ -5,6 +5,7 @@ * feel that you need to include it, it's a sure sign that you're trying to * do something BAD. */ +#define MAXLOCALES 3 #define SMAXHASH 2048 typedef struct locale_str { unsigned int hashkey; @@ -14,6 +15,7 @@ typedef struct locale_str { } locale_str; typedef struct locale { + int index; struct locale * next; unsigned int hashkey; const char * name; diff --git a/src/eressea/server.cpp b/src/eressea/server.cpp index de13be108..2afa74541 100644 --- a/src/eressea/server.cpp +++ b/src/eressea/server.cpp @@ -54,6 +54,7 @@ #endif /* gamecode includes */ +#include #include #include #include @@ -223,6 +224,7 @@ game_init(void) register_ships(); register_itemfunctions(); register_spells(); + register_archetypes(); #ifdef DUNGEON_MODULE register_dungeon(); #endif @@ -245,6 +247,7 @@ game_init(void) init_locales(); /* init_resources(); must be done inside the xml-read, because requirements use items */ + init_archetypes(); init_attributes(); init_races(); init_itemtypes(); diff --git a/src/res/rts.xml b/src/res/rts.xml new file mode 100644 index 000000000..663d26478 --- /dev/null +++ b/src/res/rts.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eressea-server@eressea.upb.de + eressea-server@eressea.upb.de + + + Bitte denke daran, deine Befehle mit dem Betreff + ERESSEA BEFEHLE an eressea-server@eressea.upb.de zu senden. + Remember to send your orders to + eressea-server@eressea.upb.de with the subject ERESSEA ORDERS. + + + ERESSEA BEFEHLE + ERESSEA ORDERS + + + diff --git a/src/res/rts/buildings.xml b/src/res/rts/buildings.xml new file mode 100644 index 000000000..725f8189b --- /dev/null +++ b/src/res/rts/buildings.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/res/rts/equipment.xml b/src/res/rts/equipment.xml new file mode 100644 index 000000000..8d5ff71be --- /dev/null +++ b/src/res/rts/equipment.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/res/rts/units.xml b/src/res/rts/units.xml new file mode 100644 index 000000000..f82b3dcbe --- /dev/null +++ b/src/res/rts/units.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/rts.txt b/src/rts.txt new file mode 100644 index 000000000..917cc18bf --- /dev/null +++ b/src/rts.txt @@ -0,0 +1,24 @@ +Aenderungen fuer Eressea RTS: + +* Befehle abgeschafft: + + ARBEITEN, LEHREN, SPIONIEREN, SABOTIEREN, KRIEG, FRIEDEN, FORSCHEN, TARNEN, TREIBEN, UNTERHALTEN, KAUFEN, VERKAUFEN, ZUECHTEN, LIEFERE, MEINUNG, MAGIEGEBIET, NEUSTART, OPFERE, BETEN, JIHAD, INFO, GM, WERWESEN, ALLIANZ, XONTORMIA, SYNONYM + +* Learning by doing abgeschafft. + +* Skills disabled: + + espionage, entertainment, taxation, tactics, stealth, trade, perception + +* Alle Gebaeude entfernt, mit Ausnahme von Burgen + +* Keine NPC-Monster + +* Einheiten koennen ueber ihre Grundskills hinaus keine neuen Skills lernen + + + +Offene Fragen: + +* Soll es eine Maximalanzahl Einheiten geben? + diff --git a/src/scripts/rts-run.lua b/src/scripts/rts-run.lua new file mode 100644 index 000000000..53504538d --- /dev/null +++ b/src/scripts/rts-run.lua @@ -0,0 +1,99 @@ +function loadscript(name) + local script = scriptpath .. "/" .. name + print("- loading " .. script) + if pcall(dofile, script)==0 then + print("Could not load " .. script) + end +end + +function change_locales() + -- local localechange = { } + local localechange = { de = { "bLub" } } + + for loc, flist in localechange do + for index, name in flist do + f = get_faction(atoi36(name)) + if f ~= nil then + f.locale = loc + print("LOCALECHANGE ", f, loc) + end + end + end +end + +function run_scripts() + scripts = { + "spells.lua", + "extensions.lua", + "familiars.lua", + "write_emails.lua" + } + for index in scripts do + loadscript(scripts[index]) + end +end + +function process(orders) + -- initialize starting equipment for new players + equipment_setitem("new_faction", "log", "30"); + equipment_setitem("new_faction", "stone", "30"); + equipment_setitem("new_faction", "money", "4200"); + + file = "" .. get_turn() + if read_game(file)~=0 then + print("could not read game") + return -1 + end + init_summary() + + -- run the turn: + if read_orders(orders) ~= 0 then + print("could not read " .. orders) + return -1 + end + run_scripts() + + plan_monsters() + + local nmrs = get_nmrs(1) + if nmrs >= 70 then + print("Shit. More than 70 factions with 1 NMR (" .. nmrs .. ")") + write_summary() + return -1 + end + print (nmrs .. " Factions with 1 NMR") + + process_orders() + + -- post-turn updates: + update_guards() + update_scores() + + change_locales() + + -- use newfactions file to place out new players + autoseed(basepath .. "/newfactions", false) + + write_passwords() + write_reports() + write_emails() + write_summary() + + file = "" .. get_turn() + if write_game(file)~=0 then + print("could not write game") + return -1 + end +end + +-- +-- main body of script +-- + +-- orderfile: contains the name of the orders. +if orderfile==nil then + print "you must specify an orderfile" +else + process(orderfile) +end +