Refactor CheckHitChance

Pulled the accuracy/avoidance spell bonuses into their own functions so
we can show the total values in #showstats
This commit is contained in:
Michael Cook (mackal) 2017-01-15 16:08:22 -05:00
parent c030e1ce8d
commit e03a90b05d
2 changed files with 89 additions and 70 deletions

View File

@ -157,6 +157,62 @@ int Mob::compute_tohit(EQEmu::skills::SkillType skillinuse)
return std::max(tohit, 1);
}
// return -1 in cases that always hit
int Mob::GetTotalToHit(EQEmu::skills::SkillType skill, int chance_mod)
{
if (chance_mod >= 10000) // override for stuff like SE_SkillAttack
return -1;
// calculate attacker's accuracy
auto accuracy = compute_tohit(skill) + 10; // add 10 in case the NPC's stats are fucked
if (chance_mod > 0) // multiplier
accuracy *= chance_mod;
// Torven parsed an apparent constant of 1.2 somewhere in here * 6 / 5 looks eqmathy to me!
accuracy = accuracy * 6 / 5;
// unsure on the stacking order of these effects, rather hard to parse
// item mod2 accuracy isn't applied to range? Theory crafting and parses back it up I guess
// mod2 accuracy -- flat bonus
if (skill != EQEmu::skills::SkillArchery && skill != EQEmu::skills::SkillThrowing)
accuracy += itembonuses.HitChance;
// 216 Melee Accuracy Amt aka SE_Accuracy -- flat bonus
accuracy += itembonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] +
aabonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] +
spellbonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] +
itembonuses.Accuracy[skill] +
aabonuses.Accuracy[skill] +
spellbonuses.Accuracy[skill];
// auto hit discs (and looks like there are some autohit AAs)
if (spellbonuses.HitChanceEffect[skill] >= 10000 || aabonuses.HitChanceEffect[skill] >= 10000)
return -1;
if (spellbonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] >= 10000)
return -1;
// 184 Accuracy % aka SE_HitChance -- percentage increase
auto hit_bonus = itembonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] +
aabonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] +
spellbonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] +
itembonuses.HitChanceEffect[skill] +
aabonuses.HitChanceEffect[skill] +
spellbonuses.HitChanceEffect[skill];
accuracy = (accuracy * (100 + hit_bonus)) / 100;
// TODO: April 2003 added an archery/throwing PVP accuracy penalty while moving, should be in here some where,
// but PVP is less important so I haven't tried parsing it at all
// There is also 110 Ranger Archery Accuracy % which should probably be in here some where, but it's not in any spells/aas
// Name implies it's a percentage increase, if one wishes to implement, do it like the hit_bonus above but limited to ranger archery
// There is also 183 UNUSED - Skill Increase Chance which devs say isn't used at all in code, but some spells reference it
// I do not recommend implementing this once since there are spells that use it which would make this not live-like with default spell files
return accuracy;
}
// based on dev quotes
// the AGI bonus has actually drastically changed from classic
int Mob::compute_defense()
@ -181,6 +237,33 @@ int Mob::compute_defense()
return std::max(1, defense);
}
// return -1 in cases that always miss
int Mob::GetTotalDefense()
{
auto avoidance = compute_defense() + 10; // add 10 in case the NPC's stats are fucked
auto evasion_bonus = spellbonuses.AvoidMeleeChanceEffect; // we check this first since it has a special case
if (evasion_bonus >= 10000)
return -1;
//
// 172 Evasion aka SE_AvoidMeleeChance
evasion_bonus += itembonuses.AvoidMeleeChanceEffect + aabonuses.AvoidMeleeChanceEffect; // item bonus here isn't mod2 avoidance
Mob *owner = nullptr;
if (IsPet())
owner = GetOwner();
else if (IsNPC() && CastToNPC()->GetSwarmOwner())
owner = entity_list.GetMobID(CastToNPC()->GetSwarmOwner());
if (owner) // 215 Pet Avoidance % aka SE_PetAvoidance
evasion_bonus += owner->aabonuses.PetAvoidance + owner->spellbonuses.PetAvoidance + owner->itembonuses.PetAvoidance;
// Evasion is a percentage bonus according to AA descriptions
if (evasion_bonus)
avoidance = (avoidance * (100 + evasion_bonus)) / 100;
return avoidance;
}
// called when a mob is attacked, does the checks to see if it's a hit
// and does other mitigation checks. 'this' is the mob being attacked.
bool Mob::CheckHitChance(Mob* other, EQEmu::skills::SkillType skillinuse, int chance_mod)
@ -192,80 +275,14 @@ bool Mob::CheckHitChance(Mob* other, EQEmu::skills::SkillType skillinuse, int ch
if (defender->IsClient() && defender->CastToClient()->IsSitting())
return true;
// calculate defender's avoidance
auto avoidance = defender->compute_defense() + 10; // add 10 in case the NPC's stats are fucked
auto evasion_bonus = defender->spellbonuses.AvoidMeleeChanceEffect; // we check this first since it has a special case
if (evasion_bonus <= -100)
return true;
if (evasion_bonus >= 10000) // some sort of auto avoid disc
auto avoidance = defender->GetTotalDefense();
if (avoidance == -1) // some sort of auto avoid disc
return false;
// 172 Evasion aka SE_AvoidMeleeChance
evasion_bonus += defender->itembonuses.AvoidMeleeChanceEffect + defender->aabonuses.AvoidMeleeChanceEffect; // item bonus here isn't mod2 avoidance
Mob *owner = nullptr;
if (defender->IsPet())
owner = defender->GetOwner();
else if (defender->IsNPC() && defender->CastToNPC()->GetSwarmOwner())
owner = entity_list.GetMobID(defender->CastToNPC()->GetSwarmOwner());
if (owner) // 215 Pet Avoidance % aka SE_PetAvoidance
evasion_bonus += owner->aabonuses.PetAvoidance + owner->spellbonuses.PetAvoidance + owner->itembonuses.PetAvoidance;
// Evasion is a percentage bonus according to AA descriptions
if (evasion_bonus)
avoidance = (avoidance * (100 + evasion_bonus)) / 100;
if (chance_mod >= 10000) // override for stuff like SE_SkillAttack
auto accuracy = attacker->GetTotalToHit(skillinuse, chance_mod);
if (accuracy == -1)
return true;
// calculate attacker's accuracy
auto accuracy = attacker->compute_tohit(skillinuse) + 10; // add 10 in case the NPC's stats are fucked
if (chance_mod > 0) // multiplier
accuracy *= chance_mod;
// Torven parsed an apparent constant of 1.2 somewhere in here * 6 / 5 looks eqmathy to me!
accuracy = accuracy * 6 / 5;
// unsure on the stacking order of these effects, rather hard to parse
// item mod2 accuracy isn't applied to range? Theory crafting and parses back it up I guess
// mod2 accuracy -- flat bonus
if (skillinuse != EQEmu::skills::SkillArchery && skillinuse != EQEmu::skills::SkillThrowing)
accuracy += attacker->itembonuses.HitChance;
// 216 Melee Accuracy Amt aka SE_Accuracy -- flat bonus
accuracy += attacker->itembonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] +
attacker->aabonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] +
attacker->spellbonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] +
attacker->itembonuses.Accuracy[skillinuse] +
attacker->aabonuses.Accuracy[skillinuse] +
attacker->spellbonuses.Accuracy[skillinuse];
// auto hit discs (and looks like there are some autohit AAs)
if (attacker->spellbonuses.HitChanceEffect[skillinuse] >= 10000 || attacker->aabonuses.HitChanceEffect[skillinuse] >= 10000)
return true;
if (attacker->spellbonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] >= 10000)
return true;
// 184 Accuracy % aka SE_HitChance -- percentage increase
auto hit_bonus = attacker->itembonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] +
attacker->aabonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] +
attacker->spellbonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] +
attacker->itembonuses.HitChanceEffect[skillinuse] +
attacker->aabonuses.HitChanceEffect[skillinuse] +
attacker->spellbonuses.HitChanceEffect[skillinuse];
accuracy = (accuracy * (100 + hit_bonus)) / 100;
// TODO: April 2003 added an archery/throwing PVP accuracy penalty while moving, should be in here some where,
// but PVP is less important so I haven't tried parsing it at all
// There is also 110 Ranger Archery Accuracy % which should probably be in here some where, but it's not in any spells/aas
// Name implies it's a percentage increase, if one wishes to implement, do it like the hit_bonus above but limited to ranger archery
// There is also 183 UNUSED - Skill Increase Chance which devs say isn't used at all in code, but some spells reference it
// I do not recommend implementing this once since there are spells that use it which would make this not live-like with default spell files
// so now we roll!
// relevant dev quote:
// Then your chance to simply avoid the attack is checked (defender's avoidance roll beat the attacker's accuracy roll.)

View File

@ -166,7 +166,9 @@ public:
virtual void TryBackstab(Mob *other,int ReuseTime = 10);
bool AvoidDamage(Mob* attacker, int &damage, int hand);
int compute_tohit(EQEmu::skills::SkillType skillinuse);
int GetTotalToHit(EQEmu::skills::SkillType skill, int chance_mod); // compute_tohit + spell bonuses
int compute_defense();
int GetTotalDefense(); // compute_defense + spell bonuses
bool CheckHitChance(Mob* attacker, EQEmu::skills::SkillType skillinuse, int chance_mod = 0);
virtual void TryCriticalHit(Mob *defender, uint16 skill, int &damage, int min_damage, ExtraAttackOptions *opts = nullptr);
void TryPetCriticalHit(Mob *defender, uint16 skill, int &damage);