using System;
using System.Collections.Generic;
using System.Text;
using CommonAI.RTS;
using CommonLang.Vector;
using CommonAI.Zone;
using CommonAI.Zone.Instance;
using CommonAI.RTS.Manhattan;
using CommonLang;
using CommonLang.Log;
using CommonAI.Zone.Formula;

using CommonAI.ZoneClient;
using CommonAI.Zone.Helper;
using CommonAI.Zone.Attributes;
using CommonLang.Property;
using static CommonAI.Zone.AttackProp;
using CommonAI.Data;

namespace CommonAI.Zone.Instance
{
    partial class InstanceUnit
    {
        //-----------------------------------------------------------------------------------------------------//
        #region SEND_EVENT

        private UnitForceSyncPosEvent mForceSync = new UnitForceSyncPosEvent();

        private UnitActionStatus mCurrentActionMainState = UnitActionStatus.Idle;
        //子状态状态
        private int mCurrentActionSubState = 0;
		//子状态扩展信息
		private short mSubStateExt = 0;


        private UnitActionStatus mLastActionStatus = 0;
        private int mLastActionSubstate = 0;

        //蓄力状态
        //private byte chargeAtkStatus = 0;

        /// <summary>
        /// 当前动做主状态
        /// </summary>
        public UnitActionStatus CurrentActionStatus
        {
            get { return mCurrentActionMainState; }
        }
        /// <summary>
        /// 当前动做子状态, 0-正常,1-隐身
        /// </summary>
        public int CurrentActionSubstate
        {
            get { return mCurrentActionSubState; }
        }


        //蓄力状态
        public byte ChargeAtkStatus { get; set; }

        public bool IsActionStatusChanged
        {
            get; private set;
        }
        public void SetActionStatus(UnitActionStatus st)
        {
            if (st == UnitActionStatus.Move && !this.Moveable)
            {
                // nothing //
            }
            else
            {
                this.mCurrentActionMainState = st;
            }
        }
        public void AddActionSubState(UnitActionSubStatus substate, short ext = 0)
        {
            this.mCurrentActionSubState = this.mCurrentActionSubState | (int)substate;
			this.mSubStateExt = ext;
			
			// 特殊状态额外信息通知
			if (this.IsPlayer && substate == UnitActionSubStatus.Stealth)
			{
				UnitStealthInfo stealInfo = new UnitStealthInfo(this.ID, 1, (short)ext);
				this.queueEvent(stealInfo);
			}
			//Console.WriteLine("add - sub - " + this.mCurrentActionSubState);
		}

        public void RemoveActionSubState(UnitActionSubStatus substate)
        {
            //有这个状态,才能进行移除
            if (this.IsHasSubState(substate))
            {
                this.mCurrentActionSubState = this.mCurrentActionSubState ^ (int)substate;

				// 特殊状态额外信息通知
				if (this.IsPlayer && substate == UnitActionSubStatus.Stealth)
                {
					UnitStealthInfo stealInfo = new UnitStealthInfo(this.ID, 0, 0);
					this.queueEvent(stealInfo);
				}
            }

			//Console.WriteLine("remove - sub - " + this.mCurrentActionSubState);
		}

        //是否拥有该子状态
        public bool IsHasSubState(UnitActionSubStatus state)
        {
            return ((this.mCurrentActionSubState & (int)state) > 0);
        }

		public void queueEvent(ObjectEvent evt, bool force = false)
        {			
            Parent.queueObjectEvent(this, evt, force);
        }

        public void queueEvent(Event evt)
        {
            Parent.queueEventInternal(evt);
        }

		public virtual bool DoAutoPick(bool ignoreInterval = false)
		{
			return false;
		}

		//通知拾取消息
		public virtual void NotifyRemoveDropItemB2C(InstanceItem item)
		{

		}

		public override void SendForceSync()
        {
            mForceSync.object_id = this.ID;
            mForceSync.X = this.X;
            mForceSync.Y = this.Y;
            mForceSync.Direction = this.Direction;
            mForceSync.UnitMainState = (byte)mCurrentActionMainState;
            this.mLastActionStatus = mCurrentActionMainState;
            mForceSync.UnitSubState = (byte)mCurrentActionSubState;
            Parent.queueObjectEvent(this, mForceSync);
			//Console.WriteLine("--------SendForceSync x:" + mForceSync.X + ", y : " + mForceSync.Y);
		}

        internal override bool updatePos(InstanceZone zone)
        {
            this.IsActionStatusChanged = (mLastActionStatus != mCurrentActionMainState) || (mLastActionSubstate != mCurrentActionSubState);
            this.mLastActionStatus = mCurrentActionMainState;
            this.mLastActionSubstate = mCurrentActionSubState;
            if (base.updatePos(zone) || IsActionStatusChanged)
            {
                return true;
            }
            return false;
        }
        protected internal virtual bool GenSyncState(ref SyncPosEvent.UnitState ret)
        {
            if (IsActionStatusChanged)
            {
                ret.SetObject(this);
                return true;
            }
            return false;
        }
        public SyncPosEvent.UnitState GetSyncState()
        {
            SyncPosEvent.UnitState ret = new SyncPosEvent.UnitState();
            ret.SetObject(this);
            return ret;
        }

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

        public abstract class State : IDisposable
        {
            private bool m_started = false;
            public InstanceUnit unit { get; private set; }
            public InstanceZone zone { get { return unit.Parent; } }
            public bool IsStarted { get { return m_started; } }
            public State(InstanceUnit unit)
            {
                this.unit = unit;
            }
            internal void start()
            {
                if (!m_started)
                {
                    m_started = true;
                    onStart();
                    if (this.mOnStart != null)
                    {
                        this.mOnStart(unit, this);
                    }
                }
            }
            internal void update()
            {
                onUpdate();
            }
            internal void stop()
            {
                if (m_started)
                {
                    m_started = false;
                    onStop();
                    if (this.mStopOnce != null)
                    {
                        var invoke = mStopOnce;
                        this.mStopOnce = null;
                        invoke.Invoke(unit, this);
                    }
                    if (this.mOnStop != null)
                    {
                        this.mOnStop.Invoke(unit, this);
                    }
                }
            }

			public virtual void MarkRemove() { }

			/// 当前状态是否可以被新状态打断
			public abstract bool onBlock(State new_state);
            protected abstract void onStart();
            protected abstract void onUpdate();
            protected abstract void onStop();

            public virtual void Dispose()
            {
                mOnStart = null;
                mOnStop = null;
                mStopOnce = null;
            }

            public delegate void StateStartHandler(InstanceUnit obj, State state);
            public delegate void StateStopHandler(InstanceUnit obj, State state);

            private StateStartHandler mOnStart;
            private StateStopHandler mOnStop;
            private StateStopHandler mStopOnce;

            [EventTriggerDescAttribute("状态机每次开始时触发")]
            public event StateStartHandler OnStart { add { mOnStart += value; } remove { mOnStart -= value; } }
            [EventTriggerDescAttribute("状态机每次结束时触发")]
            public event StateStopHandler OnStop { add { mOnStop += value; } remove { mOnStop -= value; } }
            [DescAttribute("状态机结束时触发,停止后自动清理所有监听")]
            public void AddStopOnce(StateStopHandler stop)
            {
                mStopOnce += stop;
            }

        }


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

        public class StateSpawn : State
        {
            private TimeExpire<int> timer;
            public StateSpawn(InstanceUnit unit, int timeMS)
                : base(unit)
            {
                timer = new TimeExpire<int>(timeMS);
            }

