forked from github/server
refactor calculate_armor
This commit is contained in:
parent
c15b4c8fbf
commit
d981044953
3 changed files with 61 additions and 75 deletions
46
src/battle.c
46
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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue