| | |
| | | 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; |
| | |
| | | |
| | | 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; |
| | |
| | | /// <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) |
| | |
| | | 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; |
| | | } |
| | | |
| | |
| | | { |
| | | 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: |
| | |
| | | //是否有奖励界面 |
| | | if (DnfCVHelper.IsJiangli(image, map.GameRect)) |
| | | { |
| | | G.Instance.InfoWriter("has jiangli"); |
| | | SetState(KillMonsterStates.TurnAroundCard, false); |
| | | } |
| | | else |
| | |
| | | break; |
| | | case KillMonsterStates.FindRole: |
| | | //主角 |
| | | |
| | | //定位点 |
| | | if (this.house.WithoutNumber.Count <= 0) |
| | | { |
| | |
| | | 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)); |
| | |
| | | } |
| | | 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: |
| | | //查找门 |
| | |
| | | //向门移动, 进门 |
| | | 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: |
| | | //判断使用何技能,计算攻击移动距离, 是否需要移动 |
| | |
| | | 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; |
| | |
| | | return ZTResult.Failed; |
| | | } |
| | | |
| | | G.Instance.DebugWriter("next state:" + currentState.ToString()); |
| | | G.Instance.DebugWriter($"next state:{currentState},capture screen:{needCaptureScreen}"); |
| | | } |
| | | } |
| | | |
| | |
| | | /// </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> |
| | |
| | | //要进入门的允许区域 |
| | | 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)) |
| | | { |
| | |
| | | } |
| | | else |
| | | { |
| | | //未找到门,是否存进门点 |
| | | SetState(KillMonsterStates.InNextGatePoint, false); |
| | | //未找到门,巡逻 |
| | | SetState(KillMonsterStates.ToLoop, false); |
| | | } |
| | | } |
| | | |
| | |
| | | /// </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; |
| | | //传过来人物坐标和门的坐标,根据门的朝向计算人物走向 |
| | |
| | | } |
| | | 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; |
| | | } |
| | | |
| | |
| | | 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); |
| | | } |
| | |
| | | /// </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); |
| | | } |
| | | |
| | |
| | | /// </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); |
| | |
| | | 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> |
| | |
| | | /// </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) |
| | |
| | | PickupThing,//拾取物品 |
| | | FindDoor,//查找门, 是否找到门 |
| | | EntryDoor,//向门移动, 进门 |
| | | InNextGatePoint,//是否在进门点 |
| | | ToNextGatePoint,//移至进门点 |
| | | ToLoopPoint,//移至巡逻点 |
| | | ToLoop,//巡逻 |
| | | |
| | | |
| | | |