aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS48
-rw-r--r--audio/softsynth/mt32.cpp18
-rw-r--r--backends/platform/tizen/system.cpp49
-rw-r--r--backends/saves/default/default-saves.cpp155
-rw-r--r--backends/saves/default/default-saves.h25
-rw-r--r--base/commandLine.cpp6
-rw-r--r--common/savefile.h45
-rw-r--r--devtools/create_project/msbuild.cpp4
-rw-r--r--engines/bbvs/bbvs.cpp33
-rw-r--r--engines/saga/interface.cpp6
-rw-r--r--engines/saga/saga.cpp8
-rw-r--r--engines/sci/detection_tables.h65
-rw-r--r--engines/sci/engine/kernel.h13
-rw-r--r--engines/sci/engine/kernel_tables.h27
-rw-r--r--engines/sci/engine/kevent.cpp7
-rw-r--r--engines/sci/engine/kgraphics.cpp2
-rw-r--r--engines/sci/engine/kgraphics32.cpp266
-rw-r--r--engines/sci/engine/kstring.cpp7
-rw-r--r--engines/sci/engine/savegame.cpp20
-rw-r--r--engines/sci/engine/workarounds.cpp1
-rw-r--r--engines/sci/graphics/cache.cpp4
-rw-r--r--engines/sci/graphics/cache.h2
-rw-r--r--engines/sci/graphics/celobj32.cpp343
-rw-r--r--engines/sci/graphics/celobj32.h25
-rw-r--r--engines/sci/graphics/compare.cpp4
-rw-r--r--engines/sci/graphics/frameout.cpp744
-rw-r--r--engines/sci/graphics/frameout.h82
-rw-r--r--engines/sci/graphics/palette32.cpp8
-rw-r--r--engines/sci/graphics/palette32.h1
-rw-r--r--engines/sci/graphics/plane32.cpp21
-rw-r--r--engines/sci/graphics/plane32.h11
-rw-r--r--engines/sci/graphics/remap.cpp290
-rw-r--r--engines/sci/graphics/remap.h85
-rw-r--r--engines/sci/graphics/screen_item32.cpp114
-rw-r--r--engines/sci/graphics/text32.cpp29
-rw-r--r--engines/sci/graphics/text32.h14
-rw-r--r--engines/sci/graphics/view.cpp9
-rw-r--r--engines/sci/graphics/view.h2
-rw-r--r--engines/sci/sci.cpp4
-rw-r--r--engines/sci/sci.h4
-rw-r--r--engines/scumm/players/player_ad.cpp30
-rw-r--r--engines/scumm/players/player_ad.h2
-rw-r--r--engines/sword25/fmv/movieplayer.cpp2
-rw-r--r--engines/tucker/resource.cpp8
-rw-r--r--engines/wage/debugger.cpp97
-rw-r--r--engines/wage/debugger.h47
-rw-r--r--engines/wage/design.cpp10
-rw-r--r--engines/wage/detection.cpp1
-rw-r--r--engines/wage/detection_tables.h34
-rw-r--r--engines/wage/gui.cpp82
-rw-r--r--engines/wage/gui.h11
-rw-r--r--engines/wage/menu.cpp6
-rw-r--r--engines/wage/module.mk1
-rw-r--r--engines/wage/script.cpp2
-rw-r--r--engines/wage/script.h4
-rw-r--r--engines/wage/wage.cpp11
-rw-r--r--engines/wage/wage.h7
-rw-r--r--gui/themes/translations.datbin538061 -> 562190 bytes
-rw-r--r--po/zh-Latn_CN.po3730
-rw-r--r--ports.mk2
60 files changed, 5322 insertions, 1366 deletions
diff --git a/NEWS b/NEWS
index 0dae4ffb27..84cf170bb2 100644
--- a/NEWS
+++ b/NEWS
@@ -3,10 +3,50 @@ For a more comprehensive changelog of the latest experimental code, see:
1.9.0 (XXXX-XX-XX)
AGI:
- - Added support for Hercules rendering (green + amber)
- - Added support for the Hercules hires font (also usable outside of Hercules rendering)
- - Added optional "pause, when entering commands" feature, that was only available
- in the original interpreter for Hercules rendering.
+ - Added support for Hercules rendering. Both green and amber modes are
+ supported.
+ - Added support for the Hercules high resolution font. The font is also
+ usable outside of Hercules rendering.
+ - Added optional "pause, when entering commands" feature, that was only
+ available in the original interpreter for Hercules rendering.
+
+1.8.1 (XXXX-XX-XX)
+ General:
+ - Removed TESTING flag from several supported games.
+ - Added Chinese Pinyin translation.
+
+ BBVS:
+ - Fixed game restart.
+
+ CinE:
+ - Fixed sound effect loading.
+
+ Gob:
+ - Fixed lock up for some games during sound initialization.
+
+ Lab:
+ - Fixed lock-up during ending sequence.
+ - Improved internal game controls.
+
+ SAGA:
+ - Fixed user interface colors in the French and German versions of I Have No
+ Mouth and I Must Scream.
+
+ SCUMM:
+ - Fixed detection of Maniac Mansion from Day of the Tentacle in the Windows
+ version of ScummVM.
+ - Fixed a sound effect not stopping in Loom EGA with AdLib.
+
+ Broken Sword 2.5:
+ - Added option to use English speech instead of German one when no speech is
+ available for the selected language.
+ - Fixed resource releasing on game exit.
+ - Fixed game restart after language change in-game.
+ - Fixed flickering in main Menu.
+
+ Windows port:
+ - Fixed bug in MIDI device listing affecting cases where MIDI devices were
+ not usable.
1.8.0 (2016-03-04)
New Games:
diff --git a/audio/softsynth/mt32.cpp b/audio/softsynth/mt32.cpp
index 4420657854..d514e64fe9 100644
--- a/audio/softsynth/mt32.cpp
+++ b/audio/softsynth/mt32.cpp
@@ -140,10 +140,7 @@ MidiDriver_MT32::MidiDriver_MT32(Audio::Mixer *mixer) : MidiDriver_Emulated(mixe
}
_reportHandler = NULL;
_synth = NULL;
- // Unfortunately bugs in the emulator cause inaccurate tuning
- // at rates other than 32KHz, thus we produce data at 32KHz and
- // rely on Mixer to convert.
- _outputRate = 32000; //_mixer->getOutputRate();
+ _outputRate = 0;
_initializing = false;
// Initialized in open()
@@ -180,7 +177,6 @@ int MidiDriver_MT32::open() {
if (_isOpen)
return MERR_ALREADY_OPEN;
- MidiDriver_Emulated::open();
_reportHandler = new MT32Emu::ReportHandlerScummVM();
_synth = new MT32Emu::Synth(_reportHandler);
@@ -212,6 +208,18 @@ int MidiDriver_MT32::open() {
double gain = (double)ConfMan.getInt("midi_gain") / 100.0;
_synth->setOutputGain(1.0f * gain);
_synth->setReverbOutputGain(0.68f * gain);
+ // We let the synthesizer play MIDI messages immediately. Our MIDI
+ // handling is synchronous to sample generation. This makes delaying MIDI
+ // events result in odd sound output in some cases. For example, the
+ // shattering window in the Indiana Jones and the Fate of Atlantis intro
+ // will sound like a bell if we use any delay here.
+ // Bug #6242 "AUDIO: Built-In MT-32 MUNT Produces Wrong Sounds".
+ _synth->setMIDIDelayMode(MT32Emu::MIDIDelayMode_IMMEDIATE);
+
+ // We need to report the sample rate MUNT renders at as sample rate of our
+ // AudioStream.
+ _outputRate = _synth->getStereoOutputSampleRate();
+ MidiDriver_Emulated::open();
_initializing = false;
diff --git a/backends/platform/tizen/system.cpp b/backends/platform/tizen/system.cpp
index a235456670..1820a28791 100644
--- a/backends/platform/tizen/system.cpp
+++ b/backends/platform/tizen/system.cpp
@@ -81,36 +81,41 @@ struct TizenSaveFileManager : public DefaultSaveFileManager {
};
bool TizenSaveFileManager::removeSavefile(const Common::String &filename) {
- Common::String savePathName = getSavePath();
+ // Assure the savefile name cache is up-to-date.
+ assureCached(getSavePath());
+ if (getError().getCode() != Common::kNoError)
+ return false;
- checkPath(Common::FSNode(savePathName));
- if (getError().getCode() != Common::kNoError) {
+ // Obtain node if exists.
+ SaveFileCache::const_iterator file = _saveFileCache.find(filename);
+ if (file == _saveFileCache.end()) {
return false;
- }
+ } else {
+ const Common::FSNode fileNode = file->_value;
+ // Remove from cache, this invalidates the 'file' iterator.
+ _saveFileCache.erase(file);
+ file = _saveFileCache.end();
- // recreate FSNode since checkPath may have changed/created the directory
- Common::FSNode savePath(savePathName);
- Common::FSNode file = savePath.getChild(filename);
+ String unicodeFileName;
+ StringUtil::Utf8ToString(fileNode.getPath().c_str(), unicodeFileName);
- String unicodeFileName;
- StringUtil::Utf8ToString(file.getPath().c_str(), unicodeFileName);
+ switch (Tizen::Io::File::Remove(unicodeFileName)) {
+ case E_SUCCESS:
+ return true;
- switch (Tizen::Io::File::Remove(unicodeFileName)) {
- case E_SUCCESS:
- return true;
+ case E_ILLEGAL_ACCESS:
+ setError(Common::kWritePermissionDenied, "Search or write permission denied: " +
+ file.getName());
+ break;
- case E_ILLEGAL_ACCESS:
- setError(Common::kWritePermissionDenied, "Search or write permission denied: " +
- file.getName());
- break;
+ default:
+ setError(Common::kPathDoesNotExist, "removeSavefile: '" + file.getName() +
+ "' does not exist or path is invalid");
+ break;
+ }
- default:
- setError(Common::kPathDoesNotExist, "removeSavefile: '" + file.getName() +
- "' does not exist or path is invalid");
- break;
+ return false;
}
-
- return false;
}
//
diff --git a/backends/saves/default/default-saves.cpp b/backends/saves/default/default-saves.cpp
index 4f7013724a..daec36ae72 100644
--- a/backends/saves/default/default-saves.cpp
+++ b/backends/saves/default/default-saves.cpp
@@ -60,22 +60,15 @@ void DefaultSaveFileManager::checkPath(const Common::FSNode &dir) {
}
Common::StringArray DefaultSaveFileManager::listSavefiles(const Common::String &pattern) {
- Common::String savePathName = getSavePath();
- checkPath(Common::FSNode(savePathName));
+ // Assure the savefile name cache is up-to-date.
+ assureCached(getSavePath());
if (getError().getCode() != Common::kNoError)
return Common::StringArray();
- // recreate FSNode since checkPath may have changed/created the directory
- Common::FSNode savePath(savePathName);
-
- Common::FSDirectory dir(savePath);
- Common::ArchiveMemberList savefiles;
Common::StringArray results;
- Common::String search(pattern);
-
- if (dir.listMatchingMembers(savefiles, search) > 0) {
- for (Common::ArchiveMemberList::const_iterator file = savefiles.begin(); file != savefiles.end(); ++file) {
- results.push_back((*file)->getName());
+ for (SaveFileCache::const_iterator file = _saveFileCache.begin(), end = _saveFileCache.end(); file != end; ++file) {
+ if (file->_key.matchString(pattern, true)) {
+ results.push_back(file->_key);
}
}
@@ -83,68 +76,81 @@ Common::StringArray DefaultSaveFileManager::listSavefiles(const Common::String &
}
Common::InSaveFile *DefaultSaveFileManager::openForLoading(const Common::String &filename) {
- // Ensure that the savepath is valid. If not, generate an appropriate error.
- Common::String savePathName = getSavePath();
- checkPath(Common::FSNode(savePathName));
+ // Assure the savefile name cache is up-to-date.
+ assureCached(getSavePath());
if (getError().getCode() != Common::kNoError)
- return 0;
-
- // recreate FSNode since checkPath may have changed/created the directory
- Common::FSNode savePath(savePathName);
+ return nullptr;
- Common::FSNode file = savePath.getChild(filename);
- if (!file.exists())
- return 0;
-
- // Open the file for reading
- Common::SeekableReadStream *sf = file.createReadStream();
-
- return Common::wrapCompressedReadStream(sf);
+ SaveFileCache::const_iterator file = _saveFileCache.find(filename);
+ if (file == _saveFileCache.end()) {
+ return nullptr;
+ } else {
+ // Open the file for loading.
+ Common::SeekableReadStream *sf = file->_value.createReadStream();
+ return Common::wrapCompressedReadStream(sf);
+ }
}
Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const Common::String &filename, bool compress) {
- // Ensure that the savepath is valid. If not, generate an appropriate error.
- Common::String savePathName = getSavePath();
- checkPath(Common::FSNode(savePathName));
+ // Assure the savefile name cache is up-to-date.
+ const Common::String savePathName = getSavePath();
+ assureCached(savePathName);
if (getError().getCode() != Common::kNoError)
- return 0;
+ return nullptr;
- // recreate FSNode since checkPath may have changed/created the directory
- Common::FSNode savePath(savePathName);
+ // Obtain node.
+ SaveFileCache::const_iterator file = _saveFileCache.find(filename);
+ Common::FSNode fileNode;
- Common::FSNode file = savePath.getChild(filename);
+ // If the file did not exist before, we add it to the cache.
+ if (file == _saveFileCache.end()) {
+ const Common::FSNode savePath(savePathName);
+ fileNode = savePath.getChild(filename);
+ } else {
+ fileNode = file->_value;
+ }
- // Open the file for saving
- Common::WriteStream *sf = file.createWriteStream();
+ // Open the file for saving.
+ Common::WriteStream *const sf = fileNode.createWriteStream();
+ Common::OutSaveFile *const result = compress ? Common::wrapCompressedWriteStream(sf) : sf;
- return compress ? Common::wrapCompressedWriteStream(sf) : sf;
+ // Add file to cache now that it exists.
+ _saveFileCache[filename] = Common::FSNode(fileNode.getPath());
+
+ return result;
}
bool DefaultSaveFileManager::removeSavefile(const Common::String &filename) {
- Common::String savePathName = getSavePath();
- checkPath(Common::FSNode(savePathName));
+ // Assure the savefile name cache is up-to-date.
+ assureCached(getSavePath());
if (getError().getCode() != Common::kNoError)
return false;
- // recreate FSNode since checkPath may have changed/created the directory
- Common::FSNode savePath(savePathName);
-
- Common::FSNode file = savePath.getChild(filename);
-
- // FIXME: remove does not exist on all systems. If your port fails to
- // compile because of this, please let us know (scummvm-devel or Fingolfin).
- // There is a nicely portable workaround, too: Make this method overloadable.
- if (remove(file.getPath().c_str()) != 0) {
+ // Obtain node if exists.
+ SaveFileCache::const_iterator file = _saveFileCache.find(filename);
+ if (file == _saveFileCache.end()) {
+ return false;
+ } else {
+ const Common::FSNode fileNode = file->_value;
+ // Remove from cache, this invalidates the 'file' iterator.
+ _saveFileCache.erase(file);
+ file = _saveFileCache.end();
+
+ // FIXME: remove does not exist on all systems. If your port fails to
+ // compile because of this, please let us know (scummvm-devel).
+ // There is a nicely portable workaround, too: Make this method overloadable.
+ if (remove(fileNode.getPath().c_str()) != 0) {
#ifndef _WIN32_WCE
- if (errno == EACCES)
- setError(Common::kWritePermissionDenied, "Search or write permission denied: "+file.getName());
+ if (errno == EACCES)
+ setError(Common::kWritePermissionDenied, "Search or write permission denied: "+fileNode.getName());
- if (errno == ENOENT)
- setError(Common::kPathDoesNotExist, "removeSavefile: '"+file.getName()+"' does not exist or path is invalid");
+ if (errno == ENOENT)
+ setError(Common::kPathDoesNotExist, "removeSavefile: '"+fileNode.getName()+"' does not exist or path is invalid");
#endif
- return false;
- } else {
- return true;
+ return false;
+ } else {
+ return true;
+ }
}
}
@@ -171,4 +177,43 @@ Common::String DefaultSaveFileManager::getSavePath() const {
return dir;
}
+void DefaultSaveFileManager::assureCached(const Common::String &savePathName) {
+ // Check that path exists and is usable.
+ checkPath(Common::FSNode(savePathName));
+
+ if (_cachedDirectory == savePathName) {
+ return;
+ }
+
+ _saveFileCache.clear();
+ _cachedDirectory.clear();
+
+ if (getError().getCode() != Common::kNoError) {
+ warning("DefaultSaveFileManager::assureCached: Can not cache path '%s': '%s'", savePathName.c_str(), getErrorDesc().c_str());
+ return;
+ }
+
+ // FSNode can cache its members, thus create it after checkPath to reflect
+ // actual file system state.
+ const Common::FSNode savePath(savePathName);
+
+ Common::FSList children;
+ if (!savePath.getChildren(children, Common::FSNode::kListFilesOnly)) {
+ return;
+ }
+
+ // Build the savefile name cache.
+ for (Common::FSList::const_iterator file = children.begin(), end = children.end(); file != end; ++file) {
+ if (_saveFileCache.contains(file->getName())) {
+ warning("DefaultSaveFileManager::assureCached: Name clash when building cache, ignoring file '%s'", file->getName().c_str());
+ } else {
+ _saveFileCache[file->getName()] = *file;
+ }
+ }
+
+ // Only now store that we cached 'savePathName' to indicate we successfully
+ // cached the directory.
+ _cachedDirectory = savePathName;
+}
+
#endif // !defined(DISABLE_DEFAULT_SAVEFILEMANAGER)
diff --git a/backends/saves/default/default-saves.h b/backends/saves/default/default-saves.h
index 81f45f96b8..bf4ca0229d 100644
--- a/backends/saves/default/default-saves.h
+++ b/backends/saves/default/default-saves.h
@@ -27,6 +27,7 @@
#include "common/savefile.h"
#include "common/str.h"
#include "common/fs.h"
+#include "common/hashmap.h"
/**
* Provides a default savefile manager implementation for common platforms.
@@ -54,6 +55,30 @@ protected:
* Sets the internal error and error message accordingly.
*/
virtual void checkPath(const Common::FSNode &dir);
+
+ /**
+ * Assure that the given save path is cached.
+ *
+ * @param savePathName String representation of save path to cache.
+ */
+ void assureCached(const Common::String &savePathName);
+
+ typedef Common::HashMap<Common::String, Common::FSNode, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> SaveFileCache;
+
+ /**
+ * Cache of all the save files in the currently cached directory.
+ *
+ * Modify with caution because we only re-cache when the save path changed!
+ * This needs to be updated inside at least openForSaving and
+ * removeSavefile.
+ */
+ SaveFileCache _saveFileCache;
+
+private:
+ /**
+ * The currently cached directory.
+ */
+ Common::String _cachedDirectory;
};
#endif
diff --git a/base/commandLine.cpp b/base/commandLine.cpp
index 19702ea36d..105d810460 100644
--- a/base/commandLine.cpp
+++ b/base/commandLine.cpp
@@ -373,6 +373,12 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
// We defer checking whether this is a valid target to a later point.
return s;
} else {
+ // On MacOS X prior to 10.9 the OS is sometimes adding a -psn_X_XXXXXX argument (where X are digits)
+ // to pass the process serial number. We need to ignore it to avoid an error.
+#ifdef MACOSX
+ if (strncmp(s, "-psn_", 5) == 0)
+ continue;
+#endif
bool isLongCmd = (s[0] == '-' && s[1] == '-');
diff --git a/common/savefile.h b/common/savefile.h
index b0c4d31f53..9fca07f9d5 100644
--- a/common/savefile.h
+++ b/common/savefile.h
@@ -56,6 +56,12 @@ typedef WriteStream OutSaveFile;
* i.e. typically save states, but also configuration files and similar
* things.
*
+ * Savefile names represent SaveFiles. These names are case insensitive, that
+ * means a name of "Kq1.000" represents the same savefile as "kq1.000". In
+ * addition, SaveFileManager does not allow for names which contain path
+ * separators like '/' or '\'. This is because we do not support directories
+ * in SaveFileManager.
+ *
* While not declared as a singleton, it is effectively used as such,
* with OSystem::getSavefileManager returning a pointer to the single
* SaveFileManager instances to be used.
@@ -115,49 +121,56 @@ public:
* exports from the Quest for Glory series. QfG5 is a 3D game and won't be
* supported by ScummVM.
*
- * @param name the name of the savefile
- * @param compress toggles whether to compress the resulting save file
- * (default) or not.
- * @return pointer to an OutSaveFile, or NULL if an error occurred.
+ * @param name The name of the savefile.
+ * @param compress Toggles whether to compress the resulting save file
+ * (default) or not.
+ * @return Pointer to an OutSaveFile, or NULL if an error occurred.
*/
virtual OutSaveFile *openForSaving(const String &name, bool compress = true) = 0;
/**
* Open the file with the specified name in the given directory for loading.
- * @param name the name of the savefile
- * @return pointer to an InSaveFile, or NULL if an error occurred.
+ *
+ * @param name The name of the savefile.
+ * @return Pointer to an InSaveFile, or NULL if an error occurred.
*/
virtual InSaveFile *openForLoading(const String &name) = 0;
/**
* Removes the given savefile from the system.
- * @param name the name of the savefile to be removed.
+ *
+ * @param name The name of the savefile to be removed.
* @return true if no error occurred, false otherwise.
*/
virtual bool removeSavefile(const String &name) = 0;
/**
* Renames the given savefile.
- * @param oldName Old name.
- * @param newName New name.
+ *
+ * @param oldName Old name.
+ * @param newName New name.
* @return true if no error occurred. false otherwise.
*/
virtual bool renameSavefile(const String &oldName, const String &newName);
/**
* Copy the given savefile.
- * @param oldName Old name.
- * @param newName New name.
+ *
+ * @param oldName Old name.
+ * @param newName New name.
* @return true if no error occurred. false otherwise.
*/
virtual bool copySavefile(const String &oldName, const String &newName);
/**
- * Request a list of available savegames with a given DOS-style pattern,
- * also known as "glob" in the POSIX world. Refer to the Common::matchString()
- * function to learn about the precise pattern format.
- * @param pattern Pattern to match. Wildcards like * or ? are available.
- * @return list of strings for all present file names.
+ * List available savegames matching a given pattern.
+ *
+ * Our pattern format is based on DOS paterns, also known as "glob" in the
+ * POSIX world. Please refer to the Common::matchString() function to learn
+ * about the precise pattern format.
+ *
+ * @param pattern Pattern to match. Wildcards like * or ? are available.
+ * @return List of strings for all present file names.
* @see Common::matchString()
*/
virtual StringArray listSavefiles(const String &pattern) = 0;
diff --git a/devtools/create_project/msbuild.cpp b/devtools/create_project/msbuild.cpp
index 0f9819c308..a804205c42 100644
--- a/devtools/create_project/msbuild.cpp
+++ b/devtools/create_project/msbuild.cpp
@@ -434,7 +434,11 @@ void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, b
"\t\t\t<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n"
"\t\t\t<EnablePREfast>" << (configuration == "Analysis" ? "true" : "false") << "</EnablePREfast>\n"
"\t\t</ClCompile>\n"
+ "\t\t<Lib>\n"
+ "\t\t\t<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>\n"
+ "\t\t</Lib>\n"
"\t\t<Link>\n"
+ "\t\t\t<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>\n"
"\t\t\t<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\n"
"\t\t\t<SetChecksum>true</SetChecksum>\n";
} else {
diff --git a/engines/bbvs/bbvs.cpp b/engines/bbvs/bbvs.cpp
index d40d5e482f..6ae663479d 100644
--- a/engines/bbvs/bbvs.cpp
+++ b/engines/bbvs/bbvs.cpp
@@ -137,6 +137,21 @@ BbvsEngine::~BbvsEngine() {
}
void BbvsEngine::newGame() {
+ memset(_easterEggInput, 0, sizeof(_easterEggInput));
+ _gameTicks = 0;
+ _playVideoNumber = 0;
+ memset(_inventoryItemStatus, 0, sizeof(_inventoryItemStatus));
+ memset(_gameVars, 0, sizeof(_gameVars));
+ memset(_sceneVisited, 0, sizeof(_sceneVisited));
+
+ _mouseX = 160;
+ _mouseY = 120;
+ _mouseButtons = 0;
+
+ _currVerbNum = kVerbLook;
+ _currTalkObjectIndex = -1;
+ _currSceneNum = 0;
+
_currInventoryItem = -1;
_newSceneNum = 32;
}
@@ -162,24 +177,10 @@ Common::Error BbvsEngine::run() {
_sound = new SoundMan();
allocSnapshot();
- memset(_easterEggInput, 0, sizeof(_easterEggInput));
- _gameTicks = 0;
- _playVideoNumber = 0;
- _bootSaveSlot = -1;
-
- memset(_inventoryItemStatus, 0, sizeof(_inventoryItemStatus));
- memset(_gameVars, 0, sizeof(_gameVars));
- memset(_sceneVisited, 0, sizeof(_sceneVisited));
-
- _mouseX = 160;
- _mouseY = 120;
- _mouseButtons = 0;
+ newGame();
- _currVerbNum = kVerbLook;
- _currInventoryItem = -1;
- _currTalkObjectIndex = -1;
- _currSceneNum = 0;
+ _bootSaveSlot = -1;
_newSceneNum = 31;
if (ConfMan.hasKey("save_slot"))
diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp
index cb42ac0aaa..ad940aaf8b 100644
--- a/engines/saga/interface.cpp
+++ b/engines/saga/interface.cpp
@@ -1862,8 +1862,10 @@ void Interface::drawStatusBar() {
int stringWidth;
int color;
// The default colors in the Spanish version of IHNM are shifted by one
- // Fixes bug #1848016 - "IHNM: Wrong Subtitles Color (Spanish)"
- int offset = (_vm->getLanguage() == Common::ES_ESP) ? 1 : 0;
+ // Fixes bug #1848016 - "IHNM: Wrong Subtitles Color (Spanish)". This
+ // also applies to the German and French versions (bug #7064 - "IHNM:
+ // text mistake in german version").
+ int offset = (_vm->getLanguage() == Common::ES_ESP || _vm->getLanguage() == Common::DE_DEU || _vm->getLanguage() == Common::FR_FRA) ? 1 : 0;
// Disable the status text in IHNM when the chapter is 8
if (_vm->getGameId() == GID_IHNM && _vm->_scene->currentChapterNumber() == 8)
diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp
index 532b59d3c7..77a21e7f93 100644
--- a/engines/saga/saga.cpp
+++ b/engines/saga/saga.cpp
@@ -578,9 +578,11 @@ ColorId SagaEngine::KnownColor2ColorId(KnownColor knownColor) {
}
#ifdef ENABLE_IHNM
} else if (getGameId() == GID_IHNM) {
- // The default colors in the Spanish version of IHNM are shifted by one
- // Fixes bug #1848016 - "IHNM: Wrong Subtitles Color (Spanish)"
- int offset = (getLanguage() == Common::ES_ESP) ? 1 : 0;
+ // The default colors in the Spanish, version of IHNM are shifted by one
+ // Fixes bug #1848016 - "IHNM: Wrong Subtitles Color (Spanish)". This
+ // also applies to the German and French versions (bug #7064 - "IHNM:
+ // text mistake in german version").
+ int offset = (getLanguage() == Common::ES_ESP || getLanguage() == Common::DE_DEU || getLanguage() == Common::FR_FRA) ? 1 : 0;
switch (knownColor) {
case(kKnownColorTransparent):
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index d84500cc60..968eb784b1 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -1651,14 +1651,6 @@ static const struct ADGameDescription SciGameDescriptions[] = {
#ifdef ENABLE_SCI32
- // King's Quest 7 - English Windows (from abevi)
- // VERSION 1.65c
- {"kq7", "", {
- {"resource.000", 0, "4948e4e1506f1e1c4e1d47abfa06b7f8", 204385195},
- {"resource.map", 0, "40ccafb2195301504eba2e4f4f2c7f3d", 18925},
- AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
-
// King's Quest 7 - English Windows (from the King's Quest Collection)
// Executable scanning reports "2.100.002", VERSION file reports "1.4"
{"kq7", "", {
@@ -1667,6 +1659,33 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // King's Quest 7 - English Windows-interpreter-only (supplied by m_kiewitz)
+ // SCI interpreter version 2.100.002, VERSION file reports "1.51"
+ {"kq7", "", {
+ {"resource.map", 0, "838b9ff132bd6962026fee832e8a7ddb", 18697},
+ {"resource.000", 0, "eb63ea3a2c2469dc2d777d351c626404", 206626576},
+ {"resource.aud", 0, "c2a988a16053eb98c7b73a75139902a0", 217716879},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
+ // King's Quest 7 - German Windows-interpreter-only (supplied by markcoolio in bug report #2727402)
+ // SCI interpreter version 2.100.002, VERSION file reports "1.51"
+ // same as English 1.51, only resource.aud/resource.sfx are different
+ {"kq7", "", {
+ {"resource.map", 0, "838b9ff132bd6962026fee832e8a7ddb", 18697},
+ {"resource.000", 0, "eb63ea3a2c2469dc2d777d351c626404", 206626576},
+ {"resource.aud", 0, "3f17bcaf8a9ff6a6c2d4de1a2078fdcc", 258119621},
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
+ // King's Quest 7 - English Windows (from abevi)
+ // VERSION 1.65c
+ {"kq7", "", {
+ {"resource.000", 0, "4948e4e1506f1e1c4e1d47abfa06b7f8", 204385195},
+ {"resource.map", 0, "40ccafb2195301504eba2e4f4f2c7f3d", 18925},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// King's Quest 7 - English DOS (from FRG)
// SCI interpreter version 2.100.002, VERSION file reports "2.00b"
{"kq7", "", {
@@ -1683,14 +1702,6 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
- // King's Quest 7 - German Windows (supplied by markcoolio in bug report #2727402)
- // SCI interpreter version 2.100.002
- {"kq7", "", {
- {"resource.map", 0, "838b9ff132bd6962026fee832e8a7ddb", 18697},
- {"resource.000", 0, "eb63ea3a2c2469dc2d777d351c626404", 206626576},
- AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
-
// King's Quest 7 - Spanish DOS (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "2.00"
{"kq7", "", {
@@ -2635,6 +2646,28 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+ // Phantasmagoria - English DOS/Windows (from csnover)
+ // Windows executable scanning reports "2.100.002" - "Aug 06 1995"
+ // DOS executable scanning reports "2.100.002" - "May 24 1995"
+ // VERSION file reports "1.000.000"
+ {"phantasmagoria", "", {
+ {"resmap.001", 0, "43c395f312a190e67b90b2c1e93a79e2", 11518},
+ {"ressci.001", 0, "3aae6559aa1df273bc542d5ac6330d75", 65844612},
+ {"resmap.002", 0, "94f142cfe8ec4107b6a42876cb603ed0", 12058},
+ {"ressci.002", 0, "3aae6559aa1df273bc542d5ac6330d75", 71588691},
+ {"resmap.003", 0, "39e9abd4501b5b6168dd07379c0be753", 12334},
+ {"ressci.003", 0, "3aae6559aa1df273bc542d5ac6330d75", 73651084},
+ {"resmap.004", 0, "434f9704658229fef322c863d2422a9a", 12556},
+ {"ressci.004", 0, "3aae6559aa1df273bc542d5ac6330d75", 75811935},
+ {"resmap.005", 0, "3ff9b4f7301800825c0ed008e091205e", 12604},
+ {"ressci.005", 0, "3aae6559aa1df273bc542d5ac6330d75", 78814934},
+ {"resmap.006", 0, "27ad413313e2a3ec3c53250e7ff5b2d1", 12532},
+ {"ressci.006", 0, "3aae6559aa1df273bc542d5ac6330d75", 77901360},
+ {"resmap.007", 0, "aa8175cfc93242af6f5e65bdceaafc0d", 7972},
+ //{"ressci.007", 0, "3aae6559aa1df273bc542d5ac6330d75", 25859038},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Phantasmagoria - English DOS (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.100.000UK"
{"phantasmagoria", "", {
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index b992e9742e..62566a74b2 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -412,7 +412,7 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv);
reg_t kTextColors(EngineState *s, int argc, reg_t *argv);
reg_t kTextFonts(EngineState *s, int argc, reg_t *argv);
reg_t kShow(EngineState *s, int argc, reg_t *argv);
-reg_t kRemapColors(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColors16(EngineState *s, int argc, reg_t *argv);
reg_t kDummy(EngineState *s, int argc, reg_t *argv);
reg_t kEmpty(EngineState *s, int argc, reg_t *argv);
reg_t kStub(EngineState *s, int argc, reg_t *argv);
@@ -452,7 +452,14 @@ reg_t kScrollWindowShow(EngineState *s, int argc, reg_t *argv);
reg_t kScrollWindowDestroy(EngineState *s, int argc, reg_t *argv);
reg_t kMulDiv(EngineState *s, int argc, reg_t *argv);
-reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv);
+
+reg_t kRemapColors(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapOff(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapByRange(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapByPercent(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapToGray(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapToPercentGray(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapSetNoMatchRange(EngineState *s, int argc, reg_t *argv);
reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv);
reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv);
@@ -484,6 +491,8 @@ reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv);
reg_t kSetPalStyleRange(EngineState *s, int argc, reg_t *argv);
reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv);
reg_t kFrameOut(EngineState *s, int argc, reg_t *argv);
+reg_t kCelHigh32(EngineState *s, int argc, reg_t *argv);
+reg_t kCelWide32(EngineState *s, int argc, reg_t *argv);
reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv); // kOnMe for SCI2, kIsOnMe for SCI2.1
reg_t kInPolygon(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index e49c6b4015..3463d05e77 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -352,6 +352,17 @@ static const SciKernelMapSubEntry kList_subops[] = {
};
// version, subId, function-mapping, signature, workarounds
+static const SciKernelMapSubEntry kRemapColors_subops[] = {
+ { SIG_SCI32, 0, MAP_CALL(RemapOff), "(i)", NULL },
+ { SIG_SCI32, 1, MAP_CALL(RemapByRange), "iiii(i)", NULL },
+ { SIG_SCI32, 2, MAP_CALL(RemapByPercent), "ii(i)", NULL },
+ { SIG_SCI32, 3, MAP_CALL(RemapToGray), "ii(i)", NULL },
+ { SIG_SCI32, 4, MAP_CALL(RemapToPercentGray), "iii(i)", NULL },
+ { SIG_SCI32, 5, MAP_CALL(RemapSetNoMatchRange), "ii", NULL },
+ SCI_SUBOPENTRY_TERMINATOR
+};
+
+// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kString_subops[] = {
{ SIG_SCI32, 0, MAP_CALL(StringNew), "i(i)", NULL },
{ SIG_SCI32, 1, MAP_CALL(StringSize), "[or]", NULL },
@@ -450,8 +461,12 @@ static SciKernelMapEntry s_kernelMap[] = {
#ifdef ENABLE_SCI32
{ MAP_CALL(CantBeHere), SIG_SCI32, SIGFOR_ALL, "ol", NULL, NULL },
#endif
- { MAP_CALL(CelHigh), SIG_EVERYWHERE, "ii(i)", NULL, kCelHigh_workarounds },
- { MAP_CALL(CelWide), SIG_EVERYWHERE, "ii(i)", NULL, kCelWide_workarounds },
+ { MAP_CALL(CelHigh), SIG_SCI16, SIGFOR_ALL, "ii(i)", NULL, kCelHigh_workarounds },
+ { MAP_CALL(CelWide), SIG_SCI16, SIGFOR_ALL, "ii(i)", NULL, kCelWide_workarounds },
+#ifdef ENABLE_SCI32
+ { "CelHigh", kCelHigh32, SIG_SCI32, SIGFOR_ALL, "iii", NULL, NULL },
+ { "CelWide", kCelWide32, SIG_SCI32, SIGFOR_ALL, "iii", NULL, NULL },
+#endif
{ MAP_CALL(CheckFreeSpace), SIG_SCI32, SIGFOR_ALL, "r.*", NULL, NULL },
{ MAP_CALL(CheckFreeSpace), SIG_SCI11, SIGFOR_ALL, "r(i)", NULL, NULL },
{ MAP_CALL(CheckFreeSpace), SIG_EVERYWHERE, "r", NULL, NULL },
@@ -550,9 +565,9 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(PriCoord), SIG_EVERYWHERE, "i", NULL, NULL },
{ MAP_CALL(Random), SIG_EVERYWHERE, "i(i)(i)", NULL, NULL },
{ MAP_CALL(ReadNumber), SIG_EVERYWHERE, "r", NULL, kReadNumber_workarounds },
- { MAP_CALL(RemapColors), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(i)", NULL, NULL },
+ { "RemapColors", kRemapColors16, SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(i)", NULL, NULL },
#ifdef ENABLE_SCI32
- { "RemapColors", kRemapColors32, SIG_SCI32, SIGFOR_ALL, "i(i)(i)(i)(i)(i)", NULL, NULL },
+ { MAP_CALL(RemapColors), SIG_SCI32, SIGFOR_ALL, "i(i)(i)(i)(i)(i)", kRemapColors_subops, NULL },
#endif
{ MAP_CALL(ResCheck), SIG_EVERYWHERE, "ii(iiii)", NULL, NULL },
{ MAP_CALL(RespondsTo), SIG_EVERYWHERE, ".i", NULL, NULL },
@@ -715,8 +730,8 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(WinHelp), SIG_EVERYWHERE, "(.*)", NULL, NULL },
{ MAP_CALL(GetConfig), SIG_EVERYWHERE, "ro", NULL, NULL },
{ MAP_CALL(GetSierraProfileInt), SIG_EVERYWHERE, "rri", NULL, NULL },
- { MAP_CALL(CelInfo), SIG_EVERYWHERE, "iiiiii", NULL, NULL },
- { MAP_CALL(SetLanguage), SIG_EVERYWHERE, "r", NULL, NULL },
+ { MAP_CALL(CelInfo), SIG_SINCE_SCI21MID, SIGFOR_ALL, "iiiiii", NULL, NULL },
+ { MAP_CALL(SetLanguage), SIG_SINCE_SCI21MID, SIGFOR_ALL, "r", NULL, NULL },
{ MAP_CALL(ScrollWindow), SIG_EVERYWHERE, "i(.*)", kScrollWindow_subops, NULL },
{ MAP_CALL(SetFontRes), SIG_SCI21EARLY, SIGFOR_ALL, "ii", NULL, NULL },
{ MAP_CALL(Font), SIG_SINCE_SCI21MID, SIGFOR_ALL, "i(.*)", kFont_subops, NULL },
diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp
index 254342111b..534d9ce713 100644
--- a/engines/sci/engine/kevent.cpp
+++ b/engines/sci/engine/kevent.cpp
@@ -83,11 +83,12 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
}
// For a real event we use its associated mouse position
- mousePos = curEvent.mousePos;
#ifdef ENABLE_SCI32
- if (getSciVersion() >= SCI_VERSION_2_1_EARLY)
- g_sci->_gfxCoordAdjuster->fromDisplayToScript(mousePos.y, mousePos.x);
+ if (getSciVersion() >= SCI_VERSION_2)
+ mousePos = curEvent.mousePosSci;
+ else
#endif
+ mousePos = curEvent.mousePos;
// Limit the mouse cursor position, if necessary
g_sci->_gfxCursor->refreshPosition();
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index cae5a09789..73236b98ed 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -1258,7 +1258,7 @@ reg_t kShow(EngineState *s, int argc, reg_t *argv) {
}
// Early variant of the SCI32 kRemapColors kernel function, used in the demo of QFG4
-reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) {
+reg_t kRemapColors16(EngineState *s, int argc, reg_t *argv) {
uint16 operation = argv[0].toUint16();
switch (operation) {
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index 93d5ca5ee9..7850a10006 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -45,6 +45,7 @@
#include "sci/graphics/paint16.h"
#include "sci/graphics/picture.h"
#include "sci/graphics/ports.h"
+#include "sci/graphics/remap.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/text16.h"
#include "sci/graphics/view.h"
@@ -73,19 +74,19 @@ reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv) {
reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv) {
debugC(6, kDebugLevelGraphics, "kAddScreenItem %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0]));
g_sci->_gfxFrameout->kernelAddScreenItem(argv[0]);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv) {
debugC(7, kDebugLevelGraphics, "kUpdateScreenItem %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0]));
g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv) {
debugC(6, kDebugLevelGraphics, "kDeleteScreenItem %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0]));
g_sci->_gfxFrameout->kernelDeleteScreenItem(argv[0]);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kAddPlane(EngineState *s, int argc, reg_t *argv) {
@@ -113,7 +114,7 @@ reg_t kMovePlaneItems(EngineState *s, int argc, reg_t *argv) {
const bool scrollPics = argc > 3 ? argv[3].toUint16() : false;
g_sci->_gfxFrameout->kernelMovePlaneItems(plane, deltaX, deltaY, scrollPics);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kAddPicAt(EngineState *s, int argc, reg_t *argv) {
@@ -124,7 +125,7 @@ reg_t kAddPicAt(EngineState *s, int argc, reg_t *argv) {
bool mirrorX = argc > 4 ? argv[4].toSint16() : false;
g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, x, y, mirrorX);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv) {
@@ -136,12 +137,12 @@ reg_t kFrameOut(EngineState *s, int argc, reg_t *argv) {
g_sci->_gfxFrameout->kernelFrameOut(showBits);
s->speedThrottler(16);
s->_throttleTrigger = true;
- return NULL_REG;
+ return s->r_acc;
}
reg_t kSetPalStyleRange(EngineState *s, int argc, reg_t *argv) {
g_sci->_gfxFrameout->kernelSetPalStyleRange(argv[0].toUint16(), argv[1].toUint16());
- return NULL_REG;
+ return s->r_acc;
}
reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv) {
@@ -227,7 +228,7 @@ reg_t kTextSize32(EngineState *s, int argc, reg_t *argv) {
rect[1] = make_reg(0, textRect.top);
rect[2] = make_reg(0, textRect.right - 1);
rect[3] = make_reg(0, textRect.bottom - 1);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kTextWidth(EngineState *s, int argc, reg_t *argv) {
@@ -306,31 +307,50 @@ reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) {
// on the KernelMgr
g_sci->_gfxFrameout->kernelSetShowStyle(argc, planeObj, type, seconds, back, priority, animate, refFrame, pFadeArray, divisions, blackScreen);
- return NULL_REG;
+ return s->r_acc;
+}
+
+reg_t kCelHigh32(EngineState *s, int argc, reg_t *argv) {
+ GuiResourceId resourceId = argv[0].toUint16();
+ int16 loopNo = argv[1].toSint16();
+ int16 celNo = argv[2].toSint16();
+ CelObjView celObj(resourceId, loopNo, celNo);
+ return make_reg(0, mulru(celObj._height, Ratio(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight, celObj._scaledHeight)));
+}
+
+reg_t kCelWide32(EngineState *s, int argc, reg_t *argv) {
+ GuiResourceId resourceId = argv[0].toUint16();
+ int16 loopNo = argv[1].toSint16();
+ int16 celNo = argv[2].toSint16();
+ CelObjView celObj(resourceId, loopNo, celNo);
+ return make_reg(0, mulru(celObj._width, Ratio(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth, celObj._scaledWidth)));
}
reg_t kCelInfo(EngineState *s, int argc, reg_t *argv) {
// Used by Shivers 1, room 23601 to determine what blocks on the red door puzzle board
// are occupied by pieces already
- switch (argv[0].toUint16()) { // subops 0 - 4
- // 0 - return the view
- // 1 - return the loop
- // 2, 3 - nop
- case 4: {
- GuiResourceId viewId = argv[1].toSint16();
- int16 loopNo = argv[2].toSint16();
- int16 celNo = argv[3].toSint16();
- int16 x = argv[4].toUint16();
- int16 y = argv[5].toUint16();
- byte color = g_sci->_gfxCache->kernelViewGetColorAtCoordinate(viewId, loopNo, celNo, x, y);
- return make_reg(0, color);
- }
- default: {
- kStub(s, argc, argv);
- return s->r_acc;
- }
+ CelObjView view(argv[1].toUint16(), argv[2].toSint16(), argv[3].toSint16());
+
+ int16 result = 0;
+
+ switch (argv[0].toUint16()) {
+ case 0:
+ result = view._displace.x;
+ break;
+ case 1:
+ result = view._displace.y;
+ break;
+ case 2:
+ case 3:
+ // null operation
+ break;
+ case 4:
+ result = view.readPixel(argv[4].toSint16(), argv[5].toSint16(), view._mirrorX);
+ break;
}
+
+ return make_reg(0, result);
}
reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) {
@@ -487,13 +507,13 @@ reg_t kSetFontHeight(EngineState *s, int argc, reg_t *argv) {
// which case we could just get the font directly ourselves.
g_sci->_gfxText32->setFont(argv[0].toUint16());
g_sci->_gfxText32->_scaledHeight = (g_sci->_gfxText32->_font->getHeight() * g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight + g_sci->_gfxText32->_scaledHeight - 1) / g_sci->_gfxText32->_scaledHeight;
- return NULL_REG;
+ return make_reg(0, g_sci->_gfxText32->_scaledHeight);
}
reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv) {
g_sci->_gfxText32->_scaledWidth = argv[0].toUint16();
g_sci->_gfxText32->_scaledHeight = argv[1].toUint16();
- return NULL_REG;
+ return s->r_acc;
}
reg_t kBitmap(EngineState *s, int argc, reg_t *argv) {
@@ -518,7 +538,7 @@ reg_t kBitmapCreate(EngineState *s, int argc, reg_t *argv) {
reg_t kBitmapDestroy(EngineState *s, int argc, reg_t *argv) {
s->_segMan->freeHunkEntry(argv[0]);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kBitmapDrawLine(EngineState *s, int argc, reg_t *argv) {
@@ -572,7 +592,6 @@ reg_t kBitmapDrawView(EngineState *s, int argc, reg_t *argv) {
reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) {
// called e.g. from TextButton::createBitmap() in Torin's Passage, script 64894
- // bitmap, text, textLeft, textTop, textRight, textBottom, foreColor, backColor, skipColor, fontNo, alignment, borderColor, dimmed
BitmapResource bitmap(argv[0]);
Common::String text = s->_segMan->getString(argv[1]);
Common::Rect textRect(
@@ -603,36 +622,23 @@ reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) {
textCel.draw(bitmapBuffer, textRect, Common::Point(textRect.left, textRect.top), false);
s->_segMan->freeHunkEntry(textBitmapObject);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kBitmapDrawColor(EngineState *s, int argc, reg_t *argv) {
- // bitmap, left, top, right, bottom, color
-
// called e.g. from TextView::init() and TextView::draw() in Torin's Passage, script 64890
- return kStubNull(s, argc + 1, argv - 1);
-#if 0
- reg_t hunkId = argv[1]; // obtained from kBitmap(0)
- uint16 x = argv[2].toUint16();
- uint16 y = argv[3].toUint16();
- uint16 fillWidth = argv[4].toUint16(); // width - 1
- uint16 fillHeight = argv[5].toUint16(); // height - 1
- uint16 back = argv[6].toUint16();
- byte *memoryPtr = s->_segMan->getHunkPointer(hunkId);
- // Get totalWidth, totalHeight
- uint16 totalWidth = READ_LE_UINT16(memoryPtr);
- uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2);
- uint16 width = MIN<uint16>(totalWidth - x, fillWidth);
- uint16 height = MIN<uint16>(totalHeight - y, fillHeight);
- byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE;
+ BitmapResource bitmap(argv[0]);
+ Common::Rect fillRect(
+ argv[1].toSint16(),
+ argv[2].toSint16(),
+ argv[3].toSint16() + 1,
+ argv[4].toSint16() + 1
+ );
- for (uint16 curY = 0; curY < height; curY++) {
- for (uint16 curX = 0; curX < width; curX++) {
- bitmap[(curY + y) * totalWidth + (curX + x)] = back;
- }
- }
-#endif
+ Buffer buffer(bitmap.getWidth(), bitmap.getHeight(), bitmap.getPixels());
+ buffer.fillRect(fillRect, argv[5].toSint16());
+ return s->r_acc;
}
reg_t kBitmapDrawBitmap(EngineState *s, int argc, reg_t *argv) {
@@ -648,9 +654,9 @@ reg_t kBitmapInvert(EngineState *s, int argc, reg_t *argv) {
}
reg_t kBitmapSetDisplace(EngineState *s, int argc, reg_t *argv) {
- // bitmap, x, y
-
- return kStubNull(s, argc + 1, argv - 1);
+ BitmapResource bitmap(argv[0]);
+ bitmap.setDisplace(Common::Point(argv[1].toSint16(), argv[2].toSint16()));
+ return s->r_acc;
}
reg_t kBitmapCreateFromView(EngineState *s, int argc, reg_t *argv) {
@@ -700,12 +706,12 @@ reg_t kAddLine(EngineState *s, int argc, reg_t *argv) {
reg_t plane = argv[0];
Common::Point startPoint(argv[1].toUint16(), argv[2].toUint16());
Common::Point endPoint(argv[3].toUint16(), argv[4].toUint16());
- // argv[5] is unknown (a number, usually 200)
+ byte priority = (byte)argv[5].toUint16();
byte color = (byte)argv[6].toUint16();
- byte priority = (byte)argv[7].toUint16();
- byte control = (byte)argv[8].toUint16();
- // argv[9] is unknown (usually a small number, 1 or 2). Thickness, perhaps?
-// return g_sci->_gfxFrameout->addPlaneLine(plane, startPoint, endPoint, color, priority, control);
+ byte style = (byte)argv[7].toUint16(); // 0: solid, 1: dashed, 2: pattern
+ byte pattern = (byte)argv[8].toUint16();
+ byte thickness = (byte)argv[9].toUint16();
+// return g_sci->_gfxFrameout->addPlaneLine(plane, startPoint, endPoint, color, priority, 0);
return s->r_acc;
#endif
}
@@ -764,7 +770,7 @@ reg_t kSetScroll(EngineState *s, int argc, reg_t *argv) {
// Used by SQ6, script 900, the datacorder reprogramming puzzle (from room 270)
reg_t kMorphOn(EngineState *s, int argc, reg_t *argv) {
g_sci->_gfxFrameout->_palMorphIsOn = true;
- return NULL_REG;
+ return s->r_acc;
}
reg_t kPaletteSetFade(EngineState *s, int argc, reg_t *argv) {
@@ -772,7 +778,7 @@ reg_t kPaletteSetFade(EngineState *s, int argc, reg_t *argv) {
uint16 toColor = argv[1].toUint16();
uint16 percent = argv[2].toUint16();
g_sci->_gfxPalette32->setFade(percent, fromColor, toColor);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kPalVarySetVary(EngineState *s, int argc, reg_t *argv) {
@@ -790,18 +796,14 @@ reg_t kPalVarySetVary(EngineState *s, int argc, reg_t *argv) {
}
g_sci->_gfxPalette32->kernelPalVarySet(paletteId, percent, time, fromColor, toColor);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kPalVarySetPercent(EngineState *s, int argc, reg_t *argv) {
int time = argc > 0 ? argv[0].toSint16() * 60 : 0;
int16 percent = argc > 1 ? argv[1].toSint16() : 0;
-
- // TODO: GK1 adds a third optional parameter here, at the end of chapter 1
- // (during the sunset/sunrise sequence, the parameter is 1)
-
g_sci->_gfxPalette32->setVaryPercent(percent, time, -1, -1);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kPalVaryGetPercent(EngineState *s, int argc, reg_t *argv) {
@@ -810,7 +812,7 @@ reg_t kPalVaryGetPercent(EngineState *s, int argc, reg_t *argv) {
reg_t kPalVaryOff(EngineState *s, int argc, reg_t *argv) {
g_sci->_gfxPalette32->varyOff();
- return NULL_REG;
+ return s->r_acc;
}
reg_t kPalVaryMergeTarget(EngineState *s, int argc, reg_t *argv) {
@@ -822,7 +824,7 @@ reg_t kPalVaryMergeTarget(EngineState *s, int argc, reg_t *argv) {
reg_t kPalVarySetTime(EngineState *s, int argc, reg_t *argv) {
int time = argv[0].toSint16() * 60;
g_sci->_gfxPalette32->setVaryTime(time);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kPalVarySetTarget(EngineState *s, int argc, reg_t *argv) {
@@ -907,79 +909,57 @@ reg_t kPalCycle(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
-reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) {
- // TODO
-#if 0
- uint16 operation = argv[0].toUint16();
-
- switch (operation) {
- case 0: { // turn remapping off
- // WORKAROUND: Game scripts in QFG4 erroneously turn remapping off in room
- // 140 (the character point allocation screen) and never turn it back on,
- // even if it's clearly used in that screen.
- if (g_sci->getGameId() == GID_QFG4 && s->currentRoomNumber() == 140)
- return s->r_acc;
-
- int16 color = (argc >= 2) ? argv[1].toSint16() : 0;
- if (color > 0)
- warning("kRemapColors(0) called with base %d", color);
- //g_sci->_gfxPalette32->resetRemapping();
- }
- break;
- case 1: { // remap by range
- uint16 color = argv[1].toUint16();
- uint16 from = argv[2].toUint16();
- uint16 to = argv[3].toUint16();
- uint16 delta = argv[4].toUint16();
- uint16 depth = (argc >= 6) ? argv[5].toUint16() : 0;
- if (depth > 0)
- warning("kRemapColors(1) called with 6 parameters, depth is %d", depth);
- //g_sci->_gfxPalette32->setRemappingRange(color, from, to, delta);
- }
- break;
- case 2: { // remap by percent
- uint16 color = argv[1].toUint16();
- uint16 percent = argv[2].toUint16(); // 0 - 100
- uint16 depth = (argc >= 4) ? argv[3].toUint16() : 0;
- if (depth >= 0)
- warning("RemapByPercent called with 4 parameters, depth is %d", depth);
- //g_sci->_gfxPalette32->setRemappingPercent(color, percent);
- }
- break;
- case 3: { // remap to gray
- // Example call: QFG4 room 490 (Baba Yaga's hut) - params are color 253, 75% and 0.
- // In this room, it's used for the cloud before Baba Yaga appears.
- uint16 color = argv[1].toUint16();
- uint16 percent = argv[2].toUint16(); // 0 - 100
- uint16 depth = (argc >= 4) ? argv[3].toUint16() : 0;
- if (depth >= 0)
- warning("RemapToGray called with 4 parameters, depth is %d", depth);
- //g_sci->_gfxPalette32->setRemappingPercentGray(color, percent);
- }
- break;
- case 4: { // remap to percent gray
- // Example call: QFG4 rooms 530/535 (swamp) - params are 253, 100%, 200
- uint16 color = argv[1].toUint16();
- uint16 percent = argv[2].toUint16(); // 0 - 100
- uint16 grayPercent = argv[3].toUint16();
- uint16 depth = (argc >= 5) ? argv[4].toUint16() : 0;
- if (argc >= 5)
- warning("RemapToGrayPercent called with 5 parameters, depth is %d", depth);
- //g_sci->_gfxPalette32->setRemappingPercentGray(color, percent);
- }
- break;
- case 5: { // don't map to range
- //uint16 start = argv[1].toSint16();
- //uint16 count = argv[2].toUint16();
+reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) {
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
- kStub(s, argc, argv);
- }
- break;
- default:
- break;
- }
-#endif
+reg_t kRemapOff(EngineState *s, int argc, reg_t *argv) {
+ byte color = (argc >= 1) ? argv[0].toUint16() : 0;
+ g_sci->_gfxRemap32->remapOff(color);
+ return s->r_acc;
+}
+
+reg_t kRemapByRange(EngineState *s, int argc, reg_t *argv) {
+ byte color = argv[0].toUint16();
+ byte from = argv[1].toUint16();
+ byte to = argv[2].toUint16();
+ byte base = argv[3].toUint16();
+ // The last parameter, depth, is unused
+ g_sci->_gfxRemap32->setRemappingRange(color, from, to, base);
+ return s->r_acc;
+}
+
+reg_t kRemapByPercent(EngineState *s, int argc, reg_t *argv) {
+ byte color = argv[0].toUint16();
+ byte percent = argv[1].toUint16();
+ // The last parameter, depth, is unused
+ g_sci->_gfxRemap32->setRemappingPercent(color, percent);
+ return s->r_acc;
+}
+
+reg_t kRemapToGray(EngineState *s, int argc, reg_t *argv) {
+ byte color = argv[0].toUint16();
+ byte gray = argv[1].toUint16();
+ // The last parameter, depth, is unused
+ g_sci->_gfxRemap32->setRemappingToGray(color, gray);
+ return s->r_acc;
+}
+
+reg_t kRemapToPercentGray(EngineState *s, int argc, reg_t *argv) {
+ byte color = argv[0].toUint16();
+ byte gray = argv[1].toUint16();
+ byte percent = argv[2].toUint16();
+ // The last parameter, depth, is unused
+ g_sci->_gfxRemap32->setRemappingToPercentGray(color, gray, percent);
+ return s->r_acc;
+}
+reg_t kRemapSetNoMatchRange(EngineState *s, int argc, reg_t *argv) {
+ byte from = argv[0].toUint16();
+ byte count = argv[1].toUint16();
+ g_sci->_gfxRemap32->setNoMatchRange(from, count);
return s->r_acc;
}
diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp
index f598cf7457..1c08bf597c 100644
--- a/engines/sci/engine/kstring.cpp
+++ b/engines/sci/engine/kstring.cpp
@@ -765,11 +765,14 @@ reg_t kStringCopy(EngineState *s, int argc, reg_t *argv) {
}
// The original engine ignores bad copies too
- if (index2 > string2Size)
+ if (index2 >= string2Size)
return NULL_REG;
// A count of -1 means fill the rest of the array
- uint32 count = argv[4].toSint16() == -1 ? string2Size - index2 + 1 : argv[4].toUint16();
+ uint32 count = string2Size - index2;
+ if (argv[4].toSint16() != -1) {
+ count = MIN(count, (uint32)argv[4].toUint16());
+ }
// reg_t strAddress = argv[0];
SciString *string1 = s->_segMan->lookupString(argv[0]);
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index ae7ab431f8..fcb65157d8 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -1012,6 +1012,26 @@ void gamestate_afterRestoreFixUp(EngineState *s, int savegameId) {
g_sci->_gfxMenu->kernelSetAttribute(1025 >> 8, 1025 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Status -> Statistics
g_sci->_gfxMenu->kernelSetAttribute(1026 >> 8, 1026 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Status -> Goals
break;
+ case GID_KQ6:
+ if (g_sci->isCD()) {
+ // WORKAROUND:
+ // For the CD version of King's Quest 6, set global depending on current hires/lowres state
+ // The game sets a global at the start depending on it and some things check that global
+ // instead of checking platform like for example the game action menu.
+ // This never happened in the original interpreter, because the original DOS interpreter
+ // was only capable of lowres graphics and the original Windows 3.11 interpreter was only capable
+ // of hires graphics. Saved games were not compatible between those two.
+ // Which means saving during lowres mode, then going into hires mode and restoring that saved game,
+ // will result in some graphics being incorrect (lowres).
+ // That's why we are setting the global after restoring a saved game depending on hires/lowres state.
+ // The CD demo of KQ6 does the same and uses the exact same global.
+ if ((g_sci->getPlatform() == Common::kPlatformWindows) || (g_sci->forceHiresGraphics())) {
+ s->variables[VAR_GLOBAL][0xA9].setOffset(1);
+ } else {
+ s->variables[VAR_GLOBAL][0xA9].setOffset(0);
+ }
+ }
+ break;
case GID_PQ2:
// HACK: Same as above - enable the save game menu option when loading in PQ2 (bug #6875).
// It gets disabled in the game's death screen.
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index a4e19dc8b9..3832f4cf04 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -378,6 +378,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_SQ6, -1, 64950, -1, "Feature", "handleEvent", NULL, 0, { WORKAROUND_FAKE, 0 } }, // called when pressing "Start game" in the main menu, when entering the Orion's Belt bar (room 300), and perhaps other places
{ GID_SQ6, -1, 64964, 0, "DPath", "init", NULL, 1, { WORKAROUND_FAKE, 0 } }, // during the game
{ GID_TORIN, -1, 64017, 0, "oFlags", "clear", NULL, 0, { WORKAROUND_FAKE, 0 } }, // entering Torin's home in the French version
+ { GID_TORIN, 10000, 64029, 0, "oMessager", "nextMsg", NULL, 3, { WORKAROUND_FAKE, 0 } }, // start of chapter one
SCI_WORKAROUNDENTRY_TERMINATOR
};
diff --git a/engines/sci/graphics/cache.cpp b/engines/sci/graphics/cache.cpp
index 59af8334eb..fb1f557ad6 100644
--- a/engines/sci/graphics/cache.cpp
+++ b/engines/sci/graphics/cache.cpp
@@ -102,8 +102,4 @@ int16 GfxCache::kernelViewGetCelCount(GuiResourceId viewId, int16 loopNo) {
return getView(viewId)->getCelCount(loopNo);
}
-byte GfxCache::kernelViewGetColorAtCoordinate(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 x, int16 y) {
- return getView(viewId)->getColorAtCoordinate(loopNo, celNo, x, y);
-}
-
} // End of namespace Sci
diff --git a/engines/sci/graphics/cache.h b/engines/sci/graphics/cache.h
index 33fa4fe399..61952718a9 100644
--- a/engines/sci/graphics/cache.h
+++ b/engines/sci/graphics/cache.h
@@ -49,8 +49,6 @@ public:
int16 kernelViewGetLoopCount(GuiResourceId viewId);
int16 kernelViewGetCelCount(GuiResourceId viewId, int16 loopNo);
- byte kernelViewGetColorAtCoordinate(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 x, int16 y);
-
private:
void purgeFontCache();
void purgeViewCache();
diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp
index 389270ec42..693bc5f196 100644
--- a/engines/sci/graphics/celobj32.cpp
+++ b/engines/sci/graphics/celobj32.cpp
@@ -27,6 +27,7 @@
#include "sci/graphics/frameout.h"
#include "sci/graphics/palette32.h"
#include "sci/graphics/picture.h"
+#include "sci/graphics/remap.h"
#include "sci/graphics/text32.h"
#include "sci/graphics/view.h"
@@ -109,25 +110,42 @@ void CelObj::deinit() {
template<bool FLIP, typename READER>
struct SCALER_NoScale {
+#ifndef NDEBUG
+ const byte *_rowEdge;
+#endif
const byte *_row;
READER _reader;
const int16 _lastIndex;
+ const int16 _sourceX;
+ const int16 _sourceY;
- SCALER_NoScale(const CelObj &celObj, const int16 maxWidth) :
+ SCALER_NoScale(const CelObj &celObj, const int16 maxWidth, const Common::Point &scaledPosition) :
_reader(celObj, FLIP ? celObj._width : maxWidth),
- _lastIndex(celObj._width - 1) {}
+ _lastIndex(celObj._width - 1),
+ _sourceX(scaledPosition.x),
+ _sourceY(scaledPosition.y) {}
- inline void setSource(const int16 x, const int16 y) {
- _row = _reader.getRow(y);
+ inline void setTarget(const int16 x, const int16 y) {
+ _row = _reader.getRow(y - _sourceY);
if (FLIP) {
- _row += _lastIndex - x;
+#ifndef NDEBUG
+ _rowEdge = _row - 1;
+#endif
+ _row += _lastIndex - (x - _sourceX);
+ assert(_row > _rowEdge);
} else {
- _row += x;
+#ifndef NDEBUG
+ _rowEdge = _row + _lastIndex + 1;
+#endif
+ _row += x - _sourceX;
+ assert(_row < _rowEdge);
}
}
inline byte read() {
+ assert(_row != _rowEdge);
+
if (FLIP) {
return *_row--;
} else {
@@ -138,55 +156,96 @@ struct SCALER_NoScale {
template<bool FLIP, typename READER>
struct SCALER_Scale {
+#ifndef NDEBUG
+ int16 _maxX;
+#endif
const byte *_row;
READER _reader;
- const CelScalerTable *_table;
int16 _x;
- const uint16 _lastIndex;
+ static int16 _valuesX[1024];
+ static int16 _valuesY[1024];
- SCALER_Scale(const CelObj &celObj, const int16 maxWidth, const Ratio scaleX, const Ratio scaleY) :
+ SCALER_Scale(const CelObj &celObj, const Common::Rect &targetRect, const Common::Point &scaledPosition, const Ratio scaleX, const Ratio scaleY) :
+#ifndef NDEBUG
+ _maxX(targetRect.right - 1),
+#endif
// The maximum width of the scaled object may not be as
// wide as the source data it requires if downscaling,
// so just always make the reader decompress an entire
// line of source data when scaling
- _reader(celObj, celObj._width),
- _table(CelObj::_scaler->getScalerTable(scaleX, scaleY)),
- _lastIndex(maxWidth - 1) {}
-
- inline void setSource(const int16 x, const int16 y) {
- _row = _reader.getRow(_table->valuesY[y]);
+ _reader(celObj, celObj._width) {
+ // In order for scaling ratios to apply equally across objects that
+ // start at different positions on the screen, the pixels that are
+ // read from the source bitmap must all use the same pattern of
+ // division. In other words, cels must follow the same scaling pattern
+ // as if they were drawn starting at an even multiple of the scaling
+ // ratio, even if they were not.
+ //
+ // To get the correct source pixel when reading out through the scaler,
+ // the engine creates a lookup table for each axis that translates
+ // directly from target positions to the indexes of source pixels using
+ // the global cadence for the given scaling ratio.
+
+ const CelScalerTable *table = CelObj::_scaler->getScalerTable(scaleX, scaleY);
+
+ const int16 unscaledX = (scaledPosition.x / scaleX).toInt();
if (FLIP) {
- _x = _lastIndex - x;
+ int lastIndex = celObj._width - 1;
+ for (int16 x = targetRect.left; x < targetRect.right; ++x) {
+ _valuesX[x] = lastIndex - (table->valuesX[x] - unscaledX);
+ }
} else {
- _x = x;
+ for (int16 x = targetRect.left; x < targetRect.right; ++x) {
+ _valuesX[x] = table->valuesX[x] - unscaledX;
+ }
+ }
+
+ const int16 unscaledY = (scaledPosition.y / scaleY).toInt();
+ for (int16 y = targetRect.top; y < targetRect.bottom; ++y) {
+ _valuesY[y] = table->valuesY[y] - unscaledY;
}
}
+ inline void setTarget(const int16 x, const int16 y) {
+ _row = _reader.getRow(_valuesY[y]);
+ _x = x;
+ assert(_x >= 0 && _x <= _maxX);
+ }
+
inline byte read() {
- if (FLIP) {
- return _row[_table->valuesX[_x--]];
- } else {
- return _row[_table->valuesX[_x++]];
- }
+ assert(_x >= 0 && _x <= _maxX);
+ return _row[_valuesX[_x++]];
}
};
+template<bool FLIP, typename READER>
+int16 SCALER_Scale<FLIP, READER>::_valuesX[1024];
+template<bool FLIP, typename READER>
+int16 SCALER_Scale<FLIP, READER>::_valuesY[1024];
+
#pragma mark -
#pragma mark CelObj - Resource readers
struct READER_Uncompressed {
private:
+#ifndef NDEBUG
+ const int16 _sourceHeight;
+#endif
byte *_pixels;
const int16 _sourceWidth;
public:
READER_Uncompressed(const CelObj &celObj, const int16) :
+#ifndef NDEBUG
+ _sourceHeight(celObj._height),
+#endif
_sourceWidth(celObj._width) {
byte *resource = celObj.getResPointer();
_pixels = resource + READ_SCI11ENDIAN_UINT32(resource + celObj._celHeaderOffset + 24);
}
inline const byte *getRow(const int16 y) const {
+ assert(y >= 0 && y < _sourceHeight);
return _pixels + y * _sourceWidth;
}
};
@@ -210,7 +269,7 @@ public:
_sourceHeight(celObj._height),
_transparentColor(celObj._transparentColor),
_maxWidth(maxWidth) {
- assert(_maxWidth <= celObj._width);
+ assert(maxWidth <= celObj._width);
byte *celHeader = _resource + celObj._celHeaderOffset;
_dataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 24);
@@ -219,6 +278,7 @@ public:
}
inline const byte *getRow(const int16 y) {
+ assert(y >= 0 && y < _sourceHeight);
if (y != _y) {
// compressed data segment for row
byte *row = _resource + _dataOffset + READ_SCI11ENDIAN_UINT32(_resource + _controlOffset + y * 4);
@@ -227,7 +287,7 @@ public:
byte *literal = _resource + _uncompressedDataOffset + READ_SCI11ENDIAN_UINT32(_resource + _controlOffset + _sourceHeight * 4 + y * 4);
uint8 length;
- for (int i = 0; i < _maxWidth; i += length) {
+ for (int16 i = 0; i < _maxWidth; i += length) {
byte controlByte = *row++;
length = controlByte;
@@ -274,153 +334,101 @@ struct MAPPER_NoMDNoSkip {
}
};
+struct MAPPER_Map {
+ inline void draw(byte *target, const byte pixel, const uint8 skipColor) const {
+ if (pixel != skipColor) {
+ if (pixel < g_sci->_gfxRemap32->getStartColor()) {
+ *target = pixel;
+ } else {
+ if (g_sci->_gfxRemap32->remapEnabled(pixel))
+ *target = g_sci->_gfxRemap32->remapColor(pixel, *target);
+ }
+ }
+ }
+};
+
void CelObj::draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect) const {
- const Buffer &priorityMap = g_sci->_gfxFrameout->getPriorityMap();
const Common::Point &scaledPosition = screenItem._scaledPosition;
const Ratio &scaleX = screenItem._ratioX;
const Ratio &scaleY = screenItem._ratioY;
if (_remap) {
- if (g_sci->_gfxFrameout->_hasRemappedScreenItem) {
- const uint8 priority = MAX((int16)0, MIN((int16)255, screenItem._priority));
-
- // NOTE: In the original engine code, there was a second branch for
- // _remap here that would then call the following functions if _remap was false:
- //
- // drawHzFlip(Buffer &, Buffer &, Common::Rect &, Common::Point &, uint8)
- // drawNoFlip(Buffer &, Buffer &, Common::Rect &, Common::Point &, uint8)
- // drawUncompHzFlip(Buffer &, Buffer &, Common::Rect &, Common::Point &, uint8)
- // drawUncompNoFlip(Buffer &, Buffer &, Common::Rect &, Common::Point &, uint8)
- // scaleDraw(Buffer &, Buffer &, Ratio &, Ratio &, Common::Rect &, Common::Point &, uint8)
- // scaleDrawUncomp(Buffer &, Buffer &, Ratio &, Ratio &, Common::Rect &, Common::Point &, uint8)
- //
- // However, obviously, _remap cannot be false here. This dead code branch existed in
- // at least SCI2/GK1 and SCI2.1/SQ6.
-
+ // NOTE: In the original code this check was `g_Remap_numActiveRemaps && _remap`,
+ // but since we are already in a `_remap` branch, there is no reason to check it
+ // again
+ if (g_sci->_gfxRemap32->getRemapCount()) {
if (scaleX.isOne() && scaleY.isOne()) {
if (_compressionType == kCelCompressionNone) {
if (_drawMirrored) {
- drawUncompHzFlipMap(target, priorityMap, targetRect, scaledPosition, priority);
+ drawUncompHzFlipMap(target, targetRect, scaledPosition);
} else {
- drawUncompNoFlipMap(target, priorityMap, targetRect, scaledPosition, priority);
+ drawUncompNoFlipMap(target, targetRect, scaledPosition);
}
} else {
if (_drawMirrored) {
- drawHzFlipMap(target, priorityMap, targetRect, scaledPosition, priority);
+ drawHzFlipMap(target, targetRect, scaledPosition);
} else {
- drawNoFlipMap(target, priorityMap, targetRect, scaledPosition, priority);
+ drawNoFlipMap(target, targetRect, scaledPosition);
}
}
} else {
if (_compressionType == kCelCompressionNone) {
- scaleDrawUncompMap(target, priorityMap, scaleX, scaleY, targetRect, scaledPosition, priority);
+ scaleDrawUncompMap(target, scaleX, scaleY, targetRect, scaledPosition);
} else {
- scaleDrawMap(target, priorityMap, scaleX, scaleY, targetRect, scaledPosition, priority);
+ scaleDrawMap(target, scaleX, scaleY, targetRect, scaledPosition);
}
}
} else {
- // NOTE: In the original code this check was `g_Remap_numActiveRemaps && _remap`,
- // but since we are already in a `_remap` branch, there is no reason to check it
- // again
- if (/* TODO: g_Remap_numActiveRemaps */ false) {
- if (scaleX.isOne() && scaleY.isOne()) {
- if (_compressionType == kCelCompressionNone) {
- if (_drawMirrored) {
- drawUncompHzFlipMap(target, targetRect, scaledPosition);
- } else {
- drawUncompNoFlipMap(target, targetRect, scaledPosition);
- }
+ if (scaleX.isOne() && scaleY.isOne()) {
+ if (_compressionType == kCelCompressionNone) {
+ if (_drawMirrored) {
+ drawUncompHzFlip(target, targetRect, scaledPosition);
} else {
- if (_drawMirrored) {
- drawHzFlipMap(target, targetRect, scaledPosition);
- } else {
- drawNoFlipMap(target, targetRect, scaledPosition);
- }
+ drawUncompNoFlip(target, targetRect, scaledPosition);
}
} else {
- if (_compressionType == kCelCompressionNone) {
- scaleDrawUncompMap(target, scaleX, scaleY, targetRect, scaledPosition);
+ if (_drawMirrored) {
+ drawHzFlip(target, targetRect, scaledPosition);
} else {
- scaleDrawMap(target, scaleX, scaleY, targetRect, scaledPosition);
+ drawNoFlip(target, targetRect, scaledPosition);
}
}
} else {
- if (scaleX.isOne() && scaleY.isOne()) {
- if (_compressionType == kCelCompressionNone) {
- if (_drawMirrored) {
- drawUncompHzFlip(target, targetRect, scaledPosition);
- } else {
- drawUncompNoFlip(target, targetRect, scaledPosition);
- }
- } else {
- if (_drawMirrored) {
- drawHzFlip(target, targetRect, scaledPosition);
- } else {
- drawNoFlip(target, targetRect, scaledPosition);
- }
- }
+ if (_compressionType == kCelCompressionNone) {
+ scaleDrawUncomp(target, scaleX, scaleY, targetRect, scaledPosition);
} else {
- if (_compressionType == kCelCompressionNone) {
- scaleDrawUncomp(target, scaleX, scaleY, targetRect, scaledPosition);
- } else {
- scaleDraw(target, scaleX, scaleY, targetRect, scaledPosition);
- }
+ scaleDraw(target, scaleX, scaleY, targetRect, scaledPosition);
}
}
}
} else {
- if (g_sci->_gfxFrameout->_hasRemappedScreenItem) {
- const uint8 priority = MAX((int16)0, MIN((int16)255, screenItem._priority));
- if (scaleX.isOne() && scaleY.isOne()) {
- if (_compressionType == kCelCompressionNone) {
+ if (scaleX.isOne() && scaleY.isOne()) {
+ if (_compressionType == kCelCompressionNone) {
+ if (_transparent) {
if (_drawMirrored) {
- drawUncompHzFlipNoMD(target, priorityMap, targetRect, scaledPosition, priority);
+ drawUncompHzFlipNoMD(target, targetRect, scaledPosition);
} else {
- drawUncompNoFlipNoMD(target, priorityMap, targetRect, scaledPosition, priority);
+ drawUncompNoFlipNoMD(target, targetRect, scaledPosition);
}
} else {
if (_drawMirrored) {
- drawHzFlipNoMD(target, priorityMap, targetRect, scaledPosition, priority);
+ drawUncompHzFlipNoMDNoSkip(target, targetRect, scaledPosition);
} else {
- drawNoFlipNoMD(target, priorityMap, targetRect, scaledPosition, priority);
+ drawUncompNoFlipNoMDNoSkip(target, targetRect, scaledPosition);
}
}
} else {
- if (_compressionType == kCelCompressionNone) {
- scaleDrawUncompNoMD(target, priorityMap, scaleX, scaleY, targetRect, scaledPosition, priority);
+ if (_drawMirrored) {
+ drawHzFlipNoMD(target, targetRect, scaledPosition);
} else {
- scaleDrawNoMD(target, priorityMap, scaleX, scaleY, targetRect, scaledPosition, priority);
+ drawNoFlipNoMD(target, targetRect, scaledPosition);
}
}
} else {
- if (scaleX.isOne() && scaleY.isOne()) {
- if (_compressionType == kCelCompressionNone) {
- if (_transparent) {
- if (_drawMirrored) {
- drawUncompHzFlipNoMD(target, targetRect, scaledPosition);
- } else {
- drawUncompNoFlipNoMD(target, targetRect, scaledPosition);
- }
- } else {
- if (_drawMirrored) {
- drawUncompHzFlipNoMDNoSkip(target, targetRect, scaledPosition);
- } else {
- drawUncompNoFlipNoMDNoSkip(target, targetRect, scaledPosition);
- }
- }
- } else {
- if (_drawMirrored) {
- drawHzFlipNoMD(target, targetRect, scaledPosition);
- } else {
- drawNoFlipNoMD(target, targetRect, scaledPosition);
- }
- }
+ if (_compressionType == kCelCompressionNone) {
+ scaleDrawUncompNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
} else {
- if (_compressionType == kCelCompressionNone) {
- scaleDrawUncompNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
- } else {
- scaleDrawNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
- }
+ scaleDrawNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
}
}
}
@@ -574,18 +582,15 @@ struct RENDERER {
_skipColor(skipColor) {}
inline void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- const int16 sourceX = targetRect.left - scaledPosition.x;
- const int16 sourceY = targetRect.top - scaledPosition.y;
-
byte *targetPixel = (byte *)target.getPixels() + target.screenWidth * targetRect.top + targetRect.left;
const int16 skipStride = target.screenWidth - targetRect.width();
const int16 targetWidth = targetRect.width();
const int16 targetHeight = targetRect.height();
- for (int y = 0; y < targetHeight; ++y) {
- _scaler.setSource(sourceX, sourceY + y);
+ for (int16 y = 0; y < targetHeight; ++y) {
+ _scaler.setTarget(targetRect.left, targetRect.top + y);
- for (int x = 0; x < targetWidth; ++x) {
+ for (int16 x = 0; x < targetWidth; ++x) {
_mapper.draw(targetPixel++, _scaler.read(), _skipColor);
}
@@ -598,7 +603,7 @@ template<typename MAPPER, typename SCALER>
void CelObj::render(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
MAPPER mapper;
- SCALER scaler(*this, targetRect.left - scaledPosition.x + targetRect.width());
+ SCALER scaler(*this, targetRect.left - scaledPosition.x + targetRect.width(), scaledPosition);
RENDERER<MAPPER, SCALER> renderer(mapper, scaler, _transparentColor);
renderer.draw(target, targetRect, scaledPosition);
}
@@ -607,7 +612,7 @@ template<typename MAPPER, typename SCALER>
void CelObj::render(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const Ratio &scaleX, const Ratio &scaleY) const {
MAPPER mapper;
- SCALER scaler(*this, targetRect.left - scaledPosition.x + targetRect.width(), scaleX, scaleY);
+ SCALER scaler(*this, targetRect, scaledPosition, scaleX, scaleY);
RENDERER<MAPPER, SCALER> renderer(mapper, scaler, _transparentColor);
renderer.draw(target, targetRect, scaledPosition);
}
@@ -620,49 +625,60 @@ void CelObj::drawHzFlip(Buffer &target, const Common::Rect &targetRect, const Co
debug("drawHzFlip");
dummyFill(target, targetRect);
}
+
void CelObj::drawNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
debug("drawNoFlip");
dummyFill(target, targetRect);
}
+
void CelObj::drawUncompNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
debug("drawUncompNoFlip");
dummyFill(target, targetRect);
}
+
void CelObj::drawUncompHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
debug("drawUncompHzFlip");
dummyFill(target, targetRect);
}
+
void CelObj::scaleDraw(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
debug("scaleDraw");
dummyFill(target, targetRect);
}
+
void CelObj::scaleDrawUncomp(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
debug("scaleDrawUncomp");
dummyFill(target, targetRect);
}
+
void CelObj::drawHzFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("drawHzFlipMap");
- dummyFill(target, targetRect);
+ render<MAPPER_Map, SCALER_NoScale<true, READER_Compressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::drawNoFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("drawNoFlipMap");
- dummyFill(target, targetRect);
+ render<MAPPER_Map, SCALER_NoScale<false, READER_Compressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::drawUncompNoFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("drawUncompNoFlipMap");
- dummyFill(target, targetRect);
+ render<MAPPER_Map, SCALER_NoScale<false, READER_Uncompressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::drawUncompHzFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("drawUncompHzFlipMap");
- dummyFill(target, targetRect);
+ render<MAPPER_Map, SCALER_NoScale<true, READER_Uncompressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::scaleDrawMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("scaleDrawMap");
- dummyFill(target, targetRect);
+ if (_drawMirrored)
+ render<MAPPER_Map, SCALER_Scale<true, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
+ else
+ render<MAPPER_Map, SCALER_Scale<false, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
}
+
void CelObj::scaleDrawUncompMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("scaleDrawUncompMap");
- dummyFill(target, targetRect);
+ if (_drawMirrored)
+ render<MAPPER_Map, SCALER_Scale<true, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
+ else
+ render<MAPPER_Map, SCALER_Scale<false, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
}
void CelObj::drawNoFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
@@ -680,43 +696,29 @@ void CelObj::drawUncompNoFlipNoMD(Buffer &target, const Common::Rect &targetRect
void CelObj::drawUncompNoFlipNoMDNoSkip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
render<MAPPER_NoMDNoSkip, SCALER_NoScale<false, READER_Uncompressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::drawUncompHzFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
render<MAPPER_NoMD, SCALER_NoScale<true, READER_Uncompressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::drawUncompHzFlipNoMDNoSkip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
render<MAPPER_NoMDNoSkip, SCALER_NoScale<true, READER_Uncompressed> >(target, targetRect, scaledPosition);
}
void CelObj::scaleDrawNoMD(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- if (_drawMirrored) {
+ if (_drawMirrored)
render<MAPPER_NoMD, SCALER_Scale<true, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
- } else {
+ else
render<MAPPER_NoMD, SCALER_Scale<false, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
- }
}
void CelObj::scaleDrawUncompNoMD(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- if (_drawMirrored) {
+ if (_drawMirrored)
render<MAPPER_NoMD, SCALER_Scale<true, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
- } else {
+ else
render<MAPPER_NoMD, SCALER_Scale<false, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
- }
}
-// TODO: These functions may all be vestigial.
-void CelObj::drawHzFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::drawNoFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::drawUncompNoFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::drawUncompHzFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::scaleDrawMap(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::scaleDrawUncompMap(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::drawHzFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::drawNoFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::drawUncompNoFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::drawUncompHzFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::scaleDrawNoMD(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::scaleDrawUncompNoMD(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-
#pragma mark -
#pragma mark CelObjView
CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo) {
@@ -832,8 +834,8 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
bool CelObjView::analyzeUncompressedForRemap() const {
byte *pixels = getResPointer() + READ_SCI11ENDIAN_UINT32(getResPointer() + _celHeaderOffset + 24);
for (int i = 0; i < _width * _height; ++i) {
- uint8 pixel = pixels[i];
- if (/* TODO: pixel >= Remap::minRemapColor && pixel <= Remap::maxRemapColor */ false && pixel != _transparentColor) {
+ byte pixel = pixels[i];
+ if (pixel >= g_sci->_gfxRemap32->getStartColor() && pixel <= g_sci->_gfxRemap32->getEndColor() && pixel != _transparentColor) {
return true;
}
}
@@ -841,7 +843,16 @@ bool CelObjView::analyzeUncompressedForRemap() const {
}
bool CelObjView::analyzeForRemap() const {
- // TODO: Implement decompression and analysis
+ READER_Compressed reader(*this, _width);
+ for (int y = 0; y < _height; y++) {
+ const byte *curRow = reader.getRow(y);
+ for (int x = 0; x < _width; x++) {
+ byte pixel = curRow[x];
+ if (pixel >= g_sci->_gfxRemap32->getStartColor() && pixel <= g_sci->_gfxRemap32->getEndColor() && pixel != _transparentColor) {
+ return true;
+ }
+ }
+ }
return false;
}
diff --git a/engines/sci/graphics/celobj32.h b/engines/sci/graphics/celobj32.h
index 8d030cfd4a..0bb4b03ae2 100644
--- a/engines/sci/graphics/celobj32.h
+++ b/engines/sci/graphics/celobj32.h
@@ -104,6 +104,10 @@ struct CelInfo32 {
bitmap == other.bitmap
);
}
+
+ inline bool operator!=(const CelInfo32 &other) {
+ return !(*this == other);
+ }
};
class CelObj;
@@ -180,13 +184,16 @@ public:
CelScaler() :
_scaleTables(),
_activeIndex(0) {
- CelScalerTable &table = _scaleTables[_activeIndex];
+ CelScalerTable &table = _scaleTables[0];
table.scaleX = Ratio();
table.scaleY = Ratio();
for (int i = 0; i < ARRAYSIZE(table.valuesX); ++i) {
table.valuesX[i] = i;
table.valuesY[i] = i;
}
+ for (int i = 1; i < ARRAYSIZE(_scaleTables); ++i) {
+ _scaleTables[i] = _scaleTables[0];
+ }
}
/**
@@ -391,18 +398,15 @@ private:
void drawUncompHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void scaleDraw(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void scaleDrawUncomp(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
+
void drawHzFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void drawNoFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void drawUncompNoFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void drawUncompHzFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void scaleDrawMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void scaleDrawUncompMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
- void drawHzFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void drawNoFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void drawUncompNoFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void drawUncompHzFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void scaleDrawMap(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void scaleDrawUncompMap(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
+ // NOTE: The original includes versions of the above functions with priority parameters, which were not actually used in SCI32
+
void drawHzFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void drawNoFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void drawUncompNoFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
@@ -411,12 +415,7 @@ private:
void drawUncompHzFlipNoMDNoSkip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void scaleDrawNoMD(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void scaleDrawUncompNoMD(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
- void drawHzFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void drawNoFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void drawUncompNoFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void drawUncompHzFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void scaleDrawNoMD(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void scaleDrawUncompNoMD(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
+ // NOTE: The original includes versions of the above functions with priority parameters, which were not actually used in SCI32
#pragma mark -
#pragma mark CelObj - Caching
diff --git a/engines/sci/graphics/compare.cpp b/engines/sci/graphics/compare.cpp
index 8b2d5e247a..729eeeaf81 100644
--- a/engines/sci/graphics/compare.cpp
+++ b/engines/sci/graphics/compare.cpp
@@ -158,6 +158,10 @@ reg_t GfxCompare::kernelCanBeHere(reg_t curObject, reg_t listReference) {
}
reg_t GfxCompare::kernelCantBeHere32(const reg_t curObject, const reg_t listReference) const {
+ // Most of SCI32 graphics code converts rects from the VM to exclusive
+ // rects before operating on them, but this call leverages SCI16 engine
+ // code that operates on inclusive rects, so the rect's bottom-right
+ // point is not modified like in other SCI32 kernel calls
Common::Rect checkRect(
readSelectorValue(_segMan, curObject, SELECTOR(brLeft)),
readSelectorValue(_segMan, curObject, SELECTOR(brTop)),
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 2477574c03..6454a1eb32 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -47,6 +47,7 @@
#include "sci/graphics/paint32.h"
#include "sci/graphics/palette32.h"
#include "sci/graphics/picture.h"
+#include "sci/graphics/remap.h"
#include "sci/graphics/text32.h"
#include "sci/graphics/plane32.h"
#include "sci/graphics/screen_item32.h"
@@ -55,8 +56,6 @@
namespace Sci {
-// TODO/FIXME: This is partially guesswork
-
static int dissolveSequences[2][20] = {
/* SCI2.1early- */ { 3, 6, 12, 20, 48, 96, 184, 272, 576, 1280, 3232, 6912, 13568, 24576, 46080 },
/* SCI2.1mid+ */ { 0, 0, 3, 6, 12, 20, 48, 96, 184, 272, 576, 1280, 3232, 6912, 13568, 24576, 46080, 73728, 132096, 466944 }
@@ -81,7 +80,6 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd
_showStyles(nullptr),
// TODO: Stop using _gfxScreen
_currentBuffer(screen->getDisplayWidth(), screen->getDisplayHeight(), nullptr),
- _priorityMap(screen->getDisplayWidth(), screen->getDisplayHeight(), nullptr),
_remapOccurred(false),
_frameNowVisible(false),
_screenRect(screen->getDisplayWidth(), screen->getDisplayHeight()),
@@ -117,6 +115,22 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd
_defaultUnknownC = unknownCDefaults[1];
}
+ switch (g_sci->getGameId()) {
+ case GID_GK2:
+ case GID_LIGHTHOUSE:
+ case GID_LSL7:
+ case GID_PHANTASMAGORIA2:
+ case GID_PQSWAT:
+ case GID_TORIN:
+ case GID_RAMA:
+ _currentBuffer.scriptWidth = 640;
+ _currentBuffer.scriptHeight = 480;
+ break;
+ default:
+ // default script width for other games is 320x200
+ break;
+ }
+
// TODO: Nothing in the renderer really uses this. Currently,
// the cursor renderer does, and kLocalToGlobal/kGlobalToLocal
// do, but in the real engine (1) the cursor is handled in
@@ -446,9 +460,8 @@ void GfxFrameout::frameOut(const bool shouldShowBits, const Common::Rect &rect)
screenItemLists.resize(_planes.size());
eraseLists.resize(_planes.size());
- // _numActiveRemaps was a global in SCI engine
- if (/* TODO Remap::_numActiveRemaps > 0 */ false && _remapOccurred) {
- // remapMarkRedraw();
+ if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
+ remapMarkRedraw();
}
calcLists(screenItemLists, eraseLists, rect);
@@ -772,16 +785,6 @@ void GfxFrameout::drawEraseList(const RectList &eraseList, const Plane &plane) {
}
void GfxFrameout::drawScreenItemList(const DrawList &screenItemList) {
- _hasRemappedScreenItem = false;
- if (/* TODO: g_Remap_UnknownCounter2 */ false && !_priorityMap.isNull()) {
- for (DrawList::const_iterator it = screenItemList.begin(); it != screenItemList.end(); ++it) {
- if ((*it)->screenItem->getCelObj()._remap) {
- _hasRemappedScreenItem = true;
- break;
- }
- }
- }
-
for (DrawList::const_iterator it = screenItemList.begin(); it != screenItemList.end(); ++it) {
DrawItem &drawItem = **it;
mergeToShowList(drawItem.rect, _showList, _overdrawThreshold);
@@ -826,9 +829,7 @@ void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry
Palette sourcePalette(*_palette->getNextPalette());
alterVmap(sourcePalette, sourcePalette, -1, styleRanges);
- // TODO: unsure if this is what this variable actually
- // represents, but it is the correct variable number
- int16 lastRoom = g_sci->getEngineState()->variables[VAR_GLOBAL][12].toSint16();
+ int16 prevRoom = g_sci->getEngineState()->variables[VAR_GLOBAL][12].toSint16();
Common::Rect rect(_screen->getDisplayWidth(), _screen->getDisplayHeight());
_showList.add(rect);
@@ -844,11 +845,9 @@ void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry
screenItemLists.resize(_planes.size());
eraseLists.resize(_planes.size());
- // TODO: Remap
- // _numActiveRemaps was a global in SCI engine
- // if (Remap::_numActiveRemaps > 0 && _remapOccurred) {
- // _screen->remapMarkRedraw();
- // }
+ if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
+ remapMarkRedraw();
+ }
calcLists(screenItemLists, eraseLists, calcRect);
for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
@@ -871,7 +870,7 @@ void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry
Palette nextPalette(*_palette->getNextPalette());
- if (lastRoom < 1000) {
+ if (prevRoom < 1000) {
for (int i = 0; i < ARRAYSIZE(sourcePalette.colors); ++i) {
if (styleRanges[i] == -1 || styleRanges[i] == 0) {
sourcePalette.colors[i] = nextPalette.colors[i];
@@ -895,7 +894,7 @@ void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry
if (showStyle && showStyle->type != kShowStyleUnknown) {
// TODO: SCI2.1mid transition effects
// processEffects();
- warning("Transition not implemented!");
+ warning("Transition %d not implemented!", showStyle->type);
} else {
showBits();
}
@@ -903,15 +902,12 @@ void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry
_frameNowVisible = true;
for (PlaneList::iterator plane = _planes.begin(); plane != _planes.end(); ++plane) {
-// TODO:
-// plane->updateRedrawAllCount();
+ (*plane)->_redrawAllCount = getScreenCount();
}
- // TODO: Remap
- // _numActiveRemaps was a global in SCI engine
- // if (Remap::_numActiveRemaps > 0 && _remapOccurred) {
- // _screen->remapMarkRedraw();
- // }
+ if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
+ remapMarkRedraw();
+ }
calcLists(screenItemLists, eraseLists, calcRect);
for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
@@ -1037,7 +1033,10 @@ void GfxFrameout::alterVmap(const Palette &palette1, const Palette &palette2, co
int8 styleRangeValue = styleRanges[currentValue];
if (styleRangeValue == -1 && styleRangeValue == style) {
currentValue = pixels[pixelIndex] = clut[currentValue];
- styleRangeValue = styleRanges[clut[currentValue]];
+ // NOTE: In original engine this assignment happens outside of the
+ // condition, but if the branch is not followed the value is just
+ // going to be the same as it was before
+ styleRangeValue = styleRanges[currentValue];
}
if (
@@ -1088,44 +1087,7 @@ inline ShowStyleEntry *GfxFrameout::deleteShowStyleInternal(ShowStyleEntry *cons
lastEntry->next = showStyle->next;
}
- // NOTE: Differences from SCI2/2.1early engine:
- // 1. Memory of ShowStyle-owned objects was freed before ShowStyle was
- // removed from the linked list, but since this operation is position
- // independent, it has been moved after removal from the list for
- // consistency with SCI2.1mid+
- // 2. In SCI2, `screenItems` was a pointer to an array of pointers, so
- // extra deletes were performed here; we use an owned container object
- // instead, which is automatically freed when ShowStyle is freed
-#if 0
- if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
- uint8 type = showStyle->type;
-
- if (type >= 1 && type <= 10) {
- ScreenItemList &styleItems = showStyle->screenItems;
- for (ScreenItemList::iterator it = styleItems.begin(); it != styleItems.end(); ++it) {
- if (active) {
- // TODO: _screen->deleteScreenItem(showStyle->plane, *it->id);
- _screenItems.remove(*it);
- }
- delete *it;
- }
- } else if (type == 11 || type == 12) {
- if (!showStyle->bitmapMemId.isNull()) {
- _segMan->freeHunkEntry(showStyle->bitmapMemId);
- }
- if (showStyle->bitmapScreenItem != nullptr) {
- // TODO: _screen->deleteScreenItem(showStyle->plane, showStyle->bitmapScreenItem->id);
- _screenItems.remove(showStyle->bitmapScreenItem);
- delete showStyle->bitmapScreenItem;
- }
- }
- } else {
-#endif
- delete[] showStyle->fadeColorRanges;
-#if 0
- }
-#endif
-
+ delete[] showStyle->fadeColorRanges;
delete showStyle;
// TODO: Verify that this is the correct entry to return
@@ -1137,11 +1099,20 @@ inline ShowStyleEntry *GfxFrameout::deleteShowStyleInternal(ShowStyleEntry *cons
// and need to be fixed in future
// TODO: SQ6 does not use 'priority' (exists since SCI2) or 'blackScreen' (exists since SCI3);
// check to see if other versions use or if they are just always ignored
-void GfxFrameout::kernelSetShowStyle(const uint16 argc, const reg_t &planeObj, const ShowStyleType type, const int16 seconds, const int16 back, const int16 priority, const int16 animate, const int16 frameOutNow, const reg_t &pFadeArray, const int16 divisions, const int16 blackScreen) {
+void GfxFrameout::kernelSetShowStyle(const uint16 argc, const reg_t planeObj, const ShowStyleType type, const int16 seconds, const int16 back, const int16 priority, const int16 animate, const int16 frameOutNow, reg_t pFadeArray, int16 divisions, const int16 blackScreen) {
bool hasDivisions = false;
bool hasFadeArray = false;
- if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+
+ // KQ7 2.0b uses a mismatched version of the Styler script (SCI2.1early script
+ // for SCI2.1mid engine), so the calls it makes to kSetShowStyle are wrong and
+ // put `divisions` where `pFadeArray` is supposed to be
+ if (getSciVersion() == SCI_VERSION_2_1_MIDDLE && g_sci->getGameId() == GID_KQ7) {
+ hasDivisions = argc > 7;
+ hasFadeArray = false;
+ divisions = argc > 7 ? pFadeArray.toSint16() : -1;
+ pFadeArray = NULL_REG;
+ } else if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
hasDivisions = argc > 7;
hasFadeArray = false;
} else if (getSciVersion() < SCI_VERSION_3) {
@@ -1171,20 +1142,12 @@ void GfxFrameout::kernelSetShowStyle(const uint16 argc, const reg_t &planeObj, c
error("Plane %04x:%04x is not present in active planes list", PRINT_REG(planeObj));
}
- // TODO: This is Plane.gameRect in SCI engine, not planeRect. Engine uses
- // Plane::ConvGameRectToPlaneRect to convert from gameRect to planeRect.
- // Also this never gets used by SQ6 so it is not clear what it does yet
- // Common::Rect gameRect = plane.planeRect;
-
bool createNewEntry = true;
ShowStyleEntry *entry = findShowStyleForPlane(planeObj);
if (entry != nullptr) {
+ // TODO: SCI2.1early has different criteria for show style reuse
bool useExisting = true;
- if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
- useExisting = plane->_planeRect.width() == entry->width && plane->_planeRect.height() == entry->height;
- }
-
if (useExisting) {
useExisting = entry->divisions == (hasDivisions ? divisions : _defaultDivisions[type]) && entry->unknownC == _defaultUnknownC[type];
}
@@ -1213,39 +1176,28 @@ void GfxFrameout::kernelSetShowStyle(const uint16 argc, const reg_t &planeObj, c
entry->divisions = hasDivisions ? divisions : _defaultDivisions[type];
entry->plane = planeObj;
-#if 0
- if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
- entry->bitmapMemId = NULL_REG;
- entry->screenItems.empty();
- entry->width = plane->_planeRect.width();
- entry->height = plane->_planeRect.height();
- } else {
-#endif
- entry->fadeColorRanges = nullptr;
- if (hasFadeArray) {
- // NOTE: SCI2.1mid engine does no check to verify that an array is
- // successfully retrieved, and SegMan will cause a fatal error
- // if we try to use a memory segment that is not an array
- SciArray<reg_t> *table = _segMan->lookupArray(pFadeArray);
-
- uint32 rangeCount = table->getSize();
- entry->fadeColorRangesCount = rangeCount;
-
- // NOTE: SCI engine code always allocates memory even if the range
- // table has no entries, but this does not really make sense, so
- // we avoid the allocation call in this case
- if (rangeCount > 0) {
- entry->fadeColorRanges = new uint16[rangeCount];
- for (size_t i = 0; i < rangeCount; ++i) {
- entry->fadeColorRanges[i] = table->getValue(i).toUint16();
- }
+ entry->fadeColorRanges = nullptr;
+ if (hasFadeArray) {
+ // NOTE: SCI2.1mid engine does no check to verify that an array is
+ // successfully retrieved, and SegMan will cause a fatal error
+ // if we try to use a memory segment that is not an array
+ SciArray<reg_t> *table = _segMan->lookupArray(pFadeArray);
+
+ uint32 rangeCount = table->getSize();
+ entry->fadeColorRangesCount = rangeCount;
+
+ // NOTE: SCI engine code always allocates memory even if the range
+ // table has no entries, but this does not really make sense, so
+ // we avoid the allocation call in this case
+ if (rangeCount > 0) {
+ entry->fadeColorRanges = new uint16[rangeCount];
+ for (size_t i = 0; i < rangeCount; ++i) {
+ entry->fadeColorRanges[i] = table->getValue(i).toUint16();
}
- } else {
- entry->fadeColorRangesCount = 0;
}
-#if 0
+ } else {
+ entry->fadeColorRangesCount = 0;
}
-#endif
}
// NOTE: The original engine had no nullptr check and would just crash
@@ -1262,9 +1214,6 @@ void GfxFrameout::kernelSetShowStyle(const uint16 argc, const reg_t &planeObj, c
entry->delay = (seconds * 60 + entry->divisions - 1) / entry->divisions;
if (entry->delay == 0) {
-#if 0
- if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE && entry->fadeColorRanges != nullptr) {
-#endif
if (entry->fadeColorRanges != nullptr) {
delete[] entry->fadeColorRanges;
}
@@ -1278,235 +1227,13 @@ void GfxFrameout::kernelSetShowStyle(const uint16 argc, const reg_t &planeObj, c
}
if (createNewEntry) {
- // TODO: Implement SCI3, which may or may not actually have
- // the same transitions as SCI2/SCI2.1early, but implemented
- // differently
-#if 0
- if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
- switch (entry->type) {
- case kShowStyleHShutterIn:
- case kShowStyleHShutterOut:
- prepareShowStyleWipe(entry, priority, 2, true);
- break;
-
- case kShowStyleVShutterIn:
- case kShowStyleVShutterOut:
- prepareShowStyleWipe(entry, priority, 2, false);
- break;
-
- case kShowStyleHWipe1:
- case kShowStyleHWipe2:
- prepareShowStyleWipe(entry, priority, 1, true);
- break;
-
- case kShowStyleVWipe1:
- case kShowStyleVWipe2:
- prepareShowStyleWipe(entry, priority, 1, false);
- break;
-
- case kShowStyleIrisIn:
- case kShowStyleIrisOut:
- prepareShowStyleIris(entry, priority);
- break;
-
- case kShowStyle11:
- case kShowStyle12:
- prepareShowStylePixels(entry, priority, plane->planeRect);
- break;
-
- default:
- break;
- }
- }
-#endif
-
+ // TODO: Implement SCI2.1early and SCI3
entry->next = _showStyles;
_showStyles = entry;
}
}
}
-#if 0
-void addFrameoutEntryInternal(ShowStyleEntry *const showStyle, const int16 priority, const CelInfo32 &celInfo, const Common::Rect &rect) {
- ScreenItem *screenItem = new ScreenItem;
- screenItem->plane = showStyle->plane;
- screenItem->celInfo = celInfo;
- screenItem->celRect = rect;
- screenItem->isInList = true;
- screenItem->priority = priority;
- screenItem->visible = true;
- showStyle->screenItems.push_back(screenItem);
-}
-
-void GfxFrameout::prepareShowStyleWipe(ShowStyleEntry *const showStyle, const int16 priority, const int16 edgeCount, const bool horizontal) {
- assert(edgeCount == 1 || edgeCount == 2);
-
- const int numScreenItems = showStyle->divisions * edgeCount;
- const int extra = edgeCount > 1 ? 1 : 0;
-
- showStyle->edgeCount = edgeCount;
- showStyle->screenItems.reserve(numScreenItems);
-
- CelInfo32 celInfo;
- celInfo.bitmap = NULL_REG;
- celInfo.type = kCelObjTypeView;
- celInfo.color = showStyle->color;
-
- for (int i = 0; i < numScreenItems; ++i) {
- Common::Rect rect;
-
- if (horizontal) {
- rect.top = 0;
- rect.bottom = showStyle->height - 1;
- rect.left = (showStyle->width * i) / (showStyle->divisions * edgeCount);
- rect.right = ((i + 1) * (showStyle->width + extra)) / (showStyle->divisions * edgeCount) - 1;
- } else {
- rect.left = 0;
- rect.right = showStyle->width - 1;
- rect.top = (showStyle->height * i) / (showStyle->divisions * edgeCount);
- rect.bottom = ((i + 1) * (showStyle->height + extra)) / (showStyle->divisions * edgeCount) - 1;
- }
-
- addFrameoutEntryInternal(showStyle, priority, celInfo, rect);
-
- if (edgeCount == 2) {
- if (horizontal) {
- int temp = rect.left;
- rect.left = showStyle->width - rect.right - 1;
- rect.right = showStyle->width - temp - 1;
- } else {
- int temp = rect.top;
- rect.top = showStyle->height - rect.bottom - 1;
- rect.bottom = showStyle->height - temp - 1;
- }
-
- addFrameoutEntryInternal(showStyle, priority, celInfo, rect);
- }
- }
-}
-
-void GfxFrameout::prepareShowStyleIris(ShowStyleEntry *const showStyle, const int16 priority) {
- const int edgeCount = 4;
- const int numScreenItems = showStyle->divisions * edgeCount;
-
- showStyle->edgeCount = edgeCount;
- showStyle->screenItems.reserve(numScreenItems);
-
- CelInfo32 celInfo;
- celInfo.bitmap = NULL_REG;
- celInfo.type = kCelObjTypeView;
- celInfo.color = showStyle->color;
-
- for (int i = 0; i < numScreenItems; ++i) {
- Common::Rect rect;
-
- rect.right = showStyle->width - ((showStyle->width * i) / (showStyle->divisions * 2)) - 1;
- rect.left = (showStyle->width * i) / (showStyle->divisions * 2);
- rect.top = (showStyle->height * i) / (showStyle->divisions * 2);
- rect.bottom = ((i + 1) * (showStyle->height + 1)) / (showStyle->divisions * 2) - 1;
-
- addFrameoutEntryInternal(showStyle, priority, celInfo, rect);
-
- {
- int temp = rect.top;
- rect.top = showStyle->height - rect.bottom - 1;
- rect.bottom = showStyle->height - temp - 1;
- }
-
- addFrameoutEntryInternal(showStyle, priority, celInfo, rect);
-
- rect.top = ((i + 1) * (showStyle->height + 1)) / (showStyle->divisions * 2);
- rect.right = ((i + 1) * (showStyle->width + 1)) / (showStyle->divisions * 2) - 1;
- rect.bottom = ((i + 1) * (showStyle->height + 1)) / (showStyle->divisions * 2) - 1;
-
- addFrameoutEntryInternal(showStyle, priority, celInfo, rect);
-
- {
- int temp = rect.left;
- rect.left = showStyle->width - rect.right - 1;
- rect.right = showStyle->width - temp - 1;
- }
-
- addFrameoutEntryInternal(showStyle, priority, celInfo, rect);
- }
-}
-
-void GfxFrameout::prepareShowStylePixels(ShowStyleEntry *const showStyle, const int16 priority, const Common::Rect planeGameRect) {
- const int bitmapSize = showStyle->width * showStyle->height;
-
- // TODO: Verify that memory type 0x200 (what GK1 engine uses)
- // is Hunk type
- reg_t bitmapMemId = _segMan->allocateHunkEntry("ShowStylePixels()", bitmapSize + sizeof(GfxBitmapHeader));
- showStyle->bitmapMemId = bitmapMemId;
-
- // TODO: SCI2 GK1 uses a Bitmap constructor function to
- // do this work
- byte *bitmap = _segMan->getHunkPointer(bitmapMemId);
- GfxBitmapHeader *header = (GfxBitmapHeader *)bitmap;
- byte *bitmapData = bitmap + sizeof(GfxBitmapHeader);
-
- // TODO: These are defaults from the Bitmap constructor in
- // GK1, not specific values set by this function.
- // TODO: This probably should not even be using a struct at
- // all since this information is machine endian dependent
- // and will be reversed for Mac versions or when running
- // ScummVM on big-endian systems. GK1 used packed structs
- // everywhere so this probably worked better there too.
- header->field_18 = 36;
- header->field_1c = 36;
- memset(header, 0, sizeof(GfxBitmapHeader));
-
- header->width = showStyle->width;
- header->height = showStyle->height;
- header->field_8 = 250;
- header->size = bitmapSize;
-
- // TODO: Scaled dimensions in bitmap headers was not added
- // until SCI2.1mid. It is not clear what the right thing to
- // do here is.
- if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
- header->scaledWidth = _currentBuffer.scriptWidth;
- header->scaledHeight = _currentBuffer.scriptHeight;
- }
-
- Common::Rect copyRect;
- // TODO: planeGameRect is supposedly in script coordinates,
- // which are usually 320x200. If bitsSaveDisplayScreen is
- // in native resolution then seemingly this function will
- // not work properly since we will be not copy enough bits,
- // or from the correct location.
- copyRect.left = planeGameRect.left;
- copyRect.top = planeGameRect.top;
- copyRect.right = planeGameRect.left + showStyle->width;
- copyRect.bottom = planeGameRect.top + showStyle->height;
- _screen->bitsSaveDisplayScreen(copyRect, bitmapData);
-
- CelInfo32 celInfo;
- celInfo.bitmap = bitmapMemId;
- celInfo.type = kCelObjTypeMem;
-
- ScreenItem *screenItem = new ScreenItem;
-
- screenItem->position.x = 0;
- screenItem->position.y = 0;
-
- showStyle->bitmapScreenItem = screenItem;
- screenItem->priority = priority;
-
- // TODO: Have not seen/identified this particular flag yet in
- // SCI2.1mid (SQ6) engine; maybe (1) a duplicate of `created`,
- // or (2) does not exist any more, or (3) one of the other
- // still-unidentified fields. Probably need to look at the
- // GK1 source for its use in drawing algorithms to determine
- // if/how this correlates to ScreenItem members in the
- // SCI2.1mid engine.
-// screenItem->isInList = true;
-
- Plane *plane = _planes.findByObject(showStyle.plane);
- plane->_screenItemList.add(screenItem);
-}
-#endif
-
// NOTE: Different version of SCI engine support different show styles
// SCI2 implements 0, 1/3/5/7/9, 2/4/6/8/10, 11, 12, 13, 14
// SCI2.1 implements 0, 1/2/3/4/5/6/7/8/9/10/11/12/15, 13, 14
@@ -1548,53 +1275,15 @@ void GfxFrameout::processShowStyles() {
case kShowStyleWipeLeft:
case kShowStyleWipeUp:
case kShowStyleIrisOut:
-#if 0
- if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
-#endif
- retval = processShowStyleMorph(showStyle);
-#if 0
- } else {
- retval = processShowStyleWipe(-1, showStyle);
- }
-#endif
- break;
case kShowStyleHShutterIn:
case kShowStyleVShutterIn:
case kShowStyleWipeRight:
case kShowStyleWipeDown:
case kShowStyleIrisIn:
-#if 0
- if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
-#endif
- retval = processShowStyleMorph(showStyle);
-#if 0
- } else {
- retval = processShowStyleWipe(1, showStyle);
- }
-#endif
- break;
case kShowStyle11:
-#if 0
- if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
-#endif
- retval = processShowStyleMorph(showStyle);
-#if 0
- } else {
- retval = processShowStyle11(showStyle);
- }
-#endif
- break;
case kShowStyle12:
case kShowStyleUnknown: {
-#if 0
- if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
-#endif
- retval = processShowStyleMorph(showStyle);
-#if 0
- } else {
- retval = processShowStyle12(showStyle);
- }
-#endif
+ retval = processShowStyleMorph(showStyle);
break;
}
case kShowStyleFadeOut: {
@@ -1688,285 +1377,6 @@ bool GfxFrameout::processShowStyleFade(const int direction, ShowStyleEntry *cons
return false;
}
-// TODO: Rect sizes are wrong, rects in SCI are inclusive of bottom/right but
-// in ScummVM are exclusive so extra ±1 operations here are wrong
-#if 0
-bool GfxFrameout::processShowStyleWipe(const ShowStyleEntry *const style) {
- const int16 divisions = style->divisions;
- Common::Rect rect(divisions, divisions);
-
- const Plane *const plane = _visibleScreen->planeList->findByObject(style->plane);
-
- const int16 planeLeft = plane->field_4C.left;
- const int16 planeTop = plane->field_4C.top;
- const int16 planeRight = plane->field_4C.right;
- const int16 planeBottom = plane->field_4C.bottom;
- const int16 planeWidth = planeRight - planeLeft + 1;
- const int16 planeHeight = planeBottom - planeTop + 1;
-
- const int16 divisionWidth = planeWidth / divisions - 1;
- int16 shutterDivisionWidth = planeWidth / (2 * divisions);
- if (shutterDivisionWidth >= 0) {
- const int16 heightPerDivision = planeHeight / divisions;
- int16 shutterMiddleX = divisions * shutterDivisionWidth;
- for (int16 x = divisionWidth - shutterDivisionWidth; x <= divisionWidth; ++x) {
- int16 divisionTop = 0;
- for (int16 y = 0; y < heightPerDivision; ++y, divisionTop += divisions) {
- rect.top = planeTop + divisionTop;
- rect.bottom = rect.top + divisions - 1;
- rect.left = planeLeft + shutterMiddleX;
- rect.right = rect.left + divisions - 1;
- // _screen->rectList.clear();
- // _screen->rectList.add(rect);
- // showBits();
- }
- // number of divisions does not divide evenly into plane height,
- // draw the remainder
- if (planeHeight % divisions) {
- rect.top = planeTop + divisionTop;
- rect.bottom = rect.top + planeHeight % divisions - 1;
- rect.left = planeLeft + shutterMiddleX;
- rect.right = rect.left + divisions - 1;
- // _screen->rectList.clear();
- // _screen->rectList.add(rect);
- // showBits();
- }
-
- divisionTop = 0;
- for (int16 y = 0; y < heightPerDivision; ++y, divisionTop += divisions) {
- rect.top = planeTop + divisionTop;
- rect.bottom = rect.top + divisions - 1;
- rect.left = planeLeft + divisions * x;
- rect.right = rect.left + divisions - 1;
- // _screen->rectList.clear();
- // _screen->rectList.add(rect);
- // showBits();
- }
- if (planeHeight % divisions) {
- rect.top = planeTop + divisionTop;
- rect.bottom = rect.top + planeHeight % divisions - 1;
- rect.left = planeLeft + divisions * x;
- rect.right = rect.left + divisions - 1;
- // _screen->rectList.clear();
- // _screen->rectList.add(rect);
- // showBits();
- }
-
- shutterMiddleX -= divisions;
- --shutterDivisionWidth;
- }
- }
-
- if (planeWidth % divisions) {
- const int16 roundedPlaneWidth = divisions * divisionWidth;
- int16 divisionTop = 0;
- for (int16 y = 0; y < planeHeight / divisions; ++y, divisionTop += divisions) {
- rect.top = planeTop + divisionTop;
- rect.bottom = rect.top + divisions - 1;
- rect.left = planeLeft + roundedPlaneWidth;
- rect.right = rect.left + planeWidth % divisions + divisions - 1;
- // _screen->rectList.clear();
- // _screen->rectList.add(rect);
- // showBits();
- }
- if (planeHeight % divisions) {
- rect.top = planeTop + divisionTop;
- rect.bottom = rect.top + planeHeight % divisions - 1;
- rect.left = planeLeft + roundedPlaneWidth;
- rect.right = rect.left + planeWidth % divisions + divisions - 1;
- // _screen->rectList.clear();
- // _screen->rectList.add(rect);
- // showBits();
- }
- }
-
- rect.right = planeRight;
- rect.left = planeLeft;
- rect.top = planeTop;
- rect.bottom = planeBottom;
- // _screen->rectList.clear();
- // _screen->rectList.add(rect);
- // showBits();
-}
-#endif
-#if 0
-bool GfxFrameout::processShowStyleWipe(const int direction, ShowStyleEntry *const showStyle) {
- if (showStyle->currentStep < showStyle->divisions) {
- int index;
- if (direction <= 0) {
- index = showStyle->divisions - showStyle->currentStep - 1;
- } else {
- index = showStyle->currentStep;
- }
-
- index *= showStyle->edgeCount;
-
- if (showStyle->edgeCount > 0) {
- for (int i = 0; i < showStyle->edgeCount; ++i) {
- if (showStyle->fadeUp) {
- ScreenItem *screenItem = showStyle->screenItems[index + i];
- if (screenItem != nullptr) {
- // TODO: _screen->deleteScreenItem(screenItem);
- _screenItems.remove(screenItem);
-
- delete screenItem;
- showStyle->screenItems[index + i] = nullptr;
- }
- } else {
- ScreenItem *screenItem = showStyle->screenItems[index + i];
- // TODO: _screen->addScreenItem(screenItem);
- _screenItems.push_back(screenItem);
- }
- }
-
- ++showStyle->currentStep;
- showStyle->nextTick += showStyle->delay;
- }
- }
-
- if (showStyle->currentStep >= showStyle->divisions) {
- if (showStyle->fadeUp) {
- showStyle->processed = true;
- }
-
- return true;
- }
-
- return false;
-}
-
-void fillRect(byte *data, const Common::Rect &rect, const int16 color, const int16 stride) {
-
-}
-
-bool GfxFrameout::processShowStyle11(ShowStyleEntry *const showStyle) {
- int divisions = showStyle->divisions * showStyle->divisions;
-
- byte *bitmapData = _segMan->getHunkPointer(showStyle->bitmapMemId) + sizeof(GfxBitmapHeader);
-
- int ebx;
-
- if (showStyle->currentStep == 0) {
- int ctr = 0;
- int bloot = divisions;
- do {
- bloot >>= 1;
- ++ctr;
- } while (bloot != 1);
-
- showStyle->dissolveSeed = _dissolveSequenceSeeds[ctr];
- ebx = 800;
- showStyle->unknown3A = 800;
- showStyle->dissolveInitial = 800;
- } else {
- int ebx = showStyle->unknown3A;
- do {
- int eax = ebx >> 1;
- if (ebx & 1) {
- ebx = showStyle->dissolveSeed ^ eax;
- } else {
- ebx = eax;
- }
- } while (ebx >= divisions);
-
- if (ebx == showStyle->dissolveInitial) {
- ebx = 0;
- }
- }
-
- Common::Rect rect;
-
- rect.left = (showStyle->width + showStyle->divisions - 1) / showStyle->divisions;
- rect.top = (showStyle->height + showStyle->divisions - 1) / showStyle->divisions;
-
- if (showStyle->currentStep <= showStyle->divisions) {
- int ebp = 0;
- do {
- int ecx = ebx % showStyle->divisions;
-
- Common::Rect drawRect;
- drawRect.left = rect.left * ecx;
- drawRect.right = drawRect.left + rect.left - 1;
- drawRect.top = rect.top * ebx;
- drawRect.bottom = rect.top * ebx + rect.top - 1;
-
- bool doit;
- if (drawRect.right >= 0 && drawRect.bottom >= 0 && drawRect.left <= rect.right && drawRect.top <= rect.bottom) {
- doit = true;
- } else {
- doit = false;
- }
-
- if (doit) {
- if (drawRect.left < 0) {
- drawRect.left = 0;
- }
-
- if (drawRect.top < 0) {
- drawRect.top = 0;
- }
-
- if (drawRect.right > rect.right) {
- drawRect.right = rect.right;
- }
-
- if (drawRect.bottom > rect.bottom) {
- drawRect.bottom = rect.bottom;
- }
- } else {
- drawRect.right = 0;
- drawRect.bottom = 0;
- drawRect.left = 0;
- drawRect.top = 0;
- }
-
- fillRect(bitmapData, drawRect, showStyle->color, showStyle->width);
-
- int eax = ebx;
- do {
- eax >>= 1;
- if (ebx & 1) {
- ebx = showStyle->dissolveSeed;
- ebx ^= eax;
- } else {
- ebx = eax;
- }
- } while (ebx >= divisions);
-
- if (showStyle->currentStep != showStyle->divisions) {
- ebp++;
- } else {
- drawRect.left = 0;
- drawRect.top = 0;
- drawRect.right = showStyle->width - 1;
- drawRect.bottom = showStyle->height - 1;
- fillRect(bitmapData, drawRect, showStyle->color, showStyle->width);
- }
-
- } while (ebp <= showStyle->divisions);
-
- showStyle->unknown3A = ebx;
- ++showStyle->currentStep;
- showStyle->nextTick += showStyle->delay;
- // _screen->updateScreenItem(showStyle->bitmapScreenItem);
- }
-
- if (showStyle->currentStep >= showStyle->divisions) {
- if (showStyle->fadeUp) {
- showStyle->processed = true;
- }
-
- return true;
- }
-
- return false;
-}
-
-bool GfxFrameout::processShowStyle12(ShowStyleEntry *const showStyle) {
- return true;
-}
-#endif
-
void GfxFrameout::kernelFrameOut(const bool shouldShowBits) {
if (_showStyles != nullptr) {
processShowStyles();
@@ -1975,8 +1385,8 @@ void GfxFrameout::kernelFrameOut(const bool shouldShowBits) {
_palMorphIsOn = false;
} else {
// TODO: Window scroll
-// if (g_ScrollWindow) {
-// doScroll();
+// if (g_PlaneScroll) {
+// processScrolls();
// }
frameOut(shouldShowBits);
@@ -1987,7 +1397,7 @@ void GfxFrameout::kernelFrameOut(const bool shouldShowBits) {
#pragma mark Mouse cursor
reg_t GfxFrameout::kernelIsOnMe(const reg_t object, const Common::Point &position, bool checkPixel) const {
- reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane));
+ const reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane));
Plane *plane = _visiblePlanes.findByObject(planeObject);
if (plane == nullptr) {
return make_reg(0, 0);
@@ -1998,6 +1408,13 @@ reg_t GfxFrameout::kernelIsOnMe(const reg_t object, const Common::Point &positio
return make_reg(0, 0);
}
+ // NOTE: The original engine passed a copy of the ScreenItem into isOnMe
+ // as a hack around the fact that the screen items in `_visiblePlanes`
+ // did not have their `_celObj` pointers cleared when their CelInfo was
+ // updated by `Plane::decrementScreenItemArrayCounts`. We handle this
+ // this more intelligently by clearing `_celObj` in the copy assignment
+ // operator, which is only ever called by `decrementScreenItemArrayCounts`
+ // anyway.
return make_reg(0, isOnMe(*screenItem, *plane, position, checkPixel));
}
@@ -2054,6 +1471,13 @@ void GfxFrameout::kernelSetNowSeen(const reg_t screenItemObject) const {
writeSelectorValue(_segMan, screenItemObject, SELECTOR(nsBottom), result.bottom - 1);
}
+void GfxFrameout::remapMarkRedraw() {
+ for (PlaneList::const_iterator it = _planes.begin(); it != _planes.end(); ++it) {
+ Plane *p = *it;
+ p->remapMarkRedraw();
+ }
+}
+
#pragma mark -
#pragma mark Debugging
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index 22c0e14829..8ed95a00de 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -130,64 +130,6 @@ struct ShowStyleEntry {
bool processed;
//
- // Engine-specific properties for SCI2 through 2.1early
- //
-
- // TODO: Could union this stuff to save literally
- // several bytes of memory.
-
- /**
- * The width of the plane. Used to determine the correct
- * size of screen items for wipes.
- */
- int width;
-
- /**
- * The height of the plane. Used to determine the correct
- * size of screen items for wipes.
- */
- int height;
-
- /**
- * The number of edges that a transition operates on.
- * Slide wipe: 1 edge
- * Reveal wipe: 2 edges
- * Iris wipe: 4 edges
- */
- // TODO: I have no idea why SCI engine stores this instead
- // of a screenItems count
- int edgeCount;
-
- /**
- * Used by transition types 1 through 10.
- * One screen item per division per edge.
- */
- ScreenItemList screenItems;
-
- /**
- * Used by transition types 11 and 12. A copy of the
- * visible frame buffer.
- */
- // TODO: This is a reg_t in SCI engine; not sure if
- // we can avoid allocation through SegMan or not.
- reg_t bitmapMemId;
-
- /**
- * Used by transition types 11 and 12. A screen item
- * used to display the associated bitmap data.
- */
- ScreenItem *bitmapScreenItem;
-
- /**
- * A number used to pick pixels to dissolve by types
- * 11 and 12.
- */
- int dissolveSeed;
- int unknown3A;
- // max?
- int dissolveInitial;
-
- //
// Engine specific properties for SCI2.1mid through SCI3
//
@@ -240,6 +182,7 @@ public:
#pragma mark Screen items
private:
void deleteScreenItem(ScreenItem *screenItem, const reg_t plane);
+ void remapMarkRedraw();
public:
void kernelAddScreenItem(const reg_t object);
@@ -325,14 +268,11 @@ private:
bool processShowStyleNone(ShowStyleEntry *showStyle);
bool processShowStyleMorph(ShowStyleEntry *showStyle);
bool processShowStyleFade(const int direction, ShowStyleEntry *showStyle);
-#if 0
- bool processShowStyleWipe(const int direction, ShowStyleEntry *const showStyle);
-#endif
public:
// NOTE: This signature is taken from SCI3 Phantasmagoria 2
// and is valid for all implementations of SCI32
- void kernelSetShowStyle(const uint16 argc, const reg_t &planeObj, const ShowStyleType type, const int16 seconds, const int16 direction, const int16 priority, const int16 animate, const int16 frameOutNow, const reg_t &pFadeArray, const int16 divisions, const int16 blackScreen);
+ void kernelSetShowStyle(const uint16 argc, const reg_t planeObj, const ShowStyleType type, const int16 seconds, const int16 direction, const int16 priority, const int16 animate, const int16 frameOutNow, reg_t pFadeArray, int16 divisions, const int16 blackScreen);
#pragma mark -
#pragma mark Rendering
@@ -351,13 +291,6 @@ private:
*/
Buffer _currentBuffer;
- // TODO: In SCI2.1/SQ6, priority map pixels are not allocated
- // by default. In SCI2/GK1, pixels are allocated, but not used
- // anywhere except within CelObj::Draw in seemingly the same
- // way they are used in SCI2.1/SQ6: that is, never read, only
- // written.
- Buffer _priorityMap;
-
/**
* TODO: Documentation
*/
@@ -456,12 +389,6 @@ private:
public:
/**
- * TODO: Document
- * This is used by CelObj::Draw.
- */
- bool _hasRemappedScreenItem;
-
- /**
* Whether palMorphFrameOut should be used instead of
* frameOut for rendering. Used by kMorphOn to
* explicitly enable palMorphFrameOut for one frame.
@@ -487,11 +414,6 @@ public:
*/
void alterVmap(const Palette &palette1, const Palette &palette2, const int8 style, const int8 *const styleRanges);
- // TODO: SCI2 engine never uses priority map?
- inline Buffer &getPriorityMap() {
- return _priorityMap;
- }
-
// NOTE: This function is used within ScreenItem subsystem and assigned
// to various booleanish fields that seem to represent the state of the
// screen item (created, updated, deleted). In GK1/DOS, Phant1/m68k,
diff --git a/engines/sci/graphics/palette32.cpp b/engines/sci/graphics/palette32.cpp
index 82e8d779f1..6844011675 100644
--- a/engines/sci/graphics/palette32.cpp
+++ b/engines/sci/graphics/palette32.cpp
@@ -28,6 +28,7 @@
#include "sci/event.h"
#include "sci/resource.h"
#include "sci/graphics/palette32.h"
+#include "sci/graphics/remap.h"
#include "sci/graphics/screen.h"
namespace Sci {
@@ -223,9 +224,7 @@ int16 GfxPalette32::matchColor(const byte r, const byte g, const byte b, const i
bool GfxPalette32::updateForFrame() {
applyAll();
_versionUpdated = false;
- // TODO: Implement remapping
- // return g_sci->_gfxFrameout->remapAllTables(_nextPalette != _sysPalette);
- return false;
+ return g_sci->_gfxRemap32->remapAllTables(_nextPalette != _sysPalette);
}
void GfxPalette32::updateFFrame() {
@@ -233,8 +232,7 @@ void GfxPalette32::updateFFrame() {
_nextPalette.colors[i] = _sourcePalette.colors[i];
}
_versionUpdated = false;
- // TODO: Implement remapping
- // g_sci->_gfxFrameout->remapAllTables(_nextPalette != _sysPalette);
+ g_sci->_gfxRemap32->remapAllTables(_nextPalette != _sysPalette);
}
void GfxPalette32::updateHardware() {
diff --git a/engines/sci/graphics/palette32.h b/engines/sci/graphics/palette32.h
index b8388d11ea..a5450776dc 100644
--- a/engines/sci/graphics/palette32.h
+++ b/engines/sci/graphics/palette32.h
@@ -257,6 +257,7 @@ public:
void cycleAllOff();
void applyAllCycles();
void applyCycles();
+ const bool *getCyclemap() { return _cycleMap; }
#pragma mark -
#pragma mark Fading
diff --git a/engines/sci/graphics/plane32.cpp b/engines/sci/graphics/plane32.cpp
index 099d4dd8c4..d05e4f79e1 100644
--- a/engines/sci/graphics/plane32.cpp
+++ b/engines/sci/graphics/plane32.cpp
@@ -27,6 +27,7 @@
#include "sci/graphics/frameout.h"
#include "sci/graphics/lists32.h"
#include "sci/graphics/plane32.h"
+#include "sci/graphics/remap.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/screen_item32.h"
@@ -317,7 +318,7 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList
vitem != nullptr &&
!vitem->_screenRect.isEmpty()
) {
- if (/* TODO: g_Remap_numActiveRemaps */ false) { // active remaps?
+ if (g_sci->_gfxRemap32->getRemapCount()) {
mergeToRectList(vitem->_screenRect, eraseList);
} else {
eraseList.add(vitem->_screenRect);
@@ -328,7 +329,7 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList
item->calcRects(*this);
if(!item->_screenRect.isEmpty()) {
- if (/* TODO: g_Remap_numActiveRemaps */ false) { // active remaps?
+ if (g_sci->_gfxRemap32->getRemapCount()) {
drawList.add(item, item->_screenRect);
mergeToRectList(item->_screenRect, eraseList);
} else {
@@ -338,7 +339,7 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList
} else if (item->_updated) {
// add old rect to erase list, new item to draw list
item->calcRects(*this);
- if (/* TODO: g_Remap_numActiveRemaps */ false) { // active remaps
+ if (g_sci->_gfxRemap32->getRemapCount()) {
// if item and vitem don't overlap, ...
if (item->_screenRect.isEmpty() ||
i >= visiblePlaneItemCount ||
@@ -395,7 +396,6 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList
// over the currently inserted entries later.
DrawList::size_type drawListSizePrimary = drawList.size();
- // NOTE: Setting this to true fixes the menu bars in GK1
if (/* TODO: dword_C6288 */ false) { // "high resolution pictures"????
_screenItemList.sort();
bool encounteredPic = false;
@@ -453,7 +453,7 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList
}
}
- if (/* TODO: g_Remap_numActiveRemaps == 0 */ true) { // no remaps active?
+ if (g_sci->_gfxRemap32->getRemapCount() == 0) { // no remaps active?
// Add all items that overlap with items in the drawlist and have higher
// priority.
@@ -812,6 +812,17 @@ void Plane::scrollScreenItems(const int16 deltaX, const int16 deltaY, const bool
}
}
+void Plane::remapMarkRedraw() {
+ for (ScreenItemList::const_iterator screenItemPtr = _screenItemList.begin(); screenItemPtr != _screenItemList.end(); ++screenItemPtr) {
+ if (*screenItemPtr != nullptr) {
+ ScreenItem &screenItem = **screenItemPtr;
+ if (screenItem.getCelObj()._remap && !screenItem._deleted && !screenItem._created) {
+ screenItem._updated = g_sci->_gfxFrameout->getScreenCount();
+ }
+ }
+ }
+}
+
#pragma mark -
#pragma mark PlaneList
void PlaneList::add(Plane *plane) {
diff --git a/engines/sci/graphics/plane32.h b/engines/sci/graphics/plane32.h
index 51d93b78a5..770a6fa445 100644
--- a/engines/sci/graphics/plane32.h
+++ b/engines/sci/graphics/plane32.h
@@ -166,7 +166,7 @@ public:
* another plane and cleared when draw list calculation
* occurs.
*/
- int _priorityChanged; // ?
+ int _priorityChanged;
/**
* A handle to the VM object corresponding to this
@@ -182,7 +182,12 @@ public:
int16 _priority;
/**
- * TODO: Document
+ * Whether or not all screen items in this plane should
+ * be redrawn on the next frameout, instead of just
+ * the screen items marked as updated. This is set when
+ * visual changes to the plane itself are made that
+ * affect the rendering of the entire plane, and cleared
+ * once those changes are rendered by `redrawAll`.
*/
int _redrawAllCount;
@@ -430,6 +435,8 @@ public:
* and adds them to the given draw and erase lists.
*/
void redrawAll(Plane *visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList);
+
+ void remapMarkRedraw();
};
#pragma mark -
diff --git a/engines/sci/graphics/remap.cpp b/engines/sci/graphics/remap.cpp
index 1f1ae4da0e..e331eaf971 100644
--- a/engines/sci/graphics/remap.cpp
+++ b/engines/sci/graphics/remap.cpp
@@ -23,6 +23,7 @@
#include "sci/sci.h"
#include "sci/resource.h"
#include "sci/graphics/palette.h"
+#include "sci/graphics/palette32.h"
#include "sci/graphics/remap.h"
#include "sci/graphics/screen.h"
@@ -31,8 +32,8 @@ namespace Sci {
#pragma mark -
#pragma mark SCI16 remapping (QFG4 demo)
-GfxRemap::GfxRemap(GfxScreen *screen, GfxPalette *palette)
- : _screen(screen), _palette(palette) {
+GfxRemap::GfxRemap(GfxPalette *palette)
+ : _palette(palette) {
_remapOn = false;
resetRemapping();
}
@@ -107,28 +108,279 @@ void GfxRemap::updateRemapping() {
#pragma mark -
#pragma mark SCI32 remapping
-#if 0
-// TODO
-void GfxRemap32::setRemappingPercentGray(byte color, byte percent) {
- _remapOn = true;
+#ifdef ENABLE_SCI32
- // We need to defer the setup of the remapping table every time the screen
- // palette is changed, so that kernelFindColor() can find the correct
- // colors. Set it once here, in case the palette stays the same and update
- // it on each palette change by copySysPaletteToScreen().
- _remappingPercentToSet = percent;
+GfxRemap32::GfxRemap32(GfxPalette32 *palette) : _palette(palette) {
+ for (int i = 0; i < REMAP_COLOR_COUNT; i++)
+ _remaps[i] = RemapParams(0, 0, 0, 0, 100, kRemappingNone);
+ _noMapStart = _noMapCount = 0;
+ _update = false;
+ _remapCount = 0;
- // Note: This is not what the original does, but the results are the same visually
- for (int i = 0; i < 256; i++) {
- byte rComponent = (byte)(_sysPalette.colors[i].r * _remappingPercentToSet * 0.30 / 100);
- byte gComponent = (byte)(_sysPalette.colors[i].g * _remappingPercentToSet * 0.59 / 100);
- byte bComponent = (byte)(_sysPalette.colors[i].b * _remappingPercentToSet * 0.11 / 100);
- byte luminosity = rComponent + gComponent + bComponent;
- _remappingByPercent[i] = kernelFindColor(luminosity, luminosity, luminosity);
+ // The remap range was 245 - 254 in SCI2, but was changed to 235 - 244 in SCI21 middle
+ _remapEndColor = (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) ? 244 : 254;
+}
+
+void GfxRemap32::remapOff(byte color) {
+ if (!color) {
+ for (int i = 0; i < REMAP_COLOR_COUNT; i++)
+ _remaps[i] = RemapParams(0, 0, 0, 0, 100, kRemappingNone);
+
+ _remapCount = 0;
+ } else {
+ assert(_remapEndColor - color >= 0 && _remapEndColor - color < REMAP_COLOR_COUNT);
+ const byte index = _remapEndColor - color;
+ _remaps[index] = RemapParams(0, 0, 0, 0, 100, kRemappingNone);
+ _remapCount--;
}
- _remappingType[color] = kRemappingByPercent;
+ _update = true;
+}
+
+void GfxRemap32::setRemappingRange(byte color, byte from, byte to, byte base) {
+ assert(_remapEndColor - color >= 0 && _remapEndColor - color < REMAP_COLOR_COUNT);
+ _remaps[_remapEndColor - color] = RemapParams(from, to, base, 0, 100, kRemappingByRange);
+ initColorArrays(_remapEndColor - color);
+ _remapCount++;
+ _update = true;
+}
+
+void GfxRemap32::setRemappingPercent(byte color, byte percent) {
+ assert(_remapEndColor - color >= 0 && _remapEndColor - color < REMAP_COLOR_COUNT);
+ _remaps[_remapEndColor - color] = RemapParams(0, 0, 0, 0, percent, kRemappingByPercent);
+ initColorArrays(_remapEndColor - color);
+ _remapCount++;
+ _update = true;
+}
+
+void GfxRemap32::setRemappingToGray(byte color, byte gray) {
+ assert(_remapEndColor - color >= 0 && _remapEndColor - color < REMAP_COLOR_COUNT);
+ _remaps[_remapEndColor - color] = RemapParams(0, 0, 0, gray, 100, kRemappingToGray);
+ initColorArrays(_remapEndColor - color);
+ _remapCount++;
+ _update = true;
+}
+
+void GfxRemap32::setRemappingToPercentGray(byte color, byte gray, byte percent) {
+ assert(_remapEndColor - color >= 0 && _remapEndColor - color < REMAP_COLOR_COUNT);
+ _remaps[_remapEndColor - color] = RemapParams(0, 0, 0, gray, percent, kRemappingToPercentGray);
+ initColorArrays(_remapEndColor - color);
+ _remapCount++;
+ _update = true;
+}
+
+void GfxRemap32::setNoMatchRange(byte from, byte count) {
+ _noMapStart = from;
+ _noMapCount = count;
+}
+
+bool GfxRemap32::remapEnabled(byte color) const {
+ assert(_remapEndColor - color >= 0 && _remapEndColor - color < REMAP_COLOR_COUNT);
+ const byte index = _remapEndColor - color;
+ return (_remaps[index].type != kRemappingNone);
+}
+
+byte GfxRemap32::remapColor(byte color, byte target) {
+ assert(_remapEndColor - color >= 0 && _remapEndColor - color < REMAP_COLOR_COUNT);
+ const byte index = _remapEndColor - color;
+ if (_remaps[index].type != kRemappingNone)
+ return _remaps[index].remap[target];
+ else
+ return target;
+}
+
+void GfxRemap32::initColorArrays(byte index) {
+ Palette *curPalette = &_palette->_sysPalette;
+ RemapParams *curRemap = &_remaps[index];
+
+ memcpy(curRemap->curColor, curPalette->colors, NON_REMAPPED_COLOR_COUNT * sizeof(Color));
+ memcpy(curRemap->targetColor, curPalette->colors, NON_REMAPPED_COLOR_COUNT * sizeof(Color));
+}
+
+bool GfxRemap32::updateRemap(byte index, bool palChanged) {
+ int result;
+ RemapParams *curRemap = &_remaps[index];
+ const Palette *curPalette = &_palette->_sysPalette;
+ const Palette *nextPalette = _palette->getNextPalette();
+ bool changed = false;
+
+ if (!_update && !palChanged)
+ return false;
+
+ Common::fill(_targetChanged, _targetChanged + NON_REMAPPED_COLOR_COUNT, false);
+
+ switch (curRemap->type) {
+ case kRemappingNone:
+ return false;
+ case kRemappingByRange:
+ for (int i = 0; i < NON_REMAPPED_COLOR_COUNT; i++) {
+ if (curRemap->from <= i && i <= curRemap->to)
+ result = i + curRemap->base;
+ else
+ result = i;
+
+ if (curRemap->remap[i] != result) {
+ changed = true;
+ curRemap->remap[i] = result;
+ }
+
+ curRemap->colorChanged[i] = true;
+ }
+ return changed;
+ case kRemappingByPercent:
+ for (int i = 1; i < NON_REMAPPED_COLOR_COUNT; i++) {
+ // NOTE: This method uses nextPalette instead of curPalette
+ Color color = nextPalette->colors[i];
+
+ if (curRemap->curColor[i] != color) {
+ curRemap->colorChanged[i] = true;
+ curRemap->curColor[i] = color;
+ }
+
+ if (curRemap->percent != curRemap->oldPercent || curRemap->colorChanged[i]) {
+ byte red = CLIP<byte>(color.r * curRemap->percent / 100, 0, 255);
+ byte green = CLIP<byte>(color.g * curRemap->percent / 100, 0, 255);
+ byte blue = CLIP<byte>(color.b * curRemap->percent / 100, 0, 255);
+ byte used = curRemap->targetColor[i].used;
+
+ Color newColor = { used, red, green, blue };
+ if (curRemap->targetColor[i] != newColor) {
+ _targetChanged[i] = true;
+ curRemap->targetColor[i] = newColor;
+ }
+ }
+ }
+
+ changed = applyRemap(index);
+ Common::fill(curRemap->colorChanged, curRemap->colorChanged + NON_REMAPPED_COLOR_COUNT, false);
+ curRemap->oldPercent = curRemap->percent;
+ return changed;
+ case kRemappingToGray:
+ for (int i = 1; i < NON_REMAPPED_COLOR_COUNT; i++) {
+ Color color = curPalette->colors[i];
+
+ if (curRemap->curColor[i] != color) {
+ curRemap->colorChanged[i] = true;
+ curRemap->curColor[i] = color;
+ }
+
+ if (curRemap->gray != curRemap->oldGray || curRemap->colorChanged[i]) {
+ byte lumosity = ((color.r * 77) + (color.g * 151) + (color.b * 28)) >> 8;
+ byte red = CLIP<byte>(color.r - ((color.r - lumosity) * curRemap->gray / 100), 0, 255);
+ byte green = CLIP<byte>(color.g - ((color.g - lumosity) * curRemap->gray / 100), 0, 255);
+ byte blue = CLIP<byte>(color.b - ((color.b - lumosity) * curRemap->gray / 100), 0, 255);
+ byte used = curRemap->targetColor[i].used;
+
+ Color newColor = { used, red, green, blue };
+ if (curRemap->targetColor[i] != newColor) {
+ _targetChanged[i] = true;
+ curRemap->targetColor[i] = newColor;
+ }
+ }
+ }
+
+ changed = applyRemap(index);
+ Common::fill(curRemap->colorChanged, curRemap->colorChanged + NON_REMAPPED_COLOR_COUNT, false);
+ curRemap->oldGray = curRemap->gray;
+ return changed;
+ case kRemappingToPercentGray:
+ for (int i = 1; i < NON_REMAPPED_COLOR_COUNT; i++) {
+ Color color = curPalette->colors[i];
+
+ if (curRemap->curColor[i] != color) {
+ curRemap->colorChanged[i] = true;
+ curRemap->curColor[i] = color;
+ }
+
+ if (curRemap->percent != curRemap->oldPercent || curRemap->gray != curRemap->oldGray || curRemap->colorChanged[i]) {
+ byte lumosity = ((color.r * 77) + (color.g * 151) + (color.b * 28)) >> 8;
+ lumosity = lumosity * curRemap->percent / 100;
+ byte red = CLIP<byte>(color.r - ((color.r - lumosity) * curRemap->gray / 100), 0, 255);
+ byte green = CLIP<byte>(color.g - ((color.g - lumosity) * curRemap->gray / 100), 0, 255);
+ byte blue = CLIP<byte>(color.b - ((color.b - lumosity) * curRemap->gray / 100), 0, 255);
+ byte used = curRemap->targetColor[i].used;
+
+ Color newColor = { used, red, green, blue };
+ if (curRemap->targetColor[i] != newColor) {
+ _targetChanged[i] = true;
+ curRemap->targetColor[i] = newColor;
+ }
+ }
+ }
+
+ changed = applyRemap(index);
+ Common::fill(curRemap->colorChanged, curRemap->colorChanged + NON_REMAPPED_COLOR_COUNT, false);
+ curRemap->oldPercent = curRemap->percent;
+ curRemap->oldGray = curRemap->gray;
+ return changed;
+ default:
+ return false;
+ }
}
+
+static int colorDistance(Color a, Color b) {
+ int rDiff = (a.r - b.r) * (a.r - b.r);
+ int gDiff = (a.g - b.g) * (a.g - b.g);
+ int bDiff = (a.b - b.b) * (a.b - b.b);
+ return rDiff + gDiff + bDiff;
+}
+
+bool GfxRemap32::applyRemap(byte index) {
+ RemapParams *curRemap = &_remaps[index];
+ const bool *cycleMap = _palette->getCyclemap();
+ bool unmappedColors[NON_REMAPPED_COLOR_COUNT];
+ Color newColors[NON_REMAPPED_COLOR_COUNT];
+ bool changed = false;
+
+ Common::fill(unmappedColors, unmappedColors + NON_REMAPPED_COLOR_COUNT, false);
+ if (_noMapCount)
+ Common::fill(unmappedColors + _noMapStart, unmappedColors + _noMapStart + _noMapCount, true);
+
+ for (int i = 0; i < NON_REMAPPED_COLOR_COUNT; i++) {
+ if (cycleMap[i])
+ unmappedColors[i] = true;
+ }
+
+ int curColor = 0;
+ for (int i = 1; i < NON_REMAPPED_COLOR_COUNT; i++) {
+ if (curRemap->colorChanged[i] && !unmappedColors[i])
+ newColors[curColor++] = curRemap->curColor[i];
+ }
+
+ for (int i = 1; i < NON_REMAPPED_COLOR_COUNT; i++) {
+ Color targetColor = curRemap->targetColor[i];
+ bool colorChanged = curRemap->colorChanged[curRemap->remap[i]];
+
+ if (!_targetChanged[i] && !colorChanged)
+ continue;
+
+ if (_targetChanged[i] && colorChanged)
+ if (curRemap->distance[i] < 100 && colorDistance(targetColor, curRemap->curColor[curRemap->remap[i]]) <= curRemap->distance[i])
+ continue;
+
+ int diff = 0;
+ int16 result = _palette->matchColor(targetColor.r, targetColor.g, targetColor.b, curRemap->distance[i], diff, unmappedColors);
+ if (result != -1 && curRemap->remap[i] != result) {
+ changed = true;
+ curRemap->remap[i] = result;
+ curRemap->distance[i] = diff;
+ }
+ }
+
+ return changed;
+}
+
+bool GfxRemap32::remapAllTables(bool palChanged) {
+ bool changed = false;
+
+ for (int i = 0; i < REMAP_COLOR_COUNT; i++) {
+ changed |= updateRemap(i, palChanged);
+ }
+
+ _update = false;
+ return changed;
+}
+
#endif
} // End of namespace Sci
diff --git a/engines/sci/graphics/remap.h b/engines/sci/graphics/remap.h
index e92eaffad2..d012568f7f 100644
--- a/engines/sci/graphics/remap.h
+++ b/engines/sci/graphics/remap.h
@@ -33,16 +33,22 @@ class GfxScreen;
enum ColorRemappingType {
kRemappingNone = 0,
kRemappingByRange = 1,
- kRemappingByPercent = 2
+ kRemappingByPercent = 2,
+ kRemappingToGray = 3,
+ kRemappingToPercentGray = 4
};
+#define REMAP_COLOR_COUNT 9
+#define NON_REMAPPED_COLOR_COUNT 236
+
/**
* Remap class, handles color remapping
*/
class GfxRemap {
public:
- GfxRemap(GfxScreen *screen, GfxPalette *_palette);
+ GfxRemap(GfxPalette *_palette);
~GfxRemap();
+
void resetRemapping();
void setRemappingPercent(byte color, byte percent);
void setRemappingRange(byte color, byte from, byte to, byte base);
@@ -64,11 +70,82 @@ private:
};
#ifdef ENABLE_SCI32
+
+struct RemapParams {
+ byte from;
+ byte to;
+ byte base;
+ byte gray;
+ byte oldGray;
+ byte percent;
+ byte oldPercent;
+ ColorRemappingType type;
+ Color curColor[256];
+ Color targetColor[256];
+ byte distance[256];
+ byte remap[256];
+ bool colorChanged[256];
+
+ RemapParams() {
+ from = to = base = gray = oldGray = percent = oldPercent = 0;
+ type = kRemappingNone;
+
+ // curColor and targetColor are initialized in GfxRemap32::initColorArrays
+ memset(curColor, 0, 256 * sizeof(Color));
+ memset(targetColor, 0, 256 * sizeof(Color));
+ memset(distance, 0, 256);
+ for (int i = 0; i < NON_REMAPPED_COLOR_COUNT; i++)
+ remap[i] = i;
+ Common::fill(colorChanged, colorChanged + ARRAYSIZE(colorChanged), true);
+ }
+
+ RemapParams(byte from_, byte to_, byte base_, byte gray_, byte percent_, ColorRemappingType type_) {
+ from = from_;
+ to = to_;
+ base = base_;
+ gray = oldGray = gray_;
+ percent = oldPercent = percent_;
+ type = type_;
+
+ // curColor and targetColor are initialized in GfxRemap32::initColorArrays
+ memset(curColor, 0, 256 * sizeof(Color));
+ memset(targetColor, 0, 256 * sizeof(Color));
+ memset(distance, 0, 256);
+ for (int i = 0; i < NON_REMAPPED_COLOR_COUNT; i++)
+ remap[i] = i;
+ Common::fill(colorChanged, colorChanged + ARRAYSIZE(colorChanged), true);
+ }
+};
+
class GfxRemap32 {
public:
- GfxRemap32(GfxScreen *screen, GfxPalette *_palette) {}
+ GfxRemap32(GfxPalette32 *palette);
~GfxRemap32() {}
- //void setRemappingPercentGray(byte color, byte percent);
+
+ void remapOff(byte color);
+ void setRemappingRange(byte color, byte from, byte to, byte base);
+ void setRemappingPercent(byte color, byte percent);
+ void setRemappingToGray(byte color, byte gray);
+ void setRemappingToPercentGray(byte color, byte gray, byte percent);
+ void setNoMatchRange(byte from, byte count);
+ bool remapEnabled(byte color) const;
+ byte remapColor(byte color, byte target);
+ bool remapAllTables(bool palChanged);
+ int getRemapCount() const { return _remapCount; }
+ int getStartColor() const { return _remapEndColor - REMAP_COLOR_COUNT + 1; }
+ int getEndColor() const { return _remapEndColor; }
+private:
+ GfxPalette32 *_palette;
+ RemapParams _remaps[REMAP_COLOR_COUNT];
+ bool _update;
+ byte _noMapStart, _noMapCount;
+ bool _targetChanged[NON_REMAPPED_COLOR_COUNT];
+ byte _remapEndColor;
+ int _remapCount;
+
+ void initColorArrays(byte index);
+ bool applyRemap(byte index);
+ bool updateRemap(byte index, bool palChanged);
};
#endif
diff --git a/engines/sci/graphics/screen_item32.cpp b/engines/sci/graphics/screen_item32.cpp
index 41771c802c..c3fdbb6845 100644
--- a/engines/sci/graphics/screen_item32.cpp
+++ b/engines/sci/graphics/screen_item32.cpp
@@ -115,7 +115,17 @@ _screenRect(other._screenRect) {
}
void ScreenItem::operator=(const ScreenItem &other) {
- _celInfo = other._celInfo;
+ // NOTE: The original engine did not check for differences in `_celInfo`
+ // to clear `_celObj` here; instead, it unconditionally set `_celInfo`,
+ // didn't clear `_celObj`, and did hacky stuff in `kIsOnMe` to avoid
+ // testing a mismatched `_celObj`. See `GfxFrameout::kernelIsOnMe` for
+ // more detail.
+ if (_celInfo != other._celInfo) {
+ _celInfo = other._celInfo;
+ delete _celObj;
+ _celObj = nullptr;
+ }
+
_screenRect = other._screenRect;
_mirrorX = other._mirrorX;
_useInsetRect = other._useInsetRect;
@@ -241,28 +251,33 @@ void ScreenItem::calcRects(const Plane &plane) {
_insetRect = celRect;
}
- Ratio newRatioX;
- Ratio newRatioY;
+ Ratio scaleX, scaleY;
if (_scale.signal & kScaleSignalDoScaling32) {
if (_scale.signal & kScaleSignalUseVanishingPoint) {
int num = _scale.max * (_position.y - plane._vanishingPoint.y) / (scriptWidth - plane._vanishingPoint.y);
- newRatioX = Ratio(num, 128);
- newRatioY = Ratio(num, 128);
+ scaleX = Ratio(num, 128);
+ scaleY = Ratio(num, 128);
} else {
- newRatioX = Ratio(_scale.x, 128);
- newRatioY = Ratio(_scale.y, 128);
+ scaleX = Ratio(_scale.x, 128);
+ scaleY = Ratio(_scale.y, 128);
}
}
- if (newRatioX.getNumerator() && newRatioY.getNumerator()) {
+ if (scaleX.getNumerator() && scaleY.getNumerator()) {
_screenItemRect = _insetRect;
+ const Ratio celToScreenX(screenWidth, celObj._scaledWidth);
+ const Ratio celToScreenY(screenHeight, celObj._scaledHeight);
+
+ // Cel may use a coordinate system that is not the same size as the
+ // script coordinate system (usually this means high-resolution
+ // pictures with low-resolution scripts)
if (celObj._scaledWidth != scriptWidth || celObj._scaledHeight != scriptHeight) {
if (_useInsetRect) {
- Ratio celScriptXRatio(celObj._scaledWidth, scriptWidth);
- Ratio celScriptYRatio(celObj._scaledHeight, scriptHeight);
- mulru(_screenItemRect, celScriptXRatio, celScriptYRatio, 0);
+ const Ratio scriptToCelX(celObj._scaledWidth, scriptWidth);
+ const Ratio scriptToCelY(celObj._scaledHeight, scriptHeight);
+ mulru(_screenItemRect, scriptToCelX, scriptToCelY, 0);
if (_screenItemRect.intersects(celRect)) {
_screenItemRect.clip(celRect);
@@ -278,26 +293,25 @@ void ScreenItem::calcRects(const Plane &plane) {
displaceX = celObj._width - celObj._displace.x - 1;
}
- if (!newRatioX.isOne() || !newRatioY.isOne()) {
- mulinc(_screenItemRect, newRatioX, newRatioY);
- displaceX = (displaceX * newRatioX).toInt();
- displaceY = (displaceY * newRatioY).toInt();
+ if (!scaleX.isOne() || !scaleY.isOne()) {
+ mulinc(_screenItemRect, scaleX, scaleY);
+ displaceX = (displaceX * scaleX).toInt();
+ displaceY = (displaceY * scaleY).toInt();
}
- Ratio celXRatio(screenWidth, celObj._scaledWidth);
- Ratio celYRatio(screenHeight, celObj._scaledHeight);
-
- displaceX = (displaceX * celXRatio).toInt();
- displaceY = (displaceY * celYRatio).toInt();
+ mulinc(_screenItemRect, celToScreenX, celToScreenY);
+ displaceX = (displaceX * celToScreenX).toInt();
+ displaceY = (displaceY * celToScreenY).toInt();
- mulinc(_screenItemRect, celXRatio, celYRatio);
+ const Ratio scriptToScreenX = Ratio(screenWidth, scriptWidth);
+ const Ratio scriptToScreenY = Ratio(screenHeight, scriptHeight);
if (/* TODO: dword_C6288 */ false && _celInfo.type == kCelTypePic) {
_scaledPosition.x = _position.x;
_scaledPosition.y = _position.y;
} else {
- _scaledPosition.x = (_position.x * screenWidth / scriptWidth) - displaceX;
- _scaledPosition.y = (_position.y * screenHeight / scriptHeight) - displaceY;
+ _scaledPosition.x = (_position.x * scriptToScreenX).toInt() - displaceX;
+ _scaledPosition.y = (_position.y * scriptToScreenY).toInt() - displaceY;
}
_screenItemRect.translate(_scaledPosition.x, _scaledPosition.y);
@@ -305,14 +319,14 @@ void ScreenItem::calcRects(const Plane &plane) {
if (_mirrorX != celObj._mirrorX && _celInfo.type == kCelTypePic) {
Common::Rect temp(_insetRect);
- if (!newRatioX.isOne()) {
- mulinc(temp, newRatioX, Ratio());
+ if (!scaleX.isOne()) {
+ mulinc(temp, scaleX, Ratio());
}
- mulinc(temp, celXRatio, Ratio());
+ mulinc(temp, celToScreenX, Ratio());
CelObjPic *celObjPic = dynamic_cast<CelObjPic *>(_celObj);
- temp.translate(celObjPic->_relativePosition.x * screenWidth / scriptWidth - displaceX, 0);
+ temp.translate((celObjPic->_relativePosition.x * scriptToScreenX).toInt() - displaceX, 0);
// TODO: This is weird.
int deltaX = plane._planeRect.width() - temp.right - 1 - temp.left;
@@ -325,16 +339,16 @@ void ScreenItem::calcRects(const Plane &plane) {
_scaledPosition.y += plane._planeRect.top;
_screenItemRect.translate(plane._planeRect.left, plane._planeRect.top);
- _ratioX = newRatioX * Ratio(screenWidth, celObj._scaledWidth);
- _ratioY = newRatioY * Ratio(screenHeight, celObj._scaledHeight);
+ _ratioX = scaleX * celToScreenX;
+ _ratioY = scaleY * celToScreenY;
} else {
int displaceX = celObj._displace.x;
if (_mirrorX != celObj._mirrorX && _celInfo.type != kCelTypePic) {
displaceX = celObj._width - celObj._displace.x - 1;
}
- if (!newRatioX.isOne() || !newRatioY.isOne()) {
- mulinc(_screenItemRect, newRatioX, newRatioY);
+ if (!scaleX.isOne() || !scaleY.isOne()) {
+ mulinc(_screenItemRect, scaleX, scaleY);
// TODO: This was in the original code, baked into the
// multiplication though it is not immediately clear
// why this is the only one that reduces the BR corner
@@ -342,20 +356,20 @@ void ScreenItem::calcRects(const Plane &plane) {
_screenItemRect.bottom -= 1;
}
- _scaledPosition.x = _position.x - (displaceX * newRatioX).toInt();
- _scaledPosition.y = _position.y - (celObj._displace.y * newRatioY).toInt();
+ _scaledPosition.x = _position.x - (displaceX * scaleX).toInt();
+ _scaledPosition.y = _position.y - (celObj._displace.y * scaleY).toInt();
_screenItemRect.translate(_scaledPosition.x, _scaledPosition.y);
if (_mirrorX != celObj._mirrorX && _celInfo.type == kCelTypePic) {
Common::Rect temp(_insetRect);
- if (!newRatioX.isOne()) {
- mulinc(temp, newRatioX, Ratio());
+ if (!scaleX.isOne()) {
+ mulinc(temp, scaleX, Ratio());
temp.right -= 1;
}
CelObjPic *celObjPic = dynamic_cast<CelObjPic *>(_celObj);
- temp.translate(celObjPic->_relativePosition.x - (displaceX * newRatioX).toInt(), celObjPic->_relativePosition.y - (celObj._displace.y * newRatioY).toInt());
+ temp.translate(celObjPic->_relativePosition.x - (displaceX * scaleX).toInt(), celObjPic->_relativePosition.y - (celObj._displace.y * scaleY).toInt());
// TODO: This is weird.
int deltaX = plane._gameRect.width() - temp.right - 1 - temp.left;
@@ -368,15 +382,13 @@ void ScreenItem::calcRects(const Plane &plane) {
_scaledPosition.y += plane._gameRect.top;
_screenItemRect.translate(plane._gameRect.left, plane._gameRect.top);
- if (screenWidth != celObj._scaledWidth || celObj._scaledHeight != screenHeight) {
- Ratio celXRatio(screenWidth, celObj._scaledWidth);
- Ratio celYRatio(screenHeight, celObj._scaledHeight);
- mulru(_scaledPosition, celXRatio, celYRatio);
- mulru(_screenItemRect, celXRatio, celYRatio, 1);
+ if (celObj._scaledWidth != screenWidth || celObj._scaledHeight != screenHeight) {
+ mulru(_scaledPosition, celToScreenX, celToScreenY);
+ mulru(_screenItemRect, celToScreenX, celToScreenY, 1);
}
- _ratioX = newRatioX * Ratio(screenWidth, celObj._scaledWidth);
- _ratioY = newRatioY * Ratio(screenHeight, celObj._scaledHeight);
+ _ratioX = scaleX * celToScreenX;
+ _ratioY = scaleY * celToScreenY;
}
_screenRect = _screenItemRect;
@@ -547,9 +559,9 @@ Common::Rect ScreenItem::getNowSeenRect(const Plane &plane) const {
if (celObj._scaledWidth != scriptWidth || celObj._scaledHeight != scriptHeight) {
if (_useInsetRect) {
- Ratio scriptToScaledX(celObj._scaledWidth, scriptWidth);
- Ratio scriptToScaledY(celObj._scaledHeight, scriptHeight);
- mulru(nsRect, scriptToScaledX, scriptToScaledY, 0);
+ Ratio scriptToCelX(celObj._scaledWidth, scriptWidth);
+ Ratio scriptToCelY(celObj._scaledHeight, scriptHeight);
+ mulru(nsRect, scriptToCelX, scriptToCelY, 0);
// TODO: This is weird. Checking to see if the inset rect is
// fully inside the bounds of the celObjRect, and then
@@ -570,13 +582,13 @@ Common::Rect ScreenItem::getNowSeenRect(const Plane &plane) const {
nsRect.bottom -= 1;
}
- Ratio scaledToScriptX(scriptWidth, celObj._scaledWidth);
- Ratio scaledToScriptY(scriptHeight, celObj._scaledHeight);
+ Ratio celToScriptX(scriptWidth, celObj._scaledWidth);
+ Ratio celToScriptY(scriptHeight, celObj._scaledHeight);
- displaceX = (displaceX * scaleX * scaledToScriptX).toInt();
- displaceY = (displaceY * scaleY * scaledToScriptY).toInt();
+ displaceX = (displaceX * scaleX * celToScriptX).toInt();
+ displaceY = (displaceY * scaleY * celToScriptY).toInt();
- mulinc(nsRect, scaledToScriptX, scaledToScriptY);
+ mulinc(nsRect, celToScriptX, celToScriptY);
nsRect.translate(_position.x - displaceX, _position.y - displaceY);
} else {
if (!scaleX.isOne() || !scaleY.isOne()) {
diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp
index fa19047a4c..99ffc6e328 100644
--- a/engines/sci/graphics/text32.cpp
+++ b/engines/sci/graphics/text32.cpp
@@ -625,4 +625,33 @@ int16 GfxText32::getStringWidth(const Common::String &text) {
return getTextWidth(text, 0, 10000);
}
+int16 GfxText32::getTextCount(const Common::String &text, const uint index, const Common::Rect &textRect, const bool doScaling) {
+ const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+
+ Common::Rect scaledRect(textRect);
+ if (doScaling) {
+ mulinc(scaledRect, Ratio(_scaledWidth, scriptWidth), Ratio(_scaledHeight, scriptHeight));
+ }
+
+ Common::String oldText = _text;
+ _text = text;
+
+ uint charIndex = index;
+ int16 maxWidth = scaledRect.width();
+ int16 lineCount = (scaledRect.height() - 2) / _font->getHeight();
+ while (lineCount--) {
+ getLongest(&charIndex, maxWidth);
+ }
+
+ _text = oldText;
+ return charIndex - index;
+}
+
+int16 GfxText32::getTextCount(const Common::String &text, const uint index, const GuiResourceId fontId, const Common::Rect &textRect, const bool doScaling) {
+ setFont(fontId);
+ return getTextCount(text, index, textRect, doScaling);
+}
+
+
} // End of namespace Sci
diff --git a/engines/sci/graphics/text32.h b/engines/sci/graphics/text32.h
index 472d5e0956..5768ea0c59 100644
--- a/engines/sci/graphics/text32.h
+++ b/engines/sci/graphics/text32.h
@@ -458,6 +458,20 @@ public:
* Retrieves the width of a line of text.
*/
int16 getStringWidth(const Common::String &text);
+
+ /**
+ * Gets the number of characters of `text`, starting
+ * from `index`, that can be safely rendered into
+ * `textRect`.
+ */
+ int16 getTextCount(const Common::String &text, const uint index, const Common::Rect &textRect, const bool doScaling);
+
+ /**
+ * Gets the number of characters of `text`, starting
+ * from `index`, that can be safely rendered into
+ * `textRect` using the given font.
+ */
+ int16 getTextCount(const Common::String &text, const uint index, const GuiResourceId fontId, const Common::Rect &textRect, const bool doScaling);
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp
index ff3fc70619..1939e66179 100644
--- a/engines/sci/graphics/view.cpp
+++ b/engines/sci/graphics/view.cpp
@@ -975,13 +975,4 @@ void GfxView::adjustBackUpscaledCoordinates(int16 &y, int16 &x) {
_screen->adjustBackUpscaledCoordinates(y, x, _sci2ScaleRes);
}
-byte GfxView::getColorAtCoordinate(int16 loopNo, int16 celNo, int16 x, int16 y) {
- const CelInfo *celInfo = getCelInfo(loopNo, celNo);
- const byte *bitmap = getBitmap(loopNo, celNo);
- const int16 celWidth = celInfo->width;
-
- bitmap += (celWidth * y);
- return bitmap[x];
-}
-
} // End of namespace Sci
diff --git a/engines/sci/graphics/view.h b/engines/sci/graphics/view.h
index d8803db208..91590208c1 100644
--- a/engines/sci/graphics/view.h
+++ b/engines/sci/graphics/view.h
@@ -85,8 +85,6 @@ public:
void adjustToUpscaledCoordinates(int16 &y, int16 &x);
void adjustBackUpscaledCoordinates(int16 &y, int16 &x);
- byte getColorAtCoordinate(int16 loopNo, int16 celNo, int16 x, int16 y);
-
private:
void initData(GuiResourceId resourceId);
void unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCount);
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 6bc6650245..e14d12b918 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -684,12 +684,12 @@ void SciEngine::initGraphics() {
if (getSciVersion() >= SCI_VERSION_2) {
_gfxPalette32 = new GfxPalette32(_resMan, _gfxScreen);
_gfxPalette16 = _gfxPalette32;
- _gfxRemap32 = new GfxRemap32(_gfxScreen, _gfxPalette32);
+ _gfxRemap32 = new GfxRemap32(_gfxPalette32);
} else {
#endif
_gfxPalette16 = new GfxPalette(_resMan, _gfxScreen);
if (getGameId() == GID_QFG4DEMO)
- _gfxRemap16 = new GfxRemap(_gfxScreen, _gfxPalette16);
+ _gfxRemap16 = new GfxRemap(_gfxPalette16);
#ifdef ENABLE_SCI32
}
#endif
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index 2474db81d9..7df3d38163 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -206,8 +206,8 @@ enum SciVersion {
SCI_VERSION_1_LATE, // Dr. Brain 1, EcoQuest 1, Longbow, PQ3, SQ1, LSL5, KQ5 CD
SCI_VERSION_1_1, // Dr. Brain 2, EcoQuest 1 CD, EcoQuest 2, KQ6, QFG3, SQ4CD, XMAS 1992 and many more
SCI_VERSION_2, // GK1, PQ4 floppy, QFG4 floppy
- SCI_VERSION_2_1_EARLY, // GK2 demo, KQ7, LSL6 hires, PQ4, QFG4 floppy
- SCI_VERSION_2_1_MIDDLE, // GK2, KQ7, MUMG Deluxe, Phantasmagoria 1, PQ4CD, PQ:SWAT, QFG4CD, Shivers 1, SQ6, Torin
+ SCI_VERSION_2_1_EARLY, // GK2 demo, KQ7 1.4/1.51, LSL6 hires, PQ4CD, QFG4 floppy
+ SCI_VERSION_2_1_MIDDLE, // GK2, KQ7 2.00b, MUMG Deluxe, Phantasmagoria 1, PQ:SWAT, QFG4CD, Shivers 1, SQ6, Torin
SCI_VERSION_2_1_LATE, // demos of LSL7, Lighthouse, RAMA
SCI_VERSION_3 // LSL7, Lighthouse, RAMA, Phantasmagoria 2
};
diff --git a/engines/scumm/players/player_ad.cpp b/engines/scumm/players/player_ad.cpp
index 4d4be2c3c2..55bbeeef98 100644
--- a/engines/scumm/players/player_ad.cpp
+++ b/engines/scumm/players/player_ad.cpp
@@ -50,7 +50,7 @@ Player_AD::Player_AD(ScummEngine *scumm)
writeReg(0x01, 0x20);
_engineMusicTimer = 0;
- _soundPlaying = -1;
+ _musicResource = -1;
_curOffset = 0;
@@ -104,8 +104,8 @@ void Player_AD::startSound(int sound) {
stopMusic();
// Lock the new music resource
- _soundPlaying = sound;
- _vm->_res->lock(rtSound, _soundPlaying);
+ _musicResource = sound;
+ _vm->_res->lock(rtSound, _musicResource);
// Start the new music resource
_musicData = res;
@@ -150,7 +150,7 @@ void Player_AD::startSound(int sound) {
void Player_AD::stopSound(int sound) {
Common::StackLock lock(_mutex);
- if (sound == _soundPlaying) {
+ if (sound == _musicResource) {
stopMusic();
} else {
for (int i = 0; i < ARRAYSIZE(_sfx); ++i) {
@@ -178,7 +178,17 @@ int Player_AD::getMusicTimer() {
}
int Player_AD::getSoundStatus(int sound) const {
- return (sound == _soundPlaying);
+ if (sound == _musicResource) {
+ return true;
+ }
+
+ for (int i = 0; i < ARRAYSIZE(_sfx); ++i) {
+ if (_sfx[i].resource == sound) {
+ return true;
+ }
+ }
+
+ return false;
}
void Player_AD::saveLoadWithSerializer(Serializer *ser) {
@@ -193,7 +203,7 @@ void Player_AD::saveLoadWithSerializer(Serializer *ser) {
if (ser->getVersion() >= VER(96)) {
int32 res[4] = {
- _soundPlaying, _sfx[0].resource, _sfx[1].resource, _sfx[2].resource
+ _musicResource, _sfx[0].resource, _sfx[1].resource, _sfx[2].resource
};
// The first thing we save is a list of sound resources being played
@@ -461,13 +471,13 @@ void Player_AD::startMusic() {
}
void Player_AD::stopMusic() {
- if (_soundPlaying == -1) {
+ if (_musicResource == -1) {
return;
}
// Unlock the music resource if present
- _vm->_res->unlock(rtSound, _soundPlaying);
- _soundPlaying = -1;
+ _vm->_res->unlock(rtSound, _musicResource);
+ _musicResource = -1;
// Stop the music playback
_curOffset = 0;
@@ -510,7 +520,7 @@ void Player_AD::updateMusic() {
// important to note that we need to parse a command directly
// at the new position, i.e. there is no time value we need to
// parse.
- if (_soundPlaying == -1) {
+ if (_musicResource == -1) {
return;
} else {
continue;
diff --git a/engines/scumm/players/player_ad.h b/engines/scumm/players/player_ad.h
index 63fda3cc7c..9cd1a06261 100644
--- a/engines/scumm/players/player_ad.h
+++ b/engines/scumm/players/player_ad.h
@@ -68,7 +68,7 @@ private:
OPL::OPL *_opl2;
- int _soundPlaying;
+ int _musicResource;
int32 _engineMusicTimer;
struct SfxSlot;
diff --git a/engines/sword25/fmv/movieplayer.cpp b/engines/sword25/fmv/movieplayer.cpp
index eb0f0390dc..62a897a332 100644
--- a/engines/sword25/fmv/movieplayer.cpp
+++ b/engines/sword25/fmv/movieplayer.cpp
@@ -58,6 +58,8 @@ MoviePlayer::~MoviePlayer() {
}
bool MoviePlayer::loadMovie(const Common::String &filename, uint z) {
+ if (isMovieLoaded())
+ unloadMovie();
// Get the file and load it into the decoder
Common::SeekableReadStream *in = Kernel::getInstance()->getPackage()->getStream(filename);
_decoder.loadStream(in);
diff --git a/engines/tucker/resource.cpp b/engines/tucker/resource.cpp
index 9cba7b523d..d7b75e39c1 100644
--- a/engines/tucker/resource.cpp
+++ b/engines/tucker/resource.cpp
@@ -662,9 +662,11 @@ void TuckerEngine::loadData3() {
void TuckerEngine::loadData4() {
loadFile("data4.c", _loadTempBuf);
DataTokenizer t(_loadTempBuf, _fileLoadSize);
- t.findNextToken(kDataTokenDw);
- _gameDebug = t.getNextInteger() != 0;
- _displayGameHints = t.getNextInteger() != 0;
+ if ((_gameFlags & kGameFlagDemo) == 0) {
+ t.findNextToken(kDataTokenDw);
+ _gameDebug = t.getNextInteger() != 0;
+ _displayGameHints = t.getNextInteger() != 0;
+ }
_locationObjectsCount = 0;
if (t.findIndex(_locationNum)) {
while (t.findNextToken(kDataTokenDw)) {
diff --git a/engines/wage/debugger.cpp b/engines/wage/debugger.cpp
new file mode 100644
index 0000000000..7d01b0b85e
--- /dev/null
+++ b/engines/wage/debugger.cpp
@@ -0,0 +1,97 @@
+/* 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/file.h"
+#include "wage/wage.h"
+#include "wage/debugger.h"
+#include "wage/entities.h"
+#include "wage/script.h"
+#include "wage/world.h"
+
+namespace Wage {
+
+Debugger::Debugger(WageEngine *engine) : GUI::Debugger(), _engine(engine) {
+ registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
+ registerCmd("scenes", WRAP_METHOD(Debugger, Cmd_ListScenes));
+ registerCmd("script", WRAP_METHOD(Debugger, Cmd_Script));
+}
+
+Debugger::~Debugger() {
+}
+
+static int strToInt(const char *s) {
+ if (!*s)
+ // No string at all
+ return 0;
+ else if (toupper(s[strlen(s) - 1]) != 'H')
+ // Standard decimal string
+ return atoi(s);
+
+ // Hexadecimal string
+ uint tmp = 0;
+ int read = sscanf(s, "%xh", &tmp);
+
+ if (read < 1)
+ error("strToInt failed on string \"%s\"", s);
+ return (int)tmp;
+}
+
+bool Debugger::Cmd_ListScenes(int argc, const char **argv) {
+ int currentScene;
+
+ for (uint i = 1; i < _engine->_world->_orderedScenes.size(); i++) { // #0 is STORAGE@
+ if (_engine->_world->_player->_currentScene == _engine->_world->_orderedScenes[i])
+ currentScene = i;
+
+ debugPrintf("%d: %s\n", i, _engine->_world->_orderedScenes[i]->_name.c_str());
+ }
+
+ debugPrintf("\nCurrent scene is #%d: %s\n", currentScene, _engine->_world->_orderedScenes[currentScene]->_name.c_str());
+
+ return true;
+}
+
+bool Debugger::Cmd_Script(int argc, const char **argv) {
+ Script *script = _engine->_world->_player->_currentScene->_script;
+
+ if (argc >= 2) {
+ int scriptNum = strToInt(argv[1]);
+
+ if (scriptNum)
+ script = _engine->_world->_orderedScenes[scriptNum]->_script;
+ else
+ script = _engine->_world->_globalScript;
+ }
+
+ if (script == NULL) {
+ debugPrintf("There is no script for current scene\n");
+ return true;
+ }
+
+ for (uint i = 0; i < script->_scriptText.size(); i++) {
+ debugPrintf("%d [%04x]: %s\n", i, script->_scriptText[i]->offset, script->_scriptText[i]->line.c_str());
+ }
+
+ return true;
+}
+
+} // End of namespace Wage
diff --git a/engines/wage/debugger.h b/engines/wage/debugger.h
new file mode 100644
index 0000000000..90687760cb
--- /dev/null
+++ b/engines/wage/debugger.h
@@ -0,0 +1,47 @@
+/* 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 WAGE_DEBUGGER_H
+#define WAGE_DEBUGGER_H
+
+#include "common/scummsys.h"
+#include "gui/debugger.h"
+
+namespace Wage {
+
+class WageEngine;
+
+class Debugger : public GUI::Debugger {
+protected:
+ WageEngine *_engine;
+
+ bool Cmd_ListScenes(int argc, const char **argv);
+ bool Cmd_Script(int argc, const char **argv);
+
+public:
+ Debugger(WageEngine *engine);
+ virtual ~Debugger();
+};
+
+} // End of namespace Wage
+
+#endif
diff --git a/engines/wage/design.cpp b/engines/wage/design.cpp
index 220acae05a..907a1ec435 100644
--- a/engines/wage/design.cpp
+++ b/engines/wage/design.cpp
@@ -87,16 +87,14 @@ void Design::paint(Graphics::Surface *surface, Patterns &patterns, int x, int y)
bool needRender = false;
if (_surface == NULL) {
- //_boundsCalculationMode = true;
+ _boundsCalculationMode = true;
_bounds->debugPrint(4, "Internal bounds:");
- //_bounds->left = _bounds->top = 10000;
- //_bounds->right =_bounds->bottom = -10000;
- //render(patterns);
+ render(patterns);
_boundsCalculationMode = false;
if (_bounds->right == -10000) {
_bounds->left = _bounds->top = _bounds->right = _bounds->bottom = 0;
}
- //_bounds->debugPrint(4, "Calculated bounds:");
+ _bounds->debugPrint(4, "Calculated bounds:");
_surface = new Graphics::Surface;
_surface->create(_bounds->width(), _bounds->height(), Graphics::PixelFormat::createFormatCLUT8());
@@ -201,9 +199,7 @@ bool Design::isPointOpaque(int x, int y) {
}
void Design::adjustBounds(int16 x, int16 y) {
- _bounds->left = MIN(x, _bounds->left);
_bounds->right = MAX(x, _bounds->right);
- _bounds->top = MIN(y, _bounds->top);
_bounds->bottom = MAX(y, _bounds->bottom);
}
diff --git a/engines/wage/detection.cpp b/engines/wage/detection.cpp
index fcecb8d2b0..512d432e54 100644
--- a/engines/wage/detection.cpp
+++ b/engines/wage/detection.cpp
@@ -41,6 +41,7 @@ static const PlainGameDescriptor wageGames[] = {
{"afm", "Another Fine Mess"},
{"amot", "A Mess O' Trouble"},
{"cantitoe", "Camp Cantitoe"},
+ {"drakmythcastle", "Drakmyth Castle"},
{"raysmaze", "Ray's Maze"},
{"scepters", "Enchanted Scepters"},
{"twisted", "Twisted!"},
diff --git a/engines/wage/detection_tables.h b/engines/wage/detection_tables.h
index 782319a073..e164ea70cd 100644
--- a/engines/wage/detection_tables.h
+++ b/engines/wage/detection_tables.h
@@ -23,10 +23,12 @@
namespace Wage {
#define ADGF_DEFAULT (ADGF_DROPLANGUAGE|ADGF_DROPPLATFORM|ADGF_MACRESFORK)
-#define ADGF_GENERIC (ADGF_DROPLANGUAGE|ADGF_DROPPLATFORM|ADGF_USEEXTRAASTITLE|ADGF_AUTOGENTARGET|ADGF_MACRESFORK)
+#define ADGF_GENERIC (ADGF_DEFAULT|ADGF_USEEXTRAASTITLE|ADGF_AUTOGENTARGET)
+#define ADGF_DEMO (ADGF_GENERIC|ADGF_DEMO)
#define FANGAME(n,m,s) { "wage",n,AD_ENTRY1s(n,m,s),Common::EN_ANY,Common::kPlatformMacintosh,ADGF_GENERIC,GUIO0()}
#define FANGAMEN(n,f,m,s) { "wage",n,AD_ENTRY1s(f,m,s),Common::EN_ANY,Common::kPlatformMacintosh,ADGF_GENERIC,GUIO0()}
+#define FANGAMEND(n,f,m,s) { "wage",n,AD_ENTRY1s(f,m,s),Common::EN_ANY,Common::kPlatformMacintosh,ADGF_DEMO,GUIO0()}
#define BIGGAME(t,v,f,m,s) { t,v,AD_ENTRY1s(f,m,s),Common::EN_ANY,Common::kPlatformMacintosh,ADGF_DEFAULT,GUIO0()}
static const ADGameDescription gameDescriptions[] = {
@@ -37,11 +39,17 @@ static const ADGameDescription gameDescriptions[] = {
BIGGAME("cantitoe", "", "Camp Cantitoe", "913812a1ac7a6b0e48dadd1afa1c7763", 616985),
// Problems with letter rendering
FANGAME("Canal District", "a56aa3cd4a6e070e15ce1d5815c7be0a", 641470),
+ FANGAME("Carbon Copy", "913812a1ac7a6b0e48dadd1afa1c7763", 519445),
// Invalid rect in scene "FINALE"
FANGAME("Castle of Ert", "327610eb2298a9427a566288312df040", 198955),
FANGAME("Deep Angst", "b130b3c811cd89024dd5fdd2b71f70b8", 329550),
+ FANGAME("Deep Ennui", "913812a1ac7a6b0e48dadd1afa1c7763", 86075),
// Polygons with ignored byte 1
FANGAME("Double Trouble", "1652e36857a04c01dc560234c4818619", 542371),
+ BIGGAME("drakmythcastle", "disk I", "Drakmyth Castle disk I of II", "94a9c4f8b3dabd1846d76215a49bd221", 793784),
+ BIGGAME("drakmythcastle", "disk II", "Drakmyth Castle II", "cc978cc9a5256724702463cb5aaaffa0", 1685659),
+ // Crash at start in GUI rendering
+ FANGAME("Dune Eternity", "94a9c4f8b3dabd1846d76215a49bd221", 290201), // Original file name is "***DUNE ETERNITY*** "
FANGAMEN("Dungeon World II", "DungeonWorld2", "0154ea11d3cbb536c13b4ae9e6902d48", 230199),
FANGAME("Eidisi I", "595117cbed33e8de1ab3714b33880205", 172552),
// Problems(?) with text on the first screen
@@ -51,39 +59,61 @@ static const ADGameDescription gameDescriptions[] = {
// Crash in console rendering on the first scene
FANGAME("Fantasy Quest", "4b0e1a1fbaaa4930accd0f9f0e1519c7", 762754),
FANGAME("Find the Heart", "595117cbed33e8de1ab3714b33880205", 106235), // From Joshua's Worlds 1.0
+ // Problems with window overlay
+ FANGAMEN("Jumble", "LSJUMBLE", "e12ec4d76d48bdc86567c5e63750547e", 647339), // Original file name is "LSJUMBLE† "
FANGAME("Karth of the Jungle", "595117cbed33e8de1ab3714b33880205", 96711),
FANGAME("Karth of the Jungle", "595117cbed33e8de1ab3714b33880205", 96960), // Alternative version
FANGAME("Karth of the Jungle II", "c106835ab4436de054e03aec3ce904ce", 201053),
+ FANGAMEN("Little Pythagoras", "Little Pythagoras 1.1.1", "94a9c4f8b3dabd1846d76215a49bd221", 628821),
FANGAME("Lost Crystal", "8174c81ea1858d0079ae040dae2cefd3", 771072),
FANGAME("Magic Rings", "913812a1ac7a6b0e48dadd1afa1c7763", 109044),
+ // No way to click on the house
+ FANGAME("Messy House", "913812a1ac7a6b0e48dadd1afa1c7763", 177120),
FANGAME("Midnight Snack", "913812a1ac7a6b0e48dadd1afa1c7763", 67952),
+ FANGAME("Midnight Snack", "913812a1ac7a6b0e48dadd1afa1c7763", 67966), // Alt version
FANGAME("Minitorian", "913812a1ac7a6b0e48dadd1afa1c7763", 586464),
+ // No way to pass through the first screen
+ FANGAME("Nightcrawler Ned", "94a9c4f8b3dabd1846d76215a49bd221", 366542),
+ FANGAME("Pavilion", "4d991d7d1534d48d90598d86ea6d5d97", 231687),
+ // Polygons with byte 1
+ FANGAME("Periapt", "913812a1ac7a6b0e48dadd1afa1c7763", 406006),
FANGAME("Puzzle Piece Search", "595117cbed33e8de1ab3714b33880205", 247693), // From Joshua's Worlds 1.0
// Empty(?) first scene
FANGAME("Pyramid of No Return", "77a55a45f794b4d4a56703d3acce871e", 385145),
FANGAME("Queen Quest", "4b0e1a1fbaaa4930accd0f9f0e1519c7", 57026),
+ FANGAME("Quest for T-Rex", "913812a1ac7a6b0e48dadd1afa1c7763", 592584),
// Crash in console rendering on the initial scene
FANGAME("Quest for the Dark Sword", "b35dd0c078da9f35fc25a455f56bb129", 572576),
+ FANGAME("Radical Castle", "677bfee4afeca2f7152eb8b76c85ca8d", 355601),
FANGAME("Radical Castle 1.0", "677bfee4afeca2f7152eb8b76c85ca8d", 347278),
BIGGAME("raysmaze", "v1.5", "Ray's Maze1.5", "064b16d8c20724f8debbbdc3aafde538", 1408516),
BIGGAME("raysmaze", "v1.5/alt", "Ray's Maze1.5", "92cca777800c3d31a77b5ed7f6ee49ad", 1408516),
BIGGAME("scepters", "", "Scepters", "3311deef8bf82f0b4b1cfa15a3b3289d", 346595),
// ??? problems with dog bitmap?
FANGAMEN("Space Adventure", "SpaceAdventure", "f9f3f1c419f56955f7966355b34ea5c8", 155356),
+ FANGAMEN("Spear of Destiny", "SpearOfDestiny", "913812a1ac7a6b0e48dadd1afa1c7763", 333665), // Original file name "SpearOfDestiny†"
FANGAME("Star Trek", "44aaef4806578700429de5aaf95c266e", 53320),
- // Crash in bitmap drawing on the first scene
FANGAME("Strange Disappearance", "d81f2d03a1e863f04fb1e3a5495b720e", 772282),
+ // Code 0x03 in text
+ FANGAME("Swamp Witch", "913812a1ac7a6b0e48dadd1afa1c7763", 739781), // Original file name "Swamp Witch†"
+ FANGAME("Sweetspace Now!", "e12ec4d76d48bdc86567c5e63750547e", 123813), // Comes with Jumble
FANGAME("Time Bomb", "4b0e1a1fbaaa4930accd0f9f0e1519c7", 64564),
+ FANGAME("Time Bomb", "4b0e1a1fbaaa4930accd0f9f0e1519c7", 64578), // Alt version
+ FANGAMEND("The Ashland Revolution", "The Ashland Revolution Demo", "913812a1ac7a6b0e48dadd1afa1c7763", 145023), // Original file name "The Ashland Revolution Demo†"
+ FANGAMEN("The Hotel Caper", "The Hotel Caper V1.0", "595117cbed33e8de1ab3714b33880205", 231969),
// Invalid rect in scene "Access Tube 1"
FANGAMEN("The Phoenix v1.2", "The Phoenix", "4b0e1a1fbaaa4930accd0f9f0e1519c7", 431640),
FANGAME("The Sultan's Palace", "358799d446ee4fc12f793febd6c94b95", 456855),
// Admission for on 3rd screen is messed up
FANGAME("The Tower", "435f420b9dff895ae1ddf1338040c51d", 556539),
+ // Polygons with ignored byte 1 and 2 on second scene
+ FANGAME("The Village", "913812a1ac7a6b0e48dadd1afa1c7763", 314828),
// Doesn't go past first scene
BIGGAME("twisted", "", "Twisted! 1.6", "26207bdf0bb539464f136f0669af885f", 960954),
FANGAME("Wishing Well", "913812a1ac7a6b0e48dadd1afa1c7763", 103688),
FANGAME("Wizard's Warehouse", "913812a1ac7a6b0e48dadd1afa1c7763", 159748),
FANGAME("ZikTuria", "418e74ca71029a1e9db80d0eb30c0843", 52972),
+ FANGAME("Zoony", "539a64151426edc92da5eedadf39f23c", 154990), // original filename "Zoonyâ„¢"
AD_TABLE_END_MARKER
};
diff --git a/engines/wage/gui.cpp b/engines/wage/gui.cpp
index 387731cc18..9dd1a24b3c 100644
--- a/engines/wage/gui.cpp
+++ b/engines/wage/gui.cpp
@@ -294,10 +294,10 @@ void Gui::drawBox(Graphics::Surface *g, int x, int y, int w, int h) {
g->frameRect(r, kColorBlack);
}
-void Gui::fillRect(Graphics::Surface *g, int x, int y, int w, int h) {
+void Gui::fillRect(Graphics::Surface *g, int x, int y, int w, int h, int color) {
Common::Rect r(x, y, x + w, y + h);
- g->fillRect(r, kColorBlack);
+ g->fillRect(r, color);
}
#define ARROW_W 12
@@ -310,8 +310,8 @@ const int arrowPixels[ARROW_H][ARROW_W] = {
{0,1,1,1,1,1,1,1,1,1,1,0},
{1,1,1,1,1,1,1,1,1,1,1,1}};
-void Gui::paintBorder(Graphics::Surface *g, Common::Rect &r, WindowType windowType) {
- bool active = false, scrollable = false, closeable = false, closeBoxPressed = false, drawTitle = false;
+void Gui::paintBorder(Graphics::Surface *g, Common::Rect &r, WindowType windowType, int highlightedPart) {
+ bool active = false, scrollable = false, closeable = false, drawTitle = false;
const int size = kBorderWidth;
int x = r.left - size;
int y = r.top - size;
@@ -323,14 +323,12 @@ void Gui::paintBorder(Graphics::Surface *g, Common::Rect &r, WindowType windowTy
active = _sceneIsActive;
scrollable = false;
closeable = _sceneIsActive;
- closeBoxPressed = false;
drawTitle = true;
break;
case kWindowConsole:
active = !_sceneIsActive;
scrollable = true;
closeable = !_sceneIsActive;
- closeBoxPressed = false;
drawTitle = false;
break;
}
@@ -353,29 +351,43 @@ void Gui::paintBorder(Graphics::Surface *g, Common::Rect &r, WindowType windowTy
} else {
int x1 = x + width - 15;
int y1 = y + size + 1;
+ int color1 = kColorBlack;
+ int color2 = kColorWhite;
+ if (highlightedPart == kBorderScrollUp) {
+ SWAP(color1, color2);
+ fillRect(g, x + width - kBorderWidth + 2, y + size, size - 4, r.height() / 2);
+ }
for (int yy = 0; yy < ARROW_H; yy++) {
for (int xx = 0; xx < ARROW_W; xx++) {
if (arrowPixels[yy][xx] != 0) {
- g->hLine(x1 + xx, y1 + yy, x1 + xx, kColorBlack);
+ g->hLine(x1 + xx, y1 + yy, x1 + xx, color1);
} else {
- g->hLine(x1 + xx, y1 + yy, x1 + xx, kColorWhite);
+ g->hLine(x1 + xx, y1 + yy, x1 + xx, color2);
}
}
}
- fillRect(g, x + width - 13, y + size + ARROW_H, 8, height - 2 * size - 1 - ARROW_H * 2);
+ fillRect(g, x + width - 13, y + size + ARROW_H, 8, r.height() / 2 - ARROW_H, color1);
+
+ color1 = kColorBlack;
+ color2 = kColorWhite;
+ if (highlightedPart == kBorderScrollDown) {
+ SWAP(color1, color2);
+ fillRect(g, x + width - kBorderWidth + 2, y + size + r.height() / 2, size - 4, r.height() / 2);
+ }
+ fillRect(g, x + width - 13, y + size + r.height() / 2, 8, r.height() / 2 - ARROW_H, color1);
y1 += height - 2 * size - ARROW_H - 2;
for (int yy = 0; yy < ARROW_H; yy++) {
for (int xx = 0; xx < ARROW_W; xx++) {
if (arrowPixels[ARROW_H - yy - 1][xx] != 0) {
- g->hLine(x1 + xx, y1 + yy, x1 + xx, kColorBlack);
+ g->hLine(x1 + xx, y1 + yy, x1 + xx, color1);
} else {
- g->hLine(x1 + xx, y1 + yy, x1 + xx, kColorWhite);
+ g->hLine(x1 + xx, y1 + yy, x1 + xx, color2);
}
}
}
}
if (closeable) {
- if (closeBoxPressed) {
+ if (highlightedPart == kBorderCloseButton) {
fillRect(g, x + 6, y + 6, 6, 6);
} else {
drawBox(g, x + 5, y + 5, 7, 7);
@@ -499,6 +511,26 @@ void Gui::popCursor() {
CursorMan.popCursor();
}
+static int isInBorder(Common::Rect &rect, int x, int y) {
+ if (x >= rect.left - kBorderWidth && x < rect.left && y >= rect.top - kBorderWidth && y < rect.top)
+ return kBorderCloseButton;
+
+ if (x >= rect.right && x < rect.right + kBorderWidth) {
+ if (y < rect.top - kBorderWidth)
+ return kBorderNone;
+
+ if (y >= rect.bottom + kBorderWidth)
+ return kBorderNone;
+
+ if (y >= rect.top + rect.height() / 2)
+ return kBorderScrollDown;
+
+ return kBorderScrollUp;
+ }
+
+ return kBorderNone;
+}
+
Designed *Gui::mouseUp(int x, int y) {
if (_menu->_menuActivated) {
if (_menu->mouseRelease(x, y)) {
@@ -532,6 +564,8 @@ Designed *Gui::mouseUp(int x, int y) {
}
}
+ int borderClick;
+
if (_sceneArea.contains(x, y)) {
if (!_sceneIsActive) {
_sceneIsActive = true;
@@ -552,16 +586,40 @@ Designed *Gui::mouseUp(int x, int y) {
_sceneIsActive = false;
_bordersDirty = true;
}
+ } else if ((borderClick = isInBorder(_consoleTextArea, x, y)) != kBorderNone) {
+ _bordersDirty = true;
+ int _oldScrollPos = _scrollPos;
+
+ switch (borderClick) {
+ case kBorderScrollUp:
+ _scrollPos = MAX<int>(0, _scrollPos - _consoleLineHeight);
+ undrawCursor();
+ _cursorY -= (_scrollPos - _oldScrollPos);
+ _consoleDirty = true;
+ _consoleFullRedraw = true;
+ break;
+ case kBorderScrollDown:
+ _scrollPos = MIN<int>((_lines.size() - 2) * _consoleLineHeight, _scrollPos + _consoleLineHeight);
+ undrawCursor();
+ _cursorY -= (_scrollPos - _oldScrollPos);
+ _consoleDirty = true;
+ _consoleFullRedraw = true;
+ break;
+ }
}
return NULL;
}
void Gui::mouseDown(int x, int y) {
+ int borderClick;
+
if (_menu->mouseClick(x, y)) {
_menuDirty = true;
} else if (_consoleTextArea.contains(x, y)) {
startMarking(x, y);
+ } else if ((borderClick = isInBorder(_consoleTextArea, x, y)) != kBorderNone) {
+ paintBorder(&_screen, _consoleTextArea, kWindowConsole, borderClick);
}
}
diff --git a/engines/wage/gui.h b/engines/wage/gui.h
index 61f8c31a07..73814d39b4 100644
--- a/engines/wage/gui.h
+++ b/engines/wage/gui.h
@@ -84,6 +84,13 @@ enum {
kPatternCheckers2 = 4
};
+enum {
+ kBorderNone = 0,
+ kBorderScrollUp,
+ kBorderScrollDown,
+ kBorderCloseButton
+};
+
class Gui {
public:
Gui(WageEngine *engine);
@@ -116,10 +123,10 @@ public:
private:
void undrawCursor();
void drawDesktop();
- void paintBorder(Graphics::Surface *g, Common::Rect &r, WindowType windowType);
+ void paintBorder(Graphics::Surface *g, Common::Rect &r, WindowType windowType, int highlightedPart = kBorderNone);
void renderConsole(Graphics::Surface *g, Common::Rect &r);
void drawBox(Graphics::Surface *g, int x, int y, int w, int h);
- void fillRect(Graphics::Surface *g, int x, int y, int w, int h);
+ void fillRect(Graphics::Surface *g, int x, int y, int w, int h, int color = kColorBlack);
void loadFonts();
void flowText(Common::String &str);
const Graphics::Font *getConsoleFont();
diff --git a/engines/wage/menu.cpp b/engines/wage/menu.cpp
index 48f16421b5..12ef8c2219 100644
--- a/engines/wage/menu.cpp
+++ b/engines/wage/menu.cpp
@@ -206,10 +206,10 @@ void Menu::createCommandsMenu(MenuItem *menu) {
char shortcut = 0;
const char *shortPtr = strrchr(item.c_str(), '/');
if (shortPtr != NULL) {
- if (strlen(shortPtr) == 2) {
+ if (strlen(shortPtr) >= 2) {
shortcut = shortPtr[1];
- item.deleteLastChar();
- item.deleteLastChar();
+ item.deleteChar(shortPtr - item.c_str());
+ item.deleteChar(shortPtr - item.c_str());
} else {
error("Unexpected shortcut: '%s', item '%s' in menu '%s'", shortPtr, item.c_str(), string.c_str());
}
diff --git a/engines/wage/module.mk b/engines/wage/module.mk
index 548e440c28..21316bbf83 100644
--- a/engines/wage/module.mk
+++ b/engines/wage/module.mk
@@ -2,6 +2,7 @@ MODULE := engines/wage
MODULE_OBJS := \
combat.o \
+ debugger.o \
design.o \
detection.o \
dialog.o \
diff --git a/engines/wage/script.cpp b/engines/wage/script.cpp
index bd99fa1d86..294c08ed82 100644
--- a/engines/wage/script.cpp
+++ b/engines/wage/script.cpp
@@ -1124,7 +1124,7 @@ void Script::convertToText() {
if (c < 0x80) {
if (c < 0x20)
- error("Unknown code 0x%02x at %d", c, _data->pos());
+ error("convertToText: Unknown code 0x%02x at %d", c, _data->pos());
do {
scr->line += c;
diff --git a/engines/wage/script.h b/engines/wage/script.h
index 325733add7..de9476228c 100644
--- a/engines/wage/script.h
+++ b/engines/wage/script.h
@@ -150,8 +150,10 @@ private:
void assign(byte operandType, int uservar, uint16 value);
- Common::Array<ScriptText *> _scriptText;
void convertToText();
+
+public:
+ Common::Array<ScriptText *> _scriptText;
};
} // End of namespace Wage
diff --git a/engines/wage/wage.cpp b/engines/wage/wage.cpp
index b708cff134..e0299c8da2 100644
--- a/engines/wage/wage.cpp
+++ b/engines/wage/wage.cpp
@@ -102,12 +102,14 @@ WageEngine::~WageEngine() {
}
Common::Error WageEngine::run() {
+ debug("WageEngine::init");
+
initGraphics(512, 342, true);
// Create debugger console. It requires GFX to be initialized
_console = new Console(this);
- debug("WageEngine::init");
+ _debugger = new Debugger(this);
// Your main event loop should be (invoked from) here.
_resManager = new Common::MacResManager();
@@ -130,6 +132,8 @@ Common::Error WageEngine::run() {
_shouldQuit = false;
while (!_shouldQuit) {
+ _debugger->onFrame();
+
processEvents();
_gui->draw();
@@ -180,6 +184,11 @@ void WageEngine::processEvents() {
break;
default:
+ if (event.kbd.ascii == '~') {
+ _debugger->attach();
+ break;
+ }
+
if (event.kbd.flags & (Common::KBD_ALT | Common::KBD_CTRL | Common::KBD_META)) {
if (event.kbd.ascii >= 0x20 && event.kbd.ascii <= 0x7f) {
_gui->processMenuShortCut(event.kbd.flags, event.kbd.ascii);
diff --git a/engines/wage/wage.h b/engines/wage/wage.h
index 6905fdc530..8ca306aea3 100644
--- a/engines/wage/wage.h
+++ b/engines/wage/wage.h
@@ -50,12 +50,13 @@
#include "engines/engine.h"
#include "common/debug.h"
-#include "gui/debugger.h"
#include "common/endian.h"
#include "common/rect.h"
#include "common/macresman.h"
#include "common/random.h"
+#include "wage/debugger.h"
+
struct ADGameDescription;
namespace Wage {
@@ -181,6 +182,8 @@ public:
public:
Common::RandomSource *_rnd;
+ Debugger *_debugger;
+
Gui *_gui;
World *_world;
@@ -212,6 +215,8 @@ public:
void redrawScene();
void saveGame();
+ virtual GUI::Debugger *getDebugger() { return _debugger; }
+
private:
Console *_console;
diff --git a/gui/themes/translations.dat b/gui/themes/translations.dat
index 2378bc4e13..b0da793cdf 100644
--- a/gui/themes/translations.dat
+++ b/gui/themes/translations.dat
Binary files differ
diff --git a/po/zh-Latn_CN.po b/po/zh-Latn_CN.po
new file mode 100644
index 0000000000..12105429a7
--- /dev/null
+++ b/po/zh-Latn_CN.po
@@ -0,0 +1,3730 @@
+# LANGUAGE translation for ScummVM.
+# Copyright (C) YEAR ScummVM Team
+# This file is distributed under the same license as the ScummVM package.
+# Chenbo Li <lichenbo1949@gmail.com>, 2016.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ScummVM 1.9.0git\n"
+"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
+"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"PO-Revision-Date: 2016-03-15 04:09-0700\n"
+"Last-Translator: Chenbo Li <lichenbo1949@gmail.com>\n"
+"Language-Team: Chenbo Li <lichenbo1949@gmail.com>\n"
+"Language: Chinese Pinyin (Mandarin)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.8.7\n"
+
+#: gui/about.cpp:94
+#, c-format
+msgid "(built on %s)"
+msgstr "(Bianyiyu %s)"
+
+#: gui/about.cpp:101
+msgid "Features compiled in:"
+msgstr "Gongneng BianyiYu"
+
+#: gui/about.cpp:110
+msgid "Available engines:"
+msgstr "KeyongDeYinQing"
+
+#: gui/browser.cpp:68 gui/browser_osx.mm:104
+msgid "Show hidden files"
+msgstr "Xianshi Yincang Wenjian"
+
+#: gui/browser.cpp:68
+msgid "Show files marked with the hidden attribute"
+msgstr "Xianshi Suoyou Yincang Shuxing Wenjian"
+
+#: gui/browser.cpp:72
+msgid "Go up"
+msgstr "ShangYiJi"
+
+#: gui/browser.cpp:72 gui/browser.cpp:74
+msgid "Go to previous directory level"
+msgstr "Fanhui Zhiqian Mulu"
+
+#: gui/browser.cpp:74
+msgctxt "lowres"
+msgid "Go up"
+msgstr "ShangYiJi"
+
+#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
+#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
+#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
+#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: backends/events/default/default-events.cpp:196
+#: backends/events/default/default-events.cpp:218
+#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
+#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/sword1/control.cpp:865
+msgid "Cancel"
+msgstr "Quxiao"
+
+#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
+msgid "Choose"
+msgstr "Xuanze"
+
+#: gui/editrecorddialog.cpp:58
+msgid "Author:"
+msgstr "Zuozhe:"
+
+#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
+msgid "Name:"
+msgstr "Xingming:"
+
+#: gui/editrecorddialog.cpp:60
+msgid "Notes:"
+msgstr "Beizhu:"
+
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
+msgid "Ok"
+msgstr "Queding"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "Xuanze YaoJiazai de Wenjian"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "Shuru Baocun de Wenjianming"
+
+#: gui/filebrowser-dialog.cpp:132
+msgid "Do you really want to overwrite the file?"
+msgstr "Nin Shifou Queding Fugai Ciwenjian"
+
+#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
+#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+#: backends/platform/wince/CEActionsPocket.cpp:326
+#: backends/platform/wince/CEActionsSmartphone.cpp:287
+#: backends/platform/wince/CELauncherDialog.cpp:83
+#: engines/kyra/saveload_eob.cpp:557 engines/kyra/saveload_eob.cpp:590
+msgid "Yes"
+msgstr "Shi"
+
+#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
+#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+#: backends/platform/wince/CEActionsPocket.cpp:326
+#: backends/platform/wince/CEActionsSmartphone.cpp:287
+#: backends/platform/wince/CELauncherDialog.cpp:83
+#: engines/kyra/saveload_eob.cpp:557 engines/kyra/saveload_eob.cpp:590
+msgid "No"
+msgstr "Fou"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Hunxiang"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Jihuo"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Fangjian:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "Shiqi:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Kuandu:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Jibie:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "Hechang:"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Sudu:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Shendu:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Leixing:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Zhengxian"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Sanjiaoxing"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+msgid "Misc"
+msgstr "Zaxiang"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Chazhi:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Wu (Zuikuai)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Xianxing"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "DiSiXu"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "DiQiXu"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Chongzhi"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset all FluidSynth settings to their default values."
+msgstr "Chongzhi Suoyou de FluidSynth Shezhi"
+
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
+#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
+#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
+#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: backends/platform/wince/CELauncherDialog.cpp:54
+#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
+#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/scumm/players/player_v3m.cpp:130
+#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
+#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
+#: engines/sword1/animation.cpp:545 engines/sword1/animation.cpp:561
+#: engines/sword1/animation.cpp:569 engines/sword1/control.cpp:865
+#: engines/sword1/logic.cpp:1633 engines/sword2/animation.cpp:425
+#: engines/sword2/animation.cpp:445 engines/sword2/animation.cpp:461
+#: engines/sword2/animation.cpp:471
+msgid "OK"
+msgstr "Queding"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
+msgstr "Ni Shifou Yao Chongzhi Suoyou de FluidSynth Shezhi?"
+
+#: gui/gui-manager.cpp:119 backends/keymapper/remap-dialog.cpp:53
+#: engines/scumm/help.cpp:126 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:192
+#: engines/scumm/help.cpp:210
+msgid "Close"
+msgstr "Guanbi"
+
+#: gui/gui-manager.cpp:122
+msgid "Mouse click"
+msgstr "Shubiao Danji"
+
+#: gui/gui-manager.cpp:126 base/main.cpp:322
+msgid "Display keyboard"
+msgstr "Xianshi Jianpan"
+
+#: gui/gui-manager.cpp:130 base/main.cpp:326
+msgid "Remap keys"
+msgstr "Yingshe Jianwei"
+
+#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+msgid "Toggle fullscreen"
+msgstr "Quanping Qiehuan"
+
+#: gui/KeysDialog.cpp:41
+msgid "Map"
+msgstr "Yingshe"
+
+#: gui/KeysDialog.cpp:49
+msgid "Select an action and click 'Map'"
+msgstr "Xuanze Yige Xingwei bing Danji ‘Yingshe’"
+
+#: gui/KeysDialog.cpp:80 gui/KeysDialog.cpp:102 gui/KeysDialog.cpp:141
+#, c-format
+msgid "Associated key : %s"
+msgstr "Guanlian Anjian : %s"
+
+#: gui/KeysDialog.cpp:82 gui/KeysDialog.cpp:104 gui/KeysDialog.cpp:143
+#, c-format
+msgid "Associated key : none"
+msgstr "Guanlian Anjian : Wu"
+
+#: gui/KeysDialog.cpp:90
+msgid "Please select an action"
+msgstr "Qing Xuanze Xingwei"
+
+#: gui/KeysDialog.cpp:106
+msgid "Press the key to associate"
+msgstr "Anxia Anjian lai Guanlian"
+
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Xuanze yao Yingshe de Xingwei"
+
+#: gui/launcher.cpp:193
+msgid "Game"
+msgstr "Youxi"
+
+#: gui/launcher.cpp:197
+msgid "ID:"
+msgstr "ID:"
+
+#: gui/launcher.cpp:197 gui/launcher.cpp:199 gui/launcher.cpp:200
+msgid ""
+"Short game identifier used for referring to saved games and running the game "
+"from the command line"
+msgstr ""
+"Yige Jianduan de Biaoshifu lai Baocun Youxi huo Cong Minglinghang zhong "
+"Yunxing"
+
+#: gui/launcher.cpp:199
+msgctxt "lowres"
+msgid "ID:"
+msgstr "ID:"
+
+#: gui/launcher.cpp:204 gui/launcher.cpp:206 gui/launcher.cpp:207
+msgid "Full title of the game"
+msgstr "Youxi Quanming"
+
+#: gui/launcher.cpp:206
+msgctxt "lowres"
+msgid "Name:"
+msgstr "Mingcheng:"
+
+#: gui/launcher.cpp:210
+msgid "Language:"
+msgstr "Yuyan:"
+
+#: gui/launcher.cpp:210 gui/launcher.cpp:211
+msgid ""
+"Language of the game. This will not turn your Spanish game version into "
+"English"
+msgstr ""
+"Youxi de Yuyan. CiXiang buhui jiang Yige XibanyaYu Banben Zhuancheng Yingwen"
+
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
+#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: audio/null.cpp:41
+msgid "<default>"
+msgstr "<Moren>"
+
+#: gui/launcher.cpp:222
+msgid "Platform:"
+msgstr "Pingtai:"
+
+#: gui/launcher.cpp:222 gui/launcher.cpp:224 gui/launcher.cpp:225
+msgid "Platform the game was originally designed for"
+msgstr "Youxi Chushi Yunxing de Pingtai:"
+
+#: gui/launcher.cpp:224
+msgctxt "lowres"
+msgid "Platform:"
+msgstr "Pingtai:"
+
+#: gui/launcher.cpp:237
+msgid "Engine"
+msgstr "Yinqing"
+
+#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+msgid "Graphics"
+msgstr "Tuxiang"
+
+#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+msgid "GFX"
+msgstr "GFX"
+
+#: gui/launcher.cpp:248
+msgid "Override global graphic settings"
+msgstr "Fugai Quanju Tuxiang Shezhi"
+
+#: gui/launcher.cpp:250
+msgctxt "lowres"
+msgid "Override global graphic settings"
+msgstr "Fugai Quanju Tuxiang Shezhi"
+
+#: gui/launcher.cpp:257 gui/options.cpp:1094
+msgid "Audio"
+msgstr "Yinpin"
+
+#: gui/launcher.cpp:260
+msgid "Override global audio settings"
+msgstr "Fugai Quanju Yinpin Shezhi"
+
+#: gui/launcher.cpp:262
+msgctxt "lowres"
+msgid "Override global audio settings"
+msgstr "Fugai QUanju Yinpin Shezhi"
+
+#: gui/launcher.cpp:271 gui/options.cpp:1099
+msgid "Volume"
+msgstr "Yinliang"
+
+#: gui/launcher.cpp:273 gui/options.cpp:1101
+msgctxt "lowres"
+msgid "Volume"
+msgstr "YinLiang"
+
+#: gui/launcher.cpp:276
+msgid "Override global volume settings"
+msgstr "Fugai Quanju YinLiang Shezhi"
+
+#: gui/launcher.cpp:278
+msgctxt "lowres"
+msgid "Override global volume settings"
+msgstr "Fugai Quanju YinLiang Shezhi"
+
+#: gui/launcher.cpp:286 gui/options.cpp:1109
+msgid "MIDI"
+msgstr "MIDI"
+
+#: gui/launcher.cpp:289
+msgid "Override global MIDI settings"
+msgstr "Fugai Quanju MIDI Shezhi"
+
+#: gui/launcher.cpp:291
+msgctxt "lowres"
+msgid "Override global MIDI settings"
+msgstr "Fugai Quanju MIDI Shezhi"
+
+#: gui/launcher.cpp:300 gui/options.cpp:1115
+msgid "MT-32"
+msgstr "MT-32"
+
+#: gui/launcher.cpp:303
+msgid "Override global MT-32 settings"
+msgstr "Fugai Quanju MT-32 Shezhi"
+
+#: gui/launcher.cpp:305
+msgctxt "lowres"
+msgid "Override global MT-32 settings"
+msgstr "Fugai Quanju MT-32 Shezhi"
+
+#: gui/launcher.cpp:314 gui/options.cpp:1122
+msgid "Paths"
+msgstr "Lujing"
+
+#: gui/launcher.cpp:316 gui/options.cpp:1124
+msgctxt "lowres"
+msgid "Paths"
+msgstr "Lujing"
+
+#: gui/launcher.cpp:323
+msgid "Game Path:"
+msgstr "Youxi Lujing:"
+
+#: gui/launcher.cpp:325
+msgctxt "lowres"
+msgid "Game Path:"
+msgstr "Youxi Lujing:"
+
+#: gui/launcher.cpp:330 gui/options.cpp:1148
+msgid "Extra Path:"
+msgstr "Qita Lujing:"
+
+#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+msgid "Specifies path to additional data used by the game"
+msgstr "Zhiding Youxi Suoyong de Shuju de Cunfang Lujing"
+
+#: gui/launcher.cpp:332 gui/options.cpp:1150
+msgctxt "lowres"
+msgid "Extra Path:"
+msgstr "Qita Lujing:"
+
+#: gui/launcher.cpp:339 gui/options.cpp:1132
+msgid "Save Path:"
+msgstr "Baocun Lujing:"
+
+#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
+#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+msgid "Specifies where your saved games are put"
+msgstr "Zhiding Nin Jiang Youxi Baocun Zai le Nali"
+
+#: gui/launcher.cpp:341 gui/options.cpp:1134
+msgctxt "lowres"
+msgid "Save Path:"
+msgstr "Baocun Lujing:"
+
+#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
+#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
+#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
+#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
+#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
+#: gui/options.cpp:1440
+msgctxt "path"
+msgid "None"
+msgstr "Wu"
+
+#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
+#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: backends/platform/wii/options.cpp:56
+msgid "Default"
+msgstr "Moren"
+
+#: gui/launcher.cpp:510 gui/options.cpp:1434
+msgid "Select SoundFont"
+msgstr "Xuanze SoundFont"
+
+#: gui/launcher.cpp:529 gui/launcher.cpp:682
+msgid "Select directory with game data"
+msgstr "Xuanze Youxi Shuju Mulu"
+
+#: gui/launcher.cpp:547
+msgid "Select additional game directory"
+msgstr "Xuanze Qita Youxi Mulu"
+
+#: gui/launcher.cpp:559 gui/options.cpp:1377
+msgid "Select directory for saved games"
+msgstr "Xuanze Youxi Baocun Mulu"
+
+#: gui/launcher.cpp:586
+msgid "This game ID is already taken. Please choose another one."
+msgstr "Ci Youxi ID Yi Bei Zhanyong. Qing Xuanze Qita Mingcheng"
+
+#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+msgid "~Q~uit"
+msgstr "~Q~Tuichu"
+
+#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+msgid "Quit ScummVM"
+msgstr "Tuichu ScummVM"
+
+#: gui/launcher.cpp:627
+msgid "A~b~out..."
+msgstr "~b~Guanyu"
+
+#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+msgid "About ScummVM"
+msgstr "Guanyu ScummVM"
+
+#: gui/launcher.cpp:628
+msgid "~O~ptions..."
+msgstr "~O~Xuanxiang"
+
+#: gui/launcher.cpp:628
+msgid "Change global ScummVM options"
+msgstr "Genggai ScummVM Quanju Shezhi"
+
+#: gui/launcher.cpp:630
+msgid "~S~tart"
+msgstr "~S~Kaishi"
+
+#: gui/launcher.cpp:630
+msgid "Start selected game"
+msgstr "Kaishi Xuanze de Youxi"
+
+#: gui/launcher.cpp:633
+msgid "~L~oad..."
+msgstr "~L~Jiazai"
+
+#: gui/launcher.cpp:633
+msgid "Load saved game for selected game"
+msgstr "Jiazai Xuanze Baocun de Youxi"
+
+#: gui/launcher.cpp:638
+msgid "~A~dd Game..."
+msgstr "~A~Tianjia Youxi ..."
+
+#: gui/launcher.cpp:638 gui/launcher.cpp:645
+msgid "Hold Shift for Mass Add"
+msgstr "Anzhu Shift Lai Piliang Tianjia"
+
+#: gui/launcher.cpp:640
+msgid "~E~dit Game..."
+msgstr "~E~Bianji Youxi ..."
+
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
+msgid "Change game options"
+msgstr "Genggai Youxi Xuanxiang"
+
+#: gui/launcher.cpp:642
+msgid "~R~emove Game"
+msgstr "~R~Yichu Youxi"
+
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
+msgid "Remove game from the list. The game data files stay intact"
+msgstr "Cong Liebiao zhong YIchu Youxi. Baoliu Youxi Shuju Wenjian"
+
+#: gui/launcher.cpp:645
+msgctxt "lowres"
+msgid "~A~dd Game..."
+msgstr "~A~Tianjia Youxi ..."
+
+#: gui/launcher.cpp:647
+msgctxt "lowres"
+msgid "~E~dit Game..."
+msgstr "~E~Bianji Youxi ..."
+
+#: gui/launcher.cpp:649
+msgctxt "lowres"
+msgid "~R~emove Game"
+msgstr "~R~Yichu Youxi ..."
+
+#: gui/launcher.cpp:657
+msgid "Search in game list"
+msgstr "Zai Youxi Liebiao zhong Sousuo"
+
+#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+msgid "Search:"
+msgstr "Sousuo:"
+
+#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
+#: engines/tsage/scenes.cpp:600
+msgid "Load game:"
+msgstr "Jiazai Youxi:"
+
+#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: backends/platform/wince/CEActionsPocket.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:231
+#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
+#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
+#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+msgid "Load"
+msgstr "Jiazai"
+
+#: gui/launcher.cpp:794
+msgid ""
+"Do you really want to run the mass game detector? This could potentially add "
+"a huge number of games."
+msgstr ""
+"Nin Queding yao Yunxing Youxi Piliang Jiance Ma? Zhe You Keneng Hui Zengjia "
+"Daliang Youxi."
+
+#: gui/launcher.cpp:843
+msgid "ScummVM couldn't open the specified directory!"
+msgstr "ScummVM Wufa Dakai Zhiding Mulu!"
+
+#: gui/launcher.cpp:855
+msgid "ScummVM could not find any game in the specified directory!"
+msgstr "ScummVM zai Zhiding Mulu Zhong Wufa Zhaodao Renhe Youxi!"
+
+#: gui/launcher.cpp:869
+msgid "Pick the game:"
+msgstr "Xuanze Youxi:"
+
+#: gui/launcher.cpp:943
+msgid "Do you really want to remove this game configuration?"
+msgstr "Nin Zhende Xiangyao Yichu Zhege Youxi Peizhi?"
+
+#: gui/launcher.cpp:1001
+msgid "Do you want to load saved game?"
+msgstr "Nin Yao Zairu Baocun de Youxi ma?"
+
+#: gui/launcher.cpp:1050
+msgid "This game does not support loading games from the launcher."
+msgstr "Ci Youxi Bu Zhichi cong Jiazaiqi Zhong Jiazai Youxi."
+
+#: gui/launcher.cpp:1054
+msgid "ScummVM could not find any engine capable of running the selected game!"
+msgstr "ScummVM Wufa Zhaodao Keyi Yunxing Ci Youxi de Yinqing!"
+
+#: gui/launcher.cpp:1161
+msgid "Mass Add..."
+msgstr "PiLiang Zengjia ..."
+
+#: gui/launcher.cpp:1163
+msgid "Record..."
+msgstr "Luxiang ..."
+
+#: gui/massadd.cpp:79 gui/massadd.cpp:82
+msgid "... progress ..."
+msgstr "... Jindu ..."
+
+#: gui/massadd.cpp:259
+msgid "Scan complete!"
+msgstr "Saomiao Wancheng!"
+
+#: gui/massadd.cpp:262
+#, c-format
+msgid "Discovered %d new games, ignored %d previously added games."
+msgstr "Faxian le %d ge Xinyouxi, Hulue %d ge YiTianjia de Youxi"
+
+#: gui/massadd.cpp:266
+#, c-format
+msgid "Scanned %d directories ..."
+msgstr "YiSaomiao %d ge Mulu ..."
+
+#: gui/massadd.cpp:269
+#, c-format
+msgid "Discovered %d new games, ignored %d previously added games ..."
+msgstr "Faxian le %d ge Xinyouxi, Hulue %d ge YiTianjia de Youxi ..."
+
+#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
+msgid "Stop"
+msgstr "Tingzhi"
+
+#: gui/onscreendialog.cpp:106
+msgid "Edit record description"
+msgstr "Bianji Luxiang Shuoming"
+
+#: gui/onscreendialog.cpp:108
+msgid "Switch to Game"
+msgstr "Qiehuan zhi Youxi"
+
+#: gui/onscreendialog.cpp:110
+msgid "Fast replay"
+msgstr "Kuaisu Huitui"
+
+#: gui/options.cpp:85
+msgid "Never"
+msgstr "Yongbu"
+
+#: gui/options.cpp:85
+msgid "every 5 mins"
+msgstr "Mei 5 Fenzhong"
+
+#: gui/options.cpp:85
+msgid "every 10 mins"
+msgstr "Mei 10 Fenzhong"
+
+#: gui/options.cpp:85
+msgid "every 15 mins"
+msgstr "Mei 15 Fenzhong"
+
+#: gui/options.cpp:85
+msgid "every 30 mins"
+msgstr "Mei 30 Fenzhong"
+
+#: gui/options.cpp:87
+msgid "8 kHz"
+msgstr "8 kHz"
+
+#: gui/options.cpp:87
+msgid "11 kHz"
+msgstr "11 kHz"
+
+#: gui/options.cpp:87
+msgid "22 kHz"
+msgstr "22 kHz"
+
+#: gui/options.cpp:87
+msgid "44 kHz"
+msgstr "44 kHz"
+
+#: gui/options.cpp:87
+msgid "48 kHz"
+msgstr "48 kHz"
+
+#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
+#: gui/options.cpp:649 gui/options.cpp:857
+msgctxt "soundfont"
+msgid "None"
+msgstr "Wu"
+
+#: gui/options.cpp:389
+msgid "Failed to apply some of the graphic options changes:"
+msgstr "Tuxing Xuanxiang Genggai Shibai:"
+
+#: gui/options.cpp:401
+msgid "the video mode could not be changed."
+msgstr "Shipin Moshi Wufa Genggai."
+
+#: gui/options.cpp:407
+msgid "the fullscreen setting could not be changed"
+msgstr "Quanping Shezhi Wufa Genggai"
+
+#: gui/options.cpp:413
+msgid "the aspect ratio setting could not be changed"
+msgstr "Bili Xuanxiang Wufa Genggai"
+
+#: gui/options.cpp:732
+msgid "Graphics mode:"
+msgstr "Tuxing Moshi:"
+
+#: gui/options.cpp:746
+msgid "Render mode:"
+msgstr "Xuanran Moshi:"
+
+#: gui/options.cpp:746 gui/options.cpp:747
+msgid "Special dithering modes supported by some games"
+msgstr "Youxi Zhichi Teshu de Doudong Moshi"
+
+#: gui/options.cpp:758
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Fullscreen mode"
+msgstr "Quanping Moshi"
+
+#: gui/options.cpp:761
+msgid "Aspect ratio correction"
+msgstr "Bili Jiaozheng"
+
+#: gui/options.cpp:761
+msgid "Correct aspect ratio for 320x200 games"
+msgstr "320x200 Youxi Bili Jiaozheng"
+
+#: gui/options.cpp:769
+msgid "Preferred Device:"
+msgstr "Youxian Shebei:"
+
+#: gui/options.cpp:769
+msgid "Music Device:"
+msgstr "Yinyue Shebei:"
+
+#: gui/options.cpp:769 gui/options.cpp:771
+msgid "Specifies preferred sound device or sound card emulator"
+msgstr "Zhiding Youxian Shengyin Shebei huo Shengka Moniqi"
+
+#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+msgid "Specifies output sound device or sound card emulator"
+msgstr "Zhiding Shuchu Shengyin Shebei huo Shengka Moniqi"
+
+#: gui/options.cpp:771
+msgctxt "lowres"
+msgid "Preferred Dev.:"
+msgstr "Youxian Shebei:"
+
+#: gui/options.cpp:771
+msgctxt "lowres"
+msgid "Music Device:"
+msgstr "Yinyue Shebei:"
+
+#: gui/options.cpp:798
+msgid "AdLib emulator:"
+msgstr "AdLib Moniqi:"
+
+#: gui/options.cpp:798 gui/options.cpp:799
+msgid "AdLib is used for music in many games"
+msgstr "AdLib bei Henduo Youxi Yonglai Bofang Yinyue"
+
+#: gui/options.cpp:809
+msgid "Output rate:"
+msgstr "Shuchu Malv:"
+
+#: gui/options.cpp:809 gui/options.cpp:810
+msgid ""
+"Higher value specifies better sound quality but may be not supported by your "
+"soundcard"
+msgstr ""
+"Genggao de Shuxing Hui Tisheng Yinyue Zhiliang dan Youkeneng Nin de Shengka "
+"Buzhichi"
+
+#: gui/options.cpp:820
+msgid "GM Device:"
+msgstr "GM Shebei:"
+
+#: gui/options.cpp:820
+msgid "Specifies default sound device for General MIDI output"
+msgstr "Zhiding Tongyong MIDI Shuchu Moren Shengyin Shebei"
+
+#: gui/options.cpp:831
+msgid "Don't use General MIDI music"
+msgstr "Buyao Shiyong Tongyong MIDI Yinyue"
+
+#: gui/options.cpp:842 gui/options.cpp:908
+msgid "Use first available device"
+msgstr "Shiyong Diyige keyong de Shebei"
+
+#: gui/options.cpp:854
+msgid "SoundFont:"
+msgstr "SoundFont:"
+
+#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
+msgstr "Yixie Shengka Zhichi SoundFont, Biru FluidSynth He Timidity"
+
+#: gui/options.cpp:856
+msgctxt "lowres"
+msgid "SoundFont:"
+msgstr "SoundFont:"
+
+#: gui/options.cpp:862
+msgid "Mixed AdLib/MIDI mode"
+msgstr "Hunhe AdLib/MIDI Moshi"
+
+#: gui/options.cpp:862
+msgid "Use both MIDI and AdLib sound generation"
+msgstr "TongShi Shiyong MIDI He AdLib Shengyin Shengcheng"
+
+#: gui/options.cpp:865
+msgid "MIDI gain:"
+msgstr "MIDI gain:"
+
+#: gui/options.cpp:872
+msgid "FluidSynth Settings"
+msgstr "FluidSynth Xuanxiang"
+
+#: gui/options.cpp:879
+msgid "MT-32 Device:"
+msgstr "MT-32 Shebei:"
+
+#: gui/options.cpp:879
+msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
+msgstr ""
+"QIng Zhiding Yongyu Roland MT-32/LAPC1/CM32I/CM64 Shuchu de Moren Shengyin "
+"Shebei"
+
+#: gui/options.cpp:884
+msgid "True Roland MT-32 (disable GM emulation)"
+msgstr "Zhen Roland MT-32 (Jinyong GM Moni)"
+
+#: gui/options.cpp:884 gui/options.cpp:886
+msgid ""
+"Check if you want to use your real hardware Roland-compatible sound device "
+"connected to your computer"
+msgstr ""
+"Jiancha Shifou Nin Xiang Shiyong Lianjie Dao Jisuanji de Zhenshi de Yingjian "
+"Roland Jianrong Shengyin Shebei"
+
+#: gui/options.cpp:886
+msgctxt "lowres"
+msgid "True Roland MT-32 (no GM emulation)"
+msgstr "Zhen Roland MT-32 Shebei (Wu GM Moni)"
+
+#: gui/options.cpp:889
+msgid "Roland GS Device (enable MT-32 mappings)"
+msgstr "Roland GS Shebei (Qiyong MT-32 Yingshe)"
+
+#: gui/options.cpp:889
+msgid ""
+"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
+"GS device"
+msgstr ""
+"Jiancha Shifou Nin Xiang Qiyong patch Yingshe Lai Zai Roland GS Shebei "
+"Shangmian Moni MT-32"
+
+#: gui/options.cpp:898
+msgid "Don't use Roland MT-32 music"
+msgstr "Buyao Shiyong Roland MT-32 Yinyue"
+
+#: gui/options.cpp:925
+msgid "Text and Speech:"
+msgstr "Wenzi he Yuyin:"
+
+#: gui/options.cpp:929 gui/options.cpp:939
+msgid "Speech"
+msgstr "Yuyin"
+
+#: gui/options.cpp:930 gui/options.cpp:940
+msgid "Subtitles"
+msgstr "Zimu"
+
+#: gui/options.cpp:931
+msgid "Both"
+msgstr "Liangzhe"
+
+#: gui/options.cpp:933
+msgid "Subtitle speed:"
+msgstr "Zimu Sudu:"
+
+#: gui/options.cpp:935
+msgctxt "lowres"
+msgid "Text and Speech:"
+msgstr "Wenben he Yuyin:"
+
+#: gui/options.cpp:939
+msgid "Spch"
+msgstr "Zimu"
+
+#: gui/options.cpp:940
+msgid "Subs"
+msgstr "Yuyin"
+
+#: gui/options.cpp:941
+msgctxt "lowres"
+msgid "Both"
+msgstr "Dou"
+
+#: gui/options.cpp:941
+msgid "Show subtitles and play speech"
+msgstr "Xianshi Zimu Bing Bofang Yuyin"
+
+#: gui/options.cpp:943
+msgctxt "lowres"
+msgid "Subtitle speed:"
+msgstr "Zimu Sudu"
+
+#: gui/options.cpp:959
+msgid "Music volume:"
+msgstr "Yinyue Yinliang:"
+
+#: gui/options.cpp:961
+msgctxt "lowres"
+msgid "Music volume:"
+msgstr "Yinyue Yinliang:"
+
+#: gui/options.cpp:968
+msgid "Mute All"
+msgstr "Quanbu Jinyin"
+
+#: gui/options.cpp:971
+msgid "SFX volume:"
+msgstr "Yinxiao Yinliang:"
+
+#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+msgid "Special sound effects volume"
+msgstr "Texiao Yinliang"
+
+#: gui/options.cpp:973
+msgctxt "lowres"
+msgid "SFX volume:"
+msgstr "Yinxiao Yinliang:"
+
+#: gui/options.cpp:981
+msgid "Speech volume:"
+msgstr "Yuyin Yinliang:"
+
+#: gui/options.cpp:983
+msgctxt "lowres"
+msgid "Speech volume:"
+msgstr "Yuyin Yinliang:"
+
+#: gui/options.cpp:1140
+msgid "Theme Path:"
+msgstr "Zhuti Lujing:"
+
+#: gui/options.cpp:1142
+msgctxt "lowres"
+msgid "Theme Path:"
+msgstr "Zhuti Lujing:"
+
+#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+msgid "Specifies path to additional data used by all games or ScummVM"
+msgstr "Zhiding Suoyou Youxi huo ScummVM de Shuju Lujing"
+
+#: gui/options.cpp:1157
+msgid "Plugins Path:"
+msgstr "Chajian Lujing:"
+
+#: gui/options.cpp:1159
+msgctxt "lowres"
+msgid "Plugins Path:"
+msgstr "Chajian Lujing:"
+
+#: gui/options.cpp:1170
+msgctxt "lowres"
+msgid "Misc"
+msgstr "Zaxiang"
+
+#: gui/options.cpp:1172
+msgid "Theme:"
+msgstr "Zhuti:"
+
+#: gui/options.cpp:1176
+msgid "GUI Renderer:"
+msgstr "Jiemian Xuanran:"
+
+#: gui/options.cpp:1188
+msgid "Autosave:"
+msgstr "Zidong Baocun:"
+
+#: gui/options.cpp:1190
+msgctxt "lowres"
+msgid "Autosave:"
+msgstr "Zidong Baocun:"
+
+#: gui/options.cpp:1198
+msgid "Keys"
+msgstr "Guanjianzi"
+
+#: gui/options.cpp:1205
+msgid "GUI Language:"
+msgstr "Jiemian Yuyan:"
+
+#: gui/options.cpp:1205
+msgid "Language of ScummVM GUI"
+msgstr "ScummVM Jiemian Yuyan"
+
+#: gui/options.cpp:1364
+msgid "You have to restart ScummVM before your changes will take effect."
+msgstr "Nin Xuyao Chongqi ScummVM Lai Shi Genggai Shengxiao"
+
+#: gui/options.cpp:1384
+msgid "The chosen directory cannot be written to. Please select another one."
+msgstr "Zhiding de Mulu Buneng Xieru. Qing Xuanze Qita de Mulu."
+
+#: gui/options.cpp:1393
+msgid "Select directory for GUI themes"
+msgstr "Xuanze Jiemian Zhuti de Mulu"
+
+#: gui/options.cpp:1403
+msgid "Select directory for extra files"
+msgstr "Xuanze QIta Wenjian Mulu"
+
+#: gui/options.cpp:1414
+msgid "Select directory for plugins"
+msgstr "Xuanze Chajian Mulu"
+
+#: gui/options.cpp:1467
+msgid ""
+"The theme you selected does not support your current language. If you want "
+"to use this theme you need to switch to another language first."
+msgstr ""
+"Nin Xuanze de Zhuti Bu Zhichi Xianzai de Yuyan. Qing Xian Qiehuan Dao Qita "
+"Yuyan."
+
+#. I18N: You must leave "#" as is, only word 'next' is translatable
+#: gui/predictivedialog.cpp:86
+msgid "# next"
+msgstr "# Xia Yi Ge"
+
+#: gui/predictivedialog.cpp:87
+msgid "add"
+msgstr "Zengjia"
+
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+msgid "Delete char"
+msgstr "Shanchu Zifu"
+
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+msgid "<"
+msgstr "<"
+
+#. I18N: Pre means 'Predictive', leave '*' as is
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+msgid "* Pre"
+msgstr "* Guanci"
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:575
+msgid "* Num"
+msgstr "* Shuzi"
+
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:578
+msgid "* Abc"
+msgstr "* Zimu"
+
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr "Youxi Luxiang Huo Huifang"
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Shanchu"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr "Luxiang"
+
+#: gui/recorderdialog.cpp:72
+msgid "Playback"
+msgstr "Huifang"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr "Binaji"
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr "Zuozhe:"
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr "Zhushi:"
+
+#: gui/recorderdialog.cpp:155
+msgid "Do you really want to delete this record?"
+msgstr "Nin Zhende Xinagyao Shanchu Zhege Luxiang ma?"
+
+#: gui/recorderdialog.cpp:174
+msgid "Unknown Author"
+msgstr "Weizhi Zuozhe"
+
+#: gui/saveload-dialog.cpp:167
+msgid "List view"
+msgstr "Liebiao Shitu"
+
+#: gui/saveload-dialog.cpp:168
+msgid "Grid view"
+msgstr "Wangge Shitu"
+
+#: gui/saveload-dialog.cpp:211 gui/saveload-dialog.cpp:360
+msgid "No date saved"
+msgstr "Riqi Wei Baocun"
+
+#: gui/saveload-dialog.cpp:212 gui/saveload-dialog.cpp:361
+msgid "No time saved"
+msgstr "Shijian Wei Baocun"
+
+#: gui/saveload-dialog.cpp:213 gui/saveload-dialog.cpp:362
+msgid "No playtime saved"
+msgstr "Bofang Shijian Wei Baocun"
+
+#: gui/saveload-dialog.cpp:275
+msgid "Do you really want to delete this saved game?"
+msgstr "Nin Zhende Yao Shanchu Zhege Baocun Youxi ma?"
+
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
+msgid "Date: "
+msgstr "Riqi: "
+
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
+msgid "Time: "
+msgstr "Shijian: "
+
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
+msgid "Playtime: "
+msgstr "Bofang Shijian:"
+
+#: gui/saveload-dialog.cpp:408 gui/saveload-dialog.cpp:496
+msgid "Untitled savestate"
+msgstr "Wuming Baocun Zhuangtai"
+
+#: gui/saveload-dialog.cpp:548
+msgid "Next"
+msgstr "Xia Yi Ge"
+
+#: gui/saveload-dialog.cpp:551
+msgid "Prev"
+msgstr "Shang Yi Ge"
+
+#: gui/saveload-dialog.cpp:748
+msgid "New Save"
+msgstr "Xinjian Cundang"
+
+#: gui/saveload-dialog.cpp:748
+msgid "Create a new save game"
+msgstr "Chuangjian Yige Xin Cundang"
+
+#: gui/saveload-dialog.cpp:877
+msgid "Name: "
+msgstr "Mingcheng:"
+
+#: gui/saveload-dialog.cpp:949
+#, c-format
+msgid "Enter a description for slot %d:"
+msgstr "Shuru dui %d Dangwei de Miaoshu"
+
+#: gui/themebrowser.cpp:45
+msgid "Select a Theme"
+msgstr "Xuanze Zhuti"
+
+#: gui/ThemeEngine.cpp:347
+msgid "Disabled GFX"
+msgstr "Jinyong GFX"
+
+#: gui/ThemeEngine.cpp:347
+msgctxt "lowres"
+msgid "Disabled GFX"
+msgstr "Jinyong GFX"
+
+#: gui/ThemeEngine.cpp:348
+msgid "Standard Renderer"
+msgstr "Biaozhun Xuanranqi"
+
+#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+msgid "Standard"
+msgstr "Biaozhun"
+
+#: gui/ThemeEngine.cpp:350
+msgid "Antialiased Renderer"
+msgstr "Fanjuchi Xuanranqi"
+
+#: gui/ThemeEngine.cpp:350
+msgid "Antialiased"
+msgstr "Fanjuchi"
+
+#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+msgid "Clear value"
+msgstr "Qingchu Zhi"
+
+#: base/main.cpp:237
+#, c-format
+msgid "Engine does not support debug level '%s'"
+msgstr "Yinqing Buzhichi Tiaoshi Jibie ‘%s’"
+
+#: base/main.cpp:309
+msgid "Menu"
+msgstr "Caidan"
+
+#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: backends/platform/wince/CEActionsPocket.cpp:45
+#: backends/platform/wince/CEActionsSmartphone.cpp:46
+msgid "Skip"
+msgstr "Tiaoguo"
+
+#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: backends/platform/wince/CEActionsPocket.cpp:42
+msgid "Pause"
+msgstr "Zanting"
+
+#: base/main.cpp:318
+msgid "Skip line"
+msgstr "Tiaoguo Cihang"
+
+#: base/main.cpp:510
+msgid "Error running game:"
+msgstr "Youxi Yunxing Cuowu:"
+
+#: base/main.cpp:557
+msgid "Could not find any engine capable of running the selected game"
+msgstr "Wufa Zhaodao Shihe Yunxing Youxi de Yinqing"
+
+#: common/error.cpp:38
+msgid "No error"
+msgstr "Wu Cuowu"
+
+#: common/error.cpp:40
+msgid "Game data not found"
+msgstr "Youxi Shuju Weizhaodao"
+
+#: common/error.cpp:42
+msgid "Game id not supported"
+msgstr "Youxi id Bu Zhichi"
+
+#: common/error.cpp:44
+msgid "Unsupported color mode"
+msgstr "Buzhichi Secai Moshi"
+
+#: common/error.cpp:47
+msgid "Read permission denied"
+msgstr "Wu Duqu Quanxian"
+
+#: common/error.cpp:49
+msgid "Write permission denied"
+msgstr "Wu XIeru Quanxian"
+
+#: common/error.cpp:52
+msgid "Path does not exist"
+msgstr "Lujing Bu Cunzai"
+
+#: common/error.cpp:54
+msgid "Path not a directory"
+msgstr "Lujing Bushi Mulu"
+
+#: common/error.cpp:56
+msgid "Path not a file"
+msgstr "Lujing Bushi Wenjian"
+
+#: common/error.cpp:59
+msgid "Cannot create file"
+msgstr "Wufa Chuangjian Wenjian"
+
+#: common/error.cpp:61
+msgid "Reading data failed"
+msgstr "Duqu Shuju Shibai"
+
+#: common/error.cpp:63
+msgid "Writing data failed"
+msgstr "Xieru Shuju Shibai"
+
+#: common/error.cpp:66
+msgid "Could not find suitable engine plugin"
+msgstr "Wufa Zhaodao Heshi de Yinqing Chajian"
+
+#: common/error.cpp:68
+msgid "Engine plugin does not support save states"
+msgstr "Yingqing Chajian Buzhichi Baocun Zhuangtai"
+
+#: common/error.cpp:71
+msgid "User canceled"
+msgstr "Yonghu Quxiao"
+
+#: common/error.cpp:75
+msgid "Unknown error"
+msgstr "Weizhi Cuowu"
+
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules Green"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules Amber"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 Se)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 Se)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules Green"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules Amber"
+
+#: engines/advancedDetector.cpp:317
+#, c-format
+msgid "The game in '%s' seems to be unknown."
+msgstr "'%s' Zhong de Youxi Weizhi."
+
+#: engines/advancedDetector.cpp:318
+msgid "Please, report the following data to the ScummVM team along with name"
+msgstr "Qing JIang Xialie Shuju Yiji Youxi Baogao Gei ScummVM Tuandui"
+
+#: engines/advancedDetector.cpp:320
+msgid "of the game you tried to add and its version/language/etc.:"
+msgstr "BingQie Fushang Shitu Tianjia de Youximing Yiji Banben/Yuyan Deng"
+
+#: engines/dialogs.cpp:85
+msgid "~R~esume"
+msgstr "~R~Jixu"
+
+#: engines/dialogs.cpp:87
+msgid "~L~oad"
+msgstr "~L~Zairu"
+
+#: engines/dialogs.cpp:91
+msgid "~S~ave"
+msgstr "~S~Baocun"
+
+#: engines/dialogs.cpp:95
+msgid "~O~ptions"
+msgstr "~O~Xuanxiang"
+
+#: engines/dialogs.cpp:100
+msgid "~H~elp"
+msgstr "~H~Bangzhu"
+
+#: engines/dialogs.cpp:102
+msgid "~A~bout"
+msgstr "~A~Guanyu"
+
+#: engines/dialogs.cpp:105 engines/dialogs.cpp:181
+msgid "~R~eturn to Launcher"
+msgstr "~R~Fanhui Qidongqi"
+
+#: engines/dialogs.cpp:107 engines/dialogs.cpp:183
+msgctxt "lowres"
+msgid "~R~eturn to Launcher"
+msgstr "~R~Fanhui Qidongqi"
+
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
+#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
+#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
+#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
+#: engines/sherlock/scalpel/scalpel.cpp:1249
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
+#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+msgid "Save game:"
+msgstr "Baocun Youxi:"
+
+#: engines/dialogs.cpp:116 backends/platform/symbian/src/SymbianActions.cpp:44
+#: backends/platform/wince/CEActionsPocket.cpp:43
+#: backends/platform/wince/CEActionsPocket.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:45
+#: backends/platform/wince/CEActionsSmartphone.cpp:231
+#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
+#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
+#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
+#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
+#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
+#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+msgid "Save"
+msgstr "Baocun"
+
+#: engines/dialogs.cpp:145
+msgid ""
+"Sorry, this engine does not currently provide in-game help. Please consult "
+"the README for basic information, and for instructions on how to obtain "
+"further assistance."
+msgstr ""
+"Duibuqi, Ci Yinqing Buzhichi Youxi Nei Bangzhu. Qing Chayue README Lai Huoqu "
+"Jiben Xinxi Yiji Ruhe Huode Gengduo Bangzhu."
+
+#: engines/dialogs.cpp:234 engines/pegasus/pegasus.cpp:393
+#, c-format
+msgid ""
+"Gamestate save failed (%s)! Please consult the README for basic information, "
+"and for instructions on how to obtain further assistance."
+msgstr ""
+"Cundang Baocun Shibai (%s)! Qing Chayue README Huode Jiben Xinxi, Yiji "
+"Gengduo Xinxi"
+
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
+#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+msgid "~O~K"
+msgstr "~O~Queding"
+
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
+#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+msgid "~C~ancel"
+msgstr "~C~Quxiao"
+
+#: engines/dialogs.cpp:311
+msgid "~K~eys"
+msgstr "~K~Guanjianzi"
+
+#: engines/engine.cpp:339
+msgid "Could not initialize color format."
+msgstr "Wufa Chushihua Secai Geshi."
+
+#: engines/engine.cpp:347
+msgid "Could not switch to video mode: '"
+msgstr "Wufa Qiehuandao Shipin Moshi: '"
+
+#: engines/engine.cpp:356
+msgid "Could not apply aspect ratio setting."
+msgstr "Wufa Shezhi Bili Xuanxiang"
+
+#: engines/engine.cpp:361
+msgid "Could not apply fullscreen setting."
+msgstr "Wufa Shezhi Quanping Xuanxiang"
+
+#: engines/engine.cpp:461
+msgid ""
+"You appear to be playing this game directly\n"
+"from the CD. This is known to cause problems,\n"
+"and it is therefore recommended that you copy\n"
+"the data files to your hard disk instead.\n"
+"See the README file for details."
+msgstr ""
+"Sihu Ni Zhengzai Cong CD Zhong Yunxing\n"
+"Youxi. Zhe Keneng Hui Yinfa Wenti.\n"
+"Women Tuijian Nin Ba Shuju Wenjian\n"
+"Kaobei Dao Yingpan Zhong Lai Yunxing.\n"
+"Chakan README Huode Gengduo Xinxi."
+
+#: engines/engine.cpp:472
+msgid ""
+"This game has audio tracks in its disk. These\n"
+"tracks need to be ripped from the disk using\n"
+"an appropriate CD audio extracting tool in\n"
+"order to listen to the game's music.\n"
+"See the README file for details."
+msgstr ""
+"Ci Youxi Zai Guangpan Zhong Baohan Yinyue Wenjian. \n"
+"Zhexie Yingui Xuyao Yong Xiangying de CD Yinpin\n"
+"Jieya Gongju Kaobei Dao Cipan Zhong Cai Neng \n"
+"Bofang.\n"
+"Juti Xinxi Qing Chakan README."
+
+#: engines/engine.cpp:530
+#, c-format
+msgid ""
+"Gamestate load failed (%s)! Please consult the README for basic information, "
+"and for instructions on how to obtain further assistance."
+msgstr ""
+"Cundang Zairu Shibai (%s)! Qing Chayue README Huode Bangzhu XInxi Yiji "
+"Gengduo Bangzhu."
+
+#: engines/engine.cpp:543
+msgid ""
+"WARNING: The game you are about to start is not yet fully supported by "
+"ScummVM. As such, it is likely to be unstable, and any saves you make might "
+"not work in future versions of ScummVM."
+msgstr ""
+"Jinggao: Nin Yao Yunxing de Youxi Bingwei Wanquan Bei ScummVM Zhichi. Youxi "
+"Yunxing Youkeneng Buwending, Renhe Cundang Youkeneng zai Yihou de ScummVM "
+"Banben Bu Keyong."
+
+#: engines/engine.cpp:546
+msgid "Start anyway"
+msgstr "Qiangzhi Qidong"
+
+#: audio/adlib.cpp:2291
+msgid "AdLib Emulator"
+msgstr "AdLib Moniqi"
+
+#: audio/fmopl.cpp:62
+msgid "MAME OPL emulator"
+msgstr "MAME OPL Moniqi"
+
+#: audio/fmopl.cpp:64
+msgid "DOSBox OPL emulator"
+msgstr "DosBox OPL Moniqi"
+
+#: audio/fmopl.cpp:67
+msgid "ALSA Direct FM"
+msgstr "ALSA Direct FM"
+
+#: audio/mididrv.cpp:209
+#, c-format
+msgid ""
+"The selected audio device '%s' was not found (e.g. might be turned off or "
+"disconnected)."
+msgstr ""
+"Weizhaodao Xuanding de Yinpin Shebei '%s' (Liru, Youkeneng Guandiao Huozhe "
+"Weilianjie)."
+
+#: audio/mididrv.cpp:209 audio/mididrv.cpp:221 audio/mididrv.cpp:257
+#: audio/mididrv.cpp:272
+msgid "Attempting to fall back to the next available device..."
+msgstr "ZhengChangshi Xiayige Keyong Shebei..."
+
+#: audio/mididrv.cpp:221
+#, c-format
+msgid ""
+"The selected audio device '%s' cannot be used. See log file for more "
+"information."
+msgstr ""
+"Xuanding de Yinpin Shebei '%s' Wufa Shiyong. Chakan Rizhi Wenjian Huoqu "
+"Gengduo Xinxi."
+
+#: audio/mididrv.cpp:257
+#, c-format
+msgid ""
+"The preferred audio device '%s' was not found (e.g. might be turned off or "
+"disconnected)."
+msgstr ""
+"Youxian Yinpin Shebei '%s' WeiZhaodao (Liru, Youkeneng Guanbi Huo "
+"Weilianjie)."
+
+#: audio/mididrv.cpp:272
+#, c-format
+msgid ""
+"The preferred audio device '%s' cannot be used. See log file for more "
+"information."
+msgstr ""
+"Youxian Yinpin Shebei '%s' Wufa Shiyong. Chakan Rizhi Wenjian Huode Gengduo "
+"Xinxi."
+
+#: audio/mods/paula.cpp:196
+msgid "Amiga Audio Emulator"
+msgstr "Amiga Yinpin Moniqi"
+
+#: audio/null.h:44
+msgid "No music"
+msgstr "Wu Yinyue"
+
+#: audio/softsynth/appleiigs.cpp:33
+msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
+msgstr "Apple II GS Moniqi (Wei Shixian)"
+
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "Creative Music System Moniqi"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "FM-Towns Yinpin"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+msgid "PC-98 Audio"
+msgstr "PC-98 Yinpin"
+
+#: audio/softsynth/mt32.cpp:200
+msgid "Initializing MT-32 Emulator"
+msgstr "Chushihua MT-32 Moniqi"
+
+#: audio/softsynth/mt32.cpp:426
+msgid "MT-32 Emulator"
+msgstr "MT-32 Moniqi"
+
+#: audio/softsynth/pcspk.cpp:139
+msgid "PC Speaker Emulator"
+msgstr "PC Yangshengqi Moniqi"
+
+#: audio/softsynth/pcspk.cpp:158
+msgid "IBM PCjr Emulator"
+msgstr "IBM PCjr Moniqi"
+
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "C64 Yinpin Moniqi"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Nin Zhende Xinagyao Fanhui Qidongqi Ma?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Qidongqi"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Nin Zhende Yao Tuichu Ma?"
+
+#: backends/events/default/default-events.cpp:218
+#: backends/platform/symbian/src/SymbianActions.cpp:52
+#: backends/platform/wince/CEActionsPocket.cpp:44
+#: backends/platform/wince/CEActionsSmartphone.cpp:52
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
+msgid "Quit"
+msgstr "Tuichu"
+
+#: backends/events/gph/gph-events.cpp:385
+#: backends/events/gph/gph-events.cpp:428
+#: backends/events/openpandora/op-events.cpp:168
+msgid "Touchscreen 'Tap Mode' - Left Click"
+msgstr "Chuping 'Chumo Moshi' - Zuojian Danji"
+
+#: backends/events/gph/gph-events.cpp:387
+#: backends/events/gph/gph-events.cpp:430
+#: backends/events/openpandora/op-events.cpp:170
+msgid "Touchscreen 'Tap Mode' - Right Click"
+msgstr "Chuping 'Chumo Moshi' - Youjian Danji"
+
+#: backends/events/gph/gph-events.cpp:389
+#: backends/events/gph/gph-events.cpp:432
+#: backends/events/openpandora/op-events.cpp:172
+msgid "Touchscreen 'Tap Mode' - Hover (No Click)"
+msgstr "Chuping 'Chumo Moshi' - Xuanting (Bu Danji)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Zuida YInliang"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Zengda Yinliang"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Zuixiao Yinliang"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Jianshao Yinliang"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Qidong Dianji"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Jinyong Dianji"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "Chuping 'Chumo Moshi' - Xuanting (Shoubing Dianji)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Nin Zhende Yao Tuichu Ma?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "Muqian Wei Chumoban Moshi"
+
+#. I18N: Trackpad mode on or off.
+#. I18N: Auto-drag on or off.
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "ON"
+msgstr "Kai"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "Guan"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "XiangYou Shiyong Liang Gen Shouzhi Huadong Qiehuan"
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "Muqian Wei Zidong Tuozhuai Moshi"
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr "Xiangyou Huadong San Gen Shouzhi Qiehuan"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:119
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:120
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:47
+#: backends/graphics/wincesdl/wincesdl-graphics.cpp:88
+#: backends/graphics/wincesdl/wincesdl-graphics.cpp:95
+msgid "Normal (no scaling)"
+msgstr "Putong"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Putong"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+msgid "Enabled aspect ratio correction"
+msgstr "Qiyong Bili Jiaozheng"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+msgid "Disabled aspect ratio correction"
+msgstr "Jinyong Bili Jiaozheng"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+msgid "Active graphics filter:"
+msgstr "Huodong de Tuxing Guolvqi:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+msgid "Windowed mode"
+msgstr "Chuangkou Moshi"
+
+#: backends/keymapper/remap-dialog.cpp:48
+msgid "Keymap:"
+msgstr "Jianpan Yingshe:"
+
+#: backends/keymapper/remap-dialog.cpp:67
+msgid " (Effective)"
+msgstr " (Shengxiao)"
+
+#: backends/keymapper/remap-dialog.cpp:107
+msgid " (Active)"
+msgstr " (Huodong)"
+
+#: backends/keymapper/remap-dialog.cpp:107
+msgid " (Blocked)"
+msgstr " (Zuzhi)"
+
+#: backends/keymapper/remap-dialog.cpp:120
+msgid " (Global)"
+msgstr " (Quanju)"
+
+#: backends/keymapper/remap-dialog.cpp:128
+msgid " (Game)"
+msgstr " (Youxi)"
+
+#: backends/midi/windows.cpp:165
+msgid "Windows MIDI"
+msgstr "Windows MIDI"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:56
+#: engines/scumm/dialogs.cpp:291
+msgid "~C~lose"
+msgstr "~C~Guanbi"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:57
+msgid "ScummVM Main Menu"
+msgstr "ScummVM Zhucaidan"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:63
+msgid "~L~eft handed mode"
+msgstr "~L~Zuoshou Moshi"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:64
+msgid "~I~ndy fight controls"
+msgstr "~I~Indy fight Kongzhi"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:65
+msgid "Show mouse cursor"
+msgstr "Xianshi Shubiao Zhizhen"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:66
+msgid "Snap to edges"
+msgstr "TieFu Yu Bianjie"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:68
+msgid "Touch X Offset"
+msgstr "Chumo X Pianyi"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:75
+msgid "Touch Y Offset"
+msgstr "Chumo Y Pianyi"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:87
+msgid "Use laptop trackpad-style cursor control"
+msgstr "Shiyong Bijiben Diannao Chumoban Shi Zhizhen Kongzhi"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:88
+msgid "Tap for left click, double tap right click"
+msgstr "Chumo Yici Wei Zuojian, Chumo LIangci Wei Youjian"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:90
+msgid "Sensitivity"
+msgstr "Mingandu"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:99
+msgid "Initial top screen scale:"
+msgstr "Chushi Shangping Daxiao"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:105
+msgid "Main screen scaling:"
+msgstr "Zhu Pingmu Daxiao"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:107
+msgid "Hardware scale (fast, but low quality)"
+msgstr "yingjian Suofang (Kuaisu DiXiao)"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:108
+msgid "Software scale (good quality, but slower)"
+msgstr "Ruanjian Suofang (Gaoxiao Mansu)"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:109
+msgid "Unscaled (you must scroll left and right)"
+msgstr "Wei Suofang (Xuyao ZuoYou Yidong)"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:111
+msgid "Brightness:"
+msgstr "Liangdu:"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:121
+msgid "High quality audio (slower) (reboot)"
+msgstr "Gaozhiliang Yinpin (Man) (Chongqi)"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:122
+msgid "Disable power off"
+msgstr "Jinyong Guanji"
+
+#: backends/platform/ios7/ios7_osys_events.cpp:309
+#: backends/platform/ios7/ios7_osys_events.cpp:519
+#: backends/platform/iphone/osys_events.cpp:300
+msgid "Mouse-click-and-drag mode enabled."
+msgstr "QIdong Shubiao Dianji-tuozhuai Moshi"
+
+#: backends/platform/ios7/ios7_osys_events.cpp:311
+#: backends/platform/ios7/ios7_osys_events.cpp:521
+#: backends/platform/iphone/osys_events.cpp:302
+msgid "Mouse-click-and-drag mode disabled."
+msgstr "Jinyong Shubiao Dianji-Tuozhuai Moshi."
+
+#: backends/platform/ios7/ios7_osys_events.cpp:322
+#: backends/platform/ios7/ios7_osys_events.cpp:540
+#: backends/platform/iphone/osys_events.cpp:313
+msgid "Touchpad mode enabled."
+msgstr "Qiyong Chumoban Moshi"
+
+#: backends/platform/ios7/ios7_osys_events.cpp:324
+#: backends/platform/ios7/ios7_osys_events.cpp:542
+#: backends/platform/iphone/osys_events.cpp:315
+msgid "Touchpad mode disabled."
+msgstr "Jinyong Chumoban Moshi"
+
+#: backends/platform/maemo/maemo.cpp:208
+msgid "Click Mode"
+msgstr "Danji Moshi"
+
+#: backends/platform/maemo/maemo.cpp:214
+#: backends/platform/symbian/src/SymbianActions.cpp:42
+#: backends/platform/tizen/form.cpp:275
+#: backends/platform/wince/CEActionsPocket.cpp:60
+#: backends/platform/wince/CEActionsSmartphone.cpp:43
+msgid "Left Click"
+msgstr "Zuojian Danji"
+
+#: backends/platform/maemo/maemo.cpp:217
+msgid "Middle Click"
+msgstr "Zhongjian Danji"
+
+#: backends/platform/maemo/maemo.cpp:220
+#: backends/platform/symbian/src/SymbianActions.cpp:43
+#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
+msgid "Right Click"
+msgstr "Youjian Danji"
+
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
+msgid "Hide ScummVM"
+msgstr "Yincang ScummVM"
+
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
+msgid "Hide Others"
+msgstr "Yincang QIta"
+
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
+msgid "Show All"
+msgstr "Xianshi Quanbu"
+
+#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
+msgid "Window"
+msgstr "Chuangkou"
+
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
+msgid "Minimize"
+msgstr "Zuixiaohua"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:38
+#: backends/platform/wince/CEActionsSmartphone.cpp:39
+msgid "Up"
+msgstr "Shang"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:39
+#: backends/platform/wince/CEActionsSmartphone.cpp:40
+msgid "Down"
+msgstr "Xia"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:40
+#: backends/platform/wince/CEActionsSmartphone.cpp:41
+msgid "Left"
+msgstr "Zuo"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:41
+#: backends/platform/wince/CEActionsSmartphone.cpp:42
+msgid "Right"
+msgstr "You"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:46
+#: backends/platform/wince/CEActionsSmartphone.cpp:47
+msgid "Zone"
+msgstr "Quyu"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:47
+#: backends/platform/wince/CEActionsPocket.cpp:54
+#: backends/platform/wince/CEActionsSmartphone.cpp:48
+msgid "Multi Function"
+msgstr "Duo Gongneng"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:48
+msgid "Swap character"
+msgstr "Qiehuan Juese"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:49
+msgid "Skip text"
+msgstr "Tiaoguo Wenben"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:51
+msgid "Fast mode"
+msgstr "Kuaisu Moshi"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:53
+msgid "Debugger"
+msgstr "Tiaoshi Qi"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:54
+msgid "Global menu"
+msgstr "Quanju Caidan"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:55
+msgid "Virtual keyboard"
+msgstr "Xuni JIanpan"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:56
+msgid "Key mapper"
+msgstr "Jianpan yingshe"
+
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Youjian Danji"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Jin Yidong"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Esc Jian"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Youxi Caidan"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Xianshi Jianpan"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Kongzhi Shubiao"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ Shuju ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Ziyuan]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ SD Ka ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ Meiti ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ gongxiang ]"
+
+#: backends/platform/wii/options.cpp:51
+msgid "Video"
+msgstr "Shipin"
+
+#: backends/platform/wii/options.cpp:54
+msgid "Current video mode:"
+msgstr "Muqian Shipin Moshi:"
+
+#: backends/platform/wii/options.cpp:56
+msgid "Double-strike"
+msgstr "Shuang Ji"
+
+#: backends/platform/wii/options.cpp:60
+msgid "Horizontal underscan:"
+msgstr "Shuiping Saomiao"
+
+#: backends/platform/wii/options.cpp:66
+msgid "Vertical underscan:"
+msgstr "Chuizhi Saomiao"
+
+#: backends/platform/wii/options.cpp:71
+msgid "Input"
+msgstr "Shuru"
+
+#: backends/platform/wii/options.cpp:74
+msgid "GC Pad sensitivity:"
+msgstr "GC Pan Mingandu"
+
+#: backends/platform/wii/options.cpp:80
+msgid "GC Pad acceleration:"
+msgstr "GC Pad Jiasu"
+
+#: backends/platform/wii/options.cpp:86
+msgid "DVD"
+msgstr "DVD"
+
+#: backends/platform/wii/options.cpp:89 backends/platform/wii/options.cpp:101
+msgid "Status:"
+msgstr "Zhuangtai:"
+
+#: backends/platform/wii/options.cpp:90 backends/platform/wii/options.cpp:102
+msgid "Unknown"
+msgstr "Weizhi"
+
+#: backends/platform/wii/options.cpp:93
+msgid "Mount DVD"
+msgstr "Jiazai DVD"
+
+#: backends/platform/wii/options.cpp:94
+msgid "Unmount DVD"
+msgstr "Xiezai DVD"
+
+#: backends/platform/wii/options.cpp:98
+msgid "SMB"
+msgstr "SMB"
+
+#: backends/platform/wii/options.cpp:106
+msgid "Server:"
+msgstr "Fuwuqi:"
+
+#: backends/platform/wii/options.cpp:110
+msgid "Share:"
+msgstr "Gongxiang:"
+
+#: backends/platform/wii/options.cpp:114
+msgid "Username:"
+msgstr "Yonghuming:"
+
+#: backends/platform/wii/options.cpp:118
+msgid "Password:"
+msgstr "Mima:"
+
+#: backends/platform/wii/options.cpp:121
+msgid "Init network"
+msgstr "Chushihua Wangluo"
+
+#: backends/platform/wii/options.cpp:123
+msgid "Mount SMB"
+msgstr "Jiazai SMB"
+
+#: backends/platform/wii/options.cpp:124
+msgid "Unmount SMB"
+msgstr "Xiezai SMB"
+
+#: backends/platform/wii/options.cpp:143
+msgid "DVD Mounted successfully"
+msgstr "DVD Jiazai Chenggong"
+
+#: backends/platform/wii/options.cpp:146
+msgid "Error while mounting the DVD"
+msgstr "Jiazai DVD Chucuo"
+
+#: backends/platform/wii/options.cpp:148
+msgid "DVD not mounted"
+msgstr "DVD Wei Jiazai"
+
+#: backends/platform/wii/options.cpp:161
+msgid "Network up, share mounted"
+msgstr "Wangluo Lianjie, Gongxiang Jiazai"
+
+#: backends/platform/wii/options.cpp:163
+msgid "Network up"
+msgstr "Wangluo Lianjie"
+
+#: backends/platform/wii/options.cpp:166
+msgid ", error while mounting the share"
+msgstr ", Jiazai Gongxiang Chucuo"
+
+#: backends/platform/wii/options.cpp:168
+msgid ", share not mounted"
+msgstr ", Wei jiazai Gongxiang"
+
+#: backends/platform/wii/options.cpp:174
+msgid "Network down"
+msgstr "Wangluo Duanxian"
+
+#: backends/platform/wii/options.cpp:178
+msgid "Initializing network"
+msgstr "Chushihua Wnagluo"
+
+#: backends/platform/wii/options.cpp:182
+msgid "Timeout while initializing network"
+msgstr "Chushihua Wnagluo Chaoshi"
+
+#: backends/platform/wii/options.cpp:186
+#, c-format
+msgid "Network not initialized (%d)"
+msgstr "Wangluo Wei Chushihua (%d)"
+
+#: backends/platform/wince/CEActionsPocket.cpp:46
+msgid "Hide Toolbar"
+msgstr "YIncang Gongjulan"
+
+#: backends/platform/wince/CEActionsPocket.cpp:47
+msgid "Show Keyboard"
+msgstr "Xianshi JIanpan"
+
+#: backends/platform/wince/CEActionsPocket.cpp:48
+msgid "Sound on/off"
+msgstr "Shengyin Kai/Guan"
+
+#: backends/platform/wince/CEActionsPocket.cpp:49
+msgid "Right click"
+msgstr "Youjian Danji"
+
+#: backends/platform/wince/CEActionsPocket.cpp:50
+msgid "Show/Hide Cursor"
+msgstr "Xianshi/Yincang Zhizhen"
+
+#: backends/platform/wince/CEActionsPocket.cpp:51
+msgid "Free look"
+msgstr "Ziyou Chakan"
+
+#: backends/platform/wince/CEActionsPocket.cpp:52
+msgid "Zoom up"
+msgstr "Fangda"
+
+#: backends/platform/wince/CEActionsPocket.cpp:53
+msgid "Zoom down"
+msgstr "Suoxiao"
+
+#: backends/platform/wince/CEActionsPocket.cpp:55
+#: backends/platform/wince/CEActionsSmartphone.cpp:49
+msgid "Bind Keys"
+msgstr "Bangding Jianwei"
+
+#: backends/platform/wince/CEActionsPocket.cpp:56
+msgid "Cursor Up"
+msgstr "Zhizhen Shang"
+
+#: backends/platform/wince/CEActionsPocket.cpp:57
+msgid "Cursor Down"
+msgstr "Zhizhen Xia"
+
+#: backends/platform/wince/CEActionsPocket.cpp:58
+msgid "Cursor Left"
+msgstr "Zhizhen Zuo"
+
+#: backends/platform/wince/CEActionsPocket.cpp:59
+msgid "Cursor Right"
+msgstr "Zhizhen You"
+
+#: backends/platform/wince/CEActionsPocket.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:231
+msgid "Do you want to load or save the game?"
+msgstr "Nin Xinagyao Zairu Huo Baocun Youxi Ma?"
+
+#: backends/platform/wince/CEActionsPocket.cpp:326
+#: backends/platform/wince/CEActionsSmartphone.cpp:287
+msgid " Are you sure you want to quit ? "
+msgstr "Nin Queding Tuichu ma ?"
+
+#: backends/platform/wince/CEActionsSmartphone.cpp:50
+msgid "Keyboard"
+msgstr "Jianpan"
+
+#: backends/platform/wince/CEActionsSmartphone.cpp:51
+msgid "Rotate"
+msgstr "Xuanzhuan"
+
+#: backends/platform/wince/CELauncherDialog.cpp:56
+msgid "Using SDL driver "
+msgstr "Shiyong SDL Qudong"
+
+#: backends/platform/wince/CELauncherDialog.cpp:60
+msgid "Display "
+msgstr "Xianshi"
+
+#: backends/platform/wince/CELauncherDialog.cpp:83
+msgid "Do you want to perform an automatic scan ?"
+msgstr "Nin Xiwang Zidong Saomiao ma?"
+
+#: backends/platform/wince/wince-sdl.cpp:516
+msgid "Map right click action"
+msgstr "Yingshe Youjian Dianji Xingwei"
+
+#: backends/platform/wince/wince-sdl.cpp:520
+msgid "You must map a key to the 'Right Click' action to play this game"
+msgstr "Nin Bixu Yingshe Yige Jian Dao 'Youjian Danji' Lai kaishi Youxi"
+
+#: backends/platform/wince/wince-sdl.cpp:529
+msgid "Map hide toolbar action"
+msgstr "yingshe YIncang Gongjulan Xingwei"
+
+#: backends/platform/wince/wince-sdl.cpp:533
+msgid "You must map a key to the 'Hide toolbar' action to play this game"
+msgstr "Nin Bixu Yingshe Yigejian Dao 'Yincang Gongjulan' Lai Kaishi Youxi"
+
+#: backends/platform/wince/wince-sdl.cpp:542
+msgid "Map Zoom Up action (optional)"
+msgstr "Yingshe Fnagda Xingwei (Kexuan)"
+
+#: backends/platform/wince/wince-sdl.cpp:545
+msgid "Map Zoom Down action (optional)"
+msgstr "Yingshe Suoxiao Xingwei (Kexuan)"
+
+#: backends/platform/wince/wince-sdl.cpp:553
+msgid ""
+"Don't forget to map a key to 'Hide Toolbar' action to see the whole inventory"
+msgstr ""
+"Buyao Wnagji Yingshe YIge Jian Dao 'YIncang Gongjulan' Lai Chakan Suoyou "
+"xiang"
+
+#: backends/updates/macosx/macosx-updates.mm:67
+msgid "Check for Updates..."
+msgstr "Jiancha Gengxin..."
+
+#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
+#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
+msgid "Use original save/load screens"
+msgstr "Shiyong Yuanshi Baocun/Zairu Pingmu"
+
+#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/toltecs/detection.cpp:201
+msgid "Use the original save/load screens, instead of the ScummVM ones"
+msgstr "Shiyong Yuanshi Baocun/Zairu Pingmu, Bu Shiyong ScummVM de"
+
+#: engines/agi/detection.cpp:157
+msgid "Use an alternative palette"
+msgstr "Shiyong Qita Mianban"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr "Shiyong QIta Mianban, Yiban Yonghu suoyou de Amiga Youxi. "
+
+#: engines/agi/detection.cpp:167
+msgid "Mouse support"
+msgstr "Shubiao Zhichi"
+
+#: engines/agi/detection.cpp:168
+msgid ""
+"Enables mouse support. Allows to use mouse for movement and in game menus."
+msgstr ""
+"Qiyong shubiao zhichi. Yunxu Shiyong Shubiao jinxing Yidong He Youxi Nei "
+"Caidan"
+
+#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
+#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
+#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
+#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
+#: engines/toon/toon.cpp:3430
+msgid "Restore game:"
+msgstr "Huifu Youxi:"
+
+#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
+#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
+#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
+#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
+#: engines/toon/toon.cpp:3430
+msgid "Restore"
+msgstr "Huifu"
+
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#, c-format
+msgid ""
+"Failed to load game state from file:\n"
+"\n"
+"%s"
+msgstr ""
+"Jiazai Youxi Cundang Shibai:\n"
+"\n"
+"%s"
+
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#, c-format
+msgid ""
+"Failed to save game state to file:\n"
+"\n"
+"%s"
+msgstr ""
+"Baocun Youxi Cundang Shibai:\n"
+"\n"
+"%s"
+
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#, c-format
+msgid ""
+"Successfully saved game state in file:\n"
+"\n"
+"%s"
+msgstr ""
+"Chenggong Baocun Youxi Cundang:\n"
+"\n"
+"%s"
+
+#: engines/agos/animation.cpp:557
+#, c-format
+msgid "Cutscene file '%s' not found!"
+msgstr "Changjing Qiehuan Wenjian '%s' Wei Zhaodao!"
+
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
+msgid "Color Blind Mode"
+msgstr "Semang Moshi"
+
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
+msgid "Enable Color Blind Mode by default"
+msgstr "Moren Qiyong Semang Moshi"
+
+#: engines/drascula/saveload.cpp:47
+msgid ""
+"ScummVM found that you have old savefiles for Drascula that should be "
+"converted.\n"
+"The old save game format is no longer supported, so you will not be able to "
+"load your games if you don't convert them.\n"
+"\n"
+"Press OK to convert them now, otherwise you will be asked again the next "
+"time you start the game.\n"
+msgstr ""
+"ScummVM Faxian Nin You Jiu de Drascula de Cundang Wenjian Xuyao Bei "
+"Zhuanhuan.\n"
+"Jiude cundang Wenjian Buzai Zhichi, Suoyi Nin Buneng Guo zai Zhuanhuan "
+"Zhiqian Duqu.\n"
+"Dianji Shi Lai Xianzai Zhuanhuan, Fouze Xiaci Qidong Youxi Shi Nin Huibei "
+"Zaici Xunwen\n"
+" \n"
+
+#: engines/dreamweb/detection.cpp:57
+msgid "Use bright palette mode"
+msgstr "Shiyong Liang Tiaoseban Moshi"
+
+#: engines/dreamweb/detection.cpp:58
+msgid "Display graphics using the game's bright palette"
+msgstr "Shiyong youxi de Liang Tiaoseban Lai Xianshi Tuxiang"
+
+#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
+msgid "Failed to load game state from file."
+msgstr "Wufa Cong Cundang Wenjian Zhong Duqu"
+
+#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/tinsel/saveload.cpp:545
+msgid "Failed to save game state to file."
+msgstr "Wufa Baocun Cundang "
+
+#: engines/gob/inter_v5.cpp:107
+msgid "Failed to delete file."
+msgstr "Wufa Shanchu Wenjian"
+
+#: engines/groovie/detection.cpp:312
+msgid "Fast movie speed"
+msgstr "Kuaisu Yingpian"
+
+#: engines/groovie/detection.cpp:313
+msgid "Play movies at an increased speed"
+msgstr "Yong Gengkuai de Sudu Bofang Yingpian"
+
+#: engines/groovie/script.cpp:408
+msgid "Failed to save game"
+msgstr "Wufa baocun Youxi"
+
+#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
+msgid "Gore Mode"
+msgstr "Gore Moshi"
+
+#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
+msgid "Enable Gore Mode when available"
+msgstr "Dang Kexing Shi Qiyong Gore Moshi"
+
+#. I18N: Studio audience adds an applause and cheering sounds whenever
+#. Malcolm makes a joke.
+#: engines/kyra/detection.cpp:62
+msgid "Studio audience"
+msgstr "Luyinpeng Guanzhong"
+
+#: engines/kyra/detection.cpp:63
+msgid "Enable studio audience"
+msgstr "Qiyong Luyinpeng Guanzhong"
+
+#. I18N: This option allows the user to skip text and cutscenes.
+#: engines/kyra/detection.cpp:73
+msgid "Skip support"
+msgstr "Zhichi Tiaoguo"
+
+#: engines/kyra/detection.cpp:74
+msgid "Allow text and cutscenes to be skipped"
+msgstr "Zhichi Wenzi he Changjing Bei Tiaoguo"
+
+#. I18N: Helium mode makes people sound like they've inhaled Helium.
+#: engines/kyra/detection.cpp:84
+msgid "Helium mode"
+msgstr "Haiqi Moshi"
+
+#: engines/kyra/detection.cpp:85
+msgid "Enable helium mode"
+msgstr "Shiyong Haiqi Moshi"
+
+#. I18N: When enabled, this option makes scrolling smoother when
+#. changing from one screen to another.
+#: engines/kyra/detection.cpp:99
+msgid "Smooth scrolling"
+msgstr "Pinghua Gundong"
+
+#: engines/kyra/detection.cpp:100
+msgid "Enable smooth scrolling when walking"
+msgstr "Qiyong Zoulu Shi de pinghua Gundong"
+
+#. I18N: When enabled, this option changes the cursor when it floats to the
+#. edge of the screen to a directional arrow. The player can then click to
+#. walk towards that direction.
+#: engines/kyra/detection.cpp:112
+msgid "Floating cursors"
+msgstr "Xuanfu Guangbiao"
+
+#: engines/kyra/detection.cpp:113
+msgid "Enable floating cursors"
+msgstr "Qiyong Xuanfu Guangbiao"
+
+#. I18N: HP stands for Hit Points
+#: engines/kyra/detection.cpp:127
+msgid "HP bar graphs"
+msgstr "HP Tiao Tu"
+
+#: engines/kyra/detection.cpp:128
+msgid "Enable hit point bar graphs"
+msgstr "Qiyong Jida Dian Tiao Tu"
+
+#: engines/kyra/lol.cpp:478
+msgid "Attack 1"
+msgstr "Gongji 1"
+
+#: engines/kyra/lol.cpp:479
+msgid "Attack 2"
+msgstr "Gongji 2"
+
+#: engines/kyra/lol.cpp:480
+msgid "Attack 3"
+msgstr "Gongji 3"
+
+#: engines/kyra/lol.cpp:481
+msgid "Move Forward"
+msgstr "Xiangqian Yidong"
+
+#: engines/kyra/lol.cpp:482
+msgid "Move Back"
+msgstr "Xinaghou Yidong"
+
+#: engines/kyra/lol.cpp:483
+msgid "Slide Left"
+msgstr "Xiangzuo Huadong"
+
+#: engines/kyra/lol.cpp:484
+msgid "Slide Right"
+msgstr "Xiangyou Huadong"
+
+#: engines/kyra/lol.cpp:485 engines/pegasus/pegasus.cpp:2509
+msgid "Turn Left"
+msgstr "Zuozhuan"
+
+#: engines/kyra/lol.cpp:486 engines/pegasus/pegasus.cpp:2510
+msgid "Turn Right"
+msgstr "Youzhuan"
+
+#: engines/kyra/lol.cpp:487
+msgid "Rest"
+msgstr "Xiuxi"
+
+#: engines/kyra/lol.cpp:488
+msgid "Options"
+msgstr "Xuanxiang"
+
+#: engines/kyra/lol.cpp:489
+msgid "Choose Spell"
+msgstr "Xuanze Pinxie"
+
+#: engines/kyra/sound_midi.cpp:477
+msgid ""
+"You appear to be using a General MIDI device,\n"
+"but your game only supports Roland MT32 MIDI.\n"
+"We try to map the Roland MT32 instruments to\n"
+"General MIDI ones. It is still possible that\n"
+"some tracks sound incorrect."
+msgstr ""
+"Nin Sihu zhengzai shiyong yige Tongyong MIDI Shebei\n"
+"Danshi Nin de Youxi jinzhichi Roland MT32 MIDI.\n"
+"Women zhengzai changshi JIang Roland MT32 Yingshe\n"
+"wei Tongyong MIDI. Youxie YIngui Rengran Youkeneng\n"
+"Bu zheng que."
+
+#: engines/kyra/saveload_eob.cpp:557
+#, c-format
+msgid ""
+"The following original save game file has been found in your game path:\n"
+"\n"
+"%s %s\n"
+"\n"
+"Do you wish to use this save game file with ScummVM?\n"
+"\n"
+msgstr ""
+"Xialie Yuanshi Cundang Wenjian Zai Nin de Youxi Lujing Zhong:\n"
+"\n"
+"%s %s\n"
+"\n"
+"Nin Xiwang Shiyong Zhege ScummVM Cundang Wenjian ma?\n"
+"\n"
+
+#: engines/kyra/saveload_eob.cpp:590
+#, c-format
+msgid ""
+"A save game file was found in the specified slot %d. Overwrite?\n"
+"\n"
+msgstr ""
+"Zai Cundang %d Zhong Yifaxian Baocun de Youxi WEnjian. Fugai Ma?\n"
+"\n"
+
+#: engines/kyra/saveload_eob.cpp:623
+#, c-format
+msgid ""
+"%d original save game files have been successfully imported into\n"
+"ScummVM. If you want to manually import original save game files later you "
+"will\n"
+"need to open the ScummVM debug console and use the command "
+"'import_savefile'.\n"
+"\n"
+msgstr ""
+"%d Ge yuanshi Cundang Youxi Wenjian Chenggong Daoru Daole\n"
+"ScummVM. Ruguo Nin Xinag Zhihou Rengong Daoru Cundang Wenjian, Nin Xuyao\n"
+"Dagai ScummVM Tiaoshi Kongzhitai, Bingqie shiyong mingling "
+"'import_savefile'.\n"
+"\n"
+
+#. I18N: Option for fast scene switching
+#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+msgid "~Z~ip Mode Activated"
+msgstr "~Z~Yasuo Moshi Qidong"
+
+#: engines/mohawk/dialogs.cpp:93
+msgid "~T~ransitions Enabled"
+msgstr "~T~Qiyong Zhuanyi"
+
+#. I18N: Drop book page
+#: engines/mohawk/dialogs.cpp:95
+msgid "~D~rop Page"
+msgstr "~D~shanchu Yemian"
+
+#: engines/mohawk/dialogs.cpp:99
+msgid "~S~how Map"
+msgstr "~S~Xianshi Ditu"
+
+#: engines/mohawk/dialogs.cpp:105
+msgid "~M~ain Menu"
+msgstr "~M~Zhucaidan"
+
+#: engines/mohawk/dialogs.cpp:168
+msgid "~W~ater Effect Enabled"
+msgstr "~W~Qiyong Shuimian Xiaoguo"
+
+#: engines/neverhood/detection.cpp:167
+msgid "Skip the Hall of Records storyboard scenes"
+msgstr "Tiaoguo Hall of Records Jishiban Changjing"
+
+#: engines/neverhood/detection.cpp:168
+msgid "Allows the player to skip past the Hall of Records storyboard scenes"
+msgstr "Yunxu Wanjia Tiaoguo Hall of Records Jishiban Changjing"
+
+#: engines/neverhood/detection.cpp:174
+msgid "Scale the making of videos to full screen"
+msgstr "Fangda Shipin Zhizuo Dao Quanping"
+
+#: engines/neverhood/detection.cpp:175
+msgid "Scale the making of videos, so that they use the whole screen"
+msgstr "Suofang Shipin Zhizuo, Quanping Ke Yong"
+
+#: engines/parallaction/saveload.cpp:133
+#, c-format
+msgid ""
+"Can't save game in slot %i\n"
+"\n"
+msgstr ""
+"Wufa Baocun Youxi Dao Kongwei %i\n"
+"\n"
+
+#: engines/parallaction/saveload.cpp:197
+msgid "Load file"
+msgstr "Zairu Wenjian"
+
+#: engines/parallaction/saveload.cpp:204
+msgid "Loading game..."
+msgstr "Zairu youxi..."
+
+#: engines/parallaction/saveload.cpp:212
+msgid "Save file"
+msgstr "Baocun Wenjian"
+
+#: engines/parallaction/saveload.cpp:219
+msgid "Saving game..."
+msgstr "Baocun Youxi..."
+
+#: engines/parallaction/saveload.cpp:272
+msgid ""
+"ScummVM found that you have old savefiles for Nippon Safes that should be "
+"renamed.\n"
+"The old names are no longer supported, so you will not be able to load your "
+"games if you don't convert them.\n"
+"\n"
+"Press OK to convert them now, otherwise you will be asked next time.\n"
+msgstr ""
+"ScummVM Faxian Youyixie Nippon Safes de Cundang Wenjian xuyao Gaiming.\n"
+"Yuanlai de wenjianming Buzai Bei Zhichi, Ruguo Bujing Zhuanhuan Ninjing "
+"Buneng Zairu Tamen.\n"
+"Dianji Queding Lai Xianzai Zhuanhuan, Fouze Nin Hui zai Xiaci Bei Xunwen\n"
+
+#: engines/parallaction/saveload.cpp:319
+msgid "ScummVM successfully converted all your savefiles."
+msgstr "ScummVM Chenggong Zhuanhuan le Nin de Suoyou Cundang Wenjian."
+
+#: engines/parallaction/saveload.cpp:321
+msgid ""
+"ScummVM printed some warnings in your console window and can't guarantee all "
+"your files have been converted.\n"
+"\n"
+"Please report to the team."
+msgstr ""
+"ScummVM zai Kongzhitai Zhong Youyixie Jinggai, Bingqie Women Buneng Baozheng "
+"Suoyou de wenjian doubei zhuanhuan\n"
+".\n"
+"\n"
+"QIng Jiang Qingkuang Baogao Gei Tuandui."
+
+#: engines/pegasus/pegasus.cpp:714
+msgid "Invalid save file name"
+msgstr "Wuxiao Baocun Wenjianming"
+
+#: engines/pegasus/pegasus.cpp:2507
+msgid "Up/Zoom In/Move Forward/Open Doors"
+msgstr "Xiangshang/fangda/Qianjin/Kaimen"
+
+#: engines/pegasus/pegasus.cpp:2508
+msgid "Down/Zoom Out"
+msgstr "Xiangxia/Suoxiao"
+
+#: engines/pegasus/pegasus.cpp:2511
+msgid "Display/Hide Inventory Tray"
+msgstr "Xianshi/Yincang Wupinlan"
+
+#: engines/pegasus/pegasus.cpp:2512
+msgid "Display/Hide Biochip Tray"
+msgstr "Xianshi/Yincang Biochip Lan"
+
+#: engines/pegasus/pegasus.cpp:2513
+msgid "Action/Select"
+msgstr "Dongzuo/Xuanze"
+
+#: engines/pegasus/pegasus.cpp:2514
+msgid "Toggle Center Data Display"
+msgstr "Qiehuan Shuju Zhongxin Xianshi"
+
+#: engines/pegasus/pegasus.cpp:2515
+msgid "Display/Hide Info Screen"
+msgstr "Xianshi/Yincang Xinxi Pingmu"
+
+#: engines/pegasus/pegasus.cpp:2516
+msgid "Display/Hide Pause Menu"
+msgstr "Xianshi/Yincang Zanting Caidan"
+
+#: engines/queen/detection.cpp:56
+msgid "Alternative intro"
+msgstr "QIta Jieshao"
+
+#: engines/queen/detection.cpp:57
+msgid "Use an alternative game intro (CD version only)"
+msgstr "Shiyong Qita Youxi Jieshao (Jin CD Ban)"
+
+#: engines/sci/detection.cpp:374
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr "Tiaoguo EGA Doudong (quancai Beijing)"
+
+#: engines/sci/detection.cpp:375
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr "tiaoguo EGA Youxi Zhong de Doudong, Tuxiang Yi Quancai Xianshi"
+
+#: engines/sci/detection.cpp:384
+msgid "Enable high resolution graphics"
+msgstr "QIyong Gaofenbianlv Tu"
+
+#: engines/sci/detection.cpp:385
+msgid "Enable high resolution graphics/content"
+msgstr "Qiyong Gaofenbianlv Tubian/Neirong"
+
+#: engines/sci/detection.cpp:394
+msgid "Prefer digital sound effects"
+msgstr "Youxianshiyong Shuzi Yinxiao"
+
+#: engines/sci/detection.cpp:395
+msgid "Prefer digital sound effects instead of synthesized ones"
+msgstr "Youxian SHiyong shuzi YInxiao, er fei Hecheng"
+
+#: engines/sci/detection.cpp:414
+msgid "Use IMF/Yamaha FB-01 for MIDI output"
+msgstr "Shiyong IMF/yamaha Fb-01 Huo MIDI shuchu"
+
+#: engines/sci/detection.cpp:415
+msgid ""
+"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
+"output"
+msgstr ""
+"Shiyong IBM Music Feature Ka Huozhe Yamaha FB-01 FM hecheng Mokuai zuowei "
+"MIDI shuchu"
+
+#: engines/sci/detection.cpp:425
+msgid "Use CD audio"
+msgstr "Shiyong CD YInpin"
+
+#: engines/sci/detection.cpp:426
+msgid "Use CD audio instead of in-game audio, if available"
+msgstr "Shiyong CD Yinpin erfei Youxinei Yinpin (ruguo keyong)"
+
+#: engines/sci/detection.cpp:436
+msgid "Use Windows cursors"
+msgstr "Shiyong WIndows Guangbiao"
+
+#: engines/sci/detection.cpp:437
+msgid ""
+"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
+msgstr "Shiyong Windows Guangbiao (gengxiao Danse) erfei DOS Guangbiao"
+
+#: engines/sci/detection.cpp:447
+msgid "Use silver cursors"
+msgstr "Shiyong Yinse Guangbiao"
+
+#: engines/sci/detection.cpp:448
+msgid ""
+"Use the alternate set of silver cursors, instead of the normal golden ones"
+msgstr "Shiyong Qita Yinse Guangbiao"
+
+#: engines/scumm/dialogs.cpp:176
+#, c-format
+msgid "Insert Disk %c and Press Button to Continue."
+msgstr "Charu Guangpan %c Bing An Anniu YI jixu"
+
+#: engines/scumm/dialogs.cpp:177
+#, c-format
+msgid "Unable to Find %s, (%c%d) Press Button."
+msgstr "Wufa zhaodao %s, (%c%d) Qing an anniu."
+
+#: engines/scumm/dialogs.cpp:178
+#, c-format
+msgid "Error reading disk %c, (%c%d) Press Button."
+msgstr "Duqu Guangpan %c Cuowu, (%c%d) Qing An Anniu."
+
+#: engines/scumm/dialogs.cpp:179
+msgid "Game Paused. Press SPACE to Continue."
+msgstr "Youxi Zanting. An Kongge Yi jixu."
+
+#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
+#. "Moechten Sie wirklich neu starten? (J/N)J"
+#. Will react to J as 'Yes'
+#: engines/scumm/dialogs.cpp:183
+msgid "Are you sure you want to restart? (Y/N)Y"
+msgstr "NinQueding Yao Chongqi ma? (Y/N)Y"
+
+#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
+#: engines/scumm/dialogs.cpp:185
+msgid "Are you sure you want to quit? (Y/N)Y"
+msgstr "NinQueding Yao Tuichu Ma? (Y/N)Y"
+
+#: engines/scumm/dialogs.cpp:190
+msgid "Play"
+msgstr "Kaishi"
+
+#: engines/scumm/dialogs.cpp:194
+msgid "Insert save/load game disk"
+msgstr "Charu Cundang/Duqu youxi Guangpan"
+
+#: engines/scumm/dialogs.cpp:195
+msgid "You must enter a name"
+msgstr "Nin bixu Shuru Yige Mingcheng"
+
+#: engines/scumm/dialogs.cpp:196
+msgid "The game was NOT saved (disk full?)"
+msgstr "Youxi Meiyou Baocun (Cipan Kongjian YIman?)"
+
+#: engines/scumm/dialogs.cpp:197
+msgid "The game was NOT loaded"
+msgstr "Youxi Meiyou Jiazai"
+
+#: engines/scumm/dialogs.cpp:198
+#, c-format
+msgid "Saving '%s'"
+msgstr "Baocun '%s'"
+
+#: engines/scumm/dialogs.cpp:199
+#, c-format
+msgid "Loading '%s'"
+msgstr "Zairu '%s'"
+
+#: engines/scumm/dialogs.cpp:200
+msgid "Name your SAVE game"
+msgstr "Wei baocun Youxi Qiming"
+
+#: engines/scumm/dialogs.cpp:201
+msgid "Select a game to LOAD"
+msgstr "Qing Xuanze Yige Youxi Jiazai"
+
+#: engines/scumm/dialogs.cpp:202
+msgid "Game title)"
+msgstr "Youxi Biaoti)"
+
+#. I18N: Previous page button
+#: engines/scumm/dialogs.cpp:288
+msgid "~P~revious"
+msgstr "~P~Shangyige"
+
+#. I18N: Next page button
+#: engines/scumm/dialogs.cpp:290
+msgid "~N~ext"
+msgstr "~N~Xiayige"
+
+#: engines/scumm/dialogs.cpp:602
+msgid "Speech Only"
+msgstr "Jin Yuyin"
+
+#: engines/scumm/dialogs.cpp:603
+msgid "Speech and Subtitles"
+msgstr "Yuyin he Zimu"
+
+#: engines/scumm/dialogs.cpp:604
+msgid "Subtitles Only"
+msgstr "Jin Zimu"
+
+#: engines/scumm/dialogs.cpp:612
+msgctxt "lowres"
+msgid "Speech & Subs"
+msgstr "Yuyin He Zimu"
+
+#: engines/scumm/dialogs.cpp:658
+msgid "Select a Proficiency Level."
+msgstr "Qing Xuanze Shulian Dengji"
+
+#: engines/scumm/dialogs.cpp:660
+msgid "Refer to your Loom(TM) manual for help."
+msgstr "Qingchayue Loom(TM) Shouce Huoqu Bangzhu."
+
+#: engines/scumm/dialogs.cpp:664
+msgid "Practice"
+msgstr "Lianxi"
+
+#: engines/scumm/dialogs.cpp:665
+msgid "Expert"
+msgstr "Zhuanjia"
+
+#: engines/scumm/help.cpp:74
+msgid "Common keyboard commands:"
+msgstr "Changyong Jianpan Mingling:"
+
+#: engines/scumm/help.cpp:75
+msgid "Save / Load dialog"
+msgstr "Baocun/Zairu Duihua"
+
+#: engines/scumm/help.cpp:77
+msgid "Skip line of text"
+msgstr "Tiaoguo cihang wenben"
+
+#: engines/scumm/help.cpp:78
+msgid "Esc"
+msgstr "Esc"
+
+#: engines/scumm/help.cpp:78
+msgid "Skip cutscene"
+msgstr "Tiaoguo Guochang"
+
+#: engines/scumm/help.cpp:79
+msgid "Space"
+msgstr "Kongge"
+
+#: engines/scumm/help.cpp:79
+msgid "Pause game"
+msgstr "Zanting Youxi"
+
+#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:85
+#: engines/scumm/help.cpp:96 engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98 engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100 engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102 engines/scumm/help.cpp:103
+msgid "Ctrl"
+msgstr "Ctrl"
+
+#: engines/scumm/help.cpp:80
+msgid "Load game state 1-10"
+msgstr "Zairu Youxi Cundang 1-10"
+
+#: engines/scumm/help.cpp:81 engines/scumm/help.cpp:85
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102 engines/scumm/help.cpp:103
+msgid "Alt"
+msgstr "Alt"
+
+#: engines/scumm/help.cpp:81
+msgid "Save game state 1-10"
+msgstr "Baocun Youxi Cundang 1-10"
+
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
+msgid "Enter"
+msgstr "Huiche"
+
+#: engines/scumm/help.cpp:88
+msgid "Music volume up / down"
+msgstr "Yinyue YInliang Gao/Di"
+
+#: engines/scumm/help.cpp:89
+msgid "Text speed slower / faster"
+msgstr "Wenben Sudu Man/Kuai"
+
+#: engines/scumm/help.cpp:90
+msgid "Simulate left mouse button"
+msgstr "Moni Shubiao Zuojian"
+
+#: engines/scumm/help.cpp:91
+msgid "Tab"
+msgstr "Tab"
+
+#: engines/scumm/help.cpp:91
+msgid "Simulate right mouse button"
+msgstr "Moni Shubiao Youjian"
+
+#: engines/scumm/help.cpp:94
+msgid "Special keyboard commands:"
+msgstr "Jianpan Teshu MIngling:"
+
+#: engines/scumm/help.cpp:95
+msgid "Show / Hide console"
+msgstr "Xianshi/YIncang Kongzhitai"
+
+#: engines/scumm/help.cpp:96
+msgid "Start the debugger"
+msgstr "Yunxing Tiaoshiqi"
+
+#: engines/scumm/help.cpp:97
+msgid "Show memory consumption"
+msgstr "Xianshi Neicun xioahao"
+
+#: engines/scumm/help.cpp:98
+msgid "Run in fast mode (*)"
+msgstr "zai Kuaisu Moshi Zhong YUnxing (*)"
+
+#: engines/scumm/help.cpp:99
+msgid "Run in really fast mode (*)"
+msgstr "Zai Chaokuai Moshi XIa yunxing(*)"
+
+#: engines/scumm/help.cpp:100
+msgid "Toggle mouse capture"
+msgstr "Qiehuan Shubiao buzhuo"
+
+#: engines/scumm/help.cpp:101
+msgid "Switch between graphics filters"
+msgstr "QIehuan Tuxiang Guolvqi"
+
+#: engines/scumm/help.cpp:102
+msgid "Increase / Decrease scale factor"
+msgstr "Zengjia / Jianshao suofang Yinzi"
+
+#: engines/scumm/help.cpp:103
+msgid "Toggle aspect-ratio correction"
+msgstr "Qiehuan bili Jiaozheng"
+
+#: engines/scumm/help.cpp:108
+msgid "* Note that using ctrl-f and"
+msgstr "* Zhuyi Ctrl-f He"
+
+#: engines/scumm/help.cpp:109
+msgid " ctrl-g are not recommended"
+msgstr " Ctrl-g BIngbu zhichi"
+
+#: engines/scumm/help.cpp:110
+msgid " since they may cause crashes"
+msgstr " Yinwei Keneng zaocheng cuowu"
+
+#: engines/scumm/help.cpp:111
+msgid " or incorrect game behavior."
+msgstr " Huo Buzhengque de Youxi xingwei"
+
+#: engines/scumm/help.cpp:115
+msgid "Spinning drafts on the keyboard:"
+msgstr "Jianpanshang xuanzhuan Zaogao:"
+
+#: engines/scumm/help.cpp:117
+msgid "Main game controls:"
+msgstr "Youxi zhuyao Kongzhi:"
+
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
+msgid "Push"
+msgstr "Tui"
+
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
+msgid "Pull"
+msgstr "La"
+
+#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
+#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:198
+#: engines/scumm/help.cpp:208
+msgid "Give"
+msgstr "gei"
+
+#: engines/scumm/help.cpp:125 engines/scumm/help.cpp:140
+#: engines/scumm/help.cpp:165 engines/scumm/help.cpp:191
+#: engines/scumm/help.cpp:209
+msgid "Open"
+msgstr "Dakai"
+
+#: engines/scumm/help.cpp:127
+msgid "Go to"
+msgstr "Qudao"
+
+#: engines/scumm/help.cpp:128
+msgid "Get"
+msgstr "Dedao"
+
+#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:153
+#: engines/scumm/help.cpp:171 engines/scumm/help.cpp:199
+#: engines/scumm/help.cpp:214 engines/scumm/help.cpp:225
+#: engines/scumm/help.cpp:251
+msgid "Use"
+msgstr "Shiyong"
+
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
+msgid "Read"
+msgstr "du"
+
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
+msgid "New kid"
+msgstr "Xin kid"
+
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
+msgid "Turn on"
+msgstr "DaKai"
+
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
+msgid "Turn off"
+msgstr "Guanbi"
+
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
+msgid "Walk to"
+msgstr "Zouxiang"
+
+#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:228
+msgid "Pick up"
+msgstr "Jianqi"
+
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
+msgid "What is"
+msgstr "Shenme"
+
+#: engines/scumm/help.cpp:147
+msgid "Unlock"
+msgstr "Jiesuo"
+
+#: engines/scumm/help.cpp:150
+msgid "Put on"
+msgstr "Chuanshang"
+
+#: engines/scumm/help.cpp:151
+msgid "Take off"
+msgstr "Tuoxia"
+
+#: engines/scumm/help.cpp:157
+msgid "Fix"
+msgstr "Xiufu"
+
+#: engines/scumm/help.cpp:159
+msgid "Switch"
+msgstr "Qiehuan"
+
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
+msgid "Look"
+msgstr "Kan"
+
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
+msgid "Talk"
+msgstr "Shuohua"
+
+#: engines/scumm/help.cpp:175
+msgid "Travel"
+msgstr "LvXing"
+
+#: engines/scumm/help.cpp:176
+msgid "To Henry / To Indy"
+msgstr "Gei Henry/ Gei Indy"
+
+#. I18N: These are different musical notes
+#: engines/scumm/help.cpp:180
+msgid "play C minor on distaff"
+msgstr "Yanzou C Xiaodiao"
+
+#: engines/scumm/help.cpp:181
+msgid "play D on distaff"
+msgstr "Yanzou D"
+
+#: engines/scumm/help.cpp:182
+msgid "play E on distaff"
+msgstr "Yanzou E"
+
+#: engines/scumm/help.cpp:183
+msgid "play F on distaff"
+msgstr "Yanozu F"
+
+#: engines/scumm/help.cpp:184
+msgid "play G on distaff"
+msgstr "Yanzou G"
+
+#: engines/scumm/help.cpp:185
+msgid "play A on distaff"
+msgstr "Yanzou A"
+
+#: engines/scumm/help.cpp:186
+msgid "play B on distaff"
+msgstr "Yanzou B"
+
+#: engines/scumm/help.cpp:187
+msgid "play C major on distaff"
+msgstr "Yanzou C Dadiao"
+
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+msgid "puSh"
+msgstr "Tui"
+
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
+msgid "pull (Yank)"
+msgstr "La"
+
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
+msgid "Talk to"
+msgstr "Shuohua"
+
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
+msgid "Look at"
+msgstr "Kanxiang"
+
+#: engines/scumm/help.cpp:201
+msgid "turn oN"
+msgstr "Dakai"
+
+#: engines/scumm/help.cpp:202
+msgid "turn oFf"
+msgstr "Guanbi"
+
+#: engines/scumm/help.cpp:218
+msgid "KeyUp"
+msgstr "TaiqiAnjian"
+
+#: engines/scumm/help.cpp:218
+msgid "Highlight prev dialogue"
+msgstr "Gaoliang Zhiqian Duihua"
+
+#: engines/scumm/help.cpp:219
+msgid "KeyDown"
+msgstr "AnxiaAnjian"
+
+#: engines/scumm/help.cpp:219
+msgid "Highlight next dialogue"
+msgstr "Gaoliang Zhihou Duihua"
+
+#: engines/scumm/help.cpp:223
+msgid "Walk"
+msgstr "Zou"
+
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
+msgid "Inventory"
+msgstr "Wupin"
+
+#: engines/scumm/help.cpp:227
+msgid "Object"
+msgstr "Dongxi"
+
+#: engines/scumm/help.cpp:230
+msgid "Black and White / Color"
+msgstr "Heibai / Caise"
+
+#: engines/scumm/help.cpp:233
+msgid "Eyes"
+msgstr "yanjing"
+
+#: engines/scumm/help.cpp:234
+msgid "Tongue"
+msgstr "Shetou"
+
+#: engines/scumm/help.cpp:236
+msgid "Punch"
+msgstr "Quantou"
+
+#: engines/scumm/help.cpp:237
+msgid "Kick"
+msgstr "Ti"
+
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
+msgid "Examine"
+msgstr "Jiancha"
+
+#: engines/scumm/help.cpp:241
+msgid "Regular cursor"
+msgstr "Putong Guangbiao"
+
+#. I18N: Comm is a communication device
+#: engines/scumm/help.cpp:244
+msgid "Comm"
+msgstr "Tongxin"
+
+#: engines/scumm/help.cpp:247
+msgid "Save / Load / Options"
+msgstr "Baocun / Zairu / Xuanxiang"
+
+#: engines/scumm/help.cpp:256
+msgid "Other game controls:"
+msgstr "QIta youxi Kongzhi:"
+
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
+msgid "Inventory:"
+msgstr "Wupin:"
+
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+msgid "Scroll list up"
+msgstr "LIebiao Shanghua"
+
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
+msgid "Scroll list down"
+msgstr "LIebiao Xiahua"
+
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
+msgid "Upper left item"
+msgstr "Zuoshang Wupin"
+
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+msgid "Lower left item"
+msgstr "Zuoxia Wupin"
+
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
+msgid "Upper right item"
+msgstr "Youshang Wupin"
+
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
+msgid "Lower right item"
+msgstr "Youxia Wupin"
+
+#: engines/scumm/help.cpp:270
+msgid "Middle left item"
+msgstr "Zhongzuo Wupin"
+
+#: engines/scumm/help.cpp:273
+msgid "Middle right item"
+msgstr "Zhongyou Wupin"
+
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
+msgid "Switching characters:"
+msgstr "Qiehuan Juese"
+
+#: engines/scumm/help.cpp:282
+msgid "Second kid"
+msgstr "Dierge Kid"
+
+#: engines/scumm/help.cpp:283
+msgid "Third kid"
+msgstr "Disange Kid"
+
+#: engines/scumm/help.cpp:292
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Qiehuan Wupin/IQ Dian Xianshi"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr "Qiehuan JInapan/Shubiao Zhandou (*)"
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr "* Jianpan Zhandou zongshi Kaiqi,"
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr " Suoyi Hulue youxi nei xinxi"
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr " Zhe shiji shang shi Zai qiehuan Shubiao Zhandou de Kaiguan"
+
+#: engines/scumm/help.cpp:304
+msgid "Fighting controls (numpad):"
+msgstr "Zhandou Kongzhi (zhuzijianpan):"
+
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
+msgid "Step back"
+msgstr "Shangyibu"
+
+#: engines/scumm/help.cpp:308
+msgid "Block high"
+msgstr "Zudang Gaochu"
+
+#: engines/scumm/help.cpp:309
+msgid "Block middle"
+msgstr "Zudang Zhongjian"
+
+#: engines/scumm/help.cpp:310
+msgid "Block low"
+msgstr "Zudang Dichu"
+
+#: engines/scumm/help.cpp:311
+msgid "Punch high"
+msgstr "Quanda Gaochu"
+
+#: engines/scumm/help.cpp:312
+msgid "Punch middle"
+msgstr "Quanda Zhongjian"
+
+#: engines/scumm/help.cpp:313
+msgid "Punch low"
+msgstr "Quanda Dichu"
+
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr "Sucker Punch"
+
+#: engines/scumm/help.cpp:318
+msgid "These are for Indy on left."
+msgstr "Weile zai Zuobian de Indy"
+
+#: engines/scumm/help.cpp:319
+msgid "When Indy is on the right,"
+msgstr "Dnag Indy Zai Youbian Shi,"
+
+#: engines/scumm/help.cpp:320
+msgid "7, 4, and 1 are switched with"
+msgstr "7, 4 He 1 Fenbie keyi Yong"
+
+#: engines/scumm/help.cpp:321
+msgid "9, 6, and 3, respectively."
+msgstr "9, 6, 3 Laiqiehuan."
+
+#: engines/scumm/help.cpp:328
+msgid "Biplane controls (numpad):"
+msgstr "Shuangmian Kongzhi (shuzijianpan):"
+
+#: engines/scumm/help.cpp:329
+msgid "Fly to upper left"
+msgstr "Feiwang Zuoshang"
+
+#: engines/scumm/help.cpp:330
+msgid "Fly to left"
+msgstr "Feiwang Zuobian"
+
+#: engines/scumm/help.cpp:331
+msgid "Fly to lower left"
+msgstr "Feiwang Zuoxia"
+
+#: engines/scumm/help.cpp:332
+msgid "Fly upwards"
+msgstr "Xinagshang Fei"
+
+#: engines/scumm/help.cpp:333
+msgid "Fly straight"
+msgstr "Zhifei"
+
+#: engines/scumm/help.cpp:334
+msgid "Fly down"
+msgstr "Xiangxia Fei"
+
+#: engines/scumm/help.cpp:335
+msgid "Fly to upper right"
+msgstr "Feiwang YouShang"
+
+#: engines/scumm/help.cpp:336
+msgid "Fly to right"
+msgstr "Feiwang Youbian"
+
+#: engines/scumm/help.cpp:337
+msgid "Fly to lower right"
+msgstr "Feiwang Youxia"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll on"
+msgstr "Snap hundong kai"
+
+#: engines/scumm/input.cpp:582
+msgid "Snap scroll off"
+msgstr "Snap Gundong Guan"
+
+#: engines/scumm/input.cpp:595
+msgid "Music volume: "
+msgstr "Yinyue Yinliang:"
+
+#: engines/scumm/input.cpp:612
+msgid "Subtitle speed: "
+msgstr "Zimu Sudu:"
+
+#: engines/scumm/scumm.cpp:1832
+#, c-format
+msgid ""
+"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
+"but %s is missing. Using AdLib instead."
+msgstr ""
+"Bendi MIDI Zhichi Xuyao Cong LucasArts Shengji Zhi Roland,\n"
+"Dnahsi %s meiyou zhaodao. Shiyong AdLib."
+
+#: engines/scumm/scumm.cpp:2644
+msgid ""
+"Usually, Maniac Mansion would start now. But for that to work, the game "
+"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
+"Tentacle game directory, and the game has to be added to ScummVM."
+msgstr ""
+"Tongchang, Maniac mansion Huizai XIanzai kaishi. Raner, Manian mansion De "
+"youxi Wenjian Xuyao zai 'maniac'Mulu Nei , weiyu Tentacle Youxi Mulu, Ci "
+"Youxi Xuyao Bei tianjia dao ScummVM Zhong."
+
+#: engines/scumm/players/player_v3m.cpp:129
+msgid ""
+"Could not find the 'Loom' Macintosh executable to read the\n"
+"instruments from. Music will be disabled."
+msgstr ""
+"Wufa Zhaodao 'Loom' Macintosh Chengxu lai\n"
+" Duru Yinyue. Yinyue Huibei Jinyong."
+
+#: engines/scumm/players/player_v5m.cpp:107
+msgid ""
+"Could not find the 'Monkey Island' Macintosh executable to read the\n"
+"instruments from. Music will be disabled."
+msgstr ""
+"Wufa Zhaodao 'monkey Island' Macintosh Chengxu lai Duru YInyue. yinyue "
+"Huibei Jinyong."
+
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "Shiyong Yuanshi Youxi baocun Duihuakuang"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+"YouxiNei wenjian Anniu shiyong Yuanshi Youxi Duihuakuang Erfei ScummVM Caidan"
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "Xiangsuhua Changjing Qiehuan"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr "Dang Qiehuan Changjingshi, Shiyong Suiji Xiangsu zhuanhuan"
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "Dnag Yidong shubiao Shi Buyao Xianshi Redian"
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr "JInzai Dianji Redian Huo Dongzuo Anjianhou Xianshi Redianming"
+
+#: engines/sherlock/detection.cpp:101
+msgid "Show character portraits"
+msgstr "Xianshi Juese Huaxiang"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "Jiaotan Shi Xianshi Juese Huaxiang"
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr "Huadon Duigua dao SHituzhong"
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr "Jiang UI Duihuakuang Huaru Shitu, Erfei Turan Chuxian"
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "Touming Chuangkou"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "Xianshi Diayou Bantouming Beijing de Chuangkou"
+
+#: engines/sky/compact.cpp:130
+msgid ""
+"Unable to find \"sky.cpt\" file!\n"
+"Please download it from www.scummvm.org"
+msgstr ""
+"Wufa Zhaodao \"sky.cpt\" Wenjian\n"
+"Qing Cong www.cummvm.org Xiazai"
+
+#: engines/sky/compact.cpp:141
+msgid ""
+"The \"sky.cpt\" file has an incorrect size.\n"
+"Please (re)download it from www.scummvm.org"
+msgstr ""
+"Wenjian \"sky.cpt\" Chicun Cuowu.\n"
+"Qing Cong www.scummvm.org Chongxin Xiazai"
+
+#: engines/sky/detection.cpp:44
+msgid "Floppy intro"
+msgstr "Ruanpan Jieshao"
+
+#: engines/sky/detection.cpp:45
+msgid "Use the floppy version's intro (CD version only)"
+msgstr "Shiyong Ruanpan Banben JIeshao (jin CD banben)"
+
+#: engines/sword1/animation.cpp:524
+#, c-format
+msgid "PSX stream cutscene '%s' cannot be played in paletted mode"
+msgstr "PSX liu Changjing '%s' Wufa zai Tiaosiban Moshi xia Bofang"
+
+#: engines/sword1/animation.cpp:545 engines/sword2/animation.cpp:445
+msgid "DXA cutscenes found but ScummVM has been built without zlib"
+msgstr "Zhaodao DXA Guochang Danshi ScummVM Meiyou yu Zlib bianyi"
+
+#: engines/sword1/animation.cpp:561 engines/sword2/animation.cpp:461
+msgid ""
+"MPEG-2 cutscenes found but ScummVM has been built without MPEG-2 support"
+msgstr "MPEG-2 Guocheng Zhaodao Dnashi ScummVM Meiyou He MPEG-2 Zhichi Bianyi"
+
+#: engines/sword1/animation.cpp:568 engines/sword2/animation.cpp:470
+#, c-format
+msgid "Cutscene '%s' not found"
+msgstr "Guochang '%s' Weizhaodao"
+
+#: engines/sword1/control.cpp:863
+msgid ""
+"ScummVM found that you have old savefiles for Broken Sword 1 that should be "
+"converted.\n"
+"The old save game format is no longer supported, so you will not be able to "
+"load your games if you don't convert them.\n"
+"\n"
+"Press OK to convert them now, otherwise you will be asked again the next "
+"time you start the game.\n"
+msgstr ""
+"ScummVM Zhaodaole Zhiqian De Broken Sword 1 Cundang, qie YInggai Bei "
+"zhuanhuan.\n"
+"Zhiqian de cundang Geshi BUzai Zhichi, Nin Bixu Xianzhuanhuan Caineng Duqu "
+"Cundang\n"
+"Dianji Queding Lia zhuanhuancundang, Fouze NIn Huizai Xiaci Kaishi Youxi Shi "
+"bei Zaici Tishi\n"
+
+#: engines/sword1/control.cpp:1232
+#, c-format
+msgid ""
+"Target new save game already exists!\n"
+"Would you like to keep the old save game (%s) or the new one (%s)?\n"
+msgstr ""
+"Mubiao Xin Cundang Yijing Cunzai!\n"
+"Niyao Baocun jiude Cundang (%s) Haishi Xinde(%s)?\n"
+
+#: engines/sword1/control.cpp:1235
+msgid "Keep the old one"
+msgstr "Baoliu Jiude"
+
+#: engines/sword1/control.cpp:1235
+msgid "Keep the new one"
+msgstr "Baoliu Xinde"
+
+#: engines/sword1/logic.cpp:1633
+msgid "This is the end of the Broken Sword 1 Demo"
+msgstr "Zheshi Broken Sword 1 Demo de Jiewei"
+
+#: engines/sword2/animation.cpp:425
+msgid ""
+"PSX cutscenes found but ScummVM has been built without RGB color support"
+msgstr "PSX Guochang zhaodao Danshi ScmummVM Meiyou Zhichi RGB Secai Bianyi"
+
+#: engines/sword2/sword2.cpp:79
+msgid "Show object labels"
+msgstr "Xianshi Wuti Biaoqian"
+
+#: engines/sword2/sword2.cpp:80
+msgid "Show labels for objects on mouse hover"
+msgstr "Dang Shubiao Yishang Shi Xianshi Wuti Biaoqian"
+
+#: engines/teenagent/resources.cpp:95
+msgid ""
+"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
+msgstr ""
+"Zhaobudao 'teenagent.dat' Wenjian. Cong ScummVM wangzhan Shangmian Dedao"
+
+#: engines/teenagent/resources.cpp:116
+msgid ""
+"The teenagent.dat file is compressed and zlib hasn't been included in this "
+"executable. Please decompress it"
+msgstr ""
+"teenagent.dat Wenjian Yibeiyasuo Bingqie zlib Bingmeiyou Zai chengxu Zhong. "
+"Qing jieya."
+
+#: engines/wintermute/detection.cpp:58
+msgid "Show FPS-counter"
+msgstr "Xianshi FPS Jishuqi"
+
+#: engines/wintermute/detection.cpp:59
+msgid "Show the current number of frames per second in the upper left corner"
+msgstr "Zai Zuoshangjiao Xianshi Xianzai Meimiaozhong Zhenshu"
+
+#: engines/zvision/detection_tables.h:52
+msgid "Use the original save/load screens instead of the ScummVM interface"
+msgstr "Shiyong Yuanshi baocun/zairu Pingmu Erfei ScummVM jiemian"
+
+#: engines/zvision/detection_tables.h:61
+msgid "Double FPS"
+msgstr "Shuangbei FPS"
+
+#: engines/zvision/detection_tables.h:62
+msgid "Increase framerate from 30 to 60 FPS"
+msgstr "Zengjia zhenlv cong 30 dao 60 FPS"
+
+#: engines/zvision/detection_tables.h:71
+msgid "Enable Venus"
+msgstr "Qiyong Venus"
+
+#: engines/zvision/detection_tables.h:72
+msgid "Enable the Venus help system"
+msgstr "Qiyong Venus Bangzhu Xitong"
+
+#: engines/zvision/detection_tables.h:81
+msgid "Disable animation while turning"
+msgstr "zhuanxinag shi Jinyong Donghua"
+
+#: engines/zvision/detection_tables.h:82
+msgid "Disable animation while turning in panorama mode"
+msgstr "Quanjing Moshi xia Zhuanxiang shi Jinyong Donghua"
+
+#: engines/zvision/detection_tables.h:91
+msgid "Use high resolution MPEG video"
+msgstr "Shiyong Gaofenbianlv MPEG shipin"
+
+#: engines/zvision/detection_tables.h:92
+msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
+msgstr "Cong DVD Banben Zhong shiyong MPEG shipin, erfei Difenbianlv AVI"
diff --git a/ports.mk b/ports.mk
index bcdbe532d9..0eb94264de 100644
--- a/ports.mk
+++ b/ports.mk
@@ -223,6 +223,8 @@ ifneq ($(BACKEND), iphone)
ifneq ($(BACKEND), ios7)
# Static libaries, used for the scummvm-static and iphone targets
OSX_STATIC_LIBS := `$(SDLCONFIG) --static-libs`
+# With sdl2-config we don't always get the OpenGL framework
+OSX_STATIC_LIBS += -framework OpenGL
endif
endif