diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index fe5a05198..815284c7f 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -95,6 +95,107 @@ uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell) return (castTime > 0) ? uint32(castTime) : 0; } +uint32 GetSpellCastTimeForBonus( SpellEntry const *spellProto, DamageEffectType damagetype ) +{ + uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto); + + if (CastingTime > 7000) CastingTime = 7000; + if (CastingTime < 1500) CastingTime = 1500; + + if(damagetype == DOT && !IsChanneledSpell(spellProto)) + CastingTime = 3500; + + int32 overTime = 0; + uint8 effects = 0; + bool DirectDamage = false; + bool AreaEffect = false; + + for (uint32 i = 0; i < MAX_EFFECT_INDEX; ++i) + if (IsAreaEffectTarget(Targets(spellProto->EffectImplicitTargetA[i])) || IsAreaEffectTarget(Targets(spellProto->EffectImplicitTargetB[i]))) + AreaEffect = true; + + for (uint32 i = 0; i < MAX_EFFECT_INDEX; ++i) + { + switch (spellProto->Effect[i]) + { + case SPELL_EFFECT_SCHOOL_DAMAGE: + case SPELL_EFFECT_POWER_DRAIN: + case SPELL_EFFECT_HEALTH_LEECH: + case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE: + case SPELL_EFFECT_POWER_BURN: + case SPELL_EFFECT_HEAL: + DirectDamage = true; + break; + case SPELL_EFFECT_APPLY_AURA: + switch (spellProto->EffectApplyAuraName[i]) + { + case SPELL_AURA_PERIODIC_DAMAGE: + case SPELL_AURA_PERIODIC_HEAL: + case SPELL_AURA_PERIODIC_LEECH: + if ( GetSpellDuration(spellProto) ) + overTime = GetSpellDuration(spellProto); + break; + // Penalty for additional effects + case SPELL_AURA_DUMMY: + ++effects; + break; + case SPELL_AURA_MOD_DECREASE_SPEED: + ++effects; + break; + case SPELL_AURA_MOD_CONFUSE: + case SPELL_AURA_MOD_STUN: + case SPELL_AURA_MOD_ROOT: + // -10% per effect + effects += 2; + break; + default: + break; + } + default: + break; + } + } + + // Combined Spells with Both Over Time and Direct Damage + if (overTime > 0 && CastingTime > 0 && DirectDamage) + { + // mainly for DoTs which are 3500 here otherwise + uint32 OriginalCastTime = GetSpellCastTime(spellProto); + if (OriginalCastTime > 7000) OriginalCastTime = 7000; + if (OriginalCastTime < 1500) OriginalCastTime = 1500; + // Portion to Over Time + float PtOT = (overTime / 15000.0f) / ((overTime / 15000.0f) + (OriginalCastTime / 3500.0f)); + + if (damagetype == DOT) + CastingTime = uint32(CastingTime * PtOT); + else if (PtOT < 1.0f) + CastingTime = uint32(CastingTime * (1 - PtOT)); + else + CastingTime = 0; + } + + // Area Effect Spells receive only half of bonus + if (AreaEffect) + CastingTime /= 2; + + // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing + for(int j = 0; j < MAX_EFFECT_INDEX; ++j) + { + if (spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH || + spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) + { + CastingTime /= 2; + break; + } + } + + // -5% of total per any additional effect (multiplicative) + for (int i = 0; i < effects; ++i) + CastingTime *= 0.95f; + + return CastingTime; +} + uint16 GetSpellAuraMaxTicks(SpellEntry const* spellInfo) { int32 DotDuration = GetSpellDuration(spellInfo); diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h index e9b8c5286..b709b7ca5 100644 --- a/src/game/SpellMgr.h +++ b/src/game/SpellMgr.h @@ -110,6 +110,7 @@ SpellSpecific GetSpellSpecific(uint32 spellId); // Different spell properties inline float GetSpellRadius(SpellRadiusEntry const *radius) { return (radius ? radius->Radius : 0); } uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell = NULL); +uint32 GetSpellCastTimeForBonus( SpellEntry const *spellProto, DamageEffectType damagetype ); inline float GetSpellMinRange(SpellRangeEntry const *range, bool friendly = false) { if(!range) diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 3b3689239..ae2dd8d60 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -9187,21 +9187,16 @@ uint32 Unit::SpellDamageBonusDone(Unit *pVictim, SpellEntry const *spellProto, u if (uint16 DotTicks = GetSpellAuraMaxTicks(spellProto)) DoneAdvertisedBenefit = DoneAdvertisedBenefit / DotTicks; } + // Distribute Damage over multiple effects, reduce by AoE - uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto); - CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime ); - // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing - for(int j = 0; j < MAX_EFFECT_INDEX; ++j) - { - if (spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH || - (spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && - spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH)) - { - CastingTime /= 2; - break; - } - } - DoneTotal += int32(DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty * SpellModSpellDamage); + // Not apply this to creature casted spells + float coeff; + if (GetTypeId()==TYPEID_UNIT && !((Creature*)this)->isPet()) + coeff = 1.0f; + else + coeff = GetSpellCastTimeForBonus(spellProto, damagetype) / 3500.0f; + + DoneTotal += int32(DoneAdvertisedBenefit * coeff * DotFactor * LvlPenalty * SpellModSpellDamage); } float tmpDamage = (int32(pdamage) + DoneTotal * int32(stack)) * DoneTotalMod; @@ -9294,21 +9289,16 @@ uint32 Unit::SpellDamageBonusTaken(Unit *pCaster, SpellEntry const *spellProto, if (uint16 DotTicks = GetSpellAuraMaxTicks(spellProto)) TakenAdvertisedBenefit = TakenAdvertisedBenefit / DotTicks; } + // Distribute Damage over multiple effects, reduce by AoE - uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto); - CastingTime = pCaster->GetCastingTimeForBonus( spellProto, damagetype, CastingTime ); - // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing - for(int j = 0; j < MAX_EFFECT_INDEX; ++j) - { - if (spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH || - (spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && - spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH)) - { - CastingTime /= 2; - break; - } - } - TakenTotal+= int32(TakenAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty); + // Not apply this to creature casted spells + float coeff; + if (pCaster->GetTypeId()==TYPEID_UNIT && !((Creature*)pCaster)->isPet()) + coeff = 1.0f; + else + coeff = GetSpellCastTimeForBonus(spellProto, damagetype) / 3500.0f; + + TakenTotal+= int32(TakenAdvertisedBenefit * coeff * DotFactor * LvlPenalty); } float tmpDamage = (int32(pdamage) + TakenTotal * int32(stack)) * TakenTotalMod; @@ -9744,20 +9734,16 @@ uint32 Unit::SpellHealingBonusDone(Unit *pVictim, SpellEntry const *spellProto, if(DotTicks) DoneAdvertisedBenefit = DoneAdvertisedBenefit / DotTicks; } + // Distribute Damage over multiple effects, reduce by AoE - uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto); - CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime ); - // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing - for(int j = 0; j < MAX_EFFECT_INDEX; ++j) - { - if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH || - spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH ) - { - CastingTime /= 2; - break; - } - } - DoneTotal += int32(DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty * SpellModSpellDamage * 1.88f); + // Not apply this to creature casted spells + float coeff; + if (GetTypeId()==TYPEID_UNIT && !((Creature*)this)->isPet()) + coeff = 1.0f; + else + coeff = GetSpellCastTimeForBonus(spellProto, damagetype) / 3500.0f; + + DoneTotal += int32(DoneAdvertisedBenefit * coeff * DotFactor * LvlPenalty * SpellModSpellDamage * 1.88f); } // use float as more appropriate for negative values and percent applying @@ -9827,20 +9813,16 @@ uint32 Unit::SpellHealingBonusTaken(Unit *pCaster, SpellEntry const *spellProto, if(DotTicks) TakenAdvertisedBenefit = TakenAdvertisedBenefit / DotTicks; } + // Distribute Damage over multiple effects, reduce by AoE - uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto); - CastingTime = pCaster->GetCastingTimeForBonus( spellProto, damagetype, CastingTime ); - // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing - for(int j = 0; j < MAX_EFFECT_INDEX; ++j) - { - if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH || - spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH ) - { - CastingTime /= 2; - break; - } - } - TakenTotal += int32(TakenAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty * 1.88f); + // Not apply this to creature casted spells + float coeff; + if (GetTypeId()==TYPEID_UNIT && !((Creature*)this)->isPet()) + coeff = 1.0f; + else + coeff = GetSpellCastTimeForBonus(spellProto, damagetype) / 3500.0f; + + TakenTotal += int32(TakenAdvertisedBenefit * coeff * DotFactor * LvlPenalty * 1.88f); } AuraList const& mHealingGet= GetAurasByType(SPELL_AURA_MOD_HEALING_RECEIVED); @@ -10249,10 +10231,16 @@ uint32 Unit::MeleeDamageBonusDone(Unit *pVictim, uint32 pdamage,WeaponAttackType if(DotTicks) DoneFlat = DoneFlat / DotTicks; } + // Distribute Damage over multiple effects, reduce by AoE - uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto); - CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime ); - DoneFlat *= (CastingTime / 3500.0f) * DotFactor * LvlPenalty; + // Not apply this to creature casted spells + float coeff; + if (GetTypeId()==TYPEID_UNIT && !((Creature*)this)->isPet()) + coeff = 1.0f; + else + coeff = GetSpellCastTimeForBonus(spellProto, damagetype) / 3500.0f; + + DoneFlat *= coeff * DotFactor * LvlPenalty; } } // weapon damage based spells @@ -10403,10 +10391,16 @@ uint32 Unit::MeleeDamageBonusTaken(Unit *pCaster, uint32 pdamage,WeaponAttackTyp if(DotTicks) TakenFlat = TakenFlat / DotTicks; } + // Distribute Damage over multiple effects, reduce by AoE - uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto); - CastingTime = pCaster->GetCastingTimeForBonus( spellProto, damagetype, CastingTime ); - TakenFlat*= (CastingTime / 3500.0f) * DotFactor * LvlPenalty; + // Not apply this to creature casted spells + float coeff; + if (pCaster->GetTypeId()==TYPEID_UNIT && !((Creature*)pCaster)->isPet()) + coeff = 1.0f; + else + coeff = GetSpellCastTimeForBonus(spellProto, damagetype) / 3500.0f; + + TakenFlat*= coeff * DotFactor * LvlPenalty; } } @@ -13253,96 +13247,6 @@ void Unit::ApplyCastTimePercentMod(float val, bool apply ) ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED,-val,apply); } -uint32 Unit::GetCastingTimeForBonus( SpellEntry const *spellProto, DamageEffectType damagetype, uint32 CastingTime ) -{ - // Not apply this to creature casted spells with casttime==0 - if(CastingTime==0 && GetTypeId()==TYPEID_UNIT && !((Creature*)this)->isPet()) - return 3500; - - if (CastingTime > 7000) CastingTime = 7000; - if (CastingTime < 1500) CastingTime = 1500; - - if(damagetype == DOT && !IsChanneledSpell(spellProto)) - CastingTime = 3500; - - int32 overTime = 0; - uint8 effects = 0; - bool DirectDamage = false; - bool AreaEffect = false; - - for (uint32 i = 0; i < MAX_EFFECT_INDEX; ++i) - { - switch (spellProto->Effect[i]) - { - case SPELL_EFFECT_SCHOOL_DAMAGE: - case SPELL_EFFECT_POWER_DRAIN: - case SPELL_EFFECT_HEALTH_LEECH: - case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE: - case SPELL_EFFECT_POWER_BURN: - case SPELL_EFFECT_HEAL: - DirectDamage = true; - break; - case SPELL_EFFECT_APPLY_AURA: - switch (spellProto->EffectApplyAuraName[i]) - { - case SPELL_AURA_PERIODIC_DAMAGE: - case SPELL_AURA_PERIODIC_HEAL: - case SPELL_AURA_PERIODIC_LEECH: - if ( GetSpellDuration(spellProto) ) - overTime = GetSpellDuration(spellProto); - break; - default: - // -5% per additional effect - ++effects; - break; - } - default: - break; - } - - if (IsAreaEffectTarget(Targets(spellProto->EffectImplicitTargetA[i])) || IsAreaEffectTarget(Targets(spellProto->EffectImplicitTargetB[i]))) - AreaEffect = true; - } - - // Combined Spells with Both Over Time and Direct Damage - if (overTime > 0 && CastingTime > 0 && DirectDamage) - { - // mainly for DoTs which are 3500 here otherwise - uint32 OriginalCastTime = GetSpellCastTime(spellProto); - if (OriginalCastTime > 7000) OriginalCastTime = 7000; - if (OriginalCastTime < 1500) OriginalCastTime = 1500; - // Portion to Over Time - float PtOT = (overTime / 15000.0f) / ((overTime / 15000.0f) + (OriginalCastTime / 3500.0f)); - - if (damagetype == DOT) - CastingTime = uint32(CastingTime * PtOT); - else if (PtOT < 1.0f) - CastingTime = uint32(CastingTime * (1 - PtOT)); - else - CastingTime = 0; - } - - // Area Effect Spells receive only half of bonus - if (AreaEffect) - CastingTime /= 2; - - // -5% of total per any additional effect - for (uint8 i = 0; i < effects; ++i) - { - if (CastingTime > 175) - { - CastingTime -= 175; - } - else - { - CastingTime = 0; - break; - } - } - - return CastingTime; -} - void Unit::UpdateAuraForGroup(uint8 slot) { if(GetTypeId() == TYPEID_PLAYER) diff --git a/src/game/Unit.h b/src/game/Unit.h index bd0593b63..bf255d84d 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1748,8 +1748,6 @@ class MANGOS_DLL_SPEC Unit : public WorldObject void SetContestedPvP(Player *attackedPlayer = NULL); - uint32 GetCastingTimeForBonus( SpellEntry const *spellProto, DamageEffectType damagetype, uint32 CastingTime ); - void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply); void ApplySpellDispelImmunity(const SpellEntry * spellProto, DispelType type, bool apply); virtual bool IsImmunedToSpell(SpellEntry const* spellInfo); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 871efb5a6..b2b2e4d51 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "9893" + #define REVISION_NR "9894" #endif // __REVISION_NR_H__