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;