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 CommonLang.Property;
using CommonAI.Zone.Attributes;
using CommonAI.Zone.EventTrigger;
using CommonAI.Zone.Instance.Helper;
using CommonAI.Data;
using static CommonAI.Zone.UnitInfo;
using CommonAI.data;

namespace CommonAI.Zone.Instance
{
    abstract public partial class InstanceUnit : InstanceZoneObject
    {
        private readonly UnitInfo mInfo;
        private readonly DropItemGenerator mDropItems;

        /// <summary>
        /// 统计信息
        /// </summary>
        public IUnitStatistic Statistic { get; private set; }

		//最后一次受伤时间
		public long mLastDamageTime;
		//最后一次攻击事件
		public long mLastHitOtherTime;
		//上一次处理死亡回调时间
		public long mProcessDeadCallbackTime;

        private IFormula mFormula = TemplateManager.Factory.Formula;

        private IVirtualUnit mUnitVirtual;
        private readonly string mName;
        private int mForce = 0;
        private int mAlliesForce = 0;       // 服务器对战情况下,有盟友服务器
        private int mLevel = 0;
        private int mMoney = 0;
        private readonly bool mIsAttackRangeIncludeBodySize;
        // 当前HP
        private readonly RangeValue __mCurrentHP;
        // 当前MP
        private readonly RangeValue __mCurrentMP;
        // 当前移动速度加成
        private float __mCurrentMoveSpeedSEC = 0;
        // 攻速
        private int __mCurrentAttackSpeed = 10000;
        // 当前技能速度加成
        private float __mSkillActionSpeedRate = 0;
        // 当前快速施法速度
        private float mFastCastRate = 0;
        /// <summary>
        /// 当前单位是否地图阻挡
        /// </summary>
        private bool mIntersectMap = false;
        /// <summary>
        /// 当前单位是否单位阻挡
        /// </summary>
        private bool mIntersectObj = false;

        // 当前技能cd减少
        private float __mCurrentSkillCdReduce;

        // 控制减速,韧性
        private float __mCurrentControledTimeReduce;

        // 控制增幅
        private float __mControledTimeAdd;

        /// 单位最后死亡时间
        private long mDeadTime = 0;

        //游戏服标记字段,怪物死亡的时候,回传给游戏服
        public int gameServerFlag = 0;

		//回血
		public int recoverHP = 0;
        
        //随从最后一次瞬移时间
        public long petTeleportTime = 0;
        
        //最后一次返回召回随从操作频繁时间
        public  long lastTeleportTime = 0;

		//绑定攻击玩家
		private string mBindAttackPlayerId;
		//主人id
		private long mRemoveSelfTime;
		private InstanceUnit mBindMaster;

		/// <summary>
		/// 自动恢复计数器 
		/// </summary>
		private TimeInterval<int> mRecoveryTime = null;

        public InstanceUnit(InstanceZone zone, UnitInfo uinfo, string name, int force, int level, bool is_static_block = false, int alliesForce = 0)
            : base(zone, is_static_block)
        {
            this.mInfo = (UnitInfo)uinfo.Clone();
            this.mName = string.IsNullOrEmpty(name) ? "" : name;
            this.mIsAttackRangeIncludeBodySize = zone.Templates.CFG.OBJECT_ATTACK_RANGE_INCLUDE_BODYSIZE;
            this.mForce = force;
            this.mAlliesForce = alliesForce;
            this.mLevel = level;
            this.mIntersectMap = true;
            this.mIntersectObj = !Templates.CFG.OBJECT_NONE_TOUCH && (mInfo.BodySize > 0);
            this.mSyncInfo = new SyncUnitInfo(zone.IsHalfSync);
            this.mSyncInfo.Name = mName;
            this.mSyncInfo.TemplateID = mInfo.ID;
			
			this.__mCurrentHP = new RangeValue(mInfo.HealthPoint, 0, mInfo.HealthPoint);
            this.__mCurrentMP = new RangeValue(mInfo.ManaPoint, 0, mInfo.ManaPoint);
            this.__mCurrentMoveSpeedSEC = mInfo.MoveSpeedSEC;
            this.mDropItems = new DropItemGenerator(uinfo.DropItemsSet);
            this.mTriggerHelper = new UnitTriggerHelper(this);
            if (mInfo.IdleRecover && mInfo.RecoveryIntervalMS > 0)
            {
                this.mRecoveryTime = new TimeInterval<int>(mInfo.RecoveryIntervalMS);
				this.recoverHP = Info.HealthRecoveryPoint;
			}
            this.InitTimeLines();
            this.InitBagSlots();
            this.InitSkills(mInfo.BaseSkillID, mInfo.Skills.ToArray());
            this.Statistic = this.CreateUnitStatistic();
            this.mUnitVirtual = TemplateManager.Factory.CreateUnitVirtual(this);			
		}

		public override bool IsNeedProcessDead()
		{
			return this.mProcessDeadTime == 0;
		}

		protected override void Disposing()
        {
			//if(this.IsMonster && (this.mProcessDeadTime == 0 || this.CurrentHP > 0 || this.mProcessDeadTime == 0))
			//{
			//	log.Info("单位Disposing:" + this.Parent.UUID + ", " + this.Parent.GetSceneID() + ", " + this.ID + ", " + this.CurrentHP + "," +
			//		this.IsMonster + ", " + mProcessDeadTime);
			//}

            if (mUnitVirtual != null)
            {
                mUnitVirtual.OnDispose(this);
            }
            base.Disposing();
            this.clearBindEvents();
            this.clearSkills();
            this.clearBuffs();
            this.clearItemSlots();
            this.clearTriggers();
        }

        protected override void onAdded(bool pointLv)
        {
            if (this.mUnitVirtual != null)
            {
                this.mUnitVirtual.OnInit(this, pointLv);
				if (this.mRecoveryTime != null && this.Info.UType == UnitType.TYPE_MONSTER)
				{
					this.recoverHP = Info.HealthRecoveryPoint == 0 ? (int)(this.MaxHP * 0.005f) : Info.HealthRecoveryPoint;
				}
            }

            this.mSyncInfo.ObjectID = base.ID;
            this.mSyncInfo.IsTouchObj = this.mIntersectObj;
            this.mSyncInfo.IsTouchMap = this.mIntersectMap;
            this.mSyncInfo.IsStaticBlockable = this.IsStaticBlockable;
			this.mSyncInfo.fateType = (byte)this.Virtual.GetUnitFateType();

			if (mInfo.SpawnTimeMS > 0)
			{
				this.SetInvincibleTimeMS(mInfo.SpawnTimeMS);
			}
           
            if (this.mInfo.InventoryList != null)
            {
                foreach (InventoryItem item in mInfo.InventoryList)
                {
                    ItemTemplate temp = Templates.getItem(item.ItemTemplateID);
                    if (temp != null)
                    {
                        AddItemToEmptyInventory(temp, item.Count);
                    }
                }
            }
            if (mInfo.Events != null)
            {
                foreach (int evt_id in mInfo.Events)
                {
                    this.BindUnitEvent(evt_id);
                }
            }

            if (mOnAdded != null)
            {
                mOnAdded.Invoke(this);
            }
        }
        protected override void onRemoved()
        {
            if (mOnRemoved != null)
            {
                mOnRemoved.Invoke(this);
            }
            foreach (UnitEventTriggerCollection uc in mBindEvents.Values)
            {
                uc.Dispose();
            }
            mBindEvents.Clear();
            if (Info.RemovedEffect != null)
            {
                Parent.queueEvent(new AddEffectEvent(this.ID, X, Y, Direction, Info.RemovedEffect));
            }
        }

