Core/Spells: Implementation of QAston proc system

- Move checks from Unit::IsTriggeredAtSpellProcEvent (old system) to Aura::IsProcTriggeredOnEvent (new system)
- Templatize SpellModOp param of Player::ApplySpellMod, also killed charge counter from SpellModifier and Player system for handling charges... no point in having 3 different systems doing the same thing
- Automatically add default entries to spellProcMap, based on spellinfo (else auras won't proc without an entry) Based on old Unit::ProcDamageAndSpellFor
- Old Unit::ProcDamageAndSpellFor renamed to Unit::ProcSkillsAndReactives and made private, will no longer handle auras.
- Start making use of HealInfo::AbsorbHeal in unit calculations, add effective healing info to HealInfo struct
- Changes in spell reflection system, emulates old behaviour, delaying aura drop
- Removed old charge count hacks in SpellMgr::LoadSpellInfoCorrections
- Removed bogus error log when procChance is 0: Some auras have initial 0 procChance but modified by SPELLMOD_CHANCE_OF_SUCCESS
- Fixed TriggerAurasProcOnEvent logic that tried to trigger twice from actor.
- Allow non damaging spells with DamageClass Melee or Ranged to proc character enchants. Ref issue #17034:

  * http://web.archive.org/web/20110309092008/http://elitistjerks.com/f47/t49865-paladin_retribution_pve/
  * When an auto-attack lands (does not dodge/parry/miss) that can proc a seal the of the following things happen independently of each other (see 2 roll system).

  * 1) A "hidden strike" which uses melee combat mechanics occurs. If it lands it refreshes/stacks SoV DoT. Only white swings can trigger a refresh or stack. (This hidden strike mechanic can also proc things like berserking..)
  * 2) A weapon damage based proc will occur if you used a special (CS/DS/judge) or if you have a 5 stack (from auto attacks). This attack can not be avoided.

  * Holy Vengeance is the "hidden strike" it has an apply aura effect and damage class melee.
- Fixed Blood Tap interaction with Death Runes (btw, don't know what was going on with those MiscValueB, spell 45529 doesn't have any MiscValueB in SPELL_EFFECT_ACTIVATE_RUNE)
- Ported some AuraEffect checks from old Unit.cpp function. added new AuraScript hook to check procs of an specific effect
- Allow only AuraEffects that passed the check to proc, this won't block whole aura from proccing (and lose charges) if at least one of the effects procs, though
- Changes in spell mod system (for SPELLMOD_CASTING_TIME). fixes #17558.
- Added an exception for SPELLMOD_CRITICAL_CHANCE too, fixes #15193
This commit is contained in:
Aokromes
2016-10-05 13:19:51 +02:00
parent eb745277cd
commit a70e4e26b3
22 changed files with 1192 additions and 3882 deletions

View File

