mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-24 14:16:31 +00:00
fix(Core/Spells): Implemented spell proc phases. (#9725)
* fix(Core/Spells): Implemented spell proc phases. Fixes #9634
This commit is contained in:
@@ -5849,15 +5849,15 @@ void Unit::SendSpellNonMeleeDamageLog(Unit* target, SpellInfo const* spellInfo,
|
||||
SendSpellNonMeleeDamageLog(&log);
|
||||
}
|
||||
|
||||
void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpellInfo, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo)
|
||||
void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpellInfo, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo, uint32 procPhase)
|
||||
{
|
||||
// Not much to do if no flags are set.
|
||||
if (procAttacker)
|
||||
ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo);
|
||||
ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase);
|
||||
// Now go on with a victim's events'n'auras
|
||||
// Not much to do if no flags are set or there is no victim
|
||||
if (victim && victim->IsAlive() && procVictim)
|
||||
victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo);
|
||||
victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase);
|
||||
}
|
||||
|
||||
void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo)
|
||||
@@ -8403,7 +8403,7 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlags, uint32 procEx, uint32 cooldown)
|
||||
bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlags, uint32 procEx, uint32 cooldown, uint32 procPhase)
|
||||
{
|
||||
// Get triggered aura spell info
|
||||
SpellInfo const* auraSpellInfo = triggeredByAura->GetSpellInfo();
|
||||
@@ -9295,18 +9295,21 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
|
||||
// Fingers of Frost, synchronise with Frostbite
|
||||
case 44544:
|
||||
{
|
||||
// Find Frostbite
|
||||
if (AuraEffect* aurEff = this->GetAuraEffect(SPELL_AURA_ADD_TARGET_TRIGGER, SPELLFAMILY_MAGE, 119, EFFECT_0))
|
||||
if (procPhase == PROC_SPELL_PHASE_HIT)
|
||||
{
|
||||
if (!victim)
|
||||
return false;
|
||||
// Find Frostbite
|
||||
if (AuraEffect* aurEff = this->GetAuraEffect(SPELL_AURA_ADD_TARGET_TRIGGER, SPELLFAMILY_MAGE, 119, EFFECT_0))
|
||||
{
|
||||
if (!victim)
|
||||
return false;
|
||||
|
||||
uint8 fofRank = sSpellMgr->GetSpellRank(triggeredByAura->GetId());
|
||||
uint8 fbRank = sSpellMgr->GetSpellRank(aurEff->GetId());
|
||||
uint8 chance = uint8(std::ceil(fofRank * fbRank * 16.6f));
|
||||
uint8 fofRank = sSpellMgr->GetSpellRank(triggeredByAura->GetId());
|
||||
uint8 fbRank = sSpellMgr->GetSpellRank(aurEff->GetId());
|
||||
uint8 chance = uint8(std::ceil(fofRank * fbRank * 16.6f));
|
||||
|
||||
if (roll_chance_i(chance))
|
||||
CastSpell(victim, aurEff->GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true);
|
||||
if (roll_chance_i(chance))
|
||||
CastSpell(victim, aurEff->GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -15503,13 +15506,13 @@ uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missC
|
||||
return procEx;
|
||||
}
|
||||
|
||||
void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo)
|
||||
void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo, uint32 procPhase)
|
||||
{
|
||||
// Player is loaded now - do not allow passive spell casts to proc
|
||||
if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->GetSession()->PlayerLoading())
|
||||
return;
|
||||
// For melee/ranged based attack need update skills and set some Aura states if victim present
|
||||
if (procFlag & MELEE_BASED_TRIGGER_MASK && target)
|
||||
if (procFlag & MELEE_BASED_TRIGGER_MASK && target && procPhase == PROC_SPELL_PHASE_HIT)
|
||||
{
|
||||
// Xinef: Shaman in ghost wolf form cant proc anything melee based
|
||||
if (!isVictim && GetShapeshiftForm() == FORM_GHOSTWOLF)
|
||||
@@ -15598,7 +15601,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
|
||||
Unit* actor = isVictim ? target : this;
|
||||
Unit* actionTarget = !isVictim ? target : this;
|
||||
|
||||
ProcEventInfo eventInfo = ProcEventInfo(actor, actionTarget, target, procFlag, 0, 0, procExtra, procSpell, damageInfo, healInfo, procAura, procAuraEffectIndex);
|
||||
ProcEventInfo eventInfo = ProcEventInfo(actor, actionTarget, target, procFlag, 0, procPhase, procExtra, procSpell, damageInfo, healInfo, procAura, procAuraEffectIndex);
|
||||
|
||||
ProcTriggeredList procTriggered;
|
||||
// Fill procTriggered list
|
||||
@@ -15788,7 +15791,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
|
||||
{
|
||||
LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
|
||||
// Don`t drop charge or add cooldown for not started trigger
|
||||
if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown))
|
||||
if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procPhase))
|
||||
takeCharges = true;
|
||||
break;
|
||||
}
|
||||
@@ -15847,7 +15850,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
|
||||
{
|
||||
LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell %u (triggered with value by %s aura of spell %u)", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
|
||||
|
||||
if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown))
|
||||
if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procPhase))
|
||||
takeCharges = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1492,8 +1492,8 @@ public:
|
||||
static void Kill(Unit* killer, Unit* victim, bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr);
|
||||
static int32 DealHeal(Unit* healer, Unit* victim, uint32 addhealth);
|
||||
|
||||
void ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpellInfo = nullptr, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr);
|
||||
void ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr);
|
||||
void ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpellInfo = nullptr, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/);
|
||||
void ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/);
|
||||
|
||||
void GetProcAurasTriggeredOnEvent(std::list<AuraApplication*>& aurasTriggeringProc, std::list<AuraApplication*>* procAuras, ProcEventInfo eventInfo);
|
||||
void TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo);
|
||||
@@ -2464,7 +2464,7 @@ private:
|
||||
bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent, ProcEventInfo const& eventInfo);
|
||||
bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
|
||||
bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, bool* handled);
|
||||
bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
|
||||
bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, uint32 procPhase);
|
||||
bool HandleOverrideClassScriptAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown);
|
||||
bool HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura);
|
||||
bool HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura);
|
||||
|
||||
@@ -3720,6 +3720,51 @@ void Spell::_cast(bool skipCheck)
|
||||
// we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()...
|
||||
SendSpellGo();
|
||||
|
||||
if (modOwner)
|
||||
modOwner->SetSpellModTakingSpell(this, false);
|
||||
|
||||
if (m_originalCaster)
|
||||
{
|
||||
// Handle procs on cast
|
||||
uint32 procAttacker = m_procAttacker;
|
||||
if (!procAttacker)
|
||||
{
|
||||
bool IsPositive = m_spellInfo->IsPositive();
|
||||
if (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC)
|
||||
{
|
||||
procAttacker = IsPositive ? PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG;
|
||||
}
|
||||
else
|
||||
{
|
||||
procAttacker = IsPositive ? PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 procEx = PROC_EX_NORMAL_HIT;
|
||||
|
||||
for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
|
||||
{
|
||||
if (ihit->missCondition != SPELL_MISS_NONE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ihit->crit)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
procEx |= PROC_EX_CRITICAL_HIT;
|
||||
break;
|
||||
}
|
||||
|
||||
m_originalCaster->ProcDamageAndSpell(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);
|
||||
}
|
||||
|
||||
if (modOwner)
|
||||
modOwner->SetSpellModTakingSpell(this, true);
|
||||
|
||||
// Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
|
||||
if ((m_spellInfo->Speed > 0.0f && !m_spellInfo->IsChanneled())/* xinef: we dont need this || m_spellInfo->Id == 14157*/)
|
||||
{
|
||||
@@ -3974,6 +4019,44 @@ void Spell::_handle_finish_phase()
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->IsCooldownStartedOnEvent())
|
||||
m_caster->ToPlayer()->SendCooldownEvent(m_spellInfo);
|
||||
}
|
||||
|
||||
// Handle procs on finish
|
||||
if (m_originalCaster)
|
||||
{
|
||||
uint32 procAttacker = m_procAttacker;
|
||||
if (!procAttacker)
|
||||
{
|
||||
bool IsPositive = m_spellInfo->IsPositive();
|
||||
if (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC)
|
||||
{
|
||||
procAttacker = IsPositive ? PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG;
|
||||
}
|
||||
else
|
||||
{
|
||||
procAttacker = IsPositive ? PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 procEx = PROC_EX_NORMAL_HIT;
|
||||
for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
|
||||
{
|
||||
if (ihit->missCondition != SPELL_MISS_NONE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ihit->crit)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
procEx |= PROC_EX_CRITICAL_HIT;
|
||||
break;
|
||||
}
|
||||
|
||||
m_originalCaster->ProcDamageAndSpell(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);
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::SendSpellCooldown()
|
||||
|
||||
@@ -738,9 +738,11 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, Spell
|
||||
{
|
||||
// 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
|
||||
@@ -798,6 +800,7 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, Spell
|
||||
{
|
||||
// Store extra req
|
||||
procEvent_procEx = spellProcEvent->procEx;
|
||||
procEvent_procPhase = spellProcEvent->procPhase;
|
||||
|
||||
// For melee triggers
|
||||
if (!procSpellInfo)
|
||||
@@ -847,6 +850,11 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, Spell
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(procEvent_procPhase & procPhase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for extra req (if none) and hit/crit
|
||||
if (procEvent_procEx == PROC_EX_NONE)
|
||||
{
|
||||
@@ -1730,8 +1738,8 @@ void SpellMgr::LoadSpellProcEvents()
|
||||
|
||||
mSpellProcEventMap.clear(); // need for reload case
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9 10
|
||||
QueryResult result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event");
|
||||
// 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_INFO("server.loading", ">> Loaded 0 spell proc event conditions. DB table `spell_proc_event` is empty.");
|
||||
@@ -1781,9 +1789,16 @@ void SpellMgr::LoadSpellProcEvents()
|
||||
spellProcEvent.spellFamilyMask[2] = fields[5].GetUInt32();
|
||||
spellProcEvent.procFlags = fields[6].GetUInt32();
|
||||
spellProcEvent.procEx = fields[7].GetUInt32();
|
||||
spellProcEvent.ppmRate = fields[8].GetFloat();
|
||||
spellProcEvent.customChance = fields[9].GetFloat();
|
||||
spellProcEvent.cooldown = fields[10].GetUInt32();
|
||||
spellProcEvent.procPhase = fields[8].GetUInt32();
|
||||
spellProcEvent.ppmRate = fields[9].GetFloat();
|
||||
spellProcEvent.customChance = fields[10].GetFloat();
|
||||
spellProcEvent.cooldown = fields[11].GetUInt32();
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
||||
@@ -278,6 +278,7 @@ struct SpellProcEventEntry
|
||||
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_
|
||||
|
||||
Reference in New Issue
Block a user