Core/Spells: Named and implemented most of SpellAttr7

Port From (https://github.com/TrinityCore/TrinityCore/commit/4e87bd7942d932225436940f62e26d48719a42dd)
This commit is contained in:
hondacrx
2024-02-01 15:39:38 -05:00
parent abb4092cff
commit bb2df1c0f9
11 changed files with 151 additions and 136 deletions
+34 -34
View File
@@ -1892,38 +1892,38 @@ namespace Framework.Constants
}
public enum SpellAttr7 : uint
{
Unk0 = 0x01, // 0 Shaman'S New Spells (Call Of The ...), Feign Death.
IgnoreDurationMods = 0x02, // 1 Duration is not affected by duration modifiers
DisableAuraWhileDead = 0x04, // 2 Disable Aura While Dead
IsCheatSpell = 0x08, // 3 Cannot Cast If Caster Doesn'T Have Unitflag2 & UnitFlag2AllowCheatSpells
Unk4 = 0x10, // 4 Only 47883 (Soulstone Resurrection) And Test Spell.
SummonTotem = 0x20, // 5 Only Shaman Player Totems.
NoPushbackOnDamage = 0x40, // 6 Does not cause spell pushback on damage
Unk7 = 0x80, // 7 66218 (Launch) Spell.
HordeOnly = 0x100, // 8 Teleports, Mounts And Other Spells.
AllianceOnly = 0x200, // 9 Teleports, Mounts And Other Spells.
DispelCharges = 0x400, // 10 Dispel And Spellsteal Individual Charges Instead Of Whole Aura.
InterruptOnlyNonplayer = 0x800, // 11 Only Non-Player Casts Interrupt, Though Feral Charge - Bear Has It.
SilenceOnlyNonplayer = 0x1000, // 12 Not Set In 3.2.2a.
CanAlwaysBeInterrupted = 0x2000, // 13 Can always be interrupted, even if caster is immune
Unk14 = 0x4000, // 14 Only 52150 (Raise Dead - Pet) Spell.
Unk15 = 0x8000, // 15 Exorcism. Usable On Players? 100% Crit Chance On Undead And Demons?
HiddenInSpellbookWhenLearned = 0x10000, // 16 After learning these spells become hidden in spellbook (but are visible when not learned for low level characters)
Unk17 = 0x20000, // 17 Only 27965 (Suicide) Spell.
HasChargeEffect = 0x40000, // 18 Only Spells That Have Charge Among Effects.
ZoneTeleport = 0x80000, // 19 Teleports To Specific Zones.
Unk20 = 0x100000, // 20 Blink, Divine Shield, Ice Block
Unk21 = 0x200000, // 21 Not Set
Unk22 = 0x400000, // 22
NoAttackDodge = 0x800000, // 23 No Attack Dodge
NoAttackParry = 0x1000000, // 24 No Attack Parry
AllowSpellReflection = 0x01, // Allow Spell Reflection
NoTargetDurationMod = 0x02, // No Target Duration Mod
DisableAuraWhileDead = 0x04, // Disable Aura While Dead
DebugSpell = 0x08, // Debug Spell Description Cannot Cast If Caster Doesn'T Have Unitflag2 & UnitFlag2AllowCheatSpells
TreatAsRaidBuff = 0x10, /*Nyi*/ // Treat As Raid Buff
CanBeMultiCast = 0x20, // Can Be Multi Cast
DontCauseSpellPushback = 0x40, // Don'T Cause Spell Pushback Description Damage Dealt By This Does Not Cause Spell Pushback
PrepareForVehicleControlEnd = 0x80, /*Nyi*/ // Prepare For Vehicle Control End
HordeSpecificSpell = 0x100, /*Nyi*/ // Horde Specific Spell
AllianceSpecificSpell = 0x200, /*Nyi*/ // Alliance Specific Spell
DispelRemovesCharges = 0x400, // Dispel Removes Charges Description Dispel/Spellsteal Remove Individual Charges
CanCauseInterrupt = 0x800, // Can Cause Interrupt Description Only Interrupt Non-Player Casting
CanCauseSilence = 0x1000, /*Nyi*/ // Can Cause Silence
NoUiNotInterruptible = 0x2000, // No Ui Not Interruptible Description Can Always Be Interrupted, Even If Caster Is Immune
RecastOnResummon = 0x4000, /*Nyi - Deprecated Attribute, There Is No SpellGo Sent Anymore On Pet Resummon*/ // Recast On Resummon
ResetSwingTimerAtSpellStart = 0x8000, // Reset Swing Timer At Spell Start
OnlyInSpellbookUntilLearned = 0x10000, // Only In Spellbook Until Learned Description After Learning These Spells Become Hidden In Spellbook (But Are Visible When Not Learned For Low Level Characters)
DoNotLogPvpKill = 0x20000, /*Nyi, Only Used By 1 Spell That Is Already Filtered Out In Pvp Credits Because Its Self Targeting*/ // Do Not Log Pvp Kill
AttackOnChargeToUnit = 0x40000, // Attack On Charge To Unit
ReportSpellFailureToUnitTarget = 0x80000, // Report Spell Failure To Unit Target
NoClientFailWhileStunnedFleeingConfused = 0x100000, // No Client Fail While Stunned, Fleeing, Confused Description Clientside - Skips Stunned/Fleeing/Confused Checks
RetainCooldownThroughLoad = 0x200000, /*Nyi*/ // Retain Cooldown Through Load
IgnoresColdWeatherFlyingRequirement = 0x400000, /*Nyi - Deprecated Attribute*/ // Ignores Cold Weather Flying Requirement
NoAttackDodge = 0x800000, // No Attack Dodge
NoAttackParry = 0x1000000, // No Attack Parry
NoAttackMiss = 0x2000000, // No Attack Miss
Unk26 = 0x4000000, // 26
BypassNoResurrectAura = 0x8000000, // 27 Bypass No Resurrect Aura
ConsolidatedRaidBuff = 0x10000000, // 28 Related To Player Positive Buff
Unk29 = 0x20000000, // 29 Only 69028, 71237
Unk30 = 0x40000000, // 30 Burning Determination, Divine Sacrifice, Earth Shield, Prayer Of Mending
ClientIndicator = 0x80000000 // 31 Only 70769
TreatAsNpcAoe = 0x4000000, // Treat As Npc Aoe
BypassNoResurrectAura = 0x8000000, // Bypass No Resurrect Aura
DoNotCountForPvpScoreboard = 0x10000000, // Do Not Count For Pvp Scoreboard
ReflectionOnlyDefends = 0x20000000, // Reflection Only Defends
CanProcFromSuppressedTargetProcs = 0x40000000, // Can Proc From Suppressed Target Procs
AlwaysCastLog = 0x80000000 // Always Cast Log
}
public enum SpellAttr8 : uint
{
@@ -2067,8 +2067,8 @@ namespace Framework.Constants
}
public enum SpellAttr12 : uint
{
Unk0 = 0x01, // 0
Unk1 = 0x02, // 1
EnableProcsFromSuppressedCasterProcs = 0x01, // 0
CanProcFromSuppressedCasterProcs = 0x02, // 1
Unk2 = 0x04, // 2
Unk3 = 0x08, // 3
Unk4 = 0x10, // 4
@@ -2595,7 +2595,7 @@ namespace Framework.Constants
RangedMask = DealRangedAttack | TakeRangedAttack | DealRangedAbility | TakeRangedAbility,
SpellMask = DealMeleeAbility | TakeMeleeAbility | DealRangedAttack | TakeRangedAttack
SpellMask = DealMeleeAbility | TakeMeleeAbility | DealRangedAttack | TakeRangedAttack
| DealRangedAbility | TakeRangedAbility | DealHelpfulAbility | TakeHelpfulAbility
| DealHarmfulAbility | TakeHarmfulAbility | DealHelpfulSpell | TakeHelpfulSpell
| DealHarmfulSpell | TakeHarmfulSpell | DealHarmfulPeriodic | TakeHarmfulPeriodic | DealHelpfulPeriodic | TakeHelpfulPeriodic,
+2 -2
View File
@@ -1917,7 +1917,7 @@ namespace Game.Entities
return duration;
// some auras are not affected by duration modifiers
if (spellInfo.HasAttribute(SpellAttr7.IgnoreDurationMods))
if (spellInfo.HasAttribute(SpellAttr7.NoTargetDurationMod))
return duration;
// cut duration only of negative effects
@@ -2163,7 +2163,7 @@ namespace Game.Entities
reflectchance += victim.GetTotalAuraModifierByMiscMask(AuraType.ReflectSpellsSchool, (int)spellInfo.GetSchoolMask());
if (reflectchance > 0 && RandomHelper.randChance(reflectchance))
return SpellMissInfo.Reflect;
return spellInfo.HasAttribute(SpellAttr7.ReflectionOnlyDefends) ? SpellMissInfo.Deflect : SpellMissInfo.Reflect;
}
if (spellInfo.HasAttribute(SpellAttr3.AlwaysHit))
-17
View File
@@ -295,23 +295,6 @@ namespace Game.Entities
petStable.SetCurrentActivePetIndex((uint)activePetIndex);
}
// Send fake summon spell cast - this is needed for correct cooldown application for spells
// Example: 46584 - without this cooldown (which should be set always when pet is loaded) isn't set clientside
// @todo pets should be summoned from real cast instead of just faking it?
if (petInfo.CreatedBySpellId != 0)
{
SpellGo spellGo = new();
SpellCastData castData = spellGo.Cast;
castData.CasterGUID = owner.GetGUID();
castData.CasterUnit = owner.GetGUID();
castData.CastID = ObjectGuid.Create(HighGuid.Cast, SpellCastSource.Normal, owner.GetMapId(), petInfo.CreatedBySpellId, map.GenerateLowGuid(HighGuid.Cast));
castData.SpellID = (int)petInfo.CreatedBySpellId;
castData.CastFlags = SpellCastFlags.Unk9;
castData.CastTime = Time.GetMSTime();
owner.SendMessageToSet(spellGo, true);
}
owner.SetMinion(this, true);
if (!isTemporarySummon)
+2 -2
View File
@@ -794,10 +794,10 @@ namespace Game.Entities
damage -= (int)target.GetDamageReduction((uint)damage);
}
public int CalculateAOEAvoidance(int damage, uint schoolMask, ObjectGuid casterGuid)
public int CalculateAOEAvoidance(int damage, uint schoolMask, bool npcCaster)
{
damage = (int)((float)damage * GetTotalAuraMultiplierByMiscMask(AuraType.ModAoeDamageAvoidance, schoolMask));
if (casterGuid.IsAnyTypeCreature())
if (npcCaster)
damage = (int)((float)damage * GetTotalAuraMultiplierByMiscMask(AuraType.ModCreatureAoeDamageAvoidance, schoolMask));
return damage;
+30 -19
View File
@@ -945,7 +945,7 @@ namespace Game.Entities
public void SetSilencedSchoolMask(SpellSchoolMask schoolMask) { SetUpdateFieldFlagValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.SilencedSchoolMask), (uint)schoolMask); }
public void ReplaceAllSilencedSchoolMask(SpellSchoolMask schoolMask) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.SilencedSchoolMask), (uint)schoolMask); }
public SpellHistory GetSpellHistory() { return _spellHistory; }
public static ProcFlagsHit CreateProcHitMask(SpellNonMeleeDamage damageInfo, SpellMissInfo missCondition)
@@ -1511,10 +1511,18 @@ namespace Game.Entities
}
WeaponAttackType attType = damageInfo != null ? damageInfo.GetAttackType() : WeaponAttackType.BaseAttack;
if (typeMaskActor && actor != null)
SpellInfo spellInfo = null;
if (spell != null)
spellInfo = spell.GetSpellInfo();
else if (damageInfo != null)
spellInfo = damageInfo.GetSpellInfo();
else if (healInfo != null)
spellInfo = healInfo.GetSpellInfo();
if (typeMaskActor != null && actor != null && !(spellInfo != null && spellInfo.HasAttribute(SpellAttr3.SuppressCasterProcs)))
actor.ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType);
if (typeMaskActionTarget && actionTarget != null)
if (typeMaskActionTarget && actionTarget != null && !(spellInfo != null && spellInfo.HasAttribute(SpellAttr3.SuppressTargetProcs)))
actionTarget.ProcSkillsAndReactives(true, actor, typeMaskActionTarget, hitMask, attType);
if (actor != null)
@@ -1903,9 +1911,12 @@ namespace Game.Entities
Player bgPlayer = unit.ToPlayer();
if (bgPlayer != null)
{
Battleground bg = bgPlayer.GetBattleground();
if (bg != null)
bg.UpdatePlayerScore(bgPlayer, ScoreType.HealingDone, (uint)gain);
if (healInfo.GetSpellInfo() == null || !healInfo.GetSpellInfo().HasAttribute(SpellAttr7.DoNotCountForPvpScoreboard))
{
Battleground bg = bgPlayer.GetBattleground();
if (bg != null)
bg.UpdatePlayerScore(bgPlayer, ScoreType.HealingDone, (uint)gain);
}
// use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
if (gain != 0)
@@ -2758,7 +2769,7 @@ namespace Game.Entities
return false;
}
public bool HasNegativeAuraWithInterruptFlag(SpellAuraInterruptFlags flag, ObjectGuid guid = default)
{
if (!HasInterruptFlag(flag))
@@ -2806,7 +2817,7 @@ namespace Game.Entities
return false;
}
public uint GetAuraCount(uint spellId)
{
uint count = 0;
@@ -2873,7 +2884,7 @@ namespace Game.Entities
// The charges / stack amounts don't count towards the total number of auras that can be dispelled.
// Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) . 50% chance to dispell
// Polymorph instead of 1 / (5 + 1) . 16%.
bool dispelCharges = aura.GetSpellInfo().HasAttribute(SpellAttr7.DispelCharges);
bool dispelCharges = aura.GetSpellInfo().HasAttribute(SpellAttr7.DispelRemovesCharges);
byte charges = dispelCharges ? aura.GetCharges() : aura.GetStackAmount();
if (charges > 0)
dispelList.Add(new DispelableAura(aura, chance, charges));
@@ -2911,7 +2922,7 @@ namespace Game.Entities
{
return false;
}
public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags flag, SpellInfo source = null)
{
if (!HasInterruptFlag(flag))
@@ -3038,7 +3049,7 @@ namespace Game.Entities
}
}
bool stealCharge = aura.GetSpellInfo().HasAttribute(SpellAttr7.DispelCharges);
bool stealCharge = aura.GetSpellInfo().HasAttribute(SpellAttr7.DispelRemovesCharges);
// Cast duration to unsigned to prevent permanent aura's such as Righteous Fury being permanently added to caster
uint dur = (uint)Math.Min(2u * Time.Minute * Time.InMilliseconds, aura.GetDuration());
@@ -3241,7 +3252,7 @@ namespace Game.Entities
// Call OnDispel hook on AuraScript
aura.CallScriptDispel(dispelInfo);
if (aura.GetSpellInfo().HasAttribute(SpellAttr7.DispelCharges))
if (aura.GetSpellInfo().HasAttribute(SpellAttr7.DispelRemovesCharges))
aura.ModCharges(-dispelInfo.GetRemovedCharges(), AuraRemoveMode.EnemySpell);
else
aura.ModStackAmount(-dispelInfo.GetRemovedCharges(), AuraRemoveMode.EnemySpell);
@@ -3455,7 +3466,7 @@ namespace Game.Entities
// this may be a dead loop if some events on aura remove will continiously apply aura on remove
// we want to have all auras removed, so use your brain when linking events
for (int counter = 0; !m_appliedAuras.Empty() || !m_ownedAuras.Empty(); counter++)
{
{
foreach (var aurAppIter in GetAppliedAuras())
_UnapplyAura(aurAppIter, AuraRemoveMode.Default);
@@ -3815,7 +3826,7 @@ namespace Game.Entities
}
return null;
}
// spell mustn't have familyflags
public AuraEffect GetAuraEffect(AuraType type, SpellFamilyNames family, FlagArray128 familyFlag, ObjectGuid casterGUID = default)
{
@@ -3903,7 +3914,7 @@ namespace Game.Entities
AuraApplication aurApp = GetAuraApplication(predicate);
return aurApp?.GetBase();
}
public uint BuildAuraStateUpdateForTarget(Unit target)
{
uint auraStates = m_unitData.AuraState & ~(uint)AuraStateType.PerCasterAuraStateMask;
@@ -3918,7 +3929,7 @@ namespace Game.Entities
public bool CanProc() { return m_procDeep == 0; }
public int GetProcChainLength() { return m_procChainLength; }
public void _ApplyAuraEffect(Aura aura, uint effIndex)
{
Cypher.Assert(aura != null);
@@ -3982,8 +3993,8 @@ namespace Game.Entities
if (player != null)
{
if (Global.ConditionMgr.IsSpellUsedInSpellClickConditions(aurApp.GetBase().GetId()))
player.UpdateVisibleGameobjectsOrSpellClicks();
player.UpdateVisibleGameobjectsOrSpellClicks();
player.FailCriteria(CriteriaFailEvent.GainAura, aurApp.GetBase().GetId());
player.StartCriteria(CriteriaStartEvent.GainAura, aurApp.GetBase().GetId());
player.UpdateCriteria(CriteriaType.GainAura, aurApp.GetBase().GetId());
@@ -4168,7 +4179,7 @@ namespace Game.Entities
//uint removedAuras = m_removedAurasCount;
RemoveAura(aurApp);
//if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1)
//continue;
//continue;
}
}
}
+2 -2
View File
@@ -2724,7 +2724,7 @@ namespace Game.Entities
if (killer != null)
{
// in bg, count dmg if victim is also a player
if (victim.IsPlayer())
if (victim.IsPlayer() && !(spellProto != null && spellProto.HasAttribute(SpellAttr7.DoNotCountForPvpScoreboard)))
{
Battleground bg = killer.GetBattleground();
if (bg != null)
@@ -2864,7 +2864,7 @@ namespace Game.Entities
if (damagetype != DamageEffectType.NoDamage && damagetype != DamageEffectType.DOT)
{
if (victim != attacker && (spellProto == null || !(spellProto.HasAttribute(SpellAttr6.NoPushback) || spellProto.HasAttribute(SpellAttr7.NoPushbackOnDamage) || spellProto.HasAttribute(SpellAttr3.TreatAsPeriodic))))
if (victim != attacker && (spellProto == null || !(spellProto.HasAttribute(SpellAttr6.NoPushback) || spellProto.HasAttribute(SpellAttr7.DontCauseSpellPushback) || spellProto.HasAttribute(SpellAttr3.TreatAsPeriodic))))
{
Spell spell = victim.GetCurrentSpell(CurrentSpellTypes.Generic);
if (spell != null)
+14
View File
@@ -1726,6 +1726,20 @@ namespace Game.Spells
if (GetSpellInfo().HasAttribute(SpellAttr12.OnlyProcFromClassAbilities) && !spell.GetSpellInfo().HasAttribute(SpellAttr13.AllowClassAbilityProcs))
return 0;
if (eventInfo.GetTypeMask().HasFlag(ProcFlags.TakenHitMask))
{
if (spell.GetSpellInfo().HasAttribute(SpellAttr3.SuppressTargetProcs)
&& !GetSpellInfo().HasAttribute(SpellAttr7.CanProcFromSuppressedTargetProcs))
return 0;
}
else
{
if (spell.GetSpellInfo().HasAttribute(SpellAttr3.SuppressCasterProcs)
&& !spell.GetSpellInfo().HasAttribute(SpellAttr12.EnableProcsFromSuppressedCasterProcs)
&& !GetSpellInfo().HasAttribute(SpellAttr12.CanProcFromSuppressedCasterProcs))
return 0;
}
}
// check don't break stealth attr present
+4 -4
View File
@@ -5126,8 +5126,8 @@ namespace Game.Spells
if (!GetSpellInfo().HasAttribute(SpellAttr4.IgnoreDamageTakenModifiers))
{
if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura) || GetSpellInfo().HasAttribute(SpellAttr5.TreatAsAreaEffect))
damage = (uint)target.CalculateAOEAvoidance((int)damage, (uint)m_spellInfo.SchoolMask, GetBase().GetCastItemGUID());
if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura) || GetSpellInfo().HasAttribute(SpellAttr5.TreatAsAreaEffect) || GetSpellInfo().HasAttribute(SpellAttr7.TreatAsNpcAoe))
damage = (uint)target.CalculateAOEAvoidance((int)damage, (uint)m_spellInfo.SchoolMask, (caster != null && !caster.IsControlledByPlayer()) || GetSpellInfo().HasAttribute(SpellAttr7.TreatAsNpcAoe));
}
int dmg = (int)damage;
@@ -5208,8 +5208,8 @@ namespace Game.Spells
if (!GetSpellInfo().HasAttribute(SpellAttr4.IgnoreDamageTakenModifiers))
{
if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura) || GetSpellInfo().HasAttribute(SpellAttr5.TreatAsAreaEffect))
damage = (uint)target.CalculateAOEAvoidance((int)damage, (uint)m_spellInfo.SchoolMask, GetBase().GetCastItemGUID());
if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura) || GetSpellInfo().HasAttribute(SpellAttr5.TreatAsAreaEffect) || GetSpellInfo().HasAttribute(SpellAttr7.TreatAsNpcAoe))
damage = (uint)target.CalculateAOEAvoidance((int)damage, (uint)m_spellInfo.SchoolMask, (caster != null && !caster.IsControlledByPlayer()) || GetSpellInfo().HasAttribute(SpellAttr7.TreatAsNpcAoe));
}
int dmg = (int)damage;
+59 -52
View File
@@ -90,7 +90,7 @@ namespace Game.Spells
// Determine if spell can be reflected back to the caster
// Patch 1.2 notes: Spell Reflection no longer reflects abilities
m_canReflect = caster.IsUnit() && m_spellInfo.DmgClass == SpellDmgClass.Magic && !m_spellInfo.HasAttribute(SpellAttr0.IsAbility)
m_canReflect = caster.IsUnit() && ((m_spellInfo.DmgClass == SpellDmgClass.Magic && !m_spellInfo.HasAttribute(SpellAttr0.IsAbility)) || m_spellInfo.HasAttribute(SpellAttr7.AllowSpellReflection))
&& !m_spellInfo.HasAttribute(SpellAttr1.NoReflection) && !m_spellInfo.HasAttribute(SpellAttr0.NoImmunities)
&& !m_spellInfo.IsPassive();
@@ -1746,9 +1746,9 @@ namespace Game.Spells
if (m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster))
searchRadius = GetMinMaxRange(false).maxRange;
else if (spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes.ChainFromInitialTarget))
searchRadius= jumpRadius;
searchRadius = jumpRadius;
else
searchRadius= jumpRadius * chainTargets;
searchRadius = jumpRadius * chainTargets;
WorldObject chainSource = m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster) ? m_caster : target;
List<WorldObject> tempTargets = new();
@@ -1924,7 +1924,7 @@ namespace Game.Spells
float hitDelay = m_spellInfo.LaunchDelay;
WorldObject missileSource = m_caster;
if (m_spellInfo.HasAttribute(SpellAttr4.BouncyChainMissiles))
{
{
var previousTargetInfo = m_UniqueTargetInfo.FindLast(target => (target.EffectMask & effectMask) != 0);
if (previousTargetInfo != null)
{
@@ -2614,6 +2614,9 @@ namespace Game.Spells
if (m_spellInfo.HasAttribute(SpellAttr12.StartCooldownOnCastStart))
SendSpellCooldown();
if (m_spellInfo.HasAttribute(SpellAttr7.ResetSwingTimerAtSpellStart) && IsAutoActionResetSpell())
ResetCombatTimers();
//Containers for channeled spells have to be set
// @todoApply this to all casted spells if needed
// Why check duration? 29350: channelled triggers channelled
@@ -2951,6 +2954,9 @@ namespace Game.Spells
m_launchHandled = true;
}
if (!m_spellInfo.HasAttribute(SpellAttr7.ResetSwingTimerAtSpellStart) && IsAutoActionResetSpell())
ResetCombatTimers();
// we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()...
SendSpellGo();
@@ -3052,8 +3058,7 @@ namespace Game.Spells
if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreCastInProgress) && !m_spellInfo.HasAttribute(SpellAttr2.NotAnAction))
m_originalCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ActionDelayed, m_spellInfo);
if (!m_spellInfo.HasAttribute(SpellAttr3.SuppressCasterProcs))
Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Cast, hitMask, this, null, null);
Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Cast, hitMask, this, null, null);
// Call CreatureAI hook OnSpellCast
Creature caster = m_originalCaster.ToCreature();
@@ -3306,8 +3311,7 @@ namespace Game.Spells
}
}
if (!m_spellInfo.HasAttribute(SpellAttr3.SuppressCasterProcs))
Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, new ProcFlagsInit(ProcFlags.None), m_procSpellType, ProcFlagsSpellPhase.Finish, m_hitMask, this, null, null);
Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, new ProcFlagsInit(ProcFlags.None), m_procSpellType, ProcFlagsSpellPhase.Finish, m_hitMask, this, null, null);
}
void SendSpellCooldown()
@@ -3452,8 +3456,7 @@ namespace Game.Spells
if (creatureCaster != null)
creatureCaster.ReleaseSpellFocus(this);
if (!m_spellInfo.HasAttribute(SpellAttr3.SuppressCasterProcs))
Unit.ProcSkillsAndAuras(unitCaster, null, new ProcFlagsInit(ProcFlags.CastEnded), new ProcFlagsInit(), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, this, null, null);
Unit.ProcSkillsAndAuras(unitCaster, null, new ProcFlagsInit(ProcFlags.CastEnded), new ProcFlagsInit(), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, this, null, null);
if (result != SpellCastResult.SpellCastOk)
{
@@ -3481,17 +3484,6 @@ namespace Game.Spells
}
}
if (IsAutoActionResetSpell())
{
if (!m_spellInfo.HasAttribute(SpellAttr2.DoNotResetCombatTimers))
{
unitCaster.ResetAttackTimer(WeaponAttackType.BaseAttack);
if (unitCaster.HaveOffhandWeapon())
unitCaster.ResetAttackTimer(WeaponAttackType.OffAttack);
unitCaster.ResetAttackTimer(WeaponAttackType.RangedAttack);
}
}
// potions disabled by client, send event "not in combat" if need
if (unitCaster.IsTypeId(TypeId.Player))
{
@@ -3675,7 +3667,7 @@ namespace Game.Spells
uint itemid = (uint)spellInfo.Reagent[i];
uint itemcount = spellInfo.ReagentCount[i];
if (!caster.HasItemCount(itemid, itemcount))
if (caster != null && !caster.HasItemCount(itemid, itemcount))
{
packet.FailedArg1 = (int)itemid; // first missing item
break;
@@ -3689,7 +3681,7 @@ namespace Game.Spells
{
foreach (var reagentsCurrency in spellInfo.ReagentsCurrency)
{
if (!caster.HasCurrency(reagentsCurrency.CurrencyTypesID, reagentsCurrency.CurrencyCount))
if (caster != null && !caster.HasCurrency(reagentsCurrency.CurrencyTypesID, reagentsCurrency.CurrencyCount))
{
packet.FailedArg1 = -1;
packet.FailedArg2 = reagentsCurrency.CurrencyTypesID;
@@ -3716,10 +3708,18 @@ namespace Game.Spells
if (result == SpellCastResult.SpellCastOk)
return;
if (!m_caster.IsTypeId(TypeId.Player))
Player receiver = m_caster.ToPlayer();
if (m_spellInfo.HasAttribute(SpellAttr7.ReportSpellFailureToUnitTarget))
{
Player target = m_targets.GetUnitTarget()?.ToPlayer();
if (target != null)
receiver = target;
}
if (receiver == null)
return;
if (m_caster.ToPlayer().IsLoading()) // don't send cast results at loading time
if (receiver.IsLoading()) // don't send cast results at loading time
return;
if (_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.DontReportCastError))
@@ -3728,7 +3728,7 @@ namespace Game.Spells
CastFailed castFailed = new();
castFailed.Visual = m_SpellVisual;
FillSpellCastFailedArgs(castFailed, m_castId, m_spellInfo, result, m_customError, param1, param2, m_caster.ToPlayer());
m_caster.ToPlayer().SendPacket(castFailed);
receiver.SendPacket(castFailed);
}
public void SendPetCastResult(SpellCastResult result, int? param1 = null, int? param2 = null)
@@ -4740,7 +4740,7 @@ namespace Game.Spells
}
}
if (m_spellInfo.HasAttribute(SpellAttr7.IsCheatSpell) && m_caster.IsUnit() && !m_caster.ToUnit().HasUnitFlag2(UnitFlags2.AllowCheatSpells))
if (m_spellInfo.HasAttribute(SpellAttr7.DebugSpell) && m_caster.IsUnit() && !m_caster.ToUnit().HasUnitFlag2(UnitFlags2.AllowCheatSpells))
{
m_customError = SpellCustomErrors.GmOnly;
return SpellCastResult.CustomError;
@@ -7113,7 +7113,7 @@ namespace Game.Spells
if (target.GetGUID() != corpse.GetOwnerGUID())
return false;
if (!corpse.HasCorpseDynamicFlag(CorpseDynFlags.Lootable))
return false;
@@ -7178,7 +7178,7 @@ namespace Game.Spells
bool IsAutoActionResetSpell()
{
if (IsTriggered())
if (IsTriggered() || m_spellInfo.HasAttribute(SpellAttr2.DoNotResetCombatTimers))
return false;
if (m_casttime == 0 && m_spellInfo.HasAttribute(SpellAttr6.DoesntResetSwingTimerIfInstant))
@@ -7195,7 +7195,8 @@ namespace Game.Spells
bool IsNeedSendToClient()
{
return m_SpellVisual.SpellXSpellVisualID != 0 || m_SpellVisual.ScriptVisualID != 0 || m_spellInfo.IsChanneled() ||
m_spellInfo.HasAttribute(SpellAttr8.AuraSendAmount) || m_spellInfo.HasHitDelay() || (m_triggeredByAuraSpell == null && !IsTriggered());
(m_spellInfo.HasAttribute(SpellAttr8.AuraSendAmount)) || m_spellInfo.HasHitDelay() || (m_triggeredByAuraSpell == null && !IsTriggered()) ||
m_spellInfo.HasAttribute(SpellAttr7.AlwaysCastLog);
}
public Unit GetUnitCasterForEffectHandlers()
@@ -7226,7 +7227,7 @@ namespace Game.Spells
PrepareTargetProcessing();
foreach (TargetInfo target in m_UniqueTargetInfo)
foreach (TargetInfo target in m_UniqueTargetInfo)
PreprocessSpellLaunch(target);
foreach (var spellEffectInfo in m_spellInfo.GetEffects())
@@ -7300,9 +7301,9 @@ namespace Game.Spells
if (m_originalCaster != null && m_damage > 0)
{
bool isAoeTarget = spellEffectInfo.IsTargetingArea() || spellEffectInfo.IsAreaAuraEffect() || spellEffectInfo.IsEffect(SpellEffectName.PersistentAreaAura);
if (isAoeTarget || m_spellInfo.HasAttribute(SpellAttr5.TreatAsAreaEffect))
if (isAoeTarget || m_spellInfo.HasAttribute(SpellAttr5.TreatAsAreaEffect) || m_spellInfo.HasAttribute(SpellAttr7.TreatAsNpcAoe))
{
m_damage = unit.CalculateAOEAvoidance(m_damage, (uint)m_spellInfo.SchoolMask, m_originalCaster.GetGUID());
m_damage = unit.CalculateAOEAvoidance(m_damage, (uint)m_spellInfo.SchoolMask, !m_originalCaster.IsControlledByPlayer() || m_spellInfo.HasAttribute(SpellAttr7.TreatAsNpcAoe));
if (m_originalCaster.IsPlayer())
{
@@ -7352,6 +7353,18 @@ namespace Game.Spells
targetInfo.Healing += m_healing;
}
void ResetCombatTimers()
{
Unit unitCaster = m_caster.ToUnit();
if (unitCaster == null)
return;
unitCaster.ResetAttackTimer(WeaponAttackType.BaseAttack);
if (unitCaster.HaveOffhandWeapon())
unitCaster.ResetAttackTimer(WeaponAttackType.OffAttack);
unitCaster.ResetAttackTimer(WeaponAttackType.RangedAttack);
}
SpellCastResult CanOpenLock(SpellEffectInfo effect, uint lockId, ref SkillType skillId, ref int reqSkillValue, ref int skillValue)
{
if (lockId == 0) // possible case for GO and maybe for items.
@@ -7700,7 +7713,7 @@ namespace Game.Spells
script._FinishScriptCall();
}
}
void CallScriptObjectAreaTargetSelectHandlers(List<WorldObject> targets, uint effIndex, SpellImplicitTargetInfo targetType)
{
foreach (var script in m_loadedScripts)
@@ -7782,7 +7795,7 @@ namespace Game.Spells
return source.IsWithinLOS(target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(), LineOfSightChecks.All, ignoreFlags);
}
bool CheckScriptEffectImplicitTargets(uint effIndex, uint effIndexToCheck)
{
// Skip if there are not any script
@@ -8033,7 +8046,7 @@ namespace Game.Spells
public bool IsChannelActive() { return m_caster.IsUnit() && m_caster.ToUnit().GetChannelSpellId() != 0; }
public int GetProcChainLength() { return m_procChainLength; }
public bool IsDeletable()
{
return !m_referencedFromCurrentSpell && !m_executedCurrently;
@@ -8090,7 +8103,7 @@ namespace Game.Spells
public SpellInfo GetTriggeredByAuraSpell() { return m_triggeredByAuraSpell; }
public int GetTimer() { return m_timer; }
#region Fields
Dictionary<SpellEffectName, SpellLogEffect> _executeLogEffects = new();
PathGenerator m_preGeneratedPath;
@@ -8499,7 +8512,7 @@ namespace Game.Spells
ProcFlagsHit hitMask = ProcFlagsHit.None;
// Spells with this flag cannot trigger if effect is cast on self
bool canEffectTrigger = (!spell.m_spellInfo.HasAttribute(SpellAttr3.SuppressCasterProcs) || !spell.m_spellInfo.HasAttribute(SpellAttr3.SuppressTargetProcs)) && spell.unitTarget.CanProc();
bool canEffectTrigger = spell.unitTarget.CanProc();
// Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now
if (canEffectTrigger && !procAttacker && !procVictim)
@@ -8667,12 +8680,6 @@ namespace Game.Spells
// Do triggers for unit
if (canEffectTrigger)
{
if (spell.m_spellInfo.HasAttribute(SpellAttr3.SuppressCasterProcs))
procAttacker = new ProcFlagsInit();
if (spell.m_spellInfo.HasAttribute(SpellAttr3.SuppressTargetProcs))
procVictim = new ProcFlagsInit();
Unit.ProcSkillsAndAuras(caster, spell.unitTarget, procAttacker, procVictim, procSpellType, ProcFlagsSpellPhase.Hit, hitMask, spell, spellDamageInfo, healInfo);
// item spells (spell hit of non-damage spell may also activate items, for example seal of corruption hidden hit)
@@ -8709,7 +8716,7 @@ namespace Game.Spells
}
// Check for SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER
if (MissCondition == SpellMissInfo.None && spell.m_spellInfo.HasAttribute(SpellAttr7.InterruptOnlyNonplayer) && !unit.IsPlayer())
if (MissCondition == SpellMissInfo.None && spell.m_spellInfo.HasAttribute(SpellAttr7.CanCauseInterrupt) && !unit.IsPlayer())
caster.CastSpell(unit, 32747, new CastSpellExtraArgs(spell));
}
@@ -9256,7 +9263,7 @@ namespace Game.Spells
Spell m_Spell;
}
class ProcReflectDelayed : BasicEvent
{
public ProcReflectDelayed(Unit owner, ObjectGuid casterGuid)
@@ -9333,7 +9340,7 @@ namespace Game.Spells
Targets = new();
Targets.SetDst(dest);
}
public CastSpellTargetArg(SpellCastTargets targets)
{
Targets = new();
@@ -9482,15 +9489,15 @@ namespace Game.Spells
}
public static implicit operator CastSpellExtraArgs(bool triggered) => new CastSpellExtraArgs(triggered);
public static implicit operator CastSpellExtraArgs(TriggerCastFlags trigger) => new CastSpellExtraArgs(trigger);
public static implicit operator CastSpellExtraArgs(Item item) => new CastSpellExtraArgs(item);
public static implicit operator CastSpellExtraArgs(Spell triggeringSpell) => new CastSpellExtraArgs(triggeringSpell);
public static implicit operator CastSpellExtraArgs(AuraEffect eff) => new CastSpellExtraArgs(eff);
public static implicit operator CastSpellExtraArgs(Difficulty castDifficulty) => new CastSpellExtraArgs(castDifficulty);
}
+3 -3
View File
@@ -3597,7 +3597,7 @@ namespace Game.Spells
if (effectHandleMode == SpellEffectHandleMode.HitTarget)
{
// not all charge effects used in negative spells
if (!m_spellInfo.IsPositive() && m_caster.IsTypeId(TypeId.Player))
if (m_spellInfo.HasAttribute(SpellAttr7.AttackOnChargeToUnit))
unitCaster.Attack(unitTarget, true);
if (effectInfo.TriggerSpell != 0)
@@ -4389,7 +4389,7 @@ namespace Game.Spells
// The charges / stack amounts don't count towards the total number of auras that can be dispelled.
// Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) . 50% chance to dispell
// Polymorph instead of 1 / (5 + 1) . 16%.
bool dispelCharges = aura.GetSpellInfo().HasAttribute(SpellAttr7.DispelCharges);
bool dispelCharges = aura.GetSpellInfo().HasAttribute(SpellAttr7.DispelRemovesCharges);
byte charges = dispelCharges ? aura.GetCharges() : aura.GetStackAmount();
if (charges > 0)
stealList.Add(new DispelableAura(aura, chance, charges));
@@ -4864,7 +4864,7 @@ namespace Game.Spells
if (!player.HasSpell(spell_id) || player.GetSpellHistory().HasCooldown(spell_id))
continue;
if (!spellInfo.HasAttribute(SpellAttr9.SummonPlayerTotem))
if (!spellInfo.HasAttribute(SpellAttr7.CanBeMultiCast))
continue;
CastSpellExtraArgs args = new(TriggerCastFlags.IgnoreGCD | TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.CastDirectly | TriggerCastFlags.DontReportCastError);
+1 -1
View File
@@ -3952,7 +3952,7 @@ namespace Game.Spells
public bool CanBeInterrupted(WorldObject interruptCaster, Unit interruptTarget, bool ignoreImmunity = false)
{
return HasAttribute(SpellAttr7.CanAlwaysBeInterrupted)
return HasAttribute(SpellAttr7.NoUiNotInterruptible)
|| HasChannelInterruptFlag(SpellAuraInterruptFlags.Damage | SpellAuraInterruptFlags.EnteringCombat)
|| (interruptTarget.IsPlayer() && InterruptFlags.HasFlag(SpellInterruptFlags.DamageCancelsPlayerOnly))
|| InterruptFlags.HasFlag(SpellInterruptFlags.DamageCancels)