using System;
using System.Collections.Generic;
using System.Text;
using CommonLang;
using CommonAI.Zone.Helper;
using CommonAI.Zone.Formula;
using CommonAI.Zone.UnitTriggers;
using CommonAI.Zone.Attributes;
using CommonLang.Property;
using CommonAI.RTS;
using CommonLang.Vector;
using CommonAI.ZoneClient;
using CommonAI.data;
using static CommonAI.Zone.LaunchSpell;
using CommonAI.Data;

namespace CommonAI.Zone.Instance
{
	public delegate int ReadBuffDelegate(InstanceUnit.BuffState buffState);
    /// <summary>
    /// 所有常态状态(Buff,技能,被动系)
    /// </summary>
    partial class InstanceUnit
    {
        //--------------------------------------------------------------------------------------------------------------
        #region _时效性效果_
        //--------------------------------------------------------------------------------------------------------------
        /// <summary>
        /// 是否可被发现
        /// </summary>
        virtual public bool IsVisible { get { return !mInvisibleTimeMS.Enable;/* && !DeadHide; */} }
        /// <summary>
        /// 是否无敌
        /// </summary>
        virtual public bool IsInvincible { get { return mInvincibleTimeMS.Enable; } }
        /// <summary>
        /// 此单位是否霸体
        /// </summary>
        virtual public bool IsNoneBlock { get { return mNoneBlockTimeMS.Enable; } }
        /// <summary>
        /// 是否为眩晕
        /// </summary>
        virtual public bool IsStun { get { return mStunTimeMS.Enable; } }
        /// <summary>
        /// 是否沉默
        /// </summary>
        virtual public bool IsSilent { get { return mSilentTimeMS.Enable; } }

		/// <summary>
		/// 是否免控
		/// </summary>
		virtual public bool IsIgnoreControl { get { return mIgnoreControl.Enable; } }

		/** 是否不允许移动 */
		public bool MarkCannotMove = false;
        virtual public bool IsCannotMove { get { return mCannotMoveTimeMS.Enable; } }

        //死亡隐藏
        private bool mDeadHide = false;
        public bool DeadHide{ get { return mDeadHide; } set { mDeadHide = value; } }

		public bool IsInPVP()	{ return this.Virtual.IsInPVP();	}
		public bool IsInPVE() { return this.Virtual.IsInPVE(); }

		virtual public string PlayerUUID
		{
			get { return ""; }
		}

		//--------------------------------------------------------------------------------------------------------------
		private List<MultiTimeLine> mMultiTimeLineGroup = new List<MultiTimeLine>();
        private UnitSyncMultiTimeLine mMultiTimeLineSync;

        /// <summary>
        /// 注册自定义MultiTimeLine
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public MultiTimeLine RegistMultiTimeLine(out int index)
        {
            index = mMultiTimeLineGroup.Count;
            var timeline = new MultiTimeLine(MultiTimeLineRefresh);
            mMultiTimeLineGroup.Add(timeline);
            return timeline;
        }
        /// <summary>
        /// 获取指定ID TimeLine
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public MultiTimeLine GetTimeLine(int index)
        {
            return mMultiTimeLineGroup[index];
        }

		public bool IsMoveAble()
		{
			return this.Info.IsMoveable && this.Info.MoveSpeedSEC > 0;
		}

        /// <summary>
        /// 指定TimeLine是否还有任务
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public bool IsTimeLineEnable(int index)
        {
            return mMultiTimeLineGroup[index].Enable;
        }
        /// <summary>
        /// 获取指定 TimeLine 的 ID
        /// </summary>
        /// <param name="timeline"></param>
        /// <returns></returns>
        public int GetTimeLineIndex(MultiTimeLine timeline)
        {
            return mMultiTimeLineGroup.IndexOf(timeline);
        }


		//是否跟随队长
		public virtual bool IsFollowMaster() { return false; }

		/// <summary>
		/// 添加TimeLine任务
		/// </summary>
		/// <param name="index"></param>
		/// <param name="timeMS"></param>
		/// <returns></returns>
		public TimeExpire<int> AddTimeLineTask(int index, int timeMS)
        {
            return mMultiTimeLineGroup[index].Add(timeMS);
        }
        /// <summary>
        /// 强制移除TimeLine任务
        /// </summary>
        /// <param name="index"></param>
        /// <param name="task"></param>
        /// <returns></returns>
        public bool RemoveTimeLineTask(int index, TimeExpire<int> task)
        {
            return mMultiTimeLineGroup[index].Remove(task);
        }
        //--------------------------------------------------------------------------------------------------------------
        /// <summary>
        /// 被击中后不会被中断(霸体),是一个叠加值
        /// </summary>
        private MultiTimeLine mNoneBlockTimeMS;
        /// <summary>
        /// 眩晕,移动限制状态,是一个叠加值
        /// </summary>
        private MultiTimeLine mStunTimeMS;
        /// <summary>
        /// 隐形,是一个叠加值
        /// </summary>
        private MultiTimeLine mInvisibleTimeMS;
        /// <summary>
        /// 无敌时间,是个叠加值
        /// </summary>
        private MultiTimeLine mInvincibleTimeMS;
        /// <summary>
        /// 沉默时间,是个叠加值
        /// </summary>
        private MultiTimeLine mSilentTimeMS;

        /// <summary>
        /// 沉默时间,是个叠加值
        /// </summary>
        private MultiTimeLine mCannotMoveTimeMS;

		/// <summary>
		/// 免控时间
		/// </summary>
		private MultiTimeLine mIgnoreControl;


		//是否刷新标记
		private bool mNeedUpdate = false;

		public bool IsCanLaunchSkill(int skillID)
		{
			if (this.IsStun || (this.IsSilent == true && skillID != this.Virtual.GetBaseSkillID()))
			{
				return false;
			}

			return true;
		}

		private void InitTimeLines()
        {
            int index;
            mNoneBlockTimeMS = RegistMultiTimeLine(out index);
            mStunTimeMS = RegistMultiTimeLine(out index);
            mInvisibleTimeMS = RegistMultiTimeLine(out index);
            mInvincibleTimeMS = RegistMultiTimeLine(out index);
            mSilentTimeMS = RegistMultiTimeLine(out index);
            mCannotMoveTimeMS = RegistMultiTimeLine(out index);
			mIgnoreControl = RegistMultiTimeLine(out index);
            mMultiTimeLineSync = new UnitSyncMultiTimeLine(this.ID);
        }
        private void UpdateTimeLines(int intervalMS)
        {
			if(mMultiTimeLineGroup == null || !mNeedUpdate)
			{
				return;
			}

			bool hasUpdate = false;
            for (int i = mMultiTimeLineGroup.Count - 1; i >= 0; --i)
            {
				if (mMultiTimeLineGroup[i].Update(intervalMS))
				{
					hasUpdate = true;
				}
            }

			// 全部timer都没有,不刷新
			if (!hasUpdate)
			{
				mNeedUpdate = false;
			}

            //不能移动单独刷新,此状态需要通知客户端
            if(this.MarkCannotMove && !this.IsCannotMove)
            {
                this.MarkCannotMove = false;
                this.RemoveActionSubState(UnitActionSubStatus.CanNotMove);
            }

            if (mMultiTimeLineSync.Update(mMultiTimeLineGroup))
            {
                queueEvent(mMultiTimeLineSync);
            }
        }


		public void MultiTimeLineRefresh(bool isAdd)
		{
			this.mNeedUpdate = true;
		}
		/// <summary>
		/// 设置霸体时间,如果当前已霸体,则取最大值
		/// </summary>
		/// <param name="timeMS"></param>
		public TimeExpire<int> SetNoneBlockTimeMS(int timeMS)
        {
			return mNoneBlockTimeMS.Add(timeMS);
        }
        /// <summary>
        /// 设置眩晕时间,如果当前已眩晕,则取最大值
        /// </summary>
        /// <param name="timeMS"></param>
        public TimeExpire<int> SetStunTimeMS(int timeMS)
        {
            TimeExpire<int> ret = mStunTimeMS.Add(timeMS);
            if (!IsStateDead)
            {
                changeState(new StateStun(this));
            }
            return ret;
        }
        /// <summary>
        /// 设置隐身时间,如果当前已隐身,则取最大值
        /// </summary>
        /// <param name="timeMS"></param>
        public TimeExpire<int> SetInvisibleTimeMS(int timeMS)
        {
            return mInvisibleTimeMS.Add(timeMS);
        }
        /// <summary>
        /// 设置无敌时间,如果当前已无敌,则取最大值
        /// </summary>
        /// <param name="timeMS"></param>
        public TimeExpire<int> SetInvincibleTimeMS(int timeMS)
        {
            return mInvincibleTimeMS.Add(timeMS);
        }
        /// <summary>
        /// 设置沉默时间
        /// </summary>
        /// <param name="timeMS"></param>
        public TimeExpire<int> SetSilentTimeMS(int timeMS)
        {
            return mSilentTimeMS.Add(timeMS);
        }

        /** 设置无法移动时间 */
        public TimeExpire<int> SetCannotMoveTimeMS(int timeMS)
        {
            this.MarkCannotMove = true;
            this.AddActionSubState(UnitActionSubStatus.CanNotMove);
            return mCannotMoveTimeMS.Add(timeMS);
        }

		/// <summary>
		/// 设置免控时间
		/// </summary>
		/// <param name="timeMS"></param>
		public TimeExpire<int> SetIgnoreControlTimeMS(int timeMS)
		{
			return mIgnoreControl.Add(timeMS);
		}

		public bool RemoveNoneBlock(TimeExpire<int> task)
        {
            return mNoneBlockTimeMS.Remove(task);
        }
        public bool RemoveStun(TimeExpire<int> task)
        {
            return mStunTimeMS.Remove(task);
        }
        public bool RemoveInvisible(TimeExpire<int> task)
        {
            return mInvisibleTimeMS.Remove(task);
        }
        public bool RemoveInvincible(TimeExpire<int> task)
        {
            return mInvincibleTimeMS.Remove(task);
        }
        public bool RemoveSilent(TimeExpire<int> task)
        {
            return mSilentTimeMS.Remove(task);
        }

        public bool RemoveCannotMove(TimeExpire<int> task)
        {
            return mCannotMoveTimeMS.Remove(task);
        }

		public bool RemoveIgnoreControl(TimeExpire<int> task)
		{
			return mIgnoreControl.Remove(task);
		}

		public void ClearNoneBlock()
        {
            mNoneBlockTimeMS.Clear();
        }
        public void ClearStun()
        {
            mStunTimeMS.Clear();
        }
        public void ClearInvisible()
        {
            mInvisibleTimeMS.Clear();
        }
        public void ClearInvincible()
        {
            mInvincibleTimeMS.Clear();
        }
        public void ClearSilent()
        {
            mSilentTimeMS.Clear();
        }
        public void ClearCannotMove()
        {
            mCannotMoveTimeMS.Clear();
        }

		public void ClearIgnoreControl()
		{
			mIgnoreControl.Clear();
		}
		#endregion
		//-----------------------------------------------------------------------------------------------------//


		//-----------------------------------------------------------------------------------------------
		#region _技能状态类_

		public PlayerSkillChangedEvent GetSkillEvent()
        {
            PlayerSkillChangedEvent evt = new PlayerSkillChangedEvent(ID);
            evt.unitFastCastRate = this.mFastCastRate;
            if (mDefaultSkill != null)
            {
                evt.baseSkill = mDefaultSkill.Data;
            }
            foreach (SkillState sk in mSkillStatus.Skills)
            {
                if (sk.GetSkillType() != XmdsSkillType.cardSkill && (evt.baseSkill == null || sk.Data.TemplateID != evt.baseSkill.ID))
                {
					sk.Data.CurUseTimes = (short)sk.OveryLayer;
					evt.skills.Add(sk.Data);
                }
            }
            return evt;
        }
        public ClientStruct.UnitSkillStatus[] GetCurrentSkillStatus()
        {
            ClientStruct.UnitSkillStatus[] ret = new ClientStruct.UnitSkillStatus[mSkillStatus.Count];
            int i = 0;
            foreach (SkillState sk in mSkillStatus.Skills)
            {
                ret[i].SkillTemplateID = (sk.Data.TemplateID);
                ret[i].PassTime = (sk.PassTime);
				ret[i].useTimes = sk.OveryLayer;
                i++;
            }
            return ret;
        }
        /// <summary>
        /// 初始化技能可用性
        /// </summary>
        public PlayerSkillActiveChangedEvent GetSyncSkillActives()
        {
            PlayerSkillActiveChangedEvent mSyncSkillActives = new PlayerSkillActiveChangedEvent(this.ID, mSkillStatus.Count);
            foreach (SkillState st in mSkillStatus.Skills)
            {
                PlayerSkillActiveChangedEvent.State sat = new PlayerSkillActiveChangedEvent.State();
                sat.SkillTemplateID = st.ID;
                sat.ST =  st.ActiveState;
                mSyncSkillActives.Skills.Add(sat);
            }
            return mSyncSkillActives;
        }

