Core/Spells: Add a base for brand new proc system, this is a WIP and doesn't affect currently working code.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user