asmrobot
2019-11-25 2aeab450471cb80b59002da7da80faf251a0c4f4
src/RichCreator/StateMachines/KillMonsterStateMachine.cs
@@ -2,10 +2,12 @@
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;
@@ -51,6 +53,11 @@
        public KillMonsterStateMachine(MapInfo map,HouseInfo house, DnfRole role)
        {
            if (house.HousePathInfo.LoopPoint.Equals(ZTPoint.Empty))
            {
                throw new ArgumentOutOfRangeException("寻路中不存在循环点");
            }
            this.map = map;
            this.house = house;
            this.role = role;
@@ -72,10 +79,9 @@
        /// <param name="cancellationToken"></param>
        /// <param name="timeoutMillSecond"></param>
        /// <returns></returns>
        public ZTResult Work(Int32 timeoutMillSecond,Int32 preHouseIndex,Int32 runningStep)
        public ZTResult Work(Int32 timeoutMillSecond,Int32 fromHouseIndex,Int32 runningStep)
        {
            bool imageIsChange = false;//图像是否改变
            Int32 nextGate = 0;
            DateTime expireTime = DateTime.Now.AddMilliseconds(timeoutMillSecond);
            
            while (true)
@@ -83,14 +89,14 @@
                if (map.CancelToken.IsCancellationRequested)
                {
                    G.Instance.DebugWriter("取消刷图");
                    this.role.StopMove();
                    this.role.StopMove("cancel");
                    return ZTResult.Cancel;
                }
                if (DateTime.Now > expireTime)
                {
                    G.Instance.DebugWriter("刷图超时");
                    this.role.StopMove();
                    this.role.StopMove("timeout");
                    return ZTResult.Timeout;
                }
@@ -112,7 +118,10 @@
                {
                    case KillMonsterStates.Start:
                        //开始
                        this.map.EntryHousePrework(this.house.Index, preHouseIndex);
                        if (this.house.FromHouseIndex == fromHouseIndex)
                        {
                            this.map.EntryHousePrework(this.house.Index, fromHouseIndex);
                        }
                        SetState(KillMonsterStates.IsLastHouse, true);
                        break;
                    case KillMonsterStates.IsLastHouse:
@@ -136,7 +145,6 @@
                        //是否有奖励界面
                        if (DnfCVHelper.IsJiangli(image, map.GameRect))
                        {
                            G.Instance.InfoWriter("has jiangli");
                            SetState(KillMonsterStates.TurnAroundCard, false);
                        }
                        else
@@ -178,7 +186,6 @@
                        break;
                    case KillMonsterStates.FindRole:
                        //主角
                        //定位点
                        if (this.house.WithoutNumber.Count <= 0)
                        {
@@ -201,26 +208,32 @@
                        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.role.IsMoveIntent(Utility.Dnf.MoveIntent.FindRoleMove))
                            if (this.role.IsMoveIntent(MoveIntent.FindRoleMove))
                            {
                                this.role.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 = DnfCVHelper.FindMonster(hsvImage, map.GameRect);
                        if (this.stateMonsters.Length > 0)
                        {
                            G.Instance.DebugWriter(string.Format("找到{0}个怪", this.stateMonsters.Length));
@@ -228,13 +241,16 @@
                        }
                        else
                        {
                            if (this.role.IsMoveIntent(MoveIntent.AttackMove))
                            {
                                this.role.StopMove("find monster to pickup thing");
                            }
                            SetState(KillMonsterStates.PickupThing, false);
                        }
                        break;
                    case KillMonsterStates.PickupThing:
                        //拾取物品
                        //todo: PickupThing();
                        SetState(KillMonsterStates.FindDoor, false);
                        PickupThing();
                        break;
                    case KillMonsterStates.FindDoor:
                        //查找门
@@ -249,39 +265,9 @@
                        //向门移动, 进门
                        EntryDoor();
                        break;
                    case KillMonsterStates.InNextGatePoint:
                        //是否在进门点
                        ParametersPoint nextGatePoint = ParametersPoint.Empty;
                        ZTPoint rmhp=this.house.ScreenToMapCoordinate(this.role.HalfPosition, this.stateScreenLocation);
                        if (this.house.IsInNextGatePoint(out nextGatePoint,rmhp))
                        {
                            SetState(KillMonsterStates.ToLoopPoint, false);
                        }
                        else
                        {
                            //不在进门点
                            SetState(KillMonsterStates.ToNextGatePoint, false);
                        }
                        break;
                    case KillMonsterStates.ToNextGatePoint:
                        //移到进门点
                        ZTPoint rmp = this.house.ScreenToMapCoordinate(this.role.Position, this.stateScreenLocation);
                        ZTPoint ngp = DnfRole.HalfToFootPosition(this.house.HousePathInfo.NextGates[nextGate].Point);
                        this.role.MoveToMapPoint(rmp, ngp);
                        nextGate++;
                        nextGate = nextGate % this.house.HousePathInfo.NextGates.Count;
                        SetState(KillMonsterStates.IsLastHouse, true);
                        break;
                    case KillMonsterStates.ToLoopPoint:
                        //移动到循环点
                        if (!this.house.HousePathInfo.LoopPoint.Equals(ZTPoint.Empty))
                        {
                            //开始移动
                            ZTPoint roleMapPoint = this.house.ScreenToMapCoordinate(this.role.Position, this.stateScreenLocation);
                            this.role.MoveToMapPoint(roleMapPoint, this.house.HousePathInfo.LoopPoint);
                        }
                        SetState(KillMonsterStates.IsLastHouse, true);
                    case KillMonsterStates.ToLoop:
                        //巡逻
                        ToLoop();
                        break;
                    case KillMonsterStates.CalcAttackPoint:
                        //判断使用何技能,计算攻击移动距离, 是否需要移动
@@ -292,13 +278,12 @@
                        ReleaseSkill();
                        break;
                    case KillMonsterStates.AttackMove:
                        //todo:攻击移动
                        //攻击移动
                        AttackMove();
                        break;
                    case KillMonsterStates.Exit:
                        //结束
                        G.Instance.DebugWriter("退出!~");
                        this.role.StopMove();
                        this.role.StopMove("exit");
                        if (this.isSuccess)
                        {
                            return ZTResult.Success;
@@ -306,7 +291,7 @@
                        return ZTResult.Failed;
                }
                
                G.Instance.DebugWriter("next state:" + currentState.ToString());
                G.Instance.DebugWriter($"next state:{currentState},capture screen:{needCaptureScreen}");
            }
        }
@@ -316,32 +301,69 @@
        /// </summary>
        private void FindRoleMove()
        {
            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.FindRole, true);
            SetState(KillMonsterStates.IsLastHouse, true);
        }
        DateTime pickupTime = DateTime.MinValue;
        /// <summary>
        /// 拾取物品
        /// </summary>
        private void PickupThing()
        {
            ////拾取物品,获取最近一个物品位置并步行过去
            //ZTPoint thingItemPosition = GetNearlyThingItem(image, role.Position);
            //if (!thingItemPosition .Equals( ZTPoint.Empty))
            //{
            //    if (this.role.IsMoving && !this.role.IsMoveIntent(Utility.Dnf.MoveIntent.PickupMove))
            //    {
            //        this.role.StopMove();
            //    }
            //拾取物品中,返回
            if (this.role.IsMoveIntent(MoveIntent.PickupMove))
            {
                SetState(KillMonsterStates.IsLastHouse, true);
                return;
            }
            //    this.role.PickupMove(this.role.Position, thingItemPosition);
            //    //return new KillMonsterStateResult(STATE_FindMonster, true);
            //}
            ZTPoint screenThingPosition = GetNearlyThingItem(hsvImage, role.Position);
            //是否有物品
            if (!screenThingPosition.Equals(ZTPoint.Empty))
            {
                //有其它移动,则停止
                if (this.role.IsMoving&&!this.role.IsMoveIntent(MoveIntent.PickupMove))
                {
                    this.role.StopMove("pickup moveing");
                }
            //if (this.role.IsMoveIntent(Utility.Dnf.MoveIntent.PickupMove))
            //{
            //    this.role.StopMove();
            //}
                //第一次发现有物品后,等一秒再去拾取,防物品刚出来时的去错误的位置拾取
                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);
            }
        }
        /// <summary>
