diff --git a/res/buildings/castle-2.xml b/res/buildings/castle-2.xml index 7b015d199..989832940 100644 --- a/res/buildings/castle-2.xml +++ b/res/buildings/castle-2.xml @@ -1,23 +1,22 @@ - - + - + - + - + - + - + diff --git a/res/buildings/castle.xml b/res/buildings/castle.xml index 6e9140222..78ce7066c 100644 --- a/res/buildings/castle.xml +++ b/res/buildings/castle.xml @@ -1,25 +1,24 @@ - - + - + - + - + - + - + - + diff --git a/res/e3a/buildings.xml b/res/e3a/buildings.xml index 9eeca952f..27b94dbbe 100644 --- a/res/e3a/buildings.xml +++ b/res/e3a/buildings.xml @@ -4,15 +4,14 @@ - - + - + - + diff --git a/src/economy.c b/src/economy.c index 1ef9ca8c2..87e31b97c 100644 --- a/src/economy.c +++ b/src/economy.c @@ -888,7 +888,7 @@ static void manufacture(unit * u, const item_type * itype, int want) case EBUILDINGREQ: ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "building_needed", "building", - itype->construction->btype->_name)); + itype->construction->extra.btype->_name)); return; case ELOWSKILL: ADDMSG(&u->faction->msgs, @@ -1239,7 +1239,7 @@ static void create_potion(unit * u, const potion_type * ptype, int want) case EBUILDINGREQ: ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "building_needed", "building", - ptype->itype->construction->btype->_name)); + ptype->itype->construction->extra.btype->_name)); break; case ECOMPLETE: assert(0); diff --git a/src/eressea.c b/src/eressea.c index 2d53c2511..a9dddd130 100755 --- a/src/eressea.c +++ b/src/eressea.c @@ -70,7 +70,6 @@ void game_init(void) register_spells(); register_names(); register_resources(); - register_buildings(); register_itemfunctions(); #if MUSEUM_MODULE register_museum(); diff --git a/src/kernel/build.c b/src/kernel/build.c index a8125d1a8..36d72b109 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -502,20 +502,20 @@ static int count_materials(unit *u, const construction *type, int n, int complet */ int build(unit * u, const construction * ctype, int completed, int want, int skill_mod) { - const construction *type = ctype; + const construction *con = ctype; int skills = INT_MAX; /* number of skill points remainig */ int basesk = 0; int made = 0; if (want <= 0) return 0; - if (type == NULL) + if (con == NULL) return ENOMATERIALS; - if (type->improvement == NULL && completed == type->maxsize) + if (con->improvement == NULL && completed == con->maxsize) return ECOMPLETE; - if (type->btype != NULL) { + if (con->type==CONS_ITEM && con->extra.btype) { building *b; - if (!u->building || u->building->type != type->btype) { + if (!u->building || u->building->type != con->extra.btype) { return EBUILDINGREQ; } b = inside_building(u); @@ -524,12 +524,12 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski } } - if (type->skill != NOSKILL) { + if (con->skill != NOSKILL) { int effsk; int dm = get_effect(u, oldpotiontype[P_DOMORE]); assert(u->number); - basesk = effskill(u, type->skill, 0); + basesk = effskill(u, con->skill, 0); if (basesk == 0) return ENEEDSKILL; @@ -557,13 +557,13 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski * type->improvement==type means build another object of the same time * while material lasts type->improvement==x means build x when type * is finished */ - while (type && type->improvement && - type->improvement != type && - type->maxsize > 0 && type->maxsize <= completed) { - completed -= type->maxsize; - type = type->improvement; + while (con && con->improvement && + con->improvement != con && + con->maxsize > 0 && con->maxsize <= completed) { + completed -= con->maxsize; + con = con->improvement; } - if (type == NULL) { + if (con == NULL) { if (made == 0) return ECOMPLETE; break; /* completed */ @@ -574,15 +574,15 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski * (enno): Nein, das ist f�r Dinge, bei denen die n�chste Ausbaustufe * die gleiche wie die vorherige ist. z.b. gegenst�nde. */ - if (type->maxsize > 0) { - completed = completed % type->maxsize; + if (con->maxsize > 0) { + completed = completed % con->maxsize; } else { completed = 0; - assert(type->reqsize >= 1); + assert(con->reqsize >= 1); } - if (basesk < type->minskill) { + if (basesk < con->minskill) { if (made == 0) return ELOWSKILL; else @@ -590,15 +590,15 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski } /* n = maximum buildable size */ - if (type->minskill > 1) { - n = skills / type->minskill; + if (con->minskill > 1) { + n = skills / con->minskill; } else { n = skills; } /* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische) * Talente */ - if (skill_limit(u->faction, type->skill) == INT_MAX) { + if (skill_limit(u->faction, con->skill) == INT_MAX) { const resource_type *ring = get_resourcetype(R_RING_OF_NIMBLEFINGER); item *itm = ring ? *i_find(&u->items, ring->itype) : 0; int i = itm ? itm->number : 0; @@ -610,26 +610,26 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski if (want < n) n = want; - if (type->maxsize > 0) { - n = MIN(type->maxsize - completed, n); - if (type->improvement == NULL) { + if (con->maxsize > 0) { + n = MIN(con->maxsize - completed, n); + if (con->improvement == NULL) { want = n; } } - n = count_materials(u, type, n, completed); + n = count_materials(u, con, n, completed); if (n <= 0) { if (made == 0) return ENOMATERIALS; else break; } - err = use_materials(u, type, n, completed); + err = use_materials(u, con, n, completed); if (err < 0) { return err; } made += n; - skills -= n * type->minskill; + skills -= n * con->minskill; want -= n; completed = completed + n; } diff --git a/src/kernel/build.h b/src/kernel/build.h index bb1204af9..323003efd 100644 --- a/src/kernel/build.h +++ b/src/kernel/build.h @@ -37,15 +37,27 @@ extern "C" { int number; } requirement; + typedef enum construct_t { + CONS_OTHER, + CONS_ITEM, + CONS_BUILDING + } construct_t; + typedef struct construction { + construct_t type; skill_t skill; /* skill req'd per point of size */ int minskill; /* skill req'd per point of size */ int maxsize; /* maximum size of this type */ int reqsize; /* size of object using up 1 set of requirement. */ requirement *materials; /* material req'd to build one object */ - const struct building_type *btype; - /* building type required to make this thing */ + + union { + /* CONS_BUILDING: */ + char * name; /* building level name */ + /* CONS_ITEM: */ + const struct building_type *btype; /* building required to build item */ + } extra; struct construction *improvement; /* next level, if upgradable. if more than one of these items diff --git a/src/kernel/build.test.c b/src/kernel/build.test.c index 34f645856..c3fa07e65 100644 --- a/src/kernel/build.test.c +++ b/src/kernel/build.test.c @@ -81,7 +81,8 @@ static void test_build_requires_building(CuTest *tc) { rtype = bf.cons.materials[0].rtype; i_change(&u->items, rtype->itype, 1); set_level(u, SK_ARMORER, 2); - bf.cons.btype = btype = bt_get_or_create("hodor"); + bf.cons.type = CONS_ITEM; + bf.cons.extra.btype = btype = bt_get_or_create("hodor"); btype->maxcapacity = 1; btype->capacity = 1; CuAssertIntEquals_Msg(tc, "must be inside a production building", EBUILDINGREQ, build(u, &bf.cons, 0, 1, 0)); diff --git a/src/kernel/building.c b/src/kernel/building.c index 3eef32cc4..40f09a6ad 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -157,27 +157,52 @@ attrib_type at_building_generic_type = { ATF_UNIQUE }; +/* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */ +static int adjust_size(const building *b, int bsize) { + assert(b); + if (config_get_int("rules.dwarf_castles", 0) + && strcmp(b->type->_name, "castle") == 0) { + unit *u = building_owner(b); + if (u && u->faction->race == get_race(RC_HALFLING)) { + return bsize * 5 / 4; + } + } + return bsize; +} + /* Returns the (internal) name for a building of given size and type. Especially, returns the correct * name if it depends on the size (as for Eressea castles). */ const char *buildingtype(const building_type * btype, const building * b, int bsize) { - const char *s; + const construction *con; + assert(btype); - s = btype->_name; - if (btype->name) { - s = btype->name(btype, b, bsize); - } if (b && b->attribs) { if (is_building_type(btype, "generic")) { const attrib *a = a_find(b->attribs, &at_building_generic_type); if (a) { - s = (const char *)a->data.v; + return (const char *)a->data.v; } } } - return s; + if (btype->name) { + return btype->name(btype, b, bsize); + } + if (btype->construction->extra.name) { + if (b) { + assert(b->type == btype); + bsize = adjust_size(b, bsize); + } + for (con = btype->construction; con; con = con->improvement) { + bsize -= con->maxsize; + if (!con->improvement || bsize <0) { + return con->extra.name; + } + } + } + return btype->_name; } #define BMAXHASH 7919 @@ -219,55 +244,6 @@ building *findbuilding(int i) { return bfindhash(i); } - -static const char *castle_name_i(const struct building_type *btype, - const struct building *b, int bsize, const char *fname[]) -{ - int i = bt_effsize(btype, b, bsize); - - return fname[i]; -} - -static const char *castle_name_2(const struct building_type *btype, - const struct building *b, int bsize) -{ - const char *fname[] = { - "site", - "fortification", - "tower", - "castle", - "fortress", - "citadel" - }; - return castle_name_i(btype, b, bsize, fname); -} - -static const char *castle_name(const struct building_type *btype, - const struct building *b, int bsize) -{ - const char *fname[] = { - "site", - "tradepost", - "fortification", - "tower", - "castle", - "fortress", - "citadel" - }; - return castle_name_i(btype, b, bsize, fname); -} - -static const char *fort_name(const struct building_type *btype, - const struct building *b, int bsize) -{ - const char *fname[] = { - "scaffolding", - "guardhouse", - "guardtower", - }; - return castle_name_i(btype, b, bsize, fname); -} - /* for finding out what was meant by a particular building string */ static local_names *bnames; @@ -486,24 +462,19 @@ int buildingeffsize(const building * b, int img) int bt_effsize(const building_type * btype, const building * b, int bsize) { - int i = bsize, n = 0; + int n = 0; const construction *cons = btype->construction; - /* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */ - if (b && config_get_int("rules.dwarf_castles", 0) - && strcmp(btype->_name, "castle") == 0) { - unit *u = building_owner(b); - if (u && u->faction->race == get_race(RC_HALFLING)) { - i = bsize * 10 / 8; - } + if (b) { + bsize = adjust_size(b, bsize); } if (!cons || !cons->improvement) { return 0; } - while (cons && cons->maxsize != -1 && i >= cons->maxsize) { - i -= cons->maxsize; + while (cons && cons->maxsize != -1 && bsize >= cons->maxsize) { + bsize -= cons->maxsize; cons = cons->improvement; ++n; } @@ -883,10 +854,3 @@ int cmp_current_owner(const building * b, const building * a) } return -1; } - -void register_buildings(void) -{ - register_function((pf_generic)castle_name, "castle_name"); - register_function((pf_generic)castle_name_2, "castle_name_2"); - register_function((pf_generic)fort_name, "fort_name"); -} diff --git a/src/kernel/building.h b/src/kernel/building.h index f9803cdbf..f7c0c1cdc 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -84,7 +84,6 @@ extern "C" { bool bt_changed(int *cache); const building_type *bt_find(const char *name); void free_buildingtypes(void); - void register_buildings(void); void bt_register(struct building_type *type); int bt_effsize(const struct building_type *btype, const struct building *b, int bsize); diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 603231deb..9f2b2fc51 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -214,7 +214,7 @@ xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray) void xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, -construction ** consPtr) +construction ** consPtr, construct_t type) { xmlNodePtr pushNode = xpath->node; int k; @@ -241,15 +241,25 @@ construction ** consPtr) *consPtr = con = (construction *)calloc(sizeof(construction), 1); consPtr = &con->improvement; + con->type = type; 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); + if (type == CONS_ITEM) { + propValue = xmlGetProp(node, BAD_CAST "building"); + if (propValue != NULL) { + con->extra.btype = bt_get_or_create((const char *)propValue); + xmlFree(propValue); + } + } + else if (type == CONS_BUILDING) { + propValue = xmlGetProp(node, BAD_CAST "name"); + if (propValue != NULL) { + con->extra.name = strdup((const char *)propValue); + xmlFree(propValue); + } } /* read construction/requirement */ @@ -337,7 +347,7 @@ static int parse_buildings(xmlDocPtr doc) /* reading eressea/buildings/building/construction */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); - xml_readconstruction(xpath, result->nodesetval, &btype->construction); + xml_readconstruction(xpath, result->nodesetval, &btype->construction, CONS_BUILDING); xmlXPathFreeObject(result); /* reading eressea/buildings/building/function */ @@ -572,7 +582,7 @@ static int parse_ships(xmlDocPtr doc) /* reading eressea/ships/ship/construction */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); - xml_readconstruction(xpath, result->nodesetval, &st->construction); + xml_readconstruction(xpath, result->nodesetval, &st->construction, CONS_OTHER); xmlXPathFreeObject(result); for (child = node->children; child; child = child->next) { @@ -858,7 +868,7 @@ static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) /* reading item/construction */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); - xml_readconstruction(xpath, result->nodesetval, &itype->construction); + xml_readconstruction(xpath, result->nodesetval, &itype->construction, CONS_ITEM); xmlXPathFreeObject(result); /* reading item/weapon */