		public void BindAttackPlayer(string playerId)
		{
			this.mBindAttackPlayerId = playerId;
		}

		public string GetAttackPlayer()
		{
			return this.mBindAttackPlayerId;
		}

		public void BindMasterId(int masterId)
		{
			InstanceUnit master = this.Parent.getUnitByID(masterId);
			if(master == null)
			{
				log.Error("BindMasterId找不到单位:" + this.Parent.GetSceneID() + ", " + masterId);
				return;
			}

			if(this.mBindMaster != null)
			{
				log.Error("BindMasterId重复:" + this.Info.ID + ", " + master.PlayerUUID);
				return;
			}

			this.mBindMaster = master;
		}
        

        //--------------------------------------------------------------------------
        /// <summary>
        /// 扩展功能绑定接口
        /// </summary>
        public IVirtualUnit Virtual { get { return mUnitVirtual; } }
        /// <summary>
        /// 扩展数据
        /// </summary>
        public virtual IUnitProperties Properties { get { return mInfo.Properties; } }

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

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

        public UnitInfo Info { get { return mInfo; } }
        public string Name { get { return mName; } }
        public string Alias { get { return mSyncInfo.Alias; } set { if (value != null) { mSyncInfo.Alias = value; } } }
        public int Force { get { return mForce; } protected set { mForce = value; } }
        public int AlliesForce { get { return mAlliesForce; } protected set { mAlliesForce = value; } }
        public float MoveSpeedSEC { get { return __mCurrentMoveSpeedSEC; } }

        public float SkillCdReduce { get { return __mCurrentSkillCdReduce; } }
        public float ControledTimeReduce { get { return __mCurrentControledTimeReduce; } }

        public float ControledTimeAdd { get { return __mControledTimeAdd; } }

        public float FastCastRate { get { return mFastCastRate; } }
        public override float BodyBlockSize { get { return mInfo.BodySize; } }
        public override float BodyHitSize { get { return mInfo.BodyHitSize; } }
        public override float BodyHeight { get { return mInfo.BodyHeight; } }
        public override float Weight { get { return mInfo.Weight; } }
        public override bool IntersectMap { get { return mIntersectMap; } }
        public override bool IntersectObj { get { return mIntersectObj && IsVisible; } }
        public override bool Moveable { get { return mInfo.IsMoveable; } }
        public override bool ClientVisible { get { return true; } }
        public override bool SyncPos { get { return true; } }
        public override bool IsDead (){  return __mCurrentHP.Value <= 0;  }
        public int DeadCount { get { return Statistic.DeadCount; } }
        public long LastDeadTimeMS { get { return mDeadTime; } }
        public bool CanWhiplashDeadBody { get { return Templates.CFG.UNIT_CAN_WHIPLASH_BODY && (LastDeadTimeMS + mInfo.DeadTimeMS > Parent.PassTimeMS); } }
        /// <summary>
        /// 是否为玩家
        /// </summary>
        virtual public bool IsPlayer { get { return false; } }

		virtual public bool IsMonster { get { return false; } }

		virtual public bool IsPet { get { return false; } }

		virtual public void OnUnitDead() {}

		/// <summary>
		/// 是否中立
		/// </summary>
		virtual public bool IsNature { get { return false; } }
        /// <summary>
        /// 此单位是否能被攻击并且活着
        /// </summary>
        virtual public bool IsActive { get { return (base.Enable) && (__mCurrentHP.Value > 0) /*&& !IsInvincible && IsVisible*/; } }
        /// <summary>
        /// 此单位是否可以被打到,包括鞭尸
        /// </summary>
        virtual public bool IsAttackable { get { return (base.Enable) /*&& !IsInvincible && IsVisible*/; } }
        /// <summary>
        /// 此单位是否无技能
        /// </summary>
        public bool IsNoneSkill { get { return mSkillStatus.Count == 0; } }
        /// <summary>
        /// 技能可产生位移,或者多段由服务器决定
        /// </summary>
        virtual public bool IsSkillControllableByServer { get { return true; } }
        /// <summary>
        /// 单位是否可控
        /// </summary>
        virtual public bool IsControllable { get { return IsActive && !IsStun && CurrentActionStatus != UnitActionStatus.Damage; } }

        /// <summary>
        /// 用于显示的,单位横向数据
        /// </summary>
        public ZoneClient.IUnitVisibleData VisibleInfo { get { return mSyncInfo.VisibleInfo; } }


        //-----------------------------------------------------------------------------------------------------//
        protected virtual IUnitStatistic CreateUnitStatistic()
        {
            return new UnitStatistic(this);
        }

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

        #region __StateMachine__

        private bool is_init = false;
        private State current_state = null;
        private State next_state;
        private Queue<State> next_state_queue = new Queue<State>();
        /// <summary>
        /// 当前状态机
        /// </summary>
        public State CurrentState { get { return current_state; } }

        //状态机额外数据
        public long chuangongTime = 0;

        /// <summary>
        /// 下一个状态
        /// </summary>
        protected State NextState { get { return next_state; } }
        /// <summary>
        /// 死亡状态可能的状态机,一般配合<see cref="IsDead"/>使用
        /// </summary>
        public bool IsStateDead
        {
            get
            {
                if ((current_state is StateDead) ||
                    (current_state is StateDamage) ||
                    (current_state is StateDeadFuck) ||
                    (current_state is StateDeadFuckFuck) ||
                    (current_state is StateRebirth) ||
                    (next_state is StateDead) ||
                    (next_state is StateDamage) ||
                    (next_state is StateDeadFuck) ||
                    (next_state is StateDeadFuckFuck) ||
                    (next_state is StateRebirth))
                {
                    return true;
                }
                return false;
            }
        }

        public void queueState(State s)
        {
            next_state_queue.Enqueue(s);
        }

        public bool TryEnqueueIdleState()
        {
            if (next_state_queue.Count > 0)
            {
                return false;
            }
            next_state_queue.Enqueue(new StateIdle(this));
            return true;
        }

        public void queueCurrentState(State s)
        {
            if (current_state != null)
            {
                if (!changeState(s))
                {
                    State.StateStopHandler onstop = new State.StateStopHandler((obj, st) =>
                    {
                        changeState(s);
                    });
                    current_state.AddStopOnce(onstop);
                }
            }
            else
            {
                changeState(s);
            }
        }
        public bool changeState(State s, bool force = false)
        {
            if (s == current_state)
            {
                return true;
            }
            if (s == next_state)
            {
                return true;
            }
            if (s.unit != this)
            {
                throw new Exception("State is not Owner unit : " + s);
            }
            if (current_state == null || current_state.onBlock(s) || force)
            {
                if (next_state == null || next_state.onBlock(s) || force)
                {
                    if (next_state != null)
                    {
                        next_state.stop();
                    }
                    onNewStateBeginChange(current_state, ref s);
                    next_state = s;
                    
                    return true;
                }
            }
            return false;
        }

