refactor calculate_armor

This commit is contained in:
Steffen Mecke 2018-09-12 09:37:22 +02:00
parent c15b4c8fbf
commit d981044953
3 changed files with 61 additions and 75 deletions

View File

@ -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;
/* calculate damage multiplier for magical damage */
variant res;
res = frac_sub(frac_one, magic_resistance(du));
if (!magic)
return damage;
/* calculate damage multiplier for magical damage */
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) {

View File

@ -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);

View File

@ -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();
}