            override public bool onBlock(State new_state)
            {
				if(new_state is StateDuJie)
				{
					return true;
				}

                return timer.IsEnd;
            }
            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.Spawn);
            }
            override protected void onUpdate()
            {
                if (timer.Update(zone.UpdateIntervalMS))
                {
                    unit.doSomething();
                }
            }
            override protected void onStop()
            {
                unit.doActivated();
            }
        }

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

        /// <summary>
        /// 待机状态
        /// </summary>
        public class StateIdle : State
        {
            public StateIdle(InstanceUnit unit)
                : base(unit)
            {
            }

            override public bool onBlock(State new_state)
            {
                if (new_state is StateIdle)
                {
                    return false;
                }
                return true;
            }
            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.Idle);
            }
            override protected void onUpdate()
            {
                unit.doSomething();
                //unit.SetActionStatus(UnitActionStatus.Idle);
            }
            override protected void onStop()
            {
            }
        }
        /// <summary>
        /// 浪
        /// </summary>
        public class StateIdleMove : State
        {
            private readonly TimeExpire<int> mExpire;
            private readonly MoveAI mMoveAI;
            private readonly Vector2 mOrginPos;
            private readonly float mRange;

            private MoveBlockResult mLastResult;
            public MoveBlockResult LastMoveResult { get { return mLastResult; } }

            public StateIdleMove(InstanceUnit unit, Vector2 orginPos, int timeMS, float range)
                : base(unit)
            {
                this.mExpire = new TimeExpire<int>(timeMS);
                this.mMoveAI = new MoveAI(unit, false);
                this.mRange = Math.Abs(range);
                this.mOrginPos = orginPos;
            }
            public override bool onBlock(State new_state)
            {
                return true;
            }
            protected override void onStart()
            {
                Vector2 target = this.FindTargetPos();
                this.mMoveAI.FindPath(target.X, target.Y);
                unit.SetActionStatus(UnitActionStatus.Move);
            }
            protected override void onStop()
            {
            }
            protected override void onUpdate()
            {
                if (mExpire.Update(zone.UpdateIntervalMS))
                {
                    unit.doSomething();
                }
                else
                {
                    mLastResult = mMoveAI.Update();
                    if ((mLastResult.result & MoveResult.RESULTS_MOVE_END) != 0)
                    {
                        Vector2 target = this.FindTargetPos();
                        this.mMoveAI.FindPath(target.X, target.Y);
                    }
                }
            }
            /// <summary>
            /// 搜索要去的地方
            /// </summary>
            /// <returns></returns>
            protected virtual Vector2 FindTargetPos()
            {
                var node = zone.PathFinder.FindNearRandomMoveableNode(zone.RandomN, mOrginPos.X, mOrginPos.Y, mRange);
                if (node != null)
                {
                    return new Vector2(node.PosX, node.PosY);
                }
                return new Vector2(mOrginPos.X, mOrginPos.Y);
            }
        }

        /// <summary>
        /// 移动状态
        /// </summary>
        public class StateMove : State
        {
            private Vector2 target;
            private int minStepTime;
            private bool moveEnd = false;
            private MoveBlockResult mLastMoveResult;

            public Vector2 Target { get { return target; } }
            public bool IsMoveEnd { get { return moveEnd; } }
            public MoveBlockResult LastMoveResult { get { return mLastMoveResult; } }

            public int MinStepCheckCount { get; set; }
            public bool StopOnTouchMap { get; set; }
            public Predicate<StateMove> EndMoveAction { get; set; }

            public StateMove(InstanceUnit unit, float x, float y)
                : base(unit)
            {
                this.StopOnTouchMap = false;
                this.MinStepCheckCount = 10;
                this.target = new Vector2(x, y);
            }

            override public bool onBlock(State new_state)
            {
                return true;
            }
            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.Move);
            }
            override protected void onUpdate()
            {
                unit.SetActionStatus(UnitActionStatus.Move);
                unit.faceTo(target.X, target.Y);
                mLastMoveResult = unit.moveBlockTo(target.X, target.Y, unit.MoveSpeedSEC, zone.UpdateIntervalMS);
                if ((mLastMoveResult.result & MoveResult.MOVE_RESULT_BLOCK_MAP) != 0 && StopOnTouchMap)
                {
                    moveEnd = true;
                    if (EndMoveAction == null || !EndMoveAction(this))
                    {
                        unit.doSomething();
                    }
                }
                else if ((mLastMoveResult.result & MoveResult.RESULTS_MOVE_END) != 0)
                {
                    moveEnd = true;
                    if (EndMoveAction == null || !EndMoveAction(this))
                    {
                        unit.doSomething();
                    }
                }
                else if ((mLastMoveResult.result & MoveResult.MOVE_RESULT_MIN_STEP) != 0)
                {
                    moveEnd = true;
                    minStepTime++;
                    if (minStepTime > MinStepCheckCount)
                    {
                        if (EndMoveAction == null || !EndMoveAction(this))
                        {
                            unit.doSomething();
                        }
                    }
                }
                else
                {
                    minStepTime = 0;
                }
            }
            override protected void onStop()
            {

            }
        }

        /// <summary>
        /// 释放技能状态
        /// </summary>
        public class StateSkill : State
        {
            readonly private InstanceUnit.SkillState skill;
            readonly private SkillLaunched launched;
            readonly private AttackRangeHelper attack_range;
            private Queue<UnitActionData> action_queue;
            private LaunchSkillParam param;
            private InstanceUnit targetUnit;
            private bool is_done = false;
            private UnitActionData current_action = null;
            private int curActionTotalTimes = 0;
            private PopupKeyFrames<UnitActionData.KeyFrame> current_frames = new PopupKeyFrames<UnitActionData.KeyFrame>();
            private BitSet8 current_action_status = new BitSet8();
            private int current_pass_time = 0;
            private Vector2 move_to;
            private HitMoveSpeed start_move;
            private Vector2 body_hited_last_pos = new Vector2();
            private HashMap<uint, InstanceUnit> body_hited = new HashMap<uint, InstanceUnit>();
            private TimeExpire<int> chantExpire;
            private AstarManhattan.MWayPoint move_to_target_path;
            private float jump_to_target_speed_sec;
            private TVector2 jump_to_target_pos;

			// 技能加速,攻速
			private float mSkillSpeed = 0.0f;


            public InstanceUnit.SkillState Skill { get { return skill; } }
            public SkillTemplate SkillData { get { return skill.Data; } }

            public InstanceUnit TargetUnit { get { return targetUnit; } }

            public Queue<UnitActionData> ActionQqueue { get { return action_queue; } }

            public bool IsControlMoveable { get { return current_action_status.Get(0); } private set { current_action_status.Set(0, value); } }
            public bool IsControlFaceable { get { return current_action_status.Get(1); } private set { current_action_status.Set(1, value); } }
            public bool IsCancelableBySkill { get { return current_action_status.Get(2); } private set { current_action_status.Set(2, value); } }
            public bool IsCancelableByMove { get { return current_action_status.Get(3); } private set { current_action_status.Set(3, value); } }
            public bool IsNoneBlock { get { return current_action_status.Get(4); } private set { current_action_status.Set(4, value); } }
            public bool IsNoneTouch { get { return current_action_status.Get(5); } private set { current_action_status.Set(5, value); } }
            public bool IsFaceToTarget { get { return current_action_status.Get(6); } private set { current_action_status.Set(6, value); } }
			public Vector2 GetMoveToPos() { return this.move_to; }

			//             public bool IsCancelableBySkill { get; private set; }
			//             public bool IsCancelableByMove { get; private set; }
			//             public bool IsNoneBlock { get; private set; }
			//             public bool IsNoneTouch { get; private set; }
			//             public bool IsFaceToTarget { get; private set; }
			//             public bool IsControlMoveable { get; private set; }
			//             public bool IsControlFaceable { get; private set; }


			/// <summary>
			/// 技能是否完结
			/// </summary>
			public bool IsDone { get { return is_done; } }
            /// <summary>
            /// 是否在吟唱中
            /// </summary>
            public bool IsChanting { get { return chantExpire != null; } }
            /// <summary>
            /// 动作加速因子
            /// </summary>
            public float ActionSpeed { get; private set; }
            /// <summary>
            /// 技能释放结束后的朝向
            /// </summary>
            public Vector2 StopFaceTo { set; get; }
            /// <summary>
            /// 动作总时间
            /// </summary>
            public int ActionTotalTimeMS { get; private set; }

            public int CurrentActionIndex
            {
                get
                {
                    if (current_action != null)
                    {
                        return SkillData.ActionQueue.IndexOf(current_action);
                    }
                    return 0;
                }
            }

            public StateSkill(InstanceUnit unit, InstanceUnit.SkillState skill, LaunchSkillParam param, float actionSpeed, SkillLaunched skillLaunched)
                : base(unit)
            {
                this.skill = skill;
                this.param = param;
                this.ActionSpeed = actionSpeed;
                this.ActionTotalTimeMS = skill.Data.ActionQueueTimeMS;
                this.launched = skillLaunched;
                this.targetUnit = zone.getUnit(param.TargetUnitID);
                this.attack_range = new AttackRangeHelper(unit);
                //if (SkillData.ChantTimeMS > 0)
                //{
                //    this.chantExpire = new TimeExpire<int>(SkillData.ChantTimeMS);
                //    this.IsCancelableByMove = true;
                //}

                //this.beginLaunch();
            }
            /// <summary>
            /// 释放前判断
            /// </summary>
            /// <returns></returns>
            public bool tryLaunch()
            {
                if (SkillData.ActionQueue.Count > 0)
                {
                    if (!checkTargetRange())
                    {
                        return false;
                    }
                    if (!checkMoveToTarget(SkillData.ActionQueue[0]))
                    {
                        return false;
                    }
                    return true;
                }
                return false;
            }
            public bool CanBlockByNewSkill(SkillTemplate sk)
            {
                // 反击
                if (sk.IsCounter)
                {
                    return true;
                }
                // 高优先级技能打断老技能, 0普通,-1标识位移技能
                if (sk.ActionPriority > 0 && sk.ActionPriority > this.SkillData.ActionPriority)
                {
                    return true;
                }
                // 当前动作是否可被打断
                if (this.IsCancelableBySkill)
                {
                    return true;
                }

                return false;
            }
            override public bool onBlock(State new_state)
            {
                // 吟唱中 //
                if (IsChanting)
                {
                    return true;
                }
                // 技能完结 //
                if (is_done)
                {
                    return true;
                }
                // 被死亡或控制类技能中断 //
                if (new_state is StateDead || new_state is StateStun)
                {
                    skill.Reset();
                    return true;
                }
                // 如果死亡则受击 //
                else if (new_state is StateDamage)
                {
                    if (IsNoneBlock)
                    {
                        return false;
                    }
                    skill.ForceIntoCD();
                    return true;
                }
                else if (new_state is StateSkill)
                {
                    StateSkill ns = new_state as StateSkill;
                    if (CanBlockByNewSkill(ns.SkillData))
                    {
                        return true;
                    }
                    else if (SkillData.ID == ns.SkillData.ID && SkillData.ActionQueue.Count > CurrentActionIndex)
                    {
                        if (SkillData.ActionQueue[this.CurrentActionIndex].IsCancelBySkillNext)
                        {
                            return true;
                        }
                    }
                }
                else
                {
                    // 当前动作是否可被打断 //
                    if (this.IsCancelableByMove)
                    {
                        return true;
                    }
                }
                return false;
            }

            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.Skill);
                if (IsChanting)
                {
                    unit.queueEvent(new UnitChantSkillEvent(unit.ID, SkillData));
                }
                else
                {
                    beginLaunch();
                }
            }

            override protected void onStop()
            {
                move_to_target_path = null;
                if (start_move != null)
                {
                    start_move.Stop();
                    start_move = null;
                }
                unit.Z = 0;
                is_done = true;
                if (!IsChanting)
                {
                    if (skill != null)
                    {
                        skill.Stop(this);
                    }
                    if (unit.IsSkillControllableByServer)
                    {
                        if (StopFaceTo != null)
                        {
                            //unit.Direction = MathVector.getDegree(StopFaceTo);
                            unit.faceTo(StopFaceTo.X, StopFaceTo.Y);
                        }
                    }
                }
                PlayerSkillStopEvent evt = new PlayerSkillStopEvent(unit.ID, skill.ID);
                unit.queueEvent(evt);

				unit.Virtual.DispatchSkillBlockEvent(this, null);
			}
            override protected void onUpdate()
            {
                if (chantExpire != null)
                {
                    if (!checkTargetRange())
                    {
                        is_done = true;
                        unit.doSomething();
                        return;
                    }
                    if (chantExpire.Update(zone.UpdateIntervalMS))
                    {
                        beginLaunch();
                        chantExpire = null;
                    }
                }
                if (IsChanting) return;
                if (is_done) return;

                this.current_pass_time += (int)(zone.UpdateIntervalMS * ActionSpeed);

                if (current_action == null)
                {
                    nextAction();
                }
                if (current_action == null)
                {
                    is_done = true;
                    unit.doSomething();
                }
                else
                {
                    body_hited_last_pos.SetX(unit.X);
                    body_hited_last_pos.SetY(unit.Y);

					if (IsFaceToTarget)
					{
						float tx = 0;
						float ty = 0;
						if (getTargetPos(out tx, out ty))
						{
							unit.faceTo(tx, ty);
							unit.SendForceSync();
						}
					}


					// 关键帧 //       
					List<UnitActionData.KeyFrame> kfs = new List<UnitActionData.KeyFrame>();

					// 技能加速
					int timePassVirtual = current_pass_time;
					if (this.Skill.GetSkillType() == XmdsSkillType.normalAtk && this.mSkillSpeed != 0)
					{
						timePassVirtual = (int)(timePassVirtual * this.mSkillSpeed);
					}

					if (current_frames.PopKeyFrames(timePassVirtual, kfs) > 0)
					{
						for (int i = 0; i < kfs.Count; i++)
						{
							doKeyFrame(kfs[i]);
						}
					}


					if (current_action != null)
                    {
                        var action = current_action;
                        // 技能位移 //
                        // 移动到目标时,不切换动作 //
                        if (action.IsMoveToTarget)
                        {
                            // 冲到目标,立即下段 //
                            doMoveToTarget(action);
                        }
                        else if (action.IsJumpToTarget)
                        {
                            doJumpToTarget(action);
                        }
                        else
                        {
                            if (unit.IsSkillControllableByServer)
                            {
                                if (start_move != null)
                                {
                                    doMove();
                                }
                                if (move_to != null)
                                {
                                    if (IsControlMoveable && !unit.IsCannotMove)
                                    {
                                        unit.moveImpactTo(move_to.X, move_to.Y, unit.MoveSpeedSEC, zone.UpdateIntervalMS);
                                    }
                                    else
                                    {
                                        move_to = null;
                                    }
                                }
                            }
                            // 身体攻击 //
                            if (action.BodyHit != null)
                            {
                                doBodyHit(action);
                            }
                            // 防止技能位移导致单位重合 //
                            if (action.BodyBlockOnAttackRange)
                            {
                                doBodyBlock(action);
                            }
							if (IsFaceToTarget)
							{
								float tx = 0;
								float ty = 0;
								if (getTargetPos(out tx, out ty))
								{
									unit.faceTo(tx, ty);
									unit.SendForceSync();
								}
							}
						}
					}
                    //ADD 6/21 By Zou 加入自动战斗取消后摇
                    if (current_action != null)
                    {
                        var isFinish = current_pass_time >= this.curActionTotalTimes;
                        if (!isFinish && (IsCancelableBySkill) && unit is InstancePlayer)
                        {
                            isFinish = (unit as InstancePlayer).IsGuard;
                        }

                        if (isFinish && !nextAction())
                        {
                            is_done = true;
                            unit.doSomething();
                        }
                    }
                }
            }

            private void beginLaunch()
            {
                //是否使用多段中字段时间作为cd
                bool isUseActionQueuetime = false;
				int launchIndex = 0;
				skill.setTriggerDecreaseTime(0);

				skill.Launch(this, param);
                {
					launchIndex = skill.ActionIndex;
					int maxCount = skill.GetMaxSteps();// skill.Data.ActionQueue.Count;

                    if (skill.Data.IsSingleAction)
                    {
						if (launchIndex > 0 && launchIndex < skill.Data.ActionQueue.Count
							 //&& skill.Data.ActionQueue[actionIndex].SigleActionType == ActionEnum.forbidNext_lock)
							&& !skill.IsCanLaunchNextStepByPlayer(skill.Data.ActionQueue[launchIndex]))
						{
							skill.Reset();
						}
						this.action_queue = new Queue<UnitActionData>(1);

                        if (0 <= skill.LockActionStep && skill.LockActionStep <= maxCount)
                        {
                            this.action_queue = new Queue<UnitActionData>(1);
							launchIndex = skill.LockActionStep;
							skill.Reset();
							this.action_queue.Enqueue(skill.Data.ActionQueue[skill.LockActionStep]);
                        }
                        else
                        {
                            skill.LockActionStep = -1;

                            for (int i = launchIndex; i <= maxCount; i++)
                            {
                                UnitActionData data = skill.Data.ActionQueue[i];
                                this.action_queue.Enqueue(data);

                                if (data.SigleActionType == ActionEnum.chargeAtk
                                    || data.SigleActionType == ActionEnum.showLeftTime)
                                {
                                    isUseActionQueuetime = true;
                                }
                                else if (data.SigleActionType == ActionEnum.forbidNext_showTime)
                                {
                                    isUseActionQueuetime = true;
                                    break;
                                }
                                else if (data.SigleActionType == ActionEnum.IsAutoNext)
                                {
                                    continue;
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                    }
                    else
                    {
						//if (skill.OveryLayer > 0 && maxCount > 1)
						if(skill.CanStoreTimes)
						{
                            int maxIndex = Math.Min(skill.OveryLayer, maxCount);
                            this.action_queue = new Queue<UnitActionData>(maxIndex);
                            for (int i = 0; i < maxIndex; i++)
                            {
                                UnitActionData temp = skill.Data.ActionQueue[i];
                                this.action_queue.Enqueue(temp);
                                if (temp.SigleActionType == ActionEnum.forbidNext
                                    || temp.SigleActionType == ActionEnum.forbidNext_lock
                                    || temp.SigleActionType == ActionEnum.forbidNext_showTime)
                                {
                                    break;
                                }
                            }

							//技能释放
							if (skill.CanStoreTimes)
							{
								skill.updateOverLayer(0);
							}
						}
                        else
                        {
                            this.action_queue = new Queue<UnitActionData>(skill.Data.ActionQueue);
                        }
                    }

                    launched.Invoke(this);
                    if (mSkillLaunched != null)
                    {
                        mSkillLaunched.Invoke(this);
                        mSkillLaunched = null;
                    }
                }
                if (unit.IsSkillControllableByServer && param.AutoFocusNearTarget && (targetUnit == null || !targetUnit.IsActive))
                {
                    //自动锁定目标//
                    bool directionChange = false;
                    this.targetUnit = unit.getSkillAttackableFirstTarget(this.SkillData, AttackReason.Look, ref directionChange);
                    if (targetUnit != null && targetUnit != unit && directionChange)
                    {
                        unit.faceTo(targetUnit.X, targetUnit.Y);
                    }
                }
                else
                {
                    if (param.SpellTargetPos != null)
                    {
                        unit.faceTo(param.SpellTargetPos.X, param.SpellTargetPos.Y);
                        unit.SendForceSync();
                    }
                }
                {
                    if (skill.IsMutilAction())
                    {
                        //最后一段取消连招标记
                        if (launchIndex + 1 == skill.Data.ActionQueue.Count &&
                            skill.Data.ActionQueue[launchIndex].SigleActionType != ActionEnum.showLeftTime)
                        {
							skill.Reset();
                            skill.ResetTotalTime();
                        }
                        else if(!skill.IsCodeConttrolCD())
                        {
                            if (isUseActionQueuetime)
                            {
                                skill.TotalCDTime = skill.Data.ActionQueue[launchIndex].TotalTimeMS;
                            }
                            else if (launchIndex + 1 != skill.Data.ActionQueue.Count && 
								skill.IsCanLaunchNextStepByPlayer(skill.Data.ActionQueue[launchIndex]))//非最后一段才用这个时间
                            {
                                skill.TotalCDTime = skill.Data.SingleActionCoolDownMS;
                            }
                        }
                    }
                    //Console.WriteLine("skill.TotalCDTime - " + launchIndex);
                    PushLaunchSkillEvent(launchIndex);
                }
                nextAction();
                beginMoveToTarget();

            }

            private void PushLaunchSkillEvent(int launchIndex)
            {
                float speed = ActionSpeed;
                if (this.Skill.GetSkillType() == XmdsSkillType.normalAtk)
                {
                    speed = speed * this.unit.GetAttackSpeed() / 10000;
                }

                UnitLaunchSkillEvent evt = new UnitLaunchSkillEvent(
                      unit.ID,
                      skill.Data,
                      (byte)launchIndex,
                      speed,
                      skill.TotalCDTime,
                      param.AutoFocusNearTarget,
                      targetUnit != unit ? param.SpellTargetPos : null,
                      targetUnit != null ? targetUnit.ID : 0,
                      skill.LockActionStep);

                unit.queueEvent(evt);
            }

            private bool beginMoveToTarget()
            {
                if (current_action != null && current_action.IsMoveToTarget)
                {
                    if (targetUnit != null && zone.TouchObject2(unit, targetUnit))
                    {
                        if (nextAction())
                        {
                            unit.queueEvent(new UnitSkillActionChangeEvent(unit.ID, (byte)CurrentActionIndex));
                        }
                        return true;
                    }
                }
                return false;
            }
            private bool nextAction()
            {
                move_to_target_path = null;
                if (start_move != null)
                {
                    start_move.Stop();
                    start_move = null;
                }

                if (action_queue != null && action_queue.Count > 0)
                {
					bool isNeedNotifyClient = (this.current_action != null && (this.current_action.SigleActionType == ActionEnum.IsAutoNext
                        || this.current_action.SigleActionType == ActionEnum.chargeAtk));
                    //bool perChargeAtk = (this.current_action != null && this.current_action.SigleActionType == ActionEnum.chargeAtk);
                    this.current_action = action_queue.Dequeue();

                    if (this.Skill.GetSkillType() == XmdsSkillType.normalAtk && this.unit.GetAttackSpeed() != 0)
                    {
						this.mSkillSpeed = this.unit.GetAttackSpeed() * 0.0001f;
						this.curActionTotalTimes = (int)(this.current_action.TotalTimeMS / this.mSkillSpeed);
                    }
                    else
                    {
						this.mSkillSpeed = 0;
						this.curActionTotalTimes = this.current_action.TotalTimeMS;
                    }

                    //如果为蓄力技能,通知客户端状态
                    if (this.current_action.SigleActionType == ActionEnum.chargeAtk)
                    {
                        this.skill.Owner.AddActionSubState(UnitActionSubStatus.ChargeAtkIdle);
                    }
                    else
                    {
                        this.skill.Owner.RemoveActionSubState(UnitActionSubStatus.ChargeAtkIdle);
						this.skill.Owner.RemoveActionSubState(UnitActionSubStatus.ChargeAtkMove);
					}

                    this.current_frames.AddRange(current_action.KeyFrames);
                    this.current_pass_time = 0;

                    this.IsCancelableByMove = current_action.IsCancelable;
                    this.IsCancelableBySkill = current_action.IsCancelableBySkill;
                    this.IsNoneBlock = current_action.IsNoneBlock;
                    this.IsNoneTouch = current_action.IsNoneTouch;
                    this.IsFaceToTarget = current_action.IsFaceToTarget;
                    this.IsControlFaceable = current_action.IsControlFaceable;
                    this.IsControlMoveable = current_action.IsControlMoveable;

                    if (isNeedNotifyClient)
                    {
                        skill.ResetPassTime();
                        skill.NextAction();
                        //程序自动连接每一段动作,时间默认为totalMS
                        UnitActionData actionData = skill.Data.ActionQueue[skill.ActionIndex];

						if(!skill.IsCodeConttrolCD())
						{
							if (skill.Data.IsSingleAction && actionData.SigleActionType == ActionEnum.None)
							{
								skill.TotalCDTime = skill.Data.SingleActionCoolDownMS;
							}
							else
							{
								skill.TotalCDTime = actionData.TotalTimeMS;
							}
						}

						if(this.current_action.SigleActionType != ActionEnum.IsAutoNext)
						{
							this.PushLaunchSkillEvent(skill.ActionIndex);
						}						
                    }

                    if (IsNoneBlock)
                    {
                        unit.SetNoneBlockTimeMS(this.curActionTotalTimes);
                    }
                    if (current_action.IsMoveToTarget)
                    {
                        //先寻路//
                        checkMoveToTarget(current_action);
                    }
                    else if (current_action.IsJumpToTarget)
                    {
                        //计算跳跃距离//
                        checkJumpToTarget(current_action);
                    }
                    else
                    {
                        if (unit.IsSkillControllableByServer)
                        {
                            if (param.AutoFocusNearTarget && (targetUnit == null || !targetUnit.IsActive))
                            {
                                //自动锁定目标//
                                bool directionChange = false;
                                targetUnit = unit.getSkillAttackableFirstTarget(this.SkillData, AttackReason.Look, ref directionChange);
                                if (targetUnit != null && targetUnit != unit && directionChange)
                                {
                                    unit.faceTo(targetUnit.X, targetUnit.Y);
                                }
                            }
                        }
                    }
                    return true;
                }

                //如果为蓄力技能,通知客户端状态
                if (this.current_action != null && this.current_action.SigleActionType == ActionEnum.chargeAtk)
                {
                    this.skill.Owner.RemoveActionSubState(UnitActionSubStatus.ChargeAtkIdle);
                }
                current_action = null;
                return false;
            }

            public void doKeyFrame(UnitActionData.KeyFrame kf)
            {
                // 关键帧改变状态
                if (kf.ChangeStatus != null)
                {
                    this.IsNoneBlock = kf.ChangeStatus.IsNoneBlock;
                    this.IsNoneTouch = kf.ChangeStatus.IsNoneTouch;
                    this.IsFaceToTarget = kf.ChangeStatus.IsFaceToTarget;
                    this.IsCancelableByMove = kf.ChangeStatus.IsCancelable;
                    this.IsCancelableBySkill = kf.ChangeStatus.IsCancelableBySkill;
                    this.IsControlFaceable = kf.ChangeStatus.IsControlFaceable;
                    this.IsControlMoveable = kf.ChangeStatus.IsControlMoveable;
                }
                // 如果关键帧绑定特效
                if (kf.Effect != null)
                {
                    unit.queueEvent(new UnitEffectEvent(unit.ID, kf.Effect));
                }
                // 如果关键帧绑定近战攻击
                if (kf.Attack != null)
                {
                    doHitAttack(kf.Attack);
                }
                // 如果关键帧绑定释放法术
                if (kf.Spell != null)
                {
                    float tx = unit.X;
                    float ty = unit.Y;
                    if (param.SpellTargetPos != null)
                    {
                        float td = MathVector.getDistance(unit.X, unit.Y, param.SpellTargetPos.X, param.SpellTargetPos.Y);
                        // TargetPos超出技能范围 //
                        if (td > SkillData.AttackRange)
                        {
                            // 把TargetPos拉回 //
                            MathVector.movePolar(param.SpellTargetPos,
                                MathVector.getDegree(unit.X, unit.Y, param.SpellTargetPos.X, param.SpellTargetPos.Y),
                                SkillData.AttackRange - td);
                        }
                        // 设置法术出生点 (非自身坐标发射,比如Cannon) //
                        if (!SkillData.IsLaunchBody)
                        {
                            tx = param.SpellTargetPos.X;
                            ty = param.SpellTargetPos.Y;
                        }
					}
					//else if(this.targetUnit != null)
					//{
					//	tx = this.targetUnit.X;
					//	ty = this.targetUnit.Y;
					//}

                    zone.unitLaunchSpell(this.skill == null ?XmdsSkillType.none : this.skill.GetSkillType(), unit, kf.Spell, 
                        tx, ty, param.TargetUnitID, param.SpellTargetPos, this.CurrentActionIndex);
                }
                // 如果关键帧绑定自己释放BUFF
                if (kf.SelfBuff != null)
                {
                    unit.AddBuff(kf.SelfBuff, unit);
                }
                // 如果关键帧绑定单位位移
                if (kf.Move != null && (targetUnit == null || kf.hitTargetMoveEnable))
                {
                    StartMove action_move = kf.Move;
                    //if (unit.IsSkillControllableByServer)
                    {
                        this.start_move = unit.StartHitMove(this,
                          unit.Direction + action_move.Direction,
                          action_move.RotateSpeedSEC,
                          action_move.KeepTimeMS,
                          action_move.SpeedSEC,
                          action_move.SpeedAdd,
                          action_move.SpeedAcc,
                          action_move.IsNoneTouch);
                        this.start_move.SetFly(this,
                            action_move.ZSpeedSEC,
                            action_move.ZLimit,
                            0);
                    }
                    if (action_move.HasFly && !zone.IsSyncZ)
                    {
                        unit.queueEvent(new UnitJumpEvent(unit.ID, action_move.ZSpeedSEC, action_move.OverrideGravity, action_move.ZLimit));
                    }
                }
                if (kf.Blink != null)
                {
                    if (kf.Blink.BeginEffect != null)
                    {
                        unit.queueEvent(new UnitEffectEvent(unit.ID, kf.Blink.BeginEffect));
                    }
                    unit.moveBlink(kf.Blink, param.SpellTargetPos, targetUnit);
                    unit.SendForceSync();
                    if (kf.Blink.TargetEffect != null)
                    {
                        unit.queueEvent(new UnitEffectEvent(unit.ID, kf.Blink.TargetEffect));
                    }
                }
            }

            /// <summary>
            /// 近战攻击
            /// </summary>
            /// <param name="attack"></param>
            private void doHitAttack(AttackProp attack)
            {
                float rg = unit.GetSkillAttackRange(skill.Data);
                if (current_action.OverrideAttackShape != null)
                {
                    attack_range.Shape = (AttackShape)current_action.OverrideAttackShape.AShape;
                    attack_range.Direction = unit.Direction;
                    attack_range.ExpectTarget = SkillData.ExpectTarget;
                    attack_range.BodySize = current_action.OverrideAttackShape.AttackRange;
                    attack_range.Distance = current_action.OverrideAttackShape.AttackRange;
                    attack_range.FanAngle = current_action.OverrideAttackShape.AttackAngle;
                    attack_range.StripWide = current_action.OverrideAttackShape.StripWide;
                    float dx = unit.X;
                    float dy = unit.Y;
                    if (current_action.OverrideAttackShape.OffsetRadius != 0)
                    {
                        MathVector.movePolar(ref dx, ref dy, unit.Direction, current_action.OverrideAttackShape.OffsetRadius);
                    }
                    using (var list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
                    {
                        attack_range.GetShapeAttackable(list, AttackReason.Attack, SkillData, dx, dy, dx, dy, 0, unit.AoiStatus);
                        if (list.Count > 0)
                        {
                            zone.unitAttackDirect(unit, new AttackSource(skill, attack), list);
                        }
                    }
                }
                else if (skill.Data.AttackAngle == 0)
                {
                    if (targetUnit != null)
                    {
                        if (checkTargetRange())
                        {
                            zone.unitAttackSingle(
                                unit,
                                new AttackSource(skill, attack),
                                targetUnit,
                                SkillData.ExpectTarget);
                        }
                    }
                }
                else
                {
                    int hitcount = zone.unitAttackFan(
                        unit,
                        new AttackSource(skill, attack),
                        unit.Direction,
                        rg,
                        skill.Data.AttackAngle,
                        SkillData.ExpectTarget);
                }
            }

            /// <summary>
            /// 身体攻击
            /// </summary>
            private void doBodyHit(UnitActionData current_action)
            {
                using (var list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
                {
                    float line_r = (current_action.BodyHitSize > 0) ? current_action.BodyHitSize : unit.BodyHitSize;
                    zone.getObjectsRoundLineRange<InstanceUnit>(
                        Collider.Object_HitBody_TouchRoundLine,
                        body_hited_last_pos.X,
                        body_hited_last_pos.Y,
                        unit.X,
                        unit.Y,
                        line_r,
                        list,
                        unit.AoiStatus);
                    if (list.Count > 0)
                    {
                        CUtils.RemoveAll(list, body_hited.Values);
                        zone.unitAttack(unit, new AttackSource(skill, current_action.BodyHit), list, SkillData.ExpectTarget);
                        if (list.Count > 0)
                        {
                            for (int i = 0; i < list.Count; i++)
                            {
                                InstanceUnit o = list[i];
                                body_hited.Put(o.ID, o);
                            }
                            if (current_action.BodyHitNextAction)
                            {
                                if (nextAction())
                                {
                                    unit.queueEvent(new UnitSkillActionChangeEvent(unit.ID, (byte)CurrentActionIndex));
                                }
                                unit.SendForceSync();
                            }
                        }
                    }
                }
            }
            private void doMove()
            {
                start_move.IsNoneTouch = IsNoneTouch;
                if (start_move.IsEnd)
                {
                    start_move = null;
                }
            }

            /// <summary>
            /// 防止技能位移导致单位重合
            /// </summary>
            private void doBodyBlock(UnitActionData current_action)
            {
                if (start_move != null || move_to != null)
                {
                    if (unit.ElasticOtherObjects())
                    {
                        unit.SendForceSync();
                    }
                }
            }

            /// <summary>
            /// 移动到目标面前
            /// </summary>
            private bool doMoveToTarget(UnitActionData current_action)
            {
                if (this.move_to_target_path == null)
                {
                    if (nextAction())
                    {
                        unit.queueEvent(new UnitSkillActionChangeEvent(unit.ID, (byte)CurrentActionIndex));
                    }
                    return true;
                }
                else if (targetUnit != null && zone.TouchObject2(unit, targetUnit))
                {
                    this.move_to_target_path = null;
                    unit.ElasticOtherObjects();
                    if (nextAction())
                    {
                        unit.queueEvent(new UnitSkillActionChangeEvent(unit.ID, (byte)CurrentActionIndex));
                    }
                    return true;
                }
                else
                {
                    float tx, ty;
                    tx = move_to_target_path.PosX;
                    ty = move_to_target_path.PosY;
                    unit.faceTo(tx, ty);// = MathVector.getDegree(tx - unit.X, ty - unit.Y);
                    if (unit.jumpToTarget(tx, ty, current_action.MoveToTargetSpeedSEC, zone.UpdateIntervalMS))
                    {
                        move_to_target_path = move_to_target_path.Next;
                    }
                    unit.SendForceSync();
                    return false;
                }
            }
            private bool doJumpToTarget(UnitActionData action)
            {
                unit.Z = MoveHelper.CalulateParabolicHeight(action.JumpToTargetHeightZ, action.TotalTimeMS, this.current_pass_time);
                unit.jumpToTarget(jump_to_target_pos.X, jump_to_target_pos.Y, jump_to_target_speed_sec, zone.UpdateIntervalMS);
                unit.SendForceSync();
                return false;
            }

            public bool setMoveTo(float x, float y)
            {
				//if(Math.Abs(this.unit.X - x) < 0.5 && Math.Abs(this.unit.Y - y) < 0.5)
				//{
				//	return true;
				//}

                if (unit.IsSkillControllableByServer)
                {
                    if (IsControlMoveable && !unit.IsCannotMove)
                    {
                        if (move_to == null)
                        {
                            move_to = new Vector2(x, y);
                        }
                        else
                        {
                            move_to.SetX(x);
                            move_to.SetY(y);
                        }
                    }
                    if (IsControlFaceable)
                    {
                        unit.faceTo(x, y);
                    }
                    this.StopFaceTo = new Vector2(x - unit.X, y - unit.Y);
                }

				return false;
            }
            public void setMoveTo(Vector2 pos)
            {
                if (unit.IsSkillControllableByServer)
                {
                    if (pos == null)
                    {
                        this.move_to = null;
                        return;
                    }
                    if (IsControlMoveable && !unit.IsCannotMove)
                    {
                        move_to = pos;
                    }
                    if (IsControlFaceable)
                    {
                        unit.faceTo(pos.X, pos.Y);
                    }
                    this.StopFaceTo = new Vector2(pos.X - unit.X, pos.Y - unit.Y);
                }
            }

            public void block(State newState = null)
            {
                bool old_done = is_done;
                is_done = true;
                if (newState != null)
                {
                    unit.changeState(newState);
                }
                else if (!old_done)
                {
                    unit.doSomething();
                }				
            }

            /// <summary>
            /// 检测目标距离
            /// </summary>
            /// <returns></returns>
            private bool checkTargetRange()
            {
                return skill.checkTargetRange(targetUnit);
            }
            /// <summary>
            /// 检测冲锋距离
            /// </summary>
            /// <returns></returns>
            private bool checkMoveToTarget(UnitActionData action)
            {
                if (action.IsMoveToTarget)
                {
                    float tx; float ty;
                    if (getTargetPos(out tx, out ty))
                    {
                        this.move_to_target_path = zone.findPath(unit.X, unit.Y, tx, ty);
                        if (this.move_to_target_path != null)
                        {
                            float max = MoveHelper.GetDistance(action.TotalTimeMS, action.MoveToTargetSpeedSEC);
                            float total = this.move_to_target_path.GetTotalDistance();
                            if (total > max)
                            {
                                move_to_target_path = null;
                                return false;
                            }
                            return true;
                        }
                    }
                    return false;
                }
                return true;
            }
            /// <summary>
            /// 检测跳跃速度
            /// </summary>
            /// <param name="action"></param>
            /// <returns></returns>
            private bool checkJumpToTarget(UnitActionData action)
            {
                if (action.IsJumpToTarget)
                {
                    float tx; float ty;
                    if (getTargetPos(out tx, out ty))
                    {
                        float distance = CMath.getDistance(unit.X, unit.Y, tx, ty);
                        this.jump_to_target_pos = new TVector2(tx, ty);
                        this.jump_to_target_speed_sec = distance / (action.TotalTimeMS * 0.001f);
                    }
                }
                return true;
            }

            private bool getTargetPos(out float x, out float y)
            {
                x = unit.X;
                y = unit.Y;
                if (param.SpellTargetPos != null)
                {
                    x = param.SpellTargetPos.X;
                    y = param.SpellTargetPos.Y;
                    return true;
                }
                else if (targetUnit != null && targetUnit != unit)
                {
                    x = targetUnit.X;
                    y = targetUnit.Y;
                    return true;
                }
                else return false;
            }

            public void doUpdatePosByClient(UnitUpdatePosAction act)
            {
                if (!unit.IsSkillControllableByServer)
                {
					if(this.skill.GetSkillType() == XmdsSkillType.petGiveAcitve)
					{
						unit.setPos(act.x, act.y, unit.IntersectMap);
						unit.faceTo(act.d);
					}
					else
					{
						//暂时只管方向,不管pos
						if (this.IsControlMoveable && !unit.IsCannotMove)
						{
							unit.setPos(act.x, act.y, unit.IntersectMap);
						}

						if (this.IsControlFaceable)
						{
							unit.faceTo(act.d);
						}
						else
						{
							unit.SendForceSync();
						}
					}                    
                }
            }

            public delegate void SkillLaunched(StateSkill state);
            private SkillLaunched mSkillLaunched;
            public event SkillLaunched OnSkillLaunched { add { mSkillLaunched += value; } remove { mSkillLaunched -= value; } }

        }

        internal void SetActionSubState(UnitActionStatus unitSubState)
        {
            throw new NotImplementedException();
        }

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

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

        public class StatePickObject : State
        {
            readonly private TimeExpire<int> mTimer;
            readonly private int mTotalTimeMS;
            readonly private InstanceZoneObject mPickable;

            private bool mIsDone = false;
            private string mStopReason;
            private string mStatus;

            private OnPickDone mOnDone;
            private OnCheckPickable mCheckTargetActive;

            public string StopReason { get { return mStopReason; } }

            /// <summary>
            /// 设置目标检测状态方法
            /// </summary>
            /// <param name="check">check返回True,终止状态机。</param>
            public void SetCheckTargetAcvite(OnCheckPickable check)
            {
                this.mCheckTargetActive = check;
            }


            public StatePickObject(InstanceUnit unit, InstanceZoneObject pickable, int timeMS, string status, OnPickDone done)
                : base(unit)
            {
                this.mStatus = status;
                this.mTimer = new TimeExpire<int>(timeMS);
                this.mPickable = pickable;
                this.mTotalTimeMS = timeMS;
                this.mOnDone = done;
            }

            public override bool onBlock(State new_state)
            {
                if (new_state is StateIdle)
                    return mIsDone;
                //block by anything//
                return true;
            }


            protected override void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.Pick);
                unit.queueEvent(new UnitStartPickObjectEvent(unit.ID, mTotalTimeMS, mPickable.ID, mStatus));
            }
            protected override void onStop()
            {
                unit.queueEvent(new UnitStopPickObjectEvent(unit.ID, mStopReason));
                this.mOnDone = null;
                mCheckTargetActive = null;
            }

            protected override void onUpdate()
            {
                if (!mPickable.Enable)
                {
                    mIsDone = true;
                    unit.doSomething();
                    return;
                }
                if (mCheckTargetActive != null && mCheckTargetActive(unit, mPickable, ref mStopReason))
                {
                    mIsDone = true;
                    unit.doSomething();
                    return;
                }
                if (mTimer.Update(zone.UpdateIntervalMS))
                {
                    mIsDone = true;
                    unit.doSomething();
                    if (mOnDone != null)
                    {
                        mOnDone.Invoke(unit, mPickable);
                    }
                }
            }

            public delegate void OnPickDone(InstanceUnit unit, InstanceZoneObject pickable);
            public delegate bool OnCheckPickable(InstanceUnit unit, InstanceZoneObject pickable, ref string reason);
        }

        //---------------------------------------------------------------------------------------
        #region __状态限制__
        //---------------------------------------------------------------------------------------

        public interface IStateNoneControllable
        {
            State AsState();
        }

        /// <summary>
        /// 被击中受击过程
        /// </summary>
        public class StateDamage : State, IStateNoneControllable
        {
            private readonly AttackSource source;
            private readonly InstanceUnit attacker;

            private float startDirection;
            private float rotateSpeedSEC;

            private bool isEnd = false;

            private HitMoveSpeed hitMoveSpeed;
            private TimeExpire<object> damageExpire;
            private HashMap<uint, InstanceUnit> body_hited = new HashMap<uint, InstanceUnit>();

            private IStateNoneControllable nextState;

            public void SetNextNoneControllable(IStateNoneControllable state)
            {
                nextState = state;
            }
            public State AsState()
            {
                return this;
            }
            public bool IsFallingDown
            {
                get { return (hitMoveSpeed != null && hitMoveSpeed.IsFly && unit.Z > 0); }
            }
            public bool IsKnockDown
            {
                get { return source.OutHasKnockDown; }
            }
            public bool IsDamageProtect
            {
                get { return source.Attack.IsDamageProtect; }
            }
            public int DamageTimeMS
            {
                get { return damageExpire.TotalTimeMS; }
            }
            public bool IsHitMove
            {
                get { return hitMoveSpeed != null; }
            }

            public StateDamage(InstanceUnit unit, AttackSource source, InstanceUnit attacker)
                : base(unit)
            {
                this.source = source;
                this.attacker = attacker;
                this.body_hited.Put(unit.ID, unit);

                AttackProp.HitMoveType mtype = source.Attack.HitMoveMType;
                if (source.FromSpell != null)
                {
                    this.startDirection = MoveHelper.CalculateHitMoveDirection(unit, source.FromSpellUnit, mtype);
                }
                else if (source.FromSkill != null)
                {
                    this.startDirection = MoveHelper.CalculateHitMoveDirection(unit, attacker, mtype);
                }
                else
                {
                    this.startDirection = unit.Direction + CMath.PI_F;
                }
                if (source.OutHitMove != null)
                {
                    this.startDirection += source.OutHitMove.Direction;
                    this.rotateSpeedSEC = source.OutHitMove.RotateSpeedSEC * ((unit.RandomN.Next() % 2) == 0 ? -1 : 1);
                }

                // 计算受击时间 //
                int damageTime = unit.Info.DamageTimeMS;
                if (source.OutKnockDownTimeMS > 0)
                {
                    damageTime = source.OutKnockDownTimeMS;
                }
                else if (unit.mInfo.DamageTimeMS > 0)
                {
                    damageTime = unit.mInfo.DamageTimeMS;
                }
                else
                {
                    damageTime = zone.Templates.CFG.OBJECT_DAMAGE_TIME_MS;
                }
                this.damageExpire = new TimeExpire<object>(damageTime);
            }

            override public bool onBlock(State new_state)
            {
                if (isEnd)
                {
                    return true;
                }
                if (new_state is StateDead)
                {
                    return true;
                }
                if (new_state is StateDamage)
                {
                    return onBlockNewDamage(new_state as StateDamage);
                }
                if (new_state is IStateNoneControllable)
                {
                    this.SetNextNoneControllable(new_state as IStateNoneControllable);
                }
                if (unit.IsDead())
                {
                    return false;
                }
                if (new_state is StateSkill)
                {
                    StateSkill ss = new_state as StateSkill;
                    // 反击或者状态解除//
                    if (ss.SkillData.IsCounter)
                    {
                        return true;
                    }
                }
                return isEnd;
            }
            private bool onBlockNewDamage(StateDamage new_damage)
            {
                //击飞只能被击飞中断//
                if (this.IsFallingDown)
                {
                    if (!new_damage.source.OutHasFly)
                    {
                        return false;
                    }
                }
                //击倒只能被击飞或击倒中断//
                if (this.IsKnockDown)
                {
                    if (!new_damage.source.OutHasFly)
                    {
                        return false;
                    }
                    if (!new_damage.source.OutHasKnockDown)
                    {
                        return false;
                    }
                }
                //如果正在位移,需要更高优先级//
                if (hitMoveSpeed != null)
                {
                    if (new_damage.source.OutHasFly || new_damage.source.OutHasKnockDown || new_damage.source.OutHitMove != null)
                    {
                        //带位移的受击,相等优先级也可以打断当前位移//
                        if (new_damage.source.OutWeight >= this.source.OutWeight)
                        {
                            return true;
                        }
                    }
                    else
                    {
                        //普通受击,更高优先级才能打断当前位移//
                        if (new_damage.source.OutWeight > this.source.OutWeight)
                        {
                            return true;
                        }
                    }
                    return false;
                }
                return true;
            }
            override protected void onStart()
            {
                float zgravity = 0;
                float zlimit = 0;

				bool hasHitMove = false;
                if (source.OutHitMove != null)
                {
                    int keepTimeMs = source.OutHitMove.KeepTimeMS;
                    float speedSEC = source.OutHitMove.SpeedSEC;
                    if (source.Attack.HitMoveMType == AttackProp.HitMoveType.BySenderRange)
                    {
                        float distance = CMath.getDistance(attacker.X, attacker.Y, unit.X, unit.Y);
                        if (distance > source.FromSpell.BodySize)
                        {
                            keepTimeMs = 0;
                            speedSEC = 0;
                        }
                        else
                        {
                            float moveDistance = source.FromSpell.BodySize - distance;
                            keepTimeMs = (int)(moveDistance * 1000 / source.OutHitMove.SpeedSEC);
                        }
                    }
					
					hasHitMove = true;
					this.hitMoveSpeed = unit.StartHitMove(this,
                        startDirection,
                        source.OutHitMove.RotateSpeedSEC,
                        keepTimeMs,
                        speedSEC,
                        source.OutHitMove.SpeedAdd,
                        source.OutHitMove.SpeedAcc,
                        source.OutHitMove.IsNoneTouch);
                    if (source.OutHasFly)
                    {
                        this.hitMoveSpeed.SetFly(this,
                            source.OutHitMove.ZSpeedSEC,
                            source.OutHitMove.OverrideGravity,
                            source.OutHitMove.ZLimit);
                        zgravity = source.OutHitMove.OverrideGravity;
                        zlimit = source.OutHitMove.ZLimit;
                    }
                }
                else if (source.OutHasFly)
                {
					hasHitMove = true;
					this.hitMoveSpeed = unit.StartHitMove(this,
                        startDirection,
                        0,
                        0, // 如果击飞,则计算按落地时间 //
                        zone.Templates.CFG.OBJECT_DAMAGE_FLY_SPEED_SEC,
                        zone.Templates.CFG.OBJECT_DAMAGE_FLY_SPEED_ADD,
                        zone.Templates.CFG.OBJECT_DAMAGE_FLY_SPEED_ACC,
                        false);
                    this.hitMoveSpeed.SetFly(this,
                        zone.Templates.CFG.OBJECT_DAMAGE_FLY_ZSPEED_SEC, 0, 0);
                }
                int moveTime = 0;
                float zspeed = 0;
                if (hitMoveSpeed != null)
                {
                    moveTime = hitMoveSpeed.TotalTimeMS;
                    zspeed = hitMoveSpeed.ZSpeedSEC;

                    if (source.Attack.HitMoveMType == AttackProp.HitMoveType.ToSenderCenter)
                    {
                        if (source.FromSpellUnit != null)
                        {
                            this.hitMoveSpeed.SetMoveTarget(source.FromSpellUnit, false);
                        }
                        else if (source.FromSkill != null)
                        {
                            this.hitMoveSpeed.SetMoveTarget(this.attacker, false);
                        }
                    }
                    else if (source.Attack.HitMoveMType == AttackProp.HitMoveType.ToSenderBodySize)
                    {
                        if (source.FromSpellUnit != null)
                        {
                            this.hitMoveSpeed.SetMoveTarget(source.FromSpellUnit, true);
                        }
                        else if (source.FromSkill != null)
                        {
                            this.hitMoveSpeed.SetMoveTarget(this.attacker, true);
                        }
                    }
                }
                unit.queueEvent(new UnitDamageEvent(
                    unit.ID,
                    DamageTimeMS,
                    moveTime,
                    zspeed,
                    zgravity,
                    zlimit,
                    source.OutHasKnockDown,
                    source.Attack));

				if (hasHitMove)
				{
					unit.SetActionStatus(UnitActionStatus.HitMove);
				}
				else
				{
					unit.SetActionStatus(UnitActionStatus.Damage);
				}               
            }

            override protected void onUpdate()
            {
                if (hitMoveSpeed != null)
                {
                    if (hitMoveSpeed.IsEnd)
                    {
                        hitMoveSpeed = null;
                        if (source.Attack.FlyFallenDownAttack != null)
                        {
                            doFlyDownAttack();
                        }
                    }
                    else if (source.Attack.HitMoveBodyAttack != null)
                    {
                        doBodyAttack();
                    }
                }
                else if (damageExpire != null)
                {
                    if (damageExpire.Update(zone.UpdateIntervalMS))
                    {
                        damageExpire = null;
                    }
                }
                else
                {
                    end();
                }
            }

            override protected void onStop()
            {
                if (unit.IsStun)
                {
                    unit.changeState(new StateStun(unit));
                }
                else if (nextState != null)
                {
                    unit.changeState(nextState.AsState());
                }
            }

            private void end()
            {
                if (unit.IsDead())
                {
                    isEnd = true;
                    unit.changeState(new StateDead(unit, attacker));
                }
                else if (unit.IsStun)
                {
                    unit.SetActionStatus(UnitActionStatus.Stun);
                }
                else
                {
                    isEnd = true;
                    unit.doSomething();
                }
            }

            /// <summary>
            /// 自己落地摔一下
            /// </summary>
            private void doFlyDownAttack()
            {
                unit.doHitAttack(attacker, source.GenAttackSource(source.Attack.FlyFallenDownAttack));
            }

            /// <summary>
            /// 飞行过程中打别人
            /// </summary>
            private void doBodyAttack()
            {
                using (var list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
                {
                    zone.getObjectsRoundLineRange<InstanceUnit>(
                        Collider.Object_HitBody_TouchRoundLine,
                        hitMoveSpeed.PrevX, hitMoveSpeed.PrevY,
                        unit.X, unit.Y,
                        unit.BodyBlockSize + source.Attack.HitMoveBodyAttackSize,
                        list, unit.AoiStatus);
                    if (list.Count > 0)
                    {
                        CUtils.RemoveAll(list, body_hited.Values);
                        zone.unitAttack(attacker, source.GenAttackSource(source.Attack.HitMoveBodyAttack), list, source.FromExpectTarget);
                        if (list.Count > 0)
                        {
                            for (int i = 0; i < list.Count; i++)
                            {
                                InstanceUnit o = list[i];
                                body_hited.Put(o.ID, o);
                            }
                        }
                    }
                }

            }
        }

        /// <summary>
        /// 死了,而且是被艹翻的,暴击打死然后击退
        /// </summary>
        public class StateDeadFuckFuck : State, IStateNoneControllable
        {
            private readonly AttackSource source;
            private readonly InstanceUnit attacker;

            private float startDirection;

            private bool isEnd = false;

            private HitMoveSpeed hitMoveSpeed;
            private TimeExpire<object> damageExpire;
            private HashMap<uint, InstanceUnit> body_hited = new HashMap<uint, InstanceUnit>();

            private IStateNoneControllable nextState;

            public void SetNextNoneControllable(IStateNoneControllable state)
            {
                nextState = state;
            }
            public State AsState()
            {
                return this;
            }
            public bool IsFallingDown
            {
                get { return (hitMoveSpeed != null && hitMoveSpeed.IsFly && unit.Z > 0); }
            }
            public bool IsKnockDown
            {
                get { return source.OutHasKnockDown; }
            }
            public bool IsDamageProtect
            {
                get { return source.Attack.IsDamageProtect; }
            }
            public int DamageTimeMS
            {
                get { return damageExpire.TotalTimeMS; }
            }
            public bool IsHitMove
            {
                get { return hitMoveSpeed != null; }
            }

            public StateDeadFuckFuck(InstanceUnit unit, AttackSource source, InstanceUnit attacker, HitMoveType movetype)
                : base(unit)
            {
                this.source = source;
                this.attacker = attacker;
                this.body_hited.Put(unit.ID, unit);

                HitMoveType mtype = movetype;
                if (source.FromSpell != null)
                {
                    this.startDirection = MoveHelper.CalculateHitMoveDirection(unit, source.FromSpellUnit, mtype);
                }
                else if (source.FromSkill != null)
                {
                    this.startDirection = MoveHelper.CalculateHitMoveDirection(unit, attacker, mtype);
                }
                else
                {
                    this.startDirection = unit.Direction + CMath.PI_F;
                }


                // 计算受击时间 //
                int damageTime = unit.Info.DamageTimeMS;
                if (source.OutKnockDownTimeMS > 0)
                {
                    damageTime = source.OutKnockDownTimeMS;
                }
                else if (unit.mInfo.DamageTimeMS > 0)
                {
                    damageTime = unit.mInfo.DamageTimeMS;
                }
                else
                {
                    damageTime = zone.Templates.CFG.OBJECT_DAMAGE_TIME_MS;
                }
                this.damageExpire = new TimeExpire<object>(damageTime);
            }

            override public bool onBlock(State new_state)
            {
                if (isEnd)
                {
                    return true;
                }
                if (new_state is StateDead)
                {
                    return true;
                }
                if (new_state is IStateNoneControllable)
                {
                    this.SetNextNoneControllable(new_state as IStateNoneControllable);
                }
                if (unit.IsDead())
                {
                    return false;
                }

                if (new_state is StateDamage)
                {
                    return unit.CanWhiplashDeadBody;
                }
                if (new_state is StateRebirth)
                {
                    return true;
                }
                return isEnd;
            }

            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.Dead);
                float zgravity = 0;
                float zlimit = 0;

                if (true)
                {
                    int keepTimeMs = 0;
                    int moveDistance = new Random().Next(2, 12);
                    float speedSEC = 15;
                    keepTimeMs = (int)(moveDistance * 1000 / speedSEC);
                    //speedSEC = new Random().Next(0, 11);



                    this.hitMoveSpeed = unit.StartHitMove(this,
                        startDirection,
                        0,
                        keepTimeMs,
                        speedSEC,
                        0,
                        0,
                        false);
                }

                int moveTime = 0;
                float zspeed = 0;
                if (hitMoveSpeed != null)
                {
                    moveTime = hitMoveSpeed.TotalTimeMS;
                    zspeed = hitMoveSpeed.ZSpeedSEC;
                }
                unit.queueEvent(new UnitDamageEvent(
                    unit.ID,
                    DamageTimeMS,
                    moveTime,
                    zspeed,
                    zgravity,
                    zlimit,
                    source.OutHasKnockDown,
                    source.Attack));

                //unit.SetActionStatus(UnitActionStatus.Dead);
            }

            override protected void onUpdate()
            {
                if (hitMoveSpeed != null)
                {
                    if (hitMoveSpeed.IsEnd)
                    {
                        hitMoveSpeed = null;
                        if (source.Attack.FlyFallenDownAttack != null)
                        {
                            doFlyDownAttack();
                        }
                    }
                    else if (source.Attack.HitMoveBodyAttack != null)
                    {
                        doBodyAttack();
                    }
                }
                else if (damageExpire != null)
                {
                    if (damageExpire.Update(zone.UpdateIntervalMS))
                    {
                        damageExpire = null;
                    }
                }
                else
                {
                    end();
                }
            }

            override protected void onStop()
            {
                if (unit.IsStun)
                {
                    unit.changeState(new StateStun(unit));
                }
                else if (nextState != null)
                {
                    unit.changeState(nextState.AsState());
                }
            }

            private void end()
            {
                isEnd = true;
                unit.changeState(new StateDead(unit, attacker));
            }

            /// <summary>
            /// 自己落地摔一下
            /// </summary>
            private void doFlyDownAttack()
            {
                unit.doHitAttack(attacker, source.GenAttackSource(source.Attack.FlyFallenDownAttack));
            }

            /// <summary>
            /// 飞行过程中打别人
            /// </summary>
            private void doBodyAttack()
            {
                using (var list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
                {
                    zone.getObjectsRoundLineRange<InstanceUnit>(
                        Collider.Object_HitBody_TouchRoundLine,
                        hitMoveSpeed.PrevX, hitMoveSpeed.PrevY,
                        unit.X, unit.Y,
                        unit.BodyBlockSize + source.Attack.HitMoveBodyAttackSize,
                        list, unit.AoiStatus);
                    if (list.Count > 0)
                    {
                        CUtils.RemoveAll(list, body_hited.Values);
                        zone.unitAttack(attacker, source.GenAttackSource(source.Attack.HitMoveBodyAttack), list, source.FromExpectTarget);
                        if (list.Count > 0)
                        {
                            for (int i = 0; i < list.Count; i++)
                            {
                                InstanceUnit o = list[i];
                                body_hited.Put(o.ID, o);
                            }
                        }
                    }
                }

            }
        }

        /// <summary>
        /// 死了,而且是被艹翻的,暴击打死然后击退
        /// </summary>
        public class StateDeadFuck : State, IStateNoneControllable
        {
            private readonly AttackSource source;
            private readonly InstanceUnit attacker;

            private float startDirection;

            private bool isEnd = false;

            private HitMoveSpeed hitMoveSpeed;
            private TimeExpire<object> damageExpire;
            private HashMap<uint, InstanceUnit> body_hited = new HashMap<uint, InstanceUnit>();

            private IStateNoneControllable nextState;

            public void SetNextNoneControllable(IStateNoneControllable state)
            {
                nextState = state;
            }
            public State AsState()
            {
                return this;
            }
            public bool IsFallingDown
            {
                get { return (hitMoveSpeed != null && hitMoveSpeed.IsFly && unit.Z > 0); }
            }
            public bool IsKnockDown
            {
                get { return source.OutHasKnockDown; }
            }
            public bool IsDamageProtect
            {
                get { return source.Attack.IsDamageProtect; }
            }
            public int DamageTimeMS
            {
                get { return damageExpire.TotalTimeMS; }
            }
            public bool IsHitMove
            {
                get { return hitMoveSpeed != null; }
            }

            public StateDeadFuck(InstanceUnit unit, AttackSource source, InstanceUnit attacker)
                : base(unit)
            {
                this.source = source;
                this.attacker = attacker;
                this.body_hited.Put(unit.ID, unit);

                AttackProp.HitMoveType mtype = AttackProp.HitMoveType.BySenderPosition;
                if (source.FromSpell != null)
                {
                    this.startDirection = MoveHelper.CalculateHitMoveDirection(unit, source.FromSpellUnit, mtype);
                }
                else if (source.FromSkill != null)
                {
                    this.startDirection = MoveHelper.CalculateHitMoveDirection(unit, attacker, mtype);
                }
                else
                {
                    this.startDirection = unit.Direction + CMath.PI_F;
                }


                // 计算受击时间 //
                int damageTime = unit.Info.DamageTimeMS;
                if (source.OutKnockDownTimeMS > 0)
                {
                    damageTime = source.OutKnockDownTimeMS;
                }
                else if (unit.mInfo.DamageTimeMS > 0)
                {
                    damageTime = unit.mInfo.DamageTimeMS;
                }
                else
                {
                    damageTime = zone.Templates.CFG.OBJECT_DAMAGE_TIME_MS;
                }
                this.damageExpire = new TimeExpire<object>(damageTime);
            }

            override public bool onBlock(State new_state)
            {
                if (isEnd)
                {
                    return true;
                }
                if (new_state is StateDead)
                {
                    return true;
                }
                if (new_state is IStateNoneControllable)
                {
                    this.SetNextNoneControllable(new_state as IStateNoneControllable);
                }
                if (unit.IsDead())
                {
                    return false;
                }

                if (new_state is StateDamage)
                {
                    return unit.CanWhiplashDeadBody;
                }
                if (new_state is StateRebirth)
                {
                    return true;
                }
                return isEnd;
            }

            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.Dead);
                float zgravity = 0;
                float zlimit = 0;

                if (true)
                {
                    int keepTimeMs = 0;
                    float speedSEC = 3;//这个数字要随机1-10
                    speedSEC = new Random().Next(0, 11);



                    this.hitMoveSpeed = unit.StartHitMove(this,
                        startDirection,
                        0,
                        keepTimeMs,
                        speedSEC,
                        0,
                        0,
                        false);
                    if (true)
                    {
                        this.hitMoveSpeed.SetFly(this,
                            15,//source.OutHitMove.ZSpeedSEC
                            0,
                            0);
                        zgravity = 0;
                        zlimit = 0;
                    }
                }

                int moveTime = 0;
                float zspeed = 0;
                if (hitMoveSpeed != null)
                {
                    moveTime = hitMoveSpeed.TotalTimeMS;
                    zspeed = hitMoveSpeed.ZSpeedSEC;

                }
                unit.queueEvent(new UnitDamageEvent(
                    unit.ID,
                    DamageTimeMS,
                    moveTime,
                    zspeed,
                    zgravity,
                    zlimit,
                    source.OutHasKnockDown,
                    source.Attack));

                unit.SetActionStatus(UnitActionStatus.Dead);
            }

            override protected void onUpdate()
            {
                if (hitMoveSpeed != null)
                {
                    if (hitMoveSpeed.IsEnd)
                    {
                        hitMoveSpeed = null;
                        if (source.Attack.FlyFallenDownAttack != null)
                        {
                            doFlyDownAttack();
                        }
                    }
                    else if (source.Attack.HitMoveBodyAttack != null)
                    {
                        doBodyAttack();
                    }
                }
                else if (damageExpire != null)
                {
                    if (damageExpire.Update(zone.UpdateIntervalMS))
                    {
                        damageExpire = null;
                    }
                }
                else
                {
                    end();
                }
            }

            override protected void onStop()
            {
                if (unit.IsStun)
                {
                    unit.changeState(new StateStun(unit));
                }
                else if (nextState != null)
                {
                    unit.changeState(nextState.AsState());
                }
            }

            private void end()
            {
                isEnd = true;
                unit.changeState(new StateDead(unit, attacker));
            }

            /// <summary>
            /// 自己落地摔一下
            /// </summary>
            private void doFlyDownAttack()
            {
                unit.doHitAttack(attacker, source.GenAttackSource(source.Attack.FlyFallenDownAttack));
            }

            /// <summary>
            /// 飞行过程中打别人
            /// </summary>
            private void doBodyAttack()
            {
                using (var list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
                {
                    zone.getObjectsRoundLineRange<InstanceUnit>(
                        Collider.Object_HitBody_TouchRoundLine,
                        hitMoveSpeed.PrevX, hitMoveSpeed.PrevY,
                        unit.X, unit.Y,
                        unit.BodyBlockSize + source.Attack.HitMoveBodyAttackSize,
                        list, unit.AoiStatus);
                    if (list.Count > 0)
                    {
                        CUtils.RemoveAll(list, body_hited.Values);
                        zone.unitAttack(attacker, source.GenAttackSource(source.Attack.HitMoveBodyAttack), list, source.FromExpectTarget);
                        if (list.Count > 0)
                        {
                            for (int i = 0; i < list.Count; i++)
                            {
                                InstanceUnit o = list[i];
                                body_hited.Put(o.ID, o);
                            }
                        }
                    }
                }

            }
        }

        /// <summary>
        /// 死亡状态
        /// </summary>
        public class StateDead : State, IStateNoneControllable
        {
            private TimeExpire<int> dead_time;
            private TimeExpire<int> rebirth_time;
            private InstanceUnit attacker;
            private bool crushed;
            private List<TimeExpire<int>> dead_delayTimes = new List<TimeExpire<int>>();

            public StateDead(InstanceUnit unit, InstanceUnit attacker, bool crush = false)
                : base(unit)
            {
                this.attacker = attacker;
                this.crushed = crush;
            }
            public State AsState()
            {
                return this;
            }
            override public bool onBlock(State new_state)
            {
                if (new_state is StateDamage)
                {
                    return unit.CanWhiplashDeadBody;
                }
                if (new_state is StateRebirth)
                {
                    return true;
                }
                return !unit.IsDead();
            }
            override protected void onStart()
            {
				//某些状态帧下死亡调用漏掉了
				if (unit.IsNeedProcessDead())
				{
                    log.Warn("手动调用死亡逻辑1:" + unit.PlayerUUID + ", 攻击方:" + (attacker == null ? "null" : attacker.PlayerUUID) + ", " + this.zone.GetSceneID());
                    unit.Parent.cb_unitDeadCallBack(unit, this.attacker);
				}

				unit.SetActionStatus(UnitActionStatus.Dead);
                this.rebirth_time = new TimeExpire<int>(unit.mInfo.RebirthTimeMS);
                this.dead_time = new TimeExpire<int>(unit.mInfo.DeadTimeMS);
                if (unit.Info.DeadLaunchSpell != null)
                {
                    // 自爆法术
                    zone.unitLaunchSpell(XmdsSkillType.none, unit, unit.Info.DeadLaunchSpell, unit.X, unit.Y);
                }
                // Boss 死亡之后灵魂飘到击杀者身上
                if (unit.mInfo.DeadDelayTimeMS > 0)
                {
                    dead_delayTimes.Clear();
                    for (var i = 0; i < unit.Info.DeadDelaySpellNumber; i++)
                    {
                        this.dead_delayTimes.Add(new TimeExpire<int>(
                                unit.mInfo.DeadDelayTimeMS + i * unit.Info.DeadDelaySpellIntervalMS));
                    }
                }
            }

            override protected void onUpdate()
            {
                if (dead_time.Update(zone.UpdateIntervalMS))
                {
                    if (unit.mInfo.RebirthTimeMS <= 0)
                    {
                        zone.RemoveObject(unit);
                    }

                    ////跨服场景中,单位死亡,需要移除单位,然后才能复活
                    //if (unit.IsDead() && unit.IsPlayer && unit.GetSceneType() >= CommonAI.Data.SceneType.CROSS_SERVER_NEW)
                    //{
                    //    // zone.RemoveObject(unit);
                    //    unit.DeadHide = true;
                    //}
                }
                if (rebirth_time.Update(zone.UpdateIntervalMS))
                {
                    if (unit.mInfo.RebirthTimeMS > 0)
                    {
                        unit.startRebirth();
                    }
                }
                for (var i = 0; i < this.dead_delayTimes.Count; i++)
                {
                    if (dead_delayTimes[i] != null && dead_delayTimes[i].Update(zone.UpdateIntervalMS))
                    {
                        zone.unitLaunchSpell(XmdsSkillType.none, unit, unit.Info.DeadDelayLaunchSpell, 
                            unit.X, unit.Y, attacker == null ? 0 : ((InstanceUnit)attacker).mSyncInfo.ObjectID);
                        dead_delayTimes[i] = null;
                    }
                }
            }

            override protected void onStop()
            {
                //unit.SetActionStatus(UnitActionStatus.Idle);
            }
        }

        /// <summary>
        /// 复活
        /// </summary>
        public class StateRebirth : State, IStateNoneControllable
        {
            private bool is_done = false;
            private int max_hp = 0;
            private int max_mp = 0;
            public StateRebirth(InstanceUnit unit, int max_hp, int max_mp)
                : base(unit)
            {
                this.max_hp = max_hp;
                this.max_mp = max_mp;
            }
            public State AsState()
            {
                return this;
            }
            override public bool onBlock(State new_state)
            {
                return is_done;
            }
            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.Rebirth);
            }
            override protected void onUpdate()
            {
                this.is_done = true;
                unit.doRebirth(max_hp, max_mp);
                unit.doSomething();
            }
            override protected void onStop()
            {
            }
        }

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

        /// <summary>
        /// 眩晕状态
        /// </summary>
        public class StateStun : State, IStateNoneControllable
        {
            public StateStun(InstanceUnit unit)
                : base(unit)
            {
            }
            public State AsState()
            {
                return this;
            }
            override public bool onBlock(State new_state)
            {
                if (new_state is StateDamage)
                {
                    return true;
                }
                if (unit.IsDead() && new_state is StateDead)
                {
                    return true;
                }
                if (new_state is StateSkill)
                {
                    StateSkill ss = new_state as StateSkill;
                    // 反击或者状态解除//
                    if (ss.SkillData.IsCounter)
                    {
                        return true;
                    }
                }
                return !unit.IsStun;
            }

            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.Stun);
            }
            override protected void onUpdate()
            {
                if (!unit.IsStun)
                {
                    unit.doSomething();
                }
            }
            override protected void onStop()
            {
                //unit.SetActionStatus(UnitActionStatus.Idle);
            }

        }

        /// <summary>
        /// 不可移动状态
        /// </summary>
        public class StateChuanGongA : State, IStateNoneControllable
        {
			private bool markRemove;

			public StateChuanGongA(InstanceUnit unit)
                : base(unit)
            {
				
            }
            public State AsState()
            {
                return this;
            }
            override public bool onBlock(State new_state)
            {
				if (this.markRemove)
				{
					return true;
				}

				return unit.chuangongTime < CommonLang.CUtils.localTimeMS;
            }

			public override void MarkRemove()
			{
				this.markRemove = true;
			}

			override protected void onStart()
            {
				this.markRemove = false;
                unit.chuangongTime = CommonLang.CUtils.localTimeMS + 60000;
                unit.SetActionStatus(UnitActionStatus.ChuanGongA);
            }
            override protected void onUpdate()
            {
				if (this.markRemove)
				{
					unit.startIdle();
				}
				else if (unit.chuangongTime < CommonLang.CUtils.localTimeMS)
                {
                    unit.doSomething();
                }
            }
            override protected void onStop()
            {
                unit.SetActionStatus(UnitActionStatus.Idle);
            }
        }


        /// <summary>
        /// 不可移动状态
        /// </summary>
        public class StateChuanGongB : State, IStateNoneControllable
        {
			private bool markRemove;

			public StateChuanGongB(InstanceUnit unit)
                : base(unit)
            {
            }
            public State AsState()
            {
                return this;
            }
            override public bool onBlock(State new_state)
            {
				if (this.markRemove)
				{
					return true;
				}
				return unit.chuangongTime < CommonLang.CUtils.localTimeMS;
            }

			public override void MarkRemove()
			{
				this.markRemove = true;
			}

			override protected void onStart()
            {
				this.markRemove = false;
				unit.chuangongTime = CommonLang.CUtils.localTimeMS + 60000;
                unit.SetActionStatus(UnitActionStatus.ChuanGongB);
            }
            override protected void onUpdate()
            {
				if (this.markRemove)
				{
					unit.startIdle();
				}
				else if (unit.chuangongTime < CommonLang.CUtils.localTimeMS)
                {
                    unit.doSomething();
                }
            }
            override protected void onStop()
            {
                unit.SetActionStatus(UnitActionStatus.Idle);
            }
        }

        /// <summary>
        /// 不可移动状态 净妖,和传功一样锁定4秒,时间变量用传功的
        /// </summary>
        public class StateClearYaoQi : State, IStateNoneControllable
        {
            public StateClearYaoQi(InstanceUnit unit)
                : base(unit)
            {
            }
            public State AsState()
            {
                return this;
            }
            override public bool onBlock(State new_state)
            {
                return unit.chuangongTime < CommonLang.CUtils.localTimeMS;
            }

            override protected void onStart()
            {
                unit.chuangongTime = CommonLang.CUtils.localTimeMS + 4000;
                unit.SetActionStatus(UnitActionStatus.ClearYaoQi);
            }
            override protected void onUpdate()
            {
                if (unit.chuangongTime < CommonLang.CUtils.localTimeMS)
                {
                    unit.doSomething();
                }
            }
            override protected void onStop()
            {
                unit.SetActionStatus(UnitActionStatus.Idle);
            }
        }

        /// <summary>
        ///  打坐
        /// </summary>
        public class StateDaZuo : State
        {
            private float startX;
            private float startY;
            private long lockEndTime;
			private bool markRemove;

            public StateDaZuo(InstanceUnit unit, int time)
                : base(unit)
            {
				int lockTime = Math.Max(1, time);
				//锁定短暂时间,避免一打坐就被客户端取消了。
				lockEndTime = 0;// CommonLang.CUtils.localTimeMS + lockTime * 1000;
            }

			public override void MarkRemove()
			{
				this.markRemove = true;
			}

            override public bool onBlock(State new_state)
			{
				if (this.markRemove)
				{
					return true;
				}

				if (CommonLang.CUtils.localTimeMS < lockEndTime)
				{
					return false;
				}

				if (new_state is StateIdle)
                {
                    return false;
                }
                return true;                
            }

            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.DaZuo);
            }

            override protected void onUpdate()
            {
				if(this.markRemove)
				{
					unit.startIdle();
				}
                else if(lockEndTime > CommonLang.CUtils.localTimeMS)
                {
                    startX = unit.X;
                    startY = unit.Y;
                }
                else if (unit.X != startX || unit.Y != startY)
                {
                    unit.doSomething();
                }
            }

            override protected void onStop()
            {
                unit.SetActionStatus(UnitActionStatus.Idle);
            }
        }
        
        /// <summary>
        ///  打坐恢复血量
        /// </summary>
        public class StateDaZuoRecoveryAttr : State
        {
            private long endTime;//回血结束时间
            private bool markRemove;
            private int sustainTime; //持续时间
            private long nextRecoveryTime; //下一次恢复时间
            public StateDaZuoRecoveryAttr(InstanceUnit unit, int time)
                : base(unit)
            {
                endTime = CommonLang.CUtils.CurrentTimeMS + time*1000;
                sustainTime = time-3;  //减去3是因为等待坐下去后才开始回血
                nextRecoveryTime = CommonLang.CUtils.CurrentTimeMS+2350; //2350是客户端坐下去整个动作的时间,等待动作播放完成,开始回血
            }

            public override void MarkRemove()
            {
                this.markRemove = true;
            }

            override public bool onBlock(State new_state)
            {
                return true;                
            }

            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.DaZuoRecoveryAttr);
            }

            override protected void onUpdate()
            {
                if(this.markRemove)
                {
                    unit.startIdle();
                }
                else
                {
                    if (unit.Virtual.GetBattleStatus() != BattleStatus.None)
                    {
                        unit.startIdle();
                        return;
                    }
                    
                    if (CommonLang.CUtils.CurrentTimeMS > endTime)
                    {
                        unit.startIdle();
                        return;
                    }
          
                    if (nextRecoveryTime < CommonLang.CUtils.CurrentTimeMS)
                    {
                        int Recover = 0;
                       //恢复主角血量
                       // if (unit.CurrentHP < unit.MaxHP)
                        //{
                            Recover = (int)(unit.MaxHP / sustainTime);
                            /*if (unit.CurrentHP + Recover > unit.MaxHP)
                            {
                                Recover = unit.MaxHP - unit.CurrentHP;
                            }*/

                            unit.add_hp(Recover);
                       // }
                        //恢复宠物血量
                        InstanceUnit petUnit =  unit.Virtual.GetPetUnit();
                        if (petUnit != null)
                        {
                            if (petUnit.CurrentHP < petUnit.MaxHP && petUnit.Virtual.GetBattleStatus() == BattleStatus.None)
                            {
                                Recover = (int)(petUnit.MaxHP / sustainTime);
                                if (petUnit.CurrentHP + Recover > petUnit.MaxHP)
                                {
                                    Recover = petUnit.MaxHP - petUnit.CurrentHP;
                                }
                                petUnit.add_hp(Recover);
                            }
                        }

                        nextRecoveryTime = CommonLang.CUtils.CurrentTimeMS + 1 * 1000;
                    }
                }
            }

            override protected void onStop()
            {
                unit.SetActionStatus(UnitActionStatus.Idle);
            }
        }
        
                /// <summary>
        ///  随从向玩家瞬移
        /// </summary>
        public class PetLockState : State
        {
            private long endTime;//瞬移后定住时间
            private bool markRemove;
            public PetLockState(InstanceUnit unit)
                : base(unit)
            {
                endTime = CommonLang.CUtils.CurrentTimeMS + 1*1000;  //持续时间1秒
            }

            public override void MarkRemove()
            {
                this.markRemove = true;
            }

            override public bool onBlock(State new_state)
            {
                return true;                
            }

            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.PetLock);
            }

            override protected void onUpdate()
            {
                if(this.markRemove)
                {
                    unit.startIdle();
                }
                else
                {
                    if (CommonLang.CUtils.CurrentTimeMS > endTime)
                    {
                        unit.startIdle();
                        return;
                    }
                }
            }

            override protected void onStop()
            {
                unit.SetActionStatus(UnitActionStatus.Idle);
            }
        }


		/// <summary>
		/// 渡劫场景,不能移动
		/// </summary>
		public class StateDuJie : State, IStateNoneControllable

		{
			public StateDuJie(InstanceUnit unit)
				: base(unit)
			{
			}
			public State AsState()
			{
				return this;
			}
			override public bool onBlock(State new_state)
			{
				return unit.chuangongTime < CommonLang.CUtils.localTimeMS;
			}

			override protected void onStart()
			{
				// 管他多长时间,锁一个小时再说
				unit.chuangongTime = CommonLang.CUtils.localTimeMS + 3600000;
				unit.SetActionStatus(UnitActionStatus.CrossRobbery);
			}
			override protected void onUpdate()
			{
				//if (unit.chuangongTime < CommonLang.CUtils.localTimeMS)
				//{
				//	unit.doSomething();
				//}
			}
			override protected void onStop()
			{
				unit.SetActionStatus(UnitActionStatus.Idle);
			}
		}

		/// <summary>
		/// 渡劫场景,不能移动
		/// </summary>
		public class StateTransport : State, IStateNoneControllable
		{
			private long mLockEndTime = 0;
			public StateTransport(InstanceUnit unit)
				: base(unit)
			{
			}
			public State AsState()
			{
				return this;
			}

			override public bool onBlock(State new_state)
			{
				if(new_state is StateSkill)
				{
					return true;
				}

				return unit.chuangongTime < CommonLang.CUtils.localTimeMS;
			}

			override protected void onStart()
			{
				// 管他多长时间,锁定300ms
				this.mLockEndTime = CommonLang.CUtils.localTimeMS + 250;
				unit.SetActionStatus(UnitActionStatus.Transport);
				//System.Console.WriteLine("开始传送状态:" + CommonLang.CUtils.localTimeMS);
			}
			override protected void onUpdate()
			{
				if (this.mLockEndTime <= CommonLang.CUtils.localTimeMS)
				{
					unit.doSomething();
				}
			}

			override protected void onStop()
			{
				unit.SetActionStatus(UnitActionStatus.Idle);
				//System.Console.WriteLine("end传送状态:" + CommonLang.CUtils.localTimeMS);
			}
		}

		//---------------------------------------------------------------------------------------
		/// <summary>
		/// 状态限制移动
		/// </summary>
		abstract public class StateMoveNoneControllable : State, IStateNoneControllable
        {
            private TimeExpire<int> mExpire;
            private MoveAI mMoveAI;
            private MoveBlockResult mLastResult;

            public MoveBlockResult LastMoveResult { get { return mLastResult; } }
            public State AsState()
            {
                return this;
            }

            public StateMoveNoneControllable(InstanceUnit unit, int timeMS)
                : base(unit)
            {
                this.mExpire = new TimeExpire<int>(timeMS);
                this.mMoveAI = new MoveAI(unit, false);
            }

            /// <summary>
            /// 搜索要去的地方
            /// </summary>
            /// <returns></returns>
            protected abstract Vector2 FindTargetPos();

            public override bool onBlock(State new_state)
            {
                if (new_state is StateDead)
                {
                    return true;
                }
                if (new_state is StateDamage)
                {
                    (new_state as StateDamage).SetNextNoneControllable(this);
                    return true;
                }
                if (new_state is StateSkill)
                {
                    StateSkill ss = new_state as StateSkill;
                    // 反击或者状态解除//
                    if (ss.SkillData.IsCounter)
                    {
                        return true;
                    }
                }
                return mExpire.IsEnd;
            }

            protected override void onStart()
            {
                Vector2 target = this.FindTargetPos();
                this.mMoveAI.FindPath(target.X, target.Y);
            }

            protected override void onUpdate()
            {
                if (mExpire.Update(zone.UpdateIntervalMS))
                {
                    unit.doSomething();
                }
                else
                {
                    mLastResult = mMoveAI.Update();
                    if ((mLastResult.result & MoveResult.RESULTS_MOVE_END) != 0)
                    {
                        Vector2 target = this.FindTargetPos();
                        this.mMoveAI.FindPath(target.X, target.Y);
                    }
                }
            }

            protected override void onStop()
            {

            }
        }

		/// <summary>
		///  拾取状态
		/// </summary>
		public class StateAutoPick : State
		{
			private InstanceItem mPickItem;         //要自动拾取的物品
			private MoveAI mMoveAi;
			bool mIsEnd;

			public StateAutoPick(InstanceUnit unit, InstanceItem item)
				: base(unit)
			{
				this.mPickItem = item;
				this.mMoveAi = new MoveAI(unit);
				this.mMoveAi.FindPath(item.X, item.Y);
			}


			override public bool onBlock(State new_state)
			{
				if (unit.IsDead())
				{
					return true;
				}

				return true;
			}

			override protected void onStart()
			{
				//unit.SetActionStatus(UnitActionStatus.AutoPick);
			}

			override protected void onUpdate()
			{
				if (mIsEnd || this.mPickItem.IsDead() || !this.mPickItem.Enable || this.unit.Virtual.GetBattleStatus() != BattleStatus.None)
				{
					unit.doSomething();
				}
				else
				{
					MoveBlockResult result = mMoveAi.Update();

					if ((result.result & MoveResult.MOVE_RESULT_NO_WAY) != 0)
					{
						mIsEnd = true;
						unit.doSomething();
					}
					else
					{
						float r = Math.Max(zone.MinStep, unit.BodyBlockSize);
						if (CMath.includeRoundPoint(unit.X, unit.Y, r, mPickItem.X, mPickItem.Y))
						{
							mIsEnd = true;
							unit.doSomething();
						}
					}
				}
			}

			override protected void onStop()
			{
				unit.SetActionStatus(UnitActionStatus.Idle);
			}
		}

		//---------------------------------------------------------------------------------------
		/// <summary>
		/// 逃跑状态
		/// </summary>
		public class StateEscape : StateMoveNoneControllable
        {
            private float mDistance;

            public StateEscape(InstanceUnit unit, int timeMS, float distance = 0) : base(unit, timeMS)
            {
                if (distance > 0)
                {
                    this.mDistance = distance;
                }
                else
                {
                    this.mDistance = unit.Info.GuardRange;
                }
            }
            protected override void onStart()
            {
                base.onStart();
                unit.SetActionStatus(UnitActionStatus.Escape);
            }
            protected override Vector2 FindTargetPos()
            {
                var node = zone.PathFinder.FindNearRandomMoveableNode(zone.RandomN, unit.X, unit.Y, mDistance);
                return new Vector2(node.BX, node.BY);
            }
        }

        //---------------------------------------------------------------------------------------
        /// <summary>
        /// 混乱状态
        /// </summary>
        public class StateChaos : StateMoveNoneControllable
        {
            public StateChaos(InstanceUnit unit, int timeMS) : base(unit, timeMS)
            {
            }
            protected override void onStart()
            {
                base.onStart();
                unit.SetActionStatus(UnitActionStatus.Chaos);
            }
            protected override void onStop()
            {
                base.onStop();
            }
            protected override Vector2 FindTargetPos()
            {
                var node = zone.PathFinder.FindNearRandomMoveableNode(zone.RandomN, unit.X, unit.Y, unit.Info.GuardRange);
                return new Vector2(node.BX, node.BY);
            }

        }


		//---------------------------------------------------------------------------------------
		/// <summary>
		/// 破定
		/// </summary>
		public class StateBreakShield : State
		{
			private long mStateEndTime;
			public StateBreakShield(InstanceUnit unit) : base(unit)
			{
				this.mStateEndTime = CommonLang.CUtils.localTimeMS + GlobalData.SHIELD_BREAK_HOLDTIME;
			}
			protected override void onStart()
			{
				unit.SetActionStatus(UnitActionStatus.BreakShield);
				unit.AddBuff(GlobalData.SHIELD_BREAK_BUFF, 0, true);
			}

			protected override void onUpdate()
			{
				if(CommonLang.CUtils.localTimeMS > this.mStateEndTime)
				{
					unit.startIdle();
				}
			}

			public override bool onBlock(State new_state)
			{
				if (CommonLang.CUtils.localTimeMS > this.mStateEndTime)
				{
					return true;
				}
				else if (new_state is StateDead)
				{
					return true;
				}

				return false;
			}

			protected override void onStop()
			{
				unit.SetActionStatus(UnitActionStatus.Idle);
				//unit.removeBuff(GlobalData.SHIELD_BREAK_BUFF);
				unit.Virtual.StartRecoverMP();
			}
		}

		//---------------------------------------------------------------------------------------
		#endregion
		#region __AI行为__
		//---------------------------------------------------------------------------------------
		/// <summary>
		/// 移动状态
		/// </summary>
		abstract public class StateFollow : State
        {
            public enum MoveState
            {
                Hold,
                Move,
            }

            // 被追目标
            protected IPositionObject target;
            // 如果被单位碰撞,则向左或右挪动//
            readonly private MoveAI moveAI;
            // 检测切换走停的间隔时间 //
            readonly private State<MoveState> state = new State<MoveState>(MoveState.Move);
            readonly private bool begin_in_min_range;
            // 检测切换走停的间隔时间 //
            private TimeInterval<int> start_move_hold_time;

            public abstract bool IsActive { get; }
            public MoveAI MoveAI
            {
                get
                {
                    return moveAI;
                }
                private set { }
            }

            public bool IsNoWay { get { if (moveAI != null) { return moveAI.IsNoWay; } return false; } }
            public IPositionObject Target { get { return target; } }
            public MoveState FollowState { get { return state.Value; } }
            /// <summary>
            /// Hold到Move之间的检测间隔
            /// </summary>
            public int StartMoveHoldTimeMS
            {
                get { return (start_move_hold_time != null) ? start_move_hold_time.IntervalTimeMS : 0; }
                set
                {
                    if (value > 0 && value != StartMoveHoldTimeMS)
                    {
                        start_move_hold_time = new TimeInterval<int>(value);
                    }
                }
            }

            public StateFollow(InstanceUnit unit, InstanceZoneObject target, bool beginInMinRange = true, int holdTime = 0) : base(unit)
            {
                this.begin_in_min_range = beginInMinRange;
                this.target = target;
                this.moveAI = new MoveAI(unit, true, holdTime);
            }


            public override bool onBlock(State new_state)
            {
                return true;
            }

            protected override void onStart()
            {
                if (this.unit.Info.SumType == SummonType.AwaitMaster || cheekBeginInRange())
                {
                    state.ChangeState(MoveState.Hold);
                    unit.SetActionStatus(UnitActionStatus.Idle);
                }
                else
                {
                    state.ChangeState(MoveState.Move);
                    unit.SetActionStatus(UnitActionStatus.Move);
                    moveAI.FindPath(target);
                }
            }

			protected virtual void OnMoveAiNoWay() { }

            protected override void onUpdate()
            {
                if (!IsActive)
                {
                    unit.doSomething();
                }
                else if ((unit.CurrentActionSubstate & (int)UnitActionSubStatus.CanNotMove) > 0)
                {
                    //不能移动,啥事也不干
                }
                else
                {
                    switch (FollowState)
                    {
                        case MoveState.Move:
							// 进入最小追踪距离 //
							if (CheckTargetInMinRange() == true)
							{
								changeToHold();
							}
							else
							{
								if (moveAI.Target == null)
								{
									moveAI.FindPath(target);
								}
								moveAI.Update();

								if (moveAI.IsNoWay)
								{
									this.OnMoveAiNoWay();
									if (CheckTargetInMaxRange() == true)
									{
										changeToHold();
									}
									else
									{
										unit.doSomething();
									}
								}
							}
						
                            break;
                        case MoveState.Hold:
                            // 超过最大追踪范围 //
                            if (unit.IsMoveAble() && (start_move_hold_time == null || start_move_hold_time.Update(zone.UpdateIntervalMS)) && !CheckTargetInMaxRange())
                            {
                                changeToMove();
                            }
                            else
                            {
                                if (unit.CurrentActionStatus != UnitActionStatus.Idle)
                                {
                                    unit.SetActionStatus(UnitActionStatus.Idle);
                                }
                            }
                            onUpdateFollowed(target);
                            break;
                    }
                }
            }

            protected override void onStop() { }

            private bool cheekBeginInRange()
            {
                if (begin_in_min_range)
                {
                    return CheckTargetInMinRange();
                }
                else
                {
                    return CheckTargetInMaxRange();
                }
            }
            private void changeToMove()
            {
                state.ChangeState(MoveState.Move);
                unit.SetActionStatus(UnitActionStatus.Move);
                moveAI.FindPath(target);
                onInRangeChanged();
                onChangedToMove(target);
            }
            private void changeToHold()
            {
                state.ChangeState(MoveState.Hold);
                unit.SetActionStatus(UnitActionStatus.Idle);
                moveAI.Pause();
                onInRangeChanged();
                onChangedToHold(target);
            }

            /// <summary>
            /// 检查目标是否在跟随范围内。
            /// 检测为True,停止移动。
            /// </summary>
            protected abstract bool CheckTargetInMinRange();
            /// <summary>
            /// 检查目标是否在跟随范围内。
            /// 检测为False,开始移动。
            /// </summary>
            protected abstract bool CheckTargetInMaxRange();

            /// <summary>
            /// 行为改变
            /// </summary>
            protected virtual void onInRangeChanged()
            {

            }
            /// <summary>
            /// 目标已经被追踪到
            /// </summary>
            /// <param name="target"></param>
            protected virtual void onUpdateFollowed(IPositionObject target)
            {

            }
            /// <summary>
            /// 开始移动
            /// </summary>
            /// <param name="target"></param>
            protected virtual void onChangedToMove(IPositionObject target)
            {

            }
            /// <summary>
            /// changeToHold
            /// </summary>
            /// <param name="target"></param>
            protected virtual void onChangedToHold(IPositionObject target)
            {

            }
        }

        /// <summary>
        /// 
        /// </summary>
        public class StateFollowObject : StateFollow
        {
            protected float distance;
            //protected InstanceZoneObject target;
            public override bool IsActive
            {
                get
                {
                    var t = target as InstanceZoneObject;
                    if (t != null)
                    {
                        return t.Enable;
                    }
                    return false;
                }
            }

            public float Distance
            {
                set
                {
                    this.distance = value;
                }
                get
                {
                    return this.distance;
                }
            }

            public StateFollowObject(InstanceUnit unit, InstanceZoneObject target, int holdTime = 0)
                : base(unit, target, true, holdTime)
            {
                //this.target = target;
                this.distance = Target.RadiusSize + unit.BodyBlockSize * 2;
            }
            protected override bool CheckTargetInMaxRange()
            {
                return CMath.includeRoundPoint(
                        unit.X, unit.Y,
                        distance * 2,
                        Target.X, Target.Y);
            }
            protected override bool CheckTargetInMinRange()
            {
                return CMath.includeRoundPoint(
                        unit.X, unit.Y,
                        distance,
                        Target.X, Target.Y);
            }
        }

		public class VStateFollowLeader : StateFollowObject
		{
			public VStateFollowLeader(InstanceUnit unit, InstanceZoneObject target, int holdTime = 0) : base(unit, target, holdTime)
			{
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public class StateFollowAndGuard : StateFollow
        {
            private readonly float distance_min;
            private readonly float distance_max;
            private readonly InstanceUnit targetUnit;

            public InstanceUnit TargetUnit { get { return targetUnit; } }
            public override bool IsActive { get { return targetUnit.Enable; } }

            public StateFollowAndGuard(InstanceUnit unit, InstanceUnit target, float minDistance, float maxDistance)
                : base(unit, target)
            {
                this.targetUnit = target;
                this.distance_min = Math.Max(minDistance, target.BodyBlockSize + unit.BodyBlockSize * 2);
                this.distance_max = Math.Max(maxDistance, distance_min);
            }
            protected override bool CheckTargetInMinRange()
            {
                return CMath.includeRoundPoint(
                        unit.X, unit.Y,
                        distance_min,
                        Target.X, Target.Y);
            }
            protected override bool CheckTargetInMaxRange()
            {
                return CMath.includeRoundPoint(
                        unit.X, unit.Y,
                        distance_max,
                        Target.X, Target.Y);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public class StateFollowAndAttack : StateFollow
        {
            /*readonly private*/
            InstanceUnit targetUnit;

            private SkillTemplate.CastTarget expectTarget;
            private TimeInterval<int> checkAdjustLaunchSkillTime;
            private SkillState launchSkill;
            private bool can_auto_focus_near_target;
            private bool can_random_skill = true;
            private bool can_attack = true;

            private float min_distance = -1;
            private float max_distance = -1;

            /// <summary>
            /// 是否追踪
            /// </summary>
            /// <returns></returns>
            override public bool IsActive
            {
                get { return can_attack && targetUnit.IsActive; }
            }
            public SkillState ExpectSkillState
            {
                get { return launchSkill; }
                set
                {
                    launchSkill = value;
                    expectTarget = value.Data.ExpectTarget;
                }
            }
            public SkillTemplate ExpectSkill
            {
                get { return (launchSkill != null) ? launchSkill.Data : unit.DefaultSkill; }
            }
            public InstanceUnit TargetUnit
            {
                get { return targetUnit; }
                set { targetUnit = value; }
            }
            public SkillTemplate.CastTarget ExpectTarget
            {
                get { return expectTarget; }
            }
            public bool IsLaunchRandomSkill
            {
                get { return can_random_skill; }
                set { can_random_skill = value; }
            }
            public bool IsAutoFocusNearTarget
            {
                get { return can_auto_focus_near_target; }
                set { can_auto_focus_near_target = value; }
            }

            public StateFollowAndAttack(
                InstanceUnit unit,
                InstanceUnit target,
                SkillTemplate.CastTarget expectTarget = SkillTemplate.CastTarget.Enemy,
                bool autoFocusNearTarget = false)
                : base(unit, target, false)
            {
                this.targetUnit = target;
                // Console.WriteLine(" - - - - StateFollowAndAttack - - - - " + this.TargetUnit.Name);
                this.expectTarget = expectTarget;
                this.can_auto_focus_near_target = autoFocusNearTarget;
                this.StartMoveHoldTimeMS = zone.Templates.CFG.AI_FOLLOW_AND_ATTACK_HOLD_TIME_MS;
            }
            protected override void onStart()
            {
                this.checkAdjustLaunchSkillTime = new TimeInterval<int>(zone.Templates.CFG.AI_FOLLOW_AND_ATTACK_HOLD_TIME_MS);
                this.launchSkill = unit.getRandomLaunchableExpectSkill(expectTarget);
                base.onStart();
            }
            protected override void onUpdateFollowed(IPositionObject target)
            {
                this.can_attack = zone.IsAttackable(unit, targetUnit, expectTarget, AttackReason.Tracing, this.ExpectSkill);
                if (can_attack)
                {
                    unit.faceTo(target.X, target.Y);
                    if (TryLaunchSkill() == null)
                    {
                        SkillTemplate expect_skill = ExpectSkill;
                        if (expect_skill != null && expect_skill.AttackKeepRange > 0)
                        {
                            if (checkAdjustLaunchSkillTime.IntervalTimeMS == 0 || checkAdjustLaunchSkillTime.Update(zone.UpdateIntervalMS))
                            {
                                if (CUtils.RandomPercent(zone.RandomN, zone.Templates.CFG.AI_FOLLOW_AND_ATTACK_ADJUST_ESCAPE_PCT))
                                {
                                    unit.startAdjustLaunchSkill(expect_skill, targetUnit, this.OnEndAdjustKeepRange);
                                }
                            }
                        }
                    }
                }
            }

            protected override void onUpdate()
            {
				if (IsActive)
                {
                    resetMaxMinRange();
                }
                base.onUpdate();
            }

            private void resetMaxMinRange()
            {
                var expect_skill = ExpectSkillState;
                bool needCheck = true;
                if (expect_skill == null)
                {
                    var new_skill = unit.getRandomLaunchableExpectSkill(targetUnit, expectTarget, AttackReason.Tracing, true);
                    if (new_skill != null)
                    {
                        ExpectSkillState = new_skill;
                        expect_skill = new_skill;
                        needCheck = false;
                    }
                }
                if(expect_skill == null )
                {
                    expect_skill = unit.DefaultSkillStatus();
                }

                if (expect_skill != null)
                {
                    min_distance = unit.BodyBlockSize + targetUnit.BodyBlockSize;
                    max_distance = Math.Max(min_distance, unit.BodyBlockSize + targetUnit.BodyHitSize);
                    if (can_random_skill)
                    {
                        if (needCheck == true && !expect_skill.checkTargetRange(targetUnit))
                        {
                            var new_skill = unit.getRandomLaunchableExpectSkill(targetUnit, expectTarget, AttackReason.Tracing, true);
                            if (new_skill != null)
                            {
                                ExpectSkillState = new_skill;
                                expect_skill = new_skill;
                            }
                        }
                    }
                    float skill_distance = unit.GetSkillAttackRange(expect_skill.Data);
                    float half = (skill_distance - min_distance) / 2;
                    if (expect_skill.Data.AttackKeepRange > 0 && expect_skill.Data.AttackRange > expect_skill.Data.AttackKeepRange)
                    {
                        min_distance = Math.Max(min_distance, unit.GetSkillAttackRange(expect_skill.Data.AttackKeepRange) + targetUnit.BodyBlockSize);
                        max_distance = Math.Max(max_distance, min_distance);
                    }
                    else if (half > 0)
                    {
                        min_distance = min_distance + half;
                        max_distance = Math.Max(skill_distance, min_distance);
                    }
                    else
                    {
                        min_distance = Math.Max(min_distance, skill_distance + targetUnit.BodyBlockSize);
                        max_distance = Math.Max(max_distance, min_distance);
                    }
                    max_distance = Math.Max(max_distance, skill_distance + targetUnit.BodyHitSize);
                }
            }

            protected override bool CheckTargetInMaxRange()
            {
                if (max_distance < 0) return true;
                return CMath.includeRoundPoint(unit.X, unit.Y, max_distance, targetUnit.X, targetUnit.Y);
            }
            protected override bool CheckTargetInMinRange()
            {
                if(min_distance < 0) return true;
                return CMath.includeRoundPoint(unit.X, unit.Y, min_distance, targetUnit.X, targetUnit.Y);
            }
            protected virtual bool OnEndAdjustKeepRange(StateMove m)
            {
                unit.faceTo(Target.X, Target.Y);
                unit.changeState(this);
                return true;
            }
            protected virtual SkillTemplate TryLaunchSkill()
            {
                if (launchSkill == null)
                {
                    this.launchSkill = unit.getRandomLaunchableExpectSkill(expectTarget);
                }
                StateSkill ret = null;
                Vector2 targetPos = null;
                if (launchSkill != null)
                {
                    ret = unit.launchSkill(launchSkill, new InstanceUnit.LaunchSkillParam(targetUnit.ID, targetPos, can_auto_focus_near_target));
                    if (ret != null)
                    {
                        return ret.SkillData;
                    }
                }
                if (can_random_skill)
                {
                    ret = unit.launchRandomSkill(expectTarget, new InstanceUnit.LaunchSkillParam(targetUnit.ID, targetPos, can_auto_focus_near_target));
                    if (ret != null)
                    {
                        return ret.SkillData;
                    }
                }
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public class StateFollowAndPickObject : StateFollow
        {
            private readonly InstanceZoneObject targetObject;
            private readonly int pickTimeMS;
            private readonly StatePickObject.OnPickDone doneEvent;
            private readonly string status;

            public StateFollowAndPickObject(InstanceUnit unit, InstanceZoneObject target, int timeMS, StatePickObject.OnPickDone done, string status = null)
                : base(unit, target, false)
            {
                this.targetObject = target;
                this.pickTimeMS = timeMS;
                this.doneEvent = done;
                this.status = status;
            }
            public override bool IsActive
            {
                get { return targetObject.Enable; }
            }
            protected override bool CheckTargetInMinRange()
            {
                return CMath.includeRoundPoint(unit.X, unit.Y, unit.BodyBlockSize, targetObject.X, targetObject.Y);
            }
            protected override bool CheckTargetInMaxRange()
            {
                return CMath.includeRoundPoint(unit.X, unit.Y, unit.BodyBlockSize + targetObject.BodyBlockSize, targetObject.X, targetObject.Y);
            }
            protected override void onUpdateFollowed(IPositionObject target)
            {
                unit.startPickProgressObject(targetObject, pickTimeMS, doneEvent, status);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public class StateFollowAndPickItem : StateFollow
        {
            public readonly InstanceItem targetObject;
			private long mLockEndTime;
			private bool mDoPick;
			private bool mMarkBlock;

            public StateFollowAndPickItem(InstanceUnit unit, InstanceItem target, bool doPick)
                : base(unit, target, false)
            {
                this.targetObject = target;
				this.mDoPick = doPick;
			}

            public override bool IsActive
            {
                get { return (targetObject.Enable && targetObject.IsPosValid()) || mLockEndTime > CommonLang.CUtils.localTimeMS; }
            }

			public bool IsBlock()
			{
				return this.mMarkBlock;
			}

            protected override bool CheckTargetInMinRange()
            {
                return CMath.includeRoundPoint(unit.X, unit.Y, unit.BodyBlockSize, targetObject.X, targetObject.Y);
            }
            protected override bool CheckTargetInMaxRange()
            {
                return CMath.includeRoundPoint(unit.X, unit.Y, unit.BodyBlockSize + targetObject.BodyBlockSize, targetObject.X, targetObject.Y);
            }
            protected override void onUpdateFollowed(IPositionObject target)
            {
				if (this.mDoPick && this.targetObject.Enable)
				{					
					targetObject.PickItem(unit);
				}				
            }

			public void CheckAndLockPickTime()
			{
				if(!this.targetObject.Enable && mLockEndTime == 0)
				{
					mLockEndTime = CommonLang.CUtils.localTimeMS + 350;
				}
			}


			protected override void onUpdate()
			{
				this.CheckAndLockPickTime();
				if (!this.IsActive && unit.IsPlayer)
				{
					if (unit.DoAutoPick(true))
					{
						return;
					}					
				}				
				
				base.onUpdate();			
			}

			protected override void OnMoveAiNoWay()
			{
				this.mLockEndTime = 0;
				targetObject.setPosNotValid();
			}

			public override bool onBlock(State new_state)
			{
				if(/*!(new_state is StateFollowAndPickItem) && */mLockEndTime > CommonLang.CUtils.localTimeMS)
				{
					return false;
				}

				//把当前拾取弄完,再去跟随
				if (new_state is VStateFollowLeader && unit.DoAutoPick(true))
				{
					return false;
				}
				
				return true;
			}

			protected override void onStop()
			{
				this.mMarkBlock = true;
			}

		}


        /// <summary>
        /// 
        /// </summary>
        public abstract class StateAttackTo : State
        {
            public IPositionObject Target { get { return target; } }
            public MoveBlockResult LastMovingResult { get; private set; }
            public MoveAI UnitMoveAI { get { return moveAI; } }
            // 如果被地图碰撞,则寻路
            private IPositionObject target;
            // 如果被单位碰撞,则向左或右挪动
            private MoveAI moveAI;
            private int holdTimeMS;
			private long mPeaceEndTime;

            public StateAttackTo(InstanceUnit unit, int move_ai_hold_time_ms = -1, int peaceTime = 0)
                : base(unit)
            {
                this.holdTimeMS = move_ai_hold_time_ms;
				this.mPeaceEndTime = CommonLang.CUtils.CurrentTimeMS + peaceTime;
			}
            override public bool onBlock(State new_state)
            {
				if(this.mPeaceEndTime > CommonLang.CUtils.CurrentTimeMS)
				{
					return false;
				}

                return true;
            }
            override protected void onStart()
            {
                if (target == null)
                {
                    target = PopNextPos();
                }
                this.moveAI = new MoveAI(unit, true, holdTimeMS);
                if (target != null)
                {
                    this.moveAI.FindPath(target);
                    unit.SetActionStatus(UnitActionStatus.Move);
                }
                else
                {
                    unit.SetActionStatus(UnitActionStatus.Idle);
                }
            }

            override protected void onUpdate()
            {
                if (target == null)
                {
                    unit.doSomething();
                }
                else
                {
                    LastMovingResult = this.moveAI.Update();
                    if (TestPopNext())
                    {
                        this.target = PopNextPos();
                        if (target != null)
                        {
                            this.moveAI.FindPath(target);
                        }
                    }
                }
            }

            override protected void onStop()
            {

            }

            abstract protected bool HasNextPos();
            abstract protected IPositionObject PopNextPos();

            protected virtual bool TestPopNext()
            {
                if (CMath.includeRoundPoint(unit.X, unit.Y, unit.Info.GuardRange, target.X, target.Y))
                {
                    return true;
                }
                return false;
            }

            public virtual bool IsDone
            {
                get
                {
                    if (IsStarted)
                    {
                        if (target == null)
                        {
                            return true;
                        }
                        if (HasNextPos())
                        {
                            return false;
                        }
                        return TestPopNext();
                    }
                    return false;
                }
            }
        }

        public class StateAttackToZoneWayPoint : StateAttackTo
        {
            // 如果被地图碰撞,则寻路
            private ZoneWayPoint paths;
            private ZoneWayPoint prev;

            protected ZoneWayPoint Paths { get { return paths; } }

            public StateAttackToZoneWayPoint(InstanceUnit unit, ZoneWayPoint wps, int peaceTime)
                : base(unit, -1, peaceTime)
            {
                this.paths = wps;
            }

            protected override bool HasNextPos()
            {
                return paths != null;
            }

            protected override IPositionObject PopNextPos()
            {
                if (paths != null)
                {
                    ZoneWayPoint ret = paths;
                    ZoneWayPoint prv = prev;
                    prev = paths;
                    paths = paths.GetRandomNext(prv);
                    return ret;
                }
                return null;
            }

            protected override bool TestPopNext()
            {
                if (LastMovingResult.obj != null)
                {
                    if (CMath.includeRoundPoint(unit.X, unit.Y, unit.Info.GuardRange, Target.X, Target.Y))
                    {
                        return true;
                    }
                }
                else
                {
                    if (CMath.includeRoundPoint(unit.X, unit.Y, unit.BodyBlockSize, Target.X, Target.Y))
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        public class StatePatrolWayPoint : StateAttackTo
        {
            // 如果被地图碰撞,则寻路
            private ZoneWayPoint paths;
            private ZoneWayPoint prev;
            private TimeExpire<int> hold_time;
            private int hold_max_time_ms, hold_min_time_ms;
            protected ZoneWayPoint Paths { get { return paths; } }

            public StatePatrolWayPoint(InstanceUnit unit, ZoneWayPoint wps, int hold_max_time_ms, int hold_min_time_ms, int peaceTime)
                : base(unit, -1, peaceTime)
            {
                this.paths = wps;
                this.hold_max_time_ms = Math.Max(hold_max_time_ms, hold_min_time_ms);
                this.hold_min_time_ms = Math.Min(hold_max_time_ms, hold_min_time_ms);
            }

            protected override void onUpdate()
            {
                if (this.hold_time != null)
                {
                    if (this.hold_time.Update(zone.UpdateIntervalMS))
                    {
                        this.hold_time = null;
                    }
                }
                else
                {
                    base.onUpdate();
                }
            }

            protected override bool HasNextPos()
            {
                return paths != null;
            }
            private void Hold()
            {
                if (hold_max_time_ms > 0)
                {
                    unit.SetActionStatus(UnitActionStatus.Idle);
                    this.hold_time = new TimeExpire<int>(unit.RandomN.Next(hold_min_time_ms, hold_max_time_ms));
                }
            }
            protected override IPositionObject PopNextPos()
            {
                if (paths != null)
                {
                    ZoneWayPoint ret = paths;
                    ZoneWayPoint prv = prev;
                    prev = paths;
                    paths = paths.GetRandomNext(prv);
                    Hold();
                    return ret;
                }
                return null;
            }

            protected override bool TestPopNext()
            {
                if (LastMovingResult.obj != null)
                {
                    if (CMath.includeRoundPoint(unit.X, unit.Y, unit.Info.GuardRange, Target.X, Target.Y))
                    {
                        return true;
                    }
                }
                else
                {
                    if (CMath.includeRoundPoint(unit.X, unit.Y, unit.BodyBlockSize, Target.X, Target.Y))
                    {
                        return true;
                    }
                }
                return false;
            }
        }


        /// <summary>
        /// 
        /// </summary>
        public class StateGuardInPosition : State
        {
            public Vector2 Target { get { return target; } }
            public MoveBlockResult LastMovingResult { get; private set; }

            // 如果被地图碰撞,则寻路
            private Vector2 target;
            // 如果被单位碰撞,则向左或右挪动
            private MoveAI moveAI;

            public StateGuardInPosition(InstanceUnit unit, Vector2 target)
                : base(unit)
            {
                this.target = target;
                this.moveAI = new MoveAI(unit);
            }
            override public bool onBlock(State new_state)
            {
                return true;
            }
            override protected void onStart()
            {
                this.moveAI.FindPath(target.X, target.Y);
                if (moveAI.IsNoWay)
                {
                    unit.SetActionStatus(UnitActionStatus.Idle);
                }
                else
                {
                    unit.SetActionStatus(UnitActionStatus.Move);
                }
            }

            override protected void onUpdate()
            {
                this.LastMovingResult = this.moveAI.Update();
                if ((LastMovingResult.result & MoveResult.RESULTS_MOVE_END) != 0)
                {
                    if ((LastMovingResult.result & MoveResult.MOVE_RESULT_BLOCK_MAP) != 0)
                    {
                        moveAI.Pause();
                        unit.SetActionStatus(UnitActionStatus.Idle);
                    }
                    else if (CMath.includeRoundPoint(unit.X, unit.Y, unit.Info.GuardRange, target.X, target.Y))
                    {
                        moveAI.Pause();
                        unit.SetActionStatus(UnitActionStatus.Idle);
                    }
                }
            }

            override protected void onStop()
            {

            }

        }

        /// <summary>
        /// 
        /// </summary>
        public class StateBackToPosition : State
        {
            public Vector2 Target { get { return target; } }
            public MoveBlockResult LastMovingResult { get; private set; }
            public bool IsDone { get { return isDone; } }

            // 如果被地图碰撞,则寻路
            private Vector2 target;
            // 如果被单位碰撞,则向左或右挪动
            private MoveAI moveAI;
            private bool isDone = false;

            public StateBackToPosition(InstanceUnit unit, Vector2 target)
                : base(unit)
            {
                this.target = target;
                this.moveAI = new MoveAI(unit);
            }
            override public bool onBlock(State new_state)
            {
                if (new_state is StateDamage)
                {
                    return true;
                }
                if (new_state is StateDead)
                {
                    return true;
                }
                return isDone;
            }
            override protected void onStart()
            {
                this.unit.onBack2PositionStart();
                this.moveAI.FindPath(target.X, target.Y);
                if (moveAI.IsNoWay)
                {
                    unit.SetActionStatus(UnitActionStatus.Idle);
                }
                else
                {
                    unit.SetActionStatus(UnitActionStatus.Move);
                }
            }

            override protected void onUpdate()
            {
                this.LastMovingResult = this.moveAI.Update();
                if ((LastMovingResult.result & MoveResult.RESULTS_MOVE_END) != 0)
                {
                    if (CMath.includeRoundPoint(unit.X, unit.Y, unit.Info.GuardRange, target.X, target.Y))
                    {
                        isDone = true;
                        unit.doSomething();
                    }
                    else
                    {
                        moveAI.FindPath(target.X, target.Y);
                    }
                }
            }

            override protected void onStop()
            {
                this.unit.onBack2PositionEnd();
            }


        }

        protected virtual void onBack2PositionEnd()
        {

        }

        protected virtual void onBack2PositionStart()
        {

        }

        #endregion
        //---------------------------------------------------------------------------------------
        #region __强制剧情播放__

        public abstract class ForceState : State
        {
            public ForceState(InstanceUnit unit)
                : base(unit)
            {
            }
            override public bool onBlock(State new_state)
            {
                if (new_state is StateDead) return true;
                if (new_state is StateRebirth) return true;
                if (new_state is StateStun) return true;
                return unit.IsDead();
            }
        }

        /// <summary>
        /// 强制移动到目标点,一般用于剧情动画
        /// </summary>
        public class ForceStateMoveTo : ForceState
        {
            private readonly float targetX;
            private readonly float targetY;
            private bool isEnd = false;
            private MoveAI moveAI;

            public ForceStateMoveTo(InstanceUnit unit, float x, float y)
                : base(unit)
            {
                this.targetX = x;
                this.targetY = y;
            }

            override public bool onBlock(State new_state)
            {
                if (base.onBlock(new_state)) return true;
                return isEnd;
            }
            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.Move);
                this.moveAI = new MoveAI(unit);
                this.moveAI.FindPath(targetX, targetY);
            }
            override protected void onUpdate()
            {
                if (!isEnd)
                {
                    unit.faceTo(targetX, targetY);
                    MoveBlockResult result = moveAI.Update();
                    if ((result.result & MoveResult.MOVE_RESULT_NO_WAY) != 0)
                    {
                        isEnd = true;
                        unit.doSomething();
                    }
                    else if ((result.result & MoveResult.RESULTS_MOVE_END) != 0)
                    {
                        float r = Math.Max(zone.MinStep, unit.BodyBlockSize);
                        if (CMath.includeRoundPoint(unit.X, unit.Y, r, targetX, targetY))
                        {
                            isEnd = true;
                            unit.doSomething();
                        }
                    }
                    else
                    {
                        float r = Math.Max(zone.MinStep, unit.BodyBlockSize);
                        if (CMath.includeRoundPoint(unit.X, unit.Y, r, targetX, targetY))
                        {
                            isEnd = true;
                            unit.doSomething();
                        }
                    }
                }
            }

            override protected void onStop()
            {

            }
        }

        public class ForceStateLaunchSkill : ForceState
        {
            private readonly int SkillID;
            private readonly bool IsRandom;
            private readonly StateStopHandler SkillOver;
            private StateSkill mSkillState;

            public ForceStateLaunchSkill(InstanceUnit unit, int skillID, bool random, StateStopHandler over = null)
                : base(unit)
            {
                this.SkillID = skillID;
                this.IsRandom = random;
                this.SkillOver = over;
            }
            public override bool onBlock(State new_state)
            {
                if (base.onBlock(new_state)) return true;
                if (new_state is StateSkill)
                {
                    return true;
                }
                return mSkillState != null;
            }
            protected override void onStart()
            {

            }
            protected override void onUpdate()
            {
                if (IsRandom)
                {
                    mSkillState = unit.launchRandomSkillForAll(new InstanceUnit.LaunchSkillParam());
                }
                else
                {
                    mSkillState = unit.launchSkill(SkillID, new InstanceUnit.LaunchSkillParam());
                }
                if (mSkillState == null)
                {
                    mSkillState = unit.launchRandomSkillForAll(new InstanceUnit.LaunchSkillParam());
                }
                if (mSkillState != null && SkillOver != null)
                {
                    mSkillState.AddStopOnce(SkillOver);
                }
            }
            protected override void onStop()
            {
                if (mSkillState == null && SkillOver != null)
                {
                    SkillOver.Invoke(unit, this);
                }
            }
        }

        public class ForceStateIdleTime : ForceState
        {
            private readonly TimeExpire<int> mIdleTime;

            public ForceStateIdleTime(InstanceUnit unit, float timeSEC)
                : base(unit)
            {
                mIdleTime = new TimeExpire<int>((int)(timeSEC * 1000));
            }

            override public bool onBlock(State new_state)
            {
                if (base.onBlock(new_state)) return true;
                return mIdleTime.IsEnd;
            }

            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.Idle);
            }

            override protected void onUpdate()
            {
                if (mIdleTime.Update(zone.UpdateIntervalMS))
                {
                    unit.doSomething();
                }
            }
            override protected void onStop() { }
        }

        public class ForceStateActionTime : ForceStateIdleTime
        {
            private readonly string ActionName;

            public ForceStateActionTime(InstanceUnit unit, float timeSEC, string actionName)
                : base(unit, timeSEC)
            {
                this.ActionName = actionName;
            }

            override protected void onStart()
            {
                unit.queueEvent(new UnitDoActionEvent(unit.ID, ActionName));
            }
        }

        #endregion
    }
}