先谢谢大家这么支持,好不容易才整理好的。CE 的下载地址:
http://www.ghoffice.com/bbs/read.php?tid-26455.html或者在广海游戏论坛里面有汉化版的CE。 广海游戏论坛地址:
http://www.ghoffice.com/bbs/thread.php?fid-74.html上节如果完成后,界面应该是像这样的
可以看出,这样很不美观,呵呵,所以这一节我们就来设计下界面和最基本的读取人物其他信息。
我们的目的是把界面设计成如下图片所示的样子,当然怎么排列还是看自己喜欢,呵呵。
一个按钮,一个时钟控件,其他都是标签,按着一定的排列画在窗口上。
按钮可以在上方 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;
到这里,完成读取基本信息的制作。
调试运行没有错误后,我们显示的结果图如下:
我把Unit1.CPP 的完整代码存到一个文本文件里提供下载。
这一节就说这么多勒,还有些事要处理。如果有什么不明白的地方,可以发帖或回帖,有空我就来回复下,呵呵。