脫機按鍵外掛

一、獲取指定座標的顏色

       在遊戲中,怪物的血是顯示在一個固定的地方的,所以,只要這個點沒有血,那麼表示當前沒有怪可攻擊,意思就是可以找怪了,但是這個座標是多少我都不知道。於是,我在遊戲中截了下屏,並保存了圖片,把它設爲桌面背景色,哈哈,我真是太聰明啦~~在程序中BUTTON下寫一行:lbpoint.Text = Cursor.Position.X.ToString() + "," + Cursor.Position.Y.ToString();把鼠標放到血是最左邊,也就是怪物血最少的那裏,按了下空格,嘿嘿,坐標出來了:293, 35,當然是不是一次完成的,多幾下就差不多了。

現在坐標出來了,怎麼取它的色呢?經過一陣“擺渡”,原來windows的一個API可以實現這樣的功能,OK,那就用它吧,代碼如下:

[DllImport("gdi32.dll")]
        static public extern uint GetPixel(IntPtr hDC, int XPos, int YPos);

        [DllImport("gdi32.dll")]
        static public extern IntPtr CreateDC(string driverName, string deviceName, string output, IntPtr lpinitData);

        [DllImport("gdi32.dll")]
        static public extern bool DeleteDC(IntPtr DC);

        static public byte GetRValue(uint color)
        {
            return (byte)color;
        }

        static public byte GetGValue(uint color)
        {
            return ((byte)(((short)(color)) >> 8));
        }

        static public byte GetBValue(uint color)
        {
            return ((byte)((color) >> 16));
        }

        static public byte GetAValue(uint color)
        {
            return ((byte)((color) >> 24));
        }

        static public Color GetColorOfScreen(Point screenPoint)
        {
            IntPtr displayDC = CreateDC("DISPLAY", null, null, IntPtr.Zero);
            uint colorref = GetPixel(displayDC, screenPoint.X, screenPoint.Y);
            DeleteDC(displayDC);
            byte Red = GetRValue(colorref);
            byte Green = GetGValue(colorref);
            byte Blue = GetBValue(colorref);
            return Color.FromArgb(Red, Green, Blue);
        }

我現在只要調用GetColorOfScreen這個方法就可以得到相應座標點的色了,作了下測試,OK!遊戲中怪的血條色爲:(255, 162, 2, 5)可以Color redColor = Color.FromArgb(255, 162, 2, 5);這可構造出色。

二、獲取遊戲窗口

如果按邏輯的順序的話,這一步應該放在第一的,這裏也是應用的API

[DllImport("user32.dll")]
        static extern IntPtr SetActiveWindow(IntPtr hWnd);
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool SetForegroundWindow(IntPtr hWnd);

IntPtr 這個東西,其實說白了就是窗口的句柄,

同時,我用進程名稱要獲取這個遊戲窗口,如下:

Process[] pros = Process.GetProcessesByName(txtProName.Text.Trim());
            if (pros.Length != 0)
            {
                IntPtr pGame = pros[0].MainWindowHandle;

                SetActiveWindow(pGame);
                SetForegroundWindow(pGame);
                Thread.Sleep(2000);

                BeginGame();
            }
            else
            {
                MessageBox.Show("找不到相應的窗口");
            }

三、開始遊戲

先是定義一個色表示爲怪物的血條Color redColor = Color.FromArgb(255, 162, 2, 5);

再定義一個點,並獲取它的色:

Point p = new Point(293, 35);
            Color gameColor = GetColorOfScreen(p);

當這兩個色相同時,那麼就打怪:

不相等時,再找怪

方法是這樣的:

private void BeginGame()
        {
            Color redColor = Color.FromArgb(255, 162, 2, 5);//(255, 255, 123, 104);

            Point p = new Point(293, 35);
            Color gameColor = GetColorOfScreen(p);

            if (gameColor == redColor)
            {
                Fight();

                BeginGame();
            }
            else
            {
                FindMonster();

                BeginGame();
            }
        }

四、找怪

核心: SendKeys.SendWait("{Tab}");

向指定的窗口發送消息,SendKeys還有一個方法Send,有什麼區別呢,自己試了就知道了,輸出到文本文件裏看就明白了,這裏表示按了一下Tab這個鍵,關於其它鍵的用法如下:

鍵   代碼    
BACKSPACE   {BACKSPACE}、{BS}   或   {BKSP}    
BREAK   {BREAK}    
CAPS   LOCK   {CAPSLOCK}    
DEL   或   DELETE   {DELETE}   或   {DEL}    
DOWN   ARROW(下箭頭鍵)   {DOWN}    
END   {END}    
ENTER   {ENTER}   或   ~    
ESC   {ESC}    
HELP   {HELP}    
HOME   {HOME}    
INS   或   INSERT   {INSERT}   或   {INS}    
LEFT   ARROW(左箭頭鍵)   {LEFT}    
NUM   LOCK   {NUMLOCK}    
PAGE   DOWN   {PGDN}    
PAGE   UP   {PGUP}    
PRINT   SCREEN   {PRTSC}(保留,以備將來使用)    
RIGHT   ARROW(右箭頭鍵)   {RIGHT}    
SCROLL   LOCK   {SCROLLLOCK}    
TAB   {TAB}    
UP   ARROW(上箭頭鍵)   {UP}    
F1   {F1}    
F2   {F2}    
F3   {F3}    
F4   {F4}    
F5   {F5}    
F6   {F6}    
F7   {F7}    
F8   {F8}    
F9   {F9}    
F10   {F10}    
F11   {F11}    
F12   {F12}    
F13   {F13}    
F14   {F14}    
F15   {F15}    
F16   {F16}    
數字鍵盤加號   {ADD}    
數字鍵盤減號   {SUBTRACT}    
數字鍵盤乘號   {MULTIPLY}    
數字鍵盤除號   {DIVIDE}    
   
