冒险解谜游戏中文网 ChinaAVG

标题: 【转】DirectX 9 游戏汉化详解 [打印本页]

作者: shane007    时间: 2011-1-30 14:12
标题: 【转】DirectX 9 游戏汉化详解
本帖最后由 shane007 于 2011-1-30 14:13 编辑
& r  x, W8 [: u6 k+ k
5 ]" P" O; d; b' W7 B' J8 J6 [作 者: noword_forever
1 D% N6 m5 z& ^7 e) O* _8 y时 间: 2010-05-25,14:52:51
: I; Z/ n! R4 m2 a) H. l5 N# L链 接: http://bbs.pediy.com/showthread.php?t=113739# F) }: T  M# M/ @) j6 J+ {

4 p( ~3 s1 r% d* q% L7 _【文章标题】: DirectX 9 游戏汉化详解
' Y7 h* v7 Y) i1 h' ]  q& P0 N" Z【文章作者】: noword3 G" t1 |0 L. y& K  a. V
【软件名称】: 无厘头太空战役
$ J5 S, C/ r  e4 O! d3 M1 z+ i% C【下载地址】: http://www.verycd.com/topics/2819995/
3 D9 F7 b6 D7 V0 u% Y--------------------------------------------------------------------------------) U/ H; b0 j8 x8 f2 S
  【前言】
. Y' U& o+ E+ ]$ F  先copy一段此游戏介绍:) c% _0 A! G! u" w' O* f1 o
  
0 w# V, R. Z8 S% {- n  这是一个独特的战略游戏,具有即时战略与塔防的混合风格,玩家将扮演庞大太空舰队的最高指挥官,你可以自定飞船的构造,摆放飞船的位置,下达命令,然后观看绚丽的射击与爆炸。移动和爆炸时会有动态模糊效果。支持自定义地图。6 x3 Y/ f1 w& O/ b4 i! U3 i
  
9 [1 K: j4 H" M$ u. `3 h4 H. z8 @  想玩中文版,两个游戏论坛,3DM和YX上,都有人说要汉化,等了几个月,没有下文,说是技术原因。于是决定自己来试试看。
$ n. y) r% Q( q  2 F7 c# M2 r& m* p
  1 q9 g6 }2 `9 P& u# e
  【困难何在】
+ M0 |: s, I7 b9 ]; {6 P  此游戏的文本都在data目录下,都是明文的文本文件。修改data\strings.ini,将1 a, l3 }  s) I" c
  ; S6 E1 m) a- B( ]1 R. {% n( G
代码:- c6 u$ k1 U* f2 y
  MAINMENU_QUIT        = "Exit"& N  A6 w5 X) R. s- `! A
  
