From deb39f6b8f8386169d4dd1ebe81429e9fdd0b6db Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 22 Feb 2017 14:27:13 +0100 Subject: [PATCH 01/23] test building_effsize does what it does --- src/kernel/building.test.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/kernel/building.test.c b/src/kernel/building.test.c index e02d16556..8bafcab85 100644 --- a/src/kernel/building.test.c +++ b/src/kernel/building.test.c @@ -515,6 +515,31 @@ static void test_cmp_castle_size(CuTest *tc) { test_cleanup(); } +static void test_building_effsize(CuTest *tc) { + building *b; + building_type *btype; + construction *cons; + + test_setup(); + btype = bt_get_or_create("castle"); + cons = btype->construction = calloc(1, sizeof(construction)); + cons->maxsize = 5; + cons = cons->improvement = calloc(1, sizeof(construction)); + cons->maxsize = 5; + cons = cons->improvement = calloc(1, sizeof(construction)); + cons->maxsize = -1; + b = test_create_building(test_create_region(0,0,0), btype); + b->size = 1; + CuAssertIntEquals(tc, 0, buildingeffsize(b, false)); + b->size = 5; + CuAssertIntEquals(tc, 1, buildingeffsize(b, false)); + b->size = 10; + CuAssertIntEquals(tc, 2, buildingeffsize(b, false)); + b->size = 20; + CuAssertIntEquals(tc, 2, buildingeffsize(b, false)); + test_cleanup(); +} + CuSuite *get_building_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -522,6 +547,7 @@ CuSuite *get_building_suite(void) SUITE_ADD_TEST(suite, test_register_building); SUITE_ADD_TEST(suite, test_btype_defaults); SUITE_ADD_TEST(suite, test_building_set_owner); + SUITE_ADD_TEST(suite, test_building_effsize); SUITE_ADD_TEST(suite, test_buildingowner_resets_when_empty); SUITE_ADD_TEST(suite, test_buildingowner_goes_to_next_when_empty); SUITE_ADD_TEST(suite, test_buildingowner_goes_to_other_when_empty); From 3274065004bf42a0ab670a0c27f4da0da3cf3e20 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 22 Feb 2017 19:38:46 +0100 Subject: [PATCH 02/23] reduce complexity of building_protection. --- .gitignore | 3 ++ res/buildings/castle-2.xml | 13 +++--- res/buildings/castle.xml | 15 ++++--- res/e3a/buildings.xml | 7 ++-- src/battle.c | 18 ++++---- src/battle.test.c | 84 ++++++++++++++++++++------------------ src/kernel/build.h | 3 -- src/kernel/building.c | 36 ++++------------ src/kernel/building.h | 13 ++---- src/kernel/building.test.c | 1 - src/kernel/xmlreader.c | 6 --- src/tests.c | 2 +- 12 files changed, 87 insertions(+), 114 deletions(-) diff --git a/.gitignore b/.gitignore index 4e63f5d9c..d7c102f5a 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,6 @@ tmp/ tests/config.lua tests/reports/ tests/data/185.dat +/quicklist/ +/cutest/ +/critbit/ diff --git a/res/buildings/castle-2.xml b/res/buildings/castle-2.xml index 593e9ae5e..7b015d199 100644 --- a/res/buildings/castle-2.xml +++ b/res/buildings/castle-2.xml @@ -1,24 +1,23 @@ - - + - + - + - + - + - + diff --git a/res/buildings/castle.xml b/res/buildings/castle.xml index 253f49811..6e9140222 100644 --- a/res/buildings/castle.xml +++ b/res/buildings/castle.xml @@ -1,26 +1,25 @@ - - + - + - + - + - + - + - + diff --git a/res/e3a/buildings.xml b/res/e3a/buildings.xml index f65654e2f..9eeca952f 100644 --- a/res/e3a/buildings.xml +++ b/res/e3a/buildings.xml @@ -5,15 +5,14 @@ - - + - + - + diff --git a/src/battle.c b/src/battle.c index 0ff8eecaa..23c219109 100644 --- a/src/battle.c +++ b/src/battle.c @@ -1892,10 +1892,11 @@ int skilldiff(troop at, troop dt, int dist) } if (df->building) { - if (df->building->attribs) { + building *b = df->building; + if (b->attribs) { const curse_type *strongwall_ct = ct_find("strongwall"); if (strongwall_ct) { - curse *c = get_curse(df->building->attribs, strongwall_ct); + curse *c = get_curse(b->attribs, strongwall_ct); if (curse_active(c)) { /* wirkt auf alle Geb�ude */ skdiff -= curse_geteffect_int(c); @@ -1903,15 +1904,16 @@ int skilldiff(troop at, troop dt, int dist) } } } - if (df->building->type->protection) { - int beff = df->building->type->protection(df->building, du, DEFENSE_BONUS); - if (beff) { + if (b->type->flags & BTF_FORTIFICATION) { + int stage = buildingeffsize(b, false); + int beff = building_protection(b->type, stage); + if (beff > 0) { skdiff -= beff; is_protected = 2; - if (df->building->attribs) { + if (b->attribs) { const curse_type *magicwalls_ct = ct_find("magicwalls"); if (magicwalls_ct - && curse_active(get_curse(df->building->attribs, magicwalls_ct))) { + && curse_active(get_curse(b->attribs, magicwalls_ct))) { /* Verdoppelt Burgenbonus */ skdiff -= beff; } @@ -2022,7 +2024,7 @@ void damage_building(battle * b, building * bldg, int damage_abs) /* Wenn Burg, dann gucken, ob die Leute alle noch in das Geb�ude passen. */ - if (bldg->type->protection) { + if (bldg->type->flags & BTF_FORTIFICATION) { side *s; bldg->sizeleft = bldg->size; diff --git a/src/battle.test.c b/src/battle.test.c index 5d34766db..987613277 100644 --- a/src/battle.test.c +++ b/src/battle.test.c @@ -60,10 +60,23 @@ static void test_make_fighter(CuTest * tc) test_cleanup(); } -static int add_two(const building * b, const unit * u, building_bonus bonus) { +static int add_two(const building * b, const unit * u) { return 2; } +static building_type * setup_castle(void) { + building_type * btype; + construction *cons; + + btype = bt_get_or_create("castle"); + btype->flags |= BTF_FORTIFICATION; + cons = btype->construction = calloc(1, sizeof(construction)); + cons->maxsize = 5; + cons = cons->improvement = calloc(1, sizeof(construction)); + cons->maxsize = -1; + return btype; +} + static void test_defenders_get_building_bonus(CuTest * tc) { unit *du, *au; @@ -72,16 +85,13 @@ static void test_defenders_get_building_bonus(CuTest * tc) fighter *df, *af; battle *b; side *ds, *as; - int diff; troop dt, at; building_type * btype; test_cleanup(); + btype = setup_castle(); r = test_create_region(0, 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(NULL), r); au = test_create_unit(test_create_faction(NULL), r); @@ -101,11 +111,14 @@ static void test_defenders_get_building_bonus(CuTest * tc) at.fighter = af; at.index = 0; - diff = skilldiff(at, dt, 0); - CuAssertIntEquals(tc, -2, diff); + bld->size = 10; /* stage 1 building */ + CuAssertIntEquals(tc, -1, skilldiff(at, dt, 0)); + CuAssertIntEquals(tc, 0, skilldiff(dt, at, 0)); + + bld->size = 1; /* stage 0 building */ + CuAssertIntEquals(tc, 0, skilldiff(at, dt, 0)); + CuAssertIntEquals(tc, 0, skilldiff(dt, at, 0)); - diff = skilldiff(dt, at, 0); - CuAssertIntEquals(tc, 0, diff); free_battle(b); test_cleanup(); } @@ -122,8 +135,8 @@ static void test_attackers_get_no_building_bonus(CuTest * tc) test_cleanup(); r = test_create_region(0, 0, 0); - btype = bt_get_or_create("castle"); - btype->protection = &add_two; + btype = setup_castle(); + btype->flags |= BTF_FORTIFICATION; bld = test_create_building(r, btype); bld->size = 10; @@ -151,9 +164,9 @@ static void test_building_bonus_respects_size(CuTest * tc) faction * f; test_cleanup(); + btype = setup_castle(); r = test_create_region(0, 0, 0); - btype = bt_get_or_create("castle"); - btype->protection = &add_two; + btype->flags |= BTF_FORTIFICATION; bld = test_create_building(r, btype); bld->size = 10; @@ -178,28 +191,25 @@ static void test_building_bonus_respects_size(CuTest * tc) static void test_building_defence_bonus(CuTest * tc) { - unit *au; - region *r; - building * bld; building_type * btype; - faction * f; - int def; test_cleanup(); - r = test_create_region(0, 0, 0); - btype = test_create_buildingtype("castle"); - btype->protection = (int(*)(const struct building *, const struct unit *, building_bonus))get_function("building_protection"); - btype->construction->defense_bonus = 3; - bld = test_create_building(r, btype); - bld->size = 1; + btype = setup_castle(); - f = test_create_faction(NULL); - au = test_create_unit(f, r); - scale_number(au, 1); - u_set_building(au, bld); + btype->maxsize = -1; /* unlimited buildigs get the castle bonus */ + CuAssertIntEquals(tc, 0, building_protection(btype, 0)); + CuAssertIntEquals(tc, 1, building_protection(btype, 1)); + CuAssertIntEquals(tc, 3, building_protection(btype, 2)); + CuAssertIntEquals(tc, 5, building_protection(btype, 3)); + CuAssertIntEquals(tc, 8, building_protection(btype, 4)); + CuAssertIntEquals(tc, 12, building_protection(btype, 5)); + CuAssertIntEquals(tc, 12, building_protection(btype, 6)); - def = btype->protection(bld, au, DEFENSE_BONUS); - CuAssertIntEquals(tc, 3, def); + btype->maxsize = 10; /* limited-size buildings are treated like an E3 watchtower */ + CuAssertIntEquals(tc, 0, building_protection(btype, 0)); + CuAssertIntEquals(tc, 1, building_protection(btype, 1)); + CuAssertIntEquals(tc, 2, building_protection(btype, 2)); + CuAssertIntEquals(tc, 2, building_protection(btype, 3)); test_cleanup(); } @@ -441,10 +451,6 @@ static void test_battle_skilldiff(CuTest *tc) test_cleanup(); } -static int protect(const building *b, const unit *u, building_bonus bonus) { - return (bonus == DEFENSE_BONUS) ? 4 : 0; -} - static void test_battle_skilldiff_building(CuTest *tc) { troop ta, td; @@ -455,7 +461,7 @@ static void test_battle_skilldiff_building(CuTest *tc) const curse_type *strongwall_ct, *magicwalls_ct; test_cleanup(); - btype = test_create_buildingtype("castle"); + btype = setup_castle(); strongwall_ct = ct_find("strongwall"); magicwalls_ct = ct_find("magicwalls"); @@ -470,14 +476,14 @@ static void test_battle_skilldiff_building(CuTest *tc) ua = test_create_unit(test_create_faction(0), r); CuAssertIntEquals(tc, 0, skilldiff(ta, td, 0)); - btype->protection = protect; - CuAssertIntEquals(tc, -4, skilldiff(ta, td, 0)); + ud->building->size = 10; + CuAssertIntEquals(tc, -1, skilldiff(ta, td, 0)); create_curse(NULL, &ud->building->attribs, magicwalls_ct, 1, 1, 1, 1); - CuAssertIntEquals(tc, -8, skilldiff(ta, td, 0)); + CuAssertIntEquals(tc, -2, skilldiff(ta, td, 0)); create_curse(NULL, &ud->building->attribs, strongwall_ct, 1, 1, 2, 1); - CuAssertIntEquals(tc, -10, skilldiff(ta, td, 0)); + CuAssertIntEquals(tc, -4, skilldiff(ta, td, 0)); free_battle(b); test_cleanup(); diff --git a/src/kernel/build.h b/src/kernel/build.h index 38fefb88a..7780a6cd2 100644 --- a/src/kernel/build.h +++ b/src/kernel/build.h @@ -45,9 +45,6 @@ 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 06078aaba..3c21f4dbe 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -337,40 +337,24 @@ const building_type *findbuildingtype(const char *name, int cmp_castle_size(const building * b, const building * a) { - if (!b || !b->type->protection || !building_owner(b)) { + if (!b || !(b->type->flags & BTF_FORTIFICATION) || !building_owner(b)) { return -1; } - if (!a || !a->type->protection || !building_owner(a)) { + if (!a || !(a->type->flags & BTF_FORTIFICATION) || !building_owner(a)) { return 1; } return b->size - a->size; } -int building_protection(const building * b, const unit * u, building_bonus bonus) +static const int castle_bonus[6] = { 0, 1, 3, 5, 8, 12 }; +static const int watch_bonus[3] = { 0, 1, 2 }; + +int building_protection(const building_type * btype, int stage) { - 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; + if (btype->maxsize < 0) { + return castle_bonus[MIN(stage, 5)]; } + return watch_bonus[MIN(stage, 2)]; } void write_building_reference(const struct building *b, struct storage *store) @@ -925,8 +909,6 @@ int cmp_current_owner(const building * b, const building * a) void register_buildings(void) { register_function((pf_generic)minimum_wage, "minimum_wage"); - register_function((pf_generic)building_protection, - "building_protection"); register_function((pf_generic)init_smithy, "init_smithy"); register_function((pf_generic)castle_name, "castle_name"); register_function((pf_generic)castle_name_2, "castle_name_2"); diff --git a/src/kernel/building.h b/src/kernel/building.h index 1adce7e09..8c23fdb7c 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -51,13 +51,7 @@ extern "C" { #define BTF_MAGIC 0x40 /* magical effect */ #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 */ -#define BTF_FORTIFICATION 0x200 /* safe from monsters */ - - typedef enum { - DEFENSE_BONUS, - CLOSE_COMBAT_ATTACK_BONUS, /* TODO: only DEFENSE_BONUS is in use? */ - RANGED_ATTACK_BONUS - } building_bonus; +#define BTF_FORTIFICATION 0x200 /* building_protection, safe from monsters */ typedef struct building_type { char *_name; @@ -77,7 +71,6 @@ extern "C" { const struct building * b, int size); void(*init) (struct building_type *); void(*age) (struct building *); - int(*protection) (const struct building *, const struct unit *, building_bonus bonus); double(*taxes) (const struct building *, int size); struct attrib *attribs; } building_type; @@ -85,8 +78,8 @@ extern "C" { extern struct selist *buildingtypes; extern struct attrib_type at_building_action; - int cmp_castle_size(const struct building * b, const struct building * a); - int building_protection(const struct building * b, const struct unit * u, building_bonus bonus); + int cmp_castle_size(const struct building *b, const struct building *a); + int building_protection(const struct building_type *btype, int stage); building_type *bt_get_or_create(const char *name); bool bt_changed(int *cache); const building_type *bt_find(const char *name); diff --git a/src/kernel/building.test.c b/src/kernel/building.test.c index e02d16556..4395f1c40 100644 --- a/src/kernel/building.test.c +++ b/src/kernel/building.test.c @@ -376,7 +376,6 @@ static void test_btype_defaults(CuTest *tc) { CuAssertTrue(tc, !btype->name); CuAssertTrue(tc, !btype->init); CuAssertTrue(tc, !btype->age); - CuAssertTrue(tc, !btype->protection); CuAssertTrue(tc, !btype->taxes); CuAssertDblEquals(tc, 1.0, btype->auraregen, 0.0); CuAssertIntEquals(tc, -1, btype->maxsize); diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 695f91d69..555c0f679 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -167,9 +167,6 @@ 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) { @@ -301,9 +298,6 @@ static int parse_buildings(xmlDocPtr doc) else if (strcmp((const char *)propValue, "age") == 0) { btype->age = (void(*)(struct building *))fun; } - else if (strcmp((const char *)propValue, "protection") == 0) { - btype->protection = (int(*)(const struct building *, const struct unit *, building_bonus))fun; - } else if (strcmp((const char *)propValue, "taxes") == 0) { btype->taxes = (double(*)(const struct building *, int))fun; } diff --git a/src/tests.c b/src/tests.c index 6a43e6e79..c448a27ae 100644 --- a/src/tests.c +++ b/src/tests.c @@ -230,7 +230,7 @@ building * test_create_building(region * r, const building_type * btype) assert(r); if (!btype) { building_type *bt_castle = test_create_buildingtype("castle"); - bt_castle->protection = building_protection; + bt_castle->flags |= BTF_FORTIFICATION; btype = bt_castle; } b = new_building(btype, r, default_locale); From 82e4d754292478e82af1202524d7ba04293f0fe9 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 22 Feb 2017 19:43:17 +0100 Subject: [PATCH 03/23] unused function --- src/battle.test.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/battle.test.c b/src/battle.test.c index 987613277..109561161 100644 --- a/src/battle.test.c +++ b/src/battle.test.c @@ -60,10 +60,6 @@ static void test_make_fighter(CuTest * tc) test_cleanup(); } -static int add_two(const building * b, const unit * u) { - return 2; -} - static building_type * setup_castle(void) { building_type * btype; construction *cons; From 67831ad7083fb4af108a373a3ae3e18a38c418ea Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 22 Feb 2017 20:16:51 +0100 Subject: [PATCH 04/23] we like test_setup. --- src/battle.test.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/battle.test.c b/src/battle.test.c index 109561161..d15c335a9 100644 --- a/src/battle.test.c +++ b/src/battle.test.c @@ -26,7 +26,7 @@ static void test_make_fighter(CuTest * tc) faction * f; const resource_type *rtype; - test_cleanup(); + test_setup(); test_create_horse(); r = test_create_region(0, 0, 0); f = test_create_faction(NULL); @@ -84,7 +84,7 @@ static void test_defenders_get_building_bonus(CuTest * tc) troop dt, at; building_type * btype; - test_cleanup(); + test_setup(); btype = setup_castle(); r = test_create_region(0, 0, 0); bld = test_create_building(r, btype); @@ -129,7 +129,7 @@ static void test_attackers_get_no_building_bonus(CuTest * tc) side *as; building_type * btype; - test_cleanup(); + test_setup(); r = test_create_region(0, 0, 0); btype = setup_castle(); btype->flags |= BTF_FORTIFICATION; @@ -159,7 +159,7 @@ static void test_building_bonus_respects_size(CuTest * tc) building_type * btype; faction * f; - test_cleanup(); + test_setup(); btype = setup_castle(); r = test_create_region(0, 0, 0); btype->flags |= BTF_FORTIFICATION; @@ -189,7 +189,7 @@ static void test_building_defence_bonus(CuTest * tc) { building_type * btype; - test_cleanup(); + test_setup(); btype = setup_castle(); btype->maxsize = -1; /* unlimited buildigs get the castle bonus */ @@ -225,7 +225,7 @@ static void test_natural_armor(CuTest * tc) race *rc; unit *u; - test_cleanup(); + test_setup(); rc = test_create_race("human"); u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0)); set_level(u, SK_STAMINA, 2); @@ -252,7 +252,7 @@ static void test_calculate_armor(CuTest * tc) race *rc; double magres = 0.0; - test_cleanup(); + test_setup(); r = test_create_region(0, 0, 0); ibelt = it_get_or_create(rt_get_or_create("trollbelt")); ishield = it_get_or_create(rt_get_or_create("shield")); @@ -321,7 +321,7 @@ static void test_magic_resistance(CuTest *tc) race *rc; double magres; - test_cleanup(); + test_setup(); r = test_create_region(0, 0, 0); ishield = it_get_or_create(rt_get_or_create("shield")); ashield = new_armortype(ishield, 0.0, 0.5, 1, ATF_SHIELD); @@ -386,7 +386,7 @@ static void test_projectile_armor(CuTest * tc) item_type *ishield, *ichain; race *rc; - test_cleanup(); + test_setup(); r = test_create_region(0, 0, 0); ishield = it_get_or_create(rt_get_or_create("shield")); ashield = new_armortype(ishield, 0.0, 0.5, 1, ATF_SHIELD); @@ -420,7 +420,7 @@ static void test_battle_skilldiff(CuTest *tc) unit *ua, *ud; battle *b = NULL; - test_cleanup(); + test_setup(); r = test_create_region(0, 0, 0); ud = test_create_unit(test_create_faction(0), r); @@ -456,7 +456,7 @@ static void test_battle_skilldiff_building(CuTest *tc) building_type *btype; const curse_type *strongwall_ct, *magicwalls_ct; - test_cleanup(); + test_setup(); btype = setup_castle(); strongwall_ct = ct_find("strongwall"); magicwalls_ct = ct_find("magicwalls"); From ce2ea95880aef67ff52c1dd773f8b5bcbd41b576 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 22 Feb 2017 20:28:34 +0100 Subject: [PATCH 05/23] begin refactoring limited resources. --- src/economy.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/economy.c b/src/economy.c index 94a1a90fa..f98d0f8e1 100644 --- a/src/economy.c +++ b/src/economy.c @@ -914,6 +914,11 @@ struct message * get_modifiers(unit *u, const resource_mod *mod, variant *savep, return NULL; } +static resource_limit *get_resourcelimit(const resource_type *rtype) { + attrib *a = a_find(rtype->attribs, &at_resourcelimit); + return a ? (resource_limit *)a->data.v : NULL; +} + static void allocate_resource(unit * u, const resource_type * rtype, int want) { const item_type *itype = resource2item(rtype); @@ -921,8 +926,7 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) int dm = 0; allocation_list *alist; allocation *al; - attrib *a = a_find(rtype->attribs, &at_resourcelimit); - resource_limit *rdata = (resource_limit *)a->data.v; + resource_limit *rdata = get_resourcelimit(rtype); const resource_type *rring; int amount, skill, skill_mod = 0; variant save_mod; @@ -1119,8 +1123,7 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist) { allocation *al; int nreq = 0; - attrib *a = a_find(rtype->attribs, &at_resourcelimit); - resource_limit *rdata = (resource_limit *)a->data.v; + resource_limit *rdata = get_resourcelimit(rtype); int avail = rdata->value; for (al = alist; al; al = al->next) { @@ -1160,10 +1163,9 @@ typedef void(*allocate_function) (const resource_type *, struct region *, static allocate_function get_allocator(const struct resource_type *rtype) { - attrib *a = a_find(rtype->attribs, &at_resourcelimit); + resource_limit *rdata = get_resourcelimit(rtype); - if (a != NULL) { - resource_limit *rdata = (resource_limit *)a->data.v; + if (rdata) { if (rdata->value > 0 || rdata->limit != NULL) { return attrib_allocation; } From 1498f2e1d772a5c4c51ce96348e1c5d07611aac8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 22 Feb 2017 21:10:22 +0100 Subject: [PATCH 06/23] refactor rawmaterial_type. still have to decide if we need it at all. --- src/economy.c | 3 +-- src/economy.test.c | 7 +++---- src/items/seed.c | 12 ++++-------- src/kernel/item.c | 16 ---------------- src/kernel/item.h | 24 +++++------------------- src/kernel/resources.c | 12 ++++++------ src/kernel/resources.h | 24 +++++++++++++++++++++++- src/kernel/xmlreader.c | 19 +++++++------------ 8 files changed, 49 insertions(+), 68 deletions(-) diff --git a/src/economy.c b/src/economy.c index f98d0f8e1..f0a693eca 100644 --- a/src/economy.c +++ b/src/economy.c @@ -915,8 +915,7 @@ struct message * get_modifiers(unit *u, const resource_mod *mod, variant *savep, } static resource_limit *get_resourcelimit(const resource_type *rtype) { - attrib *a = a_find(rtype->attribs, &at_resourcelimit); - return a ? (resource_limit *)a->data.v : NULL; + return rtype->limit; } static void allocate_resource(unit * u, const resource_type * rtype, int want) diff --git a/src/economy.test.c b/src/economy.test.c index 766fb4302..c67237c40 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -348,7 +348,7 @@ static void test_make_item(CuTest *tc) { struct item_type *itype; const struct resource_type *rt_silver; resource_type *rtype; - attrib *a; + rawmaterial_type *rmt; resource_limit *rdata; double d = 0.6; @@ -382,10 +382,9 @@ static void test_make_item(CuTest *tc) { free(itype->construction->materials); itype->construction->materials = 0; rtype->flags |= RTF_LIMITED; - a = a_add(&rtype->attribs, a_new(&at_resourcelimit)); - rdata = (resource_limit *)a->data.v; + rmt = rmt_create(rtype, "rm_stone"); + rdata = rtype->limit = calloc(1, sizeof(resource_limit)); rdata->value = 0; - rmt_create(rtype, "stone"); add_resource(u->region, 1, 300, 150, rtype); u->region->resources->amount = 300; /* there are 300 stones at level 1 */ set_level(u, SK_ALCHEMY, 10); diff --git a/src/items/seed.c b/src/items/seed.c index f17e8ed29..334c6a05d 100644 --- a/src/items/seed.c +++ b/src/items/seed.c @@ -24,6 +24,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include /* util includes */ #include @@ -31,6 +32,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* libc includes */ #include +#include static void produce_seeds(region * r, const resource_type * rtype, int norders) { @@ -48,14 +50,11 @@ static int limit_seeds(const region * r, const resource_type * rtype) void init_seed(void) { - attrib *a; - resource_limit *rdata; resource_type *rtype; rtype = rt_find("seed"); if (rtype != NULL) { - a = a_add(&rtype->attribs, a_new(&at_resourcelimit)); - rdata = (resource_limit *)a->data.v; + resource_limit *rdata = rtype->limit = calloc(1, sizeof(resource_limit)); rdata->limit = limit_seeds; rdata->produce = produce_seeds; } @@ -80,17 +79,14 @@ static int limit_mallornseeds(const region * r, const resource_type * rtype) void init_mallornseed(void) { - attrib *a; - resource_limit *rdata; resource_type *rtype; rtype = rt_find("mallornseed"); if (rtype != NULL) { + resource_limit *rdata = rtype->limit = calloc(1, sizeof(resource_limit)); rtype->flags |= RTF_LIMITED; rtype->flags |= RTF_POOLED; - a = a_add(&rtype->attribs, a_new(&at_resourcelimit)); - rdata = (resource_limit *)a->data.v; rdata->limit = limit_mallornseeds; rdata->produce = produce_mallornseeds; } diff --git a/src/kernel/item.c b/src/kernel/item.c index c37e3d40c..5beac7189 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -1159,22 +1159,6 @@ const item_type *finditemtype(const char *name, const struct locale *lang) return 0; } -static void init_resourcelimit(attrib * a) -{ - a->data.v = calloc(sizeof(resource_limit), 1); -} - -static void finalize_resourcelimit(attrib * a) -{ - free(a->data.v); -} - -attrib_type at_resourcelimit = { - "resourcelimit", - init_resourcelimit, - finalize_resourcelimit, -}; - item *item_spoil(const struct race *rc, int size) { item *itm = NULL; diff --git a/src/kernel/item.h b/src/kernel/item.h index 79e6f103d..1d3e5ff29 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -29,6 +29,7 @@ extern "C" { struct unit; struct attrib; struct attrib_type; + struct race; struct region; struct resource_type; struct locale; @@ -37,6 +38,8 @@ extern "C" { struct order; struct storage; struct gamedata; + struct rawmaterial_type; + struct resource_limit; typedef struct item { struct item *next; @@ -76,6 +79,8 @@ extern "C" { rtype_uchange uchange; rtype_uget uget; rtype_name name; + struct rawmaterial_type *raw; + struct resource_limit *limit; /* --- pointers --- */ struct attrib *attribs; struct item_type *itype; @@ -94,25 +99,6 @@ extern "C" { #define RMF_SAVEMATERIAL 0x02 /* fraction (sa[0]/sa[1]), multiplier on resource usage */ #define RMF_REQUIREDBUILDING 0x04 /* building, required to build */ - typedef struct resource_mod { - variant value; - const struct building_type *btype; - const struct race *race; - unsigned int flags; - } resource_mod; - - extern struct attrib_type at_resourcelimit; - typedef int(*rlimit_limit) (const struct region * r, - const struct resource_type * rtype); - typedef void(*rlimit_produce) (struct region * r, - const struct resource_type * rtype, int n); - typedef struct resource_limit { - rlimit_limit limit; - rlimit_produce produce; - int value; - resource_mod *modifiers; - } resource_limit; - /* bitfield values for item_type::flags */ #define ITF_NONE 0x0000 #define ITF_HERB 0x0001 /* this item is a herb */ diff --git a/src/kernel/resources.c b/src/kernel/resources.c index e32c7ad55..d02153e8f 100644 --- a/src/kernel/resources.c +++ b/src/kernel/resources.c @@ -195,16 +195,16 @@ struct rawmaterial_type *rmt_find(const char *str) struct rawmaterial_type *rmt_get(const struct resource_type *rtype) { - rawmaterial_type *rmt = rawmaterialtypes; - while (rmt && rmt->rtype != rtype) - rmt = rmt->next; - return rmt; + return rtype->raw; } -struct rawmaterial_type *rmt_create(const struct resource_type *rtype, +struct rawmaterial_type *rmt_create(struct resource_type *rtype, const char *name) { - rawmaterial_type *rmtype = malloc(sizeof(rawmaterial_type)); + rawmaterial_type *rmtype; + + assert(!rtype->raw); + rmtype = rtype->raw = malloc(sizeof(rawmaterial_type)); rmtype->name = strdup(name); rmtype->rtype = rtype; rmtype->terraform = terraform_default; diff --git a/src/kernel/resources.h b/src/kernel/resources.h index a1a7abd40..dd4cfd664 100644 --- a/src/kernel/resources.h +++ b/src/kernel/resources.h @@ -15,6 +15,9 @@ extern "C" { #endif + struct building_type; + struct race; + enum { RM_USED = 1 << 0, /* resource has been used */ RM_MALLORN = 1 << 1 /* this is not wood. it's mallorn */ @@ -40,6 +43,25 @@ extern "C" { struct rawmaterial *next; } rawmaterial; + typedef int(*rlimit_limit) (const struct region * r, + const struct resource_type * rtype); + typedef void(*rlimit_produce) (struct region * r, + const struct resource_type * rtype, int n); + + typedef struct resource_mod { + variant value; + const struct building_type *btype; + const struct race *race; + unsigned int flags; + } resource_mod; + + typedef struct resource_limit { + rlimit_limit limit; + rlimit_produce produce; + int value; + resource_mod *modifiers; + } resource_limit; + typedef struct rawmaterial_type { char *name; const struct resource_type *rtype; @@ -64,7 +86,7 @@ extern "C" { void add_resource(struct region *r, int level, int base, int divisor, const struct resource_type *rtype); - struct rawmaterial_type *rmt_create(const struct resource_type *rtype, + struct rawmaterial_type *rmt_create(struct resource_type *rtype, const char *name); #ifdef __cplusplus diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 555c0f679..2d08f40a4 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -949,12 +949,6 @@ static int parse_resources(xmlDocPtr doc) rtype->flags |= flags; xmlFree(name); - name = xmlGetProp(node, BAD_CAST "material"); - if (name) { - rmt_create(rtype, (const char *)name); - xmlFree(name); - } - /* reading eressea/resources/resource/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); @@ -987,18 +981,20 @@ static int parse_resources(xmlDocPtr doc) } xmlXPathFreeObject(result); + name = xmlGetProp(node, BAD_CAST "material"); + if (name) { + rmt_create(rtype, (const char *)name); + xmlFree(name); + } + /* reading eressea/resources/resource/resourcelimit */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "resourcelimit", xpath); assert(result->nodesetval->nodeNr <= 1); if (result->nodesetval->nodeNr != 0) { - resource_limit *rdata; - attrib *a = a_find(rtype->attribs, &at_resourcelimit); + resource_limit *rdata = rtype->limit = calloc(1, sizeof(resource_limit)); xmlNodePtr limit = result->nodesetval->nodeTab[0]; - if (a == NULL) - a = a_add(&rtype->attribs, a_new(&at_resourcelimit)); - rdata = (resource_limit *)a->data.v; rtype->flags |= RTF_LIMITED; xpath->node = limit; xmlXPathFreeObject(result); @@ -1095,7 +1091,6 @@ static int parse_resources(xmlDocPtr doc) } } xmlXPathFreeObject(result); - /* reading eressea/resources/resource/resourcelimit/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "resourcelimit/function", xpath); From f4dc88c3be008c9a4c3517c93d6284697789664d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 23 Feb 2017 07:53:28 +0100 Subject: [PATCH 07/23] strip rawmaterial_type to just the funpointers --- src/kernel/item.c | 3 +++ src/kernel/resources.c | 14 +++++--------- src/kernel/resources.h | 4 ---- src/kernel/save.c | 2 +- src/reports.c | 12 ++++++------ 5 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/kernel/item.c b/src/kernel/item.c index 5beac7189..9bc321fdb 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -1242,6 +1242,9 @@ void free_rtype(resource_type *rtype) { if (rtype->itype) { free_itype(rtype->itype); } + if (rtype->raw) { + free(rtype->raw); + } free(rtype->_name); free(rtype); } diff --git a/src/kernel/resources.c b/src/kernel/resources.c index d02153e8f..1261417f1 100644 --- a/src/kernel/resources.c +++ b/src/kernel/resources.c @@ -183,14 +183,13 @@ struct rawmaterial *rm_get(region * r, const struct resource_type *rtype) return rm; } -struct rawmaterial_type *rawmaterialtypes = 0; - struct rawmaterial_type *rmt_find(const char *str) { - rawmaterial_type *rmt = rawmaterialtypes; - while (rmt && strcmp(rmt->name, str) != 0) - rmt = rmt->next; - return rmt; + resource_type *rtype = rt_find(str); + if (!rtype && strncmp(str, "rm_", 3) == 0) { + rtype = rt_find(str+3); + } + return rtype ? rtype->raw : NULL; } struct rawmaterial_type *rmt_get(const struct resource_type *rtype) @@ -205,13 +204,10 @@ struct rawmaterial_type *rmt_create(struct resource_type *rtype, assert(!rtype->raw); rmtype = rtype->raw = malloc(sizeof(rawmaterial_type)); - rmtype->name = strdup(name); rmtype->rtype = rtype; rmtype->terraform = terraform_default; rmtype->update = NULL; rmtype->use = use_default; rmtype->visible = visible_default; - rmtype->next = rawmaterialtypes; - rawmaterialtypes = rmtype; return rmtype; } diff --git a/src/kernel/resources.h b/src/kernel/resources.h index dd4cfd664..9d248c0f8 100644 --- a/src/kernel/resources.h +++ b/src/kernel/resources.h @@ -63,16 +63,12 @@ extern "C" { } resource_limit; typedef struct rawmaterial_type { - char *name; const struct resource_type *rtype; void(*terraform) (struct rawmaterial *, const struct region *); void(*update) (struct rawmaterial *, const struct region *); void(*use) (struct rawmaterial *, const struct region *, int amount); int(*visible) (const struct rawmaterial *, int skilllevel); - - /* no initialization required */ - struct rawmaterial_type *next; } rawmaterial_type; extern struct rawmaterial_type *rawmaterialtypes; diff --git a/src/kernel/save.c b/src/kernel/save.c index d4045d05f..21ec98e76 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1068,7 +1068,7 @@ void writeregion(struct gamedata *data, const region * r) WRITE_INT(data->store, rhorses(r)); while (res) { - WRITE_TOK(data->store, res->type->name); + WRITE_TOK(data->store, res->type->rtype->_name); WRITE_INT(data->store, res->level); WRITE_INT(data->store, res->amount); WRITE_INT(data->store, res->startlevel); diff --git a/src/reports.c b/src/reports.c index a49957b9d..a70219b0b 100644 --- a/src/reports.c +++ b/src/reports.c @@ -412,32 +412,32 @@ const faction * viewer, bool see_unit) if (money) { if (n >= size) return -1; - report_resource(result + n, "rm_money", money, -1); + report_resource(result + n, "money", money, -1); ++n; } if (peasants) { if (n >= size) return -1; - report_resource(result + n, "rm_peasant", peasants, -1); + report_resource(result + n, "peasant", peasants, -1); ++n; } if (horses) { if (n >= size) return -1; - report_resource(result + n, "rm_horse", horses, -1); + report_resource(result + n, "horse", horses, -1); ++n; } if (saplings) { if (n >= size) return -1; - report_resource(result + n, mallorn ? "rm_mallornsapling" : "rm_sapling", + report_resource(result + n, mallorn ? "mallornsapling" : "sapling", saplings, -1); ++n; } if (trees) { if (n >= size) return -1; - report_resource(result + n, mallorn ? "rm_mallorn" : "rm_tree", trees, + report_resource(result + n, mallorn ? "mallorn" : "tree", trees, -1); ++n; } @@ -469,7 +469,7 @@ const faction * viewer, bool see_unit) if (level >= 0 && visible >= 0) { if (n >= size) return -1; - report_resource(result + n, res->type->name, visible, level); + report_resource(result + n, res->type->rtype->_name, visible, level); n++; } res = res->next; From be42137833d87889df5f157720df80432ba5746d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 23 Feb 2017 08:02:24 +0100 Subject: [PATCH 08/23] fix rmt_find for trees --- src/economy.test.c | 2 +- src/kernel/resources.c | 16 +++++++++++++--- src/kernel/resources.h | 3 +-- src/kernel/xmlreader.c | 2 +- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/economy.test.c b/src/economy.test.c index c67237c40..2de6265f0 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -382,7 +382,7 @@ static void test_make_item(CuTest *tc) { free(itype->construction->materials); itype->construction->materials = 0; rtype->flags |= RTF_LIMITED; - rmt = rmt_create(rtype, "rm_stone"); + rmt = rmt_create(rtype); rdata = rtype->limit = calloc(1, sizeof(resource_limit)); rdata->value = 0; add_resource(u->region, 1, 300, 150, rtype); diff --git a/src/kernel/resources.c b/src/kernel/resources.c index 1261417f1..e8be234a1 100644 --- a/src/kernel/resources.c +++ b/src/kernel/resources.c @@ -185,10 +185,21 @@ struct rawmaterial *rm_get(region * r, const struct resource_type *rtype) struct rawmaterial_type *rmt_find(const char *str) { + const char * replace[] = { "rm_tree", "log", NULL }; resource_type *rtype = rt_find(str); if (!rtype && strncmp(str, "rm_", 3) == 0) { - rtype = rt_find(str+3); + int i; + for (i = 0; replace[i]; i+=2) { + if (strcmp(replace[i], str) == 0) { + rtype = rt_find(replace[i+1]); + break; + } + } + if (!rtype) { + rtype = rt_find(str+3); + } } + assert(rtype); return rtype ? rtype->raw : NULL; } @@ -197,8 +208,7 @@ struct rawmaterial_type *rmt_get(const struct resource_type *rtype) return rtype->raw; } -struct rawmaterial_type *rmt_create(struct resource_type *rtype, - const char *name) +struct rawmaterial_type *rmt_create(struct resource_type *rtype) { rawmaterial_type *rmtype; diff --git a/src/kernel/resources.h b/src/kernel/resources.h index 9d248c0f8..3e93ea1de 100644 --- a/src/kernel/resources.h +++ b/src/kernel/resources.h @@ -82,8 +82,7 @@ extern "C" { void add_resource(struct region *r, int level, int base, int divisor, const struct resource_type *rtype); - struct rawmaterial_type *rmt_create(struct resource_type *rtype, - const char *name); + struct rawmaterial_type *rmt_create(struct resource_type *rtype); #ifdef __cplusplus } diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 2d08f40a4..9ba05e101 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -983,7 +983,7 @@ static int parse_resources(xmlDocPtr doc) name = xmlGetProp(node, BAD_CAST "material"); if (name) { - rmt_create(rtype, (const char *)name); + rmt_create(rtype); xmlFree(name); } From 9cbd5b88e6bf64f1f451a3e831bcb851181bfdc2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 23 Feb 2017 08:07:47 +0100 Subject: [PATCH 09/23] rm_tree is not actually a thing --- src/kernel/resources.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/kernel/resources.c b/src/kernel/resources.c index e8be234a1..ae93d542a 100644 --- a/src/kernel/resources.c +++ b/src/kernel/resources.c @@ -185,19 +185,9 @@ struct rawmaterial *rm_get(region * r, const struct resource_type *rtype) struct rawmaterial_type *rmt_find(const char *str) { - const char * replace[] = { "rm_tree", "log", NULL }; resource_type *rtype = rt_find(str); if (!rtype && strncmp(str, "rm_", 3) == 0) { - int i; - for (i = 0; replace[i]; i+=2) { - if (strcmp(replace[i], str) == 0) { - rtype = rt_find(replace[i+1]); - break; - } - } - if (!rtype) { - rtype = rt_find(str+3); - } + rtype = rt_find(str+3); } assert(rtype); return rtype ? rtype->raw : NULL; From 5e2903258c64ce4b12ce0db3b5ca8f142ef91124 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 23 Feb 2017 14:45:19 +0100 Subject: [PATCH 10/23] kill old element from XML --- res/adamantium.xml | 1 - res/core/resources/mallorn.xml | 1 - res/e3a/resources/iron.xml | 1 - 3 files changed, 3 deletions(-) diff --git a/res/adamantium.xml b/res/adamantium.xml index cc1cedadc..decc5636c 100644 --- a/res/adamantium.xml +++ b/res/adamantium.xml @@ -7,7 +7,6 @@ - diff --git a/res/core/resources/mallorn.xml b/res/core/resources/mallorn.xml index 2d301758e..fc678e79e 100644 --- a/res/core/resources/mallorn.xml +++ b/res/core/resources/mallorn.xml @@ -6,7 +6,6 @@ - diff --git a/res/e3a/resources/iron.xml b/res/e3a/resources/iron.xml index b245da358..06b70e45a 100644 --- a/res/e3a/resources/iron.xml +++ b/res/e3a/resources/iron.xml @@ -6,6 +6,5 @@ - From f06d86007c35780f1164405435b7320416fe32e1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 23 Feb 2017 22:08:16 +0100 Subject: [PATCH 11/23] seed normalization (broken) --- res/core/resources/mallornseed.xml | 4 ++ res/core/resources/seed.xml | 4 ++ res/e3a/resources/seed.xml | 8 ++- scripts/eressea/resources.lua | 46 +++++++++++++-- scripts/tests/common.lua | 62 ++++++++++++-------- src/eressea.c | 9 ++- src/gmtool.c | 1 - src/items/CMakeLists.txt | 2 - src/items/itemtypes.c | 33 ----------- src/items/itemtypes.h | 25 -------- src/items/seed.c | 93 ------------------------------ src/items/seed.h | 31 ---------- src/kernel/xmlreader.c | 4 +- 13 files changed, 102 insertions(+), 220 deletions(-) delete mode 100644 src/items/itemtypes.c delete mode 100644 src/items/itemtypes.h delete mode 100644 src/items/seed.c delete mode 100644 src/items/seed.h diff --git a/res/core/resources/mallornseed.xml b/res/core/resources/mallornseed.xml index 7a5a0310f..01b8a3416 100644 --- a/res/core/resources/mallornseed.xml +++ b/res/core/resources/mallornseed.xml @@ -3,4 +3,8 @@ + + + + diff --git a/res/core/resources/seed.xml b/res/core/resources/seed.xml index 99f5f5804..2bda26eeb 100644 --- a/res/core/resources/seed.xml +++ b/res/core/resources/seed.xml @@ -3,4 +3,8 @@ + + + + diff --git a/res/e3a/resources/seed.xml b/res/e3a/resources/seed.xml index 21652f364..2bda26eeb 100644 --- a/res/e3a/resources/seed.xml +++ b/res/e3a/resources/seed.xml @@ -1,4 +1,10 @@ - + + + + + + + diff --git a/scripts/eressea/resources.lua b/scripts/eressea/resources.lua index 94908c1ab..2829d00c7 100644 --- a/scripts/eressea/resources.lua +++ b/scripts/eressea/resources.lua @@ -38,8 +38,47 @@ function hp_changeresource(u, delta) return hp end +local function mallorn_region(r) + return r:get_flag(1) -- RF_MALLORN +end + +function seed_limit(r) + if mallorn_region(r) then + return 0 + end + return r:get_resource("seed") +end + +function seed_produce(r, n) + if not mallorn_region(r) then + local seeds = r:get_resource("seed") + if seeds>=n then + r:set_resource("seed", seeds-n) + else + r:set_resource("seed", 0) + end + end +end + +function mallornseed_limit(r) + if mallorn_region(r) then + return r:get_resource("seed") + end + return 0 +end + +function mallornseed_produce(r, n) + if mallorn_region(r) then + local seeds = r:get_resource("seed") + if seeds>=n then + r:set_resource("seed", seeds-n) + else + r:set_resource("seed", 0) + end + end +end function horse_limit(r) - return r:get_resource("horse") + return r:get_resource("horse") end function horse_produce(r, n) @@ -52,9 +91,6 @@ function horse_produce(r, n) end function log_limit(r) --- if r:get_flag(1) then -- RF_MALLORN --- return 0 --- end return r:get_resource("tree") + r:get_resource("sapling") end @@ -75,7 +111,7 @@ function log_produce(r, n) end function mallorn_limit(r) - if not r:get_flag(1) then -- RF_MALLORN + if not mallorn_region(r) then return 0 end return r:get_resource("tree") + r:get_resource("sapling") diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 96673bfd3..27177d1b6 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -438,10 +438,9 @@ function test_recruit() u:add_item("money", 110*n+20) u:add_order("REKRUTIERE " .. n) process_orders() - assert(u.number == n+1) + assert_equal(n+1, u.number) local p = r:get_resource("peasant") - assert(p<200 and p>=200-n) - -- assert(u:get_item("money")==10) + assert_true(p<200 and p>=200-n) end function test_produce() @@ -468,7 +467,7 @@ function test_work() u:clear_orders() u:add_order("ARBEITEN") process_orders() - assert(u:get_item("money")>=10) + assert_equal(20, u:get_item("money")) end function test_upkeep() @@ -480,7 +479,7 @@ function test_upkeep() u:clear_orders() u:add_order("LERNE Waffenbau") process_orders() - assert(u:get_item("money")==u.number) + assert_equal(u:get_item("money"), u.number) end function test_id() @@ -488,50 +487,63 @@ function test_id() local f = faction.create("noreply11@eressea.de", "human", "de") f.id = atoi36("42") - assert(get_faction(42)~=f) - assert(get_faction("42")==f) - assert(get_faction(atoi36("42"))==f) + assert_not_equal(f, get_faction(42)) + assert_equal(f, get_faction("42")) + assert_equal(f, get_faction(atoi36("42"))) local u = unit.create(f, r, 1) u.id = atoi36("42") - assert(get_unit(42)~=u) - assert(get_unit("42")==u) - assert(get_unit(atoi36("42"))==u) + assert_not_equal(get_unit(42), u) + assert_equal(get_unit("42"), u) + assert_equal(get_unit(atoi36("42")), u) local b = building.create(r, "castle") -- b.id = atoi36("42") local fortytwo = itoa36(b.id) - assert(get_building(fortytwo)==b) - assert(get_building(atoi36(fortytwo))==b) + assert_equal(get_building(fortytwo), b) + assert_equal(get_building(atoi36(fortytwo)), b) local s = _test_create_ship(r) assert_not_nil(s) -- s.id = atoi36("42") local fortytwo = itoa36(s.id) - assert(get_ship(fortytwo)==s) - assert(get_ship(atoi36(fortytwo))==s) + assert_equal(get_ship(fortytwo), s) + assert_equal(get_ship(atoi36(fortytwo)), s) end function test_herbalism() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply12@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u:add_item("money", u.number * 100) - u:set_skill("herbalism", 5) - u:clear_orders() - u:add_order("MACHE Samen") - process_orders() + local r = region.create(0, 0, "plain") + local f = faction.create("herbalism@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + + eressea.settings.set("rules.grow.formula", 0) -- plants do not grow + u:add_item("money", u.number * 100) + u:set_skill("herbalism", 5) + + r:set_resource("seed", 100) + r:set_flag(1, false) -- regular trees + u:clear_orders() + u:add_order("MACHE Samen") + process_orders() + assert_equal(1, u:get_item("seed")) + assert_equal(99, r:get_resource("seed")) + r:set_flag(1, true) -- mallorn + u:clear_orders() + u:add_order("MACHE Mallornsamen") + process_orders() + assert_equal(1, u:get_item("mallornseed")) + assert_equal(98, r:get_resource("seed")) end function test_mallorn() local r = region.create(0, 0, "plain") r:set_flag(1, false) -- not mallorn r:set_resource("tree", 100) - assert(r:get_resource("tree")==100) + assert_equal(100, r:get_resource("tree")) local m = region.create(0, 0, "plain") m:set_flag(1, true) -- mallorn m:set_resource("tree", 100) - assert(m:get_resource("tree")==100) + assert_equal(100, m:get_resource("tree")) local f = faction.create("noreply13@eressea.de", "human", "de") diff --git a/src/eressea.c b/src/eressea.c index dead153cb..07ea132a8 100755 --- a/src/eressea.c +++ b/src/eressea.c @@ -21,7 +21,10 @@ #include #include #include -#include +#include +#include +#include + #include #include #include @@ -81,7 +84,9 @@ void game_init(void) #endif wormholes_register(); - register_itemtypes(); + register_weapons(); + register_xerewards(); + register_artrewards(); #ifdef USE_LIBXML2 register_xmlreader(); #endif diff --git a/src/gmtool.c b/src/gmtool.c index 5a0cd576c..3551c3436 100644 --- a/src/gmtool.c +++ b/src/gmtool.c @@ -47,7 +47,6 @@ #include #include -#include #include #include diff --git a/src/items/CMakeLists.txt b/src/items/CMakeLists.txt index 0a2c581b4..b2bf2dfe5 100644 --- a/src/items/CMakeLists.txt +++ b/src/items/CMakeLists.txt @@ -7,8 +7,6 @@ xerewards.test.c SET(_FILES artrewards.c demonseye.c -itemtypes.c -seed.c speedsail.c weapons.c xerewards.c diff --git a/src/items/itemtypes.c b/src/items/itemtypes.c deleted file mode 100644 index 930829668..000000000 --- a/src/items/itemtypes.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - */ - -#include -#include "itemtypes.h" - -#include "xerewards.h" -#include "artrewards.h" -#include "weapons.h" -#include "seed.h" - -void register_itemtypes(void) -{ - /* registering misc. functions */ - register_weapons(); - register_xerewards(); - register_artrewards(); -} - -void init_itemtypes(void) -{ - init_seed(); - init_mallornseed(); -} diff --git a/src/items/itemtypes.h b/src/items/itemtypes.h deleted file mode 100644 index ec705c55b..000000000 --- a/src/items/itemtypes.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - */ - -#ifndef H_ITM_ITEMS -#define H_ITM_ITEMS -#ifdef __cplusplus -extern "C" { -#endif - - extern void init_itemtypes(void); - extern void register_itemtypes(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/items/seed.c b/src/items/seed.c deleted file mode 100644 index 334c6a05d..000000000 --- a/src/items/seed.c +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright (c) 1998-2015, Enno Rehling -Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include - -#include "seed.h" - -/* kernel includes */ -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include -#include - -static void produce_seeds(region * r, const resource_type * rtype, int norders) -{ - assert(r->land && r->land->trees[0] >= norders); - r->land->trees[0] -= norders; -} - -static int limit_seeds(const region * r, const resource_type * rtype) -{ - if ((r->flags & RF_MALLORN)) { - return 0; - } - return r->land ? r->land->trees[0] : 0; -} - -void init_seed(void) -{ - resource_type *rtype; - - rtype = rt_find("seed"); - if (rtype != NULL) { - resource_limit *rdata = rtype->limit = calloc(1, sizeof(resource_limit)); - rdata->limit = limit_seeds; - rdata->produce = produce_seeds; - } -} - -/* mallorn */ - -static void -produce_mallornseeds(region * r, const resource_type * rtype, int norders) -{ - assert(r->flags & RF_MALLORN); - r->land->trees[0] -= norders; -} - -static int limit_mallornseeds(const region * r, const resource_type * rtype) -{ - if (!(r->flags & RF_MALLORN)) { - return 0; - } - return r->land ? r->land->trees[0] : 0; -} - -void init_mallornseed(void) -{ - resource_type *rtype; - - rtype = rt_find("mallornseed"); - if (rtype != NULL) { - resource_limit *rdata = rtype->limit = calloc(1, sizeof(resource_limit)); - rtype->flags |= RTF_LIMITED; - rtype->flags |= RTF_POOLED; - - rdata->limit = limit_mallornseeds; - rdata->produce = produce_mallornseeds; - } -} diff --git a/src/items/seed.h b/src/items/seed.h deleted file mode 100644 index c853adfde..000000000 --- a/src/items/seed.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright (c) 1998-2015, Enno Rehling -Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_SEED -#define H_ITM_SEED -#ifdef __cplusplus -extern "C" { -#endif - - extern void init_seed(void); - extern void init_mallornseed(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 9ba05e101..27adba598 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1061,7 +1061,7 @@ static int parse_resources(xmlDocPtr doc) /* reading eressea/resources/resource/resourcelimit/function */ result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - if (result->nodesetval != NULL) + if (result->nodesetval != NULL) { for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; pf_generic fun; @@ -1089,6 +1089,7 @@ static int parse_resources(xmlDocPtr doc) } xmlFree(propValue); } + } } xmlXPathFreeObject(result); /* reading eressea/resources/resource/resourcelimit/function */ @@ -1118,7 +1119,6 @@ static int parse_resources(xmlDocPtr doc) /* make sure old items (used in requirements) are available */ init_resources(); - init_itemtypes(); return 0; } From 6ce487e48511911e45dcb85c6354bfc894af9157 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 23 Feb 2017 22:19:48 +0100 Subject: [PATCH 12/23] MACHE Samen geht in E3 nicht. limited ist unnoetig --- res/e3a/resources/mallornseed.xml | 2 +- res/e3a/resources/seed.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/res/e3a/resources/mallornseed.xml b/res/e3a/resources/mallornseed.xml index 4a348c212..576035b34 100644 --- a/res/e3a/resources/mallornseed.xml +++ b/res/e3a/resources/mallornseed.xml @@ -1,4 +1,4 @@ - + diff --git a/res/e3a/resources/seed.xml b/res/e3a/resources/seed.xml index 21652f364..62c971540 100644 --- a/res/e3a/resources/seed.xml +++ b/res/e3a/resources/seed.xml @@ -1,4 +1,4 @@ - + From 794dae11cf73b272c76867bc82643778351c5c6f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 24 Feb 2017 14:29:14 +0100 Subject: [PATCH 13/23] remove artsculpture and genericbuilding. deal with buildings having an unknown type. --- res/core/common/buildings.xml | 3 +-- res/core/de/strings.xml | 2 +- res/core/en/strings.xml | 2 +- res/core/fr/strings.xml | 2 +- src/kernel/building.c | 9 +++++++-- src/kernel/save.c | 5 +++++ 6 files changed, 16 insertions(+), 7 deletions(-) diff --git a/res/core/common/buildings.xml b/res/core/common/buildings.xml index cf183086b..17f779843 100644 --- a/res/core/common/buildings.xml +++ b/res/core/common/buildings.xml @@ -4,9 +4,8 @@ - + - diff --git a/res/core/de/strings.xml b/res/core/de/strings.xml index 97ded6e8d..002727630 100644 --- a/res/core/de/strings.xml +++ b/res/core/de/strings.xml @@ -912,7 +912,7 @@ Traumschlößchen - + Struktur diff --git a/res/core/en/strings.xml b/res/core/en/strings.xml index d80c742b9..063194c5d 100644 --- a/res/core/en/strings.xml +++ b/res/core/en/strings.xml @@ -310,7 +310,7 @@ dam - + structure diff --git a/res/core/fr/strings.xml b/res/core/fr/strings.xml index 7eb091570..c69bb5b75 100644 --- a/res/core/fr/strings.xml +++ b/res/core/fr/strings.xml @@ -324,7 +324,7 @@ barrage - + bâtiment diff --git a/src/kernel/building.c b/src/kernel/building.c index 3c21f4dbe..6d0db8f43 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -325,8 +325,13 @@ const building_type *findbuildingtype(const char *name, building_type *btype = (building_type *)selist_get(ql, qi); const char *n = LOC(lang, btype->_name); - type.v = (void *)btype; - addtoken((struct tnode **)&bn->names, n, type); + if (!n) { + log_error("building type %s has no translation in %s", + btype->_name, locale_name(lang)); + } else { + type.v = (void *)btype; + addtoken((struct tnode **)&bn->names, n, type); + } } bnames = bn; } diff --git a/src/kernel/save.c b/src/kernel/save.c index 21ec98e76..8316121f3 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1529,6 +1529,11 @@ struct building *read_building(gamedata *data) { READ_INT(store, &b->size); READ_STR(store, name, sizeof(name)); b->type = bt_find(name); + if (!b->type) { + log_error("building %d has unknown type %s", b->no, name); + b->type = bt_find("building"); + assert(b->type); + } read_attribs(data, &b->attribs, b); /* repairs, bug 2221: */ From 2d4b61afa90c938468c730e017eff7bbc5393ead Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 24 Feb 2017 14:32:18 +0100 Subject: [PATCH 14/23] the artacademy was E2-only --- res/core/common/buildings.xml | 1 - res/core/de/strings.xml | 8 -------- res/eressea/buildings.xml | 1 + res/eressea/strings.xml | 8 ++++++++ 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/res/core/common/buildings.xml b/res/core/common/buildings.xml index 17f779843..540e9f085 100644 --- a/res/core/common/buildings.xml +++ b/res/core/common/buildings.xml @@ -5,7 +5,6 @@ - diff --git a/res/core/de/strings.xml b/res/core/de/strings.xml index 002727630..5bde79c29 100644 --- a/res/core/de/strings.xml +++ b/res/core/de/strings.xml @@ -915,14 +915,6 @@ Struktur - - Akademie der Künste - academy of arts - - - Skulptur - sculpture - diff --git a/res/eressea/buildings.xml b/res/eressea/buildings.xml index 64d65cff0..670ab484e 100644 --- a/res/eressea/buildings.xml +++ b/res/eressea/buildings.xml @@ -4,4 +4,5 @@ + diff --git a/res/eressea/strings.xml b/res/eressea/strings.xml index 61a35ebe5..28547679d 100644 --- a/res/eressea/strings.xml +++ b/res/eressea/strings.xml @@ -352,6 +352,14 @@ + + Akademie der Künste + academy of arts + + + Skulptur + sculpture + Horn des Tanzes horn of dancing From 25d3aacffaf6b19b1352b037f31ba45df31f78dc Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 24 Feb 2017 14:38:08 +0100 Subject: [PATCH 15/23] remove artrewards, they predate my backups --- res/eressea/artrewards.xml | 14 ---- res/eressea/items.xml | 13 ---- res/eressea/strings.xml | 36 --------- res/items.xml | 3 - src/eressea.c | 2 - src/items/CMakeLists.txt | 1 - src/items/artrewards.c | 155 ------------------------------------- src/items/artrewards.h | 30 ------- 8 files changed, 254 deletions(-) delete mode 100644 res/items.xml delete mode 100644 src/items/artrewards.c delete mode 100644 src/items/artrewards.h diff --git a/res/eressea/artrewards.xml b/res/eressea/artrewards.xml index 6cb836c52..2a3c09950 100644 --- a/res/eressea/artrewards.xml +++ b/res/eressea/artrewards.xml @@ -1,20 +1,6 @@ - - - - - - - - - - - - - - diff --git a/res/eressea/items.xml b/res/eressea/items.xml index 8b2df7add..69f84c890 100644 --- a/res/eressea/items.xml +++ b/res/eressea/items.xml @@ -63,19 +63,6 @@ - - - - - - - - - - - - - diff --git a/res/eressea/strings.xml b/res/eressea/strings.xml index 28547679d..f7497b810 100644 --- a/res/eressea/strings.xml +++ b/res/eressea/strings.xml @@ -356,42 +356,6 @@ Akademie der Künste academy of arts - - Skulptur - sculpture - - - Horn des Tanzes - horn of dancing - - - Hörner des Tanzes - horns of dancing - - - Miniatur einer Akademie der Künste - academy of arts in a box - - - Miniaturen einer Akademie der Künste - academies of arts in a box - - - Miniatur einer Skulptur - art sculpture in a box - - - Miniaturen einer Skulptur - art sculptures in a box - - - Gefangener Windgeist - trapped air elemental - - - Gefangene Windgeister - trapped air elementals - Auratrank aura potion diff --git a/res/items.xml b/res/items.xml deleted file mode 100644 index 108e6d398..000000000 --- a/res/items.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/eressea.c b/src/eressea.c index 07ea132a8..8001355f1 100755 --- a/src/eressea.c +++ b/src/eressea.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -86,7 +85,6 @@ void game_init(void) register_weapons(); register_xerewards(); - register_artrewards(); #ifdef USE_LIBXML2 register_xmlreader(); #endif diff --git a/src/items/CMakeLists.txt b/src/items/CMakeLists.txt index b2bf2dfe5..bbf192a66 100644 --- a/src/items/CMakeLists.txt +++ b/src/items/CMakeLists.txt @@ -5,7 +5,6 @@ xerewards.test.c ) SET(_FILES -artrewards.c demonseye.c speedsail.c weapons.c diff --git a/src/items/artrewards.c b/src/items/artrewards.c deleted file mode 100644 index 23ab2119e..000000000 --- a/src/items/artrewards.c +++ /dev/null @@ -1,155 +0,0 @@ -/* -Copyright (c) 1998-2015, Enno Rehling -Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "artrewards.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -#define HORNRANGE 10 -#define HORNDURATION 3 -#define HORNIMMUNITY 30 - -static int age_peaceimmune(attrib * a, void *owner) -{ - UNUSED_ARG(owner); - return (--a->data.i > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; -} - -static attrib_type at_peaceimmune = { - "peaceimmune", - NULL, NULL, - age_peaceimmune, - a_writeint, - a_readint -}; - -static int -use_hornofdancing(struct unit *u, const struct item_type *itype, -int amount, struct order *ord) -{ - region *r; - int regionsPacified = 0; - - for (r = regions; r; r = r->next) { - if (distance(u->region, r) < HORNRANGE) { - if (a_find(r->attribs, &at_peaceimmune) == NULL) { - attrib *a; - - create_curse(u, &r->attribs, ct_find("peacezone"), - 20, HORNDURATION, 1.0, 0); - - a = a_add(&r->attribs, a_new(&at_peaceimmune)); - a->data.i = HORNIMMUNITY; - - ADDMSG(&r->msgs, msg_message("hornofpeace_r_success", - "unit region", u, u->region)); - - regionsPacified++; - } - else { - ADDMSG(&r->msgs, msg_message("hornofpeace_r_nosuccess", - "unit region", u, u->region)); - } - } - } - - if (regionsPacified > 0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_success", - "pacified", regionsPacified)); - } - else { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_nosuccess", - "")); - } - - return 0; -} - -#define SPEEDUP 2 - -static int -useonother_trappedairelemental(struct unit *u, int shipId, -const struct item_type *itype, int amount, struct order *ord) -{ - curse *c; - ship *sh; - - if (shipId <= 0) { - cmistake(u, ord, 20, MSG_MOVE); - return -1; - } - - sh = findshipr(u->region, shipId); - if (!sh) { - cmistake(u, ord, 20, MSG_MOVE); - return -1; - } - - c = - create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, SPEEDUP, - 0); - c_setflag(c, CURSE_NOAGE); - - ADDMSG(&u->faction->msgs, msg_message("trappedairelemental_success", - "unit region command ship", u, u->region, ord, sh)); - - use_pooled(u, itype->rtype, GET_DEFAULT, 1); - - return 0; -} - -static int -use_trappedairelemental(struct unit *u, -const struct item_type *itype, int amount, struct order *ord) -{ - ship *sh = u->ship; - - if (sh == NULL) { - cmistake(u, ord, 20, MSG_MOVE); - return -1; - } - return useonother_trappedairelemental(u, sh->no, itype, amount, ord); -} - -void register_artrewards(void) -{ - at_register(&at_peaceimmune); - register_item_use(use_hornofdancing, "use_hornofdancing"); - register_item_use(use_trappedairelemental, "use_trappedairelemental"); - register_item_useonother(useonother_trappedairelemental, - "useonother_trappedairelemental"); -} diff --git a/src/items/artrewards.h b/src/items/artrewards.h deleted file mode 100644 index 779e7cc5f..000000000 --- a/src/items/artrewards.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -Copyright (c) 1998-2015, Enno Rehling -Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_ARTREWARDS -#define H_ITM_ARTREWARDS -#ifdef __cplusplus -extern "C" { -#endif - - extern void register_artrewards(void); - -#ifdef __cplusplus -} -#endif -#endif From 158e0646e1b5b8059f8863b93b5dc0e6f8427064 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 24 Feb 2017 15:48:49 +0100 Subject: [PATCH 16/23] implement fractions --- src/util/CMakeLists.txt | 1 + src/util/variant.c | 36 ++++++++++++++++++++++++++++++++++++ src/util/variant.h | 6 ++++++ 3 files changed, 43 insertions(+) create mode 100644 src/util/variant.c diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 842bcf58c..743ff4d88 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -56,6 +56,7 @@ strings.c translation.c umlaut.c unicode.c +variant.c xml.c ) FOREACH(_FILE ${_FILES}) diff --git a/src/util/variant.c b/src/util/variant.c new file mode 100644 index 000000000..e3461f861 --- /dev/null +++ b/src/util/variant.c @@ -0,0 +1,36 @@ +#include "variant.h" +#include + +static int lcd(int a, int b) { + return a * b; +} + +variant frac_add(variant a, variant b) +{ + int num, den; + variant v; + den = lcd(a.sa[1], b.sa[1]); + num = a.sa[0] * lcd / a.sa[1] + b.sa[0] * lcd / b.sa[1]; + assert(num >= SHRT_MIN && num <= SHRT_MAX); + assert(den >= SHRT_MIN && den <= SHRT_MAX); + v.sa[0] = (short)num; + v.sa[1] = (short)den; + return v; +} + +variant frac_mul(variant a, variant b) +{ + variant v = a; + return v; +} + +variant frac_div(variant a, variant b) +{ + variant v = a; + return v; +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/variant.h b/src/util/variant.h index b65ee0868..8c78bc3ac 100644 --- a/src/util/variant.h +++ b/src/util/variant.h @@ -1,3 +1,5 @@ +#pragma once + #ifndef STRUCT_VARIANT_H #define STRUCT_VARIANT_H #ifdef __cplusplus @@ -19,6 +21,10 @@ extern "C" { VAR_FLOAT } variant_type; + variant frac_add(variant a, variant b); + variant frac_mul(variant a, variant b); + variant frac_div(variant a, variant b); + #ifdef __cplusplus } #endif From 234eb62226d665880b23e808ba2817fed66a7c76 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 24 Feb 2017 17:51:35 +0100 Subject: [PATCH 17/23] short and sweet math with fractions. goinf to use this for magres. --- src/test_eressea.c | 2 ++ src/util/CMakeLists.txt | 1 + src/util/variant.c | 54 +++++++++++++++++++++++++++++------------ src/util/variant.h | 1 + src/util/variant.test.c | 28 +++++++++++++++++++++ 5 files changed, 71 insertions(+), 15 deletions(-) create mode 100644 src/util/variant.test.c diff --git a/src/test_eressea.c b/src/test_eressea.c index 4ffe1f19c..1d991725f 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -6,6 +6,7 @@ #include #include #include +#include #pragma warning(disable: 4210) @@ -85,6 +86,7 @@ int RunAllTests(int argc, char *argv[]) ADD_SUITE(unicode); ADD_SUITE(strings); ADD_SUITE(log); + ADD_SUITE(variant); ADD_SUITE(rng); /* items */ ADD_SUITE(xerewards); diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 743ff4d88..91ed118ae 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -28,6 +28,7 @@ log.test.c # translation.test.c umlaut.test.c unicode.test.c +variant.test.c # xml.test.c ) diff --git a/src/util/variant.c b/src/util/variant.c index e3461f861..74d7adb1c 100644 --- a/src/util/variant.c +++ b/src/util/variant.c @@ -1,16 +1,39 @@ +#include #include "variant.h" + +#include #include -static int lcd(int a, int b) { - return a * b; +static int gcd(int a, int b) { + const int primes[] = { 3, 5, 7, 11, 13, 17, 19, 23, 0 }; + int i = 0, g = 1, p = 2; + while (p && p <= a && p <= b) { + if (a % p == 0 && b % p == 0) { + a /= p; + b /= p; + g *= p; + } + else { + p = primes[i++]; + } + } + return g; } -variant frac_add(variant a, variant b) +static int lcm(int a, int b) { + int x; + if (a == b) return a; + x = (a * b); + x = (x > 0 ? x : -x) / gcd(a, b); + return x; +} + +variant frac_make(int num, int den) { - int num, den; variant v; - den = lcd(a.sa[1], b.sa[1]); - num = a.sa[0] * lcd / a.sa[1] + b.sa[0] * lcd / b.sa[1]; + int g = gcd(num, den); + num /= g; + den /= g; assert(num >= SHRT_MIN && num <= SHRT_MAX); assert(den >= SHRT_MIN && den <= SHRT_MAX); v.sa[0] = (short)num; @@ -18,19 +41,20 @@ variant frac_add(variant a, variant b) return v; } +variant frac_add(variant a, variant b) +{ + int num, den; + den = lcm(a.sa[1], b.sa[1]); + num = a.sa[0] * den / a.sa[1] + b.sa[0] * den / b.sa[1]; + return frac_make(num, den); +} + variant frac_mul(variant a, variant b) { - variant v = a; - return v; + return frac_make(a.sa[0] * b.sa[0], a.sa[1] * b.sa[1]); } variant frac_div(variant a, variant b) { - variant v = a; - return v; + return frac_make(a.sa[0] * b.sa[1], a.sa[1] * b.sa[0]); } - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/util/variant.h b/src/util/variant.h index 8c78bc3ac..f98fa0b80 100644 --- a/src/util/variant.h +++ b/src/util/variant.h @@ -21,6 +21,7 @@ extern "C" { VAR_FLOAT } variant_type; + variant frac_make(int num, int den); variant frac_add(variant a, variant b); variant frac_mul(variant a, variant b); variant frac_div(variant a, variant b); diff --git a/src/util/variant.test.c b/src/util/variant.test.c new file mode 100644 index 000000000..6344e5c33 --- /dev/null +++ b/src/util/variant.test.c @@ -0,0 +1,28 @@ +#include +#include "variant.h" + +#include + +static void test_fractions(CuTest *tc) { + variant a, b; + a = frac_make(120, 12000); + CuAssertIntEquals(tc, 1, a.sa[0]); + CuAssertIntEquals(tc, 100, a.sa[1]); + b = frac_make(23, 2300); + a = frac_add(a, b); + CuAssertIntEquals(tc, 1, a.sa[0]); + CuAssertIntEquals(tc, 50, a.sa[1]); + a = frac_mul(a, b); + CuAssertIntEquals(tc, 1, a.sa[0]); + CuAssertIntEquals(tc, 5000, a.sa[1]); + a = frac_div(b, b); + CuAssertIntEquals(tc, 1, a.sa[0]); + CuAssertIntEquals(tc, 1, a.sa[1]); +} + +CuSuite *get_variant_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_fractions); + return suite; +} From e0229be5007f14e85162b65808bbe3617c2da300 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 24 Feb 2017 17:55:06 +0100 Subject: [PATCH 18/23] also implement subtraction. --- src/util/variant.c | 6 ++++++ src/util/variant.h | 1 + src/util/variant.test.c | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/src/util/variant.c b/src/util/variant.c index 74d7adb1c..2ffe4a4e3 100644 --- a/src/util/variant.c +++ b/src/util/variant.c @@ -49,6 +49,12 @@ variant frac_add(variant a, variant b) return frac_make(num, den); } +variant frac_sub(variant a, variant b) +{ + b.sa[0] = -b.sa[0]; + return frac_add(a, b); +} + variant frac_mul(variant a, variant b) { return frac_make(a.sa[0] * b.sa[0], a.sa[1] * b.sa[1]); diff --git a/src/util/variant.h b/src/util/variant.h index f98fa0b80..4bd5d952d 100644 --- a/src/util/variant.h +++ b/src/util/variant.h @@ -23,6 +23,7 @@ extern "C" { variant frac_make(int num, int den); variant frac_add(variant a, variant b); + variant frac_sub(variant a, variant b); variant frac_mul(variant a, variant b); variant frac_div(variant a, variant b); diff --git a/src/util/variant.test.c b/src/util/variant.test.c index 6344e5c33..793e4f683 100644 --- a/src/util/variant.test.c +++ b/src/util/variant.test.c @@ -18,6 +18,10 @@ static void test_fractions(CuTest *tc) { a = frac_div(b, b); CuAssertIntEquals(tc, 1, a.sa[0]); CuAssertIntEquals(tc, 1, a.sa[1]); + a = frac_sub(a, a); + CuAssertIntEquals(tc, 0, a.sa[0]); + a = frac_mul(a, b); + CuAssertIntEquals(tc, 0, a.sa[0]); } CuSuite *get_variant_suite(void) From e557140ad1038dc745c656f06c76c3a0696fa618 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 24 Feb 2017 20:47:31 +0100 Subject: [PATCH 19/23] more fractions functionality. --- src/util/variant.c | 14 ++++++++++++++ src/util/variant.h | 8 ++++++++ src/util/variant.test.c | 10 +++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/util/variant.c b/src/util/variant.c index 2ffe4a4e3..c1d42808d 100644 --- a/src/util/variant.c +++ b/src/util/variant.c @@ -4,6 +4,9 @@ #include #include +const variant frac_zero = { .sa = { 0, 1 } }; +const variant frac_one = { .sa = { 1, 1 } }; + static int gcd(int a, int b) { const int primes[] = { 3, 5, 7, 11, 13, 17, 19, 23, 0 }; int i = 0, g = 1, p = 2; @@ -28,6 +31,10 @@ static int lcm(int a, int b) { return x; } +bool frac_equal(variant a, variant b) { + return frac_sign(frac_sub(a, b)) == 0; +} + variant frac_make(int num, int den) { variant v; @@ -64,3 +71,10 @@ variant frac_div(variant a, variant b) { return frac_make(a.sa[0] * b.sa[1], a.sa[1] * b.sa[0]); } + +int frac_sign(variant a) { + if (a.sa[0] == 0) return 0; + if (a.sa[0] > 0 && a.sa[1] > 0) return 1; + if (a.sa[0] < 0 && a.sa[1] < 0) return 1; + return -1; +} diff --git a/src/util/variant.h b/src/util/variant.h index 4bd5d952d..ae75c5cda 100644 --- a/src/util/variant.h +++ b/src/util/variant.h @@ -2,6 +2,9 @@ #ifndef STRUCT_VARIANT_H #define STRUCT_VARIANT_H + +#include + #ifdef __cplusplus extern "C" { #endif @@ -21,11 +24,16 @@ extern "C" { VAR_FLOAT } variant_type; + extern const variant frac_zero; + extern const variant frac_one; + variant frac_make(int num, int den); variant frac_add(variant a, variant b); variant frac_sub(variant a, variant b); variant frac_mul(variant a, variant b); variant frac_div(variant a, variant b); + int frac_sign(variant a); + bool frac_equal(variant a, variant b); #ifdef __cplusplus } diff --git a/src/util/variant.test.c b/src/util/variant.test.c index 793e4f683..12299720b 100644 --- a/src/util/variant.test.c +++ b/src/util/variant.test.c @@ -20,8 +20,16 @@ static void test_fractions(CuTest *tc) { CuAssertIntEquals(tc, 1, a.sa[1]); a = frac_sub(a, a); CuAssertIntEquals(tc, 0, a.sa[0]); - a = frac_mul(a, b); + a = frac_sub(frac_one, a); + CuAssertIntEquals(tc, 1, a.sa[0]); + CuAssertIntEquals(tc, 1, a.sa[1]); + a = frac_mul(a, frac_zero); CuAssertIntEquals(tc, 0, a.sa[0]); + CuAssertIntEquals(tc, 1, frac_sign(frac_make(-1, -1))); + CuAssertIntEquals(tc, 1, frac_sign(frac_make(1, 1))); + CuAssertIntEquals(tc, -1, frac_sign(frac_make(-1, 1))); + CuAssertIntEquals(tc, -1, frac_sign(frac_make(1, -1))); + CuAssertIntEquals(tc, 0, frac_sign(frac_make(0, 1))); } CuSuite *get_variant_suite(void) From 3a985108a669d300408cb93a77e7898e2518fb1f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 24 Feb 2017 20:47:47 +0100 Subject: [PATCH 20/23] change all magic resistance to use fractions. --- src/battle.c | 36 ++++++++++------ src/battle.h | 2 +- src/battle.test.c | 67 ++++++++++++++++------------- src/economy.test.c | 2 +- src/guard.test.c | 6 +-- src/kernel/building.h | 2 +- src/kernel/building.test.c | 2 +- src/kernel/item.c | 4 +- src/kernel/item.h | 10 ++--- src/kernel/jsonconf.c | 2 +- src/kernel/jsonconf.test.c | 3 +- src/kernel/race.c | 5 ++- src/kernel/race.h | 4 +- src/kernel/race.test.c | 3 +- src/kernel/xmlreader.c | 47 ++++++++------------ src/laws.test.c | 4 +- src/magic.c | 88 ++++++++++++++++++++++++-------------- src/magic.h | 2 +- src/magic.test.c | 12 +++--- src/spells.c | 7 ++- src/spy.test.c | 2 +- src/volcano.c | 11 +++-- 22 files changed, 178 insertions(+), 143 deletions(-) diff --git a/src/battle.c b/src/battle.c index 23c219109..9864adc41 100644 --- a/src/battle.c +++ b/src/battle.c @@ -1059,7 +1059,7 @@ static int rc_specialdamage(const unit *au, const unit *du, const struct weapon_ return modifier; } -int calculate_armor(troop dt, const weapon_type *dwtype, const weapon_type *awtype, double *magres) { +int calculate_armor(troop dt, const weapon_type *dwtype, const weapon_type *awtype, variant *magres) { fighter *df = dt.fighter; unit *du = df->unit; int ar = 0, an, am; @@ -1110,21 +1110,31 @@ int calculate_armor(troop dt, const weapon_type *dwtype, const weapon_type *awty if (magres) { /* calculate damage multiplier for magical damage */ - double res = 1.0 - magic_resistance(du); + variant res; + + res = frac_sub(frac_one, magic_resistance(du)); if (u_race(du)->battle_flags & BF_EQUIPMENT) { /* der Effekt von Laen steigt nicht linear */ - if (armor && fval(armor, ATF_LAEN)) - res *= (1 - armor->magres); - if (shield && fval(shield, ATF_LAEN)) - res *= (1 - shield->magres); - if (dwtype) - res *= (1 - dwtype->magres); + if (armor && fval(armor, ATF_LAEN)) { + res = frac_mul(res, frac_sub(frac_one, armor->magres)); + } + if (shield && fval(shield, ATF_LAEN)) { + res = frac_mul(res, frac_sub(frac_one, shield->magres)); + } + if (dwtype) { + res = frac_mul(res, frac_sub(frac_one, dwtype->magres)); + } } - /* gegen Magie wirkt nur nat�rliche und magische R�stung */ + /* gegen Magie wirkt nur natuerliche und magische Ruestung */ ar = an + am; - *magres = res > 0 ? res : 0; + if (res.sa[0] >= 0) { + *magres = res; + } + else { + *magres = frac_make(0, 1); + } } return ar; @@ -1147,7 +1157,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) const weapon_type *dwtype = NULL; const weapon_type *awtype = NULL; const weapon *weapon; - double res = 1.0; + variant res = frac_make(1, 1); int rda, sk = 0, sd; bool magic = false; @@ -1190,9 +1200,9 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) return false; } - /* TODO not sure if res could be > 1 here */ if (magic) { - da = (int)(MAX(da * res, 0)); + res = frac_mul(frac_make(da, 1), res); + da = res.sa[0] / res.sa[1]; } if (type != AT_COMBATSPELL && type != AT_SPELL) { diff --git a/src/battle.h b/src/battle.h index 1b4cf2588..85e65cf66 100644 --- a/src/battle.h +++ b/src/battle.h @@ -248,7 +248,7 @@ extern "C" { int count_enemies(struct battle *b, const struct fighter *af, int minrow, int maxrow, int select); int natural_armor(struct unit * u); - int calculate_armor(troop dt, const struct weapon_type *dwtype, const struct weapon_type *awtype, double *magres); + int calculate_armor(troop dt, const struct weapon_type *dwtype, const struct weapon_type *awtype, union variant *magres); bool terminate(troop dt, troop at, int type, const char *damage, bool missile); extern void message_all(battle * b, struct message *m); diff --git a/src/battle.test.c b/src/battle.test.c index d15c335a9..b00d06a98 100644 --- a/src/battle.test.c +++ b/src/battle.test.c @@ -250,23 +250,24 @@ static void test_calculate_armor(CuTest * tc) armor_type *ashield, *achain; item_type *ibelt, *ishield, *ichain; race *rc; - double magres = 0.0; + variant magres = frac_zero; + variant v50p = frac_make(1, 2); test_setup(); r = test_create_region(0, 0, 0); ibelt = it_get_or_create(rt_get_or_create("trollbelt")); ishield = it_get_or_create(rt_get_or_create("shield")); - ashield = new_armortype(ishield, 0.0, 0.5, 1, ATF_SHIELD); + ashield = new_armortype(ishield, 0.0, v50p, 1, ATF_SHIELD); ichain = it_get_or_create(rt_get_or_create("chainmail")); - achain = new_armortype(ichain, 0.0, 0.5, 3, ATF_NONE); - wtype = new_weapontype(it_get_or_create(rt_get_or_create("sword")), 0, 0.5, 0, 0, 0, 0, SK_MELEE, 1); + achain = new_armortype(ichain, 0.0, v50p, 3, ATF_NONE); + wtype = new_weapontype(it_get_or_create(rt_get_or_create("sword")), 0, v50p, 0, 0, 0, 0, SK_MELEE, 1); rc = test_create_race("human"); du = test_create_unit(test_create_faction(rc), r); dt.index = 0; dt.fighter = setup_fighter(&b, du); CuAssertIntEquals_Msg(tc, "default ac", 0, calculate_armor(dt, 0, 0, &magres)); - CuAssertDblEquals_Msg(tc, "magres unmodified", 1.0, magres, 0.01); + CuAssertIntEquals_Msg(tc, "magres unmodified", magres.sa[0], magres.sa[1]); free_battle(b); b = NULL; @@ -299,13 +300,13 @@ static void test_calculate_armor(CuTest * tc) wtype->flags = WTF_NONE; CuAssertIntEquals_Msg(tc, "magical attack", 3, calculate_armor(dt, 0, 0, &magres)); - CuAssertDblEquals_Msg(tc, "magres unmodified", 1.0, magres, 0.01); + CuAssertIntEquals_Msg(tc, "magres unmodified", magres.sa[1], magres.sa[0]); ashield->flags |= ATF_LAEN; achain->flags |= ATF_LAEN; - magres = 1.0; + magres = frac_one; CuAssertIntEquals_Msg(tc, "laen armor", 3, calculate_armor(dt, 0, 0, &magres)); - CuAssertDblEquals_Msg(tc, "laen magres bonus", 0.25, magres, 0.01); + CuAssertIntEquals_Msg(tc, "laen magres bonus", 4, magres.sa[1]); free_battle(b); test_cleanup(); } @@ -319,38 +320,42 @@ static void test_magic_resistance(CuTest *tc) armor_type *ashield, *achain; item_type *ishield, *ichain; race *rc; - double magres; + variant magres; + variant v50p = frac_make(1, 2); + variant v10p = frac_make(1, 10); test_setup(); r = test_create_region(0, 0, 0); ishield = it_get_or_create(rt_get_or_create("shield")); - ashield = new_armortype(ishield, 0.0, 0.5, 1, ATF_SHIELD); + ashield = new_armortype(ishield, 0.0, v50p, 1, ATF_SHIELD); ichain = it_get_or_create(rt_get_or_create("chainmail")); - achain = new_armortype(ichain, 0.0, 0.5, 3, ATF_NONE); + achain = new_armortype(ichain, 0.0, v50p, 3, ATF_NONE); rc = test_create_race("human"); du = test_create_unit(test_create_faction(rc), r); dt.index = 0; + i_change(&du->items, ishield, 1); dt.fighter = setup_fighter(&b, du); calculate_armor(dt, 0, 0, &magres); - CuAssertDblEquals_Msg(tc, "no magres bonus", 0.0, magic_resistance(du), 0.01); - CuAssertDblEquals_Msg(tc, "no magres reduction", 1.0, magres, 0.01); + CuAssertIntEquals_Msg(tc, "no magres reduction", magres.sa[1], magres.sa[0]); + magres = magic_resistance(du); + CuAssertIntEquals_Msg(tc, "no magres reduction", 0, magres.sa[0]); ashield->flags |= ATF_LAEN; - ashield->magres = 0.1; + ashield->magres = v10p; calculate_armor(dt, 0, 0, &magres); + CuAssert(tc, "laen reduction => 10%%", frac_equal(frac_make(9, 10), magres)); free_battle(b); b = NULL; - i_change(&du->items, ishield, 1); i_change(&du->items, ichain, 1); achain->flags |= ATF_LAEN; - achain->magres = 0.1; + achain->magres = v10p; ashield->flags |= ATF_LAEN; - ashield->magres = 0.1; + ashield->magres = v10p; dt.fighter = setup_fighter(&b, du); calculate_armor(dt, 0, 0, &magres); - CuAssertDblEquals_Msg(tc, "laen reduction", 0.81, magres, 0.01); + CuAssert(tc, "2x laen reduction => 81%%", frac_equal(frac_make(81, 100), magres)); free_battle(b); b = NULL; @@ -359,17 +364,20 @@ static void test_magic_resistance(CuTest *tc) set_level(du, SK_MAGIC, 2); dt.fighter = setup_fighter(&b, du); calculate_armor(dt, 0, 0, &magres); - CuAssertDblEquals_Msg(tc, "skill bonus", 0.1, magic_resistance(du), 0.01); - CuAssertDblEquals_Msg(tc, "skill reduction", 0.9, magres, 0.01); - rc->magres = 50; /* percentage, gets added to skill bonus */ + CuAssert(tc, "skill reduction => 90%%", frac_equal(magres, frac_make(9, 10))); + magres = magic_resistance(du); + CuAssert(tc, "skill reduction", frac_equal(magres, v10p)); + rc->magres = v50p; /* percentage, gets added to skill bonus */ calculate_armor(dt, 0, 0, &magres); - CuAssertDblEquals_Msg(tc, "race bonus", 0.6, magic_resistance(du), 0.01); - CuAssertDblEquals_Msg(tc, "race reduction", 0.4, magres, 0.01); + CuAssert(tc, "race reduction => 40%%", frac_equal(magres, frac_make(4, 10))); + magres = magic_resistance(du); + CuAssert(tc, "race bonus => 60%%", frac_equal(magres, frac_make(60, 100))); - rc->magres = 150; /* should not cause negative damage multiplier */ - CuAssertDblEquals_Msg(tc, "magic resistance is never > 0.9", 0.9, magic_resistance(du), 0.01); + rc->magres = frac_make(15, 10); /* 150% resistance should not cause negative damage multiplier */ + magres = magic_resistance(du); + CuAssert(tc, "magic resistance is never > 0.9", frac_equal(magres, frac_make(9, 10))); calculate_armor(dt, 0, 0, &magres); - CuAssertDblEquals_Msg(tc, "damage reduction is never < 0.1", 0.1, magres, 0.01); + CuAssert(tc, "damage reduction is never < 0.1", frac_equal(magres, frac_make(1, 10))); free_battle(b); test_cleanup(); @@ -385,14 +393,15 @@ static void test_projectile_armor(CuTest * tc) armor_type *ashield, *achain; item_type *ishield, *ichain; race *rc; + variant v50p = frac_make(1, 2); test_setup(); r = test_create_region(0, 0, 0); ishield = it_get_or_create(rt_get_or_create("shield")); - ashield = new_armortype(ishield, 0.0, 0.5, 1, ATF_SHIELD); + ashield = new_armortype(ishield, 0.0, v50p, 1, ATF_SHIELD); ichain = it_get_or_create(rt_get_or_create("chainmail")); - achain = new_armortype(ichain, 0.0, 0.5, 3, ATF_NONE); - wtype = new_weapontype(it_get_or_create(rt_get_or_create("sword")), 0, 0.5, 0, 0, 0, 0, SK_MELEE, 1); + achain = new_armortype(ichain, 0.0, v50p, 3, ATF_NONE); + wtype = new_weapontype(it_get_or_create(rt_get_or_create("sword")), 0, v50p, 0, 0, 0, 0, SK_MELEE, 1); rc = test_create_race("human"); rc->battle_flags |= BF_EQUIPMENT; du = test_create_unit(test_create_faction(rc), r); diff --git a/src/economy.test.c b/src/economy.test.c index 2de6265f0..4ddd20105 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -211,7 +211,7 @@ static void test_tax_cmd(CuTest *tc) { silver = get_resourcetype(R_SILVER)->itype; sword = it_get_or_create(rt_get_or_create("sword")); - new_weapontype(sword, 0, 0.0, NULL, 0, 0, 0, SK_MELEE, 1); + new_weapontype(sword, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 1); i_change(&u->items, sword, 1); set_level(u, SK_MELEE, 1); diff --git a/src/guard.test.c b/src/guard.test.c index fb55129ee..17aa2891c 100644 --- a/src/guard.test.c +++ b/src/guard.test.c @@ -42,7 +42,7 @@ static void test_guard_unskilled(CuTest * tc) test_setup(); itype = it_get_or_create(rt_get_or_create("sword")); - new_weapontype(itype, 0, 0.0, NULL, 0, 0, 0, SK_MELEE, 2); + new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2); r = test_create_region(0, 0, 0); u = test_create_unit(test_create_faction(0), r); ug = test_create_unit(test_create_faction(0), r); @@ -61,7 +61,7 @@ static void test_guard_armed(CuTest * tc) test_setup(); itype = it_get_or_create(rt_get_or_create("sword")); - new_weapontype(itype, 0, 0.0, NULL, 0, 0, 0, SK_MELEE, 2); + new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2); r = test_create_region(0, 0, 0); u = test_create_unit(test_create_faction(0), r); ug = test_create_unit(test_create_faction(0), r); @@ -80,7 +80,7 @@ static void test_is_guard(CuTest * tc) test_setup(); itype = it_get_or_create(rt_get_or_create("sword")); - new_weapontype(itype, 0, 0.0, NULL, 0, 0, 0, SK_MELEE, 2); + new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2); r = test_create_region(0, 0, 0); ug = test_create_unit(test_create_faction(0), r); i_change(&ug->items, itype, 1); diff --git a/src/kernel/building.h b/src/kernel/building.h index 8c23fdb7c..6d66aa9ab 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -60,7 +60,7 @@ extern "C" { int capacity; /* Kapazit�t pro Gr��enpunkt */ int maxcapacity; /* Max. Kapazit�t */ int maxsize; /* how big can it get, with all the extensions? */ - int magres; /* how well it resists against spells */ + variant magres; /* how well it resists against spells */ int magresbonus; /* bonus it gives the target against spells */ int fumblebonus; /* bonus that reduces fumbling */ double auraregen; /* modifier for aura regeneration inside building */ diff --git a/src/kernel/building.test.c b/src/kernel/building.test.c index 1286fd6b4..2819d4a16 100644 --- a/src/kernel/building.test.c +++ b/src/kernel/building.test.c @@ -381,7 +381,7 @@ static void test_btype_defaults(CuTest *tc) { CuAssertIntEquals(tc, -1, btype->maxsize); CuAssertIntEquals(tc, 1, btype->capacity); CuAssertIntEquals(tc, -1, btype->maxcapacity); - CuAssertIntEquals(tc, 0, btype->magres); + CuAssertIntEquals(tc, 0, btype->magres.sa[0]); CuAssertIntEquals(tc, 0, btype->magresbonus); CuAssertIntEquals(tc, 0, btype->fumblebonus); CuAssertIntEquals(tc, 0, btype->flags); diff --git a/src/kernel/item.c b/src/kernel/item.c index 9bc321fdb..6e64c147f 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -275,7 +275,7 @@ luxury_type *new_luxurytype(item_type * itype, int price) } weapon_type *new_weapontype(item_type * itype, - int wflags, double magres, const char *damage[], int offmod, int defmod, + int wflags, variant magres, const char *damage[], int offmod, int defmod, int reload, skill_t sk, int minskill) { weapon_type *wtype; @@ -301,7 +301,7 @@ weapon_type *new_weapontype(item_type * itype, return wtype; } -armor_type *new_armortype(item_type * itype, double penalty, double magres, +armor_type *new_armortype(item_type * itype, double penalty, variant magres, int prot, unsigned int flags) { armor_type *atype; diff --git a/src/kernel/item.h b/src/kernel/item.h index 1d3e5ff29..c1ac38517 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -181,7 +181,7 @@ extern "C" { const item_type *itype; unsigned int flags; double penalty; - double magres; + variant magres; int prot; float projectile; /* chance, dass ein projektil abprallt */ } armor_type; @@ -205,7 +205,7 @@ extern "C" { int minskill; int offmod; int defmod; - double magres; + variant magres; int reload; /* time to reload this weapon */ weapon_mod *modifiers; /* --- functions --- */ @@ -244,14 +244,12 @@ extern "C" { /* creation */ resource_type *rt_get_or_create(const char *name); item_type *it_get_or_create(resource_type *rtype); - item_type *new_itemtype(resource_type * rtype, int iflags, int weight, - int capacity); luxury_type *new_luxurytype(item_type * itype, int price); weapon_type *new_weapontype(item_type * itype, int wflags, - double magres, const char *damage[], int offmod, int defmod, int reload, + variant magres, const char *damage[], int offmod, int defmod, int reload, skill_t sk, int minskill); armor_type *new_armortype(item_type * itype, double penalty, - double magres, int prot, unsigned int flags); + variant magres, int prot, unsigned int flags); potion_type *new_potiontype(item_type * itype, int level); typedef enum { diff --git a/src/kernel/jsonconf.c b/src/kernel/jsonconf.c index 2478c838f..287aa61db 100644 --- a/src/kernel/jsonconf.c +++ b/src/kernel/jsonconf.c @@ -460,7 +460,7 @@ static void json_race(cJSON *json, race *rc) { break; case cJSON_Number: if (strcmp(child->string, "magres") == 0) { - rc->magres = child->valueint; + rc->magres = frac_make(child->valueint, 100); } else if (strcmp(child->string, "maxaura") == 0) { rc->maxaura = child->valueint; diff --git a/src/kernel/jsonconf.test.c b/src/kernel/jsonconf.test.c index dcf748d00..8b8ac8c14 100644 --- a/src/kernel/jsonconf.test.c +++ b/src/kernel/jsonconf.test.c @@ -163,8 +163,7 @@ static void test_races(CuTest * tc) CuAssertPtrNotNull(tc, rc); CuAssertIntEquals(tc, RCF_NPC | RCF_WALK | RCF_UNDEAD, rc->flags); CuAssertStrEquals(tc, "1d4", rc->def_damage); - CuAssertIntEquals(tc, 100, rc->magres); - CuAssertDblEquals(tc, 1.0, rc_magres(rc), 0.0); + CuAssertTrue(tc, frac_equal(frac_one, rc->magres)); CuAssertIntEquals(tc, 200, rc->maxaura); CuAssertDblEquals(tc, 2.0, rc_maxaura(rc), 0.0); CuAssertDblEquals(tc, 3.0, rc->regaura, 0.0); diff --git a/src/kernel/race.c b/src/kernel/race.c index 4a3a04916..d159fd6d8 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -331,6 +331,7 @@ race *rc_create(const char *zName) assert(zName); rc = (race *)calloc(sizeof(race), 1); + rc->magres.sa[1] = 1; rc->hitpoints = 1; rc->weight = PERSON_WEIGHT; rc->capacity = 540; @@ -383,8 +384,8 @@ bool r_insectstalled(const region * r) return fval(r->terrain, ARCTIC_REGION); } -double rc_magres(const race *rc) { - return rc->magres / 100.0; +variant rc_magres(const race *rc) { + return rc->magres; } double rc_maxaura(const race *rc) { diff --git a/src/kernel/race.h b/src/kernel/race.h index e464c9447..f14b8e54f 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -116,7 +116,7 @@ extern "C" { typedef struct race { char *_name; - int magres; + variant magres; int healing; int maxaura; /* Faktor auf Maximale Aura */ double regaura; /* Faktor auf Regeneration */ @@ -182,7 +182,7 @@ extern "C" { int rc_luxury_trade(const struct race *rc); int rc_herb_trade(const struct race *rc); - double rc_magres(const struct race *rc); + variant rc_magres(const struct race *rc); double rc_maxaura(const struct race *rc); int rc_armor_bonus(const struct race *rc); int rc_scare(const struct race *rc); diff --git a/src/kernel/race.test.c b/src/kernel/race.test.c index 8363d8b72..07ecbdd45 100644 --- a/src/kernel/race.test.c +++ b/src/kernel/race.test.c @@ -24,8 +24,7 @@ static void test_rc_defaults(CuTest *tc) { rc = rc_get_or_create("human"); CuAssertStrEquals(tc, "human", rc->_name); CuAssertIntEquals(tc, 0, rc_armor_bonus(rc)); - CuAssertIntEquals(tc, 0, rc->magres); - CuAssertDblEquals(tc, 0.0, rc_magres(rc), 0.0); + CuAssertIntEquals(tc, 0, rc->magres.sa[0]); CuAssertIntEquals(tc, 0, rc->healing); CuAssertDblEquals(tc, 0.0, rc_maxaura(rc), 0.0); CuAssertDblEquals(tc, 1.0, rc->recruit_multi, 0.0); diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 27adba598..74459270c 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -61,6 +61,19 @@ without prior permission by the authors of Eressea. #include #ifdef USE_LIBXML2 + +static variant xml_fraction(xmlNodePtr node, const char *name) { + xmlChar *propValue = xmlGetProp(node, BAD_CAST name); + if (propValue != NULL) { + int num, den = 100; + double fval = atof((const char *)propValue); + num = (int)(fval * den + 0.5); + xmlFree(propValue); + return frac_make(num, den); + } + return frac_make(0, 1); +} + static void xml_readtext(xmlNodePtr node, struct locale **lang, xmlChar ** text) { xmlChar *propValue = xmlGetProp(node, BAD_CAST "locale"); @@ -245,7 +258,7 @@ static int parse_buildings(xmlDocPtr doc) btype->maxcapacity = xml_ivalue(node, "maxcapacity", btype->maxcapacity); btype->maxsize = xml_ivalue(node, "maxsize", btype->maxsize); - btype->magres = xml_ivalue(node, "magres", btype->magres); + btype->magres = frac_make(xml_ivalue(node, "magres", 0), 100); btype->magresbonus = xml_ivalue(node, "magresbonus", btype->magresbonus); btype->fumblebonus = xml_ivalue(node, "fumblebonus", btype->fumblebonus); btype->auraregen = xml_fvalue(node, "auraregen", btype->auraregen); @@ -582,7 +595,7 @@ static armor_type *xml_readarmor(xmlXPathContextPtr xpath, item_type * itype) unsigned int flags = ATF_NONE; int ac = xml_ivalue(node, "ac", 0); double penalty = xml_fvalue(node, "penalty", 0.0); - double magres = xml_fvalue(node, "magres", 0.0); + variant magres = xml_fraction(node, "magres"); if (xml_bvalue(node, "laen", false)) flags |= ATF_LAEN; @@ -607,7 +620,7 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) int offmod = xml_ivalue(node, "offmod", 0); int defmod = xml_ivalue(node, "defmod", 0); int reload = xml_ivalue(node, "reload", 0); - double magres = xml_fvalue(node, "magres", 0.0); + variant magres = xml_fraction(node, "magres"); if (xml_bvalue(node, "armorpiercing", false)) flags |= WTF_ARMORPIERCING; @@ -899,22 +912,6 @@ static int parse_rules(xmlDocPtr doc) return 0; } -static int gcd(int num, int den) { - const int primes[] = { 3, 5, 7, 11, 0 }; - int i=0, g = 1, p = 2; - while (p && p<=den && p<=num) { - if (num % p == 0 && den % p == 0) { - num /= p; - den /= p; - g *= p; - } - else { - p = primes[i++]; - } - } - return g; -} - static int parse_resources(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); @@ -1031,15 +1028,7 @@ static int parse_resources(xmlDocPtr doc) rdata->modifiers[k].flags = RMF_SKILL; } else if (strcmp((const char *)propValue, "material") == 0) { - int g, num, den = 100; - double fval = xml_fvalue(node, "value", 0); - /* TODO: extract into a function for reading fractions? */ - num = (int)(fval * den + 0.5); - g = gcd(num, den); - num /= g; - den /= g; - rdata->modifiers[k].value.sa[0] = (short)num; - rdata->modifiers[k].value.sa[1] = (short)den; + rdata->modifiers[k].value = xml_fraction(node, "value"); rdata->modifiers[k].flags = RMF_SAVEMATERIAL; } else if (strcmp((const char *)propValue, "require") == 0) { @@ -1623,7 +1612,7 @@ static int parse_races(xmlDocPtr doc) rc->def_damage = strdup((const char *)propValue); xmlFree(propValue); - rc->magres = xml_ivalue(node, "magres", rc->magres); + rc->magres = frac_make(xml_ivalue(node, "magres", 100), 100); rc->healing = (int)(xml_fvalue(node, "healing", rc->healing) * 100); /* TODO: store as int in XML */ rc->maxaura = (int)(xml_fvalue(node, "maxaura", rc->maxaura) * 100); /* TODO: store as int in XML */ rc->regaura = (float)xml_fvalue(node, "regaura", rc->regaura); diff --git a/src/laws.test.c b/src/laws.test.c index cca55beb1..c27651d83 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -611,7 +611,7 @@ void setup_guard(guard_fixture *fix, bool armed) { if (armed) { item_type *itype; itype = it_get_or_create(rt_get_or_create("sword")); - new_weapontype(itype, 0, 0.0, NULL, 0, 0, 0, SK_MELEE, 2); + new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2); i_change(&u->items, itype, 1); set_level(u, SK_MELEE, 2); } @@ -1481,7 +1481,7 @@ static void test_armedmen(CuTest *tc) { test_setup(); u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); it_sword = test_create_itemtype("sword"); - wtype = new_weapontype(it_sword, 0, 0.5, 0, 0, 0, 0, SK_MELEE, 1); + wtype = new_weapontype(it_sword, 0, frac_make(1, 2), 0, 0, 0, 0, SK_MELEE, 1); CuAssertIntEquals(tc, 0, armedmen(u, false)); CuAssertIntEquals(tc, 0, armedmen(u, true)); set_level(u, SK_MELEE, 1); diff --git a/src/magic.c b/src/magic.c index 65b454c04..de1336d66 100644 --- a/src/magic.c +++ b/src/magic.c @@ -1135,27 +1135,29 @@ static int farcasting(unit * magician, region * r) /* allgemeine Magieresistenz einer Einheit, * reduziert magischen Schaden */ -double magic_resistance(unit * target) +variant magic_resistance(unit * target) { attrib *a; curse *c; const curse_type * ct_goodresist = 0, *ct_badresist = 0; const resource_type *rtype; const race *rc = u_race(target); - double probability = rc_magres(rc); + variant v, prob = rc_magres(rc); const plane *pl = rplane(target->region); if (rc == get_race(RC_HIRNTOETER) && !pl) { - probability /= 2; + prob.sa[1] *= 2; } assert(target->number > 0); /* Magier haben einen Resistenzbonus vom Magietalent * 5% */ - probability += effskill(target, SK_MAGIC, 0) * 0.05; + prob = frac_add(prob, frac_make(effskill(target, SK_MAGIC, 0), 20)); /* Auswirkungen von Zaubern auf der Einheit */ c = get_curse(target->attribs, ct_find("magicresistance")); if (c) { - probability += 0.01 * curse_geteffect(c) * get_cursedmen(target, c); + /* TODO: legacy. magicresistance-effect is an integer-percentage stored in a double */ + int effect = curse_geteffect_int(c) * get_cursedmen(target, c); + prob = frac_add(prob, frac_make(effect, 100)); } /* Unicorn +10 */ @@ -1163,7 +1165,7 @@ double magic_resistance(unit * target) if (rtype) { int n = i_get(target->items, rtype->itype); if (n) { - probability += n * 0.1 / target->number; + prob = frac_add(prob, frac_make(n, target->number * 10)); } } @@ -1180,13 +1182,15 @@ double magic_resistance(unit * target) if (mage != NULL) { if (ct_goodresist && c->type == ct_goodresist) { if (alliedunit(mage, target->faction, HELP_GUARD)) { - probability += curse_geteffect(c) * 0.01; + /* TODO: legacy. magicresistance-effect is an integer-percentage stored in a double */ + prob = frac_add(prob, frac_make(curse_geteffect_int(c), 100)); ct_goodresist = 0; /* only one effect per region */ } } else if (ct_badresist && c->type == ct_badresist) { if (!alliedunit(mage, target->faction, HELP_GUARD)) { - probability -= curse_geteffect(c) * 0.01; + /* TODO: legacy. magicresistance-effect is an integer-percentage stored in a double */ + prob = frac_sub(prob, frac_make(curse_geteffect_int(c), 100)); ct_badresist = 0; /* only one effect per region */ } } @@ -1202,11 +1206,18 @@ double magic_resistance(unit * target) const struct building_type *btype = building_is_active(b) ? b->type : NULL; /* gesegneter Steinkreis gibt 30% dazu */ - if (btype) - probability += btype->magresbonus * 0.01; + if (btype) { + /* TODO: legacy. building-bonus is an integer-percentage */ + prob = frac_add(prob, frac_make(btype->magresbonus, 100)); + } } - return (probability<0.9) ? probability : 0.9; + /* resistance must never be more than 90% */ + v = frac_make(9, 10); + if (frac_sign(frac_sub(prob, v)) > 0) { /* prob < 90% */ + return v; /* at most 90% */ + } + return prob; } /* ------------------------------------------------------------- */ @@ -1223,12 +1234,12 @@ double magic_resistance(unit * target) bool target_resists_magic(unit * magician, void *obj, int objtyp, int t_bonus) { - double probability = 0.0; + variant v02p, v98p, prob = frac_make(t_bonus, 100); + attrib *a = NULL; - if (magician == NULL) - return true; - if (obj == NULL) + if (magician == NULL || obj == NULL) { return true; + } switch (objtyp) { case TYP_UNIT: @@ -1248,43 +1259,56 @@ target_resists_magic(unit * magician, void *obj, int objtyp, int t_bonus) pa = sk; } - /* Contest */ - probability = 0.05 * (10 + pa - at); - - probability += magic_resistance((unit *)obj); + /* Contest, probability = 0.05 * (10 + pa - at); */ + prob = frac_add(prob, frac_make(10 + pa - at, 20)); + prob = frac_add(prob, magic_resistance((unit *)obj)); break; } case TYP_REGION: - /* Bonus durch Zauber */ + /* Bonus durch Zauber probability += - 0.01 * get_curseeffect(((region *)obj)->attribs, C_RESIST_MAGIC, 0); + 0.01 * get_curseeffect(((region *)obj)->attribs, C_RESIST_MAGIC, 0); */ + a = ((region *)obj)->attribs; break; case TYP_BUILDING: - /* Bonus durch Zauber */ + /* Bonus durch Zauber probability += - 0.01 * get_curseeffect(((building *)obj)->attribs, C_RESIST_MAGIC, 0); - - /* Bonus durch Typ */ - probability += 0.01 * ((building *)obj)->type->magres; - + 0.01 * get_curseeffect(((building *)obj)->attribs, C_RESIST_MAGIC, 0); */ + a = ((building *)obj)->attribs; + /* Bonus durch Typ + probability += 0.01 * ((building *)obj)->type->magres; */ + prob = frac_add(prob, ((building *)obj)->type->magres); break; case TYP_SHIP: /* Bonus durch Zauber */ - probability += - 0.01 * get_curseeffect(((ship *)obj)->attribs, C_RESIST_MAGIC, 0); + a = ((ship *)obj)->attribs; break; } - probability = MAX(0.02, probability + t_bonus * 0.01); - probability = MIN(0.98, probability); + if (a) { + const struct curse_type *ct_resist = ct_find(oldcursename(C_RESIST_MAGIC)); + curse * c = get_curse(a, ct_resist); + int effect = curse_geteffect_int(c); + prob = frac_add(prob, frac_make(effect, 100)); + } + + /* ignore results < 2% and > 98% */ + v02p = frac_make(1, 50); + v98p = frac_make(49, 50); + if (frac_sign(frac_sub(prob, v02p)) < 0) { + prob = v02p; + } + else if (frac_sign(frac_sub(prob, v98p)) > 0) { + prob = v98p; + } /* gibt true, wenn die Zufallszahl kleiner als die chance ist und * false, wenn sie gleich oder größer ist, dh je größer die * Magieresistenz (chance) desto eher gibt die Funktion true zurück */ - return chance(probability); + return rng_int() % prob.sa[1] < prob.sa[0]; } /* ------------------------------------------------------------- */ diff --git a/src/magic.h b/src/magic.h index d282767a9..37fe33eae 100644 --- a/src/magic.h +++ b/src/magic.h @@ -315,7 +315,7 @@ extern "C" { bool is_magic_resistant(struct unit *magician, struct unit *target, int resist_bonus); /* Mapperfunktion für target_resists_magic() vom Typ struct unit. */ - extern double magic_resistance(struct unit *target); + variant magic_resistance(struct unit *target); /* gibt die Chance an, mit der einem Zauber widerstanden wird. Je * größer, desto resistenter ist da Opfer */ bool target_resists_magic(struct unit *magician, void *obj, int objtyp, diff --git a/src/magic.test.c b/src/magic.test.c index baf8ede50..a5a842172 100644 --- a/src/magic.test.c +++ b/src/magic.test.c @@ -414,15 +414,15 @@ static void test_magic_resistance(CuTest *tc) { test_setup(); rc = test_create_race("human"); u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0)); - CuAssertDblEquals(tc, rc->magres/100.0, magic_resistance(u), 0.01); - rc->magres = 100; - CuAssertDblEquals_Msg(tc, "magic resistance is capped at 0.9", 0.9, magic_resistance(u), 0.01); + CuAssertTrue(tc, frac_equal(rc->magres, magic_resistance(u))); + rc->magres = frac_one; + CuAssert(tc, "magic resistance is capped at 0.9", frac_equal(magic_resistance(u), frac_make(9, 10))); rc = test_create_race("braineater"); - rc->magres = 100; + rc->magres = frac_one; u_setrace(u, rc); - CuAssertDblEquals_Msg(tc, "brain eaters outside astral space have 50% magres", 0.5, magic_resistance(u), 0.01); + CuAssert(tc, "brain eaters outside astral space have 50% magres", frac_equal(magic_resistance(u), frac_make(1, 2))); u->region->_plane = get_astralplane(); - CuAssertDblEquals_Msg(tc, "brain eaters in astral space have full magres", 0.9, magic_resistance(u), 0.01); + CuAssert(tc, "brain eaters in astral space have full magres", frac_equal(magic_resistance(u), frac_make(9, 10))); test_cleanup(); } diff --git a/src/spells.c b/src/spells.c index 95b26434f..fcee1b51b 100644 --- a/src/spells.c +++ b/src/spells.c @@ -2851,7 +2851,8 @@ static int dc_age(struct curse *c) while (*up != NULL) { unit *u = *up; int hp; - double damage = c->effect * u->number; + variant dmg = frac_make(u->number, 1); + double damage = c->effect; if (u->number <= 0 || target_resists_magic(mage, u, TYP_UNIT, 0)) { up = &u->next; @@ -2859,7 +2860,9 @@ static int dc_age(struct curse *c) } /* Reduziert durch Magieresistenz */ - damage *= (1.0 - magic_resistance(u)); + dmg = frac_mul(dmg, frac_sub(frac_make(1,1), magic_resistance(u))); + damage *= dmg.sa[0]; + damage /= dmg.sa[1]; hp = change_hitpoints(u, -(int)damage); ADDMSG(&u->faction->msgs, msg_message((hp>0)?"poison_damage":"poison_death", "region unit", r, u)); diff --git a/src/spy.test.c b/src/spy.test.c index 8341b17d3..ae1550689 100644 --- a/src/spy.test.c +++ b/src/spy.test.c @@ -71,7 +71,7 @@ static void test_all_spy_message(CuTest *tc) { set_factionstealth(fix.victim, fix.spy->faction); itype = it_get_or_create(rt_get_or_create("sword")); - new_weapontype(itype, 0, 0.0, NULL, 0, 0, 0, SK_MELEE, 2); + new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2); i_change(&fix.victim->items, itype, 1); spy_message(99, fix.spy, fix.victim); diff --git a/src/volcano.c b/src/volcano.c index fb4cfa74c..9734bb2cd 100644 --- a/src/volcano.c +++ b/src/volcano.c @@ -80,7 +80,6 @@ damage_unit(unit * u, const char *dam, bool physical, bool magic) int *hp, hpstack[20]; int h; int i, dead = 0, hp_rem = 0, heiltrank; - double magres = magic_resistance(u); assert(u->number); if (fval(u_race(u), RCF_ILLUSIONARY) || u_race(u) == get_race(RC_SPELL)) { @@ -105,10 +104,14 @@ damage_unit(unit * u, const char *dam, bool physical, bool magic) /* Schaden */ for (i = 0; i < u->number; i++) { int damage = dice_rand(dam); - if (magic) - damage = (int)(damage * (1.0 - magres)); - if (physical) + if (magic) { + variant magres = magic_resistance(u); + magres = frac_sub(frac_make(1, 1), magres); + damage = damage * magres.sa[0] / magres.sa[1]; + } + if (physical) { damage -= nb_armor(u, i); + } hp[i] -= damage; } From 6031dff6850ec50b61d1f937383cce353390fcbb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 25 Feb 2017 19:50:32 +0100 Subject: [PATCH 21/23] resource_limit.value is always zero, never initialized. kill it. --- clibs | 2 +- src/economy.c | 4 ++-- src/economy.test.c | 1 - src/kernel/resources.h | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/clibs b/clibs index 27c8b3202..b91413316 160000 --- a/clibs +++ b/clibs @@ -1 +1 @@ -Subproject commit 27c8b3202b52766465743c3324fc0b52c5ba4b11 +Subproject commit b91413316ce13044c555084a9f605983586107b4 diff --git a/src/economy.c b/src/economy.c index f0a693eca..f9ded29de 100644 --- a/src/economy.c +++ b/src/economy.c @@ -1123,7 +1123,7 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist) allocation *al; int nreq = 0; resource_limit *rdata = get_resourcelimit(rtype); - int avail = rdata->value; + int avail = 0; for (al = alist; al; al = al->next) { nreq += required(al->want, al->save); @@ -1165,7 +1165,7 @@ static allocate_function get_allocator(const struct resource_type *rtype) resource_limit *rdata = get_resourcelimit(rtype); if (rdata) { - if (rdata->value > 0 || rdata->limit != NULL) { + if (rdata->limit != NULL) { return attrib_allocation; } return leveled_allocation; diff --git a/src/economy.test.c b/src/economy.test.c index 4ddd20105..aea42491d 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -384,7 +384,6 @@ static void test_make_item(CuTest *tc) { rtype->flags |= RTF_LIMITED; rmt = rmt_create(rtype); rdata = rtype->limit = calloc(1, sizeof(resource_limit)); - rdata->value = 0; add_resource(u->region, 1, 300, 150, rtype); u->region->resources->amount = 300; /* there are 300 stones at level 1 */ set_level(u, SK_ALCHEMY, 10); diff --git a/src/kernel/resources.h b/src/kernel/resources.h index 3e93ea1de..d7c0e5bfd 100644 --- a/src/kernel/resources.h +++ b/src/kernel/resources.h @@ -58,7 +58,6 @@ extern "C" { typedef struct resource_limit { rlimit_limit limit; rlimit_produce produce; - int value; resource_mod *modifiers; } resource_limit; From d039ca2b2ed552d959da14712aa0a334b63d1946 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 25 Feb 2017 21:07:13 +0100 Subject: [PATCH 22/23] fix display of sapling and mallornsapling. remove mateiral from XML where it's not needed. --- res/core/de/strings.xml | 40 ++-------------------------------- res/core/resources/horse.xml | 2 +- res/core/resources/log.xml | 2 +- res/core/resources/mallorn.xml | 2 +- 4 files changed, 5 insertions(+), 41 deletions(-) diff --git a/res/core/de/strings.xml b/res/core/de/strings.xml index 5bde79c29..26e8cc862 100644 --- a/res/core/de/strings.xml +++ b/res/core/de/strings.xml @@ -6611,53 +6611,17 @@ EINLADEN INVITE - - Steine - stones - - - Pferde - horses - - - Bauern - peasants - - - Silber - silver - - - Laen - laen - - - + Schößlinge saplings - + Mallornschößlinge mallorn saplings - - Bäume - trees - - - - Mallorn - mallorn - - - - Eisen - iron - - Winter winter diff --git a/res/core/resources/horse.xml b/res/core/resources/horse.xml index 53699c696..d7f794491 100644 --- a/res/core/resources/horse.xml +++ b/res/core/resources/horse.xml @@ -1,5 +1,5 @@ - + diff --git a/res/core/resources/log.xml b/res/core/resources/log.xml index e3a33ef8b..48662878f 100644 --- a/res/core/resources/log.xml +++ b/res/core/resources/log.xml @@ -1,5 +1,5 @@ - + diff --git a/res/core/resources/mallorn.xml b/res/core/resources/mallorn.xml index fc678e79e..96892b802 100644 --- a/res/core/resources/mallorn.xml +++ b/res/core/resources/mallorn.xml @@ -1,5 +1,5 @@ - + From 84c6a4b7b56d1bd6b96a874d0e85e2126959fa14 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 25 Feb 2017 21:24:47 +0100 Subject: [PATCH 23/23] remove last vestiges of the rm_* material names --- clibs | 2 +- res/adamantium.xml | 2 +- res/core/resources/iron.xml | 2 +- res/core/resources/laen.xml | 2 +- res/core/resources/stone.xml | 2 +- res/e3a/resources/iron.xml | 2 +- res/e3a/resources/stone.xml | 2 +- src/economy.test.c | 3 +-- src/kernel/xmlreader.c | 4 +--- 9 files changed, 9 insertions(+), 12 deletions(-) diff --git a/clibs b/clibs index b91413316..27c8b3202 160000 --- a/clibs +++ b/clibs @@ -1 +1 @@ -Subproject commit b91413316ce13044c555084a9f605983586107b4 +Subproject commit 27c8b3202b52766465743c3324fc0b52c5ba4b11 diff --git a/res/adamantium.xml b/res/adamantium.xml index decc5636c..bb94dfc12 100644 --- a/res/adamantium.xml +++ b/res/adamantium.xml @@ -1,7 +1,7 @@ - + diff --git a/res/core/resources/iron.xml b/res/core/resources/iron.xml index 3f8897abc..469840669 100644 --- a/res/core/resources/iron.xml +++ b/res/core/resources/iron.xml @@ -1,5 +1,5 @@ - + diff --git a/res/core/resources/laen.xml b/res/core/resources/laen.xml index 12062bf07..30531c0fe 100644 --- a/res/core/resources/laen.xml +++ b/res/core/resources/laen.xml @@ -1,5 +1,5 @@ - + diff --git a/res/core/resources/stone.xml b/res/core/resources/stone.xml index c227dcc5c..91d3aac5d 100644 --- a/res/core/resources/stone.xml +++ b/res/core/resources/stone.xml @@ -1,5 +1,5 @@ - + diff --git a/res/e3a/resources/iron.xml b/res/e3a/resources/iron.xml index 06b70e45a..7ffe36f1e 100644 --- a/res/e3a/resources/iron.xml +++ b/res/e3a/resources/iron.xml @@ -1,5 +1,5 @@ - + diff --git a/res/e3a/resources/stone.xml b/res/e3a/resources/stone.xml index 746b79c21..dfb039093 100644 --- a/res/e3a/resources/stone.xml +++ b/res/e3a/resources/stone.xml @@ -1,5 +1,5 @@ - + diff --git a/src/economy.test.c b/src/economy.test.c index aea42491d..6d9c84542 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -348,7 +348,6 @@ static void test_make_item(CuTest *tc) { struct item_type *itype; const struct resource_type *rt_silver; resource_type *rtype; - rawmaterial_type *rmt; resource_limit *rdata; double d = 0.6; @@ -382,7 +381,7 @@ static void test_make_item(CuTest *tc) { free(itype->construction->materials); itype->construction->materials = 0; rtype->flags |= RTF_LIMITED; - rmt = rmt_create(rtype); + rmt_create(rtype); rdata = rtype->limit = calloc(1, sizeof(resource_limit)); add_resource(u->region, 1, 300, 150, rtype); u->region->resources->amount = 300; /* there are 300 stones at level 1 */ diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 74459270c..737a12f66 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -978,10 +978,8 @@ static int parse_resources(xmlDocPtr doc) } xmlXPathFreeObject(result); - name = xmlGetProp(node, BAD_CAST "material"); - if (name) { + if (xml_bvalue(node, "material", false)) { rmt_create(rtype); - xmlFree(name); } /* reading eressea/resources/resource/resourcelimit */