diff --git a/.editorconfig b/.editorconfig index ecab03efb6c..8d595d7f0a4 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,3 +4,6 @@ indent_size = 4 trim_trailing_whitespace = true insert_final_newline = true vc_generate_documentation_comments = doxygen_slash_star + +[*.lingo] +charset = macroman diff --git a/.gitattributes b/.gitattributes index 61e6b61d038..459ec715c47 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,3 +6,4 @@ /po/uk_UA.po encoding=iso-8859-5 /po/el.po encoding=iso-8859-7 /po/he.po encoding=iso-8859-8 +*.lingo encoding=MacRoman diff --git a/.gitignore b/.gitignore index 4ae0fb64175..ce6fe3ec500 100644 --- a/.gitignore +++ b/.gitignore @@ -152,6 +152,7 @@ LLVM64/ #Ignore files generated by Visual Studio Code .vscode/ +compile_commands.json #Ignore gettext generated files /messages.mo @@ -207,9 +208,12 @@ gmon.out #Ignore Android Studio files .idea -#Ingore temporary Android project folder +#Ignore temporary Android project folder android_project +#Ignore snapcraft build artifacts +.snap + # Emacs files *~ .#* diff --git a/audio/mididrv.cpp b/audio/mididrv.cpp index 23bd783ab09..4791de5485c 100644 --- a/audio/mididrv.cpp +++ b/audio/mididrv.cpp @@ -57,6 +57,22 @@ const byte MidiDriver::_gmToMt32[128] = { 101, 103, 100, 120, 117, 113, 99, 128, 128, 128, 128, 124, 123, 128, 128, 128, // 7x }; +// These are the power-on default instruments of the Roland MT-32 family. +const byte MidiDriver::_mt32DefaultInstruments[8] = { + 0x44, 0x30, 0x5F, 0x4E, 0x29, 0x03, 0x6E, 0x7A +}; + +// These are the power-on default panning settings for channels 2-9 of the Roland MT-32 family. +// Internally, the MT-32 has 15 panning positions (0-E with 7 being center). +// This has been translated to the equivalent MIDI panning values (0-127). +// These are used for setting default panning on GM devices when using them with MT-32 data. +// Note that MT-32 panning is reversed compared to the MIDI specification. This is not reflected +// here; the driver is expected to flip these values based on the _reversePanning variable. +const byte MidiDriver::_mt32DefaultPanning[8] = { + // 7, 8, 7, 8, 4, A, 0, E + 0x40, 0x49, 0x40, 0x49, 0x25, 0x5B, 0x00, 0x7F +}; + // This is the drum map for the Roland Sound Canvas SC-55 v1.xx. It had a fallback mechanism // to correct invalid drumkit selections. Some games rely on this mechanism to select the // correct Roland GS drumkit. Use this map to emulate this mechanism. @@ -157,6 +173,9 @@ Common::String MidiDriver::getDeviceString(DeviceHandle handle, DeviceStringType MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) { // Query the selected music device (defaults to MT_AUTO device). Common::String selDevStr = ConfMan.hasKey("music_driver") ? ConfMan.get("music_driver") : Common::String("auto"); + if ((flags & MDT_PREFER_FLUID) && selDevStr == "auto") { + selDevStr = "fluidsynth"; + } DeviceHandle hdl = getDeviceHandle(selDevStr.empty() ? Common::String("auto") : selDevStr); DeviceHandle reslt = 0; @@ -431,19 +450,78 @@ MidiDriver::DeviceHandle MidiDriver::getDeviceHandle(const Common::String &ident return 0; } +void MidiDriver::initMT32(bool initForGM) { + sendMT32Reset(); + + if (initForGM) { + // Set up MT-32 for GM data. + // This is based on Roland's GM settings for MT-32. + debug("Initializing MT-32 for General MIDI data"); + + byte buffer[17]; + + // Roland MT-32 SysEx for system area + memcpy(&buffer[0], "\x41\x10\x16\x12\x10\x00", 6); + + // Set reverb parameters: + // - Mode 2 (Plate) + // - Time 3 + // - Level 4 + memcpy(&buffer[6], "\x01\x02\x03\x04\x66", 5); + sysEx(buffer, 11); + + // Set partial reserve to match SC-55 + memcpy(&buffer[6], "\x04\x08\x04\x04\x03\x03\x03\x03\x02\x02\x4C", 11); + sysEx(buffer, 17); + + // Use MIDI instrument channels 1-8 instead of 2-9 + memcpy(&buffer[6], "\x0D\x00\x01\x02\x03\x04\x05\x06\x07\x09\x3E", 11); + sysEx(buffer, 17); + + // The MT-32 has reversed stereo panning compared to the MIDI spec. + // GM does use panning as specified by the MIDI spec. + _reversePanning = true; + + int i; + + // Set default GM panning (center on all channels) + for (i = 0; i < 8; ++i) { + send((0x40 << 16) | (10 << 8) | (0xB0 | i)); + } + + // Set default GM instruments (0 on all channels). + // This is expected to be mapped to the MT-32 equivalent by the driver. + for (i = 0; i < 8; ++i) { + send((0 << 8) | (0xC0 | i)); + } + + // Set Pitch Bend Sensitivity to 2 semitones. + for (i = 0; i < 8; ++i) { + setPitchBendRange(i, 2); + } + setPitchBendRange(9, 2); + } +} + void MidiDriver::sendMT32Reset() { static const byte resetSysEx[] = { 0x41, 0x10, 0x16, 0x12, 0x7F, 0x00, 0x00, 0x01, 0x00 }; sysEx(resetSysEx, sizeof(resetSysEx)); g_system->delayMillis(100); } -void MidiDriver::sendGMReset() { - static const byte resetSysEx[] = { 0x7E, 0x7F, 0x09, 0x01 }; - sysEx(resetSysEx, sizeof(resetSysEx)); - g_system->delayMillis(100); +void MidiDriver::initGM(bool initForMT32, bool enableGS) { +// ResidualVM - not used } +void MidiDriver::sendGMReset() { +// ResidualVM - not used +} +byte MidiDriver::correctInstrumentBank(byte outputChannel, byte patchId) { +// ResidualVM - not used + return 0xFF; + +} void MidiDriver_BASE::midiDumpInit() { // ResidualVM - not used } @@ -482,6 +560,10 @@ void MidiDriver_BASE::send(byte status, byte firstOp, byte secondOp) { send(status | ((uint32)firstOp << 8) | ((uint32)secondOp << 16)); } +void MidiDriver_BASE::send(int8 source, byte status, byte firstOp, byte secondOp) { + send(source, status | ((uint32)firstOp << 8) | ((uint32)secondOp << 16)); +} + void MidiDriver::midiDriverCommonSend(uint32 b) { // ResidualVM - not used } diff --git a/audio/mididrv.h b/audio/mididrv.h index e6a2f65ede1..6c8a2f2d5db 100644 --- a/audio/mididrv.h +++ b/audio/mididrv.h @@ -25,6 +25,7 @@ #include "common/scummsys.h" #include "common/str.h" +#include "common/stream.h" #include "common/timer.h" #include "common/array.h" @@ -79,7 +80,8 @@ enum MidiDriverFlags { MDT_PC98 = 1 << 8, // FM-TOWNS: Maps to MT_PC98 MDT_MIDI = 1 << 9, // Real MIDI MDT_PREFER_MT32 = 1 << 10, // MT-32 output is preferred - MDT_PREFER_GM = 1 << 11 // GM output is preferred + MDT_PREFER_GM = 1 << 11, // GM output is preferred + MDT_PREFER_FLUID= 1 << 12 // FluidSynth driver is preferred }; /** @@ -99,6 +101,12 @@ public: */ virtual void send(uint32 b) = 0; + /** + * Send a MIDI command from a specific source. If the MIDI driver + * does not support multiple sources, the source parameter is + * ignored. + */ + virtual void send(int8 source, uint32 b) { send(b); } /** * Output a midi command to the midi stream. Convenience wrapper @@ -110,7 +118,14 @@ public: void send(byte status, byte firstOp, byte secondOp); /** - * Transmit a sysEx to the midi device. + * Send a MIDI command from a specific source. If the MIDI driver + * does not support multiple sources, the source parameter is + * ignored. + */ + void send(int8 source, byte status, byte firstOp, byte secondOp); + + /** + * Transmit a SysEx to the MIDI device. * * The given msg MUST NOT contain the usual SysEx frame, i.e. * do NOT include the leading 0xF0 and the trailing 0xF7. @@ -121,9 +136,29 @@ public: */ virtual void sysEx(const byte *msg, uint16 length) { } + /** + * Transmit a SysEx to the MIDI device and return the necessary + * delay until the next SysEx event in milliseconds. + * + * This can be used to implement an alternate delay method than the + * OSystem::delayMillis function used by most sysEx implementations. + * Note that not every driver needs a delay, or supports this method. + * In this case, 0 is returned and the driver itself will do a delay + * if necessary. + * + * For information on the SysEx data requirements, see the sysEx method. + */ + virtual uint16 sysExNoDelay(const byte *msg, uint16 length) { sysEx(msg, length); return 0; } + // TODO: Document this. virtual void metaEvent(byte type, byte *data, uint16 length) { } + /** + * Send a meta event from a specific source. If the MIDI driver + * does not support multiple sources, the source parameter is + * ignored. + */ + virtual void metaEvent(int8 source, byte type, byte *data, uint16 length) { metaEvent(type, data, length); } protected: /** @@ -207,6 +242,13 @@ public: /** Common operations to be done by all drivers on start of sysEx */ void midiDriverCommonSysEx(const byte *msg, uint16 length); +protected: + // True if stereo panning should be reversed. + bool _reversePanning; + // True if GS percussion channel volume should be scaled to match MT-32 volume. + bool _scaleGSPercussionVolumeToMT32; + // The currently selected GS instrument bank / variation for each channel. + byte _gsBank[16]; private: // If detectDevice() detects MT32 and we have a preferred MT32 device @@ -217,10 +259,16 @@ private: static bool _forceTypeMT32; public: + MidiDriver() : _reversePanning(false), + _scaleGSPercussionVolumeToMT32(false) { + memset(_gsBank, 0, sizeof(_gsBank)); + } virtual ~MidiDriver() { } static const byte _mt32ToGm[128]; static const byte _gmToMt32[128]; + static const byte _mt32DefaultInstruments[8]; + static const byte _mt32DefaultPanning[8]; // Map for correcting Roland GS drumkit numbers. static const uint8 _gsDrumkitFallbackMap[128]; @@ -273,11 +321,28 @@ public: send(0xB0 | channel, 100, 127); } + /** + * Initializes the MT-32 MIDI device. The device will be reset and, + * if the parameter is specified, set up for General MIDI data. + * @param initForGM True if the MT-32 should be initialized for GM mapping + */ + void initMT32(bool initForGM); + /** * Send a Roland MT-32 reset sysEx to the midi device. */ void sendMT32Reset(); + /** + * Initializes the General MIDI device. The device will be reset. + * If the initForMT32 parameter is specified, the device will be set up for + * MT-32 MIDI data. If the device supports Roland GS, the enableGS + * parameter can be specified for enhanced GS MT-32 compatiblity. + * @param initForMT32 True if the device should be initialized for MT-32 mapping + * @param enableGS True if the device should be initialized for GS MT-32 mapping + */ + void initGM(bool initForMT32, bool enableGS); + /** * Send a General MIDI reset sysEx to the midi device. */ @@ -294,6 +359,24 @@ public: // Channel allocation functions virtual MidiChannel *allocateChannel() = 0; virtual MidiChannel *getPercussionChannel() = 0; + + // Allow an engine to supply its own soundFont data. This stream will be destroyed after use. + virtual void setEngineSoundFont(Common::SeekableReadStream *soundFontData) { } + + // Does this driver accept soundFont data? + virtual bool acceptsSoundFontData() { return false; } + +protected: + /** + * Checks if the currently selected GS bank / instrument variation + * on the specified channel is valid for the specified patch. + * If this is not the case, the correct bank will be returned which + * can be set by sending a bank select message. If no correction is + * needed, 0xFF will be returned. + * This emulates the fallback functionality of the Roland SC-55 v1.2x, + * on which some games rely to correct wrong bank selects. + */ + byte correctInstrumentBank(byte outputChannel, byte patchId); }; class MidiChannel { diff --git a/backends/events/default/default-events.cpp b/backends/events/default/default-events.cpp index e7ccbde3f3a..3ec5ec4264c 100644 --- a/backends/events/default/default-events.cpp +++ b/backends/events/default/default-events.cpp @@ -41,7 +41,7 @@ DefaultEventManager::DefaultEventManager(Common::EventSource *boss) : _buttonState(0), _modifierState(0), _shouldQuit(false), - _shouldRTL(false), + _shouldReturnToLauncher(false), _confirmExitDialogActive(false) { assert(boss); @@ -95,9 +95,9 @@ bool DefaultEventManager::pollEvent(Common::Event &event) { event = _eventQueue.pop(); bool forwardEvent = true; - // If the backend has the kFeatureNoQuit, replace Quit event with RTL + // If the backend has the kFeatureNoQuit, replace Quit event with Return to Launcher if (event.type == Common::EVENT_QUIT && g_system->hasFeature(OSystem::kFeatureNoQuit)) - event.type = Common::EVENT_RTL; + event.type = Common::EVENT_RETURN_TO_LAUNCHER; switch (event.type) { case Common::EVENT_KEYDOWN: @@ -149,8 +149,8 @@ bool DefaultEventManager::pollEvent(Common::Event &event) { if (_shouldQuit) event.type = Common::EVENT_QUIT; - else if (_shouldRTL) - event.type = Common::EVENT_RTL; + else if (_shouldReturnToLauncher) + event.type = Common::EVENT_RETURN_TO_LAUNCHER; break; #ifdef ENABLE_VKEYBD case Common::EVENT_VIRTUAL_KEYBOARD: @@ -160,25 +160,23 @@ bool DefaultEventManager::pollEvent(Common::Event &event) { if (_vk->isDisplaying()) { _vk->close(true); } else { + PauseToken pt; if (g_engine) - g_engine->pauseEngine(true); + pt = g_engine->pauseEngine(); _vk->show(); - if (g_engine) - g_engine->pauseEngine(false); forwardEvent = false; } break; #endif - case Common::EVENT_RTL: + case Common::EVENT_RETURN_TO_LAUNCHER: if (ConfMan.getBool("confirm_exit")) { + PauseToken pt; if (g_engine) - g_engine->pauseEngine(true); + pt = g_engine->pauseEngine(); GUI::MessageDialog alert(_("Do you really want to return to the Launcher?"), _("Launcher"), _("Cancel")); - forwardEvent = _shouldRTL = (alert.runModal() == GUI::kMessageOK); - if (g_engine) - g_engine->pauseEngine(false); + forwardEvent = _shouldReturnToLauncher = (alert.runModal() == GUI::kMessageOK); } else - _shouldRTL = true; + _shouldReturnToLauncher = true; break; case Common::EVENT_MUTE: @@ -193,12 +191,14 @@ bool DefaultEventManager::pollEvent(Common::Event &event) { break; } _confirmExitDialogActive = true; - if (g_engine) - g_engine->pauseEngine(true); - GUI::MessageDialog alert(_("Do you really want to quit?"), _("Quit"), _("Cancel")); - forwardEvent = _shouldQuit = (alert.runModal() == GUI::kMessageOK); - if (g_engine) - g_engine->pauseEngine(false); + + { + PauseToken pt; + if (g_engine) + pt = g_engine->pauseEngine(); + GUI::MessageDialog alert(_("Do you really want to quit?"), _("Quit"), _("Cancel")); + forwardEvent = _shouldQuit = (alert.runModal() == GUI::kMessageOK); + } _confirmExitDialogActive = false; } else { _shouldQuit = true; diff --git a/backends/events/default/default-events.h b/backends/events/default/default-events.h index f309faf76f5..811908d9950 100644 --- a/backends/events/default/default-events.h +++ b/backends/events/default/default-events.h @@ -56,7 +56,7 @@ class DefaultEventManager : public Common::EventManager, Common::EventObserver { int _buttonState; int _modifierState; bool _shouldQuit; - bool _shouldRTL; + bool _shouldReturnToLauncher; bool _confirmExitDialogActive; public: @@ -72,9 +72,9 @@ public: virtual int getButtonState() const override { return _buttonState; } virtual int getModifierState() const override { return _modifierState; } virtual int shouldQuit() const override { return _shouldQuit; } - virtual int shouldRTL() const override { return _shouldRTL; } - virtual void resetRTL() override { _shouldRTL = false; } -#ifdef FORCE_RTL + virtual int shouldReturnToLauncher() const override { return _shouldReturnToLauncher; } + virtual void resetReturnToLauncher() override { _shouldReturnToLauncher = false; } +#ifdef FORCE_RETURN_TO_LAUNCHER virtual void resetQuit() override { _shouldQuit = false; } #endif diff --git a/backends/events/ps3sdl/ps3sdl-events.cpp b/backends/events/ps3sdl/ps3sdl-events.cpp index 2aa2adbac6b..15fe6407d18 100644 --- a/backends/events/ps3sdl/ps3sdl-events.cpp +++ b/backends/events/ps3sdl/ps3sdl-events.cpp @@ -37,9 +37,10 @@ */ void PS3SdlEventSource::preprocessEvents(SDL_Event *event) { if (event->type == SDL_APP_DIDENTERBACKGROUND) { + PauseToken pt; // XMB opened if (g_engine) - g_engine->pauseEngine(true); + pt = g_engine->pauseEngine(); for (;;) { if (!SDL_PollEvent(event)) { @@ -56,8 +57,6 @@ void PS3SdlEventSource::preprocessEvents(SDL_Event *event) { return; if (event->type == SDL_APP_DIDENTERFOREGROUND) { // XMB closed - if (g_engine) - g_engine->pauseEngine(false); return; } } diff --git a/backends/events/sdl/sdl-events.cpp b/backends/events/sdl/sdl-events.cpp index 0df457c68e6..80fbc626724 100644 --- a/backends/events/sdl/sdl-events.cpp +++ b/backends/events/sdl/sdl-events.cpp @@ -114,7 +114,7 @@ SdlEventSource::~SdlEventSource() { int SdlEventSource::mapKey(SDL_Keycode sdlKey, SDL_Keymod mod, Uint16 unicode) { Common::KeyCode key = SDLToOSystemKeycode(sdlKey); - // Keep unicode in case it's regular ASCII text or in case we didn't get a valid keycode + // Keep unicode in case it's regular ASCII text, Hebrew or in case we didn't get a valid keycode // // We need to use unicode in those cases, simply because SDL1.x passes us non-layout-adjusted keycodes. // So unicode is the only way to get layout-adjusted keys. @@ -136,6 +136,10 @@ int SdlEventSource::mapKey(SDL_Keycode sdlKey, SDL_Keymod mod, Uint16 unicode) { if (unicode > 0x7E) unicode = 0; // do not allow any characters above 0x7E } else { + // We allow Hebrew characters + if (unicode >= 0x05D0 && unicode <= 0x05EA) + return unicode; + // We must not restrict as much as when Ctrl/Alt-modifiers are active, otherwise // we wouldn't let umlauts through for SDL1. For SDL1 umlauts may set for example KEYCODE_QUOTE, KEYCODE_MINUS, etc. if (unicode > 0xFF) diff --git a/backends/fs/posix/posix-drives/posix-drives-fs-factory.cpp b/backends/fs/posix/posix-drives/posix-drives-fs-factory.cpp deleted file mode 100644 index 848d527c6b8..00000000000 --- a/backends/fs/posix/posix-drives/posix-drives-fs-factory.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* 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. - * - */ - -#if defined(POSIX) - -#define FORBIDDEN_SYMBOL_ALLOW_ALL - -#include "backends/fs/posix-drives/posix-drives-fs-factory.h" -#include "backends/fs/posix-drives/posix-drives-fs.h" - -#include - -void DrivesPOSIXFilesystemFactory::addDrive(const Common::String &name) { - _config.drives.push_back(Common::normalizePath(name, '/')); -} - -void DrivesPOSIXFilesystemFactory::configureBuffering(DrivePOSIXFilesystemNode::BufferingMode bufferingMode, uint32 bufferSize) { - _config.bufferingMode = bufferingMode; - _config.bufferSize = bufferSize; -} - -AbstractFSNode *DrivesPOSIXFilesystemFactory::makeRootFileNode() const { - return new DrivePOSIXFilesystemNode(_config); -} - -AbstractFSNode *DrivesPOSIXFilesystemFactory::makeCurrentDirectoryFileNode() const { - char buf[MAXPATHLEN]; - return getcwd(buf, MAXPATHLEN) ? new DrivePOSIXFilesystemNode(buf, _config) : nullptr; -} - -AbstractFSNode *DrivesPOSIXFilesystemFactory::makeFileNodePath(const Common::String &path) const { - assert(!path.empty()); - return new DrivePOSIXFilesystemNode(path, _config); -} - -#endif diff --git a/backends/fs/posix/posix-drives/posix-drives-fs-factory.h b/backends/fs/posix/posix-drives/posix-drives-fs-factory.h deleted file mode 100644 index 5dce588afce..00000000000 --- a/backends/fs/posix/posix-drives/posix-drives-fs-factory.h +++ /dev/null @@ -1,63 +0,0 @@ -/* 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. - * - */ - -#ifndef POSIX_DRIVES_FILESYSTEM_FACTORY_H -#define POSIX_DRIVES_FILESYSTEM_FACTORY_H - -#include "backends/fs/fs-factory.h" -#include "backends/fs/posix-drives/posix-drives-fs.h" - -/** - * A FilesystemFactory implementation for filesystems with a special - * top-level directory with hard-coded entries but that otherwise - * implement the POSIX APIs. - * - * For used with paths like these: - * - 'sdcard:/games/scummvm.ini' - * - 'hdd1:/usr/bin' - */ -class DrivesPOSIXFilesystemFactory : public FilesystemFactory { -public: - /** - * Add a drive to the top-level directory - */ - void addDrive(const Common::String &name); - - /** - * Configure file stream buffering - * - * @param bufferingMode select the buffering implementation to use - * @param bufferSize the size of the IO buffer in bytes. A buffer size of 0 means the default size should be used - */ - void configureBuffering(DrivePOSIXFilesystemNode::BufferingMode bufferingMode, uint32 bufferSize); - -protected: - // FilesystemFactory API - AbstractFSNode *makeRootFileNode() const override; - AbstractFSNode *makeCurrentDirectoryFileNode() const override; - AbstractFSNode *makeFileNodePath(const Common::String &path) const override; - -private: - DrivePOSIXFilesystemNode::Config _config; -}; - -#endif diff --git a/backends/fs/posix/posix-drives/posix-drives-fs.cpp b/backends/fs/posix/posix-drives/posix-drives-fs.cpp deleted file mode 100644 index 43297f15b14..00000000000 --- a/backends/fs/posix/posix-drives/posix-drives-fs.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* 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. - * - */ - -#if defined(POSIX) - -#define FORBIDDEN_SYMBOL_ALLOW_ALL - -#include "backends/fs/posix-drives/posix-drives-fs.h" -#include "backends/fs/posix/posix-iostream.h" - -#include "common/algorithm.h" -#include "common/bufferedstream.h" - -#include - -DrivePOSIXFilesystemNode::Config::Config() { - bufferingMode = kBufferingModeStdio; - bufferSize = 0; // Use the default stdio buffer size -} - -DrivePOSIXFilesystemNode::DrivePOSIXFilesystemNode(const Common::String &path, const Config &config) : - POSIXFilesystemNode(path), - _isPseudoRoot(false), - _config(config) { - - if (isDrive(path)) { - _isDirectory = true; - _isValid = true; - - // FIXME: Add a setting for deciding whether drive paths need to end with a slash - if (!_path.hasSuffix("/")) { - _path += "/"; - } - return; - } -} - -DrivePOSIXFilesystemNode::DrivePOSIXFilesystemNode(const Config &config) : - _isPseudoRoot(true), - _config(config) { - _isDirectory = true; - _isValid = false; -} - -void DrivePOSIXFilesystemNode::configureStream(StdioStream *stream) { - if (!stream) { - return; - } - - if (_config.bufferingMode != kBufferingModeStdio) { - // Disable stdio buffering - stream->setBufferSize(0); - } else if (_config.bufferSize) { - stream->setBufferSize(_config.bufferSize); - } -} - -Common::SeekableReadStream *DrivePOSIXFilesystemNode::createReadStream() { - PosixIoStream *readStream = PosixIoStream::makeFromPath(getPath(), false); - - configureStream(readStream); - - if (_config.bufferingMode == kBufferingModeScummVM) { - uint32 bufferSize = _config.bufferSize != 0 ? _config.bufferSize : 1024; - return Common::wrapBufferedSeekableReadStream(readStream, bufferSize, DisposeAfterUse::YES); - } - - return readStream; -} - -Common::WriteStream *DrivePOSIXFilesystemNode::createWriteStream() { - PosixIoStream *writeStream = PosixIoStream::makeFromPath(getPath(), true); - - configureStream(writeStream); - - if (_config.bufferingMode == kBufferingModeScummVM) { - uint32 bufferSize = _config.bufferSize != 0 ? _config.bufferSize : 1024; - return Common::wrapBufferedWriteStream(writeStream, bufferSize); - } - - return writeStream; -} - -DrivePOSIXFilesystemNode *DrivePOSIXFilesystemNode::getChildWithKnownType(const Common::String &n, bool isDirectoryFlag) const { - assert(_isDirectory); - - // Make sure the string contains no slashes - assert(!n.contains('/')); - - Common::String newPath(_path); - if (_path.lastChar() != '/') - newPath += '/'; - newPath += n; - - DrivePOSIXFilesystemNode *child = new DrivePOSIXFilesystemNode(_config); - child->_path = newPath; - child->_isValid = true; - child->_isPseudoRoot = false; - child->_isDirectory = isDirectoryFlag; - child->_displayName = n; - - return child; -} - -AbstractFSNode *DrivePOSIXFilesystemNode::getChild(const Common::String &n) const { - DrivePOSIXFilesystemNode *child = getChildWithKnownType(n, false); - child->setFlags(); - - return child; -} - -bool DrivePOSIXFilesystemNode::getChildren(AbstractFSList &list, AbstractFSNode::ListMode mode, bool hidden) const { - assert(_isDirectory); - - if (_isPseudoRoot) { - for (uint i = 0; i < _config.drives.size(); i++) { - list.push_back(makeNode(_config.drives[i])); - } - - return true; - } else { - DIR *dirp = opendir(_path.c_str()); - struct dirent *dp; - - if (!dirp) - return false; - - while ((dp = readdir(dirp)) != nullptr) { - // Skip 'invisible' files if necessary - if (dp->d_name[0] == '.' && !hidden) { - continue; - } - - // Skip '.' and '..' to avoid cycles - if ((dp->d_name[0] == '.' && dp->d_name[1] == 0) || (dp->d_name[0] == '.' && dp->d_name[1] == '.')) { - continue; - } - - AbstractFSNode *child = nullptr; - -#if !defined(SYSTEM_NOT_SUPPORTING_D_TYPE) - if (dp->d_type == DT_DIR || dp->d_type == DT_REG) { - child = getChildWithKnownType(dp->d_name, dp->d_type == DT_DIR); - } else -#endif - { - child = getChild(dp->d_name); - } - - // Honor the chosen mode - if ((mode == Common::FSNode::kListFilesOnly && child->isDirectory()) || - (mode == Common::FSNode::kListDirectoriesOnly && !child->isDirectory())) { - delete child; - continue; - } - - list.push_back(child); - } - - closedir(dirp); - - return true; - } -} - -AbstractFSNode *DrivePOSIXFilesystemNode::getParent() const { - if (_isPseudoRoot) { - return nullptr; - } - - if (isDrive(_path)) { - DrivePOSIXFilesystemNode *root = new DrivePOSIXFilesystemNode(_config); - return root; - } - - return POSIXFilesystemNode::getParent(); -} - -bool DrivePOSIXFilesystemNode::isDrive(const Common::String &path) const { - Common::String normalizedPath = Common::normalizePath(path, '/'); - DrivesArray::const_iterator drive = Common::find(_config.drives.begin(), _config.drives.end(), normalizedPath); - return drive != _config.drives.end(); -} - - -#endif //#if defined(POSIX) diff --git a/backends/fs/posix/posix-drives/posix-drives-fs.h b/backends/fs/posix/posix-drives/posix-drives-fs.h deleted file mode 100644 index 4396889e06e..00000000000 --- a/backends/fs/posix/posix-drives/posix-drives-fs.h +++ /dev/null @@ -1,79 +0,0 @@ -/* 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. - * - */ - -#ifndef POSIX_DRIVES_FILESYSTEM_H -#define POSIX_DRIVES_FILESYSTEM_H - -#include "backends/fs/posix/posix-fs.h" - -class StdioStream; - -/** - * POSIX file system node where the top-level directory is a hardcoded - * list of drives. - */ -class DrivePOSIXFilesystemNode : public POSIXFilesystemNode { -protected: - AbstractFSNode *makeNode(const Common::String &path) const override { - return new DrivePOSIXFilesystemNode(path, _config); - } - -public: - typedef Common::Array DrivesArray; - - enum BufferingMode { - /** IO buffering is fully disabled */ - kBufferingModeDisabled, - /** IO buffering is enabled and uses the libc implemenation */ - kBufferingModeStdio, - /** IO buffering is enabled and uses ScummVM's buffering stream wraappers */ - kBufferingModeScummVM - }; - - struct Config { - DrivesArray drives; - BufferingMode bufferingMode; - uint32 bufferSize; - - Config(); - }; - - DrivePOSIXFilesystemNode(const Common::String &path, const Config &config); - DrivePOSIXFilesystemNode(const Config &config); - - // AbstractFSNode API - Common::SeekableReadStream *createReadStream() override; - Common::WriteStream *createWriteStream() override; - AbstractFSNode *getChild(const Common::String &n) const override; - bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override; - AbstractFSNode *getParent() const override; - -private: - bool _isPseudoRoot; - const Config &_config; - - DrivePOSIXFilesystemNode *getChildWithKnownType(const Common::String &n, bool isDirectoryFlag) const; - bool isDrive(const Common::String &path) const; - void configureStream(StdioStream *stream); -}; - -#endif diff --git a/backends/graphics/sdl/sdl-graphics.cpp b/backends/graphics/sdl/sdl-graphics.cpp index 4d2c1aeebf2..27a19f16a2e 100644 --- a/backends/graphics/sdl/sdl-graphics.cpp +++ b/backends/graphics/sdl/sdl-graphics.cpp @@ -176,7 +176,7 @@ void SdlGraphicsManager::initSizeHint(const Graphics::ModeList &modes) { #endif } -bool SdlGraphicsManager::showMouse(const bool visible) { +bool SdlGraphicsManager::showMouse(bool visible) { if (visible == _cursorVisible) { return visible; } diff --git a/backends/graphics/windowed.h b/backends/graphics/windowed.h index c0331a1be18..4125a861ba1 100644 --- a/backends/graphics/windowed.h +++ b/backends/graphics/windowed.h @@ -223,7 +223,7 @@ protected: */ virtual void setSystemMousePosition(const int x, const int y) = 0; - virtual bool showMouse(const bool visible) override { + virtual bool showMouse(bool visible) override { if (_cursorVisible == visible) { return visible; } @@ -240,7 +240,7 @@ protected: * @param x The new X position of the mouse in virtual screen coordinates. * @param y The new Y position of the mouse in virtual screen coordinates. */ - void warpMouse(const int x, const int y) override { + void warpMouse(int x, int y) override { // Check active coordinate instead of window coordinate to avoid warping // the mouse if it is still within the same virtual pixel const Common::Point virtualCursor = convertWindowToVirtual(_cursorX, _cursorY); diff --git a/backends/keymapper/keymap.cpp b/backends/keymapper/keymap.cpp index 1e2d5f5faa4..8e721233332 100644 --- a/backends/keymapper/keymap.cpp +++ b/backends/keymapper/keymap.cpp @@ -124,10 +124,10 @@ const Action *Keymap::findAction(const char *id) const { return nullptr; } -Keymap::ActionArray Keymap::getMappedActions(const Event &event) const { +Keymap::KeymapMatch Keymap::getMappedActions(const Event &event, ActionArray &actions) const { // ResidualVM specific START if (event.type == EVENT_JOYAXIS_MOTION) { - return ActionArray(); + return kKeymapMatchNone; } // ResidualVM specific END @@ -136,68 +136,102 @@ Keymap::ActionArray Keymap::getMappedActions(const Event &event) const { case EVENT_KEYUP: { KeyState normalizedKeystate = KeyboardHardwareInputSet::normalizeKeyState(event.kbd); HardwareInput hardwareInput = HardwareInput::createKeyboard("", normalizedKeystate, ""); - return _hwActionMap[hardwareInput]; + actions.push_back(_hwActionMap[hardwareInput]); + if (!actions.empty()) { + return kKeymapMatchExact; + } + + if (normalizedKeystate.flags & KBD_NON_STICKY) { + // If no matching actions and non-sticky keyboard modifiers are down, + // check again for matches without the exact keyboard modifiers + for (HardwareActionMap::const_iterator itInput = _hwActionMap.begin(); itInput != _hwActionMap.end(); ++itInput) { + if (itInput->_key.type == kHardwareInputTypeKeyboard && itInput->_key.key.keycode == normalizedKeystate.keycode) { + int flags = itInput->_key.key.flags; + if (flags & KBD_NON_STICKY && (flags & normalizedKeystate.flags) == flags) { + actions.push_back(itInput->_value); + return kKeymapMatchPartial; + } + } + } + + // Lastly check again for matches no non-sticky keyboard modifiers + normalizedKeystate.flags &= ~KBD_NON_STICKY; + hardwareInput = HardwareInput::createKeyboard("", normalizedKeystate, ""); + actions.push_back(_hwActionMap[hardwareInput]); + return actions.empty() ? kKeymapMatchNone : kKeymapMatchPartial; + } + break; } case EVENT_LBUTTONDOWN: case EVENT_LBUTTONUP: { HardwareInput hardwareInput = HardwareInput::createMouse("", MOUSE_BUTTON_LEFT, ""); - return _hwActionMap[hardwareInput]; + actions.push_back(_hwActionMap[hardwareInput]); + break; } case EVENT_RBUTTONDOWN: case EVENT_RBUTTONUP: { HardwareInput hardwareInput = HardwareInput::createMouse("", MOUSE_BUTTON_RIGHT, ""); - return _hwActionMap[hardwareInput]; + actions.push_back(_hwActionMap[hardwareInput]); + break; } case EVENT_MBUTTONDOWN: case EVENT_MBUTTONUP: { HardwareInput hardwareInput = HardwareInput::createMouse("", MOUSE_BUTTON_MIDDLE, ""); - return _hwActionMap[hardwareInput]; + actions.push_back(_hwActionMap[hardwareInput]); + break; } case Common::EVENT_WHEELUP: { HardwareInput hardwareInput = HardwareInput::createMouse("", MOUSE_WHEEL_UP, ""); - return _hwActionMap[hardwareInput]; + actions.push_back(_hwActionMap[hardwareInput]); + break; } case Common::EVENT_WHEELDOWN: { HardwareInput hardwareInput = HardwareInput::createMouse("", MOUSE_WHEEL_DOWN, ""); - return _hwActionMap[hardwareInput]; + actions.push_back(_hwActionMap[hardwareInput]); + break; } case EVENT_X1BUTTONDOWN: case EVENT_X1BUTTONUP: { HardwareInput hardwareInput = HardwareInput::createMouse("", MOUSE_BUTTON_X1, ""); - return _hwActionMap[hardwareInput]; + actions.push_back(_hwActionMap[hardwareInput]); + break; } case EVENT_X2BUTTONDOWN: case EVENT_X2BUTTONUP: { HardwareInput hardwareInput = HardwareInput::createMouse("", MOUSE_BUTTON_X2, ""); - return _hwActionMap[hardwareInput]; + actions.push_back(_hwActionMap[hardwareInput]); + break; } case EVENT_JOYBUTTON_DOWN: case EVENT_JOYBUTTON_UP: { HardwareInput hardwareInput = HardwareInput::createJoystickButton("", event.joystick.button, ""); - return _hwActionMap[hardwareInput]; + actions.push_back(_hwActionMap[hardwareInput]); + break; } case EVENT_JOYAXIS_MOTION: { if (event.joystick.position != 0) { bool positiveHalf = event.joystick.position >= 0; HardwareInput hardwareInput = HardwareInput::createJoystickHalfAxis("", event.joystick.axis, positiveHalf, ""); - return _hwActionMap[hardwareInput]; + actions.push_back(_hwActionMap[hardwareInput]); } else { // Axis position zero is part of both half axes, and triggers actions bound to both - Keymap::ActionArray actions; HardwareInput hardwareInputPos = HardwareInput::createJoystickHalfAxis("", event.joystick.axis, true, ""); HardwareInput hardwareInputNeg = HardwareInput::createJoystickHalfAxis("", event.joystick.axis, false, ""); actions.push_back(_hwActionMap[hardwareInputPos]); actions.push_back(_hwActionMap[hardwareInputNeg]); - return actions; } + break; } case EVENT_CUSTOM_BACKEND_HARDWARE: { HardwareInput hardwareInput = HardwareInput::createCustom("", event.customType, ""); - return _hwActionMap[hardwareInput]; + actions.push_back(_hwActionMap[hardwareInput]); + break; } default: - return ActionArray(); + break; } + + return actions.empty() ? kKeymapMatchNone : kKeymapMatchExact; } void Keymap::setConfigDomain(ConfigManager::Domain *configDomain) { diff --git a/backends/keymapper/keymap.h b/backends/keymapper/keymap.h index 2f4d5680a2b..2db3653147c 100644 --- a/backends/keymapper/keymap.h +++ b/backends/keymapper/keymap.h @@ -72,6 +72,12 @@ public: kKeymapTypeGame }; + enum KeymapMatch { + kKeymapMatchNone, + kKeymapMatchPartial, + kKeymapMatchExact + }; + typedef Array ActionArray; Keymap(KeymapType type, const String &id, const String &description); @@ -109,9 +115,10 @@ public: /** * Find the Actions that a hardware input is mapped to * @param hardwareInput the input that is mapped to the required Action - * @return an array containing pointers to the actions + * @param actions an array containing pointers to the actions + * @return the matching status for the retieved actions */ - ActionArray getMappedActions(const Event &event) const; + KeymapMatch getMappedActions(const Event &event, ActionArray &actions) const; /** * Adds a new Action to this Map diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp index 873d25072c6..7ac7ce27804 100644 --- a/backends/keymapper/keymapper.cpp +++ b/backends/keymapper/keymapper.cpp @@ -170,13 +170,40 @@ List Keymapper::mapEvent(const Event &ev) { hardcodedEventMapping(ev); - List mappedEvents; - bool matchedAction = mapEvent(ev, _enabledKeymapType, mappedEvents); - if (!matchedAction) { - // If we found actions matching this input in the game / gui keymaps, + Keymap::ActionArray actions; + Keymap::KeymapMatch match = getMappedActions(ev, actions, _enabledKeymapType); + if (match != Keymap::kKeymapMatchExact) { + // If we found exact matching actions this input in the game / gui keymaps, // no need to look at the global keymaps. An input resulting in actions // from system and game keymaps would lead to unexpected user experience. - matchedAction = mapEvent(ev, Keymap::kKeymapTypeGlobal, mappedEvents); + Keymap::ActionArray globalActions; + match = getMappedActions(ev, globalActions, Keymap::kKeymapTypeGlobal); + if (match == Keymap::kKeymapMatchExact || actions.empty()) { + actions = globalActions; + } + } + + bool matchedAction = !actions.empty(); + List mappedEvents; + for (Keymap::ActionArray::const_iterator it = actions.begin(); it != actions.end(); it++) { + Event mappedEvent = executeAction(*it, ev); + if (mappedEvent.type == EVENT_INVALID) { + continue; + } + + // In case we mapped a mouse event to something else, we need to generate an artificial + // mouse move event so event observers can keep track of the mouse position. + // Makes it possible to reliably use the mouse position from EventManager when consuming + // custom action events. + if (isMouseEvent(ev) && !isMouseEvent(mappedEvent)) { + Event fakeMouseEvent; + fakeMouseEvent.type = EVENT_MOUSEMOVE; + fakeMouseEvent.mouse = ev.mouse; + + mappedEvents.push_back(fakeMouseEvent); + } + + mappedEvents.push_back(mappedEvent); } if (ev.type == EVENT_JOYAXIS_MOTION && ev.joystick.axis < ARRAYSIZE(_joystickAxisPreviouslyPressed)) { @@ -195,42 +222,25 @@ List Keymapper::mapEvent(const Event &ev) { return mappedEvents; } -bool Keymapper::mapEvent(const Event &ev, Keymap::KeymapType keymapType, List &mappedEvents) { - bool matchedAction = false; +Keymap::KeymapMatch Keymapper::getMappedActions(const Event &event, Keymap::ActionArray &actions, Keymap::KeymapType keymapType) const { + Keymap::KeymapMatch match = Keymap::kKeymapMatchNone; for (uint i = 0; i < _keymaps.size(); i++) { if (!_keymaps[i]->isEnabled() || _keymaps[i]->getType() != keymapType) { continue; } - Keymap::ActionArray actions = _keymaps[i]->getMappedActions(ev); - if (!actions.empty()) { - matchedAction = true; - } - - for (Keymap::ActionArray::const_iterator it = actions.begin(); it != actions.end(); it++) { - Event mappedEvent = executeAction(*it, ev); - if (mappedEvent.type == EVENT_INVALID) { - continue; - } - - // In case we mapped a mouse event to something else, we need to generate an artificial - // mouse move event so event observers can keep track of the mouse position. - // Makes it possible to reliably use the mouse position from EventManager when consuming - // custom action events. - if (isMouseEvent(ev) && !isMouseEvent(mappedEvent)) { - Event fakeMouseEvent; - fakeMouseEvent.type = EVENT_MOUSEMOVE; - fakeMouseEvent.mouse = ev.mouse; - - mappedEvents.push_back(fakeMouseEvent); - } - - mappedEvents.push_back(mappedEvent); + Keymap::ActionArray array; + Keymap::KeymapMatch match2 = _keymaps[i]->getMappedActions(event, array); + if (match2 == match) { + actions.push_back(array); + } else if (match2 > match) { + match = match2; + actions.clear(); + actions.push_back(array); } } - - return matchedAction; + return match; } Keymapper::IncomingEventType Keymapper::convertToIncomingEventType(const Event &ev) const { diff --git a/backends/keymapper/keymapper.h b/backends/keymapper/keymapper.h index 26bc90d769f..60ca0912a26 100644 --- a/backends/keymapper/keymapper.h +++ b/backends/keymapper/keymapper.h @@ -150,7 +150,7 @@ private: bool _joystickAxisPreviouslyPressed[6]; - bool mapEvent(const Event &ev, Keymap::KeymapType keymapType, List &mappedEvents); + Keymap::KeymapMatch getMappedActions(const Event &event, Keymap::ActionArray &actions, Keymap::KeymapType keymapType) const; Event executeAction(const Action *act, const Event &incomingEvent); EventType convertStartToEnd(EventType eventType); IncomingEventType convertToIncomingEventType(const Event &ev) const; diff --git a/backends/keymapper/remap-widget.cpp b/backends/keymapper/remap-widget.cpp index f86cf44eef5..327e02c0a5e 100644 --- a/backends/keymapper/remap-widget.cpp +++ b/backends/keymapper/remap-widget.cpp @@ -274,7 +274,7 @@ void RemapWidget::refreshKeymap() { ActionRow &row = _actions[i]; if (!row.actionText) { - row.actionText = new GUI::StaticTextWidget(widgetsBoss(), 0, 0, 0, 0, "", Graphics::kTextAlignLeft, nullptr, GUI::ThemeEngine::kFontStyleNormal); + row.actionText = new GUI::StaticTextWidget(widgetsBoss(), 0, 0, 0, 0, "", Graphics::kTextAlignStart, nullptr, GUI::ThemeEngine::kFontStyleNormal); row.actionText->setLabel(row.action->description); row.keyButton = new GUI::DropdownButtonWidget(widgetsBoss(), 0, 0, 0, 0, "", nullptr, kRemapCmd + i); @@ -303,7 +303,7 @@ void RemapWidget::refreshKeymap() { KeymapTitleRow &keymapTitle = _keymapSeparators[row.keymap]; if (!keymapTitle.descriptionText) { - keymapTitle.descriptionText = new GUI::StaticTextWidget(widgetsBoss(), 0, 0, 0, 0, row.keymap->getDescription(), Graphics::kTextAlignLeft); + keymapTitle.descriptionText = new GUI::StaticTextWidget(widgetsBoss(), 0, 0, 0, 0, row.keymap->getDescription(), Graphics::kTextAlignStart); keymapTitle.resetButton = new GUI::ButtonWidget(widgetsBoss(), 0, 0, 0, 0, "", nullptr, kResetKeymapCmd + i); // I18N: Button to reset keymap mappings to defaults diff --git a/backends/mixer/sdl/sdl-mixer.cpp b/backends/mixer/sdl/sdl-mixer.cpp index 2a46d877b22..7e59121fe3c 100644 --- a/backends/mixer/sdl/sdl-mixer.cpp +++ b/backends/mixer/sdl/sdl-mixer.cpp @@ -146,14 +146,12 @@ static uint32 roundDownPowerOfTwo(uint32 samples) { SDL_AudioSpec SdlMixerManager::getAudioSpec(uint32 outputRate) { SDL_AudioSpec desired; - const char *const appDomain = Common::ConfigManager::kApplicationDomain; - - // There was once a GUI option for this, but it was never used; - // configurability is retained for advanced users only who wish to modify - // their ScummVM config file directly + // There was once a GUI option for this, which was removed. Configurability + // is retained for advanced users only who wish to use the commandline + // option (--output-rate) or modify their ScummVM config file directly. uint32 freq = 0; - if (ConfMan.hasKey("output_rate", appDomain)) - freq = ConfMan.getInt("output_rate", appDomain); + if (ConfMan.hasKey("output_rate")) + freq = ConfMan.getInt("output_rate"); if (freq <= 0) freq = outputRate; @@ -164,8 +162,8 @@ SDL_AudioSpec SdlMixerManager::getAudioSpec(uint32 outputRate) { // characteristics which are not easily measured, so allow advanced users to // tweak their audio buffer size if they are experience excess latency or // drop-outs by setting this value in their ScummVM config file directly - if (ConfMan.hasKey("audio_buffer_size", appDomain)) - samples = ConfMan.getInt("audio_buffer_size", appDomain); + if (ConfMan.hasKey("audio_buffer_size", Common::ConfigManager::kApplicationDomain)) + samples = ConfMan.getInt("audio_buffer_size", Common::ConfigManager::kApplicationDomain); // 256 is an arbitrary minimum; 32768 is the largest power-of-two value // representable with uint16 diff --git a/backends/modular-backend.cpp b/backends/modular-backend.cpp index f7f98739dbb..88dc1f34120 100644 --- a/backends/modular-backend.cpp +++ b/backends/modular-backend.cpp @@ -28,6 +28,7 @@ #include "gui/EventRecorder.h" #include "audio/mixer.h" +#include "common/timer.h" #include "graphics/pixelformat.h" #include "graphics/pixelbuffer.h" // ResidualVM specific: @@ -44,6 +45,9 @@ ModularBackend::~ModularBackend() { _graphicsManager = 0; delete _mixer; _mixer = 0; + // _timerManager needs to be deleted before _mutexManager to avoid a crash. + delete _timerManager; + _timerManager = 0; delete _mutexManager; _mutexManager = 0; } diff --git a/backends/platform/sdl/ps3/ps3.mk b/backends/platform/sdl/ps3/ps3.mk index 80ec7aae0b7..f639c70d3d2 100644 --- a/backends/platform/sdl/ps3/ps3.mk +++ b/backends/platform/sdl/ps3/ps3.mk @@ -14,10 +14,14 @@ ifdef DIST_FILES_NETWORKING endif ifdef DIST_FILES_VKEYBD cp $(DIST_FILES_VKEYBD) ps3pkg/USRDIR/data/ +endif +ifdef DIST_PS3_EXTRA_FILES + @cp -a $(DIST_PS3_EXTRA_FILES) ps3pkg/USRDIR/data/ endif cp $(DIST_FILES_DOCS) ps3pkg/USRDIR/doc/ cp $(srcdir)/dists/ps3/readme-ps3.md ps3pkg/USRDIR/doc/ cp $(srcdir)/dists/ps3/ICON0.PNG ps3pkg/ + cp $(srcdir)/dists/ps3/PIC1.PNG ps3pkg/ sfo.py -f $(srcdir)/dists/ps3/sfo.xml ps3pkg/PARAM.SFO pkg.py --contentid UP0001-RESI12000_00-0000000000000000 ps3pkg/ residualvm-ps3.pkg diff --git a/backends/platform/sdl/win32/win32.cpp b/backends/platform/sdl/win32/win32.cpp index 3dd3b2ac830..f9e0e054639 100644 --- a/backends/platform/sdl/win32/win32.cpp +++ b/backends/platform/sdl/win32/win32.cpp @@ -33,6 +33,7 @@ #define _WIN32_IE 0x500 #endif #include +#include #include "common/scummsys.h" #include "common/config-manager.h" @@ -436,9 +437,11 @@ char *OSystem_Win32::convertEncoding(const char* to, const char *from, const cha #endif // UTF-32 is really important for us, because it is used for the // transliteration in Common::Encoding and Win32 cannot convert it + Common::String tempString; if (Common::String(from).hasPrefixIgnoreCase("utf-32")) { Common::U32String UTF32Str((const uint32 *)string, length / 4); - string = Common::convertUtf32ToUtf8(UTF32Str).c_str(); + tempString = Common::convertUtf32ToUtf8(UTF32Str); + string = tempString.c_str(); from = "utf-8"; } if (Common::String(to).hasPrefixIgnoreCase("utf-32")) { diff --git a/base/commandLine.cpp b/base/commandLine.cpp index b6c693ae24c..578e9038e70 100644 --- a/base/commandLine.cpp +++ b/base/commandLine.cpp @@ -100,7 +100,7 @@ static const char HELP_STRING[] = " -g, --gfx-mode=MODE Select graphics scaler (1x,2x,3x,2xsai,super2xsai,\n" " supereagle,advmame2x,advmame3x,hq2x,hq3x,tv2x,\n" " dotmatrix)\n" - " --stretch-mode=MODE Select stretch mode (center, integral, fit, stretch)" + " --stretch-mode=MODE Select stretch mode (center, integral, fit, stretch)\n" " --filtering Force filtered graphics mode\n" " --no-filtering Force unfiltered graphics mode\n" #endif diff --git a/base/main.cpp b/base/main.cpp index 8bd2b9049da..10d3525fc5c 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -555,13 +555,17 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { #endif #ifdef USE_TTS Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager(); - ttsMan->pushState(); + if (ttsMan != nullptr) { + ttsMan->pushState(); + } #endif // Try to run the game Common::Error result = runGame(plugin, system, specialDebug); #ifdef USE_TTS - ttsMan->popState(); + if (ttsMan != nullptr) { + ttsMan->popState(); + } #endif #ifdef ENABLE_EVENTRECORDER @@ -586,13 +590,13 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { } // Quit unless an error occurred, or Return to launcher was requested -#ifndef FORCE_RTL - if (result.getCode() == Common::kNoError && !g_system->getEventManager()->shouldRTL()) +#ifndef FORCE_RETURN_TO_LAUNCHER + if (result.getCode() == Common::kNoError && !g_system->getEventManager()->shouldReturnToLauncher()) break; #endif - // Reset RTL flag in case we want to load another engine - g_system->getEventManager()->resetRTL(); -#ifdef FORCE_RTL + // Reset the return to launcher flag in case we want to load another engine + g_system->getEventManager()->resetReturnToLauncher(); +#ifdef FORCE_RETURN_TO_LAUNCHER g_system->getEventManager()->resetQuit(); #endif #ifdef ENABLE_EVENTRECORDER diff --git a/base/module.mk b/base/module.mk index f12a710920b..fc0430fda11 100644 --- a/base/module.mk +++ b/base/module.mk @@ -1,6 +1,7 @@ MODULE := base MODULE_OBJS := \ + test_new_standards.o \ main.o \ commandLine.o \ plugins.o \ diff --git a/base/test_new_standards.cpp b/base/test_new_standards.cpp new file mode 100644 index 00000000000..ae8652abba0 --- /dev/null +++ b/base/test_new_standards.cpp @@ -0,0 +1,322 @@ +/* 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. + * + */ + +// This file does nothing functional! +// It test support for main C++11 features +// In the future, it might be extended to test also C++14, C++17, C++20 and any future standard +// +// In order to enable the tests, we have to `define ENABLE_TEST_CPP_11` (and of course, compile this file) +// Then it should print "Testing C++11" *during compilation* +// If the message is printed, and there are no compilation errors - great, C++11 is supported on this platform +// If there are errors, each one of the tests can be disabled, by defining the relevant DONT_TEST_* +// It's important to disable failing tests, because we might decide to support only specific subset of C++11 +// +// Note: there are 3 warnings in my GCC run, they have no signficance + +#if defined(NONSTANDARD_PORT) +#include "portdefs.h" +#endif + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#ifdef ENABLE_TEST_CPP_11 +#pragma message("Testing C++11") +// The tests are based on https://blog.petrzemek.net/2014/12/07/improving-cpp98-code-with-cpp11/ +// See there for further links and explanations +// +// We're not testing `nullptr` and `override`, since they're defined in common/c++11-compat.h + +#include "common/array.h" +#include "common/hashmap.h" +#include "common/hash-str.h" +#include "common/rect.h" + +#ifndef DONT_TEST_INITIALIZIER_LIST1 +#ifndef USE_INITIALIZIER_LIST_REPLACEMENT +#include +#else +namespace std { +template class initializer_list { +public: + typedef T value_type; + typedef const T& reference; + typedef const T& const_reference; + typedef size_t size_type; + typedef const T* iterator; + typedef const T* const_iterator; + + constexpr initializer_list() noexcept = default; + constexpr size_t size() const noexcept { return m_size; }; + constexpr const T* begin() const noexcept { return m_begin; }; + constexpr const T* end() const noexcept { return m_begin + m_size; } + +private: + // Note: begin has to be first or the compiler gets very upset + const T* m_begin = { nullptr }; + size_t m_size = { 0 }; + + // The compiler is allowed to call this constructor + constexpr initializer_list(const T* t, size_t s) noexcept : m_begin(t) , m_size(s) {} +}; + +template constexpr const T* begin(initializer_list il) noexcept { + return il.begin(); +} + +template constexpr const T* end(initializer_list il) noexcept { + return il.end(); +} +} // end namespace std +#endif +#endif + +#ifndef DONT_TEST_CLASS_ENUM +// ---------------------------------- +// Scoped/Strongly Typed Enumerations +// ---------------------------------- +enum class MyEnum { + VAL1, + VAL2, + VAL3 +}; +#endif + +#ifndef DONT_TEST_FINAL_CLASS +// ---------------------------------- +// Non-Inheritable Classes (final) +// ---------------------------------- +// C++11 +class TestNewStandards final { +#else +class TestNewStandards { +#endif +private: + void do_nothing(const int &i) { + // don't do anything with i + }; + +#ifndef DONT_TEST_FINAL_FUNCTION + // ---------------------------------- + // Non-Overridable Member Functions (final) + // ---------------------------------- + virtual void f() final {} +#endif + +#ifndef DONT_TEST_VARIADIC_TEMPLATES + // ------------------------ + // Variadic Templates + // ------------------------ + template + void variadic_function(const T &value) { + do_nothing(value); + } + + template + void variadic_function(const U &head, const T &... tail) { + do_nothing(head); + variadic_function(tail...); + } +#endif + +#ifndef DONT_TEST_TYPE_ALIASES + // ------------------------ + // Type Aliases + // * note - this test has another bunch of code below + // ------------------------ + // C++98 + template + struct Dictionary_98 { + typedef Common::HashMap type; + }; + // Usage: + Dictionary_98::type d98; + + // C++11 + template + using Dictionary_11 = Common::HashMap; + // Usage: + Dictionary_11 d11; +#endif + +#ifndef DONT_TEST_INITIALIZIER_LIST1 + // Array with C++11 initialization list + template class ArrayCpp11 : public Common::Array { + public: + ArrayCpp11(std::initializer_list list) { + if (list.size()) { + this->allocCapacity(list.size()); + Common::uninitialized_copy(list.begin(), list.end(), this->_storage); + } + } + }; +#endif + + void test_cpp11() { +#ifdef DONT_TEST_INITIALIZIER_LIST1 + // ------------------------ + // Initializer list + // ------------------------ + // C++98 + Common::Array arr; + arr.push_back(1); + arr.push_back(2); + arr.push_back(3); +#else + // C++11 + ArrayCpp11 arr = {1, 2, 3}; +#endif + +#ifndef DONT_TEST_INITIALIZIER_LIST2 + // C++11 + Common::Point arr3[] = {{0, 0}, {1, 1}}; +#endif + +#ifndef DONT_TEST_AUTO_TYPE_INFERENCE + // ------------------------ + // Automatic Type Inference + // ------------------------ + // C++98 + for (Common::Array::iterator i = arr.begin(), e = arr.end(); i != e; ++i) + ; + + // C++11 + for (auto i = arr.begin(), e = arr.end(); i != e; ++i) + ; +#endif + +#ifndef DONT_TEST_RANGE_BASED_FOR_LOOP + // ------------------------ + // Range based for loop + // ------------------------ + // C++98 + for (Common::Array::iterator i = arr.begin(), e = arr.end(); i != e; ++i) + do_nothing(*i); + + // C++11 + for (int &i : arr) + do_nothing(i); +#endif + +#ifndef DONT_TEST_LAMBDA_FUNCTIONS + // ------------------------ + // Lambda functions + // ------------------------ + // C++98 + // the following isn't working in VS, but it's not really important to debug... + // Common::for_each(arr.begin(), arr.end(), do_nothing); + + // C++11 + Common::for_each(arr.begin(), arr.end(), + [](int i) { + // don't do anything with i + } + ); +#endif + +#ifndef DONT_TEST_VARIADIC_TEMPLATES + variadic_function(1, 1, 2, 3, 5, 8, 13, 21, 34); +#endif + +#ifndef DONT_TEST_GET_RID_OF_SPACE_IN_NESTED_TEMPLATES + // ------------------------ + // No Need For an Extra Space In Nested Template Declarations + // ------------------------ + // C++98 + Common::Array > v_98; + + // C++11 + Common::Array> v_11; +#endif + +#ifndef DONT_TEST_TYPE_ALIASES + // ------------------------ + // Type Aliases + // * note - this test has another bunch of code above + // ------------------------ + // C++98 + typedef void (*fp_98)(int, int); + + // C++11 + using fp_11 = void (*)(int, int); +#endif + + }; + +#ifndef DONT_TEST_ALT_FUNCTION_SYNTAX + // ------------------------ + // Alternative Function Syntax + // ------------------------ + // C++98 + int f_98(int x, int y) {return x;} + + // C++11 + auto f_11(int x, int y) -> int {return x;} +#endif + +#ifndef DONT_TEST_NON_STATIC_INIT + // ------------------------ + // Non-Static Data Member Initializers + // ------------------------ + int j = 3; + Common::String s = "non static init"; +#endif + +#ifndef DONT_TEST_EXPLICIT + // ------------------------ + // Explicit Conversion Operators + // ------------------------ + explicit operator bool() const {return true;} +#endif + + +public: + TestNewStandards() { + test_cpp11(); + } + +#ifndef DONT_TEST_MOVE_SEMANTICS + // ------------------------ + // Move semantics + // Note: this test hasn't been taken from the aforementioned web page + // ------------------------ + TestNewStandards(TestNewStandards&& t) { + // I'm not convinced that it's a good example of move sematics, it's a complicated topic. But just checking the syntax. + } +#endif + + +#ifndef DONT_TEST_DELETED_FUNCTIONS + // ------------------------ + // Explicitly Deleted Functions + // (useful for non copyable classes, + // particularly for our Singleton class) + // ------------------------ + TestNewStandards &operator=(const TestNewStandards &) = delete; +#endif + +}; + +static TestNewStandards test = TestNewStandards(); + +#endif diff --git a/common/c++11-compat.h b/common/c++11-compat.h index a56b79514c8..5a981493ffc 100644 --- a/common/c++11-compat.h +++ b/common/c++11-compat.h @@ -39,12 +39,13 @@ #endif // -// Replacement for the override keyword. This allows compilation of code -// which uses it, but does not feature any semantic. +// Replacement for the override & final keywords. This allows compilation of +// code which uses it, but does not feature any semantic. // -// MSVC 2012 and newer fully support override: http://msdn.microsoft.com/en-us/library/hh567368.aspx +// MSVC 2012 and newer fully support these: http://msdn.microsoft.com/en-us/library/hh567368.aspx #if !defined(_MSC_VER) || _MSC_VER < 1700 #define override +#define final #endif #endif diff --git a/common/config-manager.cpp b/common/config-manager.cpp index 56ed2876fe5..aa44ab0e104 100644 --- a/common/config-manager.cpp +++ b/common/config-manager.cpp @@ -527,6 +527,19 @@ void ConfigManager::set(const String &key, const String &value) { _appDomain[key] = value; } +void ConfigManager::setAndFlush(const String &key, const Common::String &value) { + if (value.empty() && !hasKey(key)) { + return; + } + + if (hasKey(key) && get(key) == value) { + return; + } + + set(key, value); + flushToDisk(); +} + void ConfigManager::set(const String &key, const String &value, const String &domName) { // FIXME: For now we continue to allow empty domName to indicate // "use 'default' domain". This is mainly needed for the SCUMM ConfigDialog diff --git a/common/config-manager.h b/common/config-manager.h index 06e8ea372d4..0295abf1709 100644 --- a/common/config-manager.h +++ b/common/config-manager.h @@ -118,6 +118,12 @@ public: const String & get(const String &key) const; void set(const String &key, const String &value); + /** + * Update a configuration entry for the active domain and flush + * the configuration file to disk if the value changed + */ + void setAndFlush(const String &key, const Common::String &value); + #if 1 // // Domain specific access methods: Acces *one specific* domain and modify it. diff --git a/common/events.h b/common/events.h index 0c4ea2c432b..18205cbf628 100644 --- a/common/events.h +++ b/common/events.h @@ -60,7 +60,7 @@ enum EventType { EVENT_MBUTTONUP = 14, EVENT_MAINMENU = 15, - EVENT_RTL = 16, + EVENT_RETURN_TO_LAUNCHER = 16, EVENT_MUTE = 17, EVENT_QUIT = 10, @@ -504,14 +504,14 @@ public: /** * Should we return to the launcher? */ - virtual int shouldRTL() const = 0; + virtual int shouldReturnToLauncher() const = 0; /** - * Reset the "return to launcher" flag (as returned shouldRTL()) to false. + * Reset the "return to launcher" flag (as returned shouldReturnToLauncher()) to false. * Used when we have returned to the launcher. */ - virtual void resetRTL() = 0; -#ifdef FORCE_RTL + virtual void resetReturnToLauncher() = 0; +#ifdef FORCE_RETURN_TO_LAUNCHER virtual void resetQuit() = 0; #endif // Optional: check whether a given key is currently pressed ???? diff --git a/common/gui_options.cpp b/common/gui_options.cpp index 08ee553ea6a..2786701c858 100644 --- a/common/gui_options.cpp +++ b/common/gui_options.cpp @@ -128,12 +128,7 @@ const String getGameGUIOptionsDescription(const String &options) { void updateGameGUIOptions(const String &options, const String &langOption) { const String newOptionString = getGameGUIOptionsDescription(options) + " " + langOption; - - if ((!options.empty() && !ConfMan.hasKey("guioptions")) || - (ConfMan.hasKey("guioptions") && ConfMan.get("guioptions") != newOptionString)) { - ConfMan.set("guioptions", newOptionString); - ConfMan.flushToDisk(); - } + ConfMan.setAndFlush("guioptions", newOptionString); } diff --git a/common/json.h b/common/json.h index c1e630ca32f..7b7c6b8d588 100644 --- a/common/json.h +++ b/common/json.h @@ -53,7 +53,7 @@ #include "common/str.h" // Win32 incompatibilities -#if defined(WIN32) && !defined(__GNUC__) +#if (defined(WIN32) && !defined(__GNUC__)) || defined(__PLAYSTATION2__) static inline bool isnan(double x) { return x != x; } diff --git a/common/language.cpp b/common/language.cpp index 60409a05827..7f2ac5e355c 100644 --- a/common/language.cpp +++ b/common/language.cpp @@ -50,6 +50,7 @@ const LanguageDescription g_languages[] = { { "kr", "ko_KR", "Korean", KO_KOR }, { "lv", "lv_LV", "Latvian", LV_LAT }, { "nb", "nb_NO", "Norwegian Bokm\xE5l", NB_NOR }, + { "fa", "fa_IR", "Persian (Iran)", FA_IRN }, { "pl", "pl_PL", "Polish", PL_POL }, { "br", "pt_BR", "Portuguese (Brazil)", PT_BRA }, { "pt", "pt_PT", "Portuguese (Portugal)", PT_POR }, diff --git a/common/language.h b/common/language.h index 99719f60e2b..8c7369a8a3a 100644 --- a/common/language.h +++ b/common/language.h @@ -55,6 +55,7 @@ enum Language { KO_KOR, LV_LAT, NB_NOR, + FA_IRN, PL_POL, PT_BRA, PT_POR, diff --git a/common/macresman.cpp b/common/macresman.cpp index abcee5a066c..7f12f3207bd 100644 --- a/common/macresman.cpp +++ b/common/macresman.cpp @@ -162,7 +162,8 @@ bool MacResManager::open(const String &fileName) { if (file->open(fileName)) { _baseFileName = fileName; - // FIXME: Is this really needed? + // Maybe file is in MacBinary but without .bin extension? + // Check it here if (isMacBinary(*file)) { file->seek(0); if (loadFromMacBinary(*file)) diff --git a/common/macresman.h b/common/macresman.h index ce3e7a80131..48850ee92db 100644 --- a/common/macresman.h +++ b/common/macresman.h @@ -166,6 +166,8 @@ public: */ String getBaseFileName() const { return _baseFileName; } + void setBaseFileName(Common::String str) { _baseFileName = str; } + /** * Return list of resource IDs with specified type ID */ diff --git a/common/math.h b/common/math.h index 2c62fce6d58..5c8b82372a9 100644 --- a/common/math.h +++ b/common/math.h @@ -124,20 +124,20 @@ inline T trunc(T x) { // Convert radians to degrees // Input and Output type can be different // Upconvert everything to floats -template +template inline OutputT rad2deg(InputT rad) { return (OutputT)( (float)rad * (float)57.2957795130823); // 180.0/M_PI = 57.2957795130823 } // Handle the case differently when the input type is double -template +template inline OutputT rad2deg(double rad) { return (OutputT)( rad * 57.2957795130823); } // Convert radians to degrees // Input and Output type are the same -template +template inline T rad2deg(T rad) { return rad2deg(rad); } @@ -145,24 +145,29 @@ inline T rad2deg(T rad) { // Convert degrees to radians // Input and Output type can be different // Upconvert everything to floats -template +template inline OutputT deg2rad(InputT deg) { return (OutputT)( (float)deg * (float)0.0174532925199433); // M_PI/180.0 = 0.0174532925199433 } // Handle the case differently when the input type is double -template +template inline OutputT deg2rad(double deg) { return (OutputT)( deg * 0.0174532925199433); } // Convert degrees to radians // Input and Output type are the same -template +template inline T deg2rad(T deg) { return deg2rad(deg); } +template +inline T hypotenuse(T xv, T yv) { + return (T)sqrt((double)(xv * xv + yv * yv)); +} + } // End of namespace Common #endif // COMMON_MATH_H diff --git a/common/module.mk b/common/module.mk index 74c8c4071b6..5303e1d1952 100644 --- a/common/module.mk +++ b/common/module.mk @@ -40,6 +40,7 @@ MODULE_OBJS := \ tokenizer.o \ translation.o \ unarj.o \ + unicode-bidi.o \ unzip.o \ ustr.o \ util.o \ diff --git a/common/str-enc.cpp b/common/str-enc.cpp index e1bb3326486..3a099e48ef5 100644 --- a/common/str-enc.cpp +++ b/common/str-enc.cpp @@ -249,6 +249,23 @@ static const uint32 g_windows1255ConversionTable[] = {0x20AC, 0x0081, 0x201A, 0x 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x00FF}; +static const uint32 g_windows1256ConversionTable[] = {0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688, + 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA, + 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F, + 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, + 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0641, 0x0642, 0x0643, + 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF, + 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7, + 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2}; + static const uint32 g_windows1257ConversionTable[] = {0x20AC, 0x0081, 0x201A, 0x0083, 0x201E, 0x2026, 0x2020, 0x2021, 0x0088, 0x2030, 0x008A, 0x2039, 0x008C, 0x00A8, 0x02C7, 0x00B8, 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, @@ -276,6 +293,7 @@ static char const *const g_codePageMap[] = { "WINDOWS-1253", /* kWindows1253 */ "WINDOWS-1254", /* kWindows1254 */ "WINDOWS-1255", /* kWindows1255 */ + "WINDOWS-1256", /* kWindows1256 */ "WINDOWS-1257", /* kWindows1257 */ "MS932", /* kWindows932 */ "MSCP949", /* kWindows949 */ @@ -310,6 +328,9 @@ void String::decodeOneByte(U32String &dst, CodePage page) const { case kWindows1255: dst += g_windows1255ConversionTable[index]; break; + case kWindows1256: + dst += g_windows1256ConversionTable[index]; + break; case kWindows1257: dst += g_windows1257ConversionTable[index]; break; @@ -363,6 +384,9 @@ void U32String::encodeOneByte(String &dst, CodePage page) const { case kWindows1255: conversionTable = g_windows1255ConversionTable; break; + case kWindows1256: + conversionTable = g_windows1256ConversionTable; + break; case kWindows1257: conversionTable = g_windows1257ConversionTable; break; diff --git a/common/str-enc.h b/common/str-enc.h index 796cf963f0d..0e2a7ba8a6d 100644 --- a/common/str-enc.h +++ b/common/str-enc.h @@ -37,6 +37,7 @@ enum CodePage { kWindows1253, kWindows1254, kWindows1255, + kWindows1256, kWindows1257, kWindows932, kWindows949, diff --git a/common/str.cpp b/common/str.cpp index 2ae366bca8e..77a50bd768f 100644 --- a/common/str.cpp +++ b/common/str.cpp @@ -1323,3 +1323,22 @@ char *scumm_strdup(const char *in) { } return out; } + +// Portable implementation of strcasestr. +const char *scumm_strcasestr(const char *s, const char *find) { + char c, sc; + size_t len; + + if ((c = *find++) != 0) { + c = (char)tolower((unsigned char)c); + len = strlen(find); + do { + do { + if ((sc = *s++) == 0) + return (NULL); + } while ((char)tolower((unsigned char)sc) != c); + } while (scumm_strnicmp(s, find, len) != 0); + s--; + } + return s; +} diff --git a/common/str.h b/common/str.h index c19b2ef6999..bce55fd2103 100644 --- a/common/str.h +++ b/common/str.h @@ -568,4 +568,6 @@ extern char *scumm_strdup(const char *in); extern int scumm_compareDictionary(const char *s1, const char *s2); extern const char *scumm_skipArticle(const char *s1); +extern const char *scumm_strcasestr(const char *s, const char *find); + #endif diff --git a/common/stream.cpp b/common/stream.cpp index 988c1ab53e1..8a7359865b0 100644 --- a/common/stream.cpp +++ b/common/stream.cpp @@ -124,7 +124,7 @@ enum { CR = 0x0D }; -char *SeekableReadStream::readLine(char *buf, size_t bufSize) { +char *SeekableReadStream::readLine(char *buf, size_t bufSize, bool handleCR) { assert(buf != nullptr && bufSize > 1); char *p = buf; size_t len = 0; @@ -159,7 +159,7 @@ char *SeekableReadStream::readLine(char *buf, size_t bufSize) { // * DOS and Windows use CRLF line breaks // * Unix and OS X use LF line breaks // * Macintosh before OS X used CR line breaks - if (c == CR) { + if (c == CR && handleCR) { // Look at the next char -- is it LF? If not, seek back c = readByte(); @@ -187,12 +187,12 @@ char *SeekableReadStream::readLine(char *buf, size_t bufSize) { return buf; } -String SeekableReadStream::readLine() { +String SeekableReadStream::readLine(bool handleCR) { // Read a line String line; while (line.lastChar() != '\n') { char buf[256]; - if (!readLine(buf, 256)) + if (!readLine(buf, 256, handleCR)) break; line += buf; } diff --git a/common/stream.h b/common/stream.h index aa2f6e3a7f2..a3843290e20 100644 --- a/common/stream.h +++ b/common/stream.h @@ -629,9 +629,10 @@ public: * * @param s the buffer to store into * @param bufSize the size of the buffer + * @param handleCR if set (default), then CR and CR/LF are handled as well as LF * @return a pointer to the read string, or NULL if an error occurred */ - virtual char *readLine(char *s, size_t bufSize); + virtual char *readLine(char *s, size_t bufSize, bool handleCR = true); /** @@ -643,8 +644,10 @@ public: * of the line, *without* the end of a line marker. This method * does not indicate whether an error occurred. Callers must use * err() or eos() to determine whether an exception occurred. + * + * @param handleCR if set (default), then CR and CR/LF are handled as well as LF */ - virtual String readLine(); + virtual String readLine(bool handleCR = true); /** * Print a hexdump of the stream while maintaing position. The number diff --git a/common/system.h b/common/system.h index 72c7e14386b..abe834509a4 100644 --- a/common/system.h +++ b/common/system.h @@ -1064,7 +1064,7 @@ public: * @param shakeYOffset the shake y offset * * @note This is currently used in the SCUMM, QUEEN, KYRA, SCI, DREAMWEB, - * SUPERNOVA, TEENAGENT, and TOLTECS engines. + * SUPERNOVA, TEENAGENT, TOLTECS, ULTIMA, and PETKA engines. */ virtual void setShakePos(int shakeXOffset, int shakeYOffset) = 0; diff --git a/common/text-to-speech.h b/common/text-to-speech.h index cd34c287470..d35553b4c5c 100644 --- a/common/text-to-speech.h +++ b/common/text-to-speech.h @@ -293,6 +293,11 @@ public: */ Array getVoiceIndicesByGender (TTSVoice::Gender gender); + /** + * returns the index for the default voice. + */ + virtual int getDefaultVoice() { return 0; } + /** * Pushes the current state of the TTS */ diff --git a/common/translation.cpp b/common/translation.cpp index 133c732ad91..ea869e4cb52 100644 --- a/common/translation.cpp +++ b/common/translation.cpp @@ -33,13 +33,10 @@ #include "common/fs.h" #include "common/system.h" #include "common/textconsole.h" +#include "common/unicode-bidi.h" #ifdef USE_TRANSLATION -#ifdef USE_FRIBIDI -#include -#endif - namespace Common { DECLARE_SINGLETON(TranslationManager); @@ -463,58 +460,9 @@ String TranslationManager::convertBiDiString(const String &input) { return input; }; - return TranslationManager::convertBiDiString(input, HE_ISR); + return Common::convertBiDiString(input, HE_ISR); } -#ifdef USE_FRIBIDI -String TranslationManager::convertBiDiString(const String &input, const Common::Language lang) { - if (lang != HE_ISR) //TODO: modify when we'll support other RTL languages, such as Arabic and Farsi - return input; - - int buff_length = (input.size() + 2) * 2; // it's more than enough, but it's better to be on the safe side - FriBidiChar *input_unicode = (FriBidiChar *)malloc(buff_length * sizeof(FriBidiChar)); - FriBidiChar *visual_str = (FriBidiChar *)malloc(buff_length * sizeof(FriBidiChar)); - char *output = (char *)malloc(buff_length); - - FriBidiCharType pbase_dir = FRIBIDI_TYPE_ON; - FriBidiCharSet char_set = FRIBIDI_CHAR_SET_ISO8859_8; - - FriBidiStrIndex length = fribidi_charset_to_unicode(char_set, input.c_str(), input.size(), input_unicode); - - if (!fribidi_log2vis( - /* input */ - input_unicode, - length, - &pbase_dir, - /* output */ - visual_str, - NULL, // position_L_to_V_list, - NULL, // position_V_to_L_list, - NULL // embedding_level_list - )) { - warning("convertBiDiString: calling fribidi_log2vis failed"); - free(input_unicode); - free(visual_str); - free(output); - return input; - } - - fribidi_unicode_to_charset(char_set, visual_str, length, output); - - String result = String(output); - free(input_unicode); - free(visual_str); - free(output); - - return result; -} -#else -String TranslationManager::convertBiDiString(const String &input, const Common::Language lang) { - return input; -} -#endif - - } // End of namespace Common diff --git a/common/translation.h b/common/translation.h index 88cd86a65d4..f711316d70c 100644 --- a/common/translation.h +++ b/common/translation.h @@ -181,7 +181,6 @@ public: * For RTL (Right To Left) languages, returns visual representation of a logical single-line input */ String convertBiDiString(const String &input); - String convertBiDiString(const String &input, const Common::Language lang); private: /** diff --git a/common/unicode-bidi.cpp b/common/unicode-bidi.cpp new file mode 100644 index 00000000000..c6b2642b9bd --- /dev/null +++ b/common/unicode-bidi.cpp @@ -0,0 +1,113 @@ +/* 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 "common/ustr.h" +#include "common/unicode-bidi.h" +#include "common/textconsole.h" + +#ifdef USE_FRIBIDI +#include +#endif + +namespace Common { + +UnicodeBiDiText::UnicodeBiDiText(const Common::U32String &str) : logical(str), _log_to_vis_index(NULL), _vis_to_log_index(NULL) { + initWithU32String(str); +} + +UnicodeBiDiText::UnicodeBiDiText(const Common::String &str, const Common::CodePage page) : logical(str), _log_to_vis_index(NULL), _vis_to_log_index(NULL) { + initWithU32String(str.decode(page)); +} + +UnicodeBiDiText::~UnicodeBiDiText() { + delete[] _log_to_vis_index; + delete[] _vis_to_log_index; +} + +uint32 UnicodeBiDiText::getVisualPosition(uint32 logicalPos) const { + if (NULL != _log_to_vis_index && logicalPos < size()) { + return _log_to_vis_index[logicalPos]; + } + return logicalPos; +} +uint32 UnicodeBiDiText::getLogicalPosition(uint32 visualPos) const { + if (NULL != _log_to_vis_index && visualPos < size()) { + return _vis_to_log_index[visualPos]; + } + return visualPos; +} + +void UnicodeBiDiText::initWithU32String(const U32String &input) { + +#ifdef USE_FRIBIDI + uint32 input_size = input.size(); + uint32 buff_length = (input_size + 2) * 2; // it's more than enough, but it's better to be on the safe side + FriBidiChar *visual_str = new FriBidiChar[buff_length * sizeof(FriBidiChar)]; + _log_to_vis_index = new uint32[input_size]; + _vis_to_log_index = new uint32[input_size]; + FriBidiCharType pbase_dir = FRIBIDI_TYPE_ON; + + if (!fribidi_log2vis( + /* input */ + (const FriBidiChar *)input.c_str(), + input_size, + &pbase_dir, + /* output */ + visual_str, + (FriBidiStrIndex *)_log_to_vis_index, // position_L_to_V_list, + (FriBidiStrIndex *)_vis_to_log_index, // position_V_to_L_list, + NULL // embedding_level_list + )) { + warning("initWithU32String: calling fribidi_log2vis failed"); + delete[] visual_str; + delete[] _log_to_vis_index; + delete[] _vis_to_log_index; + visual = input; + _log_to_vis_index = NULL; + _vis_to_log_index = NULL; + } else { + visual = U32String((uint32 *)visual_str, input.size()); + delete[] visual_str; + } +#else + warning("initWithU32String: Fribidi not available, using input string as fallback"); + visual = input; +#endif + +} + +String convertBiDiString(const String &input, const Common::Language lang) { + if (lang != Common::HE_ISR) //TODO: modify when we'll support other RTL languages, such as Arabic and Farsi + return input; + + return Common::convertBiDiString(input, kWindows1255); +} + +String convertBiDiString(const String &input, const Common::CodePage page) { + return convertBiDiU32String(input.decode(page)).visual.encode(page); +} + +UnicodeBiDiText convertBiDiU32String(const U32String &input) { + return UnicodeBiDiText(input); +} + +} // End of namespace Common diff --git a/common/unicode-bidi.h b/common/unicode-bidi.h new file mode 100644 index 00000000000..995673802ae --- /dev/null +++ b/common/unicode-bidi.h @@ -0,0 +1,57 @@ +/* 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. + * + */ + +#ifndef COMMON_STRING_BIDI_H +#define COMMON_STRING_BIDI_H + +#include "common/str.h" +#include "common/ustr.h" +#include "common/language.h" + +namespace Common { + +class UnicodeBiDiText { +private: + uint32 *_log_to_vis_index; // from fribidi conversion + uint32 *_vis_to_log_index; // from fribidi conversion + void initWithU32String(const Common::U32String &str); +public: + const Common::U32String logical; // original string, ordered logically + Common::U32String visual; // from fribidi conversion, ordered visually + + UnicodeBiDiText(const Common::U32String &str); + UnicodeBiDiText(const Common::String &str, const Common::CodePage page); + ~UnicodeBiDiText(); + + uint32 getVisualPosition(uint32 logicalPos) const; + uint32 getLogicalPosition(uint32 visualPos) const; + uint32 size() const { return logical.size(); } +}; + +/* just call the constructor for convenience */ +UnicodeBiDiText convertBiDiU32String(const U32String &input); +String convertBiDiString(const String &input, const Common::Language lang); +String convertBiDiString(const String &input, const Common::CodePage page); + +} // End of namespace Common + +#endif diff --git a/common/ustr.cpp b/common/ustr.cpp index f85237a7886..5a45a8bec18 100644 --- a/common/ustr.cpp +++ b/common/ustr.cpp @@ -23,6 +23,7 @@ #include "common/ustr.h" #include "common/memorypool.h" #include "common/util.h" +#include "unicode-bidi.h" namespace Common { @@ -94,6 +95,10 @@ U32String::U32String(const String &str) : _size(0), _str(_storage) { initWithCStr(str.c_str(), str.size()); } +U32String::U32String(const UnicodeBiDiText &txt) : _size(0), _str(_storage) { + initWithCStr(txt.visual.c_str(), txt.visual.size()); +} + U32String::~U32String() { decRefCount(_extern._refCount); } diff --git a/common/ustr.h b/common/ustr.h index 7fbc9bb0402..fd93ebd89dc 100644 --- a/common/ustr.h +++ b/common/ustr.h @@ -29,6 +29,7 @@ namespace Common { class String; +class UnicodeBiDiText; /** * Very simple string class for UTF-32 strings in ScummVM. The main intention @@ -103,6 +104,9 @@ public: /** Construct a copy of the given string. */ U32String(const U32String &str); + /** Construct a copy of the given unicode BiDi converted string. */ + U32String(const UnicodeBiDiText &txt); + /** Construct a new string from the given NULL-terminated C string. */ explicit U32String(const char *str); diff --git a/common/util.h b/common/util.h index 4a030d588c8..f7c5cbd0ce6 100644 --- a/common/util.h +++ b/common/util.h @@ -49,7 +49,18 @@ template inline T ABS(T x) { return (x >= 0) ? x : -x; } template inline T MIN(T a, T b) { return (a < b) ? a : b; } template inline T MAX(T a, T b) { return (a > b) ? a : b; } template inline T CLIP(T v, T amin, T amax) - { if (v < amin) return amin; else if (v > amax) return amax; else return v; } + { +#if !defined(RELEASE_BUILD) + // debug builds use this assert to pinpoint + // any problematic cases, where amin and amax + // are incorrectly ordered + // and thus CLIP() would return an invalid result + assert(amin <= amax); +#endif + if (v < amin) return amin; + else if (v > amax) return amax; + return v; + } /** * Template method which swaps the values of its two parameters. diff --git a/config.guess b/config.guess index 7f9ebbe3109..11fda528bc7 100755 --- a/config.guess +++ b/config.guess @@ -1,8 +1,8 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2019 Free Software Foundation, Inc. +# Copyright 1992-2020 Free Software Foundation, Inc. -timestamp='2019-09-10' +timestamp='2020-04-26' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -50,7 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2019 Free Software Foundation, Inc. +Copyright 1992-2020 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -99,6 +99,8 @@ tmp= trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { + # prevent multiple calls if $tmp is already set + test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || @@ -924,7 +926,7 @@ EOF echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; @@ -1627,6 +1629,12 @@ copies of config.guess and config.sub with the latest versions from: https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess and https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub +EOF + +year=`echo $timestamp | sed 's,-.*,,'` +# shellcheck disable=SC2003 +if test "`expr "\`date +%Y\`" - "$year"`" -lt 3 ; then + cat >&2 <." version="\ GNU config.sub ($timestamp) -Copyright 1992-2019 Free Software Foundation, Inc. +Copyright 1992-2020 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -1366,7 +1366,7 @@ case $os in | skyos* | haiku* | rdos* | toppers* | drops* | es* \ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ - | nsk* | powerunix) + | nsk* | powerunix* | genode*) # Remember, each alternative MUST END IN *, to match a version number. ;; qnx*) diff --git a/configure b/configure index 624082b0f06..cd713568e34 100755 --- a/configure +++ b/configure @@ -270,6 +270,7 @@ add_feature vorbis "Vorbis file support" "_vorbis _tremor" add_feature zlib "zlib" "_zlib" add_feature lua "lua" "_lua" add_feature fribidi "FriBidi" "_fribidi" +add_feature test_cxx11 "Test C++11" "_test_cxx11" # Directories for installing ScummVM. # This list is closely based on what GNU autoconf does, @@ -1210,6 +1211,8 @@ for ac_option in $@; do --disable-mad) _mad=no ;; --enable-fribidi) _fribidi=yes ;; --disable-fribidi) _fribidi=no ;; + --enable-test-c++11) _test_cxx11=yes ;; + --disable-test-c++11) _test_cxx11=no ;; --enable-zlib) _zlib=yes ;; --disable-zlib) _zlib=no ;; --enable-sparkle) _sparkle=yes ;; @@ -1249,6 +1252,10 @@ for ac_option in $@; do --disable-updates) _updates=no ;; --enable-libunity) _libunity=yes ;; --disable-libunity) _libunity=no ;; + --enable-tts) _tts=yes ;; + --disable-tts) _tts=no ;; + --enable-gtk) _gtk=yes ;; + --disable-gtk) _gtk=no ;; --enable-glew) _glew=yes ;; #ResidualVM specific option --disable-glew) _glew=no ;; #ResidualVM specific option --enable-opengl) _opengl=yes ;; #ResidualVM specific option @@ -1563,7 +1570,7 @@ case $_host in datadir='${datarootdir}' docdir='${prefix}/doc' ;; -android | android-arm | android-v7a | android-arm-v7a | ouya) +android-arm-v7a | ouya) _host_os=android _host_cpu=arm _host_alias=arm-linux-androideabi @@ -1767,6 +1774,8 @@ switch) datarootdir='${prefix}/data' datadir='${datarootdir}' docdir='${prefix}/doc' + # Switch SDK has C++11 constructs so we must enable it + _use_cxx11=yes ;; tizen) _host_os=tizen @@ -2181,16 +2190,17 @@ if test "$have_gcc" = yes ; then if test "$_cxx_major" -ge "3" ; then # Try to use ANSI mode when C++11 is disabled. if test "$_use_cxx11" = "no" ; then - case $_host_os in - # newlib-based system include files suppress non-C89 function - # declarations under __STRICT_ANSI__ - 3ds | amigaos* | android | androidsdl | dreamcast | ds | gamecube | mingw* | mint* | n64 | psp | ps2 | ps3 | psp2 | switch | tizen | wii ) - ;; - *) - append_var CXXFLAGS "-ansi" - ;; - esac + append_var CXXFLAGS "-ansi" fi + case $_host_os in + # newlib-based system include files suppress non-C89 function + # declarations under __STRICT_ANSI__, undefine it + 3ds | amigaos* | android | androidsdl | dreamcast | ds | gamecube | mingw* | mint* | n64 | psp | ps2 | ps3 | psp2 | switch | tizen | wii ) + append_var CXXFLAGS "-U__STRICT_ANSI__" + ;; + *) + ;; + esac append_var CXXFLAGS "-W -Wno-unused-parameter" add_line_to_config_mk 'HAVE_GCC3 = 1' add_line_to_config_mk 'CXX_UPDATE_DEP_FLAG = -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d" -MQ "$@" -MP' @@ -2202,6 +2212,7 @@ if test "$have_gcc" = yes ; then else append_var CXXFLAGS "-Wconversion" fi; + append_var CXXFLAGS "-fno-operator-names" elif test "$have_icc" = yes ; then add_line_to_config_mk 'CXX_UPDATE_DEP_FLAG = -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d" -MQ "$@" -MP' fi; @@ -2498,7 +2509,7 @@ case $_host_cpu in openpandora) define_in_config_if_yes yes 'USE_ARM_NEON_ASPECT_CORRECTOR' ;; - android | android-arm | androidsdl-armeabi | arm-*riscos | caanoo | ds | gp2x | gp2xwiz | maemo | tizen) + androidsdl-armeabi | arm-*riscos | caanoo | ds | gp2x | gp2xwiz | maemo | tizen) define_in_config_if_yes yes 'USE_ARM_SCALER_ASM' # FIXME: The following feature exhibits a bug. It produces distorted # sound since 9003ce517ff9906b0288f9f7c02197fd091d4554. The ARM @@ -2578,45 +2589,45 @@ case $_host_os in ;; android) case $_host in - android | android-arm) - append_var CXXFLAGS "-march=armv5te" - append_var CXXFLAGS "-mtune=xscale" - append_var CXXFLAGS "-mfloat-abi=softfp" - append_var LDFLAGS "-mthumb" - ABI="armeabi" - ;; - android-v7a | android-arm-v7a) - append_var CXXFLAGS "-march=armv7-a" - append_var CXXFLAGS "-mfloat-abi=softfp" + android-arm-v7a) + # Disable NEON for older devices (like with Tegra 2) append_var CXXFLAGS "-mfpu=vfp" + # This is really old CPU but might be still used with android 4.1, it slightly increases code size and decreases performance. append_var LDFLAGS "-Wl,--fix-cortex-a8" ABI="armeabi-v7a" ;; - android-mips) - append_var CXXFLAGS "-march=mips32" - append_var CXXFLAGS "-mtune=mips32" - ABI="mips" + android-arm64-v8a) + ABI="arm64-v8a" ;; android-x86) - append_var CXXFLAGS "-march=i686" - append_var CXXFLAGS "-mtune=i686" ABI="x86" ;; + android-x86_64) + ABI="x86_64" + ;; + ouya) + append_var CXXFLAGS "-mtune=cortex-a9" + ABI="armeabi-v7a" + ;; esac - append_var LDFLAGS "-static-libstdc++" - append_var LDFLAGS "-Wl,--build-id=sha1" + append_var CXXFLAGS "-Wno-inconsistent-missing-override" + append_var CXXFLAGS "-fpic" append_var CXXFLAGS "-ffunction-sections" append_var CXXFLAGS "-funwind-tables" - if test "$_debug_build" = yes; then - append_var CXXFLAGS "-fno-omit-frame-pointer" - append_var CXXFLAGS "-fno-strict-aliasing" - else + if test "$_debug_build" = no; then + _optimization_level=-Os append_var CXXFLAGS "-fomit-frame-pointer" append_var CXXFLAGS "-fstrict-aliasing" + else + _optimization_level=-O0 + append_var CXXFLAGS "-fno-omit-frame-pointer" + append_var CXXFLAGS "-fno-strict-aliasing" fi - _optimization_level=-Os + + # Build ID is needed for native debugging in Android Studio + append_var LDFLAGS "-Wl,--build-id=sha1" add_line_to_config_mk "ANDROID_SDK = $ANDROID_SDK" _seq_midi=no @@ -3108,7 +3119,7 @@ if test -n "$_host"; then _vorbis=no _port_mk="backends/platform/3ds/3ds.mk" ;; - android | android-arm | android-v7a | android-arm-v7a | android-arm64-v8a | android-mips | android-x86 | ouya) + android-arm-v7a | android-arm64-v8a | android-x86 | android-x86_64 | ouya) # also __ANDROID__ is defined by Clang in the NDK DEFINES="$DEFINES -D__ANDROID_PLAIN_PORT__ -DANDROID_PLAIN_PORT" # we link a .so as default @@ -3651,7 +3662,7 @@ case $_backend in ;; ps2) append_var DEFINES "-D_EE" - append_var DEFINES "-DFORCE_RTL" + append_var DEFINES "-DFORCE_RETURN_TO_LAUNCHER" append_var INCLUDES "-I$PS2SDK/ee/include" append_var INCLUDES "-I$PS2SDK/common/include" append_var INCLUDES "-I$PS2SDK/ports/include" @@ -5601,6 +5612,12 @@ fi define_in_config_if_yes "$_fribidi" 'USE_FRIBIDI' echo "$_fribidi" +# +# Test C++11 Compatibility +# +define_in_config_if_yes "$_test_cxx11" 'ENABLE_TEST_CPP_11' +echo_n "Test C++11 compatibility during compilation... " +echo "$_test_cxx11" # Default to plain text output for pandoc if test -z "$_pandocformat" -o "$_pandocformat" = "default"; then diff --git a/devtools/create_project/cmake.cpp b/devtools/create_project/cmake.cpp index d7cc91e0111..af514f99d5c 100644 --- a/devtools/create_project/cmake.cpp +++ b/devtools/create_project/cmake.cpp @@ -51,6 +51,7 @@ const CMakeProvider::Library *CMakeProvider::getLibraryFromFeature(const char *f { "theora", kSDLVersionAny, 0, 0, 0, 0, "theoradec" }, { "fluidsynth",kSDLVersionAny, 0, 0, 0, 0, "fluidsynth" }, { "faad", kSDLVersionAny, 0, 0, 0, 0, "faad" }, + { "fribidi", kSDLVersionAny, 0, 0, 0, 0, "fribidi" }, { "opengl", kSDLVersionAny, "FindOpenGL", "OpenGL", "OPENGL_INCLUDE_DIR", "OPENGL_gl_LIBRARY", 0 }, // ResidualVM specific { "glew", kSDLVersionAny, "FindGLEW", "GLEW", "GLEW_INCLUDE_DIR", "GLEW_LIBRARIES", 0 }, // ResidualVM specific { "libcurl", kSDLVersionAny, "FindCURL", "CURL", "CURL_INCLUDE_DIRS", "CURL_LIBRARIES", 0 }, diff --git a/devtools/create_project/msvc10/create_project.sln b/devtools/create_project/msvc10/create_project.sln deleted file mode 100644 index 69eeb8ed196..00000000000 --- a/devtools/create_project/msvc10/create_project.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "create_project", "create_project.vcxproj", "{CF177559-077D-4A08-AABE-BE0FD35F6C63}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.ActiveCfg = Debug|Win32 - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.Build.0 = Debug|Win32 - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.ActiveCfg = Release|Win32 - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/devtools/create_project/msvc10/create_project.vcxproj b/devtools/create_project/msvc10/create_project.vcxproj deleted file mode 100644 index bc6f634486b..00000000000 --- a/devtools/create_project/msvc10/create_project.vcxproj +++ /dev/null @@ -1,125 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {CF177559-077D-4A08-AABE-BE0FD35F6C63} - create_project - - - - Application - MultiByte - true - - - Application - MultiByte - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - - - - Disabled - true - EnableFastChecks - MultiThreadedDebugDLL - Level4 - EditAndContinue - false - 4003;4512;4127;4100;4244 - - - Rpcrt4.lib;%(AdditionalDependencies) - true - MachineX86 - - - @echo off -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc10\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc9\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\codeblocks\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\" - - - - - MaxSpeed - true - MultiThreadedDLL - true - Level3 - ProgramDatabase - 4003;4512;4127 - - - Rpcrt4.lib;%(AdditionalDependencies) - true - true - true - MachineX86 - - - @echo off -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc10\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc9\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\codeblocks\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/devtools/create_project/msvc10/create_project.vcxproj.filters b/devtools/create_project/msvc10/create_project.vcxproj.filters deleted file mode 100644 index b4f0b187745..00000000000 --- a/devtools/create_project/msvc10/create_project.vcxproj.filters +++ /dev/null @@ -1,71 +0,0 @@ - - - - - {2e3580c8-ec3a-4c81-8351-b668c668db2a} - - - {31aaf58c-d3cb-4ed6-8eca-163b4a9b31a6} - - - {f980f6fb-41b6-4161-b035-58b200c85cad} - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - scripts - - - scripts - - - scripts - - - scripts - - - diff --git a/devtools/create_project/msvc11/create_project.sln b/devtools/create_project/msvc11/create_project.sln deleted file mode 100644 index 1552c9f502f..00000000000 --- a/devtools/create_project/msvc11/create_project.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2012 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "create_project", "create_project.vcxproj", "{CF177559-077D-4A08-AABE-BE0FD35F6C63}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.ActiveCfg = Debug|Win32 - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.Build.0 = Debug|Win32 - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.ActiveCfg = Release|Win32 - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/devtools/create_project/msvc11/create_project.vcxproj b/devtools/create_project/msvc11/create_project.vcxproj deleted file mode 100644 index 74fa93730b2..00000000000 --- a/devtools/create_project/msvc11/create_project.vcxproj +++ /dev/null @@ -1,131 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {CF177559-077D-4A08-AABE-BE0FD35F6C63} - create_project - $(VCTargetsPath11) - - - - Application - MultiByte - true - v110 - - - Application - MultiByte - v110 - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - - - - Disabled - true - EnableFastChecks - MultiThreadedDebugDLL - Level4 - EditAndContinue - false - 4003;4512;4127;4100;4244 - - - Rpcrt4.lib;%(AdditionalDependencies) - true - MachineX86 - false - - - @echo off -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc11\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc10\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc9\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\codeblocks\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\" - - - - - MaxSpeed - true - MultiThreadedDLL - true - Level3 - ProgramDatabase - 4003;4512;4127 - - - Rpcrt4.lib;%(AdditionalDependencies) - true - true - true - MachineX86 - - - @echo off -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc11\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc10\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc9\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\codeblocks\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/devtools/create_project/msvc11/create_project.vcxproj.filters b/devtools/create_project/msvc11/create_project.vcxproj.filters deleted file mode 100644 index b4f0b187745..00000000000 --- a/devtools/create_project/msvc11/create_project.vcxproj.filters +++ /dev/null @@ -1,71 +0,0 @@ - - - - - {2e3580c8-ec3a-4c81-8351-b668c668db2a} - - - {31aaf58c-d3cb-4ed6-8eca-163b4a9b31a6} - - - {f980f6fb-41b6-4161-b035-58b200c85cad} - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - scripts - - - scripts - - - scripts - - - scripts - - - diff --git a/devtools/create_project/msvc12/create_project.sln b/devtools/create_project/msvc12/create_project.sln deleted file mode 100644 index 759d5430f55..00000000000 --- a/devtools/create_project/msvc12/create_project.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "create_project", "create_project.vcxproj", "{CF177559-077D-4A08-AABE-BE0FD35F6C63}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.ActiveCfg = Debug|Win32 - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.Build.0 = Debug|Win32 - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.ActiveCfg = Release|Win32 - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/devtools/create_project/msvc12/create_project.vcxproj b/devtools/create_project/msvc12/create_project.vcxproj deleted file mode 100644 index f8afe4c0e4a..00000000000 --- a/devtools/create_project/msvc12/create_project.vcxproj +++ /dev/null @@ -1,132 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {CF177559-077D-4A08-AABE-BE0FD35F6C63} - create_project - $(VCTargetsPath11) - - - - Application - MultiByte - true - v120 - - - Application - MultiByte - v120 - - - - - - - - - - - - - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - - - - Disabled - true - EnableFastChecks - MultiThreadedDebugDLL - Level4 - EditAndContinue - false - 4003;4512;4127;4100;4244 - - - Rpcrt4.lib;%(AdditionalDependencies) - true - MachineX86 - false - - - @echo off -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc12\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc11\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc10\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc9\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\codeblocks\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\" - - - - - MaxSpeed - true - MultiThreadedDLL - true - Level3 - ProgramDatabase - 4003;4512;4127 - - - Rpcrt4.lib;%(AdditionalDependencies) - true - true - true - MachineX86 - - - @echo off -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc12\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc11\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc10\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc9\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\codeblocks\" -xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/devtools/create_project/msvc12/create_project.vcxproj.filters b/devtools/create_project/msvc12/create_project.vcxproj.filters deleted file mode 100644 index 436d1d3436b..00000000000 --- a/devtools/create_project/msvc12/create_project.vcxproj.filters +++ /dev/null @@ -1,71 +0,0 @@ - - - - - {2e3580c8-ec3a-4c81-8351-b668c668db2a} - - - {31aaf58c-d3cb-4ed6-8eca-163b4a9b31a6} - - - {f980f6fb-41b6-4161-b035-58b200c85cad} - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - scripts - - - scripts - - - scripts - - - scripts - - - diff --git a/devtools/create_project/msvc9/create_project.sln b/devtools/create_project/msvc9/create_project.sln deleted file mode 100644 index df754e1d789..00000000000 --- a/devtools/create_project/msvc9/create_project.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "create_project", "create_project.vcproj", "{CF177559-077D-4A08-AABE-BE0FD35F6C63}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.ActiveCfg = Debug|Win32 - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.Build.0 = Debug|Win32 - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.ActiveCfg = Release|Win32 - {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/devtools/create_project/msvc9/create_project.vcproj b/devtools/create_project/msvc9/create_project.vcproj deleted file mode 100644 index 0069f2ab9cb..00000000000 --- a/devtools/create_project/msvc9/create_project.vcproj +++ /dev/null @@ -1,260 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp index 83bee297241..d220abf55ac 100644 --- a/engines/advancedDetector.cpp +++ b/engines/advancedDetector.cpp @@ -289,15 +289,11 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) if (!agdDesc.desc) return Common::kNoGameDataFoundError; + DetectedGame gameDescriptor = toDetectedGame(agdDesc); + // If the GUI options were updated, we catch this here and update them in the users config // file transparently. - Common::String lang = getGameGUIOptionsDescriptionLanguage(agdDesc.desc->language); - if (agdDesc.desc->flags & ADGF_ADDENGLISH) - lang += " " + getGameGUIOptionsDescriptionLanguage(Common::EN_ANY); - - Common::updateGameGUIOptions(agdDesc.desc->guiOptions + _guiOptions, lang); - - DetectedGame gameDescriptor = toDetectedGame(agdDesc); + ConfMan.setAndFlush("guioptions", gameDescriptor.getGUIOptions()); bool showTestingWarning = false; diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h index ee15368d2eb..ee8b7cbfd78 100644 --- a/engines/advancedDetector.h +++ b/engines/advancedDetector.h @@ -317,7 +317,7 @@ protected: bool getFileProperties(const Common::FSNode &parent, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, FileProperties &fileProps) const; /** Convert an AD game description into the shared game description format */ - DetectedGame toDetectedGame(const ADDetectedGame &adGame) const; + virtual DetectedGame toDetectedGame(const ADDetectedGame &adGame) const; }; #endif diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp index bbf766dda21..d7076e34204 100644 --- a/engines/dialogs.cpp +++ b/engines/dialogs.cpp @@ -90,10 +90,10 @@ MainMenuDialog::MainMenuDialog(Engine *engine) new GUI::ButtonWidget(this, "GlobalMenu.About", _("~A~bout"), 0, kAboutCmd); if (g_system->getOverlayWidth() > 320) - _rtlButton = new GUI::ButtonWidget(this, "GlobalMenu.RTL", _("~R~eturn to Launcher"), 0, kRTLCmd); + _returnToLauncherButton = new GUI::ButtonWidget(this, "GlobalMenu.ReturnToLauncher", _("~R~eturn to Launcher"), 0, kLauncherCmd); else - _rtlButton = new GUI::ButtonWidget(this, "GlobalMenu.RTL", _c("~R~eturn to Launcher", "lowres"), 0, kRTLCmd); - _rtlButton->setEnabled(_engine->hasFeature(Engine::kSupportsRTL)); + _returnToLauncherButton = new GUI::ButtonWidget(this, "GlobalMenu.ReturnToLauncher", _c("~R~eturn to Launcher", "lowres"), 0, kLauncherCmd); + _returnToLauncherButton->setEnabled(_engine->hasFeature(Engine::kSupportsReturnToLauncher)); if (!g_system->hasFeature(OSystem::kFeatureNoQuit)) new GUI::ButtonWidget(this, "GlobalMenu.Quit", _("~Q~uit"), 0, kQuitCmd); @@ -136,10 +136,10 @@ void MainMenuDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint3 dialog.runModal(); } break; - case kRTLCmd: { - Common::Event eventRTL; - eventRTL.type = Common::EVENT_RTL; - g_system->getEventManager()->pushEvent(eventRTL); + case kLauncherCmd: { + Common::Event eventReturnToLauncher; + eventReturnToLauncher.type = Common::EVENT_RETURN_TO_LAUNCHER; + g_system->getEventManager()->pushEvent(eventReturnToLauncher); close(); } break; @@ -166,9 +166,9 @@ void MainMenuDialog::reflowLayout() { // FIXME: it might be better to declare GUI::StaticTextWidget::setLabel() virtual // and to reimplement it in GUI::ButtonWidget to handle the hotkey. if (g_system->getOverlayWidth() > 320) - _rtlButton->setLabel(_rtlButton->cleanupHotkey(_("~R~eturn to Launcher"))); + _returnToLauncherButton->setLabel(_returnToLauncherButton->cleanupHotkey(_("~R~eturn to Launcher"))); else - _rtlButton->setLabel(_rtlButton->cleanupHotkey(_c("~R~eturn to Launcher", "lowres"))); + _returnToLauncherButton->setLabel(_returnToLauncherButton->cleanupHotkey(_c("~R~eturn to Launcher", "lowres"))); #ifndef DISABLE_FANCY_THEMES if (g_gui.xmlEval()->getVar("Globals.ShowGlobalMenuLogo", 0) == 1 && g_gui.theme()->supportsImages()) { diff --git a/engines/dialogs.h b/engines/dialogs.h index 5a8e941b5ae..620812beea6 100644 --- a/engines/dialogs.h +++ b/engines/dialogs.h @@ -46,7 +46,7 @@ public: kHelpCmd = 'HELP', kAboutCmd = 'ABOU', kQuitCmd = 'QUIT', - kRTLCmd = 'RTL ', + kLauncherCmd = 'LNCR', kChooseCmd = 'CHOS' }; @@ -67,7 +67,7 @@ protected: GUI::GraphicsWidget *_logo; - GUI::ButtonWidget *_rtlButton; + GUI::ButtonWidget *_returnToLauncherButton; GUI::ButtonWidget *_loadButton; GUI::ButtonWidget *_saveButton; GUI::ButtonWidget *_helpButton; diff --git a/engines/engine.cpp b/engines/engine.cpp index ff9243c38bd..c1792b69421 100644 --- a/engines/engine.cpp +++ b/engines/engine.cpp @@ -530,18 +530,25 @@ void Engine::errorString(const char *buf1, char *buf2, int size) { Common::strlcpy(buf2, buf1, size); } -void Engine::pauseEngine(bool pause) { - assert((pause && _pauseLevel >= 0) || (!pause && _pauseLevel)); +PauseToken Engine::pauseEngine() { + assert(_pauseLevel >= 0); - if (pause) - _pauseLevel++; - else - _pauseLevel--; + _pauseLevel++; - if (_pauseLevel == 1 && pause) { + if (_pauseLevel == 1) { _pauseStartTime = _system->getMillis(); pauseEngineIntern(true); - } else if (_pauseLevel == 0) { + } + + return PauseToken(this); +} + +void Engine::resumeEngine() { + assert(_pauseLevel > 0); + + _pauseLevel--; + + if (_pauseLevel == 0) { pauseEngineIntern(false); _engineStartTime += _system->getMillis() - _pauseStartTime; _pauseStartTime = 0; @@ -558,8 +565,10 @@ void Engine::openMainMenuDialog() { _mainMenuDialog = new MainMenuDialog(this); #ifdef USE_TTS Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager(); - ttsMan->pushState(); - g_gui.initTextToSpeech(); + if (ttsMan != nullptr) { + ttsMan->pushState(); + g_gui.initTextToSpeech(); + } #endif setGameToLoadSlot(-1); @@ -584,7 +593,8 @@ void Engine::openMainMenuDialog() { applyGameSettings(); syncSoundSettings(); #ifdef USE_TTS - ttsMan->popState(); + if (ttsMan != nullptr) + ttsMan->popState(); #endif } @@ -618,9 +628,8 @@ void Engine::setTotalPlayTime(uint32 time) { } int Engine::runDialog(GUI::Dialog &dialog) { - pauseEngine(true); + PauseToken pt = pauseEngine(); int result = dialog.runModal(); - pauseEngine(false); return result; } @@ -738,9 +747,13 @@ bool Engine::loadGameDialog() { } GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load"), false); - pauseEngine(true); - int slotNum = dialog->runModalWithCurrentTarget(); - pauseEngine(false); + + int slotNum; + { + PauseToken pt = pauseEngine(); + slotNum = dialog->runModalWithCurrentTarget(); + } + delete dialog; if (slotNum < 0) @@ -763,9 +776,11 @@ bool Engine::saveGameDialog() { } GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); - pauseEngine(true); - int slotNum = dialog->runModalWithCurrentTarget(); - pauseEngine(false); + int slotNum; + { + PauseToken pt = pauseEngine(); + slotNum = dialog->runModalWithCurrentTarget(); + } Common::String desc = dialog->getResultString(); if (desc.empty()) @@ -795,7 +810,7 @@ void Engine::quitGame() { bool Engine::shouldQuit() { Common::EventManager *eventMan = g_system->getEventManager(); - return (eventMan->shouldQuit() || eventMan->shouldRTL()); + return (eventMan->shouldQuit() || eventMan->shouldReturnToLauncher()); } GUI::Debugger *Engine::getOrCreateDebugger() { @@ -819,3 +834,51 @@ MetaEngine &Engine::getMetaEngine() { assert(plugin); return plugin->get(); } + +PauseToken::PauseToken() : _engine(nullptr) {} + +PauseToken::PauseToken(Engine *engine) : _engine(engine) {} + +void PauseToken::operator=(const PauseToken &t2) { + if (_engine) { + error("Tried to assign to an already busy PauseToken"); + } + _engine = t2._engine; + if (_engine) { + _engine->_pauseLevel++; + } +} + +PauseToken::PauseToken(const PauseToken &t2) : _engine(t2._engine) { + if (_engine) { + _engine->_pauseLevel++; + } +} + +void PauseToken::clear() { + if (!_engine) { + error("Tried to clear an already cleared PauseToken"); + } + _engine->resumeEngine(); + _engine = nullptr; +} + +PauseToken::~PauseToken() { + if (_engine) { + _engine->resumeEngine(); + } +} + +#if __cplusplus >= 201103L +PauseToken::PauseToken(PauseToken &&t2) : _engine(t2._engine) { + t2._engine = nullptr; +} + +void PauseToken::operator=(PauseToken &&t2) { + if (_engine) { + error("Tried to assign to an already busy PauseToken"); + } + _engine = t2._engine; + t2._engine = nullptr; +} +#endif diff --git a/engines/engine.h b/engines/engine.h index 0275cb0368a..e005bd1a58a 100644 --- a/engines/engine.h +++ b/engines/engine.h @@ -56,6 +56,37 @@ class Dialog; void GUIErrorMessage(const Common::String &msg); void GUIErrorMessageFormat(const char *fmt, ...) GCC_PRINTF(1, 2); +class Engine; + + +/** +* Manages pausing by Engine::pauseEngine handing out tokens that +* each represent one requested level of pause. +*/ +class PauseToken { +public: + PauseToken(); + PauseToken(const PauseToken &); +#if __cplusplus >= 201103L + PauseToken(PauseToken &&); +#endif + ~PauseToken(); + + void operator=(const PauseToken &); +#if __cplusplus >= 201103L + void operator=(PauseToken &&); +#endif + /** Manually releases the PauseToken. Only allowed if the token + * currently represents a pause request. + */ + void clear(); +private: + PauseToken(Engine *); + + Engine *_engine; + + friend class Engine; +}; class Engine { public: @@ -129,11 +160,11 @@ public: kSupportsSubtitleOptions, /** - * 'Return to launcher' feature is supported, i.e., EVENT_RTL is handled + * 'Return to launcher' feature is supported, i.e., EVENT_RETURN_TO_LAUNCHER is handled * either directly, or indirectly (that is, the engine calls and honors * the result of the Engine::shouldQuit() method appropriately). */ - kSupportsRTL, + kSupportsReturnToLauncher, /** * Loading savestates during runtime is supported, that is, this engine @@ -354,17 +385,25 @@ public: static MetaEngine &getMetaEngine(); /** - * Pause or resume the engine. This should stop/resume any audio playback + * Pause the engine. This should stop any audio playback * and other stuff. Called right before the system runs a global dialog * (like a global pause, main menu, options or 'confirm exit' dialog). * - * This is a convenience tracker which automatically keeps track on how - * often the engine has been paused, ensuring that after pausing an engine - * e.g. twice, it has to be unpaused twice before actuallying resuming. - * - * @param pause true to pause the engine, false to resume it + * Returns a PauseToken. Multiple pause tokens may exist. The engine will + * be resumed when all associated pause tokens reach the end of their lives. */ - void pauseEngine(bool pause); + PauseToken pauseEngine(); +private: + /** Resume the engine. This should resume any audio playback and other stuff. + * + * Only PauseToken is allowed to call this member function. Use the PauseToken + * that you got from pauseEngine to resume the engine. + */ + void resumeEngine(); + + friend class PauseToken; + +public: /** * Return whether the engine is currently paused or not. diff --git a/engines/grim/grim.cpp b/engines/grim/grim.cpp index d9e3a1ac6b1..a2ee56ef377 100644 --- a/engines/grim/grim.cpp +++ b/engines/grim/grim.cpp @@ -1382,7 +1382,7 @@ void GrimEngine::clearEventQueue() { bool GrimEngine::hasFeature(EngineFeature f) const { return - (f == kSupportsRTL) || + (f == kSupportsReturnToLauncher) || (f == kSupportsLoadingDuringRuntime) || (f == kSupportsJoystick); } diff --git a/engines/myst3/myst3.cpp b/engines/myst3/myst3.cpp index c32862815a1..4f29bd47625 100644 --- a/engines/myst3/myst3.cpp +++ b/engines/myst3/myst3.cpp @@ -138,7 +138,7 @@ bool Myst3Engine::hasFeature(EngineFeature f) const { bool softRenderer = matchingRendererType == Graphics::kRendererTypeTinyGL; return - (f == kSupportsRTL) || + (f == kSupportsReturnToLauncher) || (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime) || (f == kSupportsArbitraryResolutions && !softRenderer); diff --git a/engines/stark/services/userinterface.cpp b/engines/stark/services/userinterface.cpp index 8c907fb6220..f85bdcb57b2 100644 --- a/engines/stark/services/userinterface.cpp +++ b/engines/stark/services/userinterface.cpp @@ -521,8 +521,12 @@ void UserInterface::handleKeyPress(const Common::KeyState &keyState) { confirm(GameMessage::kQuitPrompt, this, &UserInterface::notifyShouldExit); } else if (keyState.keycode == Common::KEYCODE_p) { if (isInGameScreen()) { - g_engine->pauseEngine(true); - debug("The game is paused"); + if (g_engine->isPaused()) { + _gamePauseToken.clear(); + } else { + _gamePauseToken = g_engine->pauseEngine(); + debug("The game is paused"); + } } } else if (keyState.keycode == Common::KEYCODE_PAGEUP) { if (isInGameScreen()) { diff --git a/engines/stark/services/userinterface.h b/engines/stark/services/userinterface.h index 13e30b6bc77..fe4746548fa 100644 --- a/engines/stark/services/userinterface.h +++ b/engines/stark/services/userinterface.h @@ -27,6 +27,8 @@ #include "engines/stark/services/gamemessage.h" +#include "engines/engine.h" + #include "common/keyboard.h" #include "common/rect.h" #include "common/str-array.h" @@ -215,6 +217,7 @@ private: Gfx::Driver *_gfx; bool _exitGame; bool _quitToMainMenu; + PauseToken _gamePauseToken; bool _interactive; bool _interactionAttemptDenied; diff --git a/engines/stark/stark.cpp b/engines/stark/stark.cpp index a9c42a5175a..8d3520a44fb 100644 --- a/engines/stark/stark.cpp +++ b/engines/stark/stark.cpp @@ -187,7 +187,7 @@ void StarkEngine::processEvents() { if (isPaused()) { // Only pressing key P to resume the game is allowed when the game is paused if (e.type == Common::EVENT_KEYDOWN && e.kbd.keycode == Common::KEYCODE_p) { - pauseEngine(false); + _gamePauseToken.clear(); } continue; } @@ -202,7 +202,7 @@ void StarkEngine::processEvents() { StarkGfx->toggleFullscreen(); } else if (e.kbd.keycode == Common::KEYCODE_p) { if (StarkUserInterface->isInGameScreen()) { - pauseEngine(true); + _gamePauseToken = pauseEngine(); debug("The game is paused"); } } else { @@ -341,7 +341,7 @@ bool StarkEngine::hasFeature(EngineFeature f) const { (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime) || (f == kSupportsArbitraryResolutions) || - (f == kSupportsRTL); + (f == kSupportsReturnToLauncher); } bool StarkEngine::canLoadGameStateCurrently() { diff --git a/engines/stark/stark.h b/engines/stark/stark.h index 49cc59e17d1..54638a42333 100644 --- a/engines/stark/stark.h +++ b/engines/stark/stark.h @@ -89,6 +89,7 @@ private: static void checkRecommendedDatafiles(); Gfx::FrameLimiter *_frameLimiter; + PauseToken _gamePauseToken; const ADGameDescription *_gameDescription; diff --git a/engines/wintermute/POTFILES b/engines/wintermute/POTFILES index 79f5c5dfed3..bf8833fed44 100644 --- a/engines/wintermute/POTFILES +++ b/engines/wintermute/POTFILES @@ -1,2 +1,3 @@ engines/wintermute/detection.cpp engines/wintermute/wintermute.cpp +engines/wintermute/keymapper_tables.h diff --git a/engines/wintermute/ad/ad_game.cpp b/engines/wintermute/ad/ad_game.cpp index 38f5c8bb95b..1a09a6da3eb 100644 --- a/engines/wintermute/ad/ad_game.cpp +++ b/engines/wintermute/ad/ad_game.cpp @@ -440,6 +440,17 @@ bool AdGame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, stack->correctParams(1); ScValue *val = stack->pop(); AdObject *obj = (AdObject *)val->getNative(); + + // HACK: We take corrosion screenshot before entering main menu + // Unused screenshots must be deleted, after main menu is closed + if (obj && BaseEngine::instance().getGameId() == "corrosion") { + const char *mm = "interface\\system\\mainmenu.window"; + const char *fn = obj->getFilename(); + if (fn && strcmp(fn, mm) == 0) { + deleteSaveThumbnail(); + } + } + removeObject(obj); if (val->getType() == VAL_VARIABLE_REF) { val->setNULL(); diff --git a/engines/wintermute/ad/ad_scene.cpp b/engines/wintermute/ad/ad_scene.cpp index 55b8e9e0beb..a86e4a2a192 100644 --- a/engines/wintermute/ad/ad_scene.cpp +++ b/engines/wintermute/ad/ad_scene.cpp @@ -94,7 +94,6 @@ void AdScene::setDefaults() { _pfTargetPath = nullptr; _pfRequester = nullptr; _mainLayer = nullptr; - #ifdef ENABLE_WME3D _sceneGeometry = nullptr; _showGeometry = false; @@ -191,7 +190,6 @@ void AdScene::cleanup() { _gameRef->unregisterObject(_objects[i]); } _objects.clear(); - #ifdef ENABLE_WME3D delete _sceneGeometry; #endif @@ -552,7 +550,6 @@ bool AdScene::initLoop() { return _sceneGeometry->initLoop(); } #endif - return STATUS_OK; } @@ -1239,7 +1236,6 @@ bool AdScene::updateFreeObjects() { } } #endif - adGame->_objects[i]->update(); adGame->_objects[i]->_drawn = false; } @@ -1249,7 +1245,6 @@ bool AdScene::updateFreeObjects() { if (!_objects[i]->_active) { continue; } - #ifdef ENABLE_WME3D if (_objects[i]->_is3D && _sceneGeometry) { Camera3D* activeCamera = _sceneGeometry->getActiveCamera(); @@ -1355,8 +1350,6 @@ bool AdScene::compareObjs(const AdObject *obj1, const AdObject *obj2) { ////////////////////////////////////////////////////////////////////////// bool AdScene::displayRegionContentOld(AdRegion *region) { - // is this function actually used? - AdGame *adGame = (AdGame *)_gameRef; AdObject *obj; diff --git a/engines/wintermute/ad/ad_scene.h b/engines/wintermute/ad/ad_scene.h index 96ae61dea14..dcb0d7ec64d 100644 --- a/engines/wintermute/ad/ad_scene.h +++ b/engines/wintermute/ad/ad_scene.h @@ -47,7 +47,6 @@ class AdPathPoint; #ifdef ENABLE_WME3D class AdSceneGeometry; #endif - class AdScene : public BaseObject { public: diff --git a/engines/wintermute/base/base_active_rect.cpp b/engines/wintermute/base/base_active_rect.cpp index 0f24975cfb7..2cf8bcffef3 100644 --- a/engines/wintermute/base/base_active_rect.cpp +++ b/engines/wintermute/base/base_active_rect.cpp @@ -86,7 +86,6 @@ BaseActiveRect::BaseActiveRect(BaseGame *inGame, BaseObject *owner, ModelX *mode } #endif - ////////////////////////////////////////////////////////////////////// BaseActiveRect::~BaseActiveRect() { _owner = nullptr; diff --git a/engines/wintermute/base/base_engine.h b/engines/wintermute/base/base_engine.h index 723bb1701fe..901a678ed17 100644 --- a/engines/wintermute/base/base_engine.h +++ b/engines/wintermute/base/base_engine.h @@ -78,6 +78,10 @@ enum WMETargetExecutable { WME_1_8_8, // DEAD:CODE 2008, released as "1.8.8 beta" WME_1_8_9, // DEAD:CODE 2008, released as "1.8.9 beta" WME_1_8_10, // DEAD:CODE 2009 + + // fork of WME_1_8_10 + WME_ANDISHE_VARAN, // Andishe Varan Engine 1.0.0.0 + WME_1_8_11, // DEAD:CODE 2009 WME_1_9_0, // DEAD:CODE 2009, released as "1.9.0 beta" @@ -115,6 +119,8 @@ enum WMETargetExecutable { FOXTAIL_1_2_304, FOXTAIL_1_2_362, FOXTAIL_1_2_527, + FOXTAIL_1_2_896, + FOXTAIL_1_2_902, FOXTAIL_LATEST_VERSION }; @@ -168,6 +174,7 @@ public: bool isFoxTail(WMETargetExecutable v1=FOXTAIL_OLDEST_VERSION, WMETargetExecutable v2=FOXTAIL_LATEST_VERSION) const { return isFoxTailCheck(_targetExecutable, v1, v2); } + void addFlags(uint32 flags) { _flags |= flags; } }; } // End of namespace Wintermute diff --git a/engines/wintermute/base/base_file_manager.cpp b/engines/wintermute/base/base_file_manager.cpp index 09c04e0c500..f99977a31e1 100644 --- a/engines/wintermute/base/base_file_manager.cpp +++ b/engines/wintermute/base/base_file_manager.cpp @@ -395,10 +395,24 @@ bool BaseFileManager::hasFile(const Common::String &filename) { return false; } -int BaseFileManager::listMatchingMembers(Common::ArchiveMemberList &list, const Common::String &pattern) { +////////////////////////////////////////////////////////////////////////// +int BaseFileManager::listMatchingPackageMembers(Common::ArchiveMemberList &list, const Common::String &pattern) { return _packages.listMatchingMembers(list, pattern); } +////////////////////////////////////////////////////////////////////////// +int BaseFileManager::listMatchingFiles(Common::StringArray &list, const Common::String &pattern) { + list = sfmFileList(pattern); + + Common::ArchiveMemberList files; + listMatchingDiskFileMembers(files, pattern); + for (Common::ArchiveMemberList::const_iterator it = files.begin(); it != files.end(); ++it) { + list.push_back((*it)->getName()); + } + + return list.size(); +} + ////////////////////////////////////////////////////////////////////////// Common::SeekableReadStream *BaseFileManager::openFile(const Common::String &filename, bool absPathWarning, bool keepTrackOf) { if (strcmp(filename.c_str(), "") == 0) { diff --git a/engines/wintermute/base/base_file_manager.h b/engines/wintermute/base/base_file_manager.h index 397e38cc3db..de4f761a932 100644 --- a/engines/wintermute/base/base_file_manager.h +++ b/engines/wintermute/base/base_file_manager.h @@ -31,6 +31,7 @@ #include "common/archive.h" #include "common/str.h" +#include "common/str-array.h" #include "common/fs.h" #include "common/file.h" #include "common/language.h" @@ -42,7 +43,8 @@ public: bool closeFile(Common::SeekableReadStream *File); bool hasFile(const Common::String &filename); - int listMatchingMembers(Common::ArchiveMemberList &list, const Common::String &pattern); + int listMatchingPackageMembers(Common::ArchiveMemberList &list, const Common::String &pattern); + int listMatchingFiles(Common::StringArray &list, const Common::String &pattern); Common::SeekableReadStream *openFile(const Common::String &filename, bool absPathWarning = true, bool keepTrackOf = true); Common::WriteStream *openFileForWrite(const Common::String &filename); byte *readWholeFile(const Common::String &filename, uint32 *size = nullptr, bool mustExist = true); diff --git a/engines/wintermute/base/base_game.cpp b/engines/wintermute/base/base_game.cpp index 760fbc6c047..435fdba48de 100644 --- a/engines/wintermute/base/base_game.cpp +++ b/engines/wintermute/base/base_game.cpp @@ -36,7 +36,9 @@ #include "engines/wintermute/base/font/base_font.h" #include "engines/wintermute/base/font/base_font_storage.h" #include "engines/wintermute/base/gfx/base_renderer.h" +#ifdef ENABLE_WME3D #include "engines/wintermute/base/gfx/opengl/base_render_opengl3d.h" +#endif #include "engines/wintermute/base/base_keyboard_state.h" #include "engines/wintermute/base/base_parser.h" #include "engines/wintermute/base/base_quick_msg.h" @@ -55,6 +57,7 @@ #include "engines/wintermute/base/scriptables/script_stack.h" #include "engines/wintermute/base/scriptables/script.h" #include "engines/wintermute/base/sound/base_sound.h" +#include "engines/wintermute/ext/plugins.h" #include "engines/wintermute/video/video_player.h" #include "engines/wintermute/video/video_theora_player.h" #include "engines/wintermute/utils/utils.h" @@ -252,8 +255,6 @@ BaseGame::~BaseGame() { cleanup(); - delete _cachedThumbnail; - delete _mathClass; delete _directoryClass; @@ -270,8 +271,6 @@ BaseGame::~BaseGame() { delete _musicSystem; delete _settings; - _cachedThumbnail = nullptr; - _mathClass = nullptr; _directoryClass = nullptr; @@ -302,6 +301,8 @@ bool BaseGame::cleanup() { delete _loadingIcon; _loadingIcon = nullptr; + deleteSaveThumbnail(); + _engineLogCallback = nullptr; _engineLogCallbackData = nullptr; @@ -1443,6 +1444,19 @@ bool BaseGame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack return STATUS_OK; } + + ////////////////////////////////////////////////////////////////////////// + // [FoxTail] ValidSaveSlotVersion + // Checks if given slot stores game state of compatible game version + // This version always returs true + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "ValidSaveSlotVersion") == 0) { + stack->correctParams(1); + /* int slot = */ stack->pop()->getInt(); + // do nothing + stack->pushBool(true); + return STATUS_OK; + } #endif ////////////////////////////////////////////////////////////////////////// @@ -1624,6 +1638,13 @@ bool BaseGame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack byte blue = stack->pop()->getInt(0); byte alpha = stack->pop()->getInt(0xFF); + // HACK: Corrosion fades screen to black while opening main menu + // Thus, we get black screenshots when saving game from in-game menus + // Let's take & keep screenshot before entering main menu + if (duration == 750 && BaseEngine::instance().getGameId() == "corrosion") { + storeSaveThumbnail(); + } + bool system = (strcmp(name, "SystemFadeOut") == 0 || strcmp(name, "SystemFadeOutAsync") == 0); _fader->fadeOut(BYTETORGBA(red, green, blue, alpha), duration, system); @@ -1929,16 +1950,7 @@ bool BaseGame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "StoreSaveThumbnail") == 0) { stack->correctParams(0); - delete _cachedThumbnail; - _cachedThumbnail = new SaveThumbHelper(this); - if (DID_FAIL(_cachedThumbnail->storeThumbnail())) { - delete _cachedThumbnail; - _cachedThumbnail = nullptr; - stack->pushBool(false); - } else { - stack->pushBool(true); - } - + stack->pushBool(storeSaveThumbnail()); return STATUS_OK; } @@ -1947,10 +1959,8 @@ bool BaseGame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "DeleteSaveThumbnail") == 0) { stack->correctParams(0); - delete _cachedThumbnail; - _cachedThumbnail = nullptr; + deleteSaveThumbnail(); stack->pushNULL(); - return STATUS_OK; } @@ -2192,6 +2202,32 @@ bool BaseGame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack return STATUS_OK; } + + ////////////////////////////////////////////////////////////////////////// + // [FoxTail] GetFiles + // Used at kalimba.script on F9 keypress to reload list of available music + // Known params: "*.mb" + // Original implementation does not seem to look up at DCP packages + // This implementation looks up at savegame storage and for actual files + // Return value expected to be an Array of Strings + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "GetFiles") == 0) { + stack->correctParams(1); + const char *pattern = stack->pop()->getString(); + + Common::StringArray fnames; + BaseFileManager::getEngineInstance()->listMatchingFiles(fnames, pattern); + + stack->pushInt(0); + BaseScriptable *arr = makeSXArray(_gameRef, stack); + for (uint32 i = 0; i < fnames.size(); i++) { + stack->pushString(fnames[i].c_str()); + ((SXArray *)arr)->push(stack->pop()); + } + + stack->pushNative(arr, false); + return STATUS_OK; + } #endif ////////////////////////////////////////////////////////////////////////// @@ -2675,6 +2711,10 @@ ScValue *BaseGame::scGetProperty(const Common::String &name) { _scValue->setString("1.2.362"); } else if (BaseEngine::instance().getTargetExecutable() == FOXTAIL_1_2_527) { _scValue->setString("1.2.527"); + } else if (BaseEngine::instance().getTargetExecutable() == FOXTAIL_1_2_896) { + _scValue->setString("1.2.896"); + } else if (BaseEngine::instance().getTargetExecutable() == FOXTAIL_1_2_902) { + _scValue->setString("1.2.902"); } else { _scValue->setString("UNKNOWN"); } @@ -3158,26 +3198,6 @@ bool BaseGame::externalCall(ScScript *script, ScStack *stack, ScStack *thisStack stack->pushNULL(); } - ////////////////////////////////////////////////////////////////////////// - // SteamAPI - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(name, "SteamAPI") == 0) { - thisObj = thisStack->getTop(); - - thisObj->setNative(makeSXSteamAPI(_gameRef, stack)); - stack->pushNULL(); - } - - ////////////////////////////////////////////////////////////////////////// - // WMEGalaxyAPI - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(name, "WMEGalaxyAPI") == 0) { - thisObj = thisStack->getTop(); - - thisObj->setNative(makeSXWMEGalaxyAPI(_gameRef, stack)); - stack->pushNULL(); - } - ////////////////////////////////////////////////////////////////////////// // Object ////////////////////////////////////////////////////////////////////////// @@ -3388,18 +3408,43 @@ bool BaseGame::externalCall(ScScript *script, ScStack *stack, ScStack *thisStack } #ifdef ENABLE_FOXTAIL + ////////////////////////////////////////////////////////////////////////// + // [FoxTail] IsNumber + // Used at kalimba.script to check if string token is a number + // If true is returned, then ToInt() is called for same parameter + // ToInt(string) implementation is using atoi(), so let's use it here too + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "IsNumber") == 0) { + stack->correctParams(1); + ScValue *val = stack->pop(); + + bool result = false; + if (val->isInt() || val->isFloat()) { + result = true; + } else if (val->isString()) { + const char *str = val->getString(); + result = (atoi(str) != 0) || (strcmp(str, "0") == 0); + } + + stack->pushBool(result); + } + ////////////////////////////////////////////////////////////////////////// // [FoxTail] Split // Returns array of words of a string, using another as a delimeter - // Used to split strings by 1 character delimeter in various scripts - // All the delimeters ever used in FoxTail are: " ", "@", "#", "$", "&" - // So, this implementation takes 1st char of delimeter string only + // Used to split strings by 1-2 characters delimeter in various scripts + // All the delimeters ever used in FoxTail are: + // " ", "@", "#", "$", "&", ",", "\\", "@h", "@i", "@p", "@s" ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "Split") == 0) { stack->correctParams(2); const char *str = stack->pop()->getString(); - const char sep = stack->pop()->getString()[0]; - size_t size = strlen(str) + 1; + Common::String sep = stack->pop()->getString(); + uint32 size = strlen(str) + 1; + + // Let's make copies before modifying stack + char *copy = new char[size]; + strcpy(copy, str); // There is no way to makeSXArray() with exactly 1 given element // That's why we are creating empty Array and SXArray::push() later @@ -3407,15 +3452,17 @@ bool BaseGame::externalCall(ScScript *script, ScStack *stack, ScStack *thisStack BaseScriptable *arr = makeSXArray(_gameRef, stack); // Iterating string copy, replacing delimeter with '\0' and pushing matches - char *copy = new char[size]; - strcpy(copy, str); + // Only non-empty matches should be pushed char *begin = copy; for (char *it = copy; it < copy + size; it++) { - if (*it == sep || *it == '\0') { + if (strncmp(it, sep.c_str(), sep.size()) == 0 || *it == '\0') { *it = '\0'; - stack->pushString(begin); - ((SXArray *)arr)->push(stack->pop()); - begin = it + 1; + if (it != begin) { + stack->pushString(begin); + ((SXArray *)arr)->push(stack->pop()); + } + begin = it + sep.size(); + it = begin - 1; } } @@ -3423,8 +3470,38 @@ bool BaseGame::externalCall(ScScript *script, ScStack *stack, ScStack *thisStack delete[] copy; } + + ////////////////////////////////////////////////////////////////////////// + // [FoxTail] Trim / lTrim / rTrim + // Removes whitespaces from a string from the left & right + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Trim") == 0 || strcmp(name, "lTrim") == 0 || strcmp(name, "rTrim") == 0) { + stack->correctParams(1); + const char *str = stack->pop()->getString(); + char *copy = new char[strlen(str) + 1]; + strcpy(copy, str); + + char *ptr = copy; + if (strcmp(name, "rTrim") != 0) { + ptr = Common::ltrim(ptr); + } + if (strcmp(name, "lTrim") != 0) { + ptr = Common::rtrim(ptr); + } + + stack->pushString(ptr); + + delete[] copy; + } #endif + ////////////////////////////////////////////////////////////////////////// + // Plugins: emulate object constructors from known "wme_*.dll" plugins + ////////////////////////////////////////////////////////////////////////// + else if(!DID_FAIL(EmulatePluginCall(_gameRef, stack, thisStack, name))) { + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// // failure else { @@ -3723,6 +3800,59 @@ bool BaseGame::handleMouseWheel(int32 delta) { return true; } +////////////////////////////////////////////////////////////////////////// +bool BaseGame::handleCustomActionStart(BaseGameCustomAction action) { + if (BaseEngine::instance().getGameId() == "corrosion") { + // Keyboard walking is added, for both original game & Enhanced Edition + + // However, Enhanced Edition contain city map screen, which is + // mouse controlled and conflicts with those custom actions + const char *m = "items\\street_map\\windows\\street_map_window.script"; + if (_scEngine->isRunningScript(m)) { + return false; + } + + Point32 p; + switch (action) { + case kClickAtCenter: + p.x = _renderer->getWidth() / 2; + p.y = _renderer->getHeight() / 2; + break; + case kClickAtLeft: + p.x = 30; + p.y = _renderer->getHeight() / 2; + break; + case kClickAtRight: + p.x = _renderer->getWidth() - 30; + p.y = _renderer->getHeight() / 2; + break; + case kClickAtTop: + p.x = _renderer->getWidth() / 2; + p.y = 10; + break; + case kClickAtBottom: + p.x = _renderer->getWidth() / 2; + p.y = _renderer->getHeight(); + p.y -= ConfMan.get("extra").contains("Enhanced") ? 35 : 90; + break; + default: + return false; + } + + BasePlatform::setCursorPos(p.x, p.y); + setActiveObject(_gameRef->_renderer->getObjectAt(p.x, p.y)); + onMouseLeftDown(); + onMouseLeftUp(); + return true; + } + + return false; +} + +////////////////////////////////////////////////////////////////////////// +bool BaseGame::handleCustomActionEnd(BaseGameCustomAction action) { + return false; +} ////////////////////////////////////////////////////////////////////////// bool BaseGame::getVersion(byte *verMajor, byte *verMinor, byte *extMajor, byte *extMinor) const { @@ -4011,6 +4141,23 @@ bool BaseGame::drawCursor(BaseSprite *cursor) { return cursor->draw(_mousePos.x, _mousePos.y); } +////////////////////////////////////////////////////////////////////////// +bool BaseGame::storeSaveThumbnail() { + delete _cachedThumbnail; + _cachedThumbnail = new SaveThumbHelper(this); + if (DID_FAIL(_cachedThumbnail->storeThumbnail())) { + deleteSaveThumbnail(); + return false; + } + return true; +} + +////////////////////////////////////////////////////////////////////////// +void BaseGame::deleteSaveThumbnail() { + delete _cachedThumbnail; + _cachedThumbnail = nullptr; +} + ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// diff --git a/engines/wintermute/base/base_game.h b/engines/wintermute/base/base_game.h index e3581aba310..bcee4747279 100644 --- a/engines/wintermute/base/base_game.h +++ b/engines/wintermute/base/base_game.h @@ -30,6 +30,7 @@ #define WINTERMUTE_BASE_GAME_H #include "engines/wintermute/base/base_object.h" +#include "engines/wintermute/base/base_game_custom_actions.h" #include "engines/wintermute/base/timer.h" #include "engines/wintermute/persistent.h" #include "engines/wintermute/coll_templ.h" @@ -210,6 +211,8 @@ public: bool handleKeypress(Common::Event *event, bool printable = false) override; virtual void handleKeyRelease(Common::Event *event); + bool handleCustomActionStart(BaseGameCustomAction action); + bool handleCustomActionEnd(BaseGameCustomAction action); bool unfreeze(); bool freeze(bool includingMusic = true); @@ -267,6 +270,8 @@ public: bool setActiveObject(BaseObject *Obj); BaseSprite *_lastCursor; bool drawCursor(BaseSprite *Cursor); + bool storeSaveThumbnail(); + void deleteSaveThumbnail(); SaveThumbHelper *_cachedThumbnail; void addMem(int32 bytes); diff --git a/engines/wintermute/base/base_game_custom_actions.h b/engines/wintermute/base/base_game_custom_actions.h new file mode 100644 index 00000000000..f717771c35b --- /dev/null +++ b/engines/wintermute/base/base_game_custom_actions.h @@ -0,0 +1,44 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#ifndef WINTERMUTE_BASE_GAME_CUSTOM_ACTION_H +#define WINTERMUTE_BASE_GAME_CUSTOM_ACTION_H + +namespace Wintermute { + +enum BaseGameCustomAction { + kClickAtCenter = 0, + kClickAtLeft = 1, + kClickAtRight = 2, + kClickAtTop = 3, + kClickAtBottom = 4 +}; + +} // End of namespace Wintermute + +#endif diff --git a/engines/wintermute/base/base_game_music.cpp b/engines/wintermute/base/base_game_music.cpp index fee7c7be2d2..29040e87883 100644 --- a/engines/wintermute/base/base_game_music.cpp +++ b/engines/wintermute/base/base_game_music.cpp @@ -49,6 +49,8 @@ BaseGameMusic::BaseGameMusic(BaseGame *gameRef) : _gameRef(gameRef) { _musicCrossfadeChannel1 = -1; _musicCrossfadeChannel2 = -1; _musicCrossfadeSwap = false; + _musicCrossfadeVolume1 = 0; + _musicCrossfadeVolume2 = 100; } void BaseGameMusic::cleanup() { @@ -152,8 +154,6 @@ bool BaseGameMusic::setMusicStartTime(int channel, uint32 time) { ////////////////////////////////////////////////////////////////////////// bool BaseGameMusic::updateMusicCrossfade() { - /* byte globMusicVol = _soundMgr->getVolumePercent(SOUND_MUSIC); */ - if (!_musicCrossfadeRunning) { return STATUS_OK; } @@ -181,13 +181,22 @@ bool BaseGameMusic::updateMusicCrossfade() { if (currentTime >= _musicCrossfadeLength) { _musicCrossfadeRunning = false; - //_music[_musicCrossfadeChannel2]->setVolume(GlobMusicVol); - _music[_musicCrossfadeChannel2]->setVolumePercent(100); - _music[_musicCrossfadeChannel1]->stop(); - //_music[_musicCrossfadeChannel1]->setVolume(GlobMusicVol); - _music[_musicCrossfadeChannel1]->setVolumePercent(100); + if (_musicCrossfadeVolume2 == 0) { + _music[_musicCrossfadeChannel2]->stop(); + _music[_musicCrossfadeChannel2]->setVolumePercent(100); + } else { + _music[_musicCrossfadeChannel2]->setVolumePercent(_musicCrossfadeVolume2); + } + if (_musicCrossfadeChannel1 != _musicCrossfadeChannel2) { + if (_musicCrossfadeVolume1 == 0) { + _music[_musicCrossfadeChannel1]->stop(); + _music[_musicCrossfadeChannel1]->setVolumePercent(100); + } else { + _music[_musicCrossfadeChannel1]->setVolumePercent(_musicCrossfadeVolume1); + } + } if (_musicCrossfadeSwap) { // swap channels @@ -201,12 +210,15 @@ bool BaseGameMusic::updateMusicCrossfade() { _musicStartTime[_musicCrossfadeChannel2] = dummyInt; } } else { - //_music[_musicCrossfadeChannel1]->setVolume(GlobMusicVol - (float)CurrentTime / (float)_musicCrossfadeLength * GlobMusicVol); - //_music[_musicCrossfadeChannel2]->setVolume((float)CurrentTime / (float)_musicCrossfadeLength * GlobMusicVol); - _music[_musicCrossfadeChannel1]->setVolumePercent((int)(100.0f - (float)currentTime / (float)_musicCrossfadeLength * 100.0f)); - _music[_musicCrossfadeChannel2]->setVolumePercent((int)((float)currentTime / (float)_musicCrossfadeLength * 100.0f)); + float progress = (float)currentTime / (float)_musicCrossfadeLength; + int volumeDelta = (int)((_musicCrossfadeVolume1 - _musicCrossfadeVolume2)*progress); + _music[_musicCrossfadeChannel2]->setVolumePercent(_musicCrossfadeVolume1 - volumeDelta); + BaseEngine::LOG(0, "Setting music channel %d volume to %d", _musicCrossfadeChannel2, _musicCrossfadeVolume1 - volumeDelta); - //_gameRef->QuickMessageForm("%d %d", _music[_musicCrossfadeChannel1]->GetVolume(), _music[_musicCrossfadeChannel2]->GetVolume()); + if (_musicCrossfadeChannel1 != _musicCrossfadeChannel2) { + _music[_musicCrossfadeChannel1]->setVolumePercent(_musicCrossfadeVolume2 + volumeDelta); + BaseEngine::LOG(0, "Setting music channel %d volume to %d", _musicCrossfadeChannel1, _musicCrossfadeVolume2 + volumeDelta); + } } return STATUS_OK; @@ -227,6 +239,12 @@ bool BaseGameMusic::persistCrossfadeSettings(BasePersistenceManager *persistMgr) persistMgr->transferSint32(TMEMBER(_musicCrossfadeChannel1)); persistMgr->transferSint32(TMEMBER(_musicCrossfadeChannel2)); persistMgr->transferBool(TMEMBER(_musicCrossfadeSwap)); + + // let's keep savegame compatibility for the price of small possibility of wrong volume at game load + if (!persistMgr->getIsSaving()) { + _musicCrossfadeVolume1 = 0; + _musicCrossfadeVolume2 = 100; + } return true; } @@ -472,6 +490,8 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this _musicCrossfadeStartTime = _gameRef->getLiveTimer()->getTime(); _musicCrossfadeChannel1 = channel1; _musicCrossfadeChannel2 = channel2; + _musicCrossfadeVolume1 = 0; + _musicCrossfadeVolume2 = 100; _musicCrossfadeLength = fadeLength; _musicCrossfadeSwap = swap; @@ -481,6 +501,38 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this return STATUS_OK; } +#ifdef ENABLE_FOXTAIL + ////////////////////////////////////////////////////////////////////////// + // [FoxTail] MusicCrossfadeVolume + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "MusicCrossfadeVolume") == 0) { + stack->correctParams(4); + int channel = stack->pop()->getInt(0); + int volume1 = stack->pop()->getInt(0); + int volume2 = stack->pop()->getInt(0); + uint32 fadeLength = (uint32)stack->pop()->getInt(0); + + if (_musicCrossfadeRunning) { + script->runtimeError("Game.MusicCrossfade: Music crossfade is already in progress."); + stack->pushBool(false); + return STATUS_OK; + } + + _musicCrossfadeStartTime = _gameRef->getLiveTimer()->getTime(); + _musicCrossfadeChannel1 = channel; + _musicCrossfadeChannel2 = channel; + _musicCrossfadeVolume1 = volume1; + _musicCrossfadeVolume2 = volume2; + _musicCrossfadeLength = fadeLength; + _musicCrossfadeSwap = false; + + _musicCrossfadeRunning = true; + + stack->pushBool(true); + return STATUS_OK; + } +#endif + ////////////////////////////////////////////////////////////////////////// // GetSoundLength ////////////////////////////////////////////////////////////////////////// diff --git a/engines/wintermute/base/base_game_music.h b/engines/wintermute/base/base_game_music.h index 1e786dbb2b0..7fa364ad471 100644 --- a/engines/wintermute/base/base_game_music.h +++ b/engines/wintermute/base/base_game_music.h @@ -66,6 +66,8 @@ private: uint32 _musicCrossfadeLength; int32 _musicCrossfadeChannel1; int32 _musicCrossfadeChannel2; + int32 _musicCrossfadeVolume1; + int32 _musicCrossfadeVolume2; }; } // End of namespace Wintermute diff --git a/engines/wintermute/base/base_object.cpp b/engines/wintermute/base/base_object.cpp index 2da2b3197a2..3ab9a4db982 100644 --- a/engines/wintermute/base/base_object.cpp +++ b/engines/wintermute/base/base_object.cpp @@ -496,6 +496,23 @@ bool BaseObject::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisSta return STATUS_OK; } +#ifdef ENABLE_FOXTAIL + ////////////////////////////////////////////////////////////////////////// + // [FoxTail] GetSoundFilename + // Used to save/restore ambient sounds + // Should contain '\\' character, because Split("\\") is called on result + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "GetSoundFilename") == 0) { + stack->correctParams(0); + + if (!_sFX) { + stack->pushNULL(); + } else { + stack->pushString(_sFX->getFilename()); + } + return STATUS_OK; + } +#endif ////////////////////////////////////////////////////////////////////////// // SoundFXNone diff --git a/engines/wintermute/base/base_scriptable.h b/engines/wintermute/base/base_scriptable.h index 02ea854d3a9..ef61d7c7afe 100644 --- a/engines/wintermute/base/base_scriptable.h +++ b/engines/wintermute/base/base_scriptable.h @@ -79,8 +79,6 @@ BaseScriptable *makeSXMemBuffer(BaseGame *inGame, ScStack *stack); BaseScriptable *makeSXObject(BaseGame *inGame, ScStack *stack); BaseScriptable *makeSXStore(BaseGame *inGame); BaseScriptable *makeSXString(BaseGame *inGame, ScStack *stack); -BaseScriptable *makeSXSteamAPI(BaseGame *inGame, ScStack *stack); -BaseScriptable *makeSXWMEGalaxyAPI(BaseGame *inGame, ScStack *stack); } // End of namespace Wintermute diff --git a/engines/wintermute/base/file/base_disk_file.cpp b/engines/wintermute/base/file/base_disk_file.cpp index 4e26ec89204..6b77d798014 100644 --- a/engines/wintermute/base/file/base_disk_file.cpp +++ b/engines/wintermute/base/file/base_disk_file.cpp @@ -61,8 +61,8 @@ static Common::FSNode getNodeForRelativePath(const Common::String &filename) { } // Relative path: - if (filename.contains('\\')) { - Common::StringTokenizer path(filename, "\\"); + if (filename.contains('/')) { + Common::StringTokenizer path(filename, "/"); // Start traversing relative to the game-data-dir const Common::FSNode gameDataDir(ConfMan.get("path")); @@ -70,7 +70,7 @@ static Common::FSNode getNodeForRelativePath(const Common::String &filename) { // Parse all path-elements while (!path.empty()) { - // Get the next path-component by slicing on '\\' + // Get the next path-component by slicing on '/' Common::String pathPart = path.nextToken(); // Get the next FSNode in the chain, if it exists as a child from the previous. curNode = curNode.getChild(pathPart); @@ -109,6 +109,11 @@ bool diskFileExists(const Common::String &filename) { return false; } + +int listMatchingDiskFileMembers(Common::ArchiveMemberList &list, const Common::String &pattern) { + return Common::FSDirectory(ConfMan.get("path")).listMatchingMembers(list, pattern); +} + Common::SeekableReadStream *openDiskFile(const Common::String &filename) { uint32 prefixSize = 0; Common::SeekableReadStream *file = nullptr; diff --git a/engines/wintermute/base/file/base_disk_file.h b/engines/wintermute/base/file/base_disk_file.h index f20629f7ec5..cd6645f1d47 100644 --- a/engines/wintermute/base/file/base_disk_file.h +++ b/engines/wintermute/base/file/base_disk_file.h @@ -29,12 +29,14 @@ #ifndef WINTERMUTE_BASE_DISKFILE_H #define WINTERMUTE_BASE_DISKFILE_H +#include "common/archive.h" #include "common/stream.h" namespace Wintermute { Common::SeekableReadStream *openDiskFile(const Common::String &filename); bool diskFileExists(const Common::String &filename); +int listMatchingDiskFileMembers(Common::ArchiveMemberList &list, const Common::String &pattern); } // End of namespace Wintermute diff --git a/engines/wintermute/base/file/base_savefile_manager_file.cpp b/engines/wintermute/base/file/base_savefile_manager_file.cpp index d76053f58fb..3e45fd0da28 100644 --- a/engines/wintermute/base/file/base_savefile_manager_file.cpp +++ b/engines/wintermute/base/file/base_savefile_manager_file.cpp @@ -42,6 +42,9 @@ Common::String makeSfmFilename(const Common::String &filename) { smFilename.setChar('_', i); } } + while (smFilename.hasPrefix("._")) { + smFilename = smFilename.substr(2); + } return BaseEngine::instance().getGameTargetName() + "." + smFilename; } @@ -60,4 +63,14 @@ Common::WriteStream *openSfmFileForWrite(const Common::String &filename) { return g_system->getSavefileManager()->openForSaving(smFilename, false); } +Common::StringArray sfmFileList(const Common::String &mask) { + Common::String prefix = BaseEngine::instance().getGameTargetName() + "."; + Common::String smMask = makeSfmFilename(mask); + Common::StringArray array = g_system->getSavefileManager()->listSavefiles(smMask); + for (uint32 i = 0; i < array.size(); i++) { + array[i] = array[i].substr(prefix.size()); + } + return array; +} + } // End of namespace Wintermute diff --git a/engines/wintermute/base/file/base_savefile_manager_file.h b/engines/wintermute/base/file/base_savefile_manager_file.h index 2b129cf39ab..99307aeab8b 100644 --- a/engines/wintermute/base/file/base_savefile_manager_file.h +++ b/engines/wintermute/base/file/base_savefile_manager_file.h @@ -29,6 +29,7 @@ #ifndef WINTERMUTE_BASE_SAVEFILEMANAGERFILE_H #define WINTERMUTE_BASE_SAVEFILEMANAGERFILE_H +#include "common/str-array.h" #include "common/stream.h" namespace Wintermute { @@ -36,6 +37,7 @@ namespace Wintermute { Common::SeekableReadStream *openSfmFile(const Common::String &filename); Common::WriteStream *openSfmFileForWrite(const Common::String &filename); bool sfmFileExists(const Common::String &filename); +Common::StringArray sfmFileList(const Common::String &mask); } // End of namespace Wintermute diff --git a/engines/wintermute/base/font/base_font_truetype.cpp b/engines/wintermute/base/font/base_font_truetype.cpp index cf79f3bbbc8..6a5605feaa9 100644 --- a/engines/wintermute/base/font/base_font_truetype.cpp +++ b/engines/wintermute/base/font/base_font_truetype.cpp @@ -32,6 +32,7 @@ #include "engines/wintermute/base/gfx/base_surface.h" #include "engines/wintermute/base/base_parser.h" #include "engines/wintermute/base/base_game.h" +#include "engines/wintermute/base/base_engine.h" #include "engines/wintermute/base/base_file_manager.h" #include "engines/wintermute/utils/utils.h" #include "engines/wintermute/wintermute.h" @@ -615,6 +616,11 @@ bool BaseFontTT::initFont() { warning("BaseFontTT::InitFont - Couldn't load font: %s", _fontFile); } _lineHeight = _font->getFontHeight(); +#ifdef ENABLE_FOXTAIL + if (BaseEngine::instance().isFoxTail(FOXTAIL_1_2_896, FOXTAIL_LATEST_VERSION)) { + _lineHeight -= 1; + } +#endif return STATUS_OK; } diff --git a/engines/wintermute/base/scriptables/dcscript.h b/engines/wintermute/base/scriptables/dcscript.h index 8047baaa68c..96bea233753 100644 --- a/engines/wintermute/base/scriptables/dcscript.h +++ b/engines/wintermute/base/scriptables/dcscript.h @@ -111,6 +111,15 @@ typedef enum { II_DEF_CONST_VAR } TInstruction; +// operation code types +typedef enum { + OPCODES_UNCHANGED = 0, +#ifdef ENABLE_FOXTAIL + OPCODES_FOXTAIL_1_2_896, + OPCODES_FOXTAIL_1_2_902 +#endif +} TOpcodesType; + // external data types typedef enum { TYPE_VOID = 0, diff --git a/engines/wintermute/base/scriptables/script.cpp b/engines/wintermute/base/scriptables/script.cpp index dc8a76b91c5..09ff121d0ee 100644 --- a/engines/wintermute/base/scriptables/script.cpp +++ b/engines/wintermute/base/scriptables/script.cpp @@ -33,10 +33,17 @@ #include "engines/wintermute/base/scriptables/script_engine.h" #include "engines/wintermute/base/scriptables/script_stack.h" #include "engines/wintermute/base/gfx/base_renderer.h" +#include "engines/wintermute/ext/externals.h" #include "common/memstream.h" + +#ifdef ENABLE_FOXTAIL +#include "engines/wintermute/base/scriptables/script_opcodes.h" +#endif + #if EXTENDED_DEBUGGER_ENABLED #include "engines/wintermute/base/scriptables/debuggable/debuggable_script.h" #endif + namespace Wintermute { IMPLEMENT_PERSISTENT(ScScript, false) @@ -97,6 +104,10 @@ ScScript::ScScript(BaseGame *inGame, ScEngine *engine) : BaseClass(inGame) { _parentScript = nullptr; _tracingMode = false; + +#ifdef ENABLE_FOXTAIL + initOpcodesType(); +#endif } @@ -511,6 +522,39 @@ char *ScScript::getString() { return ret; } +#ifdef ENABLE_FOXTAIL +////////////////////////////////////////////////////////////////////////// +void ScScript::initOpcodesType() { + _opcodesType = BaseEngine::instance().isFoxTail(FOXTAIL_1_2_896, FOXTAIL_1_2_896) ? OPCODES_FOXTAIL_1_2_896 : + BaseEngine::instance().isFoxTail(FOXTAIL_1_2_902, FOXTAIL_LATEST_VERSION) ? OPCODES_FOXTAIL_1_2_902 : + OPCODES_UNCHANGED; +} + + +////////////////////////////////////////////////////////////////////////// +// FoxTail 1.2.896+ is using unusual opcodes tables, let's map them here +// NOTE: Those opcodes are never used at FoxTail 1.2.896 and 1.2.902: +// II_CMP_STRICT_EQ +// II_CMP_STRICT_NE +// II_DEF_CONST_VAR +// II_DBG_LINE +// II_PUSH_VAR_THIS +////////////////////////////////////////////////////////////////////////// +uint32 ScScript::decodeAltOpcodes(uint32 inst) { + if (inst > 46) { + return (uint32)(-1); + } + + switch (_opcodesType) { + case OPCODES_FOXTAIL_1_2_896: + return foxtail_1_2_896_mapping[inst]; + case OPCODES_FOXTAIL_1_2_902: + return foxtail_1_2_902_mapping[inst]; + default: + return inst; + } +} +#endif ////////////////////////////////////////////////////////////////////////// bool ScScript::executeInstruction() { @@ -527,6 +571,12 @@ bool ScScript::executeInstruction() { uint32 inst = getDWORD(); +#ifdef ENABLE_FOXTAIL + if (_opcodesType) { + inst = decodeAltOpcodes(inst); + } +#endif + preInstHook(inst); switch (inst) { @@ -1314,6 +1364,9 @@ bool ScScript::persist(BasePersistenceManager *persistMgr) { if (!persistMgr->getIsSaving()) { _tracingMode = false; +#ifdef ENABLE_FOXTAIL + initOpcodesType(); +#endif } return STATUS_OK; @@ -1419,407 +1472,13 @@ ScScript::TExternalFunction *ScScript::getExternal(char *name) { ////////////////////////////////////////////////////////////////////////// bool ScScript::externalCall(ScStack *stack, ScStack *thisStack, ScScript::TExternalFunction *function) { - ////////////////////////////////////////////////////////////////////////// - // getURLContent - // Used to download news headlines at Demo 2012 of James Peris - // HTTP GET result is stored in 3rd param of the call as a plain string - // Specification: external "geturl.dll" cdecl getURLContent(string, string, string) - // Known usage: getURLContent("http://www.lacosaweb.com", , ) - // Sets 3rd param to "Request Error." on error + // Externals: emulate external functions used in known games ////////////////////////////////////////////////////////////////////////// - if (strcmp(function->name, "getURLContent") == 0 && strcmp(function->dll_name, "geturl.dll") == 0) { - stack->correctParams(3); - const char *domain = stack->pop()->getString(); - const char *dirurl = stack->pop()->getString(); - ScValue *buf = stack->pop(); - - if (strcmp(dirurl, "jpnews/demo-es1.txt") == 0) { - buf->setString("Ya disponible el juego completo en jamesperis.com"); - } else if (strcmp(dirurl, "jpnews/demo-es2.txt") == 0) { - buf->setString("Cons\355guelo por solo 3,95 euros"); - } else if (strcmp(dirurl, "jpnews/demo-en1.txt") == 0) { - buf->setString("You can get the full game in jamesperis.com"); - } else if (strcmp(dirurl, "jpnews/demo-en2.txt") == 0) { - buf->setString("Get it for 3.95 euros"); - } else { - warning("getURLContent(\"%s\",\"%s\",buf) is not implemented", domain, dirurl); - buf->setString("Request Error."); - } - - stack->pushNULL(); + if (!DID_FAIL(EmulateExternalCall(_gameRef, stack, thisStack, function))) { return STATUS_OK; } - ////////////////////////////////////////////////////////////////////////// - // SetValueToReg - // Used to switch game's windowed/fullscreen mode at games by HeroCraft - // Specification: external "tools.dll" cdecl SetValueToReg(string, string, long) - // Known usage: SetValueToReg("Software\HeroCraft\\Video", "Windowed", 1) - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "SetValueToReg") == 0 && strcmp(function->dll_name, "tools.dll") == 0) { - stack->correctParams(3); - const char *regpath = stack->pop()->getString(); - const char *key = stack->pop()->getString(); - int value = stack->pop()->getInt(); - - if (strcmp(key, "Windowed") == 0) { - _gameRef->_renderer->setWindowed(value); - } else { - warning("SetValueToReg(\"%s\",\"%s\",%d) is not implemented", regpath, key, value); - } - - stack->pushNULL(); - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // changeWindowCaption - // Used to change game's window caption at games by HeroCraft - // Specification: external "img.dll" cdecl changeWindowCaption(long, string) - // Known usage: changeWindowCaption(Game.Hwnd, ) - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "changeWindowCaption") == 0 && strcmp(function->dll_name, "img.dll") == 0) { - stack->correctParams(2); - /*int hwnd =*/ stack->pop()->getInt(); - /*const char *title =*/ stack->pop()->getString(); - - // do nothing - - stack->pushNULL(); - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // maximizedWindow - // Used to change game's window size at games by HeroCraft - // Specification: external "img.dll" cdecl maximizedWindow(long, long, long) - // Known usage: maximizedWindow(Game.Hwnd, 1024, 768) - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "maximizedWindow") == 0 && strcmp(function->dll_name, "img.dll") == 0) { - stack->correctParams(3); - /*int hwnd =*/ stack->pop()->getInt(); - /*int width =*/ stack->pop()->getInt(); - /*int height =*/ stack->pop()->getInt(); - - // do nothing - - stack->pushNULL(); - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // ShellExecuteA - // Used to open URL in browser at Wilma Tetris - // Specification: external "shell32.dll" stdcall long ShellExecuteA(long, string, string, string, string, long) - // Known usage: ShellExecuteA(0, "open", <URL>, "", "", 3) - // Returns value >32 on success - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "ShellExecuteA") == 0 && strcmp(function->dll_name, "shell32.dll") == 0) { - stack->correctParams(6); - int hwnd = stack->pop()->getInt(); - const char *operation = stack->pop()->getString(); - const char *file = stack->pop()->getString(); - const char *params = stack->pop()->getString(); - const char *directory = stack->pop()->getString(); - int cmd = stack->pop()->getInt(); - - if (strcmp(operation, "open") == 0 && !strlen(params) && !strlen(directory)) { - g_system->openUrl(file); - } else { - warning("ShellExecuteA(%d,\"%s\",\"%s\",\"%s\",\"%s\",%d) is not implemented", hwnd, operation, file, params, directory, cmd); - } - - stack->pushInt(42); - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // _InstallUtilAnsi@0 - // Used to check if DVD is inserted at Art of Murder: FBI Confidential - // Specification: external "installutil.dll" stdcall long _InstallUtilAnsi@0() - // Known usage: _InstallUtilAnsi@0() - // Returns 1 on success, other value on fail (which leads to Game.QuitGame() in non-Debug mode) - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "_InstallUtilAnsi@0") == 0 && strcmp(function->dll_name, "installutil.dll") == 0) { - stack->correctParams(0); - stack->pushInt(1); - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // IRC_init - // Used to connect to debug IRC server at games by Corbomite Games - // Specification: external "dlltest.dll" cdecl long IRC_init(string) - // Known usage: IRC_init(<PlayerName>) - // Known actions: - // 1. Connect to irc.starchat.net - // 2. Send "NICK ZU_<PlayerName>/" - // 3. Send "USER Blah ZbengHost ZbengServer ZbengRealname" - // 4. Send "Join #Zbeng" - // Returns 0 on success, other value on error - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "IRC_init") == 0 && strcmp(function->dll_name, "dlltest.dll") == 0) { - stack->correctParams(1); - /*const char *name =*/ stack->pop()->getString(); - - // do nothing - - stack->pushInt(0); - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // ChangeNick - // Used to update nick at debug IRC server at games by Corbomite Games - // Specification: external "dlltest.dll" cdecl long ChangeNick(string) - // Known usage: ChangeNick(<PlayerName>) - // Return value is never used - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "ChangeNick") == 0 && strcmp(function->dll_name, "dlltest.dll") == 0) { - stack->correctParams(1); - /*const char *name =*/ stack->pop()->getString(); - - // do nothing - - stack->pushInt(0); - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // IRC_SendString - // Used to send debug and chat lines to an IRC server at games by Corbomite Games - // Specification: external "dlltest.dll" cdecl IRC_SendString(string, string) - // Known usage: IRC_SendString(<Message>, <Channel>) - // Known Channel values are: "#Zbeng" and "#ZbengDebug" - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "IRC_SendString") == 0 && strcmp(function->dll_name, "dlltest.dll") == 0) { - stack->correctParams(2); - const char *message = stack->pop()->getString(); - const char *channel = stack->pop()->getString(); - - _gameRef->LOG(0, "IRC logging: [%s] %s", channel, message); - - stack->pushNULL(); - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // IRC_GetChatStrings - // Used to get chat lines from an IRC server at games by Corbomite Games - // Specification: external "dlltest.dll" cdecl IRC_GetChatStrings(string, long) - // Known usage: IRC_GetChatStrings(<Buffer>, 65535) - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "IRC_GetChatStrings") == 0 && strcmp(function->dll_name, "dlltest.dll") == 0) { - stack->correctParams(2); - /*const char *buffer =*/ stack->pop()->getString(); - /*int bufferMaxSize =*/ stack->pop()->getInt(); - - // do nothing - - stack->pushNULL(); - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // IRC_quit - // Used to disconnect from debug IRC server at games by Corbomite Games - // Specification: external "dlltest.dll" cdecl IRC_quit() - // Known usage: IRC_quit() - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "IRC_quit") == 0 && strcmp(function->dll_name, "dlltest.dll") == 0) { - stack->correctParams(0); - - // do nothing - - stack->pushNULL(); - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // LoadLibraryA - // Used for checking library availability at games by Corbomite Games - // Specification: external "kernel32.dll" stdcall long LoadLibraryA(string) - // Known usage: LoadLibraryA("httpconnect.dll"), LoadLibraryA("dlltest.dll") - // Return values are only compared with zero and are never used in other APIs - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "LoadLibraryA") == 0 && strcmp(function->dll_name, "kernel32.dll") == 0) { - stack->correctParams(1); - const char *dllName = stack->pop()->getString(); - int result = 0; - - if (strcmp(dllName, "httpconnect.dll") == 0) { - result = 1; // some non-zero value - } else if (strcmp(dllName, "dlltest.dll") == 0) { - result = 2; // some other non-zero value - } else { - warning("LoadLibraryA(\"%s\") is not implemented", dllName); - } - - stack->pushInt(result); - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // FreeLibrary - // Declared at games by Corbomite Games - // Seems to be unused, probably was used for unloading IRC & HTTP libraries - // Specification: external "kernel32.dll" stdcall FreeLibrary(long) - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "FreeLibrary") == 0 && strcmp(function->dll_name, "kernel32.dll") == 0) { - stack->correctParams(1); - /*int dllId =*/ stack->pop()->getInt(); - - // do nothing - - stack->pushNULL(); - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // GetEnvironmentVariableA - // Used for getting environment variables at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest - // Specification: external "kernel32.dll" stdcall long GetEnvironmentVariableA(string, string, long) - // Known usage: GetEnvironmentVariableA(<EnvName>, <buffer>, 65535) - // Known EnvName values used in debug code: "USERKEY", "ALTUSERNAME", "ENHFINGERPRINT", "EXTRAINFO", "FINGERPRINT", "KEYSTRING", "STOLENKEY", "TRIAL" - // Known EnvName values used in licensing code: "FULLGAME" - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "GetEnvironmentVariableA") == 0 && strcmp(function->dll_name, "kernel32.dll") == 0) { - stack->correctParams(3); - const char *name = stack->pop()->getString(); - /*ScValue *buf =*/ stack->pop(); - /*int bufMaxLen =*/ stack->pop()->getInt(); - - warning("Assuming variable \"%s\" is not set", name); - - stack->pushInt(0); - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // Register - // Used to register license key online at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest - // Specification: external "httpconnect.dll" cdecl long Register(string, long, string, long) - // Known usage: Register(<productId>, 65535, <productKey>, 65535) - // Known product ID values are: "357868", "353058" and "353006" - // Known action: HTTP GET http://keygen.corbomitegames.com/keygen/validateKey.php?action=REGISTER&productId=productId&key=productKey - // Returns 1 on success - // Returns 0 on firewall error - // Returns -1 on invalid product key - // Returns -2 on invalid product ID - // Returns -3 on expired product key - // Returns -4 on invalid machine ID - // Returns -5 on number of installations exceeded - // Returns -6 on socket error - // Returns -7 on no internet connection - // Returns -8 on connection reset - // Returns -11 on validation temporary unavaliable - // Returns -12 on validation error - // For some reason always returns -7 for me in a test game - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "Register") == 0 && strcmp(function->dll_name, "httpconnect.dll") == 0) { - stack->correctParams(4); - const char *productId = stack->pop()->getString(); - int productIdMaxLen = stack->pop()->getInt(); - const char *productKey = stack->pop()->getString(); - int productKeyMaxLen = stack->pop()->getInt(); - - warning("Register(\"%s\",%d,\"%s\",%d) is not implemented", productId , productIdMaxLen, productKey, productKeyMaxLen); - - stack->pushInt(-7); // "no internet connection" error - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // Validate - // Used to validate something at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest - // Specification: external "httpconnect.dll" cdecl long Validate() - // Known usage: Validate() - // Known action: HTTP GET http://keygen.corbomitegames.com/keygen/validateKey.php?action=VALIDATE&productId=Ar&key=Ar - // Used only when Debug mode is active or game is started with "INVALID" cmdline parameter - // For some reason always returns 1 for me in a test game - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "Validate") == 0 && strcmp(function->dll_name, "httpconnect.dll") == 0) { - stack->correctParams(0); - - // do nothing - - stack->pushInt(1); - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // SendHTTPAsync - // Used to send game progress events to server at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest - // Specification: external "httpconnect.dll" cdecl long SendHTTPAsync(string, long, string, long, string, long) - // Known usage: SendHTTPAsync("backend.pizzamorgana.com", 65535, <FullURL>, 65535, <Buffer?!>, 65535) - // FullURL is formed as "http://backend.pizzamorgana.com/event.php?Event=<EventName>&player=<PlayerName>&extraParams=<ExtraParams>&SN=<ProductKey>&Episode=1&GameTime=<CurrentTime>&UniqueID=<UniqueId>" - // Known EventName values are: "GameStart", "ChangeGoal", "EndGame" and "QuitGame" - // Known ExtraParams values are: "ACT0", "ACT1", "ACT2", "ACT3", "ACT4", "Ep0FindFood", "Ep0FindCellMenu", "Ep0BroRoom", "Ep0FindKey", "Ep0FindCellMenuKey", "Ep0FindMenuKey", "Ep0FindCell", "Ep0FindMenu", "Ep0OrderPizza", "Ep0GetRidOfVamp", "Ep0GetVampAttention", "Ep0License" - // Return value is never used - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "SendHTTPAsync") == 0 && strcmp(function->dll_name, "httpconnect.dll") == 0) { - stack->correctParams(6); - const char *server = stack->pop()->getString(); - int serverMaxLen = stack->pop()->getInt(); - const char *fullUrl = stack->pop()->getString(); - int fullUrlMaxLen = stack->pop()->getInt(); - const char *param5 = stack->pop()->getString(); - int param5MaxLen = stack->pop()->getInt(); - - // TODO: Maybe parse URL and call some Achievements API using ExtraParams values in some late future - warning("SendHTTPAsync(\"%s\",%d,\"%s\",%d,\"%s\",%d) is not implemented", server, serverMaxLen, fullUrl, fullUrlMaxLen, param5, param5MaxLen); - - stack->pushInt(0); - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // SendRecvHTTP (6 params variant) - // Declared at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest - // Seems to be unused, probably SendRecvHTTP was initially used instead of SendHTTPAsync - // Specification: external "httpconnect.dll" cdecl long SendRecvHTTP(string, long, string, long, string, long) - // Always returns -7 for me in a test game, probably returns the same network errors as Register() - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "SendRecvHTTP") == 0 && strcmp(function->dll_name, "httpconnect.dll") == 0 && function->nu_params == 6) { - stack->correctParams(6); - const char *server = stack->pop()->getString(); - int serverMaxLen = stack->pop()->getInt(); - const char *fullUrl = stack->pop()->getString(); - int fullUrlMaxLen = stack->pop()->getInt(); - const char *param5 = stack->pop()->getString(); - int param5MaxLen = stack->pop()->getInt(); - - warning("SendRecvHTTP(\"%s\",%d,\"%s\",%d,\"%s\",%d) is not implemented", server, serverMaxLen, fullUrl, fullUrlMaxLen, param5, param5MaxLen); - - stack->pushInt(-7); // "no internet connection" error - return STATUS_OK; - } - - ////////////////////////////////////////////////////////////////////////// - // SendRecvHTTP (4 params variant) - // Used to call HTTP methods at Zbang! The Game - // Specification: external "httpconnect.dll" cdecl long SendRecvHTTP(string, long, string, long) - // Known usage: SendRecvHTTP("scoresshort.php?player=<PlayerName>", 65535, <Buffer>, 65535) - // Known usage: SendRecvHTTP("/update.php?player=<PlayerName>&difficulty=<Difficulty>&items=<CommaSeparatedItemList>", 65535, <Buffer>, 65535) - // My Zbang demo does not have this dll, so there is no way to actually test it with a test game - // Return value is never used in Zbang scripts - ////////////////////////////////////////////////////////////////////////// - else if (strcmp(function->name, "SendRecvHTTP") == 0 && strcmp(function->dll_name, "httpconnect.dll") == 0 && function->nu_params == 4) { - stack->correctParams(4); - const char *dirUrl = stack->pop()->getString(); - int dirUrlMaxLen = stack->pop()->getInt(); - /*ScValue *buf =*/ stack->pop(); - int bufMaxLen = stack->pop()->getInt(); - - //TODO: Count items and give scores, persist those values - warning("SendRecvHTTP(\"%s\",%d,buf,%d) is not implemented", dirUrl, dirUrlMaxLen, bufMaxLen); - - stack->pushInt(0); - return STATUS_OK; - } - - _gameRef->LOG(0, "External functions are not supported on this platform."); stack->correctParams(0); stack->pushNULL(); return STATUS_FAILED; diff --git a/engines/wintermute/base/scriptables/script.h b/engines/wintermute/base/scriptables/script.h index 91e31340c33..2efdb18f0a8 100644 --- a/engines/wintermute/base/scriptables/script.h +++ b/engines/wintermute/base/scriptables/script.h @@ -167,6 +167,12 @@ private: virtual void preInstHook(uint32 inst); virtual void postInstHook(uint32 inst); + +#ifdef ENABLE_FOXTAIL + TOpcodesType _opcodesType; + void initOpcodesType(); + uint32 decodeAltOpcodes(uint32 inst); +#endif }; } // End of namespace Wintermute diff --git a/engines/wintermute/base/scriptables/script_engine.cpp b/engines/wintermute/base/scriptables/script_engine.cpp index 3a62d2e644c..e420c17d45e 100644 --- a/engines/wintermute/base/scriptables/script_engine.cpp +++ b/engines/wintermute/base/scriptables/script_engine.cpp @@ -184,6 +184,17 @@ ScScript *ScEngine::runScript(const char *filename, BaseScriptHolder *owner) { } +////////////////////////////////////////////////////////////////////////// +bool ScEngine::isRunningScript(const char *filename) { + for (uint32 i = 0; i < _scripts.size(); i++) { + if (strcmp(_scripts[i]->_filename, filename) == 0) { + return true; + } + } + return false; +} + + ////////////////////////////////////////////////////////////////////////// byte *ScEngine::getCompiledScript(const char *filename, uint32 *outSize, bool ignoreCache) { // is script in cache? diff --git a/engines/wintermute/base/scriptables/script_engine.h b/engines/wintermute/base/scriptables/script_engine.h index bb6aaf76034..ea2a75ac019 100644 --- a/engines/wintermute/base/scriptables/script_engine.h +++ b/engines/wintermute/base/scriptables/script_engine.h @@ -86,6 +86,7 @@ public: bool tick(); ScValue *_globals; ScScript *runScript(const char *filename, BaseScriptHolder *owner = nullptr); + bool isRunningScript(const char *filename); static const bool _compilerAvailable = false; ScEngine(BaseGame *inGame); diff --git a/engines/wintermute/base/scriptables/script_ext_date.cpp b/engines/wintermute/base/scriptables/script_ext_date.cpp index 89cdcde0afe..c53fd4ea111 100644 --- a/engines/wintermute/base/scriptables/script_ext_date.cpp +++ b/engines/wintermute/base/scriptables/script_ext_date.cpp @@ -90,6 +90,17 @@ bool SXDate::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, stack->pushInt(_tm.tm_mon + 1); return STATUS_OK; } +#ifdef ENABLE_FOXTAIL + ////////////////////////////////////////////////////////////////////////// + // [FoxTail] GetDay + // date.GetDate() was renamed to date.GetDay() in FoxTail 1.2.896 engine + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "GetDay") == 0) { + stack->correctParams(0); + stack->pushInt(_tm.tm_mday); + return STATUS_OK; + } +#endif ////////////////////////////////////////////////////////////////////////// // GetDate ////////////////////////////////////////////////////////////////////////// diff --git a/engines/wintermute/base/scriptables/script_opcodes.h b/engines/wintermute/base/scriptables/script_opcodes.h new file mode 100644 index 00000000000..ccb024286fc --- /dev/null +++ b/engines/wintermute/base/scriptables/script_opcodes.h @@ -0,0 +1,136 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#ifndef WINTERMUTE_SCOPCODES_H +#define WINTERMUTE_SCOPCODES_H + +namespace Wintermute { + +const uint32 foxtail_1_2_896_mapping[] = { + II_CMP_LE, + II_JMP, + II_POP_REG1, + II_PUSH_BOOL, + II_MODULO, + II_POP_EMPTY, + II_CALL_BY_EXP, + II_CMP_L, + II_PUSH_FLOAT, + II_NOT, + II_PUSH_THIS, + II_PUSH_BY_EXP, + II_PUSH_THIS_FROM_STACK, + II_CMP_G, + II_DEF_GLOB_VAR, + II_PUSH_STRING, + II_PUSH_REG1, + II_DEF_VAR, + II_PUSH_VAR_THIS, + II_RET_EVENT, + II_PUSH_VAR_REF, + II_CMP_NE, + II_DBG_LINE, + II_OR, + II_POP_VAR, + II_AND, + II_EXTERNAL_CALL, + II_CORRECT_STACK, + II_RET, + II_DIV, + II_PUSH_VAR, + II_SUB, + II_CALL, + II_CREATE_OBJECT, + II_MUL, + II_POP_BY_EXP, + II_DEF_CONST_VAR, + II_PUSH_NULL, + II_JMP_FALSE, + II_ADD, + II_CMP_GE, + II_CMP_STRICT_EQ, + II_CMP_STRICT_NE, + II_PUSH_INT, + II_CMP_EQ, + II_POP_THIS, + II_SCOPE +}; + +const uint32 foxtail_1_2_902_mapping[] = { + II_CMP_L, + II_CALL, + II_DEF_GLOB_VAR, + II_DBG_LINE, + II_JMP_FALSE, + II_CMP_STRICT_EQ, + II_PUSH_FLOAT, + II_CALL_BY_EXP, + II_MODULO, + II_PUSH_THIS, + II_CMP_GE, + II_PUSH_BOOL, + II_PUSH_VAR, + II_PUSH_VAR_REF, + II_POP_BY_EXP, + II_CMP_STRICT_NE, + II_RET_EVENT, + II_PUSH_BY_EXP, + II_CORRECT_STACK, + II_POP_VAR, + II_CMP_G, + II_PUSH_THIS_FROM_STACK, + II_JMP, + II_AND, + II_CREATE_OBJECT, + II_POP_REG1, + II_PUSH_STRING, + II_POP_EMPTY, + II_DIV, + II_ADD, + II_RET, + II_EXTERNAL_CALL, + II_NOT, + II_OR, + II_SUB, + II_PUSH_INT, + II_DEF_VAR, + II_SCOPE, + II_CMP_EQ, + II_MUL, + II_POP_THIS, + II_CMP_LE, + II_PUSH_REG1, + II_DEF_CONST_VAR, + II_PUSH_NULL, + II_CMP_NE, + II_PUSH_VAR_THIS +}; + +} // End of namespace Wintermute + +#endif diff --git a/engines/wintermute/detection_tables.h b/engines/wintermute/detection_tables.h index b568479241e..f5d99374829 100644 --- a/engines/wintermute/detection_tables.h +++ b/engines/wintermute/detection_tables.h @@ -30,6 +30,7 @@ static const PlainGameDescriptor wintermuteGames[] = { {"5ma", "Five Magical Amulets"}, {"actualdest", "Actual Destination"}, {"agustin", "Boredom of Agustin Cordes"}, + {"alavi", "Informer Alavi - Murder of Miss Rojan"}, {"alimardan1", "Alimardan's Mischief"}, {"alimardan2", "Alimardan Meets Merlin"}, {"alphapolaris", "Alpha Polaris"}, @@ -238,6 +239,16 @@ static const WMEGameDescription gameDescriptions[] = { WME_WINENTRY("actualdest", "", WME_ENTRY1s("data.dcp", "6926f44b26f21ceb1d840eaab9aeb510", 9081740), Common::EN_ANY, ADGF_UNSTABLE, WME_1_8_11), + // Informer Alavi - Murder of Miss Rojan (Persian) (Beta version -old version-, between 1387/12 to 1392/6) + // NOTE: This is a 2.5D game that is out of ScummVM scope + WME_WINENTRY("alavi", "Beta version", + WME_ENTRY1s("data.dcp", "587b46baa3f82dfe09bdb51f01231fa2", 37191939), Common::FA_IRN, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_ANDISHE_VARAN), + + // Informer Alavi - Murder of Miss Rojan (Persian) (Try version, between 1388/8) + // NOTE: This is a 2.5D game that is out of ScummVM scope + WME_WINENTRY("alavi", "Try version", + WME_ENTRY1s("data.dcp", "07b847ebafbf8e58daa341d60598c84b", 36628230), Common::FA_IRN, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_ANDISHE_VARAN), + // Alimardan's Mischief WME_WINENTRY("alimardan1", "", WME_ENTRY1s("data.dcp", "55c28b8d4f49120f980d237951a6c73f", 1834957694), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_1), @@ -257,77 +268,77 @@ static const WMEGameDescription gameDescriptions[] = { // Alpha Polaris (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("alphapolaris", "", - WME_ENTRY1s("data.dcp", "6d5d2264a3135dae3a9a74de50b4ea68", 706780438), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_1), + WME_ENTRY1s("data.dcp", "6d5d2264a3135dae3a9a74de50b4ea68", 706780438), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_1), // Alpha Polaris (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("alphapolaris", "", - WME_ENTRY1s("data.dcp", "24ebca07b7cf0bd94ec994f26bdccf83", 710319064), Common::PL_POL, ADGF_UNSTABLE, WME_1_9_1), + WME_ENTRY1s("data.dcp", "24ebca07b7cf0bd94ec994f26bdccf83", 710319064), Common::PL_POL, ADGF_UNSTABLE | GF_3D, WME_1_9_1), // Alpha Polaris (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("alphapolaris", "", - WME_ENTRY1s("data.dcp", "dd8c252e039cd3a935c7490614e5e6f6", 706780433), Common::RU_RUS, ADGF_UNSTABLE, WME_1_9_1), + WME_ENTRY1s("data.dcp", "dd8c252e039cd3a935c7490614e5e6f6", 706780433), Common::RU_RUS, ADGF_UNSTABLE | GF_3D, WME_1_9_1), // Alpha Polaris (English) (1.1.0) (1280x800 Steam) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("alphapolaris", "1.1.0 (1280x800 Steam)", WME_ENTRY2s("data.dcp", "2d1bd35749b2538915b53ce79288bceb", 706580987, - "data.dcp", "2d1bd35749b2538915b53ce79288bceb", 706580987), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_3), + "data.dcp", "2d1bd35749b2538915b53ce79288bceb", 706580987), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // Alpha Polaris (German) (1.1.0) (1280x800 Steam) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("alphapolaris", "1.1.0 (1280x800 Steam)", WME_ENTRY2s("data.dcp", "2d1bd35749b2538915b53ce79288bceb", 706580987, - "german_language_pack.dcp", "0ed4ef1647445c73b5915b60f85ed8e4", 19251966), Common::DE_DEU, ADGF_UNSTABLE, WME_1_9_3), + "german_language_pack.dcp", "0ed4ef1647445c73b5915b60f85ed8e4", 19251966), Common::DE_DEU, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // Alpha Polaris (Polish) (1.1.0) (1280x800 Steam) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("alphapolaris", "1.1.0 (1280x800 Steam)", WME_ENTRY2s("data.dcp", "2d1bd35749b2538915b53ce79288bceb", 706580987, - "polish_language_pack.dcp", "91f80c5f8d522541d666d11b60b0ea6c", 15006039), Common::PL_POL, ADGF_UNSTABLE, WME_1_9_3), + "polish_language_pack.dcp", "91f80c5f8d522541d666d11b60b0ea6c", 15006039), Common::PL_POL, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // Alpha Polaris (Russian) (1.1.0) (1280x800 Steam) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("alphapolaris", "1.1.0 (1280x800 Steam)", WME_ENTRY2s("data.dcp", "2d1bd35749b2538915b53ce79288bceb", 706580987, - "russian_language_pack.dcp", "58575db652d371af537b4b8841e962f8", 49395113), Common::RU_RUS, ADGF_UNSTABLE, WME_1_9_3), + "russian_language_pack.dcp", "58575db652d371af537b4b8841e962f8", 49395113), Common::RU_RUS, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // Alpha Polaris (English) (1.1.0) (1280x768 Steam) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("alphapolaris", "1.1.0 (1280x768 Steam)", WME_ENTRY2s("data.dcp", "481b1bff44178ef2f3d879df05f65a96", 706580987, - "data.dcp", "481b1bff44178ef2f3d879df05f65a96", 706580987), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_3), + "data.dcp", "481b1bff44178ef2f3d879df05f65a96", 706580987), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // Alpha Polaris (German) (1.1.0) (1280x768 Steam) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("alphapolaris", "1.1.0 (1280x768 Steam)", WME_ENTRY2s("data.dcp", "481b1bff44178ef2f3d879df05f65a96", 706580987, - "german_language_pack.dcp", "2ffd9b2bdf2c2b3646067644572390c0", 19251966), Common::DE_DEU, ADGF_UNSTABLE, WME_1_9_3), + "german_language_pack.dcp", "2ffd9b2bdf2c2b3646067644572390c0", 19251966), Common::DE_DEU, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // Alpha Polaris (Polish) (1.1.0) (1280x768 Steam) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("alphapolaris", "1.1.0 (1280x768 Steam)", WME_ENTRY2s("data.dcp", "481b1bff44178ef2f3d879df05f65a96", 706580987, - "polish_language_pack.dcp", "4a24986189321f39b9f48cbc4889d89a", 15006039), Common::PL_POL, ADGF_UNSTABLE, WME_1_9_3), + "polish_language_pack.dcp", "4a24986189321f39b9f48cbc4889d89a", 15006039), Common::PL_POL, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // Alpha Polaris (Russian) (1.1.0) (1280x768 Steam) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("alphapolaris", "1.1.0 (1280x768 Steam)", WME_ENTRY2s("data.dcp", "481b1bff44178ef2f3d879df05f65a96", 706580987, - "russian_language_pack.dcp", "f39ad478a711fa4b34d419ed4aac97bf", 49395113), Common::RU_RUS, ADGF_UNSTABLE, WME_1_9_3), + "russian_language_pack.dcp", "f39ad478a711fa4b34d419ed4aac97bf", 49395113), Common::RU_RUS, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // Alpha Polaris (English Demo) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("alphapolaris", "Demo", WME_ENTRY2s("data.dcp", "68f93edfb69de8f8c06c81566f279e07", 409562809, - "data.dcp", "68f93edfb69de8f8c06c81566f279e07", 409562809), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, WME_1_9_3), + "data.dcp", "68f93edfb69de8f8c06c81566f279e07", 409562809), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_9_3), // Alpha Polaris (German Demo) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("alphapolaris", "Demo", WME_ENTRY2s("data.dcp", "130545e152d0b53d84c2c99ce118d5e5", 409564920, - "german language pack.dcp", "71e19682f93399018bef90ceda0a1bfd", 16174995), Common::DE_DEU, ADGF_UNSTABLE | ADGF_DEMO, WME_1_9_3), + "german language pack.dcp", "71e19682f93399018bef90ceda0a1bfd", 16174995), Common::DE_DEU, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_9_3), // Apeiron WME_WINENTRY("apeiron", "", @@ -337,82 +348,82 @@ static const WMEGameDescription gameDescriptions[] = { // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("artofmurder1", "", WME_ENTRY2s("data.dcp", "7e4c1dc8b1fb08541f7784d6288acfc8", 633692059, - "us.dcp", "4a02b65edc45444ac69ff8a514e952b8", 176592548), Common::EN_ANY, ADGF_UNSTABLE, WME_1_8_1), + "us.dcp", "4a02b65edc45444ac69ff8a514e952b8", 176592548), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_8_1), // Art of Murder: FBI Confidential (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("artofmurder1", "", WME_ENTRY2s("data.dcp", "bba4e56a66fd6406a26515cfc86ac125", 23782002, - "fr.dcp", "5665d84d70cb3e20472e1c3eb9d884c3", 125728694), Common::FR_FRA, ADGF_UNSTABLE, WME_1_8_1), + "fr.dcp", "5665d84d70cb3e20472e1c3eb9d884c3", 125728694), Common::FR_FRA, ADGF_UNSTABLE | GF_3D, WME_1_8_1), // Art of Murder: FBI Confidential (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("artofmurder1", "", WME_ENTRY2s("data.dcp", "09e57d77b68dafa73a0924f11f61b059", 630742753, - "i18n.dcp", "583940f6d3fb4097e7cb1e2cc9a43a7b", 156078991), Common::DE_DEU, ADGF_UNSTABLE, WME_1_8_1), + "i18n.dcp", "583940f6d3fb4097e7cb1e2cc9a43a7b", 156078991), Common::DE_DEU, ADGF_UNSTABLE | GF_3D, WME_1_8_1), // Art of Murder: FBI Confidential (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("artofmurder1", "", WME_ENTRY2s("data.dcp", "7e4c1dc8b1fb08541f7784d6288acfc8", 633692059, - "it.dcp", "c3c10399644a1e9f7e977df73fb017e0", 166794517), Common::IT_ITA, ADGF_UNSTABLE, WME_1_8_1), + "it.dcp", "c3c10399644a1e9f7e977df73fb017e0", 166794517), Common::IT_ITA, ADGF_UNSTABLE | GF_3D, WME_1_8_1), // Art of Murder: FBI Confidential (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("artofmurder1", "", WME_ENTRY2s("data.dcp", "340f04f9f66a0ab978b78d317544bbed", 23757600, - "es.dcp", "47b3a609993b3c18ce5bfb1af734ea3e", 148997124), Common::ES_ESP, ADGF_UNSTABLE, WME_1_8_1), + "es.dcp", "47b3a609993b3c18ce5bfb1af734ea3e", 148997124), Common::ES_ESP, ADGF_UNSTABLE | GF_3D, WME_1_8_1), // Art of Murder: FBI Confidential (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("artofmurder1", "", WME_ENTRY2s("data.dcp", "592862a5dd1ae90d53561815a535ab2e", 630734278, - "i18n.dcp", "b43bd7b64991ad9d5d285753767fe3f4", 176591837), Common::PL_POL, ADGF_UNSTABLE, WME_1_8_1), + "i18n.dcp", "b43bd7b64991ad9d5d285753767fe3f4", 176591837), Common::PL_POL, ADGF_UNSTABLE | GF_3D, WME_1_8_1), // Art of Murder: FBI Confidential (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("artofmurder1", "", WME_ENTRY2s("data.dcp", "4f383bd02fb0eea54e9b5825c3056b52", 23761530, - "ru.dcp", "57af214554547437c823a01f6cf51b24", 201702190), Common::RU_RUS, ADGF_UNSTABLE, WME_1_8_3), + "ru.dcp", "57af214554547437c823a01f6cf51b24", 201702190), Common::RU_RUS, ADGF_UNSTABLE | GF_3D, WME_1_8_3), // Art of Murder: FBI Confidential (English Demo) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("artofmurder1", "Demo", WME_ENTRY2s("data.dcp", "d0073ddf2b25527c83785ae7a0978867", 47676670, - "data.dcp", "d0073ddf2b25527c83785ae7a0978867", 47676670), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, WME_1_8_1), + "data.dcp", "d0073ddf2b25527c83785ae7a0978867", 47676670), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_8_1), // Art of Murder: FBI Confidential (Polish Demo) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("artofmurder1", "Demo", WME_ENTRY2s("data.dcp", "d0073ddf2b25527c83785ae7a0978867", 47676670, - "pl.dcp", "4dbc02aa9f67d22226d22dc0d837d20e", 49208405), Common::PL_POL, ADGF_UNSTABLE | ADGF_DEMO, WME_1_8_1), + "pl.dcp", "4dbc02aa9f67d22226d22dc0d837d20e", 49208405), Common::PL_POL, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_8_1), // Art of Murder: FBI Confidential (German Demo 1) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("artofmurder1", "Demo", WME_ENTRY2s("data.dcp", "d7f3dd0e87e4904292d19778b8af2ed1", 47662172, - "de.dcp", "c0bbfee40b79af1f837a9f3f8fcef78c", 42741523), Common::DE_DEU, ADGF_UNSTABLE | ADGF_DEMO, WME_1_8_1), + "de.dcp", "c0bbfee40b79af1f837a9f3f8fcef78c", 42741523), Common::DE_DEU, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_8_1), // Art of Murder: FBI Confidential (German Demo 2) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("artofmurder1", "Demo", WME_ENTRY2s("data.dcp", "99d63dfee4ea97d31530649c929bee45", 81127581, - "de.dcp", "e97e2e18b26e5eff916c73f720d5f4f2", 17737492), Common::DE_DEU, ADGF_UNSTABLE | ADGF_DEMO, WME_1_8_1), + "de.dcp", "e97e2e18b26e5eff916c73f720d5f4f2", 17737492), Common::DE_DEU, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_8_1), // Barrow Hill - The Dark Path (Steam, September 2018) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("barrowhilldp", "", - WME_ENTRY1s("data.dcp", "6b7c8f8185a80c50a71e068aad82862e", 1066752), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_3), + WME_ENTRY1s("data.dcp", "6b7c8f8185a80c50a71e068aad82862e", 1066752), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // Barrow Hill - The Dark Path (Steam, September 2018) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("barrowhilldp", "", - WME_ENTRY1s("data.dcp", "958b89bd394bbaae17a3abe51eb00b5b", 1066776), Common::DE_DEU, ADGF_UNSTABLE, WME_1_9_3), + WME_ENTRY1s("data.dcp", "958b89bd394bbaae17a3abe51eb00b5b", 1066776), Common::DE_DEU, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // Basis Octavus // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("basisoctavus", "", - WME_ENTRY1s("data.dcp", "021ef97f8f49ec33f83beae0d6e38f08", 49336909), Common::CZ_CZE, ADGF_UNSTABLE, WME_1_9_1), + WME_ENTRY1s("data.dcp", "021ef97f8f49ec33f83beae0d6e38f08", 49336909), Common::CZ_CZE, ADGF_UNSTABLE | GF_3D, WME_1_9_1), // Boredom of Agustin Cordes WME_WINENTRY("agustin", "", @@ -614,7 +625,7 @@ static const WMEGameDescription gameDescriptions[] = { // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("darkfallls", "", WME_ENTRY2s("actors.dcp", "170c7ade10edd7ff6d24b16f2eecd818", 453328582, - "stageplay.dcp", "ed67b4d6e35c19597241eb1d863aa315", 226453373), Common::EN_ANY, ADGF_UNSTABLE, WME_1_8_10), + "stageplay.dcp", "ed67b4d6e35c19597241eb1d863aa315", 226453373), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_8_10), // Dead City (Czech) WME_WINENTRY("deadcity", "", @@ -639,7 +650,7 @@ static const WMEGameDescription gameDescriptions[] = { // Devil In The Capital (Steam, July 2017) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("devilincapital", "", - WME_ENTRY1s("data.dcp","c3a3cd00c0493cddb84ce243272f60be", 1317709066), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_3), + WME_ENTRY1s("data.dcp","c3a3cd00c0493cddb84ce243272f60be", 1317709066), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // DFAF Adventure WME_WINENTRY("dfafadventure", "", @@ -726,50 +737,50 @@ static const WMEGameDescription gameDescriptions[] = { // Face Noir (Bundle version) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("facenoir", "", - WME_ENTRY1s("data.dcp", "50a7a01b97cd3658fc84f2bec7c1212b", 555533359), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_1), + WME_ENTRY1s("data.dcp", "50a7a01b97cd3658fc84f2bec7c1212b", 555533359), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_1), // Face Noir // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("facenoir", "", - WME_ENTRY1s("data.dcp", "dcf71678be9432dcbfb1d9bda640a1a9", 555533343), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_1), + WME_ENTRY1s("data.dcp", "dcf71678be9432dcbfb1d9bda640a1a9", 555533343), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_1), // Face Noir (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("facenoir", "", - WME_ENTRY1s("data.dcp", "a4febf6707f60d37835870cee4e21b14", 551512773), Common::DE_DEU, ADGF_UNSTABLE, WME_1_9_1), + WME_ENTRY1s("data.dcp", "a4febf6707f60d37835870cee4e21b14", 551512773), Common::DE_DEU, ADGF_UNSTABLE | GF_3D, WME_1_9_1), // Face Noir (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("facenoir", "", - WME_ENTRY1s("data.dcp", "e6e9bd5072f9be8a0d8fda94f73f7fba", 559646789), Common::IT_ITA, ADGF_UNSTABLE, WME_1_9_1), + WME_ENTRY1s("data.dcp", "e6e9bd5072f9be8a0d8fda94f73f7fba", 559646789), Common::IT_ITA, ADGF_UNSTABLE | GF_3D, WME_1_9_1), // Face Noir (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("facenoir", "", - WME_ENTRY1s("data.dcp", "97259a073e36b1f2d06d3045e8cdeb77", 551511755), Common::PL_POL, ADGF_UNSTABLE, WME_1_9_1), + WME_ENTRY1s("data.dcp", "97259a073e36b1f2d06d3045e8cdeb77", 551511755), Common::PL_POL, ADGF_UNSTABLE | GF_3D, WME_1_9_1), // Face Noir (Steam Jul 2014) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("facenoir", "", - WME_ENTRY1s("data.dcp", "e162db79d9091faa1d670fc5cdcb4ba9", 555549627), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_1), + WME_ENTRY1s("data.dcp", "e162db79d9091faa1d670fc5cdcb4ba9", 555549627), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_1), // Face Noir (English Demo) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("facenoir", "Demo", WME_ENTRY2s("data.dcp", "545a87636e2f8762d2765d99fddc3806", 289889447, - "data2.dcp", "bb3c7bd14526006b7abd9db4982c8cfd", 197898807), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, WME_1_9_1), + "data2.dcp", "bb3c7bd14526006b7abd9db4982c8cfd", 197898807), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_9_1), // Face Noir (German Demo) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("facenoir", "Demo", WME_ENTRY2s("data.dcp", "dbf0f4545cc31f8bea82387229abe266", 259084466, - "data2.dcp", "b8bb3b1b5ae3bce3c132cb34c11056fe", 55447397), Common::DE_DEU, ADGF_UNSTABLE | ADGF_DEMO, WME_1_9_1), + "data2.dcp", "b8bb3b1b5ae3bce3c132cb34c11056fe", 55447397), Common::DE_DEU, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_9_1), // Face Noir (Polish Demo) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("facenoir", "Demo", WME_ENTRY2s("data.dcp", "8add477c70ffa712a81db4af5fcaa0e1", 293911404, - "data2.dcp", "1874aa7d51121cc43e78f71dbe9c41b7", 197953641), Common::PL_POL, ADGF_UNSTABLE | ADGF_DEMO, WME_1_9_1), + "data2.dcp", "1874aa7d51121cc43e78f71dbe9c41b7", 197953641), Common::PL_POL, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_9_1), // Finding Hope (English) WME_WINENTRY("findinghope", "", @@ -783,12 +794,12 @@ static const WMEGameDescription gameDescriptions[] = { // Forgotten Sound 1 - Revelation (Steam, January 2018) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("forgottensound1", "", - WME_ENTRY1s("data.dcp", "01b8b2b4c55c2d83071f5730269cb313", 937507449), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_3), + WME_ENTRY1s("data.dcp", "01b8b2b4c55c2d83071f5730269cb313", 937507449), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // Forgotten Sound 2 - Destiny (Steam, January 2018) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("forgottensound2", "", - WME_ENTRY1s("data.dcp", "d743f4ffee2a7cc939e314f29a1a0cd6", 1244439717), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_3), + WME_ENTRY1s("data.dcp", "d743f4ffee2a7cc939e314f29a1a0cd6", 1244439717), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // Four WME_WINENTRY("four", "", @@ -1031,6 +1042,66 @@ static const WMEGameDescription gameDescriptions[] = { WME_WINENTRY("foxtail", "1.2.527.3391", WME_ENTRY1s("data.dcp", "e5d06fa058cd9d6f20d6206356e5854d", 109503303), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_527), + // FoxTail 1.2.896.4370 (English) + WME_WINENTRY("foxtail", "1.2.896.4370", + WME_ENTRY1s("data.dcp", "cee21687240aa160b8ebf1e0cccaef59", 154006218), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_896), + + // FoxTail 1.2.896.4370 (German) + WME_WINENTRY("foxtail", "1.2.896.4370", + WME_ENTRY1s("data.dcp", "cee21687240aa160b8ebf1e0cccaef59", 154006218), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_896), + + // FoxTail 1.2.896.4370 (Polish) + WME_WINENTRY("foxtail", "1.2.896.4370", + WME_ENTRY1s("data.dcp", "cee21687240aa160b8ebf1e0cccaef59", 154006218), Common::PL_POL, ADGF_UNSTABLE, FOXTAIL_1_2_896), + + // FoxTail 1.2.896.4370 (Russian) + WME_WINENTRY("foxtail", "1.2.896.4370", + WME_ENTRY1s("data.dcp", "cee21687240aa160b8ebf1e0cccaef59", 154006218), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_896), + + // FoxTail 1.2.896.4370 (Ukranian) + WME_WINENTRY("foxtail", "1.2.896.4370", + WME_ENTRY1s("data.dcp", "cee21687240aa160b8ebf1e0cccaef59", 154006218), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_896), + + // FoxTail 1.2.896.4371 (English) + WME_WINENTRY("foxtail", "1.2.896.4371", + WME_ENTRY1s("data.dcp", "ca9842a6461cc7b00e63b5bc11813971", 154006242), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_896), + + // FoxTail 1.2.896.4371 (German) + WME_WINENTRY("foxtail", "1.2.896.4371", + WME_ENTRY1s("data.dcp", "ca9842a6461cc7b00e63b5bc11813971", 154006242), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_896), + + // FoxTail 1.2.896.4371 (Polish) + WME_WINENTRY("foxtail", "1.2.896.4371", + WME_ENTRY1s("data.dcp", "ca9842a6461cc7b00e63b5bc11813971", 154006242), Common::PL_POL, ADGF_UNSTABLE, FOXTAIL_1_2_896), + + // FoxTail 1.2.896.4371 (Russian) + WME_WINENTRY("foxtail", "1.2.896.4371", + WME_ENTRY1s("data.dcp", "ca9842a6461cc7b00e63b5bc11813971", 154006242), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_896), + + // FoxTail 1.2.896.4371 (Ukranian) + WME_WINENTRY("foxtail", "1.2.896.4371", + WME_ENTRY1s("data.dcp", "ca9842a6461cc7b00e63b5bc11813971", 154006242), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_896), + + // FoxTail 1.2.902.4379 (English) + WME_WINENTRY("foxtail", "1.2.902.4379", + WME_ENTRY1s("data.dcp", "a4a5458afa42ac1d90f4050b033421a4", 153987445), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_902), + + // FoxTail 1.2.902.4379 (German) + WME_WINENTRY("foxtail", "1.2.902.4379", + WME_ENTRY1s("data.dcp", "a4a5458afa42ac1d90f4050b033421a4", 153987445), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_902), + + // FoxTail 1.2.902.4379 (Polish) + WME_WINENTRY("foxtail", "1.2.902.4379", + WME_ENTRY1s("data.dcp", "a4a5458afa42ac1d90f4050b033421a4", 153987445), Common::PL_POL, ADGF_UNSTABLE, FOXTAIL_1_2_902), + + // FoxTail 1.2.902.4379 (Russian) + WME_WINENTRY("foxtail", "1.2.902.4379", + WME_ENTRY1s("data.dcp", "a4a5458afa42ac1d90f4050b033421a4", 153987445), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_902), + + // FoxTail 1.2.902.4379 (Ukranian) + WME_WINENTRY("foxtail", "1.2.902.4379", + WME_ENTRY1s("data.dcp", "a4a5458afa42ac1d90f4050b033421a4", 153987445), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_902), + // Framed (Beta) WME_WINENTRY("framed", "Beta", WME_ENTRY1s("data.dcp", "e7259fb36f2c6f9f28242291e0c3de98", 34690568), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, WME_1_8_11), @@ -1175,6 +1246,28 @@ static const WMEGameDescription gameDescriptions[] = { WME_WINENTRY("jamesperis", "Version 1.8", WME_ENTRY1s("data.dcp", "d6049dfb5dbe812bae1e96924a012500", 225299340), Common::ES_ESP, ADGF_UNSTABLE, WME_1_9_1), + // James Peris: No License Nor Control - Definitive Edition (English) (Steam 2020-03-12) + WME_WINENTRY("jamesperis", "Version 1.9", + WME_ENTRY2s("data.dcp", "60568c88c9dc5653bfc94a8cbf228748", 225299678, + "parche9.dcp", "05363aa13cb8aa5a3fafc68adb4dda5a", 207640138), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_3), + + // James Peris: No License Nor Control - Definitive Edition (Spanish) (Steam 2020-03-12) + WME_WINENTRY("jamesperis", "Version 1.9", + WME_ENTRY2s("data.dcp", "60568c88c9dc5653bfc94a8cbf228748", 225299678, + "parche9.dcp", "05363aa13cb8aa5a3fafc68adb4dda5a", 207640138), Common::ES_ESP, ADGF_UNSTABLE, WME_1_9_3), + + // James Peris: No License Nor Control - Definitive Edition (English) (Steam 2020-04-27) + WME_WINENTRY("jamesperis", "Version 1.9.1e", + WME_ENTRY3s("data.dcp", "60568c88c9dc5653bfc94a8cbf228748", 225299678, + "parche9.dcp", "05363aa13cb8aa5a3fafc68adb4dda5a", 207640138, + "parche91e.dcp", "ee21819363fb32a38b9f5fcf8545e374", 72496832), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_3), + + // James Peris: No License Nor Control - Definitive Edition (Spanish) (Steam 2020-04-27) + WME_WINENTRY("jamesperis", "Version 1.9.1e", + WME_ENTRY3s("data.dcp", "60568c88c9dc5653bfc94a8cbf228748", 225299678, + "parche9.dcp", "05363aa13cb8aa5a3fafc68adb4dda5a", 207640138, + "parche91e.dcp", "ee21819363fb32a38b9f5fcf8545e374", 72496832), Common::ES_ESP, ADGF_UNSTABLE, WME_1_9_3), + // James Peris: No License Nor Control (Demo) (English) WME_WINENTRY("jamesperis", "Demo", WME_ENTRY1s("data.dcp", "edb9f9c7a08993c1e28f4e477b5f9830", 116113507), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, WME_1_9_1), @@ -1186,104 +1279,104 @@ static const WMEGameDescription gameDescriptions[] = { // Lov Mamuta // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("lovmamuta", "", - WME_ENTRY1s("data.dcp", "ce2be4691fa0104cfdd63656cedaf810", 11198933), Common::CZ_CZE, ADGF_UNSTABLE, WME_1_9_1), + WME_ENTRY1s("data.dcp", "ce2be4691fa0104cfdd63656cedaf810", 11198933), Common::CZ_CZE, ADGF_UNSTABLE | GF_3D, WME_1_9_1), // J.U.L.I.A. (English) // NOTE: This is a 2.5D game that is out of ScummVM scope, however it is reported as completable with VFX low WME_WINENTRY("julia", "", - WME_ENTRY1s("data.dcp", "c2264b4f8fcd132d2913ff5b6076a24f", 10109741), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_3), + WME_ENTRY1s("data.dcp", "c2264b4f8fcd132d2913ff5b6076a24f", 10109741), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // J.U.L.I.A. (English, reported by Duffadash in https://bugs.scummvm.org/ticket/11350) // NOTE: This is a 2.5D game that is out of ScummVM scope, however it is reported as completable with VFX low WME_WINENTRY("julia", "", - WME_ENTRY1s("data.dcp", "891058639eb4d9815540c95a495b5a88", 10105692), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_3), + WME_ENTRY1s("data.dcp", "891058639eb4d9815540c95a495b5a88", 10105692), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // J.U.L.I.A. (English, Bundle in a box-version) // NOTE: This is a 2.5D game that is out of ScummVM scope, however it is reported as completable with VFX low WME_WINENTRY("julia", "Version 1.2", - WME_ENTRY1s("data.dcp", "fe90023ccc22f35185b40b910e0d03a2", 10101373), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_3), + WME_ENTRY1s("data.dcp", "fe90023ccc22f35185b40b910e0d03a2", 10101373), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // J.U.L.I.A. (English) (Demo) // NOTE: This is a 2.5D game that is out of ScummVM scope, however it is reported as completable with VFX low WME_WINENTRY("julia", "Demo", - WME_ENTRY1s("data.dcp", "f0bbc3394555a9811f6050dae428cab6", 7655237), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, WME_1_9_3), + WME_ENTRY1s("data.dcp", "f0bbc3394555a9811f6050dae428cab6", 7655237), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_9_3), // J.U.L.I.A. (English) (Greenlight Demo) // NOTE: This is a 2.5D game that is out of ScummVM scope, however it is reported as completable with VFX low WME_WINENTRY("julia", "Greenlight Demo", - WME_ENTRY1s("data.dcp", "4befd448d36b0dae9c3ab1aa7cb8b78d", 7271886), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, WME_1_9_3), + WME_ENTRY1s("data.dcp", "4befd448d36b0dae9c3ab1aa7cb8b78d", 7271886), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_9_3), // J.U.L.I.A.: Among the Stars (HD Ready Version) (Steam, January 2017) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("juliastars", "HD Ready Version/Steam", WME_ENTRY2s("data_sd.dcp", "9949302dfaea943113e2f0ee0dd468be", 4249680, - "data_sd.dcp", "9949302dfaea943113e2f0ee0dd468be", 4249680), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_LITE), + "data_sd.dcp", "9949302dfaea943113e2f0ee0dd468be", 4249680), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_LITE), // J.U.L.I.A.: Among the Stars (Full HD Version) (Steam, January 2017) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("juliastars", "Full HD Version/Steam", WME_ENTRY2s("data_hd.dcp", "fd579fa333f117882190993ea4f3bba5", 5164463, - "data_hd.dcp", "fd579fa333f117882190993ea4f3bba5", 5164463), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_LITE), + "data_hd.dcp", "fd579fa333f117882190993ea4f3bba5", 5164463), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_LITE), // J.U.L.I.A.: Among the Stars (HD Ready Version) (Steam, November 2016) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("juliastars", "HD Ready Version/Steam", WME_ENTRY2s("data_sd.dcp", "dfaf7e730a66412f68d11cddb0c8737d", 4505667, - "german_sd.dcp", "23ceb8625cebfe32aaa5950e89ac68ba", 123326075), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_LITE), + "german_sd.dcp", "23ceb8625cebfe32aaa5950e89ac68ba", 123326075), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_LITE), // J.U.L.I.A.: Among the Stars (Full HD Version) (Steam, November 2016) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("juliastars", "Full HD Version/Steam", WME_ENTRY2s("data_hd.dcp", "f40b3d0778e37c61cf309d214446d233", 5264780, - "german_hd.dcp", "8d85f83a3fc8f1bec4e5ba2158b05b1e", 152499998), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_LITE), + "german_hd.dcp", "8d85f83a3fc8f1bec4e5ba2158b05b1e", 152499998), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_LITE), // J.U.L.I.A.: Among the Stars (HD Ready Version) (Steam) (Spanish fanmade translation) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("juliastars", "HD Ready Version/Steam", WME_ENTRY2s("data_sd.dcp", "da3508bd60025bac35211fb6fc959d88", 5655554, - "data_sd.dcp", "da3508bd60025bac35211fb6fc959d88", 5655554), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_LITE), + "data_sd.dcp", "da3508bd60025bac35211fb6fc959d88", 5655554), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_LITE), // J.U.L.I.A.: Among the Stars (Full HD Version) (Steam) (Spanish fanmade translation) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("juliastars", "Full HD Version/Steam", WME_ENTRY2s("data_hd.dcp", "da3508bd60025bac35211fb6fc959d88", 5655554, - "data_hd.dcp", "da3508bd60025bac35211fb6fc959d88", 5655554), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_LITE), + "data_hd.dcp", "da3508bd60025bac35211fb6fc959d88", 5655554), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_LITE), // J.U.L.I.A.: Among the Stars (HD Ready Version) (GOG) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("juliastars", "HD Ready Version/GOG", WME_ENTRY2s("data_sd.dcp", "da1f147a5f2ee6eb0750678a8b955c93", 4526792, - "data_sd.dcp", "da1f147a5f2ee6eb0750678a8b955c93", 4526792), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_LITE), + "data_sd.dcp", "da1f147a5f2ee6eb0750678a8b955c93", 4526792), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_LITE), // J.U.L.I.A.: Among the Stars (Full HD Version) (GOG) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("juliastars", "Full HD Version/GOG", WME_ENTRY2s("data_hd.dcp", "91dcb65523da943f22fca0c025a2ce8e", 5281911, - "data_hd.dcp", "91dcb65523da943f22fca0c025a2ce8e", 5281911), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_LITE), + "data_hd.dcp", "91dcb65523da943f22fca0c025a2ce8e", 5281911), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_LITE), // J.U.L.I.A.: Among the Stars (HD Ready Version) (GOG) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("juliastars", "HD Ready Version/GOG", WME_ENTRY2s("data_sd.dcp", "070d13b70e35cd95855ddc1687446631", 4526795, - "german_sd.dcp", "85eb39225083465225c30261a6bcd63e", 123326134), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_LITE), + "german_sd.dcp", "85eb39225083465225c30261a6bcd63e", 123326134), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_LITE), // J.U.L.I.A.: Among the Stars (Full HD Version) (GOG) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("juliastars", "Full HD Version/GOG", WME_ENTRY2s("data_hd.dcp", "7973ca635255d3791123fd750cb848f2", 5281925, - "german_hd.dcp", "19a771b1a933b71b889026d53734b0c0", 152500044), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_LITE), + "german_hd.dcp", "19a771b1a933b71b889026d53734b0c0", 152500044), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_LITE), // J.U.L.I.A.: Among the Stars (HD Ready Version) (GOG) (Spanish fanmade translation) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("juliastars", "HD Ready Version/GOG", WME_ENTRY2s("data_sd.dcp", "29f4856cc1514bdb86d3b19a39d86d76", 5877935, - "data_sd.dcp", "29f4856cc1514bdb86d3b19a39d86d76", 5877935), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_LITE), + "data_sd.dcp", "29f4856cc1514bdb86d3b19a39d86d76", 5877935), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_LITE), // J.U.L.I.A.: Among the Stars (Full HD Version) (GOG) (Spanish fanmade translation) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("juliastars", "Full HD Version/GOG", WME_ENTRY2s("data_hd.dcp", "29f4856cc1514bdb86d3b19a39d86d76", 5877935, - "data_hd.dcp", "29f4856cc1514bdb86d3b19a39d86d76", 5877935), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_LITE), + "data_hd.dcp", "29f4856cc1514bdb86d3b19a39d86d76", 5877935), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_LITE), // J.U.L.I.A.: Untold (Steam, January 2016) WME_WINENTRY("juliauntold", "Steam", @@ -1336,12 +1429,12 @@ static const WMEGameDescription gameDescriptions[] = { // Limbo of the Lost (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("lotl", "", - WME_ENTRY1s("data.dcp", "637f2195a08f59e809ca48194a2ee73d", 354879400), Common::EN_ANY, ADGF_UNSTABLE, WME_1_7_2), + WME_ENTRY1s("data.dcp", "637f2195a08f59e809ca48194a2ee73d", 354879400), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_7_2), // Limbo of the Lost (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("lotl", "", - WME_ENTRY1s("data.dcp", "2042ea14f2d7c52a139d768e962040c1", 354370575), Common::RU_RUS, ADGF_UNSTABLE, WME_1_7_2), + WME_ENTRY1s("data.dcp", "2042ea14f2d7c52a139d768e962040c1", 354370575), Common::RU_RUS, ADGF_UNSTABLE | GF_3D, WME_1_7_2), // Machu Mayu (Demo) WME_WINENTRY("machumayu", "Demo", @@ -1351,13 +1444,13 @@ static const WMEGameDescription gameDescriptions[] = { // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("mentalrepairs", "", WME_ENTRY2s("data.dcp", "414d423bbff697f22fb38932f030e897", 59518068, - "english.dcp", "7573eb584e662adbc5fa3b1448e56106", 3160232), Common::EN_ANY, ADGF_UNSTABLE, WME_1_8_6), + "english.dcp", "7573eb584e662adbc5fa3b1448e56106", 3160232), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_8_6), // Mental Repairs Inc (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("mentalrepairs", "", WME_ENTRY2s("data.dcp", "414d423bbff697f22fb38932f030e897", 59518068, - "german.dcp", "af59a05ef29768e7fced3794a7a380a3", 3249142), Common::DE_DEU, ADGF_UNSTABLE, WME_1_8_6), + "german.dcp", "af59a05ef29768e7fced3794a7a380a3", 3249142), Common::DE_DEU, ADGF_UNSTABLE | GF_3D, WME_1_8_6), // Mirage WME_WINENTRY("mirage", "", @@ -1441,7 +1534,7 @@ static const WMEGameDescription gameDescriptions[] = { // Palladion (Alpha6h) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("palladion", "Alpha6h", - WME_ENTRY1s("Palladion_Alpha6h.exe", "55aec582159410ec6221d4c3fd53db24", 95240860), Common::DE_DEU, ADGF_UNSTABLE | ADGF_DEMO, WME_1_8_6), + WME_ENTRY1s("Palladion_Alpha6h.exe", "55aec582159410ec6221d4c3fd53db24", 95240860), Common::DE_DEU, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_8_6), // Papa's Daughters WME_WINENTRY("papasdaughters1", "", @@ -1459,7 +1552,7 @@ static const WMEGameDescription gameDescriptions[] = { // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("pizzamorgana", "Demo", WME_ENTRY2s("english.dcp", "7fa6149bb44574109668ce585d6c41c9", 9282608, - "data.dcp", "a69994c463ff5fcc6fe1800662f5b7d0", 34581370), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, WME_1_9_1), + "data.dcp", "a69994c463ff5fcc6fe1800662f5b7d0", 34581370), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_9_1), // Pole Chudes WME_WINENTRY("polechudes", "", @@ -1493,19 +1586,19 @@ static const WMEGameDescription gameDescriptions[] = { // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("reptilesquest", "Beta 2.5", WME_ENTRY2s("data.dcp", "b624d3b19e37c094801a28d817bc3d76", 27345755, - "english.dcp", "42188d46ee079b555d578ea2b406fa19", 3897), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, WME_1_9_1), + "english.dcp", "42188d46ee079b555d578ea2b406fa19", 3897), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_9_1), // On the Tracks of Dinosaurs (Beta 2.5) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("reptilesquest", "Beta 2.5", WME_ENTRY2s("data.dcp", "b624d3b19e37c094801a28d817bc3d76", 27345755, - "italian.dcp", "361f41b1151119f66de851f07b78b7cc", 4132), Common::IT_ITA, ADGF_UNSTABLE | ADGF_DEMO, WME_1_9_1), + "italian.dcp", "361f41b1151119f66de851f07b78b7cc", 4132), Common::IT_ITA, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_9_1), // On the Tracks of Dinosaurs (Beta 2.5) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("reptilesquest", "Beta 2.5", WME_ENTRY2s("data.dcp", "b624d3b19e37c094801a28d817bc3d76", 27345755, - "russian.dcp", "90d2bf541ba381bbb3375aa7d31613fb", 42175), Common::RU_RUS, ADGF_UNSTABLE | ADGF_DEMO, WME_1_9_1), + "russian.dcp", "90d2bf541ba381bbb3375aa7d31613fb", 42175), Common::RU_RUS, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_9_1), // Reversion: The Escape Version 1.0 WME_WINENTRY("reversion1", "Version 1.0", @@ -3538,1204 +3631,1204 @@ static const WMEGameDescription gameDescriptions[] = { WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e19b63c6aa19d491a4f533ac9c1609ef", 97061505, "data_sd.dcp", "aee08a5a713c1b45e67471134772f72f", 97833631, - "i18n_de_strings.dcp", "9cc009980d018476b177e2a4075f56b4", 43104), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "9cc009980d018476b177e2a4075f56b4", 43104), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Jul 2014) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e19b63c6aa19d491a4f533ac9c1609ef", 97061505, "data_sd.dcp", "aee08a5a713c1b45e67471134772f72f", 97833631, - "i18n_en_strings.dcp", "40f8ea49a3e8d54a5202aa88c12fba80", 75108), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "40f8ea49a3e8d54a5202aa88c12fba80", 75108), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Jul 2014) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e19b63c6aa19d491a4f533ac9c1609ef", 97061505, "data_sd.dcp", "aee08a5a713c1b45e67471134772f72f", 97833631, - "i18n_es_strings.dcp", "6a8d5b434dfe758abb2ace1a75a4dab1", 40122), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "6a8d5b434dfe758abb2ace1a75a4dab1", 40122), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Jul 2014) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e19b63c6aa19d491a4f533ac9c1609ef", 97061505, "data_sd.dcp", "aee08a5a713c1b45e67471134772f72f", 97833631, - "i18n_fr_strings.dcp", "b3fe8c720bb6a5378f6da2f593339c70", 40760), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "b3fe8c720bb6a5378f6da2f593339c70", 40760), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Jul 2014) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e19b63c6aa19d491a4f533ac9c1609ef", 97061505, "data_sd.dcp", "aee08a5a713c1b45e67471134772f72f", 97833631, - "i18n_it_strings.dcp", "5abaab4d57d7585b3c4b23f34f2d0dd8", 40468), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "5abaab4d57d7585b3c4b23f34f2d0dd8", 40468), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Feb 12th 2015) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e382f34f0bd319ad310aba2ecd239dec", 95879376, "data_sd.dcp", "6842ddf537f2cd186df050aa8c05d363", 97835480, - "i18n_de_strings.dcp", "780b0d8d4f2b2b32e729090c1018df43", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "780b0d8d4f2b2b32e729090c1018df43", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Feb 12th 2015) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e382f34f0bd319ad310aba2ecd239dec", 95879376, "data_sd.dcp", "6842ddf537f2cd186df050aa8c05d363", 97835480, - "i18n_en_strings.dcp", "636e32cf89f02fca30a6f4caa38dede1", 75126), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "636e32cf89f02fca30a6f4caa38dede1", 75126), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Feb 12th 2015) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e382f34f0bd319ad310aba2ecd239dec", 95879376, "data_sd.dcp", "6842ddf537f2cd186df050aa8c05d363", 97835480, - "i18n_es_strings.dcp", "c62f94e9cd543ecbdc0f02acc744cd29", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "c62f94e9cd543ecbdc0f02acc744cd29", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Feb 12th 2015) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e382f34f0bd319ad310aba2ecd239dec", 95879376, "data_sd.dcp", "6842ddf537f2cd186df050aa8c05d363", 97835480, - "i18n_fr_strings.dcp", "548e88d67be123bb54f5b265226f051a", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "548e88d67be123bb54f5b265226f051a", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Feb 12th 2015) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e382f34f0bd319ad310aba2ecd239dec", 95879376, "data_sd.dcp", "6842ddf537f2cd186df050aa8c05d363", 97835480, - "i18n_it_strings.dcp", "c3d180dd634705cb16ccd650066e1da8", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "c3d180dd634705cb16ccd650066e1da8", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Feb 12th 2015) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e382f34f0bd319ad310aba2ecd239dec", 95879376, "data_sd.dcp", "6842ddf537f2cd186df050aa8c05d363", 97835480, - "i18n_pl_strings.dcp", "8dac09efb73ae4a7a2b897de6f37e906", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "8dac09efb73ae4a7a2b897de6f37e906", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Feb 12th 2015) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e382f34f0bd319ad310aba2ecd239dec", 95879376, "data_sd.dcp", "6842ddf537f2cd186df050aa8c05d363", 97835480, - "i18n_ru_strings.dcp", "88daa5c022c18535e2da86fa558db792", 45838), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "88daa5c022c18535e2da86fa558db792", 45838), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Feb 22th 2015) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "bb6136d76ebadf06c90877283aa1d55a", 95890682, "data_sd.dcp", "6135b62bb28434c1af42de84ef8b96fe", 97808411, - "i18n_de_strings.dcp", "d245d247a282cda33b83ed6918b2e6d5", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "d245d247a282cda33b83ed6918b2e6d5", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Feb 22th 2015) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "bb6136d76ebadf06c90877283aa1d55a", 95890682, "data_sd.dcp", "6135b62bb28434c1af42de84ef8b96fe", 97808411, - "i18n_en_strings.dcp", "5e9cf5a8403b98f7d92de55efccc0d34", 75119), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "5e9cf5a8403b98f7d92de55efccc0d34", 75119), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Feb 22th 2015) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "bb6136d76ebadf06c90877283aa1d55a", 95890682, "data_sd.dcp", "6135b62bb28434c1af42de84ef8b96fe", 97808411, - "i18n_es_strings.dcp", "edb19a0758243da8929844bac035d384", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "edb19a0758243da8929844bac035d384", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Feb 22th 2015) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "bb6136d76ebadf06c90877283aa1d55a", 95890682, "data_sd.dcp", "6135b62bb28434c1af42de84ef8b96fe", 97808411, - "i18n_fr_strings.dcp", "40dda8156fa93717cf962e75d76929b1", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "40dda8156fa93717cf962e75d76929b1", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Feb 22th 2015) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "bb6136d76ebadf06c90877283aa1d55a", 95890682, "data_sd.dcp", "6135b62bb28434c1af42de84ef8b96fe", 97808411, - "i18n_it_strings.dcp", "0d1dac14379e55356794fb7cca8865b2", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "0d1dac14379e55356794fb7cca8865b2", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Feb 22th 2015) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "bb6136d76ebadf06c90877283aa1d55a", 95890682, "data_sd.dcp", "6135b62bb28434c1af42de84ef8b96fe", 97808411, - "i18n_pl_strings.dcp", "cdd0b203c591dfb411cb6fc89ac009c1", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "cdd0b203c591dfb411cb6fc89ac009c1", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Feb 22th 2015) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "bb6136d76ebadf06c90877283aa1d55a", 95890682, "data_sd.dcp", "6135b62bb28434c1af42de84ef8b96fe", 97808411, - "i18n_ru_strings.dcp", "77fc889bb25438bafe897d1566bd7e50", 45546), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "77fc889bb25438bafe897d1566bd7e50", 45546), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Sep 2016) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "46bb5822abf6d422d08a68070e05bd86", 95890675, "data_sd.dcp", "8864e2e552bb7816916d8c6630e8f1a5", 97821007, - "i18n_de_strings.dcp", "94230807d77dacb420f446c34dd60072", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "94230807d77dacb420f446c34dd60072", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Sep 2016) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "46bb5822abf6d422d08a68070e05bd86", 95890675, "data_sd.dcp", "8864e2e552bb7816916d8c6630e8f1a5", 97821007, - "i18n_en_strings.dcp", "253e7f5e2bb4a33c7df52a04624d18c6", 75119), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "253e7f5e2bb4a33c7df52a04624d18c6", 75119), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Sep 2016) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "46bb5822abf6d422d08a68070e05bd86", 95890675, "data_sd.dcp", "8864e2e552bb7816916d8c6630e8f1a5", 97821007, - "i18n_es_strings.dcp", "2227cee67309f564178e48d3eb30fc98", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "2227cee67309f564178e48d3eb30fc98", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Sep 2016) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "46bb5822abf6d422d08a68070e05bd86", 95890675, "data_sd.dcp", "8864e2e552bb7816916d8c6630e8f1a5", 97821007, - "i18n_fr_strings.dcp", "f50d251df43e5433b9664d5c2463fb08", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "f50d251df43e5433b9664d5c2463fb08", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Sep 2016) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "46bb5822abf6d422d08a68070e05bd86", 95890675, "data_sd.dcp", "8864e2e552bb7816916d8c6630e8f1a5", 97821007, - "i18n_it_strings.dcp", "6ad0d7c0a0c450d6af334cd1b4dbe72e", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "6ad0d7c0a0c450d6af334cd1b4dbe72e", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Sep 2016) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "46bb5822abf6d422d08a68070e05bd86", 95890675, "data_sd.dcp", "8864e2e552bb7816916d8c6630e8f1a5", 97821007, - "i18n_pl_strings.dcp", "7c07fb021517dd21ba2e2a5739d0168e", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "7c07fb021517dd21ba2e2a5739d0168e", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Sep 2016) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "46bb5822abf6d422d08a68070e05bd86", 95890675, "data_sd.dcp", "8864e2e552bb7816916d8c6630e8f1a5", 97821007, - "i18n_ru_strings.dcp", "5cecc876ec1b364f22780d18a0821349", 45546), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "5cecc876ec1b364f22780d18a0821349", 45546), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Jun 2018) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e0d5b1276cf80c858b7404f1f3381e2b", 95890675, "data_sd.dcp", "551feca25b9e0ac9d467c105efb373e8", 97979104, - "i18n_de_strings.dcp", "59d15bb3c32354b5104475df0ff6c50b", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "59d15bb3c32354b5104475df0ff6c50b", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Jun 2018) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e0d5b1276cf80c858b7404f1f3381e2b", 95890675, "data_sd.dcp", "551feca25b9e0ac9d467c105efb373e8", 97979104, - "i18n_en_strings.dcp", "733a53213ab5be27941c34dcef531e0e", 75119), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "733a53213ab5be27941c34dcef531e0e", 75119), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Jun 2018) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e0d5b1276cf80c858b7404f1f3381e2b", 95890675, "data_sd.dcp", "551feca25b9e0ac9d467c105efb373e8", 97979104, - "i18n_es_strings.dcp", "18876a252741b8bda888805ca860f600", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "18876a252741b8bda888805ca860f600", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Jun 2018) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e0d5b1276cf80c858b7404f1f3381e2b", 95890675, "data_sd.dcp", "551feca25b9e0ac9d467c105efb373e8", 97979104, - "i18n_fr_strings.dcp", "850cce9217d83785e4b56028441b0d71", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "850cce9217d83785e4b56028441b0d71", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Jun 2018) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e0d5b1276cf80c858b7404f1f3381e2b", 95890675, "data_sd.dcp", "551feca25b9e0ac9d467c105efb373e8", 97979104, - "i18n_it_strings.dcp", "de567598fba43589841c354306a80377", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "de567598fba43589841c354306a80377", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Jun 2018) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e0d5b1276cf80c858b7404f1f3381e2b", 95890675, "data_sd.dcp", "551feca25b9e0ac9d467c105efb373e8", 97979104, - "i18n_pl_strings.dcp", "daa4b251caec6c6e2c3b96aaf87ae33a", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "daa4b251caec6c6e2c3b96aaf87ae33a", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Legacy Version) (Steam, Jun 2018) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Legacy Version", WME_ENTRY3s("data.dcp", "e0d5b1276cf80c858b7404f1f3381e2b", 95890675, "data_sd.dcp", "551feca25b9e0ac9d467c105efb373e8", 97979104, - "i18n_ru_strings.dcp", "ebf28ca1475b3be9754a323966807683", 45546), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "ebf28ca1475b3be9754a323966807683", 45546), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Jul 2014) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e19b63c6aa19d491a4f533ac9c1609ef", 97061505, "data_hd.dcp", "d8d903cbda2ff7001cc7ce949775897e", 197016744, - "i18n_de_strings.dcp", "9cc009980d018476b177e2a4075f56b4", 43104), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "9cc009980d018476b177e2a4075f56b4", 43104), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Jul 2014) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e19b63c6aa19d491a4f533ac9c1609ef", 97061505, "data_hd.dcp", "d8d903cbda2ff7001cc7ce949775897e", 197016744, - "i18n_en_strings.dcp", "40f8ea49a3e8d54a5202aa88c12fba80", 75108), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "40f8ea49a3e8d54a5202aa88c12fba80", 75108), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Jul 2014) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e19b63c6aa19d491a4f533ac9c1609ef", 97061505, "data_hd.dcp", "d8d903cbda2ff7001cc7ce949775897e", 197016744, - "i18n_es_strings.dcp", "6a8d5b434dfe758abb2ace1a75a4dab1", 40122), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "6a8d5b434dfe758abb2ace1a75a4dab1", 40122), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Jul 2014) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e19b63c6aa19d491a4f533ac9c1609ef", 97061505, "data_hd.dcp", "d8d903cbda2ff7001cc7ce949775897e", 197016744, - "i18n_fr_strings.dcp", "b3fe8c720bb6a5378f6da2f593339c70", 40760), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "b3fe8c720bb6a5378f6da2f593339c70", 40760), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Jul 2014) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e19b63c6aa19d491a4f533ac9c1609ef", 97061505, "data_hd.dcp", "d8d903cbda2ff7001cc7ce949775897e", 197016744, - "i18n_it_strings.dcp", "5abaab4d57d7585b3c4b23f34f2d0dd8", 40468), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "5abaab4d57d7585b3c4b23f34f2d0dd8", 40468), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Feb 12th 2015) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e382f34f0bd319ad310aba2ecd239dec", 95879376, "data_hd.dcp", "1a077e884c659f34da61dd205591f83d", 197018612, - "i18n_de_strings.dcp", "780b0d8d4f2b2b32e729090c1018df43", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "780b0d8d4f2b2b32e729090c1018df43", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Feb 12th 2015) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e382f34f0bd319ad310aba2ecd239dec", 95879376, "data_hd.dcp", "1a077e884c659f34da61dd205591f83d", 197018612, - "i18n_en_strings.dcp", "636e32cf89f02fca30a6f4caa38dede1", 75126), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "636e32cf89f02fca30a6f4caa38dede1", 75126), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Feb 12th 2015) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e382f34f0bd319ad310aba2ecd239dec", 95879376, "data_hd.dcp", "1a077e884c659f34da61dd205591f83d", 197018612, - "i18n_es_strings.dcp", "c62f94e9cd543ecbdc0f02acc744cd29", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "c62f94e9cd543ecbdc0f02acc744cd29", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Feb 12th 2015) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e382f34f0bd319ad310aba2ecd239dec", 95879376, "data_hd.dcp", "1a077e884c659f34da61dd205591f83d", 197018612, - "i18n_fr_strings.dcp", "548e88d67be123bb54f5b265226f051a", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "548e88d67be123bb54f5b265226f051a", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Feb 12th 2015) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e382f34f0bd319ad310aba2ecd239dec", 95879376, "data_hd.dcp", "1a077e884c659f34da61dd205591f83d", 197018612, - "i18n_it_strings.dcp", "c3d180dd634705cb16ccd650066e1da8", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "c3d180dd634705cb16ccd650066e1da8", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Feb 12th 2015) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e382f34f0bd319ad310aba2ecd239dec", 95879376, "data_hd.dcp", "1a077e884c659f34da61dd205591f83d", 197018612, - "i18n_pl_strings.dcp", "8dac09efb73ae4a7a2b897de6f37e906", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "8dac09efb73ae4a7a2b897de6f37e906", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Feb 12th 2015) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e382f34f0bd319ad310aba2ecd239dec", 95879376, "data_hd.dcp", "1a077e884c659f34da61dd205591f83d", 197018612, - "i18n_ru_strings.dcp", "88daa5c022c18535e2da86fa558db792", 45838), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "88daa5c022c18535e2da86fa558db792", 45838), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Feb 22th 2015) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "bb6136d76ebadf06c90877283aa1d55a", 95890682, "data_hd.dcp", "bfd3bc963c073af866e5405d6d5f1347", 197125364, - "i18n_de_strings.dcp", "d245d247a282cda33b83ed6918b2e6d5", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "d245d247a282cda33b83ed6918b2e6d5", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Feb 22th 2015) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "bb6136d76ebadf06c90877283aa1d55a", 95890682, "data_hd.dcp", "bfd3bc963c073af866e5405d6d5f1347", 197125364, - "i18n_en_strings.dcp", "5e9cf5a8403b98f7d92de55efccc0d34", 75119), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "5e9cf5a8403b98f7d92de55efccc0d34", 75119), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Feb 22th 2015) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "bb6136d76ebadf06c90877283aa1d55a", 95890682, "data_hd.dcp", "bfd3bc963c073af866e5405d6d5f1347", 197125364, - "i18n_es_strings.dcp", "edb19a0758243da8929844bac035d384", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "edb19a0758243da8929844bac035d384", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Feb 22th 2015) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "bb6136d76ebadf06c90877283aa1d55a", 95890682, "data_hd.dcp", "bfd3bc963c073af866e5405d6d5f1347", 197125364, - "i18n_fr_strings.dcp", "40dda8156fa93717cf962e75d76929b1", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "40dda8156fa93717cf962e75d76929b1", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Feb 22th 2015) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "bb6136d76ebadf06c90877283aa1d55a", 95890682, "data_hd.dcp", "bfd3bc963c073af866e5405d6d5f1347", 197125364, - "i18n_it_strings.dcp", "0d1dac14379e55356794fb7cca8865b2", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "0d1dac14379e55356794fb7cca8865b2", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Feb 22th 2015) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "bb6136d76ebadf06c90877283aa1d55a", 95890682, "data_hd.dcp", "bfd3bc963c073af866e5405d6d5f1347", 197125364, - "i18n_pl_strings.dcp", "cdd0b203c591dfb411cb6fc89ac009c1", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "cdd0b203c591dfb411cb6fc89ac009c1", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Feb 22th 2015) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "bb6136d76ebadf06c90877283aa1d55a", 95890682, "data_hd.dcp", "bfd3bc963c073af866e5405d6d5f1347", 197125364, - "i18n_ru_strings.dcp", "77fc889bb25438bafe897d1566bd7e50", 45546), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "77fc889bb25438bafe897d1566bd7e50", 45546), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Sep 2016) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "46bb5822abf6d422d08a68070e05bd86", 95890675, "data_hd.dcp", "79a5c4ae560817a149506dce894274d0", 197155130, - "i18n_de_strings.dcp", "94230807d77dacb420f446c34dd60072", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "94230807d77dacb420f446c34dd60072", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Sep 2016) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "46bb5822abf6d422d08a68070e05bd86", 95890675, "data_hd.dcp", "79a5c4ae560817a149506dce894274d0", 197155130, - "i18n_en_strings.dcp", "253e7f5e2bb4a33c7df52a04624d18c6", 75119), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "253e7f5e2bb4a33c7df52a04624d18c6", 75119), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Sep 2016) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "46bb5822abf6d422d08a68070e05bd86", 95890675, "data_hd.dcp", "79a5c4ae560817a149506dce894274d0", 197155130, - "i18n_es_strings.dcp", "2227cee67309f564178e48d3eb30fc98", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "2227cee67309f564178e48d3eb30fc98", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Sep 2016) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "46bb5822abf6d422d08a68070e05bd86", 95890675, "data_hd.dcp", "79a5c4ae560817a149506dce894274d0", 197155130, - "i18n_fr_strings.dcp", "f50d251df43e5433b9664d5c2463fb08", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "f50d251df43e5433b9664d5c2463fb08", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Sep 2016) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "46bb5822abf6d422d08a68070e05bd86", 95890675, "data_hd.dcp", "79a5c4ae560817a149506dce894274d0", 197155130, - "i18n_it_strings.dcp", "6ad0d7c0a0c450d6af334cd1b4dbe72e", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "6ad0d7c0a0c450d6af334cd1b4dbe72e", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Sep 2016) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "46bb5822abf6d422d08a68070e05bd86", 95890675, "data_hd.dcp", "79a5c4ae560817a149506dce894274d0", 197155130, - "i18n_pl_strings.dcp", "7c07fb021517dd21ba2e2a5739d0168e", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "7c07fb021517dd21ba2e2a5739d0168e", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Sep 2016) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "46bb5822abf6d422d08a68070e05bd86", 95890675, "data_hd.dcp", "79a5c4ae560817a149506dce894274d0", 197155130, - "i18n_ru_strings.dcp", "5cecc876ec1b364f22780d18a0821349", 45546), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "5cecc876ec1b364f22780d18a0821349", 45546), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Jun 2018) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e0d5b1276cf80c858b7404f1f3381e2b", 95890675, "data_hd.dcp", "05ce36b4c7b947c503496a1d895671e5", 197431006, - "i18n_de_strings.dcp", "59d15bb3c32354b5104475df0ff6c50b", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "59d15bb3c32354b5104475df0ff6c50b", 43136), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Jun 2018) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e0d5b1276cf80c858b7404f1f3381e2b", 95890675, "data_hd.dcp", "05ce36b4c7b947c503496a1d895671e5", 197431006, - "i18n_en_strings.dcp", "733a53213ab5be27941c34dcef531e0e", 75119), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "733a53213ab5be27941c34dcef531e0e", 75119), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Jun 2018) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e0d5b1276cf80c858b7404f1f3381e2b", 95890675, "data_hd.dcp", "05ce36b4c7b947c503496a1d895671e5", 197431006, - "i18n_es_strings.dcp", "18876a252741b8bda888805ca860f600", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "18876a252741b8bda888805ca860f600", 40153), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Jun 2018) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e0d5b1276cf80c858b7404f1f3381e2b", 95890675, "data_hd.dcp", "05ce36b4c7b947c503496a1d895671e5", 197431006, - "i18n_fr_strings.dcp", "850cce9217d83785e4b56028441b0d71", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "850cce9217d83785e4b56028441b0d71", 40807), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Jun 2018) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e0d5b1276cf80c858b7404f1f3381e2b", 95890675, "data_hd.dcp", "05ce36b4c7b947c503496a1d895671e5", 197431006, - "i18n_it_strings.dcp", "de567598fba43589841c354306a80377", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "de567598fba43589841c354306a80377", 40502), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Jun 2018) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e0d5b1276cf80c858b7404f1f3381e2b", 95890675, "data_hd.dcp", "05ce36b4c7b947c503496a1d895671e5", 197431006, - "i18n_pl_strings.dcp", "daa4b251caec6c6e2c3b96aaf87ae33a", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "daa4b251caec6c6e2c3b96aaf87ae33a", 40062), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act I: Greed (Full HD Version) (Steam, Jun 2018) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv1", "Full HD Version", WME_ENTRY3s("data.dcp", "e0d5b1276cf80c858b7404f1f3381e2b", 95890675, "data_hd.dcp", "05ce36b4c7b947c503496a1d895671e5", 197431006, - "i18n_ru_strings.dcp", "ebf28ca1475b3be9754a323966807683", 45546), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "ebf28ca1475b3be9754a323966807683", 45546), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 26th 2015) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "cfea0d6c7e4a96627d16887c3480266a", 273132663, "data_sd.dcp", "bd51d2a1e662bd9ed3af7aa1f2180900", 91701364, - "i18n_en_strings.dcp", "33db4beabfe9813f16133c97198b7520", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "33db4beabfe9813f16133c97198b7520", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 26th 2015) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "cfea0d6c7e4a96627d16887c3480266a", 273132663, "data_sd.dcp", "bd51d2a1e662bd9ed3af7aa1f2180900", 91701364, - "i18n_it_strings.dcp", "1fefff6f0fb87abe9acf88da9af1a8e7", 127306), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "1fefff6f0fb87abe9acf88da9af1a8e7", 127306), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 26th 2015) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "cfea0d6c7e4a96627d16887c3480266a", 273132663, "data_sd.dcp", "bd51d2a1e662bd9ed3af7aa1f2180900", 91701364, - "i18n_de_strings.dcp", "30a2d7f796b3924af7e77e28f52a18b0", 60239), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "30a2d7f796b3924af7e77e28f52a18b0", 60239), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 29th 2015) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "cfea0d6c7e4a96627d16887c3480266a", 273132663, "data_sd.dcp", "bd51d2a1e662bd9ed3af7aa1f2180900", 91701364, - "i18n_de_strings.dcp", "1159db7384da56aae6953d1b943e4c57", 60737), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "1159db7384da56aae6953d1b943e4c57", 60737), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 26th 2015) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "cfea0d6c7e4a96627d16887c3480266a", 273132663, "data_sd.dcp", "bd51d2a1e662bd9ed3af7aa1f2180900", 91701364, - "i18n_fr_strings.dcp", "0ce3927e47f9ed8ca6668d0728508abb", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "0ce3927e47f9ed8ca6668d0728508abb", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 26th 2015) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "cfea0d6c7e4a96627d16887c3480266a", 273132663, "data_sd.dcp", "bd51d2a1e662bd9ed3af7aa1f2180900", 91701364, - "i18n_ru_strings.dcp", "20aebb86e857f213fd46d24fba3f6b9c", 73828), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "20aebb86e857f213fd46d24fba3f6b9c", 73828), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 26th 2015) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "cfea0d6c7e4a96627d16887c3480266a", 273132663, "data_sd.dcp", "bd51d2a1e662bd9ed3af7aa1f2180900", 91701364, - "i18n_pl_strings.dcp", "cc5e50a22672c17211008b6f710e2009", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "cc5e50a22672c17211008b6f710e2009", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 31th 2015) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "e499fac283cf68c6a85638415c4ec083", 273132663, "data_sd.dcp", "f9d1bb722eee17696c1c9266d6905924", 91701364, - "i18n_en_strings.dcp", "fe5b2bb6dd91bbac101f61f388ae8e09", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "fe5b2bb6dd91bbac101f61f388ae8e09", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 31th 2015) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "e499fac283cf68c6a85638415c4ec083", 273132663, "data_sd.dcp", "f9d1bb722eee17696c1c9266d6905924", 91701364, - "i18n_it_strings.dcp", "cf17089a0c047e7521c4da4a534b0c75", 127245), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "cf17089a0c047e7521c4da4a534b0c75", 127245), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 31th 2015) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "e499fac283cf68c6a85638415c4ec083", 273132663, "data_sd.dcp", "f9d1bb722eee17696c1c9266d6905924", 91701364, - "i18n_de_strings.dcp", "e0285a53d947e6e6925094604d011d3c", 60728), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "e0285a53d947e6e6925094604d011d3c", 60728), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 31th 2015) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "e499fac283cf68c6a85638415c4ec083", 273132663, "data_sd.dcp", "f9d1bb722eee17696c1c9266d6905924", 91701364, - "i18n_fr_strings.dcp", "9155180fb4b3a727a5ae58555e77fe0f", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "9155180fb4b3a727a5ae58555e77fe0f", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 31th 2015) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "e499fac283cf68c6a85638415c4ec083", 273132663, "data_sd.dcp", "f9d1bb722eee17696c1c9266d6905924", 91701364, - "i18n_ru_strings.dcp", "decc382f1e1c382e43f7a65f76177cc6", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "decc382f1e1c382e43f7a65f76177cc6", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 31th 2015) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "e499fac283cf68c6a85638415c4ec083", 273132663, "data_sd.dcp", "f9d1bb722eee17696c1c9266d6905924", 91701364, - "i18n_pl_strings.dcp", "70e7aac260fc6e114b9a52a163276889", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "70e7aac260fc6e114b9a52a163276889", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Nov 2015) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "8c9aa3c3d705f61c753e2f54f3104b8e", 273131920, "data_sd.dcp", "570aec5b2ceeea6e3d327b54b183d46b", 91702107, - "i18n_en_strings.dcp", "b53006a80b7c7c6c40d69ee4ac6eab0e", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "b53006a80b7c7c6c40d69ee4ac6eab0e", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Nov 2015) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "8c9aa3c3d705f61c753e2f54f3104b8e", 273131920, "data_sd.dcp", "570aec5b2ceeea6e3d327b54b183d46b", 91702107, - "i18n_it_strings.dcp", "4c84c9662e758c14a127130e20895f65", 127245), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "4c84c9662e758c14a127130e20895f65", 127245), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Nov 2015) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "8c9aa3c3d705f61c753e2f54f3104b8e", 273131920, "data_sd.dcp", "570aec5b2ceeea6e3d327b54b183d46b", 91702107, - "i18n_de_strings.dcp", "3a454226e403b32ac3b16a15711afe3f", 60728), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "3a454226e403b32ac3b16a15711afe3f", 60728), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Nov 2015) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "8c9aa3c3d705f61c753e2f54f3104b8e", 273131920, "data_sd.dcp", "570aec5b2ceeea6e3d327b54b183d46b", 91702107, - "i18n_fr_strings.dcp", "b2c65cef26a889663e7311a15796469b", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "b2c65cef26a889663e7311a15796469b", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Nov 2015) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "8c9aa3c3d705f61c753e2f54f3104b8e", 273131920, "data_sd.dcp", "570aec5b2ceeea6e3d327b54b183d46b", 91702107, - "i18n_ru_strings.dcp", "d9efa7d1d872f81d4d8602d5b4eb4f70", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "d9efa7d1d872f81d4d8602d5b4eb4f70", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Nov 2015) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "8c9aa3c3d705f61c753e2f54f3104b8e", 273131920, "data_sd.dcp", "570aec5b2ceeea6e3d327b54b183d46b", 91702107, - "i18n_pl_strings.dcp", "31da3aa3c184282290f5e418e6412eb3", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "31da3aa3c184282290f5e418e6412eb3", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Jan 2016) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "988f6f424110bf0d88b9c8066809df84", 273131920, "data_sd.dcp", "30e5c1bd6e98485886c0e8c665510897", 91702107, - "i18n_en_strings.dcp", "699872d03e5c379299d1cd75894c6ef5", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "699872d03e5c379299d1cd75894c6ef5", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Jan 2016) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "988f6f424110bf0d88b9c8066809df84", 273131920, "data_sd.dcp", "30e5c1bd6e98485886c0e8c665510897", 91702107, - "i18n_it_strings.dcp", "fd8a38801ff03401447e9507965841b2", 127245), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "fd8a38801ff03401447e9507965841b2", 127245), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Jan 2016) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "988f6f424110bf0d88b9c8066809df84", 273131920, "data_sd.dcp", "30e5c1bd6e98485886c0e8c665510897", 91702107, - "i18n_de_strings.dcp", "56057bb46e86965e2b5d5ca7823baad5", 60235), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "56057bb46e86965e2b5d5ca7823baad5", 60235), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Jan 2016) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "988f6f424110bf0d88b9c8066809df84", 273131920, "data_sd.dcp", "30e5c1bd6e98485886c0e8c665510897", 91702107, - "i18n_fr_strings.dcp", "29a3a13a8bf787c0811eba67f7c59b41", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "29a3a13a8bf787c0811eba67f7c59b41", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Jan 2016) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "988f6f424110bf0d88b9c8066809df84", 273131920, "data_sd.dcp", "30e5c1bd6e98485886c0e8c665510897", 91702107, - "i18n_ru_strings.dcp", "92ddba944cc23ad12122bf571ac6b856", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "92ddba944cc23ad12122bf571ac6b856", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Jan 2016) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "988f6f424110bf0d88b9c8066809df84", 273131920, "data_sd.dcp", "30e5c1bd6e98485886c0e8c665510897", 91702107, - "i18n_pl_strings.dcp", "a3729952b1e24d2d4367dd07a735235b", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "a3729952b1e24d2d4367dd07a735235b", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, May 2016) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "208df61df9b95c9d9d0107877eb2f4d7", 273131926, "data_sd.dcp", "ff35bbc26334a58b3b4da6d828d69ac2", 94358335, - "i18n_en_strings.dcp", "6a389c7509da41c4e15b63a7c0530243", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "6a389c7509da41c4e15b63a7c0530243", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, May 2016) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "208df61df9b95c9d9d0107877eb2f4d7", 273131926, "data_sd.dcp", "ff35bbc26334a58b3b4da6d828d69ac2", 94358335, - "i18n_it_strings.dcp", "6222689f42ea2948e3d38e537710383f", 127239), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "6222689f42ea2948e3d38e537710383f", 127239), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, May 2016) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "208df61df9b95c9d9d0107877eb2f4d7", 273131926, "data_sd.dcp", "ff35bbc26334a58b3b4da6d828d69ac2", 94358335, - "i18n_de_strings.dcp", "975928849951229f497de36e1a707b61", 60230), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "975928849951229f497de36e1a707b61", 60230), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, May 2016) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "208df61df9b95c9d9d0107877eb2f4d7", 273131926, "data_sd.dcp", "ff35bbc26334a58b3b4da6d828d69ac2", 94358335, - "i18n_es_strings.dcp", "83d88a4b2e5da2a40ac981fcfa9a95bc", 55013), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "83d88a4b2e5da2a40ac981fcfa9a95bc", 55013), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, May 2016) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "208df61df9b95c9d9d0107877eb2f4d7", 273131926, "data_sd.dcp", "ff35bbc26334a58b3b4da6d828d69ac2", 94358335, - "i18n_fr_strings.dcp", "6bfc2f1753141e28d22756d9768f4d44", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "6bfc2f1753141e28d22756d9768f4d44", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, May 2016) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "208df61df9b95c9d9d0107877eb2f4d7", 273131926, "data_sd.dcp", "ff35bbc26334a58b3b4da6d828d69ac2", 94358335, - "i18n_ru_strings.dcp", "e85982376d9fb1c21e1acc8272b49412", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "e85982376d9fb1c21e1acc8272b49412", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, May 2016) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "208df61df9b95c9d9d0107877eb2f4d7", 273131926, "data_sd.dcp", "ff35bbc26334a58b3b4da6d828d69ac2", 94358335, - "i18n_pl_strings.dcp", "5ba1e92f1fc762ecec74104f4588ba04", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "5ba1e92f1fc762ecec74104f4588ba04", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Sep 2016) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "73b14ef68eecd41afbe39c2c4f671986", 273131946, "data_sd.dcp", "f06a138b758e888f030ce659a42a6e31", 97327255, - "i18n_en_strings.dcp", "250626c49627e5f3f18883d6eb71e869", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "250626c49627e5f3f18883d6eb71e869", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Sep 2016) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "73b14ef68eecd41afbe39c2c4f671986", 273131946, "data_sd.dcp", "f06a138b758e888f030ce659a42a6e31", 97327255, - "i18n_it_strings.dcp", "338be9aa9c611e349ab7c0a4065a6c78", 127241), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "338be9aa9c611e349ab7c0a4065a6c78", 127241), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Sep 2016) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "73b14ef68eecd41afbe39c2c4f671986", 273131946, "data_sd.dcp", "f06a138b758e888f030ce659a42a6e31", 97327255, - "i18n_de_strings.dcp", "46811e68b29fd07e115343e17c53f676", 60429), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "46811e68b29fd07e115343e17c53f676", 60429), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Sep 2016) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "73b14ef68eecd41afbe39c2c4f671986", 273131946, "data_sd.dcp", "f06a138b758e888f030ce659a42a6e31", 97327255, - "i18n_es_strings.dcp", "61e518d05b62a48827ce6fa0a95e8021", 54964), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "61e518d05b62a48827ce6fa0a95e8021", 54964), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Sep 2016) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "73b14ef68eecd41afbe39c2c4f671986", 273131946, "data_sd.dcp", "f06a138b758e888f030ce659a42a6e31", 97327255, - "i18n_fr_strings.dcp", "4605094d334272dd2bc3ba3203b36c48", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "4605094d334272dd2bc3ba3203b36c48", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Sep 2016) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "73b14ef68eecd41afbe39c2c4f671986", 273131946, "data_sd.dcp", "f06a138b758e888f030ce659a42a6e31", 97327255, - "i18n_ru_strings.dcp", "8a948c77f185feac630600e3d8f55195", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "8a948c77f185feac630600e3d8f55195", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Sep 2016) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "73b14ef68eecd41afbe39c2c4f671986", 273131946, "data_sd.dcp", "f06a138b758e888f030ce659a42a6e31", 97327255, - "i18n_pl_strings.dcp", "4a07c25e2d082320880536cc2a835868", 119077), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "4a07c25e2d082320880536cc2a835868", 119077), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 2016) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "f04bc0d4fb2034adea3e7f9652b617ec", 273131946, "data_sd.dcp", "eedb6e8addffd6cd882f18b231e439a4", 97327255, - "i18n_en_strings.dcp", "db0db417d6dc8c70de625ee7520d5e40", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "db0db417d6dc8c70de625ee7520d5e40", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 2016) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "f04bc0d4fb2034adea3e7f9652b617ec", 273131946, "data_sd.dcp", "eedb6e8addffd6cd882f18b231e439a4", 97327255, - "i18n_it_strings.dcp", "809c993d42983fe8664a628804cba98e", 127241), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "809c993d42983fe8664a628804cba98e", 127241), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 2016) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "f04bc0d4fb2034adea3e7f9652b617ec", 273131946, "data_sd.dcp", "eedb6e8addffd6cd882f18b231e439a4", 97327255, - "i18n_de_strings.dcp", "e6570cb5365d6122e0ac549f83945a9f", 60429), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "e6570cb5365d6122e0ac549f83945a9f", 60429), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 2016) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "f04bc0d4fb2034adea3e7f9652b617ec", 273131946, "data_sd.dcp", "eedb6e8addffd6cd882f18b231e439a4", 97327255, - "i18n_es_strings.dcp", "c06845d464212b022c7eee21cc6502d1", 54964), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "c06845d464212b022c7eee21cc6502d1", 54964), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 2016) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "f04bc0d4fb2034adea3e7f9652b617ec", 273131946, "data_sd.dcp", "eedb6e8addffd6cd882f18b231e439a4", 97327255, - "i18n_fr_strings.dcp", "47ff2736401cde872ef454f41a5216ec", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "47ff2736401cde872ef454f41a5216ec", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 2016) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "f04bc0d4fb2034adea3e7f9652b617ec", 273131946, "data_sd.dcp", "eedb6e8addffd6cd882f18b231e439a4", 97327255, - "i18n_ru_strings.dcp", "5ffe06a72c914d287878f2f018109f04", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "5ffe06a72c914d287878f2f018109f04", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Oct 2016) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "f04bc0d4fb2034adea3e7f9652b617ec", 273131946, "data_sd.dcp", "eedb6e8addffd6cd882f18b231e439a4", 97327255, - "i18n_pl_strings.dcp", "43df37eaa12d9a60561297a199ba0e70", 119077), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "43df37eaa12d9a60561297a199ba0e70", 119077), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Jun 2018) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "0410ed71d9d6f133c703009edab38da4", 273131997, "data_sd.dcp", "e235c10ece56ac3056ebfa851726dca6", 97169915, - "i18n_en_strings.dcp", "4b6a631516bd9bd1aa20028b0c7266bd", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "4b6a631516bd9bd1aa20028b0c7266bd", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Jun 2018) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "0410ed71d9d6f133c703009edab38da4", 273131997, "data_sd.dcp", "e235c10ece56ac3056ebfa851726dca6", 97169915, - "i18n_it_strings.dcp", "ba71ea60d10a440b6604add1452994f6", 127751), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "ba71ea60d10a440b6604add1452994f6", 127751), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Jun 2018) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "0410ed71d9d6f133c703009edab38da4", 273131997, "data_sd.dcp", "e235c10ece56ac3056ebfa851726dca6", 97169915, - "i18n_de_strings.dcp", "999727c3c9bae93f06d19c71337b5d66", 60429), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "999727c3c9bae93f06d19c71337b5d66", 60429), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Jun 2018) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "0410ed71d9d6f133c703009edab38da4", 273131997, "data_sd.dcp", "e235c10ece56ac3056ebfa851726dca6", 97169915, - "i18n_es_strings.dcp", "fe5b26d90019d9601de6b3fb13daee87", 54964), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "fe5b26d90019d9601de6b3fb13daee87", 54964), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Jun 2018) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "0410ed71d9d6f133c703009edab38da4", 273131997, "data_sd.dcp", "e235c10ece56ac3056ebfa851726dca6", 97169915, - "i18n_fr_strings.dcp", "4f336e2ba1941c006dab3c9ec543db69", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "4f336e2ba1941c006dab3c9ec543db69", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Jun 2018) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "0410ed71d9d6f133c703009edab38da4", 273131997, "data_sd.dcp", "e235c10ece56ac3056ebfa851726dca6", 97169915, - "i18n_ru_strings.dcp", "f7243c0c9b1a9393fdd97b0c2496ba05", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "f7243c0c9b1a9393fdd97b0c2496ba05", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Legacy Version) (Steam, Jun 2018) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Legacy Version", WME_ENTRY3s("data.dcp", "0410ed71d9d6f133c703009edab38da4", 273131997, "data_sd.dcp", "e235c10ece56ac3056ebfa851726dca6", 97169915, - "i18n_pl_strings.dcp", "67c194c45375d2e26f8bf5ae17800944", 119354), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "67c194c45375d2e26f8bf5ae17800944", 119354), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_HD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 26th 2015) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "cfea0d6c7e4a96627d16887c3480266a", 273132663, "data_hd.dcp", "a6a3c9dd40902bf6177349f70cc5d215", 259399315, - "i18n_en_strings.dcp", "33db4beabfe9813f16133c97198b7520", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "33db4beabfe9813f16133c97198b7520", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 26th 2015) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "cfea0d6c7e4a96627d16887c3480266a", 273132663, "data_hd.dcp", "a6a3c9dd40902bf6177349f70cc5d215", 259399315, - "i18n_it_strings.dcp", "1fefff6f0fb87abe9acf88da9af1a8e7", 127306), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "1fefff6f0fb87abe9acf88da9af1a8e7", 127306), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 26th 2015) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "cfea0d6c7e4a96627d16887c3480266a", 273132663, "data_hd.dcp", "a6a3c9dd40902bf6177349f70cc5d215", 259399315, - "i18n_de_strings.dcp", "30a2d7f796b3924af7e77e28f52a18b0", 60239), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "30a2d7f796b3924af7e77e28f52a18b0", 60239), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 29th 2015) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "cfea0d6c7e4a96627d16887c3480266a", 273132663, "data_hd.dcp", "a6a3c9dd40902bf6177349f70cc5d215", 259399315, - "i18n_de_strings.dcp", "1159db7384da56aae6953d1b943e4c57", 60737), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "1159db7384da56aae6953d1b943e4c57", 60737), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 26th 2015) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "cfea0d6c7e4a96627d16887c3480266a", 273132663, "data_hd.dcp", "a6a3c9dd40902bf6177349f70cc5d215", 259399315, - "i18n_fr_strings.dcp", "0ce3927e47f9ed8ca6668d0728508abb", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "0ce3927e47f9ed8ca6668d0728508abb", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 26th 2015) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "cfea0d6c7e4a96627d16887c3480266a", 273132663, "data_hd.dcp", "a6a3c9dd40902bf6177349f70cc5d215", 259399315, - "i18n_ru_strings.dcp", "20aebb86e857f213fd46d24fba3f6b9c", 73828), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "20aebb86e857f213fd46d24fba3f6b9c", 73828), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 26th 2015) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "cfea0d6c7e4a96627d16887c3480266a", 273132663, "data_hd.dcp", "a6a3c9dd40902bf6177349f70cc5d215", 259399315, - "i18n_pl_strings.dcp", "cc5e50a22672c17211008b6f710e2009", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "cc5e50a22672c17211008b6f710e2009", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 31th 2015) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "e499fac283cf68c6a85638415c4ec083", 273132663, "data_hd.dcp", "13b45668b605dea1829ca5f276de1339", 259399315, - "i18n_en_strings.dcp", "fe5b2bb6dd91bbac101f61f388ae8e09", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "fe5b2bb6dd91bbac101f61f388ae8e09", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 31th 2015) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "e499fac283cf68c6a85638415c4ec083", 273132663, "data_hd.dcp", "13b45668b605dea1829ca5f276de1339", 259399315, - "i18n_it_strings.dcp", "cf17089a0c047e7521c4da4a534b0c75", 127245), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "cf17089a0c047e7521c4da4a534b0c75", 127245), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 31th 2015) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "e499fac283cf68c6a85638415c4ec083", 273132663, "data_hd.dcp", "13b45668b605dea1829ca5f276de1339", 259399315, - "i18n_de_strings.dcp", "e0285a53d947e6e6925094604d011d3c", 60728), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "e0285a53d947e6e6925094604d011d3c", 60728), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 31th 2015) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "e499fac283cf68c6a85638415c4ec083", 273132663, "data_hd.dcp", "13b45668b605dea1829ca5f276de1339", 259399315, - "i18n_fr_strings.dcp", "9155180fb4b3a727a5ae58555e77fe0f", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "9155180fb4b3a727a5ae58555e77fe0f", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 31th 2015) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "e499fac283cf68c6a85638415c4ec083", 273132663, "data_hd.dcp", "13b45668b605dea1829ca5f276de1339", 259399315, - "i18n_ru_strings.dcp", "decc382f1e1c382e43f7a65f76177cc6", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "decc382f1e1c382e43f7a65f76177cc6", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 31th 2015) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "e499fac283cf68c6a85638415c4ec083", 273132663, "data_hd.dcp", "13b45668b605dea1829ca5f276de1339", 259399315, - "i18n_pl_strings.dcp", "70e7aac260fc6e114b9a52a163276889", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "70e7aac260fc6e114b9a52a163276889", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Nov 2015) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "8c9aa3c3d705f61c753e2f54f3104b8e", 273131920, "data_hd.dcp", "b4d2ce0a1f5e2e342af7cbf74630300f", 259399911, - "i18n_en_strings.dcp", "b53006a80b7c7c6c40d69ee4ac6eab0e", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "b53006a80b7c7c6c40d69ee4ac6eab0e", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Nov 2015) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "8c9aa3c3d705f61c753e2f54f3104b8e", 273131920, "data_hd.dcp", "b4d2ce0a1f5e2e342af7cbf74630300f", 259399911, - "i18n_it_strings.dcp", "4c84c9662e758c14a127130e20895f65", 127245), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "4c84c9662e758c14a127130e20895f65", 127245), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Nov 2015) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "8c9aa3c3d705f61c753e2f54f3104b8e", 273131920, "data_hd.dcp", "b4d2ce0a1f5e2e342af7cbf74630300f", 259399911, - "i18n_de_strings.dcp", "3a454226e403b32ac3b16a15711afe3f", 60728), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "3a454226e403b32ac3b16a15711afe3f", 60728), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Nov 2015) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "8c9aa3c3d705f61c753e2f54f3104b8e", 273131920, "data_hd.dcp", "b4d2ce0a1f5e2e342af7cbf74630300f", 259399911, - "i18n_fr_strings.dcp", "b2c65cef26a889663e7311a15796469b", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "b2c65cef26a889663e7311a15796469b", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Nov 2015) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "8c9aa3c3d705f61c753e2f54f3104b8e", 273131920, "data_hd.dcp", "b4d2ce0a1f5e2e342af7cbf74630300f", 259399911, - "i18n_ru_strings.dcp", "d9efa7d1d872f81d4d8602d5b4eb4f70", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "d9efa7d1d872f81d4d8602d5b4eb4f70", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Nov 2015) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "8c9aa3c3d705f61c753e2f54f3104b8e", 273131920, "data_hd.dcp", "b4d2ce0a1f5e2e342af7cbf74630300f", 259399911, - "i18n_pl_strings.dcp", "31da3aa3c184282290f5e418e6412eb3", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "31da3aa3c184282290f5e418e6412eb3", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Jan 2016) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "988f6f424110bf0d88b9c8066809df84", 273131920, "data_hd.dcp", "a5670ea7c401ce187a54223bdc101408", 259399911, - "i18n_en_strings.dcp", "699872d03e5c379299d1cd75894c6ef5", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "699872d03e5c379299d1cd75894c6ef5", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Jan 2016) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "988f6f424110bf0d88b9c8066809df84", 273131920, "data_hd.dcp", "a5670ea7c401ce187a54223bdc101408", 259399911, - "i18n_it_strings.dcp", "fd8a38801ff03401447e9507965841b2", 127245), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "fd8a38801ff03401447e9507965841b2", 127245), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Jan 2016) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "988f6f424110bf0d88b9c8066809df84", 273131920, "data_hd.dcp", "a5670ea7c401ce187a54223bdc101408", 259399911, - "i18n_de_strings.dcp", "56057bb46e86965e2b5d5ca7823baad5", 60235), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "56057bb46e86965e2b5d5ca7823baad5", 60235), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Jan 2016) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "988f6f424110bf0d88b9c8066809df84", 273131920, "data_hd.dcp", "a5670ea7c401ce187a54223bdc101408", 259399911, - "i18n_fr_strings.dcp", "29a3a13a8bf787c0811eba67f7c59b41", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "29a3a13a8bf787c0811eba67f7c59b41", 59087), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Jan 2016) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "988f6f424110bf0d88b9c8066809df84", 273131920, "data_hd.dcp", "a5670ea7c401ce187a54223bdc101408", 259399911, - "i18n_ru_strings.dcp", "92ddba944cc23ad12122bf571ac6b856", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "92ddba944cc23ad12122bf571ac6b856", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Jan 2016) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "988f6f424110bf0d88b9c8066809df84", 273131920, "data_hd.dcp", "a5670ea7c401ce187a54223bdc101408", 259399911, - "i18n_pl_strings.dcp", "a3729952b1e24d2d4367dd07a735235b", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "a3729952b1e24d2d4367dd07a735235b", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, May 2016) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "208df61df9b95c9d9d0107877eb2f4d7", 273131926, "data_hd.dcp", "79a959116026a085435d1cc95bfa9570", 265023033, - "i18n_en_strings.dcp", "6a389c7509da41c4e15b63a7c0530243", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "6a389c7509da41c4e15b63a7c0530243", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, May 2016) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "208df61df9b95c9d9d0107877eb2f4d7", 273131926, "data_hd.dcp", "79a959116026a085435d1cc95bfa9570", 265023033, - "i18n_it_strings.dcp", "6222689f42ea2948e3d38e537710383f", 127239), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "6222689f42ea2948e3d38e537710383f", 127239), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, May 2016) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "208df61df9b95c9d9d0107877eb2f4d7", 273131926, "data_hd.dcp", "79a959116026a085435d1cc95bfa9570", 265023033, - "i18n_de_strings.dcp", "975928849951229f497de36e1a707b61", 60230), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "975928849951229f497de36e1a707b61", 60230), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, May 2016) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "208df61df9b95c9d9d0107877eb2f4d7", 273131926, "data_hd.dcp", "79a959116026a085435d1cc95bfa9570", 265023033, - "i18n_es_strings.dcp", "83d88a4b2e5da2a40ac981fcfa9a95bc", 55013), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "83d88a4b2e5da2a40ac981fcfa9a95bc", 55013), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, May 2016) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "208df61df9b95c9d9d0107877eb2f4d7", 273131926, "data_hd.dcp", "79a959116026a085435d1cc95bfa9570", 265023033, - "i18n_fr_strings.dcp", "6bfc2f1753141e28d22756d9768f4d44", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "6bfc2f1753141e28d22756d9768f4d44", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, May 2016) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "208df61df9b95c9d9d0107877eb2f4d7", 273131926, "data_hd.dcp", "79a959116026a085435d1cc95bfa9570", 265023033, - "i18n_ru_strings.dcp", "e85982376d9fb1c21e1acc8272b49412", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "e85982376d9fb1c21e1acc8272b49412", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, May 2016) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "208df61df9b95c9d9d0107877eb2f4d7", 273131926, "data_hd.dcp", "79a959116026a085435d1cc95bfa9570", 265023033, - "i18n_pl_strings.dcp", "5ba1e92f1fc762ecec74104f4588ba04", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "5ba1e92f1fc762ecec74104f4588ba04", 119066), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Sep 2016) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "73b14ef68eecd41afbe39c2c4f671986", 273131946, "data_hd.dcp", "d7d7fbdbf0ec41eddf92078d38be8de5", 271652871, - "i18n_en_strings.dcp", "250626c49627e5f3f18883d6eb71e869", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "250626c49627e5f3f18883d6eb71e869", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Sep 2016) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "73b14ef68eecd41afbe39c2c4f671986", 273131946, "data_hd.dcp", "d7d7fbdbf0ec41eddf92078d38be8de5", 271652871, - "i18n_it_strings.dcp", "338be9aa9c611e349ab7c0a4065a6c78", 127241), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "338be9aa9c611e349ab7c0a4065a6c78", 127241), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Sep 2016) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "73b14ef68eecd41afbe39c2c4f671986", 273131946, "data_hd.dcp", "d7d7fbdbf0ec41eddf92078d38be8de5", 271652871, - "i18n_de_strings.dcp", "46811e68b29fd07e115343e17c53f676", 60429), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "46811e68b29fd07e115343e17c53f676", 60429), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Sep 2016) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "73b14ef68eecd41afbe39c2c4f671986", 273131946, "data_hd.dcp", "d7d7fbdbf0ec41eddf92078d38be8de5", 271652871, - "i18n_es_strings.dcp", "61e518d05b62a48827ce6fa0a95e8021", 54964), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "61e518d05b62a48827ce6fa0a95e8021", 54964), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Sep 2016) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "73b14ef68eecd41afbe39c2c4f671986", 273131946, "data_hd.dcp", "d7d7fbdbf0ec41eddf92078d38be8de5", 271652871, - "i18n_fr_strings.dcp", "4605094d334272dd2bc3ba3203b36c48", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "4605094d334272dd2bc3ba3203b36c48", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Sep 2016) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "73b14ef68eecd41afbe39c2c4f671986", 273131946, "data_hd.dcp", "d7d7fbdbf0ec41eddf92078d38be8de5", 271652871, - "i18n_ru_strings.dcp", "8a948c77f185feac630600e3d8f55195", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "8a948c77f185feac630600e3d8f55195", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Sep 2016) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "73b14ef68eecd41afbe39c2c4f671986", 273131946, "data_hd.dcp", "d7d7fbdbf0ec41eddf92078d38be8de5", 271652871, - "i18n_pl_strings.dcp", "4a07c25e2d082320880536cc2a835868", 119077), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "4a07c25e2d082320880536cc2a835868", 119077), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 2016) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "f04bc0d4fb2034adea3e7f9652b617ec", 273131946, "data_hd.dcp", "5e4f57e77da13286bfa22ab157fcf147", 271652871, - "i18n_en_strings.dcp", "db0db417d6dc8c70de625ee7520d5e40", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "db0db417d6dc8c70de625ee7520d5e40", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 2016) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "f04bc0d4fb2034adea3e7f9652b617ec", 273131946, "data_hd.dcp", "5e4f57e77da13286bfa22ab157fcf147", 271652871, - "i18n_it_strings.dcp", "809c993d42983fe8664a628804cba98e", 127241), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "809c993d42983fe8664a628804cba98e", 127241), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 2016) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "f04bc0d4fb2034adea3e7f9652b617ec", 273131946, "data_hd.dcp", "5e4f57e77da13286bfa22ab157fcf147", 271652871, - "i18n_de_strings.dcp", "e6570cb5365d6122e0ac549f83945a9f", 60429), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "e6570cb5365d6122e0ac549f83945a9f", 60429), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 2016) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "f04bc0d4fb2034adea3e7f9652b617ec", 273131946, "data_hd.dcp", "5e4f57e77da13286bfa22ab157fcf147", 271652871, - "i18n_es_strings.dcp", "c06845d464212b022c7eee21cc6502d1", 54964), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "c06845d464212b022c7eee21cc6502d1", 54964), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 2016) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "f04bc0d4fb2034adea3e7f9652b617ec", 273131946, "data_hd.dcp", "5e4f57e77da13286bfa22ab157fcf147", 271652871, - "i18n_fr_strings.dcp", "47ff2736401cde872ef454f41a5216ec", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "47ff2736401cde872ef454f41a5216ec", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 2016) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "f04bc0d4fb2034adea3e7f9652b617ec", 273131946, "data_hd.dcp", "5e4f57e77da13286bfa22ab157fcf147", 271652871, - "i18n_ru_strings.dcp", "5ffe06a72c914d287878f2f018109f04", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "5ffe06a72c914d287878f2f018109f04", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Oct 2016) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "f04bc0d4fb2034adea3e7f9652b617ec", 273131946, "data_hd.dcp", "5e4f57e77da13286bfa22ab157fcf147", 271652871, - "i18n_pl_strings.dcp", "43df37eaa12d9a60561297a199ba0e70", 119077), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "43df37eaa12d9a60561297a199ba0e70", 119077), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Jun 2018) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "0410ed71d9d6f133c703009edab38da4", 273131997, "data_hd.dcp", "61b79bd9f732e48bb097227ee615463b", 272405838, - "i18n_en_strings.dcp", "4b6a631516bd9bd1aa20028b0c7266bd", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_en_strings.dcp", "4b6a631516bd9bd1aa20028b0c7266bd", 114808), Common::EN_ANY, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Jun 2018) (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "0410ed71d9d6f133c703009edab38da4", 273131997, "data_hd.dcp", "61b79bd9f732e48bb097227ee615463b", 272405838, - "i18n_it_strings.dcp", "ba71ea60d10a440b6604add1452994f6", 127751), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_it_strings.dcp", "ba71ea60d10a440b6604add1452994f6", 127751), Common::IT_ITA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Jun 2018) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "0410ed71d9d6f133c703009edab38da4", 273131997, "data_hd.dcp", "61b79bd9f732e48bb097227ee615463b", 272405838, - "i18n_de_strings.dcp", "999727c3c9bae93f06d19c71337b5d66", 60429), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_de_strings.dcp", "999727c3c9bae93f06d19c71337b5d66", 60429), Common::DE_DEU, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Jun 2018) (Spanish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "0410ed71d9d6f133c703009edab38da4", 273131997, "data_hd.dcp", "61b79bd9f732e48bb097227ee615463b", 272405838, - "i18n_es_strings.dcp", "fe5b26d90019d9601de6b3fb13daee87", 54964), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_es_strings.dcp", "fe5b26d90019d9601de6b3fb13daee87", 54964), Common::ES_ESP, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Jun 2018) (French) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "0410ed71d9d6f133c703009edab38da4", 273131997, "data_hd.dcp", "61b79bd9f732e48bb097227ee615463b", 272405838, - "i18n_fr_strings.dcp", "4f336e2ba1941c006dab3c9ec543db69", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_fr_strings.dcp", "4f336e2ba1941c006dab3c9ec543db69", 59086), Common::FR_FRA, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Jun 2018) (Russian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "0410ed71d9d6f133c703009edab38da4", 273131997, "data_hd.dcp", "61b79bd9f732e48bb097227ee615463b", 272405838, - "i18n_ru_strings.dcp", "f7243c0c9b1a9393fdd97b0c2496ba05", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_ru_strings.dcp", "f7243c0c9b1a9393fdd97b0c2496ba05", 73757), Common::RU_RUS, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // Shadows on the Vatican - Act II: Wrath (Full HD Version) (Steam, Jun 2018) (Polish) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("sotv2", "Full HD Version", WME_ENTRY3s("data.dcp", "0410ed71d9d6f133c703009edab38da4", 273131997, "data_hd.dcp", "61b79bd9f732e48bb097227ee615463b", 272405838, - "i18n_pl_strings.dcp", "67c194c45375d2e26f8bf5ae17800944", 119354), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES, WME_1_9_3), + "i18n_pl_strings.dcp", "67c194c45375d2e26f8bf5ae17800944", 119354), Common::PL_POL, ADGF_UNSTABLE | GF_IGNORE_SD_FILES | GF_3D, WME_1_9_3), // The Shine of a Star WME_WINENTRY("shinestar", "", @@ -4783,12 +4876,12 @@ static const WMEGameDescription gameDescriptions[] = { // Murder In Tehran's Alleys 1933 (Steam, June 2017) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("tehran1933", "", - WME_ENTRY1s("data.dcp", "7d74999f8a926bce367b2f851a06bc1c", 890506879), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_3), + WME_ENTRY1s("data.dcp", "7d74999f8a926bce367b2f851a06bc1c", 890506879), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // Murder In Tehran's Alleys 2016 (Steam, June 2017) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("tehran2016", "", - WME_ENTRY1s("data.dcp", "952346c4d7a08986688b3cc583215d33", 1163612836), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_3), + WME_ENTRY1s("data.dcp", "952346c4d7a08986688b3cc583215d33", 1163612836), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // The Ancient Mark - Episode 1 WME_WINENTRY("theancientmark1", "", @@ -4838,52 +4931,52 @@ static const WMEGameDescription gameDescriptions[] = { // NOTE: Same packages were reuploaded to Steam at October 2017 // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("thelastcrownmh", "", - WME_ENTRY1s("stageplay.dcp", "eaf6c27f45cbb786306bf9dce0db7f94", 920651607), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_3), + WME_ENTRY1s("stageplay.dcp", "eaf6c27f45cbb786306bf9dce0db7f94", 920651607), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // The Last Crown - Midnight Horror (Steam, Oct 2017) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("thelastcrownmh", "", - WME_ENTRY1s("stageplay.dcp", "563dd3383cb91b0f988fd9650815830f", 871649803), Common::DE_DEU, ADGF_UNSTABLE, WME_1_9_3), + WME_ENTRY1s("stageplay.dcp", "563dd3383cb91b0f988fd9650815830f", 871649803), Common::DE_DEU, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // The Lost Crown - A Ghost Hunting Adventure (2CD version) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("thelostcrowngha", "", - WME_ENTRY1s("theatre.dcp", "d0ee83038af66a6a4bb7c513e9550cbb", 77989556), Common::EN_ANY, ADGF_UNSTABLE, WME_1_8_2), + WME_ENTRY1s("theatre.dcp", "d0ee83038af66a6a4bb7c513e9550cbb", 77989556), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_8_2), // The Lost Crown - A Ghost Hunting Adventure (DVD version) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("thelostcrowngha", "", - WME_ENTRY1s("theatre.dcp", "741867f67bfb639ac0c96f6990822893", 78078952), Common::EN_ANY, ADGF_UNSTABLE, WME_1_8_2), + WME_ENTRY1s("theatre.dcp", "741867f67bfb639ac0c96f6990822893", 78078952), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_8_2), // The Lost Crown - A Ghost Hunting Adventure (DVD version) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("thelostcrowngha", "", - WME_ENTRY1s("theatre.dcp", "3deed61c6f6f02e7422b639c52b9169a", 78455706), Common::DE_DEU, ADGF_UNSTABLE, WME_1_8_2), + WME_ENTRY1s("theatre.dcp", "3deed61c6f6f02e7422b639c52b9169a", 78455706), Common::DE_DEU, ADGF_UNSTABLE | GF_3D, WME_1_8_2), // The Lost Crown - A Ghost Hunting Adventure (DVD version) (Russian/Akella) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("thelostcrowngha", "", - WME_ENTRY1s("theatre.dcp", "01ab6ced306f11e0d0c7d1dfbc7a2658", 78352318), Common::RU_RUS, ADGF_UNSTABLE, WME_1_8_2), + WME_ENTRY1s("theatre.dcp", "01ab6ced306f11e0d0c7d1dfbc7a2658", 78352318), Common::RU_RUS, ADGF_UNSTABLE | GF_3D, WME_1_8_2), // The Lost Crown - A Ghost Hunting Adventure (Italian) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("thelostcrowngha", "", - WME_ENTRY1s("theatre.dcp", "4ecf7175f1d7dd6524ff3c0e2cba0a28", 78444724), Common::IT_ITA, ADGF_UNSTABLE, WME_1_8_2), + WME_ENTRY1s("theatre.dcp", "4ecf7175f1d7dd6524ff3c0e2cba0a28", 78444724), Common::IT_ITA, ADGF_UNSTABLE | GF_3D, WME_1_8_2), // The Lost Crown - A Ghost Hunting Adventure (Steam, Jul 2014) (English) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("thelostcrowngha", "", - WME_ENTRY1s("theatre.dcp", "25e005501162a96743ae3d3d33e7bbc3", 88472760), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_3), + WME_ENTRY1s("theatre.dcp", "25e005501162a96743ae3d3d33e7bbc3", 88472760), Common::EN_ANY, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // The Lost Crown - A Ghost Hunting Adventure (Steam, Jun 2014) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("thelostcrowngha", "", - WME_ENTRY1s("theatre.dcp", "46cf3cfa4c4a1007b94c00d779bb24bd", 89163239), Common::DE_DEU, ADGF_UNSTABLE, WME_1_9_3), + WME_ENTRY1s("theatre.dcp", "46cf3cfa4c4a1007b94c00d779bb24bd", 89163239), Common::DE_DEU, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // The Lost Crown - A Ghost Hunting Adventure (Steam, Jul 2014) (German) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("thelostcrowngha", "", - WME_ENTRY1s("theatre.dcp", "21e943958e69c3f80803c649b6290140", 89163394), Common::DE_DEU, ADGF_UNSTABLE, WME_1_9_3), + WME_ENTRY1s("theatre.dcp", "21e943958e69c3f80803c649b6290140", 89163394), Common::DE_DEU, ADGF_UNSTABLE | GF_3D, WME_1_9_3), // Fairy Tales About Toshechka and Boshechka WME_WINENTRY("tib", "", @@ -4924,7 +5017,7 @@ static const WMEGameDescription gameDescriptions[] = { // WME 3D characters technology demo // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("wmedemo3d", "Demo", - WME_ENTRY1s("data.dcp", "9ca18ca52f873ca8fbc78bf408e0a68d", 3224894), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, WME_1_8_0), + WME_ENTRY1s("data.dcp", "9ca18ca52f873ca8fbc78bf408e0a68d", 3224894), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_8_0), // Wilma Tetris WME_WINENTRY("wtetris", "", @@ -4941,7 +5034,7 @@ static const WMEGameDescription gameDescriptions[] = { // Zbang! The Game (Demo) // NOTE: This is a 2.5D game that is out of ScummVM scope WME_WINENTRY("zbang", "0.89", - WME_ENTRY1s("data.dcp", "db9101f08d12ab95c81042d154bb0ea8", 7210044), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, WME_1_7_1), + WME_ENTRY1s("data.dcp", "db9101f08d12ab95c81042d154bb0ea8", 7210044), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO | GF_3D, WME_1_7_1), { AD_TABLE_END_MARKER, LATEST_VERSION diff --git a/engines/wintermute/ext/dll_dlltest.cpp b/engines/wintermute/ext/dll_dlltest.cpp new file mode 100644 index 00000000000..22dc9293fa5 --- /dev/null +++ b/engines/wintermute/ext/dll_dlltest.cpp @@ -0,0 +1,130 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/base/base_game.h" +#include "engines/wintermute/base/base_scriptable.h" +#include "engines/wintermute/base/scriptables/script.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/base/scriptables/script_stack.h" + +namespace Wintermute { + +bool EmulateDLLTestExternalCalls(BaseGame *inGame, ScStack *stack, ScStack *thisStack, ScScript::TExternalFunction *function) { + ////////////////////////////////////////////////////////////////////////// + // IRC_init + // Used to connect to debug IRC server at games by Corbomite Games + // Specification: external "dlltest.dll" cdecl long IRC_init(string) + // Known usage: IRC_init(<PlayerName>) + // Known actions: + // 1. Connect to irc.starchat.net + // 2. Send "NICK ZU_<PlayerName>/" + // 3. Send "USER Blah ZbengHost ZbengServer ZbengRealname" + // 4. Send "Join #Zbeng" + // Returns 0 on success, other value on error + ////////////////////////////////////////////////////////////////////////// + if (strcmp(function->name, "IRC_init") == 0) { + stack->correctParams(1); + /*const char *name =*/ stack->pop()->getString(); + + // do nothing + + stack->pushInt(0); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // ChangeNick + // Used to update nick at debug IRC server at games by Corbomite Games + // Specification: external "dlltest.dll" cdecl long ChangeNick(string) + // Known usage: ChangeNick(<PlayerName>) + // Return value is never used + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(function->name, "ChangeNick") == 0) { + stack->correctParams(1); + /*const char *name =*/ stack->pop()->getString(); + + // do nothing + + stack->pushInt(0); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // IRC_SendString + // Used to send debug and chat lines to an IRC server at games by Corbomite Games + // Specification: external "dlltest.dll" cdecl IRC_SendString(string, string) + // Known usage: IRC_SendString(<Message>, <Channel>) + // Known Channel values are: "#Zbeng" and "#ZbengDebug" + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(function->name, "IRC_SendString") == 0) { + stack->correctParams(2); + const char *message = stack->pop()->getString(); + const char *channel = stack->pop()->getString(); + + inGame->LOG(0, "IRC logging: [%s] %s", channel, message); + + stack->pushNULL(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // IRC_GetChatStrings + // Used to get chat lines from an IRC server at games by Corbomite Games + // Specification: external "dlltest.dll" cdecl IRC_GetChatStrings(string, long) + // Known usage: IRC_GetChatStrings(<Buffer>, 65535) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(function->name, "IRC_GetChatStrings") == 0) { + stack->correctParams(2); + /*const char *buffer =*/ stack->pop()->getString(); + /*int bufferMaxSize =*/ stack->pop()->getInt(); + + // do nothing + + stack->pushNULL(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // IRC_quit + // Used to disconnect from debug IRC server at games by Corbomite Games + // Specification: external "dlltest.dll" cdecl IRC_quit() + // Known usage: IRC_quit() + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(function->name, "IRC_quit") == 0) { + stack->correctParams(0); + + // do nothing + + stack->pushNULL(); + return STATUS_OK; + } + + return STATUS_FAILED; +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/ext/dll_geturl.cpp b/engines/wintermute/ext/dll_geturl.cpp new file mode 100644 index 00000000000..1384a37fc04 --- /dev/null +++ b/engines/wintermute/ext/dll_geturl.cpp @@ -0,0 +1,73 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/base/base_game.h" +#include "engines/wintermute/base/base_scriptable.h" +#include "engines/wintermute/base/scriptables/script.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/base/scriptables/script_stack.h" + +namespace Wintermute { + +// Implemented in their respective .cpp-files +bool EmulateGetURLExternalCalls(BaseGame *inGame, ScStack *stack, ScStack *thisStack, ScScript::TExternalFunction *function) { + ////////////////////////////////////////////////////////////////////////// + // getURLContent + // Used to download news headlines at Demo 2012 of James Peris + // HTTP GET result is stored in 3rd param of the call as a plain string + // Specification: external "geturl.dll" cdecl getURLContent(string, string, string) + // Known usage: getURLContent("http://www.lacosaweb.com", <DirURL>, <Buffer>) + // Sets 3rd param to "Request Error." on error + ////////////////////////////////////////////////////////////////////////// + if (strcmp(function->name, "getURLContent") == 0) { + stack->correctParams(3); + const char *domain = stack->pop()->getString(); + const char *dirurl = stack->pop()->getString(); + ScValue *buf = stack->pop(); + + if (strcmp(dirurl, "jpnews/demo-es1.txt") == 0) { + buf->setString("Ya disponible el juego completo en jamesperis.com"); + } else if (strcmp(dirurl, "jpnews/demo-es2.txt") == 0) { + buf->setString("Cons\355guelo por solo 3,95 euros"); + } else if (strcmp(dirurl, "jpnews/demo-en1.txt") == 0) { + buf->setString("You can get the full game in jamesperis.com"); + } else if (strcmp(dirurl, "jpnews/demo-en2.txt") == 0) { + buf->setString("Get it for 3.95 euros"); + } else { + warning("getURLContent(\"%s\",\"%s\",buf) is not implemented", domain, dirurl); + buf->setString("Request Error."); + } + + stack->pushNULL(); + return STATUS_OK; + } + + return STATUS_FAILED; +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/ext/dll_httpconnect.cpp b/engines/wintermute/ext/dll_httpconnect.cpp new file mode 100644 index 00000000000..bd3dededc6b --- /dev/null +++ b/engines/wintermute/ext/dll_httpconnect.cpp @@ -0,0 +1,164 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/base/base_game.h" +#include "engines/wintermute/base/base_scriptable.h" +#include "engines/wintermute/base/scriptables/script.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/base/scriptables/script_stack.h" + +namespace Wintermute { + +bool EmulateHTTPConnectExternalCalls(BaseGame *inGame, ScStack *stack, ScStack *thisStack, ScScript::TExternalFunction *function) { + ////////////////////////////////////////////////////////////////////////// + // Register + // Used to register license key online at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest + // Specification: external "httpconnect.dll" cdecl long Register(string, long, string, long) + // Known usage: Register(<productId>, 65535, <productKey>, 65535) + // Known product ID values are: "357868", "353058" and "353006" + // Known action: HTTP GET http://keygen.corbomitegames.com/keygen/validateKey.php?action=REGISTER&productId=productId&key=productKey + // Returns 1 on success + // Returns 0 on firewall error + // Returns -1 on invalid product key + // Returns -2 on invalid product ID + // Returns -3 on expired product key + // Returns -4 on invalid machine ID + // Returns -5 on number of installations exceeded + // Returns -6 on socket error + // Returns -7 on no internet connection + // Returns -8 on connection reset + // Returns -11 on validation temporary unavaliable + // Returns -12 on validation error + // For some reason always returns -7 for me in a test game + ////////////////////////////////////////////////////////////////////////// + if (strcmp(function->name, "Register") == 0) { + stack->correctParams(4); + const char *productId = stack->pop()->getString(); + int productIdMaxLen = stack->pop()->getInt(); + const char *productKey = stack->pop()->getString(); + int productKeyMaxLen = stack->pop()->getInt(); + + warning("Register(\"%s\",%d,\"%s\",%d) is not implemented", productId , productIdMaxLen, productKey, productKeyMaxLen); + + stack->pushInt(-7); // "no internet connection" error + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Validate + // Used to validate something at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest + // Specification: external "httpconnect.dll" cdecl long Validate() + // Known usage: Validate() + // Known action: HTTP GET http://keygen.corbomitegames.com/keygen/validateKey.php?action=VALIDATE&productId=Ar&key=Ar + // Used only when Debug mode is active or game is started with "INVALID" cmdline parameter + // For some reason always returns 1 for me in a test game + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(function->name, "Validate") == 0) { + stack->correctParams(0); + + // do nothing + + stack->pushInt(1); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SendHTTPAsync + // Used to send game progress events to server at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest + // Specification: external "httpconnect.dll" cdecl long SendHTTPAsync(string, long, string, long, string, long) + // Known usage: SendHTTPAsync("backend.pizzamorgana.com", 65535, <FullURL>, 65535, <Buffer?!>, 65535) + // FullURL is formed as "http://backend.pizzamorgana.com/event.php?Event=<EventName>&player=<PlayerName>&extraParams=<ExtraParams>&SN=<ProductKey>&Episode=1&GameTime=<CurrentTime>&UniqueID=<UniqueId>" + // Known EventName values are: "GameStart", "ChangeGoal", "EndGame" and "QuitGame" + // Known ExtraParams values are: "ACT0", "ACT1", "ACT2", "ACT3", "ACT4", "Ep0FindFood", "Ep0FindCellMenu", "Ep0BroRoom", "Ep0FindKey", "Ep0FindCellMenuKey", "Ep0FindMenuKey", "Ep0FindCell", "Ep0FindMenu", "Ep0OrderPizza", "Ep0GetRidOfVamp", "Ep0GetVampAttention", "Ep0License" + // Return value is never used + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(function->name, "SendHTTPAsync") == 0) { + stack->correctParams(6); + const char *server = stack->pop()->getString(); + int serverMaxLen = stack->pop()->getInt(); + const char *fullUrl = stack->pop()->getString(); + int fullUrlMaxLen = stack->pop()->getInt(); + const char *param5 = stack->pop()->getString(); + int param5MaxLen = stack->pop()->getInt(); + + // TODO: Maybe parse URL and call some Achievements API using ExtraParams values in some late future + warning("SendHTTPAsync(\"%s\",%d,\"%s\",%d,\"%s\",%d) is not implemented", server, serverMaxLen, fullUrl, fullUrlMaxLen, param5, param5MaxLen); + + stack->pushInt(0); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SendRecvHTTP (6 params variant) + // Declared at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest + // Seems to be unused, probably SendRecvHTTP was initially used instead of SendHTTPAsync + // Specification: external "httpconnect.dll" cdecl long SendRecvHTTP(string, long, string, long, string, long) + // Always returns -7 for me in a test game, probably returns the same network errors as Register() + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(function->name, "SendRecvHTTP") == 0 && function->nu_params == 6) { + stack->correctParams(6); + const char *server = stack->pop()->getString(); + int serverMaxLen = stack->pop()->getInt(); + const char *fullUrl = stack->pop()->getString(); + int fullUrlMaxLen = stack->pop()->getInt(); + const char *param5 = stack->pop()->getString(); + int param5MaxLen = stack->pop()->getInt(); + + warning("SendRecvHTTP(\"%s\",%d,\"%s\",%d,\"%s\",%d) is not implemented", server, serverMaxLen, fullUrl, fullUrlMaxLen, param5, param5MaxLen); + + stack->pushInt(-7); // "no internet connection" error + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SendRecvHTTP (4 params variant) + // Used to call HTTP methods at Zbang! The Game + // Specification: external "httpconnect.dll" cdecl long SendRecvHTTP(string, long, string, long) + // Known usage: SendRecvHTTP("scoresshort.php?player=<PlayerName>", 65535, <Buffer>, 65535) + // Known usage: SendRecvHTTP("/update.php?player=<PlayerName>&difficulty=<Difficulty>&items=<CommaSeparatedItemList>", 65535, <Buffer>, 65535) + // My Zbang demo does not have this dll, so there is no way to actually test it with a test game + // Return value is never used in Zbang scripts + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(function->name, "SendRecvHTTP") == 0 && function->nu_params == 4) { + stack->correctParams(4); + const char *dirUrl = stack->pop()->getString(); + int dirUrlMaxLen = stack->pop()->getInt(); + /*ScValue *buf =*/ stack->pop(); + int bufMaxLen = stack->pop()->getInt(); + + //TODO: Count items and give scores, persist those values + warning("SendRecvHTTP(\"%s\",%d,buf,%d) is not implemented", dirUrl, dirUrlMaxLen, bufMaxLen); + + stack->pushInt(0); + return STATUS_OK; + } + + return STATUS_FAILED; +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/ext/dll_img.cpp b/engines/wintermute/ext/dll_img.cpp new file mode 100644 index 00000000000..668b54d974e --- /dev/null +++ b/engines/wintermute/ext/dll_img.cpp @@ -0,0 +1,76 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/base/base_game.h" +#include "engines/wintermute/base/base_scriptable.h" +#include "engines/wintermute/base/scriptables/script.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/base/scriptables/script_stack.h" + +namespace Wintermute { + +bool EmulateImgExternalCalls(BaseGame *inGame, ScStack *stack, ScStack *thisStack, ScScript::TExternalFunction *function) { + ////////////////////////////////////////////////////////////////////////// + // changeWindowCaption + // Used to change game's window caption at games by HeroCraft + // Specification: external "img.dll" cdecl changeWindowCaption(long, string) + // Known usage: changeWindowCaption(Game.Hwnd, <Title>) + ////////////////////////////////////////////////////////////////////////// + if (strcmp(function->name, "changeWindowCaption") == 0) { + stack->correctParams(2); + /*int hwnd =*/ stack->pop()->getInt(); + /*const char *title =*/ stack->pop()->getString(); + + // do nothing + + stack->pushNULL(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // maximizedWindow + // Used to change game's window size at games by HeroCraft + // Specification: external "img.dll" cdecl maximizedWindow(long, long, long) + // Known usage: maximizedWindow(Game.Hwnd, 1024, 768) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(function->name, "maximizedWindow") == 0) { + stack->correctParams(3); + /*int hwnd =*/ stack->pop()->getInt(); + /*int width =*/ stack->pop()->getInt(); + /*int height =*/ stack->pop()->getInt(); + + // do nothing + + stack->pushNULL(); + return STATUS_OK; + } + + return STATUS_FAILED; +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/ext/dll_installutil.cpp b/engines/wintermute/ext/dll_installutil.cpp new file mode 100644 index 00000000000..8b8bf3bac55 --- /dev/null +++ b/engines/wintermute/ext/dll_installutil.cpp @@ -0,0 +1,54 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/base/base_game.h" +#include "engines/wintermute/base/base_scriptable.h" +#include "engines/wintermute/base/scriptables/script.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/base/scriptables/script_stack.h" + +namespace Wintermute { + +bool EmulateInstallUtilExternalCalls(BaseGame *inGame, ScStack *stack, ScStack *thisStack, ScScript::TExternalFunction *function) { + ////////////////////////////////////////////////////////////////////////// + // _InstallUtilAnsi@0 + // Used to check if DVD is inserted at Art of Murder: FBI Confidential + // Specification: external "installutil.dll" stdcall long _InstallUtilAnsi@0() + // Known usage: _InstallUtilAnsi@0() + // Returns 1 on success, other value on fail (which leads to Game.QuitGame() in non-Debug mode) + ////////////////////////////////////////////////////////////////////////// + if (strcmp(function->name, "_InstallUtilAnsi@0") == 0) { + stack->correctParams(0); + stack->pushInt(1); + return STATUS_OK; + } + + return STATUS_FAILED; +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/ext/dll_kernel32.cpp b/engines/wintermute/ext/dll_kernel32.cpp new file mode 100644 index 00000000000..a86941b7b50 --- /dev/null +++ b/engines/wintermute/ext/dll_kernel32.cpp @@ -0,0 +1,101 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/base/base_game.h" +#include "engines/wintermute/base/base_scriptable.h" +#include "engines/wintermute/base/scriptables/script.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/base/scriptables/script_stack.h" + +namespace Wintermute { + +bool EmulateKernel32ExternalCalls(BaseGame *inGame, ScStack *stack, ScStack *thisStack, ScScript::TExternalFunction *function) { + ////////////////////////////////////////////////////////////////////////// + // LoadLibraryA + // Used for checking library availability at games by Corbomite Games + // Specification: external "kernel32.dll" stdcall long LoadLibraryA(string) + // Known usage: LoadLibraryA("httpconnect.dll"), LoadLibraryA("dlltest.dll") + // Return values are only compared with zero and are never used in other APIs + ////////////////////////////////////////////////////////////////////////// + if (strcmp(function->name, "LoadLibraryA") == 0) { + stack->correctParams(1); + const char *dllName = stack->pop()->getString(); + int result = 0; + + if (strcmp(dllName, "httpconnect.dll") == 0) { + result = 1; // some non-zero value + } else if (strcmp(dllName, "dlltest.dll") == 0) { + result = 2; // some other non-zero value + } else { + warning("LoadLibraryA(\"%s\") is not implemented", dllName); + } + + stack->pushInt(result); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // FreeLibrary + // Declared at games by Corbomite Games + // Seems to be unused, probably was used for unloading IRC & HTTP libraries + // Specification: external "kernel32.dll" stdcall FreeLibrary(long) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(function->name, "FreeLibrary") == 0) { + stack->correctParams(1); + /*int dllId =*/ stack->pop()->getInt(); + + // do nothing + + stack->pushNULL(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetEnvironmentVariableA + // Used for getting environment variables at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest + // Specification: external "kernel32.dll" stdcall long GetEnvironmentVariableA(string, string, long) + // Known usage: GetEnvironmentVariableA(<EnvName>, <buffer>, 65535) + // Known EnvName values used in debug code: "USERKEY", "ALTUSERNAME", "ENHFINGERPRINT", "EXTRAINFO", "FINGERPRINT", "KEYSTRING", "STOLENKEY", "TRIAL" + // Known EnvName values used in licensing code: "FULLGAME" + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(function->name, "GetEnvironmentVariableA") == 0) { + stack->correctParams(3); + const char *name = stack->pop()->getString(); + /*ScValue *buf =*/ stack->pop(); + /*int bufMaxLen =*/ stack->pop()->getInt(); + + warning("Assuming variable \"%s\" is not set", name); + + stack->pushInt(0); + return STATUS_OK; + } + + return STATUS_FAILED; +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/ext/dll_shell32.cpp b/engines/wintermute/ext/dll_shell32.cpp new file mode 100644 index 00000000000..a2b081b48b4 --- /dev/null +++ b/engines/wintermute/ext/dll_shell32.cpp @@ -0,0 +1,67 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/base/base_game.h" +#include "engines/wintermute/base/base_scriptable.h" +#include "engines/wintermute/base/scriptables/script.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/base/scriptables/script_stack.h" + +namespace Wintermute { + +bool EmulateShell32ExternalCalls(BaseGame *inGame, ScStack *stack, ScStack *thisStack, ScScript::TExternalFunction *function) { + ////////////////////////////////////////////////////////////////////////// + // ShellExecuteA + // Used to open URL in browser at Wilma Tetris + // Specification: external "shell32.dll" stdcall long ShellExecuteA(long, string, string, string, string, long) + // Known usage: ShellExecuteA(0, "open", <URL>, "", "", 3) + // Returns value >32 on success + ////////////////////////////////////////////////////////////////////////// + if (strcmp(function->name, "ShellExecuteA") == 0) { + stack->correctParams(6); + int hwnd = stack->pop()->getInt(); + const char *operation = stack->pop()->getString(); + const char *file = stack->pop()->getString(); + const char *params = stack->pop()->getString(); + const char *directory = stack->pop()->getString(); + int cmd = stack->pop()->getInt(); + + if (strcmp(operation, "open") == 0 && !strlen(params) && !strlen(directory)) { + g_system->openUrl(file); + } else { + warning("ShellExecuteA(%d,\"%s\",\"%s\",\"%s\",\"%s\",%d) is not implemented", hwnd, operation, file, params, directory, cmd); + } + + stack->pushInt(42); + return STATUS_OK; + } + + return STATUS_FAILED; +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/ext/dll_tools.cpp b/engines/wintermute/ext/dll_tools.cpp new file mode 100644 index 00000000000..253e53555c8 --- /dev/null +++ b/engines/wintermute/ext/dll_tools.cpp @@ -0,0 +1,64 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/base/base_game.h" +#include "engines/wintermute/base/base_scriptable.h" +#include "engines/wintermute/base/gfx/base_renderer.h" +#include "engines/wintermute/base/scriptables/script.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/base/scriptables/script_stack.h" + +namespace Wintermute { + +bool EmulateToolsExternalCalls(BaseGame *inGame, ScStack *stack, ScStack *thisStack, ScScript::TExternalFunction *function) { + ////////////////////////////////////////////////////////////////////////// + // SetValueToReg + // Used to switch game's windowed/fullscreen mode at games by HeroCraft + // Specification: external "tools.dll" cdecl SetValueToReg(string, string, long) + // Known usage: SetValueToReg("Software\HeroCraft\<GameID>\Video", "Windowed", 1) + ////////////////////////////////////////////////////////////////////////// + if (strcmp(function->name, "SetValueToReg") == 0) { + stack->correctParams(3); + const char *regpath = stack->pop()->getString(); + const char *key = stack->pop()->getString(); + int value = stack->pop()->getInt(); + + if (strcmp(key, "Windowed") == 0) { + inGame->_renderer->setWindowed(value); + } else { + warning("SetValueToReg(\"%s\",\"%s\",%d) is not implemented", regpath, key, value); + } + + stack->pushNULL(); + return STATUS_OK; + } + + return STATUS_FAILED; +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/ext/externals.h b/engines/wintermute/ext/externals.h new file mode 100644 index 00000000000..fad8c45a2b8 --- /dev/null +++ b/engines/wintermute/ext/externals.h @@ -0,0 +1,104 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/base/base_scriptable.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/base/scriptables/script_stack.h" + +#ifndef WINTERMUTE_PLUGINS_H +#define WINTERMUTE_PLUGINS_H + +namespace Wintermute { + +// Implemented in their respective .cpp-files +bool EmulateGetURLExternalCalls(BaseGame *, ScStack *, ScStack *, ScScript::TExternalFunction *); +bool EmulateToolsExternalCalls(BaseGame *, ScStack *, ScStack *, ScScript::TExternalFunction *); +bool EmulateImgExternalCalls(BaseGame *, ScStack *, ScStack *, ScScript::TExternalFunction *); +bool EmulateShell32ExternalCalls(BaseGame *, ScStack *, ScStack *, ScScript::TExternalFunction *); +bool EmulateInstallUtilExternalCalls(BaseGame *, ScStack *, ScStack *, ScScript::TExternalFunction *); +bool EmulateDLLTestExternalCalls(BaseGame *, ScStack *, ScStack *, ScScript::TExternalFunction *); +bool EmulateKernel32ExternalCalls(BaseGame *, ScStack *, ScStack *, ScScript::TExternalFunction *); +bool EmulateHTTPConnectExternalCalls(BaseGame *, ScStack *, ScStack *, ScScript::TExternalFunction *); + +bool EmulateExternalCall(BaseGame *inGame, ScStack *stack, ScStack *thisStack, ScScript::TExternalFunction *function) { + + if (strcmp(function->dll_name, "geturl.dll") == 0) { + if (!DID_FAIL(EmulateGetURLExternalCalls(inGame, stack, thisStack, function))) { + return STATUS_OK; + } + } + + if (strcmp(function->dll_name, "tools.dll") == 0) { + if (!DID_FAIL(EmulateToolsExternalCalls(inGame, stack, thisStack, function))) { + return STATUS_OK; + } + } + + if (strcmp(function->dll_name, "img.dll") == 0) { + if (!DID_FAIL(EmulateImgExternalCalls(inGame, stack, thisStack, function))) { + return STATUS_OK; + } + } + + if (strcmp(function->dll_name, "shell32.dll") == 0) { + if (!DID_FAIL(EmulateShell32ExternalCalls(inGame, stack, thisStack, function))) { + return STATUS_OK; + } + } + + if (strcmp(function->dll_name, "installutil.dll") == 0) { + if (!DID_FAIL(EmulateInstallUtilExternalCalls(inGame, stack, thisStack, function))) { + return STATUS_OK; + } + } + + if (strcmp(function->dll_name, "dlltest.dll") == 0) { + if (!DID_FAIL(EmulateDLLTestExternalCalls(inGame, stack, thisStack, function))) { + return STATUS_OK; + } + } + + if (strcmp(function->dll_name, "kernel32.dll") == 0) { + if (!DID_FAIL(EmulateKernel32ExternalCalls(inGame, stack, thisStack, function))) { + return STATUS_OK; + } + } + + if (strcmp(function->dll_name, "httpconnect.dll") == 0) { + if (!DID_FAIL(EmulateHTTPConnectExternalCalls(inGame, stack, thisStack, function))) { + return STATUS_OK; + } + } + + warning("External function %s from %s library is not known by ScummVM", function->name, function->dll_name); + return STATUS_FAILED; +} + +} // End of namespace Wintermute + +#endif diff --git a/engines/wintermute/ext/plugins.h b/engines/wintermute/ext/plugins.h new file mode 100644 index 00000000000..4c61188fbdf --- /dev/null +++ b/engines/wintermute/ext/plugins.h @@ -0,0 +1,87 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/base/base_scriptable.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/base/scriptables/script_stack.h" + +#ifndef WINTERMUTE_PLUGINS_H +#define WINTERMUTE_PLUGINS_H + +namespace Wintermute { + +// Implemented in their respective .cpp-files +BaseScriptable *makeSXSteamAPI(BaseGame *inGame, ScStack *stack); +BaseScriptable *makeSXWMEGalaxyAPI(BaseGame *inGame, ScStack *stack); +BaseScriptable *makeSX3fStatistics(BaseGame *inGame, ScStack *stack); + +bool EmulatePluginCall(BaseGame *inGame, ScStack *stack, ScStack *thisStack, char *name) { + ScValue *thisObj; + + ////////////////////////////////////////////////////////////////////////// + // SteamAPI (from wme_steam.dll) + ////////////////////////////////////////////////////////////////////////// + if (strcmp(name, "SteamAPI") == 0) { + thisObj = thisStack->getTop(); + + thisObj->setNative(makeSXSteamAPI(inGame, stack)); + + stack->pushNULL(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // WMEGalaxyAPI (from GOG version of julia.exe) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "WMEGalaxyAPI") == 0) { + thisObj = thisStack->getTop(); + + thisObj->setNative(makeSXWMEGalaxyAPI(inGame, stack)); + + stack->pushNULL(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Statistics (from wme_3fstatistics.dll) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Statistics") == 0) { + thisObj = thisStack->getTop(); + + thisObj->setNative(makeSX3fStatistics(inGame, stack)); + + stack->pushNULL(); + return STATUS_OK; + } + + return STATUS_FAILED; +} + +} // End of namespace Wintermute + +#endif diff --git a/engines/wintermute/ext/wme_3fstatistics.cpp b/engines/wintermute/ext/wme_3fstatistics.cpp new file mode 100644 index 00000000000..bb5d8e29a8c --- /dev/null +++ b/engines/wintermute/ext/wme_3fstatistics.cpp @@ -0,0 +1,173 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/metaengine.h" +#include "engines/wintermute/wintermute.h" +#include "engines/wintermute/base/base_game.h" +#include "engines/wintermute/base/base_engine.h" +#include "engines/wintermute/base/scriptables/script_stack.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/ext/wme_3fstatistics.h" + +namespace Wintermute { + +IMPLEMENT_PERSISTENT(SX3fStatistics, false) + +BaseScriptable *makeSX3fStatistics(BaseGame *inGame, ScStack *stack) { + return new SX3fStatistics(inGame, stack); +} + +////////////////////////////////////////////////////////////////////////// +SX3fStatistics::SX3fStatistics(BaseGame *inGame, ScStack *stack) : BaseScriptable(inGame) { + stack->correctParams(4); + + ScValue * tmp; + _baseUrl = stack->pop()->getString(); + tmp = stack->pop(); + _chapter = tmp->isNULL() ? "" : tmp->getString(); + tmp = stack->pop(); + _language = tmp->isNULL() ? "" : tmp->getString(); + tmp = stack->pop(); + _buildNum = tmp->isNULL() ? "" : tmp->getString(); + + _repeat = 0; + + _gameRef->LOG(0, "new Statistics(\"%s\", \"%s\", \"%s\", \"%s\")", _baseUrl.c_str(), _chapter.c_str(), _language.c_str(), _buildNum.c_str()); +} + +////////////////////////////////////////////////////////////////////////// +SX3fStatistics::~SX3fStatistics() { +} + +////////////////////////////////////////////////////////////////////////// +const char *SX3fStatistics::scToString() { + return "[statistics object]"; +} + + +////////////////////////////////////////////////////////////////////////// +bool SX3fStatistics::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) { + ////////////////////////////////////////////////////////////////////////// + // Send() + // Known stats to send are "Start a new game" and "--Juego Finalizado--" + // Known action: send HTTP POST request to _baseUrl + // + // Headers: + // Accept: */* + // User-Agent: Mozilla/4.0 + // Content-Length: <len> + // Accept-Language: en-us + // Host: www.soluciones3f.com.ar + // + // Body: + // { + // "capitulo": "<_chapter value, e.g. '1'>", + // "dispositivo": "<OS family, e.g. 'windows'>", + // "hash": "<MD5 of MAC address, e.g. '58cb64ba781ca09f9e9cf8bd51ff0b05' for 44:8a:5b:00:00:00>", + // "idioma": "<_language value, e.g. 'ru'>", + // "idioma_os": "<OS language code, e.g. 'Russian_Russia.1251'>", + // "memoria": "<RAM size in bytes, e.g. '8504971264'>", + // "message": "<message value, e.g. 'Start a new game'>", + // "procesador": "<CPU model name, see /proc/cpuinfo for examples>", + // "resolucion": "<screen resolution, e.g. '1920x1080'>", + // "sistema": "<OS version, e.g. 'Microsoft (build 9200), 64-bit'", + // "version": "<_buildNum value, e.g. '1.3.2369'>", + // "windowed": "<screen mode windowed flag, e.g. 'yes'>" + // } + ////////////////////////////////////////////////////////////////////////// + if (strcmp(name, "Send") == 0) { + stack->correctParams(1); + const char *message = stack->pop()->getString(); + _gameRef->LOG(0, "Send(\"%s\")", message); + + // do nothing + + stack->pushNULL(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetRepeat() + // Known _repeat values are 0 and 60 + // Known action: set timer to send HTTP POST request every _repeat seconds + // HTTP POST request is the same as with Send(), message is "Tick" + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "SetRepeat") == 0) { + stack->correctParams(1); + _repeat = stack->pop()->getInt(); + + // do nothing + + stack->pushNULL(); + return STATUS_OK; + } + + else { + return STATUS_FAILED; + } +} + + +////////////////////////////////////////////////////////////////////////// +ScValue *SX3fStatistics::scGetProperty(const Common::String &name) { + _scValue->setNULL(); + + ////////////////////////////////////////////////////////////////////////// + // Type (RO) + ////////////////////////////////////////////////////////////////////////// + if (name == "Type") { + _scValue->setString("statistics"); + return _scValue; + } + + else { + return _scValue; + } +} + + +////////////////////////////////////////////////////////////////////////// +bool SX3fStatistics::scSetProperty(const char *name, ScValue *value) { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool SX3fStatistics::persist(BasePersistenceManager *persistMgr) { + BaseScriptable::persist(persistMgr); + + persistMgr->transferString(TMEMBER(_baseUrl)); + persistMgr->transferString(TMEMBER(_chapter)); + persistMgr->transferString(TMEMBER(_language)); + persistMgr->transferString(TMEMBER(_buildNum)); + persistMgr->transferSint32(TMEMBER(_repeat)); + + return STATUS_OK; +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/ext/wme_3fstatistics.h b/engines/wintermute/ext/wme_3fstatistics.h new file mode 100644 index 00000000000..b4f7e16cf4e --- /dev/null +++ b/engines/wintermute/ext/wme_3fstatistics.h @@ -0,0 +1,57 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#ifndef WINTERMUTE_SX3FSTATISTICS_H +#define WINTERMUTE_SX3FSTATISTICS_H + +#include "common/str.h" +#include "engines/wintermute/base/base_scriptable.h" + +namespace Wintermute { + +class SX3fStatistics : public BaseScriptable { +public: + DECLARE_PERSISTENT(SX3fStatistics, BaseScriptable) + ScValue *scGetProperty(const Common::String &name) override; + bool scSetProperty(const char *name, ScValue *value) override; + bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override; + const char *scToString() override; + SX3fStatistics(BaseGame *inGame, ScStack *stack); + ~SX3fStatistics() override; + +private: + Common::String _baseUrl; + Common::String _chapter; + Common::String _language; + Common::String _buildNum; + int32 _repeat; +}; + +} // End of namespace Wintermute + +#endif diff --git a/engines/wintermute/ext/wme_galaxy.cpp b/engines/wintermute/ext/wme_galaxy.cpp new file mode 100644 index 00000000000..949839a046a --- /dev/null +++ b/engines/wintermute/ext/wme_galaxy.cpp @@ -0,0 +1,151 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/metaengine.h" +#include "engines/wintermute/wintermute.h" +#include "engines/wintermute/base/base_game.h" +#include "engines/wintermute/base/base_engine.h" +#include "engines/wintermute/base/scriptables/script_stack.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/ext/wme_galaxy.h" + +namespace Wintermute { + +IMPLEMENT_PERSISTENT(SXWMEGalaxyAPI, false) + +BaseScriptable *makeSXWMEGalaxyAPI(BaseGame *inGame, ScStack *stack) { + return new SXWMEGalaxyAPI(inGame, stack); +} + +////////////////////////////////////////////////////////////////////////// +SXWMEGalaxyAPI::SXWMEGalaxyAPI(BaseGame *inGame, ScStack *stack) : BaseScriptable(inGame) { + stack->correctParams(0); + init(); +} + +////////////////////////////////////////////////////////////////////////// +void SXWMEGalaxyAPI::init() { + MetaEngine &meta = ((WintermuteEngine *)g_engine)->getMetaEngine(); + const Common::String target = BaseEngine::instance().getGameTargetName(); + _achievementsInfo = meta.getAchievementsInfo(target); + + if (!_achievementsInfo.appId.empty()) { + AchMan.setActiveDomain(Common::GALAXY_ACHIEVEMENTS, _achievementsInfo.appId); + } else { + warning("Unknown game accessing WMEGalaxyAPI. All achievements will be ignored."); + AchMan.unsetActiveDomain(); + } +} + + +////////////////////////////////////////////////////////////////////////// +SXWMEGalaxyAPI::~SXWMEGalaxyAPI() { +} + + +////////////////////////////////////////////////////////////////////////// +const char *SXWMEGalaxyAPI::scToString() { + return "[wmegalaxyapi object]"; +} + + +////////////////////////////////////////////////////////////////////////// +bool SXWMEGalaxyAPI::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) { + ////////////////////////////////////////////////////////////////////////// + // InitGalaxy() + // Initialization is already done at the constructor instead + ////////////////////////////////////////////////////////////////////////// + if (strcmp(name, "InitGalaxy") == 0) { + stack->correctParams(2); + const char *clientId = stack->pop()->getString(); + const char *clientSecret = stack->pop()->getString(); + _gameRef->LOG(0, "InitGalaxy(%s, %s)", clientId, clientSecret); + + stack->pushNULL(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // SetAchievement(string id) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "SetAchievement") == 0) { + stack->correctParams(1); + const char *id = stack->pop()->getString(); + + Common::String msg = id; + for (uint32 i = 0; i < _achievementsInfo.descriptions.size(); i++) { + if (strcmp(_achievementsInfo.descriptions[i].id, id) == 0) { + msg = _achievementsInfo.descriptions[i].title; + } + } + + stack->pushBool(AchMan.setAchievement(id, msg)); + return STATUS_OK; + } + + else { + return STATUS_FAILED; + } +} + + +////////////////////////////////////////////////////////////////////////// +ScValue *SXWMEGalaxyAPI::scGetProperty(const Common::String &name) { + _scValue->setNULL(); + + ////////////////////////////////////////////////////////////////////////// + // Type (RO) + ////////////////////////////////////////////////////////////////////////// + if (name == "Type") { + _scValue->setString("wmegalaxyapi"); + return _scValue; + } + + else { + return _scValue; + } +} + + +////////////////////////////////////////////////////////////////////////// +bool SXWMEGalaxyAPI::scSetProperty(const char *name, ScValue *value) { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool SXWMEGalaxyAPI::persist(BasePersistenceManager *persistMgr) { + BaseScriptable::persist(persistMgr); + + if (!persistMgr->getIsSaving()) { + init(); + } + + return STATUS_OK; +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/ext/wme_galaxy.h b/engines/wintermute/ext/wme_galaxy.h new file mode 100644 index 00000000000..4d898ed2258 --- /dev/null +++ b/engines/wintermute/ext/wme_galaxy.h @@ -0,0 +1,55 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#ifndef WINTERMUTE_SXWMEGALAXYAPI_H +#define WINTERMUTE_SXWMEGALAXYAPI_H + +#include "common/achievements.h" +#include "engines/wintermute/base/base_scriptable.h" + +namespace Wintermute { + +class SXWMEGalaxyAPI : public BaseScriptable { +public: + DECLARE_PERSISTENT(SXWMEGalaxyAPI, BaseScriptable) + ScValue *scGetProperty(const Common::String &name) override; + bool scSetProperty(const char *name, ScValue *value) override; + bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override; + const char *scToString() override; + SXWMEGalaxyAPI(BaseGame *inGame, ScStack *stack); + ~SXWMEGalaxyAPI() override; + +private: + void init(); + + Common::AchievementsInfo _achievementsInfo; +}; + +} // End of namespace Wintermute + +#endif diff --git a/engines/wintermute/ext/wme_steam.cpp b/engines/wintermute/ext/wme_steam.cpp new file mode 100644 index 00000000000..47812abc324 --- /dev/null +++ b/engines/wintermute/ext/wme_steam.cpp @@ -0,0 +1,258 @@ +/* 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. + * + */ + +/* + * This file is based on WME Steam Plugin. + * https://bitbucket.org/MnemonicWME/wme_steam_plugin + * Copyright (c) 2013 Jan Nedoma + */ + +#include "engines/metaengine.h" +#include "engines/wintermute/wintermute.h" +#include "engines/wintermute/base/base_game.h" +#include "engines/wintermute/base/base_engine.h" +#include "engines/wintermute/base/scriptables/script_stack.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/ext/wme_steam.h" + +namespace Wintermute { + +IMPLEMENT_PERSISTENT(SXSteamAPI, false) + +BaseScriptable *makeSXSteamAPI(BaseGame *inGame, ScStack *stack) { + return new SXSteamAPI(inGame, stack); +} + +////////////////////////////////////////////////////////////////////////// +SXSteamAPI::SXSteamAPI(BaseGame *inGame, ScStack *stack) : BaseScriptable(inGame) { + stack->correctParams(0); + init(); +} + +////////////////////////////////////////////////////////////////////////// +void SXSteamAPI::init() { + MetaEngine &meta = ((WintermuteEngine *)g_engine)->getMetaEngine(); + const Common::String target = BaseEngine::instance().getGameTargetName(); + _achievementsInfo = meta.getAchievementsInfo(target); + + if (!_achievementsInfo.appId.empty()) { + AchMan.setActiveDomain(Common::STEAM_ACHIEVEMENTS, _achievementsInfo.appId); + } else { + warning("Unknown game accessing SteamAPI. All achievements will be ignored."); + AchMan.unsetActiveDomain(); + } +} + + +////////////////////////////////////////////////////////////////////////// +SXSteamAPI::~SXSteamAPI() { +} + + +////////////////////////////////////////////////////////////////////////// +const char *SXSteamAPI::scToString() { + return "[steamapi object]"; +} + + +////////////////////////////////////////////////////////////////////////// +bool SXSteamAPI::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) { + ////////////////////////////////////////////////////////////////////////// + // RequestStats() + // There are currently no known games that are using this + // So, all the initialization should be done at the constructor instead + ////////////////////////////////////////////////////////////////////////// + if (strcmp(name, "RequestStats") == 0) { + stack->correctParams(0); + stack->pushBool(AchMan.isReady()); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // SetAchievement(string id) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "SetAchievement") == 0) { + stack->correctParams(1); + const char *id = stack->pop()->getString(); + + Common::String msg = id; + for (uint32 i = 0; i < _achievementsInfo.descriptions.size(); i++) { + if (strcmp(_achievementsInfo.descriptions[i].id, id) == 0) { + msg = _achievementsInfo.descriptions[i].title; + } + } + + stack->pushBool(AchMan.setAchievement(id, msg)); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // IsAchieved(string id) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "IsAchieved") == 0) { + stack->correctParams(1); + const char *id = stack->pop()->getString(); + stack->pushBool(AchMan.isAchieved(id)); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // ClearAchievement(string id) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "ClearAchievement") == 0) { + stack->correctParams(1); + const char *id = stack->pop()->getString(); + stack->pushBool(AchMan.clearAchievement(id)); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // GetAchievementId(int index) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "GetAchievementId") == 0) { + stack->correctParams(1); + uint32 index = (uint32) stack->pop()->getInt(); + + if (index < _achievementsInfo.descriptions.size()) { + stack->pushString(_achievementsInfo.descriptions[index].id); + } else { + stack->pushNULL(); + } + + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // SetStat(string id, int|float value) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "SetStat") == 0) { + stack->correctParams(2); + const char *id = stack->pop()->getString(); + ScValue *val = stack->pop(); + + if (val->isFloat()) { + stack->pushBool(AchMan.setStatFloat(id, val->getFloat())); + } else { + stack->pushBool(AchMan.setStatInt(id, val->getInt())); + } + + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // GetStatInt(string id) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "GetStatInt") == 0) { + stack->correctParams(1); + const char *id = stack->pop()->getString(); + stack->pushInt(AchMan.getStatInt(id)); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // GetStatFloat(string id) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "GetStatFloat") == 0) { + stack->correctParams(1); + const char *id = stack->pop()->getString(); + stack->pushFloat(AchMan.getStatFloat(id)); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // ResetAllStats(bool includingAchievements) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "ResetAllStats") == 0) { + stack->correctParams(1); + bool includingAchievements = stack->pop()->getBool(); + + bool result = AchMan.resetAllStats(); + if (includingAchievements) { + result = result && AchMan.resetAllAchievements(); + } + + stack->pushBool(result); + return STATUS_OK; + } + + else { + return STATUS_FAILED; + } +} + + +////////////////////////////////////////////////////////////////////////// +ScValue *SXSteamAPI::scGetProperty(const Common::String &name) { + _scValue->setNULL(); + + ////////////////////////////////////////////////////////////////////////// + // Type (RO) + ////////////////////////////////////////////////////////////////////////// + if (name == "Type") { + _scValue->setString("steamapi"); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // SteamAvailable (RO) + ////////////////////////////////////////////////////////////////////////// + else if (name == "SteamAvailable") { + _scValue->setBool(AchMan.isReady()); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // StatsAvailable (RO) + ////////////////////////////////////////////////////////////////////////// + else if (name == "StatsAvailable") { + _scValue->setBool(AchMan.isReady()); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // NumAchievements (RO) + ////////////////////////////////////////////////////////////////////////// + else if (name == "NumAchievements") { + _scValue->setInt(_achievementsInfo.descriptions.size()); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // AppId (RO) + ////////////////////////////////////////////////////////////////////////// + else if (name == "AppId") { + _scValue->setInt(atoi(_achievementsInfo.appId.c_str())); + return _scValue; + } + + else { + return _scValue; + } +} + + +////////////////////////////////////////////////////////////////////////// +bool SXSteamAPI::scSetProperty(const char *name, ScValue *value) { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool SXSteamAPI::persist(BasePersistenceManager *persistMgr) { + BaseScriptable::persist(persistMgr); + + if (!persistMgr->getIsSaving()) { + init(); + } + + return STATUS_OK; +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/ext/wme_steam.h b/engines/wintermute/ext/wme_steam.h new file mode 100644 index 00000000000..d09aecf406c --- /dev/null +++ b/engines/wintermute/ext/wme_steam.h @@ -0,0 +1,55 @@ +/* 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#ifndef WINTERMUTE_SXSTEAMAPI_H +#define WINTERMUTE_SXSTEAMAPI_H + +#include "common/achievements.h" +#include "engines/wintermute/base/base_scriptable.h" + +namespace Wintermute { + +class SXSteamAPI : public BaseScriptable { +public: + DECLARE_PERSISTENT(SXSteamAPI, BaseScriptable) + ScValue *scGetProperty(const Common::String &name) override; + bool scSetProperty(const char *name, ScValue *value) override; + bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override; + const char *scToString() override; + SXSteamAPI(BaseGame *inGame, ScStack *stack); + ~SXSteamAPI() override; + +private: + void init(); + + Common::AchievementsInfo _achievementsInfo; +}; + +} // End of namespace Wintermute + +#endif diff --git a/engines/wintermute/keymapper_tables.h b/engines/wintermute/keymapper_tables.h index 66154104cca..258195cf2fc 100644 --- a/engines/wintermute/keymapper_tables.h +++ b/engines/wintermute/keymapper_tables.h @@ -24,6 +24,8 @@ #include "backends/keymapper/keymapper.h" #include "backends/keymapper/standard-actions.h" +#include "engines/wintermute/base/base_game_custom_actions.h" + #include "common/translation.h" namespace Wintermute { @@ -64,11 +66,11 @@ inline Common::KeymapArray getWintermuteKeymaps(const char *target, const Common if (gameId == "actualdest" || gameId == "artofmurder1" || + gameId == "alavi" || gameId == "agustin" || gameId == "bickadoodle" || gameId == "bthreshold" || gameId == "colorsoncanvas" || - gameId == "corrosion" || gameId == "deadcity" || gameId == "darkfallls" || gameId == "drbohus" || @@ -518,6 +520,34 @@ inline Common::KeymapArray getWintermuteKeymaps(const char *target, const Common act->addDefaultInputMapping("DOWN"); // extra keyboard act->addDefaultInputMapping("JOY_DOWN"); // extra joy gameKeyMap->addAction(act); + } else if (gameId == "corrosion") { + act = new Action(kStandardActionMoveUp, _("Walk forward")); + act->setCustomEngineActionEvent(kClickAtCenter); + act->addDefaultInputMapping("UP"); // extra keyboard + act->addDefaultInputMapping("KP8"); // extra keyboard + act->addDefaultInputMapping("JOY_UP"); // extra joy + gameKeyMap->addAction(act); + + act = new Action(kStandardActionMoveDown, _("Walk backward")); + act->setCustomEngineActionEvent(kClickAtBottom); + act->addDefaultInputMapping("DOWN"); // extra keyboard + act->addDefaultInputMapping("KP2"); // extra keyboard + act->addDefaultInputMapping("JOY_DOWN"); // extra joy + gameKeyMap->addAction(act); + + act = new Action(kStandardActionMoveLeft, _("Turn left")); + act->setCustomEngineActionEvent(kClickAtLeft); + act->addDefaultInputMapping("LEFT"); // extra keyboard + act->addDefaultInputMapping("KP4"); // extra keyboard + act->addDefaultInputMapping("JOY_LEFT"); // extra joy + gameKeyMap->addAction(act); + + act = new Action(kStandardActionMoveRight, _("Turn right")); + act->setCustomEngineActionEvent(kClickAtRight); + act->addDefaultInputMapping("RIGHT"); // extra keyboard + act->addDefaultInputMapping("KP6"); // extra keyboard + act->addDefaultInputMapping("JOY_RIGHT"); // extra joy + gameKeyMap->addAction(act); } else if (gameId == "erinmyers") { act = new Action("GUIB", _("Change font size")); act->setKeyEvent(KEYCODE_END); @@ -669,6 +699,58 @@ inline Common::KeymapArray getWintermuteKeymaps(const char *target, const Common //TODO: extra joy control, e.g. "JOY_R+JOY_B" gameKeyMap->addAction(act); } + + if (extra.hasPrefix("1.2.896.")) { + act = new Action("CREDIT", _("Show game credits")); + act->setKeyEvent(KEYCODE_F1); + act->addDefaultInputMapping("F1"); // original keyboard + gameKeyMap->addAction(act); + + act = new Action("MPLAY", _("Play selected music record")); + act->setKeyEvent(KEYCODE_F4); + act->addDefaultInputMapping("F4"); // original keyboard + gameKeyMap->addAction(act); + + act = new Action("MNEXT", _("Select next music record")); + act->setKeyEvent(KeyState(KEYCODE_TAB, ASCII_TAB)); + act->addDefaultInputMapping("TAB"); // original keyboard + gameKeyMap->addAction(act); + + act = new Action("NOTE1", _("Play note 1: A")); + act->setKeyEvent(KeyState(KEYCODE_d, 'd')); + act->addDefaultInputMapping("d"); // original keyboard + gameKeyMap->addAction(act); + + act = new Action("NOTE2", _("Play note 2: F#")); + act->setKeyEvent(KeyState(KEYCODE_f, 'f')); + act->addDefaultInputMapping("f"); // original keyboard + gameKeyMap->addAction(act); + + act = new Action("NOTE3", _("Play note 3: D#")); + act->setKeyEvent(KeyState(KEYCODE_g, 'g')); + act->addDefaultInputMapping("g"); // original keyboard + gameKeyMap->addAction(act); + + act = new Action("NOTE4", _("Play note 4: C#")); + act->setKeyEvent(KeyState(KEYCODE_h, 'h')); + act->addDefaultInputMapping("h"); // original keyboard + gameKeyMap->addAction(act); + + act = new Action("NOTE5", _("Play note 5: E")); + act->setKeyEvent(KeyState(KEYCODE_j, 'j')); + act->addDefaultInputMapping("j"); // original keyboard + gameKeyMap->addAction(act); + + act = new Action("NOTE6", _("Play note 6: G#")); + act->setKeyEvent(KeyState(KEYCODE_k, 'k')); + act->addDefaultInputMapping("k"); // original keyboard + gameKeyMap->addAction(act); + + act = new Action("NOTE7", _("Play note 7: B")); + act->setKeyEvent(KeyState(KEYCODE_l, 'l')); + act->addDefaultInputMapping("l"); // original keyboard + gameKeyMap->addAction(act); + } } else if (gameId == "ghostsheet") { act = new Action("HINT", _("Show hints")); act->setKeyEvent(KeyState(KEYCODE_TAB, ASCII_TAB)); diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk index f9ee1a748fa..63e25433343 100644 --- a/engines/wintermute/module.mk +++ b/engines/wintermute/module.mk @@ -126,6 +126,17 @@ MODULE_OBJS := \ base/saveload.o \ base/save_thumb_helper.o \ base/timer.o \ + ext/dll_dlltest.o \ + ext/dll_geturl.o \ + ext/dll_httpconnect.o \ + ext/dll_img.o \ + ext/dll_installutil.o \ + ext/dll_kernel32.o \ + ext/dll_shell32.o \ + ext/dll_tools.o \ + ext/wme_3fstatistics.o \ + ext/wme_galaxy.o \ + ext/wme_steam.o \ debugger/breakpoint.o \ debugger/debugger_controller.o \ debugger/error.o \ diff --git a/engines/wintermute/persistent.cpp b/engines/wintermute/persistent.cpp index 23356ace9b7..00e8184397d 100644 --- a/engines/wintermute/persistent.cpp +++ b/engines/wintermute/persistent.cpp @@ -81,8 +81,9 @@ #include "engines/wintermute/base/scriptables/script_ext_mem_buffer.h" #include "engines/wintermute/base/scriptables/script_ext_object.h" #include "engines/wintermute/base/scriptables/script_ext_string.h" -#include "engines/wintermute/base/scriptables/script_ext_steam_api.h" -#include "engines/wintermute/base/scriptables/script_ext_wme_galaxy_api.h" +#include "engines/wintermute/ext/wme_3fstatistics.h" +#include "engines/wintermute/ext/wme_steam.h" +#include "engines/wintermute/ext/wme_galaxy.h" #include "engines/wintermute/ui/ui_button.h" #include "engines/wintermute/ui/ui_edit.h" #include "engines/wintermute/ui/ui_entity.h" @@ -158,6 +159,8 @@ void SystemClassRegistry::registerClasses() { REGISTER_CLASS(SXMemBuffer, false) REGISTER_CLASS(SXObject, false) REGISTER_CLASS(SXString, false) + + REGISTER_CLASS(SX3fStatistics, false) REGISTER_CLASS(SXSteamAPI, false) REGISTER_CLASS(SXWMEGalaxyAPI, false) diff --git a/engines/wintermute/platform_osystem.cpp b/engines/wintermute/platform_osystem.cpp index 08055347534..2641a080a04 100644 --- a/engines/wintermute/platform_osystem.cpp +++ b/engines/wintermute/platform_osystem.cpp @@ -109,13 +109,23 @@ void BasePlatform::handleEvent(Common::Event *event) { _gameRef->handleMouseWheel(event->type == Common::EVENT_WHEELUP ? 1 : -1); } break; + case Common::EVENT_CUSTOM_ENGINE_ACTION_START: + if (_gameRef) { + _gameRef->handleCustomActionStart((BaseGameCustomAction)event->customType); + } + break; + case Common::EVENT_CUSTOM_ENGINE_ACTION_END: + if (_gameRef) { + _gameRef->handleCustomActionEnd((BaseGameCustomAction)event->customType); + } + break; case Common::EVENT_SCREEN_CHANGED: if (_gameRef) { _gameRef->_renderer->onWindowChange(); } break; // Focus-events have been removed (_gameRef->onActivate originally) - case Common::EVENT_RTL: + case Common::EVENT_RETURN_TO_LAUNCHER: _gameRef->_quitting = true; break; case Common::EVENT_QUIT: diff --git a/engines/wintermute/ui/ui_button.cpp b/engines/wintermute/ui/ui_button.cpp index 2e41e1432ee..eb8137ce3e6 100644 --- a/engines/wintermute/ui/ui_button.cpp +++ b/engines/wintermute/ui/ui_button.cpp @@ -625,11 +625,11 @@ void UIButton::correctSize() { } if (_text) { - int textHeight; - if (_font) { - textHeight = _font->getTextHeight((byte *)_text, _width); - } else { - textHeight = _gameRef->getSystemFont()->getTextHeight((byte *)_text, _width); + int textHeight = 0; + BaseFont *font = _font ? _font : _gameRef->getSystemFont(); + + if (font) { + textHeight = font->getTextHeight((byte *)_text, _width); } if (textHeight > _height) { @@ -872,6 +872,21 @@ bool UIButton::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack return STATUS_OK; } +#ifdef ENABLE_FOXTAIL + ////////////////////////////////////////////////////////////////////////// + // [FoxTail] HeightToFit + // Used to autofit widget's height to it's content + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "HeightToFit") == 0) { + stack->correctParams(0); + + correctSize(); + + stack->pushNULL(); + return STATUS_OK; + } +#endif + ////////////////////////////////////////////////////////////////////////// // SetDisabledImage ////////////////////////////////////////////////////////////////////////// diff --git a/engines/wintermute/utils/string_util.cpp b/engines/wintermute/utils/string_util.cpp index b17c5446b75..ad1313a20f5 100644 --- a/engines/wintermute/utils/string_util.cpp +++ b/engines/wintermute/utils/string_util.cpp @@ -118,6 +118,9 @@ Common::CodePage StringUtil::mapCodePage(TTextCharset charset) { case CHARSET_HEBREW: return Common::kWindows1255; + case CHARSET_ARABIC: + return Common::kWindows1256; + case CHARSET_BALTIC: return Common::kWindows1257; @@ -167,6 +170,10 @@ Common::CodePage StringUtil::mapCodePage(TTextCharset charset) { case Common::HE_ISR: return Common::kWindows1255; + //cp1256: Arabic + case Common::FA_IRN: + return Common::kWindows1256; + //cp1257: Baltic case Common::ET_EST: case Common::LV_LAT: @@ -190,7 +197,6 @@ Common::CodePage StringUtil::mapCodePage(TTextCharset charset) { case CHARSET_SYMBOL: case CHARSET_VIETNAMESE: case CHARSET_JOHAB: - case CHARSET_ARABIC: case CHARSET_THAI: default: warning("Unsupported charset: %d", charset); diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp index ae4d03dac87..b3a525fafb6 100644 --- a/engines/wintermute/wintermute.cpp +++ b/engines/wintermute/wintermute.cpp @@ -96,7 +96,7 @@ WintermuteEngine::~WintermuteEngine() { bool WintermuteEngine::hasFeature(EngineFeature f) const { switch (f) { - case kSupportsRTL: + case kSupportsReturnToLauncher: return true; case kSupportsLoadingDuringRuntime: return true; @@ -157,10 +157,20 @@ Common::Error WintermuteEngine::run() { int WintermuteEngine::init() { BaseEngine::createInstance(_targetName, _gameDescription->adDesc.gameId, _gameDescription->adDesc.language, _gameDescription->targetExecutable, _gameDescription->adDesc.flags); + BaseEngine &instance = BaseEngine::instance(); + + // check if unknown target is a 2.5D game + if (instance.getFlags() & ADGF_AUTOGENTARGET) { + Common::ArchiveMemberList actors3d; + if (instance.getFileManager()->listMatchingPackageMembers(actors3d, "*.act3d")) { + warning("Unknown 2.5D game detected"); + instance.addFlags(GF_3D); + } + } // check dependencies for games with high resolution assets - #if not defined(USE_PNG) || not defined(USE_JPEG) || not defined(USE_VORBIS) - if (!(_gameDescription->adDesc.flags & GF_LOWSPEC_ASSETS)) { + #if !defined(USE_PNG) || !defined(USE_JPEG) || !defined(USE_VORBIS) + if (!(instance.getFlags() & GF_LOWSPEC_ASSETS)) { GUI::MessageDialog dialog(_("This game requires PNG, JPEG and Vorbis support.")); dialog.runModal(); delete _game; @@ -170,8 +180,8 @@ int WintermuteEngine::init() { #endif // check dependencies for games with FoxTail subengine - #if not defined(ENABLE_FOXTAIL) - if (BaseEngine::isFoxTailCheck(_gameDescription->targetExecutable)) { + #if !defined(ENABLE_FOXTAIL) + if (BaseEngine::isFoxTailCheck(instance.getTargetExecutable())) { GUI::MessageDialog dialog(_("This game requires the FoxTail subengine, which is not compiled in.")); dialog.runModal(); delete _game; @@ -181,8 +191,8 @@ int WintermuteEngine::init() { #endif // check dependencies for games with HeroCraft subengine - #if not defined(ENABLE_HEROCRAFT) - if (_gameDescription->targetExecutable == WME_HEROCRAFT) { + #if !defined(ENABLE_HEROCRAFT) + if (instance.getTargetExecutable() == WME_HEROCRAFT) { GUI::MessageDialog dialog(_("This game requires the HeroCraft subengine, which is not compiled in.")); dialog.runModal(); delete _game; @@ -192,13 +202,10 @@ int WintermuteEngine::init() { #endif #ifndef ENABLE_WME3D - Common::ArchiveMemberList actors3d; - if (BaseEngine::instance().getFileManager()->listMatchingMembers(actors3d, "*.act3d")) { - GUI::MessageDialog dialog( - _("This game requires 3D characters support, which is out of ScummVM's scope."), - _("Start anyway"), - _("Cancel") - ); + // check if game require 3D capabilities + if (instance.getFlags() & GF_3D) { + GUI::MessageDialog dialog(_("This game requires 3D capabilities that are out ScummVM scope. As such, it" + " is likely to be unplayable totally or partially."), _("Start anyway"), _("Cancel")); if (dialog.runModal() != GUI::kMessageOK) { delete _game; _game = nullptr; @@ -214,10 +221,9 @@ int WintermuteEngine::init() { #ifdef ENABLE_WME3D Common::ArchiveMemberList actors3d; - _game->_playing3DGame = BaseEngine::instance().getFileManager()->listMatchingMembers(actors3d, "*.act3d"); + _game->_playing3DGame = BaseEngine::instance().getFileManager()->listMatchingPackageMembers(actors3d, "*.act3d"); #endif - - BaseEngine::instance().setGameRef(_game); + instance.setGameRef(_game); BasePlatform::initialize(this, _game, 0, nullptr); _game->initConfManSettings(); diff --git a/engines/wintermute/wintermute.h b/engines/wintermute/wintermute.h index fcadb1bba86..21befc2f34d 100644 --- a/engines/wintermute/wintermute.h +++ b/engines/wintermute/wintermute.h @@ -51,7 +51,8 @@ enum WintermuteGameFeatures { /** A game with low-spec resources. */ GF_LOWSPEC_ASSETS = 1 << 0, GF_IGNORE_SD_FILES = 1 << 1, - GF_IGNORE_HD_FILES = 1 << 2 + GF_IGNORE_HD_FILES = 1 << 2, + GF_3D = 1 << 3 }; class WintermuteEngine : public Engine { diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp index cec3980ed41..e44ccd63286 100644 --- a/graphics/VectorRendererSpec.cpp +++ b/graphics/VectorRendererSpec.cpp @@ -27,7 +27,6 @@ #include "graphics/surface.h" #include "graphics/transparent_surface.h" #include "graphics/nine_patch.h" -#include "graphics/colormasks.h" #include "gui/ThemeEngine.h" #include "graphics/VectorRenderer.h" @@ -1062,8 +1061,17 @@ drawString(const Graphics::Font *font, const Common::String &text, const Common: drawArea = drawArea.findIntersectingRect(Common::Rect(0, 0, _activeSurface->w, _activeSurface->h)); if (!drawArea.isEmpty()) { + Common::Rect textArea(area); + textArea.right -= deltax; + Surface textAreaSurface = _activeSurface->getSubArea(drawArea); - font->drawString(&textAreaSurface, text, area.left - drawArea.left, offset - drawArea.top, area.width() - deltax, _fgColor, alignH, deltax, ellipsis); + + if (deltax >= 0) { + textArea.left += deltax; + deltax = 0; + } + + font->drawString(&textAreaSurface, text, textArea.left - drawArea.left, offset - drawArea.top, textArea.width(), _fgColor, alignH, deltax, ellipsis); } } diff --git a/graphics/font.cpp b/graphics/font.cpp index 3bcfad22c3a..32eefc3c3a7 100644 --- a/graphics/font.cpp +++ b/graphics/font.cpp @@ -43,7 +43,7 @@ Common::Rect getBoundingBoxImpl(const Font &font, const StringType &str, int x, // We follow the logic of drawStringImpl here. The only exception is // that we do allow an empty width to be specified here. This allows us // to obtain the complete bounding box of a string. - const int leftX = x, rightX = w ? (x + w) : 0x7FFFFFFF; + const int leftX = x, rightX = w ? (x + w + 1) : 0x7FFFFFFF; int width = font.getStringWidth(str); if (align == kTextAlignCenter) @@ -100,7 +100,7 @@ void drawStringImpl(const Font &font, Surface *dst, const StringType &str, int x // ever change something here we will need to change it there too. assert(dst != 0); - const int leftX = x, rightX = x + w; + const int leftX = x, rightX = x + w + 1; int width = font.getStringWidth(str); if (align == kTextAlignCenter) @@ -466,4 +466,15 @@ Common::String Font::handleEllipsis(const Common::String &input, int w) const { } } +TextAlign convertTextAlignH(TextAlign alignH, bool rtl) { + switch (alignH) { + case kTextAlignStart: + return rtl ? kTextAlignRight : kTextAlignLeft; + case kTextAlignEnd: + return rtl ? kTextAlignLeft : kTextAlignRight; + default: + return alignH; + } +} + } // End of namespace Graphics diff --git a/graphics/font.h b/graphics/font.h index d9f81cca8ca..487f11b8ca9 100644 --- a/graphics/font.h +++ b/graphics/font.h @@ -39,11 +39,20 @@ class ManagedSurface; /** Text alignment modes */ enum TextAlign { kTextAlignInvalid, + kTextAlignStart, ///< Text should be aligned to start of line (virtual) kTextAlignLeft, ///< Text should be aligned to the left kTextAlignCenter, ///< Text should be centered + kTextAlignEnd, ///< Text should be aligned to end of line (virtual) kTextAlignRight ///< Text should be aligned to the right }; +/** + * Converts virtual text alignments (start + end) + * to actual text alignment (left + right + center) for drawing, + * if given actual text alignments it is returned as-is + */ +TextAlign convertTextAlignH(TextAlign alignH, bool rtl); + /** * Instances of this class represent a distinct font, with a built-in renderer. * @todo Maybe move the high-level methods (drawString etc.) to a separate @@ -119,7 +128,7 @@ public: * @return The actual area where the string is drawn. */ Common::Rect getBoundingBox(const Common::String &str, int x = 0, int y = 0, const int w = 0, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const; - Common::Rect getBoundingBox(const Common::U32String &str, int x = 0, int y = 0, const int w = 0, TextAlign align = kTextAlignLeft) const; + Common::Rect getBoundingBox(const Common::U32String &str, int x = 0, int _y = 0, const int w = 0, TextAlign align = kTextAlignLeft) const; /** * Draw a character at a specific point on a surface. @@ -147,7 +156,7 @@ public: // TODO: Add doxygen comments to this void drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const; void drawString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0) const; - void drawString(ManagedSurface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const; + void drawString(ManagedSurface *dst, const Common::String &str, int x, int _y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const; void drawString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0) const; /** diff --git a/graphics/primitives.cpp b/graphics/primitives.cpp index ba898ede156..558fe27f066 100644 --- a/graphics/primitives.cpp +++ b/graphics/primitives.cpp @@ -290,7 +290,7 @@ void drawRoundRect(Common::Rect &rect, int arc, int color, bool filled, void (*p drawHLine(rect.left + x + r, rect.right - x - r, rect.bottom + y - r + stop, color, plotProc, data); } - for (int i = 0; i < dy; i++) { + for (int i = 1; i < dy; i++) { if (filled) { drawHLine(rect.left, rect.right, rect.top + r + i, color, plotProc, data); } else { @@ -335,7 +335,7 @@ void drawRoundRect(Common::Rect &rect, int arc, int color, bool filled, void (*p drawVLine(rect.right + x - r + stop, rect.top + y + r, rect.bottom - y - r, color, plotProc, data); } - for (int i = 0; i < dx; i++) { + for (int i = 1; i < dx; i++) { if (filled) { drawVLine(rect.left + r + i, rect.top, rect.bottom, color, plotProc, data); } else { diff --git a/graphics/transparent_surface.h b/graphics/transparent_surface.h index 8f4493679b9..8bfddef8c1a 100644 --- a/graphics/transparent_surface.h +++ b/graphics/transparent_surface.h @@ -36,11 +36,11 @@ */ #ifdef SCUMM_LITTLE_ENDIAN -#define TS_RGB(R,G,B) ((0xff << 24) | ((R) << 16) | ((G) << 8) | (B)) -#define TS_ARGB(A,R,G,B) (((R) << 24) | ((G) << 16) | ((B) << 8) | (A)) +#define TS_RGB(R,G,B) (uint32)((0xff << 24) | ((R) << 16) | ((G) << 8) | (B)) +#define TS_ARGB(A,R,G,B) (uint32)(((R) << 24) | ((G) << 16) | ((B) << 8) | (A)) #else -#define TS_RGB(R,G,B) (((R) << 24) | ((G) << 16) | (B << 8) | 0xff) -#define TS_ARGB(A,R,G,B) (((R) << 24) | ((G) << 16) | ((B) << 8) | (A)) +#define TS_RGB(R,G,B) (uint32)(((R) << 24) | ((G) << 16) | (B << 8) | 0xff) +#define TS_ARGB(A,R,G,B) (uint32)(((R) << 24) | ((G) << 16) | ((B) << 8) | (A)) #endif namespace Graphics { diff --git a/gui/EventRecorder.cpp b/gui/EventRecorder.cpp index e5b1cb4701c..492b7bc9f4a 100644 --- a/gui/EventRecorder.cpp +++ b/gui/EventRecorder.cpp @@ -151,7 +151,7 @@ void EventRecorder::processMillis(uint32 &millis, bool skipRecord) { _nextEvent = _playbackFile->getNextEvent(); _timerManager->handler(); } else { - if (_nextEvent.type == Common::EVENT_RTL) { + if (_nextEvent.type == Common::EVENT_RETURN_TO_LAUNCHER) { error("playback:action=stopplayback"); } else { uint32 seconds = _fakeTimer / 1000; @@ -641,9 +641,9 @@ bool EventRecorder::switchMode() { saveName = Common::String::format("Save %d", emptySlot + 1); Common::Error status = g_engine->saveGameState(emptySlot, saveName); if (status.getCode() == Common::kNoError) { - Common::Event eventRTL; - eventRTL.type = Common::EVENT_RTL; - g_system->getEventManager()->pushEvent(eventRTL); + Common::Event eventReturnToLauncher; + eventReturnToLauncher.type = Common::EVENT_RETURN_TO_LAUNCHER; + g_system->getEventManager()->pushEvent(eventReturnToLauncher); } } ConfMan.set("record_mode", "", Common::ConfigManager::kTransientDomain); diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp index 4190cc14c15..cb48ce3d4a5 100644 --- a/gui/ThemeEngine.cpp +++ b/gui/ThemeEngine.cpp @@ -137,6 +137,13 @@ static const DrawDataInfo kDrawDataDefaults[] = { {kDDDropDownButtonPressedLeft, "dropdown_button_pressed_left", kDrawLayerForeground, kDDDropDownButtonIdle}, {kDDDropDownButtonPressedRight, "dropdown_button_pressed_right", kDrawLayerForeground, kDDDropDownButtonIdle}, + {kDDDropDownButtonIdleRTL, "dropdown_button_idle_rtl", kDrawLayerBackground, kDDNone}, + {kDDDropDownButtonHoverLeftRTL, "dropdown_button_hover_left_rtl", kDrawLayerForeground, kDDDropDownButtonIdleRTL}, + {kDDDropDownButtonHoverRightRTL, "dropdown_button_hover_right_rtl", kDrawLayerForeground, kDDDropDownButtonIdleRTL}, + {kDDDropDownButtonDisabledRTL, "dropdown_button_disabled_rtl", kDrawLayerForeground, kDDNone}, + {kDDDropDownButtonPressedLeftRTL, "dropdown_button_pressed_left_rtl", kDrawLayerForeground, kDDDropDownButtonIdleRTL}, + {kDDDropDownButtonPressedRightRTL, "dropdown_button_pressed_right_rtl", kDrawLayerForeground, kDDDropDownButtonIdleRTL}, + {kDDSliderFull, "slider_full", kDrawLayerForeground, kDDNone}, {kDDSliderHover, "slider_hover", kDrawLayerForeground, kDDNone}, {kDDSliderDisabled, "slider_disabled", kDrawLayerForeground, kDDNone}, @@ -166,6 +173,10 @@ static const DrawDataInfo kDrawDataDefaults[] = { {kDDPopUpHover, "popup_hover", kDrawLayerForeground, kDDPopUpIdle}, {kDDPopUpDisabled, "popup_disabled", kDrawLayerBackground, kDDNone}, + {kDDPopUpIdleRTL, "popup_idle_rtl", kDrawLayerBackground, kDDNone}, + {kDDPopUpHoverRTL, "popup_hover_rtl", kDrawLayerForeground, kDDPopUpIdleRTL}, + {kDDPopUpDisabledRTL, "popup_disabled_rtl", kDrawLayerBackground, kDDNone}, + {kDDCaret, "caret", kDrawLayerForeground, kDDNone}, {kDDSeparator, "separator", kDrawLayerBackground, kDDNone}, }; @@ -948,28 +959,29 @@ void ThemeEngine::drawButton(const Common::Rect &r, const Common::String &str, W dd = kDDButtonPressed; drawDD(dd, r, 0, hints & WIDGET_CLEARBG); - drawDDText(getTextData(dd), getTextColor(dd), r, str, false, true, _widgets[dd]->_textAlignH, + drawDDText(getTextData(dd), getTextColor(dd), r, str, false, true, convertTextAlignH(_widgets[dd]->_textAlignH, false), _widgets[dd]->_textAlignV); } void ThemeEngine::drawDropDownButton(const Common::Rect &r, uint32 dropdownWidth, const Common::String &str, - ThemeEngine::WidgetStateInfo buttonState, bool inButton, bool inDropdown) { + ThemeEngine::WidgetStateInfo buttonState, bool inButton, bool inDropdown, bool rtl) { if (!ready()) return; DrawData dd; + if (buttonState == kStateHighlight && inButton) - dd = kDDDropDownButtonHoverLeft; + dd = rtl ? kDDDropDownButtonHoverLeftRTL : kDDDropDownButtonHoverLeft; else if (buttonState == kStateHighlight && inDropdown) - dd = kDDDropDownButtonHoverRight; + dd = rtl ? kDDDropDownButtonHoverRightRTL : kDDDropDownButtonHoverRight; else if (buttonState == kStateDisabled) - dd = kDDDropDownButtonDisabled; + dd = rtl ? kDDDropDownButtonDisabledRTL : kDDDropDownButtonDisabled; else if (buttonState == kStatePressed && inButton) - dd = kDDDropDownButtonPressedLeft; + dd = rtl ? kDDDropDownButtonPressedLeftRTL : kDDDropDownButtonPressedLeft; else if (buttonState == kStatePressed && inDropdown) - dd = kDDDropDownButtonPressedRight; + dd = rtl ? kDDDropDownButtonPressedRightRTL : kDDDropDownButtonPressedRight; else - dd = kDDDropDownButtonIdle; + dd = rtl ? kDDDropDownButtonIdleRTL : kDDDropDownButtonIdle; drawDD(dd, r); @@ -977,7 +989,7 @@ void ThemeEngine::drawDropDownButton(const Common::Rect &r, uint32 dropdownWidth Common::Rect textRect = r; textRect.left = r.left + dropdownWidth; textRect.right = r.right - dropdownWidth; - drawDDText(getTextData(dd), getTextColor(dd), textRect, str, false, true, _widgets[dd]->_textAlignH, + drawDDText(getTextData(dd), getTextColor(dd), textRect, str, false, true, convertTextAlignH(_widgets[dd]->_textAlignH, rtl), _widgets[dd]->_textAlignV); } @@ -988,7 +1000,7 @@ void ThemeEngine::drawLineSeparator(const Common::Rect &r) { drawDD(kDDSeparator, r); } -void ThemeEngine::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state) { +void ThemeEngine::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state, bool rtl) { if (!ready()) return; @@ -1003,21 +1015,27 @@ void ThemeEngine::drawCheckbox(const Common::Rect &r, const Common::String &str, const int checkBoxSize = MIN((int)r.height(), getFontHeight()); + r2.left = rtl ? r.right - checkBoxSize : r2.left; r2.bottom = r2.top + checkBoxSize; r2.right = r2.left + checkBoxSize; drawDD(dd, r2); - r2.left = r2.right + checkBoxSize; - r2.right = r.right; + if (rtl) { + r2.right = r2.left - checkBoxSize; + r2.left = r.left; + } else { + r2.left = r2.right + checkBoxSize; + r2.right = r.right; + } if (r2.right > r2.left) { - drawDDText(getTextData(dd), getTextColor(dd), r2, str, true, false, _widgets[kDDCheckboxDefault]->_textAlignH, + drawDDText(getTextData(dd), getTextColor(dd), r2, str, true, false, convertTextAlignH(_widgets[dd]->_textAlignH, rtl), _widgets[dd]->_textAlignV); } } -void ThemeEngine::drawRadiobutton(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state) { +void ThemeEngine::drawRadiobutton(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state, bool rtl) { if (!ready()) return; @@ -1032,19 +1050,25 @@ void ThemeEngine::drawRadiobutton(const Common::Rect &r, const Common::String &s const int checkBoxSize = MIN((int)r.height(), getFontHeight()); + r2.left = rtl ? r2.right - checkBoxSize : r2.left; r2.bottom = r2.top + checkBoxSize; r2.right = r2.left + checkBoxSize; drawDD(dd, r2); - r2.left = r2.right + checkBoxSize; - r2.right = MAX(r2.left, r.right); + if (rtl) { + r2.right = r2.left - checkBoxSize; + r2.left = r.left; + } else { + r2.left = r2.right + checkBoxSize; + r2.right = MAX(r2.left, r.right); + } - drawDDText(getTextData(dd), getTextColor(dd), r2, str, true, false, _widgets[kDDRadiobuttonDefault]->_textAlignH, - _widgets[dd]->_textAlignV); + drawDDText(getTextData(dd), getTextColor(dd), r2, str, true, false, convertTextAlignH(_widgets[dd]->_textAlignH, rtl), + _widgets[dd]->_textAlignV); } -void ThemeEngine::drawSlider(const Common::Rect &r, int width, WidgetStateInfo state) { +void ThemeEngine::drawSlider(const Common::Rect &r, int width, WidgetStateInfo state, bool rtl) { if (!ready()) return; @@ -1059,6 +1083,11 @@ void ThemeEngine::drawSlider(const Common::Rect &r, int width, WidgetStateInfo s r2.setWidth(MIN((int16)width, r.width())); // r2.top++; r2.bottom--; r2.left++; r2.right--; + if (rtl) { + r2.left = r.right - r2.width(); + r2.right = r.right; + } + drawWidgetBackground(r, kWidgetBackgroundSlider); drawDD(dd, r2); @@ -1132,24 +1161,24 @@ void ThemeEngine::drawCaret(const Common::Rect &r, bool erase) { drawDD(kDDCaret, r); } -void ThemeEngine::drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state) { +void ThemeEngine::drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state, bool rtl) { if (!ready()) return; - DrawData dd = kDDPopUpIdle; + DrawData dd = rtl ? kDDPopUpIdleRTL : kDDPopUpIdle; if (state == kStateEnabled) - dd = kDDPopUpIdle; + dd = rtl ? kDDPopUpIdleRTL : kDDPopUpIdle; else if (state == kStateHighlight) - dd = kDDPopUpHover; + dd = rtl ? kDDPopUpHoverRTL : kDDPopUpHover; else if (state == kStateDisabled) - dd = kDDPopUpDisabled; + dd = rtl ? kDDPopUpDisabledRTL : kDDPopUpDisabled; drawDD(dd, r); if (!sel.empty() && r.width() >= 13 && r.height() >= 1) { Common::Rect text(r.left + 3, r.top + 1, r.right - 10, r.bottom); - drawDDText(getTextData(dd), getTextColor(dd), text, sel, true, false, _widgets[dd]->_textAlignH, + drawDDText(getTextData(dd), getTextColor(dd), text, sel, true, false, convertTextAlignH(_widgets[dd]->_textAlignH, rtl), _widgets[dd]->_textAlignV, deltax); } } @@ -1199,7 +1228,7 @@ void ThemeEngine::drawWidgetBackground(const Common::Rect &r, WidgetBackground b } void ThemeEngine::drawTab(const Common::Rect &r, int tabHeight, const Common::Array<int> &tabWidths, - const Common::Array<Common::String> &tabs, int active) { + const Common::Array<Common::String> &tabs, int active, bool rtl) { if (!ready()) return; @@ -1207,22 +1236,37 @@ void ThemeEngine::drawTab(const Common::Rect &r, int tabHeight, const Common::Ar drawDD(kDDTabBackground, Common::Rect(r.left, r.top, r.right, r.top + tabHeight)); + const int numTabs = (int)tabs.size(); int width = 0; - int activePos = -1; - for (int i = 0; i < (int)tabs.size(); width += tabWidths[i++]) { - if (r.left + width > r.right || r.left + width + tabWidths[i] > r.right) - continue; - if (i == active) { + if (rtl) { + for (int i = 0; i < numTabs; i++) { + width += tabWidths[i]; + } + width = r.width() - width; + } + + int activePos = -1; + for (int i = 0; i < numTabs; i++) { + int current = rtl ? (numTabs - i - 1) : i; + + if (r.left + width > r.right || r.left + width + tabWidths[current] > r.right) { + width += tabWidths[current]; + continue; + } + + if (current == active) { activePos = width; + width += tabWidths[current]; continue; } - Common::Rect tabRect(r.left + width, r.top, r.left + width + tabWidths[i], r.top + tabHeight); + Common::Rect tabRect(r.left + width, r.top, r.left + width + tabWidths[current], r.top + tabHeight); drawDD(kDDTabInactive, tabRect); - drawDDText(getTextData(kDDTabInactive), getTextColor(kDDTabInactive), tabRect, tabs[i], false, false, - _widgets[kDDTabInactive]->_textAlignH, _widgets[kDDTabInactive]->_textAlignV); + drawDDText(getTextData(kDDTabInactive), getTextColor(kDDTabInactive), tabRect, tabs[current], false, false, + convertTextAlignH(_widgets[kDDTabInactive]->_textAlignH, rtl), _widgets[kDDTabInactive]->_textAlignV); + width += tabWidths[current]; } if (activePos >= 0) { @@ -1231,7 +1275,7 @@ void ThemeEngine::drawTab(const Common::Rect &r, int tabHeight, const Common::Ar const uint16 tabRight = MAX(r.right - tabRect.right, 0); drawDD(kDDTabActive, tabRect, (tabLeft << 16) | (tabRight & 0xFFFF)); drawDDText(getTextData(kDDTabActive), getTextColor(kDDTabActive), tabRect, tabs[active], false, false, - _widgets[kDDTabActive]->_textAlignH, _widgets[kDDTabActive]->_textAlignV); + convertTextAlignH(_widgets[kDDTabActive]->_textAlignH, rtl), _widgets[kDDTabActive]->_textAlignV); } } diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h index 668fa4b9cfd..44c35f7e800 100644 --- a/gui/ThemeEngine.h +++ b/gui/ThemeEngine.h @@ -37,7 +37,7 @@ #include "graphics/pixelformat.h" -#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8.36" +#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8.38" class OSystem; @@ -87,6 +87,13 @@ enum DrawData { kDDDropDownButtonPressedLeft, kDDDropDownButtonPressedRight, + kDDDropDownButtonIdleRTL, + kDDDropDownButtonHoverLeftRTL, + kDDDropDownButtonHoverRightRTL, + kDDDropDownButtonDisabledRTL, + kDDDropDownButtonPressedLeftRTL, + kDDDropDownButtonPressedRightRTL, + kDDSliderFull, kDDSliderHover, kDDSliderDisabled, @@ -114,6 +121,10 @@ enum DrawData { kDDPopUpHover, kDDPopUpDisabled, + kDDPopUpIdleRTL, + kDDPopUpHoverRTL, + kDDPopUpDisabledRTL, + kDDCaret, kDDSeparator, kDrawDataMAX, @@ -409,25 +420,25 @@ public: uint16 hints = 0); void drawDropDownButton(const Common::Rect &r, uint32 dropdownWidth, const Common::String &str, - WidgetStateInfo buttonState, bool inButton, bool inDropdown); + WidgetStateInfo buttonState, bool inButton, bool inDropdown, bool rtl = false); void drawSurface(const Common::Point &p, const Graphics::Surface &surface, bool themeTrans = false); - void drawSlider(const Common::Rect &r, int width, WidgetStateInfo state = kStateEnabled); + void drawSlider(const Common::Rect &r, int width, WidgetStateInfo state = kStateEnabled, bool rtl = false); void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, - WidgetStateInfo state = kStateEnabled); + WidgetStateInfo state = kStateEnabled, bool rtl = false); void drawRadiobutton(const Common::Rect &r, const Common::String &str, bool checked, - WidgetStateInfo state = kStateEnabled); + WidgetStateInfo state = kStateEnabled, bool rtl = false); void drawTab(const Common::Rect &r, int tabHeight, const Common::Array<int> &tabWidths, - const Common::Array<Common::String> &tabs, int active); + const Common::Array<Common::String> &tabs, int active, bool rtl = false); void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState scrollState); void drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, - WidgetStateInfo state = kStateEnabled); + WidgetStateInfo state = kStateEnabled, bool rtl = false); void drawCaret(const Common::Rect &r, bool erase); diff --git a/gui/ThemeEval.cpp b/gui/ThemeEval.cpp index 338e8d315e0..f7d0fde9135 100644 --- a/gui/ThemeEval.cpp +++ b/gui/ThemeEval.cpp @@ -51,6 +51,12 @@ void ThemeEval::reset() { } bool ThemeEval::getWidgetData(const Common::String &widget, int16 &x, int16 &y, int16 &w, int16 &h) { + bool useRTL; + + return getWidgetData(widget, x, y, w, h, useRTL); +} + +bool ThemeEval::getWidgetData(const Common::String &widget, int16 &x, int16 &y, int16 &w, int16 &h, bool &useRTL) { Common::StringTokenizer tokenizer(widget, "."); if (widget.hasPrefix("Dialog.")) @@ -62,7 +68,7 @@ bool ThemeEval::getWidgetData(const Common::String &widget, int16 &x, int16 &y, if (!_layouts.contains(dialogName)) return false; - return _layouts[dialogName]->getWidgetData(widgetName, x, y, w, h); + return _layouts[dialogName]->getWidgetData(widgetName, x, y, w, h, useRTL); } Graphics::TextAlign ThemeEval::getWidgetTextHAlign(const Common::String &widget) { @@ -80,7 +86,7 @@ Graphics::TextAlign ThemeEval::getWidgetTextHAlign(const Common::String &widget) return _layouts[dialogName]->getWidgetTextHAlign(widgetName); } -ThemeEval &ThemeEval::addWidget(const Common::String &name, const Common::String &type, int w, int h, Graphics::TextAlign align) { +ThemeEval &ThemeEval::addWidget(const Common::String &name, const Common::String &type, int w, int h, Graphics::TextAlign align, bool useRTL) { int typeW = -1; int typeH = -1; Graphics::TextAlign typeAlign = Graphics::kTextAlignInvalid; @@ -102,7 +108,8 @@ ThemeEval &ThemeEval::addWidget(const Common::String &name, const Common::String widget = new ThemeLayoutWidget(_curLayout.top(), name, typeW == -1 ? w : typeW, typeH == -1 ? h : typeH, - typeAlign == Graphics::kTextAlignInvalid ? align : typeAlign); + typeAlign == Graphics::kTextAlignInvalid ? align : typeAlign, + useRTL); _curLayout.top()->addChild(widget); diff --git a/gui/ThemeEval.h b/gui/ThemeEval.h index 053539ef48b..c4158e5edd8 100644 --- a/gui/ThemeEval.h +++ b/gui/ThemeEval.h @@ -76,7 +76,7 @@ public: ThemeEval &addDialog(const Common::String &name, const Common::String &overlays, int16 maxWidth = -1, int16 maxHeight = -1, int inset = 0); ThemeEval &addLayout(ThemeLayout::LayoutType type, int spacing = -1, ThemeLayout::ItemAlign itemAlign = ThemeLayout::kItemAlignStart); - ThemeEval &addWidget(const Common::String &name, const Common::String &type, int w = -1, int h = -1, Graphics::TextAlign align = Graphics::kTextAlignLeft); + ThemeEval &addWidget(const Common::String &name, const Common::String &type, int w = -1, int h = -1, Graphics::TextAlign align = Graphics::kTextAlignStart, bool useRTL = false); ThemeEval &addImportedLayout(const Common::String &name); ThemeEval &addSpace(int size = -1); @@ -89,6 +89,7 @@ public: void reflowDialogLayout(const Common::String &name, Widget *widgetChain); bool getWidgetData(const Common::String &widget, int16 &x, int16 &y, int16 &w, int16 &h); + bool getWidgetData(const Common::String &widget, int16 &x, int16 &y, int16 &w, int16 &h, bool &useRTL); Graphics::TextAlign getWidgetTextHAlign(const Common::String &widget); diff --git a/gui/ThemeLayout.cpp b/gui/ThemeLayout.cpp index edac50aa1a7..bc02efbd4cc 100644 --- a/gui/ThemeLayout.cpp +++ b/gui/ThemeLayout.cpp @@ -71,16 +71,18 @@ void ThemeLayout::resetLayout() { _children[i]->resetLayout(); } -bool ThemeLayout::getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h) { +bool ThemeLayout::getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h, bool &useRTL) { if (name.empty()) { assert(getLayoutType() == kLayoutMain); x = _x; y = _y; w = _w; h = _h; + useRTL = _useRTL; + return true; } for (uint i = 0; i < _children.size(); ++i) { - if (_children[i]->getWidgetData(name, x, y, w, h)) + if (_children[i]->getWidgetData(name, x, y, w, h, useRTL)) return true; } @@ -158,10 +160,12 @@ void ThemeLayout::debugDraw(Graphics::Surface *screen, const Graphics::Font *fon #endif -bool ThemeLayoutWidget::getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h) { +bool ThemeLayoutWidget::getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h, bool &useRTL) { if (name == _name) { x = _x; y = _y; w = _w; h = _h; + useRTL = _useRTL; + return true; } @@ -242,6 +246,19 @@ void ThemeLayoutMain::reflowLayout(Widget *widgetChain) { } } + if (g_gui.useRTL()) { + if (this->_name == "GameOptions" || this->_name == "GlobalOptions" || this->_name == "Browser") { + /** The dialogs named above are the stacked dialogs for which the left+right paddings need to be adjusted for RTL. + Whenever a stacked dialog is opened, the below code sets the left and right paddings and enables widgets to be + shifted by that amount. If any new stacked and padded dialogs are added in the future, + add them here and in Widget::draw() to enable RTL support for that particular dialog + */ + int oldX = _x; + _x = g_system->getOverlayWidth() - _w - _x; + g_gui.setDialogPaddings(oldX, _x); + } + } + if (_x >= 0) _x += _inset; if (_y >= 0) _y += _inset; if (_w >= 0) _w -= 2 * _inset; diff --git a/gui/ThemeLayout.h b/gui/ThemeLayout.h index 482413c1edf..25ec9eb997f 100644 --- a/gui/ThemeLayout.h +++ b/gui/ThemeLayout.h @@ -114,7 +114,7 @@ protected: virtual ThemeLayout *makeClone(ThemeLayout *newParent) = 0; public: - virtual bool getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h); + virtual bool getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h, bool &useRTL); virtual Graphics::TextAlign getWidgetTextHAlign(const Common::String &name); @@ -131,6 +131,7 @@ public: protected: ThemeLayout *_parent; int16 _x, _y, _w, _h; + bool _useRTL; Common::Rect _padding; Common::Array<ThemeLayout *> _children; int16 _defaultW, _defaultH; @@ -219,14 +220,15 @@ protected: class ThemeLayoutWidget : public ThemeLayout { public: - ThemeLayoutWidget(ThemeLayout *p, const Common::String &name, int16 w, int16 h, Graphics::TextAlign align) : ThemeLayout(p), _name(name) { + ThemeLayoutWidget(ThemeLayout *p, const Common::String &name, int16 w, int16 h, Graphics::TextAlign align, bool &useRTL) : ThemeLayout(p), _name(name) { _w = _defaultW = w; _h = _defaultH = h; + _useRTL = useRTL; setTextHAlign(align); } - bool getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h) override; + bool getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h, bool &useRTL) override; Graphics::TextAlign getWidgetTextHAlign(const Common::String &name) override; void reflowLayout(Widget *widgetChain) override; @@ -253,7 +255,7 @@ class ThemeLayoutTabWidget : public ThemeLayoutWidget { public: ThemeLayoutTabWidget(ThemeLayout *p, const Common::String &name, int16 w, int16 h, Graphics::TextAlign align, int tabHeight): - ThemeLayoutWidget(p, name, w, h, align) { + ThemeLayoutWidget(p, name, w, h, align, _useRTL) { _tabHeight = tabHeight; } @@ -263,8 +265,8 @@ public: } } - bool getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h) override { - if (ThemeLayoutWidget::getWidgetData(name, x, y, w, h)) { + bool getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h, bool &useRTL) override { + if (ThemeLayoutWidget::getWidgetData(name, x, y, w, h, _useRTL)) { h -= _tabHeight; return true; } @@ -294,7 +296,7 @@ public: } } - bool getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h) override { return false; } + bool getWidgetData(const Common::String &name, int16 &x, int16 &y, int16 &w, int16 &h, bool &useRTL) override { return false; } void reflowLayout(Widget *widgetChain) override {} #ifdef LAYOUT_DEBUG_DIALOG const char *getName() const { return "SPACE"; } diff --git a/gui/ThemeParser.cpp b/gui/ThemeParser.cpp index 9b9885bff53..23feda7b79f 100644 --- a/gui/ThemeParser.cpp +++ b/gui/ThemeParser.cpp @@ -80,8 +80,12 @@ static TextColor parseTextColorId(const Common::String &name) { return kTextColorMAX; } -static Graphics::TextAlign parseTextHAlign(const Common::String &val) { - if (val == "left") +Graphics::TextAlign parseTextHAlign(const Common::String &val) { + if (val == "start") + return Graphics::kTextAlignStart; + else if (val == "end") + return Graphics::kTextAlignEnd; + else if (val == "left") return Graphics::kTextAlignLeft; else if (val == "right") return Graphics::kTextAlignRight; @@ -684,6 +688,7 @@ bool ThemeParser::parserCallback_widget(ParserNode *node) { var = node->values["name"]; int width = -1; int height = -1; + bool useRTL = true; if (node->values.contains("width")) { if (_theme->getEvaluator()->hasVar(node->values["width"]) == true) @@ -701,14 +706,18 @@ bool ThemeParser::parserCallback_widget(ParserNode *node) { return parserError("Corrupted height value in key for " + var); } - Graphics::TextAlign alignH = Graphics::kTextAlignLeft; + Graphics::TextAlign alignH = Graphics::kTextAlignStart; if (node->values.contains("textalign")) { if ((alignH = parseTextHAlign(node->values["textalign"])) == Graphics::kTextAlignInvalid) return parserError("Invalid value for text alignment."); } - _theme->getEvaluator()->addWidget(var, node->values["type"], width, height, alignH); + if (node->values.contains("rtl")) { + useRTL = false; + } + + _theme->getEvaluator()->addWidget(var, node->values["type"], width, height, alignH, useRTL); } return true; @@ -956,7 +965,7 @@ bool ThemeParser::parseCommonLayoutProps(ParserNode *node, const Common::String if (node->values.contains("textalign")) { - Graphics::TextAlign alignH = Graphics::kTextAlignLeft; + Graphics::TextAlign alignH = Graphics::kTextAlignStart; if ((alignH = parseTextHAlign(node->values["textalign"])) == Graphics::kTextAlignInvalid) return parserError("Invalid value for text alignment."); diff --git a/gui/ThemeParser.h b/gui/ThemeParser.h index 661bccccf21..1b3004f1acc 100644 --- a/gui/ThemeParser.h +++ b/gui/ThemeParser.h @@ -177,6 +177,7 @@ protected: XML_PROP(padding, false) XML_PROP(resolution, false) XML_PROP(textalign, false) + XML_PROP(rtl, false) KEY_END() KEY_END() @@ -203,6 +204,7 @@ protected: XML_PROP(height, false) XML_PROP(type, false) XML_PROP(textalign, false) + XML_PROP(rtl, false) KEY_END() XML_KEY(space) diff --git a/gui/Tooltip.cpp b/gui/Tooltip.cpp index 079733c6fa2..69576628d1e 100644 --- a/gui/Tooltip.cpp +++ b/gui/Tooltip.cpp @@ -54,6 +54,10 @@ void Tooltip::setup(Dialog *parent, Widget *widget, int x, int y) { _x = MIN<int16>(parent->_x + x + _xdelta, g_gui.getWidth() - _w - 3); _y = MIN<int16>(parent->_y + y + _ydelta, g_gui.getHeight() - _h - 3); + + if (g_gui.useRTL()) + _x = g_system->getOverlayWidth() - _w - _x + g_gui.getOverlayOffset(); + #ifdef USE_TTS if (ConfMan.hasKey("tts_enabled", "residualvm") && ConfMan.getBool("tts_enabled", "residualvm")) { @@ -71,14 +75,17 @@ void Tooltip::drawDialog(DrawLayer layerToDraw) { Dialog::drawDialog(layerToDraw); - int16 textX = _x + 3; // including 2px padding and 1px original code shift + int16 textX = g_gui.useRTL() ? _x - 3 : _x + 3; // including 2px padding and 1px original code shift int16 textY = _y + 3; + + Graphics::TextAlign textAlignment = g_gui.useRTL() ? Graphics::kTextAlignRight : Graphics::kTextAlignLeft; + for (Common::StringArray::const_iterator i = _wrappedLines.begin(); i != _wrappedLines.end(); ++i, ++num) { g_gui.theme()->drawText( Common::Rect(textX, textY + num * h, textX + _w, textY + (num + 1) * h), *i, ThemeEngine::kStateEnabled, - Graphics::kTextAlignLeft, + textAlignment, ThemeEngine::kTextInversionNone, 0, false, diff --git a/gui/about.cpp b/gui/about.cpp index 71ba9fb2e88..d8e6a5206b4 100644 --- a/gui/about.cpp +++ b/gui/about.cpp @@ -473,7 +473,7 @@ void EE::run() { while (g_system->getEventManager()->pollEvent(event)) { switch (event.type) { case Common::EVENT_QUIT: - case Common::EVENT_RTL: + case Common::EVENT_RETURN_TO_LAUNCHER: _shouldQuit = true; break; diff --git a/gui/debugger.cpp b/gui/debugger.cpp index ea8a699ac00..895f37336d0 100644 --- a/gui/debugger.cpp +++ b/gui/debugger.cpp @@ -147,11 +147,11 @@ void Debugger::debugPrintColumns(const Common::StringArray &list) { } void Debugger::preEnter() { - g_engine->pauseEngine(true); + _debugPauseToken = g_engine->pauseEngine(); } void Debugger::postEnter() { - g_engine->pauseEngine(false); + _debugPauseToken.clear(); } void Debugger::attach(const char *entry) { diff --git a/gui/debugger.h b/gui/debugger.h index a100aae170a..adbdfec4614 100644 --- a/gui/debugger.h +++ b/gui/debugger.h @@ -31,6 +31,8 @@ #include "common/str.h" #include "common/str-array.h" +#include "engines/engine.h" + namespace GUI { #ifndef USE_TEXT_CONSOLE_FOR_DEBUGGER @@ -172,6 +174,9 @@ private: */ bool _firstTime; +protected: + PauseToken _debugPauseToken; + #ifndef USE_TEXT_CONSOLE_FOR_DEBUGGER GUI::ConsoleDialog *_debuggerDialog; #endif diff --git a/gui/filebrowser-dialog.cpp b/gui/filebrowser-dialog.cpp index e3d9bcb960d..734bf9fc8ff 100644 --- a/gui/filebrowser-dialog.cpp +++ b/gui/filebrowser-dialog.cpp @@ -109,7 +109,7 @@ void FileBrowserDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 void FileBrowserDialog::normalieFileName() { Common::String filename = _fileName->getEditString(); - if (filename.matchString(_fileMask)) + if (filename.matchString(_fileMask, true)) return; _fileName->setEditString(filename + "." + _fileExt); diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp index 94a6bf18cc8..bf424cc70a3 100644 --- a/gui/gui-manager.cpp +++ b/gui/gui-manager.cpp @@ -69,12 +69,18 @@ GuiManager::GuiManager() : _redrawStatus(kRedrawDisabled), _stateIsSaved(false), _launched = false; + _useRTL = false; + + _topDialogLeftPadding = 0; + _topDialogRightPadding = 0; + // Clear the cursor memset(_cursor, 0xFF, sizeof(_cursor)); #ifdef USE_TRANSLATION // Enable translation TransMan.setLanguage(ConfMan.get("gui_language").c_str()); + setLanguageRTL(); #endif // USE_TRANSLATION #ifdef USE_TTS @@ -575,6 +581,9 @@ void GuiManager::processEvent(const Common::Event &event, Dialog *const activeDi int button; uint32 time; Common::Point mouse(event.mouse.x - activeDialog->_x, event.mouse.y - activeDialog->_y); + if (g_gui.useRTL()) { + mouse.x = g_system->getOverlayWidth() - event.mouse.x - activeDialog->_x + g_gui.getOverlayOffset(); + } switch (event.type) { case Common::EVENT_KEYDOWN: @@ -584,7 +593,11 @@ void GuiManager::processEvent(const Common::Event &event, Dialog *const activeDi activeDialog->handleKeyUp(event.kbd); break; case Common::EVENT_MOUSEMOVE: - _globalMousePosition.x = event.mouse.x; + if (g_gui.useRTL()) { + _globalMousePosition.x = g_system->getOverlayWidth() - event.mouse.x + g_gui.getOverlayOffset(); + } else { + _globalMousePosition.x = event.mouse.x; + } _globalMousePosition.y = event.mouse.y; activeDialog->handleMouseMoved(mouse.x, mouse.y, 0); @@ -647,6 +660,27 @@ void GuiManager::setLastMousePos(int16 x, int16 y) { _lastMousePosition.time = _system->getMillis(true); } +void GuiManager::setLanguageRTL() { + if (ConfMan.hasKey("guiRTL")) { // Put guiRTL = yes to your scummvm.ini to force RTL GUI + _useRTL = ConfMan.getBool("guiRTL"); + return; + } +#ifdef USE_TRANSLATION + Common::String language = TransMan.getCurrentLanguage(); + if (language.equals("he")) { // GUI TODO: modify when we'll support other RTL languages, such as Arabic and Farsi + _useRTL = true; + return; + } +#endif // USE_TRANSLATION + + _useRTL = false; +} + +void GuiManager::setDialogPaddings(int l, int r) { + _topDialogLeftPadding = l; + _topDialogRightPadding = r; +} + #ifdef USE_TTS void GuiManager::initTextToSpeech() { Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager(); @@ -664,12 +698,12 @@ void GuiManager::initTextToSpeech() { ttsMan->setVolume(volume); unsigned voice; - if(ConfMan.hasKey("tts_voice")) + if(ConfMan.hasKey("tts_voice")) { voice = ConfMan.getInt("tts_voice", "residualvm"); - else - voice = 0; - if (voice >= ttsMan->getVoicesArray().size()) - voice = 0; + if (voice >= ttsMan->getVoicesArray().size()) + voice = ttsMan->getDefaultVoice(); + } else + voice = ttsMan->getDefaultVoice(); ttsMan->setVoice(voice); } #endif diff --git a/gui/gui-manager.h b/gui/gui-manager.h index 88470f0ead7..a8e88a4be2a 100644 --- a/gui/gui-manager.h +++ b/gui/gui-manager.h @@ -89,6 +89,12 @@ public: int getWidth() const { return _width; } int getHeight() const { return _height; } + bool useRTL() const { return _useRTL; } + void setLanguageRTL(); + + void setDialogPaddings(int l, int r); + int getOverlayOffset() { return _topDialogRightPadding - _topDialogLeftPadding; } + const Graphics::Font &getFont(ThemeEngine::FontStyle style = ThemeEngine::kFontStyleBold) const { return *(_theme->getFont(style)); } int getFontHeight(ThemeEngine::FontStyle style = ThemeEngine::kFontStyleBold) const { return _theme->getFontHeight(style); } int getStringWidth(const Common::String &str, ThemeEngine::FontStyle style = ThemeEngine::kFontStyleBold) const { return _theme->getStringWidth(str, style); } @@ -138,6 +144,11 @@ protected: bool _useStdCursor; + bool _useRTL; + + int _topDialogLeftPadding; + int _topDialogRightPadding; + // position and time of last mouse click (used to detect double clicks) struct MousePos { MousePos() : x(-1), y(-1), count(0) { time = 0; } diff --git a/gui/object.cpp b/gui/object.cpp index e9d2c4b19a4..339fbe8972f 100644 --- a/gui/object.cpp +++ b/gui/object.cpp @@ -30,7 +30,7 @@ namespace GUI { GuiObject::GuiObject(const Common::String &name) - : _x(-1000), _y(-1000), _w(0), _h(0), _name(name), _firstWidget(nullptr) { + : _x(-1000), _y(-1000), _w(0), _h(0), _useRTL(true), _name(name), _firstWidget(nullptr) { } GuiObject::~GuiObject() { @@ -41,12 +41,13 @@ GuiObject::~GuiObject() { void GuiObject::reflowLayout() { if (!_name.empty()) { int16 w, h; - - if (!g_gui.xmlEval()->getWidgetData(_name, _x, _y, w, h) || w == -1 || h == -1) { - error("Could not load widget position for '%s'", _name.c_str()); + bool useRTL = true; + if (!g_gui.xmlEval()->getWidgetData(_name, _x, _y, w, h, useRTL) || w == -1 || h == -1) { + error("Unable to load widget position for '%s'. Please check your theme files", _name.c_str()); } _w = w; _h = h; + _useRTL = useRTL; } } diff --git a/gui/object.h b/gui/object.h index 220e72e3f16..8320f4eb7b6 100644 --- a/gui/object.h +++ b/gui/object.h @@ -65,12 +65,13 @@ protected: int16 _x, _y; uint16 _w, _h; + bool _useRTL; const Common::String _name; Widget *_firstWidget; public: - GuiObject(int x, int y, int w, int h) : _x(x), _y(y), _w(w), _h(h), _firstWidget(nullptr) { } + GuiObject(int x, int y, int w, int h) : _x(x), _y(y), _w(w), _h(h), _useRTL(true), _firstWidget(nullptr) { } GuiObject(const Common::String &name); ~GuiObject() override; diff --git a/gui/onscreendialog.cpp b/gui/onscreendialog.cpp index 253f88c401b..4504521fa23 100644 --- a/gui/onscreendialog.cpp +++ b/gui/onscreendialog.cpp @@ -122,11 +122,11 @@ OnScreenDialog::OnScreenDialog(bool isRecord) : Dialog("OnScreenDialog") { } void OnScreenDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { - Common::Event eventRTL; + Common::Event eventReturnToLauncher; switch (cmd) { case kStopCmd: - eventRTL.type = Common::EVENT_RTL; - g_system->getEventManager()->pushEvent(eventRTL); + eventReturnToLauncher.type = Common::EVENT_RETURN_TO_LAUNCHER; + g_system->getEventManager()->pushEvent(eventReturnToLauncher); close(); break; case kEditCmd: diff --git a/gui/options.cpp b/gui/options.cpp index 8a2252df836..cc32911753c 100644 --- a/gui/options.cpp +++ b/gui/options.cpp @@ -150,6 +150,10 @@ OptionsDialog::OptionsDialog(const Common::String &domain, const Common::String OptionsDialog::~OptionsDialog() { delete _subToggleGroup; + if (g_gui.useRTL()) { + g_gui.setDialogPaddings(0, 0); + g_gui.scheduleTopDialogRedraw(); + } } void OptionsDialog::init() { @@ -1214,7 +1218,7 @@ void OptionsDialog::addAchievementsControls(GuiObject *boss, const Common::Strin yPos += yStep; if (info.descriptions[idx].comment && strlen(info.descriptions[idx].comment) > 0) { - new StaticTextWidget(scrollContainer, lineHeight + descrDelta, yPos, width - descrDelta, yStep, info.descriptions[idx].comment, Graphics::kTextAlignLeft, "", ThemeEngine::kFontStyleNormal); + new StaticTextWidget(scrollContainer, lineHeight + descrDelta, yPos, width - descrDelta, yStep, info.descriptions[idx].comment, Graphics::kTextAlignStart, "", ThemeEngine::kFontStyleNormal); yPos += yStep; } @@ -1224,12 +1228,12 @@ void OptionsDialog::addAchievementsControls(GuiObject *boss, const Common::Strin if (nHidden) { Common::String hiddenStr = Common::String::format(_("%d hidden achievements remaining"), nHidden); - new StaticTextWidget(scrollContainer, lineHeight, yPos, width, yStep, hiddenStr.c_str(), Graphics::kTextAlignLeft); + new StaticTextWidget(scrollContainer, lineHeight, yPos, width, yStep, hiddenStr.c_str(), Graphics::kTextAlignStart); } if (nMax) { Common::String totalStr = Common::String::format(_("Achievements unlocked: %d/%d"), nAchieved, nMax); - new StaticTextWidget(scrollContainer, lineHeight, lineHeight, width, yStep, totalStr.c_str(), Graphics::kTextAlignLeft); + new StaticTextWidget(scrollContainer, lineHeight, lineHeight, width, yStep, totalStr.c_str(), Graphics::kTextAlignStart); SliderWidget *progressBar; progressBar = new SliderWidget(scrollContainer, lineHeight, lineHeight*2, progressBarWidth, lineHeight); @@ -1356,13 +1360,14 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr } void OptionsDialog::addAudioControls(GuiObject *boss, const Common::String &prefix) { +#if 0 // not used by ResidualVM // The MIDI mode popup & a label if (g_system->getOverlayWidth() > 320) _midiPopUpDesc = new StaticTextWidget(boss, prefix + "auMidiPopupDesc", _domain == Common::ConfigManager::kApplicationDomain ? _("Preferred device:") : _("Music device:"), _domain == Common::ConfigManager::kApplicationDomain ? _("Specifies preferred sound device or sound card emulator") : _("Specifies output sound device or sound card emulator")); else _midiPopUpDesc = new StaticTextWidget(boss, prefix + "auMidiPopupDesc", _domain == Common::ConfigManager::kApplicationDomain ? _c("Preferred dev.:", "lowres") : _c("Music device:", "lowres"), _domain == Common::ConfigManager::kApplicationDomain ? _("Specifies preferred sound device or sound card emulator") : _("Specifies output sound device or sound card emulator")); _midiPopUp = new PopUpWidget(boss, prefix + "auMidiPopup", _("Specifies output sound device or sound card emulator")); - +#endif // Populate it const Common::String allFlags = MidiDriver::musicType2GUIO((uint32)-1); bool hasMidiDefined = (strpbrk(_guioptions.c_str(), allFlags.c_str()) != nullptr); @@ -1386,12 +1391,12 @@ void OptionsDialog::addAudioControls(GuiObject *boss, const Common::String &pref } } +#if 0 // ResidualVM specific // The OPL emulator popup & a label _oplPopUpDesc = new StaticTextWidget(boss, prefix + "auOPLPopupDesc", _("AdLib emulator:"), _("AdLib is used for music in many games")); _oplPopUp = new PopUpWidget(boss, prefix + "auOPLPopup", _("AdLib is used for music in many games")); // Populate it -#if 0 // ResidualVM specific const OPL::Config::EmulatorDescription *ed = OPL::Config::getAvailable(); while (ed->name) { _oplPopUp->appendEntry(_(ed->description), ed->id); @@ -2279,16 +2284,18 @@ void GlobalOptionsDialog::addAccessibilityControls(GuiObject *boss, const Common if (ttsMan != nullptr) voices = ttsMan->getVoicesArray(); - for(unsigned i = 0; i < voices.size(); i++) { - _ttsVoiceSelectionPopUp->appendEntry(voices[i].getDescription(), i); - } if (voices.empty()) _ttsVoiceSelectionPopUp->appendEntry(_("None"), 0); + else { + _ttsVoiceSelectionPopUp->appendEntry(_("<default>")); + for(unsigned i = 0; i < voices.size(); i++) + _ttsVoiceSelectionPopUp->appendEntry(voices[i].getDescription(), i); + } - if (ConfMan.hasKey("tts_voice") && (unsigned) ConfMan.getInt("tts_voice", _domain) < voices.size()) + if (ConfMan.hasKey("tts_voice", _domain) && (unsigned) ConfMan.getInt("tts_voice", _domain) < voices.size()) _ttsVoiceSelectionPopUp->setSelectedTag(ConfMan.getInt("tts_voice", _domain)) ; else - _ttsVoiceSelectionPopUp->setSelectedTag(0); + _ttsVoiceSelectionPopUp->setSelected(0); } #endif @@ -2394,6 +2401,7 @@ void GlobalOptionsDialog::apply() { ConfMan.set("gui_language", newLang); newCharset = TransMan.getCurrentCharset(); isRebuildNeeded = true; + g_gui.setLanguageRTL(); } bool guiUseGameLanguage = _guiLanguageUseGameLanguageCheckbox->getState(); @@ -2450,15 +2458,17 @@ void GlobalOptionsDialog::apply() { else { ttsMan->setLanguage(newLang); } - _ttsVoiceSelectionPopUp->setSelectedTag(0); + _ttsVoiceSelectionPopUp->setSelected(0); } int volume = (ConfMan.getInt("speech_volume", "residualvm") * 100) / 256; if (ConfMan.hasKey("mute", "residualvm") && ConfMan.getBool("mute", "residualvm")) volume = 0; ttsMan->setVolume(volume); ConfMan.setBool("tts_enabled", _ttsCheckbox->getState(), _domain); - int selectedVoice = _ttsVoiceSelectionPopUp->getSelectedTag(); + unsigned selectedVoice = _ttsVoiceSelectionPopUp->getSelectedTag(); ConfMan.setInt("tts_voice", selectedVoice, _domain); + if (selectedVoice >= ttsMan->getVoicesArray().size()) + selectedVoice = ttsMan->getDefaultVoice(); ttsMan->setVoice(selectedVoice); } #endif diff --git a/gui/predictivedialog.cpp b/gui/predictivedialog.cpp index 73abd5a2c16..7670912b1c0 100644 --- a/gui/predictivedialog.cpp +++ b/gui/predictivedialog.cpp @@ -72,16 +72,36 @@ PredictiveDialog::PredictiveDialog() : Dialog("Predictive") { _button[kCancelAct] = new ButtonWidget(this, "Predictive.Cancel", _("Cancel") , nullptr, kCancelCmd); _button[kOkAct] = new ButtonWidget(this, "Predictive.OK", _("Ok") , nullptr, kOkCmd); - _button[kButton1Act] = new ButtonWidget(this, "Predictive.Button1", "1 `-.&" , nullptr, kBut1Cmd); - _button[kButton2Act] = new ButtonWidget(this, "Predictive.Button2", "2 abc" , nullptr, kBut2Cmd); - _button[kButton3Act] = new ButtonWidget(this, "Predictive.Button3", "3 def" , nullptr, kBut3Cmd); - _button[kButton4Act] = new ButtonWidget(this, "Predictive.Button4", "4 ghi" , nullptr, kBut4Cmd); - _button[kButton5Act] = new ButtonWidget(this, "Predictive.Button5", "5 jkl" , nullptr, kBut5Cmd); - _button[kButton6Act] = new ButtonWidget(this, "Predictive.Button6", "6 mno" , nullptr, kBut6Cmd); - _button[kButton7Act] = new ButtonWidget(this, "Predictive.Button7", "7 pqrs" , nullptr, kBut7Cmd); - _button[kButton8Act] = new ButtonWidget(this, "Predictive.Button8", "8 tuv" , nullptr, kBut8Cmd); - _button[kButton9Act] = new ButtonWidget(this, "Predictive.Button9", "9 wxyz" , nullptr, kBut9Cmd); - _button[kButton0Act] = new ButtonWidget(this, "Predictive.Button0", "0" , nullptr, kBut0Cmd); + + if (g_gui.useRTL()) { + /** If using RTL, swap the internal name of odd columns, to be flipped again when drawing. + We flip them back to orignal, because the keyboard layout stays the same in LTR & RTL. + The rest, like okButton, cancel, etc are all flipped. + */ + + _button[kButton3Act] = new ButtonWidget(this, "Predictive.Button1", "3 def" , nullptr, kBut3Cmd); + _button[kButton2Act] = new ButtonWidget(this, "Predictive.Button2", "2 abc" , nullptr, kBut2Cmd); + _button[kButton1Act] = new ButtonWidget(this, "Predictive.Button3", "1 `-.&" , nullptr, kBut1Cmd); + _button[kButton6Act] = new ButtonWidget(this, "Predictive.Button4", "6 mno" , nullptr, kBut6Cmd); + _button[kButton5Act] = new ButtonWidget(this, "Predictive.Button5", "5 jkl" , nullptr, kBut5Cmd); + _button[kButton4Act] = new ButtonWidget(this, "Predictive.Button6", "4 ghi" , nullptr, kBut4Cmd); + _button[kButton9Act] = new ButtonWidget(this, "Predictive.Button7", "9 wxyz" , nullptr, kBut9Cmd); + _button[kButton8Act] = new ButtonWidget(this, "Predictive.Button8", "8 tuv" , nullptr, kBut8Cmd); + _button[kButton7Act] = new ButtonWidget(this, "Predictive.Button9", "7 pqrs" , nullptr, kBut7Cmd); + _button[kButton0Act] = new ButtonWidget(this, "Predictive.Button0", "0" , nullptr, kBut0Cmd); + } else { + _button[kButton1Act] = new ButtonWidget(this, "Predictive.Button1", "1 `-.&" , nullptr, kBut1Cmd); + _button[kButton2Act] = new ButtonWidget(this, "Predictive.Button2", "2 abc" , nullptr, kBut2Cmd); + _button[kButton3Act] = new ButtonWidget(this, "Predictive.Button3", "3 def" , nullptr, kBut3Cmd); + _button[kButton4Act] = new ButtonWidget(this, "Predictive.Button4", "4 ghi" , nullptr, kBut4Cmd); + _button[kButton5Act] = new ButtonWidget(this, "Predictive.Button5", "5 jkl" , nullptr, kBut5Cmd); + _button[kButton6Act] = new ButtonWidget(this, "Predictive.Button6", "6 mno" , nullptr, kBut6Cmd); + _button[kButton7Act] = new ButtonWidget(this, "Predictive.Button7", "7 pqrs" , nullptr, kBut7Cmd); + _button[kButton8Act] = new ButtonWidget(this, "Predictive.Button8", "8 tuv" , nullptr, kBut8Cmd); + _button[kButton9Act] = new ButtonWidget(this, "Predictive.Button9", "9 wxyz" , nullptr, kBut9Cmd); + _button[kButton0Act] = new ButtonWidget(this, "Predictive.Button0", "0" , nullptr, kBut0Cmd); + } + // I18N: You must leave "#" as is, only word 'next' is translatable _button[kNextAct] = new ButtonWidget(this, "Predictive.Next", _("# next") , nullptr, kNextCmd); _button[kAddAct] = new ButtonWidget(this, "Predictive.Add", _("add") , nullptr, kAddCmd); diff --git a/gui/recorderdialog.cpp b/gui/recorderdialog.cpp index ab0ce348b1b..62999ca3b66 100644 --- a/gui/recorderdialog.cpp +++ b/gui/recorderdialog.cpp @@ -24,7 +24,6 @@ #include "common/bufferedstream.h" #include "common/savefile.h" #include "common/system.h" -#include "graphics/colormasks.h" #include "graphics/palette.h" #include "graphics/scaler.h" #include "graphics/thumbnail.h" @@ -95,7 +94,7 @@ void RecorderDialog::reflowLayout() { if (g_gui.xmlEval()->getVar("Globals.RecorderDialog.ExtInfo.Visible") == 1) { int16 x, y; - uint16 w, h; + int16 w, h; if (!g_gui.xmlEval()->getWidgetData("RecorderDialog.Thumbnail", x, y, w, h)) { error("Error when loading position data for Recorder Thumbnails"); diff --git a/gui/saveload-dialog.cpp b/gui/saveload-dialog.cpp index d63d2479a6e..62678647b4a 100644 --- a/gui/saveload-dialog.cpp +++ b/gui/saveload-dialog.cpp @@ -376,7 +376,7 @@ SaveLoadChooserSimple::SaveLoadChooserSimple(const String &title, const String & _container(nullptr) { _backgroundType = ThemeEngine::kDialogBackgroundSpecial; - new StaticTextWidget(this, "SaveLoadChooser.Title", title); + _pageTitle = new StaticTextWidget(this, "SaveLoadChooser.Title", title); // Add choice list _list = new ListWidget(this, "SaveLoadChooser.List"); @@ -757,7 +757,7 @@ SaveLoadChooserGrid::SaveLoadChooserGrid(const Common::String &title, bool saveM _curPage(0), _newSaveContainer(nullptr), _nextFreeSaveSlot(0), _buttons() { _backgroundType = ThemeEngine::kDialogBackgroundSpecial; - new StaticTextWidget(this, "SaveLoadChooser.Title", title); + _pageTitle = new StaticTextWidget(this, "SaveLoadChooser.Title", title); // The list widget needs to be bound so it takes space in the layout ContainerWidget *list = new ContainerWidget(this, "SaveLoadChooser.List"); @@ -773,10 +773,13 @@ SaveLoadChooserGrid::SaveLoadChooserGrid(const Common::String &title, bool saveM // Page display _pageDisplay = new StaticTextWidget(this, "SaveLoadChooser.PageDisplay", Common::String()); - _pageDisplay->setAlign(Graphics::kTextAlignRight); + _pageDisplay->setAlign(Graphics::kTextAlignEnd); } SaveLoadChooserGrid::~SaveLoadChooserGrid() { + removeWidget(_pageTitle); + delete _pageTitle; + removeWidget(_pageDisplay); delete _pageDisplay; } @@ -994,7 +997,7 @@ void SaveLoadChooserGrid::reflowLayout() { PicButtonWidget *button = new PicButtonWidget(container, dstX, dstY, buttonWidth, buttonHeight, nullptr, buttonCmd); dstY += buttonHeight; - StaticTextWidget *description = new StaticTextWidget(container, dstX, dstY, buttonWidth, kLineHeight, Common::String(), Graphics::kTextAlignLeft); + StaticTextWidget *description = new StaticTextWidget(container, dstX, dstY, buttonWidth, kLineHeight, Common::String(), Graphics::kTextAlignStart); _buttons.push_back(SlotButton(container, button, description)); } diff --git a/gui/saveload-dialog.h b/gui/saveload-dialog.h index f9a437de604..ce8b84d9876 100644 --- a/gui/saveload-dialog.h +++ b/gui/saveload-dialog.h @@ -161,6 +161,7 @@ private: StaticTextWidget *_date; StaticTextWidget *_time; StaticTextWidget *_playtime; + StaticTextWidget *_pageTitle; String _resultString; @@ -218,6 +219,7 @@ private: ButtonWidget *_nextButton; ButtonWidget *_prevButton; + StaticTextWidget *_pageTitle; StaticTextWidget *_pageDisplay; ContainerWidget *_newSaveContainer; diff --git a/gui/themes/default.inc b/gui/themes/default.inc index b8e9831a82f..f4907481c55 100644 --- a/gui/themes/default.inc +++ b/gui/themes/default.inc @@ -287,7 +287,38 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " -"horizontal_align='left' " +"horizontal_align='start' " +"/>" +"</drawdata>" +"<drawdata id='popup_idle_rtl' cache='false' resolution='y>399'>" +"<drawstep func='bevelsq' " +"bevel='2' " +"fill='none' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='10' " +"height='5' " +"xpos='left' " +"ypos='10' " +"padding='2,0,7,0' " +"orientation='bottom' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='10' " +"height='5' " +"xpos='left' " +"ypos='4' " +"padding='2,0,7,0' " +"orientation='top' " +"/>" +"<text font='text_default' " +"text_color='color_normal' " +"vertical_align='center' " +"horizontal_align='start' " "/>" "</drawdata>" "<drawdata id='popup_idle' cache='false' resolution='y<400'>" @@ -318,7 +349,38 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " -"horizontal_align='left' " +"horizontal_align='start' " +"/>" +"</drawdata>" +"<drawdata id='popup_idle_rtl' cache='false' resolution='y<400'>" +"<drawstep func='bevelsq' " +"bevel='2' " +"fill='none' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='7' " +"height='4' " +"xpos='left' " +"ypos='9' " +"padding='2,0,3,0' " +"orientation='bottom' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='7' " +"height='4' " +"xpos='left' " +"ypos='4' " +"padding='2,0,3,0' " +"orientation='top' " +"/>" +"<text font='text_default' " +"text_color='color_normal' " +"vertical_align='center' " +"horizontal_align='start' " "/>" "</drawdata>" "<drawdata id='popup_disabled' cache='false' resolution='y>399'>" @@ -349,7 +411,38 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<text font='text_default' " "text_color='color_normal_disabled' " "vertical_align='center' " -"horizontal_align='left' " +"horizontal_align='start' " +"/>" +"</drawdata>" +"<drawdata id='popup_disabled_rtl' cache='false' resolution='y>399'>" +"<drawstep func='bevelsq' " +"bevel='2' " +"fill='none' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='10' " +"height='5' " +"xpos='left' " +"ypos='10' " +"padding='2,0,7,0' " +"orientation='bottom' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='10' " +"height='5' " +"xpos='left' " +"ypos='4' " +"padding='2,0,7,0' " +"orientation='top' " +"/>" +"<text font='text_default' " +"text_color='color_normal_disabled' " +"vertical_align='center' " +"horizontal_align='start' " "/>" "</drawdata>" "<drawdata id='popup_disabled' cache='false' resolution='y<400'>" @@ -380,7 +473,38 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " -"horizontal_align='left' " +"horizontal_align='start' " +"/>" +"</drawdata>" +"<drawdata id='popup_disabled_rtl' cache='false' resolution='y<400'>" +"<drawstep func='bevelsq' " +"bevel='2' " +"fill='none' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='7' " +"height='4' " +"xpos='left' " +"ypos='9' " +"padding='2,0,3,0' " +"orientation='bottom' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='7' " +"height='4' " +"xpos='left' " +"ypos='4' " +"padding='2,0,3,0' " +"orientation='top' " +"/>" +"<text font='text_default' " +"text_color='color_normal' " +"vertical_align='center' " +"horizontal_align='start' " "/>" "</drawdata>" "<drawdata id='popup_hover' cache='false' resolution='y>399'>" @@ -411,7 +535,38 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<text font='text_default' " "text_color='color_normal_hover' " "vertical_align='center' " -"horizontal_align='left' " +"horizontal_align='start' " +"/>" +"</drawdata>" +"<drawdata id='popup_hover_rtl' cache='false' resolution='y>399'>" +"<drawstep func='bevelsq' " +"bevel='2' " +"fill='none' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='10' " +"height='5' " +"xpos='left' " +"ypos='10' " +"padding='2,0,7,0' " +"orientation='bottom' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='10' " +"height='5' " +"xpos='left' " +"ypos='4' " +"padding='2,0,7,0' " +"orientation='top' " +"/>" +"<text font='text_default' " +"text_color='color_normal_hover' " +"vertical_align='center' " +"horizontal_align='start' " "/>" "</drawdata>" "<drawdata id='popup_hover' cache='false' resolution='y<400'>" @@ -442,7 +597,38 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " -"horizontal_align='left' " +"horizontal_align='start' " +"/>" +"</drawdata>" +"<drawdata id='popup_hover_rtl' cache='false' resolution='y<400'>" +"<drawstep func='bevelsq' " +"bevel='2' " +"fill='none' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='7' " +"height='4' " +"xpos='left' " +"ypos='9' " +"padding='2,0,3,0' " +"orientation='bottom' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='7' " +"height='4' " +"xpos='left' " +"ypos='4' " +"padding='2,0,3,0' " +"orientation='top' " +"/>" +"<text font='text_default' " +"text_color='color_normal' " +"vertical_align='center' " +"horizontal_align='start' " "/>" "</drawdata>" "<drawdata id='widget_textedit' cache='false'>" @@ -542,6 +728,37 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "padding='0,0,17,1' " "/>" "</drawdata>" +"<drawdata id='dropdown_button_idle_rtl' cache='false' resolution='y>399'>" +"<text font='text_button' " +"text_color='color_button' " +"vertical_align='center' " +"horizontal_align='center' " +"/>" +"<drawstep func='bevelsq' " +"bevel='2' " +"fill='none' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='8' " +"height='6' " +"xpos='left' " +"ypos='center' " +"padding='2,0,4,0' " +"orientation='bottom' " +"/>" +"<drawstep func='line' " +"fg_color='lightgrey' " +"stroke='2' " +"fill='foreground' " +"width='0' " +"height='auto' " +"xpos='left' " +"ypos='center' " +"padding='17,0,0,1' " +"/>" +"</drawdata>" "<drawdata id='dropdown_button_idle' cache='false' resolution='y<400'>" "<text font='text_button' " "text_color='color_button' " @@ -563,6 +780,27 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "orientation='bottom' " "/>" "</drawdata>" +"<drawdata id='dropdown_button_idle_rtl' cache='false' resolution='y<400'>" +"<text font='text_button' " +"text_color='color_button' " +"vertical_align='center' " +"horizontal_align='center' " +"/>" +"<drawstep func='bevelsq' " +"bevel='2' " +"fill='none' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='6' " +"height='6' " +"xpos='left' " +"ypos='center' " +"padding='0,0,0,0' " +"orientation='bottom' " +"/>" +"</drawdata>" "<drawdata id='dropdown_button_hover_left' cache='false' resolution='y>399'>" "<text font='text_button' " "text_color='color_button_hover' " @@ -594,6 +832,37 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "padding='0,0,17,1' " "/>" "</drawdata>" +"<drawdata id='dropdown_button_hover_left_rtl' cache='false' resolution='y>399'>" +"<text font='text_button' " +"text_color='color_button_hover' " +"vertical_align='center' " +"horizontal_align='center' " +"/>" +"<drawstep func='bevelsq' " +"bevel='2' " +"fill='none' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='8' " +"height='6' " +"xpos='left' " +"ypos='center' " +"padding='2,0,4,0' " +"orientation='bottom' " +"/>" +"<drawstep func='line' " +"fg_color='lightgrey' " +"stroke='2' " +"fill='foreground' " +"width='0' " +"height='auto' " +"xpos='left' " +"ypos='center' " +"padding='17,0,0,1' " +"/>" +"</drawdata>" "<drawdata id='dropdown_button_hover_left' cache='false' resolution='y<400'>" "<text font='text_button' " "text_color='color_button_hover' " @@ -615,6 +884,27 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "orientation='bottom' " "/>" "</drawdata>" +"<drawdata id='dropdown_button_hover_left_rtl' cache='false' resolution='y<400'>" +"<text font='text_button' " +"text_color='color_button_hover' " +"vertical_align='center' " +"horizontal_align='center' " +"/>" +"<drawstep func='bevelsq' " +"bevel='2' " +"fill='none' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='6' " +"height='6' " +"xpos='left' " +"ypos='center' " +"padding='0,0,0,0' " +"orientation='bottom' " +"/>" +"</drawdata>" "<drawdata id='dropdown_button_hover_right' cache='false' resolution='y>399'>" "<text font='text_button' " "text_color='color_button' " @@ -646,6 +936,37 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "padding='0,0,17,1' " "/>" "</drawdata>" +"<drawdata id='dropdown_button_hover_right_rtl' cache='false' resolution='y>399'>" +"<text font='text_button' " +"text_color='color_button' " +"vertical_align='center' " +"horizontal_align='center' " +"/>" +"<drawstep func='bevelsq' " +"bevel='2' " +"fill='none' " +"/>" +"<drawstep func='triangle' " +"fg_color='green2' " +"fill='foreground' " +"width='8' " +"height='6' " +"xpos='left' " +"ypos='center' " +"padding='2,0,4,0' " +"orientation='bottom' " +"/>" +"<drawstep func='line' " +"fg_color='lightgrey' " +"stroke='2' " +"fill='foreground' " +"width='0' " +"height='auto' " +"xpos='left' " +"ypos='center' " +"padding='17,0,0,1' " +"/>" +"</drawdata>" "<drawdata id='dropdown_button_hover_right' cache='false' resolution='y<400'>" "<text font='text_button' " "text_color='color_button' " @@ -667,6 +988,27 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "orientation='bottom' " "/>" "</drawdata>" +"<drawdata id='dropdown_button_hover_right_rtl' cache='false' resolution='y<400'>" +"<text font='text_button' " +"text_color='color_button' " +"vertical_align='center' " +"horizontal_align='center' " +"/>" +"<drawstep func='bevelsq' " +"bevel='2' " +"fill='none' " +"/>" +"<drawstep func='triangle' " +"fg_color='green2' " +"fill='foreground' " +"width='6' " +"height='6' " +"xpos='left' " +"ypos='center' " +"padding='0,0,0,0' " +"orientation='bottom' " +"/>" +"</drawdata>" "<drawdata id='dropdown_button_disabled' cache='false' resolution='y>399'>" "<text font='text_button' " "text_color='color_button_disabled' " @@ -698,6 +1040,37 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "padding='0,0,17,1' " "/>" "</drawdata>" +"<drawdata id='dropdown_button_disabled_rtl' cache='false' resolution='y>399'>" +"<text font='text_button' " +"text_color='color_button_disabled' " +"vertical_align='center' " +"horizontal_align='center' " +"/>" +"<drawstep func='bevelsq' " +"bevel='2' " +"fill='none' " +"/>" +"<drawstep func='triangle' " +"fg_color='lightgrey' " +"fill='foreground' " +"width='8' " +"height='6' " +"xpos='left' " +"ypos='center' " +"padding='2,0,4,0' " +"orientation='bottom' " +"/>" +"<drawstep func='line' " +"fg_color='lightgrey' " +"stroke='2' " +"fill='foreground' " +"width='0' " +"height='auto' " +"xpos='left' " +"ypos='center' " +"padding='17,0,0,1' " +"/>" +"</drawdata>" "<drawdata id='dropdown_button_disabled' cache='false' resolution='y<400'>" "<text font='text_button' " "text_color='color_button_disabled' " @@ -719,6 +1092,27 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "orientation='bottom' " "/>" "</drawdata>" +"<drawdata id='dropdown_button_disabled_rtl' cache='false' resolution='y<400'>" +"<text font='text_button' " +"text_color='color_button_disabled' " +"vertical_align='center' " +"horizontal_align='center' " +"/>" +"<drawstep func='bevelsq' " +"bevel='2' " +"fill='none' " +"/>" +"<drawstep func='triangle' " +"fg_color='lightgrey' " +"fill='foreground' " +"width='6' " +"height='6' " +"xpos='left' " +"ypos='center' " +"padding='0,0,0,0' " +"orientation='bottom' " +"/>" +"</drawdata>" "<drawdata id='dropdown_button_pressed_left' cache='false' resolution='y>399'>" "<text font='text_button' " "text_color='color_alternative_inverted' " @@ -741,6 +1135,28 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "orientation='bottom' " "/>" "</drawdata>" +"<drawdata id='dropdown_button_pressed_left_rtl' cache='false' resolution='y>399'>" +"<text font='text_button' " +"text_color='color_alternative_inverted' " +"vertical_align='center' " +"horizontal_align='center' " +"/>" +"<drawstep func='square' " +"fill='foreground' " +"fg_color='green' " +"clip='18,0,0,0' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='8' " +"height='6' " +"xpos='left' " +"ypos='center' " +"padding='2,0,4,0' " +"orientation='bottom' " +"/>" +"</drawdata>" "<drawdata id='dropdown_button_pressed_left' cache='false' resolution='y<400'>" "<text font='text_button' " "text_color='color_alternative_inverted' " @@ -763,6 +1179,28 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "orientation='bottom' " "/>" "</drawdata>" +"<drawdata id='dropdown_button_pressed_left_rtl' cache='false' resolution='y<400'>" +"<text font='text_button' " +"text_color='color_alternative_inverted' " +"vertical_align='center' " +"horizontal_align='center' " +"/>" +"<drawstep func='square' " +"fill='foreground' " +"fg_color='green' " +"clip='7,0,0,0' " +"/>" +"<drawstep func='triangle' " +"fg_color='green' " +"fill='foreground' " +"width='6' " +"height='6' " +"xpos='left' " +"ypos='center' " +"padding='0,0,0,0' " +"orientation='bottom' " +"/>" +"</drawdata>" "<drawdata id='dropdown_button_pressed_right' cache='false' resolution='y>399'>" "<text font='text_button' " "text_color='color_button' " @@ -785,6 +1223,28 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "orientation='bottom' " "/>" "</drawdata>" +"<drawdata id='dropdown_button_pressed_right_rtl' cache='false' resolution='y>399'>" +"<text font='text_button' " +"text_color='color_button' " +"vertical_align='center' " +"horizontal_align='center' " +"/>" +"<drawstep func='square' " +"fill='foreground' " +"fg_color='green' " +"clip='0,0,16,0' " +"/>" +"<drawstep func='triangle' " +"fg_color='white' " +"fill='foreground' " +"width='8' " +"height='6' " +"xpos='left' " +"ypos='center' " +"padding='2,0,4,0' " +"orientation='bottom' " +"/>" +"</drawdata>" "<drawdata id='dropdown_button_pressed_right' cache='false' resolution='y<400'>" "<text font='text_button' " "text_color='color_button' " @@ -807,11 +1267,33 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "orientation='bottom' " "/>" "</drawdata>" +"<drawdata id='dropdown_button_pressed_right_rtl' cache='false' resolution='y<400'>" +"<text font='text_button' " +"text_color='color_button' " +"vertical_align='center' " +"horizontal_align='center' " +"/>" +"<drawstep func='square' " +"fill='foreground' " +"fg_color='green' " +"clip='0,0,7,0' " +"/>" +"<drawstep func='triangle' " +"fg_color='white' " +"fill='foreground' " +"width='6' " +"height='6' " +"xpos='left' " +"ypos='center' " +"padding='0,0,0,0' " +"orientation='bottom' " +"/>" +"</drawdata>" "<drawdata id='checkbox_disabled_selected' cache='false'>" "<text font='text_default' " "text_color='color_normal_disabled' " "vertical_align='top' " -"horizontal_align='left' " +"horizontal_align='start' " "/>" "<drawstep func='bevelsq' " "bevel='2' " @@ -827,7 +1309,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<text font='text_default' " "text_color='color_normal_disabled' " "vertical_align='top' " -"horizontal_align='left' " +"horizontal_align='start' " "/>" "<drawstep func='bevelsq' " "bevel='2' " @@ -838,7 +1320,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='top' " -"horizontal_align='left' " +"horizontal_align='start' " "/>" "<drawstep func='bevelsq' " "bevel='2' " @@ -854,7 +1336,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='top' " -"horizontal_align='left' " +"horizontal_align='start' " "/>" "<drawstep func='bevelsq' " "bevel='2' " @@ -865,7 +1347,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " -"horizontal_align='left' " +"horizontal_align='start' " "/>" "<drawstep func='circle' " "width='7' " @@ -881,7 +1363,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " -"horizontal_align='left' " +"horizontal_align='start' " "/>" "<drawstep func='circle' " "width='7' " @@ -906,7 +1388,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<text font='text_default' " "text_color='color_normal_disabled' " "vertical_align='center' " -"horizontal_align='left' " +"horizontal_align='start' " "/>" "<drawstep func='circle' " "width='7' " @@ -955,7 +1437,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<def var='DropdownButton.Width' value='17'/>" "<widget name='OptionsLabel' " "size='110,Globals.Line.Height' " -"textalign='right' " +"textalign='end' " "/>" "<widget name='SmallLabel' " "size='24,Globals.Line.Height' " @@ -1030,7 +1512,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<widget name='SearchDesc' " "width='60' " "height='Globals.Line.Height' " -"textalign='right' " +"textalign='end' " "/>" "<widget name='Search' " "width='150' " @@ -1158,6 +1640,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='grKbdMouseSpeedSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='grKbdMouseSpeedLabel' " "type='SmallLabel' " @@ -1169,6 +1652,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='grJoystickDeadzoneSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='grJoystickDeadzoneLabel' " "type='SmallLabel' " @@ -1296,6 +1780,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='subSubtitleSpeedSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='subSubtitleSpeedLabel' " "type='SmallLabel' " @@ -1312,6 +1797,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='vcMusicSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='vcMusicLabel' " "type='SmallLabel' " @@ -1323,6 +1809,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='vcSfxSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='vcSfxLabel' " "type='SmallLabel' " @@ -1334,6 +1821,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='vcSpeechSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='vcSpeechLabel' " "type='SmallLabel' " @@ -1378,6 +1866,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='mcMidiGainSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='mcMidiGainLabel' " "width='32' " @@ -2080,7 +2569,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "height='Globals.Button.Height' " "/>" "<space size='10'/>" -"<widget name='RTL' " +"<widget name='ReturnToLauncher' " "width='150' " "height='Globals.Button.Height' " "/>" @@ -2129,6 +2618,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='vcMusicSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='vcMusicLabel' " "type='SmallLabel' " @@ -2140,6 +2630,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='vcSfxSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='vcSfxLabel' " "type='SmallLabel' " @@ -2151,6 +2642,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='vcSpeechSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='vcSpeechLabel' " "type='SmallLabel' " @@ -2187,6 +2679,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='subSubtitleSpeedSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='subSubtitleSpeedLabel' " "type='SmallLabel' " @@ -2232,6 +2725,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='VoiceCountSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='VoiceCountLabel' " "width='32' " @@ -2244,6 +2738,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='LevelSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='LevelLabel' " "width='32' " @@ -2256,6 +2751,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='SpeedSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='SpeedLabel' " "width='32' " @@ -2268,6 +2764,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='DepthSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='DepthLabel' " "width='32' " @@ -2295,6 +2792,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='RoomSizeSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='RoomSizeLabel' " "width='32' " @@ -2307,6 +2805,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='DampingSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='DampingLabel' " "width='32' " @@ -2319,6 +2818,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='WidthSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='WidthLabel' " "width='32' " @@ -2331,6 +2831,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='LevelSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='LevelLabel' " "width='32' " @@ -2805,7 +3306,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='OptionsLabel' " "size='110,Globals.Line.Height' " -"textalign='right' " +"textalign='end' " "/>" "<widget name='SmallLabel' " "size='18,Globals.Line.Height' " @@ -2868,7 +3369,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<widget name='SearchDesc' " "width='50' " "height='Globals.Line.Height' " -"textalign='right' " +"textalign='end' " "/>" "<widget name='Search' " "width='150' " @@ -2995,6 +3496,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='grKbdMouseSpeedSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='grKbdMouseSpeedLabel' " "type='SmallLabel' " @@ -3006,6 +3508,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='grJoystickDeadzoneSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='grJoystickDeadzoneLabel' " "type='SmallLabel' " @@ -3125,6 +3628,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='subSubtitleSpeedSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='subSubtitleSpeedLabel' " "type='SmallLabel' " @@ -3140,6 +3644,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='vcMusicSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='vcMusicLabel' " "type='SmallLabel' " @@ -3151,6 +3656,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='vcSfxSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='vcSfxLabel' " "type='SmallLabel' " @@ -3162,6 +3668,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='vcSpeechSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='vcSpeechLabel' " "type='SmallLabel' " @@ -3206,6 +3713,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='mcMidiGainSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='mcMidiGainLabel' " "width='32' " @@ -3307,7 +3815,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<widget name='RendererPopupDesc' " "width='80' " "height='Globals.Line.Height' " -"textalign='right' " +"textalign='end' " "/>" "<widget name='RendererPopup' " "type='PopUp' " @@ -3317,7 +3825,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<widget name='AutosavePeriodPopupDesc' " "width='80' " "height='Globals.Line.Height' " -"textalign='right' " +"textalign='end' " "/>" "<widget name='AutosavePeriodPopup' " "type='PopUp' " @@ -3327,7 +3835,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<widget name='GuiLanguagePopupDesc' " "width='80' " "height='Globals.Line.Height' " -"textalign='right' " +"textalign='end' " "/>" "<widget name='GuiLanguagePopup' " "type='PopUp' " @@ -3347,7 +3855,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<widget name='UpdatesPopupDesc' " "width='80' " "height='Globals.Line.Height' " -"textalign='right' " +"textalign='end' " "/>" "<widget name='UpdatesPopup' " "type='PopUp' " @@ -3373,7 +3881,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<widget name='StoragePopupDesc' " "width='100' " "height='Globals.Line.Height' " -"textalign='right' " +"textalign='end' " "/>" "</layout>" "<layout type='vertical' padding='0,0,0,0' spacing='1'>" @@ -3523,7 +4031,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<widget name='ServerPortDesc' " "width='80' " "height='Globals.Line.Height' " -"textalign='right' " +"textalign='end' " "/>" "<widget name='ServerPortEditText' " "width='60' " @@ -3781,7 +4289,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<widget name='Id' " "width='35' " "height='Globals.Line.Height' " -"textalign='right' " +"textalign='end' " "/>" "<widget name='Domain' " "type='PopUp' " @@ -3791,7 +4299,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<widget name='Name' " "width='35' " "height='Globals.Line.Height' " -"textalign='right' " +"textalign='end' " "/>" "<widget name='Desc' " "type='PopUp' " @@ -3802,7 +4310,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<widget name='LangPopupDesc' " "width='60' " "height='Globals.Line.Height' " -"textalign='right' " +"textalign='end' " "/>" "<widget name='LangPopup' " "type='PopUp' " @@ -3812,7 +4320,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "<widget name='PlatformPopupDesc' " "width='60' " "height='Globals.Line.Height' " -"textalign='right' " +"textalign='end' " "/>" "<widget name='PlatformPopup' " "type='PopUp' " @@ -3923,7 +4431,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "width='120' " "height='12' " "/>" -"<widget name='RTL' " +"<widget name='ReturnToLauncher' " "width='120' " "height='12' " "/>" @@ -3971,6 +4479,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='vcMusicSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='vcMusicLabel' " "type='SmallLabel' " @@ -3982,6 +4491,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='vcSfxSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='vcSfxLabel' " "type='SmallLabel' " @@ -3993,6 +4503,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='vcSpeechSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='vcSpeechLabel' " "type='SmallLabel' " @@ -4030,6 +4541,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='subSubtitleSpeedSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='subSubtitleSpeedLabel' " "type='SmallLabel' " @@ -4075,6 +4587,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='VoiceCountSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='VoiceCountLabel' " "width='32' " @@ -4087,6 +4600,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='LevelSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='LevelLabel' " "width='32' " @@ -4099,6 +4613,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='SpeedSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='SpeedLabel' " "width='32' " @@ -4111,6 +4626,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='DepthSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='DepthLabel' " "width='32' " @@ -4138,6 +4654,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='RoomSizeSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='RoomSizeLabel' " "width='32' " @@ -4150,6 +4667,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='DampingSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='DampingLabel' " "width='32' " @@ -4162,6 +4680,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='WidthSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='WidthLabel' " "width='32' " @@ -4174,6 +4693,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "<widget name='LevelSlider' " "type='Slider' " +"rtl='no' " "/>" "<widget name='LevelLabel' " "width='32' " diff --git a/gui/themes/modern.zip b/gui/themes/modern.zip index 5f44fcc4376..306dbd3c801 100644 Binary files a/gui/themes/modern.zip and b/gui/themes/modern.zip differ diff --git a/gui/themes/modern/THEMERC b/gui/themes/modern/THEMERC index a11cd4d82b8..390a9a54e04 100644 --- a/gui/themes/modern/THEMERC +++ b/gui/themes/modern/THEMERC @@ -1 +1 @@ -[SCUMMVM_STX0.8.36:ResidualVM Modern Theme:No Author] +[SCUMMVM_STX0.8.38:ResidualVM Modern Theme:No Author] diff --git a/gui/themes/modern/modern_gfx.stx b/gui/themes/modern/modern_gfx.stx index ed4b5172bff..49c3af20d6b 100644 --- a/gui/themes/modern/modern_gfx.stx +++ b/gui/themes/modern/modern_gfx.stx @@ -523,7 +523,45 @@ <text font = 'text_default' text_color = 'color_normal' vertical_align = 'center' - horizontal_align = 'left' + horizontal_align = 'start' + /> + </drawdata> + <drawdata id = 'popup_idle_rtl' cache = 'false' resolution = 'y>399'> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fg_color = 'lightgray2' + fill = 'background' + bg_color = 'xtrabrightred' + shadow = '1' + /> + + <drawstep func = 'triangle' + bg_color = 'shadowcolor' + fill = 'background' + width = '10' + height = '5' + xpos = 'left' + ypos = '10' + padding = '2, 0, 6, 0' + orientation = 'bottom' + /> + + <drawstep func = 'triangle' + bg_color = 'shadowcolor' + fill = 'background' + width = '10' + height = '5' + xpos = 'left' + ypos = '4' + padding = '2, 0, 6, 0' + orientation = 'top' + /> + + <text font = 'text_default' + text_color = 'color_normal' + vertical_align = 'center' + horizontal_align = 'start' /> </drawdata> @@ -562,7 +600,45 @@ <text font = 'text_default' text_color = 'color_normal' vertical_align = 'center' - horizontal_align = 'left' + horizontal_align = 'start' + /> + </drawdata> + <drawdata id = 'popup_idle_rtl' cache = 'false' resolution ='y<400'> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fg_color = 'lightgray2' + fill = 'background' + bg_color = 'xtrabrightred' + shadow = '1' + /> + + <drawstep func = 'triangle' + bg_color = 'shadowcolor' + fill = 'background' + width = '7' + height = '4' + xpos = 'left' + ypos = '9' + padding = '2, 0, 3, 0' + orientation = 'bottom' + /> + + <drawstep func = 'triangle' + bg_color = 'shadowcolor' + fill = 'background' + width = '7' + height = '4' + xpos = 'left' + ypos = '4' + padding = '2, 0, 3, 0' + orientation = 'top' + /> + + <text font = 'text_default' + text_color = 'color_normal' + vertical_align = 'center' + horizontal_align = 'start' /> </drawdata> @@ -602,7 +678,45 @@ <text font = 'text_default' text_color = 'color_normal_hover' vertical_align = 'center' - horizontal_align = 'left' + horizontal_align = 'start' + /> + </drawdata> + <drawdata id = 'popup_disabled_rtl' cache = 'false' resolution = 'y>399'> + <drawstep func = 'roundedsq' + stroke = '1' + fg_color = 'lightgray' + radius = '5' + fill = 'gradient' + gradient_start = 'blandyellow' + gradient_end = 'xtrabrightred' + shadow = '0' + /> + <drawstep func = 'triangle' + bg_color = 'shadowcolor' + fill = 'background' + width = '10' + height = '5' + xpos = 'left' + ypos = '10' + padding = '2, 0, 6, 0' + orientation = 'bottom' + /> + + <drawstep func = 'triangle' + bg_color = 'shadowcolor' + fill = 'background' + width = '10' + height = '5' + xpos = 'left' + ypos = '4' + padding = '2, 0, 6, 0' + orientation = 'top' + /> + + <text font = 'text_default' + text_color = 'color_normal_hover' + vertical_align = 'center' + horizontal_align = 'start' /> </drawdata> @@ -641,7 +755,45 @@ <text font = 'text_default' text_color = 'color_normal' vertical_align = 'center' - horizontal_align = 'left' + horizontal_align = 'start' + /> + </drawdata> + <drawdata id = 'popup_disabled_rtl' cache = 'false' resolution = 'y<400'> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fg_color = 'lightgray2' + fill = 'background' + bg_color = 'xtrabrightred' + shadow = '2' + /> + + <drawstep func = 'triangle' + bg_color = 'shadowcolor' + fill = 'background' + width = '7' + height = '4' + xpos = 'left' + ypos = '9' + padding = '2, 0, 3, 0' + orientation = 'bottom' + /> + + <drawstep func = 'triangle' + bg_color = 'shadowcolor' + fill = 'background' + width = '7' + height = '4' + xpos = 'left' + ypos = '4' + padding = '2, 0, 3, 0' + orientation = 'top' + /> + + <text font = 'text_default' + text_color = 'color_normal' + vertical_align = 'center' + horizontal_align = 'start' /> </drawdata> @@ -681,7 +833,45 @@ <text font = 'text_default' text_color = 'color_normal_hover' vertical_align = 'center' - horizontal_align = 'left' + horizontal_align = 'start' + /> + </drawdata> + <drawdata id = 'popup_hover_rtl' cache = 'false' resolution = 'y>399'> + <drawstep func = 'roundedsq' + stroke = '1' + fg_color = 'lightgray' + radius = '5' + fill = 'gradient' + gradient_start = 'blandyellow' + gradient_end = 'xtrabrightred' + shadow = '0' + /> + <drawstep func = 'triangle' + bg_color = 'shadowcolor' + fill = 'background' + width = '10' + height = '5' + xpos = 'left' + ypos = '10' + padding = '2, 0, 6, 0' + orientation = 'bottom' + /> + + <drawstep func = 'triangle' + bg_color = 'shadowcolor' + fill = 'background' + width = '10' + height = '5' + xpos = 'left' + ypos = '4' + padding = '2, 0, 6, 0' + orientation = 'top' + /> + + <text font = 'text_default' + text_color = 'color_normal_hover' + vertical_align = 'center' + horizontal_align = 'start' /> </drawdata> @@ -720,7 +910,45 @@ <text font = 'text_default' text_color = 'color_normal' vertical_align = 'center' - horizontal_align = 'left' + horizontal_align = 'start' + /> + </drawdata> + <drawdata id = 'popup_hover_rtl' cache = 'false' resolution = 'y<400'> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fg_color = 'lightgray2' + fill = 'background' + bg_color = 'xtrabrightred' + shadow = '1' + /> + + <drawstep func = 'triangle' + bg_color = 'shadowcolor' + fill = 'background' + width = '7' + height = '4' + xpos = 'left' + ypos = '9' + padding = '2, 0, 3, 0' + orientation = 'bottom' + /> + + <drawstep func = 'triangle' + bg_color = 'shadowcolor' + fill = 'background' + width = '7' + height = '4' + xpos = 'left' + ypos = '4' + padding = '2, 0, 3, 0' + orientation = 'top' + /> + + <text font = 'text_default' + text_color = 'color_normal' + vertical_align = 'center' + horizontal_align = 'start' /> </drawdata> @@ -889,6 +1117,34 @@ orientation = 'bottom' /> </drawdata> + <drawdata id = 'dropdown_button_idle_rtl' cache = 'false' resolution = 'y>399'> + <text font = 'text_button' + text_color = 'color_button' + vertical_align = 'center' + horizontal_align = 'center' + /> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fill = 'gradient' + shadow = '0' + fg_color = 'darkredborder' + gradient_start = 'brightred' + gradient_end = 'darkred' + bevel = '1' + bevel_color = 'brightredborder' + /> + <drawstep func = 'triangle' + fg_color = 'white' + fill = 'foreground' + width = '8' + height = '6' + xpos = 'left' + ypos = 'center' + padding = '2,0,2,0' + orientation = 'bottom' + /> + </drawdata> <drawdata id = 'dropdown_button_idle' cache = 'false' resolution = 'y<400'> <text font = 'text_button' text_color = 'color_button' @@ -917,6 +1173,34 @@ orientation = 'bottom' /> </drawdata> + <drawdata id = 'dropdown_button_idle_rtl' cache = 'false' resolution = 'y<400'> + <text font = 'text_button' + text_color = 'color_button' + vertical_align = 'center' + horizontal_align = 'center' + /> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fill = 'gradient' + shadow = '0' + fg_color = 'darkredborder' + gradient_start = 'brightred' + gradient_end = 'darkred' + bevel = '1' + bevel_color = 'brightredborder' + /> + <drawstep func = 'triangle' + fg_color = 'white' + fill = 'foreground' + width = '6' + height = '6' + xpos = 'left' + ypos = 'center' + padding = '0,0,0,0' + orientation = 'bottom' + /> + </drawdata> <drawdata id = 'dropdown_button_hover_left' cache = 'false' resolution = 'y>399'> <text font = 'text_button' @@ -947,6 +1231,35 @@ orientation = 'bottom' /> </drawdata> + <drawdata id = 'dropdown_button_hover_left_rtl' cache = 'false' resolution = 'y>399'> + <text font = 'text_button' + text_color = 'color_button' + vertical_align = 'center' + horizontal_align = 'center' + /> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fill = 'gradient' + shadow = '0' + fg_color = 'darkredborder' + gradient_start = 'brightpink' + gradient_end = 'darkpink' + bevel = '1' + bevel_color = 'brightredborder' + clip = '13,0,0,0' + /> + <drawstep func = 'triangle' + fg_color = 'white' + fill = 'foreground' + width = '8' + height = '6' + xpos = 'left' + ypos = 'center' + padding = '2,0,2,0' + orientation = 'bottom' + /> + </drawdata> <drawdata id = 'dropdown_button_hover_left' cache = 'false' resolution = 'y<400'> <text font = 'text_button' text_color = 'color_button' @@ -976,6 +1289,35 @@ orientation = 'bottom' /> </drawdata> + <drawdata id = 'dropdown_button_hover_left_rtl' cache = 'false' resolution = 'y<400'> + <text font = 'text_button' + text_color = 'color_button' + vertical_align = 'center' + horizontal_align = 'center' + /> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fill = 'gradient' + shadow = '0' + fg_color = 'darkredborder' + gradient_start = 'brightpink' + gradient_end = 'darkpink' + bevel = '1' + bevel_color = 'brightredborder' + clip = '7,0,0,0' + /> + <drawstep func = 'triangle' + fg_color = 'white' + fill = 'foreground' + width = '6' + height = '6' + xpos = 'left' + ypos = 'center' + padding = '0,0,0,0' + orientation = 'bottom' + /> + </drawdata> <drawdata id = 'dropdown_button_hover_right' cache = 'false' resolution = 'y>399'> <text font = 'text_button' @@ -1006,6 +1348,35 @@ orientation = 'bottom' /> </drawdata> + <drawdata id = 'dropdown_button_hover_right_rtl' cache = 'false' resolution = 'y>399'> + <text font = 'text_button' + text_color = 'color_button' + vertical_align = 'center' + horizontal_align = 'center' + /> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fill = 'gradient' + shadow = '0' + fg_color = 'darkredborder' + gradient_start = 'brightpink' + gradient_end = 'darkpink' + bevel = '1' + bevel_color = 'brightredborder' + clip = '0,0,13,0' + /> + <drawstep func = 'triangle' + fg_color = 'white' + fill = 'foreground' + width = '8' + height = '6' + xpos = 'left' + ypos = 'center' + padding = '2,0,2,0' + orientation = 'bottom' + /> + </drawdata> <drawdata id = 'dropdown_button_hover_right' cache = 'false' resolution = 'y<400'> <text font = 'text_button' text_color = 'color_button' @@ -1035,6 +1406,35 @@ orientation = 'bottom' /> </drawdata> + <drawdata id = 'dropdown_button_hover_right_rtl' cache = 'false' resolution = 'y<400'> + <text font = 'text_button' + text_color = 'color_button' + vertical_align = 'center' + horizontal_align = 'center' + /> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fill = 'gradient' + shadow = '0' + fg_color = 'darkredborder' + gradient_start = 'brightpink' + gradient_end = 'darkpink' + bevel = '1' + bevel_color = 'brightredborder' + clip = '0,0,7,0' + /> + <drawstep func = 'triangle' + fg_color = 'white' + fill = 'foreground' + width = '6' + height = '6' + xpos = 'left' + ypos = 'center' + padding = '0,0,0,0' + orientation = 'bottom' + /> + </drawdata> <drawdata id = 'dropdown_button_disabled' cache = 'false' resolution = 'y>399'> <text font = 'text_button' @@ -1064,6 +1464,34 @@ orientation = 'bottom' /> </drawdata> + <drawdata id = 'dropdown_button_disabled_rtl' cache = 'false' resolution = 'y>399'> + <text font = 'text_button' + text_color = 'color_button_disabled' + vertical_align = 'center' + horizontal_align = 'center' + /> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fill = 'gradient' + shadow = '0' + fg_color = 'shadowcolor' + gradient_start = 'darkenedbrightred' + gradient_end = 'darkeneddarkred' + bevel = '1' + bevel_color = 'darkgray' + /> + <drawstep func = 'triangle' + fg_color = 'darkgray2' + fill = 'foreground' + width = '8' + height = '6' + xpos = 'left' + ypos = 'center' + padding = '2,0,2,0' + orientation = 'bottom' + /> + </drawdata> <drawdata id = 'dropdown_button_disabled' cache = 'false' resolution = 'y<400'> <text font = 'text_button' text_color = 'color_button_disabled' @@ -1092,6 +1520,34 @@ orientation = 'bottom' /> </drawdata> + <drawdata id = 'dropdown_button_disabled_rtl' cache = 'false' resolution = 'y<400'> + <text font = 'text_button' + text_color = 'color_button_disabled' + vertical_align = 'center' + horizontal_align = 'center' + /> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fill = 'gradient' + shadow = '0' + fg_color = 'shadowcolor' + gradient_start = 'darkenedbrightred' + gradient_end = 'darkeneddarkred' + bevel = '1' + bevel_color = 'darkgray' + /> + <drawstep func = 'triangle' + fg_color = 'darkgray2' + fill = 'foreground' + width = '6' + height = '6' + xpos = 'left' + ypos = 'center' + padding = '0,0,0,0' + orientation = 'bottom' + /> + </drawdata> <drawdata id = 'dropdown_button_pressed_left' cache = 'false' resolution = 'y>399'> <text font = 'text_button' @@ -1123,6 +1579,36 @@ orientation = 'bottom' /> </drawdata> + <drawdata id = 'dropdown_button_pressed_left_rtl' cache = 'false' resolution = 'y>399'> + <text font = 'text_button' + text_color = 'color_button' + vertical_align = 'center' + horizontal_align = 'center' + /> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fill = 'foreground' + shadow = '0' + factor = '0' + fg_color = '40, 120, 16' + gradient_start = '0, 255, 0' + gradient_end = '0, 255, 0' + bevel = '1' + bevel_color = 'black' + clip = '13,0,0,0' + /> + <drawstep func = 'triangle' + fg_color = 'white' + fill = 'foreground' + width = '8' + height = '6' + xpos = 'left' + ypos = 'center' + padding = '2,0,2,0' + orientation = 'bottom' + /> + </drawdata> <drawdata id = 'dropdown_button_pressed_left' cache = 'false' resolution = 'y<400'> <text font = 'text_button' text_color = 'color_button' @@ -1153,6 +1639,36 @@ orientation = 'bottom' /> </drawdata> + <drawdata id = 'dropdown_button_pressed_left_rtl' cache = 'false' resolution = 'y<400'> + <text font = 'text_button' + text_color = 'color_button' + vertical_align = 'center' + horizontal_align = 'center' + /> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fill = 'foreground' + shadow = '0' + factor = '0' + fg_color = '40, 120, 16' + gradient_start = '0, 255, 0' + gradient_end = '0, 255, 0' + bevel = '1' + bevel_color = 'black' + clip = '7,0,0,0' + /> + <drawstep func = 'triangle' + fg_color = 'white' + fill = 'foreground' + width = '6' + height = '6' + xpos = 'left' + ypos = 'center' + padding = '0,0,0,0' + orientation = 'bottom' + /> + </drawdata> <drawdata id = 'dropdown_button_pressed_right' cache = 'false' resolution = 'y>399'> <text font = 'text_button' @@ -1184,6 +1700,36 @@ orientation = 'bottom' /> </drawdata> + <drawdata id = 'dropdown_button_pressed_right_rtl' cache = 'false' resolution = 'y>399'> + <text font = 'text_button' + text_color = 'color_button' + vertical_align = 'center' + horizontal_align = 'center' + /> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fill = 'foreground' + shadow = '0' + factor = '0' + fg_color = '40, 120, 16' + gradient_start = '0, 255, 0' + gradient_end = '0, 255, 0' + bevel = '1' + bevel_color = 'black' + clip = '0,0,13,0' + /> + <drawstep func = 'triangle' + fg_color = 'white' + fill = 'foreground' + width = '8' + height = '6' + xpos = 'left' + ypos = 'center' + padding = '2,0,2,0' + orientation = 'bottom' + /> + </drawdata> <drawdata id = 'dropdown_button_pressed_right' cache = 'false' resolution = 'y<400'> <text font = 'text_button' text_color = 'color_button' @@ -1210,6 +1756,36 @@ height = '6' xpos = 'right' ypos = 'center' + padding = '2,0,0,0' + orientation = 'bottom' + /> + </drawdata> + <drawdata id = 'dropdown_button_pressed_right_rtl' cache = 'false' resolution = 'y<400'> + <text font = 'text_button' + text_color = 'color_button' + vertical_align = 'center' + horizontal_align = 'center' + /> + <drawstep func = 'roundedsq' + radius = '5' + stroke = '1' + fill = 'foreground' + shadow = '0' + factor = '0' + fg_color = '40, 120, 16' + gradient_start = '0, 255, 0' + gradient_end = '0, 255, 0' + bevel = '1' + bevel_color = 'black' + clip = '0,0,7,0' + /> + <drawstep func = 'triangle' + fg_color = 'white' + fill = 'foreground' + width = '6' + height = '6' + xpos = 'left' + ypos = 'center' padding = '0,0,0,0' orientation = 'bottom' /> @@ -1220,7 +1796,7 @@ <text font = 'text_default' text_color = 'color_normal_disabled' vertical_align = 'top' - horizontal_align = 'left' + horizontal_align = 'start' /> <drawstep func = 'bitmap' file = 'checkbox_disabled.bmp' @@ -1232,7 +1808,7 @@ <text font = 'text_default' text_color = 'color_normal_disabled' vertical_align = 'top' - horizontal_align = 'left' + horizontal_align = 'start' /> <drawstep func = 'bitmap' file = 'checkbox_empty.bmp' @@ -1244,7 +1820,7 @@ <text font = 'text_default' text_color = 'color_normal' vertical_align = 'top' - horizontal_align = 'left' + horizontal_align = 'start' /> <drawstep func = 'bitmap' file = 'checkbox.bmp' @@ -1256,7 +1832,7 @@ <text font = 'text_default' text_color = 'color_normal' vertical_align = 'top' - horizontal_align = 'left' + horizontal_align = 'start' /> <drawstep func = 'bitmap' file = 'checkbox_empty.bmp' @@ -1268,7 +1844,7 @@ <text font = 'text_default' text_color = 'color_normal' vertical_align = 'center' - horizontal_align = 'left' + horizontal_align = 'start' /> <drawstep func = 'bitmap' file = 'radiobutton_empty.bmp' @@ -1280,7 +1856,7 @@ <text font = 'text_default' text_color = 'color_normal' vertical_align = 'center' - horizontal_align = 'left' + horizontal_align = 'start' /> <drawstep func = 'bitmap' file = 'radiobutton.bmp' @@ -1292,7 +1868,7 @@ <text font = 'text_default' text_color = 'color_normal_disabled' vertical_align = 'center' - horizontal_align = 'left' + horizontal_align = 'start' /> <drawstep func = 'bitmap' file = 'radiobutton_empty.bmp' diff --git a/gui/themes/modern/modern_layout.stx b/gui/themes/modern/modern_layout.stx index 34eb5206d2b..dcd3b1efb9e 100644 --- a/gui/themes/modern/modern_layout.stx +++ b/gui/themes/modern/modern_layout.stx @@ -62,7 +62,7 @@ <widget name = 'OptionsLabel' size = '115, Globals.Line.Height' - textalign = 'right' + textalign = 'end' /> <widget name = 'SmallLabel' size = '24, Globals.Line.Height' @@ -135,11 +135,13 @@ <widget name = 'Logo' width = '287' height = '80' + rtl = 'no' /> <layout type = 'horizontal' spacing = '5' padding = '10, 0, 0, 0'> <widget name = 'SearchPic' width = '16' height = '17' + rtl = 'no' /> <widget name = 'Search' width = '150' @@ -280,6 +282,7 @@ /> <widget name = 'grKbdMouseSpeedSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'grKbdMouseSpeedLabel' type = 'SmallLabel' @@ -291,6 +294,7 @@ /> <widget name = 'grJoystickDeadzoneSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'grJoystickDeadzoneLabel' type = 'SmallLabel' @@ -422,6 +426,7 @@ /> <widget name = 'subSubtitleSpeedSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'subSubtitleSpeedLabel' type = 'SmallLabel' @@ -439,6 +444,7 @@ /> <widget name = 'vcMusicSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'vcMusicLabel' type = 'SmallLabel' @@ -450,6 +456,7 @@ /> <widget name = 'vcSfxSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'vcSfxLabel' type = 'SmallLabel' @@ -461,6 +468,7 @@ /> <widget name = 'vcSpeechSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'vcSpeechLabel' type = 'SmallLabel' @@ -506,6 +514,7 @@ /> <widget name = 'mcMidiGainSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'mcMidiGainLabel' width = '32' @@ -1235,7 +1244,7 @@ height = 'Globals.Button.Height' /> <space size = '10'/> - <widget name = 'RTL' + <widget name = 'ReturnToLauncher' width = '150' height = 'Globals.Button.Height' /> @@ -1288,6 +1297,7 @@ /> <widget name = 'vcMusicSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'vcMusicLabel' type = 'SmallLabel' @@ -1299,6 +1309,7 @@ /> <widget name = 'vcSfxSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'vcSfxLabel' type = 'SmallLabel' @@ -1310,6 +1321,7 @@ /> <widget name = 'vcSpeechSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'vcSpeechLabel' type = 'SmallLabel' @@ -1347,6 +1359,7 @@ /> <widget name = 'subSubtitleSpeedSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'subSubtitleSpeedLabel' type = 'SmallLabel' @@ -1396,6 +1409,7 @@ /> <widget name = 'VoiceCountSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'VoiceCountLabel' width = '32' @@ -1408,6 +1422,7 @@ /> <widget name = 'LevelSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'LevelLabel' width = '32' @@ -1420,6 +1435,7 @@ /> <widget name = 'SpeedSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'SpeedLabel' width = '32' @@ -1432,6 +1448,7 @@ /> <widget name = 'DepthSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'DepthLabel' width = '32' @@ -1460,6 +1477,7 @@ /> <widget name = 'RoomSizeSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'RoomSizeLabel' width = '32' @@ -1472,6 +1490,7 @@ /> <widget name = 'DampingSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'DampingLabel' width = '32' @@ -1484,6 +1503,7 @@ /> <widget name = 'WidthSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'WidthLabel' width = '32' @@ -1496,6 +1516,7 @@ /> <widget name = 'LevelSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'LevelLabel' width = '32' diff --git a/gui/themes/modern/modern_layout_lowres.stx b/gui/themes/modern/modern_layout_lowres.stx index 153da29e157..3b8d8cd0328 100644 --- a/gui/themes/modern/modern_layout_lowres.stx +++ b/gui/themes/modern/modern_layout_lowres.stx @@ -66,7 +66,7 @@ <widget name = 'OptionsLabel' size = '100, Globals.Line.Height' - textalign = 'right' + textalign = 'end' /> <widget name = 'SmallLabel' size = '18, Globals.Line.Height' @@ -130,7 +130,7 @@ <widget name = 'SearchDesc' width = '50' height = 'Globals.Line.Height' - textalign = 'right' + textalign = 'end' /> <widget name = 'Search' width = '150' @@ -261,6 +261,7 @@ /> <widget name = 'grKbdMouseSpeedSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'grKbdMouseSpeedLabel' type = 'SmallLabel' @@ -272,6 +273,7 @@ /> <widget name = 'grJoystickDeadzoneSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'grJoystickDeadzoneLabel' type = 'SmallLabel' @@ -403,6 +405,7 @@ /> <widget name = 'subSubtitleSpeedSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'subSubtitleSpeedLabel' type = 'SmallLabel' @@ -419,6 +422,7 @@ /> <widget name = 'vcMusicSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'vcMusicLabel' type = 'SmallLabel' @@ -430,6 +434,7 @@ /> <widget name = 'vcSfxSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'vcSfxLabel' type = 'SmallLabel' @@ -441,6 +446,7 @@ /> <widget name = 'vcSpeechSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'vcSpeechLabel' type = 'SmallLabel' @@ -486,6 +492,7 @@ /> <widget name = 'mcMidiGainSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'mcMidiGainLabel' width = '32' @@ -591,7 +598,7 @@ <widget name = 'RendererPopupDesc' width = '80' height = 'Globals.Line.Height' - textalign = 'right' + textalign = 'end' /> <widget name = 'RendererPopup' type = 'PopUp' @@ -601,7 +608,7 @@ <widget name = 'AutosavePeriodPopupDesc' width = '80' height = 'Globals.Line.Height' - textalign = 'right' + textalign = 'end' /> <widget name = 'AutosavePeriodPopup' type = 'PopUp' @@ -611,7 +618,7 @@ <widget name = 'GuiLanguagePopupDesc' width = '80' height = 'Globals.Line.Height' - textalign = 'right' + textalign = 'end' /> <widget name = 'GuiLanguagePopup' type = 'PopUp' @@ -631,7 +638,7 @@ <widget name = 'UpdatesPopupDesc' width = '80' height = 'Globals.Line.Height' - textalign = 'right' + textalign = 'end' /> <widget name = 'UpdatesPopup' type = 'PopUp' @@ -659,7 +666,7 @@ <widget name = 'StoragePopupDesc' width = '80' height = 'Globals.Line.Height' - textalign = 'right' + textalign = 'end' /> </layout> <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '1'> @@ -812,7 +819,7 @@ <widget name = 'ServerPortDesc' width = '80' height = 'Globals.Line.Height' - textalign = 'right' + textalign = 'end' /> <widget name = 'ServerPortEditText' width = '60' @@ -1085,7 +1092,7 @@ <widget name = 'Id' width = '35' height = 'Globals.Line.Height' - textalign = 'right' + textalign = 'end' /> <widget name = 'Domain' type = 'PopUp' @@ -1095,7 +1102,7 @@ <widget name = 'Name' width = '35' height = 'Globals.Line.Height' - textalign = 'right' + textalign = 'end' /> <widget name = 'Desc' type = 'PopUp' @@ -1106,7 +1113,7 @@ <widget name = 'LangPopupDesc' width = '60' height = 'Globals.Line.Height' - textalign = 'right' + textalign = 'end' /> <widget name = 'LangPopup' type = 'PopUp' @@ -1116,7 +1123,7 @@ <widget name = 'PlatformPopupDesc' width = '60' height = 'Globals.Line.Height' - textalign = 'right' + textalign = 'end' /> <widget name = 'PlatformPopup' type = 'PopUp' @@ -1231,7 +1238,7 @@ width = '120' height = 'Globals.Button.Height' /> - <widget name = 'RTL' + <widget name = 'ReturnToLauncher' width = '120' height = 'Globals.Button.Height' /> @@ -1282,6 +1289,7 @@ /> <widget name = 'vcMusicSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'vcMusicLabel' type = 'SmallLabel' @@ -1293,6 +1301,7 @@ /> <widget name = 'vcSfxSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'vcSfxLabel' type = 'SmallLabel' @@ -1304,6 +1313,7 @@ /> <widget name = 'vcSpeechSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'vcSpeechLabel' type = 'SmallLabel' @@ -1343,6 +1353,7 @@ /> <widget name = 'subSubtitleSpeedSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'subSubtitleSpeedLabel' type = 'SmallLabel' @@ -1392,6 +1403,7 @@ /> <widget name = 'VoiceCountSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'VoiceCountLabel' width = '32' @@ -1404,6 +1416,7 @@ /> <widget name = 'LevelSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'LevelLabel' width = '32' @@ -1416,6 +1429,7 @@ /> <widget name = 'SpeedSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'SpeedLabel' width = '32' @@ -1428,6 +1442,7 @@ /> <widget name = 'DepthSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'DepthLabel' width = '32' @@ -1456,6 +1471,7 @@ /> <widget name = 'RoomSizeSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'RoomSizeLabel' width = '32' @@ -1468,6 +1484,7 @@ /> <widget name = 'DampingSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'DampingLabel' width = '32' @@ -1480,6 +1497,7 @@ /> <widget name = 'WidthSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'WidthLabel' width = '32' @@ -1492,6 +1510,7 @@ /> <widget name = 'LevelSlider' type = 'Slider' + rtl = 'no' /> <widget name = 'LevelLabel' width = '32' diff --git a/gui/widget.cpp b/gui/widget.cpp index 327f498f424..43fcfb41fa4 100644 --- a/gui/widget.cpp +++ b/gui/widget.cpp @@ -113,6 +113,22 @@ void Widget::draw() { Common::Rect oldClip = g_gui.theme()->swapClipRect(_boss->getClipRect()); + if (g_gui.useRTL()) { + _x = g_system->getOverlayWidth() - _x - _w; + + if (this->_name.contains("GameOptions") || this->_name.contains("GlobalOptions") || this->_name.contains("Browser") || this->_name.empty()) { + /** The dialogs named above are the stacked dialogs for which the left+right paddings need to be adjusted for RTL. + The _name is empty for some special widgets - like RemapWidgets, NavBars, ScrollBars and they need to be adjusted too. + */ + _x = _x + g_gui.getOverlayOffset(); + } + + Common::Rect r = _boss->getClipRect(); + r.moveTo(_x, r.top); + + g_gui.theme()->swapClipRect(r); + } + // Draw border if (_flags & WIDGET_BORDER) { g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x + _w, _y + _h), @@ -210,6 +226,10 @@ bool Widget::isVisible() const { return !(_flags & WIDGET_INVISIBLE); } +bool Widget::useRTL() const { + return _useRTL; +} + uint8 Widget::parseHotkey(const Common::String &label) { if (!label.contains('~')) return 0; @@ -272,11 +292,12 @@ void Widget::read(Common::String str) { #pragma mark - StaticTextWidget::StaticTextWidget(GuiObject *boss, int x, int y, int w, int h, const Common::String &text, Graphics::TextAlign align, const char *tooltip, ThemeEngine::FontStyle font) - : Widget(boss, x, y, w, h, tooltip), _align(align) { + : Widget(boss, x, y, w, h, tooltip) { setFlags(WIDGET_ENABLED); _type = kStaticTextWidget; _label = text; _font = font; + _align = Graphics::convertTextAlignH(align, g_gui.useRTL() && _useRTL); } StaticTextWidget::StaticTextWidget(GuiObject *boss, const Common::String &name, const Common::String &text, const char *tooltip, ThemeEngine::FontStyle font) @@ -285,7 +306,8 @@ StaticTextWidget::StaticTextWidget(GuiObject *boss, const Common::String &name, _type = kStaticTextWidget; _label = text; - _align = g_gui.xmlEval()->getWidgetTextHAlign(name); + _align = Graphics::convertTextAlignH(g_gui.xmlEval()->getWidgetTextHAlign(name), g_gui.useRTL() && _useRTL); + _font = font; } @@ -302,6 +324,7 @@ void StaticTextWidget::setLabel(const Common::String &label) { } void StaticTextWidget::setAlign(Graphics::TextAlign align) { + align = Graphics::convertTextAlignH(align, g_gui.useRTL() && _useRTL); if (_align != align){ _align = align; @@ -506,7 +529,7 @@ void DropdownButtonWidget::drawWidget() { g_gui.theme()->drawButton(Common::Rect(_x, _y, _x + _w, _y + _h), _label, _state); } else { g_gui.theme()->drawDropDownButton(Common::Rect(_x, _y, _x + _w, _y + _h), _dropdownWidth, _label, - _state, _inButton, _inDropdown); + _state, _inButton, _inDropdown, (g_gui.useRTL() && _useRTL)); } } @@ -623,7 +646,7 @@ void CheckboxWidget::setState(bool state) { } void CheckboxWidget::drawWidget() { - g_gui.theme()->drawCheckbox(Common::Rect(_x, _y, _x + _w, _y + _h), _label, _state, Widget::_state); + g_gui.theme()->drawCheckbox(Common::Rect(_x, _y, _x + _w, _y + _h), _label, _state, Widget::_state, (g_gui.useRTL() && _useRTL)); } #pragma mark - @@ -692,7 +715,7 @@ void RadiobuttonWidget::setState(bool state, bool setGroup) { } void RadiobuttonWidget::drawWidget() { - g_gui.theme()->drawRadiobutton(Common::Rect(_x, _y, _x + _w, _y + _h), _label, _state, Widget::_state); + g_gui.theme()->drawRadiobutton(Common::Rect(_x, _y, _x + _w, _y + _h), _label, _state, Widget::_state, (g_gui.useRTL() && _useRTL)); } #pragma mark - @@ -712,6 +735,9 @@ SliderWidget::SliderWidget(GuiObject *boss, const Common::String &name, const ch } void SliderWidget::handleMouseMoved(int x, int y, int button) { + if (g_gui.useRTL() && _useRTL == false) { + x = _w - x; // If internal flipping is off, adjust the mouse to behave as if it were LTR. + } if (isEnabled() && _isDragging) { int newValue = posToValue(x); if (newValue < _valueMin) @@ -760,7 +786,8 @@ void SliderWidget::handleMouseWheel(int x, int y, int direction) { } void SliderWidget::drawWidget() { - g_gui.theme()->drawSlider(Common::Rect(_x, _y, _x + _w, _y + _h), valueToBarWidth(_value), _state); + Common::Rect r1(_x, _y, _x + _w, _y + _h); + g_gui.theme()->drawSlider(r1, valueToBarWidth(_value), _state, (g_gui.useRTL() && _useRTL)); } int SliderWidget::valueToBarWidth(int value) { diff --git a/gui/widget.h b/gui/widget.h index 61e02fd227d..7a81017f7d9 100644 --- a/gui/widget.h +++ b/gui/widget.h @@ -164,6 +164,8 @@ public: void setVisible(bool e); bool isVisible() const override; + bool useRTL() const; + uint8 parseHotkey(const Common::String &label); Common::String cleanupHotkey(const Common::String &label); diff --git a/image/bmp.cpp b/image/bmp.cpp index d71e496f245..fd07ab89547 100644 --- a/image/bmp.cpp +++ b/image/bmp.cpp @@ -115,7 +115,7 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { } // Create the codec (it will warn about unhandled compression) - _codec = createBitmapCodec(compression, width, height, bitsPerPixel); + _codec = createBitmapCodec(compression, 0, width, height, bitsPerPixel); if (!_codec) return false; diff --git a/image/codecs/codec.cpp b/image/codecs/codec.cpp index 048d52dc86a..fdd7e98de48 100644 --- a/image/codecs/codec.cpp +++ b/image/codecs/codec.cpp @@ -32,6 +32,7 @@ #include "image/codecs/indeo3.h" #include "image/codecs/indeo4.h" #include "image/codecs/indeo5.h" +#include "image/codecs/jyv1.h" #include "image/codecs/mjpeg.h" #include "image/codecs/mpeg.h" #include "image/codecs/msvideo1.h" @@ -195,7 +196,14 @@ byte *Codec::createQuickTimeDitherTable(const byte *palette, uint colorCount) { return buf; } -Codec *createBitmapCodec(uint32 tag, int width, int height, int bitsPerPixel) { +Codec *createBitmapCodec(uint32 tag, uint32 streamTag, int width, int height, int bitsPerPixel) { + // Crusader videos are special cased here because the frame type is not in the "compression" + // tag but in the "stream handler" tag for these files + if (JYV1Decoder::isJYV1StreamTag(streamTag)) { + assert(bitsPerPixel == 8); + return new JYV1Decoder(width, height, streamTag); + } + switch (tag) { case SWAP_CONSTANT_32(0): return new BitmapRawDecoder(width, height, bitsPerPixel); diff --git a/image/codecs/codec.h b/image/codecs/codec.h index 5c072132d34..13267c2aef6 100644 --- a/image/codecs/codec.h +++ b/image/codecs/codec.h @@ -118,9 +118,9 @@ public: }; /** - * Create a codec given a bitmap/AVI compression tag. + * Create a codec given a bitmap/AVI compression tag and stream handler tag (can be 0) */ -Codec *createBitmapCodec(uint32 tag, int width, int height, int bitsPerPixel); +Codec *createBitmapCodec(uint32 tag, uint32 streamTag, int width, int height, int bitsPerPixel); /** * Create a codec given a QuickTime compression tag. diff --git a/image/codecs/jyv1.cpp b/image/codecs/jyv1.cpp new file mode 100644 index 00000000000..f459bc4355a --- /dev/null +++ b/image/codecs/jyv1.cpp @@ -0,0 +1,154 @@ +/* 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 "image/codecs/jyv1.h" + +#include "common/stream.h" +#include "common/bitstream.h" +#include "common/memstream.h" +#include "common/util.h" +#include "common/textconsole.h" +#include "common/system.h" +#include "common/debug.h" +#include "graphics/surface.h" + +#define ID_JYV1 MKTAG('J','Y','V','1') +#define ID_RRV1 MKTAG('R','R','V','1') +#define ID_RRV2 MKTAG('R','R','V','2') + +namespace Image { + +/*static*/ +bool JYV1Decoder::isJYV1StreamTag(uint32 streamTag) { + return (streamTag == ID_JYV1 || streamTag == ID_RRV1 || streamTag == ID_RRV2); +} + +JYV1Decoder::JYV1Decoder(int width, int height, uint32 streamTag) : Codec(), + _width(width), _height(height), _streamType(streamTag) { + assert(isJYV1StreamTag(streamTag)); + _surface.create(_width, _height, getPixelFormat()); +} + +JYV1Decoder::~JYV1Decoder() { + _surface.free(); +} + +static const uint32 BASE_LEN[] = {0, 1 << 7, 1 << 3, 0, 1 << 1, 0, 1 << 5, 0, + 1, 1 << 8, 1 << 4, 0, 1 << 2, 0, 1 << 6, 0}; +static const uint32 FINE_LEN_BITS[] = {0, 7, 3, 0, 1, 16, 5, 0, + 1, 8, 4, 0, 2, 24, 6, 0}; + +/** + * Details of this decoding algorithm are here: + * https://wiki.multimedia.cx/index.php/Origin_Flic_Codec + */ +const Graphics::Surface *JYV1Decoder::decodeFrame(Common::SeekableReadStream &stream) { + + byte *dst = (byte *)_surface.getPixels(); + + uint32 offsets[16]; // RRV2 has 15 block offsets, others have 5 + const int numOffsets = (_streamType == ID_RRV2 ? 15 : 5); + const int blockHeight = _height / numOffsets; + const int startOffset = stream.pos(); + + // Read in the block offsets and convert to stream offsets + for (int i = 0; i < numOffsets; i++) { + offsets[i] = stream.readUint32LE() + startOffset; + } + + int y = 0; + int x = 0; + bool upscale = false; + for (int i = 0; i < numOffsets; i++) { + stream.seek(offsets[i], SEEK_SET); + const int cmdLen = stream.readUint32LE(); + + // TODO: can probably avoid this copy to make it faster + uint8 *cmdData = new uint8[cmdLen]; + stream.read(cmdData, cmdLen); + Common::BitStreamMemoryStream cmdMemStream(cmdData, cmdLen); + Common::BitStreamMemory8MSB cmdBitStream(cmdMemStream); + bool skipping = true; + while (!cmdBitStream.eos()) { + uint32 idx = cmdBitStream.getBits(4); + uint32 blocksize = BASE_LEN[idx]; + if (idx != 0 && idx != 8) { + blocksize += cmdBitStream.getBits(FINE_LEN_BITS[idx]); + } + if (skipping) { + // leave blocksize pixels unchanged + if (upscale) + blocksize *= 2; + + while (blocksize) { + blocksize--; + x++; + if (x == _width) { + x = 0; + y++; + } + } + } else { + // draw blocksize pixels from data block + while (blocksize) { + // TODO: would be nicer to read these in whole scanlines. + // Also this upscale code is kinda ugly. + const uint8 p = stream.readByte(); + dst[y * _width + x] = p; + x++; + if (x == _width) { + x = 0; + y++; + } + if (upscale) { + dst[y * _width + x] = p; + x++; + if (x == _width) { + x = 0; + y++; + } + } + blocksize--; + } + } + skipping = !skipping; + } + + // Slight HACK - if we only used half the expected height, then + // this frame should be upscaled. Go back and do it again. + if (!upscale && y == blockHeight / 2) { + y = 0; + i--; + upscale = true; + } + + delete [] cmdData; + + } + return &_surface; +} + +Graphics::PixelFormat JYV1Decoder::getPixelFormat() const { + return Graphics::PixelFormat::createFormatCLUT8(); +} + +} // End of namespace Image diff --git a/image/codecs/jyv1.h b/image/codecs/jyv1.h new file mode 100644 index 00000000000..ec4ee1306b5 --- /dev/null +++ b/image/codecs/jyv1.h @@ -0,0 +1,53 @@ +/* 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. + * + */ + +#ifndef IMAGE_CODECS_JYV1_H +#define IMAGE_CODECS_JYV1_H + +#include "image/codecs/codec.h" + +namespace Image { + +/** + * JYV1/RRV1/RRV2 image decoder. + * + * Used by Crusader: No Remorse AVI files + */ +class JYV1Decoder : public Codec { +public: + JYV1Decoder (int width, int height, uint32 streamTag); + ~JYV1Decoder(); + + const Graphics::Surface *decodeFrame(Common::SeekableReadStream &stream) override; + Graphics::PixelFormat getPixelFormat() const override; + + static bool isJYV1StreamTag(uint32 streamTag); + +private: + Graphics::Surface _surface; + int _width, _height; + uint32 _streamType; +}; + +} // End of namespace Image + +#endif diff --git a/image/codecs/qtrle.cpp b/image/codecs/qtrle.cpp index 700e2e17563..8b5dcb1727a 100644 --- a/image/codecs/qtrle.cpp +++ b/image/codecs/qtrle.cpp @@ -30,7 +30,6 @@ #include "common/stream.h" #include "common/system.h" #include "common/textconsole.h" -#include "graphics/colormasks.h" #include "graphics/surface.h" namespace Image { diff --git a/image/iff.cpp b/image/iff.cpp index e0ac10858cf..3e156eec8e5 100644 --- a/image/iff.cpp +++ b/image/iff.cpp @@ -94,8 +94,16 @@ bool IFFDecoder::loadStream(Common::SeekableReadStream &stream) { } while (1) { + if (stream.size() < stream.pos() + 8) + break; + const uint32 chunkType = stream.readUint32BE(); - const uint32 chunkSize = stream.readUint32BE(); + uint32 chunkSize = stream.readUint32BE(); + // According to the format specs: + // "If ckData is an odd number of bytes long, a 0 pad byte follows which is not included in ckSize." + // => fix the length + if (chunkSize % 2) + chunkSize++; if (stream.eos()) break; @@ -114,6 +122,9 @@ bool IFFDecoder::loadStream(Common::SeekableReadStream &stream) { loadBitmap(stream); break; default: + if (stream.size() < stream.pos() + (int32)chunkSize) + break; + stream.skip(chunkSize); } } diff --git a/image/module.mk b/image/module.mk index be049eb8182..21566dd6029 100644 --- a/image/module.mk +++ b/image/module.mk @@ -15,6 +15,7 @@ MODULE_OBJS := \ codecs/indeo3.o \ codecs/indeo4.o \ codecs/indeo5.o \ + codecs/jyv1.o \ codecs/mjpeg.o \ codecs/msrle.o \ codecs/msrle4.o \ diff --git a/test/engines/wintermute/path_utils.h b/test/engines/wintermute/path_utils.h new file mode 100644 index 00000000000..26f3404396c --- /dev/null +++ b/test/engines/wintermute/path_utils.h @@ -0,0 +1,236 @@ +#include <cxxtest/TestSuite.h> +#include "engines/wintermute/utils/path_util.h" +/** + * Test suite for the functions in engines/wintermute/utils/path_util.h + * + * NOTE: This is not a prescription; + * this was not written by the original engine author; + * this was not written by the engine porter. + * + * It might, however, help to spot variations in behavior that are introduced by modifications + */ + +class PathUtilTestSuite : public CxxTest::TestSuite { + public: + const Common::String unixPath; + const Common::String unixCapPath; + const Common::String windowsPath; + const Common::String windowsCapPath; + const Common::String emptyString; + const Common::String dualExtPath; + const Common::String manyExtPath; + const Common::String mixedSlashesPath1; + const Common::String mixedSlashesPath2; + const Common::String unixRelativePath; + const Common::String windowsRelativePath; + const Common::String unixDirPath; + const Common::String windowsDirPath; + PathUtilTestSuite () : + unixPath("/some/file.ext"), + unixCapPath("/SOME/FILE.EXT"), + windowsPath("C:\\some\\file.ext"), + windowsCapPath("C:\\SOME\\FILE.EXT"), + emptyString(""), + dualExtPath("/some/file.tar.gz"), + manyExtPath("/some/file.tar.bz2.gz.zip"), + mixedSlashesPath1("C:\\this/IS_REALLY\\weird.exe"), + mixedSlashesPath2("/pretty\\weird/indeed.txt"), + unixRelativePath("some/file.ext"), + windowsRelativePath("some\\file.ext"), + unixDirPath("/some/dir/"), + windowsDirPath("C:\\some\\dir\\") + {} + void test_getdirectoryname() { + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getDirectoryName(unixPath), + Common::String("/some/") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getDirectoryName(unixCapPath), + Common::String("/SOME/") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getDirectoryName(windowsPath), + Common::String("C:\\some\\") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getDirectoryName(windowsCapPath), + Common::String("C:\\SOME\\") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getDirectoryName(emptyString), + Common::String("") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getDirectoryName(unixDirPath), + Common::String("/some/dir/") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getDirectoryName(windowsDirPath), + Common::String("C:\\some\\dir\\") + ); + } + + void test_getfilename() { + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileName(unixPath), + Common::String("file.ext") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileName(unixCapPath), + Common::String("FILE.EXT") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileName(windowsPath), + Common::String("file.ext") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileName(windowsCapPath), + Common::String("FILE.EXT") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileName(emptyString), + Common::String("") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileName(unixRelativePath), + Common::String("file.ext") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileName(windowsRelativePath), + Common::String("file.ext") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileName(windowsDirPath), + Common::String("") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileName(unixDirPath), + Common::String("") + ); + } + + void test_getextension() { + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getExtension(windowsPath), + Common::String("ext") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getExtension(windowsCapPath), + Common::String("EXT") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getExtension(emptyString), + Common::String("") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getExtension(dualExtPath), + Common::String("gz") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getExtension(manyExtPath), + Common::String("zip") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getExtension(unixRelativePath), + Common::String("ext") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getExtension(windowsRelativePath), + Common::String("ext") + ); + } + + void test_getfilenamewithoutextension() { + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileNameWithoutExtension(windowsPath), + Common::String("file") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileNameWithoutExtension(windowsCapPath), + Common::String("FILE") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileNameWithoutExtension(emptyString), + Common::String("") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileNameWithoutExtension(dualExtPath), + Common::String("file.tar") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileNameWithoutExtension(manyExtPath), + Common::String("file.tar.bz2.gz") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileNameWithoutExtension(unixRelativePath), + Common::String("file") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getFileNameWithoutExtension(windowsRelativePath), + Common::String("file") + ); + } + + void test_combine_identity() { + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getDirectoryName(windowsPath) + + Wintermute::PathUtil::getFileNameWithoutExtension(windowsPath) + + "." + + Wintermute::PathUtil::getExtension(windowsPath), + windowsPath + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getDirectoryName(windowsCapPath) + + Wintermute::PathUtil::getFileNameWithoutExtension(windowsCapPath) + + "." + + Wintermute::PathUtil::getExtension(windowsCapPath), + windowsCapPath + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getDirectoryName(unixCapPath) + + Wintermute::PathUtil::getFileNameWithoutExtension(unixCapPath) + + "." + + Wintermute::PathUtil::getExtension(unixCapPath), + unixCapPath + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::getDirectoryName(manyExtPath) + + Wintermute::PathUtil::getFileNameWithoutExtension(manyExtPath) + + "." + + Wintermute::PathUtil::getExtension(manyExtPath), + manyExtPath + ); + } + + void test_normalize() { + TS_ASSERT_EQUALS( + Wintermute::PathUtil::normalizeFileName(windowsCapPath), + Common::String("c:/some/file.ext") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::normalizeFileName(windowsPath), + Common::String("c:/some/file.ext") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::normalizeFileName(mixedSlashesPath1), + Common::String("c:/this/is_really/weird.exe") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::normalizeFileName(mixedSlashesPath2), + Common::String("/pretty/weird/indeed.txt") + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::normalizeFileName(emptyString), + emptyString + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::normalizeFileName(unixRelativePath), + unixRelativePath + ); + TS_ASSERT_EQUALS( + Wintermute::PathUtil::normalizeFileName(windowsRelativePath), + unixRelativePath // NOT windows + ); + } +}; diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index a42c8e28c67..4f54b82f859 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -201,6 +201,7 @@ bool AVIDecoder::parseNextChunk() { case ID_STRH: handleStreamHeader(size); break; + case ID_HDRL: // Header list.. what's it doing here? Probably ok to ignore? case ID_STRD: // Extra stream info, safe to ignore case ID_VEDT: // Unknown, safe to ignore case ID_JUNK: // Alignment bytes, should be ignored @@ -990,7 +991,8 @@ bool AVIDecoder::AVIVideoTrack::rewind() { } Image::Codec *AVIDecoder::AVIVideoTrack::createCodec() { - return Image::createBitmapCodec(_bmInfo.compression, _bmInfo.width, _bmInfo.height, _bmInfo.bitCount); + return Image::createBitmapCodec(_bmInfo.compression, _vidsHeader.streamHandler, _bmInfo.width, + _bmInfo.height, _bmInfo.bitCount); } void AVIDecoder::AVIVideoTrack::forceTrackEnd() { diff --git a/video/flic_decoder.h b/video/flic_decoder.h index d093daa3d07..3dc859f8571 100644 --- a/video/flic_decoder.h +++ b/video/flic_decoder.h @@ -43,6 +43,7 @@ namespace Video { * * Video decoder used in engines: * - chewy + * - petka * - prince * - tucker */ diff --git a/video/module.mk b/video/module.mk index be014598f27..c1fb79256ee 100644 --- a/video/module.mk +++ b/video/module.mk @@ -6,6 +6,7 @@ MODULE_OBJS := \ dxa_decoder.o \ flic_decoder.o \ mpegps_decoder.o \ + mve_decoder.o \ psx_decoder.o \ qt_decoder.o \ smk_decoder.o \ diff --git a/video/mve_decoder.cpp b/video/mve_decoder.cpp new file mode 100644 index 00000000000..418ccdbff6c --- /dev/null +++ b/video/mve_decoder.cpp @@ -0,0 +1,548 @@ +/* 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 "video/mve_decoder.h" + +#include "audio/decoders/raw.h" + +#include "common/endian.h" +#include "common/rect.h" +#include "common/stream.h" +#include "common/memstream.h" +#include "common/system.h" +#include "common/textconsole.h" +#include "common/events.h" + +#include "graphics/surface.h" +#include "graphics/palette.h" + +namespace Video { + +MveDecoder::MveDecoder() + : _done(false), + _s(nullptr), + _dirtyPalette(false), + _skipMapSize(0), + _skipMap(nullptr), + _decodingMapSize(0), + _decodingMap(nullptr), + _frameNumber(-1), + _frameSize(0), + _frameData(nullptr), + _audioTrack(0), + _audioStream(nullptr) +{ + for (int i = 0; i < 0x300; ++i) + _palette[i] = 0; +} + +MveDecoder::~MveDecoder() { + close(); + delete _audioStream; + delete[] _frameData; + delete[] _decodingMap; + delete[] _skipMap; +} + +static const char signature[] = "Interplay MVE File\x1A"; + +bool MveDecoder::loadStream(Common::SeekableReadStream *stream) { + close(); + + byte signature_buffer[sizeof(signature)]; + stream->read(signature_buffer, sizeof(signature_buffer)); + if (memcmp(signature_buffer, signature, sizeof(signature))) { + warning("MveDecoder::loadStream(): attempted to load non-MVE data"); + return false; + } + _s = stream; + + uint16 h1 = _s->readUint16LE(); + uint16 h2 = _s->readUint16LE(); + uint16 h3 = _s->readUint16LE(); + + assert(h1 == 0x001a); + assert(h2 == 0x0100); + assert(h3 == 0x1133); + + readPacketHeader(); + while (!_done && _packetKind < 3) { + readNextPacket(); + } + + return true; +} + +void MveDecoder::setAudioTrack(int track) { + assert(track >= 0 && track < 16); + _audioTrack= track; +} + +void MveDecoder::applyPalette(PaletteManager *paletteManager) { + paletteManager->setPalette(_palette + 3 * _palStart, _palStart, _palCount); +} + +void MveDecoder::copyBlock_8bit(Graphics::Surface &dst, Common::MemoryReadStream &s, int block) { + int x = (block % _widthInBlocks) * 8; + int y = (block / _widthInBlocks) * 8; + + byte *p = (byte*)dst.getBasePtr(x, y); + + for (int i = 0; i != 8; ++i) { + s.read(p, 8); + p += dst.pitch; + } +} + +void MveDecoder::copyBlock_16bit(Graphics::Surface &dst, Common::MemoryReadStream &s, int block) { + int x = (block % _widthInBlocks) * 8; + int y = (block / _widthInBlocks) * 8; + + byte *p = (byte*)dst.getBasePtr(x, y); + + for (int i = 0; i != 8; ++i) { + for (int j = 0; j != 8; ++j) { + WRITE_UINT16(p+2*j, s.readUint16LE()); + } + p += dst.pitch; + } +} + +void MveDecoder::copyBlock(Graphics::Surface &dst, Graphics::Surface &src, int block, int offset) { + int dx = (block % _widthInBlocks) * 8; + int dy = (block / _widthInBlocks) * 8; + + int sx = dx + offset % _width; + int sy = dy + offset / _width; + + byte *dp = (byte*)dst.getBasePtr(dx, dy); + byte *sp = (byte*)src.getBasePtr(sx, sy); + + for (int i = 0; i != 8; ++i) { + memmove(dp, sp, !_trueColor ? 8 : 16); + dp += dst.pitch; + sp += src.pitch; + } +} + +void MveDecoder::copyBlock(Graphics::Surface &dst, Graphics::Surface &src, int dx, int dy, int off_x, int off_y) { + int sx = dx + off_x; + int sy = dy + off_y; + + byte *dp = (byte*)dst.getBasePtr(dx, dy); + byte *sp = (byte*)src.getBasePtr(sx, sy); + + for (int i = 0; i != 8; ++i) { + memmove(dp, sp, !_trueColor ? 8 : 16); + dp += dst.pitch; + sp += src.pitch; + } +} + +void MveDecoder::decodeFormat6() { + _decodingMapSize = _widthInBlocks * _heightInBlocks * 2; + _decodingMap = _frameData + 14; + + Common::MemoryReadStream opStream = Common::MemoryReadStream(_decodingMap, _decodingMapSize); + Common::MemoryReadStream frameStream = Common::MemoryReadStream(_frameData + _decodingMapSize + 14, _frameSize); + + // Pass 1 + opStream.seek(0); + for (int b = 0; b != _widthInBlocks * _heightInBlocks; ++b) { + uint16 op = opStream.readUint16LE(); + if (op == 0) { + if (!_trueColor) { + copyBlock_8bit(_decodeSurface0, frameStream, b); + } else { + copyBlock_16bit(_decodeSurface0, frameStream, b); + } + } + } + + // Pass 2 + opStream.seek(0); + for (int b = 0; b != _widthInBlocks * _heightInBlocks; ++b) { + uint16 op = opStream.readUint16LE(); + if (op != 0) { + Graphics::Surface &src = (op & 0x8000) ? _decodeSurface1 : _decodeSurface0; + int offset = int(op & 0x7fff) - 0x4000; + copyBlock(_decodeSurface0, src, b, offset); + } + } + + // Pass 3 + for (int b = 0; b != _widthInBlocks * _heightInBlocks; ++b) { + copyBlock(_frameSurface, _decodeSurface0, b); + } + + Graphics::Surface t = _decodeSurface0; + _decodeSurface0 = _decodeSurface1; + _decodeSurface1 = t; + + _decodingMap = nullptr; +} + +void MveDecoder::decodeFormat10() { + MveSkipStream skipStream = MveSkipStream(_skipMap, _skipMapSize); + Common::MemoryReadStream opStream = Common::MemoryReadStream(_decodingMap, _decodingMapSize); + Common::MemoryReadStream frameStream = Common::MemoryReadStream(_frameData + 14, _frameSize - 14); + + // Pass 1 + opStream.seek(0); + skipStream.reset(); + for (int b = 0; b != _widthInBlocks * _heightInBlocks; ++b) { + if (skipStream.skip()) continue; + uint16 op = opStream.readUint16LE(); + if (op == 0) { + if (!_trueColor) { + copyBlock_8bit(_decodeSurface0, frameStream, b); + } else { + copyBlock_16bit(_decodeSurface0, frameStream, b); + } + } + } + + // Pass 2 + opStream.seek(0); + skipStream.reset(); + for (int b = 0; b != _widthInBlocks * _heightInBlocks; ++b) { + if (skipStream.skip()) continue; + uint16 op = opStream.readUint16LE(); + if (op != 0) { + Graphics::Surface &src = (op & 0x8000) ? _decodeSurface1 : _decodeSurface0; + int offset = int(op & 0x7fff) - 0x4000; + copyBlock(_decodeSurface0, src, b, offset); + } + } + + // Pass 3 + skipStream.reset(); + for (int b = 0; b != _widthInBlocks * _heightInBlocks; ++b) { + if (skipStream.skip()) continue; + copyBlock(_frameSurface, _decodeSurface0, b); + } + + Graphics::Surface t = _decodeSurface0; + _decodeSurface0 = _decodeSurface1; + _decodeSurface1 = t; +} + +void MveDecoder::readPacketHeader() { + _packetLen = _s->readUint16LE(); + _packetKind = _s->readUint16LE(); + + /* + switch (_packetKind) { + case 0: + warning("initialize audio"); + break; + case 1: + warning("audio"); + break; + case 2: + warning("initialize video"); + break; + case 3: + warning("video"); + break; + case 4: + warning("shutdown"); + break; + case 5: + warning("end chunk"); + break; + } + */ +} + +void MveDecoder::readNextPacket() { + bool frameDone = false; + while (!_done && !frameDone) { + uint16 opLen = _s->readUint16LE(); + uint16 opKind = _s->readUint16BE(); + + switch (opKind) { + case 0x0000: + { + _done = true; + assert(opLen == 0); + break; + } + case 0x0100: + { + assert(opLen == 0); + readPacketHeader(); + break; + } + case 0x0200: // create timer + { + assert(opLen == 6); + uint32 rate = _s->readUint32LE(); + uint16 subdiv = _s->readUint16LE(); + _frameRate = Common::Rational(1000000, rate * subdiv); + break; + } + case 0x0300: // init audio + { + assert(opLen == 8); + /*uint16 unk =*/ _s->readUint16LE(); + uint16 flags = _s->readUint16LE(); + uint16 sampleRate = _s->readUint16LE(); + /*uint16 bufLen =*/ _s->readUint16LE(); + + /* + warning("\t\tAudio: %dHz %s %s", + sampleRate, + (flags & 1) == 0 ? "mono" : "stereo", + (flags & 2) == 0 ? "8-bit" : "16-bit" + ); + */ + + assert((flags & 1) == 0); + assert((flags & 2) == 0); + + _audioStream = Audio::makeQueuingAudioStream(sampleRate, (flags & 2) != 0); + addTrack(new MveAudioTrack(this)); + + break; + } + case 0x0400: // send audio + { + assert(opLen == 0); + break; + } + case 0x0502: // init video buffers + { + assert(opLen == 8); + + uint16 width = _s->readUint16LE(); + uint16 height = _s->readUint16LE(); + /*uint16 count =*/ _s->readUint16LE(); + uint16 trueColor = _s->readUint16LE(); + + _widthInBlocks = width; + _heightInBlocks = height; + + _width = 8 * width; + _height = 8 * height; + + _trueColor = !!trueColor; + + if (!_trueColor) { + _pixelFormat = Graphics::PixelFormat::createFormatCLUT8(); + } else { + _pixelFormat = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0); + } + + _decodeSurface0.create(_width, _height, _pixelFormat); + _decodeSurface0.fillRect(Common::Rect(_width, _height), 0); + + _decodeSurface1.create(_width, _height, _pixelFormat); + _decodeSurface1.fillRect(Common::Rect(_width, _height), 0); + + _frameSurface.create(_width, _height, _pixelFormat); + _frameSurface.fillRect(Common::Rect(_width, _height), 0); + + addTrack(new MveVideoTrack(this)); + + break; + } + case 0x0600: + { + delete[] _frameData; + _frameData = new byte[opLen]; + _frameSize = opLen; + _s->read(_frameData, _frameSize); + + decodeFormat6(); + + break; + } + case 0x0701: // send video + { + assert(opLen == 6); + uint16 palStart = _s->readUint16LE(); + uint16 palCount = _s->readUint16LE(); + uint16 unk = _s->readUint16LE(); + (void)unk; + + if (palStart || palCount) { + _palStart = palStart; + _palCount = palCount; + } + + _frameNumber += 1; + frameDone = true; + + break; + } + case 0x0800: // audio frame + { + /*uint16 seq =*/ _s->readUint16LE(); + uint16 mask = _s->readUint16LE(); + uint16 len = _s->readUint16LE(); + + assert(opLen == len + 6); + assert(_audioStream); + + if (mask & (1 << _audioTrack)) { + byte *audioFrame = new byte[len]; + _s->read(audioFrame, len); + _audioStream->queueBuffer(audioFrame, len, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); + } else { + _s->skip(len); + } + + break; + } + case 0x0900: // audio frame (silent) + { + assert(opLen == 6); + /*uint16 seq =*/ _s->readUint16LE(); + /*uint16 mask =*/ _s->readUint16LE(); + /*uint16 len =*/ _s->readUint16LE(); + + break; + } + case 0x0a00: // set video mode + { + assert(opLen == 6); + /*uint16 width =*/ _s->readUint16LE(); + /*uint16 height =*/ _s->readUint16LE(); + /*uint16 flags =*/ _s->readUint16LE(); + + break; + } + case 0x0c00: + { + uint16 palStart = _s->readUint16LE(); + uint16 palCount = _s->readUint16LE(); + + assert(opLen >= 3 * palCount + 2); + + for (int i = palStart; i < palStart + palCount; ++i) { + byte r = _s->readByte(); + byte g = _s->readByte(); + byte b = _s->readByte(); + + _palette[3*i+0] = (r << 2) | (r >> 4); + _palette[3*i+1] = (g << 2) | (g >> 4); + _palette[3*i+2] = (b << 2) | (b >> 4); + } + if (palCount & 1) { + _s->skip(1); + } + + _dirtyPalette = true; + _palStart = palStart; + _palCount = palCount; + + break; + } + case 0x0e00: + { + // TODO: Preallocate or keep existing buffer + delete[] _skipMap; + _skipMap = new byte[opLen]; + _skipMapSize = opLen; + _s->read(_skipMap, _skipMapSize); + break; + } + case 0x0f00: + { + // TODO: Preallocate or keep existing buffer + delete[] _decodingMap; + _decodingMap = new byte[opLen]; + _decodingMapSize = opLen; + _s->read(_decodingMap, _decodingMapSize); + break; + } + case 0x1000: + { + // TODO: Preallocate or keep existing buffer + delete[] _frameData; + _frameData = new byte[opLen]; + _frameSize = opLen; + _s->read(_frameData, _frameSize); + + decodeFormat10(); + + break; + } + default: + error("Unknown opcode %04x", opKind); + _s->skip(opLen); + break; + } + } +} + +MveDecoder::MveVideoTrack::MveVideoTrack(MveDecoder *decoder) : _decoder(decoder) { +} + +bool MveDecoder::MveVideoTrack::endOfTrack() const { + return _decoder->_done; +} + +uint16 MveDecoder::MveVideoTrack::getWidth() const { + return _decoder->getWidth(); +} + +uint16 MveDecoder::MveVideoTrack::getHeight() const { + return _decoder->getHeight(); +} + +Graphics::PixelFormat MveDecoder::MveVideoTrack::getPixelFormat() const { + return _decoder->getPixelFormat(); +} + +int MveDecoder::MveVideoTrack::getCurFrame() const { + return _decoder->_frameNumber; +} + +const Graphics::Surface *MveDecoder::MveVideoTrack::decodeNextFrame() { + return &_decoder->_frameSurface; +} + +const byte *MveDecoder::MveVideoTrack::getPalette() const { + return _decoder->_palette; +} + +bool MveDecoder::MveVideoTrack::hasDirtyPalette() const { + return _decoder->_dirtyPalette; +} + +Common::Rational MveDecoder::MveVideoTrack::getFrameRate() const { + return _decoder->getFrameRate(); +} + +MveDecoder::MveAudioTrack::MveAudioTrack(MveDecoder *decoder) : + AudioTrack(Audio::Mixer::kPlainSoundType), + _decoder(decoder) +{ +} + +Audio::AudioStream *MveDecoder::MveAudioTrack::getAudioStream() const { + return _decoder->_audioStream; +} + +} // End of namespace Video diff --git a/video/mve_decoder.h b/video/mve_decoder.h new file mode 100644 index 00000000000..77d377e5b64 --- /dev/null +++ b/video/mve_decoder.h @@ -0,0 +1,172 @@ +/* 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. + * + */ + +#ifndef VIDEO_MVEDECODER_H +#define VIDEO_MVEDECODER_H + +#include "audio/audiostream.h" +#include "video/video_decoder.h" +#include "graphics/surface.h" +#include "common/list.h" +#include "common/rect.h" +#include "common/memstream.h" + +namespace Common { +class SeekableReadStream; +} + +namespace Graphics { +struct PixelFormat; +} + +class PaletteManager; + +namespace Video { + +/** + * Decoder for Interplay MVE videos. + * + * Video decoder used in engines: + * - kingdom + */ +class MveDecoder : public VideoDecoder { + bool _done; + Common::SeekableReadStream *_s; + + uint16 _packetLen; + uint16 _packetKind; + + Graphics::Surface _decodeSurface0; + Graphics::Surface _decodeSurface1; + Graphics::Surface _frameSurface; + + uint16 _widthInBlocks; + uint16 _heightInBlocks; + + uint16 _width; + uint16 _height; + + Common::Rational _frameRate; + + bool _trueColor; + Graphics::PixelFormat _pixelFormat; + bool _dirtyPalette; + uint16 _palStart; + uint16 _palCount; + byte _palette[0x300]; + + uint16 _skipMapSize; + byte *_skipMap; + + uint16 _decodingMapSize; + byte *_decodingMap; + + int _frameNumber; + uint16 _frameSize; + byte *_frameData; + + int _audioTrack; + Audio::QueuingAudioStream *_audioStream; + + void readPacketHeader(); + void copyBlock_8bit(Graphics::Surface &dst, Common::MemoryReadStream &s, int block); + void copyBlock_16bit(Graphics::Surface &dst, Common::MemoryReadStream &s, int block); + void copyBlock(Graphics::Surface &dst, Graphics::Surface &src, int block, int offset = 0); + void copyBlock(Graphics::Surface &dst, Graphics::Surface &src, int dx, int dy, int off_x, int off_y); + + void decodeFormat6(); + void decodeFormat10(); + + class MveVideoTrack : public FixedRateVideoTrack { + MveDecoder *_decoder; + public: + MveVideoTrack(MveDecoder *decoder); + + bool endOfTrack() const; + + uint16 getWidth() const; + uint16 getHeight() const; + + Graphics::PixelFormat getPixelFormat() const; + + int getCurFrame() const; + // int getFrameCount() const; + + const Graphics::Surface *decodeNextFrame(); + const byte *getPalette() const; + bool hasDirtyPalette() const; + + protected: + Common::Rational getFrameRate() const; + }; + + class MveAudioTrack : public AudioTrack { + MveDecoder *_decoder; + public: + MveAudioTrack(MveDecoder *decoder); + + Audio::AudioStream *getAudioStream() const; + }; + + class MveSkipStream { + Common::MemoryReadStream s; + uint16 queue; + public: + MveSkipStream(byte *p, size_t sz) + : s(p, sz), queue(0x8000) + {} + + void reset() { + s.seek(0); + queue = 0x8000; + } + + bool skip() { + if (queue == 0x8000) { + queue = s.readUint16LE(); + assert(queue != 0); + } + bool r = (queue & 0x8000) == 0; + queue <<= 1; + return r; + } + }; + +public: + MveDecoder(); + virtual ~MveDecoder(); + + bool loadStream(Common::SeekableReadStream *stream); + void setAudioTrack(int track); + void applyPalette(PaletteManager *paletteManager); + + // const Common::List<Common::Rect> *getDirtyRects() const; + // void clearDirtyRects(); + // void copyDirtyRectsToBuffer(uint8 *dst, uint pitch); + + Common::Rational getFrameRate() { return _frameRate; } + void readNextPacket(); +}; + +} // End of namespace Video + +#endif