        private void updateState()
        {
			//绑定主人类怪物,脱战或者主人移除自杀
			if(mRemoveSelfTime == 0)
			{
				if (this.mBindMaster != null && (!this.mBindMaster.IsActive || this.mBindMaster.Virtual.GetBattleStatus() <= BattleStatus.ReadyBattle))
				{
					//添加移除逻辑
					mRemoveSelfTime = CommonLang.CUtils.localTimeMS + 3000;
				}
			}
			else if(mRemoveSelfTime < CommonLang.CUtils.localTimeMS)
			{
				this.kill(null, false);
			}			

            if (IsDead() && (!IsStateDead))
            {
                changeState(new StateDead(this, this, false), true);
                Parent.cb_unitDeadCallBack(this, this);
                queueEvent(new UnitDeadEvent(ID, this.ID, false, mInfo.RebirthTimeMS));
            }
            else if (next_state == null && next_state_queue.Count > 0)
            {
                // 尝试从队列中取一个状态机,有机会就执行 //
                while (next_state_queue.Count > 0)
                {
                    State queued_state = next_state_queue.Peek();
                    if (changeState(queued_state))
                    {
                        next_state_queue.Dequeue();
                    }
                    else { break; }
                }
            }
            if (next_state != null && next_state != current_state)
            {
                State old_state = current_state;
                if (old_state != null)
                {
                    old_state.stop();
                }
                this.current_state = next_state;
                this.next_state = null;
                this.current_state.start();
                this.onStateChanged(old_state, current_state);
                if (mOnStateChanged != null)
                {
                    mOnStateChanged.Invoke(this, old_state, current_state);
                }
            }
            if (current_state != null)
            {
                current_state.update();
            }

            UpdateTimeLines(Parent.UpdateIntervalMS);
        }

        #endregion


        protected virtual void onUpdateRecover()
        {
            //自动恢复  
            if (this.recoverHP > 0 && mRecoveryTime != null && this.CurrentHP < this.MaxHP && CurrentActionStatus != UnitActionStatus.Damage
				&& this.Virtual.GetBattleStatus() == BattleStatus.None && !IsDead())
			{
                if (mRecoveryTime.Update(Parent.UpdateIntervalMS))
                {
                    AddHP(this.recoverHP, null);
                    //AddMP(Info.ManaRecoveryPoint);
                }
            }
        }

        override protected void onUpdate(bool slowRefresh)
        {
            if (!is_init)
            {
                is_init = true;
                onInit();
            }
            if (!IsPaused)
            {
                updatePhysical();

                updateState();

                onUpdateRecover();

                updateSkills();

                updateBuffs();

                updateTriggers(slowRefresh);

                updateItems();

                if (mOnUpdate != null)
                {
                    mOnUpdate.Invoke(this);
                }
            }
            updateSyncFields();
            updateSyncSkillActives();
        }

        internal void doAction(ObjectAction act)
        {
            this.onAction(act);
            if (mOnHandleObjectAction != null)
            {
                mOnHandleObjectAction.Invoke(this, act);
            }
        }

        private void doRebirth(int max_hp, int max_mp)
        {
            next_state_queue.Clear();
            if (this.Moveable)
            {
                this.mIntersectObj = !Templates.CFG.OBJECT_NONE_TOUCH && (mInfo.BodySize > 0);
            }
            else
            {
                this.mIntersectObj = (mInfo.BodySize > 0);
            }

            if (max_hp == 0) max_hp = this.MaxHP;
            if (max_mp == 0) max_mp = this.MaxMP;

            if (max_hp != 0) this.__mCurrentHP.SetValue(max_hp);
            if (max_mp != 0) this.__mCurrentMP.SetValue(max_mp);
            syncFields(UnitFieldChangedEvent.MASK_HP | UnitFieldChangedEvent.MASK_MP);
            Parent.cb_unitRebirthCallBack(this);
            queueEvent(new UnitRebirthEvent(ID));
        }

		public void updateContinueKills()
		{
			if (this.Statistic.continueKills < short.MaxValue)
			{
				++this.Statistic.continueKills;
			}
			UnitContinueKillValue temp = new UnitContinueKillValue(this.ID, this.Statistic.continueKills);
			queueEvent(temp);
        }

        public void resetContinueKills()
        {
            this.Statistic.continueKills = 0;
        }

		private void doActivated()
        {
            next_state_queue.Clear();
            if (this.Moveable)
            {
                this.mIntersectObj = !Templates.CFG.OBJECT_NONE_TOUCH && (mInfo.BodySize > 0);
            }
            else
            {
                this.mIntersectObj = (mInfo.BodySize > 0);
            }
            this.addTriggers(mInfo.Triggers);
            Parent.cb_unitActivatedCallBack(this);
        }

        internal void doDead(InstanceUnit killer)
        {
			if(killer != null)
			{
				this.Statistic.LogDead(killer.Statistic);
			}
            
            this.mIntersectObj = false;
            this.clearBuffs();
            //吴永辉:5v5人物死亡后会重置技能CD  无论在哪个地图死亡都不能重置  你可能要指给黄鱼 bugid=2748
            //this.ClearAllSkillCD();
            this.resetAI();
        }
        //------------------------------------------------------------------------------------------------------//
        internal void callback_onActivated(InstanceZone zone)
        {
            if (this.mOnActivated != null)
                this.mOnActivated.Invoke(this);
        }
        internal void callback_onAttack(InstanceZone zone, InstanceUnit target, int reduceHP, AttackSource source)
        {
            if (this.mOnAttack != null)
                this.mOnAttack(this, target, reduceHP, source);
        }
        internal void callback_onDamage(InstanceZone zone, InstanceUnit attacker, int reduceHP, AttackSource source)
        {
            if (this.mOnDamage != null)
                this.mOnDamage.Invoke(this, attacker, reduceHP, source);
        }

		public long mProcessDeadTime = 0;

		internal void callback_onDead(InstanceZone zone, InstanceUnit attacker)
        {
			this.mProcessDeadTime = CommonLang.TimeUtil.GetTimestampMS();
			this.OnUnitDead();
			if (this.mOnDead != null)
                this.mOnDead.Invoke(this, attacker);
        }
        internal void callback_onRebirth(InstanceZone zone)
        {
            if (this.mOnRebirth != null)
                this.mOnRebirth.Invoke(this);
        }
        internal void callback_onGotInstanceItem(InstanceZone zone, InstanceItem item)
        {
            if (this.mOnGotInstanceItem != null)
                this.mOnGotInstanceItem.Invoke(this, item);
        }
        internal void callback_onGotInventoryItem(InstanceZone zone, ItemTemplate item)
        {
            if (this.mOnGotInventoryItem != null)
                this.mOnGotInventoryItem.Invoke(this, item);
        }
        internal void callback_onLostInventoryItem(InstanceZone zone, ItemTemplate item)
        {
            if (this.mOnLostInventoryItem != null)
                this.mOnLostInventoryItem.Invoke(this, item);
        }
        internal void callback_onUseItem(InstanceZone zone, ItemTemplate item, InstanceUnit item_creater)
        {
            if (this.mOnUseItem != null)
                this.mOnUseItem.Invoke(this, item, item_creater);
        }
        internal void callback_onGotBuff(InstanceZone zone, InstanceUnit.BuffState buff)
        {
            if (this.mOnGotBuff != null)
                this.mOnGotBuff.Invoke(this, buff);
        }
        internal void callback_onLostBuff(InstanceZone zone, InstanceUnit.BuffState buff)
        {
            if (this.mOnLostBuff != null)
                this.mOnLostBuff.Invoke(this, buff);
        }

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

        private void onInit()
        {
            syncFields(UnitFieldChangedEvent.MASK_ALL);

            if (mInfo.SpawnTimeMS > 0)
            {
                changeState(new StateSpawn(this, mInfo.SpawnTimeMS));
            }
            else
            {
                changeState(new StateIdle(this));
                doActivated();
            }
        }

        #region _Overrideable_

