国庆在家闲来无事,下个了收费游戏,经典之作FF14,简单的分析了下,日本人的游戏结构挺简单。
具体的基地址就不写了,就发发实现的代码和效果
注意说明:
1、游戏内的字符编码是UTF8
2、游戏的数据结构大部分都是静态(至少看的几个都是)
3、日本人的代码看起来比棒子的易懂(棒子是游戏做多了,框架封装的太好了)
一、背包列表
实现代码:
procedure ShowBagList();
var
ItemPageBase:Cardinal;
i,j,Count:Cardinal;
BagObj:^_BagObj;
Name:Pchar;
begin
if pCardinal(g_BagBase)^ <> 0 then
begin
//有4页
for i := 0 to 3 do
begin
ItemPageBase:= pCardinal(g_BagBase)^ + i * $18;
if PCardinal(ItemPageBase)^ <> 0 then
begin
Printf('Item Page:%d',[i]);
Count:= pInteger(ItemPageBase + 8)^;
if Count > 0 then
begin
for j := 0 to Count - 1 do
begin
BagObj:=Pointer(pCardinal(ItemPageBase)^ + j * $40);
if BagObj.ResId <> 0 then
begin
Name:=Pointer(g_GetItemNameByResId(BagObj.ResId) + $D0);
Printf('Idx:%d ResId:%X Name:%s Num:%d',[BagObj.Idx,BagObj.ResId,Utf8ToAnsi(Name),BagObj.Num]);
end;
end;
end;
end;
end;
end;
end;
二、环境列表
代码实现:
Procedure ShowWorld();
var
ObjBase:^_RoleObj;
I:Cardinal;
begin
for I := 0 to $158 do
begin
ObjBase:=pPointer(g_WorldBase + i * 4)^;
if ObjBase <> nil then
begin
Printf('[%d]Lv:%d Name:%s Hp:%d/%d Mp:%d/%d Pos:%.2f,%.2f,%.2f',[
i,
ObjBase.BaseInfo.Lv,
Utf8ToAnsi(ObjBase.Name),
ObjBase.BaseInfo.Hp,
ObjBase.BaseInfo.MaxHp,
ObjBase.BaseInfo.Mp,
ObjBase.BaseInfo.MaxMp,
ObjBase.x,
ObjBase.z,
ObjBase.y]);
end;
end;
end;
三、角色基本信息
实现代码:
Procedure ShowRoleInfo();
var
RoleObj:^_RoleObj;
begin
RoleObj:=pPointer(g_RoleBase)^;
if RoleObj <> nil then
begin
Printf('Lv:%d',[RoleObj.BaseInfo.Lv]);
Printf('Name:%s',[Utf8ToAnsi(RoleObj.Name)]);
Printf('Hp:%d/%d',[RoleObj.BaseInfo.Hp,RoleObj.BaseInfo.MaxHp]);
Printf('Mp:%d/%d',[RoleObj.BaseInfo.Mp,RoleObj.BaseInfo.MaxMp]);
Printf('SkillPower:%d',[RoleObj.BaseInfo.SkillPower]);
Printf('Pos:%.2f,%.2f,%.2f',[RoleObj.x,RoleObj.z,RoleObj.y]);
end;
end;
=====================================我是分割线=====================================
这里要给出一个重要的对象结构体,上面的代码应该也能发现就是_RoleObj
_RoleBaseInfo = Packed record
ModIndex:Byte;
Lv:Byte;
Empty1:array [0..5] of byte;
MaxHp,Hp:Cardinal;
MaxMp,Mp:Cardinal;
SkillPower:Word;
end;
_RoleObj = packed Record
UnkonwMem1:array [0..$2F] of byte; // 0x30
Name:Array [0..$1F] of Char; // 0x20
UnkonwMem2:array [0..$4F] of byte; // 0x50
x,z,y:Single; Empty:Cardinal;
Way:Single;
Offset:Array [0..$177B] of Byte; // 0x17E0 -> BASE + 0x1830
BaseInfo:_RoleBaseInfo;
End;
另外个背包的数据的结构,这个比较简单
_BagObj = Packed Record
Unkonw:Cardinal;
Idx:Cardinal;
ResId:Cardinal;
Num:Cardinal;
End;
最后不公开的几个函数和全局地址申明如下:
type
TGetItemNameByResId = function (Resid:Cardinal):Cardinal;cdecl;
var
g_RoleBase:Cardinal;
g_BagBase:Cardinal;
g_GetItemNameByResId:TGetItemNameByResId; //通过资源ID查询物品名称
g_WorldBase:Cardinal;
[吐槽]~~又是个挂B满天飞的游戏啊~