若要指定與   SHIFT、CTRL   和   ALT   鍵的任意組合一起使用的鍵,請在這些鍵代碼之前加上以下一個或多個代碼:  
   
鍵   代碼    
SHIFT   +     (SHIFT="+")
CTRL   ^     (CTRL="^") 如果輸入
ALT   %    

如果是一般的數據和字母,就只要寫進去就可以了,如:SendKeys.SendWait("A");

五、打怪

找怪都做好了,那打怪就好辦了,我想(事實不是這樣的)

把攻擊鍵放到3這個位置,

SendKeys.SendWait("3");
            SendKeys.SendWait("3");
            SendKeys.Flush();

OK。這樣就差不多了,再加個線程進去,不然,怎麼停止呢~~,完整的代碼如下(主要部分):

Thread th = null;

//開始掛機

private void btStart_Click(object sender, EventArgs e)
        {
            th = new Thread(new ThreadStart(StartGame));
            th.Start();

            btStart.Enabled = false;
            btStop.Enabled = true;
        }

//停止掛機

        private void btStop_Click(object sender, EventArgs e)
        {
            th.Abort();

            btStart.Enabled = true;
            btStop.Enabled = false;
        }

        private void StartGame()
        {
            Process[] pros = Process.GetProcessesByName(txtProName.Text.Trim());//在窗體上輸入遊戲進程名
            if (pros.Length != 0)
            {
                IntPtr pGame = pros[0].MainWindowHandle;

                SetActiveWindow(pGame);
                SetForegroundWindow(pGame);
                Thread.Sleep(2000);

                BeginGame();
            }
            else
            {
                MessageBox.Show("找不到相應的窗口");
            }
        }

        private void BeginGame()
        {
            Color redColor = Color.FromArgb(255, 162, 2, 5);//(255, 255, 123, 104);

            Point p = new Point(293, 35);
            Color gameColor = GetColorOfScreen(p);

            if (gameColor == redColor)
            {
                Fight();

                BeginGame();
            }
            else
            {
                FindMonster();

                BeginGame();
            }
        }

        private void Fight()
        {
            SendKeys.SendWait("3");
            SendKeys.SendWait("3");
            SendKeys.Flush();

            Thread.Sleep(2000);
        }

        private void FindMonster()
        {
            SendKeys.SendWait("{Tab}");
            Thread.Sleep(2000);
        }

到這裏爲止,我認爲就差不多了,測試:

把遊戲圖片設爲桌面背景,打開一個記事本,在窗體中輸入notepad,點開始掛機,

找到記事本,OK

由於桌面那張圖片是有怪物的,輸入33 OK

再把記事本最大化,找不到怪物血條了,輸入tab OK。。

哈哈,,說明測試成功!!

但是,問題也出來了,進入遊戲後,找怪都可以正常,就是不能按3這個鍵,,不知道爲什麼,我在自己寫的窗體上都可以的~~~

於是,再做了個窗體;

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            lbMessage.Text=KeyData.ToString();
            return base.ProcessCmdKey(ref msg, keyData);
        }

這樣,窗體上輸入的按鍵都會顯示到控件是去,然後用剛剛那個窗口,輸入這個程的名稱,點開始掛機,在沒有怪血條的時候是輸入的Tab,OK。但有怪的時候是輸入的D3而不是3,啊。。這是怎麼回事呢,於是我把打怪那一行改爲:SendKeys.SendWait("D3");但是由於下午上班了,沒時間測試,晚上回去再試試吧。

後記:

我還用鼠標點示來實現觸發打怪,取到攻擊技能的座標,

[Flags]
        enum MouseEventFlag : uint
        {
            Move = 0x0001,
            LeftDown = 0x0002,
            LeftUp = 0x0004,
            RightDown = 0x0008,
            RightUp = 0x0010,
            MiddleDown = 0x0020,
            MiddleUp = 0x0040,
            XDown = 0x0080,
            XUp = 0x0100,
            Wheel = 0x0800,
            VirtualDesk = 0x4000,
            Absolute = 0x8000
        }


        [DllImport("user32.dll")]
        static extern bool SetCursorPos(int X, int Y);

        [DllImport("user32.dll")]
        static extern void mouse_event(MouseEventFlag flags, int dx, int dy, uint data, UIntPtr extraInfo);

SetCursorPos(418, 744);
            Thread.Sleep(1000);
            mouse_event(MouseEventFlag.RightDown, 418, 744, 0, UIntPtr.Zero);
            mouse_event(MouseEventFlag.RightUp, 418, 744, 0, UIntPtr.Zero);

MouseEventFlag 這個枚舉基本上所有的鼠標事件都有了,不錯,可以做很多事啦,但在遊戲中還是不行,我懷疑是遊戲處理了這種消息的發送的,不讓這種模擬的消息傳入,那樣的話,做外掛可以麻煩了,不過。今天還是有不少的體會的,因爲我一開始什麼都不懂,到後來還是學到點東西啦~

[DllImport("user32.dll")]

表示調用Windows的一個DLL,它是Windows自帶的,不過要對它有所瞭解才能用它,我們用的時候只要定義好它的方法就行了,實現交給它自身去處理,就是extern

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章