diff options
60 files changed, 5322 insertions, 1366 deletions
@@ -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 Binary files differindex 2378bc4e13..b0da793cdf 100644 --- a/gui/themes/translations.dat +++ b/gui/themes/translations.dat 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" @@ -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 |