Core/Spells: Rename SpellAttr2 to use official attribute names

Port From (https://github.com/TrinityCore/TrinityCore/commit/dda375b9868d6dbe2a4d58b386bb90ae41d25e0d)
This commit is contained in:
hondacrx
2022-06-01 11:53:42 -04:00
parent a2d9499152
commit a198e03a1d
13 changed files with 256 additions and 157 deletions
+32 -32
View File
@@ -1653,38 +1653,38 @@ namespace Framework.Constants
} }
public enum SpellAttr2 : uint public enum SpellAttr2 : uint
{ {
CanTargetDead = 0x01, // 0 Can Target Dead Unit Or Corpse AllowDeadTarget = 0x01, // Allow Dead Target
Unk1 = 0x02, // 1 Vanish, Shadowform, Ghost Wolf And Other NoShapeshiftUi = 0x02, // No Shapeshift Ui (Client Only) Description Does Not Replace Action Bar When Shapeshifted
CanTargetNotInLos = 0x04, // 2 26368 4.0.1 Dbc Change IgnoreLineOfSight = 0x04, // Ignore Line Of Sight
Unk3 = 0x08, // 3 AllowLowLevelBuff = 0x08, // Allow Low Level Buff
DisplayInStanceBar = 0x10, // 4 Client Displays Icon In Stance Bar When Learned, Even If Not Shapeshift UseShapeshiftBar = 0x10, // Use Shapeshift Bar (Client Only)
AutorepeatFlag = 0x20, // 5 AutoRepeat = 0x20, // Auto Repeat
CantTargetTapped = 0x40, // 6 Target Must Be Tapped By Caster CannotCastOnTapped = 0x40, // Cannot Cast On Tapped Description Can Only Target Untapped Units, Or Those Tapped By Caster
Unk7 = 0x80, // 7 DoNotReportSpellFailure = 0x80, // Do Not Report Spell Failure
Unk8 = 0x100, // 8 Not Set In 3.0.3 IncludeInAdvancedCombatLog = 0x100, // Include In Advanced Combat Log (Client Only) Description Determines Whether To Include This Aura In List Of Auras In SmsgEncounterStart
Unk9 = 0x200, // 9 AlwaysCastAsUnit = 0x200, /*Nyi, Unk*/ // Always Cast As Unit
Unk10 = 0x400, // 10 Related To Tame SpecialTamingFlag = 0x400, // Special Taming Flag Description Related To Taming?
HealthFunnel = 0x800, // 11 NoTargetPerSecondCosts = 0x800, // No Target Per-Second Costs
Unk12 = 0x1000, // 12 Cleave, Heart Strike, Maul, Sunder Armor, Swipe ChainFromCaster = 0x1000, // Chain From Caster
PreserveEnchantInArena = 0x2000, // 13 Items Enchanted By Spells With This Flag Preserve The Enchant To Arenas EnchantOwnItemOnly = 0x2000, // Enchant Own Item Only
Unk14 = 0x4000, // 14 AllowWhileInvisible = 0x4000, // Allow While Invisible
Unk15 = 0x8000, // 15 Not Set In 3.0.3 DoNotConsumeIfGainedDuringCast = 0x8000, // Do Not Consume If Gained During Cast
TameBeast = 0x10000, // 16 NoActivePets = 0x10000, // No Active Pets
NotResetAutoActions = 0x20000, // 17 Don'T Reset Timers For Melee Autoattacks (Swings) Or Ranged Autoattacks (Autoshoots) DoNotResetCombatTimers = 0x20000, // Do Not Reset Combat Timers Description Does Not Reset Melee/Ranged Autoattack Timer On Cast
ReqDeadPet = 0x40000, // 18 Only Revive Pet And Heart Of The Pheonix NoJumpWhileCastPending = 0x40000, // No Jump While Cast Pending (Client Only)
NotNeedShapeshift = 0x80000, // 19 Does Not Necessarly Need Shapeshift AllowWhileNotShapeshiftedCasterForm = 0x80000, // Allow While Not Shapeshifted (Caster Form) Description Even If Stances Are Nonzero, Allow Spell To Be Cast Outside Of Shapeshift (Though Not In A Different Shapeshift)
Unk20 = 0x100000, // 20 InitiateCombatPostCastEnablesAutoAttack = 0x100000, // Initiate Combat Post-Cast (Enables Auto-Attack)
DamageReducedShield = 0x200000, // 21 For Ice Blocks, Pala Immunity Buffs, Priest Absorb Shields, But Used Also For Other Spells . Not Sure! FailOnAllTargetsImmune = 0x200000, // Fail On All Targets Immune Description Causes Bg Flags To Be Dropped If Combined With Attr1DispelAurasOnImmunity
Unk22 = 0x400000, // 22 Ambush, Backstab, Cheap Shot, Death Grip, Garrote, Judgements, Mutilate, Pounce, Ravage, Shiv, Shred NoInitialThreat = 0x400000, // No Initial Threat
IsArcaneConcentration = 0x800000, // 23 Only Mage Arcane Concentration Have This Flag ProcCooldownOnFailure = 0x800000, // Proc Cooldown On Failure
Unk24 = 0x1000000, // 24 ItemCastWithOwnerSkill = 0x1000000, // Item Cast With Owner Skill
Unk25 = 0x2000000, // 25 DontBlockManaRegen = 0x2000000, // Don'T Block Mana Regen
UnaffectedByAuraSchoolImmune = 0x4000000, // 26 Unaffected By School Immunity NoSchoolImmunities = 0x4000000, // No School Immunities Description Allow Aura To Be Applied Despite Target Being Immune To New Aura Applications
Unk27 = 0x8000000, // 27 IgnoreWeaponskill = 0x8000000, // Ignore Weaponskill
IgnoreActionAuraInterruptFlags = 0x10000000, // 28 doesnt break auras with SpellAuraInterruptFlags::Action and SpellAuraInterruptFlags::ActionDelayed NotAnAction = 0x10000000, // Not An Action
CantCrit = 0x20000000, // 29 Spell Can'T Crit CantCrit = 0x20000000, // Can'T Crit
ActiveThreat = 0x40000000, // 30 Active Threat ActiveThreat = 0x40000000, // Active Threat
FoodBuff = 0x80000000 // 31 Food Or Drink Buff (Like Well Fed) RetainItemCast = 0x80000000 // Retain Item Cast Description Passes MCastitem To Triggered Spells
} }
public enum SpellAttr3 : uint public enum SpellAttr3 : uint
{ {
+14 -2
View File
@@ -1917,7 +1917,7 @@ namespace Game.Entities
if (!(spellInfo.HasAttribute(SpellAttr0.IsAbility) || spellInfo.HasAttribute(SpellAttr0.IsTradeskill) || spellInfo.HasAttribute(SpellAttr3.NoDoneBonus)) && if (!(spellInfo.HasAttribute(SpellAttr0.IsAbility) || spellInfo.HasAttribute(SpellAttr0.IsTradeskill) || spellInfo.HasAttribute(SpellAttr3.NoDoneBonus)) &&
((IsPlayer() && spellInfo.SpellFamilyName != 0) || IsCreature())) ((IsPlayer() && spellInfo.SpellFamilyName != 0) || IsCreature()))
castTime = unitCaster.CanInstantCast() ? 0 : (int)(castTime * unitCaster.m_unitData.ModCastingSpeed); castTime = unitCaster.CanInstantCast() ? 0 : (int)(castTime * unitCaster.m_unitData.ModCastingSpeed);
else if (spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot) && !spellInfo.HasAttribute(SpellAttr2.AutorepeatFlag)) else if (spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot) && !spellInfo.HasAttribute(SpellAttr2.AutoRepeat))
castTime = (int)(castTime * unitCaster.m_modAttackSpeedPct[(int)WeaponAttackType.RangedAttack]); castTime = (int)(castTime * unitCaster.m_modAttackSpeedPct[(int)WeaponAttackType.RangedAttack]);
else if (Global.SpellMgr.IsPartOfSkillLine(SkillType.Cooking, spellInfo.Id) && unitCaster.HasAura(67556)) // cooking with Chef Hat. else if (Global.SpellMgr.IsPartOfSkillLine(SkillType.Cooking, spellInfo.Id) && unitCaster.HasAura(67556)) // cooking with Chef Hat.
castTime = 500; castTime = 500;
@@ -1943,7 +1943,7 @@ namespace Game.Entities
if (!(spellInfo.HasAttribute(SpellAttr0.IsAbility) || spellInfo.HasAttribute(SpellAttr0.IsTradeskill) || spellInfo.HasAttribute(SpellAttr3.NoDoneBonus)) && if (!(spellInfo.HasAttribute(SpellAttr0.IsAbility) || spellInfo.HasAttribute(SpellAttr0.IsTradeskill) || spellInfo.HasAttribute(SpellAttr3.NoDoneBonus)) &&
((IsPlayer() && spellInfo.SpellFamilyName != 0) || IsCreature())) ((IsPlayer() && spellInfo.SpellFamilyName != 0) || IsCreature()))
duration = (int)(duration * unitCaster.m_unitData.ModCastingSpeed); duration = (int)(duration * unitCaster.m_unitData.ModCastingSpeed);
else if (spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot) && !spellInfo.HasAttribute(SpellAttr2.AutorepeatFlag)) else if (spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot) && !spellInfo.HasAttribute(SpellAttr2.AutoRepeat))
duration = (int)(duration * unitCaster.m_modAttackSpeedPct[(int)WeaponAttackType.RangedAttack]); duration = (int)(duration * unitCaster.m_modAttackSpeedPct[(int)WeaponAttackType.RangedAttack]);
} }
@@ -2369,6 +2369,18 @@ namespace Game.Entities
if (args.OriginalCastItemLevel.HasValue) if (args.OriginalCastItemLevel.HasValue)
spell.m_castItemLevel = args.OriginalCastItemLevel.Value; spell.m_castItemLevel = args.OriginalCastItemLevel.Value;
if (spell.m_CastItem == null && info.HasAttribute(SpellAttr2.RetainItemCast))
{
if (args.TriggeringSpell)
spell.m_CastItem = args.TriggeringSpell.m_CastItem;
else if (args.TriggeringAura != null && !args.TriggeringAura.GetBase().GetCastItemGUID().IsEmpty())
{
Player triggeringAuraCaster = args.TriggeringAura.GetCaster()?.ToPlayer();
if (triggeringAuraCaster != null)
spell.m_CastItem = triggeringAuraCaster.GetItemByGuid(args.TriggeringAura.GetBase().GetCastItemGUID());
}
}
return spell.Prepare(targets.Targets, args.TriggeringAura); return spell.Prepare(targets.Targets, args.TriggeringAura);
} }
+1 -1
View File
@@ -3921,7 +3921,7 @@ namespace Game.Entities
Aura itemAura = GetAura((uint)effectData.SpellID, GetGUID(), pItem.GetGUID()); Aura itemAura = GetAura((uint)effectData.SpellID, GetGUID(), pItem.GetGUID());
if (itemAura != null) if (itemAura != null)
itemAura.AddProcCooldown(now + TimeSpan.FromMilliseconds(procEntry.Cooldown)); itemAura.AddProcCooldown(procEntry, now);
continue; continue;
} }
+2 -2
View File
@@ -1261,7 +1261,7 @@ namespace Game.Entities
uint SkillValue = GetPureSkillValue((SkillType)_spell_idx.SkillupSkillLineID); uint SkillValue = GetPureSkillValue((SkillType)_spell_idx.SkillupSkillLineID);
// Alchemy Discoveries here // Alchemy Discoveries here
if (spellInfo != null && spellInfo.Mechanic == Mechanics.Discovery) if (spellInfo.Mechanic == Mechanics.Discovery)
{ {
uint discoveredSpell = SkillDiscovery.GetSkillDiscoverySpell(_spell_idx.SkillupSkillLineID, spellInfo.Id, this); uint discoveredSpell = SkillDiscovery.GetSkillDiscoverySpell(_spell_idx.SkillupSkillLineID, spellInfo.Id, this);
if (discoveredSpell != 0) if (discoveredSpell != 0)
@@ -2277,7 +2277,7 @@ namespace Game.Entities
// talent dependent passives activated at form apply have proper stance data // talent dependent passives activated at form apply have proper stance data
ShapeShiftForm form = GetShapeshiftForm(); ShapeShiftForm form = GetShapeshiftForm();
bool need_cast = (spellInfo.Stances == 0 || (form != 0 && Convert.ToBoolean(spellInfo.Stances & (1ul << ((int)form - 1)))) || bool need_cast = (spellInfo.Stances == 0 || (form != 0 && Convert.ToBoolean(spellInfo.Stances & (1ul << ((int)form - 1)))) ||
(form == 0 && spellInfo.HasAttribute(SpellAttr2.NotNeedShapeshift))); (form == 0 && spellInfo.HasAttribute(SpellAttr2.AllowWhileNotShapeshiftedCasterForm)));
// Check EquippedItemClass // Check EquippedItemClass
// passive spells which apply aura and have an item requirement are to be added manually, instead of casted // passive spells which apply aura and have an item requirement are to be added manually, instead of casted
+66 -33
View File
@@ -1343,7 +1343,7 @@ namespace Game.Entities
return true; return true;
} }
if (!spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) if (!spellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities))
{ {
// Check for immune to application of harmful magical effects // Check for immune to application of harmful magical effects
var immuneAuraApply = GetAuraEffectsByType(AuraType.ModImmuneAuraApplySchool); var immuneAuraApply = GetAuraEffectsByType(AuraType.ModImmuneAuraApplySchool);
@@ -1382,7 +1382,7 @@ namespace Game.Entities
if (spellInfo.HasAttribute(SpellAttr0.NoImmunities) && spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) if (spellInfo.HasAttribute(SpellAttr0.NoImmunities) && spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult))
return false; return false;
if (spellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) || spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) if (spellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) || spellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities))
return false; return false;
uint schoolMask = (uint)spellInfo.GetSchoolMask(); uint schoolMask = (uint)spellInfo.GetSchoolMask();
@@ -1482,32 +1482,49 @@ namespace Game.Entities
{ {
DateTime now = GameTime.Now(); DateTime now = GameTime.Now();
// use provided list of auras which can proc void processAuraApplication(AuraApplication aurApp)
if (procAuras != null)
{ {
foreach (AuraApplication aurApp in procAuras)
{
Cypher.Assert(aurApp.GetTarget() == this);
uint procEffectMask = aurApp.GetBase().GetProcEffectMask(aurApp, eventInfo, now); uint procEffectMask = aurApp.GetBase().GetProcEffectMask(aurApp, eventInfo, now);
if (procEffectMask != 0) if (procEffectMask != 0)
{ {
aurApp.GetBase().PrepareProcToTrigger(aurApp, eventInfo, now); aurApp.GetBase().PrepareProcToTrigger(aurApp, eventInfo, now);
aurasTriggeringProc.Add(Tuple.Create(procEffectMask, aurApp)); aurasTriggeringProc.Add(Tuple.Create(procEffectMask, aurApp));
} }
else
{
if (aurApp.GetBase().GetSpellInfo().HasAttribute(SpellAttr0.ProcFailureBurnsCharge))
{
SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(aurApp.GetBase().GetSpellInfo());
if (procEntry != null)
{
aurApp.GetBase().PrepareProcChargeDrop(procEntry, eventInfo);
aurApp.GetBase().ConsumeProcCharges(procEntry);
}
}
if (aurApp.GetBase().GetSpellInfo().HasAttribute(SpellAttr2.ProcCooldownOnFailure))
{
SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(aurApp.GetBase().GetSpellInfo());
if (procEntry != null)
aurApp.GetBase().AddProcCooldown(procEntry, now);
}
}
}
// use provided list of auras which can proc
if (procAuras != null)
{
foreach (AuraApplication aurApp in procAuras)
{
Cypher.Assert(aurApp.GetTarget() == this);
processAuraApplication(aurApp);
} }
} }
// or generate one on our own // or generate one on our own
else else
{ {
foreach (var pair in GetAppliedAuras()) foreach (var pair in GetAppliedAuras())
{ processAuraApplication(pair.Value);
uint procEffectMask = pair.Value.GetBase().GetProcEffectMask(pair.Value, eventInfo, now);
if (procEffectMask != 0)
{
pair.Value.GetBase().PrepareProcToTrigger(pair.Value, eventInfo, now);
aurasTriggeringProc.Add(Tuple.Create(procEffectMask, pair.Value));
}
}
} }
} }
@@ -1556,11 +1573,8 @@ namespace Game.Entities
if (disableProcs) if (disableProcs)
SetCantProc(true); SetCantProc(true);
foreach (var aurAppProc in aurasTriggeringProc) foreach (var (procEffectMask, aurApp) in aurasTriggeringProc)
{ {
AuraApplication aurApp = aurAppProc.Item2;
uint procEffectMask = aurAppProc.Item1;
if (aurApp.GetRemoveMode() != 0) if (aurApp.GetRemoveMode() != 0)
continue; continue;
@@ -1694,7 +1708,7 @@ namespace Game.Entities
{ {
if (!skipInstant || currentSpell.GetCastTime() != 0) if (!skipInstant || currentSpell.GetCastTime() != 0)
{ {
if (!isAutoshoot || !currentSpell.m_spellInfo.HasAttribute(SpellAttr2.NotResetAutoActions)) if (!isAutoshoot || !currentSpell.m_spellInfo.HasAttribute(SpellAttr2.DoNotResetCombatTimers))
return true; return true;
} }
} }
@@ -1703,7 +1717,7 @@ namespace Game.Entities
if (!skipChanneled && currentSpell && if (!skipChanneled && currentSpell &&
(currentSpell.GetState() != SpellState.Finished)) (currentSpell.GetState() != SpellState.Finished))
{ {
if (!isAutoshoot || !currentSpell.m_spellInfo.HasAttribute(SpellAttr2.NotResetAutoActions)) if (!isAutoshoot || !currentSpell.m_spellInfo.HasAttribute(SpellAttr2.DoNotResetCombatTimers))
return true; return true;
} }
currentSpell = GetCurrentSpell(CurrentSpellTypes.AutoRepeat); currentSpell = GetCurrentSpell(CurrentSpellTypes.AutoRepeat);
@@ -2494,7 +2508,7 @@ namespace Game.Entities
if (spellInfo == null) if (spellInfo == null)
return null; return null;
if (!target.IsAlive() && !spellInfo.IsPassive() && !spellInfo.HasAttribute(SpellAttr2.CanTargetDead)) if (!target.IsAlive() && !spellInfo.IsPassive() && !spellInfo.HasAttribute(SpellAttr2.AllowDeadTarget))
return null; return null;
if (target.IsImmunedToSpell(spellInfo, this)) if (target.IsImmunedToSpell(spellInfo, this))
@@ -2823,16 +2837,35 @@ namespace Game.Entities
return dispelList; return dispelList;
} }
bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags flag, Unit unit, SpellInfo spellInfo) bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags flag, Unit unit, SpellInfo auraSpellInfo, SpellInfo interruptSource)
{ {
return flag == SpellAuraInterruptFlags.Moving && unit.CanCastSpellWhileMoving(spellInfo); switch (flag)
{
case SpellAuraInterruptFlags.Moving:
return unit.CanCastSpellWhileMoving(auraSpellInfo);
case SpellAuraInterruptFlags.Action:
case SpellAuraInterruptFlags.ActionDelayed:
if (interruptSource != null)
{
if (interruptSource.HasAttribute(SpellAttr1.AllowWhileStealthed) && auraSpellInfo.HasAura(AuraType.ModStealth))
return true;
if (interruptSource.HasAttribute(SpellAttr2.AllowWhileInvisible) && auraSpellInfo.HasAura(AuraType.ModInvisibility))
return true;
} }
bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags2 flag, Unit unit, SpellInfo spellInfo) break;
default:
break;
}
return false;
}
bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags2 flag, Unit unit, SpellInfo auraSpellInfo, SpellInfo interruptSource)
{ {
return false; return false;
} }
public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags flag, uint except = 0) public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags flag, SpellInfo source = null)
{ {
if (!HasInterruptFlag(flag)) if (!HasInterruptFlag(flag))
return; return;
@@ -2842,7 +2875,7 @@ namespace Game.Entities
{ {
Aura aura = m_interruptableAuras[i].GetBase(); Aura aura = m_interruptableAuras[i].GetBase();
if (aura.GetSpellInfo().HasAuraInterruptFlag(flag) && (except == 0 || aura.GetId() != except) && !IsInterruptFlagIgnoredForSpell(flag, this, aura.GetSpellInfo())) if (aura.GetSpellInfo().HasAuraInterruptFlag(flag) && (source == null || aura.GetId() != source.Id) && !IsInterruptFlagIgnoredForSpell(flag, this, aura.GetSpellInfo(), source))
{ {
uint removedAuras = m_removedAurasCount; uint removedAuras = m_removedAurasCount;
RemoveAura(aura, AuraRemoveMode.Interrupt); RemoveAura(aura, AuraRemoveMode.Interrupt);
@@ -2857,15 +2890,15 @@ namespace Game.Entities
{ {
if (spell.GetState() == SpellState.Casting if (spell.GetState() == SpellState.Casting
&& spell.GetSpellInfo().HasChannelInterruptFlag(flag) && spell.GetSpellInfo().HasChannelInterruptFlag(flag)
&& spell.GetSpellInfo().Id != except && (source == null || spell.GetSpellInfo().Id != source.Id)
&& !IsInterruptFlagIgnoredForSpell(flag, this, spell.GetSpellInfo())) && !IsInterruptFlagIgnoredForSpell(flag, this, spell.GetSpellInfo(), source))
InterruptNonMeleeSpells(false); InterruptNonMeleeSpells(false);
} }
UpdateInterruptMask(); UpdateInterruptMask();
} }
public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2 flag, uint except = 0) public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2 flag, SpellInfo source = null)
{ {
if (!HasInterruptFlag(flag)) if (!HasInterruptFlag(flag))
return; return;
@@ -2875,7 +2908,7 @@ namespace Game.Entities
{ {
Aura aura = m_interruptableAuras[i].GetBase(); Aura aura = m_interruptableAuras[i].GetBase();
if (aura.GetSpellInfo().HasAuraInterruptFlag(flag) && (except == 0 || aura.GetId() != except) && !IsInterruptFlagIgnoredForSpell(flag, this, aura.GetSpellInfo())) if (aura.GetSpellInfo().HasAuraInterruptFlag(flag) && (source == null || aura.GetId() != source.Id) && !IsInterruptFlagIgnoredForSpell(flag, this, aura.GetSpellInfo(), source))
{ {
uint removedAuras = m_removedAurasCount; uint removedAuras = m_removedAurasCount;
RemoveAura(aura, AuraRemoveMode.Interrupt); RemoveAura(aura, AuraRemoveMode.Interrupt);
@@ -2890,8 +2923,8 @@ namespace Game.Entities
{ {
if (spell.GetState() == SpellState.Casting if (spell.GetState() == SpellState.Casting
&& spell.GetSpellInfo().HasChannelInterruptFlag(flag) && spell.GetSpellInfo().HasChannelInterruptFlag(flag)
&& spell.GetSpellInfo().Id != except && (source == null || spell.GetSpellInfo().Id != source.Id)
&& !IsInterruptFlagIgnoredForSpell(flag, this, spell.GetSpellInfo())) && !IsInterruptFlagIgnoredForSpell(flag, this, spell.GetSpellInfo(), source))
InterruptNonMeleeSpells(false); InterruptNonMeleeSpells(false);
} }
+3 -3
View File
@@ -2441,10 +2441,10 @@ namespace Game.Entities
if (spellProto != null) if (spellProto != null)
{ {
if (!spellProto.HasAttribute(SpellAttr4.DamageDoesntBreakAuras)) if (!spellProto.HasAttribute(SpellAttr4.DamageDoesntBreakAuras))
victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage, spellProto.Id); victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage, spellProto);
} }
else else
victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage, 0); victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage);
if (damage == 0 && damagetype != DamageEffectType.DOT && cleanDamage != null && cleanDamage.absorbed_damage != 0) if (damage == 0 && damagetype != DamageEffectType.DOT && cleanDamage != null && cleanDamage.absorbed_damage != 0)
{ {
@@ -2649,7 +2649,7 @@ namespace Game.Entities
victim.ModifyHealth(-(int)damage); victim.ModifyHealth(-(int)damage);
if (damagetype == DamageEffectType.Direct || damagetype == DamageEffectType.SpellDirect) if (damagetype == DamageEffectType.Direct || damagetype == DamageEffectType.SpellDirect)
victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.NonPeriodicDamage, spellProto != null ? spellProto.Id : 0); victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.NonPeriodicDamage, spellProto);
if (!victim.IsTypeId(TypeId.Player)) if (!victim.IsTypeId(TypeId.Player))
{ {
+37 -26
View File
@@ -698,7 +698,7 @@ namespace Game.Spells
{ {
if (m_timeCla > diff) if (m_timeCla > diff)
m_timeCla -= (int)diff; m_timeCla -= (int)diff;
else if (caster != null) else if (caster != null && (caster == GetOwner() || !GetSpellInfo().HasAttribute(SpellAttr2.NoTargetPerSecondCosts)))
{ {
if (!m_periodicCosts.Empty()) if (!m_periodicCosts.Empty())
{ {
@@ -1008,7 +1008,7 @@ namespace Game.Spells
{ {
return GetCasterGUID() == target.GetGUID() return GetCasterGUID() == target.GetGUID()
&& m_spellInfo.Stances != 0 && m_spellInfo.Stances != 0
&& !m_spellInfo.HasAttribute(SpellAttr2.NotNeedShapeshift) && !m_spellInfo.HasAttribute(SpellAttr2.AllowWhileNotShapeshiftedCasterForm)
&& !m_spellInfo.HasAttribute(SpellAttr0.NotShapeshifted); && !m_spellInfo.HasAttribute(SpellAttr0.NotShapeshifted);
} }
@@ -1644,9 +1644,19 @@ namespace Game.Spells
return m_procCooldown > now; return m_procCooldown > now;
} }
public void AddProcCooldown(DateTime cooldownEnd) public void AddProcCooldown(SpellProcEntry procEntry, DateTime now)
{ {
m_procCooldown = cooldownEnd; // cooldowns should be added to the whole aura (see 51698 area aura)
int procCooldown = (int)procEntry.Cooldown;
Unit caster = GetCaster();
if (caster != null)
{
Player modOwner = caster.GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(GetSpellInfo(), SpellModOp.ProcCooldown, ref procCooldown);
}
m_procCooldown = now + TimeSpan.FromMilliseconds(procCooldown);
} }
public void ResetProcCooldown() public void ResetProcCooldown()
@@ -1663,26 +1673,36 @@ namespace Game.Spells
SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(GetSpellInfo()); SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(GetSpellInfo());
Cypher.Assert(procEntry != null); Cypher.Assert(procEntry != null);
PrepareProcChargeDrop(procEntry, eventInfo);
// cooldowns should be added to the whole aura (see 51698 area aura)
AddProcCooldown(procEntry, now);
SetLastProcSuccessTime(now);
}
public void PrepareProcChargeDrop(SpellProcEntry procEntry, ProcEventInfo eventInfo)
{
// take one charge, aura expiration will be handled in Aura.TriggerProcOnEvent (if needed) // take one charge, aura expiration will be handled in Aura.TriggerProcOnEvent (if needed)
if (!procEntry.AttributesMask.HasAnyFlag(ProcAttributes.UseStacksForCharges) && IsUsingCharges() && (eventInfo.GetSpellInfo() == null || !eventInfo.GetSpellInfo().HasAttribute(SpellAttr6.DoNotConsumeResources))) if (!procEntry.AttributesMask.HasAnyFlag(ProcAttributes.UseStacksForCharges) && IsUsingCharges() && (eventInfo.GetSpellInfo() == null || !eventInfo.GetSpellInfo().HasAttribute(SpellAttr6.DoNotConsumeResources)))
{ {
--m_procCharges; --m_procCharges;
SetNeedClientUpdateForTargets(); SetNeedClientUpdateForTargets();
} }
// cooldowns should be added to the whole aura (see 51698 area aura)
int procCooldown = (int)procEntry.Cooldown;
Unit caster = GetCaster();
if (caster != null)
{
Player modOwner = caster.GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(GetSpellInfo(), SpellModOp.ProcCooldown, ref procCooldown);
} }
AddProcCooldown(now + TimeSpan.FromMilliseconds(procCooldown)); public void ConsumeProcCharges(SpellProcEntry procEntry)
{
SetLastProcSuccessTime(now); // Remove aura if we've used last charge to proc
if (procEntry.AttributesMask.HasFlag(ProcAttributes.UseStacksForCharges))
{
ModStackAmount(-1);
}
else if (IsUsingCharges())
{
if (GetCharges() == 0)
Remove();
}
} }
public uint GetProcEffectMask(AuraApplication aurApp, ProcEventInfo eventInfo, DateTime now) public uint GetProcEffectMask(AuraApplication aurApp, ProcEventInfo eventInfo, DateTime now)
@@ -1859,16 +1879,7 @@ namespace Game.Spells
CallScriptAfterProcHandlers(aurApp, eventInfo); CallScriptAfterProcHandlers(aurApp, eventInfo);
} }
// Remove aura if we've used last charge to proc ConsumeProcCharges(Global.SpellMgr.GetSpellProcEntry(GetSpellInfo()));
if (Global.SpellMgr.GetSpellProcEntry(m_spellInfo).AttributesMask.HasAnyFlag(ProcAttributes.UseStacksForCharges))
{
ModStackAmount(-1);
}
else if (IsUsingCharges())
{
if (GetCharges() == 0)
Remove();
}
} }
public float CalcPPMProcChance(Unit actor) public float CalcPPMProcChance(Unit actor)
+2 -6
View File
@@ -1308,7 +1308,7 @@ namespace Game.Spells
} }
if (!shapeInfo.Flags.HasAnyFlag(SpellShapeshiftFormFlags.Stance)) if (!shapeInfo.Flags.HasAnyFlag(SpellShapeshiftFormFlags.Stance))
target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Shapeshifting, GetId()); target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Shapeshifting, GetSpellInfo());
} }
else else
{ {
@@ -2837,7 +2837,7 @@ namespace Game.Spells
// remove all flag auras (they are positive, but they must be removed when you are immune) // remove all flag auras (they are positive, but they must be removed when you are immune)
if (GetSpellInfo().HasAttribute(SpellAttr1.ImmunityPurgesEffect) if (GetSpellInfo().HasAttribute(SpellAttr1.ImmunityPurgesEffect)
&& GetSpellInfo().HasAttribute(SpellAttr2.DamageReducedShield)) && GetSpellInfo().HasAttribute(SpellAttr2.FailOnAllTargetsImmune))
target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis); target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis);
} }
@@ -5206,10 +5206,6 @@ namespace Game.Spells
return; return;
} }
// heal for caster damage (must be alive)
if (target != caster && GetSpellInfo().HasAttribute(SpellAttr2.HealthFunnel) && (caster == null || !caster.IsAlive()))
return;
// don't regen when permanent aura target has full power // don't regen when permanent aura target has full power
if (GetBase().IsPermanent() && target.IsFullHealth()) if (GetBase().IsPermanent() && target.IsFullHealth())
return; return;
+64 -18
View File
@@ -95,6 +95,10 @@ namespace Game.Spells
m_spellState = SpellState.None; m_spellState = SpellState.None;
_triggeredCastFlags = triggerFlags; _triggeredCastFlags = triggerFlags;
if (info.HasAttribute(SpellAttr2.DoNotReportSpellFailure))
_triggeredCastFlags = _triggeredCastFlags | TriggerCastFlags.DontReportCastError;
if (m_spellInfo.HasAttribute(SpellAttr4.CanCastWhileCasting)) if (m_spellInfo.HasAttribute(SpellAttr4.CanCastWhileCasting))
_triggeredCastFlags = _triggeredCastFlags | TriggerCastFlags.IgnoreCastInProgress; _triggeredCastFlags = _triggeredCastFlags | TriggerCastFlags.IgnoreCastInProgress;
@@ -274,6 +278,35 @@ namespace Game.Spells
if (m_targets.HasDst()) if (m_targets.HasDst())
AddDestTarget(m_targets.GetDst(), spellEffectInfo.EffectIndex); AddDestTarget(m_targets.GetDst(), spellEffectInfo.EffectIndex);
if (spellEffectInfo.TargetA.GetObjectType() == SpellTargetObjectTypes.Unit
|| spellEffectInfo.TargetA.GetObjectType() == SpellTargetObjectTypes.UnitAndDest
|| spellEffectInfo.TargetB.GetObjectType() == SpellTargetObjectTypes.Unit
|| spellEffectInfo.TargetB.GetObjectType() == SpellTargetObjectTypes.UnitAndDest)
{
if (m_spellInfo.HasAttribute(SpellAttr1.RequireAllTargets))
{
bool noTargetFound = !m_UniqueTargetInfo.Any(target => (target.EffectMask & 1 << (int)spellEffectInfo.EffectIndex) != 0);
if (noTargetFound)
{
SendCastResult(m_spellInfo.Id == 51690 ? SpellCastResult.OutOfRange : SpellCastResult.BadTargets);
Finish(false);
return;
}
}
if (m_spellInfo.HasAttribute(SpellAttr2.FailOnAllTargetsImmune))
{
bool anyNonImmuneTargetFound = m_UniqueTargetInfo.Any(target => (target.EffectMask & 1 << (int)spellEffectInfo.EffectIndex) != 0 && target.MissCondition != SpellMissInfo.Immune && target.MissCondition != SpellMissInfo.Immune2);
if (!anyNonImmuneTargetFound)
{
SendCastResult(SpellCastResult.Immune);
Finish(false);
return;
}
}
}
if (m_spellInfo.IsChanneled()) if (m_spellInfo.IsChanneled())
{ {
// maybe do this for all spells? // maybe do this for all spells?
@@ -1621,8 +1654,9 @@ namespace Game.Spells
if (isBouncingFar) if (isBouncingFar)
searchRadius *= chainTargets; searchRadius *= chainTargets;
WorldObject chainSource = m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster) ? m_caster : target;
List<WorldObject> tempTargets = new(); List<WorldObject> tempTargets = new();
SearchAreaTargets(tempTargets, searchRadius, target.GetPosition(), m_caster, objectType, selectType, condList); SearchAreaTargets(tempTargets, searchRadius, chainSource, m_caster, objectType, selectType, condList);
tempTargets.Remove(target); tempTargets.Remove(target);
// remove targets which are always invalid for chain spells // remove targets which are always invalid for chain spells
@@ -1651,7 +1685,7 @@ namespace Game.Spells
if (unitTarget != null) if (unitTarget != null)
{ {
uint deficit = (uint)(unitTarget.GetMaxHealth() - unitTarget.GetHealth()); uint deficit = (uint)(unitTarget.GetMaxHealth() - unitTarget.GetHealth());
if ((deficit > maxHPDeficit || found == null) && target.IsWithinDist(unitTarget, jumpRadius) && target.IsWithinLOSInMap(unitTarget, LineOfSightChecks.All, ModelIgnoreFlags.M2)) if ((deficit > maxHPDeficit || found == null) && chainSource.IsWithinDist(unitTarget, jumpRadius) && chainSource.IsWithinLOSInMap(unitTarget, LineOfSightChecks.All, ModelIgnoreFlags.M2))
{ {
found = obj; found = obj;
maxHPDeficit = deficit; maxHPDeficit = deficit;
@@ -1666,19 +1700,22 @@ namespace Game.Spells
{ {
if (found == null) if (found == null)
{ {
if ((!isBouncingFar || target.IsWithinDist(obj, jumpRadius)) && target.IsWithinLOSInMap(obj, LineOfSightChecks.All, ModelIgnoreFlags.M2)) if ((!isBouncingFar || chainSource.IsWithinDist(obj, jumpRadius)) && chainSource.IsWithinLOSInMap(obj, LineOfSightChecks.All, ModelIgnoreFlags.M2))
found = obj; found = obj;
} }
else if (target.GetDistanceOrder(obj, found) && target.IsWithinLOSInMap(obj, LineOfSightChecks.All, ModelIgnoreFlags.M2)) else if (chainSource.GetDistanceOrder(obj, found) && chainSource.IsWithinLOSInMap(obj, LineOfSightChecks.All, ModelIgnoreFlags.M2))
found = obj; found = obj;
} }
} }
// not found any valid target - chain ends // not found any valid target - chain ends
if (found == null) if (found == null)
break; break;
target = found;
if (!m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster))
chainSource = found;
targets.Add(found);
tempTargets.Remove(found); tempTargets.Remove(found);
targets.Add(target);
--chainTargets; --chainTargets;
} }
} }
@@ -1712,7 +1749,7 @@ namespace Game.Spells
break; break;
case SpellDmgClass.Ranged: case SpellDmgClass.Ranged:
// Auto attack // Auto attack
if (m_spellInfo.HasAttribute(SpellAttr2.AutorepeatFlag)) if (m_spellInfo.HasAttribute(SpellAttr2.AutoRepeat))
{ {
m_procAttacker = new ProcFlagsInit(ProcFlags.DealRangedAttack); m_procAttacker = new ProcFlagsInit(ProcFlags.DealRangedAttack);
m_procVictim = new ProcFlagsInit(ProcFlags.TakeRangedAttack); m_procVictim = new ProcFlagsInit(ProcFlags.TakeRangedAttack);
@@ -1726,7 +1763,7 @@ namespace Game.Spells
default: default:
if (m_spellInfo.EquippedItemClass == ItemClass.Weapon && if (m_spellInfo.EquippedItemClass == ItemClass.Weapon &&
Convert.ToBoolean(m_spellInfo.EquippedItemSubClassMask & (1 << (int)ItemSubClassWeapon.Wand)) Convert.ToBoolean(m_spellInfo.EquippedItemSubClassMask & (1 << (int)ItemSubClassWeapon.Wand))
&& m_spellInfo.HasAttribute(SpellAttr2.AutorepeatFlag)) // Wands auto attack && m_spellInfo.HasAttribute(SpellAttr2.AutoRepeat)) // Wands auto attack
{ {
m_procAttacker = new ProcFlagsInit(ProcFlags.DealRangedAttack); m_procAttacker = new ProcFlagsInit(ProcFlags.DealRangedAttack);
m_procVictim = new ProcFlagsInit(ProcFlags.TakeRangedAttack); m_procVictim = new ProcFlagsInit(ProcFlags.TakeRangedAttack);
@@ -2488,8 +2525,8 @@ namespace Game.Spells
{ {
// stealth must be removed at cast starting (at show channel bar) // stealth must be removed at cast starting (at show channel bar)
// skip triggered spell (item equip spell casting and other not explicit character casts/item uses) // skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && m_spellInfo.IsBreakingStealth() && !m_spellInfo.HasAttribute(SpellAttr2.IgnoreActionAuraInterruptFlags)) if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && !m_spellInfo.HasAttribute(SpellAttr2.NotAnAction))
unitCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Action); unitCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Action, m_spellInfo);
// Do not register as current spell when requested to ignore cast in progress // Do not register as current spell when requested to ignore cast in progress
// We don't want to interrupt that other spell with cast time // We don't want to interrupt that other spell with cast time
@@ -2903,8 +2940,8 @@ namespace Game.Spells
if (!hitMask.HasAnyFlag(ProcFlagsHit.Critical)) if (!hitMask.HasAnyFlag(ProcFlagsHit.Critical))
hitMask |= ProcFlagsHit.Normal; hitMask |= ProcFlagsHit.Normal;
if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && !m_spellInfo.HasAttribute(SpellAttr2.IgnoreActionAuraInterruptFlags)) if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && !m_spellInfo.HasAttribute(SpellAttr2.NotAnAction))
m_originalCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ActionDelayed); m_originalCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ActionDelayed, m_spellInfo);
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);
@@ -3340,7 +3377,7 @@ namespace Game.Spells
if (IsAutoActionResetSpell()) if (IsAutoActionResetSpell())
{ {
if (!m_spellInfo.HasAttribute(SpellAttr2.NotResetAutoActions)) if (!m_spellInfo.HasAttribute(SpellAttr2.DoNotResetCombatTimers))
{ {
unitCaster.ResetAttackTimer(WeaponAttackType.BaseAttack); unitCaster.ResetAttackTimer(WeaponAttackType.BaseAttack);
if (unitCaster.HaveOffhandWeapon()) if (unitCaster.HaveOffhandWeapon())
@@ -4566,7 +4603,7 @@ namespace Game.Spells
if (m_spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot) if (m_spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot)
|| m_spellInfo.IsNextMeleeSwingSpell() || m_spellInfo.IsNextMeleeSwingSpell()
|| m_spellInfo.HasAttribute(SpellAttr1.InitiatesCombatEnablesAutoAttack) || m_spellInfo.HasAttribute(SpellAttr1.InitiatesCombatEnablesAutoAttack)
|| m_spellInfo.HasAttribute(SpellAttr2.Unk20) || m_spellInfo.HasAttribute(SpellAttr2.InitiateCombatPostCastEnablesAutoAttack)
|| m_spellInfo.HasEffect(SpellEffectName.Attack) || m_spellInfo.HasEffect(SpellEffectName.Attack)
|| m_spellInfo.HasEffect(SpellEffectName.NormalizedWeaponDmg) || m_spellInfo.HasEffect(SpellEffectName.NormalizedWeaponDmg)
|| m_spellInfo.HasEffect(SpellEffectName.WeaponDamageNoSchool) || m_spellInfo.HasEffect(SpellEffectName.WeaponDamageNoSchool)
@@ -4787,7 +4824,7 @@ namespace Game.Spells
losTarget = dynObj; losTarget = dynObj;
} }
if (!m_spellInfo.HasAttribute(SpellAttr2.CanTargetNotInLos) && !m_spellInfo.HasAttribute(SpellAttr5.AlwaysAoeLineOfSight) && !Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, (byte)DisableFlags.SpellLOS) if (!m_spellInfo.HasAttribute(SpellAttr2.IgnoreLineOfSight) && !m_spellInfo.HasAttribute(SpellAttr5.AlwaysAoeLineOfSight) && !Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, (byte)DisableFlags.SpellLOS)
&& !unitTarget.IsWithinLOSInMap(losTarget, LineOfSightChecks.All, ModelIgnoreFlags.M2)) && !unitTarget.IsWithinLOSInMap(losTarget, LineOfSightChecks.All, ModelIgnoreFlags.M2))
return SpellCastResult.LineOfSight; return SpellCastResult.LineOfSight;
} }
@@ -4800,7 +4837,7 @@ namespace Game.Spells
float x, y, z; float x, y, z;
m_targets.GetDstPos().GetPosition(out x, out y, out z); m_targets.GetDstPos().GetPosition(out x, out y, out z);
if (!m_spellInfo.HasAttribute(SpellAttr2.CanTargetNotInLos) && !m_spellInfo.HasAttribute(SpellAttr5.AlwaysAoeLineOfSight) && !Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, (byte)DisableFlags.SpellLOS) if (!m_spellInfo.HasAttribute(SpellAttr2.IgnoreLineOfSight) && !m_spellInfo.HasAttribute(SpellAttr5.AlwaysAoeLineOfSight) && !Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, (byte)DisableFlags.SpellLOS)
&& !m_caster.IsWithinLOS(x, y, z, LineOfSightChecks.All, ModelIgnoreFlags.M2)) && !m_caster.IsWithinLOS(x, y, z, LineOfSightChecks.All, ModelIgnoreFlags.M2))
return SpellCastResult.LineOfSight; return SpellCastResult.LineOfSight;
} }
@@ -4808,6 +4845,10 @@ namespace Game.Spells
// check pet presence // check pet presence
if (unitCaster != null) if (unitCaster != null)
{ {
if (m_spellInfo.HasAttribute(SpellAttr2.NoActivePets))
if (!unitCaster.GetPetGUID().IsEmpty())
return SpellCastResult.AlreadyHavePet;
foreach (var spellEffectInfo in m_spellInfo.GetEffects()) foreach (var spellEffectInfo in m_spellInfo.GetEffects())
{ {
if (spellEffectInfo.TargetA.GetTarget() == Targets.UnitPet) if (spellEffectInfo.TargetA.GetTarget() == Targets.UnitPet)
@@ -5697,6 +5738,9 @@ namespace Game.Spells
if (m_CastItem != null) if (m_CastItem != null)
return SpellCastResult.ItemEnchantTradeWindow; return SpellCastResult.ItemEnchantTradeWindow;
if (m_spellInfo.HasAttribute(SpellAttr2.EnchantOwnItemOnly))
return SpellCastResult.ItemEnchantTradeWindow;
if (!m_caster.IsTypeId(TypeId.Player)) if (!m_caster.IsTypeId(TypeId.Player))
return SpellCastResult.NotTrading; return SpellCastResult.NotTrading;
@@ -6964,7 +7008,7 @@ namespace Game.Spells
} }
// check for ignore LOS on the effect itself // check for ignore LOS on the effect itself
if (m_spellInfo.HasAttribute(SpellAttr2.CanTargetNotInLos) || Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, (byte)DisableFlags.SpellLOS)) if (m_spellInfo.HasAttribute(SpellAttr2.IgnoreLineOfSight) || Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, (byte)DisableFlags.SpellLOS))
return true; return true;
// check if gameobject ignores LOS // check if gameobject ignores LOS
@@ -6974,7 +7018,7 @@ namespace Game.Spells
return true; return true;
// if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour // if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour
if (IsTriggered() && m_triggeredByAuraSpell != null && (m_triggeredByAuraSpell.HasAttribute(SpellAttr2.CanTargetNotInLos) || Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_triggeredByAuraSpell.Id, null, (byte)DisableFlags.SpellLOS))) if (IsTriggered() && m_triggeredByAuraSpell != null && (m_triggeredByAuraSpell.HasAttribute(SpellAttr2.IgnoreLineOfSight) || Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_triggeredByAuraSpell.Id, null, (byte)DisableFlags.SpellLOS)))
return true; return true;
// @todo shit below shouldn't be here, but it's temporary // @todo shit below shouldn't be here, but it's temporary
@@ -9052,6 +9096,7 @@ namespace Game.Spells
{ {
public TriggerCastFlags TriggerFlags; public TriggerCastFlags TriggerFlags;
public Item CastItem; public Item CastItem;
public Spell TriggeringSpell;
public AuraEffect TriggeringAura; public AuraEffect TriggeringAura;
public ObjectGuid OriginalCaster = ObjectGuid.Empty; public ObjectGuid OriginalCaster = ObjectGuid.Empty;
public Difficulty CastDifficulty; public Difficulty CastDifficulty;
@@ -9113,6 +9158,7 @@ namespace Game.Spells
public CastSpellExtraArgs SetTriggeringSpell(Spell triggeringSpell) public CastSpellExtraArgs SetTriggeringSpell(Spell triggeringSpell)
{ {
TriggeringSpell = triggeringSpell;
if (triggeringSpell != null) if (triggeringSpell != null)
{ {
OriginalCastItemLevel = triggeringSpell.m_castItemLevel; OriginalCastItemLevel = triggeringSpell.m_castItemLevel;
+13 -5
View File
@@ -305,18 +305,26 @@ namespace Game.Spells
if (effectInfo.Effect == SpellEffectName.TriggerSpell) if (effectInfo.Effect == SpellEffectName.TriggerSpell)
delay = TimeSpan.FromMilliseconds(effectInfo.MiscValue); delay = TimeSpan.FromMilliseconds(effectInfo.MiscValue);
m_caster.m_Events.AddEventAtOffset(() =>
{
// original caster guid only for GO cast
CastSpellExtraArgs args = new(TriggerCastFlags.FullMask); CastSpellExtraArgs args = new(TriggerCastFlags.FullMask);
args.SetOriginalCaster(m_originalCasterGUID); args.SetOriginalCaster(m_originalCasterGUID);
args.SetTriggeringSpell(this); args.OriginalCastId = m_castId;
args.OriginalCastItemLevel = m_castItemLevel;
if (!m_castItemGUID.IsEmpty() && Global.SpellMgr.GetSpellInfo(effectInfo.TriggerSpell, m_caster.GetMap().GetDifficultyID()).HasAttribute(SpellAttr2.RetainItemCast))
{
Player triggeringAuraCaster = args.TriggeringAura.GetCaster()?.ToPlayer();
if (triggeringAuraCaster != null)
args.CastItem = triggeringAuraCaster.GetItemByGuid(m_castItemGUID);
}
// set basepoints for trigger with value effect // set basepoints for trigger with value effect
if (effectInfo.Effect == SpellEffectName.TriggerSpellWithValue) if (effectInfo.Effect == SpellEffectName.TriggerSpellWithValue)
for (int i = 0; i < SpellConst.MaxEffects; ++i) for (int i = 0; i < SpellConst.MaxEffects; ++i)
args.AddSpellMod(SpellValueMod.BasePoint0 + i, damage); args.AddSpellMod(SpellValueMod.BasePoint0 + i, damage);
m_caster.m_Events.AddEventAtOffset(() => m_caster.CastSpell(targets, effectInfo.TriggerSpell, args);
{
// original caster guid only for GO cast
m_caster.CastSpell(targets, triggered_spell_id, args);
}, delay); }, delay);
} }
+11 -16
View File
@@ -499,7 +499,7 @@ namespace Game.Spells
public bool IsAllowingDeadTarget() public bool IsAllowingDeadTarget()
{ {
if (HasAttribute(SpellAttr2.CanTargetDead) || Targets.HasAnyFlag(SpellCastTargetFlags.CorpseAlly | SpellCastTargetFlags.CorpseEnemy | SpellCastTargetFlags.UnitDead)) if (HasAttribute(SpellAttr2.AllowDeadTarget) || Targets.HasAnyFlag(SpellCastTargetFlags.CorpseAlly | SpellCastTargetFlags.CorpseEnemy | SpellCastTargetFlags.UnitDead))
return true; return true;
foreach (var effectInfo in _effects) foreach (var effectInfo in _effects)
@@ -566,11 +566,6 @@ namespace Game.Spells
return HasAttribute(SpellAttr0.OnNextSwingNoDamage | SpellAttr0.OnNextSwing); return HasAttribute(SpellAttr0.OnNextSwingNoDamage | SpellAttr0.OnNextSwing);
} }
public bool IsBreakingStealth()
{
return !HasAttribute(SpellAttr1.AllowWhileStealthed);
}
public bool IsRangedWeaponSpell() public bool IsRangedWeaponSpell()
{ {
return (SpellFamilyName == SpellFamilyNames.Hunter && !SpellFamilyFlags[1].HasAnyFlag(0x10000000u)) // for 53352, cannot find better way return (SpellFamilyName == SpellFamilyNames.Hunter && !SpellFamilyFlags[1].HasAnyFlag(0x10000000u)) // for 53352, cannot find better way
@@ -580,12 +575,12 @@ namespace Game.Spells
public bool IsAutoRepeatRangedSpell() public bool IsAutoRepeatRangedSpell()
{ {
return HasAttribute(SpellAttr2.AutorepeatFlag); return HasAttribute(SpellAttr2.AutoRepeat);
} }
public bool HasInitialAggro() public bool HasInitialAggro()
{ {
return !(HasAttribute(SpellAttr1.NoThreat) || HasAttribute(SpellAttr3.NoInitialAggro)); return !(HasAttribute(SpellAttr1.NoThreat) || HasAttribute(SpellAttr2.NoInitialThreat));
} }
public bool HasHitDelay() public bool HasHitDelay()
@@ -689,7 +684,7 @@ namespace Game.Spells
return true; return true;
// these spells (Cyclone for example) can pierce all... // these spells (Cyclone for example) can pierce all...
if (HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) || HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) if (HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) || HasAttribute(SpellAttr2.NoSchoolImmunities))
{ {
// ...but not these (Divine shield, Ice block, Cyclone and Banish for example) // ...but not these (Divine shield, Ice block, Cyclone and Banish for example)
if (auraSpellInfo.Mechanic != Mechanics.ImmuneShield && if (auraSpellInfo.Mechanic != Mechanics.ImmuneShield &&
@@ -717,7 +712,7 @@ namespace Game.Spells
// These auras (Cyclone for example) are not dispelable // These auras (Cyclone for example) are not dispelable
if ((auraSpellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) && auraSpellInfo.Mechanic != Mechanics.None) if ((auraSpellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) && auraSpellInfo.Mechanic != Mechanics.None)
|| auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) || auraSpellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities))
return false; return false;
return true; return true;
@@ -835,7 +830,7 @@ namespace Game.Spells
else else
{ {
// needs shapeshift // needs shapeshift
if (!HasAttribute(SpellAttr2.NotNeedShapeshift) && Stances != 0) if (!HasAttribute(SpellAttr2.AllowWhileNotShapeshiftedCasterForm) && Stances != 0)
return SpellCastResult.OnlyShapeshift; return SpellCastResult.OnlyShapeshift;
} }
@@ -1043,7 +1038,7 @@ namespace Game.Spells
if (caster.IsTypeId(TypeId.Player)) if (caster.IsTypeId(TypeId.Player))
{ {
// Do not allow these spells to target creatures not tapped by us (Banish, Polymorph, many quest spells) // Do not allow these spells to target creatures not tapped by us (Banish, Polymorph, many quest spells)
if (HasAttribute(SpellAttr2.CantTargetTapped)) if (HasAttribute(SpellAttr2.CannotCastOnTapped))
{ {
Creature targetCreature = unitTarget.ToCreature(); Creature targetCreature = unitTarget.ToCreature();
if (targetCreature != null) if (targetCreature != null)
@@ -2509,7 +2504,7 @@ namespace Game.Spells
ImmunityInfo immuneInfo = effectInfo.GetImmunityInfo(); ImmunityInfo immuneInfo = effectInfo.GetImmunityInfo();
if (!auraSpellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) && !auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) if (!auraSpellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) && !auraSpellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities))
{ {
uint schoolImmunity = immuneInfo.SchoolImmuneMask; uint schoolImmunity = immuneInfo.SchoolImmuneMask;
if (schoolImmunity != 0) if (schoolImmunity != 0)
@@ -2558,7 +2553,7 @@ namespace Game.Spells
if (!immuneInfo.AuraTypeImmune.Contains(auraName)) if (!immuneInfo.AuraTypeImmune.Contains(auraName))
isImmuneToAuraEffectApply = true; isImmuneToAuraEffectApply = true;
if (!isImmuneToAuraEffectApply && !auraSpellInfo.IsPositiveEffect(auraSpellEffectInfo.EffectIndex) && !auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) if (!isImmuneToAuraEffectApply && !auraSpellInfo.IsPositiveEffect(auraSpellEffectInfo.EffectIndex) && !auraSpellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities))
{ {
uint applyHarmfulAuraImmunityMask = immuneInfo.ApplyHarmfulAuraImmuneMask; uint applyHarmfulAuraImmunityMask = immuneInfo.ApplyHarmfulAuraImmuneMask;
if (applyHarmfulAuraImmunityMask != 0) if (applyHarmfulAuraImmunityMask != 0)
@@ -2604,7 +2599,7 @@ namespace Game.Spells
break; break;
case AuraType.SchoolImmunity: case AuraType.SchoolImmunity:
case AuraType.ModImmuneAuraApplySchool: case AuraType.ModImmuneAuraApplySchool:
if (aurEff.GetSpellInfo().HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune) || !Convert.ToBoolean((uint)aurEff.GetSpellInfo().SchoolMask & miscValue)) if (aurEff.GetSpellInfo().HasAttribute(SpellAttr2.NoSchoolImmunities) || !Convert.ToBoolean((uint)aurEff.GetSpellInfo().SchoolMask & miscValue))
continue; continue;
break; break;
case AuraType.DispelImmunity: case AuraType.DispelImmunity:
@@ -3180,7 +3175,7 @@ namespace Game.Spells
return this; return this;
// Client ignores spell with these attributes (sub_53D9D0) // Client ignores spell with these attributes (sub_53D9D0)
if (HasAttribute(SpellAttr0.AuraIsDebuff) || HasAttribute(SpellAttr2.Unk3) || HasAttribute(SpellAttr3.DrainSoul)) if (HasAttribute(SpellAttr0.AuraIsDebuff) || HasAttribute(SpellAttr2.AllowLowLevelBuff) || HasAttribute(SpellAttr3.DrainSoul))
return this; return this;
bool needRankSelection = false; bool needRankSelection = false;
+3 -3
View File
@@ -4098,7 +4098,7 @@ namespace Game.Entities
ApplySpellFix(new[] { 75509 }, spellInfo => ApplySpellFix(new[] { 75509 }, spellInfo =>
{ {
spellInfo.AttributesEx6 |= SpellAttr6.CanTargetInvisible; spellInfo.AttributesEx6 |= SpellAttr6.CanTargetInvisible;
spellInfo.AttributesEx2 |= SpellAttr2.CanTargetNotInLos; spellInfo.AttributesEx2 |= SpellAttr2.IgnoreLineOfSight;
}); });
// Awaken Flames // Awaken Flames
@@ -4122,7 +4122,7 @@ namespace Game.Entities
{ {
// All spells work even without these changes. The LOS attribute is due to problem // All spells work even without these changes. The LOS attribute is due to problem
// from collision between maps & gos with active destroyed state. // from collision between maps & gos with active destroyed state.
spellInfo.AttributesEx2 |= SpellAttr2.CanTargetNotInLos; spellInfo.AttributesEx2 |= SpellAttr2.IgnoreLineOfSight;
}); });
// Arcane Barrage (cast by players and NONMELEEDAMAGELOG with caster Scion of Eternity (original caster)). // Arcane Barrage (cast by players and NONMELEEDAMAGELOG with caster Scion of Eternity (original caster)).
@@ -4261,7 +4261,7 @@ namespace Game.Entities
ApplySpellFix(new[] { 42525 }, spellInfo => ApplySpellFix(new[] { 42525 }, spellInfo =>
{ {
spellInfo.AttributesEx3 |= SpellAttr3.DeathPersistent; spellInfo.AttributesEx3 |= SpellAttr3.DeathPersistent;
spellInfo.AttributesEx2 |= SpellAttr2.CanTargetDead; spellInfo.AttributesEx2 |= SpellAttr2.AllowDeadTarget;
}); });
// Soul Sickness (Forge of Souls) // Soul Sickness (Forge of Souls)
+3 -5
View File
@@ -1175,11 +1175,9 @@ namespace Scripts.Spells.Shaman
caster.m_Events.AddEventAtOffset(() => caster.m_Events.AddEventAtOffset(() =>
{ {
var targets = new CastSpellTargetArg(procInfo.GetProcTarget()); CastSpellExtraArgs args = new();
var overloadSpellId = GetTriggeredSpellId(procInfo.GetSpellInfo().Id); args.OriginalCastId = procInfo.GetProcSpell().m_castId;
var args = new CastSpellExtraArgs(procInfo.GetProcSpell()); caster.CastSpell(new CastSpellTargetArg(procInfo.GetProcTarget()), GetTriggeredSpellId(procInfo.GetSpellInfo().Id), args);
caster.CastSpell(targets, overloadSpellId, args);
}, TimeSpan.FromMilliseconds(400)); }, TimeSpan.FromMilliseconds(400));
} }