close
呵呵,所以這一節我們就來設計下界面和最基本讀取人物其他信息。
我們的目的把界面設計成如下圖片所示的樣子,當然怎麼排列還是看自己喜歡,呵呵。
  
  

一個按鈕,一個時鐘控件,其他是標籤,按著一定的排列畫在口上。
按鈕可以在上方 Standard 欄找到,時鐘控件可以在 
System 
欄找到。
我們利時鐘控件,就可以實現循環讀取遊戲的數據了,這一次的代碼將會和上一次的有點改變。
下面我們開始寫代碼:

首先,選擇時鐘控件,將 
Interval 屬設置為 100 ,意思就是1秒鐘讀取10次數據。Enabled 屬性設置為False 

雙擊按鈕,進入代碼界面,寫下如下代碼

    FirstAdr= 0x930014;
  
  GameFormHwnd=FindWindow("QElementClient Window", "Element 
Client");
    if(!GameFormHwnd)
    {
  
      ShowMessage("遊戲沒有啟動,請先啟動遊戲並完全進入遊戲!");
  
      return ;
    }
    
GetWindowThreadProcessId(GameFormHwnd,&hProcId);
    
Timer1->Enabled=true;

和上一次的差別是,我們把讀取數據的代碼放到時鐘控件裡,這裡只做遊戲的開啟判斷和數據初始化。

然後雙擊時鐘控件,由於所有的數據都在時鐘控件裡面讀取,所以代碼有點

HANDLE 
mProcID;
    DWORD eax,ecx, mex,tmp1,tmp2;
    
AnsiString ms; //byte dcode;
    WCHAR mname[64];
    
mProcID = OpenProcess(PROCESS_ALL_ACCESS, false, hProcId);
    
ReadProcessMemory(mProcID, LPVOID(0x930014), &eax, 4, 0);
    
ReadProcessMemory(mProcID, LPVOID(eax + 0x1C), &ecx, 4, 0);
    
ReadProcessMemory(mProcID, LPVOID(ecx + 0x24), &eax, 4, 0);
    
ReadProcessMemory(mProcID, LPVOID(eax + 0x25C), &HP, 4, 0);
    
ReadProcessMemory(mProcID, LPVOID(eax + 0x250), &ManLv, 4, 0);    
//0x24C 人物等級
    ReadProcessMemory(mProcID, LPVOID(eax + 0x398), 
&mex, 4, 0);   //怪物名字
    ReadProcessMemory(mProcID, 
LPVOID(mex), mname, 64, 0);
    ManName=mname;
    
ReadProcessMemory( mProcID, LPVOID(eax + 0x244), &ManID, 4, 0);  
    //人物 ID
    ReadProcessMemory(mProcID, 
LPVOID(eax + 0x25C), &HP, 4, 0);        //596 
當前體力  紅
    ReadProcessMemory(mProcID, LPVOID(eax + 
0x260), &MP, 4, 0);        //600 
當前內力  藍
    ReadProcessMemory(mProcID, LPVOID(eax + 
0x274), &MaxHP, 4, 0);     //620 最大血值
    
ReadProcessMemory(mProcID, LPVOID(eax + 0x278), &MaxMP, 4, 0);  
   //624 最大內力值
    ReadProcessMemory(mProcID, 
LPVOID(eax + 0x2DC), &Money, 4, 0);     //724 
當前錢值
    ReadProcessMemory(mProcID, LPVOID(eax + 0x7D4), 
&GWID, 4, 0);    //120版 偏移加 8 或地址 0x0354AF44 當前目標怪物ID 
,為負就是怪,為正就是NPC或玩,為0則怪物死亡,或沒有選擇怪物.
    ReadProcessMemory(mProcID, 
LPVOID(eax + 0x264), &Exp, 4, 0);     //0x25C 
當前經驗值,十進制
    ReadProcessMemory( mProcID, LPVOID(eax + 0x3C), 
&Mx, 4, 0);      //人物坐標 x  float 4字節
  
  ReadProcessMemory( mProcID, LPVOID(eax + 0x44), &My, 4, 0);  
    //人物坐標 y  float 4字節
    
//怪物信息
    
//---------------------------------------------------------
    if( 
GWID > 0x80000000)    //大於0x80000000為怪物或NPC
    
{
        WCHAR Buff[64];
  
      ReadProcessMemory( mProcID, LPVOID(FirstAdr), 
&eax, 4, 0);
        ReadProcessMemory( 
mProcID, LPVOID(eax + 0x1C), &ecx, 4, 0);
     
   ReadProcessMemory( mProcID, LPVOID(ecx + 0x8), &eax, 4, 
0);
        ReadProcessMemory( mProcID, 
LPVOID(eax + 0x20), &ecx, 4, 0);
     
   ReadProcessMemory( mProcID, LPVOID(ecx + 0x24), &tmp1, 4, 
0);  //讀出怪物數組的最大值
     
   ReadProcessMemory( mProcID, LPVOID(ecx + 0x18), &tmp2, 4, 
0);  //讀出怪物列的首地址
        if(GWID!=0) 
eax = tmp2 + (GWID % tmp1) * 0x4;
     
   ReadProcessMemory( mProcID, LPVOID(eax), &ecx, 4, 
0);
        ReadProcessMemory( mProcID, 
LPVOID(ecx + 0x4), &eax, 4, 0);
     
   ReadProcessMemory( mProcID, LPVOID(eax + 0x134), &GWHP, 4, 
0); //怪物當前血值
        ReadProcessMemory( 
mProcID, LPVOID(eax + 0x14C), &GWMaxHP, 4, 0); //怪物血值上限
  
      //ReadProcessMemory( mProcID, LPVOID(eax + 0xB4), 
&GWType, 4, 0);    //選類型
     
   //ReadProcessMemory( mProcID, LPVOID(eax + 0x120), 
&GWTypeID, 4, 0); //怪物類
     
   ReadProcessMemory( mProcID, LPVOID(eax + 0x128), &GWLv, 2, 
0);
        ReadProcessMemory( mProcID, 
LPVOID(eax + 0x3C), &GWMx, 4, 0);   //怪物X坐標
     
   ReadProcessMemory( mProcID, LPVOID(eax + 0x44), &GWMy, 4, 
0);   //怪物Y坐標
     
   ReadProcessMemory( mProcID, LPVOID(eax + 0x234), &MtoG, 4, 
0);   //怪物距離
     
   //怪物名稱部分------------------------------------
  
      ReadProcessMemory( mProcID, LPVOID(eax + 0x210), 
&ecx, 4, 0);   //怪物名字
     
   ReadProcessMemory( mProcID, LPVOID(ecx), Buff, 64, 
0);
        GWName = Buff;
  
      
    }
    else if(GWID 
< 0x80000000 && GWID >0)    //玩家
    
