本帖最后由 shane007 于 2023-8-12 13:57 编辑
' X- s' P( J1 \' P0 z1 _( t4 }" s& c; p6 A0 f
这个游戏原本是没有字幕的,但是在Scummvm论坛上发现了一个帖子,8 U+ J0 y, Q O7 p* H
讨论的内容是关于在原本没有字幕的游戏上加上字幕。(最初的缘由,是为了帮助一位失聪的朋友)
0 `! Q! ?5 ?: c* Ahttps://forums.scummvm.org/viewtopic.php?t=7168/ _( t* w- U0 n
[Scummvm-devel] Displaying subtitles in voice-only games (narkive.com)8 I% n8 u! Q: J
- h# ~7 Y1 |1 t& r8 [
前段时间第七访客出了25周年纪念版(The 7th Guest 25th Anniversary Edition。
/ I! Z6 H0 t& A2 C' Q' `' h9 T9 f* k% @在这个版本中,游戏的视频是有字幕的,因此把这个视频的字幕用到Scummvm中就成为了可能。
/ H1 p1 I" a" W$ e3 b9 m: _6 e% x# H5 r
我查看了一下最新版本的Scummvm的代码,发现老外已经加入了一部分代码。
9 o% \; V" j0 a在此基础上,汉化是大有希望的。此种汉化方法,也是前所未有的,如果真的实现了将会有重要意义。2 q& e4 p; l) E8 M2 E$ R2 `
- c" j2 g8 L+ H# O/ \0 [
类似游戏还有- · Groovie1 f( g6 A7 D% T0 K) @/ H
- - The 7th Guest
( P5 z& `8 a* C: A - - The 11th Hour# A/ g9 B' q) W) Z! T
% `+ z( b4 Z: E! F6 Y% R+ f9 s- · MADE
) E) q. j# [" T, b - - Return to Zork (descriptions are text only, while spoken dialogs lack. u1 N+ v* u% S: r
- any text)! I# I( h- k; s5 ^* `3 O3 q$ ~
- b% y$ l7 \" Q) y0 P- · SCI 1
% |. q/ c2 l3 k& N0 P - - King's Quest V (CD Version). In this case, just enabling voice and text4 W% T! [/ d6 n+ L+ p
- simultanously would allow a 3rd party to create a set of MSG files
( t! c5 k/ X; g* x8 _ q - containing the voice transcription/translation, as it happened with Gabriel
; ~( {+ Y; Q: z6 M* T5 e- L7 _4 P! {, X# @ - Knight II.
0 T) X, p* E. S' @5 ?, ?& H9 m - ' R& x4 Y U6 Z! W+ Y9 n k
- 8 b* ?- `+ B! ~
- Future engines:1 M) S8 w) v& t# d6 K2 e
- ' J$ }- i+ F; L8 q# w" R
- · SCI 21
2 q q9 k! T* g6 { - - Gabriel Knight II: The Beast Within (Already a fan patch available in
+ ~8 {' B7 s& ~- _ - order to enable the text display feature)
8 D6 N! { l' C' t4 @ - - Phantasmagoria
2 L$ i7 d! q( j% C; ~ - - Rama$ p7 }! M1 p0 p/ z3 G
- - Shivers, ^9 e% n* l: O) }6 M, V* V8 }
- - Phantasmagoria II: A Puzzle Of Flesh
5 f2 s9 v! |) Q+ J9 g
( R$ Y: S' p* g$ |3 {- · SCI 3/ n* i2 Y! r5 }5 P8 E3 c
- - Lighthouse: The Dark Being7 @! G8 o1 t3 J) T6 M- O
- $ P6 @' {, v/ \7 {/ h8 n# i# ]
- · M4/MADS
8 u) k+ C5 C9 F$ X1 s' g - - Orion Burger
/ Z( f5 C9 `+ A2 n - / X( }& j' d$ f: ^+ B
- · Mohawk* f2 a& x+ y# c' o% u0 } v
- - Myst
6 i5 X' V3 ], e M - - Riven: The Sequel to Myst
复制代码
- Y0 T/ R5 U+ Y2 [ M5 A6 w- d. p* S7 S9 K( d: B6 ?. l, p
. g, O1 ?3 f4 D) B$ \
# }* G G7 ]9 e k( s+ _, @4 c相关代码如下
* `& Z5 Q, c2 b [2 T% y8 g- bool VideoPlayer::playFrame() {
' w1 S8 Q5 T$ y' S1 l# C - bool end = true;
4 ]* @* |8 n2 `' E3 }3 L) K - 6 Z4 c3 ~4 O& E A! d
- // Process the next frame while the file is open0 n e I8 ?- L
- if (_file) {6 y. v9 D+ l0 d5 j- M/ z
- end = playFrameInternal();1 N Z- I& S' }! M2 Q/ g
- 3 ~9 S; b& s2 Q
- _subtitles.drawSubtitle(_lastFrameTime - _startTime);
( p' ]8 Z9 x/ H) X, ` - }
复制代码- bool Subtitles::drawSubtitle(uint32 timestamp, bool force) {
, W* M9 u* z& Q: }" r - Common::String subtitle;4 {, d/ f: N/ D, I/ C
- if (_loaded) {
& s* S9 Y& Y+ n( }, I+ o - subtitle = _srtParser.getSubtitle(timestamp);0 S& j0 m4 ~) a: [- _6 Z
- } else if (_subtitleDev) {, C% B0 o w7 W; a0 L9 P$ n
- subtitle = _fname;
: s7 v( F/ S. x; R - uint32 hours, mins, secs, msecs;
7 B: U8 ?$ L# B" p$ o3 R - secs = timestamp / 1000;
& `/ g. @8 n! K7 |, K - hours = secs / 3600;
6 }0 `! |6 a9 j8 X - mins = (secs / 60) % 60;
$ g* Z* u! [1 e x - secs %= 60;
7 k( g. Q$ V! z - msecs = timestamp % 1000;
5 ]- x( k; K( l! [1 v$ p - subtitle += " " + Common::String::format("%02u:%02u:%02u,%03u", hours, mins, secs, msecs);
, u4 [5 [6 M. ^$ q, W - } else {' u# L9 H4 I: X. `1 d% w# B
- return false;/ j' s0 B: l; R
- }
* y2 P, z2 C- S, U - * Y' c: _; Q) R
- int16 width = g_system->getOverlayWidth(),3 b P* t: X. \; s
- height = g_system->getOverlayHeight();. O6 ]+ Q& Q7 `0 }0 B2 J
, o" |% X! R, |- if (width != _lastOverlayWidth ||) K' n: |$ h0 @$ Q# C- q
- height != _lastOverlayHeight) {3 U; j: G: \/ m2 `& Y
- _lastOverlayWidth = width;
6 ^/ z; D& N6 @" k) }7 a - _lastOverlayHeight = height;1 d$ _4 @9 Y/ K( ]
- l4 `5 {; G6 c- g+ n5 c: j' S9 y: k
- // Recalculate the real bounding box to use
' X5 c; G9 P# f& ~ - _realBBox = _requestedBBox;0 ~1 x; G" ^& z
6 A( i' k/ c: t# Y- if (_realBBox.bottom > height) {% Y2 l* l. {4 j+ R% N
- // First try to move the bounding box
5 O1 \1 n6 K/ k/ o! |9 a - _realBBox.top -= _realBBox.bottom - height;+ T/ \$ x0 B G
- _realBBox.bottom = height;
8 }# M# V9 {7 C) t! C0 i5 b - }# [* ], [* W4 z& W, e. z
- if (_realBBox.top < 0) {
, [6 ?( a* l& f* P7 P3 M1 X - // Not enough space
8 g0 s" O2 D1 o K* p, M5 L - _realBBox.top = 0;
) B2 T" b+ P) n# u: v - }
; i& J! X- H4 ~) T - 0 m: c# U, X; b- |
- if (_realBBox.right > width) {, n/ h: _" M7 G, S' _
- // First try to move the bounding box
3 {- e; F0 K! ?; B! `/ a! ? - _realBBox.left -= _realBBox.right - width;
$ s( Q# m _1 _9 p - _realBBox.right = width;# \/ G7 Y$ x& D5 L, G
- }
7 d& D9 z% `. I2 @! I - if (_realBBox.left < 0) {6 Q) G. a6 A3 `3 H% J' d8 U
- // Not enough space' a+ v9 W/ h% K
- _realBBox.left = 0;2 n# X! m: U4 J% l1 d0 M2 `/ j% ?' g
- }
+ n4 Y8 f" E' b7 V" |- ` - 0 o1 y/ k9 m$ X
- force = true;
& H: m6 }( I L6 h v - }
3 Z0 K2 D, a" ?; U1 q9 d) J
r- J. A9 A1 c9 A- if (!force && _overlayHasAlpha && subtitle == _subtitle)1 F8 p8 [/ ?5 }
- return false;: U1 m* d' ]! J5 ?
- 6 N0 E6 b) m0 ~! P( W% v1 i" F+ o
- if (force || subtitle != _subtitle) {
) W. |+ s. t9 G" I' @5 ^ m - debug(1, "%d: %s", timestamp, subtitle.c_str());
* L+ @, B' t4 \( A' { - h$ S, ^3 u, r B" e
- _subtitle = subtitle;
4 x- u6 }- J/ b% g2 e, F. ]" [) r( G - renderSubtitle();1 j, a3 c! ~ T% j
- }0 s# V" s" x+ E! a" r! X) j9 r V
- ( Y( _# S9 c3 B. x/ O$ Z
- if (_overlayHasAlpha) {* y' E# G% B* J5 z
- // When we have alpha, draw the whole surface without thinking it more
- U( c. O- x. k8 D: R4 { - g_system->copyRectToOverlay(_surface->getPixels(), _surface->pitch, _realBBox.left, _realBBox.top, _realBBox.width(), _realBBox.height());
7 N7 F& O" f+ j- ^! E2 {) E' n - } else {1 H4 u# P F3 |
- // When overlay doesn't have alpha, showing it hides the underlying game screen
8 _5 y4 ^& _" M1 f5 @4 d - // We force a copy of the game screen to the overlay by clearing it
+ H# G( q- g- f4 g' O( e - // We then draw the smallest possible surface to minimize black rectangle behind text1 d6 s [; Q. n* h. P( x
- g_system->clearOverlay();
' Y- y$ e5 X6 ], K* p - g_system->copyRectToOverlay((byte *)_surface->getPixels() + _drawRect.top * _surface->pitch + _drawRect.left * _surface->format.bytesPerPixel, _surface->pitch,0 N' H# r) A4 \5 l
- _realBBox.left + _drawRect.left, _realBBox.top + _drawRect.top, _drawRect.width(), _drawRect.height());+ R. e# `4 ?9 @& g& x
- }
8 ?9 C9 k. M/ X' r - ) }5 r4 B$ p- @. |+ V
- return true;9 o& K, J. ~& `- ^! B
- }9 f6 }5 ]9 @; T2 S3 A* L
复制代码 * L- u+ A: g W* x6 h
1 p: p; v8 R T# k A4 ]& j7 i$ w: H* o8 f# O. T! f
% W$ P! s7 E( U5 W* h0 L2 c5 v
1 B" f1 n! I$ b/ N; L1 r
. Z7 M- u* ^8 o1 z/ J; G! k% Y% \6 C% d
|