Implementation of QAston proc system
This commit is contained in:
+112
-52
@@ -742,10 +742,9 @@ namespace Game.Spells
|
||||
m_timeCla = 1 * Time.InMilliseconds;
|
||||
}
|
||||
|
||||
void RefreshTimers()
|
||||
void RefreshTimers(bool resetPeriodicTimer)
|
||||
{
|
||||
m_maxDuration = CalcMaxDuration();
|
||||
bool resetPeriodic = true;
|
||||
if (m_spellInfo.HasAttribute(SpellAttr8.DontResetPeriodicTimer))
|
||||
{
|
||||
int minPeriod = m_maxDuration;
|
||||
@@ -764,15 +763,18 @@ namespace Game.Spells
|
||||
if (GetDuration() <= minPeriod)
|
||||
{
|
||||
m_maxDuration += GetDuration();
|
||||
resetPeriodic = false;
|
||||
resetPeriodicTimer = false;
|
||||
}
|
||||
}
|
||||
|
||||
RefreshDuration();
|
||||
Unit caster = GetCaster();
|
||||
for (byte i = 0; i < SpellConst.MaxEffects; ++i)
|
||||
if (HasEffect(i))
|
||||
GetEffect(i).CalculatePeriodic(caster, resetPeriodic, false);
|
||||
{
|
||||
AuraEffect aurEff = GetEffect(i);
|
||||
if (aurEff != null)
|
||||
aurEff.CalculatePeriodic(caster, resetPeriodicTimer, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCharges(int charges)
|
||||
@@ -853,7 +855,7 @@ namespace Game.Spells
|
||||
SetNeedClientUpdateForTargets();
|
||||
}
|
||||
|
||||
public bool ModStackAmount(int num, AuraRemoveMode removeMode = AuraRemoveMode.Default)
|
||||
public bool ModStackAmount(int num, AuraRemoveMode removeMode = AuraRemoveMode.Default, bool resetPeriodicTimer = true)
|
||||
{
|
||||
int stackAmount = m_stackAmount + num;
|
||||
|
||||
@@ -881,22 +883,10 @@ namespace Game.Spells
|
||||
if (refresh)
|
||||
{
|
||||
RefreshSpellMods();
|
||||
RefreshTimers();
|
||||
RefreshTimers(resetPeriodicTimer);
|
||||
|
||||
// reset charges
|
||||
SetCharges(CalcMaxCharges());
|
||||
// FIXME: not a best way to synchronize charges, but works
|
||||
for (byte i = 0; i < SpellConst.MaxEffects; ++i)
|
||||
{
|
||||
AuraEffect aurEff = GetEffect(i);
|
||||
if (aurEff != null)
|
||||
if (aurEff.GetAuraType() == AuraType.AddFlatModifier || aurEff.GetAuraType() == AuraType.AddPctModifier)
|
||||
{
|
||||
SpellModifier mod = aurEff.GetSpellModifier();
|
||||
if (mod != null)
|
||||
mod.charges = GetCharges();
|
||||
}
|
||||
}
|
||||
}
|
||||
SetNeedClientUpdateForTargets();
|
||||
return false;
|
||||
@@ -1668,7 +1658,7 @@ namespace Game.Spells
|
||||
m_procCooldown = cooldownEnd;
|
||||
}
|
||||
|
||||
void PrepareProcToTrigger(AuraApplication aurApp, ProcEventInfo eventInfo, DateTime now)
|
||||
public void PrepareProcToTrigger(AuraApplication aurApp, ProcEventInfo eventInfo, DateTime now)
|
||||
{
|
||||
bool prepare = CallScriptPrepareProcHandlers(aurApp, eventInfo);
|
||||
if (!prepare)
|
||||
@@ -1687,44 +1677,81 @@ namespace Game.Spells
|
||||
|
||||
// cooldowns should be added to the whole aura (see 51698 area aura)
|
||||
AddProcCooldown(now + TimeSpan.FromMilliseconds(procEntry.Cooldown));
|
||||
|
||||
SetLastProcSuccessTime(now);
|
||||
}
|
||||
|
||||
bool IsProcTriggeredOnEvent(AuraApplication aurApp, ProcEventInfo eventInfo, DateTime now)
|
||||
public uint IsProcTriggeredOnEvent(AuraApplication aurApp, ProcEventInfo eventInfo, DateTime now)
|
||||
{
|
||||
SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(GetId());
|
||||
// only auras with spell proc entry can trigger proc
|
||||
if (procEntry == null)
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
// check if we have charges to proc with
|
||||
if (IsUsingCharges() && GetCharges() == 0)
|
||||
return false;
|
||||
if (IsUsingCharges())
|
||||
{
|
||||
if (GetCharges() == 0)
|
||||
return 0;
|
||||
|
||||
if (procEntry.AttributesMask.HasAnyFlag(ProcAttributes.ReqSpellmod))
|
||||
{
|
||||
Spell spell = eventInfo.GetProcSpell();
|
||||
if (spell != null)
|
||||
if (!spell.m_appliedMods.Contains(this))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// check proc cooldown
|
||||
if (IsProcOnCooldown(now))
|
||||
return false;
|
||||
|
||||
/// @todo
|
||||
// something about triggered spells triggering, and add extra attack effect
|
||||
return 0;
|
||||
|
||||
// do checks against db data
|
||||
if (!Global.SpellMgr.CanSpellTriggerProcOnEvent(procEntry, eventInfo))
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
// check if aura can proc when spell is triggered
|
||||
if (!procEntry.AttributesMask.HasAnyFlag(ProcAttributes.TriggeredCanProc))
|
||||
{
|
||||
Spell spell = eventInfo.GetProcSpell();
|
||||
if (spell)
|
||||
if (spell.IsTriggered())
|
||||
if (!GetSpellInfo().HasAttribute(SpellAttr3.CanProcWithTriggered))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// do checks using conditions table
|
||||
if (!Global.ConditionMgr.IsObjectMeetingNotGroupedConditions(ConditionSourceType.SpellProc, GetId(), eventInfo.GetActor(), eventInfo.GetActionTarget()))
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
// AuraScript Hook
|
||||
bool check = CallScriptCheckProcHandlers(aurApp, eventInfo);
|
||||
if (!check)
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
// At least one effect has to pass checks to proc aura
|
||||
uint procEffectMask = 0;
|
||||
for (byte i = 0; i < SpellConst.MaxEffects; ++i)
|
||||
if (aurApp.HasEffect(i))
|
||||
if (GetEffect(i).CheckEffectProc(aurApp, eventInfo))
|
||||
procEffectMask |= (1u << i);
|
||||
|
||||
if (procEffectMask == 0)
|
||||
return 0;
|
||||
|
||||
/// @todo
|
||||
// do allow additional requirements for procs
|
||||
// this is needed because this is the last moment in which you can prevent aura charge drop on proc
|
||||
// and possibly a way to prevent default checks (if there're going to be any)
|
||||
|
||||
// Aura added by spell can't trigger from self (prevent drop charges/do triggers)
|
||||
// But except periodic and kill triggers (can triggered from self)
|
||||
SpellInfo spellInfo = eventInfo.GetSpellInfo();
|
||||
if (spellInfo != null)
|
||||
if (spellInfo.Id == GetId() && !eventInfo.GetTypeMask().HasAnyFlag(ProcFlags.TakenPeriodic | ProcFlags.Kill))
|
||||
return 0;
|
||||
|
||||
// Check if current equipment meets aura requirements
|
||||
// do that only for passive spells
|
||||
/// @todo this needs to be unified for all kinds of auras
|
||||
@@ -1734,11 +1761,12 @@ namespace Game.Spells
|
||||
if (GetSpellInfo().EquippedItemClass == ItemClass.Weapon)
|
||||
{
|
||||
if (target.ToPlayer().IsInFeralForm())
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
if (eventInfo.GetDamageInfo() != null)
|
||||
DamageInfo damageInfo = eventInfo.GetDamageInfo();
|
||||
if (damageInfo != null)
|
||||
{
|
||||
WeaponAttackType attType = eventInfo.GetDamageInfo().GetAttackType();
|
||||
WeaponAttackType attType = damageInfo.GetAttackType();
|
||||
Item item = null;
|
||||
if (attType == WeaponAttackType.BaseAttack || attType == WeaponAttackType.RangedAttack)
|
||||
item = target.ToPlayer().GetUseableItemByPos(InventorySlots.Bag0, EquipmentSlot.MainHand);
|
||||
@@ -1746,7 +1774,7 @@ namespace Game.Spells
|
||||
item = target.ToPlayer().GetUseableItemByPos(InventorySlots.Bag0, EquipmentSlot.OffHand);
|
||||
|
||||
if (item == null || item.IsBroken() || item.GetTemplate().GetClass() != ItemClass.Weapon || !Convert.ToBoolean((1 << (int)item.GetTemplate().GetSubClass()) & GetSpellInfo().EquippedItemSubClassMask))
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (GetSpellInfo().EquippedItemClass == ItemClass.Armor)
|
||||
@@ -1754,11 +1782,16 @@ namespace Game.Spells
|
||||
// Check if player is wearing shield
|
||||
Item item = target.ToPlayer().GetUseableItemByPos(InventorySlots.Bag0, EquipmentSlot.OffHand);
|
||||
if (item == null || item.IsBroken() || item.GetTemplate().GetClass() != ItemClass.Armor || !Convert.ToBoolean((1 << (int)item.GetTemplate().GetSubClass()) & GetSpellInfo().EquippedItemSubClassMask))
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return RandomHelper.randChance(CalcProcChance(procEntry, eventInfo));
|
||||
SetLastProcAttemptTime(now);
|
||||
|
||||
if (RandomHelper.randChance(CalcProcChance(procEntry, eventInfo)))
|
||||
return procEffectMask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
float CalcProcChance(SpellProcEntry procEntry, ProcEventInfo eventInfo)
|
||||
@@ -1775,6 +1808,10 @@ namespace Game.Spells
|
||||
uint WeaponSpeed = caster.GetBaseAttackTime(eventInfo.GetDamageInfo().GetAttackType());
|
||||
chance = caster.GetPPMProcChance(WeaponSpeed, procEntry.ProcsPerMinute, GetSpellInfo());
|
||||
}
|
||||
|
||||
if (GetSpellInfo().ProcBasePPM > 0.0f)
|
||||
chance = CalcPPMProcChance(caster);
|
||||
|
||||
// apply chance modifer aura, applies also to ppm chance (see improved judgement of light spell)
|
||||
Player modOwner = caster.GetSpellModOwner();
|
||||
if (modOwner != null)
|
||||
@@ -1783,18 +1820,23 @@ namespace Game.Spells
|
||||
return chance;
|
||||
}
|
||||
|
||||
void TriggerProcOnEvent(AuraApplication aurApp, ProcEventInfo eventInfo)
|
||||
public void TriggerProcOnEvent(uint procEffectMask, AuraApplication aurApp, ProcEventInfo eventInfo)
|
||||
{
|
||||
CallScriptProcHandlers(aurApp, eventInfo);
|
||||
|
||||
for (byte i = 0; i < SpellConst.MaxEffects; ++i)
|
||||
bool prevented = CallScriptProcHandlers(aurApp, eventInfo);
|
||||
if (!prevented)
|
||||
{
|
||||
if (aurApp.HasEffect(i))
|
||||
// OnEffectProc / AfterEffectProc hooks handled in AuraEffect.HandleProc()
|
||||
GetEffect(i).HandleProc(aurApp, eventInfo);
|
||||
}
|
||||
for (byte i = 0; i < SpellConst.MaxEffects; ++i)
|
||||
{
|
||||
if (!Convert.ToBoolean(procEffectMask & (1 << i)))
|
||||
continue;
|
||||
|
||||
CallScriptAfterProcHandlers(aurApp, eventInfo);
|
||||
// OnEffectProc / AfterEffectProc hooks handled in AuraEffect.HandleProc()
|
||||
if (aurApp.HasEffect(i))
|
||||
GetEffect(i).HandleProc(aurApp, eventInfo);
|
||||
}
|
||||
|
||||
CallScriptAfterProcHandlers(aurApp, eventInfo);
|
||||
}
|
||||
|
||||
// Remove aura if we've used last charge to proc
|
||||
if (IsUsingCharges() && GetCharges() == 0)
|
||||
@@ -2157,6 +2199,23 @@ namespace Game.Spells
|
||||
}
|
||||
}
|
||||
|
||||
public bool CallScriptCheckEffectProcHandlers(AuraEffect aurEff, AuraApplication aurApp, ProcEventInfo eventInfo)
|
||||
{
|
||||
bool result = true;
|
||||
foreach (var auraScript in m_loadedScripts)
|
||||
{
|
||||
auraScript._PrepareScriptCall(AuraScriptHookType.CheckEffectProc, aurApp);
|
||||
|
||||
foreach (var hook in auraScript.DoCheckEffectProc)
|
||||
if (hook.IsEffectAffected(m_spellInfo, aurEff.GetEffIndex()))
|
||||
result &= hook.Call(aurEff, eventInfo);
|
||||
|
||||
auraScript._FinishScriptCall();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool CallScriptEffectProcHandlers(AuraEffect aurEff, AuraApplication aurApp, ProcEventInfo eventInfo)
|
||||
{
|
||||
bool preventDefault = false;
|
||||
@@ -2308,7 +2367,7 @@ namespace Game.Spells
|
||||
public void SetLastProcSuccessTime(DateTime lastProcSuccessTime) { m_lastProcSuccessTime = lastProcSuccessTime; }
|
||||
|
||||
//Static Methods
|
||||
public static uint BuildEffectMaskForOwner(SpellInfo spellProto, uint avalibleEffectMask, WorldObject owner)
|
||||
public static uint BuildEffectMaskForOwner(SpellInfo spellProto, uint availableEffectMask, WorldObject owner)
|
||||
{
|
||||
Contract.Assert(spellProto != null);
|
||||
Contract.Assert(owner != null);
|
||||
@@ -2333,24 +2392,25 @@ namespace Game.Spells
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (effMask & avalibleEffectMask);
|
||||
return (effMask & availableEffectMask);
|
||||
}
|
||||
public static Aura TryRefreshStackOrCreate(SpellInfo spellproto, ObjectGuid castId, uint tryEffMask, WorldObject owner, Unit caster, int[] baseAmount = null, Item castItem = null, ObjectGuid casterGUID = default(ObjectGuid), int castItemLevel = -1)
|
||||
public static Aura TryRefreshStackOrCreate(SpellInfo spellproto, ObjectGuid castId, uint tryEffMask, WorldObject owner, Unit caster, int[] baseAmount = null, Item castItem = null, ObjectGuid casterGUID = default(ObjectGuid), bool resetPeriodicTimer = true, int castItemLevel = -1)
|
||||
{
|
||||
bool throwway;
|
||||
return TryRefreshStackOrCreate(spellproto, castId, tryEffMask, owner, caster, out throwway, baseAmount, castItem, casterGUID);
|
||||
return TryRefreshStackOrCreate(spellproto, castId, tryEffMask, owner, caster, out throwway, baseAmount, castItem, casterGUID, resetPeriodicTimer, castItemLevel);
|
||||
}
|
||||
public static Aura TryRefreshStackOrCreate(SpellInfo spellproto, ObjectGuid castId, uint tryEffMask, WorldObject owner, Unit caster, out bool refresh, int[] baseAmount, Item castItem = null, ObjectGuid casterGUID = default(ObjectGuid), int castItemLevel = -1)
|
||||
public static Aura TryRefreshStackOrCreate(SpellInfo spellproto, ObjectGuid castId, uint tryEffMask, WorldObject owner, Unit caster, out bool refresh, int[] baseAmount, Item castItem = null, ObjectGuid casterGUID = default(ObjectGuid), bool resetPeriodicTimer = true, int castItemLevel = -1)
|
||||
{
|
||||
Contract.Assert(spellproto != null);
|
||||
Contract.Assert(owner != null);
|
||||
Contract.Assert(caster || !casterGUID.IsEmpty());
|
||||
Contract.Assert(tryEffMask <= SpellConst.MaxEffectMask);
|
||||
refresh = false;
|
||||
|
||||
uint effMask = BuildEffectMaskForOwner(spellproto, tryEffMask, owner);
|
||||
if (effMask == 0)
|
||||
return null;
|
||||
Aura foundAura = owner.ToUnit()._TryStackingOrRefreshingExistingAura(spellproto, effMask, caster, baseAmount, castItem, casterGUID, castItemLevel);
|
||||
Aura foundAura = owner.ToUnit()._TryStackingOrRefreshingExistingAura(spellproto, effMask, caster, baseAmount, castItem, casterGUID, resetPeriodicTimer, castItemLevel);
|
||||
if (foundAura != null)
|
||||
{
|
||||
// we've here aura, which script triggered removal after modding stack amount
|
||||
|
||||
+129
-156
@@ -232,9 +232,9 @@ namespace Game.Spells
|
||||
else // aura just created or reapplied
|
||||
{
|
||||
m_tickNumber = 0;
|
||||
// reset periodic timer on aura create or on reapply when aura isn't dot
|
||||
// possibly we should not reset periodic timers only when aura is triggered by proc
|
||||
// or maybe there's a spell attribute somewhere
|
||||
|
||||
// reset periodic timer on aura create or reapply
|
||||
// we don't reset periodic timers when aura is triggered by proc
|
||||
if (resetPeriodicTimer)
|
||||
{
|
||||
m_periodicTimer = 0;
|
||||
@@ -258,7 +258,6 @@ namespace Game.Spells
|
||||
m_spellmod.type = GetAuraType() == AuraType.AddPctModifier ? SpellModType.Pct : SpellModType.Flat;
|
||||
m_spellmod.spellId = GetId();
|
||||
m_spellmod.mask = GetSpellEffectInfo().SpellClassMask;
|
||||
m_spellmod.charges = GetBase().GetCharges();
|
||||
}
|
||||
m_spellmod.value = GetAmount();
|
||||
break;
|
||||
@@ -655,6 +654,61 @@ namespace Game.Spells
|
||||
}
|
||||
}
|
||||
|
||||
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.MechanicImmunity:
|
||||
case AuraType.ModMechanicResistance:
|
||||
// compare mechanic
|
||||
if (spellInfo == null || (int)spellInfo.Mechanic != GetMiscValue())
|
||||
result = false;
|
||||
break;
|
||||
case AuraType.ModCastingSpeedNotStack:
|
||||
// skip melee hits and instant cast spells
|
||||
if (spellInfo == null || spellInfo.CalcCastTime() == 0)
|
||||
result = false;
|
||||
break;
|
||||
case AuraType.ModSpellDamageFromCaster:
|
||||
// Compare casters
|
||||
if (GetCasterGUID() != eventInfo.GetActor().GetGUID())
|
||||
result = 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())
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Costs Check
|
||||
var costs = eventInfo.GetProcSpell().GetPowerCost();
|
||||
var m = costs.Find(cost => { return cost.Amount > 0; });
|
||||
if (m == null)
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
case AuraType.ReflectSpellsSchool:
|
||||
// Skip melee hits and spells with wrong school
|
||||
if (spellInfo == null || !Convert.ToBoolean((int)spellInfo.GetSchoolMask() & GetMiscValue()))
|
||||
result = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void HandleProc(AuraApplication aurApp, ProcEventInfo eventInfo)
|
||||
{
|
||||
bool prevented = GetBase().CallScriptEffectProcHandlers(this, aurApp, eventInfo);
|
||||
@@ -663,6 +717,16 @@ namespace Game.Spells
|
||||
|
||||
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:
|
||||
HandleBreakableCCAuraProc(aurApp, eventInfo);
|
||||
break;
|
||||
case AuraType.Dummy:
|
||||
case AuraType.ProcTriggerSpell:
|
||||
HandleProcTriggerSpellAuraProc(aurApp, eventInfo);
|
||||
break;
|
||||
@@ -672,16 +736,6 @@ namespace Game.Spells
|
||||
case AuraType.ProcTriggerDamage:
|
||||
HandleProcTriggerDamageAuraProc(aurApp, eventInfo);
|
||||
break;
|
||||
case AuraType.RaidProcFromCharge:
|
||||
HandleRaidProcFromChargeAuraProc(aurApp, eventInfo);
|
||||
break;
|
||||
case AuraType.RaidProcFromChargeWithValue:
|
||||
HandleRaidProcFromChargeWithValueAuraProc(aurApp, eventInfo);
|
||||
break;
|
||||
case AuraType.ProcOnPowerAmount:
|
||||
case AuraType.ProcOnPowerAmount2:
|
||||
HandleProcTriggerSpellOnPowerAmountAuraProc(aurApp, eventInfo);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -829,7 +883,6 @@ namespace Game.Spells
|
||||
public Unit GetCaster() { return auraBase.GetCaster(); }
|
||||
public ObjectGuid GetCasterGUID() { return auraBase.GetCasterGUID(); }
|
||||
public Aura GetBase() { return auraBase; }
|
||||
public SpellModifier GetSpellModifier() { return m_spellmod; }
|
||||
|
||||
public SpellInfo GetSpellInfo() { return m_spellInfo; }
|
||||
public uint GetId() { return m_spellInfo.Id; }
|
||||
@@ -5131,7 +5184,10 @@ namespace Game.Spells
|
||||
if (caster != null)
|
||||
{
|
||||
uint heal = (uint)caster.CountPctFromMaxHealth(10);
|
||||
caster.HealBySpell(target, auraSpellInfo, heal);
|
||||
HealInfo healInfo = new HealInfo(caster, target, heal, auraSpellInfo, auraSpellInfo.GetSchoolMask());
|
||||
caster.HealBySpell(healInfo);
|
||||
|
||||
/// @todo: should proc other auras?
|
||||
int mana = caster.GetMaxPower(PowerType.Mana);
|
||||
if (mana != 0)
|
||||
{
|
||||
@@ -5535,7 +5591,7 @@ namespace Game.Spells
|
||||
// Set trigger flag
|
||||
ProcFlags procAttacker = ProcFlags.DonePeriodic;
|
||||
ProcFlags procVictim = ProcFlags.TakenPeriodic;
|
||||
ProcFlagsExLegacy procEx = (crit ? ProcFlagsExLegacy.CriticalHit : ProcFlagsExLegacy.NormalHit) | ProcFlagsExLegacy.InternalDot;
|
||||
ProcFlagsHit hitMask = crit ? ProcFlagsHit.Critical : ProcFlagsHit.Normal;
|
||||
damage = (damage <= absorb + resist) ? 0 : (damage - absorb - resist);
|
||||
if (damage != 0)
|
||||
procVictim |= ProcFlags.TakenDamage;
|
||||
@@ -5546,7 +5602,8 @@ namespace Game.Spells
|
||||
|
||||
SpellPeriodicAuraLogInfo pInfo = new SpellPeriodicAuraLogInfo(this, damage, overkill, absorb, resist, 0.0f, crit);
|
||||
|
||||
caster.ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, WeaponAttackType.BaseAttack, GetSpellInfo());
|
||||
DamageInfo damageInfo = new DamageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetSchoolMask(), DamageEffectType.DOT, WeaponAttackType.BaseAttack);
|
||||
caster.ProcSkillsAndAuras(target, procAttacker, procVictim, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.None, hitMask, null, damageInfo, null);
|
||||
|
||||
caster.DealDamage(target, damage, cleanDamage, DamageEffectType.DOT, GetSpellInfo().GetSchoolMask(), GetSpellInfo(), true);
|
||||
target.SendPeriodicAuraLog(pInfo);
|
||||
@@ -5624,12 +5681,17 @@ namespace Game.Spells
|
||||
// Set trigger flag
|
||||
ProcFlags procAttacker = ProcFlags.DonePeriodic;
|
||||
ProcFlags procVictim = ProcFlags.TakenPeriodic;
|
||||
ProcFlagsExLegacy procEx = (crit ? ProcFlagsExLegacy.CriticalHit : ProcFlagsExLegacy.NormalHit) | ProcFlagsExLegacy.InternalDot;
|
||||
ProcFlagsHit hitMask = crit ? ProcFlagsHit.Critical : ProcFlagsHit.Normal;
|
||||
damage = (damage <= absorb + resist) ? 0 : (damage - absorb - resist);
|
||||
if (damage != 0)
|
||||
procVictim |= ProcFlags.TakenDamage;
|
||||
|
||||
if (caster.IsAlive())
|
||||
caster.ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, WeaponAttackType.BaseAttack, GetSpellInfo());
|
||||
{
|
||||
DamageInfo damageInfo = new DamageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetSchoolMask(), DamageEffectType.DOT, WeaponAttackType.BaseAttack);
|
||||
caster.ProcSkillsAndAuras(target, procAttacker, procVictim, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.None, hitMask, null, damageInfo, null);
|
||||
}
|
||||
|
||||
int new_damage = (int)caster.DealDamage(target, damage, cleanDamage, DamageEffectType.DOT, GetSpellInfo().GetSchoolMask(), GetSpellInfo(), false);
|
||||
if (caster.IsAlive())
|
||||
{
|
||||
@@ -5638,8 +5700,11 @@ namespace Game.Spells
|
||||
uint heal = (caster.SpellHealingBonusDone(caster, GetSpellInfo(), (uint)(new_damage * gainMultiplier), DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount()));
|
||||
heal = (caster.SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount()));
|
||||
|
||||
int gain = caster.HealBySpell(caster, GetSpellInfo(), heal);
|
||||
caster.getHostileRefManager().threatAssist(caster, gain * 0.5f, GetSpellInfo());
|
||||
HealInfo healInfo = new HealInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo().GetSchoolMask());
|
||||
caster.HealBySpell(healInfo);
|
||||
|
||||
caster.getHostileRefManager().threatAssist(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo());
|
||||
caster.ProcSkillsAndAuras(caster, ProcFlags.DonePeriodic, ProcFlags.TakenPeriodic, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.None, hitMask, null, null, healInfo);
|
||||
}
|
||||
|
||||
caster.SendSpellNonMeleeDamageLog(log);
|
||||
@@ -5670,7 +5735,9 @@ namespace Game.Spells
|
||||
|
||||
damage = (uint)(damage * gainMultiplier);
|
||||
|
||||
caster.HealBySpell(target, GetSpellInfo(), damage);
|
||||
HealInfo healInfo = new HealInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetSchoolMask());
|
||||
caster.HealBySpell(healInfo);
|
||||
caster.ProcSkillsAndAuras(target, ProcFlags.DonePeriodic, ProcFlags.TakenPeriodic, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.None, ProcFlagsHit.Normal, null, null, healInfo);
|
||||
}
|
||||
|
||||
void HandlePeriodicHealAurasTick(Unit target, Unit caster)
|
||||
@@ -5750,22 +5817,23 @@ namespace Game.Spells
|
||||
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 absorb = 0;
|
||||
uint heal = (uint)damage;
|
||||
caster.CalcHealAbsorb(target, GetSpellInfo(), ref heal, ref absorb);
|
||||
int gain = caster.DealHeal(target, heal);
|
||||
|
||||
SpellPeriodicAuraLogInfo pInfo = new SpellPeriodicAuraLogInfo(this, heal, (int)(heal - gain), absorb, 0, 0.0f, crit);
|
||||
HealInfo healInfo = new HealInfo(caster, target, heal, GetSpellInfo(), GetSpellInfo().GetSchoolMask());
|
||||
caster.CalcHealAbsorb(healInfo);
|
||||
caster.DealHeal(healInfo);
|
||||
|
||||
SpellPeriodicAuraLogInfo pInfo = new SpellPeriodicAuraLogInfo(this, heal, (int)(heal - healInfo.GetEffectiveHeal()), healInfo.GetAbsorb(), 0, 0.0f, crit);
|
||||
target.SendPeriodicAuraLog(pInfo);
|
||||
|
||||
target.getHostileRefManager().threatAssist(caster, gain * 0.5f, GetSpellInfo());
|
||||
target.getHostileRefManager().threatAssist(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo());
|
||||
|
||||
ProcFlags procAttacker = ProcFlags.DonePeriodic;
|
||||
ProcFlags procVictim = ProcFlags.TakenPeriodic;
|
||||
ProcFlagsExLegacy procEx = (crit ? ProcFlagsExLegacy.CriticalHit : ProcFlagsExLegacy.NormalHit) | ProcFlagsExLegacy.InternalHot;
|
||||
ProcFlagsHit hitMask = crit ? ProcFlagsHit.Critical : ProcFlagsHit.Normal;
|
||||
// ignore item heals
|
||||
if (GetBase().GetCastItemGUID().IsEmpty())
|
||||
caster.ProcDamageAndSpell(target, procAttacker, procVictim, procEx, (uint)damage, WeaponAttackType.BaseAttack, GetSpellInfo());
|
||||
caster.ProcSkillsAndAuras(target, procAttacker, procVictim, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.None, hitMask, null, null, healInfo);
|
||||
}
|
||||
|
||||
void HandlePeriodicManaLeechAuraTick(Unit target, Unit caster)
|
||||
@@ -5912,16 +5980,43 @@ namespace Game.Spells
|
||||
// Set trigger flag
|
||||
ProcFlags procAttacker = ProcFlags.DonePeriodic;
|
||||
ProcFlags procVictim = ProcFlags.TakenPeriodic;
|
||||
ProcFlagsExLegacy procEx = Unit.createProcExtendMask(damageInfo, SpellMissInfo.None) | ProcFlagsExLegacy.InternalDot;
|
||||
ProcFlagsHit hitMask = Unit.createProcHitMask(damageInfo, SpellMissInfo.None);
|
||||
ProcFlagsSpellType spellTypeMask = ProcFlagsSpellType.NoDmgHeal;
|
||||
if (damageInfo.damage != 0)
|
||||
{
|
||||
procVictim |= ProcFlags.TakenDamage;
|
||||
spellTypeMask |= ProcFlagsSpellType.Damage;
|
||||
}
|
||||
|
||||
caster.ProcDamageAndSpell(damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, WeaponAttackType.BaseAttack, spellProto);
|
||||
DamageInfo dotDamageInfo = new DamageInfo(damageInfo, DamageEffectType.DOT, WeaponAttackType.BaseAttack, hitMask);
|
||||
caster.ProcSkillsAndAuras(target, procAttacker, procVictim, spellTypeMask, ProcFlagsSpellPhase.None, hitMask, null, dotDamageInfo, null);
|
||||
|
||||
caster.DealSpellDamage(damageInfo, true);
|
||||
caster.SendSpellNonMeleeDamageLog(damageInfo);
|
||||
}
|
||||
|
||||
void HandleBreakableCCAuraProc(AuraApplication aurApp, ProcEventInfo eventInfo)
|
||||
{
|
||||
DamageInfo damageInfo = eventInfo.GetDamageInfo();
|
||||
if (damageInfo == null)
|
||||
return;
|
||||
|
||||
// aura own damage at apply won't break CC
|
||||
if (eventInfo.GetSpellPhaseMask().HasAnyFlag(ProcFlagsSpellPhase.Cast))
|
||||
{
|
||||
SpellInfo spellInfo = eventInfo.GetSpellInfo();
|
||||
if (spellInfo != null)
|
||||
if (spellInfo == GetSpellInfo())
|
||||
return;
|
||||
}
|
||||
|
||||
int damageLeft = GetAmount();
|
||||
if (damageLeft < damageInfo.GetDamage())
|
||||
aurApp.GetTarget().RemoveAura(aurApp);
|
||||
else
|
||||
ChangeAmount((int)(damageLeft - damageInfo.GetDamage()));
|
||||
}
|
||||
|
||||
void HandleProcTriggerSpellAuraProc(AuraApplication aurApp, ProcEventInfo eventInfo)
|
||||
{
|
||||
Unit triggerCaster = aurApp.GetTarget();
|
||||
@@ -5935,7 +6030,7 @@ namespace Game.Spells
|
||||
triggerCaster.CastSpell(triggerTarget, triggeredSpellInfo, true, null, this);
|
||||
}
|
||||
else
|
||||
Log.outDebug(LogFilter.Spells, "AuraEffect.HandleProcTriggerSpellAuraProc: Could not trigger spell {0} from aura {1} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
|
||||
Log.outError(LogFilter.Spells, "AuraEffect.HandleProcTriggerSpellAuraProc: Could not trigger spell {0} from aura {1} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
|
||||
}
|
||||
|
||||
void HandleProcTriggerSpellWithValueAuraProc(AuraApplication aurApp, ProcEventInfo eventInfo)
|
||||
@@ -5952,7 +6047,7 @@ namespace Game.Spells
|
||||
triggerCaster.CastCustomSpell(triggerTarget, triggerSpellId, basepoints0, 0, 0, true, null, this);
|
||||
}
|
||||
else
|
||||
Log.outDebug(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());
|
||||
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());
|
||||
}
|
||||
|
||||
public void HandleProcTriggerDamageAuraProc(AuraApplication aurApp, ProcEventInfo eventInfo)
|
||||
@@ -5968,128 +6063,6 @@ namespace Game.Spells
|
||||
target.SendSpellNonMeleeDamageLog(damageInfo);
|
||||
}
|
||||
|
||||
void HandleRaidProcFromChargeAuraProc(AuraApplication aurApp, ProcEventInfo eventInfo)
|
||||
{
|
||||
Unit target = aurApp.GetTarget();
|
||||
|
||||
uint triggerSpellId;
|
||||
switch (GetId())
|
||||
{
|
||||
case 57949: // Shiver
|
||||
triggerSpellId = 57952;
|
||||
//animationSpellId = 57951; dummy effects for jump spell have unknown use (see also 41637)
|
||||
break;
|
||||
case 59978: // Shiver
|
||||
triggerSpellId = 59979;
|
||||
break;
|
||||
case 43593: // Cold Stare
|
||||
triggerSpellId = 43594;
|
||||
break;
|
||||
default:
|
||||
Log.outDebug(LogFilter.Spells, "AuraEffect.HandleRaidProcFromChargeAuraProc: received not handled spell: {0}", GetId());
|
||||
return;
|
||||
}
|
||||
|
||||
int jumps = GetBase().GetCharges();
|
||||
|
||||
// current aura expire on proc finish
|
||||
GetBase().SetCharges(0);
|
||||
GetBase().SetUsingCharges(true);
|
||||
|
||||
// next target selection
|
||||
if (jumps > 0)
|
||||
{
|
||||
Unit caster = GetCaster();
|
||||
if (caster != null)
|
||||
{
|
||||
float radius = GetSpellEffectInfo().CalcRadius(caster);
|
||||
Unit triggerTarget = target.GetNextRandomRaidMemberOrPet(radius);
|
||||
if (triggerTarget != null)
|
||||
{
|
||||
target.CastSpell(triggerTarget, GetSpellInfo(), true, null, this, GetCasterGUID());
|
||||
Aura aura = triggerTarget.GetAura(GetId(), GetCasterGUID());
|
||||
if (aura != null)
|
||||
aura.SetCharges((byte)jumps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log.outDebug(LogFilter.Spells, "AuraEffect.HandleRaidProcFromChargeAuraProc: Triggering spell {0} from aura {1} proc", triggerSpellId, GetId());
|
||||
target.CastSpell(target, triggerSpellId, true, null, this, GetCasterGUID());
|
||||
}
|
||||
|
||||
void HandleRaidProcFromChargeWithValueAuraProc(AuraApplication aurApp, ProcEventInfo eventInfo)
|
||||
{
|
||||
Unit target = aurApp.GetTarget();
|
||||
|
||||
// Currently only Prayer of Mending
|
||||
if (!(GetSpellInfo().SpellFamilyName == SpellFamilyNames.Priest) && GetSpellInfo().SpellFamilyFlags[1].HasAnyFlag<uint>(0x20))
|
||||
{
|
||||
Log.outDebug(LogFilter.Spells, "AuraEffect.HandleRaidProcFromChargeWithValueAuraProc: received not handled spell: {0}", GetId());
|
||||
return;
|
||||
}
|
||||
uint triggerSpellId = 33110;
|
||||
|
||||
int value = GetAmount();
|
||||
|
||||
int jumps = GetBase().GetCharges();
|
||||
|
||||
// current aura expire on proc finish
|
||||
GetBase().SetCharges(0);
|
||||
GetBase().SetUsingCharges(true);
|
||||
|
||||
// next target selection
|
||||
if (jumps > 0)
|
||||
{
|
||||
Unit caster = GetCaster();
|
||||
if (caster != null)
|
||||
{
|
||||
float radius = GetSpellEffectInfo().CalcRadius(caster);
|
||||
Unit triggerTarget = target.GetNextRandomRaidMemberOrPet(radius);
|
||||
if (triggerTarget != null)
|
||||
{
|
||||
target.CastCustomSpell(triggerTarget, GetId(), value, 0, 0, true, null, this, GetCasterGUID());
|
||||
Aura aura = triggerTarget.GetAura(GetId(), GetCasterGUID());
|
||||
if (aura != null)
|
||||
aura.SetCharges((byte)jumps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log.outDebug(LogFilter.Spells, "AuraEffect.HandleRaidProcFromChargeWithValueAuraProc: Triggering spell {0} from aura {1} proc", triggerSpellId, GetId());
|
||||
target.CastCustomSpell(target, triggerSpellId, value, 0, 0, true, null, this, GetCasterGUID());
|
||||
}
|
||||
|
||||
public void HandleProcTriggerSpellOnPowerAmountAuraProc(AuraApplication aurApp, ProcEventInfo eventInfo)
|
||||
{
|
||||
// Power amount required to proc the spell
|
||||
int powerAmountRequired = GetAmount();
|
||||
// Power type required to proc
|
||||
PowerType powerRequired = (PowerType)GetSpellInfo().GetEffect(GetEffIndex()).MiscValue;
|
||||
|
||||
if (powerRequired == 0 || powerAmountRequired == 0)
|
||||
{
|
||||
Log.outError(LogFilter.Spells, "AuraEffect.HandleProcTriggerSpellOnPowerAmountAuraProc: Spell {0} have 0 PowerAmountRequired in EffectAmount[{1}] or 0 PowerRequired in EffectMiscValue", GetId(), GetEffIndex());
|
||||
return /*false*/;
|
||||
}
|
||||
|
||||
Unit triggerCaster = aurApp.GetTarget();
|
||||
Unit triggerTarget = eventInfo.GetProcTarget();
|
||||
|
||||
if (triggerCaster.GetPower(powerRequired) != powerAmountRequired)
|
||||
return /*false*/;
|
||||
|
||||
uint triggerSpellId = GetSpellInfo().GetEffect(GetEffIndex()).TriggerSpell;
|
||||
SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId);
|
||||
if (triggeredSpellInfo != null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Spells, "AuraEffect.HandleProcTriggerSpellOnPowerAmountAuraProc: Triggering spell {0} from aura {1} proc", triggeredSpellInfo.Id, GetId());
|
||||
triggerCaster.CastSpell(triggerTarget, triggeredSpellInfo, true, null, this);
|
||||
}
|
||||
else
|
||||
Log.outDebug(LogFilter.Spells, "AuraEffect.HandleProcTriggerSpellOnPowerAmountAuraProc: Could not trigger spell {0} from aura {1} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
|
||||
}
|
||||
|
||||
[AuraEffectHandler(AuraType.ForceWeather)]
|
||||
void HandleAuraForceWeather(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user