diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 6d190aee5..29592ad0d 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -927,6 +927,17 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) uint32 procVictim = m_procVictim; uint32 procEx = PROC_EX_NONE; + if (m_spellInfo->speed > 0) + { + // mark effects that were already handled in Spell::HandleDelayedSpellLaunch on spell launch as processed + for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) + if (IsEffectHandledOnDelayedSpellLaunch(m_spellInfo, SpellEffectIndex(i))) + mask &= ~(1<damage; + } + if (missInfo==SPELL_MISS_NONE) // In case spell hit target, do all effect on that target DoSpellHitOnUnit(unit, mask); else if (missInfo == SPELL_MISS_REFLECT) // In case spell reflect from target, do all effect on caster (if hit) @@ -966,8 +977,16 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) // Fill base damage struct (unitTarget - is real spell target) SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask); + if (m_spellInfo->speed > 0) + { + damageInfo.damage = m_damage; + damageInfo.HitInfo = target->HitInfo; + } // Add bonuses and fill damageInfo struct - caster->CalculateSpellDamage(&damageInfo, m_damage, m_spellInfo, m_attackType); + else + caster->CalculateSpellDamage(&damageInfo, m_damage, m_spellInfo, m_attackType); + + unitTarget->CalculateAbsorbResistBlock(caster, &damageInfo, m_spellInfo); caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); @@ -1184,6 +1203,56 @@ void Spell::DoAllEffectOnTarget(ItemTargetInfo *target) HandleEffects(NULL, target->item, NULL, SpellEffectIndex(effectNumber)); } +void Spell::HandleDelayedSpellLaunch(TargetInfo *target) +{ + // Get mask of effects for target + uint32 mask = target->effectMask; + + Unit* unit = m_caster->GetObjectGuid() == target->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, target->targetGUID); + if (!unit) + return; + + // Get original caster (if exist) and calculate damage/healing from him data + Unit *real_caster = GetAffectiveCaster(); + // FIXME: in case wild GO heal/damage spells will be used target bonuses + Unit *caster = real_caster ? real_caster : m_caster; + + SpellMissInfo missInfo = target->missCondition; + // Need init unitTarget by default unit (can changed in code on reflect) + // Or on missInfo!=SPELL_MISS_NONE unitTarget undefined (but need in trigger subsystem) + unitTarget = unit; + + // Reset damage/healing counter + m_damage = 0; + m_healing = 0; // healing maybe not needed at this point + + // Fill base damage struct (unitTarget - is real spell target) + SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask); + + for (int32 effectNumber = 0; effectNumber < MAX_EFFECT_INDEX; ++effectNumber) + { + if (mask & (1 << effectNumber) && IsEffectHandledOnDelayedSpellLaunch(m_spellInfo, SpellEffectIndex(effectNumber))) + { + HandleEffects(unit, NULL, NULL, SpellEffectIndex(effectNumber), m_damageMultipliers[effectNumber]); + if ( m_applyMultiplierMask & (1 << effectNumber) ) + { + // Get multiplier + float multiplier = m_spellInfo->DmgMultiplier[effectNumber]; + // Apply multiplier mods + if (real_caster) + if(Player* modOwner = real_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_EFFECT_PAST_FIRST, multiplier, this); + m_damageMultipliers[effectNumber] *= multiplier; + } + } + } + + caster->CalculateSpellDamage(&damageInfo, m_damage, m_spellInfo, m_attackType); + + target->damage = damageInfo.damage; + target->HitInfo = damageInfo.HitInfo; +} + bool Spell::IsAliveUnitPresentInTargetList() { // Not need check return true @@ -2658,6 +2727,10 @@ void Spell::cast(bool skipCheck) // in case delayed spell remove item at cast delay start TakeCastItem(); + // fill initial spell damage from caster for delayed casted spells + for(std::list::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + HandleDelayedSpellLaunch(&(*ihit)); + // Okay, maps created, now prepare flags m_immediateHandled = false; m_spellState = SPELL_STATE_DELAYED; diff --git a/src/game/Spell.h b/src/game/Spell.h index 9efbe81ac..cff17d9fa 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -573,6 +573,8 @@ class Spell { ObjectGuid targetGUID; uint64 timeDelay; + uint32 HitInfo; + uint32 damage; SpellMissInfo missCondition:8; SpellMissInfo reflectResult:8; uint8 effectMask:8; @@ -603,6 +605,7 @@ class Spell void AddGOTarget(uint64 goGUID, SpellEffectIndex effIndex); void AddItemTarget(Item* target, SpellEffectIndex effIndex); void DoAllEffectOnTarget(TargetInfo *target); + void HandleDelayedSpellLaunch(TargetInfo *target); void DoSpellHitOnUnit(Unit *unit, uint32 effectMask); void DoAllEffectOnTarget(GOTargetInfo *target); void DoAllEffectOnTarget(ItemTargetInfo *target); diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 852f2737c..6d3bd1ee3 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -7478,6 +7478,8 @@ void Aura::PeriodicTick() SpellNonMeleeDamage damageInfo(pCaster, m_target, spellProto->Id, spellProto->SchoolMask); pCaster->CalculateSpellDamage(&damageInfo, gain, spellProto); + damageInfo.target->CalculateAbsorbResistBlock(pCaster, &damageInfo, spellProto); + pCaster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); pCaster->SendSpellNonMeleeDamageLog(&damageInfo); diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h index 5ebccaa83..270a33c31 100644 --- a/src/game/SpellMgr.h +++ b/src/game/SpellMgr.h @@ -136,6 +136,21 @@ inline bool IsSpellHaveEffect(SpellEntry const *spellInfo, SpellEffects effect) return false; } +inline bool IsEffectHandledOnDelayedSpellLaunch(SpellEntry const *spellInfo, SpellEffectIndex effecIdx) +{ + switch (spellInfo->Effect[effecIdx]) + { + case SPELL_EFFECT_SCHOOL_DAMAGE: + case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: + case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: + case SPELL_EFFECT_WEAPON_DAMAGE: + case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: + return true; + default: + return false; + } +} + inline bool IsSpellHaveAura(SpellEntry const *spellInfo, AuraType aura) { for(int i = 0; i < MAX_EFFECT_INDEX; ++i) diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 3250328e4..c29ce02e9 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -1186,6 +1186,7 @@ uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID); SpellNonMeleeDamage damageInfo(this, pVictim, spellInfo->Id, spellInfo->SchoolMask); CalculateSpellDamage(&damageInfo, damage, spellInfo); + damageInfo.target->CalculateAbsorbResistBlock(this, &damageInfo, spellInfo); DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb); SendSpellNonMeleeDamageLog(&damageInfo); DealSpellDamage(&damageInfo, true); @@ -1207,7 +1208,6 @@ void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, S // Check spell crit chance bool crit = IsSpellCrit(pVictim, spellInfo, damageSchoolMask, attackType); - bool blocked = false; // damage bonus (per damage class) switch (spellInfo->DmgClass) @@ -1218,8 +1218,6 @@ void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, S { //Calculate damage bonus damage = MeleeDamageBonus(pVictim, damage, attackType, spellInfo, SPELL_DIRECT_DAMAGE); - // Get blocked status - blocked = pVictim->IsSpellBlocked(this, spellInfo, attackType); // if crit add critical bonus if (crit) @@ -1270,19 +1268,6 @@ void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, S uint32 armor_affected_damage = CalcNotIgnoreDamageRedunction(damage,damageSchoolMask); damage = damage - armor_affected_damage + CalcArmorReducedDamage(pVictim, armor_affected_damage); } - - // block (only for damage class ranged and -melee, also non-physical damage possible) - if (blocked) - { - damageInfo->blocked = pVictim->GetShieldBlockValue(); - if (damage < (int32)damageInfo->blocked) - damageInfo->blocked = damage; - damage-=damageInfo->blocked; - } - - uint32 absorb_affected_damage = CalcNotIgnoreAbsorbDamage(damage,damageSchoolMask,spellInfo); - pVictim->CalculateAbsorbAndResist(this, damageSchoolMask, SPELL_DIRECT_DAMAGE, absorb_affected_damage, &damageInfo->absorb, &damageInfo->resist, !(spellInfo->AttributesEx2 & SPELL_ATTR_EX2_CANT_REFLECTED)); - damage-= damageInfo->absorb + damageInfo->resist; } else damage = 0; @@ -1319,7 +1304,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss) } // Call default DealDamage (send critical in hit info for threat calculation) - CleanDamage cleanDamage(damageInfo->cleanDamage, BASE_ATTACK, damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT ? MELEE_HIT_CRIT : MELEE_HIT_NORMAL); + CleanDamage cleanDamage(0, BASE_ATTACK, damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT ? MELEE_HIT_CRIT : MELEE_HIT_NORMAL); DealDamage(pVictim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss); } @@ -2332,6 +2317,34 @@ void Unit::CalculateAbsorbAndResist(Unit *pCaster, SpellSchoolMask schoolMask, D *absorb = damage - RemainingDamage - *resist; } +void Unit::CalculateAbsorbResistBlock(Unit *pCaster, SpellNonMeleeDamage *damageInfo, SpellEntry const* spellProto, WeaponAttackType attType) +{ + bool blocked = false; + // Get blocked status + switch (spellProto->DmgClass) + { + // Melee and Ranged Spells + case SPELL_DAMAGE_CLASS_RANGED: + case SPELL_DAMAGE_CLASS_MELEE: + blocked = IsSpellBlocked(pCaster, spellProto, attType); + break; + default: + break; + } + + if (blocked) + { + damageInfo->blocked = GetShieldBlockValue(); + if (damageInfo->damage < (int32)damageInfo->blocked) + damageInfo->blocked = damageInfo->damage; + damageInfo->damage-=damageInfo->blocked; + } + + uint32 absorb_affected_damage = pCaster->CalcNotIgnoreAbsorbDamage(damageInfo->damage,GetSpellSchoolMask(spellProto),spellProto); + CalculateAbsorbAndResist(pCaster, GetSpellSchoolMask(spellProto), SPELL_DIRECT_DAMAGE, absorb_affected_damage, &damageInfo->absorb, &damageInfo->resist, !(spellProto->AttributesEx2 & SPELL_ATTR_EX2_CANT_REFLECTED)); + damageInfo->damage-= damageInfo->absorb + damageInfo->resist; +} + void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool extra ) { if(hasUnitState(UNIT_STAT_CAN_NOT_REACT) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) ) @@ -12439,6 +12452,7 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag sLog.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", auraModifier->m_amount, spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); SpellNonMeleeDamage damageInfo(this, pTarget, spellInfo->Id, spellInfo->SchoolMask); CalculateSpellDamage(&damageInfo, auraModifier->m_amount, spellInfo); + damageInfo.target->CalculateAbsorbResistBlock(this, &damageInfo, spellInfo); DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb); SendSpellNonMeleeDamageLog(&damageInfo); DealSpellDamage(&damageInfo, true); diff --git a/src/game/Unit.h b/src/game/Unit.h index cbe061a9c..06c38a490 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -877,7 +877,7 @@ struct CalcDamageInfo struct SpellNonMeleeDamage{ SpellNonMeleeDamage(Unit *_attacker, Unit *_target, uint32 _SpellID, uint32 _schoolMask) : target(_target), attacker(_attacker), SpellID(_SpellID), damage(0), overkill(0), schoolMask(_schoolMask), - absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0) + absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0) {} Unit *target; @@ -892,8 +892,6 @@ struct SpellNonMeleeDamage{ bool unused; uint32 blocked; uint32 HitInfo; - // Used for help - uint32 cleanDamage; }; struct SpellPeriodicAuraLogInfo @@ -1742,6 +1740,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject uint32 CalcArmorReducedDamage(Unit* pVictim, const uint32 damage); void CalculateAbsorbAndResist(Unit *pCaster, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist, bool canReflect = false); + void CalculateAbsorbResistBlock(Unit *pCaster, SpellNonMeleeDamage *damageInfo, SpellEntry const* spellProto, WeaponAttackType attType = BASE_ATTACK); void UpdateWalkMode(Unit* source, bool self = true); void UpdateSpeed(UnitMoveType mtype, bool forced, float ratio = 1.0f); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index fc72e928e..a7763850b 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 "9783" + #define REVISION_NR "9784" #endif // __REVISION_NR_H__