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 */