Skip to content

Instantly share code, notes, and snippets.

@eilo
Created March 28, 2012 18:00
Show Gist options
  • Save eilo/2228780 to your computer and use it in GitHub Desktop.
Save eilo/2228780 to your computer and use it in GitHub Desktop.
Resistencias binarias ingresado el 14 de marzo (Emulador de 24 diciembre)
From efc5c8e926a33b1b761bd8707a0059b728bb318f Mon Sep 17 00:00:00 2001
From: Eilo <[email protected]>
Date: Wed, 14 Mar 2012 13:04:14 -0500
Subject: [PATCH 17/27] 0.17 Resistencias Binarias
---
src/server/game/Entities/GameObject/GameObject.cpp | 2 +
src/server/game/Entities/Player/Player.cpp | 6 +-
src/server/game/Entities/Player/Player.h | 3 +-
src/server/game/Entities/Unit/StatSystem.cpp | 6 +
src/server/game/Entities/Unit/Unit.cpp | 300 +++++++++++++-------
src/server/game/Entities/Unit/Unit.h | 11 +-
src/server/game/Spells/Spell.cpp | 25 ++-
src/server/game/Spells/Spell.h | 1 +
src/server/game/Spells/SpellInfo.h | 1 +
src/server/game/Spells/SpellMgr.cpp | 44 +++-
10 files changed, 275 insertions(+), 124 deletions(-)
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index afc8911..6892878 100755
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -1634,6 +1634,7 @@ void GameObject::CastSpell(Unit* target, uint32 spellId)
if (Unit* owner = GetOwner())
{
trigger->setFaction(owner->getFaction());
+ trigger->SetLevel(owner->getLevel());
// needed for GO casts for proper target validation checks
trigger->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, owner->GetGUID());
trigger->CastSpell(target ? target : trigger, spellInfo, true, 0, 0, owner->GetGUID());
@@ -1641,6 +1642,7 @@ void GameObject::CastSpell(Unit* target, uint32 spellId)
else
{
trigger->setFaction(14);
+ trigger->SetLevel(target ? target->getLevel() : 255);
// Set owner guid for target if no owner avalible - needed by trigger auras
// - trigger gets despawned and there's no caster avalible (see AuraEffect::TriggerSpell())
trigger->CastSpell(target ? target : trigger, spellInfo, true, 0, 0, target ? target->GetGUID() : 0);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 84c9b31..6bb2f44 100755
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -8043,8 +8043,7 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
ApplyHealthRegenBonus(int32(val), apply);
break;
case ITEM_MOD_SPELL_PENETRATION:
- ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, -val, apply);
- m_spellPenetrationItemMod += apply ? val : -val;
+ ApplySpellPenetrationBonus(int32(val), apply);
break;
// deprecated item mods
case ITEM_MOD_SPELL_HEALING_DONE:
@@ -13983,8 +13982,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "+ %u HEALTH_REGENERATION", enchant_amount);
break;
case ITEM_MOD_SPELL_PENETRATION:
- ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, enchant_amount, apply);
- m_spellPenetrationItemMod += apply ? int32(enchant_amount) : -int32(enchant_amount);
+ ApplySpellPenetrationBonus(enchant_amount, apply);
sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "+ %u SPELL_PENETRATION", enchant_amount);
break;
case ITEM_MOD_BLOCK_VALUE:
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index a83601f..ca4a5e7 100755
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1910,6 +1910,7 @@ class Player : public Unit, public GridObject<Player>
bool UpdateStats(Stats stat);
bool UpdateAllStats();
+ void ApplySpellPenetrationBonus(int32 amount, bool apply);
void UpdateResistances(uint32 school);
void UpdateArmor();
void UpdateMaxHealth();
@@ -1936,7 +1937,7 @@ class Player : public Unit, public GridObject<Player>
float OCTRegenMPPerSpirit();
float GetRatingMultiplier(CombatRating cr) const;
float GetRatingBonusValue(CombatRating cr) const;
- uint32 GetBaseSpellPowerBonus() { return m_baseSpellPower; }
+ uint32 GetBaseSpellPowerBonus() const { return m_baseSpellPower; }
int32 GetSpellPenetrationItemMod() const { return m_spellPenetrationItemMod; }
float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const;
diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp
index c0bd5cb..8c6ab91 100755
--- a/src/server/game/Entities/Unit/StatSystem.cpp
+++ b/src/server/game/Entities/Unit/StatSystem.cpp
@@ -183,6 +183,12 @@ bool Player::UpdateAllStats()
return true;
}
+void Player::ApplySpellPenetrationBonus(int32 amount, bool apply)
+{
+ ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, -amount, apply);
+ m_spellPenetrationItemMod += apply ? amount : -amount;
+}
+
void Player::UpdateResistances(uint32 school)
{
if (school > SPELL_SCHOOL_NORMAL)
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 2d6e8f1..75d579a 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -1005,7 +1005,7 @@ uint32 Unit::SpellNonMeleeDamageLog(Unit* victim, uint32 spellID, uint32 damage)
return damageInfo.damage;
}
-void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType, bool crit)
+void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType, bool crit, int32 calc_resist)
{
if (damage < 0)
return;
@@ -1102,7 +1102,7 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
// Calculate absorb resist
if (damage > 0)
{
- CalcAbsorbResist(victim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo);
+ CalcAbsorbResist(victim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo, calc_resist);
damage -= damageInfo->absorb + damageInfo->resist;
}
else
@@ -1570,74 +1570,132 @@ uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo
return (newdamage > 1) ? newdamage : 1;
}
-void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, uint32 const damage, uint32 *absorb, uint32 *resist, SpellInfo const* spellInfo)
+uint32 Unit::GetSpellPenetration(SpellSchoolMask schoolMask) const
{
- if (!victim || !victim->isAlive() || !damage)
- return;
+ int32 spellPenetration = 0;
- DamageInfo dmgInfo = DamageInfo(this, victim, damage, spellInfo, schoolMask, damagetype);
+ const Unit * source = ToPlayer();
- // Magic damage, check for resists
- if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
+ if (!source)
{
- float victimResistance = float(victim->GetResistance(schoolMask));
- victimResistance += float(GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
+ source = ToCreature();
- if (Player* player = ToPlayer())
- victimResistance -= float(player->GetSpellPenetrationItemMod());
+ if (source)
+ {
+ source = source->ToCreature()->GetOwner();
+ if (source)
+ source = source->ToPlayer();
+ }
+ }
+
+ if (source && !isTotem())
+ spellPenetration += source->ToPlayer()->GetSpellPenetrationItemMod();
+ else
+ source = this;
- // Resistance can't be lower then 0.
- if (victimResistance < 0.0f)
- victimResistance = 0.0f;
+ spellPenetration += -source->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask);
- static uint32 const BOSS_LEVEL = 83;
- static float const BOSS_RESISTANCE_CONSTANT = 510.0f;
- uint32 level = victim->getLevel();
- float resistanceConstant = 0.0f;
+ return uint32(std::max<int32>(spellPenetration, 0));
+}
- if (level == BOSS_LEVEL)
- resistanceConstant = BOSS_RESISTANCE_CONSTANT;
- else
- resistanceConstant = level * 5.0f;
+uint32 Unit::CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, bool binary, SpellInfo const* spellProto) const
+{
+ // Magic damage, check for resists
+ if (uint32(schoolMask & (SPELL_SCHOOL_MASK_NORMAL | SPELL_SCHOOL_HOLY)) > 0)
+ return 0;
- float averageResist = victimResistance / (victimResistance + resistanceConstant);
- float discreteResistProbability[11];
- for (uint32 i = 0; i < 11; ++i)
- {
- discreteResistProbability[i] = 0.5f - 2.5f * fabs(0.1f * i - averageResist);
- if (discreteResistProbability[i] < 0.0f)
- discreteResistProbability[i] = 0.0f;
- }
+ // These spells should ignore any resistances
+ if (spellProto && spellProto->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
+ return 0;
- if (averageResist <= 0.1f)
- {
- discreteResistProbability[0] = 1.0f - 7.5f * averageResist;
- discreteResistProbability[1] = 5.0f * averageResist;
- discreteResistProbability[2] = 2.5f * averageResist;
- }
+ uint8 BOSS_LEVEL = 83;
+ int32 BOSS_RESISTANCE_CONSTANT = 510;
+ int32 resistanceConstant = 0;
+
+ if (getLevel() >= BOSS_LEVEL)
+ resistanceConstant = BOSS_RESISTANCE_CONSTANT;
+ else
+ resistanceConstant = getLevel() * 5;
+
+ int32 levelDiff = std::max<int32>(victim->getLevel() - getLevel(), 0);
+ int32 baseVictimResistance = victim->GetResistance(GetFirstSchoolInMask(schoolMask));
+ uint32 spellPenetration = GetSpellPenetration(schoolMask);
+ int32 victimResistance = std::max<int32>(baseVictimResistance - spellPenetration, 0);
+ int32 ignoredResistance = 0;
+
+ if (victimResistance > 0)
+ {
+ AuraEffectList const & aurasA = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
+ for (AuraEffectList::const_iterator itr = aurasA.begin(); itr != aurasA.end(); ++itr)
+ if (((*itr)->GetMiscValue() & schoolMask) && (*itr)->IsAffectedOnSpell(spellProto))
+ ignoredResistance += (*itr)->GetAmount();
+
+ AuraEffectList const & aurasB = GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
+ for (AuraEffectList::const_iterator itr = aurasB.begin(); itr != aurasB.end(); ++itr)
+ if ((*itr)->GetMiscValue() & schoolMask)
+ ignoredResistance += (*itr)->GetAmount();
+
+ ignoredResistance = std::min<int32>(ignoredResistance, 100);
+ }
+
+ victimResistance = victimResistance * (100 - ignoredResistance) / 100;
+ victimResistance += (levelDiff * 5); // Level diff resistance cannot be pierced
+
+ if (victimResistance <= 0)
+ return 0;
- float r = float(rand_norm());
- uint32 i = 0;
- float probabilitySum = discreteResistProbability[0];
+ float averageResist = float(victimResistance) / float(victimResistance + resistanceConstant);
+
+ if (spellProto && spellProto->AttributesCu & SPELL_ATTR0_CU_BINARY)
+ {
+ int32 tmp = int32(averageResist * 10000);
+ int32 rand = irand(0, 10000);
+ return rand < tmp ? 100 : 0;
+ }
- while (r >= probabilitySum && i < 10)
- probabilitySum += discreteResistProbability[++i];
+ float discreteResistProbability[11];
- float damageResisted = float(damage * i / 10);
+ for (uint32 i = 0; i < 11; i++)
+ {
+ discreteResistProbability[i] = 0.5f - 2.5f * fabs(0.1f * i - averageResist);
+ if (discreteResistProbability[i] < 0.0f)
+ discreteResistProbability[i] = 0.0f;
+ }
- AuraEffectList const& ResIgnoreAurasAb = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
- for (AuraEffectList::const_iterator j = ResIgnoreAurasAb.begin(); j != ResIgnoreAurasAb.end(); ++j)
- if (((*j)->GetMiscValue() & schoolMask) && (*j)->IsAffectedOnSpell(spellInfo))
- AddPctN(damageResisted, -(*j)->GetAmount());
+ if (averageResist <= 0.1f)
+ {
+ discreteResistProbability[0] = 1.0f - 7.5f * averageResist;
+ discreteResistProbability[1] = 5.0f * averageResist;
+ discreteResistProbability[2] = 2.5f * averageResist;
+ }
- AuraEffectList const& ResIgnoreAuras = GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
- for (AuraEffectList::const_iterator j = ResIgnoreAuras.begin(); j != ResIgnoreAuras.end(); ++j)
- if ((*j)->GetMiscValue() & schoolMask)
- AddPctN(damageResisted, -(*j)->GetAmount());
+ uint32 resistance = 0;
+ float r = float(rand_norm());
+ float probabilitySum = discreteResistProbability[0];
- dmgInfo.ResistDamage(uint32(damageResisted));
+ while ((r >= probabilitySum) && (resistance < 10))
+ {
+ ++resistance;
+ probabilitySum += discreteResistProbability[resistance];
}
+ return (resistance * 10);
+}
+
+void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, uint32 const damage, uint32* absorb, uint32* resist, SpellInfo const* spellInfo, int32 calc_resist)
+{
+ if (!victim || !victim->isAlive() || !damage)
+ return;
+
+ DamageInfo dmgInfo = DamageInfo(this, victim, damage, spellInfo, schoolMask, damagetype);
+
+ bool binary = (spellInfo && (uint32(spellInfo->AttributesCu & SPELL_ATTR0_CU_BINARY) > 0));
+ if (!binary)
+ if (calc_resist >= 0)
+ dmgInfo.ResistDamage(damage * calc_resist / 100);
+ else
+ dmgInfo.ResistDamage(damage * CalcSpellResistance(victim, schoolMask, binary, spellInfo) / 100);
+
// Ignore Absorption Auras
float auraAbsorbMod = 0;
AuraEffectList const& AbsIgnoreAurasA = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL);
@@ -2258,7 +2316,7 @@ bool Unit::isBlockCritical()
return false;
}
-int32 Unit::GetMechanicResistChance(const SpellInfo* spell)
+int32 Unit::GetMechanicResistChance(const SpellInfo* spell) const
{
if (!spell)
return 0;
@@ -2452,19 +2510,13 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spell)
return SPELL_MISS_NONE;
}
-// TODO need use unit spell resistances in calculations
-SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spell)
+uint32 Unit::CalcMagicSpellHitChance(Unit* victim, SpellSchoolMask schoolMask, SpellInfo const* spellProto)
{
- // Can`t miss on dead target (on skinning for example)
- if (!victim->isAlive() && victim->GetTypeId() != TYPEID_PLAYER)
- return SPELL_MISS_NONE;
-
- SpellSchoolMask schoolMask = spell->GetSchoolMask();
// PvP - PvE spell misschances per leveldif > 2
int32 lchance = victim->GetTypeId() == TYPEID_PLAYER ? 7 : 11;
int32 thisLevel = getLevelForTarget(victim);
if (GetTypeId() == TYPEID_UNIT && ToCreature()->isTrigger())
- thisLevel = std::max<int32>(thisLevel, spell->SpellLevel);
+ thisLevel = std::max<int32>(thisLevel, spellProto->SpellLevel);
int32 leveldif = int32(victim->getLevelForTarget(this)) - thisLevel;
// Base hit chance from attacker and victim levels
@@ -2474,59 +2526,54 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spell)
else
modHitChance = 94 - (leveldif - 2) * lchance;
+ Unit * source = ToPlayer();
+ if (!source)
+ {
+ source = ToCreature();
+ if (source)
+ {
+ source = source->ToCreature()->GetOwner();
+ if (source)
+ source = source->ToPlayer();
+ }
+ }
+ if (source && !isTotem())
+ source->ToPlayer()->ApplySpellMod(spellProto->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance);
+ else
+ source = this;
+
// Spellmod from SPELLMOD_RESIST_MISS_CHANCE
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance);
+ modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance);
// Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
modHitChance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask);
// Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will ignore target's avoidance effects
- if (!(spell->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT))
+ if (!(spellProto->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT))
{
// Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
- modHitChance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask);
+ if (!(spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK && spellProto->SpellIconID == 3178)) // Chaos Bolt should ignore it
+ modHitChance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask);
// Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
- if (spell->IsAOE())
+ if (spellProto->IsAOE())
modHitChance -= victim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE);
// Decrease hit chance from victim rating bonus
if (victim->GetTypeId() == TYPEID_PLAYER)
modHitChance -= int32(victim->ToPlayer()->GetRatingBonusValue(CR_HIT_TAKEN_SPELL));
- }
-
- int32 HitChance = modHitChance * 100;
- // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
- HitChance += int32(m_modSpellHitChance * 100.0f);
-
- if (HitChance < 100)
- HitChance = 100;
- else if (HitChance > 10000)
- HitChance = 10000;
-
- int32 tmp = 10000 - HitChance;
-
- int32 rand = irand(0, 10000);
-
- if (rand < tmp)
- return SPELL_MISS_MISS;
-
- // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
- // resist and deflect chances
- if (spell->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
- return SPELL_MISS_NONE;
+ }
// Chance resist mechanic (select max value from every mechanic spell effect)
- int32 resist_chance = victim->GetMechanicResistChance(spell) * 100;
- tmp += resist_chance;
+ modHitChance -= victim->GetMechanicResistChance(spellProto);
// Chance resist debuff
- if (!spell->IsPositive())
+ if (!spellProto->IsPositive())
{
bool bNegativeAura = false;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- if (spell->Effects[i].ApplyAuraName != 0)
+ if (spellProto->Effects[i].ApplyAuraName != 0)
{
bNegativeAura = true;
break;
@@ -2535,25 +2582,70 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spell)
if (bNegativeAura)
{
- tmp += victim->GetMaxPositiveAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel)) * 100;
- tmp += victim->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel)) * 100;
+ modHitChance -= victim->GetMaxPositiveAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spellProto->Dispel));
+ modHitChance -= victim->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spellProto->Dispel));
}
}
- // Roll chance
- if (rand < tmp)
- return SPELL_MISS_RESIST;
+ int32 hit = modHitChance * 100;
+ // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
+ hit += int32(source->m_modSpellHitChance * 100.0f);
+
+ // Decrease hit chance from victim rating bonus
+ if (victim->ToPlayer())
+ hit -= int32(victim->ToPlayer()->GetRatingBonusValue(CR_HIT_TAKEN_SPELL) * 100.0f);
+
+ hit = std::min<int32>(std::max<int32>(hit, 100), 10000);
+
+ return uint32(hit);
+}
+
+SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spell)
+{
+ // Can`t miss on dead target (on skinning for example)
+ if (!victim->isAlive() && victim->GetTypeId() != TYPEID_PLAYER)
+ return SPELL_MISS_NONE;
+
+ SpellSchoolMask schoolMask = spell->GetSchoolMask();
+
+ int32 ignoredResistance = 0;
+
+ AuraEffectList const & aurasA = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
+ for (AuraEffectList::const_iterator itr = aurasA.begin(); itr != aurasA.end(); ++itr)
+ if (((*itr)->GetMiscValue() & schoolMask) && (*itr)->IsAffectedOnSpell(spell))
+ ignoredResistance += (*itr)->GetAmount();
+
+ AuraEffectList const & aurasB = GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
+ for (AuraEffectList::const_iterator itr = aurasB.begin(); itr != aurasB.end(); ++itr)
+ if ((*itr)->GetMiscValue() & schoolMask)
+ ignoredResistance += (*itr)->GetAmount();
+
+ ignoredResistance = std::min(ignoredResistance, int32(100));
// cast by caster in front of victim
- if (victim->HasInArc(M_PI, this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
- {
- int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100;
- tmp += deflect_chance;
- if (rand < tmp)
- return SPELL_MISS_DEFLECT;
- }
+ int32 deflect_chance = (victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * (100 - ignoredResistance) / 100) * 100;
- return SPELL_MISS_NONE;
+ if (deflect_chance > 0)
+ if (victim->HasInArc(M_PI, this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
+ {
+ int32 rand = irand(0, 10000);
+
+ if (rand < deflect_chance)
+ return SPELL_MISS_DEFLECT;
+ }
+
+ int32 miss = (10000 - CalcMagicSpellHitChance(victim, schoolMask, spell)) * (100 - ignoredResistance) / 100;
+
+ int32 rand = irand(0, 10000);
+
+ if (rand < miss)
+ return SPELL_MISS_MISS;
+
+ // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
+ // resist and deflect chances
+ if (spell->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
+ return SPELL_MISS_NONE;
+ return SPELL_MISS_NONE;
}
// Calculate spell hit result can be:
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 5a6b34b..83d7ef7 100755
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1348,6 +1348,7 @@ class Unit : public WorldObject
uint32 GetResistance(SpellSchools school) const { return GetUInt32Value(UNIT_FIELD_RESISTANCES+school); }
uint32 GetResistance(SpellSchoolMask mask) const;
void SetResistance(SpellSchools school, int32 val) { SetStatInt32Value(UNIT_FIELD_RESISTANCES+school, val); }
+ uint32 GetSpellPenetration(SpellSchoolMask schoolMask) const;
uint32 GetHealth() const { return GetUInt32Value(UNIT_FIELD_HEALTH); }
uint32 GetMaxHealth() const { return GetUInt32Value(UNIT_FIELD_MAXHEALTH); }
@@ -1464,7 +1465,7 @@ class Unit : public WorldObject
void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss);
void HandleProcExtraAttackFor(Unit* victim);
- void CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = BASE_ATTACK, bool crit = false);
+ void CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = BASE_ATTACK, bool crit = false, int32 calc_resist = -1);
void DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss);
// player or player's pet resilience (-1%)
@@ -1487,14 +1488,15 @@ class Unit : public WorldObject
float MeleeSpellMissChance(const Unit* pVictim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const;
SpellMissInfo MeleeSpellHitResult(Unit* pVictim, SpellInfo const* spell);
SpellMissInfo MagicSpellHitResult(Unit* pVictim, SpellInfo const* spell);
- SpellMissInfo SpellHitResult(Unit* pVictim, SpellInfo const* spell, bool canReflect = false);
+ SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spell, bool canReflect = false);
+ uint32 CalcMagicSpellHitChance(Unit* victim, SpellSchoolMask schoolMask, SpellInfo const* spellProto);
float GetUnitDodgeChance() const;
float GetUnitParryChance() const;
float GetUnitBlockChance() const;
float GetUnitMissChance(WeaponAttackType attType) const;
float GetUnitCriticalChance(WeaponAttackType attackType, const Unit* pVictim) const;
- int32 GetMechanicResistChance(const SpellInfo* spell);
+ int32 GetMechanicResistChance(const SpellInfo* spell) const;
bool CanUseAttackType(uint8 attacktype) const
{
switch (attacktype)
@@ -2057,7 +2059,8 @@ class Unit : public WorldObject
// redefined in Creature
static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const* spellInfo = NULL, uint8 effIndex = MAX_SPELL_EFFECTS);
uint32 CalcArmorReducedDamage(Unit* pVictim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType=MAX_ATTACK);
- void CalcAbsorbResist(Unit* pVictim, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist, SpellInfo const* spellInfo = NULL);
+ void CalcAbsorbResist(Unit* pVictim, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32* absorb, uint32* resist, SpellInfo const* spellInfo = NULL, int32 calc_resist = -1);
+ uint32 CalcSpellResistance(Unit* pVictim, SpellSchoolMask schoolMask, bool binary, SpellInfo const* spellProto) const;
void CalcHealAbsorb(Unit* pVictim, const SpellInfo* spellProto, uint32 &healAmount, uint32 &absorb);
void UpdateSpeed(UnitMoveType mtype, bool forced);
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 69cd675..3324138 100755
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -1001,7 +1001,7 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
targetInfo.missCondition = SPELL_MISS_NONE;
}
else
- targetInfo.missCondition = SPELL_MISS_EVADE; //SPELL_MISS_NONE;
+ targetInfo.missCondition = SPELL_MISS_EVADE;
// Spell have speed - need calculate incoming time
// Incoming time is zero for self casts. At least I think so.
@@ -1195,6 +1195,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
// Reset damage/healing counter
m_damage = target->damage;
m_healing = -target->damage;
+ m_resist = 0;
// Fill base trigger info
uint32 procAttacker = m_procAttacker;
@@ -1221,11 +1222,11 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (spellHitTarget)
{
- SpellMissInfo missInfo2 = DoSpellHitOnUnit(spellHitTarget, mask, target->scaleAura);
- if (missInfo2 != SPELL_MISS_NONE)
+ SpellMissInfo tmp = DoSpellHitOnUnit(spellHitTarget, mask, target->scaleAura);
+ if (tmp != SPELL_MISS_NONE)
{
- if (missInfo2 != SPELL_MISS_MISS)
- m_caster->SendSpellMiss(unit, m_spellInfo->Id, missInfo2);
+ if (tmp != SPELL_MISS_MISS)
+ m_caster->SendSpellMiss(unit, m_spellInfo->Id, tmp);
m_damage = 0;
spellHitTarget = NULL;
}
@@ -1318,7 +1319,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask);
// Add bonuses and fill damageInfo struct
- caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo, m_attackType, target->crit);
+ caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo, m_attackType, target->crit, m_resist);
caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
// Send log damage message to client
@@ -1440,6 +1441,11 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, const uint32 effectMask, bool
//TODO: This is a hack. But we do not know what types of stealth should be interrupted by CC
if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_AURA_CC) && unit->IsControlledByPlayer())
unit->RemoveAurasByType(SPELL_AURA_MOD_STEALTH);
+
+ bool binary = uint32(m_spellInfo->AttributesCu & SPELL_ATTR0_CU_BINARY);
+ m_resist = m_caster->CalcSpellResistance(unit, m_spellSchoolMask , binary, m_spellInfo);
+ if (m_resist >= 100)
+ return SPELL_MISS_RESIST;
}
else if (m_caster->IsFriendlyTo(unit))
{
@@ -1462,6 +1468,13 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, const uint32 effectMask, bool
}
}
}
+ else if (!m_spellInfo->IsPositive())
+ {
+ bool binary = uint32(m_spellInfo->AttributesCu & SPELL_ATTR0_CU_BINARY);
+ m_resist = m_caster->CalcSpellResistance(unit, m_spellSchoolMask , binary, m_spellInfo);
+ if (m_resist >= 100)
+ return SPELL_MISS_RESIST;
+ }
// Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add
m_diminishGroup = GetDiminishingReturnsGroupForSpell(m_spellInfo, m_triggeredByAuraSpell);
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 2bbc04d..89899a8 100755
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -551,6 +551,7 @@ class Spell
// Damage and healing in effects need just calculate
int32 m_damage; // Damge in effects count here
int32 m_healing; // Healing in effects count here
+ int32 m_resist; // Resist in effects count here
// ******************************************
// Spell trigger system
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 90b79d4..f5fe63d 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -201,6 +201,7 @@ enum SpellCustomAttributes
SPELL_ATTR0_CU_IGNORE_ARMOR = 0x00008000,
SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER = 0x00010000,
SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET = 0x00020000,
+ SPELL_ATTR0_CU_BINARY = 0x00100000,
SPELL_ATTR0_CU_NEGATIVE = SPELL_ATTR0_CU_NEGATIVE_EFF0 | SPELL_ATTR0_CU_NEGATIVE_EFF1 | SPELL_ATTR0_CU_NEGATIVE_EFF2,
};
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index ea24590..6aa04c3 100755
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -2698,17 +2698,32 @@ void SpellMgr::LoadSpellCustomAttr()
spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
break;
case SPELL_AURA_PERIODIC_HEAL:
- case SPELL_AURA_PERIODIC_DAMAGE:
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
- case SPELL_AURA_PERIODIC_LEECH:
- case SPELL_AURA_PERIODIC_MANA_LEECH:
+ case SPELL_AURA_PERIODIC_LEECH:
case SPELL_AURA_PERIODIC_HEALTH_FUNNEL:
case SPELL_AURA_PERIODIC_ENERGIZE:
+ case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
case SPELL_AURA_OBS_MOD_HEALTH:
case SPELL_AURA_OBS_MOD_POWER:
case SPELL_AURA_POWER_BURN:
spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
break;
+ case SPELL_AURA_PERIODIC_MANA_LEECH:
+ case SPELL_AURA_PERIODIC_DAMAGE:
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY;
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
+ break;
+ }
+
+ switch (spellInfo->Effects[j].Mechanic)
+ {
+ case MECHANIC_SNARE:
+ case MECHANIC_ROOT:
+ case MECHANIC_INTERRUPT:
+ case MECHANIC_SILENCE:
+ case MECHANIC_HORROR:
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY;
+ break;
}
switch (spellInfo->Effects[j].Effect)
@@ -2721,8 +2736,6 @@ void SpellMgr::LoadSpellCustomAttr()
case SPELL_EFFECT_HEAL:
spellInfo->AttributesCu |= SPELL_ATTR0_CU_DIRECT_DAMAGE;
break;
- case SPELL_EFFECT_POWER_DRAIN:
- case SPELL_EFFECT_POWER_BURN:
case SPELL_EFFECT_HEAL_MAX_HEALTH:
case SPELL_EFFECT_HEALTH_LEECH:
case SPELL_EFFECT_HEAL_PCT:
@@ -2738,6 +2751,16 @@ void SpellMgr::LoadSpellCustomAttr()
case SPELL_EFFECT_LEAP_BACK:
spellInfo->AttributesCu |= SPELL_ATTR0_CU_CHARGE;
break;
+ case SPELL_EFFECT_DISPEL:
+ case SPELL_EFFECT_STEAL_BENEFICIAL_BUFF:
+ case SPELL_AURA_PERIODIC_MANA_LEECH:
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY;
+ break;
+ case SPELL_EFFECT_POWER_DRAIN:
+ case SPELL_EFFECT_POWER_BURN:
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY;
+ break;
case SPELL_EFFECT_PICKPOCKET:
spellInfo->AttributesCu |= SPELL_ATTR0_CU_PICKPOCKET;
break;
@@ -2774,6 +2797,17 @@ void SpellMgr::LoadSpellCustomAttr()
}
}
+ switch (spellInfo->Mechanic)
+ {
+ case MECHANIC_FEAR:
+ case MECHANIC_CHARM:
+ case MECHANIC_SNARE:
+ case MECHANIC_FREEZE:
+ case MECHANIC_BANISH:
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY;
+ break;
+ }
+
if (!spellInfo->_IsPositiveEffect(EFFECT_0, false))
spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF0;
--
1.7.8.msysgit.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment