aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQAston <qaston@gmail.com>2011-07-10 13:13:02 +0200
committerQAston <qaston@gmail.com>2011-07-10 13:13:02 +0200
commit72ea9c9fa86fa88a5cbdd971d817c6903abf725a (patch)
treeda26b1a3acda8a57925293302435745e6fe0a46e
parent22135f4d91001f24cabea843c8f883558a6a2365 (diff)
Core/Spells: Add a base for brand new proc system, this is a WIP and doesn't affect currently working code.
-rwxr-xr-xsrc/server/game/Entities/Player/Player.cpp4
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp122
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h102
-rwxr-xr-xsrc/server/game/Spells/Auras/SpellAuraEffects.cpp200
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.h9
-rwxr-xr-xsrc/server/game/Spells/Auras/SpellAuras.cpp143
-rwxr-xr-xsrc/server/game/Spells/Auras/SpellAuras.h14
-rwxr-xr-xsrc/server/game/Spells/SpellMgr.cpp72
-rwxr-xr-xsrc/server/game/Spells/SpellMgr.h13
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp1
10 files changed, 621 insertions, 59 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 9eac54ee3f8..eea6159dbeb 100755
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -19631,7 +19631,7 @@ void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura)
SpellModifier *mod = *itr;
// spellmods without aura set cannot be charged
- if (!mod->ownerAura || !mod->ownerAura->GetCharges())
+ if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges())
continue;
// Restore only specific owner aura mods
@@ -19689,7 +19689,7 @@ void Player::RemoveSpellMods(Spell* spell)
++itr;
// spellmods without aura set cannot be charged
- if (!mod->ownerAura || !mod->ownerAura->GetCharges())
+ if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges())
continue;
// check if mod affected this spell
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index e3146a354b2..c8e50740bdc 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -92,6 +92,52 @@ static bool isAlwaysTriggeredAura[TOTAL_AURAS];
// Prepare lists
static bool procPrepared = InitTriggerAuraData();
+DamageInfo::DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellEntry const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType)
+: m_attacker(_attacker), m_victim(_victim), m_damage(_damage), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask),
+m_damageType(_damageType), m_attackType(BASE_ATTACK)
+{
+ m_absorb = 0;
+ m_resist = 0;
+ m_block = 0;
+}
+DamageInfo::DamageInfo(CalcDamageInfo& dmgInfo)
+: m_attacker(dmgInfo.attacker), m_victim(dmgInfo.target), m_damage(dmgInfo.damage), m_spellInfo(NULL), m_schoolMask(SpellSchoolMask(dmgInfo.damageSchoolMask)),
+m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.attackType)
+{
+ m_absorb = 0;
+ m_resist = 0;
+ m_block = 0;
+}
+void DamageInfo::ModifyDamage(int32 amount)
+{
+ amount = std::min(amount, int32(GetDamage()));
+ m_damage += amount;
+}
+void DamageInfo::AbsorbDamage(uint32 amount)
+{
+ amount = std::min(amount, GetDamage());
+ m_absorb += amount;
+ m_damage -= amount;
+}
+void DamageInfo::ResistDamage(uint32 amount)
+{
+ amount = std::min(amount, GetDamage());
+ m_resist += amount;
+ m_damage -= amount;
+}
+void DamageInfo::BlockDamage(uint32 amount)
+{
+ amount = std::min(amount, GetDamage());
+ m_block += amount;
+ m_damage -= amount;
+}
+
+ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
+:_actor(actor), _actionTarget(actionTarget), _procTarget(procTarget), _typeMask(typeMask), _spellTypeMask(spellTypeMask), _spellPhaseMask(spellPhaseMask),
+_hitMask(hitMask), _spell(spell), _damageInfo(damageInfo), _healInfo(healInfo)
+{
+}
+
// we can disable this warning for this since it only
// causes undefined behavior when passed to the base class constructor
#ifdef _MSC_VER
@@ -1931,7 +1977,9 @@ void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool ex
DealDamageMods(pVictim, damageInfo.damage, &damageInfo.absorb);
SendAttackStateUpdate(&damageInfo);
+ //TriggerAurasProcOnEvent(damageInfo);
ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType);
+
DealMeleeDamage(&damageInfo, true);
if (GetTypeId() == TYPEID_PLAYER)
@@ -14294,7 +14342,11 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* pTarget, uint32 procFlag,
if (i->aura->IsRemoved())
continue;
- bool useCharges = i->aura->GetCharges() > 0;
+ bool useCharges = i->aura->IsUsingCharges();
+ // no more charges to use, prevent proc
+ if (useCharges && !i->aura->GetCharges())
+ continue;
+
bool takeCharges = false;
SpellEntry const* spellInfo = i->aura->GetSpellProto();
uint32 Id = i->aura->GetId();
@@ -14495,6 +14547,70 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* pTarget, uint32 procFlag,
SetCantProc(false);
}
+void Unit::GetProcAurasTriggeredOnEvent(std::list<AuraApplication*>& aurasTriggeringProc, std::list<AuraApplication*>* procAuras, ProcEventInfo eventInfo)
+{
+ // use provided list of auras which can proc
+ if (procAuras)
+ {
+ for (std::list<AuraApplication*>::iterator itr = procAuras->begin(); itr!= procAuras->end(); ++itr)
+ {
+ ASSERT((*itr)->GetTarget() == this);
+ if (!(*itr)->GetRemoveMode())
+ if ((*itr)->GetBase()->IsProcTriggeredOnEvent(*itr, eventInfo))
+ {
+ (*itr)->GetBase()->PrepareProcToTrigger();
+ aurasTriggeringProc.push_back(*itr);
+ }
+ }
+ }
+ // or generate one on our own
+ else
+ {
+ for (AuraApplicationMap::iterator itr = GetAppliedAuras().begin(); itr!= GetAppliedAuras().end(); ++itr)
+ {
+ if (itr->second->GetBase()->IsProcTriggeredOnEvent(itr->second, eventInfo))
+ {
+ itr->second->GetBase()->PrepareProcToTrigger();
+ aurasTriggeringProc.push_back(itr->second);
+ }
+ }
+ }
+}
+
+void Unit::TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo)
+{
+ DamageInfo dmgInfo = DamageInfo(damageInfo);
+ TriggerAurasProcOnEvent(NULL, NULL, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, 0, 0, damageInfo.procEx, NULL, &dmgInfo, NULL);
+}
+
+void Unit::TriggerAurasProcOnEvent(std::list<AuraApplication*>* myProcAuras, std::list<AuraApplication*>* targetProcAuras, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
+{
+ // prepare data for self trigger
+ ProcEventInfo myProcEventInfo = ProcEventInfo(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
+ std::list<AuraApplication*> myAurasTriggeringProc;
+ GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, myProcAuras, myProcEventInfo);
+
+ // prepare data for target trigger
+ ProcEventInfo targetProcEventInfo = ProcEventInfo(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
+ std::list<AuraApplication*> targetAurasTriggeringProc;
+ if (typeMaskActionTarget)
+ GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, targetProcAuras, targetProcEventInfo);
+
+ TriggerAurasProcOnEvent(myProcEventInfo, myAurasTriggeringProc);
+
+ if (typeMaskActionTarget)
+ TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc);
+}
+
+void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, std::list<AuraApplication*>& aurasTriggeringProc)
+{
+ for (std::list<AuraApplication*>::iterator itr = aurasTriggeringProc.begin(); itr != aurasTriggeringProc.end(); ++itr)
+ {
+ if (!(*itr)->GetRemoveMode())
+ (*itr)->GetBase()->TriggerProcOnEvent(*itr, eventInfo);
+ }
+}
+
SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const
{
return SPELL_SCHOOL_MASK_NORMAL;
@@ -15059,6 +15175,10 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura * aura, SpellEntry co
{
SpellEntry const* spellProto = aura->GetSpellProto();
+ // let the aura be handled by new proc system if it has new entry
+ if (sSpellMgr->GetSpellProcEntry(spellProto->Id))
+ return false;
+
// Get proc Event Entry
spellProcEvent = sSpellMgr->GetSpellProcEvent(spellProto->Id);
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index e119438583c..6f5ca9c3aa3 100755
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -801,6 +801,8 @@ struct CleanDamage
MeleeHitOutcome hitOutCome;
};
+struct CalcDamageInfo;
+
class DamageInfo
{
private:
@@ -810,51 +812,84 @@ private:
SpellEntry const* const m_spellInfo;
SpellSchoolMask const m_schoolMask;
DamageEffectType const m_damageType;
+ WeaponAttackType m_attackType;
uint32 m_absorb;
uint32 m_resist;
uint32 m_block;
public:
- explicit DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellEntry const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType)
- : m_attacker(_attacker), m_victim(_victim), m_damage(_damage), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask), m_damageType(_damageType)
- {
- m_absorb = 0;
- m_resist = 0;
- m_block = 0;
- }
- void ModifyDamage(int32 amount)
- {
- amount = std::min(amount, int32(GetDamage()));
- m_damage += amount;
- }
- void AbsorbDamage(uint32 amount)
- {
- amount = std::min(amount, GetDamage());
- m_absorb += amount;
- m_damage -= amount;
- }
- void ResistDamage(uint32 amount)
- {
- amount = std::min(amount, GetDamage());
- m_resist += amount;
- m_damage -= amount;
- }
- void BlockDamage(uint32 amount)
- {
- amount = std::min(amount, GetDamage());
- m_block += amount;
- m_damage -= amount;
- }
+ explicit DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellEntry const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType);
+ explicit DamageInfo(CalcDamageInfo& dmgInfo);
+
+ void ModifyDamage(int32 amount);
+ void AbsorbDamage(uint32 amount);
+ void ResistDamage(uint32 amount);
+ void BlockDamage(uint32 amount);
+
Unit* GetAttacker() const { return m_attacker; };
Unit* GetVictim() const { return m_victim; };
- DamageEffectType GetDamageType() const { return m_damageType; };
SpellEntry const* GetSpellInfo() const { return m_spellInfo; };
SpellSchoolMask GetSchoolMask() const { return m_schoolMask; };
+ DamageEffectType GetDamageType() const { return m_damageType; };
+ WeaponAttackType GetAttackType() const { return m_attackType; };
uint32 GetDamage() const { return m_damage; };
uint32 GetAbsorb() const { return m_absorb; };
uint32 GetResist() const { return m_resist; };
uint32 GetBlock() const { return m_block; };
};
+class HealInfo
+{
+private:
+ Unit* const m_healer;
+ Unit* const m_target;
+ uint32 m_heal;
+ uint32 m_absorb;
+ SpellEntry const* const m_spellInfo;
+ SpellSchoolMask const m_schoolMask;
+public:
+ explicit HealInfo(Unit* _healer, Unit* _target, uint32 _heal, SpellEntry const* _spellInfo, SpellSchoolMask _schoolMask)
+ : m_healer(_healer), m_target(_target), m_heal(_heal), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask)
+ {
+ m_absorb = 0;
+ }
+ void AbsorbHeal(uint32 amount)
+ {
+ amount = std::min(amount, GetHeal());
+ m_absorb += amount;
+ m_heal -= amount;
+ }
+
+ uint32 GetHeal() const { return m_heal; };
+};
+
+class ProcEventInfo
+{
+private:
+ Unit* const _actor;
+ Unit* const _actionTarget;
+ Unit* const _procTarget;
+ uint32 _typeMask;
+ uint32 _spellTypeMask;
+ uint32 _spellPhaseMask;
+ uint32 _hitMask;
+ Spell* _spell;
+ DamageInfo* _damageInfo;
+ HealInfo* _healInfo;
+public:
+ explicit ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo);
+ Unit* GetActor() { return _actor; };
+ Unit* GetActionTarget() const { return _actionTarget; }
+ Unit* GetProcTarget() const { return _procTarget; }
+ uint32 GetTypeMask() const { return _typeMask; }
+ uint32 GetSpellTypeMask() const { return _spellTypeMask; }
+ uint32 GetSpellPhaseMask() const { return _spellPhaseMask; }
+ uint32 GetHitMask() const { return _hitMask; }
+ SpellEntry const* GetSpellInfo() const { return NULL; }
+ SpellSchoolMask GetSchoolMask() const { return SPELL_SCHOOL_MASK_NONE; }
+ DamageInfo* GetDamageInfo() const { return _damageInfo; }
+ HealInfo* GetHealInfo() const { return _healInfo; }
+};
+
// Struct for use in Unit::CalculateMeleeDamage
// Need create structure like in SMSG_ATTACKERSTATEUPDATE opcode
struct CalcDamageInfo
@@ -1362,6 +1397,11 @@ class Unit : public WorldObject
void ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellEntry const *procSpell = NULL, SpellEntry const* procAura = NULL);
void ProcDamageAndSpellFor(bool isVictim, Unit* pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const* procSpell, uint32 damage , SpellEntry const* procAura = NULL);
+ void GetProcAurasTriggeredOnEvent(std::list<AuraApplication*>& aurasTriggeringProc, std::list<AuraApplication*>* procAuras, ProcEventInfo eventInfo);
+ void TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo);
+ void TriggerAurasProcOnEvent(std::list<AuraApplication*>* myProcAuras, std::list<AuraApplication*>* targetProcAuras, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo);
+ void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, std::list<AuraApplication*>& procAuras);
+
void HandleEmoteCommand(uint32 anim_id);
void AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType = BASE_ATTACK, bool extra = false);
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index e2cdad9f266..cb89a04bca6 100755
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -1039,7 +1039,7 @@ void AuraEffect::ApplySpellMod(Unit* target, bool apply)
target->ToPlayer()->AddSpellMod(m_spellmod, apply);
// Auras with charges do not mod amount of passive auras
- if (GetBase()->GetCharges())
+ if (GetBase()->IsUsingCharges())
return;
// reapply some passive spells after add/remove related spellmods
// Warning: it is a dead loop if 2 auras each other amount-shouldn't happen
@@ -1263,6 +1263,20 @@ bool AuraEffect::IsPeriodicTickCrit(Unit* target, Unit const* caster) const
return false;
}
+bool AuraEffect::IsAffectedOnSpell(SpellEntry const* spell) const
+{
+ if (!spell)
+ return false;
+ // Check family name
+ if (spell->SpellFamilyName != m_spellProto->SpellFamilyName)
+ return false;
+
+ // Check EffectClassMask
+ if (m_spellProto->EffectSpellClassMask[m_effIndex] & spell->SpellFamilyFlags)
+ return true;
+ return false;
+}
+
void AuraEffect::SendTickImmune(Unit* target, Unit *caster) const
{
if (caster)
@@ -1324,18 +1338,29 @@ void AuraEffect::PeriodicTick(AuraApplication * aurApp, Unit* caster) const
}
}
-bool AuraEffect::IsAffectedOnSpell(SpellEntry const* spell) const
+void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
- if (!spell)
- return false;
- // Check family name
- if (spell->SpellFamilyName != m_spellProto->SpellFamilyName)
- return false;
-
- // Check EffectClassMask
- if (m_spellProto->EffectSpellClassMask[m_effIndex] & spell->SpellFamilyFlags)
- return true;
- return false;
+ // TODO: effect script handlers here
+ switch(GetAuraType())
+ {
+ case SPELL_AURA_PROC_TRIGGER_SPELL:
+ HandleProcTriggerSpellAuraProc(aurApp, eventInfo);
+ break;
+ case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE:
+ HandleProcTriggerSpellWithValueAuraProc(aurApp, eventInfo);
+ break;
+ case SPELL_AURA_PROC_TRIGGER_DAMAGE:
+ HandleProcTriggerDamageAuraProc(aurApp, eventInfo);
+ break;
+ case SPELL_AURA_RAID_PROC_FROM_CHARGE:
+ HandleRaidProcFromChargeAuraProc(aurApp, eventInfo);
+ break;
+ case SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE:
+ HandleRaidProcFromChargeWithValueAuraProc(aurApp, eventInfo);
+ break;
+ default:
+ break;
+ }
}
void AuraEffect::CleanupTriggeredSpells(Unit* target)
@@ -5885,13 +5910,13 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster)
return;
}
// Remote Toy
- case 37027: triggerSpellId = 37029; break;
+ case 37027:
+ triggerSpellId = 37029;
+ break;
// Eye of Grillok
case 38495:
- {
- target->CastSpell(target, 38530, true, NULL, this);
- return;
- }
+ triggerSpellId = 38530;
+ break;
// Absorb Eye of Grillok (Zezzak's Shard)
case 38554:
{
@@ -6634,3 +6659,144 @@ void AuraEffect::HandlePeriodicPowerBurnManaAuraTick(Unit* target, Unit* caster)
caster->DealSpellDamage(&damageInfo, true);
}
+
+void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
+{
+ Unit* triggerCaster = aurApp->GetTarget();
+ Unit* triggerTarget = eventInfo.GetProcTarget();
+
+ uint32 triggerSpellId = GetSpellProto()->EffectTriggerSpell[GetEffIndex()];
+ if (SpellEntry const* triggeredSpellInfo = sSpellStore.LookupEntry(triggerSpellId))
+ {
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "AuraEffect::HandleProcTriggerSpellAuraProc: Triggering spell %u from aura %u proc", triggeredSpellInfo->Id, GetId());
+ triggerCaster->CastSpell(triggerTarget, triggeredSpellInfo, true, NULL, this);
+ }
+ else
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS,"AuraEffect::HandleProcTriggerSpellAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
+}
+
+void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
+{
+ Unit* triggerCaster = aurApp->GetTarget();
+ Unit* triggerTarget = eventInfo.GetProcTarget();
+
+ uint32 triggerSpellId = GetSpellProto()->EffectTriggerSpell[m_effIndex];
+ if (SpellEntry const *triggeredSpellInfo = sSpellStore.LookupEntry(triggerSpellId))
+ {
+ int32 basepoints0 = GetAmount();
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Triggering spell %u with value %d from aura %u proc", triggeredSpellInfo->Id, basepoints0, GetId());
+ triggerCaster->CastCustomSpell(triggerTarget, triggerSpellId, &basepoints0, NULL, NULL, true, NULL, this);
+ }
+ else
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS,"AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
+}
+
+void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
+{
+ Unit* target = aurApp->GetTarget();
+ Unit* triggerTarget = eventInfo.GetProcTarget();
+ SpellNonMeleeDamage damageInfo(target, triggerTarget, GetId(), GetSpellProto()->SchoolMask);
+ uint32 damage = target->SpellDamageBonus(triggerTarget, GetSpellProto(), GetAmount(), SPELL_DIRECT_DAMAGE);
+ target->CalculateSpellDamageTaken(&damageInfo, damage, GetSpellProto());
+ target->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
+ target->SendSpellNonMeleeDamageLog(&damageInfo);
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "AuraEffect::HandleProcTriggerDamageAuraProc: Triggering %u spell damage from aura %u proc", damage, GetId());
+ target->DealSpellDamage(&damageInfo, true);
+}
+
+void AuraEffect::HandleRaidProcFromChargeAuraProc(AuraApplication* aurApp, ProcEventInfo& /*eventInfo*/)
+{
+ Unit* target = aurApp->GetTarget();
+
+ uint32 triggerSpellId;
+ switch (GetId())
+ {
+ case 57949: // Shiver
+ triggerSpellId = 57952;
+ //animationSpellId = 57951; dummy effects for jump spell have unknown use (see also 41637)
+ break;
+ case 59978: // Shiver
+ triggerSpellId = 59979;
+ break;
+ case 43593: // Cold Stare
+ triggerSpellId = 43594;
+ break;
+ default:
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "AuraEffect::HandleRaidProcFromChargeAuraProc: received not handled spell: %u", GetId());
+ return;
+ }
+
+ int32 jumps = GetBase()->GetCharges();
+
+ // current aura expire on proc finish
+ GetBase()->SetCharges(0);
+ GetBase()->SetUsingCharges(true);
+
+ // next target selection
+ if (jumps > 0)
+ {
+ Unit* caster = GetCaster();
+ float radius = (float)GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(GetSpellProto()->EffectRadiusIndex[GetEffIndex()]));
+
+ if (caster)
+ {
+ if (Player* modOwner = caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(GetId(), SPELLMOD_RADIUS, radius, NULL);
+
+ if (Unit* triggerTarget = target->GetNextRandomRaidMemberOrPet(radius))
+ {
+ target->CastSpell(triggerTarget, GetSpellProto(), true, NULL, this, GetCasterGUID());
+ if (Aura* aura = triggerTarget->GetAura(GetId(), GetCasterGUID()))
+ aura->SetCharges(jumps);
+ }
+ }
+ }
+
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "AuraEffect::HandleRaidProcFromChargeAuraProc: Triggering spell %u from aura %u proc", triggerSpellId, GetId());
+ target->CastSpell(target, triggerSpellId, true, NULL, this, GetCasterGUID());
+}
+
+
+void AuraEffect::HandleRaidProcFromChargeWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& /*eventInfo*/)
+{
+ Unit* target = aurApp->GetTarget();
+
+ // Currently only Prayer of Mending
+ if (!(GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST && GetSpellProto()->SpellFamilyFlags[1] & 0x20))
+ {
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "AuraEffect::HandleRaidProcFromChargeWithValueAuraProc: received not handled spell: %u", GetId());
+ return;
+ }
+ uint32 triggerSpellId = 33110;
+
+ int32 value = GetAmount();
+
+ int32 jumps = GetBase()->GetCharges();
+
+ // current aura expire on proc finish
+ GetBase()->SetCharges(0);
+ GetBase()->SetUsingCharges(true);
+
+ // next target selection
+ if (jumps > 0)
+ {
+ Unit* caster = GetCaster();
+ float radius = (float)GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(GetSpellProto()->EffectRadiusIndex[GetEffIndex()]));
+
+ if (caster)
+ {
+ if (Player* modOwner = caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(GetId(), SPELLMOD_RADIUS, radius, NULL);
+
+ if (Unit* triggerTarget = target->GetNextRandomRaidMemberOrPet(radius))
+ {
+ target->CastCustomSpell(triggerTarget, GetId(), &value, NULL, NULL, true, NULL, this, GetCasterGUID());
+ if (Aura* aura = triggerTarget->GetAura(GetId(), GetCasterGUID()))
+ aura->SetCharges(jumps);
+ }
+ }
+ }
+
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "AuraEffect::HandleRaidProcFromChargeWithValueAuraProc: Triggering spell %u from aura %u proc", triggerSpellId, GetId());
+ target->CastCustomSpell(target, triggerSpellId, &value, NULL, NULL, true, NULL, this, GetCasterGUID());
+}
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h
index 8aaef85c394..dea2e980c12 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.h
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.h
@@ -84,6 +84,8 @@ class AuraEffect
void SendTickImmune(Unit* target, Unit *caster) const;
void PeriodicTick(AuraApplication * aurApp, Unit* caster) const;
+ void HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
+
void CleanupTriggeredSpells(Unit* target);
// add/remove SPELL_AURA_MOD_SHAPESHIFT (36) linked auras
@@ -288,6 +290,13 @@ class AuraEffect
void HandleObsModPowerAuraTick(Unit* target, Unit* caster) const;
void HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) const;
void HandlePeriodicPowerBurnManaAuraTick(Unit* target, Unit* caster) const;
+
+ // aura effect proc handlers
+ void HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
+ void HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
+ void HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
+ void HandleRaidProcFromChargeAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
+ void HandleRaidProcFromChargeWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
};
namespace Trinity
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 0f21cee9868..0c457697805 100755
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -193,7 +193,8 @@ void AuraApplication::BuildUpdatePacket(ByteBuffer& data, bool remove) const
flags |= AFLAG_DURATION;
data << uint8(flags);
data << uint8(aura->GetCasterLevel());
- data << uint8(aura->GetStackAmount() > 1 ? aura->GetStackAmount() : (aura->GetCharges()) ? aura->GetCharges() : 1);
+ // stack amount has priority over charges (checked on retail with spell 50262)
+ data << uint8(aura->GetStackAmount() > 1 ? aura->GetStackAmount() : (aura->IsUsingCharges()) ? aura->GetCharges() : 0);
if (!(flags & AFLAG_CASTER))
data.appendPackGUID(aura->GetCasterGUID());
@@ -332,7 +333,7 @@ m_spellProto(spellproto), m_casterGuid(casterGUID ? casterGUID : caster->GetGUID
m_castItemGuid(castItem ? castItem->GetGUID() : 0), m_applyTime(time(NULL)),
m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0),
m_casterLevel(caster ? caster->getLevel() : m_spellProto->spellLevel), m_procCharges(0), m_stackAmount(1),
-m_isRemoved(false), m_isSingleTarget(false)
+m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false)
{
if (m_spellProto->manaPerSecond || m_spellProto->manaPerSecondPerLevel)
m_timeCla = 1 * IN_MILLISECONDS;
@@ -340,6 +341,8 @@ m_isRemoved(false), m_isSingleTarget(false)
m_maxDuration = CalcMaxDuration(caster);
m_duration = m_maxDuration;
m_procCharges = CalcMaxCharges(caster);
+ m_isUsingCharges = m_procCharges != 0;
+ // m_casterLevel = cast item level/caster level, caster level should be saved to db, confirmed with sniffs
}
void Aura::_InitEffects(uint8 effMask, Unit* caster, int32 *baseAmount)
@@ -741,12 +744,15 @@ void Aura::SetCharges(uint8 charges)
if (m_procCharges == charges)
return;
m_procCharges = charges;
+ m_isUsingCharges = m_procCharges != 0;
SetNeedClientUpdateForTargets();
}
uint8 Aura::CalcMaxCharges(Unit* caster) const
{
uint8 maxProcCharges = m_spellProto->procCharges;
+ if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId()))
+ maxProcCharges = procEntry->charges;
if (caster)
if (Player* modOwner = caster->GetSpellModOwner())
@@ -756,7 +762,7 @@ uint8 Aura::CalcMaxCharges(Unit* caster) const
bool Aura::ModCharges(int32 num, AuraRemoveMode removeMode)
{
- if (m_procCharges)
+ if (IsUsingCharges())
{
int32 charges = m_procCharges + num;
int32 maxCharges = CalcMaxCharges();
@@ -881,6 +887,10 @@ bool Aura::CanBeSaved() const
if (GetId() == 44413)
return false;
+ // don't save auras removed by proc system
+ if (IsUsingCharges() && !GetCharges())
+ return false;
+
return true;
}
@@ -906,6 +916,7 @@ void Aura::SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint
m_maxDuration = maxduration;
m_duration = duration;
m_procCharges = charges;
+ m_isUsingCharges = m_procCharges != 0;
m_stackAmount = stackamount;
Unit* caster = GetCaster();
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
@@ -1734,6 +1745,132 @@ bool Aura::CheckAreaTarget(Unit* target)
return CallScriptCheckAreaTargetHandlers(target);
}
+bool Aura::IsProcOnCooldown() const
+{
+ /*if (m_procCooldown)
+ {
+ if (m_procCooldown > time(NULL))
+ return true;
+ }*/
+ return false;
+}
+
+void Aura::AddProcCooldown(uint32 msec)
+{
+ //m_procCooldown = time(NULL) + msec;
+}
+
+void Aura::PrepareProcToTrigger()
+{
+ // TODO: allow scripts to prevent charge drop/cooldown
+ // take one charge, aura expiration will be handled in Aura::TriggerProcOnEvent (if needed)
+ if (IsUsingCharges())
+ {
+ --m_procCharges;
+ SetNeedClientUpdateForTargets();
+ }
+
+ SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId());
+
+ ASSERT(procEntry);
+
+ // cooldowns should be added to the whole aura (see 51698 area aura)
+ AddProcCooldown(procEntry->cooldown);
+}
+
+bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const
+{
+ SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId());
+ // only auras with spell proc entry can trigger proc
+ if (!procEntry)
+ return false;
+
+ // check if we have charges to proc with
+ if (IsUsingCharges() && !GetCharges())
+ return false;
+
+ // check proc cooldown
+ if (IsProcOnCooldown())
+ return false;
+
+ // TODO:
+ // something about triggered spells triggering, and add extra attack effect
+
+ // do checks against db data
+ if (!sSpellMgr->CanSpellTriggerProcOnEvent(*procEntry, eventInfo))
+ return false;
+
+ // Check if current equipment meets aura requirements
+ // do that only for passive spells
+ // TODO: this needs to be unified for all kinds of auras
+ Unit* target = aurApp->GetTarget();
+ if (IsPassive() && target->GetTypeId() == TYPEID_PLAYER)
+ {
+ if (GetSpellProto()->EquippedItemClass == ITEM_CLASS_WEAPON)
+ {
+ if (target->ToPlayer()->IsInFeralForm())
+ return false;
+
+ if (eventInfo.GetDamageInfo())
+ {
+ WeaponAttackType attType = eventInfo.GetDamageInfo()->GetAttackType();
+ Item *item = NULL;
+ if (attType == BASE_ATTACK)
+ item = target->ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
+ else if (attType == OFF_ATTACK)
+ item = target->ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
+ else
+ item = target->ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
+
+ if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_WEAPON || !((1<<item->GetTemplate()->SubClass) & GetSpellProto()->EquippedItemSubClassMask))
+ return false;
+ }
+ }
+ else if (GetSpellProto()->EquippedItemClass == ITEM_CLASS_ARMOR)
+ {
+ // Check if player is wearing shield
+ Item *item = target->ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
+ if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_ARMOR || !((1<<item->GetTemplate()->SubClass) & GetSpellProto()->EquippedItemSubClassMask))
+ return false;
+ }
+ }
+
+ return roll_chance_f(CalcProcChance(*procEntry, eventInfo));
+}
+
+float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const
+{
+ float chance = procEntry.chance;
+ // calculate chances depending on unit with caster's data
+ // so talents modifying chances and judgements will have properly calculated proc chance
+ if (Unit * caster = GetCaster())
+ {
+ // calculate ppm chance if present and we're using weapon
+ if (eventInfo.GetDamageInfo() && procEntry.ratePerMinute != 0)
+ {
+ uint32 WeaponSpeed = caster->GetAttackTime(eventInfo.GetDamageInfo()->GetAttackType());
+ chance = caster->GetPPMProcChance(WeaponSpeed, procEntry.ratePerMinute, GetSpellProto());
+ }
+ // apply chance modifer aura, applies also to ppm chance (see improved judgement of light spell)
+ if (Player* modOwner = caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(GetId(), SPELLMOD_CHANCE_OF_SUCCESS, chance);
+ }
+ return chance;
+}
+
+void Aura::TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo)
+{
+ // TODO: script hooks here (allowing prevention of selected effects)
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (aurApp->HasEffect(i))
+ GetEffect(i)->HandleProc(aurApp, eventInfo);
+ // TODO: script hooks here
+
+ // Remove aura if we've used last charge to proc
+ if (IsUsingCharges() && !GetCharges())
+ Remove();
+}
+
void Aura::_DeleteRemovedApplications()
{
while (!m_removedApplications.empty())
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index c51ae74b958..6ba2f7fe749 100755
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -25,12 +25,14 @@ class Unit;
struct SpellEntry;
struct SpellModifier;
struct ProcTriggerSpell;
+struct SpellProcEntry;
// forward decl
class AuraEffect;
class Aura;
class DynamicObject;
class AuraScript;
+class ProcInfo;
// update aura target map every 500 ms instead of every update - reduce amount of grid searcher calls
#define UPDATE_TARGET_MAP_INTERVAL 500
@@ -179,6 +181,17 @@ class Aura
bool CanBeAppliedOn(Unit* target);
bool CheckAreaTarget(Unit* target);
+ // Proc system
+ bool IsProcOnCooldown() const;
+ void AddProcCooldown(uint32 msec);
+ bool IsUsingCharges() const { return m_isUsingCharges; }
+ void SetUsingCharges(bool val) { m_isUsingCharges = val; }
+ void PrepareProcToTrigger();
+ bool IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const;
+ float CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const;
+ void TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo);
+
+
// AuraScript
void LoadScripts();
bool CallScriptCheckAreaTargetHandlers(Unit* target);
@@ -219,6 +232,7 @@ class Aura
bool m_isRemoved:1;
bool m_isSingleTarget:1; // true if it's a single target spell and registered at caster - can change at spell steal for example
+ bool m_isUsingCharges:1;
private:
Unit::AuraApplicationList m_removedApplications;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index e1bd2450641..f615c48c16b 100755
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -1528,7 +1528,8 @@ void SpellMgr::LoadSpellProcs()
baseProcEntry.attributesMask = fields[10].GetUInt32();
baseProcEntry.ratePerMinute = fields[11].GetFloat();
baseProcEntry.chance = fields[12].GetFloat();
- baseProcEntry.cooldown = fields[13].GetFloat();
+ float cooldown = fields[13].GetFloat();
+ baseProcEntry.cooldown = uint32(cooldown);
baseProcEntry.charges = fields[14].GetUInt32();
while(true)
@@ -1563,7 +1564,7 @@ void SpellMgr::LoadSpellProcs()
sLog->outErrorDb("`spell_proc` table entry for spellId %u has negative value in `ratePerMinute` field", spellId);
procEntry.ratePerMinute = 0;
}
- if (procEntry.cooldown < 0)
+ if (cooldown < 0)
{
sLog->outErrorDb("`spell_proc` table entry for spellId %u has negative value in `cooldown` field", spellId);
procEntry.cooldown = 0;
@@ -1579,7 +1580,7 @@ void SpellMgr::LoadSpellProcs()
sLog->outErrorDb("`spell_proc` table entry for spellId %u doesn't have `typeMask` value defined, proc will not be triggered", spellId);
if (procEntry.spellTypeMask & ~PROC_SPELL_PHASE_MASK_ALL)
sLog->outErrorDb("`spell_proc` table entry for spellId %u has wrong `spellTypeMask` set: %u", spellId, procEntry.spellTypeMask);
- if (procEntry.spellTypeMask && !(procEntry.typeMask & SPELL_PROC_FLAG_MASK))
+ if (procEntry.spellTypeMask && !(procEntry.typeMask & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
sLog->outErrorDb("`spell_proc` table entry for spellId %u has `spellTypeMask` value defined, but it won't be used for defined `typeMask` value", spellId);
if (!procEntry.spellPhaseMask && procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK)
sLog->outErrorDb("`spell_proc` table entry for spellId %u doesn't have `spellPhaseMask` value defined, but it's required for defined `typeMask` value, proc will not be triggered", spellId);
@@ -1609,6 +1610,71 @@ void SpellMgr::LoadSpellProcs()
sLog->outString();
}
+bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo)
+{
+ // proc type doesn't match
+ if (!(eventInfo.GetTypeMask() & procEntry.typeMask))
+ return false;
+
+ // check XP or honor target requirement
+ if (procEntry.attributesMask & PROC_ATTR_REQ_EXP_OR_HONOR)
+ if (Player* actor = eventInfo.GetActor()->ToPlayer())
+ if (eventInfo.GetActionTarget() && !actor->isHonorOrXPTarget(eventInfo.GetActionTarget()))
+ return false;
+
+ // always trigger for these types
+ if (eventInfo.GetTypeMask() & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH))
+ return true;
+
+ // check school mask (if set) for other trigger types
+ if (procEntry.schoolMask && !(eventInfo.GetSchoolMask() & procEntry.schoolMask))
+ return false;
+
+ // check spell family name/flags (if set) for spells
+ if (eventInfo.GetTypeMask() & (PERIODIC_PROC_FLAG_MASK | SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION))
+ {
+ if (procEntry.spellFamilyName && (procEntry.spellFamilyName != eventInfo.GetSpellInfo()->SpellFamilyName))
+ return false;
+
+ if (procEntry.spellFamilyMask && !(procEntry.spellFamilyMask & eventInfo.GetSpellInfo()->SpellFamilyFlags))
+ return false;
+ }
+
+ // check spell type mask (if set)
+ if (eventInfo.GetTypeMask() & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK))
+ {
+ if (procEntry.spellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.spellTypeMask))
+ return false;
+ }
+
+ // check spell phase mask
+ if (eventInfo.GetTypeMask() & REQ_SPELL_PHASE_PROC_FLAG_MASK)
+ {
+ if (!(eventInfo.GetSpellPhaseMask() & procEntry.spellPhaseMask))
+ return false;
+ }
+
+ // check hit mask (on taken hit or on done hit, but not on spell cast phase)
+ if ((eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK) || ((eventInfo.GetTypeMask() & DONE_HIT_PROC_FLAG_MASK) && !(eventInfo.GetSpellPhaseMask() & PROC_SPELL_PHASE_CAST)))
+ {
+ uint32 hitMask = procEntry.hitMask;
+ // get default values if hit mask not set
+ if (!hitMask)
+ {
+ // for taken procs allow normal + critical hits by default
+ if (eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK)
+ hitMask |= PROC_HIT_NORMAL | PROC_HIT_CRITICAL;
+ // for done procs allow normal + critical + absorbs by default
+ else
+ hitMask |= PROC_HIT_NORMAL | PROC_HIT_CRITICAL | PROC_HIT_ABSORB;
+ }
+ if (!(eventInfo.GetHitMask() & hitMask))
+ return false;
+ }
+
+ return true;
+}
+
void SpellMgr::LoadSpellBonusess()
{
uint32 oldMSTime = getMSTime();
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index 56ae5259dbf..a18592232cb 100755
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -777,7 +777,7 @@ struct SpellProcEntry
uint32 attributesMask; // bitmask, see ProcAttributes
float ratePerMinute; // if nonzero - chance to proc is equal to value * aura caster's weapon speed / 60
float chance; // if nonzero - owerwrite procChance field for given Spell.dbc entry, defines chance of proc to occur, not used if perMinuteRate set
- float cooldown; // if nonzero - cooldown in secs for aura proc, applied to aura
+ uint32 cooldown; // if nonzero - cooldown in secs for aura proc, applied to aura
uint32 charges; // if nonzero - owerwrite procCharges field for given Spell.dbc entry, defines how many times proc can occur before aura remove, 0 - infinite
};
@@ -1156,6 +1156,17 @@ class SpellMgr
return itr->second;
}
+ // spell proc table
+ SpellProcEntry const* GetSpellProcEntry(uint32 spellId) const
+ {
+ SpellProcMap::const_iterator itr = mSpellProcMap.find(spellId);
+ if (itr != mSpellProcMap.end())
+ return &itr->second;
+ return NULL;
+ }
+
+ bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo);
+
// Spell proc events
SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const
{
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
index 3183f87c5a5..c3b6b3b5770 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
@@ -605,7 +605,6 @@ public:
DoCast(me, SPELL_BODY_REGEN, true);
DoCast(Head, SPELL_FLYING_HEAD, true);
DoCast(me, SPELL_CONFUSE, false); //test
- done_by->ProcDamageAndSpell(me, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0);
whirlwind = urand(4000, 8000);
regen = 0;
}