forked from github/server
Merge pull request #801 from stm2/bug2480
fix magic resistance (bug 2480)
This commit is contained in:
commit
576ddb6652
|
@ -136,3 +136,15 @@ function test_familiar_lynx()
|
||||||
assert_equal(1, u:get_skill('magic'))
|
assert_equal(1, u:get_skill('magic'))
|
||||||
assert_equal(1, u:get_skill('perception'))
|
assert_equal(1, u:get_skill('perception'))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function test_bug_2480()
|
||||||
|
local r = region.create(0, 0, "plain")
|
||||||
|
local f = faction.create("human", "2480@eressea.de", "de")
|
||||||
|
local u1 = unit.create(f, r, 1)
|
||||||
|
local monster = unit.create(get_monsters(), r, 1, "wyrm")
|
||||||
|
u1.number = 30
|
||||||
|
u1.hp = u1.hp_max * u1.number
|
||||||
|
monster:add_order("ATTACK " .. itoa36(u1.id))
|
||||||
|
process_orders()
|
||||||
|
assert_equal(0, u1.number);
|
||||||
|
end
|
||||||
|
|
464
src/battle.c
464
src/battle.c
|
@ -120,7 +120,7 @@ const troop no_troop = { 0, 0 };
|
||||||
|
|
||||||
#define DAMAGE_CRITICAL (1<<0)
|
#define DAMAGE_CRITICAL (1<<0)
|
||||||
#define DAMAGE_MELEE_BONUS (1<<1)
|
#define DAMAGE_MELEE_BONUS (1<<1)
|
||||||
#define DAMAGE_MISSILE_BONUS (1<<2)
|
#define DAMAGE_MISSILE_BONUS (1<<2) /* deprecated */
|
||||||
#define DAMAGE_SKILL_BONUS (1<<4)
|
#define DAMAGE_SKILL_BONUS (1<<4)
|
||||||
|
|
||||||
static int max_turns;
|
static int max_turns;
|
||||||
|
@ -173,7 +173,7 @@ static void init_rules(void)
|
||||||
if (config_get_int("rules.combat.melee_bonus", 1)) {
|
if (config_get_int("rules.combat.melee_bonus", 1)) {
|
||||||
rule_damage |= DAMAGE_MELEE_BONUS;
|
rule_damage |= DAMAGE_MELEE_BONUS;
|
||||||
}
|
}
|
||||||
if (config_get_int("rules.combat.missile_bonus", 1)) {
|
if (config_get_int("rules.combat.missile_bonus", 1)) { /* deprecated */
|
||||||
rule_damage |= DAMAGE_MISSILE_BONUS;
|
rule_damage |= DAMAGE_MISSILE_BONUS;
|
||||||
}
|
}
|
||||||
if (config_get_int("rules.combat.skill_bonus", 1)) {
|
if (config_get_int("rules.combat.skill_bonus", 1)) {
|
||||||
|
@ -559,8 +559,7 @@ static weapon *preferred_weapon(const troop t, bool attacking)
|
||||||
return melee;
|
return melee;
|
||||||
}
|
}
|
||||||
|
|
||||||
static weapon *select_weapon(const troop t, bool attacking,
|
weapon *select_weapon(const troop t, bool attacking, bool ismissile)
|
||||||
bool ismissile)
|
|
||||||
/* select the primary weapon for this trooper */
|
/* select the primary weapon for this trooper */
|
||||||
{
|
{
|
||||||
if (attacking) {
|
if (attacking) {
|
||||||
|
@ -774,7 +773,7 @@ bool missile)
|
||||||
return skill;
|
return skill;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const armor_type *select_armor(troop t, bool shield)
|
const armor_type *select_armor(troop t, bool shield)
|
||||||
{
|
{
|
||||||
unsigned int type = shield ? ATF_SHIELD : 0;
|
unsigned int type = shield ? ATF_SHIELD : 0;
|
||||||
unit *u = t.fighter->unit;
|
unit *u = t.fighter->unit;
|
||||||
|
@ -954,6 +953,9 @@ void drain_exp(struct unit *u, int n)
|
||||||
|
|
||||||
static void vampirism(troop at, int damage)
|
static void vampirism(troop at, int damage)
|
||||||
{
|
{
|
||||||
|
const unit *au = at.fighter->unit;
|
||||||
|
|
||||||
|
if (u_race(au) == get_race(RC_DAEMON)) {
|
||||||
if (rule_vampire > 0) {
|
if (rule_vampire > 0) {
|
||||||
int gain = damage / rule_vampire;
|
int gain = damage / rule_vampire;
|
||||||
int chance = damage - rule_vampire * gain;
|
int chance = damage - rule_vampire * gain;
|
||||||
|
@ -968,6 +970,16 @@ static void vampirism(troop at, int damage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ship_damage(int turn, unit *du) {
|
||||||
|
if (turn>1) {
|
||||||
|
/* someone on the ship got damaged, damage the ship */
|
||||||
|
ship *sh = du->ship ? du->ship : leftship(du);
|
||||||
|
if (sh)
|
||||||
|
fset(sh, SF_DAMAGED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define MAXRACES 128
|
#define MAXRACES 128
|
||||||
|
|
||||||
|
@ -1016,85 +1028,94 @@ static int rc_specialdamage(const unit *au, const unit *du, const struct weapon_
|
||||||
return modifier;
|
return modifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
int calculate_armor(troop dt, const weapon_type *dwtype, const weapon_type *awtype, variant *magres) {
|
int calculate_armor(troop dt, const weapon_type *dwtype, const weapon_type *awtype,
|
||||||
fighter *df = dt.fighter;
|
const armor_type *armor, const armor_type *shield, bool magic) {
|
||||||
|
|
||||||
|
const fighter *df = dt.fighter;
|
||||||
unit *du = df->unit;
|
unit *du = df->unit;
|
||||||
int ar = 0, an, am;
|
int total_armor = 0, nat_armor, magic_armor;
|
||||||
const armor_type *armor = select_armor(dt, false);
|
|
||||||
const armor_type *shield = select_armor(dt, true);
|
|
||||||
bool missile = awtype && (awtype->flags&WTF_MISSILE);
|
bool missile = awtype && (awtype->flags&WTF_MISSILE);
|
||||||
|
|
||||||
if (armor) {
|
if (armor) {
|
||||||
ar += armor->prot;
|
total_armor += armor->prot;
|
||||||
if (missile && armor->projectile > 0 && chance(armor->projectile)) {
|
if (missile && armor->projectile > 0 && chance(armor->projectile)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (shield) {
|
if (shield) {
|
||||||
ar += shield->prot;
|
total_armor += shield->prot;
|
||||||
if (missile && shield->projectile > 0 && chance(shield->projectile)) {
|
if (missile && shield->projectile > 0 && chance(shield->projectile)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (magic) {
|
||||||
|
/* gegen Magie wirkt nur natuerliche und magische Ruestung */
|
||||||
|
total_armor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* nat<61>rliche R<>stung */
|
/* nat<61>rliche R<>stung */
|
||||||
an = natural_armor(du);
|
nat_armor = natural_armor(du);
|
||||||
|
|
||||||
/* magische R<>stung durch Artefakte oder Spr<70>che */
|
/* magische R<>stung durch Artefakte oder Spr<70>che */
|
||||||
/* Momentan nur Trollg<6C>rtel und Werwolf-Eigenschaft */
|
/* Momentan nur Trollg<6C>rtel und Werwolf-Eigenschaft */
|
||||||
am = select_magicarmor(dt);
|
magic_armor = select_magicarmor(dt);
|
||||||
|
|
||||||
if (rule_nat_armor == 0) {
|
if (rule_nat_armor == 0) {
|
||||||
/* nat<61>rliche R<>stung ist halbkumulativ */
|
/* nat<61>rliche R<>stung ist halbkumulativ */
|
||||||
if (ar > 0) {
|
if (total_armor > 0) {
|
||||||
ar += an / 2;
|
total_armor += nat_armor / 2;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ar = an;
|
total_armor = nat_armor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* use the higher value, add half the other value */
|
/* use the higher value, add half the other value */
|
||||||
ar = (ar > an) ? (ar + an / 2) : (an + ar / 2);
|
total_armor = (total_armor > nat_armor) ? (total_armor + nat_armor / 2) : (nat_armor + total_armor / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (awtype && fval(awtype, WTF_ARMORPIERCING)) {
|
if (awtype && fval(awtype, WTF_ARMORPIERCING)) {
|
||||||
/* crossbows */
|
/* crossbows */
|
||||||
ar /= 2;
|
total_armor /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
ar += am;
|
total_armor += magic_armor;
|
||||||
|
|
||||||
|
assert(total_armor >= 0 || !"armor < 0 means hit denied");
|
||||||
|
|
||||||
|
return total_armor;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
if (magres) {
|
|
||||||
/* calculate damage multiplier for magical damage */
|
/* calculate damage multiplier for magical damage */
|
||||||
variant res;
|
variant resistance_factor = frac_sub(frac_one, magic_resistance(du));
|
||||||
|
|
||||||
res = frac_sub(frac_one, magic_resistance(du));
|
|
||||||
|
|
||||||
if (u_race(du)->battle_flags & BF_EQUIPMENT) {
|
if (u_race(du)->battle_flags & BF_EQUIPMENT) {
|
||||||
/* der Effekt von Laen steigt nicht linear */
|
/* der Effekt von Laen steigt nicht linear */
|
||||||
if (armor && fval(armor, ATF_LAEN)) {
|
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)) {
|
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) {
|
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 (resistance_factor.sa[0] <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* gegen Magie wirkt nur natuerliche und magische Ruestung */
|
variant reduced_damage = frac_mul(frac_make(damage, 1), resistance_factor);
|
||||||
ar = an + am;
|
return reduced_damage.sa[0] / reduced_damage.sa[1];
|
||||||
if (res.sa[0] >= 0) {
|
|
||||||
*magres = res;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*magres = frac_make(0, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ar;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool resurrect_troop(troop dt)
|
static bool resurrect_troop(troop dt)
|
||||||
|
@ -1112,174 +1133,30 @@ static bool resurrect_troop(troop dt)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static void demon_dazzle(fighter *af, troop dt) {
|
||||||
terminate(troop dt, troop at, int type, const char *damage, bool missile)
|
const fighter *df = dt.fighter;
|
||||||
{
|
if (u_race(af->unit) == get_race(RC_DAEMON)) {
|
||||||
item **pitm;
|
|
||||||
fighter *df = dt.fighter;
|
|
||||||
fighter *af = at.fighter;
|
|
||||||
unit *au = af->unit;
|
|
||||||
unit *du = df->unit;
|
|
||||||
battle *b = df->side->battle;
|
|
||||||
|
|
||||||
/* Schild */
|
|
||||||
side *ds = df->side;
|
|
||||||
int ar;
|
|
||||||
|
|
||||||
const weapon_type *dwtype = NULL;
|
|
||||||
const weapon_type *awtype = NULL;
|
|
||||||
const weapon *weapon;
|
|
||||||
variant res = frac_one;
|
|
||||||
|
|
||||||
int rda, sk = 0, sd;
|
|
||||||
bool magic = false;
|
|
||||||
int da = dice_rand(damage);
|
|
||||||
|
|
||||||
assert(du->number > 0);
|
|
||||||
++at.fighter->hits;
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case AT_STANDARD:
|
|
||||||
weapon = select_weapon(at, true, missile);
|
|
||||||
sk = weapon_effskill(at, dt, weapon, true, missile);
|
|
||||||
if (weapon)
|
|
||||||
awtype = weapon->type;
|
|
||||||
if (awtype && fval(awtype, WTF_MAGICAL))
|
|
||||||
magic = true;
|
|
||||||
break;
|
|
||||||
case AT_NATURAL:
|
|
||||||
sk = weapon_effskill(at, dt, NULL, true, missile);
|
|
||||||
break;
|
|
||||||
case AT_SPELL:
|
|
||||||
case AT_COMBATSPELL:
|
|
||||||
magic = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
weapon = select_weapon(dt, false, true); /* missile=true to get the unmodified best weapon she has */
|
|
||||||
sd = weapon_effskill(dt, at, weapon, false, false);
|
|
||||||
if (weapon != NULL)
|
|
||||||
dwtype = weapon->type;
|
|
||||||
|
|
||||||
if (is_riding(at) && (awtype == NULL || (fval(awtype, WTF_HORSEBONUS)
|
|
||||||
&& !fval(awtype, WTF_MISSILE)))) {
|
|
||||||
da += CavalryBonus(au, dt, BONUS_DAMAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
ar = calculate_armor(dt, dwtype, awtype, magic ? &res : 0);
|
|
||||||
if (ar < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (magic) {
|
|
||||||
res = frac_sub(frac_one, res);
|
|
||||||
res = frac_mul(frac_make(da, 1), res);
|
|
||||||
da = res.sa[0] / res.sa[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type != AT_COMBATSPELL && type != AT_SPELL) {
|
|
||||||
if (rule_damage & DAMAGE_CRITICAL) {
|
|
||||||
double kritchance = (sk * 3 - sd) / 200.0;
|
|
||||||
int maxk = 4;
|
|
||||||
|
|
||||||
kritchance = fmax(kritchance, 0.005);
|
|
||||||
kritchance = fmin(0.9, kritchance);
|
|
||||||
|
|
||||||
while (maxk-- && chance(kritchance)) {
|
|
||||||
da += dice_rand(damage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
da += rc_specialdamage(au, du, awtype);
|
|
||||||
|
|
||||||
if (awtype != NULL && fval(awtype, WTF_MISSILE)) {
|
|
||||||
/* missile weapon bonus */
|
|
||||||
if (rule_damage & DAMAGE_MISSILE_BONUS) {
|
|
||||||
da += af->person[at.index].damage_rear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* melee bonus */
|
|
||||||
if (rule_damage & DAMAGE_MELEE_BONUS) {
|
|
||||||
da += af->person[at.index].damage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Skilldifferenzbonus */
|
|
||||||
if (rule_damage & DAMAGE_SKILL_BONUS) {
|
|
||||||
da += MAX(0, (sk - sd) / DAMAGE_QUOTIENT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rda = MAX(da - ar, 0);
|
|
||||||
|
|
||||||
if ((u_race(du)->battle_flags & BF_INV_NONMAGIC) && !magic)
|
|
||||||
rda = 0;
|
|
||||||
else {
|
|
||||||
int qi;
|
|
||||||
selist *ql;
|
|
||||||
unsigned int i = 0;
|
|
||||||
|
|
||||||
if (u_race(du)->battle_flags & BF_RES_PIERCE)
|
|
||||||
i |= WTF_PIERCE;
|
|
||||||
if (u_race(du)->battle_flags & BF_RES_CUT)
|
|
||||||
i |= WTF_CUT;
|
|
||||||
if (u_race(du)->battle_flags & BF_RES_BASH)
|
|
||||||
i |= WTF_BLUNT;
|
|
||||||
|
|
||||||
if (i && awtype && fval(awtype, i))
|
|
||||||
rda /= 2;
|
|
||||||
|
|
||||||
/* 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 <= rda); /* 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 = rda * (me->effect / 100);
|
|
||||||
rda -= hp;
|
|
||||||
me->duration -= hp;
|
|
||||||
}
|
|
||||||
/* gibt R<>stung +effect f<>r duration Treffer */
|
|
||||||
if (me->typ == SHIELD_ARMOR) {
|
|
||||||
rda = MAX(rda - me->effect, 0);
|
|
||||||
me->duration--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(dt.index >= 0 && dt.index < du->number);
|
|
||||||
if (rda>0) {
|
|
||||||
df->person[dt.index].hp -= rda;
|
|
||||||
if (u_race(au) == get_race(RC_DAEMON)) {
|
|
||||||
vampirism(at, rda);
|
|
||||||
}
|
|
||||||
if (b->turn>1) {
|
|
||||||
/* someone on the ship got damaged, damage the ship */
|
|
||||||
ship *sh = du->ship ? du->ship : leftship(du);
|
|
||||||
if (sh)
|
|
||||||
fset(sh, SF_DAMAGED);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (df->person[dt.index].hp > 0) { /* Hat <20>berlebt */
|
|
||||||
if (u_race(au) == get_race(RC_DAEMON)) {
|
|
||||||
if (!(df->person[dt.index].flags & (FL_COURAGE | FL_DAZZLED))) {
|
if (!(df->person[dt.index].flags & (FL_COURAGE | FL_DAZZLED))) {
|
||||||
df->person[dt.index].flags |= FL_DAZZLED;
|
df->person[dt.index].flags |= FL_DAZZLED;
|
||||||
df->person[dt.index].defence--;
|
df->person[dt.index].defence--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
static bool survives(fighter *af, troop dt, battle *b) {
|
||||||
|
const unit *du = af->unit;
|
||||||
|
const fighter *df = dt.fighter;
|
||||||
|
|
||||||
|
if (df->person[dt.index].hp > 0) { /* Hat <20>berlebt */
|
||||||
|
demon_dazzle(af, dt);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sieben Leben */
|
/* Sieben Leben */
|
||||||
if (u_race(du) == get_race(RC_CAT) && (chance(1.0 / 7))) {
|
if (u_race(du) == get_race(RC_CAT) && (chance(1.0 / 7))) {
|
||||||
df->person[dt.index].hp = unit_max_hp(du);
|
df->person[dt.index].hp = unit_max_hp(du);
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* healing potions can avert a killing blow */
|
/* healing potions can avert a killing blow */
|
||||||
|
@ -1287,9 +1164,16 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile)
|
||||||
message *m = msg_message("potionsave", "unit", du);
|
message *m = msg_message("potionsave", "unit", du);
|
||||||
battle_message_faction(b, du->faction, m);
|
battle_message_faction(b, du->faction, m);
|
||||||
msg_release(m);
|
msg_release(m);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
++at.fighter->kills;
|
|
||||||
|
static void destroy_items(troop dt) {
|
||||||
|
unit *du = dt.fighter->unit;
|
||||||
|
|
||||||
|
item **pitm;
|
||||||
|
|
||||||
for (pitm = &du->items; *pitm;) {
|
for (pitm = &du->items; *pitm;) {
|
||||||
item *itm = *pitm;
|
item *itm = *pitm;
|
||||||
|
@ -1304,6 +1188,194 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile)
|
||||||
pitm = &itm->next;
|
pitm = &itm->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void calculate_defence_type(troop dt, troop at, int type, bool missile,
|
||||||
|
const weapon_type **dwtype, int *defskill) {
|
||||||
|
const weapon *weapon;
|
||||||
|
weapon = select_weapon(dt, false, true); /* missile=true to get the unmodified best weapon she has */
|
||||||
|
*defskill = weapon_effskill(dt, at, weapon, false, false);
|
||||||
|
if (weapon != NULL)
|
||||||
|
*dwtype = weapon->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void calculate_attack_type(troop dt, troop at, int type, bool missile,
|
||||||
|
const weapon_type **awtype, int *attskill, bool *magic) {
|
||||||
|
const weapon *weapon;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case AT_STANDARD:
|
||||||
|
weapon = select_weapon(at, true, missile);
|
||||||
|
*attskill = weapon_effskill(at, dt, weapon, true, missile);
|
||||||
|
if (weapon)
|
||||||
|
*awtype = weapon->type;
|
||||||
|
if (*awtype && fval(*awtype, WTF_MAGICAL))
|
||||||
|
*magic = true;
|
||||||
|
break;
|
||||||
|
case AT_NATURAL:
|
||||||
|
*attskill = weapon_effskill(at, dt, NULL, true, missile);
|
||||||
|
break;
|
||||||
|
case AT_SPELL:
|
||||||
|
case AT_COMBATSPELL:
|
||||||
|
*magic = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int crit_damage(int attskill, int defskill, const char *damage_formula) {
|
||||||
|
int damage = 0;
|
||||||
|
if (rule_damage & DAMAGE_CRITICAL) {
|
||||||
|
double kritchance = (attskill * 3 - defskill) / 200.0;
|
||||||
|
int maxk = 4;
|
||||||
|
|
||||||
|
kritchance = fmax(kritchance, 0.005);
|
||||||
|
kritchance = fmin(0.9, kritchance);
|
||||||
|
|
||||||
|
while (maxk-- && chance(kritchance)) {
|
||||||
|
damage += dice_rand(damage_formula);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return damage;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apply_race_resistance(int reduced_damage, fighter *df,
|
||||||
|
const weapon_type *awtype, bool magic) {
|
||||||
|
unit *du = df->unit;
|
||||||
|
|
||||||
|
if ((u_race(du)->battle_flags & BF_INV_NONMAGIC) && !magic)
|
||||||
|
reduced_damage = 0;
|
||||||
|
else {
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
if (u_race(du)->battle_flags & BF_RES_PIERCE)
|
||||||
|
i |= WTF_PIERCE;
|
||||||
|
if (u_race(du)->battle_flags & BF_RES_CUT)
|
||||||
|
i |= WTF_CUT;
|
||||||
|
if (u_race(du)->battle_flags & BF_RES_BASH)
|
||||||
|
i |= WTF_BLUNT;
|
||||||
|
|
||||||
|
if (i && awtype && fval(awtype, i))
|
||||||
|
reduced_damage /= 2;
|
||||||
|
}
|
||||||
|
return reduced_damage;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apply_magicshield(int reduced_damage, fighter *df,
|
||||||
|
const weapon_type *awtype, battle *b, bool magic) {
|
||||||
|
side *ds = df->side;
|
||||||
|
selist *ql;
|
||||||
|
int qi;
|
||||||
|
|
||||||
|
if (reduced_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 R<>stung +effect f<>r duration Treffer */
|
||||||
|
if (me->typ == SHIELD_ARMOR) {
|
||||||
|
reduced_damage = MAX(reduced_damage - me->effect, 0);
|
||||||
|
me->duration--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return reduced_damage;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
terminate(troop dt, troop at, int type, const char *damage_formula, bool missile)
|
||||||
|
{
|
||||||
|
fighter *df = dt.fighter;
|
||||||
|
fighter *af = at.fighter;
|
||||||
|
unit *au = af->unit;
|
||||||
|
unit *du = df->unit;
|
||||||
|
battle *b = df->side->battle;
|
||||||
|
|
||||||
|
int armor_value;
|
||||||
|
|
||||||
|
const weapon_type *dwtype = NULL;
|
||||||
|
const weapon_type *awtype = NULL;
|
||||||
|
const armor_type *armor = NULL;
|
||||||
|
const armor_type *shield = NULL;
|
||||||
|
|
||||||
|
int reduced_damage, attskill = 0, defskill = 0;
|
||||||
|
bool magic = false;
|
||||||
|
|
||||||
|
int damage = dice_rand(damage_formula);
|
||||||
|
|
||||||
|
assert(du->number > 0);
|
||||||
|
++at.fighter->hits;
|
||||||
|
|
||||||
|
calculate_attack_type(at, dt, type, missile, &awtype, &attskill, &magic);
|
||||||
|
calculate_defence_type(at, dt, type, missile, &awtype, &attskill);
|
||||||
|
|
||||||
|
if (is_riding(at) && (awtype == NULL || (fval(awtype, WTF_HORSEBONUS)
|
||||||
|
&& !fval(awtype, WTF_MISSILE)))) {
|
||||||
|
damage += CavalryBonus(au, dt, BONUS_DAMAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
armor = select_armor(dt, false);
|
||||||
|
shield = select_armor(dt, true);
|
||||||
|
|
||||||
|
armor_value = calculate_armor(dt, dwtype, awtype, armor, shield, magic);
|
||||||
|
if (armor_value < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
damage = apply_resistance(damage, dt, dwtype, armor, shield, magic);
|
||||||
|
|
||||||
|
if (type != AT_COMBATSPELL && type != AT_SPELL) {
|
||||||
|
damage += crit_damage(attskill, defskill, damage_formula);
|
||||||
|
|
||||||
|
damage += rc_specialdamage(au, du, awtype);
|
||||||
|
|
||||||
|
if (awtype == NULL || !fval(awtype, WTF_MISSILE)) {
|
||||||
|
/* melee bonus */
|
||||||
|
if (rule_damage & DAMAGE_MELEE_BONUS) {
|
||||||
|
damage += af->person[at.index].damage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skilldifferenzbonus */
|
||||||
|
if (rule_damage & DAMAGE_SKILL_BONUS) {
|
||||||
|
damage += MAX(0, (attskill - defskill) / DAMAGE_QUOTIENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reduced_damage = MAX(damage - armor_value, 0);
|
||||||
|
|
||||||
|
reduced_damage = apply_race_resistance(reduced_damage, df, awtype, magic);
|
||||||
|
reduced_damage = apply_magicshield(reduced_damage, df, awtype, b, magic);
|
||||||
|
|
||||||
|
assert(dt.index >= 0 && dt.index < du->number);
|
||||||
|
if (reduced_damage > 0) {
|
||||||
|
df->person[dt.index].hp -= reduced_damage;
|
||||||
|
|
||||||
|
vampirism(at, reduced_damage);
|
||||||
|
|
||||||
|
ship_damage(b->turn, du);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (survives(af, dt, b))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
++at.fighter->kills;
|
||||||
|
|
||||||
|
destroy_items(dt);
|
||||||
|
|
||||||
kill_troop(dt);
|
kill_troop(dt);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -175,7 +175,6 @@ extern "C" {
|
||||||
int attack;
|
int attack;
|
||||||
int defence;
|
int defence;
|
||||||
int damage;
|
int damage;
|
||||||
int damage_rear;
|
|
||||||
int flags;
|
int flags;
|
||||||
int speed;
|
int speed;
|
||||||
int reload;
|
int reload;
|
||||||
|
@ -233,7 +232,10 @@ extern "C" {
|
||||||
int count_enemies(struct battle *b, const struct fighter *af,
|
int count_enemies(struct battle *b, const struct fighter *af,
|
||||||
int minrow, int maxrow, int select);
|
int minrow, int maxrow, int select);
|
||||||
int natural_armor(struct unit * u);
|
int natural_armor(struct unit * u);
|
||||||
int calculate_armor(troop dt, const struct weapon_type *dwtype, const struct weapon_type *awtype, union variant *magres);
|
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);
|
||||||
|
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 terminate(troop dt, troop at, int type, const char *damage,
|
||||||
bool missile);
|
bool missile);
|
||||||
void message_all(battle * b, struct message *m);
|
void message_all(battle * b, struct message *m);
|
||||||
|
|
|
@ -358,6 +358,16 @@ static void test_natural_armor(CuTest * tc)
|
||||||
test_teardown();
|
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)
|
static void test_calculate_armor(CuTest * tc)
|
||||||
{
|
{
|
||||||
troop dt;
|
troop dt;
|
||||||
|
@ -368,7 +378,6 @@ static void test_calculate_armor(CuTest * tc)
|
||||||
armor_type *ashield, *achain;
|
armor_type *ashield, *achain;
|
||||||
item_type *ibelt, *ishield, *ichain;
|
item_type *ibelt, *ishield, *ichain;
|
||||||
race *rc;
|
race *rc;
|
||||||
variant magres = frac_zero;
|
|
||||||
variant v50p = frac_make(1, 2);
|
variant v50p = frac_make(1, 2);
|
||||||
|
|
||||||
test_setup();
|
test_setup();
|
||||||
|
@ -384,18 +393,19 @@ static void test_calculate_armor(CuTest * tc)
|
||||||
dt.index = 0;
|
dt.index = 0;
|
||||||
|
|
||||||
dt.fighter = setup_fighter(&b, du);
|
dt.fighter = setup_fighter(&b, du);
|
||||||
CuAssertIntEquals_Msg(tc, "default ac", 0, calculate_armor(dt, 0, 0, &magres));
|
CuAssertIntEquals_Msg(tc, "default ac", 0, test_armor(dt, 0, false));
|
||||||
CuAssertIntEquals_Msg(tc, "magres unmodified", magres.sa[0], magres.sa[1]);
|
|
||||||
|
CuAssertIntEquals_Msg(tc, "magres unmodified", 1000, test_resistance(dt));
|
||||||
free_battle(b);
|
free_battle(b);
|
||||||
|
|
||||||
b = NULL;
|
b = NULL;
|
||||||
i_change(&du->items, ibelt, 1);
|
i_change(&du->items, ibelt, 1);
|
||||||
dt.fighter = setup_fighter(&b, du);
|
dt.fighter = setup_fighter(&b, du);
|
||||||
CuAssertIntEquals_Msg(tc, "without natural armor", 0, natural_armor(du));
|
CuAssertIntEquals_Msg(tc, "without natural armor", 0, natural_armor(du));
|
||||||
CuAssertIntEquals_Msg(tc, "magical armor", 1, calculate_armor(dt, 0, 0, 0));
|
CuAssertIntEquals_Msg(tc, "magical armor", 1, test_armor(dt, 0, false));
|
||||||
rc->armor = 2;
|
rc->armor = 2;
|
||||||
CuAssertIntEquals_Msg(tc, "with natural armor", 2, natural_armor(du));
|
CuAssertIntEquals_Msg(tc, "with natural armor", 2, natural_armor(du));
|
||||||
CuAssertIntEquals_Msg(tc, "natural armor", 3, calculate_armor(dt, 0, 0, 0));
|
CuAssertIntEquals_Msg(tc, "natural armor", 3, test_armor(dt, 0, false));
|
||||||
rc->armor = 0;
|
rc->armor = 0;
|
||||||
free_battle(b);
|
free_battle(b);
|
||||||
|
|
||||||
|
@ -404,29 +414,30 @@ static void test_calculate_armor(CuTest * tc)
|
||||||
i_change(&du->items, ichain, 1);
|
i_change(&du->items, ichain, 1);
|
||||||
dt.fighter = setup_fighter(&b, du);
|
dt.fighter = setup_fighter(&b, du);
|
||||||
rc->battle_flags &= ~BF_EQUIPMENT;
|
rc->battle_flags &= ~BF_EQUIPMENT;
|
||||||
CuAssertIntEquals_Msg(tc, "require BF_EQUIPMENT", 1, calculate_armor(dt, 0, 0, 0));
|
CuAssertIntEquals_Msg(tc, "require BF_EQUIPMENT", 1, test_armor(dt, 0, false));
|
||||||
free_battle(b);
|
free_battle(b);
|
||||||
|
|
||||||
b = NULL;
|
b = NULL;
|
||||||
rc->battle_flags |= BF_EQUIPMENT;
|
rc->battle_flags |= BF_EQUIPMENT;
|
||||||
dt.fighter = setup_fighter(&b, du);
|
dt.fighter = setup_fighter(&b, du);
|
||||||
CuAssertIntEquals_Msg(tc, "stack equipment rc", 5, calculate_armor(dt, 0, 0, 0));
|
CuAssertIntEquals_Msg(tc, "stack equipment rc", 5, test_armor(dt, 0, false));
|
||||||
rc->armor = 2;
|
rc->armor = 2;
|
||||||
CuAssertIntEquals_Msg(tc, "natural armor adds 50%", 6, calculate_armor(dt, 0, 0, 0));
|
CuAssertIntEquals_Msg(tc, "natural armor adds 50%", 6, test_armor(dt, 0, false));
|
||||||
wtype->flags = WTF_NONE;
|
wtype->flags = WTF_NONE;
|
||||||
CuAssertIntEquals_Msg(tc, "regular weapon has no effect", 6, calculate_armor(dt, 0, wtype, 0));
|
CuAssertIntEquals_Msg(tc, "regular weapon has no effect", 6, test_armor(dt, wtype, false));
|
||||||
wtype->flags = WTF_ARMORPIERCING;
|
wtype->flags = WTF_ARMORPIERCING;
|
||||||
CuAssertIntEquals_Msg(tc, "armor piercing weapon", 3, calculate_armor(dt, 0, wtype, 0));
|
CuAssertIntEquals_Msg(tc, "armor piercing weapon", 3, test_armor(dt, wtype, false));
|
||||||
wtype->flags = WTF_NONE;
|
wtype->flags = WTF_NONE;
|
||||||
|
|
||||||
CuAssertIntEquals_Msg(tc, "magical attack", 3, calculate_armor(dt, 0, 0, &magres));
|
CuAssertIntEquals_Msg(tc, "magical attack", 3, test_armor(dt, wtype, true));
|
||||||
CuAssertIntEquals_Msg(tc, "magres unmodified", magres.sa[1], magres.sa[0]);
|
CuAssertIntEquals_Msg(tc, "magres unmodified", 1000,
|
||||||
|
test_resistance(dt));
|
||||||
|
|
||||||
ashield->flags |= ATF_LAEN;
|
ashield->flags |= ATF_LAEN;
|
||||||
achain->flags |= ATF_LAEN;
|
achain->flags |= ATF_LAEN;
|
||||||
magres = frac_one;
|
|
||||||
CuAssertIntEquals_Msg(tc, "laen armor", 3, calculate_armor(dt, 0, 0, &magres));
|
CuAssertIntEquals_Msg(tc, "laen armor", 3, test_armor(dt, wtype, true));
|
||||||
CuAssertIntEquals_Msg(tc, "laen magres bonus", 4, magres.sa[1]);
|
CuAssertIntEquals_Msg(tc, "laen magres bonus", 250, test_resistance(dt));
|
||||||
free_battle(b);
|
free_battle(b);
|
||||||
test_teardown();
|
test_teardown();
|
||||||
}
|
}
|
||||||
|
@ -456,15 +467,17 @@ static void test_magic_resistance(CuTest *tc)
|
||||||
|
|
||||||
i_change(&du->items, ishield, 1);
|
i_change(&du->items, ishield, 1);
|
||||||
dt.fighter = setup_fighter(&b, du);
|
dt.fighter = setup_fighter(&b, du);
|
||||||
calculate_armor(dt, 0, 0, &magres);
|
CuAssertIntEquals_Msg(tc, "no magres reduction", 1000, test_resistance(dt));
|
||||||
CuAssertIntEquals_Msg(tc, "no magres reduction", magres.sa[1], magres.sa[0]);
|
|
||||||
magres = magic_resistance(du);
|
magres = magic_resistance(du);
|
||||||
CuAssertIntEquals_Msg(tc, "no magres reduction", 0, magres.sa[0]);
|
CuAssertIntEquals_Msg(tc, "no magres reduction", 0, magres.sa[0]);
|
||||||
|
|
||||||
ashield->flags |= ATF_LAEN;
|
ashield->flags |= ATF_LAEN;
|
||||||
ashield->magres = v10p;
|
ashield->magres = v10p;
|
||||||
calculate_armor(dt, 0, 0, &magres);
|
CuAssertIntEquals_Msg(tc, "laen reduction => 10%%", 900, test_resistance(dt));
|
||||||
CuAssert(tc, "laen reduction => 10%%", frac_equal(frac_make(9, 10), magres));
|
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);
|
free_battle(b);
|
||||||
|
|
||||||
b = NULL;
|
b = NULL;
|
||||||
|
@ -474,8 +487,7 @@ static void test_magic_resistance(CuTest *tc)
|
||||||
ashield->flags |= ATF_LAEN;
|
ashield->flags |= ATF_LAEN;
|
||||||
ashield->magres = v10p;
|
ashield->magres = v10p;
|
||||||
dt.fighter = setup_fighter(&b, du);
|
dt.fighter = setup_fighter(&b, du);
|
||||||
calculate_armor(dt, 0, 0, &magres);
|
CuAssertIntEquals_Msg(tc, "2x laen reduction => 81%%", 810, test_resistance(dt));
|
||||||
CuAssert(tc, "2x laen reduction => 81%%", frac_equal(frac_make(81, 100), magres));
|
|
||||||
free_battle(b);
|
free_battle(b);
|
||||||
|
|
||||||
b = NULL;
|
b = NULL;
|
||||||
|
@ -483,21 +495,18 @@ static void test_magic_resistance(CuTest *tc)
|
||||||
i_change(&du->items, ichain, -1);
|
i_change(&du->items, ichain, -1);
|
||||||
set_level(du, SK_MAGIC, 2);
|
set_level(du, SK_MAGIC, 2);
|
||||||
dt.fighter = setup_fighter(&b, du);
|
dt.fighter = setup_fighter(&b, du);
|
||||||
calculate_armor(dt, 0, 0, &magres);
|
CuAssertIntEquals_Msg(tc, "skill reduction => 90%%", 900, test_resistance(dt));
|
||||||
CuAssert(tc, "skill reduction => 90%%", frac_equal(magres, frac_make(9, 10)));
|
|
||||||
magres = magic_resistance(du);
|
magres = magic_resistance(du);
|
||||||
CuAssert(tc, "skill reduction", frac_equal(magres, v10p));
|
CuAssert(tc, "skill reduction", frac_equal(magres, v10p));
|
||||||
rc->magres = v50p; /* percentage, gets added to skill bonus */
|
rc->magres = v50p; /* percentage, gets added to skill bonus */
|
||||||
calculate_armor(dt, 0, 0, &magres);
|
CuAssertIntEquals_Msg(tc, "race reduction => 40%%", 400, test_resistance(dt));
|
||||||
CuAssert(tc, "race reduction => 40%%", frac_equal(magres, frac_make(4, 10)));
|
|
||||||
magres = magic_resistance(du);
|
magres = magic_resistance(du);
|
||||||
CuAssert(tc, "race bonus => 60%%", frac_equal(magres, frac_make(60, 100)));
|
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 */
|
rc->magres = frac_make(15, 10); /* 150% resistance should not cause negative damage multiplier */
|
||||||
magres = magic_resistance(du);
|
magres = magic_resistance(du);
|
||||||
CuAssert(tc, "magic resistance is never > 0.9", frac_equal(magres, frac_make(9, 10)));
|
CuAssert(tc, "magic resistance is never > 0.9", frac_equal(magres, frac_make(9, 10)));
|
||||||
calculate_armor(dt, 0, 0, &magres);
|
CuAssertIntEquals_Msg(tc, "damage reduction is never < 0.1", 100, test_resistance(dt));
|
||||||
CuAssert(tc, "damage reduction is never < 0.1", frac_equal(magres, frac_make(1, 10)));
|
|
||||||
|
|
||||||
free_battle(b);
|
free_battle(b);
|
||||||
test_teardown();
|
test_teardown();
|
||||||
|
@ -532,12 +541,12 @@ static void test_projectile_armor(CuTest * tc)
|
||||||
dt.fighter = setup_fighter(&b, du);
|
dt.fighter = setup_fighter(&b, du);
|
||||||
wtype->flags = WTF_MISSILE;
|
wtype->flags = WTF_MISSILE;
|
||||||
achain->projectile = 1.0;
|
achain->projectile = 1.0;
|
||||||
CuAssertIntEquals_Msg(tc, "projectile armor", -1, calculate_armor(dt, 0, wtype, 0));
|
CuAssertIntEquals_Msg(tc, "projectile armor", -1, test_armor(dt, wtype, false));
|
||||||
achain->projectile = 0.0;
|
achain->projectile = 0.0;
|
||||||
ashield->projectile = 1.0;
|
ashield->projectile = 1.0;
|
||||||
CuAssertIntEquals_Msg(tc, "projectile shield", -1, calculate_armor(dt, 0, wtype, 0));
|
CuAssertIntEquals_Msg(tc, "projectile shield", -1, test_armor(dt, wtype, false));
|
||||||
wtype->flags = WTF_NONE;
|
wtype->flags = WTF_NONE;
|
||||||
CuAssertIntEquals_Msg(tc, "no projectiles", 4, calculate_armor(dt, 0, wtype, 0));
|
CuAssertIntEquals_Msg(tc, "no projectiles", 4, test_armor(dt, wtype, false));
|
||||||
free_battle(b);
|
free_battle(b);
|
||||||
test_teardown();
|
test_teardown();
|
||||||
}
|
}
|
||||||
|
@ -575,6 +584,38 @@ static void test_battle_skilldiff(CuTest *tc)
|
||||||
test_teardown();
|
test_teardown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_terminate(CuTest * tc)
|
||||||
|
{
|
||||||
|
troop at, dt;
|
||||||
|
battle *b = NULL;
|
||||||
|
region *r;
|
||||||
|
unit *au, *du;
|
||||||
|
race *rc;
|
||||||
|
|
||||||
|
test_setup();
|
||||||
|
r = test_create_region(0, 0, NULL);
|
||||||
|
|
||||||
|
rc = test_create_race("human");
|
||||||
|
au = test_create_unit(test_create_faction(rc), r);
|
||||||
|
du = test_create_unit(test_create_faction(rc), r);
|
||||||
|
dt.index = 0;
|
||||||
|
at.index = 0;
|
||||||
|
|
||||||
|
at.fighter = setup_fighter(&b, au);
|
||||||
|
dt.fighter = setup_fighter(&b, du);
|
||||||
|
|
||||||
|
CuAssertIntEquals_Msg(tc, "not killed", 0, terminate(dt, at, AT_STANDARD, "1d1", false));
|
||||||
|
b = NULL;
|
||||||
|
at.fighter = setup_fighter(&b, au);
|
||||||
|
dt.fighter = setup_fighter(&b, du);
|
||||||
|
CuAssertIntEquals_Msg(tc, "killed", 1, terminate(dt, at, AT_STANDARD, "100d1", false));
|
||||||
|
CuAssertIntEquals_Msg(tc, "number", 0, dt.fighter->person[0].hp);
|
||||||
|
|
||||||
|
free_battle(b);
|
||||||
|
test_teardown();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void test_battle_report_one(CuTest *tc)
|
static void test_battle_report_one(CuTest *tc)
|
||||||
{
|
{
|
||||||
battle * b = NULL;
|
battle * b = NULL;
|
||||||
|
@ -853,6 +894,7 @@ CuSuite *get_battle_suite(void)
|
||||||
SUITE_ADD_TEST(suite, test_magic_resistance);
|
SUITE_ADD_TEST(suite, test_magic_resistance);
|
||||||
SUITE_ADD_TEST(suite, test_projectile_armor);
|
SUITE_ADD_TEST(suite, test_projectile_armor);
|
||||||
SUITE_ADD_TEST(suite, test_tactics_chance);
|
SUITE_ADD_TEST(suite, test_tactics_chance);
|
||||||
|
SUITE_ADD_TEST(suite, test_terminate);
|
||||||
DISABLE_TEST(suite, test_drain_exp);
|
DISABLE_TEST(suite, test_drain_exp);
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue