mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-21 12:47:07 +00:00
refactor(Core/Spells): Implement QAston Proc System (#11079)
* . * sql * . * . * 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * Update spell_item.cpp * Update Unit.cpp * 16 * 17 * 18 * 19 * 20 * 21 * Update Unit.cpp * REVERT UltraNIX Commit * 22 * 23 * . * . * . * warrior * warlock * shaman rogue priest paladin mage * spell item * hunter * druid * dk * war * error style * Update rev_1647677899565690722.sql * Update rev_1647677899565690722.sql * Update rev_1647677899565690722.sql * . * DOND DEL ME WAD DO DO * error 2 * . * . * . * FIX * Update SpellInfoCorrections.cpp * Update SpellInfoCorrections.cpp * . * ja genau * Update .gitignore * . * . * ., * . * . * . * . * Update Unit.cpp
This commit is contained in:
committed by
GitHub
parent
5189b43a28
commit
cbd3fd0967
@@ -103,8 +103,8 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS] =
|
||||
&AuraEffect::HandleAuraModSchoolImmunity, // 39 SPELL_AURA_SCHOOL_IMMUNITY
|
||||
&AuraEffect::HandleAuraModDmgImmunity, // 40 SPELL_AURA_DAMAGE_IMMUNITY
|
||||
&AuraEffect::HandleAuraModDispelImmunity, // 41 SPELL_AURA_DISPEL_IMMUNITY
|
||||
&AuraEffect::HandleNoImmediateEffect, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in Unit::ProcDamageAndSpellFor and Unit::HandleProcTriggerSpell
|
||||
&AuraEffect::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in Unit::ProcDamageAndSpellFor
|
||||
&AuraEffect::HandleNoImmediateEffect, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in AuraEffect::HandleProc
|
||||
&AuraEffect::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in AuraEffect::HandleProc
|
||||
&AuraEffect::HandleAuraTrackCreatures, // 44 SPELL_AURA_TRACK_CREATURES
|
||||
&AuraEffect::HandleAuraTrackResources, // 45 SPELL_AURA_TRACK_RESOURCES
|
||||
&AuraEffect::HandleNULL, // 46 SPELL_AURA_46 (used in test spells 54054 and 54058, and spell 48050) (3.0.8a)
|
||||
@@ -323,7 +323,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS] =
|
||||
&AuraEffect::HandleNoImmediateEffect, //259 SPELL_AURA_MOD_HOT_PCT implemented in Unit::SpellHealingBonus
|
||||
&AuraEffect::HandleNoImmediateEffect, //260 SPELL_AURA_SCREEN_EFFECT (miscvalue = id in ScreenEffect.dbc) not required any code
|
||||
&AuraEffect::HandlePhase, //261 SPELL_AURA_PHASE
|
||||
&AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in spell::cancast
|
||||
&AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in Spell::CheckCast
|
||||
&AuraEffect::HandleAuraAllowOnlyAbility, //263 SPELL_AURA_ALLOW_ONLY_ABILITY player can use only abilities set in SpellClassMask
|
||||
&AuraEffect::HandleUnused, //264 unused (3.2.0)
|
||||
&AuraEffect::HandleUnused, //265 unused (3.2.0)
|
||||
@@ -631,7 +631,7 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load)
|
||||
{
|
||||
// Apply periodic time mod
|
||||
if (modOwner)
|
||||
modOwner->ApplySpellMod(GetId(), SPELLMOD_ACTIVATION_TIME, m_amplitude);
|
||||
modOwner->ApplySpellMod<SPELLMOD_ACTIVATION_TIME>(GetId(), m_amplitude);
|
||||
|
||||
if (caster)
|
||||
{
|
||||
@@ -689,7 +689,6 @@ void AuraEffect::CalculateSpellMod()
|
||||
m_spellmod->type = SpellModType(GetAuraType()); // SpellModType value == spell aura types
|
||||
m_spellmod->spellId = GetId();
|
||||
m_spellmod->mask = GetSpellInfo()->Effects[GetEffIndex()].SpellClassMask;
|
||||
m_spellmod->charges = GetBase()->GetCharges();
|
||||
}
|
||||
m_spellmod->value = GetAmount();
|
||||
break;
|
||||
@@ -1072,14 +1071,11 @@ bool AuraEffect::IsAffectedOnSpell(SpellInfo const* spell) const
|
||||
{
|
||||
if (!spell)
|
||||
return false;
|
||||
// Check family name
|
||||
if (spell->SpellFamilyName != m_spellInfo->SpellFamilyName)
|
||||
// Check family name and EffectClassMask
|
||||
if (!spell->IsAffected(m_spellInfo->SpellFamilyName, m_spellInfo->Effects[m_effIndex].SpellClassMask))
|
||||
return false;
|
||||
|
||||
// Check EffectClassMask
|
||||
if (m_spellInfo->Effects[m_effIndex].SpellClassMask & spell->SpellFamilyFlags)
|
||||
return true;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AuraEffect::HasSpellClassMask() const
|
||||
@@ -1146,6 +1142,99 @@ void AuraEffect::PeriodicTick(AuraApplication* aurApp, Unit* caster) const
|
||||
}
|
||||
}
|
||||
|
||||
bool AuraEffect::CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) const
|
||||
{
|
||||
bool result = GetBase()->CallScriptCheckEffectProcHandlers(this, aurApp, eventInfo);
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
|
||||
switch (GetAuraType())
|
||||
{
|
||||
case SPELL_AURA_MOD_CONFUSE:
|
||||
case SPELL_AURA_MOD_FEAR:
|
||||
case SPELL_AURA_MOD_STUN:
|
||||
case SPELL_AURA_MOD_ROOT:
|
||||
case SPELL_AURA_TRANSFORM:
|
||||
{
|
||||
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
|
||||
if (!damageInfo || !damageInfo->GetDamage())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Spell own damage at apply won't break CC
|
||||
if (spellInfo && spellInfo == eventInfo.GetSpellInfo())
|
||||
{
|
||||
Aura* aura = GetBase();
|
||||
// called from spellcast, should not have ticked yet
|
||||
if (aura->GetDuration() == aura->GetMaxDuration())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SPELL_AURA_MECHANIC_IMMUNITY:
|
||||
case SPELL_AURA_MOD_MECHANIC_RESISTANCE:
|
||||
// Compare mechanic
|
||||
if (!spellInfo || static_cast<int32>(spellInfo->Mechanic) != GetMiscValue())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK:
|
||||
// Skip melee hits and instant cast spells
|
||||
if (!spellInfo || !spellInfo->CalcCastTime())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SPELL_AURA_MOD_DAMAGE_FROM_CASTER:
|
||||
// Compare casters
|
||||
if (GetCasterGUID() != eventInfo.GetActor()->GetGUID())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SPELL_AURA_MOD_POWER_COST_SCHOOL:
|
||||
case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT:
|
||||
// Skip melee hits and spells with wrong school or zero cost
|
||||
if (!spellInfo || (!spellInfo->ManaCost && !spellInfo->ManaCostPercentage) || // Cost Check
|
||||
!(spellInfo->GetSchoolMask() & GetMiscValue())) // School Check
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SPELL_AURA_REFLECT_SPELLS_SCHOOL:
|
||||
// Skip melee hits and spells with wrong school
|
||||
if (!spellInfo || !(spellInfo->GetSchoolMask() & GetMiscValue()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SPELL_AURA_PROC_TRIGGER_SPELL:
|
||||
case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE:
|
||||
{
|
||||
// Don't proc extra attacks while already processing extra attack spell
|
||||
uint32 triggerSpellId = GetSpellInfo()->Effects[GetEffIndex()].TriggerSpell;
|
||||
if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId))
|
||||
{
|
||||
if (aurApp->GetTarget()->m_extraAttacks && triggeredSpellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
|
||||
{
|
||||
bool prevented = GetBase()->CallScriptEffectProcHandlers(this, aurApp, eventInfo);
|
||||
@@ -1154,6 +1243,16 @@ void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
|
||||
|
||||
switch (GetAuraType())
|
||||
{
|
||||
// CC Auras which use their amount to drop
|
||||
// Are there anyu more auras which need this?
|
||||
case SPELL_AURA_MOD_CONFUSE:
|
||||
case SPELL_AURA_MOD_FEAR:
|
||||
case SPELL_AURA_MOD_STUN:
|
||||
case SPELL_AURA_MOD_ROOT:
|
||||
case SPELL_AURA_TRANSFORM:
|
||||
HandleBreakableCCAuraProc(aurApp, eventInfo);
|
||||
break;
|
||||
case SPELL_AURA_DUMMY:
|
||||
case SPELL_AURA_PROC_TRIGGER_SPELL:
|
||||
HandleProcTriggerSpellAuraProc(aurApp, eventInfo);
|
||||
break;
|
||||
@@ -2878,7 +2977,6 @@ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bo
|
||||
displayId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
target->Mount(displayId, vehicleId, GetMiscValue());
|
||||
}
|
||||
@@ -5116,12 +5214,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
|
||||
if (target->GetTypeId() == TYPEID_PLAYER)
|
||||
target->ToPlayer()->RemoveAmmo(); // not use ammo and not allow use
|
||||
break;
|
||||
case 71563:
|
||||
{
|
||||
if (Aura* newAura = target->AddAura(71564, target))
|
||||
newAura->SetStackAmount(newAura->GetSpellInfo()->StackAmount);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// AT REMOVE
|
||||
@@ -6354,10 +6446,8 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
|
||||
mitigatedDamage += resilienceReduction;
|
||||
}
|
||||
|
||||
damage = std::max(0, dmg);
|
||||
cleanDamage.mitigated_damage = std::max(0, mitigatedDamage);
|
||||
DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK, cleanDamage.mitigated_damage);
|
||||
|
||||
DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, cleanDamage.mitigated_damage);
|
||||
Unit::CalcAbsorbResist(dmgInfo);
|
||||
|
||||
uint32 absorb = dmgInfo.GetAbsorb();
|
||||
@@ -6371,12 +6461,15 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
|
||||
// Set trigger flag
|
||||
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
|
||||
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
|
||||
uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT;
|
||||
uint32 hitMask = dmgInfo.GetHitMask();
|
||||
if (absorb > 0)
|
||||
procEx |= PROC_EX_ABSORB;
|
||||
hitMask |= PROC_HIT_ABSORB;
|
||||
|
||||
if (damage)
|
||||
{
|
||||
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
|
||||
hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
|
||||
}
|
||||
|
||||
int32 overkill = damage - target->GetHealth();
|
||||
if (overkill < 0)
|
||||
@@ -6387,7 +6480,8 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
|
||||
|
||||
Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true);
|
||||
|
||||
Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo);
|
||||
// allow null caster to call this function
|
||||
caster->ProcSkillsAndAuras(target, caster ? procAttacker : 0, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dmgInfo, nullptr);
|
||||
}
|
||||
|
||||
void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) const
|
||||
@@ -6440,10 +6534,8 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
|
||||
cleanDamageAmount += resilienceReduction;
|
||||
}
|
||||
|
||||
damage = std::max(0, dmg);
|
||||
cleanDamage.mitigated_damage = std::max(0, cleanDamageAmount);
|
||||
DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK, cleanDamage.mitigated_damage);
|
||||
|
||||
DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, cleanDamage.mitigated_damage);
|
||||
Unit::CalcAbsorbResist(dmgInfo);
|
||||
|
||||
uint32 absorb = dmgInfo.GetAbsorb();
|
||||
@@ -6453,12 +6545,15 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
|
||||
// Set trigger flag
|
||||
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
|
||||
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
|
||||
uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT;
|
||||
uint32 hitMask = dmgInfo.GetHitMask();
|
||||
if (absorb > 0)
|
||||
procEx |= PROC_EX_ABSORB;
|
||||
hitMask |= PROC_HIT_ABSORB;
|
||||
|
||||
if (dmgInfo.GetDamage())
|
||||
{
|
||||
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
|
||||
hitMask |= crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
|
||||
}
|
||||
|
||||
if (target->GetHealth() < dmgInfo.GetDamage())
|
||||
{
|
||||
@@ -6476,7 +6571,8 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
|
||||
|
||||
new_damage = Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false);
|
||||
|
||||
Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo);
|
||||
// allow null caster to call this function
|
||||
caster->ProcSkillsAndAuras(target, caster ? procAttacker : 0, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, nullptr, &dmgInfo, nullptr);
|
||||
|
||||
if (!caster || !caster->IsAlive())
|
||||
return;
|
||||
@@ -6489,6 +6585,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
|
||||
HealInfo healInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
|
||||
int32 gain = caster->HealBySpell(healInfo);
|
||||
caster->getHostileRefMgr().threatAssist(caster, gain * 0.5f, GetSpellInfo());
|
||||
caster->ProcSkillsAndAuras(caster, PROC_FLAG_DONE_PERIODIC, PROC_FLAG_TAKEN_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo);
|
||||
}
|
||||
|
||||
void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) const
|
||||
@@ -6622,13 +6719,13 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
|
||||
|
||||
HealInfo healInfo(caster, target, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
|
||||
Unit::CalcHealAbsorb(healInfo);
|
||||
int32 gain = Unit::DealHeal(caster, target, healInfo.GetHeal());
|
||||
Unit::DealHeal(healInfo);
|
||||
|
||||
SpellPeriodicAuraLogInfo pInfo(this, healInfo.GetHeal(), healInfo.GetHeal() - gain, healInfo.GetAbsorb(), 0, 0.0f, crit);
|
||||
SpellPeriodicAuraLogInfo pInfo(this, healInfo.GetHeal(), healInfo.GetHeal() - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit);
|
||||
target->SendPeriodicAuraLog(&pInfo);
|
||||
|
||||
if (caster)
|
||||
target->getHostileRefMgr().threatAssist(caster, float(gain) * 0.5f, GetSpellInfo());
|
||||
target->getHostileRefMgr().threatAssist(caster, float(healInfo.GetEffectiveHeal()) * 0.5f, GetSpellInfo());
|
||||
|
||||
bool haveCastItem = GetBase()->GetCastItemGUID();
|
||||
|
||||
@@ -6638,9 +6735,9 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
|
||||
if (target != caster && GetSpellInfo()->HasAttribute(SPELL_ATTR2_NO_TARGET_PER_SECOND_COST))
|
||||
{
|
||||
uint32 manaPerSecond = GetSpellInfo()->ManaPerSecond;
|
||||
if ((int32)manaPerSecond > gain && gain > 0)
|
||||
if (manaPerSecond > healInfo.GetEffectiveHeal() && healInfo.GetEffectiveHeal() > 0)
|
||||
{
|
||||
manaPerSecond = gain;
|
||||
manaPerSecond = healInfo.GetEffectiveHeal();
|
||||
}
|
||||
|
||||
uint32 absorb2 = 0;
|
||||
@@ -6652,13 +6749,15 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
|
||||
|
||||
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
|
||||
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
|
||||
uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_HOT;
|
||||
uint32 hitMask = (crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL);
|
||||
if (healInfo.GetAbsorb() > 0)
|
||||
procEx |= PROC_EX_ABSORB;
|
||||
{
|
||||
hitMask |= PROC_HIT_ABSORB;
|
||||
}
|
||||
|
||||
// ignore item heals
|
||||
if (!haveCastItem && GetAuraType() != SPELL_AURA_OBS_MOD_HEALTH) // xinef: dont allow obs_mod_health to proc spells, this is passive regeneration and not hot
|
||||
Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, heal, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, nullptr, &healInfo);
|
||||
caster->ProcSkillsAndAuras(target, caster ? procAttacker : 0, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo);
|
||||
}
|
||||
|
||||
void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const
|
||||
@@ -6839,14 +6938,32 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con
|
||||
// Set trigger flag
|
||||
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
|
||||
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
|
||||
uint32 procEx = createProcExtendMask(&damageInfo, SPELL_MISS_NONE) | PROC_EX_INTERNAL_DOT;
|
||||
uint32 hitMask = createProcHitMask(&damageInfo, SPELL_MISS_NONE);
|
||||
uint32 spellTypeMask = PROC_SPELL_TYPE_NO_DMG_HEAL;
|
||||
if (damageInfo.damage)
|
||||
{
|
||||
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
|
||||
spellTypeMask |= PROC_SPELL_TYPE_DAMAGE;
|
||||
}
|
||||
|
||||
caster->DealSpellDamage(&damageInfo, true);
|
||||
|
||||
DamageInfo dmgInfo(damageInfo, DOT);
|
||||
Unit::ProcDamageAndSpell(caster, damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto, nullptr, GetEffIndex(), nullptr, &dmgInfo);
|
||||
DamageInfo dmgInfo(damageInfo, DOT, BASE_ATTACK, hitMask);
|
||||
caster->ProcSkillsAndAuras(target, procAttacker, procVictim, spellTypeMask, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dmgInfo, nullptr);
|
||||
}
|
||||
|
||||
void AuraEffect::HandleBreakableCCAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
|
||||
{
|
||||
int32 const damageLeft = GetAmount() - static_cast<int32>(eventInfo.GetDamageInfo()->GetDamage());
|
||||
|
||||
if (damageLeft <= 0)
|
||||
{
|
||||
aurApp->GetTarget()->RemoveAura(aurApp);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetAmount(damageLeft);
|
||||
}
|
||||
}
|
||||
|
||||
void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
|
||||
@@ -6862,7 +6979,7 @@ void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEve
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("spells.aura", "AuraEffect::HandleProcTriggerSpellAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
|
||||
LOG_ERROR("spells.aura", "AuraEffect::HandleProcTriggerSpellAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6883,7 +7000,7 @@ void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("spells.aura", "AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
|
||||
LOG_ERROR("spells.aura", "AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ public:
|
||||
Aura* GetBase() const { return m_base; }
|
||||
void GetTargetList(std::list<Unit*>& targetList) const;
|
||||
void GetApplicationList(std::list<AuraApplication*>& applicationList) const;
|
||||
SpellModifier* GetSpellModifier() const { return m_spellmod; }
|
||||
|
||||
SpellInfo const* GetSpellInfo() const { return m_spellInfo; }
|
||||
uint32 GetId() const;
|
||||
@@ -96,6 +95,7 @@ public:
|
||||
void SendTickImmune(Unit* target, Unit* caster) const;
|
||||
void PeriodicTick(AuraApplication* aurApp, Unit* caster) const;
|
||||
|
||||
bool CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) const;
|
||||
void HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
|
||||
|
||||
void CleanupTriggeredSpells(Unit* target);
|
||||
@@ -333,6 +333,7 @@ public:
|
||||
void HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) const;
|
||||
|
||||
// aura effect proc handlers
|
||||
void HandleBreakableCCAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
|
||||
void HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
|
||||
void HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
|
||||
void HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
|
||||
|
||||
@@ -411,7 +411,7 @@ Aura::Aura(SpellInfo const* spellproto, WorldObject* owner, Unit* caster, Item*
|
||||
m_castItemGuid(itemGUID ? itemGUID : castItem ? castItem->GetGUID() : ObjectGuid::Empty), m_castItemEntry(castItem ? castItem->GetEntry() : 0), m_applyTime(GameTime::GetGameTime().count()),
|
||||
m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0),
|
||||
m_casterLevel(caster ? caster->getLevel() : m_spellInfo->SpellLevel), m_procCharges(0), m_stackAmount(1),
|
||||
m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_triggeredByAuraSpellInfo(nullptr)
|
||||
m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_procCooldown(std::chrono::steady_clock::time_point::min()), m_triggeredByAuraSpellInfo(nullptr)
|
||||
{
|
||||
if ((m_spellInfo->ManaPerSecond || m_spellInfo->ManaPerSecondPerLevel) && !m_spellInfo->HasAttribute(SPELL_ATTR2_NO_TARGET_PER_SECOND_COST))
|
||||
m_timeCla = 1 * IN_MILLISECONDS;
|
||||
@@ -875,7 +875,7 @@ int32 Aura::CalcMaxDuration(Unit* caster) const
|
||||
|
||||
// IsPermanent() checks max duration (which we are supposed to calculate here)
|
||||
if (maxDuration != -1 && modOwner)
|
||||
modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, maxDuration);
|
||||
modOwner->ApplySpellMod<SPELLMOD_DURATION>(GetId(), maxDuration);
|
||||
return maxDuration;
|
||||
}
|
||||
|
||||
@@ -885,7 +885,7 @@ void Aura::SetDuration(int32 duration, bool withMods)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, duration);
|
||||
modOwner->ApplySpellMod<SPELLMOD_DURATION>(GetId(), duration);
|
||||
}
|
||||
m_duration = duration;
|
||||
SetNeedClientUpdateForTargets();
|
||||
@@ -976,11 +976,11 @@ uint8 Aura::CalcMaxCharges(Unit* caster) const
|
||||
{
|
||||
uint32 maxProcCharges = m_spellInfo->ProcCharges;
|
||||
if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId()))
|
||||
maxProcCharges = procEntry->charges;
|
||||
maxProcCharges = procEntry->Charges;
|
||||
|
||||
if (caster)
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, maxProcCharges);
|
||||
modOwner->ApplySpellMod<SPELLMOD_CHARGES>(GetId(), maxProcCharges);
|
||||
return maxProcCharges;
|
||||
}
|
||||
|
||||
@@ -1062,12 +1062,6 @@ bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode, bool periodicRes
|
||||
|
||||
// reset charges
|
||||
SetCharges(CalcMaxCharges());
|
||||
// FIXME: not a best way to synchronize charges, but works
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
if (AuraEffect* aurEff = GetEffect(i))
|
||||
if (aurEff->GetAuraType() == SPELL_AURA_ADD_FLAT_MODIFIER || aurEff->GetAuraType() == SPELL_AURA_ADD_PCT_MODIFIER)
|
||||
if (SpellModifier* mod = aurEff->GetSpellModifier())
|
||||
mod->charges = GetCharges();
|
||||
}
|
||||
|
||||
SetStackAmount(stackAmount);
|
||||
@@ -1202,7 +1196,7 @@ int32 Aura::CalcDispelChance(Unit* auraTarget, bool offensive) const
|
||||
// Apply dispel mod from aura caster
|
||||
if (Unit* caster = GetCaster())
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(GetId(), SPELLMOD_RESIST_DISPEL_CHANCE, resistChance);
|
||||
modOwner->ApplySpellMod<SPELLMOD_RESIST_DISPEL_CHANCE>(GetId(), resistChance);
|
||||
|
||||
// Dispel resistance from target SPELL_AURA_MOD_DISPEL_RESIST
|
||||
// Only affects offensive dispels
|
||||
@@ -1260,7 +1254,7 @@ void Aura::HandleAllEffects(AuraApplication* aurApp, uint8 mode, bool apply)
|
||||
m_effects[i]->HandleEffect(aurApp, mode, apply);
|
||||
}
|
||||
|
||||
void Aura::GetApplicationList(std::list<AuraApplication*>& applicationList) const
|
||||
void Aura::GetApplicationList(Unit::AuraApplicationList& applicationList) const
|
||||
{
|
||||
for (Aura::ApplicationMap::const_iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter)
|
||||
{
|
||||
@@ -1439,6 +1433,9 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
|
||||
}
|
||||
break;
|
||||
case 44544: // Fingers of Frost
|
||||
// Refresh or add visual aura
|
||||
target->CastCustomSpell(74396, SPELLVALUE_AURA_STACK, sSpellMgr->AssertSpellInfo(74396)->StackAmount, (Unit*)nullptr, true);
|
||||
break;
|
||||
{
|
||||
// See if we already have the indicator aura. If not, create one.
|
||||
if (Aura* aur = target->GetAura(74396))
|
||||
@@ -1663,10 +1660,6 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
|
||||
target->CastSpell(target, 32612, true, nullptr, GetEffect(1));
|
||||
target->CombatStop();
|
||||
break;
|
||||
case 74396: // Fingers of Frost
|
||||
// Remove the IGNORE_AURASTATE aura
|
||||
target->RemoveAurasDueToSpell(44544);
|
||||
break;
|
||||
case 44401: // Missile Barrage
|
||||
case 48108: // Hot Streak
|
||||
case 57761: // Fireball!
|
||||
@@ -2192,22 +2185,17 @@ bool Aura::CanStackWith(Aura const* existingAura, bool remove) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Aura::IsProcOnCooldown() const
|
||||
bool Aura::IsProcOnCooldown(std::chrono::steady_clock::time_point now) const
|
||||
{
|
||||
/*if (m_procCooldown)
|
||||
{
|
||||
if (m_procCooldown > GameTime::GetGameTime().count())
|
||||
return true;
|
||||
}*/
|
||||
return false;
|
||||
return m_procCooldown > now;
|
||||
}
|
||||
|
||||
void Aura::AddProcCooldown(uint32 /*msec*/)
|
||||
void Aura::AddProcCooldown(std::chrono::steady_clock::time_point cooldownEnd)
|
||||
{
|
||||
//m_procCooldown = GameTime::GetGameTime().count() + msec;
|
||||
m_procCooldown = cooldownEnd;
|
||||
}
|
||||
|
||||
void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo)
|
||||
void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now)
|
||||
{
|
||||
bool prepare = CallScriptPrepareProcHandlers(aurApp, eventInfo);
|
||||
if (!prepare)
|
||||
@@ -2225,47 +2213,101 @@ void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInf
|
||||
ASSERT(procEntry);
|
||||
|
||||
// cooldowns should be added to the whole aura (see 51698 area aura)
|
||||
AddProcCooldown(procEntry->cooldown);
|
||||
AddProcCooldown(now + procEntry->Cooldown);
|
||||
}
|
||||
|
||||
bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const
|
||||
uint8 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const
|
||||
{
|
||||
SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId());
|
||||
// only auras with spell proc entry can trigger proc
|
||||
if (!procEntry)
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
// check spell triggering us
|
||||
if (Spell const* spell = eventInfo.GetProcSpell())
|
||||
{
|
||||
// Do not allow auras to proc from effect triggered from itself
|
||||
if (spell->IsTriggeredByAura(m_spellInfo))
|
||||
return 0;
|
||||
|
||||
// check if aura can proc when spell is triggered (exception for hunter auto shot & wands)
|
||||
if (spell->IsTriggered() && !(procEntry->AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC) && !(eventInfo.GetTypeMask() & AUTO_ATTACK_PROC_FLAG_MASK))
|
||||
if (!GetSpellInfo()->HasAttribute(SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check don't break stealth attr present
|
||||
if (m_spellInfo->HasAura(SPELL_AURA_MOD_STEALTH))
|
||||
{
|
||||
if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_CU_DONT_BREAK_STEALTH))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check if we have charges to proc with
|
||||
if (IsUsingCharges() && !GetCharges())
|
||||
return false;
|
||||
if (IsUsingCharges())
|
||||
{
|
||||
if (!GetCharges())
|
||||
return 0;
|
||||
|
||||
if (procEntry->AttributesMask & PROC_ATTR_REQ_SPELLMOD)
|
||||
{
|
||||
if (Spell const* spell = eventInfo.GetProcSpell())
|
||||
{
|
||||
if (!spell->m_appliedMods.count(const_cast<Aura*>(this)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check proc cooldown
|
||||
if (IsProcOnCooldown())
|
||||
return false;
|
||||
|
||||
// TODO:
|
||||
// something about triggered spells triggering, and add extra attack effect
|
||||
if (IsProcOnCooldown(now))
|
||||
return 0;
|
||||
|
||||
// do checks against db data
|
||||
if (!sSpellMgr->CanSpellTriggerProcOnEvent(*procEntry, eventInfo))
|
||||
return false;
|
||||
if (!SpellMgr::CanSpellTriggerProcOnEvent(*procEntry, eventInfo))
|
||||
return 0;
|
||||
|
||||
// do checks using conditions table
|
||||
ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_PROC, GetId());
|
||||
ConditionSourceInfo condInfo = ConditionSourceInfo(eventInfo.GetActor(), eventInfo.GetActionTarget());
|
||||
if (!sConditionMgr->IsObjectMeetToConditions(condInfo, conditions))
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
// AuraScript Hook
|
||||
bool check = const_cast<Aura*>(this)->CallScriptCheckProcHandlers(aurApp, eventInfo);
|
||||
if (!check)
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
// At least one effect has to pass checks to proc aura
|
||||
uint8 procEffectMask = aurApp->GetEffectMask();
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (procEffectMask & (1 << i))
|
||||
if ((procEntry->AttributesMask & (PROC_ATTR_DISABLE_EFF_0 << i)) || !GetEffect(i)->CheckEffectProc(aurApp, eventInfo))
|
||||
procEffectMask &= ~(1 << i);
|
||||
}
|
||||
|
||||
if (!procEffectMask)
|
||||
return 0;
|
||||
|
||||
// TODO:
|
||||
// do allow additional requirements for procs
|
||||
// this is needed because this is the last moment in which you can prevent aura charge drop on proc
|
||||
// and possibly a way to prevent default checks (if there're going to be any)
|
||||
|
||||
// Aura added by spoell can't trigger from self (prevent drop charges/do triggers)
|
||||
// But except periodic and kill triggers (can triggered from self)
|
||||
if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
|
||||
{
|
||||
if (spellInfo->Id == GetId() && !(eventInfo.GetTypeMask() & (PROC_FLAG_TAKEN_PERIODIC | PROC_FLAG_KILL)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if current equipment meets aura requirements
|
||||
// do that only for passive spells
|
||||
// TODO: this needs to be unified for all kinds of auras
|
||||
@@ -2278,7 +2320,7 @@ bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventI
|
||||
if (GetSpellInfo()->EquippedItemClass == ITEM_CLASS_WEAPON)
|
||||
{
|
||||
if (target->ToPlayer()->IsInFeralForm())
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
if (DamageInfo const* damageInfo = eventInfo.GetDamageInfo())
|
||||
{
|
||||
@@ -2309,39 +2351,50 @@ bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventI
|
||||
}
|
||||
}
|
||||
|
||||
return roll_chance_f(CalcProcChance(*procEntry, eventInfo));
|
||||
if (roll_chance_f(CalcProcChance(*procEntry, eventInfo)))
|
||||
return procEffectMask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const
|
||||
{
|
||||
float chance = procEntry.chance;
|
||||
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)
|
||||
if (eventInfo.GetDamageInfo() && procEntry.ProcsPerMinute != 0)
|
||||
{
|
||||
uint32 WeaponSpeed = caster->GetAttackTime(eventInfo.GetDamageInfo()->GetAttackType());
|
||||
chance = caster->GetPPMProcChance(WeaponSpeed, procEntry.ratePerMinute, GetSpellInfo());
|
||||
chance = caster->GetPPMProcChance(WeaponSpeed, procEntry.ProcsPerMinute, GetSpellInfo());
|
||||
}
|
||||
// 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);
|
||||
modOwner->ApplySpellMod<SPELLMOD_CHANCE_OF_SUCCESS>(GetId(), chance);
|
||||
}
|
||||
return chance;
|
||||
}
|
||||
|
||||
void Aura::TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo)
|
||||
void Aura::TriggerProcOnEvent(uint8 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo)
|
||||
{
|
||||
CallScriptProcHandlers(aurApp, eventInfo);
|
||||
bool prevented = CallScriptProcHandlers(aurApp, eventInfo);
|
||||
|
||||
if (!prevented)
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (!(procEffectMask & (1 << i)))
|
||||
continue;
|
||||
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
if (aurApp->HasEffect(i))
|
||||
// OnEffectProc / AfterEffectProc hooks handled in AuraEffect::HandleProc()
|
||||
GetEffect(i)->HandleProc(aurApp, eventInfo);
|
||||
if (aurApp->HasEffect(i))
|
||||
GetEffect(i)->HandleProc(aurApp, eventInfo);
|
||||
}
|
||||
|
||||
CallScriptAfterProcHandlers(aurApp, eventInfo);
|
||||
CallScriptAfterProcHandlers(aurApp, eventInfo);
|
||||
}
|
||||
|
||||
// Remove aura if we've used last charge to proc
|
||||
if (IsUsingCharges() && !GetCharges())
|
||||
@@ -2637,30 +2690,14 @@ void Aura::CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication con
|
||||
bool Aura::CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
|
||||
{
|
||||
bool result = true;
|
||||
for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
|
||||
for (auto & m_loadedScript : m_loadedScripts)
|
||||
{
|
||||
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_PROC, aurApp);
|
||||
std::list<AuraScript::CheckProcHandler>::iterator hookItrEnd = (*scritr)->DoCheckProc.end(), hookItr = (*scritr)->DoCheckProc.begin();
|
||||
m_loadedScript->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_PROC, aurApp);
|
||||
auto hookItrEnd = m_loadedScript->DoCheckProc.end(), hookItr = m_loadedScript->DoCheckProc.begin();
|
||||
for (; hookItr != hookItrEnd; ++hookItr)
|
||||
result &= hookItr->Call(*scritr, eventInfo);
|
||||
result &= hookItr->Call(m_loadedScript, eventInfo);
|
||||
|
||||
(*scritr)->_FinishScriptCall();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Aura::CallScriptCheckAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
|
||||
{
|
||||
bool result = true;
|
||||
for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
|
||||
{
|
||||
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_AFTER_PROC, aurApp);
|
||||
std::list<AuraScript::CheckProcHandler>::iterator hookItrEnd = (*scritr)->DoCheckAfterProc.end(), hookItr = (*scritr)->DoCheckAfterProc.begin();
|
||||
for (; hookItr != hookItrEnd; ++hookItr)
|
||||
result &= hookItr->Call(*scritr, eventInfo);
|
||||
|
||||
(*scritr)->_FinishScriptCall();
|
||||
m_loadedScript->_FinishScriptCall();
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -2715,6 +2752,26 @@ void Aura::CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventI
|
||||
}
|
||||
}
|
||||
|
||||
bool Aura::CallScriptCheckEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
|
||||
{
|
||||
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC, aurApp);
|
||||
std::list<AuraScript::CheckEffectProcHandler>::iterator hookItrEnd = (*scritr)->DoCheckEffectProc.end(), hookItr = (*scritr)->DoCheckEffectProc.begin();
|
||||
for (; hookItr != hookItrEnd; ++hookItr)
|
||||
{
|
||||
if (hookItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
|
||||
result &= hookItr->Call(*scritr, aurEff, eventInfo);
|
||||
}
|
||||
|
||||
(*scritr)->_FinishScriptCall();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Aura::CallScriptEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo)
|
||||
{
|
||||
bool preventDefault = false;
|
||||
|
||||
@@ -191,18 +191,14 @@ public:
|
||||
bool CanStackWith(Aura const* checkAura, bool remove) const;
|
||||
bool IsAuraStronger(Aura const* newAura) const;
|
||||
|
||||
// Proc system
|
||||
// this subsystem is not yet in use - the core of it is functional, but still some research has to be done
|
||||
// and some dependant problems fixed before it can replace old proc system (for example cooldown handling)
|
||||
// currently proc system functionality is implemented in Unit::ProcDamageAndSpell
|
||||
bool IsProcOnCooldown() const;
|
||||
void AddProcCooldown(uint32 msec);
|
||||
bool IsProcOnCooldown(std::chrono::steady_clock::time_point now) const;
|
||||
void AddProcCooldown(std::chrono::steady_clock::time_point cooldownEnd);
|
||||
bool IsUsingCharges() const { return m_isUsingCharges; }
|
||||
void SetUsingCharges(bool val) { m_isUsingCharges = val; }
|
||||
void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo);
|
||||
bool IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const;
|
||||
void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now);
|
||||
uint8 GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const;
|
||||
float CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const;
|
||||
void TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo);
|
||||
void TriggerProcOnEvent(uint8 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo);
|
||||
|
||||
// AuraScript
|
||||
void LoadScripts();
|
||||
@@ -226,7 +222,7 @@ public:
|
||||
|
||||
// Spell Proc Hooks
|
||||
bool CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
|
||||
bool CallScriptCheckAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
|
||||
bool CallScriptCheckEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo);
|
||||
bool CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
|
||||
bool CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
|
||||
void CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
|
||||
@@ -269,6 +265,8 @@ protected:
|
||||
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;
|
||||
|
||||
std::chrono::steady_clock::time_point m_procCooldown;
|
||||
|
||||
private:
|
||||
Unit::AuraApplicationList m_removedApplications;
|
||||
|
||||
|
||||
@@ -640,7 +640,7 @@ Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags,
|
||||
m_healing = 0;
|
||||
m_procAttacker = 0;
|
||||
m_procVictim = 0;
|
||||
m_procEx = 0;
|
||||
m_hitMask = 0;
|
||||
focusObject = nullptr;
|
||||
m_cast_count = 0;
|
||||
m_glyphIndex = 0;
|
||||
@@ -1811,7 +1811,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)
|
||||
{
|
||||
@@ -2273,12 +2273,11 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -2317,7 +2316,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 &&
|
||||
@@ -2326,10 +2325,11 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
|
||||
m_spellInfo->SpellFamilyFlags[2] & 0x00064000)) // Explosive and Immolation Trap
|
||||
{
|
||||
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 */
|
||||
// also fill up other flags (DoAllEffectOnTarget only fills up flag if both are not set)
|
||||
m_procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG;
|
||||
m_procVictim |= PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG;
|
||||
}
|
||||
|
||||
// Hellfire Effect - trigger as DOT
|
||||
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags[0] & 0x00000040)
|
||||
@@ -2337,20 +2337,6 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
|
||||
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_ACTIVE_THREAT) ||
|
||||
m_spellInfo->HasAttribute(SPELL_ATTR3_NOT_A_PROC)))
|
||||
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->ToCreature()->IsTotem() && m_caster->IsControlledByPlayer())
|
||||
m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY;
|
||||
}
|
||||
|
||||
void Spell::CleanupTargetList()
|
||||
@@ -2362,6 +2348,32 @@ void Spell::CleanupTargetList()
|
||||
m_delayTrajectory = 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*/)
|
||||
{
|
||||
for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
|
||||
@@ -2373,11 +2385,8 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
|
||||
return;
|
||||
|
||||
if (checkIfValid)
|
||||
{
|
||||
SpellCastResult res = m_spellInfo->CheckTarget(m_caster, target, implicit);
|
||||
if (res != SPELL_CAST_OK)
|
||||
if (m_spellInfo->CheckTarget(m_caster, target, implicit) != SPELL_CAST_OK) // skip stealth checks for AOE
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for effect immune skip if immuned
|
||||
for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
|
||||
@@ -2448,23 +2457,22 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
|
||||
targetInfo.timeDelay = (uint64) floor(dist / 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
|
||||
m_caster->m_Events.AddEvent(new ReflectEvent(m_caster, targetInfo.targetGUID, m_spellInfo), m_caster->m_Events.CalculateTime(targetInfo.timeDelay));
|
||||
targetInfo.timeDelay += targetInfo.timeDelay >> 1;
|
||||
|
||||
m_spellFlags |= SPELL_FLAG_REFLECTED;
|
||||
@@ -2545,7 +2553,7 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask)
|
||||
if (dist < 5.0f)
|
||||
dist = 5.0f;
|
||||
target.timeDelay = uint64(floor(dist / 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
|
||||
@@ -2660,8 +2668,8 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
|
||||
PrepareScriptHitHandlers();
|
||||
CallScriptBeforeHitHandlers(missInfo);
|
||||
|
||||
//Spells with this flag cannot trigger if effect is casted on self
|
||||
bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPRESS_CASTER_PROCS) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE2);
|
||||
// Spells with this flag cannot trigger if effect is casted on self
|
||||
bool const canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPRESS_CASTER_PROCS) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE2);
|
||||
bool reflectedSpell = missInfo == SPELL_MISS_REFLECT;
|
||||
Unit* spellHitTarget = nullptr;
|
||||
|
||||
@@ -2699,18 +2707,14 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
|
||||
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);
|
||||
}
|
||||
|
||||
// Fill base trigger info
|
||||
uint32 procAttacker = m_procAttacker;
|
||||
uint32 procVictim = m_procVictim;
|
||||
uint32 procEx = m_procEx;
|
||||
uint32 hitMask = m_hitMask;
|
||||
|
||||
// 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;
|
||||
@@ -2766,11 +2770,11 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
|
||||
|
||||
if (crit)
|
||||
{
|
||||
procEx |= PROC_EX_CRITICAL_HIT;
|
||||
hitMask |= PROC_HIT_CRITICAL;
|
||||
addhealth = Unit::SpellCriticalHealingBonus(caster, m_spellInfo, addhealth, nullptr);
|
||||
}
|
||||
else
|
||||
procEx |= PROC_EX_NORMAL_HIT;
|
||||
hitMask |= PROC_HIT_NORMAL;
|
||||
|
||||
HealInfo healInfo(caster, unitTarget, addhealth, m_spellInfo, m_spellInfo->GetSchoolMask());
|
||||
|
||||
@@ -2778,27 +2782,20 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
|
||||
if (GetSpellValue()->ForcedCritResult)
|
||||
{
|
||||
crit = true;
|
||||
procEx |= PROC_EX_CRITICAL_HIT;
|
||||
hitMask |= PROC_HIT_CRITICAL;
|
||||
}
|
||||
|
||||
int32 gain = caster->HealBySpell(healInfo, crit);
|
||||
unitTarget->getHostileRefMgr().threatAssist(caster, float(gain) * 0.5f, m_spellInfo);
|
||||
m_healing = gain;
|
||||
|
||||
// Xinef: if heal acutally healed something, add no overheal flag
|
||||
if (m_healing)
|
||||
procEx |= PROC_EX_NO_OVERHEAL;
|
||||
|
||||
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
|
||||
// Do triggers for unit
|
||||
if (canEffectTrigger)
|
||||
Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
|
||||
m_triggeredByAuraSpell.effectIndex, this, nullptr, &healInfo);
|
||||
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)
|
||||
{
|
||||
caster->SetLastDamagedTargetGuid(unitTarget->GetGUID());
|
||||
|
||||
// Fill base damage struct (unitTarget - is real spell target)
|
||||
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo, m_spellSchoolMask);
|
||||
|
||||
@@ -2858,7 +2855,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
|
||||
if (reflectedSpell)
|
||||
effectUnit->SendSpellNonMeleeReflectLog(&damageInfo, effectUnit);
|
||||
|
||||
procEx |= createProcExtendMask(&damageInfo, missInfo);
|
||||
hitMask |= createProcHitMask(&damageInfo, missInfo);
|
||||
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
|
||||
|
||||
caster->DealSpellDamage(&damageInfo, true, this);
|
||||
@@ -2866,16 +2863,15 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
|
||||
// do procs after damage, eg healing effects
|
||||
// no need to check if target is alive, done in procdamageandspell
|
||||
|
||||
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
|
||||
// Do triggers for unit
|
||||
if (canEffectTrigger)
|
||||
{
|
||||
DamageInfo dmgInfo(damageInfo, SPELL_DIRECT_DAMAGE);
|
||||
Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
|
||||
m_triggeredByAuraSpell.effectIndex, this, &dmgInfo);
|
||||
DamageInfo dmgInfo(damageInfo, SPELL_DIRECT_DAMAGE, m_attackType, hitMask);
|
||||
caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, this, &dmgInfo, nullptr);
|
||||
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 &&
|
||||
m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) == 0 && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
|
||||
caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx);
|
||||
caster->ToPlayer()->CastItemCombatSpell(dmgInfo);
|
||||
}
|
||||
|
||||
m_damage = damageInfo.damage;
|
||||
@@ -2885,19 +2881,16 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
|
||||
{
|
||||
// Fill base damage struct (unitTarget - is real spell target)
|
||||
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo, m_spellSchoolMask);
|
||||
procEx |= createProcExtendMask(&damageInfo, missInfo);
|
||||
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
|
||||
hitMask |= createProcHitMask(&damageInfo, missInfo);
|
||||
// Do triggers for unit
|
||||
if (canEffectTrigger)
|
||||
{
|
||||
DamageInfo dmgInfo(damageInfo, NODAMAGE);
|
||||
Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
|
||||
m_triggeredByAuraSpell.effectIndex, this, &dmgInfo);
|
||||
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);
|
||||
|
||||
// Xinef: eg. rogue poisons can proc off cheap shot, etc. so this block should be here also
|
||||
// Xinef: ofc count only spells that HIT the target, little hack used to fool the system
|
||||
if ((procEx & PROC_EX_NORMAL_HIT || procEx & PROC_EX_CRITICAL_HIT) && caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 &&
|
||||
m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) == 0 && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
|
||||
caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim | PROC_FLAG_TAKEN_DAMAGE, procEx);
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) &&
|
||||
!m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
|
||||
caster->ToPlayer()->CastItemCombatSpell(spellNoDamageInfo);
|
||||
}
|
||||
|
||||
// Failed Pickpocket, reveal rogue
|
||||
@@ -3121,10 +3114,6 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
|
||||
m_spellAura = Aura::TryRefreshStackOrCreate(aurSpellInfo, effectMask, unit, m_originalCaster,
|
||||
(aurSpellInfo == m_spellInfo) ? &m_spellValue->EffectBasePoints[0] : &basePoints[0], m_CastItem, ObjectGuid::Empty, &refresh, refreshPeriodic);
|
||||
|
||||
// xinef: if aura was not refreshed, add proc ex
|
||||
if (!refresh)
|
||||
m_procEx |= PROC_EX_NO_AURA_REFRESH;
|
||||
|
||||
if (m_spellAura)
|
||||
{
|
||||
// Set aura stack amount to desired value
|
||||
@@ -3253,8 +3242,8 @@ void Spell::DoTriggersOnSpellHit(Unit* unit, uint8 effMask)
|
||||
// info confirmed with retail sniffs of permafrost and shadow weaving
|
||||
if (!m_hitTriggerSpells.empty())
|
||||
{
|
||||
int _duration = 0;
|
||||
for (HitTriggerSpellList::const_iterator i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i)
|
||||
int32 _duration = 0;
|
||||
for (auto i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i)
|
||||
{
|
||||
if (CanExecuteTriggersOnHit(effMask, i->triggeredByAura) && roll_chance_i(i->chance))
|
||||
{
|
||||
@@ -3380,7 +3369,7 @@ bool Spell::UpdateChanneledTargetList()
|
||||
}
|
||||
|
||||
if (Player* modOwner = m_caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
|
||||
modOwner->ApplySpellMod<SPELLMOD_RANGE>(m_spellInfo->Id, range, this);
|
||||
|
||||
// xinef: add little tolerance level
|
||||
range += std::min(3.0f, range * 0.1f); // 10% but no more than 3yd
|
||||
@@ -3543,7 +3532,7 @@ SpellCastResult Spell::prepare(SpellCastTargets const* targets, AuraEffect const
|
||||
}
|
||||
|
||||
// Prepare data for triggers
|
||||
prepareDataForTriggerSystem(triggeredByAura);
|
||||
prepareDataForTriggerSystem();
|
||||
|
||||
// calculate cast time (calculated after first CheckCast check to prevent charge counting for first CheckCast fail)
|
||||
m_casttime = (_triggeredCastFlags & TRIGGERED_CAST_DIRECTLY) ? 0 : m_spellInfo->CalcCastTime(m_caster, this);
|
||||
@@ -3727,10 +3716,6 @@ void Spell::cancel(bool bySelf)
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->NeedSendSpectatorData())
|
||||
ArenaSpectator::SendCommand_Spell(m_caster->FindMap(), m_caster->GetGUID(), "SPE", m_spellInfo->Id, bySelf ? 99998 : 99999);
|
||||
|
||||
// spell is canceled-take mods and clear list
|
||||
if (Player* player = m_caster->GetSpellModOwner())
|
||||
player->RemoveSpellMods(this);
|
||||
|
||||
m_appliedMods.clear();
|
||||
break;
|
||||
default:
|
||||
@@ -3955,26 +3940,14 @@ void Spell::_cast(bool skipCheck)
|
||||
}
|
||||
}
|
||||
|
||||
uint32 procEx = PROC_EX_NORMAL_HIT;
|
||||
uint32 hitMask = m_hitMask;
|
||||
|
||||
for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
|
||||
if (!(hitMask & PROC_HIT_CRITICAL))
|
||||
{
|
||||
if (ihit->missCondition != SPELL_MISS_NONE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ihit->crit)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
procEx |= PROC_EX_CRITICAL_HIT;
|
||||
break;
|
||||
hitMask |= PROC_HIT_NORMAL;
|
||||
}
|
||||
|
||||
Unit::ProcDamageAndSpell(m_originalCaster, m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
|
||||
m_triggeredByAuraSpell.effectIndex, this, nullptr, nullptr, PROC_SPELL_PHASE_CAST);
|
||||
m_originalCaster->ProcSkillsAndAuras(m_originalCaster, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr);
|
||||
}
|
||||
|
||||
if (modOwner)
|
||||
@@ -3995,11 +3968,6 @@ void Spell::_cast(bool skipCheck)
|
||||
if (m_caster->HasUnitState(UNIT_STATE_CASTING) && !m_caster->IsNonMeleeSpellCast(false, false, true))
|
||||
m_caster->ClearUnitState(UNIT_STATE_CASTING);
|
||||
|
||||
// remove all applied mods at this point
|
||||
// dont allow user to use them twice in case spell did not reach current target
|
||||
if (modOwner)
|
||||
modOwner->RemoveSpellMods(this);
|
||||
|
||||
// Xinef: why do we keep focus after spell is sent to air?
|
||||
// Xinef: Because of this, in the middle of some animation after setting targetguid to 0 etc
|
||||
// Xinef: we get focused to it out of nowhere...
|
||||
@@ -4092,7 +4060,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
|
||||
if (m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC))
|
||||
@@ -4264,10 +4232,8 @@ void Spell::_handle_finish_phase()
|
||||
m_caster->AddComboPoints(m_comboTarget, m_comboPointGain);
|
||||
}
|
||||
|
||||
if (m_spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
|
||||
{
|
||||
m_caster->SetLastExtraAttackSpell(m_spellInfo->Id);
|
||||
}
|
||||
if (m_caster->m_extraAttacks && GetSpellInfo()->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
|
||||
m_caster->HandleProcExtraAttackFor(m_caster->GetVictim());
|
||||
|
||||
if (!IsAutoRepeat() && !IsNextMeleeSwingSpell())
|
||||
if (m_caster->GetCharmerOrOwnerPlayerOrPlayerItself())
|
||||
@@ -4296,25 +4262,13 @@ void Spell::_handle_finish_phase()
|
||||
}
|
||||
}
|
||||
|
||||
uint32 procEx = PROC_EX_NORMAL_HIT;
|
||||
for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
|
||||
uint32 hitMask = m_hitMask;
|
||||
if (!(hitMask & PROC_HIT_CRITICAL))
|
||||
{
|
||||
if (ihit->missCondition != SPELL_MISS_NONE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ihit->crit)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
procEx |= PROC_EX_CRITICAL_HIT;
|
||||
break;
|
||||
hitMask |= PROC_HIT_NORMAL;
|
||||
}
|
||||
|
||||
Unit::ProcDamageAndSpell(m_originalCaster, m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
|
||||
m_triggeredByAuraSpell.effectIndex, this, nullptr, nullptr, PROC_SPELL_PHASE_FINISH);
|
||||
m_originalCaster->ProcSkillsAndAuras(m_originalCaster, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_FINISH, hitMask, this, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4504,11 +4458,6 @@ void Spell::finish(bool ok)
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER && !m_triggeredByAuraSpell)
|
||||
m_caster->ToPlayer()->UpdatePotionCooldown(this);
|
||||
|
||||
// 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
|
||||
if (Player* player = m_caster->GetSpellModOwner())
|
||||
player->RemoveSpellMods(this);
|
||||
|
||||
// xinef: clear reactive auras states after spell cast
|
||||
if (m_spellInfo->CasterAuraState == AURA_STATE_DEFENSE || m_spellInfo->CasterAuraState == AURA_STATE_HUNTER_PARRY)
|
||||
m_caster->ModifyAuraState(AuraStateType(m_spellInfo->CasterAuraState), false);
|
||||
@@ -5293,7 +5242,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, this);
|
||||
modOwner->ApplySpellMod<SPELLMOD_SPELL_COST_REFUND_ON_FAIL>(m_spellInfo->Id, m_powerCost, this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -5394,7 +5343,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
|
||||
@@ -5434,7 +5383,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);
|
||||
}
|
||||
|
||||
runeCost[RUNE_DEATH] = 0; // calculated later
|
||||
@@ -5831,7 +5780,11 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
// Xinef: do not check explicit target for triggered spell casted on self with targetflag enemy
|
||||
if (!m_triggeredByAuraSpell || m_targets.GetUnitTarget() != m_caster || !(m_spellInfo->GetExplicitTargetMask() & TARGET_FLAG_UNIT_ENEMY))
|
||||
{
|
||||
SpellCastResult castResult = m_spellInfo->CheckExplicitTarget((m_originalCaster && m_caster->GetEntry() != WORLD_TRIGGER) ? m_originalCaster : m_caster, m_targets.GetObjectTarget(), m_targets.GetItemTarget());
|
||||
Unit* caster = m_caster;
|
||||
if (m_originalCaster && m_caster->GetEntry() != WORLD_TRIGGER) // Do a simplified check for gameobject casts
|
||||
caster = m_originalCaster;
|
||||
|
||||
SpellCastResult castResult = m_spellInfo->CheckExplicitTarget(caster, m_targets.GetObjectTarget(), m_targets.GetItemTarget());
|
||||
if (castResult != SPELL_CAST_OK)
|
||||
return castResult;
|
||||
}
|
||||
@@ -5839,7 +5792,7 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
|
||||
if (Unit* target = m_targets.GetUnitTarget())
|
||||
{
|
||||
SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, false);
|
||||
SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, m_caster->GetEntry() == WORLD_TRIGGER); // skip stealth checks for GO casts
|
||||
if (castResult != SPELL_CAST_OK)
|
||||
return castResult;
|
||||
|
||||
@@ -7035,7 +6988,7 @@ SpellCastResult Spell::CheckRange(bool strict)
|
||||
range_type = SPELL_RANGE_RANGED;
|
||||
|
||||
if (Player* modOwner = m_caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, max_range, this);
|
||||
modOwner->ApplySpellMod<SPELLMOD_RANGE>(m_spellInfo->Id, max_range, this);
|
||||
|
||||
// xinef: dont check max_range to strictly after cast
|
||||
if (range_type != SPELL_RANGE_MELEE && !strict)
|
||||
@@ -7749,7 +7702,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;
|
||||
@@ -7787,7 +7740,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;
|
||||
@@ -8167,14 +8120,6 @@ bool SpellEvent::IsDeletable() const
|
||||
return m_Spell->IsDeletable();
|
||||
}
|
||||
|
||||
bool ReflectEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
|
||||
{
|
||||
Unit* target = ObjectAccessor::GetUnit(*_caster, _targetGUID);
|
||||
if (target && _caster->IsInMap(target))
|
||||
Unit::ProcDamageAndSpell(_caster, target, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_REFLECT, 1, BASE_ATTACK, _spellInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Spell::IsValidDeadOrAliveTarget(Unit const* target) const
|
||||
{
|
||||
if (target->IsAlive())
|
||||
@@ -8750,26 +8695,24 @@ void Spell::PrepareTriggersExecutedOnHit()
|
||||
// save auras which were present on spell caster on cast, to prevent triggered auras from affecting caster
|
||||
// and to correctly calculate proc chance when combopoints are present
|
||||
Unit::AuraEffectList const& targetTriggers = m_caster->GetAuraEffectsByType(SPELL_AURA_ADD_TARGET_TRIGGER);
|
||||
for (Unit::AuraEffectList::const_iterator i = targetTriggers.begin(); i != targetTriggers.end(); ++i)
|
||||
for (AuraEffect const* aurEff : targetTriggers)
|
||||
{
|
||||
if (!(*i)->IsAffectedOnSpell(m_spellInfo))
|
||||
if (!aurEff->IsAffectedOnSpell(m_spellInfo))
|
||||
continue;
|
||||
SpellInfo const* auraSpellInfo = (*i)->GetSpellInfo();
|
||||
uint32 auraSpellIdx = (*i)->GetEffIndex();
|
||||
|
||||
SpellInfo const* auraSpellInfo = aurEff->GetSpellInfo();
|
||||
uint32 auraSpellIdx = aurEff->GetEffIndex();
|
||||
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(auraSpellInfo->Effects[auraSpellIdx].TriggerSpell))
|
||||
{
|
||||
// calculate the chance using spell base amount, because aura amount is not updated on combo-points change
|
||||
// this possibly needs fixing
|
||||
int32 auraBaseAmount = (*i)->GetBaseAmount();
|
||||
int32 auraBaseAmount = aurEff->GetBaseAmount();
|
||||
// proc chance is stored in effect amount
|
||||
int32 chance = m_caster->CalculateSpellDamage(nullptr, auraSpellInfo, auraSpellIdx, &auraBaseAmount);
|
||||
chance *= aurEff->GetBase()->GetStackAmount();
|
||||
|
||||
// build trigger and add to the list
|
||||
HitTriggerSpell spellTriggerInfo;
|
||||
spellTriggerInfo.triggeredSpell = spellInfo;
|
||||
spellTriggerInfo.triggeredByAura = auraSpellInfo;
|
||||
spellTriggerInfo.triggeredByEffIdx = (*i)->GetEffIndex();
|
||||
spellTriggerInfo.chance = chance * (*i)->GetBase()->GetStackAmount();
|
||||
m_hitTriggerSpells.push_back(spellTriggerInfo);
|
||||
m_hitTriggerSpells.emplace_back(spellInfo, auraSpellInfo, chance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8814,8 +8757,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);
|
||||
|
||||
// Apply haste rating
|
||||
if (m_spellInfo->StartRecoveryCategory == 133 && m_spellInfo->StartRecoveryTime == 1500 && m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE &&
|
||||
@@ -8824,10 +8767,7 @@ void Spell::TriggerGlobalCooldown()
|
||||
gcd = int32(float(gcd) * m_caster->GetFloatValue(UNIT_MOD_CAST_SPEED));
|
||||
}
|
||||
|
||||
if (gcd < MIN_GCD)
|
||||
gcd = MIN_GCD;
|
||||
else if (gcd > MAX_GCD)
|
||||
gcd = MAX_GCD;
|
||||
RoundToInterval<int32>(gcd, MIN_GCD, MAX_GCD);
|
||||
}
|
||||
|
||||
// Only players or controlled units have global cooldown
|
||||
|
||||
@@ -414,7 +414,7 @@ public:
|
||||
void EffectCastButtons(SpellEffIndex effIndex);
|
||||
void EffectRechargeManaGem(SpellEffIndex effIndex);
|
||||
|
||||
typedef std::set<Aura*> UsedSpellMods;
|
||||
typedef std::unordered_set<Aura*> UsedSpellMods;
|
||||
|
||||
void InitExplicitTargets(SpellCastTargets const& targets);
|
||||
void SelectExplicitTargets();
|
||||
@@ -554,6 +554,8 @@ public:
|
||||
bool IsAutoActionResetSpell() const;
|
||||
bool IsIgnoringCooldowns() const;
|
||||
|
||||
bool IsTriggeredByAura(SpellInfo const* auraSpellInfo) const { return (auraSpellInfo == m_triggeredByAuraSpell.spellInfo); }
|
||||
|
||||
bool IsDeletable() const { return !m_referencedFromCurrentSpell && !m_executedCurrently; }
|
||||
void SetReferencedFromCurrent(bool yes) { m_referencedFromCurrentSpell = yes; }
|
||||
bool IsInterruptable() const { return !m_executedCurrently; }
|
||||
@@ -670,8 +672,8 @@ public:
|
||||
// ******************************************
|
||||
uint32 m_procAttacker; // Attacker trigger flags
|
||||
uint32 m_procVictim; // Victim trigger flags
|
||||
uint32 m_procEx;
|
||||
void prepareDataForTriggerSystem(AuraEffect const* triggeredByAura);
|
||||
uint32 m_hitMask;
|
||||
void prepareDataForTriggerSystem();
|
||||
|
||||
// *****************************************
|
||||
// Spell target subsystem
|
||||
@@ -739,6 +741,9 @@ public:
|
||||
|
||||
struct HitTriggerSpell
|
||||
{
|
||||
HitTriggerSpell(SpellInfo const* spellInfo, SpellInfo const* auraSpellInfo, int32 procChance) :
|
||||
triggeredSpell(spellInfo), triggeredByAura(auraSpellInfo), chance(procChance) { }
|
||||
|
||||
SpellInfo const* triggeredSpell;
|
||||
SpellInfo const* triggeredByAura;
|
||||
uint8 triggeredByEffIdx;
|
||||
@@ -747,7 +752,7 @@ public:
|
||||
|
||||
bool CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByAura = nullptr) const;
|
||||
void PrepareTriggersExecutedOnHit();
|
||||
typedef std::list<HitTriggerSpell> HitTriggerSpellList;
|
||||
typedef std::vector<HitTriggerSpell> HitTriggerSpellList;
|
||||
HitTriggerSpellList m_hitTriggerSpells;
|
||||
|
||||
// effect helpers
|
||||
@@ -838,17 +843,4 @@ namespace Acore
|
||||
}
|
||||
|
||||
typedef void(Spell::*pEffect)(SpellEffIndex effIndex);
|
||||
|
||||
class ReflectEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
ReflectEvent(Unit* caster, ObjectGuid targetGUID, SpellInfo const* spellInfo) : _caster(caster), _targetGUID(targetGUID), _spellInfo(spellInfo) { }
|
||||
bool Execute(uint64 e_time, uint32 p_time) override;
|
||||
|
||||
protected:
|
||||
Unit* _caster;
|
||||
ObjectGuid _targetGUID;
|
||||
SpellInfo const* _spellInfo;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -72,38 +72,38 @@ enum SpellAuraInterruptFlags
|
||||
AURA_INTERRUPT_FLAG_NOT_VICTIM = (AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE | AURA_INTERRUPT_FLAG_DIRECT_DAMAGE),
|
||||
};
|
||||
|
||||
enum SpellModOp
|
||||
enum SpellModOp : uint8
|
||||
{
|
||||
SPELLMOD_DAMAGE = 0,
|
||||
SPELLMOD_DURATION = 1,
|
||||
SPELLMOD_THREAT = 2,
|
||||
SPELLMOD_EFFECT1 = 3,
|
||||
SPELLMOD_CHARGES = 4,
|
||||
SPELLMOD_RANGE = 5,
|
||||
SPELLMOD_RADIUS = 6,
|
||||
SPELLMOD_CRITICAL_CHANCE = 7,
|
||||
SPELLMOD_ALL_EFFECTS = 8,
|
||||
SPELLMOD_NOT_LOSE_CASTING_TIME = 9,
|
||||
SPELLMOD_CASTING_TIME = 10,
|
||||
SPELLMOD_COOLDOWN = 11,
|
||||
SPELLMOD_EFFECT2 = 12,
|
||||
SPELLMOD_IGNORE_ARMOR = 13,
|
||||
SPELLMOD_COST = 14,
|
||||
SPELLMOD_CRIT_DAMAGE_BONUS = 15,
|
||||
SPELLMOD_RESIST_MISS_CHANCE = 16,
|
||||
SPELLMOD_JUMP_TARGETS = 17,
|
||||
SPELLMOD_CHANCE_OF_SUCCESS = 18,
|
||||
SPELLMOD_ACTIVATION_TIME = 19,
|
||||
SPELLMOD_DAMAGE_MULTIPLIER = 20,
|
||||
SPELLMOD_GLOBAL_COOLDOWN = 21,
|
||||
SPELLMOD_DOT = 22,
|
||||
SPELLMOD_EFFECT3 = 23,
|
||||
SPELLMOD_BONUS_MULTIPLIER = 24,
|
||||
SPELLMOD_DAMAGE = 0,
|
||||
SPELLMOD_DURATION = 1,
|
||||
SPELLMOD_THREAT = 2,
|
||||
SPELLMOD_EFFECT1 = 3,
|
||||
SPELLMOD_CHARGES = 4,
|
||||
SPELLMOD_RANGE = 5,
|
||||
SPELLMOD_RADIUS = 6,
|
||||
SPELLMOD_CRITICAL_CHANCE = 7,
|
||||
SPELLMOD_ALL_EFFECTS = 8,
|
||||
SPELLMOD_NOT_LOSE_CASTING_TIME = 9,
|
||||
SPELLMOD_CASTING_TIME = 10,
|
||||
SPELLMOD_COOLDOWN = 11,
|
||||
SPELLMOD_EFFECT2 = 12,
|
||||
SPELLMOD_IGNORE_ARMOR = 13,
|
||||
SPELLMOD_COST = 14,
|
||||
SPELLMOD_CRIT_DAMAGE_BONUS = 15,
|
||||
SPELLMOD_RESIST_MISS_CHANCE = 16,
|
||||
SPELLMOD_JUMP_TARGETS = 17,
|
||||
SPELLMOD_CHANCE_OF_SUCCESS = 18,
|
||||
SPELLMOD_ACTIVATION_TIME = 19,
|
||||
SPELLMOD_DAMAGE_MULTIPLIER = 20,
|
||||
SPELLMOD_GLOBAL_COOLDOWN = 21,
|
||||
SPELLMOD_DOT = 22,
|
||||
SPELLMOD_EFFECT3 = 23,
|
||||
SPELLMOD_BONUS_MULTIPLIER = 24,
|
||||
// spellmod 25
|
||||
SPELLMOD_PROC_PER_MINUTE = 26,
|
||||
SPELLMOD_VALUE_MULTIPLIER = 27,
|
||||
SPELLMOD_RESIST_DISPEL_CHANCE = 28,
|
||||
SPELLMOD_CRIT_DAMAGE_BONUS_2 = 29, //one not used spell
|
||||
SPELLMOD_PROC_PER_MINUTE = 26,
|
||||
SPELLMOD_VALUE_MULTIPLIER = 27,
|
||||
SPELLMOD_RESIST_DISPEL_CHANCE = 28,
|
||||
SPELLMOD_CRIT_DAMAGE_BONUS_2 = 29, //one not used spell
|
||||
SPELLMOD_SPELL_COST_REFUND_ON_FAIL = 30
|
||||
};
|
||||
|
||||
@@ -143,7 +143,7 @@ enum TriggerCastFlags
|
||||
TRIGGERED_IGNORE_CASTER_AURASTATE = 0x00000800, //! Will ignore caster aura states including combat requirements and death state
|
||||
TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE = 0x00002000, //! Will ignore mounted/on vehicle restrictions
|
||||
TRIGGERED_IGNORE_CASTER_AURAS = 0x00010000, //! Will ignore caster aura restrictions or requirements
|
||||
TRIGGERED_DISALLOW_PROC_EVENTS = 0x00020000, //! Disallows proc events from triggered spell (default)
|
||||
// reuse 0x00020000
|
||||
TRIGGERED_DONT_REPORT_CAST_ERROR = 0x00040000, //! Will return SPELL_FAILED_DONT_REPORT in CheckCast functions
|
||||
TRIGGERED_FULL_MASK = 0x0007FFFF, //! Used when doing CastSpell with triggered == true
|
||||
TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT = 0x00080000, //! Will ignore equipped item requirements
|
||||
|
||||
@@ -310,7 +310,7 @@ void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/)
|
||||
unitTarget->ToPlayer()->EnvironmentalDamage(DAMAGE_FIRE, damage);
|
||||
else
|
||||
{
|
||||
DamageInfo dmgInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE);
|
||||
DamageInfo dmgInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK);
|
||||
|
||||
uint32 absorb = dmgInfo.GetAbsorb();
|
||||
uint32 resist = dmgInfo.GetResist();
|
||||
@@ -2342,7 +2342,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
|
||||
|
||||
int32 duration = m_spellInfo->GetDuration();
|
||||
if (Player* modOwner = m_originalCaster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
|
||||
modOwner->ApplySpellMod<SPELLMOD_DURATION>(m_spellInfo->Id, duration);
|
||||
|
||||
TempSummon* summon = nullptr;
|
||||
|
||||
@@ -3148,7 +3148,7 @@ void Spell::EffectSummonPet(SpellEffIndex effIndex)
|
||||
int32 duration = m_spellInfo->GetDuration();
|
||||
|
||||
if(Player* modOwner = m_originalCaster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
|
||||
modOwner->ApplySpellMod<SPELLMOD_DURATION>(m_spellInfo->Id, duration);
|
||||
|
||||
Player* owner = m_originalCaster->ToPlayer();
|
||||
if (!owner && m_originalCaster->ToCreature()->IsTotem())
|
||||
@@ -3722,6 +3722,7 @@ void Spell::EffectInterruptCast(SpellEffIndex effIndex)
|
||||
{
|
||||
int32 duration = m_originalCaster->ModSpellDuration(m_spellInfo, unitTarget, m_originalCaster->CalcSpellDuration(m_spellInfo), false, 1 << effIndex);
|
||||
unitTarget->ProhibitSpellSchool(curSpellInfo->GetSchoolMask(), duration/*spellInfo->GetDuration()*/);
|
||||
m_originalCaster->ProcSkillsAndAuras(unitTarget, PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_HIT, PROC_HIT_INTERRUPT, nullptr, nullptr, nullptr);
|
||||
}
|
||||
ExecuteLogEffectInterruptCast(effIndex, unitTarget, curSpellInfo->Id);
|
||||
unitTarget->InterruptSpell(CurrentSpellTypes(i), false);
|
||||
@@ -4682,18 +4683,17 @@ void Spell::EffectResurrect(SpellEffIndex effIndex)
|
||||
void Spell::EffectAddExtraAttacks(SpellEffIndex effIndex)
|
||||
{
|
||||
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!unitTarget || !unitTarget->IsAlive())
|
||||
{
|
||||
if (!unitTarget || !unitTarget->IsAlive() || !unitTarget->GetVictim())
|
||||
return;
|
||||
}
|
||||
|
||||
unitTarget->AddExtraAttacks(damage);
|
||||
if (unitTarget->m_extraAttacks)
|
||||
return;
|
||||
|
||||
ExecuteLogEffectExtraAttacks(effIndex, unitTarget, damage);
|
||||
unitTarget->m_extraAttacks = damage;
|
||||
|
||||
ExecuteLogEffectExtraAttacks(effIndex, unitTarget->GetVictim(), damage);
|
||||
}
|
||||
|
||||
void Spell::EffectParry(SpellEffIndex /*effIndex*/)
|
||||
@@ -5816,19 +5816,8 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
|
||||
m_runesState = m_caster->ToPlayer()->GetRunesState();
|
||||
|
||||
uint32 count = damage;
|
||||
if (count == 0) count = 1;
|
||||
for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j)
|
||||
{
|
||||
if (player->GetRuneCooldown(j) && player->GetCurrentRune(j) == RuneType(m_spellInfo->Effects[effIndex].MiscValue))
|
||||
{
|
||||
if (m_spellInfo->Id == 45529)
|
||||
if (player->GetBaseRune(j) != RuneType(m_spellInfo->Effects[effIndex].MiscValueB))
|
||||
continue;
|
||||
player->SetRuneCooldown(j, 0);
|
||||
player->SetGracePeriod(j, player->IsInCombat()); // xinef: reset grace period
|
||||
--count;
|
||||
}
|
||||
}
|
||||
if (count == 0)
|
||||
count = 1;
|
||||
|
||||
// Blood Tap
|
||||
if (m_spellInfo->Id == 45529 && count > 0)
|
||||
@@ -5836,10 +5825,10 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
|
||||
for (uint32 l = 0; l < MAX_RUNES && count > 0; ++l)
|
||||
{
|
||||
// Check if both runes are on cd as that is the only time when this needs to come into effect
|
||||
if ((player->GetRuneCooldown(l) && player->GetCurrentRune(l) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB)) && (player->GetRuneCooldown(l + 1) && player->GetCurrentRune(l + 1) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB)))
|
||||
if ((player->GetRuneCooldown(l) && player->GetCurrentRune(l) == RUNE_BLOOD) && (player->GetRuneCooldown(l + 1) && player->GetCurrentRune(l + 1) == RUNE_BLOOD))
|
||||
{
|
||||
// Should always update the rune with the lowest cd
|
||||
if (player->GetRuneCooldown(l) >= player->GetRuneCooldown(l + 1))
|
||||
if (l + 1 < MAX_RUNES && player->GetRuneCooldown(l) >= player->GetRuneCooldown(l + 1))
|
||||
l++;
|
||||
player->SetRuneCooldown(l, 0);
|
||||
player->SetGracePeriod(l, player->IsInCombat()); // xinef: reset grace period
|
||||
@@ -5850,6 +5839,15 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j)
|
||||
{
|
||||
if (player->GetRuneCooldown(j) && player->GetCurrentRune(j) == RuneType(m_spellInfo->Effects[effIndex].MiscValue))
|
||||
{
|
||||
player->SetRuneCooldown(j, 0);
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
// Empower rune weapon
|
||||
if (m_spellInfo->Id == 47568)
|
||||
{
|
||||
@@ -5859,7 +5857,7 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
|
||||
|
||||
for (uint32 i = 0; i < MAX_RUNES; ++i)
|
||||
{
|
||||
if (player->GetRuneCooldown(i) && (player->GetCurrentRune(i) == RUNE_FROST || player->GetCurrentRune(i) == RUNE_DEATH))
|
||||
if (player->GetRuneCooldown(i) && (player->GetCurrentRune(i) == RUNE_FROST))
|
||||
{
|
||||
player->SetRuneCooldown(i, 0);
|
||||
player->SetGracePeriod(i, player->IsInCombat()); // xinef: reset grace period
|
||||
@@ -6061,7 +6059,7 @@ void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const*
|
||||
int32 duration = m_spellInfo->GetDuration();
|
||||
|
||||
if (Player* modOwner = m_originalCaster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
|
||||
modOwner->ApplySpellMod<SPELLMOD_DURATION>(m_spellInfo->Id, duration);
|
||||
|
||||
//TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
|
||||
Map* map = caster->GetMap();
|
||||
|
||||
@@ -524,7 +524,7 @@ float SpellEffectInfo::CalcValueMultiplier(Unit* caster, Spell* spell) const
|
||||
{
|
||||
float multiplier = ValueMultiplier;
|
||||
if (Player* modOwner = (caster ? caster->GetSpellModOwner() : nullptr))
|
||||
modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_VALUE_MULTIPLIER, multiplier, spell);
|
||||
modOwner->ApplySpellMod<SPELLMOD_VALUE_MULTIPLIER>(_spellInfo->Id, multiplier, spell);
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
@@ -532,7 +532,7 @@ float SpellEffectInfo::CalcDamageMultiplier(Unit* caster, Spell* spell) const
|
||||
{
|
||||
float multiplier = DamageMultiplier;
|
||||
if (Player* modOwner = (caster ? caster->GetSpellModOwner() : nullptr))
|
||||
modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_DAMAGE_MULTIPLIER, multiplier, spell);
|
||||
modOwner->ApplySpellMod<SPELLMOD_DAMAGE_MULTIPLIER>(_spellInfo->Id, multiplier, spell);
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
@@ -552,7 +552,7 @@ float SpellEffectInfo::CalcRadius(Unit* caster, Spell* spell) const
|
||||
radius += RadiusEntry->RadiusPerLevel * caster->getLevel();
|
||||
radius = std::min(radius, RadiusEntry->RadiusMax);
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_RADIUS, radius, spell);
|
||||
modOwner->ApplySpellMod<SPELLMOD_RADIUS>(_spellInfo->Id, radius, spell);
|
||||
}
|
||||
|
||||
return radius;
|
||||
@@ -831,7 +831,7 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry)
|
||||
SpellVisual = spellEntry->SpellVisual;
|
||||
SpellIconID = spellEntry->SpellIconID;
|
||||
ActiveIconID = spellEntry->ActiveIconID;
|
||||
SpellPriority = spellEntry->SpellPriority;
|
||||
Priority = spellEntry->SpellPriority;
|
||||
SpellName = spellEntry->SpellName;
|
||||
Rank = spellEntry->Rank;
|
||||
MaxTargetLevel = spellEntry->MaxTargetLevel;
|
||||
@@ -1268,6 +1268,26 @@ bool SpellInfo::IsAutoRepeatRangedSpell() const
|
||||
return AttributesEx2 & SPELL_ATTR2_AUTO_REPEAT;
|
||||
}
|
||||
|
||||
bool SpellInfo::IsAffected(uint32 familyName, flag96 const& familyFlags) const
|
||||
{
|
||||
if (!familyName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (familyName != SpellFamilyName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (familyFlags && !(familyFlags & SpellFamilyFlags))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SpellInfo::IsAffectedBySpellMods() const
|
||||
{
|
||||
return !(AttributesEx3 & SPELL_ATTR3_IGNORE_CASTER_MODIFIERS);
|
||||
@@ -1292,15 +1312,7 @@ bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const
|
||||
return true;
|
||||
}
|
||||
|
||||
// False if affect_spell == nullptr or spellFamily not equal
|
||||
if (affectSpell->SpellFamilyName != SpellFamilyName)
|
||||
return false;
|
||||
|
||||
// true
|
||||
if (mod->mask & SpellFamilyFlags)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return IsAffected(affectSpell->SpellFamilyName, mod->mask);
|
||||
}
|
||||
|
||||
bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const
|
||||
@@ -2311,7 +2323,7 @@ float SpellInfo::GetMaxRange(bool positive, Unit* caster, Spell* spell) const
|
||||
range = RangeEntry->RangeMax[0];
|
||||
if (caster)
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(Id, SPELLMOD_RANGE, range, spell);
|
||||
modOwner->ApplySpellMod<SPELLMOD_RANGE>(Id, range, spell);
|
||||
return range;
|
||||
}
|
||||
|
||||
@@ -2446,7 +2458,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S
|
||||
|
||||
// Apply cost mod by spell
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(Id, SPELLMOD_COST, powerCost, spell);
|
||||
modOwner->ApplySpellMod<SPELLMOD_COST>(Id, powerCost, spell);
|
||||
|
||||
if (!caster->IsControlledByPlayer())
|
||||
{
|
||||
|
||||
@@ -377,7 +377,7 @@ public:
|
||||
std::array<uint32, 2> SpellVisual;
|
||||
uint32 SpellIconID;
|
||||
uint32 ActiveIconID;
|
||||
uint32 SpellPriority;
|
||||
uint32 Priority;
|
||||
std::array<char const*, 16> SpellName;
|
||||
std::array<char const*, 16> Rank;
|
||||
uint32 MaxTargetLevel;
|
||||
@@ -463,6 +463,8 @@ public:
|
||||
bool IsRangedWeaponSpell() const;
|
||||
bool IsAutoRepeatRangedSpell() const;
|
||||
|
||||
bool IsAffected(uint32 familyName, flag96 const& familyFlags) const;
|
||||
|
||||
bool IsAffectedBySpellMods() const;
|
||||
bool IsAffectedBySpellMod(SpellModifier const* mod) const;
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
53232, // Rapid Killing (Rank 2)
|
||||
}, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_FROM_PROCS; // Entries were not updated after spell effect change, we have to do that manually
|
||||
spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED; // Entries were not updated after spell effect change, we have to do that manually
|
||||
});
|
||||
|
||||
ApplySpellFix({
|
||||
@@ -257,7 +257,7 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
ApplySpellFix({ 57761 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->ProcCharges = 1;
|
||||
spellInfo->SpellPriority = 50;
|
||||
spellInfo->Priority = 50;
|
||||
});
|
||||
|
||||
// Tidal Wave
|
||||
@@ -272,10 +272,10 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->AttributesEx3 |= SPELL_ATTR3_DOT_STACKING_RULE;
|
||||
});
|
||||
|
||||
// Ascendance (Talisman of Ascendance trinket)
|
||||
ApplySpellFix({ 28200 }, [](SpellInfo* spellInfo)
|
||||
// Death and Decay
|
||||
ApplySpellFix({ 52212 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->ProcCharges = 6;
|
||||
spellInfo->AttributesEx6 |= SPELL_ATTR6_IGNORE_PHASE_SHIFT;
|
||||
});
|
||||
|
||||
// The Eye of Acherus (no spawn in phase 2 in db)
|
||||
|
||||
@@ -727,166 +727,6 @@ void SpellMgr::GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpe
|
||||
availableElixirs.insert(itr->first); // insert spell id
|
||||
}
|
||||
|
||||
SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const
|
||||
{
|
||||
SpellProcEventMap::const_iterator itr = mSpellProcEventMap.find(spellId);
|
||||
if (itr != mSpellProcEventMap.end())
|
||||
return &itr->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, ProcEventInfo const& eventInfo, bool active) const
|
||||
{
|
||||
// No extra req need
|
||||
uint32 procEvent_procEx = PROC_EX_NONE;
|
||||
uint32 procEvent_procPhase = PROC_SPELL_PHASE_HIT;
|
||||
|
||||
uint32 procFlags = eventInfo.GetTypeMask();
|
||||
uint32 procExtra = eventInfo.GetHitMask();
|
||||
uint32 procPhase = eventInfo.GetSpellPhaseMask();
|
||||
SpellInfo const* procSpellInfo = eventInfo.GetSpellInfo();
|
||||
|
||||
// check prockFlags for condition
|
||||
if ((procFlags & EventProcFlag) == 0)
|
||||
return false;
|
||||
|
||||
// Xinef: Always trigger for this, including TAKEN_DAMAGE
|
||||
if (EventProcFlag & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH | PROC_FLAG_TAKEN_DAMAGE))
|
||||
return true;
|
||||
|
||||
bool hasFamilyMask = false;
|
||||
|
||||
if (procFlags & PROC_FLAG_DONE_PERIODIC)
|
||||
{
|
||||
if (procExtra & PROC_EX_INTERNAL_HOT)
|
||||
{
|
||||
if (EventProcFlag == PROC_FLAG_DONE_PERIODIC)
|
||||
{
|
||||
/// no aura with only PROC_FLAG_DONE_PERIODIC and spellFamilyName == 0 can proc from a HOT.
|
||||
if (!spellProto->SpellFamilyName)
|
||||
return false;
|
||||
}
|
||||
/// Aura must have positive procflags for a HOT to proc
|
||||
else if (!(EventProcFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS)))
|
||||
return false;
|
||||
}
|
||||
/// Aura must have negative or neutral(PROC_FLAG_DONE_PERIODIC only) procflags for a DOT to proc
|
||||
else if (EventProcFlag != PROC_FLAG_DONE_PERIODIC)
|
||||
if (!(EventProcFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG | PROC_FLAG_DONE_TRAP_ACTIVATION)))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (procFlags & PROC_FLAG_TAKEN_PERIODIC)
|
||||
{
|
||||
if (procExtra & PROC_EX_INTERNAL_HOT)
|
||||
{
|
||||
/// No aura that only has PROC_FLAG_TAKEN_PERIODIC can proc from a HOT.
|
||||
if (EventProcFlag == PROC_FLAG_TAKEN_PERIODIC)
|
||||
return false;
|
||||
/// Aura must have positive procflags for a HOT to proc
|
||||
if (!(EventProcFlag & (PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS)))
|
||||
return false;
|
||||
}
|
||||
/// Aura must have negative or neutral(PROC_FLAG_TAKEN_PERIODIC only) procflags for a DOT to proc
|
||||
else if (EventProcFlag != PROC_FLAG_TAKEN_PERIODIC)
|
||||
if (!(EventProcFlag & (PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG)))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Trap casts are active by default
|
||||
if (procFlags & PROC_FLAG_DONE_TRAP_ACTIVATION)
|
||||
active = true;
|
||||
|
||||
if (spellProcEvent) // Exist event data
|
||||
{
|
||||
// Store extra req
|
||||
procEvent_procEx = spellProcEvent->procEx;
|
||||
procEvent_procPhase = spellProcEvent->procPhase;
|
||||
|
||||
// For melee triggers
|
||||
if (!procSpellInfo)
|
||||
{
|
||||
// Check (if set) for school (melee attack have Normal school)
|
||||
if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
|
||||
return false;
|
||||
}
|
||||
else // For spells need check school/spell family/family mask
|
||||
{
|
||||
// Check (if set) for school
|
||||
if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & procSpellInfo->SchoolMask) == 0)
|
||||
return false;
|
||||
|
||||
// Check (if set) for spellFamilyName
|
||||
if (spellProcEvent->spellFamilyName && (spellProcEvent->spellFamilyName != procSpellInfo->SpellFamilyName))
|
||||
return false;
|
||||
|
||||
// spellFamilyName is Ok need check for spellFamilyMask if present
|
||||
if (spellProcEvent->spellFamilyMask)
|
||||
{
|
||||
if (!(spellProcEvent->spellFamilyMask & procSpellInfo->SpellFamilyFlags))
|
||||
return false;
|
||||
hasFamilyMask = true;
|
||||
// Some spells are not considered as active even with have spellfamilyflags
|
||||
if (!(procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL))
|
||||
active = true;
|
||||
}
|
||||
|
||||
// Check tick numbers
|
||||
if (procEvent_procEx & PROC_EX_ONLY_FIRST_TICK)
|
||||
{
|
||||
if (Spell const* procSpell = eventInfo.GetProcSpell())
|
||||
{
|
||||
if (procSpell->GetTriggeredByAuraTickNumber() > 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (procExtra & (PROC_EX_INTERNAL_REQ_FAMILY))
|
||||
{
|
||||
if (!hasFamilyMask)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(procEvent_procPhase & procPhase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for extra req (if none) and hit/crit
|
||||
if (procEvent_procEx == PROC_EX_NONE)
|
||||
{
|
||||
// No extra req, so can trigger only for hit/crit - spell has to be active
|
||||
if ((procExtra & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) && active)
|
||||
return true;
|
||||
}
|
||||
else // Passive spells hits here only if resist/reflect/immune/evade
|
||||
{
|
||||
if (procExtra & AURA_SPELL_PROC_EX_MASK)
|
||||
{
|
||||
// if spell marked as procing only from not active spells
|
||||
if (active && procEvent_procEx & PROC_EX_NOT_ACTIVE_SPELL)
|
||||
return false;
|
||||
// if spell marked as procing only from active spells
|
||||
if (!active && procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL)
|
||||
return false;
|
||||
// Exist req for PROC_EX_EX_TRIGGER_ALWAYS
|
||||
if (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS)
|
||||
return true;
|
||||
// PROC_EX_NOT_ACTIVE_SPELL and PROC_EX_ONLY_ACTIVE_SPELL flags handle: if passed checks before
|
||||
if ((procExtra & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) && ((procEvent_procEx & (AURA_SPELL_PROC_EX_MASK)) == 0))
|
||||
return true;
|
||||
}
|
||||
// Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other)
|
||||
if (procEvent_procEx & procExtra)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const
|
||||
{
|
||||
SpellProcMap::const_iterator itr = mSpellProcMap.find(spellId);
|
||||
@@ -895,54 +735,78 @@ SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const
|
||||
bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo)
|
||||
{
|
||||
// proc type doesn't match
|
||||
if (!(eventInfo.GetTypeMask() & procEntry.typeMask))
|
||||
if (!(eventInfo.GetTypeMask() & procEntry.ProcFlags))
|
||||
return false;
|
||||
|
||||
// check XP or honor target requirement
|
||||
if (procEntry.attributesMask & PROC_ATTR_REQ_EXP_OR_HONOR)
|
||||
if (procEntry.AttributesMask & PROC_ATTR_REQ_EXP_OR_HONOR)
|
||||
if (Player* actor = eventInfo.GetActor()->ToPlayer())
|
||||
if (eventInfo.GetActionTarget() && !actor->isHonorOrXPTarget(eventInfo.GetActionTarget()))
|
||||
return false;
|
||||
|
||||
// check mana requirement
|
||||
if (procEntry.AttributesMask & PROC_ATTR_REQ_MANA_COST)
|
||||
if (SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo())
|
||||
if (!eventSpellInfo->ManaCost && !eventSpellInfo->ManaCostPercentage)
|
||||
return false;
|
||||
|
||||
// always trigger for these types
|
||||
if (eventInfo.GetTypeMask() & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH))
|
||||
return true;
|
||||
|
||||
// do triggered cast checks
|
||||
// Do not consider autoattacks as triggered spells
|
||||
if (!(procEntry.AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC) && !(eventInfo.GetTypeMask() & AUTO_ATTACK_PROC_FLAG_MASK))
|
||||
{
|
||||
if (Spell const* spell = eventInfo.GetProcSpell())
|
||||
{
|
||||
if (spell->IsTriggered())
|
||||
{
|
||||
SpellInfo const* spellInfo = spell->GetSpellInfo();
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2) &&
|
||||
!spellInfo->HasAttribute(SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check school mask (if set) for other trigger types
|
||||
if (procEntry.schoolMask && !(eventInfo.GetSchoolMask() & procEntry.schoolMask))
|
||||
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 (eventInfo.GetTypeMask() & (PERIODIC_PROC_FLAG_MASK | SPELL_PROC_FLAG_MASK))
|
||||
{
|
||||
if (procEntry.spellFamilyName && (procEntry.spellFamilyName != eventInfo.GetSpellInfo()->SpellFamilyName))
|
||||
return false;
|
||||
|
||||
if (procEntry.spellFamilyMask && !(procEntry.spellFamilyMask & eventInfo.GetSpellInfo()->SpellFamilyFlags))
|
||||
return false;
|
||||
if (SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo())
|
||||
{
|
||||
if (!eventSpellInfo->IsAffected(procEntry.SpellFamilyName, procEntry.SpellFamilyMask))
|
||||
{
|
||||
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))
|
||||
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))
|
||||
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;
|
||||
uint32 hitMask = procEntry.HitMask;
|
||||
// get default values if hit mask not set
|
||||
if (!hitMask)
|
||||
{
|
||||
@@ -1733,111 +1597,17 @@ void SpellMgr::LoadSpellGroupStackRules()
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
void SpellMgr::LoadSpellProcEvents()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
mSpellProcEventMap.clear(); // need for reload case
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11
|
||||
QueryResult result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, procFlags, procEx, procPhase, ppmRate, CustomChance, Cooldown FROM spell_proc_event");
|
||||
if (!result)
|
||||
{
|
||||
LOG_WARN("server.loading", ">> Loaded 0 spell proc event conditions. DB table `spell_proc_event` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
int32 spellId = fields[0].Get<int32>();
|
||||
|
||||
bool allRanks = false;
|
||||
if (spellId < 0)
|
||||
{
|
||||
allRanks = true;
|
||||
spellId = -spellId;
|
||||
}
|
||||
|
||||
SpellInfo const* spellInfo = GetSpellInfo(spellId);
|
||||
if (!spellInfo)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` does not exist", spellId);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (allRanks)
|
||||
{
|
||||
if (!spellInfo->IsRanked())
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` with all ranks, but spell has no ranks.", spellId);
|
||||
|
||||
if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` is not first rank of spell.", spellId);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
SpellProcEventEntry spellProcEvent;
|
||||
|
||||
spellProcEvent.schoolMask = fields[1].Get<int8>();
|
||||
spellProcEvent.spellFamilyName = fields[2].Get<uint16>();
|
||||
spellProcEvent.spellFamilyMask[0] = fields[3].Get<uint32>();
|
||||
spellProcEvent.spellFamilyMask[1] = fields[4].Get<uint32>();
|
||||
spellProcEvent.spellFamilyMask[2] = fields[5].Get<uint32>();
|
||||
spellProcEvent.procFlags = fields[6].Get<uint32>();
|
||||
spellProcEvent.procEx = fields[7].Get<uint32>();
|
||||
spellProcEvent.procPhase = fields[8].Get<uint32>();
|
||||
spellProcEvent.ppmRate = fields[9].Get<float>();
|
||||
spellProcEvent.customChance = fields[10].Get<float>();
|
||||
spellProcEvent.cooldown = fields[11].Get<uint32>();
|
||||
|
||||
// PROC_SPELL_PHASE_NONE is by default PROC_SPELL_PHASE_HIT
|
||||
if (spellProcEvent.procPhase == PROC_SPELL_PHASE_NONE)
|
||||
{
|
||||
spellProcEvent.procPhase = PROC_SPELL_PHASE_HIT;
|
||||
}
|
||||
|
||||
while (spellInfo)
|
||||
{
|
||||
if (mSpellProcEventMap.find(spellInfo->Id) != mSpellProcEventMap.end())
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` already has its first rank in table.", spellInfo->Id);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!spellInfo->ProcFlags && !spellProcEvent.procFlags)
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` probally not triggered spell", spellInfo->Id);
|
||||
|
||||
mSpellProcEventMap[spellInfo->Id] = spellProcEvent;
|
||||
|
||||
if (allRanks)
|
||||
spellInfo = spellInfo->GetNextRankSpell();
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} Extra Spell Proc Event Conditions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
void SpellMgr::LoadSpellProcs()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
mSpellProcMap.clear(); // need for reload case
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
||||
QueryResult result = WorldDatabase.Query("SELECT spellId, schoolMask, spellFamilyName, spellFamilyMask0, spellFamilyMask1, spellFamilyMask2, typeMask, spellTypeMask, spellPhaseMask, hitMask, attributesMask, ratePerMinute, chance, cooldown, charges FROM spell_proc");
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
||||
QueryResult result = WorldDatabase.Query("SELECT SpellId, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, ProcFlags, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc");
|
||||
if (!result)
|
||||
{
|
||||
LOG_WARN("server.loading", ">> Loaded 0 Spell Proc Conditions And Data. DB table `spell_proc` Is Empty.");
|
||||
LOG_INFO("server.loading", ">> Loaded 0 spell proc conditions and data. DB table `spell_proc` is empty.");
|
||||
LOG_INFO("server.loading", " ");
|
||||
return;
|
||||
}
|
||||
@@ -1874,21 +1644,20 @@ void SpellMgr::LoadSpellProcs()
|
||||
|
||||
SpellProcEntry baseProcEntry;
|
||||
|
||||
baseProcEntry.schoolMask = fields[1].Get<int8>();
|
||||
baseProcEntry.spellFamilyName = fields[2].Get<uint16>();
|
||||
baseProcEntry.spellFamilyMask[0] = fields[3].Get<uint32>();
|
||||
baseProcEntry.spellFamilyMask[1] = fields[4].Get<uint32>();
|
||||
baseProcEntry.spellFamilyMask[2] = fields[5].Get<uint32>();
|
||||
baseProcEntry.typeMask = fields[6].Get<uint32>();
|
||||
baseProcEntry.spellTypeMask = fields[7].Get<uint32>();
|
||||
baseProcEntry.spellPhaseMask = fields[8].Get<uint32>();
|
||||
baseProcEntry.hitMask = fields[9].Get<uint32>();
|
||||
baseProcEntry.attributesMask = fields[10].Get<uint32>();
|
||||
baseProcEntry.ratePerMinute = fields[11].Get<float>();
|
||||
baseProcEntry.chance = fields[12].Get<float>();
|
||||
float cooldown = fields[13].Get<float>();
|
||||
baseProcEntry.cooldown = uint32(cooldown);
|
||||
baseProcEntry.charges = fields[14].Get<uint32>();
|
||||
baseProcEntry.SchoolMask = fields[1].Get<int8>();
|
||||
baseProcEntry.SpellFamilyName = fields[2].Get<uint16>();
|
||||
baseProcEntry.SpellFamilyMask[0] = fields[3].Get<uint32>();
|
||||
baseProcEntry.SpellFamilyMask[1] = fields[4].Get<uint32>();
|
||||
baseProcEntry.SpellFamilyMask[2] = fields[5].Get<uint32>();
|
||||
baseProcEntry.ProcFlags = fields[6].Get<uint32>();
|
||||
baseProcEntry.SpellTypeMask = fields[7].Get<uint32>();
|
||||
baseProcEntry.SpellPhaseMask = fields[8].Get<uint32>();
|
||||
baseProcEntry.HitMask = fields[9].Get<uint32>();
|
||||
baseProcEntry.AttributesMask = fields[10].Get<uint32>();
|
||||
baseProcEntry.ProcsPerMinute = fields[11].Get<float>();
|
||||
baseProcEntry.Chance = fields[12].Get<float>();
|
||||
baseProcEntry.Cooldown = Milliseconds(fields[13].Get<uint32>());
|
||||
baseProcEntry.Charges = fields[14].Get<uint8>();
|
||||
|
||||
while (spellInfo)
|
||||
{
|
||||
@@ -1900,56 +1669,54 @@ void SpellMgr::LoadSpellProcs()
|
||||
SpellProcEntry procEntry = SpellProcEntry(baseProcEntry);
|
||||
|
||||
// take defaults from dbcs
|
||||
if (!procEntry.typeMask)
|
||||
procEntry.typeMask = spellInfo->ProcFlags;
|
||||
if (!procEntry.charges)
|
||||
procEntry.charges = spellInfo->ProcCharges;
|
||||
if (!procEntry.chance && !procEntry.ratePerMinute)
|
||||
procEntry.chance = float(spellInfo->ProcChance);
|
||||
if (!procEntry.ProcFlags)
|
||||
procEntry.ProcFlags = spellInfo->ProcFlags;
|
||||
if (!procEntry.Charges)
|
||||
procEntry.Charges = spellInfo->ProcCharges;
|
||||
if (!procEntry.Chance && !procEntry.ProcsPerMinute)
|
||||
procEntry.Chance = float(spellInfo->ProcChance);
|
||||
|
||||
// validate data
|
||||
if (procEntry.schoolMask & ~SPELL_SCHOOL_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `schoolMask` set: {}", spellId, procEntry.schoolMask);
|
||||
if (procEntry.spellFamilyName && (procEntry.spellFamilyName < 3 || procEntry.spellFamilyName > 17 || procEntry.spellFamilyName == 14 || procEntry.spellFamilyName == 16))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellFamilyName` set: {}", spellId, procEntry.spellFamilyName);
|
||||
if (procEntry.chance < 0)
|
||||
if (procEntry.SchoolMask & ~SPELL_SCHOOL_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SchoolMask` set: {}", spellId, procEntry.SchoolMask);
|
||||
if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName < 3 || procEntry.SpellFamilyName > 17 || procEntry.SpellFamilyName == 14 || procEntry.SpellFamilyName == 16))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellFamilyName` set: {}", spellId, procEntry.SpellFamilyName);
|
||||
if (procEntry.Chance < 0)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `chance` field", spellId);
|
||||
procEntry.chance = 0;
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has negative value in `Chance` field", spellId);
|
||||
procEntry.Chance = 0;
|
||||
}
|
||||
if (procEntry.ratePerMinute < 0)
|
||||
if (procEntry.ProcsPerMinute < 0)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `ratePerMinute` field", spellId);
|
||||
procEntry.ratePerMinute = 0;
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has negative value in `ProcsPerMinute` field", spellId);
|
||||
procEntry.ProcsPerMinute = 0;
|
||||
}
|
||||
if (cooldown < 0)
|
||||
if (procEntry.Chance == 0 && procEntry.ProcsPerMinute == 0)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `Chance` and `ProcsPerMinute` values defined, proc will not be triggered", spellId);
|
||||
if (procEntry.Charges > 99)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `cooldown` field", spellId);
|
||||
procEntry.cooldown = 0;
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has too big value in `Charges` field", spellId);
|
||||
procEntry.Charges = 99;
|
||||
}
|
||||
if (procEntry.chance == 0 && procEntry.ratePerMinute == 0)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `chance` and `ratePerMinute` values defined, proc will not be triggered", spellId);
|
||||
if (procEntry.charges > 99)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has too big value in `charges` field", spellId);
|
||||
procEntry.charges = 99;
|
||||
}
|
||||
if (!procEntry.typeMask)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `typeMask` value defined, proc will not be triggered", spellId);
|
||||
if (procEntry.spellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellTypeMask` set: {}", spellId, procEntry.spellTypeMask);
|
||||
if (procEntry.spellTypeMask && !(procEntry.typeMask & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} 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)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `spellPhaseMask` value defined, but it's required for defined `typeMask` value, proc will not be triggered", spellId);
|
||||
if (procEntry.spellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellPhaseMask` set: {}", spellId, procEntry.spellPhaseMask);
|
||||
if (procEntry.spellPhaseMask && !(procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `spellPhaseMask` value defined, but it won't be used for defined `typeMask` value", spellId);
|
||||
if (procEntry.hitMask & ~PROC_HIT_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `hitMask` set: {}", spellId, procEntry.hitMask);
|
||||
if (procEntry.hitMask && !(procEntry.typeMask & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.typeMask & DONE_HIT_PROC_FLAG_MASK && (!procEntry.spellPhaseMask || procEntry.spellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH)))))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `hitMask` value defined, but it won't be used for defined `typeMask` and `spellPhaseMask` values", spellId);
|
||||
if (!procEntry.ProcFlags)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `ProcFlags` value defined, proc will not be triggered", spellId);
|
||||
if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellTypeMask` set: {}", spellId, procEntry.SpellTypeMask);
|
||||
if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `SpellTypeMask` value defined, but it won't be used for defined `ProcFlags` value", spellId);
|
||||
if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `SpellPhaseMask` value defined, but it's required for defined `ProcFlags` value, proc will not be triggered", spellId);
|
||||
if (procEntry.SpellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellPhaseMask` set: {}", spellId, procEntry.SpellPhaseMask);
|
||||
if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `SpellPhaseMask` value defined, but it won't be used for defined `ProcFlags` value", spellId);
|
||||
if (procEntry.HitMask & ~PROC_HIT_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `HitMask` set: {}", spellId, procEntry.HitMask);
|
||||
if (procEntry.HitMask && !(procEntry.ProcFlags & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.ProcFlags & DONE_HIT_PROC_FLAG_MASK && (!procEntry.SpellPhaseMask || procEntry.SpellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH)))))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `HitMask` value defined, but it won't be used for defined `ProcFlags` and `SpellPhaseMask` values", spellId);
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
if ((procEntry.AttributesMask & (PROC_ATTR_DISABLE_EFF_0 << i)) && !spellInfo->Effects[i].IsAura())
|
||||
LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has Attribute PROC_ATTR_DISABLE_EFF_{}, but effect {} is not an aura effect", spellInfo->Id, static_cast<uint32>(i), static_cast<uint32>(i));
|
||||
|
||||
mSpellProcMap[spellInfo->Id] = procEntry;
|
||||
|
||||
@@ -1961,8 +1728,175 @@ void SpellMgr::LoadSpellProcs()
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} spell proc conditions and data in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", ">> Loaded {} Extra Spell Proc Event Conditions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
|
||||
// Define can trigger auras
|
||||
bool isTriggerAura[TOTAL_AURAS];
|
||||
// Triggered always, even from triggered spells
|
||||
bool isAlwaysTriggeredAura[TOTAL_AURAS];
|
||||
// SpellTypeMask to add to the proc
|
||||
uint32 spellTypeMask[TOTAL_AURAS];
|
||||
|
||||
// List of auras that CAN trigger but may not exist in spell_proc
|
||||
// in most cases needed to drop charges
|
||||
|
||||
// some aura types need additional checks (eg SPELL_AURA_MECHANIC_IMMUNITY needs mechanic check)
|
||||
// see AuraEffect::CheckEffectProc
|
||||
for (uint16 i = 0; i < TOTAL_AURAS; ++i)
|
||||
{
|
||||
isTriggerAura[i] = false;
|
||||
isAlwaysTriggeredAura[i] = false;
|
||||
spellTypeMask[i] = PROC_SPELL_TYPE_MASK_ALL;
|
||||
}
|
||||
|
||||
isTriggerAura[SPELL_AURA_DUMMY] = true; // Most dummy auras should require scripting, but there are some exceptions (ie 12311)
|
||||
isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true; // "Any direct damaging attack will revive targets"
|
||||
isTriggerAura[SPELL_AURA_MOD_THREAT] = true; // Only one spell: 28762 part of Mage T3 8p bonus
|
||||
isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura does not have charges but needs to be removed on trigger
|
||||
isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true;
|
||||
isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true;
|
||||
isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true;
|
||||
isTriggerAura[SPELL_AURA_MOD_STEALTH] = true;
|
||||
isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura does not have charges but needs to be removed on trigger
|
||||
isTriggerAura[SPELL_AURA_MOD_ROOT] = true;
|
||||
isTriggerAura[SPELL_AURA_TRANSFORM] = true;
|
||||
isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true;
|
||||
isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true;
|
||||
isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true;
|
||||
isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true;
|
||||
isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK] = true;
|
||||
isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true;
|
||||
isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true;
|
||||
isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true;
|
||||
isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true;
|
||||
isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true;
|
||||
isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true;
|
||||
isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
|
||||
isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE] = true;
|
||||
isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE] = true;
|
||||
isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE] = true;
|
||||
isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE] = true;
|
||||
isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true;
|
||||
isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true;
|
||||
isTriggerAura[SPELL_AURA_ADD_FLAT_MODIFIER] = true;
|
||||
isTriggerAura[SPELL_AURA_ADD_PCT_MODIFIER] = true;
|
||||
isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true;
|
||||
|
||||
isAlwaysTriggeredAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
|
||||
isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true;
|
||||
isAlwaysTriggeredAura[SPELL_AURA_MOD_CONFUSE] = true;
|
||||
isAlwaysTriggeredAura[SPELL_AURA_MOD_FEAR] = true;
|
||||
isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT] = true;
|
||||
isAlwaysTriggeredAura[SPELL_AURA_MOD_STUN] = true;
|
||||
isAlwaysTriggeredAura[SPELL_AURA_TRANSFORM] = true;
|
||||
|
||||
spellTypeMask[SPELL_AURA_MOD_STEALTH] = PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL;
|
||||
spellTypeMask[SPELL_AURA_MOD_CONFUSE] = PROC_SPELL_TYPE_DAMAGE;
|
||||
spellTypeMask[SPELL_AURA_MOD_FEAR] = PROC_SPELL_TYPE_DAMAGE;
|
||||
spellTypeMask[SPELL_AURA_MOD_ROOT] = PROC_SPELL_TYPE_DAMAGE;
|
||||
spellTypeMask[SPELL_AURA_MOD_STUN] = PROC_SPELL_TYPE_DAMAGE;
|
||||
spellTypeMask[SPELL_AURA_TRANSFORM] = PROC_SPELL_TYPE_DAMAGE;
|
||||
|
||||
// This generates default procs to retain compatibility with previous proc system
|
||||
LOG_INFO("server.loading", "Generating spell proc data from SpellMap...");
|
||||
count = 0;
|
||||
oldMSTime = getMSTime();
|
||||
|
||||
for (SpellInfo const* spellInfo : mSpellInfoMap)
|
||||
{
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
// Data already present in DB, overwrites default proc
|
||||
if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
|
||||
continue;
|
||||
|
||||
// Nothing to do if no flags set
|
||||
if (!spellInfo->ProcFlags)
|
||||
continue;
|
||||
|
||||
bool addTriggerFlag = false;
|
||||
uint32 procSpellTypeMask = PROC_SPELL_TYPE_NONE;
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (!spellInfo->Effects[i].IsEffect())
|
||||
continue;
|
||||
|
||||
uint32 auraName = spellInfo->Effects[i].ApplyAuraName;
|
||||
if (!auraName)
|
||||
continue;
|
||||
|
||||
if (!isTriggerAura[auraName])
|
||||
continue;
|
||||
|
||||
procSpellTypeMask |= spellTypeMask[auraName];
|
||||
|
||||
if (isAlwaysTriggeredAura[auraName])
|
||||
addTriggerFlag = true;
|
||||
|
||||
// many proc auras with taken procFlag mask don't have attribute "can proc with triggered"
|
||||
// they should proc nevertheless (example mage armor spells with judgement)
|
||||
if (!addTriggerFlag && (spellInfo->ProcFlags & TAKEN_HIT_PROC_FLAG_MASK) != 0)
|
||||
{
|
||||
switch (auraName)
|
||||
{
|
||||
case SPELL_AURA_PROC_TRIGGER_SPELL:
|
||||
case SPELL_AURA_PROC_TRIGGER_DAMAGE:
|
||||
addTriggerFlag = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!procSpellTypeMask)
|
||||
continue;
|
||||
|
||||
SpellProcEntry procEntry;
|
||||
procEntry.SchoolMask = 0;
|
||||
procEntry.ProcFlags = spellInfo->ProcFlags;
|
||||
procEntry.SpellFamilyName = 0;
|
||||
for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
if (spellInfo->Effects[i].IsEffect() && isTriggerAura[spellInfo->Effects[i].ApplyAuraName])
|
||||
procEntry.SpellFamilyMask |= spellInfo->Effects[i].SpellClassMask;
|
||||
|
||||
if (procEntry.SpellFamilyMask)
|
||||
procEntry.SpellFamilyName = spellInfo->SpellFamilyName;
|
||||
|
||||
procEntry.SpellTypeMask = procSpellTypeMask;
|
||||
procEntry.SpellPhaseMask = PROC_SPELL_PHASE_HIT;
|
||||
procEntry.HitMask = PROC_HIT_NONE; // uses default proc @see SpellMgr::CanSpellTriggerProcOnEvent
|
||||
|
||||
// Reflect auras should only proc off reflects
|
||||
for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (spellInfo->Effects[i].IsAura(SPELL_AURA_REFLECT_SPELLS) || spellInfo->Effects[i].IsAura(SPELL_AURA_REFLECT_SPELLS_SCHOOL))
|
||||
{
|
||||
procEntry.HitMask = PROC_HIT_REFLECT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
procEntry.AttributesMask = 0;
|
||||
if (spellInfo->ProcFlags & PROC_FLAG_KILL)
|
||||
procEntry.AttributesMask |= PROC_ATTR_REQ_EXP_OR_HONOR;
|
||||
if (addTriggerFlag)
|
||||
procEntry.AttributesMask |= PROC_ATTR_TRIGGERED_CAN_PROC;
|
||||
|
||||
procEntry.ProcsPerMinute = 0;
|
||||
procEntry.Chance = spellInfo->ProcChance;
|
||||
procEntry.Cooldown = Milliseconds::zero();
|
||||
procEntry.Charges = spellInfo->ProcCharges;
|
||||
|
||||
mSpellProcMap[spellInfo->Id] = procEntry;
|
||||
++count;
|
||||
}
|
||||
|
||||
LOG_INFO("server.loading", ">> Generated spell proc data for {} spells in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
void SpellMgr::LoadSpellBonuses()
|
||||
|
||||
@@ -154,13 +154,15 @@ enum ProcFlags
|
||||
| PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS,
|
||||
|
||||
SPELL_PROC_FLAG_MASK = PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS
|
||||
| PROC_FLAG_DONE_RANGED_AUTO_ATTACK | PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK
|
||||
| PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS
|
||||
| PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS
|
||||
| PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG
|
||||
| PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS
|
||||
| PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG,
|
||||
| PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG
|
||||
| PROC_FLAG_DONE_TRAP_ACTIVATION,
|
||||
|
||||
SPELL_CAST_PROC_FLAG_MASK = SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION | RANGED_PROC_FLAG_MASK,
|
||||
SPELL_CAST_PROC_FLAG_MASK = SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION,
|
||||
|
||||
PERIODIC_PROC_FLAG_MASK = PROC_FLAG_DONE_PERIODIC | PROC_FLAG_TAKEN_PERIODIC,
|
||||
|
||||
@@ -168,7 +170,8 @@ enum ProcFlags
|
||||
| PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS
|
||||
| PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG
|
||||
| PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG
|
||||
| PROC_FLAG_DONE_PERIODIC | PROC_FLAG_DONE_MAINHAND_ATTACK | PROC_FLAG_DONE_OFFHAND_ATTACK,
|
||||
| PROC_FLAG_DONE_PERIODIC | PROC_FLAG_DONE_TRAP_ACTIVATION
|
||||
| PROC_FLAG_DONE_MAINHAND_ATTACK | PROC_FLAG_DONE_OFFHAND_ATTACK,
|
||||
|
||||
TAKEN_HIT_PROC_FLAG_MASK = PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK | PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK
|
||||
| PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS
|
||||
@@ -188,46 +191,6 @@ enum ProcFlags
|
||||
PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | \
|
||||
PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS)
|
||||
|
||||
enum ProcFlagsExLegacy
|
||||
{
|
||||
PROC_EX_NONE = 0x0000000, // If none can tigger on Hit/Crit only (passive spells MUST defined by SpellFamily flag)
|
||||
PROC_EX_NORMAL_HIT = 0x0000001, // If set only from normal hit (only damage spells)
|
||||
PROC_EX_CRITICAL_HIT = 0x0000002,
|
||||
PROC_EX_MISS = 0x0000004,
|
||||
PROC_EX_RESIST = 0x0000008,
|
||||
PROC_EX_DODGE = 0x0000010,
|
||||
PROC_EX_PARRY = 0x0000020,
|
||||
PROC_EX_BLOCK = 0x0000040,
|
||||
PROC_EX_EVADE = 0x0000080,
|
||||
PROC_EX_IMMUNE = 0x0000100,
|
||||
PROC_EX_DEFLECT = 0x0000200,
|
||||
PROC_EX_ABSORB = 0x0000400,
|
||||
PROC_EX_REFLECT = 0x0000800,
|
||||
PROC_EX_INTERRUPT = 0x0001000, // Melee hit result can be Interrupt (not used)
|
||||
PROC_EX_FULL_BLOCK = 0x0002000, // block all attack damage
|
||||
PROC_EX_RESERVED2 = 0x0004000,
|
||||
PROC_EX_NOT_ACTIVE_SPELL = 0x0008000, // Spell mustn't do damage/heal to proc
|
||||
PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always no matter of hit result
|
||||
PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000, // If set trigger always but only one time (not implemented yet)
|
||||
PROC_EX_ONLY_ACTIVE_SPELL = 0x0040000, // Spell has to do damage/heal to proc
|
||||
PROC_EX_NO_OVERHEAL = 0x0080000, // Proc if heal did some work
|
||||
PROC_EX_NO_AURA_REFRESH = 0x0100000, // Proc if aura was not refreshed
|
||||
PROC_EX_ONLY_FIRST_TICK = 0x0200000, // Proc only on first tick (in case of periodic spells)
|
||||
|
||||
// Flags for internal use - do not use these in db!
|
||||
PROC_EX_INTERNAL_CANT_PROC = 0x0800000,
|
||||
PROC_EX_INTERNAL_DOT = 0x1000000,
|
||||
PROC_EX_INTERNAL_HOT = 0x2000000,
|
||||
PROC_EX_INTERNAL_TRIGGERED = 0x4000000,
|
||||
PROC_EX_INTERNAL_REQ_FAMILY = 0x8000000
|
||||
};
|
||||
|
||||
#define AURA_SPELL_PROC_EX_MASK \
|
||||
(PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT | PROC_EX_MISS | \
|
||||
PROC_EX_RESIST | PROC_EX_DODGE | PROC_EX_PARRY | PROC_EX_BLOCK | \
|
||||
PROC_EX_EVADE | PROC_EX_IMMUNE | PROC_EX_DEFLECT | \
|
||||
PROC_EX_ABSORB | PROC_EX_REFLECT | PROC_EX_INTERRUPT)
|
||||
|
||||
enum ProcFlagsSpellType
|
||||
{
|
||||
PROC_SPELL_TYPE_NONE = 0x0000000,
|
||||
@@ -261,45 +224,37 @@ enum ProcFlagsHit
|
||||
PROC_HIT_DEFLECT = 0x0000200,
|
||||
PROC_HIT_ABSORB = 0x0000400, // partial or full absorb
|
||||
PROC_HIT_REFLECT = 0x0000800,
|
||||
PROC_HIT_INTERRUPT = 0x0001000, // (not used atm)
|
||||
PROC_HIT_INTERRUPT = 0x0001000,
|
||||
PROC_HIT_FULL_BLOCK = 0x0002000,
|
||||
PROC_HIT_MASK_ALL = 0x2FFF,
|
||||
PROC_HIT_MASK_ALL = 0x0002FFF,
|
||||
};
|
||||
|
||||
enum ProcAttributes
|
||||
{
|
||||
PROC_ATTR_REQ_EXP_OR_HONOR = 0x0000010,
|
||||
};
|
||||
PROC_ATTR_REQ_EXP_OR_HONOR = 0x0000001, // requires proc target to give exp or honor for aura proc
|
||||
PROC_ATTR_TRIGGERED_CAN_PROC = 0x0000002, // aura can proc even with triggered spells
|
||||
PROC_ATTR_REQ_MANA_COST = 0x0000004, // requires triggering spell to have a mana cost for aura proc
|
||||
PROC_ATTR_REQ_SPELLMOD = 0x0000008, // requires triggering spell to be affected by proccing aura to drop charges
|
||||
|
||||
struct SpellProcEventEntry
|
||||
{
|
||||
uint32 schoolMask; // if nonzero - bit mask for matching proc condition based on spell candidate's school: Fire=2, Mask=1<<(2-1)=2
|
||||
uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyNamer value
|
||||
flag96 spellFamilyMask; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyFlags (like auras 107 and 108 do)
|
||||
uint32 procFlags; // bitmask for matching proc event
|
||||
uint32 procEx; // proc Extend info (see ProcFlagsEx)
|
||||
uint32 procPhase; // proc phase (see ProcFlagsSpellPhase)
|
||||
float ppmRate; // for melee (ranged?) damage spells - proc rate per minute. if zero, falls back to flat chance from Spell.dbc
|
||||
float customChance; // Owerride chance (in most cases for debug only)
|
||||
uint32 cooldown; // hidden cooldown used for some spell proc events, applied to _triggered_spell_
|
||||
PROC_ATTR_DISABLE_EFF_0 = 0x0000010, // explicitly disables aura proc from effects, USE ONLY IF 100% SURE AURA SHOULDN'T PROC
|
||||
PROC_ATTR_DISABLE_EFF_1 = 0x0000020, // used to avoid a console error if the spell has invalid trigger spell and handled elsewhere
|
||||
PROC_ATTR_DISABLE_EFF_2 = 0x0000040 // or handling not needed
|
||||
};
|
||||
|
||||
typedef std::unordered_map<uint32, SpellProcEventEntry> SpellProcEventMap;
|
||||
|
||||
struct SpellProcEntry
|
||||
{
|
||||
uint32 schoolMask; // if nonzero - bitmask for matching proc condition based on spell's school
|
||||
uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName
|
||||
flag96 spellFamilyMask; // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags
|
||||
uint32 typeMask; // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags
|
||||
uint32 spellTypeMask; // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType
|
||||
uint32 spellPhaseMask; // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase
|
||||
uint32 hitMask; // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit
|
||||
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
|
||||
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
|
||||
uint32 SchoolMask; // if nonzero - bitmask for matching proc condition based on spell's school
|
||||
uint32 SpellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName
|
||||
flag96 SpellFamilyMask; // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags
|
||||
uint32 ProcFlags; // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags
|
||||
uint32 SpellTypeMask; // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType
|
||||
uint32 SpellPhaseMask; // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase
|
||||
uint32 HitMask; // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit
|
||||
uint32 AttributesMask; // bitmask, see ProcAttributes
|
||||
float ProcsPerMinute; // 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
|
||||
Milliseconds 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
|
||||
};
|
||||
|
||||
typedef std::unordered_map<uint32, SpellProcEntry> SpellProcMap;
|
||||
@@ -669,13 +624,9 @@ public:
|
||||
SpellGroupStackFlags CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2, bool remove, bool areaAura) const;
|
||||
void GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpecialFlags flag, std::set<uint32>& availableElixirs) const;
|
||||
|
||||
// Spell proc event table
|
||||
[[nodiscard]] SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const;
|
||||
bool IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, ProcEventInfo const& eventInfo, bool active) const;
|
||||
|
||||
// Spell proc table
|
||||
[[nodiscard]] SpellProcEntry const* GetSpellProcEntry(uint32 spellId) const;
|
||||
bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const;
|
||||
static bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo);
|
||||
|
||||
// Spell bonus data table
|
||||
[[nodiscard]] SpellBonusEntry const* GetSpellBonusData(uint32 spellId) const;
|
||||
@@ -750,7 +701,6 @@ public:
|
||||
void LoadSpellTargetPositions();
|
||||
void LoadSpellGroups();
|
||||
void LoadSpellGroupStackRules();
|
||||
void LoadSpellProcEvents();
|
||||
void LoadSpellProcs();
|
||||
void LoadSpellBonuses();
|
||||
void LoadSpellThreats();
|
||||
@@ -779,7 +729,6 @@ private:
|
||||
SpellTargetPositionMap mSpellTargetPositions;
|
||||
SpellGroupMap mSpellGroupMap;
|
||||
SpellGroupStackMap mSpellGroupStackMap;
|
||||
SpellProcEventMap mSpellProcEventMap;
|
||||
SpellProcMap mSpellProcMap;
|
||||
SpellBonusMap mSpellBonusMap;
|
||||
SpellThreatMap mSpellThreatMap;
|
||||
|
||||
@@ -733,6 +733,9 @@ bool AuraScript::_Validate(SpellInfo const* entry)
|
||||
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
|
||||
LOG_ERROR("spells.scripts", "Spell `{}` of script `{}` does not have apply aura effect - handler bound to hook `DoCheckProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
|
||||
|
||||
for (std::list<CheckEffectProcHandler>::iterator itr = DoCheckEffectProc.begin(); itr != DoCheckEffectProc.end(); ++itr)
|
||||
if (!itr->GetAffectedEffectsMask(entry))
|
||||
LOG_ERROR("spells.scripts", "Spell `{}` Effect `{}` of script `{}` did not match dbc effect data - handler bound to hook `DoCheckEffectProc` of AuraScript won't be executed", entry->Id, (*itr).ToString(), m_scriptName->c_str());
|
||||
for (std::list<CheckProcHandler>::iterator itr = DoCheckAfterProc.begin(); itr != DoCheckAfterProc.end(); ++itr)
|
||||
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
|
||||
LOG_ERROR("spells.scripts", "Spell `{}` of script `{}` does not have apply aura effect - handler bound to hook `DoCheckAfterProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
|
||||
@@ -906,6 +909,17 @@ bool AuraScript::CheckProcHandler::Call(AuraScript* auraScript, ProcEventInfo& e
|
||||
return (auraScript->*_HandlerScript)(eventInfo);
|
||||
}
|
||||
|
||||
AuraScript::CheckEffectProcHandler::CheckEffectProcHandler(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName)
|
||||
: AuraScript::EffectBase(effIndex, effName)
|
||||
{
|
||||
_HandlerScript = handlerScript;
|
||||
}
|
||||
|
||||
bool AuraScript::CheckEffectProcHandler::Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo)
|
||||
{
|
||||
return (auraScript->*_HandlerScript)(aurEff, eventInfo);
|
||||
}
|
||||
|
||||
AuraScript::AuraProcHandler::AuraProcHandler(AuraProcFnType handlerScript)
|
||||
{
|
||||
_HandlerScript = handlerScript;
|
||||
@@ -1167,6 +1181,7 @@ Unit* AuraScript::GetTarget() const
|
||||
case AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD:
|
||||
case AURA_SCRIPT_HOOK_EFFECT_SPLIT:
|
||||
case AURA_SCRIPT_HOOK_CHECK_PROC:
|
||||
case AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC:
|
||||
case AURA_SCRIPT_HOOK_CHECK_AFTER_PROC:
|
||||
case AURA_SCRIPT_HOOK_PREPARE_PROC:
|
||||
case AURA_SCRIPT_HOOK_PROC:
|
||||
|
||||
@@ -499,6 +499,7 @@ enum AuraScriptHookType
|
||||
AURA_SCRIPT_HOOK_AFTER_DISPEL,
|
||||
// Spell Proc Hooks
|
||||
AURA_SCRIPT_HOOK_CHECK_PROC,
|
||||
AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC,
|
||||
AURA_SCRIPT_HOOK_CHECK_AFTER_PROC,
|
||||
AURA_SCRIPT_HOOK_PREPARE_PROC,
|
||||
AURA_SCRIPT_HOOK_PROC,
|
||||
@@ -529,7 +530,8 @@ public:
|
||||
typedef void(CLASSNAME::*AuraEffectCalcSpellModFnType)(AuraEffect const*, SpellModifier* &); \
|
||||
typedef void(CLASSNAME::*AuraEffectAbsorbFnType)(AuraEffect*, DamageInfo &, uint32 &); \
|
||||
typedef void(CLASSNAME::*AuraEffectSplitFnType)(AuraEffect*, DamageInfo &, uint32 &); \
|
||||
typedef bool(CLASSNAME::*AuraCheckProcFnType)(ProcEventInfo&); \
|
||||
typedef bool(CLASSNAME::*AuraCheckProcFnType)(ProcEventInfo&); \
|
||||
typedef bool(CLASSNAME::*AuraCheckEffectProcFnType)(AuraEffect const*, ProcEventInfo&); \
|
||||
typedef void(CLASSNAME::*AuraProcFnType)(ProcEventInfo&); \
|
||||
typedef void(CLASSNAME::*AuraEffectProcFnType)(AuraEffect const*, ProcEventInfo&); \
|
||||
|
||||
@@ -639,6 +641,14 @@ public:
|
||||
private:
|
||||
AuraCheckProcFnType _HandlerScript;
|
||||
};
|
||||
class CheckEffectProcHandler : public EffectBase
|
||||
{
|
||||
public:
|
||||
CheckEffectProcHandler(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName);
|
||||
bool Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo);
|
||||
private:
|
||||
AuraCheckEffectProcFnType _HandlerScript;
|
||||
};
|
||||
class AuraProcHandler
|
||||
{
|
||||
public:
|
||||
@@ -668,8 +678,9 @@ public:
|
||||
class EffectAbsorbFunction : public AuraScript::EffectAbsorbHandler { public: EffectAbsorbFunction(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectAbsorbHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex) {} }; \
|
||||
class EffectManaShieldFunction : public AuraScript::EffectManaShieldHandler { public: EffectManaShieldFunction(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectManaShieldHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex) {} }; \
|
||||
class EffectSplitFunction : public AuraScript::EffectSplitHandler { public: EffectSplitFunction(AuraEffectSplitFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectSplitHandler((AuraScript::AuraEffectSplitFnType)_pEffectHandlerScript, _effIndex) {} }; \
|
||||
class CheckProcHandlerFunction : public AuraScript::CheckProcHandler { public: CheckProcHandlerFunction(AuraCheckProcFnType handlerScript) : AuraScript::CheckProcHandler((AuraScript::AuraCheckProcFnType)handlerScript) {} }; \
|
||||
class AuraProcHandlerFunction : public AuraScript::AuraProcHandler { public: AuraProcHandlerFunction(AuraProcFnType handlerScript) : AuraScript::AuraProcHandler((AuraScript::AuraProcFnType)handlerScript) {} }; \
|
||||
class CheckProcHandlerFunction : public AuraScript::CheckProcHandler { public: CheckProcHandlerFunction(AuraCheckProcFnType handlerScript) : AuraScript::CheckProcHandler((AuraScript::AuraCheckProcFnType)handlerScript) {} }; \
|
||||
class CheckEffectProcHandlerFunction : public AuraScript::CheckEffectProcHandler { public: CheckEffectProcHandlerFunction(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName) : AuraScript::CheckEffectProcHandler((AuraScript::AuraCheckEffectProcFnType)handlerScript, effIndex, effName) { } }; \
|
||||
class AuraProcHandlerFunction : public AuraScript::AuraProcHandler { public: AuraProcHandlerFunction(AuraProcFnType handlerScript) : AuraScript::AuraProcHandler((AuraScript::AuraProcFnType)handlerScript) {} }; \
|
||||
class EffectProcHandlerFunction : public AuraScript::EffectProcHandler { public: EffectProcHandlerFunction(AuraEffectProcFnType effectHandlerScript, uint8 effIndex, uint16 effName) : AuraScript::EffectProcHandler((AuraScript::AuraEffectProcFnType)effectHandlerScript, effIndex, effName) {} }; \
|
||||
|
||||
#define PrepareAuraScript(CLASSNAME) AURASCRIPT_FUNCTION_TYPE_DEFINES(CLASSNAME) AURASCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME)
|
||||
@@ -811,6 +822,12 @@ public:
|
||||
HookList<CheckProcHandler> DoCheckAfterProc;
|
||||
#define AuraCheckProcFn(F) CheckProcHandlerFunction(&F)
|
||||
|
||||
// executed when aura effect checks if it can proc the aura
|
||||
// example: DoCheckEffectProc += AuraCheckEffectProcFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier);
|
||||
// where function is bool function (AuraEffect const* aurEff, ProcEventInfo& eventInfo);
|
||||
HookList<CheckEffectProcHandler> DoCheckEffectProc;
|
||||
#define AuraCheckEffectProcFn(F, I, N) CheckEffectProcHandlerFunction(&F, I, N)
|
||||
|
||||
// executed before aura procs (possibility to prevent charge drop/cooldown)
|
||||
// example: DoPrepareProc += AuraProcFn(class::function);
|
||||
// where function is: void function (ProcEventInfo& eventInfo);
|
||||
|
||||
Reference in New Issue
Block a user