asmrobot
2019-11-25 2aeab450471cb80b59002da7da80faf251a0c4f4
src/RichCreator/StateMachines/KillMonsterStateMachine.cs
@@ -1,22 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.CV.Structure;
using RichCreator.Dnf;
using RichCreator.Maps.Kalete;
using RichCreator.Models;
using RichCreator.StateMachines;
using RichCreator.Utility;
using RichCreator.Utility.Captures;
using RichCreator.Utility.CV;
using RichCreator.Utility.Dnf;
using RichCreator.Utility.InputControl;
using RichCreator.Utility.Maps;
using RichCreator.Utility.Skills;
using RichCreator.Utility.Structs;
using Emgu.CV;
using Emgu.CV.Structure;
using RichCreator.Maps;
using RichCreator.Maps.Lindong;
using RichCreator.StateMachines;
using RichCreator.Utility.Utilitys;
using RichCreator.Utilitys;
using static RichCreator.Utilitys.AttackRectangle;
using Utils = RichCreator.Utilitys.Utils;
using System;
using System.Collections.Generic;
using System.Threading;
using ZTImage.Collections;
namespace RichCreator.Jobs.StateMachines
@@ -27,73 +27,49 @@
    public class KillMonsterStateMachine : StateMachineBase
    {
        private const Int32 NoMoveMaxMillSecond = 2000;//最大未移动容忍毫秒数
        private MapInfo map;//地图
        private HouseInfo house;//当前房间
        private ZTPoint miniMapStart;//小地图区域
        private ZTRectangle GameRect;//游戏区域
        private Int32 preHouseIndex = 0;//上一房间编号
        private MoveState moveState;//移动状态
        private OutOfBounds outOfBounds;//禁区
        private DnfRole role;//当前角色控制
        private bool isSuccess;//退出结果
        private ZTPoint roleLastPosition = ZTPoint.Empty;//角色最后位置
        private Int32 runningStep = RunningStep.None;//是否恢复的状态
        //当前状态
        private KillMonsterStates currentState = KillMonsterStates.Start;
        //是否截图屏幕
        private bool captureScreen = false;
        //怪
        private ZTPoint[] stateMonsters;
        private System.Drawing.Bitmap bitmap = null;
        //原图
        private Image<Rgb, byte> image = null;
        //图像是否改变
        private bool imageIsChange = false;
        //色彩hsv
        private Image<Hsv, byte> hsvImage = null;
        //取消令牌
        private CancellationToken cancellationToken = CancellationToken.None;
        #region Find Door Info
        //门坐标
        private ZTPoint stateDoorPosition;
        //角色位置
        private ZTPoint stateRolePosition;
        //离开的门朝向
        private Direction stateDoorLevelDirect = Direction.None;
        //定位点方框
        private MultiList<ZTRectangle, Int32> stateLocationRectangle = new MultiList<ZTRectangle, int>();
        
        #endregion
        private KillMonsterStates currentState = KillMonsterStates.Start;//当前状态
        private bool needCaptureScreen = false;//是否截图屏幕
        private ZTPoint[] stateMonsters;//怪
        private Image<Rgb, byte> image = null;//原图
        private Image<Hsv, byte> hsvImage = null;//色彩hsv
        private ZTPoint state_DoorPosition;//门坐标
        private Direction state_DoorDirect = Direction.None;//门朝向
        private ParametersPoint stateScreenLocation = new ParametersPoint();//屏幕定位点
        private ZTPoint skillReleasePoint = ZTPoint.Empty;
        private HIDCode roleDirection = HIDCode.NoEvent;
        private bool tryEntryDoor = false;//是否尝试进门
        public KillMonsterStateMachine(HouseInfo house, ZTPoint miniMapStart, ZTRectangle gameRect, Int32 preHouseIndex, Int32 runningStep, CancellationToken cancellationToken)
        public KillMonsterStateMachine(MapInfo map,HouseInfo house, DnfRole role)
        {
            this.runningStep = runningStep;
            if (house.HousePathInfo.LoopPoint.Equals(ZTPoint.Empty))
            {
                throw new ArgumentOutOfRangeException("寻路中不存在循环点");
            }
            this.map = map;
            this.house = house;
            this.miniMapStart = miniMapStart;
            this.GameRect = gameRect;
            this.preHouseIndex = preHouseIndex;
            this.cancellationToken = cancellationToken;
            moveState = new MoveState(this.GameRect, this.house);
            outOfBounds = new OutOfBounds(this.GameRect, moveState);
            hsvImage = new Image<Hsv, byte>(gameRect.End.X - gameRect.Start.X + 1, gameRect.End.Y - gameRect.Start.Y + 1);
            this.role = role;
            hsvImage = new Image<Hsv, byte>(map.GameRect.End.X - map.GameRect.Start.X + 1, map.GameRect.End.Y - map.GameRect.Start.Y + 1);
        }
        private void SetState(KillMonsterStates current, bool capture)
        {
            currentState = current;
            captureScreen = capture;
            needCaptureScreen = capture;
        }
        /// <summary>
@@ -103,50 +79,49 @@
        /// <param name="cancellationToken"></param>
        /// <param name="timeoutMillSecond"></param>
        /// <returns></returns>
        public ZTResult Work(Int32 timeoutMillSecond)
        public ZTResult Work(Int32 timeoutMillSecond,Int32 fromHouseIndex,Int32 runningStep)
        {
            bool imageIsChange = false;//图像是否改变
            DateTime expireTime = DateTime.Now.AddMilliseconds(timeoutMillSecond);
            if (this.runningStep > RunningStep.None)
            {
                SetState(KillMonsterStates.FindMonster, true);
            }
            while (true)
            {
                if (cancellationToken.IsCancellationRequested)
                if (map.CancelToken.IsCancellationRequested)
                {
                    G.Instance.DebugWriter("取消刷图");
                    this.moveState.StopMove();
                    this.role.StopMove("cancel");
                    return ZTResult.Cancel;
                }
                if (DateTime.Now > expireTime)
                {
                    G.Instance.DebugWriter("刷图超时");
                    this.moveState.StopMove();
                    this.role.StopMove("timeout");
                    return ZTResult.Timeout;
                }
                if (captureScreen)
                if (needCaptureScreen)
                {
                    using (bitmap = ScreenCapture.Instance.CaptureScreen())
                    using (System.Drawing.Bitmap bitmap = ScreenCapture.Instance.CaptureScreen())
                    {
                        if (image != null)
                        {
                            image.Dispose();
                        }
                        image = new Image<Rgb, byte>(bitmap);
                        image = image.GetSubRect(new System.Drawing.Rectangle(GameRect.Start.X, GameRect.Start.Y, GameRect.End.X - GameRect.Start.X + 1, GameRect.End.Y - GameRect.Start.Y + 1));
                        image = image.GetSubRect(new System.Drawing.Rectangle(map.GameRect.Start.X, map.GameRect.Start.Y, map.GameRect.End.X - map.GameRect.Start.X + 1, map.GameRect.End.Y - map.GameRect.Start.Y + 1));
                        imageIsChange = true;
                    }
                }
                switch (currentState)
                {
                    case KillMonsterStates.Start:
                        //开始
                        SingleEntryHouseSkill.ReleaseSkill(this.house.Index, this.preHouseIndex, this.moveState);
                        if (this.house.FromHouseIndex == fromHouseIndex)
                        {
                            this.map.EntryHousePrework(this.house.Index, fromHouseIndex);
                        }
                        SetState(KillMonsterStates.IsLastHouse, true);
                        break;
                    case KillMonsterStates.IsLastHouse:
@@ -157,18 +132,18 @@
                            SetState(KillMonsterStates.FindRole, false);
                            break;
                        }
                        if (this.house.Index == 15)
                        if (this.house.IsEnd)
                        {
                            SetState(KillMonsterStates.HasRewardWindow, false);
                        }
                        else
                        {
                            SetState(KillMonsterStates.IsOtherHouse, false);
                        }
                        }
                        break;
                    case KillMonsterStates.HasRewardWindow:
                        //是否有奖励界面
                        if (DnfCVHelper.IsJiangli(image, this.GameRect))
                        if (DnfCVHelper.IsJiangli(image, map.GameRect))
                        {
                            SetState(KillMonsterStates.TurnAroundCard, false);
                        }
@@ -186,7 +161,7 @@
                        break;
                    case KillMonsterStates.IsCompletePage:
                        //是否刷完界面
                        if (DnfCVHelper.IsCompleteRoom(image, this.GameRect))
                        if (DnfCVHelper.IsCompleteRoom(image, map.GameRect))
                        {
                            this.isSuccess = true;
                            SetState(KillMonsterStates.Exit, false);
@@ -211,70 +186,90 @@
                        break;
                    case KillMonsterStates.FindRole:
                        //主角
                        CvInvoke.CvtColor(image, hsvImage, Emgu.CV.CvEnum.ColorConversion.Rgb2Hsv);
                        //定位点
                        if (!DnfCVHelper.GetLocationPoint(out stateLocationRectangle, hsvImage, this.GameRect))
                        if (this.house.WithoutNumber.Count <= 0)
                        {
                            this.stateScreenLocation = DnfCVHelper.GetLocationPoint(image, map.GameRect);
                        }
                        else
                        {
                            this.stateScreenLocation = DnfCVHelper.GetLocationPoint(image, map.GameRect,this.house.WithoutNumber);
                        }
                        if (this.stateScreenLocation.Equals(ParametersPoint.Empty))
                        {
                            //找不到定位点
                            G.Instance.InfoWriter("找不到定位点");
                            SetState(KillMonsterStates.IsLastHouse, true);
                            break;
                        }
                        CvInvoke.CvtColor(image, hsvImage, Emgu.CV.CvEnum.ColorConversion.Rgb2Hsv);
                        this.stateRolePosition = DnfCVHelper.FindRole(hsvImage, this.GameRect);
                        if (this.stateRolePosition .Equals( ZTPoint.Empty))
                        ZTPoint roleCBPosition = DnfCVHelper.FindRole(hsvImage, map.GameRect);
                        if (roleCBPosition.Equals(ZTPoint.Empty))
                        {
                            SetState(KillMonsterStates.FindRoleMove, false);
                            //未找到角色
                            if (!this.role.IsMoving)
                            {
                                SetState(KillMonsterStates.FindRoleMove, false);
                            }
                            else
                            {
                                SetState(KillMonsterStates.IsLastHouse, true);
                            }
                        }
                        else
                        {
                            if (this.moveState.IsFindRoleMoving)
                            if (this.role.IsMoveIntent(MoveIntent.FindRoleMove))
                            {
                                this.moveState.StopMove();
                                this.role.StopMove("update cb position");
                            }
                            role.UpdatePosition(roleCBPosition);
                            SetState(KillMonsterStates.FindMonster, false);
                        }
                        break;
                    case KillMonsterStates.FindRoleMove:
                        //todo:让主角移动(原:有怪攻击一下,无怪移动一下)
                        FindRoleMove();
                        break;
                    case KillMonsterStates.FindMonster:
                        //找怪
                        this.stateMonsters = LindongCVHelper.FindMonster(hsvImage, this.GameRect);
                        //找怪
                        this.stateMonsters = DnfCVHelper.FindMonster(hsvImage, map.GameRect);
                        if (this.stateMonsters.Length > 0)
                        {
                            G.Instance.DebugWriter(string.Format("已找到{0}个怪", this.stateMonsters.Length));
                            SetState(KillMonsterStates.CalcAttackDistance, false);
                            G.Instance.DebugWriter(string.Format("找到{0}个怪", this.stateMonsters.Length));
                            SetState(KillMonsterStates.CalcAttackPoint, false);
                        }
                        else
                        {
                            if (this.role.IsMoveIntent(MoveIntent.AttackMove))
                            {
                                this.role.StopMove("find monster to pickup thing");
                            }
                            SetState(KillMonsterStates.PickupThing, false);
                        }
                        break;
                    case KillMonsterStates.PickupThing:
                        //拾取物品
                        SetState(KillMonsterStates.FindDoor, false);
                        //todo: PickupThing();
                        PickupThing();
                        break;
                    case KillMonsterStates.FindDoor:
                        //查找门, 是否找到门
                        //查找门
                        if (this.house.IsEnd)
                        {
                            SetState(KillMonsterStates.IsLastHouse, true);
                            break;
                        }
                        FindDoor();
                        break;
                    case KillMonsterStates.EntryDoor:
                        //向门移动, 进门
                        EntryDoor();
                        break;
                    case KillMonsterStates.FindDoorMove:
                        //todo:找门移动
                        FindDoorMove();
                    case KillMonsterStates.ToLoop:
                        //巡逻
                        ToLoop();
                        break;
                    case KillMonsterStates.CalcAttackDistance:
                    case KillMonsterStates.CalcAttackPoint:
                        //判断使用何技能,计算攻击移动距离, 是否需要移动
                        CalcAttackDistance();
                        break;
@@ -283,23 +278,20 @@
                        ReleaseSkill();
                        break;
                    case KillMonsterStates.AttackMove:
                        //todo:攻击移动
                        //攻击移动
                        AttackMove();
                        break;
                    case KillMonsterStates.Exit:
                        //结束
                        G.Instance.DebugWriter("退出状态");
                        this.moveState.StopMove();
                        this.role.StopMove("exit");
                        if (this.isSuccess)
                        {
                            return ZTResult.Success;
                        }
                        return ZTResult.Failed;
                }
                
                G.Instance.DebugWriter("next state:" + currentState.ToString());
                G.Instance.DebugWriter($"next state:{currentState},capture screen:{needCaptureScreen}");
            }
        }