/ X$ C" `& T$ K+ }  改成
; n$ F9 |+ ~: [1 E  z: s  
8 Z' }, {, [6 n& C" q1 M- _# C, Y代码:
$ y! t4 n6 Z  R1 n8 i0 p  MAINMENU_QUIT        = "退出"' e  Y/ B2 _% G& @' W* T3 e2 r  M
  
* u9 {! L0 x% w. H. m  6 e" X/ V; Y2 u7 _' ]8 P9 `
  进入游戏后,不出所料,无法显示此中文。
# B7 U3 D- `' t8 |' W  " L1 i( ^* Y& R* [( Z; Y/ ~
  茫茫多的游戏爱好者,在尝试汉化某款自己心仪的游戏时,都是死在了这一步——找了半天文本资源,然后翻成中文,满心欢喜和期待的进入游戏,面对的却是一堆乱码或一片空白。满腔热情,化为乌有,无可奈何,黯然神伤。0 m% l2 W: K: a( u* l1 R
  " f6 g$ O3 B5 U4 C9 \% V1 ]
  本文的目的,就是希望能够帮助这些有志于游戏汉化的同学,主要介绍了如何让一个英文的游戏,能够正确的显示出中文。
& z2 }+ M3 E- j. E% q  - Z* A5 D( L! O- r
  
5 g3 |3 `, I8 x5 U! l  【调试分析】$ S1 p7 l7 g8 {* {* o% P7 Y7 |0 T( Z
  DirectX 9游戏的启动流程是这样的,先执行Direct3DCreate9,返回值是一个IDirect3D9句柄,然后执行IDirect3D9->CreateDevice,得到IDirect3DDevice9句柄。6 M  Z9 Z2 h8 g- Q0 N
  有了IDirect3DDevice9就能使用DirectX 9的一切绘图手段,而我们最关心的就是能够使用D3DXCreateFont来创建ID3DXFont,继而能够非常方便快捷的在游戏中显示文字。' I& P! F' u$ |6 d- u0 H) M# M  W! R
  / c% `4 o; A5 n1 [6 M- W
  用ODBG载入游戏的exe文件,“查找所有模块间的调用”,找“d3d9.Direct3DCreate9”:
% ^4 c1 f/ C& g: k2 _" \  + E9 E- H- c2 _1 E: v
代码:
1 m: }% C- u: h' q9 C5 q+ A/ e  00501974   .  BB 500A5400        mov     ebx, 00540A50                   ;  ASCII "Initialising 3D Engine"
0 A/ P5 j; h- `6 M$ A  00501979   .  E8 22130000        call    00502CA0
7 e& d' h% {8 d2 X' u  0050197E   .  6A 20              push    20& }8 G6 m! R6 f3 k5 M' f: Q; w
  00501980   .  8977 18            mov     dword ptr [edi+18], esi! u0 [6 ^0 Q+ K0 t* N- j) l' ~
  00501983   .  E8 2E8B0100        call    <jmp.&d3d9.Direct3DCreate9>' L3 m- W3 O; q5 ]5 x5 g  m- n6 P' g
  00501988   .  85C0               test    eax, eax: Q! ?1 c$ F& o' g5 y% J
  0050198A   .  8947 10            mov     dword ptr [edi+10], eax         ;  edi+10 = 58d550
( Q( [$ R! l+ K; k( p, e( L  
. l1 Y8 S) O. B6 E  s& N  往下找,就能找到IDirect3D9->CreateDevice:
  x) ]6 f$ D7 X6 q0 S  
  X" V2 l6 \* O2 A2 p代码:
) n. V( s# h5 s  J. C/ |/ j: T  00501B4C   .  8D77 14            lea     esi, dword ptr [edi+14]
5 f( l1 k+ l& c2 S* B$ u6 {  00501B4F   .  56                 push    esi                              ;  58d554  => IDirect3DDevice9: v' A$ f/ X4 q8 x# m* |" L
  00501B50   .  8D4F 40            lea     ecx, dword ptr [edi+40]6 Z. c7 y, {+ `: T. m
  00501B53   .  51                 push    ecx( t0 i" J3 k7 d6 k
  00501B54   .  6A 40              push    408 D9 C  [: B. f8 `0 H, q! \3 ~
  00501B56   .  EB 14              jmp     short 00501B6C4 [$ o4 _% T) P, G9 \( x) W2 p. Y: A4 I
  ...
2 n) `1 h4 H; H# g  T1 X4 s. q  00501B6C   >  8B4F 18            mov     ecx, dword ptr [edi+18]
1 q+ T) {, ]: t0 x: r% f  00501B6F   .  8B47 10            mov     eax, dword ptr [edi+10]4 Y% A/ o4 y7 N% I( M( x3 d6 t8 d
  00501B72   .  8B10               mov     edx, dword ptr [eax]
8 x( U3 s6 r' i( s; s  00501B74   .  8B52 40            mov     edx, dword ptr [edx+40]
% E. i+ p/ ]8 S& B( ~- o% X  00501B77   .  51                 push    ecx2 [, p! ]! u5 h+ N  Y  @! k
  00501B78   .  8B4C24 24          mov     ecx, dword ptr [esp+24]
; v8 v  T% H1 ]9 t3 A  00501B7C   .  51                 push    ecx2 f8 x+ y8 v  m! Q1 K3 o" K7 t. ?7 z& Z
  00501B7D   .  55                 push    ebp
; K1 Y1 E. {* C% n0 z$ X, n  00501B7E   .  50                 push    eax  ^: |; u+ E( x
  00501B7F   .  FFD2               call    edx                             ;  IDirect3D9::CreateDevice9 I4 L: a9 D" b+ p# l+ B
  
  D- Z$ ]1 P! ?1 M4 e. C& x& g# \& b  - k  q: W" Z5 Q+ n: G+ o
  由于是所谓的COM接口,没有十分明显的标志,不是很好找。! z% c  d& _( J+ f( Z0 k
  8 l" A4 A" t# v- {
  在微软的DirectX SDK d3d9.h文件中,IDirect3D9的接口是这样的:  o& w  S$ N) @( @: c; D7 M
  
6 N5 n/ f% Q9 ~' L) H0 C- N  7 G) I$ N$ A$ ~# n" C" R7 I% A
代码:
8 J& ]9 k3 ^( B' i- r  DECLARE_INTERFACE_(IDirect3D9, IUnknown)% @/ Z9 B6 T3 u$ a% l
  {1 }* b4 e1 a7 r- U+ n
      /*** IUnknown methods ***/
+ x. f5 a1 T4 m' W( v. `' g      STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObj) PURE;1 E4 b$ u0 C% F. F
      STDMETHOD_(ULONG,AddRef)(THIS) PURE;
6 {8 s- C, w+ ]+ Z* f( }$ ~8 L      STDMETHOD_(ULONG,Release)(THIS) PURE;
$ i" [9 X5 V7 h. f$ B' R  
# T1 O% x, {/ w. l" q3 A; P      /*** IDirect3D9 methods ***/* N) E* o, p7 z) j3 {0 l3 O
      STDMETHOD(RegisterSoftwareDevice)(THIS_ void* pInitializeFunction) PURE;
, z1 ]+ U, D+ {      STDMETHOD_(UINT, GetAdapterCount)(THIS) PURE;
4 p9 l* ]6 G* _% I9 A' d5 V      STDMETHOD(GetAdapterIdentifier)(THIS_ UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER9* pIdentifier) PURE;
, }: {7 ?5 N  `9 i6 c- g: S( l3 O      STDMETHOD_(UINT, GetAdapterModeCount)(THIS_ UINT Adapter,D3DFORMAT Format) PURE;
% A6 ]4 W" Q, C- ?      STDMETHOD(EnumAdapterModes)(THIS_ UINT Adapter,D3DFORMAT Format,UINT Mode,D3DDISPLAYMODE* pMode) PURE;7 b- H1 N; }  `3 W$ x4 \" g
      STDMETHOD(GetAdapterDisplayMode)(THIS_ UINT Adapter,D3DDISPLAYMODE* pMode) PURE;5 `+ p) L% v; r* V/ x( ]
      STDMETHOD(CheckDeviceType)(THIS_ UINT Adapter,D3DDEVTYPE DevType,D3DFORMAT AdapterFormat,D3DFORMAT BackBufferFormat,BOOL bWindowed) PURE;( g% f2 L: p4 g
      STDMETHOD(CheckDeviceFormat)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat) PURE;# i: i! B+ J1 `
      STDMETHOD(CheckDeviceMultiSampleType)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType,DWORD* pQualityLevels) PURE;) e7 M& K- n9 P, [
      STDMETHOD(CheckDepthStencilMatch)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat) PURE;
5 @6 ], m; {7 d" Q" q* k3 S      STDMETHOD(CheckDeviceFormatConversion)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SourceFormat,D3DFORMAT TargetFormat) PURE;6 Y3 B1 b8 n% _
      STDMETHOD(GetDeviceCaps)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS9* pCaps) PURE;
$ m7 G: c7 h1 X5 q      STDMETHOD_(HMONITOR, GetAdapterMonitor)(THIS_ UINT Adapter) PURE;3 J/ q) w) V! p% s6 p* s
      STDMETHOD(CreateDevice)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice9** ppReturnedDeviceInterface) PURE;
