o
asmrobot
2019-10-27 c4bd9d8c587bd1401f0fb2f60c34a4964d7afe20
o
9 files added
1 files deleted
5 files renamed
28 files modified
3955 ■■■■ changed files
doc/流程图/切换频道.vsd patch | view | raw | blame | history
doc/流程图/刷怪图.vsdx patch | view | raw | blame | history
doc/流程图/杀怪KillMonster.vsd patch | view | raw | blame | history
src/RichCreator.Editor/App.xaml 2 ●●● patch | view | raw | blame | history
src/RichCreator.Editor/MainWindow.xaml 4 ●●●● patch | view | raw | blame | history
src/RichCreator.Editor/MainWindow.xaml.cs 12 ●●●● patch | view | raw | blame | history
src/RichCreator.Editor/RichCreator.Editor.csproj 13 ●●●● patch | view | raw | blame | history
src/RichCreator.Editor/Tools/MapEditor.xaml 59 ●●●●● patch | view | raw | blame | history
src/RichCreator.Editor/Tools/MapEditor.xaml.cs 817 ●●●●● patch | view | raw | blame | history
src/RichCreator.Editor/Tools/MapEditor_old.xaml 12 ●●●● patch | view | raw | blame | history
src/RichCreator.Editor/Tools/MapEditor_old.xaml.cs 24 ●●●● patch | view | raw | blame | history
src/RichCreator.Utility/CV/ChannelCVHelper.cs 6 ●●●● patch | view | raw | blame | history
src/RichCreator.Utility/CV/DnfCVHelper.cs 34 ●●●● patch | view | raw | blame | history
src/RichCreator.Utility/CV/GroupCVHelper.cs 12 ●●●● patch | view | raw | blame | history
src/RichCreator.Utility/CV/LindongCVHelper.cs 36 ●●●● patch | view | raw | blame | history
src/RichCreator.Utility/CV/SkillCVHelper.cs 19 ●●●●● patch | view | raw | blame | history
src/RichCreator.Utility/Captures/BitBltCapture.cs 1 ●●●● patch | view | raw | blame | history
src/RichCreator.Utility/InputControl/HardwareInputControl.cs 4 ●●●● patch | view | raw | blame | history
src/RichCreator.Utility/InputControl/IInputControl.cs 4 ●●●● patch | view | raw | blame | history
src/RichCreator.Utility/RichCreator.Utility.csproj 5 ●●●●● patch | view | raw | blame | history
src/RichCreator.Utility/Structs/HousePathInfo.cs 396 ●●●●● patch | view | raw | blame | history
src/RichCreator.Utility/Structs/ParametersPoint.cs 33 ●●●●● patch | view | raw | blame | history
src/RichCreator.Utility/Structs/ZTLine.cs 8 ●●●● patch | view | raw | blame | history
src/RichCreator.Utility/Structs/ZTLinePoint.cs 88 ●●●●● patch | view | raw | blame | history
src/RichCreator.Utility/Structs/ZTPoint.cs 11 ●●●●● patch | view | raw | blame | history
src/RichCreator.Utility/Structs/ZTPolygon.cs 84 ●●●●● patch | view | raw | blame | history
src/RichCreator.Utility/Utilitys/GeometryHelper.cs 267 ●●●●● patch | view | raw | blame | history
src/RichCreator/Jobs/DNFJob.cs 28 ●●●● patch | view | raw | blame | history
src/RichCreator/Jobs/WeGameJob.cs 8 ●●●● patch | view | raw | blame | history
src/RichCreator/MainWindow.xaml.cs 6 ●●●● patch | view | raw | blame | history
src/RichCreator/Maps/HouseInfo.cs 2 ●●● patch | view | raw | blame | history
src/RichCreator/Maps/Lindong/LindongMap.cs 76 ●●●● patch | view | raw | blame | history
src/RichCreator/Maps/MapInfo.cs 6 ●●●●● patch | view | raw | blame | history
src/RichCreator/Maps/Skills/SkillMap.cs 81 ●●●● patch | view | raw | blame | history
src/RichCreator/Maps/Test/TestMap.cs 16 ●●●● patch | view | raw | blame | history
src/RichCreator/RichCreator.csproj 3 ●●●● patch | view | raw | blame | history
src/RichCreator/StateMachines/KillMonsterStateMachine.cs 937 ●●●● patch | view | raw | blame | history
src/RichCreator/StateMachines/KillMonsterStateMachine_old.cs 670 ●●●●● patch | view | raw | blame | history
src/RichCreator/StateMachines/KillMonsterStateResult.cs 35 ●●●●● patch | view | raw | blame | history
src/RichCreator/StateMachines/MoveState.cs 41 ●●●● patch | view | raw | blame | history
src/RichCreator/configs/RichCreator.config 4 ●●●● patch | view | raw | blame | history
src/test/Program.cs 85 ●●●● patch | view | raw | blame | history
src/test/test.csproj 6 ●●●●● patch | view | raw | blame | history
doc/流程图/切换频道.vsd
Binary files differ
doc/流程图/刷怪图.vsdx
Binary files differ
doc/流程图/杀怪KillMonster.vsd
Binary files differ
src/RichCreator.Editor/App.xaml
@@ -2,7 +2,7 @@
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:RichCreator.Editor"
             StartupUri="MainWindow.xaml">
             StartupUri="Tools/MapEditor.xaml">
    <Application.Resources>
         
    </Application.Resources>
src/RichCreator.Editor/MainWindow.xaml
@@ -58,8 +58,8 @@
                <MenuItem Header="方块灰度" Click="BlockGray" />
                <MenuItem Header="鼠标模式识别" Click="MenuItem_Click" />
                <MenuItem Header="AStar寻路工具" Click="AStarTools_Click" />
                <MenuItem Header="图最短路径寻路" Click="DijkstraTools_Click" />
                <!--<MenuItem Header="AStar寻路工具" Click="AStarTools_Click" />-->
                <MenuItem Header="地图编辑..." Click="DijkstraTools_Click" />
            </MenuItem>
            <MenuItem Header="帮助(H)" >
src/RichCreator.Editor/MainWindow.xaml.cs
@@ -1110,15 +1110,15 @@
            mt.ShowDialog();
        }
        private void AStarTools_Click(object sender, RoutedEventArgs e)
        {
            AStarTools window = new AStarTools();
            window.ShowDialog();
        }
        //private void AStarTools_Click(object sender, RoutedEventArgs e)
        //{
        //    AStarTools window = new AStarTools();
        //    window.ShowDialog();
        //}
        private void DijkstraTools_Click(object sender, RoutedEventArgs e)
        {
            DijkstraTools window = new DijkstraTools();
            MapEditor window = new MapEditor();
            window.ShowDialog();
        }
src/RichCreator.Editor/RichCreator.Editor.csproj
@@ -75,11 +75,8 @@
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
    </ApplicationDefinition>
    <Compile Include="Tools\DijkstraTools.xaml.cs">
      <DependentUpon>DijkstraTools.xaml</DependentUpon>
    </Compile>
    <Compile Include="Tools\AStarTools.xaml.cs">
      <DependentUpon>AStarTools.xaml</DependentUpon>
    <Compile Include="Tools\MapEditor.xaml.cs">
      <DependentUpon>MapEditor.xaml</DependentUpon>
    </Compile>
    <Compile Include="Tools\CV\MainCV.xaml.cs">
      <DependentUpon>MainCV.xaml</DependentUpon>
@@ -121,13 +118,9 @@
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
    </Page>
    <Page Include="Tools\DijkstraTools.xaml">
    <Page Include="Tools\MapEditor.xaml">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
    </Page>
    <Page Include="Tools\AStarTools.xaml">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>
    <Page Include="Tools\CV\MainCV.xaml">
      <Generator>MSBuild:Compile</Generator>
src/RichCreator.Editor/Tools/MapEditor.xaml
New file
@@ -0,0 +1,59 @@
<Window x:Class="RichCreator.Editor.Tools.MapEditor"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:RichCreator.Editor.Tools"
        mc:Ignorable="d"
        Loaded="Window_Loaded"
        Title="地图编辑器" Height="720" Width="1280">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Border  Grid.Row="0" BorderThickness="1" BorderBrush="Gray">
            <Grid>
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,4,0,0">
                    <TextBlock Text="参数:" Margin="22 0 0 0" VerticalAlignment="Center" />
                    <TextBox Width="45" x:Name="tagNumber" Text="0" VerticalContentAlignment="Center"/>
                    <ComboBox SelectedIndex="0" x:Name="slOperate">
                        <ComboBoxItem>障碍</ComboBoxItem>
                        <ComboBoxItem>定位点</ComboBoxItem>
                        <ComboBoxItem>寻路点</ComboBoxItem>
                        <ComboBoxItem>巡逻线</ComboBoxItem>
                        <ComboBoxItem>寻路线</ComboBoxItem>
                    </ComboBox>
                    <Button Content="清空定位点" Margin="5 0" Click="ClearPosition_Click" />
                    <TextBlock VerticalAlignment="Center">除定位点外,其它物体右键删除。</TextBlock>
                </StackPanel>
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="5 5">
                    <Button Content="加载图片" Margin="5 0" Click="OpenFromFile_Click" />
                    <Button Content="复制为JSON" Margin="5 0" Click="CopyJSON_Click" />
                    <Button Content="加载JSON" Margin="5 0" Click="CreateFromJSON_Click" />
                </StackPanel>
            </Grid>
        </Border>
        <ScrollViewer x:Name="scrollViewer" Grid.Row="1"    HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" >
            <Canvas x:Name="mainContainer" HorizontalAlignment="Left" VerticalAlignment="Top" MouseMove="SourceImage_MouseMove"  MouseDown="SourceImage_MouseDown" PreviewMouseUp="SourceImage_MouseUp" MouseUp="SourceImage_MouseUp">
                <Image x:Name="SourceImage" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"  />
                <Canvas x:Name="HouseInfoLayer" />
                <Canvas x:Name="LocationPointLayer" IsHitTestVisible="False"/>
                <!--<Polyline StrokeThickness="1" Stroke="Black"    Opacity="0.5">
                    <Polyline.Points>10,50 180,50 180,150 </Polyline.Points>
                </Polyline>-->
            </Canvas>
        </ScrollViewer>
    </Grid>