@@ -363,20 +385,15 @@
                    //要进入门的允许区域
                    ZTPoint nextGatePoint = this.house.GetNextGatePoint(door.Value);
                    ZTRectangle doorRect = new ZTRectangle(nextGatePoint.X - 70, nextGatePoint.Y - 70, nextGatePoint.X + 70, nextGatePoint.Y + 70);
                    G.Instance.InfoWriter("has door:" + mapDoorPoint.ToString()+",rect:"+doorRect.ToString());
                    if (GeoHelper.IsInRect(mapDoorPoint, doorRect))
                    {
                        G.Instance.InfoWriter("in door");
                        this.state_DoorDirect = door.Value;
                        this.state_DoorPosition = door.Key;
                        break;
                    }
                }
            }
            
            if (!this.state_DoorPosition.Equals(ZTPoint.Empty))
            {
@@ -385,8 +402,8 @@
            }
            else
            {
                //未找到门,是否存进门点
                SetState(KillMonsterStates.InNextGatePoint, false);
                //未找到门,巡逻
                SetState(KillMonsterStates.ToLoop, false);
            }
        }
@@ -395,12 +412,19 @@
        /// </summary>
        private void EntryDoor()
        {
            //已经开始进门
            if (this.role.IsMoving)
            {
                this.role.StopMove("entry door other moving");
            }
            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, doorRect))
            if (tryEntryDoor && GeoHelper.IsInRect(this.role.RoleCBPosition.Sub(DnfRole.RoleHalfOffset), doorRect))
            {
                //离门太近,先向外走,再向门走
                Int32 limitLine = 0;
                Int32 diff = 0;
                //传过来人物坐标和门的坐标,根据门的朝向计算人物走向
@@ -460,32 +484,7 @@
            }
            else
            {
                //先到进门点
                ZTPoint roleMapPoint = this.house.ScreenToMapCoordinate(this.role.Position, this.stateScreenLocation);
                ZTPoint nextGatePoint = this.house.GetNextGatePoint(this.state_DoorDirect);
                List<ZTPoint> paths = this.house.FindPath(roleMapPoint, DnfRole.HalfToFootPosition(nextGatePoint));
                //再到门后50像素
                ZTPoint dp = this.house.ScreenToMapCoordinate(this.state_DoorPosition, this.stateScreenLocation);
                ZTPoint doorPoint = DnfRole.HalfToFootPosition(dp);
                switch (this.state_DoorDirect)
                {
                    case Direction.Up:
                        doorPoint = doorPoint.Add(0, -50);
                        break;
                    case Direction.Right:
                        doorPoint = doorPoint.Add(50, 0);
                        break;
                    case Direction.Bottom:
                        doorPoint = doorPoint.Add(0, 50);
                        break;
                    case Direction.Left:
                        doorPoint = doorPoint.Add(-50, 0);
                        break;
                }
                paths.Add(doorPoint);
                this.role.MovePaths(roleMapPoint, paths);
                this.role.EntryDoorMove(this.state_DoorPosition, this.stateScreenLocation, this.state_DoorDirect);
                tryEntryDoor = true;
            }