        /// <summary>
        /// 收到协议
        /// </summary>
        /// <param name="act"></param>
        virtual protected void onAction(ObjectAction act) { }
        /// <summary>
        /// 新的状态将要切换时回调
        /// </summary>
        virtual protected void onNewStateBeginChange(State old_state, ref State new_state) { }
        /// <summary>
        /// 状态已切换时回调
        /// </summary>
        /// <param name="old_state"></param>
        /// <param name="state"></param>
        virtual protected void onStateChanged(State old_state, State state) { }

        // 被攻击时回调
        virtual protected void onDamaged(InstanceUnit attacker, AttackSource source, int reduceHP) { }

        virtual protected void onDead(InstanceUnit killer) { }

        #endregion

        /// <summary>
        /// 单位被攻击核心函数,里面处理受击状态,死亡状态
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="source"></param>
        virtual protected internal void doHitAttack(InstanceUnit attacker, AttackSource source)
        {
            if (IsDead())
            {
                //死亡后鞭尸//
                if (Moveable && CanWhiplashDeadBody)
                {
                    source.Begin(this);
                    changeState(new StateDamage(this, source, attacker));
                }
                doHitAttackEndEffect(attacker, source);
                return;
            }
            else
            {
                if (current_state is StateDamage)
                {
                    StateDamage state_damage = current_state as StateDamage;
                    if (state_damage.IsDamageProtect)
                    {
                        return;
                    }
                }
                // TODO HP //
                source.Begin(this);
                int reduceHP = mFormula.OnHit(attacker, source, this);

                // 统计 //
                this.Statistic.LogDamage(attacker.Statistic, reduceHP);
				reduceHP = this.AddHP(-reduceHP, attacker, !source.OutSendEvent, source);
                

                AttackProp attack = source.Attack;
                // Post Event //
                if (source.OutSendEvent)
                {
                    UnitHitEvent evt = new UnitHitEvent(ID);
                    evt.senderId = attacker.ID;
					evt.senderMasterId = attacker.Virtual.GetMasterID();
					evt.hitMasterId = this.Virtual.GetMasterID();

					evt.hp = reduceHP;
                    evt.isDead = IsDead();
                    evt.isCritical = source.Attack.MaskMustCritical;
                    evt.effect = source.OutHitEffect;
                    evt.SourceAttack = source.Attack;
                    evt.client_state = source.OutClientState;
					if(source != null && attacker != null && source.FromSkillType == XmdsSkillType.cardSkill && this.IsMonster && attacker.IsMonster)
					{
						evt.InViewForceSend = true;
					}
					
                    queueEvent(evt);
                }
                if (reduceHP > 0)
                {
                    source.HasHitted = true;
                    onDamaged(attacker, source, reduceHP);
                    Parent.cb_unitDamageCallBack(this, attacker, reduceHP, source);
                    if (IsDead())
                    {
						doDeadProcess(attacker, source);
						return;
                    }
                }

				// 非免控,才会有受击
                if (!this.IsIgnoreControl && source.OutIsDamage && Moveable)
                {
                    changeState(new StateDamage(this, source, attacker));
                }
                doHitAttackEndEffect(attacker, source);
                return;
            }
        }

		/** 执行死亡处理逻辑 */
		private void doDeadProcess(InstanceUnit attacker, AttackSource source)
		{
			if (this.IsMonster)
			{
				if (this.mProcessDeadCallbackTime + 1000 > CommonLang.CUtils.localTimeMS)
				{
					log.Info("cb_unitDeadCallBack 跳过:" + this.mProcessDeadCallbackTime + ", " + this.Info.ID + ", " + this.ID);
					return;
				}

				if(this.Virtual.GetMaType() >= 4 && this.Level > 80)
				{
					log.Info("boss死亡:" + this.mProcessDeadCallbackTime + ", 单位id=" + this.Info.ID + ", 场景Id=" + 
						this.Parent.GetSceneID() + ", " + this.mZone.UUID + ", " + (attacker == null ? "null" : attacker.PlayerUUID));
				}				
			}

			mDeadTime = Parent.PassTimeMS;
			onDead(attacker);
			Parent.cb_unitDeadCallBack(this, attacker);
			queueEvent(new UnitDeadEvent(ID, attacker.ID, source.OutIsCrush, mInfo.RebirthTimeMS));
			// 被击碎,秒杀 //
			if (source.OutIsCrush)
			{
				Parent.queueEvent(new AddEffectEvent(this.ID, X, Y, Direction, source.Attack.CrushEffect));
				changeState(new StateDead(this, attacker, true));
			}
			else
			{
				if (!Moveable)
				{
					changeState(new StateDead(this, attacker));
				}
				else if (source.OutHasKnockDown || source.OutHasFly)
				{
					if (!changeState(new StateDamage(this, source, attacker)))
					{
						changeState(new StateDead(this, attacker));
					}
				}
				else
				{
					changeState(new StateDead(this, attacker));
				}
			}
			doHitAttackEndEffect(attacker, source);
		}


        /// <summary>
        /// 死亡后自爆或者触发法术
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="source"></param>
        private void doHitAttackEndEffect(InstanceUnit attacker, AttackSource source)
        {
            if (source.Attack.Buff != null)
            {
                AddBuff(source.Attack.Buff, attacker);
            }
            if (source.Attack.Spell != null)
            {
                Parent.attackLaunchSpell(source.FromSkillType, attacker, this, source);
            }
        }

        // 单位获取道具 
        protected virtual bool tryGotItem(InstanceItem item, out bool removeItem)
        {
            if (!Parent.IsVisibleAOI(this, item))
            {
                removeItem = false;
                return false;
            }
            if (item.Info.DropMoneyMin > 0 && item.Info.DropMoneyMax > 0)
            {
                int min = Math.Min(item.Info.DropMoneyMin, item.Info.DropMoneyMax);
                int max = Math.Max(item.Info.DropMoneyMin, item.Info.DropMoneyMax);
                int money = RandomN.Next(min, max + 1);
                this.CurrentMoney += money;
                removeItem = item.Info.RemoveOnFinishPick;
                return true;
            }
            if (item.Info.GotOnUse)
            {
                // 获取后立即使用 //
                if (UseItem(item.Info, item.ItemCreater))
                {
                    removeItem = item.Info.RemoveOnFinishPick;
                    return true;
                }
            }
            else
            {
                // 获取后进背包 //
                if (AddItemToEmptyInventory(item.Info) > 0)
                {
                    removeItem = item.Info.RemoveOnFinishPick;
                    return true;
                }
            }
            removeItem = false;
            return false;
        }

        internal bool doGotInstanceItem(InstanceItem item, out bool removeItem, out int pickTimes)
        {
			pickTimes = 0;
			var ret = tryGotItem(item, out removeItem);
            if (ret)
            {
				pickTimes = Parent.cb_unitGotInstanceItemCallBack(this, item);
                if (item.Info.GotEffect != null)
                {
                    queueEvent(new UnitEffectEvent(ID, item.Info.GotEffect));
                }
            }
            return ret;
        }

        internal void doGotInventoryItem(InventorySlot slot, ItemTemplate item, int index, int count)
        {
            mFormula.OnGotInventoryItem(this, item);
            queueEvent(new UnitSyncInventoryItemEvent(ID, item.ID, index, slot.Count));
            Parent.cb_unitGotInventoryItemCallBack(this, item, count);
            // 添加装备Buff //
            if (item.EquipBuffs != null)
            {
                foreach (LaunchBuff buff in item.EquipBuffs)
                {
                    AddBuff(buff, this, true);
                }
            }
        }
        internal void doLostInventoryItem(InventorySlot slot, ItemTemplate item, int index, int count)
        {
            mFormula.OnLostInventoryItem(this, item);
            queueEvent(new UnitSyncInventoryItemEvent(ID, item.ID, index, slot.Count));
            Parent.cb_unitLostInventoryItemCallBack(this, item, count);
            // 移除装备Buff //
            if (item.EquipBuffs != null)
            {
                foreach (LaunchBuff buff in item.EquipBuffs)
                {
                    removeBuff(buff.BuffID);
                }
            }
        }