@@ -594,7 +594,7 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO
m_healing = 0;
m_procAttacker = 0;
m_procVictim = 0;
m_procEx = 0;
m_hitMask = 0;
focusObject = NULL;
m_cast_count = 0;
m_glyphIndex = 0;
@@ -1474,7 +1474,7 @@ void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTarg
{
uint32 maxTargets = m_spellInfo->Effects[effIndex].ChainTarget;
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, maxTargets, this);
modOwner->ApplySpellMod<SPELLMOD_JUMP_TARGETS>(m_spellInfo->Id, maxTargets, this);
if (maxTargets > 1)
{
@@ -1943,12 +1943,11 @@ GameObject* Spell::SearchSpellFocus()
return focus;
}
void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
void Spell::prepareDataForTriggerSystem()
{
//==========================================================================================
// Now fill data for trigger system, need know:
// can spell trigger another or not (m_canTrigger)
// Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_procEx)
// Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_hitMask)
//==========================================================================================
m_procVictim = m_procAttacker = 0;
@@ -1978,7 +1977,7 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
break;
default:
if (m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON &&
m_spellInfo->EquippedItemSubClassMask & (1<<ITEM_SUBCLASS_WEAPON_WAND)
m_spellInfo->EquippedItemSubClassMask & (1 << ITEM_SUBCLASS_WEAPON_WAND)
&& m_spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG)) // Wands auto attack
{
m_procAttacker = PROC_FLAG_DONE_RANGED_AUTO_ATTACK;
@@ -1987,7 +1986,7 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
// For other spells trigger procflags are set in Spell::DoAllEffectOnTarget
// Because spell positivity is dependant on target
}
m_procEx = PROC_EX_NONE;
m_hitMask = PROC_HIT_NONE;
// Hunter trap spells - activation proc for Lock and Load, Entrapment and Misdirection
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER &&
@@ -1998,29 +1997,12 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
m_procAttacker |= PROC_FLAG_DONE_TRAP_ACTIVATION;
}
/* Effects which are result of aura proc from triggered spell cannot proc
to prevent chain proc of these spells */
// Hellfire Effect - trigger as DOT
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags[0] & 0x00000040)
{
m_procAttacker = PROC_FLAG_DONE_PERIODIC;
m_procVictim = PROC_FLAG_TAKEN_PERIODIC;
}
// Ranged autorepeat attack is set as triggered spell - ignore it
if (!(m_procAttacker & PROC_FLAG_DONE_RANGED_AUTO_ATTACK))
{
if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS &&
(m_spellInfo->HasAttribute(SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC) ||
m_spellInfo->HasAttribute(SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2)))
m_procEx |= PROC_EX_INTERNAL_CANT_PROC;
else if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS)
m_procEx |= PROC_EX_INTERNAL_TRIGGERED;
}
// Totem casts require spellfamilymask defined in spell_proc_event to proc
if (m_originalCaster && m_caster != m_originalCaster && m_caster->GetTypeId() == TYPEID_UNIT && m_caster->IsTotem() && m_caster->IsControlledByPlayer())
m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY;
}
void Spell::CleanupTargetList()
@@ -2031,6 +2013,32 @@ void Spell::CleanupTargetList()
m_delayMoment = 0;
}
class ProcReflectDelayed : public BasicEvent
{
public:
ProcReflectDelayed(Unit* owner, ObjectGuid casterGuid) : _victim(owner), _casterGuid(casterGuid) { }
bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override
{
Unit* caster = ObjectAccessor::GetUnit(*_victim, _casterGuid);
if (!caster)
return true;
uint32 const typeMaskActor = PROC_FLAG_NONE;
uint32 const typeMaskActionTarget = PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG;
uint32 const spellTypeMask = PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL;
uint32 const spellPhaseMask = PROC_SPELL_PHASE_NONE;
uint32 const hitMask = PROC_HIT_REFLECT;
caster->ProcSkillsAndAuras(_victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, nullptr, nullptr, nullptr);
return true;
}
private:
Unit* _victim;
ObjectGuid _casterGuid;
};
void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/, bool implicit /*= true*/, Position const* losPosition /*= nullptr*/)
{
for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
@@ -2114,20 +2122,20 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
targetInfo.timeDelay = uint64(m_spellInfo->Speed * 1000.0f);
// Calculate minimum incoming time
if (m_delayMoment == 0 || m_delayMoment > targetInfo.timeDelay)
if (!m_delayMoment || m_delayMoment > targetInfo.timeDelay)
m_delayMoment = targetInfo.timeDelay;
}
else
targetInfo.timeDelay = 0LL;
targetInfo.timeDelay = 0ULL;
// If target reflect spell back to caster
if (targetInfo.missCondition == SPELL_MISS_REFLECT)
{
// Calculate reflected spell result on caster
targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, m_canReflect);
targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, false); // can't reflect twice
if (targetInfo.reflectResult == SPELL_MISS_REFLECT) // Impossible reflect again, so simply deflect spell
targetInfo.reflectResult = SPELL_MISS_PARRY;
// Proc spell reflect aura when missile hits the original target
target->m_Events.AddEvent(new ProcReflectDelayed(target, m_originalCasterGUID), target->m_Events.CalculateTime(targetInfo.timeDelay));
// Increase time interval for reflected spells by 1.5
targetInfo.timeDelay += targetInfo.timeDelay >> 1;
@@ -2149,14 +2157,14 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask)
{
switch (m_spellInfo->Effects[effIndex].Effect)
{
case SPELL_EFFECT_GAMEOBJECT_DAMAGE:
case SPELL_EFFECT_GAMEOBJECT_REPAIR:
case SPELL_EFFECT_GAMEOBJECT_SET_DESTRUCTION_STATE:
if (go->GetGoType() != GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
effectMask &= ~(1 << effIndex);
break;
default:
break;
case SPELL_EFFECT_GAMEOBJECT_DAMAGE:
case SPELL_EFFECT_GAMEOBJECT_REPAIR:
case SPELL_EFFECT_GAMEOBJECT_SET_DESTRUCTION_STATE:
if (go->GetGoType() != GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
effectMask &= ~(1 << effIndex);
break;
default:
break;
}
}
}
@@ -2196,7 +2204,7 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask)
else
target.timeDelay = uint64(m_spellInfo->Speed * 1000.0f);
if (m_delayMoment == 0 || m_delayMoment > target.timeDelay)
if (!m_delayMoment || m_delayMoment > target.timeDelay)
m_delayMoment = target.timeDelay;
}
else
@@ -2304,13 +2312,13 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
// Fill base trigger info
uint32 procAttacker = m_procAttacker;
uint32 procVictim = m_procVictim;
uint32 procEx = m_procEx;
uint32 hitMask = m_hitMask;
m_spellAura = NULL; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied
m_spellAura = nullptr; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied
//Spells with this flag cannot trigger if effect is cast on self
bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2);
Unit* spellHitTarget = NULL;
// Spells with this flag cannot trigger if effect is cast on self
bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2);
Unit* spellHitTarget = nullptr;
if (missInfo == SPELL_MISS_NONE) // In case spell hit target, do all effect on that target
spellHitTarget = unit;
@@ -2338,23 +2346,15 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (missInfo2 != SPELL_MISS_MISS)
m_caster->SendSpellMiss(unit, m_spellInfo->Id, missInfo2);
m_damage = 0;
spellHitTarget = NULL;
spellHitTarget = nullptr;
}
}
// Do not take combo points on dodge and miss
if (missInfo != SPELL_MISS_NONE && m_needComboPoints &&
m_targets.GetUnitTargetGUID() == target->targetGUID)
{
if (missInfo != SPELL_MISS_NONE && m_needComboPoints && m_targets.GetUnitTargetGUID() == target->targetGUID)
m_needComboPoints = false;
// Restore spell mods for a miss/dodge/parry Cold Blood
/// @todo check how broad this rule should be
if (m_caster->GetTypeId() == TYPEID_PLAYER && (missInfo == SPELL_MISS_MISS ||
missInfo == SPELL_MISS_DODGE || missInfo == SPELL_MISS_PARRY))
m_caster->ToPlayer()->RestoreSpellMods(this, 14177);
}
// Trigger info was not filled in spell::preparedatafortriggersystem - we do it now
// Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now
if (canEffectTrigger && !procAttacker && !procVictim)
{
bool positive = true;
@@ -2401,19 +2401,20 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
uint32 addhealth = m_healing;
if (crit)
{
procEx |= PROC_EX_CRITICAL_HIT;
addhealth = caster->SpellCriticalHealingBonus(m_spellInfo, addhealth, NULL);
hitMask |= PROC_HIT_CRITICAL;
addhealth = caster->SpellCriticalHealingBonus(m_spellInfo, addhealth, nullptr);
}
else
procEx |= PROC_EX_NORMAL_HIT;
hitMask |= PROC_HIT_NORMAL;
int32 gain = caster->HealBySpell(unitTarget, m_spellInfo, addhealth, crit);
unitTarget->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, m_spellInfo);
m_healing = gain;
HealInfo healInfo(caster, unitTarget, addhealth, m_spellInfo, m_spellInfo->GetSchoolMask());
caster->HealBySpell(healInfo, crit);
unitTarget->getHostileRefManager().threatAssist(caster, float(healInfo.GetEffectiveHeal()) * 0.5f, m_spellInfo);
m_healing = healInfo.GetEffectiveHeal();
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
// Do triggers for unit
if (canEffectTrigger)
caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, nullptr, &healInfo);
}
// Do damage and triggers
else if (m_damage > 0)
@@ -2428,16 +2429,18 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
// Send log damage message to client
caster->SendSpellNonMeleeDamageLog(&damageInfo);
procEx |= createProcExtendMask(&damageInfo, missInfo);
hitMask |= createProcHitMask(&damageInfo, missInfo);
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
// Do triggers for unit
if (canEffectTrigger)
{
caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
if (caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) == 0 &&
(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx);
DamageInfo spellDamageInfo(damageInfo, SPELL_DIRECT_DAMAGE, m_attackType, hitMask);
caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, this, &spellDamageInfo, nullptr);
if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) &&
(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
caster->ToPlayer()->CastItemCombatSpell(spellDamageInfo);
}
m_damage = damageInfo.damage;
@@ -2449,10 +2452,17 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
{
// Fill base damage struct (unitTarget - is real spell target)
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask);
procEx |= createProcExtendMask(&damageInfo, missInfo);
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
caster->ProcDamageAndSpell(unit, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
hitMask |= createProcHitMask(&damageInfo, missInfo);
// Do triggers for unit
if (canEffectTrigger)
{
DamageInfo spellNoDamageInfo(damageInfo, NODAMAGE, m_attackType, hitMask);
caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_NO_DMG_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, &spellNoDamageInfo, nullptr);
if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) &&
(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
caster->ToPlayer()->CastItemCombatSpell(spellNoDamageInfo);
}
// Failed Pickpocket, reveal rogue
if (missInfo == SPELL_MISS_RESIST && m_spellInfo->HasAttribute(SPELL_ATTR0_CU_PICKPOCKET) && unitTarget->GetTypeId() == TYPEID_UNIT)
@@ -2819,7 +2829,7 @@ bool Spell::UpdateChanneledTargetList()
{
range = m_spellInfo->GetMaxRange(m_spellInfo->IsPositive());
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
modOwner->ApplySpellMod<SPELLMOD_RANGE>(m_spellInfo->Id, range, this);
}
for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
@@ -2961,7 +2971,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
}
// Prepare data for triggers
prepareDataForTriggerSystem(triggeredByAura);
prepareDataForTriggerSystem();
if (Player* player = m_caster->ToPlayer())
{
@@ -3073,10 +3083,6 @@ void Spell::cancel()
SendInterrupted(0);
SendCastResult(SPELL_FAILED_INTERRUPTED);
// spell is canceled-take mods and clear list
if (m_caster->GetTypeId() == TYPEID_PLAYER)
m_caster->ToPlayer()->RemoveSpellMods(this);
m_appliedMods.clear();
break;
@@ -3310,7 +3316,25 @@ void Spell::cast(bool skipCheck)
SetExecutedCurrently(false);
if (Creature* creatureCaster = m_caster->ToCreature())
creatureCaster->ReleaseFocus(this);
if (!m_originalCaster)
return;
// Handle procs on cast
uint32 procAttacker = m_procAttacker;
if (!procAttacker)
{
if (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC)
procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG;
else
procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG;
}
uint32 hitMask = m_hitMask;
if (!(hitMask & PROC_HIT_CRITICAL))
hitMask |= PROC_HIT_NORMAL;
m_originalCaster->ProcSkillsAndAuras(nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr);
}
void Spell::handle_immediate()
@@ -3324,7 +3348,7 @@ void Spell::handle_immediate()
// First mod_duration then haste - see Missile Barrage
// Apply duration mod
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
modOwner->ApplySpellMod<SPELLMOD_DURATION>(m_spellInfo->Id, duration);
// Apply haste mods
m_caster->ModSpellDurationTime(m_spellInfo, duration, this);
@@ -3467,22 +3491,8 @@ void Spell::_handle_immediate_phase()
}
// process items
for (std::list<ItemTargetInfo>::iterator ihit= m_UniqueItemInfo.begin(); ihit != m_UniqueItemInfo.end(); ++ihit)
for (std::list<ItemTargetInfo>::iterator ihit = m_UniqueItemInfo.begin(); ihit != m_UniqueItemInfo.end(); ++ihit)
DoAllEffectOnTarget(&(*ihit));
if (!m_originalCaster)
return;
// Handle procs on cast
/// @todo finish new proc system:P
if (m_UniqueTargetInfo.empty() && m_targets.HasDst())
{
uint32 procAttacker = m_procAttacker;
if (!procAttacker)
procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS;
// Proc the spells that have DEST target
m_originalCaster->ProcDamageAndSpell(NULL, procAttacker, 0, m_procEx | PROC_EX_NORMAL_HIT, 0, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell);
}
}
void Spell::_handle_finish_phase()
@@ -3509,7 +3519,24 @@ void Spell::_handle_finish_phase()
m_caster->m_extraAttacks = 0;
}
/// @todo trigger proc phase finish here
// Handle procs on finish
if (!m_originalCaster)
return;
uint32 procAttacker = m_procAttacker;
if (!procAttacker)
{
if (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC)
procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG;
else
procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG;
}
uint32 hitMask = m_hitMask;
if (!(hitMask & PROC_HIT_CRITICAL))
hitMask |= PROC_HIT_NORMAL;
m_originalCaster->ProcSkillsAndAuras(nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_FINISH, hitMask, this, nullptr, nullptr);
}
void Spell::SendSpellCooldown()
@@ -3675,18 +3702,6 @@ void Spell::finish(bool ok)
m_caster->ToPlayer()->UpdatePotionCooldown(this);
}
if (Player* modOwner = m_caster->GetSpellModOwner())
{
// triggered spell pointer can be not set in some cases
// this is needed for proper apply of triggered spell mods
modOwner->SetSpellModTakingSpell(this, true);
// Take mods after trigger spell (needed for 14177 to affect 48664)
// mods are taken only on succesfull cast and independantly from targets of the spell
modOwner->RemoveSpellMods(this);
modOwner->SetSpellModTakingSpell(this, false);
}
// Stop Attack for some spells
if (m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET))
m_caster->AttackStop();
@@ -4425,7 +4440,7 @@ void Spell::TakePower()
hit = false;
//lower spell cost on fail (by talent aura)
if (Player* modOwner = m_caster->ToPlayer()->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_SPELL_COST_REFUND_ON_FAIL, m_powerCost);
modOwner->ApplySpellMod<SPELLMOD_SPELL_COST_REFUND_ON_FAIL>(m_spellInfo->Id, m_powerCost);
}
break;
}
@@ -4514,7 +4529,7 @@ SpellCastResult Spell::CheckRuneCost(uint32 runeCostID)
{
runeCost[i] = src->RuneCost[i];
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this);
modOwner->ApplySpellMod<SPELLMOD_COST>(m_spellInfo->Id, runeCost[i], this);
}
runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later
@@ -4554,7 +4569,7 @@ void Spell::TakeRunePower(bool didHit)
{
runeCost[i] = runeCostData->RuneCost[i];
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this);
modOwner->ApplySpellMod<SPELLMOD_COST>(m_spellInfo->Id, runeCost[i], this);
}
// Let's say we use a skill that requires a Frost rune. This is the order:
@@ -6000,7 +6015,7 @@ SpellCastResult Spell::CheckRange(bool strict)
maxRange *= ranged->GetTemplate()->RangedModRange * 0.01f;
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, maxRange, this);
modOwner->ApplySpellMod<SPELLMOD_RANGE>(m_spellInfo->Id, maxRange, this);
maxRange += rangeMod;
@@ -6530,7 +6545,7 @@ void Spell::Delayed() // only called in DealDamage()
//check pushback reduce
int32 delaytime = 500; // spellcasting delay is normally 500ms
int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
m_caster->ToPlayer()->ApplySpellMod<SPELLMOD_NOT_LOSE_CASTING_TIME>(m_spellInfo->Id, delayReduce, this);
delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
if (delayReduce >= 100)
return;
@@ -6568,7 +6583,7 @@ void Spell::DelayedChannel()
int32 delaytime = CalculatePct(duration, 25); // channeling delay is normally 25% of its time per hit
int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
m_caster->ToPlayer()->ApplySpellMod<SPELLMOD_NOT_LOSE_CASTING_TIME>(m_spellInfo->Id, delayReduce, this);
delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
if (delayReduce >= 100)
return;
@@ -7491,8 +7506,8 @@ void Spell::TriggerGlobalCooldown()
if (m_spellInfo->StartRecoveryTime >= MIN_GCD && m_spellInfo->StartRecoveryTime <= MAX_GCD)
{
// gcd modifier auras are applied only to own spells and only players have such mods
if (m_caster->GetTypeId() == TYPEID_PLAYER)
m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_GLOBAL_COOLDOWN, gcd, this);
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_GLOBAL_COOLDOWN>(m_spellInfo->Id, gcd, this);
bool isMeleeOrRangedSpell = m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE ||
m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED ||