From beecc0e323afa5ac57c31f8318d2d0ba30f379fe Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 25 Jun 2017 14:07:50 +0200 Subject: [PATCH] BUG 2343: fix clone_men (hitpoints), add test. --- src/kernel/curse.c | 6 +++--- src/kernel/curse.h | 4 ++-- src/kernel/unit.c | 13 ++++++------- src/kernel/unit.h | 2 +- src/kernel/unit.test.c | 24 ++++++++++++++++++++++++ src/upkeep.c | 1 + 6 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 01e77eace..4a3e1c045 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -493,7 +493,7 @@ const curse_type * ct) /* ------------------------------------------------------------- */ /* gibt bei Personenbeschränkten Verzauberungen die Anzahl der * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ -int get_cursedmen(unit * u, const curse * c) +int get_cursedmen(const unit * u, const curse * c) { int cursedmen = u->number; @@ -631,7 +631,7 @@ curse *create_curse(unit * magician, attrib ** ap, const curse_type * ct, /* hier müssen alle c-typen, die auf Einheiten gezaubert werden können, * berücksichtigt werden */ -static void do_transfer_curse(curse * c, unit * u, unit * u2, int n) +static void do_transfer_curse(curse * c, const unit * u, unit * u2, int n) { int cursedmen = 0; int men = get_cursedmen(u, c); @@ -678,7 +678,7 @@ static void do_transfer_curse(curse * c, unit * u, unit * u2, int n) } } -void transfer_curse(unit * u, unit * u2, int n) +void transfer_curse(const unit * u, unit * u2, int n) { attrib *a; diff --git a/src/kernel/curse.h b/src/kernel/curse.h index 543755c2b..a4fd1c430 100644 --- a/src/kernel/curse.h +++ b/src/kernel/curse.h @@ -267,7 +267,7 @@ extern "C" { /* gibt bei Personenbeschränkten Verzauberungen die Anzahl der * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ - int get_cursedmen(struct unit *u, const struct curse *c); + int get_cursedmen(const struct unit *u, const struct curse *c); /* setzt/loescht Spezialflag einer Verzauberung (zB 'dauert ewig') */ void c_setflag(curse * c, unsigned int flag); @@ -277,7 +277,7 @@ extern "C" { * korrekt gehandhabt werden. Je nach internen Flag kann dies * unterschiedlich gewünscht sein * */ - void transfer_curse(struct unit *u, struct unit *u2, int n); + void transfer_curse(const struct unit *u, struct unit *u2, int n); /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, * oder einen NULL-pointer diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 7b6f135fc..bdd5ac232 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -981,10 +981,9 @@ void move_unit(unit * u, region * r, unit ** ulist) /* ist mist, aber wegen nicht skalierender attribute notwendig: */ #include "alchemy.h" -void clone_men(unit * u, unit * dst, int n) +void clone_men(const unit * u, unit * dst, int n) { const attrib *a; - int hp = u->hp; region *r = u->region; if (n == 0) @@ -1073,11 +1072,9 @@ void clone_men(unit * u, unit * dst, int n) if (u->attribs) { transfer_curse(u, dst, n); } - } - if (dst) { set_number(dst, dst->number + n); - hp -= u->hp; - dst->hp += hp; + dst->hp += u->hp * dst->number / u->number; + assert(dst->hp >= dst->number); /* TODO: Das ist schnarchlahm! und gehoert nicht hierhin */ a = a_find(dst->attribs, &at_effect); while (a && a->type == &at_effect) { @@ -1530,7 +1527,9 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace, /* u->race muss bereits gesetzt sein, wird fuer default-hp gebraucht */ /* u->region auch */ - u->hp = unit_max_hp(u) * number; + if (number > 0) { + u->hp = unit_max_hp(u) * number; + } if (dname) { u->_name = strdup(dname); diff --git a/src/kernel/unit.h b/src/kernel/unit.h index beea74ee7..dede956b5 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -166,7 +166,7 @@ extern "C" { void set_level(struct unit *u, skill_t id, int level); int get_level(const struct unit *u, skill_t id); void transfermen(struct unit *src, struct unit *dst, int n); - void clone_men(struct unit *src, struct unit *dst, int n); /* like transfer, but do not subtract from src */ + void clone_men(const struct unit *src, struct unit *dst, int n); /* like transfer, but do not subtract from src */ int eff_skill(const struct unit *u, const struct skill *sv, const struct region *r); int effskill_study(const struct unit *u, skill_t sk, const struct region *r); diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c index 54b07b63f..6ab8ee21a 100644 --- a/src/kernel/unit.test.c +++ b/src/kernel/unit.test.c @@ -525,6 +525,29 @@ static void test_unlimited_units(CuTest *tc) { test_cleanup(); } +static void test_clone_men(CuTest *tc) { + unit *u1, *u2; + region *r; + faction *f; + test_setup(); + r = test_create_region(0, 0, NULL); + f = test_create_faction(NULL); + u1 = test_create_unit(f, r); + scale_number(u1, 10); + u2 = test_create_unit(f, r); + scale_number(u2, 0); + CuAssertIntEquals(tc, 10, u1->number); + CuAssertIntEquals(tc, 200, u1->hp); + CuAssertIntEquals(tc, 0, u2->number); + CuAssertIntEquals(tc, 0, u2->hp); + clone_men(u1, u2, 1); + CuAssertIntEquals(tc, 10, u1->number); + CuAssertIntEquals(tc, 200, u1->hp); + CuAssertIntEquals(tc, 1, u2->number); + CuAssertIntEquals(tc, 20, u2->hp); + test_cleanup(); +} + CuSuite *get_unit_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -533,6 +556,7 @@ CuSuite *get_unit_suite(void) SUITE_ADD_TEST(suite, test_unit_name); SUITE_ADD_TEST(suite, test_unit_name_from_race); SUITE_ADD_TEST(suite, test_update_monster_name); + SUITE_ADD_TEST(suite, test_clone_men); SUITE_ADD_TEST(suite, test_remove_unit); SUITE_ADD_TEST(suite, test_remove_empty_units); SUITE_ADD_TEST(suite, test_remove_units_without_faction); diff --git a/src/upkeep.c b/src/upkeep.c index 8494d7f25..c4a937a45 100644 --- a/src/upkeep.c +++ b/src/upkeep.c @@ -191,6 +191,7 @@ void get_food(region * r) int need = lifestyle(u); faction *f = u->faction; + assert(u->hp > 0); need -= MAX(0, get_money(u)); if (need > 0) {