2009-02-17 15:20:21 +00: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.
|
|
|
|
*
|
|
|
|
* 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 2
|
|
|
|
* of the License, or (at your option) any later version.
|
2014-02-18 01:34:24 +00:00
|
|
|
*
|
2009-02-17 15:20:21 +00: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.
|
2014-02-18 01:34:24 +00:00
|
|
|
*
|
2009-02-17 15:20:21 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
*/
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
#include "common/system.h"
|
|
|
|
#include "common/config-manager.h"
|
2010-05-04 11:59:22 +00:00
|
|
|
#include "common/debug-channels.h"
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-15 08:20:53 +00:00
|
|
|
#include "engines/advancedDetector.h"
|
2010-05-04 11:58:12 +00:00
|
|
|
#include "engines/util.h"
|
|
|
|
|
2009-02-15 11:03:21 +00:00
|
|
|
#include "sci/sci.h"
|
2009-07-03 14:22:50 +00:00
|
|
|
#include "sci/debug.h"
|
2009-02-20 21:26:31 +00:00
|
|
|
#include "sci/console.h"
|
2009-12-04 17:38:24 +00:00
|
|
|
#include "sci/event.h"
|
2009-05-11 13:31:17 +00:00
|
|
|
|
2010-02-13 17:44:58 +00:00
|
|
|
#include "sci/engine/features.h"
|
2010-06-10 07:32:05 +00:00
|
|
|
#include "sci/engine/message.h"
|
2010-11-19 08:18:24 +00:00
|
|
|
#include "sci/engine/object.h"
|
2009-02-27 02:23:40 +00:00
|
|
|
#include "sci/engine/state.h"
|
2009-02-24 05:51:55 +00:00
|
|
|
#include "sci/engine/kernel.h"
|
2010-02-02 22:52:41 +00:00
|
|
|
#include "sci/engine/script.h" // for script_adjust_opcode_formats
|
2013-12-04 19:42:16 +00:00
|
|
|
#include "sci/engine/script_patches.h"
|
2010-06-10 09:18:57 +00:00
|
|
|
#include "sci/engine/selector.h" // for SELECTOR
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-01-05 01:22:16 +00:00
|
|
|
#include "sci/sound/audio.h"
|
2010-09-01 19:20:17 +00:00
|
|
|
#include "sci/sound/music.h"
|
2010-01-05 01:22:16 +00:00
|
|
|
#include "sci/sound/soundcmd.h"
|
2010-06-15 15:44:24 +00:00
|
|
|
#include "sci/graphics/animate.h"
|
|
|
|
#include "sci/graphics/cache.h"
|
|
|
|
#include "sci/graphics/compare.h"
|
2011-10-25 22:48:20 +00:00
|
|
|
#include "sci/graphics/controls16.h"
|
2011-10-28 19:19:52 +00:00
|
|
|
#include "sci/graphics/controls32.h"
|
2010-06-15 15:44:24 +00:00
|
|
|
#include "sci/graphics/coordadjuster.h"
|
|
|
|
#include "sci/graphics/cursor.h"
|
2010-05-24 17:21:11 +00:00
|
|
|
#include "sci/graphics/maciconbar.h"
|
2010-06-09 21:41:20 +00:00
|
|
|
#include "sci/graphics/menu.h"
|
2010-06-15 13:34:40 +00:00
|
|
|
#include "sci/graphics/paint16.h"
|
2010-06-15 15:44:24 +00:00
|
|
|
#include "sci/graphics/paint32.h"
|
2010-07-24 16:47:12 +00:00
|
|
|
#include "sci/graphics/picture.h"
|
2010-01-31 12:35:15 +00:00
|
|
|
#include "sci/graphics/ports.h"
|
2010-01-05 01:37:57 +00:00
|
|
|
#include "sci/graphics/palette.h"
|
|
|
|
#include "sci/graphics/screen.h"
|
2010-06-15 15:44:24 +00:00
|
|
|
#include "sci/graphics/text16.h"
|
|
|
|
#include "sci/graphics/transitions.h"
|
2009-10-03 20:49:18 +00:00
|
|
|
|
2010-01-29 22:02:28 +00:00
|
|
|
#ifdef ENABLE_SCI32
|
2016-01-07 02:00:28 +00:00
|
|
|
#include "sci/graphics/palette32.h"
|
2011-09-03 11:50:58 +00:00
|
|
|
#include "sci/graphics/text32.h"
|
2010-06-15 15:44:24 +00:00
|
|
|
#include "sci/graphics/frameout.h"
|
2011-02-07 12:24:09 +00:00
|
|
|
#include "sci/video/robot_decoder.h"
|
2010-01-29 22:02:28 +00:00
|
|
|
#endif
|
|
|
|
|
2009-02-20 14:45:28 +00:00
|
|
|
namespace Sci {
|
|
|
|
|
2010-02-13 17:42:49 +00:00
|
|
|
SciEngine *g_sci = 0;
|
|
|
|
|
|
|
|
|
2009-06-06 10:21:48 +00:00
|
|
|
class GfxDriver;
|
2009-02-21 10:23:36 +00:00
|
|
|
|
2010-06-25 16:16:29 +00:00
|
|
|
SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc, SciGameId gameId)
|
2011-05-16 14:35:10 +00:00
|
|
|
: Engine(syst), _gameDescription(desc), _gameId(gameId), _rng("sci") {
|
2009-02-20 21:26:31 +00:00
|
|
|
|
2010-02-14 12:32:25 +00:00
|
|
|
assert(g_sci == 0);
|
2010-02-13 17:42:49 +00:00
|
|
|
g_sci = this;
|
2010-06-15 12:15:52 +00:00
|
|
|
|
|
|
|
_gfxMacIconBar = 0;
|
|
|
|
|
|
|
|
_audio = 0;
|
2010-02-13 17:44:58 +00:00
|
|
|
_features = 0;
|
2010-06-15 12:15:52 +00:00
|
|
|
_resMan = 0;
|
|
|
|
_gamestate = 0;
|
|
|
|
_kernel = 0;
|
|
|
|
_vocabulary = 0;
|
2010-07-19 15:32:26 +00:00
|
|
|
_vocabularyLanguage = 1; // we load english vocabulary on startup
|
2010-06-15 12:15:52 +00:00
|
|
|
_eventMan = 0;
|
|
|
|
_console = 0;
|
2011-11-29 17:34:25 +00:00
|
|
|
_opcode_formats = 0;
|
2010-02-13 17:42:49 +00:00
|
|
|
|
2016-01-22 01:01:28 +00:00
|
|
|
_forceHiresGraphics = false;
|
|
|
|
|
2009-02-17 18:16:48 +00:00
|
|
|
// Set up the engine specific debug levels
|
2010-04-27 21:40:52 +00:00
|
|
|
DebugMan.addDebugChannel(kDebugLevelError, "Error", "Script error debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelNodes, "Lists", "Lists and nodes debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelGraphics, "Graphics", "Graphics debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelStrings, "Strings", "Strings debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelMemory, "Memory", "Memory debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelFuncCheck, "Func", "Function parameter debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelBresen, "Bresenham", "Bresenham algorithms debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelSound, "Sound", "Sound debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelBaseSetter, "Base", "Base Setter debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelParser, "Parser", "Parser debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelSaid, "Said", "Said specs debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelFile, "File", "File I/O debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelTime, "Time", "Time debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelRoom, "Room", "Room number debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelAvoidPath, "Pathfinding", "Pathfinding debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelDclInflate, "DCL", "DCL inflate debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelVM, "VM", "VM debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelScripts, "Scripts", "Notifies when scripts are unloaded");
|
2013-11-01 12:25:31 +00:00
|
|
|
DebugMan.addDebugChannel(kDebugLevelScriptPatcher, "ScriptPatcher", "Notifies when scripts are patched");
|
2015-04-18 21:13:11 +00:00
|
|
|
DebugMan.addDebugChannel(kDebugLevelWorkarounds, "Workarounds", "Notifies when workarounds are triggered");
|
2010-04-27 21:40:52 +00:00
|
|
|
DebugMan.addDebugChannel(kDebugLevelGC, "GC", "Garbage Collector debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelResMan, "ResMan", "Resource manager debugging");
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelOnStartup, "OnStartup", "Enter debugger at start of game");
|
2011-10-29 15:31:53 +00:00
|
|
|
DebugMan.addDebugChannel(kDebugLevelDebugMode, "DebugMode", "Enable game debug mode at start of game");
|
2009-02-17 18:16:48 +00:00
|
|
|
|
2010-05-04 11:56:52 +00:00
|
|
|
const Common::FSNode gameDataDir(ConfMan.get("path"));
|
|
|
|
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "actors"); // KQ6 hi-res portraits
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "aud"); // resource.aud and audio files
|
2010-08-01 10:07:24 +00:00
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "audio");// resource.aud and audio files
|
2010-08-01 16:23:44 +00:00
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "audiosfx");// resource.aud and audio files
|
2010-05-04 11:56:52 +00:00
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "wav"); // speech files in WAV format
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "sfx"); // music/sound files in WAV format
|
2010-06-16 23:30:22 +00:00
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "avi"); // AVI movie files for Windows versions
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "seq"); // SEQ movie files for DOS versions
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "robot"); // robot movie files
|
2010-07-28 06:03:52 +00:00
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "robots"); // robot movie files
|
2010-11-11 18:42:22 +00:00
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "movie"); // VMD movie files
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "movies"); // VMD movie files
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "vmd"); // VMD movie files
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "duk"); // Duck movie files in Phantasmagoria 2
|
2011-02-05 08:27:33 +00:00
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "Robot Folder"); // Mac robot files
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "Sound Folder"); // Mac audio files
|
2013-12-12 01:27:45 +00:00
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "Voices Folder", 0, 2, true); // Mac audio36 files (recursive for Torin)
|
2011-02-05 08:27:33 +00:00
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "Voices"); // Mac audio36 files
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "VMD Folder"); // Mac VMD files
|
2010-02-05 03:29:04 +00:00
|
|
|
|
2010-02-05 09:02:36 +00:00
|
|
|
// Add the patches directory, except for KQ6CD; The patches folder in some versions of KQ6CD
|
|
|
|
// is for the demo of Phantasmagoria, included in the disk
|
2010-06-25 16:16:29 +00:00
|
|
|
if (_gameId != GID_KQ6)
|
2010-05-04 11:56:52 +00:00
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "patches"); // resource patches
|
2009-02-17 18:16:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SciEngine::~SciEngine() {
|
|
|
|
// Remove all of our debug levels here
|
2010-04-27 21:40:52 +00:00
|
|
|
DebugMan.clearAllDebugChannels();
|
2009-02-20 21:26:31 +00:00
|
|
|
|
2010-06-28 08:18:55 +00:00
|
|
|
#ifdef ENABLE_SCI32
|
2016-01-07 02:00:28 +00:00
|
|
|
// _gfxPalette32 is the same as _gfxPalette16
|
|
|
|
// and will be destroyed when _gfxPalette16 is
|
|
|
|
// destroyed
|
2011-10-28 19:19:52 +00:00
|
|
|
delete _gfxControls32;
|
2011-09-03 11:50:58 +00:00
|
|
|
delete _gfxText32;
|
2011-02-07 12:24:09 +00:00
|
|
|
delete _robotDecoder;
|
2010-06-28 08:18:55 +00:00
|
|
|
delete _gfxFrameout;
|
|
|
|
#endif
|
|
|
|
delete _gfxMenu;
|
2011-10-25 22:48:20 +00:00
|
|
|
delete _gfxControls16;
|
2010-06-28 08:18:55 +00:00
|
|
|
delete _gfxText16;
|
|
|
|
delete _gfxAnimate;
|
|
|
|
delete _gfxPaint;
|
|
|
|
delete _gfxTransitions;
|
|
|
|
delete _gfxCompare;
|
|
|
|
delete _gfxCoordAdjuster;
|
|
|
|
delete _gfxPorts;
|
|
|
|
delete _gfxCache;
|
2016-01-07 02:00:28 +00:00
|
|
|
delete _gfxPalette16;
|
2010-06-28 08:18:55 +00:00
|
|
|
delete _gfxCursor;
|
|
|
|
delete _gfxScreen;
|
|
|
|
|
2009-11-04 09:36:18 +00:00
|
|
|
delete _audio;
|
2010-06-29 09:00:08 +00:00
|
|
|
delete _soundCmd;
|
2009-07-11 23:45:54 +00:00
|
|
|
delete _kernel;
|
|
|
|
delete _vocabulary;
|
2009-02-20 21:26:31 +00:00
|
|
|
delete _console;
|
2010-02-13 17:44:58 +00:00
|
|
|
delete _features;
|
2010-05-24 21:51:45 +00:00
|
|
|
delete _gfxMacIconBar;
|
2010-02-13 17:42:49 +00:00
|
|
|
|
2010-06-28 08:18:55 +00:00
|
|
|
delete _eventMan;
|
|
|
|
delete _gamestate->_segMan;
|
|
|
|
delete _gamestate;
|
2011-11-29 17:34:25 +00:00
|
|
|
|
|
|
|
delete[] _opcode_formats;
|
|
|
|
|
2013-12-04 19:42:16 +00:00
|
|
|
delete _scriptPatcher;
|
2010-06-28 08:18:55 +00:00
|
|
|
delete _resMan; // should be deleted last
|
2010-02-13 17:42:49 +00:00
|
|
|
g_sci = 0;
|
2009-02-17 18:16:48 +00:00
|
|
|
}
|
|
|
|
|
2010-08-17 20:36:28 +00:00
|
|
|
extern void showScummVMDialog(const Common::String &message);
|
|
|
|
|
2009-03-01 04:42:46 +00:00
|
|
|
Common::Error SciEngine::run() {
|
2009-09-02 12:02:37 +00:00
|
|
|
_resMan = new ResourceManager();
|
2010-06-15 12:15:52 +00:00
|
|
|
assert(_resMan);
|
|
|
|
_resMan->addAppropriateSources();
|
|
|
|
_resMan->init();
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-15 12:15:52 +00:00
|
|
|
// TODO: Add error handling. Check return values of addAppropriateSources
|
|
|
|
// and init. We first have to *add* sensible return values, though ;).
|
|
|
|
/*
|
2009-09-02 12:02:37 +00:00
|
|
|
if (!_resMan) {
|
2009-10-10 00:07:19 +00:00
|
|
|
warning("No resources found, aborting");
|
2009-02-17 18:16:48 +00:00
|
|
|
return Common::kNoGameDataFoundError;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
2010-06-15 12:15:52 +00:00
|
|
|
*/
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-07-03 06:55:10 +00:00
|
|
|
// Reset, so that error()s before SoundCommandParser is initialized wont cause a crash
|
|
|
|
_soundCmd = NULL;
|
|
|
|
|
2010-06-09 18:42:21 +00:00
|
|
|
// Add the after market GM patches for the specified game, if they exist
|
2010-06-17 23:14:34 +00:00
|
|
|
_resMan->addNewGMPatch(_gameId);
|
2010-08-23 20:29:13 +00:00
|
|
|
_gameObjectAddress = _resMan->findGameObject();
|
2014-10-28 14:17:06 +00:00
|
|
|
|
2013-12-04 19:42:16 +00:00
|
|
|
_scriptPatcher = new ScriptPatcher();
|
|
|
|
SegManager *segMan = new SegManager(_resMan, _scriptPatcher);
|
2010-05-18 12:16:48 +00:00
|
|
|
|
2016-01-22 01:01:28 +00:00
|
|
|
// Read user option for hires graphics
|
|
|
|
// Only show/selectable for:
|
|
|
|
// - King's Quest 6 CD
|
|
|
|
// - King's Quest 6 CD demo
|
|
|
|
// - Gabriel Knight 1 CD
|
2016-01-22 01:30:13 +00:00
|
|
|
// - Police Quest 4 CD
|
2016-01-22 01:01:28 +00:00
|
|
|
// TODO: Check, if Gabriel Knight 1 floppy supports high resolution
|
|
|
|
// TODO: Check, if Gabriel Knight 1 on Mac supports high resolution
|
|
|
|
switch (getPlatform()) {
|
|
|
|
case Common::kPlatformDOS:
|
|
|
|
case Common::kPlatformWindows:
|
|
|
|
// Only DOS+Windows
|
|
|
|
switch (_gameId) {
|
|
|
|
case GID_KQ6:
|
|
|
|
if (isCD())
|
|
|
|
_forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics");
|
|
|
|
break;
|
|
|
|
case GID_GK1:
|
|
|
|
if ((isCD()) && (!isDemo()))
|
|
|
|
_forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics");
|
|
|
|
break;
|
2016-01-22 01:30:13 +00:00
|
|
|
case GID_PQ4:
|
|
|
|
if (isCD())
|
|
|
|
_forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics");
|
|
|
|
break;
|
2016-01-22 01:01:28 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
|
2010-06-28 08:18:55 +00:00
|
|
|
// Initialize the game screen
|
|
|
|
_gfxScreen = new GfxScreen(_resMan);
|
2012-03-31 10:55:03 +00:00
|
|
|
_gfxScreen->enableUndithering(ConfMan.getBool("disable_dithering"));
|
2010-06-09 18:42:21 +00:00
|
|
|
|
2010-05-18 12:16:48 +00:00
|
|
|
_kernel = new Kernel(_resMan, segMan);
|
2013-11-21 21:41:07 +00:00
|
|
|
_kernel->init();
|
2010-08-23 20:29:13 +00:00
|
|
|
|
2010-06-09 18:42:21 +00:00
|
|
|
_features = new GameFeatures(segMan, _kernel);
|
2010-08-07 08:59:43 +00:00
|
|
|
// Only SCI0, SCI01 and SCI1 EGA games used a parser
|
2011-02-27 14:48:53 +00:00
|
|
|
_vocabulary = (getSciVersion() <= SCI_VERSION_1_EGA_ONLY) ? new Vocabulary(_resMan, false) : NULL;
|
2010-08-07 08:59:43 +00:00
|
|
|
// Also, XMAS1990 apparently had a parser too. Refer to http://forums.scummvm.org/viewtopic.php?t=9135
|
|
|
|
if (getGameId() == GID_CHRISTMAS1990)
|
|
|
|
_vocabulary = new Vocabulary(_resMan, false);
|
2009-11-04 09:36:18 +00:00
|
|
|
_audio = new AudioPlayer(_resMan);
|
2010-06-01 15:11:20 +00:00
|
|
|
_gamestate = new EngineState(segMan);
|
2010-06-17 23:11:34 +00:00
|
|
|
_eventMan = new EventManager(_resMan->detectFontExtended());
|
2010-11-10 01:08:17 +00:00
|
|
|
|
2011-05-27 15:34:43 +00:00
|
|
|
// Create debugger console. It requires GFX and _gamestate to be initialized
|
|
|
|
_console = new Console(this);
|
|
|
|
|
2010-11-17 14:08:13 +00:00
|
|
|
// The game needs to be initialized before the graphics system is initialized, as
|
|
|
|
// the graphics code checks parts of the seg manager upon initialization (e.g. for
|
|
|
|
// the presence of the fastCast object)
|
|
|
|
if (!initGame()) { /* Initialize */
|
|
|
|
warning("Game initialization failed: Aborting...");
|
|
|
|
// TODO: Add an "init failed" error?
|
|
|
|
return Common::kUnknownError;
|
|
|
|
}
|
2010-06-09 21:41:20 +00:00
|
|
|
|
2010-11-17 14:08:13 +00:00
|
|
|
// we try to find the super class address of the game object, we can't do that earlier
|
|
|
|
const Object *gameObject = segMan->getObject(_gameObjectAddress);
|
|
|
|
if (!gameObject) {
|
|
|
|
warning("Could not get game object, aborting...");
|
|
|
|
return Common::kUnknownError;
|
2010-08-23 20:29:13 +00:00
|
|
|
}
|
|
|
|
|
2010-06-15 07:21:52 +00:00
|
|
|
script_adjust_opcode_formats();
|
2009-08-30 14:53:58 +00:00
|
|
|
|
2010-06-29 09:00:08 +00:00
|
|
|
// Must be called after game_init(), as they use _features
|
|
|
|
_kernel->loadKernelNames(_features);
|
|
|
|
_soundCmd = new SoundCommandParser(_resMan, segMan, _kernel, _audio, _features->detectDoSoundType());
|
2009-11-12 15:24:11 +00:00
|
|
|
|
2010-01-12 00:51:37 +00:00
|
|
|
syncSoundSettings();
|
2010-12-22 13:58:28 +00:00
|
|
|
syncIngameAudioOptions();
|
2010-01-12 00:51:37 +00:00
|
|
|
|
2011-02-17 18:13:30 +00:00
|
|
|
// Load our Mac executable here for icon bar palettes and high-res fonts
|
|
|
|
loadMacExecutable();
|
|
|
|
|
2010-06-28 08:18:55 +00:00
|
|
|
// Initialize all graphics related subsystems
|
2010-06-15 13:34:40 +00:00
|
|
|
initGraphics();
|
2009-10-03 20:49:18 +00:00
|
|
|
|
2010-11-17 14:08:13 +00:00
|
|
|
// Patch in our save/restore code, so that dialogs are replaced
|
2011-01-27 10:49:11 +00:00
|
|
|
patchGameSaveRestore();
|
|
|
|
setLauncherLanguage();
|
2010-08-01 22:41:06 +00:00
|
|
|
|
2010-11-17 14:08:13 +00:00
|
|
|
// Check whether loading a savestate was requested
|
|
|
|
int directSaveSlotLoading = ConfMan.getInt("save_slot");
|
|
|
|
if (directSaveSlotLoading >= 0) {
|
2015-04-27 16:21:41 +00:00
|
|
|
_gamestate->_delayedRestoreGame = true;
|
|
|
|
_gamestate->_delayedRestoreGameId = directSaveSlotLoading;
|
2016-03-02 18:34:40 +00:00
|
|
|
_gamestate->_delayedRestoreFromLauncher = true;
|
2010-08-25 10:38:09 +00:00
|
|
|
|
2014-02-17 01:29:17 +00:00
|
|
|
// Jones only initializes its menus when restarting/restoring, thus set
|
|
|
|
// the gameIsRestarting flag here before initializing. Fixes bug #6536.
|
|
|
|
if (g_sci->getGameId() == GID_JONES)
|
|
|
|
_gamestate->gameIsRestarting = GAMEISRESTARTING_RESTORE;
|
2010-01-30 19:08:00 +00:00
|
|
|
}
|
|
|
|
|
2011-06-19 22:59:48 +00:00
|
|
|
// Show any special warnings for buggy scripts with severe game bugs,
|
2010-08-17 20:36:28 +00:00
|
|
|
// which have been patched by Sierra
|
|
|
|
if (getGameId() == GID_LONGBOW) {
|
|
|
|
// Longbow 1.0 has a buggy script which prevents the game
|
|
|
|
// from progressing during the Green Man riddle sequence.
|
|
|
|
// A patch for this buggy script has been released by Sierra,
|
|
|
|
// and is necessary to complete the game without issues.
|
|
|
|
// The patched script is included in Longbow 1.1.
|
|
|
|
// Refer to bug #3036609.
|
|
|
|
Resource *buggyScript = _resMan->findResource(ResourceId(kResourceTypeScript, 180), 0);
|
|
|
|
|
2010-08-24 14:58:29 +00:00
|
|
|
if (buggyScript && (buggyScript->size == 12354 || buggyScript->size == 12362)) {
|
2010-08-17 20:36:28 +00:00
|
|
|
showScummVMDialog("A known buggy game script has been detected, which could "
|
2010-10-29 16:28:22 +00:00
|
|
|
"prevent you from progressing later on in the game, during "
|
|
|
|
"the sequence with the Green Man's riddles. Please, apply "
|
|
|
|
"the latest patch for this game by Sierra to avoid possible "
|
|
|
|
"problems");
|
2010-08-17 20:36:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-02 21:50:00 +00:00
|
|
|
// Show a warning if the user has selected a General MIDI device, no GM patch exists
|
|
|
|
// (i.e. patch 4) and the game is one of the known 8 SCI1 games that Sierra has provided
|
|
|
|
// after market patches for in their "General MIDI Utility".
|
2010-09-07 15:09:59 +00:00
|
|
|
if (_soundCmd->getMusicType() == MT_GM && !ConfMan.getBool("native_mt32")) {
|
2010-09-02 21:50:00 +00:00
|
|
|
if (!_resMan->findResource(ResourceId(kResourceTypePatch, 4), 0)) {
|
|
|
|
switch (getGameId()) {
|
|
|
|
case GID_ECOQUEST:
|
|
|
|
case GID_HOYLE3:
|
|
|
|
case GID_LSL1:
|
|
|
|
case GID_LSL5:
|
|
|
|
case GID_LONGBOW:
|
|
|
|
case GID_SQ1:
|
|
|
|
case GID_SQ4:
|
|
|
|
case GID_FAIRYTALES:
|
|
|
|
showScummVMDialog("You have selected General MIDI as a sound device. Sierra "
|
2010-10-29 16:28:22 +00:00
|
|
|
"has provided after-market support for General MIDI for this "
|
|
|
|
"game in their \"General MIDI Utility\". Please, apply this "
|
|
|
|
"patch in order to enjoy MIDI music with this game. Once you "
|
|
|
|
"have obtained it, you can unpack all of the included *.PAT "
|
|
|
|
"files in your ScummVM extras folder and ScummVM will add the "
|
|
|
|
"appropriate patch automatically. Alternatively, you can follow "
|
|
|
|
"the instructions in the READ.ME file included in the patch and "
|
|
|
|
"rename the associated *.PAT file to 4.PAT and place it in the "
|
|
|
|
"game folder. Without this patch, General MIDI music for this "
|
|
|
|
"game will sound badly distorted.");
|
2010-09-02 21:50:00 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-29 10:58:54 +00:00
|
|
|
if (gameHasFanMadePatch()) {
|
|
|
|
showScummVMDialog("Your game is patched with a fan made script patch. Such patches have "
|
2010-10-29 16:28:22 +00:00
|
|
|
"been reported to cause issues, as they modify game scripts extensively. "
|
|
|
|
"The issues that these patches fix do not occur in ScummVM, so you are "
|
|
|
|
"advised to remove this patch from your game folder in order to avoid "
|
|
|
|
"having unexpected errors and/or issues later on.");
|
2010-10-29 10:58:54 +00:00
|
|
|
}
|
2010-09-02 21:50:00 +00:00
|
|
|
|
2010-11-17 14:08:13 +00:00
|
|
|
runGame();
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-01-12 00:51:37 +00:00
|
|
|
ConfMan.flushToDisk();
|
|
|
|
|
2009-02-15 08:20:53 +00:00
|
|
|
return Common::kNoError;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2010-10-29 10:58:54 +00:00
|
|
|
bool SciEngine::gameHasFanMadePatch() {
|
|
|
|
struct FanMadePatchInfo {
|
|
|
|
SciGameId gameID;
|
|
|
|
uint16 targetScript;
|
|
|
|
uint16 targetSize;
|
|
|
|
uint16 patchedByteOffset;
|
|
|
|
byte patchedByte;
|
|
|
|
};
|
|
|
|
|
|
|
|
const FanMadePatchInfo patchInfo[] = {
|
|
|
|
// game script size offset byte
|
|
|
|
// ** NRS Patches **************************
|
|
|
|
{ GID_HOYLE3, 994, 2580, 656, 0x78 },
|
|
|
|
{ GID_KQ1, 85, 5156, 631, 0x02 },
|
|
|
|
{ GID_LAURABOW2, 994, 4382, 0, 0x00 },
|
|
|
|
{ GID_LONGBOW, 994, 4950, 1455, 0x78 }, // English
|
|
|
|
{ GID_LONGBOW, 994, 5020, 1469, 0x78 }, // German
|
2010-10-30 11:07:44 +00:00
|
|
|
{ GID_LSL1, 803, 592, 342, 0x01 },
|
2010-10-29 10:58:54 +00:00
|
|
|
{ GID_LSL3, 380, 6148, 195, 0x35 },
|
|
|
|
{ GID_LSL5, 994, 4810, 1342, 0x78 }, // English
|
|
|
|
{ GID_LSL5, 994, 4942, 1392, 0x76 }, // German
|
|
|
|
{ GID_PQ1, 994, 4332, 1473, 0x78 },
|
|
|
|
{ GID_PQ2, 200, 10614, 0, 0x00 },
|
|
|
|
{ GID_PQ3, 994, 4686, 1291, 0x78 }, // English
|
|
|
|
{ GID_PQ3, 994, 4734, 1283, 0x78 }, // German
|
|
|
|
{ GID_QFG1VGA, 994, 4388, 0, 0x00 },
|
2013-04-27 11:40:08 +00:00
|
|
|
{ GID_QFG3, 994, 4714, 2, 0x48 },
|
2010-10-29 10:58:54 +00:00
|
|
|
// TODO: Disabled, as it fixes a whole lot of bugs which can't be tested till SCI2.1 support is finished
|
|
|
|
//{ GID_QFG4, 710, 11477, 0, 0x00 },
|
|
|
|
{ GID_SQ1, 994, 4740, 0, 0x00 },
|
|
|
|
{ GID_SQ5, 994, 4142, 1496, 0x78 }, // English/German/French
|
|
|
|
// TODO: Disabled, till we can test the Italian version
|
|
|
|
//{ GID_SQ5, 994, 4148, 0, 0x00 }, // Italian - patched file is the same size as the original
|
|
|
|
// TODO: The bugs in SQ6 can't be tested till SCI2.1 support is finished
|
|
|
|
//{ GID_SQ6, 380, 16308, 15042, 0x0C }, // English
|
|
|
|
//{ GID_SQ6, 380, 11652, 0, 0x00 }, // German - patched file is the same size as the original
|
|
|
|
// ** End marker ***************************
|
|
|
|
{ GID_FANMADE, 0, 0, 0, 0x00 }
|
|
|
|
};
|
|
|
|
|
|
|
|
int curEntry = 0;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
if (patchInfo[curEntry].targetSize == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (patchInfo[curEntry].gameID == getGameId()) {
|
|
|
|
Resource *targetScript = _resMan->findResource(ResourceId(kResourceTypeScript, patchInfo[curEntry].targetScript), 0);
|
|
|
|
|
|
|
|
if (targetScript && targetScript->size + 2 == patchInfo[curEntry].targetSize) {
|
|
|
|
if (patchInfo[curEntry].patchedByteOffset == 0)
|
|
|
|
return true;
|
|
|
|
else if (targetScript->data[patchInfo[curEntry].patchedByteOffset - 2] == patchInfo[curEntry].patchedByte)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
curEntry++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-08-24 14:40:18 +00:00
|
|
|
static byte patchGameRestoreSave[] = {
|
2010-08-24 09:11:53 +00:00
|
|
|
0x39, 0x03, // pushi 03
|
2010-08-23 23:04:07 +00:00
|
|
|
0x76, // push0
|
|
|
|
0x38, 0xff, 0xff, // pushi -1
|
2010-08-24 09:11:53 +00:00
|
|
|
0x76, // push0
|
2011-03-03 22:20:28 +00:00
|
|
|
0x43, 0xff, 0x06, // callk kRestoreGame/kSaveGame (will get changed afterwards)
|
2011-02-21 23:51:50 +00:00
|
|
|
0x48, // ret
|
|
|
|
};
|
|
|
|
|
|
|
|
// SCI2 version: Same as above, but the second parameter to callk is a word
|
|
|
|
static byte patchGameRestoreSaveSci2[] = {
|
|
|
|
0x39, 0x03, // pushi 03
|
|
|
|
0x76, // push0
|
|
|
|
0x38, 0xff, 0xff, // pushi -1
|
|
|
|
0x76, // push0
|
2011-03-03 22:20:28 +00:00
|
|
|
0x43, 0xff, 0x06, 0x00, // callk kRestoreGame/kSaveGame (will get changed afterwards)
|
|
|
|
0x48, // ret
|
|
|
|
};
|
|
|
|
|
|
|
|
// SCI21 version: Same as above, but the second parameter to callk is a word
|
|
|
|
static byte patchGameRestoreSaveSci21[] = {
|
|
|
|
0x39, 0x04, // pushi 04
|
|
|
|
0x76, // push0 // 0: save, 1: restore (will get changed afterwards)
|
|
|
|
0x76, // push0
|
|
|
|
0x38, 0xff, 0xff, // pushi -1
|
|
|
|
0x76, // push0
|
|
|
|
0x43, 0xff, 0x08, 0x00, // callk kSave (will get changed afterwards)
|
2010-08-23 23:04:07 +00:00
|
|
|
0x48, // ret
|
|
|
|
};
|
|
|
|
|
2011-02-27 22:15:47 +00:00
|
|
|
static void patchGameSaveRestoreCode(SegManager *segMan, reg_t methodAddress, byte id) {
|
2012-06-18 02:21:59 +00:00
|
|
|
Script *script = segMan->getScript(methodAddress.getSegment());
|
|
|
|
byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.getOffset()));
|
2013-04-28 18:47:15 +00:00
|
|
|
|
|
|
|
if (getSciVersion() <= SCI_VERSION_1_1) {
|
2011-02-27 22:15:47 +00:00
|
|
|
memcpy(patchPtr, patchGameRestoreSave, sizeof(patchGameRestoreSave));
|
2013-04-28 18:47:15 +00:00
|
|
|
} else { // SCI2+
|
2011-02-27 22:15:47 +00:00
|
|
|
memcpy(patchPtr, patchGameRestoreSaveSci2, sizeof(patchGameRestoreSaveSci2));
|
2013-04-28 18:47:15 +00:00
|
|
|
|
|
|
|
if (g_sci->isBE()) {
|
|
|
|
// LE -> BE
|
|
|
|
patchPtr[9] = 0x00;
|
|
|
|
patchPtr[10] = 0x06;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-27 22:15:47 +00:00
|
|
|
patchPtr[8] = id;
|
|
|
|
}
|
|
|
|
|
2011-03-03 22:20:28 +00:00
|
|
|
static void patchGameSaveRestoreCodeSci21(SegManager *segMan, reg_t methodAddress, byte id, bool doRestore) {
|
2012-06-18 02:21:59 +00:00
|
|
|
Script *script = segMan->getScript(methodAddress.getSegment());
|
|
|
|
byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.getOffset()));
|
2011-03-03 22:20:28 +00:00
|
|
|
memcpy(patchPtr, patchGameRestoreSaveSci21, sizeof(patchGameRestoreSaveSci21));
|
2013-04-28 18:47:15 +00:00
|
|
|
|
2011-03-03 22:20:28 +00:00
|
|
|
if (doRestore)
|
|
|
|
patchPtr[2] = 0x78; // push1
|
2013-04-28 18:47:15 +00:00
|
|
|
|
|
|
|
if (g_sci->isBE()) {
|
|
|
|
// LE -> BE
|
|
|
|
patchPtr[10] = 0x00;
|
|
|
|
patchPtr[11] = 0x08;
|
|
|
|
}
|
|
|
|
|
2011-03-03 22:20:28 +00:00
|
|
|
patchPtr[9] = id;
|
|
|
|
}
|
|
|
|
|
2011-01-27 10:49:11 +00:00
|
|
|
void SciEngine::patchGameSaveRestore() {
|
|
|
|
SegManager *segMan = _gamestate->_segMan;
|
2010-08-24 15:11:53 +00:00
|
|
|
const Object *gameObject = segMan->getObject(_gameObjectAddress);
|
2011-02-27 22:15:47 +00:00
|
|
|
const Object *gameSuperObject = segMan->getObject(gameObject->getSuperClassSelector());
|
2010-11-27 18:46:12 +00:00
|
|
|
if (!gameSuperObject)
|
|
|
|
gameSuperObject = gameObject; // happens in KQ5CD, when loading saved games before r54510
|
2010-08-23 23:04:07 +00:00
|
|
|
byte kernelIdRestore = 0;
|
2010-08-24 13:50:55 +00:00
|
|
|
byte kernelIdSave = 0;
|
2010-08-23 23:04:07 +00:00
|
|
|
|
2010-08-24 09:00:53 +00:00
|
|
|
switch (_gameId) {
|
2016-02-14 09:27:44 +00:00
|
|
|
case GID_HOYLE1: // gets confused, although the game doesn't support saving/restoring at all
|
2010-09-08 12:45:42 +00:00
|
|
|
case GID_HOYLE2: // gets confused, see hoyle1
|
2011-03-03 23:42:53 +00:00
|
|
|
case GID_JONES: // gets confused, when we patch us in, the game is only able to save to 1 slot, so hooking is not required
|
2014-06-02 18:51:39 +00:00
|
|
|
case GID_MOTHERGOOSE: // mother goose EGA saves/restores directly and has no save/restore dialogs
|
2011-03-03 23:42:53 +00:00
|
|
|
case GID_MOTHERGOOSE256: // mother goose saves/restores directly and has no save/restore dialogs
|
|
|
|
case GID_PHANTASMAGORIA: // has custom save/load code
|
2011-03-09 21:45:42 +00:00
|
|
|
case GID_SHIVERS: // has custom save/load code
|
2010-08-24 09:00:53 +00:00
|
|
|
return;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-03-25 14:48:38 +00:00
|
|
|
if (ConfMan.getBool("originalsaveload"))
|
2010-08-24 09:00:53 +00:00
|
|
|
return;
|
2010-08-24 08:31:57 +00:00
|
|
|
|
2011-02-27 22:15:47 +00:00
|
|
|
uint16 kernelNamesSize = _kernel->getKernelNamesSize();
|
|
|
|
for (uint16 kernelNr = 0; kernelNr < kernelNamesSize; kernelNr++) {
|
2010-08-23 23:04:07 +00:00
|
|
|
Common::String kernelName = _kernel->getKernelName(kernelNr);
|
|
|
|
if (kernelName == "RestoreGame")
|
|
|
|
kernelIdRestore = kernelNr;
|
2010-08-24 13:50:55 +00:00
|
|
|
if (kernelName == "SaveGame")
|
|
|
|
kernelIdSave = kernelNr;
|
2011-03-03 22:20:28 +00:00
|
|
|
if (kernelName == "Save")
|
|
|
|
kernelIdSave = kernelIdRestore = kernelNr;
|
2010-08-23 23:04:07 +00:00
|
|
|
}
|
|
|
|
|
2011-02-27 22:15:47 +00:00
|
|
|
// Search for gameobject superclass ::restore
|
|
|
|
uint16 gameSuperObjectMethodCount = gameSuperObject->getMethodCount();
|
|
|
|
for (uint16 methodNr = 0; methodNr < gameSuperObjectMethodCount; methodNr++) {
|
2010-08-23 23:04:07 +00:00
|
|
|
uint16 selectorId = gameSuperObject->getFuncSelector(methodNr);
|
|
|
|
Common::String methodName = _kernel->getSelectorName(selectorId);
|
2011-03-03 22:20:28 +00:00
|
|
|
if (methodName == "restore") {
|
|
|
|
if (kernelIdSave != kernelIdRestore)
|
|
|
|
patchGameSaveRestoreCode(segMan, gameSuperObject->getFunction(methodNr), kernelIdRestore);
|
|
|
|
else
|
|
|
|
patchGameSaveRestoreCodeSci21(segMan, gameSuperObject->getFunction(methodNr), kernelIdRestore, true);
|
|
|
|
}
|
2011-02-27 22:15:47 +00:00
|
|
|
else if (methodName == "save") {
|
2011-03-03 22:20:28 +00:00
|
|
|
if (_gameId != GID_FAIRYTALES) { // Fairy Tales saves automatically without a dialog
|
|
|
|
if (kernelIdSave != kernelIdRestore)
|
|
|
|
patchGameSaveRestoreCode(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave);
|
|
|
|
else
|
|
|
|
patchGameSaveRestoreCodeSci21(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave, false);
|
|
|
|
}
|
2010-08-24 15:11:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-21 19:32:42 +00:00
|
|
|
const Object *patchObjectSave = nullptr;
|
|
|
|
|
|
|
|
if (getSciVersion() < SCI_VERSION_2) {
|
|
|
|
// Patch gameobject ::save for now for SCI0 - SCI1.1
|
|
|
|
// TODO: It seems this was never adjusted to superclass, but adjusting it now may cause
|
|
|
|
// issues with some game. Needs to get checked and then possibly changed.
|
|
|
|
patchObjectSave = gameObject;
|
|
|
|
} else {
|
|
|
|
// Patch superclass ::save for SCI32
|
|
|
|
patchObjectSave = gameSuperObject;
|
|
|
|
}
|
|
|
|
|
2011-02-27 22:15:47 +00:00
|
|
|
// Search for gameobject ::save, if there is one patch that one too
|
2016-02-21 19:32:42 +00:00
|
|
|
uint16 patchObjectMethodCount = patchObjectSave->getMethodCount();
|
|
|
|
for (uint16 methodNr = 0; methodNr < patchObjectMethodCount; methodNr++) {
|
|
|
|
uint16 selectorId = patchObjectSave->getFuncSelector(methodNr);
|
2010-08-24 15:11:53 +00:00
|
|
|
Common::String methodName = _kernel->getSelectorName(selectorId);
|
|
|
|
if (methodName == "save") {
|
2011-03-03 22:20:28 +00:00
|
|
|
if (_gameId != GID_FAIRYTALES) { // Fairy Tales saves automatically without a dialog
|
|
|
|
if (kernelIdSave != kernelIdRestore)
|
2016-02-21 19:32:42 +00:00
|
|
|
patchGameSaveRestoreCode(segMan, patchObjectSave->getFunction(methodNr), kernelIdSave);
|
2011-03-03 22:20:28 +00:00
|
|
|
else
|
2016-02-21 19:32:42 +00:00
|
|
|
patchGameSaveRestoreCodeSci21(segMan, patchObjectSave->getFunction(methodNr), kernelIdSave, false);
|
2011-03-03 22:20:28 +00:00
|
|
|
}
|
2010-08-23 23:04:07 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-10 07:32:05 +00:00
|
|
|
bool SciEngine::initGame() {
|
|
|
|
// Script 0 needs to be allocated here before anything else!
|
|
|
|
int script0Segment = _gamestate->_segMan->getScriptSegment(0, SCRIPT_GET_LOCK);
|
|
|
|
DataStack *stack = _gamestate->_segMan->allocateStack(VM_STACK_SIZE, NULL);
|
|
|
|
|
|
|
|
_gamestate->_msgState = new MessageState(_gamestate->_segMan);
|
2010-06-10 11:43:20 +00:00
|
|
|
_gamestate->gcCountDown = GC_INTERVAL - 1;
|
2010-06-10 07:32:05 +00:00
|
|
|
|
|
|
|
// Script 0 should always be at segment 1
|
|
|
|
if (script0Segment != 1) {
|
2014-02-17 09:48:34 +00:00
|
|
|
debug(2, "Failed to instantiate script 0");
|
2010-06-10 07:32:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
_gamestate->initGlobals();
|
|
|
|
_gamestate->_segMan->initSysStrings();
|
|
|
|
|
|
|
|
_gamestate->r_acc = _gamestate->r_prev = NULL_REG;
|
|
|
|
|
|
|
|
_gamestate->_executionStack.clear(); // Start without any execution stack
|
2010-06-10 11:18:10 +00:00
|
|
|
_gamestate->executionStackBase = -1; // No vm is running yet
|
2010-06-10 07:32:05 +00:00
|
|
|
_gamestate->_executionStackPosChanged = false;
|
|
|
|
|
|
|
|
_gamestate->abortScriptProcessing = kAbortNone;
|
2010-07-31 14:09:42 +00:00
|
|
|
_gamestate->gameIsRestarting = GAMEISRESTARTING_NONE;
|
2010-06-10 07:32:05 +00:00
|
|
|
|
|
|
|
_gamestate->stack_base = stack->_entries;
|
|
|
|
_gamestate->stack_top = stack->_entries + stack->_capacity;
|
|
|
|
|
2010-06-27 21:18:19 +00:00
|
|
|
if (!_gamestate->_segMan->instantiateScript(0)) {
|
2010-06-17 23:45:38 +00:00
|
|
|
error("initGame(): Could not instantiate script 0");
|
2010-06-10 07:32:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset parser
|
2011-03-27 15:13:42 +00:00
|
|
|
if (_vocabulary)
|
2010-07-19 15:30:27 +00:00
|
|
|
_vocabulary->reset();
|
2010-06-10 07:32:05 +00:00
|
|
|
|
2010-10-31 01:45:24 +00:00
|
|
|
_gamestate->lastWaitTime = _gamestate->_screenUpdateTime = g_system->getMillis();
|
2010-06-10 07:32:05 +00:00
|
|
|
|
|
|
|
// Load game language into printLang property of game object
|
2010-06-10 11:18:10 +00:00
|
|
|
setSciLanguage();
|
2010-06-10 07:32:05 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-06-15 13:34:40 +00:00
|
|
|
void SciEngine::initGraphics() {
|
2010-06-28 08:18:55 +00:00
|
|
|
|
|
|
|
// Reset all graphics objects
|
|
|
|
_gfxAnimate = 0;
|
|
|
|
_gfxCache = 0;
|
|
|
|
_gfxCompare = 0;
|
2011-10-25 22:48:20 +00:00
|
|
|
_gfxControls16 = 0;
|
2010-06-28 08:18:55 +00:00
|
|
|
_gfxCoordAdjuster = 0;
|
|
|
|
_gfxCursor = 0;
|
|
|
|
_gfxMacIconBar = 0;
|
|
|
|
_gfxMenu = 0;
|
|
|
|
_gfxPaint = 0;
|
|
|
|
_gfxPaint16 = 0;
|
2016-01-07 02:00:28 +00:00
|
|
|
_gfxPalette16 = 0;
|
2010-06-28 08:18:55 +00:00
|
|
|
_gfxPorts = 0;
|
|
|
|
_gfxText16 = 0;
|
|
|
|
_gfxTransitions = 0;
|
|
|
|
#ifdef ENABLE_SCI32
|
2011-10-28 19:19:52 +00:00
|
|
|
_gfxControls32 = 0;
|
2011-09-03 11:50:58 +00:00
|
|
|
_gfxText32 = 0;
|
2011-02-07 12:24:09 +00:00
|
|
|
_robotDecoder = 0;
|
2010-06-28 08:18:55 +00:00
|
|
|
_gfxFrameout = 0;
|
|
|
|
_gfxPaint32 = 0;
|
2016-01-10 11:38:10 +00:00
|
|
|
_gfxPalette32 = 0;
|
2010-06-28 08:18:55 +00:00
|
|
|
#endif
|
|
|
|
|
2010-10-13 03:28:59 +00:00
|
|
|
if (hasMacIconBar())
|
2010-06-28 08:18:55 +00:00
|
|
|
_gfxMacIconBar = new GfxMacIconBar();
|
|
|
|
|
2016-01-07 02:00:28 +00:00
|
|
|
#ifdef ENABLE_SCI32
|
|
|
|
if (getSciVersion() >= SCI_VERSION_2) {
|
|
|
|
_gfxPalette32 = new GfxPalette32(_resMan, _gfxScreen);
|
|
|
|
_gfxPalette16 = _gfxPalette32;
|
|
|
|
} else {
|
|
|
|
#endif
|
|
|
|
_gfxPalette16 = new GfxPalette(_resMan, _gfxScreen);
|
|
|
|
#ifdef ENABLE_SCI32
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
_gfxCache = new GfxCache(_resMan, _gfxScreen, _gfxPalette16);
|
|
|
|
_gfxCursor = new GfxCursor(_resMan, _gfxPalette16, _gfxScreen);
|
2010-06-28 08:18:55 +00:00
|
|
|
|
|
|
|
#ifdef ENABLE_SCI32
|
|
|
|
if (getSciVersion() >= SCI_VERSION_2) {
|
|
|
|
// SCI32 graphic objects creation
|
|
|
|
_gfxCoordAdjuster = new GfxCoordAdjuster32(_gamestate->_segMan);
|
|
|
|
_gfxCursor->init(_gfxCoordAdjuster, _eventMan);
|
2013-04-18 18:14:44 +00:00
|
|
|
_gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxCoordAdjuster);
|
2016-01-07 02:00:28 +00:00
|
|
|
_gfxPaint32 = new GfxPaint32(_resMan, _gfxCoordAdjuster, _gfxScreen, _gfxPalette32);
|
2010-06-28 08:18:55 +00:00
|
|
|
_gfxPaint = _gfxPaint32;
|
2012-07-23 03:17:36 +00:00
|
|
|
_robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh);
|
2016-01-07 02:00:28 +00:00
|
|
|
_gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette32, _gfxPaint32);
|
2016-03-06 05:56:38 +00:00
|
|
|
_gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache);
|
2016-02-14 18:07:30 +00:00
|
|
|
_gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32);
|
2016-01-18 06:12:47 +00:00
|
|
|
_gfxFrameout->run();
|
2010-06-28 08:18:55 +00:00
|
|
|
} else {
|
|
|
|
#endif
|
|
|
|
// SCI0-SCI1.1 graphic objects creation
|
|
|
|
_gfxPorts = new GfxPorts(_gamestate->_segMan, _gfxScreen);
|
|
|
|
_gfxCoordAdjuster = new GfxCoordAdjuster16(_gfxPorts);
|
2011-01-22 13:01:10 +00:00
|
|
|
_gfxCursor->init(_gfxCoordAdjuster, _eventMan);
|
2013-04-18 18:14:44 +00:00
|
|
|
_gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxCoordAdjuster);
|
2016-01-07 02:00:28 +00:00
|
|
|
_gfxTransitions = new GfxTransitions(_gfxScreen, _gfxPalette16);
|
|
|
|
_gfxPaint16 = new GfxPaint16(_resMan, _gamestate->_segMan, _gfxCache, _gfxPorts, _gfxCoordAdjuster, _gfxScreen, _gfxPalette16, _gfxTransitions, _audio);
|
2010-06-28 08:18:55 +00:00
|
|
|
_gfxPaint = _gfxPaint16;
|
2016-02-23 19:17:18 +00:00
|
|
|
_gfxAnimate = new GfxAnimate(_gamestate, _scriptPatcher, _gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen, _gfxPalette16, _gfxCursor, _gfxTransitions);
|
2013-04-18 18:14:44 +00:00
|
|
|
_gfxText16 = new GfxText16(_gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen);
|
2011-10-25 22:48:20 +00:00
|
|
|
_gfxControls16 = new GfxControls16(_gamestate->_segMan, _gfxPorts, _gfxPaint16, _gfxText16, _gfxScreen);
|
2011-01-22 13:01:10 +00:00
|
|
|
_gfxMenu = new GfxMenu(_eventMan, _gamestate->_segMan, _gfxPorts, _gfxPaint16, _gfxText16, _gfxScreen, _gfxCursor);
|
2010-06-28 08:18:55 +00:00
|
|
|
|
|
|
|
_gfxMenu->reset();
|
|
|
|
|
2010-06-15 13:34:40 +00:00
|
|
|
_gfxPorts->init(_features->usesOldGfxFunctions(), _gfxPaint16, _gfxText16);
|
|
|
|
_gfxPaint16->init(_gfxAnimate, _gfxText16);
|
2013-04-18 18:14:44 +00:00
|
|
|
|
|
|
|
#ifdef ENABLE_SCI32
|
2010-06-15 13:34:40 +00:00
|
|
|
}
|
2013-04-18 18:14:44 +00:00
|
|
|
#endif
|
|
|
|
|
2010-06-15 13:34:40 +00:00
|
|
|
// Set default (EGA, amiga or resource 999) palette
|
2016-01-07 02:00:28 +00:00
|
|
|
_gfxPalette16->setDefault();
|
2010-06-15 13:34:40 +00:00
|
|
|
}
|
|
|
|
|
2010-06-10 07:32:05 +00:00
|
|
|
void SciEngine::initStackBaseWithSelector(Selector selector) {
|
|
|
|
_gamestate->stack_base[0] = make_reg(0, (uint16)selector);
|
|
|
|
_gamestate->stack_base[1] = NULL_REG;
|
|
|
|
|
|
|
|
// Register the first element on the execution stack
|
2010-08-23 20:29:13 +00:00
|
|
|
if (!send_selector(_gamestate, _gameObjectAddress, _gameObjectAddress, _gamestate->stack_base, 2, _gamestate->stack_base)) {
|
|
|
|
_console->printObject(_gameObjectAddress);
|
2010-06-10 07:32:05 +00:00
|
|
|
error("initStackBaseWithSelector: error while registering the first selector in the call stack");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void SciEngine::runGame() {
|
2010-10-31 01:45:24 +00:00
|
|
|
setTotalPlayTime(0);
|
|
|
|
|
2010-06-10 09:18:57 +00:00
|
|
|
initStackBaseWithSelector(SELECTOR(play)); // Call the play selector
|
2010-06-10 07:32:05 +00:00
|
|
|
|
|
|
|
// Attach the debug console on game startup, if requested
|
|
|
|
if (DebugMan.isDebugChannelEnabled(kDebugLevelOnStartup))
|
|
|
|
_console->attach();
|
|
|
|
|
2012-12-03 00:10:58 +00:00
|
|
|
_gamestate->_syncedAudioOptions = false;
|
|
|
|
|
2010-06-10 07:32:05 +00:00
|
|
|
do {
|
|
|
|
_gamestate->_executionStackPosChanged = false;
|
2010-07-20 23:15:07 +00:00
|
|
|
run_vm(_gamestate);
|
2010-06-10 07:32:05 +00:00
|
|
|
exitGame();
|
|
|
|
|
2011-01-22 13:01:10 +00:00
|
|
|
_gamestate->_syncedAudioOptions = true;
|
2010-12-22 13:58:28 +00:00
|
|
|
|
2010-06-10 07:32:05 +00:00
|
|
|
if (_gamestate->abortScriptProcessing == kAbortRestartGame) {
|
|
|
|
_gamestate->_segMan->resetSegMan();
|
|
|
|
initGame();
|
2010-06-10 09:18:57 +00:00
|
|
|
initStackBaseWithSelector(SELECTOR(play));
|
2011-01-27 10:49:11 +00:00
|
|
|
patchGameSaveRestore();
|
|
|
|
setLauncherLanguage();
|
2010-07-31 14:09:42 +00:00
|
|
|
_gamestate->gameIsRestarting = GAMEISRESTARTING_RESTART;
|
2012-11-06 10:58:33 +00:00
|
|
|
_gamestate->_throttleLastTime = 0;
|
2010-07-26 13:40:07 +00:00
|
|
|
if (_gfxMenu)
|
|
|
|
_gfxMenu->reset();
|
|
|
|
_gamestate->abortScriptProcessing = kAbortNone;
|
2012-12-03 00:10:58 +00:00
|
|
|
_gamestate->_syncedAudioOptions = false;
|
2010-06-10 07:32:05 +00:00
|
|
|
} else if (_gamestate->abortScriptProcessing == kAbortLoadGame) {
|
|
|
|
_gamestate->abortScriptProcessing = kAbortNone;
|
2010-07-22 12:38:48 +00:00
|
|
|
_gamestate->_executionStack.clear();
|
2010-06-10 09:18:57 +00:00
|
|
|
initStackBaseWithSelector(SELECTOR(replay));
|
2011-01-27 10:49:11 +00:00
|
|
|
patchGameSaveRestore();
|
|
|
|
setLauncherLanguage();
|
2010-07-22 12:38:48 +00:00
|
|
|
_gamestate->shrinkStackToBase();
|
2010-07-26 13:40:07 +00:00
|
|
|
_gamestate->abortScriptProcessing = kAbortNone;
|
2010-12-22 13:58:28 +00:00
|
|
|
|
|
|
|
syncSoundSettings();
|
|
|
|
syncIngameAudioOptions();
|
2012-12-03 00:10:58 +00:00
|
|
|
// Games do not set their audio settings when loading
|
2010-06-10 07:32:05 +00:00
|
|
|
} else {
|
|
|
|
break; // exit loop
|
|
|
|
}
|
|
|
|
} while (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SciEngine::exitGame() {
|
|
|
|
if (_gamestate->abortScriptProcessing != kAbortLoadGame) {
|
|
|
|
_gamestate->_executionStack.clear();
|
|
|
|
_audio->stopAllAudio();
|
2011-01-22 13:01:10 +00:00
|
|
|
_soundCmd->clearPlayList();
|
2010-06-10 07:32:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO Free parser segment here
|
|
|
|
|
|
|
|
// TODO Free scripts here
|
|
|
|
|
|
|
|
// Close all opened file handles
|
|
|
|
_gamestate->_fileHandles.clear();
|
|
|
|
_gamestate->_fileHandles.resize(5);
|
|
|
|
}
|
|
|
|
|
2009-07-03 14:22:50 +00:00
|
|
|
// Invoked by error() when a severe error occurs
|
2009-05-11 13:31:17 +00:00
|
|
|
GUI::Debugger *SciEngine::getDebugger() {
|
2009-07-07 06:53:53 +00:00
|
|
|
if (_gamestate) {
|
|
|
|
ExecStack *xs = &(_gamestate->_executionStack.back());
|
2010-10-27 19:22:37 +00:00
|
|
|
if (xs) {
|
2012-06-18 02:21:59 +00:00
|
|
|
xs->addr.pc.setOffset(_debugState.old_pc_offset);
|
2010-10-27 19:22:37 +00:00
|
|
|
xs->sp = _debugState.old_sp;
|
|
|
|
}
|
2009-07-07 06:53:53 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 23:20:33 +00:00
|
|
|
_debugState.runningStep = 0; // Stop multiple execution
|
|
|
|
_debugState.seeking = kDebugSeekNothing; // Stop special seeks
|
2009-07-03 14:22:50 +00:00
|
|
|
|
|
|
|
return _console;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used to obtain the engine's console in order to print messages to it
|
|
|
|
Console *SciEngine::getSciDebugger() {
|
2009-05-11 13:31:17 +00:00
|
|
|
return _console;
|
|
|
|
}
|
|
|
|
|
2010-06-25 16:16:29 +00:00
|
|
|
const char *SciEngine::getGameIdStr() const {
|
2016-03-08 17:53:55 +00:00
|
|
|
return _gameDescription->gameId;
|
2010-06-25 16:16:29 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 14:45:28 +00:00
|
|
|
Common::Language SciEngine::getLanguage() const {
|
2009-10-09 23:19:53 +00:00
|
|
|
return _gameDescription->language;
|
2009-02-20 14:45:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Common::Platform SciEngine::getPlatform() const {
|
2009-10-09 23:19:53 +00:00
|
|
|
return _gameDescription->platform;
|
2009-02-20 14:45:28 +00:00
|
|
|
}
|
|
|
|
|
2009-12-30 16:00:56 +00:00
|
|
|
bool SciEngine::isDemo() const {
|
2010-06-25 16:12:38 +00:00
|
|
|
return _gameDescription->flags & ADGF_DEMO;
|
2009-12-30 16:00:56 +00:00
|
|
|
}
|
|
|
|
|
2010-11-25 14:19:02 +00:00
|
|
|
bool SciEngine::isCD() const {
|
|
|
|
return _gameDescription->flags & ADGF_CD;
|
|
|
|
}
|
|
|
|
|
2016-01-22 01:01:28 +00:00
|
|
|
bool SciEngine::forceHiresGraphics() const {
|
|
|
|
return _forceHiresGraphics;
|
|
|
|
}
|
|
|
|
|
2011-03-04 20:07:52 +00:00
|
|
|
bool SciEngine::isBE() const{
|
|
|
|
switch(_gameDescription->platform) {
|
|
|
|
case Common::kPlatformAmiga:
|
|
|
|
case Common::kPlatformMacintosh:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-13 03:28:59 +00:00
|
|
|
bool SciEngine::hasMacIconBar() const {
|
2011-02-08 15:03:23 +00:00
|
|
|
return _resMan->isSci11Mac() && getSciVersion() == SCI_VERSION_1_1 &&
|
|
|
|
(getGameId() == GID_KQ6 || getGameId() == GID_FREDDYPHARKAS);
|
2010-10-13 03:28:59 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 23:41:15 +00:00
|
|
|
Common::String SciEngine::getSavegameName(int nr) const {
|
2010-11-01 16:02:28 +00:00
|
|
|
return _targetName + Common::String::format(".%03d", nr);
|
2009-02-20 23:41:15 +00:00
|
|
|
}
|
|
|
|
|
2009-02-27 01:17:24 +00:00
|
|
|
Common::String SciEngine::getSavegamePattern() const {
|
2016-01-26 15:55:38 +00:00
|
|
|
return _targetName + ".###";
|
2009-02-27 01:17:24 +00:00
|
|
|
}
|
|
|
|
|
2010-01-01 09:40:28 +00:00
|
|
|
Common::String SciEngine::getFilePrefix() const {
|
|
|
|
return _targetName;
|
|
|
|
}
|
|
|
|
|
2009-02-27 01:17:24 +00:00
|
|
|
Common::String SciEngine::wrapFilename(const Common::String &name) const {
|
2010-08-29 15:13:25 +00:00
|
|
|
return getFilePrefix() + "-" + name;
|
2009-02-27 01:17:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Common::String SciEngine::unwrapFilename(const Common::String &name) const {
|
2010-01-01 09:40:28 +00:00
|
|
|
Common::String prefix = getFilePrefix() + "-";
|
2010-08-29 15:13:25 +00:00
|
|
|
if (name.hasPrefix(prefix.c_str()))
|
2009-02-27 01:17:24 +00:00
|
|
|
return Common::String(name.c_str() + prefix.size());
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2010-08-29 15:13:25 +00:00
|
|
|
int SciEngine::inQfGImportRoom() const {
|
2010-08-29 00:17:56 +00:00
|
|
|
if (_gameId == GID_QFG2 && _gamestate->currentRoomNumber() == 805) {
|
|
|
|
// QFG2 character import screen
|
2010-08-29 15:13:25 +00:00
|
|
|
return 2;
|
2010-08-29 00:17:56 +00:00
|
|
|
} else if (_gameId == GID_QFG3 && _gamestate->currentRoomNumber() == 54) {
|
|
|
|
// QFG3 character import screen
|
2010-08-29 15:13:25 +00:00
|
|
|
return 3;
|
2010-08-29 00:17:56 +00:00
|
|
|
} else if (_gameId == GID_QFG4 && _gamestate->currentRoomNumber() == 54) {
|
2010-08-29 15:13:25 +00:00
|
|
|
return 4;
|
2010-08-29 00:17:56 +00:00
|
|
|
}
|
2010-08-29 15:13:25 +00:00
|
|
|
return 0;
|
2010-08-29 00:17:56 +00:00
|
|
|
}
|
|
|
|
|
2011-01-27 10:49:11 +00:00
|
|
|
void SciEngine::setLauncherLanguage() {
|
|
|
|
if (_gameDescription->flags & ADGF_ADDENGLISH) {
|
|
|
|
// If game is multilingual
|
2016-02-23 23:51:50 +00:00
|
|
|
Common::Language chosenLanguage = Common::parseLanguage(ConfMan.get("language"));
|
|
|
|
uint16 languageToSet = 0;
|
|
|
|
|
|
|
|
switch (chosenLanguage) {
|
|
|
|
case Common::EN_ANY:
|
2011-01-27 10:49:11 +00:00
|
|
|
// and English was selected as language
|
2016-02-23 23:51:50 +00:00
|
|
|
languageToSet = K_LANG_ENGLISH;
|
|
|
|
break;
|
|
|
|
case Common::JA_JPN: {
|
|
|
|
// Set Japanese for FM-Towns games
|
|
|
|
// KQ5 on FM-Towns has no initial language set
|
|
|
|
if (g_sci->getPlatform() == Common::kPlatformFMTowns) {
|
|
|
|
languageToSet = K_LANG_JAPANESE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (languageToSet) {
|
|
|
|
if (SELECTOR(printLang) != -1) // set text language
|
|
|
|
writeSelectorValue(_gamestate->_segMan, _gameObjectAddress, SELECTOR(printLang), languageToSet);
|
|
|
|
if (SELECTOR(parseLang) != -1) // and set parser language as well
|
|
|
|
writeSelectorValue(_gamestate->_segMan, _gameObjectAddress, SELECTOR(parseLang), languageToSet);
|
2011-01-27 10:49:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-02 19:03:43 +00:00
|
|
|
void SciEngine::pauseEngineIntern(bool pause) {
|
|
|
|
_mixer->pauseAll(pause);
|
2010-10-27 19:22:37 +00:00
|
|
|
if (_soundCmd)
|
|
|
|
_soundCmd->pauseAll(pause);
|
2009-06-02 19:03:43 +00:00
|
|
|
}
|
|
|
|
|
2010-01-12 00:51:37 +00:00
|
|
|
void SciEngine::syncSoundSettings() {
|
|
|
|
Engine::syncSoundSettings();
|
|
|
|
|
|
|
|
bool mute = false;
|
|
|
|
if (ConfMan.hasKey("mute"))
|
|
|
|
mute = ConfMan.getBool("mute");
|
|
|
|
|
|
|
|
int soundVolumeMusic = (mute ? 0 : ConfMan.getInt("music_volume"));
|
|
|
|
|
2011-01-22 13:01:10 +00:00
|
|
|
if (_gamestate && _soundCmd) {
|
2010-09-01 19:20:17 +00:00
|
|
|
int vol = (soundVolumeMusic + 1) * MUSIC_MASTERVOLUME_MAX / Audio::Mixer::kMaxMixerVolume;
|
2011-01-22 13:01:10 +00:00
|
|
|
_soundCmd->setMasterVolume(vol);
|
2010-01-12 00:51:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-08 14:40:18 +00:00
|
|
|
// used by Script Patcher. Used to find out, if Laura Bow 2/King's Quest 6 need patching for Speech+Subtitles - or not
|
2013-11-20 22:31:36 +00:00
|
|
|
bool SciEngine::speechAndSubtitlesEnabled() {
|
|
|
|
bool subtitlesOn = ConfMan.getBool("subtitles");
|
|
|
|
bool speechOn = !ConfMan.getBool("speech_mute");
|
2014-10-28 14:17:06 +00:00
|
|
|
|
2013-12-08 14:40:18 +00:00
|
|
|
if (isCD() && subtitlesOn && speechOn)
|
2013-11-20 22:31:36 +00:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-12-22 13:58:28 +00:00
|
|
|
void SciEngine::syncIngameAudioOptions() {
|
2015-12-22 00:53:19 +00:00
|
|
|
bool useGlobal90 = false;
|
2015-12-21 22:25:58 +00:00
|
|
|
|
2013-10-31 05:25:25 +00:00
|
|
|
// Sync the in-game speech/subtitles settings for SCI1.1 CD games
|
2015-12-21 22:25:58 +00:00
|
|
|
if (isCD()) {
|
|
|
|
switch (getSciVersion()) {
|
|
|
|
case SCI_VERSION_1_1:
|
2015-12-22 00:53:19 +00:00
|
|
|
// All SCI1.1 CD games use global 90
|
|
|
|
useGlobal90 = true;
|
|
|
|
break;
|
2015-12-21 22:25:58 +00:00
|
|
|
#ifdef ENABLE_SCI32
|
|
|
|
case SCI_VERSION_2:
|
2015-12-29 00:44:11 +00:00
|
|
|
case SCI_VERSION_2_1_EARLY:
|
|
|
|
case SCI_VERSION_2_1_MIDDLE:
|
|
|
|
case SCI_VERSION_2_1_LATE:
|
2015-12-22 00:53:19 +00:00
|
|
|
// Only use global 90 for some specific games, not all SCI32 games used this method
|
|
|
|
switch (_gameId) {
|
|
|
|
case GID_KQ7: // SCI2.1
|
|
|
|
case GID_GK1: // SCI2
|
|
|
|
case GID_GK2: // SCI2.1
|
|
|
|
case GID_SQ6: // SCI2.1
|
|
|
|
case GID_TORIN: // SCI2.1
|
|
|
|
case GID_QFG4: // SCI2.1
|
|
|
|
useGlobal90 = true;
|
|
|
|
break;
|
|
|
|
case GID_LSL6: // SCI2.1
|
|
|
|
// TODO: Uses gameFlags array
|
|
|
|
break;
|
|
|
|
// TODO: Unknown at the moment:
|
|
|
|
// Shivers - seems not to use global 90
|
|
|
|
// Police Quest: SWAT - unable to check
|
|
|
|
// Police Quest 4 - unable to check
|
|
|
|
// Mixed Up Mother Goose - unable to check
|
|
|
|
// Phantasmagoria - seems to use global 90, unable to check for subtitles atm
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
2015-12-21 22:25:58 +00:00
|
|
|
#endif // ENABLE_SCI32
|
2015-12-22 00:53:19 +00:00
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool subtitlesOn = ConfMan.getBool("subtitles");
|
|
|
|
bool speechOn = !ConfMan.getBool("speech_mute");
|
2015-12-21 22:25:58 +00:00
|
|
|
|
2015-12-22 00:53:19 +00:00
|
|
|
if (useGlobal90) {
|
2015-12-21 22:25:58 +00:00
|
|
|
if (subtitlesOn && !speechOn) {
|
|
|
|
_gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 1); // subtitles
|
|
|
|
} else if (!subtitlesOn && speechOn) {
|
2010-12-22 13:58:28 +00:00
|
|
|
_gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 2); // speech
|
2015-12-21 22:25:58 +00:00
|
|
|
} else if (subtitlesOn && speechOn) {
|
|
|
|
// Is it a game that supports simultaneous speech and subtitles?
|
|
|
|
switch (_gameId) {
|
|
|
|
case GID_SQ4:
|
|
|
|
case GID_FREDDYPHARKAS:
|
|
|
|
case GID_ECOQUEST:
|
|
|
|
case GID_LSL6:
|
|
|
|
case GID_LAURABOW2:
|
|
|
|
case GID_KQ6:
|
|
|
|
#ifdef ENABLE_SCI32
|
2015-12-22 00:53:19 +00:00
|
|
|
// Unsure about Gabriel Knight 2
|
2015-12-21 22:25:58 +00:00
|
|
|
case GID_KQ7: // SCI2.1
|
|
|
|
case GID_GK1: // SCI2
|
2015-12-22 00:53:19 +00:00
|
|
|
case GID_SQ6: // SCI2.1, SQ6 seems to always use subtitles anyway
|
|
|
|
case GID_TORIN: // SCI2.1
|
2015-12-21 22:25:58 +00:00
|
|
|
case GID_QFG4: // SCI2.1
|
|
|
|
#endif // ENABLE_SCI32
|
|
|
|
_gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 3); // speech + subtitles
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// Game does not support speech and subtitles, set it to speech
|
|
|
|
_gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 2); // speech
|
|
|
|
}
|
2010-12-22 13:58:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-31 05:25:25 +00:00
|
|
|
void SciEngine::updateScummVMAudioOptions() {
|
|
|
|
// Update ScummVM's speech/subtitles settings for SCI1.1 CD games,
|
|
|
|
// depending on the in-game settings
|
|
|
|
if (isCD() && getSciVersion() == SCI_VERSION_1_1) {
|
2013-11-20 22:31:36 +00:00
|
|
|
uint16 ingameSetting = _gamestate->variables[VAR_GLOBAL][90].getOffset();
|
2014-10-28 14:17:06 +00:00
|
|
|
|
2013-11-20 22:31:36 +00:00
|
|
|
switch (ingameSetting) {
|
|
|
|
case 1:
|
2013-10-31 05:25:25 +00:00
|
|
|
// subtitles
|
|
|
|
ConfMan.setBool("subtitles", true);
|
|
|
|
ConfMan.setBool("speech_mute", true);
|
2013-11-20 22:31:36 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2013-10-31 05:25:25 +00:00
|
|
|
// speech
|
|
|
|
ConfMan.setBool("subtitles", false);
|
|
|
|
ConfMan.setBool("speech_mute", false);
|
2013-11-20 22:31:36 +00:00
|
|
|
break;
|
|
|
|
case 3:
|
2013-10-31 05:25:25 +00:00
|
|
|
// speech + subtitles
|
|
|
|
ConfMan.setBool("subtitles", true);
|
|
|
|
ConfMan.setBool("speech_mute", false);
|
2013-11-20 22:31:36 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2013-10-31 05:25:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-17 18:13:30 +00:00
|
|
|
void SciEngine::loadMacExecutable() {
|
|
|
|
if (getPlatform() != Common::kPlatformMacintosh || getSciVersion() < SCI_VERSION_1_EARLY || getSciVersion() > SCI_VERSION_1_1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Common::String filename;
|
|
|
|
|
|
|
|
switch (getGameId()) {
|
|
|
|
case GID_KQ6:
|
|
|
|
filename = "King's Quest VI";
|
|
|
|
break;
|
|
|
|
case GID_FREDDYPHARKAS:
|
|
|
|
filename = "Freddy Pharkas";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filename.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!_macExecutable.open(filename) || !_macExecutable.hasResFork()) {
|
|
|
|
// KQ6/Freddy require the executable to load their icon bar palettes
|
|
|
|
if (hasMacIconBar())
|
|
|
|
error("Could not load Mac resource fork '%s'", filename.c_str());
|
2011-06-19 22:59:48 +00:00
|
|
|
|
2011-02-17 18:13:30 +00:00
|
|
|
// TODO: Show some sort of warning dialog saying they can't get any
|
|
|
|
// high-res Mac fonts, when we get to that point ;)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-07 02:00:28 +00:00
|
|
|
uint32 SciEngine::getTickCount() {
|
2016-01-14 16:54:27 +00:00
|
|
|
return g_engine->getTotalPlayTime() * 60 / 1000;
|
|
|
|
}
|
|
|
|
void SciEngine::setTickCount(const uint32 ticks) {
|
|
|
|
return g_engine->setTotalPlayTime(ticks * 1000 / 60);
|
2016-01-07 02:00:28 +00:00
|
|
|
}
|
2009-02-20 14:45:28 +00:00
|
|
|
} // End of namespace Sci
|