本帖最后由 shane007 于 2023-8-12 13:57 编辑 ; v" h% H3 D1 o6 H
( t; p4 H, H" f这个游戏原本是没有字幕的,但是在Scummvm论坛上发现了一个帖子,
" j `3 }+ |9 e- z) U! K H% B* `' U; U讨论的内容是关于在原本没有字幕的游戏上加上字幕。(最初的缘由,是为了帮助一位失聪的朋友)
3 M8 @' p2 X, _' i6 F: zhttps://forums.scummvm.org/viewtopic.php?t=7168
1 u- B& J1 d" Q" L3 K[Scummvm-devel] Displaying subtitles in voice-only games (narkive.com)
3 w' M* p- N9 d: l( s) ~/ R# a4 G- D9 `$ A( b' n
前段时间第七访客出了25周年纪念版(The 7th Guest 25th Anniversary Edition。
7 [9 V, ]+ f9 E) C在这个版本中,游戏的视频是有字幕的,因此把这个视频的字幕用到Scummvm中就成为了可能。( j& X- C* Y E$ m1 w
7 B& P& o7 N: W1 Y- K# z8 v
我查看了一下最新版本的Scummvm的代码,发现老外已经加入了一部分代码。/ t8 b9 R c# o3 I( x! J
在此基础上,汉化是大有希望的。此种汉化方法,也是前所未有的,如果真的实现了将会有重要意义。
0 ]: @9 ~! @# H! Q. }( j, `* h& G9 u1 C5 o& y. l/ t! Y3 y+ i- b
类似游戏还有- · Groovie
: M3 L8 Z7 o& I- \% j8 a2 G - - The 7th Guest4 ]# U; r# l. N- B& `: v
- - The 11th Hour! S; D, n& |! C) k, y
w, V/ v6 x6 ^- · MADE
2 L" h# v: H* {0 z8 B2 \ - - Return to Zork (descriptions are text only, while spoken dialogs lack
- K/ w' C# Q F - any text)7 X! }( d# G5 E% Z, A8 ^
6 B Y4 @. V2 T6 s- · SCI 1# h( r% ^2 N/ x
- - King's Quest V (CD Version). In this case, just enabling voice and text
, ~, T7 [9 O1 j! U4 d8 P3 y - simultanously would allow a 3rd party to create a set of MSG files( N c4 z% T1 T* s1 E. y
- containing the voice transcription/translation, as it happened with Gabriel! A+ W( c3 V* P& K# n& i% P3 V
- Knight II.
3 G6 C% Q/ e5 U) D8 s: ]8 r - " {! c4 C. [) Q% R- }
- 6 `0 H0 h# X: K! [- K
- Future engines:
* F2 p* F# P$ |) U0 ^3 D8 f - " Y! p9 h" h! F0 \5 d4 K+ c
- · SCI 21
3 e1 N, [' s7 d, _: y8 I* d - - Gabriel Knight II: The Beast Within (Already a fan patch available in
3 Z; n1 d/ f, l* c% s* z - order to enable the text display feature)# \; b# O0 k$ e4 ~2 W+ R4 s8 T
- - Phantasmagoria0 ~2 _4 R, ]) J6 X$ j b/ X
- - Rama6 _/ F3 I2 \2 v1 W
- - Shivers
% U$ n' G7 _( O - - Phantasmagoria II: A Puzzle Of Flesh; f' h- H7 m) z3 |! O
- * K6 x1 F, s$ J j
- · SCI 3# t; w- q" q7 ^
- - Lighthouse: The Dark Being" ?& c T% z: Y( M$ K2 I8 ~
- 7 w' U4 r# o2 [5 I' e! p
- · M4/MADS# C, O% r' `! W6 d" Y/ Z& Z$ z
- - Orion Burger9 C9 k6 N2 F) ^
5 L$ [6 [& `# ? U# m- · Mohawk% t$ c+ G7 Y5 [- x6 g9 o4 a! @4 k
- - Myst
+ S5 f/ d1 m7 I. [( n8 J- \) F - - Riven: The Sequel to Myst
复制代码
1 D5 D, a# K* j% r0 z" r+ m5 f( V. P3 p) T
# [. u2 n: h+ h
6 w; Q" ~% `7 X; h相关代码如下
% { f0 ]: S v9 f, C' Q8 ` x2 j- bool VideoPlayer::playFrame() {7 l6 C( ]' X$ |7 J' \- A; e3 C
- bool end = true;) @6 |% c1 Y$ T; x5 ~
/ N) M9 U- {1 U3 K7 e3 {9 U7 g3 x- // Process the next frame while the file is open
* h! T8 `4 f d( B5 b - if (_file) {: T5 T3 A0 X% U/ A6 g
- end = playFrameInternal();
. P, w. a0 E* H; f/ s. q
' e: X, b9 J/ d0 b; B0 ]- _subtitles.drawSubtitle(_lastFrameTime - _startTime);# n$ Z! g$ W9 P
- }
复制代码- bool Subtitles::drawSubtitle(uint32 timestamp, bool force) {! W0 i5 a; S* G! s
- Common::String subtitle;
1 R0 u( a k _6 P' ~* } - if (_loaded) {
& C( b8 ?! g, b( p% A/ x - subtitle = _srtParser.getSubtitle(timestamp);& z* l* j7 Q) w
- } else if (_subtitleDev) {
8 Q2 o8 F. w/ o- C - subtitle = _fname;, |! V* E) Z& g9 a! D
- uint32 hours, mins, secs, msecs;4 v4 ~+ R7 }6 y6 {2 N* W8 T4 F
- secs = timestamp / 1000;
: c# a! t" |& R! ?) o& N! ?2 {# C( |6 M - hours = secs / 3600;
& m1 I8 t4 C8 F( ?) S# {2 z - mins = (secs / 60) % 60;
9 t8 ?" i* `! l$ V - secs %= 60;
9 P+ S7 C3 \' r& v& N- v - msecs = timestamp % 1000;
% B# X% a( B6 Y# Z: M5 W - subtitle += " " + Common::String::format("%02u:%02u:%02u,%03u", hours, mins, secs, msecs); \+ q8 R) P0 _3 n
- } else {
. _8 k& e' o5 y* L& U5 B& A - return false;
7 b8 Q1 F! P |9 c' r+ l: j' j - }
- q% k" ~5 H+ |9 q - 2 O2 E8 C0 I: W4 O* G
- int16 width = g_system->getOverlayWidth(),
1 n* F. Z( N# \- i - height = g_system->getOverlayHeight();
4 N3 C$ Y+ x9 M ~ l P+ c) d% b - % I; u5 I* S: F3 C! z* ^' S
- if (width != _lastOverlayWidth ||
0 k3 J* n1 \2 U5 S" F - height != _lastOverlayHeight) {1 m f o' m7 Q
- _lastOverlayWidth = width;1 n, Y( Q% ^7 u# |
- _lastOverlayHeight = height;
8 Z1 U$ O2 H; R% a4 ? - / T Q# q+ B7 h" j4 [. d0 [
- // Recalculate the real bounding box to use9 e5 q& c8 j/ [2 ]1 a8 k
- _realBBox = _requestedBBox;1 ?* o+ r' r, b. v
. V7 Z+ F, W2 ]" U- if (_realBBox.bottom > height) {0 _+ X2 ?8 |. p A( [" m0 N
- // First try to move the bounding box. H) I7 U- ]" h5 D3 R* V1 |
- _realBBox.top -= _realBBox.bottom - height;
7 l0 L; Y& e! d( X" L ] - _realBBox.bottom = height;
5 ?2 h! p, |" _* E/ x' B& v- A- w# N - }; e9 L- @; b' v+ t0 I
- if (_realBBox.top < 0) {
9 [ W+ k" t- C; P# f: k1 W - // Not enough space
3 [* M$ o$ s, p3 Z - _realBBox.top = 0;5 c+ U9 I3 |0 D) E$ K. ]) `
- }
8 T5 e4 W' J* Z2 T* T5 D - 7 ]* `& \9 L. @8 ^, N4 b; B
- if (_realBBox.right > width) {
" V& ?. R0 m/ y - // First try to move the bounding box3 Q$ G3 c! K, G m) d
- _realBBox.left -= _realBBox.right - width;
+ a/ l/ B. N8 X: t3 u( b9 E1 } - _realBBox.right = width;
) \9 t. M$ x! _& [2 k* \9 r - }
2 G+ N7 g; K6 F" N, r - if (_realBBox.left < 0) {2 I. v, K- `2 [, o
- // Not enough space3 M1 L& b" F+ R* e
- _realBBox.left = 0;# n4 Z7 S1 _! J4 D4 k# k* Y1 A9 W
- }7 |& V& u9 O: h) ^, F
- / T! g4 i0 f, x& ?% o9 ?" v
- force = true;
4 e8 ~6 o& C, _% { - }* L" c% N4 L( C+ S* J7 i
- ; }: F+ N1 S7 _+ n
- if (!force && _overlayHasAlpha && subtitle == _subtitle)
$ G0 U3 g; Y* K9 U7 {2 Y' g - return false;& t" a5 h: F6 y" V: e
1 W6 g% C* h- d' {$ C6 l- if (force || subtitle != _subtitle) {
, l" z& a) x( P! e, i6 j5 A - debug(1, "%d: %s", timestamp, subtitle.c_str());
7 a5 e Y, [3 Q4 W7 F# E
1 c0 s! v* {& L+ o9 n- _subtitle = subtitle;
6 S; F( i1 R& ]6 ^ - renderSubtitle();
& N4 L$ X. p G- ^# b i - }
. s2 Z }8 [. ~: v2 q - ' M; d0 N; Q, @9 r0 V+ H- Q6 m
- if (_overlayHasAlpha) {0 n c- s( j! k1 o0 u1 u* s2 |) j
- // When we have alpha, draw the whole surface without thinking it more3 M3 g# i L+ O2 s& s$ {- G4 T u% l
- g_system->copyRectToOverlay(_surface->getPixels(), _surface->pitch, _realBBox.left, _realBBox.top, _realBBox.width(), _realBBox.height());6 R0 Z; C2 L2 z. L% E$ a% B+ Y7 Y
- } else {: D1 [7 M6 a' ?
- // When overlay doesn't have alpha, showing it hides the underlying game screen
6 ?. q6 k& P$ j# [0 ? - // We force a copy of the game screen to the overlay by clearing it& ^4 S5 |4 Q* L- ?8 h! s
- // We then draw the smallest possible surface to minimize black rectangle behind text# w; H: t8 e8 z2 G* l, S
- g_system->clearOverlay();; w3 L% B$ Q5 E/ I
- g_system->copyRectToOverlay((byte *)_surface->getPixels() + _drawRect.top * _surface->pitch + _drawRect.left * _surface->format.bytesPerPixel, _surface->pitch,
3 o; l( a0 q7 U2 E1 G - _realBBox.left + _drawRect.left, _realBBox.top + _drawRect.top, _drawRect.width(), _drawRect.height());
: d1 {9 l* C0 m* Q - }
* z+ g. a" v" h- {) `% G - h8 s z1 t4 x
- return true;
( f+ k/ v( U5 _9 K, X - }! v) ~4 q4 C' \6 a! ^2 `6 v# [
复制代码 ! @1 c) M* G/ A! I
6 B1 B! M' Y1 s6 {$ a: n D' J0 m. ]5 {. \- w
# ^9 X2 X6 W2 N
; P7 o4 i# O6 V" y
1 V: Z5 ]+ b! o
3 ?0 @0 \4 f1 z+ O) F( k |