        private SkillMap mSkillStatus = new SkillMap();
        private SkillState mDefaultSkill;
        private List<SkillTemplate> mAllSkills = new List<SkillTemplate>();
        private bool mSyncSkillActivesChanged = false;

        private void updateSyncSkillActives()
        {
            if (mSyncSkillActivesChanged)
            {
                mSyncSkillActivesChanged = false;
                queueEvent(GetSyncSkillActives());
            }
        }

        protected bool DoTryAddSkill(ref SkillTemplate sk)
        {
            bool ret = true;
            if (mOnTryAddSkill != null)
            {
                foreach (TryAddSkill tryadd in mOnTryAddSkill.GetInvocationList())
                {
                    if (!tryadd.Invoke(this, ref sk))
                    {
                        ret = false;
                    }
                }
            }
            return ret;
        }

        /// <summary>
        /// 重置当前单位技能,当前单位技能重置为单位模板指定技能
        /// </summary>
        public void ResetSkills()
        {
            if (mFormula.TryResetSkill(this))
            {
                InitSkills(mInfo.BaseSkillID, mInfo.Skills.ToArray());
            }
        }

        /// <summary>
        /// 设置当前单位技能
        /// </summary>
        /// <param name="baseSkill"></param>
        /// <param name="skills"></param>
        public virtual void InitSkills(LaunchSkill baseSkill, LaunchSkill[] skills)
        {
            List<SkillState> exist = new List<SkillState>(mSkillStatus.Skills);
            mSyncSkillActivesChanged = true;
            mDefaultSkill = null;
            mSkillStatus.Clear();
            mAllSkills.Clear();
            foreach (SkillState st in exist)
            {
                if (mOnSkillRemoved != null) { mOnSkillRemoved.Invoke(this, st); }
            }

            if (baseSkill != null)
            {
                SkillTemplate st = Templates.getSkill(baseSkill.SkillID);
                if (DoTryAddSkill(ref st))
                {
                    if (st != null && !mSkillStatus.ContainsKey(baseSkill.SkillID))
                    {
                        mDefaultSkill = new SkillState(st, baseSkill, this);
                        mAllSkills.Add(st);
                        mSkillStatus.Add(mDefaultSkill);
                        if (mOnSkillAdded != null) { mOnSkillAdded.Invoke(this, mDefaultSkill); }
                    }
                }
            }
            foreach (LaunchSkill lsk in skills)
            {
                SkillTemplate stt = Templates.getSkill(lsk.SkillID);
                if (DoTryAddSkill(ref stt))
                {
                    if (stt != null && !mSkillStatus.ContainsKey(lsk.SkillID))
                    {
                        SkillState sk = new SkillState(stt, lsk, this);
                        mAllSkills.Add(stt);
                        mSkillStatus.Add(sk);
                        if (mOnSkillAdded != null) { mOnSkillAdded.Invoke(this, sk); }
                    }
                }
            }
            if (IsInZone)
            {
                Parent.queueObjectEvent(this, GetSkillEvent());
            }
            if (mOnSkillChanged != null)
            {
                mOnSkillChanged.Invoke(this, mDefaultSkill, mSkillStatus.SkillsArray);
            }
        }
        /// <summary>
        /// 设置当前单位技能
        /// </summary>
        /// <param name="baseSkill"></param>
        /// <param name="skills"></param>
        public void InitSkills(SkillTemplate baseSkill, SkillTemplate[] skills)
        {
            List<SkillState> exist = new List<SkillState>(mSkillStatus.Skills);
            mSyncSkillActivesChanged = true;
            mDefaultSkill = null;
            mSkillStatus.Clear();
            mAllSkills.Clear();
            foreach (SkillState st in exist)
            {
                if (mOnSkillRemoved != null) { mOnSkillRemoved.Invoke(this, st); }
            }

            if (baseSkill != null)
            {
                if (DoTryAddSkill(ref baseSkill))
                {
                    if (baseSkill != null && !mSkillStatus.ContainsKey(baseSkill.ID))
                    {
                        mDefaultSkill = new SkillState(baseSkill, new LaunchSkill(baseSkill.ID), this);
                        mAllSkills.Add(baseSkill);
                        mSkillStatus.Add(mDefaultSkill);
                        if (mOnSkillAdded != null) { mOnSkillAdded.Invoke(this, mDefaultSkill); }
                    }
                }
            }
            foreach (SkillTemplate ssk in skills)
            {
                SkillTemplate stt = ssk;
                if (DoTryAddSkill(ref stt))
                {
                    if (stt != null && !mSkillStatus.ContainsKey(stt.ID))
                    {
                        LaunchSkill lsk = null;
                        foreach(LaunchSkill _lsk in mInfo.Skills)
                        {
                            if (_lsk.SkillID == stt.ID)
                            {
                                lsk = _lsk;
                                break;
                            } 
                        }
                        if (lsk == null)
                            lsk = new LaunchSkill(stt.ID);

                        SkillState state = new SkillState(stt, lsk, this);
						mAllSkills.Add(stt);
                        mSkillStatus.Add(state);
                        if (mOnSkillAdded != null) { mOnSkillAdded.Invoke(this, state); }
                    }
                }
            }
            if (IsInZone)
            {
                Parent.queueObjectEvent(this, GetSkillEvent());
            }
            if (mOnSkillChanged != null)
            {
                mOnSkillChanged.Invoke(this, mDefaultSkill, mSkillStatus.SkillsArray);
            }
        }

        public SkillState AddSkill(SkillTemplate st, bool autoLaunch, bool is_default = false)
        {
            if (DoTryAddSkill(ref st))
            {
                if (st != null && !mSkillStatus.ContainsKey(st.ID))
                {
                    mSyncSkillActivesChanged = true;
                    SkillState state = new SkillState(st, new LaunchSkill(st.ID, autoLaunch), this);
                    mAllSkills.Add(st);
                    mSkillStatus.Add(state);
                    if (is_default)
                    {
                        mDefaultSkill = state;
                    }
                    if (IsInZone)
					{
						st.CurUseTimes = (short)state.OveryLayer;
						Parent.queueObjectEvent(this, new PlayerSkillAddedEvent(ID, st, is_default));
					}
                    if (mOnSkillAdded != null) { mOnSkillAdded.Invoke(this, state); }
                    if (mOnSkillChanged != null) { mOnSkillChanged.Invoke(this, mDefaultSkill, mSkillStatus.SkillsArray); }
                    return state;
                }
            }
            return null;
        }
        public SkillState RemoveSkill(int skillTemplateID)
        {
            SkillState state = mSkillStatus.RemoveByKey(skillTemplateID);
            if (state != null)
            {
                mSyncSkillActivesChanged = true;
                mAllSkills.RemoveAll((t) => { return (t.TemplateID == skillTemplateID); });
                if (state == mDefaultSkill)
                {
                    mDefaultSkill = null;
                }
                if (IsInZone) { Parent.queueObjectEvent(this, new PlayerSkillRemovedEvent(ID, skillTemplateID)); }
                if (mOnSkillRemoved != null) { mOnSkillRemoved.Invoke(this, state); }
                if (mOnSkillChanged != null) { mOnSkillChanged.Invoke(this, mDefaultSkill, mSkillStatus.SkillsArray); }
            }
            return state;
        }

        public SkillTemplate DefaultSkill
        {
            get
            {
                if (mDefaultSkill != null)
                {
                    return mDefaultSkill.Data;
                }
                return null;
            }
        }

        public SkillState DefaultSkillStatus()
        {
            return mDefaultSkill;
        }

        public IEnumerable<SkillState> SkillStatus
        {
            get
            {
                return mSkillStatus.Skills;
            }
        }

        public SkillTemplate getSkill(int skillID)
        {
            SkillState st = mSkillStatus.Get(skillID);
            if (st != null)
            {
                return st.Data;
            }
            return null;
        }

        public SkillState getSkillState(int skillID)
        {
            SkillState st = mSkillStatus.Get(skillID);
            if (st != null)
            {
                return st;
            }
            return null;
        }

        public void onSkillHitTarget()
        {
            if (mOnSkillHitTarger != null) mOnSkillHitTarger.Invoke();
        }

