public void ValidateAndTrigger(Spell spell, Unit triggerOwner, WorldObject target, IUnitAction action = null, SpellEffect triggerEffect = null) { WorldObject[] targets; if (triggerOwner == null) { LogManager.GetCurrentClassLogger().Warn("triggerOwner is null when trying to proc spell: {0} (target: {1})", spell, target); return; } if (spell.CasterIsTarget || !spell.HasTargets) { targets = new[] { triggerOwner }; } else if (target != null) { if (spell.IsAreaSpell || (spell.IsHarmfulFor(CasterReference, target))) { targets = null; } else { targets = new[] { target }; } } else { targets = null; } if (action != null) { action.ReferenceCount++; TriggerAction = action; } Start(spell, triggerEffect, true, targets); //Dispose(); }
void CreateAuras(ref List <MissedTarget> missedTargets, ref List <IAura> auras, DynamicObject dynObj) { auras = AuraListPool.Obtain(); var allowDead = Spell.PersistsThroughDeath; // create AreaAura if (Spell.IsAreaAura) { if (dynObj != null || (CasterObject != null && (allowDead || !(CasterObject is Unit) || ((Unit)CasterObject).IsAlive))) { // AreaAura is created at the target location if it is a DynamicObject, else its applied to the caster var aaura = new AreaAura(dynObj ?? CasterObject, Spell); if (dynObj != null) { // also start the area aura auras.Add(aaura); } // else: Is coupled to an Aura instance } else { LogManager.GetCurrentClassLogger().Warn( "Tried to cast Spell {0} with invalid dynObj or Caster - dynObj: {1}, CasterObject: {2}, CasterUnit: {3}", Spell, dynObj, CasterObject, CasterUnit); } } // remove missed targets for (var i = m_auraApplicationInfos.Count - 1; i >= 0; i--) { var app = m_auraApplicationInfos[i]; if (!Targets.Contains(app.Target)) { m_auraApplicationInfos.RemoveAt(i); } } if (m_auraApplicationInfos.Count == 0) { return; } // create Aura-Handlers for (var i = 0; i < Handlers.Length; i++) { var spellHandler = Handlers[i]; if (spellHandler is ApplyAuraEffectHandler) { ((ApplyAuraEffectHandler)spellHandler).AddAuraHandlers(m_auraApplicationInfos); } } if (missedTargets == null) { missedTargets = CastMissListPool.Obtain(); } // apply all new Auras for (var i = 0; i < m_auraApplicationInfos.Count; i++) { var info = m_auraApplicationInfos[i]; var target = info.Target; if (!target.IsInContext) { continue; } if (info.Handlers == null || (!allowDead && !target.IsAlive)) { continue; } // check for immunities and resistances CastMissReason missReason; var hostile = Spell.IsHarmfulFor(CasterReference, target); if (!IsPassive && !Spell.IsPreventionDebuff && (missReason = CheckDebuffResist(target, Spell, CasterReference.Level, hostile)) != CastMissReason.None) { // debuff miss missedTargets.Add(new MissedTarget(target, missReason)); } else { // create aura var newAura = target.Auras.CreateAura(CasterReference, Spell, info.Handlers, TargetItem, !Spell.IsPreventionDebuff && !hostile); if (newAura != null) { // check for debuff and if the spell causes no threat we aren't put in combat if (!Spell.IsPreventionDebuff && !((Spell.AttributesExC & SpellAttributesExC.NoInitialAggro) != 0) && hostile && target.IsInWorld && target.IsAlive) { // force combat mode target.IsInCombat = true; if (target is NPC && CasterUnit != null) { ((NPC)target).ThreatCollection.AddNewIfNotExisted(CasterUnit); } } // add Aura now auras.Add(newAura); } } } //m_auraApplicationInfos.Clear(); //AuraAppListPool.Recycle(m_auraApplicationInfos); m_auraApplicationInfos = null; }
/// <summary> /// Validates targets and applies all SpellEffects /// </summary> public SpellFailedReason Impact() { if (!IsCasting) { return(SpellFailedReason.Ok); } // apply effects foreach (var handler in Handlers) { if (handler.Effect.IsPeriodic || handler.Effect.IsStrikeEffect) { // weapon ability or handled by Aura or Channel continue; } handler.Apply(); if (!IsCasting) { // the last handler cancelled the SpellCast return(SpellFailedReason.DontReport); } } if (CasterObject is Unit && Spell.IsPhysicalAbility) { // strike at everyone foreach (var target in UnitTargets) { ProcHitFlags hitFlags = CasterUnit.Strike(GetWeapon(), target, this); m_hitInfoByTarget[target] = hitFlags; } } // open Channel and spawn DynamicObject DynamicObject dynObj = null; if (Spell.DOEffect != null) { dynObj = new DynamicObject(this, Spell.DOEffect.GetRadius(CasterReference)); } if (!IsCasting) { return(SpellFailedReason.Ok); } List <MissedTarget> missedTargets = null; // create auras List <IAura> auras = null; if (m_auraApplicationInfos != null) { CreateAuras(ref missedTargets, ref auras, dynObj); } // check for missed targets if (missedTargets != null) { if (missedTargets.Count > 0) { // TODO: Flash message ontop of missed heads when impact is delayed CombatLogHandler.SendSpellMiss(this, true, missedTargets); missedTargets.Clear(); } CastMissListPool.Recycle(missedTargets); } // open channel if (Spell.IsChanneled && CasterObject != null) { Channel = SpellChannel.SpellChannelPool.Obtain(); Channel.m_cast = this; if (CasterObject is Unit) { if (dynObj != null) { CasterUnit.ChannelObject = dynObj; } else if (SelectedTarget != null) { CasterUnit.ChannelObject = SelectedTarget; if (SelectedTarget is NPC && Spell.IsTame) { ((NPC)SelectedTarget).CurrentTamer = CasterObject as Character; } } } var len = Handlers.Length; var channelEffectHandlers = SpellEffectHandlerListPool.Obtain(); //var channelEffectHandlers = new List<SpellEffectHandler>(6); for (var i = 0; i < len; i++) { var handler = Handlers[i]; if (handler.Effect.IsPeriodic) { channelEffectHandlers.Add(handler); } } Channel.Open(channelEffectHandlers, auras); } // start Auras if (auras != null) { for (var i = 0; i < auras.Count; i++) { var aura = auras[i]; aura.Start(Spell.IsChanneled ? Channel : null, false); } if (!IsChanneling) { auras.Clear(); AuraListPool.Recycle(auras); auras = null; } } // applying debuffs might cancel other Auras if (Spell.HasHarmfulEffects && !Spell.IsPreventionDebuff) { foreach (var target in Targets) { if (target is Unit && Spell.IsHarmfulFor(CasterReference, target)) { ((Unit)target).Auras.RemoveByFlag(AuraInterruptFlags.OnHostileSpellInflicted); } } } //if (CasterChar != null) //{ // CasterChar.SendSystemMessage("SpellCast (Impact): {0} ms", sw1.ElapsedTicks / 10000d); //} return(SpellFailedReason.Ok); }