{
        WCHAR Buff2[64];
  
      ReadProcessMemory( mProcID, LPVOID(FirstAdr), 
&eax, 4, 0);
        ReadProcessMemory( 
mProcID, LPVOID(eax + 0x1C), &ecx, 4, 0);
     
   ReadProcessMemory( mProcID, LPVOID(ecx + 0x24), &eax, 4, 
0);
     
   //-------------------------------------------------------
  
      ReadProcessMemory( mProcID, LPVOID(eax + 0x138), 
&ecx, 4, 0);
     
   //-------------------------------------------------------
  
      ReadProcessMemory( mProcID, LPVOID(ecx + 0x24), 
&tmp1, 4, 0);  //讀出怪物數組的最大值
     
   ReadProcessMemory( mProcID, LPVOID(ecx + 0x18), &tmp2, 4, 
0);  //讀出怪物列表的首地址
        if(GWID!=0) 
eax = tmp2 + (GWID % tmp1) * 0x4;
     
   ReadProcessMemory( mProcID, LPVOID(eax), &ecx, 4, 
0);
        ReadProcessMemory( mProcID, 
LPVOID(ecx + 0x4), &eax, 4, 0);
     
   ReadProcessMemory( mProcID, LPVOID(eax + 0x25C), &GWHP, 4, 
0); //選中人物當前血值
        ReadProcessMemory( 
mProcID, LPVOID(eax + 0x274), &GWMaxHP, 4, 0); //選中人物血值上限
  
      ReadProcessMemory( mProcID, LPVOID(eax + 0x250), 
&GWLv, 2, 0);
        //ReadProcessMemory( 
mProcID, LPVOID(eax + 0xB4), &GWType, 4, 0);  //選中類型
  
      ReadProcessMemory( mProcID, LPVOID(eax + 0x3C), 
&GWMx, 4, 0);   //怪物X坐標
     
   ReadProcessMemory( mProcID, LPVOID(eax + 0x44), &GWMy, 4, 
0);   //怪物Y坐標
     
   ReadProcessMemory( mProcID, LPVOID(eax + 0x4D0), &MtoG, 4, 
0);    //人與人距離
        if( GWID == 
ManID && GWID!=0)
        {
  
          GWHP = HP;
     
       GWMaxHP = MaxHP;
     
       GWMx = Mx;
        
    GWMy = My;
     
   }
     
   //選擇人物名字部分----------------------------------------
  
      ReadProcessMemory( mProcID, LPVOID(eax + 0x398), 
&ecx, 4, 0);
        ReadProcessMemory( 
mProcID, LPVOID(ecx), Buff2, 64, 0);
     
   GWName = Buff2;
    }
    