@@ -309,45 +301,68 @@
        /// </summary>
        private void FindRoleMove()
        {
            this.moveState.FindRoleMove();
            SetState(KillMonsterStates.FindRole, true);
            //if (this.stateMonsters.Length > 0)
            //{
            //    this.moveState.StopMove();
            //    G.Instance.DebugWriter("找不到角色,Send X");
            //    G.Instance.InputControl.PressKey(1000, HIDCode.X);
            //    SetState(KillMonsterStates.FindMonster, true);
            //    return;
            //}
            //else
            //{
            //    this.moveState.FindRoleMove();
            //    SetState(KillMonsterStates.IsLastHouse, true);
            //}
            if (this.role.IsMoving)
            {
                if (this.role.IsMoveIntent(MoveIntent.FindRoleMove))
                {
                    //进行中,则返回
                    SetState(KillMonsterStates.IsLastHouse, true);
                    return;
                }
                else
                {
                    //不是则停止
                    this.role.StopMove("find role other");
                }
            }
            this.role.FindRoleMove();
            SetState(KillMonsterStates.IsLastHouse, true);
        }
        DateTime pickupTime = DateTime.MinValue;
        /// <summary>
        /// 拾取物品
        /// </summary>
        private void PickupThing()
        {
            //拾取物品,获取最近一个物品位置并步行过去
            ZTPoint thingItemPosition = GetNearlyThingItem(image, stateRolePosition);
            if (!thingItemPosition .Equals( ZTPoint.Empty))
            {
                if (this.moveState.IsMoving && !this.moveState.IsPickupMoving)
                {
                    this.moveState.StopMove();
                }
                this.moveState.PickupMove(this.stateRolePosition, thingItemPosition);
                //return new KillMonsterStateResult(STATE_FindMonster, true);
            //拾取物品中,返回
            if (this.role.IsMoveIntent(MoveIntent.PickupMove))
            {
                SetState(KillMonsterStates.IsLastHouse, true);
                return;
            }
            if (this.moveState.IsPickupMoving)
            ZTPoint screenThingPosition = GetNearlyThingItem(hsvImage, role.Position);
            //是否有物品
            if (!screenThingPosition.Equals(ZTPoint.Empty))
            {
                this.moveState.StopMove();
                //有其它移动,则停止
                if (this.role.IsMoving&&!this.role.IsMoveIntent(MoveIntent.PickupMove))
                {
                    this.role.StopMove("pickup moveing");
                }
                //第一次发现有物品后,等一秒再去拾取,防物品刚出来时的去错误的位置拾取
                if (pickupTime == DateTime.MinValue)
                {
                    pickupTime = DateTime.Now.AddSeconds(1);
                }
                if (pickupTime > DateTime.Now)
                {
                    SetState(KillMonsterStates.IsLastHouse, true);
                    return;
                }
                ////todo:remove
                //hsvImage.Save(DateTime.Now.ToString("HH_mm_ss_fff")+"_" + Guid.NewGuid().ToString()+".png");
                this.role.PickupMove(screenThingPosition,this.stateScreenLocation);
                SetState(KillMonsterStates.IsLastHouse, true);
            }
            else
            {
                SetState(KillMonsterStates.FindDoor, false);
            }
        }
@@ -357,21 +372,38 @@
        private void FindDoor()
        {
            //查找真实的门
            this.stateDoorPosition = LindongCVHelper.FindDoor(out stateDoorLevelDirect, hsvImage, this.house.DoorDirection, this.GameRect);
            if (!this.stateDoorPosition .Equals(ZTPoint.Empty))
            Dictionary<ZTPoint,Direction> doors=ShikongzhimenCVHelper.FindDoor(hsvImage, this.house.DoorDirection, map.GameRect);
            this.state_DoorDirect = Direction.None;
            this.state_DoorPosition = ZTPoint.Empty;
            if (doors.Count > 0)
            {
                foreach (var door in doors)
                {
                    //门地图坐标
                    ZTPoint mapDoorPoint = this.house.ScreenToMapCoordinate(door.Key, this.stateScreenLocation);
                    //要进入门的允许区域
                    ZTPoint nextGatePoint = this.house.GetNextGatePoint(door.Value);
                    ZTRectangle doorRect = new ZTRectangle(nextGatePoint.X - 70, nextGatePoint.Y - 70, nextGatePoint.X + 70, nextGatePoint.Y + 70);
                    if (GeoHelper.IsInRect(mapDoorPoint, doorRect))
                    {
                        this.state_DoorDirect = door.Value;
                        this.state_DoorPosition = door.Key;
                        break;
                    }
                }
            }
            if (!this.state_DoorPosition.Equals(ZTPoint.Empty))
            {
                //找到门,向门移动  
                if (this.moveState.IsFindDoorMoving)
                {
                    this.moveState.StopMove();
                }
                G.Instance.InfoWriter("已找到门,位置:" + stateDoorPosition.ToString());
                SetState(KillMonsterStates.EntryDoor, false);
            }
            else
            {
                //未找到门,循环移动
                SetState(KillMonsterStates.FindDoorMove, false);
                //未找到门,巡逻
                SetState(KillMonsterStates.ToLoop, false);
            }
        }
@@ -380,122 +412,103 @@
        /// </summary>
        private void EntryDoor()
        {
            const Int32 XLevelOffset = 200;
            const Int32 YLevelOffset = 100;
            Int32 limitLine = 0;
            Int32 diff = 0;
            //传过来人物坐标和门的坐标,根据门的朝向计算人物走向
            switch (stateDoorLevelDirect)
            //已经开始进门
            if (this.role.IsMoving)
            {
                case Direction.Up:
                    //门在上方
                    limitLine = stateDoorPosition.Y + YLevelOffset;
                    if (stateRolePosition.Y < limitLine)
                    {
                        //下移
                        this.moveState.SyncMove(new ZTPoint(0, limitLine - stateRolePosition.Y));
                    }
                    //垂直对齐
                    diff = stateDoorPosition.X - stateRolePosition.X;
                    this.moveState.SyncMove(new ZTPoint(diff, 0));
                    //移动y,进入
                    this.moveState.SyncMove(new ZTPoint(0, this.GameRect.Start.Y - stateRolePosition.Y));
                    break;
                case Direction.Right:
                    //门在右侧
                    limitLine = stateDoorPosition.X - XLevelOffset;
                    if (stateRolePosition.X > limitLine)
                    {
                        //如果角色位于门右侧,先向左移
                        this.moveState.SyncMove(new ZTPoint(limitLine - stateRolePosition.X, 0));
                    }
                    //水平对齐
                    diff = stateDoorPosition.Y - stateRolePosition.Y;
                    this.moveState.SyncMove(new ZTPoint(0, diff));
                    //移动x,进入
                    this.moveState.SyncMove(new ZTPoint(this.GameRect.End.X - stateRolePosition.X, 0));
                    break;
                case Direction.Bottom:
                    //门在下方
                    limitLine = stateDoorPosition.Y - YLevelOffset;
                    if (stateRolePosition.Y > limitLine)
                    {
                        //如果角色在门下方,先向上移
                        this.moveState.SyncMove(new ZTPoint(0, limitLine - stateRolePosition.Y));
                    }
                    //垂直对齐
                    diff = stateDoorPosition.X - stateRolePosition.X;
                    this.moveState.SyncMove(new ZTPoint(diff, 0));
                    //移动y,进入
                    this.moveState.SyncMove(new ZTPoint(0, this.GameRect.End.Y - stateRolePosition.Y));
                    break;
                case Direction.Left:
                    //门在左侧
                    limitLine = stateDoorPosition.X + XLevelOffset;
                    if (stateRolePosition.X < limitLine)
                    {
                        //如果角色位于门左侧,先向右移
                        this.moveState.SyncMove(new ZTPoint(limitLine - stateRolePosition.X, 0));
                    }
                    //水平对齐
                    diff = stateDoorPosition.Y - stateRolePosition.Y;
                    this.moveState.SyncMove(new ZTPoint(0, diff));
                    //移动x,进入
                    this.moveState.SyncMove(new ZTPoint(this.GameRect.Start.X - stateRolePosition.X, 0));
                    break;
                this.role.StopMove("entry door other moving");
            }
            SetState(KillMonsterStates.IsLastHouse, true);
            return;
        }
        /// <summary>
        /// 找门移动
        /// </summary>
        private void FindDoorMove()
        {
            Int32 areaID = 0;
            if (this.outOfBounds.InOutOfBound(this.house.Index, stateRolePosition, out areaID))
            const Int32 offsetX = 200;
            const Int32 offsetY = 100;
            ZTRectangle doorRect = new ZTRectangle(this.state_DoorPosition.X - offsetX, this.state_DoorPosition.Y - offsetY, this.state_DoorPosition.X + offsetX, this.state_DoorPosition.Y + offsetY);
            if (tryEntryDoor && GeoHelper.IsInRect(this.role.RoleCBPosition.Sub(DnfRole.RoleHalfOffset), doorRect))
            {
                this.outOfBounds.MoveToCommonBound(areaID);
                //离门太近,先向外走,再向门走
                Int32 limitLine = 0;
                Int32 diff = 0;
                //传过来人物坐标和门的坐标,根据门的朝向计算人物走向
                switch (state_DoorDirect)
                {
                    case Direction.Up:
                        //门在上方
                        limitLine = state_DoorPosition.Y + offsetY;
                        //下移
                        this.role.SyncMove(new ZTPoint(0, limitLine - role.Position.Y));
                        //垂直对齐
                        diff = state_DoorPosition.X - role.Position.X;
                        this.role.SyncMove(new ZTPoint(diff, 0));
                        //移动y,进入
                        this.role.SyncMove(new ZTPoint(0, map.GameRect.Start.Y - role.Position.Y));
                        break;
                    case Direction.Right:
                        //门在右侧
                        limitLine = state_DoorPosition.X - offsetX;
                        //如果角色位于门右侧,先向左移
                        this.role.SyncMove(new ZTPoint(limitLine - role.Position.X, 0));
                        //水平对齐
                        diff = state_DoorPosition.Y - role.Position.Y;
                        this.role.SyncMove(new ZTPoint(0, diff));
                        //移动x,进入
                        this.role.SyncMove(new ZTPoint(map.GameRect.End.X - role.Position.X, 0));
                        break;
                    case Direction.Bottom:
                        //门在下方
                        limitLine = state_DoorPosition.Y - offsetY;
                        //如果角色在门下方,先向上移
                        this.role.SyncMove(new ZTPoint(0, limitLine - role.Position.Y));
                        //垂直对齐
                        diff = state_DoorPosition.X - role.Position.X;
                        this.role.SyncMove(new ZTPoint(diff, 0));
                        //移动y,进入
                        this.role.SyncMove(new ZTPoint(0, map.GameRect.End.Y - role.Position.Y));
                        break;
                    case Direction.Left:
                        //门在左侧
                        limitLine = state_DoorPosition.X + offsetX;
                        //如果角色位于门左侧,先向右移
                        this.role.SyncMove(new ZTPoint(limitLine - role.Position.X, 0));
                        //水平对齐
                        diff = state_DoorPosition.Y - role.Position.Y;
                        this.role.SyncMove(new ZTPoint(0, diff));
                        //移动x,进入
                        this.role.SyncMove(new ZTPoint(map.GameRect.Start.X - role.Position.X, 0));
                        break;
                }
                tryEntryDoor = false;
            }
            else
            {
                this.moveState.FindDoorMove(stateRolePosition);
                this.role.EntryDoorMove(this.state_DoorPosition, this.stateScreenLocation, this.state_DoorDirect);
                tryEntryDoor = true;
            }
            SetState(KillMonsterStates.IsLastHouse, true);
            return;
        }
        private DateTime FindRoleLastNoMoveTime = DateTime.MaxValue;//最后没移动时间
        private bool FindRoleLastNoMoveStart = false;//没移动是否开始计时
        private ZTSize attackMoveDistance = ZTSize.Empty;
        private HIDCode roleDirection = HIDCode.NoEvent;
        /// <summary>
        /// 判断使用何技能,计算攻击移动距离, 是否需要移动
        /// </summary>
        private void CalcAttackDistance()
        {
            SkillInfo attackSkill = this.house.Skills.SyncPeek();
            
            //计算攻击移动距离
            bool needMove = false;
            attackMoveDistance = AttackRectangle.GetMoveDistance(this.GameRect, stateRolePosition, stateMonsters, attackSkill, out roleDirection, out needMove);
            skillReleasePoint = AttackRectangle.GetAttackPoint(map.GameRect, role.HalfPosition, stateMonsters, attackSkill, out roleDirection, out needMove);
            if (!needMove)
            {
                G.Instance.DebugWriter(string.Format("不需移动直接发技能,距离:{0}", attackMoveDistance.ToString()));
                if (this.role.IsMoving)
                {
                    this.role.StopMove("calc attack");
                }
                G.Instance.DebugWriter(string.Format("不需移动直接发技能,距离:{0}", skillReleasePoint.ToString()));
                SetState(KillMonsterStates.ReleaseSkill, false);
            }
            else
@@ -503,25 +516,44 @@
                SetState(KillMonsterStates.AttackMove, false);
            }
        }
        /// <summary>
        /// 攻击移动
        /// </summary>
        private void AttackMove()
        {
            if (this.role.IsMoving)
            {
                if (this.role.IsMoveIntent(MoveIntent.AttackMove))
                {
                    //todo:添加如果是攻击移动中,如果怪物偏差太大则重新计算
                    //进行中,则返回
                    SetState(KillMonsterStates.IsLastHouse, true);
                    return;
                }
                else
                {
                    //不是则停止
                    this.role.StopMove("attack move other");
                }
            }
            G.Instance.DebugWriter("attack move :" + skillReleasePoint.ToString() + ",role:" + role.Position.ToString() + ",monster1:" + stateMonsters[0].ToString() + ",skill:" + this.house.Skills.SyncPeek().Key.ToString());
            this.role.AttackMove(skillReleasePoint, this.stateScreenLocation);
            SetState(KillMonsterStates.FindRole, true);
        }
        /// <summary>
        /// 调整朝向, 释放技能
        /// </summary>
        private void ReleaseSkill()
        {
            SkillInfo skill = this.house.Skills.SyncDeQueue();
            this.roleLastPosition = ZTPoint.Empty;
            StateProvider.Instance.AttackKey = skill.Key;
            if (roleDirection != HIDCode.NoEvent)
            {
                G.Instance.InputControl.PressKey(100, roleDirection);
            }
            this.moveState.StopMove();
            if (skill.Key == HIDCode.X)
            {
                for (int i = 0; i < 5; i++)
@@ -533,47 +565,36 @@
            else
            {
                G.Instance.InputControl.PressKey(RandomUtils.KeyPressDuration, skill.Key);
                Thread.Sleep((Int32)skill.ReleaseTime);
                Thread.Sleep((Int32)skill.ReleaseWaitTime);
            }
            G.Instance.DebugWriter(string.Format("发完技能,技能按键:{0},技能名称:{1}", skill.Key, skill.SkillName));
            SetState(KillMonsterStates.IsLastHouse, true);
        }
        /// <summary>
        /// 攻击移动
        /// 巡逻
        /// </summary>
        private void AttackMove()
        private void ToLoop()
        {
            SkillInfo attackSkill = this.house.Skills.SyncPeek();
            //没有移动,可能有障碍物
            if (stateRolePosition .Equals( this.roleLastPosition))
            //巡逻
            if (this.role.IsMoving)
            {
                if (FindRoleLastNoMoveStart && (DateTime.Now - FindRoleLastNoMoveTime).TotalMilliseconds > NoMoveMaxMillSecond)
                if (this.role.IsMoveIntent(MoveIntent.ToLoop))
                {
                    //开始计时 并且 超过最大未移动容忍时间
                    G.Instance.DebugWriter("find role no mvoe:" + stateRolePosition.ToString());
                    this.moveState.StopMove();
                    G.Instance.InputControl.PressKey(RandomUtils.KeyPressDuration, HIDCode.X);
                    FindRoleLastNoMoveTime = DateTime.Now;
                    //进行中,则返回
                    SetState(KillMonsterStates.IsLastHouse, true);
                    return;
                }
                else if (!FindRoleLastNoMoveStart)
                else
                {
                    //没开始计时 则 开始计时
                    FindRoleLastNoMoveStart = true;
                    FindRoleLastNoMoveTime = DateTime.Now;
                    //不是则停止
                    this.role.StopMove("to loop other");
                }
            }
            else
            {
                //移动了 取消计时
                this.roleLastPosition = stateRolePosition;
                FindRoleLastNoMoveStart = false;
            }
            G.Instance.DebugWriter("attack move :" + attackMoveDistance.ToString() + ",role:" + stateRolePosition.ToString() + ",monster1:" + stateMonsters[0].ToString() + ",skill:" + attackSkill.Key.ToString());
            this.moveState.AttackMove(attackMoveDistance);
            SetState(KillMonsterStates.FindRole, true);
            this.role.LoopMove(this.stateScreenLocation);
            SetState(KillMonsterStates.IsLastHouse, true);
        }
        #endregion
@@ -582,22 +603,22 @@
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        public ZTPoint GetNearlyThingItem(Image<Rgb, byte> image, ZTPoint rolePosition)
        public ZTPoint GetNearlyThingItem(Image<Hsv, byte> image, ZTPoint rolePosition)
        {
            List<ZTPoint> points = DnfCVHelper.GetThingItemPoints(image, this.GameRect);
            if (points.Count <= 0)
            ZTPoint[] points = DnfCVHelper.FindThings(image, map.GameRect);
            if (points.Length <= 0)
            {
                return ZTPoint.Empty;
            }
            if (points.Count == 1)
            if (points.Length == 1)
            {
                return points[0];
            }
            double distance = 0;
            ZTPoint result = ZTPoint.Empty;
            for (int i = 0; i < points.Count; i++)
            for (int i = 0; i < points.Length; i++)
            {
                double temp = ZTImage.Utils.GetDistance(rolePosition.X, rolePosition.Y, points[i].X, points[i].Y);
                if (i == 0)
@@ -617,23 +638,23 @@
            return result;
        }
        
        /// <summary>
        /// 牌的位置
        /// </summary>
        private static readonly ZTPoint[] CardList = new ZTPoint[] {
            new ZTPoint(364,231),
            new ZTPoint(561,231),
            new ZTPoint(744,231),
            new ZTPoint(924,231),
            new ZTPoint(164,195),
            new ZTPoint(315,195),
            new ZTPoint(474,195),
            new ZTPoint(635,195),
            new ZTPoint(364,570),
            new ZTPoint(561,570),
            new ZTPoint(744,570),
            new ZTPoint(924,570),
            new ZTPoint(164,480),
            new ZTPoint(315,480),
            new ZTPoint(474,480),
            new ZTPoint(635,480),
        };
        /// <summary>
        /// 翻牌
        /// 1-4
@@ -644,20 +665,19 @@
        {
            Thread.Sleep(2000);
            Int32 number = RandomUtils.G(1, 4);
            ZTPoint willPosition = this.GameRect.Start.Add(CardList[number - 1]);
            ZTPoint willPosition = map.GameRect.Start.Add(CardList[number - 1]);
            G.Instance.InputControl.MoveToAndClick(RandomUtils.PointRange(willPosition, 10));
            //判断黄金版是否可以翻
            if (DnfCVHelper.HasMowangqiyueCard(this.GameRect))
            if (DnfCVHelper.HasGoldCard(map.GameRect))
            {
                number = RandomUtils.G(5, 8);
                willPosition = this.GameRect.Start.Add(CardList[number - 1]);
                willPosition = map.GameRect.Start.Add(CardList[number - 1]);
                G.Instance.InputControl.MoveToAndClick(RandomUtils.PointRange(willPosition, 10));
            }
        }
        
        /// <summary>
        /// 是否改变房间
        /// </summary>
@@ -665,32 +685,18 @@
        /// <returns></returns>
        private bool HouseIsChange()
        {
            Int32 houseIndex;
            if (!LindongCVHelper.GetCurrentHouseIndex(out houseIndex, image, this.miniMapStart))
            Int32 houseIndex = 0;
            if (!map.MiniMap.GetCurrentHouseIndexWaitTimeout(out houseIndex, image, map.CancelToken, 30 * 1000))
            {
                //得不到房间
                if (!FuncUtils.TimeoutCancelableWrap(30 * 1000, cancellationToken, () =>
                {
                    using (bitmap = ScreenCapture.Instance.CaptureScreen())
                    {
                        image = new Image<Rgb, byte>(bitmap);
                        image = image.GetSubRect(new System.Drawing.Rectangle(GameRect.Start.X, GameRect.Start.Y, GameRect.End.X - GameRect.Start.X + 1, GameRect.End.Y - GameRect.Start.Y + 1));
                        return LindongCVHelper.GetCurrentHouseIndex(out houseIndex, image, this.miniMapStart);
                    }
                }, 50))
                {
                    throw new Exception("找不到默认房间");
                }
                throw new Exception("找不到默认房间");
            }
            if (houseIndex != this.house.Index)
            {
                this.moveState.StopMove();
                return true;
            }
            return false;
        }
        /// <summary>
        /// 杀怪状态
        /// </summary>
@@ -709,8 +715,11 @@
            PickupThing,//拾取物品
            FindDoor,//查找门, 是否找到门
            EntryDoor,//向门移动, 进门
            FindDoorMove,//找门移动
            CalcAttackDistance,//判断使用何技能,计算攻击移动距离, 是否需要移动
            ToLoop,//巡逻
            CalcAttackPoint,//判断使用何技能,计算攻击移动距离, 是否需要移动
            ReleaseSkill,//调整朝向, 释放技能,
            AttackMove,//攻击移动
        }