本帖最后由 shane007 于 2023-8-12 13:57 编辑
- q7 T2 z. y# z
: j( F3 \" y) ]" m这个游戏原本是没有字幕的,但是在Scummvm论坛上发现了一个帖子,
5 A' {# A1 w' z% Z讨论的内容是关于在原本没有字幕的游戏上加上字幕。(最初的缘由,是为了帮助一位失聪的朋友)/ t" b/ S4 M m+ W( Y- O' ^
https://forums.scummvm.org/viewtopic.php?t=7168
7 q/ j1 G) z9 \$ T[Scummvm-devel] Displaying subtitles in voice-only games (narkive.com)
4 j+ l" \5 l2 _6 R/ I. H! I- e( t% C! q9 v5 z( r8 ~9 F7 |
前段时间第七访客出了25周年纪念版(The 7th Guest 25th Anniversary Edition。
2 l# U9 Y" s1 O3 @2 c* q' E在这个版本中,游戏的视频是有字幕的,因此把这个视频的字幕用到Scummvm中就成为了可能。
3 w. l+ F. r: @2 A4 B5 O" A9 ^( z# n
8 e* m, O5 K7 Q+ o. z5 q/ v7 d我查看了一下最新版本的Scummvm的代码,发现老外已经加入了一部分代码。' @0 v' S! [: P3 b" V8 A1 o# H$ \
在此基础上,汉化是大有希望的。此种汉化方法,也是前所未有的,如果真的实现了将会有重要意义。4 d) m9 A T: ]( j3 U K
8 ^0 y$ F" q0 @& y3 `# F* D
类似游戏还有- · Groovie b8 X- h2 | g- J
- - The 7th Guest, ]: i+ f }) e
- - The 11th Hour* W, ^3 }8 u( P) M2 o0 B: _8 O
- f1 f/ e( c0 A6 n) w/ p- · MADE: C& y4 f7 I. P$ @
- - Return to Zork (descriptions are text only, while spoken dialogs lack
' o+ U, {/ X) }: h - any text)
P2 U! N% d! l
' _3 b) N5 A- w/ F K6 ^- · SCI 1
5 _* O4 f( D. o. C0 c - - King's Quest V (CD Version). In this case, just enabling voice and text
( Q! {) t( V1 o/ _ - simultanously would allow a 3rd party to create a set of MSG files: O! Q9 d" a z) _) R( j5 K
- containing the voice transcription/translation, as it happened with Gabriel
% B' h3 G# v) C! Z5 {4 b; u - Knight II.
0 R% ?. \2 K) U! p% R3 y# ]* s
; c* r3 }* j5 b9 J! P
& t6 Z9 R/ A- c+ ]- Future engines:
5 a6 g# Q2 u [+ _
9 K% q& }' o4 x3 c- · SCI 21" _! z% o2 W' s( n& @: ~0 y
- - Gabriel Knight II: The Beast Within (Already a fan patch available in* N K5 \2 `, z. I0 Z/ D
- order to enable the text display feature)" [9 d% [+ w/ L: t! t
- - Phantasmagoria
: s: N- n7 s+ G# _9 R& c9 R - - Rama# G" ^3 l: q/ @ L& k' }+ v
- - Shivers* m+ I' E5 A' f \
- - Phantasmagoria II: A Puzzle Of Flesh% r |; Z2 i5 o+ G0 q0 s
- 3 E5 M) `0 s9 n
- · SCI 3
. T6 O4 ^- b ~0 J U; u1 K - - Lighthouse: The Dark Being
' ~4 x+ Q6 q* o1 N - - [5 M* K( _9 w# w: Y& \0 d
- · M4/MADS
5 H) ?% X! v# c - - Orion Burger( Q) c) d" r0 [
- ; [" j( n# f8 a9 g& ~0 K
- · Mohawk& }) s6 C0 P3 s }
- - Myst: j, Y. w* m, u
- - Riven: The Sequel to Myst
复制代码 1 `8 _$ P, ?! H1 {" C, w8 `- N( ~
! W% [6 a0 {* o9 F& {( Y* C7 s$ n% ?" v' A5 C9 w
, H0 e6 z) {4 D0 @) o+ ]
相关代码如下9 i# m/ }2 O% t0 H7 r
- bool VideoPlayer::playFrame() {
/ K y6 a+ v# ~& k/ f - bool end = true;' v2 O0 t7 F6 ]+ ?, z
( F% _. t$ s n0 V8 I. t- // Process the next frame while the file is open
2 K# H* M6 l( W. ?- K/ Q V6 c& V - if (_file) {+ c7 X; @( M$ g: ?& E
- end = playFrameInternal();
" }" ?0 T3 A2 D: f: W/ A( T
2 S) P/ G5 Z+ |; r, {- _subtitles.drawSubtitle(_lastFrameTime - _startTime);: M, G% Q4 B! k/ q: v. J' x' q
- }
复制代码- bool Subtitles::drawSubtitle(uint32 timestamp, bool force) {
% f& Y" y9 A y [) M - Common::String subtitle;; M8 }) X, P$ S
- if (_loaded) {
* m: G! H9 ?. A/ h: X# ] - subtitle = _srtParser.getSubtitle(timestamp);2 b$ C. P+ C% O
- } else if (_subtitleDev) {
4 B3 F8 O: o8 T" s6 o0 ? - subtitle = _fname;4 g5 E: W" Q3 h1 C! f( y$ ?! L+ M
- uint32 hours, mins, secs, msecs;
7 i3 N& b1 M) s: z+ I - secs = timestamp / 1000;
3 O8 C5 n) Y& l - hours = secs / 3600;
" c( y; x, S5 [1 T( k2 e - mins = (secs / 60) % 60;) S" r5 {8 ?7 |5 K
- secs %= 60;9 e: y2 [2 W$ q! a, c) M4 t& m
- msecs = timestamp % 1000;
+ `' z+ e0 A# v - subtitle += " " + Common::String::format("%02u:%02u:%02u,%03u", hours, mins, secs, msecs);8 {$ y2 f4 F3 A
- } else {
& f/ _' t8 p% l4 Y% Q4 `: l1 [ - return false;
! u9 J* y# \8 F6 ?1 ]6 W; A - }
) Q: o$ J! @. H; y% U, S& W
. t1 e/ Z% b4 p0 M- Z7 ^- int16 width = g_system->getOverlayWidth(),
2 F! A9 v( `# s" {, J% V - height = g_system->getOverlayHeight();( b& D* c! I* Q4 N3 f
2 X7 d* c; |/ v, _* G, Z: p- if (width != _lastOverlayWidth ||: P2 l' B2 {% b- ~8 E
- height != _lastOverlayHeight) {' i% B0 o# I7 Z
- _lastOverlayWidth = width;
- ^9 n" b/ D h/ S) x8 d - _lastOverlayHeight = height;2 J5 X% R2 ~2 K, ^/ M
' c$ _: B2 U( o3 u0 [- // Recalculate the real bounding box to use
: y2 T$ T9 T5 Z5 b" } - _realBBox = _requestedBBox;* f& U9 j# G3 j; [5 j0 A1 A {
- # T y8 A8 v. i3 n
- if (_realBBox.bottom > height) {1 o: z% }. v3 X; w
- // First try to move the bounding box: f( o7 j z% }2 F' S( u
- _realBBox.top -= _realBBox.bottom - height;
$ f! T8 Z. f) X7 D3 l) B6 c) [. r - _realBBox.bottom = height;
6 ^- L5 C( ]- \. [' y: n - }
. w" l& U! W, W9 n0 k; Q! i - if (_realBBox.top < 0) {
! ]0 a1 h3 @* X: q2 j' h - // Not enough space
& r" x" B2 Q Z4 B; N$ C - _realBBox.top = 0;9 H6 u7 g0 \& C. ]! o8 d& |
- }
K% Q6 M( Q! T- Y* P - ) `1 e: F- b+ W% N! I
- if (_realBBox.right > width) {
# X2 P, x# J- H: i! }( } - // First try to move the bounding box$ T& i" ^+ T0 N" \
- _realBBox.left -= _realBBox.right - width;
! c3 i9 h5 Z+ t; B* N& p - _realBBox.right = width;, K3 H5 f* V+ s M! R
- }
/ g) y, }1 ^3 ~$ e - if (_realBBox.left < 0) {
2 C# ~& z4 L: h7 m3 J5 K/ l - // Not enough space
3 m; D. _* G( [% l: ~3 z - _realBBox.left = 0;
1 |) _% a/ y% q - }3 ^7 _# |9 N% _- K c& b
- % I* O' Z9 W0 M8 C$ U
- force = true;! }; Q, ^5 I0 d) }1 r0 f4 a' O
- }/ c4 M' i7 ^" z! a! L4 w2 t
- : f( Z; H( d! r$ F+ W
- if (!force && _overlayHasAlpha && subtitle == _subtitle)! x, o2 U. d# ], d8 P. D0 N
- return false;
+ F% Z! C5 J7 }. C/ k/ f - 4 o7 A( z' b9 j$ b
- if (force || subtitle != _subtitle) {; W, @' _8 D/ P% v5 y
- debug(1, "%d: %s", timestamp, subtitle.c_str());
( t3 g8 K+ x' L1 d& f" @* n - , P, w0 }' D4 p* t7 U i& `
- _subtitle = subtitle;
# ~$ F; Z1 K$ v: S5 t - renderSubtitle();9 \; m- O. X z. t9 t2 t
- }
, ?- B1 L1 x! o7 G' [' K) y - ' [3 B2 W- }2 u! h: ?, \ w5 Q, {; x
- if (_overlayHasAlpha) {) u7 `8 Z$ ]$ E+ k, C
- // When we have alpha, draw the whole surface without thinking it more* b: E2 M$ X+ c% P% Y, j, ?+ _- u
- g_system->copyRectToOverlay(_surface->getPixels(), _surface->pitch, _realBBox.left, _realBBox.top, _realBBox.width(), _realBBox.height());( D, h$ ]& G) n
- } else {9 S9 H# A; L7 I2 ?
- // When overlay doesn't have alpha, showing it hides the underlying game screen
! V# A: e! c; \/ H - // We force a copy of the game screen to the overlay by clearing it
. s, a u% W5 a) y! Y - // We then draw the smallest possible surface to minimize black rectangle behind text
! ]! g% r; H) C- ^ - g_system->clearOverlay();: l0 X; c: G) T; S2 t% w
- g_system->copyRectToOverlay((byte *)_surface->getPixels() + _drawRect.top * _surface->pitch + _drawRect.left * _surface->format.bytesPerPixel, _surface->pitch,
+ o; {4 V0 I/ j+ ~9 c - _realBBox.left + _drawRect.left, _realBBox.top + _drawRect.top, _drawRect.width(), _drawRect.height());
( Z0 c6 d7 [, j% n+ c9 i$ ~ - }, Q, P" v. L. `4 g0 H
- 9 ?$ F' G( m! f9 i( p, D
- return true;
0 G* Y6 K0 W G - }
; E& U/ W& @1 s0 H
复制代码 7 x. g: s" Y. S! T
; Y* p- _) t. W" |: I9 U! _ w) k" p# j' K
" D# @% S- [. t' r0 a1 n& m: v5 D7 O) Y0 O% {4 o4 e% @5 o' ]
( a4 P5 b5 j K1 d1 z, z" Y
9 B! r' R6 A$ n& h9 q
|