本帖最后由 shane007 于 2023-8-12 09:10 编辑
& P8 I# a& w5 n. a2 M
& L. |5 b, s* t7 x, k2 j 这游戏的字幕放在LINK目录下,分为*.IND和*.TXT 这2类文件。
) h1 n, n6 o9 C' c7 ?" m$ ]4 O9 o 其中*.IND是索引文件,每4字节是一个索引,定义了每条字幕在*.TXT中的偏移位置。+ j3 g/ H Q1 o) x
) o& a, {5 d' V' V" m
比如,对话字幕保存在以下一对文件中,其中an代表的英文,此游戏共支持3种语言。/ T6 G; I, d8 t# S
RUEAN.IND9 ~- I+ K' ~9 _6 ]9 h. v4 g
ruean.Txt
) O# @1 Z2 S2 C. j( c. {" \' z: S& Q; o+ ~# E d7 F% T
*.TXT使用了加密方法,将字幕逐字节按照某种方式进行加密,具体实现可以参考代码。
% O/ y) O% Z$ l. v) m4 i, _ 提取字幕的方法,暂定为在*.TXT的解密代码后边临时加入一段代码,将解密后的明文输出到控制台,然后提取出来进行整理。, q" x0 `9 H1 X2 F& @& C: b
0 w( Z4 |( r0 ]1 L% c
8 S0 x g& A! K3 z- R/ ~# b2 i *.TXT的解密代码如下
( @- x* ^; j, v, w$ W- int TalkManager::countBoxLines(int idx, const Common::String &file) {
, E- |/ ^$ C7 ?/ F5 T- K - _vm->_fontMan->_fontFixedWidth = 11;
! l3 K! \# f) b1 I
. g2 K1 H* e+ }% w1 ~- // Build up the filename4 X9 N4 ?+ o1 b# T7 a; z n
- Common::String filename;7 z Q$ X( s% j5 g0 Y) c
- Common::String dest;( A- M/ R: i9 i/ ? R" d( v
- filename = dest = file;# N4 Z; R& N* ~( {9 x4 v# ~
- while (filename.lastChar() != '.')! |" l/ {) P# _; C
- filename.deleteLastChar();
3 ^3 s& l" G+ N/ W2 q+ M( ^! E - filename += "IND";
6 q( i% O( @9 |/ Y" M - 7 U, J& b0 M) R& ]
- Common::File f;
$ A, U0 D( O/ U+ R7 N - if (!f.open(filename)). M( k2 r8 m5 e" L& R
- error("Could not open file - %s", filename.c_str());# U) o: _) N$ l. R% r
- int filesize = f.size();
* w6 I1 o- S9 ~1 Q) @7 S - assert(filesize < 16188);
) p( R ^# x- A. |* q: ~+ @9 N& c, R - ) J) n$ d& x4 K4 f
- uint32 indexData[4047];* |$ R' R7 b# B: n( a9 Q
- for (int i = 0; i < (filesize / 4); ++i)
2 X8 `8 l. r2 B z! B - indexData[i] = f.readUint32LE();* P4 q j0 d9 f1 @
- f.close();6 X$ l+ Z) ?6 F5 z' ~5 \. b
- ) M7 _+ E. B& J! Q
- if (!f.open(dest)) `$ O3 C! f' ]3 D
- error("Error opening file - %s", dest.c_str());
; m0 r v1 z% _# k4 v! f: M/ U$ f4 [ - 5 H. g$ S6 w+ O$ p4 N( e
- f.seek(indexData[idx]);
! b" D( k( _8 T0 j3 A - byte *decryptBuf = _vm->_globals->allocMemory(2058);
1 C4 } f5 L$ |1 J w - assert(decryptBuf);
0 B. B& s# t& @
+ l: Z; N# k" e; ]# W- f.read(decryptBuf, 2048);
0 V! e% c, H2 p - f.close();- X6 D9 K0 L0 {/ q* Y/ ~& Z
- : p. Y. H9 B3 e5 `- B
- // Decrypt buffer1 _" n$ l9 ]2 r& m/ w* ~
- byte *curDecryptPtr = decryptBuf;
) r4 d2 o) w9 {+ w" s* p) q( g - for (int i = 0; i < 2048; i++) {
6 s. X8 j4 {" [; @" } - char curByte = *curDecryptPtr;
+ m/ k% S2 |' N8 n, J, Z4 q% K4 W - if ((byte)(curByte + 46) > 27) {
) P$ s Y2 e/ M) N! z - if ((byte)(curByte + 80) > 27) {
: M6 U: j! n4 y9 g( j5 y - if ((curByte >= 'A' && curByte <= 'Z') || (curByte >= 'a' && curByte <= 'z'))
, A1 Y8 A% m% W: P5 a - curByte = ' ';3 ~+ V' e+ n9 j. f4 w; ` O2 x
- } else {
/ o$ ]" a) j w5 \0 R" e* @ - curByte -= 79;; {: c, u0 ~ U A
- }
1 w( r9 e2 _8 F# ] - } else {
) p2 T2 T+ q# w1 [4 s p - curByte += 111;
8 V9 b# Y3 l c0 ], g - }# ^3 ]# D9 y5 l# M7 b T
- *curDecryptPtr = curByte;
- A% Z4 x- }7 z1 g( m; K. g - curDecryptPtr++;/ ~# c# r/ x) m& U' ^
- }
# s, S7 N; P! f7 H9 k
r' q& c. L& x4 n- // Separate strings
% C% [/ V* j, _, k; N( a7 h, K - for (int i = 0; i < 2048; i++) {6 R) A- c- c" W! b9 U8 @4 U0 J
- if ( decryptBuf[i] == 10 || decryptBuf[i] == 13); ?6 f! B8 e/ J7 B
- decryptBuf[i] = 0;
7 G( r J; R. [3 q! y; K$ u - }
& Q& Q/ H p, _. x4 \6 ^3 D
) X2 s2 e2 n% \0 x- //add by shane007
; \- o& r8 Q$ b; m: I - //debug((const char *)decryptBuf);
$ s% ?2 C# t; A) o* l6 @
, y7 [( Z W/ n$ F- // Check size of each strings in order to compute box width% w ~5 v! @# K5 [& A I
- int curBufIndx = 0;5 U2 [. X8 ~( I) Z; S
- int lineCount = 0; u5 L- t7 t3 b" K
- int lineSize = 0;
& C# ]# n$ B7 I* l - char curChar;) O. v0 D( E. F: K6 H
- do {
- T! Z/ g/ v# K" M' e - int curLineSize = 0;
% O ~: ~: d- Z9 y$ q5 \ - for (;;) {
9 `7 X x; L( b& K: P - lineSize = curLineSize;/ [5 p* [ ?! B
- do {; h$ r. `+ P1 x0 i E. K4 _
- curChar = decryptBuf[curBufIndx + curLineSize];9 j, s4 v1 l4 W. e4 o" a
- ++curLineSize;
# u K$ H0 \% G- D5 A - } while (curChar != ' ' && curChar != '%');' ?" [# y! o s* V7 g6 k" q: I
- 4 z% c+ n# I: x
- if (curLineSize >= MIN_LETTERS_PER_LINE - 1) {
$ U5 Z! {5 ]2 m: N4 S - if (curChar == '%')+ _7 h+ Q) ^! T2 G! K* B# s; p
- curChar = ' ';1 [1 w7 w9 L0 M* B# `. g% |
- break;: y9 B; y" L5 p% q. ]/ U1 O
- }. Y' Y6 g' {/ x+ f+ `5 j, R0 b1 D- E
- 0 t9 T! E7 W( {$ ]9 j
- if (curChar == '%') {
$ Y8 e- q0 F. R5 X; w% }1 F- @3 O - lineSize = curLineSize;1 `7 S. J$ @! L; w9 \2 O6 i' @9 d
- break;
5 \# i' ?. |; ~ - }" y- {) `" D, ?
- }% B. {: a( E1 a3 J5 D& ^
- ++lineCount;
# ^: d/ a- Y! P! \2 ]/ S. _3 t, G - curBufIndx += lineSize;
' }7 E( ?2 q' p* D2 V0 a; E7 f - } while (curChar != '%');
, `* u# q" |+ v! C: B& \ - _vm->_globals->freeMemory(decryptBuf);
; U4 q( y3 d+ n - return lineCount;
6 L& i7 l1 l. C8 j0 Z4 T - }
复制代码 . F, D; _0 C9 N& @; e& q
$ {+ V6 |% D4 B
|