//下面開始顯示數據
    LbName->Caption="人物: " + ManName;
  
  LbLv->Caption = "等級: " + AnsiString(ManLv);
    
LbId->Caption = "ID: " + AnsiString(ManID);
    
LbManPos->Caption = "坐標: X: " + ms.FormatFloat("0.0",Mx) + "   Y: " 
+
    ms.FormatFloat("0.0",My);
    LbHP->Caption= 
"HP: " + IntToStr(HP) + " / " + IntToStr(MaxHP);
    
LbMP->Caption= "MP: " + IntToStr(MP) + " / " + IntToStr(MaxMP);
  
  LbExp->Caption = "Exp: " + IntToStr(Exp);
    
LbMon->Caption = "金錢: " + AnsiString(Money / 10000) + "金 " 
+  AnsiString((Money % 10000) / 100) +
    "銀 " + 
AnsiString(Money % 100) +    "銅";
    if( GWID > 
0)
    {
        if( GWID == 
ManID)
           
Form1->LbObj->Caption = "目標: " + AnsiString(ManLv) + "級 ID:" 
+
            AnsiString(ManID) + " " 
+ ManName;
        else
     
       Form1->LbObj->Caption = "目標: " + 
AnsiString(GWLv) + "級 ID:" +
           
AnsiString(GWID) + " " + GWName;
    }
    
else
        Form1->LbObj->Caption = "目標: 
";
    LbObjHP->Caption="目標HP: " + IntToStr(GWHP) + " / " + 
IntToStr(GWMaxHP);
    LbObjPos->Caption = "坐標: X: " + 
ms.FormatFloat("0.0",GWMx) + "   Y: " + ms.FormatFloat("0.0",GWMy) + 
"   距離: " + ms.FormatFloat("0.0",MtoG);
    
//顯示段完
    
CloseHandle(mProcID);

以上就是在時鐘控件裡的代碼。
另外,我們需要定義一些全局變量,在 


#include <vcl.h>
#pragma hdrstop
#include 
"Unit1.h"
//---------------------------------------------------------------------------
#pragma 
package(smart_init)
#pragma resource "*.dfm"
TForm1 
*Form1;

這些代碼下面,加入以下代碼

DWORD FirstAdr;
DWORD 
ShutTime,hProcId,ManID,HP,MaxHP,MP,MaxMP,Money;
DWORD 
GWID,GWMaxHP,GWHP,ObjHP,ObjMaxHP,ObjID,Exp,MaxExp,ExpLvUp;
HWND 
GameFormHwnd;
long ManLv,GWLv;
float 
MtoG,AreaMtoG,GWMx,GWMy,Mx,My;
AnsiString 
ManName,GWName;


到這裡,完成讀取基本信息的製作。
 
 
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 UM程式研究日誌 的頭像
    UM程式研究日誌

    UM程式研究日誌

    UM程式研究日誌 發表在 痞客邦 留言(0) 人氣()