diff --git a/src/battle.c b/src/battle.c index b93ecb12f..b13c64b0d 100644 --- a/src/battle.c +++ b/src/battle.c @@ -778,7 +778,28 @@ int select_magicarmor(troop t) return ma; } -/* Sind side ds und Magier des meffect verbuendet, dann return 1*/ +int meffect_apply(struct meffect *me, int damage) { + assert(0 <= damage); /* damage sollte hier immer mindestens 0 sein */ + /* jeder Schaden wird um effect% reduziert bis der Schild duration + * Trefferpunkte aufgefangen hat */ + if (me->typ == SHIELD_REDUCE && me->effect <= 100) { + int hp = damage * me->effect / 100; + if (hp > me->duration) { + hp = me->duration; + } + damage -= hp; + me->duration -= hp; + } + /* gibt Ruestung +effect fuer duration Treffer */ + else if (me->typ == SHIELD_ARMOR) { + damage -= me->effect; + if (damage < 0) damage = 0; + me->duration--; + } + return damage; +} + +/* Sind side ds und Magier des meffect verbuendet? */ bool meffect_protection(battle * b, meffect * s, side * ds) { UNUSED_ARG(b); @@ -793,7 +814,7 @@ bool meffect_protection(battle * b, meffect * s, side * ds) return false; } -/* Sind side as und Magier des meffect verfeindet, dann return 1*/ +/* Sind side as und Magier des meffect verfeindet? */ bool meffect_blocked(battle * b, meffect * s, side * as) { UNUSED_ARG(b); @@ -1219,37 +1240,25 @@ static int apply_race_resistance(int reduced_damage, fighter *df, return reduced_damage; } -static int apply_magicshield(int reduced_damage, fighter *df, +static int apply_magicshield(int damage, fighter *df, const weapon_type *awtype, battle *b, bool magic) { side *ds = df->side; selist *ql; int qi; - if (reduced_damage <= 0) + if (damage <= 0) { return 0; + } /* Schilde */ for (qi = 0, ql = b->meffects; ql; selist_advance(&ql, &qi, 1)) { meffect *me = (meffect *)selist_get(ql, qi); if (meffect_protection(b, me, ds) != 0) { - assert(0 <= reduced_damage); /* rda sollte hier immer mindestens 0 sein */ - /* jeder Schaden wird um effect% reduziert bis der Schild duration - * Trefferpunkte aufgefangen hat */ - if (me->typ == SHIELD_REDUCE) { - int hp = reduced_damage * me->effect / 100; - reduced_damage -= hp; - me->duration -= hp; - } - /* gibt Ruestung +effect fuer duration Treffer */ - if (me->typ == SHIELD_ARMOR) { - reduced_damage -= me->effect; - if (reduced_damage < 0) reduced_damage = 0; - me->duration--; - } + damage = meffect_apply(me, damage); } } - return reduced_damage; + return damage; } bool diff --git a/src/battle.h b/src/battle.h index 83bcaf09a..da6fea9a9 100644 --- a/src/battle.h +++ b/src/battle.h @@ -254,6 +254,7 @@ extern "C" { void battle_message_faction(struct battle * b, struct faction * f, struct message *m); double tactics_chance(const struct unit *u, int skilldiff); + int meffect_apply(struct meffect *me, int damage); #ifdef __cplusplus } #endif diff --git a/src/battle.test.c b/src/battle.test.c index 665aeff1e..10bcae721 100644 --- a/src/battle.test.c +++ b/src/battle.test.c @@ -448,6 +448,30 @@ static void test_calculate_armor(CuTest * tc) test_teardown(); } +static void test_spells_reduce_damage(CuTest *tc) +{ + struct meffect me; + + me.typ = SHIELD_ARMOR; + me.duration = 10; + me.effect = 5; + CuAssertIntEquals(tc, 5, meffect_apply(&me, 10)); + CuAssertIntEquals(tc, 9, me.duration); + CuAssertIntEquals(tc, 5, me.effect); + CuAssertIntEquals(tc, 0, meffect_apply(&me, 1)); + CuAssertIntEquals(tc, 8, me.duration); + CuAssertIntEquals(tc, 5, me.effect); + + me.typ = SHIELD_REDUCE; + me.duration = 10; + me.effect = 50; + CuAssertIntEquals(tc, 5, meffect_apply(&me, 10)); + CuAssertIntEquals(tc, 5, me.duration); + CuAssertIntEquals(tc, 50, me.effect); + CuAssertIntEquals(tc, 7, meffect_apply(&me, 12)); + CuAssertIntEquals(tc, 0, me.duration); +} + static void test_magic_resistance(CuTest *tc) { troop dt; @@ -898,6 +922,7 @@ CuSuite *get_battle_suite(void) SUITE_ADD_TEST(suite, test_calculate_armor); SUITE_ADD_TEST(suite, test_natural_armor); SUITE_ADD_TEST(suite, test_magic_resistance); + SUITE_ADD_TEST(suite, test_spells_reduce_damage); SUITE_ADD_TEST(suite, test_projectile_armor); SUITE_ADD_TEST(suite, test_tactics_chance); SUITE_ADD_TEST(suite, test_terminate);