Core/Spells: don't allow spells which hit target only with SPELL_EFFECT_DUMMY to execute spell triggers on that targets, also cleanup related code a bit.

This commit is contained in:
QAston
2011-06-26 00:29:12 +02:00
parent b54b72ba54
commit 2bcf63d387
5 changed files with 103 additions and 84 deletions

View File

@@ -1166,7 +1166,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
//Spells with this flag cannot trigger if effect is casted on self
// Slice and Dice, relentless strikes, eviscerate
bool canEffectTrigger = unitTarget->CanProc() && (m_spellInfo->AttributesEx4 & (SPELL_ATTR4_CANT_PROC_FROM_SELFCAST) ? m_caster != unitTarget : true);
bool canEffectTrigger = unitTarget->CanProc() && CanExecuteTriggersOnHit(mask);
Unit* spellHitTarget = NULL;
if (missInfo == SPELL_MISS_NONE) // In case spell hit target, do all effect on that target
@@ -1355,7 +1355,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
m_caster->ToCreature()->AI()->SpellHitTarget(spellHitTarget, m_spellInfo);
// Needs to be called after dealing damage/healing to not remove breaking on damage auras
DoTriggersOnSpellHit(spellHitTarget);
DoTriggersOnSpellHit(spellHitTarget, mask);
// if target is fallged for pvp also flag caster if a player
if (unit->IsPvP())
@@ -1525,9 +1525,10 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask, bool
return SPELL_MISS_NONE;
}
void Spell::DoTriggersOnSpellHit(Unit *unit)
void Spell::DoTriggersOnSpellHit(Unit *unit, uint8 effMask)
{
// Apply additional spell effects to target
// TODO: move this code to scripts
if (m_preCastSpell)
{
// Paladin immunity shields
@@ -1549,38 +1550,44 @@ void Spell::DoTriggersOnSpellHit(Unit *unit)
m_caster->AddAura(m_preCastSpell, unit);
}
// spells with this flag can trigger only if not selfcast (eviscerate for example)
if (m_ChanceTriggerSpells.size() && (!((m_spellInfo->AttributesEx4 & SPELL_ATTR4_CANT_PROC_FROM_SELFCAST) && unit == m_caster)))
// handle SPELL_AURA_ADD_TARGET_TRIGGER auras
// this is executed after spell proc spells on target hit
// spells are triggered for each hit spell target
// info confirmed with retail sniffs of permafrost and shadow weaving
if (!m_hitTriggerSpells.empty() && CanExecuteTriggersOnHit(effMask))
{
int _duration=0;
for (ChanceTriggerSpells::const_iterator i = m_ChanceTriggerSpells.begin(); i != m_ChanceTriggerSpells.end(); ++i)
int _duration = 0;
for (HitTriggerSpells::const_iterator i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i)
{
// SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration
// set duration equal to triggering spell
if (roll_chance_i(i->second))
{
m_caster->CastSpell(unit, i->first, true);
sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell %d triggered spell %d by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->first->Id);
}
if (GetSpellDuration(i->first) == -1)
{
if (Aura * triggeredAur = unit->GetAura(i->first->Id, m_caster->GetGUID()))
// SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration
// set duration of current aura to the triggered spell
if (GetSpellDuration(i->first) == -1)
{
// get duration from aura-only once
if (!_duration)
if (Aura * triggeredAur = unit->GetAura(i->first->Id, m_caster->GetGUID()))
{
Aura * aur = unit->GetAura(m_spellInfo->Id, m_caster->GetGUID());
_duration = aur ? aur->GetDuration() : -1;
// get duration from aura-only once
if (!_duration)
{
Aura * aur = unit->GetAura(m_spellInfo->Id, m_caster->GetGUID());
_duration = aur ? aur->GetDuration() : -1;
}
triggeredAur->SetDuration(_duration);
}
triggeredAur->SetDuration(_duration);
}
}
}
}
// trigger linked auras remove/apply
// TODO: remove/cleanup this, as this table is not documented and people are doing stupid things with it
if (m_customAttr & SPELL_ATTR0_CU_LINK_HIT)
if (const std::vector<int32> *spell_triggered = sSpellMgr->GetSpellLinked(m_spellInfo->Id + SPELL_LINK_HIT))
for (std::vector<int32>::const_iterator i = spell_triggered->begin(); i != spell_triggered->end(); ++i)
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(m_spellInfo->Id + SPELL_LINK_HIT))
for (std::vector<int32>::const_iterator i = spellTriggered->begin(); i != spellTriggered->end(); ++i)
if (*i < 0)
unit->RemoveAurasDueToSpell(-(*i));
else
@@ -3135,30 +3142,7 @@ void Spell::cast(bool skipCheck)
return;
}
if (m_spellInfo->SpellFamilyName)
{
if (m_spellInfo->excludeCasterAuraSpell && !IsPositiveSpell(m_spellInfo->excludeCasterAuraSpell))
m_preCastSpell = m_spellInfo->excludeCasterAuraSpell;
else if (m_spellInfo->excludeTargetAuraSpell && !IsPositiveSpell(m_spellInfo->excludeTargetAuraSpell))
m_preCastSpell = m_spellInfo->excludeTargetAuraSpell;
}
switch (m_spellInfo->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
{
if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
m_preCastSpell = 11196; // Recently Bandaged
break;
}
case SPELLFAMILY_MAGE:
{
// Permafrost
if (m_spellInfo->SpellFamilyFlags[1] & 0x00001000 || m_spellInfo->SpellFamilyFlags[0] & 0x00100220)
m_preCastSpell = 68391;
break;
}
}
PrepareTriggersExecutedOnHit();
// traded items have trade slot instead of guid in m_itemTargetGUID
// set to real guid to be sent later to the client
@@ -3188,23 +3172,6 @@ void Spell::cast(bool skipCheck)
TakeReagents();
}
// are there any spells need to be triggered after hit?
// handle SPELL_AURA_ADD_TARGET_TRIGGER auras
Unit::AuraEffectList const& targetTriggers = m_caster->GetAuraEffectsByType(SPELL_AURA_ADD_TARGET_TRIGGER);
for (Unit::AuraEffectList::const_iterator i = targetTriggers.begin(); i != targetTriggers.end(); ++i)
{
if (!(*i)->IsAffectedOnSpell(m_spellInfo))
continue;
SpellEntry const *auraSpellInfo = (*i)->GetSpellProto();
uint32 auraSpellIdx = (*i)->GetEffIndex();
if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(auraSpellInfo->EffectTriggerSpell[auraSpellIdx]))
{
int32 auraBaseAmount = (*i)->GetBaseAmount();
int32 chance = m_caster->CalculateSpellDamage(NULL, auraSpellInfo, auraSpellIdx, &auraBaseAmount);
m_ChanceTriggerSpells.push_back(std::make_pair(spellInfo, chance * (*i)->GetBase()->GetStackAmount()));
}
}
if (m_customAttr & SPELL_ATTR0_CU_DIRECT_DAMAGE)
CalculateDamageDoneForAllTargets();
@@ -3482,6 +3449,7 @@ void Spell::_handle_finish_phase()
if (m_comboPointGain)
m_caster->m_movedPlayer->GainSpellComboPoints(m_comboPointGain);
}
// TODO: trigger proc phase finish here
}
void Spell::SendSpellCooldown()
@@ -7302,6 +7270,70 @@ void Spell::CallScriptAfterUnitTargetSelectHandlers(std::list<Unit*>& unitTarget
}
}
bool Spell::CanExecuteTriggersOnHit(uint8 effMask) const
{
// check which effects can trigger proc
// don't allow to proc for dummy-only spell target hits
// prevents triggering/procing effects twice from spells like Eviscerate
for (uint8 i = 0;effMask && i < MAX_SPELL_EFFECTS; ++i)
{
if (m_spellInfo->Effect[i] == SPELL_EFFECT_DUMMY)
effMask &= ~(1<<i);
}
return effMask;
}
void Spell::PrepareTriggersExecutedOnHit()
{
// todo: move this to scripts
if (m_spellInfo->SpellFamilyName)
{
if (m_spellInfo->excludeCasterAuraSpell && !IsPositiveSpell(m_spellInfo->excludeCasterAuraSpell))
m_preCastSpell = m_spellInfo->excludeCasterAuraSpell;
else if (m_spellInfo->excludeTargetAuraSpell && !IsPositiveSpell(m_spellInfo->excludeTargetAuraSpell))
m_preCastSpell = m_spellInfo->excludeTargetAuraSpell;
}
// todo: move this to scripts
switch (m_spellInfo->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
{
if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
m_preCastSpell = 11196; // Recently Bandaged
break;
}
case SPELLFAMILY_MAGE:
{
// Permafrost
if (m_spellInfo->SpellFamilyFlags[1] & 0x00001000 || m_spellInfo->SpellFamilyFlags[0] & 0x00100220)
m_preCastSpell = 68391;
break;
}
}
// handle SPELL_AURA_ADD_TARGET_TRIGGER auras:
// 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)
{
if (!(*i)->IsAffectedOnSpell(m_spellInfo))
continue;
SpellEntry const *auraSpellInfo = (*i)->GetSpellProto();
uint32 auraSpellIdx = (*i)->GetEffIndex();
if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(auraSpellInfo->EffectTriggerSpell[auraSpellIdx]))
{
// 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 chance = m_caster->CalculateSpellDamage(NULL, auraSpellInfo, auraSpellIdx, &auraBaseAmount);
// proc chance is stored in effect amount
m_hitTriggerSpells.push_back(std::make_pair(spellInfo, chance * (*i)->GetBase()->GetStackAmount()));
}
}
}
// Global cooldowns management
enum GCDLimits
{