Created
March 28, 2012 18:00
-
-
Save eilo/2228780 to your computer and use it in GitHub Desktop.
Resistencias binarias ingresado el 14 de marzo (Emulador de 24 diciembre)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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