</Window>
src/RichCreator.Editor/Tools/MapEditor.xaml.cs
New file
@@ -0,0 +1,817 @@
using Emgu.CV;
using RichCreator.Utility;
using RichCreator.Utility.PathFindings;
using RichCreator.Utility.Structs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using ZTImage;
namespace RichCreator.Editor.Tools
{
    /// <summary>
    /// AStarTools.xaml 的交互逻辑
    /// </summary>
    public partial class MapEditor : Window
    {
        public MapEditor()
        {
            InitializeComponent();
        }
        // 寻路信息
        private HousePathInfo housePathInfo = null;
        private bool moveable = false;//可移动的
        private Line tempLine = null;
        private Polyline tempPolyline = null;
        // 当前图像
        private System.Drawing.Image image;
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
        }
        /// <summary>
        /// 加载图片
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OpenFromFile_Click(object sender, RoutedEventArgs e)
        {
            string imagePath = string.Empty;
            Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
            ofd.DefaultExt = ".jpg";
            ofd.Filter = "image file|*.jpg;*.png;";
            ofd.Multiselect = false;
            if (ofd.ShowDialog() == true)
            {
                imagePath = ofd.FileName;
            }
            else
            {
                return;
            }
            Mat source = CvInvoke.Imread(imagePath, Emgu.CV.CvEnum.ImreadModes.Color);
            this.image = source.Bitmap;
            SetImage();
        }
        /// <summary>
        /// 复制JSON
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CopyJSON_Click(object sender, RoutedEventArgs e)
        {
            string json = this.housePathInfo.ToJsonString();
            Clipboard.SetDataObject(json, true);
        }
        /// <summary>
        /// 从JSON创建
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CreateFromJSON_Click(object sender, RoutedEventArgs e)
        {
            //SerializeInput input = new SerializeInput();
            //if (input.ShowDialog() != true)
            //{
            //    return;
            //}
            //FindPathInfo pi = FindPathInfo.FromJsonString(input.ColorString);
            ////生成网格
            //this.rectWidth.Text = pi.Width.ToString();
            //this.rectHeight.Text = pi.Height.ToString();
            //GenericRect(pi.Width, pi.Height, pi.RowCount, pi.ColCount);
            ////生成顶点
            //for (int i = 0; i < pi.Vertexs.Count; i++)
            //{
            //    SetVertexUI(pi.Vertexs[i]);
            //}
            ////生成连线
            //for (int i = 0; i < pi.Edges.Count; i++)
            //{
            //    GenericEdge(pi.Edges[i].StartIndex);
            //    SetEdge(pi.Edges[i].EndIndex);
            //}
            //this.PositionOverflowLayer.Children.Clear();
            ////生成定位点
            //for (int i = 0; i < pi.Positions.Count; i++)
            //{
            //    AddLocationPoint(pi.Positions[i].X, pi.Positions[i].Y, pi.Positions[i].Parameter);
            //}
        }
        /// <summary>
        /// 清理定位点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClearPosition_Click(object sender, RoutedEventArgs e)
        {
            this.LocationPointLayer.Children.Clear();
            this.housePathInfo.ClearLocationPosiltion();
        }
        /// <summary>
        /// 鼠标按下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SourceImage_MouseDown(object sender, MouseButtonEventArgs e)
        {
            //是否添加障碍物
            OperateActionD op = (OperateActionD)(slOperate.SelectedIndex);
            Int32 number = TypeConverter.StringToInt(this.tagNumber.Text, 0);
            if (e.LeftButton == MouseButtonState.Released)
            {
                return;
            }
            Point point = GetPosition(e);
            if (op == OperateActionD.Obstacle)
            {
                //障碍物
            }
            else if (op == OperateActionD.LocationPoint)
            {
                //定位点
                ParametersPoint lp = new ParametersPoint(new ZTPoint((Int32)point.X, (Int32)point.Y), number);
                if (this.housePathInfo.AddLocationPosition(lp))
                {
                    Canvas lpControl = CreateLocationPointUI(lp);
                    this.LocationPointLayer.Children.Add(lpControl);
                }
            }
            else if (op == OperateActionD.FindPathPoint)
            {
                //寻路点
                ZTPoint fp = new ZTPoint((Int32)point.X, (Int32)point.Y);
                if (this.housePathInfo.AddFindPathPoint(fp))
                {
                    Canvas fpControl = CreateFindPathPointUI(fp);
                    this.HouseInfoLayer.Children.Add(fpControl);
                }
            }
            else if (op == OperateActionD.LoopLine)
            {
                //循环线
                ZTPoint llPoint = GetFindPathPoint(new ZTPoint((Int32)point.X,(Int32)point.Y));
                if (llPoint != ZTPoint.Empty)
                {
                    tempLine = CreateTempLoopLineUI(llPoint);
                    this.HouseInfoLayer.Children.Add(tempLine);
                    moveable = true;
                }
            }
            else if (op == OperateActionD.FindPathLine)
            {
                //寻路线
                ZTPoint fpPoint = GetFindPathPoint(new ZTPoint((Int32)point.X, (Int32)point.Y));
                if (fpPoint != ZTPoint.Empty)
                {
                    tempLine = CreateTempFindPathLineUI(fpPoint);
                    this.HouseInfoLayer.Children.Add(tempLine);
                    moveable = true;
                }
            }
        }
        /// <summary>
        /// 鼠标移动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SourceImage_MouseMove(object sender, MouseEventArgs e)
        {
            OperateActionD op = (OperateActionD)(slOperate.SelectedIndex);
            Point point = GetPosition(e);
            if (op == OperateActionD.LoopLine)
            {
                //巡逻线
                if (!moveable)
                {
                    return;
                }
                tempLine.X2 = point.X;
                tempLine.Y2 = point.Y;
            }
            else if (op == OperateActionD.FindPathLine)
            {
                //寻路线
                if (!moveable)
                {
                    return;
                }
                tempLine.X2 = point.X;
                tempLine.Y2 = point.Y;
            }
            else if (op == OperateActionD.Obstacle)
            {
                //障碍物线
                if (!moveable)
                {
                    return;
                }
                tempLine.X2 = point.X;
                tempLine.Y2 = point.Y;
            }
        }
        /// <summary>
        /// 鼠标提起
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SourceImage_MouseUp(object sender, MouseButtonEventArgs e)
        {
            OperateActionD op = (OperateActionD)(slOperate.SelectedIndex);
            Point point = GetPosition(e);
            if (op == OperateActionD.LoopLine)
            {
                //巡逻线
                if (!moveable)
                {
                    return;
                }
                moveable = false;
                if (tempLine == null)
                {
                    return;
                }
                ZTPoint startPoint = (ZTPoint)tempLine.Tag;
                ZTPoint centerPoint = GetFindPathPoint(new ZTPoint((Int32)point.X, (Int32)point.Y));
                if (centerPoint != ZTPoint.Empty)
                {
                    ZTLinePoint ll = new ZTLinePoint(startPoint, centerPoint);
                    if (this.housePathInfo.AddLoopLine(ll))
                    {
                        Line llline = CreateLoopLineUI(ll);
                        this.HouseInfoLayer.Children.Add(llline);
                    }
                }
                this.HouseInfoLayer.Children.Remove(tempLine);
                tempLine = null;
            }
            else if (op == OperateActionD.FindPathLine)
            {
                //寻路线
                if (!moveable)
                {
                    return;
                }
                moveable = false;
                if (tempLine == null)
                {
                    return;
                }
                ZTPoint startPoint = (ZTPoint)tempLine.Tag;
                ZTPoint centerPoint = GetFindPathPoint(new ZTPoint((Int32)point.X, (Int32)point.Y));
                if (centerPoint != ZTPoint.Empty)
                {
                    ZTLinePoint fp = new ZTLinePoint(startPoint, centerPoint);
                    if (this.housePathInfo.AddFindPathLine(fp))
                    {
                        Line fpline = CreateFindPathLineUI(fp);
                        this.HouseInfoLayer.Children.Add(fpline);
                    }
                }
                this.HouseInfoLayer.Children.Remove(tempLine);
                tempLine = null;
            }
            else if (op == OperateActionD.Obstacle)
            {
                //绘制障碍物
                //判断是否起点
                if (tempPolyline == null)
                {
                    //首次画
                    this.points.Add(point);
                    this.tempPolyline=CreateTempObstacleUI(point);
                    this.tempLine = CreateObstacleLineUI(new ZTPoint((Int32)point.X, (Int32)point.Y));
                    moveable = true;
                    this.HouseInfoLayer.Children.Add(this.tempPolyline);
                    this.HouseInfoLayer.Children.Add(this.tempLine);
                }
                else
                {
                    if (IsLastPoint(point))
                    {
                        //判断是否跟最后一个点重合,如果重合则不处理
                        return;
                    }
                    if (IsFirstPoint(point))
                    {
                        //到起点,完成,画折线,向houseinfo里添加障碍物
                        Polygon polygon = CreateObstacleUI();
                        this.HouseInfoLayer.Children.Add(polygon);
                        ZTPoint[] obstaclePoints = new ZTPoint[this.points.Count];
                        for (int i = 0; i < this.points.Count; i++)
                        {
                            obstaclePoints[i] = new ZTPoint((Int32)this.points[i].X, (Int32)this.points[i].Y);
                        }
                        this.housePathInfo.AddObstacle(new ZTPolygon(obstaclePoints));
                        this.HouseInfoLayer.Children.Remove(tempPolyline);
                        tempPolyline = null;
                        this.HouseInfoLayer.Children.Remove(tempLine);
                        tempLine = null;
                        this.points.Clear();
                        moveable = false;
                    }
                    else
                    {
                        //向points里添加障碍点,画折线,更新tempLine,
                        this.points.Add(point);
                        //画折线
                        this.tempPolyline.Points.Add(point);
                        //更新tempLine
                        tempLine.X1 = point.X;
                        tempLine.Y1 = point.Y;
                        tempLine.X2 = point.X;
                        tempLine.Y2 = point.Y;
                    }
                }
            }
        }
        /// <summary>
        /// 计算当前鼠标位置和颜色
        /// </summary>
        /// <param name="e"></param>
        /// <param name="point"></param>
        /// <param name="color"></param>
        /// <returns></returns>
        private Point GetPosition(MouseEventArgs e)
        {
            Point point = e.GetPosition(this.scrollViewer);
            Int32 x = (Int32)Math.Round(this.scrollViewer.HorizontalOffset + point.X);
            Int32 y = (Int32)Math.Round(this.scrollViewer.VerticalOffset + point.Y);
            return new Point(x, y);
        }
        private List<Point> points = new List<Point>();
        /// <summary>
        /// 是否第一个点
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        private bool IsFirstPoint(Point point)
        {
            Point temp =this.points[0];
            if (Math.Abs(temp.X - point.X) <= 10 && Math.Abs(temp.Y - point.Y) <= 10)
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 是否最后一个点
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        private bool IsLastPoint(Point point)
        {
            Point temp = this.points[this.points.Count-1];
            if (Math.Abs(temp.X - point.X) <= 10 && Math.Abs(temp.Y - point.Y) <= 10)
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 操作类型
        /// </summary>
        public enum OperateActionD
        {
            Obstacle = 0,//障碍物
            LocationPoint,//定位点
            FindPathPoint,//寻路点
            LoopLine,//循环线
            FindPathLine,//寻路线
        }
        #region createUI
        /// <summary>
        /// 设置图像
        /// </summary>
        /// <param name="control"></param>
        /// <param name="image"></param>
        private void SetImage()
        {
            BitmapImage t = ImageHelper.BitmapToImageSource(image);
            this.SourceImage.Source = t;
            mainContainer.Width = image.Width;
            mainContainer.Height = image.Height;
            this.housePathInfo = new HousePathInfo();
        }
        /// <summary>
        /// 创建定位点UI
        /// 外方内圆
        /// </summary>
        private Canvas CreateLocationPointUI(ParametersPoint point)
        {
            //<Canvas Canvas.Left="point.x" Canvas.Top="point.y">
            //    <Rectangle Canvas.Left="-10" Canvas.Top="-10" Width="20" Height="20"  Stroke="Red" StrokeThickness="1"   />
            //    <Ellipse Canvas.Left="-2" Canvas.Top="-2" Width="4" Height="4" Fill="Red" StrokeThickness="1"  />
            //</Canvas>
            Canvas main = new Canvas();
            main.Tag = point;
            Canvas.SetLeft(main,point.Point.X);
            Canvas.SetTop(main, point.Point.Y);
            Rectangle rect = new Rectangle();
            Canvas.SetLeft(rect, -10);
            Canvas.SetTop(rect, -10);
            rect.Width = 20;
            rect.Height = 20;
            rect.Stroke = new SolidColorBrush(Colors.Red);
            rect.StrokeThickness = 1;
            rect.Fill = new SolidColorBrush(Colors.Red);
            rect.Opacity = 0.5f;
            main.Children.Add(rect);
            Ellipse elli = new Ellipse();
            Canvas.SetLeft(elli, -2);
            Canvas.SetTop(elli, -2);
            elli.Width = 4;
            elli.Height = 4;
            elli.Stroke = new SolidColorBrush(Colors.Black);
            elli.StrokeThickness = 1;
            elli.Fill = new SolidColorBrush(Colors.Black);
            main.Children.Add(elli);
            TextBlock tb = new TextBlock();
            tb.Text = point.Parameter.ToString();
            tb.FontSize = 9;
            main.Children.Add(tb);
            return main;
        }
        /// <summary>
        /// 创建寻路点UI
        /// </summary>
        private Canvas CreateFindPathPointUI(ZTPoint findPathPoint)
        {
            //<Canvas Canvas.Left="point.x" Canvas.Top="point.y">
            //    <Ellipse Canvas.Left="-10" Canvas.Top="-10" Width="20" Height="20"  Stroke="Red" StrokeThickness="1"  HorizontalAlignment="Center" VerticalAlignment="Center" />
            //    <Rectangle Canvas.Left="-2" Canvas.Top="-2" Width="4" Height="4" Fill="Red" StrokeThickness="1"  HorizontalAlignment="Center" VerticalAlignment="Center" />
            //</Canvas>
            Canvas main = new Canvas();
            main.Tag = findPathPoint;
            main.MouseRightButtonUp += FindPathPoint_MouseRightButtonUp;
            Canvas.SetLeft(main, findPathPoint.X);
            Canvas.SetTop(main, findPathPoint.Y);
            Ellipse elli = new Ellipse();
            Canvas.SetLeft(elli, -10);
            Canvas.SetTop(elli, -10);
            elli.Width = 20;
            elli.Height = 20;
            elli.Stroke = new SolidColorBrush(Colors.Red);
            elli.StrokeThickness = 1;
            elli.Fill = new SolidColorBrush(Colors.Red);
            elli.Opacity = 0.5f;
            main.Children.Add(elli);
            Rectangle rect = new Rectangle();
            Canvas.SetLeft(rect, -2);
            Canvas.SetTop(rect, -2);
            rect.Width = 4;
            rect.Height = 4;
            rect.Stroke = new SolidColorBrush(Colors.Black);
            rect.StrokeThickness = 1;
            rect.Fill = new SolidColorBrush(Colors.Black);
            rect.StrokeThickness = 1;
            main.Children.Add(rect);
            return main;
        }
        /// <summary>
        /// 寻路点右击
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FindPathPoint_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            Canvas c = sender as Canvas;
            if (c == null)
            {
                return;
            }
            ZTPoint fp = default(ZTPoint);
            try
            {
                fp = (ZTPoint)c.Tag;
            }
            catch
            {
                return;
            }
            if (this.housePathInfo.RemoveFindPathPoint(fp))
            {
                this.HouseInfoLayer.Children.Remove(c);
            }
        }
        /// <summary>
        /// 创建巡逻线UI
        /// </summary>
        private Line CreateLoopLineUI(ZTLinePoint linePoint)
        {
            Line edgeLine = new Line();
            edgeLine.Tag = linePoint;
            edgeLine.MouseRightButtonUp += LoopLine_MouseRightButtonUp;
            edgeLine.Stroke = new SolidColorBrush(Colors.Red);
            edgeLine.StrokeThickness = 6;
            edgeLine.X1 = linePoint.X1;
            edgeLine.Y1 = linePoint.Y1;
            edgeLine.X2 = linePoint.X2;
            edgeLine.Y2 = linePoint.Y2;
            edgeLine.StrokeDashArray = new DoubleCollection() { 2, 3 };
            edgeLine.StrokeDashCap = PenLineCap.Triangle;
            edgeLine.StrokeEndLineCap = PenLineCap.Square;
            edgeLine.StrokeStartLineCap = PenLineCap.Round;
            return edgeLine;
        }
        /// <summary>
        /// 巡逻线右击
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void LoopLine_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            Line c = sender as Line;
            if (c == null)
            {
                return;
            }
            ZTLinePoint fp = default(ZTLinePoint);
            try
            {
                fp = (ZTLinePoint)c.Tag;
            }
            catch
            {
                return;
            }
            if (this.housePathInfo.RemoveLoopLine(fp))
            {
                this.HouseInfoLayer.Children.Remove(c);
            }
        }
        /// <summary>
        /// 创建临时巡逻线UI
        /// </summary>
        /// <param name="linePoint"></param>
        /// <returns></returns>
        private Line CreateTempLoopLineUI(ZTPoint point)
        {
            Line edgeLine = new Line();
            edgeLine.Tag = point;
            edgeLine.Stroke = new SolidColorBrush(Colors.Red);
            edgeLine.StrokeThickness = 3;
            edgeLine.X1 = point.X;
            edgeLine.Y1 = point.Y;
            edgeLine.X2 = point.X;
            edgeLine.Y2 = point.Y;
            edgeLine.StrokeDashArray = new DoubleCollection() { 2, 3 };
            edgeLine.StrokeDashCap = PenLineCap.Triangle;
            edgeLine.StrokeEndLineCap = PenLineCap.Square;
            edgeLine.StrokeStartLineCap = PenLineCap.Round;
            return edgeLine;
        }
        /// <summary>
        /// 创建寻路线UI
        /// </summary>
        private Line CreateFindPathLineUI(ZTLinePoint linePoint)
        {
            Line edgeLine = new Line();
            edgeLine.Tag = linePoint;
            edgeLine.MouseRightButtonUp += FindPathLine_MouseRightButtonUp; ;
            edgeLine.Stroke = new SolidColorBrush(Colors.Red);
            edgeLine.StrokeThickness = 3;
            edgeLine.X1 = linePoint.X1;
            edgeLine.Y1 = linePoint.Y1;
            edgeLine.X2 = linePoint.X2;
            edgeLine.Y2 = linePoint.Y2;
            return edgeLine;
        }
        /// <summary>
        /// 寻路线右键
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FindPathLine_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            Line c = sender as Line;
            if (c == null)
            {
                return;
            }
            ZTLinePoint fp = default(ZTLinePoint);
            try
            {
                fp = (ZTLinePoint)c.Tag;
            }
            catch
            {
                return;
            }
            if (this.housePathInfo.RemoveFindPathLine(fp))
            {
                this.HouseInfoLayer.Children.Remove(c);
            }
        }
        /// <summary>
        /// 创建临时寻路线UI
        /// </summary>
        /// <param name="linePoint"></param>
        /// <returns></returns>
        private Line CreateTempFindPathLineUI(ZTPoint point)
        {
            Line edgeLine = new Line();
            edgeLine.Tag = point;
            edgeLine.Stroke = new SolidColorBrush(Colors.Red);
            edgeLine.StrokeThickness = 3;
            edgeLine.X1 = point.X;
            edgeLine.Y1 = point.Y;
            edgeLine.X2 = point.X;
            edgeLine.Y2 = point.Y;
            return edgeLine;
        }
        /// <summary>
        /// 创建临时障碍物UI
        /// </summary>
        /// <returns></returns>
        private Polyline CreateTempObstacleUI(Point point)
        {
            //<!--<Polygon StrokeThickness="1" Stroke="Black"    Opacity="0.5">
            //        <Polygon.Points>10,50 180,50 180,150 </Polygon.Points>
            //    </Polygon>-->
            Polyline polyline = new Polyline();
            polyline.StrokeThickness = 1;
            polyline.Stroke = new SolidColorBrush(Colors.Black);
            polyline.Opacity = 0.5f;
            polyline.Points.Add(point);
            return polyline;
        }
        /// <summary>
        /// 创建障碍物UI
        /// </summary>
        /// <returns></returns>
        private Polygon CreateObstacleUI()
        {
            //<!--<Polygon StrokeThickness="1" Stroke="Black"    Opacity="0.5">
            //        <Polygon.Points>10,50 180,50 180,150 </Polygon.Points>
            //    </Polygon>-->
            Polygon polygon = new Polygon();
            polygon.StrokeThickness = 1;
            polygon.Stroke = new SolidColorBrush(Colors.Black);
            polygon.Fill= new SolidColorBrush(Colors.Black);
            polygon.Opacity = 0.7f;
            for (int i = 0; i < this.points.Count; i++)
            {
                polygon.Points.Add(this.points[i]);
            }
            return polygon;
        }
        /// <summary>
        /// 创建临时障碍物线UI
        /// </summary>
        /// <param name="linePoint"></param>
        /// <returns></returns>
        private Line CreateObstacleLineUI(ZTPoint point)
        {
            Line edgeLine = new Line();
            edgeLine.Tag = point;
            edgeLine.Stroke = new SolidColorBrush(Colors.Black);
            edgeLine.StrokeThickness = 1;
            edgeLine.X1 = point.X;
            edgeLine.Y1 = point.Y;
            edgeLine.X2 = point.X;
            edgeLine.Y2 = point.Y;
            return edgeLine;
        }
        /// <summary>
        /// 获取当前位置点
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        private ZTPoint GetFindPathPoint(ZTPoint point)
        {
            ZTPoint temp = ZTPoint.Empty;
            for (int i = 0; i < this.housePathInfo.FindPathPoints.Count; i++)
            {
                temp = this.housePathInfo.FindPathPoints[i];
                if (Math.Abs(temp.X - point.X) <= 10 && Math.Abs(temp.Y - point.Y) <= 10)
                {
                    return temp;
                }
            }
            return default(ZTPoint);
        }
        #endregion
        #region Tools
        //private bool PointInRang(Point)
        #endregion
    }
}
src/RichCreator.Editor/Tools/MapEditor_old.xaml
File was renamed from src/RichCreator.Editor/Tools/DijkstraTools.xaml
@@ -1,12 +1,12 @@
<Window x:Class="RichCreator.Editor.Tools.DijkstraTools"
<Window x:Class="RichCreator.Editor.Tools.MapEditor"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:RichCreator.Editor.Tools"
        mc:Ignorable="d"
        Title="AStarFindingTools" Height="720" Width="1280">
        Loaded="Window_Loaded"
        Title="地图编辑器" Height="720" Width="1280">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
@@ -66,6 +66,12 @@
                        <TextBlock Text="(128,334)" HorizontalAlignment="Left"/>
                    </StackPanel>
                </Border>-->
                <!--<Polygon StrokeThickness="1" Stroke="Black"  Fill="Red" >
                    <Polygon.Points>10,50 180,50 180,150 10,150</Polygon.Points>
                </Polygon>-->
            </Canvas>
        </ScrollViewer>
    </Grid>
src/RichCreator.Editor/Tools/MapEditor_old.xaml.cs
File was renamed from src/RichCreator.Editor/Tools/DijkstraTools.xaml.cs
@@ -22,9 +22,9 @@
    /// <summary>
    /// AStarTools.xaml 的交互逻辑
    /// </summary>
    public partial class DijkstraTools : Window
    public partial class MapEditor : Window
    {
        public DijkstraTools()
        public MapEditor()
        {
            InitializeComponent();
        }
@@ -67,7 +67,22 @@
            this.image = source.Bitmap;
            SetImage(this.SourceImage);
        }
        private Polygon myPolygon = null;
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Polygon p = new Polygon();
            p.Stroke = Brushes.Black;
            p.Fill = Brushes.LightBlue;
            p.StrokeThickness = 5;
            p.HorizontalAlignment = HorizontalAlignment.Left;
            p.VerticalAlignment = VerticalAlignment.Center;
            p.Points = new System.Windows.Media.PointCollection() { new Point(10, 10), new Point(100, 100), new Point(200, 200) };
            this.mainContainer.Children.Add(p);
        }
        /// <summary>
        /// 设置图像
        /// </summary>
@@ -562,8 +577,7 @@
            {
                AddLocationPoint(pi.Positions[i].X, pi.Positions[i].Y, pi.Positions[i].Parameter);
            }
        }
    }
}
src/RichCreator.Utility/CV/ChannelCVHelper.cs
@@ -112,9 +112,9 @@
        /// <param name="confirmButtonPoint"></param>
        /// <param name="gameRect"></param>
        /// <returns></returns>
        public static bool HasConnectIsVaildWindow(out ZTPoint confirmButtonPoint, ZTRectangle gameRect)
        public static bool HasConnectIsVaildWindow(out Structs.ZTPoint confirmButtonPoint, ZTRectangle gameRect)
        {
            confirmButtonPoint = ZTPoint.Empty;
            confirmButtonPoint = Structs.ZTPoint.Empty;
            ZTRectangle tempRect = ZTRectangle.Empty;
            if (!CVHelper.RectExistsArray(out tempRect, gameRect, DisconnectionWhiteText))
            {
@@ -124,7 +124,7 @@
                }
            }
            confirmButtonPoint = new ZTPoint(tempRect.GetCenterPoint().X, tempRect.End.Y);
            confirmButtonPoint = new Structs.ZTPoint(tempRect.GetCenterPoint().X, tempRect.End.Y);
            return true;
        }
    }
