Core/Spells: SPELL_AURA_48 implementation
Port From (https://github.com/TrinityCore/TrinityCore/commit/37178ff311af95c4a2035a38839b5e8a9afe2af5)
This commit is contained in:
@@ -1041,8 +1041,8 @@ namespace Game.Entities
|
||||
return 0;
|
||||
}
|
||||
|
||||
public virtual bool HasSpellFocus(Spell focusSpell = null) { return false; }
|
||||
|
||||
public virtual bool HasSpellFocus(Spell focusSpell = null) { return false; }
|
||||
|
||||
/// <summary>
|
||||
/// Check if our current channel spell has attribute SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING
|
||||
/// </summary>
|
||||
@@ -1075,7 +1075,7 @@ namespace Game.Entities
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public bool HasBreakableByDamageAuraType(AuraType type, uint excludeAura = 0)
|
||||
{
|
||||
var auras = GetAuraEffectsByType(type);
|
||||
@@ -1428,7 +1428,7 @@ namespace Game.Entities
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static void ProcSkillsAndAuras(Unit actor, Unit actionTarget, ProcFlags typeMaskActor, ProcFlags typeMaskActionTarget, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell spell, DamageInfo damageInfo, HealInfo healInfo)
|
||||
{
|
||||
WeaponAttackType attType = damageInfo != null ? damageInfo.GetAttackType() : WeaponAttackType.BaseAttack;
|
||||
@@ -1627,51 +1627,51 @@ namespace Game.Entities
|
||||
switch (CSpellType)
|
||||
{
|
||||
case CurrentSpellTypes.Generic:
|
||||
{
|
||||
// generic spells always break channeled not delayed spells
|
||||
InterruptSpell(CurrentSpellTypes.Channeled, false);
|
||||
|
||||
// autorepeat breaking
|
||||
if (GetCurrentSpell(CurrentSpellTypes.AutoRepeat) != null)
|
||||
{
|
||||
// generic spells always break channeled not delayed spells
|
||||
InterruptSpell(CurrentSpellTypes.Channeled, false);
|
||||
|
||||
// autorepeat breaking
|
||||
if (GetCurrentSpell(CurrentSpellTypes.AutoRepeat) != null)
|
||||
{
|
||||
// break autorepeat if not Auto Shot
|
||||
if (m_currentSpells[CurrentSpellTypes.AutoRepeat].m_spellInfo.Id != 75)
|
||||
InterruptSpell(CurrentSpellTypes.AutoRepeat);
|
||||
m_AutoRepeatFirstCast = true;
|
||||
}
|
||||
if (pSpell.m_spellInfo.CalcCastTime() > 0)
|
||||
AddUnitState(UnitState.Casting);
|
||||
|
||||
break;
|
||||
}
|
||||
case CurrentSpellTypes.Channeled:
|
||||
{
|
||||
// channel spells always break generic non-delayed and any channeled spells
|
||||
InterruptSpell(CurrentSpellTypes.Generic, false);
|
||||
InterruptSpell(CurrentSpellTypes.Channeled);
|
||||
|
||||
// it also does break autorepeat if not Auto Shot
|
||||
if (GetCurrentSpell(CurrentSpellTypes.AutoRepeat) != null &&
|
||||
m_currentSpells[CurrentSpellTypes.AutoRepeat].m_spellInfo.Id != 75)
|
||||
// break autorepeat if not Auto Shot
|
||||
if (m_currentSpells[CurrentSpellTypes.AutoRepeat].m_spellInfo.Id != 75)
|
||||
InterruptSpell(CurrentSpellTypes.AutoRepeat);
|
||||
m_AutoRepeatFirstCast = true;
|
||||
}
|
||||
if (pSpell.m_spellInfo.CalcCastTime() > 0)
|
||||
AddUnitState(UnitState.Casting);
|
||||
|
||||
break;
|
||||
}
|
||||
case CurrentSpellTypes.AutoRepeat:
|
||||
{
|
||||
// only Auto Shoot does not break anything
|
||||
if (pSpell.m_spellInfo.Id != 75)
|
||||
{
|
||||
// generic autorepeats break generic non-delayed and channeled non-delayed spells
|
||||
InterruptSpell(CurrentSpellTypes.Generic, false);
|
||||
InterruptSpell(CurrentSpellTypes.Channeled, false);
|
||||
}
|
||||
// special action: set first cast flag
|
||||
m_AutoRepeatFirstCast = true;
|
||||
break;
|
||||
}
|
||||
case CurrentSpellTypes.Channeled:
|
||||
{
|
||||
// channel spells always break generic non-delayed and any channeled spells
|
||||
InterruptSpell(CurrentSpellTypes.Generic, false);
|
||||
InterruptSpell(CurrentSpellTypes.Channeled);
|
||||
|
||||
break;
|
||||
// it also does break autorepeat if not Auto Shot
|
||||
if (GetCurrentSpell(CurrentSpellTypes.AutoRepeat) != null &&
|
||||
m_currentSpells[CurrentSpellTypes.AutoRepeat].m_spellInfo.Id != 75)
|
||||
InterruptSpell(CurrentSpellTypes.AutoRepeat);
|
||||
AddUnitState(UnitState.Casting);
|
||||
|
||||
break;
|
||||
}
|
||||
case CurrentSpellTypes.AutoRepeat:
|
||||
{
|
||||
// only Auto Shoot does not break anything
|
||||
if (pSpell.m_spellInfo.Id != 75)
|
||||
{
|
||||
// generic autorepeats break generic non-delayed and channeled non-delayed spells
|
||||
InterruptSpell(CurrentSpellTypes.Generic, false);
|
||||
InterruptSpell(CurrentSpellTypes.Channeled, false);
|
||||
}
|
||||
// special action: set first cast flag
|
||||
m_AutoRepeatFirstCast = true;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break; // other spell types don't break anything now
|
||||
}
|
||||
@@ -1948,74 +1948,74 @@ namespace Game.Entities
|
||||
// Melee and Ranged Spells
|
||||
case SpellDmgClass.Ranged:
|
||||
case SpellDmgClass.Melee:
|
||||
{
|
||||
// Physical Damage
|
||||
if (damageSchoolMask.HasAnyFlag(SpellSchoolMask.Normal))
|
||||
{
|
||||
// Physical Damage
|
||||
if (damageSchoolMask.HasAnyFlag(SpellSchoolMask.Normal))
|
||||
// Spells with this attribute were already calculated in MeleeSpellHitResult
|
||||
if (!spellInfo.HasAttribute(SpellAttr3.BlockableSpell))
|
||||
{
|
||||
// Spells with this attribute were already calculated in MeleeSpellHitResult
|
||||
if (!spellInfo.HasAttribute(SpellAttr3.BlockableSpell))
|
||||
{
|
||||
// Get blocked status
|
||||
blocked = IsSpellBlocked(victim, spellInfo, attackType);
|
||||
}
|
||||
// Get blocked status
|
||||
blocked = IsSpellBlocked(victim, spellInfo, attackType);
|
||||
}
|
||||
|
||||
if (crit)
|
||||
{
|
||||
damageInfo.HitInfo |= HitInfo.CriticalHit;
|
||||
|
||||
// Calculate crit bonus
|
||||
uint crit_bonus = (uint)damage;
|
||||
// Apply crit_damage bonus for melee spells
|
||||
Player modOwner = GetSpellModOwner();
|
||||
if (modOwner != null)
|
||||
modOwner.ApplySpellMod(spellInfo, SpellModOp.CritDamageAndHealing, ref crit_bonus);
|
||||
damage += (int)crit_bonus;
|
||||
|
||||
// Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
|
||||
float critPctDamageMod = (GetTotalAuraMultiplierByMiscMask(AuraType.ModCritDamageBonus, (uint)spellInfo.GetSchoolMask()) - 1.0f) * 100;
|
||||
|
||||
if (critPctDamageMod != 0)
|
||||
MathFunctions.AddPct(ref damage, (int)critPctDamageMod);
|
||||
}
|
||||
|
||||
// Spell weapon based damage CAN BE crit & blocked at same time
|
||||
if (blocked)
|
||||
{
|
||||
// double blocked amount if block is critical
|
||||
float value = victim.GetBlockPercent(GetLevel());
|
||||
if (victim.IsBlockCritical())
|
||||
value *= 2; // double blocked percent
|
||||
damageInfo.blocked = (uint)MathFunctions.CalculatePct(damage, value);
|
||||
if (damage <= damageInfo.blocked)
|
||||
{
|
||||
damageInfo.blocked = (uint)damage;
|
||||
damageInfo.fullBlock = true;
|
||||
}
|
||||
damage -= (int)damageInfo.blocked;
|
||||
}
|
||||
|
||||
if (CanApplyResilience())
|
||||
ApplyResilience(victim, ref damage);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (crit)
|
||||
{
|
||||
damageInfo.HitInfo |= HitInfo.CriticalHit;
|
||||
|
||||
// Calculate crit bonus
|
||||
uint crit_bonus = (uint)damage;
|
||||
// Apply crit_damage bonus for melee spells
|
||||
Player modOwner = GetSpellModOwner();
|
||||
if (modOwner != null)
|
||||
modOwner.ApplySpellMod(spellInfo, SpellModOp.CritDamageAndHealing, ref crit_bonus);
|
||||
damage += (int)crit_bonus;
|
||||
|
||||
// Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
|
||||
float critPctDamageMod = (GetTotalAuraMultiplierByMiscMask(AuraType.ModCritDamageBonus, (uint)spellInfo.GetSchoolMask()) - 1.0f) * 100;
|
||||
|
||||
if (critPctDamageMod != 0)
|
||||
MathFunctions.AddPct(ref damage, (int)critPctDamageMod);
|
||||
}
|
||||
|
||||
// Spell weapon based damage CAN BE crit & blocked at same time
|
||||
if (blocked)
|
||||
{
|
||||
// double blocked amount if block is critical
|
||||
float value = victim.GetBlockPercent(GetLevel());
|
||||
if (victim.IsBlockCritical())
|
||||
value *= 2; // double blocked percent
|
||||
damageInfo.blocked = (uint)MathFunctions.CalculatePct(damage, value);
|
||||
if (damage <= damageInfo.blocked)
|
||||
{
|
||||
damageInfo.blocked = (uint)damage;
|
||||
damageInfo.fullBlock = true;
|
||||
}
|
||||
damage -= (int)damageInfo.blocked;
|
||||
}
|
||||
|
||||
if (CanApplyResilience())
|
||||
ApplyResilience(victim, ref damage);
|
||||
|
||||
break;
|
||||
}
|
||||
// Magical Attacks
|
||||
case SpellDmgClass.None:
|
||||
case SpellDmgClass.Magic:
|
||||
{
|
||||
// If crit add critical bonus
|
||||
if (crit)
|
||||
{
|
||||
// If crit add critical bonus
|
||||
if (crit)
|
||||
{
|
||||
damageInfo.HitInfo |= HitInfo.CriticalHit;
|
||||
damage = (int)SpellCriticalDamageBonus(this, spellInfo, (uint)damage, victim);
|
||||
}
|
||||
|
||||
if (CanApplyResilience())
|
||||
ApplyResilience(victim, ref damage);
|
||||
|
||||
break;
|
||||
damageInfo.HitInfo |= HitInfo.CriticalHit;
|
||||
damage = (int)SpellCriticalDamageBonus(this, spellInfo, (uint)damage, victim);
|
||||
}
|
||||
|
||||
if (CanApplyResilience())
|
||||
ApplyResilience(victim, ref damage);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2241,7 +2241,7 @@ namespace Game.Entities
|
||||
}
|
||||
|
||||
public virtual bool IsAffectedByDiminishingReturns() { return (GetCharmerOrOwnerPlayerOrPlayerItself() != null); }
|
||||
|
||||
|
||||
public DiminishingLevels GetDiminishing(DiminishingGroup group)
|
||||
{
|
||||
DiminishingReturn diminish = m_Diminishing[(int)group];
|
||||
@@ -2568,7 +2568,7 @@ namespace Game.Entities
|
||||
{
|
||||
int[] bp = new int[SpellConst.MaxEffects];
|
||||
foreach (var spellEffectInfo in spellEntry.GetEffects())
|
||||
bp[spellEffectInfo.EffectIndex] = spellEffectInfo.BasePoints;
|
||||
bp[spellEffectInfo.EffectIndex] = spellEffectInfo.BasePoints;
|
||||
|
||||
bp[i] = seatId;
|
||||
|
||||
@@ -2611,7 +2611,7 @@ namespace Game.Entities
|
||||
{
|
||||
return GetAuraApplication(predicate) != null;
|
||||
}
|
||||
|
||||
|
||||
public bool HasAuraEffect(uint spellId, uint effIndex, ObjectGuid casterGUID = default)
|
||||
{
|
||||
var range = m_appliedAuras.LookupByKey(spellId);
|
||||
@@ -2678,6 +2678,15 @@ namespace Game.Entities
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool HasAuraTypeWithTriggerSpell(AuraType auratype, uint triggerSpell)
|
||||
{
|
||||
foreach (var aura in GetAuraEffectsByType(auratype))
|
||||
if (aura.GetSpellEffectInfo().TriggerSpell == triggerSpell)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool HasNegativeAuraWithInterruptFlag(SpellAuraInterruptFlags flag, ObjectGuid guid = default)
|
||||
{
|
||||
if (!HasInterruptFlag(flag))
|
||||
|
||||
@@ -677,13 +677,30 @@ namespace Game
|
||||
return;
|
||||
}
|
||||
|
||||
// do not cast not learned spells
|
||||
if (!caster.HasSpell(spellInfo.Id) || spellInfo.IsPassive())
|
||||
return;
|
||||
|
||||
SpellCastTargets targets = new(caster, petCastSpell.Cast);
|
||||
|
||||
Spell spell = new(caster, spellInfo, TriggerCastFlags.None);
|
||||
TriggerCastFlags triggerCastFlags = TriggerCastFlags.None;
|
||||
|
||||
if (spellInfo.IsPassive())
|
||||
return;
|
||||
|
||||
// cast only learned spells
|
||||
if (!caster.HasSpell(spellInfo.Id))
|
||||
{
|
||||
bool allow = false;
|
||||
|
||||
// allow casting of spells triggered by clientside periodic trigger auras
|
||||
if (caster.HasAuraTypeWithTriggerSpell(AuraType.PeriodicTriggerSpellFromClient, spellInfo.Id))
|
||||
{
|
||||
allow = true;
|
||||
triggerCastFlags = TriggerCastFlags.FullMask;
|
||||
}
|
||||
|
||||
if (!allow)
|
||||
return;
|
||||
}
|
||||
|
||||
Spell spell = new(caster, spellInfo, triggerCastFlags);
|
||||
spell.m_fromClient = true;
|
||||
spell.m_misc.Data0 = petCastSpell.Cast.Misc[0];
|
||||
spell.m_misc.Data1 = petCastSpell.Cast.Misc[1];
|
||||
|
||||
@@ -314,15 +314,12 @@ namespace Game
|
||||
if (go.GetSpellForLock(caster.ToPlayer()) == spellInfo)
|
||||
allow = true;
|
||||
|
||||
// TODO: Preparation for #23204
|
||||
// allow casting of spells triggered by clientside periodic trigger auras
|
||||
/*
|
||||
if (caster->HasAuraTypeWithTriggerSpell(SPELL_AURA_PERIODIC_TRIGGER_SPELL_FROM_CLIENT, spellId))
|
||||
if (caster.HasAuraTypeWithTriggerSpell(AuraType.PeriodicTriggerSpellFromClient, spellInfo.Id))
|
||||
{
|
||||
allow = true;
|
||||
triggerFlag = TRIGGERED_FULL_MASK;
|
||||
triggerFlag = TriggerCastFlags.FullMask;
|
||||
}
|
||||
*/
|
||||
|
||||
if (!allow)
|
||||
return;
|
||||
|
||||
@@ -188,6 +188,7 @@ namespace Game.Spells
|
||||
case AuraType.PeriodicHeal:
|
||||
case AuraType.ObsModHealth:
|
||||
case AuraType.PeriodicTriggerSpell:
|
||||
case AuraType.PeriodicTriggerSpellFromClient:
|
||||
case AuraType.PeriodicEnergize:
|
||||
case AuraType.PeriodicLeech:
|
||||
case AuraType.PeriodicHealthFunnel:
|
||||
@@ -520,6 +521,9 @@ namespace Game.Spells
|
||||
case AuraType.PeriodicTriggerSpell:
|
||||
HandlePeriodicTriggerSpellAuraTick(target, caster);
|
||||
break;
|
||||
case AuraType.PeriodicTriggerSpellFromClient:
|
||||
// Don't actually do anything - client will trigger casts of these spells by itself
|
||||
break;
|
||||
case AuraType.PeriodicTriggerSpellWithValue:
|
||||
HandlePeriodicTriggerSpellWithValueAuraTick(target, caster);
|
||||
break;
|
||||
|
||||
@@ -2705,7 +2705,7 @@ namespace Game.Spells
|
||||
case AuraType.PeriodicHeal:
|
||||
case AuraType.ObsModHealth:
|
||||
case AuraType.ObsModPower:
|
||||
case AuraType.Unk48:
|
||||
case AuraType.PeriodicTriggerSpellFromClient:
|
||||
case AuraType.PowerBurn:
|
||||
case AuraType.PeriodicLeech:
|
||||
case AuraType.PeriodicManaLeech:
|
||||
@@ -3530,6 +3530,7 @@ namespace Game.Spells
|
||||
case AuraType.AddTargetTrigger:
|
||||
return true;
|
||||
case AuraType.PeriodicTriggerSpellWithValue:
|
||||
case AuraType.PeriodicTriggerSpellFromClient:
|
||||
case AuraType.PeriodicTriggerSpell:
|
||||
if (!_isPositiveTarget(effect))
|
||||
{
|
||||
|
||||
@@ -2935,6 +2935,7 @@ namespace Game.Entities
|
||||
switch (spellEffectInfo.ApplyAuraName)
|
||||
{
|
||||
case AuraType.PeriodicTriggerSpell:
|
||||
case AuraType.PeriodicTriggerSpellFromClient:
|
||||
case AuraType.PeriodicTriggerSpellWithValue:
|
||||
SpellInfo triggerSpell = Global.SpellMgr.GetSpellInfo(spellEffectInfo.TriggerSpell, Difficulty.None);
|
||||
if (triggerSpell != null)
|
||||
@@ -3257,7 +3258,8 @@ namespace Game.Entities
|
||||
43109, // Throw Torch
|
||||
58552, // Return to Orgrimmar
|
||||
58533, // Return to Stormwind
|
||||
21855 // Challenge Flag
|
||||
21855, // Challenge Flag
|
||||
51122 // Fierce Lightning Stike
|
||||
}, spellInfo =>
|
||||
{
|
||||
spellInfo.MaxAffectedTargets = 1;
|
||||
@@ -3578,6 +3580,14 @@ namespace Game.Entities
|
||||
spellInfo.RangeEntry = CliDB.SpellRangeStorage.LookupByKey(13); // 50000yd
|
||||
});
|
||||
|
||||
ApplySpellFix(new[] {
|
||||
44327, // Trained Rock Falcon/Hawk Hunting
|
||||
44408 // Trained Rock Falcon/Hawk Hunting
|
||||
}, spellInfo =>
|
||||
{
|
||||
spellInfo.Speed = 0.0f;
|
||||
});
|
||||
|
||||
// Summon Corpse Scarabs
|
||||
ApplySpellFix(new[] { 28864, 29105 }, spellInfo =>
|
||||
{
|
||||
@@ -3917,6 +3927,13 @@ namespace Game.Entities
|
||||
});
|
||||
});
|
||||
|
||||
// Mutated Transformation (Professor Putricide)
|
||||
ApplySpellFix(new[] { 70402 }, spellInfo =>
|
||||
{
|
||||
// Resistance is calculated inside of SpellScript
|
||||
spellInfo.AttributesEx4 |= SpellAttr4.IgnoreResistances;
|
||||
});
|
||||
|
||||
// Empowered Flare (Blood Prince Council)
|
||||
ApplySpellFix(new[] { 71708 }, spellInfo =>
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user