@@ -505,6 +504,10 @@
            skillReleasePoint = AttackRectangle.GetAttackPoint(map.GameRect, role.HalfPosition, stateMonsters, attackSkill, out roleDirection, out needMove);
            if (!needMove)
            {
                if (this.role.IsMoving)
                {
                    this.role.StopMove("calc attack");
                }
                G.Instance.DebugWriter(string.Format("不需移动直接发技能,距离:{0}", skillReleasePoint.ToString()));
                SetState(KillMonsterStates.ReleaseSkill, false);
            }
@@ -519,8 +522,24 @@
        /// </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.AttackMoveTo(skillReleasePoint,this.stateScreenLocation);
            this.role.AttackMove(skillReleasePoint, this.stateScreenLocation);
            SetState(KillMonsterStates.FindRole, true);
        }
        
@@ -529,9 +548,8 @@
        /// </summary>
        private void ReleaseSkill()
        {
            this.role.StopMove();
            SkillInfo skill = this.house.Skills.SyncDeQueue();
            StateProvider.Instance.AttackKey = skill.Key;
            if (roleDirection != HIDCode.NoEvent)
            {
                G.Instance.InputControl.PressKey(100, roleDirection);
@@ -553,6 +571,31 @@
            G.Instance.DebugWriter(string.Format("发完技能,技能按键:{0},技能名称:{1}", skill.Key, skill.SkillName));
            SetState(KillMonsterStates.IsLastHouse, true);
        }
        /// <summary>
        /// 巡逻
        /// </summary>
        private void ToLoop()
        {
            //巡逻
            if (this.role.IsMoving)
            {
                if (this.role.IsMoveIntent(MoveIntent.ToLoop))
                {
                    //进行中,则返回
                    SetState(KillMonsterStates.IsLastHouse, true);
                    return;
                }
                else
                {
                    //不是则停止
                    this.role.StopMove("to loop other");
                }
            }
            this.role.LoopMove(this.stateScreenLocation);
            SetState(KillMonsterStates.IsLastHouse, true);
        }
        #endregion
        /// <summary>
@@ -560,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, map.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)
@@ -672,9 +715,7 @@
            PickupThing,//拾取物品
            FindDoor,//查找门, 是否找到门
            EntryDoor,//向门移动, 进门
            InNextGatePoint,//是否在进门点
            ToNextGatePoint,//移至进门点
            ToLoopPoint,//移至巡逻点
            ToLoop,//巡逻