本帖最后由 shane007 于 2023-8-12 09:10 编辑 , i% E" I7 k& R1 M$ \# @) S
- m: x; z' E0 f( [/ H 这游戏的字幕放在LINK目录下,分为*.IND和*.TXT 这2类文件。
: v" C) ?7 ~0 v# z 其中*.IND是索引文件,每4字节是一个索引,定义了每条字幕在*.TXT中的偏移位置。4 N/ s* K1 n9 ^, Z; e8 Z
/ _9 t1 B% F. H# _- r 比如,对话字幕保存在以下一对文件中,其中an代表的英文,此游戏共支持3种语言。: p: t' E- d5 i% _& W. c5 i) |
RUEAN.IND
4 W& x) @9 q' m ruean.Txt
! H& `" \/ Q! G
9 w- i6 x3 }- g; x *.TXT使用了加密方法,将字幕逐字节按照某种方式进行加密,具体实现可以参考代码。* q: C3 c" t) Y9 y* T
提取字幕的方法,暂定为在*.TXT的解密代码后边临时加入一段代码,将解密后的明文输出到控制台,然后提取出来进行整理。
6 n3 H& {1 Q1 u7 W) X
1 k* I4 J% `* j1 o, Q$ \% v
& \$ o. I" Z2 [ y4 W, I *.TXT的解密代码如下
0 Y1 t8 T' e& [" X- int TalkManager::countBoxLines(int idx, const Common::String &file) {
# }. O! { P: z. F! \) }3 V - _vm->_fontMan->_fontFixedWidth = 11;2 x; M0 [! ~8 l$ w7 h
- # k X% R K' H% n
- // Build up the filename
Y/ t/ _8 I) E. y& P - Common::String filename;
9 H* P& u1 S5 k& P2 r - Common::String dest;
; ^ }, { e! n - filename = dest = file;% G7 y; J1 o+ F+ M; s" p' T7 A
- while (filename.lastChar() != '.')
5 y0 i) C- N3 }1 x& r2 X - filename.deleteLastChar();/ l! m; E$ p) K' ~% K6 O
- filename += "IND";
, [& Y9 o7 c( Y5 L; t
0 y$ }* L9 p9 S, R: `% b- Common::File f;* n% V# y1 V7 r6 h6 w- U- |
- if (!f.open(filename))
8 R+ F! ^ Y4 \" v. b* b1 Z7 W - error("Could not open file - %s", filename.c_str());1 u0 q' Y2 t% Q' L8 w0 i
- int filesize = f.size();
3 X, R4 h, ?3 x | A1 h' C* J) m( I" ~ - assert(filesize < 16188);* W( R ^. m7 d7 {& V7 O( ?/ U
- % ^: x( `6 H4 }9 @1 V$ Y3 c
- uint32 indexData[4047];& X3 K9 Z. R! e( S; i1 X
- for (int i = 0; i < (filesize / 4); ++i)6 k4 b6 H* M+ F8 l6 ^
- indexData[i] = f.readUint32LE();; V/ V$ A6 G! d. A: w% u
- f.close();- h6 j/ q; l1 `: y
- 4 p8 L! E. Z: _
- if (!f.open(dest))
7 n8 N; G- K. h' [ - error("Error opening file - %s", dest.c_str());
5 p/ M3 S _3 C$ Q9 l5 V; Q
6 Z8 S6 G9 h8 `+ v' q- L8 H- f.seek(indexData[idx]);# G( K: K2 c. M$ ], W( X2 E% ]1 {
- byte *decryptBuf = _vm->_globals->allocMemory(2058);
" s5 ]5 u& d2 V0 S, l9 V' ] - assert(decryptBuf);5 O# U# I! x; N0 O( r, H1 v' q
$ f" _& | h3 j z, g. w- f.read(decryptBuf, 2048);, C) ^( t3 ] Y& X+ `4 ~7 _
- f.close();
4 {0 z, }9 v! j2 Q7 U4 A2 c - * [: Q, Q# T& V
- // Decrypt buffer
0 P+ P+ d0 w9 f' _# A& i( J - byte *curDecryptPtr = decryptBuf;
5 Y* o! N" Q1 l2 \5 H8 i - for (int i = 0; i < 2048; i++) {! ^6 y, j: I( a* a
- char curByte = *curDecryptPtr;2 {3 w. d0 \! P" N5 N
- if ((byte)(curByte + 46) > 27) {4 |; j' ^+ |# o* v
- if ((byte)(curByte + 80) > 27) {
. @* S z% |4 f4 \ U7 u/ p9 z- s, ^ - if ((curByte >= 'A' && curByte <= 'Z') || (curByte >= 'a' && curByte <= 'z'))3 [3 V" C, N% D8 ]+ z& q1 p
- curByte = ' ';
0 h8 w; }( q* ?9 k( F& D - } else {" g5 u( ~7 t; O. V# U+ g; Q
- curByte -= 79;. `/ {7 h5 w$ f ?2 J s9 P
- }
! T- ~1 P2 T, R ] - } else {5 ?6 E' G% q% e9 S
- curByte += 111;
+ m6 Y- Q6 _8 d- ~; w/ M3 G - }
/ ]$ `+ H b; J6 T, E/ Z3 C - *curDecryptPtr = curByte;& q7 m `* s- ^6 {, R, ^
- curDecryptPtr++;) ^: e$ x5 o- }) o/ t
- }( H3 L7 w' v0 U9 E
y, F: i1 e* N# b0 J) p* B+ m6 p) Y- // Separate strings$ h5 V" e/ I" O3 z4 G d
- for (int i = 0; i < 2048; i++) {( ]3 p, Y9 E* O5 ]8 l+ s8 G3 e
- if ( decryptBuf[i] == 10 || decryptBuf[i] == 13)9 P W/ K! {: q3 O- J! Y' c( H
- decryptBuf[i] = 0;" Z( Q, Q+ l: Z' \ J5 }
- }$ g H5 v+ l; V
- 3 _! `' F) r4 e5 p- d
- //add by shane007
/ V8 p+ Q( c/ L7 Q8 G0 y, g - //debug((const char *)decryptBuf);* z. j. E( c n+ {9 l$ ?. n
- 1 Y1 f6 Z. k$ Q7 X, c
- // Check size of each strings in order to compute box width/ Y4 P4 J! [; \" D& G, g$ {
- int curBufIndx = 0;
' G# l$ h+ c! W - int lineCount = 0;0 ?# L. V7 P. W
- int lineSize = 0;8 ]& m! j, p' u2 k* P
- char curChar;! }$ @0 S. X7 _9 B
- do {
9 c9 @- y, u/ u, ]' w9 u' a - int curLineSize = 0;1 V3 S5 S( b( u) k% \, Y2 N
- for (;;) {: P- C6 H2 h( x' u% W
- lineSize = curLineSize;6 ]1 B$ v9 m/ w% V/ s+ j
- do {- U' e5 Q# B* X2 \- s8 Y9 E
- curChar = decryptBuf[curBufIndx + curLineSize];3 I" g5 n6 c+ N7 Y2 V2 g& V
- ++curLineSize;
; b- l [& p% A( c) q - } while (curChar != ' ' && curChar != '%');
3 P8 Y: ~( [9 E9 X4 e8 G. [ - . C7 G1 C2 ~; r& w! p1 a
- if (curLineSize >= MIN_LETTERS_PER_LINE - 1) {2 s S6 L* L9 } l* k
- if (curChar == '%')4 e% O" K" v8 Y% [ w+ O' t
- curChar = ' ';
' Y; U0 Q7 p# [# y) W: K - break;
7 H4 A x: d a6 Q! t% X - }
/ T2 }6 M# V+ V8 b# N/ N2 s - & w E5 f' h: F, g$ V) z: M
- if (curChar == '%') {
& ?+ E; f8 P' d$ h# e' m+ b - lineSize = curLineSize;
; t& t7 v1 n5 D( ?/ M' L7 F - break;. w9 G8 x d" E: G, T
- }
1 V+ y: q% W9 \0 r - }
! c, A: Q) ^; ?& ~ V; E- P - ++lineCount;
4 I' G2 d) _$ w9 y - curBufIndx += lineSize; b+ s6 D1 H) N; d
- } while (curChar != '%');! ?% e+ y* k/ y2 O: G' V
- _vm->_globals->freeMemory(decryptBuf);
& N" _( M+ Y+ N' o% M, d" C- R6 F' G - return lineCount;
" _; U" j- d* D - }
复制代码 9 p$ A6 R; D6 N: s5 P+ Y
# F" d) l+ H: [! i0 i
|