using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using RichCreator.Utility; using RichCreator.Utility.Captures; using RichCreator.Utility.CV; using RichCreator.Utility.InputControl; using RichCreator.Utility.Structs; using Emgu.CV; using Emgu.CV.Structure; using RichCreator.Maps; using RichCreator.Maps.Lindong; using RichCreator.StateMachines; using RichCreator.Utilitys; using static RichCreator.Utilitys.AttackRectangle; using Utils= RichCreator.Utilitys.Utils; using ZTImage.Collections; namespace RichCreator.Jobs.StateMachines { /// /// 杀怪状态机 /// public class KillMonsterStateMachine_old:StateMachineBase { private const Int32 NoMoveMaxMillSecond = 2000;//最大未移动容忍毫秒数 private HouseInfo house;//当前房间 private ZTPoint miniMapStart;//小地图区域 private ZTRectangle gameRect;//游戏区域 private Int32 preHouseIndex = 0;//上一房间编号 private MoveState moveState;//移动状态 private OutOfBounds outOfBounds;//禁区 private bool isSuccess;//退出结果 private ZTPoint roleLastPosition=ZTPoint.Empty;//角色最后位置 private Int32 runningStep = RunningStep.None;//是否恢复的状态 //当前状态 private KillMonsterStates currentState = KillMonsterStates.Start; //是否截图屏幕 private bool captureScreen = false; #region Find Door Info //门坐标 private ZTPoint stateDoorPosition; //角色位置 private ZTPoint stateRolePosition; //离开的门朝向 private Direction stateDoorLevelDirect = Direction.None; //定位点方框 private MultiList stateLocationRectangle = new MultiList(); //怪 private ZTPoint[] stateMonsters; private System.Drawing.Bitmap bitmap = null; //原图 private Image image = null; //色彩hsv private Image hsvImage = null; #endregion public KillMonsterStateMachine(HouseInfo house, ZTPoint miniMapStart, ZTRectangle gameRect,Int32 preHouseIndex,Int32 runningStep) { this.runningStep = runningStep; this.house = house; this.miniMapStart = miniMapStart; this.gameRect = gameRect; this.preHouseIndex = preHouseIndex; moveState = new MoveState(this.gameRect, this.house); outOfBounds = new OutOfBounds(this.gameRect,moveState); hsvImage = new Image(gameRect.End.X - gameRect.Start.X + 1, gameRect.End.Y - gameRect.Start.Y + 1); } private void SetState(KillMonsterStates current, bool capture) { currentState = current; captureScreen = capture; } /// /// 状态机开始 /// /// /// /// /// public ZTResult Work(CancellationToken cancellationToken, Int32 timeoutMillSecond) { DateTime expireTime = DateTime.Now.AddMilliseconds(timeoutMillSecond); if (this.runningStep > RunningStep.None) { SetState(KillMonsterStates.FindMonster, true); } while (true) { if (cancellationToken.IsCancellationRequested) { G.Instance.DebugWriter("取消刷图"); this.moveState.StopMove(); return ZTResult.Cancel; } if (DateTime.Now > expireTime) { G.Instance.DebugWriter("刷图超时"); this.moveState.StopMove(); return ZTResult.Timeout; } if (captureScreen) { using (bitmap = ScreenCapture.Instance.CaptureScreen()) { image = new Image(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)); } if (this.house.Index != 15) { //计算是否进入其它房间 if (HouseIsChange(cancellationToken)) { return ZTResult.Success; } } } bool lastCaptureScreen = this.captureScreen; switch (currentState) { case KillMonsterStates.Start: StartState(); //开始 break; case KillMonsterStates.FindMonster: //找怪 CvInvoke.CvtColor(image, hsvImage, Emgu.CV.CvEnum.ColorConversion.Rgb2Hsv); FindMonster(image, hsvImage); break; case KillMonsterStates.DetectDoorIsOpen: //查找进入下一房间的门是否开了 CvInvoke.CvtColor(image, hsvImage, Emgu.CV.CvEnum.ColorConversion.Rgb2Hsv); DetectDoorIsOpen(image, hsvImage); break; case KillMonsterStates.MoveToDoor: //移动进门 MoveToDoor(); break; case KillMonsterStates.PrepareReleaseSkill: //释放技能预处理,计算位置 PrepareReleaseSkill(); break; case KillMonsterStates.ReleaseSkill: //释放技能 ReleaseSkill(); break; case KillMonsterStates.Exit: //结束 G.Instance.DebugWriter("退出状态"); this.moveState.StopMove(); if (this.isSuccess) { return ZTResult.Success; } return ZTResult.Failed; } if (lastCaptureScreen) { image.Dispose(); } G.Instance.DebugWriter("next state:" + currentState.ToString()); } } #region States private void StartState() { SingleEntryHouseSkill.ReleaseSkill(this.house.Index, this.preHouseIndex,this.moveState); SetState(KillMonsterStates.FindMonster, true); } /// /// 0.找怪 /// /// /// /// private void FindMonster(Image image, Image hsvImage) { //怪 this.stateMonsters = LindongCVHelper.FindMonster(hsvImage,this.gameRect); //主角 this.stateRolePosition = DnfCVHelper.FindRole(hsvImage, this.gameRect); //定位点 DnfCVHelper.GetLocationPoint(out stateLocationRectangle, hsvImage, this.gameRect); if (this.stateMonsters.Length > 0) { G.Instance.DebugWriter(string.Format("已找到{0}个怪", this.stateMonsters.Length)); //未找到主角 if (stateRolePosition == ZTPoint.Empty) { this.moveState.StopMove(); G.Instance.DebugWriter("找不到角色,Send X"); G.Instance.InputControl.PressKey(1000, HIDCode.X); SetState(KillMonsterStates.FindMonster, true); return; } SetState(KillMonsterStates.PrepareReleaseSkill, false); return; } else { //未查找到主角 if (stateRolePosition == ZTPoint.Empty) { if (this.moveState.IsMoving && !this.moveState.IsFindRoleMoving) { this.moveState.StopMove(); } //是否刷完 if (IsComplete(image)) { SetState(KillMonsterStates.Exit, false); return; } this.moveState.FindRoleMove(); SetState(KillMonsterStates.FindMonster, true); return; } SetState(KillMonsterStates.DetectDoorIsOpen, true); return; } } private DateTime FindRoleLastNoMoveTime = DateTime.MaxValue;//最后没移动时间 private bool FindRoleLastNoMoveStart = false;//没移动是否开始计时 /// /// 1.释放技能预处理,计算位置 /// /// private void PrepareReleaseSkill() { if (this.moveState.IsMoving&&!this.moveState.IsAttackMoving) { this.moveState.StopMove(); } SkillInfo skill = this.house.Skills.SyncPeek(); //计算攻击移动距离 HIDCode dir = HIDCode.RightArrow; bool needMove = false; ZTSize moveDistance = AttackRectangle.GetMoveDistance(this.gameRect, stateRolePosition, stateMonsters, skill, out dir, out needMove); if (!needMove) { this.roleLastPosition = ZTPoint.Empty; //不需要移动 if (dir != HIDCode.NoEvent) { G.Instance.InputControl.PressKey(100, dir); } this.moveState.StopMove(); G.Instance.DebugWriter(string.Format("不需移动直接发技能,距离:{0}", moveDistance.ToString())); SetState(KillMonsterStates.ReleaseSkill, false); return; } //没有移动,可能有障碍物 if (stateRolePosition == this.roleLastPosition) { if (FindRoleLastNoMoveStart && (DateTime.Now - FindRoleLastNoMoveTime).TotalMilliseconds > NoMoveMaxMillSecond) { //开始计时 并且 超过最大未移动容忍时间 G.Instance.DebugWriter("find role no mvoe:" + stateRolePosition.ToString()); this.moveState.StopMove(); G.Instance.InputControl.PressKey(RandomUtils.KeyPressDuration, HIDCode.X); FindRoleLastNoMoveTime = DateTime.Now; } else if (!FindRoleLastNoMoveStart) { //没开始计时 则 开始计时 FindRoleLastNoMoveStart = true; FindRoleLastNoMoveTime = DateTime.Now; } } else { //移动了 取消计时 this.roleLastPosition = stateRolePosition; FindRoleLastNoMoveStart = false; } G.Instance.DebugWriter("attack move :"+moveDistance.ToString()+",role:"+stateRolePosition.ToString()+",monster1:"+stateMonsters[0].ToString()+",skill:"+skill.Key.ToString()); this.moveState.AttackMove(moveDistance); SetState(KillMonsterStates.FindMonster, true); return; } /// /// 2.释放技能 /// /// private void ReleaseSkill() { SkillInfo skill = this.house.Skills.SyncDeQueue(); if (skill.Key == HIDCode.X) { for (int i = 0; i < 5; i++) { G.Instance.InputControl.PressKey(RandomUtils.KeyPressDuration, skill.Key); Thread.Sleep(200); } } else { G.Instance.InputControl.PressKey(RandomUtils.KeyPressDuration, skill.Key); Thread.Sleep((Int32)skill.ReleaseTime); } G.Instance.DebugWriter(string.Format("发完技能,技能按键:{0},技能名称:{1}", skill.Key, skill.SkillName)); SetState(KillMonsterStates.FindMonster, true); return; } /// /// 3.检测进入下一房间的门是否开了 /// /// private void DetectDoorIsOpen(Image image, Image hsvImage) { if (this.moveState.IsAttackMoving|| this.moveState.IsFindRoleMoving) { this.moveState.StopMove(); } ////查找当前房间编号,看是否进入其它房间 //Int32 houseIndex; //if (!LindongCVHelper.GetCurrentHouseIndex(out houseIndex, image, this.miniMapStart)) //{ if (IsComplete(image)) { SetState(KillMonsterStates.Exit, false); return; } // G.Instance.DebugWriter("检测是否进入下一房间时,未发现小地图中有人物标记,id"+this.house.Index+",isend:"+this.house.IsEnd.ToString()); // return new KillMonsterStateResult(STATE_FindMonster, true); //} //if (houseIndex != this.house.Index) //{ // //已进入其它房间 // this.moveState.StopMove(); // this.exitResult = true; // return new KillMonsterStateResult(STATE_Exit, false); //} ////拾取物品,获取最近一个物品位置并步行过去 //ZTPoint thingItemPosition = GetNearlyThingItem(image, rolePosition); //if (thingItemPosition != ZTPoint.Empty) //{ // if (this.moveState.IsMoving && !this.moveState.IsPickupMoving) // { // this.moveState.StopMove(); // } // this.moveState.PickupMove(rolePosition, thingItemPosition); // return new KillMonsterStateResult(STATE_FindMonster, true); //} //if (this.moveState.IsPickupMoving) //{ // this.moveState.StopMove(); //} //查找真实的门 ZTPoint doorPosition = LindongCVHelper.FindDoor(out stateDoorLevelDirect,hsvImage, this.house.DoorDirection,this.gameRect); if (doorPosition != ZTPoint.Empty) { G.Instance.InfoWriter("door find:"+doorPosition.ToString()); this.moveState.StopMove(); this.stateDoorPosition = doorPosition; //找到门,向门移动 SetState(KillMonsterStates.MoveToDoor, false); return; } else { //未找到门,循环移动 Int32 areaID = 0; if (this.outOfBounds.InOutOfBound(this.house.Index, stateRolePosition, out areaID)) { this.outOfBounds.MoveToCommonBound(areaID); } else { this.moveState.FindDoorMove(stateRolePosition); } } SetState(KillMonsterStates.FindMonster, true); return; } /// /// 4.找门 /// /// private void MoveToDoor() { const Int32 XLevelOffset = 200; const Int32 YLevelOffset = 100; Int32 limitLine = 0; Int32 diff = 0; //传过来人物坐标和门的坐标,根据门的朝向计算人物走向 switch (stateDoorLevelDirect) { 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; } SetState(KillMonsterStates.DetectDoorIsOpen, true); return; } #endregion /// /// 得到最近的物品 /// /// /// public ZTPoint GetNearlyThingItem(Image image,ZTPoint rolePosition) { List points=DnfCVHelper.GetThingItemPoints(image, this.gameRect); if (points.Count <= 0) { return ZTPoint.Empty; } if (points.Count == 1) { return points[0]; } double distance = 0; ZTPoint result = ZTPoint.Empty; for (int i = 0; i < points.Count; i++) { double temp = ZTImage.Utils.GetDistance(rolePosition.X, rolePosition.Y, points[i].X, points[i].Y); if (i == 0) { distance = temp; result = points[0]; continue; } if (temp < distance) { distance = temp; result = points[i]; } } return result; } /// /// 是否完成 /// /// /// public bool IsComplete(Image image) { if (this.house.IsEnd) { if (DnfCVHelper.IsJiangli(image, this.gameRect)) { //翻牌 this.moveState.StopMove(); Fanpai(); Thread.Sleep(5000); this.isSuccess = true; return true; } if (DnfCVHelper.IsCompleteRoom(image, this.gameRect)) { //已经刷完 this.moveState.StopMove(); this.isSuccess = true; return true; } } return false; } #region 翻牌 /// /// 牌的位置 /// 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(364,570), new ZTPoint(561,570), new ZTPoint(744,570), new ZTPoint(924,570), }; /// /// 翻牌 /// 1-4 /// 5-8 /// /// private void Fanpai() { Thread.Sleep(2000); Int32 number = RandomUtils.G(1, 4); ZTPoint willPosition = this.gameRect.Start.Add(CardList[number - 1]); G.Instance.InputControl.MoveToAndClick(RandomUtils.PointRange(willPosition,10)); //判断黄金版是否可以翻 if (DnfCVHelper.HasMowangqiyueCard(this.gameRect)) { number = RandomUtils.G(5, 8); willPosition = this.gameRect.Start.Add(CardList[number - 1]); G.Instance.InputControl.MoveToAndClick(RandomUtils.PointRange(willPosition, 10)); } } #endregion /// /// 是否改变房间 /// /// /// private bool HouseIsChange(CancellationToken cancellationToken) { Int32 houseIndex; if (!LindongCVHelper.GetCurrentHouseIndex(out houseIndex, image, this.miniMapStart)) { //得不到房间 if (!FuncUtils.TimeoutCancelableWrap(30 * 1000, cancellationToken, () => { using (bitmap = ScreenCapture.Instance.CaptureScreen()) { image = new Image(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("找不到默认房间"); } } if (houseIndex != this.house.Index) { this.moveState.StopMove(); return true; } return false; } /// /// 杀怪状态 /// public enum KillMonsterStates:Int32 { FindMonster = 0,//找怪 PrepareReleaseSkill = 1,//释放技能预处理,计算位置 ReleaseSkill = 2,//释放技能 DetectDoorIsOpen = 3,//查找进入下一房间的门是否开了 MoveToDoor = 4,//移动进门 Start = 8,//开始状态 Exit = 9,//完成状态 } } }