diff --git a/res/buildings/castle-2.xml b/res/buildings/castle-2.xml
index 5f48e73ee..76c908572 100644
--- a/res/buildings/castle-2.xml
+++ b/res/buildings/castle-2.xml
@@ -1,24 +1,24 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/res/buildings/castle.xml b/res/buildings/castle.xml
index 296d1f716..49d1ca5a8 100644
--- a/res/buildings/castle.xml
+++ b/res/buildings/castle.xml
@@ -1,26 +1,26 @@
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/res/e3a/buildings.xml b/res/e3a/buildings.xml
index b3e59f0a4..227a2e47a 100644
--- a/res/e3a/buildings.xml
+++ b/res/e3a/buildings.xml
@@ -5,15 +5,15 @@
-
+
-
+
-
+
-
+
diff --git a/scripts/eressea/e3/rules.lua b/scripts/eressea/e3/rules.lua
index 0c5e9be85..c0ac8978a 100644
--- a/scripts/eressea/e3/rules.lua
+++ b/scripts/eressea/e3/rules.lua
@@ -26,10 +26,6 @@ function item_canuse(u, iname)
return true
end
-function building_protection(b, u)
- return 1
-end
-
function building_taxes(b, blevel)
btype = b.type
if btype=="castle" then
diff --git a/src/battle.c b/src/battle.c
index 7065ad11b..ed4354049 100644
--- a/src/battle.c
+++ b/src/battle.c
@@ -1901,7 +1901,7 @@ int skilldiff(troop at, troop dt, int dist)
init = true;
}
if (df->building->type->protection) {
- int beff = df->building->type->protection(df->building, du);
+ int beff = df->building->type->protection(df->building, du, DEFENSE_BONUS);
if (beff) {
skdiff -= beff;
is_protected = 2;
@@ -1918,7 +1918,7 @@ int skilldiff(troop at, troop dt, int dist)
if (magicwalls_ct
&& curse_active(get_curse(df->building->attribs, magicwalls_ct))) {
/* Verdoppelt Burgenbonus */
- skdiff -= buildingeffsize(df->building, false);
+ skdiff -= df->building->type->protection(df->building, du, DEFENSE_BONUS);
}
}
/* Goblin-Verteidigung
diff --git a/src/battle.test.c b/src/battle.test.c
index e35864c12..e72a9d5ac 100644
--- a/src/battle.test.c
+++ b/src/battle.test.c
@@ -57,131 +57,160 @@ static void test_make_fighter(CuTest * tc)
test_cleanup();
}
-static int add_two(building * b, unit * u) {
+static int add_two(building * b, unit * u, building_bonus bonus) {
return 2;
}
static void test_defenders_get_building_bonus(CuTest * tc)
{
- unit *du, *au;
- region *r;
- building * bld;
- fighter *df, *af;
- battle *b;
- side *ds, *as;
- int diff;
- troop dt, at;
- building_type * btype;
+ unit *du, *au;
+ region *r;
+ building * bld;
+ fighter *df, *af;
+ battle *b;
+ side *ds, *as;
+ int diff;
+ troop dt, at;
+ building_type * btype;
- test_cleanup();
- test_create_world();
- r = findregion(0, 0);
- btype = bt_get_or_create("castle");
- btype->protection = &add_two;
- bld = test_create_building(r, btype);
- bld->size = 10;
+ test_cleanup();
+ test_create_world();
+ r = findregion(0, 0);
+ btype = bt_get_or_create("castle");
+ btype->protection = &add_two;
+ bld = test_create_building(r, btype);
+ bld->size = 10;
- du = test_create_unit(test_create_faction(rc_find("human")), r);
- au = test_create_unit(test_create_faction(rc_find("human")), r);
- u_set_building(du, bld);
+ du = test_create_unit(test_create_faction(rc_find("human")), r);
+ au = test_create_unit(test_create_faction(rc_find("human")), r);
+ u_set_building(du, bld);
- b = make_battle(r);
- ds = make_side(b, du->faction, 0, 0, 0);
- df = make_fighter(b, du, ds, false);
- as = make_side(b, au->faction, 0, 0, 0);
- af = make_fighter(b, au, as, true);
+ b = make_battle(r);
+ ds = make_side(b, du->faction, 0, 0, 0);
+ df = make_fighter(b, du, ds, false);
+ as = make_side(b, au->faction, 0, 0, 0);
+ af = make_fighter(b, au, as, true);
- CuAssertPtrEquals(tc, bld, df->building);
- CuAssertPtrEquals(tc, 0, af->building);
+ CuAssertPtrEquals(tc, bld, df->building);
+ CuAssertPtrEquals(tc, 0, af->building);
- dt.fighter = df;
- dt.index = 0;
- at.fighter = af;
- at.index = 0;
+ dt.fighter = df;
+ dt.index = 0;
+ at.fighter = af;
+ at.index = 0;
- diff = skilldiff(at, dt, 0);
- CuAssertIntEquals(tc, -2, diff);
+ diff = skilldiff(at, dt, 0);
+ CuAssertIntEquals(tc, -2, diff);
- diff = skilldiff(dt, at, 0);
- CuAssertIntEquals(tc, 0, diff);
+ diff = skilldiff(dt, at, 0);
+ CuAssertIntEquals(tc, 0, diff);
free_battle(b);
test_cleanup();
}
static void test_attackers_get_no_building_bonus(CuTest * tc)
{
- unit *au;
- region *r;
- building * bld;
- fighter *af;
- battle *b;
- side *as;
- building_type * btype;
+ unit *au;
+ region *r;
+ building * bld;
+ fighter *af;
+ battle *b;
+ side *as;
+ building_type * btype;
- test_cleanup();
- test_create_world();
- r = findregion(0, 0);
- btype = bt_get_or_create("castle");
- btype->protection = &add_two;
- bld = test_create_building(r, btype);
- bld->size = 10;
+ test_cleanup();
+ test_create_world();
+ r = findregion(0, 0);
+ btype = bt_get_or_create("castle");
+ btype->protection = &add_two;
+ bld = test_create_building(r, btype);
+ bld->size = 10;
- au = test_create_unit(test_create_faction(rc_find("human")), r);
- u_set_building(au, bld);
+ au = test_create_unit(test_create_faction(rc_find("human")), r);
+ u_set_building(au, bld);
- b = make_battle(r);
- as = make_side(b, au->faction, 0, 0, 0);
- af = make_fighter(b, au, as, true);
+ b = make_battle(r);
+ as = make_side(b, au->faction, 0, 0, 0);
+ af = make_fighter(b, au, as, true);
- CuAssertPtrEquals(tc, 0, af->building);
+ CuAssertPtrEquals(tc, 0, af->building);
free_battle(b);
test_cleanup();
}
static void test_building_bonus_respects_size(CuTest * tc)
{
- unit *au, *du;
- region *r;
- building * bld;
- fighter *af, *df;
- battle *b;
- side *as;
- building_type * btype;
- faction * f;
+ unit *au, *du;
+ region *r;
+ building * bld;
+ fighter *af, *df;
+ battle *b;
+ side *as;
+ building_type * btype;
+ faction * f;
- test_cleanup();
- test_create_world();
- r = findregion(0, 0);
- btype = bt_get_or_create("castle");
- btype->protection = &add_two;
- bld = test_create_building(r, btype);
- bld->size = 10;
+ test_cleanup();
+ test_create_world();
+ r = findregion(0, 0);
+ btype = bt_get_or_create("castle");
+ btype->protection = &add_two;
+ bld = test_create_building(r, btype);
+ bld->size = 10;
- f = test_create_faction(rc_find("human"));
- au = test_create_unit(f, r);
- scale_number(au, 9);
- u_set_building(au, bld);
- du = test_create_unit(f, r);
- u_set_building(du, bld);
- scale_number(du, 2);
+ f = test_create_faction(rc_find("human"));
+ au = test_create_unit(f, r);
+ scale_number(au, 9);
+ u_set_building(au, bld);
+ du = test_create_unit(f, r);
+ u_set_building(du, bld);
+ scale_number(du, 2);
- b = make_battle(r);
- as = make_side(b, au->faction, 0, 0, 0);
- af = make_fighter(b, au, as, false);
- df = make_fighter(b, du, as, false);
+ b = make_battle(r);
+ as = make_side(b, au->faction, 0, 0, 0);
+ af = make_fighter(b, au, as, false);
+ df = make_fighter(b, du, as, false);
- CuAssertPtrEquals(tc, bld, af->building);
- CuAssertPtrEquals(tc, 0, df->building);
+ CuAssertPtrEquals(tc, bld, af->building);
+ CuAssertPtrEquals(tc, 0, df->building);
free_battle(b);
test_cleanup();
}
+static void test_building_defence_bonus(CuTest * tc)
+{
+ unit *au;
+ region *r;
+ building * bld;
+ building_type * btype;
+ faction * f;
+ int def;
+ test_cleanup();
+ test_create_world();
+ r = findregion(0, 0);
+ register_buildings();
+ btype = bt_get_or_create("castle");
+ btype->protection = get_function("building_protection");
+ btype->construction->defense_bonus = 3;
+ bld = test_create_building(r, btype);
+ bld->size = 1;
+
+ f = test_create_faction(rc_find("human"));
+ au = test_create_unit(f, r);
+ scale_number(au, 1);
+ u_set_building(au, bld);
+
+ def = btype->protection(bld, au, DEFENSE_BONUS);
+ CuAssertIntEquals(tc, 3, def);
+ test_cleanup();
+}
+
CuSuite *get_battle_suite(void)
{
- CuSuite *suite = CuSuiteNew();
- SUITE_ADD_TEST(suite, test_make_fighter);
- SUITE_ADD_TEST(suite, test_defenders_get_building_bonus);
- SUITE_ADD_TEST(suite, test_attackers_get_no_building_bonus);
- SUITE_ADD_TEST(suite, test_building_bonus_respects_size);
- return suite;
+ CuSuite *suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_make_fighter);
+ SUITE_ADD_TEST(suite, test_defenders_get_building_bonus);
+ SUITE_ADD_TEST(suite, test_attackers_get_no_building_bonus);
+ SUITE_ADD_TEST(suite, test_building_bonus_respects_size);
+ SUITE_ADD_TEST(suite, test_building_defence_bonus);
+ return suite;
}
diff --git a/src/helpers.c b/src/helpers.c
index 5f0b3a12d..e37865be5 100644
--- a/src/helpers.c
+++ b/src/helpers.c
@@ -388,32 +388,6 @@ static void lua_agebuilding(building * b)
}
}
-static int lua_building_protection(building * b, unit * u)
-{
- lua_State *L = (lua_State *) global.vm_state;
- const char *fname = "building_protection";
- int result = 0;
-
- lua_getglobal(L, fname);
- if (lua_isfunction(L, -1)) {
- tolua_pushusertype(L, (void *)b, TOLUA_CAST "building");
- tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit");
-
- if (lua_pcall(L, 2, 1, 0) != 0) {
- const char *error = lua_tostring(L, -1);
- log_error("building_protection(%s, %s) calling '%s': %s.\n", buildingname(b), unitname(u), fname, error);
- lua_pop(L, 1);
- } else {
- result = (int)lua_tonumber(L, -1);
- lua_pop(L, 1);
- }
- } else {
- log_error("building_protection(%s, %s) calling '%s': not a function.\n", buildingname(b), unitname(u), fname);
- lua_pop(L, 1);
- }
- return result;
-}
-
static double lua_building_taxes(building * b, int level)
{
lua_State *L = (lua_State *) global.vm_state;
@@ -545,8 +519,6 @@ void register_tolua_helpers(void)
at_register(&at_direction);
at_register(&at_building_action);
- register_function((pf_generic) & lua_building_protection,
- TOLUA_CAST "lua_building_protection");
register_function((pf_generic) & lua_building_taxes,
TOLUA_CAST "lua_building_taxes");
register_function((pf_generic) & lua_agebuilding,
diff --git a/src/kernel/build.h b/src/kernel/build.h
index 4e3bbedaa..8bd41e409 100644
--- a/src/kernel/build.h
+++ b/src/kernel/build.h
@@ -45,6 +45,9 @@ extern "C" {
int maxsize; /* maximum size of this type */
int reqsize; /* size of object using up 1 set of requirement. */
+ int defense_bonus; /* protection bonus (defense) during combat */
+ int close_combat_bonus; /* close combat attack bonus*/
+ int ranged_bonus; /* ranged attack bonus */
requirement *materials; /* material req'd to build one object */
const struct building_type *btype;
/* building type required to make this thing */
diff --git a/src/kernel/building.c b/src/kernel/building.c
index a382a63bf..f74976661 100644
--- a/src/kernel/building.c
+++ b/src/kernel/building.c
@@ -316,12 +316,32 @@ const building_type *findbuildingtype(const char *name,
return (const building_type *)type.v;
}
-static int eressea_building_protection(building * b, unit * u)
+static int building_protection(building * b, unit * u, building_bonus bonus)
{
- int beff = buildingeffsize(b, false) - 1;
- /* -1 because the tradepost has no protection value */
- return beff;
+ int i = 0;
+ int bsize = buildingeffsize(b, false);
+ const construction *cons = b->type->construction;
+ if (!cons) {
+ return 0;
+ }
+
+ for (i = 0; i < bsize; i++)
+ {
+ cons = cons->improvement;
+ }
+
+ switch (bonus)
+ {
+ case DEFENSE_BONUS:
+ return cons->defense_bonus;
+ case CLOSE_COMBAT_ATTACK_BONUS:
+ return cons->close_combat_bonus;
+ case RANGED_ATTACK_BONUS:
+ return cons->ranged_bonus;
+ default:
+ return 0;
+ }
}
static int meropis_building_protection(building * b, unit * u)
@@ -331,8 +351,8 @@ static int meropis_building_protection(building * b, unit * u)
void register_buildings(void)
{
- register_function((pf_generic)& eressea_building_protection,
- "eressea_building_protection");
+ register_function((pf_generic)& building_protection,
+ "building_protection");
register_function((pf_generic)& meropis_building_protection,
"meropis_building_protection");
register_function((pf_generic)& init_smithy, "init_smithy");
diff --git a/src/kernel/building.h b/src/kernel/building.h
index cf80de84f..98db1bd2f 100644
--- a/src/kernel/building.h
+++ b/src/kernel/building.h
@@ -48,6 +48,12 @@ extern "C" {
#define BTF_ONEPERTURN 0x80 /* one one sizepoint can be added per turn */
#define BTF_NAMECHANGE 0x100 /* name and description can be changed more than once */
+ typedef enum {
+ DEFENSE_BONUS,
+ CLOSE_COMBAT_ATTACK_BONUS,
+ RANGED_ATTACK_BONUS,
+ } building_bonus;
+
typedef struct building_type {
char *_name;
@@ -66,7 +72,7 @@ extern "C" {
const struct building * b, int size);
void (*init) (struct building_type *);
void (*age) (struct building *);
- int (*protection) (struct building *, struct unit *);
+ int (*protection) (struct building *, struct unit *, building_bonus);
double (*taxes) (const struct building *, int size);
struct attrib *attribs;
} building_type;
diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c
index 77d2270e1..1b1c6b356 100644
--- a/src/kernel/xmlreader.c
+++ b/src/kernel/xmlreader.c
@@ -167,7 +167,10 @@ construction ** consPtr)
con->maxsize = xml_ivalue(node, "maxsize", -1);
con->minskill = xml_ivalue(node, "minskill", -1);
con->reqsize = xml_ivalue(node, "reqsize", -1);
-
+ con->defense_bonus = xml_ivalue(node, "defense_bonus", 0);
+ con->close_combat_bonus = xml_ivalue(node, "close_combat_bonus", 0);
+ con->ranged_bonus = xml_ivalue(node, "ranged_bonus", 0);
+
propValue = xmlGetProp(node, BAD_CAST "building");
if (propValue != NULL) {
con->btype = bt_get_or_create((const char *)propValue);
@@ -297,7 +300,7 @@ static int parse_buildings(xmlDocPtr doc)
btype->age = (void(*)(struct building *))fun;
}
else if (strcmp((const char *)propValue, "protection") == 0) {
- btype->protection = (int(*)(struct building *, struct unit *))fun;
+ btype->protection = (int(*)(struct building *, struct unit *, building_bonus))fun;
}
else if (strcmp((const char *)propValue, "taxes") == 0) {
btype->taxes = (double(*)(const struct building *, int))fun;