Skip to content

Instantly share code, notes, and snippets.

@eilo
Created March 28, 2012 18:00

Revisions

  1. @invalid-email-address Anonymous created this gist Mar 28, 2012.
    736 changes: 736 additions & 0 deletions resistencias_binarias.patch
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,736 @@
    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