Core/Spells: Named and implemented most of SpellAttr8

Port From (https://github.com/TrinityCore/TrinityCore/commit/dc9361fcc2eb16a59b52dfd8b0d47dfc1bf639be)
This commit is contained in:
hondacrx
2024-02-01 18:59:34 -05:00
parent e37c9558ad
commit 5869fbaee0
10 changed files with 232 additions and 87 deletions
+40 -32
View File
@@ -1927,38 +1927,38 @@ namespace Framework.Constants
}
public enum SpellAttr8 : uint
{
CantMiss = 0x01, // 0
Unk1 = 0x02, // 1
Unk2 = 0x04, // 2
Unk3 = 0x08, // 3
Unk4 = 0x10, // 4
Unk5 = 0x20, // 5
Unk6 = 0x40, // 6
Unk7 = 0x80, // 7
AffectPartyAndRaid = 0x100, // 8
PeriodicCanCrit = 0x200, // 9
NameChangedDuringTransofrm = 0x400, // 10
Unk11 = 0x800, // 11
AuraSendAmount = 0x1000, // 12 Aura Must Have Flag AflagAnyEffectAmountSent To Send Amount
Unk13 = 0x2000, // 13
Unk14 = 0x4000, // 14
WaterMount = 0x8000, // 15
Unk16 = 0x10000, // 16
HasteAffectsDuration = 0x20000, // 17 Haste Affects Duration
RememberSpells = 0x40000, // 18
UseComboPointsOnAnyTarget = 0x80000, // 19
ArmorSpecialization = 0x100000, // 20
Unk21 = 0x200000, // 21
Unk22 = 0x400000, // 22
BattleResurrection = 0x800000, // 23
HealingSpell = 0x1000000, // 24
Unk25 = 0x2000000, // 25
RaidMarker = 0x4000000, // 26 Probably Spell No Need Learn To Cast
Unk27 = 0x8000000, // 27
NotInBgOrArena = 0x10000000, // 28
MasteryAffectPoints = 0x20000000, // 29
Unk30 = 0x40000000, // 30
AttackIgnoreImmuneToPCFlag = 0x80000000 // 31
NoAttackBlock = 0x01, // No Attack Block
IgnoreDynamicObjectCaster = 0x02, /*Nyi*/ // Ignore Dynamic Object Caster
RemoveOutsideDungeonsAndRaids = 0x04, // Remove Outside Dungeons And Raids
OnlyTargetIfSameCreator = 0x08, // Only Target If Same Creator
CanHitAoeUntargetable = 0x10, /*Nyi - No Aoe Immunity Implementation*/ // Can Hit Aoe Untargetable
AllowWhileCharmed = 0x20, /*Nyi - Not Implementable Currently, Charming Replaces Ai*/ // Allow While Charmed
AuraRequiredByClient = 0x40, /*Nyi - We Send All Auras To Client*/ // Aura Required By Client
IgnoreSanctuary = 0x80, // Ignore Sanctuary
UseTargetsLevelForSpellScaling = 0x100, // Use Target'S Level For Spell Scaling
PeriodicCanCrit = 0x200, // Periodic Can Crit
MirrorCreatureName = 0x400, // Mirror Creature Name Description Transform Auras Also Override Name (Handled Clientside)
OnlyPlayersCanCastThisSpell = 0x800, // Only Players Can Cast This Spell
AuraPointsOnClient = 0x1000, // Aura Points On Client
NotInSpellbookUntilLearned = 0x2000, // Not In Spellbook Until Learned Description Hides Autolearned Spell From Spellbook Before Learning (Handled Clientside)
TargetProcsOnCaster = 0x4000, // Target Procs On Caster Description Target (Taken) Procs Happen On Caster (Actor) Instead Of Aura Target (Action Target)
RequiresLocationToBeOnLiquidSurface = 0x8000, // Requires Location To Be On Liquid Surface
OnlyTargetOwnSummons = 0x10000, // Only Target Own Summons
HasteAffectsDuration = 0x20000, // Haste Affects Duration
IgnoreSpellcastOverrideCost = 0x40000, // Ttile Ignore Spellcast Override Cost
AllowTargetsHiddenBySpawnTracking = 0x80000, /*Nyi - No Spawn Tracking Implementation*/ // Allow Targets Hidden By Spawn Tracking
RequiresEquippedInvTypes = 0x100000, // Requires Equipped Inv Types
NoSummonDestFromClientTargetingPathingRequirement = 0x200000, /*Nyi - Vald Path To A Spell Dest Is Not Required Currently If The Dest Comes From Client*/ // No 'Summon + Dest From Client' Targeting Pathing Requirement
MeleeHasteAffectsPeriodic = 0x400000, // Melee Haste Affects Periodic
EnforceInCombatRessurectionLimit = 0x800000, // Enforce In Combat Ressurection Limit Description Used To Limit The Number Of Resurrections In Boss Encounters
HealPrediction = 0x1000000, // Heal Prediction
NoLevelUpToast = 0x2000000, // No Level Up Toast
SkipIsKnownCheck = 0x4000000, // Skip Is Known Check
AiFaceTarget = 0x8000000, /*Nyi - Unknown Facing Conditions, Needs Research*/ // Ai Face Target
NotInBattleground = 0x10000000, // Not In Battleground
MasteryAffectsPoints = 0x20000000, // Mastery Affects Points
DisplayLargeAuraIconOnUnitFramesBossAura = 0x40000000, // Display Large Aura Icon On Unit Frames (Boss Aura)
AttackIgnoreImmuneToPcFlag = 0x80000000 // Can Attack Immunepc Description Do Not Check UnitFlagImmuneToPc In Isvalidattacktarget
}
public enum SpellAttr9 : uint
{
@@ -2973,4 +2973,12 @@ namespace Framework.Constants
TargetA = 0,
TargetB = 1
}
public enum SpellHealPredictionType : byte
{
Target = 0,
TargetAndCaster = 1,
TargetAndBeacon = 2,
TargetParty = 3,
}
}
+7 -6
View File
@@ -2004,7 +2004,7 @@ namespace Game.Entities
if (spellInfo == null || duration < 0)
return;
if (spellInfo.IsChanneled() && !spellInfo.HasAttribute(SpellAttr5.SpellHasteAffectsPeriodic))
if (spellInfo.IsChanneled() && !spellInfo.HasAttribute(SpellAttr5.SpellHasteAffectsPeriodic) && !spellInfo.HasAttribute(SpellAttr8.MeleeHasteAffectsPeriodic))
return;
// called from caster
@@ -2594,7 +2594,7 @@ namespace Game.Entities
if (!unitTarget.HasUnitFlag(UnitFlags.PlayerControlled) && unitOrOwner.IsImmuneToNPC())
return false;
if (bySpell == null || !bySpell.HasAttribute(SpellAttr8.AttackIgnoreImmuneToPCFlag))
if (bySpell == null || !bySpell.HasAttribute(SpellAttr8.AttackIgnoreImmuneToPcFlag))
{
if (unitOrOwner.HasUnitFlag(UnitFlags.PlayerControlled) && unitTarget.IsImmuneToPC())
return false;
@@ -2664,7 +2664,8 @@ namespace Game.Entities
// PvP case - can't attack when attacker or target are in sanctuary
// however, 13850 client doesn't allow to attack when one of the unit's has sanctuary flag and is pvp
if (unitTarget != null && unitTarget.HasUnitFlag(UnitFlags.PlayerControlled) && unitOrOwner != null && unitOrOwner.HasUnitFlag(UnitFlags.PlayerControlled) && (unitTarget.IsInSanctuary() || unitOrOwner.IsInSanctuary()))
if (unitTarget != null && unitTarget.HasUnitFlag(UnitFlags.PlayerControlled) && unitOrOwner != null && unitOrOwner.HasUnitFlag(UnitFlags.PlayerControlled)
&& (unitTarget.IsInSanctuary() || unitOrOwner.IsInSanctuary()) && (bySpell == null || bySpell.HasAttribute(SpellAttr8.IgnoreSanctuary)))
return false;
// additional checks - only PvP case
@@ -2738,7 +2739,7 @@ namespace Game.Entities
{
if (unit != null && unit.HasUnitFlag(UnitFlags.PlayerControlled))
{
if (bySpell == null || !bySpell.HasAttribute(SpellAttr8.AttackIgnoreImmuneToPCFlag))
if (bySpell == null || !bySpell.HasAttribute(SpellAttr8.AttackIgnoreImmuneToPcFlag))
if (unitTarget != null && unitTarget.IsImmuneToPC())
return false;
}
@@ -2771,7 +2772,7 @@ namespace Game.Entities
return false;
// can't assist player out of sanctuary from sanctuary if has pvp enabled
if (unitTarget.IsPvP())
if (unitTarget.IsPvP() && (bySpell == null || bySpell.HasAttribute(SpellAttr8.IgnoreSanctuary)))
if (unit.IsInSanctuary() && !unitTarget.IsInSanctuary())
return false;
}
@@ -2836,7 +2837,7 @@ namespace Game.Entities
{
return spellInfo.GetSpellXSpellVisualId(this);
}
public List<GameObject> GetGameObjectListWithEntryInGrid(uint entry = 0, float maxSearchRange = 250.0f)
{
List<GameObject> gameobjectList = new();
+4 -4
View File
@@ -274,7 +274,7 @@ namespace Game.Entities
return false;
}
public override SpellInfo GetCastSpellInfo(SpellInfo spellInfo)
public override SpellInfo GetCastSpellInfo(SpellInfo spellInfo, TriggerCastFlags triggerFlag)
{
var overrides = m_overrideSpells.LookupByKey(spellInfo.Id);
if (!overrides.Empty())
@@ -283,11 +283,11 @@ namespace Game.Entities
{
SpellInfo newInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID());
if (newInfo != null)
return GetCastSpellInfo(newInfo);
return GetCastSpellInfo(newInfo, triggerFlag);
}
}
return base.GetCastSpellInfo(spellInfo);
return base.GetCastSpellInfo(spellInfo, triggerFlag);
}
public void SetOverrideSpellsId(uint overrideSpellsId) { SetUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.OverrideSpellsID), overrideSpellsId); }
@@ -1778,7 +1778,7 @@ namespace Game.Entities
}
case ItemClass.Armor:
{
if (!spellInfo.HasAttribute(SpellAttr8.ArmorSpecialization))
if (!spellInfo.HasAttribute(SpellAttr8.RequiresEquippedInvTypes))
{
// most used check: shield only
if ((spellInfo.EquippedItemSubClassMask & (1 << (int)ItemSubClassArmor.Shield)) != 0)
+8 -2
View File
@@ -774,7 +774,7 @@ namespace Game.Entities
bool canDodge = !spellInfo.HasAttribute(SpellAttr7.NoAttackDodge);
bool canParry = !spellInfo.HasAttribute(SpellAttr7.NoAttackParry);
bool canBlock = true;
bool canBlock = !spellInfo.HasAttribute(SpellAttr8.NoAttackBlock);
// if victim is casting or cc'd it can't avoid attacks
if (victim.IsNonMeleeSpellCast(false, false, true) || victim.HasUnitState(UnitState.Controlled))
@@ -892,7 +892,7 @@ namespace Game.Entities
spell.Finish(result);
}
public virtual SpellInfo GetCastSpellInfo(SpellInfo spellInfo)
public virtual SpellInfo GetCastSpellInfo(SpellInfo spellInfo, TriggerCastFlags triggerFlag)
{
SpellInfo findMatchingAuraEffectIn(AuraType type)
{
@@ -903,7 +903,13 @@ namespace Game.Entities
{
SpellInfo info = Global.SpellMgr.GetSpellInfo((uint)auraEffect.GetAmount(), GetMap().GetDifficultyID());
if (info != null)
{
if (auraEffect.GetSpellInfo().HasAttribute(SpellAttr8.IgnoreSpellcastOverrideCost))
triggerFlag |= TriggerCastFlags.IgnorePowerAndReagentCost;
return info;
}
}
}
+2 -3
View File
@@ -308,11 +308,10 @@ namespace Game
SpellCastTargets targets = new(caster, cast.Cast);
// check known spell or raid marker spell (which not requires player to know it)
if (caster.IsTypeId(TypeId.Player) && !caster.ToPlayer().HasActiveSpell(spellInfo.Id) && !spellInfo.HasEffect(SpellEffectName.ChangeRaidMarker) && !spellInfo.HasAttribute(SpellAttr8.RaidMarker))
if (caster.IsTypeId(TypeId.Player) && !caster.ToPlayer().HasActiveSpell(spellInfo.Id) && !spellInfo.HasAttribute(SpellAttr8.SkipIsKnownCheck))
{
bool allow = false;
// allow casting of unknown spells for special lock cases
GameObject go = targets.GetGOTarget();
if (go != null)
@@ -331,7 +330,7 @@ namespace Game
}
// Check possible spell cast overrides
spellInfo = caster.GetCastSpellInfo(spellInfo);
spellInfo = caster.GetCastSpellInfo(spellInfo, triggerFlag);
if (spellInfo.IsPassive())
return;
@@ -1819,12 +1819,12 @@ namespace Game.Networking.Packets
{
public ObjectGuid BeaconGUID;
public uint Points;
public byte Type;
public SpellHealPredictionType Type;
public void Write(WorldPacket data)
{
data.WriteUInt32(Points);
data.WriteUInt8(Type);
data.WriteUInt8((byte)Type);
data.WritePackedGuid(BeaconGUID);
}
}
+1 -1
View File
@@ -143,7 +143,7 @@ namespace Game.Spells
bool effectNeedsAmount(AuraEffect effect) => effect != null && (GetEffectsToApply() & (1 << (int)effect.GetEffIndex())) != 0 && Aura.EffectTypeNeedsSendingAmount(effect.GetAuraType());
if (GetBase().GetSpellInfo().HasAttribute(SpellAttr8.AuraSendAmount) || GetBase().GetAuraEffects().Any(effectNeedsAmount))
if (GetBase().GetSpellInfo().HasAttribute(SpellAttr8.AuraPointsOnClient) || GetBase().GetAuraEffects().Any(effectNeedsAmount))
_flags |= AuraFlags.Scalable;
}
+14 -6
View File
@@ -61,7 +61,7 @@ namespace Game.Spells
// default amount calculation
int amount = 0;
if (!m_spellInfo.HasAttribute(SpellAttr8.MasteryAffectPoints) || MathFunctions.fuzzyEq(GetSpellEffectInfo().BonusCoefficient, 0.0f))
if (!m_spellInfo.HasAttribute(SpellAttr8.MasteryAffectsPoints) || MathFunctions.fuzzyEq(GetSpellEffectInfo().BonusCoefficient, 0.0f))
amount = GetSpellEffectInfo().CalcValue(caster, m_baseAmount, GetBase().GetOwner().ToUnit(), GetBase().GetCastItemId(), GetBase().GetCastItemLevel());
else if (caster != null && caster.IsTypeId(TypeId.Player))
amount = (int)(caster.ToPlayer().m_activePlayerData.Mastery * GetSpellEffectInfo().BonusCoefficient);
@@ -169,6 +169,8 @@ namespace Game.Spells
caster.ModSpellDurationTime(spellInfo, ref period);
else if (spellInfo.HasAttribute(SpellAttr5.SpellHasteAffectsPeriodic))
period = (int)(period * caster.m_unitData.ModCastingSpeed);
else if (spellInfo.HasAttribute(SpellAttr8.MeleeHasteAffectsPeriodic))
period = (int)(period * caster.m_unitData.ModHaste);
if (period == 0)
return 0.0f;
@@ -179,7 +181,7 @@ namespace Game.Spells
return totalTicks * CalculateEstimatedAmount(caster, target, spellInfo, spellEffectInfo, (int)amount, stack, null).GetValueOrDefault(amount);
}
public uint GetTotalTicks()
{
uint totalTicks = 0;
@@ -252,6 +254,8 @@ namespace Game.Spells
caster.ModSpellDurationTime(m_spellInfo, ref _period);
else if (m_spellInfo.HasAttribute(SpellAttr5.SpellHasteAffectsPeriodic))
_period = (int)(_period * caster.m_unitData.ModCastingSpeed);
else if (m_spellInfo.HasAttribute(SpellAttr8.MeleeHasteAffectsPeriodic))
_period = (int)(_period * caster.m_unitData.ModHaste);
}
}
else // prevent infinite loop on Update
@@ -365,7 +369,7 @@ namespace Game.Spells
HandleEffect(aurApp, handleMask, true, triggeredBy);
}
if (GetSpellInfo().HasAttribute(SpellAttr8.AuraSendAmount) || Aura.EffectTypeNeedsSendingAmount(GetAuraType()))
if (GetSpellInfo().HasAttribute(SpellAttr8.AuraPointsOnClient) || Aura.EffectTypeNeedsSendingAmount(GetAuraType()))
GetBase().SetNeedClientUpdateForTargets();
}
@@ -2519,7 +2523,7 @@ namespace Game.Spells
if (!apply && !target.IsFlying())
target.GetMotionMaster().MoveFall();
}
[AuraEffectHandler(AuraType.ModStunDisableGravity)]
void HandleAuraModStunAndDisableGravity(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
{
@@ -4826,7 +4830,7 @@ namespace Game.Spells
uint casterType = (uint)GetMiscValue();
if (casterType > 0)
caster = GetCaster();
caster?.CastSpell(aurApp.GetTarget(), GetSpellEffectInfo().TriggerSpell, new CastSpellExtraArgs(this));
}
@@ -5558,6 +5562,8 @@ namespace Game.Spells
{
Unit triggerCaster = aurApp.GetTarget();
Unit triggerTarget = eventInfo.GetProcTarget();
if (GetSpellInfo().HasAttribute(SpellAttr8.TargetProcsOnCaster) && eventInfo.GetTypeMask().HasFlag(ProcFlags.TakenHitMask))
triggerTarget = eventInfo.GetActor();
uint triggerSpellId = GetSpellEffectInfo().TriggerSpell;
if (triggerSpellId == 0)
@@ -5580,6 +5586,8 @@ namespace Game.Spells
{
Unit triggerCaster = aurApp.GetTarget();
Unit triggerTarget = eventInfo.GetProcTarget();
if (GetSpellInfo().HasAttribute(SpellAttr8.TargetProcsOnCaster) && eventInfo.GetTypeMask().HasFlag(ProcFlags.TakenHitMask))
triggerTarget = eventInfo.GetActor();
uint triggerSpellId = GetSpellEffectInfo().TriggerSpell;
if (triggerSpellId == 0)
@@ -5993,7 +6001,7 @@ namespace Game.Spells
playerTarget.ReplaceAllRequiredMountCapabilityFlags((byte)mountCapabilityFlags);
}
}
[AuraEffectHandler(AuraType.SuppressItemPassiveEffectBySpellLabel)]
void HandleSuppressItemPassiveEffectBySpellLabel(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
{
+126 -28
View File
@@ -305,6 +305,21 @@ namespace Game.Spells
}
}
}
if (m_targets.HasDst())
{
if (m_spellInfo.HasAttribute(SpellAttr8.RequiresLocationToBeOnLiquidSurface))
{
ZLiquidStatus status = m_caster.GetMap().GetLiquidStatus(m_caster.GetPhaseShift(), m_targets.GetDstPos().GetPositionX(), m_targets.GetDstPos().GetPositionY(), m_targets.GetDstPos().GetPositionZ(), LiquidHeaderTypeFlags.AllLiquids);
if (!status.HasAnyFlag(ZLiquidStatus.WaterWalk | ZLiquidStatus.InWater))
{
SendCastResult(SpellCastResult.NoLiquid);
Finish(SpellCastResult.NoLiquid);
return;
}
}
}
ulong dstDelay = CalculateDelayMomentForDst(m_spellInfo.LaunchDelay);
if (dstDelay != 0)
m_delayMoment = dstDelay;
@@ -3806,6 +3821,9 @@ namespace Game.Spells
if (HasPowerTypeCost(PowerType.Runes))
castFlags |= SpellCastFlags.NoGCD; // not needed, but Blizzard sends it
if (m_spellInfo.HasAttribute(SpellAttr8.HealPrediction) && m_casttime != 0 && m_caster.IsUnit())
castFlags |= SpellCastFlags.HealPrediction;
SpellStart packet = new();
SpellCastData castData = packet.Cast;
@@ -3874,13 +3892,7 @@ namespace Game.Spells
castData.Immunities.Value = (uint)mechanicImmunityMask;
}
/** @todo implement heal prediction packet data
if (castFlags & CAST_FLAG_HEAL_PREDICTION)
{
castData.Predict.BeconGUID = ??
castData.Predict.Points = 0;
castData.Predict.Type = 0;
}**/
UpdateSpellHealPrediction(castData.Predict, false);
m_caster.SendMessageToSet(packet, true);
}
@@ -4093,6 +4105,77 @@ namespace Game.Spells
return ammoDisplayID;
}
static (int, SpellHealPredictionType) CalcPredictedHealing(SpellInfo spellInfo, Unit unitCaster, Unit target, uint castItemEntry, int castItemLevel, Spell spell, bool withPeriodic)
{
int points = 0;
SpellHealPredictionType type = SpellHealPredictionType.Target;
foreach (SpellEffectInfo spellEffectInfo in spellInfo.GetEffects())
{
switch (spellEffectInfo.Effect)
{
case SpellEffectName.Heal:
case SpellEffectName.HealPct:
points += unitCaster.SpellHealingBonusDone(target, spellInfo, spellEffectInfo.CalcValue(unitCaster, null, target, castItemEntry, castItemLevel), DamageEffectType.Direct, spellEffectInfo, 1, spell);
if (target != unitCaster && (spellEffectInfo.TargetA.GetTarget() == Targets.UnitCaster || spellEffectInfo.TargetB.GetTarget() == Targets.UnitCaster))
type = SpellHealPredictionType.TargetAndCaster; // Binding Heal-like spells
else if (spellEffectInfo.TargetA.GetCheckType() == SpellTargetCheckTypes.Party || spellEffectInfo.TargetB.GetCheckType() == SpellTargetCheckTypes.Party)
type = SpellHealPredictionType.TargetParty; // Prayer of Healing (old party-wide targeting)
break;
default:
break;
}
if (withPeriodic)
{
switch (spellEffectInfo.ApplyAuraName)
{
case AuraType.PeriodicHeal:
case AuraType.ObsModHealth:
points += (int)(unitCaster.SpellHealingBonusDone(target, spellInfo, spellEffectInfo.CalcValue(unitCaster, null, target, castItemEntry, castItemLevel), DamageEffectType.Direct, spellEffectInfo, 1, spell) * spellInfo.GetMaxTicks());
break;
case AuraType.PeriodicTriggerSpell:
SpellInfo triggered = Global.SpellMgr.GetSpellInfo(spellEffectInfo.TriggerSpell, spellInfo.Difficulty);
if (triggered != null)
points += CalcPredictedHealing(triggered, unitCaster, target, castItemEntry, castItemLevel, null, withPeriodic).Item1;
break;
default:
break;
}
}
}
return (points, type);
}
void UpdateSpellHealPrediction(SpellHealPrediction healPrediction, bool withPeriodic)
{
healPrediction.BeaconGUID = ObjectGuid.Empty;
healPrediction.Points = 0;
healPrediction.Type = SpellHealPredictionType.Target;
Unit unitCaster = m_caster.ToUnit();
Unit target = m_targets.GetUnitTarget();
if (target != null)
{
var (points, type) = CalcPredictedHealing(m_spellInfo, unitCaster, target, m_castItemEntry, m_castItemLevel, this, withPeriodic);
healPrediction.Points = (uint)points;
healPrediction.Type = type;
}
uint beaconSpellId = 53651;
if (healPrediction.Type == SpellHealPredictionType.Target && unitCaster.HasAura(beaconSpellId, unitCaster.GetGUID()))
{
var beacon = unitCaster.GetSingleCastAuras().Find(aura => aura.GetSpellInfo().GetEffects().Count > 1 && aura.GetSpellInfo().GetEffect(1).TriggerSpell == beaconSpellId);
if (beacon != null)
{
healPrediction.BeaconGUID = beacon.GetOwner().GetGUID();
healPrediction.Type = SpellHealPredictionType.TargetAndBeacon;
}
}
}
void SendSpellExecuteLog()
{
if (_executeLogEffects.Empty())
@@ -4256,25 +4339,6 @@ namespace Game.Spells
if (unitCaster == null)
return;
SpellChannelStart spellChannelStart = new();
spellChannelStart.CasterGUID = unitCaster.GetGUID();
spellChannelStart.SpellID = (int)m_spellInfo.Id;
spellChannelStart.Visual = m_SpellVisual;
spellChannelStart.ChannelDuration = duration;
uint schoolImmunityMask = unitCaster.GetSchoolImmunityMask();
ulong mechanicImmunityMask = unitCaster.GetMechanicImmunityMask();
if (schoolImmunityMask != 0 || mechanicImmunityMask != 0)
{
SpellChannelStartInterruptImmunities interruptImmunities = new();
interruptImmunities.SchoolImmunities = (int)schoolImmunityMask;
interruptImmunities.Immunities = (int)mechanicImmunityMask;
spellChannelStart.InterruptImmunities = interruptImmunities;
}
unitCaster.SendMessageToSet(spellChannelStart, true);
m_timer = (int)duration;
if (!m_targets.HasDst())
@@ -4320,6 +4384,37 @@ namespace Game.Spells
unitCaster.SetChannelSpellId(m_spellInfo.Id);
unitCaster.SetChannelVisual(m_SpellVisual);
SpellChannelStart spellChannelStart = new();
spellChannelStart.CasterGUID = unitCaster.GetGUID();
spellChannelStart.SpellID = (int)m_spellInfo.Id;
spellChannelStart.Visual = m_SpellVisual;
spellChannelStart.ChannelDuration = duration;
uint schoolImmunityMask = unitCaster.GetSchoolImmunityMask();
ulong mechanicImmunityMask = unitCaster.GetMechanicImmunityMask();
if (schoolImmunityMask != 0 || mechanicImmunityMask != 0)
{
SpellChannelStartInterruptImmunities interruptImmunities = new();
interruptImmunities.SchoolImmunities = (int)schoolImmunityMask;
interruptImmunities.Immunities = (int)mechanicImmunityMask;
spellChannelStart.InterruptImmunities = interruptImmunities;
}
if (m_spellInfo.HasAttribute(SpellAttr8.HealPrediction) && m_casttime != 0 && m_caster.IsUnit())
{
SpellTargetedHealPrediction healPrediction = new();
if (unitCaster.m_unitData.ChannelObjects.Size() == 1 && unitCaster.m_unitData.ChannelObjects[0].IsUnit())
healPrediction.TargetGUID = unitCaster.m_unitData.ChannelObjects[0];
UpdateSpellHealPrediction(healPrediction.Predict, true);
spellChannelStart.HealPrediction = healPrediction;
}
unitCaster.SendMessageToSet(spellChannelStart, true);
}
void SendResurrectRequest(Player target)
@@ -4746,6 +4841,9 @@ namespace Game.Spells
return SpellCastResult.CustomError;
}
if (m_spellInfo.HasAttribute(SpellAttr8.OnlyPlayersCanCastThisSpell) && !m_caster.IsPlayer())
return SpellCastResult.CasterAurastate;
// Check global cooldown
if (strict && !Convert.ToBoolean(_triggeredCastFlags & TriggerCastFlags.IgnoreGCD) && HasGlobalCooldown())
return !m_spellInfo.HasAttribute(SpellAttr0.CooldownOnEvent) ? SpellCastResult.NotReady : SpellCastResult.DontReport;
@@ -7195,7 +7293,7 @@ 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.AuraPointsOnClient)) || m_spellInfo.HasHitDelay() || (m_triggeredByAuraSpell == null && !IsTriggered()) ||
m_spellInfo.HasAttribute(SpellAttr7.AlwaysCastLog);
}
@@ -8474,7 +8572,7 @@ namespace Game.Spells
if (unit.IsAlive() != IsAlive)
return;
if (spell.GetState() == SpellState.Delayed && !spell.IsPositive() && (GameTime.GetGameTimeMS() - TimeDelay) <= unit.LastSanctuaryTime)
if (!spell.m_spellInfo.HasAttribute(SpellAttr8.IgnoreSanctuary) && spell.GetState() == SpellState.Delayed && !spell.IsPositive() && (GameTime.GetGameTimeMS() - TimeDelay) <= unit.LastSanctuaryTime)
return; // No missinfo in that case
if (_spellHitTarget != null)
+28 -3
View File
@@ -877,6 +877,18 @@ namespace Game.Spells
return SpellCastResult.NotInRaidInstance;
}
if (HasAttribute(SpellAttr8.RemoveOutsideDungeonsAndRaids))
{
if (mapEntry == null || !mapEntry.IsDungeon())
return SpellCastResult.TargetNotInInstance;
}
if (HasAttribute(SpellAttr8.NotInBattleground))
{
if (mapEntry == null || mapEntry.IsBattleground())
return SpellCastResult.NotInBattleground;
}
// DB base check (if non empty then must fit at least single for allow)
var saBounds = Global.SpellMgr.GetSpellAreaMapBounds(Id);
if (!saBounds.Empty())
@@ -993,6 +1005,10 @@ namespace Game.Spells
Unit unitTarget = target.ToUnit();
if (HasAttribute(SpellAttr8.OnlyTargetIfSameCreator))
if (caster != target && caster.GetGUID() != target.GetOwnerGUID())
return SpellCastResult.BadTargets;
// creature/player specific target checks
if (unitTarget != null)
{
@@ -1046,6 +1062,10 @@ namespace Game.Spells
}
}
}
if (HasAttribute(SpellAttr8.OnlyTargetOwnSummons))
if (!unitTarget.IsSummon() || unitTarget.ToTempSummon().GetSummonerGUID() != caster.GetGUID())
return SpellCastResult.BadTargets;
}
// corpse specific target checks
else if (target.IsTypeId(TypeId.Corpse))
@@ -1137,7 +1157,7 @@ namespace Game.Spells
if (HasEffect(SpellEffectName.SelfResurrect) || HasEffect(SpellEffectName.Resurrect))
return SpellCastResult.TargetCannotBeResurrected;
if (HasAttribute(SpellAttr8.BattleResurrection))
if (HasAttribute(SpellAttr8.EnforceInCombatRessurectionLimit))
{
Map map = caster.GetMap();
if (map != null)
@@ -4248,7 +4268,7 @@ namespace Game.Spells
if (Scaling.Coefficient != 0.0f)
{
uint level = _spellInfo.SpellLevel;
if (target != null && _spellInfo.IsPositiveEffect(EffectIndex) && (Effect == SpellEffectName.ApplyAura))
if (target != null && _spellInfo.HasAttribute(SpellAttr8.UseTargetsLevelForSpellScaling))
level = target.GetLevel();
else if (caster != null && caster.IsUnit())
level = caster.ToUnit().GetLevel();
@@ -4333,7 +4353,12 @@ namespace Game.Spells
if (contentTuning != null)
expansion = contentTuning.ExpansionID;
uint level = caster != null && caster.IsUnit() ? caster.ToUnit().GetLevel() : 1;
uint level = 1;
if (target != null && _spellInfo.HasAttribute(SpellAttr8.UseTargetsLevelForSpellScaling))
level = target.GetLevel();
else if (caster != null && caster.IsUnit())
level = caster.ToUnit().GetLevel();
tempValue = Global.DB2Mgr.EvaluateExpectedStat(stat, level, expansion, 0, Class.None, 0) * BasePoints / 100.0f;
}