src/RichCreator.Utility/CV/DnfCVHelper.cs
@@ -68,7 +68,7 @@
        public static bool IsInSaiLiYaHouse(ZTRectangle gameRect)
        {
            ZTRectangle mailText = ZTRectangle.Empty;
            ZTPoint limitPoint = gameRect.GetRatioPoint(0.667f);
            Structs.ZTPoint limitPoint = gameRect.GetRatioPoint(0.667f);
            ZTRectangle limit = new ZTRectangle(limitPoint.X, gameRect.Start.Y, gameRect.End.X, gameRect.End.Y);
            //截图
            System.Drawing.Bitmap bitmap = ScreenCapture.Instance.CaptureScreen();
@@ -374,28 +374,28 @@
        //min:(0,0.,0.0352941192686558),max:(0.,0.,0.0980392172932625)
        private static ZTHsvFloatColor equipmentColorMin = new ZTHsvFloatColor(0,0, 0);
        private static ZTHsvFloatColor equipmentColorMax = new ZTHsvFloatColor(1, 0.7827f, 0.1099f);
        private static ZTPoint[] equipmentComparePositionss;
        private static Structs.ZTPoint[] equipmentComparePositionss;
        /// <summary>
        /// 获取有装备的所有点,只便利前两行
        /// </summary>
        /// <param name="startPoint"></param>
        /// <returns></returns>
        public static List<Int32> GetEquipmentIndexs(ZTPoint startPoint)
        public static List<Int32> GetEquipmentIndexs(Structs.ZTPoint startPoint)
        {
            Image<Rgb, byte> image = ScreenCapture.Instance.CaptureScreenReturnImage();
            return GetEquipmentIndexs(image, startPoint);
        }
        public static List<Int32> GetEquipmentIndexs(Image<Rgb, byte> image,ZTPoint startPoint)
        public static List<Int32> GetEquipmentIndexs(Image<Rgb, byte> image, Structs.ZTPoint startPoint)
        {
            if (equipmentComparePositionss == null)
            {
                equipmentComparePositionss = new ZTPoint[15 * 15];
                equipmentComparePositionss = new Structs.ZTPoint[15 * 15];
                for (int y = 0; y < 15; y++)
                {
                    for (int x = 0; x < 15; x++)
                    {
                        equipmentComparePositionss[y * 15 + x] = new ZTPoint(x, y);
                        equipmentComparePositionss[y * 15 + x] = new Structs.ZTPoint(x, y);
                    }
                }
            }
@@ -441,11 +441,11 @@
            if (rects.Count <= 0)
            {
                return ZTPoint.Empty;
                return Structs.ZTPoint.Empty;
            }
            //主角位置
            ZTPoint rolePosition = gameRect.Start + new ZTPoint(rects[0].Start.X + rolePositionOffset.Width, rects[0].Start.Y + rolePositionOffset.Height);
            Structs.ZTPoint rolePosition = gameRect.Start + new Structs.ZTPoint(rects[0].Start.X + rolePositionOffset.Width, rects[0].Start.Y + rolePositionOffset.Height);
            return rolePosition;
        }
@@ -474,11 +474,11 @@
        /// <param name="image"></param>
        /// <param name="gameRect"></param>
        /// <returns></returns>
        public static List<ZTPoint> GetThingItemPoints(Image<Rgb, byte> image, ZTRectangle gameRect)
        public static List<Structs.ZTPoint> GetThingItemPoints(Image<Rgb, byte> image, ZTRectangle gameRect)
        {
            List<ZTLine> lines = CVHelper.FindLines(image, xLineMin,gameRect, Orientation.Horizontal, min, max);
            List<ZTLine> filterLines = new List<ZTLine>();
            List<ZTPoint> points = new List<ZTPoint>();
            List<Structs.ZTPoint> points = new List<Structs.ZTPoint>();
            Func<ZTLine, bool> existsLines = (line) =>
            {
                for (int i = 0; i < filterLines.Count; i++)
@@ -530,7 +530,7 @@
                }
                
                filterLines.Add(line);
                points.Add(new ZTPoint(line.X + line.Length / 2, line.Y + thingItemYOffset));
                points.Add(new Structs.ZTPoint(line.X + line.Length / 2, line.Y + thingItemYOffset));
            }
            return points;
        }
