Core/Spells: SPELL_AURA_48 implementation

Port From (https://github.com/TrinityCore/TrinityCore/commit/37178ff311af95c4a2035a38839b5e8a9afe2af5)
This commit is contained in:
hondacrx
2022-01-06 00:17:58 -05:00
parent a4ace1e181
commit e89a36a232
6 changed files with 162 additions and 117 deletions
+114 -105
View File
@@ -1041,8 +1041,8 @@ namespace Game.Entities
return 0; return 0;
} }
public virtual bool HasSpellFocus(Spell focusSpell = null) { return false; } public virtual bool HasSpellFocus(Spell focusSpell = null) { return false; }
/// <summary> /// <summary>
/// Check if our current channel spell has attribute SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING /// Check if our current channel spell has attribute SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING
/// </summary> /// </summary>
@@ -1075,7 +1075,7 @@ namespace Game.Entities
return true; return true;
return false; return false;
} }
public bool HasBreakableByDamageAuraType(AuraType type, uint excludeAura = 0) public bool HasBreakableByDamageAuraType(AuraType type, uint excludeAura = 0)
{ {
var auras = GetAuraEffectsByType(type); var auras = GetAuraEffectsByType(type);
@@ -1428,7 +1428,7 @@ namespace Game.Entities
return false; 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) 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; WeaponAttackType attType = damageInfo != null ? damageInfo.GetAttackType() : WeaponAttackType.BaseAttack;
@@ -1627,51 +1627,51 @@ namespace Game.Entities
switch (CSpellType) switch (CSpellType)
{ {
case CurrentSpellTypes.Generic: 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 // break autorepeat if not Auto Shot
InterruptSpell(CurrentSpellTypes.Channeled, false); if (m_currentSpells[CurrentSpellTypes.AutoRepeat].m_spellInfo.Id != 75)
// 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)
InterruptSpell(CurrentSpellTypes.AutoRepeat); InterruptSpell(CurrentSpellTypes.AutoRepeat);
m_AutoRepeatFirstCast = true;
}
if (pSpell.m_spellInfo.CalcCastTime() > 0)
AddUnitState(UnitState.Casting); AddUnitState(UnitState.Casting);
break; break;
} }
case CurrentSpellTypes.AutoRepeat: case CurrentSpellTypes.Channeled:
{ {
// only Auto Shoot does not break anything // channel spells always break generic non-delayed and any channeled spells
if (pSpell.m_spellInfo.Id != 75) InterruptSpell(CurrentSpellTypes.Generic, false);
{ InterruptSpell(CurrentSpellTypes.Channeled);
// 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; // 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: default:
break; // other spell types don't break anything now break; // other spell types don't break anything now
} }
@@ -1948,74 +1948,74 @@ namespace Game.Entities
// Melee and Ranged Spells // Melee and Ranged Spells
case SpellDmgClass.Ranged: case SpellDmgClass.Ranged:
case SpellDmgClass.Melee: case SpellDmgClass.Melee:
{
// Physical Damage
if (damageSchoolMask.HasAnyFlag(SpellSchoolMask.Normal))
{ {
// Physical Damage // Spells with this attribute were already calculated in MeleeSpellHitResult
if (damageSchoolMask.HasAnyFlag(SpellSchoolMask.Normal)) if (!spellInfo.HasAttribute(SpellAttr3.BlockableSpell))
{ {
// Spells with this attribute were already calculated in MeleeSpellHitResult // Get blocked status
if (!spellInfo.HasAttribute(SpellAttr3.BlockableSpell)) 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 // Magical Attacks
case SpellDmgClass.None: case SpellDmgClass.None:
case SpellDmgClass.Magic: case SpellDmgClass.Magic:
{
// If crit add critical bonus
if (crit)
{ {
// If crit add critical bonus damageInfo.HitInfo |= HitInfo.CriticalHit;
if (crit) damage = (int)SpellCriticalDamageBonus(this, spellInfo, (uint)damage, victim);
{
damageInfo.HitInfo |= HitInfo.CriticalHit;
damage = (int)SpellCriticalDamageBonus(this, spellInfo, (uint)damage, victim);
}
if (CanApplyResilience())
ApplyResilience(victim, ref damage);
break;
} }
if (CanApplyResilience())
ApplyResilience(victim, ref damage);
break;
}
default: default:
break; break;
} }
@@ -2241,7 +2241,7 @@ namespace Game.Entities
} }
public virtual bool IsAffectedByDiminishingReturns() { return (GetCharmerOrOwnerPlayerOrPlayerItself() != null); } public virtual bool IsAffectedByDiminishingReturns() { return (GetCharmerOrOwnerPlayerOrPlayerItself() != null); }
public DiminishingLevels GetDiminishing(DiminishingGroup group) public DiminishingLevels GetDiminishing(DiminishingGroup group)
{ {
DiminishingReturn diminish = m_Diminishing[(int)group]; DiminishingReturn diminish = m_Diminishing[(int)group];
@@ -2568,7 +2568,7 @@ namespace Game.Entities
{ {
int[] bp = new int[SpellConst.MaxEffects]; int[] bp = new int[SpellConst.MaxEffects];
foreach (var spellEffectInfo in spellEntry.GetEffects()) foreach (var spellEffectInfo in spellEntry.GetEffects())
bp[spellEffectInfo.EffectIndex] = spellEffectInfo.BasePoints; bp[spellEffectInfo.EffectIndex] = spellEffectInfo.BasePoints;
bp[i] = seatId; bp[i] = seatId;
@@ -2611,7 +2611,7 @@ namespace Game.Entities
{ {
return GetAuraApplication(predicate) != null; return GetAuraApplication(predicate) != null;
} }
public bool HasAuraEffect(uint spellId, uint effIndex, ObjectGuid casterGUID = default) public bool HasAuraEffect(uint spellId, uint effIndex, ObjectGuid casterGUID = default)
{ {
var range = m_appliedAuras.LookupByKey(spellId); var range = m_appliedAuras.LookupByKey(spellId);
@@ -2678,6 +2678,15 @@ namespace Game.Entities
return false; 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) public bool HasNegativeAuraWithInterruptFlag(SpellAuraInterruptFlags flag, ObjectGuid guid = default)
{ {
if (!HasInterruptFlag(flag)) if (!HasInterruptFlag(flag))
+22 -5
View File
@@ -677,13 +677,30 @@ namespace Game
return; return;
} }
// do not cast not learned spells
if (!caster.HasSpell(spellInfo.Id) || spellInfo.IsPassive())
return;
SpellCastTargets targets = new(caster, petCastSpell.Cast); 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_fromClient = true;
spell.m_misc.Data0 = petCastSpell.Cast.Misc[0]; spell.m_misc.Data0 = petCastSpell.Cast.Misc[0];
spell.m_misc.Data1 = petCastSpell.Cast.Misc[1]; spell.m_misc.Data1 = petCastSpell.Cast.Misc[1];
+2 -5
View File
@@ -314,15 +314,12 @@ namespace Game
if (go.GetSpellForLock(caster.ToPlayer()) == spellInfo) if (go.GetSpellForLock(caster.ToPlayer()) == spellInfo)
allow = true; allow = true;
// TODO: Preparation for #23204
// allow casting of spells triggered by clientside periodic trigger auras // allow casting of spells triggered by clientside periodic trigger auras
/* if (caster.HasAuraTypeWithTriggerSpell(AuraType.PeriodicTriggerSpellFromClient, spellInfo.Id))
if (caster->HasAuraTypeWithTriggerSpell(SPELL_AURA_PERIODIC_TRIGGER_SPELL_FROM_CLIENT, spellId))
{ {
allow = true; allow = true;
triggerFlag = TRIGGERED_FULL_MASK; triggerFlag = TriggerCastFlags.FullMask;
} }
*/
if (!allow) if (!allow)
return; return;
+4
View File
@@ -188,6 +188,7 @@ namespace Game.Spells
case AuraType.PeriodicHeal: case AuraType.PeriodicHeal:
case AuraType.ObsModHealth: case AuraType.ObsModHealth:
case AuraType.PeriodicTriggerSpell: case AuraType.PeriodicTriggerSpell:
case AuraType.PeriodicTriggerSpellFromClient:
case AuraType.PeriodicEnergize: case AuraType.PeriodicEnergize:
case AuraType.PeriodicLeech: case AuraType.PeriodicLeech:
case AuraType.PeriodicHealthFunnel: case AuraType.PeriodicHealthFunnel:
@@ -520,6 +521,9 @@ namespace Game.Spells
case AuraType.PeriodicTriggerSpell: case AuraType.PeriodicTriggerSpell:
HandlePeriodicTriggerSpellAuraTick(target, caster); HandlePeriodicTriggerSpellAuraTick(target, caster);
break; break;
case AuraType.PeriodicTriggerSpellFromClient:
// Don't actually do anything - client will trigger casts of these spells by itself
break;
case AuraType.PeriodicTriggerSpellWithValue: case AuraType.PeriodicTriggerSpellWithValue:
HandlePeriodicTriggerSpellWithValueAuraTick(target, caster); HandlePeriodicTriggerSpellWithValueAuraTick(target, caster);
break; break;
+2 -1
View File
@@ -2705,7 +2705,7 @@ namespace Game.Spells
case AuraType.PeriodicHeal: case AuraType.PeriodicHeal:
case AuraType.ObsModHealth: case AuraType.ObsModHealth:
case AuraType.ObsModPower: case AuraType.ObsModPower:
case AuraType.Unk48: case AuraType.PeriodicTriggerSpellFromClient:
case AuraType.PowerBurn: case AuraType.PowerBurn:
case AuraType.PeriodicLeech: case AuraType.PeriodicLeech:
case AuraType.PeriodicManaLeech: case AuraType.PeriodicManaLeech:
@@ -3530,6 +3530,7 @@ namespace Game.Spells
case AuraType.AddTargetTrigger: case AuraType.AddTargetTrigger:
return true; return true;
case AuraType.PeriodicTriggerSpellWithValue: case AuraType.PeriodicTriggerSpellWithValue:
case AuraType.PeriodicTriggerSpellFromClient:
case AuraType.PeriodicTriggerSpell: case AuraType.PeriodicTriggerSpell:
if (!_isPositiveTarget(effect)) if (!_isPositiveTarget(effect))
{ {
+18 -1
View File
@@ -2935,6 +2935,7 @@ namespace Game.Entities
switch (spellEffectInfo.ApplyAuraName) switch (spellEffectInfo.ApplyAuraName)
{ {
case AuraType.PeriodicTriggerSpell: case AuraType.PeriodicTriggerSpell:
case AuraType.PeriodicTriggerSpellFromClient:
case AuraType.PeriodicTriggerSpellWithValue: case AuraType.PeriodicTriggerSpellWithValue:
SpellInfo triggerSpell = Global.SpellMgr.GetSpellInfo(spellEffectInfo.TriggerSpell, Difficulty.None); SpellInfo triggerSpell = Global.SpellMgr.GetSpellInfo(spellEffectInfo.TriggerSpell, Difficulty.None);
if (triggerSpell != null) if (triggerSpell != null)
@@ -3257,7 +3258,8 @@ namespace Game.Entities
43109, // Throw Torch 43109, // Throw Torch
58552, // Return to Orgrimmar 58552, // Return to Orgrimmar
58533, // Return to Stormwind 58533, // Return to Stormwind
21855 // Challenge Flag 21855, // Challenge Flag
51122 // Fierce Lightning Stike
}, spellInfo => }, spellInfo =>
{ {
spellInfo.MaxAffectedTargets = 1; spellInfo.MaxAffectedTargets = 1;
@@ -3578,6 +3580,14 @@ namespace Game.Entities
spellInfo.RangeEntry = CliDB.SpellRangeStorage.LookupByKey(13); // 50000yd 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 // Summon Corpse Scarabs
ApplySpellFix(new[] { 28864, 29105 }, spellInfo => 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) // Empowered Flare (Blood Prince Council)
ApplySpellFix(new[] { 71708 }, spellInfo => ApplySpellFix(new[] { 71708 }, spellInfo =>
{ {