本帖最后由 shane007 于 2023-8-12 09:10 编辑 6 N5 Q9 m. _( k; c& v8 c3 K7 i9 y
$ q7 G s* v3 @+ X0 [1 r" E 这游戏的字幕放在LINK目录下,分为*.IND和*.TXT 这2类文件。
, |$ r* v; e0 c0 N3 t" O, b. T" p 其中*.IND是索引文件,每4字节是一个索引,定义了每条字幕在*.TXT中的偏移位置。7 g) f2 ?4 Z3 R: ]; S- l
" _6 b9 e* L6 a. G! L6 n2 p
比如,对话字幕保存在以下一对文件中,其中an代表的英文,此游戏共支持3种语言。
) [* Q3 Z$ [ |& R RUEAN.IND! x9 x! Y1 C) c5 T' ]' n
ruean.Txt
# V1 f9 [3 F- W: x+ s7 ^
( s, s T! }! p( R0 k9 G *.TXT使用了加密方法,将字幕逐字节按照某种方式进行加密,具体实现可以参考代码。
, ^; l+ H9 | \( I" h& E9 R% o 提取字幕的方法,暂定为在*.TXT的解密代码后边临时加入一段代码,将解密后的明文输出到控制台,然后提取出来进行整理。6 ` i- F; w1 W9 _/ U
) d$ w3 N+ ~* X/ N. u
, C6 `) E5 F# @( o *.TXT的解密代码如下
" Y- R# A( e+ r- int TalkManager::countBoxLines(int idx, const Common::String &file) {2 |0 P& l0 s! [8 B
- _vm->_fontMan->_fontFixedWidth = 11;3 q0 G1 V& s- J6 N
- & P5 O+ w9 J* D6 W
- // Build up the filename% _" w, h! s( e4 B: K! |
- Common::String filename;
/ r+ u# M7 K& Q( h# s7 a9 W: w i - Common::String dest;# t8 X7 G+ j! f [5 S+ G& @7 r
- filename = dest = file;( T+ p& _# W0 n8 v1 x/ K: ?2 q
- while (filename.lastChar() != '.')2 B/ D7 b$ N4 d9 H) t+ S
- filename.deleteLastChar();
: w' l: Y3 o; G& o - filename += "IND";
- t2 G5 }2 q$ ]/ L0 _; ]" ] - + b! m' S. ]4 [! k0 Y
- Common::File f;5 h8 ?& w% W+ h4 k0 r: z: F9 N& |* _
- if (!f.open(filename)): Q- Z B1 }* G5 g/ o' h
- error("Could not open file - %s", filename.c_str());" A& h+ S1 A$ J4 F4 \, y# B
- int filesize = f.size();% M1 L* C, D8 y# m4 T. V
- assert(filesize < 16188);7 x0 W6 _% V1 [
- % t$ J/ I& b# g3 J
- uint32 indexData[4047];! p: x; V% w, l: _
- for (int i = 0; i < (filesize / 4); ++i): X7 f$ s+ E2 p7 ?; U# \
- indexData[i] = f.readUint32LE();! y1 X! \# `' j$ _9 a2 [
- f.close();
- ?- _5 f4 w+ ~7 x
. t5 S. L8 f8 ^. A2 w2 ^ O- if (!f.open(dest))8 n/ i& i9 E2 m2 {; V; Z
- error("Error opening file - %s", dest.c_str());3 K3 f5 [1 p4 V+ g: U- n5 F
) m) n$ u* Q9 j2 l$ F x6 w/ ]. r- f.seek(indexData[idx]);
8 P. C- \" M5 n m( Y( j - byte *decryptBuf = _vm->_globals->allocMemory(2058);( _3 h5 n- Y C. @! Z- Z- e6 }" l! p$ _
- assert(decryptBuf);0 X8 Z1 O+ c& S* Q7 r$ f, U) P5 g! }
- 9 X+ h1 R: L- C4 U& ]# c) H+ }
- f.read(decryptBuf, 2048);* s! W4 F! M5 [) t# z
- f.close();: e j0 s# [6 r* V; G3 G, Q0 ]+ \
7 z7 [4 Z# Q/ P" V5 q- // Decrypt buffer
o* j) Y( w- L$ z: b7 N - byte *curDecryptPtr = decryptBuf;
6 ^3 ]% B" \2 z - for (int i = 0; i < 2048; i++) {0 g6 E7 w4 q: p3 U% Z! E, U
- char curByte = *curDecryptPtr;, v( I! R. N% |. F7 a/ f2 @3 ]6 g
- if ((byte)(curByte + 46) > 27) {
9 o1 q2 J$ M: G8 G( r$ d - if ((byte)(curByte + 80) > 27) {4 [) X8 E5 L- |1 O& K
- if ((curByte >= 'A' && curByte <= 'Z') || (curByte >= 'a' && curByte <= 'z'))
1 E4 @8 M0 `: \, d% p - curByte = ' ';
8 ~+ E- b0 T/ j - } else {
" d' ~. r: Z& E2 N9 e& M" e" u0 ` - curByte -= 79;
b' W2 T0 i0 I. \2 d% B - }
$ }" m, ? c6 o/ i& M - } else {- V1 A" g2 T% D/ h( i5 G. n' A
- curByte += 111;
+ T( T7 p) e$ J. Z* B2 n - }
" V* F. a" K; m9 Y& J) r; [" J - *curDecryptPtr = curByte;
4 D; N" b& `# J* a+ l - curDecryptPtr++;
8 I% h y. ~, m0 w1 u4 x - }
( k( d! M+ h( A& N: l2 J - 2 Q; r. }" ]5 W/ q- M% E
- // Separate strings) x$ I8 N5 ^9 T" p5 w
- for (int i = 0; i < 2048; i++) {+ T2 Q, K! d7 L% l8 s$ y. f
- if ( decryptBuf[i] == 10 || decryptBuf[i] == 13)2 ~# O9 U* h5 W# u7 u2 G
- decryptBuf[i] = 0;: Z3 p. b$ E+ t, q" f9 j
- }% E( g7 p1 g9 A4 P+ a0 I$ o2 d
- - j6 T! @2 z& C, ]: Z
- //add by shane007
" Z' |$ r1 N: i+ K: @$ w4 k9 q8 r - //debug((const char *)decryptBuf);
& E% T& q, @7 m* f& H' d - * E) i; E$ v- f- E# m+ V8 X
- // Check size of each strings in order to compute box width# g2 j" ~/ E/ t4 ~" O# h+ G
- int curBufIndx = 0;1 A! i& t# f$ _" Z1 x
- int lineCount = 0;
* P' L! q% K7 U - int lineSize = 0;' c; ~7 B( S7 [' U
- char curChar;
9 A' F/ h- I" y$ b. E% m - do {
j$ s2 u2 R( K - int curLineSize = 0;$ N7 ^( K7 `& ^& Z8 L- I, ]
- for (;;) {
7 w' w0 [+ W F9 p" q& j0 N - lineSize = curLineSize;/ _5 J* I8 m7 V2 r# C: V) g
- do {! Z U- s! T% c- J- H$ V0 Z0 {$ y
- curChar = decryptBuf[curBufIndx + curLineSize];# X; R: |! C# C+ ^
- ++curLineSize;
" M$ d" _! ^( h" H8 ?" ]9 x! c - } while (curChar != ' ' && curChar != '%');4 | k2 m O/ Q0 j4 h9 x( l
; g( j) R! z+ O" W; M+ x' U- if (curLineSize >= MIN_LETTERS_PER_LINE - 1) {# \7 z& B. ]7 ]& ]% T' @% L
- if (curChar == '%')% o' Q r7 |# c, W. q* e
- curChar = ' ';
5 @$ }5 w! g/ f3 M5 O - break;
% ]! `; o- ~) I& y2 E - }
' l F4 J1 Z7 |9 [( N; e U# T
# L. r7 t- s3 M$ ~5 d( |* y6 T. Y- if (curChar == '%') {% b0 J5 }3 [8 {7 e& U
- lineSize = curLineSize;
. V6 S5 ~8 { s# x! u1 p5 `& k - break;, t/ ~7 h& M" d
- }
/ Y+ g. L; \+ e; \7 s - }
U2 w$ O9 [$ M/ a5 H# h - ++lineCount;
. ]% ]- o4 b0 o: R2 a - curBufIndx += lineSize; H0 T* v2 Z, \$ J
- } while (curChar != '%');
2 T# \" i& p0 c2 L+ ` - _vm->_globals->freeMemory(decryptBuf);
; O; G( o i0 J3 a3 ?2 P - return lineCount;
% u' `& r5 N. J. h& ` - }
复制代码 " ~ l+ r+ K( B! |, r Y, u
# g6 _5 i+ N+ J! f* q, P/ C5 Z |