@@ -595,10 +595,10 @@
            number = 0;
            byte[,,] datas = rangeImage.Data;
            bool one = false, two = false, four = false, eight = false;
            ZTPoint center = locationPointRect.GetCenterPoint();
            Structs.ZTPoint center = locationPointRect.GetCenterPoint();
            //格1
            ZTPoint lefttop = center.Add(-11);
            Structs.ZTPoint lefttop = center.Add(-11);
            if (!BlockOf6x6IsColor(datas, lefttop, black))
            {
                if (!BlockOf6x6IsColor(datas, lefttop, white))
@@ -615,7 +615,7 @@
                one = true;
            }
            //格2
            ZTPoint righttop = center.Add(new ZTPoint(5,-11));
            Structs.ZTPoint righttop = center.Add(new Structs.ZTPoint(5,-11));
            if (!BlockOf6x6IsColor(datas, righttop, black))
            {
                if (!BlockOf6x6IsColor(datas, righttop, white))
@@ -633,7 +633,7 @@
            }
            //格4
            ZTPoint leftbottom = center.Add(new ZTPoint(-11, 5));
            Structs.ZTPoint leftbottom = center.Add(new Structs.ZTPoint(-11, 5));
            if (!BlockOf6x6IsColor(datas, leftbottom, black))
            {
                if (!BlockOf6x6IsColor(datas, leftbottom, white))
@@ -647,7 +647,7 @@
            }
            //格8
            ZTPoint rightbottom = center.Add(5);
            Structs.ZTPoint rightbottom = center.Add(5);
            if (!BlockOf6x6IsColor(datas, rightbottom, black))
            {
                if (!BlockOf6x6IsColor(datas, rightbottom, white))
@@ -675,7 +675,7 @@
        /// <param name="starty"></param>
        /// <param name="color"></param>
        /// <returns></returns>
        private static bool BlockOf6x6IsColor(byte[,,] datas,ZTPoint start, byte color)
        private static bool BlockOf6x6IsColor(byte[,,] datas, Structs.ZTPoint start, byte color)
        {
            for (int y = start.Y; y < start.Y + 6; y++)
            {
src/RichCreator.Utility/CV/GroupCVHelper.cs
@@ -215,11 +215,11 @@
        /// <param name="noPoint"></param>
        /// <param name="limitRect"></param>
        /// <returns></returns>
        public static bool FindYaoqingZuduiWindow(out ZTPoint yesPoint,out ZTPoint noPoint, ZTRectangle limitRect)
        public static bool FindYaoqingZuduiWindow(out Structs.ZTPoint yesPoint,out Structs.ZTPoint noPoint, ZTRectangle limitRect)
        {
            ZTRectangle textRect = ZTRectangle.Empty;
            yesPoint = ZTPoint.Empty;
            noPoint = ZTPoint.Empty;
            yesPoint = Structs.ZTPoint.Empty;
            noPoint = Structs.ZTPoint.Empty;
            Image<Rgb, byte> image = ScreenCapture.Instance.CaptureScreenReturnImage();
            if (!CVHelper.FindColorArray(out textRect, image, YaoqingZuduiWindowTitle, limitRect))
@@ -233,9 +233,9 @@
                return false;
            }
            ZTPoint center = textRect.GetCenterPoint();
            yesPoint = new ZTPoint(center.X - 28, center.Y + 186);
            noPoint = new ZTPoint(center.X + 28, center.Y + 186);
            Structs.ZTPoint center = textRect.GetCenterPoint();
            yesPoint = new Structs.ZTPoint(center.X - 28, center.Y + 186);
            noPoint = new Structs.ZTPoint(center.X + 28, center.Y + 186);
            return true;
        }
src/RichCreator.Utility/CV/LindongCVHelper.cs
@@ -35,11 +35,11 @@
        /// <summary>
        /// 小方格主角偏移
        /// </summary>
        private static ZTPoint[] houseRoleBlockOffset = new ZTPoint[] {
            new ZTPoint(0,0),
            new ZTPoint(1,0),
            new ZTPoint(0,1),
            new ZTPoint(1,1)
        private static Structs.ZTPoint[] houseRoleBlockOffset = new Structs.ZTPoint[] {
            new Structs.ZTPoint(0,0),
            new Structs.ZTPoint(1,0),
            new Structs.ZTPoint(0,1),
            new Structs.ZTPoint(1,1)
        };
        
        /// <summary>
@@ -49,7 +49,7 @@
        /// <param name="minMapStart"></param>
        /// <param name="offset"></param>
        /// <returns></returns>
        public static bool GetCurrentHouseIndex(out Int32 houseIndex, Image<Rgb, byte> image, ZTPoint minMapStart)
        public static bool GetCurrentHouseIndex(out Int32 houseIndex, Image<Rgb, byte> image, Structs.ZTPoint minMapStart)
        {
            houseIndex = -1;
            Int32 mainMonsterHouseIndex = -1;            
@@ -62,7 +62,7 @@
                Int32 x = minMapStart.X + col * 18;
                Int32 y = minMapStart.Y + row * 18;
                ZTPoint position = ZTPoint.Empty;
                Structs.ZTPoint position = Structs.ZTPoint.Empty;
                ZTRectangle limit = new ZTRectangle(x, y, x + 17, y + 17);
                if (CVHelper.FindColorBlock(out position, image, limit, minMinimapRoleColor, maxMinimapRoleColor, houseRoleBlockOffset))
                {
@@ -110,18 +110,18 @@
        /// <summary>
        /// 小方格色块偏移
        /// </summary>
        private static ZTPoint[] houseColorBlockOffset = new ZTPoint[] {
            new ZTPoint(2,2),
            new ZTPoint(2,3),
            new ZTPoint(15,14),
            new ZTPoint(15,15),
        private static Structs.ZTPoint[] houseColorBlockOffset = new Structs.ZTPoint[] {
            new Structs.ZTPoint(2,2),
            new Structs.ZTPoint(2,3),
            new Structs.ZTPoint(15,14),
            new Structs.ZTPoint(15,15),
        };
        /// <summary>
        /// 房间是否开放
        /// </summary>
        /// <param name="houseIndex"></param>
        /// <returns></returns>
        public static bool HouseIsOpen(Image<Rgb, byte> image, ZTPoint minMapStart, Int32 houseIndex)
        public static bool HouseIsOpen(Image<Rgb, byte> image, Structs.ZTPoint minMapStart, Int32 houseIndex)
        {
            //第一块距上边15px,距左边1px
            Int32 row = houseIndex / 4;
@@ -154,10 +154,10 @@
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        public static ZTPoint[] FindMonster(Image<Hsv, byte> image,ZTRectangle gameRect)
        public static Structs.ZTPoint[] FindMonster(Image<Hsv, byte> image,ZTRectangle gameRect)
        {
            List<ZTRectangle> rects = CVHelper.FindBlocks(image, minMonsterHsv, maxMonsterHsv, monsterBlockSize);
            ZTPoint[] monsterPoints = new ZTPoint[rects.Count];
            Structs.ZTPoint[] monsterPoints = new Structs.ZTPoint[rects.Count];
            for (int i = 0; i < rects.Count; i++)
            {
                monsterPoints[i] = rects[i].GetCenterPoint().Add(gameRect.Start);
@@ -225,10 +225,10 @@
                {
                    continue;
                }
                ZTPoint doorPosition = ZTPoint.Empty;
                Structs.ZTPoint doorPosition = Structs.ZTPoint.Empty;
                for (int i = 0; i < doors.Count; i++)
                {
                    doorPosition = new ZTPoint(doors[i].Start.X + (doors[i].End.X - doors[i].Start.X) / 2, doors[i].Start.Y + (doors[i].End.Y - doors[i].Start.Y) / 2);
                    doorPosition = new Structs.ZTPoint(doors[i].Start.X + (doors[i].End.X - doors[i].Start.X) / 2, doors[i].Start.Y + (doors[i].End.Y - doors[i].Start.Y) / 2);
                    if (doorPosition.X >= limitRect.Start.X &&
                        doorPosition.X <= limitRect.End.X &&
                        doorPosition.Y >= limitRect.Start.Y &&
@@ -239,7 +239,7 @@
                }
            }
            return ZTPoint.Empty;
            return Structs.ZTPoint.Empty;
        }
        /// <summary>
src/RichCreator.Utility/CV/SkillCVHelper.cs
@@ -114,7 +114,11 @@
            return true;
        }
        private static ColorArray notificationText = ColorArray.FromHsvFloatString(0.002f, 0.002f, 0.002f, "661,316,255,255,255$658,306,255,255,255$658,308,255,255,255$657,309,255,255,255$657,310,255,255,255$660,311,255,255,255$660,310,255,255,255$659,313,255,255,255$659,312,255,255,255$656,316,255,255,255$657,316,255,255,255$658,316,255,255,255$659,316,255,255,255$660,316,255,255,255$664,316,255,255,255$668,316,255,255,255$668,317,255,255,255$668,313,255,255,255$676,313,255,255,255$676,317,255,255,255$676,311,255,255,255$672,311,255,255,255$668,311,255,255,255$668,309,255,255,255$669,308,255,255,255$672,306,255,255,255$672,308,255,255,255$672,310,255,255,255$673,308,255,255,255$675,308,255,255,255$676,308,255,255,255");
        /// <summary>
        /// 公告文字
        /// </summary>
        private static ColorArray notificationGrayText = ColorArray.FromHsvFloatString(0.002f, 0.002f, 0.002f, "645,296,170,170,170$630,291,0,0,0$631,291,170,170,170$632,291,0,0,0$634,291,0,0,0$635,291,170,170,170$636,291,0,0,0$641,291,0,0,0$644,291,0,0,0$645,291,170,170,170$646,291,0,0,0$651,296,0,0,0$650,296,170,170,170$640,296,170,170,170$639,296,0,0,0$638,296,0,0,0$637,296,170,170,170$636,296,0,0,0$634,296,0,0,0$633,296,170,170,170$632,296,0,0,0$630,296,0,0,0$629,296,170,170,170$628,296,0,0,0$628,301,0,0,0$629,301,170,170,170$633,301,170,170,170$637,301,170,170,170$638,301,0,0,0$640,301,0,0,0$641,301,170,170,170$646,301,170,170,170$648,301,170,170,170$649,301,170,170,170$650,301,0,0,0$645,301,170,170,170$645,300,0,0,0$645,299,0,0,0$645,298,170,170,170$645,297,0,0,0$645,296,170,170,170$645,293,170,170,170$645,291,170,170,170$645,290,0,0,0$633,294,0,0,0$633,295,170,170,170$633,296,170,170,170$633,297,0,0,0$633,300,0,0,0$633,302,0,0,0$633,301,170,170,170");
        private static ColorArray notificationWhiteText = ColorArray.FromHsvFloatString(0.002f, 0.002f, 0.002f, "645,296,255,255,255$630,291,0,0,0$631,291,255,255,255$632,291,0,0,0$634,291,0,0,0$635,291,255,255,255$636,291,0,0,0$641,291,0,0,0$644,291,0,0,0$645,291,255,255,255$646,291,0,0,0$651,296,0,0,0$650,296,255,255,255$640,296,255,255,255$639,296,0,0,0$638,296,0,0,0$637,296,255,255,255$636,296,0,0,0$634,296,0,0,0$633,296,255,255,255$632,296,0,0,0$630,296,0,0,0$629,296,255,255,255$628,296,0,0,0$628,301,0,0,0$629,301,255,255,255$634,301,255,255,255$637,301,255,255,255$638,301,0,0,0$640,301,0,0,0$641,301,255,255,255$647,301,255,255,255$649,301,255,255,255$650,301,0,0,0$645,302,0,0,0$645,301,255,255,255$645,300,0,0,0$645,299,0,0,0$645,298,255,255,255$645,297,0,0,0$645,296,255,255,255$645,293,255,255,255$645,291,255,255,255$645,290,0,0,0$633,294,0,0,0$633,295,255,255,255$633,296,255,255,255$633,300,0,0,0$633,301,255,255,255$633,302,0,0,0");
        /// <summary>
        /// 是否存在公告文本
@@ -125,9 +129,12 @@
        {
            Image<Rgb, byte> image = ScreenCapture.Instance.CaptureScreenReturnImage();
            
            if (!CVHelper.FindColorArray(out notificationRect, image, notificationText, gameRect))
            if (!CVHelper.FindColorArray(out notificationRect, image, notificationGrayText, gameRect))
            {
                return false;
                if (!CVHelper.FindColorArray(out notificationRect, image, notificationWhiteText, gameRect))
                {
                    return false;
                }
            }
            return true;
        }
@@ -258,13 +265,13 @@
        /// <summary>
        /// 已学技能文字
        /// 技能栏后面的“已学”文字
        /// 白色
        /// 灰色
        /// </summary>
        private static ColorArray[] studayedText = new ColorArray[] {
            ColorArray.FromHsvFloatString(0.002f,0.002f,0.002f,"739,471,255,255,255$739,468,255,255,255$740,468,255,255,255$742,468,255,255,255$743,468,255,255,255$745,468,255,255,255$746,468,255,255,255$747,468,255,255,255$747,469,255,255,255$747,472,255,255,255$747,473,255,255,255$746,473,255,255,255$739,473,255,255,255$739,477,255,255,255$739,476,255,255,255$740,478,255,255,255$741,478,255,255,255$747,478,255,255,255$748,478,255,255,255$748,477,255,255,255$748,476,255,255,255$753,478,255,255,255$755,478,255,255,255$755,474,255,255,255$760,474,255,255,255$750,474,255,255,255$756,473,255,255,255$757,472,255,255,255$758,471,255,255,255$752,471,255,255,255$750,470,255,255,255$750,469,255,255,255$751,469,255,255,255$753,469,255,255,255$755,469,255,255,255$757,469,255,255,255$760,469,255,255,255$760,470,255,255,255"),
            ColorArray.FromHsvFloatString(0.002f,0.002f,0.002f,"739,476,170,170,170$739,468,170,170,170$740,468,170,170,170$743,468,170,170,170$744,468,170,170,170$747,468,170,170,170$747,469,170,170,170$747,472,170,170,170$747,473,170,170,170$746,473,170,170,170$742,473,170,170,170$740,473,170,170,170$739,473,170,170,170$739,472,170,170,170$739,471,170,170,170$739,477,170,170,170$740,478,170,170,170$741,478,170,170,170$744,478,170,170,170$748,478,170,170,170$748,477,170,170,170$748,476,170,170,170$753,478,170,170,170$754,478,170,170,170$755,478,170,170,170$755,477,170,170,170$755,474,170,170,170$750,474,170,170,170$751,474,170,170,170$760,474,170,170,170$759,474,170,170,170$756,473,170,170,170$757,472,170,170,170$758,471,170,170,170$756,471,170,170,170$752,471,170,170,170$750,470,170,170,170$750,469,170,170,170$751,469,170,170,170$757,469,170,170,170$759,469,170,170,170$760,469,170,170,170$760,470,170,170,170"),
            ColorArray.FromHsvFloatString(0.002f,0.002f,0.002f,"710,457,0,0,0$692,457,0,0,0$693,457,255,255,255$696,457,255,255,255$698,457,255,255,255$700,457,255,255,255$701,457,255,255,255$702,457,0,0,0$705,457,0,0,0$706,457,255,255,255$707,457,0,0,0$708,457,0,0,0$709,457,255,255,255$711,457,0,0,0$712,457,255,255,255$713,457,0,0,0$713,460,0,0,0$712,460,255,255,255$709,460,255,255,255$706,460,255,255,255$705,460,0,0,0$702,460,0,0,0$701,460,255,255,255$700,460,0,0,0$694,460,0,0,0$693,460,255,255,255$692,460,0,0,0$692,462,0,0,0$693,462,255,255,255$697,462,255,255,255$701,462,255,255,255$702,462,0,0,0$709,462,0,0,0$710,462,255,255,255$711,462,0,0,0$710,465,0,0,0$709,465,255,255,255$708,465,0,0,0$703,465,0,0,0$702,465,255,255,255$701,465,0,0,0$694,465,0,0,0$693,465,255,255,255$692,465,0,0,0"),//白色
            ColorArray.FromHsvFloatString(0.002f,0.002f,0.002f,"712,457,170,170,170$692,457,0,0,0$693,457,170,170,170$696,457,170,170,170$698,457,170,170,170$701,457,170,170,170$702,457,0,0,0$705,457,0,0,0$706,457,170,170,170$707,457,0,0,0$708,457,0,0,0$709,457,170,170,170$710,457,0,0,0$711,457,0,0,0$713,457,0,0,0$715,459,0,0,0$714,459,170,170,170$713,459,0,0,0$705,459,0,0,0$704,459,170,170,170$703,459,0,0,0$702,459,0,0,0$701,459,170,170,170$700,459,0,0,0$693,467,0,0,0$694,467,170,170,170$697,467,170,170,170$699,467,170,170,170$702,467,170,170,170$703,467,0,0,0$706,467,0,0,0$707,467,170,170,170$708,467,170,170,170$709,467,170,170,170$710,467,0,0,0$708,468,0,0,0$708,467,170,170,170$708,466,0,0,0$708,464,0,0,0$708,463,170,170,170$708,461,0,0,0$708,460,170,170,170$708,459,0,0,0$708,458,170,170,170$697,456,0,0,0$697,457,170,170,170$697,458,0,0,0$697,461,0,0,0$697,462,170,170,170$697,463,0,0,0$697,466,0,0,0$697,467,170,170,170$697,468,0,0,0"),
            
        };
        /// <summary>
src/RichCreator.Utility/Captures/BitBltCapture.cs
@@ -42,7 +42,6 @@
        /// <returns></returns>
        private static Bitmap CaptureWindow(IntPtr handle,Int32 x,Int32 y,Int32 width,Int32 height)
        {
            //todo:只截取部分的图
            // get te hDC of the target window
            IntPtr hdcSrc = Utils.GetWindowDC(handle);
            // get the size
src/RichCreator.Utility/InputControl/HardwareInputControl.cs
@@ -324,9 +324,9 @@
        public void PressKey(bool pressLeftControl, bool pressRightControl, bool pressLeftShift, bool pressRightShift, bool pressLeftAlt, bool pressRightAlt, bool pressLeftGUI, bool pressRightGUI, params HIDCode[] keys)
        {
            PutDown(pressLeftControl, pressRightControl, pressLeftShift, pressRightShift, pressLeftAlt, pressRightAlt, pressLeftGUI, pressRightGUI, keys);
            Thread.Sleep(100);
            Thread.Sleep(RandomUtils.KeyPressDuration);
            PutDown(false, false, false, false, false, false, false, false);
            Thread.Sleep(100);
            Thread.Sleep(RandomUtils.KeyPressDuration);
        }
        /// <summary>
src/RichCreator.Utility/InputControl/IInputControl.cs
@@ -31,11 +31,7 @@
        void MoveToAndClick(ZTPoint point);
        //todo:void DoubleClick()
        //todo:void Click();
        //todo:void DragTo();
        /// <summary>
        /// 输入字符串
src/RichCreator.Utility/RichCreator.Utility.csproj
@@ -110,9 +110,13 @@
    <Compile Include="Structs\ColorArray.cs" />
    <Compile Include="Structs\ColorArrayItem.cs" />
    <Compile Include="Structs\Direction.cs" />
    <Compile Include="Structs\HousePathInfo.cs" />
    <Compile Include="Structs\ParametersPoint.cs" />
    <Compile Include="Structs\ZTLinePoint.cs" />
    <Compile Include="Structs\MoveQueueItem.cs" />
    <Compile Include="Structs\Orientation.cs" />
    <Compile Include="Structs\FindPathInfo.cs" />
    <Compile Include="Structs\ZTPolygon.cs" />
    <Compile Include="Structs\ZTColor.cs" />
    <Compile Include="Structs\ZTColorArrayItem.cs" />
    <Compile Include="Structs\ZTHsvColor.cs" />
@@ -124,6 +128,7 @@
    <Compile Include="Structs\ZTSize.cs" />
    <Compile Include="Structs\ZTSizeDouble.cs" />
    <Compile Include="Utilitys\ColorUtils.cs" />
    <Compile Include="Utilitys\GeometryHelper.cs" />
    <Compile Include="Utilitys\ProcessUtils.cs" />
    <Compile Include="Utilitys\RandomUtils.cs" />
    <Compile Include="Utilitys\WindowUtils.cs" />
src/RichCreator.Utility/Structs/HousePathInfo.cs
New file
@@ -0,0 +1,396 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RichCreator.Utility.Structs
{
    /// <summary>
    /// 路径信息
    /// </summary>
    public class HousePathInfo
    {
        public HousePathInfo()
        {
            Obstacles = new List<ZTPolygon>();
            LocationPoints = new List<ParametersPoint>();
            FindPathPoints = new List<ZTPoint>();
            LoopLines = new List<ZTLinePoint>();
            FindPathLines = new List<ZTLinePoint>();
        }
        public HousePathInfo(Int32 width,Int32 height):this()
        {
            this.Width = width;
            this.Height = height;
        }
        #region Propertys
        /// <summary>
        /// 宽
        /// </summary>
        public int Width { get; set; }
        /// <summary>
        /// 高
        /// </summary>
        public int Height { get; set; }
        /// <summary>
        /// 障碍物
        /// </summary>
        public List<ZTPolygon> Obstacles { get; set; }
        /// <summary>
        /// 定位点
        /// </summary>
        public List<ParametersPoint> LocationPoints { get; set; }
        /// <summary>
        /// 寻路点
        /// </summary>
        public List<ZTPoint> FindPathPoints{ get; set; }
        /// <summary>
        /// 循逻线
        /// </summary>
        public List<ZTLinePoint> LoopLines { get; set; }
        /// <summary>
        /// 寻路线
        /// </summary>
        public List<ZTLinePoint> FindPathLines { get; set; }
        #endregion
        #region Editor
        /// <summary>
        /// 添加障碍物
        /// </summary>
        /// <returns></returns>
        public bool AddObstacle(ZTPolygon obstacle)
        {
            Int32 index = 0;
            if (ExistsObstacle(out index, obstacle))
            {
                return false;
            }
            this.Obstacles.Add(obstacle);
            return true;
        }
        /// <summary>
        /// 删除障碍物
        /// </summary>
        /// <param name="obstacle"></param>
        /// <returns></returns>
        public void RemoveObstacle(ZTPolygon obstacle)
        {
            Int32 index = 0;
            if (!ExistsObstacle(out index, obstacle))
            {
                return;
            }
            this.Obstacles.RemoveAt(index);
            return;
        }
        /// <summary>
        /// 是否存在障碍物
        /// </summary>
        /// <param name="obstacle"></param>
        /// <returns></returns>
        private bool ExistsObstacle(out Int32 index,ZTPolygon obstacle)
        {
            index = 0;
            for (int i = 0; i < Obstacles.Count; i++)
            {
                if (Obstacles[i] == obstacle)
                {
                    index = i;
                    return true;
                }
            }
            return false;
        }
        /// <summary>
        /// 添加定位点
        /// </summary>
        /// <param name="point"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public bool AddLocationPosition(ParametersPoint point)
        {
            if (this.LocationPoints.Exists((p) => { return point.Point == p.Point; }))
            {
                return false;
            }
            this.LocationPoints.Add(point);
            return true;
        }
        /// <summary>
        /// 清空定位点
        /// </summary>
        /// <returns></returns>
        public void ClearLocationPosiltion()
        {
            this.LocationPoints.Clear();
        }
        /// <summary>
        /// 添加寻路点
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public bool AddFindPathPoint(ZTPoint point)
        {
            Int32 index = 0;
            if (ExistsFindPathPoint(out index, point))
            {
                return false;
            }
            this.FindPathPoints.Add(point);
            return true;
        }
        /// <summary>
        /// 删除寻路点
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public bool RemoveFindPathPoint(ZTPoint point)
        {
            Int32 index = 0;
            if (!ExistsFindPathPoint(out index,point))
            {
                return true;
            }
            //查询巡逻线和寻路线是否有用到此点
            if (ExistsPointInAllLine(point))
            {
                return false;
            }
            this.FindPathPoints.RemoveAt(index);
            return true;
        }
        /// <summary>
        /// 是否存在指定寻路点
        /// </summary>
        /// <param name="index"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        private bool ExistsFindPathPoint(out Int32 index, ZTPoint point)
        {
            index = 0;
            for (int i = 0; i < this.FindPathPoints.Count; i++)
            {
                if (this.FindPathPoints[i] == point)
                {
                    index = i;
                    return true;
                }
            }
            return false;
        }
        /// <summary>
        /// 添加巡逻线
        /// </summary>
        /// <param name="line"></param>
        /// <returns></returns>
        public bool  AddLoopLine(ZTLinePoint line)
        {
            Int32 index = 0;
            if (ExistsLoopLine(out index, line))
            {
                return false;
            }
            if (line.P1 == line.P2)
            {
                return false;
            }
            this.LoopLines.Add(line);
            return true;
        }
        /// <summary>
        /// 删除巡逻线
        /// </summary>
        /// <param name="line"></param>
        /// <returns></returns>
        public bool RemoveLoopLine(ZTLinePoint line)
        {
            Int32 index = 0;
            if (!ExistsLoopLine(out index, line))
            {
                return true;
            }
            this.LoopLines.RemoveAt(index);
            return true;
        }
        /// <summary>
        /// 是否存在巡逻线
        /// </summary>
        /// <param name="index"></param>
        /// <param name="line"></param>
        /// <returns></returns>
        private  bool ExistsLoopLine(out Int32 index, ZTLinePoint line)
        {
            index = 0;
            for (int i = 0; i < this.LoopLines.Count; i++)
            {
                if (this.LoopLines[i] == line)
                {
                    index = i;
                    return true;
                }
            }
            return false;
        }
        /// <summary>
        /// 添加寻路线
        /// </summary>
        /// <param name="line"></param>
        /// <returns></returns>
        public bool AddFindPathLine(ZTLinePoint line)
        {
            Int32 index = 0;
            if (ExistsFindPathLine(out index, line))
            {
                return false;
            }
            this.FindPathLines.Add(line);
            return true;
        }
        /// <summary>
        /// 删除寻路线
        /// </summary>
        /// <param name="line"></param>
        /// <returns></returns>
        public bool RemoveFindPathLine(ZTLinePoint line)
        {
            Int32 index = 0;
            if (!ExistsFindPathLine(out index, line))
            {
                return true;
            }
            this.FindPathLines.RemoveAt(index);
            return true;
        }
        /// <summary>
        /// 是否存在寻路线
        /// </summary>
        /// <param name="index"></param>
        /// <param name="line"></param>
        /// <returns></returns>
        private bool ExistsFindPathLine(out Int32 index, ZTLinePoint line)
        {
            index = 0;
            for (int i = 0; i < this.FindPathLines.Count; i++)
            {
                if (this.FindPathLines[i] == line)
                {
                    index = i;
                    return true;
                }
            }
            return false;
        }
        /// <summary>
        /// 巡逻线或寻路线中是否存在某点
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        private bool ExistsPointInAllLine(ZTPoint point)
        {
            for (int i = 0; i < this.LoopLines.Count; i++)
            {
                if (this.LoopLines[i].P1 == point || this.LoopLines[i].P2 == point)
                {
                    return true;
                }
            }
            for (int i = 0; i < this.FindPathLines.Count; i++)
            {
                if (this.FindPathLines[i].P1 == point || this.FindPathLines[i].P2 == point)
                {
                    return true;
                }
            }
            return false;
        }
        #endregion
        /// <summary>
        /// 获取json
        /// </summary>
        /// <returns></returns>
        public string ToJsonString()
        {
            string json = ZTImage.Json.JsonBuilder.ToJsonString(this);
            return json;
        }
        /// <summary>
        /// 从json字符串生成对象
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public static HousePathInfo FromJsonString(string json)
        {
            return ZTImage.Json.JsonParser.ToObject<HousePathInfo>(json);
        }
        /// <summary>
        /// 寻找巡逻路线
        /// </summary>
        /// <param name="rolePosition"></param>
        public static void FindLoopPath(ZTPoint rolePosition)
        {
        }
        /// <summary>
        /// 两点之间寻路
        /// </summary>
        /// <param name="start"></param>
        /// <param name="end"></param>
        public static void FindPath(ZTPoint start, ZTPoint end)
        {
        }
    }
}
src/RichCreator.Utility/Structs/ParametersPoint.cs
New file
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RichCreator.Utility.Structs
{
    /// <summary>
    /// 带参数的点
    /// </summary>
    public class ParametersPoint
    {
        public ParametersPoint()
        { }
        public ParametersPoint(ZTPoint point, Int32 number)
        {
            this.Point = point;
            this.Parameter = number;
        }
        /// <summary>
        /// 点
        /// </summary>
        public ZTPoint Point { get; set; }
        /// <summary>
        /// 参数
        /// </summary>
        public Int32 Parameter { get; set; }
    }
}
src/RichCreator.Utility/Structs/ZTLine.cs
@@ -19,15 +19,15 @@
            this.Y = y;
            this.Length = length;
        }
        public Int32 X;
        public Int32 X { get; set; }
        public Int32 Y;
        public Int32 Y { get; set; }
        public Int32 Length;
        public Int32 Length { get; set; }
        public static bool operator ==(ZTLine a, ZTLine b)
        {
            if (a.X == b.X && a.Y == b.Y && a.Length == b.Length)
            if ((a.X == b.X && a.Y == b.Y && a.Length == b.Length))
            {
                return true;
            }
src/RichCreator.Utility/Structs/ZTLinePoint.cs
New file
@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RichCreator.Utility.Structs
{
    /// <summary>
    /// 线
    /// </summary>
    public class ZTLinePoint
    {
        public static ZTLinePoint Empty;
        private ZTPoint p1;
        private ZTPoint p2;
        public ZTLinePoint()
        {
        }
        public ZTLinePoint(ZTPoint p1, ZTPoint p2)
        {
            this.p1 = p1;
            this.p2 = p2;
        }
        public ZTPoint P1
        {
            get { return p1; }
            set { p1 = value; }
        }
        public ZTPoint P2
        {
            get { return p2; }
            set { p2 = value; }
        }
        [ZTImage.Reflection.UnSerializedAttribute]
        public Int32 X1
        {
            get { return p1.X; }
            set { p1.X = value; }
        }
        [ZTImage.Reflection.UnSerializedAttribute]
        public Int32 X2
        {
            get { return p2.X; }
            set { p2.X = value; }
        }
        [ZTImage.Reflection.UnSerializedAttribute]
        public Int32 Y1
        {
            get { return p1.Y; }
            set { p1.Y = value; }
        }
        [ZTImage.Reflection.UnSerializedAttribute]
        public Int32 Y2
        {
            get { return p2.Y; }
            set { p2.Y = value; }
        }
        public static bool operator !=(ZTLinePoint a, ZTLinePoint b)
        {
            if (a == b)
            {
                return false;
            }
            return true;
        }
        public static bool operator ==(ZTLinePoint a, ZTLinePoint b)
        {
            if ((a.p1 == b.p1 && a.p2 == b.p2) || (a.p1 == b.p2 && a.p2 == b.p1))
            {
                return true;
            }
            return false;
        }
    }
}
src/RichCreator.Utility/Structs/ZTPoint.cs
@@ -9,18 +9,21 @@
    /// <summary>
    /// 点
    /// </summary>
    public struct ZTPoint : IEquatable<ZTPoint>
    public class ZTPoint : IEquatable<ZTPoint>
    {
        public static ZTPoint Empty = new ZTPoint(0, 0);
        public static ZTPoint Empty = default(ZTPoint);
        public ZTPoint(Int32 x, Int32 y)
        {
            this.X = x;
            this.Y = y;
        }
        public Int32 X;
        public Int32 Y;
        public Int32 X { get; set; }
        public Int32 Y { get; set; }
        public static bool operator ==(ZTPoint a, ZTPoint b)
src/RichCreator.Utility/Structs/ZTPolygon.cs
New file
@@ -0,0 +1,84 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RichCreator.Utility.Structs
{
    /// <summary>
    /// 多边形
    /// </summary>
    public class ZTPolygon : IEnumerable<ZTPoint>
    {
        private ZTPoint[] points;
        public ZTPolygon(ZTPoint[] points)
        {
            this.points = points;
        }
        public ZTPoint[] Points
        {
            get { return points; }
            set { points = value; }
        }
        public int Length
        {
            get { return points.Length; }
        }
        public ZTPoint this[int index]
        {
            get { return points[index]; }
            set { points[index] = value; }
        }
        public static bool operator !=(ZTPolygon a, ZTPolygon b)
        {
            if (a == b)
            {
                return false;
            }
            return true;
        }
        public static bool operator ==(ZTPolygon a, ZTPolygon b)
        {
            if (a.Length != b.Length)
            {
                return false;
            }
            for (int i = 0; i < a.Length; i++)
            {
                if (a[i] != b[i])
                {
                    return false;
                }
            }
            return true;
        }
        public static implicit operator ZTPoint[] (ZTPolygon polygon)
        {
            return polygon.points;
        }
        public static implicit operator ZTPolygon(ZTPoint[] points)
        {
            return new ZTPolygon(points);
        }
        IEnumerator<ZTPoint> IEnumerable<ZTPoint>.GetEnumerator()
        {
            return (IEnumerator<ZTPoint>)points.GetEnumerator();
        }
        public IEnumerator GetEnumerator()
        {
            return points.GetEnumerator();
        }
    }
}
src/RichCreator.Utility/Utilitys/GeometryHelper.cs
New file
@@ -0,0 +1,267 @@
using RichCreator.Utility.Structs;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RichCreator.Utility.Utilitys
{
    /// <summary>
    /// 几何体之间的关系类型
    /// </summary>
    public enum Intersection
    {
        None,//没关系
        Tangent,//切线,正切
        Intersection,//相交,交叉
        Containment//包含
    }
    /// <summary>
    /// 与几何相关的辅助类
    /// </summary>
    public static class GeometryHelper
    {
        /// <summary>
        /// 获取点到点的距离
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static double GetPointDistance(ZTPoint a, ZTPoint b)
        {
            return Math.Sqrt((a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y));
        }
        /// <summary>
        /// 获取点到直线的距离
        /// </summary>
        /// <param name="line"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public static double GetNearestDistance(ZTLinePoint line, ZTPoint point)
        {
            double a, b, c;
            a = GetPointDistance(line.P2, point);
            if (a <= 0.00001)
            {
                return 0.0f;
            }
            b = GetPointDistance(line.P1, point);
            if (b <= 0.00001)
            {
                return 0.0f;
            }
            c = GetPointDistance(line.P1, line.P2);
            if (c <= 0.00001)
            {
                //如果PA和PB坐标相同,则退出函数,并返回距离
                return a;
            }
            if (a * a >= b * b + c * c)
            {
                return b;      //如果是钝角返回b
            }
            if (b * b >= a * a + c * c)
            {
                return a;      //如果是钝角返回a
            }
            double l = (a + b + c) / 2;     //周长的一半
            double s = Math.Sqrt(Math.Abs(l * (l - a) * (l - b) * (l - c)));  //海伦公式求面积,也可以用矢量求
            return 2 * s / c;
        }
        /// <summary>
        /// 判断线段与多边形的关系
        /// </summary>
        /// <param name="line"></param>
        /// <param name="polygon"></param>
        /// <returns></returns>
        public static Intersection IntersectionOf(ZTLinePoint line, ZTPolygon polygon)
        {
            if (polygon.Length == 0)
            {
                return Intersection.None;
            }
            if (polygon.Length == 1)
            {
                return IntersectionOf(polygon[0], line);
            }
            bool tangent = false;
            for (int index = 0; index < polygon.Length; index++)
            {
                int index2 = (index + 1) % polygon.Length;
                Intersection intersection = IntersectionOf(line, new ZTLinePoint(polygon[index], polygon[index2]));
                if (intersection == Intersection.Intersection)
                {
                    return intersection;
                }
                if (intersection == Intersection.Tangent)
                {
                    tangent = true;
                }
            }
            return tangent ? Intersection.Tangent : IntersectionOf(line.P1, polygon);
        }
        /// <summary>
        /// 判断点与多边形的关系
        /// </summary>
        /// <param name="point"></param>
        /// <param name="polygon"></param>
        /// <returns></returns>
        public static Intersection IntersectionOf(ZTPoint point, ZTPolygon polygon)
        {
            switch (polygon.Length)
            {
                case 0:
                    return Intersection.None;
                case 1:
                    if (polygon[0].X == point.X && polygon[0].Y == point.Y)
                    {
                        return Intersection.Tangent;
                    }
                    else
                    {
                        return Intersection.None;
                    }
                case 2:
                    return IntersectionOf(point, new ZTLinePoint(polygon[0], polygon[1]));
            }
            int counter = 0;
            int i;
            ZTPoint p1;
            int n = polygon.Length;
            p1 = polygon[0];
            if (point == p1)
            {
                return Intersection.Tangent;
            }
            for (i = 1; i <= n; i++)
            {
                ZTPoint p2 = polygon[i % n];
                if (point == p2)
                {
                    return Intersection.Tangent;
                }
                if (point.Y > Math.Min(p1.Y, p2.Y))
                {
                    if (point.Y <= Math.Max(p1.Y, p2.Y))
                    {
                        if (point.X <= Math.Max(p1.X, p2.X))
                        {
                            if (p1.Y != p2.Y)
                            {
                                double xinters = (point.Y - p1.Y) * (p2.X - p1.X) / (p2.Y - p1.Y) + p1.X;
                                if (p1.X == p2.X || point.X <= xinters)
                                    counter++;
                            }
                        }
                    }
                }
                p1 = p2;
            }
            return (counter % 2 == 1) ? Intersection.Containment : Intersection.None;
        }
        /// <summary>
        /// 判断点与直线的关系
        /// </summary>
        /// <param name="point"></param>
        /// <param name="line"></param>
        /// <returns></returns>
        public static Intersection IntersectionOf(ZTPoint point, ZTLinePoint line)
        {
            float bottomY = Math.Min(line.Y1, line.Y2);
            float topY = Math.Max(line.Y1, line.Y2);
            bool heightIsRight = point.Y >= bottomY &&
                                 point.Y <= topY;
            //Vertical line, slope is divideByZero error!
            if (line.X1 == line.X2)
            {
                if (point.X == line.X1 && heightIsRight)
                {
                    return Intersection.Tangent;
                }
                else
                {
                    return Intersection.None;
                }
            }
            float slope = (line.X2 - line.X1) / (line.Y2 - line.Y1);
            bool onLine = (line.Y1 - point.Y) == (slope * (line.X1 - point.X));
            if (onLine && heightIsRight)
            {
                return Intersection.Tangent;
            }
            else
            {
                return Intersection.None;
            }
        }
        /// <summary>
        /// 判断直线与直线的关系
        /// </summary>
        /// <param name="line1"></param>
        /// <param name="line2"></param>
        /// <returns></returns>
        public static Intersection IntersectionOf(ZTLinePoint line1, ZTLinePoint line2)
        {
            //  Fail if either line segment is zero-length.
            if (line1.X1 == line1.X2 && line1.Y1 == line1.Y2 || line2.X1 == line2.X2 && line2.Y1 == line2.Y2)
                return Intersection.None;
            if (line1.X1 == line2.X1 && line1.Y1 == line2.Y1 || line1.X2 == line2.X1 && line1.Y2 == line2.Y1)
                return Intersection.Intersection;
            if (line1.X1 == line2.X2 && line1.Y1 == line2.Y2 || line1.X2 == line2.X2 && line1.Y2 == line2.Y2)
                return Intersection.Intersection;
            //  (1) Translate the system so that point A is on the origin.
            line1.X2 -= line1.X1; line1.Y2 -= line1.Y1;
            line2.X1 -= line1.X1; line2.Y1 -= line1.Y1;
            line2.X2 -= line1.X1; line2.Y2 -= line1.Y1;
            //  Discover the length of segment A-B.
            double distAB = Math.Sqrt(line1.X2 * line1.X2 + line1.Y2 * line1.Y2);
            //  (2) Rotate the system so that point B is on the positive X axis.
            double theCos = line1.X2 / distAB;
            double theSin = line1.Y2 / distAB;
            double newX = line2.X1 * theCos + line2.Y1 * theSin;
            line2.Y1 = (Int32)(line2.Y1 * theCos - line2.X1 * theSin); line2.X1 = (Int32)newX;
            newX = line2.X2 * theCos + line2.Y2 * theSin;
            line2.Y2 = (Int32)(line2.Y2 * theCos - line2.X2 * theSin); line2.X2 = (Int32)newX;
            //  Fail if segment C-D doesn't cross line A-B.
            if (line2.Y1 < 0 && line2.Y2 < 0 || line2.Y1 >= 0 && line2.Y2 >= 0)
                return Intersection.None;
            //  (3) Discover the position of the intersection point along line A-B.
            double posAB = line2.X2 + (line2.X1 - line2.X2) * line2.Y2 / (line2.Y2 - line2.Y1);
            //  Fail if segment C-D crosses line A-B outside of segment A-B.
            if (posAB < 0 || posAB > distAB)
                return Intersection.None;
            //  (4) Apply the discovered position to line A-B in the original coordinate system.
            return Intersection.Intersection;
        }
    }
}
src/RichCreator/Jobs/DNFJob.cs
@@ -29,20 +29,20 @@
        /// <summary>
        /// 选角色时的角色选择偏移
        /// </summary>
        private static ZTPoint[] RoleOffset = new ZTPoint[] {
            new ZTPoint (154,225),
            new ZTPoint (300,225),
            new ZTPoint (443,225),
            new ZTPoint (593,225),
            new ZTPoint (726,225),
            new ZTPoint (883,225),
        private static Utility.Structs.ZTPoint[] RoleOffset = new Utility.Structs.ZTPoint[] {
            new Utility.Structs.ZTPoint (154,225),
            new Utility.Structs.ZTPoint (300,225),
            new Utility.Structs.ZTPoint (443,225),
            new Utility.Structs.ZTPoint (593,225),
            new Utility.Structs.ZTPoint (726,225),
            new Utility.Structs.ZTPoint (883,225),
            new ZTPoint (154,455),
            new ZTPoint (300,455),
            new ZTPoint (443,455),
            new ZTPoint (593,455),
            new ZTPoint (726,455),
            new ZTPoint (883,455)
            new Utility.Structs.ZTPoint (154,455),
            new Utility.Structs.ZTPoint (300,455),
            new Utility.Structs.ZTPoint (443,455),
            new Utility.Structs.ZTPoint (593,455),
            new Utility.Structs.ZTPoint (726,455),
            new Utility.Structs.ZTPoint (883,455)
        };
        /// <summary>
@@ -279,7 +279,7 @@
            if (result)
            {
                //点击切换角色按钮624,502
                G.Instance.InputControl.MoveToAndClick(new ZTPoint(this.GameRect.Start.X + 624, this.GameRect.Start.Y + 502));
                G.Instance.InputControl.MoveToAndClick(new Utility.Structs.ZTPoint(this.GameRect.Start.X + 624, this.GameRect.Start.Y + 502));
                return true;
            }
            G.Instance.InfoWriter("退回选择角色界面失败");
src/RichCreator/Jobs/WeGameJob.cs
@@ -101,11 +101,11 @@
        private bool LoginWeGame(CancellationToken cancelToken, Int64 timeoutSecond, ZTRectangle weGameRect, ZTRectangle changButtonRect)
        {
            ZTPoint basePoint = changButtonRect.GetCenterPoint();
            Utility.Structs.ZTPoint basePoint = changButtonRect.GetCenterPoint();
            ZTPoint userPoint = new ZTPoint(basePoint.X, basePoint.Y - 148);
            ZTPoint pwdPoint = new ZTPoint(basePoint.X, basePoint.Y - 118);
            ZTPoint loginPoint = new ZTPoint(basePoint.X, basePoint.Y - 42);
            Utility.Structs.ZTPoint userPoint = new Utility.Structs.ZTPoint(basePoint.X, basePoint.Y - 148);
            Utility.Structs.ZTPoint pwdPoint = new Utility.Structs.ZTPoint(basePoint.X, basePoint.Y - 118);
            Utility.Structs.ZTPoint loginPoint = new Utility.Structs.ZTPoint(basePoint.X, basePoint.Y - 42);
            
            //输入用户名
            G.Instance.InputControl.MoveToAndClick(userPoint);
src/RichCreator/MainWindow.xaml.cs
@@ -187,8 +187,8 @@
        private bool TestHardware()
        {
            testTempVar = false;
            ZTPoint btnPosition = ZTPoint.Empty;
            ZTPoint txtPosition = ZTPoint.Empty;
            Utility.Structs.ZTPoint btnPosition = Utility.Structs.ZTPoint.Empty;
            Utility.Structs.ZTPoint txtPosition = Utility.Structs.ZTPoint.Empty;
            using (ManualResetEvent mre = new ManualResetEvent(false))
            {
                //等待读取位置成功
@@ -236,7 +236,7 @@
        private ZTPoint GetElementClickPosition(Control element)
        {
            Point t = element.PointToScreen(new Point(0, 0));
            ZTPoint t1 = new ZTPoint((Int32)(t.X + element.ActualWidth / 2), (Int32)(t.Y + element.ActualHeight / 2));
            Utility.Structs.ZTPoint t1 = new Utility.Structs.ZTPoint((Int32)(t.X + element.ActualWidth / 2), (Int32)(t.Y + element.ActualHeight / 2));
            return t1;
        }
        #endregion
src/RichCreator/Maps/HouseInfo.cs
File was renamed from src/RichCreator/Maps/MapHouse.cs
@@ -11,7 +11,7 @@
    /// <summary>
    /// 房间信息
    /// </summary>
    public class MapHouse
    public class HouseInfo
    {
        /// <summary>
        /// 房间编号
src/RichCreator/Maps/Lindong/LindongMap.cs
@@ -24,27 +24,27 @@
        /// NextIndex=-1,完成
        /// NextIndex=-2,出错
        /// </summary>
        internal static MapHouse[] Houses = new MapHouse[] {
            new MapHouse (){ Index=0 ,NextIndex=1 , OpenStatusDetectIndex=1 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Right } },
            new MapHouse (){ Index=1 ,NextIndex=5 , OpenStatusDetectIndex=5 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Bottom } },
            new MapHouse (){ Index=2 ,NextIndex=1 , OpenStatusDetectIndex=1 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Left } },
            new MapHouse (){ Index=3 ,NextIndex=2 , OpenStatusDetectIndex=2 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Left } },
            new MapHouse (){ Index=4 ,NextIndex=8 , OpenStatusDetectIndex=8 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Bottom } },
            new MapHouse (){ Index=5 ,NextIndex=4 , OpenStatusDetectIndex=4 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Left } },
            new MapHouse (){ Index=6 ,NextIndex=5 , OpenStatusDetectIndex=5 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Left } },
            new MapHouse (){ Index=7 ,NextIndex=6 , OpenStatusDetectIndex=6 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Left } },
            new MapHouse (){ Index=8 ,NextIndex=12 ,OpenStatusDetectIndex=12, HouseCenterMoveLine=-148,IsEnd=false,DoorDirection=new[]{Direction.Right,Direction.Bottom } },
            new MapHouse (){ Index=9 ,NextIndex=10, OpenStatusDetectIndex=10, HouseCenterMoveLine=-300,IsEnd=false,DoorDirection=new[]{Direction.Right,Direction.Bottom } },
            new MapHouse (){ Index=10,NextIndex=14, OpenStatusDetectIndex=14, HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Bottom } },
            new MapHouse (){ Index=11,NextIndex=10, OpenStatusDetectIndex=10, HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Left } },
            new MapHouse (){ Index=12,NextIndex=13, OpenStatusDetectIndex=12, HouseCenterMoveLine=-220,IsEnd=false,DoorDirection=new[]{Direction.Right } },
            new MapHouse (){ Index=13,NextIndex=14, OpenStatusDetectIndex=14, HouseCenterMoveLine=-320,IsEnd=false,DoorDirection=new[]{Direction.Right } },
            new MapHouse (){ Index=14,NextIndex=15, OpenStatusDetectIndex=-1, HouseCenterMoveLine=-320,IsEnd=false,DoorDirection=new[]{Direction.Right } },
            new MapHouse (){ Index=15,NextIndex=-1, OpenStatusDetectIndex=-1, HouseCenterMoveLine=-250,IsEnd=true, DoorDirection=new[]{Direction.Right } },
            new MapHouse (){ Index=16,NextIndex=12, OpenStatusDetectIndex=12, HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Up } },
            new MapHouse (){ Index=17,NextIndex=13, OpenStatusDetectIndex=13, HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Up } },
            new MapHouse (){ Index=18,NextIndex=14, OpenStatusDetectIndex=14, HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Up } },
            new MapHouse (){ Index=19,NextIndex=15, OpenStatusDetectIndex=15, HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Up } }
        internal static HouseInfo[] Houses = new HouseInfo[] {
            new HouseInfo (){ Index=0 ,NextIndex=1 , OpenStatusDetectIndex=1 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Right } },
            new HouseInfo (){ Index=1 ,NextIndex=5 , OpenStatusDetectIndex=5 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Bottom } },
            new HouseInfo (){ Index=2 ,NextIndex=1 , OpenStatusDetectIndex=1 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Left } },
            new HouseInfo (){ Index=3 ,NextIndex=2 , OpenStatusDetectIndex=2 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Left } },
            new HouseInfo (){ Index=4 ,NextIndex=8 , OpenStatusDetectIndex=8 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Bottom } },
            new HouseInfo (){ Index=5 ,NextIndex=4 , OpenStatusDetectIndex=4 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Left } },
            new HouseInfo (){ Index=6 ,NextIndex=5 , OpenStatusDetectIndex=5 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Left } },
            new HouseInfo (){ Index=7 ,NextIndex=6 , OpenStatusDetectIndex=6 , HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Left } },
            new HouseInfo (){ Index=8 ,NextIndex=12 ,OpenStatusDetectIndex=12, HouseCenterMoveLine=-148,IsEnd=false,DoorDirection=new[]{Direction.Right,Direction.Bottom } },
            new HouseInfo (){ Index=9 ,NextIndex=10, OpenStatusDetectIndex=10, HouseCenterMoveLine=-300,IsEnd=false,DoorDirection=new[]{Direction.Right,Direction.Bottom } },
            new HouseInfo (){ Index=10,NextIndex=14, OpenStatusDetectIndex=14, HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Bottom } },
            new HouseInfo (){ Index=11,NextIndex=10, OpenStatusDetectIndex=10, HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Left } },
            new HouseInfo (){ Index=12,NextIndex=13, OpenStatusDetectIndex=12, HouseCenterMoveLine=-220,IsEnd=false,DoorDirection=new[]{Direction.Right } },
            new HouseInfo (){ Index=13,NextIndex=14, OpenStatusDetectIndex=14, HouseCenterMoveLine=-320,IsEnd=false,DoorDirection=new[]{Direction.Right } },
            new HouseInfo (){ Index=14,NextIndex=15, OpenStatusDetectIndex=-1, HouseCenterMoveLine=-320,IsEnd=false,DoorDirection=new[]{Direction.Right } },
            new HouseInfo (){ Index=15,NextIndex=-1, OpenStatusDetectIndex=-1, HouseCenterMoveLine=-250,IsEnd=true, DoorDirection=new[]{Direction.Right } },
            new HouseInfo (){ Index=16,NextIndex=12, OpenStatusDetectIndex=12, HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Up } },
            new HouseInfo (){ Index=17,NextIndex=13, OpenStatusDetectIndex=13, HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Up } },
            new HouseInfo (){ Index=18,NextIndex=14, OpenStatusDetectIndex=14, HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Up } },
            new HouseInfo (){ Index=19,NextIndex=15, OpenStatusDetectIndex=15, HouseCenterMoveLine=-250,IsEnd=false,DoorDirection=new[]{Direction.Up } }
        };
        static LindongMap()
