本帖最后由 shane007 于 2023-8-12 13:57 编辑 . g$ ~: ^, S: w0 H$ f- Y$ E' L1 N, `
/ ]3 |# V- q1 I
这个游戏原本是没有字幕的,但是在Scummvm论坛上发现了一个帖子,) V2 p" D- `& S6 @( r5 Z5 y
讨论的内容是关于在原本没有字幕的游戏上加上字幕。(最初的缘由,是为了帮助一位失聪的朋友)
% L- t. A$ b/ [7 U" m0 ]8 Nhttps://forums.scummvm.org/viewtopic.php?t=7168
* G& S/ g* _- B, o. {8 e/ A5 C[Scummvm-devel] Displaying subtitles in voice-only games (narkive.com)- L; `7 Y' n) \
9 o" ~* R/ v# o8 i7 M7 \8 ]5 s$ ?, Q
前段时间第七访客出了25周年纪念版(The 7th Guest 25th Anniversary Edition。2 O5 a5 @$ O9 |& i W- A9 Y! K
在这个版本中,游戏的视频是有字幕的,因此把这个视频的字幕用到Scummvm中就成为了可能。
% x; j9 t3 ?# K8 J
5 w% p4 e+ P1 X# ]2 A: Z% v我查看了一下最新版本的Scummvm的代码,发现老外已经加入了一部分代码。5 q# o! t1 x7 j. B; V) l' B6 |
在此基础上,汉化是大有希望的。此种汉化方法,也是前所未有的,如果真的实现了将会有重要意义。8 l+ D% { K6 `9 } W' B1 U+ `# x' j
- T& }1 ~: b( b
类似游戏还有- · Groovie9 D1 @- }# R" ~
- - The 7th Guest) N0 p3 l' [4 F3 ^# T
- - The 11th Hour h, B2 y8 `: M9 b f+ |
. H. |- c. K4 |- · MADE- x4 J3 R$ R% s3 k- s& U+ H; f
- - Return to Zork (descriptions are text only, while spoken dialogs lack5 t9 A7 [- I. }9 N; P7 x% [) v
- any text)* V4 ~3 x4 |. c! q! a6 f
- * p5 \$ {$ Q1 ~) V0 G9 B
- · SCI 12 P1 ^' X$ F4 X+ r# A. z
- - King's Quest V (CD Version). In this case, just enabling voice and text; k* N% Z: v, M2 w' \" h. _' F: u6 n
- simultanously would allow a 3rd party to create a set of MSG files
( a% `8 f5 e9 ]5 w0 M) F - containing the voice transcription/translation, as it happened with Gabriel: t& y i0 T1 x8 u2 e- ~+ l6 p
- Knight II." x. o: r: Z* a
- , Z g4 J" K7 z: ~
- ) h* v0 H9 B7 m T* w1 W/ b7 m3 p) U
- Future engines:
" F0 _& ~; @4 N9 x' A9 w2 C, o - : \6 n: f; u2 P6 e; P
- · SCI 217 b1 ~; l9 M8 ] L
- - Gabriel Knight II: The Beast Within (Already a fan patch available in
$ w3 y z2 D# Y# z - order to enable the text display feature)
, O) S' `8 l, l) `! s: Y4 [% Y - - Phantasmagoria1 A, ~4 k' P! i1 t3 i/ U
- - Rama3 j& d% w0 O, ~) I, J0 a# n
- - Shivers
- F' J/ ?0 g) e# l. c @2 U: L4 }: p - - Phantasmagoria II: A Puzzle Of Flesh3 l9 W8 P X/ s, p. N( j
" J8 p* w5 c$ [- · SCI 3
2 Z3 M! v* ]* @2 Z$ Z9 j+ \7 v/ y - - Lighthouse: The Dark Being0 V1 j2 e0 `" t. @$ g( C+ R
- 2 {" ?3 K f8 Q) L: G: j; S
- · M4/MADS
: I6 D9 s% q! L) C) p - - Orion Burger
% ]1 j, V/ \& o5 |% u+ b
# @; U& V. {, L9 E1 |. B7 X* c- · Mohawk
4 b( T( d E/ [% K. j - - Myst
7 G) K/ H+ q/ Y8 u2 n* |# b4 G* F. i - - Riven: The Sequel to Myst
复制代码 : h( }! ^! J/ A- s" L# {: j. ]
) O/ c% d3 h- b# E, v
: | @& V) n3 V3 K' F2 U
! O6 Q! r0 }! O: i
相关代码如下
% h- |- }) g# @ h- bool VideoPlayer::playFrame() {
7 X* O% V1 P f1 S4 m4 X% Z - bool end = true;: c# p, l) b8 B6 X- ^2 ]
- . M. n( I1 W! \. ~& Y
- // Process the next frame while the file is open: C0 @7 a( K: q8 ` q
- if (_file) {
" |0 x& F% V1 J6 a - end = playFrameInternal();# r! r- X" ^6 x
, s E7 q9 B, D- _subtitles.drawSubtitle(_lastFrameTime - _startTime);2 i3 _( X, ^0 i( M+ I: `
- }
复制代码- bool Subtitles::drawSubtitle(uint32 timestamp, bool force) {
1 f( }2 K( q; v1 C$ A/ b" K - Common::String subtitle;) ?& T$ B: S) k/ j- {
- if (_loaded) {: a' R( g" _# @" |2 M! Q; _+ t: h
- subtitle = _srtParser.getSubtitle(timestamp);8 F7 M) u# k$ {
- } else if (_subtitleDev) {0 t+ g: {# e) b& }$ f( B& X
- subtitle = _fname;
8 T7 C U7 e( T" [1 U - uint32 hours, mins, secs, msecs;+ O8 Y. p; Y& d2 p9 g
- secs = timestamp / 1000;- c0 l+ |% w6 U
- hours = secs / 3600;
, e# L6 g% D% k7 k - mins = (secs / 60) % 60;
" ^# Z h k1 m, z- h. P - secs %= 60;1 i* n* p; K5 y/ E3 I u/ B2 w
- msecs = timestamp % 1000;
! K- h- o6 `$ B) ^: l; C' ? e - subtitle += " " + Common::String::format("%02u:%02u:%02u,%03u", hours, mins, secs, msecs);
" x6 n' e( U1 c( X - } else {
+ m1 }! f9 ~) f Y- t: f - return false;
( F' j3 Z. G* W/ Q1 e0 U - }" E# o8 A/ O r- b b0 Z) U
3 {' j5 `$ T8 e6 L7 @- int16 width = g_system->getOverlayWidth(),
5 A. P F9 J$ b - height = g_system->getOverlayHeight();$ F- e7 L3 d1 `4 F2 N/ d' Q1 K2 ?
- / n+ K) s ?9 c7 r, R
- if (width != _lastOverlayWidth ||1 u1 E6 V) D, o% F1 _2 h
- height != _lastOverlayHeight) {
: V! T* m% I0 `9 h$ [1 l - _lastOverlayWidth = width;
2 S8 k4 `0 b. B8 r# l - _lastOverlayHeight = height;) j* o/ j* X% t
- 8 r! C# I8 X N5 N- \
- // Recalculate the real bounding box to use% M5 g3 P& C. z/ @
- _realBBox = _requestedBBox;
7 L; ?2 e4 y- {+ _& Z H0 G1 g - : G1 Y6 @3 n9 `; J- D
- if (_realBBox.bottom > height) {9 d& o! E; l$ R; @% A! M2 J$ j0 b' I
- // First try to move the bounding box) c! f0 \9 E) n8 u* o c
- _realBBox.top -= _realBBox.bottom - height;: N6 t+ a/ ~4 L( v9 u' A; f
- _realBBox.bottom = height;: n% L+ N; ]2 q9 t1 {0 e0 _
- }
; R. B2 I# _( ^! S' n* a& K - if (_realBBox.top < 0) {
! @3 `0 x) ~3 ]3 B" U5 y6 ~ - // Not enough space$ f3 V5 Z% a9 N2 I M% K
- _realBBox.top = 0;6 ~0 W2 c" g) W* A0 v5 G
- }
' E; `; K: D/ M4 C
( c: R8 C0 I, C3 R- if (_realBBox.right > width) {) p; j- ~) w6 S/ `0 x# T, ^
- // First try to move the bounding box& h, C6 N7 J! a' X- I
- _realBBox.left -= _realBBox.right - width;8 S( h' h. S7 \5 n0 W
- _realBBox.right = width;9 O/ G7 i( p$ I0 J( C3 m
- }
, z4 K; ?7 M* C - if (_realBBox.left < 0) {
+ m7 I& P! w } - // Not enough space
% t b4 }4 J. } - _realBBox.left = 0;
3 f; [* U7 u" ^+ m( A0 A* v - }9 a, i$ y1 K, ?/ @, V' t+ b% M+ a
- v1 o% Z- J: J9 K2 q; ~7 y- force = true;* e2 p( d1 {/ L
- }4 f6 j+ g* Z2 [5 p3 ]- V; \2 T
- + h f" _& i/ M. ^
- if (!force && _overlayHasAlpha && subtitle == _subtitle)
2 T o7 s6 C; Y# w# [; ~6 H - return false;1 n1 _) E: w3 v" K
- ! a, ^, a) c0 i* K3 g O
- if (force || subtitle != _subtitle) {7 H X& L7 F0 ^0 ^* ^1 j
- debug(1, "%d: %s", timestamp, subtitle.c_str());
( d" t, v8 P5 J: Y' f, b! t
4 i0 {+ |$ e, j- I- j- _subtitle = subtitle;
. a, m6 q" q/ P3 @# d - renderSubtitle();: J$ H$ K: J R$ S) B; c
- }
# j9 n6 {% m! {, p& G2 j8 E, n- C4 S
1 M0 |% L6 t) e$ C( @- if (_overlayHasAlpha) {
& X. G8 Y- u% @5 k0 b1 A& ~: t - // When we have alpha, draw the whole surface without thinking it more
/ Z9 D& `+ x' ?% V! L/ C: f. Y - g_system->copyRectToOverlay(_surface->getPixels(), _surface->pitch, _realBBox.left, _realBBox.top, _realBBox.width(), _realBBox.height());7 |) G. X4 J5 p6 l( L
- } else {
* P; D$ e& O& _* I# k - // When overlay doesn't have alpha, showing it hides the underlying game screen
6 r5 b6 r) V, b- }, i% Y/ a! l5 R - // We force a copy of the game screen to the overlay by clearing it
8 B+ S7 x4 G) d) o: C8 i - // We then draw the smallest possible surface to minimize black rectangle behind text
+ O6 a Q- ~& S4 T9 j - g_system->clearOverlay();
; {) `$ l; n- h+ f( q - g_system->copyRectToOverlay((byte *)_surface->getPixels() + _drawRect.top * _surface->pitch + _drawRect.left * _surface->format.bytesPerPixel, _surface->pitch,. r! d* S; X/ u3 _: G* u
- _realBBox.left + _drawRect.left, _realBBox.top + _drawRect.top, _drawRect.width(), _drawRect.height());
5 x' `8 i# j7 G, }: L/ _ v% @ - }
0 s3 K: Z; F) D" r" q$ S6 s - ) v8 d. D8 N0 l6 m, h0 U q' v1 z
- return true;
$ _$ ~( F- M9 i$ [9 a - }
9 q- H) m* F+ J* |/ _7 x/ i
复制代码 3 _' J/ q* j s! k6 M8 F! c
^1 ]2 i( a: L" | p0 x& Q
, U" u* q4 e9 K( S: Z6 f5 J
1 A# ?2 k: Q' [* e, Y
) q9 F- V" [0 V ` l$ v1 ~& ~' v' a; b" Y7 o
* \4 m6 K0 `- @& ~9 e0 G8 y
|