        // 单位获取道具 
        internal void doGotBuff(InstanceUnit.BuffState buff)
        {
            Parent.cb_unitGotBuffCallBack(this, buff);
        }
        internal void doLostBuff(InstanceUnit.BuffState buff)
        {
            Parent.cb_unitLostBuffCallBack(this, buff);
        }
        public bool UseItem(int itemTemplateID, InstanceUnit item_creater = null)
        {
            ItemTemplate item = Templates.getItem(itemTemplateID);
            if (item != null)
            {
                return UseItem(item, item_creater);
            }
            return false;
        }
        public bool UseItem(ItemTemplate item, InstanceUnit item_creater = null)
        {
            if (item_creater == null)
            {
                item_creater = this;
            }
            if (tryUseItem(item, item_creater))
            {
                beginUseItem(item);

                // 如果关键帧绑定特效
                if (item.UseEffect != null)
                {
                    queueEvent(new UnitEffectEvent(ID, item.UseEffect));
                }
                // 如果关键帧绑定释放法术
                if (item.UseSpell != null)
                {
                    Parent.unitLaunchSpell(XmdsSkillType.none, item_creater, item.UseSpell, X, Y);
                }
                if (item.UseSummon != null)
                {
                    Parent.unitSummonUnit(item_creater, item.UseSummon);
                }
                // 如果关键帧绑定自己释放BUFF
                if (item.UseBuffs != null)
                {
                    foreach (LaunchBuff buff in item.UseBuffs)
                    {
                        this.AddBuff(buff, item_creater);
                    }
                }

                mFormula.OnUseItem(this, item, item_creater);
                queueEvent(new UnitUseItemEvent(ID, item.ID));
                Parent.cb_unitUseItemCallBack(this, item, item_creater);
                Statistic.LogUseItem(item);

                return true;
            }
            return false;
        }

		//-----------------------------------------------------------------------------------------------------//
		/// <summary>
		/// 有伤害源的扣血
		/// </summary>
		/// <param name="hp"></param>
		/// <param name="attacker"></param>
		/// <param name="sendHit"></param>
		/// <param name="hitMessage"></param>
		public int ReduceHP(int hp, InstanceUnit attacker, bool sendHit = true, UnitHitEvent hitMessage = null,
			bool IngoreHealEffect = false, DamageSource dmgSrc = DamageSource.Def)
        {
			//1.目标无敌,不扣血
            if (IsDead() || hp == 0 || ( hp > 0 && this.IsInvincible))
            {
                return 0;
            }

			if (attacker != null)
			{
				if (hp < 0 && !IngoreHealEffect)
				{
					int healedEffect = this.Virtual.GetHealedEffect();
					int healEffect = (attacker.Virtual.GetUnitPro() == XmdsUnitPro.Priest) ? attacker.Virtual.GetHealEffect() : 0;
					if (healedEffect != 0 || healEffect != 0)
					{
						hp = CUtils.CastInt(hp * (1 + healEffect * 0.0001) * (1 + healedEffect * 0.0001));
					}
				}

				this.Statistic.LogDamage(attacker.Statistic, hp);
			}

			//2. 针对有发送者的伤害来源
			if(attacker != null)
			{				
				if (hp < 0)
				{
					//2.1 传递加血事件
					int finalHP = hp;
					attacker.Virtual.DispatchAddOtherHPEvent(-hp, this, out finalHP);
					hp = -finalHP;

					//2.2 道灵对宠物加血,需要有个系数
					if(attacker.IsPlayer && this.IsPet && attacker.Virtual.GetUnitPro() == XmdsUnitPro.Priest)
					{
						hp = (int)(hp * XmdsConstConfig.PET_HEALD_RATIO);
					}
				}
				else if(this.IsPlayer)
				{
					//2.2 如果为玩家,伤害来源存在且为怪物,宠物可以分担伤害
					InstanceUnit petUnit = this.Virtual.GetPetUnit();
					if(petUnit != null)
					{
						int petShareDmg = Math.Max(1, (int)(hp * XmdsConstConfig.PET_SHARE_MASTERDMG_RATIO));
						hp = Math.Max(1, hp - petShareDmg);
						petUnit.PetShareDamage(petShareDmg, this);
					}
				}
			}
			
            this.DoAddHP(-hp);
            
            if (attacker != null && sendHit)
            {
                if (hitMessage == null)
                {
                    hitMessage = new UnitHitEvent();
                }
                hitMessage.object_id = this.ID;
                hitMessage.senderId = attacker == null ? 0 : attacker.ID;
				hitMessage.senderMasterId = attacker == null ? 0 : attacker.Virtual.GetMasterID();
				hitMessage.hitMasterId = this.Virtual.GetMasterID();
                hitMessage.hp = hp;
				hitMessage.isSpecialHit = dmgSrc != DamageSource.Def;
				hitMessage.dmgSrc = dmgSrc;
				hitMessage.isDead = IsDead();
                queueEvent(hitMessage);
            }

            //if (IsDead())
            //{
            //    changeState(new StateDead(this, attacker, false));
            //    Parent.cb_unitDeadCallBack(this, attacker);
            //    queueEvent(new UnitDeadEvent(ID, attacker == null ? 0 : attacker.ID, false, mInfo.RebirthTimeMS));
            //}

			return hp;
        }

		public void AddMP(int mp, InstanceUnit sender, bool sendMsg = true, bool force = false, AttackSource source = null)
		{
			if(mp == 0 || this.MaxMP <= 0)
			{
				return;
			}

			//传递扣定力事件
			if (mp < 0 && sender != null)
			{
				int finalHP = mp;
				sender.Virtual.DispatchAddMPEvent(mp, this, out finalHP, source);
				mp = finalHP;
			}

			this.DoAddMP(mp, force);
		}


        public void removeFromParent()
        {
            Parent.RemoveObjectByID(ID);
        }
        public void kill(InstanceUnit killer = null, bool sendHit = true, UnitHitEvent hitMessage = null)
        {
            ReduceHP(this.CurrentHP, killer, sendHit, hitMessage, true);
        }

        virtual protected void onResetAI()
        {
            this.doSomething();
        }

        public void resetAI()
        {
            next_state_queue.Clear();
            onResetAI();
        }

        public override void faceTo(float d)
        {
            if (Info.IsTurnable) { base.faceTo(d); }
        }
        public override void faceTo(float x, float y)
        {
            if (Info.IsTurnable) { base.faceTo(x, y); }
        }


        /// <summary>
        /// 瞬移
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public void transport(float x, float y, bool setDirction = false, float direction = 0)
        {
			this.SetActionStatus(UnitActionStatus.Transport);
			this.changeState(new StateTransport(this), true);

			setPos(x, y);
			if (setDirction)
			{
				this.faceTo(direction);
			}
            SendForceSync();

			if (mOnRegionTransport != null)
			{
				mOnRegionTransport.Invoke();
			}
		}

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

		public virtual void doSomething()
        {
            startIdle();
        }

        /// <summary>
        /// 单位待机
        /// </summary>
        public bool startIdle(bool force = false)
        {
            if (current_state is StateIdle)
            {
            }
            else
            {
                return changeState(new StateIdle(this), force);
            }
            return false;
        }