, m3 F: _" Y/ K# t      ' [0 P/ E! A/ A  N% C1 a" e0 {$ h
      #ifdef D3D_DEBUG_INFO
5 v- L3 o( i8 {      LPCWSTR Version;$ K: f3 c6 j. y
      #endif, ]8 \  I  I/ \- n3 x. E: ^
  };
0 x1 @+ `* C- u+ c9 y, |0 [: y( X  
3 O* _" h4 C1 V# r! {( f  8 U/ h4 L# M  B$ W0 j" [
  CreateDevice是第17个函数,所以它的地址是(17-1)*4 = 0x40,
7 e6 `- x# v$ q3 W. }8 O. f  00501B74   .  8B52 40            mov     edx, dword ptr [edx+40]' Q- u% l) p* F* a+ s
  这里的edx+40就是这么来的。
6 a$ E9 S( e. L" w% Q  
( \  @7 w. E8 W: v2 O% u" Q  如果觉得算起来很麻烦的话,还有一个简单的方法,可以自己编译一个d3d9的程序,然后反汇编看看。
! Q+ X" y( E5 _# N+ s& Q  
% X5 I8 }' t$ {) g  如果还觉得麻烦,还有个更简单的方法,直接往下找,通常会有一些调试文本能够帮助定位,例如:: y5 q3 j" f/ n% c1 ?4 T
  00501B86   .  BB 600B5400        mov     ebx, 00540B60                   ;  ASCII "CreateDevice"0 b; e5 ^% i  y3 s# I; G3 }9 C$ c
  ...
: c; ?0 R" |) S1 ?; e! V9 A  00501BBB   .  BB 700B5400        mov     ebx, 00540B70                   ;  ASCII "CreateDevice failed again"
/ v7 s0 R' O1 j6 G) g  当然,这个办法并不通用,有效与否完全要看游戏作者的脸色。
$ X3 y! L# _$ g  
, z2 \2 r' n! A+ g7 t4 d  知道了IDirect3DDevice9的地址,就能植入我们自己的初始化ID3DXFont的代码。
. g* A+ [( ]( n5 E1 w$ N  
8 {. _) i+ _( E  有了ID3DXFont,下面就是要找到用于显示文字的函数,并用我们自己的代码来替换实现。
" c' a. G' u4 v  4 p& t5 `5 {. p& l0 S  `
  随便找一段游戏中出现的文字,比如开始菜单上出现的“Full 1.37”,ALT-M,进入内存窗口,在所有搜到的该字符串上下“内存访问”断点,最终会找到地址在4FFF50的一个函数。2 F  X7 H5 W& `% c5 c0 q
  6 ?) j6 [, k2 h$ m9 u/ N, b  x
  该函数返回时,用的是“retn 14”,在4FFF50处用“retn 14”改写,切回到游戏后没有任何字符出现,说明这个函数正是用来显示字符的。
' Q: F4 _: O* A: C: @    G4 S$ f2 r/ B0 N4 `: T
  原谅我在这里对于怎么找到4FFF50的过程含糊其辞,一笔带过了。确实没有什么取巧的方法,完全取决于破解的功力,良好的耐力,以及一点点好运气。而这也正是游戏汉化的难点所在。, M0 r5 H, d) T* \  F8 D: ]
  ; y' f: _, ~) N$ f
  找到字符串显示的函数后,还要弄清楚该函数的接口。+ _9 @2 ]4 U( W! p
  9 ^3 Q0 u+ z+ j4 U; F' t! R4 Z- Q
  在屏幕上显示一个字符串,通常需要知道这些要素:字符串、显示的位置(X,Y坐标)、颜色、字符的大小,以及一些flag用于表示左对齐,右对齐,居中,加粗,倾斜等。
& ?3 l6 G4 j. u6 G  \# Q' M- E  
- `* r6 x/ l* l: {  前面说过,返回用的是“retn 14”,说明栈里有20(10进制的14h)/4=5个参数,当进入该函数时,栈上的数据是这样的:
3 s( F: ^8 K+ P0 ~& g' ~  ! A. I. R! C4 j8 J
代码:2 `6 N( c3 \7 T, F
  0012FE84   00453C48  返回到 GSB_1_37.00453C48 来自 GSB_1_37.004FFF50
5 }& M. Z; H1 ^4 C( u& ?- d" r  0012FE88   0012FEB8  ASCII "Full 1.37"
+ K) e1 T( C% N) L  0012FE8C   00000000
8 k! K9 }1 n9 C  0012FE90   40400000
- Z& d+ o% g4 g  L! d  0012FE94   FFFFFFFF
1 i) x$ E$ `/ i/ W) Z  0012FE98   447D8000
5 j4 s* E* s( A, T2 u( z. u3 Q  ; `2 @4 J! s4 v# k8 W* W# c
  第一个,很明显就是要显示的字符串,后面几个是什么玩意儿呢?
# O# }( k+ Z$ {) |9 p5 q  
; z$ H# ?! l3 Y* y+ M  ]/ q  回到调用004FFF50的地方,在00453C1D下断点:1 R  n) N8 y1 ~' Y+ n* W& @6 V% u
  
4 K. P) G0 F+ t1 q5 T代码:& L# ]" Y5 Y+ p6 m4 Y9 t
  00453C1D  |> \D94424 14          fld     dword ptr [esp+14]. e; G4 f; Z  r" O8 v$ p! N
  00453C21  |.  51                 push    ecx( H8 T$ G# Y; \' l* Q; o# g8 D  D
  00453C22  |.  D91C24             fstp    dword ptr [esp]                  ;  参数5  1024.0
0 s0 F+ k6 g) ?8 @, M+ n* P  00453C25  |.  6A FF              push    -1                               ;  参数4) O+ |" M: W9 c8 z/ S* Z
  00453C27  |.  D905 F4125400      fld     dword ptr [5412F4]
