diff options
42 files changed, 677 insertions, 468 deletions
diff --git a/audio/decoders/adpcm.cpp b/audio/decoders/adpcm.cpp index fd97d5d109..ffb61a49c0 100644 --- a/audio/decoders/adpcm.cpp +++ b/audio/decoders/adpcm.cpp @@ -320,10 +320,11 @@ int MS_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { _decodedSamples[_decodedSampleCount++] = decodeMS(&_status.ch[0], (data >> 4) & 0x0f); _decodedSamples[_decodedSampleCount++] = decodeMS(&_status.ch[_channels - 1], data & 0x0f); } + _decodedSampleIndex = 0; } - // (1 - (count - 1)) ensures that _decodedSamples acts as a FIFO of depth 2 - buffer[samples] = _decodedSamples[1 - (_decodedSampleCount - 1)]; + // _decodedSamples acts as a FIFO of depth 2 or 4; + buffer[samples] = _decodedSamples[_decodedSampleIndex++]; _decodedSampleCount--; } diff --git a/audio/decoders/adpcm_intern.h b/audio/decoders/adpcm_intern.h index 3a2af91c90..f4a708c3fc 100644 --- a/audio/decoders/adpcm_intern.h +++ b/audio/decoders/adpcm_intern.h @@ -209,6 +209,7 @@ public: error("MS_ADPCMStream(): blockAlign isn't specified for MS ADPCM"); memset(&_status, 0, sizeof(_status)); _decodedSampleCount = 0; + _decodedSampleIndex = 0; } virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos) && (_decodedSampleCount == 0); } @@ -220,6 +221,7 @@ protected: private: uint8 _decodedSampleCount; + uint8 _decodedSampleIndex; int16 _decodedSamples[4]; }; diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp index 21345515bc..5b591e77ff 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp @@ -2047,7 +2047,7 @@ void SurfaceSdlGraphicsManager::undrawMouse() { return; if (_mouseBackup.w != 0 && _mouseBackup.h != 0) - addDirtyRect(x, y - _currentShakePos, _mouseBackup.w, _mouseBackup.h); + addDirtyRect(x, y, _mouseBackup.w, _mouseBackup.h); } void SurfaceSdlGraphicsManager::drawMouse() { @@ -2088,9 +2088,7 @@ void SurfaceSdlGraphicsManager::drawMouse() { // We draw the pre-scaled cursor image, so now we need to adjust for // scaling, shake position and aspect ratio correction manually. - if (!_overlayVisible) { - dst.y += _currentShakePos; - } + dst.y += _currentShakePos; if (_videoMode.aspectRatioCorrection && !_overlayVisible) dst.y = real2Aspect(dst.y); diff --git a/base/version.cpp b/base/version.cpp index fcb2740de9..299e4ce325 100644 --- a/base/version.cpp +++ b/base/version.cpp @@ -51,7 +51,7 @@ * header file, analog to internal_version.h, maybe called svn_rev.h or so.) * * Drawback: This only works on systems which can run suitable scripts as part - * of the build proces (so I guess Visual C++ would be out of the game here? + * of the build process (so I guess Visual C++ would be out of the game here? * I don't know VC enough to be sure). And of course it must be robust enough * to properly work in exports (i.e. release tar balls etc.). */ diff --git a/common/memstream.h b/common/memstream.h index a01973c6fa..94407f5cc9 100644 --- a/common/memstream.h +++ b/common/memstream.h @@ -157,7 +157,7 @@ public: * that grows as it's written to. */ class MemoryWriteStreamDynamic : public WriteStream { -private: +protected: uint32 _capacity; uint32 _size; byte *_ptr; diff --git a/devtools/skycpt/README b/devtools/skycpt/README index 4b303cb0e9..ec7828f35c 100644 --- a/devtools/skycpt/README +++ b/devtools/skycpt/README @@ -16,8 +16,8 @@ This program was only included in ScummVM's source tree because the Debian licen forces us to. Instead download the file from http://www.scummvm.org/ Also, please be aware that if you create your own CPT file (if it isn't exactly the same as the -one we offer for download at www.scummvm.org), it will be incompatible and the savegames produced -using the file will be incompatible with ScummVM using the normal CPT file. +one we offer for download at www.scummvm.org), it will be incompatible and the saved games +produced using the file will be incompatible with ScummVM using the normal CPT file. The incompatibility will not be detected by ScummVM, it will most probably simply crash. If you still want to waste your time by creating this file: diff --git a/engines/bbvs/dialogs.cpp b/engines/bbvs/dialogs.cpp index 1609794c73..64fa86e1ee 100644 --- a/engines/bbvs/dialogs.cpp +++ b/engines/bbvs/dialogs.cpp @@ -95,8 +95,8 @@ void MainMenu::init() { } void MainMenu::reflowLayout() { - const int screenW = g_system->getOverlayWidth(); - const int screenH = g_system->getOverlayHeight(); + const int screenW = _vm->_system->getOverlayWidth(); + const int screenH = _vm->_system->getOverlayHeight(); const int buttonWidth = screenW * 70 / 320; const int buttonHeight = screenH * 14 / 240; diff --git a/engines/bbvs/saveload.cpp b/engines/bbvs/saveload.cpp index e7725713fd..79afd112be 100644 --- a/engines/bbvs/saveload.cpp +++ b/engines/bbvs/saveload.cpp @@ -59,13 +59,13 @@ BbvsEngine::kReadSaveHeaderError BbvsEngine::readSaveHeader(Common::SeekableRead void BbvsEngine::savegame(const char *filename, const char *description) { Common::OutSaveFile *out; - if (!(out = g_system->getSavefileManager()->openForSaving(filename))) { + if (!(out = _system->getSavefileManager()->openForSaving(filename))) { warning("Can't create file '%s', game not saved", filename); return; } TimeDate curTime; - g_system->getTimeAndDate(curTime); + _system->getTimeAndDate(curTime); // Header start out->writeUint32LE(BBVS_SAVEGAME_VERSION); @@ -95,7 +95,7 @@ void BbvsEngine::savegame(const char *filename, const char *description) { void BbvsEngine::loadgame(const char *filename) { Common::InSaveFile *in; - if (!(in = g_system->getSavefileManager()->openForLoading(filename))) { + if (!(in = _system->getSavefileManager()->openForLoading(filename))) { warning("Can't open file '%s', game not loaded", filename); return; } diff --git a/engines/bbvs/videoplayer.cpp b/engines/bbvs/videoplayer.cpp index 1b721c434f..9bef02a3cc 100644 --- a/engines/bbvs/videoplayer.cpp +++ b/engines/bbvs/videoplayer.cpp @@ -73,7 +73,7 @@ void BbvsEngine::playVideo(int videoNum) { } Common::Event event; - while (g_system->getEventManager()->pollEvent(event)) { + while (_system->getEventManager()->pollEvent(event)) { if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP) skipVideo = true; diff --git a/engines/mohawk/dialogs.cpp b/engines/mohawk/dialogs.cpp index 6c6ae9e77f..8c11e3a5e9 100644 --- a/engines/mohawk/dialogs.cpp +++ b/engines/mohawk/dialogs.cpp @@ -25,7 +25,6 @@ #include "gui/gui-manager.h" #include "gui/saveload.h" -#include "gui/ThemeEngine.h" #include "gui/widget.h" #include "common/system.h" #include "common/translation.h" @@ -89,27 +88,11 @@ enum { kQuitCmd = 'QUIT' }; -#ifdef ENABLE_MYST - -MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::Dialog(0, 0, 360, 200), _vm(vm) { - // I18N: Option for fast scene switching - _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), 0, kZipCmd); - _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~T~ransitions Enabled"), 0, kTransCmd); - // I18N: Drop book page - _dropPageButton = new GUI::ButtonWidget(this, 15, 60, 100, 25, _("~D~rop Page"), 0, kDropCmd); - - // Myst ME only has maps - if (_vm->getFeatures() & GF_ME) - _showMapButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Show ~M~ap"), 0, kMapCmd); - else - _showMapButton = 0; - - // Myst demo only has a menu - if (_vm->getFeatures() & GF_DEMO) - _returnToMenuButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Main Men~u~"), 0, kMenuCmd); - else - _returnToMenuButton = 0; +#if defined(ENABLE_MYST) || defined(ENABLE_RIVEN) +MohawkOptionsDialog::MohawkOptionsDialog(MohawkEngine *vm) : + GUI::Dialog(0, 0, 360, 200), + _vm(vm) { _loadButton = new GUI::ButtonWidget(this, 245, 25, 100, 25, _("~L~oad"), 0, kLoadCmd); _saveButton = new GUI::ButtonWidget(this, 245, 60, 100, 25, _("~S~ave"), 0, kSaveCmd); new GUI::ButtonWidget(this, 245, 95, 100, 25, _("~Q~uit"), 0, kQuitCmd); @@ -121,37 +104,20 @@ MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::Dialog(0, 0, _saveDialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); } -MystOptionsDialog::~MystOptionsDialog() { +MohawkOptionsDialog::~MohawkOptionsDialog() { delete _loadDialog; delete _saveDialog; } -void MystOptionsDialog::open() { - Dialog::open(); - - _dropPageButton->setEnabled(_vm->_gameState->_globals.heldPage != 0); - - if (_showMapButton) - _showMapButton->setEnabled(_vm->_scriptParser && - _vm->_scriptParser->getMap()); - - // Return to menu button is not enabled on the menu - if (_returnToMenuButton) - _returnToMenuButton->setEnabled(_vm->_scriptParser && - _vm->getCurStack() != kDemoStack); - - // Zip mode is disabled in the demo - if (_vm->getFeatures() & GF_DEMO) - _zipModeCheckbox->setEnabled(false); - - _zipModeCheckbox->setState(_vm->_gameState->_globals.zipMode); - _transitionsCheckbox->setState(_vm->_gameState->_globals.transitions); +void MohawkOptionsDialog::open() { + GUI::Dialog::open(); _loadButton->setEnabled(_vm->canLoadGameStateCurrently()); _saveButton->setEnabled(_vm->canSaveGameStateCurrently()); } -void MystOptionsDialog::save() { + +void MohawkOptionsDialog::save() { int slot = _saveDialog->runModalWithCurrentTarget(); if (slot >= 0) { @@ -166,7 +132,7 @@ void MystOptionsDialog::save() { } } -void MystOptionsDialog::load() { +void MohawkOptionsDialog::load() { int slot = _loadDialog->runModalWithCurrentTarget(); if (slot >= 0) { @@ -175,7 +141,7 @@ void MystOptionsDialog::load() { } } -void MystOptionsDialog::reflowLayout() { +void MohawkOptionsDialog::reflowLayout() { const int screenW = g_system->getOverlayWidth(); const int screenH = g_system->getOverlayHeight(); @@ -183,7 +149,73 @@ void MystOptionsDialog::reflowLayout() { _x = (screenW - getWidth()) / 2; _y = (screenH - getHeight()) / 2; - Dialog::reflowLayout(); + GUI::Dialog::reflowLayout(); +} + + +void MohawkOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) { + switch (cmd) { + case kLoadCmd: + load(); + break; + case kSaveCmd: + save(); + break; + case GUI::kCloseCmd: + close(); + break; + default: + GUI::Dialog::handleCommand(sender, cmd, data); + } +} + +#endif + +#ifdef ENABLE_MYST + +MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : MohawkOptionsDialog(vm), _vm(vm) { + // I18N: Option for fast scene switching + _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), 0, kZipCmd); + _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~T~ransitions Enabled"), 0, kTransCmd); + // I18N: Drop book page + _dropPageButton = new GUI::ButtonWidget(this, 15, 60, 100, 25, _("~D~rop Page"), 0, kDropCmd); + + // Myst ME only has maps + if (_vm->getFeatures() & GF_ME) + _showMapButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Show ~M~ap"), 0, kMapCmd); + else + _showMapButton = 0; + + // Myst demo only has a menu + if (_vm->getFeatures() & GF_DEMO) + _returnToMenuButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Main Men~u~"), 0, kMenuCmd); + else + _returnToMenuButton = 0; +} + +MystOptionsDialog::~MystOptionsDialog() { +} + +void MystOptionsDialog::open() { + MohawkOptionsDialog::open(); + + _dropPageButton->setEnabled(_vm->_gameState->_globals.heldPage != 0); + + if (_showMapButton) + _showMapButton->setEnabled(_vm->_scriptParser && + _vm->_scriptParser->getMap()); + + // Return to menu button is not enabled on the menu + if (_returnToMenuButton) + _returnToMenuButton->setEnabled(_vm->_scriptParser && + _vm->getCurStack() != kDemoStack); + + // Zip mode is disabled in the demo + if (_vm->getFeatures() & GF_DEMO) + _zipModeCheckbox->setEnabled(false); + + _zipModeCheckbox->setState(_vm->_gameState->_globals.zipMode); + _transitionsCheckbox->setState(_vm->_gameState->_globals.transitions); } void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) { @@ -200,12 +232,6 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui _vm->_needsShowDemoMenu = true; close(); break; - case kLoadCmd: - load(); - break; - case kSaveCmd: - save(); - break; case kQuitCmd: { if (_vm->getGameType() != GType_MAKINGOF) { _vm->_needsShowCredits = true; @@ -223,11 +249,8 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui setResult(1); close(); break; - case GUI::kCloseCmd: - close(); - break; default: - GUI::Dialog::handleCommand(sender, cmd, data); + MohawkOptionsDialog::handleCommand(sender, cmd, data); } } @@ -235,19 +258,18 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui #ifdef ENABLE_RIVEN -RivenOptionsDialog::RivenOptionsDialog(MohawkEngine_Riven* vm) : GUI::OptionsDialog("", 120, 120, 360, 200), _vm(vm) { - _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 300, 15, _("~Z~ip Mode Activated"), 0, kZipCmd); - _waterEffectCheckbox = new GUI::CheckboxWidget(this, 15, 30, 300, 15, _("~W~ater Effect Enabled"), 0, kWaterCmd); - - new GUI::ButtonWidget(this, 95, 160, 120, 25, _("~O~K"), 0, GUI::kOKCmd); - new GUI::ButtonWidget(this, 225, 160, 120, 25, _("~C~ancel"), 0, GUI::kCloseCmd); +RivenOptionsDialog::RivenOptionsDialog(MohawkEngine_Riven* vm) : + MohawkOptionsDialog(vm), + _vm(vm) { + _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), 0, kZipCmd); + _waterEffectCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~W~ater Effect Enabled"), 0, kWaterCmd); } RivenOptionsDialog::~RivenOptionsDialog() { } void RivenOptionsDialog::open() { - Dialog::open(); + MohawkOptionsDialog::open(); _zipModeCheckbox->setState(_vm->_vars["azip"] != 0); _waterEffectCheckbox->setState(_vm->_vars["waterenabled"] != 0); @@ -255,17 +277,21 @@ void RivenOptionsDialog::open() { void RivenOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) { switch (cmd) { - case kZipCmd: + case GUI::kOKCmd: _vm->_vars["azip"] = _zipModeCheckbox->getState() ? 1 : 0; - break; - case kWaterCmd: _vm->_vars["waterenabled"] = _waterEffectCheckbox->getState() ? 1 : 0; + setResult(1); + close(); break; - case GUI::kCloseCmd: + case kQuitCmd: { + Common::Event eventQ; + eventQ.type = Common::EVENT_QUIT; + g_system->getEventManager()->pushEvent(eventQ); close(); break; + } default: - GUI::OptionsDialog::handleCommand(sender, cmd, data); + MohawkOptionsDialog::handleCommand(sender, cmd, data); } } diff --git a/engines/mohawk/dialogs.h b/engines/mohawk/dialogs.h index 59b3e01fb7..3cfb628f9d 100644 --- a/engines/mohawk/dialogs.h +++ b/engines/mohawk/dialogs.h @@ -28,7 +28,6 @@ #include "common/events.h" #include "common/str.h" #include "gui/dialog.h" -#include "gui/options.h" namespace GUI { class SaveLoadChooser; @@ -72,18 +71,44 @@ public: virtual void handleKeyDown(Common::KeyState state); }; +#if defined(ENABLE_MYST) || defined(ENABLE_RIVEN) + +class MohawkOptionsDialog : public GUI::Dialog { +public: + MohawkOptionsDialog(MohawkEngine *_vm); + virtual ~MohawkOptionsDialog(); + + virtual void open() override; + virtual void reflowLayout() override; + virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override; + +private: + MohawkEngine *_vm; + + GUI::ButtonWidget *_loadButton; + GUI::ButtonWidget *_saveButton; + + GUI::SaveLoadChooser *_loadDialog; + GUI::SaveLoadChooser *_saveDialog; + + void save(); + void load(); +}; + +#endif + #ifdef ENABLE_MYST class MohawkEngine_Myst; -class MystOptionsDialog : public GUI::Dialog { +class MystOptionsDialog : public MohawkOptionsDialog { public: MystOptionsDialog(MohawkEngine_Myst *vm); - ~MystOptionsDialog(); - void open(); + virtual ~MystOptionsDialog(); + + virtual void open() override; + virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); - virtual void reflowLayout() override; - virtual void handleCommand(GUI::CommandSender*, uint32, uint32); private: MohawkEngine_Myst *_vm; @@ -93,15 +118,6 @@ private: GUI::ButtonWidget *_dropPageButton; GUI::ButtonWidget *_showMapButton; GUI::ButtonWidget *_returnToMenuButton; - - GUI::ButtonWidget *_loadButton; - GUI::ButtonWidget *_saveButton; - - GUI::SaveLoadChooser *_loadDialog; - GUI::SaveLoadChooser *_saveDialog; - - void save(); - void load(); }; #endif @@ -110,15 +126,17 @@ private: class MohawkEngine_Riven; -class RivenOptionsDialog : public GUI::OptionsDialog { +class RivenOptionsDialog : public MohawkOptionsDialog { public: RivenOptionsDialog(MohawkEngine_Riven *vm); - ~RivenOptionsDialog(); - void open(); + virtual ~RivenOptionsDialog(); + + virtual void open() override; + virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override; - virtual void handleCommand(GUI::CommandSender*, uint32, uint32); private: MohawkEngine_Riven *_vm; + GUI::CheckboxWidget *_zipModeCheckbox; GUI::CheckboxWidget *_waterEffectCheckbox; }; diff --git a/engines/prince/module.mk b/engines/prince/module.mk index b1be123d4b..27bbc21700 100644 --- a/engines/prince/module.mk +++ b/engines/prince/module.mk @@ -19,7 +19,8 @@ MODULE_OBJS = \ saveload.o \ script.o \ sound.o \ - variatxt.o + variatxt.o \ + videoplayer.o # This module can be built as a plugin ifeq ($(ENABLE_PRINCE), DYNAMIC_PLUGIN) diff --git a/engines/prince/prince.cpp b/engines/prince/prince.cpp index a1386c6b16..b1a5438978 100644 --- a/engines/prince/prince.cpp +++ b/engines/prince/prince.cpp @@ -107,8 +107,6 @@ PrinceEngine::PrinceEngine(OSystem *syst, const PrinceGameDescription *gameDesc) DebugMan.enableDebugChannel("script"); memset(_audioStream, 0, sizeof(_audioStream)); - - gDebugLevel = 10; } PrinceEngine::~PrinceEngine() { @@ -226,8 +224,8 @@ void PrinceEngine::init() { error("Can't open all/databank.ptc"); PtcArchive *voices = new PtcArchive(); - if (!voices->open("data/voices/databank.ptc")) - error("Can't open data/voices/databank.ptc"); + if (!voices->open("voices/databank.ptc")) + error("Can't open voices/databank.ptc"); PtcArchive *sound = new PtcArchive(); if (!sound->open("sound/databank.ptc")) @@ -241,9 +239,12 @@ void PrinceEngine::init() { SearchMan.addSubDirectoryMatching(gameDataDir, "all"); - SearchMan.add("all", all); - SearchMan.add("voices", voices); - SearchMan.add("sound", sound); + // Prefix the archive names, so that "all" doesn't conflict with the + // "all" directory, if that happens to be named in all lower case. + // It isn't on the CD, but we should try to stay case-insensitive. + SearchMan.add("_all", all); + SearchMan.add("_voices", voices); + SearchMan.add("_sound", sound); if (getLanguage() != Common::PL_POL && getLanguage() != Common::DE_DEU) { SearchMan.add("translation", translation); } @@ -444,6 +445,7 @@ Common::Error PrinceEngine::run() { int startGameSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1; init(); if (startGameSlot == -1) { + playVideo("topware.avi"); showLogo(); } else { loadLocation(59); // load intro location - easiest way to set everything up diff --git a/engines/prince/prince.h b/engines/prince/prince.h index 82fcb152fa..5e07de691f 100644 --- a/engines/prince/prince.h +++ b/engines/prince/prince.h @@ -262,6 +262,8 @@ public: virtual Common::Error saveGameState(int slot, const Common::String &desc); virtual Common::Error loadGameState(int slot); + void playVideo(Common::String videoFilename); + static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header); Common::String generateSaveName(int slot); void writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header); diff --git a/engines/prince/videoplayer.cpp b/engines/prince/videoplayer.cpp new file mode 100644 index 0000000000..0d07dea10a --- /dev/null +++ b/engines/prince/videoplayer.cpp @@ -0,0 +1,84 @@ +/* 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. + + * 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. + + * 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. + * + */ + +#include "prince/prince.h" +#include "engines/util.h" +#include "graphics/palette.h" +#include "graphics/surface.h" +#include "video/avi_decoder.h" + +namespace Prince { + +void PrinceEngine::playVideo(Common::String videoFilename) { + // Set the correct video mode + initGraphics(640, 480, true, 0); + if (_system->getScreenFormat().bytesPerPixel == 1) { + warning("Couldn't switch to a RGB color video mode to play a video."); + return; + } + + debug(2, "Screen format: %s", _system->getScreenFormat().toString().c_str()); + + Video::VideoDecoder *videoDecoder = new Video::AVIDecoder(); + if (!videoDecoder->loadFile(videoFilename)) { + delete videoDecoder; + warning("Unable to open video %s", videoFilename.c_str()); + initGraphics(640, 480, true); + return; + } + + videoDecoder->start(); + + bool skipVideo = false; + + while (!shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { + if (videoDecoder->needsUpdate()) { + const Graphics::Surface *frame = videoDecoder->decodeNextFrame(); + if (frame) { + if (frame->format.bytesPerPixel > 1) { + Graphics::Surface *frame1 = frame->convertTo(_system->getScreenFormat()); + _system->copyRectToScreen(frame1->getPixels(), frame1->pitch, 0, 0, frame1->w, frame1->h); + frame1->free(); + delete frame1; + } else { + _system->copyRectToScreen(frame->getPixels(), frame->pitch, 0, 0, frame->w, frame->h); + } + _system->updateScreen(); + } + } + + Common::Event event; + while (_system->getEventManager()->pollEvent(event)) { + if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || + event.type == Common::EVENT_LBUTTONUP) + skipVideo = true; + } + + _system->delayMillis(10); + } + + delete videoDecoder; + + initGraphics(640, 480, true); +} + +} // End of namespace Prince diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 27ac4fac49..2c74fe4b0c 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -3094,7 +3094,10 @@ bool Console::cmdBacktrace(int argc, const char **argv) { break; case EXEC_STACK_TYPE_KERNEL: // Kernel function - debugPrintf(" %x:[%x] k%s(", i, call.debugOrigin, _engine->getKernel()->getKernelName(call.debugSelector).c_str()); + if (call.debugKernelSubFunction == -1) + debugPrintf(" %x:[%x] k%s(", i, call.debugOrigin, _engine->getKernel()->getKernelName(call.debugKernelFunction).c_str()); + else + debugPrintf(" %x:[%x] k%s(", i, call.debugOrigin, _engine->getKernel()->getKernelName(call.debugKernelFunction, call.debugKernelSubFunction).c_str()); break; case EXEC_STACK_TYPE_VARSELECTOR: diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index c920ef10e2..6b945d6f62 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -89,6 +89,7 @@ static const PlainGameDescriptor s_sciGameTitles[] = { {"ecoquest2", "EcoQuest II: Lost Secret of the Rainforest"}, {"freddypharkas", "Freddy Pharkas: Frontier Pharmacist"}, {"hoyle4", "Hoyle Classic Card Games"}, + {"inndemo", "ImagiNation Network (INN) Demo"}, {"kq6", "King's Quest VI: Heir Today, Gone Tomorrow"}, {"laurabow2", "Laura Bow 2: The Dagger of Amon Ra"}, {"qfg1vga", "Quest for Glory I: So You Want to Be a Hero"}, // Note: There was also a SCI0 version of this (further up) @@ -157,6 +158,7 @@ static const GameIdStrToEnum s_gameIdStrToEnum[] = { { "hoyle3", GID_HOYLE3 }, { "hoyle4", GID_HOYLE4 }, { "iceman", GID_ICEMAN }, + { "inndemo", GID_INNDEMO }, { "islandbrain", GID_ISLANDBRAIN }, { "jones", GID_JONES }, { "kq1sci", GID_KQ1 }, diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index 0b69aa9221..54e8abed71 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -1110,6 +1110,14 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // ImagiNation Network (INN) Demo + // SCI interpreter version 1.001.097 + {"inndemo", "", { + {"resource.000", 0, "535b1b920441ec73f42eaa4ccfd47b89", 514578}, + {"resource.map", 0, "333daf27c3e8a6d274a3e0061ed7cd5c", 1545}, + AD_LISTEND}, + Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Jones in the Fast Lane EGA - English DOS // SCI interpreter version 1.000.172 (not 100% sure FIXME) {"jones", "EGA", { diff --git a/engines/sci/engine/file.cpp b/engines/sci/engine/file.cpp index 0b1001bfda..156f6f51f7 100644 --- a/engines/sci/engine/file.cpp +++ b/engines/sci/engine/file.cpp @@ -22,6 +22,7 @@ #include "common/savefile.h" #include "common/stream.h" +#include "common/memstream.h" #include "sci/sci.h" #include "sci/engine/file.h" @@ -32,6 +33,112 @@ namespace Sci { +#ifdef ENABLE_SCI32 +/** + * A MemoryWriteStreamDynamic with additional read functionality. + * The read and write functions share a single stream position. + */ +class MemoryDynamicRWStream : public Common::MemoryWriteStreamDynamic, public Common::SeekableReadStream { +protected: + bool _eos; +public: + MemoryDynamicRWStream(DisposeAfterUse::Flag disposeMemory = DisposeAfterUse::NO) : MemoryWriteStreamDynamic(disposeMemory), _eos(false) { } + + uint32 read(void *dataPtr, uint32 dataSize); + + bool eos() const { return _eos; } + int32 pos() const { return _pos; } + int32 size() const { return _size; } + void clearErr() { _eos = false; Common::MemoryWriteStreamDynamic::clearErr(); } + bool seek(int32 offs, int whence = SEEK_SET) { return Common::MemoryWriteStreamDynamic::seek(offs, whence); } + +}; + +uint32 MemoryDynamicRWStream::read(void *dataPtr, uint32 dataSize) +{ + // Read at most as many bytes as are still available... + if (dataSize > _size - _pos) { + dataSize = _size - _pos; + _eos = true; + } + memcpy(dataPtr, _ptr, dataSize); + + _ptr += dataSize; + _pos += dataSize; + + return dataSize; +} + +/** + * A MemoryDynamicRWStream intended to re-write a file. + * It reads the contents of `inFile` in the constructor, and writes back + * the changes to `fileName` in the destructor (and when calling commit() ). + */ +class SaveFileRewriteStream : public MemoryDynamicRWStream { +public: + SaveFileRewriteStream(Common::String fileName, + Common::SeekableReadStream *inFile, + bool truncate, bool compress); + virtual ~SaveFileRewriteStream(); + + virtual uint32 write(const void *dataPtr, uint32 dataSize) { _changed = true; return MemoryDynamicRWStream::write(dataPtr, dataSize); } + + void commit(); //< Save back to disk + +protected: + Common::String _fileName; + bool _compress; + bool _changed; +}; + +SaveFileRewriteStream::SaveFileRewriteStream(Common::String fileName, + Common::SeekableReadStream *inFile, + bool truncate, + bool compress) +: MemoryDynamicRWStream(DisposeAfterUse::YES), + _fileName(fileName), _compress(compress) +{ + if (!truncate && inFile) { + unsigned int s = inFile->size(); + ensureCapacity(s); + inFile->read(_data, s); + _changed = false; + } else { + _changed = true; + } +} + +SaveFileRewriteStream::~SaveFileRewriteStream() { + commit(); +} + +void SaveFileRewriteStream::commit() { + // Write contents of buffer back to file + + if (_changed) { + Common::WriteStream *outFile = g_sci->getSaveFileManager()->openForSaving(_fileName, _compress); + outFile->write(_data, _size); + delete outFile; + _changed = false; + } +} + +#endif + +uint findFreeFileHandle(EngineState *s) { + // Find a free file handle + uint handle = 1; // Ignore _fileHandles[0] + while ((handle < s->_fileHandles.size()) && s->_fileHandles[handle].isOpen()) + handle++; + + if (handle == s->_fileHandles.size()) { + // Hit size limit => Allocate more space + s->_fileHandles.resize(s->_fileHandles.size() + 1); + } + + return handle; +} + /* * Note on how file I/O is implemented: In ScummVM, one can not create/write * arbitrary data files, simply because many of our target platforms do not @@ -91,6 +198,27 @@ reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool u break; } +#ifdef ENABLE_SCI32 + if (mode != _K_FILE_MODE_OPEN_OR_FAIL && ( + (g_sci->getGameId() == GID_PHANTASMAGORIA && filename == "phantsg.dir") || + (g_sci->getGameId() == GID_PQSWAT && filename == "swat.dat"))) { + debugC(kDebugLevelFile, " -> file_open opening %s for rewriting", wrappedName.c_str()); + + inFile = saveFileMan->openForLoading(wrappedName); + // If no matching savestate exists: fall back to reading from a regular + // file + if (!inFile) + inFile = SearchMan.createReadStreamForMember(englishName); + + SaveFileRewriteStream *stream; + stream = new SaveFileRewriteStream(wrappedName, inFile, mode == _K_FILE_MODE_CREATE, isCompressed); + + delete inFile; + + inFile = stream; + outFile = stream; + } else +#endif if (mode == _K_FILE_MODE_OPEN_OR_FAIL) { // Try to open file, abort if not possible inFile = saveFileMan->openForLoading(wrappedName); @@ -126,15 +254,7 @@ reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool u return SIGNAL_REG; } - // Find a free file handle - uint handle = 1; // Ignore _fileHandles[0] - while ((handle < s->_fileHandles.size()) && s->_fileHandles[handle].isOpen()) - handle++; - - if (handle == s->_fileHandles.size()) { - // Hit size limit => Allocate more space - s->_fileHandles.resize(s->_fileHandles.size() + 1); - } + uint handle = findFreeFileHandle(s); s->_fileHandles[handle]._in = inFile; s->_fileHandles[handle]._out = outFile; @@ -252,8 +372,12 @@ FileHandle::~FileHandle() { } void FileHandle::close() { - delete _in; - delete _out; + // NB: It is possible _in and _out are both non-null, but + // then they point to the same object. + if (_in) + delete _in; + else + delete _out; _in = 0; _out = 0; _name.clear(); @@ -365,119 +489,4 @@ reg_t DirSeeker::nextFile(SegManager *segMan) { return _outbuffer; } - -#ifdef ENABLE_SCI32 - -VirtualIndexFile::VirtualIndexFile(Common::String fileName) : _fileName(fileName), _changed(false) { - Common::SeekableReadStream *inFile = g_sci->getSaveFileManager()->openForLoading(fileName); - - _bufferSize = inFile->size(); - _buffer = new char[_bufferSize]; - inFile->read(_buffer, _bufferSize); - _ptr = _buffer; - delete inFile; -} - -VirtualIndexFile::VirtualIndexFile(uint32 initialSize) : _changed(false) { - _bufferSize = initialSize; - _buffer = new char[_bufferSize]; - _ptr = _buffer; -} - -VirtualIndexFile::~VirtualIndexFile() { - close(); - - _bufferSize = 0; - delete[] _buffer; - _buffer = 0; -} - -uint32 VirtualIndexFile::read(char *buffer, uint32 size) { - uint32 curPos = _ptr - _buffer; - uint32 finalSize = MIN<uint32>(size, _bufferSize - curPos); - char *localPtr = buffer; - - for (uint32 i = 0; i < finalSize; i++) - *localPtr++ = *_ptr++; - - return finalSize; -} - -uint32 VirtualIndexFile::write(const char *buffer, uint32 size) { - _changed = true; - uint32 curPos = _ptr - _buffer; - - // Check if the buffer needs to be resized - if (curPos + size >= _bufferSize) { - _bufferSize = curPos + size + 1; - char *tmp = _buffer; - _buffer = new char[_bufferSize]; - _ptr = _buffer + curPos; - memcpy(_buffer, tmp, _bufferSize); - delete[] tmp; - } - - for (uint32 i = 0; i < size; i++) - *_ptr++ = *buffer++; - - return size; -} - -uint32 VirtualIndexFile::readLine(char *buffer, uint32 size) { - uint32 startPos = _ptr - _buffer; - uint32 bytesRead = 0; - char *localPtr = buffer; - - // This is not a full-blown implementation of readLine, but it - // suffices for Phantasmagoria - while (startPos + bytesRead < size) { - bytesRead++; - - if (*_ptr == 0 || *_ptr == 0x0A) { - _ptr++; - *localPtr = 0; - return bytesRead; - } else { - *localPtr++ = *_ptr++; - } - } - - return bytesRead; -} - -bool VirtualIndexFile::seek(int32 offset, int whence) { - uint32 startPos = _ptr - _buffer; - assert(offset >= 0); - - switch (whence) { - case SEEK_CUR: - assert(startPos + offset < _bufferSize); - _ptr += offset; - break; - case SEEK_SET: - assert(offset < (int32)_bufferSize); - _ptr = _buffer + offset; - break; - case SEEK_END: - assert((int32)_bufferSize - offset >= 0); - _ptr = _buffer + (_bufferSize - offset); - break; - } - - return true; -} - -void VirtualIndexFile::close() { - if (_changed && !_fileName.empty()) { - Common::WriteStream *outFile = g_sci->getSaveFileManager()->openForSaving(_fileName); - outFile->write(_buffer, _bufferSize); - delete outFile; - } - - // Maintain the buffer, and seek to the beginning of it - _ptr = _buffer; -} - -#endif - } // End of namespace Sci diff --git a/engines/sci/engine/file.h b/engines/sci/engine/file.h index 54627d5228..982d7b7823 100644 --- a/engines/sci/engine/file.h +++ b/engines/sci/engine/file.h @@ -43,7 +43,6 @@ enum { #define VIRTUALFILE_HANDLE_START 32000 #define VIRTUALFILE_HANDLE_SCI32SAVE 32100 -#define PHANTASMAGORIA_SAVEGAME_INDEX "phantsg.dir" #define VIRTUALFILE_HANDLE_SCIAUDIO 32300 #define VIRTUALFILE_HANDLE_END 32300 @@ -93,50 +92,7 @@ private: void addAsVirtualFiles(Common::String title, Common::String fileMask); }; - -#ifdef ENABLE_SCI32 - -/** - * An implementation of a virtual file that supports basic read and write - * operations simultaneously. - * - * This class has been initially implemented for Phantasmagoria, which has its - * own custom save/load code. The load code keeps checking for the existence - * of the save index file and keeps closing and reopening it for each save - * slot. This is notoriously slow and clumsy, and introduces noticeable delays, - * especially for non-desktop systems. Also, its game scripts request to open - * the index file for reading and writing with the same parameters - * (SaveManager::setCurrentSave and SaveManager::getCurrentSave). Moreover, - * the game scripts reopen the index file for writing in order to update it - * and seek within it. We do not support seeking in writeable streams, and the - * fact that our saved games are ZIP files makes this operation even more - * expensive. Finally, the savegame index file is supposed to be expanded when - * a new save slot is added. - * For the aforementioned reasons, this class has been implemented, which offers - * the basic functionality needed by the game scripts in Phantasmagoria. - */ -class VirtualIndexFile { -public: - VirtualIndexFile(Common::String fileName); - VirtualIndexFile(uint32 initialSize); - ~VirtualIndexFile(); - - uint32 read(char *buffer, uint32 size); - uint32 readLine(char *buffer, uint32 size); - uint32 write(const char *buffer, uint32 size); - bool seek(int32 offset, int whence); - void close(); - -private: - char *_buffer; - uint32 _bufferSize; - char *_ptr; - - Common::String _fileName; - bool _changed; -}; - -#endif +uint findFreeFileHandle(EngineState *s); } // End of namespace Sci diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 796dea2382..2fc338b618 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -84,13 +84,19 @@ uint Kernel::getKernelNamesSize() const { } const Common::String &Kernel::getKernelName(uint number) const { - // FIXME: The following check is a temporary workaround for an issue - // leading to crashes when using the debugger's backtrace command. - if (number >= _kernelNames.size()) - return _invalid; + assert(number < _kernelFuncs.size()); return _kernelNames[number]; } +Common::String Kernel::getKernelName(uint number, uint subFunction) const { + assert(number < _kernelFuncs.size()); + const KernelFunction &kernelCall = _kernelFuncs[number]; + + assert(subFunction < kernelCall.subFunctionCount); + return kernelCall.subFunctions[subFunction].name; +} + + int Kernel::findKernelFuncPos(Common::String kernelFuncName) { for (uint32 i = 0; i < _kernelNames.size(); i++) if (_kernelNames[i] == kernelFuncName) diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index 1202982986..d95e228045 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -158,6 +158,7 @@ public: uint getKernelNamesSize() const; const Common::String &getKernelName(uint number) const; + Common::String getKernelName(uint number, uint subFunction) const; /** * Determines the selector ID of a selector by its name. diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index d604bb85d0..4508a481a0 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -29,6 +29,7 @@ #include "common/savefile.h" #include "common/system.h" #include "common/translation.h" +#include "common/memstream.h" #include "gui/saveload.h" @@ -263,19 +264,6 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) { } #ifdef ENABLE_SCI32 - if (name == PHANTASMAGORIA_SAVEGAME_INDEX) { - if (s->_virtualIndexFile) { - return make_reg(0, VIRTUALFILE_HANDLE_SCI32SAVE); - } else { - Common::String englishName = g_sci->getSciLanguageString(name, K_LANG_ENGLISH); - Common::String wrappedName = g_sci->wrapFilename(englishName); - if (!g_sci->getSaveFileManager()->listSavefiles(wrappedName).empty()) { - s->_virtualIndexFile = new VirtualIndexFile(wrappedName); - return make_reg(0, VIRTUALFILE_HANDLE_SCI32SAVE); - } - } - } - // Shivers is trying to store savegame descriptions and current spots in // separate .SG files, which are hardcoded in the scripts. // Essentially, there is a normal save file, created by the executable @@ -313,18 +301,18 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) { listSavegames(saves); int savegameNr = findSavegame(saves, slotNumber - SAVEGAMEID_OFFICIALRANGE_START); - if (!s->_virtualIndexFile) { - // Make the virtual file buffer big enough to avoid having it grow dynamically. - // 50 bytes should be more than enough. - s->_virtualIndexFile = new VirtualIndexFile(50); - } + int size = strlen(saves[savegameNr].name) + 2; + char *buf = (char *)malloc(size); + strcpy(buf, saves[savegameNr].name); + buf[size - 1] = 0; // Spot description (empty) - s->_virtualIndexFile->seek(0, SEEK_SET); - s->_virtualIndexFile->write(saves[savegameNr].name, strlen(saves[savegameNr].name)); - s->_virtualIndexFile->write("\0", 1); - s->_virtualIndexFile->write("\0", 1); // Spot description (empty) - s->_virtualIndexFile->seek(0, SEEK_SET); - return make_reg(0, VIRTUALFILE_HANDLE_SCI32SAVE); + uint handle = findFreeFileHandle(s); + + s->_fileHandles[handle]._in = new Common::MemoryReadStream((byte *)buf, size, DisposeAfterUse::YES); + s->_fileHandles[handle]._out = nullptr; + s->_fileHandles[handle]._name = ""; + + return make_reg(0, handle); } } #endif @@ -349,13 +337,6 @@ reg_t kFileIOClose(EngineState *s, int argc, reg_t *argv) { uint16 handle = argv[0].toUint16(); -#ifdef ENABLE_SCI32 - if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) { - s->_virtualIndexFile->close(); - return SIGNAL_REG; - } -#endif - if (handle >= VIRTUALFILE_HANDLE_START) { // it's a virtual handle? ignore it return SIGNAL_REG; @@ -381,17 +362,9 @@ reg_t kFileIOReadRaw(EngineState *s, int argc, reg_t *argv) { char *buf = new char[size]; debugC(kDebugLevelFile, "kFileIO(readRaw): %d, %d", handle, size); -#ifdef ENABLE_SCI32 - if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) { - bytesRead = s->_virtualIndexFile->read(buf, size); - } else { -#endif - FileHandle *f = getFileFromHandle(s, handle); - if (f) - bytesRead = f->_in->read(buf, size); -#ifdef ENABLE_SCI32 - } -#endif + FileHandle *f = getFileFromHandle(s, handle); + if (f) + bytesRead = f->_in->read(buf, size); // TODO: What happens if less bytes are read than what has // been requested? (i.e. if bytesRead is non-zero, but still @@ -411,20 +384,11 @@ reg_t kFileIOWriteRaw(EngineState *s, int argc, reg_t *argv) { s->_segMan->memcpy((byte *)buf, argv[1], size); debugC(kDebugLevelFile, "kFileIO(writeRaw): %d, %d", handle, size); -#ifdef ENABLE_SCI32 - if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) { - s->_virtualIndexFile->write(buf, size); + FileHandle *f = getFileFromHandle(s, handle); + if (f) { + f->_out->write(buf, size); success = true; - } else { -#endif - FileHandle *f = getFileFromHandle(s, handle); - if (f) { - f->_out->write(buf, size); - success = true; - } -#ifdef ENABLE_SCI32 } -#endif delete[] buf; if (success) @@ -463,13 +427,6 @@ reg_t kFileIOUnlink(EngineState *s, int argc, reg_t *argv) { const Common::String wrappedName = g_sci->wrapFilename(name); result = saveFileMan->removeSavefile(wrappedName); } - -#ifdef ENABLE_SCI32 - if (name == PHANTASMAGORIA_SAVEGAME_INDEX) { - delete s->_virtualIndexFile; - s->_virtualIndexFile = 0; - } -#endif } else { const Common::String wrappedName = g_sci->wrapFilename(name); result = saveFileMan->removeSavefile(wrappedName); @@ -488,12 +445,7 @@ reg_t kFileIOReadString(EngineState *s, int argc, reg_t *argv) { debugC(kDebugLevelFile, "kFileIO(readString): %d, %d", handle, maxsize); uint32 bytesRead; -#ifdef ENABLE_SCI32 - if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) - bytesRead = s->_virtualIndexFile->readLine(buf, maxsize); - else -#endif - bytesRead = fgets_wrapper(s, buf, maxsize, handle); + bytesRead = fgets_wrapper(s, buf, maxsize, handle); s->_segMan->memcpy(argv[0], (const byte*)buf, maxsize); delete[] buf; @@ -520,13 +472,6 @@ reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) { return NULL_REG; } -#ifdef ENABLE_SCI32 - if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) { - s->_virtualIndexFile->write(str.c_str(), str.size()); - return NULL_REG; - } -#endif - FileHandle *f = getFileFromHandle(s, handle); if (f) { @@ -547,11 +492,6 @@ reg_t kFileIOSeek(EngineState *s, int argc, reg_t *argv) { uint16 whence = argv[2].toUint16(); debugC(kDebugLevelFile, "kFileIO(seek): %d, %d, %d", handle, offset, whence); -#ifdef ENABLE_SCI32 - if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) - return make_reg(0, s->_virtualIndexFile->seek(offset, whence)); -#endif - FileHandle *f = getFileFromHandle(s, handle); if (f && f->_in) { @@ -591,14 +531,6 @@ reg_t kFileIOFindNext(EngineState *s, int argc, reg_t *argv) { reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) { Common::String name = s->_segMan->getString(argv[0]); -#ifdef ENABLE_SCI32 - // Cache the file existence result for the Phantasmagoria - // save index file, as the game scripts keep checking for - // its existence. - if (name == PHANTASMAGORIA_SAVEGAME_INDEX && s->_virtualIndexFile) - return TRUE_REG; -#endif - bool exists = false; if (g_sci->getGameId() == GID_PEPPER) { @@ -611,6 +543,9 @@ reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) { return NULL_REG; } + // TODO: It may apparently be worth caching the existence of + // phantsg.dir, and possibly even keeping it open persistently + // Check for regular file exists = Common::File::exists(name); diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index 0a5f26476f..065625f85f 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -605,18 +605,28 @@ reg_t kEmpty(EngineState *s, int argc, reg_t *argv) { reg_t kStub(EngineState *s, int argc, reg_t *argv) { Kernel *kernel = g_sci->getKernel(); int kernelCallNr = -1; + int kernelSubCallNr = -1; Common::List<ExecStack>::const_iterator callIterator = s->_executionStack.end(); if (callIterator != s->_executionStack.begin()) { callIterator--; ExecStack lastCall = *callIterator; - kernelCallNr = lastCall.debugSelector; + kernelCallNr = lastCall.debugKernelFunction; + kernelSubCallNr = lastCall.debugKernelSubFunction; } - Common::String warningMsg = "Dummy function k" + kernel->getKernelName(kernelCallNr) + - Common::String::format("[%x]", kernelCallNr) + - " invoked. Params: " + - Common::String::format("%d", argc) + " ("; + Common::String warningMsg; + if (kernelSubCallNr == -1) { + warningMsg = "Dummy function k" + kernel->getKernelName(kernelCallNr) + + Common::String::format("[%x]", kernelCallNr); + } else { + warningMsg = "Dummy function k" + kernel->getKernelName(kernelCallNr, kernelSubCallNr) + + Common::String::format("[%x:%x]", kernelCallNr, kernelSubCallNr); + + } + + warningMsg += " invoked. Params: " + + Common::String::format("%d", argc) + " ("; for (int i = 0; i < argc; i++) { warningMsg += Common::String::format("%04x:%04x", PRINT_REG(argv[i])); diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp index 13c3297f90..a88c283592 100644 --- a/engines/sci/engine/script_patches.cpp +++ b/engines/sci/engine/script_patches.cpp @@ -1492,9 +1492,109 @@ static const uint16 longbowPatchShowHandCode[] = { PATCH_END }; +// When walking through the forest, arithmetic errors may occur at "random". +// The scripts try to add a value and a pointer to the object "berryBush". +// +// This is caused by a local variable overflow. +// +// The scripts create berry bush objects dynamically. The array storage for +// those bushes may hold a total of 8 bushes. But sometimes 10 bushes +// are created. This overwrites 2 additional locals in script 225 and +// those locals are used normally for value lookups. +// +// Changing the total of bushes could cause all sorts of other issues, +// that's why I rather patched the code, that uses the locals for a lookup. +// Which means it doesn't matter anymore when those locals are overwritten. +// +// Applies to at least: English PC floppy, German PC floppy (not tested), English Amiga floppy +// Responsible method: export 2 of script 225 +// Fixes bug: #6751 +static const uint16 longbowSignatureBerryBushFix[] = { + 0x89, 0x70, // lsg global[70h] + 0x35, 0x03, // ldi 03h + 0x1a, // eq? + 0x2e, SIG_UINT16(0x002d), // bt [process code] + 0x89, 0x70, // lsg global[70h] + 0x35, 0x04, // ldi 04h + 0x1a, // eq? + 0x2e, SIG_UINT16(0x0025), // bt [process code] + 0x89, 0x70, // lsg global[70h] + 0x35, 0x05, // ldi 05h + 0x1a, // eq? + 0x2e, SIG_UINT16(0x001d), // bt [process code] + 0x89, 0x70, // lsg global[70h] + 0x35, 0x06, // ldi 06h + 0x1a, // eq? + 0x2e, SIG_UINT16(0x0015), // bt [process code] + 0x89, 0x70, // lsg global[70h] + 0x35, 0x18, // ldi 18h + 0x1a, // eq? + 0x2e, SIG_UINT16(0x000d), // bt [process code] + 0x89, 0x70, // lsg global[70h] + 0x35, 0x19, // ldi 19h + 0x1a, // eq? + 0x2e, SIG_UINT16(0x0005), // bt [process code] + 0x89, 0x70, // lsg global[70h] + 0x35, 0x1a, // ldi 1Ah + 0x1a, // eq? + // jump location for the "bt" instructions + 0x30, SIG_UINT16(0x0011), // bnt [skip over follow up code, to offset 0c35] + // 55 bytes until here + 0x85, 00, // lat temp[0] + SIG_MAGICDWORD, + 0x9a, SIG_UINT16(0x0110), // lsli local[110h] -> 110h points normally to 110h / 2Bh + // 5 bytes + 0x7a, // push2 + SIG_END +}; + +static const uint16 longbowPatchBerryBushFix[] = { + PATCH_ADDTOOFFSET(+4), // keep: lsg global[70h], ldi 03h + 0x22, // lt? (global < 03h) + 0x2f, 0x42, // bt [skip over all the code directly] + 0x89, 0x70, // lsg global[70h] + 0x35, 0x06, // ldi 06h + 0x24, // le? (global <= 06h) + 0x2f, 0x0e, // bt [to kRandom code] + 0x89, 0x70, // lsg global[70h] + 0x35, 0x18, // ldi 18h + 0x22, // lt? (global < 18h) + 0x2f, 0x34, // bt [skip over all the code directly] + 0x89, 0x70, // lsg global[70h] + 0x35, 0x1a, // ldi 1Ah + 0x24, // le? (global <= 1Ah) + 0x31, 0x2d, // bnt [skip over all the code directly] + // 28 bytes, 27 bytes saved + // kRandom code + 0x85, 0x00, // lat temp[0] + 0x2f, 0x05, // bt [skip over case 0] + // temp[0] == 0 + 0x38, SIG_UINT16(0x0110), // pushi 0110h - that's what's normally at local[110h] + 0x33, 0x18, // jmp [kRandom call] + // check temp[0] further + 0x78, // push1 + 0x1a, // eq? + 0x31, 0x05, // bt [skip over case 1] + // temp[0] == 1 + 0x38, SIG_UINT16(0x002b), // pushi 002Bh - that's what's normally at local[111h] + 0x33, 0x0F, // jmp [kRandom call] + // temp[0] >= 2 + 0x8d, 00, // lst temp[0] + 0x35, 0x02, // ldi 02 + 0x04, // sub + 0x9a, SIG_UINT16(0x0112), // lsli local[112h] -> look up value in 2nd table + // this may not be needed at all and was just added for safety reasons + // waste 9 spare bytes + 0x35, 0x00, // ldi 00 + 0x35, 0x00, // ldi 00 + 0x34, PATCH_UINT16(0x0000), // ldi 0000 + PATCH_END +}; + // script, description, signature patch static const SciScriptPatcherEntry longbowSignatures[] = { { true, 210, "hand code crash", 5, longbowSignatureShowHandCode, longbowPatchShowHandCode }, + { true, 225, "arithmetic berry bush fix", 1, longbowSignatureBerryBushFix, longbowPatchBerryBushFix }, SCI_SIGNATUREENTRY_TERMINATOR }; diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index fda78317b5..2c85907628 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -70,9 +70,6 @@ static const uint16 s_halfWidthSJISMap[256] = { EngineState::EngineState(SegManager *segMan) : _segMan(segMan), -#ifdef ENABLE_SCI32 - _virtualIndexFile(0), -#endif _dirseeker() { reset(false); @@ -80,9 +77,6 @@ EngineState::EngineState(SegManager *segMan) EngineState::~EngineState() { delete _msgState; -#ifdef ENABLE_SCI32 - delete _virtualIndexFile; -#endif } void EngineState::reset(bool isRestoring) { diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index cf9a753f5c..baca4a503b 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -131,10 +131,6 @@ public: int16 _lastSaveVirtualId; // last virtual id fed to kSaveGame, if no kGetSaveFiles was called inbetween int16 _lastSaveNewId; // last newly created filename-id by kSaveGame -#ifdef ENABLE_SCI32 - VirtualIndexFile *_virtualIndexFile; -#endif - // see detection.cpp / SciEngine::loadGameState() bool _delayedRestoreGame; // boolean, that triggers delayed restore (triggered by ScummVM menu) int _delayedRestoreGameId; // the saved game id, that it supposed to get restored (triggered by ScummVM menu) diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 64e6c045db..3e12084ed6 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -239,8 +239,9 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP // Check if a breakpoint is set on this method g_sci->checkExportBreakpoint(script, pubfunct); + assert(argp[0].toUint16() == argc); // The first argument is argc ExecStack xstack(calling_obj, calling_obj, sp, argc, argp, - seg, make_reg32(seg, exportAddr), -1, pubfunct, -1, + seg, make_reg32(seg, exportAddr), -1, -1, -1, pubfunct, -1, s->_executionStack.size() - 1, EXEC_STACK_TYPE_CALL); s->_executionStack.push_back(xstack); return &(s->_executionStack.back()); @@ -312,8 +313,9 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt if (activeBreakpointTypes || DebugMan.isDebugChannelEnabled(kDebugLevelScripts)) debugSelectorCall(send_obj, selector, argc, argp, varp, funcp, s->_segMan, selectorType); + assert(argp[0].toUint16() == argc); // The first argument is argc ExecStack xstack(work_obj, send_obj, curSP, argc, argp, - 0xFFFF, curFP, selector, -1, -1, + 0xFFFF, curFP, selector, -1, -1, -1, -1, origin, stackType); if (selectorType == kSelectorVariable) @@ -335,12 +337,12 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt return s->_executionStack.empty() ? NULL : &(s->_executionStack.back()); } -static void addKernelCallToExecStack(EngineState *s, int kernelCallNr, int argc, reg_t *argv) { +static void addKernelCallToExecStack(EngineState *s, int kernelCallNr, int kernelSubCallNr, int argc, reg_t *argv) { // Add stack frame to indicate we're executing a callk. // This is useful in debugger backtraces if this // kernel function calls a script itself. ExecStack xstack(NULL_REG, NULL_REG, NULL, argc, argv - 1, 0xFFFF, make_reg32(0, 0), - kernelCallNr, -1, -1, s->_executionStack.size() - 1, EXEC_STACK_TYPE_KERNEL); + -1, kernelCallNr, kernelSubCallNr, -1, -1, s->_executionStack.size() - 1, EXEC_STACK_TYPE_KERNEL); s->_executionStack.push_back(xstack); } @@ -386,7 +388,8 @@ static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) { // Call kernel function if (!kernelCall.subFunctionCount) { - addKernelCallToExecStack(s, kernelCallNr, argc, argv); + argv[-1] = make_reg(0, argc); // The first argument is argc + addKernelCallToExecStack(s, kernelCallNr, -1, argc, argv); s->r_acc = kernelCall.function(s, argc, argv); if (kernelCall.debugLogging) @@ -444,7 +447,8 @@ static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) { } if (!kernelSubCall.function) error("[VM] k%s: subfunction ID %d requested, but not available", kernelCall.name, subId); - addKernelCallToExecStack(s, kernelCallNr, argc, argv); + argv[-1] = make_reg(0, argc); // The first argument is argc + addKernelCallToExecStack(s, kernelCallNr, subId, argc, argv); s->r_acc = kernelSubCall.function(s, argc, argv); if (kernelSubCall.debugLogging) @@ -834,14 +838,15 @@ void run_vm(EngineState *s) { int argc = (opparams[1] >> 1) // Given as offset, but we need count + 1 + s->r_rest; StackPtr call_base = s->xs->sp - argc; - s->xs->sp[1].incOffset(s->r_rest); uint32 localCallOffset = s->xs->addr.pc.getOffset() + opparams[0]; + int final_argc = (call_base->requireUint16()) + s->r_rest; + call_base[0] = make_reg(0, final_argc); // The first argument is argc ExecStack xstack(s->xs->objp, s->xs->objp, s->xs->sp, - (call_base->requireUint16()) + s->r_rest, call_base, + final_argc, call_base, s->xs->local_segment, make_reg32(s->xs->addr.pc.getSegment(), localCallOffset), - NULL_SELECTOR, -1, localCallOffset, s->_executionStack.size() - 1, + NULL_SELECTOR, -1, -1, -1, localCallOffset, s->_executionStack.size() - 1, EXEC_STACK_TYPE_CALL); s->_executionStack.push_back(xstack); diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index 514bf58b64..c41060dc32 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -93,16 +93,19 @@ struct ExecStack { SegmentId local_segment; // local variables etc - Selector debugSelector; // The selector which was used to call or -1 if not applicable - int debugExportId; // The exportId which was called or -1 if not applicable - int debugLocalCallOffset; // Local call offset or -1 if not applicable - int debugOrigin; // The stack frame position the call was made from, or -1 if it was the initial call + Selector debugSelector; // The selector which was used to call or -1 if not applicable + int debugExportId; // The exportId which was called or -1 if not applicable + int debugLocalCallOffset; // Local call offset or -1 if not applicable + int debugOrigin; // The stack frame position the call was made from, or -1 if it was the initial call + int debugKernelFunction; // The kernel function called, or -1 if not applicable + int debugKernelSubFunction; // The kernel subfunction called, or -1 if not applicable ExecStackType type; reg_t* getVarPointer(SegManager *segMan) const; ExecStack(reg_t objp_, reg_t sendp_, StackPtr sp_, int argc_, StackPtr argp_, SegmentId localsSegment_, reg32_t pc_, Selector debugSelector_, + int debugKernelFunction_, int debugKernelSubFunction_, int debugExportId_, int debugLocalCallOffset_, int debugOrigin_, ExecStackType type_) { objp = objp_; @@ -112,12 +115,13 @@ struct ExecStack { fp = sp = sp_; argc = argc_; variables_argp = argp_; - *variables_argp = make_reg(0, argc); // The first argument is argc if (localsSegment_ != 0xFFFF) local_segment = localsSegment_; else local_segment = pc_.getSegment(); debugSelector = debugSelector_; + debugKernelFunction = debugKernelFunction_; + debugKernelSubFunction = debugKernelSubFunction_; debugExportId = debugExportId_; debugLocalCallOffset = debugLocalCallOffset_; debugOrigin = debugOrigin_; diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index 073bb93983..2a2540b470 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -780,7 +780,7 @@ SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroun Common::List<ExecStack>::const_iterator callIterator = state->_executionStack.end(); while (callIterator != state->_executionStack.begin()) { callIterator--; - ExecStack loopCall = *callIterator; + const ExecStack &loopCall = *callIterator; if ((loopCall.debugSelector != -1) || (loopCall.debugExportId != -1)) { lastCall->debugSelector = loopCall.debugSelector; lastCall->debugExportId = loopCall.debugExportId; diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp index 34f1618514..4ad2a0cfa3 100644 --- a/engines/sci/event.cpp +++ b/engines/sci/event.cpp @@ -166,7 +166,7 @@ SciEvent EventManager::getScummVMEvent() { #if ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2) { - Buffer &screen = g_sci->_gfxFrameout->getCurrentBuffer(); + const Buffer &screen = g_sci->_gfxFrameout->getCurrentBuffer(); Common::Point mousePosSci = mousePos; mulru(mousePosSci, Ratio(screen.scriptWidth, screen.screenWidth), Ratio(screen.scriptHeight, screen.screenHeight)); diff --git a/engines/sci/graphics/controls32.cpp b/engines/sci/graphics/controls32.cpp index 61dfbedfc5..4cbb4541df 100644 --- a/engines/sci/graphics/controls32.cpp +++ b/engines/sci/graphics/controls32.cpp @@ -191,7 +191,8 @@ reg_t GfxControls32::kernelEditText(const reg_t controlObject) { // Consume the event now that we know it is not one of the // defocusing events above - eventManager->getSciEvent(SCI_EVENT_ANY); + if (event.type != SCI_EVENT_NONE) + eventManager->getSciEvent(SCI_EVENT_ANY); // NOTE: In the original engine, the font and bitmap were // reset here on each iteration through the loop, but it @@ -309,8 +310,7 @@ reg_t GfxControls32::kernelEditText(const reg_t controlObject) { g_sci->_gfxFrameout->frameOut(true); g_sci->getSciDebugger()->onFrame(); - g_sci->getEngineState()->speedThrottler(16); - g_sci->getEngineState()->_throttleTrigger = true; + g_sci->_gfxFrameout->throttle(); } g_sci->_gfxFrameout->deletePlane(*plane); diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index 140c27a6d7..c0feea8999 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -76,6 +76,7 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd _benchmarkingFinished(false), _throttleFrameOut(true), _showStyles(nullptr), + _throttleState(0), // TODO: Stop using _gfxScreen _currentBuffer(screen->getDisplayWidth(), screen->getDisplayHeight(), nullptr), _remapOccurred(false), @@ -1566,8 +1567,21 @@ void GfxFrameout::kernelFrameOut(const bool shouldShowBits) { frameOut(shouldShowBits); } + throttle(); +} + +void GfxFrameout::throttle() { if (_throttleFrameOut) { - g_sci->getEngineState()->speedThrottler(16); + uint8 throttleTime; + if (_throttleState == 2) { + throttleTime = 17; + _throttleState = 0; + } else { + throttleTime = 16; + ++_throttleState; + } + + g_sci->getEngineState()->speedThrottler(throttleTime); g_sci->getEngineState()->_throttleTrigger = true; } } diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h index e736872773..cc62c61d22 100644 --- a/engines/sci/graphics/frameout.h +++ b/engines/sci/graphics/frameout.h @@ -185,7 +185,7 @@ private: /** * Whether or not calls to kFrameOut should be framerate - * limited to ~60fps. + * limited to 60fps. */ bool _throttleFrameOut; @@ -304,6 +304,12 @@ public: #pragma mark Rendering private: /** + * State tracker to provide more accurate 60fps + * video throttling. + */ + uint8 _throttleState; + + /** * TODO: Documentation */ int8 _styleRanges[256]; @@ -318,7 +324,9 @@ private: Buffer _currentBuffer; /** - * TODO: Documentation + * When true, a change to the remap zone in the palette + * has occurred and screen items with remap data need to + * be redrawn. */ bool _remapOccurred; @@ -423,13 +431,19 @@ public: */ bool _palMorphIsOn; - inline Buffer &getCurrentBuffer() { + inline const Buffer &getCurrentBuffer() const { return _currentBuffer; } void kernelFrameOut(const bool showBits); /** + * Throttles the engine as necessary to maintain + * 60fps output. + */ + void throttle(); + + /** * Updates the internal screen buffer for the next * frame. If `shouldShowBits` is true, also sends the * buffer to hardware. If `eraseRect` is non-empty, diff --git a/engines/sci/graphics/screen_item32.h b/engines/sci/graphics/screen_item32.h index 2e44e418ce..caa7a9d725 100644 --- a/engines/sci/graphics/screen_item32.h +++ b/engines/sci/graphics/screen_item32.h @@ -88,15 +88,23 @@ private: Common::Rect _screenItemRect; /** - * TODO: Document + * If true, the `_insetRect` rectangle will be used + * when calculating the dimensions of the screen item + * instead of the cel's intrinsic width and height. + * + * In other words, using an inset rect means that + * the cel is cropped to the dimensions given in + * `_insetRect`. */ bool _useInsetRect; /** - * TODO: Documentation - * The insetRect is also used to describe the fill - * rectangle of a screen item that is drawn using - * CelObjColor. + * The cropping rectangle used when `_useInsetRect` + * is true. + * + * `_insetRect` is also used to describe the fill + * rectangle of a screen item with a CelObjColor + * cel. */ Common::Rect _insetRect; diff --git a/engines/sci/sci.h b/engines/sci/sci.h index 956187ce69..3216fa13b9 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -139,6 +139,7 @@ enum SciGameId { GID_HOYLE3, GID_HOYLE4, GID_ICEMAN, + GID_INNDEMO, GID_ISLANDBRAIN, GID_JONES, GID_KQ1, diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 3f34ecc2f8..487d30e840 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -354,12 +354,14 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) { pSnd->pStreamAud = Audio::makeRawStream(channelData + track->digitalSampleStart, track->digitalSampleSize - track->digitalSampleStart - endPart, track->digitalSampleRate, flags, DisposeAfterUse::NO); + assert(pSnd->pStreamAud); delete pSnd->pLoopStream; pSnd->pLoopStream = 0; pSnd->soundType = Audio::Mixer::kSFXSoundType; pSnd->hCurrentAud = Audio::SoundHandle(); pSnd->playBed = false; pSnd->overridePriority = false; + pSnd->isSample = true; } else { // play MIDI track Common::StackLock lock(_mutex); @@ -659,6 +661,7 @@ void SciMusic::soundKill(MusicEntry *pSnd) { pSnd->pStreamAud = NULL; delete pSnd->pLoopStream; pSnd->pLoopStream = 0; + pSnd->isSample = false; } _mutex.lock(); diff --git a/engines/scumm/debugger.cpp b/engines/scumm/debugger.cpp index 0ebea94608..617c2ab85f 100644 --- a/engines/scumm/debugger.cpp +++ b/engines/scumm/debugger.cpp @@ -411,14 +411,15 @@ bool ScummDebugger::Cmd_PrintActor(int argc, const char **argv) { int i; Actor *a; - debugPrintf("+---------------------------------------------------------------+\n"); - debugPrintf("|# | x | y | w | h |elev|cos|box|mov| zp|frm|scl|dir| cls |\n"); - debugPrintf("+--+----+----+---+---+----+---+---+---+---+---+---+---+---------+\n"); + debugPrintf("+----------------------------------------------------------------------------+\n"); + debugPrintf("|# | name | x | y | w | h |elev|cos|box|mov| zp|frm|scl|dir| cls |\n"); + debugPrintf("+--+------------+----+----+---+---+----+---+---+---+---+---+---+---+---------+\n"); for (i = 1; i < _vm->_numActors; i++) { a = _vm->_actors[i]; + const byte *name = _vm->getObjOrActorName(_vm->actorToObj(a->_number)); if (a->_visible) - debugPrintf("|%2d|%4d|%4d|%3d|%3d|%4d|%3d|%3d|%3d|%3d|%3d|%3d|%3d|$%08x|\n", - a->_number, a->getRealPos().x, a->getRealPos().y, a->_width, a->_bottom - a->_top, + debugPrintf("|%2d|%-12.12s|%4d|%4d|%3d|%3d|%4d|%3d|%3d|%3d|%3d|%3d|%3d|%3d|$%08x|\n", + a->_number, name, a->getRealPos().x, a->getRealPos().y, a->_width, a->_bottom - a->_top, a->getElevation(), a->_costume, a->_walkbox, a->_moving, a->_forceClip, a->_frame, a->_scalex, a->getFacing(), _vm->_classData[a->_number]); @@ -431,17 +432,18 @@ bool ScummDebugger::Cmd_PrintObjects(int argc, const char **argv) { int i; ObjectData *o; debugPrintf("Objects in current room\n"); - debugPrintf("+---------------------------------+------------+\n"); - debugPrintf("|num | x | y |width|height|state|fl| cls |\n"); - debugPrintf("+----+----+----+-----+------+-----+--+---------+\n"); + debugPrintf("+-----------------------------------------------------------+\n"); + debugPrintf("|num | name | x | y |width|height|state|fl| cls |\n"); + debugPrintf("+----+------------+----+----+-----+------+-----+--+---------+\n"); for (i = 1; i < _vm->_numLocalObjects; i++) { o = &(_vm->_objs[i]); if (o->obj_nr == 0) continue; int classData = (_vm->_game.version != 0 ? _vm->_classData[o->obj_nr] : 0); - debugPrintf("|%4d|%4d|%4d|%5d|%6d|%5d|%2d|$%08x|\n", - o->obj_nr, o->x_pos, o->y_pos, o->width, o->height, o->state, + const byte *name = _vm->getObjOrActorName(o->obj_nr); + debugPrintf("|%4d|%-12.12s|%4d|%4d|%5d|%6d|%5d|%2d|$%08x|\n", + o->obj_nr, name, o->x_pos, o->y_pos, o->width, o->height, o->state, o->fl_object_index, classData); } debugPrintf("\n"); diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp index 8a6b545bf2..9b09f426ef 100644 --- a/engines/scumm/dialogs.cpp +++ b/engines/scumm/dialogs.cpp @@ -149,8 +149,8 @@ static const ResString string_map_table_v6[] = { {91, "Unable to Find %s, (%c%d) Press Button."}, {92, "Error reading disk %c, (%c%d) Press Button."}, {93, "Game Paused. Press SPACE to Continue."}, - {94, "Are you sure you want to restart? (Y/N)"}, - {95, "Are you sure you want to quit? (Y/N)"}, + {94, "Are you sure you want to restart? (Y/N)Y"}, + {95, "Are you sure you want to quit? (Y/N)Y"}, {96, "Save"}, {97, "Load"}, {98, "Play"}, diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 40dc83c7f3..0ab36d1a96 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -1137,6 +1137,10 @@ void ScummEngine::saveOrLoad(Serializer *s) { if (s->isLoading() && s->getVersion() < VER(14)) upgradeGfxUsageBits(); + // When loading, reset the ShakePos. Fixes one part of bug #7141 + if (s->isLoading() && s->getVersion() >= VER(10)) + _system->setShakePos(0); + // When loading, move the mouse to the saved mouse position. if (s->isLoading() && s->getVersion() >= VER(20)) { updateCursor(); diff --git a/engines/sky/control.cpp b/engines/sky/control.cpp index 9f4b6c21c6..a3fef3c0cd 100644 --- a/engines/sky/control.cpp +++ b/engines/sky/control.cpp @@ -1338,13 +1338,13 @@ uint16 Control::parseSaveData(uint8 *srcBuf) { displayMessage(0, "Unknown save file revision (%d)", saveRev); return RESTORE_FAILED; } else if (saveRev < OLD_SAVEGAME_TYPE) { - displayMessage(0, "This savegame version is unsupported."); + displayMessage(0, "This saved game version is unsupported."); return RESTORE_FAILED; } LODSD(srcPos, gameVersion); if (gameVersion != SkyEngine::_systemVars.gameVersion) { if ((!SkyEngine::isCDVersion()) || (gameVersion < 365)) { // cd versions are compatible - displayMessage(NULL, "This savegame was created by\n" + displayMessage(NULL, "This saved game was created by\n" "Beneath a Steel Sky v0.0%03d\n" "It cannot be loaded by this version (v0.0%3d)", gameVersion, SkyEngine::_systemVars.gameVersion); diff --git a/po/nl_NL.po b/po/nl_NL.po index 1385e96a94..065ce2439a 100644 --- a/po/nl_NL.po +++ b/po/nl_NL.po @@ -5,17 +5,17 @@ # msgid "" msgstr "" -"Project-Id-Version: ScummVM 1.8.0git\n" +"Project-Id-Version: ScummVM 1.9.0git\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" "POT-Creation-Date: 2016-06-07 19:20+0200\n" -"PO-Revision-Date: 2016-02-21 13:05+0100\n" +"PO-Revision-Date: 2016-07-05 10:07+0200\n" "Last-Translator: Ben Castricum <scummvm@bencastricum.nl>\n" "Language-Team: Ben Castricum <scummvm@bencastricum.nl>\n" "Language: Nederlands\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.8.7\n" +"X-Generator: Poedit 1.8.8\n" "X-Poedit-SourceCharset: iso-8859-1\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -547,7 +547,7 @@ msgstr "Laad een eerder opgeslagen spel voor het geselecteerde spel." #: gui/launcher.cpp:640 msgid "~A~dd Game..." -msgstr "Spel ~T~oevoegen" +msgstr "Spel ~T~oevoegen..." #: gui/launcher.cpp:640 gui/launcher.cpp:647 msgid "Hold Shift for Mass Add" @@ -556,7 +556,7 @@ msgstr "" #: gui/launcher.cpp:642 msgid "~E~dit Game..." -msgstr "Spel ~B~ewerken" +msgstr "Spel ~B~ewerken..." #: gui/launcher.cpp:642 gui/launcher.cpp:649 msgid "Change game options" @@ -674,7 +674,7 @@ msgstr "" #: gui/massadd.cpp:266 #, c-format msgid "Scanned %d directories ..." -msgstr "%d directories doorgezocht..." +msgstr "%d directories doorgezocht ..." #: gui/massadd.cpp:269 #, c-format @@ -1062,15 +1062,15 @@ msgstr "Taal van de ScummVM GUI" #: gui/options.cpp:1239 msgid "Update check:" -msgstr "" +msgstr "Update controle:" #: gui/options.cpp:1239 msgid "How often to check ScummVM updates" -msgstr "" +msgstr "Hoe vaak checken op ScummVM updates" #: gui/options.cpp:1251 msgid "Check now" -msgstr "" +msgstr "Controleer nu" #: gui/options.cpp:1386 msgid "You have to restart ScummVM before your changes will take effect." @@ -1273,19 +1273,22 @@ msgid "" "\n" "Would you like to enable this feature?" msgstr "" +"ScummVM ondersteund nu automatische updates.\n" +"Hiervoor is wel internet toegang nodig.\n" +"\n" +"Wilt u deze functie inschakelen?" #: gui/updates-dialog.cpp:55 msgid "(You can always enable it in the options dialog on the Misc tab)" -msgstr "" +msgstr "(U kunt dit altijd inschakelen in de opties dialoog van de Misc tab)" #: gui/updates-dialog.cpp:92 -#, fuzzy msgid "Check for updates automatically" -msgstr "Controleren op updates..." +msgstr "Automatisch controleren op updates" #: gui/updates-dialog.cpp:111 msgid "Proceed" -msgstr "" +msgstr "Ga verder" #: gui/widget.cpp:335 gui/widget.cpp:337 gui/widget.cpp:343 gui/widget.cpp:345 msgid "Clear value" @@ -1417,20 +1420,19 @@ msgstr "Hercules Amber" #: common/updates.cpp:58 msgid "Daily" -msgstr "" +msgstr "Dagelijks" #: common/updates.cpp:60 msgid "Weekly" -msgstr "" +msgstr "Wekelijks" #: common/updates.cpp:62 msgid "Monthly" -msgstr "" +msgstr "Maandelijks" #: common/updates.cpp:64 -#, fuzzy msgid "<Bad value>" -msgstr "Veld leegmaken" +msgstr "<Ongeldige waarde>" #: engines/advancedDetector.cpp:334 #, c-format @@ -2377,22 +2379,20 @@ msgid "Check for Updates..." msgstr "Controleren op updates..." #: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53 -#, fuzzy msgid "Color mode" -msgstr "Kleurenblind Modus" +msgstr "Kleurenmodus" #: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54 msgid "Use color graphics" -msgstr "" +msgstr "Gebruik kleurenafbeeldingen" #: engines/adl/detection.cpp:63 msgid "Scanlines" -msgstr "" +msgstr "scanlines" #: engines/adl/detection.cpp:64 -#, fuzzy msgid "Show scanlines" -msgstr "Toon objectnamen" +msgstr "Toon scanlines" #: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70 #: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48 @@ -2433,23 +2433,26 @@ msgstr "" "bewegen en in spelmenus." #: engines/agi/detection.cpp:177 -#, fuzzy msgid "Use Hercules hires font" -msgstr "Hercules Groen" +msgstr "Gebruik Hercules hires lettertype" #: engines/agi/detection.cpp:178 msgid "Uses Hercules hires font, when font file is available." msgstr "" +"Gebruikt het Hercules hires lettertype wanneer het lettertype bestand " +"beschikbaar is." #: engines/agi/detection.cpp:187 msgid "Pause when entering commands" -msgstr "" +msgstr "Pauzeer tijdens invoeren van opdrachten" #: engines/agi/detection.cpp:188 msgid "" "Shows a command prompt window and pauses the game (like in SCI) instead of a " "real-time prompt." msgstr "" +"Toont een opdrachtpromptscherm en pauzeert het spel (zoals in SCI) in plaats " +"van een real-time prompt." #: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888 #: engines/cge/events.cpp:83 engines/cge2/events.cpp:76 @@ -2735,17 +2738,17 @@ msgstr "" "%d origneel opgeslagen spellen zijn succesvol geimporteerd in ScummVM.\n" "Als u later handmatig origineel opgeslagen spellen wilt importeren dan zult " "u de\n" -"ScummVM debug console moeten openen en het commando 'import_savefile' " +"ScummVM debug console moeten openen en de opdracht 'import_savefile' " "gebruiken.\n" "\n" #: engines/mohawk/detection.cpp:168 msgid "Play the Myst fly by movie" -msgstr "" +msgstr "Speel de Myst fly by film" #: engines/mohawk/detection.cpp:169 msgid "The Myst fly by movie was not played by the original engine." -msgstr "" +msgstr "De Myst fly by file werd niet door de originele engine afgespeeld." #. I18N: Option for fast scene switching #: engines/mohawk/dialogs.cpp:96 engines/mohawk/dialogs.cpp:239 @@ -2762,12 +2765,10 @@ msgid "~D~rop Page" msgstr "Laat Pagina ~V~allen" #: engines/mohawk/dialogs.cpp:103 -#, fuzzy msgid "Show ~M~ap" msgstr "~T~oon Map" #: engines/mohawk/dialogs.cpp:109 -#, fuzzy msgid "Main Men~u~" msgstr "~H~oofdmenu" @@ -2965,13 +2966,12 @@ msgstr "" "gouden" #: engines/scumm/detection.cpp:1340 -#, fuzzy msgid "Show Object Line" -msgstr "Toon objectnamen" +msgstr "Toon Object Regel" #: engines/scumm/detection.cpp:1341 msgid "Show the names of objects at the bottom of the screen" -msgstr "" +msgstr "Toon de namen van de objecten onderaan het scherm." #: engines/scumm/dialogs.cpp:172 #, c-format @@ -3830,12 +3830,12 @@ msgstr "Toon labels voor objecten als de muis er over zweeft" #: engines/sword25/detection.cpp:46 msgid "Use English speech" -msgstr "" +msgstr "Gebruik Engels" #: engines/sword25/detection.cpp:47 msgid "" "Use English speech instead of German for every language other than German" -msgstr "" +msgstr "Gebruik Engels in plaats van Duits voor elke taal anders dan Duits" #: engines/teenagent/resources.cpp:96 msgid "" |