mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-15 01:59:09 +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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user