@@ -172,10 +172,10 @@
        /// <summary>
        /// 小地图区域
        /// </summary>
        public ZTPoint MinimapPoint = ZTPoint.Empty;
        public Utility.Structs.ZTPoint MinimapPoint = Utility.Structs.ZTPoint.Empty;
        //小地图距游戏区域的偏移
        private ZTPoint minimapPointOffset = new ZTPoint(1201, 47);
        private Utility.Structs.ZTPoint minimapPointOffset = new Utility.Structs.ZTPoint(1201, 47);
        public CancellationToken cancellationToken { get; set; }
@@ -269,7 +269,7 @@
        private void ExitToTown()
        {
            G.Instance.DebugWriter("返回城镇");
            ZTPoint point = new ZTPoint(this.GameRect.End.X - 124, this.GameRect.Start.Y + 146);
            Utility.Structs.ZTPoint point = new Utility.Structs.ZTPoint(this.GameRect.End.X - 124, this.GameRect.Start.Y + 146);
            G.Instance.InputControl.MoveToAndClick(point);
            Thread.Sleep(5000);
        }
@@ -280,7 +280,7 @@
        private void ReplayGame()
        {
            G.Instance.DebugWriter("重新挑战");
            ZTPoint point = new ZTPoint(this.GameRect.End.X - 132, this.GameRect.Start.Y + 90);
            Utility.Structs.ZTPoint point = new Utility.Structs.ZTPoint(this.GameRect.End.X - 132, this.GameRect.Start.Y + 90);
            G.Instance.InputControl.MoveToAndClick(point);
        }
@@ -335,8 +335,8 @@
                
                DateTime roomStartTime = DateTime.Now;
                KillMonsterStateMachine kmsm = new KillMonsterStateMachine(Houses[houseIndex], this.MinimapPoint, this.GameRect, preHouseIndex,this.runningStep);
                ZTResult smresult = kmsm.Work(cancellationToken, 5 * 60 * 1000);
                KillMonsterStateMachine kmsm = new KillMonsterStateMachine(Houses[houseIndex], this.MinimapPoint, this.GameRect, preHouseIndex,this.runningStep, cancellationToken);
                ZTResult smresult = kmsm.Work( 5 * 60 * 1000);
                Int32 roomTotalSecond = (Int32)(DateTime.Now - roomStartTime).TotalSeconds;
                G.Instance.InfoWriter("房间刷完,用时:" + (roomTotalSecond / 60) + "分" + (roomTotalSecond % 60) + "秒");
                runningStep = RunningStep.None;
