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;
using CommonAI.ZoneServer.JSGModule;

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;

        /// 单位最后死亡时间
        public 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;
        //检测散开间隔
        protected long mCheckAttackSpread = 0;

        /// <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();

            this.mNoneBlockTimeMS.Disposing();
            this.mStunTimeMS.Disposing();
            this.mInvisibleTimeMS.Disposing();
            this.mInvincibleTimeMS.Disposing();
            this.mSilentTimeMS.Disposing();
            this.mCannotMoveTimeMS.Disposing();
            this.mIgnoreControl.Disposing();

            foreach (MultiTimeLine timeLine in mMultiTimeLineGroup)
            {
                timeLine.Disposing();
            }
            this.mMultiTimeLineGroup.Clear();
            this.mMultiTimeLineGroup = null;
            this.mMultiTimeLineSync = null;
        }

        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(0/*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 bool IsPlayerUnit { get { return false; } }

        virtual public void OnUnitDead() { }

        /// <summary>
        /// 是否中立
        /// </summary>
        virtual public bool IsNature { get { return false; } }
        /// <summary>
        /// 此单位是否能被攻击并且活着
        /// </summary>
        virtual public bool IsActive { get { return (__mCurrentHP.Value > 0) && (base.Enable)/*&& !IsInvincible && IsVisible*/; } }
        /// <summary>
        /// 此单位是否可以被打到,包括鞭尸
        /// </summary>
        virtual public bool IsAttackable { get { return (base.Enable) /*&& !IsInvincible && IsVisible*/; } }
        /// <summary>
        /// 此单位是否无技能
        /// </summary>
        public bool IsNoneSkill { 
            get 
            {
                foreach (SkillState st in mSkillStatus.Skills)
                {
                    if (st.LaunchSkill.AutoLaunch) return false;
                }
                return true;
            } 
        }
        /// <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);                
                queueEvent(new UnitDeadEvent(ID, this.ID, false, mInfo.RebirthTimeMS));

                if(this.mProcessDeadCallbackTime < CommonLang.CUtils.localTimeMS)
                {
                    log.Warn("手动调用死亡逻辑2:" + this.PlayerUUID + ", " + this.mZone.GetSceneID() + ", templateID:" + this.Info.ID + ", state: " + this.current_state);
                    Parent.cb_unitDeadCallBack(this, this);
                }
            }
            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);

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

                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)
        {
            try
            {
                onDead(attacker);
                Parent.cb_unitDeadCallBack(this, attacker);

                if (source == null)
                {
                    queueEvent(new UnitDeadEvent(ID, attacker == null ? 0 : attacker.ID, false, mInfo.RebirthTimeMS));
                    changeState(new StateDead(this, attacker, true));
                }
                else
                {
                    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);
                }
            }
            catch (Exception e)
            {
                log.Warn("doDeadProcess catch:" + this.Info.ID + ", AttackId: " + (attacker == null ? -1 : attacker.Info.ID), e);
            }
        }


        /// <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>
        /// force: 忽略无敌效果,强制扣血
        public int ReduceHP(int hp, InstanceUnit attacker, AttackSource source, bool sendHit = true, UnitHitEvent hitMessage = null,
            bool IngoreHealEffect = false, DamageSource dmgSrc = DamageSource.Def, bool force = false)
        {
            //1.目标无敌,不扣血
            if (IsDead() || hp == 0 || (hp > 0 && this.IsInvincible && !force))
            {
                return 0;
            }

            //2. 针对有发送者的伤害来源
            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));
                    }
                }

                if (hp < 0)
                {
                    //传递加血事件
                    hp = attacker.Virtual.DispatchAddOtherHPEvent(hp, this, source);

                    //2 道灵对宠物加血,需要有个系数
                    if (attacker.IsPlayer && this.IsPet && attacker.Virtual.GetUnitPro() == XmdsUnitPro.Priest)
                    {
                        hp = (int)(hp * XmdsConstConfig.PET_HEALD_RATIO);
                    }
                }
                else
                {
                    //传递单位-被其他人扣血
                    hp = this.Virtual.DispatchAddOtherHPEvent(hp, attacker, source);
                    if (this.IsPlayer && attacker.IsMonster)
                    {
                        //2.3 如果玩家受伤,伤害来源存在且为怪物,宠物可以分担伤害
                        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.Statistic.LogDamage(attacker.Statistic, hp);
            }

            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));
            //}

            if (hp > 0 && this.IsDead())
            {
                this.doDeadProcess(attacker, source);
            }

            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, null, 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.Direction = 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;
                this.mProcessDeadCallbackTime = 0;
                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, InstanceUnit targetUnit)
        {
            return mIsAttackRangeIncludeBodySize ? (BodyBlockSize + skill.AttackRange + targetUnit.BodyBlockSize) : skill.AttackRange;
            //return mIsAttackRangeIncludeBodySize ? (BodyBlockSize + skill.AttackRange) : skill.AttackRange;
        }

        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
        //-----------------------------------------------------------------------------------------------------//

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

}