        /// <summary>
        /// 获得当前随机可释放的技能
        /// </summary>
        /// <param name="expectTarget"></param>
        /// <returns></returns>
        public virtual SkillState getRandomLaunchableExpectSkill(SkillTemplate.CastTarget expectTarget)
        {
            int rand = RandomN.Next(0, mAllSkills.Count);
            for (int si = mAllSkills.Count - 1; si >= 0; --si)
            {
                SkillTemplate st = mAllSkills[CMath.cycNum(rand, si, mAllSkills.Count)];
                if (st.ExpectTarget == expectTarget)
                {
                    SkillState sst = mSkillStatus.Get(st.GetID());
                    if (sst.LaunchSkill.AutoLaunch && sst.TryLaunch() && sst.CanAutoLaunch())
                    {
                        return sst;
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 获得当前随机可释放的技能
        /// </summary>
        /// <param name="target"></param>
        /// <param name="expectTarget"></param>
        /// <param name="reason"></param>
        /// <param name="checkRange"></param>
        /// <returns></returns>
        public virtual SkillState getRandomLaunchableExpectSkill(InstanceUnit target, SkillTemplate.CastTarget expectTarget, AttackReason reason = AttackReason.Tracing, bool checkRange = false)
        {
            int rand = RandomN.Next(0, mAllSkills.Count);
            for (int si = mAllSkills.Count - 1; si >= 0; --si)
            {
                SkillTemplate st = mAllSkills[CMath.cycNum(rand, si, mAllSkills.Count)];
                if (st.ExpectTarget == expectTarget)
                {
                    SkillState sst = mSkillStatus.Get(st.GetID());
                    if (sst.LaunchSkill.AutoLaunch && sst.TryLaunch() && Parent.IsAttackable(this, target, expectTarget, reason, st))
                    {
                        if (!checkRange || sst.checkTargetRange(target))
                        {
                            return sst;
                        }
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 获得当前随机可释放的技能
        /// </summary>
        /// <returns></returns>
        public virtual SkillState getRandomLaunchableSkill()
        {
            int rand = RandomN.Next(0, mAllSkills.Count);
            for (int si = mAllSkills.Count - 1; si >= 0; --si)
            {
                SkillTemplate st = mAllSkills[CMath.cycNum(rand, si, mAllSkills.Count)];
                SkillState sst = mSkillStatus.Get(st.GetID());
                if (sst.TryLaunch())
                {
                    return sst;
                }
            }
            return null;
        }
        public void getKeepSkills(List<int> keeps, List<LaunchSkill> ret)
        {
            foreach (SkillState st in mSkillStatus.Skills)
            {
                if (keeps.Contains(st.ID))
                {
                    ret.Add(st.LaunchSkill);
                }
            }
        }


        private void updateSkills()
        {
            //int intervalMS = Parent.UpdateIntervalMS;
			//for (int i = 0; i < mSkillStatus.Count; i++)
			//{
			//    SkillState st = mSkillStatus.GetAt(i);
			//    st.Update(intervalMS);
			//}

			mSkillStatus.update(Parent.UpdateIntervalMS);
		}


        protected virtual void clearSkills()
        {
            this.mSkillStatus.Clear();
        }
        // Skills
        class SkillMap
        {
            private HashMap<int, SkillState> Map = new HashMap<int, SkillState>();
            private List<SkillState> For = new List<SkillState>();

            public int Count { get { return For.Count; } }
            public IEnumerable<SkillState> Skills { get { return For; } }
            public SkillState[] SkillsArray { get { return For.ToArray(); } }

            public SkillState GetAt(int i)
            {
                return For[i];
            }
            public SkillState Get(int id)
            {
                return Map.Get(id);
            }
            public void Add(SkillState state)
            {
                if (!Map.ContainsKey(state.ID))
                {
                    Map.Put(state.ID, state);
                    For.Add(state);
                }
            }
            public SkillState RemoveByKey(int id)
            {
                SkillState ret = Map.RemoveByKey(id);
                if (ret != null)
                {
                    For.Remove(ret);
                }
                return ret;
            }
            public bool ContainsKey(int id)
            {
                return Map.ContainsKey(id);
            }
            public void Clear()
            {
                Map.Clear();
                For.Clear();
            }

			public void update(int intervalMS)
			{
				foreach (SkillState st in this.For)
				{
					st.Update(intervalMS);
				}
			}
        }

		public delegate void ISkillCDStatusChange(SkillState skill, bool iscd);

		public class SkillState
        {
			// 技能CD状态更改监听
			readonly private List<ISkillCDStatusChange> mSkillCDStatusChange = new List<ISkillCDStatusChange>();

			readonly public SkillTemplate Data;
            readonly public LaunchSkill LaunchSkill;
            readonly public InstanceUnit Owner;
            private SkillActiveState current_state = SkillActiveState.Active;
            private int total_cd_time;
            private int decrease_total_timems;
			private int trigger_decrease_times;			//机制触发,减少CD

			// 叠层
			private int overLayer = -1;

            /// <summary>
            /// 从技能开始时的逝去时间
            /// </summary>
            private int pass_time;
            /// <summary>
            /// 最后CD完成时间
            /// </summary>
            private int stop_time;
            /// <summary>
            /// 如果是多段攻击,记录段数
            /// </summary>
            private int action_step = -1;
            private int lockActionStep = -1;         //锁定执行序列号

			// 是否是多段式技能
			private bool mCanStoreTimes = false;

			/// <summary>
			/// 多段攻击自动下段
			/// </summary>
			private bool auto_increase_action_step = true;
            /// <summary>
            /// 当前是否在冷却
            /// </summary>
            private bool is_cd = false;

            /// <summary>
            /// 当前是否在多段攻击允许时间内
            /// </summary>
            private bool is_in_mutil_time = true;

            /// <summary>
            /// 当前释放技能时的状态机
            /// </summary>
            private StateSkill state;
            private float action_speed;

            public int ID { get { return Data.ID; } }
            /// <summary>
            /// 当前技能是否在转CD
            /// </summary>
            public bool IsCD { get { return is_cd; } }

            public SkillActiveState ActiveState { get { return current_state; } }
            public bool IsActive { get { return current_state == SkillActiveState.Active || current_state == SkillActiveState.ActiveAndHide; } }
            public bool IsPauseOnDeactive { get { return current_state == SkillActiveState.DeactiveAndPause; } }

            public XmdsSkillType GetSkillType() { return this.Data.Properties.GetSkillType(); }

			//是否是多段式技能
			private byte mMaxMutilStep = 0;

			//代码逻辑控制cd
			private bool mCodeControl_HasNext;
            
            /// <summary>
            /// 当前技能是否放完
            /// </summary>
            public bool IsDone
            {
                get
                {
                    if (Data.IsCoolDownWithAction)
                    {
                        if (state == null)
                            return true;
                        if (state.IsDone)
                            return true;
                        if (state.IsCancelableBySkill)
                            return true;
                        return false;
                    }
                    else if (this.IsMutilAction() && this.IsHasNext())//多段式攻击
                    {
						if (is_in_mutil_time)
						{
							return true;
						}
					}

                    return !is_cd;
                }
            }

			public bool CanAutoLaunch()
			{
				return this.stop_time == 0 || this.GetSkillType() == XmdsSkillType.normalAtk || this.stop_time + 2000 < this.pass_time || this.IsInMutilTime;
			}

			public bool IsCodeConttrolCD()
			{
				return this.mCodeControl_HasNext;
			}

            /// <summary>
            /// CD 需要的总时间
            /// </summary>
            public int TotalCDTime
            {
                get { return total_cd_time - this.trigger_decrease_times; } set { total_cd_time = value; }
            }

            /// <summary>
            /// CD 需要的总时间
            /// </summary>
            public bool IsInMutilTime
            {
                get { return is_in_mutil_time; } set { is_in_mutil_time = value; }
            }

            public void ResetTotalTime()
            {
                this.total_cd_time = Data.ToUnitSkillTotalTime(Owner.mFastCastRate) - decrease_total_timems;
                this.total_cd_time = Math.Max(0, this.total_cd_time);
            }

            public int PassTime
            {
                get { return pass_time; }
            }

			public int OveryLayer
			{
				get { return this.overLayer; }
			}

			public void ResetPassTime()
			{
				this.pass_time = 0;
			}

			public void SetCDStates(bool cdStatus)
			{
				this.is_cd = cdStatus;

				for (int i = 0; i < mSkillCDStatusChange.Count; i++)
				{
					mSkillCDStatusChange[i].Invoke(this, this.is_cd);
				}
			}

			public void ResgistSkillCDChangeListen(ISkillCDStatusChange listen)
			{
				if(listen != null)
				{
					this.mSkillCDStatusChange.Add(listen);
				}
			}


            public bool IsMutilAction()
            {
				return Data.IsSingleAction && (Data.ActionQueue.Count > 1);
			}

            public bool IsHasNext()
            {
                bool isHasNext =  this.ActionIndex < this.mMaxMutilStep;

				if(!isHasNext && this.Data.ActionQueue.Count > this.ActionIndex && this.Data.ActionQueue[this.ActionIndex].IsCancelBySkillNext)
				{
					isHasNext = true;
				}

				return isHasNext;
			}

			public byte GetMaxMutilStep()
			{
				return this.mMaxMutilStep;
			}

			public int GetMaxSteps()
			{
				return this.mMaxMutilStep > 0 ? Math.Min(this.mMaxMutilStep, this.Data.ActionQueue.Count-1) : (this.Data.ActionQueue.Count-1);
			}

            public UnitActionData GetNextAction()
            {
                if(this.ActionIndex + 1 >= this.Data.ActionQueue.Count)
                {
                    return null;
                }

                return this.Data.ActionQueue[this.ActionIndex + 1];
            }

            public UnitActionData GetCurAction()
            {
                if (this.ActionIndex < 0 || this.ActionIndex >= this.Data.ActionQueue.Count)
                {
                    return null;
                }

                return this.Data.ActionQueue[this.ActionIndex];
            }

            public float ActionSpeed { get { return action_speed; } }
            public int ActionIndex { get { return action_step; }}
            public int LockActionStep { get { return lockActionStep; } set { lockActionStep = value; } }

            public object Tag { get; set; }

			public bool CanStoreTimes { get { return this.mCanStoreTimes; }}

			internal SkillState(SkillTemplate data, LaunchSkill skill, InstanceUnit owner)
            {
                this.Owner = owner;
                this.Data = data;
				this.mCanStoreTimes = (this.Data.Properties.GetSkillUseTimes() > 1 && this.Data.Properties.GetSkillAddTimeInterval() > 0);
				//默认有最大层数
				if (this.mCanStoreTimes)
				{
					this.overLayer = this.Data.Properties.GetSkillUseTimes();
				}

				this.LaunchSkill = skill;
                this.total_cd_time = Data.ToUnitSkillTotalTime(Owner.mFastCastRate) - decrease_total_timems;
                this.pass_time = int.MaxValue / 2;
                this.action_speed = data.ActionSpeedRate + Owner.__mSkillActionSpeedRate;

				// 多段式技能,但是只能释放一段
				if(Data.IsSingleAction && (Data.ActionQueue.Count > 1))
				{
					for (int i = 0; i < Data.ActionQueue.Count; i++)
					{
						this.mMaxMutilStep = (byte)i;
						if (Data.ActionQueue[i].SigleActionType == ActionEnum.forbidNext || Data.ActionQueue[i].SigleActionType == ActionEnum.forbidNext_lock
						|| Data.ActionQueue[i].SigleActionType == ActionEnum.forbidNext_showTime)
						{							
							break;
						}
					}				
				}
            }

            //设置自动释放
            public void setAutoLaunch(bool AutoLaunch)
            {
                this.LaunchSkill.AutoLaunch = AutoLaunch;
            }

			public void setMaxMutilStep(int vlaue)
			{
				this.mMaxMutilStep = (byte)vlaue;
			}

			public void SetActionIndex(int index)
			{
				this.action_step = index;
			}

			// 设置机制冷却缩减时间
			public void setTriggerDecreaseTime(int time, bool notify = false)
			{
				this.trigger_decrease_times = time;

				// time==0是开始释放时的重置
				if(notify)
				{
					PlayerCDEvent evt = new PlayerCDEvent(this.Owner.ID);
					evt.is_decrease_time = true;
					evt.is_all = false;
					evt.decrease_timeMS = time;
					evt.skill_template_id = this.LaunchSkill.SkillID;
					this.Owner.Parent.queueObjectEvent(this.Owner, evt);
				}
			}

			/// <summary>
			/// 检测目标距离
			/// </summary>
			/// <returns></returns>
			public bool checkTargetRange(InstanceUnit targetUnit)
			{
				if (Data.AttackMustBeInRange && Data.AttackAngle == 0)
				{
					if (targetUnit != null)
					{
						float rg = Owner.GetSkillAttackRange(this.Data, targetUnit);
						if (Collider.Object_HitBody_TouchRound(targetUnit, Owner.X, Owner.Y, rg))
						{
							return true;
						}
					}
					return false;

				}
				return true;
			}

			/// <summary>
			/// 检测目标距离
			/// </summary>
			/// <returns></returns>
			public bool checkTargetInAttackRange(InstanceUnit targetUnit, LaunchSkillParam param)
			{
				//只处理怪物的自动战斗,玩家控制不了
				if (this.Owner.IsMonster && this.Data.AttackKeepRange > 0)
				{
					targetUnit = targetUnit == null ? this.Owner.Parent.getUnit(param.TargetUnitID) : targetUnit;
					if (targetUnit != null && CMath.getDistance(targetUnit.X, targetUnit.Y, this.Owner.X, this.Owner.Y) < Data.AttackKeepRange)
					{
						return false;
					}
				}

				if (this.Data.AttackRange > 0)
				{
					targetUnit = targetUnit == null ? this.Owner.Parent.getUnit(param.TargetUnitID) : targetUnit;
					if (targetUnit != null && CMath.getDistance(targetUnit.X, targetUnit.Y, this.Owner.X, this.Owner.Y) > (Owner.GetSkillAttackRange(this.Data) + targetUnit.BodyBlockSize))
					{
						return false;
					}
				}

				return true;
			}

			public void SetDecreaseTotalTimeMS(int timeMS)
            {
                this.decrease_total_timems = timeMS;
            }

			public void AddDecreaseTotalTimeMS(int timeMS)
			{
				this.decrease_total_timems += timeMS;
			}

            public int GetDecreaseTotalTimeMS()
            {
                return this.decrease_total_timems;
            }

			/// <summary>
			/// 指定技能动作
			/// </summary>
			/// <param name="step"></param>
			public void Reset(bool init = false)
            {
                this.action_step = -1;
				if (!init)
				{
					this.IsInMutilTime = false;
				}				
            }
            /// <summary>
            /// 设置是否自动控制多段攻击(如果要手动指定播放技能,则设置为False)
            /// </summary>
            /// <param name="at"></param>
            public void SetAutoIncreaseActionIndex(bool at)
            {
                this.auto_increase_action_step = at;
            }

            internal void Launch(StateSkill s, LaunchSkillParam param)
            {
                this.NextAction();
				this.total_cd_time = this.GetDefTotalCDTime();
				this.pass_time = 0;
                this.state = s;
                this.SetCDStates(true);					
			}

			private int GetDefTotalCDTime()
			{
				int cd_time = 0;
				cd_time = Data.ToUnitSkillTotalTime(Owner.mFastCastRate) - decrease_total_timems;
				if(this.GetSkillType() == XmdsSkillType.normalAtk)
				{
					cd_time = (int)(cd_time / (Owner.GetAttackSpeed() * 0.0001f));
				}
				else
				{
					cd_time = (int)((1.0f - Math.Min(XmdsConstConfig.SKILL_CD_REDUCE_MAX, Owner.SkillCdReduce) * 0.0001f) * cd_time);
				}
				
				cd_time = Math.Max(0, cd_time);

				return cd_time;
			}

			public void updateOverLayer(int value)
			{
				this.overLayer = value;

				//通知叠层
				var queData = new PlayerSkillUseTimeChangedEvent(this.Owner.ID, this.Data.ID, (byte)this.overLayer);
				queData.hasNext = (byte)((this.OveryLayer >= this.Data.Properties.GetSkillUseTimes()) ? 0 : 1);
				this.Owner.queueEvent(queData);
			}

            public void StartCD(int total_time = 0)
            {
                if (total_time > 0)
                {
                    this.total_cd_time = Math.Max(0, total_time - decrease_total_timems);
                }
                else
                {
                    //this.total_cd_time = Data.ToUnitSkillTotalTime(Owner.mFastCastRate) - decrease_total_timems;
                    //this.total_cd_time = Math.Max(0, this.total_cd_time);

					this.total_cd_time = this.GetDefTotalCDTime();
				}
                this.pass_time = 0;
                this.SetCDStates(true);
                Owner.queueEvent(new PlayerSkillTimeChangedEvent(Owner.ID, ID, this.pass_time, this.TotalCDTime));
            }

			public void LogicToCD()
			{
				this.mCodeControl_HasNext = true;
				this.StartCD();
			}

			public void SetCodeControlNext()
			{
				this.mCodeControl_HasNext = false;
			}

			public void ForceIntoCD()
			{
				this.is_in_mutil_time = false;
				this.action_step = -1;
				this.StartCD();
			}

            internal void Stop(StateSkill s)
            {
                this.state = null;
                // CD 依靠动作结束
                if (Data.IsCoolDownWithAction)
                {
                    this.SetCDStates(false);
                    this.stop_time = this.pass_time;
                }
            }
            internal void Update(int intervalMS)
            {
                if (!IsActive && IsPauseOnDeactive)
                {
                    return;
                }
                this.pass_time += intervalMS;

				if(this.CanStoreTimes)
				{
					if(this.overLayer < Data.Properties.GetSkillUseTimes() && this.pass_time >= Data.Properties.GetSkillAddTimeInterval())
					{
						this.pass_time = 0;
						this.updateOverLayer(this.overLayer + 1);
					}
				}
				else if (is_cd && !Data.IsCoolDownWithAction)
                {
                    // 技能 CD
                    if (this.pass_time >= TotalCDTime)
                    {
                        if(this.IsMutilAction() && (this.is_in_mutil_time || (this.action_step >= Data.ActionQueue.Count)))
                        {
							if(this.action_step < Data.ActionQueue.Count && this.action_step > 0 && 
								(Data.ActionQueue[this.action_step].SigleActionType == ActionEnum.chargeAtk || Data.ActionQueue[this.action_step].SigleActionType == ActionEnum.IsAutoNext))
							{
								pass_time = 0;
								return;
							}
							else
							{
								this.Reset();
								this.StartCD();
							}                           
                        }
                        else
                        {
                            this.is_in_mutil_time = true;
                            this.SetCDStates(false);
                            this.stop_time = this.pass_time;
							//Console.WriteLine("out cd : " + TimeUtil.GetTimestampMS());
                        }
                    }
                }
            }

            public bool TryLaunch()
            {
                if (!IsActive)
                {
                    return false;
                }
				if (!this.Owner.IsCanLaunchSkill(Data.TemplateID))
				{
					return false;
				}

				//if (Owner.__mCurrentHP.Value >= Data.CostHP)
                {
                    return IsDone;
                }				

                //return false;
            }
            public int NextAction()
            {
                if (Data.IsSingleAction && auto_increase_action_step)
                {
                    int action_time = this.TotalCDTime;
                  
                    // 是放技能时,处于多段攻击连击冷却时间范围
                    //if (pass_time - stop_time < Data.SingleActionCoolDownMS || pass_time < (action_time + Data.SingleActionCoolDownMS))
                    if (this.action_step < 0)
                    {
                        this.action_step = 0;
                    }
					else
					{
						if (Data.IsCoolDownWithAction)
						{
							action_time = Data.ActionQueue[action_step % Data.ActionQueue.Count].TotalTimeMS;
						}

						if (this.IsMutilAction())
						{
							if (this.IsInMutilTime || (this.Data.IsCoolDownWithAction && this.IsDone) || (!this.IsDone && this.action_step < this.mMaxMutilStep))
							{
								this.action_step += 1;
								this.action_step = (byte)(action_step % Data.ActionQueue.Count);

								//if (this.action_step >= Data.ActionQueue.Count || !IsCanLaunchNextStepByPlayer(Data.ActionQueue[this.action_step]))
								//{
								//	this.action_step = 0;
								//	this.is_in_mutil_time = false;
								//}
							}
						}
					}                  
				}
                return action_step;
            }

			public bool IsCanLaunchNextStepByPlayer(UnitActionData actionData)
			{
				// = this.Data.ActionQueue[this.ActionIndex];
				if (actionData.SigleActionType == ActionEnum.forbidNext || 
					actionData.SigleActionType == ActionEnum.forbidNext_lock)
				{
					return false;
				}

				return true;
			}


            internal void ClearCD()
            {
                this.pass_time = TotalCDTime;
            }
            internal void DecreaseSkillCD(int timeMS)
            {
                if (!Data.IsCoolDownWithAction)
                {
                    this.pass_time += timeMS;
                }
            }
            internal void DecreaseSkillCD_Pct(float percent)
            {
                if (!Data.IsCoolDownWithAction)
                {
                    this.pass_time += (int)(TotalCDTime * percent);
                }
            }
            internal void SetPassTime(int passtime)
            {
                if (!Data.IsCoolDownWithAction)
                {
                    if (passtime != this.pass_time)
                    {
                        this.pass_time = passtime;
                        Owner.queueEvent(new PlayerSkillTimeChangedEvent(Owner.ID, ID, this.pass_time, this.total_cd_time));
                        if (pass_time < TotalCDTime)
                        {
                            this.SetCDStates(true);
                        }
                    }
                }
            }
            internal bool TrySetActive(SkillActiveState state)
            {
                if (state != current_state)
                {
                    this.current_state = state;
                    this.Owner.mSyncSkillActivesChanged = true;
                    return true;
                }
                return false;
            }

        }
        /// <summary>
        /// 设置技能可用性
        /// </summary>
        /// <param name="skillTemplateID"></param>
        /// <param name="active"></param>
        /// <param name="pause_on_deactive"></param>
        public void SetSkillActive(int skillTemplateID, bool active, bool pause_on_deactive = false)
        {
            SkillState st = getSkillState(skillTemplateID);
            if (st != null)
            {
                if (active)
                    st.TrySetActive(SkillActiveState.Active);
                else if (pause_on_deactive)
                    st.TrySetActive(SkillActiveState.DeactiveAndPause);
                else
                    st.TrySetActive(SkillActiveState.Deactive);
            }

			//标记冻结
			this.Virtual.SetSkillActive(skillTemplateID, active, pause_on_deactive);

		}
        public void SetSkillActive(int skillTemplateID, SkillActiveState state)
        {
            SkillState st = getSkillState(skillTemplateID);
            if (st != null)
            {
                st.TrySetActive(state);
            }
        }

        /// <summary>
        /// 清除技能CD
        /// </summary>
        /// <param name="skillTemplateID"></param>
        public void ClearSkillCD(int skillTemplateID)
        {
            SkillState ss = getSkillState(skillTemplateID);
            if (ss != null)
            {
                ss.ClearCD();
                PlayerCDEvent evt = new PlayerCDEvent(ID);
                evt.is_clear = true;
                evt.is_all = false;
                evt.skill_template_id = skillTemplateID;
                Parent.queueObjectEvent(this, evt);
            }
        }
        /// <summary>
        /// 清除所有技能CD
        /// </summary>
        public void ClearAllSkillCD()
        {
            foreach (SkillState ss in mSkillStatus.Skills)
            {
                ss.ClearCD();
            }
            PlayerCDEvent evt = new PlayerCDEvent(ID);
            evt.is_clear = true;
            evt.is_all = true;
            Parent.queueObjectEvent(this, evt);
        }
        /// <summary>
        /// 减少当前CD固定时间
        /// </summary>
        /// <param name="skillTemplateID"></param>
        /// <param name="updateTimeMS"></param>
        public void DecreaseSkillCD(int skillTemplateID, int updateTimeMS)
        {
            SkillState ss = getSkillState(skillTemplateID);
            if (ss != null)
            {
                ss.DecreaseSkillCD(updateTimeMS);
                PlayerCDEvent evt = new PlayerCDEvent(ID);
                evt.is_decrease_time = true;
                evt.is_all = false;
                evt.decrease_timeMS = updateTimeMS;
                evt.skill_template_id = skillTemplateID;
                Parent.queueObjectEvent(this, evt);
            }
        }

        /// <summary>
        /// 减少当前CD固定时间
        /// </summary>
        /// <param name="updateTimeMS"></param>
        public void DecreaseAllSkillCD(int updateTimeMS)
        {
            foreach (SkillState ss in mSkillStatus.Skills)
            {
                ss.DecreaseSkillCD(updateTimeMS);
            }
            PlayerCDEvent evt = new PlayerCDEvent(ID);
            evt.is_decrease_time = true;
            evt.is_all = true;
            evt.decrease_timeMS = updateTimeMS;
            Parent.queueObjectEvent(this, evt);
        }

        public void DecreaseSkillCD_Pct(int skillTemplateID, float percent)
        {
            SkillState ss = getSkillState(skillTemplateID);
            if (ss != null)
            {
                ss.DecreaseSkillCD_Pct(percent);
                PlayerCDEvent evt = new PlayerCDEvent(ID);
                evt.is_decrease_pct = true;
                evt.is_all = false;
                evt.decrease_pct = percent;
                evt.skill_template_id = skillTemplateID;
                Parent.queueObjectEvent(this, evt);
            }
        }
        public void DecreaseAllSkillCD_Pct(float percent)
        {
            foreach (SkillState ss in mSkillStatus.Skills)
            {
                ss.DecreaseSkillCD_Pct(percent);
            }
            PlayerCDEvent evt = new PlayerCDEvent(ID);
            evt.is_decrease_pct = true;
            evt.is_all = true;
            evt.decrease_pct = percent;
            Parent.queueObjectEvent(this, evt);
        }
        public void SetSkillPassTime(int skillID, int passTimeMS)
        {
            SkillState ss = this.getSkillState(skillID);
            if (ss != null)
            {
                ss.SetPassTime(passTimeMS);
            }
        }
        public void StartSkillCD(int skillID, int totalTimeMS = 0)
        {
            SkillState ss = this.getSkillState(skillID);
            if (ss != null)
            {
                ss.StartCD(totalTimeMS);
            }
        }


        #endregion

        //-----------------------------------------------------------------------------------------------

        #region _BUFF状态类_

        public ClientStruct.UnitBuffStatus[] GetCurrentBuffStatus()
        {
            List<ClientStruct.UnitBuffStatus> ret = new List<ClientStruct.UnitBuffStatus>(mBuffs.Count);
            mBuffs.ForEachRead((buff) =>
            {
                if (buff.Data.ClientVisible)
                {
                    ClientStruct.UnitBuffStatus bf = new ClientStruct.UnitBuffStatus();
                    bf.BuffTemplateID = (buff.Data.TemplateID);
                    bf.SenderID = buff.SenderID;
                    bf.IsEquip = buff.IsEquip;
                    bf.TotalTime = buff.Data.LifeTimeMS;
                    bf.PassTime = (buff.PassTimeMS);
                    bf.OverlayLevel = buff.OverlayLevel;
                    ret.Add(bf);
                }
                return false;
            });
            return ret.ToArray();
        }

		public bool IshasControlBuff(Predicate<BuffTemplate> cb)
		{
            bool hasControlBuff = false;
            mBuffs.ForEachReadTrueReturn((buff) =>
            {
                if (cb(buff.Data))
                {
                    hasControlBuff = true;
                    return true;
                }

                return false;
            });


            return hasControlBuff;
		}


		public void GetAllBuffStatus(List<BuffState> ret)
        {
            mBuffs.ForEachRead((bf) =>
            {
                ret.Add(bf);
                return false;
            });
        }
        private class BuffMap
        {
            class BuffList : IEnumerable<InstanceUnit.BuffState>
            {
                readonly public BuffTemplate bufft;
                private HashMap<uint, InstanceUnit.BuffState> list;
                private InstanceUnit.BuffState last;

                public BuffList(BuffTemplate bufft)
                {
                    this.bufft = bufft;
                    this.list = new HashMap<uint, BuffState>(1);
                }
                public void Add(InstanceUnit.BuffState bs)
                {
                    if (bs.Data.IsDuplicating)
                    {
                        list.Add(bs.SenderID, bs);
                    }
                    else
                    {
                        list.Add(0, bs);
                    }
                    last = bs;
                }
                public InstanceUnit.BuffState Remove(uint unit_id)
                {
                    if (bufft.IsDuplicating)
                    {
                        InstanceUnit.BuffState bs = list.RemoveByKey(unit_id);
                        if (bs != null && bs == last)
                        {
                            if (list.Count > 0)
                            {
                                foreach (InstanceUnit.BuffState bf in list.Values)
                                {
                                    last = bf;
                                    break;
                                }
                            }
                            else
                            {
                                last = null;
                            }
                        }
                        return bs;
                    }
                    else
                    {
                        last = null;
                        return list.RemoveByKey(0);
                    }
                }
                public void Clear(List<InstanceUnit.BuffState> cleared)
                {
                    last = null;
                    cleared.AddRange(list.Values);
                    list.Clear();
                }
                public InstanceUnit.BuffState Get(uint unit_id)
                {
                    return list.Get(unit_id);
                }
                public int Count { get { return list.Count; } }
                public InstanceUnit.BuffState Last { get { return last; } }
                IEnumerator<BuffState> IEnumerable<BuffState>.GetEnumerator()
                {
                    return list.Values.GetEnumerator();
                }
                System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
                {
                    return list.Values.GetEnumerator();
                }
            }
            private HashMap<int, BuffList> mObjects = new HashMap<int, BuffList>();
            private List<BuffState> mObjectsList = new List<BuffState>();
            private bool dirty = true;

            public int Count { get { return mObjects.Count; } }
            //-----------------------------------------------------------------------
            // read
            //-----------------------------------------------------------------------
            public InstanceUnit.BuffState GetObject(int id)
            {
                BuffList list;
                if (mObjects.TryGetValue(id, out list))
                {
                    return list.Last;
                }
                return null;
            }
            public void GetObjects(int id, List<InstanceUnit.BuffState> ret)
            {
                BuffList list;
                if (mObjects.TryGetValue(id, out list))
                {
                    ret.AddRange(list);
                }
            }
            public InstanceUnit.BuffState GetObject(int buff_id, uint unit_id)
            {
                BuffList list;
                if (mObjects.TryGetValue(buff_id, out list))
                {
                    return list.Get(unit_id);
                }
                return null;
            }

            //-----------------------------------------------------------------------
            // write
            //-----------------------------------------------------------------------
            public bool RemoveObject(InstanceUnit.BuffState bs)
            {
                BuffList list;
                if (mObjects.TryGetValue(bs.ID, out list))
                {
                    dirty = true;
                    return list.Remove(bs.SenderID) != null;
                }
                return false;
            }
            public InstanceUnit.BuffState RemoveObject(int buffID, uint unit_id)
            {
                BuffList list;
                if (mObjects.TryGetValue(buffID, out list))
                {
                    dirty = true;
                    return list.Remove(unit_id);
                }
                return null;
            }

            public void RemoveObjects(int buffID, List<InstanceUnit.BuffState> removed)
            {
                BuffList list;
                if (mObjects.TryGetValue(buffID, out list))
                {
                    dirty = true;
                    list.Clear(removed);
                }
            }

            public void AddObject(InstanceUnit.BuffState obj)
            {
                BuffList list = mObjects.Get(obj.ID);
                if (list == null)
                {
                    list = new BuffList(obj.Data);
                    mObjects.Add(obj.ID, list);
                }
                list.Add(obj);
                dirty = true;
            }

            private IList<BuffState> Refresh()
            {
                if (dirty)
                {
                    dirty = false;
                    mObjectsList.Clear();
                    foreach (BuffList list in mObjects.Values)
                    {
                        foreach (InstanceUnit.BuffState buff in list)
                        {
                            mObjectsList.Add(buff);
                        }
                    }
                }
                return mObjectsList;
            }

            private void ToList(List<BuffState> ret)
            {
                foreach (BuffList list in mObjects.Values)
                {
                    foreach (InstanceUnit.BuffState buff in list)
                    {
                        ret.Add(buff);
                    }
                }
            }

            //-----------------------------------------------------------------------
            // 
            //-----------------------------------------------------------------------
            /// <summary>
            /// 
            /// </summary>
            /// <param name="action">返回true终止迭代!</param>
            public void ForEachRead(Predicate<InstanceUnit.BuffState> action)
            {
                foreach (BuffList list in mObjects.Values)
                {
                    foreach (InstanceUnit.BuffState buff in list)
                    {
                        if (action(buff))
                        {
                            return;
                        }
                    }
                }
            }
			public bool ForEachReadTrueReturn(Predicate<InstanceUnit.BuffState> action)
			{
				foreach (BuffList list in mObjects.Values)
				{
					foreach (InstanceUnit.BuffState buff in list)
					{
						if (action(buff))
						{
							return true;
						}
					}
				}

				return false;
			}

			
			/// <summary>
			/// 
			/// </summary>
			/// <param name="action">返回true终止迭代!</param>
			public void ForEachWrite(Predicate<InstanceUnit.BuffState> action)
            {
                using (var list = ListObjectPool<BuffState>.AllocAutoRelease())
                {
                    ToList(list);
                    for (int i = 0; i < list.Count; i++)
                    {
                        if (action(list[i]))
                        {
                            return;
                        }
                    }
                }
            }

            public void Update(InstanceZone parent)
            {
                IList<BuffState> list = Refresh();
                for (int i = 0; i < list.Count; i++)
                {
                    BuffState bs = list[i];
                    bs.OnUpdate(parent);
                    if (bs.IsEnd() && !bs.MarkRemove)
                    {
                        this.RemoveObject(bs);
                        bs.OnEnd(BuffState.EndResult_ByTimeUp);
                    }
                }
            }

        }

        public class BuffState
        {

            public const string EndResult_ByTimeUp = "time_up";
            public const string EndResult_ByReplaced = "replaced";
            public const string EndResult_ByClientRemoved = "client_removed";
            public const string EndResult_ByCatgoryExclusive = "catgory_exclusive";
            public const string EndResult_ByCode = "code";
			public const string ENDResult_HuDunBreak = "HuDunBreak";

            readonly private BuffTemplate mData;
            readonly private InstanceUnit mOwner;
            readonly private InstanceUnit sender;

            private TimeExpire<int> st_stun;
            private TimeExpire<int> st_invisible;
            private TimeExpire<int> st_invincible;
            private TimeExpire<int> st_silent;
            private TimeExpire<int> st_canmove;
			private TimeExpire<int> st_ignoreControl;

			private int mBuffExtData;                //buff扩展字段

            private TimeInterval<BuffTemplate.KeyFrame> interval;
            private PopupKeyFrames<BuffTemplate.KeyFrame> keyframes;
            private int total_time;
            private int passtime;
            private byte overlay_level;
            public BuffTemplate Data { get { return mData; } }
            public int ID { get { return mData.ID; } }
            public byte OverlayLevel { get { return overlay_level; }}
            public int PassTimeMS { get { return passtime; } }
            public int LifeTimeMS { get { return total_time; } }
            public bool IsEquip { get; private set; }
            public uint SenderID { get { return sender.ID; } }

            public int BuffExtData { get { return mBuffExtData; }  set { mBuffExtData = value; } }

            public InstanceZone Zone { get { return mOwner.Parent; } }
            public InstanceUnit Owner { get { return mOwner; } }
            public InstanceUnit Sender { get { return sender; } }
            public object Tag { get; set; }


			//释放时位置信息
			private Vector2 mHitPos = new Vector2();

			public bool MarkRemove { get; set; }

			//set和get放在一起虽然爽,但是可读性真一般
			public void SetLayerLevel(byte value)
			{
				this.overlay_level = value;
			}

			internal BuffState(BuffTemplate data, InstanceUnit unit, InstanceUnit sender, byte overlay_level, bool forever, bool isControlBuf)
            {
                this.mData = data;  
                this.mOwner = unit;
                this.sender = sender;

                this.IsEquip = forever;
                this.overlay_level = overlay_level;
                this.passtime = 0;
				this.MarkRemove = false; 
                this.interval = new TimeInterval<BuffTemplate.KeyFrame>(data.HitIntervalMS);
                this.interval.FirstTimeEnable = data.FirstTimeEnable;
                this.interval.Tag = data.HitKeyFrame;
                this.keyframes = new PopupKeyFrames<BuffTemplate.KeyFrame>();
                this.keyframes.AddRange(data.KeyFrames);
                this.total_time = data.LifeTimeMS;


                //控制增幅
                if (sender.__mControledTimeAdd != 0 && (mData.IsSilent || mData.MakeStun || isControlBuf))
                {
                    this.total_time = (int)(Math.Max(0.0f, 1.0f + unit.__mControledTimeAdd * 0.0001f) * this.total_time);
                }

                //韧性,控制减
                if (unit.ControledTimeReduce != 0 && (mData.IsSilent || mData.MakeStun || isControlBuf))
                {
                    this.total_time = (int)(Math.Max(0.0f, 1.0f - unit.ControledTimeReduce * 0.0001f) * this.total_time);
                }
            }

            internal void OnStart()
            {
				mHitPos.SetX(mOwner.X);
				mHitPos.SetY(mOwner.Y);
				mOwner.mFormula.OnBuffBegin(mOwner, this, sender);

                if (mData.MakeStun)
                {
                    this.st_stun = mOwner.SetStunTimeMS(total_time);
                }
                if (mData.IsInvisible)
                {
                    this.st_invisible = mOwner.SetInvisibleTimeMS(total_time);
                }
                if (mData.IsInvincible)
                {
                    this.st_invincible = mOwner.SetInvincibleTimeMS(total_time);
                }
                if (mData.IsSilent)
                {
                    this.st_silent = mOwner.SetSilentTimeMS(total_time);
                }

                if(!mData.IsCanMove)
                {
                    this.st_canmove = mOwner.SetCannotMoveTimeMS(total_time);
                }

				// 免疫控制
				if(mData.IgnoreControl)
				{
					this.st_ignoreControl = mOwner.SetIgnoreControlTimeMS(total_time);
				}

                if (mData.UnitTrigger != null)
                {
                    mOwner.addTrigger(mData.UnitTrigger.TriggerTemplateID);
                }
                if (mData.UnitChangeSkills)
                {
                    if (mData.UnitKeepSkillsID != null && mData.UnitKeepSkillsID.Count > 0)
                    {
                        using (var keeps = ListObjectPool<LaunchSkill>.AllocAutoRelease())
                        {
                            mOwner.getKeepSkills(mData.UnitKeepSkillsID, keeps);
                            keeps.AddRange(mData.UnitSkills);
                            mOwner.InitSkills(mData.UnitBaseSkillID, keeps.ToArray());
                        }
                    }
                    else
                    {
                        mOwner.InitSkills(mData.UnitBaseSkillID, mData.UnitSkills.ToArray());
                    }
                }
                mOwner.doGotBuff(this);
                if (mData.ClientVisible)
                {
                    //Console.WriteLine("获得剑影 - " + this.BuffExtData);
                    mOwner.queueEvent(new UnitLaunchBuffEvent(mOwner.ID, this.ID, this.SenderID, 
                        this.LifeTimeMS, this.IsEquip, overlay_level, this.BuffExtData));
                }
            }

            internal void OnEnd(string result, bool replace = false)
            {
                this.passtime = total_time;
				this.MarkRemove = true;
                mOwner.doLostBuff(this);
                if (this.st_stun != null)
                {
                    mOwner.mStunTimeMS.Remove(st_stun);
                }
                if (this.st_invisible != null)
                {
                    mOwner.mInvisibleTimeMS.Remove(st_invisible);
                }
                if (this.st_invincible != null)
                {
                    mOwner.mInvisibleTimeMS.Remove(st_invincible);
                }
                if (this.st_silent != null)
                {
                    mOwner.mSilentTimeMS.Remove(st_silent);
                }
                if(this.st_canmove != null)
                {
                    mOwner.mCannotMoveTimeMS.Remove(st_canmove);
                }

				if(this.st_ignoreControl != null)
				{
					mOwner.mIgnoreControl.Remove(st_ignoreControl);
				}

                if (mData.UnitTrigger != null)
                {
                    mOwner.removeTrigger(mData.UnitTrigger.TriggerTemplateID);
                }
                if (mData.UnitChangeSkills)
                {
                    mOwner.ResetSkills();
                }
                if (mData.EndKeyFrame != null)
                {
                    doKeyFrame(mData.EndKeyFrame);
                }
                mOwner.mFormula.OnBuffEnd(mOwner, this, result, replace);
                if (this.Data.ClientVisible)
                {
                    if (!replace)
                    {
                        mOwner.queueEvent(new UnitStopBuffEvent(mOwner.ID, this.ID, SenderID));
                    }
                }
            }

            internal void OnUpdate(InstanceZone zone)
            {
                using (var kfs = ListObjectPool<BuffTemplate.KeyFrame>.AllocAutoRelease())
                {
                    if (keyframes.PopKeyFrames(passtime, kfs) > 0)
                    {
                        foreach (BuffTemplate.KeyFrame kf in kfs)
                        {
                            doKeyFrame(kf);
                        }
                    }
                }
                if (interval.Update(zone.UpdateIntervalMS))
                {
                    doKeyFrame(mData.HitKeyFrame);
                    mOwner.mFormula.OnBuffUpdate(mOwner, this, interval.TotalTickCount);
                }
                passtime += zone.UpdateIntervalMS;
            }

            private void doKeyFrame(BuffTemplate.KeyFrame kf)
            {
                if (kf != null)
                {
                    if (kf.Attack != null)
                    {
                        mOwner.doHitAttack(sender, new AttackSource(this, kf.Attack));
                    }
                    if (kf.Spell != null)
                    {
						if(kf.Spell.SenderUnit == LaunchSpllSenderUnit.AttackerUnit)
						{
							this.sender.Parent.unitLaunchSpell(XmdsSkillType.none, sender, kf.Spell,
							 this.sender.X, this.sender.Y, mOwner.ID, null);
						}
						else
						{
							mOwner.Parent.unitLaunchSpell(XmdsSkillType.none, sender, kf.Spell,
							 mOwner.X, mOwner.Y, mOwner.ID, null);
						}                      
                    }
                    if (kf.Item != null)
                    {
                        mOwner.UseItem(kf.Item.ItemTemplateID);
                    }

					if(kf.addItem != null)
					{
						this.BuffAddItem(kf.addItem);
					}
                }
            }

			/** buff生成道具 */
			private void BuffAddItem(BuffAddItem addItem)
			{
				var itemInfo = Zone.Templates.getItem(addItem.ItemTemplateID);
				if(itemInfo == null)
				{
					log.Warn("BuffAddItem找不到指定道具: " + addItem.ItemTemplateID);
					return;
				}

				if(addItem.posType == CommonAI.Zone.BuffAddItem.PosType.HitBuffPos)
				{
					this.mOwner.Parent.AddItem(itemInfo, null, this.mHitPos.X, this.mHitPos.Y, 0, this.mOwner.Force, null, this.Owner);
				}
				else if(addItem.posType == CommonAI.Zone.BuffAddItem.PosType.BindUnitPos)
				{
					this.mOwner.Parent.AddItem(itemInfo, null, this.Owner.X, this.Owner.Y, 0, this.mOwner.Force, null, this.Owner);
				}
				else if(addItem.posType == CommonAI.Zone.BuffAddItem.PosType.PointPos)
				{
					this.mOwner.Parent.AddItem(itemInfo, null, addItem.pointX, addItem.pointY, 0, this.mOwner.Force, null, this.Owner);
				}				
			}

            public bool IsEnd()
            {
                if (Data.IsRemoveOnSenderRemoved)
                {
                    if (!sender.Enable || sender.IsDead())
                    {
                        return true;
                    }
                }

				if(Data.IsRemoveOnDead && this.mOwner.IsDead())
				{
					return true;
				}

                if (IsEquip) return false;
                return (passtime >= total_time);
            }

            public void AddLifeTimeMS(int timeMS)
            {
                this.total_time += timeMS;
            }

			//public void RefrushToMaxOverlayer()
			//{
			//	this.overlay_level = this.mData.MaxOverlay;
			//}
        }

        private BuffMap mBuffs = new BuffMap();

        /// <summary>
        /// 是否存在技能变身BUFF
        /// </summary>
        public bool IsBuffChangeSkills
        {
            get
            {
                return GetChangeSkillBuff() != null;
            }
        }
        /// <summary>
        /// 获得技能变身BUFF
        /// </summary>
        public BuffState GetChangeSkillBuff()
        {
            BuffState ret = null;
            mBuffs.ForEachRead((bs) =>
            {
                if (bs.Data.UnitChangeSkills && !bs.IsEnd())
                {
                    ret = bs;
                    return true;
                }
                return false;
            });
            return ret;
        }
        public BuffState GetBuffByID(int buffTemplateID)
        {
            return mBuffs.GetObject(buffTemplateID);
        }
        public BuffState GetBuffByIDAndSender(int buffTemplateID, uint senderUnitID)
        {
            return mBuffs.GetObject(buffTemplateID, senderUnitID);
        }


		public BuffState AddBuff(int buffID, int pointMaxOverLayer = 0, bool forever = false, bool bMaxOverlayer = false, bool bMaxReset = false)
        {
            BuffTemplate buff = Templates.getBuff(buffID);
            if (buff != null)
            {
                return this.AddBuff(buff, this, pointMaxOverLayer, forever, bMaxOverlayer, 0, false, bMaxReset);
            }

            return null;
        }
		public BuffState AddBuff(int buffID, InstanceUnit sender, int pointMaxOverLayer = 0, bool forever = false, 
			bool bMaxOverlayer = false, bool bMaxReset = false, int buffExt = 0, int addLyers = 0)
        {
            BuffTemplate buff = Templates.getBuff(buffID);
            if (buff != null)
            {
                return this.AddBuff(buff, sender, pointMaxOverLayer, forever, bMaxOverlayer, buffExt, false, bMaxReset, addLyers);
            }

            return null;
        }

		/** 编辑器直接编写增加buff接口 */
		public BuffState AddBuff(LaunchBuff buff, InstanceUnit sender, bool forever = false)
		{
			//如果绑定了事件id,就表示去触发事件
			if (buff.BuffID == 0 && buff.BindEventID > 0)
			{
				BattleFunction.GetInstance().TriggrBattleFunction(buff.BindEventID, this.Virtual, sender == null ? null : sender.Virtual);
				return null;
			}

			return this.AddBuff(buff.BuffID, sender, 0, forever);
		}

		/// <summary>
		/// 增加Buff
		/// </summary>
		/// <param name="forever">如果为True,则表示Buff不受时间CD控制</param>
		public virtual BuffState AddBuff(BuffTemplate buff, InstanceUnit sender, int pointMaxOverLayer = 0, bool forever = false,
			bool bMaxOverlayer = false, int buffExt = 0, bool isControlBuf = false, bool maxReset = false, int addLayers = 0)
        {
            object tag = null;
            if (mFormula.TryAddBuff(this, sender, ref buff, out tag))
            {
                if (!forever && buff.LifeTimeMS <= 0)
                {
                    return null;
                }

				//凌驾于一切之上的免控
				if(isControlBuf && this.IsIgnoreControl)
				{
					return null;
				}

                if (!removeBuffByCatgory(buff.ID, buff.ExclusiveCatgory, buff.ExclusivePriority))
                {
                    return null;
                }

				int finalMaxOverLay = (pointMaxOverLayer <= 0) ? buff.MaxOverlay : pointMaxOverLayer;
				int overlay_level = bMaxOverlayer ? (finalMaxOverLay - 1) : 0;
                BuffState bs = mBuffs.RemoveObject(buff.ID, sender.ID);
                if (bs != null)
                {
                    if (buff.IsOverlay)
                    {
						int finalAddLayer = Math.Max(1, addLayers);
						if(bs.OverlayLevel + finalAddLayer >= finalMaxOverLay && maxReset)
						{
							overlay_level = 0;
						}
						else
						{
							overlay_level = bMaxOverlayer ? (finalMaxOverLay - 1) : (Math.Min(bs.OverlayLevel + finalAddLayer, finalMaxOverLay - 1));
						}
					}
                    bs.OnEnd(BuffState.EndResult_ByReplaced, true);
				}
				else if(addLayers > 0 && buff.MaxOverlay > 0)
				{
					overlay_level = Math.Max(0, Math.Min(buff.MaxOverlay - 1, addLayers-1));
				}

                BuffState newbs = new BuffState(buff, this, sender, (byte)overlay_level, forever, isControlBuf);
                newbs.Tag = tag;
                newbs.BuffExtData = (bs == null) ? buffExt : bs.BuffExtData;
                mBuffs.AddObject(newbs);
                newbs.OnStart();

                //System.Console.WriteLine("AddBuf - " + newbs.Data.ID + ", " + newbs.OverlayLevel);
                mFormula.SendAddBuffEvent(this, sender, buff);
   
                return newbs;
            }
            return null;
        }

        /// <summary>
        /// 移除互斥技能,根据优先级
        /// </summary>
        /// <param name="buffID"></param>
        /// <param name="catgory"></param>
        /// <param name="priority"></param>
        private bool removeBuffByCatgory(int buffID, int catgory, int priority)
        {
            if (catgory != 0)
            {
                // 检测当时有更高优先级 //
                {
                    BuffState greater_buff = null;
                    mBuffs.ForEachRead((bs) =>
                    {
                        if ((bs.ID != buffID) && (bs.Data.ExclusiveCatgory == catgory) && (bs.Data.ExclusivePriority > priority))
                        {
                            greater_buff = bs;
                            return true;
                        }
                        return false;
                    });
                    if (greater_buff != null)
                    {
                        return false;
                    }
                }
                // 移除低优先级 //
                mBuffs.ForEachWrite((bs) =>
                {
                    if ((bs.ID != buffID) && (bs.Data.ExclusiveCatgory == catgory))
                    {
                        mBuffs.RemoveObject(bs);
                        bs.OnEnd(BuffState.EndResult_ByCatgoryExclusive);
                    }
                    return false;
                });
            }
            return true;
        }

        public void removeBuff(int buffID, string result = BuffState.EndResult_ByCode)
        {
            using (var bss = ListObjectPool<BuffState>.AllocAutoRelease())
            {
                mBuffs.RemoveObjects(buffID, bss);
                if (bss.Count > 0)
                {
                    foreach (BuffState bs in bss)
                    {
                        bs.OnEnd(result);
                    }
                }
            }
        }
        public void removeBuffBySender(int buffID, uint senderUnitID, string result = BuffState.EndResult_ByCode)
        {
            BuffState bs = mBuffs.RemoveObject(buffID, senderUnitID);
            if (bs != null)
            {
                bs.OnEnd(result);
            }
        }
        public void clearBuffs(string result = BuffState.EndResult_ByCode)
        {
            mBuffs.ForEachWrite((bs) =>
            {
                if (!bs.Data.IsPassive && !bs.IsEquip)
                {
                    mBuffs.RemoveObject(bs);
                    bs.OnEnd(result);
                }
                return false;
            });
        }
        private void updateBuffs()
        {
            mBuffs.Update(Parent);
        }
        #endregion

        //---------------------------------------------------------------------------------------------------------------

        #region _被动系触发类_

        private readonly List<TriggerState> mTriggerStatus = new List<TriggerState>();

        private readonly UnitTriggerHelper mTriggerHelper;
        /// <summary>
        /// 保存被动状态
        /// </summary>
        public class TriggerState
        {
            readonly internal UnitTriggerTemplate mData;
            readonly internal InstanceUnit mOwner;
            public bool IsDamageTrigger { get; private set; }
            public bool IsAttackTrigger { get; private set; }
            public UnitTriggerTemplate Data { get { return mData; } }
            public object Tag { get; set; }

            private long launch_time;

            internal TriggerState(UnitTriggerTemplate data, InstanceUnit unit)
            {
                this.mData = data;
                this.mOwner = unit;
                this.IsDamageTrigger = false;
                this.IsAttackTrigger = false;
                this.launch_time = -mData.CoolDownTimeMS;
                foreach (BaseTriggerEvent evt in data.Triggers)
                {
                    UnitTriggerEventTypeAttribute ut = PropertyUtil.GetAttribute<UnitTriggerEventTypeAttribute>(evt.GetType());
                    foreach (Type dtype in ut.DelegateTypes)
                    {
                        if (dtype == typeof(DamageHandler))
                        {
                            this.IsDamageTrigger = true;
                        }
                        else if (dtype == typeof(AttackHandler))
                        {
                            this.IsAttackTrigger = true;
                        }
                    }
                }
            }
            internal void Start(InstanceUnit target)
            {
                if (IsActive)
                {
                    this.launch_time = mOwner.Parent.PassTimeMS;

                    uint targetID = 0;
                    Vector2 targetPos = new Vector2(mOwner.X, mOwner.Y);
                    if (target != null)
                    {
                        targetPos.SetX(target.X);
                        targetPos.SetY(target.Y);
                        targetID = target.ID;
                    }

                    // 如果关键帧绑定特效
                    if (mData.DoEffect != null)
                    {
                        mOwner.queueEvent(new UnitEffectEvent(mOwner.ID, mData.DoEffect));
                    }
                    // 如果关键帧绑定释放法术
                    if (mData.DoSpell != null)
                    {
                        mOwner.Parent.unitLaunchSpell(XmdsSkillType.none, mOwner, mData.DoSpell, mOwner.X, mOwner.Y, 0, targetPos);
                    }
                    // 如果关键帧绑定自己释放BUFF
                    if (mData.DoBuff != null)
                    {
                        mOwner.AddBuff(mData.DoBuff, mOwner);
                    }
                    // 如果关键帧绑定单位位移
                    if (mData.DoSkill != null)
                    {
                        mOwner.launchSkill(mData.DoSkill.SkillID, new InstanceUnit.LaunchSkillParam(targetID, targetPos));
                    }
					//召唤
					if (mData.DoSummon != null)
					{
						mOwner.Parent.unitSummonUnit(mOwner, mData.DoSummon);
					}

					mOwner.mFormula.OnTriggerStart(mOwner, this, target);
                }
            }

            public bool Test(AttackSource source)
            {
                if (IsActive)
                {
                    foreach (BaseTriggerEvent evt in mData.Triggers)
                    {
                        if (!mOwner.mFormula.TryLaunchTrigger(mOwner, mData, evt, source) || !evt.Test(mOwner, source))
                        {
                            return false;
                        }
                    }
                    return true;
                }
                return false;
            }
            /// <summary>
            /// 是否处于冷却状态
            /// </summary>
            public bool IsActive
            {
                get { return (launch_time + mData.CoolDownTimeMS) < mOwner.Parent.PassTimeMS; }
            }

        }

        private void updateTriggers(bool slowRefresh)
        {
            this.mFormula.OnUpdateTriggerSkill(this, Parent.UpdateIntervalMS, slowRefresh);
        }

        public void addTriggers(ICollection<LaunchTrigger> triggers)
        {
            foreach (LaunchTrigger launch in triggers)
            {
                addTrigger(launch.TriggerTemplateID);
            }
        }

        public bool containsTrigger(int tgID)
        {
            for (int i = mTriggerStatus.Count - 1; i >= 0; --i)
            {
                if (mTriggerStatus[i].mData.ID == tgID)
                {
                    return true;
                }
            }
            return false;
        }
        public TriggerState findTrigger(int tgID)
        {
            for (int i = mTriggerStatus.Count - 1; i >= 0; --i)
            {
                if (mTriggerStatus[i].mData.ID == tgID)
                {
                    return mTriggerStatus[i];
                }
            }
            return null;
        }

        public bool addTrigger(UnitTriggerTemplate trigger)
        {
            if (!containsTrigger(trigger.ID))
            {
                TriggerState ts = new TriggerState(trigger, this);
                mTriggerStatus.Add(ts);
            }
            return false;
        }

        public bool addTrigger(int triggerID)
        {
            if (!containsTrigger(triggerID))
            {
                UnitTriggerTemplate tg = Templates.getUnitTrigger(triggerID);
                if (tg != null)
                {
                    TriggerState ts = new TriggerState(tg, this);
                    mTriggerStatus.Add(ts);
                }
            }
            return false;
        }

        public void removeTrigger(int tgID)
        {
            TriggerState bs = findTrigger(tgID);
            if (bs != null)
            {
                mTriggerStatus.Remove(bs);
            }
        }

        public bool startTrigger(int tgID, InstanceUnit target)
        {
            TriggerState bs = findTrigger(tgID);
            if (bs != null && bs.IsActive)
            {
                bs.Start(target);
                return true;
            }
            return false;
        }

        public void clearTriggers()
        {
            mTriggerStatus.Clear();
        }

        /// <summary>
        /// 如果被攻击,尝试启动单位触发器
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="source"></param>
        public void TryStartDamageTriggers(InstanceUnit attacker, AttackSource source)
        {
            foreach (TriggerState ts in this.mTriggerStatus)
            {
                if (ts.IsDamageTrigger && ts.Test(source))
                {
                    ts.Start(attacker);
                }
            }
        }
        /// <summary>
        /// 如果攻击别人,尝试启动触发器
        /// </summary>
        /// <param name="target"></param>
        /// <param name="source"></param>
        public void TryStartAttackTriggers(InstanceUnit target, AttackSource source)
        {
            foreach (TriggerState ts in this.mTriggerStatus)
            {
                if (ts.IsAttackTrigger && ts.Test(source))
                {
                    ts.Start(target);
                }
            }
        }

        public class UnitTriggerHelper
        {
            private readonly InstanceUnit unit;

            public UnitTriggerHelper(InstanceUnit unit)
            {
                this.unit = unit;
                unit.OnDamage += this.onUnitDamage;
                unit.OnAttack += this.onUnitAttack;
            }


            public void onUnitDamage(InstanceUnit obj, InstanceUnit attacker, int hp, AttackSource source)
            {
                unit.TryStartDamageTriggers(attacker, source);
            }
            public void onUnitAttack(InstanceUnit obj, InstanceUnit target, int hp, AttackSource source)
            {
                unit.TryStartAttackTriggers(target, source);
            }
        }

        #endregion

        //---------------------------------------------------------------------------------------------------------------

        #region _背包和道具_



        public ClientStruct.UnitItemStatus[] GetCurrentItemStatus()
        {
            ClientStruct.UnitItemStatus[] ret = new ClientStruct.UnitItemStatus[mInventorySlots.Count];
            int i = 0;
            foreach (InventorySlot item in mInventorySlots)
            {
                ret[i].ItemTemplateID = item.ItemTemplateID;
                ret[i].Count = item.Count;
                i++;
            }
            return ret;
        }
        public class InventorySlot
        {
            readonly public int Index;
            readonly public InstanceUnit Owner;
            public InventorySlot(int index, InstanceUnit owner)
            {
                this.Index = index;
                this.Owner = owner;
            }

            public bool IsEmpty
            {
                get
                {
                    return (Item == null);
                }
            }
            public int ItemTemplateID
            {
                get
                {
                    if (Item != null)
                        return Item.TemplateID;
                    return 0;
                }
            }
            public ItemTemplate Item { get; private set; }
            public int Count { get; private set; }

            internal int AddItem(ItemTemplate item, int count)
            {
                if (item == null) return 0;
                if (count <= 0) return 0;
                if (this.IsEmpty)
                {
                    // 背包为空 //
                    this.Item = item;
                    this.Count = Math.Min(this.Item.MaxStackCount, count);
                    this.Owner.doGotInventoryItem(this, item, Index, count);
                    return this.Count;
                }
                else if (item.TemplateID == this.ItemTemplateID)
                {
                    int oldcount = this.Count;
                    // 道具类型一致, 堆叠 //
                    this.Count = Math.Min(this.Item.MaxStackCount, this.Count + count);
                    if (oldcount != this.Count)
                    {
                        this.Owner.doGotInventoryItem(this, item, Index, count);
                        return this.Count - oldcount;
                    }
                    return 0;
                }
                return 0;
            }
            internal int TryUse(int count)
            {
                if (IsEmpty) return 0;
                if (!Item.IsInventoryUseable) return 0;
                if (Owner.tryUseItem(Item, Owner))
                {
                    return Math.Min(count, this.Count);
                }
                return 0;
            }
            internal int Use(int count)
            {
                if (IsEmpty) return 0;
                if (!Item.IsInventoryUseable) return 0;
                if (Owner.tryUseItem(Item, Owner))
                {
                    int used = 0;
                    count = Math.Min(count, this.Count);
                    for (int i = 0; i < count; i++)
                    {
                        Owner.UseItem(Item);
                        this.Count--;
                        used++;
                        if (Count == 0)
                        {
                            break;
                        }
                    }
                    this.Owner.doLostInventoryItem(this, Item, Index, count);
                    if (Count == 0)
                    {
                        this.Item = null;
                    }
                    return used;
                }
                return 0;
            }
            internal int Drop(int count)
            {
                if (IsEmpty) return 0;
                count = Math.Min(count, this.Count);
                this.Count -= count;
                if (this.Count <= 0)
                {
                    this.Count = 0;
                }
                this.Owner.doLostInventoryItem(this, Item, Index, count);
                if (this.Count == 0)
                {
                    this.Item = null;
                }
                return count;
            }
            internal int Clean()
            {
                return Drop(this.Count);
            }
        }

        private List<InventorySlot> mInventorySlots = new List<InventorySlot>();

        private HashMap<int, TimeExpire<ItemTemplate>> mCoolDownItems = new HashMap<int, TimeExpire<ItemTemplate>>();

        private List<TimeExpire<ItemTemplate>> mRemoved = new List<TimeExpire<ItemTemplate>>();

        private void InitBagSlots()
        {
            for (int i = 0; i < mInfo.InventorySize; i++)
            {
                mInventorySlots.Add(new InventorySlot(i, this));
            }
        }


        private bool tryUseItem(ItemTemplate item, InstanceUnit item_creater)
        {
            if (mFormula.TryUseItem(this, item, item_creater))
            {
                if (item.UseCoolDownTimeMS > 0)
                {
                    if (IsItemCoolDown(item.ID))
                    {
                        return false;
                    }
                    return true;
                }
                return true;
            }
            return false;
        }
        private void beginUseItem(ItemTemplate item)
        {
            if (item.UseCoolDownTimeMS > 0)
            {
                mCoolDownItems.Put(item.ID, new TimeExpire<ItemTemplate>(item, item.UseCoolDownTimeMS));
            }
        }
        private void updateItems()
        {
            int intervalMS = Parent.UpdateIntervalMS;
            
            /*
            using (var removed = ListObjectPool<TimeExpire<ItemTemplate>>.AllocAutoRelease())
            {
                foreach (TimeExpire<ItemTemplate> expire in mCoolDownItems.Values)
                {
                    if (expire.Update(intervalMS))
                    {
                        removed.Add(expire);
                    }
                }
                if (removed.Count > 0)
                {
                    foreach (TimeExpire<ItemTemplate> expire in removed)
                    {
                        if (expire.IsEnd)
                        {
                            mCoolDownItems.RemoveByKey(expire.Tag.ID);
                        }
                    }
                }
            }*/

			if(mCoolDownItems.Count <= 0)
			{
				return;
			}

            //换一个写法
			mRemoved.Clear();
            foreach (TimeExpire<ItemTemplate> expire in mCoolDownItems.Values)
            {
                if (expire.Update(intervalMS))
                {
                    mRemoved.Add(expire);
                }
            }

            if (mRemoved.Count > 0)
            {
                foreach (TimeExpire<ItemTemplate> expire in mRemoved)
                {
                    if (expire.IsEnd)
                    {
                        mCoolDownItems.RemoveByKey(expire.Tag.ID);
                    }
                }
                mRemoved.Clear();
            }           
        }
        protected virtual void clearItemSlots()
        {
            foreach (var slot in mInventorySlots)
            {
                slot.Clean();
            }
            mInventorySlots.Clear();
            mCoolDownItems.Clear();
        }


        /// <summary>
        /// 检测此道具是否在CD
        /// </summary>
        /// <param name="itemTemplateID"></param>
        /// <returns></returns>
        public bool IsItemCoolDown(int itemTemplateID)
        {
            if (mCoolDownItems.ContainsKey(itemTemplateID))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 添加道具到白空的背包
        /// </summary>
        /// <param name="item"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public int AddItemToEmptyInventory(ItemTemplate item, int count = 1)
        {
            if (item == null) return 0;
            if (count <= 0) return 0;
            if (!item.IsDuplicateInventory || item.HoldingLimit > 0)
            {
                int holding = GetItemCountInInventory(item.ID);
                if (!item.IsDuplicateInventory)
                {
                    if (holding > 0)
                    {
                        return 0;
                    }
                    count = 1;
                }
                if (item.HoldingLimit > 0)
                {
                    if (holding >= item.HoldingLimit)
                    {
                        return 0;
                    }
                    if (holding + count > item.HoldingLimit)
                    {
                        count = item.HoldingLimit - holding;
                    }
                    if (count <= 0) return 0;
                }
            }
            int added = 0;
            //优先堆叠//
            for (int i = 0; i < mInventorySlots.Count; i++)
            {
                InventorySlot slot = mInventorySlots[i];
                if (slot.ItemTemplateID == item.ID)
                {
                    added += slot.AddItem(item, count - added);
                    if (added >= count)
                    {
                        break;
                    }
                }
            }
            //使用空闲格子//
            for (int i = 0; i < mInventorySlots.Count; i++)
            {
                InventorySlot slot = mInventorySlots[i];
                added += slot.AddItem(item, count - added);
                if (added >= count)
                {
                    break;
                }
            }
            return added;
        }

        /// <summary>
        /// 添加道具到指定背包
        /// </summary>
        /// <param name="item"></param>
        /// <param name="index"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public int AddItemToInventory(ItemTemplate item, int index, int count = 1)
        {
            if (item == null) return 0;
            if (count <= 0) return 0;
            if (!item.IsDuplicateInventory || item.HoldingLimit > 0)
            {
                int holding = GetItemCountInInventory(item.ID);
                if (!item.IsDuplicateInventory)
                {
                    if (holding > 0)
                    {
                        return 0;
                    }
                    count = 1;
                }
                if (item.HoldingLimit > 0)
                {
                    if (holding >= item.HoldingLimit)
                    {
                        return 0;
                    }
                    if (holding + count > item.HoldingLimit)
                    {
                        count = item.HoldingLimit - holding;
                    }
                    if (count <= 0) return 0;
                }
            }
            if (index >= 0 && index < mInventorySlots.Count)
            {
                InventorySlot slot = mInventorySlots[index];
                return slot.AddItem(item, count);
            }
            return 0;
        }
        /// <summary>
        /// 添加道具到指定背包
        /// </summary>
        /// <param name="itemTemplateID"></param>
        /// <param name="index"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public int AddItemToInventory(int itemTemplateID, int index, int count = 1)
        {
            if (count <= 0) return 0;
            return AddItemToInventory(Templates.getItem(itemTemplateID), index, count);
        }


        private int UseItemInternal(InventorySlot slot, int count)
        {
            if (slot.Item != null)
            {
                if (slot.Item.UseInProgressTimeMS > 0)
                {
                    count = slot.TryUse(count);
                    if (count > 0)
                    {
                        this.startPickProgressSelf(slot.Item.UseInProgressTimeMS, (s, p) =>
                        {
                            slot.Use(count);
                        });
                    }
                    return count;
                }
                else
                {
                    return slot.Use(count);
                }
            }
            return 0;
        }
        /// <summary>
        /// 使用背包的道具
        /// </summary>
        /// <param name="index"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public int UseInventoryItem(int index, int count = 1)
        {
            if (count <= 0) return 0;
            if (index >= 0 && index < mInventorySlots.Count)
            {
                InventorySlot slot = mInventorySlots[index];
                return UseItemInternal(slot, count);
            }
            return 0;
        }
        public int UseInventoryItemByType(int itemTemplateID, int count = 1)
        {
            if (count <= 0) return 0;
            for (int i = 0; i < mInventorySlots.Count; i++)
            {
                InventorySlot slot = mInventorySlots[i];
                if (slot.ItemTemplateID == itemTemplateID)
                {
                    return UseItemInternal(slot, count);
                }
            }
            return 0;
        }


        public int DropInventoryItemByIndex(int index, int count = 1)
        {
            if (count <= 0) return 0;
            if (index >= 0 && index < mInventorySlots.Count)
            {
                InventorySlot slot = mInventorySlots[index];
                return slot.Drop(count);
            }
            return 0;
        }
        public int DropInventoryItemByType(int itemTemplateID, int count = 1)
        {
            if (count <= 0) return 0;
            int droped = 0;
            for (int i = 0; i < mInventorySlots.Count; i++)
            {
                InventorySlot slot = mInventorySlots[i];
                if (slot.ItemTemplateID == itemTemplateID)
                {
                    droped += slot.Drop(count);
                    if (droped >= count)
                    {
                        break;
                    }
                }
            }
            return droped;
        }
        public int ClearInventoryItemByIndex(int index)
        {
            if (index >= 0 && index < mInventorySlots.Count)
            {
                InventorySlot slot = mInventorySlots[index];
                return slot.Clean();
            }
            return 0;
        }
        public int ClearInventoryItemByType(int itemTemplateID)
        {
            int droped = 0;
            for (int i = 0; i < mInventorySlots.Count; i++)
            {
                InventorySlot slot = mInventorySlots[i];
                if (slot.ItemTemplateID == itemTemplateID)
                {
                    droped += slot.Clean();
                }
            }
            return droped;
        }

        /// <summary>
        /// 背包内是否有此道具
        /// </summary>
        /// <param name="itemTemplateID"></param>
        /// <returns></returns>
        public bool ContainsItemInInventory(int itemTemplateID)
        {
            for (int i = 0; i < mInventorySlots.Count; i++)
            {
                InventorySlot slot = mInventorySlots[i];
                if (slot.ItemTemplateID == itemTemplateID)
                {
                    return true;
                }
            }
            return false;
        }
        public int GetItemCountInInventory(int itemTemplateID)
        {
            int ret = 0;
            for (int i = 0; i < mInventorySlots.Count; i++)
            {
                InventorySlot slot = mInventorySlots[i];
                if (slot.ItemTemplateID == itemTemplateID)
                {
                    ret += slot.Count;
                }
            }
            return ret;
        }



        #endregion

        //---------------------------------------------------------------------------------------------------------------
        #region _物理运动_



        public bool IsFallingDown
        {
            get
            {
                if (mCurrentFallingDown != null)
                    return !mCurrentFallingDown.IsEnd;
                return false;
            }
        }
        public bool IsDamageFallingDown
        {
            get
            {
                StateDamage damage = (this.CurrentState as StateDamage);
                if (damage != null)
                {
                    return damage.IsFallingDown;
                }
                return false;
            }
        }
        public bool IsPhysicalMove
        {
            get
            {
                if (mCurrentStartMove != null)
                    return !mCurrentStartMove.IsEnd;
                return false;
            }
        }

        private FallingDown mCurrentFallingDown;
        private HitMoveSpeed mCurrentStartMove;

        private void updatePhysical()
        {
            if (mCurrentFallingDown != null && mCurrentFallingDown.Update(Parent.UpdateIntervalMS))
            {
                mCurrentFallingDown = null;
            }
            if (mCurrentStartMove != null && mCurrentStartMove.Update(Parent.UpdateIntervalMS))
            {
                mCurrentStartMove = null;
            }
        }

        /// <summary>
        /// 开始自由落体
        /// </summary>
        /// <param name="launcher"></param>
        /// <param name="speedZ"></param>
        /// <param name="gravity"></param>
        /// <param name="zlimit"></param>
        /// <returns></returns>
        public virtual FallingDown StartFly(object launcher, float speedZ, float gravity, float zlimit)
        {
            mCurrentFallingDown = new FallingDown(this, speedZ, gravity, zlimit);
            return mCurrentFallingDown;
        }

        /// <summary>
        /// 开始复杂移动
        /// </summary>
        /// <param name="launcher"></param>
        /// <param name="direction"></param>
        /// <param name="rotateSpeedSEC"></param>
        /// <param name="expectlTimeMS"></param>
        /// <param name="moveSpeedSEC"></param>
        /// <param name="moveSpeedAdd"></param>
        /// <param name="moveSpeedAcc"></param>
        /// <param name="isNoneTouch"></param>
        public virtual HitMoveSpeed StartHitMove(
            object launcher,
            float direction,
            float rotateSpeedSEC,
            int expectlTimeMS,
            float moveSpeedSEC,
            float moveSpeedAdd,
            float moveSpeedAcc,
            bool isNoneTouch)
        {
            if (mCurrentStartMove != null)
            {
                mCurrentStartMove.Stop();
            }
            HitMoveSpeed move = new HitMoveSpeed(
                this,
                direction,
                rotateSpeedSEC,
                expectlTimeMS,
                moveSpeedSEC,
                moveSpeedAdd,
                moveSpeedAcc,
                isNoneTouch);
            mCurrentStartMove = move;
            return move;
        }

        /// <summary>
        /// 落体运动
        /// </summary>
        public class FallingDown
        {
            private readonly InstanceUnit unit;
            private readonly float gravity;
            private readonly float z_limit;
            private float z_speed;

            public FallingDown(InstanceUnit unit, float zspeed, float zgravity, float zlimit)
            {
                this.unit = unit;
                this.z_limit = zlimit;
                this.z_speed = zspeed;
                this.gravity = zgravity == 0 ? unit.Templates.CFG.GLOBAL_GRAVITY : zgravity;
                this.ExpectTimeMS = MoveHelper.CalculateFlyTimeMS(unit.Z, zspeed, zlimit, gravity, 10);
                this.IsEnd = false;
            }

            public bool Update(int intervalMS)
            {
                //向上受到ZLimit限制//
                unit.Z += MoveHelper.GetDistance(intervalMS, z_speed);
                unit.Z = Math.Max(0, unit.Z);
                this.IsEnd = unit.Z <= 0;
                //骤停//
                if (z_limit != 0 && z_speed > 0 && unit.Z > z_limit)
                {
                    z_speed = 0;
                }
                this.z_speed -= MoveHelper.GetDistance(intervalMS, gravity);

                return IsEnd;
            }
            public bool IsEnd { get; private set; }
            public int ExpectTimeMS { get; private set; }
            public float ZSpeedSEC { get { return z_speed; } }
            public float ZLimit { get { return z_limit; } }
        }



        public class HitMoveSpeed
        {
            private readonly InstanceUnit mOwner;
            private readonly float mStartDirection;

            private readonly float mMoveSpeedAdd;
            private readonly float mMoveSpeedAcc;
            private readonly float mRotateSpeedSEC;

            private float moveSpeedSEC;

            private TimeExpire<int> hitMoveTime;
            private FallingDown hasFly;
            private IPositionObject moveTarget;
            private bool moveTargetBody;

            private bool isNoneTouch = false;

            public HitMoveSpeed(
                InstanceUnit owner,
                float direction,
                float rotateSpeedSEC,
                int expectlTimeMS,
                float moveSpeedSEC,
                float moveSpeedAdd,
                float moveSpeedAccPct,
                bool isNoneTouch)
            {
                this.mOwner = owner;
                this.mStartDirection = direction;

                this.moveSpeedSEC = moveSpeedSEC;
                this.mMoveSpeedAdd = moveSpeedAdd;
                this.mMoveSpeedAcc = moveSpeedAccPct / 100f;
                this.mRotateSpeedSEC = rotateSpeedSEC;
                this.isNoneTouch = isNoneTouch;

                this.TotalTimeMS = expectlTimeMS;
                this.hitMoveTime = new TimeExpire<int>(TotalTimeMS);


                this.IsEnd = false;

                this.PrevX = owner.X;
                this.PrevY = owner.Y;
            }

            public void SetFly(object launcher, float moveZSpeed, float gravity, float zlimit)
            {
                if (moveZSpeed != 0)
                {
                    this.hasFly = mOwner.StartFly(launcher, moveZSpeed, gravity, zlimit);
                    this.TotalTimeMS = hasFly.ExpectTimeMS;
                    this.hitMoveTime = new TimeExpire<int>(TotalTimeMS);
                }
            }
            public void SetMoveTarget(IPositionObject target, bool targetBodyBlock)
            {
                moveTarget = target;
                moveTargetBody = targetBodyBlock;
            }

            public void Stop()
            {
                this.IsEnd = true;
            }

            public bool Update(int intervalMS)
            {
                int intervalMS_move = intervalMS;
                if (hitMoveTime.PassTimeMS + intervalMS >= hitMoveTime.TotalTimeMS)
                {
                    intervalMS_move = hitMoveTime.TotalTimeMS - hitMoveTime.PassTimeMS;
                }

                if (mRotateSpeedSEC != 0)
                {
                    mOwner.turn(MoveHelper.GetDistance(intervalMS_move, mRotateSpeedSEC));
                }
                this.PrevX = mOwner.X;
                this.PrevY = mOwner.Y;
                // 移动 //
                if (moveTarget != null)
                {
                    move(intervalMS_move, moveTarget);
                }
                else
                {
                    move(intervalMS_move, mStartDirection);
                }
                // 递增 //
                {
                    //每秒递减速度绝对值//
                    MoveHelper.UpdateSpeed(intervalMS_move, ref moveSpeedSEC, mMoveSpeedAdd, mMoveSpeedAcc);
                }
                if (hitMoveTime.PassTimeMS + intervalMS >= hitMoveTime.TotalTimeMS || hitMoveTime.Update(intervalMS)) 
                {
                    IsEnd = true;
                }
                return IsEnd;
            }

            private void move(int intervalMS, IPositionObject target)
            {
                if (moveTargetBody)
                {
                    float distance = MoveHelper.GetDistance(intervalMS, moveSpeedSEC);
                    if (CMath.includeRoundPoint(mOwner.X, mOwner.Y, target.RadiusSize + mOwner.RadiusSize + distance, target.X, target.Y))
                    {
                        return;
                    }
                }
                if (hasFly != null)
                {
                    mOwner.jumpToTarget(target.X, target.Y, moveSpeedSEC, intervalMS, IsNoneTouch);
                }
                else
                {
                    if (IsNoneTouch)
                    {
                        mOwner.jumpToTarget(target.X, target.Y, moveSpeedSEC, intervalMS, IsNoneTouch);
                    }
                    else if (mMoveSpeedAdd != 0 || mMoveSpeedAcc != 0)
                    {
                        mOwner.moveImpactTo(target.X, target.Y, moveSpeedSEC, intervalMS);
                    }
                    else
                    {
                        mOwner.moveBlockTo(target.X, target.Y, moveSpeedSEC, intervalMS);
                    }
                }
            }

            private void move(int intervalMS, float direction)
            {
                if (hasFly != null)
                {
                    mOwner.jumpTo(direction, moveSpeedSEC, intervalMS, IsNoneTouch);
                }
                else
                {
                    if (IsNoneTouch)
                    {
                        mOwner.jumpTo(direction, moveSpeedSEC, intervalMS, IsNoneTouch);
                    }
                    else if (mMoveSpeedAdd != 0 || mMoveSpeedAcc != 0)
                    {
                        mOwner.moveImpact(direction, moveSpeedSEC, intervalMS);
                    }
                    else
                    {
                        mOwner.moveBlockTo(direction, moveSpeedSEC, intervalMS);
                    }
                }
            }

            public float PrevX { get; private set; }
            public float PrevY { get; private set; }

            public bool IsFly { get { return hasFly != null; } }
            public int TotalTimeMS { get; private set; }
            public bool IsEnd { get; private set; }
            public bool IsNoneTouch
            {
                get { return isNoneTouch; }
                set { this.isNoneTouch = value; }
            }
            public float ZSpeedSEC
            {
                get
                {
                    if (hasFly != null)
                        return hasFly.ZSpeedSEC;
                    return 0;
                }
            }
        }

        #endregion
        //---------------------------------------------------------------------------------------------------------------

    }
}