mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-25 14:46:24 +00:00
fix(Core/Spells): Implemented spell proc phases. (#9725)
* fix(Core/Spells): Implemented spell proc phases. Fixes #9634
This commit is contained in:
@@ -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