diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 440 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 13 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.cpp | 91 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.h | 12 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.cpp | 90 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.h | 3 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 31 | ||||
-rw-r--r-- | src/server/scripts/Spells/spell_hunter.cpp | 9 | ||||
-rw-r--r-- | src/server/scripts/Spells/spell_priest.cpp | 11 | ||||
-rw-r--r-- | src/server/scripts/Spells/spell_warlock.cpp | 13 | ||||
-rw-r--r-- | src/server/scripts/Spells/spell_warrior.cpp | 15 |
12 files changed, 457 insertions, 275 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 5f05cf65739..43b12cb0cba 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3385,6 +3385,7 @@ void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask) return; aura->HandleAuraSpecificMods(aurApp, caster, true, false); + aura->HandleAuraSpecificPeriodics(aurApp, caster); // apply effects of the aura for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) @@ -8159,23 +8160,14 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg if (GetTypeId() != TYPEID_PLAYER) return false; + float averageDmg = 0; // now compute approximate weapon damage by formula from wowwiki.com - Item* item = NULL; if (procFlags & PROC_FLAG_DONE_OFFHAND_ATTACK) - item = ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); + averageDmg = (GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE)) / 2; else - item = ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); - - // dunno if it's really needed but will prevent any possible crashes - if (!item) - return false; + averageDmg = (GetFloatValue(UNIT_FIELD_MINDAMAGE) + GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2; - ItemTemplate const* weapon = item->GetTemplate(); - - float weaponDPS = weapon->getDPS(); - float attackPower = GetTotalAttackPowerValue(BASE_ATTACK) / 14.0f; - float weaponSpeed = float(weapon->Delay) / 1000.0f; - basepoints0 = int32((weaponDPS + attackPower) * weaponSpeed); + basepoints0 = int32(averageDmg); break; } // Persistent Shield (Scarab Brooch trinket) @@ -9853,39 +9845,164 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin if (Unit* owner = GetOwner()) return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype); - // Done total percent damage auras - float DoneTotalMod = 1.0f; float ApCoeffMod = 1.0f; int32 DoneTotal = 0; - // Pet damage? - if (GetTypeId() == TYPEID_UNIT && !ToCreature()->IsPet()) - DoneTotalMod *= ToCreature()->GetSpellDamageMod(ToCreature()->GetCreatureTemplate()->rank); + uint32 creatureTypeMask = victim->GetCreatureTypeMask(); - // Some spells don't benefit from pct done mods - if (!(spellProto->AttributesEx6 & SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS)) + // done scripted mod (take it from owner) + Unit const* owner = GetOwner() ? GetOwner() : this; + AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) { - AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - for (AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i) + if (!(*i)->IsAffectedOnSpell(spellProto)) + continue; + + switch ((*i)->GetMiscValue()) { - if (spellProto->EquippedItemClass == -1 && (*i)->GetSpellInfo()->EquippedItemClass != -1) //prevent apply mods from weapon specific case to non weapon specific spells (Example: thunder clap and two-handed weapon specialization) - continue; + case 4418: // Increased Shock Damage + case 4554: // Increased Lightning Damage + case 4555: // Improved Moonfire + case 5142: // Increased Lightning Damage + case 5147: // Improved Consecration / Libram of Resurgence + case 5148: // Idol of the Shooting Star + case 6008: // Increased Lightning Damage + case 8627: // Totem of Hex + { + DoneTotal += (*i)->GetAmount(); + break; + } + } + } - if ((*i)->GetMiscValue() & spellProto->GetSchoolMask()) + // Custom scripted damage + switch (spellProto->SpellFamilyName) + { + case SPELLFAMILY_DEATHKNIGHT: + // Impurity (dummy effect) + if (GetTypeId() == TYPEID_PLAYER) { - if ((*i)->GetSpellInfo()->EquippedItemClass == -1) - AddPct(DoneTotalMod, (*i)->GetAmount()); - else if (!((*i)->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0)) - AddPct(DoneTotalMod, (*i)->GetAmount()); - else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellInfo())) - AddPct(DoneTotalMod, (*i)->GetAmount()); + PlayerSpellMap playerSpells = ToPlayer()->GetSpellMap(); + for (PlayerSpellMap::const_iterator itr = playerSpells.begin(); itr != playerSpells.end(); ++itr) + { + if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) + continue; + switch (itr->first) + { + case 49220: + case 49633: + case 49635: + case 49636: + case 49638: + if (SpellInfo const* proto = sSpellMgr->GetSpellInfo(itr->first)) + AddPct(ApCoeffMod, proto->Effects[0].CalcValue()); + break; + } + } + } + break; + } + + // Done fixed damage bonus auras + int32 DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto->GetSchoolMask()); + // Pets just add their bonus damage to their spell damage + // note that their spell damage is just gain of their own auras + if (HasUnitTypeMask(UNIT_MASK_GUARDIAN)) + DoneAdvertisedBenefit += ((Guardian*)this)->GetBonusDamage(); + + // Check for table values + float coeff = 0; + SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id); + if (bonus) + { + if (damagetype == DOT) + { + coeff = bonus->dot_damage; + if (bonus->ap_dot_bonus > 0) + { + WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK; + float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS)); + APbonus += GetTotalAttackPowerValue(attType); + DoneTotal += int32(bonus->ap_dot_bonus * stack * ApCoeffMod * APbonus); + } + } + else + { + coeff = bonus->direct_damage; + if (bonus->ap_bonus > 0) + { + WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK; + float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS)); + APbonus += GetTotalAttackPowerValue(attType); + DoneTotal += int32(bonus->ap_bonus * stack * ApCoeffMod * APbonus); } } } + // Default calculation + if (DoneAdvertisedBenefit) + { + if (!bonus || coeff < 0) + coeff = CalculateDefaultCoefficient(spellProto, damagetype) * int32(stack); + + float factorMod = CalculateLevelPenalty(spellProto) * stack; + + if (Player* modOwner = GetSpellModOwner()) + { + coeff *= 100.0f; + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff); + coeff /= 100.0f; + } + DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod); + } + + // Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods. + float tmpDamage = (int32(pdamage) + DoneTotal) * (damagetype == DOT ? 1.0f : SpellDamagePctDone(victim, spellProto, damagetype)); + // apply spellmod to Done damage (flat and pct) + if (Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage); + + return uint32(std::max(tmpDamage, 0.0f)); +} + +float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype) const +{ + if (!spellProto || !victim || damagetype == DIRECT_DAMAGE) + return 1.0f; + + // Some spells don't benefit from pct done mods + if (spellProto->AttributesEx6 & SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS) + return 1.0f; + + // For totems pct done mods are calculated when its calculation is run on the player in SpellDamageBonusDone. + if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsTotem()) + return 1.0f; + + // Done total percent damage auras + float DoneTotalMod = 1.0f; + + // Pet damage? + if (GetTypeId() == TYPEID_UNIT && !ToCreature()->IsPet()) + DoneTotalMod *= ToCreature()->GetSpellDamageMod(ToCreature()->GetCreatureTemplate()->rank); + + AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + for (AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i) + { + if (spellProto->EquippedItemClass == -1 && (*i)->GetSpellInfo()->EquippedItemClass != -1) //prevent apply mods from weapon specific case to non weapon specific spells (Example: thunder clap and two-handed weapon specialization) + continue; + + if ((*i)->GetMiscValue() & spellProto->GetSchoolMask()) + { + if ((*i)->GetSpellInfo()->EquippedItemClass == -1) + AddPct(DoneTotalMod, (*i)->GetAmount()); + else if (!((*i)->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0)) + AddPct(DoneTotalMod, (*i)->GetAmount()); + else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellInfo())) + AddPct(DoneTotalMod, (*i)->GetAmount()); + } + } uint32 creatureTypeMask = victim->GetCreatureTypeMask(); - // Add flat bonus from spell damage versus - DoneTotal += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, creatureTypeMask); + AuraEffectList const& mDamageDoneVersus = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS); for (AuraEffectList::const_iterator i = mDamageDoneVersus.begin(); i != mDamageDoneVersus.end(); ++i) if (creatureTypeMask & uint32((*i)->GetMiscValue())) @@ -9899,7 +10016,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin // done scripted mod (take it from owner) Unit const* owner = GetOwner() ? GetOwner() : this; - AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) { if (!(*i)->IsAffectedOnSpell(spellProto)) @@ -9956,18 +10073,6 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin AddPct(DoneTotalMod, (*i)->GetAmount()); break; } - case 4418: // Increased Shock Damage - case 4554: // Increased Lightning Damage - case 4555: // Improved Moonfire - case 5142: // Increased Lightning Damage - case 5147: // Improved Consecration / Libram of Resurgence - case 5148: // Idol of the Shooting Star - case 6008: // Increased Lightning Damage - case 8627: // Totem of Hex - { - DoneTotal += (*i)->GetAmount(); - break; - } // Tundra Stalker // Merciless Combat case 7277: @@ -10133,14 +10238,14 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin break; } } - // Drain Soul - increased damage for targets under 25 % HP - if (spellProto->SpellFamilyFlags[0] & 0x00004000) - if (HasAura(100001)) - DoneTotalMod *= 4; // Shadow Bite (15% increase from each dot) if (spellProto->SpellFamilyFlags[1] & 0x00400000 && IsPet()) if (uint8 count = victim->GetDoTsByCaster(GetOwnerGUID())) AddPct(DoneTotalMod, 15 * count); + + // Drain Soul - If the target is at or below 25% health, Drain Soul causes four times the normal damage + if (spellProto->SpellFamilyFlags[0] & 0x00004000 && !victim->HealthAbovePct(25)) + DoneTotalMod *= 4; break; case SPELLFAMILY_HUNTER: // Steady Shot @@ -10155,101 +10260,15 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin if (AuraEffect* aurEff = GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 2721, 0)) AddPct(DoneTotalMod, aurEff->GetAmount()); - // Sigil of the Vengeful Heart - if (spellProto->SpellFamilyFlags[0] & 0x2000) - if (AuraEffect* aurEff = GetAuraEffect(64962, EFFECT_1)) - AddPct(DoneTotal, aurEff->GetAmount()); - // Glacier Rot if (spellProto->SpellFamilyFlags[0] & 0x2 || spellProto->SpellFamilyFlags[1] & 0x6) if (AuraEffect* aurEff = GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 196, 0)) if (victim->GetDiseasesByCaster(owner->GetGUID()) > 0) AddPct(DoneTotalMod, aurEff->GetAmount()); - - // Impurity (dummy effect) - if (GetTypeId() == TYPEID_PLAYER) - { - PlayerSpellMap playerSpells = ToPlayer()->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = playerSpells.begin(); itr != playerSpells.end(); ++itr) - { - if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) - continue; - switch (itr->first) - { - case 49220: - case 49633: - case 49635: - case 49636: - case 49638: - { - if (SpellInfo const* proto = sSpellMgr->GetSpellInfo(itr->first)) - AddPct(ApCoeffMod, proto->Effects[0].CalcValue()); - } - break; - } - } - } break; } - // Done fixed damage bonus auras - int32 DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto->GetSchoolMask()); - // Pets just add their bonus damage to their spell damage - // note that their spell damage is just gain of their own auras - if (HasUnitTypeMask(UNIT_MASK_GUARDIAN)) - DoneAdvertisedBenefit += ((Guardian*)this)->GetBonusDamage(); - - // Check for table values - float coeff = 0; - SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id); - if (bonus) - { - if (damagetype == DOT) - { - coeff = bonus->dot_damage; - if (bonus->ap_dot_bonus > 0) - { - WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK; - float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS)); - APbonus += GetTotalAttackPowerValue(attType); - DoneTotal += int32(bonus->ap_dot_bonus * stack * ApCoeffMod * APbonus); - } - } - else - { - coeff = bonus->direct_damage; - if (bonus->ap_bonus > 0) - { - WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK; - float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS)); - APbonus += GetTotalAttackPowerValue(attType); - DoneTotal += int32(bonus->ap_bonus * stack * ApCoeffMod * APbonus); - } - } - } - // Default calculation - if (DoneAdvertisedBenefit) - { - if (!bonus || coeff < 0) - coeff = CalculateDefaultCoefficient(spellProto, damagetype) * int32(stack); - - float factorMod = CalculateLevelPenalty(spellProto) * stack; - - if (Player* modOwner = GetSpellModOwner()) - { - coeff *= 100.0f; - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff); - coeff /= 100.0f; - } - DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod); - } - - float tmpDamage = (int32(pdamage) + DoneTotal) * DoneTotalMod; - // apply spellmod to Done damage (flat and pct) - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage); - - return uint32(std::max(tmpDamage, 0.0f)); + return DoneTotalMod; } uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack) const @@ -10406,16 +10425,21 @@ int32 Unit::SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) const return TakenAdvertisedBenefit; } -bool Unit::isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType) const +bool Unit::IsSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType) const +{ + return roll_chance_f(GetUnitSpellCriticalChance(victim, spellProto, schoolMask, attackType)); +} + +float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType) const { //! Mobs can't crit with spells. Player Totems can //! Fire Elemental (from totem) can too - but this part is a hack and needs more research - if (IS_CREATURE_GUID(GetGUID()) && !(IsTotem() && IS_PLAYER_GUID(GetOwnerGUID())) && GetEntry() != 15438) - return false; + if (IS_CRE_OR_VEH_GUID(GetGUID()) && !(IsTotem() && IS_PLAYER_GUID(GetOwnerGUID())) && GetEntry() != 15438) + return 0.0f; // not critting spell if ((spellProto->AttributesEx2 & SPELL_ATTR2_CANT_CRIT)) - return false; + return 0.0f; float crit_chance = 0.0f; switch (spellProto->DmgClass) @@ -10431,7 +10455,7 @@ bool Unit::isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMas case 71646: // Item - Bauble of True Blood 25m break; default: - return false; + return 0.0f; } // Do not add a break here, case fallthrough is intentional! Adding a break will make above spells unable to crit. case SPELL_DAMAGE_CLASS_MAGIC: @@ -10533,7 +10557,7 @@ bool Unit::isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMas else if (spellProto->GetCategory() == 19) { if (victim->GetCreatureTypeMask() & CREATURE_TYPEMASK_DEMON_OR_UNDEAD) - return true; + return 100.0f; break; } break; @@ -10543,7 +10567,7 @@ bool Unit::isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMas { if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0, 0, GetGUID())) if (victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE) > -100) - return true; + return 100.0f; break; } break; @@ -10591,17 +10615,14 @@ bool Unit::isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMas break; } default: - return false; + return 0.0f; } // percent done // only players use intelligence for critical chance computations if (Player* modOwner = GetSpellModOwner()) modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance); - crit_chance = crit_chance > 0.0f ? crit_chance : 0.0f; - if (roll_chance_f(crit_chance)) - return true; - return false; + return crit_chance > 0.0f ? crit_chance : 0.0f; } uint32 Unit::SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim) @@ -10685,14 +10706,8 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui if (spellProto->SpellFamilyName == SPELLFAMILY_POTION) return healamount; - float DoneTotalMod = 1.0f; int32 DoneTotal = 0; - // Healing done percent - AuraEffectList const& mHealingDonePct = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT); - for (AuraEffectList::const_iterator i = mHealingDonePct.begin(); i != mHealingDonePct.end(); ++i) - AddPct(DoneTotalMod, (*i)->GetAmount()); - // done scripted mod (take it from owner) Unit const* owner = GetOwner() ? GetOwner() : this; AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); @@ -10707,43 +10722,6 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui case 3736: // Hateful Totem of the Third Wind / Increased Lesser Healing Wave / LK Arena (4/5/6) Totem of the Third Wind / Savage Totem of the Third Wind DoneTotal += (*i)->GetAmount(); break; - case 21: // Test of Faith - case 6935: - case 6918: - if (victim->HealthBelowPct(50)) - AddPct(DoneTotalMod, (*i)->GetAmount()); - break; - case 7798: // Glyph of Regrowth - { - if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_DRUID, 0x40, 0, 0)) - AddPct(DoneTotalMod, (*i)->GetAmount()); - break; - } - case 8477: // Nourish Heal Boost - { - int32 stepPercent = (*i)->GetAmount(); - int32 modPercent = 0; - AuraApplicationMap const& victimAuras = victim->GetAppliedAuras(); - for (AuraApplicationMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr) - { - Aura const* aura = itr->second->GetBase(); - if (aura->GetCasterGUID() != GetGUID()) - continue; - SpellInfo const* m_spell = aura->GetSpellInfo(); - if (m_spell->SpellFamilyName != SPELLFAMILY_DRUID || - !(m_spell->SpellFamilyFlags[1] & 0x00000010 || m_spell->SpellFamilyFlags[0] & 0x50)) - continue; - modPercent += stepPercent * aura->GetStackAmount(); - } - AddPct(DoneTotalMod, modPercent); - break; - } - case 7871: // Glyph of Lesser Healing Wave - { - if (victim->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0, 0x00000400, 0, GetGUID())) - AddPct(DoneTotalMod, (*i)->GetAmount()); - break; - } default: break; } @@ -10816,8 +10794,8 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui DoneTotal = 0; } - // use float as more appropriate for negative values and percent applying - float heal = float(int32(healamount) + DoneTotal) * DoneTotalMod; + // Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods. + float heal = float(int32(healamount) + DoneTotal) * (damagetype == DOT ? 1.0f : SpellHealingPctDone(victim, spellProto)); // apply spellmod to Done amount if (Player* modOwner = GetSpellModOwner()) modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal); @@ -10825,6 +10803,78 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui return uint32(std::max(heal, 0.0f)); } +float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const +{ + // For totems pct done mods are calculated when its calculation is run on the player in SpellHealingBonusDone. + if (GetTypeId() == TYPEID_UNIT && IsTotem()) + if (Unit* owner = GetOwner()) + return 1.0f; + + // No bonus healing for potion spells + if (spellProto->SpellFamilyName == SPELLFAMILY_POTION) + return 1.0f; + + float DoneTotalMod = 1.0f; + + // Healing done percent + AuraEffectList const& mHealingDonePct = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT); + for (AuraEffectList::const_iterator i = mHealingDonePct.begin(); i != mHealingDonePct.end(); ++i) + AddPct(DoneTotalMod, (*i)->GetAmount()); + + // done scripted mod (take it from owner) + Unit const* owner = GetOwner() ? GetOwner() : this; + AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) + { + if (!(*i)->IsAffectedOnSpell(spellProto)) + continue; + switch ((*i)->GetMiscValue()) + { + case 21: // Test of Faith + case 6935: + case 6918: + if (victim->HealthBelowPct(50)) + AddPct(DoneTotalMod, (*i)->GetAmount()); + break; + case 7798: // Glyph of Regrowth + { + if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_DRUID, 0x40, 0, 0)) + AddPct(DoneTotalMod, (*i)->GetAmount()); + break; + } + case 8477: // Nourish Heal Boost + { + int32 stepPercent = (*i)->GetAmount(); + int32 modPercent = 0; + AuraApplicationMap const& victimAuras = victim->GetAppliedAuras(); + for (AuraApplicationMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr) + { + Aura const* aura = itr->second->GetBase(); + if (aura->GetCasterGUID() != GetGUID()) + continue; + SpellInfo const* m_spell = aura->GetSpellInfo(); + if (m_spell->SpellFamilyName != SPELLFAMILY_DRUID || + !(m_spell->SpellFamilyFlags[1] & 0x00000010 || m_spell->SpellFamilyFlags[0] & 0x50)) + continue; + modPercent += stepPercent * aura->GetStackAmount(); + } + AddPct(DoneTotalMod, modPercent); + break; + } + case 7871: // Glyph of Lesser Healing Wave + { + if (victim->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0, 0x00000400, 0, GetGUID())) + AddPct(DoneTotalMod, (*i)->GetAmount()); + break; + } + default: + break; + } + } + + return DoneTotalMod; +} + uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack) const { float TakenTotalMod = 1.0f; @@ -11180,7 +11230,7 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType // Some spells don't benefit from pct done mods if (spellProto) - if (!(spellProto->AttributesEx6 & SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS) && !spellProto->IsRankOf(sSpellMgr->GetSpellInfo(12162))) + if (!(spellProto->AttributesEx6 & SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS)) { AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); for (AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 1735d1a8b8c..dbb463585f0 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1972,13 +1972,15 @@ class Unit : public WorldObject Unit* GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo); Unit* GetMeleeHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo = NULL); - int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const; - int32 SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) const; + int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const; + int32 SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) const; uint32 SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1) const; + float SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype) const; uint32 SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1) const; - int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const; - int32 SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask) const; + int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const; + int32 SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask) const; uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1) const; + float SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const; uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1) const; uint32 MeleeDamageBonusDone(Unit* pVictim, uint32 damage, WeaponAttackType attType, SpellInfo const* spellProto = NULL); @@ -1986,7 +1988,8 @@ class Unit : public WorldObject bool isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType = BASE_ATTACK); bool isBlockCritical(); - bool isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK) const; + bool IsSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK) const; + float GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK) const; uint32 SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim); uint32 SpellCriticalHealingBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 07691e14e4f..138e6b84d0a 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -380,7 +380,7 @@ AuraEffect::AuraEffect(Aura* base, uint8 effIndex, int32 *baseAmount, Unit* cast m_base(base), m_spellInfo(base->GetSpellInfo()), m_baseAmount(baseAmount ? *baseAmount : m_spellInfo->Effects[effIndex].BasePoints), m_spellmod(NULL), m_periodicTimer(0), m_tickNumber(0), m_effIndex(effIndex), -m_canBeRecalculated(true), m_isPeriodic(false) +m_canBeRecalculated(true), m_isPeriodic(false), m_damage(0), m_critChance(0.0f), m_donePct(1.0f) { CalculatePeriodic(caster, true, false); @@ -890,19 +890,15 @@ void AuraEffect::UpdatePeriodic(Unit* caster) GetBase()->CallScriptEffectUpdatePeriodicHandlers(this); } -bool AuraEffect::IsPeriodicTickCrit(Unit* target, Unit const* caster) const +bool AuraEffect::CanPeriodicTickCrit(Unit* target, Unit const* caster) const { ASSERT(caster); - Unit::AuraEffectList const& mPeriodicCritAuras= caster->GetAuraEffectsByType(SPELL_AURA_ABILITY_PERIODIC_CRIT); - for (Unit::AuraEffectList::const_iterator itr = mPeriodicCritAuras.begin(); itr != mPeriodicCritAuras.end(); ++itr) - { - if ((*itr)->IsAffectedOnSpell(m_spellInfo) && caster->isSpellCrit(target, m_spellInfo, m_spellInfo->GetSchoolMask())) - return true; - } + if (caster->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_PERIODIC_CRIT, m_spellInfo)) + return true; // Rupture - since 3.3.3 can crit if (m_spellInfo->SpellIconID == 500 && m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE) - return caster->isSpellCrit(target, m_spellInfo, m_spellInfo->GetSchoolMask()); + return true; return false; } @@ -5780,15 +5776,19 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const uint32 resist = 0; CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - // ignore non positive values (can be result apply spellmods to aura damage - uint32 damage = std::max(GetAmount(), 0); + // AOE spells are not affected by the new periodic system. + bool isAreaAura = m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA); + // ignore negative values (can be result apply spellmods to aura damage + uint32 damage = isAreaAura ? std::max(GetAmount(), 0) : m_damage; // Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations - sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); + if (isAreaAura) + sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); if (GetAuraType() == SPELL_AURA_PERIODIC_DAMAGE) { - damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); + if (isAreaAura) + damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellDamagePctDone(target, m_spellInfo, DOT); damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); // Calculate armor mitigation @@ -5844,14 +5844,19 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const else damage = uint32(target->CountPctFromMaxHealth(damage)); - if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) - { - damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); - if (caster->GetTypeId() != TYPEID_PLAYER) - damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); - } + if (!(m_spellInfo->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE)) + if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura) + { + damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); + if (caster->GetTypeId() != TYPEID_PLAYER) + damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); + } + + bool crit = false; + + if (CanPeriodicTickCrit(target, caster)) + crit = roll_chance_f(isAreaAura ? caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask()) : m_critChance); - bool crit = IsPeriodicTickCrit(target, caster); if (crit) damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target); @@ -5906,23 +5911,42 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c uint32 resist = 0; CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - uint32 damage = std::max(GetAmount(), 0); + bool isAreaAura = m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA); + // ignore negative values (can be result apply spellmods to aura damage + uint32 damage = isAreaAura ? std::max(GetAmount(), 0) : m_damage; - damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); + if (isAreaAura) + { + // Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations + sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); + damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellDamagePctDone(target, m_spellInfo, DOT); + } damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); - bool crit = IsPeriodicTickCrit(target, caster); - if (crit) - damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target); - // Calculate armor mitigation - if (Unit::IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), m_effIndex)) + if (Unit::IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), GetEffIndex())) { uint32 damageReductedArmor = caster->CalcArmorReducedDamage(target, damage, GetSpellInfo()); cleanDamage.mitigated_damage += damage - damageReductedArmor; damage = damageReductedArmor; } + if (!(m_spellInfo->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE)) + if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura) + { + damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); + if (caster->GetTypeId() != TYPEID_PLAYER) + damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); + } + + bool crit = false; + + if (CanPeriodicTickCrit(target, caster)) + crit = roll_chance_f(isAreaAura ? caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask()) : m_critChance); + + if (crit) + damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target); + int32 dmg = damage; if (!(GetSpellInfo()->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE)) caster->ApplyResilience(target, NULL, &dmg, crit, CR_CRIT_TAKEN_SPELL); @@ -6007,8 +6031,9 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const if (GetBase()->IsPermanent() && target->IsFullHealth()) return; + bool isAreaAura = m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA); // ignore negative values (can be result apply spellmods to aura damage - int32 damage = std::max(m_amount, 0); + int32 damage = isAreaAura ? std::max(GetAmount(), 0) : m_damage; if (GetAuraType() == SPELL_AURA_OBS_MOD_HEALTH) { @@ -6056,12 +6081,16 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const damage += addition; } - - damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); + if (isAreaAura) + damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellHealingPctDone(target, m_spellInfo); damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); } - bool crit = IsPeriodicTickCrit(target, caster); + bool crit = false; + + if (CanPeriodicTickCrit(target, caster)) + crit = roll_chance_f(isAreaAura ? caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask()) : m_critChance); + if (crit) damage = caster->SpellCriticalHealingBonus(m_spellInfo, damage, target); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 0887ce123e2..c8c6ad7fad7 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -70,6 +70,13 @@ class AuraEffect void HandleEffect(Unit* target, uint8 mode, bool apply); void ApplySpellMod(Unit* target, bool apply); + void SetDamage(int32 val) { m_damage = val; } + int32 GetDamage() const { return m_damage; } + void SetCritChance(float val) { m_critChance = val; } + float GetCritChance() const { return m_critChance; } + void SetDonePct(float val) { m_donePct = val; } + float GetDonePct() const { return m_donePct; } + void Update(uint32 diff, Unit* caster); void UpdatePeriodic(Unit* caster); @@ -98,6 +105,9 @@ class AuraEffect int32 const m_baseAmount; int32 m_amount; + int32 m_damage; + float m_critChance; + float m_donePct; SpellModifier* m_spellmod; @@ -109,7 +119,7 @@ class AuraEffect bool m_canBeRecalculated; bool m_isPeriodic; private: - bool IsPeriodicTickCrit(Unit* target, Unit const* caster) const; + bool CanPeriodicTickCrit(Unit* target, Unit const* caster) const; public: // aura effect apply/remove handlers diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 3e1763e6c5b..683059b8e99 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -746,9 +746,20 @@ void Aura::SetDuration(int32 duration, bool withMods) SetNeedClientUpdateForTargets(); } -void Aura::RefreshDuration() +void Aura::RefreshDuration(bool withMods) { - SetDuration(GetMaxDuration()); + if (withMods) + { + int32 duration = m_spellInfo->GetMaxDuration(); + // Calculate duration of periodics affected by haste. + if (GetCaster()->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION) + duration = int32(duration * GetCaster()->GetFloatValue(UNIT_MOD_CAST_SPEED)); + + SetMaxDuration(duration); + SetDuration(duration); + } + else + SetDuration(GetMaxDuration()); if (m_spellInfo->ManaPerSecond || m_spellInfo->ManaPerSecondPerLevel) m_timeCla = 1 * IN_MILLISECONDS; @@ -825,7 +836,10 @@ void Aura::SetStackAmount(uint8 stackAmount) for (std::list<AuraApplication*>::const_iterator apptItr = applications.begin(); apptItr != applications.end(); ++apptItr) if (!(*apptItr)->GetRemoveMode()) + { HandleAuraSpecificMods(*apptItr, caster, true, true); + HandleAuraSpecificPeriodics(*apptItr, caster); + } SetNeedClientUpdateForTargets(); } @@ -1631,26 +1645,62 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b break; } break; - case SPELLFAMILY_WARLOCK: - // Drain Soul - If the target is at or below 25% health, Drain Soul causes four times the normal damage - if (GetSpellInfo()->SpellFamilyFlags[0] & 0x00004000) + } +} + +void Aura::HandleAuraSpecificPeriodics(AuraApplication const* aurApp, Unit* caster) +{ + Unit* target = aurApp->GetTarget(); + + if (!caster || aurApp->GetRemoveMode()) + return; + + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (!HasEffect(i)) + continue; + + if (m_spellInfo->Effects[i].IsAreaAuraEffect() || m_spellInfo->Effects[i].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) + continue; + + switch (m_spellInfo->Effects[i].ApplyAuraName) + { + case SPELL_AURA_PERIODIC_DAMAGE: + case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: + case SPELL_AURA_PERIODIC_LEECH: { - if (!caster) - break; - if (apply) - { - if (target != caster && !target->HealthAbovePct(25)) - caster->CastSpell(caster, 100001, true); - } - else - { - if (target != caster) - caster->RemoveAurasDueToSpell(GetId()); - else - caster->RemoveAurasDueToSpell(100001); - } + AuraEffect* aurEff = GetEffect(i); + + // ignore non positive values (can be result apply spellmods to aura damage + uint32 damage = std::max(aurEff->GetAmount(), 0); + + // Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations + sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); + + aurEff->SetDonePct(caster->SpellDamagePctDone(target, m_spellInfo, DOT)); // Calculate done percentage first! + aurEff->SetDamage(caster->SpellDamageBonusDone(target, m_spellInfo, damage, DOT, GetStackAmount()) * aurEff->GetDonePct()); + aurEff->SetCritChance(caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask())); + break; } - break; + case SPELL_AURA_PERIODIC_HEAL: + case SPELL_AURA_OBS_MOD_HEALTH: + { + AuraEffect* aurEff = GetEffect(i); + + // ignore non positive values (can be result apply spellmods to aura damage + uint32 damage = std::max(aurEff->GetAmount(), 0); + + // Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations + sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); + + aurEff->SetDonePct(caster->SpellHealingPctDone(target, m_spellInfo)); // Calculate done percentage first! + aurEff->SetDamage(caster->SpellHealingBonusDone(target, m_spellInfo, damage, DOT, GetStackAmount()) * aurEff->GetDonePct()); + aurEff->SetCritChance(caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask())); + break; + } + default: + break; + } } } diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index f62b1ff47b4..669d2a529a1 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -129,7 +129,7 @@ class Aura int32 CalcMaxDuration(Unit* caster) const; int32 GetDuration() const { return m_duration; } void SetDuration(int32 duration, bool withMods = false); - void RefreshDuration(); + void RefreshDuration(bool withMods = false); void RefreshTimers(); bool IsExpired() const { return !GetDuration();} bool IsPermanent() const { return GetMaxDuration() == -1; } @@ -190,6 +190,7 @@ class Aura void SetNeedClientUpdateForTargets() const; void HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, bool apply, bool onReapply); + void HandleAuraSpecificPeriodics(AuraApplication const* aurApp, Unit* caster); bool CanBeAppliedOn(Unit* target); bool CheckAreaTarget(Unit* target); bool CanStackWith(Aura const* existingAura) const; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index f5d90bc3612..ca170187e82 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2340,7 +2340,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // Do healing and triggers if (m_healing > 0) { - bool crit = caster->isSpellCrit(unitTarget, m_spellInfo, m_spellSchoolMask); + bool crit = caster->IsSpellCrit(unitTarget, m_spellInfo, m_spellSchoolMask); uint32 addhealth = m_healing; if (crit) { @@ -6729,7 +6729,7 @@ void Spell::DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier) } } - targetInfo.crit = m_caster->isSpellCrit(unit, m_spellInfo, m_spellSchoolMask, m_attackType); + targetInfo.crit = m_caster->IsSpellCrit(unit, m_spellInfo, m_spellSchoolMask, m_attackType); } SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& skillId, int32& reqSkillValue, int32& skillValue) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 5b68d244457..6df87228f3e 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4056,15 +4056,40 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) { // Get diseases on target of spell if (m_targets.GetUnitTarget() && // Glyph of Disease - cast on unit target too to refresh aura - (m_targets.GetUnitTarget() != unitTarget || m_caster->GetAura(63334))) + (m_targets.GetUnitTarget() != unitTarget || m_caster->HasAura(63334))) { // And spread them on target // Blood Plague - if (m_targets.GetUnitTarget()->GetAura(55078)) + if (m_targets.GetUnitTarget()->HasAura(55078)) + { + AuraEffect* aurEffOld = m_targets.GetUnitTarget()->GetAura(55078)->GetEffect(0); + float donePct = aurEffOld->GetDonePct(); + float critChance = aurEffOld->GetCritChance(); + m_caster->CastSpell(unitTarget, 55078, true); + + if (unitTarget->HasAura(55078)) + if (AuraEffect* aurEffNew = unitTarget->GetAura(55078)->GetEffect(0)) + { + aurEffNew->SetCritChance(critChance); // Blood Plague can crit if caster has T9. + aurEffNew->SetDonePct(donePct); + aurEffNew->SetDamage(m_caster->SpellDamageBonusDone(unitTarget, aurEffNew->GetSpellInfo(), std::max(aurEffNew->GetAmount(), 0), DOT) * donePct); + } + } // Frost Fever - if (m_targets.GetUnitTarget()->GetAura(55095)) + if (m_targets.GetUnitTarget()->HasAura(55095)) + { + float donePct = m_targets.GetUnitTarget()->GetAura(55095)->GetEffect(0)->GetDonePct(); + m_caster->CastSpell(unitTarget, 55095, true); + + if (unitTarget->HasAura(55095)) + if (AuraEffect* aurEffNew = unitTarget->GetAura(55095)->GetEffect(0)) + { + aurEffNew->SetDonePct(donePct); + aurEffNew->SetDamage(m_caster->SpellDamageBonusDone(unitTarget, aurEffNew->GetSpellInfo(), std::max(aurEffNew->GetAmount(), 0), DOT) * donePct); + } + } } } break; diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index 725312eafce..c3f994135aa 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -202,16 +202,21 @@ class spell_hun_chimera_shot : public SpellScriptLoader flag96 familyFlag = aura->GetSpellInfo()->SpellFamilyFlags; if (!(familyFlag[1] & 0x00000080 || familyFlag[0] & 0x0000C000)) continue; - if (AuraEffect const* aurEff = aura->GetEffect(0)) + if (AuraEffect* aurEff = aura->GetEffect(0)) { // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting. if (familyFlag[0] & 0x4000) { int32 TickCount = aurEff->GetTotalTicks(); spellId = SPELL_HUNTER_CHIMERA_SHOT_SERPENT; - basePoint = caster->SpellDamageBonusDone(unitTarget, aura->GetSpellInfo(), aurEff->GetAmount(), DOT, aura->GetStackAmount()); + basePoint = aurEff->GetDamage(); ApplyPct(basePoint, TickCount * 40); basePoint = unitTarget->SpellDamageBonusTaken(caster, aura->GetSpellInfo(), basePoint, DOT, aura->GetStackAmount()); + + // Recalculate bonus damage on roll. + uint32 damage = std::max(aurEff->GetAmount(), 0); + sScriptMgr->ModifyPeriodicDamageAurasTick(unitTarget, caster, damage); + aurEff->SetDamage(caster->SpellDamageBonusDone(unitTarget, aurEff->GetSpellInfo(), damage, DOT) * aurEff->GetDonePct()); } // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting. else if (familyFlag[1] & 0x00000080) diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index dea67b5222d..76781e0fdc2 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -531,10 +531,17 @@ class spell_pri_pain_and_suffering_proc : public SpellScriptLoader void HandleEffectScriptEffect(SpellEffIndex /*effIndex*/) { + Unit* caster = GetCaster(); // Refresh Shadow Word: Pain on target - if (Unit* unitTarget = GetHitUnit()) - if (AuraEffect* aur = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, GetCaster()->GetGUID())) + if (Unit* target = GetHitUnit()) + if (AuraEffect* aur = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, caster->GetGUID())) + { + uint32 damage = std::max(aur->GetAmount(), 0); + sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); + aur->SetDamage(caster->SpellDamageBonusDone(target, aur->GetSpellInfo(), damage, DOT) * aur->GetDonePct()); + aur->CalculatePeriodic(caster, false, false); aur->GetBase()->RefreshDuration(); + } } void Register() override diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index 18979d24ecb..3f935077b22 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -405,10 +405,17 @@ class spell_warl_everlasting_affliction : public SpellScriptLoader void HandleScriptEffect(SpellEffIndex /*effIndex*/) { - if (Unit* unitTarget = GetHitUnit()) + Unit* caster = GetCaster(); + if (Unit* target = GetHitUnit()) // Refresh corruption on target - if (AuraEffect* aur = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x2, 0, 0, GetCaster()->GetGUID())) - aur->GetBase()->RefreshDuration(); + if (AuraEffect* aur = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x2, 0, 0, caster->GetGUID())) + { + uint32 damage = std::max(aur->GetAmount(), 0); + sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); + aur->SetDamage(caster->SpellDamageBonusDone(target, aur->GetSpellInfo(), damage, DOT) * aur->GetDonePct()); + aur->CalculatePeriodic(caster, false, false); + aur->GetBase()->RefreshDuration(true); + } } void Register() override diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index fd1c785cf50..40d939c6394 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -36,7 +36,7 @@ enum WarriorSpells SPELL_WARRIOR_DEEP_WOUNDS_RANK_1 = 12162, SPELL_WARRIOR_DEEP_WOUNDS_RANK_2 = 12850, SPELL_WARRIOR_DEEP_WOUNDS_RANK_3 = 12868, - SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC = 12721, + SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC = 12721, SPELL_WARRIOR_EXECUTE = 20647, SPELL_WARRIOR_GLYPH_OF_EXECUTION = 58367, SPELL_WARRIOR_GLYPH_OF_VIGILANCE = 63326, @@ -268,23 +268,18 @@ class spell_warr_deep_wounds : public SpellScriptLoader Unit* caster = GetCaster(); if (Unit* target = GetHitUnit()) { - // apply percent damage mods - damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE); - ApplyPct(damage, 16 * GetSpellInfo()->GetRank()); - damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE); - - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC); + SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC); uint32 ticks = spellInfo->GetDuration() / spellInfo->Effects[EFFECT_0].Amplitude; // Add remaining ticks to damage done - if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC, EFFECT_0, caster->GetGUID())) - damage += aurEff->GetAmount() * (ticks - aurEff->GetTickNumber()); + if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC, EFFECT_0, caster->GetGUID())) + damage += aurEff->GetDamage() * (ticks - aurEff->GetTickNumber()); damage /= ticks; - caster->CastCustomSpell(target, SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC, &damage, NULL, NULL, true); + caster->CastCustomSpell(target, SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC, &damage, NULL, NULL, true); } } |