Implementation of QAston proc system
This commit is contained in:
@@ -4289,10 +4289,24 @@ namespace Game.Entities
|
||||
if (proto.GetFlags().HasAnyFlag(ItemFlags.NoEquipCooldown))
|
||||
return;
|
||||
|
||||
DateTime now = DateTime.Now;
|
||||
for (byte i = 0; i < proto.Effects.Count; ++i)
|
||||
{
|
||||
var effectData = proto.Effects[i];
|
||||
|
||||
// apply proc cooldown to equip auras if we have any
|
||||
if (effectData.Trigger == ItemSpelltriggerType.OnEquip)
|
||||
{
|
||||
SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(effectData.SpellID);
|
||||
if (procEntry == null)
|
||||
continue;
|
||||
|
||||
Aura itemAura = GetAura(effectData.SpellID, GetGUID(), pItem.GetGUID());
|
||||
if (itemAura != null)
|
||||
itemAura.AddProcCooldown(now + TimeSpan.FromMilliseconds(procEntry.Cooldown));
|
||||
continue;
|
||||
}
|
||||
|
||||
// no spell
|
||||
if (effectData.SpellID == 0)
|
||||
continue;
|
||||
|
||||
@@ -1797,19 +1797,18 @@ namespace Game.Entities
|
||||
return;
|
||||
|
||||
List<Aura> aurasQueue = new List<Aura>();
|
||||
|
||||
for (var i = 0; i < (int)SpellModOp.Max; ++i)
|
||||
{
|
||||
for (var j = 0; j < (int)SpellModType.End; ++j)
|
||||
{
|
||||
foreach (var mod in m_spellMods[i][j])
|
||||
{
|
||||
// spellmods without aura set cannot be charged
|
||||
if (mod.ownerAura == null || !mod.ownerAura.IsUsingCharges())
|
||||
// Spellmods without charged aura set cannot be charged
|
||||
if (!mod.ownerAura.IsUsingCharges())
|
||||
continue;
|
||||
|
||||
// Restore only specific owner aura mods
|
||||
if (ownerAuraId != 0 && (ownerAuraId != mod.ownerAura.GetSpellInfo().Id))
|
||||
if (ownerAuraId != 0 && mod.spellId != ownerAuraId)
|
||||
continue;
|
||||
|
||||
if (aura != null && mod.ownerAura != aura)
|
||||
@@ -1831,70 +1830,37 @@ namespace Game.Entities
|
||||
// only see the first of its modifier restored)
|
||||
aurasQueue.Add(mod.ownerAura);
|
||||
|
||||
// add mod charges back to mod
|
||||
if (mod.charges == -1)
|
||||
mod.charges = 1;
|
||||
else
|
||||
mod.charges++;
|
||||
|
||||
// Do not set more spellmods than avalible
|
||||
if (mod.ownerAura.GetCharges() < mod.charges)
|
||||
mod.charges = mod.ownerAura.GetCharges();
|
||||
|
||||
// Skip this check for now - aura charges may change due to various reason
|
||||
/// @todo track these changes correctly
|
||||
//ASSERT (mod->ownerAura->GetCharges() <= mod->charges);
|
||||
// add charges back to aura
|
||||
mod.ownerAura.ModCharges(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var removeAura in aurasQueue)
|
||||
spell.m_appliedMods.Remove(aura);
|
||||
}
|
||||
|
||||
public void RestoreAllSpellMods(uint ownerAuraId = 0, Aura aura = null)
|
||||
{
|
||||
for (CurrentSpellTypes i = 0; i < CurrentSpellTypes.Max; ++i)
|
||||
{
|
||||
var appliedMod = spell.m_appliedMods.Find(p => p == removeAura);
|
||||
if (appliedMod != null)
|
||||
spell.m_appliedMods.Remove(appliedMod);
|
||||
Spell spell = m_currentSpells[i];
|
||||
if (spell != null)
|
||||
RestoreSpellMods(spell, ownerAuraId, aura);
|
||||
}
|
||||
}
|
||||
|
||||
public void RestoreAllSpellMods(uint ownerAuraId, Aura aura)
|
||||
{
|
||||
for (CurrentSpellTypes i = 0; i < CurrentSpellTypes.Max; ++i)
|
||||
if (GetCurrentSpell(i) != null)
|
||||
RestoreSpellMods(m_currentSpells[i], ownerAuraId, aura);
|
||||
}
|
||||
|
||||
public void RemoveSpellMods(Spell spell)
|
||||
public void ApplyModToSpell(SpellModifier mod, Spell spell)
|
||||
{
|
||||
if (spell == null)
|
||||
return;
|
||||
|
||||
if (spell.m_appliedMods.Empty())
|
||||
// don't do anything with no charges
|
||||
if (mod.ownerAura.IsUsingCharges() && mod.ownerAura.GetCharges() == 0)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < (int)SpellModOp.Max; ++i)
|
||||
{
|
||||
for (var j = 0; j < (int)SpellModType.End; ++j)
|
||||
{
|
||||
for (var c = 0; c < m_spellMods[i][j].Count; c++)
|
||||
{
|
||||
SpellModifier mod = m_spellMods[i][j][c];
|
||||
// spellmods without aura set cannot be charged
|
||||
if (mod.ownerAura == null || !mod.ownerAura.IsUsingCharges())
|
||||
continue;
|
||||
|
||||
// check if mod affected this spell
|
||||
var iterMod = spell.m_appliedMods.Find(p => p == mod.ownerAura);
|
||||
if (iterMod == null)
|
||||
continue;
|
||||
|
||||
// remove from list
|
||||
spell.m_appliedMods.Remove(iterMod);
|
||||
|
||||
if (mod.ownerAura.DropCharge(AuraRemoveMode.Expire))
|
||||
c = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// register inside spell, proc system uses this to drop charges
|
||||
spell.m_appliedMods.Add(mod.ownerAura);
|
||||
}
|
||||
|
||||
public void LearnCustomSpells()
|
||||
@@ -2643,25 +2609,71 @@ namespace Game.Entities
|
||||
if (m_spellModTakingSpell != null)
|
||||
spell = m_spellModTakingSpell;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
// special case, if a mod makes spell instant, only consume that mod
|
||||
case SpellModOp.CastingTime:
|
||||
{
|
||||
SpellModifier modInstantSpell = null;
|
||||
foreach (SpellModifier mod in m_spellMods[(int)op][(int)SpellModType.Pct])
|
||||
{
|
||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
||||
continue;
|
||||
|
||||
if (Convert.ToInt64(basevalue) < 10000 && mod.value <= -100)
|
||||
{
|
||||
modInstantSpell = mod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (modInstantSpell != null)
|
||||
{
|
||||
ApplyModToSpell(modInstantSpell, spell);
|
||||
basevalue = default(T);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// special case if two mods apply 100% critical chance, only consume one
|
||||
case SpellModOp.CriticalChance:
|
||||
{
|
||||
SpellModifier modCritical = null;
|
||||
foreach (SpellModifier mod in m_spellMods[(int)op][(int)SpellModType.Flat])
|
||||
{
|
||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
||||
continue;
|
||||
|
||||
if (mod.value >= 100)
|
||||
{
|
||||
modCritical = mod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (modCritical != null)
|
||||
{
|
||||
ApplyModToSpell(modCritical, spell);
|
||||
basevalue = (T)Convert.ChangeType(100, typeof(T));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var mod in m_spellMods[(int)op][(int)SpellModType.Flat])
|
||||
{
|
||||
// Charges can be set only for mods with auras
|
||||
if (mod.ownerAura == null)
|
||||
Contract.Assert(mod.charges == 0);
|
||||
|
||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
||||
continue;
|
||||
|
||||
totalflat += mod.value;
|
||||
DropModCharge(mod, spell);
|
||||
ApplyModToSpell(mod, spell);
|
||||
}
|
||||
|
||||
foreach (var mod in m_spellMods[(int)op][(int)SpellModType.Pct])
|
||||
{
|
||||
// Charges can be set only for mods with auras
|
||||
if (mod.ownerAura == null)
|
||||
Contract.Assert(mod.charges == 0);
|
||||
|
||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
||||
continue;
|
||||
|
||||
@@ -2670,22 +2682,26 @@ namespace Game.Entities
|
||||
continue;
|
||||
|
||||
// special case (skip > 10sec spell casts for instant cast setting)
|
||||
if (mod.op == SpellModOp.CastingTime && Convert.ToInt64(basevalue) >= 10000 && mod.value <= -100)
|
||||
continue;
|
||||
if (op == SpellModOp.CastingTime)
|
||||
{
|
||||
if (Convert.ToInt32(basevalue) >= 10000 && mod.value <= -100)
|
||||
continue;
|
||||
}
|
||||
|
||||
totalmul *= 1.0f + MathFunctions.CalculatePct(1.0f, mod.value);
|
||||
DropModCharge(mod, spell);
|
||||
ApplyModToSpell(mod, spell);
|
||||
}
|
||||
|
||||
basevalue = (T)Convert.ChangeType(((Convert.ToSingle(basevalue) + totalflat) * totalmul), typeof(T));
|
||||
}
|
||||
|
||||
bool IsAffectedBySpellmod(SpellInfo spellInfo, SpellModifier mod, Spell spell)
|
||||
{
|
||||
if (mod == null || spellInfo == null)
|
||||
return false;
|
||||
|
||||
// Mod out of charges
|
||||
if (spell != null && mod.charges == -1 && !spell.m_appliedMods.Contains(mod.ownerAura))
|
||||
// First time this aura applies a mod to us and is out of charges
|
||||
if (spell && mod.ownerAura.IsUsingCharges() && mod.ownerAura.GetCharges() == 0 && !spell.m_appliedMods.Contains(mod.ownerAura))
|
||||
return false;
|
||||
|
||||
// +duration to infinite duration spells making them limited
|
||||
@@ -2694,21 +2710,6 @@ namespace Game.Entities
|
||||
|
||||
return spellInfo.IsAffectedBySpellMod(mod);
|
||||
}
|
||||
void DropModCharge(SpellModifier mod, Spell spell)
|
||||
{
|
||||
// don't handle spells with proc_event entry defined
|
||||
// this is a temporary workaround, because all spellmods should be handled like that
|
||||
if (Global.SpellMgr.GetSpellProcEvent(mod.spellId) != null)
|
||||
return;
|
||||
|
||||
if (spell != null && mod.ownerAura != null && mod.charges > 0)
|
||||
{
|
||||
if (--mod.charges == 0)
|
||||
mod.charges = -1;
|
||||
|
||||
spell.m_appliedMods.Add(mod.ownerAura);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSpellModTakingSpell(Spell spell, bool apply)
|
||||
{
|
||||
@@ -2992,10 +2993,62 @@ namespace Game.Entities
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CastItemCombatSpell(Unit target, WeaponAttackType attType, ProcFlags procVictim, ProcFlagsExLegacy procEx, Item item, ItemTemplate proto)
|
||||
public void CastItemCombatSpell(DamageInfo damageInfo)
|
||||
{
|
||||
Unit target = damageInfo.GetVictim();
|
||||
if (target == null || !target.IsAlive() || target == this)
|
||||
return;
|
||||
|
||||
for (byte i = EquipmentSlot.Start; i < EquipmentSlot.End; ++i)
|
||||
{
|
||||
// If usable, try to cast item spell
|
||||
Item item = GetItemByPos(InventorySlots.Bag0, i);
|
||||
if (item != null)
|
||||
{
|
||||
if (!item.IsBroken() && CanUseAttackType(damageInfo.GetAttackType()))
|
||||
{
|
||||
ItemTemplate proto = item.GetTemplate();
|
||||
if (proto != null)
|
||||
{
|
||||
// Additional check for weapons
|
||||
if (proto.GetClass() == ItemClass.Weapon)
|
||||
{
|
||||
// offhand item cannot proc from main hand hit etc
|
||||
byte slot;
|
||||
switch (damageInfo.GetAttackType())
|
||||
{
|
||||
case WeaponAttackType.BaseAttack:
|
||||
case WeaponAttackType.RangedAttack:
|
||||
slot = EquipmentSlot.MainHand;
|
||||
break;
|
||||
case WeaponAttackType.OffAttack:
|
||||
slot = EquipmentSlot.OffHand;
|
||||
break;
|
||||
default:
|
||||
slot = EquipmentSlot.End;
|
||||
break;
|
||||
}
|
||||
if (slot != i)
|
||||
continue;
|
||||
// Check if item is useable (forms or disarm)
|
||||
if (damageInfo.GetAttackType() == WeaponAttackType.BaseAttack)
|
||||
if (!IsUseEquipedWeapon(true) && !IsInFeralForm())
|
||||
continue;
|
||||
}
|
||||
|
||||
CastItemCombatSpell(damageInfo, item, proto);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CastItemCombatSpell(DamageInfo damageInfo, Item item, ItemTemplate proto)
|
||||
{
|
||||
// Can do effect if any damage done to target
|
||||
if (procVictim.HasAnyFlag(ProcFlags.TakenDamage))
|
||||
// for done procs allow normal + critical + absorbs by default
|
||||
bool canTrigger = damageInfo.GetHitMask().HasAnyFlag(ProcFlagsHit.Normal | ProcFlagsHit.Critical | ProcFlagsHit.Absorb);
|
||||
if (canTrigger)
|
||||
{
|
||||
for (byte i = 0; i < proto.Effects.Count; ++i)
|
||||
{
|
||||
@@ -3024,14 +3077,14 @@ namespace Game.Entities
|
||||
|
||||
if (proto.SpellPPMRate != 0)
|
||||
{
|
||||
uint WeaponSpeed = GetBaseAttackTime(attType);
|
||||
uint WeaponSpeed = GetBaseAttackTime(damageInfo.GetAttackType());
|
||||
chance = GetPPMProcChance(WeaponSpeed, proto.SpellPPMRate, spellInfo);
|
||||
}
|
||||
else if (chance > 100.0f)
|
||||
chance = GetWeaponProcChance();
|
||||
|
||||
if (RandomHelper.randChance(chance))
|
||||
CastSpell(target, spellInfo.Id, true, item);
|
||||
CastSpell(damageInfo.GetVictim(), spellInfo.Id, true, item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3053,13 +3106,13 @@ namespace Game.Entities
|
||||
if (entry != null && entry.procEx != 0)
|
||||
{
|
||||
// Check hit/crit/dodge/parry requirement
|
||||
if ((entry.procEx & procEx) == 0)
|
||||
if (((uint)entry.procEx & (uint)damageInfo.GetHitMask()) == 0)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can do effect if any damage done to target
|
||||
if (!Convert.ToBoolean(procVictim & ProcFlags.TakenDamage))
|
||||
// for done procs allow normal + critical + absorbs by default
|
||||
if (!canTrigger)
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3093,58 +3146,12 @@ namespace Game.Entities
|
||||
if (spellInfo.IsPositive())
|
||||
CastSpell(this, spellInfo, true, item);
|
||||
else
|
||||
CastSpell(target, spellInfo, true, item);
|
||||
CastSpell(damageInfo.GetVictim(), spellInfo, true, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CastItemCombatSpell(Unit target, WeaponAttackType attType, ProcFlags procVictim, ProcFlagsExLegacy procEx)
|
||||
{
|
||||
if (target == null || !target.IsAlive() || target == this)
|
||||
return;
|
||||
|
||||
for (byte i = EquipmentSlot.Start; i < EquipmentSlot.End; ++i)
|
||||
{
|
||||
// If usable, try to cast item spell
|
||||
Item item = GetItemByPos(InventorySlots.Bag0, i);
|
||||
if (item != null)
|
||||
if (!item.IsBroken() && CanUseAttackType(attType))
|
||||
{
|
||||
ItemTemplate proto = item.GetTemplate();
|
||||
if (proto != null)
|
||||
{
|
||||
// Additional check for weapons
|
||||
if (proto.GetClass() == ItemClass.Weapon)
|
||||
{
|
||||
// offhand item cannot proc from main hand hit etc
|
||||
byte slot;
|
||||
switch (attType)
|
||||
{
|
||||
case WeaponAttackType.BaseAttack:
|
||||
case WeaponAttackType.RangedAttack:
|
||||
slot = EquipmentSlot.MainHand;
|
||||
break;
|
||||
case WeaponAttackType.OffAttack:
|
||||
slot = EquipmentSlot.OffHand;
|
||||
break;
|
||||
default:
|
||||
slot = EquipmentSlot.End;
|
||||
break;
|
||||
}
|
||||
if (slot != i)
|
||||
continue;
|
||||
// Check if item is useable (forms or disarm)
|
||||
if (attType == WeaponAttackType.BaseAttack)
|
||||
if (!IsUseEquipedWeapon(true) && !IsInFeralForm())
|
||||
continue;
|
||||
}
|
||||
CastItemCombatSpell(target, attType, procVictim, procEx, item, proto);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float GetWeaponProcChance()
|
||||
{
|
||||
// normalized proc chance for weapon attack speed
|
||||
|
||||
@@ -595,7 +595,8 @@ namespace Game.Entities
|
||||
DealDamageMods(victim, ref damageInfo.damage, ref damageInfo.absorb);
|
||||
SendAttackStateUpdate(damageInfo);
|
||||
|
||||
ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType);
|
||||
DamageInfo dmgInfo = new DamageInfo(damageInfo);
|
||||
ProcSkillsAndAuras(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, ProcFlagsSpellType.None, ProcFlagsSpellPhase.None, dmgInfo.GetHitMask(), null, dmgInfo, null);
|
||||
|
||||
DealMeleeDamage(damageInfo, true);
|
||||
|
||||
@@ -646,7 +647,6 @@ namespace Game.Entities
|
||||
|
||||
damageInfo.procAttacker = ProcFlags.None;
|
||||
damageInfo.procVictim = ProcFlags.None;
|
||||
damageInfo.procEx = ProcFlagsExLegacy.None;
|
||||
damageInfo.hitOutCome = MeleeHitOutcome.Normal;
|
||||
|
||||
SendAttackStateUpdate(damageInfo);
|
||||
@@ -808,7 +808,10 @@ namespace Game.Entities
|
||||
}
|
||||
|
||||
if (IsTypeId(TypeId.Player))
|
||||
ToPlayer().CastItemCombatSpell(victim, damageInfo.attackType, damageInfo.procVictim, damageInfo.procEx);
|
||||
{
|
||||
DamageInfo dmgInfo = new DamageInfo(damageInfo);
|
||||
ToPlayer().CastItemCombatSpell(dmgInfo);
|
||||
}
|
||||
|
||||
// Do effect if any damage done to target
|
||||
if (damageInfo.damage != 0)
|
||||
@@ -1431,16 +1434,17 @@ namespace Game.Entities
|
||||
// Do KILL and KILLED procs. KILL proc is called only for the unit who landed the killing blow (and its owner - for pets and totems) regardless of who tapped the victim
|
||||
if (IsPet() || IsTotem())
|
||||
{
|
||||
// proc only once for victim
|
||||
Unit owner = GetOwner();
|
||||
if (owner != null)
|
||||
owner.ProcDamageAndSpell(victim, ProcFlags.Kill, ProcFlags.None, ProcFlagsExLegacy.None, 0);
|
||||
owner.ProcSkillsAndAuras(victim, ProcFlags.Kill, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
|
||||
}
|
||||
|
||||
if (!victim.IsCritter())
|
||||
ProcDamageAndSpell(victim, ProcFlags.Kill, ProcFlags.Killed, ProcFlagsExLegacy.None, 0);
|
||||
ProcSkillsAndAuras(victim, ProcFlags.Kill, ProcFlags.Killed, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
|
||||
|
||||
// Proc auras on death - must be before aura/combat remove
|
||||
victim.ProcDamageAndSpell(null, ProcFlags.Death, ProcFlags.None, ProcFlagsExLegacy.None, 0, WeaponAttackType.BaseAttack, null);
|
||||
victim.ProcSkillsAndAuras(victim, ProcFlags.None, ProcFlags.Death, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
|
||||
|
||||
// update get killing blow achievements, must be done before setDeathState to be able to require auras on target
|
||||
// and before Spirit of Redemption as it also removes auras
|
||||
@@ -1808,7 +1812,6 @@ namespace Game.Entities
|
||||
damageInfo.HitInfo = 0;
|
||||
damageInfo.procAttacker = ProcFlags.None;
|
||||
damageInfo.procVictim = ProcFlags.None;
|
||||
damageInfo.procEx = ProcFlagsExLegacy.None;
|
||||
damageInfo.hitOutCome = MeleeHitOutcome.Evade;
|
||||
|
||||
if (victim == null)
|
||||
@@ -1839,7 +1842,6 @@ namespace Game.Entities
|
||||
damageInfo.HitInfo |= HitInfo.NormalSwing;
|
||||
damageInfo.TargetState = VictimState.Immune;
|
||||
|
||||
damageInfo.procEx |= ProcFlagsExLegacy.Immune;
|
||||
damageInfo.damage = 0;
|
||||
damageInfo.cleanDamage = 0;
|
||||
return;
|
||||
@@ -1869,25 +1871,22 @@ namespace Game.Entities
|
||||
case MeleeHitOutcome.Evade:
|
||||
damageInfo.HitInfo |= HitInfo.Miss | HitInfo.SwingNoHitSound;
|
||||
damageInfo.TargetState = VictimState.Evades;
|
||||
damageInfo.procEx |= ProcFlagsExLegacy.Evade;
|
||||
|
||||
damageInfo.damage = 0;
|
||||
damageInfo.cleanDamage = 0;
|
||||
return;
|
||||
case MeleeHitOutcome.Miss:
|
||||
damageInfo.HitInfo |= HitInfo.Miss;
|
||||
damageInfo.TargetState = VictimState.Intact;
|
||||
damageInfo.procEx |= ProcFlagsExLegacy.Miss;
|
||||
damageInfo.damage = 0;
|
||||
damageInfo.cleanDamage = 0;
|
||||
break;
|
||||
case MeleeHitOutcome.Normal:
|
||||
damageInfo.TargetState = VictimState.Hit;
|
||||
damageInfo.procEx |= ProcFlagsExLegacy.NormalHit;
|
||||
break;
|
||||
case MeleeHitOutcome.Crit:
|
||||
damageInfo.HitInfo |= HitInfo.CriticalHit;
|
||||
damageInfo.TargetState = VictimState.Hit;
|
||||
damageInfo.procEx |= ProcFlagsExLegacy.CriticalHit;
|
||||
// Crit bonus calc
|
||||
damageInfo.damage += damageInfo.damage;
|
||||
float mod = 0.0f;
|
||||
@@ -1905,19 +1904,16 @@ namespace Game.Entities
|
||||
break;
|
||||
case MeleeHitOutcome.Parry:
|
||||
damageInfo.TargetState = VictimState.Parry;
|
||||
damageInfo.procEx |= ProcFlagsExLegacy.Parry;
|
||||
damageInfo.cleanDamage += damageInfo.damage;
|
||||
damageInfo.damage = 0;
|
||||
break;
|
||||
case MeleeHitOutcome.Dodge:
|
||||
damageInfo.TargetState = VictimState.Dodge;
|
||||
damageInfo.procEx |= ProcFlagsExLegacy.Dodge;
|
||||
damageInfo.cleanDamage += damageInfo.damage;
|
||||
damageInfo.damage = 0;
|
||||
break;
|
||||
case MeleeHitOutcome.Block:
|
||||
damageInfo.TargetState = VictimState.Hit;
|
||||
damageInfo.procEx |= ProcFlagsExLegacy.Block | ProcFlagsExLegacy.NormalHit;
|
||||
// 30% damage blocked, double blocked amount if block is critical
|
||||
damageInfo.blocked_amount = MathFunctions.CalculatePct(damageInfo.damage, damageInfo.target.isBlockCritical() ? damageInfo.target.GetBlockPercent() * 2 : damageInfo.target.GetBlockPercent());
|
||||
damageInfo.damage -= damageInfo.blocked_amount;
|
||||
@@ -1926,7 +1922,6 @@ namespace Game.Entities
|
||||
case MeleeHitOutcome.Glancing:
|
||||
damageInfo.HitInfo |= HitInfo.Glancing;
|
||||
damageInfo.TargetState = VictimState.Hit;
|
||||
damageInfo.procEx |= ProcFlagsExLegacy.NormalHit;
|
||||
int leveldif = (int)victim.getLevel() - (int)getLevel();
|
||||
if (leveldif > 3)
|
||||
leveldif = 3;
|
||||
@@ -1938,7 +1933,6 @@ namespace Game.Entities
|
||||
case MeleeHitOutcome.Crushing:
|
||||
damageInfo.HitInfo |= HitInfo.Crushing;
|
||||
damageInfo.TargetState = VictimState.Hit;
|
||||
damageInfo.procEx |= ProcFlagsExLegacy.NormalHit;
|
||||
// 150% normal damage
|
||||
damageInfo.damage += (damageInfo.damage / 2);
|
||||
break;
|
||||
@@ -1965,10 +1959,7 @@ namespace Game.Entities
|
||||
CalcAbsorbResist(damageInfo.target, (SpellSchoolMask)damageInfo.damageSchoolMask, DamageEffectType.Direct, damageInfo.damage, ref damageInfo.absorb, ref damageInfo.resist);
|
||||
|
||||
if (damageInfo.absorb != 0)
|
||||
{
|
||||
damageInfo.HitInfo |= (damageInfo.damage - damageInfo.absorb == 0 ? HitInfo.FullAbsorb : HitInfo.PartialAbsorb);
|
||||
damageInfo.procEx |= ProcFlagsExLegacy.Absorb;
|
||||
}
|
||||
|
||||
if (damageInfo.resist != 0)
|
||||
damageInfo.HitInfo |= (damageInfo.damage - damageInfo.resist == 0 ? HitInfo.FullResist : HitInfo.PartialResist);
|
||||
@@ -2437,7 +2428,7 @@ namespace Game.Entities
|
||||
if (eff.GetAmount() >= 0)
|
||||
{
|
||||
// Reduce shield amount
|
||||
eff.SetAmount(eff.GetAmount() - currentAbsorb);
|
||||
eff.ChangeAmount(eff.GetAmount() - currentAbsorb);
|
||||
// Aura cannot absorb anything more - remove it
|
||||
if (eff.GetAmount() <= 0)
|
||||
eff.GetBase().Remove(AuraRemoveMode.EnemySpell);
|
||||
@@ -2498,7 +2489,7 @@ namespace Game.Entities
|
||||
// Check if our aura is using amount to count damage
|
||||
if (absorbAurEff.GetAmount() >= 0)
|
||||
{
|
||||
absorbAurEff.SetAmount(absorbAurEff.GetAmount() - currentAbsorb);
|
||||
absorbAurEff.ChangeAmount(absorbAurEff.GetAmount() - currentAbsorb);
|
||||
if ((absorbAurEff.GetAmount() <= 0))
|
||||
absorbAurEff.GetBase().Remove(AuraRemoveMode.EnemySpell);
|
||||
}
|
||||
@@ -2558,7 +2549,8 @@ namespace Game.Entities
|
||||
SendSpellNonMeleeDamageLog(log);
|
||||
|
||||
// break 'Fear' and similar auras
|
||||
caster.ProcDamageAndSpellFor(true, this, ProcFlags.TakenSpellMagicDmgClassNeg, ProcFlagsExLegacy.NormalHit, WeaponAttackType.BaseAttack, eff.GetSpellInfo(), splitDamage);
|
||||
DamageInfo damageInfo = new DamageInfo(caster, this, splitDamage, eff.GetSpellInfo(), schoolMask, DamageEffectType.Direct, WeaponAttackType.BaseAttack);
|
||||
ProcSkillsAndAuras(caster, ProcFlags.None, ProcFlags.TakenSpellMagicDmgClassNeg, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.Hit, ProcFlagsHit.None, null, damageInfo, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2566,24 +2558,22 @@ namespace Game.Entities
|
||||
absorb = dmgInfo.GetAbsorb();
|
||||
}
|
||||
|
||||
public void CalcHealAbsorb(Unit victim, SpellInfo healSpell, ref uint healAmount, ref uint absorb)
|
||||
public void CalcHealAbsorb(HealInfo healInfo)
|
||||
{
|
||||
if (healAmount == 0)
|
||||
if (healInfo.GetHeal() == 0)
|
||||
return;
|
||||
|
||||
int RemainingHeal = (int)healAmount;
|
||||
|
||||
// Need remove expired auras after
|
||||
bool existExpired = false;
|
||||
|
||||
// absorb without mana cost
|
||||
var vHealAbsorb = victim.GetAuraEffectsByType(AuraType.SchoolHealAbsorb);
|
||||
var vHealAbsorb = healInfo.GetTarget().GetAuraEffectsByType(AuraType.SchoolHealAbsorb);
|
||||
foreach (var eff in vHealAbsorb)
|
||||
{
|
||||
if (RemainingHeal <= 0)
|
||||
if (healInfo.GetHeal() <= 0)
|
||||
break;
|
||||
|
||||
if (!Convert.ToBoolean(eff.GetMiscValue() & (int)healSpell.SchoolMask))
|
||||
if (!Convert.ToBoolean(eff.GetMiscValue() & (int)healInfo.GetSpellInfo().SchoolMask))
|
||||
continue;
|
||||
|
||||
// Max Amount can be absorbed by this aura
|
||||
@@ -2598,13 +2588,12 @@ namespace Game.Entities
|
||||
|
||||
// currentAbsorb - damage can be absorbed by shield
|
||||
// If need absorb less damage
|
||||
if (RemainingHeal < currentAbsorb)
|
||||
currentAbsorb = RemainingHeal;
|
||||
currentAbsorb = (int)Math.Min(healInfo.GetHeal(), currentAbsorb);
|
||||
|
||||
RemainingHeal -= currentAbsorb;
|
||||
healInfo.AbsorbHeal((uint)currentAbsorb);
|
||||
|
||||
// Reduce shield amount
|
||||
eff.SetAmount(eff.GetAmount() - currentAbsorb);
|
||||
eff.ChangeAmount(eff.GetAmount() - currentAbsorb);
|
||||
// Need remove it later
|
||||
if (eff.GetAmount() <= 0)
|
||||
existExpired = true;
|
||||
@@ -2619,16 +2608,13 @@ namespace Game.Entities
|
||||
++i;
|
||||
if (auraEff.GetAmount() <= 0)
|
||||
{
|
||||
uint removedAuras = victim.m_removedAurasCount;
|
||||
uint removedAuras = healInfo.GetTarget().m_removedAurasCount;
|
||||
auraEff.GetBase().Remove(AuraRemoveMode.EnemySpell);
|
||||
if (removedAuras + 1 < victim.m_removedAurasCount)
|
||||
if (removedAuras + 1 < healInfo.GetTarget().m_removedAurasCount)
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
absorb = (uint)(RemainingHeal > 0 ? (healAmount - RemainingHeal) : healAmount);
|
||||
healAmount = (uint)RemainingHeal;
|
||||
}
|
||||
|
||||
public uint CalcArmorReducedDamage(Unit attacker, Unit victim, uint damage, SpellInfo spellInfo, WeaponAttackType attackType = WeaponAttackType.Max)
|
||||
|
||||
@@ -154,23 +154,10 @@ namespace Game.Entities
|
||||
public DiminishingLevels hitCount;
|
||||
}
|
||||
|
||||
public class ProcTriggeredData
|
||||
{
|
||||
public ProcTriggeredData(Aura _aura)
|
||||
{
|
||||
aura = _aura;
|
||||
effMask = 0;
|
||||
spellProcEvent = null;
|
||||
}
|
||||
public SpellProcEventEntry spellProcEvent;
|
||||
public Aura aura;
|
||||
public uint effMask;
|
||||
}
|
||||
|
||||
public class ProcEventInfo
|
||||
{
|
||||
public ProcEventInfo(Unit actor, Unit actionTarget, Unit procTarget, uint typeMask, uint spellTypeMask,
|
||||
uint spellPhaseMask, uint hitMask, Spell spell, DamageInfo damageInfo, HealInfo healInfo)
|
||||
public ProcEventInfo(Unit actor, Unit actionTarget, Unit procTarget, ProcFlags typeMask, ProcFlagsSpellType spellTypeMask,
|
||||
ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell spell, DamageInfo damageInfo, HealInfo healInfo)
|
||||
{
|
||||
_actor = actor;
|
||||
_actionTarget = actionTarget;
|
||||
@@ -188,10 +175,10 @@ namespace Game.Entities
|
||||
public Unit GetActionTarget() { return _actionTarget; }
|
||||
public Unit GetProcTarget() { return _procTarget; }
|
||||
|
||||
public ProcFlags GetTypeMask() { return (ProcFlags)_typeMask; }
|
||||
public ProcFlagsSpellType GetSpellTypeMask() { return (ProcFlagsSpellType)_spellTypeMask; }
|
||||
public ProcFlagsSpellPhase GetSpellPhaseMask() { return (ProcFlagsSpellPhase)_spellPhaseMask; }
|
||||
public ProcFlagsHit GetHitMask() { return (ProcFlagsHit)_hitMask; }
|
||||
public ProcFlags GetTypeMask() { return _typeMask; }
|
||||
public ProcFlagsSpellType GetSpellTypeMask() { return _spellTypeMask; }
|
||||
public ProcFlagsSpellPhase GetSpellPhaseMask() { return _spellPhaseMask; }
|
||||
public ProcFlagsHit GetHitMask() { return _hitMask; }
|
||||
|
||||
public SpellInfo GetSpellInfo()
|
||||
{
|
||||
@@ -221,13 +208,15 @@ namespace Game.Entities
|
||||
public DamageInfo GetDamageInfo() { return _damageInfo; }
|
||||
public HealInfo GetHealInfo() { return _healInfo; }
|
||||
|
||||
public Spell GetProcSpell() { return _spell; }
|
||||
|
||||
Unit _actor;
|
||||
Unit _actionTarget;
|
||||
Unit _procTarget;
|
||||
uint _typeMask;
|
||||
uint _spellTypeMask;
|
||||
uint _spellPhaseMask;
|
||||
uint _hitMask;
|
||||
ProcFlags _typeMask;
|
||||
ProcFlagsSpellType _spellTypeMask;
|
||||
ProcFlagsSpellPhase _spellPhaseMask;
|
||||
ProcFlagsHit _hitMask;
|
||||
Spell _spell;
|
||||
DamageInfo _damageInfo;
|
||||
HealInfo _healInfo;
|
||||
@@ -245,6 +234,7 @@ namespace Game.Entities
|
||||
m_damageType = damageType;
|
||||
m_attackType = attackType;
|
||||
}
|
||||
|
||||
public DamageInfo(CalcDamageInfo dmgInfo)
|
||||
{
|
||||
m_attacker = dmgInfo.attacker;
|
||||
@@ -291,11 +281,20 @@ namespace Game.Entities
|
||||
case MeleeHitOutcome.Evade:
|
||||
m_hitMask |= ProcFlagsHit.Evade;
|
||||
break;
|
||||
case MeleeHitOutcome.Crushing:
|
||||
case MeleeHitOutcome.Glancing:
|
||||
case MeleeHitOutcome.Normal:
|
||||
m_hitMask |= ProcFlagsHit.Normal;
|
||||
break;
|
||||
case MeleeHitOutcome.Crit:
|
||||
m_hitMask |= ProcFlagsHit.Critical;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
public DamageInfo(SpellNonMeleeDamage spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType)
|
||||
|
||||
public DamageInfo(SpellNonMeleeDamage spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, ProcFlagsHit hitMask)
|
||||
{
|
||||
m_attacker = spellNonMeleeDamage.attacker;
|
||||
m_victim = spellNonMeleeDamage.target;
|
||||
@@ -307,6 +306,7 @@ namespace Game.Entities
|
||||
m_absorb = spellNonMeleeDamage.absorb;
|
||||
m_resist = spellNonMeleeDamage.resist;
|
||||
m_block = spellNonMeleeDamage.blocked;
|
||||
m_hitMask = hitMask;
|
||||
|
||||
if (spellNonMeleeDamage.blocked != 0)
|
||||
m_hitMask |= ProcFlagsHit.Block;
|
||||
@@ -354,7 +354,7 @@ namespace Game.Entities
|
||||
public uint GetAbsorb() { return m_absorb; }
|
||||
public uint GetResist() { return m_resist; }
|
||||
uint GetBlock() { return m_block; }
|
||||
ProcFlagsHit GetHitMask() { return m_hitMask; }
|
||||
public ProcFlagsHit GetHitMask() { return m_hitMask; }
|
||||
|
||||
Unit m_attacker;
|
||||
Unit m_victim;
|
||||
@@ -380,7 +380,7 @@ namespace Game.Entities
|
||||
_schoolMask = schoolMask;
|
||||
}
|
||||
|
||||
void AbsorbHeal(uint amount)
|
||||
public void AbsorbHeal(uint amount)
|
||||
{
|
||||
amount = Math.Min(amount, GetHeal());
|
||||
_absorb += amount;
|
||||
@@ -425,7 +425,6 @@ namespace Game.Entities
|
||||
public WeaponAttackType attackType { get; set; }
|
||||
public ProcFlags procAttacker { get; set; }
|
||||
public ProcFlags procVictim { get; set; }
|
||||
public ProcFlagsExLegacy procEx { get; set; }
|
||||
public uint cleanDamage { get; set; } // Used only for rage calculation
|
||||
public MeleeHitOutcome hitOutCome { get; set; } // TODO: remove this field (need use TargetState)
|
||||
}
|
||||
|
||||
+142
-799
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user