8563fa8952
Port From (https://github.com/TrinityCore/TrinityCore/commit/5c8a058120dcf2c3ff8592886cb842ca889e0411)
5839 lines
244 KiB
C#
5839 lines
244 KiB
C#
/*
|
|
* Copyright (C) 2012-2020 CypherCore <http://github.com/CypherCore>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
using Framework.Constants;
|
|
using Framework.Dynamic;
|
|
using Game.BattleFields;
|
|
using Game.BattleGrounds;
|
|
using Game.DataStorage;
|
|
using Game.Entities;
|
|
using Game.Loots;
|
|
using Game.Maps;
|
|
using Game.Networking.Packets;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Collections;
|
|
|
|
namespace Game.Spells
|
|
{
|
|
public class AuraEffect
|
|
{
|
|
public AuraEffect(Aura baseAura, SpellEffectInfo spellEfffectInfo, int? baseAmount, Unit caster)
|
|
{
|
|
auraBase = baseAura;
|
|
m_spellInfo = baseAura.GetSpellInfo();
|
|
_effectInfo = spellEfffectInfo;
|
|
m_baseAmount = baseAmount.HasValue ? baseAmount.Value : _effectInfo.CalcBaseValue(caster, baseAura.GetAuraType() == AuraObjectType.Unit ? baseAura.GetOwner().ToUnit() : null, baseAura.GetCastItemId(), baseAura.GetCastItemLevel());
|
|
m_canBeRecalculated = true;
|
|
m_isPeriodic = false;
|
|
|
|
CalculatePeriodic(caster, true, false);
|
|
_amount = CalculateAmount(caster);
|
|
CalculateSpellMod();
|
|
}
|
|
|
|
void GetTargetList(out List<Unit> targetList)
|
|
{
|
|
targetList = new List<Unit>();
|
|
var targetMap = GetBase().GetApplicationMap();
|
|
// remove all targets which were not added to new list - they no longer deserve area aura
|
|
foreach (var app in targetMap.Values)
|
|
{
|
|
if (app.HasEffect(GetEffIndex()))
|
|
targetList.Add(app.GetTarget());
|
|
}
|
|
}
|
|
|
|
void GetApplicationList(out List<AuraApplication> applicationList)
|
|
{
|
|
applicationList = new List<AuraApplication>();
|
|
var targetMap = GetBase().GetApplicationMap();
|
|
foreach (var app in targetMap.Values)
|
|
{
|
|
if (app.HasEffect(GetEffIndex()))
|
|
applicationList.Add(app);
|
|
}
|
|
}
|
|
|
|
public int CalculateAmount(Unit caster)
|
|
{
|
|
// default amount calculation
|
|
int amount = 0;
|
|
|
|
if (!m_spellInfo.HasAttribute(SpellAttr8.MasterySpecialization) || MathFunctions.fuzzyEq(GetSpellEffectInfo().BonusCoefficient, 0.0f))
|
|
amount = GetSpellEffectInfo().CalcValue(caster, m_baseAmount, GetBase().GetOwner().ToUnit(), GetBase().GetCastItemId(), GetBase().GetCastItemLevel());
|
|
else if (caster != null && caster.IsTypeId(TypeId.Player))
|
|
amount = (int)(caster.ToPlayer().m_activePlayerData.Mastery * GetSpellEffectInfo().BonusCoefficient);
|
|
|
|
// custom amount calculations go here
|
|
switch (GetAuraType())
|
|
{
|
|
// crowd control auras
|
|
case AuraType.ModConfuse:
|
|
case AuraType.ModFear:
|
|
case AuraType.ModStun:
|
|
case AuraType.ModRoot:
|
|
case AuraType.Transform:
|
|
case AuraType.ModRoot2:
|
|
m_canBeRecalculated = false;
|
|
if (m_spellInfo.ProcFlags == 0)
|
|
break;
|
|
amount = (int)(GetBase().GetUnitOwner().CountPctFromMaxHealth(10));
|
|
break;
|
|
case AuraType.SchoolAbsorb:
|
|
case AuraType.ManaShield:
|
|
m_canBeRecalculated = false;
|
|
break;
|
|
case AuraType.Mounted:
|
|
uint mountType = (uint)GetMiscValueB();
|
|
MountRecord mountEntry = Global.DB2Mgr.GetMount(GetId());
|
|
if (mountEntry != null)
|
|
mountType = mountEntry.MountTypeID;
|
|
|
|
var mountCapability = GetBase().GetUnitOwner().GetMountCapability(mountType);
|
|
if (mountCapability != null)
|
|
{
|
|
amount = (int)mountCapability.Id;
|
|
m_canBeRecalculated = false;
|
|
}
|
|
break;
|
|
case AuraType.ShowConfirmationPromptWithDifficulty:
|
|
if (caster)
|
|
amount = (int)caster.GetMap().GetDifficultyID();
|
|
m_canBeRecalculated = false;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (GetSpellInfo().HasAttribute(SpellAttr10.RollingPeriodic))
|
|
{
|
|
var periodicAuras = GetBase().GetUnitOwner().GetAuraEffectsByType(GetAuraType());
|
|
amount = periodicAuras.Aggregate(0, (val, aurEff) =>
|
|
{
|
|
if (aurEff.GetCasterGUID() == GetCasterGUID() && aurEff.GetId() == GetId() && aurEff.GetEffIndex() == GetEffIndex() && aurEff.GetTotalTicks() > 0)
|
|
val += aurEff.GetAmount() * (int)aurEff.GetRemainingTicks() / (int)aurEff.GetTotalTicks();
|
|
return val;
|
|
});
|
|
}
|
|
|
|
GetBase().CallScriptEffectCalcAmountHandlers(this, ref amount, ref m_canBeRecalculated);
|
|
if (!GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes.NoScaleWithStack))
|
|
amount *= GetBase().GetStackAmount();
|
|
|
|
if (caster && GetBase().GetAuraType() == AuraObjectType.Unit)
|
|
{
|
|
uint stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes.NoScaleWithStack) ? GetBase().GetStackAmount() : 1u;
|
|
|
|
switch (GetAuraType())
|
|
{
|
|
case AuraType.PeriodicDamage:
|
|
case AuraType.PeriodicLeech:
|
|
_estimatedAmount = caster.SpellDamageBonusDone(GetBase().GetUnitOwner(), GetSpellInfo(), (uint)amount, DamageEffectType.DOT, GetSpellEffectInfo(), stackAmountForBonuses);
|
|
break;
|
|
case AuraType.PeriodicHeal:
|
|
_estimatedAmount = caster.SpellHealingBonusDone(GetBase().GetUnitOwner(), GetSpellInfo(), (uint)amount, DamageEffectType.DOT, GetSpellEffectInfo(), stackAmountForBonuses);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return amount;
|
|
}
|
|
|
|
public uint GetTotalTicks()
|
|
{
|
|
uint totalTicks = 0;
|
|
if (_period != 0 && !GetBase().IsPermanent())
|
|
{
|
|
totalTicks = (uint)(GetBase().GetMaxDuration() / _period);
|
|
if (m_spellInfo.HasAttribute(SpellAttr5.StartPeriodicAtApply))
|
|
++totalTicks;
|
|
}
|
|
|
|
return totalTicks;
|
|
}
|
|
|
|
void ResetPeriodic(bool resetPeriodicTimer = false)
|
|
{
|
|
_ticksDone = 0;
|
|
if (resetPeriodicTimer)
|
|
{
|
|
_periodicTimer = 0;
|
|
// Start periodic on next tick or at aura apply
|
|
if (m_spellInfo.HasAttribute(SpellAttr5.StartPeriodicAtApply))
|
|
_periodicTimer = _period;
|
|
}
|
|
}
|
|
public void CalculatePeriodic(Unit caster, bool resetPeriodicTimer = true, bool load = false)
|
|
{
|
|
_period = (int)GetSpellEffectInfo().ApplyAuraPeriod;
|
|
|
|
// prepare periodics
|
|
switch (GetAuraType())
|
|
{
|
|
case AuraType.ObsModPower:
|
|
case AuraType.PeriodicDamage:
|
|
case AuraType.PeriodicHeal:
|
|
case AuraType.ObsModHealth:
|
|
case AuraType.PeriodicTriggerSpell:
|
|
case AuraType.PeriodicEnergize:
|
|
case AuraType.PeriodicLeech:
|
|
case AuraType.PeriodicHealthFunnel:
|
|
case AuraType.PeriodicManaLeech:
|
|
case AuraType.PeriodicDamagePercent:
|
|
case AuraType.PowerBurn:
|
|
case AuraType.PeriodicDummy:
|
|
case AuraType.PeriodicTriggerSpellWithValue:
|
|
m_isPeriodic = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
GetBase().CallScriptEffectCalcPeriodicHandlers(this, ref m_isPeriodic, ref _period);
|
|
|
|
if (!m_isPeriodic)
|
|
return;
|
|
|
|
Player modOwner = caster != null ? caster.GetSpellModOwner() : null;
|
|
|
|
// Apply casting time mods
|
|
if (_period != 0)
|
|
{
|
|
// Apply periodic time mod
|
|
if (modOwner != null)
|
|
modOwner.ApplySpellMod(GetSpellInfo(), SpellModOp.Period, ref _period);
|
|
|
|
if (caster != null)
|
|
{
|
|
// Haste modifies periodic time of channeled spells
|
|
if (m_spellInfo.IsChanneled())
|
|
caster.ModSpellDurationTime(m_spellInfo, ref _period);
|
|
else if (m_spellInfo.HasAttribute(SpellAttr5.HasteAffectDuration))
|
|
_period = (int)(_period * caster.m_unitData.ModCastingSpeed);
|
|
}
|
|
}
|
|
else // prevent infinite loop on Update
|
|
m_isPeriodic = false;
|
|
|
|
if (load) // aura loaded from db
|
|
{
|
|
if (_period != 0 && !GetBase().IsPermanent())
|
|
{
|
|
uint elapsedTime = (uint)(GetBase().GetMaxDuration() - GetBase().GetDuration());
|
|
_ticksDone = elapsedTime / (uint)_period;
|
|
_periodicTimer = (int)(elapsedTime % _period);
|
|
}
|
|
|
|
if (m_spellInfo.HasAttribute(SpellAttr5.StartPeriodicAtApply))
|
|
++_ticksDone;
|
|
}
|
|
else // aura just created or reapplied
|
|
{
|
|
// reset periodic timer on aura create or reapply
|
|
// we don't reset periodic timers when aura is triggered by proc
|
|
ResetPeriodic(resetPeriodicTimer);
|
|
}
|
|
}
|
|
public void CalculateSpellMod()
|
|
{
|
|
switch (GetAuraType())
|
|
{
|
|
case AuraType.AddFlatModifier:
|
|
case AuraType.AddPctModifier:
|
|
if (m_spellmod == null)
|
|
{
|
|
SpellModifierByClassMask spellmod = new SpellModifierByClassMask(GetBase());
|
|
spellmod.op = (SpellModOp)GetMiscValue();
|
|
|
|
spellmod.type = GetAuraType() == AuraType.AddPctModifier ? SpellModType.Pct : SpellModType.Flat;
|
|
spellmod.spellId = GetId();
|
|
spellmod.mask = GetSpellEffectInfo().SpellClassMask;
|
|
m_spellmod = spellmod;
|
|
}
|
|
(m_spellmod as SpellModifierByClassMask).value = GetAmount();
|
|
break;
|
|
case AuraType.AddFlatModifierBySpellLabel:
|
|
if (m_spellmod == null)
|
|
{
|
|
SpellFlatModifierByLabel spellmod = new SpellFlatModifierByLabel(GetBase());
|
|
spellmod.op = (SpellModOp)GetMiscValue();
|
|
|
|
spellmod.type = SpellModType.LabelFlat;
|
|
spellmod.spellId = GetId();
|
|
spellmod.value.ModIndex = GetMiscValue();
|
|
spellmod.value.LabelID = GetMiscValueB();
|
|
m_spellmod = spellmod;
|
|
}
|
|
(m_spellmod as SpellFlatModifierByLabel).value.ModifierValue = GetAmount();
|
|
break;
|
|
case AuraType.AddPctModifierBySpellLabel:
|
|
if (m_spellmod == null)
|
|
{
|
|
SpellPctModifierByLabel spellmod = new SpellPctModifierByLabel(GetBase());
|
|
spellmod.op = (SpellModOp)GetMiscValue();
|
|
|
|
spellmod.type = SpellModType.LabelPct;
|
|
spellmod.spellId = GetId();
|
|
spellmod.value.ModIndex = GetMiscValue();
|
|
spellmod.value.LabelID = GetMiscValueB();
|
|
m_spellmod = spellmod;
|
|
}
|
|
(m_spellmod as SpellPctModifierByLabel).value.ModifierValue = 1.0f + MathFunctions.CalculatePct(1.0f, GetAmount());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
GetBase().CallScriptEffectCalcSpellModHandlers(this, ref m_spellmod);
|
|
}
|
|
public void ChangeAmount(int newAmount, bool mark = true, bool onStackOrReapply = false, AuraEffect triggeredBy = null)
|
|
{
|
|
// Reapply if amount change
|
|
AuraEffectHandleModes handleMask = 0;
|
|
if (newAmount != GetAmount())
|
|
handleMask |= AuraEffectHandleModes.ChangeAmount;
|
|
if (onStackOrReapply)
|
|
handleMask |= AuraEffectHandleModes.Reapply;
|
|
|
|
if (handleMask == 0)
|
|
return;
|
|
|
|
GetApplicationList(out List<AuraApplication> effectApplications);
|
|
|
|
foreach (var aurApp in effectApplications)
|
|
{
|
|
aurApp.GetTarget()._RegisterAuraEffect(this, false);
|
|
HandleEffect(aurApp, handleMask, false, triggeredBy);
|
|
}
|
|
|
|
if (Convert.ToBoolean(handleMask & AuraEffectHandleModes.ChangeAmount))
|
|
{
|
|
if (!mark)
|
|
_amount = newAmount;
|
|
else
|
|
SetAmount(newAmount);
|
|
CalculateSpellMod();
|
|
}
|
|
|
|
foreach (var aurApp in effectApplications)
|
|
{
|
|
if (aurApp.GetRemoveMode() != AuraRemoveMode.None)
|
|
continue;
|
|
|
|
aurApp.GetTarget()._RegisterAuraEffect(this, true);
|
|
HandleEffect(aurApp, handleMask, true, triggeredBy);
|
|
}
|
|
|
|
if (GetSpellInfo().HasAttribute(SpellAttr8.AuraSendAmount) || Aura.EffectTypeNeedsSendingAmount(GetAuraType()))
|
|
GetBase().SetNeedClientUpdateForTargets();
|
|
}
|
|
|
|
public void HandleEffect(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply, AuraEffect triggeredBy = null)
|
|
{
|
|
// check if call is correct, we really don't want using bitmasks here (with 1 exception)
|
|
Cypher.Assert(mode == AuraEffectHandleModes.Real || mode == AuraEffectHandleModes.SendForClient
|
|
|| mode == AuraEffectHandleModes.ChangeAmount || mode == AuraEffectHandleModes.Stat
|
|
|| mode == AuraEffectHandleModes.Skill || mode == AuraEffectHandleModes.Reapply
|
|
|| mode == (AuraEffectHandleModes.ChangeAmount | AuraEffectHandleModes.Reapply));
|
|
|
|
// register/unregister effect in lists in case of real AuraEffect apply/remove
|
|
// registration/unregistration is done always before real effect handling (some effect handlers code is depending on this)
|
|
if (mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
aurApp.GetTarget()._RegisterAuraEffect(this, apply);
|
|
|
|
// real aura apply/remove, handle modifier
|
|
if (mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask))
|
|
ApplySpellMod(aurApp.GetTarget(), apply, triggeredBy);
|
|
|
|
// call scripts helping/replacing effect handlers
|
|
bool prevented;
|
|
if (apply)
|
|
prevented = GetBase().CallScriptEffectApplyHandlers(this, aurApp, mode);
|
|
else
|
|
prevented = GetBase().CallScriptEffectRemoveHandlers(this, aurApp, mode);
|
|
|
|
// check if script events have removed the aura already
|
|
if (apply && aurApp.HasRemoveMode())
|
|
return;
|
|
|
|
// call default effect handler if it wasn't prevented
|
|
if (!prevented)
|
|
Global.SpellMgr.GetAuraEffectHandler(GetAuraType()).Invoke(this, aurApp, mode, apply);
|
|
|
|
// check if the default handler reemoved the aura
|
|
if (apply && aurApp.HasRemoveMode())
|
|
return;
|
|
|
|
// call scripts triggering additional events after apply/remove
|
|
if (apply)
|
|
GetBase().CallScriptAfterEffectApplyHandlers(this, aurApp, mode);
|
|
else
|
|
GetBase().CallScriptAfterEffectRemoveHandlers(this, aurApp, mode);
|
|
}
|
|
public void HandleEffect(Unit target, AuraEffectHandleModes mode, bool apply, AuraEffect triggeredBy = null)
|
|
{
|
|
AuraApplication aurApp = GetBase().GetApplicationOfTarget(target.GetGUID());
|
|
Cypher.Assert(aurApp != null);
|
|
HandleEffect(aurApp, mode, apply, triggeredBy);
|
|
}
|
|
|
|
void ApplySpellMod(Unit target, bool apply, AuraEffect triggeredBy = null)
|
|
{
|
|
if (m_spellmod == null || !target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
target.ToPlayer().AddSpellMod(m_spellmod, apply);
|
|
|
|
// Auras with charges do not mod amount of passive auras
|
|
if (GetBase().IsUsingCharges())
|
|
return;
|
|
// reapply some passive spells after add/remove related spellmods
|
|
// Warning: it is a dead loop if 2 auras each other amount-shouldn't happen
|
|
BitSet recalculateEffectMask = new(SpellConst.MaxEffects);
|
|
switch ((SpellModOp)GetMiscValue())
|
|
{
|
|
case SpellModOp.Points:
|
|
recalculateEffectMask.SetAll(true);
|
|
break;
|
|
case SpellModOp.PointsIndex0:
|
|
recalculateEffectMask.Set(0, true);
|
|
break;
|
|
case SpellModOp.PointsIndex1:
|
|
recalculateEffectMask.Set(1, true);
|
|
break;
|
|
case SpellModOp.PointsIndex2:
|
|
recalculateEffectMask.Set(2, true);
|
|
break;
|
|
case SpellModOp.PointsIndex3:
|
|
recalculateEffectMask.Set(3, true);
|
|
break;
|
|
case SpellModOp.PointsIndex4:
|
|
recalculateEffectMask.Set(4, true);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (recalculateEffectMask.Any())
|
|
{
|
|
if (triggeredBy == null)
|
|
triggeredBy = this;
|
|
|
|
ObjectGuid guid = target.GetGUID();
|
|
var auras = target.GetAppliedAuras();
|
|
foreach (var iter in auras)
|
|
{
|
|
Aura aura = iter.Value.GetBase();
|
|
// only passive and permament auras-active auras should have amount set on spellcast and not be affected
|
|
// if aura is cast by others, it will not be affected
|
|
if ((aura.IsPassive() || aura.IsPermanent()) && aura.GetCasterGUID() == guid && aura.GetSpellInfo().IsAffectedBySpellMod(m_spellmod))
|
|
{
|
|
for (uint i = 0; i < recalculateEffectMask.Count; ++i)
|
|
{
|
|
if (recalculateEffectMask[(int)i])
|
|
{
|
|
AuraEffect aurEff = aura.GetEffect(i);
|
|
if (aurEff != null)
|
|
if (aurEff != triggeredBy)
|
|
aurEff.RecalculateAmount(triggeredBy);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Update(uint diff, Unit caster)
|
|
{
|
|
if (!m_isPeriodic || (GetBase().GetDuration() < 0 && !GetBase().IsPassive() && !GetBase().IsPermanent()))
|
|
return;
|
|
|
|
uint totalTicks = GetTotalTicks();
|
|
|
|
_periodicTimer += (int)diff;
|
|
while (_periodicTimer >= _period)
|
|
{
|
|
_periodicTimer -= _period;
|
|
|
|
if (!GetBase().IsPermanent() && (_ticksDone + 1) > totalTicks)
|
|
break;
|
|
|
|
++_ticksDone;
|
|
|
|
GetBase().CallScriptEffectUpdatePeriodicHandlers(this);
|
|
|
|
GetApplicationList(out List<AuraApplication> effectApplications);
|
|
// tick on targets of effects
|
|
foreach (var appt in effectApplications)
|
|
PeriodicTick(appt, caster);
|
|
}
|
|
}
|
|
|
|
public float GetCritChanceFor(Unit caster, Unit target)
|
|
{
|
|
return target.SpellCritChanceTaken(caster, null, this, GetSpellInfo().GetSchoolMask(), CalcPeriodicCritChance(caster), GetSpellInfo().GetAttackType());
|
|
}
|
|
|
|
public bool IsAffectingSpell(SpellInfo spell)
|
|
{
|
|
if (spell == null)
|
|
return false;
|
|
|
|
// Check family name and EffectClassMask
|
|
if (!spell.IsAffected(m_spellInfo.SpellFamilyName, GetSpellEffectInfo().SpellClassMask))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void SendTickImmune(Unit target, Unit caster)
|
|
{
|
|
if (caster != null)
|
|
caster.SendSpellDamageImmune(target, m_spellInfo.Id, true);
|
|
}
|
|
|
|
void PeriodicTick(AuraApplication aurApp, Unit caster)
|
|
{
|
|
bool prevented = GetBase().CallScriptEffectPeriodicHandlers(this, aurApp);
|
|
if (prevented)
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
switch (GetAuraType())
|
|
{
|
|
case AuraType.PeriodicDummy:
|
|
// handled via scripts
|
|
break;
|
|
case AuraType.PeriodicTriggerSpell:
|
|
HandlePeriodicTriggerSpellAuraTick(target, caster);
|
|
break;
|
|
case AuraType.PeriodicTriggerSpellWithValue:
|
|
HandlePeriodicTriggerSpellWithValueAuraTick(target, caster);
|
|
break;
|
|
case AuraType.PeriodicDamage:
|
|
case AuraType.PeriodicWeaponPercentDamage:
|
|
case AuraType.PeriodicDamagePercent:
|
|
HandlePeriodicDamageAurasTick(target, caster);
|
|
break;
|
|
case AuraType.PeriodicLeech:
|
|
HandlePeriodicHealthLeechAuraTick(target, caster);
|
|
break;
|
|
case AuraType.PeriodicHealthFunnel:
|
|
HandlePeriodicHealthFunnelAuraTick(target, caster);
|
|
break;
|
|
case AuraType.PeriodicHeal:
|
|
case AuraType.ObsModHealth:
|
|
HandlePeriodicHealAurasTick(target, caster);
|
|
break;
|
|
case AuraType.PeriodicManaLeech:
|
|
HandlePeriodicManaLeechAuraTick(target, caster);
|
|
break;
|
|
case AuraType.ObsModPower:
|
|
HandleObsModPowerAuraTick(target, caster);
|
|
break;
|
|
case AuraType.PeriodicEnergize:
|
|
HandlePeriodicEnergizeAuraTick(target, caster);
|
|
break;
|
|
case AuraType.PowerBurn:
|
|
HandlePeriodicPowerBurnAuraTick(target, caster);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
public bool CheckEffectProc(AuraApplication aurApp, ProcEventInfo eventInfo)
|
|
{
|
|
bool result = GetBase().CallScriptCheckEffectProcHandlers(this, aurApp, eventInfo);
|
|
if (!result)
|
|
return false;
|
|
|
|
SpellInfo spellInfo = eventInfo.GetSpellInfo();
|
|
switch (GetAuraType())
|
|
{
|
|
case AuraType.ModConfuse:
|
|
case AuraType.ModFear:
|
|
case AuraType.ModStun:
|
|
case AuraType.ModRoot:
|
|
case AuraType.Transform:
|
|
{
|
|
DamageInfo damageInfo = eventInfo.GetDamageInfo();
|
|
if (damageInfo == null || damageInfo.GetDamage() == 0)
|
|
return false;
|
|
|
|
// Spell own damage at apply won't break CC
|
|
if (spellInfo != null && spellInfo == GetSpellInfo())
|
|
{
|
|
Aura aura = GetBase();
|
|
// called from spellcast, should not have ticked yet
|
|
if (aura.GetDuration() == aura.GetMaxDuration())
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case AuraType.MechanicImmunity:
|
|
case AuraType.ModMechanicResistance:
|
|
// compare mechanic
|
|
if (spellInfo == null || !Convert.ToBoolean(spellInfo.GetAllEffectsMechanicMask() & (1 << GetMiscValue())))
|
|
return false;
|
|
break;
|
|
case AuraType.ModCastingSpeedNotStack:
|
|
// skip melee hits and instant cast spells
|
|
if (!eventInfo.GetProcSpell() || eventInfo.GetProcSpell().GetCastTime() == 0)
|
|
return false;
|
|
break;
|
|
case AuraType.ModSchoolMaskDamageFromCaster:
|
|
case AuraType.ModSpellDamageFromCaster:
|
|
// Compare casters
|
|
if (GetCasterGUID() != eventInfo.GetActor().GetGUID())
|
|
return false;
|
|
break;
|
|
case AuraType.ModPowerCostSchool:
|
|
case AuraType.ModPowerCostSchoolPct:
|
|
{
|
|
// Skip melee hits and spells with wrong school or zero cost
|
|
if (spellInfo == null || !Convert.ToBoolean((int)spellInfo.GetSchoolMask() & GetMiscValue()) // School Check
|
|
|| !eventInfo.GetProcSpell())
|
|
return false;
|
|
|
|
// Costs Check
|
|
var costs = eventInfo.GetProcSpell().GetPowerCost();
|
|
var m = costs.Find(cost => cost.Amount > 0);
|
|
if (m == null)
|
|
return false;
|
|
break;
|
|
}
|
|
case AuraType.ReflectSpellsSchool:
|
|
// Skip melee hits and spells with wrong school
|
|
if (spellInfo == null || !Convert.ToBoolean((int)spellInfo.GetSchoolMask() & GetMiscValue()))
|
|
return false;
|
|
break;
|
|
case AuraType.ProcTriggerSpell:
|
|
case AuraType.ProcTriggerSpellWithValue:
|
|
{
|
|
// Don't proc extra attacks while already processing extra attack spell
|
|
uint triggerSpellId = GetSpellEffectInfo().TriggerSpell;
|
|
SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId, GetBase().GetCastDifficulty());
|
|
if (triggeredSpellInfo != null)
|
|
if (aurApp.GetTarget().ExtraAttacks != 0 && triggeredSpellInfo.HasEffect(SpellEffectName.AddExtraAttacks))
|
|
return false;
|
|
break;
|
|
}
|
|
case AuraType.ModSpellCritChance:
|
|
// skip spells that can't crit
|
|
if (spellInfo == null || !spellInfo.HasAttribute(SpellCustomAttributes.CanCrit))
|
|
return false;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public void HandleProc(AuraApplication aurApp, ProcEventInfo eventInfo)
|
|
{
|
|
bool prevented = GetBase().CallScriptEffectProcHandlers(this, aurApp, eventInfo);
|
|
if (prevented)
|
|
return;
|
|
|
|
switch (GetAuraType())
|
|
{
|
|
// CC Auras which use their amount to drop
|
|
// Are there any more auras which need this?
|
|
case AuraType.ModConfuse:
|
|
case AuraType.ModFear:
|
|
case AuraType.ModStun:
|
|
case AuraType.ModRoot:
|
|
case AuraType.Transform:
|
|
case AuraType.ModRoot2:
|
|
HandleBreakableCCAuraProc(aurApp, eventInfo);
|
|
break;
|
|
case AuraType.Dummy:
|
|
case AuraType.ProcTriggerSpell:
|
|
HandleProcTriggerSpellAuraProc(aurApp, eventInfo);
|
|
break;
|
|
case AuraType.ProcTriggerSpellWithValue:
|
|
HandleProcTriggerSpellWithValueAuraProc(aurApp, eventInfo);
|
|
break;
|
|
case AuraType.ProcTriggerDamage:
|
|
HandleProcTriggerDamageAuraProc(aurApp, eventInfo);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
GetBase().CallScriptAfterEffectProcHandlers(this, aurApp, eventInfo);
|
|
}
|
|
|
|
public void HandleShapeshiftBoosts(Unit target, bool apply)
|
|
{
|
|
uint spellId = 0;
|
|
uint spellId2 = 0;
|
|
uint spellId3 = 0;
|
|
uint spellId4 = 0;
|
|
|
|
switch ((ShapeShiftForm)GetMiscValue())
|
|
{
|
|
case ShapeShiftForm.CatForm:
|
|
spellId = 3025;
|
|
spellId2 = 48629;
|
|
spellId3 = 106840;
|
|
spellId4 = 113636;
|
|
break;
|
|
case ShapeShiftForm.TreeOfLife:
|
|
spellId = 5420;
|
|
spellId2 = 81097;
|
|
break;
|
|
case ShapeShiftForm.TravelForm:
|
|
spellId = 5419;
|
|
break;
|
|
case ShapeShiftForm.AquaticForm:
|
|
spellId = 5421;
|
|
break;
|
|
case ShapeShiftForm.BearForm:
|
|
spellId = 1178;
|
|
spellId2 = 21178;
|
|
spellId3 = 106829;
|
|
spellId4 = 106899;
|
|
break;
|
|
case ShapeShiftForm.FlightForm:
|
|
spellId = 33948;
|
|
spellId2 = 34764;
|
|
break;
|
|
case ShapeShiftForm.FlightFormEpic:
|
|
spellId = 40122;
|
|
spellId2 = 40121;
|
|
break;
|
|
case ShapeShiftForm.SpiritOfRedemption:
|
|
spellId = 27792;
|
|
spellId2 = 27795;
|
|
spellId3 = 62371;
|
|
break;
|
|
case ShapeShiftForm.Shadowform:
|
|
if (target.HasAura(107906)) // Glyph of Shadow
|
|
spellId = 107904;
|
|
else if (target.HasAura(126745)) // Glyph of Shadowy Friends
|
|
spellId = 142024;
|
|
else
|
|
spellId = 107903;
|
|
break;
|
|
case ShapeShiftForm.GhostWolf:
|
|
if (target.HasAura(58135)) // Glyph of Spectral Wolf
|
|
spellId = 160942;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (apply)
|
|
{
|
|
if (spellId != 0)
|
|
target.CastSpell(target, spellId, new CastSpellExtraArgs(this));
|
|
|
|
if (spellId2 != 0)
|
|
target.CastSpell(target, spellId2, new CastSpellExtraArgs(this));
|
|
|
|
if (spellId3 != 0)
|
|
target.CastSpell(target, spellId3, new CastSpellExtraArgs(this));
|
|
|
|
if (spellId4 != 0)
|
|
target.CastSpell(target, spellId4, new CastSpellExtraArgs(this));
|
|
|
|
if (target.IsTypeId(TypeId.Player))
|
|
{
|
|
Player plrTarget = target.ToPlayer();
|
|
|
|
var sp_list = plrTarget.GetSpellMap();
|
|
foreach (var pair in sp_list)
|
|
{
|
|
if (pair.Value.State == PlayerSpellState.Removed || pair.Value.Disabled)
|
|
continue;
|
|
|
|
if (pair.Key == spellId || pair.Key == spellId2 || pair.Key == spellId3 || pair.Key == spellId4)
|
|
continue;
|
|
|
|
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(pair.Key, Difficulty.None);
|
|
if (spellInfo == null || !(spellInfo.IsPassive() || spellInfo.HasAttribute(SpellAttr0.HiddenClientside)))
|
|
continue;
|
|
|
|
// always valid?
|
|
if (spellInfo.HasAttribute(SpellAttr8.MasterySpecialization) && !plrTarget.IsCurrentSpecMasterySpell(spellInfo))
|
|
continue;
|
|
|
|
if (Convert.ToBoolean(spellInfo.Stances & (1ul << (GetMiscValue() - 1))))
|
|
target.CastSpell(target, pair.Key, new CastSpellExtraArgs(this));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (spellId != 0)
|
|
target.RemoveOwnedAura(spellId, target.GetGUID());
|
|
if (spellId2 != 0)
|
|
target.RemoveOwnedAura(spellId2, target.GetGUID());
|
|
if (spellId3 != 0)
|
|
target.RemoveOwnedAura(spellId3, target.GetGUID());
|
|
if (spellId4 != 0)
|
|
target.RemoveOwnedAura(spellId4, target.GetGUID());
|
|
|
|
var shapeshifts = target.GetAuraEffectsByType(AuraType.ModShapeshift);
|
|
AuraEffect newAura = null;
|
|
// Iterate through all the shapeshift auras that the target has, if there is another aura with SPELL_AURA_MOD_SHAPESHIFT, then this aura is being removed due to that one being applied
|
|
foreach (var eff in shapeshifts)
|
|
{
|
|
if (eff != this)
|
|
{
|
|
newAura = eff;
|
|
break;
|
|
}
|
|
}
|
|
|
|
foreach (var app in target.GetAppliedAuras())
|
|
{
|
|
if (app.Value == null)
|
|
continue;
|
|
|
|
// Use the new aura to see on what stance the target will be
|
|
ulong newStance = newAura != null ? (1ul << (newAura.GetMiscValue() - 1)) : 0;
|
|
|
|
// If the stances are not compatible with the spell, remove it
|
|
if (app.Value.GetBase().IsRemovedOnShapeLost(target) && !Convert.ToBoolean(app.Value.GetBase().GetSpellInfo().Stances & newStance))
|
|
target.RemoveAura(app);
|
|
}
|
|
}
|
|
}
|
|
|
|
public Unit GetCaster() { return auraBase.GetCaster(); }
|
|
public ObjectGuid GetCasterGUID() { return auraBase.GetCasterGUID(); }
|
|
public Aura GetBase() { return auraBase; }
|
|
|
|
public SpellInfo GetSpellInfo() { return m_spellInfo; }
|
|
public uint GetId() { return m_spellInfo.Id; }
|
|
public uint GetEffIndex() { return _effectInfo.EffectIndex; }
|
|
public int GetBaseAmount() { return m_baseAmount; }
|
|
public int GetPeriod() { return _period; }
|
|
|
|
public int GetMiscValueB() { return GetSpellEffectInfo().MiscValueB; }
|
|
public int GetMiscValue() { return GetSpellEffectInfo().MiscValue; }
|
|
public AuraType GetAuraType() { return GetSpellEffectInfo().ApplyAuraName; }
|
|
public int GetAmount() { return _amount; }
|
|
public bool HasAmount() { return _amount != 0; }
|
|
public void SetAmount(int amount) { _amount = amount; m_canBeRecalculated = false; }
|
|
|
|
public float? GetEstimatedAmount() { return _estimatedAmount; }
|
|
|
|
public int GetPeriodicTimer() { return _periodicTimer; }
|
|
public void SetPeriodicTimer(int periodicTimer) { _periodicTimer = periodicTimer; }
|
|
|
|
void RecalculateAmount(AuraEffect triggeredBy = null)
|
|
{
|
|
if (!CanBeRecalculated())
|
|
return;
|
|
|
|
ChangeAmount(CalculateAmount(GetCaster()), false, false, triggeredBy);
|
|
}
|
|
public void RecalculateAmount(Unit caster, AuraEffect triggeredBy = null)
|
|
{
|
|
if (!CanBeRecalculated())
|
|
return;
|
|
|
|
ChangeAmount(CalculateAmount(caster), false, false, triggeredBy);
|
|
}
|
|
|
|
public bool CanBeRecalculated() { return m_canBeRecalculated; }
|
|
public void SetCanBeRecalculated(bool val) { m_canBeRecalculated = val; }
|
|
|
|
public void ResetTicks() { _ticksDone = 0; }
|
|
public uint GetTickNumber() { return _ticksDone; }
|
|
public uint GetRemainingTicks() { return GetTotalTicks() - _ticksDone; }
|
|
|
|
public bool IsPeriodic() { return m_isPeriodic; }
|
|
public void SetPeriodic(bool isPeriodic) { m_isPeriodic = isPeriodic; }
|
|
bool HasSpellClassMask() { return GetSpellEffectInfo().SpellClassMask; }
|
|
|
|
public SpellEffectInfo GetSpellEffectInfo() { return _effectInfo; }
|
|
|
|
public bool IsEffect() { return _effectInfo.Effect != 0; }
|
|
public bool IsEffect(SpellEffectName effectName) { return _effectInfo.Effect == effectName; }
|
|
public bool IsAreaAuraEffect()
|
|
{
|
|
return _effectInfo.IsAreaAuraEffect();
|
|
}
|
|
|
|
#region Fields
|
|
Aura auraBase;
|
|
SpellInfo m_spellInfo;
|
|
SpellEffectInfo _effectInfo;
|
|
SpellModifier m_spellmod;
|
|
|
|
public int m_baseAmount;
|
|
int _amount;
|
|
float? _estimatedAmount; // for periodic damage and healing auras this will include damage done bonuses
|
|
|
|
// periodic stuff
|
|
int _periodicTimer;
|
|
int _period; // time between consecutive ticks
|
|
uint _ticksDone; // ticks counter
|
|
|
|
bool m_canBeRecalculated;
|
|
bool m_isPeriodic;
|
|
#endregion
|
|
|
|
#region AuraEffect Handlers
|
|
/**************************************/
|
|
/*** VISIBILITY & PHASES ***/
|
|
/**************************************/
|
|
[AuraEffectHandler(AuraType.None)]
|
|
void HandleUnused(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModInvisibilityDetect)]
|
|
void HandleModInvisibilityDetect(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
InvisibilityType type = (InvisibilityType)GetMiscValue();
|
|
|
|
if (apply)
|
|
{
|
|
target.m_invisibilityDetect.AddFlag(type);
|
|
target.m_invisibilityDetect.AddValue(type, GetAmount());
|
|
}
|
|
else
|
|
{
|
|
if (!target.HasAuraType(AuraType.ModInvisibilityDetect))
|
|
target.m_invisibilityDetect.DelFlag(type);
|
|
|
|
target.m_invisibilityDetect.AddValue(type, -GetAmount());
|
|
}
|
|
|
|
// call functions which may have additional effects after chainging state of unit
|
|
target.UpdateObjectVisibility();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModInvisibility)]
|
|
void HandleModInvisibility(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountSendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
InvisibilityType type = (InvisibilityType)GetMiscValue();
|
|
|
|
if (apply)
|
|
{
|
|
// apply glow vision
|
|
Player playerTarget = target.ToPlayer();
|
|
if (playerTarget != null)
|
|
playerTarget.AddAuraVision(PlayerFieldByte2Flags.InvisibilityGlow);
|
|
|
|
target.m_invisibility.AddFlag(type);
|
|
target.m_invisibility.AddValue(type, GetAmount());
|
|
}
|
|
else
|
|
{
|
|
if (!target.HasAuraType(AuraType.ModInvisibility))
|
|
{
|
|
// if not have different invisibility auras.
|
|
// remove glow vision
|
|
Player playerTarget = target.ToPlayer();
|
|
if (playerTarget != null)
|
|
playerTarget.RemoveAuraVision(PlayerFieldByte2Flags.InvisibilityGlow);
|
|
|
|
target.m_invisibility.DelFlag(type);
|
|
}
|
|
else
|
|
{
|
|
bool found = false;
|
|
var invisAuras = target.GetAuraEffectsByType(AuraType.ModInvisibility);
|
|
foreach (var eff in invisAuras)
|
|
{
|
|
if (GetMiscValue() == eff.GetMiscValue())
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
target.m_invisibility.DelFlag(type);
|
|
}
|
|
|
|
target.m_invisibility.AddValue(type, -GetAmount());
|
|
}
|
|
|
|
// call functions which may have additional effects after chainging state of unit
|
|
if (apply && mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
{
|
|
// drop flag at invisibiliy in bg
|
|
target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis);
|
|
}
|
|
target.UpdateObjectVisibility();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModStealthDetect)]
|
|
void HandleModStealthDetect(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
StealthType type = (StealthType)GetMiscValue();
|
|
|
|
if (apply)
|
|
{
|
|
target.m_stealthDetect.AddFlag(type);
|
|
target.m_stealthDetect.AddValue(type, GetAmount());
|
|
}
|
|
else
|
|
{
|
|
if (!target.HasAuraType(AuraType.ModStealthDetect))
|
|
target.m_stealthDetect.DelFlag(type);
|
|
|
|
target.m_stealthDetect.AddValue(type, -GetAmount());
|
|
}
|
|
|
|
// call functions which may have additional effects after chainging state of unit
|
|
target.UpdateObjectVisibility();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModStealth)]
|
|
void HandleModStealth(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountSendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
StealthType type = (StealthType)GetMiscValue();
|
|
|
|
if (apply)
|
|
{
|
|
target.m_stealth.AddFlag(type);
|
|
target.m_stealth.AddValue(type, GetAmount());
|
|
target.AddVisFlags(UnitVisFlags.Creep);
|
|
Player playerTarget = target.ToPlayer();
|
|
if (playerTarget != null)
|
|
playerTarget.AddAuraVision(PlayerFieldByte2Flags.Stealth);
|
|
}
|
|
else
|
|
{
|
|
target.m_stealth.AddValue(type, -GetAmount());
|
|
|
|
if (!target.HasAuraType(AuraType.ModStealth)) // if last SPELL_AURA_MOD_STEALTH
|
|
{
|
|
target.m_stealth.DelFlag(type);
|
|
|
|
target.RemoveVisFlags(UnitVisFlags.Creep);
|
|
Player playerTarget = target.ToPlayer();
|
|
if (playerTarget != null)
|
|
playerTarget.RemoveAuraVision(PlayerFieldByte2Flags.Stealth);
|
|
}
|
|
}
|
|
|
|
// call functions which may have additional effects after chainging state of unit
|
|
if (apply && mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
{
|
|
// drop flag at stealth in bg
|
|
target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis);
|
|
}
|
|
target.UpdateObjectVisibility();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModStealthLevel)]
|
|
void HandleModStealthLevel(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
StealthType type = (StealthType)GetMiscValue();
|
|
|
|
if (apply)
|
|
target.m_stealth.AddValue(type, GetAmount());
|
|
else
|
|
target.m_stealth.AddValue(type, -GetAmount());
|
|
|
|
// call functions which may have additional effects after chainging state of unit
|
|
target.UpdateObjectVisibility();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.DetectAmore)]
|
|
void HandleDetectAmore(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
if (apply)
|
|
{
|
|
Player playerTarget = target.ToPlayer();
|
|
if (playerTarget != null)
|
|
{
|
|
playerTarget.AddAuraVision((PlayerFieldByte2Flags)(1 << (GetMiscValue() - 1)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (target.HasAuraType(AuraType.DetectAmore))
|
|
{
|
|
var amoreAuras = target.GetAuraEffectsByType(AuraType.DetectAmore);
|
|
foreach (var auraEffect in amoreAuras)
|
|
{
|
|
if (GetMiscValue() == auraEffect.GetMiscValue())
|
|
return;
|
|
}
|
|
}
|
|
|
|
Player playerTarget = target.ToPlayer();
|
|
if (playerTarget != null)
|
|
playerTarget.RemoveAuraVision((PlayerFieldByte2Flags)(1 << (GetMiscValue() - 1)));
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.SpiritOfRedemption)]
|
|
void HandleSpiritOfRedemption(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
// prepare spirit state
|
|
if (apply)
|
|
{
|
|
if (target.IsTypeId(TypeId.Player))
|
|
{
|
|
// set stand state (expected in this form)
|
|
if (!target.IsStandState())
|
|
target.SetStandState(UnitStandStateType.Stand);
|
|
}
|
|
}
|
|
// die at aura end
|
|
else if (target.IsAlive())
|
|
// call functions which may have additional effects after chainging state of unit
|
|
target.SetDeathState(DeathState.JustDied);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.Ghost)]
|
|
void HandleAuraGhost(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (target == null)
|
|
return;
|
|
|
|
if (apply)
|
|
{
|
|
target.AddPlayerFlag(PlayerFlags.Ghost);
|
|
target.m_serverSideVisibility.SetValue(ServerSideVisibilityType.Ghost, GhostVisibilityType.Ghost);
|
|
target.m_serverSideVisibilityDetect.SetValue(ServerSideVisibilityType.Ghost, GhostVisibilityType.Ghost);
|
|
}
|
|
else
|
|
{
|
|
if (target.HasAuraType(AuraType.Ghost))
|
|
return;
|
|
|
|
target.RemovePlayerFlag(PlayerFlags.Ghost);
|
|
target.m_serverSideVisibility.SetValue(ServerSideVisibilityType.Ghost, GhostVisibilityType.Alive);
|
|
target.m_serverSideVisibilityDetect.SetValue(ServerSideVisibilityType.Ghost, GhostVisibilityType.Alive);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.Phase)]
|
|
void HandlePhase(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
PhasingHandler.AddPhase(target, (uint)GetMiscValueB(), true);
|
|
else
|
|
PhasingHandler.RemovePhase(target, (uint)GetMiscValueB(), true);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.PhaseGroup)]
|
|
void HandlePhaseGroup(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
PhasingHandler.AddPhaseGroup(target, (uint)GetMiscValueB(), true);
|
|
else
|
|
PhasingHandler.RemovePhaseGroup(target, (uint)GetMiscValueB(), true);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.PhaseAlwaysVisible)]
|
|
void HandlePhaseAlwaysVisible(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!apply)
|
|
PhasingHandler.SetAlwaysVisible(target, true, true);
|
|
else
|
|
{
|
|
if (target.HasAuraType(AuraType.PhaseAlwaysVisible) || (target.IsPlayer() && target.ToPlayer().IsGameMaster()))
|
|
return;
|
|
|
|
PhasingHandler.SetAlwaysVisible(target, false, true);
|
|
}
|
|
}
|
|
|
|
/**********************/
|
|
/*** UNIT MODEL ***/
|
|
/**********************/
|
|
[AuraEffectHandler(AuraType.ModShapeshift)]
|
|
void HandleAuraModShapeshift(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.RealOrReapplyMask))
|
|
return;
|
|
|
|
SpellShapeshiftFormRecord shapeInfo = CliDB.SpellShapeshiftFormStorage.LookupByKey(GetMiscValue());
|
|
//ASSERT(shapeInfo, "Spell {0} uses unknown ShapeshiftForm (%u).", GetId(), GetMiscValue());
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
ShapeShiftForm form = (ShapeShiftForm)GetMiscValue();
|
|
uint modelid = target.GetModelForForm(form, GetId());
|
|
|
|
if (apply)
|
|
{
|
|
// remove polymorph before changing display id to keep new display id
|
|
switch (form)
|
|
{
|
|
case ShapeShiftForm.CatForm:
|
|
case ShapeShiftForm.TreeOfLife:
|
|
case ShapeShiftForm.TravelForm:
|
|
case ShapeShiftForm.AquaticForm:
|
|
case ShapeShiftForm.BearForm:
|
|
case ShapeShiftForm.FlightFormEpic:
|
|
case ShapeShiftForm.FlightForm:
|
|
case ShapeShiftForm.MoonkinForm:
|
|
{
|
|
// remove movement affects
|
|
target.RemoveAurasByShapeShift();
|
|
|
|
// and polymorphic affects
|
|
if (target.IsPolymorphed())
|
|
target.RemoveAurasDueToSpell(target.GetTransformSpell());
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// remove other shapeshift before applying a new one
|
|
target.RemoveAurasByType(AuraType.ModShapeshift, ObjectGuid.Empty, GetBase());
|
|
|
|
// stop handling the effect if it was removed by linked event
|
|
if (aurApp.HasRemoveMode())
|
|
return;
|
|
|
|
ShapeShiftForm prevForm = target.GetShapeshiftForm();
|
|
target.SetShapeshiftForm(form);
|
|
// add the shapeshift aura's boosts
|
|
if (prevForm != form)
|
|
HandleShapeshiftBoosts(target, true);
|
|
|
|
if (modelid > 0)
|
|
{
|
|
SpellInfo transformSpellInfo = Global.SpellMgr.GetSpellInfo(target.GetTransformSpell(), GetBase().GetCastDifficulty());
|
|
if (transformSpellInfo == null || !GetSpellInfo().IsPositive())
|
|
target.SetDisplayId(modelid);
|
|
}
|
|
|
|
if (!shapeInfo.Flags.HasAnyFlag(SpellShapeshiftFormFlags.Stance))
|
|
target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Shapeshifting, GetId());
|
|
}
|
|
else
|
|
{
|
|
// reset model id if no other auras present
|
|
// may happen when aura is applied on linked event on aura removal
|
|
if (!target.HasAuraType(AuraType.ModShapeshift))
|
|
{
|
|
target.SetShapeshiftForm(ShapeShiftForm.None);
|
|
if (target.GetClass() == Class.Druid)
|
|
{
|
|
// Remove movement impairing effects also when shifting out
|
|
target.RemoveAurasByShapeShift();
|
|
}
|
|
}
|
|
|
|
if (modelid > 0)
|
|
target.RestoreDisplayId(target.IsMounted());
|
|
|
|
switch (form)
|
|
{
|
|
// Nordrassil Harness - bonus
|
|
case ShapeShiftForm.BearForm:
|
|
case ShapeShiftForm.CatForm:
|
|
AuraEffect dummy = target.GetAuraEffect(37315, 0);
|
|
if (dummy != null)
|
|
target.CastSpell(target, 37316, new CastSpellExtraArgs(dummy));
|
|
break;
|
|
// Nordrassil Regalia - bonus
|
|
case ShapeShiftForm.MoonkinForm:
|
|
dummy = target.GetAuraEffect(37324, 0);
|
|
if (dummy != null)
|
|
target.CastSpell(target, 37325, new CastSpellExtraArgs(dummy));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// remove the shapeshift aura's boosts
|
|
HandleShapeshiftBoosts(target, apply);
|
|
}
|
|
|
|
Player playerTarget = target.ToPlayer();
|
|
if (playerTarget != null)
|
|
{
|
|
playerTarget.SendMovementSetCollisionHeight(playerTarget.GetCollisionHeight(), UpdateCollisionHeightReason.Force);
|
|
playerTarget.InitDataForForm();
|
|
}
|
|
else
|
|
target.UpdateDisplayPower();
|
|
|
|
if (target.GetClass() == Class.Druid)
|
|
{
|
|
// Dash
|
|
AuraEffect aurEff = target.GetAuraEffect(AuraType.ModIncreaseSpeed, SpellFamilyNames.Druid, new FlagArray128(0, 0, 0x8));
|
|
if (aurEff != null)
|
|
aurEff.RecalculateAmount();
|
|
|
|
// Disarm handling
|
|
// If druid shifts while being disarmed we need to deal with that since forms aren't affected by disarm
|
|
// and also HandleAuraModDisarm is not triggered
|
|
if (!target.CanUseAttackType(WeaponAttackType.BaseAttack))
|
|
{
|
|
Item pItem = target.ToPlayer().GetItemByPos(InventorySlots.Bag0, EquipmentSlot.MainHand);
|
|
if (pItem != null)
|
|
target.ToPlayer()._ApplyWeaponDamage(EquipmentSlot.MainHand, pItem, apply);
|
|
}
|
|
}
|
|
|
|
// stop handling the effect if it was removed by linked event
|
|
if (apply && aurApp.HasRemoveMode())
|
|
return;
|
|
|
|
if (target.IsTypeId(TypeId.Player))
|
|
{
|
|
// Learn spells for shapeshift form - no need to send action bars or add spells to spellbook
|
|
for (byte i = 0; i < SpellConst.MaxShapeshift; ++i)
|
|
{
|
|
if (shapeInfo.PresetSpellID[i] == 0)
|
|
continue;
|
|
if (apply)
|
|
target.ToPlayer().AddTemporarySpell(shapeInfo.PresetSpellID[i]);
|
|
else
|
|
target.ToPlayer().RemoveTemporarySpell(shapeInfo.PresetSpellID[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.Transform)]
|
|
void HandleAuraTransform(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
{
|
|
// update active transform spell only when transform not set or not overwriting negative by positive case
|
|
SpellInfo transformSpellInfo = Global.SpellMgr.GetSpellInfo(target.GetTransformSpell(), GetBase().GetCastDifficulty());
|
|
if (transformSpellInfo == null || !GetSpellInfo().IsPositive() || transformSpellInfo.IsPositive())
|
|
{
|
|
target.SetTransformSpell(GetId());
|
|
// special case (spell specific functionality)
|
|
if (GetMiscValue() == 0)
|
|
{
|
|
switch (GetId())
|
|
{
|
|
// Orb of Deception
|
|
case 16739:
|
|
{
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
switch (target.GetRace())
|
|
{
|
|
// Blood Elf
|
|
case Race.BloodElf:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 17830 : 17829u);
|
|
break;
|
|
// Orc
|
|
case Race.Orc:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 10140 : 10139u);
|
|
break;
|
|
// Troll
|
|
case Race.Troll:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 10134 : 10135u);
|
|
break;
|
|
// Tauren
|
|
case Race.Tauren:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 10147 : 10136u);
|
|
break;
|
|
// Undead
|
|
case Race.Undead:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 10145 : 10146u);
|
|
break;
|
|
// Draenei
|
|
case Race.Draenei:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 17828 : 17827u);
|
|
break;
|
|
// Dwarf
|
|
case Race.Dwarf:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 10142 : 10141u);
|
|
break;
|
|
// Gnome
|
|
case Race.Gnome:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 10149 : 10148u);
|
|
break;
|
|
// Human
|
|
case Race.Human:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 10138 : 10137u);
|
|
break;
|
|
// Night Elf
|
|
case Race.NightElf:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 10144 : 10143u);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
// Murloc costume
|
|
case 42365:
|
|
target.SetDisplayId(21723);
|
|
break;
|
|
// Dread Corsair
|
|
case 50517:
|
|
// Corsair Costume
|
|
case 51926:
|
|
{
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
switch (target.GetRace())
|
|
{
|
|
// Blood Elf
|
|
case Race.BloodElf:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 25043 : 25032u);
|
|
break;
|
|
// Orc
|
|
case Race.Orc:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 25050 : 25039u);
|
|
break;
|
|
// Troll
|
|
case Race.Troll:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 25052 : 25041u);
|
|
break;
|
|
// Tauren
|
|
case Race.Tauren:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 25051 : 25040u);
|
|
break;
|
|
// Undead
|
|
case Race.Undead:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 25053 : 25042u);
|
|
break;
|
|
// Draenei
|
|
case Race.Draenei:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 25044 : 25033u);
|
|
break;
|
|
// Dwarf
|
|
case Race.Dwarf:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 25045 : 25034u);
|
|
break;
|
|
// Gnome
|
|
case Race.Gnome:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 25035 : 25046u);
|
|
break;
|
|
// Human
|
|
case Race.Human:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 25037 : 25048u);
|
|
break;
|
|
// Night Elf
|
|
case Race.NightElf:
|
|
target.SetDisplayId(target.GetGender() == Gender.Female ? 25038 : 25049u);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
// Pygmy Oil
|
|
case 53806:
|
|
target.SetDisplayId(22512);
|
|
break;
|
|
// Honor the Dead
|
|
case 65386:
|
|
case 65495:
|
|
target.SetDisplayId(target.GetGender() == Gender.Male ? 29203 : 29204u);
|
|
break;
|
|
// Darkspear Pride
|
|
case 75532:
|
|
target.SetDisplayId(target.GetGender() == Gender.Male ? 31737 : 31738u);
|
|
break;
|
|
// Gnomeregan Pride
|
|
case 75531:
|
|
target.SetDisplayId(target.GetGender() == Gender.Male ? 31654 : 31655u);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CreatureTemplate ci = Global.ObjectMgr.GetCreatureTemplate((uint)GetMiscValue());
|
|
if (ci == null)
|
|
{
|
|
target.SetDisplayId(16358); // pig pink ^_^
|
|
Log.outError(LogFilter.Spells, "Auras: unknown creature id = {0} (only need its modelid) From Spell Aura Transform in Spell ID = {1}", GetMiscValue(), GetId());
|
|
}
|
|
else
|
|
{
|
|
uint model_id = 0;
|
|
uint modelid = ObjectManager.ChooseDisplayId(ci).CreatureDisplayID;
|
|
if (modelid != 0)
|
|
model_id = modelid; // Will use the default model here
|
|
|
|
target.SetDisplayId(model_id);
|
|
|
|
// Dragonmaw Illusion (set mount model also)
|
|
if (GetId() == 42016 && target.GetMountDisplayId() != 0 && !target.GetAuraEffectsByType(AuraType.ModIncreaseMountedFlightSpeed).Empty())
|
|
target.SetMountDisplayId(16314);
|
|
}
|
|
}
|
|
}
|
|
|
|
// polymorph case
|
|
if (mode.HasAnyFlag(AuraEffectHandleModes.Real) && target.IsTypeId(TypeId.Player) && target.IsPolymorphed())
|
|
{
|
|
// for players, start regeneration after 1s (in polymorph fast regeneration case)
|
|
// only if caster is Player (after patch 2.4.2)
|
|
if (GetCasterGUID().IsPlayer())
|
|
target.ToPlayer().SetRegenTimerCount(1 * Time.InMilliseconds);
|
|
|
|
//dismount polymorphed target (after patch 2.4.2)
|
|
if (target.IsMounted())
|
|
target.RemoveAurasByType(AuraType.Mounted);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (target.GetTransformSpell() == GetId())
|
|
target.SetTransformSpell(0);
|
|
|
|
target.RestoreDisplayId(target.IsMounted());
|
|
|
|
// Dragonmaw Illusion (restore mount model)
|
|
if (GetId() == 42016 && target.GetMountDisplayId() == 16314)
|
|
{
|
|
if (!target.GetAuraEffectsByType(AuraType.Mounted).Empty())
|
|
{
|
|
int cr_id = target.GetAuraEffectsByType(AuraType.Mounted)[0].GetMiscValue();
|
|
CreatureTemplate ci = Global.ObjectMgr.GetCreatureTemplate((uint)cr_id);
|
|
if (ci != null)
|
|
{
|
|
CreatureModel model = ObjectManager.ChooseDisplayId(ci);
|
|
Global.ObjectMgr.GetCreatureModelRandomGender(ref model, ci);
|
|
|
|
target.SetMountDisplayId(model.CreatureDisplayID);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModScale)]
|
|
[AuraEffectHandler(AuraType.ModScale2)]
|
|
void HandleAuraModScale(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountSendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
float scale = target.GetObjectScale();
|
|
scale += MathFunctions.CalculatePct(1.0f, apply ? GetAmount() : -GetAmount());
|
|
target.SetObjectScale(scale);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.CloneCaster)]
|
|
void HandleAuraCloneCaster(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
{
|
|
Unit caster = GetCaster();
|
|
if (caster == null || caster == target)
|
|
return;
|
|
|
|
// What must be cloned? at least display and scale
|
|
target.SetDisplayId(caster.GetDisplayId());
|
|
//target.SetObjectScale(caster.GetFloatValue(OBJECT_FIELD_SCALE_X)); // we need retail info about how scaling is handled (aura maybe?)
|
|
target.AddUnitFlag2(UnitFlags2.MirrorImage);
|
|
}
|
|
else
|
|
{
|
|
target.SetDisplayId(target.GetNativeDisplayId());
|
|
target.RemoveUnitFlag2(UnitFlags2.MirrorImage);
|
|
}
|
|
}
|
|
|
|
/************************/
|
|
/*** FIGHT ***/
|
|
/************************/
|
|
[AuraEffectHandler(AuraType.FeignDeath)]
|
|
void HandleFeignDeath(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
{
|
|
List<Unit> targets = new();
|
|
var u_check = new AnyUnfriendlyUnitInObjectRangeCheck(target, target, target.GetMap().GetVisibilityRange());
|
|
var searcher = new UnitListSearcher(target, targets, u_check);
|
|
|
|
Cell.VisitAllObjects(target, searcher, target.GetMap().GetVisibilityRange());
|
|
foreach (var unit in targets)
|
|
{
|
|
if (!unit.HasUnitState(UnitState.Casting))
|
|
continue;
|
|
|
|
for (var i = CurrentSpellTypes.Generic; i < CurrentSpellTypes.Max; i++)
|
|
{
|
|
if (unit.GetCurrentSpell(i) != null
|
|
&& unit.GetCurrentSpell(i).m_targets.GetUnitTargetGUID() == target.GetGUID())
|
|
{
|
|
unit.InterruptSpell(i, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (target.GetMap().IsDungeon()) // feign death does not remove combat in dungeons
|
|
{
|
|
target.AttackStop();
|
|
Player targetPlayer = target.ToPlayer();
|
|
if (targetPlayer != null)
|
|
targetPlayer.SendAttackSwingCancelAttack();
|
|
}
|
|
else
|
|
target.CombatStop(false, false);
|
|
|
|
// prevent interrupt message
|
|
if (GetCasterGUID() == target.GetGUID() && target.GetCurrentSpell(CurrentSpellTypes.Generic) != null)
|
|
target.FinishSpell(CurrentSpellTypes.Generic, false);
|
|
target.InterruptNonMeleeSpells(true);
|
|
|
|
// stop handling the effect if it was removed by linked event
|
|
if (aurApp.HasRemoveMode())
|
|
return;
|
|
|
|
target.AddUnitFlag(UnitFlags.Unk29);
|
|
target.AddUnitFlag2(UnitFlags2.FeignDeath);
|
|
target.AddDynamicFlag(UnitDynFlags.Dead);
|
|
target.AddUnitState(UnitState.Died);
|
|
|
|
Creature creature = target.ToCreature();
|
|
if (creature != null)
|
|
creature.SetReactState(ReactStates.Passive);
|
|
}
|
|
else
|
|
{
|
|
target.RemoveUnitFlag(UnitFlags.Unk29);
|
|
target.RemoveUnitFlag2(UnitFlags2.FeignDeath);
|
|
target.RemoveDynamicFlag(UnitDynFlags.Dead);
|
|
target.ClearUnitState(UnitState.Died);
|
|
|
|
Creature creature = target.ToCreature();
|
|
if (creature != null)
|
|
creature.InitializeReactState();
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModUnattackable)]
|
|
void HandleModUnattackable(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (!apply && target.HasAuraType(AuraType.ModUnattackable))
|
|
return;
|
|
|
|
if (apply)
|
|
target.AddUnitFlag(UnitFlags.NonAttackable2);
|
|
else
|
|
target.RemoveUnitFlag(UnitFlags.NonAttackable2);
|
|
|
|
// call functions which may have additional effects after chainging state of unit
|
|
if (apply && mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
{
|
|
if (target.GetMap().IsDungeon())
|
|
{
|
|
target.AttackStop();
|
|
Player targetPlayer = target.ToPlayer();
|
|
if (targetPlayer != null)
|
|
targetPlayer.SendAttackSwingCancelAttack();
|
|
}
|
|
else
|
|
target.CombatStop();
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModDisarm)]
|
|
void HandleAuraModDisarm(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
//Prevent handling aura twice
|
|
AuraType type = GetAuraType();
|
|
|
|
if (apply ? target.GetAuraEffectsByType(type).Count > 1 : target.HasAuraType(type))
|
|
return;
|
|
|
|
Action<Unit> flagChangeFunc = null;
|
|
byte slot;
|
|
WeaponAttackType attType;
|
|
switch (type)
|
|
{
|
|
case AuraType.ModDisarm:
|
|
if (apply)
|
|
flagChangeFunc = unit => { unit.AddUnitFlag(UnitFlags.Disarmed); };
|
|
else
|
|
flagChangeFunc = unit => { unit.RemoveUnitFlag(UnitFlags.Disarmed); };
|
|
slot = EquipmentSlot.MainHand;
|
|
attType = WeaponAttackType.BaseAttack;
|
|
break;
|
|
case AuraType.ModDisarmOffhand:
|
|
if (apply)
|
|
flagChangeFunc = unit => { unit.AddUnitFlag2(UnitFlags2.DisarmOffhand); };
|
|
else
|
|
flagChangeFunc = unit => { unit.RemoveUnitFlag2(UnitFlags2.DisarmOffhand); };
|
|
slot = EquipmentSlot.OffHand;
|
|
attType = WeaponAttackType.OffAttack;
|
|
break;
|
|
case AuraType.ModDisarmRanged:
|
|
if (apply)
|
|
flagChangeFunc = unit => { unit.AddUnitFlag2(UnitFlags2.DisarmRanged); };
|
|
else
|
|
flagChangeFunc = unit => { unit.RemoveUnitFlag2(UnitFlags2.DisarmRanged); };
|
|
slot = EquipmentSlot.MainHand;
|
|
attType = WeaponAttackType.RangedAttack;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
// set/remove flag before weapon bonuses so it's properly reflected in CanUseAttackType
|
|
flagChangeFunc?.Invoke(target);
|
|
|
|
// Handle damage modification, shapeshifted druids are not affected
|
|
if (target.IsTypeId(TypeId.Player) && !target.IsInFeralForm())
|
|
{
|
|
Player player = target.ToPlayer();
|
|
|
|
Item item = player.GetItemByPos(InventorySlots.Bag0, slot);
|
|
if (item != null)
|
|
{
|
|
WeaponAttackType attackType = Player.GetAttackBySlot(slot, item.GetTemplate().GetInventoryType());
|
|
|
|
player.ApplyItemDependentAuras(item, !apply);
|
|
if (attackType < WeaponAttackType.Max)
|
|
{
|
|
player._ApplyWeaponDamage(slot, item, !apply);
|
|
if (!apply) // apply case already handled on item dependent aura removal (if any)
|
|
player.UpdateWeaponDependentAuras(attackType);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (target.IsTypeId(TypeId.Unit) && target.ToCreature().GetCurrentEquipmentId() != 0)
|
|
target.UpdateDamagePhysical(attType);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModSilence)]
|
|
void HandleAuraModSilence(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
{
|
|
target.AddUnitFlag(UnitFlags.Silenced);
|
|
|
|
// call functions which may have additional effects after chainging state of unit
|
|
// Stop cast only spells vs PreventionType & SPELL_PREVENTION_TYPE_SILENCE
|
|
for (var i = CurrentSpellTypes.Melee; i < CurrentSpellTypes.Max; ++i)
|
|
{
|
|
Spell spell = target.GetCurrentSpell(i);
|
|
if (spell != null)
|
|
if (spell.m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Silence))
|
|
// Stop spells on prepare or casting state
|
|
target.InterruptSpell(i, false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (target.HasAuraType(AuraType.ModSilence) || target.HasAuraType(AuraType.ModPacifySilence))
|
|
return;
|
|
|
|
target.RemoveUnitFlag(UnitFlags.Silenced);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModPacify)]
|
|
void HandleAuraModPacify(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
target.AddUnitFlag(UnitFlags.Pacified);
|
|
else
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (target.HasAuraType(AuraType.ModPacify) || target.HasAuraType(AuraType.ModPacifySilence))
|
|
return;
|
|
target.RemoveUnitFlag(UnitFlags.Pacified);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModPacifySilence)]
|
|
void HandleAuraModPacifyAndSilence(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
// Vengeance of the Blue Flight (@todo REMOVE THIS!)
|
|
// @workaround
|
|
if (m_spellInfo.Id == 45839)
|
|
{
|
|
if (apply)
|
|
target.AddUnitFlag(UnitFlags.NonAttackable);
|
|
else
|
|
target.RemoveUnitFlag(UnitFlags.NonAttackable);
|
|
}
|
|
if (!(apply))
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (target.HasAuraType(AuraType.ModPacifySilence))
|
|
return;
|
|
}
|
|
HandleAuraModPacify(aurApp, mode, apply);
|
|
HandleAuraModSilence(aurApp, mode, apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.DisableAttackingExceptAbilities)]
|
|
void HandleAuraDisableAttackingExceptAbilities(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
if (apply)
|
|
aurApp.GetTarget().AttackStop();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModNoActions)]
|
|
void HandleAuraModNoActions(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
{
|
|
target.AddUnitFlag2(UnitFlags2.NoActions);
|
|
|
|
// call functions which may have additional effects after chainging state of unit
|
|
// Stop cast only spells vs PreventionType & SPELL_PREVENTION_TYPE_SILENCE
|
|
for (var i = CurrentSpellTypes.Melee; i < CurrentSpellTypes.Max; ++i)
|
|
{
|
|
Spell spell = target.GetCurrentSpell(i);
|
|
if (spell)
|
|
if (spell.m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.NoActions))
|
|
// Stop spells on prepare or casting state
|
|
target.InterruptSpell(i, false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (target.HasAuraType(AuraType.ModNoActions))
|
|
return;
|
|
|
|
target.RemoveUnitFlag2(UnitFlags2.NoActions);
|
|
}
|
|
}
|
|
|
|
/****************************/
|
|
/*** TRACKING ***/
|
|
/****************************/
|
|
[AuraEffectHandler(AuraType.TrackCreatures)]
|
|
void HandleAuraTrackCreatures(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (target == null)
|
|
return;
|
|
|
|
if (apply)
|
|
target.AddTrackCreatureFlag(1u << (GetMiscValue() - 1));
|
|
else
|
|
target.RemoveTrackCreatureFlag(1u << (GetMiscValue() - 1));
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.TrackStealthed)]
|
|
void HandleAuraTrackStealthed(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (target == null)
|
|
return;
|
|
|
|
if (!(apply))
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (target.HasAuraType(GetAuraType()))
|
|
return;
|
|
}
|
|
if (apply)
|
|
target.AddPlayerLocalFlag(PlayerLocalFlags.TrackStealthed);
|
|
else
|
|
target.RemovePlayerLocalFlag(PlayerLocalFlags.TrackStealthed);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModStalked)]
|
|
void HandleAuraModStalked(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
// used by spells: Hunter's Mark, Mind Vision, Syndicate Tracker (MURP) DND
|
|
if (apply)
|
|
target.AddDynamicFlag(UnitDynFlags.TrackUnit);
|
|
else
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (!target.HasAuraType(GetAuraType()))
|
|
target.RemoveDynamicFlag(UnitDynFlags.TrackUnit);
|
|
}
|
|
|
|
// call functions which may have additional effects after chainging state of unit
|
|
target.UpdateObjectVisibility();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.Untrackable)]
|
|
void HandleAuraUntrackable(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (target == null)
|
|
return;
|
|
|
|
if (apply)
|
|
target.AddVisFlags(UnitVisFlags.Untrackable);
|
|
else
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (target.HasAuraType(GetAuraType()))
|
|
return;
|
|
target.RemoveVisFlags(UnitVisFlags.Untrackable);
|
|
}
|
|
}
|
|
|
|
/****************************/
|
|
/*** SKILLS & TALENTS ***/
|
|
/****************************/
|
|
[AuraEffectHandler(AuraType.ModSkill)]
|
|
[AuraEffectHandler(AuraType.ModSkill2)]
|
|
void HandleAuraModSkill(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Skill)))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (target == null)
|
|
return;
|
|
|
|
SkillType prot = (SkillType)GetMiscValue();
|
|
int points = GetAmount();
|
|
|
|
if (prot == SkillType.Defense)
|
|
return;
|
|
|
|
target.ModifySkillBonus(prot, (apply ? points : -points), GetAuraType() == AuraType.ModSkillTalent);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.AllowTalentSwapping)]
|
|
void HandleAuraAllowTalentSwapping(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (target == null)
|
|
return;
|
|
|
|
if (apply)
|
|
target.AddUnitFlag2(UnitFlags2.AllowChangingTalents);
|
|
else if (!target.HasAuraType(GetAuraType()))
|
|
target.RemoveUnitFlag2(UnitFlags2.AllowChangingTalents);
|
|
}
|
|
|
|
/****************************/
|
|
/*** MOVEMENT ***/
|
|
/****************************/
|
|
[AuraEffectHandler(AuraType.Mounted)]
|
|
void HandleAuraMounted(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
{
|
|
uint creatureEntry = (uint)GetMiscValue();
|
|
uint displayId = 0;
|
|
uint vehicleId = 0;
|
|
|
|
MountRecord mountEntry = Global.DB2Mgr.GetMount(GetId());
|
|
if (mountEntry != null)
|
|
{
|
|
var mountDisplays = Global.DB2Mgr.GetMountDisplays(mountEntry.Id);
|
|
if (mountDisplays != null)
|
|
{
|
|
if (mountEntry.IsSelfMount())
|
|
{
|
|
displayId = 73200; //DisplayId: HiddenMount
|
|
}
|
|
else
|
|
{
|
|
List<MountXDisplayRecord> usableDisplays = mountDisplays.Where(mountDisplay =>
|
|
{
|
|
Player playerTarget = target.ToPlayer();
|
|
if (playerTarget)
|
|
{
|
|
PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(mountDisplay.PlayerConditionID);
|
|
if (playerCondition != null)
|
|
return ConditionManager.IsPlayerMeetingCondition(playerTarget, playerCondition);
|
|
}
|
|
|
|
return true;
|
|
}).ToList();
|
|
|
|
if (!usableDisplays.Empty())
|
|
displayId = usableDisplays.SelectRandom().CreatureDisplayInfoID;
|
|
}
|
|
}
|
|
// TODO: CREATE TABLE mount_vehicle (mountId, vehicleCreatureId) for future mounts that are vehicles (new mounts no longer have proper data in MiscValue)
|
|
//if (MountVehicle const* mountVehicle = sObjectMgr.GetMountVehicle(mountEntry.Id))
|
|
// creatureEntry = mountVehicle.VehicleCreatureId;
|
|
}
|
|
|
|
CreatureTemplate creatureInfo = Global.ObjectMgr.GetCreatureTemplate(creatureEntry);
|
|
if (creatureInfo != null)
|
|
{
|
|
vehicleId = creatureInfo.VehicleId;
|
|
|
|
if (displayId == 0)
|
|
{
|
|
CreatureModel model = ObjectManager.ChooseDisplayId(creatureInfo);
|
|
Global.ObjectMgr.GetCreatureModelRandomGender(ref model, creatureInfo);
|
|
displayId = model.CreatureDisplayID;
|
|
}
|
|
|
|
//some spell has one aura of mount and one of vehicle
|
|
foreach (var spellEffectInfo in GetSpellInfo().GetEffects())
|
|
if (spellEffectInfo.IsEffect(SpellEffectName.Summon) && spellEffectInfo.MiscValue == GetMiscValue())
|
|
displayId = 0;
|
|
}
|
|
|
|
target.Mount(displayId, vehicleId, creatureEntry);
|
|
|
|
// cast speed aura
|
|
if (mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
{
|
|
var mountCapability = CliDB.MountCapabilityStorage.LookupByKey(GetAmount());
|
|
if (mountCapability != null)
|
|
target.CastSpell(target, mountCapability.ModSpellAuraID, new CastSpellExtraArgs(this));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
target.Dismount();
|
|
//some mounts like Headless Horseman's Mount or broom stick are skill based spell
|
|
// need to remove ALL arura related to mounts, this will stop client crash with broom stick
|
|
// and never endless flying after using Headless Horseman's Mount
|
|
if (mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
{
|
|
target.RemoveAurasByType(AuraType.Mounted);
|
|
|
|
// remove speed aura
|
|
var mountCapability = CliDB.MountCapabilityStorage.LookupByKey(GetAmount());
|
|
if (mountCapability != null)
|
|
target.RemoveAurasDueToSpell(mountCapability.ModSpellAuraID, target.GetGUID());
|
|
}
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.Fly)]
|
|
void HandleAuraAllowFlight(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!apply)
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (target.HasAuraType(GetAuraType()) || target.HasAuraType(AuraType.ModIncreaseMountedFlightSpeed))
|
|
return;
|
|
}
|
|
|
|
target.SetCanTransitionBetweenSwimAndFly(apply);
|
|
|
|
if (target.SetCanFly(apply))
|
|
if (!apply && !target.IsLevitating())
|
|
target.GetMotionMaster().MoveFall();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.WaterWalk)]
|
|
void HandleAuraWaterWalk(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!apply)
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (target.HasAuraType(GetAuraType()))
|
|
return;
|
|
}
|
|
|
|
target.SetWaterWalking(apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.FeatherFall)]
|
|
void HandleAuraFeatherFall(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!apply)
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (target.HasAuraType(GetAuraType()))
|
|
return;
|
|
}
|
|
|
|
target.SetFeatherFall(apply);
|
|
|
|
// start fall from current height
|
|
if (!apply && target.IsTypeId(TypeId.Player))
|
|
target.ToPlayer().SetFallInformation(0, target.GetPositionZ());
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.Hover)]
|
|
void HandleAuraHover(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!apply)
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (target.HasAuraType(GetAuraType()))
|
|
return;
|
|
}
|
|
|
|
target.SetHover(apply); //! Sets movementflags
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.WaterBreathing)]
|
|
void HandleWaterBreathing(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
// update timers in client
|
|
if (target.IsTypeId(TypeId.Player))
|
|
target.ToPlayer().UpdateMirrorTimers();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ForceMoveForward)]
|
|
void HandleForceMoveForward(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
target.AddUnitFlag2(UnitFlags2.ForceMove);
|
|
else
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (target.HasAuraType(GetAuraType()))
|
|
return;
|
|
target.RemoveUnitFlag2(UnitFlags2.ForceMove);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.CanTurnWhileFalling)]
|
|
void HandleAuraCanTurnWhileFalling(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!apply)
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (target.HasAuraType(GetAuraType()))
|
|
return;
|
|
}
|
|
|
|
target.SetCanTurnWhileFalling(apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.IgnoreMovementForces)]
|
|
void HandleIgnoreMovementForces(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
if (!apply)
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (target.HasAuraType(GetAuraType()))
|
|
return;
|
|
}
|
|
|
|
target.SetIgnoreMovementForces(apply);
|
|
}
|
|
|
|
/****************************/
|
|
/*** THREAT ***/
|
|
/****************************/
|
|
[AuraEffectHandler(AuraType.ModThreat)]
|
|
void HandleModThreat(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask))
|
|
return;
|
|
|
|
aurApp.GetTarget().GetThreatManager().UpdateMySpellSchoolModifiers();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModTotalThreat)]
|
|
void HandleAuraModTotalThreat(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsAlive() || !target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
Unit caster = GetCaster();
|
|
if (caster != null && caster.IsAlive())
|
|
caster.GetThreatManager().UpdateMyTempModifiers();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModTaunt)]
|
|
void HandleModTaunt(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsAlive() || !target.CanHaveThreatList())
|
|
return;
|
|
|
|
target.GetThreatManager().TauntUpdate();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModDetaunt)]
|
|
void HandleModDetaunt(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit caster = GetCaster();
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!caster || !caster.IsAlive() || !target.IsAlive() || !caster.CanHaveThreatList())
|
|
return;
|
|
|
|
caster.GetThreatManager().TauntUpdate();
|
|
}
|
|
|
|
/*****************************/
|
|
/*** CONTROL ***/
|
|
/*****************************/
|
|
[AuraEffectHandler(AuraType.ModConfuse)]
|
|
void HandleModConfuse(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
target.SetControlled(apply, UnitState.Confused);
|
|
|
|
if (apply)
|
|
target.GetThreatManager().EvaluateSuppressed();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModFear)]
|
|
void HandleModFear(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
target.SetControlled(apply, UnitState.Fleeing);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModStun)]
|
|
void HandleAuraModStun(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
target.SetControlled(apply, UnitState.Stunned);
|
|
|
|
if (apply)
|
|
target.GetThreatManager().EvaluateSuppressed();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModRoot)]
|
|
[AuraEffectHandler(AuraType.ModRoot2)]
|
|
void HandleAuraModRoot(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
target.SetControlled(apply, UnitState.Root);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.PreventsFleeing)]
|
|
void HandlePreventFleeing(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
// Since patch 3.0.2 this mechanic no longer affects fear effects. It will ONLY prevent humanoids from fleeing due to low health.
|
|
if (!apply || target.HasAuraType(AuraType.ModFear))
|
|
return;
|
|
// TODO: find a way to cancel fleeing for assistance.
|
|
// Currently this will only stop creatures fleeing due to low health that could not find nearby allies to flee towards.
|
|
target.SetControlled(false, UnitState.Fleeing);
|
|
}
|
|
|
|
/***************************/
|
|
/*** CHARM ***/
|
|
/***************************/
|
|
[AuraEffectHandler(AuraType.ModPossess)]
|
|
void HandleModPossess(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
Unit caster = GetCaster();
|
|
|
|
// no support for posession AI yet
|
|
if (caster != null && caster.IsTypeId(TypeId.Unit))
|
|
{
|
|
HandleModCharm(aurApp, mode, apply);
|
|
return;
|
|
}
|
|
|
|
if (apply)
|
|
target.SetCharmedBy(caster, CharmType.Possess, aurApp);
|
|
else
|
|
target.RemoveCharmedBy(caster);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModPossessPet)]
|
|
void HandleModPossessPet(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit caster = GetCaster();
|
|
if (caster == null || !caster.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
if (!target.IsTypeId(TypeId.Unit) || !target.IsPet())
|
|
return;
|
|
|
|
Pet pet = target.ToPet();
|
|
|
|
if (apply)
|
|
{
|
|
if (caster.ToPlayer().GetPet() != pet)
|
|
return;
|
|
|
|
pet.SetCharmedBy(caster, CharmType.Possess, aurApp);
|
|
}
|
|
else
|
|
{
|
|
pet.RemoveCharmedBy(caster);
|
|
|
|
if (!pet.IsWithinDistInMap(caster, pet.GetMap().GetVisibilityRange()))
|
|
pet.Remove(PetSaveMode.NotInSlot, true);
|
|
else
|
|
{
|
|
// Reinitialize the pet bar or it will appear greyed out
|
|
caster.ToPlayer().PetSpellInitialize();
|
|
|
|
// TODO: remove this
|
|
if (pet.GetVictim() == null && !pet.GetCharmInfo().HasCommandState(CommandStates.Stay))
|
|
pet.GetMotionMaster().MoveFollow(caster, SharedConst.PetFollowDist, pet.GetFollowAngle());
|
|
}
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModCharm)]
|
|
void HandleModCharm(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
Unit caster = GetCaster();
|
|
|
|
if (apply)
|
|
target.SetCharmedBy(caster, CharmType.Charm, aurApp);
|
|
else
|
|
target.RemoveCharmedBy(caster);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.AoeCharm)]
|
|
void HandleCharmConvert(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
Unit caster = GetCaster();
|
|
|
|
if (apply)
|
|
target.SetCharmedBy(caster, CharmType.Convert, aurApp);
|
|
else
|
|
target.RemoveCharmedBy(caster);
|
|
}
|
|
|
|
/**
|
|
* Such auras are applied from a caster(=player) to a vehicle.
|
|
* This has been verified using spell #49256
|
|
*/
|
|
[AuraEffectHandler(AuraType.ControlVehicle)]
|
|
void HandleAuraControlVehicle(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
if (!target.IsVehicle())
|
|
return;
|
|
|
|
Unit caster = GetCaster();
|
|
if (caster == null || caster == target)
|
|
return;
|
|
|
|
if (apply)
|
|
{
|
|
// Currently spells that have base points 0 and DieSides 0 = "0/0" exception are pushed to -1,
|
|
// however the idea of 0/0 is to ingore flag VEHICLE_SEAT_FLAG_CAN_ENTER_OR_EXIT and -1 checks for it,
|
|
// so this break such spells or most of them.
|
|
// Current formula about m_amount: effect base points + dieside - 1
|
|
// TO DO: Reasearch more about 0/0 and fix it.
|
|
caster._EnterVehicle(target.GetVehicleKit(), (sbyte)(GetAmount() - 1), aurApp);
|
|
}
|
|
else
|
|
{
|
|
// Remove pending passengers before exiting vehicle - might cause an Uninstall
|
|
target.GetVehicleKit().RemovePendingEventsForPassenger(caster);
|
|
|
|
if (GetId() == 53111) // Devour Humanoid
|
|
{
|
|
Unit.Kill(target, caster);
|
|
if (caster.IsTypeId(TypeId.Unit))
|
|
caster.ToCreature().DespawnOrUnsummon();
|
|
}
|
|
|
|
bool seatChange = mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmount) // Seat change on the same direct vehicle
|
|
|| target.HasAuraTypeWithCaster(AuraType.ControlVehicle, caster.GetGUID()); // Seat change to a proxy vehicle (for example turret mounted on a siege engine)
|
|
|
|
if (!seatChange)
|
|
caster._ExitVehicle();
|
|
else
|
|
target.GetVehicleKit().RemovePassenger(caster); // Only remove passenger from vehicle without launching exit movement or despawning the vehicle
|
|
|
|
// some SPELL_AURA_CONTROL_VEHICLE auras have a dummy effect on the player - remove them
|
|
caster.RemoveAurasDueToSpell(GetId());
|
|
}
|
|
}
|
|
|
|
/*********************************************************/
|
|
/*** MODIFY SPEED ***/
|
|
/*********************************************************/
|
|
[AuraEffectHandler(AuraType.ModIncreaseSpeed)]
|
|
[AuraEffectHandler(AuraType.ModSpeedAlways)]
|
|
[AuraEffectHandler(AuraType.ModSpeedNotStack)]
|
|
[AuraEffectHandler(AuraType.ModMinimumSpeed)]
|
|
void HandleAuraModIncreaseSpeed(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
target.UpdateSpeed(UnitMoveType.Run);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModIncreaseMountedSpeed)]
|
|
[AuraEffectHandler(AuraType.ModMountedSpeedAlways)]
|
|
[AuraEffectHandler(AuraType.ModMountedSpeedNotStack)]
|
|
void HandleAuraModIncreaseMountedSpeed(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
HandleAuraModIncreaseSpeed(aurApp, mode, apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModIncreaseVehicleFlightSpeed)]
|
|
[AuraEffectHandler(AuraType.ModIncreaseMountedFlightSpeed)]
|
|
[AuraEffectHandler(AuraType.ModIncreaseFlightSpeed)]
|
|
[AuraEffectHandler(AuraType.ModMountedFlightSpeedAlways)]
|
|
[AuraEffectHandler(AuraType.ModVehicleSpeedAlways)]
|
|
[AuraEffectHandler(AuraType.ModFlightSpeedNotStack)]
|
|
void HandleAuraModIncreaseFlightSpeed(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountSendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
if (mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask))
|
|
target.UpdateSpeed(UnitMoveType.Flight);
|
|
|
|
//! Update ability to fly
|
|
if (GetAuraType() == AuraType.ModIncreaseMountedFlightSpeed)
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask) && (apply || (!target.HasAuraType(AuraType.ModIncreaseMountedFlightSpeed) && !target.HasAuraType(AuraType.Fly))))
|
|
{
|
|
target.SetCanTransitionBetweenSwimAndFly(apply);
|
|
|
|
if (target.SetCanFly(apply))
|
|
if (!apply && !target.IsLevitating())
|
|
target.GetMotionMaster().MoveFall();
|
|
}
|
|
|
|
//! Someone should clean up these hacks and remove it from this function. It doesn't even belong here.
|
|
if (mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
{
|
|
//Players on flying mounts must be immune to polymorph
|
|
if (target.IsTypeId(TypeId.Player))
|
|
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, (uint)Mechanics.Polymorph, apply);
|
|
|
|
// Dragonmaw Illusion (overwrite mount model, mounted aura already applied)
|
|
if (apply && target.HasAuraEffect(42016, 0) && target.GetMountDisplayId() != 0)
|
|
target.SetMountDisplayId(16314);
|
|
}
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModIncreaseSwimSpeed)]
|
|
void HandleAuraModIncreaseSwimSpeed(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
target.UpdateSpeed(UnitMoveType.Swim);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModDecreaseSpeed)]
|
|
void HandleAuraModDecreaseSpeed(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
target.UpdateSpeed(UnitMoveType.Run);
|
|
target.UpdateSpeed(UnitMoveType.Swim);
|
|
target.UpdateSpeed(UnitMoveType.Flight);
|
|
target.UpdateSpeed(UnitMoveType.RunBack);
|
|
target.UpdateSpeed(UnitMoveType.SwimBack);
|
|
target.UpdateSpeed(UnitMoveType.FlightBack);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.UseNormalMovementSpeed)]
|
|
void HandleAuraModUseNormalSpeed(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
target.UpdateSpeed(UnitMoveType.Run);
|
|
target.UpdateSpeed(UnitMoveType.Swim);
|
|
target.UpdateSpeed(UnitMoveType.Flight);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModMinimumSpeedRate)]
|
|
void HandleAuraModMinimumSpeedRate(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
target.UpdateSpeed(UnitMoveType.Run);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModMovementForceMagnitude)]
|
|
void HandleModMovementForceMagnitude(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask))
|
|
return;
|
|
|
|
aurApp.GetTarget().UpdateMovementForcesModMagnitude();
|
|
}
|
|
|
|
/*********************************************************/
|
|
/*** IMMUNITY ***/
|
|
/*********************************************************/
|
|
[AuraEffectHandler(AuraType.MechanicImmunityMask)]
|
|
void HandleModMechanicImmunityMask(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.MechanicImmunity)]
|
|
void HandleModMechanicImmunity(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.EffectImmunity)]
|
|
void HandleAuraModEffectImmunity(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
|
|
|
|
// when removing flag aura, handle flag drop
|
|
// TODO: this should be handled in aura script for flag spells using AfterEffectRemove hook
|
|
Player player = target.ToPlayer();
|
|
if (!apply && player != null && GetSpellInfo().HasAuraInterruptFlag(SpellAuraInterruptFlags.StealthOrInvis))
|
|
{
|
|
if (player.InBattleground())
|
|
{
|
|
Battleground bg = player.GetBattleground();
|
|
if (bg)
|
|
bg.EventPlayerDroppedFlag(player);
|
|
}
|
|
else
|
|
Global.OutdoorPvPMgr.HandleDropFlag(player, GetSpellInfo().Id);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.StateImmunity)]
|
|
void HandleAuraModStateImmunity(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.SchoolImmunity)]
|
|
void HandleAuraModSchoolImmunity(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
|
|
|
|
if (GetSpellInfo().Mechanic == Mechanics.Banish)
|
|
{
|
|
if (apply)
|
|
target.AddUnitState(UnitState.Isolated);
|
|
else
|
|
{
|
|
bool banishFound = false;
|
|
var banishAuras = target.GetAuraEffectsByType(GetAuraType());
|
|
foreach (var aurEff in banishAuras)
|
|
{
|
|
if (aurEff.GetSpellInfo().Mechanic == Mechanics.Banish)
|
|
{
|
|
banishFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!banishFound)
|
|
target.ClearUnitState(UnitState.Isolated);
|
|
}
|
|
}
|
|
|
|
// TODO: should be changed to a proc script on flag spell (they have "Taken positive" proc flags in db2)
|
|
{
|
|
if (apply && GetMiscValue() == (int)SpellSchoolMask.Normal)
|
|
target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis);
|
|
|
|
// remove all flag auras (they are positive, but they must be removed when you are immune)
|
|
if (GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity)
|
|
&& GetSpellInfo().HasAttribute(SpellAttr2.DamageReducedShield))
|
|
target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis);
|
|
}
|
|
|
|
if (apply)
|
|
target.GetThreatManager().EvaluateSuppressed();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.DamageImmunity)]
|
|
void HandleAuraModDmgImmunity(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
|
|
|
|
if (apply)
|
|
target.GetThreatManager().EvaluateSuppressed();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.DispelImmunity)]
|
|
void HandleAuraModDispelImmunity(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
|
|
}
|
|
|
|
/*********************************************************/
|
|
/*** MODIFY STATS ***/
|
|
/*********************************************************/
|
|
|
|
/********************************/
|
|
/*** RESISTANCE ***/
|
|
/********************************/
|
|
[AuraEffectHandler(AuraType.ModResistance)]
|
|
void HandleAuraModResistance(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
for (byte x = (byte)SpellSchools.Normal; x < (byte)SpellSchools.Max; x++)
|
|
if (Convert.ToBoolean(GetMiscValue() & (1 << x)))
|
|
target.HandleStatFlatModifier(UnitMods.ResistanceStart + x, UnitModifierFlatType.Total, GetAmount(), apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModBaseResistancePct)]
|
|
void HandleAuraModBaseResistancePCT(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
// only players have base stats
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
{
|
|
//pets only have base armor
|
|
if (target.IsPet() && Convert.ToBoolean(GetMiscValue() & (int)SpellSchoolMask.Normal))
|
|
{
|
|
if (apply)
|
|
target.ApplyStatPctModifier(UnitMods.Armor, UnitModifierPctType.Base, GetAmount());
|
|
else
|
|
{
|
|
float amount = target.GetTotalAuraMultiplierByMiscMask(AuraType.ModBaseResistancePct, (uint)SpellSchoolMask.Normal);
|
|
target.SetStatPctModifier(UnitMods.Armor, UnitModifierPctType.Base, amount);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (byte x = (byte)SpellSchools.Normal; x < (byte)SpellSchools.Max; x++)
|
|
{
|
|
if (Convert.ToBoolean(GetMiscValue() & (1 << x)))
|
|
{
|
|
if (apply)
|
|
target.ApplyStatPctModifier(UnitMods.ResistanceStart + x, UnitModifierPctType.Base, GetAmount());
|
|
else
|
|
{
|
|
float amount = target.GetTotalAuraMultiplierByMiscMask(AuraType.ModBaseResistancePct, 1u << x);
|
|
target.SetStatPctModifier(UnitMods.ResistanceStart + x, UnitModifierPctType.Base, amount);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModResistancePct)]
|
|
void HandleModResistancePercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
for (byte i = (byte)SpellSchools.Normal; i < (byte)SpellSchools.Max; i++)
|
|
{
|
|
if (Convert.ToBoolean(GetMiscValue() & (1 << i)))
|
|
{
|
|
float amount = target.GetTotalAuraMultiplierByMiscMask(AuraType.ModResistancePct, 1u << i);
|
|
if (target.GetPctModifierValue(UnitMods.ResistanceStart + i, UnitModifierPctType.Total) == amount)
|
|
continue;
|
|
|
|
target.SetStatPctModifier(UnitMods.ResistanceStart + i, UnitModifierPctType.Total, amount);
|
|
}
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModBaseResistance)]
|
|
void HandleModBaseResistance(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
// only players have base stats
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
{
|
|
//only pets have base stats
|
|
if (target.IsPet() && Convert.ToBoolean(GetMiscValue() & (int)SpellSchoolMask.Normal))
|
|
target.HandleStatFlatModifier(UnitMods.Armor, UnitModifierFlatType.Total, GetAmount(), apply);
|
|
}
|
|
else
|
|
{
|
|
for (byte i = (byte)SpellSchools.Normal; i < (byte)SpellSchools.Max; i++)
|
|
if (Convert.ToBoolean(GetMiscValue() & (1 << i)))
|
|
target.HandleStatFlatModifier(UnitMods.ResistanceStart + i, UnitModifierFlatType.Total, GetAmount(), apply);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModTargetResistance)]
|
|
void HandleModTargetResistance(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (target == null)
|
|
return;
|
|
|
|
// applied to damage as HandleNoImmediateEffect in Unit.CalcAbsorbResist and Unit.CalcArmorReducedDamage
|
|
|
|
// show armor penetration
|
|
if (target.IsTypeId(TypeId.Player) && Convert.ToBoolean(GetMiscValue() & (int)SpellSchoolMask.Normal))
|
|
target.ApplyModTargetPhysicalResistance(GetAmount(), apply);
|
|
|
|
// show as spell penetration only full spell penetration bonuses (all resistances except armor and holy
|
|
if (target.IsTypeId(TypeId.Player) && ((SpellSchoolMask)GetMiscValue() & SpellSchoolMask.Spell) == SpellSchoolMask.Spell)
|
|
target.ApplyModTargetResistance(GetAmount(), apply);
|
|
}
|
|
|
|
/********************************/
|
|
/*** STAT ***/
|
|
/********************************/
|
|
[AuraEffectHandler(AuraType.ModStat)]
|
|
void HandleAuraModStat(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
if (GetMiscValue() < -2 || GetMiscValue() > 4)
|
|
{
|
|
Log.outError(LogFilter.Spells, "WARNING: Spell {0} effect {1} has an unsupported misc value ({2}) for SPELL_AURA_MOD_STAT ", GetId(), GetEffIndex(), GetMiscValue());
|
|
return;
|
|
}
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
int spellGroupVal = target.GetHighestExclusiveSameEffectSpellGroupValue(this, AuraType.ModStat, true, GetMiscValue());
|
|
if (Math.Abs(spellGroupVal) >= Math.Abs(GetAmount()))
|
|
return;
|
|
|
|
for (var i = Stats.Strength; i < Stats.Max; i++)
|
|
{
|
|
// -1 or -2 is all stats (misc < -2 checked in function beginning)
|
|
if (GetMiscValue() < 0 || GetMiscValue() == (int)i)
|
|
{
|
|
if (spellGroupVal != 0)
|
|
{
|
|
target.HandleStatFlatModifier((UnitMods.StatStart + (int)i), UnitModifierFlatType.Total, (float)spellGroupVal, !apply);
|
|
if (target.IsTypeId(TypeId.Player) || target.IsPet())
|
|
target.UpdateStatBuffMod(i);
|
|
}
|
|
|
|
target.HandleStatFlatModifier(UnitMods.StatStart + (int)i, UnitModifierFlatType.Total, GetAmount(), apply);
|
|
if (target.IsTypeId(TypeId.Player) || target.IsPet())
|
|
target.UpdateStatBuffMod(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModPercentStat)]
|
|
void HandleModPercentStat(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (GetMiscValue() < -1 || GetMiscValue() > 4)
|
|
{
|
|
Log.outError(LogFilter.Spells, "WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid");
|
|
return;
|
|
}
|
|
|
|
// only players have base stats
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
for (int i = (int)Stats.Strength; i < (int)Stats.Max; ++i)
|
|
{
|
|
if (GetMiscValue() == i || GetMiscValue() == -1)
|
|
{
|
|
if (apply)
|
|
target.ApplyStatPctModifier(UnitMods.StatStart + i, UnitModifierPctType.Base, GetAmount());
|
|
else
|
|
{
|
|
float amount = target.GetTotalAuraMultiplier(AuraType.ModPercentStat, aurEff =>
|
|
{
|
|
if (aurEff.GetMiscValue() == i || aurEff.GetMiscValue() == -1)
|
|
return true;
|
|
return false;
|
|
});
|
|
target.SetStatPctModifier(UnitMods.StatStart + i, UnitModifierPctType.Base, amount);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModSpellDamageOfStatPercent)]
|
|
void HandleModSpellDamagePercentFromStat(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
// Magic damage modifiers implemented in Unit.SpellDamageBonus
|
|
// This information for client side use only
|
|
// Recalculate bonus
|
|
target.ToPlayer().UpdateSpellDamageAndHealingBonus();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModSpellHealingOfStatPercent)]
|
|
void HandleModSpellHealingPercentFromStat(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
// Recalculate bonus
|
|
target.ToPlayer().UpdateSpellDamageAndHealingBonus();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModHealingDone)]
|
|
void HandleModHealingDone(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
// implemented in Unit.SpellHealingBonus
|
|
// this information is for client side only
|
|
target.ToPlayer().UpdateSpellDamageAndHealingBonus();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModHealingDonePercent)]
|
|
void HandleModHealingDonePct(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
Player player = aurApp.GetTarget().ToPlayer();
|
|
if (player)
|
|
player.UpdateHealingDonePercentMod();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModTotalStatPercentage)]
|
|
void HandleModTotalPercentStat(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
// save current health state
|
|
float healthPct = target.GetHealthPct();
|
|
bool zeroHealth = !target.IsAlive();
|
|
|
|
// players in corpse state may mean two different states:
|
|
/// 1. player just died but did not release (in this case health == 0)
|
|
/// 2. player is corpse running (ie ghost) (in this case health == 1)
|
|
if (target.GetDeathState() == DeathState.Corpse)
|
|
zeroHealth = target.GetHealth() == 0;
|
|
|
|
for (int i = (int)Stats.Strength; i < (int)Stats.Max; i++)
|
|
{
|
|
if (Convert.ToBoolean(GetMiscValueB() & 1 << i) || GetMiscValueB() == 0) // 0 is also used for all stats
|
|
{
|
|
float amount = target.GetTotalAuraMultiplier(AuraType.ModTotalStatPercentage, aurEff =>
|
|
{
|
|
if ((aurEff.GetMiscValueB() & 1 << i) != 0 || aurEff.GetMiscValueB() == 0)
|
|
return true;
|
|
return false;
|
|
});
|
|
|
|
if (target.GetPctModifierValue(UnitMods.StatStart + i, UnitModifierPctType.Total) == amount)
|
|
continue;
|
|
|
|
target.SetStatPctModifier(UnitMods.StatStart + i, UnitModifierPctType.Total, amount);
|
|
if (target.IsTypeId(TypeId.Player) || target.IsPet())
|
|
target.UpdateStatBuffMod((Stats)i);
|
|
}
|
|
}
|
|
|
|
// recalculate current HP/MP after applying aura modifications (only for spells with SPELL_ATTR0_ABILITY 0x00000010 flag)
|
|
// this check is total bullshit i think
|
|
if ((Convert.ToBoolean(GetMiscValueB() & 1 << (int)Stats.Stamina) || GetMiscValueB() == 0) && m_spellInfo.HasAttribute(SpellAttr0.Ability))
|
|
target.SetHealth(Math.Max(MathFunctions.CalculatePct(target.GetMaxHealth(), healthPct), (zeroHealth ? 0 : 1ul)));
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModExpertise)]
|
|
void HandleAuraModExpertise(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
target.ToPlayer().UpdateExpertise(WeaponAttackType.BaseAttack);
|
|
target.ToPlayer().UpdateExpertise(WeaponAttackType.OffAttack);
|
|
}
|
|
|
|
// Increase armor by <AuraEffect.BasePoints> % of your <primary stat>
|
|
[AuraEffectHandler(AuraType.ModArmorPctFromStat)]
|
|
void HandleModArmorPctFromStat(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
// only players have primary stats
|
|
Player player = aurApp.GetTarget().ToPlayer();
|
|
if (!player)
|
|
return;
|
|
|
|
player.UpdateArmor();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModStatBonusPct)]
|
|
void HandleModStatBonusPercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (GetMiscValue() < -1 || GetMiscValue() > 4)
|
|
{
|
|
Log.outError(LogFilter.Spells, "WARNING: Misc Value for SPELL_AURA_MOD_STAT_BONUS_PCT not valid");
|
|
return;
|
|
}
|
|
|
|
// only players have base stats
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
for (Stats stat = Stats.Strength; stat < Stats.Max; ++stat)
|
|
{
|
|
if (GetMiscValue() == (int)stat || GetMiscValue() == -1)
|
|
{
|
|
target.HandleStatFlatModifier(UnitMods.StatStart + (int)stat, UnitModifierFlatType.BasePCTExcludeCreate, GetAmount(), apply);
|
|
target.UpdateStatBuffMod(stat);
|
|
}
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.OverrideSpellPowerByApPct)]
|
|
void HandleOverrideSpellPowerByAttackPower(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (!target)
|
|
return;
|
|
|
|
target.ApplyModOverrideSpellPowerByAPPercent(GetAmount(), apply);
|
|
target.UpdateSpellDamageAndHealingBonus();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.OverrideAttackPowerBySpPct)]
|
|
void HandleOverrideAttackPowerBySpellPower(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (!target)
|
|
return;
|
|
|
|
target.ApplyModOverrideAPBySpellPowerPercent(GetAmount(), apply);
|
|
target.UpdateAttackPowerAndDamage();
|
|
target.UpdateAttackPowerAndDamage(true);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModVersatility)]
|
|
void HandleModVersatilityByPct(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (target)
|
|
{
|
|
target.SetVersatilityBonus(target.GetTotalAuraModifier(AuraType.ModVersatility));
|
|
target.UpdateHealingDonePercentMod();
|
|
target.UpdateVersatilityDamageDone();
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModMaxPower)]
|
|
void HandleAuraModMaxPower(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
PowerType power = (PowerType)GetMiscValue();
|
|
UnitMods unitMod = (UnitMods)(UnitMods.PowerStart + (int)power);
|
|
|
|
target.HandleStatFlatModifier(unitMod, UnitModifierFlatType.Total, GetAmount(), apply);
|
|
}
|
|
|
|
/********************************/
|
|
/*** HEAL & ENERGIZE ***/
|
|
/********************************/
|
|
[AuraEffectHandler(AuraType.ModPowerRegen)]
|
|
void HandleModPowerRegen(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
// Update manaregen value
|
|
if (GetMiscValue() == (int)PowerType.Mana)
|
|
target.ToPlayer().UpdateManaRegen();
|
|
else if (GetMiscValue() == (int)PowerType.Runes)
|
|
target.ToPlayer().UpdateAllRunesRegen();
|
|
// other powers are not immediate effects - implemented in Player.Regenerate, Creature.Regenerate
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModPowerRegenPercent)]
|
|
void HandleModPowerRegenPCT(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
HandleModPowerRegen(aurApp, mode, apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModManaRegenPct)]
|
|
void HandleModManaRegenPct(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsPlayer())
|
|
return;
|
|
|
|
target.ToPlayer().UpdateManaRegen();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModIncreaseHealth)]
|
|
[AuraEffectHandler(AuraType.ModIncreaseHealth2)]
|
|
[AuraEffectHandler(AuraType.ModMaxHealth)]
|
|
void HandleAuraModIncreaseHealth(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
int amt = apply ? GetAmount() : -GetAmount();
|
|
if (amt < 0)
|
|
target.ModifyHealth(Math.Max((int)(1 - target.GetHealth()), amt));
|
|
|
|
target.HandleStatFlatModifier(UnitMods.Health, UnitModifierFlatType.Total, GetAmount(), apply);
|
|
|
|
if (amt > 0)
|
|
target.ModifyHealth(amt);
|
|
}
|
|
|
|
void HandleAuraModIncreaseMaxHealth(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
float percent = target.GetHealthPct();
|
|
|
|
target.HandleStatFlatModifier(UnitMods.Health, UnitModifierFlatType.Total, GetAmount(), apply);
|
|
|
|
// refresh percentage
|
|
if (target.GetHealth() > 0)
|
|
{
|
|
uint newHealth = (uint)Math.Max(target.CountPctFromMaxHealth((int)percent), 1);
|
|
target.SetHealth(newHealth);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModIncreaseEnergy)]
|
|
void HandleAuraModIncreaseEnergy(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
PowerType powerType = (PowerType)GetMiscValue();
|
|
|
|
UnitMods unitMod = (UnitMods.PowerStart + (int)powerType);
|
|
target.HandleStatFlatModifier(unitMod, UnitModifierFlatType.Total, GetAmount(), apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModIncreaseEnergyPercent)]
|
|
void HandleAuraModIncreaseEnergyPercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
PowerType powerType = (PowerType)GetMiscValue();
|
|
|
|
UnitMods unitMod = UnitMods.PowerStart + (int)powerType;
|
|
|
|
// Save old powers for further calculation
|
|
int oldPower = target.GetPower(powerType);
|
|
int oldMaxPower = target.GetMaxPower(powerType);
|
|
|
|
// Handle aura effect for max power
|
|
if (apply)
|
|
target.ApplyStatPctModifier(unitMod, UnitModifierPctType.Total, GetAmount());
|
|
else
|
|
{
|
|
float amount = target.GetTotalAuraMultiplier(AuraType.ModIncreaseEnergyPercent, aurEff =>
|
|
{
|
|
if (aurEff.GetMiscValue() == (int)powerType)
|
|
return true;
|
|
return false;
|
|
});
|
|
|
|
amount *= target.GetTotalAuraMultiplier(AuraType.ModMaxPowerPct, aurEff =>
|
|
{
|
|
if (aurEff.GetMiscValue() == (int)powerType)
|
|
return true;
|
|
return false;
|
|
});
|
|
|
|
target.SetStatPctModifier(unitMod, UnitModifierPctType.Total, amount);
|
|
}
|
|
|
|
// Calculate the current power change
|
|
int change = target.GetMaxPower(powerType) - oldMaxPower;
|
|
change = (oldPower + change) - target.GetPower(powerType);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModIncreaseHealthPercent)]
|
|
void HandleAuraModIncreaseHealthPercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
// Unit will keep hp% after MaxHealth being modified if unit is alive.
|
|
float percent = target.GetHealthPct();
|
|
if (apply)
|
|
target.ApplyStatPctModifier(UnitMods.Health, UnitModifierPctType.Total, GetAmount());
|
|
else
|
|
{
|
|
float amount = target.GetTotalAuraMultiplier(AuraType.ModIncreaseHealthPercent) * target.GetTotalAuraMultiplier(AuraType.ModIncreaseHealthPercent2);
|
|
target.SetStatPctModifier(UnitMods.Health, UnitModifierPctType.Total, amount);
|
|
}
|
|
|
|
if (target.GetHealth() > 0)
|
|
{
|
|
uint newHealth = (uint)Math.Max(MathFunctions.CalculatePct(target.GetMaxHealth(), (int)percent), 1);
|
|
target.SetHealth(newHealth);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModBaseHealthPct)]
|
|
void HandleAuraIncreaseBaseHealthPercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
target.ApplyStatPctModifier(UnitMods.Health, UnitModifierPctType.Base, GetAmount());
|
|
else
|
|
{
|
|
float amount = target.GetTotalAuraMultiplier(AuraType.ModBaseHealthPct);
|
|
target.SetStatPctModifier(UnitMods.Health, UnitModifierPctType.Base, amount);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModBaseManaPct)]
|
|
void HandleAuraModIncreaseBaseManaPercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
target.ApplyStatPctModifier(UnitMods.Mana, UnitModifierPctType.Base, GetAmount());
|
|
else
|
|
{
|
|
float amount = target.GetTotalAuraMultiplier(AuraType.ModBaseManaPct);
|
|
target.SetStatPctModifier(UnitMods.Mana, UnitModifierPctType.Base, amount);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModManaCostPct)]
|
|
void HandleModManaCostPct(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
aurApp.GetTarget().ApplyModManaCostMultiplier(GetAmount() / 100.0f, apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModPowerDisplay)]
|
|
void HandleAuraModPowerDisplay(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.RealOrReapplyMask))
|
|
return;
|
|
|
|
if (GetMiscValue() >= (int)PowerType.Max)
|
|
return;
|
|
|
|
if (apply)
|
|
aurApp.GetTarget().RemoveAurasByType(GetAuraType(), ObjectGuid.Empty, GetBase());
|
|
|
|
aurApp.GetTarget().UpdateDisplayPower();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModOverridePowerDisplay)]
|
|
void HandleAuraModOverridePowerDisplay(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
PowerDisplayRecord powerDisplay = CliDB.PowerDisplayStorage.LookupByKey(GetMiscValue());
|
|
if (powerDisplay == null)
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
if (target.GetPowerIndex((PowerType)powerDisplay.ActualType) == (int)PowerType.Max)
|
|
return;
|
|
|
|
if (apply)
|
|
{
|
|
target.RemoveAurasByType(GetAuraType(), ObjectGuid.Empty, GetBase());
|
|
target.SetOverrideDisplayPowerId(powerDisplay.Id);
|
|
}
|
|
else
|
|
target.SetOverrideDisplayPowerId(0);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModMaxPowerPct)]
|
|
void HandleAuraModMaxPowerPct(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
if (!target.IsPlayer())
|
|
return;
|
|
|
|
PowerType powerType = (PowerType)GetMiscValue();
|
|
UnitMods unitMod = UnitMods.PowerStart + (int)powerType;
|
|
|
|
// Save old powers for further calculation
|
|
int oldPower = target.GetPower(powerType);
|
|
int oldMaxPower = target.GetMaxPower(powerType);
|
|
|
|
// Handle aura effect for max power
|
|
if (apply)
|
|
target.ApplyStatPctModifier(unitMod, UnitModifierPctType.Total, GetAmount());
|
|
else
|
|
{
|
|
float amount = target.GetTotalAuraMultiplier(AuraType.ModMaxPowerPct, aurEff =>
|
|
{
|
|
if (aurEff.GetMiscValue() == (int)powerType)
|
|
return true;
|
|
return false;
|
|
});
|
|
|
|
amount *= target.GetTotalAuraMultiplier(AuraType.ModIncreaseEnergyPercent, aurEff =>
|
|
{
|
|
if (aurEff.GetMiscValue() == (int)powerType)
|
|
return true;
|
|
return false;
|
|
});
|
|
|
|
target.SetStatPctModifier(unitMod, UnitModifierPctType.Total, amount);
|
|
}
|
|
|
|
// Calculate the current power change
|
|
int change = target.GetMaxPower(powerType) - oldMaxPower;
|
|
change = (oldPower + change) - target.GetPower(powerType);
|
|
target.ModifyPower(powerType, change);
|
|
}
|
|
|
|
/********************************/
|
|
/*** FIGHT ***/
|
|
/********************************/
|
|
[AuraEffectHandler(AuraType.ModParryPercent)]
|
|
void HandleAuraModParryPercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
target.ToPlayer().UpdateParryPercentage();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModDodgePercent)]
|
|
void HandleAuraModDodgePercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
target.ToPlayer().UpdateDodgePercentage();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModBlockPercent)]
|
|
void HandleAuraModBlockPercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
target.ToPlayer().UpdateBlockPercentage();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.InterruptRegen)]
|
|
void HandleAuraModRegenInterrupt(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsPlayer())
|
|
return;
|
|
|
|
target.ToPlayer().UpdateManaRegen();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModWeaponCritPercent)]
|
|
void HandleAuraModWeaponCritPercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (!target)
|
|
return;
|
|
|
|
target.UpdateAllWeaponDependentCritAuras();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModSpellHitChance)]
|
|
void HandleModSpellHitChance(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (target.IsTypeId(TypeId.Player))
|
|
target.ToPlayer().UpdateSpellHitChances();
|
|
else
|
|
target.ModSpellHitChance += (apply) ? GetAmount() : (-GetAmount());
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModSpellCritChance)]
|
|
void HandleModSpellCritChance(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (target.IsTypeId(TypeId.Player))
|
|
target.ToPlayer().UpdateSpellCritChance();
|
|
else
|
|
target.BaseSpellCritChance += (apply) ? GetAmount() : -GetAmount();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModCritPct)]
|
|
void HandleAuraModCritPct(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
{
|
|
target.BaseSpellCritChance += (apply) ? GetAmount() : -GetAmount();
|
|
return;
|
|
}
|
|
|
|
target.ToPlayer().UpdateAllWeaponDependentCritAuras();
|
|
|
|
// included in Player.UpdateSpellCritChance calculation
|
|
target.ToPlayer().UpdateSpellCritChance();
|
|
}
|
|
|
|
/********************************/
|
|
/*** ATTACK SPEED ***/
|
|
/********************************/
|
|
[AuraEffectHandler(AuraType.HasteSpells)]
|
|
[AuraEffectHandler(AuraType.ModCastingSpeedNotStack)]
|
|
void HandleModCastingSpeed(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
// Do not apply such auras in normal way
|
|
if (GetAmount() >= 1000)
|
|
{
|
|
if (apply)
|
|
target.SetInstantCast(true);
|
|
else
|
|
{
|
|
// only SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK can have this high amount
|
|
// it's some rare case that you have 2 auras like that, but just in case ;)
|
|
|
|
bool remove = true;
|
|
var castingSpeedNotStack = target.GetAuraEffectsByType(AuraType.ModCastingSpeedNotStack);
|
|
foreach (AuraEffect aurEff in castingSpeedNotStack)
|
|
{
|
|
if (aurEff != this && aurEff.GetAmount() >= 1000)
|
|
{
|
|
remove = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (remove)
|
|
target.SetInstantCast(false);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
target.ApplyCastTimePercentMod(GetAmount(), apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModMeleeRangedHaste)]
|
|
[AuraEffectHandler(AuraType.ModMeleeRangedHaste2)]
|
|
void HandleModMeleeRangedSpeedPct(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
//! ToDo: Haste auras with the same handler _CAN'T_ stack together
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
target.ApplyAttackTimePercentMod(WeaponAttackType.BaseAttack, GetAmount(), apply);
|
|
target.ApplyAttackTimePercentMod(WeaponAttackType.OffAttack, GetAmount(), apply);
|
|
target.ApplyAttackTimePercentMod(WeaponAttackType.RangedAttack, GetAmount(), apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.MeleeSlow)]
|
|
[AuraEffectHandler(AuraType.ModSpeedSlowAll)]
|
|
void HandleModCombatSpeedPct(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
int spellGroupVal = target.GetHighestExclusiveSameEffectSpellGroupValue(this, AuraType.MeleeSlow);
|
|
if (Math.Abs(spellGroupVal) >= Math.Abs(GetAmount()))
|
|
return;
|
|
|
|
if (spellGroupVal != 0)
|
|
{
|
|
target.ApplyCastTimePercentMod(spellGroupVal, !apply);
|
|
target.ApplyAttackTimePercentMod(WeaponAttackType.BaseAttack, spellGroupVal, !apply);
|
|
target.ApplyAttackTimePercentMod(WeaponAttackType.OffAttack, spellGroupVal, !apply);
|
|
target.ApplyAttackTimePercentMod(WeaponAttackType.RangedAttack, spellGroupVal, !apply);
|
|
}
|
|
|
|
target.ApplyCastTimePercentMod(GetAmount(), apply);
|
|
target.ApplyAttackTimePercentMod(WeaponAttackType.BaseAttack, GetAmount(), apply);
|
|
target.ApplyAttackTimePercentMod(WeaponAttackType.OffAttack, GetAmount(), apply);
|
|
target.ApplyAttackTimePercentMod(WeaponAttackType.RangedAttack, GetAmount(), apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModAttackspeed)]
|
|
void HandleModAttackSpeed(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
target.ApplyAttackTimePercentMod(WeaponAttackType.BaseAttack, GetAmount(), apply);
|
|
target.UpdateDamagePhysical(WeaponAttackType.BaseAttack);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModMeleeHaste)]
|
|
[AuraEffectHandler(AuraType.ModMeleeHaste2)]
|
|
[AuraEffectHandler(AuraType.ModMeleeHaste3)]
|
|
void HandleModMeleeSpeedPct(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
//! ToDo: Haste auras with the same handler _CAN'T_ stack together
|
|
Unit target = aurApp.GetTarget();
|
|
int spellGroupVal = target.GetHighestExclusiveSameEffectSpellGroupValue(this, AuraType.ModMeleeHaste);
|
|
if (Math.Abs(spellGroupVal) >= Math.Abs(GetAmount()))
|
|
return;
|
|
|
|
if (spellGroupVal != 0)
|
|
{
|
|
target.ApplyAttackTimePercentMod(WeaponAttackType.BaseAttack, spellGroupVal, !apply);
|
|
target.ApplyAttackTimePercentMod(WeaponAttackType.OffAttack, spellGroupVal, !apply);
|
|
}
|
|
target.ApplyAttackTimePercentMod(WeaponAttackType.BaseAttack, GetAmount(), apply);
|
|
target.ApplyAttackTimePercentMod(WeaponAttackType.OffAttack, GetAmount(), apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModRangedHaste)]
|
|
[AuraEffectHandler(AuraType.ModRangedHaste2)]
|
|
void HandleAuraModRangedHaste(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
//! ToDo: Haste auras with the same handler _CAN'T_ stack together
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
target.ApplyAttackTimePercentMod(WeaponAttackType.RangedAttack, GetAmount(), apply);
|
|
}
|
|
|
|
/********************************/
|
|
/*** COMBAT RATING ***/
|
|
/********************************/
|
|
[AuraEffectHandler(AuraType.ModRating)]
|
|
void HandleModRating(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
for (int rating = 0; rating < (int)CombatRating.Max; ++rating)
|
|
if (Convert.ToBoolean(GetMiscValue() & (1 << rating)))
|
|
target.ToPlayer().ApplyRatingMod((CombatRating)rating, GetAmount(), apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModRatingPct)]
|
|
void HandleModRatingPct(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
// Just recalculate ratings
|
|
for (int rating = 0; rating < (int)CombatRating.Max; ++rating)
|
|
if (Convert.ToBoolean(GetMiscValue() & (1 << rating)))
|
|
target.ToPlayer().UpdateRating((CombatRating)rating);
|
|
}
|
|
|
|
/********************************/
|
|
/*** ATTACK POWER ***/
|
|
/********************************/
|
|
[AuraEffectHandler(AuraType.ModAttackPower)]
|
|
void HandleAuraModAttackPower(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
target.HandleStatFlatModifier(UnitMods.AttackPower, UnitModifierFlatType.Total, GetAmount(), apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModRangedAttackPower)]
|
|
void HandleAuraModRangedAttackPower(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if ((target.GetClassMask() & (uint)Class.ClassMaskWandUsers) != 0)
|
|
return;
|
|
|
|
target.HandleStatFlatModifier(UnitMods.AttackPowerRanged, UnitModifierFlatType.Total, GetAmount(), apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModAttackPowerPct)]
|
|
void HandleAuraModAttackPowerPercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
//UNIT_FIELD_ATTACK_POWER_MULTIPLIER = multiplier - 1
|
|
if (apply)
|
|
target.ApplyStatPctModifier(UnitMods.AttackPower, UnitModifierPctType.Total, GetAmount());
|
|
else
|
|
{
|
|
float amount = target.GetTotalAuraMultiplier(AuraType.ModAttackPowerPct);
|
|
target.SetStatPctModifier(UnitMods.AttackPower, UnitModifierPctType.Total, amount);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModRangedAttackPowerPct)]
|
|
void HandleAuraModRangedAttackPowerPercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if ((target.GetClassMask() & (uint)Class.ClassMaskWandUsers) != 0)
|
|
return;
|
|
|
|
//UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = multiplier - 1
|
|
if (apply)
|
|
target.ApplyStatPctModifier(UnitMods.AttackPowerRanged, UnitModifierPctType.Total, GetAmount());
|
|
else
|
|
{
|
|
float amount = target.GetTotalAuraMultiplier(AuraType.ModRangedAttackPowerPct);
|
|
target.SetStatPctModifier(UnitMods.AttackPowerRanged, UnitModifierPctType.Total, amount);
|
|
}
|
|
}
|
|
|
|
/********************************/
|
|
/*** DAMAGE BONUS ***/
|
|
/********************************/
|
|
[AuraEffectHandler(AuraType.ModDamageDone)]
|
|
void HandleModDamageDone(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if ((GetMiscValue() & (int)SpellSchoolMask.Normal) != 0)
|
|
target.UpdateAllDamageDoneMods();
|
|
|
|
// Magic damage modifiers implemented in Unit::SpellBaseDamageBonusDone
|
|
// This information for client side use only
|
|
Player playerTarget = target.ToPlayer();
|
|
if (playerTarget != null)
|
|
{
|
|
for (int i = 0; i < (int)SpellSchools.Max; ++i)
|
|
{
|
|
if (Convert.ToBoolean(GetMiscValue() & (1 << i)))
|
|
{
|
|
if (GetAmount() >= 0)
|
|
playerTarget.ApplyModDamageDonePos((SpellSchools)i, GetAmount(), apply);
|
|
else
|
|
playerTarget.ApplyModDamageDoneNeg((SpellSchools)i, GetAmount(), apply);
|
|
}
|
|
}
|
|
|
|
Guardian pet = playerTarget.GetGuardianPet();
|
|
if (pet)
|
|
pet.UpdateAttackPowerAndDamage();
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModDamagePercentDone)]
|
|
void HandleModDamagePercentDone(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
// also handles spell group stacks
|
|
if (Convert.ToBoolean(GetMiscValue() & (int)SpellSchoolMask.Normal))
|
|
target.UpdateAllDamagePctDoneMods();
|
|
|
|
Player thisPlayer = target.ToPlayer();
|
|
if (thisPlayer != null)
|
|
{
|
|
for (var i = SpellSchools.Normal; i < SpellSchools.Max; ++i)
|
|
{
|
|
if (Convert.ToBoolean(GetMiscValue() & (1 << (int)i)))
|
|
{
|
|
// only aura type modifying PLAYER_FIELD_MOD_DAMAGE_DONE_PCT
|
|
float amount = thisPlayer.GetTotalAuraMultiplierByMiscMask(AuraType.ModDamagePercentDone, 1u << (int)i);
|
|
thisPlayer.SetModDamageDonePercent(i, amount);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModOffhandDamagePct)]
|
|
void HandleModOffhandDamagePercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
// also handles spell group stacks
|
|
target.UpdateDamagePctDoneMods(WeaponAttackType.OffAttack);
|
|
}
|
|
|
|
void HandleShieldBlockValue(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
|
|
return;
|
|
|
|
Player player = aurApp.GetTarget().ToPlayer();
|
|
if (player != null)
|
|
player.HandleBaseModFlatValue(BaseModGroup.ShieldBlockValue, GetAmount(), apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModShieldBlockvaluePct)]
|
|
void HandleShieldBlockValuePercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (!target)
|
|
return;
|
|
|
|
if (apply)
|
|
target.ApplyBaseModPctValue(BaseModGroup.ShieldBlockValue, GetAmount());
|
|
else
|
|
{
|
|
float amount = target.GetTotalAuraMultiplier(AuraType.ModShieldBlockvaluePct);
|
|
target.SetBaseModPctValue(BaseModGroup.ShieldBlockValue, amount);
|
|
}
|
|
}
|
|
|
|
/********************************/
|
|
/*** POWER COST ***/
|
|
/********************************/
|
|
[AuraEffectHandler(AuraType.ModPowerCostSchool)]
|
|
void HandleModPowerCost(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask))
|
|
return;
|
|
|
|
// handled in SpellInfo::CalcPowerCost, this is only for client UI
|
|
if ((GetMiscValueB() & (1 << (int)PowerType.Mana)) == 0)
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
for (int i = 0; i < (int)SpellSchools.Max; ++i)
|
|
if (Convert.ToBoolean(GetMiscValue() & (1 << i)))
|
|
target.ApplyModManaCostModifier((SpellSchools)i, GetAmount(), apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ArenaPreparation)]
|
|
void HandleArenaPreparation(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
target.AddUnitFlag(UnitFlags.Preparation);
|
|
else
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (target.HasAuraType(GetAuraType()))
|
|
return;
|
|
target.RemoveUnitFlag(UnitFlags.Preparation);
|
|
}
|
|
|
|
target.ModifyAuraState(AuraStateType.ArenaPreparation, apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.NoReagentUse)]
|
|
void HandleNoReagentUseAura(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
FlagArray128 mask = new();
|
|
var noReagent = target.GetAuraEffectsByType(AuraType.NoReagentUse);
|
|
foreach (var eff in noReagent)
|
|
{
|
|
SpellEffectInfo effect = eff.GetSpellEffectInfo();
|
|
if (effect != null)
|
|
mask |= effect.SpellClassMask;
|
|
}
|
|
|
|
target.ToPlayer().SetNoRegentCostMask(mask);
|
|
}
|
|
|
|
/*********************************************************/
|
|
/*** OTHERS ***/
|
|
/*********************************************************/
|
|
[AuraEffectHandler(AuraType.Dummy)]
|
|
void HandleAuraDummy(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Reapply)))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
Unit caster = GetCaster();
|
|
|
|
// pet auras
|
|
if (target.GetTypeId() == TypeId.Player && mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
{
|
|
PetAura petSpell = Global.SpellMgr.GetPetAura(GetId(), (byte)GetEffIndex());
|
|
if (petSpell != null)
|
|
{
|
|
if (apply)
|
|
target.ToPlayer().AddPetAura(petSpell);
|
|
else
|
|
target.ToPlayer().RemovePetAura(petSpell);
|
|
}
|
|
}
|
|
|
|
if (mode.HasAnyFlag(AuraEffectHandleModes.Real | AuraEffectHandleModes.Reapply))
|
|
{
|
|
// AT APPLY
|
|
if (apply)
|
|
{
|
|
switch (GetId())
|
|
{
|
|
case 1515: // Tame beast
|
|
// FIX_ME: this is 2.0.12 threat effect replaced in 2.1.x by dummy aura, must be checked for correctness
|
|
if (caster != null && target.CanHaveThreatList())
|
|
target.GetThreatManager().AddThreat(caster, 10.0f);
|
|
break;
|
|
case 13139: // net-o-matic
|
|
// root to self part of (root_target.charge.root_self sequence
|
|
if (caster != null)
|
|
caster.CastSpell(caster, 13138, new CastSpellExtraArgs(this));
|
|
break;
|
|
case 34026: // kill command
|
|
{
|
|
Unit pet = target.GetGuardianPet();
|
|
if (pet == null)
|
|
break;
|
|
|
|
target.CastSpell(target, 34027, new CastSpellExtraArgs(this));
|
|
|
|
// set 3 stacks and 3 charges (to make all auras not disappear at once)
|
|
Aura owner_aura = target.GetAura(34027, GetCasterGUID());
|
|
Aura pet_aura = pet.GetAura(58914, GetCasterGUID());
|
|
if (owner_aura != null)
|
|
{
|
|
owner_aura.SetStackAmount((byte)owner_aura.GetSpellInfo().StackAmount);
|
|
if (pet_aura != null)
|
|
{
|
|
pet_aura.SetCharges(0);
|
|
pet_aura.SetStackAmount((byte)owner_aura.GetSpellInfo().StackAmount);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 37096: // Blood Elf Illusion
|
|
{
|
|
if (caster != null)
|
|
{
|
|
if (caster.GetGender() == Gender.Female)
|
|
caster.CastSpell(target, 37095, new CastSpellExtraArgs(this)); // Blood Elf Disguise
|
|
else
|
|
caster.CastSpell(target, 37093, new CastSpellExtraArgs(this));
|
|
}
|
|
break;
|
|
}
|
|
case 39850: // Rocket Blast
|
|
if (RandomHelper.randChance(20)) // backfire stun
|
|
target.CastSpell(target, 51581, new CastSpellExtraArgs(this));
|
|
break;
|
|
case 43873: // Headless Horseman Laugh
|
|
target.PlayDistanceSound(11965);
|
|
break;
|
|
case 46354: // Blood Elf Illusion
|
|
if (caster != null)
|
|
{
|
|
if (caster.GetGender() == Gender.Female)
|
|
caster.CastSpell(target, 46356, new CastSpellExtraArgs(this));
|
|
else
|
|
caster.CastSpell(target, 46355, new CastSpellExtraArgs(this));
|
|
}
|
|
break;
|
|
case 46361: // Reinforced Net
|
|
if (caster != null)
|
|
target.GetMotionMaster().MoveFall();
|
|
break;
|
|
}
|
|
}
|
|
// AT REMOVE
|
|
else
|
|
{
|
|
if ((GetSpellInfo().IsQuestTame()) && caster != null && caster.IsAlive() && target.IsAlive())
|
|
{
|
|
uint finalSpelId = 0;
|
|
switch (GetId())
|
|
{
|
|
case 19548:
|
|
finalSpelId = 19597;
|
|
break;
|
|
case 19674:
|
|
finalSpelId = 19677;
|
|
break;
|
|
case 19687:
|
|
finalSpelId = 19676;
|
|
break;
|
|
case 19688:
|
|
finalSpelId = 19678;
|
|
break;
|
|
case 19689:
|
|
finalSpelId = 19679;
|
|
break;
|
|
case 19692:
|
|
finalSpelId = 19680;
|
|
break;
|
|
case 19693:
|
|
finalSpelId = 19684;
|
|
break;
|
|
case 19694:
|
|
finalSpelId = 19681;
|
|
break;
|
|
case 19696:
|
|
finalSpelId = 19682;
|
|
break;
|
|
case 19697:
|
|
finalSpelId = 19683;
|
|
break;
|
|
case 19699:
|
|
finalSpelId = 19685;
|
|
break;
|
|
case 19700:
|
|
finalSpelId = 19686;
|
|
break;
|
|
case 30646:
|
|
finalSpelId = 30647;
|
|
break;
|
|
case 30653:
|
|
finalSpelId = 30648;
|
|
break;
|
|
case 30654:
|
|
finalSpelId = 30652;
|
|
break;
|
|
case 30099:
|
|
finalSpelId = 30100;
|
|
break;
|
|
case 30102:
|
|
finalSpelId = 30103;
|
|
break;
|
|
case 30105:
|
|
finalSpelId = 30104;
|
|
break;
|
|
}
|
|
|
|
if (finalSpelId != 0)
|
|
caster.CastSpell(target, finalSpelId, new CastSpellExtraArgs(this));
|
|
}
|
|
|
|
switch (m_spellInfo.SpellFamilyName)
|
|
{
|
|
case SpellFamilyNames.Generic:
|
|
switch (GetId())
|
|
{
|
|
case 2584: // Waiting to Resurrect
|
|
// Waiting to resurrect spell cancel, we must remove player from resurrect queue
|
|
if (target.IsTypeId(TypeId.Player))
|
|
{
|
|
Battleground bg = target.ToPlayer().GetBattleground();
|
|
if (bg)
|
|
bg.RemovePlayerFromResurrectQueue(target.GetGUID());
|
|
BattleField bf = Global.BattleFieldMgr.GetBattlefieldToZoneId(target.GetZoneId());
|
|
if (bf != null)
|
|
bf.RemovePlayerFromResurrectQueue(target.GetGUID());
|
|
}
|
|
break;
|
|
case 36730: // Flame Strike
|
|
{
|
|
target.CastSpell(target, 36731, new CastSpellExtraArgs(this));
|
|
break;
|
|
}
|
|
case 44191: // Flame Strike
|
|
{
|
|
if (target.GetMap().IsDungeon())
|
|
{
|
|
uint spellId = (uint)(target.GetMap().IsHeroic() ? 46163 : 44190);
|
|
|
|
target.CastSpell(target, spellId, new CastSpellExtraArgs(this));
|
|
}
|
|
break;
|
|
}
|
|
case 43681: // Inactive
|
|
{
|
|
if (!target.IsTypeId(TypeId.Player) || aurApp.GetRemoveMode() != AuraRemoveMode.Expire)
|
|
return;
|
|
|
|
if (target.GetMap().IsBattleground())
|
|
target.ToPlayer().LeaveBattleground();
|
|
break;
|
|
}
|
|
case 42783: // Wrath of the Astromancer
|
|
target.CastSpell(target, (uint)GetAmount(), new CastSpellExtraArgs(this));
|
|
break;
|
|
case 46308: // Burning Winds casted only at creatures at spawn
|
|
target.CastSpell(target, 47287, new CastSpellExtraArgs(this));
|
|
break;
|
|
case 52172: // Coyote Spirit Despawn Aura
|
|
case 60244: // Blood Parrot Despawn Aura
|
|
target.CastSpell((Unit)null, (uint)GetAmount(), new CastSpellExtraArgs(this));
|
|
break;
|
|
case 91604: // Restricted Flight Area
|
|
if (aurApp.GetRemoveMode() == AuraRemoveMode.Expire)
|
|
target.CastSpell(target, 58601, new CastSpellExtraArgs(this));
|
|
break;
|
|
}
|
|
break;
|
|
case SpellFamilyNames.Deathknight:
|
|
// Summon Gargoyle (Dismiss Gargoyle at remove)
|
|
if (GetId() == 61777)
|
|
target.CastSpell(target, (uint)GetAmount(), new CastSpellExtraArgs(this));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// AT APPLY & REMOVE
|
|
|
|
switch (m_spellInfo.SpellFamilyName)
|
|
{
|
|
case SpellFamilyNames.Generic:
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
break;
|
|
switch (GetId())
|
|
{
|
|
// Recently Bandaged
|
|
case 11196:
|
|
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, (uint)GetMiscValue(), apply);
|
|
break;
|
|
// Unstable Power
|
|
case 24658:
|
|
{
|
|
uint spellId = 24659;
|
|
if (apply && caster != null)
|
|
{
|
|
SpellInfo spell = Global.SpellMgr.GetSpellInfo(spellId, GetBase().GetCastDifficulty());
|
|
CastSpellExtraArgs args = new();
|
|
args.TriggerFlags = TriggerCastFlags.FullMask;
|
|
args.OriginalCaster = GetCasterGUID();
|
|
args.OriginalCastId = GetBase().GetCastId();
|
|
args.CastDifficulty = GetBase().GetCastDifficulty();
|
|
|
|
for (uint i = 0; i < spell.StackAmount; ++i)
|
|
caster.CastSpell(target, spell.Id, args);
|
|
break;
|
|
}
|
|
target.RemoveAurasDueToSpell(spellId);
|
|
break;
|
|
}
|
|
// Restless Strength
|
|
case 24661:
|
|
{
|
|
uint spellId = 24662;
|
|
if (apply && caster != null)
|
|
{
|
|
SpellInfo spell = Global.SpellMgr.GetSpellInfo(spellId, GetBase().GetCastDifficulty());
|
|
CastSpellExtraArgs args = new(TriggerCastFlags.FullMask);
|
|
args.OriginalCaster = GetCasterGUID();
|
|
args.OriginalCastId = GetBase().GetCastId();
|
|
args.CastDifficulty = GetBase().GetCastDifficulty();
|
|
|
|
for (uint i = 0; i < spell.StackAmount; ++i)
|
|
caster.CastSpell(target, spell.Id, args);
|
|
break;
|
|
}
|
|
target.RemoveAurasDueToSpell(spellId);
|
|
break;
|
|
}
|
|
// Tag Murloc
|
|
case 30877:
|
|
{
|
|
// Tag/untag Blacksilt Scout
|
|
target.SetEntry((uint)(apply ? 17654 : 17326));
|
|
break;
|
|
}
|
|
case 57819: // Argent Champion
|
|
case 57820: // Ebon Champion
|
|
case 57821: // Champion of the Kirin Tor
|
|
case 57822: // Wyrmrest Champion
|
|
{
|
|
if (!caster || !caster.IsTypeId(TypeId.Player))
|
|
break;
|
|
|
|
uint FactionID = 0;
|
|
|
|
if (apply)
|
|
{
|
|
switch (m_spellInfo.Id)
|
|
{
|
|
case 57819:
|
|
FactionID = 1106; // Argent Crusade
|
|
break;
|
|
case 57820:
|
|
FactionID = 1098;// Knights of the Ebon Blade
|
|
break;
|
|
case 57821:
|
|
FactionID = 1090; // Kirin Tor
|
|
break;
|
|
case 57822:
|
|
FactionID = 1091; // The Wyrmrest Accord
|
|
break;
|
|
}
|
|
}
|
|
caster.ToPlayer().SetChampioningFaction(FactionID);
|
|
break;
|
|
}
|
|
// LK Intro VO (1)
|
|
case 58204:
|
|
if (target.IsTypeId(TypeId.Player))
|
|
{
|
|
// Play part 1
|
|
if (apply)
|
|
target.PlayDirectSound(14970, target.ToPlayer());
|
|
// continue in 58205
|
|
else
|
|
target.CastSpell(target, 58205, new CastSpellExtraArgs(this));
|
|
}
|
|
break;
|
|
// LK Intro VO (2)
|
|
case 58205:
|
|
if (target.IsTypeId(TypeId.Player))
|
|
{
|
|
// Play part 2
|
|
if (apply)
|
|
target.PlayDirectSound(14971, target.ToPlayer());
|
|
// Play part 3
|
|
else
|
|
target.PlayDirectSound(14972, target.ToPlayer());
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ChannelDeathItem)]
|
|
void HandleChannelDeathItem(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
if (apply || aurApp.GetRemoveMode() != AuraRemoveMode.Death)
|
|
return;
|
|
|
|
Unit caster = GetCaster();
|
|
|
|
if (caster == null || !caster.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
Player plCaster = caster.ToPlayer();
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
// Item amount
|
|
if (GetAmount() <= 0)
|
|
return;
|
|
|
|
if (GetSpellEffectInfo().ItemType == 0)
|
|
return;
|
|
|
|
// Soul Shard
|
|
if (GetSpellEffectInfo().ItemType == 6265)
|
|
{
|
|
// Soul Shard only from units that grant XP or honor
|
|
if (!plCaster.IsHonorOrXPTarget(target) ||
|
|
(target.IsTypeId(TypeId.Unit) && !target.ToCreature().IsTappedBy(plCaster)))
|
|
return;
|
|
}
|
|
|
|
//Adding items
|
|
uint noSpaceForCount;
|
|
uint count = (uint)GetAmount();
|
|
|
|
List<ItemPosCount> dest = new();
|
|
InventoryResult msg = plCaster.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, GetSpellEffectInfo().ItemType, count, out noSpaceForCount);
|
|
if (msg != InventoryResult.Ok)
|
|
{
|
|
count -= noSpaceForCount;
|
|
plCaster.SendEquipError(msg, null, null, GetSpellEffectInfo().ItemType);
|
|
if (count == 0)
|
|
return;
|
|
}
|
|
|
|
Item newitem = plCaster.StoreNewItem(dest, GetSpellEffectInfo().ItemType, true);
|
|
if (newitem == null)
|
|
{
|
|
plCaster.SendEquipError(InventoryResult.ItemNotFound);
|
|
return;
|
|
}
|
|
plCaster.SendNewItem(newitem, count, true, true);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.BindSight)]
|
|
void HandleBindSight(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
Unit caster = GetCaster();
|
|
|
|
if (caster == null || !caster.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
caster.ToPlayer().SetViewpoint(target, apply);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ForceReaction)]
|
|
void HandleForceReaction(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
Player player = target.ToPlayer();
|
|
if (player == null)
|
|
return;
|
|
|
|
uint factionId = (uint)GetMiscValue();
|
|
ReputationRank factionRank = (ReputationRank)GetAmount();
|
|
|
|
player.GetReputationMgr().ApplyForceReaction(factionId, factionRank, apply);
|
|
player.GetReputationMgr().SendForceReactions();
|
|
|
|
// stop fighting at apply (if forced rank friendly) or at remove (if real rank friendly)
|
|
if ((apply && factionRank >= ReputationRank.Friendly) || (!apply && player.GetReputationRank(factionId) >= ReputationRank.Friendly))
|
|
player.StopAttackFaction(factionId);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.Empathy)]
|
|
void HandleAuraEmpathy(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
if (!apply)
|
|
{
|
|
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
|
|
if (target.HasAuraType(GetAuraType()))
|
|
return;
|
|
}
|
|
|
|
if (target.GetCreatureType() == CreatureType.Beast)
|
|
{
|
|
if (apply)
|
|
target.AddDynamicFlag(UnitDynFlags.SpecialInfo);
|
|
else
|
|
target.RemoveDynamicFlag(UnitDynFlags.SpecialInfo);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModFaction)]
|
|
void HandleAuraModFaction(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
{
|
|
target.SetFaction((uint)GetMiscValue());
|
|
if (target.IsTypeId(TypeId.Player))
|
|
target.RemoveUnitFlag(UnitFlags.PlayerControlled);
|
|
}
|
|
else
|
|
{
|
|
target.RestoreFaction();
|
|
if (target.IsTypeId(TypeId.Player))
|
|
target.AddUnitFlag(UnitFlags.PlayerControlled);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.LearnSpell)]
|
|
void HandleLearnSpell(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player player = aurApp.GetTarget().ToPlayer();
|
|
if (player == null)
|
|
return;
|
|
|
|
if (apply)
|
|
player.LearnSpell((uint)GetMiscValue(), true, 0, true);
|
|
else
|
|
player.RemoveSpell((uint)GetMiscValue(), false, false, true);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ComprehendLanguage)]
|
|
void HandleComprehendLanguage(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.SendForClientMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
target.AddUnitFlag2(UnitFlags2.ComprehendLang);
|
|
else
|
|
{
|
|
if (target.HasAuraType(GetAuraType()))
|
|
return;
|
|
|
|
target.RemoveUnitFlag2(UnitFlags2.ComprehendLang);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.Linked)]
|
|
void HandleAuraLinked(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
uint triggeredSpellId = GetSpellEffectInfo().TriggerSpell;
|
|
SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggeredSpellId, GetBase().GetCastDifficulty());
|
|
if (triggeredSpellInfo == null)
|
|
return;
|
|
|
|
Unit caster = triggeredSpellInfo.NeedsToBeTriggeredByCaster(m_spellInfo) ? GetCaster() : target;
|
|
if (!caster)
|
|
return;
|
|
|
|
if (mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
{
|
|
if (apply)
|
|
{
|
|
CastSpellExtraArgs args = new(this);
|
|
if (GetAmount() != 0) // If amount avalible cast with basepoints (Crypt Fever for example)
|
|
args.AddSpellMod(SpellValueMod.BasePoint0, GetAmount());
|
|
|
|
caster.CastSpell(target, triggeredSpellId, args);
|
|
}
|
|
else
|
|
{
|
|
ObjectGuid casterGUID = triggeredSpellInfo.NeedsToBeTriggeredByCaster(m_spellInfo) ? GetCasterGUID() : target.GetGUID();
|
|
target.RemoveAura(triggeredSpellId, casterGUID);
|
|
}
|
|
}
|
|
else if (mode.HasAnyFlag(AuraEffectHandleModes.Reapply) && apply)
|
|
{
|
|
ObjectGuid casterGUID = triggeredSpellInfo.NeedsToBeTriggeredByCaster(m_spellInfo) ? GetCasterGUID() : target.GetGUID();
|
|
// change the stack amount to be equal to stack amount of our aura
|
|
Aura triggeredAura = target.GetAura(triggeredSpellId, casterGUID);
|
|
if (triggeredAura != null)
|
|
triggeredAura.ModStackAmount(GetBase().GetStackAmount() - triggeredAura.GetStackAmount());
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.TriggerSpellOnPowerPct)]
|
|
void HandleTriggerSpellOnPowerPercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real) || !apply)
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
int effectAmount = GetAmount();
|
|
uint triggerSpell = GetSpellEffectInfo().TriggerSpell;
|
|
float powerAmountPct = MathFunctions.GetPctOf(target.GetPower((PowerType)GetMiscValue()), target.GetMaxPower((PowerType)GetMiscValue()));
|
|
|
|
switch ((AuraTriggerOnPowerChangeDirection)GetMiscValueB())
|
|
{
|
|
case AuraTriggerOnPowerChangeDirection.Gain:
|
|
if (powerAmountPct < effectAmount)
|
|
return;
|
|
break;
|
|
case AuraTriggerOnPowerChangeDirection.Loss:
|
|
if (powerAmountPct > effectAmount)
|
|
return;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
target.CastSpell(target, triggerSpell, new CastSpellExtraArgs(this));
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.TriggerSpellOnPowerAmount)]
|
|
void HandleTriggerSpellOnPowerAmount(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real) || !apply)
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
int effectAmount = GetAmount();
|
|
uint triggerSpell = GetSpellEffectInfo().TriggerSpell;
|
|
float powerAmount = target.GetPower((PowerType)GetMiscValue());
|
|
|
|
switch ((AuraTriggerOnPowerChangeDirection)GetMiscValueB())
|
|
{
|
|
case AuraTriggerOnPowerChangeDirection.Gain:
|
|
if (powerAmount < effectAmount)
|
|
return;
|
|
break;
|
|
case AuraTriggerOnPowerChangeDirection.Loss:
|
|
if (powerAmount > effectAmount)
|
|
return;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
target.CastSpell(target, triggerSpell, new CastSpellExtraArgs(this));
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.OpenStable)]
|
|
void HandleAuraOpenStable(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsTypeId(TypeId.Player) || !target.IsInWorld)
|
|
return;
|
|
|
|
if (apply)
|
|
target.ToPlayer().GetSession().SendStablePet(target.GetGUID());
|
|
|
|
// client auto close stable dialog at !apply aura
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModFakeInebriate)]
|
|
void HandleAuraModFakeInebriation(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
{
|
|
target.m_invisibilityDetect.AddFlag(InvisibilityType.Drunk);
|
|
target.m_invisibilityDetect.AddValue(InvisibilityType.Drunk, GetAmount());
|
|
|
|
Player playerTarget = target.ToPlayer();
|
|
if (playerTarget)
|
|
playerTarget.ApplyModFakeInebriation(GetAmount(), true);
|
|
}
|
|
else
|
|
{
|
|
bool removeDetect = !target.HasAuraType(AuraType.ModFakeInebriate);
|
|
|
|
target.m_invisibilityDetect.AddValue(InvisibilityType.Drunk, -GetAmount());
|
|
|
|
Player playerTarget = target.ToPlayer();
|
|
if (playerTarget != null)
|
|
{
|
|
playerTarget.ApplyModFakeInebriation(GetAmount(), false);
|
|
|
|
if (removeDetect)
|
|
removeDetect = playerTarget.GetDrunkValue() == 0;
|
|
}
|
|
|
|
if (removeDetect)
|
|
target.m_invisibilityDetect.DelFlag(InvisibilityType.Drunk);
|
|
}
|
|
|
|
// call functions which may have additional effects after chainging state of unit
|
|
target.UpdateObjectVisibility();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.OverrideSpells)]
|
|
void HandleAuraOverrideSpells(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
|
|
if (target == null || !target.IsInWorld)
|
|
return;
|
|
|
|
uint overrideId = (uint)GetMiscValue();
|
|
|
|
if (apply)
|
|
{
|
|
target.SetOverrideSpellsId(overrideId);
|
|
OverrideSpellDataRecord overrideSpells = CliDB.OverrideSpellDataStorage.LookupByKey(overrideId);
|
|
if (overrideSpells != null)
|
|
{
|
|
for (byte i = 0; i < SharedConst.MaxOverrideSpell; ++i)
|
|
{
|
|
uint spellId = overrideSpells.Spells[i];
|
|
if (spellId != 0)
|
|
target.AddTemporarySpell(spellId);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
target.SetOverrideSpellsId(0);
|
|
OverrideSpellDataRecord overrideSpells = CliDB.OverrideSpellDataStorage.LookupByKey(overrideId);
|
|
if (overrideSpells != null)
|
|
{
|
|
for (byte i = 0; i < SharedConst.MaxOverrideSpell; ++i)
|
|
{
|
|
uint spellId = overrideSpells.Spells[i];
|
|
if (spellId != 0)
|
|
target.RemoveTemporarySpell(spellId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.SetVehicleId)]
|
|
void HandleAuraSetVehicle(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (!target.IsInWorld)
|
|
return;
|
|
|
|
int vehicleId = GetMiscValue();
|
|
|
|
if (apply)
|
|
{
|
|
if (!target.CreateVehicleKit((uint)vehicleId, 0))
|
|
return;
|
|
}
|
|
else if (target.GetVehicleKit() != null)
|
|
target.RemoveVehicleKit();
|
|
|
|
if (!target.IsTypeId(TypeId.Player))
|
|
return;
|
|
|
|
if (apply)
|
|
target.ToPlayer().SendOnCancelExpectedVehicleRideAura();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.PreventResurrection)]
|
|
void HandlePreventResurrection(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (target == null)
|
|
return;
|
|
|
|
if (apply)
|
|
target.RemovePlayerLocalFlag(PlayerLocalFlags.ReleaseTimer);
|
|
else if (!target.GetMap().Instanceable())
|
|
target.AddPlayerLocalFlag(PlayerLocalFlags.ReleaseTimer);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.Mastery)]
|
|
void HandleMastery(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (target == null)
|
|
return;
|
|
|
|
target.UpdateMastery();
|
|
}
|
|
|
|
void HandlePeriodicTriggerSpellAuraTick(Unit target, Unit caster)
|
|
{
|
|
uint triggerSpellId = GetSpellEffectInfo().TriggerSpell;
|
|
|
|
SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId, GetBase().GetCastDifficulty());
|
|
if (triggeredSpellInfo != null)
|
|
{
|
|
Unit triggerCaster = triggeredSpellInfo.NeedsToBeTriggeredByCaster(m_spellInfo) ? caster : target;
|
|
if (triggerCaster != null)
|
|
{
|
|
triggerCaster.CastSpell(target, triggerSpellId, new CastSpellExtraArgs(this));
|
|
Log.outDebug(LogFilter.Spells, "AuraEffect.HandlePeriodicTriggerSpellAuraTick: Spell {0} Trigger {1}", GetId(), triggeredSpellInfo.Id);
|
|
}
|
|
}
|
|
else
|
|
Log.outWarn(LogFilter.Spells, "AuraEffect.HandlePeriodicTriggerSpellAuraTick: Spell {0} has non-existent spell {1} in EffectTriggered[{2}] and is therefor not triggered.", GetId(), triggerSpellId, GetEffIndex());
|
|
}
|
|
|
|
void HandlePeriodicTriggerSpellWithValueAuraTick(Unit target, Unit caster)
|
|
{
|
|
uint triggerSpellId = GetSpellEffectInfo().TriggerSpell;
|
|
SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId, GetBase().GetCastDifficulty());
|
|
if (triggeredSpellInfo != null)
|
|
{
|
|
Unit triggerCaster = triggeredSpellInfo.NeedsToBeTriggeredByCaster(m_spellInfo) ? caster : target;
|
|
if (triggerCaster != null)
|
|
{
|
|
CastSpellExtraArgs args = new(this);
|
|
for (int i = 0; i < SpellConst.MaxEffects; ++i)
|
|
args.AddSpellMod(SpellValueMod.BasePoint0 + i, GetAmount());
|
|
|
|
triggerCaster.CastSpell(target, triggerSpellId, args);
|
|
Log.outDebug(LogFilter.Spells, "AuraEffect.HandlePeriodicTriggerSpellWithValueAuraTick: Spell {0} Trigger {1}", GetId(), triggeredSpellInfo.Id);
|
|
}
|
|
}
|
|
else
|
|
Log.outWarn(LogFilter.Spells, "AuraEffect.HandlePeriodicTriggerSpellWithValueAuraTick: Spell {0} has non-existent spell {1} in EffectTriggered[{2}] and is therefor not triggered.", GetId(), triggerSpellId, GetEffIndex());
|
|
}
|
|
|
|
void HandlePeriodicDamageAurasTick(Unit target, Unit caster)
|
|
{
|
|
if (!target.IsAlive())
|
|
return;
|
|
|
|
if (target.HasUnitState(UnitState.Isolated) || target.IsImmunedToDamage(GetSpellInfo()))
|
|
{
|
|
SendTickImmune(target, caster);
|
|
return;
|
|
}
|
|
|
|
// Consecrate ticks can miss and will not show up in the combat log
|
|
// dynobj auras must always have a caster
|
|
if (GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura) &&
|
|
caster.SpellHitResult(target, GetSpellInfo(), false) != SpellMissInfo.None)
|
|
return;
|
|
|
|
CleanDamage cleanDamage = new(0, 0, WeaponAttackType.BaseAttack, MeleeHitOutcome.Normal);
|
|
|
|
uint stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes.NoScaleWithStack) ? GetBase().GetStackAmount() : 1u;
|
|
|
|
// ignore non positive values (can be result apply spellmods to aura damage
|
|
uint damage = (uint)Math.Max(GetAmount(), 0);
|
|
|
|
// Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations
|
|
Global.ScriptMgr.ModifyPeriodicDamageAurasTick(target, caster, ref damage);
|
|
|
|
switch (GetAuraType())
|
|
{
|
|
case AuraType.PeriodicDamage:
|
|
{
|
|
if (caster != null)
|
|
damage = caster.SpellDamageBonusDone(target, GetSpellInfo(), damage, DamageEffectType.DOT, GetSpellEffectInfo(), stackAmountForBonuses);
|
|
|
|
damage = target.SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DamageEffectType.DOT);
|
|
|
|
// There is a Chance to make a Soul Shard when Drain soul does damage
|
|
if (caster != null && GetSpellInfo().SpellFamilyName == SpellFamilyNames.Warlock && GetSpellInfo().SpellFamilyFlags[0].HasAnyFlag(0x00004000u))
|
|
{
|
|
if (caster.IsTypeId(TypeId.Player) && caster.ToPlayer().IsHonorOrXPTarget(target))
|
|
caster.CastSpell(caster, 95810, new CastSpellExtraArgs(this));
|
|
}
|
|
else if (GetSpellInfo().SpellFamilyName == SpellFamilyNames.Generic)
|
|
{
|
|
switch (GetId())
|
|
{
|
|
case 70911: // Unbound Plague
|
|
case 72854: // Unbound Plague
|
|
case 72855: // Unbound Plague
|
|
case 72856: // Unbound Plague
|
|
damage *= (uint)Math.Pow(1.25f, _ticksDone);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case AuraType.PeriodicWeaponPercentDamage:
|
|
{
|
|
WeaponAttackType attackType = GetSpellInfo().GetAttackType();
|
|
|
|
damage = MathFunctions.CalculatePct(caster.CalculateDamage(attackType, false, true), GetAmount());
|
|
|
|
// Add melee damage bonuses (also check for negative)
|
|
if (caster != null)
|
|
damage = caster.MeleeDamageBonusDone(target, damage, attackType, DamageEffectType.DOT, GetSpellInfo());
|
|
|
|
damage = target.MeleeDamageBonusTaken(caster, damage, attackType, DamageEffectType.DOT, GetSpellInfo());
|
|
break;
|
|
}
|
|
case AuraType.PeriodicDamagePercent:
|
|
// ceil obtained value, it may happen that 10 ticks for 10% damage may not kill owner
|
|
damage = (uint)Math.Ceiling(MathFunctions.CalculatePct((float)target.GetMaxHealth(), (float)damage));
|
|
damage = target.SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DamageEffectType.DOT);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
bool crit = RandomHelper.randChance(GetCritChanceFor(caster, target));
|
|
if (crit)
|
|
damage = Unit.SpellCriticalDamageBonus(caster, m_spellInfo, damage, target);
|
|
|
|
// Calculate armor mitigation
|
|
if (Unit.IsDamageReducedByArmor(GetSpellInfo().GetSchoolMask(), GetSpellInfo()))
|
|
{
|
|
uint damageReducedArmor = Unit.CalcArmorReducedDamage(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetAttackType(), GetBase().GetCasterLevel());
|
|
cleanDamage.mitigated_damage += damage - damageReducedArmor;
|
|
damage = damageReducedArmor;
|
|
}
|
|
|
|
if (!GetSpellInfo().HasAttribute(SpellAttr4.FixedDamage))
|
|
{
|
|
if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura))
|
|
damage = (uint)target.CalculateAOEAvoidance((int)damage, (uint)m_spellInfo.SchoolMask, GetBase().GetCastItemGUID());
|
|
}
|
|
|
|
int dmg = (int)damage;
|
|
if (!GetSpellInfo().HasAttribute(SpellAttr4.FixedDamage) && caster != null && caster.CanApplyResilience())
|
|
Unit.ApplyResilience(target, ref dmg);
|
|
damage = (uint)dmg;
|
|
|
|
DamageInfo damageInfo = new(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetSchoolMask(), DamageEffectType.DOT, WeaponAttackType.BaseAttack);
|
|
Unit.CalcAbsorbResist(damageInfo);
|
|
damage = damageInfo.GetDamage();
|
|
|
|
uint absorb = damageInfo.GetAbsorb();
|
|
uint resist = damageInfo.GetResist();
|
|
Unit.DealDamageMods(caster, target, ref damage, ref absorb);
|
|
|
|
// Set trigger flag
|
|
ProcFlags procAttacker = ProcFlags.DonePeriodic;
|
|
ProcFlags procVictim = ProcFlags.TakenPeriodic;
|
|
ProcFlagsHit hitMask = damageInfo.GetHitMask();
|
|
|
|
if (damage != 0)
|
|
{
|
|
hitMask |= crit ? ProcFlagsHit.Critical : ProcFlagsHit.Normal;
|
|
procVictim |= ProcFlags.TakenDamage;
|
|
}
|
|
|
|
int overkill = (int)(damage - target.GetHealth());
|
|
if (overkill < 0)
|
|
overkill = 0;
|
|
|
|
SpellPeriodicAuraLogInfo pInfo = new(this, damage, (uint)dmg, (uint)overkill, absorb, resist, 0.0f, crit);
|
|
|
|
Unit.DealDamage(caster, target, damage, cleanDamage, DamageEffectType.DOT, GetSpellInfo().GetSchoolMask(), GetSpellInfo(), true);
|
|
|
|
Unit.ProcSkillsAndAuras(caster, target, procAttacker, procVictim, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.Hit, hitMask, null, damageInfo, null);
|
|
target.SendPeriodicAuraLog(pInfo);
|
|
}
|
|
|
|
void HandlePeriodicHealthLeechAuraTick(Unit target, Unit caster)
|
|
{
|
|
if (!target.IsAlive())
|
|
return;
|
|
|
|
if (target.HasUnitState(UnitState.Isolated) || target.IsImmunedToDamage(GetSpellInfo()))
|
|
{
|
|
SendTickImmune(target, caster);
|
|
return;
|
|
}
|
|
|
|
// dynobj auras must always have a caster
|
|
if (GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura) &&
|
|
caster.SpellHitResult(target, GetSpellInfo(), false) != SpellMissInfo.None)
|
|
return;
|
|
|
|
CleanDamage cleanDamage = new(0, 0, GetSpellInfo().GetAttackType(), MeleeHitOutcome.Normal);
|
|
|
|
uint stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes.NoScaleWithStack) ? GetBase().GetStackAmount() : 1u;
|
|
|
|
// ignore negative values (can be result apply spellmods to aura damage
|
|
uint damage = (uint)Math.Max(GetAmount(), 0);
|
|
|
|
if (caster)
|
|
damage = caster.SpellDamageBonusDone(target, GetSpellInfo(), damage, DamageEffectType.DOT, GetSpellEffectInfo(), stackAmountForBonuses);
|
|
|
|
damage = target.SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DamageEffectType.DOT);
|
|
|
|
bool crit = RandomHelper.randChance(GetCritChanceFor(caster, target));
|
|
if (crit)
|
|
damage = Unit.SpellCriticalDamageBonus(caster, m_spellInfo, damage, target);
|
|
|
|
// Calculate armor mitigation
|
|
if (Unit.IsDamageReducedByArmor(GetSpellInfo().GetSchoolMask(), GetSpellInfo()))
|
|
{
|
|
uint damageReducedArmor = Unit.CalcArmorReducedDamage(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetAttackType(), GetBase().GetCasterLevel());
|
|
cleanDamage.mitigated_damage += damage - damageReducedArmor;
|
|
damage = damageReducedArmor;
|
|
}
|
|
|
|
if (!GetSpellInfo().HasAttribute(SpellAttr4.FixedDamage))
|
|
{
|
|
if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura))
|
|
damage = (uint)target.CalculateAOEAvoidance((int)damage, (uint)m_spellInfo.SchoolMask, GetBase().GetCastItemGUID());
|
|
}
|
|
|
|
int dmg = (int)damage;
|
|
if (!GetSpellInfo().HasAttribute(SpellAttr4.FixedDamage) && caster != null && caster.CanApplyResilience())
|
|
Unit.ApplyResilience(target, ref dmg);
|
|
|
|
damage = (uint)dmg;
|
|
|
|
DamageInfo damageInfo = new(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetSchoolMask(), DamageEffectType.DOT, GetSpellInfo().GetAttackType());
|
|
Unit.CalcAbsorbResist(damageInfo);
|
|
|
|
uint absorb = damageInfo.GetAbsorb();
|
|
uint resist = damageInfo.GetResist();
|
|
|
|
// SendSpellNonMeleeDamageLog expects non-absorbed/non-resisted damage
|
|
SpellNonMeleeDamage log = new(caster, target, GetSpellInfo(), GetBase().GetSpellVisual(), GetSpellInfo().GetSchoolMask(), GetBase().GetCastId());
|
|
log.damage = damage;
|
|
log.originalDamage = (uint)dmg;
|
|
log.absorb = absorb;
|
|
log.resist = resist;
|
|
log.periodicLog = true;
|
|
if (crit)
|
|
log.HitInfo |= HitInfo.CriticalHit;
|
|
|
|
// Set trigger flag
|
|
ProcFlags procAttacker = ProcFlags.DonePeriodic;
|
|
ProcFlags procVictim = ProcFlags.TakenPeriodic;
|
|
ProcFlagsHit hitMask = damageInfo.GetHitMask();
|
|
|
|
if (damage != 0)
|
|
{
|
|
hitMask |= crit ? ProcFlagsHit.Critical : ProcFlagsHit.Normal;
|
|
procVictim |= ProcFlags.TakenDamage;
|
|
}
|
|
|
|
int new_damage = (int)Unit.DealDamage(caster, target, damage, cleanDamage, DamageEffectType.DOT, GetSpellInfo().GetSchoolMask(), GetSpellInfo(), false);
|
|
Unit.ProcSkillsAndAuras(caster, target, procAttacker, procVictim, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.Hit, hitMask, null, damageInfo, null);
|
|
|
|
// process caster heal from now on (must be in world)
|
|
if (!caster || !caster.IsAlive())
|
|
return;
|
|
|
|
float gainMultiplier = GetSpellEffectInfo().CalcValueMultiplier(caster);
|
|
|
|
uint heal = caster.SpellHealingBonusDone(caster, GetSpellInfo(), (uint)(new_damage * gainMultiplier), DamageEffectType.DOT, GetSpellEffectInfo(), stackAmountForBonuses);
|
|
heal = caster.SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DamageEffectType.DOT);
|
|
|
|
HealInfo healInfo = new(caster, caster, heal, GetSpellInfo(), GetSpellInfo().GetSchoolMask());
|
|
caster.HealBySpell(healInfo);
|
|
|
|
caster.GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo());
|
|
Unit.ProcSkillsAndAuras(caster, caster, ProcFlags.DonePeriodic, ProcFlags.TakenPeriodic, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.Hit, hitMask, null, null, healInfo);
|
|
|
|
caster.SendSpellNonMeleeDamageLog(log);
|
|
}
|
|
|
|
void HandlePeriodicHealthFunnelAuraTick(Unit target, Unit caster)
|
|
{
|
|
if (caster == null || !caster.IsAlive() || !target.IsAlive())
|
|
return;
|
|
|
|
if (target.HasUnitState(UnitState.Isolated))
|
|
{
|
|
SendTickImmune(target, caster);
|
|
return;
|
|
}
|
|
|
|
uint damage = (uint)Math.Max(GetAmount(), 0);
|
|
// do not kill health donator
|
|
if (caster.GetHealth() < damage)
|
|
damage = (uint)caster.GetHealth() - 1;
|
|
if (damage == 0)
|
|
return;
|
|
|
|
caster.ModifyHealth(-(int)damage);
|
|
Log.outDebug(LogFilter.Spells, "PeriodicTick: donator {0} target {1} damage {2}.", caster.GetEntry(), target.GetEntry(), damage);
|
|
|
|
float gainMultiplier = GetSpellEffectInfo().CalcValueMultiplier(caster);
|
|
|
|
damage = (uint)(damage * gainMultiplier);
|
|
|
|
HealInfo healInfo = new(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetSchoolMask());
|
|
caster.HealBySpell(healInfo);
|
|
Unit.ProcSkillsAndAuras(caster, target, ProcFlags.DonePeriodic, ProcFlags.TakenPeriodic, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.Hit, ProcFlagsHit.Normal, null, null, healInfo);
|
|
}
|
|
|
|
void HandlePeriodicHealAurasTick(Unit target, Unit caster)
|
|
{
|
|
if (!target.IsAlive())
|
|
return;
|
|
|
|
if (target.HasUnitState(UnitState.Isolated))
|
|
{
|
|
SendTickImmune(target, caster);
|
|
return;
|
|
}
|
|
|
|
// heal for caster damage (must be alive)
|
|
if (target != caster && GetSpellInfo().HasAttribute(SpellAttr2.HealthFunnel) && (caster == null || !caster.IsAlive()))
|
|
return;
|
|
|
|
// don't regen when permanent aura target has full power
|
|
if (GetBase().IsPermanent() && target.IsFullHealth())
|
|
return;
|
|
|
|
uint stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes.NoScaleWithStack) ? GetBase().GetStackAmount() : 1u;
|
|
|
|
// ignore negative values (can be result apply spellmods to aura damage
|
|
uint damage = (uint)Math.Max(GetAmount(), 0);
|
|
|
|
if (GetAuraType() == AuraType.ObsModHealth)
|
|
damage = (uint)target.CountPctFromMaxHealth((int)damage);
|
|
else if (caster != null)
|
|
damage = caster.SpellHealingBonusDone(target, GetSpellInfo(), damage, DamageEffectType.DOT, GetSpellEffectInfo(), stackAmountForBonuses);
|
|
|
|
damage = target.SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DamageEffectType.DOT);
|
|
|
|
bool crit = RandomHelper.randChance(GetCritChanceFor(caster, target));
|
|
if (crit)
|
|
damage = (uint)Unit.SpellCriticalHealingBonus(caster, m_spellInfo, (int)damage, target);
|
|
|
|
Log.outDebug(LogFilter.Spells, "PeriodicTick: {0} (TypeId: {1}) heal of {2} (TypeId: {3}) for {4} health inflicted by {5}",
|
|
GetCasterGUID().ToString(), GetCaster().GetTypeId(), target.GetGUID().ToString(), target.GetTypeId(), damage, GetId());
|
|
|
|
uint heal = (uint)damage;
|
|
|
|
HealInfo healInfo = new(caster, target, heal, GetSpellInfo(), GetSpellInfo().GetSchoolMask());
|
|
Unit.CalcHealAbsorb(healInfo);
|
|
Unit.DealHeal(healInfo);
|
|
|
|
SpellPeriodicAuraLogInfo pInfo = new(this, heal, (uint)damage, heal - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit);
|
|
target.SendPeriodicAuraLog(pInfo);
|
|
|
|
if (caster != null)
|
|
target.GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo());
|
|
|
|
// %-based heal - does not proc auras
|
|
if (GetAuraType() == AuraType.ObsModHealth)
|
|
return;
|
|
|
|
ProcFlags procAttacker = ProcFlags.DonePeriodic;
|
|
ProcFlags procVictim = ProcFlags.TakenPeriodic;
|
|
ProcFlagsHit hitMask = crit ? ProcFlagsHit.Critical : ProcFlagsHit.Normal;
|
|
// ignore item heals
|
|
if (GetBase().GetCastItemGUID().IsEmpty())
|
|
Unit.ProcSkillsAndAuras(caster, target, procAttacker, procVictim, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.Hit, hitMask, null, null, healInfo);
|
|
}
|
|
|
|
void HandlePeriodicManaLeechAuraTick(Unit target, Unit caster)
|
|
{
|
|
PowerType powerType = (PowerType)GetMiscValue();
|
|
|
|
if (caster == null || !caster.IsAlive() || !target.IsAlive() || target.GetPowerType() != powerType)
|
|
return;
|
|
|
|
if (target.HasUnitState(UnitState.Isolated) || target.IsImmunedToDamage(GetSpellInfo()))
|
|
{
|
|
SendTickImmune(target, caster);
|
|
return;
|
|
}
|
|
|
|
if (GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura) &&
|
|
caster.SpellHitResult(target, GetSpellInfo(), false) != SpellMissInfo.None)
|
|
return;
|
|
|
|
// ignore negative values (can be result apply spellmods to aura damage
|
|
int drainAmount = Math.Max(GetAmount(), 0);
|
|
|
|
int drainedAmount = -target.ModifyPower(powerType, -drainAmount);
|
|
float gainMultiplier = GetSpellEffectInfo().CalcValueMultiplier(caster);
|
|
|
|
SpellPeriodicAuraLogInfo pInfo = new(this, (uint)drainedAmount, (uint)drainAmount, 0, 0, 0, gainMultiplier, false);
|
|
|
|
int gainAmount = (int)(drainedAmount * gainMultiplier);
|
|
int gainedAmount = 0;
|
|
if (gainAmount != 0)
|
|
{
|
|
gainedAmount = caster.ModifyPower(powerType, gainAmount);
|
|
// energize is not modified by threat modifiers
|
|
target.GetThreatManager().AddThreat(caster, gainedAmount * 0.5f, GetSpellInfo(), true);
|
|
}
|
|
|
|
// Drain Mana
|
|
if (caster.GetGuardianPet() != null && m_spellInfo.SpellFamilyName == SpellFamilyNames.Warlock && m_spellInfo.SpellFamilyFlags[0].HasAnyFlag<uint>(0x00000010))
|
|
{
|
|
int manaFeedVal = 0;
|
|
AuraEffect aurEff = GetBase().GetEffect(1);
|
|
if (aurEff != null)
|
|
manaFeedVal = aurEff.GetAmount();
|
|
|
|
if (manaFeedVal > 0)
|
|
{
|
|
int feedAmount = MathFunctions.CalculatePct(gainedAmount, manaFeedVal);
|
|
|
|
CastSpellExtraArgs args = new(this);
|
|
args.AddSpellMod(SpellValueMod.BasePoint0, feedAmount);
|
|
caster.CastSpell(caster, 32554, args);
|
|
}
|
|
}
|
|
|
|
target.SendPeriodicAuraLog(pInfo);
|
|
}
|
|
|
|
void HandleObsModPowerAuraTick(Unit target, Unit caster)
|
|
{
|
|
PowerType powerType;
|
|
if (GetMiscValue() == (int)PowerType.All)
|
|
powerType = target.GetPowerType();
|
|
else
|
|
powerType = (PowerType)GetMiscValue();
|
|
|
|
if (!target.IsAlive() || target.GetMaxPower(powerType) == 0)
|
|
return;
|
|
|
|
if (target.HasUnitState(UnitState.Isolated))
|
|
{
|
|
SendTickImmune(target, caster);
|
|
return;
|
|
}
|
|
|
|
// don't regen when permanent aura target has full power
|
|
if (GetBase().IsPermanent() && target.GetPower(powerType) == target.GetMaxPower(powerType))
|
|
return;
|
|
|
|
// ignore negative values (can be result apply spellmods to aura damage
|
|
int amount = Math.Max(GetAmount(), 0) * target.GetMaxPower(powerType) / 100;
|
|
|
|
SpellPeriodicAuraLogInfo pInfo = new(this, (uint)amount, (uint)amount, 0, 0, 0, 0.0f, false);
|
|
|
|
int gain = target.ModifyPower(powerType, amount);
|
|
|
|
if (caster != null)
|
|
target.GetThreatManager().ForwardThreatForAssistingMe(caster, gain * 0.5f, GetSpellInfo(), true);
|
|
|
|
target.SendPeriodicAuraLog(pInfo);
|
|
}
|
|
|
|
void HandlePeriodicEnergizeAuraTick(Unit target, Unit caster)
|
|
{
|
|
PowerType powerType = (PowerType)GetMiscValue();
|
|
if (!target.IsAlive() || target.GetMaxPower(powerType) == 0)
|
|
return;
|
|
|
|
if (target.HasUnitState(UnitState.Isolated))
|
|
{
|
|
SendTickImmune(target, caster);
|
|
return;
|
|
}
|
|
|
|
// don't regen when permanent aura target has full power
|
|
if (GetBase().IsPermanent() && target.GetPower(powerType) == target.GetMaxPower(powerType))
|
|
return;
|
|
|
|
// ignore negative values (can be result apply spellmods to aura damage
|
|
int amount = Math.Max(GetAmount(), 0);
|
|
|
|
SpellPeriodicAuraLogInfo pInfo = new(this, (uint)amount, (uint)amount, 0, 0, 0, 0.0f, false);
|
|
int gain = target.ModifyPower(powerType, amount);
|
|
|
|
if (caster != null)
|
|
target.GetThreatManager().ForwardThreatForAssistingMe(caster, gain * 0.5f, GetSpellInfo(), true);
|
|
|
|
target.SendPeriodicAuraLog(pInfo);
|
|
}
|
|
|
|
void HandlePeriodicPowerBurnAuraTick(Unit target, Unit caster)
|
|
{
|
|
PowerType powerType = (PowerType)GetMiscValue();
|
|
|
|
if (caster == null || !target.IsAlive() || target.GetPowerType() != powerType)
|
|
return;
|
|
|
|
if (target.HasUnitState(UnitState.Isolated) || target.IsImmunedToDamage(GetSpellInfo()))
|
|
{
|
|
SendTickImmune(target, caster);
|
|
return;
|
|
}
|
|
|
|
// ignore negative values (can be result apply spellmods to aura damage
|
|
int damage = Math.Max(GetAmount(), 0);
|
|
|
|
uint gain = (uint)(-target.ModifyPower(powerType, -damage));
|
|
|
|
float dmgMultiplier = GetSpellEffectInfo().CalcValueMultiplier(caster);
|
|
|
|
SpellInfo spellProto = GetSpellInfo();
|
|
// maybe has to be sent different to client, but not by SMSG_PERIODICAURALOG
|
|
SpellNonMeleeDamage damageInfo = new(caster, target, spellProto, GetBase().GetSpellVisual(), spellProto.SchoolMask, GetBase().GetCastId());
|
|
damageInfo.periodicLog = true;
|
|
// no SpellDamageBonus for burn mana
|
|
caster.CalculateSpellDamageTaken(damageInfo, (int)(gain * dmgMultiplier), spellProto);
|
|
|
|
Unit.DealDamageMods(damageInfo.attacker, damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb);
|
|
|
|
// Set trigger flag
|
|
ProcFlags procAttacker = ProcFlags.DonePeriodic;
|
|
ProcFlags procVictim = ProcFlags.TakenPeriodic;
|
|
ProcFlagsHit hitMask = Unit.CreateProcHitMask(damageInfo, SpellMissInfo.None);
|
|
ProcFlagsSpellType spellTypeMask = ProcFlagsSpellType.NoDmgHeal;
|
|
if (damageInfo.damage != 0)
|
|
{
|
|
procVictim |= ProcFlags.TakenDamage;
|
|
spellTypeMask |= ProcFlagsSpellType.Damage;
|
|
}
|
|
|
|
caster.DealSpellDamage(damageInfo, true);
|
|
|
|
DamageInfo dotDamageInfo = new(damageInfo, DamageEffectType.DOT, WeaponAttackType.BaseAttack, hitMask);
|
|
Unit.ProcSkillsAndAuras(caster, target, procAttacker, procVictim, spellTypeMask, ProcFlagsSpellPhase.Hit, hitMask, null, dotDamageInfo, null);
|
|
|
|
caster.SendSpellNonMeleeDamageLog(damageInfo);
|
|
}
|
|
|
|
bool CanPeriodicTickCrit()
|
|
{
|
|
if (GetSpellInfo().HasAttribute(SpellAttr2.CantCrit))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
float CalcPeriodicCritChance(Unit caster)
|
|
{
|
|
if (!caster || !CanPeriodicTickCrit())
|
|
return 0.0f;
|
|
|
|
Player modOwner = caster.GetSpellModOwner();
|
|
if (!modOwner)
|
|
return 0.0f;
|
|
|
|
float critChance = modOwner.SpellCritChanceDone(null, this, GetSpellInfo().GetSchoolMask(), GetSpellInfo().GetAttackType());
|
|
return Math.Max(0.0f, critChance);
|
|
}
|
|
|
|
void HandleBreakableCCAuraProc(AuraApplication aurApp, ProcEventInfo eventInfo)
|
|
{
|
|
int damageLeft = (int)(GetAmount() - eventInfo.GetDamageInfo().GetDamage());
|
|
|
|
if (damageLeft <= 0)
|
|
aurApp.GetTarget().RemoveAura(aurApp);
|
|
else
|
|
ChangeAmount(damageLeft);
|
|
}
|
|
|
|
void HandleProcTriggerSpellAuraProc(AuraApplication aurApp, ProcEventInfo eventInfo)
|
|
{
|
|
Unit triggerCaster = aurApp.GetTarget();
|
|
Unit triggerTarget = eventInfo.GetProcTarget();
|
|
|
|
uint triggerSpellId = GetSpellEffectInfo().TriggerSpell;
|
|
SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId, GetBase().GetCastDifficulty());
|
|
if (triggeredSpellInfo != null)
|
|
{
|
|
Log.outDebug(LogFilter.Spells, $"AuraEffect.HandleProcTriggerSpellAuraProc: Triggering spell {triggeredSpellInfo.Id} from aura {GetId()} proc");
|
|
triggerCaster.CastSpell(triggerTarget, triggeredSpellInfo.Id, new CastSpellExtraArgs(this));
|
|
}
|
|
else if (triggerSpellId != 0 && GetAuraType() != AuraType.Dummy)
|
|
Log.outError(LogFilter.Spells, $"AuraEffect.HandleProcTriggerSpellAuraProc: Could not trigger spell {triggerSpellId} from aura {GetId()} proc, because the spell does not have an entry in Spell.dbc.");
|
|
}
|
|
|
|
void HandleProcTriggerSpellWithValueAuraProc(AuraApplication aurApp, ProcEventInfo eventInfo)
|
|
{
|
|
Unit triggerCaster = aurApp.GetTarget();
|
|
Unit triggerTarget = eventInfo.GetProcTarget();
|
|
|
|
uint triggerSpellId = GetSpellEffectInfo().TriggerSpell;
|
|
SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId, GetBase().GetCastDifficulty());
|
|
if (triggeredSpellInfo != null)
|
|
{
|
|
CastSpellExtraArgs args = new(this);
|
|
args.AddSpellMod(SpellValueMod.BasePoint0, GetAmount());
|
|
triggerCaster.CastSpell(triggerTarget, triggerSpellId, args);
|
|
Log.outDebug(LogFilter.Spells, "AuraEffect.HandleProcTriggerSpellWithValueAuraProc: Triggering spell {0} with value {1} from aura {2} proc", triggeredSpellInfo.Id, GetAmount(), GetId());
|
|
}
|
|
else
|
|
Log.outError(LogFilter.Spells, "AuraEffect.HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell {0} from aura {1} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
|
|
}
|
|
|
|
void HandleProcTriggerDamageAuraProc(AuraApplication aurApp, ProcEventInfo eventInfo)
|
|
{
|
|
Unit target = aurApp.GetTarget();
|
|
Unit triggerTarget = eventInfo.GetProcTarget();
|
|
if (triggerTarget.HasUnitState(UnitState.Isolated) || triggerTarget.IsImmunedToDamage(GetSpellInfo()))
|
|
{
|
|
SendTickImmune(triggerTarget, target);
|
|
return;
|
|
}
|
|
|
|
SpellNonMeleeDamage damageInfo = new(target, triggerTarget, GetSpellInfo(), GetBase().GetSpellVisual(), GetSpellInfo().SchoolMask, GetBase().GetCastId());
|
|
int damage = (int)target.SpellDamageBonusDone(triggerTarget, GetSpellInfo(), (uint)GetAmount(), DamageEffectType.SpellDirect, GetSpellEffectInfo());
|
|
damage = (int)triggerTarget.SpellDamageBonusTaken(target, GetSpellInfo(), (uint)damage, DamageEffectType.SpellDirect);
|
|
target.CalculateSpellDamageTaken(damageInfo, damage, GetSpellInfo());
|
|
Unit.DealDamageMods(damageInfo.attacker, damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb);
|
|
target.DealSpellDamage(damageInfo, true);
|
|
target.SendSpellNonMeleeDamageLog(damageInfo);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ForceWeather)]
|
|
void HandleAuraForceWeather(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
|
|
if (target == null)
|
|
return;
|
|
|
|
if (apply)
|
|
target.SendPacket(new WeatherPkt((WeatherState)GetMiscValue(), 1.0f));
|
|
else
|
|
target.GetMap().SendZoneWeather(target.GetZoneId(), target);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.EnableAltPower)]
|
|
void HandleEnableAltPower(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
int altPowerId = GetMiscValue();
|
|
UnitPowerBarRecord powerEntry = CliDB.UnitPowerBarStorage.LookupByKey(altPowerId);
|
|
if (powerEntry == null)
|
|
return;
|
|
|
|
if (apply)
|
|
aurApp.GetTarget().SetMaxPower(PowerType.AlternatePower, (int)powerEntry.MaxPower);
|
|
else
|
|
aurApp.GetTarget().SetMaxPower(PowerType.AlternatePower, 0);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModSpellCategoryCooldown)]
|
|
void HandleModSpellCategoryCooldown(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player player = aurApp.GetTarget().ToPlayer();
|
|
if (player)
|
|
player.SendSpellCategoryCooldowns();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ShowConfirmationPrompt)]
|
|
[AuraEffectHandler(AuraType.ShowConfirmationPromptWithDifficulty)]
|
|
void HandleShowConfirmationPrompt(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player player = aurApp.GetTarget().ToPlayer();
|
|
if (!player)
|
|
return;
|
|
|
|
if (apply)
|
|
player.AddTemporarySpell(_effectInfo.TriggerSpell);
|
|
else
|
|
player.RemoveTemporarySpell(_effectInfo.TriggerSpell);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.OverridePetSpecs)]
|
|
void HandleOverridePetSpecs(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player player = aurApp.GetTarget().ToPlayer();
|
|
if (!player)
|
|
return;
|
|
|
|
if (player.GetClass() != Class.Hunter)
|
|
return;
|
|
|
|
Pet pet = player.GetPet();
|
|
if (!pet)
|
|
return;
|
|
|
|
ChrSpecializationRecord currSpec = CliDB.ChrSpecializationStorage.LookupByKey(pet.GetSpecialization());
|
|
if (currSpec == null)
|
|
return;
|
|
|
|
pet.SetSpecialization(Global.DB2Mgr.GetChrSpecializationByIndex(apply ? Class.Max : 0, currSpec.OrderIndex).Id);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.AllowUsingGameobjectsWhileMounted)]
|
|
void HandleAllowUsingGameobjectsWhileMounted(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (target == null)
|
|
return;
|
|
|
|
if (apply)
|
|
target.AddPlayerLocalFlag(PlayerLocalFlags.CanUseObjectsMounted);
|
|
else if (!target.HasAuraType(AuraType.AllowUsingGameobjectsWhileMounted))
|
|
target.RemovePlayerLocalFlag(PlayerLocalFlags.CanUseObjectsMounted);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.PlayScene)]
|
|
void HandlePlayScene(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player player = aurApp.GetTarget().ToPlayer();
|
|
if (!player)
|
|
return;
|
|
|
|
if (apply)
|
|
player.GetSceneMgr().PlayScene((uint)GetMiscValue());
|
|
else
|
|
player.GetSceneMgr().CancelSceneBySceneId((uint)GetMiscValue());
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.AreaTrigger)]
|
|
void HandleCreateAreaTrigger(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
|
|
if (apply)
|
|
{
|
|
AreaTrigger.CreateAreaTrigger((uint)GetMiscValue(), GetCaster(), target, GetSpellInfo(), target, GetBase().GetDuration(), GetBase().GetSpellVisual(), ObjectGuid.Empty, this);
|
|
}
|
|
else
|
|
{
|
|
Unit caster = GetCaster();
|
|
if (caster)
|
|
caster.RemoveAreaTrigger(this);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.PvpTalents)]
|
|
void HandleAuraPvpTalents(AuraApplication auraApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player target = auraApp.GetTarget().ToPlayer();
|
|
if (target)
|
|
{
|
|
if (apply)
|
|
target.TogglePvpTalents(true);
|
|
else if (!target.HasAuraType(AuraType.PvpTalents))
|
|
target.TogglePvpTalents(false);
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.LinkedSummon)]
|
|
void HandleLinkedSummon(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Unit target = aurApp.GetTarget();
|
|
SpellInfo triggerSpellInfo = Global.SpellMgr.GetSpellInfo(GetSpellEffectInfo().TriggerSpell, GetBase().GetCastDifficulty());
|
|
if (triggerSpellInfo == null)
|
|
return;
|
|
|
|
// on apply cast summon spell
|
|
if (apply)
|
|
{
|
|
CastSpellExtraArgs args = new(this);
|
|
args.CastDifficulty = triggerSpellInfo.Difficulty;
|
|
target.CastSpell(target, triggerSpellInfo.Id, args);
|
|
}
|
|
// on unapply we need to search for and remove the summoned creature
|
|
else
|
|
{
|
|
List<uint> summonedEntries = new();
|
|
foreach (var spellEffectInfo in triggerSpellInfo.GetEffects())
|
|
{
|
|
if (spellEffectInfo.IsEffect(SpellEffectName.Summon))
|
|
{
|
|
uint summonEntry = (uint)spellEffectInfo.MiscValue;
|
|
if (summonEntry != 0)
|
|
summonedEntries.Add(summonEntry);
|
|
|
|
}
|
|
}
|
|
|
|
// we don't know if there can be multiple summons for the same effect, so consider only 1 summon for each effect
|
|
// most of the spells have multiple effects with the same summon spell id for multiple spawns, so right now it's safe to assume there's only 1 spawn per effect
|
|
foreach (uint summonEntry in summonedEntries)
|
|
{
|
|
List<Creature> nearbyEntries = new();
|
|
target.GetCreatureListWithEntryInGrid(nearbyEntries, summonEntry);
|
|
foreach (var creature in nearbyEntries)
|
|
{
|
|
if (creature.GetOwner() == target)
|
|
{
|
|
creature.DespawnOrUnsummon();
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
TempSummon tempSummon = creature.ToTempSummon();
|
|
if (tempSummon)
|
|
{
|
|
if (tempSummon.GetSummoner() == target)
|
|
{
|
|
tempSummon.DespawnOrUnsummon();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.SetFFAPvp)]
|
|
void HandleSetFFAPvP(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (!target)
|
|
return;
|
|
|
|
target.UpdatePvPState(true);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.ModOverrideZonePvpType)]
|
|
void HandleModOverrideZonePVPType(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (target == null)
|
|
return;
|
|
|
|
if (apply)
|
|
target.SetOverrideZonePVPType((ZonePVPTypeOverride)GetMiscValue());
|
|
else if (target.HasAuraType(AuraType.ModOverrideZonePvpType))
|
|
target.SetOverrideZonePVPType((ZonePVPTypeOverride)target.GetAuraEffectsByType(AuraType.ModOverrideZonePvpType).Last().GetMiscValue());
|
|
else
|
|
target.SetOverrideZonePVPType(ZonePVPTypeOverride.None);
|
|
|
|
target.UpdateHostileAreaState(CliDB.AreaTableStorage.LookupByKey(target.GetZoneId()));
|
|
target.UpdatePvPState();
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.BattleGroundPlayerPositionFactional)]
|
|
[AuraEffectHandler(AuraType.BattleGroundPlayerPosition)]
|
|
void HandleBattlegroundPlayerPosition(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player target = aurApp.GetTarget().ToPlayer();
|
|
if (target == null)
|
|
return;
|
|
|
|
BattlegroundMap battlegroundMap = target.GetMap().ToBattlegroundMap();
|
|
if (battlegroundMap == null)
|
|
return;
|
|
|
|
Battleground bg = battlegroundMap.GetBG();
|
|
if (bg == null)
|
|
return;
|
|
|
|
if (apply)
|
|
{
|
|
BattlegroundPlayerPosition playerPosition = new();
|
|
playerPosition.Guid = target.GetGUID();
|
|
playerPosition.ArenaSlot = (sbyte)GetMiscValue();
|
|
playerPosition.Pos = target.GetPosition();
|
|
|
|
if (GetAuraType() == AuraType.BattleGroundPlayerPositionFactional)
|
|
playerPosition.IconID = target.GetTeam() == Team.Alliance ? BattlegroundConst.PlayerPositionIconHordeFlag : BattlegroundConst.PlayerPositionIconAllianceFlag;
|
|
else if (GetAuraType() == AuraType.BattleGroundPlayerPosition)
|
|
playerPosition.IconID = target.GetTeam() == Team.Alliance ? BattlegroundConst.PlayerPositionIconAllianceFlag : BattlegroundConst.PlayerPositionIconHordeFlag;
|
|
else
|
|
Log.outWarn(LogFilter.Spells, $"Unknown aura effect {GetAuraType()} handled by HandleBattlegroundPlayerPosition.");
|
|
|
|
bg.AddPlayerPosition(playerPosition);
|
|
}
|
|
else
|
|
bg.RemovePlayerPosition(target.GetGUID());
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.StoreTeleportReturnPoint)]
|
|
void HandleStoreTeleportReturnPoint(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
Player playerTarget = aurApp.GetTarget().ToPlayer();
|
|
if (playerTarget == null)
|
|
return;
|
|
|
|
if (apply)
|
|
playerTarget.AddStoredAuraTeleportLocation(GetSpellInfo().Id);
|
|
else if (!playerTarget.GetSession().IsLogingOut())
|
|
playerTarget.RemoveStoredAuraTeleportLocation(GetSpellInfo().Id);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.CosmeticMounted)]
|
|
void HandleCosmeticMounted(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
if (apply)
|
|
aurApp.GetTarget().SetCosmeticMountDisplayId((uint)GetMiscValue());
|
|
else
|
|
aurApp.GetTarget().SetCosmeticMountDisplayId(0); // set cosmetic mount to 0, even if multiple auras are active; tested with zandalari racial + divine steed
|
|
|
|
Player playerTarget = aurApp.GetTarget().ToPlayer();
|
|
if (playerTarget == null)
|
|
return;
|
|
|
|
playerTarget.SendMovementSetCollisionHeight(playerTarget.GetCollisionHeight(), UpdateCollisionHeightReason.Force);
|
|
}
|
|
|
|
[AuraEffectHandler(AuraType.SuppressItemPassiveEffectBySpellLabel)]
|
|
void HandleSuppressItemPassiveEffectBySpellLabel(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
|
{
|
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
|
return;
|
|
|
|
List<Aura> suppressedAuras = new();
|
|
foreach (var appliedAura in aurApp.GetTarget().GetOwnedAuras())
|
|
if (appliedAura.Value.GetSpellInfo().HasLabel((uint)GetMiscValue()))
|
|
suppressedAuras.Add(appliedAura.Value);
|
|
|
|
// Refresh applications
|
|
foreach (Aura aura in suppressedAuras)
|
|
aura.ApplyForTargets();
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
class AbsorbAuraOrderPred : Comparer<AuraEffect>
|
|
{
|
|
public override int Compare(AuraEffect aurEffA, AuraEffect aurEffB)
|
|
{
|
|
SpellInfo spellProtoA = aurEffA.GetSpellInfo();
|
|
SpellInfo spellProtoB = aurEffB.GetSpellInfo();
|
|
|
|
// Fel Blossom
|
|
if (spellProtoA.Id == 28527)
|
|
return 1;
|
|
if (spellProtoB.Id == 28527)
|
|
return 0;
|
|
|
|
// Ice Barrier
|
|
if (spellProtoA.GetCategory() == 471)
|
|
return 1;
|
|
if (spellProtoB.GetCategory() == 471)
|
|
return 0;
|
|
|
|
// Sacrifice
|
|
if (spellProtoA.Id == 7812)
|
|
return 1;
|
|
if (spellProtoB.Id == 7812)
|
|
return 0;
|
|
|
|
// Cauterize (must be last)
|
|
if (spellProtoA.Id == 86949)
|
|
return 0;
|
|
if (spellProtoB.Id == 86949)
|
|
return 1;
|
|
|
|
// Spirit of Redemption (must be last)
|
|
if (spellProtoA.Id == 20711)
|
|
return 0;
|
|
if (spellProtoB.Id == 20711)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
}
|