设为主页 | 加入收藏 | 繁體中文

一个游戏的汉化实例

  【介绍】
  前几天,tbsgame.net 的 Lejardo老大,经过 MSN Messager 与我联系,说是想汉化一游戏
  —— War In The Pacific : The struggle against Japan 1941-1945,是一个古老的2D回合
  制游戏,我想也只有骨灰级的玩家会体贴这个。
  以前,曾在该网站,到场了《铁血同盟2黄金版》的汉化事情。但是,那是有完整的C源码的
  汉化,与这次的难度不行等量齐观。
  从TLF的FTP里下载了一个硬盘版,谁知不能升级最新的1.8补丁,于是从已经升级的人那里
  失掉1.8的exe,虽然在正式游戏时会出错,但好歹能看到选单画面和任务简报了。
  在DX9之前,险些每个英文游戏都有一套本身的字符显示引擎,利用DirectDraw的2D游戏把
  字符寄存在Surface中,利用Direct3D的3D游戏则把字符寄存在Texture中,显示时根据字符找
  到相应的Surface或Texture,然后把它们贴上屏幕。
  汉化的要领,一种是利用WINDOWS的GDI函数,直接操纵HDC。这种要领的缺陷是服从低下,这
  也是为什么在DX9之前,英文游戏要利用本身的字符输出引擎的缘故原由;另一种要领是修改原有的
  引擎,使其支持中文输出,但如果游戏没有利用unicode,就会牵涉到一个单字节、双字节的问
  题,在没有源码的环境下十分麻烦;末了一种是把游戏阐发透彻后,外接一个dll,利用本身的
  字符输出引擎。
  考虑到该游戏是一个2D游戏,并且现在的电脑配置已远远高于该游戏的推荐配置,所以预备使
  用第一种要领进行汉化。
  【阐发】
  起首要搞明白游戏原本的字符显示机制。
  用ODBG载入,加-w参数,让游戏在窗口形式下运转。
  任意找一显示出来的字符串,然后在内存中搜刮,下内存断点,步步跟踪,层层深入,末了找到
  了这里:
  代码:-------------------------------------------------------------------------------- 
  0057E5E0  /$  A1 105D6004          mov eax,dword ptr ds:[4605D10]
  0057E5E5  |.  83EC 18              sub esp,18
  0057E5E8  |.  85C0                 test eax,eax
  0057E5EA  |.  0F84 79010000        je war_in_t.0057E769
  0057E5F0  |.  8B0D 080B0E04        mov ecx,dword ptr ds:[40E0B08]               ;  [ecx]+10 = 颜色
  0057E5F6  |.  85C9                 test ecx,ecx
  0057E5F8  |.  0F84 6B010000        je war_in_t.0057E769
  0057E5FE  |.  55                   push ebp
  0057E5FF  |.  8B6C24 2C            mov ebp,dword ptr ss:[esp+2C]
  0057E603  |.  85ED                 test ebp,ebp
  0057E605  |.  56                   push esi
  0057E606  |.  57                   push edi
  0057E607  |.  75 06                jnz short war_in_t.0057E60F
  0057E609  |.  8B2D 54840F04        mov ebp,dword ptr ds:[40F8454]               ;  目标surface
  0057E60F  |>  8B4424 30            mov eax,dword ptr ss:[esp+30]
  0057E613  |.  8D70 01              lea esi,dword ptr ds:[eax+1]
  0057E616  |>  8A10                 /mov dl,byte ptr ds:[eax]
  0057E618  |.  40                   |inc eax
  0057E619  |.  84D2                 |test dl,dl
  0057E61B  |.^ 75 F9                \jnz short war_in_t.0057E616
  0057E61D  |.  2BC6                 sub eax,esi
  0057E61F  |.  8BF0                 mov esi,eax
  0057E621  |.  81FE 58020000        cmp esi,258
  0057E627  |.  897424 0C            mov dword ptr ss:[esp+C],esi
  0057E62B  |.  7C 0C                jl short war_in_t.0057E639
  0057E62D  |.  C74424 0C 57020000   mov dword ptr ss:[esp+C],257
  0057E635  |.  8B7424 0C            mov esi,dword ptr ss:[esp+C]
  0057E639  |>  8B4424 28            mov eax,dword ptr ss:[esp+28]
  0057E63D  |.  8B5424 2C            mov edx,dword ptr ss:[esp+2C]
  0057E641  |.  33FF                 xor edi,edi
  0057E643  |.  85F6                 test esi,esi
  0057E645  |.  A3 48740604          mov dword ptr ds:[4067448],eax
  0057E64A  |.  8915 E4760604        mov dword ptr ds:[40676E4],edx
  0057E650  |.  897C24 10            mov dword ptr ss:[esp+10],edi
  0057E654  |.  0F8E 0C010000        jle war_in_t.0057E766
  0057E65A  |.  53                   push ebx
  0057E65B  |.  8B5C24 3C            mov ebx,dword ptr ss:[esp+3C]
  0057E65F  |.  90                   nop
  0057E660  |>  8B7424 34            /mov esi,dword ptr ss:[esp+34]
  0057E664  |.  0FB63437             |movzx esi,byte ptr ds:[edi+esi]
  0057E668  |.  83FE 20              |cmp esi,20
  0057E66B  |.  0F8C CB000000        |jl war_in_t.0057E73C
  0057E671  |.  3B31                 |cmp esi,dword ptr ds:[ecx]                  ;  [ecx] == 80
  0057E673  |.  0F8D DB000000        |jge war_in_t.0057E754                       ;  非法字符?
  0057E679  |.  803D 88860F04 00     |cmp byte ptr ds:[40F8688],0
  0057E680  |.  74 05                |je short war_in_t.0057E687
  0057E682  |.  8B79 04              |mov edi,dword ptr ds:[ecx+4]
  0057E685  |.  EB 0C                |jmp short war_in_t.0057E693
  0057E687  |>  8BFE                 |mov edi,esi
  0057E689  |.  6BFF 38              |imul edi,edi,38
  0057E68C  |.  8BBC0F 24080000      |mov edi,dword ptr ds:[edi+ecx+824]
  0057E693  |>  833D 585E6004 00     |cmp dword ptr ds:[4605E58],0
  0057E69A  |.  7E 4A                |jle short war_in_t.0057E6E6
  0057E69C  |.  894424 18            |mov dword ptr ss:[esp+18],eax
  0057E6A0  |.  03C7                 |add eax,edi
  0057E6A2  |.  894424 20            |mov dword ptr ss:[esp+20],eax
  0057E6A6  |.  895424 1C            |mov dword ptr ss:[esp+1C],edx
  0057E6AA  |.  8B41 08              |mov eax,dword ptr ds:[ecx+8]
  0057E6AD  |.  03C2                 |add eax,edx
  0057E6AF  |.  85DB                 |test ebx,ebx
  0057E6B1  |.  894424 24            |mov dword ptr ss:[esp+24],eax
  0057E6B5  |.  74 10                |je short war_in_t.0057E6C7
  0057E6B7  |.  8D4C24 18            |lea ecx,dword ptr ss:[esp+18]
  0057E6BB  |.  51                   |push ecx
  0057E6BC  |.  53                   |push ebx
  0057E6BD  |.  6A 00                |push 0
  0057E6BF  |.  E8 FC75FFFF          |call war_in_t.00575CC0
  0057E6C4  |.  83C4 0C              |add esp,0C
  0057E6C7  |>  8B15 585E6004        |mov edx,dword ptr ds:[4605E58]
  0057E6CD  |.  6A 00                |push 0                                      ; /Arg5 = 00000000
  0057E6CF  |.  55                   |push ebp                                    ; |Arg4
  0057E6D0  |.  6A 00                |push 0                                      ; |Arg3 = 00000000
  0057E6D2  |.  52                   |push edx                                    ; |Arg2 => 00000000
  0057E6D3  |.  8D4424 28            |lea eax,dword ptr ss:[esp+28]               ; |
  0057E6D7  |.  50                   |push eax                                    ; |Arg1
  0057E6D8  |.  E8 33CAFFFF          |call war_in_t.0057B110                      ; \war_in_t.0057B110
  0057E6DD  |.  8B0D 080B0E04        |mov ecx,dword ptr ds:[40E0B08]
  0057E6E3  |.  83C4 14              |add esp,14
  0057E6E6  |>  56                   |push esi
  0057E6E7  |.  51                   |push ecx
  0057E6E8  |.  E8 F3B3FFFF          |call war_in_t.00579AE0                      ;  颜色相关
  0057E6ED  |.  6BF6 38              |imul esi,esi,38
  0057E6F0  |.  8B0D E4760604        |mov ecx,dword ptr ds:[40676E4]
  0057E6F6  |.  8B15 48740604        |mov edx,dword ptr ds:[4067448]
  0057E6FC  |.  A1 080B0E04          |mov eax,dword ptr ds:[40E0B08]
  0057E701  |.  55                   |push ebp
  0057E702  |.  6A 00                |push 0
  0057E704  |.  68 A00F0000          |push 0FA0
  0057E709  |.  6A 00                |push 0
  0057E70B  |.  53                   |push ebx
  0057E70C  |.  51                   |push ecx
  0057E70D  |.  52                   |push edx
  0057E70E  |.  8D8C06 20080000      |lea ecx,dword ptr ds:[esi+eax+820]
  0057E715  |.  51                   |push ecx
  0057E716  |.  E8 C5F7FFFF          |call war_in_t.0057DEE0
  0057E71B  |.  A1 48740604          |mov eax,dword ptr ds:[4067448]
  0057E720  |.  8B0D 080B0E04        |mov ecx,dword ptr ds:[40E0B08]
  0057E726  |.  8B15 E4760604        |mov edx,dword ptr ds:[40676E4]
  0057E72C  |.  83C4 28              |add esp,28
  0057E72F  |.  03C7                 |add eax,edi
  0057E731  |.  8B7C24 14            |mov edi,dword ptr ss:[esp+14]
  0057E735  |.  A3 48740604          |mov dword ptr ds:[4067448],eax
  0057E73A  |.  EB 18                |jmp short war_in_t.0057E754
  0057E73C  |>  83FE 0A              |cmp esi,0A
  0057E73F  |.  75 13                |jnz short war_in_t.0057E754
  0057E741  |.  A1 74720604          |mov eax,dword ptr ds:[4067274]
  0057E746  |.  A3 48740604          |mov dword ptr ds:[4067448],eax
  0057E74B  |.  0351 08              |add edx,dword ptr ds:[ecx+8]
  0057E74E  |.  8915 E4760604        |mov dword ptr ds:[40676E4],edx
  0057E754  |>  8B7424 10            |mov esi,dword ptr ss:[esp+10]
  0057E758  |.  47                   |inc edi
  0057E759  |.  3BFE                 |cmp edi,esi
  0057E75B  |.  897C24 14            |mov dword ptr ss:[esp+14],edi
  0057E75F  |.^ 0F8C FBFEFFFF        \jl war_in_t.0057E660
  0057E765  |.  5B                   pop ebx
  0057E766  |>  5F                   pop edi
  0057E767  |.  5E                   pop esi
  0057E768  |.  5D                   pop ebp
  0057E769  |>  83C4 18              add esp,18
  0057E76C  \.  C3                   retn
  --------------------------------------------------------------------------------
  从0057E660到0057E75F的循环是把字符串中的字符逐一显示出来。
  其中
  代码:--------------------------------------------------------------------------------
  0057E671  |.  3B31                 |cmp esi,dword ptr ds:[ecx]                  ;  [ecx] == 80
  0057E673  |.  0F8D DB000000        |jge war_in_t.0057E754                       ;  非法字符?
  --------------------------------------------------------------------------------
  过滤了大于80(十进制128)的字符,这便是为什么中文无法显示的缘故原由。固然,简略的把
  这个果断去掉是不行行的。
  这个函数有3个参数:输出的字符串和坐标(x,y),而如果我们要用本身的代码取代,还需要
  晓得两样工具:颜色,以及输出的目标地(目标Surface)。
  把 0057E6E8 的 “call 00579AE0”nop掉,发明全部字符不再有颜色变化,可见这个函数
  同颜色有关。连续跟踪,发明颜色寄存在[40E0B08],一个全局的struct中。
  而目标Surface是经过跟踪 0057E716 的“call 0057DEE0”失掉的。
  接下来要做的,便是把这个函数更换成我们本身的。
  【动手】
  这个游戏利用了DirectDraw7,先写一个DirectDraw7的步伐:
  代码:-------------------------------------------------------------------------------- 
  #include
  #include
  #pragma comment(lib,"ddraw.lib")
  #pragma comment(lib,"dxguid.lib")
  #define GSM_CAPTION GetSystemMetrics(SM_CYCAPTION)      //标题栏
  #define GSM_CXBORDER GetSystemMetrics(SM_CXFIXEDFRAME)  //不行调边框
  #define GSM_CYBORDER GetSystemMetrics(SM_CYFIXEDFRAME)
  #define GSM_CYMENU GetSystemMetrics(SM_CYMENU)  //如果有菜单
  #define MAXWIDTH 640            //游戏显示区大小
  #define MAXHEIGHT 480
  //全局变量
  LPDIRECTDRAW7 lpDD;             //DirectDraw对象
  LPDIRECTDRAWSURFACE7 lpDDSPrimary;      //DirectDraw主表面
  LPDIRECTDRAWSURFACE7 lpDDSBack; //后台缓冲表面
  char szMsg1[] = "001 Tutorial";
  char szMsg2[] = "按ESC加入";
  BOOL bActive = TRUE;
  HWND hwnd;
  HFONT hfont;
  //函数声明
  LRESULT CALLBACK WinProc (HWND hWnd, UINT message, WPARAM wParam,
  LPARAM lParam);
  BOOL InitWindow (HINSTANCE hInstance, int nCmdShow);
  BOOL InitDDraw (void);          //初始化DirectX
  void FreeDDraw (void);          //开释DirectX对象
  void MainLoop (void);           //游戏主循环
  //-------------------------------------------------------
  //函数:WinMain()
  //功效:Win32使用步伐入口函数.进行初始化事情,处置惩罚消息循环
  //-------------------------------------------------------
  int WINAPI
  WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
  int nCmdShow)
  {
  MSG msg;
  //初始化主窗口
  if (!InitWindow (hInstance, nCmdShow))
  return FALSE;
  //初始化DirectDraw环境,并完成DirectDraw功效
  if (!InitDDraw ())
  {
  MessageBox (GetActiveWindow (), "初始化DirectDraw历程中出错!", "Error",
  MB_OK);
  FreeDDraw ();
  DestroyWindow (GetActiveWindow ());
  return FALSE;
  }
  hfont =
  CreateFont (15, 0, 0, 0, FW_EXTRALIGHT, FALSE, FALSE, FALSE, ANSI_CHARSET,
  OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, 3,
  VARIABLE_PITCH | FF_DONTCARE, "Lucida Sans Unicode");
  while (1)
  {
  if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
  {
  //如果有消息就处置惩罚消息
  if (!GetMessage (&msg, NULL, 0, 0))
  return msg.wParam;
  TranslateMessage (&msg);
  DispatchMessage (&msg);
  }
  else if (bActive)
  {                       //如果步伐处于激活状态,进入游戏主循环
  MainLoop ();
  }
  //等待消息
  else
  WaitMessage ();
  }
  return msg.wParam;
  }
  //--------------------------------------
  //函数:InitWindow()
  //功效:创立主窗口
  //--------------------------------------
  static BOOL
  InitWindow (HINSTANCE hInstance, int nCmdShow)
  {
  WNDCLASS wc;                  //窗口类布局
  //添补窗口类布局


    文章作者: 福州军威计算机技术有限公司
    军威网络是福州最专业的电脑维修公司,专业承接福州电脑维修、上门维修、IT外包、企业电脑包年维护、局域网网络布线、网吧承包等相关维修服务。
    版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处 、作者信息和声明。否则将追究法律责任。

TAG:
评论加载中...
内容:
评论者: 验证码: