最终幻想OL(FF14)分析 - 基本数据

来源:互联网 发布:caffe windows python 编辑:程序博客网 时间:2024/04/27 13:43

国庆在家闲来无事,下个了收费游戏,经典之作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满天飞的游戏啊~

0 0