@@ -367,7 +367,7 @@
            bool result = FuncUtils.NoChangeRetryCallWrap(
               () =>
               {
                   WindowUtils.SetDnfToTop();
                   CloseAllAlertWindow(this.cancellationToken, this.GameRect);
                   //向下走出赛丽亚的房间  ,走向素喃
                   G.Instance.InputControl.PressKey(2000, HIDCode.DownArrow);
@@ -400,15 +400,15 @@
        /// <returns></returns>
        private bool MoveToShikongzhimen()
        {
            bool result=FuncUtils.NoChangeRetryCallWrap(() =>
            bool result= FuncUtils.NoChangeRetryCallWrap(() =>
            {
                //打开地图
                ZTPoint mapButtonPosition = new ZTPoint(this.GameRect.End.X - 14, this.GameRect.Start.Y + 16);
                Utility.Structs.ZTPoint mapButtonPosition = new Utility.Structs.ZTPoint(this.GameRect.End.X - 14, this.GameRect.Start.Y + 16);
                G.Instance.InputControl.MoveToAndClick(mapButtonPosition);
                Thread.Sleep(1000);
                //点到副本之前的地图
                ZTPoint mapPrePosition = new ZTPoint(this.GameRect.Start.X + 382, this.GameRect.Start.Y + 252);
                Utility.Structs.ZTPoint mapPrePosition = new Utility.Structs.ZTPoint(this.GameRect.Start.X + 382, this.GameRect.Start.Y + 252);
                G.Instance.InputControl.MoveToAndClick(mapPrePosition);
                //关闭地图框
@@ -539,7 +539,7 @@
                return true; 
            }
            G.Instance.InputControl.MoveToAndClick(new ZTPoint(this.GameRect.Start.X + 508, this.GameRect.Start.Y + 552));
            G.Instance.InputControl.MoveToAndClick(new Utility.Structs.ZTPoint(this.GameRect.Start.X + 508, this.GameRect.Start.Y + 552));
            Thread.Sleep(5000);
            image = ScreenCapture.Instance.CaptureScreenReturnImage();
            if (LindongCVHelper.GetChoiceLingdongNandu(out nandu, image, this.GameRect))
@@ -624,7 +624,6 @@
            if (!result)
            {
                //todo:remove
                G.Instance.InfoWriter("装备文字未取到");
                return false;
            }
@@ -632,7 +631,7 @@
            //开始点,每格步进30
            ZTPoint startPoint = new ZTPoint( equipmentTextRect.End.X-30,equipmentTextRect.End.Y+9);
            Utility.Structs.ZTPoint startPoint = new Utility.Structs.ZTPoint( equipmentTextRect.End.X-30, equipmentTextRect.End.Y+9);
            List<Int32> points = DnfCVHelper.GetEquipmentIndexs(startPoint);
            for (int i = 0; i < points.Count; i++)
@@ -643,9 +642,9 @@
                int col = index % 8;
                int x = col * 30+15;
                int y = row * 30+15;
                //点窗格
                G.Instance.InputControl.MoveToAndClick(new ZTPoint(startPoint.X+x,startPoint.Y+y));
                G.Instance.InputControl.MoveToAndClick(new Utility.Structs.ZTPoint(startPoint.X + x, startPoint.Y + y));
                Thread.Sleep(500);
                //点确定
                G.Instance.InputControl.Move(0, 0, true, false, false);
@@ -658,8 +657,5 @@
            G.Instance.InputControl.PressKey(RandomUtils.KeyPressDuration, HIDCode.Escape);
            return true;
        }
    }
}
src/RichCreator/Maps/MapInfo.cs
@@ -13,6 +13,12 @@
    /// </summary>
    public abstract class MapInfo
    {
        public MapInfo()
        {
        }
        /// <summary>
        /// 地图名称
        /// </summary>
src/RichCreator/Maps/Skills/SkillMap.cs
@@ -150,7 +150,7 @@
                    {
                        //如果当前选的是tp技能学习(tp技能学习的右侧滚动条跟sp右侧的不一样),则:
                        //选中sp技能学习
                        ZTPoint spPoint = new ZTPoint(lvRect.End.X + 55, lvRect.Start.Y - 80);
                        Utility.Structs.ZTPoint spPoint = new Utility.Structs.ZTPoint(lvRect.End.X + 55, lvRect.Start.Y - 80);
                        G.Instance.InputControl.MoveToAndClick(spPoint);
                        result = FuncUtils.TimeoutCancelableWrap(3000, this.cancellationToken, () => {
@@ -175,7 +175,7 @@
        private bool InitSkills()
        {
            //点击初始化
            ZTPoint initButton = new ZTPoint(this.upKeyRect.Start.X - 37, this.upKeyRect.Start.Y - 86);
            Utility.Structs.ZTPoint initButton = new Utility.Structs.ZTPoint(this.upKeyRect.Start.X - 37, this.upKeyRect.Start.Y - 86);
            G.Instance.InputControl.MoveToAndClick(initButton);
            //是否已打开确认对话框
@@ -188,10 +188,13 @@
                G.Instance.DebugWriter("公告未找到");
                return false;
            }
            //点击确认
            G.Instance.InputControl.Move(0, 0, true, false, false);
            Thread.Sleep(RandomUtils.MouseClickDuration);
            G.Instance.InputControl.Move(0, 0, false, false, false);
            Thread.Sleep(1000);
            
            //是否已打开完毕对话框 
            result = FuncUtils.TimeoutCancelableWrap(3000, this.cancellationToken, () => {
@@ -203,7 +206,7 @@
                return false;
            }
            //点击确认
            ZTPoint okPosition = new ZTPoint(notificationRect.GetCenterPoint().X, notificationRect.End.Y + 70);
            Utility.Structs.ZTPoint okPosition = new Utility.Structs.ZTPoint(notificationRect.GetCenterPoint().X, notificationRect.End.Y + 60);
            G.Instance.InputControl.MoveToAndClick(okPosition);
            Thread.Sleep(RandomUtils.G(500,800));
            return true;
@@ -243,11 +246,11 @@
        private bool SettingTopSkills()
        {
            //物理暴击
            ZTPoint skillPoint = new ZTPoint(lvRect.End.X + 200, lvRect.Start.Y - 42);
            Utility.Structs.ZTPoint skillPoint = new Utility.Structs.ZTPoint(lvRect.End.X + 200, lvRect.Start.Y - 42);
            SettingSkill(skillPoint);
            //物理背击
            skillPoint = new ZTPoint(lvRect.End.X + 280, lvRect.Start.Y - 42);
            skillPoint = new Utility.Structs.ZTPoint(lvRect.End.X + 280, lvRect.Start.Y - 42);
            SettingSkill(skillPoint);
            return true;
        }
@@ -256,28 +259,28 @@
        /// 要点的技能列表
        /// 内部为每个节所相对于节的相对位置
        /// </summary>
        private List<ZTPoint>[] toAddLevelSkills = new List<ZTPoint>[] {
            new List<ZTPoint> (){
                new ZTPoint(762-346,450-237),//疾风之棍棒精通
        private List<Utility.Structs.ZTPoint>[] toAddLevelSkills = new List<Utility.Structs.ZTPoint>[] {
            new List<Utility.Structs.ZTPoint> (){
                new Utility.Structs.ZTPoint(762-346,450-237),//疾风之棍棒精通
            },
            new List<ZTPoint> (){
                new ZTPoint(182,17),//朔风牵引
                new ZTPoint(274,17),//流风决
                new ZTPoint(481-251,342-262),//风鸣冲击
                new ZTPoint(323,82),//游离之风
                new ZTPoint(574-251,409-262),//双翼风刃
                new ZTPoint(574-251,477-262),//风暴之眼
                new ZTPoint(529-251,544-262),//真空旋风破
            new List<Utility.Structs.ZTPoint> (){
                new Utility.Structs.ZTPoint(182,17),//朔风牵引
                new Utility.Structs.ZTPoint(274,17),//流风决
                new Utility.Structs.ZTPoint(481-251,342-262),//风鸣冲击
                new Utility.Structs.ZTPoint(323,82),//游离之风
                new Utility.Structs.ZTPoint(574-251,409-262),//双翼风刃
                new Utility.Structs.ZTPoint(574-251,477-262),//风暴之眼
                new Utility.Structs.ZTPoint(529-251,544-262),//真空旋风破
            },
            new List<ZTPoint> (){
                new ZTPoint(432-251,275-329),//风暴之拳
                new ZTPoint(479-251,342-329),//万象风龙阵
                new ZTPoint(572-251,340-329),//御风之力
                new ZTPoint(433-251,478-329),//风神决
                new ZTPoint(526-251,475-329),//风卷残云
                new ZTPoint(574-251,476-329),//游龙惊风破
                new ZTPoint(431-251,542-329),//九霄风雷
                new ZTPoint(663-295,545-331),//无限风域
            new List<Utility.Structs.ZTPoint> (){
                new Utility.Structs.ZTPoint(432-251,275-329),//风暴之拳
                new Utility.Structs.ZTPoint(479-251,342-329),//万象风龙阵
                new Utility.Structs.ZTPoint(572-251,340-329),//御风之力
                new Utility.Structs.ZTPoint(433-251,478-329),//风神决
                new Utility.Structs.ZTPoint(526-251,475-329),//风卷残云
                new Utility.Structs.ZTPoint(574-251,476-329),//游龙惊风破
                new Utility.Structs.ZTPoint(431-251,542-329),//九霄风雷
                new Utility.Structs.ZTPoint(663-295,545-331),//无限风域
            }
        };
@@ -288,7 +291,7 @@
        private bool SettingSPSkills()
        {
            //选中sp技能学习
            ZTPoint spPoint = new ZTPoint(lvRect.End.X + 55, lvRect.Start.Y - 80);
            Utility.Structs.ZTPoint spPoint = new Utility.Structs.ZTPoint(lvRect.End.X + 55, lvRect.Start.Y - 80);
            G.Instance.InputControl.MoveToAndClick(spPoint);
            ZTRectangle numberLimitArea = new ZTRectangle(lvRect.Start.X-5,lvRect.End.Y,lvRect.End.X+21,lvRect.End.Y+340);
@@ -371,16 +374,16 @@
        private bool SettingTPSkills()
        {
            //选中tp技能学习
            ZTPoint spPoint = new ZTPoint(lvRect.End.X + 253, lvRect.Start.Y - 80);
            Utility.Structs.ZTPoint spPoint = new Utility.Structs.ZTPoint(lvRect.End.X + 253, lvRect.Start.Y - 80);
            G.Instance.InputControl.MoveToAndClick(spPoint);
            ZTPoint[] skills = new ZTPoint[] {
            Utility.Structs.ZTPoint[] skills = new Utility.Structs.ZTPoint[] {
                new ZTPoint(334-296,277-251),//1.第一行第一个
                new ZTPoint(381-296,545-251),//2.第三行第二个
                new ZTPoint(664-296,413-251),//3.第二行倒数第三个
                new ZTPoint(567-296,410-251),//4.第二行倒数第五个
                new ZTPoint(758-296,411-251),//5.第二行倒数第一个
                new Utility.Structs.ZTPoint(334-296,277-251),//1.第一行第一个
                new Utility.Structs.ZTPoint(381-296,545-251),//2.第三行第二个
                new Utility.Structs.ZTPoint(664-296,413-251),//3.第二行倒数第三个
                new Utility.Structs.ZTPoint(567-296,410-251),//4.第二行倒数第五个
                new Utility.Structs.ZTPoint(758-296,411-251),//5.第二行倒数第一个
            };
            for (int i = 0; i < skills.Length; i++)
@@ -397,7 +400,7 @@
        /// <returns></returns>
        private bool Studay()
        {
            ZTPoint studayPoint = new ZTPoint(this.downKeyRect.Start.X-331,this.downKeyRect.End.Y+27);
            Utility.Structs.ZTPoint studayPoint = new Utility.Structs.ZTPoint(this.downKeyRect.Start.X-331,this.downKeyRect.End.Y+27);
            G.Instance.InputControl.MoveToAndClick(studayPoint);
            Thread.Sleep(1000);
            //点击确认
@@ -413,7 +416,7 @@
        /// </summary>
        /// <param name="skillPoint"></param>
        /// <returns></returns>
        private bool SettingSkill(ZTPoint skillPoint)
        private bool SettingSkill(Utility.Structs.ZTPoint skillPoint)
        {
            //84,71
            ZTRectangle limitRect = new ZTRectangle(skillPoint.X-84,skillPoint.Y-71,skillPoint.X+84,skillPoint.Y+71);
@@ -501,7 +504,7 @@
        {
            studayTextRect = ZTRectangle.Empty;
            ZTRectangle innerstudyTextRect = ZTRectangle.Empty;
            ZTPoint openwindowButton = new ZTPoint(this.titleRect.Start.X + 194, this.titleRect.Start.Y + 517);
            Utility.Structs.ZTPoint openwindowButton = new Utility.Structs.ZTPoint(this.titleRect.Start.X + 194, this.titleRect.Start.Y + 517);
            for (int i = 0; i < 2; i++)
            {
                if (this.cancellationToken.IsCancellationRequested)
@@ -575,7 +578,7 @@
                    return false;
                }
                //获取位置,并将鼠标移到位置,显示出技能名
                ZTPoint studayPoint = GetStudaySkillRect(studayTextRect, i).GetCenterPoint();
                Utility.Structs.ZTPoint studayPoint = GetStudaySkillRect(studayTextRect, i).GetCenterPoint();
                G.Instance.InputControl.MoveTo(studayPoint.X, studayPoint.Y, false, false, false);
                Thread.Sleep(1000);
@@ -590,7 +593,7 @@
                    if (skillToExpressMap.ContainsKey(skillIndex))
                    {
                        //要放到技能栏的位置
                        ZTPoint to = GetExpressSkillRect(skillToExpressMap[skillIndex]).GetCenterPoint();
                        Utility.Structs.ZTPoint to = GetExpressSkillRect(skillToExpressMap[skillIndex]).GetCenterPoint();
                        MoveSkill(studayPoint, to);
                        count--;
                        continue;
@@ -613,7 +616,7 @@
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <returns></returns>
        private bool MoveSkill(ZTPoint from, ZTPoint to)
        private bool MoveSkill(Utility.Structs.ZTPoint from, Utility.Structs.ZTPoint to)
        {
            //移动指定位置
            G.Instance.InputControl.MoveTo(from.X, from.Y, false, false, false);
src/RichCreator/Maps/Test/TestMap.cs
@@ -97,9 +97,9 @@
                return false;
            }
            ZTPoint windowCenter = createGroupWindowTextRect.GetCenterPoint();
            G.Instance.InputControl.MoveToAndClick(new ZTPoint(windowCenter.X + 50, windowCenter.Y + 80));
            Utility.Structs.ZTPoint windowCenter = createGroupWindowTextRect.GetCenterPoint();
            G.Instance.InputControl.MoveToAndClick(new Utility.Structs.ZTPoint(windowCenter.X + 50, windowCenter.Y + 80));
            //清空文字
            for (int i = 0; i < 15; i++)
            {
@@ -120,13 +120,13 @@
                G.Instance.InfoWriter("create group ok");
                //点击组队“确定”按钮
                result = FuncUtils.TimeoutCancelableWrap(15 * 60 * 1000,this.cancellationToken, () => {
                    ZTPoint yes = ZTPoint.Empty;
                    ZTPoint no = ZTPoint.Empty;
                    Utility.Structs.ZTPoint yes = Utility.Structs.ZTPoint.Empty;
                    Utility.Structs.ZTPoint no = Utility.Structs.ZTPoint.Empty;
                    bool retFind = GroupCVHelper.FindYaoqingZuduiWindow(out yes, out no, this.GameRect);
                    if (retFind)
                    {
                        G.Instance.InputControl.MoveToAndClick(yes);
                        G.Instance.InfoWriter("other join group ok:"+yes);
                        G.Instance.InfoWriter("other join group ok:"+ yes);
                    }
                    return retFind;
                });
@@ -161,9 +161,9 @@
                return true;
            }
            ZTPoint searchButtonCenerPoint = searchButtonRect.GetCenterPoint();
            Utility.Structs.ZTPoint searchButtonCenerPoint = searchButtonRect.GetCenterPoint();
            //输入组名
            G.Instance.InputControl.MoveToAndClick(new ZTPoint (searchButtonCenerPoint.X-80,searchButtonCenerPoint.Y));
            G.Instance.InputControl.MoveToAndClick(new Utility.Structs.ZTPoint (searchButtonCenerPoint.X-80, searchButtonCenerPoint.Y));
            DeleteAllChar(groupName.Length + 3);
            G.Instance.InputControl.InputString(groupName);
src/RichCreator/RichCreator.csproj
@@ -121,11 +121,10 @@
    <Compile Include="Models\RunningModel.cs" />
    <Compile Include="Models\RunningStep.cs" />
    <Compile Include="StateMachines\KillMonsterStateMachine.cs" />
    <Compile Include="StateMachines\KillMonsterStateResult.cs" />
    <Compile Include="StateMachines\MoveState.cs" />
    <Compile Include="StateMachines\SkillInfo.cs" />
    <Compile Include="StateMachines\SkillQueue.cs" />
    <Compile Include="Maps\MapHouse.cs" />
    <Compile Include="Maps\HouseInfo.cs" />
    <Compile Include="Maps\Lindong\LindongMap.cs" />
    <Compile Include="Maps\MapInfo.cs" />
    <Compile Include="Models\RichCreatorConfig.cs" />
src/RichCreator/StateMachines/KillMonsterStateMachine.cs
@@ -16,40 +16,49 @@
using RichCreator.StateMachines;
using RichCreator.Utilitys;
using static RichCreator.Utilitys.AttackRectangle;
using Utils= RichCreator.Utilitys.Utils;
using Utils = RichCreator.Utilitys.Utils;
using ZTImage.Collections;
namespace RichCreator.Jobs.StateMachines
{
    /// <summary>
    /// 状态动作
    /// </summary>
    /// <param name=""></param>
    /// <param name=""></param>
    /// <param name=""></param>
    /// <returns></returns>
    public delegate KillMonsterStateResult StateAction(Image<Rgb, byte> image, Image<Hsv, byte> hsvImage);
    /// <summary>
    /// 杀怪状态机
    /// </summary>
    public class KillMonsterStateMachine:StateMachineBase
    public class KillMonsterStateMachine : StateMachineBase
    {
        private const Int32 NoMoveMaxMillSecond = 2000;//最大未移动容忍毫秒数
        private StateAction[] states;//状态动作列表
        private MapHouse house;//当前房间
        private HouseInfo house;//当前房间
        private ZTPoint miniMapStart;//小地图区域
        private ZTRectangle gameRect;//游戏区域
        private ZTRectangle GameRect;//游戏区域
        private Int32 preHouseIndex = 0;//上一房间编号
        private MoveState moveState;//移动状态
        private OutOfBounds outOfBounds;//是否在禁区
        private bool exitResult;//退出结果
        private OutOfBounds outOfBounds;//禁区
        private bool isSuccess;//退出结果
        private ZTPoint roleLastPosition=ZTPoint.Empty;//角色最后位置
        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;
@@ -59,26 +68,34 @@
        private Direction stateDoorLevelDirect = Direction.None;
        //定位点方框
        private MultiList<ZTRectangle, Int32> stateLocationRectangle = new MultiList<ZTRectangle, int>();
        //怪
        private ZTPoint[] stateMonsters;
        #endregion
        public KillMonsterStateMachine(MapHouse house, ZTPoint miniMapStart, ZTRectangle gameRect,Int32 preHouseIndex,Int32 runningStep)
        public KillMonsterStateMachine(HouseInfo house, ZTPoint miniMapStart, ZTRectangle gameRect, Int32 preHouseIndex, Int32 runningStep, CancellationToken cancellationToken)
        {
            this.runningStep = runningStep;
            this.house = house;
            this.miniMapStart = miniMapStart;
            this.gameRect = gameRect;
            this.GameRect = gameRect;
            this.preHouseIndex = preHouseIndex;
            moveState = new MoveState(this.gameRect, this.house);
            outOfBounds = new OutOfBounds(this.gameRect,moveState);
            InitStates();
            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);
        }
        private void SetState(KillMonsterStates current, bool capture)
        {
            currentState = current;
            captureScreen = capture;
        }
        /// <summary>
        /// 状态机开始
        /// </summary>
@@ -86,23 +103,17 @@
        /// <param name="cancellationToken"></param>
        /// <param name="timeoutMillSecond"></param>
        /// <returns></returns>
        public ZTResult Work(CancellationToken cancellationToken, Int32 timeoutMillSecond)
        public ZTResult Work(Int32 timeoutMillSecond)
        {
            DateTime expireTime = DateTime.Now.AddMilliseconds(timeoutMillSecond);
            KillMonsterStateResult result = new KillMonsterStateResult(STATE_Start, false);
            if (this.runningStep > RunningStep.None)
            {
                result = new KillMonsterStateResult(STATE_FindMonster, true);
                SetState(KillMonsterStates.FindMonster, true);
            }
            System.Drawing.Bitmap bitmap;
            //原图
            Image<Rgb, byte> image = null;
            //色彩hsv
            Image<Hsv, byte> hsvImage = new Image<Hsv, byte>(gameRect.End.X - gameRect.Start.X + 1, gameRect.End.Y - gameRect.Start.Y + 1);
            while (true)
            {
                byte currentState = result.NextState;
                if (cancellationToken.IsCancellationRequested)
                {
                    G.Instance.DebugWriter("取消刷图");
@@ -116,216 +127,425 @@
                    this.moveState.StopMove();
                    return ZTResult.Timeout;
                }
                if (result.NextState == STATE_Exit)
                {
                    G.Instance.DebugWriter("退出状态");
                    this.moveState.StopMove();
                    if (this.exitResult)
                    {
                        return ZTResult.Success;
                    }
                    return ZTResult.Failed;
                }
                bool refreshScreen = result.RefreshScreen;
                if (refreshScreen)
                if (captureScreen)
                {
                    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));
                        CvInvoke.CvtColor(image, hsvImage, Emgu.CV.CvEnum.ColorConversion.Rgb2Hsv);
                    }
                    if (this.house.Index != 15)
                    {
                        //计算是否进入其它房间
                        Int32 houseIndex;
                        if (!LindongCVHelper.GetCurrentHouseIndex(out houseIndex, image, this.miniMapStart))
                        if (image != null)
                        {
                            //得不到房间
                            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))
                            {
                                return ZTResult.Failed;
                            }
                            image.Dispose();
                        }
                        if (houseIndex != this.house.Index)
                        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));
                        imageIsChange = true;
                    }
                }
                switch (currentState)
                {
                    case KillMonsterStates.Start:
                        //开始
                        SingleEntryHouseSkill.ReleaseSkill(this.house.Index, this.preHouseIndex, this.moveState);
                        SetState(KillMonsterStates.IsLastHouse, true);
                        break;
                    case KillMonsterStates.IsLastHouse:
                        //是否最后一个房间
                        if (!imageIsChange)
                        {
                            this.moveState.StopMove();
                            //图片没变,不用判断
                            SetState(KillMonsterStates.FindRole, false);
                            break;
                        }
                        if (this.house.Index == 15)
                        {
                            SetState(KillMonsterStates.HasRewardWindow, false);
                        }
                        else
                        {
                            SetState(KillMonsterStates.IsOtherHouse, false);
                        }
                        break;
                    case KillMonsterStates.HasRewardWindow:
                        //是否有奖励界面
                        if (DnfCVHelper.IsJiangli(image, this.GameRect))
                        {
                            SetState(KillMonsterStates.TurnAroundCard, false);
                        }
                        else
                        {
                            SetState(KillMonsterStates.IsCompletePage, false);
                        }
                        break;
                    case KillMonsterStates.TurnAroundCard:
                        //翻牌
                        Fanpai();
                        Thread.Sleep(5000);
                        this.isSuccess = true;
                        SetState(KillMonsterStates.Exit, false);
                        break;
                    case KillMonsterStates.IsCompletePage:
                        //是否刷完界面
                        if (DnfCVHelper.IsCompleteRoom(image, this.GameRect))
                        {
                            this.isSuccess = true;
                            SetState(KillMonsterStates.Exit, false);
                        }
                        else
                        {
                            SetState(KillMonsterStates.FindRole, false);
                        }
                        break;
                    case KillMonsterStates.IsOtherHouse:
                        //是否进入其它房间
                        if (HouseIsChange())
                        {
                            this.isSuccess = true;
                            SetState(KillMonsterStates.Exit, false);
                        }
                        else
                        {
                            //是否需要截图
                            SetState(KillMonsterStates.FindRole, false);
                        }
                        break;
                    case KillMonsterStates.FindRole:
                        //主角
                        CvInvoke.CvtColor(image, hsvImage, Emgu.CV.CvEnum.ColorConversion.Rgb2Hsv);
                        //定位点
                        if (!DnfCVHelper.GetLocationPoint(out stateLocationRectangle, hsvImage, this.GameRect))
                        {
                            //找不到定位点
                            G.Instance.InfoWriter("找不到定位点");
                            SetState(KillMonsterStates.IsLastHouse, true);
                            break;
                        }
                        this.stateRolePosition = DnfCVHelper.FindRole(hsvImage, this.GameRect);
                        if (this.stateRolePosition == ZTPoint.Empty)
                        {
                            SetState(KillMonsterStates.FindRoleMove, false);
                        }
                        else
                        {
                            if (this.moveState.IsFindRoleMoving)
                            {
                                this.moveState.StopMove();
                            }
                            SetState(KillMonsterStates.FindMonster, false);
                        }
                        break;
                    case KillMonsterStates.FindRoleMove:
                        //todo:让主角移动(原:有怪攻击一下,无怪移动一下)
                        FindRoleMove();
                        break;
                    case KillMonsterStates.FindMonster:
                        //找怪
                        this.stateMonsters = LindongCVHelper.FindMonster(hsvImage, this.GameRect);
                        if (this.stateMonsters.Length > 0)
                        {
                            G.Instance.DebugWriter(string.Format("已找到{0}个怪", this.stateMonsters.Length));
                            SetState(KillMonsterStates.CalcAttackDistance, false);
                        }
                        else
                        {
                            SetState(KillMonsterStates.PickupThing, false);
                        }
                        break;
                    case KillMonsterStates.PickupThing:
                        //拾取物品
                        SetState(KillMonsterStates.FindDoor, false);
                        //todo: PickupThing();
                        break;
                    case KillMonsterStates.FindDoor:
                        //查找门, 是否找到门
                        FindDoor();
                        break;
                    case KillMonsterStates.EntryDoor:
                        //向门移动, 进门
                        EntryDoor();
                        break;
                    case KillMonsterStates.FindDoorMove:
                        //todo:找门移动
                        FindDoorMove();
                        break;
                    case KillMonsterStates.CalcAttackDistance:
                        //判断使用何技能,计算攻击移动距离, 是否需要移动
                        CalcAttackDistance();
                        break;
                    case KillMonsterStates.ReleaseSkill:
                        //调整朝向, 释放技能,
                        ReleaseSkill();
                        break;
                    case KillMonsterStates.AttackMove:
                        //todo:攻击移动
                        AttackMove();
                        break;
                    case KillMonsterStates.Exit:
                        //结束
                        G.Instance.DebugWriter("退出状态");
                        this.moveState.StopMove();
                        if (this.isSuccess)
                        {
                            return ZTResult.Success;
                        }
                    }
                        return ZTResult.Failed;
                }
                StateAction action = states[currentState];
                result =action(image, hsvImage);
                if (refreshScreen)
                {
                    image.Dispose();
                }
                G.Instance.DebugWriter("next state:" + result.NextState.ToString());
                G.Instance.DebugWriter("next state:" + currentState.ToString());
            }
        }
        #region States
        private const byte STATE_FindMonster = 0;//找怪
        private const byte STATE_PrepareReleaseSkill = 1;//释放技能预处理,计算位置
        private const byte STATE_ReleaseSkill = 2;//释放技能
        private const byte STATE_DetectDoorIsOpen = 3;//查找进入下一房间的门是否开了
        private const byte STATE_MoveToDoor = 4;//移动进门
        private const byte STATE_Start = 8;//开始状态
        private const byte STATE_Exit = 9;//完成状态
        #region States
        /// <summary>
        /// 初始化状态
        /// 让主角移动(原:有怪攻击一下,无怪移动一下)
        /// </summary>
        private void InitStates()
        private void FindRoleMove()
        {
            //状态列表
            states = new StateAction[STATE_Exit+1];
            states[STATE_FindMonster] = FindMonster;
            states[STATE_PrepareReleaseSkill] = PrepareReleaseSkill;
            states[STATE_ReleaseSkill] = ReleaseSkill;
            states[STATE_DetectDoorIsOpen] = DetectDoorIsOpen;
            states[STATE_MoveToDoor] = MoveToDoor;
            states[STATE_Start] = StartState;
        }
            this.moveState.FindRoleMove();
            SetState(KillMonsterStates.FindRole, true);
        private KillMonsterStateResult StartState(Image<Rgb, byte> image, Image<Hsv, byte> hsvImage)
        {
            SingleEntryHouseSkill.ReleaseSkill(this.house.Index, this.preHouseIndex,this.moveState);
            return new KillMonsterStateResult(STATE_FindMonster, true);
        }
        /// <summary>
        /// 0.找怪
        /// </summary>
        /// <param name="image"></param>
        /// <param name="hsvImage"></param>
        /// <returns></returns>
        private KillMonsterStateResult FindMonster(Image<Rgb, byte> image, Image<Hsv, byte> hsvImage)
        {
            #region coll
            //while (true)
            //if (this.stateMonsters.Length > 0)
            //{
            //    image = ScreenCapture.Instance.CaptureScreenReturnImage();
            //    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));
            //    CvInvoke.CvtColor(image, hsvImage, Emgu.CV.CvEnum.ColorConversion.Rgb2Hsv);
            //    ZTPoint start=DnfCVHelper.FindRole(hsvImage, this.gameRect);
            //    Int32 dur = RandomUtils.KeyPressDuration;
            //    G.Instance.InputControl.PutDown(false, false, false, false, false, false, false, false,HIDCode.LeftArrow);
            //    Thread.Sleep(dur);
            //    G.Instance.InputControl.PutDown(false, false, false, false, false, false, false, false);
            //    Thread.Sleep(dur);
            //    G.Instance.InputControl.PutDown(false, false, false, false, false, false, false, false, HIDCode.LeftArrow);
            //    Thread.Sleep(dur);
            //    G.Instance.InputControl.PutDown(false, false, false, false, false, false, false, false);
            //    image = ScreenCapture.Instance.CaptureScreenReturnImage();
            //    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));
            //    CvInvoke.CvtColor(image, hsvImage, Emgu.CV.CvEnum.ColorConversion.Rgb2Hsv);
            //    ZTPoint end = DnfCVHelper.FindRole(hsvImage, this.gameRect);
            //    G.Instance.InfoWriter($"dur:{dur},start:{start},end{end},distance:{end.X - start.X}");
            //    Thread.Sleep(2000);
            //    this.moveState.StopMove();
            //    G.Instance.DebugWriter("找不到角色,Send X");
            //    G.Instance.InputControl.PressKey(1000, HIDCode.X);
            //    SetState(KillMonsterStates.FindMonster, true);
            //    return;
            //}
            #endregion
            //怪
            this.stateMonsters = LindongCVHelper.FindMonster(hsvImage,this.gameRect);
            //主角
            this.stateRolePosition = DnfCVHelper.FindRole(hsvImage, this.gameRect);
            //定位点
            DnfCVHelper.GetLocationPoint(out stateLocationRectangle, hsvImage, this.gameRect);
            //else
            //{
            //    this.moveState.FindRoleMove();
            //    SetState(KillMonsterStates.IsLastHouse, true);
            //}
        }
            if (this.stateMonsters.Length > 0)
        /// <summary>
        /// 拾取物品
        /// </summary>
        private void PickupThing()
        {
            //拾取物品,获取最近一个物品位置并步行过去
            ZTPoint thingItemPosition = GetNearlyThingItem(image, stateRolePosition);
            if (thingItemPosition != ZTPoint.Empty)
            {
                G.Instance.DebugWriter(string.Format("已找到{0}个怪", this.stateMonsters.Length));
                //未找到主角
                if (stateRolePosition == ZTPoint.Empty)
                if (this.moveState.IsMoving && !this.moveState.IsPickupMoving)
                {
                    this.moveState.StopMove();
                    G.Instance.DebugWriter("找不到角色,Send X");
                    G.Instance.InputControl.PressKey(1000, HIDCode.X);
                    return new KillMonsterStateResult(STATE_FindMonster, true);
                }
                return new KillMonsterStateResult(STATE_PrepareReleaseSkill, false);
                this.moveState.PickupMove(this.stateRolePosition, thingItemPosition);
                //return new KillMonsterStateResult(STATE_FindMonster, true);
            }
            if (this.moveState.IsPickupMoving)
            {
                this.moveState.StopMove();
            }
        }
        /// <summary>
        /// 查找门, 是否找到门
        /// </summary>
        private void FindDoor()
        {
            //查找真实的门
            this.stateDoorPosition = LindongCVHelper.FindDoor(out stateDoorLevelDirect, hsvImage, this.house.DoorDirection, this.GameRect);
            if (this.stateDoorPosition != ZTPoint.Empty)
            {
                //找到门,向门移动
                if (this.moveState.IsFindDoorMoving)
                {
                    this.moveState.StopMove();
                }
                G.Instance.InfoWriter("已找到门,位置:" + stateDoorPosition.ToString());
                SetState(KillMonsterStates.EntryDoor, false);
            }
            else
            {
                //未查找到主角
                if (stateRolePosition == ZTPoint.Empty)
                {
                    if (this.moveState.IsMoving && !this.moveState.IsFindRoleMoving)
                    {
                        this.moveState.StopMove();
                    }
                    //是否刷完
                    if (IsComplete(image))
                    {
                        return new KillMonsterStateResult(STATE_Exit, false);
                    }
                    this.moveState.FindRoleMove();
                    return new KillMonsterStateResult(STATE_FindMonster, true);
                }
                return new KillMonsterStateResult(STATE_DetectDoorIsOpen, true);
                //未找到门,循环移动
                SetState(KillMonsterStates.FindDoorMove, false);
            }
        }
        /// <summary>
        /// 向门移动, 进门
        /// </summary>
        private void EntryDoor()
        {
            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.IsLastHouse, true);
            return;
        }
        /// <summary>
        /// 找门移动
        /// </summary>
        private void FindDoorMove()
        {
            Int32 areaID = 0;
            if (this.outOfBounds.InOutOfBound(this.house.Index, stateRolePosition, out areaID))
            {
                this.outOfBounds.MoveToCommonBound(areaID);
            }
            else
            {
                this.moveState.FindDoorMove(stateRolePosition);
            }
            SetState(KillMonsterStates.IsLastHouse, true);
        }
        private DateTime FindRoleLastNoMoveTime = DateTime.MaxValue;//最后没移动时间
        private bool FindRoleLastNoMoveStart = false;//没移动是否开始计时
        private ZTSize attackMoveDistance = ZTSize.Empty;
        private HIDCode roleDirection = HIDCode.NoEvent;
        /// <summary>
        /// 1.释放技能预处理,计算位置
        /// 判断使用何技能,计算攻击移动距离, 是否需要移动
        /// </summary>
        /// <param name="image"></param>
        /// <param name="hsvImage"></param>
        /// <returns></returns>
        private KillMonsterStateResult PrepareReleaseSkill(Image<Rgb, byte> image, Image<Hsv, byte> hsvImage)
        private void CalcAttackDistance()
        {
            if (this.moveState.IsMoving&&!this.moveState.IsAttackMoving)
            {
                this.moveState.StopMove();
            }
            SkillInfo skill = this.house.Skills.SyncPeek();
            SkillInfo attackSkill = this.house.Skills.SyncPeek();
            //计算攻击移动距离
            HIDCode dir = HIDCode.RightArrow;
            bool needMove = false;
            ZTSize moveDistance = AttackRectangle.GetMoveDistance(this.gameRect, stateRolePosition, stateMonsters, skill, out dir, out needMove);
            attackMoveDistance = AttackRectangle.GetMoveDistance(this.GameRect, stateRolePosition, stateMonsters, attackSkill, out roleDirection, 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()));
                return new KillMonsterStateResult(STATE_ReleaseSkill, false);
                G.Instance.DebugWriter(string.Format("不需移动直接发技能,距离:{0}", attackMoveDistance.ToString()));
                SetState(KillMonsterStates.ReleaseSkill, false);
            }
            else
            {
                SetState(KillMonsterStates.AttackMove, false);
            }
        }
        /// <summary>
        /// 调整朝向, 释放技能
        /// </summary>
        private void ReleaseSkill()
        {
            SkillInfo skill = this.house.Skills.SyncDeQueue();
            this.roleLastPosition = ZTPoint.Empty;
            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++)
                {
                    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.IsLastHouse, true);
        }
        /// <summary>
        /// 攻击移动
        /// </summary>
        private void AttackMove()
        {
            SkillInfo attackSkill = this.house.Skills.SyncPeek();
            //没有移动,可能有障碍物
            if (stateRolePosition == this.roleLastPosition)
            {
@@ -350,203 +570,10 @@
                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);
            return new KillMonsterStateResult(STATE_FindMonster, true);
        }
        /// <summary>
        /// 2.释放技能
        /// </summary>
        /// <param name="image"></param>
        /// <param name="hsvImage"></param>
        /// <returns></returns>
        private KillMonsterStateResult ReleaseSkill(Image<Rgb, byte> image, Image<Hsv, byte> hsvImage)
        {
            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));
            return new KillMonsterStateResult(STATE_FindMonster, true);
        }
        /// <summary>
        /// 3.检测进入下一房间的门是否开了
        /// </summary>
        /// <returns></returns>
        private KillMonsterStateResult DetectDoorIsOpen(Image<Rgb, byte> image, Image<Hsv, byte> hsvImage)
        {
            if (this.moveState.IsAttackMoving|| this.moveState.IsFindRoleMoving)
            {
                this.moveState.StopMove();
            }
            ////查找当前房间编号,看是否进入其它房间
            //Int32 houseIndex;
            //if (!LindongCVHelper.GetCurrentHouseIndex(out houseIndex, image, this.miniMapStart))
            //{
            if (IsComplete(image))
            {
                return new KillMonsterStateResult(STATE_Exit, false);
            }
            //    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;
                //找到门,向门移动
                return new KillMonsterStateResult(STATE_MoveToDoor, false);
            }
            else
            {
                //未找到门,循环移动
                Int32 areaID = 0;
                if (this.outOfBounds.InOutOfBound(this.house.Index, stateRolePosition, out areaID))
                {
                    this.outOfBounds.MoveToCommonBound(areaID);
                }
                else
                {
                    this.moveState.FindDoorMove(stateRolePosition);
                }
            }
            return new KillMonsterStateResult(STATE_FindMonster, true);
        }
        private const Int32 XDoorLevelOffset = 200;
        private const Int32 YDoorLevelOffset = 100;
        /// <summary>
        /// 4.找门
        /// </summary>
        /// <param name="image"></param>
        /// <param name="hsvImage"></param>
        /// <returns></returns>
        private KillMonsterStateResult MoveToDoor(Image<Rgb, byte> image, Image<Hsv, byte> hsvImage)
        {
            Int32 limitLine = 0;
            Int32 diff = 0;
            //传过来人物坐标和门的坐标,根据门的朝向计算人物走向
            switch (stateDoorLevelDirect)
            {
                case Direction.Up:
                    //门在上方
                    limitLine = stateDoorPosition.Y + YDoorLevelOffset;
                    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 - XDoorLevelOffset;
                    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 - YDoorLevelOffset;
                    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 + XDoorLevelOffset;
                    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;
            }
            return new KillMonsterStateResult(STATE_DetectDoorIsOpen, true);
            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);
        }
        #endregion
@@ -555,9 +582,9 @@
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        public ZTPoint GetNearlyThingItem(Image<Rgb, byte> image,ZTPoint rolePosition)
        public ZTPoint GetNearlyThingItem(Image<Rgb, byte> image, ZTPoint rolePosition)
        {
            List<ZTPoint> points=DnfCVHelper.GetThingItemPoints(image, this.gameRect);
            List<ZTPoint> points = DnfCVHelper.GetThingItemPoints(image, this.GameRect);
            if (points.Count <= 0)
            {
                return ZTPoint.Empty;
@@ -567,7 +594,7 @@
            {
                return points[0];
            }
            double distance = 0;
            ZTPoint result = ZTPoint.Empty;
            for (int i = 0; i < points.Count; i++)
@@ -589,39 +616,8 @@
            return result;
        }
        /// <summary>
        /// 是否完成
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        public bool IsComplete(Image<Rgb,byte> image)
        {
            if (this.house.IsEnd)
            {
                if (DnfCVHelper.IsJiangli(image, this.gameRect))
                {
                    //翻牌
                    this.moveState.StopMove();
                    Fanpai();
                    Thread.Sleep(5000);
                    this.exitResult = true;
                    return true;
                }
                if (DnfCVHelper.IsCompleteRoom(image, this.gameRect))
                {
                    //已经刷完
                    this.moveState.StopMove();
                    this.exitResult = true;
                    return true;
                }
            }
            return false;
        }
        #region 翻牌
        /// <summary>
        /// 牌的位置
        /// </summary>
@@ -648,34 +644,75 @@
        {
            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));
            ZTPoint willPosition = this.GameRect.Start.Add(CardList[number - 1]);
            G.Instance.InputControl.MoveToAndClick(RandomUtils.PointRange(willPosition, 10));
            //判断黄金版是否可以翻
            if (DnfCVHelper.HasMowangqiyueCard(this.gameRect))
            if (DnfCVHelper.HasMowangqiyueCard(this.GameRect))
            {
                number = RandomUtils.G(5, 8);
                willPosition = this.gameRect.Start.Add(CardList[number - 1]);
                willPosition = this.GameRect.Start.Add(CardList[number - 1]);
                G.Instance.InputControl.MoveToAndClick(RandomUtils.PointRange(willPosition, 10));
            }
        }
        #endregion
        /// <summary>
        /// 是否改变房间
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private bool HouseIsChange()
        {
            Int32 houseIndex;
            if (!LindongCVHelper.GetCurrentHouseIndex(out houseIndex, image, this.miniMapStart))
            {
                //得不到房间
                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("找不到默认房间");
                }
            }
            if (houseIndex != this.house.Index)
            {
                this.moveState.StopMove();
                return true;
            }
            return false;
        }
        /// <summary>
        /// 杀怪状态
        /// </summary>
        public enum KillMonsterStates:Int32
        public enum KillMonsterStates : Int32
        {
                FindMonster = 0,//找怪
                PrepareReleaseSkill = 1,//释放技能预处理,计算位置
                ReleaseSkill = 2,//释放技能
                DetectDoorIsOpen = 3,//查找进入下一房间的门是否开了
                MoveToDoor = 4,//移动进门
                Start = 8,//开始状态
                Exit = 9,//完成状态
    }
            Start,//开始状态
            Exit,//完成状态
            IsLastHouse,//是否最后一个房间
            HasRewardWindow,//是否有奖励界面
            TurnAroundCard,//翻牌
            IsCompletePage,//是否刷完界面
            IsOtherHouse,//是否进入其它房间
            FindRole,//找主角
            FindRoleMove,//让主角移动(原:有怪攻击一下,无怪移动一下)
            FindMonster,//找怪
            PickupThing,//拾取物品
            FindDoor,//查找门, 是否找到门
            EntryDoor,//向门移动, 进门
            FindDoorMove,//找门移动
            CalcAttackDistance,//判断使用何技能,计算攻击移动距离, 是否需要移动
            ReleaseSkill,//调整朝向, 释放技能,
            AttackMove,//攻击移动
        }
    }
}
src/RichCreator/StateMachines/KillMonsterStateMachine_old.cs
New file
@@ -0,0 +1,670 @@
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
{
    /// <summary>
    /// 杀怪状态机
    /// </summary>
    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<ZTRectangle, Int32> stateLocationRectangle = new MultiList<ZTRectangle, int>();
        //怪
        private ZTPoint[] stateMonsters;
        private System.Drawing.Bitmap bitmap = null;
        //原图
        private Image<Rgb, byte> image = null;
        //色彩hsv
        private Image<Hsv, byte> 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<Hsv, byte>(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;
        }
        /// <summary>
        /// 状态机开始
        /// </summary>
        /// <param name="gameRect"></param>
        /// <param name="cancellationToken"></param>
        /// <param name="timeoutMillSecond"></param>
        /// <returns></returns>
        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<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));
                    }
                    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);
        }
        /// <summary>
        /// 0.找怪
        /// </summary>
        /// <param name="image"></param>
        /// <param name="hsvImage"></param>
        /// <returns></returns>
        private void FindMonster(Image<Rgb, byte> image, Image<Hsv, byte> 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;//没移动是否开始计时
        /// <summary>
        /// 1.释放技能预处理,计算位置
        /// </summary>
        /// <returns></returns>
        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;
        }
        /// <summary>
        /// 2.释放技能
        /// </summary>
        /// <returns></returns>
        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;
        }
        /// <summary>
        /// 3.检测进入下一房间的门是否开了
        /// </summary>
        /// <returns></returns>
        private void DetectDoorIsOpen(Image<Rgb, byte> image, Image<Hsv, byte> 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;
        }
        /// <summary>
        /// 4.找门
        /// </summary>
        /// <returns></returns>
        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
        /// <summary>
        /// 得到最近的物品
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        public ZTPoint GetNearlyThingItem(Image<Rgb, byte> image,ZTPoint rolePosition)
        {
            List<ZTPoint> 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;
        }
        /// <summary>
        /// 是否完成
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        public bool IsComplete(Image<Rgb,byte> 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 翻牌
        /// <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(364,570),
            new ZTPoint(561,570),
            new ZTPoint(744,570),
            new ZTPoint(924,570),
        };
        /// <summary>
        /// 翻牌
        /// 1-4
        /// 5-8
        /// </summary>
        /// <param name="number"></param>
        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
        /// <summary>
        /// 是否改变房间
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        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<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("找不到默认房间");
                }
            }
            if (houseIndex != this.house.Index)
            {
                this.moveState.StopMove();
                return true;
            }
            return false;
        }
        /// <summary>
        /// 杀怪状态
        /// </summary>
        public enum KillMonsterStates:Int32
        {
                FindMonster = 0,//找怪
                PrepareReleaseSkill = 1,//释放技能预处理,计算位置
                ReleaseSkill = 2,//释放技能
                DetectDoorIsOpen = 3,//查找进入下一房间的门是否开了
                MoveToDoor = 4,//移动进门
                Start = 8,//开始状态
                Exit = 9,//完成状态
    }
    }
}
src/RichCreator/StateMachines/KillMonsterStateResult.cs
File was deleted
src/RichCreator/StateMachines/MoveState.cs
@@ -20,7 +20,7 @@
        private const Int32 PaddingLeft = 140;//左边框内边距
        private const Int32 PaddingRight = 140;//右边框内边距
        public MoveState(ZTRectangle gameRect, MapHouse house)
        public MoveState(ZTRectangle gameRect, HouseInfo house)
        {
            this.gameRect = gameRect;
            this.house = house;
@@ -93,11 +93,11 @@
        private Int32 maxCenterLineY;
        private Int32 centerLineErrorRange = 35;//中间性可允许的误差
        private MapHouse house;
        private HouseInfo house;
        private ZTRectangle gameRect = ZTRectangle.Empty;
        
        private HIDCode moveKey = HIDCode.NoEvent;
        private MoveIntent movingIntent = MoveIntent.ToAttack;//移动意图
        private MoveIntent movingIntent = MoveIntent.AttackMove;//移动意图
        private MoveMethod movingMethod= MoveMethod.Vertical;//移动方式,默认垂直移动
        private ZTSize movingDistance;//移动距离
@@ -126,10 +126,10 @@
        public enum MoveIntent
        {
            None,//没移动
            ToAttack,//去攻击
            ToFindDoor,//去找门
            ToFindRole,//找主角
            ToPickup//去拾取
            AttackMove,//去攻击
            FindDoorMove,//去找门
            FindRoleMove,//找主角
            PickupMove//去拾取
        }
        /// <summary>
@@ -151,7 +151,7 @@
        {
            get
            {
                if (IsMoving && movingIntent == MoveIntent.ToAttack)
                if (IsMoving && movingIntent == MoveIntent.AttackMove)
                {
                    return true;
                }
@@ -167,7 +167,7 @@
        {
            get
            {
                if (IsMoving && movingIntent == MoveIntent.ToFindDoor)
                if (IsMoving && movingIntent == MoveIntent.FindDoorMove)
                {
                    return true;
                }
@@ -184,7 +184,7 @@
        {
            get
            {
                if (IsMoving && movingIntent == MoveIntent.ToFindRole)
                if (IsMoving && movingIntent == MoveIntent.FindRoleMove)
                {
                    return true;
                }
@@ -201,7 +201,7 @@
        {
            get
            {
                if (IsMoving && movingIntent == MoveIntent.ToPickup)
                if (IsMoving && movingIntent == MoveIntent.PickupMove)
                {
                    return true;
                }
@@ -217,11 +217,10 @@
        public void AttackMove(ZTSize moveDistance)
        {
            PutKey(moveDistance);
            movingIntent = MoveIntent.ToAttack;
            movingIntent = MoveIntent.AttackMove;
        }
        private Int32 RandomDirRun = 0;//随机行走的方向
        private const Int32 FindRoleMaxDelayMillSecond = 1000;//找角色开始移动最大延迟
        private DateTime FindRoleMoveTimeout = DateTime.MinValue;//方向移动过期时间
        private DateTime FindRoleStartTimeout = DateTime.MinValue;//开始查找主角移动过期时间
        /// <summary>
@@ -230,6 +229,11 @@
        /// <param name="moveDistance"></param>
        public void FindRoleMove()
        {
            if (IsMoving && !IsFindRoleMoving)
            {
                StopMove();
            }
            const Int32 FindRoleMaxDelayMillSecond = 1000;//找角色开始移动最大延迟
            bool recomputationTimeoutTime = false;
            //延迟开始找角色
            if (!IsMoving)
@@ -306,10 +310,9 @@
                G.Instance.InputControl.PutDown(false, false, false, false, false, false, false, false, dirKey);
                moveKey = dirKey;
            }
            movingIntent = MoveIntent.ToFindRole;
            movingIntent = MoveIntent.FindRoleMove;
        }
        /// <summary>
        /// 拾起物品移动
        /// </summary>
@@ -327,11 +330,11 @@
            //G.Instance.DebugWriter("pickup distance:" + moveDistance.ToString());
            PutKey(moveDistance);
            movingIntent = MoveIntent.ToPickup;
            movingIntent = MoveIntent.PickupMove;
        }
        /// <summary>
        /// 找门找怪移动
        /// 找门移动
        /// </summary>
        /// <param name="rolePosition"></param>
        public void FindDoorMove(ZTPoint rolePosition)
@@ -357,7 +360,7 @@
            }
            
            PutKey(movingDistance);
            movingIntent = MoveIntent.ToFindDoor;
            movingIntent = MoveIntent.FindDoorMove;
        }
src/RichCreator/configs/RichCreator.config
@@ -7,8 +7,8 @@
  <NotificationWechat>true</NotificationWechat>
    <UserName1>1258493488</UserName1>
    <Password1>cc11111111</Password1>
    <UserName2>2228607100</UserName2>
    <Password2>a5m1nf0g00d</Password2>
    <!--<UserName2>2228607100</UserName2>
    <Password2>a5m1nf0g00d</Password2>-->
    <UserName3></UserName3>
    <Password3></Password3>
</RichCreatorConfig>
src/test/Program.cs
@@ -4,63 +4,66 @@
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using RichCreator.Utility.Structs;
using RichCreator.Utility;
using System.Drawing;
using RichCreator.Utility.Captures;
using static test.Graphics;
using RichCreator.Utility.PathFinding;
namespace test
{
    public class person
    {
        public int age { get; set; }
    }
    class Program
    {
        static void GetN(person p)
        {
            p = new person();
            p.age = 2;
        }
        //static void GetN(person p)
        //{
        //    p = new person();
        //    p.age = 2;
        //}
        static void Main(string[] args)
        {
            ZTPoint A = new ZTPoint(0, 1);
            ZTPoint B = new ZTPoint(1, 0);
            ZTPoint C = new ZTPoint(3, 0);
            ZTPoint D = new ZTPoint(4, 1);
            ZTPoint E = new ZTPoint(3, 2);
            ZTPoint F = new ZTPoint(2, 1);
            ZTPoint G = new ZTPoint(1, 2);
            var edges = new List<Tuple<ZTPoint, ZTPoint, double>>()
            {
                new Tuple<ZTPoint,ZTPoint,double>(A,B,12),
                new Tuple<ZTPoint,ZTPoint,double>(A,F,16),
                new Tuple<ZTPoint,ZTPoint,double>(A,G,14),
                new Tuple<ZTPoint,ZTPoint,double>(B,F,7),
                new Tuple<ZTPoint,ZTPoint,double>(B,C,10),
                new Tuple<ZTPoint,ZTPoint,double>(G,F,9),
                new Tuple<ZTPoint,ZTPoint,double>(G,E,8),
                new Tuple<ZTPoint,ZTPoint,double>(F,C,6),
                new Tuple<ZTPoint,ZTPoint,double>(F,E,2),
                new Tuple<ZTPoint,ZTPoint,double>(C,D,3),
                new Tuple<ZTPoint,ZTPoint,double>(C,E,5),
                new Tuple<ZTPoint,ZTPoint,double>(E,D,4),
            };
            var dij = new Dijkstra(edges);
            var path = dij.Find(D, G);
            for (int i = 0; i < path.Count; i++)
            {
                Console.WriteLine(path[i].ToString());
            }
            //ZTPoint A = new ZTPoint(0, 1);
            //ZTPoint B = new ZTPoint(1, 0);
            //ZTPoint C = new ZTPoint(3, 0);
            //ZTPoint D = new ZTPoint(4, 1);
            //ZTPoint E = new ZTPoint(3, 2);
            //ZTPoint F = new ZTPoint(2, 1);
            //ZTPoint G = new ZTPoint(1, 2);
            //var edges = new List<Tuple<ZTPoint, ZTPoint, double>>()
            //{
            //    new Tuple<ZTPoint,ZTPoint,double>(A,B,12),
            //    new Tuple<ZTPoint,ZTPoint,double>(A,F,16),
            //    new Tuple<ZTPoint,ZTPoint,double>(A,G,14),
            //    new Tuple<ZTPoint,ZTPoint,double>(B,F,7),
            //    new Tuple<ZTPoint,ZTPoint,double>(B,C,10),
            //    new Tuple<ZTPoint,ZTPoint,double>(G,F,9),
            //    new Tuple<ZTPoint,ZTPoint,double>(G,E,8),
            //    new Tuple<ZTPoint,ZTPoint,double>(F,C,6),
            //    new Tuple<ZTPoint,ZTPoint,double>(F,E,2),
            //    new Tuple<ZTPoint,ZTPoint,double>(C,D,3),
            //    new Tuple<ZTPoint,ZTPoint,double>(C,E,5),
            //    new Tuple<ZTPoint,ZTPoint,double>(E,D,4),
            //};
            //var dij = new Dijkstra(edges);
            //var path = dij.Find(D, G);
            //for (int i = 0; i < path.Count; i++)
            //{
            //    Console.WriteLine(path[i].ToString());
            //}
            Console.WriteLine("finish!~");
src/test/test.csproj
@@ -66,12 +66,6 @@
    <None Include="App.config" />
    <None Include="packages.config" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\RichCreator.Utility\RichCreator.Utility.csproj">
      <Project>{ceeff4d3-cc6f-4afe-85fe-e590c87a9972}</Project>
      <Name>RichCreator.Utility</Name>
    </ProjectReference>
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <Import Project="..\packages\EMGU.CV.4.1.0.3420\build\EMGU.CV.targets" Condition="Exists('..\packages\EMGU.CV.4.1.0.3420\build\EMGU.CV.targets')" />
  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">