diff --git a/src/battle.c b/src/battle.c index 11d804efb..661982c3e 100644 --- a/src/battle.c +++ b/src/battle.c @@ -1012,8 +1012,9 @@ static int rc_specialdamage(const unit *au, const unit *du, const struct weapon_ } int calculate_armor(troop dt, const weapon_type *dwtype, const weapon_type *awtype, - const armor_type *armor, const armor_type *shield, bool magic) { - fighter *df = dt.fighter; + const armor_type *armor, const armor_type *shield, bool magic) { + + const fighter *df = dt.fighter; unit *du = df->unit; int total_armor = 0, nat_armor, magic_armor; bool missile = awtype && (awtype->flags&WTF_MISSILE); @@ -1067,31 +1068,35 @@ int calculate_armor(troop dt, const weapon_type *dwtype, const weapon_type *awty return total_armor; } -variant calculate_resistance(troop dt, const weapon_type *dwtype, const armor_type *armor, const armor_type *shield) { - fighter *df = dt.fighter; +int apply_resistance(int damage, troop dt, const weapon_type *dwtype, const armor_type *armor, const armor_type *shield, bool magic) { + const fighter *df = dt.fighter; unit *du = df->unit; + + if (!magic) + return damage; + /* calculate damage multiplier for magical damage */ - variant res; - - res = frac_sub(frac_one, magic_resistance(du)); + variant resistance_factor = 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 = frac_mul(res, frac_sub(frac_one, armor->magres)); + resistance_factor = frac_mul(resistance_factor, frac_sub(frac_one, armor->magres)); } if (shield && fval(shield, ATF_LAEN)) { - res = frac_mul(res, frac_sub(frac_one, shield->magres)); + resistance_factor = frac_mul(resistance_factor, frac_sub(frac_one, shield->magres)); } if (dwtype) { - res = frac_mul(res, frac_sub(frac_one, dwtype->magres)); + resistance_factor = frac_mul(resistance_factor, frac_sub(frac_one, dwtype->magres)); } } - if (res.sa[0] >= 0) { - return res; - } else { - return frac_zero; + if (resistance_factor.sa[0] <= 0) { + return 0; } + + variant reduced_damage = frac_mul(frac_make(damage, 1), resistance_factor); + return reduced_damage.sa[0] / reduced_damage.sa[1]; + } static bool resurrect_troop(troop dt) @@ -1129,10 +1134,9 @@ terminate(troop dt, troop at, int type, const char *damage_formula, bool missile const armor_type *armor = NULL; const armor_type *shield = NULL; - variant resistance_factor = frac_one; - - int reduced_damage, attskill = 0, defskill; + int reduced_damage, attskill = 0, defskill = 0; bool magic = false; + int damage = dice_rand(damage_formula); assert(du->number > 0); @@ -1171,17 +1175,11 @@ terminate(troop dt, troop at, int type, const char *damage_formula, bool missile shield = select_armor(dt, true); armor_value = calculate_armor(dt, dwtype, awtype, armor, shield, magic); - if (magic) { - resistance_factor = calculate_resistance(dt, dwtype, armor, shield); - } if (armor_value < 0) { return false; } - if (magic) { - variant reduced_damage = frac_mul(frac_make(damage, 1), resistance_factor); - damage = reduced_damage.sa[0] / reduced_damage.sa[1]; - } + damage = apply_resistance(damage, dt, dwtype, armor, shield, magic); if (type != AT_COMBATSPELL && type != AT_SPELL) { if (rule_damage & DAMAGE_CRITICAL) { diff --git a/src/battle.h b/src/battle.h index c747f49e5..a35a44a0f 100644 --- a/src/battle.h +++ b/src/battle.h @@ -236,7 +236,7 @@ extern "C" { const struct armor_type *select_armor(struct troop t, bool shield); struct weapon *select_weapon(const struct troop t, bool attacking, bool ismissile); int calculate_armor(troop dt, const struct weapon_type *dwtype, const struct weapon_type *awtype, const struct armor_type *armor, const struct armor_type *shield, bool magic); - union variant calculate_resistance(struct troop dt, const struct weapon_type *dwtype, const struct armor_type *armor, const struct armor_type *shield); + int apply_resistance(int damage, struct troop dt, const struct weapon_type *dwtype, const struct armor_type *armor, const struct armor_type *shield, bool magic); bool terminate(troop dt, troop at, int type, const char *damage, bool missile); void message_all(battle * b, struct message *m); diff --git a/src/battle.test.c b/src/battle.test.c index 3c35ef640..ba0807472 100644 --- a/src/battle.test.c +++ b/src/battle.test.c @@ -339,6 +339,16 @@ static void test_natural_armor(CuTest * tc) test_teardown(); } +static int test_armor(troop dt, weapon_type *awtype, bool magic) { + return calculate_armor(dt, 0, awtype, select_armor(dt, false), select_armor(dt, true), magic); +} + +static int test_resistance(troop dt) { + return apply_resistance(1000, dt, + select_weapon(dt, false, true) ? select_weapon(dt, false, true)->type : 0, + select_armor(dt, false), select_armor(dt, true), true); +} + static void test_calculate_armor(CuTest * tc) { troop dt; @@ -349,7 +359,6 @@ static void test_calculate_armor(CuTest * tc) armor_type *ashield, *achain; item_type *ibelt, *ishield, *ichain; race *rc; - variant magres = frac_zero; variant v50p = frac_make(1, 2); test_setup(); @@ -365,21 +374,19 @@ static void test_calculate_armor(CuTest * tc) dt.index = 0; dt.fighter = setup_fighter(&b, du); - CuAssertIntEquals_Msg(tc, "default ac", 0, calculate_armor(dt, 0, 0, select_armor(dt, false), select_armor(dt, true), false)); - magres = calculate_resistance(dt, - select_weapon(dt, false, true) ? select_weapon(dt, false, true)->type : 0, - select_armor(dt, false), select_armor(dt, true)); - CuAssertIntEquals_Msg(tc, "magres unmodified", magres.sa[0], magres.sa[1]); + CuAssertIntEquals_Msg(tc, "default ac", 0, test_armor(dt, 0, false)); + + CuAssertIntEquals_Msg(tc, "magres unmodified", 1000, test_resistance(dt)); free_battle(b); b = NULL; i_change(&du->items, ibelt, 1); dt.fighter = setup_fighter(&b, du); CuAssertIntEquals_Msg(tc, "without natural armor", 0, natural_armor(du)); - CuAssertIntEquals_Msg(tc, "magical armor", 1, calculate_armor(dt, 0, 0, select_armor(dt, false), select_armor(dt, true), false)); + CuAssertIntEquals_Msg(tc, "magical armor", 1, test_armor(dt, 0, false)); rc->armor = 2; CuAssertIntEquals_Msg(tc, "with natural armor", 2, natural_armor(du)); - CuAssertIntEquals_Msg(tc, "natural armor", 3, calculate_armor(dt, 0, 0, select_armor(dt, false), select_armor(dt, true), false)); + CuAssertIntEquals_Msg(tc, "natural armor", 3, test_armor(dt, 0, false)); rc->armor = 0; free_battle(b); @@ -388,35 +395,30 @@ static void test_calculate_armor(CuTest * tc) i_change(&du->items, ichain, 1); dt.fighter = setup_fighter(&b, du); rc->battle_flags &= ~BF_EQUIPMENT; - CuAssertIntEquals_Msg(tc, "require BF_EQUIPMENT", 1, calculate_armor(dt, 0, 0, select_armor(dt, false), select_armor(dt, true), false)); + CuAssertIntEquals_Msg(tc, "require BF_EQUIPMENT", 1, test_armor(dt, 0, false)); free_battle(b); b = NULL; rc->battle_flags |= BF_EQUIPMENT; dt.fighter = setup_fighter(&b, du); - CuAssertIntEquals_Msg(tc, "stack equipment rc", 5, calculate_armor(dt, 0, 0, select_armor(dt, false), select_armor(dt, true), false)); + CuAssertIntEquals_Msg(tc, "stack equipment rc", 5, test_armor(dt, 0, false)); rc->armor = 2; - CuAssertIntEquals_Msg(tc, "natural armor adds 50%", 6, calculate_armor(dt, 0, 0, select_armor(dt, false), select_armor(dt, true), false)); + CuAssertIntEquals_Msg(tc, "natural armor adds 50%", 6, test_armor(dt, 0, false)); wtype->flags = WTF_NONE; - CuAssertIntEquals_Msg(tc, "regular weapon has no effect", 6, calculate_armor(dt, 0, wtype, select_armor(dt, false), select_armor(dt, true), false)); + CuAssertIntEquals_Msg(tc, "regular weapon has no effect", 6, test_armor(dt, wtype, false)); wtype->flags = WTF_ARMORPIERCING; - CuAssertIntEquals_Msg(tc, "armor piercing weapon", 3, calculate_armor(dt, 0, wtype, select_armor(dt, false), select_armor(dt, true), false)); + CuAssertIntEquals_Msg(tc, "armor piercing weapon", 3, test_armor(dt, wtype, false)); wtype->flags = WTF_NONE; - CuAssertIntEquals_Msg(tc, "magical attack", 3, calculate_armor(dt, 0, 0, select_armor(dt, false), select_armor(dt, true), true)); - magres = calculate_resistance(dt, - select_weapon(dt, false, true) ? select_weapon(dt, false, true)->type : 0, - select_armor(dt, false), select_armor(dt, true)); - CuAssertIntEquals_Msg(tc, "magres unmodified", magres.sa[1], magres.sa[0]); + CuAssertIntEquals_Msg(tc, "magical attack", 3, test_armor(dt, wtype, true)); + CuAssertIntEquals_Msg(tc, "magres unmodified", 1000, + test_resistance(dt)); ashield->flags |= ATF_LAEN; achain->flags |= ATF_LAEN; - CuAssertIntEquals_Msg(tc, "laen armor", 3, calculate_armor(dt, 0, 0, select_armor(dt, false), select_armor(dt, true), true)); - magres = calculate_resistance(dt, - select_weapon(dt, false, true) ? select_weapon(dt, false, true)->type : 0, - select_armor(dt, false), select_armor(dt, true)); - CuAssertIntEquals_Msg(tc, "laen magres bonus", 4, magres.sa[1]); + CuAssertIntEquals_Msg(tc, "laen armor", 3, test_armor(dt, wtype, true)); + CuAssertIntEquals_Msg(tc, "laen magres bonus", 250, test_resistance(dt)); free_battle(b); test_teardown(); } @@ -446,19 +448,17 @@ static void test_magic_resistance(CuTest *tc) i_change(&du->items, ishield, 1); dt.fighter = setup_fighter(&b, du); - magres = calculate_resistance(dt, - select_weapon(dt, false, true) ? select_weapon(dt, false, true)->type : 0, - select_armor(dt, false), select_armor(dt, true)); - CuAssertIntEquals_Msg(tc, "no magres reduction", magres.sa[1], magres.sa[0]); + CuAssertIntEquals_Msg(tc, "no magres reduction", 1000, test_resistance(dt)); magres = magic_resistance(du); CuAssertIntEquals_Msg(tc, "no magres reduction", 0, magres.sa[0]); ashield->flags |= ATF_LAEN; ashield->magres = v10p; - magres = calculate_resistance(dt, - select_weapon(dt, false, true) ? select_weapon(dt, false, true)->type : 0, - select_armor(dt, false), select_armor(dt, true)); - CuAssert(tc, "laen reduction => 10%%", frac_equal(frac_make(9, 10), magres)); + CuAssertIntEquals_Msg(tc, "laen reduction => 10%%", 900, test_resistance(dt)); + CuAssertIntEquals_Msg(tc, "no magic, no resistance", 1000, + apply_resistance(1000, dt, + select_weapon(dt, false, true) ? select_weapon(dt, false, true)->type : 0, + select_armor(dt, false), select_armor(dt, true), false)); free_battle(b); b = NULL; @@ -468,10 +468,7 @@ static void test_magic_resistance(CuTest *tc) ashield->flags |= ATF_LAEN; ashield->magres = v10p; dt.fighter = setup_fighter(&b, du); - magres = calculate_resistance(dt, - select_weapon(dt, false, true) ? select_weapon(dt, false, true)->type : 0, - select_armor(dt, false), select_armor(dt, true)); - CuAssert(tc, "2x laen reduction => 81%%", frac_equal(frac_make(81, 100), magres)); + CuAssertIntEquals_Msg(tc, "2x laen reduction => 81%%", 810, test_resistance(dt)); free_battle(b); b = NULL; @@ -479,27 +476,18 @@ static void test_magic_resistance(CuTest *tc) i_change(&du->items, ichain, -1); set_level(du, SK_MAGIC, 2); dt.fighter = setup_fighter(&b, du); - magres = calculate_resistance(dt, - select_weapon(dt, false, true) ? select_weapon(dt, false, true)->type : 0, - select_armor(dt, false), select_armor(dt, true)); - CuAssert(tc, "skill reduction => 90%%", frac_equal(magres, frac_make(9, 10))); + CuAssertIntEquals_Msg(tc, "skill reduction => 90%%", 900, test_resistance(dt)); magres = magic_resistance(du); CuAssert(tc, "skill reduction", frac_equal(magres, v10p)); rc->magres = v50p; /* percentage, gets added to skill bonus */ - magres = calculate_resistance(dt, - select_weapon(dt, false, true) ? select_weapon(dt, false, true)->type : 0, - select_armor(dt, false), select_armor(dt, true)); - CuAssert(tc, "race reduction => 40%%", frac_equal(magres, frac_make(4, 10))); + CuAssertIntEquals_Msg(tc, "race reduction => 40%%", 400, test_resistance(dt)); magres = magic_resistance(du); CuAssert(tc, "race bonus => 60%%", frac_equal(magres, frac_make(60, 100))); 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))); - magres = calculate_resistance(dt, - select_weapon(dt, false, true) ? select_weapon(dt, false, true)->type : 0, - select_armor(dt, false), select_armor(dt, true)); - CuAssert(tc, "damage reduction is never < 0.1", frac_equal(magres, frac_make(1, 10))); + CuAssertIntEquals_Msg(tc, "damage reduction is never < 0.1", 100, test_resistance(dt)); free_battle(b); test_teardown(); @@ -534,12 +522,12 @@ static void test_projectile_armor(CuTest * tc) dt.fighter = setup_fighter(&b, du); wtype->flags = WTF_MISSILE; achain->projectile = 1.0; - CuAssertIntEquals_Msg(tc, "projectile armor", -1, calculate_armor(dt, 0, wtype, select_armor(dt, false), select_armor(dt, true), false)); + CuAssertIntEquals_Msg(tc, "projectile armor", -1, test_armor(dt, wtype, false)); achain->projectile = 0.0; ashield->projectile = 1.0; - CuAssertIntEquals_Msg(tc, "projectile shield", -1, calculate_armor(dt, 0, wtype, select_armor(dt, false), select_armor(dt, true), false)); + CuAssertIntEquals_Msg(tc, "projectile shield", -1, test_armor(dt, wtype, false)); wtype->flags = WTF_NONE; - CuAssertIntEquals_Msg(tc, "no projectiles", 4, calculate_armor(dt, 0, wtype, select_armor(dt, false), select_armor(dt, true), false)); + CuAssertIntEquals_Msg(tc, "no projectiles", 4, test_armor(dt, wtype, false)); free_battle(b); test_teardown(); }