1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "common/file.h"
24 #include "common/system.h"
25 #include "common/macresman.h"
26
27 #include "graphics/primitives.h"
28 #include "graphics/macgui/macwindowmanager.h"
29
30 #include "director/director.h"
31 #include "director/cast.h"
32 #include "director/lingo/lingo.h"
33 #include "director/movie.h"
34 #include "director/window.h"
35 #include "director/score.h"
36 #include "director/castmember.h"
37 #include "director/cursor.h"
38 #include "director/channel.h"
39 #include "director/sound.h"
40 #include "director/sprite.h"
41 #include "director/util.h"
42
43 namespace Director {
44
Window(int id,bool scrollable,bool resizable,bool editable,Graphics::MacWindowManager * wm,DirectorEngine * vm,bool isStage)45 Window::Window(int id, bool scrollable, bool resizable, bool editable, Graphics::MacWindowManager *wm, DirectorEngine *vm, bool isStage)
46 : MacWindow(id, scrollable, resizable, editable, wm), Object<Window>("Window") {
47 _vm = vm;
48 _isStage = isStage;
49 _stageColor = _wm->_colorBlack;
50 _puppetTransition = nullptr;
51 _soundManager = new DirectorSound(this);
52
53 _currentMovie = nullptr;
54 _mainArchive = nullptr;
55 _macBinary = nullptr;
56 _nextMovie.frameI = -1;
57 _newMovieStarted = true;
58
59 _objType = kWindowObj;
60 _startFrame = _vm->getStartMovie().startFrame;
61
62 _windowType = -1;
63 _titleVisible = true;
64 updateBorderType();
65
66 _retPC = 0;
67 _retScript = nullptr;
68 _retContext = nullptr;
69 _retFreezeContext = false;
70 _retLocalVars = nullptr;
71 }
72
~Window()73 Window::~Window() {
74 delete _soundManager;
75 delete _currentMovie;
76 if (_macBinary) {
77 delete _macBinary;
78 _macBinary = nullptr;
79 }
80 }
81
invertChannel(Channel * channel,const Common::Rect & destRect)82 void Window::invertChannel(Channel *channel, const Common::Rect &destRect) {
83 const Graphics::Surface *mask;
84
85 // in D3, we have inverted QDshape
86 if (channel->_sprite->isQDShape() && channel->_sprite->_ink == kInkTypeMatte)
87 mask = channel->_sprite->getQDMatte();
88 else
89 mask = channel->getMask(true);
90
91 Common::Rect srcRect = channel->getBbox();
92 srcRect.clip(destRect);
93
94 // let compiler to optimize it
95 int xoff = srcRect.left - channel->getBbox().left;
96 int yoff = srcRect.top - channel->getBbox().top;
97
98 if (_wm->_pixelformat.bytesPerPixel == 1) {
99 for (int i = 0; i < srcRect.height(); i++) {
100 byte *src = (byte *)_composeSurface->getBasePtr(srcRect.left, srcRect.top + i);
101 const byte *msk = mask ? (const byte *)mask->getBasePtr(xoff, yoff + i) : nullptr;
102
103 for (int j = 0; j < srcRect.width(); j++, src++)
104 if (!mask || (msk && !(*msk++)))
105 *src = _wm->inverter(*src);
106 }
107 } else {
108
109 for (int i = 0; i < srcRect.height(); i++) {
110 uint32 *src = (uint32 *)_composeSurface->getBasePtr(srcRect.left, srcRect.top + i);
111 const uint32 *msk = mask ? (const uint32 *)mask->getBasePtr(xoff, yoff + i) : nullptr;
112
113 for (int j = 0; j < srcRect.width(); j++, src++)
114 if (!mask || (msk && !(*msk++)))
115 *src = _wm->inverter(*src);
116 }
117 }
118 }
119
render(bool forceRedraw,Graphics::ManagedSurface * blitTo)120 bool Window::render(bool forceRedraw, Graphics::ManagedSurface *blitTo) {
121 if (!_currentMovie)
122 return false;
123
124 if (forceRedraw) {
125 blitTo->clear(_stageColor);
126 markAllDirty();
127 } else {
128 if (_dirtyRects.size() == 0 && _currentMovie->_videoPlayback == false)
129 return false;
130
131 mergeDirtyRects();
132 }
133
134 if (!blitTo)
135 blitTo = _composeSurface;
136 Channel *hiliteChannel = _currentMovie->getScore()->getChannelById(_currentMovie->_currentHiliteChannelId);
137
138 for (Common::List<Common::Rect>::iterator i = _dirtyRects.begin(); i != _dirtyRects.end(); i++) {
139 const Common::Rect &r = *i;
140 _dirtyChannels = _currentMovie->getScore()->getSpriteIntersections(r);
141
142 bool shouldClear = true;
143 for (Common::List<Channel *>::iterator j = _dirtyChannels.begin(); j != _dirtyChannels.end(); j++) {
144 if ((*j)->_visible && r == (*j)->getBbox() && (*j)->isTrail()) {
145 shouldClear = false;
146 break;
147 }
148 }
149
150 if (shouldClear)
151 blitTo->fillRect(r, _stageColor);
152
153 for (int pass = 0; pass < 2; pass++) {
154 for (Common::List<Channel *>::iterator j = _dirtyChannels.begin(); j != _dirtyChannels.end(); j++) {
155 if ((*j)->isActiveVideo() && (*j)->isVideoDirectToStage()) {
156 if (pass == 0)
157 continue;
158 } else {
159 if (pass == 1)
160 continue;
161 }
162
163 if ((*j)->_visible) {
164 inkBlitFrom(*j, r, blitTo);
165 if ((*j) == hiliteChannel)
166 invertChannel(hiliteChannel, r);
167 }
168 }
169 }
170 }
171
172 _dirtyRects.clear();
173 _contentIsDirty = true;
174
175 return true;
176 }
177
setStageColor(uint32 stageColor,bool forceReset)178 void Window::setStageColor(uint32 stageColor, bool forceReset) {
179 if (stageColor != _stageColor || forceReset) {
180 _stageColor = stageColor;
181 reset();
182 markAllDirty();
183 }
184 }
185
reset()186 void Window::reset() {
187 resize(_composeSurface->w, _composeSurface->h, true);
188 _composeSurface->clear(_stageColor);
189 _contentIsDirty = true;
190 }
191
inkBlitFrom(Channel * channel,Common::Rect destRect,Graphics::ManagedSurface * blitTo)192 void Window::inkBlitFrom(Channel *channel, Common::Rect destRect, Graphics::ManagedSurface *blitTo) {
193 Common::Rect srcRect = channel->getBbox();
194 destRect.clip(srcRect);
195
196 DirectorPlotData pd = channel->getPlotData();
197 pd.destRect = destRect;
198 pd.dst = blitTo;
199
200 if (pd.ms) {
201 inkBlitShape(&pd, srcRect);
202 } else if (pd.srf) {
203 if (channel->isStretched()) {
204 srcRect = channel->getBbox(true);
205 inkBlitStretchSurface(&pd, srcRect, channel->getMask());
206 } else {
207 inkBlitSurface(&pd, srcRect, channel->getMask());
208 }
209 } else {
210 if (debugChannelSet(kDebugImages, 2))
211 warning("Window::inkBlitFrom: No source surface: spriteType: %d, castType: %d, castId: %s", channel->_sprite->_spriteType, channel->_sprite->_cast ? channel->_sprite->_cast->_type : 0, channel->_sprite->_castId.asString().c_str());
212 }
213 }
214
inkBlitShape(DirectorPlotData * pd,Common::Rect & srcRect)215 void Window::inkBlitShape(DirectorPlotData *pd, Common::Rect &srcRect) {
216 if (!pd->ms)
217 return;
218
219 // Preprocess shape colours
220 switch (pd->ink) {
221 case kInkTypeNotTrans:
222 case kInkTypeNotReverse:
223 case kInkTypeNotGhost:
224 return;
225 case kInkTypeReverse:
226 pd->ms->foreColor = 0;
227 pd->ms->backColor = 0;
228 break;
229 default:
230 break;
231 }
232
233 Common::Rect fillAreaRect((int)srcRect.width(), (int)srcRect.height());
234 fillAreaRect.moveTo(srcRect.left, srcRect.top);
235 Graphics::MacPlotData plotFill(pd->dst, nullptr, &g_director->getPatterns(), pd->ms->pattern, srcRect.left, srcRect.top, 1, pd->ms->backColor);
236
237 Common::Rect strokeRect(MAX((int)srcRect.width() - pd->ms->lineSize, 0), MAX((int)srcRect.height() - pd->ms->lineSize, 0));
238 strokeRect.moveTo(srcRect.left, srcRect.top);
239 Graphics::MacPlotData plotStroke(pd->dst, nullptr, &g_director->getPatterns(), 1, strokeRect.left, strokeRect.top, pd->ms->lineSize, pd->ms->backColor);
240
241 switch (pd->ms->spriteType) {
242 case kRectangleSprite:
243 pd->ms->pd = &plotFill;
244 Graphics::drawFilledRect(fillAreaRect, pd->ms->foreColor, g_director->getInkDrawPixel(), pd);
245 // fall through
246 case kOutlinedRectangleSprite:
247 // if we have lineSize <= 0, means we are not drawing anything. so we may return directly.
248 if (pd->ms->lineSize <= 0)
249 break;
250 pd->ms->pd = &plotStroke;
251 Graphics::drawRect(strokeRect, pd->ms->foreColor, g_director->getInkDrawPixel(), pd);
252 break;
253 case kRoundedRectangleSprite:
254 pd->ms->pd = &plotFill;
255 Graphics::drawRoundRect(fillAreaRect, 12, pd->ms->foreColor, true, g_director->getInkDrawPixel(), pd);
256 // fall through
257 case kOutlinedRoundedRectangleSprite:
258 if (pd->ms->lineSize <= 0)
259 break;
260 pd->ms->pd = &plotStroke;
261 Graphics::drawRoundRect(strokeRect, 12, pd->ms->foreColor, false, g_director->getInkDrawPixel(), pd);
262 break;
263 case kOvalSprite:
264 pd->ms->pd = &plotFill;
265 Graphics::drawEllipse(fillAreaRect.left, fillAreaRect.top, fillAreaRect.right, fillAreaRect.bottom, pd->ms->foreColor, true, g_director->getInkDrawPixel(), pd);
266 // fall through
267 case kOutlinedOvalSprite:
268 if (pd->ms->lineSize <= 0)
269 break;
270 pd->ms->pd = &plotStroke;
271 Graphics::drawEllipse(strokeRect.left, strokeRect.top, strokeRect.right, strokeRect.bottom, pd->ms->foreColor, false, g_director->getInkDrawPixel(), pd);
272 break;
273 case kLineTopBottomSprite:
274 pd->ms->pd = &plotStroke;
275 Graphics::drawLine(strokeRect.left, strokeRect.top, strokeRect.right, strokeRect.bottom, pd->ms->foreColor, g_director->getInkDrawPixel(), pd);
276 break;
277 case kLineBottomTopSprite:
278 pd->ms->pd = &plotStroke;
279 Graphics::drawLine(strokeRect.left, strokeRect.bottom, strokeRect.right, strokeRect.top, pd->ms->foreColor, g_director->getInkDrawPixel(), pd);
280 break;
281 default:
282 warning("Window::inkBlitFrom: Expected shape type but got type %d", pd->ms->spriteType);
283 }
284 }
285
inkBlitSurface(DirectorPlotData * pd,Common::Rect & srcRect,const Graphics::Surface * mask)286 void Window::inkBlitSurface(DirectorPlotData *pd, Common::Rect &srcRect, const Graphics::Surface *mask) {
287 if (!pd->srf)
288 return;
289
290 // TODO: Determine why colourization causes problems in Warlock
291 if (pd->sprite == kTextSprite)
292 pd->applyColor = false;
293
294 pd->srcPoint.y = abs(srcRect.top - pd->destRect.top);
295 for (int i = 0; i < pd->destRect.height(); i++, pd->srcPoint.y++) {
296 if (_wm->_pixelformat.bytesPerPixel == 1) {
297 pd->srcPoint.x = abs(srcRect.left - pd->destRect.left);
298 const byte *msk = mask ? (const byte *)mask->getBasePtr(pd->srcPoint.x, pd->srcPoint.y) : nullptr;
299
300 for (int j = 0; j < pd->destRect.width(); j++, pd->srcPoint.x++) {
301 if (!mask || (msk && !(*msk++))) {
302 (g_director->getInkDrawPixel())(pd->destRect.left + j, pd->destRect.top + i,
303 preprocessColor(pd, *((byte *)pd->srf->getBasePtr(pd->srcPoint.x, pd->srcPoint.y))), pd);
304 }
305 }
306 } else {
307 pd->srcPoint.x = abs(srcRect.left - pd->destRect.left);
308 const uint32 *msk = mask ? (const uint32 *)mask->getBasePtr(pd->srcPoint.x, pd->srcPoint.y) : nullptr;
309
310 for (int j = 0; j < pd->destRect.width(); j++, pd->srcPoint.x++) {
311 if (!mask || (msk && !(*msk++))) {
312 (g_director->getInkDrawPixel())(pd->destRect.left + j, pd->destRect.top + i,
313 preprocessColor(pd, *((int *)pd->srf->getBasePtr(pd->srcPoint.x, pd->srcPoint.y))), pd);
314 }
315 }
316 }
317 }
318 }
319
inkBlitStretchSurface(DirectorPlotData * pd,Common::Rect & srcRect,const Graphics::Surface * mask)320 void Window::inkBlitStretchSurface(DirectorPlotData *pd, Common::Rect &srcRect, const Graphics::Surface *mask) {
321 if (!pd->srf)
322 return;
323
324 // TODO: Determine why colourization causes problems in Warlock
325 if (pd->sprite == kTextSprite)
326 pd->applyColor = false;
327
328 int scaleX = SCALE_THRESHOLD * srcRect.width() / pd->destRect.width();
329 int scaleY = SCALE_THRESHOLD * srcRect.height() / pd->destRect.height();
330
331 pd->srcPoint.y = abs(srcRect.top - pd->destRect.top);
332
333 for (int i = 0, scaleYCtr = 0; i < pd->destRect.height(); i++, scaleYCtr += scaleY, pd->srcPoint.y++) {
334 if (_wm->_pixelformat.bytesPerPixel == 1) {
335 pd->srcPoint.x = abs(srcRect.left - pd->destRect.left);
336 const byte *msk = mask ? (const byte *)mask->getBasePtr(pd->srcPoint.x, pd->srcPoint.y) : nullptr;
337
338 for (int xCtr = 0, scaleXCtr = 0; xCtr < pd->destRect.width(); xCtr++, scaleXCtr += scaleX, pd->srcPoint.x++) {
339 if (!mask || !(*msk++)) {
340 (g_director->getInkDrawPixel())(pd->destRect.left + xCtr, pd->destRect.top + i,
341 preprocessColor(pd, *((byte *)pd->srf->getBasePtr(scaleXCtr / SCALE_THRESHOLD, scaleYCtr / SCALE_THRESHOLD))), pd);
342 }
343 }
344 } else {
345 pd->srcPoint.x = abs(srcRect.left - pd->destRect.left);
346 const uint32 *msk = mask ? (const uint32 *)mask->getBasePtr(pd->srcPoint.x, pd->srcPoint.y) : nullptr;
347
348 for (int xCtr = 0, scaleXCtr = 0; xCtr < pd->destRect.width(); xCtr++, scaleXCtr += scaleX, pd->srcPoint.x++) {
349 if (!mask || !(*msk++)) {
350 (g_director->getInkDrawPixel())(pd->destRect.left + xCtr, pd->destRect.top + i,
351 preprocessColor(pd, *((int *)pd->srf->getBasePtr(scaleXCtr / SCALE_THRESHOLD, scaleYCtr / SCALE_THRESHOLD))), pd);
352 }
353 }
354 }
355 }
356 }
357
preprocessColor(DirectorPlotData * p,uint32 src)358 int Window::preprocessColor(DirectorPlotData *p, uint32 src) {
359 // HACK: Right now this method is just used for adjusting the colourization on text
360 // sprites, as it would be costly to colourize the chunks on the fly each
361 // time a section needs drawing. It's ugly but mostly works.
362 if (p->sprite == kTextSprite) {
363 switch(p->ink) {
364 case kInkTypeMask:
365 src = (src == p->backColor ? p->foreColor : 0xff);
366 break;
367 case kInkTypeReverse:
368 src = (src == p->foreColor ? 0 : p->colorWhite);
369 break;
370 case kInkTypeNotReverse:
371 src = (src == p->backColor ? p->colorWhite : 0);
372 break;
373 // looks like this part is wrong, maybe it's very same as reverse?
374 // check warlock/DATA/WARLOCKSHIP/ENG/ABOUT to see more detail.
375 // case kInkTypeGhost:
376 // src = (src == p->foreColor ? p->backColor : p->colorWhite);
377 // break;
378 case kInkTypeNotGhost:
379 src = (src == p->backColor ? p->colorWhite : p->backColor);
380 break;
381 case kInkTypeNotCopy:
382 src = (src == p->foreColor ? p->backColor : p->foreColor);
383 break;
384 case kInkTypeNotTrans:
385 src = (src == p->foreColor ? p->backColor : p->colorWhite);
386 break;
387 default:
388 break;
389 }
390 }
391
392 return src;
393 }
394
getMousePos()395 Common::Point Window::getMousePos() {
396 return g_system->getEventManager()->getMousePos() - Common::Point(_innerDims.left, _innerDims.top);
397 }
398
setVisible(bool visible,bool silent)399 void Window::setVisible(bool visible, bool silent) {
400 // setting visible triggers movie load
401 if (!_currentMovie && !silent) {
402 Common::String movieName = getName();
403 setNextMovie(movieName);
404 }
405
406 BaseMacWindow::setVisible(visible);
407
408 if (visible)
409 _wm->setActiveWindow(_id);
410 }
411
setNextMovie(Common::String & movieFilenameRaw)412 bool Window::setNextMovie(Common::String &movieFilenameRaw) {
413 Common::String movieFilename = pathMakeRelative(movieFilenameRaw);
414
415 bool fileExists = false;
416 Common::File file;
417 if (file.open(Common::Path(movieFilename, _vm->_dirSeparator))) {
418 fileExists = true;
419 file.close();
420 }
421
422 debug(1, "Window::setNextMovie: '%s' -> '%s' -> '%s'", movieFilenameRaw.c_str(), convertPath(movieFilenameRaw).c_str(), movieFilename.c_str());
423
424 if (!fileExists) {
425 warning("Movie %s does not exist", movieFilename.c_str());
426 return false;
427 }
428
429 _nextMovie.movie = movieFilename;
430 return true;
431 }
432
updateBorderType()433 void Window::updateBorderType() {
434 if (_isStage) {
435 setBorderType(3);
436 } else if (!_titleVisible) {
437 setBorderType(2);
438 } else {
439 setBorderType(MAX(0, MIN(_windowType, 16)));
440 }
441 }
442
step()443 bool Window::step() {
444 // finish last movie
445 if (_currentMovie && _currentMovie->getScore()->_playState == kPlayStopped) {
446 debugC(3, kDebugEvents, "\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
447 debugC(3, kDebugEvents, "@@@@ Finishing movie '%s' in '%s'", utf8ToPrintable(_currentMovie->getMacName()).c_str(), _currentPath.c_str());
448 debugC(3, kDebugEvents, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
449
450 _currentMovie->getScore()->stopPlay();
451 debugC(1, kDebugEvents, "Finished playback of movie '%s'", utf8ToPrintable(_currentMovie->getMacName()).c_str());
452
453 if (_vm->getGameGID() == GID_TESTALL) {
454 _nextMovie = getNextMovieFromQueue();
455 }
456 }
457
458 // prepare next movie
459 if (!_nextMovie.movie.empty()) {
460 _soundManager->changingMovie();
461
462 _newMovieStarted = true;
463
464 _currentPath = getPath(_nextMovie.movie, _currentPath);
465
466 Cast *sharedCast = nullptr;
467 if (_currentMovie) {
468 sharedCast = _currentMovie->getSharedCast();
469 _currentMovie->_sharedCast = nullptr;
470 }
471
472 delete _currentMovie;
473 _currentMovie = nullptr;
474
475 Archive *mov = openMainArchive(_currentPath + Common::lastPathComponent(_nextMovie.movie, g_director->_dirSeparator));
476
477 if (!mov) {
478 warning("nextMovie: No movie is loaded");
479
480 if (_vm->getGameGID() == GID_TESTALL) {
481 return true;
482 }
483
484 return false;
485 }
486
487 _currentMovie = new Movie(this);
488 _currentMovie->setArchive(mov);
489
490 debug(0, "\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
491 debug(0, "@@@@ Switching to movie '%s' in '%s'", utf8ToPrintable(_currentMovie->getMacName()).c_str(), _currentPath.c_str());
492 debug(0, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
493
494 g_lingo->resetLingo();
495 Common::String sharedCastPath = getSharedCastPath();
496 if (!sharedCastPath.empty()) {
497 if (sharedCast && sharedCast->_castArchive
498 && sharedCast->_castArchive->getPathName().equalsIgnoreCase(sharedCastPath)) {
499 // if we are not deleting shared cast, then we need to clear those previous widget pointer
500 sharedCast->releaseCastMemberWidget();
501 _currentMovie->_sharedCast = sharedCast;
502 } else {
503 delete sharedCast;
504 _currentMovie->loadSharedCastsFrom(sharedCastPath);
505 }
506 } else {
507 delete sharedCast;
508 }
509
510 _nextMovie.movie.clear();
511 }
512
513 // play current movie
514 if (_currentMovie) {
515 switch (_currentMovie->getScore()->_playState) {
516 case kPlayNotStarted:
517 {
518 debug(0, "\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
519 debug(0, "@@@@ Loading movie '%s' in '%s'", utf8ToPrintable(_currentMovie->getMacName()).c_str(), _currentPath.c_str());
520 debug(0, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
521
522 bool goodMovie = _currentMovie->loadArchive();
523
524 // If we came in a loop, then skip as requested
525 if (!_nextMovie.frameS.empty()) {
526 _currentMovie->getScore()->setStartToLabel(_nextMovie.frameS);
527 _nextMovie.frameS.clear();
528 }
529
530 if (_nextMovie.frameI != -1) {
531 _currentMovie->getScore()->setCurrentFrame(_nextMovie.frameI);
532 _nextMovie.frameI = -1;
533 }
534
535 if (!debugChannelSet(-1, kDebugCompileOnly) && goodMovie) {
536 debugC(1, kDebugEvents, "Starting playback of movie '%s'", _currentMovie->getMacName().c_str());
537 _currentMovie->getScore()->startPlay();
538 if (_startFrame != -1) {
539 _currentMovie->getScore()->setCurrentFrame(_startFrame);
540 _startFrame = -1;
541 }
542 } else {
543 return false;
544 }
545 }
546 // fall through
547 case kPlayStarted:
548 debugC(3, kDebugEvents, "\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
549 debugC(3, kDebugEvents, "@@@@ Stepping movie '%s' in '%s'", utf8ToPrintable(_currentMovie->getMacName()).c_str(), _currentPath.c_str());
550 debugC(3, kDebugEvents, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
551 _currentMovie->getScore()->step();
552 return true;
553 default:
554 return false;
555 }
556 }
557
558 return false;
559 }
560
getSharedCastPath()561 Common::String Window::getSharedCastPath() {
562 Common::Array<Common::String> namesToTry;
563 if (_vm->getVersion() < 400) {
564 if (g_director->getPlatform() == Common::kPlatformWindows) {
565 namesToTry.push_back("SHARDCST.MMM");
566 } else {
567 namesToTry.push_back("Shared Cast");
568 }
569 } else if (_vm->getVersion() < 500) {
570 namesToTry.push_back("Shared.dir");
571 namesToTry.push_back("Shared.dxr");
572 } else {
573 // TODO: Does D5 actually support D4-style shared cast?
574 namesToTry.push_back("Shared.cst");
575 namesToTry.push_back("Shared.cxt");
576 }
577
578 for (uint i = 0; i < namesToTry.size(); i++) {
579 Common::File f;
580 if (f.open(Common::Path(_currentPath + namesToTry[i], _vm->_dirSeparator))) {
581 f.close();
582 return _currentPath + namesToTry[i];
583 }
584 }
585
586 return Common::String();
587 }
588
589 } // End of namespace Director
590