        /// <summary>
        /// 直接复活
        /// </summary>
        public bool startRebirth(int max_hp = 0, int max_mp = 0)
        {
            if (IsDead())
            {
                this.DeadHide = false;
                return changeState(new StateRebirth(this, max_hp, max_mp));
            }
            return false;
        }

        /// <summary>
        /// 单位移动
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public bool startMoveTo(float x, float y)
        {
            return changeState(new StateMove(this, x, y));
        }
        /// <summary>
        /// 调整射击位置
        /// </summary>
        /// <param name="expect_skill"></param>
        /// <param name="target"></param>
        /// <param name="onEndAction"></param>
        public bool startAdjustLaunchSkill(SkillTemplate expect_skill, InstanceUnit target, Predicate<StateMove> onEndAction)
        {
            if (expect_skill.AttackKeepRange > 0 && expect_skill.AttackRange > expect_skill.AttackKeepRange)
            {
                float keep_range = GetSkillAttackRange(expect_skill.AttackKeepRange) + target.BodyBlockSize;
                float distance = MathVector.getDistance(this.X, this.Y, target.X, target.Y);
                if (distance < keep_range)
                {
                    var half = (expect_skill.AttackRange - expect_skill.AttackKeepRange) / 2;
                    var md = (keep_range - distance) + (float)(RandomN.NextDouble() * half);
                    var target_pos = new Vector2(this.X, this.Y);
                    var rd = (CMath.PI_DIV_2 / 4);
                    var target_direction = this.Direction + CMath.PI_F - (rd / 2 + (float)(RandomN.NextDouble() * rd));
                    MathVector.movePolar(target_pos, target_direction, md);
                    if (!Parent.TryTouchMap(this, target_pos.X, target_pos.Y))
                    {
                        var back_pos = new Vector2(this.X, this.Y);
                        MathVector.movePolar(back_pos, target_direction, this.BodyBlockSize);
                        if (!Parent.TryTouchMap(this, back_pos.X, back_pos.Y))
                        {
                            var move = new StateMove(this, target_pos.X, target_pos.Y);
                            move.MinStepCheckCount = 0;
                            move.StopOnTouchMap = true;
                            move.EndMoveAction = onEndAction;
                            return this.changeState(move);
                        }
                    }
                }
            }
            return false;
        }
        /// <summary>
        /// 单位移动
        /// </summary>
        /// <param name="obj"></param>
        public bool startFollowTo(InstanceZoneObject obj)
        {
            return changeState(new StateFollowObject(this, obj));
        }
        /// <summary>
        /// 单位逃跑
        /// </summary>
        /// <param name="timeMS"></param>
        /// <param name="distance"></param>
        public bool startEscape(int timeMS, float distance = 0)
        {
            return changeState(new StateEscape(this, timeMS, distance));
        }

        /// <summary>
        /// 和自身交互(搓炉石)
        /// </summary>
        /// <param name="timeMS"></param>
        /// <param name="done"></param>
        /// <param name="status"></param>
        public StatePickObject startPickProgressSelf(int timeMS, StatePickObject.OnPickDone done, string status = null)
        {
            StatePickObject picking = new StatePickObject(this, this, timeMS, status, done);
            changeState(picking);
            return picking;
        }
        /// <summary>
        /// 和目标交互
        /// </summary>
        /// <param name="item"></param>
        /// <param name="timeMS"></param>
        /// <param name="done"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        public StatePickObject startPickProgressObject(InstanceZoneObject item, int timeMS, StatePickObject.OnPickDone done, string status = null)
        {
            StatePickObject picking = new StatePickObject(this, item, timeMS, status, done);
            changeState(picking);
            return picking;
        }


        //-----------------------------------------------------------------------------------------------------------------
        #region _SKILL_
        //-----------------------------------------------------------------------------------------------------------------
        public float GetSkillAttackRange(SkillTemplate skill)
        {
            return mIsAttackRangeIncludeBodySize ? BodyBlockSize + skill.AttackRange : skill.AttackRange;
        }
        public float GetSkillAttackRange(float range)
        {
            return (mIsAttackRangeIncludeBodySize ? BodyBlockSize + range : range);
        }
        /// <summary>
        /// 判断当前目标在攻击范围内
        /// </summary>
        /// <param name="skill"></param>
        /// <param name="unit"></param>
        /// <returns></returns>
        public bool IsTargetInSkillRange(SkillTemplate skill, InstanceUnit unit)
        {
            float rg = GetSkillAttackRange(skill);
            float dr = skill.AttackAngle / 2;
            if (Collider.Object_HitBody_TouchFan(unit, X, Y, rg, Direction - dr, Direction + dr))
            {
                return true;
            }
            return false;
        }

        [Obsolete]
        public List<InstanceUnit> getSkillAttackableTargets(SkillTemplate skill, AttackReason reason)
        {
            float rg = GetSkillAttackRange(skill);
            List<InstanceUnit> list = Parent.getObjectsRoundRange<InstanceUnit>(Collider.Object_HitBody_TouchRound, X, Y, rg , this.AoiStatus);
            Parent.getAttackableUnits(this, list, skill.ExpectTarget, reason, skill);
            return list;
        }
        public void getSkillAttackableTargets(SkillTemplate skill, List<InstanceUnit> list, AttackReason reason)
        {
            float rg = GetSkillAttackRange(skill);
            Parent.getObjectsRoundRange<InstanceUnit>(Collider.Object_HitBody_TouchRound, X, Y, rg, list, this.AoiStatus);
            Parent.getAttackableUnits(this, list, skill.ExpectTarget, reason, skill);
        }

        /// <summary>
        /// 获得可用的技能
        /// </summary>
        /// <param name="expect"></param>
        /// <returns></returns>
        public SkillState getAvailableSkill(SkillTemplate.CastTarget expect)
        {
            for (int si = mAllSkills.Count - 1; si >= 0; --si)
            {
                SkillTemplate st = mAllSkills[si];
                if (st.ExpectTarget == expect)
                {
                    SkillState sst = mSkillStatus.Get(st.GetID());                   
					if (sst.IsActive && sst.IsDone)
					{
                        return sst;
                    }
                }
            }
            return null;
        }

		/** 获取当前可自动释放的技能 */
		public SkillState getAvailableAutoLaunchSkill(SkillTemplate.CastTarget expect)
		{
			for (int si = mAllSkills.Count - 1; si >= 0; --si)
			{
				SkillTemplate st = mAllSkills[si];
				if (st.ExpectTarget == expect)
				{
					SkillState sst = mSkillStatus.Get(st.GetID());
					if (sst.IsActive && sst.IsDone && sst.LaunchSkill.AutoLaunch && sst.CanAutoLaunch())
					{
						return sst;
					}
				}
			}
			return null;
		}

