public bool StartCastAtPos(Unit instigator, ushort abilityID, Point3D worldPos, ushort zoneId, byte castSequence)
        {
            if (PreventCasting)
            {
                if (_Owner is Player)
                {
                    Player owner = _Owner as Player;
                    owner?.SendClientMessage("A developer has disabled all abilities.", ChatLogFilters.CHATLOGFILTERS_USER_ERROR);
                }
                return(false);
            }

            // Allow only interruption of channeled skills of a different ID to the skill being used
            if (IsCasting() && (!_abilityProcessor.IsChannelling || _abilityProcessor.AbInfo.Entry == abilityID))
            {
                return(false);
            }

            AbilityInfo abInfo = AbilityMgr.GetAbilityInfo(abilityID);

            if (abInfo == null || (abInfo.ConstantInfo.Origin != AbilityOrigin.AO_ITEM && !IsValidAbility(abInfo)))
            {
                return(false);
            }
            try
            {
                if (AbilityMgr.HasCommandsFor(abilityID) || abInfo.ConstantInfo.ChannelID != 0)
                {
                    if (_abilityProcessor == null)
                    {
                        _abilityProcessor = new AbilityProcessor(_unitOwner, this);
                    }

                    abInfo.Instigator = instigator;

                    if (!_abilityProcessor.HasInfo())
                    {
                        _abilityProcessor.StartAbilityAtPos(abInfo, castSequence, worldPos, zoneId);
                    }
                    return(true);
                }
                if (_Owner is Player)
                {
                    var owner = _Owner as Player;
                    owner?.SendClientMessage(abilityID + " " + AbilityMgr.GetAbilityNameFor(abilityID) + " has no implementation.", ChatLogFilters.CHATLOGFILTERS_USER_ERROR);
                }
                return(false);
            }

            catch (Exception e)
            {
                if (_Owner is Player)
                {
                    var owner = _Owner as Player;
                    owner?.SendClientMessage(abilityID + " " + AbilityMgr.GetAbilityNameFor(abilityID) + " threw an unhandled " + e.GetType().Name + " from " + e.TargetSite + ".");
                }
                return(false);
            }
        }
        public bool StartCast(Unit instigator, ushort abilityID, byte castSequence, byte cooldownGroup = 0, byte overrideAbilityLevel = 0, bool enemyVisible = true, bool friendlyVisible = true, bool moving = false)
        {
            if (PreventCasting)
            {
                if (_Owner is Player)
                {
                    (_Owner as Player)?.SendClientMessage("A developer has disabled all abilities.", ChatLogFilters.CHATLOGFILTERS_USER_ERROR);
                }
                return(false);
            }

            // Allow only interruption of channeled skills of a different ID to the skill being used
            if (IsCasting() && (!_abilityProcessor.IsChannelling || _abilityProcessor.AbInfo.Entry == abilityID))
            {
                return(false);
            }

            AbilityInfo abInfo = AbilityMgr.GetAbilityInfo(abilityID);

            if (abInfo == null || (abInfo.ConstantInfo.Origin != AbilityOrigin.AO_ITEM && !IsValidAbility(abInfo)))
            {
                return(false);
            }

            //Fix so that WE/WH cant use all their 3 openers at the same time, this is in conjunction with whats in AbilityProcessor
            if (_Owner is Player)
            {
                if ((_Owner as Player).StealthLevel == 0 && (abilityID == 9406 || abilityID == 9401 || abilityID == 9411 || abilityID == 8091 || abilityID == 8096 || abilityID == 8098))
                {
                    return(false);
                }
            }

            try
            {
                if (AbilityMgr.HasCommandsFor(abilityID) || abInfo.ConstantInfo.ChannelID != 0)
                {
                    if (_abilityProcessor == null)
                    {
                        _abilityProcessor = new AbilityProcessor(_unitOwner, this);
                    }

                    abInfo.Instigator = instigator;
                    abInfo.Level      = overrideAbilityLevel;

                    return(_abilityProcessor.StartAbility(abInfo, castSequence, cooldownGroup, enemyVisible, friendlyVisible, moving));
                }
                if (_Owner is Player)
                {
                    Player owner = _Owner as Player;
                    owner?.SendClientMessage(abilityID + " " + AbilityMgr.GetAbilityNameFor(abilityID) + " has no implementation.", ChatLogFilters.CHATLOGFILTERS_USER_ERROR);
                }
                return(false);
            }

            catch (Exception e)
            {
                if (_Owner is Player)
                {
                    (_Owner as Player)?.SendClientMessage(abilityID + " " + AbilityMgr.GetAbilityNameFor(abilityID) + " threw an unhandled " + e.GetType().Name + " from " + e.TargetSite + ".");
                }
                Log.Error("Ability System", e.ToString());
                return(false);
            }
        }
        public virtual void StartBuff()
        {
            if (_buffInfo.StackLine != 0)
            {
                AddBuffParameter(_buffInfo.StackLine, StackLevel);
            }

            // Invoke commands and register event subscriptions.
            if (_buffInfo.CommandInfo != null)
            {
                for (byte i = 0; i < _buffInfo.CommandInfo.Count; ++i)
                {
                    BuffCommandInfo command = _buffInfo.CommandInfo[i];

                    if (command.EventID != 0)
                    {
                        EventCommands.Add(new Tuple <byte, BuffCommandInfo>(command.EventID, command));
                        _buffInterface.AddEventSubscription(this, command.EventID);
                        //InvokeOn override - 8 == Invoke as permanent conditional effect while buff is active (for Channel)
                        if (command.InvokeOn == 8 && command.TargetType == CommandTargetTypes.Caster)
                        {
                            Caster.BuffInterface.AddEventSubscription(this, command.EventID);
                        }

                        if (command.InvokeOn == 0 && command.BuffLine > 0)
                        {
                            AddBuffParameter(command.BuffLine, command.PrimaryValue);
                        }
                    }
                    if ((command.InvokeOn & BuffState) > 0)
                    {
                        BuffEffectInvoker.InvokeCommand(this, command, Target);
                    }
                }
            }

            BuffState = (byte)EBuffState.Running;

            #region Check for CC block or no tooltip text
            // If a buff is crowd control and no tooltip text was added, a CC immunity blocked it.
            // In this case the buff is removed here.
            if (BuffLines.Count != 0)
            {
                if (Duration > 0)
                {
                    if (CrowdControl == 1)
                    {
                        DurationMs = (uint)(DurationMs * Target.StsInterface.GetStatReductionModifier(Stats.SnareDuration));
                        EndTime    = TCPManager.GetTimeStampMS() + DurationMs;
                    }
                    if (CrowdControl == 16)
                    {
                        DurationMs = (uint)(DurationMs * Target.StsInterface.GetStatReductionModifier(Stats.KnockdownDuration));
                        EndTime    = TCPManager.GetTimeStampMS() + DurationMs;
                    }
                }

                SendStart(null);

                ChannelHandler?.NotifyBuffStarted();
            }
            else
            {
                #if DEBUG
                Log.Info("Buff " + _buffInfo.Entry, "Couldn't find any buff lines.");
                if (CrowdControl == 0 && Caster is Player)
                {
                    ((Player)Caster).SendClientMessage(Entry + " " + AbilityMgr.GetAbilityNameFor(Entry) + ": Couldn't find any buff lines.");
                }
                #endif
                BuffHasExpired = true;
            }
            #endregion
        }
        public virtual void InvokeDamageEvent(byte eventId, AbilityDamageInfo damageInfo, Unit eventInstigator)
        {
            if (BuffState != (byte)EBuffState.Running)
            {
                return;
            }

            BuffCommandInfo myCommand = EventCommands.Find(evtpair => evtpair.Item1 == eventId).Item2;

            if (myCommand == null)
            {
                return;
            }

            if (!string.IsNullOrEmpty(myCommand.EventCheck) && !BuffEffectInvoker.PerformCheck(this, damageInfo, myCommand, eventInstigator))
            {
                return;
            }

            if (myCommand.EventChance > 0 && StaticRandom.Instance.Next(0, 100) > myCommand.EventChance)
            {
                return;
            }

            if (myCommand.RetriggerInterval != 0)
            {
                // If two threads clash here, we're guaranteed to be setting the next time anyway
                // so the thread which can't get the lock should just return
                if (Interlocked.CompareExchange(ref BuffTimerLock, 1, 0) != 0)
                {
                    return;
                }

                if (myCommand.NextTriggerTime != 0 && myCommand.NextTriggerTime > TCPManager.GetTimeStampMS())
                {
                    Interlocked.Exchange(ref BuffTimerLock, 0);
                    return;
                }

                myCommand.NextTriggerTime = TCPManager.GetTimeStampMS() + myCommand.RetriggerInterval;
                Interlocked.Exchange(ref BuffTimerLock, 0);
            }

            if (myCommand.ConsumesStack)
            {
                while (Interlocked.CompareExchange(ref BuffStackLock, 1, 0) != 0)
                {
                    ;
                }

                if (StackLevel == 0)
                {
                    Interlocked.Exchange(ref BuffStackLock, 0);
                    return;
                }

                RemoveStack();

                if (Entry == 8090 || Entry == 9393)
                {
                    ((Player)Caster).SendClientMessage((eventInstigator?.Name ?? "Something") + "'s " + AbilityMgr.GetAbilityNameFor(damageInfo.DisplayEntry) + " broke your stealth.");
                }


                Interlocked.Exchange(ref BuffStackLock, 0);
            }

            if (myCommand.CommandName == "None")
            {
                return;
            }

            BuffEffectInvoker.InvokeDamageEventCommand(this, myCommand, damageInfo, Target, eventInstigator);
        }
        public void ReloadTactics()
        {
            List <ushort> tacList          = new List <ushort>();
            bool          sendTacticUpdate = false;

            if (_myPlayer._Value.Tactic1 != 0 && !tacList.Contains(_myPlayer._Value.Tactic1))
            {
                tacList.Add(_myPlayer._Value.Tactic1);
            }
            if (_myPlayer._Value.Tactic2 != 0 && !tacList.Contains(_myPlayer._Value.Tactic2))
            {
                tacList.Add(_myPlayer._Value.Tactic2);
            }
            if (_myPlayer._Value.Tactic3 != 0 && !tacList.Contains(_myPlayer._Value.Tactic3))
            {
                tacList.Add(_myPlayer._Value.Tactic3);
            }
            if (_myPlayer._Value.Tactic4 != 0 && !tacList.Contains(_myPlayer._Value.Tactic4))
            {
                tacList.Add(_myPlayer._Value.Tactic4);
            }

            int maxAllowedTactics = _myPlayer.AdjustedLevel / 10;

            while (tacList.Count > maxAllowedTactics)
            {
                tacList.RemoveAt(tacList.Count - 1);
                sendTacticUpdate = true;
            }

            foreach (NewBuff buff in _activeBuffs)
            {
                buff.BuffHasExpired = true;

                if (_modifyingTactics.Contains(buff.Entry))
                {
                    _modifyingTactics.Remove(buff.Entry);

                    List <ushort> toRemove = new List <ushort>();

                    if (AbilityMgr.HasPreCastModifiers(buff.Entry))
                    {
                        foreach (AbilityModifier mod in AbilityMgr.GetAbilityPreCastModifiers(buff.Entry))
                        {
                            if (mod.Affecting == 0)
                            {
                                _generalPreCastModifiers.RemoveAll(fmod => fmod.Source == buff.Entry);
                            }
                            else if (mod.Affecting <= 3)
                            {
                                _speclinePreCastModifiers[(byte)(mod.Affecting - 1)].RemoveAll(fmod => fmod.Source == buff.Entry);
                            }
                            else
                            {
                                toRemove.Add(mod.Affecting);
                            }
                        }

                        foreach (ushort rem in toRemove)
                        {
                            _abilityPreCastModifiers[rem].RemoveAll(fmod => fmod.Source == buff.Entry);
                        }

                        toRemove.Clear();
                    }

                    if (AbilityMgr.HasModifiers(buff.Entry))
                    {
                        foreach (AbilityModifier mod in AbilityMgr.GetAbilityModifiers(buff.Entry))
                        {
                            if (mod.Affecting == 0)
                            {
                                _generalModifiers.RemoveAll(fmod => fmod.Source == buff.Entry);
                            }
                            else if (mod.Affecting <= 3)
                            {
                                _speclineModifiers[(byte)(mod.Affecting - 1)].RemoveAll(fmod => fmod.Source == buff.Entry);
                            }
                            else
                            {
                                toRemove.Add(mod.Affecting);
                            }
                        }

                        foreach (ushort rem in toRemove)
                        {
                            _abilityModifiers[rem].RemoveAll(fmod => fmod.Source == buff.Entry);
                        }

                        toRemove.Clear();
                    }

                    if (AbilityMgr.HasBuffModifiers(buff.Entry))
                    {
                        foreach (AbilityModifier mod in AbilityMgr.GetBuffModifiers(buff.Entry))
                        {
                            if (mod.Affecting == 0)
                            {
                                _generalBuffModifiers.RemoveAll(fmod => fmod.Source == buff.Entry);
                            }
                            else if (mod.Affecting <= 3)
                            {
                                _speclineBuffModifiers[(byte)(mod.Affecting - 1)].RemoveAll(fmod => fmod.Source == buff.Entry);
                            }
                            else
                            {
                                toRemove.Add(mod.Affecting);
                            }
                        }

                        foreach (ushort rem in toRemove)
                        {
                            _buffModifiers[rem].RemoveAll(fmod => fmod.Source == buff.Entry);
                        }
                    }
                }

                _activeTactics.Remove(buff.Entry);
            }

            _activeBuffs.Clear();

            foreach (ushort id in tacList)
            {
                if (id == 0 || _activeTactics.Contains(id))
                {
                    continue;
                }
                BuffInfo b = AbilityMgr.GetBuffInfo(id);

                if (b == null)
                {
                    _myPlayer.SendClientMessage("Nonexistent tactic: " + id + " " + AbilityMgr.GetAbilityNameFor(id));
                    continue;
                }

                if (!_myPlayer.AbtInterface.IsValidTactic(id))
                {
                    _myPlayer.SendClientMessage("Invalid tactic: " + id + " " + AbilityMgr.GetAbilityNameFor(id));
                    sendTacticUpdate = true;
                    continue;
                }

                if (!string.IsNullOrEmpty(b.AuraPropagation))
                {
                    _myPlayer.BuffInterface.QueueBuff(new BuffQueueInfo(_myPlayer, _myPlayer.AbtInterface.GetMasteryLevelFor(AbilityMgr.GetMasteryTreeFor(b.Entry)), b, BuffEffectInvoker.CreateAura, RegisterTacticBuff));
                }
                else
                {
                    _myPlayer.BuffInterface.QueueBuff(new BuffQueueInfo(_myPlayer, _myPlayer.AbtInterface.GetMasteryLevelFor(AbilityMgr.GetMasteryTreeFor(b.Entry)), b, RegisterTacticBuff));
                }
                _activeTactics.Add(id);
            }

            // Update the saved list for the server
            for (int i = 0; i < 4; ++i)
            {
                _myPlayer._Value.SetTactic((byte)(i + 1), i < _activeTactics.Count ? _activeTactics[i] : (ushort)0);
            }

            if (sendTacticUpdate)
            {
                SendTactics();
            }
        }