+ _  C( P; p$ h, ~  00453C2D  |.  83EC 08            sub     esp, 8# H: d" [* c  H4 l
  00453C30  |.  D95C24 04          fstp    dword ptr [esp+4]                ;  参数3  3.04 X2 _/ A. S6 V$ q5 [; Q
  00453C34  |.  8BD0               mov     edx, eax
% y, F- d3 Y7 B8 `  00453C36  |.  D9EE               fldz* c- Z; I2 t: M9 N! y
  00453C38  |.  D91C24             fstp    dword ptr [esp]                  ;  参数2  0.0" v, q, b7 a" ]0 `/ e
  00453C3B  |.  56                 push    esi                              ;  参数1! y1 C, m  Y! g" @2 v) F# Q
  00453C3C  |.  BE 01000000        mov     esi, 14 N2 O) U7 n$ t7 d
  00453C41  |.  8BCE               mov     ecx, esi
: {2 c8 H9 {6 |" s3 _  00453C43  |.  E8 08C30A00        call    004FFF50
2 m3 N( E; p+ e# ~+ `- R  
% H1 l# v8 I" k0 P, F  
5 F/ r2 `1 G) ~5 }# S! `& U  可以看到,参数4是一个固定值,第二、三、五参数都是浮点数。# u9 X! _# r8 c
  
% a6 N* {8 g: D/ z) V# A7 o! b  这里有一个技巧,在函数开始的地方修改参数的值,看看会发生什么变化,很快就能知道参数的作用。
1 \1 f- v3 M5 Y  
. Y4 \, S3 O  ~+ R  参数4是颜色值,Alpha和RGB值都是FF,就是白色,与在游戏中看到的字符颜色相同。
6 w4 L2 F1 i6 N2 x. b  参数2是X坐标,参数3是Y坐标,参数5用于调整。4 x0 V) l1 [" }! ]1 [; C( K) x1 G
  需要注意的是,还有两个参数是通过寄存器ECX和EDX传递的,ECX用于表示左对齐(0),右对齐(1)和居中(2),EDX是固定值58D6D0,一个全局的结构或类。; E* R: J+ J( @5 S& l( Z, v$ d3 p
  & C4 z; G- s4 |8 K. F' S6 O4 {" K
  此游戏有两种字体,因此用于显示字符的几大要素,现在还缺一个,就是不知道如何判断字符的大小。/ T$ R4 \+ Q5 n3 g
  ) |$ x5 j& v$ X; a- F- v* |
  在用于显示文字的004FFF50的上下断点,多跟几次,就会发现,每次调用以前,都会调用一个call:
3 g& f; f1 I/ G' R2 s: N- P  & _3 M  C3 e* z' G) u1 K
代码:- y- F& U3 Q9 C+ `
  00453BD5  |.  BE 44035300        mov     esi, 00530344                    ;  ASCII "zekton16.dds"6 c- b9 b) h) Z5 a3 o  o' S
  00453BDA  |.  E8 91B50A00        call    004FF170  ?" ^" d) N9 y$ v4 N
  3 g# [9 w5 m9 k$ g/ f6 Z4 G  ]
  004479E7  |.  BE 54035300        mov     esi, 00530354                    ;  ASCII "cwfont20.dds"
$ N9 r9 t. R7 {8 E4 o. [) k" z; N3 {  004479EC  |.  E8 7F770B00        call    004FF170% I5 `( d6 X! Y" [# c- d9 d
  
6 m* f& n* S$ _: Y3 `2 q  在游戏目录data\font下面有两个文件zekton16.dds.dat和cwfont20.dds.dat,由此判断004FF170应该是用于选择字体的函数。# i4 y/ O; p7 b* K# ^
  ; I7 R& X4 x2 Y+ [! J' s" R2 p  R
  总结一下:
0 k( w- y7 _; s/ W. Q  F, u& o  第一步,找到IDirect3DDevice9句柄,用于初始化ID3DXFont。, r" F6 Z" A! g# f" _& _
  第二步,找到显示文字的函数,用自己的代码实现之。
) f/ I; ^2 ]- r4 n' f- \  第三步,逐步找到其他需要修改的地方,比如用于得到字符串宽度、高度,指定宽度的字符串换行显示等函数。' i  ^* `8 ^; s
  ! h& H# u3 p' v& D
  
* o! c; p8 g  S! M  【具体实现】
: Y( b2 F+ o" z$ T  我用的是注入dll,然后打内存补丁的方式。这样的好处是便于更新,可以任意修改实现过程,以后游戏出了新版本,也只要修改几个地址变量,重新编译一下就可以了。# @& @. W4 c' i) w& t
  另外一个好处是,不以文件补丁的形式发布,没有版权问题。(有人关心这个吗?)& s+ @+ j5 \. K# i
  
2 B" o- z$ q7 ?" e  源码在这里:
) ^& |4 \: p; N9 i  http://gsbzhcn.googlecode.com/svn/trunk/src" [( _4 l( G4 h9 w! w9 O
  ! C* D" s% L& M5 K# i, W6 l( y
  简单的介绍一下流程:
" }  X8 s8 V8 |! \" o  1.CreateProcess启动游戏的exe,并使之处于挂起状态。
. I" T' @# e: @, Y  2.VirtualAllocEx在游戏进程上申请一块内存,WriteProcessMemory往里写入要注入的dll名称。
4 o0 ?9 J; E% \  3.GetProcAddress得到LoadLibraryA的地址。& g2 ?5 O3 K2 i4 V
  4.CreateRemoteThread运行LoadLibraryA,注入dll,dll载入时会为游戏进程打上补丁。
) j8 D( }$ C% D- T( K! N  6.WaitForSingleObject等候dll载入完成。
. J/ @3 z8 U* X* |1 n  7.VirtualFreeEx清理掉之前申请的内存。
2 E! s) H$ e- b& L" T  8.ResumeThread让打过补丁的游戏进程运行起来。
' K' x- Z" V. i* ]* q" p  8 f: A5 M; ]. z! I
  内存补丁主要是让游戏在关键的地方跳转到我们的dll,执行一段代码后再跳回去,或者直接用dll里的函数代替之。
* M* W; A0 B5 E5 ^. P  
! C( }( \# R( J  V3 C, K) H  
/ M' o2 _5 C, a3 M- [, x: O  【结尾】
* `. e$ D+ o: r8 o. w# ]  o: o& W& L  此游戏的汉化正在http://code.google.com/p/gsbzhcn/ 进行,文本不多,奈何翻译人手也不多,希望有兴趣的同学能够参与。0 g9 B  C) O- f* j
  
4 |. V: N5 ]0 W  |! K. s9 ^* U6 x--------------------------------------------------------------------------------5 H( A+ Y7 ^2 t7 N
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
, ]9 S" G  U& ?
8 ~* N9 w- m4 T7 a8 ]! r+ L% }3 u                                                       2010年05月25日 14:52:11
作者: zhdam    时间: 2011-2-6 20:47
楼主忒牛了
作者: tengbin    时间: 2011-3-10 15:19
高手啊,仰望。
作者: 笨蛋狐狸    时间: 2011-3-11 10:19
提示: 作者被禁止或删除 内容自动屏蔽




欢迎光临 冒险解谜游戏中文网 ChinaAVG (https://chinaavg.com/) Powered by Discuz! X3.2