		/// <summary>
		/// 获取当前最适合攻击的目标
		/// </summary>
		/// <param name="skill"></param>
		/// <param name="reason"></param>
		/// <param name="directionChange"></param>
		/// <returns></returns>
		public InstanceUnit getSkillAttackableFirstTarget(SkillTemplate skill, AttackReason reason, ref bool directionChange)
        {
            using (var list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
            {
                getSkillAttackableTargets(skill, list, reason);
                if (list.Count > 0)
                {
                    float rg = GetSkillAttackRange(skill);
                    // 检测攻击范围内的单位 //
                    float dr = skill.AttackAngle / 2;
                    for (int i = 0; i < list.Count; i++)
                    {
                        InstanceUnit u = list[i];
                        if (Collider.Object_HitBody_TouchFan(u, X, Y, rg, Direction - dr, Direction + dr))
                        {
                            directionChange = false;
                            return u;
                        }
                    }
                    // 优先当前朝向的目标 //
                    dr = CMath.PI_DIV_2;
                    directionChange = true;
                    for (int i = 0; i < list.Count; i++)
                    {
                        InstanceUnit u = list[i];
                        if (Collider.Object_HitBody_TouchFan(u, X, Y, rg, Direction - dr, Direction + dr))
                        {
                            return u;
                        }
                    }
                    // 最后选取最近的目标 //
                    InstanceUnit min = null;
                    float min_len = float.MaxValue;
                    for (int i = 0; i < list.Count; i++)
                    {
                        InstanceUnit u = list[i];
                        float len = MathVector.getDistanceSquare(u.X, u.Y, X, Y);
                        if (min_len > len)
                        {
                            min_len = len;
                            min = u;
                        }
                    }
                    return min;
                }
            }
            return null;
        }

        public struct LaunchSkillParam
        {
            public uint TargetUnitID;
            public Vector2 SpellTargetPos;
            public bool AutoFocusNearTarget;
            public bool LaunchSetDirection;         // 释放时是否重新设置方向 
            public float direction;
			public bool IsAutoLaunch;               // 是否自动战斗时释放
			public bool IsInGuard;					// 是否是自动战斗

            public LaunchSkillParam(uint targetUnitID = 0, Vector2 target_pos = null, bool autoFocusNearTarget = false,
                bool LaunchSetDirection = false, float direction = 0, bool IsAutoLaunch = false, bool IsInGuard = false)
            {
                this.TargetUnitID = targetUnitID;
                this.SpellTargetPos = target_pos;
                this.AutoFocusNearTarget = autoFocusNearTarget;
                this.LaunchSetDirection = LaunchSetDirection;
                this.direction = direction;
				this.IsAutoLaunch = IsAutoLaunch;
				this.IsInGuard = IsInGuard;
			}
        }

        public StateSkill launchSkill(SkillState ss, LaunchSkillParam param)
        {
            if (ss == null) return null;
            StateSkill current = CurrentState as StateSkill;
            if (current != null && current.SkillData.IsManuallyCancelable)
            {
                //如果当前技能为手动取消//
                if (current.Skill.ID == ss.ID)
                {
                    //判断停止当前技能//
                    if (current.IsCancelableBySkill)
                    {
                        current.block();
                    }
                }
                //手动取消技能禁止其他技能打断//
                return null;
            }
            if (ss.TryLaunch() && mFormula.TryLaunchSkill(this, ss, ref param))
            {
				if(param.IsAutoLaunch && !ss.CanAutoLaunch())
				{
					return null;
				}

                //沉默不能释放其他技能//
                if (IsSilent && ss != mDefaultSkill)
                {
                    return null;
                }
				// 自动战斗下,释放技能要在范围内
				InstanceUnit target = null;
				if (ss.Data.AttackMustBeInRange)
                {
                    target = Parent.getUnit(param.TargetUnitID);
                    if (!ss.checkTargetRange(target))
                    {
                        return null;
                    }
				}

				//是否在合理的攻击范围内
				if(param.IsInGuard && !ss.checkTargetInAttackRange(target, param))
				{
					return null;
				}

				if (ss.GetSkillType() == XmdsSkillType.petGiveAcitve)
				{
					mFormula.TriggerPetSkill(this, ss, ref param);
					return null;
				}

				StateSkill state = new StateSkill(this, ss, param, ss.ActionSpeed, (st) =>
                {
                    overLaunchSkill(ss, st);
                    if (mOnLaunchSkill != null)
                    {
                        mOnLaunchSkill.Invoke(this, ss);
                    }
                });				

				if (state.tryLaunch())
                {
                    this.Virtual.SetCombatState(BattleStatus.ReadyBattle);
                    Parent.cb_unitLaunchSkill(this, ss);
                    if (changeState(state))
                    {
                        //释放成功
                        if (param.LaunchSetDirection)
                        {
                            //Console.WriteLine("launchSkill - 设置方向: " + param.direction + ", " + this.ID);
                            //this.faceTo(param.direction);
                            //this.SendForceSync();
                        }
                        return state;
                    }                  
                }
            }
            return null;
        }

        protected virtual void overLaunchSkill(SkillState ss, StateSkill state)
        {
            this.AddHP(-ss.Data.CostHP, null);
            this.AddMP(-ss.Data.CostMP, null);
        }

        /// <summary>
        /// 单位释放技能
        /// </summary>
        public StateSkill launchSkill(int skillID, LaunchSkillParam param)
        {
            SkillState skill = getSkillState(skillID);
            return launchSkill(skill, param);
        }

        /// <summary>
        /// 释放随机技能,一般用于AI
        /// </summary>
        /// <param name="expectTarget"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public virtual StateSkill launchRandomSkill(SkillTemplate.CastTarget expectTarget, LaunchSkillParam param)
        {
            StateSkill current = CurrentState as StateSkill;
            if (current != null && !current.IsCancelableBySkill)
            {
                return null;
            }
            int rand = RandomN.Next(0, mAllSkills.Count);
            for (int si = mAllSkills.Count - 1; si >= 0; --si)
            {
                SkillTemplate st = mAllSkills[CMath.cycNum(rand, si, mAllSkills.Count)];
                if (st.ExpectTarget == expectTarget)
                {
                    SkillState sst = mSkillStatus.Get(st.GetID());
                    if (sst.LaunchSkill.AutoLaunch && sst.TryLaunch())
                    {
                        StateSkill state = launchSkill(sst, param);
                        if (state != null)
                        {
                            return state;
                        }
                    }
                }
            }
            return null;
        }
        public virtual StateSkill launchRandomSkillForAll(LaunchSkillParam param)
        {
            StateSkill current = CurrentState as StateSkill;
            if (current != null && !current.IsCancelableBySkill)
            {
                return null;
            }
            int rand = RandomN.Next(0, mAllSkills.Count);
            for (int si = mAllSkills.Count - 1; si >= 0; --si)
            {
                SkillTemplate st = mAllSkills[CMath.cycNum(rand, si, mAllSkills.Count)];
                SkillState sst = mSkillStatus.Get(st.GetID());
                if (sst.LaunchSkill.AutoLaunch && sst.TryLaunch())
                {
                    StateSkill state = launchSkill(sst, param);
                    if (state != null)
                    {
                        return state;
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 尝试取消当前技能,打出连击
        /// </summary>
        /// <param name="target"></param>
        /// <param name="autoFocusNearTarget"></param>
        /// <returns></returns>
        public virtual bool tryLaunchRandomSkillAndCancelCurrentSkill(InstanceUnit target, bool autoFocusNearTarget = false)
        {
            StateSkill current = CurrentState as StateSkill;
            if (current != null && !current.IsChanting && current.IsCancelableBySkill)
            {
                LaunchSkillParam param = new LaunchSkillParam(target.ID, null, autoFocusNearTarget);
                //优先多段攻击//
                if (current.SkillData.IsSingleAction)
                {
                    if (IsTargetInSkillRange(current.SkillData, target))
                    {
                        StateSkill st = launchSkill(current.SkillData.ID, param);
                        if (st != null)
                        {
                            return true;
                        }
                    }
                }
                //随机其他技能//
                int rand = RandomN.Next(0, mAllSkills.Count);
                for (int si = mAllSkills.Count - 1; si >= 0; --si)
                {
                    SkillTemplate st = mAllSkills[CMath.cycNum(rand, si, mAllSkills.Count)];
                    if (Parent.IsAttackable(this, target, st.ExpectTarget, AttackReason.Attack, st))
                    {
                        SkillState sst = mSkillStatus.Get(st.GetID());
                        if (sst.LaunchSkill.AutoLaunch && IsTargetInSkillRange(st, target))
                        {
                            StateSkill state = launchSkill(sst, param);
                            if (state != null)
                            {
                                return true;
                            }
                        }
                    }
                }
            }
            return false;
        }


        /// <summary>
        /// 尝试在范围内找到目标释放技能,并进入StateFollowAndAttack,自己走过去打。
        /// </summary>
        /// <param name="range"></param>
        /// <param name="skill_auto_launchable"></param>
        /// <returns></returns>
        public virtual bool tryFollowAndLaunchRandomSkillToTargetInRange(float range, bool skill_auto_launchable = false)
        {
            if (!IsNoneSkill)
            {
                SkillState[] skills = mSkillStatus.SkillsArray;
                CUtils.RandomArray(RandomN, skills);

                using (var list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
                {
                    //随机找个目标施法//
                    Parent.getObjectsRoundRange<InstanceUnit>(Collider.Object_Pos_IncludeInRound, X, Y, Info.GuardRange, list , this.AoiStatus);
                    DoAndRemoveCollection.UpdateAndRemove<InstanceUnit>(list, (InstanceUnit u) =>
                    {
                        return !u.IsActive;
                    });
                    if (list.Count == 0) { return false; }

                    CUtils.RandomList(Parent.RandomN, list);
                    foreach (SkillState skill in skills)
                    {
                        if ((!skill_auto_launchable || skill.LaunchSkill.AutoLaunch) && skill.TryLaunch())
                        {
                            for (int i = 0; i < list.Count; i++)
                            {
                                InstanceUnit u = list[i];
                                if (Parent.IsAttackable(this, u, skill.Data.ExpectTarget, AttackReason.Attack, skill.Data))
                                {
                                    //检测是否有可释放技能//
                                    changeState(new StateFollowAndAttack(this, u, skill.Data.ExpectTarget));
                                    return true;
                                }
                            }
                        }
                    }
                }
            }
            return false;
        }

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

        internal void deadDropItems(int force)
        {
            foreach (KeyValuePair<ItemTemplate, DropItem> e in mDropItems.Drop(Parent, Parent.RandomN))
            {
                float x;
                float y;
                CMath.RandomPosInRound(RandomN, X, Y, e.Value.DropPosRange, out x, out y);
                Parent.AddItem(e.Key, e.Key.Name, x, y, CMath.RandomAngle(RandomN), force, e.Key.Name, this);
            }
        }

        protected bool tryPickObject(InstanceUnit unit)
        {
            if (!Parent.IsVisibleAOI(this, unit))
            {
                return false;
            }
            bool ret = true;
            if (mOnTryPickUnit != null)
            {
                foreach (TryPickUnitHandler trypick in mOnTryPickUnit.GetInvocationList())
                {
                    if (!trypick.Invoke(this, unit))
                    {
                        ret = false;
                    }
                }
            }

            return ret;
        }

        public void PickUnit(InstanceUnit pickable)
        {
            if (tryPickObject(pickable))
            {
                Parent.cb_unitPickUnitCallBack(this, pickable);
                if (mOnPickUnit != null)
                {
                    mOnPickUnit.Invoke(this, pickable);
                }
            }
        }

        public CommonAI.Data.SceneType GetSceneType()
        {
            return mZone.SceneType;
        }

        //-----------------------------------------------------------------------------------------------------//
        #region Environment
        //-----------------------------------------------------------------------------------------------------//

        private HashMap<string, EnvironmentVar> EnvironmentVarMap = new HashMap<string, EnvironmentVar>();
        public void SetEnvironmentVar(string key, object value, bool syncToClient = false)
        {
            if (!string.IsNullOrEmpty(key))
            {
                EnvironmentVar var = EnvironmentVarMap.Get(key);
                if (var != null)
                {
                    if (EnvironmentVar.ALWAYS_SYNC_ENVIRONMENT_VAR || (var.SyncToClient && var.Value != value))
                    {
                        queueEvent(new PlayerSyncEnvironmentVarEvent(ID, key, value));
                    }
                    var.Value = value;
                }
                else
                {
                    var = new EnvironmentVar(key, syncToClient, value);
                    EnvironmentVarMap.Add(key, var);
                    if (EnvironmentVar.ALWAYS_SYNC_ENVIRONMENT_VAR || var.SyncToClient)
                    {
                        queueEvent(new PlayerSyncEnvironmentVarEvent(ID, key, value));
                    }
                }
            }
        }
        public T GetEnvironmentVarAs<T>(string key)
        {
            if (!string.IsNullOrEmpty(key))
            {
                EnvironmentVar var = EnvironmentVarMap.Get(key);
                if (var != null)
                {
                    try
                    {
                        return (T)var.Value;
                    }
                    catch (Exception err)
					{
						log.Warn("GetEnvironmentVarAs : " + key + ", catch: " + err);
					}
                }
            }
            return default(T);
        }
        public int ListEnvironmentVars(List<EnvironmentVar> list)
        {
            list.AddRange(EnvironmentVarMap.Values);
            return EnvironmentVarMap.Count;
        }
        public List<EnvironmentVar> ListEnvironmentVars()
        {
            return new List<EnvironmentVar>(EnvironmentVarMap.Values);
        }

        public ClientStruct.ZoneEnvironmentVar[] GetCurrentUnitVars()
        {
			ClientStruct.ZoneEnvironmentVar[] ret = new ClientStruct.ZoneEnvironmentVar[EnvironmentVarMap.Count];
			int i = 0;
			try
			{				
				foreach (EnvironmentVar var in EnvironmentVarMap.Values)
				{
					ret[i].Key = var.Key;
					ret[i].Value = var.Value;
					ret[i].SyncToClient = var.SyncToClient;
					i++;
				}				
			}
			catch(Exception e)
			{
				log.Warn("GetCurrentUnitVars catch: " + ret.Length + ", " + EnvironmentVarMap.Count + ", " + i + ", e: " + e);
			}

			return ret;
		}
        #endregion
        //-----------------------------------------------------------------------------------------------------//


        //-----------------------------------------------------------------------------------------------------//
        #region SceneEvents
        //-----------------------------------------------------------------------------------------------------//

        private HashMap<int, UnitEventTriggerCollection> mBindEvents = new HashMap<int, UnitEventTriggerCollection>();
        public void BindUnitEvent(int unit_event_id)
        {
            if (!mBindEvents.ContainsKey(unit_event_id))
            {
                UnitEventTemplate uet = Templates.getUnitEvent(unit_event_id);
                if (uet != null)
                {
                    uet = uet.Clone() as UnitEventTemplate;
                    UnitEventTriggerCollection bind_event = new UnitEventTriggerCollection(this);
                    bind_event.Bind(uet.Events);
                    mBindEvents.Add(unit_event_id, bind_event);
                }
            }
        }

        protected virtual void clearBindEvents()
        {
            foreach (var evt in mBindEvents.Values)
            {
                evt.Dispose();
            }
            mBindEvents.Clear();
        }

		/** 计算并获得伤害 */
		public virtual void PetShareDamage(int baseDmgValue, InstanceUnit sender)
		{
		}

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

		//-----------------------------------------------------------------------------------------------------//
	}

}