2012-11-13 20:23:11 -05:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
|
|
|
*
|
|
|
|
* ScummVM is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
2021-12-26 18:47:58 +01:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
2016-09-03 12:46:38 +02:00
|
|
|
*
|
2012-11-13 20:23:11 -05:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2016-09-03 12:46:38 +02:00
|
|
|
*
|
2012-11-13 20:23:11 -05:00
|
|
|
* You should have received a copy of the GNU General Public License
|
2021-12-26 18:47:58 +01:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2012-11-13 20:23:11 -05:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2013-10-26 16:37:00 -04:00
|
|
|
#include "common/config-manager.h"
|
2016-08-15 19:34:21 +02:00
|
|
|
#include "common/debug-channels.h"
|
2012-11-13 20:23:11 -05:00
|
|
|
#include "common/error.h"
|
2021-08-07 00:01:06 +02:00
|
|
|
#include "common/punycode.h"
|
|
|
|
#include "common/tokenizer.h"
|
2017-01-17 10:21:54 +01:00
|
|
|
|
2016-08-03 18:17:34 +02:00
|
|
|
#include "graphics/macgui/macwindowmanager.h"
|
2021-08-17 08:55:39 +08:00
|
|
|
#include "graphics/wincursor.h"
|
2012-11-13 20:23:11 -05:00
|
|
|
|
2016-06-07 00:05:48 +02:00
|
|
|
#include "director/director.h"
|
2016-10-26 10:08:17 +02:00
|
|
|
#include "director/archive.h"
|
2020-06-30 19:32:14 -04:00
|
|
|
#include "director/cast.h"
|
|
|
|
#include "director/movie.h"
|
2019-12-24 00:02:44 +01:00
|
|
|
#include "director/score.h"
|
2016-06-09 22:12:55 +03:00
|
|
|
#include "director/sound.h"
|
2020-08-04 23:26:50 -04:00
|
|
|
#include "director/window.h"
|
2020-07-01 17:40:52 +02:00
|
|
|
#include "director/lingo/lingo.h"
|
2021-06-12 17:40:01 +02:00
|
|
|
#include "director/detection.h"
|
2021-06-10 12:33:26 +01:00
|
|
|
|
2021-06-12 17:40:01 +02:00
|
|
|
/**
|
|
|
|
* When detection is compiled dynamically, directory globs end up in detection plugin and
|
|
|
|
* engine cannot link to them so duplicate them in the engine in this case
|
|
|
|
*/
|
|
|
|
#ifndef DETECTION_STATIC
|
2021-06-10 12:33:26 +01:00
|
|
|
#include "director/detection_paths.h"
|
2021-06-12 17:40:01 +02:00
|
|
|
#endif
|
2016-05-24 22:03:21 +03:00
|
|
|
|
2012-11-13 20:23:11 -05:00
|
|
|
namespace Director {
|
|
|
|
|
2020-07-03 11:02:10 -04:00
|
|
|
const uint32 wmModeDesktop = Graphics::kWMModalMenuMode | Graphics::kWMModeManualDrawWidgets;
|
|
|
|
const uint32 wmModeFullscreen = Graphics::kWMModalMenuMode | Graphics::kWMModeNoDesktop
|
2020-06-05 16:35:39 -04:00
|
|
|
| Graphics::kWMModeManualDrawWidgets | Graphics::kWMModeFullscreen;
|
2020-07-03 11:02:10 -04:00
|
|
|
uint32 wmMode = 0;
|
2020-06-05 16:35:39 -04:00
|
|
|
|
2017-01-08 09:32:32 +01:00
|
|
|
DirectorEngine *g_director;
|
|
|
|
|
2020-07-11 23:21:16 +02:00
|
|
|
DirectorEngine::DirectorEngine(OSystem *syst, const DirectorGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {
|
2017-01-08 09:32:32 +01:00
|
|
|
g_director = this;
|
|
|
|
|
2021-08-07 00:16:03 -04:00
|
|
|
_dirSeparator = ':';
|
|
|
|
|
2021-08-07 00:01:06 +02:00
|
|
|
parseOptions();
|
|
|
|
|
2012-11-13 20:23:11 -05:00
|
|
|
// Setup mixer
|
|
|
|
syncSoundSettings();
|
2016-08-03 17:44:10 +02:00
|
|
|
|
2020-01-11 23:30:40 +08:00
|
|
|
// Load Palettes
|
2020-07-26 21:26:28 -04:00
|
|
|
loadDefaultPalettes();
|
2020-01-11 23:30:40 +08:00
|
|
|
|
2017-01-13 12:17:36 +11:00
|
|
|
// Load Patterns
|
|
|
|
loadPatterns();
|
|
|
|
|
2020-06-16 22:43:12 -04:00
|
|
|
// Load key codes
|
|
|
|
loadKeyCodes();
|
|
|
|
|
2016-08-26 12:33:48 +02:00
|
|
|
_currentPalette = nullptr;
|
|
|
|
_currentPaletteLength = 0;
|
2020-08-04 23:26:50 -04:00
|
|
|
_stage = nullptr;
|
2020-07-08 14:06:37 -04:00
|
|
|
_windowList = new Datum;
|
|
|
|
_windowList->type = ARRAY;
|
2021-07-27 22:55:53 +08:00
|
|
|
_windowList->u.farr = new FArray;
|
2020-08-04 23:26:50 -04:00
|
|
|
_currentWindow = nullptr;
|
2021-08-06 01:00:53 -04:00
|
|
|
_cursorWindow = nullptr;
|
2016-08-26 12:33:48 +02:00
|
|
|
_lingo = nullptr;
|
2020-08-02 21:17:36 +02:00
|
|
|
_version = getDescriptionVersion();
|
2016-08-26 12:33:48 +02:00
|
|
|
|
2016-08-03 18:17:34 +02:00
|
|
|
_wm = nullptr;
|
|
|
|
|
2020-08-05 11:00:42 -04:00
|
|
|
_gameDataDir = Common::FSNode(ConfMan.get("path"));
|
2020-05-24 00:21:56 +02:00
|
|
|
|
|
|
|
// Meet Mediaband could have up to 5 levels of directories
|
2020-08-05 11:00:42 -04:00
|
|
|
SearchMan.addDirectory(_gameDataDir.getPath(), _gameDataDir, 0, 5);
|
2020-05-24 00:21:56 +02:00
|
|
|
|
2021-06-26 00:27:07 +02:00
|
|
|
SearchMan.addSubDirectoryMatching(_gameDataDir, "win_data", 0, 2);
|
|
|
|
|
2021-06-12 17:40:01 +02:00
|
|
|
for (uint i = 0; Director::directoryGlobs[i]; i++) {
|
2021-06-09 10:26:14 -04:00
|
|
|
Common::String directoryGlob = directoryGlobs[i];
|
|
|
|
SearchMan.addSubDirectoryMatching(_gameDataDir, directoryGlob);
|
|
|
|
}
|
|
|
|
|
2021-09-26 10:26:02 +02:00
|
|
|
if (debugChannelSet(-1, kDebug32bpp))
|
|
|
|
_colorDepth = 32;
|
|
|
|
else
|
|
|
|
_colorDepth = 8; // 256-color
|
|
|
|
|
2021-08-13 19:58:21 +02:00
|
|
|
switch (getPlatform()) {
|
|
|
|
case Common::kPlatformMacintoshII:
|
|
|
|
_machineType = 4;
|
|
|
|
break;
|
|
|
|
case Common::kPlatformWindows:
|
|
|
|
_machineType = 256;
|
|
|
|
break;
|
|
|
|
case Common::kPlatformMacintosh:
|
|
|
|
default:
|
|
|
|
_machineType = 9; // Macintosh IIci
|
|
|
|
}
|
|
|
|
|
2017-02-04 15:16:25 +01:00
|
|
|
_playbackPaused = false;
|
2017-03-13 19:58:15 +01:00
|
|
|
_skipFrameAdvance = false;
|
2020-08-06 12:36:38 -04:00
|
|
|
_centerStage = true;
|
2021-06-15 15:41:21 +08:00
|
|
|
|
|
|
|
_surface = nullptr;
|
2016-05-18 09:53:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
DirectorEngine::~DirectorEngine() {
|
2020-07-13 11:21:07 +02:00
|
|
|
delete _windowList;
|
2016-07-01 16:31:15 +03:00
|
|
|
delete _lingo;
|
2020-04-02 17:54:58 +02:00
|
|
|
delete _wm;
|
2021-06-15 15:41:21 +08:00
|
|
|
delete _surface;
|
2020-07-20 12:54:48 -04:00
|
|
|
|
|
|
|
for (Common::HashMap<Common::String, Archive *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo>::iterator it = _openResFiles.begin(); it != _openResFiles.end(); ++it) {
|
|
|
|
delete it->_value;
|
|
|
|
}
|
2020-07-26 21:26:28 -04:00
|
|
|
|
2021-08-17 08:55:39 +08:00
|
|
|
for (uint i = 0; i < _winCursor.size(); i++)
|
|
|
|
delete _winCursor[i];
|
2021-08-15 20:26:13 +08:00
|
|
|
|
2020-07-26 21:26:28 -04:00
|
|
|
clearPalettes();
|
2016-05-18 09:53:32 +02:00
|
|
|
}
|
|
|
|
|
2020-08-04 23:26:50 -04:00
|
|
|
Archive *DirectorEngine::getMainArchive() const { return _currentWindow->getMainArchive(); }
|
|
|
|
Movie *DirectorEngine::getCurrentMovie() const { return _currentWindow->getCurrentMovie(); }
|
|
|
|
Common::String DirectorEngine::getCurrentPath() const { return _currentWindow->getCurrentPath(); }
|
2020-07-03 14:57:31 -04:00
|
|
|
|
2021-07-24 16:04:02 +01:00
|
|
|
static bool buildbotErrorHandler(const char *msg) { return true; }
|
2020-07-23 16:25:09 +02:00
|
|
|
|
2020-07-23 18:49:21 -04:00
|
|
|
void DirectorEngine::setCurrentMovie(Movie *movie) {
|
2020-08-04 23:26:50 -04:00
|
|
|
_currentWindow = movie->getWindow();
|
2020-07-23 18:49:21 -04:00
|
|
|
}
|
|
|
|
|
2020-08-10 13:40:01 -04:00
|
|
|
void DirectorEngine::setVersion(uint16 version) {
|
|
|
|
if (version == _version)
|
|
|
|
return;
|
2020-08-14 01:10:56 +02:00
|
|
|
|
2020-08-10 13:40:01 -04:00
|
|
|
debug("Switching to Director v%d", version);
|
|
|
|
_version = version;
|
|
|
|
_lingo->reloadBuiltIns();
|
|
|
|
}
|
|
|
|
|
2016-05-18 09:53:32 +02:00
|
|
|
Common::Error DirectorEngine::run() {
|
|
|
|
debug("Starting v%d Director game", getVersion());
|
|
|
|
|
2020-07-23 16:25:09 +02:00
|
|
|
// We want to avoid GUI errors for buildbot, because they hang it
|
|
|
|
if (debugChannelSet(-1, kDebugFewFramesOnly))
|
|
|
|
Common::setErrorHandler(buildbotErrorHandler);
|
|
|
|
|
2018-06-07 20:14:27 +02:00
|
|
|
if (!_mixer->isReady()) {
|
|
|
|
return Common::kAudioDeviceInitFailed;
|
|
|
|
}
|
|
|
|
|
2016-07-04 22:58:45 +02:00
|
|
|
_currentPalette = nullptr;
|
|
|
|
|
2020-07-03 11:02:10 -04:00
|
|
|
wmMode = debugChannelSet(-1, kDebugDesktop) ? wmModeDesktop : wmModeFullscreen;
|
2020-08-14 01:10:56 +02:00
|
|
|
|
|
|
|
if (debugChannelSet(-1, kDebug32bpp))
|
|
|
|
wmMode |= Graphics::kWMMode32bpp;
|
|
|
|
|
2021-07-12 17:53:14 -04:00
|
|
|
_wm = new Graphics::MacWindowManager(wmMode, &_director3QuickDrawPatterns, getLanguage());
|
2020-06-01 08:18:28 -04:00
|
|
|
_wm->setEngine(this);
|
2016-08-03 18:17:34 +02:00
|
|
|
|
2020-08-14 10:23:13 +02:00
|
|
|
_pixelformat = _wm->_pixelformat;
|
2020-07-11 11:01:47 +02:00
|
|
|
|
2020-08-06 13:50:09 -04:00
|
|
|
_stage = new Window(_wm->getNextId(), false, false, false, _wm, this, true);
|
2020-08-04 23:26:50 -04:00
|
|
|
*_stage->_refCount += 1;
|
2020-07-03 11:02:10 -04:00
|
|
|
|
2020-08-06 14:50:59 -04:00
|
|
|
if (!debugChannelSet(-1, kDebugDesktop))
|
2020-08-04 23:26:50 -04:00
|
|
|
_stage->disableBorder();
|
2020-07-03 11:02:10 -04:00
|
|
|
|
2021-06-15 15:41:21 +08:00
|
|
|
_surface = new Graphics::ManagedSurface(1, 1);
|
|
|
|
_wm->setScreen(_surface);
|
2020-08-04 23:26:50 -04:00
|
|
|
_wm->addWindowInitialized(_stage);
|
|
|
|
_wm->setActiveWindow(_stage->getId());
|
2021-08-13 13:18:23 -04:00
|
|
|
setPalette(-1);
|
2020-07-27 09:25:38 -04:00
|
|
|
|
2020-08-04 23:26:50 -04:00
|
|
|
_currentWindow = _stage;
|
2020-06-29 18:16:48 -04:00
|
|
|
|
2016-06-14 19:03:11 +03:00
|
|
|
_lingo = new Lingo(this);
|
2016-06-26 13:08:26 +02:00
|
|
|
|
2020-05-22 12:57:01 +02:00
|
|
|
if (getGameGID() == GID_TEST) {
|
2020-08-04 23:26:50 -04:00
|
|
|
_currentWindow->runTests();
|
2016-07-10 13:05:30 +02:00
|
|
|
return Common::kNoError;
|
2020-05-22 12:57:01 +02:00
|
|
|
} else if (getGameGID() == GID_TESTALL) {
|
2020-08-04 23:26:50 -04:00
|
|
|
_currentWindow->enqueueAllMovies();
|
2016-07-10 13:05:30 +02:00
|
|
|
}
|
2016-06-19 11:23:52 +02:00
|
|
|
|
2020-06-22 13:23:27 +02:00
|
|
|
if (getPlatform() == Common::kPlatformWindows)
|
|
|
|
_machineType = 256; // IBM PC-type machine
|
|
|
|
|
2020-08-04 23:26:50 -04:00
|
|
|
Common::Error err = _currentWindow->loadInitialMovie();
|
2020-07-03 14:57:31 -04:00
|
|
|
if (err.getCode() != Common::kNoError)
|
|
|
|
return err;
|
2016-08-02 22:25:00 +03:00
|
|
|
|
2017-02-07 20:57:32 +01:00
|
|
|
bool loop = true;
|
|
|
|
|
|
|
|
while (loop) {
|
2020-08-04 23:26:50 -04:00
|
|
|
if (_stage->getCurrentMovie())
|
2020-07-24 15:06:30 -04:00
|
|
|
processEvents();
|
2020-07-23 18:49:21 -04:00
|
|
|
|
2020-08-04 23:26:50 -04:00
|
|
|
_currentWindow = _stage;
|
2021-07-26 12:52:21 -04:00
|
|
|
g_lingo->loadStateFromWindow();
|
2020-08-04 23:26:50 -04:00
|
|
|
loop = _currentWindow->step();
|
2021-07-26 12:52:21 -04:00
|
|
|
g_lingo->saveStateToWindow();
|
2020-07-09 12:20:23 -04:00
|
|
|
|
|
|
|
if (loop) {
|
2021-07-27 22:55:53 +08:00
|
|
|
FArray *windowList = g_lingo->_windowList.u.farr;
|
|
|
|
for (uint i = 0; i < windowList->arr.size(); i++) {
|
|
|
|
if (windowList->arr[i].type != OBJECT || windowList->arr[i].u.obj->getObjType() != kWindowObj)
|
2020-07-09 12:20:23 -04:00
|
|
|
continue;
|
2020-07-11 11:01:47 +02:00
|
|
|
|
2021-07-27 22:55:53 +08:00
|
|
|
_currentWindow = static_cast<Window *>(windowList->arr[i].u.obj);
|
2021-07-26 12:52:21 -04:00
|
|
|
g_lingo->loadStateFromWindow();
|
2020-08-04 23:26:50 -04:00
|
|
|
_currentWindow->step();
|
2021-07-26 12:52:21 -04:00
|
|
|
g_lingo->saveStateToWindow();
|
2020-07-09 12:20:23 -04:00
|
|
|
}
|
|
|
|
}
|
2020-07-09 14:46:00 -04:00
|
|
|
|
2020-07-11 12:30:58 +08:00
|
|
|
draw();
|
2017-02-07 20:57:32 +01:00
|
|
|
}
|
2016-08-02 22:25:00 +03:00
|
|
|
|
2012-11-13 20:23:11 -05:00
|
|
|
return Common::kNoError;
|
|
|
|
}
|
|
|
|
|
2021-07-14 17:10:18 -04:00
|
|
|
Common::CodePage DirectorEngine::getPlatformEncoding() {
|
2021-11-08 23:44:08 -05:00
|
|
|
// Returns the default encoding for the platform we're pretending to be.
|
|
|
|
// (English Mac OS, Japanese Mac OS, English Windows, etc.)
|
2021-07-14 17:10:18 -04:00
|
|
|
return getEncoding(getPlatform(), getLanguage());
|
|
|
|
}
|
|
|
|
|
2021-08-07 00:01:06 +02:00
|
|
|
Common::String DirectorEngine::getEXEName() const {
|
|
|
|
StartMovie startMovie = getStartMovie();
|
|
|
|
if (startMovie.startMovie.size() > 0)
|
|
|
|
return startMovie.startMovie;
|
|
|
|
|
2021-11-30 23:48:09 +01:00
|
|
|
return Common::punycode_decodefilename(Common::lastPathComponent(_gameDescription->desc.filesDescriptions[0].fileName, '/'));
|
2021-08-07 00:01:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void DirectorEngine::parseOptions() {
|
|
|
|
_options.startMovie.startFrame = -1;
|
|
|
|
|
|
|
|
if (!ConfMan.hasKey("start_movie"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
Common::StringTokenizer tok(ConfMan.get("start_movie"), ",");
|
|
|
|
|
|
|
|
while (!tok.empty()) {
|
|
|
|
Common::String part = tok.nextToken();
|
|
|
|
|
|
|
|
int eqPos = part.findLastOf("=");
|
|
|
|
Common::String key;
|
|
|
|
Common::String value;
|
|
|
|
|
|
|
|
if ((uint)eqPos != Common::String::npos) {
|
|
|
|
key = part.substr(0, eqPos);
|
|
|
|
value = part.substr(eqPos + 1, part.size());
|
|
|
|
} else {
|
|
|
|
value = part;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key == "movie" || key.empty()) { // Format is movie[@startFrame]
|
|
|
|
if (!_options.startMovie.startMovie.empty()) {
|
|
|
|
warning("parseOptions(): Duplicate startup movie: %s", value.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
int atPos = value.findLastOf("@");
|
|
|
|
|
|
|
|
if ((uint)atPos == Common::String::npos) {
|
|
|
|
_options.startMovie.startMovie = value;
|
|
|
|
} else {
|
|
|
|
_options.startMovie.startMovie = value.substr(0, atPos);
|
|
|
|
Common::String tail = value.substr(atPos + 1, value.size());
|
|
|
|
if (tail.size() > 0)
|
|
|
|
_options.startMovie.startFrame = atoi(tail.c_str());
|
|
|
|
}
|
|
|
|
|
2021-08-06 23:44:22 -04:00
|
|
|
_options.startMovie.startMovie = Common::punycode_decodepath(_options.startMovie.startMovie).toString(_dirSeparator);
|
2021-08-07 00:01:06 +02:00
|
|
|
|
|
|
|
debug(2, "parseOptions(): Movie is: %s, frame is: %d", _options.startMovie.startMovie.c_str(), _options.startMovie.startFrame);
|
|
|
|
} else if (key == "startup") {
|
|
|
|
_options.startupPath = value;
|
|
|
|
|
|
|
|
debug(2, "parseOptions(): Startup is: %s", value.c_str());
|
|
|
|
} else {
|
|
|
|
warning("parseOptions(): unknown option %s", part.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
StartMovie DirectorEngine::getStartMovie() const {
|
|
|
|
return _options.startMovie;
|
|
|
|
}
|
|
|
|
|
|
|
|
Common::String DirectorEngine::getStartupPath() const {
|
|
|
|
return _options.startupPath;
|
|
|
|
}
|
|
|
|
|
2012-11-13 20:23:11 -05:00
|
|
|
} // End of namespace Director
|