diff options
583 files changed, 37609 insertions, 11453 deletions
@@ -285,6 +285,9 @@ ScummVM Team Dreamcast: Marcus Comstedt + GCW0: + Eugene Sandulenko + GPH Devices (GP2X, GP2XWiz & Caanoo): John Willis @@ -66,6 +66,7 @@ Edward Rudd Eugene Sandulenko Johannes Schickel Keith Scroggins +Tarek Soliman Won Star Ludvig Strigeus Fedor Strizhniou @@ -1,14 +1,63 @@ For a more comprehensive changelog of the latest experimental code, see: https://github.com/scummvm/scummvm/commits/ -1.8.0 (????-??-??) +1.9.0 (XXXX-XX-XX) + AGI: + - 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: - Added support for Rex Nebular and the Cosmic Gender Bender. - Added support for Sfinx. - Added support for Zork Nemesis: The Forbidden Lands. - Added support for Zork: Grand Inquisitor. - - Added support for The Lost Files of Sherlock Holmes: The Case of the Serrated Scalpel. - - Added support for The Lost Files of Sherlock Holmes: The Case of the Rose Tattoo. + - Added support for The Lost Files of Sherlock Holmes: The Case of the + Serrated Scalpel. + - Added support for The Lost Files of Sherlock Holmes: The Case of the Rose + Tattoo. - Added support for Beavis and Butthead in Virtual Stupidity. - Added support for Amazon: Guardians of Eden. - Added support for Broken Sword 2.5: The Return of the Templars. @@ -16,13 +65,13 @@ For a more comprehensive changelog of the latest experimental code, see: New Ports: - Added Raspberry Pi port. + - Added GCW0 port. General: - Updated Munt MT-32 emulation code to version 1.5.0. SDL: - - Alt-x no longer quits ScummVM on platforms exhibiting this behavior - before. A notable example is our Windows port. + - Alt-x no longer quits ScummVM. Use Cmd-q/Ctrl-q/Ctrl-z instead; see README. - On POSIX systems we now follow the XDG Base Directory Specification for placement of files for users. This effectively results in new locations for our configuration file, our log file, and our default savegame path. @@ -36,15 +85,17 @@ For a more comprehensive changelog of the latest experimental code, see: AGI: - It is now possible to disable mouse support (except for Amiga versions and fanmade games, that require a mouse). - - Fix incorrect volume attenuation in PCjr sound code (bug #6858). + - Fixed PCjr sound volumes. - Major rewrite of graphics subsystem. - - Support for Apple IIgs, Amiga + Atari ST transitions, fonts and mouse cursors. - (Atari ST 8x8 system font is not included with ScummVM) - - Added ability to make for example a PC version look like an Apple IIgs version. - (includes palette, cursor, transition and even font). Just set corresponding render mode. - - Support for simplified automatic saving/restoring (used by Mixed Up Mother Goose). - - Removed forced 2 second delay on every room change, replaced with heuristic. - - Now saving controllers (key bindings by scripts) when saving games (bug #5858). + - Support for Apple IIgs, Amiga + Atari ST transitions, fonts and mouse + cursors. The Atari ST 8x8 system font is not included with ScummVM. + - Added ability to make for example a PC version look like an Apple IIgs + version. This includes palette, cursor, transition and even font. Just + set corresponding render mode. + - Fixed Apple IIgs game versions running too fast. + - Added support for automatic saving/restoring used by Mixed Up Mother Goose. + - Removed forced two second delay on room changes; replaced with heuristic. + - Fixed certain key bindings breaking after saving/reloading. AGOS: - Fixed arpeggio effect used in music of Amiga version of Elvira 1. @@ -56,11 +107,8 @@ For a more comprehensive changelog of the latest experimental code, see: output and makes it closer to the original. Broken Sword 1: - - Fix speech endianness detection on big endian systems for the Macintosh - version (bug #6720). - - Fix crash when reloading a game from the Main Menu while in the bull's - head scene (bug #6728). It may have been happening in other scenes as - well. + - Fixed Macintosh version speech when running on big endian systems. + - Fixed loading from Main Menu in bull's head scene, and maybe other scenes. CinE: - Added support for music in CD version of Future Wars. @@ -74,10 +122,12 @@ For a more comprehensive changelog of the latest experimental code, see: SCI: - Handling of music priority has been greatly improved. - A lot of fixes for original game script bugs that also occurred when - using the original interpreter. - KQ6 (Dual Mode), LSL5, QfG1 (EGA), QfG1 (VGA), QfG2, QfG3, SQ1, SQ4 (CD) + using the original interpreter. This affects the following games: + KQ6 (Dual Mode), LSL5, PQ1, QfG1 (EGA), QfG1 (VGA), QfG2, QfG3, SQ1, + SQ4 (CD). - Restoring from the ScummVM in-game menu should now work all the time. - - Improve support for Japanese PC-9801 games. + - Improved support for Japanese PC-9801 games. + - Default to hi res version of KQ6, changeable using engine option. SCUMM: - Major improvements to Korean versions text rendering. @@ -85,6 +135,7 @@ For a more comprehensive changelog of the latest experimental code, see: - It is now possible to play Maniac Mansion from within Day of the Tentacle, with a few caveats. See README for details. - Alt-x can now be used to quit SCUMM games on all platforms. + - Improved lip sync animation in later HE games. Tinsel: - Improved AdLib music support in Discworld 1. @@ -48,10 +48,10 @@ Table of Contents: 4.0) Supported Platforms 5.0) Running ScummVM * 5.1 Command Line Options - * 5.2 Language Options + * 5.2 Global Menu * 5.3 Graphics Filters - * 5.4 Global Menu - * 5.5 Hotkeys + * 5.4 Hotkeys + * 5.5 Language Options 6.0) Saved Games * 6.1 Autosaves * 6.2 Converting saved games @@ -1487,6 +1487,7 @@ other games. Ctrl-F5 - Displays the Global Menu Cmd-q - Quit (Mac OS X) Ctrl-q - Quit (other unices including Linux) + Alt-F4 - Quit (Windows) Ctrl-z - Quit (other platforms) Ctrl-u - Mute all sounds Ctrl-m - Toggle mouse capture diff --git a/audio/mods/maxtrax.cpp b/audio/mods/maxtrax.cpp index c18812ee54..f5754a5f96 100644 --- a/audio/mods/maxtrax.cpp +++ b/audio/mods/maxtrax.cpp @@ -54,7 +54,7 @@ void nullFunc(int) {} // Function to calculate 2^x, where x is a fixedpoint number with 16 fraction bits // using exp would be more accurate and needs less space if mathlibrary is already linked -// but this function should be faster and doesnt use floats +// but this function should be faster and doesn't use floats #if 1 inline uint32 pow2Fixed(int32 val) { static const uint16 tablePow2[] = { 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/events/dinguxsdl/dinguxsdl-events.cpp b/backends/events/dinguxsdl/dinguxsdl-events.cpp index cc15f2666c..0492c569e1 100644 --- a/backends/events/dinguxsdl/dinguxsdl-events.cpp +++ b/backends/events/dinguxsdl/dinguxsdl-events.cpp @@ -175,7 +175,10 @@ bool DINGUXSdlEventSource::remapKey(SDL_Event &ev, Common::Event &event) { return true; } else if (ev.key.keysym.sym == BUT_SELECT) { // virtual keyboard #ifdef ENABLE_VKEYBD - event.type = Common::EVENT_VIRTUAL_KEYBOARD; + if (ev.type == SDL_KEYDOWN) + event.type = Common::EVENT_VIRTUAL_KEYBOARD; + + return true; #endif } else if (ev.key.keysym.sym == BUT_START) { // F5, menu in some games ev.key.keysym.sym = SDLK_F5; diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp index 2b9d3aa100..21345515bc 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp @@ -127,7 +127,8 @@ SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSou #if SDL_VERSION_ATLEAST(2, 0, 0) _renderer(nullptr), _screenTexture(nullptr), _viewport(), _windowWidth(1), _windowHeight(1), -#else +#endif +#if defined(WIN32) && !SDL_VERSION_ATLEAST(2, 0, 0) _originalBitsPerPixel(0), #endif _screen(0), _tmpscreen(0), @@ -801,8 +802,9 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() { } else #endif { - // Save the original bpp to be able to restore the video mode on unload -#if !SDL_VERSION_ATLEAST(2, 0, 0) +#if defined(WIN32) && !SDL_VERSION_ATLEAST(2, 0, 0) + // Save the original bpp to be able to restore the video mode on + // unload. See _originalBitsPerPixel documentation. if (_originalBitsPerPixel == 0) { const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo(); _originalBitsPerPixel = videoInfo->vfmt->BitsPerPixel; @@ -947,9 +949,10 @@ void SurfaceSdlGraphicsManager::unloadGFXMode() { #endif DestroyScalers(); -#if !SDL_VERSION_ATLEAST(2, 0, 0) - // Reset video mode to original - // This will ensure that any new graphic manager will use the initial BPP when listing available modes +#if defined(WIN32) && !SDL_VERSION_ATLEAST(2, 0, 0) + // Reset video mode to original. + // This will ensure that any new graphic manager will use the initial BPP + // when listing available modes. See _originalBitsPerPixel documentation. if (_originalBitsPerPixel != 0) SDL_SetVideoMode(_videoMode.screenWidth, _videoMode.screenHeight, _originalBitsPerPixel, _videoMode.fullscreen ? (SDL_FULLSCREEN | SDL_SWSURFACE) : SDL_SWSURFACE); #endif diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.h b/backends/graphics/surfacesdl/surfacesdl-graphics.h index c4f7346525..25d6ff041c 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.h +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.h @@ -251,8 +251,22 @@ protected: }; VideoState _videoMode, _oldVideoMode; - // Original BPP to restore the video mode on unload +#if defined(WIN32) && !SDL_VERSION_ATLEAST(2, 0, 0) + /** + * Original BPP to restore the video mode on unload. + * + * This is required to make listing video modes for the OpenGL output work + * on Windows 8+. On these systems OpenGL modes are only available for + * 32bit formats. However, we setup a 16bit format and thus mode listings + * for OpenGL will return an empty list afterwards. + * + * In theory we might require this behavior on non-Win32 platforms too. + * However, SDL sometimes gives us invalid pixel formats for X11 outputs + * causing crashes when trying to setup the original pixel format. + * See bug #7038 "IRIX: X BadMatch when trying to start any 640x480 game". + */ uint8 _originalBitsPerPixel; +#endif /** Force full redraw on next updateScreen */ bool _forceFull; diff --git a/backends/midi/windows.cpp b/backends/midi/windows.cpp index e2b327ffa7..52a46200cb 100644 --- a/backends/midi/windows.cpp +++ b/backends/midi/windows.cpp @@ -185,6 +185,9 @@ MusicDevices WindowsMusicPlugin::getDevices() const { deviceNames.push_back(tmp.szPname); } + // Limit us to the number of actually retrieved devices. + numDevs = deviceNames.size(); + // Check for non-unique device names. This may happen if someone has devices with identical // names (e. g. more than one USB device of the exact same hardware type). It seems that this // does happen in reality sometimes. We generate index numbers for these devices. diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index d7713f99d8..f847296892 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -469,7 +469,7 @@ void OSystem_Android::updateScreen() { GLCALL(glTranslatex(0, -_shake_offset << 16, 0)); } -// TODO this doesnt work on those sucky drivers, do it differently +// TODO this doesn't work on those sucky drivers, do it differently // if (_show_overlay) // GLCALL(glColor4ub(0x9f, 0x9f, 0x9f, 0x9f)); diff --git a/backends/platform/dc/vmsave.cpp b/backends/platform/dc/vmsave.cpp index 5f5cdff24f..75fc1ed0df 100644 --- a/backends/platform/dc/vmsave.cpp +++ b/backends/platform/dc/vmsave.cpp @@ -165,30 +165,7 @@ static bool tryDelete(const char *filename, int vm) return true; } -static bool matches(const char *glob, const char *name) -{ - while(*glob) - if(*glob == '*') { - while(*glob == '*') - glob++; - do { - if((*name == *glob || *glob == '?') && - matches(glob, name)) - return true; - } while(*name++); - return false; - } else if(!*name) - return false; - else if(*glob == '?' || *glob == *name) { - glob++; - name++; - } - else - return false; - return !*name; -} - -static void tryList(const char *glob, int vm, Common::StringArray &list) +static void tryList(const Common::String &glob, int vm, Common::StringArray &list) { struct vmsinfo info; struct superblock super; @@ -205,7 +182,7 @@ static void tryList(const char *glob, int vm, Common::StringArray &list) char buf[16]; strncpy(buf, (char *)de.entry+4, 12); buf[12] = 0; - if (matches(glob, buf)) + if (Common::matchString(buf, glob.c_str())) list.push_back(buf); } } @@ -425,7 +402,7 @@ Common::StringArray VMSaveManager::listSavefiles(const Common::String &pattern) Common::StringArray list; for (int i=0; i<24; i++) - tryList(pattern.c_str(), i, list); + tryList(pattern, i, list); return list; } diff --git a/backends/platform/dingux/README.GCW0 b/backends/platform/dingux/README.GCW0 new file mode 100644 index 0000000000..1875e5323a --- /dev/null +++ b/backends/platform/dingux/README.GCW0 @@ -0,0 +1,26 @@ +[ScummVM-GCW0 README] + +Controls +======== +- Dpad/analog joy: move mouse cursor +- A: left mouse button click +- B: right mouse button click +- X: '0' key +- Y: '.' key (skips dialogue line in some engines) +- Left Trigger: open global menu +- Right Trigger: opens virtual keyboard +- Select: ESC button, scene skip in some engines +- Start: F5 key, game menu in some engines + +Installation from binaries +========================== +Copy over scummvm.opk file + +Building from binaries +====================== +It's pretty simple if you are running Linux on an x86/amd64 machine: +1. Download and install the GCW0 toolchain (http://www.gcw-zero.com/develop) +2. Download ScummVM sources and uncompress them +3. Run backends/platform/dingux/build.gcw0.sh script +4. Copy the resulting file scummvm.opk to your device +5. Enjoy diff --git a/backends/platform/dingux/build.gcw0.sh b/backends/platform/dingux/build.gcw0.sh new file mode 100755 index 0000000000..c1a4fa29c2 --- /dev/null +++ b/backends/platform/dingux/build.gcw0.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +export PATH=/opt/gcw0-toolchain/usr/bin:$PATH + +# Disable high resolution engines since we have 320x240 hardware +./configure --host=gcw0 --enable-plugins --default-dynamic --enable-release --disable-mt32emu --disable-hq-scalers && make -j6 gcw-opk && ls -l scummvm.opk diff --git a/backends/platform/dingux/dingux.mk b/backends/platform/dingux/dingux.mk index 1333e89ff8..56c26c3be1 100644 --- a/backends/platform/dingux/dingux.mk +++ b/backends/platform/dingux/dingux.mk @@ -55,6 +55,13 @@ endif $(CP) $(srcdir)/dists/gcw0/default.gcw0.desktop $(gcw0_bundle)/ $(CP) $(srcdir)/dists/gcw0/scummvmrc $(gcw0_bundle)/ $(CP) $(srcdir)/dists/gcw0/scummvm.sh $(gcw0_bundle)/ + $(CP) $(srcdir)/backends/platform/dingux/README.GCW0 $(gcw0_bundle)/README.man.txt + echo >> $(gcw0_bundle)/README.man.txt + echo '[General README]' >> $(gcw0_bundle)/README.man.txt + echo >> $(gcw0_bundle)/README.man.txt + cat README >> $(gcw0_bundle)/README.man.txt + +# $(CP) GeneralUser\ GS\ FluidSynth\ v1.44.sf2 $(gcw0_bundle)/ gcw0-opk-unstripped: $(gcw0_bundle) $(CP) $(PLUGINS) $(gcw0_bundle)/plugins/ @@ -65,3 +72,12 @@ gcw-opk: $(gcw0_bundle) $(STRIP) $(gcw0_bundle)/plugins/* $(STRIP) $(gcw0_bundle)/scummvm ./dists/gcw0/opk_make.sh -d $(gcw0_bundle) -o scummvm + +GeneralUser_GS_1.44-FluidSynth.zip: + curl -s http://www.scummvm.org/frs/extras/SoundFont/GeneralUser_GS_1.44-FluidSynth.zip -o GeneralUser_GS_1.44-FluidSynth.zip + +GeneralUser\ GS\ FluidSynth\ v1.44.sf2: GeneralUser_GS_1.44-FluidSynth.zip + unzip -n GeneralUser_GS_1.44-FluidSynth.zip + mv "GeneralUser GS 1.44 FluidSynth/GeneralUser GS FluidSynth v1.44.sf2" . + mv "GeneralUser GS 1.44 FluidSynth/README.txt" README.soundfont + mv "GeneralUser GS 1.44 FluidSynth/LICENSE.txt" LICENSE.soundfont diff --git a/backends/platform/ios7/ios7_osys_main.cpp b/backends/platform/ios7/ios7_osys_main.cpp index c1280a2969..25d9cbed15 100644 --- a/backends/platform/ios7/ios7_osys_main.cpp +++ b/backends/platform/ios7/ios7_osys_main.cpp @@ -79,6 +79,33 @@ AQCallbackStruct OSystem_iOS7::s_AudioQueue; SoundProc OSystem_iOS7::s_soundCallback = NULL; void *OSystem_iOS7::s_soundParam = NULL; +#ifdef IPHONE_SANDBOXED +class SandboxedSaveFileManager : public DefaultSaveFileManager { + Common::String _sandboxRootPath; +public: + + SandboxedSaveFileManager(Common::String sandboxRootPath, Common::String defaultSavepath) + : DefaultSaveFileManager(defaultSavepath), _sandboxRootPath(sandboxRootPath) { + } + + virtual bool removeSavefile(const Common::String &filename) override { + Common::String chrootedFile = getSavePath() + "/" + filename; + Common::String realFilePath = _sandboxRootPath + chrootedFile; + + if (remove(realFilePath.c_str()) != 0) { + if (errno == EACCES) + setError(Common::kWritePermissionDenied, "Search or write permission denied: "+chrootedFile); + + if (errno == ENOENT) + setError(Common::kPathDoesNotExist, "removeSavefile: '"+chrootedFile+"' does not exist or path is invalid"); + return false; + } else { + return true; + } + } +}; +#endif + OSystem_iOS7::OSystem_iOS7() : _mixer(NULL), _lastMouseTap(0), _queuedEventTime(0), _mouseNeedTextureUpdate(false), _secondaryTapped(false), _lastSecondaryTap(0), @@ -89,7 +116,8 @@ OSystem_iOS7::OSystem_iOS7() : _queuedInputEvent.type = Common::EVENT_INVALID; _touchpadModeEnabled = !iOS7_isBigDevice(); #ifdef IPHONE_SANDBOXED - _fsFactory = new ChRootFilesystemFactory(iOS7_getDocumentsDir()); + _chrootBasePath = iOS7_getDocumentsDir(); + _fsFactory = new ChRootFilesystemFactory(_chrootBasePath); #else _fsFactory = new POSIXFilesystemFactory(); #endif @@ -124,7 +152,7 @@ int OSystem_iOS7::timerHandler(int t) { void OSystem_iOS7::initBackend() { #ifdef IPHONE_SANDBOXED - _savefileManager = new DefaultSaveFileManager("/Savegames"); + _savefileManager = new SandboxedSaveFileManager(_chrootBasePath, "/Savegames"); #else _savefileManager = new DefaultSaveFileManager(SCUMMVM_SAVE_PATH); #endif diff --git a/backends/platform/ios7/ios7_osys_main.h b/backends/platform/ios7/ios7_osys_main.h index cc2f1ccc06..174c160bd6 100644 --- a/backends/platform/ios7/ios7_osys_main.h +++ b/backends/platform/ios7/ios7_osys_main.h @@ -111,6 +111,10 @@ protected: char *_lastErrorMessage; +#ifdef IPHONE_SANDBOXED + Common::String _chrootBasePath; +#endif + public: OSystem_iOS7(); diff --git a/backends/platform/maemo/debian/changelog b/backends/platform/maemo/debian/changelog index 8975871203..6b6d1aebd8 100644 --- a/backends/platform/maemo/debian/changelog +++ b/backends/platform/maemo/debian/changelog @@ -1,8 +1,14 @@ -scummvm (1.8.0~git) unstable; urgency=low +scummvm (1.9.0~git) unstable; urgency=low * Development snapshot - -- Tarek Soliman <tsoliman@scummvm.org> Mon, 01 Feb 2016 22:37:44 -0600 + -- Tarek Soliman <tsoliman@scummvm.org> Fri, 26 Feb 2016 21:11:20 -0600 + +scummvm (1.8.0) unstable; urgency=low + + * 1.8.0 release + + -- Tarek Soliman <tsoliman@scummvm.org> Fri, 26 Feb 2016 21:11:20 -0600 scummvm (1.7.0) unstable; urgency=low diff --git a/backends/platform/maemo/debian/rules b/backends/platform/maemo/debian/rules index 70f52aac8f..0e72c8aa9a 100755 --- a/backends/platform/maemo/debian/rules +++ b/backends/platform/maemo/debian/rules @@ -6,8 +6,8 @@ build: scummvm scummvm: dh_testdir - ./configure --host=maemo - $(MAKE) + ./configure --host=maemo $(CONFIGURE_EXTRA_ARGS) + $(MAKE) $(MAKE_EXTRA_ARGS) clean: dh_testdir diff --git a/backends/platform/sdl/amigaos/amigaos.mk b/backends/platform/sdl/amigaos/amigaos.mk index 0c3c467965..15a2e9f93f 100644 --- a/backends/platform/sdl/amigaos/amigaos.mk +++ b/backends/platform/sdl/amigaos/amigaos.mk @@ -11,8 +11,14 @@ ifdef DIST_FILES_ENGINEDATA cp $(DIST_FILES_ENGINEDATA) $(AMIGAOSPATH)/extras/ endif cat ${srcdir}/README | sed -f ${srcdir}/dists/amiga/convertRM.sed > README.conv - rx dists/amiga/RM2AG.rx README.conv - cp ${srcdir}/README.guide $(AMIGAOSPATH) - rm ${srcdir}/README.conv - rm ${srcdir}/README.guide +# AmigaOS's shell is not happy with indented comments, thus don't do it. +# AREXX seems to have problems when ${srcdir} is '.'. It will break with a +# "Program not found" error. Therefore we copy the script to the cwd and +# remove it again, once it has finished. + cp ${srcdir}/dists/amiga/RM2AG.rx . + rx RM2AG.rx README.conv + cp README.guide $(AMIGAOSPATH) + rm RM2AG.rx + rm README.conv + rm README.guide cp $(DIST_FILES_DOCS) $(AMIGAOSPATH) diff --git a/backends/platform/sdl/sdl-sys.h b/backends/platform/sdl/sdl-sys.h index 67ad84efd3..551605a4b4 100644 --- a/backends/platform/sdl/sdl-sys.h +++ b/backends/platform/sdl/sdl-sys.h @@ -52,6 +52,21 @@ typedef struct { int FAKE; } FAKE_FILE; #define strncasecmp FAKE_strncasecmp #endif +#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_exit) +#undef exit +#define exit FAKE_exit +#endif + +#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_abort) +#undef abort +#define abort FAKE_abort +#endif + +#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_system) +#undef system +#define system FAKE_system +#endif + // HACK: SDL might include windows.h which defines its own ARRAYSIZE. // However, we want to use the version from common/util.h. Thus, we make sure // that we actually have this definition after including the SDL headers. @@ -112,7 +127,7 @@ typedef struct { int FAKE; } FAKE_FILE; #endif // In a moment of brilliance Xlib.h included by SDL_syswm.h #defines the -// following names. In a moment of mental breakdown, which occured upon +// following names. In a moment of mental breakdown, which occurred upon // gazing at Xlib.h, LordHoto decided to undefine them to prevent havoc. #ifdef Status #undef Status @@ -146,6 +161,21 @@ typedef struct { int FAKE; } FAKE_FILE; #define strncasecmp FORBIDDEN_SYMBOL_REPLACEMENT #endif +#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_exit) +#undef exit +#define exit(a) FORBIDDEN_SYMBOL_REPLACEMENT +#endif + +#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_abort) +#undef abort +#define abort() FORBIDDEN_SYMBOL_REPLACEMENT +#endif + +#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_system) +#undef system +#define system(a) FORBIDDEN_SYMBOL_REPLACEMENT +#endif + // SDL 2 has major API changes. We redefine constants which got renamed to // ease the transition. This is sometimes dangerous because the values changed // too! diff --git a/backends/platform/sdl/win32/win32-main.cpp b/backends/platform/sdl/win32/win32-main.cpp index c6339f0c8c..4864347d81 100644 --- a/backends/platform/sdl/win32/win32-main.cpp +++ b/backends/platform/sdl/win32/win32-main.cpp @@ -44,7 +44,12 @@ int __stdcall WinMain(HINSTANCE /*hInst*/, HINSTANCE /*hPrevInst*/, LPSTR /*lpC SDL_SetModuleHandle(GetModuleHandle(NULL)); #endif // HACK: __argc, __argv are broken and return zero when using mingwrt 4.0+ on MinGW -#if defined(__GNUC__) && defined(__MINGW32__) && !defined(__MINGW64__) +// HACK: MinGW-w64 based toolchains neither feature _argc nor _argv. The 32 bit +// incarnation only defines __MINGW32__. This leads to build breakage due to +// missing declarations. Luckily MinGW-w64 based toolchains define +// __MINGW64_VERSION_foo macros inside _mingw.h, which is included from all +// system headers. Thus we abuse that to detect them. +#if defined(__GNUC__) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) return main(_argc, _argv); #else return main(__argc, __argv); 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/platform/wince/wince-sdl.cpp b/backends/platform/wince/wince-sdl.cpp index c1b0c7f692..02853b548e 100644 --- a/backends/platform/wince/wince-sdl.cpp +++ b/backends/platform/wince/wince-sdl.cpp @@ -645,7 +645,7 @@ Common::String OSystem_WINCE3::getSystemLanguage() const { const char *posixMappingTable[][3] = { {"CAT", "ESP", "ca_ES"}, {"CSY", "CZE", "cs_CZ"}, - {"DAN", "DNK", "da_DA"}, + {"DAN", "DNK", "da_DK"}, {"DEU", "DEU", "de_DE"}, {"ESN", "ESP", "es_ES"}, {"ESP", "ESP", "es_ES"}, @@ -657,7 +657,7 @@ Common::String OSystem_WINCE3::getSystemLanguage() const { {"PLK", "POL", "pl_PL"}, {"PTB", "BRA", "pt_BR"}, {"RUS", "RUS", "ru_RU"}, - {"SVE", "SWE", "se_SE"}, + {"SVE", "SWE", "sv_SE"}, {"UKR", "UKR", "uk_UA"}, {NULL, NULL, NULL} }; diff --git a/backends/plugins/win32/win32-provider.cpp b/backends/plugins/win32/win32-provider.cpp index 5f4d405da4..ae8a5f0472 100644 --- a/backends/plugins/win32/win32-provider.cpp +++ b/backends/plugins/win32/win32-provider.cpp @@ -77,7 +77,7 @@ public: debug("Failed loading plugin '%s' (error code %d)", _filename.c_str(), (int32) GetLastError()); return false; } else { - debug(1, "Success loading plugin '%s', handle %08X", _filename.c_str(), (uint32) _dlHandle); + debug(1, "Success loading plugin '%s', handle %p", _filename.c_str(), _dlHandle); } return DynamicPlugin::loadPlugin(); 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/backends/taskbar/win32/win32-taskbar.cpp b/backends/taskbar/win32/win32-taskbar.cpp index 0192b1dc03..f3339fb917 100644 --- a/backends/taskbar/win32/win32-taskbar.cpp +++ b/backends/taskbar/win32/win32-taskbar.cpp @@ -28,8 +28,22 @@ #if defined(WIN32) && defined(USE_TASKBAR) +// HACK: To get __MINGW64_VERSION_foo defines we need to manually include +// _mingw.h in this file because we do not include any system headers at this +// point on purpose. The defines are required to detect whether this is a +// classic MinGW toolchain or a MinGW-w64 based one. +#if defined(__MINGW32__) +#include <_mingw.h> +#endif + // Needed for taskbar functions -#if defined(__GNUC__) && defined(__MINGW32__) && !defined(__MINGW64__) +// HACK: MinGW-w64 based toolchains include the symbols we require in their +// headers. The 32 bit incarnation only defines __MINGW32__. This leads to +// build breakage due to clashes with our compat header. Luckily MinGW-w64 +// based toolchains define __MINGW64_VERSION_foo macros inside _mingw.h, +// which is included from all system headers. Thus we abuse that to detect +// them. +#if defined(__GNUC__) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) #include "backends/taskbar/win32/mingw-compat.h" #else // We use functionality introduced with Win7 in this file. 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/archive.cpp b/common/archive.cpp index 36d420561f..5a339900b6 100644 --- a/common/archive.cpp +++ b/common/archive.cpp @@ -48,7 +48,7 @@ int Archive::listMatchingMembers(ArchiveMemberList &list, const String &pattern) int matches = 0; ArchiveMemberList::const_iterator it = allNames.begin(); - for ( ; it != allNames.end(); ++it) { + for (; it != allNames.end(); ++it) { // TODO: We match case-insenstivie for now, our API does not define whether that's ok or not though... // For our use case case-insensitive is probably what we want to have though. if ((*it)->getName().matchString(pattern, true, true)) { @@ -64,7 +64,7 @@ int Archive::listMatchingMembers(ArchiveMemberList &list, const String &pattern) SearchSet::ArchiveNodeList::iterator SearchSet::find(const String &name) { ArchiveNodeList::iterator it = _list.begin(); - for ( ; it != _list.end(); ++it) { + for (; it != _list.end(); ++it) { if (it->_name == name) break; } @@ -73,7 +73,7 @@ SearchSet::ArchiveNodeList::iterator SearchSet::find(const String &name) { SearchSet::ArchiveNodeList::const_iterator SearchSet::find(const String &name) const { ArchiveNodeList::const_iterator it = _list.begin(); - for ( ; it != _list.end(); ++it) { + for (; it != _list.end(); ++it) { if (it->_name == name) break; } @@ -81,13 +81,13 @@ SearchSet::ArchiveNodeList::const_iterator SearchSet::find(const String &name) c } /* - Keep the nodes sorted according to descending priorities. - In case two or node nodes have the same priority, insertion - order prevails. + Keep the nodes sorted according to descending priorities. + In case two or node nodes have the same priority, insertion + order prevails. */ void SearchSet::insert(const Node &node) { ArchiveNodeList::iterator it = _list.begin(); - for ( ; it != _list.end(); ++it) { + for (; it != _list.end(); ++it) { if (it->_priority < node._priority) break; } @@ -131,8 +131,7 @@ void SearchSet::addSubDirectoriesMatching(const FSNode &directory, String origPa ++sep; if (sep != origPattern.end()) nextPattern = String(sep, origPattern.end()); - } - else { + } else { pattern = origPattern; } @@ -211,7 +210,7 @@ bool SearchSet::hasFile(const String &name) const { return false; ArchiveNodeList::const_iterator it = _list.begin(); - for ( ; it != _list.end(); ++it) { + for (; it != _list.end(); ++it) { if (it->_arc->hasFile(name)) return true; } @@ -223,7 +222,7 @@ int SearchSet::listMatchingMembers(ArchiveMemberList &list, const String &patter int matches = 0; ArchiveNodeList::const_iterator it = _list.begin(); - for ( ; it != _list.end(); ++it) + for (; it != _list.end(); ++it) matches += it->_arc->listMatchingMembers(list, pattern); return matches; @@ -233,7 +232,7 @@ int SearchSet::listMembers(ArchiveMemberList &list) const { int matches = 0; ArchiveNodeList::const_iterator it = _list.begin(); - for ( ; it != _list.end(); ++it) + for (; it != _list.end(); ++it) matches += it->_arc->listMembers(list); return matches; @@ -244,7 +243,7 @@ const ArchiveMemberPtr SearchSet::getMember(const String &name) const { return ArchiveMemberPtr(); ArchiveNodeList::const_iterator it = _list.begin(); - for ( ; it != _list.end(); ++it) { + for (; it != _list.end(); ++it) { if (it->_arc->hasFile(name)) return it->_arc->getMember(name); } @@ -257,7 +256,7 @@ SeekableReadStream *SearchSet::createReadStreamForMember(const String &name) con return 0; ArchiveNodeList::const_iterator it = _list.begin(); - for ( ; it != _list.end(); ++it) { + for (; it != _list.end(); ++it) { SeekableReadStream *stream = it->_arc->createReadStreamForMember(name); if (stream) return stream; @@ -268,7 +267,7 @@ SeekableReadStream *SearchSet::createReadStreamForMember(const String &name) con SearchManager::SearchManager() { - clear(); // Force a reset + clear(); // Force a reset } void SearchManager::clear() { diff --git a/common/array.h b/common/array.h index f240a9c2f5..db1a62ba34 100644 --- a/common/array.h +++ b/common/array.h @@ -141,6 +141,12 @@ public: insert_aux(_storage + idx, array.begin(), array.end()); } + /** + * Inserts element before pos. + */ + void insert(iterator pos, const T &element) { + insert_aux(pos, &element, &element + 1); + } T remove_at(size_type idx) { assert(idx < _size); @@ -187,6 +193,14 @@ public: _capacity = 0; } + iterator erase(iterator pos) { + copy(pos + 1, _storage + _size, pos); + _size--; + // We also need to destroy the last object properly here. + _storage[_size].~T(); + return pos; + } + bool empty() const { return (_size == 0); } diff --git a/common/dcl.cpp b/common/dcl.cpp index 66dfb76b2a..75a533aa9d 100644 --- a/common/dcl.cpp +++ b/common/dcl.cpp @@ -470,7 +470,7 @@ bool decompressDCL(ReadStream *src, byte *dest, uint32 packedSize, uint32 unpack // Read source into memory src->read(sourceBufferPtr, packedSize); - Common::MemoryReadStream *sourceStream = new MemoryReadStream(sourceBufferPtr, packedSize, DisposeAfterUse::NO); + Common::MemoryReadStream *sourceStream = new MemoryReadStream(sourceBufferPtr, packedSize, DisposeAfterUse::YES); Common::MemoryWriteStream *targetStream = new MemoryWriteStream(dest, unpackedSize); success = dcl.unpack(sourceStream, targetStream, unpackedSize, true); diff --git a/common/macresman.cpp b/common/macresman.cpp index d83bde8fd8..adca1ea10b 100644 --- a/common/macresman.cpp +++ b/common/macresman.cpp @@ -29,6 +29,7 @@ #include "common/md5.h" #include "common/substream.h" #include "common/textconsole.h" +#include "common/archive.h" #ifdef MACOSX #include "common/config-manager.h" @@ -261,6 +262,76 @@ bool MacResManager::exists(const String &fileName) { return false; } +void MacResManager::listFiles(StringArray &files, const String &pattern) { + // Base names discovered so far. + typedef HashMap<String, bool, IgnoreCase_Hash, IgnoreCase_EqualTo> BaseNameSet; + BaseNameSet baseNames; + + // List files itself. + ArchiveMemberList memberList; + SearchMan.listMatchingMembers(memberList, pattern); + SearchMan.listMatchingMembers(memberList, pattern + ".rsrc"); + SearchMan.listMatchingMembers(memberList, pattern + ".bin"); + SearchMan.listMatchingMembers(memberList, constructAppleDoubleName(pattern)); + + for (ArchiveMemberList::const_iterator i = memberList.begin(), end = memberList.end(); i != end; ++i) { + String filename = (*i)->getName(); + + // For raw resource forks and MacBinary files we strip the extension + // here to obtain a valid base name. + int lastDotPos = filename.size() - 1; + for (; lastDotPos >= 0; --lastDotPos) { + if (filename[lastDotPos] == '.') { + break; + } + } + + if (lastDotPos != -1) { + const char *extension = filename.c_str() + lastDotPos + 1; + bool removeExtension = false; + + // TODO: Should we really keep filenames suggesting raw resource + // forks or MacBinary files but not being such around? This might + // depend on the pattern the client requests... + if (!scumm_stricmp(extension, "rsrc")) { + SeekableReadStream *stream = (*i)->createReadStream(); + removeExtension = stream && isRawFork(*stream); + delete stream; + } else if (!scumm_stricmp(extension, "bin")) { + SeekableReadStream *stream = (*i)->createReadStream(); + removeExtension = stream && isMacBinary(*stream); + delete stream; + } + + if (removeExtension) { + filename.erase(lastDotPos); + } + } + + // Strip AppleDouble '._' prefix if applicable. + bool isAppleDoubleName = false; + const String filenameAppleDoubleStripped = disassembleAppleDoubleName(filename, &isAppleDoubleName); + + if (isAppleDoubleName) { + SeekableReadStream *stream = (*i)->createReadStream(); + if (stream->readUint32BE() == 0x00051607) { + filename = filenameAppleDoubleStripped; + } + // TODO: Should we really keep filenames suggesting AppleDouble + // but not being AppleDouble around? This might depend on the + // pattern the client requests... + delete stream; + } + + baseNames[filename] = true; + } + + // Append resulting base names to list to indicate found files. + for (BaseNameSet::const_iterator i = baseNames.begin(), end = baseNames.end(); i != end; ++i) { + files.push_back(i->_key); + } +} + bool MacResManager::loadFromAppleDouble(SeekableReadStream &stream) { if (stream.readUint32BE() != 0x00051607) // tag return false; @@ -314,6 +385,18 @@ bool MacResManager::isMacBinary(SeekableReadStream &stream) { return true; } +bool MacResManager::isRawFork(SeekableReadStream &stream) { + // TODO: Is there a better way to detect whether this is a raw fork? + const uint32 dataOffset = stream.readUint32BE(); + const uint32 mapOffset = stream.readUint32BE(); + const uint32 dataLength = stream.readUint32BE(); + const uint32 mapLength = stream.readUint32BE(); + + return !stream.eos() && !stream.err() + && dataOffset < (uint32)stream.size() && dataOffset + dataLength <= (uint32)stream.size() + && mapOffset < (uint32)stream.size() && mapOffset + mapLength <= (uint32)stream.size(); +} + bool MacResManager::loadFromMacBinary(SeekableReadStream &stream) { byte infoHeader[MBI_INFOHDR]; stream.read(infoHeader, MBI_INFOHDR); @@ -592,4 +675,32 @@ String MacResManager::constructAppleDoubleName(String name) { return name; } +String MacResManager::disassembleAppleDoubleName(String name, bool *isAppleDouble) { + if (isAppleDouble) { + *isAppleDouble = false; + } + + // Remove "._" before the last portion of a path name. + for (int i = name.size() - 1; i >= 0; --i) { + if (i == 0) { + if (name.size() > 2 && name[0] == '.' && name[1] == '_') { + name.erase(0, 2); + if (isAppleDouble) { + *isAppleDouble = true; + } + } + } else if (name[i] == '/') { + if ((uint)(i + 2) < name.size() && name[i + 1] == '.' && name[i + 2] == '_') { + name.erase(i + 1, 2); + if (isAppleDouble) { + *isAppleDouble = true; + } + } + break; + } + } + + return name; +} + } // End of namespace Common diff --git a/common/macresman.h b/common/macresman.h index 43ec8d8e2c..05b2a875f4 100644 --- a/common/macresman.h +++ b/common/macresman.h @@ -33,6 +33,7 @@ #include "common/array.h" #include "common/fs.h" #include "common/str.h" +#include "common/str-array.h" #ifndef COMMON_MACRESMAN_H #define COMMON_MACRESMAN_H @@ -82,6 +83,16 @@ public: static bool exists(const String &fileName); /** + * List all filenames matching pattern for opening with open(). + * + * @param files Array containing all matching filenames discovered. Only + * adds to the list. + * @param pattern Pattern to match against. Taking String::matchPattern's + * format. + */ + static void listFiles(StringArray &files, const String &pattern); + + /** * Close the Mac data/resource fork pair. */ void close(); @@ -176,6 +187,7 @@ private: bool loadFromAppleDouble(SeekableReadStream &stream); static String constructAppleDoubleName(String name); + static String disassembleAppleDoubleName(String name, bool *isAppleDouble); /** * Check if the given stream is in the MacBinary format. @@ -183,6 +195,13 @@ private: */ static bool isMacBinary(SeekableReadStream &stream); + /** + * Do a sanity check whether the given stream is a raw resource fork. + * + * @param stream Stream object to check. Will not preserve its position. + */ + static bool isRawFork(SeekableReadStream &stream); + enum { kResForkNone = 0, kResForkRaw, diff --git a/common/rational.h b/common/rational.h index 55fb361774..89caaf25b4 100644 --- a/common/rational.h +++ b/common/rational.h @@ -84,6 +84,8 @@ public: int getNumerator() const { return _num; } int getDenominator() const { return _denom; } + bool isOne() const { return _num == _denom; } + void debugPrint(int debuglevel = 0, const char *caption = "Rational:") const; private: diff --git a/common/rect.h b/common/rect.h index 32424d3e6a..e6534e55d3 100644 --- a/common/rect.h +++ b/common/rect.h @@ -163,7 +163,8 @@ struct Rect { * * @param r the rectangle to check * - * @return true if the given rectangle is inside the rectangle, false otherwise + * @return true if the given rectangle has a non-empty intersection with + * this rectangle, false otherwise */ bool intersects(const Rect &r) const { return (left < r.right) && (r.left < right) && (top < r.bottom) && (r.top < bottom); 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/common/taskbar.h b/common/taskbar.h index b4ec673739..f1a9adb2d9 100644 --- a/common/taskbar.h +++ b/common/taskbar.h @@ -123,7 +123,7 @@ public: virtual void addRecent(const String &name, const String &description) {} /** - * Notifies the user an error occured through the taskbar icon + * Notifies the user an error occurred through the taskbar icon * * This will for example show the taskbar icon as red (using progress of 100% and an error state) * on Windows, and set the launcher icon in the urgent state on Unity @@ -162,6 +162,7 @@ _translation=yes # Default platform settings _backend=sdl _16bit=auto +_highres=auto _savegame_timestamp=auto _dynamic_modules=no _elf_loader=no @@ -181,6 +182,7 @@ _stagingpath="staging" _win32path="c:/scummvm" _amigaospath="Games:ScummVM" _staticlibpath= +_xcodetoolspath= _sdlconfig=sdl-config _freetypeconfig=freetype-config _sdlpath="$PATH" @@ -201,6 +203,7 @@ add_feature 16bit "16bit color" "_16bit" add_feature faad "libfaad" "_faad" add_feature flac "FLAC" "_flac" add_feature freetype2 "FreeType2" "_freetype2" +add_feature highres "high resolution" "_highres" add_feature mad "MAD" "_mad" add_feature jpeg "JPEG" "_jpeg" add_feature png "PNG" "_png" @@ -593,7 +596,7 @@ engine_enable() { parent=`get_subengine_parent ${engine}` if test `get_engine_build ${parent}` = "no" ; then set_var _engine_${parent}_build "yes" - fi + fi fi if test "$opt" = "static" -o "$opt" = "dynamic" -o "$opt" = "yes" ; then @@ -903,7 +906,7 @@ Game engines: --disable-all-engines disable all engines --enable-engine=<engine name>[,<engine name>...] enable engine(s) listed --disable-engine=<engine name>[,<engine name>...] disable engine(s) listed - --enable-engine-static=<engine name>[,<engine name>...] + --enable-engine-static=<engine name>[,<engine name>...] enable engine(s) listed as static builtin (when plugins are enabled) --enable-engine-dynamic=<engine name>[,<engine name>...] enable engine(s) listed as dynamic plugin (when plugins are enabled) @@ -922,6 +925,7 @@ Optional Features: --default-dynamic make plugins dynamic by default --disable-mt32emu don't enable the integrated MT-32 emulator --disable-16bit don't enable 16bit color support + --disable-highres don't enable support for high resolution engines >320x240 --disable-savegame-timestamp don't use timestamps for blank savegame descriptions --disable-scalers exclude scalers --disable-hq-scalers exclude HQ2x and HQ3x scalers @@ -1019,6 +1023,8 @@ done # for parm in ... for ac_option in $@; do case "$ac_option" in --disable-16bit) _16bit=no ;; + --enable-highres) _highres=yes ;; + --disable-highres) _highres=no ;; --disable-savegame-timestamp) _savegame_timestamp=no ;; --disable-scalers) _build_scalers=no ;; --disable-hq-scalers) _build_hq_scalers=no ;; @@ -1230,6 +1236,9 @@ for ac_option in $@; do --with-staticlib-prefix=*) _staticlibpath=`echo $ac_option | cut -d '=' -f 2` ;; + --with-xcodetools-path=*) + _xcodetoolspath=`echo $ac_option | cut -d '=' -f 2` + ;; --host=*) _host=`echo $ac_option | cut -d '=' -f 2` ;; @@ -1318,7 +1327,7 @@ raspberrypi) _host_cpu=arm # This tuple is the one used by the official Rpi toolchain. # It may change in the future. - _host_alias=bcm2708hardfp + _host_alias=arm-linux-gnueabihf ;; caanoo) _host_os=gph-linux @@ -2283,7 +2292,7 @@ case $_host_os in LDFLAGS="-L${macport_prefix}/lib $LDFLAGS" CXXFLAGS="-I${macport_prefix}/include $CXXFLAGS" - + if test -z "$_staticlibpath"; then _staticlibpath=${macport_prefix} echo "Set staticlib-prefix to ${_staticlibpath}" @@ -2345,6 +2354,17 @@ case $_host_os in echo "Could not determine prefix for static libraries" fi fi + + # If _xcodetoolspath is not set yet use xcode-select to get the path + if test -z "$_xcodetoolspath"; then + _xcodetoolspath=`xcode-select -print-path`/Tools + if test -d "$_xcodetoolspath"; then + echo "Set xcodetools-path to ${_xcodetoolspath}" + else + _xcodetoolspath= + echo "Could not determine path for Xcode Tools" + fi + fi ;; dreamcast) append_var DEFINES "-D__DC__" @@ -2438,6 +2458,10 @@ case $_host_os in mint*) append_var DEFINES "-DSYSTEM_NOT_SUPPORTING_D_TYPE" ;; + msys) + echo ERROR: Using the MSYS shell in msys mode is not supported. Please use the MSYS shell in mingw mode instead. + exit 1 + ;; n64) append_var DEFINES "-D__N64__" append_var DEFINES "-DLIMIT_FPS" @@ -2604,7 +2628,7 @@ if test -n "$_host"; then _mt32emu=no _optimization_level=-O3 # Disable alsa midi to get the port build on OpenDingux toolchain - _alsa=no + _alsa=no _vkeybd=yes _build_hq_scalers=no _keymapper=no @@ -2631,7 +2655,7 @@ if test -n "$_host"; then _eventrec=no _build_scalers=no _build_hq_scalers=no - # We prefer SDL2 on the Raspberry Pi: acceleration now depends on it + # We prefer SDL2 on the Raspberry Pi: acceleration now depends on it # since SDL2 manages dispmanx/GLES2 very well internally. # SDL1 is bit-rotten on this platform. _sdlconfig=sdl2-config @@ -2659,7 +2683,11 @@ if test -n "$_host"; then _build_scalers=no _mad=yes _zlib=yes - add_line_to_config_mk 'ronindir = /usr/local/ronin' + if test -z "$RONINDIR"; then + add_line_to_config_mk "ronindir := /usr/local/ronin" + else + add_line_to_config_mk "ronindir := $RONINDIR" + fi _port_mk="backends/platform/dc/dreamcast.mk" ;; ds) @@ -2692,7 +2720,9 @@ if test -n "$_host"; then add_line_to_config_h "/* #define DEBUG_WII_GDB */" add_line_to_config_h "#define USE_WII_DI" ;; - gcw0) + gcw0) + _sysroot=`$CXX --print-sysroot` + _sdlpath=$_sysroot/usr/bin append_var DEFINES "-DDINGUX -DGCW0" append_var DEFINES "-DREDUCE_MEMORY_USAGE" append_var CXXFLAGS "-mips32" @@ -2749,11 +2779,8 @@ if test -n "$_host"; then ;; ios7) append_var DEFINES "-DIPHONE" - append_var CFLAGS "-Wno-shift-count-overflow" - append_var CXXFLAGS "-Wno-shift-count-overflow" _backend="ios7" _build_scalers=no - _mt32emu=no _seq_midi=no _timidity=no ;; @@ -2770,7 +2797,7 @@ if test -n "$_host"; then append_var INCLUDES "-I/usr/X11R6/include" append_var LIBS "-lX11" append_var LIBS "-L/usr/lib" - + _backend="maemo" _vkeybd=yes _keymapper=yes @@ -3207,6 +3234,26 @@ case $_backend in esac # +# Enable High resolution engines (>320x240) support only for backends which support it +# +case $_host in + gcw0) + if test "$_highres" = yes ; then + _highres=yes + else + _highres=no + fi + ;; + *) + if test "$_highres" = no ; then + _highres=no + else + _highres=yes + fi + ;; +esac + +# # Enable Event Recorder only for backends that support it # case $_backend in @@ -3519,6 +3566,11 @@ define_in_config_if_yes "$_mt32emu" 'USE_MT32EMU' define_in_config_if_yes "$_16bit" 'USE_RGB_COLOR' # +# Check whether High resolution graphics support is requested +# +define_in_config_if_yes "$_highres" 'USE_HIGHRES' + +# # Check whether save games use the current time as default description # define_in_config_if_yes "$_savegame_timestamp" 'USE_SAVEGAME_TIMESTAMP' @@ -3898,17 +3950,14 @@ fi echo "$_sparkle" # -# Check for FluidSynth +# Check for FluidSynth # echocheck "FluidSynth" append_var FLUIDSYNTH_LIBS "-lfluidsynth" case $_host_os in mingw*) - # NOTE: Windows builds use an older FluidSynth version (1.0.9) - # which doesn't require glib, to avoid bundling the complete glib - # libraries with Windows builds. - FLUIDSYNTH_STATIC_LIBS="$FLUIDSYNTH_LIBS -ldsound -lwinmm" + FLUIDSYNTH_STATIC_LIBS="$FLUIDSYNTH_LIBS -lglib-2.0 -lintl -liconv -lws2_32 -lole32 -lshlwapi -lpcre -ldsound -lwinmm" ;; darwin*) @@ -4421,6 +4470,10 @@ if test "$_16bit" = yes ; then echo_n ", 16bit color" fi +if test "$_highres" = yes ; then + echo_n ", high resolution" +fi + if test "$_savegame_timestamp" = yes ; then echo_n ", savegame timestamp" fi @@ -4434,7 +4487,7 @@ if test "$_build_scalers" = yes ; then fi if test "$_mt32emu" = yes ; then - echo_n ", MT-32 emu" + echo_n ", MT-32 emulator" fi if test "$_text_console" = yes ; then @@ -4691,6 +4744,7 @@ STAGINGPATH=$_stagingpath WIN32PATH=$_win32path AMIGAOSPATH=$_amigaospath STATICLIBPATH=$_staticlibpath +XCODETOOLSPATH=$_xcodetoolspath SDLCONFIG=$_sdlconfig ABI := $ABI diff --git a/devtools/create_project/create_project.cpp b/devtools/create_project/create_project.cpp index 65b7601a54..aa450f1461 100644 --- a/devtools/create_project/create_project.cpp +++ b/devtools/create_project/create_project.cpp @@ -939,7 +939,7 @@ const Feature s_features[] = { { "mad", "USE_MAD", "libmad", true, "libmad (MP3) support" }, { "vorbis", "USE_VORBIS", "libvorbisfile_static libvorbis_static libogg_static", true, "Ogg Vorbis support" }, { "flac", "USE_FLAC", "libFLAC_static win_utf8_io_static", true, "FLAC support" }, - { "png", "USE_PNG", "libpng", true, "libpng support" }, + { "png", "USE_PNG", "libpng16", true, "libpng support" }, { "faad", "USE_FAAD", "libfaad", false, "AAC support" }, { "mpeg2", "USE_MPEG2", "libmpeg2", false, "MPEG-2 support" }, { "theora", "USE_THEORADEC", "libtheora_static", true, "Theora decoding support" }, diff --git a/devtools/create_project/msbuild.cpp b/devtools/create_project/msbuild.cpp index a326bd721a..a804205c42 100644 --- a/devtools/create_project/msbuild.cpp +++ b/devtools/create_project/msbuild.cpp @@ -319,12 +319,6 @@ void MSBuildProvider::outputProjectSettings(std::ofstream &project, const std::s for (StringList::const_iterator i = setup.libraries.begin(); i != setup.libraries.end(); ++i) libraries += *i + ".lib;"; - if (_version == 14) { - std::string debug = isRelease ? "" : "d"; - libraries += "libvcruntime" + debug + ".lib;"; - libraries += "libucrt" + debug + ".lib;"; - } - project << "\t\t<Link>\n" "\t\t\t<OutputFile>$(OutDir)" << ((setup.devTools || setup.tests) ? name : setup.projectName) << ".exe</OutputFile>\n" "\t\t\t<AdditionalDependencies>" << libraries << "%(AdditionalDependencies)</AdditionalDependencies>\n" @@ -370,17 +364,17 @@ void MSBuildProvider::outputGlobalPropFile(const BuildSetup &setup, std::ofstrea "<Project DefaultTargets=\"Build\" ToolsVersion=\"" << (_version >= 12 ? _version : 4) << ".0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n" "\t<PropertyGroup>\n" "\t\t<_PropertySheetDisplayName>" << setup.projectDescription << "_Global</_PropertySheetDisplayName>\n" - "\t\t<ExecutablePath>$(" << LIBS_DEFINE << ")\\bin;$(ExecutablePath)</ExecutablePath>\n" - "\t\t<LibraryPath>$(" << LIBS_DEFINE << ")\\lib\\" << (bits == 32 ? "x86" : "x64") << ";$(LibraryPath)</LibraryPath>\n" + "\t\t<ExecutablePath>$(" << LIBS_DEFINE << ")\\bin;$(" << LIBS_DEFINE << ")\\bin\\" << (bits == 32 ? "x86" : "x64") << ";$(ExecutablePath)</ExecutablePath>\n" + "\t\t<LibraryPath>$(" << LIBS_DEFINE << ")\\lib\\" << (bits == 32 ? "x86" : "x64") << ";$(" << LIBS_DEFINE << ")\\lib\\" << (bits == 32 ? "x86" : "x64") << "\\$(Configuration);$(LibraryPath)</LibraryPath>\n" "\t\t<IncludePath>$(" << LIBS_DEFINE << ")\\include;$(" << LIBS_DEFINE << ")\\include\\SDL;$(IncludePath)</IncludePath>\n" "\t\t<OutDir>$(Configuration)" << bits << "\\</OutDir>\n" - "\t\t<IntDir>$(Configuration)" << bits << "/$(ProjectName)\\</IntDir>\n" + "\t\t<IntDir>$(Configuration)" << bits << "\\$(ProjectName)\\</IntDir>\n" "\t</PropertyGroup>\n" "\t<ItemDefinitionGroup>\n" "\t\t<ClCompile>\n" "\t\t\t<DisableLanguageExtensions>true</DisableLanguageExtensions>\n" "\t\t\t<DisableSpecificWarnings>" << warnings << ";%(DisableSpecificWarnings)</DisableSpecificWarnings>\n" - "\t\t\t<AdditionalIncludeDirectories>$(" << LIBS_DEFINE << ")\\include;.;" << prefix << ";" << prefix << "\\engines;" << (setup.tests ? prefix + "\\test\\cxxtest;" : "") << "$(TargetDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n" + "\t\t\t<AdditionalIncludeDirectories>.;" << prefix << ";" << prefix << "\\engines;" << (setup.tests ? prefix + "\\test\\cxxtest;" : "") << "$(TargetDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n" "\t\t\t<PreprocessorDefinitions>" << definesList << "%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" "\t\t\t<ExceptionHandling>" << ((setup.devTools || setup.tests) ? "Sync" : "") << "</ExceptionHandling>\n"; @@ -437,10 +431,14 @@ void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, b "\t\t\t<StringPooling>true</StringPooling>\n" "\t\t\t<BufferSecurityCheck>false</BufferSecurityCheck>\n" "\t\t\t<DebugInformationFormat></DebugInformationFormat>\n" - "\t\t\t<RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n" + "\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 { @@ -448,11 +446,17 @@ void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, b "\t\t\t<PreprocessorDefinitions>WIN32;" << (configuration == "LLVM" ? "_CRT_SECURE_NO_WARNINGS;" : "") << "%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" "\t\t\t<MinimalRebuild>true</MinimalRebuild>\n" "\t\t\t<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n" - "\t\t\t<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n" + "\t\t\t<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n" "\t\t\t<FunctionLevelLinking>true</FunctionLevelLinking>\n" - "\t\t\t<TreatWarningAsError>false</TreatWarningAsError>\n" - "\t\t\t<DebugInformationFormat>" << (isWin32 ? "EditAndContinue" : "ProgramDatabase") << "</DebugInformationFormat>\n" // For x64 format Edit and continue is not supported, thus we default to Program Database - "\t\t\t<EnablePREfast>" << (configuration == "Analysis" ? "true" : "false") << "</EnablePREfast>\n"; + "\t\t\t<TreatWarningAsError>false</TreatWarningAsError>\n"; + if (_version >= 14) { + // Since MSVC 2015 Edit and Continue is support for x64 too. + properties << "\t\t\t<DebugInformationFormat>" << "EditAndContinue" << "</DebugInformationFormat>\n"; + } else { + // Older MSVC versions did not support Edit and Continue for x64, thus we do not use it. + properties << "\t\t\t<DebugInformationFormat>" << (isWin32 ? "EditAndContinue" : "ProgramDatabase") << "</DebugInformationFormat>\n"; + } + properties << "\t\t\t<EnablePREfast>" << (configuration == "Analysis" ? "true" : "false") << "</EnablePREfast>\n"; if (configuration == "LLVM") { // FIXME The LLVM cl wrapper does not seem to work properly with the $(TargetDir) path so we hard-code the build folder until the issue is resolved @@ -463,8 +467,7 @@ void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, b properties << "\t\t</ClCompile>\n" "\t\t<Link>\n" "\t\t\t<GenerateDebugInformation>true</GenerateDebugInformation>\n" - "\t\t\t<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\n" - "\t\t\t<IgnoreSpecificDefaultLibraries>libcmt.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\n"; + "\t\t\t<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\n"; } properties << "\t\t</Link>\n" diff --git a/devtools/create_project/scripts/postbuild.cmd b/devtools/create_project/scripts/postbuild.cmd index fcbd8c534a..31d2a94416 100644 --- a/devtools/create_project/scripts/postbuild.cmd +++ b/devtools/create_project/scripts/postbuild.cmd @@ -59,7 +59,7 @@ echo Invalid installer parameter. Should be "0" or "1" (was %~5)! goto done
:error_script:
-echo An error occured while running the installer script!
+echo An error occurred while running the installer script!
goto done
:done
diff --git a/devtools/create_project/scripts/prebuild.cmd b/devtools/create_project/scripts/prebuild.cmd index fbab426137..0efaab190c 100644 --- a/devtools/create_project/scripts/prebuild.cmd +++ b/devtools/create_project/scripts/prebuild.cmd @@ -27,7 +27,7 @@ echo Invalid target folder (%~2)! goto done
:error_script:
-echo An error occured while running the revision script!
+echo An error occurred while running the revision script!
:done
exit /B0
diff --git a/devtools/create_wage/create_wage.sh b/devtools/create_wage/create_wage.sh new file mode 100755 index 0000000000..5e8fe352a2 --- /dev/null +++ b/devtools/create_wage/create_wage.sh @@ -0,0 +1,119 @@ +#!/bin/bash +# +# This script downloads System 7.0.1 image from Apple and extracts fonts +# from it. Mac only, unfortunately. +# +# On Windows you perhaps can perform the extraction manually with use of +# HFV Explorer: https://web.archive.org/web/20011202005455/http://gamma.nic.fi/~lpesonen/HFVExplorer/ +# +# More information could be found in the vMac documentation: http://www.gryphel.com/c/image/ +# +# Alternatively you may use vMac instructions for extracting these disk images: +# http://www.gryphel.com/c/minivmac/recipes/sys7inst/ +# +# Based on instructions posted at +# http://apple.stackexchange.com/questions/58243/can-i-get-the-original-mac-font-chicago-on-a-mountain-lion-mac + +echo_n() { + printf "$@" +} + +if test `uname` != "Darwin"; then + echo This script is Mac OS X-only + exit +fi + +echo_n "Downloading System 7.0.1 image..." +if test ! -f System_7.0.1.smi.bin; then + curl -s http://download.info.apple.com/Apple_Support_Area/Apple_Software_Updates/English-North_American/Macintosh/System/Older_System/System_7.0.x/System_7.0.1.smi.bin -o System_7.0.1.smi.bin +fi + +if test ! -f System_7.0.1.smi.bin; then + echo "Cannot download System_7.0.1.smi.bin" + exit +fi + +echo done + +echo_n "Mounting System 7.0.1 image..." + +macbinary decode System_7.0.1.smi.bin +hdiutil convert -quiet System\ 7.0.1.smi -format UDRO -o sys7.dmg +hdiutil attach -quiet sys7.dmg + +if test ! -f /Volumes/7.0.1\ \(1440k.images\)/Fonts.image; then + echo "Failed to attach sys7.dmg" + exit +fi + +echo done + +echo_n "Mounting Fonts disk image..." + +hdiutil convert -quiet /Volumes/7.0.1\ \(1440k.images\)/Fonts.image -format UDRO -o fonts.dmg +hdiutil detach -quiet `hdiutil info|grep "/Volumes/7.0.1 (1440k.images)"|cut -f 1` +hdiutil attach -quiet fonts.dmg + +if test ! -f /Volumes/Fonts/Chicago; then + echo "Failed to attach fonts.dmg" + exit +fi + +echo done + +echo_n "Copying fonts..." + +for i in Athens Cairo Chicago Courier Geneva Helvetica London "Los Angeles" Monaco "New York" Palatino "San Francisco" Symbol Times Venice +do + echo $i + macbinary encode "/Volumes/Fonts/$i" -o "$i.bin" -n +done + +echo ...Done + +hdiutil detach -quiet `hdiutil info|grep "/Volumes/Fonts"|cut -f 1` + +if test ! -f fondu_src-060102.tgz; then + echo_n "Getting fondu_src-060102.tgz..." + curl -s http://fondu.sourceforge.net/fondu_src-060102.tgz -o fondu_src-060102.tgz + tar xf fondu_src-060102.tgz +fi + +if test ! -d fondu-060102; then + echo "Failed to download fondu_src-060102.tgz" + exit +fi + +echo done + +if test ! -x fondu-060102/fondu; then + echo_n "Compiling fondu..." + cd fondu-060102 + ./configure >configure.log 2>&1 && make 2>&1 >make.log + cd .. +fi + +if test ! -x fondu-060102/fondu; then + echo "Failed to build fondu. See configure.log and make.log" + exit +else + rm -f configure.log make.log +fi + +echo done + +echo_n "Converting fonts..." +fondu-060102/fondu -force *.bin +echo done + +zip -9 wage *.bdf +mv wage.zip wage.dat + +echo_n "Cleaning up..." +rm *.bdf +rm *.ttf +rm *.bin +rm *.dmg +echo done + +ls -l wage.dat diff --git a/devtools/credits.pl b/devtools/credits.pl index d7cd26fbdc..c67793cbfa 100755 --- a/devtools/credits.pl +++ b/devtools/credits.pl @@ -287,7 +287,7 @@ sub begin_section { # headlines... my $ascii_title = html_entities_to_ascii($title); $title = html_entities_to_cpp($title); - if ($ascii_title ne $title) { + if ($ascii_title ne $title) { print '"A1""'.$ascii_title.'",' . "\n"; } print '"C1""'.$title.'",' . "\n"; @@ -295,7 +295,7 @@ sub begin_section { } else { my $ascii_title = html_entities_to_ascii($title); $title = html_entities_to_cpp($title); - if ($ascii_title ne $title) { + if ($ascii_title ne $title) { print '"A1""'.$ascii_title.'",' . "\n"; } print '"C1""'.$title.'",' . "\n"; @@ -428,7 +428,7 @@ sub add_person { if (length $desc > 0) { my $ascii_desc = html_entities_to_ascii($desc); $desc = html_entities_to_cpp($desc); - if ($ascii_desc ne $desc) { + if ($ascii_desc ne $desc) { print '"A2""'.$ascii_desc.'",' . "\n"; } print '"C2""'.$desc.'",' . "\n"; @@ -572,7 +572,7 @@ begin_credits("Credits"); add_person("Arnaud Boutonné", "Strangerke", ""); add_person("Paul Gilbert", "dreammaster", ""); end_section(); - + begin_section("CGE2"); add_person("Peter Bozsó", "uruk", ""); add_person("Arnaud Boutonné", "Strangerke", ""); @@ -803,7 +803,7 @@ begin_credits("Credits"); add_person("Einar Johan T. Sømåen", "somaen", ""); add_person("Tobia Tesan", "t0by", ""); end_section(); - + begin_section("Z-Vision"); add_person("Adrian Astley", "RichieSams", ""); add_person("Filippos Karapetis", "[md5]", ""); @@ -823,6 +823,10 @@ begin_credits("Credits"); add_person("Marcus Comstedt", "", ""); end_section(); + begin_section("GCW0"); + add_person("Eugene Sandulenko", "", ""); + end_section(); + begin_section("GPH Devices (GP2X, GP2XWiz & Caanoo)"); add_person("John Willis", "DJWillis", ""); end_section(); diff --git a/dists/gcw0/default.gcw0.desktop b/dists/gcw0/default.gcw0.desktop index 46bd2be092..890852184f 100644 --- a/dists/gcw0/default.gcw0.desktop +++ b/dists/gcw0/default.gcw0.desktop @@ -11,6 +11,6 @@ Exec=scummvm.sh Icon=scummvm Terminal=false Type=Application -Categories=games +Categories=games; StartupNotify=false -X-OD-Manual=README +X-OD-Manual=README.man.txt diff --git a/dists/ios7/Info.plist b/dists/ios7/Info.plist index 2ea3ad87be..ceef7e7d36 100644 --- a/dists/ios7/Info.plist +++ b/dists/ios7/Info.plist @@ -26,6 +26,11 @@ <string>1.9.0git</string> <key>UIApplicationExitsOnSuspend</key> <false/> + <key>UIDeviceFamily</key> + <array> + <integer>1</integer> + <integer>2</integer> + </array> <key>UIFileSharingEnabled</key> <true/> <key>UILaunchImages</key> diff --git a/dists/ios7/Info.plist.in b/dists/ios7/Info.plist.in index 33094f4df9..447677ebd9 100644 --- a/dists/ios7/Info.plist.in +++ b/dists/ios7/Info.plist.in @@ -26,6 +26,11 @@ <string>@VERSION@</string> <key>UIApplicationExitsOnSuspend</key> <false/> + <key>UIDeviceFamily</key> + <array> + <integer>1</integer> + <integer>2</integer> + </array> <key>UIFileSharingEnabled</key> <true/> <key>UILaunchImages</key> diff --git a/dists/macosx/DS_Store b/dists/macosx/DS_Store Binary files differindex 7ad5a19d61..164e7beb9a 100644 --- a/dists/macosx/DS_Store +++ b/dists/macosx/DS_Store diff --git a/dists/openpandora/pnd_make.sh b/dists/openpandora/pnd_make.sh index 0c03e8154d..a24beaf5d4 100755 --- a/dists/openpandora/pnd_make.sh +++ b/dists/openpandora/pnd_make.sh @@ -41,9 +41,16 @@ cecho () # Color-echo. Argument $1 = message, Argument $2 = color { local default_msg="No message passed." # Doesn't really need to be a local variable. message=${1:-$default_msg} # Defaults to default message. - color=${2:-$black} # Defaults to black, if not specified. - echo -e "$color$message" - tput sgr0 # Reset to normal. + + # We only output colors when stdout is outputting to a terminal. + # This avoids color codes being output in log files created on buildbot. + if [ -t 1 -a -n "$TERM" ]; then + color=${2:-$black} # Defaults to black, if not specified. + echo -e "$color$message" + tput -T"$TERM" sgr0 # Reset to normal. + else + echo "$message" + fi return } diff --git a/dists/samsungtv/README-SamsungTV b/dists/samsungtv/README-SamsungTV index 26ded6c7e6..7c171747dc 100644 --- a/dists/samsungtv/README-SamsungTV +++ b/dists/samsungtv/README-SamsungTV @@ -3,7 +3,7 @@ Notes: - Should works on 2009 B series TVs (Full HD): LExxBE65x, LExxBE75x, PSxxB65x, UExxB7xxx, UExxB8xxx, PSxxB85x, LAxxB65x, LAxxB75x, UNxxB7xxx, UAxxB8xxx - To allow use mouse and keyboard you need load extension first: "SamyGO Mouse And Keyboard" Download from SamyGO project and run from Content Library: - http://sourceforge.net/projects/samygo/files/SamyGO%20Kernel%20Modules/SamyGO%20Mouse%20and%20Keyboard%20Modules%20v0.01.zip/download + http://download.samygo.tv/B%20Series/Content%20Library%20Applications/SamyGO%20Mouse%20and%20Keyboard%20Modules%20v0.01.zip - Buttons on remote controler: EXIT, SOURCE, P+, P-, TV, POWER, CONTENT - cause immediately exit from ScummVM - Config file is in /mtd_rwarea/.scummvmrc - Saves are stored in '/mtd_wiselink/scummvm savegames' directory diff --git a/dists/win32/ScummVM.iss b/dists/win32/ScummVM.iss index c156ab6ca1..817cc5aeef 100644 --- a/dists/win32/ScummVM.iss +++ b/dists/win32/ScummVM.iss @@ -105,7 +105,7 @@ Source: doc/de/Liesmich.txt; DestDir: {app}; Flags: ignoreversion isreadme; Lang Source: doc/se/LasMig.txt; DestDir: {app}; Flags: ignoreversion isreadme; Languages: se Source: README-SDL.txt; DestDir: {app}; Flags: ignoreversion Source: scummvm.exe; DestDir: {app}; Flags: ignoreversion -Source: SDL.dll; DestDir: {app} +Source: SDL.dll; DestDir: {app}; Flags: replacesameversion ;Mirgration script for saved games in Windows NT4 onwards Source: migration.bat; DestDir: {app}; Flags: ignoreversion; MinVersion: 0, 1 Source: migration.txt; DestDir: {app}; Flags: ignoreversion; MinVersion: 0, 1 diff --git a/doc/cz/PrectiMe b/doc/cz/PrectiMe index d360aa46f9..3c03db9802 100644 --- a/doc/cz/PrectiMe +++ b/doc/cz/PrectiMe @@ -1,8 +1,8 @@ -PŘEÄŒTIMÄš ScummVM
+\rPŘEČTIMĚ ScummVM
------------------------------------------------------------------------
Pro vÃce informacÃ, seznamy kompatibility, podrobnosti o dotacÃch, nejnovÄ›jÅ¡Ã verze,
-novinky o vývoji a dalÅ¡Ã, prosÃm navÅ¡tivte domovskou stránku ScummVM na: http://www.scummvm.org/
+novinky o vývoji a dalÅ¡Ã, prosÃm navÅ¡tivte domovskou stránku ScummVM na: <http://www.scummvm.org/>
Obsah:
@@ -10,31 +10,40 @@ Obsah: 1.0) Úvod
* 1.1 O ScummVM
* 1.2 Rychlý návod
+ * 1.3 NejÄastÄ›jÅ¡Ã otázky
2.0) Kontakt
* 2.1 Hlášenà chyb
3.0) Podporované hry
* 3.1 Ochrana proti kopÃrovánÃ
- * 3.2 Poznámky ke hře Day of the Tentacle
- * 3.3 Poznámky ke hrám Commodore64
- * 3.4 Poznámky k Maniac Mansion NES
- * 3.5 Poznámky ke hrám Macintosh
- * 3.6 Poznámky ke hrám Multi-CD
- * 3.7 Poznámky k The Curse of Monkey Island
- * 3.8 Poznámky ke hrám Broken Sword
- * 3.9 Poznámky k Beneath a Steel Sky
+ * 3.2 Datové soubory
+ * 3.3 Poznámky ke hrám Multi-CD
+ * 3.4 Známé problémy
+ * 3.5 Poznámky k Beneath a Steel Sky
+ * 3.6 Poznámky ke hrám Broken Sword
+ * * 3.6.1 Broken Sword
+ * * 3.6.2 Broken Sword II
+ * * 3.6.3 Videa z her Broken Sword
+ * * 3.6.4 Videa her Broken Sword ve zpětném pohledu
+ * 3.7 Poznámky k Day of the Tentacle
+ * 3.8 Poznámky k Discworld II
+ * 3.9 Poznámky k DraÄà Historie
* 3.10 Poznámky k Flight of the Amazon Queen
* 3.11 Poznámky ke Gobliiins
* 3.12 Poznámky k Inherit the Earth: Quest for the Orb
- * 3.13 Poznámky k Simon the Sorcerer
- * 3.14 Poznámky k The Feeble Files
- * 3.15 Poznámky k The Legend of Kyrandia
- * 3.16 Poznámky k PÅ™edvÃdavému VstupnÃmu Dialogu her Sierra AGI
- * 3.17 Poznámky k Mickey's Space Adventure
- * 3.18 Poznámky k Winnie the Pooh
- * 3.19 Poznámky k Troll's Tale
- * 3.20 Poznámky k DraÄà Historie
- * 3.21 Titulky a hlasy souběžně v hrách Sierra SCI
- * 3.22 Známé problémy
+ * 3.13 Poznámky k Maniac Mansion na Apple II/NES
+ * 3.14 Poznámky k Mickey's Space Adventure
+ * 3.15 Poznámky k Nippon Safes Inc. na Amiga
+ * 3.16 Poznámky k Simon the Sorcerer
+ * 3.17 Poznámky k The Curse of Monkey Island
+ * 3.18 Poznámky k The Feeble Files
+ * 3.19 Poznámky k The Legend of Kyrandia
+ * 3.20 Poznámky k Troll's Tale
+ * 3.21 Poznámky k Winnie the Pooh
+ * 3.22 Poznámky k PÅ™edvÃdavému VstupnÃmu Dialogu her Sierra AGI
+ * 3.23 Titulky a hlasy souběžně v hrách Sierra SCI
+ * 3.24 Poznámky k hrám Zork
+ * 3.25 Poznámky ke hrám Commodore64
+ * 3.26 Poznámky ke hrám Macintosh
4.0) Podporované platformy
5.0) Spuštěnà ScummVM
* 5.1 Možnosti pÅ™Ãkazového řádku
@@ -52,7 +61,21 @@ Obsah: * 7.3 Emulace MT-32
* 7.4 Emulace MIDI
* 7.5 Přirozená podpora MIDI
+ * * 7.5.1 Použità voleb MIDI pro přizpůsobenà výstupu přirozeného MIDI
* 7.6 Podpora nativnÃho UNIX, ALSA a sekvenceru dmedia
+ * * 7.6.1 Sekvencer ALSA [POUZE UNIX]
+ * * 7.6.2 Sekvencer dmedia IRIX [POUZE UNIX]
+ * 7.7 Podpora MIDI serveru TiMidity++
+ * 7.8 Použità komprimovaných zvukových souborů (MP3, Ogg Vorbis, Flac)
+ * * 7.8.1 Použità souborů MP3 pro zvuky z CD
+ * * 7.8.2 Použità souborů Ogg Vorbis pro zvuky z CD
+ * * 7.8.3 Použità souborů Flac pro zvuky z CD
+ * * 7.8.4 Komprimovánà MONSTER.SOU pomocà MP3
+ * * 7.8.5 Komprimovánà MONSTER.SOU pomocà Ogg Vorbis
+ * * 7.8.6 Komprimovánà MONSTER.SOU pomocà Flac
+ * * 7.8.7 Komprimovánà hudby/zvuků/hlasů v hrách AGOS
+ * * 7.8.8 Komprimovánà hlasů/hudby v Broken Sword
+ * * 7.8.9 Komprimovánà hlasů/hudby v Broken Sword II
* 7.7 Podpora MIDI serveru TiMidity++
* 7.8 Použità komprimovaných zvukových souborů (MP3, Ogg Vorbis, Flac)
* 7.9 Výstupnà vzorkovacà kmitoÄet
@@ -60,6 +83,7 @@ Obsah: * 8.1 Rozpoznávaná klÃÄová slova nastavenÃ
* 8.2 Vlastnà hernà volby, které mohou být pÅ™epÃnány pomoci grafického rozhranÃ
9.0) SestavenÃ
+10.0) PodÄ›kovánÃ
1.0) Úvod:
@@ -104,16 +128,21 @@ V budoucnu byste mÄ›li být schopni pÅ™eskoÄit na krok 5, pokud nechcete pÅ™id Rada: Pokud chcete pÅ™idat vÃce her najednou, zkuste stisknout a držet klávesu shift pÅ™edtÃm, než kliknete na 'PÅ™idat hru' – tlaÄÃtko se zmÄ›nà na 'Hromadné PÅ™idánÃ' a pokud ho stisknÄ›te, jste znovu požádáni o zvolenà složky, ale tentokrát ScummVM prohledá vÅ¡echny podsložky pro podporované hry.
+1.3) NejÄastÄ›jÅ¡Ã otázky
+---- ------------------
+Na <http://www.scummvm.org/faq/> jsme pro Vás pÅ™ipravili seznam nejÄastÄ›jÅ¡Ãch otázek a jejich odpovÄ›dÃ.
+
+
2.0) Kontakt:
---- --------
-NejjednoduÅ¡Å¡Ãm způsobem, jak kontaktovat tým ScummVM je pÅ™edloženÃm hlášenà o chybÄ› (viz oddÃl 2.1) nebo použitÃm naÅ¡ich fór na http://forums.scummvm.org .
+NejjednoduÅ¡Å¡Ãm způsobem, jak kontaktovat tým ScummVM je pÅ™edloženÃm hlášenà o chybÄ› (viz oddÃl 2.1) nebo použitÃm naÅ¡ich fór na <http://forums.scummvm.org>.
Můžete se také pÅ™ipojit a odesÃlat a e-maily na korespondenÄnà seznam scummvm-devel, nebo si s námi popovÃdejte na IRC (#scummvm na irc.freenode.net) Nežádejte nás, prosÃm, o podporu nefungujÃcà hry – nejdÅ™Ãve si pÅ™eÄtÄ›te nejÄastÄ›jÅ¡Ã otázky na naÅ¡Ã stránce
2.1) Hlášenà chyb:
---- -------------
Abyste mohli nahlásit chybu, nejdÅ™Ãve si, prosÃme, vytvoÅ™te si úÄet na SourceForge a kliknÄ›te na odkaz "Bug Tracker" na naÅ¡Ã stránce. UjistÄ›te se, prosÃm, že se chyba dá znovu zjistit a stále se objevuje v nejnovÄ›jÅ¡Ã verzi git/dennÃho sestavenÃ. Také na naÅ¡Ã stránce zkontrolujte seznam známých problémů (nÞe) a seznam kompatibility pro tuto hru, abyste se ujistili, že problém již nenà znám:
- http://www.scummvm.org/compatibility
+ <http://www.scummvm.org/compatibility>
ProsÃme, nenahlaÅ¡ujte chyby ve hrách, které nejsou v seznamu v sekci 'Supported Games' nebo seznamu kompatibility uvedeny jako dokonÄitelné. My –vÃme-, že tyto hry majà chyby.
@@ -131,13 +160,18 @@ Nakonec prosÃme, abyste každou chybu nahlaÅ¡ovali samostatnÄ›; neohlaÅ¡ujte nÄ 3.0) Podporované hry:
---- ----------------
-V tuto chvÃli je o následujÃcÃch hrách známo, že fungujà a mÄ›ly by být hratelné až dokonce:
+V tuto chvÃli je o následujÃcÃch hrách známo, že fungujà a mÄ›ly by být hratelné až dokonce.
+Podrobnějšà seznam kompatibility podporovaných her můžete nalézt na adrese:
+
+ <http://www.scummvm.org/compatibility/>)
+
-Hry SCUMM od LucasArts:
+Hry od LucasArts (SCUMM):
Maniac Mansion [maniac]
Zak McKracken and the Alien Mindbenders [zak]
Indiana Jones and the Last Crusade [indy3]
Loom [loom]
+ Passport to Adventure [pass]
The Secret of Monkey Island [monkey]
Monkey Island 2: LeChuck's Revenge [monkey2]
Indiana Jones and the Fate of Atlantis [atlantis]
@@ -147,32 +181,16 @@ Hry SCUMM od LucasArts: The Dig [dig]
The Curse of Monkey Island [comi]
-Hry AGI a před AGI od Sierra:
- The Black Cauldron [bc]
- Gold Rush! [goldrush]
- King's Quest I [kq1]
- King's Quest II [kq2]
- King's Quest III [kq3]
- King's Quest IV [kq4]
- Leisure Suit Larry in the Land of the
- Lounge Lizards [lsl1]
- Mixed-Up Mother Goose [mixedup]
- Manhunter 1: New York [mh1]
- Manhunter 2: San Francisco [mh2]
- Police Quest I: In Pursuit of the Death
- Angel [pq1]
- Space Quest I: The Sarien Encounter [sq1]
- Space Quest II: Vohaul's Revenge [sq2]
- Fanmade Games [agi-fanmade]
- Mickey's Space Adventure [mickey]
- Troll's Tale [troll]
- Winnie the Pooh in the Hundred Acre Wood [winnie]
+Hry od Activision (MADE):
+ Leather Goddesses of Phobos 2 [lgop2]
+ The Manhole [manhole]
+ Return to Zork [rtz]
+ Rodney's Funscreen [rodney]
-Hry AGOS od Adventuresoft/Horrorsoft:
+Hry od Adventuresoft/Horrorsoft (AGOS):
Elvira - Mistress of the Dark [elvira1]
Elvira II - The Jaws of Cerberus [elvira2]
Personal Nightmare [pn]
- Waxworks [waxworks]
Simon the Sorcerer 1 [simon1]
Simon the Sorcerer 2 [simon2]
Simon the Sorcerer's Puzzle Pack
@@ -184,16 +202,9 @@ Hry AGOS od Adventuresoft/Horrorsoft: Simon the Sorcerer's Puzzle Pack
- Swampy Adventures [swampy]
The Feeble Files [feeble]
-
-Hry Composer od Animation Magic:
- Darby the Dragon [darby]
- Gregory and the Hot Air Balloon [gregory]
- Magic Tales: Liam Finds a Story [liam]
- The Princess and the Crab [princess]
- Sleeping Cub's Test of Courage [sleepingcub]
+ Waxworks [waxworks]
-Hry GOB od Coktel Vision:
- Bambou le sauveur de la jungle [bambou]
+Hry od Coktel Vision (GOB):
Bargon Attack [bargon]
Fascination [fascination]
Geisha [geisha]
@@ -202,80 +213,40 @@ Hry GOB od Coktel Vision: Goblins 3 [gob3]
Lost in Time [lostintime]
Once Upon A Time: Little Red Riding Hood [littlered]
+ Playtoons: Bambou le sauveur de la jungle [bambou]
The Bizarre Adventures of Woodruff
and the Schnibble [woodruff]
Urban Runner [urban]
Ween: The Prophecy [ween]
-
-Hry Living Books:
- Aesop's Fables: The Tortoise and the Hare [tortoise]
- Arthur's Birthday [arthurbday]
- Arthur's Teacher Trouble [arthur]
- Dr. Seuss's ABC [seussabc]
- Green Eggs and Ham [greeneggs]
- Harry and the Haunted House [harryhh]
- Just Grandma and Me [grandma]
- Little Monster at School [lilmonster]
- Ruff's Bone [ruff]
- Sheila Rae, the Brave [sheila]
- Stellaluna [stellaluna]
- The Berenstain Bears Get in a Fight [bearfight]
- The Berenstain Bears in the Dark [beardark]
- The New Kid on the Block [newkid]
-Hry MADE od Activision:
- Leather Goddesses of Phobos 2 [lgop2]
- Return to Zork [rtz]
- Rodney's Funscreen [rodney]
- The Manhole [manhole]
-
-Dalšà hry:
- 3 Skulls of the Toltecs [toltecs]
- Blue Force [blueforce]
+Hry od Revolution Software (Různé):
Beneath a Steel Sky [sky]
Broken Sword: The Shadow of the Templars [sword1]
Broken Sword II: The Smoking Mirror [sword2]
- Bud Tucker in Double Trouble [tucker]
- Cruise for a Corpse [cruise]
- Discworld [dw]
- Discworld 2: Missing Presumed ...!? [dw2]
- Dragon History [draci]
- Drascula: The Vampire Strikes Back [drascula]
- DreamWeb [dreamweb]
- Eye of the Beholder [eob]
- Eye of the Beholder II: The Legend of
- Darkmoon [eob2]
- Flight of the Amazon Queen [queen]
- Future Wars [fw]
- Hopkins FBI [hopkins]
- Hugo's House of Horrors [hugo1]
- Hugo 2: Whodunit? [hugo2]
- Hugo 3: Jungle of Doom [hugo3]
- I Have No Mouth, and I Must Scream [ihnm]
- Inherit the Earth: Quest for the Orb [ite]
- Nippon Safes Inc. [nippon]
- Lands of Lore: The Throne of Chaos [lol]
Lure of the Temptress [lure]
- Mortville Manor [mortevielle]
- Nippon Safes Inc. [nippon]
- Ringworld: Revenge Of The Patriarch [ringworld]
- Return to Ringworld [ringworld2]
- Sfinx [sfinx]
- Soltys [soltys]
- TeenAgent [teenagent]
- The Journeyman Project: Pegasus Prime [pegasus]
- The Legend of Kyrandia [kyra1]
- The Legend of Kyrandia: The Hand of Fate [kyra2]
- The Legend of Kyrandia: Malcolm's Revenge [kyra3]
- The 7th Guest [t7g]
- The Neverhood [neverhood]
- Tony Tough and the Night of Roasted Moths [tony]
- Toonstruck [toon]
- Touche: The Adventures of the Fifth
- Musketeer [touche]
- Voyeur [voyeur]
-
-Hry SCI od Sierra Entertainment:
+
+Hry od Sierra (AGI a před AGI):
+ The Black Cauldron [bc]
+ Gold Rush! [goldrush]
+ King's Quest I [kq1]
+ King's Quest II [kq2]
+ King's Quest III [kq3]
+ King's Quest IV [kq4]
+ Leisure Suit Larry in the Land of the
+ Lounge Lizards [lsl1]
+ Mixed-Up Mother Goose [mixedup]
+ Manhunter 1: New York [mh1]
+ Manhunter 2: San Francisco [mh2]
+ Police Quest I: In Pursuit of the Death
+ Angel [pq1]
+ Space Quest I: The Sarien Encounter [sq1]
+ Space Quest II: Vohaul's Revenge [sq2]
+ Hry od fanoušků [agi-fanmade]
+ Mickey's Space Adventure [mickey]
+ Troll's Tale [troll]
+ Winnie the Pooh in the Hundred Acre Wood [winnie]
+
+Hry od Sierra Entertainment (SCI):
Castle of Dr. Brain [castlebrain]
Codename: ICEMAN [iceman]
Conquests of Camelot [camelot]
@@ -316,19 +287,64 @@ Hry SCI od Sierra Entertainment: Space Quest V [sq5]
The Island of Dr. Brain [islandbrain]
-Hry Wintermute:
+Dalšà hry:
+ 3 Skulls of the Toltecs [toltecs]
+ Amazon: Guardians of Eden [access]
+ Beavis and Butt-head in Virtual Stupidity [bbvs]
+ Blue Force [blueforce]
+ Broken Sword: The Return of the Templars [sword25]
+ Bud Tucker in Double Trouble [tucker]
Chivalry is Not Dead [chivalry]
-
-Hry ZVISION od Activision:
- Zork Nemesis: The Forbidden Lands [znemesis]
+ Cruise for a Corpse [cruise]
+ DreamWeb [dreamweb]
+ Discworld [dw]
+ Discworld 2: Missing Presumed ...!? [dw2]
+ Dragon History [draci]
+ Drascula: The Vampire Strikes Back [drascula]
+ Eye of the Beholder [eob]
+ Eye of the Beholder II: The Legend of
+ Darkmoon [eob2]
+ Flight of the Amazon Queen [queen]
+ Future Wars [fw]
+ Hopkins FBI [hopkins]
+ Hugo's House of Horrors [hugo1]
+ Hugo 2: Whodunit? [hugo2]
+ Hugo 3: Jungle of Doom [hugo3]
+ I Have No Mouth, and I Must Scream [ihnm]
+ Inherit the Earth: Quest for the Orb [ite]
+ Lands of Lore: The Throne of Chaos [lol]
+ Mortville Manor [mortevielle]
+ Nippon Safes Inc. [nippon]
+ Rex Nebular and the Cosmic Gender Bender [nebular]
+ Ringworld: Revenge Of The Patriarch [ringworld]
+ Return to Ringworld [ringworld2]
+ Sfinx [sfinx]
+ Soltys [soltys]
+ The Journeyman Project: Pegasus Prime [pegasus]
+ The Legend of Kyrandia [kyra1]
+ The Legend of Kyrandia: The Hand of Fate [kyra2]
+ The Legend of Kyrandia: Malcolm's Revenge [kyra3]
+ The Lost Files of Sherlock Holmes: The Case
+ of the Serrated Scalpel [scalpel]
+ The Lost Files of Sherlock Holmes: The Case
+ of the Rose Tattoo [rosetattoo]
+ The Neverhood [neverhood]
+ The 7th Guest [t7g]
+ TeenAgent [teenagent]
+ Toonstruck [toon]
+ Tony Tough and the Night of Roasted Moths [tony]
+ Touche: The Adventures of the Fifth
+ Musketeer [touche]
+ Voyeur [voyeur]
Zork: Grand Inquisitor [zgi]
+ Zork Nemesis: The Forbidden Lands [znemesis]
-Hry SCUMM od Humongous Entertainment:
+Hry od Humongous Entertainment (SCUMM):
Backyard Baseball [baseball]
Backyard Baseball 2001 [baseball2001]
Backyard Baseball 2003 [baseball2003]
Backyard Football [football]
- Backyard Football 2002 [football2002]
+ Backyard Football 2002 [football2002]
Bear Stormin' [brstorm]
Big Thinkers First Grade [thinker1]
Big Thinkers Kindergarten [thinkerk]
@@ -354,7 +370,7 @@ Hry SCUMM od Humongous Entertainment: Let's Explore the Airport with Buzzy [airport]
Let's Explore the Farm with Buzzy [farm]
Let's Explore the Jungle with Buzzy [jungle]
- Pajama Sam: Games to Play on Any Day [pjgames]
+ Pajama Sam: Games to Play on Any Day [pjgames]
Pajama Sam 1: No Need to Hide When It's
Dark Outside [pajama]
Pajama Sam 2: Thunder and Lightning
@@ -363,12 +379,12 @@ Hry SCUMM od Humongous Entertainment: From Your Head to Your Feet [pajama3]
Pajama Sam's Lost & Found [lost]
Pajama Sam's Sock Works [socks]
- Putt-Putt Joins the Parade [puttputt]
+ Putt-Putt Enters the Race [puttrace]
Putt-Putt Goes to the Moon [puttmoon]
+ Putt-Putt Joins the Circus [puttcircus]
+ Putt-Putt Joins the Parade [puttputt]
Putt-Putt Saves the Zoo [puttzoo]
Putt-Putt Travels Through Time [putttime]
- Putt-Putt Enters the Race [puttrace]
- Putt-Putt Joins the Circus [puttcircus]
Putt-Putt and Pep's Balloon-O-Rama [balloon]
Putt-Putt and Pep's Dog on a Stick [dog]
Putt-Putt & Fatty Bear's Activity Pack [activity]
@@ -387,6 +403,29 @@ Pokud chcete mÃt nejnovÄ›jÅ¡Ã zprávy o kompatibilitách her, navÅ¡tivte naÅ¡Ã Backyard Soccer 2004 [soccer2004]
Blue's Treasure Hunt [BluesTreasureHunt]
+Hry Composer od Animation Magic:
+ Darby the Dragon [darby]
+ Gregory and the Hot Air Balloon [gregory]
+ Magic Tales: Liam Finds a Story [liam]
+ The Princess and the Crab [princess]
+ Sleeping Cub's Test of Courage [sleepingcub]
+
+Hry Living Books:
+ Aesop's Fables: The Tortoise and the Hare [tortoise]
+ Arthur's Birthday [arthurbday]
+ Arthur's Teacher Trouble [arthur]
+ Dr. Seuss's ABC [seussabc]
+ Green Eggs and Ham [greeneggs]
+ Harry and the Haunted House [harryhh]
+ Just Grandma and Me [grandma]
+ Little Monster at School [lilmonster]
+ Ruff's Bone [ruff]
+ Sheila Rae, the Brave [sheila]
+ Stellaluna [stellaluna]
+ The Berenstain Bears Get in a Fight [bearfight]
+ The Berenstain Bears in the Dark [beardark]
+ The New Kid on the Block [newkid]
+
NásledujÃcà hry jsou odvozeny od jádra SCUMM, ale ScummVM je nepodporuje (zatÃm):
Moonbase Commander
@@ -422,95 +461,122 @@ ScummVM pÅ™eskakuje ochranu v následujÃcÃch hrách: * Waxworks
* Zak McKracken and the Alien Mindbenders
-3.2) Poznámky ke hře Day of the Tentacle:
------------------------------------------
-Na jednom mÃstÄ› ve hÅ™e narazÃte na poÄÃtaÄ umožňujÃcà si zahrát původnÃ
-Maniac Mansion jako bonus. ScummVM toto podporuje, ale je třeba
-upozornit na pár vÄ›cÃ:
+3.2) Datové soubory
+---- --------------
+Pro přehledný seznam požadovaných datových souborů u podporovaných her navštivte:
-ScummVM prohledá váš soubor s nastavenÃm hledajÃc hru nacházejÃcà se
-v podsložce 'Maniac' ve složce hry Day of the Tentacle. Pokud jste
-zkopÃrovali datové soubory z CD verze, tato struktura by již mÄ›la být
-vytvoÅ™ena, navÃc ale budete muset hru pÅ™idat také do ScummVM.
+<http://wiki.scummvm.org/index.php/Datafiles>
-Pro návrat do Day of the Tentacle, stisknÄ›te F5 a zvolte "Návrat do spouÅ¡tÄ›Äe".
-Teoreticky toto znamená, že je možné spustit jakoukoli hru jako bonus.
-Vskutku tomu tak je. Existuje "tajná" volba nastavenÃ, "easter_egg", která
-mÄ›nà ID spouÅ¡tÄ›né hry. BuÄte ale opatrnÃ, protože ne vÅ¡echny hry podporujÃ
-návrat do spouÅ¡tÄ›Äe, a nedoporuÄuje se nastavovat spuÅ¡tÄ›nà samotné hry Day
-of the Tentacle jako bonus.
-
-3.3) Poznámky ke hrám Commodore64:
----- -----------------------------
-Jak Maniac Mansion tak Zak McKracken mohou být spuštěny, ale Maniac Mansion nenà ještě hratelný. Jednoduše pojmenujte disky D64 jako
-"maniac1.d64" a "maniac2.d64" nebo "zak1.d64" a "zak2.d64", pak by měl ScummVM automaticky hru zjistit, pokud ho odkážete na správnou složku.
+3.3) Poznámky ke hrám Multi-CD:
+---- --------------------------
+ObecnÄ› ScummVM moc dobÅ™e nefunguje s hrami na Multi-CD. To je proto, že ScummVM pÅ™edpokládá, že vÅ¡echno o hÅ™e může být nalezeno v jedné složce. I když ScummVM má schopnost požádat uživatele, aby vymÄ›nil CD, původnà spouÅ¡tÄ›Ä souboru vÄ›tÅ¡inou nainstaluje malé množstvà souborů na pevný disk. Pokud tyto soubory nelze najÃt na vÅ¡ech CD, ScummVM bude mÃt potÞe.
-Nebo můžete použÃt 'extract_mm_c64' z balÃÄku nástrojů pro extrahovánà datových souborů. Pak ale ScummVM hru řádnÄ› automaticky nezjistà ScummVM, a musÃte se ujistit, že platforma je nastavena na Commodore64. DoporuÄujeme použÃt mnohem jednoduÅ¡Å¡Ã postup popsaný v pÅ™edchozÃm odstavci.
+NaÅ¡tÄ›stà může ScummVM hry bez problémů spouÅ¡tÄ›t pÅ™Ãmo z pevného disku, pokud vytvoÅ™Ãte složku se správnou kombinacà souborů. VÄ›tÅ¡inou, když se soubor objevà na vÃce, než jednom CD můžete vybrat jeden z nich.
-3.4) Poznámky ke Maniac Mansion NES:
----- -------------------------
-Podporované verze jsou Britská angliÄtina (E), FrancouzÅ¡tina (F), NÄ›mÄina (G), ItalÅ¡tina (I), Å védÅ¡tina (SW) a Americká angliÄtina (U). ScummVM pro spuÅ¡tÄ›nà vyžaduje pouze Äást PRG a ne celý ROM.
+3.4) Známé Problémy:
+---- ---------------
+Toto vydánà má následujÃcà známé problémy. Nenà tÅ™eba je ohlaÅ¡ovat, i když záplaty pro jejich opravu jsou vÃtány. Pokud objevÃte chybu, která nenà zde v seznamu, ani nenà v seznamu kompatibility na internetové stránce, prohlédnÄ›te si, prosÃm, Äást o hlášenà chyb.
-Abyste mohli hru spustit, musÃte vyjmout prvnÃch 16 bajtů z ROM, s kterým pracujete. Jakýkoli hex editor bude fungovat, pokud můžete kopÃrovat/vkládat. Poté. Co ROM otevÅ™ete pomocà hex editoru, zkopÃrujte vÅ¡echno z druhého řádku (17. bajt) na konec. Poté, co toto provedete, vložte ho do nového hex souboru. Pojmenujte ho "Maniac Mansion (XX).prg" kde XX znamená verzi, se kterou pracujete (E, F, G, I, SW, nebo U). KoneÄná velikost by mÄ›la být pÅ™esnÄ› 262144 bajtů.
+ Hry CD Audio:
+ - PÅ™i hranà her, které použÃvajà CD Audio (hry FM-TOWNS, Loom CD, atd) může u uživatelů Microsoft Windows 2000/XP docházet k náhodným pádům. To je dÃky dlouhotrvajÃcà chybÄ› Windows, která má za následek poÅ¡kozené soubory
+ pÅ™i Ätenà z CD. Abyste se tomuto vyhnuli, zkopÃrujte, prosÃm, soubory na pevný disk
-Pokud hru pÅ™idáváte ruÄnÄ›, ujistÄ›te se, že platforma je nastavena na NES.
+ Verze FM-TOWNS:
+ - Verze Kandži vyžaduje ROM pÃsma FM-TOWNS
-Nejběžnějšà chyby, které zabraňujà spuštěnà hry:
+ Loom:
+ - Vypnutà titulků pomocà souboru nastavenà je nevypne spolehlivě, protože skripty Loom je znovu automaticky zapnou
+ - Podpora MIDI ve verzi EGA vyžaduje aktualizaci Roland LucasArts
+ - Verze Kandži na PC-Engine vyžaduje rom systémové karty
- * Špatný soubor
- * ROM byl extrahován pomocà nástrojů z verze 0.7.0
- * SnažÃte se do ScummVM vkládat CELà ROM a ne jenom PRG Äást.
+ The Secret of Monkey Island:
+ - Podpora MIDI ve verzi EGA vyžaduje aktualizaci Roland LucasArts
-Je také možno extrahovat oddÄ›lené soubory LFL z PRG Äásti. Pro toto použijte nástroj 'extract_mm_nes' z balÃÄku nástrojů.
+ Beneath a Steel Sky:
+ - Verze pro Amiga nejsou podporovány
+ - Demoverze z diskety nejsou podporovány
+ - Nenà chyba: Ve verzi na CD chybà v jistých dialozÃch Å™eÄ, to je normálnÃ.
+ Elvira - Mistress of the Dark:
+ - Ve verzi pro Atari ST nefunguje hudba
-3.5) Poznámky ke hrám Macintosh:
----- ---------------------------
-VÅ¡echny adventury LucasArts založené na SCUMM, kromÄ› COMI, také existujà ve verzÃch pro in Macintosh. ScummVM může vÄ›tÅ¡inu (vÅ¡echny?) použÃt, nicménÄ›, v nÄ›kterých pÅ™Ãpadech je nutná dodateÄná práce. NejdÅ™Ãve, pokud pro toto nepoužÃváte Macintosh, pÅ™Ãstup k datům na CD/disketÄ› může být obtÞný. Důvodem je to, že Mac použÃvá zvláštnà formát disku nazvaný HFS, který ostatnà systémy vÄ›tÅ¡inou nepodporujÃ. NicménÄ› existuje, nÄ›kolik nástrojů, které jsou zadarmo a umožňujà ÄÃst takovéto svazky HFS. NapÅ™Ãklad "HFVExplorer" pro Windows a "hfsutils" pro Linux a ostatnà Unixové operaÄnà systémy.
+ Elvira II - The Jaws of Cerberus:
+ - Ve verzi pro Atari ST nefunguje hudba
+ - Ve verzi pro PC nefungujà zvukové efekty
+ - Ve verzi pro Atari ST jsou problémy s paletou
-VÄ›tÅ¡ina novÄ›jÅ¡Ãch her na Macintosh je dodávána pouze s jednÃm datovým souborem (v nÄ›kterých pÅ™Ãpadech byl tento soubor uÄinÄ›n neviditelným, takže možná budete potÅ™ebovat dodateÄné nástroje, abyste ho mohli zkopÃrovat). ScummVM je schopen takovýto soubor použÃt pÅ™Ãmo; jednoduÅ¡e odkažte ScummVM na složku obsahujÃcà tento soubor a mÄ›lo by to fungovat (tak jako s každou podporovanou hrou).
+ Inherit the Earth: Quest for the Orb:
+ - Verze pro Amiga nejsou podporovány
-V balÃÄku nástrojů také poskytujeme nástroj nazvaný 'extract_scumm_mac', který extrahuje data z tÄ›chto datových souborů, ale toto nenà ani potÅ™eba, ani doporuÄeno.
+ Lure of the Temptress:
+ - Žádná podpora Roland MT-32
+ - Podpora zvuku nenà dokonÄena a neznà jako v původnà hÅ™e
-Pro dalÅ¡Ã informace o kopÃrovánà hernÃch souborů Macintosh na Váš pevný disk si prohlédnÄ›te:
+ Simon the Sorcerer 1:
+ - V anglických a nÄ›meckých verzÃch na CD nejsou titulky dostupné, protože jim vÄ›tÅ¡ina titulků chybÃ.
- http://wiki.scummvm.org/index.php/HOWTO-Mac_Games
+ Simon the Sorcerer 2:
+ - Kombinace Å™eÄi a titulků Äasto způsobÃ, že Å™eÄ je pÅ™eruÅ¡ena brzo, toto je omezenà původnà hry.
+ - Ve verzÃch pro Amiga a Macintosh je podporován pouze výchozà jazyk datových souborů (angliÄtina).
+ Simon the Sorcerer's Puzzle Pack:
+ - Žádná podpora pro zobrazovánÃ, zadávánÃ, ukládánÃ, Äi naÄÃtánà nejvyÅ¡Å¡Ãch skóre.
+ - Žádná podpora pro zobrazovánà názvů položek, když na ně najedete myšà ve Swampy Adventures.
-3.6) Poznámky ke hrám Multi-CD:
----- --------------------------
-ObecnÄ› ScummVM moc dobÅ™e nefunguje s hrami na Multi-CD. To je proto, že ScummVM pÅ™edpokládá, že vÅ¡echno o hÅ™e může být nalezeno v jedné složce. I když ScummVM má schopnost požádat uživatele, aby vymÄ›nil CD, původnà spouÅ¡tÄ›Ä souboru vÄ›tÅ¡inou nainstaluje malé množstvà souborů na pevný disk. Pokud tyto soubory nelze najÃt na vÅ¡ech CD, ScummVM bude mÃt potÞe.
+ The Feeble Files:
+ - Titulky jsou Äasto nedokonÄené. V původnà hÅ™e byly vždy zakázány.
-NaÅ¡tÄ›stà může ScummVM hry bez problémů spouÅ¡tÄ›t pÅ™Ãmo z pevného disku, pokud vytvoÅ™Ãte složku se správnou kombinacà souborů. VÄ›tÅ¡inou, když se soubor objevà na vÃce, než jednom CD můžete vybrat jeden z nich.
+ The Legend of Kyrandia:
+ - Ve verzÃch na disketÄ› pro Mac nenà žádná hudba ani zvukové efekty.
+ - CD Macintosh použÃvá zahrnutou hudbu a zvukové efekty z DOS.
+ Hry Humongous Entertainment:
+ - Pouze původnà rozhranà pro uloženà a naÄtenà mohou být použity.
+ - Žádná podpora pro hru vÃce hráÄů nebo tisknutà obrázků
-3.7) Poznámky k The Curse of Monkey Island:
----- --------------------------------------
-Pro tuto hru budete potřebovat soubory comi.la0, comi.la1 a comi.la2.
-Soubor comi.la0 můžete nalézt na vÅ¡ech CD hry, ale protože jsou stejné, můžete použÃt kterýkoli z nich.
-Dále potÅ™ebujete vytvoÅ™it podsložku "resource" obsahujÃcà vÅ¡echny soubory z –obou- podsložek "resource" na dvou CD. NÄ›které soubory se objevujà na obou CD, ale znovu jsou stejné.
+3.5) Poznámky k Beneath a Steel Sky:
+---- -------------------------------
+Od ScummVM 0.8.0 potÅ™ebujete dodateÄný soubor 'SKY.CPT', abyste mohli Beneath a Steel Sky spustit.
+
+Tento soubor je dostupný na stránce 'Downloads' domovské stránky ScummVM.
+Můžete ho umÃstit buÄ do složky obsahujÃcà ostatnà datové soubory (SKY.DNR, SKY.DSK), na VaÅ¡i dodateÄnou cestu, nebo do složky. Kde se nacházà spouÅ¡tÄ›cà soubor ScummVM.
-3.8) Poznámky ke hrám Broken Sword:
+3.6) Poznámky ke hrám Broken Sword:
---- ------------------------------
Pokyny pro hry Broken Sword jsou pro verze od Sold-Out Software, kde každá hra je na dvou CD, protože tyto verze byly nejdostupnÄ›jÅ¡Ã v dobÄ›, kdy je ScummVM zaÄal podporovat. Doufáme, že jsou dostateÄnÄ› obecné pro použità i v jiných vydánÃch her.
-3.8.1) Videa z her Broken Sword:
+3.6.1) Broken Sword:
+------ -------------
+Pro tuto hru budete potÅ™ebovat vÅ¡echny soubory ze seskupenà složek na obou CD. Pro verze Windows a Macintosh budete také potÅ™ebovat soubory speech.clu ze složek speech, ale protože soubory nejsou stejné, budete je muset pÅ™ejmenovat na speech1.clu a speech2.clu z CD 1 a 2 v tomto poÅ™adÃ. Verze na PlayStation vyžaduje speech.tab, speech.dat, speech.lis, a speech.inf.
+
+Dále verze pro Windows a Macintosh vyžadujà podsložku music se vÅ¡emi soubory z podsložek music na obou CD. NÄ›které z tÄ›chto souborů se objevujà na obou CD, ale v tÄ›chto pÅ™Ãpadech jsou buÄ stejné, nebo, v jednom pÅ™ÃpadÄ›, je téměř stejný, že to nemá žádný význam. Verze pro PlayStation vyžaduje tunes.dat a tunes.tab.
+
+
+3.6.2) Broken Sword II:
+------ ----------------
+Pro tuto hru budete potřebovat všechny soubory ze seskupenà složek na obou CD. (Abych pravdu řekl, pár z nich nemusà být nezbytně nutné, ale ty, o kterých nemám jistotu, jsou velmi malé.)
+Je také tÅ™eba pÅ™ejmenovat soubory speech.clu a music.clu na speech1.clu, speech2.clu, music1.clu a music2.clu, aby ScummVM mohl zjistit, které jsou z CD 1 a které z CD 2. VÅ¡echny ostatnà soubory, které jsou umÃstÄ›ny v seskupenà složek, jsou stejné. Použijte kterékoli soubory chcete.
+
+KromÄ› toho budete potÅ™ebovat soubory cd.inf a, pÅ™ÃpadnÄ›, startup.inf ze složky sword2 na CD 1.
+
+
+3.6.3) Videa z her Broken Sword:
------ -------------------------
Videa pro hry Broken Sword majà v sobÄ› trochu historie (viz dalÅ¡Ã oddÃl, pokud jste zvÄ›davÃ), ale obecnÄ› jediné, co potÅ™ebujete udÄ›lat, je zkopÃrovat soubory .SMK ze složek "SMACKS" nebo "SMACKSHI" na CD do stejné složky jako ostatnà datové soubory hry. (Broken Sword má také složku "SMACKSLO" se stejnými videi, ale ty jsou nižšà kvality.) Můžete je umÃstit do podsložky s názvem "video", pokud Vám to pÅ™ijde hezÄÃ.
Ve verzÃch pro PlayStation, můžete původnà videa vypsat z disku. Každý soubor, který má pÅ™Ãponu "STR", byste mÄ›li vypsat jako *Äist* sektory z disku (vÅ¡ech 2352 bajtů na sektor). Můžete také mÃst toho použÃt pÅ™eformátovaná videa, která jsou zmÃnÄ›na nÞe, ale to nebude fungovat pro vÅ¡echny videa v Broken Sword II. Pro vÃce informacà si prohlédnÄ›te:
- http://wiki.scummvm.org/index.php/HOWTO-PlayStation_Videos
+ <http://wiki.scummvm.org/index.php/HOWTO-PlayStation_Videos>
NÄ›která vydánà hry, a také verze pro PlayStation, Smacker videa nemajÃ. Revolution Software nám laskavÄ› dovolilo poskytovat pÅ™eformátovaná videa ke staženà na naÅ¡Ã stránce:
- http://www.scummvm.org/downloads.php
+ <http://www.scummvm.org/downloads.php>
Tato videa jsou poskytována ve formátu DXA se zvukem ve formátu FLAC. Jejich kvalita se rovná originálu dÃky použità bezztrátové komprese. Zobrazenà tÄ›chto videà vyžaduje, aby verze ScummVM byla sestavena s podporou FLAC i zlib.
@@ -519,7 +585,7 @@ Pro systémy, které jsou pÅ™ÃliÅ¡ pomalé, aby zvládli dekódovat formát FLA Pro Broken Sword také poskytujeme pÅ™Ãdavek pro titulky. JednoduÅ¡e ho rozbalte a následujte pokyny v souboru readme.txt. BalÃÄek v souÄasnosti nefunguje ve videÃch na PlayStation. (Broken Sword II již titulky má; nenà tÅ™eba dalÅ¡Ã práce pro jejich pÅ™idánÃ.)
-3.8.2) Videa her Broken Sword ve zpětném pohledu:
+3.6.4) Videa her Broken Sword ve zpětném pohledu:
------ ------------------------------------------
Původnà vydánà her Broken Sword použÃvalo formát Smackerâ„¢ od RAD Game Tools. Protože spoleÄnost RAD nebyla ochotna nám otevÅ™Ãt starÅ¡Ã zastaralé verze tohoto formátu a požádala, abychom neprovádÄ›li jeho zpÄ›tnou analýzu, museli jsme nalézt jiné Å™eÅ¡enÃ.
@@ -531,49 +597,59 @@ Ve ScummVM 0.6.0 jsme použÃvali MPEG, což zajistilo rozumný kompromis mezi v Nakonec na zaÄátku roku 2006 byl formát Smacker zpÄ›tnÄ› analyzován pro projekt FFmpeg. DÃky jejich tvrdé práci ScummVM 1.0.0 nynà podporuje původnà videa. Zároveň byla ukonÄena podpora MPEG. Z technického hlediska je toto dobÅ™e, protože pÅ™ehrávánà videà MPEG bylo velmi složité a stejnÄ› nevypadaly tak dobÅ™e jako verze ve formátu DXA a Smacker.
-3.8.3) Broken Sword:
------- -------------
-Pro tuto hru budete potÅ™ebovat vÅ¡echny soubory ze seskupenà složek na obou CD. Pro verze Windows a Macintosh budete také potÅ™ebovat soubory speech.clu ze složek speech, ale protože soubory nejsou stejné, budete je muset pÅ™ejmenovat na speech1.clu a speech2.clu z CD 1 a 2 v tomto poÅ™adÃ. Verze na PlayStation vyžaduje speech.tab, speech.dat, speech.lis, a speech.inf.
+3.7) Poznámky k Day of the Tentacle:
+---- -------------------------------
-Dále verze pro Windows a Macintosh vyžadujà podsložku music se vÅ¡emi soubory z podsložek music na obou CD. NÄ›které z tÄ›chto souborů se objevujà na obou CD, ale v tÄ›chto pÅ™Ãpadech jsou buÄ stejné, nebo, v jednom pÅ™ÃpadÄ›, je téměř stejný, že to nemá žádný význam. Verze pro PlayStation vYžaduje tunes.dat a tunes.tab.
+Na jednom mÃstÄ› ve hÅ™e narazÃte na poÄÃtaÄ umožňujÃcà si zahrát původnà Maniac Mansion jako bonus. ScummVM toto podporuje, ale je tÅ™eba upozornit na pár vÄ›cÃ:
+ScummVM prohledá váš soubor s nastavenÃm hledajÃc hru nacházejÃcà se v podsložce 'Maniac' ve složce hry Day of the Tentacle. Pokud jste zkopÃrovali datové soubory z CD verze, tato struktura by již mÄ›la být
+vytvoÅ™ena, navÃc ale budete muset hru pÅ™idat také do ScummVM.
-3.8.4) Broken Sword II:
------- ----------------
-Pro tuto hru budete potřebovat všechny soubory ze seskupenà složek na obou CD. (Abych pravdu řekl, pár z nich nemusà být nezbytně nutné, ale ty, o kterých nemám jistotu, jsou velmi malé.)
-Je také třeba přejmenovat soubory speech.clu a music.clu na speech1.clu,
-speech2.clu, music1.clu a music2.clu, aby ScummVM mohl zjistit, které jsou z CD 1 a které z CD 2. VÅ¡echny ostatnà soubory, které jsou umÃstÄ›ny v seskupenà složek, jsou stejné. Použijte kterékoli soubory chcete.
+Pro návrat do Day of the Tentacle, stisknÄ›te F5 a zvolte "Návrat do spouÅ¡tÄ›Äe".
-KromÄ› toho budete potÅ™ebovat soubory cd.inf a, pÅ™ÃpadnÄ›, startup.inf ze složky sword2 na CD 1.
+Teoreticky toto znamená, že je možné spustit jakoukoli hru jako bonus. Vskutku tomu tak je. Existuje "tajná" volba nastavenÃ, "easter_egg", která mÄ›nà ID spouÅ¡tÄ›né hry. BuÄte ale opatrnÃ, protože ne vÅ¡echny hry podporujÃ
+návrat do spouÅ¡tÄ›Äe, a nedoporuÄuje se nastavovat spuÅ¡tÄ›nà samotné hry Day of the Tentacle jako bonus.
-3.9) Poznámky k Beneath a Steel Sky:
----- -------------------------------
-Od ScummVM 0.8.0 potÅ™ebujete dodateÄný soubor 'SKY.CPT', abyste mohli Beneath a Steel Sky spustit.
+3.8) Poznámky k Discworld II:
+---- ------------------------
-Tento soubor je dostupný na stránce 'Downloads' domovské stránky ScummVM.
-Můžete ho umÃstit buÄ do složky obsahujÃcà ostatnà datové soubory (SKY.DNR, SKY.DSK), na VaÅ¡i dodateÄnou cestu, nebo do složky. Kde se nacházà spouÅ¡tÄ›cà soubor ScummVM.
+Pro tuto hru potřebujete všechny soubory z podsložky DW2 na obou CD.
+Dále je tÅ™eba zkopÃrovat soubor SAMPLE.BNK.
+
+Je třeba přejmenovat soubory ENGLISH.SMP, ENGLISH.IDX a ENGLISH.TXT na CD1 na ENGLISH1.SMP, ENGLISH1.IDX a ENGLISH1.txt.
+To samé provést se soubory z CD2 a přejmenovat je na ENGLISH2.SMP, ENGLISH2.IDX a ENGLISH2.TXT.
+
+
+3.9) Poznámky k DraÄà Historie:
+---- --------------------------
+Existujà 4 jazykové varianty této hry: Äeská, anglická, polská a nÄ›mecká. Každá je umÃstÄ›na v oddÄ›leném archivu. Jediná oficiálnà verze je Äeská, a anglická, polská a nÄ›mecká byly vždycky nedokonÄené práce a nikdy nebyly oficiálnÄ› vydány. I když texty byly zcela pÅ™eloženy, je známo, že nÄ›které z nich obsahujà pÅ™eklepy.
+
+Pro tuto hru existuje nepovinný Äeský dabing. Z důvodu velikosti si ho můžete dodateÄnÄ› stáhnout a pak ho rozbalit do adresáře hry. Můžete také Äeský dabing poslouchat se vÅ¡emi jazykovými varianty hry, zatÃmco Ätete titulky.
+
+Všechny hernà soubory a návody můžou být staženy z:
+
+<http://www.ucw.cz/draci-historie/index-en.html>
3.10) Poznámky k Flight of the Amazon Queen:
----- --------------------------------------
-Abyste mohli použÃt tu verzi, která nenà volnÄ› Å¡iÅ™itelná
-(z původnÃho CD), musÃte mÃt soubor 'queen.tbl'
-(dostupný ze stránky 'Downloads' naÅ¡Ã domovské stránky) a umÃstit ho buÄ do složky obsahujÃcà soubor hry 'queen.1', na VaÅ¡i dodateÄnou cestu, nebo do složky. Kde se nacházà spouÅ¡tÄ›cà soubor ScummVM.
+----- --------------------------------------
+Abyste mohli použÃt tu verzi, která nenà volnÄ› Å¡iÅ™itelná (z původnÃho CD), musÃte mÃt soubor 'queen.tbl' (dostupný ze stránky 'Downloads' naÅ¡Ã domovské stránky) a umÃstit ho buÄ do složky obsahujÃcà soubor hry 'queen.1',
+na VaÅ¡i dodateÄnou cestu, nebo do složky. Kde se nacházà spouÅ¡tÄ›cà soubor ScummVM.
Také můžete použÃt nástroj 'compress_queen' z balÃÄku nástrojů pro 'znovu sestavenÃ' VaÅ¡eho datového souboru FOTAQ pro zahrnutà tabulky pro tuto konkrétnà verzi, ÄÃmž odstranÃte závislost na soubor 'queen.tbl' pÅ™i spuÅ¡tÄ›nÃ. Tento nástroj Vám také umožňuje komprimovat Å™eÄ a zvukové efekty do formátu MP3, OGG nebo FLAC.
3.11) Poznámky ke Gobliiins:
----- ----------------------
-CD verze série Gobliiins obsahuje jednu velkou zvukovou stopu, kterou potÅ™ebujete vyjmout (viz oddÃl o použità komprimovaných zvukových souborů) a zkopÃrovat ji do hernà složky, pokud chcete ve hÅ™e hudbu, aniž byste museli CD mÃt stále v jednotce. V této stopÄ› jsou také Å™eÄ a jejà hlasitost se tedy také mÄ›nà podle hlasitosti hudby.
+CD verze série Gobliiins obsahuje jednu velkou zvukovou stopu, kterou je tÅ™eba vyjmout (viz oddÃl o použità komprimovaných zvukových souborů) a zkopÃrovat ji do hernà složky, pokud chcete ve hÅ™e hudbu, aniž byste museli CD mÃt stále v jednotce. V této stopÄ› je také Å™eÄ a jejà hlasitost se tedy také mÄ›nà podle hlasitosti hudby.
3.12) Poznámky k Inherit the Earth: Quest for the Orb:
----- ------------------------------------------------
Abyste mohli spustit verzi pro Mac OS X od Wyrmkeep musÃte data zkopÃrovat z CD na Váš pevný disk. Pokud použÃváte PC, pak se podÃvejte na:
- http://wiki.scummvm.org/index.php/HOWTO-Mac_Games
+ <http://wiki.scummvm.org/index.php/HOWTO-Mac_Games>
I když se v tomto Älánku pÃÅ¡e hlavnÄ› o hrách SCUMM, je zde také zmÃnÄ›n nástroj "HFVExplorer", který potÅ™ebujete k extrakci souborů. Nezapomeňte, že data Å™eÄi "Inherit the Earth Voices" musÃte umÃstit do stejného adresáře, kde jsou uložena data hry:
@@ -582,13 +658,64 @@ I když se v tomto Älánku pÃÅ¡e hlavnÄ› o hrách SCUMM, je zde také zmÃnÄ› Ve staré verzi pro Mac OS 9 potÅ™ebujete soubory zkopÃrovat ve formátu MacBinary, protože by mÄ›li obsahovat jak zdrojové, tak datové vidlice. ZkopÃrujte vÅ¡echny soubory 'ITE *'.
-3.13) Poznámky k Simon the Sorcerer 1 a 2:
+3.13) Poznámky ke Maniac Mansion na Apple II/NES:
+----- -------------------------------------------
+Apple II:
+Je třeba přejmenovat obraz disku 1 na maniac1.dsk
+Je třeba přejmenovat obraz disku 2 na maniac2.dsk
+
+NES:
+Podporované verze jsou Britská angliÄtina (E), FrancouzÅ¡tina (F), NÄ›mÄina (G), ItalÅ¡tina (I), Å védÅ¡tina (SW) a Americká angliÄtina (U). ScummVM pro spuÅ¡tÄ›nà vyžaduje pouze Äást PRG a ne celý ROM.
+
+Abyste mohli hru spustit, musÃte vyjmout prvnÃch 16 bajtů z ROM, s kterým pracujete. Jakýkoli hex editor bude fungovat, pokud můžete kopÃrovat/vkládat. Poté. Co ROM otevÅ™ete pomocà hex editoru, zkopÃrujte vÅ¡echno z druhého řádku (17. bajt) na konec. Poté, co toto provedete, vložte ho do nového hex souboru. Pojmenujte ho "Maniac Mansion (XX).prg" kde XX znamená verzi, se kterou pracujete (E, F, G, I, SW, nebo U). KoneÄná velikost by mÄ›la být pÅ™esnÄ› 262144 bajtů.
+
+Pokud hru pÅ™idáváte ruÄnÄ›, ujistÄ›te se, že platforma je nastavena na NES.
+
+Nejběžnějšà chyby, které zabraňujà spuštěnà hry:
+
+ * Špatný soubor
+ * ROM byl extrahován pomocà nástrojů z verze 0.7.0
+ * SnažÃte se do ScummVM vkládat CELà ROM a ne jenom PRG Äást.
+
+Je také možno extrahovat oddÄ›lené soubory LFL z PRG Äásti. Pro toto použijte nástroj 'extract_mm_nes' z balÃÄku nástrojů.
+
+
+3.14) Poznámky k Mickey's Space Adventure:
+----- ------------------------------------
+Abyste mohli Mickey's Space Adventure hrát ve ScummVM, potÅ™ebujete spolu s datovými soubory hry také původnà spouÅ¡tÄ›Ä (mickey.exe).
+
+Pro tuto hru ve ScummVM, existuje rozÅ¡ÃÅ™ená podpora myÅ¡i, i když v původnà hÅ™e takováto podpora nebyla. Položky menu mohou být vybrány pomocà myÅ¡i a je také možné se myÅ¡Ã pÅ™esunout do jiných mÃst. Když se kurzor myÅ¡i nacházà na okraji obrazovky, zÄervená, pokud je možné jÃt v tomto smÄ›ru. HrÃ¡Ä pak může jednoduÅ¡e kliknout na okraje hernà obrazovky pro zmÄ›nu mÃsta, podobnÄ› jako mnoho adventur, což je jednoduÅ¡Å¡Ã a pÅ™ÃmoÄaÅ™ejÅ¡Ã než pohyb pomocà menu.
+
+
+3.15) Nippon Safes Inc. Amiga notes:
+----- ------------------------------
+Pro tuto hru potřebujete disk0, soubory global.table a pointer a it (en, fr, ge pro mezinárodnà verzi).
+
+Dále je třeba přejmenovat obraz disku 2 na disk1, obraz disku 3 na disk2, obraz disku 4 na disk3 a obraz disku 5 na disk4.
+
+
+3.16) Poznámky k Simon the Sorcerer 1 a 2:
----- ------------------------------------
Pokud máte dvojitou verzi Simon the Sorcerer 1 nebo 2 na CD, verzi pro Windows naleznete v hlavnà složce na CD a verzi pro DOS ve složce DOS na CD.
-3.14) Poznámky k The Feeble Files:
+3.17) Poznámky k The Curse of Monkey Island:
+----- --------------------------------------
+Pro tuto hru budete potřebovat soubory comi.la0, comi.la1 a comi.la2.
+Soubor comi.la0 můžete nalézt na vÅ¡ech CD hry, ale protože jsou stejné, můžete použÃt kterýkoli z nich.
+
+Dále potÅ™ebujete vytvoÅ™it podsložku "resource" obsahujÃcà vÅ¡echny soubory z –obou- podsložek "resource" na dvou CD. NÄ›které soubory se objevujà na obou CD, ale znovu jsou stejné.
+
+
+3.18) Poznámky k The Feeble Files:
----- ----------------------------
+Amiga/Macintosh:
+MusÃte nainstalovat malý balÃÄek videÃ, které chybà v obou tÄ›chto verzÃch této hry. Jmenuje se "The Feeble Files - Omni TV and epilogue cutscenes for the Amiga and Macintosh versions"
+a lze ho zÃskat zde:
+
+ <http://www.scummvm.org/games/#feeble>
+
+Windows:
Pokud máte verzi pro Windows, je tÅ™eba si uvÄ›domit pár vÄ›cÃ.
Mnoho souborů, které hra vyžaduje, je uloženo v souboru InstallShield s názvem data1.cab, který ScummVM nemůže rozbalit. Budete muset použÃt původnà instalátor, nebo i5comp pro rozbalenà obsahu tohoto souboru. Nástroj pro dekomprimaci i5comp může být nalezen pÅ™i hledánà na internetu.
@@ -599,7 +726,7 @@ Přejmenovat voices.wav na CD2 na voices2.wav Přejmenovat voices.wav na CD3 na voices3.wav
Přejmenovat voices.wav na CD4 na voices4.wav
-3.15) Poznámky k The Legend of Kyrandia:
+3.19) Poznámky k The Legend of Kyrandia:
----- ----------------------------------
Abyste mohli spustit The Legend of Kyrandia ve ScummVM potřebujete soubor 'kyra.dat'.
Soubor by mÄ›l být vždycky souÄástà oficiálnÃch balÃÄků ScummVM. V pÅ™ÃpadÄ›, že ScummVM
@@ -607,7 +734,20 @@ nahlásÃ, že soubor chybÃ, můžete ho najÃt na stránce ScummVM v sekci 'Do Nezapomeňte, že souÄasná verze ScummVM pro Windows by mÄ›la soubor obsahovat ve spouÅ¡tÄ›Äi a tudÞ ho
musÃte mÃt pouze, když ScummVM soubor nemůže nalézt.
-3.16) Poznámky k PÅ™edvÃdavému VstupnÃmu Dialogu her Sierra AGI:
+
+3.20) Poznámky k Troll's Tale:
+----- ------------------------
+Původnà hra vycházela na zavádÄ›cÃm disku PC, proto je nutné vypsat obsah tohoto disku jako obraz disku a pÅ™ejmenovat ho na "troll.img", abyste tuho hru mohli hrát ve ScummVM.
+
+
+3.21) Winnie the Pooh notes:
+----- ----------------------
+Je možné importovat uložené hry z původnà hry do ScummVM.
+
+Pro tuto hru ve ScummVM, existuje rozÅ¡ÃÅ™ená podpora myÅ¡i, i když v původnà hÅ™e takováto podpora nebyla. Položky menu mohou být vybrány pomocà myÅ¡i a je také možné se myÅ¡Ã pÅ™esunout do jiných mÃst. Když se kurzor myÅ¡i nacházà na okraji obrazovky, zÄervená, pokud je možné jÃt v tomto smÄ›ru. HrÃ¡Ä pak může jednoduÅ¡e kliknout na okraje hernà obrazovky pro zmÄ›nu mÃsta, podobnÄ› jako mnoho adventur, což je jednoduÅ¡Å¡Ã a pÅ™ÃmoÄaÅ™ejÅ¡Ã než pohyb pomocà menu.
+
+
+3.22) Poznámky k PÅ™edvÃdavému VstupnÃmu Dialogu her Sierra AGI:
----- ---------------------------------------------------------
PÅ™edvÃdavý Vstupnà Dialog je pomůcka ScummVM pro spouÅ¡tÄ›nà her použÃvajÃcà jádro AGI (který je znám, že vyžaduje vstup z pÅ™Ãkazové řádky) na zaÅ™ÃzenÃch s omezenou podporou klávesnice. V tÄ›chto situacÃch, kdy zadávánà pomocà emulované klávesnice je dosti únavné, můžou být pÅ™Ãkazy rychle a snadno zadány pomocà PÅ™edvÃdavého VstupnÃho Dialogu.
@@ -615,48 +755,19 @@ Abyste zapnuli pÅ™edvÃdavý vstup v hrách AGI, potÅ™ebujete zkopÃrovat soubor Pokud je slovnÃk zjiÅ¡tÄ›n, je PÅ™edvÃdavý Vstupnà Dialog zobrazen buÄ pÅ™i kliknutà na oblast pÅ™Ãkazového řádku (kdykoliv je požadován vstup klávesnice, i v rámeÄcÃch dialogových oken), nebo v nÄ›kterých verzÃch pro jiné systémy stisknutÃm urÄené klávesové zkratky.
-PÅ™edvÃdavý Vstupnà Dialog pracuje ve tÅ™ech režimech, které jsou pÅ™epÃnány tlaÄÃtkem (*)Pre/123/Abc. Hlavnà vstupnà metodou je pÅ™edvÃdavý režim
-(Pre), který pÅ™ipomÃná "rychlé zadávánÃ" v mobilnÃch telefonech.
+PÅ™edvÃdavý Vstupnà Dialog pracuje ve tÅ™ech režimech, které jsou pÅ™epÃnány tlaÄÃtkem (*)Pre/123/Abc. Hlavnà vstupnà metodou je pÅ™edvÃdavý režim
+(Pre), který pÅ™ipomÃná "rychlé zadávánÃ" v mobilnÃch telefonech.
Abeceda je rozdÄ›lena do 9 sad, které pÅ™irozenÄ› odpovÃdajà 9 klávesám ÄÃselné klávesnice (0 je mezera). Pro psanà slova zmáÄknÄ›te jednou ÄÃslo sady, která obsahuje pÃsmeno slova, které chcete napsat, pak pokraÄujete k dalÅ¡Ãmu. NapÅ™Ãklad, pokud chcete napsat pÅ™Ãkaz 'look', mÄ›li byste zmáÄknout 5665. Jak postupnÄ› pÃÅ¡ete ÄÃselný kód zamýšleného slova, je slovnÃk prohledáván pro známá slova, která se shodujà s VaÅ¡Ãm vstupem až do tohoto bodu. Jak maÄkáte vÃce kláves, slovnÃk se pÅ™iblÞà ke správnému slovu. To je důvod, proÄ vypsané slovo se může náhle zmÄ›nit mezi stisky kláves. NÄ›kdy se ale vyskytnou pÅ™Ãpady, kdy vÃce než jedno slovo má stejné ÄÃselné zastoupenÃ. NapÅ™Ãklad slova 'quit' a 'suit' odpovÃdajà stejným ÄÃslům, a to 7848. V tÄ›chto pÅ™Ãpadech se rozsvÃtà tlaÄÃtko dalÅ¡Ã
(#). Jeho stisknutÃm můžete procházet seznam slov, která sdÃlejà stejný kód a nakonec pÅ™ijmout to správné stisknutÃm (0)mezera nebo tlaÄÃtka Ok.
Druhou vstupnà metodou (123) je ÄÃselný vstup: Každou klávesu, kterou stisknÄ›te, je doslova zadána jako ÄÃslo.
-
+
TÅ™età vstupnà metodou (Abc) je vstupnà režim Alfa/opakovaného stisknutà tlaÄÃtka. Tento režim je urÄen pro zadávánà textu bez pomoci od slovnÃku pÅ™edvÃdavého režimu (Pre). Text je zadáván po jednotlivých pÃsmenech. Pro každé pÃsmeno nejdÅ™Ãve stisknÄ›te ÄÃslo sady, které obsahuje pÃsmeno, které chcete, pak použijte tlaÄÃtko dalÅ¡Ã (#) pro procházenà pÃsmeny a opakujte s dalÅ¡Ãm ÄÃslem. NapÅ™Ãklad, pro zadánà slova 'look' musÃte stisknout následujÃcÃ: 5##6##6##5#
Dialogové okno je plnÄ› použitelné pomocà myÅ¡i, ale v nÄ›kterých verzÃch ScummVM pro jiné platformy, je použità dialogu pohodlnÄ›jÅ¡Ã pomocà ÄÃselné klávesnice. NÄ›která tlaÄÃtka dialogu mohou být také použÃvána pomocà šipkových kláves a enter.
-3.17) Poznámky k Mickey's Space Adventure:
------ ------------------------------------
-Abyste mohli Mickey's Space Adventure hrát ve ScummVM, potÅ™ebujete spolu s datovými soubory hry také původnà spouÅ¡tÄ›Ä (mickey.exe).
-
-Pro tuto hru ve ScummVM, existuje rozÅ¡ÃÅ™ená podpora myÅ¡i, i když v původnà hÅ™e takováto podpora nebyla. Položky menu mohou být vybrány pomocà myÅ¡i a je také možné se myÅ¡Ã pÅ™esunout do jiných mÃst. Když se kurzor myÅ¡i nacházà na okraji obrazovky, zÄervená, pokud je možné jÃt v tomto smÄ›ru. HrÃ¡Ä pak může jednoduÅ¡e kliknout na okraje hernà obrazovky pro zmÄ›nu mÃsta, podobnÄ› jako mnoho adventur, což je jednoduÅ¡Å¡Ã a pÅ™ÃmoÄaÅ™ejÅ¡Ã než pohyb pomocà menu.
-
-
-3.18) Winnie the Pooh notes:
------ ----------------------
-Je možné importovat uložené hry z původnà hry do ScummVM.
-
-Pro tuto hru ve ScummVM, existuje rozÅ¡ÃÅ™ená podpora myÅ¡i, i když v původnà hÅ™e takováto podpora nebyla. Položky menu mohou být vybrány pomocà myÅ¡i a je také možné se myÅ¡Ã pÅ™esunout do jiných mÃst. Když se kurzor myÅ¡i nacházà na okraji obrazovky, zÄervená, pokud je možné jÃt v tomto smÄ›ru. HrÃ¡Ä pak může jednoduÅ¡e kliknout na okraje hernà obrazovky pro zmÄ›nu mÃsta, podobnÄ› jako mnoho adventur, což je jednoduÅ¡Å¡Ã a pÅ™ÃmoÄaÅ™ejÅ¡Ã než pohyb pomocà menu.
-
-
-3.19) Poznámky k Troll's Tale:
------ ------------------------
-Původnà hra vycházela na zavádÄ›cÃm disku PC, proto je nutné vypsat obsah tohoto disku jako obraz disku a pÅ™ejmenovat ho na "troll.img", abyste tuho hru mohli hrát ve ScummVM.
-
-
-3.20) Poznámky k DraÄà Historie:
------ --------------------------
-Existujà 4 jazykové varianty této hry: Äeská, anglická, polská a
-nÄ›mecká. Každá je umÃstÄ›na v oddÄ›leném archivu. Jediná oficiálnà verze je Äeská, a anglická, polská a nÄ›mecká byly vždycky nedokonÄené práce a nikdy nebyly oficiálnÄ› vydány. I když texty byly zcela pÅ™eloženy, je známo, že nÄ›které z nich obsahujà pÅ™eklepy.
-
-Pro tuto hru existuje nepovinný Äeský dabing. Z důvodu velikosti si ho můžete dodateÄnÄ› stáhnout a pak ho rozbalit do adresáře hry. Můžete také Äeský dabing poslouchat se vÅ¡emi jazykovými varianty hry, zatÃmco Ätete titulky.
-
-Všechny hernà soubory a návody můžou být staženy z
-http://www.ucw.cz/draci-historie/index-en.html
-
-3.21) Titulky a hlasy souběžně v hrách Sierra SCI:
+3.23) Titulky a hlasy souběžně v hrách Sierra SCI:
----- --------------------------------------------
UrÄité CD verze her Sierra SCI majà textová i hlasová data.
NÄ›které z nich majà volbu pro pÅ™epÃnánà mezi nimi, ale existujà pÅ™Ãpady
@@ -674,7 +785,7 @@ Hry na CD, kde zvuk i titulky lze zobrazit souÄasnÄ›: Space Quest 4 CD
EcoQuest 1 CD:
- Hlas i text lze zapnout pomocà volby "Mode" v oknÄ› nastavenÃ,
+ Hlas i text lze zapnout pomocà volby "Mode" v oknÄ› nastavenÃ,
nebo přes nastavenà zvuku ScummVM.
Freddy Pharkas CD:
@@ -684,84 +795,136 @@ Freddy Pharkas CD: King's Quest 6 CD
Hlas i text lze zapnout pomocà volby "Mode" v okně nastavenà (kde je ve
- ScummVM pÅ™idána dodateÄná volba "Dual"), nebo pomocà nastavenÃ
+ ScummVM pÅ™idána dodateÄná volba "Dual"), nebo pomocà nastavenÃ
zvuku ve ScummVM.
Laura Bow 2 CD
Hlas i text lze zapnout pomocà volby "Mode" v okně nastavenà (kde je ve
- ScummVM pÅ™idána dodateÄná volba "Dual"), nebo pomocà nastavenÃ
+ ScummVM pÅ™idána dodateÄná volba "Dual"), nebo pomocà nastavenÃ
zvuku ve ScummVM.
Leisure Suit Larry 6 CD
Ve hÅ™e lze povolit buÄ hlas, nebo hlas a text. Neexistuje možnost pro
- povolenà textu. Pouze nastavenà zvuku ve ScummVM lze použÃt pro
+ povolenà textu. Pouze nastavenà zvuku ve ScummVM lze použÃt pro
zobrazenà jen titulků.
Space Quest 4 CD:
Hlas a text lze povolit pomocà tlaÄÃtka "Display Mode" v
nastavenà hry, nebo pomocà nastavenà zvuku ve ScummVM.
-
-3.22) Známé Problémy:
------ ---------------
-Toto vydánà má následujÃcà známé problémy. Nenà tÅ™eba je ohlaÅ¡ovat, i když záplaty pro jejich opravu jsou vÃtány. Pokud objevÃte chybu, která nenà zde v seznamu, ani nenà v seznamu kompatibility na internetové stránce, prohlédnÄ›te si, prosÃm, Äást o hlášenà chyb.
-
- Hry CD Audio:
- - PÅ™i hranà her, které použÃvajà CD Audio (hry FM-TOWNS, Loom CD, atd) může u uživatelů Microsoft Windows 2000/XP docházet k náhodným pádům. To je dÃky dlouhotrvajÃcà chybÄ› Windows, která má za následek poÅ¡kozené soubory
- pÅ™i Ätenà z CD. Abyste se tomuto vyhnuli, zkopÃrujte, prosÃm, soubory na pevný disk
-
- Verze FM-TOWNS:
- - Verze Kandži vyžaduje ROM pÃsma FM-TOWNS
-
- Loom:
- - Vypnutà titulků pomocà souboru nastavenà je nevypne spolehlivě, protože skripty Loom je znovu automaticky zapnou
- - Podpora MIDI ve verzi EGA vyžaduje aktualizaci Roland LucasArts
- - Verze Kandži na PC-Engine vyžaduje rom systémové karty
-
- The Secret of Monkey Island:
- - Podpora MIDI ve verzi EGA vyžaduje aktualizaci Roland LucasArts
- Beneath a Steel Sky:
- - Verze pro Amiga nejsou podporovány
- - Demoverze z diskety nejsou podporovány
- - Nenà chyba: Ve verzi na CD chybà v jistých dialozÃch Å™eÄ, to je normálnÃ.
-
- Elvira - Mistress of the Dark
- - Ve verzi pro Atari ST nefunguje hudba
-
- Elvira II - The Jaws of Cerberus
- - Ve verzi pro Atari ST nefunguje hudba
- - Ve verzi pro PC nefungujà zvukové efekty
- - Ve verzi pro Atari ST jsou problémy s paletou
+3.24) Poznámky ke hrám Zork:
+----- ----------------------
+Pro spuÅ¡tÄ›nà podporovaných her Zork (Zork Nemesis: The Forbidden Lands a Zork: Grand Inquisitor) musÃte zkopÃrovat nÄ›která (dodateÄná) data do odpovÃdajÃcÃch umÃstÄ›nÃ.
+
+Zork Nemesis: The Forbidden Lands
+
+VÅ¡echny verze
+
+StáhnÄ›te si balÃÄek pÃsem Liberation(tm)
+<https://fedorahosted.org/releases/l/i/liberation-fonts/liberation-fonts-ttf-2.00.1.tar.gz>
+a rozbalte vÅ¡echny soubory ttf do vaÅ¡Ã dodateÄné složky ScummVM.
+Nebo si stáhnÄ›te balÃÄek GNU FreeFont TTF
+<https://ftp.gnu.org/gnu/freefont/freefont-ttf.zip> a umÃstÄ›te vÅ¡echny soubory ttf z adresáře sfd do dodateÄné složky ScummVM, i když je tÅ™eba Å™Ãci, že v souÄasné dobÄ›
+majà nÄ›která tato pÃsma potÞe pÅ™i vykreslovánÃ.
+Stáhněte si opravu pro titulky
+<http://www.thezorklibrary.com/installguides/znpatch.zip> a rozbalte adresář addon pÅ™Ãmo do koÅ™enového adresáře hry
+
+Verze z GoG
+
+Použijte instalátor GoG, žádných dalÅ¡Ãch kroků nenà tÅ™eba
+
+Verze z CD
+
+ZkopÃrujte následujÃcà z adresáře nemesis na CD1 do koÅ™enového adresáře hry:
+Adresář znemmx
+Adresář znemscr
+nemesis.str
+Z CD1 zkopÃrujte adresář zassets do koÅ™enového adresáře hry
+Z CD2 zkopÃrujte adresář zassets do koÅ™enového adresáře hry a nahraÄte vÅ¡echny soubory
+Z CD3 zkopÃrujte adresář zassets do koÅ™enového adresáře hry a nahraÄte vÅ¡echny soubory
+
+Verze z DVD
+
+ZkopÃrujte následujÃcà z adresáře nemesis do koÅ™enového adresáře hry:
+Adresář znemmx
+Adresář znemscr
+nemesis.str
+Poznámka: Je třeba také přesunout cursor.zfs z adresáře zassets/global do adresáře znemscr
+ZkopÃrujte adresář disc2 do koÅ™enového adresáře hry
+ZkopÃrujte adresář disc3 do koÅ™enového adresáře hry
+ZkopÃrujte adresář zassets do koÅ™enového adresáře hry
+
+
+Zork: Grand Inquisitor
+
+VÅ¡echny verze
+
+StáhnÄ›te si balÃÄek pÃsem Liberation(tm)
+<https://fedorahosted.org/releases/l/i/liberation-fonts/liberation-fonts-ttf-2.00.1.tar.gz>
+a rozbalte vÅ¡echny soubory ttf do vaÅ¡Ã dodateÄné složky ScummVM.
+Nebo si stáhnÄ›te balÃÄek GNU FreeFont TTF
+<https://ftp.gnu.org/gnu/freefont/freefont-ttf.zip> a umÃstÄ›te vÅ¡echny soubory ttf z adresáře sfd do dodateÄné složky ScummVM, i když je tÅ™eba Å™Ãci, že v souÄasné dobÄ›
+majà nÄ›která tato pÃsma potÞe pÅ™i vykreslovánÃ.
+
+Verze z GoG
+
+Použijte instalátor GoG, žádných dalÅ¡Ãch kroků nenà tÅ™eba
+
+Verze z CD
+
+ZkopÃrujte následujÃcà z adresáře zgi na CD1 do koÅ™enového adresáře hry:
+Adresář zgi_mx
+cursor.zfs
+death.zfs
+inquis.str
+inquis.zix
+r.svr
+scripts.zfs
+subtitle.zfs
+Z CD1 zkopÃrujte adresář zassets1 do koÅ™enového adresáře hry
+Z CD2 zkopÃrujte adresář zassets2 do koÅ™enového adresáře hry
+DoporuÄujeme V8m nainstalovat záplatu 1.2
+<http://www.thezorklibrary.com/installguides/Zpatch.exe>,
+ale je možné že pro to budete muset hru nainstalovat normálnÃm způsobem, protože záplata má vlastnà instalátor.
+
+Verze z DVD
+
+ZkopÃrujte následujÃcà z adresáře zgi_e do koÅ™enového adresáře hry:
+Adresář addon (oprava hry 1.2)
+Adresář zgi_mx
+cursor.zfs
+death.zfs
+inquis.str
+inquis.zix
+r.svr
+scripts.zfs
+subtitle.zfs
+ZkopÃrujte adresář eng_mpeg (video soubory MPEG2 ve vysokém rozliÅ¡enÃ) do koÅ™enového adresáře hry
+ZkopÃrujte adresář zassetsc do koÅ™enového adresáře hry
+ZkopÃrujte adresář zassetse do koÅ™enového adresáře hry
+
+
+3.25) Poznámky ke hrám Commodore64:
+----- -----------------------------
+Jak Maniac Mansion tak Zak McKracken mohou být spuštěny, ale Maniac Mansion nenà ještě hratelný. Jednoduše pojmenujte disky D64 jako
+"maniac1.d64" a "maniac2.d64" nebo "zak1.d64" a "zak2.d64", pak by měl ScummVM automaticky hru zjistit, pokud ho odkážete na správnou složku.
- Inherit the Earth: Quest for the Orb
- - Verze pro Amiga nejsou podporovány
+Nebo můžete použÃt 'extract_mm_c64' z balÃÄku nástrojů pro extrahovánà datových souborů. Pak ale ScummVM hru řádnÄ› automaticky nezjistà ScummVM, a musÃte se ujistit, že platforma je nastavena na Commodore64. DoporuÄujeme použÃt mnohem jednoduÅ¡Å¡Ã postup popsaný v pÅ™edchozÃm odstavci.
- Lure of the Temptress
- - Žádná podpora Roland MT-32
- - Podpora zvuku nenà dokonÄena a neznà jako v původnà hÅ™e
- Simon the Sorcerer 1:
- - V anglických a nÄ›meckých verzÃch na CD nejsou titulky dostupné, protože jim vÄ›tÅ¡ina titulků chybÃ.
+3.26) Poznámky ke hrám Macintosh:
+----- ---------------------------
+VÅ¡echny adventury LucasArts založené na SCUMM, kromÄ› COMI, také existujà ve verzÃch pro in Macintosh. ScummVM může vÄ›tÅ¡inu (vÅ¡echny?) použÃt, nicménÄ›, v nÄ›kterých pÅ™Ãpadech je nutná dodateÄná práce. NejdÅ™Ãve, pokud pro toto nepoužÃváte Macintosh, pÅ™Ãstup k datům na CD/disketÄ› může být obtÞný. Důvodem je to, že Mac použÃvá zvláštnà formát disku nazvaný HFS, který ostatnà systémy vÄ›tÅ¡inou nepodporujÃ. NicménÄ› existuje, nÄ›kolik nástrojů, které jsou zadarmo a umožňujà ÄÃst takovéto svazky HFS. NapÅ™Ãklad "HFVExplorer" pro Windows a "hfsutils" pro Linux a ostatnà Unixové operaÄnà systémy.
- Simon the Sorcerer 2:
- - Kombinace Å™eÄi a titulků Äasto způsobÃ, že Å™eÄ je pÅ™eruÅ¡ena brzo, toto je omezenà původnà hry.
- - Ve verzÃch pro Amiga a Macintosh je podporován pouze výchozà jazyk datových souborů (angliÄtina).
+VÄ›tÅ¡ina novÄ›jÅ¡Ãch her na Macintosh je dodávána pouze s jednÃm datovým souborem (v nÄ›kterých pÅ™Ãpadech byl tento soubor uÄinÄ›n neviditelným, takže možná budete potÅ™ebovat dodateÄné nástroje, abyste ho mohli zkopÃrovat). ScummVM je schopen takovýto soubor použÃt pÅ™Ãmo; jednoduÅ¡e odkažte ScummVM na složku obsahujÃcà tento soubor a mÄ›lo by to fungovat (tak jako s každou podporovanou hrou).
- Simon the Sorcerer's Puzzle Pack:
- - Žádná podpora pro zobrazovánÃ, zadávánÃ, ukládánÃ, Äi naÄÃtánà nejvyÅ¡Å¡Ãch skóre.
- - Žádná podpora pro zobrazovánà názvů položek, když na ně najedete myšà ve Swampy Adventures.
+V balÃÄku nástrojů také poskytujeme nástroj nazvaný 'extract_scumm_mac', který extrahuje data z tÄ›chto datových souborů, ale toto nenà ani potÅ™eba, ani doporuÄeno.
- The Feeble Files:
- - Titulky jsou Äasto nedokonÄené. V původnà hÅ™e byly vždy zakázány.
+Pro dalÅ¡Ã informace o kopÃrovánà hernÃch souborů Macintosh na Váš pevný disk si prohlédnÄ›te:
- The Legend of Kyrandia:
- - Ve verzÃch na disketÄ› pro Mac nenà žádná hudba ani zvukové efekty.
- - CD Macintosh použÃvá zahrnutou hudbu a zvukové efekty z DOS.
+ <http://wiki.scummvm.org/index.php/HOWTO-Mac_Games>
- Hry Humongous Entertainment:
- - Pouze původnà rozhranà pro uloženà a naÄtenà mohou být použity.
- - Žádná podpora pro hru vÃce hráÄů nebo tisknutà obrázků
4.0) Podporované Platformy:
---- ----------------------
@@ -772,7 +935,8 @@ Podporované platformy zahrnujà (mimo jiné): UNIX (Linux, Solaris, IRIX, *BSD, ...)
Windows
- Windows CE a Windows Mobile (vÄetnÄ› Smartphonů a PocketPCs)
+ Windows CE
+ Windows Mobile (vÄetnÄ› Smartphonů a PocketPCs)
Mac OS X
AmigaOS
Android
@@ -793,7 +957,7 @@ Podporované platformy zahrnujà (mimo jiné): Verze pro Dreamcast nepodporuje The Curse of Monkey Island, ani The Dig. Verze pro Nintendo DS nepodporuje Full Throttle, The Dig, nebo The Curse of Monkey Island.
Pro dalÅ¡Ã omezenà v závislosti na platformÄ› se, prosÃm, podÃvejte na naÅ¡Ã Wiki:
- http://wiki.scummvm.org/index.php/Platforms
+ <http://wiki.scummvm.org/index.php/Platforms>
Ve verzi pro Macintosh je stisknutà pravého tlaÄÃtka myÅ¡i emulováno pomocà Cmd-kliknutà (to je, že stisknete tlaÄÃtko myÅ¡i pÅ™i drženà klávesy
Command/Apple/Vrtule).
@@ -833,7 +997,7 @@ ScummVM může také hru spustit pÅ™Ãmo pomocà argumentů pÅ™Ãkazové řádky -g, --gfx-mode=REŽIM Vybere režim obrazu (viz také Äást 5.3)
--gui-theme=VZHLED Vybere vzhled rozhranà (výchozÃ, modernÃ, klasický)
--themepath=CESTA Cesta kde jsou vzhledy rozhranà uloženy
- --list-themes Zobrazà seznam všech použitelných vzhledů
+ --list-themes Zobrazà seznam všech použitelných vzhledů
-e, --music-driver=REŽIM Vybere ovladaÄ hudby (viz také Äást 7.0)
--list-audio-devices Zobrazà seznam vÅ¡ech dostupných zvukových zaÅ™ÃzenÃ
-q, --language=JAZYK Vybere jazyk hry (viz také Äást 5.2)
@@ -858,7 +1022,10 @@ ScummVM může také hru spustit pÅ™Ãmo pomocà argumentů pÅ™Ãkazové řádky --output-rate=FREKVENCE Výstupnà vzorkovacà kmitoÄet v Hz (napÅ™. 22050)
--opl-driver=OVLADAČ Vybere emulátor AdLib (OPL) (db, mame)
--aspect-ratio Povolà korekci poměru stran
- --render-mode=REŽIM Povolà dodateÄné režimy vykreslenà (cga, ega, hercGreen, hercAmber, amiga)
+ --render-mode=REŽIM Povolà dodateÄné režimy vykreslenà (hercGreen, hercAmber,
+ cga, ega, vga, amiga, fmtowns, pc9821, pc9801, 2gs,
+ atari, macintosh)
+
--alt-intro Použije alternativnà intro pro CD verze Beneath a Steel Sky a Flight of the Amazon Queen
--copy-protection Povolà ochranu proti kopÃrovánà v hrách, když ji ScummVM standardnÄ› zakazuje.
--talkspeed=ÄŒÃSLO Nastavà zdrženà mluvenà v hrách SCUMM, nebo rychlost mluvenà v jiných hrách (výchozÃ: 60)
@@ -1018,12 +1185,12 @@ ScummVM podporuje různé zkratky ve hře. Lišà se mezi různými hrami SCUMM Ctrl-F5 - Zobrazà Globálnà Menu
Cmd-q - UkonÄit (Mac OS X)
Ctrl-q - UkonÄit (dalÅ¡Ã unixy vÄetnÄ› Linux)
- Ctrl-z NEBO Alt-x - UkonÄit (dalÅ¡Ã platformy)
+ Ctrl-z - UkonÄit (dalÅ¡Ã platformy)
Ctrl-u - Zeslabà všechny zvuky
Ctrl-m - PÅ™epÃnat zachycenà myÅ¡i
Ctrl-Alt 1-8 - PÅ™epÃnat mezi grafickými filtry
Ctrl-Alt + a - - ZvÄ›tÅ¡it/ZmenÅ¡it faktor zvÄ›tÅ¡enÃ
- Ctrl-Alt a - PÅ™epÃnat korekci pomÄ›ru stran. VÄ›tÅ¡ina her použÃvá rozliÅ¡enà 320x200 pixelů, což může na vÄ›tÅ¡inÄ› novÄ›jÅ¡Ãch monitorů vypadat splácle. Korekce pomÄ›ru stran obraz roztáhne, aby mÃsto toho použil
+ Ctrl-Alt a - PÅ™epÃnat korekci pomÄ›ru stran. VÄ›tÅ¡ina her použÃvá rozliÅ¡enà 320x200 pixelů, což může na vÄ›tÅ¡inÄ› novÄ›jÅ¡Ãch monitorů vypadat splácle. Korekce pomÄ›ru stran obraz roztáhne, aby mÃsto toho použil
320x240, nebo jeho násobky
Alt-Enter - PÅ™epÃná celou obrazovku/do okna
Alt-s - VytvoÅ™it snÃmek obrazovky (pouze jádro SDL)
@@ -1032,6 +1199,7 @@ ScummVM podporuje různé zkratky ve hÅ™e. LiÅ¡Ã se mezi různými hrami SCUMM prostÅ™ednÃho tlaÄÃtka nebo koleÄka myÅ¡i.
SCUMM:
+ Alt-x - UkonÄit
Ctrl 0-9 a Alt 0-9 - Nahrát a uložit stav hry
Ctrl-d - Spustit ladÄ›nÃ
Ctrl-f - Zapnout rychlý režim
@@ -1058,12 +1226,12 @@ ScummVM podporuje různé zkratky ve hÅ™e. LiÅ¡Ã se mezi různými hrami SCUMM TeÄka (.) - PÅ™eskoÄà souÄasný řádek textu
Broken Sword:
- F5 nebo Escape - Zobrazà rámeÄek pro uloženÃ/naÄtenÃ
+ F5 nebo Escape - Zobrazà rámeÄek pro uloženÃ/naÄtenÃ
Broken Sword II:
Ctrl-d - Spustit ladÄ›nÃ
Ctrl-f - Zapnout rychlý režim
- p - PozastavenÃ
+ p - PozastavenÃ
DraÄÃ Historie:
F5 - Zobrazà Globálnà Menu
@@ -1084,7 +1252,7 @@ ScummVM podporuje různé zkratky ve hÅ™e. LiÅ¡Ã se mezi různými hrami SCUMM Escape - PÅ™eskoÄà video
MezernÃk - PÅ™eskoÄà souÄasný řádek textu
- Future Wars
+ Future Wars:
F1 - Prozkoumat
F2 - VzÃt
F3 - Inventář
@@ -1095,7 +1263,7 @@ ScummVM podporuje různé zkratky ve hÅ™e. LiÅ¡Ã se mezi různými hrami SCUMM F10 - Menu "PoužÃt"
Escape - Zobrazit menu pÅ™Ãkazů
- Nippon Safes
+ Nippon Safes:
Ctrl-d - Spustit ladÄ›nÃ
l - NaÄÃst hru
s - Uložit hru
@@ -1115,21 +1283,21 @@ ScummVM podporuje různé zkratky ve hÅ™e. LiÅ¡Ã se mezi různými hrami SCUMM t - PÅ™epÃnat mezi Å™eÄà a kombinacà řeÄi a titulků [Simon the Sorcerer 1 CD (jiné než angliÄtina a nÄ›mÄina) a Simon the Sorcerer 2 CD (vÅ¡echny jazyky)]
v - PÅ™epÃnat mezi titulky a kombinacà řeÄi a titulků [Pouze Simon the Sorcerer 2 CD]
- Simon the Sorcerer's Puzzle Pack
+ Simon the Sorcerer's Puzzle Pack:
Ctrl-d - Spustit ladÄ›nÃ
Ctrl-f - Zapnout rychlý režim
F12 - Zapnout/vypnout režim rychle rychlosti ve Swampy Adventures
- a + - Hlasitost hudby, snÞit/zvýšit
m - Hudba vypnout/zapnout
s - Zvukové efekty zapnout/vypnout
- Pause - PozastavenÃ
+ Pause - PozastavenÃ
- The Feeble Files
+ The Feeble Files:
Ctrl-d - Spustit ladÄ›nÃ
Ctrl-f - Zapnout rychlý režim
F7 - Vyměnit postavy
F9 - Zapnout/vypnout jména hitboxů
- s - Zvukové efekty zapnout/vypnout
+ s - Zvukové efekty zapnout/vypnout
Pause - PozastavenÃ
t - PÅ™epÃnat mezi Å™eÄà a kombinacà řeÄi a titulků
v - PÅ™epÃnat mezi titulky a kombinacà řeÄi a titulků
@@ -1143,16 +1311,16 @@ ScummVM podporuje různé zkratky ve hře. Lišà se mezi různými hrami SCUMM F5 - Zobrazà Globálnà Menu
Touche: The Adventures of the Fifth Musketeer:
- Ctrl-f - Zapnout rychlý režim
+ Ctrl-f - Zapnout rychlý režim
F5 - Zobrazit možnosti
F9 - Zapnout režim rychlé chůze
- F10 - Vypnout režim rychlé chůze
+ F10 - Vypnout režim rychlé chůze
Escape - UkonÄit
MezernÃk - PÅ™eskoÄà souÄasný řádek textu
t - PÅ™epnout mezi 'Pouze ŘeÄ',
'ŘeÄ a Text' a 'Pouze Text'
-
- Zork: Grand Inquisitor
+
+ Zork: Grand Inquisitor:
Ctrl-s - Uložit
Ctrl-r - NaÄÃst
Ctrl-q - UkonÄit
@@ -1165,7 +1333,7 @@ ScummVM podporuje různé zkratky ve hÅ™e. LiÅ¡Ã se mezi různými hrami SCUMM F9 - Vyjmout minci (musÃte mÃt měšec)
Space - PÅ™eskoÄit videa
- Zork Nemesis: The Forbidden Lands
+ Zork Nemesis: The Forbidden Lands:
Ctrl-s - Uložit
Ctrl-r - NaÄÃst
Ctrl-q - UkonÄit
@@ -1182,18 +1350,24 @@ Poznámka pro uživatele WinCE: Kvůli omezenému vstupu z klávesnice ve vÄ›tÅ Uložené hry jsou na nÄ›kterých platformách standardnÄ› umÃstÄ›ny do souÄasné složky a v jiných do pÅ™ednastavené složky. To můžete urÄit v souboru s nastavenÃm pomocà parametru savepath. PodÃvejte se na vzorový soubor s nastavenÃm dále v tomto souboru.
Platformy, které v souÄasnosti majà jiné výchozà složky jsou:
- Mac OS X:
+ Mac OS X:
$HOME/Documents/ScummVM Savegames/
-
+
Jiné unixy:
- $HOME/.scummvm/
-
+ ŘÃdÃme se specifikacemi základnÃho adresáře XDG. To znamená, že nastavenà lze nalézt v:
+ $XDG_DATA_HOME/scummvm/saves/
+
+ Pokud XDG_DATA_HOME nenà nastaven nebo je prázdný, bude, podle pravidel specifikace, použito '~/.local/share' jako hodnota pro XDG_DATA_HOME.
+
+ Pokud byla ve vaÅ¡em systému nainstalována dÅ™ÃvÄ›jÅ¡Ã verze ScummVM, bude ponecháno původnà výchozà umÃstÄ›nà '~/.scummvm'.
+ Program toto zjistà nalezenÃm složky '~/.scummvm'´ v cestÄ›.
+
Windows Vista/7:
\Users\užjméno\AppData\Roaming\ScummVM\Saved games\
-
+
Windows 2000/XP:
\Documents and Settings\užjméno\Application Data\ScummVM\Saved games\
-
+
Windows NT4:
<windir>\Profiles\užjméno\Application Data\ScummVM\Saved games\
@@ -1203,7 +1377,7 @@ povolenÃm zobrazenà skrytých složek v PrůzkumnÃku Windows. Poznámka pro uživatele Windows NT4/2000/XP/Vista/7: Výchozà umÃstÄ›nà uložených her
bylo ve ScummVM 1.5.0 zmÄ›nÄ›no. Dávkový soubor pÅ™esunu může být použit pro zkopÃrovánÃ
-uložených her ze starého výchozÃho umÃstÄ›nà do nového.
+uložených her ze starého výchozÃho umÃstÄ›nà do nového.
6.1) 6.1 Automatické ukládánÃ:
---- -------------------------
@@ -1465,7 +1639,7 @@ do VaÅ¡eho souboru s nastavenÃm v Äásti [scummvm], nebo nastavenÃm SCUMMVM_P 7.7) Použità MIDI serveru TiMidity++:
---- --------------------------------
-Pokud na VaÅ¡em systému chybà jakýkoliv sekvencer MIDI, ale pÅ™esto chcete lepÅ¡Ã kvalitu MIDI, než kterou může nabÃdnout standardnà emulace AdLib, můžete zkusit MIDI server TiMidity++. ProhlédnÄ›te si http://timidity.sourceforge.net/ pro staženà a pokyny k instalaci.
+Pokud na VaÅ¡em systému chybà jakýkoliv sekvencer MIDI, ale pÅ™esto chcete lepÅ¡Ã kvalitu MIDI, než kterou může nabÃdnout standardnà emulace AdLib, můžete zkusit MIDI server TiMidity++. ProhlédnÄ›te si <http://timidity.sourceforge.net/> pro staženà a pokyny k instalaci.
NejdÅ™Ãve musÃte spustit daemona:
@@ -1475,7 +1649,7 @@ Nynà můžete spustit ScummVM a zkusit vybrat TiMidity jako výstup pro hudbu. "ÄÃslo zaÅ™ÃzenÃ" použitÃm promÄ›nné "SCUMMVM_MIDIPORT".
-7.8) Použità komprimovaných zvukových souborů
+7.8) Použità komprimovaných zvukových souborů
---- ----------------------------------------
7.8.0) Použità souborů MP3 pro CD audio:
@@ -1625,7 +1799,12 @@ StandardnÄ› je soubor s nastavenÃm uložen a naÄÃtán: Pokud ve Windows nainstalována dÅ™ÃvÄ›jÅ¡Ã verze ScummVM bude ponecháno dÅ™ÃvÄ›jÅ¡Ã umÃstÄ›nà '<složkawin>\scummvm.ini'.
Unix:
- ~/.scummvmrc
+ ŘÃdÃme se specifikacemi základnÃho adresáře XDG. To znamená, že naÅ¡e nastavenà lze nalézt v:
+ $XDG_CONFIG_HOME/scummvm/scummvm.ini
+
+ Pokud XDG_CONFIG_HOME nenà nastaven nebo je prázdný, bude, podle pravidel specifikace, použito '~/.config' jako hodnota pro XDG_CONFIG_HOME.
+
+ Pokud byla ve vaÅ¡em systému nainstalována dÅ™ÃvÄ›jÅ¡Ã verze ScummVM, bude ponecháno původnà výchozà umÃstÄ›nà '~/.scummvmrc'.
Mac OS X:
~/Library/Preferences/ScummVM Preferences
@@ -1672,7 +1851,7 @@ Vzorový soubor s nastavenÃm vypadá takto: music_driver=windows
8.1) Rozpoznávaná klÃÄová slova nastavenÃ
----- ------------------------------------
+---- ------------------------------------
Jsou rozpoznávána následujÃcà klÃÄová slova:
path Å™etÄ›zec Cesta, kde jsou umÃstÄ›ny datové soubory hry
@@ -1689,7 +1868,8 @@ Jsou rozpoznávána následujÃcà klÃÄová slova: talkspeed ÄÃslo ZpoždÄ›nà textu v hrách SCUMM, nebo rychlost textu v jiných hrách.
fullscreen boolean Režim celé obrazovky
aspect_ratio boolean Povolit korekci poměru stran
- gfx_mode Å™etÄ›zec Grafický režim (normálnÃ, 2x, 3x, 2xsai, super2xsai, supereagle, advmame2x, advmame3x,hq2x, hq3x, tv2x, dotmatrix)
+ gfx_mode Å™etÄ›zec Grafický režim (normálnÃ, 2x, 3x, 2xsai, super2xsai, supereagle, advmame2x, advmame3x, hq2x, hq3x, tv2x, dotmatrix, opengl_linear, opengl_nearest)
+
confirm_exit boolean Zeptat se uživatele na potvrzenà pÅ™ed ukonÄenÃm (pouze jádro SDL).
console boolean Povolit okno konzole (výchozÃ: zapnuto) (pouze Windows).
cdrom ÄÃslo ÄŒÃslo jednotky CD-ROM, kterou použÃt pro zvuk. Pokud je záporné, k pokusu o pÅ™Ãstup k CD-ROM nedojde.
@@ -1727,7 +1907,7 @@ Hry Sierra použÃvajÃcà jádro SCI pÅ™idávajà následujÃcà nestandardnà use_cdaudio boolean PoužÃt zvuky na CD mÃsto ve hÅ™e, pokud je dostupné
windows_cursors boolean PoužÃt kurzory Windows (menÅ¡Ã a ÄernobÃlé) mÃsto kurzorů z DOS (King's Quest 6)
silver_cursors boolean PoužÃt alternativnà sadu stÅ™Ãbrných kurzorů mÃsto standardnÃch zlatých (Space Quest 4)
-
+
Broken Sword II pÅ™idává následujÃcà nestandardnà klÃÄová slova:
gfx_details ÄÃslo Nastavenà grafických detailů (0-3)
@@ -1740,13 +1920,13 @@ Flight of the Amazon Queen pÅ™idává následujÃcà nestandardnà klÃÄová sl music_mute boolean Pokud true, hudba je ztlumena
sfx_mute boolean Pokud true, zvukové efekty jsou ztlumeny
-
+
Hopkins FBI pÅ™idává následujÃcà nestandardnà klÃÄové slovo:
enable_gore boolean Pokud true, povolà některé nepovinné krvavé scény ve hře
Jones in the Fast Lane pÅ™idává následujÃcà nestandardnà klÃÄové slovo:
- music_mute boolean Pokud true, je použito CD audio mÃsto zvuků ve hÅ™e
+ music_mute boolean Pokud true, je použito CD audio mÃsto zvuků ve hÅ™e
King's Quest VI Windows pÅ™idává následujÃcà nestandardnà klÃÄové slovo:
@@ -1758,14 +1938,14 @@ Lands of Lore: The Throne of Chaos pÅ™idává následujÃcà nestandardnà klÃÄ floating_cursors boolean Pokud true, je kurzor zmÄ›nÄ›n na smÄ›rovou Å¡ipku pÅ™i najetà na okraj obrazovky. HrÃ¡Ä pak může kliknout pro pohyb v tomto smÄ›ru.
Space Quest IV CD pÅ™idává následujÃcà nestandardnà klÃÄové slovo:
-
+
silver_cursors boolean Pokud true, je mÃsto původnÃch zlatých kurzorů použita alternativnà sada stÅ™Ãbrných
-
+
Simon the Sorcerer 1 a 2 pÅ™idává následujÃcà nestandardnà klÃÄová slova:
music_mute boolean Pokud true, hudba je ztlumena
sfx_mute boolean Pokud true, zvukové efekty jsou ztlumeny
-
+
Soltys pÅ™idává následujÃcà nestandardnà klÃÄové slovo:
enable_color_blind bool Pokud true, jsou původnà barvy nahrazeny odstÃny Å¡edi
@@ -1777,7 +1957,7 @@ The Legend of Kyrandia: The Hand of Fate pÅ™idává následujÃcà nestandardnà walkspeed ÄÃslo Rychlost chůze (3 nebo 5, což znamená
rychle nebo pomalu)
-
+
The Legend of Kyrandia: Malcolm's Revenge pÅ™idává následujÃcà nestandardnà klÃÄová slova:
walkspeed ÄÃslo Rychlost chůze (3 nebo 5, což znamená
@@ -1785,10 +1965,10 @@ The Legend of Kyrandia: Malcolm's Revenge pÅ™idává následujÃcà nestandardnà studio_audience boolean Pokud true, je slyÅ¡et potlesk a smÃch kdykoliv Malcolm provede nÄ›co vtipného
skip_support boolean Pokud true, hrÃ¡Ä může pÅ™eskakovat text a scény hry
helium_mode boolean Pokud true, lidé znějà tak, jakoby se nadýchali hélia
-
+
The Neverhood pÅ™idává následujÃcà nestandardnà klÃÄová slova:
- originalsaveload boolean Pokud true, jsou použity původnà obrazovky pro
+ originalsaveload boolean Pokud true, jsou použity původnà obrazovky pro
naÄÃtánÃ/ukládánà mÃsto obrazovek ScummVM
skiphallofrecordsscenes boolean
Pokud true, umožnà hráÄi pÅ™eskoÄit
@@ -1823,10 +2003,8 @@ Zork: Grand Inquisitor pÅ™idává následujÃcà nestandardnà klÃÄové slovo: mpegmovies boolean Pokud true, jsou použita videa MPEG ve vysokém rozliÅ¡enà z
DVD verze hry, mÃsto videà AVI v nÃzkém rozliÅ¡enÃ
-8.2) Vlastnà hernà volby, které mohou být pÅ™epÃnány pomoci grafického
----- ----------------------------------------------------------------
-rozhranÃ
---------
+8.2) Vlastnà hernà volby, které mohou být pÅ™epÃnány pomoci grafického rozhranÃ
+---- -------------------------------------------------------------------------
Mnoho vlastnÃch hernÃch voleb v pÅ™edchozà Äásti může být pÅ™epnuto pÅ™es grafické rozhranÃ. Pokud je takováto volba pro urÄitou hru dostupná, objevà se karta "Jádro" pÅ™i pÅ™idávánà nebo úpravÄ› nastavenà této hry.
Pokud vlastnà možnosti nejsou zobrazeny, musà být konkrétnà hry spuÅ¡tÄ›ny jednou nebo znovu pÅ™idány do seznamu her spouÅ¡tÄ›Äe ScummVM. Toto aktualizuje nastavenà každé položky, ÄÃmž umožnà zobrazenà vlastnÃch voleb.
@@ -1834,73 +2012,124 @@ Pokud vlastnà možnosti nejsou zobrazeny, musà být konkrétnà hry spuštěny ---- ----------
Pro aktuálnà pÅ™ehled o tom, jak ScummVM sestavit pro různé platformy, prohlédnÄ›te si, prosÃm, naÅ¡Ã Wiki, zvláštÄ› tuto stránku:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM>
Pokud sestavujete ve Windows, Linux nebo Mac OS X, potřebujete SDL-1.2.2
Nebo novÄ›jÅ¡Ã (starÅ¡Ã verze mohou fungovat, ale nejsou podporovány) a podporovaný kompilátor. VÄ›tÅ¡ina kompilátorů, vÄetnÄ› GCC, mingw a novÄ›jÅ¡Ãch verzà Microsoft Visual C++ jsou podporovány. Pokud chcete použÃt stopy CD komprimované do MP3 nebo soubory .SOU, musÃte nainstalovat knihovnu MAD; podobnÄ› potÅ™ebujete vhodné knihovny pro komprimovaný zvuk pomocà Ogg Vorbis a FLAC. Pro komprimované uložené stavy je potÅ™eba mÃt zlib.
-NÄ›které Äásti ScummVM, zvláštÄ› zvÄ›tÅ¡ovaÄe, majà vysoce optimalizované verze napsané v assembleru. Pokud si pÅ™ejete tuto možnost použÃt, potÅ™ebuje mÃt nainstalován assembler nasm (viz http://nasm.sf.net). Nezapomeňte, že v souÄasnosti máme pouze verze optimalizované pro x86 MMX, a nebudou sestaveny pro jiné procesory.
-
-Na Win9x/NT/XP můžete urÄit USE_WINDBG a pÅ™ipojit WinDbg pro procházenà ladÃcÃch zpráv (viz https://technet.microsoft.com/en-us/sysinternals/debugview.aspx).
-
- GCC a MinGW32:
- * Zadejte "./configure"
- * Zadejte "make" (nebo "gmake", Äi "gnumake", v závislosti na tom, jak je GNU make ve VaÅ¡em systému nazván) a ScummVM snad bude pro Vás sestaven.
- * Pro dalšà informace si prohlédněte:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/GCC
- Äi
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/MinGW
-
- Microsoft Visual C++ 9 a novÄ›jÅ¡Ã:
- * PÅ™eÄtÄ›te si, jak vytvoÅ™it soubory projektu v odpovÃdajÃcÃ",
- složce "dists\msvc".
- * Otevřete výsledný soubor projektu.
- * Zadejte cestu k potÅ™ebným knihovnám a hlsiÄkovým souborům v
- Tools|Options|Projects and Solutions|VC++ Directories".
- * TeÄ by program mÄ›l být úspěšnÄ› sestaven.
- * Pro dalšà informace si prohlédněte:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/Visual_Studio
-
- Windows Mobile:
- * PÅ™eÄtÄ›te si prosÃm:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/Windows_CE
-
- Mac OS X:
- * Ujistěte se, že máte nainstalovány nástroje pro vývojáře.
- * BalÃÄek SDL pro vývojáře na OS X, který je dostupný na stránce SDL _nenÃ_ vhodný. SpÃÅ¡e potÅ™ebujete sestavenà v unixovém stylu. Jeden takový způsob, jak ho nainstalovat je pomocà Fink
- (http://fink.sf.net). Také můžete SDL sestavit ruÄnÄ› ze zdrojového kódu pomocà systému sestavenà pro unix (configure a make).
- * Ve složce ScummVM zadejte "./configure".
- * Nynà můžete zadat 'make' pro vytvoÅ™enà spouÅ¡tÄ›Äe pÅ™Ãkazového řádku.
- * Abyste zÃskali verzi, kterou můžete spustit z Finder, zadejte 'make bundle' což vytvořà ScummVM.app (toto se pokusà zjistit kde máte nainstalovány statické knihovny, což by mÄ›lo fungovat ve vÄ›tÅ¡inÄ› pÅ™Ãpadů, pokud ne, musÃte jejich cestu zadat pomocà --with-staticlib-prefix= pÅ™i konfiguraci - napÅ™Ãklad "./configure --with-staticlib-prefix=/Uživatelé/bla" pokud jsou knihovny umÃstÄ›ny v /Uživatelé/bla/lib.
- * Pro dalšà informace si prohlédněte:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/MacOS_X_Crosscompiling
-
- AmigaOS 4 (KřÞová kompilace pomocà Cygwin):
- * Ujistěte se, že máte nainstalován SDL, můžete také potřebovat
- libogg, libvorbis, libvorbisfile, zlib, libmad.
- * Zadejte ./configure --host=ppc-amigaos
- * Pokud dostanete chybu o sdl-config, použijte parametr --with-sdl-prefix pro nastavenà cesty.
- * Zkontrolujte soubor 'config.mk' a pokud je vše v pořádku:
- * Spusťte 'make'.
- * KřÞová kompilace pomocà Linux může být také tak lehká.
-
- iPhone:
- * PÅ™eÄtÄ›te si prosÃm:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/iPhone
-
- Maemo:
- * Nainstalujte Maemo SDK s rootstrap 4.1.2
- * Nainstalujte libmad, Tremor, FLAC ze zdroje
- * Spusťte 'ln -s backends/platform/maemo/debian'
- * Aktualizujte debian/changelog
- * Spusťte 'sb2 dpkg-buildpackage -b'
+NÄ›které Äásti ScummVM, zvláštÄ› zvÄ›tÅ¡ovaÄe, majà vysoce optimalizované verze napsané v assembleru. Pokud si pÅ™ejete tuto možnost použÃt, potÅ™ebuje mÃt nainstalován assembler nasm (viz http://www.nasm.us/). Nezapomeňte, že v souÄasnosti máme pouze verze optimalizované pro x86 MMX, a nebudou sestaveny pro jiné procesory.
+
+Na Win9x/NT/XP můžete urÄit USE_WINDBG a pÅ™ipojit WinDbg pro procházenà ladÃcÃch zpráv (viz <https://technet.microsoft.com/en-us/sysinternals/debugview.aspx)>.
+
+ Windows:
+ * Dev-C++
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/DevCPP>
+ * MinGW
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/MinGW>
+ * Visual Studio (MSVC)
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Visual_Studio>
+ * Windows CE/Mobile
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Windows_CE>
+
+ Linux:
+ * GCC
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/GCC>
+
+ Mac OS X:
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Mac_OS_X>
+
+ AmigaOS4:
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/AmigaOS>
+
+ Apple iPhone:
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/iPhone>
+
+ Atari/FreeMiNT:
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Atari/FreeMiNT>
+
+ Bada/Tizen:
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Bada/Tizen>
+
+ BeOS/ZETA/Haiku:
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/BeOS/ZETA/Haiku>
+
+ Google Android:
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Android>
+
+ HP webOS:
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/WebOS>
+
+ Mac OS:
+ * Mac OS X
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Mac_OS_X>
+ * Mac OS X 10.2.8
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Mac_OS_X_10.2.8>
+ * Mac OS X KřÞová kompilace
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Mac_OS_X_Crosscompiling>
+
+ Maemo:
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Maemo>
+
+ Nintendo DS:
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Nintendo_DS>
+
+ Nintendo Wii a Gamecube:
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Wii>
+
+ RaspberryPi:
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/RPI>
+
+ Sega Dreamcast:
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Dreamcast>
+
+ Sony Playstation:
+ * Sony PlayStation 2
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/PlayStation_2>
+ * Sony PlayStation 3
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/PlayStation_3#Building_from_source>
+ * Sony PlayStation Portable
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/PlayStation_Portable>
+
+ Symbian:
+ PÅ™eÄtÄ›te si prosÃm:
+ <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Symbian>
+
+
+10.0) PodÄ›kovánÃ
+----- ----------
+ProsÃm pÅ™eÄtÄ›te si náš rozsáhlý seznam lidÃ, kterým chceme podÄ›kovat na
+
+<http://www.scummvm.org/credits/>
+
+
+
------------------------------------------------------------------------
HodnÄ› Å tÄ›stà a Šťastné AdventurovánÃ!
Tým ScummVM.
-http://www.scummvm.org/
+<http://www.scummvm.org/>
------------------------------------------------------------------------
-
-
-
-
diff --git a/doc/de/Liesmich b/doc/de/Liesmich index cdc11ffd09..f37fc7d396 100644 --- a/doc/de/Liesmich +++ b/doc/de/Liesmich @@ -20,38 +20,38 @@ Inhaltsverzeichnis: * 3.3 Hinweise zu Spielen auf mehreren CDs * 3.4 Bekannte Probleme * 3.5 Hinweise zu Beneath a Steel Sky - * 3.6 Hinweise zu Baphomets Fluch + * 3.6 Hinweise zu Baphomets Fluch I und II * * 3.6.1 Baphomets Fluch * * 3.6.2 Baphomets Fluch II - * * 3.6.3 Zwischenszenen in Baphomets Fluch - * * 3.6.4 Zwischenszenen in Baphomets Fluch (Rückblick) + * * 3.6.3 Zwischensequenzen in Baphomets Fluch + * * 3.6.4 Zwischensequenzen in Baphomets Fluch (Rückblick) * 3.7 Hinweise zu Day of the Tentacle * 3.8 Hinweise zu Discworld II * 3.9 Hinweise zu DraÄi Historie * 3.10 Hinweise zu Flight of the Amazon Queen * 3.11 Hinweise zu Gobliiins - * 3.12 Hinweise zu Inherit the Earth: Quest for the Orb + * 3.12 Hinweise zu Inherit the Earth: Quest for the Orb (Macintosh) * 3.13 Hinweise zu Maniac Mansion (Apple II/NES) * 3.14 Hinweise zu Mickey's Space Adventure - * 3.15 Hinweise zu Nippon Safes Inc. - * 3.16 Hinweise zu Simon the Sorcerer + * 3.15 Hinweise zu Nippon Safes Inc. (Amiga) + * 3.16 Hinweise zu Simon the Sorcerer 1 und 2 * 3.17 Hinweise zu The Curse of Monkey Island * 3.18 Hinweise zu Floyd – Es gibt noch Helden * 3.19 Hinweise zu The Legend of Kyrandia * 3.20 Hinweise zu Troll's Tale * 3.21 Hinweise zu Winnie the Pooh * 3.22 Hinweise zum vorhersagenden Eingabedialog in AGI-Spielen von Sierra - * 3.23 Gleichzeitige Sprachausgabe und Untertitel SCI-Spielen von Sierra + * 3.23 Gleichzeitige Sprachausgabe und Untertitel in SCI-Spielen von Sierra * 3.24 Hinweise zu den Spielen der Zork-Reihe * 3.25 Hinweise zu Spielen für den Commodore 64 * 3.26 Hinweise zu Spielen für den Macintosh 4.0) Unterstützte Plattformen 5.0) ScummVM verwenden * 5.1 Kommandozeilenoptionen - * 5.2 Sprachoptionen + * 5.2 Globales Menü * 5.3 Grafikfilter - * 5.4 Globales Menü - * 5.5 Tastenkürzel + * 5.4 Tastenkürzel + * 5.5 Sprachoptionen 6.0) Spielstände * 6.1 Automatisches Speichern von Spielständen * 6.2 Spielstände umwandeln @@ -69,14 +69,14 @@ Inhaltsverzeichnis: * 7.7 TiMidity++-MIDI-Server-Unterstützung * 7.8 Komprimierte Audio-Dateien verwenden (MP3, Ogg Vorbis, FLAC) * * 7.8.1 MP3-Dateien für CD-Audio verwenden - * * 7.8.2 Ogg Vorbis-Dateien für CD-Audio verwenden - * * 7.8.3 Flac-Dateien für CD-Audio verwenden + * * 7.8.2 Ogg-Vorbis-Dateien für CD-Audio verwenden + * * 7.8.3 FLAC-Dateien für CD-Audio verwenden * * 7.8.4 MONSTER.SOU mit MP3 komprimieren * * 7.8.5 MONSTER.SOU mit Ogg Vorbis komprimieren - * * 7.8.6 MONSTER.SOU mit Flac komprimieren - * * 7.8.7 Musik/Effekte/Sprache in AGOS-Spielen komprimieren - * * 7.8.8 Sprache/Musik in Baphomets Fluch komprimieren - * * 7.8.9 Sprache/Musik in Baphomets Fluch II komprimieren + * * 7.8.6 MONSTER.SOU mit FLAC komprimieren + * * 7.8.7 Musik/Effekte/Sprachausgabe in AGOS-Spielen komprimieren + * * 7.8.8 Sprachausgabe/Musik in Baphomets Fluch komprimieren + * * 7.8.9 Sprachausgabe/Musik in Baphomets Fluch II komprimieren * 7.9 Ausgabefrequenzen 8.0) Konfigurationsdatei * 8.1 Verwendbare Konfigurationsschlüsselwörter @@ -273,6 +273,7 @@ Spiele von Activision (MADE): Spiele von Adventuresoft/Horrorsoft (AGOS): Elvira - Mistress of the Dark [elvira1] Elvira II - The Jaws of Cerberus [elvira2] + Floyd - Es gibt noch Helden [feeble] Personal Nightmare [pn] Simon the Sorcerer 1 [simon1] Simon the Sorcerer 2 [simon2] @@ -284,7 +285,6 @@ Spiele von Adventuresoft/Horrorsoft (AGOS): - NoPatience [puzzle] Simon the Sorcerer's Game Pack - Swampy Adventures [swampy] - Floyd - Es gibt noch Helden [feeble] Waxworks [waxworks] Spiele von Coktel Vision (GOB): @@ -297,10 +297,9 @@ Spiele von Coktel Vision (GOB): Lost in Time [lostintime] Once Upon A Time: Little Red Riding Hood [littlered] Playtoons: Bambou le sauveur de la jungle [bambou] - The Bizarre Adventures of Woodruff - and the Schnibble [woodruff] Urban Runner [urban] Ween: The Prophecy [ween] + Woodruff and the Schnibble of Azimuth [woodruff] Spiele von Revolution Software: Beneath a Steel Sky [sky] @@ -329,7 +328,7 @@ Spiele von Sierra (AGI und preAGI): Troll's Tale [troll] Winnie the Pooh in the Hundred Acre Wood [winnie] -SCI-Spiele von Sierra Entertainment: +Spiele von Sierra (SCI): Codename: ICEMAN [iceman] Conquests of Camelot [camelot] Conquests of the Longbow [longbow] @@ -373,17 +372,22 @@ SCI-Spiele von Sierra Entertainment: Andere Spiele: 3 Skulls of the Toltecs [toltecs] Amazon: Guardians of Eden [access] + Baphomets Fluch 2.5: + Die Rückkehr der Tempelritter [sword25] Beavis and Butt-head in Virtual Stupidity [bbvs] Blue Force [blueforce] - Baphomets Fluch: Die Rückkehr der Templer [sword25] Bud Tucker in Double Trouble [tucker] Chivalry is Not Dead [chivalry] Cruise for a Corpse [cruise] - DreamWeb [dreamweb] + Die ungelösten Fälle von Sherlock Holmes: + Das gezackte Skalpell [scalpel] + Die ungelösten Fälle von Sherlock Holmes: + Die tätowierte Rose [rosetattoo] Discworld [dw] Discworld 2: Vermutlich vermisst [dw2] DraÄi Historie [draci] Drascula: The Vampire Strikes Back [drascula] + DreamWeb [dreamweb] Erben der Erde: Die große Suche [ite] Eye of the Beholder [eob] Eye of the Beholder II: The Legend of @@ -403,25 +407,20 @@ Andere Spiele: Return to Ringworld [ringworld2] Sfinx [sfinx] Soltys [soltys] + TeenAgent [teenagent] + The 7th Guest [t7g] The Journeyman Project: Pegasus Prime [pegasus] The Legend of Kyrandia [kyra1] The Legend of Kyrandia: The Hand of Fate [kyra2] The Legend of Kyrandia: Malcolm's Revenge [kyra3] - The Lost Files of Sherlock Holmes: The Case - of the Serrated Scalpel [scalpel] - The Lost Files of Sherlock Holmes: The Case - of the Rose Tattoo [rosetattoo] The Neverhood [neverhood] - The 7th Guest [t7g] - TeenAgent [teenagent] - Toonstruck [toon] Tony Tough and the Night of Roasted Moths [tony] Toonstruck [toon] Touché: Die Abenteuer des fünften Musketiers [touche] Voyeur [voyeur] - Zork: Grand Inquisitor [zgi] - Zork Nemesis: The Forbidden Lands [znemesis] + Zork: Der Großinquisitor [zgi] + Zork Nemesis: Das verbotene Land [znemesis] Spiele von Humongous Entertainment (SCUMM): Backyard Baseball [baseball] @@ -517,10 +516,10 @@ ScummVM unterstützt: Seien Sie sich bitte bewusst, dass die Engines („Motoren“ der Spiele) Fehler enthalten können und manche Funktionen möglicherweise fehlen, was es unmöglich -machten kann, das Spiel zu Ende zu spielen. Speichern Sie oft und bitte schicken Sie -englischsprachige Fehlerberichte ein (Anweisungen zum Senden von Fehlerberichten finden -Sie oben), wenn Sie einen solchen Fehler in einem „unterstützten“ Spiel -vorfinden. +machen kann, das Spiel zu Ende zu spielen. Speichern Sie oft und bitte schicken +Sie englischsprachige Fehlerberichte ein (Anweisungen zum Senden von +Fehlerberichten finden Sie oben), wenn Sie einen solchen Fehler in einem +„unterstützten“ Spiel vorfinden. 3.1) Kopierschutz: @@ -562,16 +561,16 @@ ScummVM wird den Kopierschutz in folgenden Spielen überspringen: * Zak McKracken and the Alien Mindbenders -3.2) Spieldateien ----- ------------ -Für eine ausführliche Liste der benötigten Spieldateien für unterstützte -Spiele, besuchen Sie: +3.2) Spieldateien: +---- ------------- +Für eine ausführliche Liste der benötigten Spieldateien für unterstützte Spiele, +besuchen Sie: - <http://wiki.scummvm.org/index.php/Datafiles> + http://wiki.scummvm.org/index.php/Datafiles 3.3) Hinweise zu Spielen auf mehreren CDs: ----- ----------------------------------- +---- ------------------------------------- Allgemein kann ScummVM nicht sehr gut mit Spielen auf mehreren CDs umgehen. Das liegt daran, dass ScummVM annimmt, alles von einem Spiel in einem Verzeichnis vorzufinden. Selbst wenn ScummVM einige Fälle berücksichtigt und den Anwender @@ -588,20 +587,20 @@ hineinkopieren. 3.4) Bekannte Probleme: ------ ------------------ -Diese Version hat die unten folgenden bekannten Probleme. Es ist -nicht notwendig, diese zu melden, jedoch sind Patches, um diese zu beheben, +---- ------------------ +Diese Version hat die unten folgenden bekannten Probleme. Es ist nicht +notwendig, diese zu melden, jedoch sind Patches, um diese zu beheben, willkommen. Wenn Sie einen Fehler entdecken, der weder hier noch auf der Kompatibilitätsseite der Website aufgeführt ist, sehen Sie bitte im Abschnitt „Fehler melden“ nach, wenn Sie diesen melden möchten. Spiele mit Ton von CD: - Bei Spielen, die auf Audio von CD zurückgreifen (FM-TOWNS-Spiele, - CD-Version von Loom usw.), ist es möglich, dass Anwender von Microsoft Windows - 2000/XP zufällige Abstürze erleben. Das liegt an einem lange bestehenden - Windows-Fehler, der dazu führt, dass fehlerhafte Spieldaten von der CD - ausgelesen werden. Bitte kopieren Sie die Spieldaten in ein Verzeichnis - Ihrer Festplatte, um dies zu vermeiden. + CD-Version von Loom usw.), ist es möglich, dass Anwender von Microsoft + Windows 2000/XP zufällige Abstürze erleben. Das liegt an einem lange + bestehenden Windows-Fehler, der dazu führt, dass fehlerhafte Spieldaten + von der CD ausgelesen werden. Bitte kopieren Sie die Spieldaten in ein + Verzeichnis Ihrer Festplatte, um dies zu vermeiden. FM-TOWNS-Versionen: - Die Kanji-Versionen erfordern die Schriftart-ROM-Datei von FM-TOWNS. @@ -636,7 +635,7 @@ Kompatibilitätsseite der Website aufgeführt ist, sehen Sie bitte im Abschnitt Lure of the Temptress: - Keine Unterstützung für Roland MT32 - - Sound-Unterstützung ist unvollständig und klingt nicht wie das Original + - Sound-Unterstützung ist unvollständig und klingt nicht wie ursprünglich. Simon the Sorcerer 1: - Untertitel sind in den deutschen und englischen CD-Versionen nicht @@ -794,8 +793,8 @@ Sache, da das Entschlüsseln von MPEG-Filmen mit vielen Schwierigkeiten verbunde war und diese ohnehin nicht so gut aussahen wie Smacker- und DXA-Versionen. -3.7) Hinweise zu Day of the Tentacle ----- ------------------------------- +3.7) Hinweise zu Day of the Tentacle: +---- -------------------------------- An einem bestimmten Punkt im Spiel kommen Sie an einem Computer vorbei, der Ihnen erlaubt, das originale Maniac Mansion zu spielen. ScummVM unterstützt @@ -816,9 +815,10 @@ festlegen können. Jedoch erlauben nicht alle Spiele die Rückkehr zum Hauptmenà Es ist nicht empfehlenswert, Day of the Tentacle selbst als Easter-Egg-Spiel festzulegen. -3.8) Hinweise zu Discworld II ----- ------------------------ -Für diese Spiel benötien Sie alle Dateien im Verzeichnis DW2 auf beiden CDs. + +3.8) Hinweise zu Discworld II: +---- ------------------------- +Für diese Spiel benötigen Sie alle Dateien im Verzeichnis DW2 auf beiden CDs. Zusätzlich benötigen Sie die Datei SAMPLE.BNK. Sie müssen ENGISH.SMP, ENGLISH.IDX und ENGLISH.TXT von CD1 zu ENGLISH1.SMP, @@ -945,8 +945,8 @@ unkomplizierter ist, als sich mit dem Menü umherzubewegen. Für dieses Spiel benötigen Sie die Dateien disk0, global.table, pointer und it (en, fr, ge für die internationale Version). -Zusätzlich müssen Sie das Diskettenabbild 2 in disk1, Abbild 3 in disk2, Abbild 4 -in disk3 sowie Abbild 5 in disk4 umbenennen. +Zusätzlich müssen Sie das Diskettenabbild 2 in disk1, Abbild 3 in disk2, +Abbild 4 in disk3 sowie Abbild 5 in disk4 umbenennen. 3.16) Hinweise zu Simon the Sorcerer 1 und 2: @@ -973,10 +973,11 @@ diesem Fall identisch. Amiga/Macintosh: Sie benötigen ein kleines Paket mit Zwischensequenzen, welche sowohl in der Amiga- als auch in der Macintosh-Version fehlen. Es heißt -"The Feeble Files- Omni TV and epilogue cutscenes for the Amiga and Macintosh versions" +„The Feeble Files - Omni TV and epilogue cutscenes for the Amiga and Macintosh +versions“ und kann hier heruntergeladen werden: - <http://www.scummvm.org/games/#feeble> + http://www.scummvm.org/games/#feeble Windows: Wenn Sie die Windows-Version von Floyd – Es gibt noch Helden haben, sind einige @@ -1141,77 +1142,84 @@ Space Quest 4 CD: deaktiviert und aktiviert werden. -3.24) Hinweise zu den Spielen der Zork-Reihe ------ -------------------------------------- -Um die unterstützen Zork-Spiele (Zork Nemesis: The Forbidden Lands -und Zork: Grand Inquisitor) zu spielen, müssen Sie einige zusätzliche +3.24) Hinweise zu den Spielen der Zork-Reihe: +----- --------------------------------------- +Um die unterstützen Zork-Spiele (Zork Nemesis: Das verbotene Land und +Zork: Der Großinquisitor) spielen zu können, müssen Sie einige zusätzliche Dateien zu ihren entsprechenden Zielen kopieren. -Zork Nemesis: The Forbidden Lands +Zork Nemesis: Das verbotene Land Alle Versionen -Laden Sie das Liberation(tm)-Schriftartenpaket -<https://fedorahosted.org/releases/l/i/liberation-fonts/liberation-fonts-ttf-2.00.1.tar.gz> -herunter und entpacken Sie alle ttf-Dateien in Ihr ScummVM "extras"-Verzeichnis. -Alternativ können Sie auch das GNU FreeFont TTF-Paket unter -<https://ftp.gnu.org/gnu/freefont/freefont-ttf.zip> herunterladen und alle ttf-Dateien -aus dem sfd-Verzeichnis in Ihr ScummVM "extras"-Verzeichnis kopieren. Diese Schriftarten -können Probleme mit der Textdarstellung verursachen. -Laden Sie den Untertitel-Patch -<http://www.thezorklibrary.com/installguides/znpatch.zip> herunter und entpacken -Sie das Verzeichnis "addon" in das Hauptverzeichnis des Spiels. + +Laden Sie das Liberation(tm)-Schriftartenpaket unter +https://fedorahosted.org/releases/l/i/liberation-fonts/liberation-fonts-ttf- +2.00.1.tar.gz +herunter und entpacken Sie alle ttf-Dateien in ScummVMs Extras-Pfad. Alternativ +können Sie auch das GNU FreeFont TTF-Paket unter +https://ftp.gnu.org/gnu/freefont/freefont-ttf.zip +herunterladen und alle ttf-Dateien aus dem sfd-Verzeichnis in ScummVMs Extras- +Pfad kopieren. Diese Schriftarten können Probleme bei der Textdarstellung +verursachen. Laden Sie den Untertitel-Patch unter +http://www.thezorklibrary.com/installguides/znpatch.zip +herunter und entpacken Sie das Verzeichnis "addon" in das Hauptverzeichnis des +Spiels. GoG-Version -Verwenden Sie das GoG-Installationsprogramm. Keine weiteren Dateien müssen kopiert werden. +Verwenden Sie das GoG-Installationsprogramm. Keine weiteren Dateien müssen +kopiert werden. CD-Version -Kopieren Sie folgende Verzeichnisse und Dateien aus dem Verzeichnis "nemesis" auf CD1 -in das Hauptverzeichnis des Spiels: -Das Verzeichnis "znemmx" -Das Verzeichnis "znemscr" +Kopieren Sie folgende Verzeichnisse und Dateien aus dem Verzeichnis "nemesis" +auf CD1 in das Hauptverzeichnis des Spiels: +das Verzeichnis "znemmx" +das Verzeichnis "znemscr" nemesis.str -Von CD1, kopieren Sie das Verzeichnis "zassets" in das Hauptverzeichnis des Spiels. -Von CD2, kopieren Sie das Verzeichnis "zassets" in das Hauptverzeichnis des Spiels und -überschreiben Sie alle identischen Dateien. -Von CD3, kopieren Sie das Verzeichnis "zassets" in das Hauptverzeichnis des Spiels und -überschreiben Sie alle identischen Dateien. +Von CD1 kopieren Sie das Verzeichnis "zassets" in das Hauptverzeichnis des +Spiels. +Von CD2 kopieren Sie das Verzeichnis "zassets" in das Hauptverzeichnis des +Spiels und überschreiben Sie alle identischen Dateien. +Von CD3 kopieren Sie das Verzeichnis "zassets" in das Hauptverzeichnis des +Spiels und überschreiben Sie alle identischen Dateien. DVD-Version -Kopieren Sie folgende Verzeichnisse und Dateien aus dem Verzeichnis "nemesis" auf CD1 -in das Hauptverzeichnis des Spiels: +Kopieren Sie folgende Verzeichnisse und Dateien aus dem Verzeichnis "nemesis" +auf CD1 in das Hauptverzeichnis des Spiels: Das Verzeichnis "znemmx" Das Verzeichnis "znemscr" nemesis.str -Hinweis: Sie müssen auch die Datei cursor.zfs vom Verzeichnis "zassets/global" in -das Verzeichnis "znemscr" verschieben. -Kopieren Sie die Verzeichnisse "disc2", "disc3" und "zassets" in das Hauptverzeichnis -des Spiels. +Hinweis: Sie müssen auch die Datei cursor.zfs vom Verzeichnis "zassets/global" +in das Verzeichnis "znemscr" verschieben. +Kopieren Sie die Verzeichnisse "disc2", "disc3" und "zassets" in das +Hauptverzeichnis des Spiels. -Zork: Grand Inquisitor +Zork: Der Großinquisitor Alle Versionen -Alle Versionen -Laden Sie das Liberation(tm)-Schriftartenpaket -<https://fedorahosted.org/releases/l/i/liberation-fonts/liberation-fonts-ttf-2.00.1.tar.gz> -herunter und entpacken Sie alle ttf-Dateien in Ihr ScummVM "extras"-Verzeichnis. +Laden Sie das Liberation(tm)-Schriftartenpaket unter +https://fedorahosted.org/releases/l/i/liberation-fonts/liberation-fonts-ttf- +2.00.1.tar.gz +herunter und entpacken Sie alle ttf-Dateien in ScummVMs Extras-Pfad. Alternativ können Sie auch das GNU FreeFont TTF-Paket unter -<https://ftp.gnu.org/gnu/freefont/freefont-ttf.zip> herunterladen und alle ttf-Dateien -aus dem sfd-Verzeichnis in Ihr ScummVM "extras"-Verzeichnis kopieren. Diese Schriftarten -können Probleme mit der Textdarstellung verursachen. +https://ftp.gnu.org/gnu/freefont/freefont-ttf.zip +herunterladen und alle ttf-Dateien aus dem sfd-Verzeichnis in ScummVMs Extras- +Pfad kopieren. Diese Schriftarten können Probleme bei der Textdarstellung +verursachen. GoG-Version -Verwenden Sie das GoG-Installationsprogramm. Es müssen keine weiteren Dateien kopiert werden. +Verwenden Sie das GoG-Installationsprogramm. Es müssen keine weiteren Dateien +kopiert werden. CD-Version: -Kopieren Sie die folgenden Verzeichnisse und Dateien aus dem Verzeichnis "zgi" von CD1 -in das Hauptverzeichnis des Spiels: +Kopieren Sie die folgenden Verzeichnisse und Dateien aus dem Verzeichnis "zgi" +von CD1 in das Hauptverzeichnis des Spiels: das Verzeichnis "zgi_mx" cursor.zfs death.zfs @@ -1220,19 +1228,21 @@ inquis.zix r.svr scripts.zfs subtitle.zfs -Von CD1, kopieren Sie das Verzeichnis "zassets1" in das Hauptverzeichnis des Spiels -Von CD2, kopieren Sie das Verzeichnis "zassets2" in das Hauptverzeichnis des Spiels -Es wird empfohlen, den Patch 1.2 anzuwenden. -<http://www.thezorklibrary.com/installguides/Zpatch.exe> +Von CD1 kopieren Sie das Verzeichnis "zassets1" in das Hauptverzeichnis des +Spiels. +Von CD2 kopieren Sie das Verzeichnis "zassets2" in das Hauptverzeichnis des +Spiels. +Es wird empfohlen, den hier erhältlichen Patch 1.2 anzuwenden: +http://www.thezorklibrary.com/installguides/Zpatch.exe Möglicherweise müssen Sie das Spiel zuvor normal installieren, da der Patch ein eigenes Installationsprogramm besitzt. DVD-Version -Kopieren Sie die folgenden Verzeichnisse und Dateien aus dem Verzeichnis "zgi_e" +Kopieren Sie die folgenden Verzeichnisse und Dateien aus dem Verzeichnis "zgi_e" in das Hauptverzeichnis des Spiels: -Das Verzeichnis "addon" (Spiel-Patch 1.2) -Das Verzeichnis zgi_mx +das Verzeichnis "addon" (Spiel-Patch 1.2) +das Verzeichnis zgi_mx cursor.zfs death.zfs inquis.str @@ -1240,13 +1250,13 @@ inquis.zix r.svr scripts.zfs subtitle.zfs -Kopieren Sie das Verzeichnis "eng_mpeg" (hochauflösende MPEG2-Videodateien") in das -Hauptverzeichnis des Spiels. Kopieren Sie die Verzeichnisse "zassetsc" und "zassetse" -ebenfalls in das Hauptverzeichnis des Spiels. +Kopieren Sie das Verzeichnis "eng_mpeg" (hochauflösende MPEG2-Videodateien) in +das Hauptverzeichnis des Spiels. Kopieren Sie die Verzeichnisse "zassetsc" und +"zassetse" ebenfalls in das Hauptverzeichnis des Spiels. 3.25) Hinweise zu Spielen für den Commodore 64: ----- ------------------------------------------ +----- ----------------------------------------- Sowohl Maniac Mansion als auch Zak McKracken laufen, aber Maniac Mansion ist noch nicht spielbar. Benennen Sie einfach die D64-Datenträger um in „maniac1.d64“ und „maniac2.d64“ und entsprechend „zak1.d64“ und „zak2.d64“, dann @@ -1260,8 +1270,8 @@ Plattform eingestellt ist. Wir empfehlen, auf die viel einfachere Methode zurückzugreifen, die im vorherigen Absatz beschrieben ist. -3.5) Hinweise zu Spielen für den Macintosh: ----- -------------------------------------- +3.26) Hinweise zu Spielen für den Macintosh: +----- -------------------------------------- Alle auf SCUMM basierenden Adventures von Lucasarts, mit Ausnahme von COMI, existieren auch als Versionen für den Macintosh. ScummVM kann die meisten (alle?) von diesen verwenden, jedoch ist in manchen Fällen zusätzliche Arbeit @@ -1431,8 +1441,9 @@ gestartet werden -- siehe nächster Abschnitt. --output-rate=FREQUENZ Wählt Ausgabefrequenz in Hz (z. B. 22050). --opl-driver=TREIBER Wählt AdLib-(OPL-)Emulator (db, mame). --aspect-ratio Aktiviert Seitenverhältniskorrektur. - --render-mode=MODUS Aktiviert zusätzlichen Render-Modus (cga, ega, - hercGreen, hercAmber, amiga). + --render-mode=MODUS Aktiviert zusätzlichen Render-Modus (hercGreen, + hercAmber, cga, ega, vga, amiga, fmtowns, pc9821, + pc9801, 2gs, atari, macintosh). --alt-intro Verwendet alternativen Vorspann in CD-Versionen von Beneath a Steel Sky und Flight of the Amazon Queen. @@ -1582,6 +1593,7 @@ zwischen SCUMM-Spielen und anderen Spielen. Strg+F5 - Zeigt globales Menü. Cmd+q - Beenden (Mac OS X) Strg+q - Beenden (andere UNIX-Systeme einschließlich Linux) + Alt+F4 - Beenden (Windows) Strg+z ODER Alt+x - Beenden (andere Plattformen) Strg+u - Allen Ton abschalten - EIN/AUS Strg+m - Mausbegrenzung in Fenster EIN/AUS @@ -1735,27 +1747,28 @@ zwischen SCUMM-Spielen und anderen Spielen. Escape - Beenden Leertaste - Ãœberspringt aktuelle Textzeile. t - Wechselt zwischen „Nur Sprachausgabe“, - „Sprachausgabe und Text“ und „Nur Text“ - - Zork: Grand Inquisitor: - Ctrl-s - Save - Ctrl-r - Restore - Ctrl-q - Quit - Ctrl-p - Preferences - F1 - Help - F5 - Inventory - F6 - Spellbook - F7 - Score - F8 - Put away current object/forget spell - F9 - Extract coin (must have the coin bag) - Space - Skips movies - - Zork Nemesis: The Forbidden Lands: - Ctrl-s - Save - Ctrl-r - Restore - Ctrl-q - Quit - Ctrl-p - Preferences - Space - Skips movies + „Sprachausgabe und Text“ und „Nur Text“. + + Zork: Der Großinquisitor: + Strg+s - Speichern + Strg+r - Laden + Strg+q - Beenden + Strg+p - Einstellungen + F1 - Hilfe + F5 - Inventar + F6 - Zauberbuch + F7 - Punkte + F8 - Aktuelles Objekt wegtun / Zauberspruch vergessen + F9 - Münze hervorholen (muss Münzentasche haben) + Space - Ãœberspringt Zwischensequenzen. + + Zork Nemesis: Das verbotene Land: + Strg+s - Speichern + Strg+r - Laden + Strg+q - Beenden + Strg+p - Einstellungen + Leertaste - Ãœberspringt Zwischensequenzen. + Beachten Sie, dass von der Verwendung von Strg+f oder Strg+g abgeraten wird: Spiele können abstürzen, wenn sie schneller als mit ihrer normalen @@ -1838,8 +1851,8 @@ Die folgenden Plattformen haben ein anderes Standard-Verzeichnis: $HOME/Documents/ScummVM Savegames/ Andere UNIX-Systeme: - Wir befolgen die "XDG Base Directory"-Spezifikation. Dies bedeutet, dass - die Spielstände in: + Wir befolgen die Spezifikation XDG Base Directory. Dies bedeutet, dass + die Spielstände in $XDG_DATA_HOME/scummvm/saves/ gespeichert werden. @@ -1847,8 +1860,8 @@ Die folgenden Plattformen haben ein anderes Standard-Verzeichnis: Wert für XDG_DATA_HOME in Ãœbereinstimmung mit der Spezifikation verwendet. Wenn eine frühere Version von ScummVM auf Ihrem System installiert war, wird - das ursprüngliche Standard-Verzeichnis "~/.scummvm" beibehalten. Dies wird daran - erkannt, dass der Pfad "~/.scummvm" vorhanden ist. + das ursprüngliche Standard-Verzeichnis „~/.scummvm“ beibehalten. Dies wird + daran erkannt, dass der Pfad „~/.scummvm“ vorhanden ist. Windows Vista/7/8/10: \Users\Benutzername\AppData\Roaming\ScummVM\Saved games\ @@ -1862,14 +1875,15 @@ Die folgenden Plattformen haben ein anderes Standard-Verzeichnis: Application Data\ScummVM\Saved games\ Spielstände werden unter Windows NT4/2000/XP/Vista/7/8/10 in einem versteckten -Verzeichnis gespeichert, auf welches über den Pfad "%APPDATA%\ScummVM\Saved Games\" -zugegriffen werden kann. Es wir auch sichtbar, wenn die Anzeige von versteckten -Dateien im Windows Explorer aktiviert wird. +Verzeichnis gespeichert, auf welches über den Pfad +„%APPDATA%\ScummVM\Saved Games\“ zugegriffen werden kann. Es wird auch sichtbar, +wenn die Anzeige versteckter Dateien im Windows Explorer aktiviert wird. + +Hinweis für Anwender von Windows NT4/2000/XP/Vista/7/8/10: Das Standard- +Verzeichnis für Spielstände wurde bei ScummVM 1.5.0 geändert. Die +Stapelverarbeitungsdatei migration.bat kann verwendet werden, um die Spielstände +vom alten Standard-Verzeichnis in das neue zu kopieren. -Hinweis für Anwender von Windows NT4/2000/XP/Vista/7/8/10: Das Standard-Verzeichnis -für Spielstände wurde bei ScummVM 1.5.0 geändert. Die Stapelverarbeitungsdatei -migration.bat kann verwendet werden, um die Spielstände vom alten -Standard-Verzeichnis in das neue zu kopieren. 6.1) Automatische Speicherung der Spielstände: ---- ----------------------------------------- @@ -2466,7 +2480,7 @@ Ausgabefrequenz ein Vielfaches der Originalfrequenz ist. ---- -------------------- Standardmäßig wird die Konfigurationsdatei hier gespeichert und geladen: - Windows Vista/7/8/10: + Windows Vista/7: \Users\Benutzername\AppData\Roaming\ScummVM\scummvm.ini Windows 2000/XP: @@ -2484,8 +2498,8 @@ Standardmäßig wird die Konfigurationsdatei hier gespeichert und geladen: der frühere Standard-Ort „<Windows-Verzeichnis>\scummvm.ini“ beibehalten. Unix: - Wir befolgen die "XDG Base Directory"-Spezifikation. Dies bedeutet, dass - unsere Konfiguration in: + Wir befolgen die Spezifikation XDG Base Directory. Dies bedeutet, dass + unsere Konfiguration in $XDG_DATA_HOME/scummvm/scummvm.ini gefunden werden kann. @@ -2493,9 +2507,8 @@ Standardmäßig wird die Konfigurationsdatei hier gespeichert und geladen: Wert für XDG_DATA_HOME in Ãœbereinstimmung mit der Spezifikation verwendet. Wenn eine frühere Version von ScummVM auf Ihrem System installiert war, wird - das ursprüngliche Standard-Verzeichnis "~/.scummvm" beibehalten. Dies wird daran - erkannt, dass der Pfad "~/.scummvm" vorhanden ist. - + das ursprüngliche Standard-Verzeichnis „~/.scummvm“ beibehalten. Dies wird + daran erkannt, dass der Pfad „~/.scummvm“ vorhanden ist. Mac OS X: ~/Library/Preferences/ScummVM Preferences @@ -2771,7 +2784,7 @@ Schlüsselwort: Geschwindigkeit wiedergegeben, um Probleme bei der Musik-Synchronität zu vermeiden. -Zork Nemesis: The Forbidden Lands verfügt zusätzlich über folgende nicht +Zork Nemesis: Das verbotene Land verfügt zusätzlich über folgende nicht standardmäßige Schlüsselwörter: originalsaveload Bool Falls „true“, werden die originalen Menüs zum @@ -2782,11 +2795,11 @@ standardmäßige Schlüsselwörter: noanimwhileturning Bool Falls „true“, werden Animationen während des Drehens im Panorama-Modus deaktiviert. mpegmovies Bool Falls „true“, werden hochauflösende MPEG-Videos - der DVD-Version im Spiel verwendet, anstelle der + der DVD-Version im Spiel verwendet anstelle der niedrig auflösenden AVI-Videos. -Zork: Grand Inquisitor verfügt zusätzlich über folgende nicht -standardmäßige Schlüsselwörter: +Zork: Der Großinquisitor verfügt zusätzlich über folgende nicht standardmäßige +Schlüsselwörter: originalsaveload Bool Falls „true“, werden die originalen Menüs zum Speichern und Laden statt der erweiterten @@ -2796,12 +2809,12 @@ standardmäßige Schlüsselwörter: noanimwhileturning Bool Falls „true“, werden Animationen während des Drehens im Panorama-Modus deaktiviert. mpegmovies Bool Falls „true“, werden hochauflösende MPEG-Videos - der DVD-Version im Spiel verwendet, anstelle der + der DVD-Version im Spiel verwendet anstelle der niedrig auflösenden AVI-Videos. -8.2) Spielspezifische Optionen der grafischen Benutzeroberfläche ----- --------------------------------------------------------------- +8.2) Spielspezifische Optionen bei der grafischen Benutzeroberfläche: +---- ---------------------------------------------------------------- Viele spielspezifische Optionen, die im vorigen Abschnitt aufgeführt wurden, können über die grafische Benutzeroberfläche angesprochen werden. Falls eine spielspezifische Option für ein bestimmtes Spiel verfügbar ist, erscheint ein @@ -2813,7 +2826,7 @@ aktualisiert, was die spielspezifischen Optionen zum Vorschein bringt. 9.0) Kompilieren: ----- ------------- +---- ------------ Für eine aktuelle Ãœbersicht dazu, wie man ScummVM für unterschiedliche Plattformen kompiliert, schauen Sie bitte in unserem Wiki nach, insbesondere auf dieser Seite: @@ -2821,12 +2834,12 @@ dieser Seite: Wenn Sie für Windows, Linux oder Mac OS X kompilieren, benötigen Sie SDL-1.2.2 oder höher (ältere Versionen funktionieren möglicherweise, haben aber keinen -Support) und einen unterstützten Compiler. Mehrere Compiler, -einschließlich GCC, mingw und neue Versionen von Microsoft Visual C++ werden -unterstützt. Wenn Sie mit MP3 komprimierte CD-Titel oder .SOU-Dateien verwenden -möchten, müssen Sie die MAD-Bibliothek installieren; ebenso benötigen Sie die -geeigneten Bibliotheken für Sound-Dateien, die mit Ogg Vorbis und FLAC -komprimiert wurden. Für komprimierte Speicherstände ist zlib erforderlich. +Support) und einen unterstützten Compiler. Mehrere Compiler, einschließlich GCC, +mingw und neue Versionen von Microsoft Visual C++ werden unterstützt. Wenn Sie +mit MP3 komprimierte CD-Titel oder .SOU-Dateien verwenden möchten, müssen Sie +die MAD-Bibliothek installieren; ebenso benötigen Sie die geeigneten +Bibliotheken für Sound-Dateien, die mit Ogg Vorbis und FLAC komprimiert wurden. +Für komprimierte Speicherstände ist zlib erforderlich. Von einigen Teilen in ScummVM, insbesondere Grafikwandlern, gibt es stark optimierte Versionen, die in Assembler geschrieben sind. Wenn Sie diese @@ -2843,102 +2856,103 @@ Debug-Nachrichten zu durchsuchen Windows: * Dev-C++ Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/DevCPP> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/DevCPP * MinGW Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/MinGW> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/MinGW * Visual Studio (MSVC) Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Visual_Studio> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/Visual_Studio * Windows CE/Mobile Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Windows_CE> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/Windows_CE Linux: * GCC Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/GCC> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/GCC AmigaOS4: Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/AmigaOS> + http://wiki.scummvm.org/index.php/AmigaOS Apple iPhone: Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/iPhone> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/iPhone Atari/FreeMiNT: Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Atari/FreeMiNT> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/Atari/FreeMiNT Bada/Tizen: Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Bada/Tizen> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/Bada/Tizen BeOS/ZETA/Haiku: Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/BeOS/ZETA/Haiku> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/BeOS/ZETA/Haiku Google Android: Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Android> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/Android HP webOS: Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/WebOS> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/WebOS Mac OS: * Mac OS X Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Mac_OS_X> + http://wiki.scummvm.org/index.php/Mac_OS_X * Mac OS X 10.2.8 Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Mac_OS_X_10.2.8> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/Mac_OS_X_10.2.8 * Mac OS X Crosscompiling Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Mac_OS_X_Crosscompiling> +http://wiki.scummvm.org/index.php/Compiling_ScummVM/Mac_OS_X_Crosscompiling Maemo: Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Maemo> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/Maemo Nintendo DS: Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Nintendo_DS> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/Nintendo_DS Nintendo Wii and Gamecube: Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Wii> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/Wii RaspberryPi: Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/RPI> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/RPI Sega Dreamcast: Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Dreamcast> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/Dreamcast Sony Playstation: * Sony PlayStation 2 Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/PlayStation_2> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/PlayStation_2 * Sony PlayStation 3 Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/PlayStation_3#Building_from_source> + http://wiki.scummvm.org/index.php/PlayStation_3#Building_from_source * Sony PlayStation Portable Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/PlayStation_Portable> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/PlayStation_Portable Symbian: Weiterführende Informationen finden Sie unter: - <http://wiki.scummvm.org/index.php/Compiling_ScummVM/Symbian> + http://wiki.scummvm.org/index.php/Compiling_ScummVM/Symbian 10.0) Mitwirkende ----- ------- -Eine ausführliche Liste derjenigen, die ScummVM ermöglicht haben, finden Sie unter: +Eine ausführliche Liste derjenigen, die ScummVM ermöglicht haben, finden Sie +unter: - <http://www.scummvm.org/credits/> + http://www.scummvm.org/credits/ ------------------------------------------------------------------------ diff --git a/doc/de/Neues b/doc/de/Neues index 1b109a91f0..ef462c189c 100644 --- a/doc/de/Neues +++ b/doc/de/Neues @@ -2,36 +2,50 @@ Umfangreichere Informationen über die Änderungen des aktuellen experimentellen Programmcodes finden Sie auf Englisch unter: https://github.com/scummvm/scummvm/commits/ -1.8.0 (??.??.????) +1.9.0 (DD.MM.YYYY) + AGI: + - Unterstützung für Hercules-Darstellung (Grün + Bernstein) hinzugefügt + - Unterstützung für hochauflösende Hercules-Schriftart hinzugefügt + (auch außerhalb der Hercules-Darstellung nutzbar) + - Optionale Funktion "Pause, wenn Befehle eingegeben werden" hinzugefügt. + Diese Funktion war im originalen Interpreter nur im Hercules-Darstellungsmodus + verfügbar. + + +1.8.0 (04.03.2016) Neue Spiele: - Unterstützung für Rex Nebular and the Cosmic Gender Bender hinzugefügt. - Unterstützung für Sfinx hinzugefügt. - - Unterstützung für Zork Nemesis: The Forbidden Lands hinzugefügt. - - Unterstützung für Zork: Grand Inquisitor hinzugefügt. - - Unterstützung für The Lost Files of Sherlock Holmes: The Case of the Serrated Scalpel - hinzugefügt. - - Unterstützung für The Lost Files of Sherlock Holmes: The Case of the Rose Tattoo hinzugefügt. + - Unterstützung für Zork Nemesis: Das verbotene Land hinzugefügt. + - Unterstützung für Zork: Der Großinquisitor hinzugefügt. + - Unterstützung für Die ungelösten Fälle von Sherlock Holmes: Das gezackte + Skalpell hinzugefügt. + - Unterstützung für Die ungelösten Fälle von Sherlock Holmes: Das Geheimnis + der tätowierten Rose hinzugefügt. - Unterstützung für Beavis and Butthead in Virtual Stupidity hinzugefügt. - Unterstützung für Amazon: Guardians of Eden hinzugefügt. - - Unterstützung für Broken Sword 2.5: The Return of the Templars hinzugefügt. + - Unterstützung für Baphomets Fluch 2.5: Die Rückkehr der Tempelritter + hinzugefügt. - Unterstützung für Labyrinth of Time hinzugefügt. - Neue Portierungen: - - Portierung auf den Raspberry Pi erfolgt. +Neue Portierungen: + - Portierung für den Raspberry Pi hinzugefügt. + - Portierung für den GCW Zero (GCW0) hinzugefügt. Allgemein: - Code für Munt-MT-32-Emulation auf Version 1.5.0 aktualisiert. SDL: - - Alt-x beendet ScummVM nicht mehr auf Plattformen, die dieses Problem - zuvor gezeigt haben. Ein bedeutendes Beispiel dafür ist unsere Version für Windows. - Auf POSIX-Systemen befolgen wir nun die "XDG Base Directory Specification" für die - Speicherung von Benutzerdaten. Dies resultiert in neuen Speicherorten für unsere - Konfigurationsdatei, unsere Log-Datei sowie für den standardmäßig voreingestellten - Speicherort für Spielstände. Wir unterstützen weiterhin die vorherigen Speicherorte. - Solange diese vorhanden sind, werden wir diese weiter verwenden. Bitte beachten Sie die - Liesmich-Datei für weitere Informationen. Speicherorte auf Mac OS X sind von dieser - Änderung nicht betroffen. + - Alt+x beendet ScummVM nicht mehr. Verwenden Sie stattdessen + Cmd+q/Strg+q/Strg+z und beachten Sie die Hinweise in der Liesmich-Datei. + - Auf POSIX-Systemen befolgen wir nun die Spezifikation XDG Base Directory + für die Speicherung von Benutzerdaten. Dies führt zu neuen + Speicherorten für unsere Konfigurationsdatei, unsere Log-Datei sowie für + den standardmäßig voreingestellten Speicherort für Spielstände. Wir + unterstützen weiterhin die vorherigen Speicherorte. Solange diese vorhanden + sind, werden wir diese weiter verwenden. Bitte beachten Sie die + Liesmich-Datei für weitere Informationen. Speicherorte auf Mac OS X sind + von dieser Änderung nicht betroffen. 3 Skulls of the Toltecs: - Unterstützung für AdLib-Musik verbessert. @@ -39,17 +53,20 @@ Programmcodes finden Sie auf Englisch unter: AGI: - Es ist nun möglich, die Maus-Unterstützung zu deaktivieren (außer bei Amiga-Versionen und Fan-Spielen, die eine Maus benötigen). - - Fehlerhafte Lautstärke-Dämpfung im PCjr-Sound-Code behoben (Fehler #6858). + - Fehlerhafte Lautstärke in PCjr-Spielen korrigiert. - Umfangreiche Änderung im Grafik-Subsystem. - - Unterstützung für Ãœbergänge, Schriftarten und Mauszeigern für Apple IIgs, Amiga + Atari. - (die Atari ST 8x8 Systemschriftart ist nicht in ScummVM enthalten) - - Eine PC-Version kann jetzt wie eine Apple IIgs-Version dargestellt werden. - (inklusive Farbpalette, Cursor, Ãœbergänge und Schriftart). Sie müssen lediglich - den gewünschten Darstellungsmodus auswählen. - - Unterstützung für vereinfachtes automatisches Speichern/Wiederherstellen hinzugefügt. - (verwendet von Mixed Up Mother Goose) - - Feste Verzögerung von 2 Sekunden bei Raumwechseln entfernt und durch Heuristik ersetzt - - Controller (skriptgesteuerte Tastenbelegungen) werden jetzt mit abgespeichert (Fehler #5858). + - Unterstützung für Ãœbergänge, Schriftarten und Mauszeigern für Apple IIgs, + Amiga und Atari (die Systemschriftart Atari ST 8x8 ist nicht in ScummVM + enthalten) + - Eine PC-Version kann jetzt wie eine Apple IIgs-Version dargestellt werden + (inklusive Farbpalette, Cursor, Ãœbergänge und Schriftart). Sie müssen + lediglich den gewünschten Darstellungsmodus auswählen. + - Apple IIgs-Spiele laufen nicht mehr zu schnell. + - Unterstützung für automatisches Speichern / Laden hinzugefügt + (verwendet von Mixed Up Mother Goose). + - Feste Verzögerung von 2 Sekunden bei Raumwechseln entfernt und durch + Heuristik ersetzt. + - Fehlerhafte Tastenbelegungen nach abspeichern/laden behoben AGOS: - Arpeggio-Effekt in der Musik der Amiga-Version von Elvira 1 repariert. @@ -57,19 +74,19 @@ Programmcodes finden Sie auf Englisch unter: - Verb-Feld in der Amiga-Version von Simon the Sorcerer 1 repariert. - Accolade AdLib- und MT32-Treiber für folgende Spiele hinzugefügt: Elvira 1, Elvira 2, Waxworks und Simon the Sorcerer 1 (Demoversion) - - AdLib-Ausgabe in Simon the Sorcerer 1 hinzugefügt. Dies verbessert die AdLib- - Ausgabe erheblich und erhöht die Originaltreue. + - AdLib-Ausgabe in Simon the Sorcerer 1 hinzugefügt. Dies verbessert die + AdLib-Ausgabe erheblich und erhöht die Originaltreue. Baphomets Fluch 1: - - Erkennung der Byte-Reihenfolge der Sprachausgabe auf Big-Endian-Systemen - für die Macintosh-Version (Fehler #6720) repariert. - - Absturz beim Neuladen eines Spiels aus dem Hauptmenü heraus, während sich - das Spiel in der Szene am Bull's Head Hill befindet, behoben - (Fehler #6728). Dieser Fehler trat womöglich auch in anderen Szenen auf. + - Sprachausgabe in Macintosh-Versionen korrigiert, wenn ScumMVM + auf Big-Endian-Systemen ausgeführt wird. + - Fehler beim Laden eines Spielstandes aus dem Hauptmenü in der + Bull's Head Hill-Szene korrigiert. Dieser Fehler trat womöglich auch + in anderen Szenen auf. CinE: - Unterstützung für Musik in der CD-Version von Future Wars hinzugefügt. - + MADE: - Unterstützung für AdLib-Musik in Return to Zork verbessert. @@ -79,18 +96,23 @@ Programmcodes finden Sie auf Englisch unter: SCI: - Behandlung der Musik-Priorität extrem verbessert. - Viele Fehler in den originalen Skripten behoben, die auch bei - Verwendung des originalen Interpreters auftreten: - KQ6 (Sprache und Untertitel), LSL5, QfG1 (EGA), QfG (VGA), QfG2, QfG3, - SQ1, SQ4 (CD) + Verwendung des originalen Interpreters auftreten. + Folgende Spiele sind davon betroffen: + KQ6 (Sprache und Untertitel), LSL5, PQ1, QfG1 (EGA), QfG (VGA), + QfG2, QfG3, SQ1, SQ4 (CD) - Rückkehr aus dem ScummVM-Menü im Spiel sollte nun immer funktionieren. - Verbesserte Unterstützung für japanische PC-9801-Spiele + - Verwende standardmäßig die hochauflösende Version von KQ6 + (kann in den Spieloptionen umgeschaltet werden) SCUMM: - Umfangreiche Verbesserung der Textdarstellung in koreanischen Versionen - - Originaler Code der Gang-Animation in Maniac Mansion v0-v1 hinzugefügt + - Originaler Code der Geh-Animation in Maniac Mansion v0-v1 hinzugefügt. - Es ist nun möglich, Maniac Mansion innerhalb von Day of the Tentacle zu spielen. Bitte Liesmich-Datei für weitere Details lesen. - - Alt-x kann jetzt auf allen Plattformen dazu verwendet werden, SCUMM-Spiele zu beenden. + - Alt+x kann jetzt auf allen Plattformen dazu verwendet werden, SCUMM-Spiele + zu beenden. + - Lippensynchronisation in neueren Spielen von Humongous Entertainment verbessert. Tinsel: - Unterstützung für AdLib-Musik in Discworld 1 verbessert. diff --git a/engines/access/access.cpp b/engines/access/access.cpp index bc9bcb4b08..c12761af4a 100644 --- a/engines/access/access.cpp +++ b/engines/access/access.cpp @@ -436,20 +436,9 @@ void AccessEngine::copyBF1BF2() { } void AccessEngine::copyBF2Vid() { - const byte *srcP = (const byte *)_buffer2.getPixels(); - byte *destP = (byte *)_screen->getBasePtr(_screen->_windowXAdd, - _screen->_windowYAdd + _screen->_screenYOff); - - for (int yp = 0; yp < _screen->_vWindowLinesTall; ++yp) { - Common::copy(srcP, srcP + _screen->_vWindowBytesWide, destP); - srcP += _buffer2.pitch; - destP += _screen->pitch; - } - - // Add dirty rect for affected area - Common::Rect r(_screen->_vWindowBytesWide, _screen->_vWindowLinesTall); - r.moveTo(_screen->_windowXAdd, _screen->_windowYAdd + _screen->_screenYOff); - _screen->addDirtyRect(r); + _screen->blitFrom(_buffer2, + Common::Rect(0, 0, _screen->_vWindowBytesWide, _screen->_vWindowLinesTall), + Common::Point(_screen->_windowXAdd, _screen->_windowYAdd)); } void AccessEngine::playVideo(int videoNum, const Common::Point &pt) { diff --git a/engines/access/asurface.cpp b/engines/access/asurface.cpp index f693e6a3a0..2518ff6ad8 100644 --- a/engines/access/asurface.cpp +++ b/engines/access/asurface.cpp @@ -110,7 +110,7 @@ void ImageEntryList::addToList(ImageEntry &ie) { int ASurface::_clipWidth; int ASurface::_clipHeight; -ASurface::ASurface(): Graphics::Surface() { +ASurface::ASurface(): Graphics::ManagedSurface() { _leftSkip = _rightSkip = 0; _topSkip = _bottomSkip = 0; _lastBoundsX = _lastBoundsY = 0; @@ -122,65 +122,14 @@ ASurface::ASurface(): Graphics::Surface() { } ASurface::~ASurface() { - free(); _savedBlock.free(); } -void ASurface::create(uint16 width, uint16 height) { - Graphics::Surface::create(width, height, Graphics::PixelFormat::createFormatCLUT8()); -} - void ASurface::clearBuffer() { byte *pSrc = (byte *)getPixels(); Common::fill(pSrc, pSrc + w * h, 0); } -bool ASurface::clip(Common::Rect &r) { - int skip; - _leftSkip = _rightSkip = 0; - _topSkip = _bottomSkip = 0; - - if (r.left > _clipWidth || r.left < 0) { - if (r.left >= 0) - return true; - - skip = -r.left; - r.setWidth(r.width() - skip); - _leftSkip = skip; - r.moveTo(0, r.top); - } - - int right = r.right - 1; - if (right < 0) - return true; - else if (right > _clipWidth) { - skip = right - _clipWidth; - r.setWidth(r.width() - skip); - _rightSkip = skip; - } - - if (r.top > _clipHeight || r.top < 0) { - if (r.top >= 0) - return true; - - skip = -r.top; - r.setHeight(r.height() - skip); - _topSkip = skip; - r.moveTo(r.left, 0); - } - - int bottom = r.bottom - 1; - if (bottom < 0) - return true; - else if (bottom > _clipHeight) { - skip = bottom - _clipHeight; - _bottomSkip = skip; - r.setHeight(r.height() - skip); - } - - return false; -} - void ASurface::plotImage(SpriteResource *sprite, int frameNum, const Common::Point &pt) { SpriteFrame *frame = sprite->getFrame(frameNum); Common::Rect r(pt.x, pt.y, pt.x + frame->w, pt.y + frame->h); @@ -195,81 +144,7 @@ void ASurface::plotImage(SpriteResource *sprite, int frameNum, const Common::Poi } } -void ASurface::transBlitFrom(ASurface *src, const Common::Point &destPos) { - if (getPixels() == nullptr) - create(w, h); - - for (int yp = 0; yp < src->h; ++yp) { - const byte *srcP = (const byte *)src->getBasePtr(0, yp); - byte *destP = (byte *)getBasePtr(destPos.x, destPos.y + yp); - - for (int xp = 0; xp < this->w; ++xp, ++srcP, ++destP) { - if (*srcP != TRANSPARENCY) - *destP = *srcP; - } - } -} - -void ASurface::transBlitFrom(ASurface *src, const Common::Rect &bounds) { - const int SCALE_LIMIT = 0x100; - int scaleX = SCALE_LIMIT * bounds.width() / src->w; - int scaleY = SCALE_LIMIT * bounds.height() / src->h; - int scaleXCtr = 0, scaleYCtr = 0; - - for (int yCtr = 0, destY = bounds.top; yCtr < src->h; ++yCtr) { - // Handle skipping lines if Y scaling - scaleYCtr += scaleY; - if (scaleYCtr < SCALE_LIMIT) - continue; - scaleYCtr -= SCALE_LIMIT; - - // Handle off-screen lines - if (destY >= this->h) - break; - - if (destY >= 0) { - // Handle drawing the line - const byte *pSrc = (const byte *)src->getBasePtr(0, yCtr); - byte *pDest = (byte *)getBasePtr(bounds.left, destY); - scaleXCtr = 0; - int x = bounds.left; - - for (int xCtr = 0; xCtr < src->w; ++xCtr, ++pSrc) { - // Handle horizontal scaling - scaleXCtr += scaleX; - if (scaleXCtr < SCALE_LIMIT) - continue; - scaleXCtr -= SCALE_LIMIT; - - // Only handle on-screen pixels - if (x >= this->w) - break; - if (x >= 0 && *pSrc != 0) - *pDest = *pSrc; - - ++pDest; - ++x; - } - } - - ++destY; - } -} - -void ASurface::transBlitFrom(ASurface &src) { - blitFrom(src); -} - -void ASurface::blitFrom(const Graphics::Surface &src) { - assert(w >= src.w && h >= src.h); - for (int y = 0; y < src.h; ++y) { - const byte *srcP = (const byte *)src.getBasePtr(0, y); - byte *destP = (byte *)getBasePtr(0, y); - Common::copy(srcP, srcP + src.w, destP); - } -} - -void ASurface::copyBuffer(Graphics::Surface *src) { +void ASurface::copyBuffer(Graphics::ManagedSurface *src) { blitFrom(*src); } @@ -282,14 +157,11 @@ void ASurface::plotB(SpriteFrame *frame, const Common::Point &pt) { } void ASurface::sPlotF(SpriteFrame *frame, const Common::Rect &bounds) { - transBlitFrom(frame, bounds); + transBlitFrom(*frame, Common::Rect(0, 0, frame->w, frame->h), bounds, TRANSPARENCY, false); } void ASurface::sPlotB(SpriteFrame *frame, const Common::Rect &bounds) { - ASurface flippedFrame; - frame->flipHorizontal(flippedFrame); - - transBlitFrom(&flippedFrame, bounds); + transBlitFrom(*frame, Common::Rect(0, 0, frame->w, frame->h), bounds, TRANSPARENCY, true); } void ASurface::copyBlock(ASurface *src, const Common::Rect &bounds) { @@ -324,22 +196,22 @@ void ASurface::restoreBlock() { } void ASurface::drawRect() { - Graphics::Surface::fillRect(Common::Rect(_orgX1, _orgY1, _orgX2, _orgY2), _lColor); + Graphics::ManagedSurface::fillRect(Common::Rect(_orgX1, _orgY1, _orgX2, _orgY2), _lColor); } void ASurface::drawLine(int x1, int y1, int x2, int y2, int col) { - Graphics::Surface::drawLine(x1, y1, x2, y2, col); + Graphics::ManagedSurface::drawLine(x1, y1, x2, y2, col); } void ASurface::drawLine() { - Graphics::Surface::drawLine(_orgX1, _orgY1, _orgX2, _orgY1, _lColor); + Graphics::ManagedSurface::drawLine(_orgX1, _orgY1, _orgX2, _orgY1, _lColor); } void ASurface::drawBox() { - Graphics::Surface::drawLine(_orgX1, _orgY1, _orgX2, _orgY1, _lColor); - Graphics::Surface::drawLine(_orgX1, _orgY2, _orgX2, _orgY2, _lColor); - Graphics::Surface::drawLine(_orgX2, _orgY1, _orgX2, _orgY1, _lColor); - Graphics::Surface::drawLine(_orgX2, _orgY2, _orgX2, _orgY2, _lColor); + Graphics::ManagedSurface::drawLine(_orgX1, _orgY1, _orgX2, _orgY1, _lColor); + Graphics::ManagedSurface::drawLine(_orgX1, _orgY2, _orgX2, _orgY2, _lColor); + Graphics::ManagedSurface::drawLine(_orgX2, _orgY1, _orgX2, _orgY1, _lColor); + Graphics::ManagedSurface::drawLine(_orgX2, _orgY2, _orgX2, _orgY2, _lColor); } void ASurface::flipHorizontal(ASurface &dest) { @@ -373,4 +245,50 @@ void ASurface::moveBufferDown() { Common::copy_backward(p, p + (pitch * (h - TILE_HEIGHT)), p + (pitch * h)); } +bool ASurface::clip(Common::Rect &r) { + int skip; + _leftSkip = _rightSkip = 0; + _topSkip = _bottomSkip = 0; + + if (r.left > _clipWidth || r.left < 0) { + if (r.left >= 0) + return true; + + skip = -r.left; + r.setWidth(r.width() - skip); + _leftSkip = skip; + r.moveTo(0, r.top); + } + + int right = r.right - 1; + if (right < 0) + return true; + else if (right > _clipWidth) { + skip = right - _clipWidth; + r.setWidth(r.width() - skip); + _rightSkip = skip; + } + + if (r.top > _clipHeight || r.top < 0) { + if (r.top >= 0) + return true; + + skip = -r.top; + r.setHeight(r.height() - skip); + _topSkip = skip; + r.moveTo(r.left, 0); + } + + int bottom = r.bottom - 1; + if (bottom < 0) + return true; + else if (bottom > _clipHeight) { + skip = bottom - _clipHeight; + _bottomSkip = skip; + r.setHeight(r.height() - skip); + } + + return false; +} + } // End of namespace Access diff --git a/engines/access/asurface.h b/engines/access/asurface.h index dd05c8067b..ec18ec09c3 100644 --- a/engines/access/asurface.h +++ b/engines/access/asurface.h @@ -27,7 +27,7 @@ #include "common/array.h" #include "common/memstream.h" #include "common/rect.h" -#include "graphics/surface.h" +#include "graphics/managed_surface.h" #include "access/data.h" namespace Access { @@ -35,7 +35,7 @@ namespace Access { class SpriteResource; class SpriteFrame; -class ASurface : public Graphics::Surface { +class ASurface : virtual public Graphics::ManagedSurface { private: Graphics::Surface _savedBlock; @@ -61,14 +61,8 @@ public: virtual ~ASurface(); - void create(uint16 width, uint16 height); - - bool empty() const { return w == 0 || h == 0 || pixels == nullptr; } - void clearBuffer(); - bool clip(Common::Rect &r); - void plotImage(SpriteResource *sprite, int frameNum, const Common::Point &pt); /** @@ -102,18 +96,8 @@ public: virtual void drawLine(); virtual void drawBox(); - - virtual void transBlitFrom(ASurface *src, const Common::Point &destPos); - - virtual void transBlitFrom(ASurface *src, const Common::Rect &bounds); - virtual void transBlitFrom(ASurface &src); - - virtual void blitFrom(const Graphics::Surface &src); - - virtual void copyBuffer(Graphics::Surface *src); - - virtual void addDirtyRect(const Common::Rect &r) {} + virtual void copyBuffer(Graphics::ManagedSurface *src); void copyTo(ASurface *dest); @@ -126,6 +110,8 @@ public: void moveBufferUp(); void moveBufferDown(); + + bool clip(Common::Rect &r); }; class SpriteFrame : public ASurface { diff --git a/engines/access/detection.cpp b/engines/access/detection.cpp index 7494c9c047..2cd7e50f0f 100644 --- a/engines/access/detection.cpp +++ b/engines/access/detection.cpp @@ -146,7 +146,6 @@ SaveStateList AccessMetaEngine::listSaves(const char *target) const { Access::AccessSavegameHeader header; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -167,6 +166,8 @@ SaveStateList AccessMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/access/detection_tables.h b/engines/access/detection_tables.h index 9556cd9f67..7d9509ca43 100644 --- a/engines/access/detection_tables.h +++ b/engines/access/detection_tables.h @@ -49,7 +49,7 @@ static const AccessGameDescription gameDescriptions[] = { AD_ENTRY1s("c00.ap", "aeb429ff015596144c0df06886c84825", 303753), Common::ES_ESP, Common::kPlatformDOS, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, GType_Amazon, diff --git a/engines/access/events.cpp b/engines/access/events.cpp index d62b05c33f..21ff0d0928 100644 --- a/engines/access/events.cpp +++ b/engines/access/events.cpp @@ -115,7 +115,7 @@ void EventsManager::setCursor(CursorType cursorId) { } } -void EventsManager::setCursorData(Graphics::Surface *src, const Common::Rect &r) { +void EventsManager::setCursorData(Graphics::ManagedSurface *src, const Common::Rect &r) { _invCursor.create(r.width(), r.height(), Graphics::PixelFormat::createFormatCLUT8()); _invCursor.copyRectToSurface(*src, 0, 0, r); } @@ -281,8 +281,7 @@ void EventsManager::nextFrame() { // Give time to the debugger _vm->_debugger->onFrame(); - // TODO: Refactor for dirty rects - _vm->_screen->updateScreen(); + _vm->_screen->update(); } void EventsManager::nextTimer() { diff --git a/engines/access/events.h b/engines/access/events.h index b8c5f0ee5e..5acbb71c9d 100644 --- a/engines/access/events.h +++ b/engines/access/events.h @@ -100,7 +100,7 @@ public: /** * Set the image for the inventory cursor */ - void setCursorData(Graphics::Surface *src, const Common::Rect &r); + void setCursorData(Graphics::ManagedSurface *src, const Common::Rect &r); /** * Return the current cursor Id diff --git a/engines/access/files.cpp b/engines/access/files.cpp index b9c0f7080d..48276ee477 100644 --- a/engines/access/files.cpp +++ b/engines/access/files.cpp @@ -130,13 +130,13 @@ void FileManager::openFile(Resource *res, const Common::String &filename) { error("Could not open file - %s", filename.c_str()); } -void FileManager::loadScreen(Graphics::Surface *dest, int fileNum, int subfile) { +void FileManager::loadScreen(Graphics::ManagedSurface *dest, int fileNum, int subfile) { Resource *res = loadFile(fileNum, subfile); handleScreen(dest, res); delete res; } -void FileManager::handleScreen(Graphics::Surface *dest, Resource *res) { +void FileManager::handleScreen(Graphics::ManagedSurface *dest, Resource *res) { _vm->_screen->loadRawPalette(res->_stream); if (_setPaletteFlag) _vm->_screen->setPalette(); @@ -147,20 +147,17 @@ void FileManager::handleScreen(Graphics::Surface *dest, Resource *res) { res->_size -= res->_stream->pos(); handleFile(res); - if (dest != _vm->_screen) - dest->w = _vm->_screen->w; + Graphics::Surface destSurface = dest->getSubArea(Common::Rect(0, 0, + _vm->_screen->w, _vm->_screen->h)); - if (dest->w == dest->pitch) { - res->_stream->read((byte *)dest->getPixels(), dest->w * dest->h); + if (destSurface.w == destSurface.pitch) { + res->_stream->read((byte *)destSurface.getPixels(), destSurface.w * destSurface.h); } else { - for (int y = 0; y < dest->h; ++y) { - byte *pDest = (byte *)dest->getBasePtr(0, y); - res->_stream->read(pDest, dest->w); + for (int y = 0; y < destSurface.h; ++y) { + byte *pDest = (byte *)destSurface.getBasePtr(0, y); + res->_stream->read(pDest, destSurface.w); } } - - if (dest == _vm->_screen) - _vm->_screen->addDirtyRect(Common::Rect(0, 0, dest->w, dest->h)); } void FileManager::loadScreen(int fileNum, int subfile) { diff --git a/engines/access/files.h b/engines/access/files.h index d081934e91..61fccc2431 100644 --- a/engines/access/files.h +++ b/engines/access/files.h @@ -26,7 +26,7 @@ #include "common/scummsys.h" #include "common/array.h" #include "common/file.h" -#include "graphics/surface.h" +#include "graphics/managed_surface.h" #include "access/decompress.h" namespace Access { @@ -81,7 +81,7 @@ private: /** * Handles loading a screen surface and palette with decoded resource */ - void handleScreen(Graphics::Surface *dest, Resource *res); + void handleScreen(Graphics::ManagedSurface *dest, Resource *res); /** * Open up a sub-file container file @@ -133,7 +133,7 @@ public: /** * Load a screen resource onto a designated surface */ - void loadScreen(Graphics::Surface *dest, int fileNum, int subfile); + void loadScreen(Graphics::ManagedSurface *dest, int fileNum, int subfile); }; } // End of namespace Access diff --git a/engines/access/font.cpp b/engines/access/font.cpp index 8af183f193..6ae65e43f0 100644 --- a/engines/access/font.cpp +++ b/engines/access/font.cpp @@ -151,13 +151,12 @@ void Font::drawString(ASurface *s, const Common::String &msg, const Common::Poin int Font::drawChar(ASurface *s, char c, Common::Point &pt) { Graphics::Surface &ch = _chars[c - ' ']; - - s->addDirtyRect(Common::Rect(pt.x, pt.y, pt.x + ch.w, pt.y + ch.h)); + Graphics::Surface dest = s->getSubArea(Common::Rect(pt.x, pt.y, pt.x + ch.w, pt.y + ch.h)); // Loop through the lines of the character for (int y = 0; y < ch.h; ++y) { byte *pSrc = (byte *)ch.getBasePtr(0, y); - byte *pDest = (byte *)s->getBasePtr(pt.x, pt.y + y); + byte *pDest = (byte *)dest.getBasePtr(0, y); // Loop through the horizontal pixels of the line for (int x = 0; x < ch.w; ++x, ++pSrc, ++pDest) { diff --git a/engines/access/screen.cpp b/engines/access/screen.cpp index aa15abd59a..9700640b71 100644 --- a/engines/access/screen.cpp +++ b/engines/access/screen.cpp @@ -69,8 +69,6 @@ void Screen::clearScreen() { clearBuffer(); if (_vesaMode) _vm->_clearSummaryFlag = true; - - addDirtyRect(Common::Rect(0, 0, this->w, this->h)); } void Screen::setDisplayScan() { @@ -89,28 +87,14 @@ void Screen::setPanel(int num) { _msVirtualOffset = _virtualOffsetsTable[num]; } -void Screen::updateScreen() { +void Screen::update() { if (_vm->_startup >= 0) { if (--_vm->_startup == -1) _fadeIn = true; return; } - - // Merge the dirty rects - mergeDirtyRects(); - - // Loop through copying dirty areas to the physical screen - Common::List<Common::Rect>::iterator i; - for (i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i) { - const Common::Rect &r = *i; - const byte *srcP = (const byte *)getBasePtr(r.left, r.top); - g_system->copyRectToScreen(srcP, this->pitch, r.left, r.top, - r.width(), r.height()); - } - - // Signal the physical screen to update - g_system->updateScreen(); - _dirtyRects.clear(); + markAllDirty();//****DEBUG**** + Graphics::Screen::update(); } void Screen::setInitialPalettte() { @@ -153,7 +137,7 @@ void Screen::loadRawPalette(Common::SeekableReadStream *stream) { void Screen::updatePalette() { g_system->getPaletteManager()->setPalette(&_tempPalette[0], 0, PALETTE_COUNT); - updateScreen(); + update(); } void Screen::savePalette() { @@ -293,22 +277,7 @@ void Screen::drawBox() { ASurface::drawBox(); } -void Screen::transBlitFrom(ASurface *src, const Common::Point &destPos) { - addDirtyRect(Common::Rect(destPos.x, destPos.y, destPos.x + src->w, destPos.y + src->h)); - ASurface::transBlitFrom(src, destPos); -} - -void Screen::transBlitFrom(ASurface *src, const Common::Rect &bounds) { - addDirtyRect(bounds); - ASurface::transBlitFrom(src, bounds); -} - -void Screen::blitFrom(const Graphics::Surface &src) { - addDirtyRect(Common::Rect(0, 0, src.w, src.h)); - ASurface::blitFrom(src); -} - -void Screen::copyBuffer(Graphics::Surface *src) { +void Screen::copyBuffer(Graphics::ManagedSurface *src) { addDirtyRect(Common::Rect(0, 0, src->w, src->h)); ASurface::copyBuffer(src); } @@ -349,51 +318,7 @@ void Screen::cyclePaletteBackwards() { } void Screen::flashPalette(int count) { - warning("TODO: Implement flashPalette"); -} - -void Screen::addDirtyRect(const Common::Rect &r) { - _dirtyRects.push_back(r); - assert(r.isValidRect() && r.width() > 0 && r.height() > 0); -} - -void Screen::mergeDirtyRects() { - Common::List<Common::Rect>::iterator rOuter, rInner; - - // Ensure dirty rect list has at least two entries - rOuter = _dirtyRects.begin(); - for (int i = 0; i < 2; ++i, ++rOuter) { - if (rOuter == _dirtyRects.end()) - return; - } - - // Process the dirty rect list to find any rects to merge - for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) { - rInner = rOuter; - while (++rInner != _dirtyRects.end()) { - - if ((*rOuter).intersects(*rInner)) { - // these two rectangles overlap or - // are next to each other - merge them - - unionRectangle(*rOuter, *rOuter, *rInner); - - // remove the inner rect from the list - _dirtyRects.erase(rInner); - - // move back to beginning of list - rInner = rOuter; - } - } - } + // No implementation needed in ScummVM } -bool Screen::unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2) { - destRect = src1; - destRect.extend(src2); - - return !destRect.isEmpty(); -} - - } // End of namespace Access diff --git a/engines/access/screen.h b/engines/access/screen.h index 6fa0fe3812..a022741f91 100644 --- a/engines/access/screen.h +++ b/engines/access/screen.h @@ -26,15 +26,13 @@ #include "common/scummsys.h" #include "common/rect.h" #include "common/stream.h" +#include "graphics/screen.h" #include "access/asurface.h" namespace Access { class AccessEngine; -#define PALETTE_COUNT 256 -#define PALETTE_SIZE (256 * 3) - struct ScreenSave { int _clipWidth; int _clipHeight; @@ -47,7 +45,7 @@ struct ScreenSave { int _screenYOff; }; -class Screen : public ASurface { +class Screen : public virtual ASurface, public virtual Graphics::Screen { private: AccessEngine *_vm; byte _tempPalette[PALETTE_SIZE]; @@ -66,10 +64,6 @@ private: Common::List<Common::Rect> _dirtyRects; void updatePalette(); - - void mergeDirtyRects(); - - bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2); public: int _vesaMode; int _startColor, _numColors; @@ -87,6 +81,11 @@ public: bool _screenChangeFlag; bool _fadeIn; public: + /** + * Updates the screen + */ + virtual void update(); + virtual void copyBlock(ASurface *src, const Common::Rect &bounds); virtual void restoreBlock(); @@ -95,15 +94,7 @@ public: virtual void drawBox(); - virtual void transBlitFrom(ASurface *src, const Common::Point &destPos); - - virtual void transBlitFrom(ASurface *src, const Common::Rect &bounds); - - virtual void blitFrom(const Graphics::Surface &src); - - virtual void copyBuffer(Graphics::Surface *src); - - virtual void addDirtyRect(const Common::Rect &r); + virtual void copyBuffer(Graphics::ManagedSurface *src); public: Screen(AccessEngine *vm); @@ -114,11 +105,6 @@ public: void setPanel(int num); /** - * Update the underlying screen - */ - void updateScreen(); - - /** * Fade out screen */ void forceFadeOut(); diff --git a/engines/access/scripts.cpp b/engines/access/scripts.cpp index 7c354e78e5..38313640f1 100644 --- a/engines/access/scripts.cpp +++ b/engines/access/scripts.cpp @@ -1005,10 +1005,7 @@ void Scripts::cmdFreeSound() { } while (!_vm->shouldQuit() && sound.isSFXPlaying()); // Free the sounds - while (sound._soundTable.size() > 0) { - delete sound._soundTable[0]._res; - sound._soundTable.remove_at(0); - } + sound.freeSounds(); } } diff --git a/engines/access/video.cpp b/engines/access/video.cpp index 5fc5f6762c..e3ff457c3b 100644 --- a/engines/access/video.cpp +++ b/engines/access/video.cpp @@ -157,7 +157,7 @@ void VideoPlayer::playVideo() { // If the video is playing on the screen surface, add a dirty rect if (_vidSurface == _vm->_screen) - _vm->_screen->addDirtyRect(_videoBounds); + _vm->_screen->markAllDirty(); getFrame(); if (++_videoFrame == _frameCount) { diff --git a/engines/access/video/movie_decoder.cpp b/engines/access/video/movie_decoder.cpp index 05ec25d54c..1406e549ad 100644 --- a/engines/access/video/movie_decoder.cpp +++ b/engines/access/video/movie_decoder.cpp @@ -719,7 +719,7 @@ bool AccessEngine::playMovie(const Common::String &filename, const Common::Point g_system->getPaletteManager()->setPalette(palette, 0, 256); } - _screen->updateScreen(); + _screen->update(); } } diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp index 72629a833e..7a09f662d1 100644 --- a/engines/advancedDetector.cpp +++ b/engines/advancedDetector.cpp @@ -41,8 +41,8 @@ static GameDescriptor toGameDescriptor(const ADGameDescription &g, const PlainGa title = g.extra; extra = ""; } else { - while (sg->gameid) { - if (!scumm_stricmp(g.gameid, sg->gameid)) + while (sg->gameId) { + if (!scumm_stricmp(g.gameId, sg->gameId)) title = sg->description; sg++; } @@ -56,7 +56,7 @@ static GameDescriptor toGameDescriptor(const ADGameDescription &g, const PlainGa else if (g.flags & ADGF_TESTING) gsl = kTestingGame; - GameDescriptor gd(g.gameid, title, g.language, g.platform, 0, gsl); + GameDescriptor gd(g.gameId, title, g.language, g.platform, 0, gsl); gd.updateDesc(extra); return gd; } @@ -89,21 +89,38 @@ static Common::String generatePreferredTarget(const Common::String &id, const AD return res; } +static Common::String sanitizeName(const char *name) { + Common::String res; + + while (*name) { + if (Common::isAlnum(*name)) + res += tolower(*name); + name++; + } + + return res; +} + void AdvancedMetaEngine::updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *realDesc) const { - if (_singleid != NULL) { + if (_singleId != NULL) { desc["preferredtarget"] = desc["gameid"]; - desc["gameid"] = _singleid; + desc["gameid"] = _singleId; } if (!desc.contains("preferredtarget")) desc["preferredtarget"] = desc["gameid"]; + if (realDesc->flags & ADGF_AUTOGENTARGET) { + if (*realDesc->extra) + desc["preferredtarget"] = sanitizeName(realDesc->extra); + } + desc["preferredtarget"] = generatePreferredTarget(desc["preferredtarget"], realDesc); if (_flags & kADFlagUseExtraAsHint) desc["extra"] = realDesc->extra; - desc.setGUIOptions(realDesc->guioptions + _guioptions); + desc.setGUIOptions(realDesc->guiOptions + _guiOptions); desc.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(realDesc->language)); if (realDesc->flags & ADGF_ADDENGLISH) @@ -149,7 +166,7 @@ GameList AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const { // Use fallback detector if there were no matches by other means const ADGameDescription *fallbackDesc = fallbackDetect(allFiles, fslist); if (fallbackDesc != 0) { - GameDescriptor desc(toGameDescriptor(*fallbackDesc, _gameids)); + GameDescriptor desc(toGameDescriptor(*fallbackDesc, _gameIds)); updateGameDescriptor(desc, fallbackDesc); detectedGames.push_back(desc); } @@ -157,7 +174,7 @@ GameList AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const { // Otherwise use the found matches cleanupPirated(matches); for (uint i = 0; i < matches.size(); i++) { - GameDescriptor desc(toGameDescriptor(*matches[i], _gameids)); + GameDescriptor desc(toGameDescriptor(*matches[i], _gameIds)); updateGameDescriptor(desc, matches[i]); detectedGames.push_back(desc); } @@ -252,10 +269,10 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) if (cleanupPirated(matches)) return Common::kNoGameDataFoundError; - if (_singleid == NULL) { + if (_singleId == NULL) { // Find the first match with correct gameid. for (uint i = 0; i < matches.size(); i++) { - if (matches[i]->gameid == gameid) { + if (matches[i]->gameId == gameid) { agdDesc = matches[i]; break; } @@ -270,7 +287,7 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) if (agdDesc != 0) { // Seems we found a fallback match. But first perform a basic // sanity check: the gameid must match. - if (_singleid == NULL && agdDesc->gameid != gameid) + if (_singleId == NULL && agdDesc->gameId != gameid) agdDesc = 0; } } @@ -284,9 +301,9 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) if (agdDesc->flags & ADGF_ADDENGLISH) lang += " " + getGameGUIOptionsDescriptionLanguage(Common::EN_ANY); - Common::updateGameGUIOptions(agdDesc->guioptions + _guioptions, lang); + Common::updateGameGUIOptions(agdDesc->guiOptions + _guiOptions, lang); - GameDescriptor gameDescriptor = toGameDescriptor(*agdDesc, _gameids); + GameDescriptor gameDescriptor = toGameDescriptor(*agdDesc, _gameIds); bool showTestingWarning = false; @@ -407,7 +424,7 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons // Check which files are included in some ADGameDescription *and* are present. // Compute MD5s and file sizes for these files. - for (descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += _descItemSize) { + for (descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != 0; descPtr += _descItemSize) { g = (const ADGameDescription *)descPtr; for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) { @@ -430,7 +447,7 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons // MD5 based matching uint i; - for (i = 0, descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += _descItemSize, ++i) { + for (i = 0, descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != 0; descPtr += _descItemSize, ++i) { g = (const ADGameDescription *)descPtr; bool fileMissing = false; @@ -487,7 +504,7 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons gotAnyMatchesWithAllFiles = true; if (!fileMissing) { - debug(2, "Found game: %s (%s %s/%s) (%d)", g->gameid, g->extra, + debug(2, "Found game: %s (%s %s/%s) (%d)", g->gameId, g->extra, getPlatformDescription(g->platform), getLanguageDescription(g->language), i); if (curFilesMatched > maxFilesMatched) { @@ -503,7 +520,7 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons } } else { - debug(5, "Skipping game: %s (%s %s/%s) (%d)", g->gameid, g->extra, + debug(5, "Skipping game: %s (%s %s/%s) (%d)", g->gameId, g->extra, getPlatformDescription(g->platform), getLanguageDescription(g->language), i); } } @@ -543,7 +560,7 @@ const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap & } if (!fileMissing) { - debug(4, "Matched: %s", agdesc->gameid); + debug(4, "Matched: %s", agdesc->gameId); if (numMatchedFiles > maxNumMatchedFiles) { matchedDesc = agdesc; @@ -568,27 +585,27 @@ const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap & } GameList AdvancedMetaEngine::getSupportedGames() const { - if (_singleid != NULL) { + if (_singleId != NULL) { GameList gl; - const PlainGameDescriptor *g = _gameids; - while (g->gameid) { - if (0 == scumm_stricmp(_singleid, g->gameid)) { - gl.push_back(GameDescriptor(g->gameid, g->description)); + const PlainGameDescriptor *g = _gameIds; + while (g->gameId) { + if (0 == scumm_stricmp(_singleId, g->gameId)) { + gl.push_back(GameDescriptor(g->gameId, g->description)); return gl; } g++; } - error("Engine %s doesn't have its singleid specified in ids list", _singleid); + error("Engine %s doesn't have its singleid specified in ids list", _singleId); } - return GameList(_gameids); + return GameList(_gameIds); } -GameDescriptor AdvancedMetaEngine::findGame(const char *gameid) const { +GameDescriptor AdvancedMetaEngine::findGame(const char *gameId) const { // First search the list of supported gameids for a match. - const PlainGameDescriptor *g = findPlainGameDescriptor(gameid, _gameids); + const PlainGameDescriptor *g = findPlainGameDescriptor(gameId, _gameIds); if (g) return GameDescriptor(*g); @@ -596,14 +613,14 @@ GameDescriptor AdvancedMetaEngine::findGame(const char *gameid) const { return GameDescriptor(); } -AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameids, const ADExtraGuiOptionsMap *extraGuiOptions) - : _gameDescriptors((const byte *)descs), _descItemSize(descItemSize), _gameids(gameids), +AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions) + : _gameDescriptors((const byte *)descs), _descItemSize(descItemSize), _gameIds(gameIds), _extraGuiOptions(extraGuiOptions) { _md5Bytes = 5000; - _singleid = NULL; + _singleId = NULL; _flags = 0; - _guioptions = GUIO_NONE; + _guiOptions = GUIO_NONE; _maxScanDepth = 1; _directoryGlobs = NULL; } diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h index ad551698f6..ab3ec22bdc 100644 --- a/engines/advancedDetector.h +++ b/engines/advancedDetector.h @@ -81,6 +81,7 @@ typedef Common::HashMap<Common::String, ADFileProperties, Common::IgnoreCase_Has enum ADGameFlags { ADGF_NO_FLAGS = 0, + ADGF_AUTOGENTARGET = (1 << 20), // automatically generate gameid from extra ADGF_UNSTABLE = (1 << 21), // flag to designate not yet officially-supported games that are not fit for public testing ADGF_TESTING = (1 << 22), // flag to designate not yet officially-supported games that are fit for public testing ADGF_PIRATED = (1 << 23), ///< flag to designate well known pirated versions with cracks @@ -94,7 +95,7 @@ enum ADGameFlags { }; struct ADGameDescription { - const char *gameid; + const char *gameId; const char *extra; ADGameFileDescription filesDescriptions[14]; Common::Language language; @@ -107,7 +108,7 @@ struct ADGameDescription { */ uint32 flags; - const char *guioptions; + const char *guiOptions; }; /** @@ -191,7 +192,7 @@ protected: * A list of all gameids (and their corresponding descriptions) supported * by this engine. */ - const PlainGameDescriptor *_gameids; + const PlainGameDescriptor *_gameIds; /** * A map containing all the extra game GUI options the engine supports. @@ -219,7 +220,7 @@ protected: * address a more generic problem. We should find a better way to * disambiguate gameids. */ - const char *_singleid; + const char *_singleId; /** * A bitmask of flags which can be used to configure the behavior @@ -233,7 +234,7 @@ protected: * entry in addition to per-game options. Refer to GameGUIOption * enum for the list. */ - Common::String _guioptions; + Common::String _guiOptions; /** * Maximum depth of directories to look up. @@ -251,7 +252,7 @@ protected: const char * const *_directoryGlobs; public: - AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameids, const ADExtraGuiOptionsMap *extraGuiOptions = 0); + AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions = 0); /** * Returns list of targets supported by the engine. @@ -259,7 +260,7 @@ public: */ virtual GameList getSupportedGames() const; - virtual GameDescriptor findGame(const char *gameid) const; + virtual GameDescriptor findGame(const char *gameId) const; virtual GameList detectGames(const Common::FSList &fslist) const; diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp index bcf84840d2..6e63cd3e71 100644 --- a/engines/agi/agi.cpp +++ b/engines/agi/agi.cpp @@ -283,18 +283,7 @@ void AgiBase::initRenderMode() { switch (platform) { case Common::kPlatformDOS: - switch (configRenderMode) { - case Common::kRenderCGA: - _renderMode = Common::kRenderCGA; - break; - // Hercules is not supported atm - //case Common::kRenderHercA: - //case Common::kRenderHercG: - // _renderMode = Common::kRenderHercG; - // break; - default: - break; - } + // Keep EGA break; case Common::kPlatformAmiga: _renderMode = Common::kRenderAmiga; @@ -323,6 +312,12 @@ void AgiBase::initRenderMode() { case Common::kRenderVGA: _renderMode = Common::kRenderVGA; break; + case Common::kRenderHercG: + _renderMode = Common::kRenderHercG; + break; + case Common::kRenderHercA: + _renderMode = Common::kRenderHercA; + break; case Common::kRenderAmiga: _renderMode = Common::kRenderAmiga; break; @@ -401,6 +396,11 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas setupOpcodes(); _game._curLogic = NULL; + _veryFirstInitialCycle = true; + _instructionCounter = 0; + resetGetVarSecondsHeuristic(); + + _setVolumeBrokenFangame = false; // for further study see AgiEngine::setVolumeViaScripts() _lastSaveTime = 0; @@ -461,7 +461,7 @@ void AgiEngine::initialize() { _console = new Console(this); _words = new Words(this); _font = new GfxFont(this); - _gfx = new GfxMgr(this); + _gfx = new GfxMgr(this, _font); _sound = new SoundMgr(this, _mixer); _picture = new PictureMgr(this, _gfx); _sprites = new SpritesMgr(this, _gfx); @@ -470,6 +470,8 @@ void AgiEngine::initialize() { _inventory = new InventoryMgr(this, _gfx, _text, _systemUI); _font->init(); + _gfx->initVideo(); + _text->init(_systemUI); _game.gameFlags = 0; @@ -478,8 +480,6 @@ void AgiEngine::initialize() { _game.name[0] = '\0'; - _gfx->initVideo(); - _lastSaveTime = 0; debugC(2, kDebugLevelMain, "Detect game"); @@ -507,19 +507,6 @@ void AgiEngine::redrawScreen() { _text->promptRedraw(); } -// Adjust a given coordinate to the local game screen -// Used on mouse cursor coordinates before passing them to scripts -void AgiEngine::adjustPosToGameScreen(int16 &x, int16 &y) { - x = x / 2; // 320 -> 160 - y = y - _gfx->getRenderStartOffsetY(); // remove status bar line - if (y < 0) { - y = 0; - } - if (y >= SCRIPT_HEIGHT) { - y = SCRIPT_HEIGHT + 1; // 1 beyond - } -} - AgiEngine::~AgiEngine() { agiDeinit(); delete _loader; @@ -563,17 +550,28 @@ void AgiEngine::syncSoundSettings() { setVolumeViaSystemSetting(); } +// WORKAROUND: +// Sometimes Sierra printed some text on the screen and did a room change immediately afterwards expecting the +// interpreter to load the data for a bit of time. This of course doesn't happen in our AGI, so we try to +// detect such situations via heuristic and then delay the game for a bit. +// In those cases a wait mouse cursor will be shown. +// // Scenes that need this: // +// Gold Rush: +// - During Stagecoach path, after getting solving the steep hill "Congratulations!!!" (NewRoom) +// - when following your mule "Yet right on his tail!!!" (NewRoom/NewPicture - but room 123 stays the same) // Manhunter 1: // - intro text screen (DrawPic) // - MAD "zooming in..." during intro and other scenes, for example room 124 (NewRoom) // The NewRoom call is not done during the same cycle as the "zooming in..." print call. // Space Quest 1: // - right at the start of the game (NewRoom) +// - right at the end of the asteroids "That was mighty close!" (NewRoom) // Space Quest 2 // - right at the start of the game (NewRoom) // - after exiting the very first room, a message pops up, that isn't readable without it (NewRoom) +// - Climbing into shuttle on planet Labion. "You open the hatch and head on in." (NewRoom) // Games, that must not be triggered: @@ -590,7 +588,14 @@ void AgiEngine::nonBlockingText_Forget() { _game.nonBlockingTextShown = false; _game.nonBlockingTextCyclesLeft = 0; } -void AgiEngine::nonBlockingText_CycleDone() { + +void AgiEngine::artificialDelay_Reset() { + nonBlockingText_Forget(); + _artificialDelayCurrentRoom = -1; + _artificialDelayCurrentPicture = -1; +} + +void AgiEngine::artificialDelay_CycleDone() { if (_game.nonBlockingTextCyclesLeft) { _game.nonBlockingTextCyclesLeft--; @@ -601,30 +606,97 @@ void AgiEngine::nonBlockingText_CycleDone() { } } -void AgiEngine::loadingTrigger_NewRoom(int16 newRoomNr) { - if (_game.nonBlockingTextShown) { - _game.nonBlockingTextShown = false; +// WORKAROUND: +// On Apple IIgs, there are situations like for example the Police Quest 1 intro, where music is playing +// and then the scripts switch to a new room, expecting it to load for a bit of time. In ScummVM this results +// in music getting cut off, because our loading is basically done in an instant. This also happens in the +// original interpreter, when you use a faster CPU in emulation. +// +// That's why there is an additional table, where one can add such situations to it. +// These issues are basically impossible to detect, because sometimes music is also supposed to play throughout +// multiple rooms. +// +// Normally all text-based issues should get detected by the current heuristic. Do not add those in here. + +// script, description, signature patch +static const AgiArtificialDelayEntry artificialDelayTable[] = { + { GID_GOLDRUSH, Common::kPlatformApple2GS, ARTIFICIALDELAYTYPE_NEWROOM, 14, 21, 2200 }, // Stagecoach path: right after getting on it in Brooklyn + { GID_PQ1, Common::kPlatformApple2GS, ARTIFICIALDELAYTYPE_NEWPICTURE, 1, 2, 2200 }, // Intro: music track is supposed to finish before credits screen. Developers must have assumed that room loading would take that long. + { GID_MH1, Common::kPlatformApple2GS, ARTIFICIALDELAYTYPE_NEWPICTURE, 155, 183, 2200 }, // Happens, when hitting fingers at bar + { GID_AGIDEMO, Common::kPlatformUnknown, ARTIFICIALDELAYTYPE_END, -1, -1, 0 } +}; - int16 curRoomNr = getVar(VM_VAR_CURRENT_ROOM); +uint16 AgiEngine::artificialDelay_SearchTable(AgiArtificialDelayTriggerType triggerType, int16 orgNr, int16 newNr) { + if (getPlatform() != Common::kPlatformApple2GS) { + return 0; + } + + const AgiArtificialDelayEntry *delayEntry = artificialDelayTable; - if (newRoomNr != curRoomNr) { - if (!_game.automaticRestoreGame) { - // wait a bit, we detected non-blocking text - wait(2000, true); // 2 seconds, set busy + while (delayEntry->triggerType != ARTIFICIALDELAYTYPE_END) { + if (triggerType == delayEntry->triggerType) { + if ((orgNr == delayEntry->orgNr) && (newNr == delayEntry->newNr)) { + if ((getGameID() == delayEntry->gameId) && (getPlatform() == delayEntry->platform)) { + warning("artificial delay forced"); + return delayEntry->millisecondsDelay; + } } } + + delayEntry++; } + return 0; } -void AgiEngine::loadingTrigger_DrawPicture() { - if (_game.nonBlockingTextShown) { - _game.nonBlockingTextShown = false; +void AgiEngine::artificialDelayTrigger_NewRoom(int16 newRoomNr) { + uint16 millisecondsDelay = 0; - if (!_game.automaticRestoreGame) { - // wait a bit, we detected non-blocking text - wait(2000, true); // 2 seconds, set busy + //warning("artificial delay trigger: room %d -> new room %d", _artificialDelayCurrentRoom, newRoomNr); + + if (!_game.automaticRestoreGame) { + millisecondsDelay = artificialDelay_SearchTable(ARTIFICIALDELAYTYPE_NEWROOM, _artificialDelayCurrentRoom, newRoomNr); + + if (_game.nonBlockingTextShown) { + if (newRoomNr != _artificialDelayCurrentRoom) { + if (millisecondsDelay < 2000) { + // wait a bit, we detected non-blocking text + millisecondsDelay = 2000; // 2 seconds + } + } + } + + if (millisecondsDelay) { + wait(millisecondsDelay, true); // set busy mouse cursor + _game.nonBlockingTextShown = false; + } + } + + _artificialDelayCurrentRoom = newRoomNr; +} + +void AgiEngine::artificialDelayTrigger_DrawPicture(int16 newPictureNr) { + uint16 millisecondsDelay = 0; + + //warning("artificial delay trigger: picture %d -> new picture %d", _artificialDelayCurrentPicture, newPictureNr); + + if (!_game.automaticRestoreGame) { + millisecondsDelay = artificialDelay_SearchTable(ARTIFICIALDELAYTYPE_NEWPICTURE, _artificialDelayCurrentPicture, newPictureNr); + + if (_game.nonBlockingTextShown) { + if (newPictureNr != _artificialDelayCurrentPicture) { + if (millisecondsDelay < 2000) { + // wait a bit, we detected non-blocking text + millisecondsDelay = 2000; // 2 seconds, set busy + } + } + } + + if (millisecondsDelay) { + wait(millisecondsDelay, true); // set busy mouse cursor + _game.nonBlockingTextShown = false; } } + _artificialDelayCurrentPicture = newPictureNr; } } // End of namespace Agi diff --git a/engines/agi/agi.h b/engines/agi/agi.h index 93017af099..b288557f57 100644 --- a/engines/agi/agi.h +++ b/engines/agi/agi.h @@ -148,17 +148,17 @@ enum BooterDisks { // position and position.v. // enum AgiGameFeatures { - GF_AGIMOUSE = (1 << 0), + GF_AGIMOUSE = (1 << 0), // this disables "Click-to-walk mouse interface" GF_AGDS = (1 << 1), - GF_AGI256 = (1 << 2), - GF_AGI256_2 = (1 << 3), - GF_AGIPAL = (1 << 4), - GF_MACGOLDRUSH = (1 << 5), - GF_FANMADE = (1 << 6), - GF_MENUS = (1 << 7), - GF_ESCPAUSE = (1 << 8), + GF_AGI256 = (1 << 2), // marks fanmade AGI-256 games + GF_AGI256_2 = (1 << 3), // marks fanmade AGI-256-2 games + GF_AGIPAL = (1 << 4), // marks game using fanmade AGIPAL extension + GF_MACGOLDRUSH = (1 << 5), // use "grdir" instead of "dir" for volume loading + GF_FANMADE = (1 << 6), // marks fanmade games + GF_MENUS = (1 << 7), // not used anymore + GF_ESCPAUSE = (1 << 8), // not used anymore, we detect this internally GF_OLDAMIGAV20 = (1 << 9), - GF_CLIPCOORDS = (1 << 10), + GF_CLIPCOORDS = (1 << 10), // not used atm GF_2GSOLDSOUND = (1 << 11) }; @@ -704,6 +704,21 @@ public: } }; +enum AgiArtificialDelayTriggerType { + ARTIFICIALDELAYTYPE_NEWROOM = 0, + ARTIFICIALDELAYTYPE_NEWPICTURE = 1, + ARTIFICIALDELAYTYPE_END = -1 +}; + +struct AgiArtificialDelayEntry { + uint32 gameId; + Common::Platform platform; + AgiArtificialDelayTriggerType triggerType; + int16 orgNr; + int16 newNr; + uint16 millisecondsDelay; +}; + typedef void (*AgiCommand)(AgiGame *state, AgiEngine *vm, uint8 *p); class AgiEngine : public AgiBase { @@ -724,8 +739,6 @@ public: Common::Error loadGameState(int slot); Common::Error saveGameState(int slot, const Common::String &description); - void adjustPosToGameScreen(int16 &x, int16 &y); - private: int _keyQueue[KEY_QUEUE_SIZE]; int _keyQueueStart; @@ -746,7 +759,7 @@ public: SavedGameSlotIdArray getSavegameSlotIds(); Common::String getSavegameFilename(int16 slotId) const; - bool getSavegameInformation(int16 slotId, Common::String &saveDescription, uint32 &saveDate, uint16 &saveTime, bool &saveIsValid); + bool getSavegameInformation(int16 slotId, Common::String &saveDescription, uint32 &saveDate, uint32 &saveTime, bool &saveIsValid); int saveGame(const Common::String &fileName, const Common::String &descriptionString); int loadGame(const Common::String &fileName, bool checkId = true); @@ -847,6 +860,21 @@ public: int testIfCode(int); void executeAgiCommand(uint8, uint8 *); +private: + bool _veryFirstInitialCycle; /**< signals, that currently the very first cycle is executed (restarts, etc. do not count!) */ + uint32 _instructionCounter; /**< counts every instruction, that got executed, can wrap around */ + + bool _setVolumeBrokenFangame; + + void resetGetVarSecondsHeuristic(); + void getVarSecondsHeuristicTrigger(); + uint32 _getVarSecondsHeuristicLastInstructionCounter; /**< last time VM_VAR_SECONDS were read */ + uint16 _getVarSecondsHeuristicCounter; /**< how many times heuristic was triggered */ + + uint32 _playTimeInSecondsAdjust; /**< milliseconds to adjust for calculating current play time in seconds, see setVarSecondsTrigger() */ + + void setVarSecondsTrigger(byte newSeconds); + public: // Some submethods of testIfCode void skipInstruction(byte op); @@ -899,6 +927,8 @@ private: void checkMotion(ScreenObjEntry *screenObj); public: + void motionActivated(ScreenObjEntry *screenObj); + void cyclerActivated(ScreenObjEntry *screenObj); void checkAllMotions(); void moveObj(ScreenObjEntry *screenObj); void inDestination(ScreenObjEntry *screenObj); @@ -924,10 +954,18 @@ public: void nonBlockingText_IsShown(); void nonBlockingText_Forget(); - void nonBlockingText_CycleDone(); - void loadingTrigger_NewRoom(int16 newRoomNr); - void loadingTrigger_DrawPicture(); + void artificialDelay_Reset(); + void artificialDelay_CycleDone(); + + uint16 artificialDelay_SearchTable(AgiArtificialDelayTriggerType triggerType, int16 orgNr, int16 newNr); + + void artificialDelayTrigger_NewRoom(int16 newRoomNr); + void artificialDelayTrigger_DrawPicture(int16 newPictureNr); + +private: + int16 _artificialDelayCurrentRoom; + int16 _artificialDelayCurrentPicture; public: void redrawScreen(); diff --git a/engines/agi/appleIIgs_timedelay_overwrite.h b/engines/agi/appleIIgs_timedelay_overwrite.h new file mode 100644 index 0000000000..c24d7cb5bd --- /dev/null +++ b/engines/agi/appleIIgs_timedelay_overwrite.h @@ -0,0 +1,91 @@ +/* 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 AGI_APPLEIIGS_DELAY_OVERWRITE_H +#define AGI_APPLEIIGS_DELAY_OVERWRITE_H + +namespace Agi { + +struct AgiAppleIIgsDelayOverwriteRoomEntry { + int16 fromRoom; + int16 toRoom; + int16 timeDelayOverwrite; // time delay here is like on PC, so 0 - unlimited, 1 - 20 cycles, 2 - 10 cycles + bool onlyWhenPlayerNotInControl; +}; + +struct AgiAppleIIgsDelayOverwriteGameEntry { + uint32 gameId; + int16 defaultTimeDelayOverwrite; // time delay here is like on PC, so 0 - unlimited, 1 - 20 cycles, 2 - 10 cycles + const AgiAppleIIgsDelayOverwriteRoomEntry *roomTable; +}; + +static const AgiAppleIIgsDelayOverwriteRoomEntry appleIIgsDelayOverwriteKQ4[] = { + { 120, 121, -1, true }, // Part of the intro: Graham gets his hat, throws it and breaks down, don't touch speed (3 is set) + { 128, 128, -1, true }, // Part of the intro: first actual room for gameplay, but during intro, don't touch speed (3 is set) + { 92, 92, -1, true }, // Part of caught by gargoyle w/ Lolotte cutscene (3 is set) + // room 54 sets the speed for a short time to 3 right after entering "clean" command. It doesn't seem to hurt that we switch it down to 2 + // room 92 is dual use, part of cutscenes, part of gameplay, that's why we only stop touching it, when player is not in control + { 135, 135, -1, true }, // Part of ending cutscene. Don't touch speed (3 is set) + { -1, -1, -1, false } +}; + +static const AgiAppleIIgsDelayOverwriteRoomEntry appleIIgsDelayOverwriteMH1[] = { + //{ 153, 153, 2, false }, // Intro w/ credits + //{ 104, 104, 2, false }, // Intro cutscene + //{ 117, 117, 2, false }, // Intro cutscene (ego waking up) + { 114, 114, -1, false }, // interactive MAD map + { 124, 125, -1, false }, // MAD during intro (tracking), seem to work properly at given speed + { 132, 133, -1, false }, // MAD day 2 intro (tracking) + { 137, 137, -1, false }, // Night Club 4th arcade game - game sets speed to 7 + { 115, 116, -1, false }, // MAD day 3 intro (tracking) + { 148, 148, -1, false }, // day 3: arcade sequence under pawn shop (game sets speed to 6) + { 103, 103, -1, false }, // MAD day 4 intro (tracking) + { 105, 105, -1, false }, // day 4 tracking mini game right at the start (game sets speed to 3) + { 107, 107, -1, false }, // MAD day 4 intro (tracking) + { 112, 112, -1, false }, // MAD day 4 intro (tracking) + { -1, -1, -1, false } +}; + +static const AgiAppleIIgsDelayOverwriteRoomEntry appleIIgsDelayOverwriteSQ2[] = { + { 1, 1, -1, false }, // Intro: space ship entering space port, don't touch speed + { -1, -1, -1, false } +}; + +static const AgiAppleIIgsDelayOverwriteGameEntry appleIIgsDelayOverwriteGameTable[] = { + { GID_BC, 2, nullptr }, // sets the speed at the start and doesn't modify it + { GID_GOLDRUSH, 2, nullptr }, + { GID_KQ1, 2, nullptr }, + // KQ2 seems to work fine at speed given by scripts + { GID_KQ3, 2, nullptr }, + { GID_KQ4, 2, appleIIgsDelayOverwriteKQ4 }, + { GID_LSL1, 2, nullptr }, // Switch Larry 1 to 10 cycles per second (that's around PC Larry 1's "normal" speed + { GID_MH1, 2, appleIIgsDelayOverwriteMH1 }, + { GID_MIXEDUP, 2, nullptr }, + { GID_PQ1, 2, nullptr }, + { GID_SQ1, 2, nullptr }, // completed, no issues using these settings + { GID_SQ2, 2, appleIIgsDelayOverwriteSQ2 }, + { GID_AGIDEMO, -1, nullptr } +}; + +} // End of namespace Agi + +#endif /* AGI_APPLEIIGS_DELAY_OVERWRITE_H */ diff --git a/engines/agi/checks.cpp b/engines/agi/checks.cpp index 1e1670f674..c67b6a5810 100644 --- a/engines/agi/checks.cpp +++ b/engines/agi/checks.cpp @@ -129,7 +129,7 @@ bool AgiEngine::checkPriority(ScreenObjEntry *screenObj) { screenPriority = _gfx->getPriority(curX, curY); if (screenPriority == 0) { // unconditional black. no go at all! - touchedControl = 0; + touchedControl = false; break; } diff --git a/engines/agi/console.cpp b/engines/agi/console.cpp index 6419e60219..9a4a357b44 100644 --- a/engines/agi/console.cpp +++ b/engines/agi/console.cpp @@ -33,27 +33,28 @@ namespace Agi { Console::Console(AgiEngine *vm) : GUI::Debugger() { _vm = vm; - registerCmd("debug", WRAP_METHOD(Console, Cmd_Debug)); - registerCmd("cont", WRAP_METHOD(Console, Cmd_Cont)); - registerCmd("agiver", WRAP_METHOD(Console, Cmd_Agiver)); - registerCmd("version", WRAP_METHOD(Console, Cmd_Version)); - registerCmd("flags", WRAP_METHOD(Console, Cmd_Flags)); - registerCmd("logic0", WRAP_METHOD(Console, Cmd_Logic0)); - registerCmd("objs", WRAP_METHOD(Console, Cmd_Objs)); - registerCmd("runopcode", WRAP_METHOD(Console, Cmd_RunOpcode)); - registerCmd("opcode", WRAP_METHOD(Console, Cmd_Opcode)); - registerCmd("step", WRAP_METHOD(Console, Cmd_Step)); - registerCmd("trigger", WRAP_METHOD(Console, Cmd_Trigger)); - registerCmd("vars", WRAP_METHOD(Console, Cmd_Vars)); - registerCmd("setvar", WRAP_METHOD(Console, Cmd_SetVar)); - registerCmd("setflag", WRAP_METHOD(Console, Cmd_SetFlag)); - registerCmd("setobj", WRAP_METHOD(Console, Cmd_SetObj)); - registerCmd("room", WRAP_METHOD(Console, Cmd_Room)); - registerCmd("bt", WRAP_METHOD(Console, Cmd_BT)); - registerCmd("show_map", WRAP_METHOD(Console, Cmd_ShowMap)); - registerCmd("screenobj", WRAP_METHOD(Console, Cmd_ScreenObj)); - registerCmd("vmvars", WRAP_METHOD(Console, Cmd_VmVars)); - registerCmd("vmflags", WRAP_METHOD(Console, Cmd_VmFlags)); + registerCmd("debug", WRAP_METHOD(Console, Cmd_Debug)); + registerCmd("cont", WRAP_METHOD(Console, Cmd_Cont)); + registerCmd("agiver", WRAP_METHOD(Console, Cmd_Agiver)); + registerCmd("version", WRAP_METHOD(Console, Cmd_Version)); + registerCmd("flags", WRAP_METHOD(Console, Cmd_Flags)); + registerCmd("logic0", WRAP_METHOD(Console, Cmd_Logic0)); + registerCmd("objs", WRAP_METHOD(Console, Cmd_Objs)); + registerCmd("runopcode", WRAP_METHOD(Console, Cmd_RunOpcode)); + registerCmd("opcode", WRAP_METHOD(Console, Cmd_Opcode)); + registerCmd("step", WRAP_METHOD(Console, Cmd_Step)); + registerCmd("trigger", WRAP_METHOD(Console, Cmd_Trigger)); + registerCmd("vars", WRAP_METHOD(Console, Cmd_Vars)); + registerCmd("setvar", WRAP_METHOD(Console, Cmd_SetVar)); + registerCmd("setflag", WRAP_METHOD(Console, Cmd_SetFlag)); + registerCmd("setobj", WRAP_METHOD(Console, Cmd_SetObj)); + registerCmd("room", WRAP_METHOD(Console, Cmd_Room)); + registerCmd("bt", WRAP_METHOD(Console, Cmd_BT)); + registerCmd("show_map", WRAP_METHOD(Console, Cmd_ShowMap)); + registerCmd("screenobj", WRAP_METHOD(Console, Cmd_ScreenObj)); + registerCmd("vmvars", WRAP_METHOD(Console, Cmd_VmVars)); + registerCmd("vmflags", WRAP_METHOD(Console, Cmd_VmFlags)); + registerCmd("disableautosave", WRAP_METHOD(Console, Cmd_DisableAutomaticSave)); } bool Console::Cmd_SetVar(int argc, const char **argv) { @@ -609,6 +610,18 @@ bool Console::Cmd_VmFlags(int argc, const char **argv) { return true; } +bool Console::Cmd_DisableAutomaticSave(int argc, const char **argv) { + if (!_vm->_game.automaticSave) { + debugPrintf("Automatic saving is currently not enabled\n"); + return true; + } + + _vm->_game.automaticSave = false; + + debugPrintf("Automatic saving DISABLED!\n"); + return true; +} + bool Console::parseInteger(const char *argument, int &result) { char *endPtr = 0; int idxLen = strlen(argument); diff --git a/engines/agi/console.h b/engines/agi/console.h index 41dc9ddabc..ccc17b31de 100644 --- a/engines/agi/console.h +++ b/engines/agi/console.h @@ -66,6 +66,7 @@ private: bool Cmd_ScreenObj(int argc, const char **argv); bool Cmd_VmVars(int argc, const char **argv); bool Cmd_VmFlags(int argc, const char **argv); + bool Cmd_DisableAutomaticSave(int argc, const char **argv); bool parseInteger(const char *argument, int &result); diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp index 17c9c873cc..19aca6f2c4 100644 --- a/engines/agi/cycle.cpp +++ b/engines/agi/cycle.cpp @@ -30,6 +30,7 @@ #include "agi/keyboard.h" #include "agi/menu.h" #include "agi/systemui.h" +#include "agi/appleIIgs_timedelay_overwrite.h" namespace Agi { @@ -44,7 +45,7 @@ void AgiEngine::newRoom(int16 newRoomNr) { int i; // Loading trigger - loadingTrigger_NewRoom(newRoomNr); + artificialDelayTrigger_NewRoom(newRoomNr); debugC(4, kDebugLevelMain, "*** room %d ***", newRoomNr); _sound->stopSound(); @@ -141,6 +142,9 @@ void AgiEngine::interpretCycle() { oldScore = getVar(VM_VAR_SCORE); oldSound = getFlag(VM_FLAG_SOUND_ON); + // Reset script heuristic here + resetGetVarSecondsHeuristic(); + _game.exitAllLogics = false; while (runLogic(0) == 0 && !(shouldQuit() || _restartGame)) { setVar(VM_VAR_WORD_NOT_FOUND, 0); @@ -149,10 +153,12 @@ void AgiEngine::interpretCycle() { oldScore = getVar(VM_VAR_SCORE); setFlag(VM_FLAG_ENTERED_CLI, false); _game.exitAllLogics = false; - nonBlockingText_CycleDone(); + _veryFirstInitialCycle = false; + artificialDelay_CycleDone(); resetControllers(); } - nonBlockingText_CycleDone(); + _veryFirstInitialCycle = false; + artificialDelay_CycleDone(); resetControllers(); screenObjEgo->direction = getVar(VM_VAR_EGO_DIRECTION); @@ -219,9 +225,10 @@ uint16 AgiEngine::processAGIEvents() { // no inner loop active at the moment, regular processing if (key) { - setVar(VM_VAR_KEY, key & 0xFF); if (!handleController(key)) { if (key) { + // Only set VAR_KEY, when no controller/direction was detected + setVar(VM_VAR_KEY, key & 0xFF); if (_text->promptIsEnabled()) { _text->promptKeyPress(key); } @@ -288,6 +295,8 @@ uint16 AgiEngine::processAGIEvents() { int AgiEngine::playGame() { int ec = errOK; + const AgiAppleIIgsDelayOverwriteGameEntry *appleIIgsDelayOverwrite = nullptr; + const AgiAppleIIgsDelayOverwriteRoomEntry *appleIIgsDelayRoomOverwrite = nullptr; debugC(2, kDebugLevelMain, "initializing..."); debugC(2, kDebugLevelMain, "game version = 0x%x", getVersion()); @@ -306,7 +315,7 @@ int AgiEngine::playGame() { setFlag(VM_FLAG_LOGIC_ZERO_FIRST_TIME, true); // not in 2.917 setFlag(VM_FLAG_NEW_ROOM_EXEC, true); // needed for MUMG and SQ2! setFlag(VM_FLAG_SOUND_ON, true); // enable sound - setVar(VM_VAR_TIME_DELAY, 2); // "normal" speed + // do not set VM_VAR_TIME_DELAY, original AGI did not do it (in the data segment it was simply set to 0) _game.gfxMode = true; _text->promptRow_Set(22); @@ -335,7 +344,17 @@ int AgiEngine::playGame() { } } - nonBlockingText_Forget(); + artificialDelay_Reset(); + + if (getPlatform() == Common::kPlatformApple2GS) { + // Look up, if there is a time delay overwrite table for the current game + appleIIgsDelayOverwrite = appleIIgsDelayOverwriteGameTable; + while (appleIIgsDelayOverwrite->gameId != GID_AGIDEMO) { + if (appleIIgsDelayOverwrite->gameId == getGameID()) + break; // game found + appleIIgsDelayOverwrite++; + } + } do { processAGIEvents(); @@ -352,6 +371,46 @@ int AgiEngine::playGame() { // Normally that game runs at TIME_DELAY 1. // Maybe a script patch for this game would make sense. // TODO: needs further investigation + + int16 timeDelayOverwrite = -99; + + // Now check, if we got a time delay overwrite entry for current room + if (appleIIgsDelayOverwrite->roomTable) { + byte curRoom = getVar(VM_VAR_CURRENT_ROOM); + + appleIIgsDelayRoomOverwrite = appleIIgsDelayOverwrite->roomTable; + while (appleIIgsDelayRoomOverwrite->fromRoom >= 0) { + if ((appleIIgsDelayRoomOverwrite->fromRoom <= curRoom) && (appleIIgsDelayRoomOverwrite->toRoom >= curRoom)) { + if (appleIIgsDelayRoomOverwrite->onlyWhenPlayerNotInControl) { + if (_game.playerControl) { + // Player is actually currently in control? -> then skip this entry + appleIIgsDelayRoomOverwrite++; + continue; + } + } + timeDelayOverwrite = appleIIgsDelayRoomOverwrite->timeDelayOverwrite; + break; + } + appleIIgsDelayRoomOverwrite++; + } + + if (timeDelayOverwrite == -99) { + // use default time delay in case no room specific one was found + timeDelayOverwrite = appleIIgsDelayOverwrite->defaultTimeDelayOverwrite; + } + } else { + timeDelayOverwrite = appleIIgsDelayOverwrite->defaultTimeDelayOverwrite; + } + + if (timeDelayOverwrite >= 0) { + if (timeDelayOverwrite != timeDelay) { + // delayOverwrite is not the same as the delay taken from the scripts? overwrite it + //warning("AppleIIgs: time delay overwrite from %d to %d", timeDelay, timeDelayOverwrite); + + setVar(VM_VAR_TIME_DELAY, timeDelayOverwrite - 1); // adjust for Apple IIgs + timeDelay = timeDelayOverwrite; + } + } } if (_passedPlayTimeCycles >= timeDelay) { @@ -396,7 +455,7 @@ int AgiEngine::runGame() { if (_restartGame) { setFlag(VM_FLAG_RESTART_GAME, true); - setVar(VM_VAR_TIME_DELAY, 2); // "normal" speed + // do not set VM_VAR_TIME_DELAY, original AGI did not do it // Reset in-game timer inGameTimerReset(); @@ -438,7 +497,13 @@ int AgiEngine::runGame() { break; case Common::kRenderHercA: case Common::kRenderHercG: - setVar(VM_VAR_MONITOR, kAgiMonitorHercules); + // Set EGA for now. Some games place text differently, when this is set to kAgiMonitorHercules. + // Text placement was different for Hercules rendering (16x12 instead of 16x16). There also was + // not enough space left for the prompt at the bottom. This was caused by the Hercules resolution. + // We don't have this restriction and we also support the regular prompt for Hercules mode. + // In theory Sierra could have had special Hercules code inside their games. + // TODO: check this. + setVar(VM_VAR_MONITOR, kAgiMonitorEga); break; // Don't know if Amiga AGI games use a different value than kAgiMonitorEga // for vMonitor so I just use kAgiMonitorEga for them (As was done before too). diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index 6fca86db63..9f66d78d80 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -171,6 +171,26 @@ static const ADExtraGuiOptionsMap optionsList[] = { } }, + { + GAMEOPTION_USE_HERCULES_FONT, + { + _s("Use Hercules hires font"), + _s("Uses Hercules hires font, when font file is available."), + "herculesfont", + false + } + }, + + { + GAMEOPTION_COMMAND_PROMPT_WINDOW, + { + _s("Pause when entering commands"), + _s("Shows a command prompt window and pauses the game (like in SCI) instead of a real-time prompt."), + "commandpromptwindow", + false + } + }, + AD_EXTRA_GUI_OPTIONS_TERMINATOR }; @@ -182,8 +202,8 @@ class AgiMetaEngine : public AdvancedMetaEngine { public: AgiMetaEngine() : AdvancedMetaEngine(Agi::gameDescriptions, sizeof(Agi::AGIGameDescription), agiGames, optionsList) { - _singleid = "agi"; - _guioptions = GUIO1(GUIO_NOSPEECH); + _singleId = "agi"; + _guiOptions = GUIO1(GUIO_NOSPEECH); } virtual const char *getName() const { @@ -261,7 +281,6 @@ SaveStateList AgiMetaEngine::listSaves(const char *target) const { pattern += ".###"; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -299,6 +318,8 @@ SaveStateList AgiMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } @@ -359,6 +380,9 @@ SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int sl uint32 saveDate = in->readUint32BE(); uint16 saveTime = in->readUint16BE(); + if (saveVersion >= 9) { + in->readByte(); // skip over seconds of saveTime (not needed here) + } if (saveVersion >= 6) { uint32 playTime = in->readUint32BE(); descriptor.setPlayTime(playTime * 1000); @@ -543,13 +567,13 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX // Override the gameid & extra values in g_fallbackDesc.desc. This only works // until the fallback detector is called again, and while the MetaEngine instance // is alive (as else the string storage is modified/deleted). - g_fallbackDesc.desc.gameid = _gameid.c_str(); + g_fallbackDesc.desc.gameId = _gameid.c_str(); g_fallbackDesc.desc.extra = _extra.c_str(); Common::String fallbackWarning; fallbackWarning = "Your game version has been detected using fallback matching as a\n"; - fallbackWarning += Common::String::format("variant of %s (%s).\n", g_fallbackDesc.desc.gameid, g_fallbackDesc.desc.extra); + fallbackWarning += Common::String::format("variant of %s (%s).\n", g_fallbackDesc.desc.gameId, g_fallbackDesc.desc.extra); fallbackWarning += "If this is an original and unmodified version or new made Fanmade game,\n"; fallbackWarning += "please report any, information previously printed by ScummVM to the team.\n"; diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h index 8da255d9ee..0938e9d4d6 100644 --- a/engines/agi/detection_tables.h +++ b/engines/agi/detection_tables.h @@ -24,12 +24,14 @@ namespace Agi { #define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1 #define GAMEOPTION_AMIGA_ALTERNATIVE_PALETTE GUIO_GAMEOPTIONS2 -#define GAMEOPTION_DISABLE_MOUSE GUIO_GAMEOPTIONS3 +#define GAMEOPTION_DISABLE_MOUSE GUIO_GAMEOPTIONS3 +#define GAMEOPTION_USE_HERCULES_FONT GUIO_GAMEOPTIONS4 +#define GAMEOPTION_COMMAND_PROMPT_WINDOW GUIO_GAMEOPTIONS5 // TODO: properly implement GAMEOPTIONs -#define GAMEOPTIONS_DEFAULT GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_DISABLE_MOUSE) -#define GAMEOPTIONS_AMIGA GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_AMIGA_ALTERNATIVE_PALETTE) -#define GAMEOPTIONS_FANMADE_MOUSE GUIO1(GAMEOPTION_ORIGINAL_SAVELOAD) +#define GAMEOPTIONS_DEFAULT GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_DISABLE_MOUSE,GAMEOPTION_USE_HERCULES_FONT,GAMEOPTION_COMMAND_PROMPT_WINDOW) +#define GAMEOPTIONS_AMIGA GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_AMIGA_ALTERNATIVE_PALETTE,GAMEOPTION_USE_HERCULES_FONT,GAMEOPTION_COMMAND_PROMPT_WINDOW) +#define GAMEOPTIONS_FANMADE_MOUSE GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_USE_HERCULES_FONT,GAMEOPTION_COMMAND_PROMPT_WINDOW) #define GAME_LVFPN(id,extra,fname,md5,size,lang,ver,features,gid,platform,interp,guioptions) { \ { \ @@ -573,7 +575,14 @@ static const AGIGameDescription gameDescriptions[] = { GAME("sq2", "2.0D 1988-03-14 3.5\"", "85390bde8958c39830e1adbe9fff87f3", 0x2936, GID_SQ2), // Space Quest 2 (IIgs) 2.0A 7/25/88 (CE) - GAME_P("sq2", "2.0A 1988-07-25 (CE)", "5dfdac98dd3c01fcfb166529f917e911", 0x2936, GID_SQ2, Common::kPlatformApple2GS), + // We have to see this as AGI < 2.936, because otherwise a set.pri.base call would somewhat break + // priority in SQ2, when entering Vohaul's vault. + // The Apple IIgs AGI included with SQ2 is the same as the one included with KQ3. + // We currently consider KQ3 IIgs to be a 2.917-equivalent. + // The SQ2 IIgs AGI definitely has 177 kernel functions, but it seems that Sierra shuffled the last few around / added a few extras at the end. + // For KQ3 set.pri.base is called with parameters that seem to be sound resources, which means + // set.pri.base was possibly discard.sound. For KQ4 onwards it seems this was cleaned up. + GAME_P("sq2", "2.0A 1988-07-25 (CE)", "5dfdac98dd3c01fcfb166529f917e911", 0x2917, GID_SQ2, Common::kPlatformApple2GS), { // Space Quest 2 (Amiga) 2.0F @@ -849,6 +858,7 @@ static const AGIGameDescription gameDescriptions[] = { FANMADE("Tex McPhilip 2 - Road To Divinity (v1.5)", "7387e8df854440bc26620ca0ea43af9a"), FANMADE("Tex McPhilip 3 - A Destiny of Sin (Demo v0.25)", "992d12031a486ad84e592ff5d7c9d782"), FANMADE("The 13th Disciple (v1.00)", "887719ad59afce9a41ec057dbb73ad73"), + FANMADE("The 13th Disciple (v1.01)", "58e3ec1b9ac1a79901c472aaa59db832"), FANMADE("The Adventures of a Crazed Hermit", "6e3086cbb794d3299a9c5a9792295511"), FANMADE("The Gourd of the Beans", "246f4d94946afb547482d44a53616d06"), FANMADE("The Grateful Dead", "c2146631afacf8cb455ce24f3d2d46e7"), diff --git a/engines/agi/font.cpp b/engines/agi/font.cpp index 670c1bf575..f9605e4a3d 100644 --- a/engines/agi/font.cpp +++ b/engines/agi/font.cpp @@ -20,6 +20,7 @@ * */ +#include "common/config-manager.h" #include "agi/agi.h" #include "agi/font.h" #include "agi/text.h" @@ -31,6 +32,7 @@ GfxFont::GfxFont(AgiBase *vm) { _fontData = nullptr; _fontDataAllocated = nullptr; + _fontIsHires = false; } GfxFont::~GfxFont() { @@ -619,52 +621,71 @@ static const uint8 fontData_ExtendedRussian[] = { }; void GfxFont::init() { - switch (_vm->_renderMode) { - case Common::kRenderAmiga: - // Try user-file first, if that fails use our internal inaccurate topaz font - loadFontScummVMFile("agi-font-amiga.bin"); - if (!_fontData) { - loadFontAmigaPseudoTopaz(); + if (ConfMan.getBool("herculesfont")) { + // User wants, that we use Hercules hires font, try to load it + loadFontHercules(); + } else { + switch (_vm->_renderMode) { + case Common::kRenderHercA: + case Common::kRenderHercG: + // Render mode is Hercules, we try to load Hercules hires font + loadFontHercules(); + break; + default: + break; } - break; - case Common::kRenderApple2GS: - // Special font, stored in file AGIFONT - loadFontAppleIIgs(); - break; - case Common::kRenderAtariST: - // TODO: Atari ST uses another font - // Seems to be the standard Atari ST 8x8 system font - loadFontScummVMFile("agi-font-atarist.bin"); - if (!_fontData) { - loadFontAtariST("agi-font-atarist-system.fnt"); + } + + if (!_fontData) { + switch (_vm->_renderMode) { + case Common::kRenderAmiga: + // Try user-file first, if that fails use our internal inaccurate topaz font + loadFontScummVMFile("agi-font-amiga.bin"); if (!_fontData) { - // TODO: in case we find a recreation of the font, add it in here + loadFontAmigaPseudoTopaz(); } - } - break; - case Common::kRenderCGA: - case Common::kRenderEGA: - case Common::kRenderVGA: - switch (_vm->getGameID()) { - case GID_MICKEY: - // load mickey mouse font from interpreter file - loadFontMickey(); break; + case Common::kRenderApple2GS: + // Special font, stored in file AGIFONT + loadFontAppleIIgs(); + break; + case Common::kRenderAtariST: + // TODO: Atari ST uses another font + // Seems to be the standard Atari ST 8x8 system font + loadFontScummVMFile("agi-font-atarist.bin"); + if (!_fontData) { + loadFontAtariST("agi-font-atarist-system.fnt"); + if (!_fontData) { + // TODO: in case we find a recreation of the font, add it in here + } + } + break; + case Common::kRenderHercA: + case Common::kRenderHercG: + case Common::kRenderCGA: + case Common::kRenderEGA: + case Common::kRenderVGA: + switch (_vm->getGameID()) { + case GID_MICKEY: + // load mickey mouse font from interpreter file + loadFontMickey(); + break; + default: + loadFontScummVMFile("agi-font-dos.bin"); + break; + } + break; + default: - loadFontScummVMFile("agi-font-dos.bin"); break; } - break; - - default: - break; - } - if (!_fontData) { - // no font assigned? - // use regular PC-BIOS font (taken from Dos-Box with a few modifications) - _fontData = fontData_PCBIOS; - debug("AGI: Using PC-BIOS font"); + if (!_fontData) { + // no font assigned? + // use regular PC-BIOS font (taken from Dos-Box with a few modifications) + _fontData = fontData_PCBIOS; + debug("AGI: Using PC-BIOS font"); + } } if (_vm->getLanguage() == Common::RU_RUS) { @@ -678,6 +699,10 @@ const byte *GfxFont::getFontData() { return _fontData; } +bool GfxFont::isFontHires() { + return _fontIsHires; +} + void GfxFont::overwriteSaveRestoreDialogCharacter() { // overwrite character 0x1A with the standard Sierra arrow to the right character // required for the original save/restore dialogs @@ -686,6 +711,11 @@ void GfxFont::overwriteSaveRestoreDialogCharacter() { // Overwrite extended character set (0x80-0xFF) with Russian characters void GfxFont::overwriteExtendedWithRussianSet() { + if (_fontIsHires) { + // TODO: Implement overwriting hires font characters too + return; + } + if (!_fontDataAllocated) { // nothing allocated, we need to allocate space ourselves to be able to modify an internal font _fontDataAllocated = (uint8 *)calloc(256, 8); @@ -829,6 +859,11 @@ void GfxFont::loadFontAmigaPseudoTopaz() { assert((topazBitOffset & 7) == 0); topazByteOffset = topazBitOffset >> 3; + + // Security check, although we are working on static const data from within ScummVM + uint maxOffset = (topazByteOffset + ((topazHeight - 1) * topazModulo)); + assert(maxOffset < sizeof(fontData_AmigaPseudoTopaz)); + for (uint16 curHeight = 0; curHeight < topazHeight; curHeight++) { *fontData = topazData[topazByteOffset]; fontData++; @@ -1160,4 +1195,102 @@ void GfxFont::loadFontAtariST(Common::String fontFilename) { debug("AGI: Using Atari ST 8x8 system font"); } +// Loads a Sierra Hercules font file +void GfxFont::loadFontHercules() { + Common::File fontFile; + int32 fontFileSize = 0; + byte *fontData = nullptr; + byte *rawData = nullptr; + + uint16 rawDataPos = 0; + uint16 curCharNr = 0; + uint16 curCharLine = 0; + + if (fontFile.open("hgc_font")) { + // hgc_font file found, this is interleaved font data 16x12, should be 3072 bytes + // 24 bytes per character, 128 characters + fontFileSize = fontFile.size(); + if (fontFileSize == (128 * 24)) { + // size seems to be fine + fontData = (uint8 *)calloc(256, 32); + _fontDataAllocated = fontData; + + rawData = (byte *)calloc(128, 24); + fontFile.read(rawData, 128 * 24); + + // convert interleaved 16x12 -> non-interleaved 16x16 + for (curCharNr = 0; curCharNr < 128; curCharNr++) { + fontData += 4; // skip the first 2 lines + for (curCharLine = 0; curCharLine < 6; curCharLine++) { + fontData[0] = rawData[rawDataPos + 2 + 0]; + fontData[1] = rawData[rawDataPos + 2 + 1]; + fontData[2] = rawData[rawDataPos + 0 + 0]; + fontData[3] = rawData[rawDataPos + 0 + 1]; + rawDataPos += 4; + fontData += 4; + } + fontData += 4; // skip the last 2 lines + } + + free(rawData); + } else { + warning("Fontfile 'hgc_font': unexpected file size"); + } + fontFile.close(); + + } + + // It seems hgc_graf.ovl holds a low-res font. It makes no real sense to use it. + // This was only done to AGI3 games and those rendered differently (2 pixel lines -> 3 pixel lines instead of 4) + // User could copy hgc_font from another AGI game over to get the hires font working. +#if 0 + if (!_fontDataAllocated) { + if (fontFile.open("hgc_graf.ovl")) { + // hgc_graf.ovl file found, this is font data + code. non-interleaved font data, should be 3075 bytes + // 16 bytes per character, 128 characters, 2048 bytes of font data, starting offset 21 + fontFileSize = fontFile.size(); + if (fontFileSize == 3075) { + // size seems to be fine + fontData = (uint8 *)calloc(256, 32); + _fontDataAllocated = fontData; + + fontFile.seek(21); + rawData = (byte *)calloc(128, 16); + fontFile.read(rawData, 128 * 16); + + // repeat every line 2 times to get 16x16 pixels + for (curCharNr = 0; curCharNr < 128; curCharNr++) { + for (curCharLine = 0; curCharLine < 8; curCharLine++) { + fontData[0] = rawData[rawDataPos + 0]; + fontData[1] = rawData[rawDataPos + 1]; + fontData[2] = rawData[rawDataPos + 0]; + fontData[3] = rawData[rawDataPos + 1]; + rawDataPos += 2; + fontData += 4; + } + } + + free(rawData); + + } else { + warning("Fontfile 'hgc_graf.ovl': unexpected file size"); + } + fontFile.close(); + } + } +#endif + + if (_fontDataAllocated) { + // font loaded + _fontData = _fontDataAllocated; + _fontIsHires = true; + + debug("AGI: Using Hercules hires font"); + + } else { + // Continue, if no file was not found + warning("Could not open/use file 'hgc_font' for Hercules hires font"); + } +} + } // End of namespace Agi diff --git a/engines/agi/font.h b/engines/agi/font.h index 0bb1bbb18d..485b139858 100644 --- a/engines/agi/font.h +++ b/engines/agi/font.h @@ -36,6 +36,7 @@ private: public: void init(); const byte *getFontData(); + bool isFontHires(); private: void overwriteSaveRestoreDialogCharacter(); @@ -46,9 +47,11 @@ private: void loadFontAmigaPseudoTopaz(); void loadFontAppleIIgs(); void loadFontAtariST(Common::String fontFilename); + void loadFontHercules(); const uint8 *_fontData; // pointer to the currently used font uint8 *_fontDataAllocated; + bool _fontIsHires; }; } // End of namespace Agi diff --git a/engines/agi/global.cpp b/engines/agi/global.cpp index 0f10976988..23256f27fb 100644 --- a/engines/agi/global.cpp +++ b/engines/agi/global.cpp @@ -23,6 +23,7 @@ #include "common/config-manager.h" #include "agi/agi.h" +#include "agi/graphics.h" namespace Agi { @@ -53,14 +54,21 @@ void AgiBase::flipFlag(int16 flagNr) { void AgiEngine::setVar(int16 varNr, byte newValue) { _game.vars[varNr] = newValue; - if (varNr == VM_VAR_VOLUME) { + switch (varNr) { + case VM_VAR_SECONDS: + setVarSecondsTrigger(newValue); + break; + case VM_VAR_VOLUME: setVolumeViaScripts(newValue); + break; } } byte AgiEngine::getVar(int16 varNr) { switch (varNr) { case VM_VAR_SECONDS: + getVarSecondsHeuristicTrigger(); + // is supposed to fall through case VM_VAR_MINUTES: case VM_VAR_HOURS: case VM_VAR_DAYS: @@ -79,7 +87,32 @@ byte AgiEngine::getVar(int16 varNr) { // 15 - mute void AgiEngine::setVolumeViaScripts(byte newVolume) { newVolume = CLIP<byte>(newVolume, 0, 15); - newVolume = 15 - newVolume; // turn volume around + + if (_veryFirstInitialCycle) { + // WORKAROUND: + // The very first cycle is currently running and volume got changed + // This is surely the initial value. For plenty of fan games, a default of 15 is set + // Which actually means "mute" in AGI, but AGI on PC used PC speaker, which did not use + // volume setting. We do. So we detect such a situation and set a flag, so that the + // volume will get interpreted "correctly" for those fan games. + // Note: not all fan games are broken in that regard! + // See bug #7035 + if (getFeatures() & GF_FANMADE) { + // We only check for fan games, Sierra always did it properly of course + if (newVolume == 15) { + // Volume gets set to mute at the start? + // Probably broken fan game detected, set flag + debug("Broken volume in fan game detected, enabling workaround"); + _setVolumeBrokenFangame = true; + } + } + } + + if (!_setVolumeBrokenFangame) { + // In AGI 15 is mute, 0 is loudest + // Some fan games set this incorrectly as 15 for loudest, 0 for mute + newVolume = 15 - newVolume; // turn volume around + } int scummVMVolume = newVolume * Audio::Mixer::kMaxMixerVolume / 15; bool scummVMMute = false; @@ -135,10 +168,42 @@ void AgiEngine::setVolumeViaSystemSetting() { _game.vars[VM_VAR_VOLUME] = internalVolume; } +void AgiEngine::resetGetVarSecondsHeuristic() { + _getVarSecondsHeuristicLastInstructionCounter = 0; + _getVarSecondsHeuristicCounter = 0; +} + +// Called, when the scripts read VM_VAR_SECONDS +void AgiEngine::getVarSecondsHeuristicTrigger() { + uint32 counterDifference = _instructionCounter - _getVarSecondsHeuristicLastInstructionCounter; + + if (counterDifference <= 3) { + // Seconds were read within 3 instructions + _getVarSecondsHeuristicCounter++; + if (_getVarSecondsHeuristicCounter > 20) { + // More than 20 times in a row? This really seems to be an inner loop waiting for seconds to change + // This happens in at least: + // Police Quest 1 - Poker game (room 75, responsible script 81) + + // Wait a few milliseconds, get events and update screen + // We MUST NOT process AGI events in here + wait(10); + processScummVMEvents(); + _gfx->updateScreen(); + + _getVarSecondsHeuristicCounter = 0; + } + } else { + _getVarSecondsHeuristicCounter = 0; + } + _getVarSecondsHeuristicLastInstructionCounter = _instructionCounter; +} + // In-Game timer, used for timer VM Variables void AgiEngine::inGameTimerReset(uint32 newPlayTime) { _lastUsedPlayTimeInCycles = newPlayTime / 50; _lastUsedPlayTimeInSeconds = newPlayTime / 1000; + _playTimeInSecondsAdjust = 0; // no adjust for now setTotalPlayTime(newPlayTime); inGameTimerResetPassedCycles(); } @@ -158,6 +223,24 @@ uint32 AgiEngine::inGameTimerGetPassedCycles() { return _passedPlayTimeCycles; } +// Seconds got set by the game +// This happens in Mixed Up Mother Goose. The game syncs the songs to VM_VAR_SECONDS, but instead +// of only reading them, it sets it to 0 and then checks if it reached a certain second. +// The original interpreter didn't reset the internal cycles counter. Which means the timing was never accurate, +// because the cycles counter may just overflow right after setting the seconds, which means a second +// increase almost immediately happened. We even fix this issue by adjusting for it. +void AgiEngine::setVarSecondsTrigger(byte newSeconds) { + // Adjust in game timer, so that VM timer variables are accurate + inGameTimerUpdate(); + + // Adjust VM seconds again + _game.vars[VM_VAR_SECONDS] = newSeconds; + + // Calculate milliseconds adjust (see comment above) + uint32 curPlayTimeMilliseconds = inGameTimerGet(); + _playTimeInSecondsAdjust = curPlayTimeMilliseconds % 1000; +} + // This is called, when one of the timer variables is read // We calculate the latest variables, according to current official playtime // This is also called in the main loop, because the game needs to be sync'd to 20 cycles per second @@ -178,6 +261,14 @@ void AgiEngine::inGameTimerUpdate() { _lastUsedPlayTimeInCycles = curPlayTimeCycles; // Now calculate current play time in seconds + if (_playTimeInSecondsAdjust) { + // Apply adjust from setVarSecondsTrigger() + if (curPlayTimeMilliseconds >= _playTimeInSecondsAdjust) { + curPlayTimeMilliseconds -= _playTimeInSecondsAdjust; + } else { + curPlayTimeMilliseconds = 0; + } + } uint32 curPlayTimeSeconds = curPlayTimeMilliseconds / 1000; if (curPlayTimeSeconds == _lastUsedPlayTimeInSeconds) { @@ -185,26 +276,50 @@ void AgiEngine::inGameTimerUpdate() { return; } - uint32 secondsLeft = 0; - byte curDays = 0; - byte curHours = 0; - byte curMinutes = 0; - byte curSeconds = 0; - - curDays = curPlayTimeSeconds / 86400; - secondsLeft = curPlayTimeSeconds % 86400; - - curHours = secondsLeft / 3600; - secondsLeft = secondsLeft % 3600; - - curMinutes = secondsLeft / 60; - curSeconds = secondsLeft % 60; - - // directly set them, otherwise we would go into an endless loop - _game.vars[VM_VAR_SECONDS] = curSeconds; - _game.vars[VM_VAR_MINUTES] = curMinutes; - _game.vars[VM_VAR_HOURS] = curHours; - _game.vars[VM_VAR_DAYS] = curDays; + int32 playTimeSecondsDelta = curPlayTimeSeconds - _lastUsedPlayTimeInSeconds; + + if (playTimeSecondsDelta > 0) { + // Read and write to VM vars directly to avoid endless loop + uint32 secondsLeft = playTimeSecondsDelta; + byte curSeconds = _game.vars[VM_VAR_SECONDS]; + byte curMinutes = _game.vars[VM_VAR_MINUTES]; + byte curHours = _game.vars[VM_VAR_HOURS]; + byte curDays = _game.vars[VM_VAR_DAYS]; + + // Add delta to VM variables + if (secondsLeft >= 86400) { + curDays += secondsLeft / 86400; + secondsLeft = secondsLeft % 86400; + } + if (secondsLeft >= 3600) { + curHours += secondsLeft / 3600; + secondsLeft = secondsLeft % 3600; + } + if (secondsLeft >= 60) { + curMinutes += secondsLeft / 60; + secondsLeft = secondsLeft % 60; + } + curSeconds += secondsLeft; + + while (curSeconds > 59) { + curSeconds -= 60; + curMinutes++; + } + while (curMinutes > 59) { + curMinutes -= 60; + curHours++; + } + while (curHours > 23) { + curHours -= 24; + curDays++; + } + + // directly set them + _game.vars[VM_VAR_SECONDS] = curSeconds; + _game.vars[VM_VAR_MINUTES] = curMinutes; + _game.vars[VM_VAR_HOURS] = curHours; + _game.vars[VM_VAR_DAYS] = curDays; + } _lastUsedPlayTimeInSeconds = curPlayTimeSeconds; } diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp index ba5895ccd1..6d3563a451 100644 --- a/engines/agi/graphics.cpp +++ b/engines/agi/graphics.cpp @@ -39,7 +39,7 @@ namespace Agi { #include "agi/font.h" -GfxMgr::GfxMgr(AgiBase *vm) : _vm(vm) { +GfxMgr::GfxMgr(AgiBase *vm, GfxFont *font) : _vm(vm), _font(font) { _agipalFileNum = 0; memset(&_paletteGfxMode, 0, sizeof(_paletteGfxMode)); @@ -50,7 +50,17 @@ GfxMgr::GfxMgr(AgiBase *vm) : _vm(vm) { initPriorityTable(); - _renderStartOffsetY = 0; + _renderStartVisualOffsetY = 0; + _renderStartDisplayOffsetY = 0; + + _upscaledHires = DISPLAY_UPSCALED_DISABLED; + _displayScreenWidth = DISPLAY_DEFAULT_WIDTH; + _displayScreenHeight = DISPLAY_DEFAULT_HEIGHT; + _displayFontWidth = 8; + _displayFontHeight = 8; + + _displayWidthMulAdjust = 0; // visualPos * (2+0) = displayPos + _displayHeightMulAdjust = 0; // visualPos * (1+0) = displayPos } /** @@ -59,6 +69,8 @@ GfxMgr::GfxMgr(AgiBase *vm) : _vm(vm) { * @see deinit_video() */ int GfxMgr::initVideo() { + bool forceHires = false; + // Set up palettes initPalette(_paletteTextMode, PALETTE_EGA); @@ -72,6 +84,14 @@ int GfxMgr::initVideo() { case Common::kRenderVGA: initPalette(_paletteGfxMode, PALETTE_VGA, 256, 8); break; + case Common::kRenderHercG: + initPalette(_paletteGfxMode, PALETTE_HERCULES_GREEN, 2, 8); + forceHires = true; + break; + case Common::kRenderHercA: + initPalette(_paletteGfxMode, PALETTE_HERCULES_AMBER, 2, 8); + forceHires = true; + break; case Common::kRenderAmiga: if (!ConfMan.getBool("altamigapalette")) { // Set the correct Amiga palette depending on AGI interpreter version @@ -87,7 +107,16 @@ int GfxMgr::initVideo() { } break; case Common::kRenderApple2GS: - initPalette(_paletteGfxMode, PALETTE_APPLE_II_GS, 16, 4); + switch (_vm->getGameID()) { + case GID_SQ1: + // Special one, only used for Space Quest 1 on Apple IIgs. Is the same as Amiga v1 palette + initPalette(_paletteGfxMode, PALETTE_APPLE_II_GS_SQ1, 16, 4); + break; + default: + // Regular "standard" Apple IIgs palette, used by everything else + initPalette(_paletteGfxMode, PALETTE_APPLE_II_GS, 16, 4); + break; + } break; case Common::kRenderAtariST: initPalette(_paletteGfxMode, PALETTE_ATARI_ST, 16, 3); @@ -116,31 +145,47 @@ int GfxMgr::initVideo() { break; } + //bool forcedUpscale = true; + + if (_font->isFontHires() || forceHires) { + // Upscaling enable + _upscaledHires = DISPLAY_UPSCALED_640x400; + _displayScreenWidth = 640; + _displayScreenHeight = 400; + _displayFontWidth = 16; + _displayFontHeight = 16; + + _displayWidthMulAdjust = 2; + _displayHeightMulAdjust = 1; + } + // set up mouse cursors switch (_vm->_renderMode) { case Common::kRenderEGA: case Common::kRenderCGA: case Common::kRenderVGA: - initMouseCursor(&_mouseCursor, MOUSECURSOR_SCI, 11, 16, 1, 1); + case Common::kRenderHercG: + case Common::kRenderHercA: + initMouseCursor(&_mouseCursor, MOUSECURSOR_SCI, 11, 16, 0, 0); initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_SCI_BUSY, 15, 16, 7, 8); break; case Common::kRenderAmiga: - initMouseCursor(&_mouseCursor, MOUSECURSOR_AMIGA, 8, 11, 1, 1); + initMouseCursor(&_mouseCursor, MOUSECURSOR_AMIGA, 8, 11, 0, 0); initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_AMIGA_BUSY, 13, 16, 7, 8); break; case Common::kRenderApple2GS: // had no special busy mouse cursor - initMouseCursor(&_mouseCursor, MOUSECURSOR_APPLE_II_GS, 9, 11, 1, 1); + initMouseCursor(&_mouseCursor, MOUSECURSOR_APPLE_II_GS, 9, 11, 0, 0); initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_SCI_BUSY, 15, 16, 7, 8); break; case Common::kRenderAtariST: - initMouseCursor(&_mouseCursor, MOUSECURSOR_ATARI_ST, 11, 16, 1, 1); + initMouseCursor(&_mouseCursor, MOUSECURSOR_ATARI_ST, 11, 16, 0, 0); initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_SCI_BUSY, 15, 16, 7, 8); break; case Common::kRenderMacintosh: // It looks like Atari ST + Macintosh used the same standard mouse cursor // TODO: Verify by checking actual hardware - initMouseCursor(&_mouseCursor, MOUSECURSOR_ATARI_ST, 11, 16, 1, 1); + initMouseCursor(&_mouseCursor, MOUSECURSOR_ATARI_ST, 11, 16, 0, 0); initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_MACINTOSH_BUSY, 10, 14, 7, 8); break; default: @@ -149,15 +194,15 @@ int GfxMgr::initVideo() { } _pixels = SCRIPT_WIDTH * SCRIPT_HEIGHT; - _visualScreen = (byte *)calloc(_pixels, 1); + _gameScreen = (byte *)calloc(_pixels, 1); _priorityScreen = (byte *)calloc(_pixels, 1); - _activeScreen = _visualScreen; + _activeScreen = _gameScreen; //_activeScreen = _priorityScreen; - _displayPixels = DISPLAY_WIDTH * DISPLAY_HEIGHT; + _displayPixels = _displayScreenWidth * _displayScreenHeight; _displayScreen = (byte *)calloc(_displayPixels, 1); - initGraphics(DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_WIDTH > 320); + initGraphics(_displayScreenWidth, _displayScreenHeight, _displayScreenWidth > 320); setPalette(true); // set gfx-mode palette @@ -174,27 +219,151 @@ int GfxMgr::initVideo() { * @see init_video() */ int GfxMgr::deinitVideo() { + // Free mouse cursors in case they were allocated + if (_mouseCursor.bitmapDataAllocated) + free(_mouseCursor.bitmapDataAllocated); + if (_mouseCursorBusy.bitmapDataAllocated) + free(_mouseCursorBusy.bitmapDataAllocated); + free(_displayScreen); - free(_visualScreen); + free(_gameScreen); free(_priorityScreen); return errOK; } void GfxMgr::setRenderStartOffset(uint16 offsetY) { - if (offsetY >= (DISPLAY_HEIGHT - SCRIPT_HEIGHT)) + if (offsetY >= (VISUAL_HEIGHT - SCRIPT_HEIGHT)) error("invalid render start offset"); - _renderStartOffsetY = offsetY; + _renderStartVisualOffsetY = offsetY; + _renderStartDisplayOffsetY = offsetY * (1 + _displayHeightMulAdjust); +} +uint16 GfxMgr::getRenderStartDisplayOffsetY() { + return _renderStartDisplayOffsetY; +} + +// Translates a game screen coordinate to a display screen coordinate +// Game screen to 320x200 -> x * 2, y + renderStart +// Game screen to 640x400 -> x * 4, (y * 2) + renderStart +void GfxMgr::translateGamePosToDisplayScreen(int16 &x, int16 &y) { + x = x * (2 + _displayWidthMulAdjust); + y = y * (1 + _displayHeightMulAdjust) + _renderStartDisplayOffsetY; +} + +// Translates a visual coordinate to a display screen coordinate +// Visual to 320x200 -> x * 2, y +// Visual to 640x400 -> x * 4, y * 2 +void GfxMgr::translateVisualPosToDisplayScreen(int16 &x, int16 &y) { + x = x * (2 + _displayWidthMulAdjust); + y = y * (1 + _displayHeightMulAdjust); +} + +// Translates a display screen coordinate to a game screen coordinate +// Display screen to 320x200 -> x / 2, y - renderStart +// Display screen to 640x400 -> x / 4, (y / 2) - renderStart +void GfxMgr::translateDisplayPosToGameScreen(int16 &x, int16 &y) { + y -= _renderStartDisplayOffsetY; // remove status bar line + x = x / (2 + _displayWidthMulAdjust); + y = y / (1 + _displayHeightMulAdjust); + if (y < 0) + y = 0; + if (y >= SCRIPT_HEIGHT) + y = SCRIPT_HEIGHT + 1; // 1 beyond +} + +// Translates dimension from visual screen to display screen +void GfxMgr::translateVisualDimensionToDisplayScreen(int16 &width, int16 &height) { + width = width * (2 + _displayWidthMulAdjust); + height = height * (1 + _displayHeightMulAdjust); +} + +// Translates dimension from display screen to visual screen +void GfxMgr::translateDisplayDimensionToVisualScreen(int16 &width, int16 &height) { + width = width / (2 + _displayWidthMulAdjust); + height = height / (1 + _displayHeightMulAdjust); +} + +// Translates a rect from game screen to display screen +void GfxMgr::translateGameRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height) { + translateGamePosToDisplayScreen(x, y); + translateVisualDimensionToDisplayScreen(width, height); } -uint16 GfxMgr::getRenderStartOffsetY() { - return _renderStartOffsetY; + +// Translates a rect from visual screen to display screen +void GfxMgr::translateVisualRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height) { + translateVisualPosToDisplayScreen(x, y); + translateVisualDimensionToDisplayScreen(width, height); +} + +uint32 GfxMgr::getDisplayOffsetToGameScreenPos(int16 x, int16 y) { + translateGamePosToDisplayScreen(x, y); + return (y * _displayScreenWidth) + x; +} + +uint32 GfxMgr::getDisplayOffsetToVisualScreenPos(int16 x, int16 y) { + translateVisualPosToDisplayScreen(x, y); + return (y * _displayScreenWidth) + x; +} + +// Attention: uses display screen coordinates! +void GfxMgr::copyDisplayRectToScreen(int16 x, int16 y, int16 width, int16 height) { + g_system->copyRectToScreen(_displayScreen + y * _displayScreenWidth + x, _displayScreenWidth, x, y, width, height); +} +void GfxMgr::copyDisplayRectToScreen(int16 x, int16 adjX, int16 y, int16 adjY, int16 width, int16 adjWidth, int16 height, int16 adjHeight) { + switch (_upscaledHires) { + case DISPLAY_UPSCALED_DISABLED: + break; + case DISPLAY_UPSCALED_640x400: + adjX *= 2; adjY *= 2; + adjWidth *= 2; adjHeight *= 2; + break; + default: + assert(0); + break; + } + x += adjX; y += adjY; + width += adjWidth; height += adjHeight; + g_system->copyRectToScreen(_displayScreen + y * _displayScreenWidth + x, _displayScreenWidth, x, y, width, height); +} +void GfxMgr::copyDisplayRectToScreenUsingGamePos(int16 x, int16 y, int16 width, int16 height) { + translateGameRectToDisplayScreen(x, y, width, height); + g_system->copyRectToScreen(_displayScreen + (y * _displayScreenWidth) + x, _displayScreenWidth, x, y, width, height); +} +void GfxMgr::copyDisplayRectToScreenUsingVisualPos(int16 x, int16 y, int16 width, int16 height) { + translateVisualRectToDisplayScreen(x, y, width, height); + g_system->copyRectToScreen(_displayScreen + (y * _displayScreenWidth) + x, _displayScreenWidth, x, y, width, height); +} +void GfxMgr::copyDisplayToScreen() { + g_system->copyRectToScreen(_displayScreen, _displayScreenWidth, 0, 0, _displayScreenWidth, _displayScreenHeight); +} + +void GfxMgr::translateFontPosToDisplayScreen(int16 &x, int16 &y) { + x *= _displayFontWidth; + y *= _displayFontHeight; +} +void GfxMgr::translateDisplayPosToFontScreen(int16 &x, int16 &y) { + x /= _displayFontWidth; + y /= _displayFontHeight; +} +void GfxMgr::translateFontDimensionToDisplayScreen(int16 &width, int16 &height) { + width *= _displayFontWidth; + height *= _displayFontHeight; +} +void GfxMgr::translateFontRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height) { + translateFontPosToDisplayScreen(x, y); + translateFontDimensionToDisplayScreen(width, height); +} +Common::Rect GfxMgr::getFontRectForDisplayScreen(int16 column, int16 row, int16 width, int16 height) { + Common::Rect displayRect(width * _displayFontWidth, height * _displayFontHeight); + displayRect.moveTo(column * _displayFontWidth, row * _displayFontHeight); + return displayRect; } void GfxMgr::debugShowMap(int mapNr) { switch (mapNr) { case 0: - _activeScreen = _visualScreen; + _activeScreen = _gameScreen; break; case 1: _activeScreen = _priorityScreen; @@ -203,11 +372,11 @@ void GfxMgr::debugShowMap(int mapNr) { break; } - render_Block(0, 167, SCRIPT_WIDTH, SCRIPT_HEIGHT); + render_Block(0, 0, SCRIPT_WIDTH, SCRIPT_HEIGHT); } void GfxMgr::clear(byte color, byte priority) { - memset(_visualScreen, color, _pixels); + memset(_gameScreen, color, _pixels); memset(_priorityScreen, priority, _pixels); } @@ -215,7 +384,7 @@ void GfxMgr::clearDisplay(byte color, bool copyToScreen) { memset(_displayScreen, color, _displayPixels); if (copyToScreen) { - g_system->copyRectToScreen(_displayScreen, DISPLAY_WIDTH, 0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT); + copyDisplayToScreen(); } } @@ -223,7 +392,7 @@ void GfxMgr::putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority int offset = y * SCRIPT_WIDTH + x; if (drawMask & GFX_SCREEN_MASK_VISUAL) { - _visualScreen[offset] = color; + _gameScreen[offset] = color; } if (drawMask & GFX_SCREEN_MASK_PRIORITY) { _priorityScreen[offset] = priority; @@ -231,15 +400,72 @@ void GfxMgr::putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority } void GfxMgr::putPixelOnDisplay(int16 x, int16 y, byte color) { - int offset = y * DISPLAY_WIDTH + x; + uint32 offset = 0; + + switch (_upscaledHires) { + case DISPLAY_UPSCALED_DISABLED: + offset = y * _displayScreenWidth + x; + + _displayScreen[offset] = color; + break; + case DISPLAY_UPSCALED_640x400: + offset = (y * _displayScreenWidth) + x; - _displayScreen[offset] = color; + _displayScreen[offset + 0] = color; + _displayScreen[offset + 1] = color; + _displayScreen[offset + _displayScreenWidth + 0] = color; + _displayScreen[offset + _displayScreenWidth + 1] = color; + break; + default: + break; + } +} + +void GfxMgr::putPixelOnDisplay(int16 x, int16 adjX, int16 y, int16 adjY, byte color) { + switch (_upscaledHires) { + case DISPLAY_UPSCALED_DISABLED: + break; + case DISPLAY_UPSCALED_640x400: + adjX *= 2; adjY *= 2; + break; + default: + assert(0); + break; + } + x += adjX; + y += adjY; + putPixelOnDisplay(x, y, color); +} + +void GfxMgr::putFontPixelOnDisplay(int16 baseX, int16 baseY, int16 addX, int16 addY, byte color, bool isHires) { + uint32 offset = 0; + + switch (_upscaledHires) { + case DISPLAY_UPSCALED_DISABLED: + offset = ((baseY + addY) * _displayScreenWidth) + (baseX + addX); + _displayScreen[offset] = color; + break; + case DISPLAY_UPSCALED_640x400: + if (isHires) { + offset = ((baseY + addY) * _displayScreenWidth) + (baseX + addX); + _displayScreen[offset] = color; + } else { + offset = ((baseY + addY * 2) * _displayScreenWidth) + (baseX + addX * 2); + _displayScreen[offset + 0] = color; + _displayScreen[offset + 1] = color; + _displayScreen[offset + _displayScreenWidth + 0] = color; + _displayScreen[offset + _displayScreenWidth + 1] = color; + } + break; + default: + break; + } } byte GfxMgr::getColor(int16 x, int16 y) { int offset = y * SCRIPT_WIDTH + x; - return _visualScreen[offset]; + return _gameScreen[offset]; } byte GfxMgr::getPriority(int16 x, int16 y) { @@ -279,12 +505,17 @@ byte GfxMgr::getCGAMixtureColor(byte color) { return CGA_MixtureColorTable[color & 0x0F]; } -// Attention: y-coordinate points to the LOWER left! +// Attention: in our implementation, y-coordinate is upper left. +// Sierra passed the lower left instead. We changed it to make upscaling easier. void GfxMgr::render_Block(int16 x, int16 y, int16 width, int16 height, bool copyToScreen) { if (!render_Clip(x, y, width, height)) return; switch (_vm->_renderMode) { + case Common::kRenderHercG: + case Common::kRenderHercA: + render_BlockHercules(x, y, width, height, copyToScreen); + break; case Common::kRenderCGA: render_BlockCGA(x, y, width, height, copyToScreen); break; @@ -295,17 +526,26 @@ void GfxMgr::render_Block(int16 x, int16 y, int16 width, int16 height, bool copy } if (copyToScreen) { - int16 upperY = y - height + 1 + _renderStartOffsetY; - g_system->copyRectToScreen(_displayScreen + upperY * DISPLAY_WIDTH + x * 2, DISPLAY_WIDTH, x * 2, upperY, width * 2, height); + copyDisplayRectToScreenUsingGamePos(x, y, width, height); } } bool GfxMgr::render_Clip(int16 &x, int16 &y, int16 &width, int16 &height, int16 clipAgainstWidth, int16 clipAgainstHeight) { if ((x >= clipAgainstWidth) || ((x + width - 1) < 0) || - (y < 0) || ((y - (height - 1)) >= clipAgainstHeight)) { + (y < 0) || ((y + (height - 1)) >= clipAgainstHeight)) { return false; } + if (y < 0) { + height += y; + y = 0; + } + + if ((y + height - 1) >= clipAgainstHeight) { + height = clipAgainstHeight - y; + } + +#if 0 if ((y - height + 1) < 0) height = y + 1; @@ -313,6 +553,7 @@ bool GfxMgr::render_Clip(int16 &x, int16 &y, int16 &width, int16 &height, int16 height -= y - (clipAgainstHeight - 1); y = clipAgainstHeight - 1; } +#endif if (x < 0) { width += x; @@ -326,52 +567,212 @@ bool GfxMgr::render_Clip(int16 &x, int16 &y, int16 &width, int16 &height, int16 } void GfxMgr::render_BlockEGA(int16 x, int16 y, int16 width, int16 height, bool copyToScreen) { - int offsetVisual = SCRIPT_WIDTH * y + x; - int offsetDisplay = (DISPLAY_WIDTH * (y + _renderStartOffsetY)) + x * 2; + uint32 offsetVisual = SCRIPT_WIDTH * y + x; + uint32 offsetDisplay = getDisplayOffsetToGameScreenPos(x, y); int16 remainingWidth = width; int16 remainingHeight = height; byte curColor = 0; + int16 displayWidth = width * (2 + _displayWidthMulAdjust); while (remainingHeight) { remainingWidth = width; - while (remainingWidth) { - curColor = _activeScreen[offsetVisual++]; - _displayScreen[offsetDisplay++] = curColor; - _displayScreen[offsetDisplay++] = curColor; - remainingWidth--; + + switch (_upscaledHires) { + case DISPLAY_UPSCALED_DISABLED: + while (remainingWidth) { + curColor = _activeScreen[offsetVisual++]; + _displayScreen[offsetDisplay++] = curColor; + _displayScreen[offsetDisplay++] = curColor; + remainingWidth--; + } + break; + case DISPLAY_UPSCALED_640x400: + while (remainingWidth) { + curColor = _activeScreen[offsetVisual++]; + memset(&_displayScreen[offsetDisplay], curColor, 4); + memset(&_displayScreen[offsetDisplay + _displayScreenWidth], curColor, 4); + offsetDisplay += 4; + remainingWidth--; + } + break; + default: + assert(0); + break; + } + + offsetVisual += SCRIPT_WIDTH - width; + offsetDisplay += _displayScreenWidth - displayWidth; + + switch (_upscaledHires) { + case DISPLAY_UPSCALED_640x400: + offsetDisplay += _displayScreenWidth;; + break; + default: + break; } - offsetVisual -= SCRIPT_WIDTH + width; - offsetDisplay -= DISPLAY_WIDTH + width * 2; remainingHeight--; } } void GfxMgr::render_BlockCGA(int16 x, int16 y, int16 width, int16 height, bool copyToScreen) { - int offsetVisual = SCRIPT_WIDTH * y + x; - int offsetDisplay = (DISPLAY_WIDTH * (y + _renderStartOffsetY)) + x * 2; + uint32 offsetVisual = SCRIPT_WIDTH * y + x; + uint32 offsetDisplay = getDisplayOffsetToGameScreenPos(x, y); + int16 remainingWidth = width; + int16 remainingHeight = height; + byte curColor = 0; + int16 displayWidth = width * (2 + _displayWidthMulAdjust); + + while (remainingHeight) { + remainingWidth = width; + + switch (_upscaledHires) { + case DISPLAY_UPSCALED_DISABLED: + while (remainingWidth) { + curColor = _activeScreen[offsetVisual++]; + _displayScreen[offsetDisplay++] = curColor & 0x03; // we process CGA mixture + _displayScreen[offsetDisplay++] = curColor >> 2; + remainingWidth--; + } + break; + case DISPLAY_UPSCALED_640x400: + while (remainingWidth) { + curColor = _activeScreen[offsetVisual++]; + _displayScreen[offsetDisplay + 0] = curColor & 0x03; // we process CGA mixture + _displayScreen[offsetDisplay + 1] = curColor >> 2; + _displayScreen[offsetDisplay + 2] = curColor & 0x03; + _displayScreen[offsetDisplay + 3] = curColor >> 2; + _displayScreen[offsetDisplay + _displayScreenWidth + 0] = curColor & 0x03; + _displayScreen[offsetDisplay + _displayScreenWidth + 1] = curColor >> 2; + _displayScreen[offsetDisplay + _displayScreenWidth + 2] = curColor & 0x03; + _displayScreen[offsetDisplay + _displayScreenWidth + 3] = curColor >> 2; + offsetDisplay += 4; + remainingWidth--; + } + break; + default: + assert(0); + break; + } + + offsetVisual += SCRIPT_WIDTH - width; + offsetDisplay += _displayScreenWidth - displayWidth; + + switch (_upscaledHires) { + case DISPLAY_UPSCALED_640x400: + offsetDisplay += _displayScreenWidth;; + break; + default: + break; + } + + remainingHeight--; + } +} + +static const uint8 herculesColorMapping[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x88, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x80, 0x10, 0x02, 0x20, 0x01, 0x08, 0x40, 0x04, + 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, + 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, + 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, + 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88, + 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, + 0x22, 0x00, 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, + 0xD7, 0xFF, 0x7D, 0xFF, 0xD7, 0xFF, 0x7D, 0xFF, + 0xDD, 0x55, 0x77, 0xAA, 0xDD, 0x55, 0x77, 0xAA, + 0x7F, 0xEF, 0xFD, 0xDF, 0xFE, 0xF7, 0xBF, 0xFB, + 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, + 0x77, 0xBB, 0xDD, 0xEE, 0x77, 0xBB, 0xDD, 0xEE, + 0x77, 0xFF, 0xFF, 0xFF, 0xDD, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +// Sierra actually seems to have rendered the whole screen all the time +void GfxMgr::render_BlockHercules(int16 x, int16 y, int16 width, int16 height, bool copyToScreen) { + uint32 offsetVisual = SCRIPT_WIDTH * y + x; + uint32 offsetDisplay = getDisplayOffsetToGameScreenPos(x, y); int16 remainingWidth = width; int16 remainingHeight = height; byte curColor = 0; + int16 displayWidth = width * (2 + _displayWidthMulAdjust); + + assert(_upscaledHires == DISPLAY_UPSCALED_640x400); + + uint16 lookupOffset1 = (y * 2 & 0x07); + uint16 lookupOffset2 = 0; + bool getUpperNibble = false; + byte herculesColors1 = 0; + byte herculesColors2 = 0; while (remainingHeight) { remainingWidth = width; + + lookupOffset1 = (lookupOffset1 + 0) & 0x07; + lookupOffset2 = (lookupOffset1 + 1) & 0x07; + + getUpperNibble = (x & 1) ? false : true; while (remainingWidth) { - curColor = _activeScreen[offsetVisual++]; - _displayScreen[offsetDisplay++] = curColor & 0x03; // we process CGA mixture - _displayScreen[offsetDisplay++] = curColor >> 2; + curColor = _activeScreen[offsetVisual++] & 0x0F; + + if (getUpperNibble) { + herculesColors1 = herculesColorMapping[curColor * 8 + lookupOffset1] & 0x0F; + herculesColors2 = herculesColorMapping[curColor * 8 + lookupOffset2] & 0x0F; + } else { + herculesColors1 = herculesColorMapping[curColor * 8 + lookupOffset1] >> 4; + herculesColors2 = herculesColorMapping[curColor * 8 + lookupOffset2] >> 4; + } + getUpperNibble ^= true; + + _displayScreen[offsetDisplay + 0] = (herculesColors1 & 0x08) ? 1 : 0; + _displayScreen[offsetDisplay + 1] = (herculesColors1 & 0x04) ? 1 : 0; + _displayScreen[offsetDisplay + 2] = (herculesColors1 & 0x02) ? 1 : 0; + _displayScreen[offsetDisplay + 3] = (herculesColors1 & 0x01) ? 1 : 0; + + _displayScreen[offsetDisplay + _displayScreenWidth + 0] = (herculesColors2 & 0x08) ? 1 : 0; + _displayScreen[offsetDisplay + _displayScreenWidth + 1] = (herculesColors2 & 0x04) ? 1 : 0; + _displayScreen[offsetDisplay + _displayScreenWidth + 2] = (herculesColors2 & 0x02) ? 1 : 0; + _displayScreen[offsetDisplay + _displayScreenWidth + 3] = (herculesColors2 & 0x01) ? 1 : 0; + + offsetDisplay += 4; remainingWidth--; } - offsetVisual -= SCRIPT_WIDTH + width; - offsetDisplay -= DISPLAY_WIDTH + width * 2; + + lookupOffset1 += 2; + + offsetVisual += SCRIPT_WIDTH - width; + offsetDisplay += _displayScreenWidth - displayWidth; + offsetDisplay += _displayScreenWidth;; remainingHeight--; } } +// Table used for at least Manhunter 2, it renders 2 lines -> 3 lines instead of 4 +// Manhunter 1 is shipped with a broken Hercules font +// King's Quest 4 aborts right at the start, when Hercules rendering is active +#if 0 +static const uint8 herculesCoordinateOffset[] = { + 0x00, 0x01, 0x03, 0x04, 0x06, 0x07, 0x01, 0x02, + 0x04, 0x05, 0x07, 0x00, 0x02, 0x03, 0x05, 0x06 +}; + +static const uint8 herculesColorMapping[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x02, 0x00, 0x40, 0x00, 0x08, 0x00, + 0x80, 0x10, 0x02, 0x20, 0x01, 0x08, 0x40, 0x04, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, + 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, + 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, + 0x22, 0x00, 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0xD7, 0xFF, 0x7D, 0xFF, 0xD7, 0xFF, 0x7D, 0xFF, + 0xDD, 0x55, 0x77, 0xAA, 0xDD, 0x55, 0x77, 0xAA, 0x7F, 0xEF, 0xFD, 0xDF, 0xFE, 0xF7, 0xBF, 0xFB, + 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0x77, 0xBB, 0xDD, 0xEE, 0x77, 0xBB, 0xDD, 0xEE, + 0x7F, 0xEF, 0xFB, 0xBF, 0xEF, 0xFE, 0xBF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; +#endif + void GfxMgr::transition_Amiga() { uint16 screenPos = 1; - uint16 screenStepPos = 1; + uint32 screenStepPos = 1; int16 posY = 0, posX = 0; int16 stepCount = 0; @@ -393,15 +794,29 @@ void GfxMgr::transition_Amiga() { posY = screenStepPos / SCRIPT_WIDTH; posX = screenStepPos - (posY * SCRIPT_WIDTH); - posY += _renderStartOffsetY; // adjust to only update the main area, not the status bar - posX *= 2; // adjust for display screen - - screenStepPos = (screenStepPos * 2) + (_renderStartOffsetY * DISPLAY_WIDTH); // adjust here too for display screen - for (int16 multiPixel = 0; multiPixel < 4; multiPixel++) { - g_system->copyRectToScreen(_displayScreen + screenStepPos, DISPLAY_WIDTH, posX, posY, 2, 1); - screenStepPos += (0x1A40 * 2); // 6720d - posY += 42; + // Adjust to only update the game screen, not the status bar + translateGamePosToDisplayScreen(posX, posY); + + switch (_upscaledHires) { + case DISPLAY_UPSCALED_DISABLED: + for (int16 multiPixel = 0; multiPixel < 4; multiPixel++) { + screenStepPos = (posY * _displayScreenWidth) + posX; + g_system->copyRectToScreen(_displayScreen + screenStepPos, _displayScreenWidth, posX, posY, 2, 1); + posY += 42; + } + break; + case DISPLAY_UPSCALED_640x400: + for (int16 multiPixel = 0; multiPixel < 4; multiPixel++) { + screenStepPos = (posY * _displayScreenWidth) + posX; + g_system->copyRectToScreen(_displayScreen + screenStepPos, _displayScreenWidth, posX, posY, 4, 2); + posY += 42 * 2; + } + break; + default: + assert(0); + break; } + stepCount++; if (stepCount == 220) { // 30 times for the whole transition, so should take around 0.5 seconds @@ -424,7 +839,7 @@ void GfxMgr::transition_Amiga() { // Atari ST definitely had a hi-res transition using the full resolution unlike the Amiga transition. void GfxMgr::transition_AtariSt() { uint16 screenPos = 1; - uint16 screenStepPos = 1; + uint32 screenStepPos = 1; int16 posY = 0, posX = 0; int16 stepCount = 0; @@ -443,17 +858,31 @@ void GfxMgr::transition_AtariSt() { if ((screenPos < 13440) && (screenPos & 1)) { screenStepPos = screenPos >> 1; - posY = screenStepPos / DISPLAY_WIDTH; - posX = screenStepPos - (posY * DISPLAY_WIDTH); - - posY += _renderStartOffsetY; // adjust to only update the main area, not the status bar - - screenStepPos = screenStepPos + (_renderStartOffsetY * DISPLAY_WIDTH); // adjust here too for display screen - for (int16 multiPixel = 0; multiPixel < 8; multiPixel++) { - g_system->copyRectToScreen(_displayScreen + screenStepPos, DISPLAY_WIDTH, posX, posY, 1, 1); - screenStepPos += 0x1a40; // 6720d - posY += 21; + posY = screenStepPos / DISPLAY_DEFAULT_WIDTH; + posX = screenStepPos - (posY * DISPLAY_DEFAULT_WIDTH); + + switch (_upscaledHires) { + case DISPLAY_UPSCALED_DISABLED: + posY += _renderStartDisplayOffsetY; // adjust to only update the main area, not the status bar + for (int16 multiPixel = 0; multiPixel < 8; multiPixel++) { + screenStepPos = (posY * _displayScreenWidth) + posX; + g_system->copyRectToScreen(_displayScreen + screenStepPos, _displayScreenWidth, posX, posY, 1, 1); + posY += 21; + } + break; + case DISPLAY_UPSCALED_640x400: + posX *= 2; posY *= 2; + posY += _renderStartDisplayOffsetY; // adjust to only update the main area, not the status bar + for (int16 multiPixel = 0; multiPixel < 8; multiPixel++) { + screenStepPos = (posY * _displayScreenWidth) + posX; + g_system->copyRectToScreen(_displayScreen + screenStepPos, _displayScreenWidth, posX, posY, 2, 2); + posY += 21 * 2; + } + break; + default: + break; } + stepCount++; if (stepCount == 168) { // 40 times for the whole transition, so should take around 0.7 seconds @@ -484,7 +913,7 @@ void GfxMgr::block_save(int16 x, int16 y, int16 width, int16 height, byte *buffe //warning("block_save: %d, %d -> %d, %d", x, y, width, height); while (remainingHeight) { - memcpy(curBufferPtr, _visualScreen + offset, width); + memcpy(curBufferPtr, _gameScreen + offset, width); offset += SCRIPT_WIDTH; curBufferPtr += width; remainingHeight--; @@ -510,7 +939,7 @@ void GfxMgr::block_restore(int16 x, int16 y, int16 width, int16 height, byte *bu //warning("block_restore: %d, %d -> %d, %d", x, y, width, height); while (remainingHeight) { - memcpy(_visualScreen + offset, curBufferPtr, width); + memcpy(_gameScreen + offset, curBufferPtr, width); offset += SCRIPT_WIDTH; curBufferPtr += width; remainingHeight--; @@ -526,12 +955,8 @@ void GfxMgr::block_restore(int16 x, int16 y, int16 width, int16 height, byte *bu } } -// Attention: uses visual screen coordinates! -void GfxMgr::copyDisplayRectToScreen(int16 x, int16 y, int16 width, int16 height) { - g_system->copyRectToScreen(_displayScreen + y * DISPLAY_WIDTH + x, DISPLAY_WIDTH, x, y, width, height); -} - // coordinates are for visual screen, but are supposed to point somewhere inside the playscreen +// x, y is the upper left. Sierra passed them as lower left. We change that to make upscaling easier. // attention: Clipping is done here against 160x200 instead of 160x168 // Original interpreter didn't do any clipping, we do it for security. // Clipping against the regular script width/height must not be done, @@ -539,13 +964,13 @@ void GfxMgr::copyDisplayRectToScreen(int16 x, int16 y, int16 width, int16 height // Going beyond 160x168 will result in messageboxes not getting fully removed // In KQ4's case, the scripts clear the screen that's why it works. void GfxMgr::drawBox(int16 x, int16 y, int16 width, int16 height, byte backgroundColor, byte lineColor) { - if (!render_Clip(x, y, width, height, SCRIPT_WIDTH, DISPLAY_HEIGHT - _renderStartOffsetY)) + if (!render_Clip(x, y, width, height, VISUAL_WIDTH, VISUAL_HEIGHT - _renderStartVisualOffsetY)) return; // coordinate translation: visual-screen -> display-screen - x = x * 2; - y = y + _renderStartOffsetY; // drawDisplayRect paints anywhere on the whole screen, our coordinate is within playscreen - width = width * 2; // width was given as visual width, we need display width + translateVisualRectToDisplayScreen(x, y, width, height); + + y = y + _renderStartDisplayOffsetY; // drawDisplayRect paints anywhere on the whole screen, our coordinate is within playscreen // draw box background drawDisplayRect(x, y, width, height, backgroundColor); @@ -555,75 +980,87 @@ void GfxMgr::drawBox(int16 x, int16 y, int16 width, int16 height, byte backgroun case Common::kRenderApple2GS: case Common::kRenderAmiga: // Slightly different window frame, and actually using 1-pixel width, which is "hi-res" - drawDisplayRect(x + 2, y - 2, width - 4, 1, lineColor); - drawDisplayRect(x + width - 3, y - 2, 1, height - 4, lineColor); - drawDisplayRect(x + 2, y - height + 3, width - 4, 1, lineColor); - drawDisplayRect(x + 2, y - 2, 1, height - 4, lineColor); + drawDisplayRect(x, +2, y, +2, width, -4, 0, 1, lineColor); + drawDisplayRect(x + width, -3, y, +2, 0, 1, height, -4, lineColor); + drawDisplayRect(x, +2, y + height, -3, width, -4, 0, 1, lineColor); + drawDisplayRect(x, +2, y, +2, 0, 1, height, -4, lineColor); break; case Common::kRenderMacintosh: // 1 pixel between box and frame lines. Frame lines were black - drawDisplayRect(x + 1, y - 1, width - 2, 1, 0); - drawDisplayRect(x + width - 2, y - 1, 1, height - 2, 0); - drawDisplayRect(x + 1, y - height + 2, width - 2, 1, 0); - drawDisplayRect(x + 1, y - 1, 1, height - 2, 0); + drawDisplayRect(x, +1, y, +1, width, -2, 0, 1, 0); + drawDisplayRect(x + width, -2, y, +1, 0, 1, height, -2, 0); + drawDisplayRect(x, +1, y + height, -2, width, -2, 0, 1, 0); + drawDisplayRect(x, +1, y, +1, 0, 1, height, -2, 0); break; + case Common::kRenderHercA: + case Common::kRenderHercG: + lineColor = 0; // change linecolor to black + // supposed to fall through case Common::kRenderCGA: case Common::kRenderEGA: case Common::kRenderVGA: case Common::kRenderAtariST: default: - drawDisplayRect(x + 2, y - 1, width - 4, 1, lineColor); - drawDisplayRect(x + width - 4, y - 2, 2, height - 4, lineColor); - drawDisplayRect(x + 2, y - height + 2, width - 4, 1, lineColor); - drawDisplayRect(x + 2, y - 2, 2, height - 4, lineColor); + drawDisplayRect(x, +2, y, +1, width, -4, 0, 1, lineColor); + drawDisplayRect(x + width, -4, y, +2, 0, 2, height, -4, lineColor); + drawDisplayRect(x, +2, y + height, -2, width, -4, 0, 1, lineColor); + drawDisplayRect(x, +2, y, +2, 0, 2, height, -4, lineColor); break; } } -// coordinates for visual screen -void GfxMgr::drawRect(int16 x, int16 y, int16 width, int16 height, byte color) { - if (!render_Clip(x, y, width, height, SCRIPT_WIDTH, DISPLAY_HEIGHT - _renderStartOffsetY)) - return; - - // coordinate translation: visual-screen -> display-screen - x = x * 2; - y = y + _renderStartOffsetY; // drawDisplayRect paints anywhere on the whole screen, our coordinate is within playscreen - width = width * 2; // width was given as visual width, we need display width - - drawDisplayRect(x, y, width, height, color); -} - // coordinates are directly for display screen void GfxMgr::drawDisplayRect(int16 x, int16 y, int16 width, int16 height, byte color, bool copyToScreen) { switch (_vm->_renderMode) { case Common::kRenderCGA: drawDisplayRectCGA(x, y, width, height, color); break; + case Common::kRenderHercG: + case Common::kRenderHercA: + if (color) + color = 1; // change any color except black to green/amber + // supposed to fall through case Common::kRenderEGA: default: drawDisplayRectEGA(x, y, width, height, color); break; } if (copyToScreen) { - int16 upperY = y - height + 1; - g_system->copyRectToScreen(_displayScreen + upperY * DISPLAY_WIDTH + x, DISPLAY_WIDTH, x, upperY, width, height); + copyDisplayRectToScreen(x, y, width, height); } } +void GfxMgr::drawDisplayRect(int16 x, int16 adjX, int16 y, int16 adjY, int16 width, int16 adjWidth, int16 height, int16 adjHeight, byte color, bool copyToScreen) { + switch (_upscaledHires) { + case DISPLAY_UPSCALED_DISABLED: + x += adjX; y += adjY; + width += adjWidth; height += adjHeight; + break; + case DISPLAY_UPSCALED_640x400: + x += adjX * 2; y += adjY * 2; + width += adjWidth * 2; height += adjHeight * 2; + break; + default: + assert(0); + break; + } + drawDisplayRect(x, y, width, height, color, copyToScreen); +} + void GfxMgr::drawDisplayRectEGA(int16 x, int16 y, int16 width, int16 height, byte color) { - int offsetDisplay = (DISPLAY_WIDTH * y) + x; + uint32 offsetDisplay = (y * _displayScreenWidth) + x; int16 remainingHeight = height; while (remainingHeight) { memset(_displayScreen + offsetDisplay, color, width); - offsetDisplay -= DISPLAY_WIDTH; + offsetDisplay += _displayScreenWidth; remainingHeight--; } } void GfxMgr::drawDisplayRectCGA(int16 x, int16 y, int16 width, int16 height, byte color) { - int offsetDisplay = (DISPLAY_WIDTH * y) + x; + uint32 offsetDisplay = (y * _displayScreenWidth) + x; int16 remainingHeight = height; int16 remainingWidth = width; byte CGAMixtureColor = getCGAMixtureColor(color); @@ -644,18 +1081,20 @@ void GfxMgr::drawDisplayRectCGA(int16 x, int16 y, int16 width, int16 height, byt remainingWidth -= 2; } - offsetDisplay -= DISPLAY_WIDTH; + offsetDisplay += _displayScreenWidth; remainingHeight--; } } // row + column are text-coordinates void GfxMgr::drawCharacter(int16 row, int16 column, byte character, byte foreground, byte background, bool disabledLook) { - int16 x = column * FONT_DISPLAY_WIDTH; - int16 y = row * FONT_DISPLAY_HEIGHT; + int16 x = column; + int16 y = row; byte transformXOR = 0; byte transformOR = 0; + translateFontPosToDisplayScreen(x, y); + // Now figure out, if special handling needs to be done if (_vm->_game.gfxMode) { if (background & 0x08) { @@ -676,22 +1115,43 @@ void GfxMgr::drawStringOnDisplay(int16 x, int16 y, const char *text, byte foregr while (*text) { drawCharacterOnDisplay(x, y, *text, foregroundColor, backgroundColor); text++; - x += FONT_DISPLAY_WIDTH; + x += _displayFontWidth; + } +} + +void GfxMgr::drawStringOnDisplay(int16 x, int16 adjX, int16 y, int16 adjY, const char *text, byte foregroundColor, byte backgroundColor) { + switch (_upscaledHires) { + case DISPLAY_UPSCALED_DISABLED: + x += adjX; + y += adjY; + break; + case DISPLAY_UPSCALED_640x400: + x += adjX * 2; + y += adjY * 2; + break; + default: + assert(0); + break; } + drawStringOnDisplay(x, y, text, foregroundColor, backgroundColor); } void GfxMgr::drawCharacterOnDisplay(int16 x, int16 y, const byte character, byte foreground, byte background, byte transformXOR, byte transformOR) { int16 curX, curY; const byte *fontData; + bool fontIsHires = _font->isFontHires(); + int16 fontHeight = fontIsHires ? 16 : FONT_DISPLAY_HEIGHT; + int16 fontWidth = fontIsHires ? 16 : FONT_DISPLAY_WIDTH; + int16 fontBytesPerCharacter = fontIsHires ? 32 : FONT_BYTES_PER_CHARACTER; byte curByte = 0; uint16 curBit; // get font data of specified character - fontData = _vm->getFontData() + character * FONT_BYTES_PER_CHARACTER; + fontData = _font->getFontData() + character * fontBytesPerCharacter; curBit = 0; - for (curY = 0; curY < FONT_DISPLAY_HEIGHT; curY++) { - for (curX = 0; curX < FONT_DISPLAY_WIDTH; curX++) { + for (curY = 0; curY < fontHeight; curY++) { + for (curX = 0; curX < fontWidth; curX++) { if (!curBit) { curByte = *fontData; // do transformations in case they are needed (invert/disabled look) @@ -701,9 +1161,9 @@ void GfxMgr::drawCharacterOnDisplay(int16 x, int16 y, const byte character, byte curBit = 0x80; } if (curByte & curBit) { - putPixelOnDisplay(x + curX, y + curY, foreground); + putFontPixelOnDisplay(x, y, curX, curY, foreground, fontIsHires); } else { - putPixelOnDisplay(x + curX, y + curY, background); + putFontPixelOnDisplay(x, y, curX, curY, background, fontIsHires); } curBit = curBit >> 1; } @@ -711,18 +1171,20 @@ void GfxMgr::drawCharacterOnDisplay(int16 x, int16 y, const byte character, byte transformOR ^= 0xFF; } - copyDisplayRectToScreen(x, y, FONT_DISPLAY_WIDTH, FONT_DISPLAY_HEIGHT); + copyDisplayRectToScreen(x, y, _displayFontWidth, _displayFontHeight); } #define SHAKE_VERTICAL_PIXELS 4 -#define SHAKE_HORIZONTAL_PIXELS 8 +#define SHAKE_HORIZONTAL_PIXELS 4 // Sierra used some EGA port trickery to do it, we have to do it by copying pixels around void GfxMgr::shakeScreen(int16 repeatCount) { int shakeNr, shakeCount; uint8 *blackSpace; + int16 shakeHorizontalPixels = SHAKE_HORIZONTAL_PIXELS * (2 + _displayWidthMulAdjust); + int16 shakeVerticalPixels = SHAKE_VERTICAL_PIXELS * (1 + _displayHeightMulAdjust); - if ((blackSpace = (uint8 *)calloc(SHAKE_HORIZONTAL_PIXELS * DISPLAY_WIDTH, 1)) == NULL) + if ((blackSpace = (uint8 *)calloc(shakeVerticalPixels * _displayScreenWidth, 1)) == NULL) return; shakeCount = repeatCount * 8; // effectively 4 shakes per repeat @@ -732,12 +1194,12 @@ void GfxMgr::shakeScreen(int16 repeatCount) { for (shakeNr = 0; shakeNr < shakeCount; shakeNr++) { if (shakeNr & 1) { // move back - copyDisplayRectToScreen(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT); + copyDisplayToScreen(); } else { - g_system->copyRectToScreen(_displayScreen, DISPLAY_WIDTH, SHAKE_HORIZONTAL_PIXELS, SHAKE_VERTICAL_PIXELS, DISPLAY_WIDTH - SHAKE_HORIZONTAL_PIXELS, DISPLAY_HEIGHT - SHAKE_VERTICAL_PIXELS); + g_system->copyRectToScreen(_displayScreen, _displayScreenWidth, shakeHorizontalPixels, shakeVerticalPixels, _displayScreenWidth - shakeHorizontalPixels, _displayScreenHeight - shakeVerticalPixels); // additionally fill the remaining space with black - g_system->copyRectToScreen(blackSpace, DISPLAY_WIDTH, 0, 0, DISPLAY_WIDTH, SHAKE_VERTICAL_PIXELS); - g_system->copyRectToScreen(blackSpace, SHAKE_HORIZONTAL_PIXELS, 0, 0, SHAKE_HORIZONTAL_PIXELS, DISPLAY_HEIGHT); + g_system->copyRectToScreen(blackSpace, _displayScreenWidth, 0, 0, _displayScreenWidth, shakeVerticalPixels); + g_system->copyRectToScreen(blackSpace, shakeHorizontalPixels, 0, 0, shakeHorizontalPixels, _displayScreenHeight); } g_system->updateScreen(); g_system->delayMillis(66); // Sierra waited for 4 V'Syncs, which is around 66 milliseconds @@ -751,13 +1213,18 @@ void GfxMgr::updateScreen() { } void GfxMgr::initPriorityTable() { + _priorityTableSet = false; + + createDefaultPriorityTable(_priorityTable); +} + +void GfxMgr::createDefaultPriorityTable(uint8 *priorityTable) { int16 priority, step; int16 yPos = 0; - _priorityTableSet = false; for (priority = 1; priority < 15; priority++) { for (step = 0; step < 12; step++) { - _priorityTable[yPos++] = priority < 4 ? 4 : priority; + priorityTable[yPos++] = priority < 4 ? 4 : priority; } } } @@ -776,11 +1243,35 @@ void GfxMgr::setPriorityTable(int16 priorityBase) { } } +// used for saving +int16 GfxMgr::saveLoadGetPriority(int16 yPos) { + assert(yPos < SCRIPT_HEIGHT); + return _priorityTable[yPos]; +} +bool GfxMgr::saveLoadWasPriorityTableModified() { + return _priorityTableSet; +} + // used for restoring -void GfxMgr::setPriority(int16 yPos, int16 priority) { +void GfxMgr::saveLoadSetPriority(int16 yPos, int16 priority) { assert(yPos < SCRIPT_HEIGHT); _priorityTable[yPos] = priority; } +void GfxMgr::saveLoadSetPriorityTableModifiedBool(bool wasModified) { + _priorityTableSet = wasModified; +} +void GfxMgr::saveLoadFigureOutPriorityTableModifiedBool() { + uint8 defaultPriorityTable[SCRIPT_HEIGHT]; /**< priority table */ + + createDefaultPriorityTable(defaultPriorityTable); + + if (memcmp(defaultPriorityTable, _priorityTable, sizeof(_priorityTable)) == 0) { + // Match, it is the default table, so reset the flag + _priorityTableSet = false; + } else { + _priorityTableSet = true; + } +} /** * Convert sprite priority to y value. @@ -793,7 +1284,8 @@ int16 GfxMgr::priorityToY(int16 priority) { return (priority - 5) * 12 + 48; } - // dynamic priority bands were introduced in 3.002.086 (effectively AGI3) + // Dynamic priority bands were introduced in 2.425, but removed again until 2.936 (effectively last version of AGI2) + // They are available from 2.936 onwards. // It seems there was a glitch, that caused priority bands to not get calculated properly. // It was caused by this function starting with Y = 168 instead of 167, which meant it always // returned with 168 as result. @@ -804,6 +1296,8 @@ int16 GfxMgr::priorityToY(int16 priority) { // drawn first, followed by ego, which would then draw ego over the dwarf. // For more information see bug #1712585 (dwarf sprite priority) // + // This glitch is definitely present in 2.425, 2.936 and 3.002.086. + // // Priority bands were working properly in: 3.001.098 (Black Cauldron) uint16 agiVersion = _vm->getVersion(); @@ -925,7 +1419,38 @@ int GfxMgr::getAGIPalFileNum() { } void GfxMgr::initMouseCursor(MouseCursorData *mouseCursor, const byte *bitmapData, uint16 width, uint16 height, int hotspotX, int hotspotY) { - mouseCursor->bitmapData = bitmapData; + switch (_upscaledHires) { + case DISPLAY_UPSCALED_DISABLED: + mouseCursor->bitmapData = bitmapData; + break; + case DISPLAY_UPSCALED_640x400: { + mouseCursor->bitmapDataAllocated = (byte *)malloc(width * height * 4); + mouseCursor->bitmapData = mouseCursor->bitmapDataAllocated; + + // Upscale mouse cursor + byte *upscaledData = mouseCursor->bitmapDataAllocated; + + for (uint16 y = 0; y < height; y++) { + for (uint16 x = 0; x < width; x++) { + byte curColor = *bitmapData++; + upscaledData[x * 2 + 0] = curColor; + upscaledData[x * 2 + 1] = curColor; + upscaledData[x * 2 + (width * 2) + 0] = curColor; + upscaledData[x * 2 + (width * 2) + 1] = curColor; + } + upscaledData += width * 2 * 2; + } + + width *= 2; + height *= 2; + hotspotX *= 2; + hotspotY *= 2; + break; + } + default: + assert(0); + break; + } mouseCursor->width = width; mouseCursor->height = height; mouseCursor->hotspotX = hotspotX; diff --git a/engines/agi/graphics.h b/engines/agi/graphics.h index fb596626c6..1cb595cdfa 100644 --- a/engines/agi/graphics.h +++ b/engines/agi/graphics.h @@ -29,13 +29,15 @@ namespace Agi { #define SCRIPT_WIDTH 160 #define SCRIPT_HEIGHT 168 -#define DISPLAY_WIDTH 320 -#define DISPLAY_HEIGHT 200 - -#define GFX_WIDTH 320 -#define GFX_HEIGHT 200 -#define CHAR_COLS 8 -#define CHAR_LINES 8 +#define VISUAL_WIDTH 160 +#define VISUAL_HEIGHT 200 +#define DISPLAY_DEFAULT_WIDTH 320 +#define DISPLAY_DEFAULT_HEIGHT 200 + +enum GfxScreenUpscaledMode { + DISPLAY_UPSCALED_DISABLED = 0, + DISPLAY_UPSCALED_640x400 = 1 +}; class AgiEngine; @@ -47,6 +49,7 @@ enum GfxScreenMasks { struct MouseCursorData { const byte *bitmapData; + byte *bitmapDataAllocated; uint16 width; uint16 height; int hotspotX; @@ -56,6 +59,7 @@ struct MouseCursorData { class GfxMgr { private: AgiBase *_vm; + GfxFont *_font; uint8 _paletteGfxMode[256 * 3]; uint8 _paletteTextMode[256 * 3]; @@ -64,7 +68,7 @@ private: int _agipalFileNum; public: - GfxMgr(AgiBase *vm); + GfxMgr(AgiBase *vm, GfxFont *font); int initVideo(); int deinitVideo(); @@ -78,18 +82,58 @@ public: void setMouseCursor(bool busy = false); void setRenderStartOffset(uint16 offsetY); - uint16 getRenderStartOffsetY(); + uint16 getRenderStartDisplayOffsetY(); + + void translateGamePosToDisplayScreen(int16 &x, int16 &y); + void translateVisualPosToDisplayScreen(int16 &x, int16 &y); + void translateDisplayPosToGameScreen(int16 &x, int16 &y); + + void translateVisualDimensionToDisplayScreen(int16 &width, int16 &height); + void translateDisplayDimensionToVisualScreen(int16 &width, int16 &height); + + void translateGameRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height); + void translateVisualRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height); + void translateDisplayRectToVisualScreen(int16 &x, int16 &y, int16 &width, int16 &height); + + uint32 getDisplayOffsetToGameScreenPos(int16 x, int16 y); + uint32 getDisplayOffsetToVisualScreenPos(int16 x, int16 y); + + void copyDisplayRectToScreen(int16 x, int16 y, int16 width, int16 height); + void copyDisplayRectToScreen(int16 x, int16 adjX, int16 y, int16 adjY, int16 width, int16 adjWidth, int16 height, int16 adjHeight); + void copyDisplayRectToScreenUsingGamePos(int16 x, int16 y, int16 width, int16 height); + void copyDisplayRectToScreenUsingVisualPos(int16 x, int16 y, int16 width, int16 height); + void copyDisplayToScreen(); + + void translateFontPosToDisplayScreen(int16 &x, int16 &y); + void translateDisplayPosToFontScreen(int16 &x, int16 &y); + void translateFontDimensionToDisplayScreen(int16 &width, int16 &height); + void translateFontRectToDisplayScreen(int16 &x, int16 &y, int16 &width, int16 &height); + Common::Rect getFontRectForDisplayScreen(int16 column, int16 row, int16 width, int16 height); private: uint _pixels; - //uint16 _displayWidth; - //uint16 _displayHeight; uint _displayPixels; byte *_activeScreen; - byte *_visualScreen; // 160x168 - byte *_priorityScreen; // 160x168 - byte *_displayScreen; // 320x200 + byte *_gameScreen; // 160x168 - screen, where the actual game content is drawn to (actual graphics, not including status line, prompt, etc.) + byte *_priorityScreen; // 160x168 - screen contains priority information of the game screen + // the term "visual screen" is effectively the display screen, but at 160x200 resolution. Used for coordinate translation + byte *_displayScreen; // 320x200 or 640x400 - screen, that the game is rendered to and which is then copied to framebuffer + + uint16 _displayScreenWidth; + uint16 _displayScreenHeight; + + uint16 _displayFontWidth; + uint16 _displayFontHeight; + + uint16 _displayWidthMulAdjust; + uint16 _displayHeightMulAdjust; + + /** + * This variable defines, if upscaled hires is active and what upscaled mode + * is used. + */ + GfxScreenUpscaledMode _upscaledHires; bool _priorityTableSet; uint8 _priorityTable[SCRIPT_HEIGHT]; /**< priority table */ @@ -97,15 +141,32 @@ private: MouseCursorData _mouseCursor; MouseCursorData _mouseCursorBusy; - uint16 _renderStartOffsetY; + uint16 _renderStartVisualOffsetY; + uint16 _renderStartDisplayOffsetY; public: + uint16 getDisplayScreenWidth() { + return _displayScreenWidth; + } + uint16 getDisplayFontWidth() { + return _displayFontWidth; + } + uint16 getDisplayFontHeight() { + return _displayFontHeight; + } + + GfxScreenUpscaledMode getUpscaledHires() { + return _upscaledHires; + } + void debugShowMap(int mapNr); void clear(byte color, byte priority); void clearDisplay(byte color, bool copyToScreen = true); void putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority); void putPixelOnDisplay(int16 x, int16 y, byte color); + void putPixelOnDisplay(int16 x, int16 adjX, int16 y, int16 adjY, byte color); + void putFontPixelOnDisplay(int16 baseX, int16 baseY, int16 addX, int16 addY, byte color, bool isHires); byte getColor(int16 x, int16 y); byte getPriority(int16 x, int16 y); @@ -119,6 +180,7 @@ public: private: void render_BlockEGA(int16 x, int16 y, int16 width, int16 height, bool copyToScreen); void render_BlockCGA(int16 x, int16 y, int16 width, int16 height, bool copyToScreen); + void render_BlockHercules(int16 x, int16 y, int16 width, int16 height, bool copyToScreen); public: void transition_Amiga(); @@ -127,11 +189,9 @@ public: void block_save(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr); void block_restore(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr); - void copyDisplayRectToScreen(int16 x, int16 y, int16 width, int16 height); - void drawBox(int16 x, int16 y, int16 width, int16 height, byte backgroundColor, byte lineColor); - void drawRect(int16 x, int16 y, int16 width, int16 height, byte color); void drawDisplayRect(int16 x, int16 y, int16 width, int16 height, byte color, bool copyToScreen = true); + void drawDisplayRect(int16 x, int16 adjX, int16 y, int16 adjY, int16 width, int16 adjWidth, int16 height, int16 adjHeight, byte color, bool copyToScreen = true); private: void drawDisplayRectEGA(int16 x, int16 y, int16 width, int16 height, byte color); void drawDisplayRectCGA(int16 x, int16 y, int16 width, int16 height, byte color); @@ -139,14 +199,21 @@ private: public: void drawCharacter(int16 row, int16 column, byte character, byte foreground, byte background, bool disabledLook); void drawStringOnDisplay(int16 x, int16 y, const char *text, byte foreground, byte background); + void drawStringOnDisplay(int16 x, int16 adjX, int16 y, int16 adjY, const char *text, byte foregroundColor, byte backgroundColor); void drawCharacterOnDisplay(int16 x, int16 y, byte character, byte foreground, byte background, byte transformXOR = 0, byte transformOR = 0); void shakeScreen(int16 repeatCount); void updateScreen(); void initPriorityTable(); + void createDefaultPriorityTable(uint8 *priorityTable); void setPriorityTable(int16 priorityBase); - void setPriority(int16 yPos, int16 priority); + bool saveLoadWasPriorityTableModified(); + int16 saveLoadGetPriority(int16 yPos); + void saveLoadSetPriorityTableModifiedBool(bool wasModified); + void saveLoadSetPriority(int16 yPos, int16 priority); + void saveLoadFigureOutPriorityTableModifiedBool(); + int16 priorityToY(int16 priority); int16 priorityFromY(int16 yPos); }; diff --git a/engines/agi/inv.cpp b/engines/agi/inv.cpp index 1df5282622..834fa9badc 100644 --- a/engines/agi/inv.cpp +++ b/engines/agi/inv.cpp @@ -34,6 +34,8 @@ InventoryMgr::InventoryMgr(AgiEngine *agi, GfxMgr *gfx, TextMgr *text, SystemUI _gfx = gfx; _text = text; _systemUI = systemUI; + + _activeItemNr = -1; } InventoryMgr::~InventoryMgr() { diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp index 5a73afe6fb..3bc45af5d4 100644 --- a/engines/agi/keyboard.cpp +++ b/engines/agi/keyboard.cpp @@ -130,7 +130,7 @@ void AgiEngine::processScummVMEvents() { } break; case Common::EVENT_KEYDOWN: - if (event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_d) { + if (event.kbd.hasFlags(Common::KBD_CTRL | Common::KBD_SHIFT) && event.kbd.keycode == Common::KEYCODE_d) { _console->attach(); break; } @@ -256,7 +256,28 @@ void AgiEngine::processScummVMEvents() { // Original AGI actually created direction events in here // We don't do that, that's why we create a stationary event instead, which will // result in a direction change to 0 in handleController(). - keyEnqueue(AGI_KEY_STATIONARY); + switch (event.kbd.keycode) { + case Common::KEYCODE_LEFT: + case Common::KEYCODE_RIGHT: + case Common::KEYCODE_UP: + case Common::KEYCODE_DOWN: + case Common::KEYCODE_HOME: + case Common::KEYCODE_END: + case Common::KEYCODE_PAGEUP: + case Common::KEYCODE_PAGEDOWN: + case Common::KEYCODE_KP4: + case Common::KEYCODE_KP6: + case Common::KEYCODE_KP8: + case Common::KEYCODE_KP2: + case Common::KEYCODE_KP9: + case Common::KEYCODE_KP3: + case Common::KEYCODE_KP7: + case Common::KEYCODE_KP1: + keyEnqueue(AGI_KEY_STATIONARY); + break; + default: + break; + } } break; @@ -292,7 +313,8 @@ bool AgiEngine::handleMouseClicks(uint16 &key) { if (!cycleInnerLoopIsActive()) { // Only do this, when no inner loop is currently active - Common::Rect displayLineRect(DISPLAY_WIDTH, FONT_DISPLAY_HEIGHT); + Common::Rect displayLineRect = _gfx->getFontRectForDisplayScreen(0, 0, FONT_COLUMN_CHARACTERS, 1); +// Common::Rect displayLineRect(_gfx->getDisplayScreenWidth(), _gfx->getDisplayFontHeight()); if (displayLineRect.contains(_mouse.pos)) { // Mouse is inside first line of the screen @@ -307,7 +329,7 @@ bool AgiEngine::handleMouseClicks(uint16 &key) { // Prompt is currently enabled int16 promptRow = _text->promptRow_Get(); - displayLineRect.moveTo(0, promptRow * FONT_DISPLAY_HEIGHT); + displayLineRect.moveTo(0, promptRow * _gfx->getDisplayFontHeight()); if (displayLineRect.contains(_mouse.pos)) { // and user clicked within the line of the prompt @@ -330,9 +352,7 @@ bool AgiEngine::handleMouseClicks(uint16 &key) { _text->stringPos_Get(stringRow, stringColumn); stringMaxLen = _text->stringGetMaxLen(); - Common::Rect displayRect(stringMaxLen * FONT_DISPLAY_WIDTH, FONT_DISPLAY_HEIGHT); - displayRect.moveTo(stringColumn * FONT_DISPLAY_WIDTH, stringRow * FONT_DISPLAY_HEIGHT); - + Common::Rect displayRect = _gfx->getFontRectForDisplayScreen(stringColumn, stringRow, stringMaxLen, 1); if (displayRect.contains(_mouse.pos)) { // user clicked inside the input space showPredictiveDialog(); @@ -472,7 +492,7 @@ bool AgiEngine::handleController(uint16 key) { // in case you walked to the log by using the mouse, so don't!!! int16 egoDestinationX = _mouse.pos.x; int16 egoDestinationY = _mouse.pos.y; - adjustPosToGameScreen(egoDestinationX, egoDestinationY); + _gfx->translateDisplayPosToGameScreen(egoDestinationX, egoDestinationY); screenObjEgo->motionType = kMotionEgo; if (egoDestinationX < (screenObjEgo->xSize / 2)) { diff --git a/engines/agi/menu.cpp b/engines/agi/menu.cpp index 803efd757e..49c2d0eeab 100644 --- a/engines/agi/menu.cpp +++ b/engines/agi/menu.cpp @@ -49,8 +49,8 @@ GfxMenu::GfxMenu(AgiEngine *vm, GfxMgr *gfx, PictureMgr *picture, TextMgr *text) _drawnMenuNr = -1; _drawnMenuHeight = 0; _drawnMenuWidth = 0; - _drawnMenuRow = 0; - _drawnMenuColumn = 0; + _drawnMenuY = 0; + _drawnMenuX = 0; } GfxMenu::~GfxMenu() { @@ -64,6 +64,8 @@ GfxMenu::~GfxMenu() { } void GfxMenu::addMenu(const char *menuText) { + int16 curColumnEnd = _setupMenuColumn; + // already submitted? in that case no further changes possible if (_submitted) return; @@ -72,6 +74,18 @@ void GfxMenu::addMenu(const char *menuText) { menuEntry->text = menuText; menuEntry->textLen = menuEntry->text.size(); + + // Cut menu name in case menu bar is full + // Happens in at least the fan game Get Outta Space Quest + // Original interpreter had graphical issues in this case + // TODO: this whole code needs to get reworked anyway to support different types of menu bars depending on platform + curColumnEnd += menuEntry->textLen; + while ((menuEntry->textLen) && (curColumnEnd > 40)) { + menuEntry->text.deleteLastChar(); + menuEntry->textLen--; + curColumnEnd--; + } + menuEntry->row = 0; menuEntry->column = _setupMenuColumn; menuEntry->itemCount = 0; @@ -309,8 +323,9 @@ void GfxMenu::execute() { // Unless we are in "via mouse" mode. In that case check current mouse position if (viaMouse) { - int16 mouseRow = _vm->_mouse.pos.y / FONT_DISPLAY_HEIGHT; - int16 mouseColumn = _vm->_mouse.pos.x / FONT_DISPLAY_WIDTH; + int16 mouseRow = _vm->_mouse.pos.y; + int16 mouseColumn = _vm->_mouse.pos.x; + _gfx->translateDisplayPosToFontScreen(mouseColumn, mouseRow); mouseFindMenuSelection(mouseRow, mouseColumn, _drawnMenuNr, _mouseModeItemNr); } @@ -354,7 +369,7 @@ void GfxMenu::execute() { // WORKAROUND: Playarea starts right at the stop, so instead of clearing that part, render it from playarea // Required for at least Donald Duck // This was not done by original AGI, which means the upper pixel line were cleared in this case. - _gfx->render_Block(0, (1 * FONT_VISUAL_HEIGHT) - 1, SCRIPT_WIDTH, FONT_VISUAL_HEIGHT); + _gfx->render_Block(0, 0, SCRIPT_WIDTH, FONT_VISUAL_HEIGHT); } else { _text->clearLine(0, 0); } @@ -365,6 +380,10 @@ void GfxMenu::drawMenuName(int16 menuNr, bool inverted) { GuiMenuEntry *menuEntry = _array[menuNr]; bool disabledLook = false; + // Don't draw in case there is no text + if (!menuEntry->text.size()) + return; + if (!inverted) { _text->charAttrib_Set(0, _text->calculateTextBackground(15)); } else { @@ -409,10 +428,11 @@ void GfxMenu::drawMenu(int16 selectedMenuNr, int16 selectedMenuItemNr) { // calculate active menu dimensions _drawnMenuHeight = (menuEntry->itemCount + 2) * FONT_VISUAL_HEIGHT; _drawnMenuWidth = (menuEntry->maxItemTextLen * FONT_VISUAL_WIDTH) + 8; - _drawnMenuRow = (menuEntry->itemCount + 3 - _text->getWindowRowMin()) * FONT_VISUAL_HEIGHT - 1; - _drawnMenuColumn = (itemEntry->column - 1) * FONT_VISUAL_WIDTH; + _drawnMenuY = (1 - _text->getWindowRowMin()) * FONT_VISUAL_HEIGHT; + //(menuEntry->itemCount + 3 - _text->getWindowRowMin()) * FONT_VISUAL_HEIGHT - 1; + _drawnMenuX = (itemEntry->column - 1) * FONT_VISUAL_WIDTH; - _gfx->drawBox(_drawnMenuColumn, _drawnMenuRow, _drawnMenuWidth, _drawnMenuHeight, 15, 0); + _gfx->drawBox(_drawnMenuX, _drawnMenuY, _drawnMenuWidth, _drawnMenuHeight, 15, 0); while (itemCount) { if (itemNr == selectedMenuItemNr) { @@ -430,7 +450,7 @@ void GfxMenu::removeActiveMenu(int16 selectedMenuNr) { drawMenuName(selectedMenuNr, false); // overwrite actual menu items by rendering play screen - _gfx->render_Block(_drawnMenuColumn, _drawnMenuRow, _drawnMenuWidth, _drawnMenuHeight); + _gfx->render_Block(_drawnMenuX, _drawnMenuY, _drawnMenuWidth, _drawnMenuHeight); } void GfxMenu::keyPress(uint16 newKey) { @@ -531,8 +551,10 @@ void GfxMenu::keyPress(uint16 newKey) { // In "via mouse" mode, we check if user let go of the left mouse button and then select the item that way void GfxMenu::mouseEvent(uint16 newKey) { // Find out, where current mouse cursor actually is - int16 mouseRow = _vm->_mouse.pos.y / FONT_DISPLAY_HEIGHT; - int16 mouseColumn = _vm->_mouse.pos.x / FONT_DISPLAY_WIDTH; + int16 mouseRow = _vm->_mouse.pos.y; + int16 mouseColumn = _vm->_mouse.pos.x; + + _gfx->translateDisplayPosToFontScreen(mouseColumn, mouseRow); int16 activeMenuNr, activeItemNr; mouseFindMenuSelection(mouseRow, mouseColumn, activeMenuNr, activeItemNr); @@ -620,7 +642,7 @@ void GfxMenu::mouseFindMenuSelection(int16 mouseRow, int16 mouseColumn, int16 &a if (mouseRow == menuEntry->row) { // line match - if ((mouseColumn >= menuEntry->column) && (mouseColumn <= (menuEntry->column + menuEntry->textLen))) { + if ((mouseColumn >= menuEntry->column) && (mouseColumn < (menuEntry->column + menuEntry->textLen))) { // full match activeMenuNr = menuNr; activeMenuItemNr = -1; // no item selected @@ -642,7 +664,7 @@ void GfxMenu::mouseFindMenuSelection(int16 mouseRow, int16 mouseColumn, int16 &a if (mouseRow == itemEntry->row) { // line match - if ((mouseColumn >= itemEntry->column) && (mouseColumn <= (itemEntry->column + itemEntry->textLen))) { + if ((mouseColumn >= itemEntry->column) && (mouseColumn < (itemEntry->column + itemEntry->textLen))) { // full match if (itemEntry->enabled) { // Only see it, when it's currently enabled diff --git a/engines/agi/menu.h b/engines/agi/menu.h index a621d7f0f2..b47289180b 100644 --- a/engines/agi/menu.h +++ b/engines/agi/menu.h @@ -111,8 +111,8 @@ private: uint16 _drawnMenuHeight; uint16 _drawnMenuWidth; - int16 _drawnMenuRow; - int16 _drawnMenuColumn; + int16 _drawnMenuY; + int16 _drawnMenuX; // Following variables are used in "via mouse" mode int16 _mouseModeItemNr; diff --git a/engines/agi/motion.cpp b/engines/agi/motion.cpp index 7f49028701..f408ba35e6 100644 --- a/engines/agi/motion.cpp +++ b/engines/agi/motion.cpp @@ -62,6 +62,60 @@ void AgiEngine::changePos(ScreenObjEntry *screenObj) { } } +// WORKAROUND: +// A motion was just activated, check if "end.of.loop"/"reverse.loop" is currently active for the same screen object +// If this is the case, it would result in some random flag getting overwritten in original AGI after the loop was +// completed, because in original AGI loop_flag + wander_count/follow_stepSize/move_X shared the same memory location. +// This is basically an implementation error in the original interpreter. +// Happens in at least: +// - BC: right at the end when the witches disappear at least on Apple IIgs (room 12, screen object 13, view 84) +// - KQ1: when grabbing the eagle (room 22). +// - KQ2: happened somewhere in the game, LordHoto couldn't remember exactly where +void AgiEngine::motionActivated(ScreenObjEntry *screenObj) { + if (screenObj->flags & fCycling) { + // Cycling active too + switch (screenObj->cycle) { + case kCycleEndOfLoop: // "end.of.loop" + case kCycleRevLoop: // "reverse.loop" + // Disable it + screenObj->flags &= ~fCycling; + screenObj->cycle = kCycleNormal; + + warning("Motion activated for screen object %d, but cycler also active", screenObj->objectNr); + warning("This would have resulted in flag corruption in original AGI. Cycler disabled."); + break; + default: + break; + } + } +} + +// WORKAROUND: +// See comment for motionActivated() +// This way no flag would have been overwritten, but certain other variables of the motions. +void AgiEngine::cyclerActivated(ScreenObjEntry *screenObj) { + switch (screenObj->motionType) { + case kMotionWander: + // this would have resulted in wander_count to get corrupted + // We don't stop it. + break; + case kMotionFollowEgo: + // this would have resulted in follow_stepSize to get corrupted + // do not stop motion atm - screenObj->direction = 0; + // do not stop motion atm - screenObj->motionType = kMotionNormal; + break; + case kMotionMoveObj: + // this would have resulted in move_x to get corrupted + // do not stop motion atm - motionMoveObjStop(screenObj); + break; + default: + return; + break; + } + warning("Cycler activated for screen object %d, but motion also active", screenObj->objectNr); + warning("This would have resulted in corruption in original AGI. Motion disabled."); +} + void AgiEngine::motionWander(ScreenObjEntry *screenObj) { uint8 originalWanderCount = screenObj->wander_count; diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp index 3f8630521d..fed07ea986 100644 --- a/engines/agi/op_cmd.cpp +++ b/engines/agi/op_cmd.cpp @@ -37,7 +37,6 @@ namespace Agi { -#define getGameID() state->_vm->getGameID() #define getFeatures() state->_vm->getFeatures() #define getVersion() state->_vm->getVersion() #define getLanguage() state->_vm->getLanguage() @@ -82,7 +81,7 @@ void cmdAssignN(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // variable to the correct value here // Fixes bug #1942476 - "AGI: Fan(Get Outta SQ) - Score // is lost on restart" - if (getGameID() == GID_GETOUTTASQ && varNr == 7) + if (vm->getGameID() == GID_GETOUTTASQ && varNr == 7) vm->setVar(varNr, 8); } @@ -890,6 +889,19 @@ void cmdObjStatusF(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // unk_181: Deactivate keypressed control (default control of ego) void cmdSetSimple(AgiGame *state, AgiEngine *vm, uint8 *parameter) { if (!(getFeatures() & (GF_AGI256 | GF_AGI256_2))) { + // set.simple is called by Larry 1 on Apple IIgs at the store, after answering the 555-6969 phone. + // load.sound(16) is called right before it. Interpreter is 2.440-like. + // it's called with parameter 16. + // Original interpreter doesn't seem to play any sound. + // TODO: Figure out what's going on. It can't be automatic saving of course. + // Also getting called in KQ1, when planting beans - parameter 12. + // And when killing the witch - parameter 40. + if ((getVersion() < 0x2425) || (getVersion() == 0x2440)) { + // was not available before 2.2425, but also not available in 2.440 + warning("set.simple called, although not available for current AGI version"); + return; + } + int16 stringNr = parameter[0]; const char *textPtr = nullptr; @@ -897,7 +909,10 @@ void cmdSetSimple(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // Try to get description for automatic saves textPtr = state->strings[stringNr]; + strncpy(state->automaticSaveDescription, textPtr, sizeof(state->automaticSaveDescription)); + state->automaticSaveDescription[sizeof(state->automaticSaveDescription) - 1] = 0; + if (state->automaticSaveDescription[0]) { // We got it and it's set, so enable automatic saving state->automaticSave = true; @@ -917,21 +932,26 @@ void cmdSetSimple(AgiGame *state, AgiEngine *vm, uint8 *parameter) { spritesMgr->drawAllSpriteLists(); state->pictureShown = false; + // Loading trigger + vm->artificialDelayTrigger_DrawPicture(resourceNr); + // Show the picture. Similar to void cmdShow_pic(AgiGame *state, AgiEngine *vm, uint8 *p). vm->setFlag(VM_FLAG_OUTPUT_MODE, false); vm->_text->closeWindow(); vm->_picture->showPic(); state->pictureShown = true; - - // Loading trigger - vm->loadingTrigger_DrawPicture(); } } +// push.script was not available until 2.425, and also not available in 2.440 void cmdPopScript(AgiGame *state, AgiEngine *vm, uint8 *parameter) { - if (getVersion() >= 0x2915) { - debug(0, "pop.script"); + if ((getVersion() < 0x2425) || (getVersion() == 0x2440)) { + // was not available before 2.2425, but also not available in 2.440 + warning("pop.script called, although not available for current AGI version"); + return; } + + debug(0, "pop.script"); } void cmdDiscardSound(AgiGame *state, AgiEngine *vm, uint8 *parameter) { @@ -953,8 +973,18 @@ void cmdShowMouse(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // but show.mouse is never called afterwards. Game running under emulator doesn't seem to hide the mouse cursor. // TODO: figure out, what exactly happens. Probably some hacked-in command and not related to mouse cursor for that game? void cmdHideMouse(AgiGame *state, AgiEngine *vm, uint8 *parameter) { - if (getVersion() < 0x3000) + if (getVersion() < 0x3000) { + // was not available before 3.086 + warning("hide.mouse, although not available for current AGI version"); + return; + } + + if ((vm->getGameID() == GID_MH1) && (vm->getPlatform() == Common::kPlatformApple2GS)) { + // Called right after beating arcade sequence on day 4 in the hospital Parameter is "1". + // Right before cutscene. show.mouse isn't called. Probably different function. + warning("hide.mouse called, disabled for MH1 Apple IIgs"); return; + } // WORKAROUND: Turns off current movement that's being caused with the mouse. // This fixes problems with too many popup boxes appearing in the Amiga @@ -972,14 +1002,18 @@ void cmdHideMouse(AgiGame *state, AgiEngine *vm, uint8 *parameter) { } void cmdAllowMenu(AgiGame *state, AgiEngine *vm, uint8 *parameter) { + if (getVersion() < 0x3098) { + // was not available before 3.098 + warning("allow.menu called, although not available for current AGI version"); + return; + } + uint16 allowed = parameter[0]; - if (getVersion() >= 0x3098) { - if (allowed) { - state->_vm->_menu->accessAllow(); - } else { - state->_vm->_menu->accessDeny(); - } + if (allowed) { + state->_vm->_menu->accessAllow(); + } else { + state->_vm->_menu->accessDeny(); } } @@ -997,15 +1031,21 @@ void cmdFenceMouse(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // HoldKey was added in 2.425 // There was no way to disable this mode until 3.098 though void cmdHoldKey(AgiGame *state, AgiEngine *vm, uint8 *parameter) { - if (getVersion() < 0x2425) + if ((getVersion() < 0x2425) || (getVersion() == 0x2440)) { + // was not available before 2.425, but also not available in 2.440 + warning("hold.key called, although not available for current AGI version"); return; + } vm->_keyHoldMode = true; } void cmdReleaseKey(AgiGame *state, AgiEngine *vm, uint8 *parameter) { - if (getVersion() < 0x3098) + if (getVersion() < 0x3098) { + // was not available before 3.098 + warning("release.key called, although not available for current AGI version"); return; + } vm->_keyHoldMode = false; } @@ -1094,7 +1134,7 @@ void cmdDrawPicV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) { vm->_text->promptClear(); // Loading trigger - vm->loadingTrigger_DrawPicture(); + vm->artificialDelayTrigger_DrawPicture(resourceNr); } void cmdDrawPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) { @@ -1106,6 +1146,7 @@ void cmdDrawPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) { spritesMgr->eraseSprites(); vm->_picture->decodePicture(resourceNr, true); + spritesMgr->buildAllSpriteLists(); spritesMgr->drawAllSpriteLists(); state->pictureShown = false; @@ -1123,11 +1164,11 @@ void cmdDrawPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // above the ground), flag 103 is reset, thereby fixing this issue. Note // that this is a script bug and occurs in the original interpreter as well. // Fixes bug #3056: AGI: SQ1 (2.2 DOS ENG) bizzare exploding roger - if (getGameID() == GID_SQ1 && resourceNr == 20) + if (vm->getGameID() == GID_SQ1 && resourceNr == 20) vm->setFlag(103, false); // Loading trigger - vm->loadingTrigger_DrawPicture(); + vm->artificialDelayTrigger_DrawPicture(resourceNr); } void cmdShowPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) { @@ -1179,7 +1220,7 @@ void cmdOverlayPic(AgiGame *state, AgiEngine *vm, uint8 *parameter) { state->pictureShown = false; // Loading trigger - vm->loadingTrigger_DrawPicture(); + vm->artificialDelayTrigger_DrawPicture(resourceNr); } void cmdShowPriScreen(AgiGame *state, AgiEngine *vm, uint8 *parameter) { @@ -1454,6 +1495,8 @@ void cmdReverseLoop(AgiGame *state, AgiEngine *vm, uint8 *parameter) { screenObj->flags |= (fDontupdate | fUpdate | fCycling); screenObj->loop_flag = loopFlag; state->_vm->setFlag(screenObj->loop_flag, false); + + vm->cyclerActivated(screenObj); } void cmdReverseLoopV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) { @@ -1479,6 +1522,8 @@ void cmdEndOfLoop(AgiGame *state, AgiEngine *vm, uint8 *parameter) { screenObj->flags |= (fDontupdate | fUpdate | fCycling); screenObj->loop_flag = loopFlag; vm->setFlag(screenObj->loop_flag, false); + + vm->cyclerActivated(screenObj); } void cmdEndOfLoopV1(AgiGame *state, AgiEngine *vm, uint8 *parameter) { @@ -1591,6 +1636,8 @@ void cmdFollowEgo(AgiGame *state, AgiEngine *vm, uint8 *parameter) { vm->setFlag(screenObj->follow_flag, false); screenObj->flags |= fUpdate; } + + vm->motionActivated(screenObj); } void cmdMoveObj(AgiGame *state, AgiEngine *vm, uint8 *parameter) { @@ -1619,6 +1666,8 @@ void cmdMoveObj(AgiGame *state, AgiEngine *vm, uint8 *parameter) { screenObj->flags |= fUpdate; } + vm->motionActivated(screenObj); + if (objectNr == 0) state->playerControl = false; @@ -1647,6 +1696,8 @@ void cmdMoveObjF(AgiGame *state, AgiEngine *vm, uint8 *parameter) { vm->setFlag(screenObj->move_flag, false); screenObj->flags |= fUpdate; + vm->motionActivated(screenObj); + if (objectNr == 0) state->playerControl = false; @@ -1668,6 +1719,8 @@ void cmdWander(AgiGame *state, AgiEngine *vm, uint8 *parameter) { } else { screenObj->flags |= fUpdate; } + + vm->motionActivated(screenObj); } void cmdSetGameID(AgiGame *state, AgiEngine *vm, uint8 *parameter) { @@ -1857,7 +1910,7 @@ void cmdDistance(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // wouldn't chase Rosella around anymore. If it had worked correctly the zombie // wouldn't have come up at all or it would have come up and gone back down // immediately. The latter approach is the one implemented here. - if (getGameID() == GID_KQ4 && (vm->getVar(VM_VAR_CURRENT_ROOM) == 16 || vm->getVar(VM_VAR_CURRENT_ROOM) == 18) && destVarNr >= 221 && destVarNr <= 223) { + if (vm->getGameID() == GID_KQ4 && (vm->getVar(VM_VAR_CURRENT_ROOM) == 16 || vm->getVar(VM_VAR_CURRENT_ROOM) == 18) && destVarNr >= 221 && destVarNr <= 223) { // Rooms 16 and 18 are graveyards where three zombies come up at night. They use logics 16 and 18. // Variables 221-223 are used to save the distance between each zombie and Rosella. // Variables 155, 156 and 162 are used to save the state of each zombie in room 16. @@ -2132,6 +2185,7 @@ void cmdPrintAtV(AgiGame *state, AgiEngine *vm, uint8 *parameter) { state->_vm->_text->printAt(textNr, textRow, textColumn, textWidth); } +// push.script was not available until 2.425, and also not available in 2.440 void cmdPushScript(AgiGame *state, AgiEngine *vm, uint8 *parameter) { // We run AGIMOUSE always as a side effect //if (getFeatures() & GF_AGIMOUSE || true) { @@ -2146,6 +2200,20 @@ void cmdPushScript(AgiGame *state, AgiEngine *vm, uint8 *parameter) { } void cmdSetPriBase(AgiGame *state, AgiEngine *vm, uint8 *parameter) { + if ((getVersion() != 0x2425) && (getVersion() < 0x2936)) { + // was only available in the 2.425 interpreter and from 2.936 (last AGI2 version) onwards + // Called during KQ3 (Apple IIgs): + // - picking up chicken (parameter = 50) + // - opening store/tavern door (parameter = 19) + // - when pirates say "Land Ho" (parameter = 16) + // - when killing the dragon (parameter = 4) + // Also called by SQ2 (Apple IIgs): + // - in Vohaul's lair (SQ2 currently gets this call through, which breaks some priority) + // TODO: Figure out what's going on + warning("set.pri.base called, although not available for current AGI version"); + return; + } + uint16 priorityBase = parameter[0]; debug(0, "Priority base set to %d", priorityBase); @@ -2159,7 +2227,7 @@ void cmdMousePosn(AgiGame *state, AgiEngine *vm, uint8 *parameter) { int16 mouseX = vm->_mouse.pos.x; int16 mouseY = vm->_mouse.pos.y; - state->_vm->adjustPosToGameScreen(mouseX, mouseY); + vm->_gfx->translateDisplayPosToGameScreen(mouseX, mouseY); vm->setVar(destVarNr1, mouseX); vm->setVar(destVarNr2, mouseY); @@ -2285,6 +2353,9 @@ int AgiEngine::runLogic(int16 logicNr) { } #endif + // Just a counter for every instruction, that got executed + _instructionCounter++; + _game.execStack.back().curIP = state->_curLogic->cIP; char st[101]; diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp index 359d79ee4a..472917de77 100644 --- a/engines/agi/opcodes.cpp +++ b/engines/agi/opcodes.cpp @@ -343,18 +343,18 @@ AgiInstruction insV2[] = { { "div.n", "vn", &cmdDivN }, // B7 { "div.v", "vv", &cmdDivV }, // B8 { "close.window", "", &cmdCloseWindow }, // B9 - { "set.simple", "n", &cmdSetSimple }, // BA + { "set.simple", "n", &cmdSetSimple }, // BA AGI2.425+, *BUT* not included in AGI2.440 { "push.script", "", &cmdPushScript }, // BB { "pop.script", "", &cmdPopScript }, // BC { "hold.key", "", &cmdHoldKey }, // BD - { "set.pri.base", "n", &cmdSetPriBase }, // BE - { "discard.sound", "n", &cmdDiscardSound }, // BF - { "hide.mouse", "", &cmdHideMouse }, // 1 arg for AGI version 3.002.086 + { "set.pri.base", "n", &cmdSetPriBase }, // BE AGI2.936+ *AND* also inside AGI2.425 + { "discard.sound", "n", &cmdDiscardSound }, // BF was skip for PC + { "hide.mouse", "", &cmdHideMouse }, // C0 1 arg for AGI version 3.002.086 AGI3+ only starts here { "allow.menu", "n", &cmdAllowMenu }, // C1 { "show.mouse", "", &cmdShowMouse }, // C2 { "fence.mouse", "nnnn", &cmdFenceMouse }, // C3 { "mouse.posn", "vv", &cmdMousePosn }, // C4 - { "release.key", "", &cmdReleaseKey }, // 2 args for at least the Amiga GR (v2.05 1989-03-09) using AGI 2.316 + { "release.key", "", &cmdReleaseKey }, // C5 2 args for at least the Amiga GR (v2.05 1989-03-09) using AGI 2.316 { "adj.ego.move.to.xy", "", &cmdAdjEgoMoveToXY } // C6 }; diff --git a/engines/agi/palette.h b/engines/agi/palette.h index f66582b9b6..40c31da425 100644 --- a/engines/agi/palette.h +++ b/engines/agi/palette.h @@ -60,6 +60,22 @@ static const uint8 PALETTE_CGA[4 * 3] = { }; /** + * 2 color Hercules (green) palette. Using 8-bit RGB values. + */ +static const uint8 PALETTE_HERCULES_GREEN[2 * 3] = { + 0x00, 0x00, 0x00, // black + 0x00, 0xdc, 0x28 // green +}; + +/** + * 2 color Hercules (amber) palette. Using 8-bit RGB values. + */ +static const uint8 PALETTE_HERCULES_AMBER[2 * 3] = { + 0x00, 0x00, 0x00, // black + 0xdc, 0xb4, 0x00 // amber +}; + +/** * Atari ST AGI palette. * Used by all of the tested Atari ST AGI games * from Donald Duck's Playground (1986) to Manhunter II (1989). @@ -122,6 +138,9 @@ static const uint8 PALETTE_APPLE_II_GS[16 * 3] = { 0xF, 0xF, 0xF }; +// Re-use Amiga v1 palette for Apple IIgs Space Quest 1 +#define PALETTE_APPLE_II_GS_SQ1 PALETTE_AMIGA_V1 + /** * First generation Amiga & Apple IIGS AGI palette. * A 16-color, 12-bit RGB palette. diff --git a/engines/agi/picture.cpp b/engines/agi/picture.cpp index 36eb587f68..a80e811f44 100644 --- a/engines/agi/picture.cpp +++ b/engines/agi/picture.cpp @@ -394,9 +394,6 @@ void PictureMgr::drawPictureC64() { _patCode = getNextByte(); plotBrush(); break; - case 0xfb: - draw_LineShort(); - break; case 0xff: // end of data return; default: @@ -433,6 +430,9 @@ void PictureMgr::drawPictureV1() { _scrOn = true; _priOn = false; break; + case 0xfb: + draw_LineShort(); + break; case 0xff: // end of data return; default: @@ -1001,7 +1001,7 @@ void PictureMgr::clear() { void PictureMgr::showPic() { debugC(8, kDebugLevelMain, "Show picture!"); - _gfx->render_Block(0, 167, SCRIPT_WIDTH, SCRIPT_HEIGHT); + _gfx->render_Block(0, 0, SCRIPT_WIDTH, SCRIPT_HEIGHT); } /** @@ -1014,8 +1014,7 @@ void PictureMgr::showPic(int16 x, int16 y, int16 pic_width, int16 pic_height) { debugC(8, kDebugLevelMain, "Show picture!"); - // render block requires lower left coordinate! - _gfx->render_Block(x, pic_height + y - 1, pic_width, pic_height); + _gfx->render_Block(x, y, pic_width, pic_height); } void PictureMgr::showPicWithTransition() { @@ -1038,13 +1037,13 @@ void PictureMgr::showPicWithTransition() { case Common::kRenderAmiga: case Common::kRenderApple2GS: // Platform Amiga/Apple II GS -> render and do Amiga transition - _gfx->render_Block(0, 167, SCRIPT_WIDTH, SCRIPT_HEIGHT, false); + _gfx->render_Block(0, 0, SCRIPT_WIDTH, SCRIPT_HEIGHT, false); _gfx->transition_Amiga(); return; break; case Common::kRenderAtariST: // Platform Atari ST used a different transition, looks "high-res" (full 320x168) - _gfx->render_Block(0, 167, SCRIPT_WIDTH, SCRIPT_HEIGHT, false); + _gfx->render_Block(0, 0, SCRIPT_WIDTH, SCRIPT_HEIGHT, false); _gfx->transition_AtariSt(); return; default: @@ -1054,7 +1053,7 @@ void PictureMgr::showPicWithTransition() { } } - _gfx->render_Block(0, 167, SCRIPT_WIDTH, SCRIPT_HEIGHT); + _gfx->render_Block(0, 0, SCRIPT_WIDTH, SCRIPT_HEIGHT); } // preagi needed functions (for plotPattern) diff --git a/engines/agi/preagi.cpp b/engines/agi/preagi.cpp index 104b442f5d..bb5d3b8896 100644 --- a/engines/agi/preagi.cpp +++ b/engines/agi/preagi.cpp @@ -58,7 +58,7 @@ void PreAgiEngine::initialize() { initRenderMode(); _font = new GfxFont(this); - _gfx = new GfxMgr(this); + _gfx = new GfxMgr(this, _font); _picture = new PictureMgr(this, _gfx); _font->init(); @@ -112,7 +112,7 @@ void PreAgiEngine::clearScreen(int attr, bool overrideDefault) { } void PreAgiEngine::clearGfxScreen(int attr) { - _gfx->drawDisplayRect(0, 0, GFX_WIDTH - 1, IDI_MAX_ROW_PIC * 8 - 1, (attr & 0xF0) / 0x10); + _gfx->drawDisplayRect(0, 0, DISPLAY_DEFAULT_WIDTH - 1, IDI_MAX_ROW_PIC * 8 - 1, (attr & 0xF0) / 0x10); } // String functions diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp index 8b1ae81b8e..620d5e0baf 100644 --- a/engines/agi/preagi_mickey.cpp +++ b/engines/agi/preagi_mickey.cpp @@ -957,7 +957,7 @@ void MickeyEngine::drawLogo() { } } - _gfx->copyDisplayRectToScreen(0, 0, DISPLAY_WIDTH, height); + _gfx->copyDisplayToScreen(); delete[] fileBuffer; } diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp index 1bf0dbcc02..0658609cd0 100644 --- a/engines/agi/saveload.cpp +++ b/engines/agi/saveload.cpp @@ -45,23 +45,25 @@ #include "agi/systemui.h" #include "agi/words.h" -#define SAVEGAME_CURRENT_VERSION 8 +#define SAVEGAME_CURRENT_VERSION 11 // -// Version 0 (Sarien): view table has 64 entries -// Version 1 (Sarien): view table has 256 entries (needed in KQ3) -// Version 2 (ScummVM): first ScummVM version -// Version 3 (ScummVM): added AGIPAL save/load support -// Version 4 (ScummVM): added thumbnails and save creation date/time -// Version 5 (ScummVM): Added game md5 -// Version 6 (ScummVM): Added game played time -// Version 7 (ScummVM): Added controller key mappings -// required for some games for quick-loading from ScummVM main menu -// for games, that do not set all key mappings right at the start -// Added automatic save data (for command SetSimple) -// Version 8 (ScummVM): Added Hold-Key-Mode boolean -// required for at least Mixed Up Mother Goose -// gets set at the start of the game only +// Version 0 (Sarien): view table has 64 entries +// Version 1 (Sarien): view table has 256 entries (needed in KQ3) +// Version 2 (ScummVM): first ScummVM version +// Version 3 (ScummVM): added AGIPAL save/load support +// Version 4 (ScummVM): added thumbnails and save creation date/time +// Version 5 (ScummVM): Added game md5 +// Version 6 (ScummVM): Added game played time +// Version 7 (ScummVM): Added controller key mappings +// required for some games for quick-loading from ScummVM main menu +// for games, that do not set all key mappings right at the start +// Added automatic save data (for command SetSimple) +// Version 8 (ScummVM): Added Hold-Key-Mode boolean +// required for at least Mixed Up Mother Goose +// gets set at the start of the game only +// Version 9 (ScummVM): Added seconds to saved game time stamp +// Version 10 (ScummVM): Added priorityTableSet boolean namespace Agi { @@ -109,6 +111,8 @@ int AgiEngine::saveGame(const Common::String &fileName, const Common::String &de debugC(5, kDebugLevelMain | kDebugLevelSavegame, "Writing save date (%d)", saveDate); out->writeUint16BE(saveTime); debugC(5, kDebugLevelMain | kDebugLevelSavegame, "Writing save time (%d)", saveTime); + // Version 9+: save seconds of current time as well + out->writeByte(curTime.tm_sec & 0xFF); out->writeUint32BE(playTime); debugC(5, kDebugLevelMain | kDebugLevelSavegame, "Writing play time (%d)", playTime); @@ -171,9 +175,11 @@ int AgiEngine::saveGame(const Common::String &fileName, const Common::String &de out->writeSint16BE(0); } - // TODO: save if priority table was modified for (i = 0; i < SCRIPT_HEIGHT; i++) - out->writeByte(_gfx->priorityFromY(i)); + out->writeByte(_gfx->saveLoadGetPriority(i)); + + // Version 10+: Save, if priority table got modified (set.pri.base opcode) + out->writeSint16BE((int16)_gfx->saveLoadWasPriorityTableModified()); out->writeSint16BE((int16)_game.gfxMode); out->writeByte(_text->inputGetCursorChar()); @@ -260,6 +266,8 @@ int AgiEngine::saveGame(const Common::String &fileName, const Common::String &de out->writeByte(screenObj->motionType); out->writeByte(screenObj->cycle); + // Version 11+: loop_flag, was saved previously under vt.parm1 + out->writeByte(screenObj->loop_flag); out->writeByte(screenObj->priority); out->writeUint16BE(screenObj->flags); @@ -338,6 +346,7 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) { int16 parm[7]; Common::InSaveFile *in; bool totalPlayTimeWasSet = false; + byte oldLoopFlag = 0; debugC(3, kDebugLevelMain | kDebugLevelSavegame, "AgiEngine::loadGame(%s)", fileName.c_str()); @@ -384,7 +393,10 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) { Graphics::skipThumbnail(*in); in->readUint32BE(); // save date - in->readUint16BE(); // save time + in->readUint16BE(); // save time (hour + minute) + if (saveVersion >= 9) { + in->readByte(); // save time seconds + } if (saveVersion >= 6) { uint32 playTime = in->readUint32BE(); inGameTimerReset(playTime * 1000); @@ -494,7 +506,21 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) { } for (i = 0; i < SCRIPT_HEIGHT; i++) - _gfx->setPriority(i, in->readByte()); + _gfx->saveLoadSetPriority(i, in->readByte()); + + if (saveVersion >= 10) { + // Version 10+: priority table was modified by scripts + int16 priorityTableWasModified = in->readSint16BE(); + + if (priorityTableWasModified) { + _gfx->saveLoadSetPriorityTableModifiedBool(true); + } else { + _gfx->saveLoadSetPriorityTableModifiedBool(false); + } + } else { + // Try to figure it out by ourselves + _gfx->saveLoadFigureOutPriorityTableModifiedBool(); + } _text->closeWindow(); @@ -611,6 +637,10 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) { screenObj->motionType = (MotionType)in->readByte(); screenObj->cycle = (CycleType)in->readByte(); + if (saveVersion >= 11) { + // Version 11+: loop_flag, was previously vt.parm1 + screenObj->loop_flag = in->readByte(); + } screenObj->priority = in->readByte(); screenObj->flags = in->readUint16BE(); @@ -618,7 +648,7 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) { // this was done so that saved games compatibility isn't broken switch (screenObj->motionType) { case kMotionNormal: - in->readByte(); + oldLoopFlag = in->readByte(); in->readByte(); in->readByte(); in->readByte(); @@ -628,12 +658,14 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) { in->readByte(); in->readByte(); in->readByte(); + oldLoopFlag = screenObj->wander_count; break; case kMotionFollowEgo: screenObj->follow_stepSize = in->readByte(); screenObj->follow_flag = in->readByte(); screenObj->follow_count = in->readByte(); in->readByte(); + oldLoopFlag = screenObj->follow_stepSize; break; case kMotionEgo: case kMotionMoveObj: @@ -641,10 +673,21 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) { screenObj->move_y = in->readByte(); screenObj->move_stepSize = in->readByte(); screenObj->move_flag = in->readByte(); + oldLoopFlag = screenObj->move_x; break; default: error("unknown motion-type"); } + if (saveVersion < 11) { + if (saveVersion < 7) { + // Recreate loop_flag from motion-type (was previously vt.parm1) + // vt.parm1 was shared for multiple uses + screenObj->loop_flag = oldLoopFlag; + } else { + // for Version 7-10 we can't really do anything, it was not saved + screenObj->loop_flag = 0; // set it to 0 + } + } } for (i = vtEntries; i < SCREENOBJECTS_MAX; i++) { memset(&_game.screenObjTable[i], 0, sizeof(ScreenObjEntry)); @@ -693,7 +736,7 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) { _words->clearEgoWords(); // don't delay anything right after restoring a game - nonBlockingText_Forget(); + artificialDelay_Reset(); _sprites->eraseSprites(); _sprites->buildAllSpriteLists(); @@ -704,7 +747,7 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) { _text->promptRedraw(); // copy everything over (we should probably only copy over the remaining parts of the screen w/o play screen - _gfx->copyDisplayRectToScreen(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT); + _gfx->copyDisplayToScreen(); // Sync volume settings from ScummVM system settings, so that VM volume variable is overwritten setVolumeViaSystemSetting(); @@ -813,7 +856,7 @@ Common::String AgiEngine::getSavegameFilename(int16 slotId) const { return saveLoadSlot; } -bool AgiEngine::getSavegameInformation(int16 slotId, Common::String &saveDescription, uint32 &saveDate, uint16 &saveTime, bool &saveIsValid) { +bool AgiEngine::getSavegameInformation(int16 slotId, Common::String &saveDescription, uint32 &saveDate, uint32 &saveTime, bool &saveIsValid) { Common::InSaveFile *in; Common::String fileName = getSavegameFilename(slotId); char saveGameDescription[31]; @@ -875,7 +918,10 @@ bool AgiEngine::getSavegameInformation(int16 slotId, Common::String &saveDescrip Graphics::skipThumbnail(*in); saveDate = in->readUint32BE(); - saveTime = in->readUint16BE(); + saveTime = in->readUint16BE() << 8; + if (saveVersion >= 9) { + saveTime |= in->readByte(); // add seconds (only available since saved game version 9+) + } // save date is DDMMYYYY, we need a proper format byte saveDateDay = saveDate >> 24; diff --git a/engines/agi/sound_2gs.cpp b/engines/agi/sound_2gs.cpp index b33591343a..b1bcee3920 100644 --- a/engines/agi/sound_2gs.cpp +++ b/engines/agi/sound_2gs.cpp @@ -482,6 +482,8 @@ static bool convertWave(Common::SeekableReadStream &source, int8 *dest, uint len IIgsSample::IIgsSample(uint8 *data, uint32 len, int16 resourceNr) : AgiSound() { Common::MemoryReadStream stream(data, len, DisposeAfterUse::YES); + _sample = nullptr; + // Check that the header was read ok and that it's of the correct type if (_header.read(stream) && _header.type == AGI_SOUND_SAMPLE) { // An Apple IIGS AGI sample resource uint32 sampleStartPos = stream.pos(); diff --git a/engines/agi/sprite.cpp b/engines/agi/sprite.cpp index 74f20c1d22..8263ea12ac 100644 --- a/engines/agi/sprite.cpp +++ b/engines/agi/sprite.cpp @@ -106,6 +106,28 @@ void SpritesMgr::buildSpriteListAdd(uint16 givenOrderNr, ScreenObjEntry *screenO spriteEntry.yPos = (screenObj->yPos) - (screenObj->ySize) + 1; spriteEntry.xSize = screenObj->xSize; spriteEntry.ySize = screenObj->ySize; + + // Checking, if xPos/yPos/right/bottom are valid and do not go outside of playscreen (visual screen) + // Original AGI did not do this (but it then resulted in memory corruption) + if (spriteEntry.xPos < 0) { + warning("buildSpriteListAdd(): ignoring screen obj %d, b/c xPos (%d) < 0", screenObj->objectNr, spriteEntry.xPos); + return; + } + if (spriteEntry.yPos < 0) { + warning("buildSpriteListAdd(): ignoring screen obj %d, b/c yPos (%d) < 0", screenObj->objectNr, spriteEntry.yPos); + return; + } + int16 xRight = spriteEntry.xPos + spriteEntry.xSize; + if (xRight > SCRIPT_HEIGHT) { + warning("buildSpriteListAdd(): ignoring screen obj %d, b/c rightPos (%d) > %d", screenObj->objectNr, xRight, SCRIPT_WIDTH); + return; + } + int16 yBottom = spriteEntry.yPos + spriteEntry.ySize; + if (yBottom > SCRIPT_HEIGHT) { + warning("buildSpriteListAdd(): ignoring screen obj %d, b/c bottomPos (%d) > %d", screenObj->objectNr, yBottom, SCRIPT_HEIGHT); + return; + } + // warning("list-add: %d, %d, original yPos: %d, ySize: %d", spriteEntry.xPos, spriteEntry.yPos, screenObj->yPos, screenObj->ySize); spriteEntry.backgroundBuffer = (uint8 *)malloc(spriteEntry.xSize * spriteEntry.ySize * 2); // for visual + priority data assert(spriteEntry.backgroundBuffer); @@ -332,7 +354,8 @@ void SpritesMgr::showSprite(ScreenObjEntry *screenObj) { } // render this block - _gfx->render_Block(x, y, width, height); + int16 upperY = y - height + 1; + _gfx->render_Block(x, upperY, width, height); } void SpritesMgr::showSprites(SpriteList &spriteList) { @@ -394,7 +417,7 @@ void SpritesMgr::showObject(int16 viewNr) { screenObj.yPos_prev = SCRIPT_HEIGHT - 1; screenObj.yPos = screenObj.yPos_prev; screenObj.priority = 15; - screenObj.flags |= fFixedPriority; + screenObj.flags = fFixedPriority; // Original AGI did "| fFixedPriority" on uninitialized memory screenObj.objectNr = 255; // ??? backgroundBuffer = (uint8 *)malloc(screenObj.xSize * screenObj.ySize * 2); // for visual + priority data diff --git a/engines/agi/systemui.cpp b/engines/agi/systemui.cpp index 2dd6629103..aeb1ded4a2 100644 --- a/engines/agi/systemui.cpp +++ b/engines/agi/systemui.cpp @@ -38,10 +38,14 @@ SystemUI::SystemUI(AgiEngine *vm, GfxMgr *gfx, TextMgr *text) { _askForVerificationMouseLockedButtonNr = -1; _askForVerificationMouseActiveButtonNr = -1; + clearSavedGameSlots(); + _textStatusScore = "Score:%v3 of %v7"; _textStatusSoundOn = "Sound:on"; _textStatusSoundOff = "Sound:off"; + _textEnterCommand = "Enter input\n\n"; + _textPause = " Game paused.\nPress Enter to continue."; _textPauseButton = nullptr; @@ -212,6 +216,47 @@ const char *SystemUI::getInventoryTextReturnToGame() { return _textInventoryReturnToGame; } +bool SystemUI::askForCommand(Common::String &commandText) { + // Let user enter the command (this was originally only available for Hercules rendering, we allow it everywhere) + bool previousEditState = _text->inputGetEditStatus(); + byte previousEditCursor = _text->inputGetCursorChar(); + + _text->drawMessageBox(_textEnterCommand, 0, 36, true); + + _text->inputEditOn(); + + _text->charPos_Push(); + _text->charAttrib_Push(); + + _text->charPos_SetInsideWindow(2, 0); + _text->charAttrib_Set(15, 0); + _text->clearBlockInsideWindow(2, 0, 36, 0); // input line is supposed to be black + _text->inputSetCursorChar('_'); + + _text->stringSet(commandText.c_str()); // Set current command text (may be a command recall) + + _vm->cycleInnerLoopActive(CYCLE_INNERLOOP_GETSTRING); + _text->stringEdit(35); // only allow up to 35 characters + + _text->charAttrib_Pop(); + _text->charPos_Pop(); + _text->inputSetCursorChar(previousEditCursor); + if (!previousEditState) { + _text->inputEditOff(); + } + + _text->closeWindow(); + + if (!_text->stringWasEntered()) { + // User cancelled? exit now + return false; + } + + commandText.clear(); + commandText += (char *)_text->_inputString; + return true; +} + int16 SystemUI::figureOutAutomaticSaveGameSlot(const char *automaticSaveDescription) { int16 matchedGameSlotId = -1; int16 freshGameSlotId = -1; @@ -327,7 +372,7 @@ int16 SystemUI::askForRestoreGameSlot() { int16 restoreGameSlotNr = -1; // Fill saved game slot cache - readSavedGameSlots(true, true); // filter empty/corrupt slots, but including auto-save slot + readSavedGameSlots(true, true); // filter empty/corrupt slots, but include auto-save slot if (_savedGameArray.size() == 0) { // no saved games @@ -526,12 +571,12 @@ void SystemUI::readSavedGameSlots(bool filterNonexistant, bool withAutoSaveSlot) SystemUISavedGameEntry savedGameEntry; Common::String saveDescription; uint32 saveDate = 0; - uint16 saveTime = 0; + uint32 saveTime = 0; bool saveIsValid = false; int16 mostRecentSlotNr = -1; uint32 mostRecentSlotSaveDate = 0; - uint16 mostRecentSlotSaveTime = 0; + uint32 mostRecentSlotSaveTime = 0; clearSavedGameSlots(); @@ -638,6 +683,9 @@ void SystemUI::readSavedGameSlots(bool filterNonexistant, bool withAutoSaveSlot) void SystemUI::figureOutAutomaticSavedGameSlot(const char *automaticSaveDescription, int16 &matchedGameSlotId, int16 &freshGameSlotId) { bool foundFresh = false; + matchedGameSlotId = -1; + freshGameSlotId = -1; + for (uint16 slotNr = 0; slotNr < _savedGameArray.size(); slotNr++) { SystemUISavedGameEntry *savedGameEntry = &_savedGameArray[slotNr]; @@ -653,7 +701,7 @@ void SystemUI::figureOutAutomaticSavedGameSlot(const char *automaticSaveDescript // no new slot found yet if (!savedGameEntry->exists) { // and current slot doesn't exist - if (slotNr) { + if (savedGameEntry->slotId) { // and slot is not the auto-save slot -> remember this slot freshGameSlotId = savedGameEntry->slotId; foundFresh = true; @@ -746,21 +794,23 @@ bool SystemUI::askForVerification(const char *verifyText, const char *button1Tex // Buttons enabled, calculate button coordinates int16 msgBoxX = 0, msgBoxY = 0, msgBoxLowerY = 0; int16 msgBoxWidth = 0, msgBoxHeight = 0; + int16 fontHeight = _gfx->getDisplayFontHeight(); + int16 fontWidth = _gfx->getDisplayFontWidth(); _text->getMessageBoxInnerDisplayDimensions(msgBoxX, msgBoxY, msgBoxWidth, msgBoxHeight); - // Adjust Y coordinate to lower edge + // Calculate lower Y msgBoxLowerY = msgBoxY + (msgBoxHeight - 1); buttonEntry.active = false; if (button1Text) { buttonEntry.text = button1Text; - buttonEntry.textWidth = strlen(button1Text) * FONT_DISPLAY_WIDTH; + buttonEntry.textWidth = strlen(button1Text) * _gfx->getDisplayFontWidth(); buttonEntry.isDefault = true; _buttonArray.push_back(buttonEntry); } if (button2Text) { buttonEntry.text = button2Text; - buttonEntry.textWidth = strlen(button2Text) * FONT_DISPLAY_WIDTH; + buttonEntry.textWidth = strlen(button2Text) * _gfx->getDisplayFontWidth(); buttonEntry.isDefault = false; _buttonArray.push_back(buttonEntry); } @@ -768,37 +818,30 @@ bool SystemUI::askForVerification(const char *verifyText, const char *button1Tex // Render-Mode specific calculations switch (_vm->_renderMode) { case Common::kRenderApple2GS: - _buttonArray[0].rect = Common::Rect(14 + _buttonArray[0].textWidth, FONT_DISPLAY_HEIGHT + 6); - _buttonArray[0].rect.moveTo(msgBoxX + 2, msgBoxLowerY - (8 + FONT_DISPLAY_HEIGHT + 2)); - + _buttonArray[0].rect = createRect(msgBoxX, +2, msgBoxLowerY - fontHeight, -(8 + 2), _buttonArray[0].textWidth, +14, fontHeight, +6); + if (_buttonArray.size() > 1) { - int16 adjustedX = msgBoxX + msgBoxWidth - 10; - _buttonArray[1].rect = Common::Rect(14 + _buttonArray[1].textWidth, FONT_DISPLAY_HEIGHT + 6); - adjustedX -= _buttonArray[1].rect.width(); - _buttonArray[1].rect.moveTo(adjustedX, msgBoxLowerY - (8 + FONT_DISPLAY_HEIGHT + 2)); + int16 adjustedX = msgBoxX + msgBoxWidth - _buttonArray[1].textWidth; // - 10; + _buttonArray[1].rect = createRect(adjustedX, -(14 + 10), _buttonArray[0].rect.top, 0, _buttonArray[1].textWidth, +14, fontHeight, +6); } break; - case Common::kRenderAmiga: - _buttonArray[0].rect = Common::Rect(4 + _buttonArray[0].textWidth + 4, 2 + FONT_DISPLAY_HEIGHT + 2); - _buttonArray[0].rect.moveTo(msgBoxX, msgBoxLowerY - _buttonArray[0].rect.height()); + case Common::kRenderAmiga: { + _buttonArray[0].rect = createRect(msgBoxX, 0, msgBoxLowerY - fontHeight, -(2 + 2), _buttonArray[0].textWidth, +(4 + 4), fontHeight, +(2 + 2)); if (_buttonArray.size() > 1) { - int16 adjustedX = msgBoxX + msgBoxWidth; - _buttonArray[1].rect = Common::Rect(4 + _buttonArray[1].textWidth + 4, 2 + FONT_DISPLAY_HEIGHT + 2); - adjustedX -= _buttonArray[1].rect.width(); - _buttonArray[1].rect.moveTo(adjustedX, msgBoxLowerY - _buttonArray[1].rect.height()); + int16 adjustedX = msgBoxX + msgBoxWidth - _buttonArray[1].textWidth; + _buttonArray[1].rect = createRect(adjustedX, -(4 + 4), _buttonArray[0].rect.top, 0, _buttonArray[1].textWidth, +(4 + 4), fontHeight, +(2 + 2)); } break; + } case Common::kRenderAtariST: - _buttonArray[0].rect = Common::Rect(_buttonArray[0].textWidth, FONT_DISPLAY_HEIGHT); - _buttonArray[0].rect.moveTo(msgBoxX + (5 * FONT_DISPLAY_WIDTH), msgBoxLowerY - FONT_DISPLAY_HEIGHT); + _buttonArray[0].rect = createRect(msgBoxX + (5 * fontWidth), 0, msgBoxLowerY - fontHeight, 0, _buttonArray[0].textWidth, 0, fontHeight, 0); + if (_buttonArray.size() > 1) { - int16 adjustedX = msgBoxX + msgBoxWidth - (5 * FONT_DISPLAY_WIDTH); - _buttonArray[1].rect = Common::Rect(_buttonArray[1].textWidth, FONT_DISPLAY_HEIGHT); - adjustedX -= _buttonArray[1].rect.width(); - _buttonArray[1].rect.moveTo(adjustedX, msgBoxLowerY - _buttonArray[1].rect.height()); + int16 adjustedX = msgBoxX + msgBoxWidth - (5 * fontWidth + _buttonArray[1].textWidth); + _buttonArray[1].rect = createRect(adjustedX, 0, _buttonArray[0].rect.top, 0, _buttonArray[1].textWidth, 0, fontHeight, 0); } break; @@ -946,6 +989,25 @@ void SystemUI::askForVerificationKeyPress(uint16 newKey) { } } +Common::Rect SystemUI::createRect(int16 x, int16 adjX, int16 y, int16 adjY, int16 width, int16 adjWidth, int16 height, int16 adjHeight) { + switch (_gfx->getUpscaledHires()) { + case DISPLAY_UPSCALED_DISABLED: + break; + case DISPLAY_UPSCALED_640x400: + adjX *= 2; adjY *= 2; + adjWidth *= 2; adjHeight *= 2; + break; + default: + assert(0); + break; + } + x += adjX; y += adjY; + width += adjWidth; height += adjHeight; + Common::Rect newRect(width, height); + newRect.moveTo(x, y); + return newRect; +} + #define SYSTEMUI_BUTTONEDGE_APPLEIIGS_WIDTH 8 #define SYSTEMUI_BUTTONEDGE_APPLEIIGS_HEIGHT 5 @@ -993,20 +1055,20 @@ void SystemUI::drawButtonAppleIIgs(SystemUIButtonEntry *button) { } // draw base box for it - _gfx->drawDisplayRect(button->rect.left, button->rect.bottom - 1, button->rect.width(), button->rect.height(), backgroundColor, false); + _gfx->drawDisplayRect(button->rect.left, button->rect.top, button->rect.width(), button->rect.height(), backgroundColor, false); // draw inner lines - _gfx->drawDisplayRect(button->rect.left + 1, button->rect.top - 1, button->rect.width() - 2, 1, 0, false); // upper horizontal - _gfx->drawDisplayRect(button->rect.left - 2, button->rect.bottom - 2, 2, button->rect.height() - 2, 0, false); // left vertical - _gfx->drawDisplayRect(button->rect.right, button->rect.bottom - 2, 2, button->rect.height() - 2, 0, false); // right vertical - _gfx->drawDisplayRect(button->rect.left + 1, button->rect.bottom, button->rect.width() - 2, 1, 0, false); // lower horizontal + _gfx->drawDisplayRect(button->rect.left, +1, button->rect.top, -1, button->rect.width(), -2, 0, 1, 0, false); // lower horizontal + _gfx->drawDisplayRect(button->rect.left, -2, button->rect.top, +1, 0, 2, button->rect.height(), -2, 0, false); // left vertical + _gfx->drawDisplayRect(button->rect.right, 0, button->rect.top, +1, 0, 2, button->rect.height(), -2, 0, false); // right vertical + _gfx->drawDisplayRect(button->rect.left, +1, button->rect.bottom, 0, button->rect.width(), -2, 0, 1, 0, false); // upper horizontal if (button->isDefault) { // draw outer lines - _gfx->drawDisplayRect(button->rect.left, button->rect.top - 3, button->rect.width(), 1, 0, false); // upper horizontal - _gfx->drawDisplayRect(button->rect.left - 5, button->rect.bottom - 2, 2, button->rect.height() - 2, 0, false); // left vertical - _gfx->drawDisplayRect(button->rect.right + 3, button->rect.bottom - 2, 2, button->rect.height() - 2, 0, false); // right vertical - _gfx->drawDisplayRect(button->rect.left, button->rect.bottom + 2, button->rect.width(), 1, 0, false); // lower horizontal + _gfx->drawDisplayRect(button->rect.left, 0, button->rect.top, -3, button->rect.width(), 0, 0, 1, 0, false); // upper horizontal + _gfx->drawDisplayRect(button->rect.left, -5, button->rect.top, +2, 0, 2, button->rect.height(), -2, 0, false); // left vertical + _gfx->drawDisplayRect(button->rect.right, +3, button->rect.top, +2, 0, 2, button->rect.height(), -2, 0, false); // right vertical + _gfx->drawDisplayRect(button->rect.left, 0, button->rect.bottom, +2, button->rect.width(), 0, 0, 1, 0, false); // lower horizontal if (button->active) edgeBitmap = buttonEdgeAppleIIgsDefaultActive; @@ -1021,18 +1083,18 @@ void SystemUI::drawButtonAppleIIgs(SystemUIButtonEntry *button) { } // draw edge graphics - drawButtonAppleIIgsEdgePixels(button->rect.left - 5, button->rect.top - 3, edgeBitmap, false, false); - drawButtonAppleIIgsEdgePixels(button->rect.right + 4, button->rect.top - 3, edgeBitmap, true, false); - drawButtonAppleIIgsEdgePixels(button->rect.left - 5, button->rect.bottom + 2, edgeBitmap, false, true); - drawButtonAppleIIgsEdgePixels(button->rect.right + 4, button->rect.bottom + 2, edgeBitmap, true, true); + drawButtonAppleIIgsEdgePixels(button->rect.left, -5, button->rect.top, -3, edgeBitmap, false, false); + drawButtonAppleIIgsEdgePixels(button->rect.right, +4, button->rect.top, -3, edgeBitmap, true, false); + drawButtonAppleIIgsEdgePixels(button->rect.left, -5, button->rect.bottom, +2, edgeBitmap, false, true); + drawButtonAppleIIgsEdgePixels(button->rect.right, +4, button->rect.bottom, +2, edgeBitmap, true, true); // Button text - _gfx->drawStringOnDisplay(button->rect.left + 7, button->rect.top + 3, button->text, foregroundColor, backgroundColor); + _gfx->drawStringOnDisplay(button->rect.left, +7, button->rect.top, +3, button->text, foregroundColor, backgroundColor); - _gfx->copyDisplayRectToScreen(button->rect.left - 5, button->rect.top - 3, button->rect.width() + 10, button->rect.height() + 6); + _gfx->copyDisplayRectToScreen(button->rect.left, -5, button->rect.top, -3, button->rect.width(), +10, button->rect.height(), +6); } -void SystemUI::drawButtonAppleIIgsEdgePixels(int16 x, int16 y, byte *edgeBitmap, bool mirrored, bool upsideDown) { +void SystemUI::drawButtonAppleIIgsEdgePixels(int16 x, int16 adjX, int16 y, int16 adjY, byte *edgeBitmap, bool mirrored, bool upsideDown) { int8 directionY = upsideDown ? -1 : +1; int8 directionX = mirrored ? -1 : +1; int8 curY = 0; @@ -1050,9 +1112,9 @@ void SystemUI::drawButtonAppleIIgsEdgePixels(int16 x, int16 y, byte *edgeBitmap, while (widthLeft) { if (curBitmapByte & curBitmapBit) { - _gfx->putPixelOnDisplay(x + curX, y + curY, 0); + _gfx->putPixelOnDisplay(x, adjX + curX, y, adjY + curY, 0); } else { - _gfx->putPixelOnDisplay(x + curX, y + curY, 15); + _gfx->putPixelOnDisplay(x, adjX + curX, y, adjY + curY, 15); } curBitmapBit = curBitmapBit >> 1; @@ -1087,12 +1149,11 @@ void SystemUI::drawButtonAmiga(SystemUIButtonEntry *button) { } // draw base box for it - _gfx->drawDisplayRect(button->rect.left, button->rect.bottom - 1, button->rect.width(), button->rect.height(), backgroundColor, false); + _gfx->drawDisplayRect(button->rect.left, button->rect.top, button->rect.width(), button->rect.height(), backgroundColor, false); // Button text - _gfx->drawStringOnDisplay(button->rect.left + 4, button->rect.top + 2, button->text, foregroundColor, backgroundColor); + _gfx->drawStringOnDisplay(button->rect.left, +4, button->rect.top, +2, button->text, foregroundColor, backgroundColor); - // draw base box for it _gfx->copyDisplayRectToScreen(button->rect.left, button->rect.top, button->rect.width(), button->rect.height()); } diff --git a/engines/agi/systemui.h b/engines/agi/systemui.h index ceb78935eb..283de8794c 100644 --- a/engines/agi/systemui.h +++ b/engines/agi/systemui.h @@ -77,6 +77,8 @@ public: const char *getInventoryTextSelectItems(); const char *getInventoryTextReturnToGame(); + bool askForCommand(Common::String &commandText); + int16 figureOutAutomaticSaveGameSlot(const char *automaticSaveDescription); int16 figureOutAutomaticRestoreGameSlot(const char *automaticSaveDescription); @@ -107,9 +109,12 @@ private: private: SystemUIButtonArray _buttonArray; + Common::Rect createRect(int16 x, int16 adjX, int16 y, int16 adjY, int16 width, int16 adjWidth, int16 height, int16 adjHeight); + //void moveRect(int16 x, int16 adjX, int16 y, int16 adjY); + void drawButton(SystemUIButtonEntry *button); void drawButtonAppleIIgs(SystemUIButtonEntry *buttonEntry); - void drawButtonAppleIIgsEdgePixels(int16 x, int16 y, byte *edgeBitmap, bool mirrored, bool upsideDown); + void drawButtonAppleIIgsEdgePixels(int16 x, int16 adjX, int16 y, int16 adjY, byte *edgeBitmap, bool mirrored, bool upsideDown); void drawButtonAmiga(SystemUIButtonEntry *buttonEntry); void drawButtonAtariST(SystemUIButtonEntry *buttonEntry); @@ -127,6 +132,8 @@ private: const char *_textStatusSoundOn; const char *_textStatusSoundOff; + const char *_textEnterCommand; + const char *_textPause; const char *_textPauseButton; const char *_textRestart; diff --git a/engines/agi/text.cpp b/engines/agi/text.cpp index 965de69335..0cacce2421 100644 --- a/engines/agi/text.cpp +++ b/engines/agi/text.cpp @@ -20,6 +20,7 @@ * */ +#include "common/config-manager.h" #include "agi/agi.h" #include "agi/sprite.h" // for commit_both() #include "agi/graphics.h" @@ -66,6 +67,7 @@ TextMgr::TextMgr(AgiEngine *vm, Words *words, GfxMgr *gfx) { _inputStringRow = 0; _inputStringColumn = 0; + _inputStringEntered = false; _inputStringMaxLen = 0; _inputStringCursorPos = 0; _inputString[0] = 0; @@ -73,6 +75,12 @@ TextMgr::TextMgr(AgiEngine *vm, Words *words, GfxMgr *gfx) { configureScreen(2); _messageBoxCancelled = false; + + _optionCommandPromptWindow = false; + + if (ConfMan.getBool("commandpromptwindow")) { + _optionCommandPromptWindow = true; + } } TextMgr::~TextMgr() { @@ -87,7 +95,7 @@ void TextMgr::configureScreen(uint16 row_Min) { _window_Row_Max = row_Min + 21; // forward data to GfxMgr as well - _gfx->setRenderStartOffset(row_Min * FONT_DISPLAY_HEIGHT); + _gfx->setRenderStartOffset(row_Min * FONT_VISUAL_HEIGHT); } uint16 TextMgr::getWindowRowMin() { return _window_Row_Min; @@ -169,7 +177,7 @@ void TextMgr::charAttrib_Set(byte foreground, byte background) { if (background) { _textAttrib.combinedForeground = 3; _textAttrib.combinedBackground = 8; // enable invert of colors - } else if (foreground > 14) { + } else { if (foreground > 14) { _textAttrib.combinedForeground = 3; } else { @@ -178,6 +186,16 @@ void TextMgr::charAttrib_Set(byte foreground, byte background) { _textAttrib.combinedBackground = 0; } break; + case Common::kRenderHercA: + case Common::kRenderHercG: + if (background) { + _textAttrib.combinedForeground = 0; + _textAttrib.combinedBackground = 1; + } else { + _textAttrib.combinedForeground = 1; + _textAttrib.combinedBackground = 0; + } + break; default: // EGA-handling: if (background) { @@ -465,7 +483,8 @@ void TextMgr::drawMessageBox(const char *textPtr, int16 forcedHeight, int16 want _messageState.backgroundSize_Width = (_messageState.textSize_Width * FONT_VISUAL_WIDTH) + 10; _messageState.backgroundSize_Height = (_messageState.textSize_Height * FONT_VISUAL_HEIGHT) + 10; _messageState.backgroundPos_x = (_messageState.textPos.column * FONT_VISUAL_WIDTH) - 5; - _messageState.backgroundPos_y = (_messageState.textPos_Edge.row - _window_Row_Min + 1) * FONT_VISUAL_HEIGHT + 4; + _messageState.backgroundPos_y = (startingRow * FONT_VISUAL_HEIGHT) - 5; + // original AGI used lowerY here, calculated using (_messageState.textPos_Edge.row - _window_Row_Min + 1) * FONT_VISUAL_HEIGHT + 4; // Hardcoded colors: white background and red lines _gfx->drawBox(_messageState.backgroundPos_x, _messageState.backgroundPos_y, _messageState.backgroundSize_Width, _messageState.backgroundSize_Height, 15, 4); @@ -486,10 +505,11 @@ void TextMgr::getMessageBoxInnerDisplayDimensions(int16 &x, int16 &y, int16 &wid if (!_messageState.window_Active) return; - y = _messageState.textPos.row * FONT_DISPLAY_HEIGHT; - x = _messageState.textPos.column * FONT_DISPLAY_WIDTH; - width = _messageState.textSize_Width * FONT_DISPLAY_WIDTH; - height = _messageState.textSize_Height * FONT_DISPLAY_HEIGHT; + y = _messageState.textPos.row; + x = _messageState.textPos.column; + width = _messageState.textSize_Width; + height = _messageState.textSize_Height; + _gfx->translateFontRectToDisplayScreen(x, y, width, height); } bool TextMgr::isMouseWithinMessageBox() { @@ -498,10 +518,10 @@ bool TextMgr::isMouseWithinMessageBox() { int16 mouseX = _vm->_mouse.pos.x; if (_messageState.window_Active) { - _vm->adjustPosToGameScreen(mouseX, mouseY); + _gfx->translateDisplayPosToGameScreen(mouseX, mouseY); - if ((mouseX >= _messageState.backgroundPos_x) && (mouseX <= (_messageState.backgroundPos_x + _messageState.backgroundSize_Width))) { - if ((mouseY >= _messageState.backgroundPos_y - _messageState.backgroundSize_Height) && (mouseY <= (_messageState.backgroundPos_y))) { + if ((mouseX >= _messageState.backgroundPos_x) && (mouseX < (_messageState.backgroundPos_x + _messageState.backgroundSize_Width))) { + if ((mouseY >= _messageState.backgroundPos_y) && (mouseY < (_messageState.backgroundPos_y + _messageState.backgroundSize_Height))) { return true; } } @@ -580,12 +600,12 @@ void TextMgr::clearBlock(int16 row_Upper, int16 column_Upper, int16 row_Lower, i charPos_Clip(row_Upper, column_Upper); charPos_Clip(row_Lower, column_Lower); - int16 x = column_Upper * FONT_DISPLAY_WIDTH; - int16 y = row_Upper * FONT_DISPLAY_HEIGHT; - int16 width = (column_Lower + 1 - column_Upper) * FONT_DISPLAY_WIDTH; - int16 height = (row_Lower + 1 - row_Upper) * FONT_DISPLAY_HEIGHT; + int16 x = column_Upper; + int16 y = row_Upper; + int16 width = (column_Lower + 1 - column_Upper); + int16 height = (row_Lower + 1 - row_Upper); + _gfx->translateFontRectToDisplayScreen(x, y, width, height); - y = y + height - 1; // drawDisplayRect wants lower Y-coordinate _gfx->drawDisplayRect(x, y, width, height, color); } @@ -658,6 +678,30 @@ void TextMgr::promptKeyPress(uint16 newKey) { int16 maxChars = 0; int16 scriptsInputLen = _vm->getVar(VM_VAR_MAX_INPUT_CHARACTERS); + bool acceptableInput = false; + + // FEATURE: Sierra didn't check for valid characters (filtered out umlauts etc.) + // In text-mode this sort of worked at least with the DOS interpreter + // but as soon as invalid characters were used in graphics mode they weren't properly shown + switch (_vm->getLanguage()) { + case Common::RU_RUS: + if (newKey >= 0x20) + acceptableInput = true; + break; + default: + if ((newKey >= 0x20) && (newKey <= 0x7f)) + acceptableInput = true; + break; + } + + if (_optionCommandPromptWindow) { + // Forward to command prompt window, using last command + if (acceptableInput) { + promptCommandWindow(false, newKey); + } + return; + } + if (_messageState.dialogue_Open) { maxChars = TEXT_STRING_MAX_SIZE - 4; } else { @@ -702,22 +746,6 @@ void TextMgr::promptKeyPress(uint16 newKey) { } default: if (maxChars > _promptCursorPos) { - bool acceptableInput = false; - - // FEATURE: Sierra didn't check for valid characters (filtered out umlauts etc.) - // In text-mode this sort of worked at least with the DOS interpreter - // but as soon as invalid characters were used in graphics mode they weren't properly shown - switch (_vm->getLanguage()) { - case Common::RU_RUS: - if (newKey >= 0x20) - acceptableInput = true; - break; - default: - if ((newKey >= 0x20) && (newKey <= 0x7f)) - acceptableInput = true; - break; - } - if (acceptableInput) { _prompt[_promptCursorPos] = newKey; _promptCursorPos++; @@ -734,6 +762,11 @@ void TextMgr::promptKeyPress(uint16 newKey) { } void TextMgr::promptCancelLine() { + if (_optionCommandPromptWindow) { + // Abort, in case command prompt window is active + return; + } + while (_promptCursorPos) { promptKeyPress(0x08); // Backspace until prompt is empty } @@ -742,6 +775,12 @@ void TextMgr::promptCancelLine() { void TextMgr::promptEchoLine() { int16 previousLen = strlen((char *)_promptPrevious); + if (_optionCommandPromptWindow) { + // Forward to command prompt window, using last command + promptCommandWindow(true, 0); + return; + } + if (_promptCursorPos < previousLen) { inputEditOn(); @@ -758,6 +797,11 @@ void TextMgr::promptRedraw() { char *textPtr = nullptr; if (_promptEnabled) { + if (_optionCommandPromptWindow) { + // Abort, in case command prompt window is active + return; + } + inputEditOn(); clearLine(_promptRow, _textAttrib.background); charPos_Set(_promptRow, 0); @@ -775,6 +819,10 @@ void TextMgr::promptRedraw() { // for AGI1 void TextMgr::promptClear() { + if (_optionCommandPromptWindow) { + // Abort, in case command prompt window is active + return; + } clearLine(_promptRow, _textAttrib.background); } @@ -784,6 +832,35 @@ void TextMgr::promptRememberForAutoComplete(bool entered) { #endif } +void TextMgr::promptCommandWindow(bool recallLastCommand, uint16 newKey) { + Common::String commandText; + + if (recallLastCommand) { + commandText += Common::String((char *)_promptPrevious); + } + if (newKey) { + if (newKey != ' ') { + // Only add char, when it's not a space. + // Original AGI did not filter space, but it makes no sense to start with a space. + // Space would get filtered anyway during dictionary parsing. + commandText += newKey; + } + } + + if (_systemUI->askForCommand(commandText)) { + if (commandText.size()) { + // Something actually was entered? + strncpy((char *)&_prompt, commandText.c_str(), sizeof(_prompt)); + promptRememberForAutoComplete(true); + memcpy(&_promptPrevious, &_prompt, sizeof(_prompt)); + // parse text + _vm->_words->parseUsingDictionary((char *)&_prompt); + + _prompt[0] = 0; + } + } +} + bool TextMgr::stringWasEntered() { return _inputStringEntered; } @@ -941,8 +1018,18 @@ char *TextMgr::stringWordWrap(const char *originalText, int16 maxWidth, int16 *c //memset(resultWrappedBuffer, 0, sizeof(resultWrappedBuffer)); for debugging + // Good testcases: + // King's Quest 1 intro: the scrolling text is filled up with spaces, so that old lines are erased + // Apple IIgs restart system UI: spaces used to make the window larger + // Gold Rush Stagecoach path room 60: " Lake Michigan!", with max length 9 -> should get split into " Lake" / "Michigan!" + while (originalText[curReadPos]) { // Try to find out length of next word + + // If first character is a space, skip it, so that we process at least this space + if (originalText[curReadPos] == ' ') + curReadPos++; + while (originalText[curReadPos]) { if (originalText[curReadPos] == ' ') break; @@ -957,6 +1044,15 @@ char *TextMgr::stringWordWrap(const char *originalText, int16 maxWidth, int16 *c if (wordLen >= lineWidthLeft) { // Not enough space left + + // If first character right after the new line is a space, skip over it + if (wordLen) { + if (originalText[wordStartPos] == ' ') { + wordStartPos++; + wordLen--; + } + } + if (wordLen > maxWidth) { // Word way too long, split it in half curReadPos = curReadPos - (wordLen - maxWidth); @@ -973,14 +1069,6 @@ char *TextMgr::stringWordWrap(const char *originalText, int16 maxWidth, int16 *c // Reached absolute maximum? -> exit now if (boxHeight >= HEIGHT_MAX) break; - - // If first character right after the new line is a space, skip over it - if (wordLen) { - if (originalText[wordStartPos] == ' ') { - wordStartPos++; - wordLen--; - } - } } // Copy current word over @@ -1005,10 +1093,6 @@ char *TextMgr::stringWordWrap(const char *originalText, int16 maxWidth, int16 *c } wordStartPos = curReadPos; - - // Last word ended with a space, skip this space for reading the next word - if (wordEndChar == ' ') - curReadPos++; } resultWrappedBuffer[curWritePos] = 0; diff --git a/engines/agi/text.h b/engines/agi/text.h index 72d012b917..f0aeab7762 100644 --- a/engines/agi/text.h +++ b/engines/agi/text.h @@ -55,7 +55,7 @@ struct MessageState_Struct { uint16 printed_Height; int16 backgroundPos_x; - int16 backgroundPos_y; + int16 backgroundPos_y; // original AGI used lowerY here, we use upperY so that upscaling is easier int16 backgroundSize_Width; int16 backgroundSize_Height; }; @@ -163,6 +163,8 @@ public: bool _inputEditEnabled; byte _inputCursorChar; + bool _optionCommandPromptWindow; + bool _promptEnabled; int16 _promptRow; int16 _promptCursorPos; @@ -189,6 +191,8 @@ public: void promptClear(); // for AGI1 void promptRememberForAutoComplete(bool entered = false); // for auto-completion + void promptCommandWindow(bool recallLastCommand, uint16 newKey); + int16 _inputStringRow; int16 _inputStringColumn; bool _inputStringEntered; diff --git a/engines/agi/view.cpp b/engines/agi/view.cpp index ac3e60ee6d..a13e40e60d 100644 --- a/engines/agi/view.cpp +++ b/engines/agi/view.cpp @@ -111,7 +111,6 @@ int AgiEngine::decodeView(byte *resourceData, uint16 resourceSize, int16 viewNr) byte *celCompressedData = nullptr; uint16 celCompressedSize = 0; -// byte *rawBitmap = nullptr; debugC(5, kDebugLevelResources, "decode_view(%d)", viewNr); @@ -431,14 +430,28 @@ void AgiEngine::unloadView(int16 viewNr) { * @param viewNr number of AGI view resource */ void AgiEngine::setView(ScreenObjEntry *screenObj, int16 viewNr) { - screenObj->viewData = &_game.views[viewNr]; + if (!(_game.dirView[viewNr].flags & RES_LOADED)) { + // View resource currently not loaded, this is probably a game bug + // Load the resource now to fix the issue, and give out a warning + // This happens in at least Larry 1 for Apple IIgs right after getting beaten up by taxi driver + // Original interpreter bombs out in this situation saying "view not loaded, Press ESC to quit" + warning("setView() called on screen object %d to use view %d, but view not loaded", screenObj->objectNr, viewNr); + warning("probably game script bug, trying to load view into memory"); + if (agiLoadResource(RESOURCETYPE_VIEW, viewNr) != errOK) { + // loading failed, we better error() out now + error("setView() called to set view %d for screen object %d, which is not loaded atm and loading failed", viewNr, screenObj->objectNr); + return; + }; + } + + screenObj->viewResource = &_game.views[viewNr]; screenObj->currentViewNr = viewNr; - screenObj->loopCount = screenObj->viewData->loopCount; + screenObj->loopCount = screenObj->viewResource->loopCount; screenObj->viewReplaced = true; if (getVersion() < 0x2000) { - screenObj->stepSize = screenObj->viewData->headerStepSize; - screenObj->cycleTime = screenObj->viewData->headerCycleTime; + screenObj->stepSize = screenObj->viewResource->headerStepSize; + screenObj->cycleTime = screenObj->viewResource->headerCycleTime; screenObj->cycleTimeCount = 0; } if (screenObj->currentLoopNr >= screenObj->loopCount) { @@ -454,7 +467,11 @@ void AgiEngine::setView(ScreenObjEntry *screenObj, int16 viewNr) { * @param loopNr number of loop */ void AgiEngine::setLoop(ScreenObjEntry *screenObj, int16 loopNr) { - assert(screenObj->viewData != NULL); + if (!(_game.dirView[screenObj->currentViewNr].flags & RES_LOADED)) { + error("setLoop() called on screen object %d, which has no loaded view resource assigned to it", screenObj->objectNr); + return; + } + assert(screenObj->viewResource); if (screenObj->loopCount == 0) { warning("setLoop() called on screen object %d, which has no loops (view %d)", screenObj->objectNr, screenObj->currentViewNr); @@ -465,7 +482,11 @@ void AgiEngine::setLoop(ScreenObjEntry *screenObj, int16 loopNr) { // requested loop not existant // instead of error()ing out, we instead clip it // At least required for possibly Manhunter 1 according to previous comment when leaving the arcade machine - // TODO: check MH1 + // TODO: Check MH1 + // TODO: This causes an issue in KQ1, when bowing to the king in room 53 + // Ego will face away from the king, because the scripts set the loop first and then the view + // Loop is corrected by us, because at that time it's invalid. Was already present in 1.7.0 + // We should probably script-patch it out. int16 requestedLoopNr = loopNr; loopNr = screenObj->loopCount - 1; @@ -493,7 +514,16 @@ void AgiEngine::setLoop(ScreenObjEntry *screenObj, int16 loopNr) { * @param celNr number of cel */ void AgiEngine::setCel(ScreenObjEntry *screenObj, int16 celNr) { - assert(screenObj->viewData != NULL); + if (!(_game.dirView[screenObj->currentViewNr].flags & RES_LOADED)) { + error("setCel() called on screen object %d, which has no loaded view resource assigned to it", screenObj->objectNr); + return; + } + assert(screenObj->viewResource); + + if (screenObj->loopCount == 0) { + warning("setLoop() called on screen object %d, which has no loops (view %d)", screenObj->objectNr, screenObj->currentViewNr); + return; + } AgiViewLoop *curViewLoop = &_game.views[screenObj->currentViewNr].loop[screenObj->currentLoopNr]; diff --git a/engines/agi/view.h b/engines/agi/view.h index 04021260a3..e59916da78 100644 --- a/engines/agi/view.h +++ b/engines/agi/view.h @@ -47,10 +47,6 @@ struct AgiView { byte *description; int16 loopCount; AgiViewLoop *loop; - - //struct ViewLoop *loop; - //bool agi256_2; - //byte *resourceData; }; enum MotionType { @@ -98,7 +94,7 @@ struct ScreenObjEntry { int16 yPos; uint8 currentViewNr; bool viewReplaced; - struct AgiView *viewData; + struct AgiView *viewResource; uint8 currentLoopNr; uint8 loopCount; struct AgiViewLoop *loopData; diff --git a/engines/agi/words.cpp b/engines/agi/words.cpp index 32fa4cbff4..7072f003c2 100644 --- a/engines/agi/words.cpp +++ b/engines/agi/words.cpp @@ -293,7 +293,7 @@ int16 Words::findWordInDictionary(const Common::String &userInputLowcased, uint1 return wordId; } -void Words::parseUsingDictionary(char *rawUserInput) { +void Words::parseUsingDictionary(const char *rawUserInput) { Common::String userInput; Common::String userInputLowcased; const char *userInputPtr = nullptr; diff --git a/engines/agi/words.h b/engines/agi/words.h index c7bf4829c3..96dafae275 100644 --- a/engines/agi/words.h +++ b/engines/agi/words.h @@ -57,7 +57,7 @@ public: void unloadDictionary(); void clearEgoWords(); - void parseUsingDictionary(char *rawUserInput); + void parseUsingDictionary(const char *rawUserInput); private: void cleanUpInput(const char *userInput, Common::String &cleanInput); diff --git a/engines/agos/configure.engine b/engines/agos/configure.engine index 3ae1fb16f2..cd7fcf9d78 100644 --- a/engines/agos/configure.engine +++ b/engines/agos/configure.engine @@ -1,4 +1,4 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] add_engine agos "AGOS" yes "agos2" "AGOS 1 games" -add_engine agos2 "AGOS 2 games" yes +add_engine agos2 "AGOS 2 games" yes "" "" "highres" diff --git a/engines/agos/detection.cpp b/engines/agos/detection.cpp index 94446159b9..2c89522089 100644 --- a/engines/agos/detection.cpp +++ b/engines/agos/detection.cpp @@ -94,13 +94,13 @@ using namespace AGOS; class AgosMetaEngine : public AdvancedMetaEngine { public: AgosMetaEngine() : AdvancedMetaEngine(AGOS::gameDescriptions, sizeof(AGOS::AGOSGameDescription), agosGames) { - _guioptions = GUIO1(GUIO_NOLAUNCHLOAD); + _guiOptions = GUIO1(GUIO_NOLAUNCHLOAD); _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } - virtual GameDescriptor findGame(const char *gameid) const { - return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable); + virtual GameDescriptor findGame(const char *gameId) const { + return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable); } virtual const char *getName() const { @@ -186,7 +186,6 @@ SaveStateList AgosMetaEngine::listSaves(const char *target) const { pattern += ".###"; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -203,6 +202,8 @@ SaveStateList AgosMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/agos/sound.cpp b/engines/agos/sound.cpp index 762f60bd91..13b5bf761c 100644 --- a/engines/agos/sound.cpp +++ b/engines/agos/sound.cpp @@ -217,7 +217,7 @@ static void convertVolume(int &vol) { } static void convertPan(int &pan) { - // DirectSound was orginally used, which specifies volume + // DirectSound was originally used, which specifies volume // and panning differently than ScummVM does, using a logarithmic scale // rather than a linear one. // diff --git a/engines/avalanche/POTFILES b/engines/avalanche/POTFILES new file mode 100644 index 0000000000..5b0bb910ed --- /dev/null +++ b/engines/avalanche/POTFILES @@ -0,0 +1 @@ +engines/avalanche/parser.cpp diff --git a/engines/avalanche/configure.engine b/engines/avalanche/configure.engine index 28d6a558db..9b913ff053 100644 --- a/engines/avalanche/configure.engine +++ b/engines/avalanche/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine avalanche "Lord Avalot d'Argent" no +add_engine avalanche "Lord Avalot d'Argent" no "" "" "highres" diff --git a/engines/avalanche/detection.cpp b/engines/avalanche/detection.cpp index 484d148161..e35c5d2cac 100644 --- a/engines/avalanche/detection.cpp +++ b/engines/avalanche/detection.cpp @@ -40,7 +40,7 @@ uint32 AvalancheEngine::getFeatures() const { } const char *AvalancheEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } static const PlainGameDescriptor avalancheGames[] = { @@ -110,7 +110,6 @@ SaveStateList AvalancheMetaEngine::listSaves(const char *target) const { pattern += ".###"; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) { @@ -152,6 +151,8 @@ SaveStateList AvalancheMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/avalanche/parser.cpp b/engines/avalanche/parser.cpp index 220186ca5e..7c6d254099 100644 --- a/engines/avalanche/parser.cpp +++ b/engines/avalanche/parser.cpp @@ -30,6 +30,7 @@ #include "avalanche/nim.h" #include "gui/saveload.h" +#include "common/translation.h" namespace Avalanche { @@ -1883,7 +1884,7 @@ void Parser::doThat() { break; case kVerbCodeLoad: { - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false); int16 savegameId = dialog->runModalWithCurrentTarget(); delete dialog; @@ -1895,7 +1896,7 @@ void Parser::doThat() { } break; case kVerbCodeSave: { - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); int16 savegameId = dialog->runModalWithCurrentTarget(); Common::String savegameDescription = dialog->getResultString(); delete dialog; 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/bbvs/detection.cpp b/engines/bbvs/detection.cpp index eb894e9f13..7c0045ee73 100644 --- a/engines/bbvs/detection.cpp +++ b/engines/bbvs/detection.cpp @@ -43,7 +43,7 @@ static const ADGameDescription gameDescriptions[] = { AD_ENTRY1s("vspr0001.vnm", "7ffe9b9e7ca322db1d48e86f5130578e", 1166628), Common::EN_ANY, Common::kPlatformWindows, - ADGF_NO_FLAGS | ADGF_TESTING, + ADGF_NO_FLAGS, GUIO0() }, { @@ -52,7 +52,7 @@ static const ADGameDescription gameDescriptions[] = { AD_ENTRY1s("vspr0001.vnm", "91c76b1048f93208cd7b1a05ebccb408", 1176976), Common::RU_RUS, Common::kPlatformWindows, - GF_GUILANGSWITCH | ADGF_TESTING, + GF_GUILANGSWITCH | ADGF_NO_FLAGS, GUIO0() }, @@ -69,7 +69,7 @@ static const char * const directoryGlobs[] = { class BbvsMetaEngine : public AdvancedMetaEngine { public: BbvsMetaEngine() : AdvancedMetaEngine(Bbvs::gameDescriptions, sizeof(ADGameDescription), bbvsGames) { - _singleid = "bbvs"; + _singleId = "bbvs"; _maxScanDepth = 3; _directoryGlobs = directoryGlobs; } @@ -116,7 +116,6 @@ SaveStateList BbvsMetaEngine::listSaves(const char *target) const { pattern += ".###"; Common::StringArray filenames; filenames = saveFileMan->listSavefiles(pattern.c_str()); - Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { // Obtain the last 3 digits of the filename, since they correspond to the save slot @@ -131,6 +130,8 @@ SaveStateList BbvsMetaEngine::listSaves(const char *target) const { } } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/bbvs/dialogs.cpp b/engines/bbvs/dialogs.cpp index ef7f3c9320..c8470f8eef 100644 --- a/engines/bbvs/dialogs.cpp +++ b/engines/bbvs/dialogs.cpp @@ -102,7 +102,7 @@ void MainMenu::reflowLayout() { _w = 2 * buttonWidth + buttonPadding; _h = 3 * buttonHeight + 3 * buttonPadding; _x = (screenW - _w) / 2; - _y = screenH - _h; + _y = screenH - _h - 2; int x = 0, y = 0; diff --git a/engines/cge/POTFILES b/engines/cge/POTFILES index 55430683c3..f8aef4932d 100644 --- a/engines/cge/POTFILES +++ b/engines/cge/POTFILES @@ -1,2 +1,3 @@ engines/cge/detection.cpp +engines/cge/events.cpp diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp index 47c5f56b6e..52168dc934 100644 --- a/engines/cge/detection.cpp +++ b/engines/cge/detection.cpp @@ -115,7 +115,7 @@ static const ADExtraGuiOptionsMap optionsList[] = { class CGEMetaEngine : public AdvancedMetaEngine { public: CGEMetaEngine() : AdvancedMetaEngine(CGE::gameDescriptions, sizeof(ADGameDescription), CGEGames, optionsList) { - _singleid = "soltys"; + _singleId = "soltys"; } virtual const char *getName() const { @@ -199,7 +199,6 @@ SaveStateList CGEMetaEngine::listSaves(const char *target) const { pattern += ".###"; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) { @@ -235,6 +234,8 @@ SaveStateList CGEMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/cge/events.cpp b/engines/cge/events.cpp index 24b3a270cf..c2f8982592 100644 --- a/engines/cge/events.cpp +++ b/engines/cge/events.cpp @@ -30,6 +30,7 @@ #include "gui/message.h" #include "common/config-manager.h" #include "common/events.h" +#include "common/translation.h" #include "engines/advancedDetector.h" #include "cge/events.h" #include "cge/events.h" @@ -70,7 +71,7 @@ bool Keyboard::getKey(Common::Event &event) { return false; case Common::KEYCODE_F5: if (_vm->canSaveGameStateCurrently()) { - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); int16 savegameId = dialog->runModalWithCurrentTarget(); Common::String savegameDescription = dialog->getResultString(); delete dialog; @@ -81,7 +82,7 @@ bool Keyboard::getKey(Common::Event &event) { return false; case Common::KEYCODE_F7: if (_vm->canLoadGameStateCurrently()) { - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false); int16 savegameId = dialog->runModalWithCurrentTarget(); delete dialog; diff --git a/engines/cge2/POTFILES b/engines/cge2/POTFILES index 1e904763ec..3bff3258fd 100644 --- a/engines/cge2/POTFILES +++ b/engines/cge2/POTFILES @@ -1 +1,2 @@ engines/cge2/detection.cpp +engines/cge2/events.cpp diff --git a/engines/cge2/detection.cpp b/engines/cge2/detection.cpp index a1867b0dfe..01119bb1fd 100644 --- a/engines/cge2/detection.cpp +++ b/engines/cge2/detection.cpp @@ -111,7 +111,7 @@ static const ADExtraGuiOptionsMap optionsList[] = { class CGE2MetaEngine : public AdvancedMetaEngine { public: CGE2MetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(ADGameDescription), CGE2Games, optionsList) { - _singleid = "sfinx"; + _singleId = "sfinx"; } virtual const char *getName() const { @@ -199,7 +199,6 @@ SaveStateList CGE2MetaEngine::listSaves(const char *target) const { pattern += ".###"; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) { @@ -235,6 +234,8 @@ SaveStateList CGE2MetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/cge2/events.cpp b/engines/cge2/events.cpp index 85743c8011..96cecc8e23 100644 --- a/engines/cge2/events.cpp +++ b/engines/cge2/events.cpp @@ -30,6 +30,7 @@ #include "gui/message.h" #include "common/config-manager.h" #include "common/events.h" +#include "common/translation.h" #include "engines/advancedDetector.h" #include "cge2/events.h" #include "cge2/text.h" @@ -63,7 +64,7 @@ bool Keyboard::getKey(Common::Event &event) { return false; case Common::KEYCODE_F5: if (_vm->canSaveGameStateCurrently()) { - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); int16 savegameId = dialog->runModalWithCurrentTarget(); Common::String savegameDescription = dialog->getResultString(); delete dialog; @@ -74,7 +75,7 @@ bool Keyboard::getKey(Common::Event &event) { return false; case Common::KEYCODE_F7: if (_vm->canLoadGameStateCurrently()) { - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false); int16 savegameId = dialog->runModalWithCurrentTarget(); delete dialog; diff --git a/engines/cge2/vga13h.cpp b/engines/cge2/vga13h.cpp index eb111c3255..54f5c00d93 100644 --- a/engines/cge2/vga13h.cpp +++ b/engines/cge2/vga13h.cpp @@ -141,7 +141,7 @@ Sprite::Sprite(CGE2Engine *vm) memset(_actionCtrl, 0, sizeof(_actionCtrl)); memset(_file, 0, sizeof(_file)); memset(&_flags, 0, sizeof(_flags)); - _flags._frnt = 1; + _flags._frnt = true; } Sprite::Sprite(CGE2Engine *vm, BitmapPtr shpP, int cnt) @@ -152,7 +152,7 @@ Sprite::Sprite(CGE2Engine *vm, BitmapPtr shpP, int cnt) memset(_actionCtrl, 0, sizeof(_actionCtrl)); memset(_file, 0, sizeof(_file)); memset(&_flags, 0, sizeof(_flags)); - _flags._frnt = 1; + _flags._frnt = true; setShapeList(shpP, cnt); } diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp index c6099447d8..6ecf07fe15 100644 --- a/engines/cine/anim.cpp +++ b/engines/cine/anim.cpp @@ -535,7 +535,7 @@ int loadSpl(const char *resourceName, int16 idx) { entry = idx < 0 ? emptyAnimSpace() : idx; assert(entry >= 0); - g_cine->_animDataTable[entry].load(dataPtr + 0x16, ANIM_RAW, g_cine->_partBuffer[foundFileIdx].unpackedSize - 0x16, 1, foundFileIdx, 0, currentPartName); + g_cine->_animDataTable[entry].load(dataPtr, ANIM_RAW, g_cine->_partBuffer[foundFileIdx].unpackedSize, 1, foundFileIdx, 0, currentPartName); free(dataPtr); return entry + 1; diff --git a/engines/cine/detection.cpp b/engines/cine/detection.cpp index dac7add16b..ec01e8734d 100644 --- a/engines/cine/detection.cpp +++ b/engines/cine/detection.cpp @@ -80,12 +80,12 @@ static const ADExtraGuiOptionsMap optionsList[] = { class CineMetaEngine : public AdvancedMetaEngine { public: CineMetaEngine() : AdvancedMetaEngine(Cine::gameDescriptions, sizeof(Cine::CINEGameDescription), cineGames, optionsList) { - _singleid = "cine"; - _guioptions = GUIO2(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVELOAD); + _singleId = "cine"; + _guiOptions = GUIO2(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVELOAD); } - virtual GameDescriptor findGame(const char *gameid) const { - return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable); + virtual GameDescriptor findGame(const char *gameId) const { + return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable); } virtual const char *getName() const { @@ -137,7 +137,6 @@ SaveStateList CineMetaEngine::listSaves(const char *target) const { Common::String pattern = target; pattern += ".#"; Common::StringArray filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); Common::StringArray::const_iterator file; Common::String filename = target; @@ -169,6 +168,8 @@ SaveStateList CineMetaEngine::listSaves(const char *target) const { delete in; + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/cine/saveload.cpp b/engines/cine/saveload.cpp index 1f4f286694..dfd3a1f4bc 100644 --- a/engines/cine/saveload.cpp +++ b/engines/cine/saveload.cpp @@ -691,6 +691,11 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor } if (strlen(bgName)) { + if (g_cine->getGameType() == GType_FW && (g_cine->getFeatures() & GF_CD)) { + char buffer[20]; + removeExtention(buffer, bgName); + g_sound->setBgMusic(atoi(buffer + 1)); + } loadBg(bgName); } diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 6ad38f4433..86eb709d5a 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -1858,7 +1858,9 @@ int FWScript::o1_playSample() { if (g_cine->getGameType() == Cine::GType_OS && size == 0) { return 0; } - g_sound->stopMusic(); + // The DOS CD version of Future Wars uses CD audio for music + if (!(g_cine->getGameType() == Cine::GType_FW && (g_cine->getFeatures() & GF_CD))) + g_sound->stopMusic(); if (size == 0xFFFF) { g_sound->playSound(channel, 0, data, 0, 0, 0, volume, 0); } else { diff --git a/engines/composer/configure.engine b/engines/composer/configure.engine index 71a79acb5d..17120a3a3d 100644 --- a/engines/composer/configure.engine +++ b/engines/composer/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine composer "Magic Composer" yes +add_engine composer "Magic Composer" yes "" "" "highres" diff --git a/engines/composer/detection.cpp b/engines/composer/detection.cpp index 036c1e88d8..a3ab18ae54 100644 --- a/engines/composer/detection.cpp +++ b/engines/composer/detection.cpp @@ -38,7 +38,7 @@ int ComposerEngine::getGameType() const { } const char *ComposerEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } uint32 ComposerEngine::getFeatures() const { @@ -81,12 +81,12 @@ static const ComposerGameDescription gameDescriptions[] = { GType_ComposerV1 }, - // Magic Tales: Baba Yaga and the Magic Geese Mac - from bug #3466402 + // Magic Tales: Baba Yaga and the Magic Geese Mac - from bug #3466402, #7025 { { "babayaga", "", - AD_ENTRY1("Baba Yaga", "ae3a4445f42fe10253da7ee4ea0d37"), + AD_ENTRY1s("Baba Yaga", "ae3a4445f42fe10253da7ee4ea0d37d6", 44321), Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, @@ -386,7 +386,7 @@ static const char *directoryGlobs[] = { class ComposerMetaEngine : public AdvancedMetaEngine { public: ComposerMetaEngine() : AdvancedMetaEngine(Composer::gameDescriptions, sizeof(Composer::ComposerGameDescription), composerGames) { - _singleid = "composer"; + _singleId = "composer"; _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } diff --git a/engines/cruise/detection.cpp b/engines/cruise/detection.cpp index 4d0ed2bf91..6f5d236173 100644 --- a/engines/cruise/detection.cpp +++ b/engines/cruise/detection.cpp @@ -35,7 +35,7 @@ struct CRUISEGameDescription { }; const char *CruiseEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } Common::Language CruiseEngine::getLanguage() const { @@ -196,8 +196,8 @@ static const CRUISEGameDescription gameDescriptions[] = { class CruiseMetaEngine : public AdvancedMetaEngine { public: CruiseMetaEngine() : AdvancedMetaEngine(Cruise::gameDescriptions, sizeof(Cruise::CRUISEGameDescription), cruiseGames) { - _singleid = "cruise"; - _guioptions = GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI); + _singleId = "cruise"; + _guiOptions = GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI); } virtual const char *getName() const { @@ -231,7 +231,6 @@ SaveStateList CruiseMetaEngine::listSaves(const char *target) const { Common::String pattern("cruise.s##"); filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -250,6 +249,8 @@ SaveStateList CruiseMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/draci/detection.cpp b/engines/draci/detection.cpp index a32dae3216..65427bd8cd 100644 --- a/engines/draci/detection.cpp +++ b/engines/draci/detection.cpp @@ -84,7 +84,7 @@ const ADGameDescription gameDescriptions[] = { class DraciMetaEngine : public AdvancedMetaEngine { public: DraciMetaEngine() : AdvancedMetaEngine(Draci::gameDescriptions, sizeof(ADGameDescription), draciGames) { - _singleid = "draci"; + _singleId = "draci"; } virtual const char *getName() const { @@ -120,7 +120,6 @@ SaveStateList DraciMetaEngine::listSaves(const char *target) const { Common::String pattern("draci.s##"); filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -143,6 +142,8 @@ SaveStateList DraciMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp index fbf58faaa1..ffec393a0a 100644 --- a/engines/drascula/detection.cpp +++ b/engines/drascula/detection.cpp @@ -310,8 +310,8 @@ SaveStateDescriptor loadMetaData(Common::ReadStream *s, int slot, bool setPlayTi class DrasculaMetaEngine : public AdvancedMetaEngine { public: DrasculaMetaEngine() : AdvancedMetaEngine(Drascula::gameDescriptions, sizeof(Drascula::DrasculaGameDescription), drasculaGames) { - _singleid = "drascula"; - _guioptions = GUIO1(GUIO_NOMIDI); + _singleId = "drascula"; + _guiOptions = GUIO1(GUIO_NOMIDI); } virtual const char *getName() const { @@ -355,7 +355,6 @@ SaveStateList DrasculaMetaEngine::listSaves(const char *target) const { pattern += ".###"; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; int slotNum = 0; @@ -378,6 +377,8 @@ SaveStateList DrasculaMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/dreamweb/detection.cpp b/engines/dreamweb/detection.cpp index 4fc624c2f3..764171bcb0 100644 --- a/engines/dreamweb/detection.cpp +++ b/engines/dreamweb/detection.cpp @@ -70,8 +70,8 @@ public: AdvancedMetaEngine(DreamWeb::gameDescriptions, sizeof(DreamWeb::DreamWebGameDescription), dreamWebGames, gameGuiOptions) { - _singleid = "dreamweb"; - _guioptions = GUIO1(GUIO_NOMIDI); + _singleId = "dreamweb"; + _guiOptions = GUIO1(GUIO_NOMIDI); } virtual const char *getName() const { @@ -128,7 +128,6 @@ bool DreamWebMetaEngine::createInstance(OSystem *syst, Engine **engine, const AD SaveStateList DreamWebMetaEngine::listSaves(const char *target) const { Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); Common::StringArray files = saveFileMan->listSavefiles("DREAMWEB.D##"); - Common::sort(files.begin(), files.end()); SaveStateList saveList; for (uint i = 0; i < files.size(); ++i) { @@ -146,6 +145,8 @@ SaveStateList DreamWebMetaEngine::listSaves(const char *target) const { saveList.push_back(sd); } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/engine.cpp b/engines/engine.cpp index 475cc77064..d3b9b113cf 100644 --- a/engines/engine.cpp +++ b/engines/engine.cpp @@ -292,7 +292,7 @@ void splashScreen() { Common::Event event; while (time0 + 600 > g_system->getMillis()) { g_system->updateScreen(); - g_system->getEventManager()->pollEvent(event); + (void)g_system->getEventManager()->pollEvent(event); g_system->delayMillis(10); } g_system->hideOverlay(); diff --git a/engines/fullpipe/configure.engine b/engines/fullpipe/configure.engine index a9042449db..611d0188dc 100644 --- a/engines/fullpipe/configure.engine +++ b/engines/fullpipe/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine fullpipe "Full Pipe" no "" "" "16bit" +add_engine fullpipe "Full Pipe" no "" "" "16bit highres" diff --git a/engines/fullpipe/detection.cpp b/engines/fullpipe/detection.cpp index ccd55935e6..6f92f19f24 100644 --- a/engines/fullpipe/detection.cpp +++ b/engines/fullpipe/detection.cpp @@ -32,7 +32,7 @@ namespace Fullpipe { const char *FullpipeEngine::getGameId() const { - return _gameDescription->gameid; + return _gameDescription->gameId; } } @@ -76,7 +76,7 @@ static const ADGameDescription gameDescriptions[] = { class FullpipeMetaEngine : public AdvancedMetaEngine { public: FullpipeMetaEngine() : AdvancedMetaEngine(Fullpipe::gameDescriptions, sizeof(ADGameDescription), fullpipeGames) { - _singleid = "fullpipe"; + _singleId = "fullpipe"; } virtual const char *getName() const { @@ -111,7 +111,6 @@ SaveStateList FullpipeMetaEngine::listSaves(const char *target) const { Common::String pattern("fullpipe.s##"); filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -130,6 +129,8 @@ SaveStateList FullpipeMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/game.cpp b/engines/game.cpp index 85ad6fe2e8..7ff51a99cc 100644 --- a/engines/game.cpp +++ b/engines/game.cpp @@ -26,8 +26,8 @@ const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list) { const PlainGameDescriptor *g = list; - while (g->gameid) { - if (0 == scumm_stricmp(gameid, g->gameid)) + while (g->gameId) { + if (0 == scumm_stricmp(gameid, g->gameId)) return g; g++; } @@ -40,7 +40,7 @@ GameDescriptor::GameDescriptor() { } GameDescriptor::GameDescriptor(const PlainGameDescriptor &pgd, Common::String guioptions) { - setVal("gameid", pgd.gameid); + setVal("gameid", pgd.gameId); setVal("description", pgd.description); if (!guioptions.empty()) diff --git a/engines/game.h b/engines/game.h index a9bec8f9e0..e01e5c6885 100644 --- a/engines/game.h +++ b/engines/game.h @@ -36,7 +36,7 @@ * consisting of PlainGameDescriptors. */ struct PlainGameDescriptor { - const char *gameid; + const char *gameId; const char *description; }; @@ -108,7 +108,7 @@ public: GameList() {} GameList(const GameList &list) : Common::Array<GameDescriptor>(list) {} GameList(const PlainGameDescriptor *g) { - while (g->gameid) { + while (g->gameId) { push_back(GameDescriptor(*g)); g++; } diff --git a/engines/gob/detection/detection.cpp b/engines/gob/detection/detection.cpp index 3b26f63c39..b0aa78f416 100644 --- a/engines/gob/detection/detection.cpp +++ b/engines/gob/detection/detection.cpp @@ -33,7 +33,7 @@ class GobMetaEngine : public AdvancedMetaEngine { public: GobMetaEngine(); - virtual GameDescriptor findGame(const char *gameid) const; + virtual GameDescriptor findGame(const char *gameId) const; virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const; @@ -55,12 +55,12 @@ private: GobMetaEngine::GobMetaEngine() : AdvancedMetaEngine(Gob::gameDescriptions, sizeof(Gob::GOBGameDescription), gobGames) { - _singleid = "gob"; - _guioptions = GUIO1(GUIO_NOLAUNCHLOAD); + _singleId = "gob"; + _guiOptions = GUIO1(GUIO_NOLAUNCHLOAD); } -GameDescriptor GobMetaEngine::findGame(const char *gameid) const { - return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable); +GameDescriptor GobMetaEngine::findGame(const char *gameId) const { + return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable); } const ADGameDescription *GobMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const { diff --git a/engines/gob/script.cpp b/engines/gob/script.cpp index d6e9841e0a..9298f159a4 100644 --- a/engines/gob/script.cpp +++ b/engines/gob/script.cpp @@ -215,7 +215,7 @@ char *Script::readString(int32 length) { } byte Script::peekByte(int32 offset) { - byte v; + byte v = 0; peek(&v, 1, offset); diff --git a/engines/gob/sound/adlib.cpp b/engines/gob/sound/adlib.cpp index 1e024d5a50..2a9a716058 100644 --- a/engines/gob/sound/adlib.cpp +++ b/engines/gob/sound/adlib.cpp @@ -283,7 +283,12 @@ void AdLib::initOPL() { _voiceOn [i] = 0; } - _opl->reset(); + /* NOTE: We used to completely reset the OPL here, via _opl->reset(). However, + * with the OPL timer change in 73e8ac2a, reset() must not be called while + * the callback is still active. With the Gob AdLib rewrite in 03ef6689, + * this reset shouldn't be necessary anymore either, since this function + * here cleans everything properly anyway. If suddenly a certain piece of + * music in a Gob game sounds weird, we need to re-examine that. */ initOperatorVolumes(); resetFreqs(); diff --git a/engines/groovie/configure.engine b/engines/groovie/configure.engine index 212a49bec8..f283731a58 100644 --- a/engines/groovie/configure.engine +++ b/engines/groovie/configure.engine @@ -1,4 +1,4 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine groovie "Groovie" yes "groovie2" "7th Guest" +add_engine groovie "Groovie" yes "groovie2" "7th Guest" "highres" add_engine groovie2 "Groovie 2 games" no "" "" "jpeg 16bit" diff --git a/engines/groovie/detection.cpp b/engines/groovie/detection.cpp index a249b66858..b12e264a57 100644 --- a/engines/groovie/detection.cpp +++ b/engines/groovie/detection.cpp @@ -322,7 +322,7 @@ static const ADExtraGuiOptionsMap optionsList[] = { class GroovieMetaEngine : public AdvancedMetaEngine { public: GroovieMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(GroovieGameDescription), groovieGames, optionsList) { - _singleid = "groovie"; + _singleId = "groovie"; // Use kADFlagUseExtraAsHint in order to distinguish the 11th hour from // its "Making of" as well as the Clandestiny Trailer; they all share @@ -333,7 +333,7 @@ public: // to the detection entries. In the latter case, this TODO should be // replaced with an according explanation. _flags = kADFlagUseExtraAsHint; - _guioptions = GUIO3(GUIO_NOSUBTITLES, GUIO_NOSFX, GUIO_NOASPECT); + _guiOptions = GUIO3(GUIO_NOSUBTITLES, GUIO_NOSFX, GUIO_NOASPECT); // Need MIDI directory to detect 11H Mac Installed _maxScanDepth = 2; diff --git a/engines/groovie/groovie.cpp b/engines/groovie/groovie.cpp index b42cf09245..2021cef6e8 100644 --- a/engines/groovie/groovie.cpp +++ b/engines/groovie/groovie.cpp @@ -69,7 +69,7 @@ GroovieEngine::GroovieEngine(OSystem *syst, const GroovieGameDescription *gd) : // Initialize the custom debug levels DebugMan.addDebugChannel(kDebugVideo, "Video", "Debug video and audio playback"); - DebugMan.addDebugChannel(kDebugResource, "Resource", "Debug resouce management"); + DebugMan.addDebugChannel(kDebugResource, "Resource", "Debug resource management"); DebugMan.addDebugChannel(kDebugScript, "Script", "Debug the scripts"); DebugMan.addDebugChannel(kDebugUnknown, "Unknown", "Report values of unknown data in files"); DebugMan.addDebugChannel(kDebugHotspots, "Hotspots", "Show the hotspots"); diff --git a/engines/hopkins/configure.engine b/engines/hopkins/configure.engine index c38ecd4cd2..cd9f50a5f9 100644 --- a/engines/hopkins/configure.engine +++ b/engines/hopkins/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine hopkins "Hopkins FBI" yes "" "" "16bit" +add_engine hopkins "Hopkins FBI" yes "" "" "16bit highres" diff --git a/engines/hopkins/detection.cpp b/engines/hopkins/detection.cpp index 670efb8898..cc1e84f5f8 100644 --- a/engines/hopkins/detection.cpp +++ b/engines/hopkins/detection.cpp @@ -153,7 +153,6 @@ SaveStateList HopkinsMetaEngine::listSaves(const char *target) const { Common::String pattern = Common::String::format("%s.0##", target); filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order Hopkins::hopkinsSavegameHeader header; @@ -178,6 +177,8 @@ SaveStateList HopkinsMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/hugo/POTFILES b/engines/hugo/POTFILES new file mode 100644 index 0000000000..ff61e12ca5 --- /dev/null +++ b/engines/hugo/POTFILES @@ -0,0 +1 @@ +engines/hugo/file.cpp diff --git a/engines/hugo/detection.cpp b/engines/hugo/detection.cpp index a005e649d4..4e4746c002 100644 --- a/engines/hugo/detection.cpp +++ b/engines/hugo/detection.cpp @@ -41,7 +41,7 @@ uint32 HugoEngine::getFeatures() const { } const char *HugoEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } @@ -180,7 +180,6 @@ SaveStateList HugoMetaEngine::listSaves(const char *target) const { pattern += "-##.SAV"; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; char slot[3]; @@ -217,6 +216,8 @@ SaveStateList HugoMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/hugo/file.cpp b/engines/hugo/file.cpp index e2633977a8..7a3538ea63 100644 --- a/engines/hugo/file.cpp +++ b/engines/hugo/file.cpp @@ -32,6 +32,7 @@ #include "common/savefile.h" #include "common/textconsole.h" #include "common/config-manager.h" +#include "common/translation.h" #include "graphics/surface.h" #include "graphics/thumbnail.h" @@ -294,7 +295,7 @@ bool FileManager::saveGame(const int16 slot, const Common::String &descrip) { Common::String savegameDescription; if (slot == -1) { - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); savegameId = dialog->runModalWithCurrentTarget(); savegameDescription = dialog->getResultString(); delete dialog; @@ -396,7 +397,7 @@ bool FileManager::restoreGame(const int16 slot) { int16 savegameId; if (slot == -1) { - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false); savegameId = dialog->runModalWithCurrentTarget(); delete dialog; } else { diff --git a/engines/kyra/debugger.cpp b/engines/kyra/debugger.cpp index 4a90722a35..6683f973ca 100644 --- a/engines/kyra/debugger.cpp +++ b/engines/kyra/debugger.cpp @@ -542,7 +542,7 @@ bool Debugger_EoB::cmdSaveOriginal(int argc, const char **argv) { debugPrintf("Failure.\n"); } } else { - debugPrintf("Syntax: save_original\n (Saves game in original file format to a file which can be used with the orginal game executable.)\n\n"); + debugPrintf("Syntax: save_original\n (Saves game in original file format to a file which can be used with the original game executable.)\n\n"); } return true; @@ -562,7 +562,7 @@ bool Debugger_EoB::cmdSaveOriginal(int argc, const char **argv) { return true; } - debugPrintf("Syntax: save_original <slot>\n (Saves game in original file format to a file which can be used with the orginal game executable.\n A save slot between 0 and 5 must be specified.)\n\n"); + debugPrintf("Syntax: save_original <slot>\n (Saves game in original file format to a file which can be used with the original game executable.\n A save slot between 0 and 5 must be specified.)\n\n"); return true; } diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index a4786ef583..989a45b420 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -246,7 +246,6 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const { Common::StringArray filenames; filenames = saveFileMan->listSavefiles(pattern); - Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -269,6 +268,8 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h index 2ee0262ef2..773d491423 100644 --- a/engines/kyra/detection_tables.h +++ b/engines/kyra/detection_tables.h @@ -1546,7 +1546,7 @@ const KYRAGameDescription adGameDescs[] = { }, Common::EN_ANY, Common::kPlatformDOS, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO7(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA, GAMEOPTION_EOB_HPGRAPHS) }, EOB_FLAGS @@ -1562,7 +1562,7 @@ const KYRAGameDescription adGameDescs[] = { }, Common::DE_DEU, Common::kPlatformDOS, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO7(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA, GAMEOPTION_EOB_HPGRAPHS) }, EOB_FLAGS @@ -1576,10 +1576,10 @@ const KYRAGameDescription adGameDescs[] = { { "EOBDATA3.PAK", 0, "3ed915ab5b94d60dbfe1b55379889c51", -1 }, { 0, 0, 0, 0 } }, - Common::IT_ITA, - Common::kPlatformDOS, - ADGF_TESTING, - GUIO7(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA, GAMEOPTION_EOB_HPGRAPHS) + Common::IT_ITA, + Common::kPlatformDOS, + ADGF_NO_FLAGS, + GUIO7(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA, GAMEOPTION_EOB_HPGRAPHS) }, EOB_FLAGS }, @@ -1594,7 +1594,7 @@ const KYRAGameDescription adGameDescs[] = { }, Common::EN_ANY, Common::kPlatformDOS, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GAMEOPTION_EOB_HPGRAPHS) }, EOB2_FLAGS @@ -1610,7 +1610,7 @@ const KYRAGameDescription adGameDescs[] = { }, Common::DE_DEU, Common::kPlatformDOS, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GAMEOPTION_EOB_HPGRAPHS) }, EOB2_FLAGS diff --git a/engines/kyra/gui_lol.cpp b/engines/kyra/gui_lol.cpp index cfdf762bba..5ff0b6a109 100644 --- a/engines/kyra/gui_lol.cpp +++ b/engines/kyra/gui_lol.cpp @@ -2219,7 +2219,7 @@ int GUI_LoL::runMenu(Menu &menu) { int fW = (d->w << 3) - wW; int fC = 0; - // LoL doesnt't have default higlighted items. No item should be + // LoL doesn't have default higlighted items. No item should be // highlighted when entering a new menu. // Instead, the respevtive struct entry is used to determine whether // a menu has scroll buttons or slider bars. diff --git a/engines/kyra/gui_v1.cpp b/engines/kyra/gui_v1.cpp index a75c14b071..92891f71b2 100644 --- a/engines/kyra/gui_v1.cpp +++ b/engines/kyra/gui_v1.cpp @@ -200,7 +200,7 @@ void GUI_v1::processHighlights(Menu &menu) { int mouseY = p.y; if (_vm->game() == GI_LOL && menu.highlightedItem != 255) { - // LoL doesnt't have default highlighted items. + // LoL doesn't have default highlighted items. // We use a highlightedItem value of 255 for this. // With LoL no highlighting should take place unless the diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp index 3c3aff6ea9..6c0d529f96 100644 --- a/engines/kyra/sound.cpp +++ b/engines/kyra/sound.cpp @@ -37,7 +37,7 @@ namespace Kyra { Sound::Sound(KyraEngine_v1 *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer), _soundChannels(), _musicEnabled(1), - _sfxEnabled(true) { + _sfxEnabled(true) { } Sound::~Sound() { @@ -165,7 +165,7 @@ bool Sound::allVoiceChannelsPlaying() const { #pragma mark - MixedSoundDriver::MixedSoundDriver(KyraEngine_v1 *vm, Audio::Mixer *mixer, Sound *music, Sound *sfx) - : Sound(vm, mixer), _music(music), _sfx(sfx) { + : Sound(vm, mixer), _music(music), _sfx(sfx) { } MixedSoundDriver::~MixedSoundDriver() { @@ -289,16 +289,16 @@ void KyraEngine_v1::snd_playWanderScoreViaMap(int command, int restart) { //} if (_flags.platform == Common::kPlatformDOS || _flags.platform == Common::kPlatformMacintosh) { - assert(command*2+1 < _trackMapSize); - if (_curMusicTheme != _trackMap[command*2]) { - if (_trackMap[command*2] != -1 && _trackMap[command*2] != -2) - snd_playTheme(_trackMap[command*2], -1); + assert(command * 2 + 1 < _trackMapSize); + if (_curMusicTheme != _trackMap[command * 2]) { + if (_trackMap[command * 2] != -1 && _trackMap[command * 2] != -2) + snd_playTheme(_trackMap[command * 2], -1); } if (command != 1) { if (_lastMusicCommand != command) { _sound->haltTrack(); - _sound->playTrack(_trackMap[command*2+1]); + _sound->playTrack(_trackMap[command * 2 + 1]); } } else { _sound->beginFadeOut(); @@ -307,8 +307,8 @@ void KyraEngine_v1::snd_playWanderScoreViaMap(int command, int restart) { if (command == -1) { _sound->haltTrack(); } else { - assert(command*2+1 < _trackMapSize); - if (_trackMap[command*2] != -2 && command != _lastMusicCommand) { + assert(command * 2 + 1 < _trackMapSize); + if (_trackMap[command * 2] != -2 && command != _lastMusicCommand) { _sound->haltTrack(); _sound->playTrack(command); } diff --git a/engines/lab/configure.engine b/engines/lab/configure.engine index 18091b1b84..3be9545aa6 100644 --- a/engines/lab/configure.engine +++ b/engines/lab/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine lab "Labyrinth of Time" no +add_engine lab "Labyrinth of Time" yes diff --git a/engines/lab/detection.cpp b/engines/lab/detection.cpp index d01dff2843..1fd3ca8944 100644 --- a/engines/lab/detection.cpp +++ b/engines/lab/detection.cpp @@ -48,7 +48,7 @@ static const ADGameDescription labDescriptions[] = { }, Common::EN_ANY, Common::kPlatformDOS, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO0() }, { @@ -61,7 +61,7 @@ static const ADGameDescription labDescriptions[] = { }, Common::EN_ANY, Common::kPlatformDOS, - Lab::GF_LOWRES | ADGF_TESTING, + Lab::GF_LOWRES | ADGF_NO_FLAGS, GUIO0() }, { @@ -75,7 +75,7 @@ static const ADGameDescription labDescriptions[] = { }, Common::EN_ANY, Common::kPlatformWindows, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO0() }, { @@ -115,7 +115,7 @@ uint32 LabEngine::getFeatures() const { class LabMetaEngine : public AdvancedMetaEngine { public: LabMetaEngine() : AdvancedMetaEngine(labDescriptions, sizeof(ADGameDescription), lab_setting) { - _singleid = "lab"; + _singleId = "lab"; _maxScanDepth = 4; _directoryGlobs = directoryGlobs; @@ -169,7 +169,6 @@ SaveStateList LabMetaEngine::listSaves(const char *target) const { Common::StringArray filenames; filenames = saveFileMan->listSavefiles(pattern.c_str()); - Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)*/ SaveStateList saveList; @@ -187,6 +186,8 @@ SaveStateList LabMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } @@ -196,26 +197,7 @@ int LabMetaEngine::getMaximumSaveSlot() const { void LabMetaEngine::removeSaveState(const char *target, int slot) const { Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); - Common::String filename = Common::String::format("%s.%03u", target, slot); - - saveFileMan->removeSavefile(filename.c_str()); - - Common::StringArray filenames; - Common::String pattern = target; - pattern += ".###"; - filenames = saveFileMan->listSavefiles(pattern.c_str()); - Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) - - for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { - // Obtain the last 3 digits of the filename, since they correspond to the save slot - int slotNum = atoi(file->c_str() + file->size() - 3); - - // Rename every slot greater than the deleted slot, - if (slotNum > slot) { - saveFileMan->renameSavefile(file->c_str(), filename.c_str()); - filename = Common::String::format("%s.%03u", target, ++slot); - } - } + saveFileMan->removeSavefile(Common::String::format("%s.%03u", target, slot)); } SaveStateDescriptor LabMetaEngine::querySaveMetaInfos(const char *target, int slot) const { diff --git a/engines/lab/lab.cpp b/engines/lab/lab.cpp index 0a4cf4ec50..9b0ebfc4e5 100644 --- a/engines/lab/lab.cpp +++ b/engines/lab/lab.cpp @@ -214,12 +214,6 @@ void LabEngine::updateEvents() { Common::Error LabEngine::loadGameState(int slot) { bool result = loadGame(slot); - _curFileName = " "; - _closeDataPtr = nullptr; - _mainDisplay = true; - _followingCrumbs = false; - _event->simulateEvent(); - _graphics->_longWinInFront = false; return (result) ? Common::kNoError : Common::kUserCanceled; } @@ -229,11 +223,11 @@ Common::Error LabEngine::saveGameState(int slot, const Common::String &desc) { } bool LabEngine::canLoadGameStateCurrently() { - return !_anim->isPlaying() && !_introPlaying; + return !_introPlaying; } bool LabEngine::canSaveGameStateCurrently() { - return !_anim->isPlaying() && !_introPlaying; + return !_introPlaying; } } // End of namespace Lab diff --git a/engines/lab/processroom.cpp b/engines/lab/processroom.cpp index 44c8d65d7c..5093e8ef85 100644 --- a/engines/lab/processroom.cpp +++ b/engines/lab/processroom.cpp @@ -238,6 +238,8 @@ void LabEngine::doActions(const ActionList &actionList) { ActionList::const_iterator action; for (action = actionList.begin(); action != actionList.end(); ++action) { updateEvents(); + if (_quitLab || shouldQuit()) + return; switch (action->_actionType) { case kActionPlaySound: @@ -381,6 +383,8 @@ void LabEngine::doActions(const ActionList &actionList) { while (_system->getMillis() < targetMillis) { updateEvents(); + if (_quitLab || shouldQuit()) + return; _anim->diffNextFrame(); } } @@ -409,6 +413,8 @@ void LabEngine::doActions(const ActionList &actionList) { case kActionWaitSound: // used in scene 44 (heart of the labyrinth / ending) while (_music->isSoundEffectActive()) { updateEvents(); + if (_quitLab || shouldQuit()) + return; _anim->diffNextFrame(); waitTOF(); } diff --git a/engines/lab/savegame.cpp b/engines/lab/savegame.cpp index 16c4044839..656595e3e5 100644 --- a/engines/lab/savegame.cpp +++ b/engines/lab/savegame.cpp @@ -157,6 +157,11 @@ bool LabEngine::saveGame(int slot, const Common::String desc) { file->finalize(); delete file; + _mainDisplay = true; + _alternate = false; + _event->simulateEvent(); + _graphics->screenUpdate(); + return true; } @@ -202,6 +207,17 @@ bool LabEngine::loadGame(int slot) { delete file; + _curFileName = " "; + _closeDataPtr = nullptr; + _followingCrumbs = false; + _graphics->_longWinInFront = false; + _event->initMouse(); + + _mainDisplay = true; + _alternate = false; + _event->simulateEvent(); + _graphics->screenUpdate(); + return true; } @@ -238,11 +254,6 @@ bool LabEngine::saveRestoreGame() { delete dialog; } - _alternate = false; - _mainDisplay = true; - _event->initMouse(); - _graphics->screenUpdate(); - return isOK; } diff --git a/engines/lastexpress/configure.engine b/engines/lastexpress/configure.engine index 807b1a088b..66bac55dea 100644 --- a/engines/lastexpress/configure.engine +++ b/engines/lastexpress/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine lastexpress "The Last Express" no "" "" "16bit" +add_engine lastexpress "The Last Express" no "" "" "16bit highres" diff --git a/engines/lastexpress/detection.cpp b/engines/lastexpress/detection.cpp index d790582104..52224e4ea5 100644 --- a/engines/lastexpress/detection.cpp +++ b/engines/lastexpress/detection.cpp @@ -199,8 +199,8 @@ static const ADGameDescription gameDescriptions[] = { class LastExpressMetaEngine : public AdvancedMetaEngine { public: LastExpressMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(ADGameDescription), lastExpressGames) { - _singleid = "lastexpress"; - _guioptions = GUIO2(GUIO_NOSUBTITLES, GUIO_NOSFX); + _singleId = "lastexpress"; + _guiOptions = GUIO2(GUIO_NOSUBTITLES, GUIO_NOSFX); } const char *getName() const { diff --git a/engines/lure/detection.cpp b/engines/lure/detection.cpp index 902e8afd65..690a358bc3 100644 --- a/engines/lure/detection.cpp +++ b/engines/lure/detection.cpp @@ -193,12 +193,12 @@ class LureMetaEngine : public AdvancedMetaEngine { public: LureMetaEngine() : AdvancedMetaEngine(Lure::gameDescriptions, sizeof(Lure::LureGameDescription), lureGames) { _md5Bytes = 1024; - _singleid = "lure"; + _singleId = "lure"; // Use kADFlagUseExtraAsHint to distinguish between EGA and VGA versions // of italian Lure when their datafiles sit in the same directory. _flags = kADFlagUseExtraAsHint; - _guioptions = GUIO1(GUIO_NOSPEECH); + _guiOptions = GUIO1(GUIO_NOSPEECH); } virtual const char *getName() const { @@ -245,7 +245,6 @@ SaveStateList LureMetaEngine::listSaves(const char *target) const { Common::String pattern = "lure.###"; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -262,6 +261,8 @@ SaveStateList LureMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/made/detection.cpp b/engines/made/detection.cpp index 7adc3e1f98..636c2d147c 100644 --- a/engines/made/detection.cpp +++ b/engines/made/detection.cpp @@ -521,7 +521,7 @@ static MadeGameDescription g_fallbackDesc = { class MadeMetaEngine : public AdvancedMetaEngine { public: MadeMetaEngine() : AdvancedMetaEngine(Made::gameDescriptions, sizeof(Made::MadeGameDescription), madeGames) { - _singleid = "made"; + _singleId = "made"; } virtual const char *getName() const { diff --git a/engines/mads/debugger.cpp b/engines/mads/debugger.cpp index 740c19abad..b9731b1d31 100644 --- a/engines/mads/debugger.cpp +++ b/engines/mads/debugger.cpp @@ -158,7 +158,7 @@ bool Debugger::Cmd_ShowCodes(int argc, const char **argv) { Scene &scene = _vm->_game->_scene; // Copy the depth/walk surface to the background and flag for screen refresh - scene._depthSurface.copyTo(&scene._backgroundSurface); + scene._depthSurface.blitFrom(scene._backgroundSurface); scene._spriteSlots.fullRefresh(); // Draw the locations of scene nodes onto the background diff --git a/engines/mads/detection.cpp b/engines/mads/detection.cpp index 0357bd4bcc..b3ba60b6d0 100644 --- a/engines/mads/detection.cpp +++ b/engines/mads/detection.cpp @@ -192,7 +192,6 @@ SaveStateList MADSMetaEngine::listSaves(const char *target) const { MADS::MADSSavegameHeader header; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -213,6 +212,8 @@ SaveStateList MADSMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/mads/dialogs.cpp b/engines/mads/dialogs.cpp index d9a1e53964..fa656a90c1 100644 --- a/engines/mads/dialogs.cpp +++ b/engines/mads/dialogs.cpp @@ -54,21 +54,19 @@ Dialog::~Dialog() { void Dialog::save() { _savedSurface = new MSurface(_width, _height); - _vm->_screen.copyTo(_savedSurface, + _savedSurface->blitFrom(*_vm->_screen, Common::Rect(_position.x, _position.y, _position.x + _width, _position.y + _height), Common::Point()); - _vm->_screen.copyRectToScreen(getBounds()); +// _vm->_screen->copyRectToScreen(getBounds()); } void Dialog::restore() { if (_savedSurface) { - _savedSurface->copyTo(&_vm->_screen, _position); + _vm->_screen->blitFrom(*_savedSurface, _position); delete _savedSurface; _savedSurface = nullptr; - _vm->_screen.copyRectToScreen(getBounds()); - Common::copy(&_dialogPalette[0], &_dialogPalette[8 * 3], &_vm->_palette->_mainPalette[248 * 3]); _vm->_palette->setPalette(&_vm->_palette->_mainPalette[248 * 3], 248, 8); @@ -87,16 +85,16 @@ void Dialog::draw() { // Draw the dialog // Fill entire content of dialog Common::Rect bounds = getBounds(); - _vm->_screen.fillRect(bounds, TEXTDIALOG_BACKGROUND); + _vm->_screen->fillRect(bounds, TEXTDIALOG_BACKGROUND); // Draw the outer edge lines - _vm->_screen.hLine(_position.x + 1, _position.y + _height - 2, + _vm->_screen->hLine(_position.x + 1, _position.y + _height - 2, _position.x + _width - 2, TEXTDIALOG_EDGE); - _vm->_screen.hLine(_position.x, _position.y + _height - 1, + _vm->_screen->hLine(_position.x, _position.y + _height - 1, _position.x + _width - 1, TEXTDIALOG_EDGE); - _vm->_screen.vLine(_position.x + _width - 2, _position.y + 2, + _vm->_screen->vLine(_position.x + _width - 2, _position.y + 2, _position.y + _height - 2, TEXTDIALOG_EDGE); - _vm->_screen.vLine(_position.x + _width - 1, _position.y + 1, + _vm->_screen->vLine(_position.x + _width - 1, _position.y + 1, _position.y + _height - 1, TEXTDIALOG_EDGE); // Draw the gravelly dialog content @@ -125,8 +123,9 @@ void Dialog::calculateBounds() { void Dialog::drawContent(const Common::Rect &r, int seed, byte color1, byte color2) { uint16 currSeed = seed ? seed : 0xB78E; + Graphics::Surface dest = _vm->_screen->getSubArea(r); for (int yp = 0; yp < r.height(); ++yp) { - byte *destP = _vm->_screen.getBasePtr(r.left, r.top + yp); + byte *destP = (byte *)dest.getBasePtr(0, yp); for (int xp = 0; xp < r.width(); ++xp) { uint16 seedAdjust = currSeed; @@ -326,7 +325,7 @@ void TextDialog::draw() { for (int lineNum = 0; lineNum <= _numLines; ++lineNum) { if (_lineXp[lineNum] == -1) { // Draw a line across the entire dialog - _vm->_screen.hLine(_position.x + 2, + _vm->_screen->hLine(_position.x + 2, lineYp + (_font->getHeight() + 1) / 2, _position.x + _width - 4, TEXTDIALOG_BLACK); } else { @@ -336,21 +335,19 @@ void TextDialog::draw() { if (_lineXp[lineNum] & 0x40) ++yp; - _font->writeString(&_vm->_screen, _lines[lineNum], + _font->writeString(_vm->_screen, _lines[lineNum], Common::Point(xp, yp), 1); if (_lineXp[lineNum] & 0x80) { // Draw an underline under the text int lineWidth = _font->getWidth(_lines[lineNum], 1); - _vm->_screen.hLine(xp, yp + _font->getHeight(), xp + lineWidth, + _vm->_screen->hLine(xp, yp + _font->getHeight(), xp + lineWidth, TEXTDIALOG_BLACK); } } lineYp += _font->getHeight() + 1; } - - _vm->_screen.copyRectToScreen(getBounds()); } void TextDialog::calculateBounds() { @@ -360,10 +357,10 @@ void TextDialog::calculateBounds() { if (_position.y == -1) _position.y = 100 - (_height / 2); - if ((_position.x + _width) > _vm->_screen.getWidth()) - _position.x = _vm->_screen.getWidth() - (_position.x + _width); - if ((_position.y + _height) > _vm->_screen.getHeight()) - _position.y = _vm->_screen.getHeight() - (_position.y + _height); + if ((_position.x + _width) > _vm->_screen->w) + _position.x = _vm->_screen->w - (_position.x + _width); + if ((_position.y + _height) > _vm->_screen->h) + _position.y = _vm->_screen->h - (_position.y + _height); } void TextDialog::drawWithInput() { @@ -452,7 +449,7 @@ FullScreenDialog::FullScreenDialog(MADSEngine *vm) : _vm(vm) { } FullScreenDialog::~FullScreenDialog() { - _vm->_screen.resetClipBounds(); + _vm->_screen->resetClipBounds(); _vm->_game->_scene.restrictScene(); } @@ -491,16 +488,13 @@ void FullScreenDialog::display() { game._trigger = 0; // Clear the screen and draw the upper and lower horizontal lines - _vm->_screen.empty(); + _vm->_screen->clear(); _vm->_palette->setLowRange(); - _vm->_screen.hLine(0, 20, MADS_SCREEN_WIDTH, 2); - _vm->_screen.hLine(0, 179, MADS_SCREEN_WIDTH, 2); - _vm->_screen.resetClipBounds(); - _vm->_screen.copyRectToScreen(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT)); + _vm->_screen->hLine(0, 20, MADS_SCREEN_WIDTH, 2); + _vm->_screen->hLine(0, 179, MADS_SCREEN_WIDTH, 2); // Restrict the screen to the area between the two lines - _vm->_screen.setClipBounds(Common::Rect(0, DIALOG_TOP, MADS_SCREEN_WIDTH, - DIALOG_TOP + MADS_SCENE_HEIGHT)); + _vm->_screen->setClipBounds(Common::Rect(0, DIALOG_TOP, MADS_SCREEN_WIDTH, DIALOG_TOP + MADS_SCENE_HEIGHT)); _vm->_game->_scene.restrictScene(); if (_screenId > 0) diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.cpp b/engines/mads/dragonsphere/dragonsphere_scenes.cpp index 938931e80d..a18d03d143 100644 --- a/engines/mads/dragonsphere/dragonsphere_scenes.cpp +++ b/engines/mads/dragonsphere/dragonsphere_scenes.cpp @@ -218,7 +218,7 @@ void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, int variant) { } void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) { - byte *destP = depthSurface.getData(); + byte *destP = (byte *)depthSurface.getPixels(); byte *walkMap = new byte[stream->size()]; stream->read(walkMap, stream->size()); diff --git a/engines/mads/events.cpp b/engines/mads/events.cpp index 7463704c4b..de83260b0f 100644 --- a/engines/mads/events.cpp +++ b/engines/mads/events.cpp @@ -98,7 +98,7 @@ void EventsManager::changeCursor() { // Check for hotspot indication pixels along the right-hand and bottom // row. Put together, these give the cursor's hotspot x,y int hotspotX = 0, hotspotY = 0; - byte *cursorData = cursor->getData(); + const byte *cursorData = (const byte *)cursor->getPixels(); for (int idx = 0; idx < cursor->w; ++idx) { if (cursorData[(cursor->h - 1) * cursor->w + idx] != transIndex) hotspotX = idx; @@ -110,7 +110,7 @@ void EventsManager::changeCursor() { // Reduce the cursor data to remove the last column from each row, since // the cursor routines don't have a pitch option byte *destCursor = new byte[(cursor->w - 1) * (cursor->h - 1)]; - byte *srcP = cursorData; + const byte *srcP = cursorData; byte *destP = destCursor; for (int idx = 0; idx < (cursor->h - 1); ++idx) { @@ -217,7 +217,7 @@ bool EventsManager::checkForNextFrameCounter() { _vm->_debugger->onFrame(); // Display the frame - _vm->_screen.updateScreen(); + _vm->_screen->update(); // Signal the ScummVM debugger _vm->_debugger->onFrame(); diff --git a/engines/mads/font.cpp b/engines/mads/font.cpp index 3e6d23fe6f..3828c3df8e 100644 --- a/engines/mads/font.cpp +++ b/engines/mads/font.cpp @@ -167,16 +167,13 @@ int Font::writeString(MSurface *surface, const Common::String &msg, const Common return x; int bottom = y + height - 1; - if (bottom > surface->getHeight() - 1) { - height -= MIN(height, bottom - (surface->getHeight() - 1)); + if (bottom > surface->h - 1) { + height -= MIN(height, bottom - (surface->h - 1)); } if (height <= 0) return x; - byte *destPtr = surface->getBasePtr(x, y); - uint8 *oldDestPtr = destPtr; - int xPos = x; const char *text = msg.c_str(); @@ -185,10 +182,11 @@ int Font::writeString(MSurface *surface, const Common::String &msg, const Common int charWidth = _charWidths[(byte)theChar]; if (charWidth > 0) { - if (xPos + charWidth > xEnd) return xPos; + Graphics::Surface dest = surface->getSubArea( + Common::Rect(xPos, y, xPos + charWidth, y + height)); uint8 *charData = &_charData[_charOffs[(byte)theChar]]; int bpp = getBpp(charWidth); @@ -196,6 +194,8 @@ int Font::writeString(MSurface *surface, const Common::String &msg, const Common charData += bpp * skipY; for (int i = 0; i < height; i++) { + byte *destPtr = (byte *)dest.getBasePtr(0, i); + for (int j = 0; j < bpp; j++) { if (*charData & 0xc0) *destPtr = _fontColors[(*charData & 0xc0) >> 6]; @@ -211,22 +211,13 @@ int Font::writeString(MSurface *surface, const Common::String &msg, const Common destPtr++; charData++; } - - destPtr += surface->getWidth() - bpp * 4; - } - - destPtr = oldDestPtr + charWidth + spaceWidth; - oldDestPtr = destPtr; - } xPos += charWidth + spaceWidth; - } return xPos; - } int Font::getWidth(const Common::String &msg, int spaceWidth) { diff --git a/engines/mads/game.cpp b/engines/mads/game.cpp index 8ebea2a3b2..0a6741ba7a 100644 --- a/engines/mads/game.cpp +++ b/engines/mads/game.cpp @@ -498,7 +498,7 @@ void Game::loadGame(int slotNumber) { _scene._currentSceneId = -2; _sectionNumber = _scene._nextSceneId / 100; _scene._frameStartTime = _vm->_events->getFrameCounter(); - _vm->_screen._shakeCountdown = -1; + _vm->_screen->_shakeCountdown = -1; // Default the selected inventory item to the first one, if the player has any _scene._userInterface._selectedInvIndex = _objects._inventoryList.size() > 0 ? 0 : -1; @@ -600,7 +600,8 @@ void Game::createThumbnail() { uint8 thumbPalette[PALETTE_SIZE]; _vm->_palette->grabPalette(thumbPalette, 0, PALETTE_COUNT); _saveThumb = new Graphics::Surface(); - ::createThumbnail(_saveThumb, _vm->_screen.getData(), MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT, thumbPalette); + ::createThumbnail(_saveThumb, (const byte *)_vm->_screen->getPixels(), + MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT, thumbPalette); } void Game::syncTimers(SyncType slaveType, int slaveId, SyncType masterType, int masterId) { diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp index 963a35c24c..29bcd10094 100644 --- a/engines/mads/mads.cpp +++ b/engines/mads/mads.cpp @@ -94,22 +94,15 @@ void MADSEngine::initialize() { _palette = new Palette(this); Font::init(this); _font = new Font(); - _screen.init(); + _screen = new Screen(); _sound = new SoundManager(this, _mixer); _audio = new AudioPlayer(_mixer, getGameID()); _game = Game::init(this); - - switch (getGameID()) { - case GType_RexNebular: - _gameConv = nullptr; - break; - default: - _gameConv = new GameConversations(this); - } + _gameConv = new GameConversations(this); loadOptions(); - _screen.empty(); + _screen->clear(); } void MADSEngine::loadOptions() { diff --git a/engines/mads/mads.h b/engines/mads/mads.h index eb808de32f..52f71f7c79 100644 --- a/engines/mads/mads.h +++ b/engines/mads/mads.h @@ -100,7 +100,7 @@ public: GameConversations * _gameConv; Palette *_palette; Resources *_resources; - ScreenSurface _screen; + Screen *_screen; SoundManager *_sound; AudioPlayer *_audio; bool _easyMouse; diff --git a/engines/mads/menu_views.cpp b/engines/mads/menu_views.cpp index 10d5a2179a..9050ca6081 100644 --- a/engines/mads/menu_views.cpp +++ b/engines/mads/menu_views.cpp @@ -253,7 +253,7 @@ void TextView::processCommand() { SceneInfo *sceneInfo = SceneInfo::init(_vm); sceneInfo->_width = MADS_SCREEN_WIDTH; sceneInfo->_height = MADS_SCENE_HEIGHT; - _spareScreens[spareIndex].setSize(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT); + _spareScreens[spareIndex].create(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT); sceneInfo->loadMadsV1Background(screenId, "", SCENEFLAG_TRANSLATE, _spareScreens[spareIndex]); @@ -346,9 +346,11 @@ void TextView::doFrame() { // If a screen transition is in progress and it's time for another column, handle it if (_spareScreen) { - byte *srcP = _spareScreen->getBasePtr(_translationX, 0); - byte *bgP = scene._backgroundSurface.getBasePtr(_translationX, 0); - byte *screenP = (byte *)_vm->_screen.getBasePtr(_translationX, 0); + const byte *srcP = (const byte *)_spareScreen->getBasePtr(_translationX, 0); + byte *bgP = (byte *)scene._backgroundSurface.getBasePtr(_translationX, 0); + + Graphics::Surface dest = _vm->_screen->getSubArea(Common::Rect(_translationX, 0, _translationX + 1, 0)); + byte *screenP = (byte *)dest.getBasePtr(0, 0); for (int y = 0; y < MADS_SCENE_HEIGHT; ++y, srcP += MADS_SCREEN_WIDTH, bgP += MADS_SCREEN_WIDTH, screenP += MADS_SCREEN_WIDTH) { @@ -356,10 +358,6 @@ void TextView::doFrame() { *screenP = *srcP; } - // Flag the column of the screen is modified - _vm->_screen.copyRectToScreen(Common::Rect(_translationX, 0, - _translationX + 1, MADS_SCENE_HEIGHT)); - // Keep moving the column to copy to the right if (++_translationX == MADS_SCREEN_WIDTH) { // Surface transition is complete @@ -571,6 +569,7 @@ void AnimationView::doFrame() { void AnimationView::loadNextResource() { Scene &scene = _vm->_game->_scene; Palette &palette = *_vm->_palette; + Screen &screen = *_vm->_screen; ResourceEntry &resEntry = _resources[_resourceIndex]; Common::Array<PaletteCycle> paletteCycles; @@ -587,12 +586,15 @@ void AnimationView::loadNextResource() { // Handle the bars at the top/bottom if (resEntry._showWhiteBars) { // For animations the screen has been clipped to the middle 156 rows. - // So although it's slightly messy, bypass our screen class entirely, - // and draw the horizontal lines directly on the physiacl screen surface - Graphics::Surface *s = g_system->lockScreen(); - s->hLine(0, 20, MADS_SCREEN_WIDTH, 253); - s->hLine(0, 179, MADS_SCREEN_WIDTH, 253); - g_system->unlockScreen(); + // So although it's slightly messy, temporarily reset clip bounds + // so we can redraw the white lines + Common::Rect clipBounds = screen.getClipBounds(); + screen.resetClipBounds(); + + screen.hLine(0, 20, MADS_SCREEN_WIDTH, 253); + screen.hLine(0, 179, MADS_SCREEN_WIDTH, 253); + + screen.setClipBounds(clipBounds); } // Load the new animation diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp index f768624278..40c69c0f08 100644 --- a/engines/mads/msurface.cpp +++ b/engines/mads/msurface.cpp @@ -32,37 +32,6 @@ namespace MADS { MADSEngine *MSurface::_vm = nullptr; -MSurface::MSurface() { - pixels = nullptr; - _freeFlag = false; -} - -MSurface::MSurface(int width, int height) { - pixels = nullptr; - _freeFlag = false; - setSize(width, height); -} - -MSurface::~MSurface() { - if (_freeFlag) - Graphics::Surface::free(); -} - -void MSurface::setSize(int width, int height) { - if (_freeFlag) - Graphics::Surface::free(); - Graphics::Surface::create(width, height, Graphics::PixelFormat::createFormatCLUT8()); - _freeFlag = true; -} - -void MSurface::setPixels(byte *pData, int horizSize, int vertSize) { - _freeFlag = false; - pixels = pData; - w = pitch = horizSize; - h = vertSize; - format.bytesPerPixel = 1; -} - int MSurface::scaleValue(int value, int scale, int err) { int scaled = 0; while (value--) { @@ -76,7 +45,6 @@ int MSurface::scaleValue(int value, int scale, int err) { } void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Common::Rect &clipRect) { - enum { kStatusSkip, kStatusScale, @@ -116,8 +84,8 @@ void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Commo return; int heightAmt = scaledHeight; - byte *src = info.sprite->getData(); - byte *dst = getBasePtr(x - info.hotX - clipX, y - info.hotY - clipY); + const byte *src = (const byte *)info.sprite->getPixels(); + byte *dst = (byte *)getBasePtr(x - info.hotX - clipX, y - info.hotY - clipY); int status = kStatusSkip; byte *scaledLineBuf = new byte[scaledWidth]; @@ -138,7 +106,7 @@ void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Commo byte *lineDst = scaledLineBuf; int curErrX = errX; int width = scaledWidth; - byte *tempSrc = src; + const byte *tempSrc = src; int startX = clipX; while (width > 0) { byte pixel = *tempSrc++; @@ -201,63 +169,136 @@ void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Commo } delete[] scaledLineBuf; - } -void MSurface::empty() { - Common::fill(getBasePtr(0, 0), getBasePtr(0, h), 0); +void MSurface::scrollX(int xAmount) { + if (xAmount == 0) + return; + + byte buffer[80]; + int direction = (xAmount > 0) ? -1 : 1; + int xSize = ABS(xAmount); + assert(xSize <= 80); + + byte *srcP = (byte *)getBasePtr(0, 0); + + for (int y = 0; y < this->h; ++y, srcP += pitch) { + if (direction < 0) { + // Copy area to be overwritten + Common::copy(srcP, srcP + xSize, &buffer[0]); + // Shift the remainder of the line over the given area + Common::copy(srcP + xSize, srcP + this->w, srcP); + // Move buffered area to the end of the line + Common::copy(&buffer[0], &buffer[xSize], srcP + this->w - xSize); + } else { + // Copy area to be overwritten + Common::copy_backward(srcP + this->w - xSize, srcP + this->w, &buffer[80]); + // Shift the remainder of the line over the given area + Common::copy_backward(srcP, srcP + this->w - xSize, srcP + this->w); + // Move buffered area to the start of the line + Common::copy_backward(&buffer[80 - xSize], &buffer[80], srcP + xSize); + } + } + + markAllDirty(); } -void MSurface::copyFrom(MSurface *src, const Common::Rect &srcBounds, - const Common::Point &destPos, int transparentColor) { - // Validation of the rectangle and position - int destX = destPos.x, destY = destPos.y; - if ((destX >= w) || (destY >= h)) +void MSurface::scrollY(int yAmount) { + if (yAmount == 0) return; - Common::Rect copyRect = srcBounds; - if (destX < 0) { - copyRect.left += -destX; - destX = 0; - } else if (destX + copyRect.width() > w) { - copyRect.right -= destX + copyRect.width() - w; - } - if (destY < 0) { - copyRect.top += -destY; - destY = 0; - } else if (destY + copyRect.height() > h) { - copyRect.bottom -= destY + copyRect.height() - h; + int direction = (yAmount > 0) ? 1 : -1; + int ySize = ABS(yAmount); + assert(ySize < (this->h / 2)); + assert(this->w == pitch); + + int blockSize = ySize * this->w; + byte *tempData = new byte[blockSize]; + byte *pixelsP = (byte *)getBasePtr(0, 0); + + if (direction > 0) { + // Buffer the lines to be overwritten + byte *srcP = (byte *)getBasePtr(0, this->h - ySize); + Common::copy(srcP, srcP + (pitch * ySize), tempData); + // Vertically shift all the lines + Common::copy_backward(pixelsP, pixelsP + (pitch * (this->h - ySize)), + pixelsP + (pitch * this->h)); + // Transfer the buffered lines top the top of the screen + Common::copy(tempData, tempData + blockSize, pixelsP); + } else { + // Buffer the lines to be overwritten + Common::copy(pixelsP, pixelsP + (pitch * ySize), tempData); + // Vertically shift all the lines + Common::copy(pixelsP + (pitch * ySize), pixelsP + (pitch * this->h), pixelsP); + // Transfer the buffered lines to the bottom of the screen + Common::copy(tempData, tempData + blockSize, pixelsP + (pitch * (this->h - ySize))); } - if (!copyRect.isValidRect()) - return; + markAllDirty(); + delete[] tempData; +} - // Copy the specified area +void MSurface::translate(Common::Array<RGB6> &palette) { + for (int y = 0; y < this->h; ++y) { + byte *pDest = (byte *)getBasePtr(0, y); + + for (int x = 0; x < this->w; ++x, ++pDest) { + if (*pDest < 255) // scene 752 has some palette indices of 255 + *pDest = palette[*pDest]._palIndex; + } + } - byte *data = src->getData(); - byte *srcPtr = data + (src->getWidth() * copyRect.top + copyRect.left); - byte *destPtr = (byte *)pixels + (destY * getWidth()) + destX; + markAllDirty(); +} - for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) { - if (transparentColor == -1) { - // No transparency, so copy line over - Common::copy(srcPtr, srcPtr + copyRect.width(), destPtr); - } else { - // Copy each byte one at a time checking for the transparency color - for (int xCtr = 0; xCtr < copyRect.width(); ++xCtr) - if (srcPtr[xCtr] != transparentColor) destPtr[xCtr] = srcPtr[xCtr]; +void MSurface::translate(byte map[PALETTE_COUNT]) { + for (int y = 0; y < this->h; ++y) { + byte *pDest = (byte *)getBasePtr(0, y); + + for (int x = 0; x < this->w; ++x, ++pDest) { + *pDest = map[*pDest]; } + } + + markAllDirty(); +} + +MSurface *MSurface::flipHorizontal() const { + MSurface *dest = new MSurface(this->w, this->h); + + for (int y = 0; y < this->h; ++y) { + const byte *srcP = getBasePtr(this->w - 1, y); + byte *destP = dest->getBasePtr(0, y); - srcPtr += src->getWidth(); - destPtr += getWidth(); + for (int x = 0; x < this->w; ++x) + *destP++ = *srcP--; + } + + return dest; +} + +void MSurface::copyRectTranslate(MSurface &srcSurface, const byte *paletteMap, + const Common::Point &destPos, const Common::Rect &srcRect) { + // Loop through the lines + for (int yCtr = 0; yCtr < srcRect.height(); ++yCtr) { + const byte *srcP = (const byte *)srcSurface.getBasePtr(srcRect.left, srcRect.top + yCtr); + byte *destP = (byte *)getBasePtr(destPos.x, destPos.y + yCtr); + + // Copy the line over + for (int xCtr = 0; xCtr < srcRect.width(); ++xCtr, ++srcP, ++destP) { + *destP = paletteMap[*srcP]; + } } + + addDirtyRect(Common::Rect(destPos.x, destPos.y, destPos.x + srcRect.width(), + destPos.y + srcRect.height())); } -void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth, +void MSurface::copyFrom(MSurface &src, const Common::Point &destPos, int depth, DepthSurface *depthSurface, int scale, bool flipped, int transparentColor) { int destX = destPos.x, destY = destPos.y; - int frameWidth = src->getWidth(); - int frameHeight = src->getHeight(); + int frameWidth = src.w; + int frameHeight = src.h; int direction = flipped ? -1 : 1; int highestDim = MAX(frameWidth, frameHeight); @@ -271,7 +312,8 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth, distCtr += scale; if (distCtr < 100) { lineDist[distIndex] = false; - } else { + } + else { lineDist[distIndex] = true; distCtr -= 100; @@ -290,18 +332,20 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth, // Special case for quicker drawing of non-scaled images if (scale == 100 || scale == -1) { // Copy the specified area - Common::Rect copyRect(0, 0, src->getWidth(), src->getHeight()); + Common::Rect copyRect(0, 0, src.w, src.h); if (destX < 0) { copyRect.left += -destX; destX = 0; - } else if (destX + copyRect.width() > w) { + } + else if (destX + copyRect.width() > w) { copyRect.right -= destX + copyRect.width() - w; } if (destY < 0) { copyRect.top += -destY; destY = 0; - } else if (destY + copyRect.height() > h) { + } + else if (destY + copyRect.height() > h) { copyRect.bottom -= destY + copyRect.height() - h; } @@ -311,9 +355,9 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth, if (flipped) copyRect.moveTo(0, copyRect.top); - byte *data = src->getData(); - byte *srcPtr = data + (src->getWidth() * copyRect.top + copyRect.left); - byte *destPtr = (byte *)pixels + (destY * pitch) + destX; + byte *data = src.getPixels(); + byte *srcPtr = data + (src.w * copyRect.top + copyRect.left); + byte *destPtr = (byte *)getPixels() + (destY * pitch) + destX; if (flipped) srcPtr += copyRect.width() - 1; @@ -329,18 +373,18 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth, destPtr[xCtr] = *srcP; } - srcPtr += src->getWidth(); - destPtr += getWidth(); + srcPtr += src.w; + destPtr += this->w; } return; } // Start of draw logic for scaled sprites - const byte *srcPixelsP = src->getData(); + const byte *srcPixelsP = src.getPixels(); - int destRight = this->getWidth() - 1; - int destBottom = this->getHeight() - 1; + int destRight = this->w - 1; + int destBottom = this->h - 1; // Check x bounding area int spriteLeft = 0; @@ -387,7 +431,7 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth, spriteLeft = spriteLeft * direction; // Loop through the lines of the sprite - for (int yp = 0, sprY = -1; yp < frameHeight; ++yp, srcPixelsP += src->pitch) { + for (int yp = 0, sprY = -1; yp < frameHeight; ++yp, srcPixelsP += src.pitch) { if (!lineDist[yp]) // Not a display line, so skip it continue; @@ -411,8 +455,8 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth, continue; // Get depth of current output pixel in depth surface - Common::Point pt((destP - (byte *)this->pixels) % this->pitch, - (destP - (byte *)this->pixels) / this->pitch); + Common::Point pt((destP - (byte *)getPixels()) % this->pitch, + (destP - (byte *)getPixels()) / this->pitch); int pixelDepth = (depthSurface == nullptr) ? 15 : depthSurface->getDepth(pt); if ((*srcP != transparentColor) && (depth <= pixelDepth)) @@ -424,119 +468,8 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth, // Move to the next destination line destPixelsP += this->pitch; } -} - -void MSurface::scrollX(int xAmount) { - if (xAmount == 0) - return; - - byte buffer[80]; - int direction = (xAmount > 0) ? -1 : 1; - int xSize = ABS(xAmount); - assert(xSize <= 80); - - byte *srcP = getBasePtr(0, 0); - - for (int y = 0; y < this->h; ++y, srcP += pitch) { - if (direction < 0) { - // Copy area to be overwritten - Common::copy(srcP, srcP + xSize, &buffer[0]); - // Shift the remainder of the line over the given area - Common::copy(srcP + xSize, srcP + this->w, srcP); - // Move buffered area to the end of the line - Common::copy(&buffer[0], &buffer[xSize], srcP + this->w - xSize); - } else { - // Copy area to be overwritten - Common::copy_backward(srcP + this->w - xSize, srcP + this->w, &buffer[80]); - // Shift the remainder of the line over the given area - Common::copy_backward(srcP, srcP + this->w - xSize, srcP + this->w); - // Move buffered area to the start of the line - Common::copy_backward(&buffer[80 - xSize], &buffer[80], srcP + xSize); - } - } -} - -void MSurface::scrollY(int yAmount) { - if (yAmount == 0) - return; - - int direction = (yAmount > 0) ? 1 : -1; - int ySize = ABS(yAmount); - assert(ySize < (this->h / 2)); - assert(this->w == pitch); - - int blockSize = ySize * this->w; - byte *tempData = new byte[blockSize]; - byte *pixelsP = getBasePtr(0, 0); - - if (direction > 0) { - // Buffer the lines to be overwritten - byte *srcP = (byte *)getBasePtr(0, this->h - ySize); - Common::copy(srcP, srcP + (pitch * ySize), tempData); - // Vertically shift all the lines - Common::copy_backward(pixelsP, pixelsP + (pitch * (this->h - ySize)), - pixelsP + (pitch * this->h)); - // Transfer the buffered lines top the top of the screen - Common::copy(tempData, tempData + blockSize, pixelsP); - } else { - // Buffer the lines to be overwritten - Common::copy(pixelsP, pixelsP + (pitch * ySize), tempData); - // Vertically shift all the lines - Common::copy(pixelsP + (pitch * ySize), pixelsP + (pitch * this->h), pixelsP); - // Transfer the buffered lines to the bottom of the screen - Common::copy(tempData, tempData + blockSize, pixelsP + (pitch * (this->h - ySize))); - } - - delete[] tempData; -} - -void MSurface::translate(Common::Array<RGB6> &palette) { - for (int y = 0; y < this->h; ++y) { - byte *pDest = getBasePtr(0, y); - - for (int x = 0; x < this->w; ++x, ++pDest) { - if (*pDest < 255) // scene 752 has some palette indices of 255 - *pDest = palette[*pDest]._palIndex; - } - } -} - -void MSurface::translate(byte map[PALETTE_COUNT]) { - for (int y = 0; y < this->h; ++y) { - byte *pDest = getBasePtr(0, y); - - for (int x = 0; x < this->w; ++x, ++pDest) { - *pDest = map[*pDest]; - } - } -} - -MSurface *MSurface::flipHorizontal() const { - MSurface *dest = new MSurface(this->w, this->h); - - for (int y = 0; y < this->h; ++y) { - const byte *srcP = getBasePtr(this->w - 1, y); - byte *destP = dest->getBasePtr(0, y); - - for (int x = 0; x < this->w; ++x) - *destP++ = *srcP--; - } - - return dest; -} - -void MSurface::copyRectTranslate(MSurface &srcSurface, const byte *paletteMap, - const Common::Point &destPos, const Common::Rect &srcRect) { - // Loop through the lines - for (int yCtr = 0; yCtr < srcRect.height(); ++yCtr) { - const byte *srcP = srcSurface.getBasePtr(srcRect.left, srcRect.top + yCtr); - byte *destP = getBasePtr(destPos.x, destPos.y + yCtr); - // Copy the line over - for (int xCtr = 0; xCtr < srcRect.width(); ++xCtr, ++srcP, ++destP) { - *destP = paletteMap[*srcP]; - } - } + addDirtyRect(Common::Rect(destX, destY, destX + frameWidth, destY + frameHeight)); } /*------------------------------------------------------------------------*/ @@ -544,26 +477,26 @@ void MSurface::copyRectTranslate(MSurface &srcSurface, const byte *paletteMap, int DepthSurface::getDepth(const Common::Point &pt) { if (_depthStyle == 2) { int bits = (3 - (pt.x % 4)) * 2; - byte v = *getBasePtr(pt.x >> 2, pt.y); + byte v = *(const byte *)getBasePtr(pt.x >> 2, pt.y); return v >> bits; } else { if (pt.x < 0 || pt.y < 0 || pt.x >= this->w || pt.y >= this->h) return 0; - return *getBasePtr(pt.x, pt.y) & 0xF; + return *(const byte *)getBasePtr(pt.x, pt.y) & 0xF; } } int DepthSurface::getDepthHighBit(const Common::Point &pt) { if (_depthStyle == 2) { int bits = (3 - (pt.x % 4)) * 2; - byte v = *getBasePtr(pt.x >> 2, pt.y); + byte v = *(const byte *)getBasePtr(pt.x >> 2, pt.y); return (v >> bits) & 2; } else { if (pt.x < 0 || pt.y < 0 || pt.x >= this->w || pt.y >= this->h) return 0; - return *getBasePtr(pt.x, pt.y) & 0x80; + return *(const byte *)getBasePtr(pt.x, pt.y) & 0x80; } } diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h index 80891afb83..e92770900d 100644 --- a/engines/mads/msurface.h +++ b/engines/mads/msurface.h @@ -25,7 +25,7 @@ #include "common/scummsys.h" #include "common/rect.h" -#include "graphics/surface.h" +#include "graphics/managed_surface.h" #include "mads/palette.h" namespace MADS { @@ -50,22 +50,21 @@ struct SpriteInfo { /* * MADS graphics surface */ -class MSurface : public Graphics::Surface { +class MSurface : virtual public Graphics::ManagedSurface { +private: + /** + * Helper method for calculating new dimensions when scaling a sprite + */ + int scaleValue(int value, int scale, int err); protected: static MADSEngine *_vm; - bool _freeFlag; public: /** - * Sets the engine refrence used all surfaces + * Sets the engine reference used all surfaces */ static void setVm(MADSEngine *vm) { _vm = vm; } /** - * Helper method for calculating new dimensions when scaling a sprite - */ - static int scaleValue(int value, int scale, int err); - - /** * Base method for descendents to load their contents */ virtual void load(const Common::String &resName) {} @@ -73,126 +72,50 @@ public: /** * Basic constructor */ - MSurface(); + MSurface() : Graphics::ManagedSurface() {} /** * Constructor for a surface with fixed dimensions */ - MSurface(int width, int height); + MSurface(int width, int height) : Graphics::ManagedSurface(width, height) {} /** * Destructor */ - virtual ~MSurface(); - - /** - * Reinitializes a surface to have a given set of dimensions - */ - void setSize(int width, int height); - - /** - * Sets the pixels the surface is associated with - * @remarks The surface will not free the data block - */ - void setPixels(byte *pData, int horizSize, int vertSize); - - /** - * Draws an arbitrary line on the screen using a specified color - * @param startPos Starting position - * @param endPos Ending position - * @param color Color to use - */ - void line(const Common::Point &startPos, const Common::Point &endPos, byte color); - - /** - * Draws a sprite - * @param pt Position to draw sprite at - * @param info General sprite details - * @param clipRect Clipping rectangle to constrain sprite drawing within - */ - void drawSprite(const Common::Point &pt, SpriteInfo &info, const Common::Rect &clipRect); - - /** - * Returns the width of the surface - */ - int getWidth() const { return w; } - - /** - * Returns the height of the surface - */ - int getHeight() const { return h; } + virtual ~MSurface() {} /** - * Returns the size of the surface as a Rect + * Return a rect containing the bounds of the surface */ - Common::Rect getBounds() const { - return Common::Rect(0, 0, w, h); - } + Common::Rect getBounds() { return Common::Rect(0, 0, this->w, this->h); } /** - * Returns a pointer to the surface data + * Return the pixels for the surface */ - byte *getData() { return (byte *)Graphics::Surface::getPixels(); } + inline byte *getPixels() { return (byte *)Graphics::ManagedSurface::getPixels(); } /** - * Returns a pointer to a given position within the surface + * Return the pixels for the surface */ - byte *getBasePtr(int x, int y) { return (byte *)Graphics::Surface::getBasePtr(x, y); } + inline const void *getPixels() const { return (const byte *)Graphics::ManagedSurface::getPixels(); } /** - * Returns a pointer to a given position within the surface - */ - const byte *getBasePtr(int x, int y) const { return (const byte *)Graphics::Surface::getBasePtr(x, y); } - - /** - * Clears the surface - */ - void empty(); - - /** - * Copys a sub-section of another surface into the current one. - * @param src Source surface - * @param srcBounds Area of source surface to copy - * @param destPos Destination position to draw in current surface - * @param transparentColor Transparency palette index - */ - void copyFrom(MSurface *src, const Common::Rect &srcBounds, const Common::Point &destPos, - int transparentColor = -1); - - /** - * Copys a sub-section of another surface into the current one. - * @param src Source surface - * @param destPos Destination position to draw in current surface - * @param depth Depth of sprite - * @param depthSurface Depth surface to use with sprite depth - * @param scale Scale for image - * @param flipped Flag for whether image is to be flipped - * @param transparentColor Transparency palette index - */ - void copyFrom(MSurface *src, const Common::Point &destPos, int depth, DepthSurface *depthSurface, - int scale, bool flipped, int transparentColor = -1); - - /** - * Copies the surface to a given destination surface + * Return a pointer to a given position on the surface */ - void copyTo(MSurface *dest, int transparentColor = -1) { - dest->copyFrom(this, Common::Rect(w, h), Common::Point(), transparentColor); - } + byte *getBasePtr(int x, int y) { return (byte *)Graphics::ManagedSurface::getBasePtr(x, y); } /** - * Copies the surface to a given destination surface + * Return a pointer to a given position on the surface */ - void copyTo(MSurface *dest, const Common::Point &pt, int transparentColor = -1) { - dest->copyFrom(this, Common::Rect(w, h), pt, transparentColor); - } + inline const byte *getBasePtr(int x, int y) const { return (const byte *)Graphics::ManagedSurface::getBasePtr(x, y); } /** - * Copies the surface to a given destination surface + * Draws a sprite + * @param pt Position to draw sprite at + * @param info General sprite details + * @param clipRect Clipping rectangle to constrain sprite drawing within */ - void copyTo(MSurface *dest, const Common::Rect &srcBounds, const Common::Point &destPos, - int transparentColor = -1) { - dest->copyFrom(this, srcBounds, destPos, transparentColor); - } + void drawSprite(const Common::Point &pt, SpriteInfo &info, const Common::Rect &clipRect); /** * Scroll the screen horizontally by a given amount @@ -227,6 +150,19 @@ public: */ void copyRectTranslate(MSurface &srcSurface, const byte *paletteMap, const Common::Point &destPos, const Common::Rect &srcRect); + + /** + * Copys a sub-section of another surface into the current one. + * @param src Source surface + * @param destPos Destination position to draw in current surface + * @param depth Depth of sprite + * @param depthSurface Depth surface to use with sprite depth + * @param scale Scale for image + * @param flipped Flag for whether image is to be flipped + * @param transparentColor Transparency palette index + */ + void copyFrom(MSurface &src, const Common::Point &destPos, int depth, DepthSurface *depthSurface, + int scale, bool flipped, int transparentColor = -1); }; class DepthSurface : public MSurface { @@ -239,7 +175,7 @@ public: /** * Constructor */ - DepthSurface() : _depthStyle(0) {} + DepthSurface() : MSurface(), _depthStyle(0) {} /** * Returns the depth at a given position diff --git a/engines/mads/nebular/dialogs_nebular.cpp b/engines/mads/nebular/dialogs_nebular.cpp index 58e60fe323..2af80f517e 100644 --- a/engines/mads/nebular/dialogs_nebular.cpp +++ b/engines/mads/nebular/dialogs_nebular.cpp @@ -438,11 +438,10 @@ void CopyProtectionDialog::show() { Common::KeyState curKey; const Common::Rect inputArea(110, 165, 210, 175); MSurface *origInput = new MSurface(inputArea.width(), inputArea.height()); - _vm->_screen.frameRect(inputArea, TEXTDIALOG_BLACK); - _vm->_screen.copyTo(origInput, inputArea, Common::Point(0, 0)); - _font->setColors(TEXTDIALOG_FE, TEXTDIALOG_FE, TEXTDIALOG_FE, TEXTDIALOG_FE); - _vm->_screen.copyRectToScreen(inputArea); - _vm->_screen.updateScreen(); + _vm->_screen->frameRect(inputArea, TEXTDIALOG_BLACK); + origInput->blitFrom(*_vm->_screen, inputArea, Common::Point(0, 0)); + _font->setColors(TEXTDIALOG_FE, TEXTDIALOG_FE, TEXTDIALOG_FE, TEXTDIALOG_FE); + _vm->_screen->update(); bool firstTime = true; @@ -470,11 +469,10 @@ void CopyProtectionDialog::show() { _textInput = _hogEntry._word[0]; } - _vm->_screen.copyFrom(origInput, Common::Rect(0, 0, inputArea.width(), inputArea.height()), Common::Point(inputArea.left, inputArea.top)); - _font->writeString(&_vm->_screen, _textInput, + _vm->_screen->blitFrom(*origInput, Common::Point(inputArea.left, inputArea.top)); + _font->writeString(_vm->_screen, _textInput, Common::Point(inputArea.left + 2, inputArea.top + 1), 1); - _vm->_screen.copyRectToScreen(inputArea); - _vm->_screen.updateScreen(); + _vm->_screen->update(); } origInput->free(); @@ -537,7 +535,7 @@ void PictureDialog::save() { // Save the entire screen _savedSurface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT); - _vm->_screen.copyTo(_savedSurface); + _savedSurface->blitFrom(*_vm->_screen); // Save palette information Common::copy(&palette._mainPalette[0], &palette._mainPalette[PALETTE_SIZE], &_palette[0]); @@ -568,7 +566,7 @@ void PictureDialog::save() { // Remap the greyed out screen to use the small greyscale range // at the top end of the palette - _vm->_screen.translate(map); + _vm->_screen->translate(map); // Load the inventory picture Common::String setName = Common::String::format("*OB%.3d.SS", _objectId); @@ -578,13 +576,12 @@ void PictureDialog::save() { // Get the inventory frame, and adjust the dialog position to allow for it MSprite *frame = asset->getFrame(0); _position.y = frame->h + 12; - if ((_position.y + _height) > _vm->_screen.getHeight()) - _position.y -= (_position.y + _height) - _vm->_screen.getHeight(); + if ((_position.y + _height) > _vm->_screen->h) + _position.y -= (_position.y + _height) - _vm->_screen->h; // Draw the inventory picture - frame->copyTo(&_vm->_screen, Common::Point(160 - frame->w / 2, 6), + _vm->_screen->transBlitFrom(*frame, Common::Point(160 - frame->w / 2, 6), frame->getTransparencyIndex()); - _vm->_screen.copyRectToScreen(_vm->_screen.getBounds()); // Adjust the dialog colors to use TEXTDIALOG_CONTENT1 -= 10; @@ -598,13 +595,11 @@ void PictureDialog::save() { void PictureDialog::restore() { if (_savedSurface) { - _savedSurface->copyTo(&_vm->_screen); + _vm->_screen->blitFrom(*_savedSurface); _savedSurface->free(); delete _savedSurface; _savedSurface = nullptr; - _vm->_screen.copyRectToScreen(_vm->_screen.getBounds()); - // Restore palette information Palette &palette = *_vm->_palette; Common::copy(&_palette[0], &_palette[PALETTE_SIZE], &palette._mainPalette[0]); @@ -691,7 +686,6 @@ void GameDialog::display() { } GameDialog::~GameDialog() { - _vm->_screen.resetClipBounds(); _vm->_game->_scene._currentSceneId = RETURNING_FROM_DIALOG; } diff --git a/engines/mads/nebular/game_nebular.cpp b/engines/mads/nebular/game_nebular.cpp index 9c0acf1a47..1db5eaea00 100644 --- a/engines/mads/nebular/game_nebular.cpp +++ b/engines/mads/nebular/game_nebular.cpp @@ -827,49 +827,51 @@ void GameNebular::step() { if (_player._visible && _player._stepEnabled && !_player._moving && (_player._facing == _player._turnToFacing)) { if (_scene._frameStartTime >= (uint32)_globals[kWalkerTiming]) { - int randomVal = _vm->getRandomNumber(29999); - if (_globals[kSexOfRex] == REX_MALE) { - switch (_player._facing) { - case FACING_SOUTHWEST: - case FACING_SOUTHEAST: - case FACING_NORTHWEST: - case FACING_NORTHEAST: - if (randomVal < 200) { - _player.addWalker(-1, 0); - _player.addWalker(1, 0); - } - break; - - case FACING_WEST: - case FACING_EAST: - if (randomVal < 500) { - for (int count = 0; count < 10; ++count) { + if (_player._stopWalkers.empty()) { + int randomVal = _vm->getRandomNumber(29999); + if (_globals[kSexOfRex] == REX_MALE) { + switch (_player._facing) { + case FACING_SOUTHWEST: + case FACING_SOUTHEAST: + case FACING_NORTHWEST: + case FACING_NORTHEAST: + if (randomVal < 200) { + _player.addWalker(-1, 0); _player.addWalker(1, 0); } - } - break; - - case FACING_SOUTH: - if (randomVal < 500) { - for (int count = 0; count < 10; ++count) { - _player.addWalker((randomVal < 250) ? 1 : 2, 0); + break; + + case FACING_WEST: + case FACING_EAST: + if (randomVal < 500) { + for (int count = 0; count < 10; ++count) { + _player.addWalker(1, 0); + } } - } else if (randomVal < 750) { - for (int count = 0; count < 5; ++count) { - _player.addWalker(1, 0); + break; + + case FACING_SOUTH: + if (randomVal < 500) { + for (int count = 0; count < 10; ++count) { + _player.addWalker((randomVal < 250) ? 1 : 2, 0); + } + } else if (randomVal < 750) { + for (int count = 0; count < 5; ++count) { + _player.addWalker(1, 0); + } + + _player.addWalker(0, 0); + _player.addWalker(0, 0); + + for (int count = 0; count < 5; ++count) { + _player.addWalker(2, 0); + } } + break; - _player.addWalker(0, 0); - _player.addWalker(0, 0); - - for (int count = 0; count < 5; ++count) { - _player.addWalker(2, 0); - } + default: + break; } - break; - - default: - break; } } diff --git a/engines/mads/nebular/menu_nebular.cpp b/engines/mads/nebular/menu_nebular.cpp index 0520294b29..cd81efe0f0 100644 --- a/engines/mads/nebular/menu_nebular.cpp +++ b/engines/mads/nebular/menu_nebular.cpp @@ -384,8 +384,8 @@ void AdvertView::show() { // Load the advert background onto the screen SceneInfo *sceneInfo = SceneInfo::init(_vm); sceneInfo->load(screenId, 0, Common::String(), 0, _vm->_game->_scene._depthSurface, - _vm->_screen); - _vm->_screen.copyRectToScreen(_vm->_screen.getBounds()); + *_vm->_screen); + _vm->_screen->markAllDirty(); _vm->_palette->setFullPalette(_vm->_palette->_mainPalette); delete sceneInfo; diff --git a/engines/mads/nebular/nebular_scenes.cpp b/engines/mads/nebular/nebular_scenes.cpp index da419a70a2..40228b4b7d 100644 --- a/engines/mads/nebular/nebular_scenes.cpp +++ b/engines/mads/nebular/nebular_scenes.cpp @@ -323,8 +323,8 @@ void SceneInfoNebular::loadCodes(MSurface &depthSurface, int variant) { } void SceneInfoNebular::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) { - byte *destP = depthSurface.getData(); - byte *endP = depthSurface.getBasePtr(0, depthSurface.h); + byte *destP = (byte *)depthSurface.getPixels(); + byte *endP = (byte *)depthSurface.getBasePtr(0, depthSurface.h); byte runLength = stream->readByte(); while (destP < endP && runLength > 0) { diff --git a/engines/mads/nebular/nebular_scenes3.cpp b/engines/mads/nebular/nebular_scenes3.cpp index 0fb13a706c..7323ee893d 100644 --- a/engines/mads/nebular/nebular_scenes3.cpp +++ b/engines/mads/nebular/nebular_scenes3.cpp @@ -2818,7 +2818,7 @@ void Scene318::step() { if (_internCounter >= 3600) { _vm->_sound->command(59); - _vm->_screen._shakeCountdown = 20; + _vm->_screen->_shakeCountdown = 20; _internWalkingFl = true; } } @@ -3288,22 +3288,22 @@ void Scene319::step() { if (_animMode == 2) { if (_animFrame == 13) - _vm->_screen._shakeCountdown = 40; + _vm->_screen->_shakeCountdown = 40; if (_animFrame == 16) - _vm->_screen._shakeCountdown = 1; + _vm->_screen->_shakeCountdown = 1; } if (_animMode == 3) { if (_animFrame == 11) - _vm->_screen._shakeCountdown = 60; + _vm->_screen->_shakeCountdown = 60; if (_animFrame == 18) - _vm->_screen._shakeCountdown = 1; + _vm->_screen->_shakeCountdown = 1; } if ((_animMode == 4) && (_animFrame == 16)) - _vm->_screen._shakeCountdown = 80; + _vm->_screen->_shakeCountdown = 80; if ((nextFrame >= 0) && (nextFrame != _scene->_animation[0]->getCurrentFrame())) { _scene->_animation[0]->setCurrentFrame(nextFrame); @@ -3326,7 +3326,7 @@ void Scene319::step() { _animFrame = _scene->_animation[0]->getCurrentFrame(); _slacheTalkingFl = true; - _vm->_screen._shakeCountdown = 1; + _vm->_screen->_shakeCountdown = 1; for (int i = 0; i <= 1; i++) { int oldIdx = _globals._sequenceIndexes[i]; @@ -3350,7 +3350,7 @@ void Scene319::step() { _vm->_palette->setColorValues(0, 0, 0); _vm->_palette->fadeOut(_vm->_palette->_mainPalette, nullptr, 18, 228, 248, 0, 1, 16); - _vm->_screen._shakeCountdown = 1; + _vm->_screen->_shakeCountdown = 1; _scene->_reloadSceneFlag = true; break; @@ -3731,7 +3731,7 @@ void Scene320::step() { case 417: case 457: - _vm->_screen._shakeCountdown = 40; + _vm->_screen->_shakeCountdown = 40; _vm->_sound->command(59); break; diff --git a/engines/mads/nebular/nebular_scenes5.cpp b/engines/mads/nebular/nebular_scenes5.cpp index 3778a59eb3..ea3574b0d1 100644 --- a/engines/mads/nebular/nebular_scenes5.cpp +++ b/engines/mads/nebular/nebular_scenes5.cpp @@ -1603,7 +1603,7 @@ void Scene508::enter() { _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2); _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 8); _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, -2); - int idx = _scene->_dynamicHotspots.add(NOUN_LASER_BEAM, VERB_WALKTO, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0)); + int idx = _scene->_dynamicHotspots.add(NOUN_SPINACH_PATCH_DOLL, VERB_WALKTO, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0)); _scene->_dynamicHotspots.setPosition(idx, Common::Point(57, 116), FACING_NORTHEAST); _scene->_hotspots.activate(NOUN_HOLE, false); _scene->_hotspots.activate(NOUN_LASER_BEAM, false); diff --git a/engines/mads/phantom/phantom_scenes.cpp b/engines/mads/phantom/phantom_scenes.cpp index f7a7153fbe..7ef627ceeb 100644 --- a/engines/mads/phantom/phantom_scenes.cpp +++ b/engines/mads/phantom/phantom_scenes.cpp @@ -191,7 +191,7 @@ void SceneInfoPhantom::loadCodes(MSurface &depthSurface, int variant) { } void SceneInfoPhantom::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) { - byte *destP = depthSurface.getData(); + byte *destP = (byte *)depthSurface.getPixels(); byte *walkMap = new byte[stream->size()]; stream->read(walkMap, stream->size()); diff --git a/engines/mads/rails.cpp b/engines/mads/rails.cpp index ee0ca98cd3..46d9e0ebd3 100644 --- a/engines/mads/rails.cpp +++ b/engines/mads/rails.cpp @@ -149,7 +149,7 @@ int Rails::scanPath(const Common::Point &srcPos, const Common::Point &destPos) { ++xDiff; ++yDiff; - const byte *srcP = _depthSurface->getBasePtr(srcPos.x, srcPos.y); + const byte *srcP = (const byte *)_depthSurface->getBasePtr(srcPos.x, srcPos.y); int index = xAmount; // Outer loop diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp index 83ab1151a9..66f56f9407 100644 --- a/engines/mads/scene.cpp +++ b/engines/mads/scene.cpp @@ -89,8 +89,7 @@ Scene::~Scene() { } void Scene::restrictScene() { - _sceneSurface.init(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH, - _vm->_screen.getPixels(), Graphics::PixelFormat::createFormatCLUT8()); + _sceneSurface.create(*_vm->_screen, Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT)); } void Scene::clearVocab() { @@ -517,7 +516,7 @@ void Scene::drawElements(ScreenTransition transitionType, bool surfaceFlag) { if (_posAdjust != Common::Point(0, 0)) warning("Adjust used %d %d", _posAdjust.x, _posAdjust.y); // Copy background for the dirty areas to the screen - _dirtyAreas.copy(&_backgroundSurface, &_vm->_screen, _posAdjust); + _dirtyAreas.copy(&_backgroundSurface, _vm->_screen, _posAdjust); // Handle dirty areas for foreground objects _spriteSlots.setDirtyAreas(); @@ -528,11 +527,11 @@ void Scene::drawElements(ScreenTransition transitionType, bool surfaceFlag) { _spriteSlots.drawSprites(&_sceneSurface); // Draw text elements onto the view - _textDisplay.draw(&_vm->_screen); + _textDisplay.draw(_vm->_screen); if (transitionType) { // Fading in the screen - _vm->_screen.transition(transitionType, surfaceFlag); + _vm->_screen->transition(transitionType, surfaceFlag); _vm->_sound->startQueuedCommands(); } else { // Copy dirty areas to the screen diff --git a/engines/mads/scene_data.cpp b/engines/mads/scene_data.cpp index 7b0e64c1fe..5323178ec7 100644 --- a/engines/mads/scene_data.cpp +++ b/engines/mads/scene_data.cpp @@ -242,13 +242,13 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName, int height = _height; if (!bgSurface.getPixels() || (bgSurface.w != width) || (bgSurface.h != height)) { - bgSurface.setSize(width, height); + bgSurface.create(width, height); } if (_depthStyle == 2) width >>= 2; if (!depthSurface.getPixels()) { - depthSurface.setSize(width, height); + depthSurface.create(width, height); } loadCodes(depthSurface, variant); @@ -288,7 +288,7 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName, assert(asset && _depthStyle != 2); MSprite *spr = asset->getFrame(si._frameNumber); - bgSurface.copyFrom(spr, si._position, si._depth, &depthSurface, + bgSurface.copyFrom(*spr, si._position, si._depth, &depthSurface, si._scale, false, spr->getTransparencyIndex()); } @@ -455,7 +455,7 @@ void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName, newHeight = tileCount * tileHeight; if (bgSurface.w != newWidth || bgSurface.h != newHeight) - bgSurface.setSize(newWidth, newHeight); + bgSurface.create(newWidth, newHeight); // -------------------------------------------------------------------------------- @@ -477,7 +477,7 @@ void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName, //debugCN(kDebugGraphics, "Tile: %i, compressed size: %i\n", i, compressedTileDataSize); - newTile->empty(); + newTile->clear(); byte *compressedTileData = new byte[compressedTileDataSize]; @@ -503,7 +503,8 @@ void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName, TileSetIterator tile = tileSet.begin(); for (int i = 0; i < tileIndex; i++) ++tile; - ((*tile).get())->copyTo(&bgSurface, Common::Point(x * tileWidth, y * tileHeight)); + + bgSurface.blitFrom(*(*tile).get(), Common::Point(x * tileWidth, y * tileHeight)); ((*tile).get())->free(); } } diff --git a/engines/mads/screen.cpp b/engines/mads/screen.cpp index 90fbbe7e2a..05f9de61e2 100644 --- a/engines/mads/screen.cpp +++ b/engines/mads/screen.cpp @@ -69,7 +69,6 @@ void DirtyArea::setArea(int width, int height, int maxWidth, int maxHeight) { _active = true; } - void DirtyArea::setSpriteSlot(const SpriteSlot *spriteSlot) { int width, height; Scene &scene = _vm->_game->_scene; @@ -215,12 +214,13 @@ void DirtyAreas::copy(MSurface *srcSurface, MSurface *destSurface, const Common: Common::Point destPos(srcBounds.left, srcBounds.top); if ((*this)[i]._active && bounds.isValidRect()) { - srcSurface->copyTo(destSurface, bounds, destPos); + destSurface->blitFrom(*srcSurface, bounds, destPos); } } } void DirtyAreas::copyToScreen() { +/* for (uint i = 0; i < size(); ++i) { const Common::Rect &bounds = (*this)[i]._bounds; @@ -229,9 +229,10 @@ void DirtyAreas::copyToScreen() { continue; if ((*this)[i]._active && (*this)[i]._bounds.isValidRect()) { - _vm->_screen.copyRectToScreen(bounds); + _vm->_screen->copyRectToScreen(bounds); } } + */ } void DirtyAreas::reset() { @@ -554,38 +555,17 @@ void ScreenObjects::synchronize(Common::Serializer &s) { /*------------------------------------------------------------------------*/ -ScreenSurface::ScreenSurface() { +Screen::Screen(): Graphics::Screen(), MSurface() { + // Create the screen surface separately on another surface, since the screen + // surface will be subject to change as the clipping area is altered + _rawSurface.create(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT); + resetClipBounds(); + _shakeCountdown = -1; _random = 0x4D2; - _surfacePixels = nullptr; -} - -void ScreenSurface::init() { - // Set the size for the screen - setSize(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT); - - // Store a copy of the raw pixels pointer for the screen, since the surface - // itself may be later changed to only a subset of the screen - _surfacePixels = (byte *)getPixels(); - _freeFlag = false; -} - -ScreenSurface::~ScreenSurface() { - ::free(_surfacePixels); } -void ScreenSurface::copyRectToScreen(const Common::Rect &bounds) { - const byte *buf = getBasePtr(bounds.left, bounds.top); - - Common::Rect destBounds = bounds; - destBounds.translate(_clipBounds.left, _clipBounds.top); - - if (bounds.width() != 0 && bounds.height() != 0) - g_system->copyRectToScreen(buf, this->pitch, destBounds.left, destBounds.top, - destBounds.width(), destBounds.height()); -} - -void ScreenSurface::updateScreen() { +void Screen::update() { if (_shakeCountdown >= 0) { _random = _random * 5 + 1; int offset = (_random >> 8) & 3; @@ -596,27 +576,42 @@ void ScreenSurface::updateScreen() { // offset width shown at the very right. The offset changes to give // an effect of shaking the screen offset *= 4; - const byte *buf = getBasePtr(offset, 0); - g_system->copyRectToScreen(buf, this->pitch, 0, 0, - this->pitch - offset, this->h); + const byte *buf = (const byte *)getBasePtr(offset, 0); + g_system->copyRectToScreen(buf, this->pitch, 0, 0, this->pitch - offset, this->h); if (offset > 0) - g_system->copyRectToScreen(this->pixels, this->pitch, + g_system->copyRectToScreen(getPixels(), this->pitch, this->pitch - offset, 0, offset, this->h); + return; } - g_system->updateScreen(); + // Reset any clip bounds if active whilst the screen is updated + Common::Rect clipBounds = getClipBounds(); + resetClipBounds(); + + // Update the screen + Graphics::Screen::update(); + + // Revert back to whatever clipping is active + setClipBounds(clipBounds); } -void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag) { +void Screen::transition(ScreenTransition transitionType, bool surfaceFlag) { Palette &pal = *_vm->_palette; Scene &scene = _vm->_game->_scene; byte palData[PALETTE_SIZE]; + // The original loads the new scene to the screen surface for some of the + // transition types like fade out/in, so we need to clear the dirty rects so + // it doesn't prematurely get blitted to the physical screen before fade out + Common::Rect clipBounds = getClipBounds(); + clearDirtyRects(); + switch (transitionType) { case kTransitionFadeIn: - case kTransitionFadeOutIn: + case kTransitionFadeOutIn: { Common::fill(&pal._colorValues[0], &pal._colorValues[3], 0); Common::fill(&pal._colorFlags[0], &pal._colorFlags[3], false); + resetClipBounds(); if (transitionType == kTransitionFadeOutIn) { // Fade out @@ -628,9 +623,11 @@ void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag Common::fill(&palData[0], &palData[PALETTE_SIZE], 0); pal.setFullPalette(palData); - copyRectToScreen(getBounds()); + markAllDirty(); + update(); pal.fadeIn(palData, pal._mainPalette, 0, 256, 0, 1, 1, 16); break; + } case kTransitionBoxInBottomLeft: case kTransitionBoxInBottomRight: @@ -666,19 +663,13 @@ void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag // Quick transitions break; } -} -void ScreenSurface::setClipBounds(const Common::Rect &r) { - _clipBounds = r; - setPixels(_surfacePixels + pitch * r.top + r.left, r.width(), r.height()); - this->pitch = MADS_SCREEN_WIDTH; + // Reset clipping + markAllDirty(); + setClipBounds(clipBounds); } -void ScreenSurface::resetClipBounds() { - setClipBounds(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT)); -} - -void ScreenSurface::panTransition(MSurface &newScreen, byte *palData, int entrySide, +void Screen::panTransition(MSurface &newScreen, byte *palData, int entrySide, const Common::Point &srcPos, const Common::Point &destPos, ThroughBlack throughBlack, bool setPalette, int numTicks) { EventsManager &events = *_vm->_events; @@ -735,8 +726,6 @@ void ScreenSurface::panTransition(MSurface &newScreen, byte *palData, int entryS srcPos.x + xAt + 1, srcPos.y + size.y)); } - copyRectToScreen(Common::Rect(xAt, destPos.y, xAt + 1, destPos.y + size.y)); - // Slight delay events.pollEvents(); g_system->delayMillis(1); @@ -747,16 +736,18 @@ void ScreenSurface::panTransition(MSurface &newScreen, byte *palData, int entryS } if (throughBlack == THROUGH_BLACK2) { + /* Common::Rect r(srcPos.x, srcPos.y, srcPos.x + size.x, srcPos.y + size.y); copyRectToSurface(newScreen, destPos.x, destPos.y, r); copyRectToScreen(r); + */ } } /** * Translates the current screen from the old palette to the new palette */ -void ScreenSurface::swapForeground(byte newPalette[PALETTE_SIZE], byte *paletteMap) { +void Screen::swapForeground(byte newPalette[PALETTE_SIZE], byte *paletteMap) { Palette &palette = *_vm->_palette; byte oldPalette[PALETTE_SIZE]; byte oldMap[PALETTE_COUNT]; @@ -775,7 +766,7 @@ void ScreenSurface::swapForeground(byte newPalette[PALETTE_SIZE], byte *paletteM destP += 2 * RGB_SIZE; } - Common::Rect oldClip = _clipBounds; + Common::Rect oldClip = getClipBounds(); resetClipBounds(); copyRectTranslate(*this, oldMap, Common::Point(0, 0), @@ -790,7 +781,7 @@ void ScreenSurface::swapForeground(byte newPalette[PALETTE_SIZE], byte *paletteM * Palettes consist of 128 RGB entries for the foreground and background * respectively, with the two interleaved together. So the start */ -void ScreenSurface::swapPalette(const byte *palData, byte swapTable[PALETTE_COUNT], +void Screen::swapPalette(const byte *palData, byte swapTable[PALETTE_COUNT], bool foreground) { int start = foreground ? 1 : 0; const byte *dynamicList = &palData[start * RGB_SIZE]; @@ -815,5 +806,12 @@ void ScreenSurface::swapPalette(const byte *palData, byte swapTable[PALETTE_COUN } } +void Screen::setClipBounds(const Common::Rect &r) { + create(_rawSurface, r); +} + +void Screen::resetClipBounds() { + setClipBounds(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT)); +} } // End of namespace MADS diff --git a/engines/mads/screen.h b/engines/mads/screen.h index d910e88633..626080580e 100644 --- a/engines/mads/screen.h +++ b/engines/mads/screen.h @@ -25,6 +25,7 @@ #include "common/scummsys.h" #include "common/array.h" +#include "graphics/screen.h" #include "mads/msurface.h" #include "mads/action.h" @@ -207,11 +208,10 @@ public: void synchronize(Common::Serializer &s); }; -class ScreenSurface : public MSurface { +class Screen : virtual public Graphics::Screen, virtual public MSurface { private: uint16 _random; - byte *_surfacePixels; - Common::Rect _clipBounds; + MSurface _rawSurface; void panTransition(MSurface &newScreen, byte *palData, int entrySide, const Common::Point &srcPos, const Common::Point &destPos, @@ -226,36 +226,40 @@ public: /** * Constructor */ - ScreenSurface(); + Screen(); /** * Destructor */ - ~ScreenSurface(); + virtual ~Screen() {} /** - * Initialize the surface + * Updates the physical screen with contents of the internal surface */ - void init(); + virtual void update(); /** - * Copys an area of the screen surface to the ScmmVM physical screen buffer - * @param bounds Area of screen surface to copy + * Transition to a new screen with a given effect */ - void copyRectToScreen(const Common::Rect &bounds); + void transition(ScreenTransition transitionType, bool surfaceFlag); /** - * Updates the screen with the contents of the surface + * Set the screen drawing area to a sub-section of the real screen */ - void updateScreen(); - - void transition(ScreenTransition transitionType, bool surfaceFlag); - void setClipBounds(const Common::Rect &r); + /** + * Reset back to drawing on the entirety of the screen + */ void resetClipBounds(); - const Common::Rect &getClipBounds() { return _clipBounds; } + /** + * Return the current drawing/clip area + */ + const Common::Rect getClipBounds() const { + const Common::Point pt = getOffsetFromOwner(); + return Common::Rect(pt.x, pt.y, pt.x + this->w, pt.y + this->h); + } }; } // End of namespace MADS diff --git a/engines/mads/sequence.cpp b/engines/mads/sequence.cpp index 50b37de7ea..2afe089d4a 100644 --- a/engines/mads/sequence.cpp +++ b/engines/mads/sequence.cpp @@ -237,8 +237,8 @@ bool SequenceList::loadSprites(int seqIndex) { if ((seqEntry._flags != 0) || (seqEntry._dynamicHotspotIndex >= 0)) { SpriteAsset &spriteSet = *scene._sprites[seqEntry._spritesIndex]; MSprite *frame = spriteSet.getFrame(seqEntry._frameIndex - 1); - int width = frame->getWidth() * seqEntry._scale / 200; - int height = frame->getHeight() * seqEntry._scale / 100; + int width = frame->w * seqEntry._scale / 200; + int height = frame->h * seqEntry._scale / 100; Common::Point pt = spriteSlot._position; // Handle sprite movement, if present diff --git a/engines/mads/sprites.cpp b/engines/mads/sprites.cpp index 0a1c0b710d..fc8ddf22d2 100644 --- a/engines/mads/sprites.cpp +++ b/engines/mads/sprites.cpp @@ -59,10 +59,10 @@ MSprite::MSprite() : MSurface() { } MSprite::MSprite(Common::SeekableReadStream *source, const Common::Array<RGB6> &palette, - const Common::Rect &bounds) - : MSurface(bounds.width(), bounds.height()), - _offset(Common::Point(bounds.left, bounds.top)), _transparencyIndex(TRANSPARENT_COLOR_INDEX) { + const Common::Rect &bounds): MSurface(), _transparencyIndex(TRANSPARENT_COLOR_INDEX), + _offset(Common::Point(bounds.left, bounds.top)) { // Load the sprite data + create(bounds.width(), bounds.height()); loadSprite(source, palette); } @@ -74,8 +74,8 @@ void MSprite::loadSprite(Common::SeekableReadStream *source, byte *outp, *lineStart; bool newLine = false; - outp = getData(); - lineStart = getData(); + outp = getPixels(); + lineStart = getPixels(); int spriteSize = this->w * this->h; byte transIndex = getTransparencyIndex(); Common::fill(outp, outp + spriteSize, transIndex); @@ -84,7 +84,7 @@ void MSprite::loadSprite(Common::SeekableReadStream *source, byte cmd1, cmd2, count, pixel; if (newLine) { - outp = lineStart + getWidth(); + outp = lineStart + this->w; lineStart = outp; newLine = false; } @@ -126,7 +126,7 @@ void MSprite::loadSprite(Common::SeekableReadStream *source, // Do a final iteration over the sprite to convert it's pixels to // the final positions in the main palette spriteSize = this->w * this->h; - for (outp = getData(); spriteSize > 0; --spriteSize, ++outp) { + for (outp = getPixels(); spriteSize > 0; --spriteSize, ++outp) { if (*outp != transIndex) *outp = palette[*outp]._palIndex; } @@ -257,12 +257,12 @@ void SpriteSlots::drawBackground() { } if (spriteSlot._depth <= 1) { - frame->copyTo(&scene._backgroundSurface, pt, frame->getTransparencyIndex()); + scene._backgroundSurface.transBlitFrom(*frame, pt, frame->getTransparencyIndex()); } else if (scene._depthStyle == 0) { - scene._backgroundSurface.copyFrom(frame, pt, spriteSlot._depth, &scene._depthSurface, + scene._backgroundSurface.copyFrom(*frame, pt, spriteSlot._depth, &scene._depthSurface, -1, false, frame->getTransparencyIndex()); } else { - frame->copyTo(&scene._backgroundSurface, pt, frame->getTransparencyIndex()); + scene._backgroundSurface.transBlitFrom(*frame, pt, frame->getTransparencyIndex()); } } } @@ -319,7 +319,7 @@ void SpriteSlots::drawSprites(MSurface *s) { if ((slot._scale < 100) && (slot._scale != -1)) { // Scaled drawing - s->copyFrom(sprite, slot._position, slot._depth, &scene._depthSurface, + s->copyFrom(*sprite, slot._position, slot._depth, &scene._depthSurface, slot._scale, flipped, sprite->getTransparencyIndex()); } else { int xp, yp; @@ -334,7 +334,7 @@ void SpriteSlots::drawSprites(MSurface *s) { if (slot._depth > 1) { // Draw the frame with depth processing - s->copyFrom(sprite, Common::Point(xp, yp), slot._depth, &scene._depthSurface, + s->copyFrom(*sprite, Common::Point(xp, yp), slot._depth, &scene._depthSurface, -1, flipped, sprite->getTransparencyIndex()); } else { MSurface *spr = sprite; @@ -344,7 +344,7 @@ void SpriteSlots::drawSprites(MSurface *s) { } // No depth, so simply draw the image - spr->copyTo(s, Common::Point(xp, yp), sprite->getTransparencyIndex()); + s->transBlitFrom(*spr, Common::Point(xp, yp), sprite->getTransparencyIndex()); // Free sprite if it was a flipped one if (flipped) { diff --git a/engines/mads/user_interface.cpp b/engines/mads/user_interface.cpp index e4b09ff54c..8f7cb0a24b 100644 --- a/engines/mads/user_interface.cpp +++ b/engines/mads/user_interface.cpp @@ -112,7 +112,7 @@ void UISlots::draw(bool updateFlag, bool delFlag) { Common::Point(dirtyArea._bounds.left, dirtyArea._bounds.top)); } else { // Copy area - userInterface._surface.copyTo(&userInterface, dirtyArea._bounds, + userInterface.blitFrom(userInterface._surface, dirtyArea._bounds, Common::Point(dirtyArea._bounds.left, dirtyArea._bounds.top)); } } @@ -155,7 +155,7 @@ void UISlots::draw(bool updateFlag, bool delFlag) { if (slot._segmentId == IMG_SPINNING_OBJECT) { MSprite *sprite = asset->getFrame(frameNumber - 1); - sprite->copyTo(&userInterface, slot._position, + userInterface.transBlitFrom(*sprite, slot._position, sprite->getTransparencyIndex()); } else { MSprite *sprite = asset->getFrame(frameNumber - 1); @@ -185,7 +185,7 @@ void UISlots::draw(bool updateFlag, bool delFlag) { // Flag area of screen as needing update Common::Rect r = dirtyArea._bounds; r.translate(0, scene._interfaceY); - _vm->_screen.copyRectToScreen(r); + //_vm->_screen->copyRectToScreen(r); } } } @@ -339,10 +339,10 @@ UserInterface::UserInterface(MADSEngine *vm) : _vm(vm), _dirtyAreas(vm), Common::fill(&_categoryIndexes[0], &_categoryIndexes[7], 0); // Map the user interface to the bottom of the game's screen surface - byte *pData = _vm->_screen.getBasePtr(0, MADS_SCENE_HEIGHT); - setPixels(pData, MADS_SCREEN_WIDTH, MADS_INTERFACE_HEIGHT); + create(*_vm->_screen, Common::Rect(0, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH, + MADS_SCREEN_HEIGHT)); - _surface.setSize(MADS_SCREEN_WIDTH, MADS_INTERFACE_HEIGHT); + _surface.create(MADS_SCREEN_WIDTH, MADS_INTERFACE_HEIGHT); } void UserInterface::load(const Common::String &resName) { @@ -367,7 +367,7 @@ void UserInterface::load(const Common::String &resName) { // Read in the surface data Common::SeekableReadStream *pixelsStream = madsPack.getItemStream(1); - pixelsStream->read(_surface.getData(), MADS_SCREEN_WIDTH * MADS_INTERFACE_HEIGHT); + pixelsStream->read(_surface.getPixels(), MADS_SCREEN_WIDTH * MADS_INTERFACE_HEIGHT); delete pixelsStream; } @@ -390,7 +390,7 @@ void UserInterface::setup(InputMode inputMode) { resName += ".INT"; load(resName); - _surface.copyTo(this); + blitFrom(_surface); } _vm->_game->_screenObjects._inputMode = inputMode; @@ -455,9 +455,9 @@ void UserInterface::mergeFrom(MSurface *src, const Common::Rect &srcBounds, // Copy the specified area - byte *data = src->getData(); - byte *srcPtr = data + (src->getWidth() * copyRect.top + copyRect.left); - byte *destPtr = (byte *)this->pixels + (destY * getWidth()) + destX; + byte *data = src->getPixels(); + byte *srcPtr = data + (src->w * copyRect.top + copyRect.left); + byte *destPtr = (byte *)getPixels() + (destY * this->w) + destX; for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) { // Process each line of the area @@ -468,8 +468,8 @@ void UserInterface::mergeFrom(MSurface *src, const Common::Rect &srcBounds, destPtr[xCtr] = srcPtr[xCtr]; } - srcPtr += src->getWidth(); - destPtr += getWidth(); + srcPtr += src->w; + destPtr += this->w; } } @@ -593,7 +593,7 @@ void UserInterface::scrollbarChanged() { _uiSlots.add(r); _uiSlots.draw(false, false); drawScroller(); - updateRect(r); +// updateRect(r); } void UserInterface::writeVocab(ScrCategory category, int id) { @@ -1012,7 +1012,7 @@ void UserInterface::selectObject(int invIndex) { _uiSlots.add(bounds); _uiSlots.draw(false, false); drawItemVocabList(); - updateRect(bounds); + //updateRect(bounds); } } @@ -1036,7 +1036,7 @@ void UserInterface::updateSelection(ScrCategory category, int newIndex, int *idx _uiSlots.add(bounds); _uiSlots.draw(false, false); drawInventoryList(); - updateRect(bounds); + //updateRect(bounds); _inventoryChanged = false; if (invList.size() < 2) { @@ -1052,25 +1052,19 @@ void UserInterface::updateSelection(ScrCategory category, int newIndex, int *idx if (oldIndex >= 0) { writeVocab(category, oldIndex); - if (getBounds(category, oldIndex, bounds)) - updateRect(bounds); +/* if (getBounds(category, oldIndex, bounds)) + updateRect(bounds); */ } if (newIndex >= 0) { writeVocab(category, newIndex); - if (getBounds(category, newIndex, bounds)) - updateRect(bounds); +/* if (getBounds(category, newIndex, bounds)) + updateRect(bounds); */ } } } -void UserInterface::updateRect(const Common::Rect &bounds) { - Common::Rect r = bounds; - r.translate(0, MADS_SCENE_HEIGHT); - _vm->_screen.copyRectToScreen(r); -} - void UserInterface::scrollerChanged() { warning("TODO: scrollerChanged"); } diff --git a/engines/mads/user_interface.h b/engines/mads/user_interface.h index 60cc1f736d..9232dc1bb1 100644 --- a/engines/mads/user_interface.h +++ b/engines/mads/user_interface.h @@ -190,8 +190,6 @@ private: * Draw a UI textual element */ void writeVocab(ScrCategory category, int id); - - void updateRect(const Common::Rect &bounds); public: MSurface _surface; UISlots _uiSlots; diff --git a/engines/metaengine.h b/engines/metaengine.h index 41f3ec4cba..e7bfebab71 100644 --- a/engines/metaengine.h +++ b/engines/metaengine.h @@ -96,6 +96,9 @@ public: /** * Return a list of all save states associated with the given target. * + * The returned list is guaranteed to be sorted by slot numbers. That + * means smaller slot numbers are always stored before bigger slot numbers. + * * The caller has to ensure that this (Meta)Engine is responsible * for the specified target (by using findGame on it respectively * on the associated gameid from the relevant ConfMan entry, if present). diff --git a/engines/mohawk/configure.engine b/engines/mohawk/configure.engine index 47402c4560..ccb9499ef0 100644 --- a/engines/mohawk/configure.engine +++ b/engines/mohawk/configure.engine @@ -1,6 +1,6 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine mohawk "Mohawk" yes "cstime myst riven" "Living Books" +add_engine mohawk "Mohawk" yes "cstime myst riven" "Living Books" "highres" add_engine cstime "Where in Time is Carmen Sandiego?" no add_engine riven "Riven: The Sequel to Myst" no "" "" "16bit" -add_engine myst "Myst" no +add_engine myst "Myst" yes diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp index 9b5bae78be..fd79e53b07 100644 --- a/engines/mohawk/console.cpp +++ b/engines/mohawk/console.cpp @@ -63,6 +63,8 @@ MystConsole::MystConsole(MohawkEngine_Myst *vm) : GUI::Debugger(), _vm(vm) { registerCmd("disableInitOpcodes", WRAP_METHOD(MystConsole, Cmd_DisableInitOpcodes)); registerCmd("cache", WRAP_METHOD(MystConsole, Cmd_Cache)); registerCmd("resources", WRAP_METHOD(MystConsole, Cmd_Resources)); + registerCmd("quickTest", WRAP_METHOD(MystConsole, Cmd_QuickTest)); + registerVar("show_resource_rects", &_vm->_showResourceRects); } MystConsole::~MystConsole() { @@ -119,7 +121,7 @@ static const uint16 default_start_card[12] = { 10000, 2000, 5038, - 2, // TODO: Should be 1? + 1, 1, 6122, 4134, @@ -329,6 +331,44 @@ bool MystConsole::Cmd_Resources(int argc, const char **argv) { return true; } +bool MystConsole::Cmd_QuickTest(int argc, const char **argv) { + // Go through all the ages, all the views and click random stuff + for (uint i = 0; i < ARRAYSIZE(mystStackNames); i++) { + if (i == 2 || i == 5 || i == 9 || i == 10) continue; + debug("Loading stack %s", mystStackNames[i]); + _vm->changeToStack(i, default_start_card[i], 0, 0); + + Common::Array<uint16> ids = _vm->getResourceIDList(ID_VIEW); + for (uint j = 0; j < ids.size(); j++) { + if (ids[j] == 4632) continue; + + debug("Loading card %d", ids[j]); + _vm->changeToCard(ids[j], kTransitionCopy); + + _vm->_video->updateMovies(); + _vm->_scriptParser->runPersistentScripts(); + _vm->_system->updateScreen(); + + int16 resIndex = _vm->_rnd->getRandomNumber(_vm->_resources.size()) - 1; + if (resIndex >= 0 && _vm->_resources[resIndex]->isEnabled()) { + _vm->_resources[resIndex]->handleMouseDown(); + _vm->_resources[resIndex]->handleMouseUp(); + } + + _vm->_video->updateMovies(); + _vm->_scriptParser->runPersistentScripts(); + _vm->_system->updateScreen(); + + if (_vm->getCurStack() != i) { + // Clicking may have linked us to another age + _vm->changeToStack(i, default_start_card[i], 0, 0); + } + } + } + + return true; +} + #endif // ENABLE_MYST #ifdef ENABLE_RIVEN diff --git a/engines/mohawk/console.h b/engines/mohawk/console.h index af01c0d1e0..dc40049a89 100644 --- a/engines/mohawk/console.h +++ b/engines/mohawk/console.h @@ -55,6 +55,7 @@ private: bool Cmd_DisableInitOpcodes(int argc, const char **argv); bool Cmd_Cache(int argc, const char **argv); bool Cmd_Resources(int argc, const char **argv); + bool Cmd_QuickTest(int argc, const char **argv); }; #endif diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp index 926c296257..a64d7ff7df 100644 --- a/engines/mohawk/detection.cpp +++ b/engines/mohawk/detection.cpp @@ -26,6 +26,7 @@ #include "common/savefile.h" #include "common/system.h" #include "common/textconsole.h" +#include "common/translation.h" #include "mohawk/livingbooks.h" @@ -35,6 +36,7 @@ #ifdef ENABLE_MYST #include "mohawk/myst.h" +#include "mohawk/myst_state.h" #endif #ifdef ENABLE_RIVEN @@ -52,7 +54,7 @@ struct MohawkGameDescription { }; const char* MohawkEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } uint32 MohawkEngine::getFeatures() const { @@ -159,10 +161,24 @@ static const char *directoryGlobs[] = { 0 }; +static const ADExtraGuiOptionsMap optionsList[] = { + { + GAMEOPTION_PLAY_MYST_FLYBY, + { + _s("Play the Myst fly by movie"), + _s("The Myst fly by movie was not played by the original engine."), + "playmystflyby", + false + } + }, + + AD_EXTRA_GUI_OPTIONS_TERMINATOR +}; + class MohawkMetaEngine : public AdvancedMetaEngine { public: - MohawkMetaEngine() : AdvancedMetaEngine(Mohawk::gameDescriptions, sizeof(Mohawk::MohawkGameDescription), mohawkGames) { - _singleid = "mohawk"; + MohawkMetaEngine() : AdvancedMetaEngine(Mohawk::gameDescriptions, sizeof(Mohawk::MohawkGameDescription), mohawkGames, optionsList) { + _singleId = "mohawk"; _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } @@ -184,13 +200,18 @@ public: virtual SaveStateList listSaves(const char *target) const; virtual int getMaximumSaveSlot() const { return 999; } virtual void removeSaveState(const char *target, int slot) const; + virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; }; bool MohawkMetaEngine::hasFeature(MetaEngineFeature f) const { return (f == kSupportsListSaves) || (f == kSupportsLoadingDuringStartup) - || (f == kSupportsDeleteSave); + || (f == kSupportsDeleteSave) + || (f == kSavesSupportMetaInfo) + || (f == kSavesSupportThumbnail) + || (f == kSavesSupportCreationDate) + || (f == kSavesSupportPlayTime); } SaveStateList MohawkMetaEngine::listSaves(const char *target) const { @@ -198,12 +219,15 @@ SaveStateList MohawkMetaEngine::listSaves(const char *target) const { SaveStateList saveList; // Loading games is only supported in Myst/Riven currently. +#ifdef ENABLE_MYST if (strstr(target, "myst")) { - filenames = g_system->getSavefileManager()->listSavefiles("*.mys"); + filenames = Mohawk::MystGameState::generateSaveGameList(); for (uint32 i = 0; i < filenames.size(); i++) saveList.push_back(SaveStateDescriptor(i, filenames[i])); - } else if (strstr(target, "riven")) { + } else +#endif + if (strstr(target, "riven")) { filenames = g_system->getSavefileManager()->listSavefiles("*.rvn"); for (uint32 i = 0; i < filenames.size(); i++) @@ -215,15 +239,35 @@ SaveStateList MohawkMetaEngine::listSaves(const char *target) const { void MohawkMetaEngine::removeSaveState(const char *target, int slot) const { // Removing saved games is only supported in Myst/Riven currently. +#ifdef ENABLE_MYST if (strstr(target, "myst")) { - Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("*.mys"); - g_system->getSavefileManager()->removeSavefile(filenames[slot].c_str()); - } else if (strstr(target, "riven")) { + Common::StringArray filenames = Mohawk::MystGameState::generateSaveGameList(); + Mohawk::MystGameState::deleteSave(filenames[slot]); + } else +#endif + if (strstr(target, "riven")) { Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("*.rvn"); g_system->getSavefileManager()->removeSavefile(filenames[slot].c_str()); } } +SaveStateDescriptor MohawkMetaEngine::querySaveMetaInfos(const char *target, int slot) const { +#ifdef ENABLE_MYST + if (strstr(target, "myst")) { + Common::StringArray filenames = Mohawk::MystGameState::generateSaveGameList(); + + if (slot >= (int) filenames.size()) { + return SaveStateDescriptor(); + } + + return Mohawk::MystGameState::querySaveMetaInfos(filenames[slot]); + } else +#endif + { + return SaveStateDescriptor(); + } +} + bool MohawkMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { const Mohawk::MohawkGameDescription *gd = (const Mohawk::MohawkGameDescription *)desc; diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h index 97d2932d57..7941a0d51a 100644 --- a/engines/mohawk/detection_tables.h +++ b/engines/mohawk/detection_tables.h @@ -22,6 +22,13 @@ namespace Mohawk { +#define GAMEOPTION_PLAY_MYST_FLYBY GUIO_GAMEOPTIONS1 + +#define GUI_OPTIONS_MYST GUIO3(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI) +#define GUI_OPTIONS_MYST_ME GUIO4(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI, GAMEOPTION_PLAY_MYST_FLYBY) +#define GUI_OPTIONS_MYST_DEMO GUIO4(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI, GUIO_NOLAUNCHLOAD) +#define GUI_OPTIONS_MYST_MAKING_OF GUIO4(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI, GUIO_NOLAUNCHLOAD) + static const MohawkGameDescription gameDescriptions[] = { // Myst // English Windows 3.11 @@ -34,7 +41,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -52,7 +59,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_DEMO }, GType_MYST, GF_DEMO, @@ -70,7 +77,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -88,7 +95,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -106,7 +113,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -124,7 +131,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -142,7 +149,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::JA_JPN, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -160,7 +167,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -178,7 +185,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_MAKING_OF }, GType_MAKINGOF, 0, @@ -196,7 +203,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::JA_JPN, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_MAKING_OF }, GType_MAKINGOF, 0, @@ -214,7 +221,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_ME }, GType_MYST, GF_ME, @@ -232,7 +239,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_ME }, GType_MYST, GF_ME, @@ -250,7 +257,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_ME }, GType_MYST, GF_ME, @@ -268,7 +275,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::PL_POL, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_ME }, GType_MYST, GF_ME, @@ -2698,7 +2705,7 @@ static const MohawkGameDescription fallbackDescs[] = { Common::UNK_LANG, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -2713,7 +2720,7 @@ static const MohawkGameDescription fallbackDescs[] = { Common::UNK_LANG, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_MAKING_OF }, GType_MAKINGOF, 0, @@ -2728,7 +2735,7 @@ static const MohawkGameDescription fallbackDescs[] = { Common::UNK_LANG, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_ME }, GType_MYST, GF_ME, diff --git a/engines/mohawk/dialogs.cpp b/engines/mohawk/dialogs.cpp index ffc455286f..6c6ae9e77f 100644 --- a/engines/mohawk/dialogs.cpp +++ b/engines/mohawk/dialogs.cpp @@ -24,6 +24,7 @@ #include "mohawk/dialogs.h" #include "gui/gui-manager.h" +#include "gui/saveload.h" #include "gui/ThemeEngine.h" #include "gui/widget.h" #include "common/system.h" @@ -82,35 +83,47 @@ enum { kWaterCmd = 'WATR', kDropCmd = 'DROP', kMapCmd = 'SMAP', - kMenuCmd = 'MENU' + kMenuCmd = 'MENU', + kSaveCmd = 'SAVE', + kLoadCmd = 'LOAD', + kQuitCmd = 'QUIT' }; #ifdef ENABLE_MYST -MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::OptionsDialog("", 120, 120, 360, 200), _vm(vm) { +MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::Dialog(0, 0, 360, 200), _vm(vm) { // I18N: Option for fast scene switching - _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 300, 15, _("~Z~ip Mode Activated"), 0, kZipCmd); - _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 300, 15, _("~T~ransitions Enabled"), 0, kTransCmd); + _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), 0, kZipCmd); + _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~T~ransitions Enabled"), 0, kTransCmd); // I18N: Drop book page _dropPageButton = new GUI::ButtonWidget(this, 15, 60, 100, 25, _("~D~rop Page"), 0, kDropCmd); // Myst ME only has maps if (_vm->getFeatures() & GF_ME) - _showMapButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("~S~how Map"), 0, kMapCmd); + _showMapButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Show ~M~ap"), 0, kMapCmd); else _showMapButton = 0; // Myst demo only has a menu if (_vm->getFeatures() & GF_DEMO) - _returnToMenuButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("~M~ain Menu"), 0, kMenuCmd); + _returnToMenuButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Main Men~u~"), 0, kMenuCmd); else _returnToMenuButton = 0; + _loadButton = new GUI::ButtonWidget(this, 245, 25, 100, 25, _("~L~oad"), 0, kLoadCmd); + _saveButton = new GUI::ButtonWidget(this, 245, 60, 100, 25, _("~S~ave"), 0, kSaveCmd); + new GUI::ButtonWidget(this, 245, 95, 100, 25, _("~Q~uit"), 0, kQuitCmd); + new GUI::ButtonWidget(this, 95, 160, 120, 25, _("~O~K"), 0, GUI::kOKCmd); new GUI::ButtonWidget(this, 225, 160, 120, 25, _("~C~ancel"), 0, GUI::kCloseCmd); + + _loadDialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load"), false); + _saveDialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); } MystOptionsDialog::~MystOptionsDialog() { + delete _loadDialog; + delete _saveDialog; } void MystOptionsDialog::open() { @@ -133,6 +146,44 @@ void MystOptionsDialog::open() { _zipModeCheckbox->setState(_vm->_gameState->_globals.zipMode); _transitionsCheckbox->setState(_vm->_gameState->_globals.transitions); + + _loadButton->setEnabled(_vm->canLoadGameStateCurrently()); + _saveButton->setEnabled(_vm->canSaveGameStateCurrently()); +} + +void MystOptionsDialog::save() { + int slot = _saveDialog->runModalWithCurrentTarget(); + + if (slot >= 0) { + Common::String result(_saveDialog->getResultString()); + if (result.empty()) { + // If the user was lazy and entered no save name, come up with a default name. + result = _saveDialog->createDefaultSaveDescription(slot); + } + + _vm->saveGameState(slot, result); + close(); + } +} + +void MystOptionsDialog::load() { + int slot = _loadDialog->runModalWithCurrentTarget(); + + if (slot >= 0) { + _vm->loadGameState(slot); + close(); + } +} + +void MystOptionsDialog::reflowLayout() { + const int screenW = g_system->getOverlayWidth(); + const int screenH = g_system->getOverlayHeight(); + + // Center the dialog + _x = (screenW - getWidth()) / 2; + _y = (screenH - getHeight()) / 2; + + Dialog::reflowLayout(); } void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) { @@ -144,18 +195,39 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui case kMapCmd: _vm->_needsShowMap = true; close(); - break; + break; case kMenuCmd: _vm->_needsShowDemoMenu = true; close(); - break; + break; + case kLoadCmd: + load(); + break; + case kSaveCmd: + save(); + break; + case kQuitCmd: { + if (_vm->getGameType() != GType_MAKINGOF) { + _vm->_needsShowCredits = true; + } else { + Common::Event eventQ; + eventQ.type = Common::EVENT_QUIT; + g_system->getEventManager()->pushEvent(eventQ); + } + close(); + } + break; case GUI::kOKCmd: _vm->_gameState->_globals.zipMode = _zipModeCheckbox->getState(); _vm->_gameState->_globals.transitions = _transitionsCheckbox->getState(); - GUI::OptionsDialog::handleCommand(sender, cmd, data); + setResult(1); + close(); + break; + case GUI::kCloseCmd: + close(); break; default: - GUI::OptionsDialog::handleCommand(sender, cmd, data); + GUI::Dialog::handleCommand(sender, cmd, data); } } diff --git a/engines/mohawk/dialogs.h b/engines/mohawk/dialogs.h index 7470cd3acd..bc25c72a43 100644 --- a/engines/mohawk/dialogs.h +++ b/engines/mohawk/dialogs.h @@ -32,6 +32,10 @@ #include "gui/widget.h" #include "gui/widgets/list.h" +namespace GUI { +class SaveLoadChooser; +} + namespace Mohawk { class MohawkEngine; @@ -70,20 +74,32 @@ public: class MohawkEngine_Myst; -class MystOptionsDialog : public GUI::OptionsDialog { +class MystOptionsDialog : public GUI::Dialog { public: MystOptionsDialog(MohawkEngine_Myst *vm); ~MystOptionsDialog(); void open(); + virtual void reflowLayout() override; virtual void handleCommand(GUI::CommandSender*, uint32, uint32); private: MohawkEngine_Myst *_vm; + GUI::CheckboxWidget *_zipModeCheckbox; GUI::CheckboxWidget *_transitionsCheckbox; + GUI::ButtonWidget *_dropPageButton; GUI::ButtonWidget *_showMapButton; GUI::ButtonWidget *_returnToMenuButton; + + GUI::ButtonWidget *_loadButton; + GUI::ButtonWidget *_saveButton; + + GUI::SaveLoadChooser *_loadDialog; + GUI::SaveLoadChooser *_saveDialog; + + void save(); + void load(); }; #endif diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp index b6a6c27329..c16fab9131 100644 --- a/engines/mohawk/myst.cpp +++ b/engines/mohawk/myst.cpp @@ -66,38 +66,22 @@ MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription DebugMan.addDebugChannel(kDebugHelp, "Help", "Track Help File (HELP) Parsing"); DebugMan.addDebugChannel(kDebugCache, "Cache", "Track Resource Cache Accesses"); - // Engine tweaks - // Disabling this makes engine behavior as per - // original, including bugs, missing bits etc. :) - _tweaksEnabled = true; - _currentCursor = 0; _mainCursor = kDefaultMystCursor; _showResourceRects = false; _curCard = 0; _needsUpdate = false; + _canSafelySaveLoad = false; _curResource = -1; - _hoverResource = 0; - _dragResource = 0; - - _gfx = NULL; - _console = NULL; - _scriptParser = NULL; - _gameState = NULL; - _loadDialog = NULL; - _optionsDialog = NULL; - - _cursorHintCount = 0; - _cursorHints = NULL; - - _prevStack = NULL; - - _view.conditionalImageCount = 0; - _view.conditionalImages = NULL; - _view.soundList = NULL; - _view.soundListVolume = NULL; - _view.scriptResCount = 0; - _view.scriptResources = NULL; + _hoverResource = nullptr; + + _gfx = nullptr; + _console = nullptr; + _scriptParser = nullptr; + _gameState = nullptr; + _optionsDialog = nullptr; + + _prevStack = nullptr; } MohawkEngine_Myst::~MohawkEngine_Myst() { @@ -107,20 +91,12 @@ MohawkEngine_Myst::~MohawkEngine_Myst() { delete _console; delete _scriptParser; delete _gameState; - delete _loadDialog; delete _optionsDialog; delete _prevStack; delete _rnd; - delete[] _cursorHints; - - delete[] _view.conditionalImages; - delete[] _view.scriptResources; - for (uint32 i = 0; i < _resources.size(); i++) delete _resources[i]; - - _resources.clear(); } // Uses cached data objects in preference to disk access @@ -138,7 +114,11 @@ Common::SeekableReadStream *MohawkEngine_Myst::getResource(uint32 tag, uint16 id } error("Could not find a \'%s\' resource with ID %04x", tag2str(tag), id); - return NULL; + return nullptr; +} + +Common::Array<uint16> MohawkEngine_Myst::getResourceIDList(uint32 type) const { + return _mhk[0]->getResourceIDList(type); } void MohawkEngine_Myst::cachePreload(uint32 tag, uint16 id) { @@ -242,7 +222,6 @@ Common::Error MohawkEngine_Myst::run() { _gfx = new MystGraphics(this); _console = new MystConsole(this); _gameState = new MystGameState(this, _saveFileMan); - _loadDialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load"), false); _optionsDialog = new MystOptionsDialog(this); _cursor = new MystCursorManager(this); _rnd = new Common::RandomSource("myst"); @@ -251,9 +230,9 @@ Common::Error MohawkEngine_Myst::run() { _cursor->showCursor(); // Load game from launcher/command line if requested - if (ConfMan.hasKey("save_slot") && canLoadGameStateCurrently()) { + if (ConfMan.hasKey("save_slot") && hasGameSaveSupport()) { uint32 gameToLoad = ConfMan.getInt("save_slot"); - Common::StringArray savedGamesList = _gameState->generateSaveGameList(); + Common::StringArray savedGamesList = MystGameState::generateSaveGameList(); if (gameToLoad > savedGamesList.size()) error ("Could not find saved game"); _gameState->load(savedGamesList[gameToLoad]); @@ -284,7 +263,7 @@ Common::Error MohawkEngine_Myst::run() { _needsUpdate = _video->updateMovies(); _scriptParser->runPersistentScripts(); - while (_eventMan->pollEvent(event)) { + while (pollEvent(event)) { switch (event.type) { case Common::EVENT_MOUSEMOVE: { _needsUpdate = true; @@ -324,17 +303,15 @@ Common::Error MohawkEngine_Myst::run() { case Common::KEYCODE_SPACE: pauseGame(); break; - case Common::KEYCODE_F4: - _showResourceRects = !_showResourceRects; - if (_showResourceRects) - drawResourceRects(); - break; case Common::KEYCODE_F5: _needsPageDrop = false; _needsShowMap = false; _needsShowDemoMenu = false; + _needsShowCredits = false; + _canSafelySaveLoad = true; runDialog(*_optionsDialog); + _canSafelySaveLoad = false; if (_needsPageDrop) { dropPage(); @@ -350,6 +327,12 @@ Common::Error MohawkEngine_Myst::run() { changeToStack(kDemoStack, 2002, 0, 0); _needsShowDemoMenu = false; } + + if (_needsShowCredits) { + _cursor->hideCursor(); + changeToStack(kCreditsStack, 10000, 0, 0); + _needsShowCredits = false; + } break; default: break; @@ -372,6 +355,15 @@ Common::Error MohawkEngine_Myst::run() { return Common::kNoError; } +bool MohawkEngine_Myst::pollEvent(Common::Event &event) { + // Saving / Loading is allowed from the GMM only when the main event loop is running + _canSafelySaveLoad = true; + bool eventReturned = _eventMan->pollEvent(event); + _canSafelySaveLoad = false; + + return eventReturned; +} + bool MohawkEngine_Myst::skippableWait(uint32 duration) { uint32 end = _system->getMillis() + duration; bool skipped = false; @@ -413,6 +405,7 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS // Fill screen with black and empty cursor _cursor->setCursor(0); + _currentCursor = 0; if (getFeatures() & GF_ME) _system->fillScreen(_system->getScreenFormat().RGBToColor(0, 0, 0)); @@ -502,7 +495,7 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS if (getFeatures() & GF_ME) { // Play Flyby Entry Movie on Masterpiece Edition. - const char *flyby = 0; + const char *flyby = nullptr; switch (_curStack) { case kSeleniticStack: @@ -512,8 +505,9 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS flyby = "stoneship flyby"; break; // Myst Flyby Movie not used in Original Masterpiece Edition Engine + // We play it when first arriving on Myst, and if the user has chosen so. case kMystStack: - if (_tweaksEnabled) + if (ConfMan.getBool("playmystflyby") && card == 4134) flyby = "myst flyby"; break; case kMechanicalStack: @@ -539,12 +533,12 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS uint16 MohawkEngine_Myst::getCardBackgroundId() { uint16 imageToDraw = 0; - if (_view.conditionalImageCount == 0) + if (_view.conditionalImages.size() == 0) imageToDraw = _view.mainImage; else { - for (uint16 i = 0; i < _view.conditionalImageCount; i++) { + for (uint16 i = 0; i < _view.conditionalImages.size(); i++) { uint16 varValue = _scriptParser->getVar(_view.conditionalImages[i].var); - if (varValue < _view.conditionalImages[i].numStates) + if (varValue < _view.conditionalImages[i].values.size()) imageToDraw = _view.conditionalImages[i].values[varValue]; } } @@ -586,36 +580,7 @@ void MohawkEngine_Myst::changeToCard(uint16 card, TransitionType transition) { drawCardBackground(); // Handle sound - int16 soundAction = 0; - uint16 soundActionVolume = 0; - - if (_view.sound == kMystSoundActionConditional) { - uint16 soundVarValue = _scriptParser->getVar(_view.soundVar); - if (soundVarValue >= _view.soundCount) - warning("Conditional sound variable outside range"); - else { - soundAction = _view.soundList[soundVarValue]; - soundActionVolume = _view.soundListVolume[soundVarValue]; - } - } else { - soundAction = _view.sound; - soundActionVolume = _view.soundVolume; - } - - if (soundAction == kMystSoundActionContinue) - debug(2, "Continuing with current sound"); - else if (soundAction == kMystSoundActionChangeVolume) { - debug(2, "Continuing with current sound, changing volume"); - _sound->changeBackgroundVolumeMyst(soundActionVolume); - } else if (soundAction == kMystSoundActionStop) { - debug(2, "Stopping sound"); - _sound->stopBackgroundMyst(); - } else if (soundAction > 0) { - debug(2, "Playing new sound %d", soundAction); - _sound->replaceBackgroundMyst(soundAction, soundActionVolume); - } else { - error("Unknown sound action %d", soundAction); - } + applySoundBlock(_view.soundBlock); if (_view.flags & kMystZipDestination) _gameState->addZipDest(_curStack, card); @@ -637,15 +602,16 @@ void MohawkEngine_Myst::changeToCard(uint16 card, TransitionType transition) { // Make sure the screen is updated if (transition != kNoTransition) { - if (!_gameState->_globals.transitions) - transition = kTransitionCopy; - - _gfx->runTransition(transition, Common::Rect(544, 333), 10, 0); + if (_gameState->_globals.transitions) { + _gfx->runTransition(transition, Common::Rect(544, 333), 10, 0); + } else { + _gfx->copyBackBufferToScreen(Common::Rect(544, 333)); + _needsUpdate = true; + } } // Make sure we have the right cursor showing - _dragResource = 0; - _hoverResource = 0; + _hoverResource = nullptr; _curResource = -1; checkCurrentResource(); @@ -671,13 +637,13 @@ void MohawkEngine_Myst::checkCurrentResource() { // Tell previous resource the mouse is no longer hovering it if (_hoverResource && !_hoverResource->contains(mouse)) { _hoverResource->handleMouseLeave(); - _hoverResource = 0; + _hoverResource = nullptr; } for (uint16 i = 0; i < _resources.size(); i++) if (_resources[i]->contains(mouse)) { - if (_hoverResource != _resources[i] && _resources[i]->type == kMystHoverArea) { - _hoverResource = static_cast<MystResourceType13 *>(_resources[i]); + if (_hoverResource != _resources[i] && _resources[i]->type == kMystAreaHover) { + _hoverResource = static_cast<MystAreaHover *>(_resources[i]); _hoverResource->handleMouseEnter(); } @@ -694,17 +660,17 @@ void MohawkEngine_Myst::checkCurrentResource() { checkCursorHints(); } -MystResource *MohawkEngine_Myst::updateCurrentResource() { +MystArea *MohawkEngine_Myst::updateCurrentResource() { checkCurrentResource(); if (_curResource >= 0) return _resources[_curResource]; else - return 0; + return nullptr; } void MohawkEngine_Myst::loadCard() { - debugC(kDebugView, "Loading Card View:"); + debugC(kDebugView, "Loading Card View: %d", _curCard); Common::SeekableReadStream *viewStream = getResource(ID_VIEW, _curCard); @@ -713,21 +679,23 @@ void MohawkEngine_Myst::loadCard() { debugC(kDebugView, "Flags: 0x%04X", _view.flags); // The Image Block (Reminiscent of Riven PLST resources) - _view.conditionalImageCount = viewStream->readUint16LE(); - debugC(kDebugView, "Conditional Image Count: %d", _view.conditionalImageCount); - if (_view.conditionalImageCount != 0) { - _view.conditionalImages = new MystCondition[_view.conditionalImageCount]; - for (uint16 i = 0; i < _view.conditionalImageCount; i++) { + uint16 conditionalImageCount = viewStream->readUint16LE(); + debugC(kDebugView, "Conditional Image Count: %d", conditionalImageCount); + if (conditionalImageCount != 0) { + for (uint16 i = 0; i < conditionalImageCount; i++) { + MystCondition conditionalImage; + debugC(kDebugView, "\tImage %d:", i); - _view.conditionalImages[i].var = viewStream->readUint16LE(); - debugC(kDebugView, "\t\tVar: %d", _view.conditionalImages[i].var); - _view.conditionalImages[i].numStates = viewStream->readUint16LE(); - debugC(kDebugView, "\t\tNumber of States: %d", _view.conditionalImages[i].numStates); - _view.conditionalImages[i].values = new uint16[_view.conditionalImages[i].numStates]; - for (uint16 j = 0; j < _view.conditionalImages[i].numStates; j++) { - _view.conditionalImages[i].values[j] = viewStream->readUint16LE(); - debugC(kDebugView, "\t\tState %d -> Value %d", j, _view.conditionalImages[i].values[j]); + conditionalImage.var = viewStream->readUint16LE(); + debugC(kDebugView, "\t\tVar: %d", conditionalImage.var); + uint16 numStates = viewStream->readUint16LE(); + debugC(kDebugView, "\t\tNumber of States: %d", numStates); + for (uint16 j = 0; j < numStates; j++) { + conditionalImage.values.push_back(viewStream->readUint16LE()); + debugC(kDebugView, "\t\tState %d -> Value %d", j, conditionalImage.values[j]); } + + _view.conditionalImages.push_back(conditionalImage); } _view.mainImage = 0; } else { @@ -736,87 +704,58 @@ void MohawkEngine_Myst::loadCard() { } // The Sound Block (Reminiscent of Riven SLST resources) - _view.sound = viewStream->readSint16LE(); - debugCN(kDebugView, "Sound Control: %d = ", _view.sound); - if (_view.sound > 0) { - debugC(kDebugView, "Play new Sound, change volume"); - debugC(kDebugView, "\tSound: %d", _view.sound); - _view.soundVolume = viewStream->readUint16LE(); - debugC(kDebugView, "\tVolume: %d", _view.soundVolume); - } else if (_view.sound == kMystSoundActionContinue) - debugC(kDebugView, "Continue current sound"); - else if (_view.sound == kMystSoundActionChangeVolume) { - debugC(kDebugView, "Continue current sound, change volume"); - _view.soundVolume = viewStream->readUint16LE(); - debugC(kDebugView, "\tVolume: %d", _view.soundVolume); - } else if (_view.sound == kMystSoundActionStop) { - debugC(kDebugView, "Stop sound"); - } else if (_view.sound == kMystSoundActionConditional) { - debugC(kDebugView, "Conditional sound list"); - _view.soundVar = viewStream->readUint16LE(); - debugC(kDebugView, "\tVar: %d", _view.soundVar); - _view.soundCount = viewStream->readUint16LE(); - debugC(kDebugView, "\tCount: %d", _view.soundCount); - _view.soundList = new int16[_view.soundCount]; - _view.soundListVolume = new uint16[_view.soundCount]; - - for (uint16 i = 0; i < _view.soundCount; i++) { - _view.soundList[i] = viewStream->readSint16LE(); - debugC(kDebugView, "\t\tCondition %d: Action %d", i, _view.soundList[i]); - if (_view.soundList[i] == kMystSoundActionChangeVolume || _view.soundList[i] >= 0) { - _view.soundListVolume[i] = viewStream->readUint16LE(); - debugC(kDebugView, "\t\tCondition %d: Volume %d", i, _view.soundListVolume[i]); - } - } - } else { - debugC(kDebugView, "Unknown"); - warning("Unknown sound control value in card"); - } + _view.soundBlock = readSoundBlock(viewStream); // Resources that scripts can call upon - _view.scriptResCount = viewStream->readUint16LE(); - debugC(kDebugView, "Script Resource Count: %d", _view.scriptResCount); - if (_view.scriptResCount != 0) { - _view.scriptResources = new MystView::ScriptResource[_view.scriptResCount]; - for (uint16 i = 0; i < _view.scriptResCount; i++) { - debugC(kDebugView, "\tResource %d:", i); - _view.scriptResources[i].type = viewStream->readUint16LE(); - debugC(kDebugView, "\t\t Type: %d", _view.scriptResources[i].type); - - switch (_view.scriptResources[i].type) { - case 1: - debugC(kDebugView, "\t\t\t\t= Image"); - break; - case 2: - debugC(kDebugView, "\t\t\t\t= Sound"); - break; - case 3: - debugC(kDebugView, "\t\t\t\t= Resource List"); - break; - default: - debugC(kDebugView, "\t\t\t\t= Unknown"); - break; - } + uint16 scriptResCount = viewStream->readUint16LE(); + debugC(kDebugView, "Script Resource Count: %d", scriptResCount); + for (uint16 i = 0; i < scriptResCount; i++) { + MystView::ScriptResource scriptResource; + + debugC(kDebugView, "\tResource %d:", i); + scriptResource.type = (MystView::ScriptResourceType) viewStream->readUint16LE(); + debugC(kDebugView, "\t\t Type: %d", scriptResource.type); + + switch (scriptResource.type) { + case MystView::kResourceImage: + debugC(kDebugView, "\t\t\t\t= Image"); + break; + case MystView::kResourceSound: + debugC(kDebugView, "\t\t\t\t= Sound"); + break; + case MystView::kResourceSwitch: + debugC(kDebugView, "\t\t\t\t= Resource Switch"); + break; + case MystView::kResourceImageNoCache: + debugC(kDebugView, "\t\t\t\t= Image - Caching disabled"); + break; + case MystView::kResourceSoundNoCache: + debugC(kDebugView, "\t\t\t\t= Sound - Caching disabled"); + break; + default: + debugC(kDebugView, "\t\t\t\t= Unknown"); + warning("Unknown script resource type '%d' in card '%d'", scriptResource.type, _curCard); + break; + } - if (_view.scriptResources[i].type == 3) { - _view.scriptResources[i].var = viewStream->readUint16LE(); - debugC(kDebugView, "\t\t Var: %d", _view.scriptResources[i].var); - _view.scriptResources[i].count = viewStream->readUint16LE(); - debugC(kDebugView, "\t\t Resource List Count: %d", _view.scriptResources[i].count); - _view.scriptResources[i].u0 = viewStream->readUint16LE(); - debugC(kDebugView, "\t\t u0: %d", _view.scriptResources[i].u0); - _view.scriptResources[i].resource_list = new int16[_view.scriptResources[i].count]; - - for (uint16 j = 0; j < _view.scriptResources[i].count; j++) { - _view.scriptResources[i].resource_list[j] = viewStream->readSint16LE(); - debugC(kDebugView, "\t\t Resource List %d: %d", j, _view.scriptResources[i].resource_list[j]); - } - } else { - _view.scriptResources[i].resource_list = NULL; - _view.scriptResources[i].id = viewStream->readUint16LE(); - debugC(kDebugView, "\t\t Id: %d", _view.scriptResources[i].id); + if (scriptResource.type == MystView::kResourceSwitch) { + scriptResource.switchVar = viewStream->readUint16LE(); + debugC(kDebugView, "\t\t Var: %d", scriptResource.switchVar); + uint16 count = viewStream->readUint16LE(); + debugC(kDebugView, "\t\t Resource List Count: %d", count); + scriptResource.switchResourceType = (MystView::ScriptResourceType) viewStream->readUint16LE(); + debugC(kDebugView, "\t\t u0: %d", scriptResource.switchResourceType); + + for (uint16 j = 0; j < count; j++) { + scriptResource.switchResourceIds.push_back(viewStream->readSint16LE()); + debugC(kDebugView, "\t\t Resource List %d: %d", j, scriptResource.switchResourceIds[j]); } + } else { + scriptResource.id = viewStream->readUint16LE(); + debugC(kDebugView, "\t\t Id: %d", scriptResource.id); } + + _view.scriptResources.push_back(scriptResource); } // Identifiers for other resources. 0 if non existent. There is always an RLST. @@ -831,7 +770,6 @@ void MohawkEngine_Myst::loadCard() { delete viewStream; // Precache Card Resources - // TODO: Deal with Mac ME External Picture File uint32 cacheImageType; if (getFeatures() & GF_ME) cacheImageType = ID_PICT; @@ -839,63 +777,58 @@ void MohawkEngine_Myst::loadCard() { cacheImageType = ID_WDIB; // Precache Image Block data - if (_view.conditionalImageCount != 0) { - for (uint16 i = 0; i < _view.conditionalImageCount; i++) - for (uint16 j = 0; j < _view.conditionalImages[i].numStates; j++) - cachePreload(cacheImageType, _view.conditionalImages[i].values[j]); - } else + if (_view.conditionalImages.size() != 0) { + for (uint16 i = 0; i < _view.conditionalImages.size(); i++) { + uint16 value = _scriptParser->getVar(_view.conditionalImages[i].var); + cachePreload(cacheImageType, _view.conditionalImages[i].values[value]); + } + } else { cachePreload(cacheImageType, _view.mainImage); + } // Precache Sound Block data - if (_view.sound > 0) - cachePreload(ID_MSND, _view.sound); - else if (_view.sound == kMystSoundActionConditional) { - for (uint16 i = 0; i < _view.soundCount; i++) { - if (_view.soundList[i] > 0) - cachePreload(ID_MSND, _view.soundList[i]); + if (_view.soundBlock.sound > 0) + cachePreload(ID_MSND, _view.soundBlock.sound); + else if (_view.soundBlock.sound == kMystSoundActionConditional) { + uint16 value = _scriptParser->getVar(_view.soundBlock.soundVar); + if (_view.soundBlock.soundList[value].action > 0) { + cachePreload(ID_MSND, _view.soundBlock.soundList[value].action); } } // Precache Script Resources - if (_view.scriptResCount != 0) { - for (uint16 i = 0; i < _view.scriptResCount; i++) { - switch (_view.scriptResources[i].type) { - case 1: - cachePreload(cacheImageType, _view.scriptResources[i].id); - break; - case 2: - cachePreload(ID_MSND, _view.scriptResources[i].id); - break; - case 3: - warning("TODO: Precaching of Script Resource List not supported"); - break; - default: - warning("Unknown Resource in Script Resource List Precaching"); - break; - } + for (uint16 i = 0; i < _view.scriptResources.size(); i++) { + MystView::ScriptResourceType type; + int16 id; + if (_view.scriptResources[i].type == MystView::kResourceSwitch) { + type = _view.scriptResources[i].switchResourceType; + uint16 value = _scriptParser->getVar(_view.scriptResources[i].switchVar); + id = _view.scriptResources[i].switchResourceIds[value]; + } else { + type = _view.scriptResources[i].type; + id = _view.scriptResources[i].id; + } + + if (id < 0) continue; + + switch (type) { + case MystView::kResourceImage: + cachePreload(cacheImageType, id); + break; + case MystView::kResourceSound: + cachePreload(ID_MSND, id); + break; + default: + // The other resource types should not be cached + break; } } } void MohawkEngine_Myst::unloadCard() { - for (uint16 i = 0; i < _view.conditionalImageCount; i++) - delete[] _view.conditionalImages[i].values; - - delete[] _view.conditionalImages; - _view.conditionalImageCount = 0; - _view.conditionalImages = NULL; - - delete[] _view.soundList; - _view.soundList = NULL; - delete[] _view.soundListVolume; - _view.soundListVolume = NULL; - - for (uint16 i = 0; i < _view.scriptResCount; i++) - delete[] _view.scriptResources[i].resource_list; - - delete[] _view.scriptResources; - _view.scriptResources = NULL; - _view.scriptResCount = 0; + _view.conditionalImages.clear(); + _view.soundBlock.soundList.clear(); + _view.scriptResources.clear(); } void MohawkEngine_Myst::runInitScript() { @@ -968,14 +901,12 @@ void MohawkEngine_Myst::loadHelp(uint16 id) { debugC(kDebugHelp, "\thelpText: \"%s\"", helpText.c_str()); delete[] u0; + + delete helpStream; } void MohawkEngine_Myst::loadCursorHints() { - for (uint16 i = 0; i < _cursorHintCount; i++) - delete[] _cursorHints[i].variableHint.values; - _cursorHintCount = 0; - delete[] _cursorHints; - _cursorHints = NULL; + _cursorHints.clear(); if (!_view.hint) { debugC(kDebugHint, "No HINT Present"); @@ -985,33 +916,33 @@ void MohawkEngine_Myst::loadCursorHints() { debugC(kDebugHint, "Loading Cursor Hints:"); Common::SeekableReadStream *hintStream = getResource(ID_HINT, _curCard); - _cursorHintCount = hintStream->readUint16LE(); - debugC(kDebugHint, "Cursor Hint Count: %d", _cursorHintCount); - _cursorHints = new MystCursorHint[_cursorHintCount]; + uint16 cursorHintCount = hintStream->readUint16LE(); + debugC(kDebugHint, "Cursor Hint Count: %d", cursorHintCount); + + for (uint16 i = 0; i < cursorHintCount; i++) { + MystCursorHint hint; - for (uint16 i = 0; i < _cursorHintCount; i++) { debugC(kDebugHint, "Cursor Hint %d:", i); - _cursorHints[i].id = hintStream->readUint16LE(); - debugC(kDebugHint, "\tId: %d", _cursorHints[i].id); - _cursorHints[i].cursor = hintStream->readSint16LE(); - debugC(kDebugHint, "\tCursor: %d", _cursorHints[i].cursor); + hint.id = hintStream->readUint16LE(); + debugC(kDebugHint, "\tId: %d", hint.id); + hint.cursor = hintStream->readSint16LE(); + debugC(kDebugHint, "\tCursor: %d", hint.cursor); - if (_cursorHints[i].cursor == -1) { + if (hint.cursor == -1) { debugC(kDebugHint, "\tConditional Cursor Hints:"); - _cursorHints[i].variableHint.var = hintStream->readUint16LE(); - debugC(kDebugHint, "\tVar: %d", _cursorHints[i].variableHint.var); - _cursorHints[i].variableHint.numStates = hintStream->readUint16LE(); - debugC(kDebugHint, "\tNumber of States: %d", _cursorHints[i].variableHint.numStates); - _cursorHints[i].variableHint.values = new uint16[_cursorHints[i].variableHint.numStates]; - for (uint16 j = 0; j < _cursorHints[i].variableHint.numStates; j++) { - _cursorHints[i].variableHint.values[j] = hintStream->readUint16LE(); - debugC(kDebugHint, "\t\t State %d: Cursor %d", j, _cursorHints[i].variableHint.values[j]); + hint.variableHint.var = hintStream->readUint16LE(); + debugC(kDebugHint, "\tVar: %d", hint.variableHint.var); + uint16 numStates = hintStream->readUint16LE(); + debugC(kDebugHint, "\tNumber of States: %d", numStates); + for (uint16 j = 0; j < numStates; j++) { + hint.variableHint.values.push_back(hintStream->readUint16LE()); + debugC(kDebugHint, "\t\t State %d: Cursor %d", j, hint.variableHint.values[j]); } } else { - _cursorHints[i].variableHint.var = 0; - _cursorHints[i].variableHint.numStates = 0; - _cursorHints[i].variableHint.values = NULL; + hint.variableHint.var = 0; } + + _cursorHints.push_back(hint); } delete hintStream; @@ -1033,12 +964,12 @@ void MohawkEngine_Myst::checkCursorHints() { } // Check all the cursor hints to see if we're in a hotspot that contains a hint. - for (uint16 i = 0; i < _cursorHintCount; i++) + for (uint16 i = 0; i < _cursorHints.size(); i++) if (_cursorHints[i].id == _curResource && _resources[_cursorHints[i].id]->isEnabled()) { if (_cursorHints[i].cursor == -1) { uint16 var_value = _scriptParser->getVar(_cursorHints[i].variableHint.var); - if (var_value >= _cursorHints[i].variableHint.numStates) + if (var_value >= _cursorHints[i].variableHint.values.size()) warning("Variable %d Out of Range in variable HINT Resource %d", _cursorHints[i].variableHint.var, i); else { _currentCursor = _cursorHints[i].variableHint.values[var_value]; @@ -1076,50 +1007,50 @@ void MohawkEngine_Myst::drawResourceImages() { _resources[i]->drawDataToScreen(); } -void MohawkEngine_Myst::redrawResource(MystResourceType8 *resource, bool update) { - resource->drawConditionalDataToScreen(_scriptParser->getVar(resource->getType8Var()), update); +void MohawkEngine_Myst::redrawResource(MystAreaImageSwitch *resource, bool update) { + resource->drawConditionalDataToScreen(_scriptParser->getVar(resource->getImageSwitchVar()), update); } void MohawkEngine_Myst::redrawArea(uint16 var, bool update) { for (uint16 i = 0; i < _resources.size(); i++) - if (_resources[i]->type == kMystConditionalImage && _resources[i]->getType8Var() == var) - redrawResource(static_cast<MystResourceType8 *>(_resources[i]), update); + if (_resources[i]->type == kMystAreaImageSwitch && _resources[i]->getImageSwitchVar() == var) + redrawResource(static_cast<MystAreaImageSwitch *>(_resources[i]), update); } -MystResource *MohawkEngine_Myst::loadResource(Common::SeekableReadStream *rlstStream, MystResource *parent) { - MystResource *resource = 0; +MystArea *MohawkEngine_Myst::loadResource(Common::SeekableReadStream *rlstStream, MystArea *parent) { + MystArea *resource = nullptr; ResourceType type = static_cast<ResourceType>(rlstStream->readUint16LE()); debugC(kDebugResource, "\tType: %d", type); - debugC(kDebugResource, "\tSub_Record: %d", (parent == NULL) ? 0 : 1); + debugC(kDebugResource, "\tSub_Record: %d", (parent == nullptr) ? 0 : 1); switch (type) { - case kMystAction: - resource = new MystResourceType5(this, rlstStream, parent); + case kMystAreaAction: + resource = new MystAreaAction(this, rlstStream, parent); break; - case kMystVideo: - resource = new MystResourceType6(this, rlstStream, parent); + case kMystAreaVideo: + resource = new MystAreaVideo(this, rlstStream, parent); break; - case kMystSwitch: - resource = new MystResourceType7(this, rlstStream, parent); + case kMystAreaActionSwitch: + resource = new MystAreaActionSwitch(this, rlstStream, parent); break; - case kMystConditionalImage: - resource = new MystResourceType8(this, rlstStream, parent); + case kMystAreaImageSwitch: + resource = new MystAreaImageSwitch(this, rlstStream, parent); break; - case kMystSlider: - resource = new MystResourceType10(this, rlstStream, parent); + case kMystAreaSlider: + resource = new MystAreaSlider(this, rlstStream, parent); break; - case kMystDragArea: - resource = new MystResourceType11(this, rlstStream, parent); + case kMystAreaDrag: + resource = new MystAreaDrag(this, rlstStream, parent); break; case kMystVideoInfo: - resource = new MystResourceType12(this, rlstStream, parent); + resource = new MystVideoInfo(this, rlstStream, parent); break; - case kMystHoverArea: - resource = new MystResourceType13(this, rlstStream, parent); + case kMystAreaHover: + resource = new MystAreaHover(this, rlstStream, parent); break; default: - resource = new MystResource(this, rlstStream, parent); + resource = new MystArea(this, rlstStream, parent); break; } @@ -1145,34 +1076,42 @@ void MohawkEngine_Myst::loadResources() { for (uint16 i = 0; i < resourceCount; i++) { debugC(kDebugResource, "Resource #%d:", i); - _resources.push_back(loadResource(rlstStream, NULL)); + _resources.push_back(loadResource(rlstStream, nullptr)); } delete rlstStream; } Common::Error MohawkEngine_Myst::loadGameState(int slot) { - if (_gameState->load(_gameState->generateSaveGameList()[slot])) + if (_gameState->load(MystGameState::generateSaveGameList()[slot])) return Common::kNoError; return Common::kUnknownError; } Common::Error MohawkEngine_Myst::saveGameState(int slot, const Common::String &desc) { - Common::StringArray saveList = _gameState->generateSaveGameList(); + Common::StringArray saveList = MystGameState::generateSaveGameList(); if ((uint)slot < saveList.size()) - _gameState->deleteSave(saveList[slot]); + MystGameState::deleteSave(saveList[slot]); + + return _gameState->save(desc) ? Common::kNoError : Common::kUnknownError; +} - return _gameState->save(Common::String(desc)) ? Common::kNoError : Common::kUnknownError; +bool MohawkEngine_Myst::hasGameSaveSupport() const { + return !(getFeatures() & GF_DEMO) && getGameType() != GType_MAKINGOF; } bool MohawkEngine_Myst::canLoadGameStateCurrently() { // No loading in the demo/makingof - return !(getFeatures() & GF_DEMO) && getGameType() != GType_MAKINGOF; + return _canSafelySaveLoad && hasGameSaveSupport(); } bool MohawkEngine_Myst::canSaveGameStateCurrently() { + if (!_canSafelySaveLoad) { + return false; + } + // There's a limited number of stacks the game can save in switch (_curStack) { case kChannelwoodStack: @@ -1225,4 +1164,82 @@ void MohawkEngine_Myst::dropPage() { checkCursorHints(); } +MystSoundBlock MohawkEngine_Myst::readSoundBlock(Common::ReadStream *stream) const { + MystSoundBlock soundBlock; + soundBlock.sound = stream->readSint16LE(); + debugCN(kDebugView, "Sound Control: %d = ", soundBlock.sound); + + if (soundBlock.sound > 0) { + debugC(kDebugView, "Play new Sound, change volume"); + debugC(kDebugView, "\tSound: %d", soundBlock.sound); + soundBlock.soundVolume = stream->readUint16LE(); + debugC(kDebugView, "\tVolume: %d", soundBlock.soundVolume); + } else if (soundBlock.sound == kMystSoundActionContinue) + debugC(kDebugView, "Continue current sound"); + else if (soundBlock.sound == kMystSoundActionChangeVolume) { + debugC(kDebugView, "Continue current sound, change volume"); + soundBlock.soundVolume = stream->readUint16LE(); + debugC(kDebugView, "\tVolume: %d", soundBlock.soundVolume); + } else if (soundBlock.sound == kMystSoundActionStop) { + debugC(kDebugView, "Stop sound"); + } else if (soundBlock.sound == kMystSoundActionConditional) { + debugC(kDebugView, "Conditional sound list"); + soundBlock.soundVar = stream->readUint16LE(); + debugC(kDebugView, "\tVar: %d", soundBlock.soundVar); + uint16 soundCount = stream->readUint16LE(); + debugC(kDebugView, "\tCount: %d", soundCount); + + for (uint16 i = 0; i < soundCount; i++) { + MystSoundBlock::SoundItem sound; + + sound.action = stream->readSint16LE(); + debugC(kDebugView, "\t\tCondition %d: Action %d", i, sound.action); + if (sound.action == kMystSoundActionChangeVolume || sound.action >= 0) { + sound.volume = stream->readUint16LE(); + debugC(kDebugView, "\t\tCondition %d: Volume %d", i, sound.volume); + } + + soundBlock.soundList.push_back(sound); + } + } else { + debugC(kDebugView, "Unknown"); + warning("Unknown sound control value '%d' in card '%d'", soundBlock.sound, _curCard); + } + + return soundBlock; +} + +void MohawkEngine_Myst::applySoundBlock(const MystSoundBlock &block) { + int16 soundAction = 0; + uint16 soundActionVolume = 0; + + if (block.sound == kMystSoundActionConditional) { + uint16 soundVarValue = _scriptParser->getVar(block.soundVar); + if (soundVarValue >= block.soundList.size()) + warning("Conditional sound variable outside range"); + else { + soundAction = block.soundList[soundVarValue].action; + soundActionVolume = block.soundList[soundVarValue].volume; + } + } else { + soundAction = block.sound; + soundActionVolume = block.soundVolume; + } + + if (soundAction == kMystSoundActionContinue) + debug(2, "Continuing with current sound"); + else if (soundAction == kMystSoundActionChangeVolume) { + debug(2, "Continuing with current sound, changing volume"); + _sound->changeBackgroundVolumeMyst(soundActionVolume); + } else if (soundAction == kMystSoundActionStop) { + debug(2, "Stopping sound"); + _sound->stopBackgroundMyst(); + } else if (soundAction > 0) { + debug(2, "Playing new sound %d", soundAction); + _sound->replaceBackgroundMyst(soundAction, soundActionVolume); + } else { + error("Unknown sound action %d", soundAction); + } +} + } // End of namespace Mohawk diff --git a/engines/mohawk/myst.h b/engines/mohawk/myst.h index 4d86642652..0b249e5499 100644 --- a/engines/mohawk/myst.h +++ b/engines/mohawk/myst.h @@ -28,10 +28,9 @@ #include "mohawk/resource_cache.h" #include "mohawk/myst_scripts.h" +#include "common/events.h" #include "common/random.h" -#include "gui/saveload.h" - namespace Mohawk { class MohawkEngine_Myst; @@ -41,9 +40,9 @@ class MystScriptParser; class MystConsole; class MystGameState; class MystOptionsDialog; -class MystResource; -class MystResourceType8; -class MystResourceType13; +class MystArea; +class MystAreaImageSwitch; +class MystAreaHover; // Engine Debug Flags enum { @@ -96,8 +95,19 @@ const uint16 kMasterpieceOnly = 0xFFFF; struct MystCondition { uint16 var; - uint16 numStates; - uint16 *values; + Common::Array<uint16> values; +}; + +struct MystSoundBlock { + struct SoundItem { + int16 action; + uint16 volume; + }; + + int16 sound; + uint16 soundVolume; + uint16 soundVar; + Common::Array<SoundItem> soundList; }; // View Sound Action Type @@ -118,29 +128,29 @@ struct MystView { uint16 flags; // Image Data - uint16 conditionalImageCount; - MystCondition *conditionalImages; + Common::Array<MystCondition> conditionalImages; uint16 mainImage; // Sound Data - int16 sound; - uint16 soundVolume; - uint16 soundVar; - uint16 soundCount; - int16 *soundList; - uint16 *soundListVolume; + MystSoundBlock soundBlock; // Script Resources - uint16 scriptResCount; + enum ScriptResourceType { + kResourceImage = 1, + kResourceSound = 2, + kResourceSwitch = 3, + kResourceImageNoCache = 4, + kResourceSoundNoCache = 5 + }; + struct ScriptResource { - uint16 type; - uint16 id; // Not used by type 3 - // TODO: Type 3 has more. Maybe use a union? - uint16 var; // Used by type 3 only - uint16 count; // Used by type 3 only - uint16 u0; // Used by type 3 only - int16 *resource_list; // Used by type 3 only - } *scriptResources; + ScriptResourceType type; + uint16 id; + uint16 switchVar; + ScriptResourceType switchResourceType; + Common::Array<int16> switchResourceIds; + }; + Common::Array<ScriptResource> scriptResources; // Resource ID's uint16 rlst; @@ -158,18 +168,17 @@ struct MystCursorHint { class MohawkEngine_Myst : public MohawkEngine { protected: - Common::Error run(); + Common::Error run() override; public: MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription *gamedesc); virtual ~MohawkEngine_Myst(); - Common::SeekableReadStream *getResource(uint32 tag, uint16 id); + Common::SeekableReadStream *getResource(uint32 tag, uint16 id) override; + Common::Array<uint16> getResourceIDList(uint32 type) const; Common::String wrapMovieFilename(const Common::String &movieName, uint16 stack); - void reloadSaveList(); - void changeToStack(uint16 stack, uint16 card, uint16 linkSrcSound, uint16 linkDstSound); void changeToCard(uint16 card, TransitionType transition); uint16 getCurCard() { return _curCard; } @@ -177,46 +186,50 @@ public: void setMainCursor(uint16 cursor); uint16 getMainCursor() { return _mainCursor; } void checkCursorHints(); - MystResource *updateCurrentResource(); + MystArea *updateCurrentResource(); bool skippableWait(uint32 duration); - bool _tweaksEnabled; + MystSoundBlock readSoundBlock(Common::ReadStream *stream) const; + void applySoundBlock(const MystSoundBlock &block); + bool _needsUpdate; bool _needsPageDrop; bool _needsShowMap; bool _needsShowDemoMenu; + bool _needsShowCredits; + + bool _showResourceRects; - MystView _view; MystGraphics *_gfx; MystGameState *_gameState; MystScriptParser *_scriptParser; - Common::Array<MystResource *> _resources; - MystResource *_dragResource; + Common::Array<MystArea *> _resources; Common::RandomSource *_rnd; - bool _showResourceRects; - MystResource *loadResource(Common::SeekableReadStream *rlstStream, MystResource *parent); + MystArea *loadResource(Common::SeekableReadStream *rlstStream, MystArea *parent); void setResourceEnabled(uint16 resourceId, bool enable); void redrawArea(uint16 var, bool update = true); - void redrawResource(MystResourceType8 *resource, bool update = true); + void redrawResource(MystAreaImageSwitch *resource, bool update = true); void drawResourceImages(); void drawCardBackground(); uint16 getCardBackgroundId(); + template<class T> + T *getViewResource(uint index); + void setCacheState(bool state) { _cache.enabled = state; } bool getCacheState() { return _cache.enabled; } - GUI::Debugger *getDebugger() { return _console; } + GUI::Debugger *getDebugger() override { return _console; } - bool canLoadGameStateCurrently(); - bool canSaveGameStateCurrently(); - Common::Error loadGameState(int slot); - Common::Error saveGameState(int slot, const Common::String &desc); - bool hasFeature(EngineFeature f) const; + bool canLoadGameStateCurrently() override; + bool canSaveGameStateCurrently() override; + Common::Error loadGameState(int slot) override; + Common::Error saveGameState(int slot, const Common::String &desc) override; + bool hasFeature(EngineFeature f) const override; private: MystConsole *_console; - GUI::SaveLoadChooser *_loadDialog; MystOptionsDialog *_optionsDialog; MystScriptParser *_prevStack; ResourceCache _cache; @@ -224,9 +237,18 @@ private: uint16 _curStack; uint16 _curCard; + MystView _view; bool _runExitScript; + /** + * Saving / Loading is only allowed from the main event loop + */ + bool _canSafelySaveLoad; + bool hasGameSaveSupport() const; + + bool pollEvent(Common::Event &event); + void dropPage(); void loadCard(); @@ -240,15 +262,25 @@ private: void drawResourceRects(); void checkCurrentResource(); int16 _curResource; - MystResourceType13 *_hoverResource; + MystAreaHover *_hoverResource; - uint16 _cursorHintCount; - MystCursorHint *_cursorHints; + Common::Array<MystCursorHint> _cursorHints; void loadCursorHints(); uint16 _currentCursor; uint16 _mainCursor; // Also defines the current page being held (white, blue, red, or none) }; +template<class T> +T *MohawkEngine_Myst::getViewResource(uint index) { + T *resource = dynamic_cast<T *>(_resources[index]); + + if (!resource) { + error("View resource '%d' has unexpected type", index); + } + + return resource; +} + } // End of namespace Mohawk #endif diff --git a/engines/mohawk/myst_areas.cpp b/engines/mohawk/myst_areas.cpp index 7a9596d8e0..4b9cf546fa 100644 --- a/engines/mohawk/myst_areas.cpp +++ b/engines/mohawk/myst_areas.cpp @@ -32,11 +32,11 @@ namespace Mohawk { -MystResource::MystResource(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) { +MystArea::MystArea(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) { _vm = vm; _parent = parent; - if (parent == NULL) { + if (parent == nullptr) { _flags = rlstStream->readUint16LE(); _rect.left = rlstStream->readSint16LE(); _rect.top = rlstStream->readSint16LE(); @@ -66,10 +66,10 @@ MystResource::MystResource(MohawkEngine_Myst *vm, Common::SeekableReadStream *rl debugC(kDebugResource, "\tdest: %d", _dest); } -MystResource::~MystResource() { +MystArea::~MystArea() { } -void MystResource::handleMouseUp() { +void MystArea::handleMouseUp() { if (_dest == 0) { warning("Movement type resource with null destination at position (%d, %d), (%d, %d)", _rect.left, _rect.top, _rect.right, _rect.bottom); return; @@ -78,13 +78,13 @@ void MystResource::handleMouseUp() { uint16 opcode; switch (type) { - case kMystForwardArea: + case kMystAreaForward: opcode = 6; break; - case kMystLeftArea: + case kMystAreaLeft: opcode = 8; break; - case kMystRightArea: + case kMystAreaRight: opcode = 7; break; default: @@ -96,27 +96,27 @@ void MystResource::handleMouseUp() { _vm->_scriptParser->runOpcode(opcode, 0); } -bool MystResource::canBecomeActive() { +bool MystArea::canBecomeActive() { return !unreachableZipDest() && (isEnabled() || (_flags & kMystUnknownFlag)); } -bool MystResource::unreachableZipDest() { +bool MystArea::unreachableZipDest() { return (_flags & kMystZipModeEnableFlag) && !_vm->_gameState->isReachableZipDest(_vm->getCurStack() , _dest); } -bool MystResource::isEnabled() { +bool MystArea::isEnabled() { return _flags & kMystHotspotEnableFlag; } -void MystResource::setEnabled(bool enabled) { +void MystArea::setEnabled(bool enabled) { if (enabled) _flags |= kMystHotspotEnableFlag; else _flags &= ~kMystHotspotEnableFlag; } -const Common::String MystResource::describe() { +const Common::String MystArea::describe() { Common::String desc = Common::String::format("type: %2d rect: (%3d %3d %3d %3d)", type, _rect.left, _rect.top, _rect.width(), _rect.height()); @@ -126,7 +126,7 @@ const Common::String MystResource::describe() { return desc; } -void MystResource::drawBoundingRect() { +void MystArea::drawBoundingRect() { if (_rect.isValidRect()) { if (!canBecomeActive()) _vm->_gfx->drawRect(_rect, kRectUnreachable); @@ -137,18 +137,19 @@ void MystResource::drawBoundingRect() { } } -MystResourceType5::MystResourceType5(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResource(vm, rlstStream, parent) { +MystAreaAction::MystAreaAction(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystArea(vm, rlstStream, parent) { debugC(kDebugResource, "\tResource Type 5 Script:"); _script = vm->_scriptParser->readScript(rlstStream, kMystScriptNormal); } -void MystResourceType5::handleMouseUp() { +void MystAreaAction::handleMouseUp() { _vm->_scriptParser->runScript(_script, this); } -const Common::String MystResourceType5::describe() { - Common::String desc = MystResource::describe(); +const Common::String MystAreaAction::describe() { + Common::String desc = MystArea::describe(); if (_script->size() != 0) { desc += " ops:"; @@ -161,7 +162,7 @@ const Common::String MystResourceType5::describe() { } // In Myst/Making of Myst, the paths are hardcoded ala Windows style without extension. Convert them. -Common::String MystResourceType6::convertMystVideoName(Common::String name) { +Common::String MystAreaVideo::convertMystVideoName(Common::String name) { Common::String temp; for (uint32 i = 1; i < name.size(); i++) { @@ -174,7 +175,8 @@ Common::String MystResourceType6::convertMystVideoName(Common::String name) { return temp + ".mov"; } -MystResourceType6::MystResourceType6(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResourceType5(vm, rlstStream, parent) { +MystAreaVideo::MystAreaVideo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystAreaAction(vm, rlstStream, parent) { char c = 0; do { @@ -197,16 +199,7 @@ MystResourceType6::MystResourceType6(MohawkEngine_Myst *vm, Common::SeekableRead _direction = rlstStream->readSint16LE(); _playBlocking = rlstStream->readUint16LE(); _loop = rlstStream->readUint16LE(); - _u3 = rlstStream->readUint16LE(); - - // TODO: Out of bound values should clip the movie - if (_left < 0) - _left = 0; - if (_top < 0) - _top = 0; - - if (_u3 != 0) - warning("Type 6 _u3 != 0"); + _playRate = rlstStream->readUint16LE(); debugC(kDebugResource, "\tvideoFile: \"%s\"", _videoFile.c_str()); debugC(kDebugResource, "\tleft: %d", _left); @@ -215,15 +208,15 @@ MystResourceType6::MystResourceType6(MohawkEngine_Myst *vm, Common::SeekableRead debugC(kDebugResource, "\tdirection: %d", _direction); debugC(kDebugResource, "\tplayBlocking: %d", _playBlocking); debugC(kDebugResource, "\tplayOnCardChange: %d", _playOnCardChange); - debugC(kDebugResource, "\tu3: %d", _u3); + debugC(kDebugResource, "\tplayRate: %d", _playRate); } -VideoHandle MystResourceType6::playMovie() { +VideoHandle MystAreaVideo::playMovie() { // Check if the video is already running VideoHandle handle = _vm->_video->findVideoHandle(_videoFile); // If the video is not running, play it - if (!handle || handle->endOfVideo()) { + if (!handle) { handle = _vm->_video->playMovie(_videoFile); if (!handle) error("Failed to open '%s'", _videoFile.c_str()); @@ -231,13 +224,23 @@ VideoHandle MystResourceType6::playMovie() { handle->moveTo(_left, _top); handle->setLooping(_loop != 0); + Common::Rational rate; + if (_playRate != 0) { + rate = Common::Rational(_playRate, 100); + } else { + rate = 1; + } + if (_direction == -1) { + rate = -rate; handle->seek(handle->getDuration()); - handle->setRate(-1); } + + handle->setRate(rate); } else { // Resume the video handle->pause(false); + handle->start(); } if (_playBlocking) { @@ -248,186 +251,156 @@ VideoHandle MystResourceType6::playMovie() { return handle; } -void MystResourceType6::handleCardChange() { +VideoHandle MystAreaVideo::getMovieHandle() { + // If the video is already in the manager, just return the handle + VideoHandle handle = _vm->_video->findVideoHandle(_videoFile); + if (!handle) { + // If the video has not been loaded yet, do it but don't start playing it + handle = _vm->_video->playMovie(_videoFile); + if (!handle) + error("Failed to open '%s'", _videoFile.c_str()); + handle->stop(); + } + + return handle; +} + +void MystAreaVideo::handleCardChange() { if (_playOnCardChange) playMovie(); } -bool MystResourceType6::isPlaying() { +bool MystAreaVideo::isPlaying() { VideoHandle handle = _vm->_video->findVideoHandle(_videoFile); return handle && !handle->endOfVideo(); } -void MystResourceType6::pauseMovie(bool pause) { +void MystAreaVideo::pauseMovie(bool pause) { VideoHandle handle = _vm->_video->findVideoHandle(_videoFile); if (handle && !handle->endOfVideo()) handle->pause(pause); } -MystResourceType7::MystResourceType7(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResource(vm, rlstStream, parent) { - _var7 = rlstStream->readUint16LE(); - _numSubResources = rlstStream->readUint16LE(); - debugC(kDebugResource, "\tvar7: %d", _var7); - debugC(kDebugResource, "\tnumSubResources: %d", _numSubResources); +MystAreaActionSwitch::MystAreaActionSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystArea(vm, rlstStream, parent) { + _actionSwitchVar = rlstStream->readUint16LE(); + uint16 numSubResources = rlstStream->readUint16LE(); + debugC(kDebugResource, "\tactionSwitchVar: %d", _actionSwitchVar); + debugC(kDebugResource, "\tnumSubResources: %d", numSubResources); - for (uint16 i = 0; i < _numSubResources; i++) + for (uint16 i = 0; i < numSubResources; i++) _subResources.push_back(vm->loadResource(rlstStream, this)); } -MystResourceType7::~MystResourceType7() { +MystAreaActionSwitch::~MystAreaActionSwitch() { for (uint32 i = 0; i < _subResources.size(); i++) delete _subResources[i]; _subResources.clear(); } -// TODO: All these functions to switch subresource are very similar. -// Find way to share code (function pointer pass?) -void MystResourceType7::drawDataToScreen() { - if (_var7 == 0xFFFF) { - if (_numSubResources == 1) - _subResources[0]->drawDataToScreen(); - else if (_numSubResources != 0) - warning("Type 7 Resource with _numSubResources of %d, but no control variable", _numSubResources); +void MystAreaActionSwitch::doSwitch(AreaHandler handler) { + if (_actionSwitchVar == 0xFFFF) { + if (_subResources.size() == 1) + (_subResources[0]->*handler)(); + else if (_subResources.size() != 0) + warning("Action switch resource with _numSubResources of %d, but no control variable", _subResources.size()); } else { - uint16 varValue = _vm->_scriptParser->getVar(_var7); + uint16 varValue = _vm->_scriptParser->getVar(_actionSwitchVar); - if (_numSubResources == 1 && varValue != 0) - _subResources[0]->drawDataToScreen(); - else if (_numSubResources != 0) { - if (varValue < _numSubResources) - _subResources[varValue]->drawDataToScreen(); + if (_subResources.size() == 1 && varValue != 0) + (_subResources[0]->*handler)(); + else if (_subResources.size() != 0) { + if (varValue < _subResources.size()) + (_subResources[varValue]->*handler)(); else - warning("Type 7 Resource Var %d: %d exceeds number of sub resources %d", _var7, varValue, _numSubResources); + warning("Action switch resource Var %d: %d exceeds number of sub resources %d", _actionSwitchVar, varValue, _subResources.size()); } } } -void MystResourceType7::handleCardChange() { - if (_var7 == 0xFFFF) { - if (_numSubResources == 1) - _subResources[0]->handleCardChange(); - else if (_numSubResources != 0) - warning("Type 7 Resource with _numSubResources of %d, but no control variable", _numSubResources); - } else { - uint16 varValue = _vm->_scriptParser->getVar(_var7); - - if (_numSubResources == 1 && varValue != 0) - _subResources[0]->handleCardChange(); - else if (_numSubResources != 0) { - if (varValue < _numSubResources) - _subResources[varValue]->handleCardChange(); - else - warning("Type 7 Resource Var %d: %d exceeds number of sub resources %d", _var7, varValue, _numSubResources); - } - } +void MystAreaActionSwitch::drawDataToScreen() { + doSwitch(&MystArea::drawDataToScreen); } -void MystResourceType7::handleMouseUp() { - if (_var7 == 0xFFFF) { - if (_numSubResources == 1) - _subResources[0]->handleMouseUp(); - else if (_numSubResources != 0) - warning("Type 7 Resource with _numSubResources of %d, but no control variable", _numSubResources); - } else { - uint16 varValue = _vm->_scriptParser->getVar(_var7); - - if (_numSubResources == 1 && varValue != 0) - _subResources[0]->handleMouseUp(); - else if (_numSubResources != 0) { - if (varValue < _numSubResources) - _subResources[varValue]->handleMouseUp(); - else - warning("Type 7 Resource Var %d: %d exceeds number of sub resources %d", _var7, varValue, _numSubResources); - } - } +void MystAreaActionSwitch::handleCardChange() { + doSwitch(&MystArea::handleCardChange); } -void MystResourceType7::handleMouseDown() { - if (_var7 == 0xFFFF) { - if (_numSubResources == 1) - _subResources[0]->handleMouseDown(); - else if (_numSubResources != 0) - warning("Type 7 Resource with _numSubResources of %d, but no control variable", _numSubResources); - } else { - uint16 varValue = _vm->_scriptParser->getVar(_var7); - - if (_numSubResources == 1 && varValue != 0) - _subResources[0]->handleMouseDown(); - else if (_numSubResources != 0) { - if (varValue < _numSubResources) - _subResources[varValue]->handleMouseDown(); - else - warning("Type 7 Resource Var %d: %d exceeds number of sub resources %d", _var7, varValue, _numSubResources); - } - } +void MystAreaActionSwitch::handleMouseUp() { + doSwitch(&MystArea::handleMouseUp); } -MystResourceType8::MystResourceType8(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResourceType7(vm, rlstStream, parent) { - _var8 = rlstStream->readUint16LE(); - _numSubImages = rlstStream->readUint16LE(); - debugC(kDebugResource, "\tvar8: %d", _var8); - debugC(kDebugResource, "\tnumSubImages: %d", _numSubImages); +void MystAreaActionSwitch::handleMouseDown() { + doSwitch(&MystArea::handleMouseDown); +} - _subImages = new MystResourceType8::SubImage[_numSubImages]; +MystAreaImageSwitch::MystAreaImageSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystAreaActionSwitch(vm, rlstStream, parent) { + _imageSwitchVar = rlstStream->readUint16LE(); + uint16 numSubImages = rlstStream->readUint16LE(); + debugC(kDebugResource, "\tvar8: %d", _imageSwitchVar); + debugC(kDebugResource, "\tnumSubImages: %d", numSubImages); - for (uint16 i = 0; i < _numSubImages; i++) { + for (uint16 i = 0; i < numSubImages; i++) { debugC(kDebugResource, "\tSubimage %d:", i); - _subImages[i].wdib = rlstStream->readUint16LE(); - _subImages[i].rect.left = rlstStream->readSint16LE(); + SubImage subImage; + subImage.wdib = rlstStream->readUint16LE(); + subImage.rect.left = rlstStream->readSint16LE(); - if (_subImages[i].rect.left != -1) { - _subImages[i].rect.top = rlstStream->readSint16LE(); - _subImages[i].rect.right = rlstStream->readSint16LE(); - _subImages[i].rect.bottom = rlstStream->readSint16LE(); + if (subImage.rect.left != -1) { + subImage.rect.top = rlstStream->readSint16LE(); + subImage.rect.right = rlstStream->readSint16LE(); + subImage.rect.bottom = rlstStream->readSint16LE(); } else { // Use the hotspot rect as the source rect since the subimage is fullscreen // Convert to bitmap coordinates (upside down) - _subImages[i].rect.left = _rect.left; - _subImages[i].rect.top = 333 - _rect.bottom; - _subImages[i].rect.right = _rect.right; - _subImages[i].rect.bottom = 333 - _rect.top; + subImage.rect.left = _rect.left; + subImage.rect.top = 333 - _rect.bottom; + subImage.rect.right = _rect.right; + subImage.rect.bottom = 333 - _rect.top; } - debugC(kDebugResource, "\twdib: %d", _subImages[i].wdib); - debugC(kDebugResource, "\tleft: %d", _subImages[i].rect.left); - debugC(kDebugResource, "\ttop: %d", _subImages[i].rect.top); - debugC(kDebugResource, "\tright: %d", _subImages[i].rect.right); - debugC(kDebugResource, "\tbottom: %d", _subImages[i].rect.bottom); + debugC(kDebugResource, "\twdib: %d", subImage.wdib); + debugC(kDebugResource, "\tleft: %d", subImage.rect.left); + debugC(kDebugResource, "\ttop: %d", subImage.rect.top); + debugC(kDebugResource, "\tright: %d", subImage.rect.right); + debugC(kDebugResource, "\tbottom: %d", subImage.rect.bottom); + + _subImages.push_back(subImage); } } -MystResourceType8::~MystResourceType8() { - delete[] _subImages; +MystAreaImageSwitch::~MystAreaImageSwitch() { } -void MystResourceType8::drawDataToScreen() { - // Need to call overidden Type 7 function to ensure +void MystAreaImageSwitch::drawDataToScreen() { + // Need to call overridden function to ensure // switch section is processed correctly. - MystResourceType7::drawDataToScreen(); + MystAreaActionSwitch::drawDataToScreen(); bool drawSubImage = false; int16 subImageId = 0; - if (_var8 == 0xFFFF) { - if (_numSubImages == 1) { + if (_imageSwitchVar == 0xFFFF) { + if (_subImages.size() == 1) { subImageId = 0; drawSubImage = true; - } else if (_numSubImages != 0) - warning("Type 8 Resource with _numSubImages of %d, but no control variable", _numSubImages); + } else if (_subImages.size() != 0) + warning("Image Switch resource with _numSubImages of %d, but no control variable", _subImages.size()); } else { - uint16 varValue = _vm->_scriptParser->getVar(_var8); + uint16 varValue = _vm->_scriptParser->getVar(_imageSwitchVar); - if (_numSubImages == 1 && varValue != 0) { + if (_subImages.size() == 1 && varValue != 0) { subImageId = 0; drawSubImage = true; - } else if (_numSubImages != 0) { - if (varValue < _numSubImages) { + } else if (_subImages.size() != 0) { + if (varValue < _subImages.size()) { subImageId = varValue; drawSubImage = true; } else - warning("Type 8 Image Var %d: %d exceeds number of subImages %d", _var8, varValue, _numSubImages); + warning("Image Switch Var %d: %d exceeds number of subImages %d", _imageSwitchVar, varValue, _subImages.size()); } } @@ -442,20 +415,21 @@ void MystResourceType8::drawDataToScreen() { } } -void MystResourceType8::drawConditionalDataToScreen(uint16 state, bool update) { +//TODO: Merge with the method above? +void MystAreaImageSwitch::drawConditionalDataToScreen(uint16 state, bool update) { bool drawSubImage = false; int16 subImageId = 0; - if (_numSubImages == 1 && state != 0) { + if (_subImages.size() == 1 && state != 0) { subImageId = 0; drawSubImage = true; - } else if (_numSubImages != 0) { - if (state < _numSubImages) { + } else if (_subImages.size() != 0) { + if (state < _subImages.size()) { subImageId = state; drawSubImage = true; } else - warning("Type 8 Image Var %d: %d exceeds number of subImages %d", _var8, state, _numSubImages); + warning("Image Switch Var %d: %d exceeds number of subImages %d", _imageSwitchVar, state, _subImages.size()); } @@ -476,18 +450,26 @@ void MystResourceType8::drawConditionalDataToScreen(uint16 state, bool update) { } } -uint16 MystResourceType8::getType8Var() { - return _var8; +uint16 MystAreaImageSwitch::getImageSwitchVar() { + return _imageSwitchVar; +} + +MystAreaImageSwitch::SubImage MystAreaImageSwitch::getSubImage(uint index) const { + return _subImages[index]; } -const Common::String MystResourceType8::describe() { +void MystAreaImageSwitch::setSubImageRect(uint index, const Common::Rect &rect) { + _subImages[index].rect = rect; +} + +const Common::String MystAreaImageSwitch::describe() { Common::String desc = Common::String::format("%s var: %2d", - MystResourceType7::describe().c_str(), _var8); + MystAreaActionSwitch::describe().c_str(), _imageSwitchVar); - if (_numSubImages > 0) { + if (_subImages.size() > 0) { desc += " subImgs:"; - for (uint i = 0; i < _numSubImages; i++) + for (uint i = 0; i < _subImages.size(); i++) desc += Common::String::format(" %d", (int16)_subImages[i].wdib); } @@ -496,7 +478,8 @@ const Common::String MystResourceType8::describe() { // No MystResourceType9! -MystResourceType10::MystResourceType10(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResourceType11(vm, rlstStream, parent) { +MystAreaSlider::MystAreaSlider(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystAreaDrag(vm, rlstStream, parent) { _dragSound = rlstStream->readUint16LE(); debugC(kDebugResource, "\tdrag sound : %d", _dragSound); @@ -505,23 +488,23 @@ MystResourceType10::MystResourceType10(MohawkEngine_Myst *vm, Common::SeekableRe _sliderHeight = _rect.bottom - _rect.top; } -MystResourceType10::~MystResourceType10() { +MystAreaSlider::~MystAreaSlider() { } -void MystResourceType10::setStep(uint16 step) { +void MystAreaSlider::setStep(uint16 step) { _rect.top = _minV + _stepV * step - _sliderHeight / 2; _rect.bottom = _rect.top + _sliderHeight; _subImages[0].rect.top = 333 - _rect.bottom - 1; _subImages[0].rect.bottom = 333 - _rect.top - 1; } -void MystResourceType10::setPosition(uint16 pos) { +void MystAreaSlider::setPosition(uint16 pos) { Common::Point mouse; mouse.y = pos; updatePosition(mouse); } -Common::Rect MystResourceType10::boundingBox() { +Common::Rect MystAreaSlider::boundingBox() { Common::Rect bb; bb.top = _rect.top; @@ -544,7 +527,7 @@ Common::Rect MystResourceType10::boundingBox() { return bb; } -void MystResourceType10::restoreBackground() { +void MystAreaSlider::restoreBackground() { // Restore background Common::Rect src = boundingBox(); Common::Rect dest = boundingBox(); @@ -553,14 +536,11 @@ void MystResourceType10::restoreBackground() { _vm->_gfx->copyImageSectionToScreen(_vm->getCardBackgroundId(), src, dest); } -void MystResourceType10::handleMouseDown() { - // Tell the engine we are dragging a resource - _vm->_dragResource = this; - +void MystAreaSlider::handleMouseDown() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); updatePosition(mouse); - MystResourceType11::handleMouseDown(); + MystAreaDrag::handleMouseDown(); // Restore background restoreBackground(); @@ -569,7 +549,7 @@ void MystResourceType10::handleMouseDown() { drawConditionalDataToScreen(2); } -void MystResourceType10::handleMouseUp() { +void MystAreaSlider::handleMouseUp() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); updatePosition(mouse); @@ -593,19 +573,16 @@ void MystResourceType10::handleMouseUp() { value = _pos.x; } - _vm->_scriptParser->setVarValue(_var8, value); - - MystResourceType11::handleMouseUp(); + _vm->_scriptParser->setVarValue(_imageSwitchVar, value); - // No longer in drag mode - _vm->_dragResource = 0; + MystAreaDrag::handleMouseUp(); } -void MystResourceType10::handleMouseDrag() { +void MystAreaSlider::handleMouseDrag() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); updatePosition(mouse); - MystResourceType11::handleMouseDrag(); + MystAreaDrag::handleMouseDrag(); // Restore background restoreBackground(); @@ -614,7 +591,7 @@ void MystResourceType10::handleMouseDrag() { drawConditionalDataToScreen(2); } -void MystResourceType10::updatePosition(const Common::Point &mouse) { +void MystAreaSlider::updatePosition(const Common::Point &mouse) { bool positionChanged = false; Common::Point mouseClipped; @@ -667,7 +644,8 @@ void MystResourceType10::updatePosition(const Common::Point &mouse) { _vm->_sound->replaceSoundMyst(_dragSound); } -MystResourceType11::MystResourceType11(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResourceType8(vm, rlstStream, parent) { +MystAreaDrag::MystAreaDrag(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystAreaImageSwitch(vm, rlstStream, parent) { _flagHV = rlstStream->readUint16LE(); _minH = rlstStream->readUint16LE(); _maxH = rlstStream->readUint16LE(); @@ -694,16 +672,15 @@ MystResourceType11::MystResourceType11(MohawkEngine_Myst *vm, Common::SeekableRe debugCN(kDebugResource, "Type 11 _mouseDragOpcode: %d\n", _mouseDragOpcode); debugCN(kDebugResource, "Type 11 _mouseUpOpcode: %d\n", _mouseUpOpcode); - for (byte i = 0; i < 3; i++) { + for (byte i = 0; i < ARRAYSIZE(_lists); i++) { debugC(kDebugResource, "\tList %d:", i); - _lists[i].listCount = rlstStream->readUint16LE(); - debugC(kDebugResource, "\t%d values", _lists[i].listCount); + uint16 listCount = rlstStream->readUint16LE(); + debugC(kDebugResource, "\t%d values", listCount); - _lists[i].list = new uint16[_lists[i].listCount]; - for (uint16 j = 0; j < _lists[i].listCount; j++) { - _lists[i].list[j] = rlstStream->readUint16LE(); - debugC(kDebugResource, "\tValue %d: %d", j, _lists[i].list[j]); + for (uint16 j = 0; j < listCount; j++) { + _lists[i].push_back(rlstStream->readUint16LE()); + debugC(kDebugResource, "\tValue %d: %d", j, _lists[i][j]); } } @@ -717,44 +694,42 @@ MystResourceType11::MystResourceType11(MohawkEngine_Myst *vm, Common::SeekableRe _stepV = (_maxV - _minV) / (_stepsV - 1); } -MystResourceType11::~MystResourceType11() { - for (byte i = 0; i < 3; i++) - delete[] _lists[i].list; +MystAreaDrag::~MystAreaDrag() { } -void MystResourceType11::handleMouseDown() { +void MystAreaDrag::handleMouseDown() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); setPositionClipping(mouse, _pos); _vm->_scriptParser->setInvokingResource(this); - _vm->_scriptParser->runOpcode(_mouseDownOpcode, _var8); + _vm->_scriptParser->runOpcode(_mouseDownOpcode, _imageSwitchVar); } -void MystResourceType11::handleMouseUp() { +void MystAreaDrag::handleMouseUp() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); setPositionClipping(mouse, _pos); _vm->_scriptParser->setInvokingResource(this); - _vm->_scriptParser->runOpcode(_mouseUpOpcode, _var8); + _vm->_scriptParser->runOpcode(_mouseUpOpcode, _imageSwitchVar); } -void MystResourceType11::handleMouseDrag() { +void MystAreaDrag::handleMouseDrag() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); setPositionClipping(mouse, _pos); _vm->_scriptParser->setInvokingResource(this); - _vm->_scriptParser->runOpcode(_mouseDragOpcode, _var8); + _vm->_scriptParser->runOpcode(_mouseDragOpcode, _imageSwitchVar); } -const Common::String MystResourceType11::describe() { +const Common::String MystAreaDrag::describe() { return Common::String::format("%s down: %s drag: %s up: %s", - MystResourceType8::describe().c_str(), + MystAreaImageSwitch::describe().c_str(), _vm->_scriptParser->getOpcodeDesc(_mouseDownOpcode).c_str(), _vm->_scriptParser->getOpcodeDesc(_mouseDragOpcode).c_str(), _vm->_scriptParser->getOpcodeDesc(_mouseUpOpcode).c_str()); } -void MystResourceType11::setPositionClipping(const Common::Point &mouse, Common::Point &dest) { +void MystAreaDrag::setPositionClipping(const Common::Point &mouse, Common::Point &dest) { if (_flagHV & 2) dest.y = CLIP<uint16>(mouse.y, _minV, _maxV); @@ -762,19 +737,20 @@ void MystResourceType11::setPositionClipping(const Common::Point &mouse, Common: dest.x = CLIP<uint16>(mouse.x, _minH, _maxH); } -uint16 MystResourceType11::getList1(uint16 index) { - return (index < _lists[0].listCount) ? _lists[0].list[index] : 0; +uint16 MystAreaDrag::getList1(uint16 index) { + return (index < _lists[0].size()) ? _lists[0][index] : 0; } -uint16 MystResourceType11::getList2(uint16 index) { - return (index < _lists[1].listCount) ? _lists[1].list[index] : 0; +uint16 MystAreaDrag::getList2(uint16 index) { + return (index < _lists[1].size()) ? _lists[1][index] : 0; } -uint16 MystResourceType11::getList3(uint16 index) { - return (index < _lists[2].listCount) ? _lists[2].list[index] : 0; +uint16 MystAreaDrag::getList3(uint16 index) { + return (index < _lists[2].size()) ? _lists[2][index] : 0; } -MystResourceType12::MystResourceType12(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResourceType11(vm, rlstStream, parent) { +MystVideoInfo::MystVideoInfo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystAreaDrag(vm, rlstStream, parent) { _numFrames = rlstStream->readUint16LE(); _firstFrame = rlstStream->readUint16LE(); uint16 frameWidth = rlstStream->readUint16LE(); @@ -795,16 +771,16 @@ MystResourceType12::MystResourceType12(MohawkEngine_Myst *vm, Common::SeekableRe debugC(kDebugResource, "\t_frameRect.bottom: %d", _frameRect.bottom); } -MystResourceType12::~MystResourceType12() { +MystVideoInfo::~MystVideoInfo() { } -void MystResourceType12::drawFrame(uint16 frame) { +void MystVideoInfo::drawFrame(uint16 frame) { _currentFrame = _firstFrame + frame; _vm->_gfx->copyImageToScreen(_currentFrame, _frameRect); _vm->_system->updateScreen(); } -bool MystResourceType12::pullLeverV() { +bool MystVideoInfo::pullLeverV() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); // Make the handle follow the mouse @@ -820,7 +796,7 @@ bool MystResourceType12::pullLeverV() { return step == maxStep; } -void MystResourceType12::releaseLeverV() { +void MystVideoInfo::releaseLeverV() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); // Get current lever frame @@ -836,7 +812,8 @@ void MystResourceType12::releaseLeverV() { } } -MystResourceType13::MystResourceType13(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResource(vm, rlstStream, parent) { +MystAreaHover::MystAreaHover(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystArea(vm, rlstStream, parent) { _enterOpcode = rlstStream->readUint16LE(); _leaveOpcode = rlstStream->readUint16LE(); @@ -844,27 +821,27 @@ MystResourceType13::MystResourceType13(MohawkEngine_Myst *vm, Common::SeekableRe debugC(kDebugResource, "\t_leaveOpcode: %d", _leaveOpcode); } -void MystResourceType13::handleMouseEnter() { +void MystAreaHover::handleMouseEnter() { // Pass along the enter opcode to the script parser // The variable to use is stored in the dest field _vm->_scriptParser->runOpcode(_enterOpcode, _dest); } -void MystResourceType13::handleMouseLeave() { +void MystAreaHover::handleMouseLeave() { // Pass along the leave opcode (with no parameters) to the script parser // The variable to use is stored in the dest field _vm->_scriptParser->runOpcode(_leaveOpcode, _dest); } -void MystResourceType13::handleMouseUp() { +void MystAreaHover::handleMouseUp() { // Type 13 Resources do nothing on Mouse Clicks. // This is required to override the inherited default - // i.e. MystResource::handleMouseUp + // i.e. MystArea::handleMouseUp } -const Common::String MystResourceType13::describe() { +const Common::String MystAreaHover::describe() { return Common::String::format("%s enter: %s leave: %s", - MystResource::describe().c_str(), + MystArea::describe().c_str(), _vm->_scriptParser->getOpcodeDesc(_enterOpcode).c_str(), _vm->_scriptParser->getOpcodeDesc(_leaveOpcode).c_str()); } diff --git a/engines/mohawk/myst_areas.h b/engines/mohawk/myst_areas.h index 97ec882497..b19a2df9e2 100644 --- a/engines/mohawk/myst_areas.h +++ b/engines/mohawk/myst_areas.h @@ -32,19 +32,19 @@ namespace Mohawk { // Myst Resource Types enum ResourceType { - kMystForwardArea = 0, - kMystLeftArea = 1, - kMystRightArea = 2, - kMystDownArea = 3, - kMystUpArea = 4, - kMystAction = 5, - kMystVideo = 6, - kMystSwitch = 7, - kMystConditionalImage = 8, - kMystSlider = 10, - kMystDragArea = 11, + kMystAreaForward = 0, + kMystAreaLeft = 1, + kMystAreaRight = 2, + kMystAreaDown = 3, + kMystAreaUp = 4, + kMystAreaAction = 5, + kMystAreaVideo = 6, + kMystAreaActionSwitch = 7, + kMystAreaImageSwitch = 8, + kMystAreaSlider = 10, + kMystAreaDrag = 11, kMystVideoInfo = 12, - kMystHoverArea = 13 + kMystAreaHover = 13 }; // Myst Resource Flags @@ -56,16 +56,14 @@ enum { kMystZipModeEnableFlag = (1 << 3) }; -class MystResource { +class MystArea { public: - MystResource(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - virtual ~MystResource(); + MystArea(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + virtual ~MystArea(); + virtual const Common::String describe(); void drawBoundingRect(); - MystResource *_parent; - ResourceType type; - bool contains(Common::Point point) { return _rect.contains(point); } virtual void drawDataToScreen() {} virtual void handleCardChange() {} @@ -75,7 +73,7 @@ public: void setEnabled(bool enabled); bool isDrawSubimages() { return _flags & kMystSubimageEnableFlag; } uint16 getDest() { return _dest; } - virtual uint16 getType8Var() { return 0xFFFF; } + virtual uint16 getImageSwitchVar() { return 0xFFFF; } bool unreachableZipDest(); bool canBecomeActive(); @@ -84,6 +82,8 @@ public: virtual void handleMouseDown() {} virtual void handleMouseDrag() {} + MystArea *_parent; + ResourceType type; protected: MohawkEngine_Myst *_vm; @@ -92,21 +92,25 @@ protected: uint16 _dest; }; -class MystResourceType5 : public MystResource { +class MystAreaAction : public MystArea { public: - MystResourceType5(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - void handleMouseUp(); - const Common::String describe(); + MystAreaAction(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + + void handleMouseUp() override; + const Common::String describe() override; protected: MystScript _script; }; -class MystResourceType6 : public MystResourceType5 { +class MystAreaVideo : public MystAreaAction { public: - MystResourceType6(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); + MystAreaVideo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + VideoHandle playMovie(); - void handleCardChange(); + VideoHandle getMovieHandle(); + + void handleCardChange() override; bool isPlaying(); void setDirection(int16 direction) { _direction = direction; } void setBlocking(bool blocking) { _playBlocking = blocking; } @@ -114,6 +118,7 @@ public: protected: static Common::String convertMystVideoName(Common::String name); + Common::String _videoFile; int16 _left; int16 _top; @@ -121,58 +126,63 @@ protected: int16 _direction; // 1 => forward, -1 => backwards uint16 _playBlocking; uint16 _playOnCardChange; - uint16 _u3; + uint16 _playRate; // percents }; -class MystResourceType7 : public MystResource { +class MystAreaActionSwitch : public MystArea { public: - MystResourceType7(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - virtual ~MystResourceType7(); + MystAreaActionSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + virtual ~MystAreaActionSwitch(); - virtual void drawDataToScreen(); - virtual void handleCardChange(); + virtual void drawDataToScreen() override; + virtual void handleCardChange() override; - virtual void handleMouseUp(); - virtual void handleMouseDown(); + virtual void handleMouseUp() override; + virtual void handleMouseDown() override; - MystResource *getSubResource(uint16 index) { return _subResources[index]; } + MystArea *getSubResource(uint16 index) { return _subResources[index]; } protected: - uint16 _var7; - uint16 _numSubResources; - Common::Array<MystResource *> _subResources; + typedef void (MystArea::*AreaHandler)(); + + void doSwitch(AreaHandler handler); + + uint16 _actionSwitchVar; + Common::Array<MystArea *> _subResources; }; -class MystResourceType8 : public MystResourceType7 { +class MystAreaImageSwitch : public MystAreaActionSwitch { public: - MystResourceType8(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - virtual ~MystResourceType8(); - virtual const Common::String describe(); - - virtual void drawDataToScreen(); - void drawConditionalDataToScreen(uint16 state, bool update = true); - uint16 getType8Var(); + MystAreaImageSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + virtual ~MystAreaImageSwitch(); struct SubImage { uint16 wdib; Common::Rect rect; - } *_subImages; + }; + + virtual const Common::String describe() override; + virtual void drawDataToScreen() override; + void drawConditionalDataToScreen(uint16 state, bool update = true); + uint16 getImageSwitchVar() override; + + SubImage getSubImage(uint index) const; + void setSubImageRect(uint index, const Common::Rect &rect); protected: - uint16 _var8; - uint16 _numSubImages; + uint16 _imageSwitchVar; + Common::Array<SubImage> _subImages; }; -// No MystResourceType9! - -class MystResourceType11 : public MystResourceType8 { +class MystAreaDrag : public MystAreaImageSwitch { public: - MystResourceType11(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - virtual ~MystResourceType11(); - const Common::String describe(); + MystAreaDrag(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + virtual ~MystAreaDrag(); - void handleMouseDown(); - void handleMouseUp(); - void handleMouseDrag(); + const Common::String describe() override; + + virtual void handleMouseDown() override; + virtual void handleMouseUp() override; + virtual void handleMouseDrag() override; uint16 getList1(uint16 index); uint16 getList2(uint16 index); @@ -183,6 +193,8 @@ public: Common::Point _pos; protected: + typedef Common::Array<uint16> ValueList; + void setPositionClipping(const Common::Point &mouse, Common::Point &dest); uint16 _flagHV; @@ -197,21 +209,17 @@ protected: uint16 _mouseDownOpcode; uint16 _mouseDragOpcode; uint16 _mouseUpOpcode; - struct { - uint16 listCount; - uint16 *list; - } _lists[3]; - + ValueList _lists[3]; }; -class MystResourceType10 : public MystResourceType11 { +class MystAreaSlider : public MystAreaDrag { public: - MystResourceType10(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - virtual ~MystResourceType10(); + MystAreaSlider(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + virtual ~MystAreaSlider(); - void handleMouseDown(); - void handleMouseUp(); - void handleMouseDrag(); + void handleMouseDown() override; + void handleMouseUp() override; + void handleMouseDrag() override; void setStep(uint16 step); void setPosition(uint16 pos); void restoreBackground(); @@ -225,10 +233,11 @@ protected: uint16 _sliderHeight; }; -class MystResourceType12 : public MystResourceType11 { +class MystVideoInfo : public MystAreaDrag { public: - MystResourceType12(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - virtual ~MystResourceType12(); + MystVideoInfo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + virtual ~MystVideoInfo(); + void drawFrame(uint16 frame); bool pullLeverV(); void releaseLeverV(); @@ -243,12 +252,13 @@ private: uint16 _currentFrame; }; -class MystResourceType13 : public MystResource { +class MystAreaHover : public MystArea { public: - MystResourceType13(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - const Common::String describe(); + MystAreaHover(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + + const Common::String describe() override; - void handleMouseUp(); + void handleMouseUp() override; void handleMouseEnter(); void handleMouseLeave(); diff --git a/engines/mohawk/myst_graphics.cpp b/engines/mohawk/myst_graphics.cpp index 49f97cca63..5db9697a78 100644 --- a/engines/mohawk/myst_graphics.cpp +++ b/engines/mohawk/myst_graphics.cpp @@ -40,7 +40,7 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) { if (_vm->getFeatures() & GF_ME) { // High color - initGraphics(_viewport.width(), _viewport.height(), true, NULL); + initGraphics(_viewport.width(), _viewport.height(), true, nullptr); if (_vm->_system->getScreenFormat().bytesPerPixel == 1) error("Myst ME requires greater than 256 colors to run"); @@ -73,7 +73,7 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) { // if it's a PICT or WDIB resource. If it's Myst ME it's most likely a PICT, and if it's // original it's definitely a WDIB. However, Myst ME throws us another curve ball in // that PICT resources can contain WDIB's instead of PICT's. - Common::SeekableReadStream *dataStream = NULL; + Common::SeekableReadStream *dataStream = nullptr; if (_vm->getFeatures() & GF_ME && _vm->hasResource(ID_PICT, id)) { // The PICT resource exists. However, it could still contain a MystBitmap @@ -95,7 +95,7 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) { dataStream->seek(0); } - MohawkSurface *mhkSurface = 0; + MohawkSurface *mhkSurface = nullptr; if (isPict) { Image::PICTDecoder pict; @@ -103,6 +103,8 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) { if (!pict.loadStream(*dataStream)) error("Could not decode Myst ME PICT"); + delete dataStream; + mhkSurface = new MohawkSurface(pict.getSurface()->convertTo(_pixelFormat)); } else { mhkSurface = _bmpDecoder->decodeImage(dataStream); @@ -225,9 +227,8 @@ void MystGraphics::copyBackBufferToScreen(Common::Rect r) { void MystGraphics::runTransition(TransitionType type, Common::Rect rect, uint16 steps, uint16 delay) { - // Do not artificially delay during transitions - int oldEnableDrawingTimeSimulation = _enableDrawingTimeSimulation; - _enableDrawingTimeSimulation = 0; + // Transitions are barely visible without adding delays between the draw calls + enableDrawingTimeSimulation(true); switch (type) { case kTransitionLeftToRight: { @@ -288,7 +289,10 @@ void MystGraphics::runTransition(TransitionType type, Common::Rect rect, uint16 debugC(kDebugView, "Dissolve"); for (int16 step = 0; step < 8; step++) { - simulatePreviousDrawDelay(rect); + // Only one eighth of the rect pixels are updated by a draw step, + // delay by one eighth of the regular time + simulatePreviousDrawDelay(Common::Rect(rect.width() / 8, rect.height())); + transitionDissolve(rect, step); } } @@ -367,7 +371,7 @@ void MystGraphics::runTransition(TransitionType type, Common::Rect rect, uint16 error("Unknown transition %d", type); } - _enableDrawingTimeSimulation = oldEnableDrawingTimeSimulation; + enableDrawingTimeSimulation(false); } void MystGraphics::transitionDissolve(Common::Rect rect, uint step) { @@ -639,8 +643,10 @@ void MystGraphics::simulatePreviousDrawDelay(const Common::Rect &dest) { // Do not draw anything new too quickly after the previous draw call // so that images stay at least a little while on screen // This is enabled only for scripted draw calls - if (time < _nextAllowedDrawTime) + if (time < _nextAllowedDrawTime) { + debugC(kDebugView, "Delaying draw call by %d ms", _nextAllowedDrawTime - time); _vm->_system->delayMillis(_nextAllowedDrawTime - time); + } } // Next draw call allowed at DELAY + AERA * COEFF milliseconds from now diff --git a/engines/mohawk/myst_graphics.h b/engines/mohawk/myst_graphics.h index 6281c94cc8..93e388cb83 100644 --- a/engines/mohawk/myst_graphics.h +++ b/engines/mohawk/myst_graphics.h @@ -61,8 +61,8 @@ public: const byte *getPalette() const { return _palette; } protected: - MohawkSurface *decodeImage(uint16 id); - MohawkEngine *getVM() { return (MohawkEngine *)_vm; } + MohawkSurface *decodeImage(uint16 id) override; + MohawkEngine *getVM() override { return (MohawkEngine *)_vm; } private: MohawkEngine_Myst *_vm; diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp index 487d0f45fe..04e7c5a9b7 100644 --- a/engines/mohawk/myst_scripts.cpp +++ b/engines/mohawk/myst_scripts.cpp @@ -29,6 +29,7 @@ #include "mohawk/video.h" #include "common/system.h" +#include "common/memstream.h" #include "common/textconsole.h" #include "gui/message.h" @@ -38,7 +39,7 @@ MystScriptEntry::MystScriptEntry() { type = kMystScriptNone; var = 0; argc = 0; - argv = 0; + argv = nullptr; resourceId = 0; u1 = 0; } @@ -81,7 +82,7 @@ MystScriptParser::MystScriptParser(MohawkEngine_Myst *vm) : _vm(vm), _globals(vm->_gameState->_globals) { setupCommonOpcodes(); - _invokingResource = NULL; + _invokingResource = nullptr; _savedCardId = 0; _savedCursorId = 0; _tempVar = 0; @@ -154,7 +155,7 @@ void MystScriptParser::setupCommonOpcodes() { #undef OPCODE -void MystScriptParser::runScript(MystScript script, MystResource *invokingResource) { +void MystScriptParser::runScript(MystScript script, MystArea *invokingResource) { debugC(kDebugScript, "Script Size: %d", script->size()); // Scripted drawing takes more time to simulate older hardware @@ -260,15 +261,6 @@ bool MystScriptParser::setVarValue(uint16 var, uint16 value) { return false; } -// NOTE: Check to be used on Opcodes where var is thought -// not to be used. This emits a warning if var is nonzero. -// It is possible that the opcode does use var 0 in this case, -// but this will catch the majority of missed cases. -void MystScriptParser::varUnusedCheck(uint16 op, uint16 var) { - if (var != 0) - warning("Opcode %d: Unused Var %d", op, var); -} - void MystScriptParser::animatedUpdate(uint16 argc, uint16 *argv, uint16 delay) { uint16 argsRead = 0; @@ -331,7 +323,7 @@ void MystScriptParser::o_changeCardSwitch4(uint16 op, uint16 var, uint16 argc, u if (value) _vm->changeToCard(argv[value -1 ], kTransitionDissolve); - else if (_invokingResource != NULL) + else if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionDissolve); else warning("Missing invokingResource in altDest call"); @@ -344,7 +336,7 @@ void MystScriptParser::o_changeCardSwitchLtR(uint16 op, uint16 var, uint16 argc, if (value) _vm->changeToCard(argv[value -1 ], kTransitionLeftToRight); - else if (_invokingResource != NULL) + else if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionLeftToRight); else warning("Missing invokingResource in altDest call"); @@ -357,7 +349,7 @@ void MystScriptParser::o_changeCardSwitchRtL(uint16 op, uint16 var, uint16 argc, if (value) _vm->changeToCard(argv[value -1 ], kTransitionRightToLeft); - else if (_invokingResource != NULL) + else if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionRightToLeft); else warning("Missing invokingResource in altDest call"); @@ -398,7 +390,7 @@ void MystScriptParser::o_redrawCard(uint16 op, uint16 var, uint16 argc, uint16 * void MystScriptParser::o_goToDest(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Change To Dest of Invoking Resource", op); - if (_invokingResource != NULL) + if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionCopy); else warning("Opcode %d: Missing invokingResource", op); @@ -407,7 +399,7 @@ void MystScriptParser::o_goToDest(uint16 op, uint16 var, uint16 argc, uint16 *ar void MystScriptParser::o_goToDestForward(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Change To Dest of Invoking Resource", op); - if (_invokingResource != NULL) + if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionDissolve); else warning("Opcode %d: Missing invokingResource", op); @@ -416,7 +408,7 @@ void MystScriptParser::o_goToDestForward(uint16 op, uint16 var, uint16 argc, uin void MystScriptParser::o_goToDestLeft(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Change To Dest of Invoking Resource", op); - if (_invokingResource != NULL) + if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionPartToRight); else warning("Opcode %d: Missing invokingResource", op); @@ -425,7 +417,7 @@ void MystScriptParser::o_goToDestLeft(uint16 op, uint16 var, uint16 argc, uint16 void MystScriptParser::o_goToDestRight(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Change To Dest of Invoking Resource", op); - if (_invokingResource != NULL) + if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionPartToLeft); else warning("Opcode %d: Missing invokingResource", op); @@ -434,7 +426,7 @@ void MystScriptParser::o_goToDestRight(uint16 op, uint16 var, uint16 argc, uint1 void MystScriptParser::o_goToDestUp(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Change To Dest of Invoking Resource", op); - if (_invokingResource != NULL) + if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionTopToBottom); else warning("Opcode %d: Missing invokingResource", op); @@ -442,7 +434,10 @@ void MystScriptParser::o_goToDestUp(uint16 op, uint16 var, uint16 argc, uint16 * void MystScriptParser::o_triggerMovie(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Trigger Type 6 Resource Movie..", op); - // TODO: If movie has sound, pause background music + // The original has code to pause the background music before playing the movie, + // if the movie has a sound track, as well as code to resume it afterwards. But since + // the movie has not yet been loaded at this point, it is impossible to know + // if the movie actually has a sound track. The code is never executed. int16 direction = 1; if (argc == 1) @@ -451,11 +446,9 @@ void MystScriptParser::o_triggerMovie(uint16 op, uint16 var, uint16 argc, uint16 debugC(kDebugScript, "\tDirection: %d", direction); // Trigger resource 6 movie overriding play direction - MystResourceType6 *resource = static_cast<MystResourceType6 *>(_invokingResource); + MystAreaVideo *resource = getInvokingResource<MystAreaVideo>(); resource->setDirection(direction); resource->playMovie(); - - // TODO: If movie has sound, resume background music } void MystScriptParser::o_toggleVarNoRedraw(uint16 op, uint16 var, uint16 argc, uint16 *argv) { @@ -468,7 +461,7 @@ void MystScriptParser::o_drawAreaState(uint16 op, uint16 var, uint16 argc, uint1 debugC(kDebugScript, "Opcode %d: drawAreaState, state: %d", op, argv[0]); debugC(kDebugScript, "\tVar: %d", var); - MystResourceType8 *parent = static_cast<MystResourceType8 *>(_invokingResource->_parent); + MystAreaImageSwitch *parent = static_cast<MystAreaImageSwitch *>(getInvokingResource<MystArea>()->_parent); parent->drawConditionalDataToScreen(argv[0]); } @@ -517,6 +510,11 @@ void MystScriptParser::o_changeCardPop(uint16 op, uint16 var, uint16 argc, uint1 debugC(kDebugScript, "Opcode %d: Return To Stored Card Id", op); debugC(kDebugScript, "\tCardId: %d", _savedCardId); + if (_savedCardId == 0) { + warning("No pushed card to go back to"); + return; + } + TransitionType transition = static_cast<TransitionType>(argv[0]); _vm->changeToCard(_savedCardId, transition); @@ -531,7 +529,7 @@ void MystScriptParser::o_enableAreas(uint16 op, uint16 var, uint16 argc, uint16 for (uint16 i = 0; i < count; i++) { debugC(kDebugScript, "Enable hotspot index %d", argv[i + 1]); - MystResource *resource = 0; + MystArea *resource = nullptr; if (argv[i + 1] == 0xFFFF) resource = _invokingResource; else @@ -556,7 +554,7 @@ void MystScriptParser::o_disableAreas(uint16 op, uint16 var, uint16 argc, uint16 for (uint16 i = 0; i < count; i++) { debugC(kDebugScript, "Disable hotspot index %d", argv[i + 1]); - MystResource *resource = 0; + MystArea *resource = nullptr; if (argv[i + 1] == 0xFFFF) resource = _invokingResource; else @@ -587,7 +585,7 @@ void MystScriptParser::o_toggleAreasActivation(uint16 op, uint16 var, uint16 arg for (uint16 i = 0; i < count; i++) { debugC(kDebugScript, "Enable/Disable hotspot index %d", argv[i + 1]); - MystResource *resource = 0; + MystArea *resource = nullptr; if (argv[i + 1] == 0xFFFF) resource = _invokingResource; else @@ -682,82 +680,15 @@ void MystScriptParser::o_copyImageToBackBuffer(uint16 op, uint16 var, uint16 arg _vm->_gfx->copyImageSectionToBackBuffer(imageId, srcRect, dstRect); } -// TODO: Implement common engine function for read and processing of sound blocks -// for use by this opcode and VIEW sound block. -// TODO: Though the playSound and PlaySoundBlocking opcodes play sounds immediately, -// this opcode changes the main background sound playing.. -// Current behavior here and with VIEW sound block is not right as demonstrated -// by Channelwood Card 3280 (Tank Valve) and water flow sound behavior in pipe -// on cards leading from shed... void MystScriptParser::o_changeBackgroundSound(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - int16 *soundList = NULL; - uint16 *soundListVolume = NULL; - // Used on Stoneship Card 2080 // Used on Channelwood Card 3225 with argc = 8 i.e. Conditional Sound List - if (argc == 1 || argc == 2 || argc == 8) { - debugC(kDebugScript, "Opcode %d: Process Sound Block", op); - uint16 decodeIdx = 0; - - int16 soundAction = argv[decodeIdx++]; - uint16 soundVolume = 65535; - if (soundAction == kMystSoundActionChangeVolume || soundAction > 0) { - soundVolume = argv[decodeIdx++]; - } else if (soundAction == kMystSoundActionConditional) { - debugC(kDebugScript, "Conditional sound list"); - uint16 condVar = argv[decodeIdx++]; - uint16 condVarValue = getVar(condVar); - uint16 condCount = argv[decodeIdx++]; - - debugC(kDebugScript, "\tcondVar: %d = %d", condVar, condVarValue); - debugC(kDebugScript, "\tcondCount: %d", condCount); - - soundList = new int16[condCount]; - soundListVolume = new uint16[condCount]; - - if (condVarValue >= condCount) - warning("Opcode %d: Conditional sound variable outside range", op); - else { - for (uint16 i = 0; i < condCount; i++) { - soundList[i] = argv[decodeIdx++]; - debugC(kDebugScript, "\t\tCondition %d: Action %d", i, soundList[i]); - if (soundList[i] == kMystSoundActionChangeVolume || soundList[i] > 0) { - soundListVolume[i] = argv[decodeIdx++]; - } else - soundListVolume[i] = 65535; - debugC(kDebugScript, "\t\tCondition %d: Volume %d", i, soundListVolume[i]); - } - - soundAction = soundList[condVarValue]; - soundVolume = soundListVolume[condVarValue]; - } - } + debugC(kDebugScript, "Opcode %d: Process Sound Block", op); - if (soundAction == kMystSoundActionContinue) - debugC(kDebugScript, "Continue current sound"); - else if (soundAction == kMystSoundActionChangeVolume) { - debugC(kDebugScript, "Continue current sound, change volume"); - debugC(kDebugScript, "\tVolume: %d", soundVolume); - _vm->_sound->changeBackgroundVolumeMyst(soundVolume); - } else if (soundAction == kMystSoundActionStop) { - debugC(kDebugScript, "Stop sound"); - _vm->_sound->stopBackgroundMyst(); - } else if (soundAction > 0) { - debugC(kDebugScript, "Play new Sound, change volume"); - debugC(kDebugScript, "\tSound: %d", soundAction); - debugC(kDebugScript, "\tVolume: %d", soundVolume); - _vm->_sound->replaceBackgroundMyst(soundAction, soundVolume); - } else { - debugC(kDebugScript, "Unknown"); - warning("Unknown sound control value in opcode %d", op); - } - } else - warning("Unknown arg count in opcode %d", op); + Common::MemoryReadStream stream = Common::MemoryReadStream((const byte *) argv, argc * sizeof(uint16)); - delete[] soundList; - soundList = NULL; - delete[] soundListVolume; - soundListVolume = NULL; + MystSoundBlock soundBlock = _vm->readSoundBlock(&stream); + _vm->applySoundBlock(soundBlock); } void MystScriptParser::o_soundPlaySwitch(uint16 op, uint16 var, uint16 argc, uint16 *argv) { diff --git a/engines/mohawk/myst_scripts.h b/engines/mohawk/myst_scripts.h index 7d8165c762..69052b10f5 100644 --- a/engines/mohawk/myst_scripts.h +++ b/engines/mohawk/myst_scripts.h @@ -34,7 +34,7 @@ namespace Mohawk { #define DECLARE_OPCODE(x) void x(uint16 op, uint16 var, uint16 argc, uint16 *argv) class MohawkEngine_Myst; -class MystResource; +class MystArea; enum MystScriptType { kMystScriptNone, @@ -63,11 +63,11 @@ public: MystScriptParser(MohawkEngine_Myst *vm); virtual ~MystScriptParser(); - void runScript(MystScript script, MystResource *invokingResource = NULL); - void runOpcode(uint16 op, uint16 var = 0, uint16 argc = 0, uint16 *argv = NULL); + void runScript(MystScript script, MystArea *invokingResource = nullptr); + void runOpcode(uint16 op, uint16 var = 0, uint16 argc = 0, uint16 *argv = nullptr); const Common::String getOpcodeDesc(uint16 op); MystScript readScript(Common::SeekableReadStream *stream, MystScriptType type); - void setInvokingResource(MystResource *resource) { _invokingResource = resource; } + void setInvokingResource(MystArea *resource) { _invokingResource = resource; } virtual void disablePersistentScripts() = 0; virtual void runPersistentScripts() = 0; @@ -151,8 +151,6 @@ protected: Common::Array<MystOpcode *> _opcodes; - MystResource *_invokingResource; - uint16 _savedCardId; uint16 _savedMapCardId; uint16 _savedCursorId; @@ -163,9 +161,25 @@ protected: static const uint16 _startCard[]; void setupCommonOpcodes(); - void varUnusedCheck(uint16 op, uint16 var); + + template<class T> + T *getInvokingResource() const; + +private: + MystArea *_invokingResource; }; +template<class T> +T *MystScriptParser::getInvokingResource() const { + T *resource = dynamic_cast<T *>(_invokingResource); + + if (!resource) { + error("Invoking resource has unexpected type"); + } + + return resource; +} + } // End of namespace Mohawk #undef DECLARE_OPCODE diff --git a/engines/mohawk/myst_stacks/channelwood.cpp b/engines/mohawk/myst_stacks/channelwood.cpp index 0718f8e683..21c3042359 100644 --- a/engines/mohawk/myst_stacks/channelwood.cpp +++ b/engines/mohawk/myst_stacks/channelwood.cpp @@ -363,7 +363,7 @@ void Channelwood::o_drawImageChangeCardAndVolume(uint16 op, uint16 var, uint16 a void Channelwood::o_waterTankValveOpen(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Do Water Tank Valve Open Animation", op); - Common::Rect rect = _invokingResource->getRect(); + Common::Rect rect = getInvokingResource<MystArea>()->getRect(); for (uint i = 0; i < 2; i++) for (uint16 imageId = 3601; imageId >= 3595; imageId--) { @@ -377,7 +377,7 @@ void Channelwood::o_waterTankValveOpen(uint16 op, uint16 var, uint16 argc, uint1 void Channelwood::o_leverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Generic lever start move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(0); _vm->_cursor->setCursor(700); _leverPulled = false; @@ -386,7 +386,7 @@ void Channelwood::o_leverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *a void Channelwood::o_leverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Generic lever move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); if (lever->pullLeverV()) { if (!_leverPulled) { @@ -401,7 +401,7 @@ void Channelwood::o_leverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) void Channelwood::o_leverMoveFail(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Generic lever move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); if (lever->pullLeverV()) { if (!_leverPulled) { @@ -419,7 +419,7 @@ void Channelwood::o_leverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *arg debugC(kDebugScript, "Opcode %d: Generic lever end move", op); // Get current lever frame - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Release lever lever->releaseLeverV(); @@ -439,7 +439,7 @@ void Channelwood::o_leverEndMoveResumeBackground(uint16 op, uint16 var, uint16 a void Channelwood::o_leverEndMoveWithSound(uint16 op, uint16 var, uint16 argc, uint16 *argv) { o_leverEndMove(op, var, argc, argv); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); uint16 soundId = lever->getList3(0); if (soundId) _vm->_sound->replaceSoundMyst(soundId); @@ -461,7 +461,7 @@ void Channelwood::o_leverElev3EndMove(uint16 op, uint16 var, uint16 argc, uint16 void Channelwood::o_pumpLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Pump lever move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); if (lever->pullLeverV()) { uint16 soundId = lever->getList2(0); @@ -475,7 +475,7 @@ void Channelwood::o_pumpLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *ar void Channelwood::o_pumpLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { o_leverEndMove(op, var, argc, argv); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); uint16 soundId = lever->getList3(0); if (soundId) _vm->_sound->replaceBackgroundMyst(soundId, 36864); @@ -484,7 +484,7 @@ void Channelwood::o_pumpLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 void Channelwood::o_stairsDoorToggle(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Play stairs door video", op); - MystResourceType6 *movie = static_cast<MystResourceType6 *>(_invokingResource); + MystAreaVideo *movie = getInvokingResource<MystAreaVideo>(); if (_state.stairsUpperDoorState) { // Close door, play the open movie backwards @@ -500,7 +500,7 @@ void Channelwood::o_stairsDoorToggle(uint16 op, uint16 var, uint16 argc, uint16 void Channelwood::o_valveHandleMove1(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Valve handle move", op); - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); if (handle->getRect().contains(mouse)) { @@ -516,7 +516,7 @@ void Channelwood::o_valveHandleMove1(uint16 op, uint16 var, uint16 argc, uint16 void Channelwood::o_valveHandleMoveStart1(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Valve handle move start", op); - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); uint16 soundId = handle->getList1(0); if (soundId) _vm->_sound->replaceSoundMyst(soundId); @@ -528,7 +528,7 @@ void Channelwood::o_valveHandleMoveStart1(uint16 op, uint16 var, uint16 argc, ui void Channelwood::o_valveHandleMoveStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Valve handle move stop", op); - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); // Update state with valve position if (_tempVar <= 5) @@ -551,7 +551,7 @@ void Channelwood::o_valveHandleMoveStop(uint16 op, uint16 var, uint16 argc, uint void Channelwood::o_valveHandleMove2(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Valve handle move", op); - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); if (handle->getRect().contains(mouse)) { @@ -567,7 +567,7 @@ void Channelwood::o_valveHandleMove2(uint16 op, uint16 var, uint16 argc, uint16 void Channelwood::o_valveHandleMoveStart2(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Valve handle move start", op); - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); uint16 soundId = handle->getList1(0); if (soundId) _vm->_sound->replaceSoundMyst(soundId); @@ -579,7 +579,7 @@ void Channelwood::o_valveHandleMoveStart2(uint16 op, uint16 var, uint16 argc, ui void Channelwood::o_valveHandleMove3(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Valve handle move", op); - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); if (handle->getRect().contains(mouse)) { @@ -595,7 +595,7 @@ void Channelwood::o_valveHandleMove3(uint16 op, uint16 var, uint16 argc, uint16 void Channelwood::o_valveHandleMoveStart3(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Valve handle move start", op); - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); uint16 soundId = handle->getList1(0); if (soundId) _vm->_sound->replaceSoundMyst(soundId); @@ -621,24 +621,32 @@ void Channelwood::o_hologramMonitor(uint16 op, uint16 var, uint16 argc, uint16 * switch (button) { case 0: handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monalgh", kChannelwoodStack)); + if (!handle) + error("Failed to open monalgh movie"); + handle->moveTo(227, 70); break; case 1: handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monamth", kChannelwoodStack)); + if (!handle) + error("Failed to open monamth movie"); + handle->moveTo(227, 70); break; case 2: handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monasirs", kChannelwoodStack)); + if (!handle) + error("Failed to open monasirs movie"); + handle->moveTo(227, 70); break; case 3: handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monsmsg", kChannelwoodStack)); + if (!handle) + error("Failed to open monsmsg movie"); + handle->moveTo(226, 68); break; default: warning("Opcode %d Control Variable Out of Range", op); break; } - - // Move the video to the right location - if (handle) - handle->moveTo(227, 70); } } @@ -680,13 +688,13 @@ void Channelwood::o_hologramTemple(uint16 op, uint16 var, uint16 argc, uint16 *a void Channelwood::o_executeMouseUp(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Execute mouse up", op); - MystResourceType5 *resource = static_cast<MystResourceType5 *>(_vm->_resources[argv[0]]); + MystArea *resource = _vm->getViewResource<MystArea>(argv[0]); resource->handleMouseUp(); } void Channelwood::o_waterTankValveClose(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Do Water Tank Valve Close Animation", op); - Common::Rect rect = _invokingResource->getRect(); + Common::Rect rect = getInvokingResource<MystArea>()->getRect(); for (uint i = 0; i < 2; i++) for (uint16 imageId = 3595; imageId <= 3601; imageId++) { @@ -747,13 +755,14 @@ void Channelwood::o_soundReplace(uint16 op, uint16 var, uint16 argc, uint16 *arg uint16 soundId = argv[0]; - // TODO: If is foreground playing - _vm->_sound->replaceSoundMyst(soundId); + if (!_vm->_sound->isPlaying()) { + _vm->_sound->replaceSoundMyst(soundId); + } } void Channelwood::o_lever_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Generic lever init", op); - _leverAction = static_cast<MystResourceType5 *>(_invokingResource); + _leverAction = getInvokingResource<MystArea>(); } void Channelwood::o_pipeValve_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { diff --git a/engines/mohawk/myst_stacks/channelwood.h b/engines/mohawk/myst_stacks/channelwood.h index bd5d7ffe94..ac875e52d8 100644 --- a/engines/mohawk/myst_stacks/channelwood.h +++ b/engines/mohawk/myst_stacks/channelwood.h @@ -40,16 +40,16 @@ public: Channelwood(MohawkEngine_Myst *vm); ~Channelwood(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); - uint16 getVar(uint16 var); - void toggleVar(uint16 var); - bool setVarValue(uint16 var, uint16 value); + uint16 getVar(uint16 var) override; + void toggleVar(uint16 var) override; + bool setVarValue(uint16 var, uint16 value) override; - virtual uint16 getMap() { return 9932; } + virtual uint16 getMap() override { return 9932; } DECLARE_OPCODE(o_bridgeToggle); DECLARE_OPCODE(o_pipeExtend); @@ -94,7 +94,7 @@ private: uint16 _doorOpened; // 68 bool _leverPulled; - MystResourceType5 *_leverAction; // 72 + MystArea *_leverAction; // 72 bool pipeChangeValve(bool open, uint16 mask); }; diff --git a/engines/mohawk/myst_stacks/credits.cpp b/engines/mohawk/myst_stacks/credits.cpp index b9ff8b26aa..b4a2076528 100644 --- a/engines/mohawk/myst_stacks/credits.cpp +++ b/engines/mohawk/myst_stacks/credits.cpp @@ -37,6 +37,7 @@ namespace MystStacks { Credits::Credits(MohawkEngine_Myst *vm) : MystScriptParser(vm) { setupOpcodes(); + _curImage = 0; } Credits::~Credits() { @@ -66,8 +67,10 @@ void Credits::runPersistentScripts() { _curImage++; // After the 6th image has shown, it's time to quit - if (_curImage == 7) + if (_curImage == 7) { _vm->quitGame(); + return; + } // Draw next image _vm->drawCardBackground(); diff --git a/engines/mohawk/myst_stacks/credits.h b/engines/mohawk/myst_stacks/credits.h index 3c0f969203..c2c20372bd 100644 --- a/engines/mohawk/myst_stacks/credits.h +++ b/engines/mohawk/myst_stacks/credits.h @@ -40,12 +40,12 @@ public: Credits(MohawkEngine_Myst *vm); ~Credits(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); - uint16 getVar(uint16 var); + uint16 getVar(uint16 var) override; DECLARE_OPCODE(o_runCredits); diff --git a/engines/mohawk/myst_stacks/demo.h b/engines/mohawk/myst_stacks/demo.h index f19b9a6c2c..64a392502f 100644 --- a/engines/mohawk/myst_stacks/demo.h +++ b/engines/mohawk/myst_stacks/demo.h @@ -40,8 +40,8 @@ public: Demo(MohawkEngine_Myst *vm); ~Demo(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); diff --git a/engines/mohawk/myst_stacks/dni.h b/engines/mohawk/myst_stacks/dni.h index 3dc4645bd3..1a5f0911f9 100644 --- a/engines/mohawk/myst_stacks/dni.h +++ b/engines/mohawk/myst_stacks/dni.h @@ -40,12 +40,12 @@ public: Dni(MohawkEngine_Myst *vm); ~Dni(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); - uint16 getVar(uint16 var); + uint16 getVar(uint16 var) override; void atrus_run(); void loopVideo_run(); diff --git a/engines/mohawk/myst_stacks/intro.cpp b/engines/mohawk/myst_stacks/intro.cpp index dc66984398..1d733d8100 100644 --- a/engines/mohawk/myst_stacks/intro.cpp +++ b/engines/mohawk/myst_stacks/intro.cpp @@ -170,7 +170,7 @@ void Intro::mystLinkBook_run() { void Intro::o_mystLinkBook_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Myst link book init", op); - _linkBookMovie = static_cast<MystResourceType6 *>(_invokingResource); + _linkBookMovie = getInvokingResource<MystAreaVideo>(); _startTime = 1; _linkBookRunning = true; } diff --git a/engines/mohawk/myst_stacks/intro.h b/engines/mohawk/myst_stacks/intro.h index a6c4a594d2..0095706795 100644 --- a/engines/mohawk/myst_stacks/intro.h +++ b/engines/mohawk/myst_stacks/intro.h @@ -29,7 +29,7 @@ namespace Mohawk { -class MystResourceType6; +class MystAreaVideo; struct MystScriptEntry; namespace MystStacks { @@ -41,12 +41,12 @@ public: Intro(MohawkEngine_Myst *vm); ~Intro(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); - uint16 getVar(uint16 var); + uint16 getVar(uint16 var) override; DECLARE_OPCODE(o_useLinkBook); @@ -60,7 +60,7 @@ private: uint16 _introStep; bool _linkBookRunning; - MystResourceType6 *_linkBookMovie; + MystAreaVideo *_linkBookMovie; }; } // End of namespace MystStacks diff --git a/engines/mohawk/myst_stacks/makingof.h b/engines/mohawk/myst_stacks/makingof.h index 79ef913bcf..41f91bc3fa 100644 --- a/engines/mohawk/myst_stacks/makingof.h +++ b/engines/mohawk/myst_stacks/makingof.h @@ -40,8 +40,8 @@ public: MakingOf(MohawkEngine_Myst *vm); ~MakingOf(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); diff --git a/engines/mohawk/myst_stacks/mechanical.cpp b/engines/mohawk/myst_stacks/mechanical.cpp index ffcaa226c6..3324c9a22d 100644 --- a/engines/mohawk/myst_stacks/mechanical.cpp +++ b/engines/mohawk/myst_stacks/mechanical.cpp @@ -40,6 +40,9 @@ Mechanical::Mechanical(MohawkEngine_Myst *vm) : setupOpcodes(); _elevatorGoingMiddle = false; + _elevatorPosition = 0; + + _crystalLit = 0; _mystStaircaseState = false; _fortressPosition = 0; @@ -277,7 +280,7 @@ void Mechanical::o_throneEnablePassage(uint16 op, uint16 var, uint16 argc, uint1 void Mechanical::o_birdCrankStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Mechanical bird crank start", op); - MystResourceType11 *crank = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *crank = getInvokingResource<MystAreaDrag>(); uint16 crankSoundId = crank->getList2(0); _vm->_sound->replaceSoundMyst(crankSoundId, Audio::Mixer::kMaxChannelVolume, true); @@ -285,16 +288,16 @@ void Mechanical::o_birdCrankStart(uint16 op, uint16 var, uint16 argc, uint16 *ar _birdSingEndTime = 0; _birdCrankStartTime = _vm->_system->getMillis(); - MystResourceType6 *crankMovie = static_cast<MystResourceType6 *>(crank->getSubResource(0)); + MystAreaVideo *crankMovie = static_cast<MystAreaVideo *>(crank->getSubResource(0)); crankMovie->playMovie(); } void Mechanical::o_birdCrankStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Mechanical bird crank stop", op); - MystResourceType11 *crank = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *crank = getInvokingResource<MystAreaDrag>(); - MystResourceType6 *crankMovie = static_cast<MystResourceType6 *>(crank->getSubResource(0)); + MystAreaVideo *crankMovie = static_cast<MystAreaVideo *>(crank->getSubResource(0)); crankMovie->pauseMovie(true); uint16 crankSoundId = crank->getList2(1); @@ -334,7 +337,7 @@ void Mechanical::o_fortressStaircaseMovie(uint16 op, uint16 var, uint16 argc, ui void Mechanical::o_elevatorRotationStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Elevator rotation lever start", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(0); _elevatorRotationLeverMoving = true; @@ -349,7 +352,7 @@ void Mechanical::o_elevatorRotationMove(uint16 op, uint16 var, uint16 argc, uint debugC(kDebugScript, "Opcode %d: Elevator rotation lever move", op); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Make the handle follow the mouse int16 maxStep = lever->getNumFrames() - 1; @@ -367,7 +370,7 @@ void Mechanical::o_elevatorRotationStop(uint16 op, uint16 var, uint16 argc, uint debugC(kDebugScript, "Opcode %d: Elevator rotation lever stop", op); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Get current lever frame int16 maxStep = lever->getNumFrames() - 1; @@ -416,7 +419,7 @@ void Mechanical::o_fortressRotationSpeedStart(uint16 op, uint16 var, uint16 argc _vm->_cursor->setCursor(700); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(0); } @@ -424,7 +427,7 @@ void Mechanical::o_fortressRotationSpeedMove(uint16 op, uint16 var, uint16 argc, debugC(kDebugScript, "Opcode %d Fortress rotation speed lever move", op); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Make the handle follow the mouse int16 maxStep = lever->getNumFrames() - 1; @@ -441,7 +444,7 @@ void Mechanical::o_fortressRotationSpeedMove(uint16 op, uint16 var, uint16 argc, void Mechanical::o_fortressRotationSpeedStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d Fortress rotation speed lever stop", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Release lever for (int i = _fortressRotationSpeed; i >= 0; i--) { @@ -459,7 +462,7 @@ void Mechanical::o_fortressRotationBrakeStart(uint16 op, uint16 var, uint16 argc _vm->_cursor->setCursor(700); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(_fortressRotationBrake); } @@ -467,7 +470,7 @@ void Mechanical::o_fortressRotationBrakeMove(uint16 op, uint16 var, uint16 argc, debugC(kDebugScript, "Opcode %d Fortress rotation brake lever move", op); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Make the handle follow the mouse int16 maxStep = lever->getNumFrames() - 1; @@ -484,7 +487,7 @@ void Mechanical::o_fortressRotationBrakeMove(uint16 op, uint16 var, uint16 argc, void Mechanical::o_fortressRotationBrakeStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d Fortress rotation brake lever stop", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(_fortressRotationBrake); _vm->checkCursorHints(); @@ -495,7 +498,7 @@ void Mechanical::o_fortressSimulationSpeedStart(uint16 op, uint16 var, uint16 ar _vm->_cursor->setCursor(700); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(0); } @@ -503,7 +506,7 @@ void Mechanical::o_fortressSimulationSpeedMove(uint16 op, uint16 var, uint16 arg debugC(kDebugScript, "Opcode %d Fortress rotation simulator speed lever move", op); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Make the handle follow the mouse int16 maxStep = lever->getNumFrames() - 1; @@ -520,7 +523,7 @@ void Mechanical::o_fortressSimulationSpeedMove(uint16 op, uint16 var, uint16 arg void Mechanical::o_fortressSimulationSpeedStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d Fortress rotation simulator speed lever stop", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Release lever for (int i = _fortressSimulationSpeed; i >= 0; i--) { @@ -538,7 +541,7 @@ void Mechanical::o_fortressSimulationBrakeStart(uint16 op, uint16 var, uint16 ar _vm->_cursor->setCursor(700); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(_fortressSimulationBrake); } @@ -546,7 +549,7 @@ void Mechanical::o_fortressSimulationBrakeMove(uint16 op, uint16 var, uint16 arg debugC(kDebugScript, "Opcode %d Fortress rotation simulator brake lever move", op); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Make the handle follow the mouse int16 maxStep = lever->getNumFrames() - 1; @@ -563,7 +566,7 @@ void Mechanical::o_fortressSimulationBrakeMove(uint16 op, uint16 var, uint16 arg void Mechanical::o_fortressSimulationBrakeStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d Fortress rotation simulator brake lever stop", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(_fortressSimulationBrake); _vm->checkCursorHints(); @@ -664,7 +667,7 @@ void Mechanical::o_elevatorTopMovie(uint16 op, uint16 var, uint16 argc, uint16 * void Mechanical::o_fortressRotationSetPosition(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Set fortress position", op); - VideoHandle gears = _fortressRotationGears->playMovie(); + VideoHandle gears = _fortressRotationGears->getMovieHandle(); uint32 moviePosition = Audio::Timestamp(gears->getTime(), 600).totalNumberOfFrames(); // Myst ME short movie workaround, explained in o_fortressRotation_init @@ -737,7 +740,7 @@ void Mechanical::o_throne_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) // Used on Card 6238 (Sirrus' Throne) and Card 6027 (Achenar's Throne) debugC(kDebugScript, "Opcode %d: Brother throne init", op); - _invokingResource->setEnabled(getVar(var)); + getInvokingResource<MystArea>()->setEnabled(getVar(var)); } void Mechanical::o_fortressStaircase_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { @@ -763,13 +766,13 @@ void Mechanical::o_bird_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { _birdSinging = false; _birdSingEndTime = 0; - _bird = static_cast<MystResourceType6 *>(_invokingResource); + _bird = getInvokingResource<MystAreaVideo>(); } void Mechanical::o_snakeBox_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Snake box init", op); - _snakeBox = static_cast<MystResourceType6 *>(_invokingResource); + _snakeBox = getInvokingResource<MystAreaVideo>(); } void Mechanical::elevatorRotation_run() { @@ -798,7 +801,7 @@ void Mechanical::o_elevatorRotation_init(uint16 op, uint16 var, uint16 argc, uin } void Mechanical::fortressRotation_run() { - VideoHandle gears = _fortressRotationGears->playMovie(); + VideoHandle gears = _fortressRotationGears->getMovieHandle(); double oldRate = gears->getRate().toDouble(); uint32 moviePosition = Audio::Timestamp(gears->getTime(), 600).totalNumberOfFrames(); @@ -872,7 +875,7 @@ void Mechanical::fortressRotation_run() { void Mechanical::o_fortressRotation_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Fortress rotation init", op); - _fortressRotationGears = static_cast<MystResourceType6 *>(_invokingResource); + _fortressRotationGears = getInvokingResource<MystAreaVideo>(); VideoHandle gears = _fortressRotationGears->playMovie(); gears->setLooping(true); @@ -938,13 +941,22 @@ void Mechanical::fortressSimulation_run() { holo->setLooping(true); holo->setRate(0); + // HACK: Support negative rates with edit lists + _fortressSimulationHoloRate = 0; + // END HACK + _vm->_cursor->showCursor(); _fortressSimulationInit = false; } else { - VideoHandle holo = _fortressSimulationHolo->playMovie(); + VideoHandle holo = _fortressSimulationHolo->getMovieHandle(); double oldRate = holo->getRate().toDouble(); + + // HACK: Support negative rates with edit lists + oldRate = _fortressSimulationHoloRate; + // END HACK + uint32 moviePosition = Audio::Timestamp(holo->getTime(), 600).totalNumberOfFrames(); int32 positionInQuarter = 900 - (moviePosition + 900) % 1800; @@ -978,7 +990,26 @@ void Mechanical::fortressSimulation_run() { newRate = CLIP<double>(newRate, -2.5, 2.5); - holo->setRate(Common::Rational((int)(newRate * 1000.0), 1000)); + // HACK: Support negative rates with edit lists + + // Our current QuickTime implementation does not support negative + // playback rates for movies using edit lists. + // The fortress rotation simulator movie this code handles is the + // only movie in the game requiring that feature. + + // This hack approximates the next frame to display when the rate + // is negative, and seeks to it. It's not intended to be precise. + + _fortressSimulationHoloRate = newRate; + + if (_fortressSimulationHoloRate < 0) { + double newMoviePosition = moviePosition + _fortressSimulationHoloRate * 10; + holo->setRate(0); + holo->seek(Audio::Timestamp(0, (uint)newMoviePosition, 600)); + } else { + holo->setRate(Common::Rational((int)(newRate * 1000.0), 1000)); + } + // END HACK _gearsWereRunning = true; } else if (_gearsWereRunning) { @@ -986,6 +1017,11 @@ void Mechanical::fortressSimulation_run() { uint16 simulationPosition = (moviePosition + 900) / 1800 % 4; holo->setRate(0); + + // HACK: Support negative rates with edit lists + _fortressSimulationHoloRate = 0; + // END HACK + holo->seek(Audio::Timestamp(0, 1800 * simulationPosition, 600)); _vm->_sound->playSoundBlocking( _fortressRotationSounds[simulationPosition]); @@ -997,7 +1033,7 @@ void Mechanical::fortressSimulation_run() { void Mechanical::o_fortressSimulation_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Fortress rotation simulator init", op); - _fortressSimulationHolo = static_cast<MystResourceType6 *>(_invokingResource); + _fortressSimulationHolo = getInvokingResource<MystAreaVideo>(); _fortressSimulationStartSound1 = argv[0]; _fortressSimulationStartSound2 = argv[1]; @@ -1019,7 +1055,7 @@ void Mechanical::o_fortressSimulation_init(uint16 op, uint16 var, uint16 argc, u void Mechanical::o_fortressSimulationStartup_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Fortress rotation simulator startup init", op); - _fortressSimulationStartup = static_cast<MystResourceType6 *>(_invokingResource); + _fortressSimulationStartup = getInvokingResource<MystAreaVideo>(); } } // End of namespace MystStacks diff --git a/engines/mohawk/myst_stacks/mechanical.h b/engines/mohawk/myst_stacks/mechanical.h index 6360b2be2d..aae02df433 100644 --- a/engines/mohawk/myst_stacks/mechanical.h +++ b/engines/mohawk/myst_stacks/mechanical.h @@ -40,16 +40,16 @@ public: Mechanical(MohawkEngine_Myst *vm); ~Mechanical(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); - uint16 getVar(uint16 var); - void toggleVar(uint16 var); - bool setVarValue(uint16 var, uint16 value); + uint16 getVar(uint16 var) override; + void toggleVar(uint16 var) override; + bool setVarValue(uint16 var, uint16 value) override; - virtual uint16 getMap() { return 9931; } + virtual uint16 getMap() override { return 9931; } void birdSing_run(); void elevatorRotation_run(); @@ -109,7 +109,7 @@ private: uint16 _fortressRotationBrake; // 80 uint16 _fortressPosition; // 82 uint16 _fortressRotationSounds[4]; // 86 to 92 - MystResourceType6 *_fortressRotationGears; // 172 + MystAreaVideo *_fortressRotationGears; // 172 bool _fortressRotationShortMovieWorkaround; uint32 _fortressRotationShortMovieCount; @@ -121,8 +121,12 @@ private: uint16 _fortressSimulationBrake; // 98 uint16 _fortressSimulationStartSound1; // 102 uint16 _fortressSimulationStartSound2; // 100 - MystResourceType6 *_fortressSimulationHolo; // 160 - MystResourceType6 *_fortressSimulationStartup; // 164 + MystAreaVideo *_fortressSimulationHolo; // 160 + MystAreaVideo *_fortressSimulationStartup; // 164 + + // HACK: Support negative rates with edit lists + double _fortressSimulationHoloRate; + // END HACK uint16 _elevatorGoingDown; // 112 @@ -143,10 +147,10 @@ private: bool _birdSinging; // 144 uint32 _birdCrankStartTime; // 136 uint32 _birdSingEndTime; // 140 - MystResourceType6 *_bird; // 152 + MystAreaVideo *_bird; // 152 - MystResourceType6 *_snakeBox; // 156 + MystAreaVideo *_snakeBox; // 156 }; } // End of namespace MystStacks diff --git a/engines/mohawk/myst_stacks/myst.cpp b/engines/mohawk/myst_stacks/myst.cpp index 9ad1635757..9d23d2fb10 100644 --- a/engines/mohawk/myst_stacks/myst.cpp +++ b/engines/mohawk/myst_stacks/myst.cpp @@ -50,14 +50,16 @@ Myst::Myst(MohawkEngine_Myst *vm) : _libraryBookcaseChanged = false; _dockVaultState = 0; _cabinDoorOpened = 0; + _cabinHandleDown = 0; _cabinMatchState = 2; + _cabinGaugeMovieEnabled = false; _matchBurning = false; - _tree = 0; - _treeAlcove = 0; + _tree = nullptr; + _treeAlcove = nullptr; _treeStopped = false; _treeMinPosition = 0; _imagerValidationStep = 0; - _observatoryCurrentSlider = 0; + _observatoryCurrentSlider = nullptr; _butterfliesMoviePlayed = false; _state.treeLastMoveTime = _vm->_system->getMillis(); } @@ -626,7 +628,7 @@ uint16 Myst::getVar(uint16 var) { case 307: // Cabin Boiler Fully Pressurized return _state.cabinPilotLightLit == 1 && _state.cabinValvePosition > 12; case 308: // Cabin handle position - return 0; // Not implemented in the original + return _cabinHandleDown; default: return MystScriptParser::getVar(var); } @@ -764,6 +766,9 @@ bool Myst::setVarValue(uint16 var, uint16 value) { case 304: // Myst Library Image Present on Tower Rotation Map _towerRotationMapInitialized = value; break; + case 308: // Cabin handle position + _cabinHandleDown = value; + break; case 309: // Tree stopped _treeStopped = value; break; @@ -860,14 +865,14 @@ void Myst::o_fireplaceToggleButton(uint16 op, uint16 var, uint16 argc, uint16 *a if (line & bitmask) { // Unset button for (uint i = 4795; i >= 4779; i--) { - _vm->_gfx->copyImageToScreen(i, _invokingResource->getRect()); + _vm->_gfx->copyImageToScreen(i, getInvokingResource<MystArea>()->getRect()); _vm->_system->updateScreen(); } _fireplaceLines[var - 17] &= ~bitmask; } else { // Set button for (uint i = 4779; i <= 4795; i++) { - _vm->_gfx->copyImageToScreen(i, _invokingResource->getRect()); + _vm->_gfx->copyImageToScreen(i, getInvokingResource<MystArea>()->getRect()); _vm->_system->updateScreen(); } _fireplaceLines[var - 17] |= bitmask; @@ -1251,7 +1256,7 @@ void Myst::o_imagerPlayButton(uint16 op, uint16 var, uint16 argc, uint16 *argv) void Myst::o_imagerEraseButton(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Imager erase button", op); - _imagerRedButton = static_cast<MystResourceType8 *>(_invokingResource->_parent); + _imagerRedButton = static_cast<MystAreaImageSwitch *>(getInvokingResource<MystArea>()->_parent); for (uint i = 0; i < 4; i++) _imagerSound[i] = argv[i]; _imagerValidationCard = argv[4]; @@ -1351,7 +1356,7 @@ void Myst::o_towerElevatorAnimation(uint16 op, uint16 var, uint16 argc, uint16 * void Myst::o_generatorButtonPressed(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Generator button pressed", op); - MystResource *button = _invokingResource->_parent; + MystArea *button = getInvokingResource<MystArea>()->_parent; generatorRedrawRocket(); @@ -1376,7 +1381,7 @@ void Myst::o_generatorButtonPressed(uint16 op, uint16 var, uint16 argc, uint16 * if (_generatorVoltage) _vm->_sound->replaceSoundMyst(6297); else { - _vm->_sound->replaceSoundMyst(7297); // TODO: Replace with play sound and replace background 4297 + _vm->_sound->replaceSoundMyst(7297); _vm->_sound->replaceBackgroundMyst(4297); } @@ -1385,7 +1390,7 @@ void Myst::o_generatorButtonPressed(uint16 op, uint16 var, uint16 argc, uint16 * } // Redraw button - _vm->redrawArea(button->getType8Var()); + _vm->redrawArea(button->getImageSwitchVar()); // Blow breaker if (_state.generatorVoltage > 59) @@ -1398,8 +1403,8 @@ void Myst::generatorRedrawRocket() { _vm->redrawArea(97); } -void Myst::generatorButtonValue(MystResource *button, uint16 &mask, uint16 &value) { - switch (button->getType8Var()) { +void Myst::generatorButtonValue(MystArea *button, uint16 &mask, uint16 &value) { + switch (button->getImageSwitchVar()) { case 52: // Generator Switch #1 mask = 1; value = 10; @@ -1466,7 +1471,7 @@ void Myst::o_cabinSafeHandleStartMove(uint16 op, uint16 var, uint16 argc, uint16 debugC(kDebugScript, "Opcode %d: Cabin safe handle start move", op); // Used on Card 4100 - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); handle->drawFrame(0); _vm->_cursor->setCursor(700); _tempVar = 0; @@ -1476,7 +1481,7 @@ void Myst::o_cabinSafeHandleMove(uint16 op, uint16 var, uint16 argc, uint16 *arg debugC(kDebugScript, "Opcode %d: Cabin safe handle move", op); // Used on Card 4100 - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); if (handle->pullLeverV()) { // Sound not played yet @@ -1506,7 +1511,7 @@ void Myst::o_cabinSafeHandleEndMove(uint16 op, uint16 var, uint16 argc, uint16 * debugC(kDebugScript, "Opcode %d: Cabin safe handle end move", op); // Used on Card 4100 - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); handle->drawFrame(0); _vm->checkCursorHints(); } @@ -1804,7 +1809,7 @@ void Myst::o_observatoryTimeSliderMove(uint16 op, uint16 var, uint16 argc, uint1 void Myst::o_circuitBreakerStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Circuit breaker start move", op); - MystResourceType12 *breaker = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *breaker = getInvokingResource<MystVideoInfo>(); breaker->drawFrame(0); _vm->_cursor->setCursor(700); _tempVar = 0; @@ -1813,7 +1818,7 @@ void Myst::o_circuitBreakerStartMove(uint16 op, uint16 var, uint16 argc, uint16 void Myst::o_circuitBreakerMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Circuit breaker move", op); - MystResourceType12 *breaker = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *breaker = getInvokingResource<MystVideoInfo>(); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); int16 maxStep = breaker->getStepsV() - 1; @@ -1828,7 +1833,7 @@ void Myst::o_circuitBreakerMove(uint16 op, uint16 var, uint16 argc, uint16 *argv // Breaker switched if (step == maxStep) { // Choose breaker - if (breaker->getType8Var() == 93) { + if (breaker->getImageSwitchVar() == 93) { // Voltage is still too high or not broken if (_state.generatorVoltage > 59 || _state.generatorBreakers != 1) { uint16 soundId = breaker->getList2(1); @@ -1864,8 +1869,8 @@ void Myst::o_circuitBreakerMove(uint16 op, uint16 var, uint16 argc, uint16 *argv void Myst::o_circuitBreakerEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Circuit breaker end move", op); - MystResourceType12 *breaker = static_cast<MystResourceType12 *>(_invokingResource); - _vm->redrawArea(breaker->getType8Var()); + MystVideoInfo *breaker = getInvokingResource<MystVideoInfo>(); + _vm->redrawArea(breaker->getImageSwitchVar()); _vm->checkCursorHints(); } @@ -2138,7 +2143,7 @@ void Myst::tree_run() { // Check if alcove is accessible treeSetAlcoveAccessible(); - if (_cabinGaugeMovie) { + if (_cabinGaugeMovieEnabled) { Common::Rational rate = boilerComputeGaugeRate(pressure, delay); boilerResetGauge(rate); } @@ -2187,22 +2192,22 @@ void Myst::o_rocketSoundSliderEndMove(uint16 op, uint16 var, uint16 argc, uint16 if (_state.generatorVoltage == 59 && !_state.generatorBreakers && _rocketSliderSound) _vm->_sound->stopSound(); - if (_invokingResource == _rocketSlider1) + if (getInvokingResource<MystArea>() == _rocketSlider1) _state.rocketSliderPosition[0] = _rocketSlider1->_pos.y; - else if (_invokingResource == _rocketSlider2) + else if (getInvokingResource<MystArea>() == _rocketSlider2) _state.rocketSliderPosition[1] = _rocketSlider2->_pos.y; - else if (_invokingResource == _rocketSlider3) + else if (getInvokingResource<MystArea>() == _rocketSlider3) _state.rocketSliderPosition[2] = _rocketSlider3->_pos.y; - else if (_invokingResource == _rocketSlider4) + else if (getInvokingResource<MystArea>() == _rocketSlider4) _state.rocketSliderPosition[3] = _rocketSlider4->_pos.y; - else if (_invokingResource == _rocketSlider5) + else if (getInvokingResource<MystArea>() == _rocketSlider5) _state.rocketSliderPosition[4] = _rocketSlider5->_pos.y; _vm->_sound->resumeBackgroundMyst(); } void Myst::rocketSliderMove() { - MystResourceType10 *slider = static_cast<MystResourceType10 *>(_invokingResource); + MystAreaSlider *slider = getInvokingResource<MystAreaSlider>(); if (_state.generatorVoltage == 59 && !_state.generatorBreakers) { uint16 soundId = rocketSliderGetSound(slider->_pos.y); @@ -2262,7 +2267,7 @@ void Myst::rocketCheckSolution() { if (solved) { // Reset lever position - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(0); // Book appearing @@ -2299,17 +2304,17 @@ void Myst::rocketCheckSolution() { void Myst::o_rocketPianoStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Rocket piano start move", op); - MystResourceType11 *key = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *key = getInvokingResource<MystAreaDrag>(); // What the hell?? - Common::Rect src = key->_subImages[1].rect; - Common::Rect rect = key->_subImages[0].rect; + Common::Rect src = key->getSubImage(1).rect; + Common::Rect rect = key->getSubImage(0).rect; Common::Rect dest = rect; dest.top = 332 - rect.bottom; dest.bottom = 332 - rect.top; // Draw pressed piano key - _vm->_gfx->copyImageSectionToScreen(key->_subImages[1].wdib, src, dest); + _vm->_gfx->copyImageSectionToScreen(key->getSubImage(1).wdib, src, dest); _vm->_system->updateScreen(); // Play note @@ -2326,29 +2331,29 @@ void Myst::o_rocketPianoMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { Common::Rect piano = Common::Rect(85, 123, 460, 270); // Unpress previous key - MystResourceType11 *key = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *key = getInvokingResource<MystAreaDrag>(); - Common::Rect src = key->_subImages[0].rect; + Common::Rect src = key->getSubImage(0).rect; Common::Rect dest = src; dest.top = 332 - src.bottom; dest.bottom = 332 - src.top; // Draw unpressed piano key - _vm->_gfx->copyImageSectionToScreen(key->_subImages[0].wdib, src, dest); + _vm->_gfx->copyImageSectionToScreen(key->getSubImage(0).wdib, src, dest); if (piano.contains(mouse)) { - MystResource *resource = _vm->updateCurrentResource(); - if (resource && resource->type == kMystDragArea) { + MystArea *resource = _vm->updateCurrentResource(); + if (resource && resource->type == kMystAreaDrag) { // Press new key - key = static_cast<MystResourceType11 *>(resource); - src = key->_subImages[1].rect; - Common::Rect rect = key->_subImages[0].rect; + key = static_cast<MystAreaDrag *>(resource); + src = key->getSubImage(1).rect; + Common::Rect rect = key->getSubImage(0).rect; dest = rect; dest.top = 332 - rect.bottom; dest.bottom = 332 - rect.top; // Draw pressed piano key - _vm->_gfx->copyImageSectionToScreen(key->_subImages[1].wdib, src, dest); + _vm->_gfx->copyImageSectionToScreen(key->getSubImage(1).wdib, src, dest); // Play note if (_state.generatorVoltage == 59 && !_state.generatorBreakers) { @@ -2368,15 +2373,15 @@ void Myst::o_rocketPianoMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { void Myst::o_rocketPianoStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Rocket piano end move", op); - MystResourceType8 *key = static_cast<MystResourceType8 *>(_invokingResource); + MystAreaImageSwitch *key = getInvokingResource<MystAreaImageSwitch>(); - Common::Rect &src = key->_subImages[0].rect; + Common::Rect src = key->getSubImage(0).rect; Common::Rect dest = src; dest.top = 332 - src.bottom; dest.bottom = 332 - src.top; // Draw unpressed piano key - _vm->_gfx->copyImageSectionToScreen(key->_subImages[0].wdib, src, dest); + _vm->_gfx->copyImageSectionToScreen(key->getSubImage(0).wdib, src, dest); _vm->_system->updateScreen(); _vm->_sound->stopSound(); @@ -2386,7 +2391,7 @@ void Myst::o_rocketPianoStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { void Myst::o_rocketLeverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Rocket lever start move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); _vm->_cursor->setCursor(700); _rocketLeverPosition = 0; @@ -2406,7 +2411,7 @@ void Myst::o_rocketOpenBook(uint16 op, uint16 var, uint16 argc, uint16 *argv) { void Myst::o_rocketLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Rocket lever move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); // Make the lever follow the mouse @@ -2435,7 +2440,7 @@ void Myst::o_rocketLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { void Myst::o_rocketLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Rocket lever end move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); _vm->checkCursorHints(); _rocketLeverPosition = 0; @@ -2712,7 +2717,7 @@ void Myst::clockWheel_run() { } void Myst::clockWheelStartTurn(uint16 wheel) { - MystResourceType11 *resource = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *resource = getInvokingResource<MystAreaDrag>(); uint16 soundId = resource->getList1(0); if (soundId) @@ -2835,10 +2840,10 @@ void Myst::o_observatoryChangeSettingStop(uint16 op, uint16 var, uint16 argc, ui _observatoryIncrement = 0; // Restore button and slider - _vm->_gfx->copyBackBufferToScreen(_invokingResource->getRect()); + _vm->_gfx->copyBackBufferToScreen(getInvokingResource<MystArea>()->getRect()); if (_observatoryCurrentSlider) { _vm->redrawResource(_observatoryCurrentSlider); - _observatoryCurrentSlider = 0; + _observatoryCurrentSlider = nullptr; } _vm->_sound->resumeBackgroundMyst(); } @@ -2874,7 +2879,7 @@ void Myst::o_imagerEraseStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { void Myst::o_clockLeverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Clock lever start move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(0); _vm->_cursor->setCursor(700); _clockMiddleGearMovedAlone = false; @@ -2885,7 +2890,7 @@ void Myst::o_clockLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Clock left lever move", op); if (!_clockLeverPulled) { - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // If lever pulled if (lever->pullLeverV()) { @@ -2977,7 +2982,7 @@ void Myst::o_clockLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) _vm->_sound->replaceSoundMyst(8113); // Release lever - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->releaseLeverV(); // Check if puzzle is solved @@ -3021,7 +3026,7 @@ void Myst::clockGearsCheckSolution() { void Myst::o_clockResetLeverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Clock reset lever start move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(0); _vm->_cursor->setCursor(700); } @@ -3029,7 +3034,7 @@ void Myst::o_clockResetLeverStartMove(uint16 op, uint16 var, uint16 argc, uint16 void Myst::o_clockResetLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Clock reset lever move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // If pulled if (lever->pullLeverV() && _clockWeightPosition != 0) @@ -3125,7 +3130,7 @@ void Myst::o_clockResetLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 * debugC(kDebugScript, "Opcode %d: Clock reset lever end move", op); // Get current lever frame - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->releaseLeverV(); @@ -3189,8 +3194,8 @@ void Myst::towerRotationMap_run() { void Myst::o_towerRotationMap_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { _towerRotationMapRunning = true; - _towerRotationMapTower = static_cast<MystResourceType11 *>(_invokingResource); - _towerRotationMapLabel = static_cast<MystResourceType8 *>(_vm->_resources[argv[0]]); + _towerRotationMapTower = getInvokingResource<MystAreaImageSwitch>(); + _towerRotationMapLabel = _vm->getViewResource<MystAreaImageSwitch>(argv[0]); _tempVar = 0; _startTime = 0; _towerRotationMapClicked = false; @@ -3202,7 +3207,7 @@ void Myst::towerRotationDrawBuildings() { // Draw other resources for (uint i = 1; i <= 10; i++) { - MystResourceType8 *resource = static_cast<MystResourceType8 *>(_vm->_resources[i]); + MystAreaImageSwitch *resource = _vm->getViewResource<MystAreaImageSwitch>(i); _vm->redrawResource(resource, false); } } @@ -3313,7 +3318,7 @@ void Myst::o_forechamberDoor_init(uint16 op, uint16 var, uint16 argc, uint16 *ar void Myst::o_shipAccess_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { // Enable acces to the ship if (_state.shipFloating) { - _invokingResource->setEnabled(true); + getInvokingResource<MystArea>()->setEnabled(true); } } @@ -3322,7 +3327,7 @@ void Myst::o_butterflies_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) // Used for Card 4256 (Butterfly Movie Activation) if (!_butterfliesMoviePlayed) { - MystResourceType6 *butterflies = static_cast<MystResourceType6 *>(_invokingResource); + MystAreaVideo *butterflies = getInvokingResource<MystAreaVideo>(); butterflies->playMovie(); _butterfliesMoviePlayed = true; @@ -3333,8 +3338,8 @@ void Myst::o_imager_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Imager init", op); debugC(kDebugScript, "Var: %d", var); - MystResourceType7 *select = static_cast<MystResourceType7 *>(_invokingResource); - _imagerMovie = static_cast<MystResourceType6 *>(select->getSubResource(getVar(var))); + MystAreaActionSwitch *select = getInvokingResource<MystAreaActionSwitch>(); + _imagerMovie = static_cast<MystAreaVideo *>(select->getSubResource(getVar(var))); _imagerRunning = true; } @@ -3377,8 +3382,8 @@ void Myst::libraryBookcaseTransform_run(void) { void Myst::o_libraryBookcaseTransform_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { if (_libraryBookcaseChanged) { - MystResourceType7 *resource = static_cast<MystResourceType7 *>(_invokingResource); - _libraryBookcaseMovie = static_cast<MystResourceType6 *>(resource->getSubResource(getVar(0))); + MystAreaActionSwitch *resource = getInvokingResource<MystAreaActionSwitch>(); + _libraryBookcaseMovie = static_cast<MystAreaVideo *>(resource->getSubResource(getVar(0))); _libraryBookcaseSoundId = argv[0]; _libraryBookcaseMoving = true; } @@ -3471,17 +3476,17 @@ void Myst::o_observatory_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) _tempVar = 0; _observatoryNotInitialized = true; - _observatoryVisualizer = static_cast<MystResourceType8 *>(_invokingResource); - _observatoryGoButton = static_cast<MystResourceType8 *>(_vm->_resources[argv[0]]); + _observatoryVisualizer = getInvokingResource<MystAreaImageSwitch>(); + _observatoryGoButton = _vm->getViewResource<MystAreaImageSwitch>(argv[0]); if (observatoryIsDDMMYYYY2400()) { - _observatoryDaySlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[1]]); - _observatoryMonthSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[2]]); + _observatoryDaySlider = _vm->getViewResource<MystAreaSlider>(argv[1]); + _observatoryMonthSlider = _vm->getViewResource<MystAreaSlider>(argv[2]); } else { - _observatoryMonthSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[1]]); - _observatoryDaySlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[2]]); + _observatoryMonthSlider = _vm->getViewResource<MystAreaSlider>(argv[1]); + _observatoryDaySlider = _vm->getViewResource<MystAreaSlider>(argv[2]); } - _observatoryYearSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[3]]); - _observatoryTimeSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[4]]); + _observatoryYearSlider = _vm->getViewResource<MystAreaSlider>(argv[3]); + _observatoryTimeSlider = _vm->getViewResource<MystAreaSlider>(argv[4]); // Set date selection sliders position _observatoryDaySlider->setPosition(_state.observatoryDaySlider); @@ -3503,18 +3508,14 @@ bool Myst::observatoryIsDDMMYYYY2400() { } void Myst::observatoryUpdateVisualizer(uint16 x, uint16 y) { - Common::Rect &visu0 = _observatoryVisualizer->_subImages[0].rect; - Common::Rect &visu1 = _observatoryVisualizer->_subImages[1].rect; - - visu0.left = x; - visu0.right = visu0.left + 105; - visu0.bottom = 512 - y; - visu0.top = visu0.bottom - 106; + Common::Rect visu; + visu.left = x; + visu.right = visu.left + 105; + visu.bottom = 512 - y; + visu.top = visu.bottom - 106; - visu1.left = visu0.left; - visu1.top = visu0.top; - visu1.right = visu0.right; - visu1.bottom = visu0.bottom; + _observatoryVisualizer->setSubImageRect(0, visu); + _observatoryVisualizer->setSubImageRect(1, visu); } void Myst::observatorySetTargetToSetting() { @@ -3618,13 +3619,13 @@ void Myst::gullsFly2_run() { void Myst::o_treeCard_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Enter tree card", op); - _tree = static_cast<MystResourceType8 *>(_invokingResource); + _tree = getInvokingResource<MystAreaImageSwitch>(); } void Myst::o_treeEntry_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Enter tree card with entry", op); - _treeAlcove = static_cast<MystResourceType5 *>(_invokingResource); + _treeAlcove = getInvokingResource<MystArea>(); _treeMinAccessiblePosition = argv[0]; _treeMaxAccessiblePosition = argv[1]; @@ -3703,16 +3704,18 @@ void Myst::boilerGaugeInit() { frame = Audio::Timestamp(0, 0, 600); _vm->_video->drawVideoFrame(_cabinGaugeMovie, frame); + + _cabinGaugeMovieEnabled = true; } void Myst::o_rocketSliders_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Rocket sliders init", op); - _rocketSlider1 = static_cast<MystResourceType10 *>(_vm->_resources[argv[0]]); - _rocketSlider2 = static_cast<MystResourceType10 *>(_vm->_resources[argv[1]]); - _rocketSlider3 = static_cast<MystResourceType10 *>(_vm->_resources[argv[2]]); - _rocketSlider4 = static_cast<MystResourceType10 *>(_vm->_resources[argv[3]]); - _rocketSlider5 = static_cast<MystResourceType10 *>(_vm->_resources[argv[4]]); + _rocketSlider1 = _vm->getViewResource<MystAreaSlider>(argv[0]); + _rocketSlider2 = _vm->getViewResource<MystAreaSlider>(argv[1]); + _rocketSlider3 = _vm->getViewResource<MystAreaSlider>(argv[2]); + _rocketSlider4 = _vm->getViewResource<MystAreaSlider>(argv[3]); + _rocketSlider5 = _vm->getViewResource<MystAreaSlider>(argv[4]); // Initialize sliders position for (uint i = 0; i < 5; i++) @@ -3828,13 +3831,13 @@ void Myst::o_bookAddSpecialPage_exit(uint16 op, uint16 var, uint16 argc, uint16 void Myst::o_treeCard_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Exit tree card", op); - _tree = 0; + _tree = nullptr; } void Myst::o_treeEntry_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Exit tree card with entry", op); - _treeAlcove = 0; + _treeAlcove = nullptr; } void Myst::o_boiler_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) { @@ -3842,6 +3845,8 @@ void Myst::o_boiler_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) { _cabinGaugeMovie = VideoHandle(); _cabinFireMovie = VideoHandle(); + + _cabinGaugeMovieEnabled = false; } void Myst::o_generatorControlRoom_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) { diff --git a/engines/mohawk/myst_stacks/myst.h b/engines/mohawk/myst_stacks/myst.h index a83609f640..6e2f7cc1c8 100644 --- a/engines/mohawk/myst_stacks/myst.h +++ b/engines/mohawk/myst_stacks/myst.h @@ -40,21 +40,20 @@ public: Myst(MohawkEngine_Myst *vm); ~Myst(); - virtual void disablePersistentScripts(); - virtual void runPersistentScripts(); + virtual void disablePersistentScripts() override; + virtual void runPersistentScripts() override; protected: void setupOpcodes(); - uint16 getVar(uint16 var); - void toggleVar(uint16 var); - bool setVarValue(uint16 var, uint16 value); + uint16 getVar(uint16 var) override; + void toggleVar(uint16 var) override; + bool setVarValue(uint16 var, uint16 value) override; - virtual uint16 getMap() { return 9934; } + virtual uint16 getMap() override { return 9934; } void towerRotationMap_run(); virtual void libraryBookcaseTransform_run(); void generatorControlRoom_run(); - void opcode_212_run(); void libraryCombinationBook_run(); void clockWheel_run(); void matchBurn_run(); @@ -192,11 +191,11 @@ protected: bool _generatorControlRoomRunning; uint16 _generatorVoltage; // 58 - MystResourceType10 *_rocketSlider1; // 248 - MystResourceType10 *_rocketSlider2; // 252 - MystResourceType10 *_rocketSlider3; // 256 - MystResourceType10 *_rocketSlider4; // 260 - MystResourceType10 *_rocketSlider5; // 264 + MystAreaSlider *_rocketSlider1; // 248 + MystAreaSlider *_rocketSlider2; // 252 + MystAreaSlider *_rocketSlider3; // 256 + MystAreaSlider *_rocketSlider4; // 260 + MystAreaSlider *_rocketSlider5; // 264 uint16 _rocketSliderSound; // 294 uint16 _rocketLeverPosition; // 296 VideoHandle _rocketLinkBook; @@ -214,7 +213,7 @@ protected: uint32 _gullsNextTime; // 216 bool _libraryBookcaseMoving; - MystResourceType6 *_libraryBookcaseMovie; // 104 + MystAreaVideo *_libraryBookcaseMovie; // 104 uint16 _libraryBookcaseSoundId; // 284 bool _libraryBookcaseChanged; // 288 uint16 _libraryBookSound1; // 298 @@ -223,13 +222,13 @@ protected: uint16 _courtyardBoxSound; // 302 bool _imagerValidationRunning; - MystResourceType8 *_imagerRedButton; // 304 + MystAreaImageSwitch *_imagerRedButton; // 304 uint16 _imagerSound[4]; // 308 to 314 uint16 _imagerValidationCard; // 316 uint16 _imagerValidationStep; // 318 bool _imagerRunning; - MystResourceType6 *_imagerMovie; // 64 + MystAreaVideo *_imagerMovie; // 64 uint16 _fireplaceLines[6]; // 74 to 84 @@ -248,8 +247,8 @@ protected: bool _towerRotationBlinkLabel; uint16 _towerRotationBlinkLabelCount; uint16 _towerRotationMapInitialized; // 292 - MystResourceType11 *_towerRotationMapTower; // 108 - MystResourceType8 *_towerRotationMapLabel; // 112 + MystAreaImageSwitch *_towerRotationMapTower; // 108 + MystAreaImageSwitch *_towerRotationMapLabel; // 112 uint16 _towerRotationSpeed; // 124 bool _towerRotationMapClicked; // 132 bool _towerRotationOverSpot; // 136 @@ -257,10 +256,13 @@ protected: bool _matchBurning; uint16 _matchGoOutCnt; uint16 _cabinDoorOpened; // 56 + uint16 _cabinHandleDown; // 344 uint16 _cabinMatchState; // 60 uint32 _matchGoOutTime; // 144 VideoHandle _cabinFireMovie; // 240 + + bool _cabinGaugeMovieEnabled; VideoHandle _cabinGaugeMovie; // 244 bool _boilerPressureIncreasing; @@ -269,8 +271,8 @@ protected: bool _basementPressureDecreasing; bool _treeStopped; // 236 - MystResourceType8 *_tree; // 220 - MystResourceType5 *_treeAlcove; // 224 + MystAreaImageSwitch *_tree; // 220 + MystArea *_treeAlcove; // 224 uint16 _treeMinPosition; // 228 uint16 _treeMinAccessiblePosition; // 230 uint16 _treeMaxAccessiblePosition; // 232 @@ -280,21 +282,21 @@ protected: bool _observatoryDayChanging; bool _observatoryYearChanging; bool _observatoryTimeChanging; - MystResourceType8 *_observatoryVisualizer; // 184 - MystResourceType8 *_observatoryGoButton; // 188 - MystResourceType10 *_observatoryDaySlider; // 192 - MystResourceType10 *_observatoryMonthSlider; // 196 - MystResourceType10 *_observatoryYearSlider; // 200 - MystResourceType10 *_observatoryTimeSlider; // 204 + MystAreaImageSwitch *_observatoryVisualizer; // 184 + MystAreaImageSwitch *_observatoryGoButton; // 188 + MystAreaSlider *_observatoryDaySlider; // 192 + MystAreaSlider *_observatoryMonthSlider; // 196 + MystAreaSlider *_observatoryYearSlider; // 200 + MystAreaSlider *_observatoryTimeSlider; // 204 uint32 _observatoryLastTime; // 208 bool _observatoryNotInitialized; // 212 int16 _observatoryIncrement; // 346 - MystResourceType10 *_observatoryCurrentSlider; // 348 + MystAreaSlider *_observatoryCurrentSlider; // 348 bool _greenBookRunning; void generatorRedrawRocket(); - void generatorButtonValue(MystResource *button, uint16 &offset, uint16 &value); + void generatorButtonValue(MystArea *button, uint16 &offset, uint16 &value); void rocketSliderMove(); uint16 rocketSliderGetSound(uint16 pos); diff --git a/engines/mohawk/myst_stacks/preview.cpp b/engines/mohawk/myst_stacks/preview.cpp index 4cae4aaca7..42458758f5 100644 --- a/engines/mohawk/myst_stacks/preview.cpp +++ b/engines/mohawk/myst_stacks/preview.cpp @@ -239,13 +239,13 @@ void Preview::o_library_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Library init", op); // Used for Card 3002 (Myst Island Overview) - _library = static_cast<MystResourceType8 *>(_invokingResource); + _library = getInvokingResource<MystAreaImageSwitch>(); } void Preview::o_libraryBookcaseTransformDemo_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { if (_libraryBookcaseChanged) { - MystResourceType7 *resource = static_cast<MystResourceType7 *>(_invokingResource); - _libraryBookcaseMovie = static_cast<MystResourceType6 *>(resource->getSubResource(getVar(303))); + MystAreaActionSwitch *resource = getInvokingResource<MystAreaActionSwitch>(); + _libraryBookcaseMovie = static_cast<MystAreaVideo *>(resource->getSubResource(getVar(303))); _libraryBookcaseSoundId = argv[0]; _libraryBookcaseMoving = true; } diff --git a/engines/mohawk/myst_stacks/preview.h b/engines/mohawk/myst_stacks/preview.h index 0959e935f5..9d833b35e2 100644 --- a/engines/mohawk/myst_stacks/preview.h +++ b/engines/mohawk/myst_stacks/preview.h @@ -40,8 +40,8 @@ public: Preview(MohawkEngine_Myst *vm); ~Preview(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); @@ -56,7 +56,7 @@ private: DECLARE_OPCODE(o_library_init); uint16 _libraryState; // 4 - MystResourceType8 *_library; // 32 + MystAreaImageSwitch *_library; // 32 bool _speechRunning; uint _speechStep; @@ -67,7 +67,7 @@ private: void speech_run(); void speechUpdateCue(); - void libraryBookcaseTransform_run(); + void libraryBookcaseTransform_run() override; }; } // End of namespace MystStacks diff --git a/engines/mohawk/myst_stacks/selenitic.cpp b/engines/mohawk/myst_stacks/selenitic.cpp index 8b95c7fa53..5402e5a581 100644 --- a/engines/mohawk/myst_stacks/selenitic.cpp +++ b/engines/mohawk/myst_stacks/selenitic.cpp @@ -39,9 +39,12 @@ namespace MystStacks { Selenitic::Selenitic(MohawkEngine_Myst *vm) : MystScriptParser(vm), _state(vm->_gameState->_selenitic) { setupOpcodes(); - _invokingResource = NULL; _mazeRunnerPosition = 288; _mazeRunnerDirection = 8; + _mazeRunnerDoorOpened = false; + + _soundReceiverDirection = 0; + _soundReceiverStartTime = 0; } Selenitic::~Selenitic() { @@ -669,14 +672,20 @@ void Selenitic::soundReceiverUpdate() { } void Selenitic::soundReceiverDrawView() { + soundReceiverSetSubimageRect(); + soundReceiverDrawAngle(); +} + +void Selenitic::soundReceiverSetSubimageRect() const { uint32 left = ((*_soundReceiverPosition) * 1800) / 3600; - _soundReceiverViewer->_subImages->rect.left = left; - _soundReceiverViewer->_subImages->rect.right = left + 136; + Common::Rect rect = _soundReceiverViewer->getSubImage(0).rect; - _soundReceiverViewer->drawConditionalDataToScreen(0); + rect.left = left; + rect.right = left + 136; - soundReceiverDrawAngle(); + _soundReceiverViewer->setSubImageRect(0, rect); + _soundReceiverViewer->drawConditionalDataToScreen(0); } void Selenitic::soundReceiverDrawAngle() { @@ -770,7 +779,7 @@ uint16 Selenitic::soundLockCurrentSound(uint16 position, bool pixels) { return 0; } -MystResourceType10 *Selenitic::soundLockSliderFromVar(uint16 var) { +MystAreaSlider *Selenitic::soundLockSliderFromVar(uint16 var) { switch (var) { case 20: return _soundLockSlider1; @@ -784,13 +793,13 @@ MystResourceType10 *Selenitic::soundLockSliderFromVar(uint16 var) { return _soundLockSlider5; } - return 0; + return nullptr; } void Selenitic::o_soundLockMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Sound lock move", op); - MystResourceType10 *slider = soundLockSliderFromVar(var); + MystAreaSlider *slider = soundLockSliderFromVar(var); uint16 soundId = soundLockCurrentSound(slider->_pos.y, true); if (_soundLockSoundId != soundId) { @@ -802,7 +811,7 @@ void Selenitic::o_soundLockMove(uint16 op, uint16 var, uint16 argc, uint16 *argv void Selenitic::o_soundLockStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Sound lock start move", op); - MystResourceType10 *slider = soundLockSliderFromVar(var); + MystAreaSlider *slider = soundLockSliderFromVar(var); _vm->_cursor->setCursor(700); _vm->_sound->pauseBackgroundMyst(); @@ -814,7 +823,7 @@ void Selenitic::o_soundLockStartMove(uint16 op, uint16 var, uint16 argc, uint16 void Selenitic::o_soundLockEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Sound lock end move", op); - MystResourceType10 *slider = soundLockSliderFromVar(var); + MystAreaSlider *slider = soundLockSliderFromVar(var); uint16 *value = &_state.soundLockSliderPositions[0]; switch (var) { @@ -858,7 +867,7 @@ void Selenitic::o_soundLockEndMove(uint16 op, uint16 var, uint16 argc, uint16 *a _vm->_sound->resumeBackgroundMyst(); } -void Selenitic::soundLockCheckSolution(MystResourceType10 *slider, uint16 value, uint16 solution, bool &solved) { +void Selenitic::soundLockCheckSolution(MystAreaSlider *slider, uint16 value, uint16 solution, bool &solved) { slider->drawConditionalDataToScreen(2); _vm->_sound->replaceSoundMyst(soundLockCurrentSound(value / 12, false)); _vm->_system->delayMillis(1500); @@ -926,15 +935,15 @@ void Selenitic::o_soundReceiverEndMove(uint16 op, uint16 var, uint16 argc, uint1 } void Selenitic::o_mazeRunnerCompass_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - _mazeRunnerCompass = static_cast<MystResourceType8 *>(_invokingResource); + _mazeRunnerCompass = getInvokingResource<MystAreaImageSwitch>(); } void Selenitic::o_mazeRunnerWindow_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - _mazeRunnerWindow = static_cast<MystResourceType8 *>(_invokingResource); + _mazeRunnerWindow = getInvokingResource<MystAreaImageSwitch>(); } void Selenitic::o_mazeRunnerLight_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - _mazeRunnerLight = static_cast<MystResourceType8 *>(_invokingResource); + _mazeRunnerLight = getInvokingResource<MystAreaImageSwitch>(); } void Selenitic::soundReceiver_run() { @@ -942,10 +951,13 @@ void Selenitic::soundReceiver_run() { if (_soundReceiverDirection) { uint32 currentTime = _vm->_system->getMillis(); - if (_soundReceiverSpeed == 50 && currentTime > _soundReceiverStartTime + 500) - soundReceiverIncreaseSpeed(); - else if (currentTime > _soundReceiverStartTime + 1000) - soundReceiverIncreaseSpeed(); + if (_soundReceiverSpeed == 50 && currentTime > _soundReceiverStartTime + 500) { + soundReceiverIncreaseSpeed(); + _soundReceiverStartTime = currentTime; + } else if (currentTime > _soundReceiverStartTime + 1000) { + soundReceiverIncreaseSpeed(); + _soundReceiverStartTime = currentTime; + } if (currentTime > _soundReceiverStartTime + 100) soundReceiverUpdate(); @@ -1056,24 +1068,26 @@ void Selenitic::o_soundReceiver_init(uint16 op, uint16 var, uint16 argc, uint16 // Used for Card 1245 (Sound Receiver) _soundReceiverRunning = true; - _soundReceiverRightButton = static_cast<MystResourceType8 *>(_vm->_resources[0]); - _soundReceiverLeftButton = static_cast<MystResourceType8 *>(_vm->_resources[1]); - _soundReceiverSigmaButton = static_cast<MystResourceType8 *>(_vm->_resources[2]); - _soundReceiverSources[4] = static_cast<MystResourceType8 *>(_vm->_resources[3]); - _soundReceiverSources[3] = static_cast<MystResourceType8 *>(_vm->_resources[4]); - _soundReceiverSources[2] = static_cast<MystResourceType8 *>(_vm->_resources[5]); - _soundReceiverSources[1] = static_cast<MystResourceType8 *>(_vm->_resources[6]); - _soundReceiverSources[0] = static_cast<MystResourceType8 *>(_vm->_resources[7]); - _soundReceiverViewer = static_cast<MystResourceType8 *>(_vm->_resources[8]); - _soundReceiverAngle1 = static_cast<MystResourceType8 *>(_vm->_resources[10]); - _soundReceiverAngle2 = static_cast<MystResourceType8 *>(_vm->_resources[11]); - _soundReceiverAngle3 = static_cast<MystResourceType8 *>(_vm->_resources[12]); - _soundReceiverAngle4 = static_cast<MystResourceType8 *>(_vm->_resources[13]); + _soundReceiverRightButton = _vm->getViewResource<MystAreaImageSwitch>(0); + _soundReceiverLeftButton = _vm->getViewResource<MystAreaImageSwitch>(1); + _soundReceiverSigmaButton = _vm->getViewResource<MystAreaImageSwitch>(2); + _soundReceiverSources[4] = _vm->getViewResource<MystAreaImageSwitch>(3); + _soundReceiverSources[3] = _vm->getViewResource<MystAreaImageSwitch>(4); + _soundReceiverSources[2] = _vm->getViewResource<MystAreaImageSwitch>(5); + _soundReceiverSources[1] = _vm->getViewResource<MystAreaImageSwitch>(6); + _soundReceiverSources[0] = _vm->getViewResource<MystAreaImageSwitch>(7); + _soundReceiverViewer = _vm->getViewResource<MystAreaImageSwitch>(8); + _soundReceiverAngle1 = _vm->getViewResource<MystAreaImageSwitch>(10); + _soundReceiverAngle2 = _vm->getViewResource<MystAreaImageSwitch>(11); + _soundReceiverAngle3 = _vm->getViewResource<MystAreaImageSwitch>(12); + _soundReceiverAngle4 = _vm->getViewResource<MystAreaImageSwitch>(13); uint16 currentSource = _state.soundReceiverCurrentSource; _soundReceiverPosition = &_state.soundReceiverPositions[currentSource]; _soundReceiverCurrentSource = _soundReceiverSources[currentSource]; + soundReceiverSetSubimageRect(); + _soundReceiverSigmaPressed = false; } @@ -1081,31 +1095,31 @@ void Selenitic::o_soundLock_init(uint16 op, uint16 var, uint16 argc, uint16 *arg debugC(kDebugScript, "Opcode %d: Sound lock init", op); for (uint i = 0; i < _vm->_resources.size(); i++) { - if (_vm->_resources[i]->type == kMystSlider) { - switch (_vm->_resources[i]->getType8Var()) { + if (_vm->_resources[i]->type == kMystAreaSlider) { + switch (_vm->_resources[i]->getImageSwitchVar()) { case 20: - _soundLockSlider1 = static_cast<MystResourceType10 *>(_vm->_resources[i]); + _soundLockSlider1 = _vm->getViewResource<MystAreaSlider>(i); _soundLockSlider1->setStep(_state.soundLockSliderPositions[0]); break; case 21: - _soundLockSlider2 = static_cast<MystResourceType10 *>(_vm->_resources[i]); + _soundLockSlider2 = _vm->getViewResource<MystAreaSlider>(i); _soundLockSlider2->setStep(_state.soundLockSliderPositions[1]); break; case 22: - _soundLockSlider3 = static_cast<MystResourceType10 *>(_vm->_resources[i]); + _soundLockSlider3 = _vm->getViewResource<MystAreaSlider>(i); _soundLockSlider3->setStep(_state.soundLockSliderPositions[2]); break; case 23: - _soundLockSlider4 = static_cast<MystResourceType10 *>(_vm->_resources[i]); + _soundLockSlider4 = _vm->getViewResource<MystAreaSlider>(i); _soundLockSlider4->setStep(_state.soundLockSliderPositions[3]); break; case 24: - _soundLockSlider5 = static_cast<MystResourceType10 *>(_vm->_resources[i]); + _soundLockSlider5 = _vm->getViewResource<MystAreaSlider>(i); _soundLockSlider5->setStep(_state.soundLockSliderPositions[4]); break; } - } else if (_vm->_resources[i]->type == kMystConditionalImage && _vm->_resources[i]->getType8Var() == 28) { - _soundLockButton = static_cast<MystResourceType8 *>(_vm->_resources[i]); + } else if (_vm->_resources[i]->type == kMystAreaImageSwitch && _vm->_resources[i]->getImageSwitchVar() == 28) { + _soundLockButton = _vm->getViewResource<MystAreaImageSwitch>(i); } } @@ -1113,11 +1127,11 @@ void Selenitic::o_soundLock_init(uint16 op, uint16 var, uint16 argc, uint16 *arg } void Selenitic::o_mazeRunnerRight_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - _mazeRunnerRightButton = static_cast<MystResourceType8 *>(_invokingResource); + _mazeRunnerRightButton = getInvokingResource<MystAreaImageSwitch>(); } void Selenitic::o_mazeRunnerLeft_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - _mazeRunnerLeftButton = static_cast<MystResourceType8 *>(_invokingResource); + _mazeRunnerLeftButton = getInvokingResource<MystAreaImageSwitch>(); } const uint16 Selenitic::_mazeRunnerMap[300][4] = { diff --git a/engines/mohawk/myst_stacks/selenitic.h b/engines/mohawk/myst_stacks/selenitic.h index c669d01012..fc9649755d 100644 --- a/engines/mohawk/myst_stacks/selenitic.h +++ b/engines/mohawk/myst_stacks/selenitic.h @@ -29,7 +29,7 @@ namespace Mohawk { -class MystResourceType8; +class MystAreaImageSwitch; struct MystScriptEntry; namespace MystStacks { @@ -41,16 +41,16 @@ public: Selenitic(MohawkEngine_Myst *vm); ~Selenitic(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); - uint16 getVar(uint16 var); - void toggleVar(uint16 var); - bool setVarValue(uint16 var, uint16 value); + uint16 getVar(uint16 var) override; + void toggleVar(uint16 var) override; + bool setVarValue(uint16 var, uint16 value) override; - virtual uint16 getMap() { return 9930; } + virtual uint16 getMap() override { return 9930; } DECLARE_OPCODE(o_mazeRunnerMove); DECLARE_OPCODE(o_mazeRunnerSoundRepeat); @@ -80,43 +80,44 @@ private: bool _soundReceiverRunning; bool _soundReceiverSigmaPressed; // 6 - MystResourceType8 *_soundReceiverSources[5]; // 92 -> 108 - MystResourceType8 *_soundReceiverCurrentSource; // 112 + MystAreaImageSwitch *_soundReceiverSources[5]; // 92 -> 108 + MystAreaImageSwitch *_soundReceiverCurrentSource; // 112 uint16 *_soundReceiverPosition; // 116 uint16 _soundReceiverDirection; // 120 uint16 _soundReceiverSpeed; // 122 uint32 _soundReceiverStartTime; //124 - MystResourceType8 *_soundReceiverViewer; // 128 - MystResourceType8 *_soundReceiverRightButton; // 132 - MystResourceType8 *_soundReceiverLeftButton; // 136 - MystResourceType8 *_soundReceiverAngle1; // 140 - MystResourceType8 *_soundReceiverAngle2; // 144 - MystResourceType8 *_soundReceiverAngle3; // 148 - MystResourceType8 *_soundReceiverAngle4; // 152 - MystResourceType8 *_soundReceiverSigmaButton; // 156 + MystAreaImageSwitch *_soundReceiverViewer; // 128 + MystAreaImageSwitch *_soundReceiverRightButton; // 132 + MystAreaImageSwitch *_soundReceiverLeftButton; // 136 + MystAreaImageSwitch *_soundReceiverAngle1; // 140 + MystAreaImageSwitch *_soundReceiverAngle2; // 144 + MystAreaImageSwitch *_soundReceiverAngle3; // 148 + MystAreaImageSwitch *_soundReceiverAngle4; // 152 + MystAreaImageSwitch *_soundReceiverSigmaButton; // 156 static const uint16 _mazeRunnerMap[300][4]; static const uint8 _mazeRunnerVideos[300][4]; uint16 _mazeRunnerPosition; // 56 uint16 _mazeRunnerDirection; // 58 - MystResourceType8 *_mazeRunnerWindow; // 68 - MystResourceType8 *_mazeRunnerCompass; // 72 - MystResourceType8 *_mazeRunnerLight; // 76 - MystResourceType8 *_mazeRunnerRightButton; // 80 - MystResourceType8 *_mazeRunnerLeftButton; // 84 + MystAreaImageSwitch *_mazeRunnerWindow; // 68 + MystAreaImageSwitch *_mazeRunnerCompass; // 72 + MystAreaImageSwitch *_mazeRunnerLight; // 76 + MystAreaImageSwitch *_mazeRunnerRightButton; // 80 + MystAreaImageSwitch *_mazeRunnerLeftButton; // 84 bool _mazeRunnerDoorOpened; // 160 uint16 _soundLockSoundId; - MystResourceType10 *_soundLockSlider1; // 164 - MystResourceType10 *_soundLockSlider2; // 168 - MystResourceType10 *_soundLockSlider3; // 172 - MystResourceType10 *_soundLockSlider4; // 176 - MystResourceType10 *_soundLockSlider5; // 180 - MystResourceType8 *_soundLockButton; // 184 + MystAreaSlider *_soundLockSlider1; // 164 + MystAreaSlider *_soundLockSlider2; // 168 + MystAreaSlider *_soundLockSlider3; // 172 + MystAreaSlider *_soundLockSlider4; // 176 + MystAreaSlider *_soundLockSlider5; // 180 + MystAreaImageSwitch *_soundLockButton; // 184 void soundReceiverLeftRight(uint direction); void soundReceiverUpdate(); + void soundReceiverSetSubimageRect() const; void soundReceiverDrawView(); void soundReceiverDrawAngle(); void soundReceiverIncreaseSpeed(); @@ -125,8 +126,8 @@ private: void soundReceiverSolution(uint16 source, uint16 &solution, bool &enabled); uint16 soundLockCurrentSound(uint16 position, bool pixels); - MystResourceType10 *soundLockSliderFromVar(uint16 var); - void soundLockCheckSolution(MystResourceType10 *slider, uint16 value, uint16 solution, bool &solved); + MystAreaSlider *soundLockSliderFromVar(uint16 var); + void soundLockCheckSolution(MystAreaSlider *slider, uint16 value, uint16 solution, bool &solved); bool mazeRunnerForwardAllowed(uint16 position); void mazeRunnerUpdateCompass(); diff --git a/engines/mohawk/myst_stacks/slides.h b/engines/mohawk/myst_stacks/slides.h index fb7868a03c..a0c9ae5821 100644 --- a/engines/mohawk/myst_stacks/slides.h +++ b/engines/mohawk/myst_stacks/slides.h @@ -40,8 +40,8 @@ public: Slides(MohawkEngine_Myst *vm); ~Slides(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); diff --git a/engines/mohawk/myst_stacks/stoneship.cpp b/engines/mohawk/myst_stacks/stoneship.cpp index 1113ceeac9..293c0f96f4 100644 --- a/engines/mohawk/myst_stacks/stoneship.cpp +++ b/engines/mohawk/myst_stacks/stoneship.cpp @@ -50,6 +50,8 @@ Stoneship::Stoneship(MohawkEngine_Myst *vm) : _chestDrawersOpen = 0; _chestAchenarBottomDrawerClosed = 1; + _brotherDoorOpen = 0; + // Drop key if (_state.trapdoorKeyState == 1) _state.trapdoorKeyState = 2; @@ -402,9 +404,9 @@ void Stoneship::o_pumpTurnOff(uint16 op, uint16 var, uint16 argc, uint16 *argv) } for (uint i = 0; i < _vm->_resources.size(); i++) { - MystResource *resource = _vm->_resources[i]; - if (resource->type == kMystConditionalImage && resource->getType8Var() == buttonVar) { - static_cast<MystResourceType8 *>(resource)->drawConditionalDataToScreen(0, true); + MystArea *resource = _vm->_resources[i]; + if (resource->type == kMystAreaImageSwitch && resource->getImageSwitchVar() == buttonVar) { + static_cast<MystAreaImageSwitch *>(resource)->drawConditionalDataToScreen(0, true); break; } } @@ -437,9 +439,9 @@ void Stoneship::o_cabinBookMovie(uint16 op, uint16 var, uint16 argc, uint16 *arg void Stoneship::o_drawerOpenSirius(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Open drawer", op); - MystResourceType8 *drawer = static_cast<MystResourceType8 *>(_vm->_resources[argv[0]]); + MystAreaImageSwitch *drawer = _vm->getViewResource<MystAreaImageSwitch>(argv[0]); - if (drawer->getType8Var() == 35) { + if (drawer->getImageSwitchVar() == 35) { drawer->drawConditionalDataToScreen(getVar(102), 0); } else { drawer->drawConditionalDataToScreen(0, 0); @@ -466,7 +468,7 @@ void Stoneship::o_telescopeStart(uint16 op, uint16 var, uint16 argc, uint16 *arg void Stoneship::o_telescopeMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Telescope move", op); - MystResourceType11 *display = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *display = getInvokingResource<MystAreaDrag>(); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); // Compute telescope position @@ -489,7 +491,7 @@ void Stoneship::o_telescopeStop(uint16 op, uint16 var, uint16 argc, uint16 *argv void Stoneship::o_generatorStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Generator start", op); - MystResourceType11 *handle = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *handle = getInvokingResource<MystAreaDrag>(); uint16 soundId = handle->getList1(0); if (soundId) @@ -504,7 +506,7 @@ void Stoneship::o_generatorStart(uint16 op, uint16 var, uint16 argc, uint16 *arg _batteryNextTime = _vm->_system->getMillis() + 1000; // Start handle movie - MystResourceType6 *movie = static_cast<MystResourceType6 *>(handle->getSubResource(0)); + MystAreaVideo *movie = static_cast<MystAreaVideo *>(handle->getSubResource(0)); movie->playMovie(); soundId = handle->getList2(0); @@ -530,8 +532,8 @@ void Stoneship::o_generatorStop(uint16 op, uint16 var, uint16 argc, uint16 *argv } // Pause handle movie - MystResourceType11 *handle = static_cast<MystResourceType11 *>(_invokingResource); - MystResourceType6 *movie = static_cast<MystResourceType6 *>(handle->getSubResource(0)); + MystAreaDrag *handle = getInvokingResource<MystAreaDrag>(); + MystAreaVideo *movie = static_cast<MystAreaVideo *>(handle->getSubResource(0)); movie->pauseMovie(true); uint16 soundId = handle->getList3(0); @@ -582,7 +584,7 @@ void Stoneship::batteryDeplete_run() { void Stoneship::o_drawerOpenAchenar(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Open drawer", op); - MystResourceType8 *drawer = static_cast<MystResourceType8 *>(_vm->_resources[argv[0]]); + MystAreaImageSwitch *drawer = _vm->getViewResource<MystAreaImageSwitch>(argv[0]); drawer->drawConditionalDataToScreen(0, 0); _vm->_gfx->runTransition(kTransitionTopToBottom, drawer->getRect(), 25, 5); } @@ -617,7 +619,7 @@ void Stoneship::o_hologramSelectionStart(uint16 op, uint16 var, uint16 argc, uin void Stoneship::o_hologramSelectionMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Hologram move", op); - MystResourceType11 *handle = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *handle = getInvokingResource<MystAreaDrag>(); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); if (handle->getRect().contains(mouse)) { @@ -806,7 +808,7 @@ void Stoneship::o_cloudOrbLeave(uint16 op, uint16 var, uint16 argc, uint16 *argv _cloudOrbMovie->pauseMovie(true); _vm->_sound->replaceSoundMyst(_cloudOrbStopSound); - _vm->_gfx->runTransition(kTransitionTopToBottom, _invokingResource->getRect(), 4, 0); + _vm->_gfx->runTransition(kTransitionTopToBottom, getInvokingResource<MystArea>()->getRect(), 4, 0); } void Stoneship::o_drawerCloseOpened(uint16 op, uint16 var, uint16 argc, uint16 *argv) { @@ -822,20 +824,20 @@ void Stoneship::drawerClose(uint16 drawer) { _vm->drawCardBackground(); _vm->drawResourceImages(); - MystResource *res = _vm->_resources[drawer]; + MystArea *res = _vm->_resources[drawer]; _vm->_gfx->runTransition(kTransitionBottomToTop, res->getRect(), 25, 5); } void Stoneship::o_hologramDisplay_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Hologram display init", op); - _hologramDisplay = static_cast<MystResourceType6 *>(_invokingResource); + _hologramDisplay = getInvokingResource<MystAreaVideo>(); _hologramDisplayPos = 0; } void Stoneship::o_hologramSelection_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Hologram selection init", op); - _hologramSelection = static_cast<MystResourceType6 *>(_invokingResource); + _hologramSelection = getInvokingResource<MystAreaVideo>(); } void Stoneship::batteryGaugeUpdate() { @@ -856,7 +858,7 @@ void Stoneship::o_battery_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) // Used for Card 2160 (Lighthouse Battery Pack Closeup) debugC(kDebugScript, "Opcode %d: Battery init", op); - _batteryGauge = static_cast<MystResourceType8 *>(_invokingResource); + _batteryGauge = getInvokingResource<MystAreaImageSwitch>(); batteryGaugeUpdate(); } @@ -1014,7 +1016,7 @@ void Stoneship::o_achenarDrawers_init(uint16 op, uint16 var, uint16 argc, uint16 void Stoneship::o_cloudOrb_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Cloud orb init", op); - _cloudOrbMovie = static_cast<MystResourceType6 *>(_invokingResource); + _cloudOrbMovie = getInvokingResource<MystAreaVideo>(); _cloudOrbSound = argv[0]; _cloudOrbStopSound = argv[1]; } diff --git a/engines/mohawk/myst_stacks/stoneship.h b/engines/mohawk/myst_stacks/stoneship.h index 4e1b42f26b..776641a787 100644 --- a/engines/mohawk/myst_stacks/stoneship.h +++ b/engines/mohawk/myst_stacks/stoneship.h @@ -40,16 +40,16 @@ public: Stoneship(MohawkEngine_Myst *vm); ~Stoneship(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); - uint16 getVar(uint16 var); - void toggleVar(uint16 var); - bool setVarValue(uint16 var, uint16 value); + uint16 getVar(uint16 var) override; + void toggleVar(uint16 var) override; + bool setVarValue(uint16 var, uint16 value) override; - virtual uint16 getMap() { return 9933; } + virtual uint16 getMap() override { return 9933; } DECLARE_OPCODE(o_pumpTurnOff); DECLARE_OPCODE(o_brotherDoorOpen); @@ -98,7 +98,7 @@ private: bool _batteryGaugeRunning; uint16 _batteryLastCharge; // 92 - MystResourceType8 *_batteryGauge; // 96 + MystAreaImageSwitch *_batteryGauge; // 96 void batteryGaugeUpdate(); void batteryGauge_run(); @@ -113,8 +113,8 @@ private: void drawerClose(uint16 drawer); uint16 _hologramTurnedOn; // 80 - MystResourceType6 *_hologramDisplay; // 84 - MystResourceType6 *_hologramSelection; // 88 + MystAreaVideo *_hologramDisplay; // 84 + MystAreaVideo *_hologramSelection; // 88 uint16 _hologramDisplayPos; bool _tunnelRunning; @@ -135,7 +135,7 @@ private: void telescope_run(); void telescopeLighthouseDraw(); - MystResourceType6 *_cloudOrbMovie; // 136 + MystAreaVideo *_cloudOrbMovie; // 136 uint16 _cloudOrbSound; // 140 uint16 _cloudOrbStopSound; // 142 diff --git a/engines/mohawk/myst_state.cpp b/engines/mohawk/myst_state.cpp index 3e54017df8..06cd69b23c 100644 --- a/engines/mohawk/myst_state.cpp +++ b/engines/mohawk/myst_state.cpp @@ -26,11 +26,41 @@ #include "common/debug.h" #include "common/serializer.h" +#include "common/system.h" #include "common/textconsole.h" #include "common/util.h" +#include "graphics/thumbnail.h" + namespace Mohawk { +MystSaveMetadata::MystSaveMetadata() { + saveDay = 0; + saveMonth = 0; + saveYear = 0; + saveHour = 0; + saveMinute = 0; + totalPlayTime = 0; +} + +bool MystSaveMetadata::sync(Common::Serializer &s) { + static const Common::Serializer::Version kCurrentVersion = 1; + + if (!s.syncVersion(kCurrentVersion)) { + return false; + } + + s.syncAsByte(saveDay); + s.syncAsByte(saveMonth); + s.syncAsUint16LE(saveYear); + s.syncAsByte(saveHour); + s.syncAsByte(saveMinute); + s.syncString(saveDescription); + s.syncAsUint32LE(totalPlayTime); + + return true; +} + MystGameState::MystGameState(MohawkEngine_Myst *vm, Common::SaveFileManager *saveFileMan) : _vm(vm), _saveFileMan(saveFileMan) { // Most of the variables are zero at game start. memset(&_globals, 0, sizeof(_globals)); @@ -77,28 +107,15 @@ MystGameState::~MystGameState() { } Common::StringArray MystGameState::generateSaveGameList() { - return _saveFileMan->listSavefiles("*.mys"); + return g_system->getSavefileManager()->listSavefiles("*.mys"); } bool MystGameState::load(const Common::String &filename) { - Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename); - if (!loadFile) - return false; - - debugC(kDebugSaveLoad, "Loading game from '%s'", filename.c_str()); - - // First, let's make sure we're using a saved game file from this version of Myst - // By checking length of file... - int32 size = loadFile->size(); - if (size != 664 && size != 601) { - warning("Incompatible saved game version"); - delete loadFile; + if (!loadState(filename)) { return false; } - Common::Serializer s(loadFile, 0); - syncGameState(s, size == 664); - delete loadFile; + loadMetadata(filename); // Set Channelwood elevator state to down, because we start on the lower level _channelwood.elevatorState = 0; @@ -119,19 +136,76 @@ bool MystGameState::load(const Common::String &filename) { return true; } -bool MystGameState::save(const Common::String &fname) { - Common::String filename(fname); - // Make sure we have the right extension - if (!filename.hasSuffix(".mys") && !filename.hasSuffix(".MYS")) - filename += ".mys"; +bool MystGameState::loadState(const Common::String &filename) { + Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename); + if (!loadFile) { + return false; + } + + debugC(kDebugSaveLoad, "Loading game from '%s'", filename.c_str()); + + // First, let's make sure we're using a saved game file from this version of Myst + // By checking length of file... + int32 size = loadFile->size(); + if (size != 664 && size != 601) { + warning("Incompatible saved game version"); + delete loadFile; + return false; + } + + Common::Serializer s(loadFile, nullptr); + syncGameState(s, size == 664); + delete loadFile; + + return true; +} + +void MystGameState::loadMetadata(const Common::String &filename) { + // Open the metadata file + Common::InSaveFile *metadataFile = openMetadataFile(filename); + if (!metadataFile) { + return; + } + + debugC(kDebugSaveLoad, "Loading metadata from '%s'", filename.c_str()); + + Common::Serializer m(metadataFile, nullptr); + + // Read the metadata file + if (_metadata.sync(m)) { + _vm->setTotalPlayTime(_metadata.totalPlayTime); + } + delete metadataFile; +} + +bool MystGameState::save(const Common::String &filename) { + // Make sure the description does not have an extension + Common::String desc = filename; + if (filename.hasSuffix(".mys") || filename.hasSuffix(".MYS")) { + desc = removeExtension(filename); + } + + if (!saveState(desc)) { + return false; + } + + updateMetadateForSaving(desc); + + return saveMetadata(desc); +} + +bool MystGameState::saveState(const Common::String &desc) { + // Make sure we have the right extension + Common::String filename = desc + ".mys"; Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(filename); - if (!saveFile) + if (!saveFile) { return false; + } debugC(kDebugSaveLoad, "Saving game to '%s'", filename.c_str()); - Common::Serializer s(0, saveFile); + Common::Serializer s(nullptr, saveFile); syncGameState(s, _vm->getFeatures() & GF_ME); saveFile->finalize(); delete saveFile; @@ -139,6 +213,88 @@ bool MystGameState::save(const Common::String &fname) { return true; } +void MystGameState::updateMetadateForSaving(const Common::String &desc) { + // Update save creation info + TimeDate t; + g_system->getTimeAndDate(t); + _metadata.saveYear = t.tm_year + 1900; + _metadata.saveMonth = t.tm_mon + 1; + _metadata.saveDay = t.tm_mday; + _metadata.saveHour = t.tm_hour; + _metadata.saveMinute = t.tm_min; + _metadata.saveDescription = desc; + _metadata.totalPlayTime = _vm->getTotalPlayTime(); +} + +bool MystGameState::saveMetadata(const Common::String &desc) { + // Write the metadata to a separate file so that the save files + // are still compatible with the original engine + Common::String metadataFilename = desc + ".mym"; + Common::OutSaveFile *metadataFile = _saveFileMan->openForSaving(metadataFilename); + if (!metadataFile) { + return false; + } + + // Save the metadata + Common::Serializer m(nullptr, metadataFile); + _metadata.sync(m); + + // Append a thumbnail + Graphics::saveThumbnail(*metadataFile); + + metadataFile->finalize(); + delete metadataFile; + + return true; +} + +SaveStateDescriptor MystGameState::querySaveMetaInfos(const Common::String filename) { + SaveStateDescriptor desc; + desc.setDescription(filename); + + // Open the metadata file + Common::InSaveFile *metadataFile = openMetadataFile(filename); + if (!metadataFile) { + return desc; + } + + Common::Serializer m(metadataFile, nullptr); + + // Read the metadata file + Mohawk::MystSaveMetadata metadata; + if (!metadata.sync(m)) { + delete metadataFile; + return desc; + } + + // Set the save description + desc.setDescription(metadata.saveDescription); + desc.setSaveDate(metadata.saveYear, metadata.saveMonth, metadata.saveDay); + desc.setSaveTime(metadata.saveHour, metadata.saveMinute); + desc.setPlayTime(metadata.totalPlayTime); + desc.setThumbnail(Graphics::loadThumbnail(*metadataFile)); + + delete metadataFile; + + return desc; +} + +Common::InSaveFile *MystGameState::openMetadataFile(const Common::String &filename) { + // Remove the extension + Common::String baseName = removeExtension(filename); + + // Open the metadata file + return g_system->getSavefileManager()->openForLoading(baseName + ".mym"); +} + +Common::String MystGameState::removeExtension(const Common::String &filename) { + Common::String baseName = filename; + for (uint i = 0; i < 4; i++) { + baseName.deleteLastChar(); + } + return baseName; +} + void MystGameState::syncGameState(Common::Serializer &s, bool isME) { // Globals first s.syncAsUint16LE(_globals.u0); @@ -317,11 +473,14 @@ void MystGameState::syncGameState(Common::Serializer &s, bool isME) { void MystGameState::deleteSave(const Common::String &saveName) { debugC(kDebugSaveLoad, "Deleting save file \'%s\'", saveName.c_str()); - _saveFileMan->removeSavefile(saveName.c_str()); + Common::String basename = removeExtension(saveName); + + g_system->getSavefileManager()->removeSavefile(saveName); + g_system->getSavefileManager()->removeSavefile(basename + ".mym"); } void MystGameState::addZipDest(uint16 stack, uint16 view) { - ZipDests *zipDests = 0; + ZipDests *zipDests = nullptr; // The demo has no zip dest storage if (_vm->getFeatures() & GF_DEMO) diff --git a/engines/mohawk/myst_state.h b/engines/mohawk/myst_state.h index b07a0f2469..50359a5b52 100644 --- a/engines/mohawk/myst_state.h +++ b/engines/mohawk/myst_state.h @@ -27,6 +27,8 @@ #include "common/file.h" #include "common/str.h" +#include "engines/savestate.h" + namespace Common { class Serializer; } @@ -35,15 +37,33 @@ namespace Mohawk { class MohawkEngine_Myst; +struct MystSaveMetadata { + uint8 saveDay; + uint8 saveMonth; + uint16 saveYear; + + uint8 saveHour; + uint8 saveMinute; + + uint32 totalPlayTime; + + Common::String saveDescription; + + MystSaveMetadata(); + bool sync(Common::Serializer &s); +}; + class MystGameState { public: MystGameState(MohawkEngine_Myst*, Common::SaveFileManager*); ~MystGameState(); - Common::StringArray generateSaveGameList(); - bool load(const Common::String &); - bool save(const Common::String &); - void deleteSave(const Common::String &); + static Common::StringArray generateSaveGameList(); + static SaveStateDescriptor querySaveMetaInfos(const Common::String filename); + + bool load(const Common::String &filename); + bool save(const Common::String &filename); + static void deleteSave(const Common::String &saveName); void addZipDest(uint16 stack, uint16 view); bool isReachableZipDest(uint16 stack, uint16 view); @@ -268,8 +288,17 @@ public: uint32 generatorDepletionTime; } _stoneship; + MystSaveMetadata _metadata; + private: void syncGameState(Common::Serializer &s, bool isME); + static Common::InSaveFile *openMetadataFile(const Common::String &filename); + bool loadState(const Common::String &filename); + void loadMetadata(const Common::String &filename); + bool saveState(const Common::String &desc); + void updateMetadateForSaving(const Common::String &desc); + bool saveMetadata(const Common::String &desc); + static Common::String removeExtension(const Common::String &filename); // The values in these regions are lists of VIEW resources // which correspond to visited zip destinations diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp index 198627e012..a2c08d4a92 100644 --- a/engines/mohawk/sound.cpp +++ b/engines/mohawk/sound.cpp @@ -21,6 +21,7 @@ */ #include "common/debug.h" +#include "common/events.h" #include "common/system.h" #include "common/util.h" #include "common/textconsole.h" @@ -163,8 +164,26 @@ Audio::SoundHandle *Sound::replaceSoundMyst(uint16 id, byte volume, bool loop) { void Sound::playSoundBlocking(uint16 id, byte volume) { Audio::SoundHandle *handle = playSound(id, volume); - while (_vm->_mixer->isSoundHandleActive(*handle)) + while (_vm->_mixer->isSoundHandleActive(*handle) && !_vm->shouldQuit()) { + Common::Event event; + while (_vm->_system->getEventManager()->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_SPACE: + _vm->pauseGame(); + break; + default: + break; + } + default: + break; + } + } + + // Cut down on CPU usage _vm->_system->delayMillis(10); + } } void Sound::playMidi(uint16 id) { @@ -625,7 +644,7 @@ uint16 Sound::convertMystID(uint16 id) { return id; } -Audio::SoundHandle *Sound::replaceBackgroundMyst(uint16 id, uint16 volume) { +void Sound::replaceBackgroundMyst(uint16 id, uint16 volume) { debug(0, "Replacing background sound with %d", id); // TODO: The original engine does fading @@ -641,8 +660,11 @@ Audio::SoundHandle *Sound::replaceBackgroundMyst(uint16 id, uint16 volume) { // Check if sound is already playing if (_mystBackgroundSound.type == kUsedHandle && _vm->_mixer->isSoundHandleActive(_mystBackgroundSound.handle) - && _vm->getResourceName(ID_MSND, convertMystID(_mystBackgroundSound.id)).hasPrefix(prefix)) - return &_mystBackgroundSound.handle; + && _vm->getResourceName(ID_MSND, convertMystID(_mystBackgroundSound.id)).hasPrefix(prefix)) { + // The sound is already playing, just change the volume + changeBackgroundVolumeMyst(volume); + return; + } // Stop old background sound stopBackgroundMyst(); @@ -659,10 +681,7 @@ Audio::SoundHandle *Sound::replaceBackgroundMyst(uint16 id, uint16 volume) { Audio::AudioStream *audStream = Audio::makeLoopingAudioStream(rewindStream, 0); _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_mystBackgroundSound.handle, audStream, -1, volume >> 8); - return &_mystBackgroundSound.handle; } - - return NULL; } void Sound::stopBackgroundMyst() { diff --git a/engines/mohawk/sound.h b/engines/mohawk/sound.h index 75c9492d96..c62e6e9874 100644 --- a/engines/mohawk/sound.h +++ b/engines/mohawk/sound.h @@ -136,7 +136,7 @@ public: // Myst-specific sound functions Audio::SoundHandle *replaceSoundMyst(uint16 id, byte volume = Audio::Mixer::kMaxChannelVolume, bool loop = false); - Audio::SoundHandle *replaceBackgroundMyst(uint16 id, uint16 volume = 0xFFFF); + void replaceBackgroundMyst(uint16 id, uint16 volume = 0xFFFF); void pauseBackgroundMyst(); void resumeBackgroundMyst(); void stopBackgroundMyst(); diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index ff4a69cd28..eec543235e 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -146,7 +146,7 @@ VideoHandle::VideoHandle(const VideoHandle &handle) : _ptr(handle._ptr) { VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) { // Set dithering enabled, if required - _enableDither = _vm->getGameType() == GType_MYST && !(_vm->getFeatures() & GF_ME); + _enableDither = (_vm->getGameType() == GType_MYST || _vm->getGameType() == GType_MAKINGOF) && !(_vm->getFeatures() & GF_ME); } VideoManager::~VideoManager() { @@ -184,7 +184,7 @@ void VideoManager::playMovieBlocking(const Common::String &fileName, uint16 x, u } ptr->start(); - waitUntilMovieEnds(ptr); + waitUntilMovieEnds(VideoHandle(ptr)); } void VideoManager::playMovieBlockingCentered(const Common::String &fileName, bool clearScreen) { @@ -200,7 +200,7 @@ void VideoManager::playMovieBlockingCentered(const Common::String &fileName, boo ptr->center(); ptr->start(); - waitUntilMovieEnds(ptr); + waitUntilMovieEnds(VideoHandle(ptr)); } void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) { @@ -278,7 +278,7 @@ VideoHandle VideoManager::playMovie(const Common::String &fileName) { return VideoHandle(); ptr->start(); - return ptr; + return VideoHandle(ptr); } VideoHandle VideoManager::playMovie(uint16 id) { @@ -287,7 +287,7 @@ VideoHandle VideoManager::playMovie(uint16 id) { return VideoHandle(); ptr->start(); - return ptr; + return VideoHandle(ptr); } bool VideoManager::updateMovies() { @@ -317,50 +317,13 @@ bool VideoManager::updateMovies() { // Check if we need to draw a frame if (video->needsUpdate()) { - const Graphics::Surface *frame = video->decodeNextFrame(); - Graphics::Surface *convertedFrame = 0; - - if (frame && (*it)->isEnabled()) { - Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat(); - - if (frame->format != pixelFormat) { - // We don't support downconverting to 8bpp without having - // support in the codec. Set _enableDither if shows up. - if (pixelFormat.bytesPerPixel == 1) { - warning("Cannot convert high color video frame to 8bpp"); - (*it)->close(); - it = _videos.erase(it); - continue; - } - - // Convert to the current screen format - convertedFrame = frame->convertTo(pixelFormat, video->getPalette()); - frame = convertedFrame; - } else if (pixelFormat.bytesPerPixel == 1 && video->hasDirtyPalette()) { - // Set the palette when running in 8bpp mode only - // Don't do this for Myst, which has its own per-stack handling - if (_vm->getGameType() != GType_MYST) - _vm->_system->getPaletteManager()->setPalette(video->getPalette(), 0, 256); - } - - // Clip the width/height to make sure we stay on the screen (Myst does this a few times) - uint16 width = MIN<int32>(video->getWidth(), _vm->_system->getWidth() - (*it)->getX()); - uint16 height = MIN<int32>(video->getHeight(), _vm->_system->getHeight() - (*it)->getY()); - _vm->_system->copyRectToScreen(frame->getPixels(), frame->pitch, (*it)->getX(), (*it)->getY(), width, height); - - // We've drawn something to the screen, make sure we update it + if (drawNextFrame(*it)) { updateScreen = true; - - // Delete 8bpp conversion surface - if (convertedFrame) { - convertedFrame->free(); - delete convertedFrame; - } } } // Check the video time - _vm->doVideoTimer(*it, false); + _vm->doVideoTimer(VideoHandle(*it), false); // Remember to increase the iterator it++; @@ -370,6 +333,74 @@ bool VideoManager::updateMovies() { return updateScreen; } +bool VideoManager::drawNextFrame(VideoEntryPtr videoEntry) { + Video::VideoDecoder *video = videoEntry->_video; + const Graphics::Surface *frame = video->decodeNextFrame(); + + if (!frame || !videoEntry->isEnabled()) { + return false; + } + + Graphics::Surface *convertedFrame = 0; + Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat(); + + if (frame->format != pixelFormat) { + // We don't support downconverting to 8bpp without having + // support in the codec. Set _enableDither if shows up. + if (pixelFormat.bytesPerPixel == 1) { + warning("Cannot convert high color video frame to 8bpp"); + return false; + } + + // Convert to the current screen format + convertedFrame = frame->convertTo(pixelFormat, video->getPalette()); + frame = convertedFrame; + } else if (pixelFormat.bytesPerPixel == 1 && video->hasDirtyPalette()) { + // Set the palette when running in 8bpp mode only + // Don't do this for Myst, which has its own per-stack handling + if (_vm->getGameType() != GType_MYST) + _vm->_system->getPaletteManager()->setPalette(video->getPalette(), 0, 256); + } + + // Clip the video to make sure it stays on the screen (Myst does this a few times) + Common::Rect targetRect = Common::Rect(video->getWidth(), video->getHeight()); + targetRect.translate(videoEntry->getX(), videoEntry->getY()); + + Common::Rect frameRect = Common::Rect(video->getWidth(), video->getHeight()); + + if (targetRect.left < 0) { + frameRect.left -= targetRect.left; + targetRect.left = 0; + } + + if (targetRect.top < 0) { + frameRect.top -= targetRect.top; + targetRect.top = 0; + } + + if (targetRect.right > _vm->_system->getWidth()) { + frameRect.right -= targetRect.right - _vm->_system->getWidth(); + targetRect.right = _vm->_system->getWidth(); + } + + if (targetRect.bottom > _vm->_system->getHeight()) { + frameRect.bottom -= targetRect.bottom - _vm->_system->getHeight(); + targetRect.bottom = _vm->_system->getHeight(); + } + + _vm->_system->copyRectToScreen(frame->getBasePtr(frameRect.left, frameRect.top), frame->pitch, + targetRect.left, targetRect.top, targetRect.width(), targetRect.height()); + + // Delete 8bpp conversion surface + if (convertedFrame) { + convertedFrame->free(); + delete convertedFrame; + } + + // We've drawn something to the screen, make sure we update it + return true; +} + void VideoManager::activateMLST(uint16 mlstId, uint16 card) { Common::SeekableReadStream *mlstStream = _vm->getResource(ID_MLST, card); uint16 recordCount = mlstStream->readUint16BE(); @@ -430,7 +461,7 @@ VideoHandle VideoManager::playMovieRiven(uint16 id) { ptr->start(); } - return ptr; + return VideoHandle(ptr); } } @@ -445,7 +476,7 @@ void VideoManager::playMovieBlockingRiven(uint16 id) { ptr->moveTo(_mlstRecords[i].left, _mlstRecords[i].top); ptr->setVolume(_mlstRecords[i].volume); ptr->start(); - waitUntilMovieEnds(ptr); + waitUntilMovieEnds(VideoHandle(ptr)); return; } } @@ -522,7 +553,7 @@ VideoHandle VideoManager::findVideoHandleRiven(uint16 id) { if (_mlstRecords[i].code == id) for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++) if ((*it)->getID() == _mlstRecords[i].movieID) - return *it; + return VideoHandle(*it); return VideoHandle(); } @@ -533,7 +564,7 @@ VideoHandle VideoManager::findVideoHandle(uint16 id) { for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++) if ((*it)->getID() == id) - return *it; + return VideoHandle(*it); return VideoHandle(); } @@ -544,7 +575,7 @@ VideoHandle VideoManager::findVideoHandle(const Common::String &fileName) { for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++) if ((*it)->getFileName().equalsIgnoreCase(fileName)) - return *it; + return VideoHandle(*it); return VideoHandle(); } @@ -558,12 +589,10 @@ bool VideoManager::isVideoPlaying() { } void VideoManager::drawVideoFrame(VideoHandle handle, const Audio::Timestamp &time) { - // FIXME: This should be done separately from the "playing" - // videos eventually. assert(handle); handle->seek(time); - updateMovies(); - handle->close(); + drawNextFrame(handle._ptr); + handle->stop(); } VideoManager::VideoList::iterator VideoManager::findEntry(VideoEntryPtr ptr) { diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h index 106a32f8e2..d0edab9def 100644 --- a/engines/mohawk/video.h +++ b/engines/mohawk/video.h @@ -293,7 +293,7 @@ private: /** * Constructor for internal VideoManager use */ - VideoHandle(VideoEntryPtr ptr); + explicit VideoHandle(VideoEntryPtr ptr); /** * The video entry this is associated with @@ -350,6 +350,8 @@ private: VideoList::iterator findEntry(VideoEntryPtr ptr); void removeEntry(VideoEntryPtr ptr); + bool drawNextFrame(VideoEntryPtr videoEntry); + // Dithering control bool _enableDither; void checkEnableDither(VideoEntryPtr &entry); diff --git a/engines/mortevielle/configure.engine b/engines/mortevielle/configure.engine index a7fb2ccda6..0fe89acc99 100644 --- a/engines/mortevielle/configure.engine +++ b/engines/mortevielle/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine mortevielle "Mortevielle" yes +add_engine mortevielle "Mortevielle" yes "" "" "highres" diff --git a/engines/mortevielle/detection.cpp b/engines/mortevielle/detection.cpp index b6c27e6b12..6791707dd5 100644 --- a/engines/mortevielle/detection.cpp +++ b/engines/mortevielle/detection.cpp @@ -55,7 +55,7 @@ public: MortevielleMetaEngine() : AdvancedMetaEngine(Mortevielle::MortevielleGameDescriptions, sizeof(Mortevielle::MortevielleGameDescription), MortevielleGame) { _md5Bytes = 512; - _singleid = "mortevielle"; + _singleId = "mortevielle"; // Use kADFlagUseExtraAsHint to distinguish between original and improved versions // (i.e. use or not of the game data file). _flags = kADFlagUseExtraAsHint; diff --git a/engines/neverhood/configure.engine b/engines/neverhood/configure.engine index 46910e293e..f04e6c69f6 100644 --- a/engines/neverhood/configure.engine +++ b/engines/neverhood/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine neverhood "Neverhood" yes +add_engine neverhood "Neverhood" yes "" "" "highres" diff --git a/engines/neverhood/detection.cpp b/engines/neverhood/detection.cpp index 4d545e136c..cfddc2d6b4 100644 --- a/engines/neverhood/detection.cpp +++ b/engines/neverhood/detection.cpp @@ -41,7 +41,7 @@ struct NeverhoodGameDescription { }; const char *NeverhoodEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } uint32 NeverhoodEngine::getFeatures() const { @@ -181,8 +181,8 @@ static const ExtraGuiOption neverhoodExtraGuiOption3 = { class NeverhoodMetaEngine : public AdvancedMetaEngine { public: NeverhoodMetaEngine() : AdvancedMetaEngine(Neverhood::gameDescriptions, sizeof(Neverhood::NeverhoodGameDescription), neverhoodGames) { - _singleid = "neverhood"; - _guioptions = GUIO2(GUIO_NOSUBTITLES, GUIO_NOMIDI); + _singleId = "neverhood"; + _guiOptions = GUIO2(GUIO_NOSUBTITLES, GUIO_NOMIDI); } virtual const char *getName() const { @@ -245,7 +245,6 @@ SaveStateList NeverhoodMetaEngine::listSaves(const char *target) const { Common::StringArray filenames; filenames = saveFileMan->listSavefiles(pattern.c_str()); - Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); file++) { @@ -262,6 +261,8 @@ SaveStateList NeverhoodMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/parallaction/detection.cpp b/engines/parallaction/detection.cpp index daeee1fee4..4c52990874 100644 --- a/engines/parallaction/detection.cpp +++ b/engines/parallaction/detection.cpp @@ -220,7 +220,7 @@ static const PARALLACTIONGameDescription gameDescriptions[] = { class ParallactionMetaEngine : public AdvancedMetaEngine { public: ParallactionMetaEngine() : AdvancedMetaEngine(Parallaction::gameDescriptions, sizeof(Parallaction::PARALLACTIONGameDescription), parallactionGames) { - _guioptions = GUIO1(GUIO_NOLAUNCHLOAD); + _guiOptions = GUIO1(GUIO_NOLAUNCHLOAD); } virtual const char *getName() const { @@ -273,7 +273,6 @@ SaveStateList ParallactionMetaEngine::listSaves(const char *target) const { Common::String pattern(ConfMan.getDomain(target)->getVal("gameid") + ".0##"); Common::StringArray filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -290,6 +289,8 @@ SaveStateList ParallactionMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/parallaction/saveload.cpp b/engines/parallaction/saveload.cpp index 72e9400acd..6d598d9557 100644 --- a/engines/parallaction/saveload.cpp +++ b/engines/parallaction/saveload.cpp @@ -194,7 +194,7 @@ int SaveLoad::selectSaveFile(Common::String &selectedName, bool saveMode, const bool SaveLoad::loadGame() { Common::String null; - int _di = selectSaveFile(null, false, "Load file", "Load"); + int _di = selectSaveFile(null, false, _("Load file"), _("Load")); if (_di == -1) { return false; } @@ -209,7 +209,7 @@ bool SaveLoad::loadGame() { bool SaveLoad::saveGame() { Common::String saveName; - int slot = selectSaveFile(saveName, true, "Save file", "Save"); + int slot = selectSaveFile(saveName, true, _("Save file"), _("Save")); if (slot == -1) { return false; } diff --git a/engines/pegasus/configure.engine b/engines/pegasus/configure.engine index ed7e295287..650d57a602 100644 --- a/engines/pegasus/configure.engine +++ b/engines/pegasus/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine pegasus "The Journeyman Project: Pegasus Prime" yes "" "" "16bit" +add_engine pegasus "The Journeyman Project: Pegasus Prime" yes "" "" "16bit highres" diff --git a/engines/pegasus/detection.cpp b/engines/pegasus/detection.cpp index 721c382d4f..161a133c8b 100644 --- a/engines/pegasus/detection.cpp +++ b/engines/pegasus/detection.cpp @@ -134,7 +134,7 @@ static const PegasusGameDescription gameDescriptions[] = { class PegasusMetaEngine : public AdvancedMetaEngine { public: PegasusMetaEngine() : AdvancedMetaEngine(Pegasus::gameDescriptions, sizeof(Pegasus::PegasusGameDescription), pegasusGames) { - _singleid = "pegasus"; + _singleId = "pegasus"; } virtual const char *getName() const { diff --git a/engines/prince/configure.engine b/engines/prince/configure.engine index 50740d9f41..827579b00d 100644 --- a/engines/prince/configure.engine +++ b/engines/prince/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine prince "The Prince and The Coward" no +add_engine prince "The Prince and The Coward" no "" "" "highres" diff --git a/engines/prince/detection.cpp b/engines/prince/detection.cpp index 3fe7993fdb..1c6f63aff3 100644 --- a/engines/prince/detection.cpp +++ b/engines/prince/detection.cpp @@ -29,7 +29,7 @@ int PrinceEngine::getGameType() const { } const char *PrinceEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } uint32 PrinceEngine::getFeatures() const { diff --git a/engines/prince/detection.h b/engines/prince/detection.h index 7e5bdd6b7b..3076253cf5 100644 --- a/engines/prince/detection.h +++ b/engines/prince/detection.h @@ -104,7 +104,7 @@ const static char *directoryGlobs[] = { class PrinceMetaEngine : public AdvancedMetaEngine { public: PrinceMetaEngine() : AdvancedMetaEngine(Prince::gameDescriptions, sizeof(Prince::PrinceGameDescription), princeGames) { - _singleid = "prince"; + _singleId = "prince"; _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } diff --git a/engines/prince/graphics.cpp b/engines/prince/graphics.cpp index 3482d79f69..d5178efc17 100644 --- a/engines/prince/graphics.cpp +++ b/engines/prince/graphics.cpp @@ -279,7 +279,7 @@ void GraphicsMan::drawTransparentWithTransDrawNode(Graphics::Surface *screen, Dr // first and last row at the same time (height = 1) - no anti-alias continue; } - // new color value based on orginal screen surface color and sprite's edge pixel color + // new color value based on original screen surface color and sprite's edge pixel color *dst2 = transTableData[*dst2 * 256 + value]; } } diff --git a/engines/queen/detection.cpp b/engines/queen/detection.cpp index 96075a0f0c..81e0767836 100644 --- a/engines/queen/detection.cpp +++ b/engines/queen/detection.cpp @@ -185,6 +185,19 @@ static const QueenGameDescription gameDescriptions[] = { }, }, + // DOS Floppy - Russian + { + { + "queen", + "Floppy", + AD_ENTRY1s("queen.1", "0d1c10d5c3a1bd90bc0b3859a3258093", 22677657), + Common::RU_RUS, + Common::kPlatformDOS, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOSPEECH) + }, + }, + // DOS CD - French { { @@ -388,7 +401,7 @@ static const QueenGameDescription gameDescriptions[] = { class QueenMetaEngine : public AdvancedMetaEngine { public: QueenMetaEngine() : AdvancedMetaEngine(Queen::gameDescriptions, sizeof(Queen::QueenGameDescription), queenGames, optionsList) { - _singleid = "queen"; + _singleId = "queen"; } virtual const char *getName() const { @@ -430,25 +443,25 @@ const ADGameDescription *QueenMetaEngine::fallbackDetect(const FileMap &allFiles } Queen::DetectedGameVersion version; if (Queen::Resource::detectVersion(&version, &dataFile)) { - desc.gameid = "queen"; + desc.gameId = "queen"; desc.language = version.language; desc.platform = version.platform; desc.flags = ADGF_NO_FLAGS; - desc.guioptions = GUIO0(); + desc.guiOptions = GUIO0(); if (version.features & Queen::GF_DEMO) { desc.extra = "Demo"; desc.flags = ADGF_DEMO; - desc.guioptions = GUIO_NOSPEECH; + desc.guiOptions = GUIO_NOSPEECH; } else if (version.features & Queen::GF_INTERVIEW) { desc.extra = "Interview"; desc.flags = ADGF_DEMO; - desc.guioptions = GUIO_NOSPEECH; + desc.guiOptions = GUIO_NOSPEECH; } else if (version.features & Queen::GF_FLOPPY) { desc.extra = "Floppy"; - desc.guioptions = GUIO_NOSPEECH; + desc.guiOptions = GUIO_NOSPEECH; } else if (version.features & Queen::GF_TALKIE) { desc.extra = "Talkie"; - desc.guioptions = GAMEOPTION_ALT_INTRO; + desc.guiOptions = GAMEOPTION_ALT_INTRO; } return (const ADGameDescription *)&desc; } @@ -464,7 +477,6 @@ SaveStateList QueenMetaEngine::listSaves(const char *target) const { Common::String pattern("queen.s##"); filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -483,6 +495,8 @@ SaveStateList QueenMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/saga/configure.engine b/engines/saga/configure.engine index 99e2ab367b..adb904a6dd 100644 --- a/engines/saga/configure.engine +++ b/engines/saga/configure.engine @@ -1,5 +1,5 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] add_engine saga "SAGA" yes "ihnm saga2" "ITE" -add_engine ihnm "IHNM" yes -add_engine saga2 "SAGA 2 games" no +add_engine ihnm "IHNM" yes "" "" "highres" +add_engine saga2 "SAGA 2 games" no "" "" "highres" diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp index 13ca63525a..0677e84d67 100644 --- a/engines/saga/detection.cpp +++ b/engines/saga/detection.cpp @@ -102,11 +102,11 @@ static const Engines::ObsoleteGameID obsoleteGameIDsTable[] = { class SagaMetaEngine : public AdvancedMetaEngine { public: SagaMetaEngine() : AdvancedMetaEngine(Saga::gameDescriptions, sizeof(Saga::SAGAGameDescription), sagaGames) { - _singleid = "saga"; + _singleId = "saga"; } - virtual GameDescriptor findGame(const char *gameid) const { - return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable); + virtual GameDescriptor findGame(const char *gameId) const { + return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable); } virtual const char *getName() const { @@ -183,7 +183,6 @@ SaveStateList SagaMetaEngine::listSaves(const char *target) const { pattern += ".s##"; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; int slotNum = 0; @@ -203,6 +202,8 @@ SaveStateList SagaMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp index 44581f26fc..ad940aaf8b 100644 --- a/engines/saga/interface.cpp +++ b/engines/saga/interface.cpp @@ -332,6 +332,9 @@ void Interface::saveReminderCallback(void *refCon) { } void Interface::updateSaveReminder() { + // CHECKME: This is potentially called from a different thread because it is + // called from a timer callback. However, it does not seem to take any + // precautions to avoid race conditions. if (_active && _panelMode == kPanelMain) { _saveReminderState = _saveReminderState % _vm->getDisplayInfo().saveReminderNumSprites + 1; drawStatusBar(); @@ -1859,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/music.cpp b/engines/saga/music.cpp index 663f5991d0..cd48ebaa4d 100644 --- a/engines/saga/music.cpp +++ b/engines/saga/music.cpp @@ -224,6 +224,9 @@ void Music::musicVolumeGaugeCallback(void *refCon) { } void Music::musicVolumeGauge() { + // CHECKME: This is potentially called from a different thread because it is + // called from a timer callback. However, it does not seem to take any + // precautions to avoid race conditions. int volume; _currentVolumePercent += 10; diff --git a/engines/saga/puzzle.cpp b/engines/saga/puzzle.cpp index 705834f1b7..099bf79e6b 100644 --- a/engines/saga/puzzle.cpp +++ b/engines/saga/puzzle.cpp @@ -399,6 +399,9 @@ void Puzzle::hintTimerCallback(void *refCon) { } void Puzzle::solicitHint() { + // CHECKME: This is potentially called from a different thread because it is + // called from a timer callback. However, it does not seem to take any + // precautions to avoid race conditions. int i; _vm->_actor->setSpeechColor(1, kITEColorBlack); diff --git a/engines/saga/render.cpp b/engines/saga/render.cpp index 1f23a388d0..b932e228ad 100644 --- a/engines/saga/render.cpp +++ b/engines/saga/render.cpp @@ -276,6 +276,9 @@ void Render::fpsTimerCallback(void *refCon) { } void Render::fpsTimer() { + // CHECKME: This is potentially called from a different thread because it is + // called from a timer callback. However, it does not seem to take any + // precautions to avoid race conditions. _fps = _renderedFrameCount; _renderedFrameCount = 0; } 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/savestate.h b/engines/savestate.h index 54eff0f8cb..21ade602fa 100644 --- a/engines/savestate.h +++ b/engines/savestate.h @@ -27,7 +27,6 @@ #include "common/str.h" #include "common/ptr.h" - namespace Graphics { struct Surface; } @@ -205,5 +204,13 @@ private: /** List of savestates. */ typedef Common::Array<SaveStateDescriptor> SaveStateList; +/** + * Comparator object to compare SaveStateDescriptor's based on slot. + */ +struct SaveStateDescriptorSlotComparator { + bool operator()(const SaveStateDescriptor &x, const SaveStateDescriptor &y) const { + return x.getSaveSlot() < y.getSaveSlot(); + } +}; #endif diff --git a/engines/sci/configure.engine b/engines/sci/configure.engine index d1c45a4654..f8a519002e 100644 --- a/engines/sci/configure.engine +++ b/engines/sci/configure.engine @@ -1,4 +1,4 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] add_engine sci "SCI" yes "sci32" "SCI 0-1.1 games" -add_engine sci32 "SCI32 games" no +add_engine sci32 "SCI32 games" no "" "" "highres" diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 438c725324..a092e0676d 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -137,8 +137,12 @@ Console::Console(SciEngine *engine) : GUI::Debugger(), registerCmd("wl", WRAP_METHOD(Console, cmdWindowList)); // alias registerCmd("plane_list", WRAP_METHOD(Console, cmdPlaneList)); registerCmd("pl", WRAP_METHOD(Console, cmdPlaneList)); // alias + registerCmd("visible_plane_list", WRAP_METHOD(Console, cmdVisiblePlaneList)); + registerCmd("vpl", WRAP_METHOD(Console, cmdVisiblePlaneList)); // alias registerCmd("plane_items", WRAP_METHOD(Console, cmdPlaneItemList)); registerCmd("pi", WRAP_METHOD(Console, cmdPlaneItemList)); // alias + registerCmd("visible_plane_items", WRAP_METHOD(Console, cmdVisiblePlaneItemList)); + registerCmd("vpi", WRAP_METHOD(Console, cmdVisiblePlaneItemList)); // alias registerCmd("saved_bits", WRAP_METHOD(Console, cmdSavedBits)); registerCmd("show_saved_bits", WRAP_METHOD(Console, cmdShowSavedBits)); // Segments @@ -190,6 +194,7 @@ Console::Console(SciEngine *engine) : GUI::Debugger(), registerCmd("send", WRAP_METHOD(Console, cmdSend)); registerCmd("go", WRAP_METHOD(Console, cmdGo)); registerCmd("logkernel", WRAP_METHOD(Console, cmdLogKernel)); + registerCmd("vocab994", WRAP_METHOD(Console, cmdMapVocab994)); // Breakpoints registerCmd("bp_list", WRAP_METHOD(Console, cmdBreakpointList)); registerCmd("bplist", WRAP_METHOD(Console, cmdBreakpointList)); // alias @@ -330,6 +335,7 @@ bool Console::cmdHelp(int argc, const char **argv) { debugPrintf("debugflag_list - Lists the available debug flags and their status\n"); debugPrintf("debugflag_enable - Enables a debug flag\n"); debugPrintf("debugflag_disable - Disables a debug flag\n"); + debugPrintf("debuglevel - Shows or sets debug level\n"); debugPrintf("\n"); debugPrintf("Commands\n"); debugPrintf("--------\n"); @@ -380,7 +386,9 @@ bool Console::cmdHelp(int argc, const char **argv) { debugPrintf(" animate_list / al - Shows the current list of objects in kAnimate's draw list (SCI0 - SCI1.1)\n"); debugPrintf(" window_list / wl - Shows a list of all the windows (ports) in the draw list (SCI0 - SCI1.1)\n"); debugPrintf(" plane_list / pl - Shows a list of all the planes in the draw list (SCI2+)\n"); + debugPrintf(" visible_plane_list / vpl - Shows a list of all the planes in the visible draw list (SCI2+)\n"); debugPrintf(" plane_items / pi - Shows a list of all items for a plane (SCI2+)\n"); + debugPrintf(" visible_plane_items / vpi - Shows a list of all items for a plane in the visible draw list (SCI2+)\n"); debugPrintf(" saved_bits - List saved bits on the hunk\n"); debugPrintf(" show_saved_bits - Display saved bits\n"); debugPrintf("\n"); @@ -487,6 +495,9 @@ bool Console::cmdGetVersion(int argc, const char **argv) { debugPrintf("SCI2.1 kernel table: %s\n", (_engine->_features->detectSci21KernelType() == SCI_VERSION_2) ? "modified SCI2 (old)" : "SCI2.1 (new)"); #endif debugPrintf("View type: %s\n", viewTypeDesc[g_sci->getResMan()->getViewType()]); + if (getSciVersion() <= SCI_VERSION_1_1) { + debugPrintf("kAnimate fastCast enabled: %s\n", g_sci->_gfxAnimate->isFastCastEnabled() ? "yes" : "no"); + } debugPrintf("Uses palette merging: %s\n", g_sci->_gfxPalette16->isMerging() ? "yes" : "no"); debugPrintf("Uses 16 bit color matching: %s\n", g_sci->_gfxPalette16->isUsing16bitColorMatch() ? "yes" : "no"); debugPrintf("Resource volume version: %s\n", g_sci->getResMan()->getVolVersionDesc()); @@ -994,7 +1005,7 @@ bool Console::cmdHexgrep(int argc, const char **argv) { for (; resNumber <= resMax; resNumber++) { script = _engine->getResMan()->findResource(ResourceId(restype, resNumber), 0); if (script) { - unsigned int seeker = 0, seekerold = 0; + uint32 seeker = 0, seekerold = 0; uint32 comppos = 0; int output_script_name = 0; @@ -1500,7 +1511,7 @@ bool Console::cmdSaid(int argc, const char **argv) { } // TODO: Maybe turn this into a proper said spec compiler - unsigned int len = 0; + uint32 len = 0; for (p++; p < argc; p++) { if (strcmp(argv[p], ",") == 0) { spec[len++] = 0xf0; @@ -1537,7 +1548,7 @@ bool Console::cmdSaid(int argc, const char **argv) { spec[len++] = 0xfe; spec[len++] = 0xf6; } else { - unsigned int s = strtol(argv[p], 0, 16); + uint32 s = strtol(argv[p], 0, 16); if (s >= 0xf0 && s <= 0xff) { spec[len++] = s; } else { @@ -1766,6 +1777,21 @@ bool Console::cmdPlaneList(int argc, const char **argv) { return true; } +bool Console::cmdVisiblePlaneList(int argc, const char **argv) { +#ifdef ENABLE_SCI32 + if (_engine->_gfxFrameout) { + debugPrintf("Visible plane list:\n"); + _engine->_gfxFrameout->printVisiblePlaneList(this); + } else { + debugPrintf("This SCI version does not have a list of planes\n"); + } +#else + debugPrintf("SCI32 isn't included in this compiled executable\n"); +#endif + return true; +} + + bool Console::cmdPlaneItemList(int argc, const char **argv) { if (argc != 2) { debugPrintf("Shows the list of items for a plane\n"); @@ -1794,6 +1820,34 @@ bool Console::cmdPlaneItemList(int argc, const char **argv) { return true; } +bool Console::cmdVisiblePlaneItemList(int argc, const char **argv) { + if (argc != 2) { + debugPrintf("Shows the list of items for a plane\n"); + debugPrintf("Usage: %s <plane address>\n", argv[0]); + return true; + } + + reg_t planeObject = NULL_REG; + + if (parse_reg_t(_engine->_gamestate, argv[1], &planeObject, false)) { + debugPrintf("Invalid address passed.\n"); + debugPrintf("Check the \"addresses\" command on how to use addresses\n"); + return true; + } + +#ifdef ENABLE_SCI32 + if (_engine->_gfxFrameout) { + debugPrintf("Visible plane item list:\n"); + _engine->_gfxFrameout->printVisiblePlaneItemList(this, planeObject); + } else { + debugPrintf("This SCI version does not have a list of plane items\n"); + } +#else + debugPrintf("SCI32 isn't included in this compiled executable\n"); +#endif + return true; +} + bool Console::cmdSavedBits(int argc, const char **argv) { SegManager *segman = _engine->_gamestate->_segMan; SegmentId id = segman->findSegmentByType(SEG_TYPE_HUNK); @@ -3901,6 +3955,55 @@ bool Console::cmdSfx01Track(int argc, const char **argv) { return true; } +bool Console::cmdMapVocab994(int argc, const char **argv) { + EngineState *s = _engine->_gamestate; // for the several defines in this function + reg_t reg; + + if (argc != 4) { + debugPrintf("Attempts to map a range of vocab.994 entries to a given class\n"); + debugPrintf("Usage: %s <class addr> <first> <last>\n", argv[0]); + return true; + } + + if (parse_reg_t(_engine->_gamestate, argv[1], ®, false)) { + debugPrintf("Invalid address passed.\n"); + debugPrintf("Check the \"addresses\" command on how to use addresses\n"); + return true; + } + + Resource *resource = _engine->_resMan->findResource(ResourceId(kResourceTypeVocab, 994), 0); + const Object *obj = s->_segMan->getObject(reg); + uint16 *data = (uint16 *) resource->data; + uint32 first = atoi(argv[2]); + uint32 last = atoi(argv[3]); + Common::Array<bool> markers; + + markers.resize(_engine->getKernel()->getSelectorNamesSize()); + if (!obj->isClass() && getSciVersion() != SCI_VERSION_3) + obj = s->_segMan->getObject(obj->getSuperClassSelector()); + + first = MIN(first, (uint32) (resource->size / 2 - 2)); + last = MIN(last, (uint32) (resource->size / 2 - 2)); + + for (uint32 i = first; i <= last; ++i) { + uint16 ofs = data[i]; + + if (obj && ofs < obj->getVarCount()) { + uint16 varSelector = obj->getVarSelector(ofs); + debugPrintf("%d: property at index %04x of %s is %s %s\n", i, ofs, + s->_segMan->derefString(obj->getNameSelector()), + _engine->getKernel()->getSelectorName(varSelector).c_str(), + markers[varSelector] ? "(repeat!)" : ""); + markers[varSelector] = true; + } + else { + debugPrintf("%d: property at index %04x doesn't match up with %s\n", i, ofs, + s->_segMan->derefString(obj->getNameSelector())); + } + } + + return true; +} bool Console::cmdQuit(int argc, const char **argv) { if (argc != 2) { } @@ -4339,7 +4442,8 @@ int Console::printObject(reg_t pos) { debugPrintf(" "); if (var_container && i < var_container->getVarCount()) { uint16 varSelector = var_container->getVarSelector(i); - debugPrintf("[%03x] %s = ", varSelector, _engine->getKernel()->getSelectorName(varSelector).c_str()); + // Times two commented out for now for easy parsing of vocab.994 + debugPrintf("(%04x) [%03x] %s = ", i /* *2 */, varSelector, _engine->getKernel()->getSelectorName(varSelector).c_str()); } else debugPrintf("p#%x = ", i); diff --git a/engines/sci/console.h b/engines/sci/console.h index 8b10912fbe..cf85def950 100644 --- a/engines/sci/console.h +++ b/engines/sci/console.h @@ -96,7 +96,9 @@ private: bool cmdAnimateList(int argc, const char **argv); bool cmdWindowList(int argc, const char **argv); bool cmdPlaneList(int argc, const char **argv); + bool cmdVisiblePlaneList(int argc, const char **argv); bool cmdPlaneItemList(int argc, const char **argv); + bool cmdVisiblePlaneItemList(int argc, const char **argv); bool cmdSavedBits(int argc, const char **argv); bool cmdShowSavedBits(int argc, const char **argv); // Segments @@ -137,6 +139,7 @@ private: bool cmdSend(int argc, const char **argv); bool cmdGo(int argc, const char **argv); bool cmdLogKernel(int argc, const char **argv); + bool cmdMapVocab994(int argc, const char **argv); // Breakpoints bool cmdBreakpointList(int argc, const char **argv); bool cmdBreakpointDelete(int argc, const char **argv); diff --git a/engines/sci/decompressor.cpp b/engines/sci/decompressor.cpp index e65ff148de..ca2298e67e 100644 --- a/engines/sci/decompressor.cpp +++ b/engines/sci/decompressor.cpp @@ -257,7 +257,7 @@ int DecompressorLZW::unpackLZW1(Common::ReadStream *src, byte *dest, uint32 nPac init(src, dest, nPacked, nUnpacked); byte *stak = (byte *)malloc(0x1014); - unsigned int tokensSize = 0x1004 * sizeof(Tokenlist); + uint32 tokensSize = 0x1004 * sizeof(Tokenlist); Tokenlist *tokens = (Tokenlist *)malloc(tokensSize); if (!stak || !tokens) { free(stak); diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index f4f104010f..c920ef10e2 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -98,8 +98,11 @@ static const PlainGameDescriptor s_sciGameTitles[] = { {"lsl6", "Leisure Suit Larry 6: Shape Up or Slip Out!"}, {"pepper", "Pepper's Adventure in Time"}, {"slater", "Slater & Charlie Go Camping"}, + {"gk1demo", "Gabriel Knight: Sins of the Fathers"}, + {"qfg4demo", "Quest for Glory IV: Shadows of Darkness"}, + {"pq4demo", "Police Quest IV: Open Season"}, // === SCI2 games ========================================================= - {"gk1", "Gabriel Knight: Sins of the Fathers"}, // demo is SCI11, full version SCI32 + {"gk1", "Gabriel Knight: Sins of the Fathers"}, {"pq4", "Police Quest IV: Open Season"}, // floppy is SCI2, CD SCI2.1 {"qfg4", "Quest for Glory IV: Shadows of Darkness"}, // floppy is SCI2, CD SCI2.1 // === SCI2.1 games ======================================================== @@ -146,6 +149,7 @@ static const GameIdStrToEnum s_gameIdStrToEnum[] = { { "fairytales", GID_FAIRYTALES }, { "freddypharkas", GID_FREDDYPHARKAS }, { "funseeker", GID_FUNSEEKER }, + { "gk1demo", GID_GK1DEMO }, { "gk1", GID_GK1 }, { "gk2", GID_GK2 }, { "hoyle1", GID_HOYLE1 }, @@ -183,12 +187,14 @@ static const GameIdStrToEnum s_gameIdStrToEnum[] = { { "pq2", GID_PQ2 }, { "pq3", GID_PQ3 }, { "pq4", GID_PQ4 }, + { "pq4demo", GID_PQ4DEMO }, { "pqswat", GID_PQSWAT }, { "qfg1", GID_QFG1 }, { "qfg1vga", GID_QFG1VGA }, { "qfg2", GID_QFG2 }, { "qfg3", GID_QFG3 }, { "qfg4", GID_QFG4 }, + { "qfg4demo", GID_QFG4DEMO }, { "rama", GID_RAMA }, { "sci-fanmade", GID_FANMADE }, // FIXME: Do we really need/want this? { "shivers", GID_SHIVERS }, @@ -356,7 +362,7 @@ Common::String convertSierraGameId(Common::String sierraId, uint32 *gameFlags, R // qfg4 demo has less than 50 scripts if (resources.size() < 50) - return "qfg4"; + return "qfg4demo"; // Otherwise it's qfg3 return "qfg3"; @@ -473,7 +479,7 @@ static char s_fallbackGameIdBuf[256]; class SciMetaEngine : public AdvancedMetaEngine { public: SciMetaEngine() : AdvancedMetaEngine(Sci::SciGameDescriptions, sizeof(ADGameDescription), s_sciGameTitles, optionsList) { - _singleid = "sci"; + _singleId = "sci"; } virtual const char *getName() const { @@ -526,8 +532,8 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, s_fallbackDesc.language = Common::EN_ANY; s_fallbackDesc.flags = ADGF_NO_FLAGS; s_fallbackDesc.platform = Common::kPlatformDOS; // default to PC platform - s_fallbackDesc.gameid = "sci"; - s_fallbackDesc.guioptions = GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI); + s_fallbackDesc.gameId = "sci"; + s_fallbackDesc.guiOptions = GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI); if (allFiles.contains("resource.map") || allFiles.contains("Data1") || allFiles.contains("resmap.001") || allFiles.contains("resmap.001")) { @@ -578,7 +584,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, ResourceManager resMan; resMan.addAppropriateSourcesForDetection(fslist); - resMan.initForDetection(); + resMan.init(); // TODO: Add error handling. #ifndef ENABLE_SCI32 @@ -610,7 +616,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, Common::String gameId = convertSierraGameId(sierraGameId, &s_fallbackDesc.flags, resMan); strncpy(s_fallbackGameIdBuf, gameId.c_str(), sizeof(s_fallbackGameIdBuf) - 1); s_fallbackGameIdBuf[sizeof(s_fallbackGameIdBuf) - 1] = 0; // Make sure string is NULL terminated - s_fallbackDesc.gameid = s_fallbackGameIdBuf; + s_fallbackDesc.gameId = s_fallbackGameIdBuf; // Try to determine the game language // Load up text 0 and start looking for "#" characters @@ -653,7 +659,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, const bool isCD = (s_fallbackDesc.flags & ADGF_CD); if (!isCD) - s_fallbackDesc.guioptions = GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI); + s_fallbackDesc.guiOptions = GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI); if (gameId.hasSuffix("sci")) { s_fallbackDesc.extra = "SCI"; @@ -686,7 +692,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, bool SciMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { const GameIdStrToEnum *g = s_gameIdStrToEnum; for (; g->gameidStr; ++g) { - if (0 == strcmp(desc->gameid, g->gameidStr)) { + if (0 == strcmp(desc->gameId, g->gameidStr)) { *engine = new SciEngine(syst, desc, g->gameidEnum); return true; } @@ -727,7 +733,6 @@ SaveStateList SciMetaEngine::listSaves(const char *target) const { pattern += ".###"; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; int slotNr = 0; @@ -760,6 +765,8 @@ SaveStateList SciMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index 25623215ed..968eb784b1 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -684,21 +684,23 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, - // Gabriel Knight - English DOS CD Demo + // Gabriel Knight - English DOS Demo // SCI interpreter version 1.001.092 - {"gk1", "CD Demo", { + // Note: we are not using ADGF_DEMO here, to avoid a game ID like gk1demo-demo + {"gk1demo", "Demo", { {"resource.map", 0, "39645952ae0ed8072c7e838f31b75464", 2490}, {"resource.000", 0, "eb3ed7477ca4110813fe1fcf35928561", 1718450}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformDOS, 0, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, - // Gabriel Knight - English DOS CD Demo (from DrMcCoy) + // Gabriel Knight - English DOS Demo (from DrMcCoy) // SCI interpreter version 1.001.092 - {"gk1", "CD Demo", { + // Note: we are not using ADGF_DEMO here, to avoid a game ID like gk1demo-demo + {"gk1demo", "Demo", { {"resource.map", 0, "8cad2a256f41463030cbb7ea1bfb2857", 2490}, {"resource.000", 0, "eb3ed7477ca4110813fe1fcf35928561", 1718450}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformDOS, 0, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, #ifdef ENABLE_SCI32 // Gabriel Knight - English DOS Floppy @@ -941,6 +943,15 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Hoyle 2 - English DOS (supplied by m_kiewitz) + // SCI interpreter version 0.000.668, Ver 1.000.014, 2x5.25" + {"hoyle2", "", { + {"resource.map", 0, "8cef06c93d17d96f44aacd5902d84b30", 2100}, + {"resource.001", 0, "8f2dd70abe01112eca464cda818b5eb6", 98289}, + {"resource.002", 0, "8f2dd70abe01112eca464cda818b5eb6", 197326}, + AD_LISTEND}, + Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Hoyle 2 - English DOS (supplied by misterhands in bug report #6598) // Game v1.000.016, interpreter 0.000.668, INT #12.5.90 {"hoyle2", "", { @@ -1531,13 +1542,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.000", 0, "71afd220d46bde1109c58e6acc0f3a01", 469094}, {"resource.001", 0, "72a569f46f1abf2d9d2b1526ad3799c3", 12808839}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformFMTowns, 0, GUIO2(GUIO_NOASPECT, GUIO_MIDITOWNS) }, - {"kq5", "", { - {"resource.map", 0, "20c7cd248ff1a349ed354568eebd972b", 12733}, - {"resource.000", 0, "71afd220d46bde1109c58e6acc0f3a01", 469094}, - {"resource.001", 0, "72a569f46f1abf2d9d2b1526ad3799c3", 12808839}, - AD_LISTEND}, - Common::JA_JPN, Common::kPlatformFMTowns, 0, GUIO2(GUIO_NOASPECT, GUIO_MIDITOWNS) }, + Common::JA_JPN, Common::kPlatformFMTowns, ADGF_ADDENGLISH, GUIO3(GUIO_NOASPECT, GAMEOPTION_ORIGINAL_SAVELOAD, GUIO_MIDITOWNS) }, // King's Quest 5 - Japanese PC-98 Floppy 0.000.015 (supplied by omer_mor in bug report #3073583) {"kq5", "", { @@ -1646,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", "", { @@ -1662,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", "", { @@ -1678,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", "", { @@ -2286,6 +2302,14 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Larry 6 - French DOS Floppy - LOWRES (provided by theco33) + // SCI interpreter version 1.001.113 + {"lsl6", "", { + {"resource.map", 0, "1e07144d3b06a3269236880170978acb", 6943}, + {"resource.000", 0, "7884a8db9253e29e6b37a2651fd90ba3", 5749882}, + AD_LISTEND}, + Common::FR_FRA, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Larry 6 - English/German/French DOS CD - LOWRES // SCI interpreter version 1.001.115 {"lsl6", "", { @@ -2593,12 +2617,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "b11e971ccd2040bebba59dfb409a08ef", 5772}, {"resource.001", 0, "d49625d9b8005ec01c852f8322a82867", 4330713}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformFMTowns, 0, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, - {"mothergoose256", "", { - {"resource.map", 0, "b11e971ccd2040bebba59dfb409a08ef", 5772}, - {"resource.001", 0, "d49625d9b8005ec01c852f8322a82867", 4330713}, - AD_LISTEND}, - Common::JA_JPN, Common::kPlatformFMTowns, 0, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::JA_JPN, Common::kPlatformFMTowns, ADGF_ADDENGLISH, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, #ifdef ENABLE_SCI32 // Mixed-Up Mother Goose Deluxe - English Windows/DOS CD (supplied by markcoolio in bug report #2723810) @@ -2627,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", "", { @@ -2875,6 +2916,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, // Police Quest 2 - Japanese PC-98 (also includes english language) + // Executable scanning reports "x.yyy.zzz" // SCI interpreter version unknown {"pq2", "", { {"resource.map", 0, "883804c616dca1d82373bf9fda3a71d2", 4656}, @@ -2882,7 +2924,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "05fdee43a228dd6ea4d1a92ccae3f788", 637662}, {"resource.003", 0, "05fdee43a228dd6ea4d1a92ccae3f788", 684395}, AD_LISTEND}, - Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO6(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, // Police Quest 3 - English Amiga // Executable scanning reports "1.004.024" @@ -2969,11 +3011,12 @@ static const struct ADGameDescription SciGameDescriptions[] = { // Police Quest 4 - English DOS Non-Interactive Demo (from FRG) // SCI interpreter version 1.001.096 - {"pq4", "Demo", { + // Note: we are not using ADGF_DEMO here, to avoid a game ID like pq4demo-demo + {"pq4demo", "Demo", { {"resource.map", 0, "be56f87a1c4a13062a30a362df860c2f", 1472}, {"resource.000", 0, "527d5684016e6816157cd15d9071b11b", 1121310}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, #ifdef ENABLE_SCI32 // Police Quest 4 - English DOS CD (from the Police Quest Collection) @@ -3381,11 +3424,12 @@ static const struct ADGameDescription SciGameDescriptions[] = { // Quest for Glory 4 - English DOS Non-Interactive Demo (from FRG) // SCI interpreter version 1.001.069 (just a guess) - {"qfg4", "Demo", { + // Note: we are not using ADGF_DEMO here, to avoid a game ID like qfg4demo-demo + {"qfg4demo", "Demo", { {"resource.map", 0, "1ba7c7ae1efb315326d45cb931569b1b", 922}, {"resource.000", 0, "41ba03f0b188b029132daa3ece0d3e14", 623154}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, #ifdef ENABLE_SCI32 // Quest for Glory 4 1.1 Floppy - English DOS (supplied by markcool in bug report #2723852) diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 0df4701334..796dea2382 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -853,7 +853,7 @@ void Kernel::loadKernelNames(GameFeatures *features) { _kernelNames[0x26] = "Portrait"; else if (g_sci->getPlatform() == Common::kPlatformMacintosh) _kernelNames[0x84] = "ShowMovie"; - } else if (g_sci->getGameId() == GID_QFG4 && g_sci->isDemo()) { + } else if (g_sci->getGameId() == GID_QFG4DEMO) { _kernelNames[0x7b] = "RemapColors"; // QFG4 Demo has this SCI2 function instead of StrSplit } diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index f62c43840f..62566a74b2 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -75,6 +75,10 @@ struct SciWorkaroundEntry; // from workarounds.h * vocab.997. This results in much more readable code. Thus, this vocabulary isn't * used at all. * + * 993.voc (unneeded) - Contains the SCI3 equivalent of vocab.994; like its predecessor, + * the raw selector numbers can be deduced and used instead. In fact, one version of this + * file has turned out to cover all versiona of SCI3. + * * SCI0 parser vocabularies: * - vocab.901 / 901.voc - suffix vocabulary * - vocab.900 / 900.voc - parse tree branches @@ -408,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); @@ -441,24 +445,54 @@ reg_t kStringLower(EngineState *s, int argc, reg_t *argv); reg_t kStringTrn(EngineState *s, int argc, reg_t *argv); reg_t kStringTrnExclude(EngineState *s, int argc, reg_t *argv); +reg_t kScrollWindowCreate(EngineState *s, int argc, reg_t *argv); +reg_t kScrollWindowAdd(EngineState *s, int argc, reg_t *argv); +reg_t kScrollWindowWhere(EngineState *s, int argc, reg_t *argv); +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 kCantBeHere32(EngineState *s, int argc, reg_t *argv); -reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv); -// "Screen items" in SCI32 are views + +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); reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv); -// Text + reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv); -reg_t kDisposeTextBitmap(EngineState *s, int argc, reg_t *argv); -// "Planes" in SCI32 are pictures +reg_t kBitmap(EngineState *s, int argc, reg_t *argv); +reg_t kBitmapCreate(EngineState *s, int argc, reg_t *argv); +reg_t kBitmapDestroy(EngineState *s, int argc, reg_t *argv); +reg_t kBitmapDrawLine(EngineState *s, int argc, reg_t *argv); +reg_t kBitmapDrawView(EngineState *s, int argc, reg_t *argv); +reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv); +reg_t kBitmapDrawColor(EngineState *s, int argc, reg_t *argv); +reg_t kBitmapDrawBitmap(EngineState *s, int argc, reg_t *argv); +reg_t kBitmapInvert(EngineState *s, int argc, reg_t *argv); +reg_t kBitmapSetDisplace(EngineState *s, int argc, reg_t *argv); +reg_t kBitmapCreateFromView(EngineState *s, int argc, reg_t *argv); +reg_t kBitmapCopyPixels(EngineState *s, int argc, reg_t *argv); +reg_t kBitmapClone(EngineState *s, int argc, reg_t *argv); +reg_t kBitmapGetInfo(EngineState *s, int argc, reg_t *argv); +reg_t kBitmapScale(EngineState *s, int argc, reg_t *argv); +reg_t kBitmapCreateFromUnknown(EngineState *s, int argc, reg_t *argv); + reg_t kAddPlane(EngineState *s, int argc, reg_t *argv); reg_t kDeletePlane(EngineState *s, int argc, reg_t *argv); reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv); +reg_t kMovePlaneItems(EngineState *s, int argc, reg_t *argv); 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); @@ -473,6 +507,7 @@ reg_t kEditText(EngineState *s, int argc, reg_t *argv); reg_t kMakeSaveCatName(EngineState *s, int argc, reg_t *argv); reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv); reg_t kSetScroll(EngineState *s, int argc, reg_t *argv); + reg_t kPalCycle(EngineState *s, int argc, reg_t *argv); reg_t kPaletteSetFade(EngineState *s, int argc, reg_t *argv); reg_t kPalVarySetVary(EngineState *s, int argc, reg_t *argv); @@ -488,6 +523,8 @@ reg_t kPalVaryMergeStart(EngineState *s, int argc, reg_t *argv); // SCI2.1 Kernel Functions reg_t kMorphOn(EngineState *s, int argc, reg_t *argv); reg_t kText(EngineState *s, int argc, reg_t *argv); +reg_t kTextSize32(EngineState *s, int argc, reg_t *argv); +reg_t kTextWidth(EngineState *s, int argc, reg_t *argv); reg_t kSave(EngineState *s, int argc, reg_t *argv); reg_t kAutoSave(EngineState *s, int argc, reg_t *argv); reg_t kList(EngineState *s, int argc, reg_t *argv); @@ -505,9 +542,9 @@ reg_t kGetSierraProfileInt(EngineState *s, int argc, reg_t *argv); reg_t kCelInfo(EngineState *s, int argc, reg_t *argv); reg_t kSetLanguage(EngineState *s, int argc, reg_t *argv); reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv); +reg_t kSetFontHeight(EngineState *s, int argc, reg_t *argv); reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv); reg_t kFont(EngineState *s, int argc, reg_t *argv); -reg_t kBitmap(EngineState *s, int argc, reg_t *argv); reg_t kAddLine(EngineState *s, int argc, reg_t *argv); reg_t kUpdateLine(EngineState *s, int argc, reg_t *argv); reg_t kDeleteLine(EngineState *s, int argc, reg_t *argv); diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index fce3230a18..3463d05e77 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -60,14 +60,19 @@ struct SciKernelMapSubEntry { #define SCI_SUBOPENTRY_TERMINATOR { SCI_VERSION_NONE, SCI_VERSION_NONE, 0, NULL, NULL, NULL, NULL } -#define SIG_SCIALL SCI_VERSION_NONE, SCI_VERSION_NONE -#define SIG_SCI0 SCI_VERSION_NONE, SCI_VERSION_01 -#define SIG_SCI1 SCI_VERSION_1_EGA_ONLY, SCI_VERSION_1_LATE -#define SIG_SCI11 SCI_VERSION_1_1, SCI_VERSION_1_1 -#define SIG_SINCE_SCI11 SCI_VERSION_1_1, SCI_VERSION_NONE -#define SIG_SINCE_SCI21 SCI_VERSION_2_1_EARLY, SCI_VERSION_3 -#define SIG_UNTIL_SCI21MID SCI_VERSION_2, SCI_VERSION_2_1_MIDDLE -#define SIG_SINCE_SCI21LATE SCI_VERSION_2_1_LATE, SCI_VERSION_3 +#define SIG_SCIALL SCI_VERSION_NONE, SCI_VERSION_NONE +#define SIG_SCI0 SCI_VERSION_NONE, SCI_VERSION_01 +#define SIG_SCI1 SCI_VERSION_1_EGA_ONLY, SCI_VERSION_1_LATE +#define SIG_SCI11 SCI_VERSION_1_1, SCI_VERSION_1_1 +#define SIG_SINCE_SCI11 SCI_VERSION_1_1, SCI_VERSION_NONE +#define SIG_SCI2 SCI_VERSION_2, SCI_VERSION_2 +#define SIG_SCI21EARLY SCI_VERSION_2_1_EARLY, SCI_VERSION_2_1_EARLY +#define SIG_UNTIL_SCI21EARLY SCI_VERSION_2, SCI_VERSION_2_1_EARLY +#define SIG_UNTIL_SCI21MID SCI_VERSION_2, SCI_VERSION_2_1_MIDDLE +#define SIG_SINCE_SCI21 SCI_VERSION_2_1_EARLY, SCI_VERSION_3 +#define SIG_SINCE_SCI21MID SCI_VERSION_2_1_MIDDLE, SCI_VERSION_3 +#define SIG_SINCE_SCI21LATE SCI_VERSION_2_1_LATE, SCI_VERSION_3 +#define SIG_SCI3 SCI_VERSION_3, SCI_VERSION_3 #define SIG_SCI16 SCI_VERSION_NONE, SCI_VERSION_1_1 #define SIG_SCI32 SCI_VERSION_2, SCI_VERSION_NONE @@ -210,7 +215,7 @@ static const SciKernelMapSubEntry kPalVary_subops[] = { { SIG_SCI16, 6, MAP_CALL(PalVaryPauseResume), "i", NULL }, #ifdef ENABLE_SCI32 { SIG_SCI32, 0, MAP_CALL(PalVarySetVary), "i(i)(i)(ii)", NULL }, - { SIG_SCI32, 1, MAP_CALL(PalVarySetPercent), "(i)(i)", NULL }, + { SIG_SCI32, 1, MAP_CALL(PalVarySetPercent), "(i)(i)", kPalVarySetPercent_workarounds }, { SIG_SCI32, 2, MAP_CALL(PalVaryGetPercent), "", NULL }, { SIG_SCI32, 3, MAP_CALL(PalVaryOff), "", NULL }, { SIG_SCI32, 4, MAP_CALL(PalVaryMergeTarget), "i", NULL }, @@ -283,6 +288,42 @@ static const SciKernelMapSubEntry kSave_subops[] = { }; // version, subId, function-mapping, signature, workarounds +static const SciKernelMapSubEntry kFont_subops[] = { + { SIG_SINCE_SCI21MID, 0, MAP_CALL(SetFontHeight), "i", NULL }, + { SIG_SINCE_SCI21MID, 1, MAP_CALL(SetFontRes), "ii", NULL }, + SCI_SUBOPENTRY_TERMINATOR +}; + +// version, subId, function-mapping, signature, workarounds +static const SciKernelMapSubEntry kText_subops[] = { + { SIG_SINCE_SCI21MID, 0, MAP_CALL(TextSize32), "r[r0]i(i)(i)", NULL }, + { SIG_SINCE_SCI21MID, 1, MAP_CALL(TextWidth), "ri", NULL }, + SCI_SUBOPENTRY_TERMINATOR +}; + +// version, subId, function-mapping, signature, workarounds +static const SciKernelMapSubEntry kBitmap_subops[] = { + { SIG_SINCE_SCI21, 0, MAP_CALL(BitmapCreate), "iiii(i)(i)(i)", NULL }, + { SIG_SINCE_SCI21, 1, MAP_CALL(BitmapDestroy), "r", NULL }, + { SIG_SINCE_SCI21, 2, MAP_CALL(BitmapDrawLine), "riiiii(i)(i)", NULL }, + { SIG_SINCE_SCI21, 3, MAP_CALL(BitmapDrawView), "riii(i)(i)(0)(i)(i)", NULL }, + { SIG_SINCE_SCI21, 4, MAP_CALL(BitmapDrawText), "rriiiiiiiiiii", NULL }, + { SIG_SINCE_SCI21, 5, MAP_CALL(BitmapDrawColor), "riiiii", NULL }, + { SIG_SINCE_SCI21, 6, MAP_CALL(BitmapDrawBitmap), "rr(i)(i)(i)", NULL }, + { SIG_SINCE_SCI21, 7, MAP_CALL(BitmapInvert), "riiiiii", NULL }, + { SIG_SINCE_SCI21MID, 8, MAP_CALL(BitmapSetDisplace), "rii", NULL }, + { SIG_SINCE_SCI21MID, 9, MAP_CALL(BitmapCreateFromView), "iii(i)(i)(i)([r0])", NULL }, + { SIG_SINCE_SCI21MID, 10, MAP_CALL(BitmapCopyPixels), "rr", NULL }, + { SIG_SINCE_SCI21MID, 11, MAP_CALL(BitmapClone), "r", NULL }, + { SIG_SINCE_SCI21LATE, 12, MAP_CALL(BitmapGetInfo), "r(i)(i)", NULL }, + { SIG_SINCE_SCI21LATE, 13, MAP_CALL(BitmapScale), "r...ii", NULL }, + { SIG_SCI3, 14, MAP_CALL(BitmapCreateFromUnknown), "......", NULL }, + { SIG_SCI3, 15, MAP_EMPTY(Bitmap), "(.*)", NULL }, + { SIG_SCI3, 16, MAP_EMPTY(Bitmap), "(.*)", NULL }, + SCI_SUBOPENTRY_TERMINATOR +}; + +// version, subId, function-mapping, signature, workarounds static const SciKernelMapSubEntry kList_subops[] = { { SIG_SINCE_SCI21, 0, MAP_CALL(NewList), "", NULL }, { SIG_SINCE_SCI21, 1, MAP_CALL(DisposeList), "l", NULL }, @@ -311,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 }, @@ -352,6 +404,31 @@ static const SciKernelMapSubEntry kString_subops[] = { SCI_SUBOPENTRY_TERMINATOR }; +// version, subId, function-mapping, signature, workarounds +static const SciKernelMapSubEntry kScrollWindow_subops[] = { + { SIG_SCI32, 0, MAP_CALL(ScrollWindowCreate), "oi", NULL }, + { SIG_SCI32, 1, MAP_CALL(ScrollWindowAdd), "o.ii.(.)", NULL }, + { SIG_SCI32, 2, MAP_DUMMY(ScrollWindowClear), "o", NULL }, + { SIG_SCI32, 3, MAP_DUMMY(ScrollWindowPageUp), "o", NULL }, + { SIG_SCI32, 4, MAP_DUMMY(ScrollWindowPageDown), "o", NULL }, + { SIG_SCI32, 5, MAP_DUMMY(ScrollWindowUpArrow), "o", NULL }, + { SIG_SCI32, 6, MAP_DUMMY(ScrollWindowDownArrow), "o", NULL }, + { SIG_SCI32, 7, MAP_DUMMY(ScrollWindowHome), "o", NULL }, + { SIG_SCI32, 8, MAP_DUMMY(ScrollWindowEnd), "o", NULL }, + { SIG_SCI32, 9, MAP_DUMMY(ScrollWindowResize), "o.", NULL }, + { SIG_SCI32, 10, MAP_CALL(ScrollWindowWhere), "oi", NULL }, + { SIG_SCI32, 11, MAP_DUMMY(ScrollWindowGo), "o..", NULL }, + { SIG_SCI32, 12, MAP_DUMMY(ScrollWindowInsert), "o.....", NULL }, + { SIG_SCI32, 13, MAP_DUMMY(ScrollWindowDelete), "o.", NULL }, + { SIG_SCI32, 14, MAP_DUMMY(ScrollWindowModify), "o.....(.)", NULL }, + { SIG_SCI32, 15, MAP_DUMMY(ScrollWindowHide), "o", NULL }, + { SIG_SCI32, 16, MAP_CALL(ScrollWindowShow), "o", NULL }, + { SIG_SCI32, 17, MAP_CALL(ScrollWindowDestroy), "o", NULL }, + { SIG_SCI32, 18, MAP_DUMMY(ScrollWindowText), "o", NULL }, + { SIG_SCI32, 19, MAP_DUMMY(ScrollWindowReconstruct), "o.", NULL }, + SCI_SUBOPENTRY_TERMINATOR +}; + #endif struct SciKernelMapEntry { @@ -380,12 +457,16 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(AvoidPath), SIG_EVERYWHERE, "ii(.*)", NULL, NULL }, { MAP_CALL(BaseSetter), SIG_EVERYWHERE, "o", NULL, NULL }, { MAP_CALL(CanBeHere), SIG_EVERYWHERE, "o(l)", NULL, NULL }, + { MAP_CALL(CantBeHere), SIG_SCI16, SIGFOR_ALL, "o(l)", NULL, NULL }, #ifdef ENABLE_SCI32 - { "CantBeHere", kCantBeHere32, SIG_SCI32, SIGFOR_ALL, "ol", NULL, NULL }, + { MAP_CALL(CantBeHere), SIG_SCI32, SIGFOR_ALL, "ol", NULL, NULL }, +#endif + { 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(CantBeHere), SIG_EVERYWHERE, "o(l)", NULL, NULL }, - { MAP_CALL(CelHigh), SIG_EVERYWHERE, "ii(i)", NULL, kCelHigh_workarounds }, - { MAP_CALL(CelWide), SIG_EVERYWHERE, "ii(i)", NULL, kCelWide_workarounds }, { 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 }, @@ -484,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 }, @@ -502,7 +583,10 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(SetDebug), SIG_EVERYWHERE, "(i*)", NULL, NULL }, { MAP_CALL(SetJump), SIG_EVERYWHERE, "oiii", NULL, NULL }, { MAP_CALL(SetMenu), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, - { MAP_CALL(SetNowSeen), SIG_EVERYWHERE, "o(i)", NULL, NULL }, + { MAP_CALL(SetNowSeen), SIG_SCI16, SIGFOR_ALL, "o(i)", NULL, NULL }, +#ifdef ENABLE_SCI32 + { MAP_CALL(SetNowSeen), SIG_SCI32, SIGFOR_ALL, "o", NULL, NULL }, +#endif { MAP_CALL(SetPort), SIG_EVERYWHERE, "i(iiiii)(i)", NULL, kSetPort_workarounds }, { MAP_CALL(SetQuitStr), SIG_EVERYWHERE, "r", NULL, NULL }, { MAP_CALL(SetSynonyms), SIG_EVERYWHERE, "o", NULL, NULL }, @@ -520,10 +604,10 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(StrEnd), SIG_EVERYWHERE, "r", NULL, NULL }, { MAP_CALL(StrLen), SIG_EVERYWHERE, "[r0]", NULL, kStrLen_workarounds }, { MAP_CALL(StrSplit), SIG_EVERYWHERE, "rr[r0]", NULL, NULL }, - { MAP_CALL(TextColors), SIG_EVERYWHERE, "(i*)", NULL, NULL }, - { MAP_CALL(TextFonts), SIG_EVERYWHERE, "(i*)", NULL, NULL }, - { MAP_CALL(TextSize), SIG_SCIALL, SIGFOR_MAC, "r[r0]i(i)(r0)(i)", NULL, NULL }, - { MAP_CALL(TextSize), SIG_EVERYWHERE, "r[r0]i(i)(r0)", NULL, NULL }, + { MAP_CALL(TextColors), SIG_SCI16, SIGFOR_ALL, "(i*)", NULL, NULL }, + { MAP_CALL(TextFonts), SIG_SCI16, SIGFOR_ALL, "(i*)", NULL, NULL }, + { MAP_CALL(TextSize), SIG_SCI16, SIGFOR_MAC, "r[r0]i(i)(r0)(i)", NULL, NULL }, + { MAP_CALL(TextSize), SIG_SCI16, SIGFOR_ALL, "r[r0]i(i)(r0)", NULL, NULL }, { MAP_CALL(TimesCos), SIG_EVERYWHERE, "ii", NULL, NULL }, { "CosMult", kTimesCos, SIG_EVERYWHERE, "ii", NULL, NULL }, { MAP_CALL(TimesCot), SIG_EVERYWHERE, "ii", NULL, NULL }, @@ -555,14 +639,18 @@ static SciKernelMapEntry s_kernelMap[] = { #ifdef ENABLE_SCI32 // SCI2 Kernel Functions // TODO: whoever knows his way through those calls, fix the signatures. + { "TextSize", kTextSize32, SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "r[r0]i(i)", NULL, NULL }, + { MAP_DUMMY(TextColors), SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "(.*)", NULL, NULL }, + { MAP_DUMMY(TextFonts), SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "(.*)", NULL, NULL }, + { MAP_CALL(AddPlane), SIG_EVERYWHERE, "o", NULL, NULL }, { MAP_CALL(AddScreenItem), SIG_EVERYWHERE, "o", NULL, NULL }, { MAP_CALL(Array), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(CreateTextBitmap), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, { MAP_CALL(DeletePlane), SIG_EVERYWHERE, "o", NULL, NULL }, { MAP_CALL(DeleteScreenItem), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(DisposeTextBitmap), SIG_EVERYWHERE, "r", NULL, NULL }, - { MAP_CALL(FrameOut), SIG_EVERYWHERE, "", NULL, NULL }, + { "DisposeTextBitmap", kBitmapDestroy, SIG_SCI2, SIGFOR_ALL, "r", NULL, NULL }, + { MAP_CALL(FrameOut), SIG_EVERYWHERE, "(i)", NULL, NULL }, { MAP_CALL(GetHighPlanePri), SIG_EVERYWHERE, "", NULL, NULL }, { MAP_CALL(InPolygon), SIG_EVERYWHERE, "iio", NULL, NULL }, { MAP_CALL(IsHiRes), SIG_EVERYWHERE, "", NULL, NULL }, @@ -623,9 +711,9 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_DUMMY(MarkMemory), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(GetHighItemPri), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(ShowStylePercent), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_DUMMY(InvertRect), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(InvertRect), SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "(.*)", NULL, NULL }, { MAP_DUMMY(InputText), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_DUMMY(TextWidth), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(TextWidth), SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "ri", NULL, NULL }, { MAP_DUMMY(PointSize), SIG_EVERYWHERE, "(.*)", NULL, NULL }, // SCI2.1 Kernel Functions @@ -636,18 +724,18 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(Save), SIG_EVERYWHERE, "i(.*)", kSave_subops, NULL }, - { MAP_CALL(Text), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(Text), SIG_SINCE_SCI21MID, SIGFOR_ALL, "i(.*)", kText_subops, NULL }, { MAP_CALL(AddPicAt), SIG_EVERYWHERE, "oiii", NULL, NULL }, { MAP_CALL(GetWindowsOption), SIG_EVERYWHERE, "i", NULL, NULL }, { 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(ScrollWindow), SIG_EVERYWHERE, "io(.*)", NULL, NULL }, - { MAP_CALL(SetFontRes), SIG_EVERYWHERE, "ii", NULL, NULL }, - { MAP_CALL(Font), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, - { MAP_CALL(Bitmap), SIG_EVERYWHERE, "(.*)", 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 }, + { MAP_CALL(Bitmap), SIG_EVERYWHERE, "(.*)", kBitmap_subops, NULL }, { MAP_CALL(AddLine), SIG_EVERYWHERE, "oiiiiiiiii", NULL, NULL }, { MAP_CALL(UpdateLine), SIG_EVERYWHERE, "[r0]oiiiiiiiii", NULL, NULL }, { MAP_CALL(DeleteLine), SIG_EVERYWHERE, "[r0]o", NULL, NULL }, @@ -699,9 +787,9 @@ static SciKernelMapEntry s_kernelMap[] = { // <lskovlun> The idea, if I understand correctly, is that the engine generates events // of a special HotRect type continuously when the mouse is on that rectangle - // MovePlaneItems - used by SQ6 to scroll through the inventory via the up/down buttons - // SetPalStyleRange - 2 integer parameters, start and end. All styles from start-end - // (inclusive) are set to 0 + // Used by SQ6 to scroll through the inventory via the up/down buttons + { MAP_CALL(MovePlaneItems), SIG_SINCE_SCI21, SIGFOR_ALL, "oii(i)", NULL, NULL }, + { MAP_CALL(SetPalStyleRange), SIG_EVERYWHERE, "ii", NULL, NULL }, { MAP_CALL(MorphOn), SIG_EVERYWHERE, "", NULL, NULL }, @@ -1004,7 +1092,6 @@ static const char *const sci2_default_knames[] = { /*0x89*/ "TextWidth", // for debugging(?), only in SCI2, not used in any SCI2 game /*0x8a*/ "PointSize", // for debugging(?), only in SCI2, not used in any SCI2 game - // GK2 Demo (and similar) only kernel functions /*0x8b*/ "AddLine", /*0x8c*/ "DeleteLine", /*0x8d*/ "UpdateLine", diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp index bb595e9960..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(); @@ -101,7 +102,25 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) { // question. Check GfxCursor::setPosition(), for a more detailed // explanation and a list of cursor position workarounds. if (s->_cursorWorkaroundRect.contains(mousePos.x, mousePos.y)) { - s->_cursorWorkaroundActive = false; + // For OpenPandora and possibly other platforms, that support analog-stick control + touch screen + // control at the same time: in case the cursor is currently at the coordinate set by the scripts, + // we will count down instead of immediately disabling the workaround. + // On OpenPandora the cursor position is set, but it's overwritten shortly afterwards by the + // touch screen. In this case we would sometimes disable the workaround, simply because the touch + // screen hasn't yet overwritten the position and thus the workaround would not work anymore. + // On OpenPandora it would sometimes work and sometimes not without this. + if (s->_cursorWorkaroundPoint == mousePos) { + // Cursor is still at the same spot as set by the scripts + if (s->_cursorWorkaroundPosCount > 0) { + s->_cursorWorkaroundPosCount--; + } else { + // Was for quite a bit of time at that spot, so disable workaround now + s->_cursorWorkaroundActive = false; + } + } else { + // Cursor has moved, but is within the rect -> disable workaround immediately + s->_cursorWorkaroundActive = false; + } } else { mousePos.x = s->_cursorWorkaroundPoint.x; mousePos.y = s->_cursorWorkaroundPoint.y; diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index 979fa95a42..335763a35f 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -37,7 +37,6 @@ #include "sci/engine/state.h" #include "sci/engine/kernel.h" #include "sci/engine/savegame.h" -#include "sci/graphics/menu.h" #include "sci/sound/audio.h" #include "sci/console.h" @@ -602,6 +601,16 @@ reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) { bool exists = false; + if (g_sci->getGameId() == GID_PEPPER) { + // HACK: Special case for Pepper's Adventure in Time + // The game checks like crazy for the file CDAUDIO when entering the game menu. + // On at least Windows that makes the engine slow down to a crawl and takes at least 1 second. + // Should get solved properly by changing the code below. This here is basically for 1.8.0 release. + // TODO: Fix this properly. + if (name == "CDAUDIO") + return NULL_REG; + } + // Check for regular file exists = Common::File::exists(name); @@ -907,50 +916,8 @@ reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) { gamestate_restore(s, in); delete in; - switch (g_sci->getGameId()) { - case GID_MOTHERGOOSE: - // WORKAROUND: Mother Goose SCI0 - // Script 200 / rm200::newRoom will set global C5h directly right after creating a child to the - // current number of children plus 1. - // We can't trust that global, that's why we set the actual savedgame id right here directly after - // restoring a saved game. - // If we didn't, the game would always save to a new slot - s->variables[VAR_GLOBAL][0xC5].setOffset(SAVEGAMEID_OFFICIALRANGE_START + savegameId); - break; - case GID_MOTHERGOOSE256: - // WORKAROUND: Mother Goose SCI1/SCI1.1 does some weird things for - // saving a previously restored game. - // We set the current savedgame-id directly and remove the script - // code concerning this via script patch. - s->variables[VAR_GLOBAL][0xB3].setOffset(SAVEGAMEID_OFFICIALRANGE_START + savegameId); - break; - case GID_JONES: - // HACK: The code that enables certain menu items isn't called when a game is restored from the - // launcher, or the "Restore game" option in the game's main menu - bugs #6537 and #6723. - // These menu entries are disabled when the game is launched, and are enabled when a new game is - // started. The code for enabling these entries is is all in script 1, room1::init, but that code - // path is never followed in these two cases (restoring game from the menu, or restoring a game - // from the ScummVM launcher). Thus, we perform the calls to enable the menus ourselves here. - // These two are needed when restoring from the launcher - // FIXME: The original interpreter saves and restores the menu state, so these attributes - // are automatically reset there. We may want to do the same. - g_sci->_gfxMenu->kernelSetAttribute(257 >> 8, 257 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Sierra -> About Jones - g_sci->_gfxMenu->kernelSetAttribute(258 >> 8, 258 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Sierra -> Help - // The rest are normally enabled from room1::init - g_sci->_gfxMenu->kernelSetAttribute(769 >> 8, 769 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Options -> Delete current player - g_sci->_gfxMenu->kernelSetAttribute(513 >> 8, 513 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Game -> Save Game - g_sci->_gfxMenu->kernelSetAttribute(515 >> 8, 515 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Game -> Restore Game - 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_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. - g_sci->_gfxMenu->kernelSetAttribute(2, 1, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Game -> Save Game - break; - default: - break; - } + gamestate_afterRestoreFixUp(s, savegameId); + } else { s->r_acc = TRUE_REG; warning("Savegame #%d not found", savegameId); diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index 0b945c1eec..73236b98ed 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.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" @@ -359,12 +360,7 @@ reg_t kTextSize(EngineState *s, int argc, reg_t *argv) { uint16 languageSplitter = 0; Common::String splitText = g_sci->strSplitLanguage(text.c_str(), &languageSplitter, sep); -#ifdef ENABLE_SCI32 - if (g_sci->_gfxText32) - g_sci->_gfxText32->kernelTextSize(splitText.c_str(), font_nr, maxwidth, &textWidth, &textHeight); - else -#endif - g_sci->_gfxText16->kernelTextSize(splitText.c_str(), languageSplitter, font_nr, maxwidth, &textWidth, &textHeight); + g_sci->_gfxText16->kernelTextSize(splitText.c_str(), languageSplitter, font_nr, maxwidth, &textWidth, &textHeight); // One of the game texts in LB2 German contains loads of spaces in // its end. We trim the text here, otherwise the graphics code will @@ -445,8 +441,15 @@ reg_t kCantBeHere(EngineState *s, int argc, reg_t *argv) { reg_t curObject = argv[0]; reg_t listReference = (argc > 1) ? argv[1] : NULL_REG; - reg_t canBeHere = g_sci->_gfxCompare->kernelCanBeHere(curObject, listReference); - return canBeHere; +#ifdef ENABLE_SCI32 + if (getSciVersion() >= SCI_VERSION_2) { + return g_sci->_gfxCompare->kernelCantBeHere32(curObject, listReference); + } else { +#endif + return g_sci->_gfxCompare->kernelCanBeHere(curObject, listReference); +#ifdef ENABLE_SCI32 + } +#endif } reg_t kIsItSkip(EngineState *s, int argc, reg_t *argv) { @@ -492,7 +495,7 @@ reg_t kNumLoops(EngineState *s, int argc, reg_t *argv) { loopCount = g_sci->_gfxCache->kernelViewGetLoopCount(viewId); - debugC(kDebugLevelGraphics, "NumLoops(view.%d) = %d", viewId, loopCount); + debugC(9, kDebugLevelGraphics, "NumLoops(view.%d) = %d", viewId, loopCount); return make_reg(0, loopCount); } @@ -505,7 +508,7 @@ reg_t kNumCels(EngineState *s, int argc, reg_t *argv) { celCount = g_sci->_gfxCache->kernelViewGetCelCount(viewId, loopNo); - debugC(kDebugLevelGraphics, "NumCels(view.%d, %d) = %d", viewId, loopNo, celCount); + debugC(9, kDebugLevelGraphics, "NumCels(view.%d, %d) = %d", viewId, loopNo, celCount); return make_reg(0, celCount); } @@ -576,9 +579,17 @@ reg_t kBaseSetter(EngineState *s, int argc, reg_t *argv) { } reg_t kSetNowSeen(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxCompare->kernelSetNowSeen(argv[0]); - - return s->r_acc; +#ifdef ENABLE_SCI32 + if (getSciVersion() >= SCI_VERSION_2) { + g_sci->_gfxFrameout->kernelSetNowSeen(argv[0]); + return NULL_REG; + } else { +#endif + g_sci->_gfxCompare->kernelSetNowSeen(argv[0]); + return s->r_acc; +#ifdef ENABLE_SCI32 + } +#endif } reg_t kPalette(EngineState *s, int argc, reg_t *argv) { @@ -1247,22 +1258,22 @@ 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) { case 0: { // remap by percent uint16 percent = argv[1].toUint16(); - g_sci->_gfxPalette16->resetRemapping(); - g_sci->_gfxPalette16->setRemappingPercent(254, percent); + g_sci->_gfxRemap16->resetRemapping(); + g_sci->_gfxRemap16->setRemappingPercent(254, percent); } break; case 1: { // remap by range uint16 from = argv[1].toUint16(); uint16 to = argv[2].toUint16(); uint16 base = argv[3].toUint16(); - g_sci->_gfxPalette16->resetRemapping(); - g_sci->_gfxPalette16->setRemappingRange(254, from, to, base); + g_sci->_gfxRemap16->resetRemapping(); + g_sci->_gfxRemap16->setRemappingRange(254, from, to, base); } break; case 2: // turn remapping off (unused) diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp index 8d41393a9e..7850a10006 100644 --- a/engines/sci/engine/kgraphics32.cpp +++ b/engines/sci/engine/kgraphics32.cpp @@ -45,15 +45,17 @@ #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" #ifdef ENABLE_SCI32 -#include "sci/graphics/palette32.h" +#include "sci/graphics/celobj32.h" #include "sci/graphics/controls32.h" #include "sci/graphics/font.h" // TODO: remove once kBitmap is moved in a separate class -#include "sci/graphics/text32.h" #include "sci/graphics/frameout.h" +#include "sci/graphics/palette32.h" +#include "sci/graphics/text32.h" #endif namespace Sci { @@ -62,63 +64,67 @@ namespace Sci { extern void showScummVMDialog(const Common::String &message); reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv) { - // Returns 0 if the screen width or height is less than 640 or 400, - // respectively. - if (g_system->getWidth() < 640 || g_system->getHeight() < 400) + const Buffer &buffer = g_sci->_gfxFrameout->getCurrentBuffer(); + if (buffer.screenWidth < 640 || buffer.screenHeight < 400) return make_reg(0, 0); return make_reg(0, 1); } -// SCI32 variant, can't work like sci16 variants -reg_t kCantBeHere32(EngineState *s, int argc, reg_t *argv) { - // TODO -// reg_t curObject = argv[0]; -// reg_t listReference = (argc > 1) ? argv[1] : NULL_REG; - - return NULL_REG; -} - reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv) { - if (g_sci->_gfxFrameout->findScreenItem(argv[0]) == NULL) - g_sci->_gfxFrameout->kernelAddScreenItem(argv[0]); - else - g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]); + debugC(6, kDebugLevelGraphics, "kAddScreenItem %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0])); + g_sci->_gfxFrameout->kernelAddScreenItem(argv[0]); 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 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 s->r_acc; } reg_t kAddPlane(EngineState *s, int argc, reg_t *argv) { + debugC(6, kDebugLevelGraphics, "kAddPlane %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0])); g_sci->_gfxFrameout->kernelAddPlane(argv[0]); return s->r_acc; } +reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv) { + debugC(7, kDebugLevelGraphics, "kUpdatePlane %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0])); + g_sci->_gfxFrameout->kernelUpdatePlane(argv[0]); + return s->r_acc; +} + reg_t kDeletePlane(EngineState *s, int argc, reg_t *argv) { + debugC(6, kDebugLevelGraphics, "kDeletePlane %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0])); g_sci->_gfxFrameout->kernelDeletePlane(argv[0]); return s->r_acc; } -reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxFrameout->kernelUpdatePlane(argv[0]); +reg_t kMovePlaneItems(EngineState *s, int argc, reg_t *argv) { + const reg_t plane = argv[0]; + const int16 deltaX = argv[1].toSint16(); + const int16 deltaY = argv[2].toSint16(); + const bool scrollPics = argc > 3 ? argv[3].toUint16() : false; + + g_sci->_gfxFrameout->kernelMovePlaneItems(plane, deltaX, deltaY, scrollPics); return s->r_acc; } reg_t kAddPicAt(EngineState *s, int argc, reg_t *argv) { reg_t planeObj = argv[0]; GuiResourceId pictureId = argv[1].toUint16(); - int16 pictureX = argv[2].toSint16(); - int16 pictureY = argv[3].toSint16(); + int16 x = argv[2].toSint16(); + int16 y = argv[3].toSint16(); + bool mirrorX = argc > 4 ? argv[4].toSint16() : false; - g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, pictureX, pictureY); + g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, x, y, mirrorX); return s->r_acc; } @@ -127,44 +133,16 @@ reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv) { } reg_t kFrameOut(EngineState *s, int argc, reg_t *argv) { -/* TODO: Transcribed from SCI engine disassembly. - GraphicsMgr &graphicsMgr = g_sci->_graphicsMgr; - if (graphicsMgr.palMorphNeeded) { - graphicsMgr.PalMorphFrameOut(&g_PalStyleRanges, false); - } - else { - // TODO: Not sure if this is a pointer or not yet. - if (g_ScrollState != nullptr) { - kFrameOutDoScroll(); - } - - bool showBits = true; - if (argc == 1) { - showBits = (bool) argv[0].toUint16(); - } - - rect SOL_Rect = { .left = 0, .top = 0, .right = UINT32_MAX, .bottom = UINT32_MAX }; - graphicsMgr.FrameOut(showBits, &rect); - } -*/ - g_sci->_gfxFrameout->kernelFrameout(); - return NULL_REG; + bool showBits = argc > 0 ? argv[0].toUint16() : true; + g_sci->_gfxFrameout->kernelFrameOut(showBits); + s->speedThrottler(16); + s->_throttleTrigger = true; + return s->r_acc; } reg_t kSetPalStyleRange(EngineState *s, int argc, reg_t *argv) { -/* TODO: Transcribed from SCI engine disassembly. - uint16 start = argv[0].toUint16(); - uint16 end = argv[1].toUint16(); - if (end <= start) { - uint16 index = start; - while (index <= end) { - g_PalStyleRanges[index] = 0; - } - } -*/ - - kStub(s, argc, argv); - return NULL_REG; + g_sci->_gfxFrameout->kernelSetPalStyleRange(argv[0].toUint16(), argv[1].toUint16()); + return s->r_acc; } reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv) { @@ -173,81 +151,92 @@ reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv) { return make_reg(0, objRect1.intersects(objRect2)); } -// Tests if the coordinate is on the passed object reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv) { - uint16 x = argv[0].toUint16(); - uint16 y = argv[1].toUint16(); - reg_t targetObject = argv[2]; - uint16 illegalBits = argv[3].getOffset(); - Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(targetObject); - - uint16 itemX = readSelectorValue(s->_segMan, targetObject, SELECTOR(x)); - uint16 itemY = readSelectorValue(s->_segMan, targetObject, SELECTOR(y)); - // If top and left are negative, we need to adjust coordinates by the item's x and y - if (nsRect.left < 0) - nsRect.translate(itemX, 0); - if (nsRect.top < 0) - nsRect.translate(0, itemY); - - // we assume that x, y are local coordinates - - bool contained = nsRect.contains(x, y); - if (contained && illegalBits) { - // If illegalbits are set, we check the color of the pixel that got clicked on - // for now, we return false if the pixel is transparent - // although illegalBits may get differently set, don't know yet how this really works out - uint16 viewId = readSelectorValue(s->_segMan, targetObject, SELECTOR(view)); - int16 loopNo = readSelectorValue(s->_segMan, targetObject, SELECTOR(loop)); - int16 celNo = readSelectorValue(s->_segMan, targetObject, SELECTOR(cel)); - if (g_sci->_gfxCompare->kernelIsItSkip(viewId, loopNo, celNo, Common::Point(x - nsRect.left, y - nsRect.top))) - contained = false; - } - return make_reg(0, contained); + int16 x = argv[0].toSint16(); + int16 y = argv[1].toSint16(); + reg_t object = argv[2]; + bool checkPixel = argv[3].toSint16(); + + return g_sci->_gfxFrameout->kernelIsOnMe(object, Common::Point(x, y), checkPixel); } reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) { - switch (argv[0].toUint16()) { - case 0: { - if (argc != 4) { - warning("kCreateTextBitmap(0): expected 4 arguments, got %i", argc); - return NULL_REG; - } - reg_t object = argv[3]; - Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text))); - debugC(kDebugLevelStrings, "kCreateTextBitmap case 0 (%04x:%04x, %04x:%04x, %04x:%04x)", - PRINT_REG(argv[1]), PRINT_REG(argv[2]), PRINT_REG(argv[3])); - debugC(kDebugLevelStrings, "%s", text.c_str()); - int16 maxWidth = argv[1].toUint16(); - int16 maxHeight = argv[2].toUint16(); - g_sci->_gfxCoordAdjuster->fromScriptToDisplay(maxHeight, maxWidth); - // These values can be larger than the screen in the SQ6 demo, room 100 - // TODO: Find out why. For now, don't show any text in that room. - if (g_sci->getGameId() == GID_SQ6 && g_sci->isDemo() && s->currentRoomNumber() == 100) - return NULL_REG; - return g_sci->_gfxText32->createTextBitmap(object, maxWidth, maxHeight); - } - case 1: { - if (argc != 2) { - warning("kCreateTextBitmap(1): expected 2 arguments, got %i", argc); - return NULL_REG; - } - reg_t object = argv[1]; - Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text))); - debugC(kDebugLevelStrings, "kCreateTextBitmap case 1 (%04x:%04x)", PRINT_REG(argv[1])); - debugC(kDebugLevelStrings, "%s", text.c_str()); - return g_sci->_gfxText32->createTextBitmap(object); - } - default: - warning("CreateTextBitmap(%d)", argv[0].toUint16()); + SegManager *segMan = s->_segMan; + + int16 subop = argv[0].toUint16(); + + int16 width = 0; + int16 height = 0; + reg_t object; + + if (subop == 0) { + width = argv[1].toUint16(); + height = argv[2].toUint16(); + object = argv[3]; + } else if (subop == 1) { + object = argv[1]; + } else { + warning("Invalid kCreateTextBitmap subop %d", subop); return NULL_REG; } + + Common::String text = segMan->getString(readSelector(segMan, object, SELECTOR(text))); + int16 foreColor = readSelectorValue(segMan, object, SELECTOR(fore)); + int16 backColor = readSelectorValue(segMan, object, SELECTOR(back)); + int16 skipColor = readSelectorValue(segMan, object, SELECTOR(skip)); + GuiResourceId fontId = (GuiResourceId)readSelectorValue(segMan, object, SELECTOR(font)); + int16 borderColor = readSelectorValue(segMan, object, SELECTOR(borderColor)); + int16 dimmed = readSelectorValue(segMan, object, SELECTOR(dimmed)); + + Common::Rect rect( + readSelectorValue(segMan, object, SELECTOR(textLeft)), + readSelectorValue(segMan, object, SELECTOR(textTop)), + readSelectorValue(segMan, object, SELECTOR(textRight)) + 1, + readSelectorValue(segMan, object, SELECTOR(textBottom)) + 1 + ); + + if (subop == 0) { + TextAlign alignment = (TextAlign)readSelectorValue(segMan, object, SELECTOR(mode)); + return g_sci->_gfxText32->createFontBitmap(width, height, rect, text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, true); + } else { + CelInfo32 celInfo; + celInfo.type = kCelTypeView; + celInfo.resourceId = readSelectorValue(segMan, object, SELECTOR(view)); + celInfo.loopNo = readSelectorValue(segMan, object, SELECTOR(loop)); + celInfo.celNo = readSelectorValue(segMan, object, SELECTOR(cel)); + return g_sci->_gfxText32->createFontBitmap(celInfo, rect, text, foreColor, backColor, fontId, skipColor, borderColor, dimmed); + } +} + +reg_t kText(EngineState *s, int argc, reg_t *argv) { + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); } -reg_t kDisposeTextBitmap(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxText32->disposeTextBitmap(argv[0]); +reg_t kTextSize32(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxText32->setFont(argv[2].toUint16()); + + reg_t *rect = s->_segMan->derefRegPtr(argv[0], 4); + + Common::String text = s->_segMan->getString(argv[1]); + int16 maxWidth = argc > 3 ? argv[3].toSint16() : 0; + bool doScaling = argc > 4 ? argv[4].toSint16() : true; + + Common::Rect textRect = g_sci->_gfxText32->getTextSize(text, maxWidth, doScaling); + rect[0] = make_reg(0, textRect.left); + rect[1] = make_reg(0, textRect.top); + rect[2] = make_reg(0, textRect.right - 1); + rect[3] = make_reg(0, textRect.bottom - 1); return s->r_acc; } +reg_t kTextWidth(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxText32->setFont(argv[1].toUint16()); + Common::String text = s->_segMan->getString(argv[0]); + return make_reg(0, g_sci->_gfxText32->getStringWidth(text)); +} + reg_t kWinHelp(EngineState *s, int argc, reg_t *argv) { switch (argv[0].toUint16()) { case 1: @@ -266,98 +255,137 @@ reg_t kWinHelp(EngineState *s, int argc, reg_t *argv) { } /** - * Used for scene transitions, replacing (but reusing parts of) the old - * transition code. + * Causes an immediate plane transition with an optional transition + * effect */ reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) { - // Can be called with 7 or 8 parameters - // The style defines which transition to perform. Related to the transition - // tables inside graphics/transitions.cpp - uint16 showStyle = argv[0].toUint16(); // 0 - 15 - reg_t planeObj = argv[1]; // the affected plane - Common::String planeObjName = s->_segMan->getObjectName(planeObj); - uint16 seconds = argv[2].toUint16(); // seconds that the transition lasts - uint16 backColor = argv[3].toUint16(); // target back color(?). When fading out, it's 0x0000. When fading in, it's 0xffff - int16 priority = argv[4].toSint16(); // always 0xc8 (200) when fading in/out - uint16 animate = argv[5].toUint16(); // boolean, animate or not while the transition lasts - uint16 refFrame = argv[6].toUint16(); // refFrame, always 0 when fading in/out + ShowStyleType type = (ShowStyleType)argv[0].toUint16(); + reg_t planeObj = argv[1]; + int16 seconds = argv[2].toSint16(); + // NOTE: This value seems to indicate whether the transition is an + // “exit†transition (0) or an “enter†transition (-1) for fade + // transitions. For other types of transitions, it indicates a palette + // index value to use when filling the screen. + int16 back = argv[3].toSint16(); + int16 priority = argv[4].toSint16(); + int16 animate = argv[5].toSint16(); + // TODO: Rename to frameOutNow? + int16 refFrame = argv[6].toSint16(); + int16 blackScreen; + reg_t pFadeArray; int16 divisions; - // If the game has the pFadeArray selector, another parameter is used here, - // before the optional last parameter - bool hasFadeArray = g_sci->getKernel()->findSelector("pFadeArray") > 0; - if (hasFadeArray) { - // argv[7] - divisions = (argc >= 9) ? argv[8].toSint16() : -1; // divisions (transition steps?) - } else { - divisions = (argc >= 8) ? argv[7].toSint16() : -1; // divisions (transition steps?) + // SCI 2–2.1early + if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) { + blackScreen = 0; + pFadeArray = NULL_REG; + divisions = argc > 7 ? argv[7].toSint16() : -1; } - - if (showStyle > 15) { - warning("kSetShowStyle: Illegal style %d for plane %04x:%04x", showStyle, PRINT_REG(planeObj)); - return s->r_acc; + // SCI 2.1mid–2.1late + else if (getSciVersion() < SCI_VERSION_3) { + blackScreen = 0; + pFadeArray = argc > 7 ? argv[7] : NULL_REG; + divisions = argc > 8 ? argv[8].toSint16() : -1; + } + // SCI 3 + else { + blackScreen = argv[7].toSint16(); + pFadeArray = argc > 8 ? argv[8] : NULL_REG; + divisions = argc > 9 ? argv[9].toSint16() : -1; } - // GK1 calls fadeout (13) / fadein (14) with the following parameters: - // seconds: 1 - // backColor: 0 / -1 - // fade: 200 - // animate: 0 - // refFrame: 0 - // divisions: 0 / 20 +// TODO: Reuse later for SCI2 and SCI3 implementation and then discard +// warning("kSetShowStyle: effect %d, plane: %04x:%04x (%s), sec: %d, " +// "dir: %d, prio: %d, animate: %d, ref frame: %d, black screen: %d, " +// "pFadeArray: %04x:%04x (%s), divisions: %d", +// type, PRINT_REG(planeObj), s->_segMan->getObjectName(planeObj), seconds, +// back, priority, animate, refFrame, blackScreen, +// PRINT_REG(pFadeArray), s->_segMan->getObjectName(pFadeArray), divisions); - // TODO: Check if the plane is in the list of planes to draw + // NOTE: The order of planeObj and showStyle are reversed + // because this is how SCI3 called the corresponding method + // on the KernelMgr + g_sci->_gfxFrameout->kernelSetShowStyle(argc, planeObj, type, seconds, back, priority, animate, refFrame, pFadeArray, divisions, blackScreen); - Common::String effectName = "unknown"; + return s->r_acc; +} - switch (showStyle) { - case 0: // no transition / show - effectName = "show"; +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 + + 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 13: // fade out - effectName = "fade out"; - // TODO + case 1: + result = view._displace.y; break; - case 14: // fade in - effectName = "fade in"; - // TODO + case 2: + case 3: + // null operation break; - default: - // TODO + case 4: + result = view.readPixel(argv[4].toSint16(), argv[5].toSint16(), view._mirrorX); break; } - warning("kSetShowStyle: effect %d (%s) - plane: %04x:%04x (%s), sec: %d, " - "back: %d, prio: %d, animate: %d, ref frame: %d, divisions: %d", - showStyle, effectName.c_str(), PRINT_REG(planeObj), planeObjName.c_str(), - seconds, backColor, priority, animate, refFrame, divisions); - return s->r_acc; + return make_reg(0, result); } -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 +reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) { + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} - 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; - } - } +reg_t kScrollWindowCreate(EngineState *s, int argc, reg_t *argv) { + debug("kScrollWindowCreate"); + kStub(s, argc, argv); + return argv[0]; +} + +reg_t kScrollWindowAdd(EngineState *s, int argc, reg_t *argv) { + debug("kScrollWindowAdd"); + return kStubNull(s, argc, argv); } +reg_t kScrollWindowWhere(EngineState *s, int argc, reg_t *argv) { + debug("kScrollWindowWhere"); + return kStubNull(s, argc, argv); +} + +reg_t kScrollWindowShow(EngineState *s, int argc, reg_t *argv) { + debug("kScrollWindowShow"); + return kStubNull(s, argc, argv); +} + +reg_t kScrollWindowDestroy(EngineState *s, int argc, reg_t *argv) { + debug("kScrollWindowDestroy"); + return kStubNull(s, argc, argv); +} + +#if 0 reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) { // Used by SQ6 and LSL6 hires for the text area in the bottom of the // screen. The relevant scripts also exist in Phantasmagoria 1, but they're @@ -465,226 +493,233 @@ reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } +#endif + +reg_t kFont(EngineState *s, int argc, reg_t *argv) { + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} + +reg_t kSetFontHeight(EngineState *s, int argc, reg_t *argv) { + // TODO: Setting font may have just been for side effect + // of setting the fontHeight on the font manager, in + // 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 make_reg(0, g_sci->_gfxText32->_scaledHeight); +} reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv) { - // TODO: This defines the resolution that the fonts are supposed to be displayed - // in. Currently, this is only used for showing high-res fonts in GK1 Mac, but - // should be extended to handle other font resolutions such as those + g_sci->_gfxText32->_scaledWidth = argv[0].toUint16(); + g_sci->_gfxText32->_scaledHeight = argv[1].toUint16(); + return s->r_acc; +} - int xResolution = argv[0].toUint16(); - //int yResolution = argv[1].toUint16(); +reg_t kBitmap(EngineState *s, int argc, reg_t *argv) { + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} - g_sci->_gfxScreen->setFontIsUpscaled(xResolution == 640 && - g_sci->_gfxScreen->getUpscaledHires() != GFX_SCREEN_UPSCALED_DISABLED); +reg_t kBitmapCreate(EngineState *s, int argc, reg_t *argv) { + int16 width = argv[0].toSint16(); + int16 height = argv[1].toSint16(); + int16 skipColor = argv[2].toSint16(); + int16 backColor = argv[3].toSint16(); + int16 scaledWidth = argc > 4 ? argv[4].toSint16() : g_sci->_gfxText32->_scaledWidth; + int16 scaledHeight = argc > 5 ? argv[5].toSint16() : g_sci->_gfxText32->_scaledHeight; + bool useRemap = argc > 6 ? argv[6].toSint16() : false; - return s->r_acc; + BitmapResource bitmap(s->_segMan, width, height, skipColor, 0, 0, scaledWidth, scaledHeight, 0, useRemap); + memset(bitmap.getPixels(), backColor, width * height); + return bitmap.getObject(); } -reg_t kFont(EngineState *s, int argc, reg_t *argv) { - // Handle font settings for SCI2.1 +reg_t kBitmapDestroy(EngineState *s, int argc, reg_t *argv) { + s->_segMan->freeHunkEntry(argv[0]); + return s->r_acc; +} - switch (argv[0].toUint16()) { - case 1: - // Set font resolution - return kSetFontRes(s, argc - 1, argv + 1); - default: - warning("kFont: unknown subop %d", argv[0].toUint16()); +reg_t kBitmapDrawLine(EngineState *s, int argc, reg_t *argv) { + // bitmapMemId, (x1, y1, x2, y2) OR (x2, y2, x1, y1), line color, unknown int, unknown int + return kStubNull(s, argc + 1, argv - 1); +} + +reg_t kBitmapDrawView(EngineState *s, int argc, reg_t *argv) { + // viewId, loopNo, celNo, displace x, displace y, unused, view x, view y + + // called e.g. from TiledBitmap::resize() in Torin's Passage, script 64869 + // The tiled view seems to always have 2 loops. + // These loops need to have 1 cel in loop 0 and 8 cels in loop 1. + + return kStubNull(s, argc + 1, argv - 1); + +#if 0 + // tiled surface + // 6 params, called e.g. from TiledBitmap::resize() in Torin's Passage, + // script 64869 + reg_t hunkId = argv[1]; // obtained from kBitmap(0) + // The tiled view seems to always have 2 loops. + // These loops need to have 1 cel in loop 0 and 8 cels in loop 1. + uint16 viewNum = argv[2].toUint16(); // vTiles selector + uint16 loop = argv[3].toUint16(); + uint16 cel = argv[4].toUint16(); + uint16 x = argv[5].toUint16(); + uint16 y = 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); + byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; + + GfxView *view = g_sci->_gfxCache->getView(viewNum); + uint16 tileWidth = view->getWidth(loop, cel); + uint16 tileHeight = view->getHeight(loop, cel); + const byte *tileBitmap = view->getBitmap(loop, cel); + uint16 width = MIN<uint16>(totalWidth - x, tileWidth); + uint16 height = MIN<uint16>(totalHeight - y, tileHeight); + + for (uint16 curY = 0; curY < height; curY++) { + for (uint16 curX = 0; curX < width; curX++) { + bitmap[(curY + y) * totalWidth + (curX + x)] = tileBitmap[curY * tileWidth + curX]; + } } +#endif +} + +reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) { + // called e.g. from TextButton::createBitmap() in Torin's Passage, script 64894 + + BitmapResource bitmap(argv[0]); + Common::String text = s->_segMan->getString(argv[1]); + Common::Rect textRect( + argv[2].toSint16(), + argv[3].toSint16(), + argv[4].toSint16() + 1, + argv[5].toSint16() + 1 + ); + int16 foreColor = argv[6].toSint16(); + int16 backColor = argv[7].toSint16(); + int16 skipColor = argv[8].toSint16(); + GuiResourceId fontId = (GuiResourceId)argv[9].toUint16(); + TextAlign alignment = (TextAlign)argv[10].toSint16(); + int16 borderColor = argv[11].toSint16(); + bool dimmed = argv[12].toUint16(); + + // NOTE: Technically the engine checks these things: + // textRect.bottom > 0 + // textRect.right > 0 + // textRect.left < bitmap.width + // textRect.top < bitmap.height + // Then clips. But this seems stupid. + textRect.clip(Common::Rect(bitmap.getWidth(), bitmap.getHeight())); + + reg_t textBitmapObject = g_sci->_gfxText32->createFontBitmap(textRect.width(), textRect.height(), Common::Rect(textRect.width(), textRect.height()), text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, false); + Buffer bitmapBuffer(bitmap.getWidth(), bitmap.getHeight(), bitmap.getPixels()); + CelObjMem textCel(textBitmapObject); + textCel.draw(bitmapBuffer, textRect, Common::Point(textRect.left, textRect.top), false); + s->_segMan->freeHunkEntry(textBitmapObject); return s->r_acc; } -// TODO: Eventually, all of the kBitmap operations should be put -// in a separate class +reg_t kBitmapDrawColor(EngineState *s, int argc, reg_t *argv) { + // called e.g. from TextView::init() and TextView::draw() in Torin's Passage, script 64890 -#define BITMAP_HEADER_SIZE 46 + BitmapResource bitmap(argv[0]); + Common::Rect fillRect( + argv[1].toSint16(), + argv[2].toSint16(), + argv[3].toSint16() + 1, + argv[4].toSint16() + 1 + ); -reg_t kBitmap(EngineState *s, int argc, reg_t *argv) { - // Used for bitmap operations in SCI2.1 and SCI3. - // This is the SCI2.1 version, the functionality seems to have changed in SCI3. + Buffer buffer(bitmap.getWidth(), bitmap.getHeight(), bitmap.getPixels()); + buffer.fillRect(fillRect, argv[5].toSint16()); + return s->r_acc; +} - switch (argv[0].toUint16()) { - case 0: // init bitmap surface - { - // 6 params, called e.g. from TextView::init() in Torin's Passage, - // script 64890 and TransView::init() in script 64884 - uint16 width = argv[1].toUint16(); - uint16 height = argv[2].toUint16(); - //uint16 skip = argv[3].toUint16(); - uint16 back = argv[4].toUint16(); // usually equals skip - //uint16 width2 = (argc >= 6) ? argv[5].toUint16() : 0; - //uint16 height2 = (argc >= 7) ? argv[6].toUint16() : 0; - //uint16 transparentFlag = (argc >= 8) ? argv[7].toUint16() : 0; - - // TODO: skip, width2, height2, transparentFlag - // (used for transparent bitmaps) - int entrySize = width * height + BITMAP_HEADER_SIZE; - reg_t memoryId = s->_segMan->allocateHunkEntry("Bitmap()", entrySize); - byte *memoryPtr = s->_segMan->getHunkPointer(memoryId); - memset(memoryPtr, 0, BITMAP_HEADER_SIZE); // zero out the bitmap header - memset(memoryPtr + BITMAP_HEADER_SIZE, back, width * height); - // Save totalWidth, totalHeight - // TODO: Save the whole bitmap header, like SSCI does - WRITE_LE_UINT16(memoryPtr, width); - WRITE_LE_UINT16(memoryPtr + 2, height); - return memoryId; - } - break; - case 1: // dispose text bitmap surface - return kDisposeTextBitmap(s, argc - 1, argv + 1); - case 2: // dispose bitmap surface, with extra param - // 2 params, called e.g. from MenuItem::dispose in Torin's Passage, - // script 64893 - warning("kBitmap(2), unk1 %d, bitmap ptr %04x:%04x", argv[1].toUint16(), PRINT_REG(argv[2])); - break; - case 3: // tiled surface - { - // 6 params, called e.g. from TiledBitmap::resize() in Torin's Passage, - // script 64869 - reg_t hunkId = argv[1]; // obtained from kBitmap(0) - // The tiled view seems to always have 2 loops. - // These loops need to have 1 cel in loop 0 and 8 cels in loop 1. - uint16 viewNum = argv[2].toUint16(); // vTiles selector - uint16 loop = argv[3].toUint16(); - uint16 cel = argv[4].toUint16(); - uint16 x = argv[5].toUint16(); - uint16 y = 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); - byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; - - GfxView *view = g_sci->_gfxCache->getView(viewNum); - uint16 tileWidth = view->getWidth(loop, cel); - uint16 tileHeight = view->getHeight(loop, cel); - const byte *tileBitmap = view->getBitmap(loop, cel); - uint16 width = MIN<uint16>(totalWidth - x, tileWidth); - uint16 height = MIN<uint16>(totalHeight - y, tileHeight); - - for (uint16 curY = 0; curY < height; curY++) { - for (uint16 curX = 0; curX < width; curX++) { - bitmap[(curY + y) * totalWidth + (curX + x)] = tileBitmap[curY * tileWidth + curX]; - } - } +reg_t kBitmapDrawBitmap(EngineState *s, int argc, reg_t *argv) { + // target bitmap, source bitmap, x, y, unknown boolean - } - break; - case 4: // add text to bitmap - { - // 13 params, called e.g. from TextButton::createBitmap() in Torin's Passage, - // script 64894 - reg_t hunkId = argv[1]; // obtained from kBitmap(0) - Common::String text = s->_segMan->getString(argv[2]); - uint16 textX = argv[3].toUint16(); - uint16 textY = argv[4].toUint16(); - //reg_t unk5 = argv[5]; - //reg_t unk6 = argv[6]; - //reg_t unk7 = argv[7]; // skip? - //reg_t unk8 = argv[8]; // back? - //reg_t unk9 = argv[9]; - uint16 fontId = argv[10].toUint16(); - //uint16 mode = argv[11].toUint16(); - uint16 dimmed = argv[12].toUint16(); - //warning("kBitmap(4): bitmap ptr %04x:%04x, font %d, mode %d, dimmed %d - text: \"%s\"", - // PRINT_REG(bitmapPtr), font, mode, dimmed, text.c_str()); - uint16 foreColor = 255; // TODO - - byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); - // Get totalWidth, totalHeight - uint16 totalWidth = READ_LE_UINT16(memoryPtr); - uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); - byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; - - GfxFont *font = g_sci->_gfxCache->getFont(fontId); - - int16 charCount = 0; - uint16 curX = textX, curY = textY; - const char *txt = text.c_str(); - - while (*txt) { - charCount = g_sci->_gfxText32->GetLongest(txt, totalWidth, font); - if (charCount == 0) - break; - - for (int i = 0; i < charCount; i++) { - unsigned char curChar = txt[i]; - font->drawToBuffer(curChar, curY, curX, foreColor, dimmed, bitmap, totalWidth, totalHeight); - curX += font->getCharWidth(curChar); - } - - curX = textX; - curY += font->getHeight(); - txt += charCount; - while (*txt == ' ') - txt++; // skip over breaking spaces - } + return kStubNull(s, argc + 1, argv - 1); +} - } - break; - case 5: // fill with color - { - // 6 params, called e.g. from TextView::init() and TextView::draw() - // in Torin's Passage, script 64890 - 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; - - for (uint16 curY = 0; curY < height; curY++) { - for (uint16 curX = 0; curX < width; curX++) { - bitmap[(curY + y) * totalWidth + (curX + x)] = back; - } - } +reg_t kBitmapInvert(EngineState *s, int argc, reg_t *argv) { + // bitmap, left, top, right, bottom, foreColor, backColor - } - break; - default: - kStub(s, argc, argv); - break; - } + return kStubNull(s, argc + 1, argv - 1); +} +reg_t kBitmapSetDisplace(EngineState *s, int argc, reg_t *argv) { + BitmapResource bitmap(argv[0]); + bitmap.setDisplace(Common::Point(argv[1].toSint16(), argv[2].toSint16())); return s->r_acc; } -// Used for edit boxes in save/load dialogs. It's a rewritten version of kEditControl, -// but it handles events on its own, using an internal loop, instead of using SCI -// scripts for event management like kEditControl does. Called by script 64914, -// DEdit::hilite(). -reg_t kEditText(EngineState *s, int argc, reg_t *argv) { - reg_t controlObject = argv[0]; +reg_t kBitmapCreateFromView(EngineState *s, int argc, reg_t *argv) { + // viewId, loopNo, celNo, skipColor, backColor, useRemap, source overlay bitmap - if (!controlObject.isNull()) { - g_sci->_gfxControls32->kernelTexteditChange(controlObject); - } + return kStub(s, argc + 1, argv - 1); +} - return s->r_acc; +reg_t kBitmapCopyPixels(EngineState *s, int argc, reg_t *argv) { + // target bitmap, source bitmap + + return kStubNull(s, argc + 1, argv - 1); +} + +reg_t kBitmapClone(EngineState *s, int argc, reg_t *argv) { + // bitmap + + return kStub(s, argc + 1, argv - 1); +} + +reg_t kBitmapGetInfo(EngineState *s, int argc, reg_t *argv) { + // bitmap + + // argc 1 = get width + // argc 2 = pixel at row 0 col n + // argc 3 = pixel at row n col n + return kStub(s, argc + 1, argv - 1); +} + +reg_t kBitmapScale(EngineState *s, int argc, reg_t *argv) { + // TODO: SCI3 + return kStubNull(s, argc + 1, argv - 1); +} + +reg_t kBitmapCreateFromUnknown(EngineState *s, int argc, reg_t *argv) { + // TODO: SCI3 + return kStub(s, argc + 1, argv - 1); +} + +reg_t kEditText(EngineState *s, int argc, reg_t *argv) { + return g_sci->_gfxControls32->kernelEditText(argv[0]); } reg_t kAddLine(EngineState *s, int argc, reg_t *argv) { + return kStubNull(s, argc, argv); // return 0:0 for now, so that follow up calls won't create signature mismatches +#if 0 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 } reg_t kUpdateLine(EngineState *s, int argc, reg_t *argv) { + return kStub(s, argc, argv); + +#if 0 reg_t hunkId = argv[0]; reg_t plane = argv[1]; Common::Point startPoint(argv[2].toUint16(), argv[3].toUint16()); @@ -694,14 +729,18 @@ reg_t kUpdateLine(EngineState *s, int argc, reg_t *argv) { byte priority = (byte)argv[8].toUint16(); byte control = (byte)argv[9].toUint16(); // argv[10] is unknown (usually a small number, 1 or 2). Thickness, perhaps? - g_sci->_gfxFrameout->updatePlaneLine(plane, hunkId, startPoint, endPoint, color, priority, control); +// g_sci->_gfxFrameout->updatePlaneLine(plane, hunkId, startPoint, endPoint, color, priority, control); return s->r_acc; +#endif } reg_t kDeleteLine(EngineState *s, int argc, reg_t *argv) { + return kStub(s, argc, argv); +#if 0 reg_t hunkId = argv[0]; reg_t plane = argv[1]; - g_sci->_gfxFrameout->deletePlaneLine(plane, hunkId); +// g_sci->_gfxFrameout->deletePlaneLine(plane, hunkId); return s->r_acc; +#endif } reg_t kSetScroll(EngineState *s, int argc, reg_t *argv) { @@ -730,13 +769,8 @@ 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) { - // TODO: g_sci->_gfxManager->palMorphIsOn = true - // This function sets the palMorphIsOn flag which causes kFrameOut to use - // an alternative FrameOut function (GraphicsMgr::PalMorphFrameOut instead - // of GraphicsMgr::FrameOut). At the end of the frame, kFrameOut sets the - // palMorphIsOn flag back to false. - kStub(s, argc, argv); - return NULL_REG; + g_sci->_gfxFrameout->_palMorphIsOn = true; + return s->r_acc; } reg_t kPaletteSetFade(EngineState *s, int argc, reg_t *argv) { @@ -744,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) { @@ -762,14 +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; 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) { @@ -778,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) { @@ -790,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) { @@ -875,76 +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) { - uint16 operation = argv[0].toUint16(); +reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) { + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} - 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; +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; +} - int16 base = (argc >= 2) ? argv[1].toSint16() : 0; - if (base > 0) - warning("kRemapColors(0) called with base %d", base); - 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 base = argv[4].toUint16(); - uint16 unk5 = (argc >= 6) ? argv[5].toUint16() : 0; - if (unk5 > 0) - warning("kRemapColors(1) called with 6 parameters, unknown parameter is %d", unk5); - g_sci->_gfxPalette32->setRemappingRange(color, from, to, base); - } - break; - case 2: { // remap by percent - uint16 color = argv[1].toUint16(); - uint16 percent = argv[2].toUint16(); // 0 - 100 - if (argc >= 4) - warning("RemapByPercent called with 4 parameters, unknown parameter is %d", argv[3].toUint16()); - 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. - int16 color = argv[1].toSint16(); - int16 percent = argv[2].toSint16(); // 0 - 100 - if (argc >= 4) - warning("RemapToGray called with 4 parameters, unknown parameter is %d", argv[3].toUint16()); - 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 - int16 color = argv[1].toSint16(); - int16 percent = argv[2].toSint16(); // 0 - 100 - // argv[3] is unknown (a number, e.g. 200) - start color, perhaps? - if (argc >= 5) - warning("RemapToGrayPercent called with 5 parameters, unknown parameter is %d", argv[4].toUint16()); - g_sci->_gfxPalette32->setRemappingPercentGray(color, percent); - } - break; - case 5: { // don't map to range - //int16 mapping = argv[1].toSint16(); - uint16 intensity = argv[2].toUint16(); - // HACK for PQ4 - if (g_sci->getGameId() == GID_PQ4) - g_sci->_gfxPalette32->kernelSetIntensity(0, 255, intensity, true); +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; +} - kStub(s, argc, argv); - } - break; - default: - break; - } +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/kmisc.cpp b/engines/sci/engine/kmisc.cpp index 9d47a37bca..f4bb4ff85b 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -268,7 +268,10 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) { switch (argv[0].toUint16()) { case K_MEMORY_ALLOCATE_CRITICAL: { int byteCount = argv[1].toUint16(); - // WORKAROUND: + // Sierra themselves allocated at least 2 bytes more than requested. + // Probably as a safety margin. And they also made size even. + // + // This behavior is required by at least these: // - pq3 (multilingual) room 202 // when plotting crimes, allocates the returned bytes from kStrLen // on "W" and "E" and wants to put a string in there, which doesn't @@ -276,18 +279,22 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) { // - lsl5 (multilingual) room 280 // allocates memory according to a previous kStrLen for the name of // the airport ladies (bug #3093818), which isn't enough - - // We always allocate 1 byte more, because of this - byteCount++; + byteCount += 2 + (byteCount & 1); if (!s->_segMan->allocDynmem(byteCount, "kMemory() critical", &s->r_acc)) { error("Critical heap allocation failed"); } break; } - case K_MEMORY_ALLOCATE_NONCRITICAL: - s->_segMan->allocDynmem(argv[1].toUint16(), "kMemory() non-critical", &s->r_acc); + case K_MEMORY_ALLOCATE_NONCRITICAL: { + int byteCount = argv[1].toUint16(); + + // See above + byteCount += 2 + (byteCount & 1); + + s->_segMan->allocDynmem(byteCount, "kMemory() non-critical", &s->r_acc); break; + } case K_MEMORY_FREE : if (!s->_segMan->freeDynmem(argv[1])) { if (g_sci->getGameId() == GID_QFG1VGA) { diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp index 5b2245e84d..7ac744f584 100644 --- a/engines/sci/engine/kpathing.cpp +++ b/engines/sci/engine/kpathing.cpp @@ -1943,14 +1943,14 @@ static int liesBefore(const Vertex *v, const Common::Point &p1, const Common::Po // indexp1/vertexp1 on the polygon being merged. // It ends with the point intersection2, being the analogous intersection. struct Patch { - unsigned int indexw1; - unsigned int indexp1; + uint32 indexw1; + uint32 indexp1; const Vertex *vertexw1; const Vertex *vertexp1; Common::Point intersection1; - unsigned int indexw2; - unsigned int indexp2; + uint32 indexw2; + uint32 indexp2; const Vertex *vertexw2; const Vertex *vertexp2; Common::Point intersection2; @@ -1960,7 +1960,7 @@ struct Patch { // Check if the given vertex on the work polygon is bypassed by this patch. -static bool isVertexCovered(const Patch &p, unsigned int wi) { +static bool isVertexCovered(const Patch &p, uint32 wi) { // / v (outside) // ---w1--1----p----w2--2---- @@ -2402,7 +2402,7 @@ reg_t kMergePoly(EngineState *s, int argc, reg_t *argv) { // Copy work.vertices into arrayRef Vertex *vertex; - unsigned int n = 0; + uint32 n = 0; CLIST_FOREACH(vertex, &work.vertices) { if (vertex == work.vertices._head || vertex->v != vertex->_prev->v) writePoint(arrayRef, n++, vertex->v); diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp index 032191e4c1..398a623286 100644 --- a/engines/sci/engine/ksound.cpp +++ b/engines/sci/engine/ksound.cpp @@ -206,8 +206,15 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) { // athrxx: It seems from disasm that the original KQ5 FM-Towns loads a default language (Japanese) audio map at the beginning // right after loading the video and audio drivers. The -1 language argument in here simply means that the original will stick // with Japanese. Instead of doing that we switch to the language selected in the launcher. - if (g_sci->getPlatform() == Common::kPlatformFMTowns && language == -1) - language = (g_sci->getLanguage() == Common::JA_JPN) ? K_LANG_JAPANESE : K_LANG_ENGLISH; + if (g_sci->getPlatform() == Common::kPlatformFMTowns && language == -1) { + // FM-Towns calls us to get the current language / also set the default language + // This doesn't just happen right at the start, but also when the user clicks on the Sierra logo in the game menu + // It uses the result of this call to either show "English Voices" or "Japanese Voices". + + // Language should have been set by setLauncherLanguage() already (or could have been modified by the scripts). + // Get this language setting, so that the chosen language will get set for resource manager. + language = g_sci->getSciLanguage(); + } debugC(kDebugLevelSound, "kDoAudio: set language to %d", language); @@ -233,19 +240,38 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) { #endif } - // 3 new subops in Pharkas. kDoAudio in Pharkas sits at seg026:038C + // 3 new subops in Pharkas CD (including CD demo). kDoAudio in Pharkas sits at seg026:038C case 11: // Not sure where this is used yet warning("kDoAudio: Unhandled case 11, %d extra arguments passed", argc - 1); break; case 12: - // Seems to be some sort of audio sync, used in Pharkas. Silenced the - // warning due to the high level of spam it produces. (takes no params) - //warning("kDoAudio: Unhandled case 12, %d extra arguments passed", argc - 1); + // SSCI calls this function with no parameters from + // the TalkRandCycle class and branches on the return + // value like a boolean. The conjectured purpose of + // this function is to ensure that the talker's mouth + // does not move if there is read jitter (slow CD + // drive, scratched CD). The old behavior here of not + // doing anything caused a nonzero value to be left in + // the accumulator by chance. This is equivalent, but + // more explicit. + + return make_reg(0, 1); break; case 13: - // Used in Pharkas whenever a speech sample starts (takes no params) - //warning("kDoAudio: Unhandled case 13, %d extra arguments passed", argc - 1); + // SSCI returns a serial number for the played audio + // here, used in the PointsSound class. The reason is severalfold: + + // 1. SSCI does not support multiple wave effects at once + // 2. FPFP may disable its icon bar during the points sound. + // 3. Each new sound preempts any sound already playing. + // 4. If the points sound is interrupted before completion, + // the icon bar could remain disabled. + + // Since points (1) and (3) do not apply to us, we can simply + // return a constant here. This is equivalent to the + // old behavior, as above. + return make_reg(0, 1); break; case 17: // Seems to be some sort of audio sync, used in SQ6. Silenced the diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp index 310e38dbd1..1c08bf597c 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -661,19 +661,6 @@ reg_t kStrSplit(EngineState *s, int argc, reg_t *argv) { #ifdef ENABLE_SCI32 -reg_t kText(EngineState *s, int argc, reg_t *argv) { - switch (argv[0].toUint16()) { - case 0: - return kTextSize(s, argc - 1, argv + 1); - default: - // TODO: Other subops here too, perhaps kTextColors and kTextFonts - warning("kText(%d)", argv[0].toUint16()); - break; - } - - return s->r_acc; -} - // TODO: there is an unused second argument, happens at least in LSL6 right during the intro reg_t kStringNew(EngineState *s, int argc, reg_t *argv) { reg_t stringHandle; @@ -778,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/object.cpp b/engines/sci/engine/object.cpp index 0626c084c1..0566d6955f 100644 --- a/engines/sci/engine/object.cpp +++ b/engines/sci/engine/object.cpp @@ -255,6 +255,8 @@ void Object::initSelectorsSci3(const byte *buf) { if (g_sci->getKernel()->getSelectorNamesSize() % 32) ++groups; + _mustSetViewVisible.resize(groups); + methods = properties = 0; // Selectors are divided into groups of 32, of which the first @@ -270,7 +272,9 @@ void Object::initSelectorsSci3(const byte *buf) { // This object actually has selectors belonging to this group int typeMask = READ_SCI11ENDIAN_UINT32(seeker); - for (int bit = 2; bit < 32; ++bit) { + _mustSetViewVisible[groupNr] = (typeMask & 1); + + for (int bit = 2; bit < 32; ++bit) { int value = READ_SCI11ENDIAN_UINT16(seeker + bit * 2); if (typeMask & (1 << bit)) { // Property ++properties; @@ -281,7 +285,8 @@ void Object::initSelectorsSci3(const byte *buf) { } } - } + } else + _mustSetViewVisible[groupNr] = false; } _variables.resize(properties); diff --git a/engines/sci/engine/object.h b/engines/sci/engine/object.h index 0ae7ed2cab..a7be170f4f 100644 --- a/engines/sci/engine/object.h +++ b/engines/sci/engine/object.h @@ -41,8 +41,21 @@ enum { }; enum infoSelectorFlags { - kInfoFlagClone = 0x0001, - kInfoFlagClass = 0x8000 + kInfoFlagClone = 0x0001, +#ifdef ENABLE_SCI32 + /** + * When set, indicates to game scripts that a screen + * item can be updated. + */ + kInfoFlagViewVisible = 0x0008, // TODO: "dirty" ? + + /** + * When set, the object has an associated screen item in + * the rendering tree. + */ + kInfoFlagViewInserted = 0x0010, +#endif + kInfoFlagClass = 0x8000 }; enum ObjectOffsets { @@ -120,7 +133,24 @@ public: _infoSelectorSci3 = info; } - // No setter for the -info- selector +#ifdef ENABLE_SCI32 + void setInfoSelectorFlag(infoSelectorFlags flag) { + if (getSciVersion() < SCI_VERSION_3) { + _variables[_offset + 2] |= flag; + } else { + _infoSelectorSci3 |= flag; + } + } + + // NOTE: In real engine, -info- is treated as byte size + void clearInfoSelectorFlag(infoSelectorFlags flag) { + if (getSciVersion() < SCI_VERSION_3) { + _variables[_offset + 2] &= ~flag; + } else { + _infoSelectorSci3 &= ~flag; + } + } +#endif reg_t getNameSelector() const { if (getSciVersion() < SCI_VERSION_3) @@ -232,6 +262,8 @@ public: bool initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass = true); void syncBaseObject(const byte *ptr) { _baseObj = ptr; } + bool mustSetViewVisibleSci3(int selector) const { return _mustSetViewVisible[selector/32]; } + private: void initSelectorsSci3(const byte *buf); @@ -248,6 +280,7 @@ private: reg_t _superClassPosSci3; /**< reg_t pointing to superclass for SCI3 */ reg_t _speciesSelectorSci3; /**< reg_t containing species "selector" for SCI3 */ reg_t _infoSelectorSci3; /**< reg_t containing info "selector" for SCI3 */ + Common::Array<bool> _mustSetViewVisible; /** cached bit of info to make lookup fast, SCI3 only */ }; diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 165c147c1c..fcb65157d8 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -39,6 +39,7 @@ #include "sci/engine/vm_types.h" #include "sci/engine/script.h" // for SCI_OBJ_EXPORTS and SCI_OBJ_SYNONYMS #include "sci/graphics/helpers.h" +#include "sci/graphics/menu.h" #include "sci/graphics/palette.h" #include "sci/graphics/ports.h" #include "sci/graphics/screen.h" @@ -957,7 +958,8 @@ bool gamestate_save(EngineState *s, Common::WriteStream *fh, const Common::Strin extern void showScummVMDialog(const Common::String &message); void gamestate_delayedrestore(EngineState *s) { - Common::String fileName = g_sci->getSavegameName(s->_delayedRestoreGameId); + int savegameId = s->_delayedRestoreGameId; // delayedRestoreGameId gets destroyed within gamestate_restore()! + Common::String fileName = g_sci->getSavegameName(savegameId); Common::SeekableReadStream *in = g_sci->getSaveFileManager()->openForLoading(fileName); if (in) { @@ -965,6 +967,7 @@ void gamestate_delayedrestore(EngineState *s) { gamestate_restore(s, in); delete in; if (s->r_acc != make_reg(0, 1)) { + gamestate_afterRestoreFixUp(s, savegameId); return; } } @@ -972,6 +975,73 @@ void gamestate_delayedrestore(EngineState *s) { error("Restoring gamestate '%s' failed", fileName.c_str()); } +void gamestate_afterRestoreFixUp(EngineState *s, int savegameId) { + switch (g_sci->getGameId()) { + case GID_MOTHERGOOSE: + // WORKAROUND: Mother Goose SCI0 + // Script 200 / rm200::newRoom will set global C5h directly right after creating a child to the + // current number of children plus 1. + // We can't trust that global, that's why we set the actual savedgame id right here directly after + // restoring a saved game. + // If we didn't, the game would always save to a new slot + s->variables[VAR_GLOBAL][0xC5].setOffset(SAVEGAMEID_OFFICIALRANGE_START + savegameId); + break; + case GID_MOTHERGOOSE256: + // WORKAROUND: Mother Goose SCI1/SCI1.1 does some weird things for + // saving a previously restored game. + // We set the current savedgame-id directly and remove the script + // code concerning this via script patch. + s->variables[VAR_GLOBAL][0xB3].setOffset(SAVEGAMEID_OFFICIALRANGE_START + savegameId); + break; + case GID_JONES: + // HACK: The code that enables certain menu items isn't called when a game is restored from the + // launcher, or the "Restore game" option in the game's main menu - bugs #6537 and #6723. + // These menu entries are disabled when the game is launched, and are enabled when a new game is + // started. The code for enabling these entries is is all in script 1, room1::init, but that code + // path is never followed in these two cases (restoring game from the menu, or restoring a game + // from the ScummVM launcher). Thus, we perform the calls to enable the menus ourselves here. + // These two are needed when restoring from the launcher + // FIXME: The original interpreter saves and restores the menu state, so these attributes + // are automatically reset there. We may want to do the same. + g_sci->_gfxMenu->kernelSetAttribute(257 >> 8, 257 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Sierra -> About Jones + g_sci->_gfxMenu->kernelSetAttribute(258 >> 8, 258 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Sierra -> Help + // The rest are normally enabled from room1::init + g_sci->_gfxMenu->kernelSetAttribute(769 >> 8, 769 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Options -> Delete current player + g_sci->_gfxMenu->kernelSetAttribute(513 >> 8, 513 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Game -> Save Game + g_sci->_gfxMenu->kernelSetAttribute(515 >> 8, 515 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Game -> Restore Game + 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. + g_sci->_gfxMenu->kernelSetAttribute(2, 1, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Game -> Save Game + break; + default: + break; + } +} + void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { SavegameMetadata meta; @@ -1013,13 +1083,31 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { if (g_sci->_gfxPorts) g_sci->_gfxPorts->reset(); // clear screen - if (g_sci->_gfxScreen) - g_sci->_gfxScreen->clearForRestoreGame(); + if (getSciVersion() <= SCI_VERSION_1_1) { + // Only do clearing the screen for SCI16 + // Both SCI16 + SCI32 did not clear the screen. + // We basically do it for SCI16, because of KQ6. + // When hires portraits are shown and the user restores during that time, the portraits + // wouldn't get fully removed. In original SCI, the user wasn't able to restore during that time, + // so this is basically a workaround, so that ScummVM features work properly. + // For SCI32, behavior was verified in DOSBox, that SCI32 does not clear and also not redraw the screen. + // It only redraws elements that have changed in comparison to the state before the restore. + // If we cleared the screen for SCI32, we would have issues because of this behavior. + if (g_sci->_gfxScreen) + g_sci->_gfxScreen->clearForRestoreGame(); + } #ifdef ENABLE_SCI32 - // Also clear any SCI32 planes/screen items currently showing so they - // don't show up after the load. - if (getSciVersion() >= SCI_VERSION_2) - g_sci->_gfxFrameout->clear(); + // Delete current planes/elements of actively loaded VM, only when our ScummVM dialogs are patched in + // We MUST NOT delete all planes/screen items. At least Space Quest 6 has a few in memory like for example + // the options plane, which are not re-added and are in memory all the time right from the start of the + // game. Sierra SCI32 did not clear planes, only scripts cleared the ones inside planes::elements. + if (getSciVersion() >= SCI_VERSION_2) { + if (!s->_delayedRestoreFromLauncher) { + // Only do it, when we are restoring regulary and not from launcher + // As it could result in option planes etc. on the screen (happens in gk1) + g_sci->_gfxFrameout->syncWithScripts(false); + } + } #endif s->reset(true); @@ -1044,6 +1132,13 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { if (g_sci->_gfxPorts) g_sci->_gfxPorts->saveLoadWithSerializer(ser); + // SCI32: + // Current planes/screen elements of freshly loaded VM are re-added by scripts in [gameID]::replay + // We don't have to do that in here. + // But we may have to do it ourselves in case we ever implement some soft-error handling in case + // a saved game can't be restored. That way we can restore the game screen. + // see _gfxFrameout->syncWithScripts() + Vocabulary *voc = g_sci->getVocabulary(); if (ser.getVersion() >= 30 && voc) voc->saveLoadWithSerializer(ser); @@ -1061,6 +1156,8 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { // signal restored game to game scripts s->gameIsRestarting = GAMEISRESTARTING_RESTORE; + + s->_delayedRestoreFromLauncher = false; } bool get_savegame_metadata(Common::SeekableReadStream *stream, SavegameMetadata *meta) { diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h index bb555434c9..459e992e24 100644 --- a/engines/sci/engine/savegame.h +++ b/engines/sci/engine/savegame.h @@ -87,6 +87,9 @@ bool gamestate_save(EngineState *s, Common::WriteStream *save, const Common::Str // does a delayed saved game restore, used by ScummVM game menu - see detection.cpp / SciEngine::loadGameState() void gamestate_delayedrestore(EngineState *s); +// does a few fixups right after restoring a saved game +void gamestate_afterRestoreFixUp(EngineState *s, int savegameId); + /** * Restores a game state from a directory. * @param s An older state from the same game diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp index 6915e12a0e..8039c5f282 100644 --- a/engines/sci/engine/script_patches.cpp +++ b/engines/sci/engine/script_patches.cpp @@ -101,6 +101,8 @@ static const char *const selectorNameTable[] = { "startText", // King's Quest 6 CD / Laura Bow 2 CD for audio+text support "startAudio", // King's Quest 6 CD / Laura Bow 2 CD for audio+text support "modNum", // King's Quest 6 CD / Laura Bow 2 CD for audio+text support + "cycler", // Space Quest 4 / system selector + "setLoop", // Laura Bow 1 Colonel's Bequest NULL }; @@ -127,7 +129,9 @@ enum ScriptPatcherSelectors { SELECTOR_timesShownID, SELECTOR_startText, SELECTOR_startAudio, - SELECTOR_modNum + SELECTOR_modNum, + SELECTOR_cycler, + SELECTOR_setLoop }; // =========================================================================== @@ -404,6 +408,59 @@ static const SciScriptPatcherEntry fanmadeSignatures[] = { }; // =========================================================================== + +// WORKAROUND +// Freddy Pharkas intro screen +// Sierra used inner loops for the scaling of the 2 title views. +// Those inner loops don't call kGameIsRestarting, which is why +// we do not update the screen and we also do not throttle. +// +// This patch fixes this and makes it work. +// Applies to at least: English PC-CD +// Responsible method: sTownScript::changeState(1), sTownScript::changeState(3) (script 110) +static const uint16 freddypharkasSignatureIntroScaling[] = { + 0x38, SIG_ADDTOOFFSET(+2), // pushi (setLoop) (009b for PC CD) + 0x78, // push1 + PATCH_ADDTOOFFSET(1), // push0 for first code, push1 for second code + 0x38, SIG_ADDTOOFFSET(+2), // pushi (setStep) (0143 for PC CD) + 0x7a, // push2 + 0x39, 0x05, // pushi 05 + 0x3c, // dup + 0x72, SIG_ADDTOOFFSET(+2), // lofsa (view) + SIG_MAGICDWORD, + 0x4a, 0x1e, // send 1e + 0x35, 0x0a, // ldi 0a + 0xa3, 0x02, // sal local[2] + // start of inner loop + 0x8b, 0x02, // lsl local[2] + SIG_ADDTOOFFSET(+43), // skip almost all of inner loop + 0xa3, 0x02, // sal local[2] + 0x33, 0xcf, // jmp [inner loop start] + SIG_END +}; + +static const uint16 freddypharkasPatchIntroScaling[] = { + // remove setLoop(), objects in heap are already prepared, saves 5 bytes + 0x38, + PATCH_GETORIGINALBYTE(+6), + PATCH_GETORIGINALBYTE(+7), // pushi (setStep) + 0x7a, // push2 + 0x39, 0x05, // pushi 05 + 0x3c, // dup + 0x72, + PATCH_GETORIGINALBYTE(+13), + PATCH_GETORIGINALBYTE(+14), // lofsa (view) + 0x4a, 0x18, // send 18 - adjusted + 0x35, 0x0a, // ldi 0a + 0xa3, 0x02, // sal local[2] + // start of new inner loop + 0x39, 0x00, // pushi 00 + 0x43, 0x2c, 0x00, // callk GameIsRestarting <-- add this so that our speed throttler is triggered + SIG_ADDTOOFFSET(+47), // skip almost all of inner loop + 0x33, 0xca, // jmp [inner loop start] + PATCH_END +}; + // script 0 of freddy pharkas/CD PointsSound::check waits for a signal and if // no signal received will call kDoSound(0xD) which is a dummy in sierra sci // and ScummVM and will use acc (which is not set by the dummy) to trigger @@ -522,6 +579,7 @@ static const uint16 freddypharkasPatchMacInventory[] = { static const SciScriptPatcherEntry freddypharkasSignatures[] = { { true, 0, "CD: score early disposal", 1, freddypharkasSignatureScoreDisposal, freddypharkasPatchScoreDisposal }, { true, 15, "Mac: broken inventory", 1, freddypharkasSignatureMacInventory, freddypharkasPatchMacInventory }, + { true, 110, "intro scaling workaround", 2, freddypharkasSignatureIntroScaling, freddypharkasPatchIntroScaling }, { true, 235, "CD: canister pickup hang", 3, freddypharkasSignatureCanisterHang, freddypharkasPatchCanisterHang }, { true, 320, "ladder event issue", 2, freddypharkasSignatureLadderEvent, freddypharkasPatchLadderEvent }, SCI_SIGNATUREENTRY_TERMINATOR @@ -755,6 +813,32 @@ static const uint16 kq5PatchWitchCageInit[] = { PATCH_END }; +// The multilingual releases of KQ5 hang right at the end during the magic battle with Mordack. +// It seems additional code was added to wait for signals, but the signals are never set and thus +// the game hangs. We disable that code, so that the battle works again. +// This also happened in the original interpreter. +// We must not change similar code, that happens before. + +// Applies to at least: French PC floppy, German PC floppy, Spanish PC floppy +// Responsible method: stingScript::changeState, dragonScript::changeState, snakeScript::changeState +static const uint16 kq5SignatureMultilingualEndingGlitch[] = { + SIG_MAGICDWORD, + 0x89, 0x57, // lsg global[57h] + 0x35, 0x00, // ldi 0 + 0x1a, // eq? + 0x18, // not + 0x30, SIG_UINT16(0x0011), // bnt [skip signal check] + SIG_ADDTOOFFSET(+8), // skip globalSound::prevSignal get code + 0x36, // push + 0x35, 0x0a, // ldi 0Ah + SIG_END +}; + +static const uint16 kq5PatchMultilingualEndingGlitch[] = { + PATCH_ADDTOOFFSET(+6), + 0x32, // change BNT into JMP + PATCH_END +}; // In the final battle, the DOS version uses signals in the music to handle // timing, while in the Windows version another method is used and the GM @@ -785,9 +869,10 @@ static const uint16 kq5PatchWinGMSignals[] = { // script, description, signature patch static const SciScriptPatcherEntry kq5Signatures[] = { - { true, 0, "CD: harpy volume change", 1, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume }, - { true, 200, "CD: witch cage init", 1, kq5SignatureWitchCageInit, kq5PatchWitchCageInit }, - { false, 124, "Win: GM Music signal checks", 4, kq5SignatureWinGMSignals, kq5PatchWinGMSignals }, + { true, 0, "CD: harpy volume change", 1, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume }, + { true, 200, "CD: witch cage init", 1, kq5SignatureWitchCageInit, kq5PatchWitchCageInit }, + { true, 124, "Multilingual: Ending glitching out", 3, kq5SignatureMultilingualEndingGlitch, kq5PatchMultilingualEndingGlitch }, + { false, 124, "Win: GM Music signal checks", 4, kq5SignatureWinGMSignals, kq5PatchWinGMSignals }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -1201,8 +1286,10 @@ static const uint16 kq6CDPatchAudioTextSupportJumpAlways[] = { }; // Fixes "Girl In The Tower" to get played in dual mode as well +// Also changes credits to use CD audio for dual mode. +// // Applies to at least: PC-CD -// Patched method: rm740::cue +// Patched method: rm740::cue (script 740), sCredits::init (script 52) static const uint16 kq6CDSignatureAudioTextSupportGirlInTheTower[] = { SIG_MAGICDWORD, 0x89, 0x5a, // lsg global[5a] @@ -1329,6 +1416,7 @@ static const SciScriptPatcherEntry kq6Signatures[] = { { false, 928, "CD: audio + text support KQ6 4", 1, kq6CDSignatureAudioTextSupport4, kq6CDPatchAudioTextSupport4 }, { false, 1009, "CD: audio + text support KQ6 Guards", 2, kq6CDSignatureAudioTextSupportGuards, kq6CDPatchAudioTextSupportGuards }, { false, 1027, "CD: audio + text support KQ6 Stepmother", 1, kq6CDSignatureAudioTextSupportStepmother, kq6CDPatchAudioTextSupportJumpAlways }, + { false, 52, "CD: audio + text support KQ6 Girl In The Tower", 1, kq6CDSignatureAudioTextSupportGirlInTheTower, kq6CDPatchAudioTextSupportGirlInTheTower }, { false, 740, "CD: audio + text support KQ6 Girl In The Tower", 1, kq6CDSignatureAudioTextSupportGirlInTheTower, kq6CDPatchAudioTextSupportGirlInTheTower }, { false, 370, "CD: audio + text support KQ6 Azure & Ariel", 6, kq6CDSignatureAudioTextSupportAzureAriel, kq6CDPatchAudioTextSupportAzureAriel }, { false, 903, "CD: audio + text support KQ6 menu", 1, kq6CDSignatureAudioTextMenuSupport, kq6CDPatchAudioTextMenuSupport }, @@ -1536,6 +1624,43 @@ static const SciScriptPatcherEntry larry6Signatures[] = { }; // =========================================================================== +// Laura Bow 1 - Colonel's Bequest +// +// This is basically just a broken easter egg in Colonel's Bequest. +// A plane can show up in room 4, but that only happens really rarely. +// Anyway the Sierra developer seems to have just entered the wrong loop, +// which is why the statue view is used instead (loop 0). +// We fix it to use the correct loop. +// +// This is only broken in the PC version. It was fixed for Amiga + Atari ST. +// +// Credits to OmerMor, for finding it. + +// Applies to at least: English PC Floppy +// Responsible method: room4::init +static const uint16 laurabow1SignatureEasterEggViewFix[] = { + 0x78, // push1 + 0x76, // push0 + SIG_MAGICDWORD, + 0x38, SIG_SELECTOR16(setLoop), // pushi "setLoop" + 0x78, // push1 + 0x39, 0x03, // pushi 3 (loop 3, view only has 3 loops) + SIG_END +}; + +static const uint16 laurabow1PatchEasterEggViewFix[] = { + PATCH_ADDTOOFFSET(+7), + 0x02, // change loop to 2 + PATCH_END +}; + +// script, description, signature patch +static const SciScriptPatcherEntry laurabow1Signatures[] = { + { true, 4, "easter egg view fix", 1, laurabow1SignatureEasterEggViewFix, laurabow1PatchEasterEggViewFix }, + SCI_SIGNATUREENTRY_TERMINATOR +}; + +// =========================================================================== // Laura Bow 2 // // Moving away the painting in the room with the hidden safe is problematic @@ -1840,15 +1965,103 @@ static const SciScriptPatcherEntry laurabow2Signatures[] = { // MG::replay somewhat calculates the savedgame-id used when saving again // this doesn't work right and we remove the code completely. // We set the savedgame-id directly right after restoring in kRestoreGame. +// We also draw the background picture in here instead. +// This Mixed Up Mother Goose draws the background picture before restoring, +// instead of doing it properly in MG::replay. This fixes graphic issues, +// when restoring from GMM. +// +// Applies to at least: English SCI1 CD, English SCI1.1 floppy, Japanese FM-Towns +// Responsible method: MG::replay (script 0) static const uint16 mothergoose256SignatureReplay[] = { + 0x7a, // push2 + 0x78, // push1 + 0x5b, 0x00, 0xbe, // lea global[BEh] + 0x36, // push + 0x43, 0x70, 0x04, // callk MemorySegment + 0x7a, // push2 + 0x5b, 0x00, 0xbe, // lea global[BEh] + 0x36, // push + 0x76, // push0 + 0x43, 0x62, 0x04, // callk StrAt + 0xa1, 0xaa, // sag global[AAh] + 0x7a, // push2 + 0x5b, 0x00, 0xbe, // lea global[BEh] + 0x36, // push + 0x78, // push1 + 0x43, 0x62, 0x04, // callk StrAt + 0x36, // push + 0x35, 0x20, // ldi 20 + 0x04, // sub + 0xa1, SIG_ADDTOOFFSET(+1), // sag global[57h] -> FM-Towns [9Dh] + // 35 bytes + 0x39, 0x03, // pushi 03 + 0x89, SIG_ADDTOOFFSET(+1), // lsg global[1Dh] -> FM-Towns [1Eh] + 0x76, // push0 + 0x7a, // push2 + 0x5b, 0x00, 0xbe, // lea global[BEh] + 0x36, // push + 0x7a, // push2 + 0x43, 0x62, 0x04, // callk StrAt + 0x36, // push + 0x35, 0x01, // ldi 01 + 0x04, // sub + 0x36, // push + 0x43, 0x62, 0x06, // callk StrAt + // 22 bytes + 0x7a, // push2 + 0x5b, 0x00, 0xbe, // lea global[BE] + 0x36, // push + 0x39, 0x03, // pushi 03 + 0x43, 0x62, 0x04, // callk StrAt + // 10 bytes 0x36, // push 0x35, SIG_MAGICDWORD, 0x20, // ldi 20 0x04, // sub 0xa1, 0xb3, // sag global[b3] + // 6 bytes SIG_END }; static const uint16 mothergoose256PatchReplay[] = { + 0x39, 0x06, // pushi 06 + 0x76, // push0 + 0x76, // push0 + 0x38, PATCH_UINT16(200), // pushi 200d + 0x38, PATCH_UINT16(320), // pushi 320d + 0x76, // push0 + 0x76, // push0 + 0x43, 0x15, 0x0c, // callk SetPort -> set picture port to full screen + // 15 bytes + 0x39, 0x04, // pushi 04 + 0x3c, // dup + 0x76, // push0 + 0x38, PATCH_UINT16(255), // pushi 255d + 0x76, // push0 + 0x43, 0x6f, 0x08, // callk Palette -> set intensity to 0 for all colors + // 11 bytes + 0x7a, // push2 + 0x38, PATCH_UINT16(800), // pushi 800 + 0x76, // push0 + 0x43, 0x08, 0x04, // callk DrawPic -> draw picture 800 + // 8 bytes + 0x39, 0x06, // pushi 06 + 0x39, 0x0c, // pushi 0Ch + 0x76, // push0 + 0x76, // push0 + 0x38, PATCH_UINT16(200), // push 200 + 0x38, PATCH_UINT16(320), // push 320 + 0x78, // push1 + 0x43, 0x6c, 0x0c, // callk Graph -> send everything to screen + // 16 bytes + 0x39, 0x06, // pushi 06 + 0x76, // push0 + 0x76, // push0 + 0x38, PATCH_UINT16(156), // pushi 156d + 0x38, PATCH_UINT16(258), // pushi 258d + 0x39, 0x03, // pushi 03 + 0x39, 0x04, // pushi 04 + 0x43, 0x15, 0x0c, // callk SetPort -> set picture port back + // 17 bytes 0x34, PATCH_UINT16(0x0000), // ldi 0000 (dummy) 0x34, PATCH_UINT16(0x0000), // ldi 0000 (dummy) PATCH_END @@ -1856,6 +2069,9 @@ static const uint16 mothergoose256PatchReplay[] = { // when saving, it also checks if the savegame ID is below 13. // we change this to check if below 113 instead +// +// Applies to at least: English SCI1 CD, English SCI1.1 floppy, Japanese FM-Towns +// Responsible method: Game::save (script 994 for SCI1), MG::save (script 0 for SCI1.1) static const uint16 mothergoose256SignatureSaveLimit[] = { 0x89, SIG_MAGICDWORD, 0xb3, // lsg global[b3] 0x35, 0x0d, // ldi 0d @@ -1879,6 +2095,50 @@ static const SciScriptPatcherEntry mothergoose256Signatures[] = { // =========================================================================== // Police Quest 1 VGA + +// When briefing is about to start in room 15, other officers will get into the room too. +// When one of those officers gets into the way of ego, they will tell the player to sit down. +// But control will be disabled right at that point. Ego may then go to his seat by himself, +// or more often than not will just stand there. The player is unable to do anything. +// +// Sergeant Dooley will then enter the room. Tell the player to sit down 3 times and after +// that it's game over. +// +// Because the Sergeant is telling the player to sit down, one has to assume that the player +// is meant to still be in control. Which is why this script patch removes disabling of player control. +// +// The script also tries to make ego walk to the chair, but it fails because it gets stuck with other +// actors. So I guess the safest way is to remove all of that and let the player do it manually. +// +// The responsible method seems to use a few hardcoded texts, which is why I have to assume that it's +// not used anywhere else. I also checked all scripts and couldn't find any other calls to it. +// +// This of course also happens when using the original interpreter. +// +// Scripts work like this: manX::doit (script 134) triggers gab::changeState, which then triggers rm015::notify +// +// Applies to at least: English floppy +// Responsible method: gab::changeState (script 152) +// Fixes bug: #5865 +static const uint16 pq1vgaSignatureBriefingGettingStuck[] = { + 0x76, // push0 + 0x45, 0x02, 0x00, // call export 2 of script 0 (disable control) + 0x38, SIG_ADDTOOFFSET(+2), // pushi notify + 0x76, // push0 + 0x81, 0x02, // lag global[2] (get current room) + 0x4a, 0x04, // send 04 + SIG_MAGICDWORD, + 0x8b, 0x02, // lsl local[2] + 0x35, 0x01, // ldi 01 + 0x02, // add + SIG_END +}; + +static const uint16 pq1vgaPatchBriefingGettingStuck[] = { + 0x33, 0x0a, // jmp to lsl local[2], skip over export 2 and ::notify + PATCH_END // rm015::notify would try to make ego walk to the chair +}; + // When at the police station, you can put or get your gun from your locker. // The script, that handles this, is buggy. It disposes the gun as soon as // you click, but then waits 2 seconds before it also closes the locker. @@ -1966,10 +2226,11 @@ static const uint16 pq1vgaPatchMapSaveRestoreBug[] = { PATCH_END }; -// script, description, signature patch +// script, description, signature patch static const SciScriptPatcherEntry pq1vgaSignatures[] = { - { true, 341, "put gun in locker bug", 1, pq1vgaSignaturePutGunInLockerBug, pq1vgaPatchPutGunInLockerBug }, - { true, 500, "map save/restore bug", 2, pq1vgaSignatureMapSaveRestoreBug, pq1vgaPatchMapSaveRestoreBug }, + { true, 152, "getting stuck while briefing is about to start", 1, pq1vgaSignatureBriefingGettingStuck, pq1vgaPatchBriefingGettingStuck }, + { true, 341, "put gun in locker bug", 1, pq1vgaSignaturePutGunInLockerBug, pq1vgaPatchPutGunInLockerBug }, + { true, 500, "map save/restore bug", 2, pq1vgaSignatureMapSaveRestoreBug, pq1vgaPatchMapSaveRestoreBug }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -2673,14 +2934,75 @@ static const uint16 qfg3PatchChiefPriority[] = { PATCH_END }; +// Partly WORKAROUND: +// During combat, the game is not properly throttled. That's because the game uses +// an inner loop for combat and does not iterate through the main loop. +// It also doesn't call kGameIsRestarting. This may get fixed properly at some point +// by rewriting the speed throttler. +// +// Additionally Sierra set the cycle speed of the hero to 0. Which explains +// why the actions of the hero are so incredibly fast. This issue also happened +// in the original interpreter, when the computer was too powerful. +// +// Applies to at least: English, French, German, Italian, Spanish PC floppy +// Responsible method: combatControls::dispatchEvent (script 550) + WarriorObj in heap +// Fixes bug #6247 +static const uint16 qfg3SignatureCombatSpeedThrottling1[] = { + 0x31, 0x0d, // bnt [skip code] + SIG_MAGICDWORD, + 0x89, 0xd2, // lsg global[D2h] + 0x35, 0x00, // ldi 0 + 0x1e, // gt? + 0x31, 0x06, // bnt [skip code] + 0xe1, 0xd2, // -ag global[D2h] (jump skips over this) + 0x81, 0x58, // lag global[58h] + 0xa3, 0x01, // sal local[01] + SIG_END +}; + +static const uint16 qfg3PatchCombatSpeedThrottling1[] = { + 0x80, 0xd2, // lsg global[D2h] + 0x14, // or + 0x31, 0x06, // bnt [skip code] - saves 4 bytes + 0xe1, 0xd2, // -ag global[D2h] + 0x81, 0x58, // lag global[58h] + 0xa3, 0x01, // sal local[01] (jump skips over this) + // our code + 0x76, // push0 + 0x43, 0x2c, 0x00, // callk GameIsRestarting <-- add this so that our speed throttler is triggered + PATCH_END +}; + +static const uint16 qfg3SignatureCombatSpeedThrottling2[] = { + SIG_MAGICDWORD, + SIG_UINT16(12), // priority 12 + SIG_UINT16(0), // underbits 0 + SIG_UINT16(0x4010), // signal 4010h + SIG_ADDTOOFFSET(+18), + SIG_UINT16(0), // scaleSignal 0 + SIG_UINT16(128), // scaleX + SIG_UINT16(128), // scaleY + SIG_UINT16(128), // maxScale + SIG_UINT16(0), // cycleSpeed + SIG_END +}; + +static const uint16 qfg3PatchCombatSpeedThrottling2[] = { + PATCH_ADDTOOFFSET(+32), + PATCH_UINT16(5), // set cycleSpeed to 5 + PATCH_END +}; + // script, description, signature patch static const SciScriptPatcherEntry qfg3Signatures[] = { - { true, 944, "import dialog continuous calls", 1, qfg3SignatureImportDialog, qfg3PatchImportDialog }, - { true, 440, "dialog crash when asking about Woo", 1, qfg3SignatureWooDialog, qfg3PatchWooDialog }, - { true, 440, "dialog crash when asking about Woo", 1, qfg3SignatureWooDialogAlt, qfg3PatchWooDialogAlt }, - { true, 52, "export character save bug", 2, qfg3SignatureExportChar, qfg3PatchExportChar }, - { true, 54, "import character from QfG1 bug", 1, qfg3SignatureImportQfG1Char, qfg3PatchImportQfG1Char }, - { true, 640, "chief in hut priority fix", 1, qfg3SignatureChiefPriority, qfg3PatchChiefPriority }, + { true, 944, "import dialog continuous calls", 1, qfg3SignatureImportDialog, qfg3PatchImportDialog }, + { true, 440, "dialog crash when asking about Woo", 1, qfg3SignatureWooDialog, qfg3PatchWooDialog }, + { true, 440, "dialog crash when asking about Woo", 1, qfg3SignatureWooDialogAlt, qfg3PatchWooDialogAlt }, + { true, 52, "export character save bug", 2, qfg3SignatureExportChar, qfg3PatchExportChar }, + { true, 54, "import character from QfG1 bug", 1, qfg3SignatureImportQfG1Char, qfg3PatchImportQfG1Char }, + { true, 640, "chief in hut priority fix", 1, qfg3SignatureChiefPriority, qfg3PatchChiefPriority }, + { true, 550, "combat speed throttling script", 1, qfg3SignatureCombatSpeedThrottling1, qfg3PatchCombatSpeedThrottling1 }, + { true, 550, "combat speed throttling heap", 1, qfg3SignatureCombatSpeedThrottling2, qfg3PatchCombatSpeedThrottling2 }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -2836,6 +3158,66 @@ static const uint16 sq4CdPatchGetPointsForChangingBackClothes[] = { PATCH_END }; + +// For Space Quest 4 CD, Sierra added a pick up animation for Roger, when he picks up the rope. +// +// When the player is detected by the zombie right at the start of the game, while picking up the rope, +// scripts bomb out. This also happens, when using the original interpreter. +// +// This is caused by code, that's supposed to make Roger face the arriving drone. +// We fix it, by checking if ego::cycler is actually set before calling that code. +// +// Applies to at least: English PC CD +// Responsible method: droidShoots::changeState(3) +// Fixes bug: #6076 +static const uint16 sq4CdSignatureGettingShotWhileGettingRope[] = { + 0x35, 0x02, // ldi 02 + 0x65, 0x1a, // aTop cycles + 0x32, SIG_UINT16(0x02fa), // jmp [end] + SIG_MAGICDWORD, + 0x3c, // dup + 0x35, 0x02, // ldi 02 + 0x1a, // eq? + 0x31, 0x0b, // bnt [state 3 check] + 0x76, // push0 + 0x45, 0x02, 0x00, // call export 2 of script 0 -> disable controls + 0x35, 0x02, // ldi 02 + 0x65, 0x1a, // aTop cycles + 0x32, SIG_UINT16(0x02e9), // jmp [end] + 0x3c, // dup + 0x35, 0x03, // ldi 03 + 0x1a, // eq? + 0x31, 0x1e, // bnt [state 4 check] + 0x76, // push0 + 0x45, 0x02, 0x00, // call export 2 of script 0 -> disable controls again?? + 0x7a, // push2 + 0x89, 0x00, // lsg global[0] + 0x72, SIG_UINT16(0x0242), // lofsa deathDroid + 0x36, // push + 0x45, 0x0d, 0x04, // call export 13 of script 0 -> set heading of ego to face droid + SIG_END +}; + +static const uint16 sq4CdPatchGettingShotWhileGettingRope[] = { + PATCH_ADDTOOFFSET(+11), + // this makes state 2 only do the 2 cycles wait, controls should always be disabled already at this point + 0x2f, 0xf3, // bt [previous state aTop cycles code] + // Now we check for state 3, this change saves us 11 bytes + 0x3c, // dup + 0x35, 0x03, // ldi 03 + 0x1a, // eq? + 0x31, 0x29, // bnt [state 4 check] + // new state 3 code + 0x76, // push0 + 0x45, 0x02, 0x00, // call export 2 of script 0 (disable controls, actually not needed) + 0x38, PATCH_SELECTOR16(cycler), // pushi cycler + 0x76, // push0 + 0x81, 0x00, // lag global[0] + 0x4a, 0x04, // send 04 (get ego::cycler) + 0x30, PATCH_UINT16(10), // bnt [jump over heading call] + PATCH_END +}; + // The scripts in SQ4CD support simultaneous playing of speech and subtitles, // but this was not available as an option. The following two patches enable // this functionality in the game's GUI options dialog. @@ -2932,6 +3314,7 @@ static const SciScriptPatcherEntry sq4Signatures[] = { { true, 700, "Floppy: throw stuff at sequel police bug", 1, sq4FloppySignatureThrowStuffAtSequelPoliceBug, sq4FloppyPatchThrowStuffAtSequelPoliceBug }, { true, 45, "CD: walk in from below for room 45 fix", 1, sq4CdSignatureWalkInFromBelowRoom45, sq4CdPatchWalkInFromBelowRoom45 }, { true, 396, "CD: get points for changing back clothes fix",1, sq4CdSignatureGetPointsForChangingBackClothes, sq4CdPatchGetPointsForChangingBackClothes }, + { true, 701, "CD: getting shot, while getting rope", 1, sq4CdSignatureGettingShotWhileGettingRope, sq4CdPatchGettingShotWhileGettingRope }, { true, 0, "CD: Babble icon speech and subtitles fix", 1, sq4CdSignatureBabbleIcon, sq4CdPatchBabbleIcon }, { true, 818, "CD: Speech and subtitles option", 1, sq4CdSignatureTextOptions, sq4CdPatchTextOptions }, { true, 818, "CD: Speech and subtitles option button", 1, sq4CdSignatureTextOptionsButton, sq4CdPatchTextOptionsButton }, @@ -3374,20 +3757,20 @@ bool ScriptPatcher::verifySignature(uint32 byteOffset, const uint16 *signatureDa } // will return -1 if no match was found, otherwise an offset to the start of the signature match -int32 ScriptPatcher::findSignature(const SciScriptPatcherEntry *patchEntry, SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize) { +int32 ScriptPatcher::findSignature(uint32 magicDWord, int magicOffset, const uint16 *signatureData, const char *patchDescription, const byte *scriptData, const uint32 scriptSize) { if (scriptSize < 4) // we need to find a DWORD, so less than 4 bytes is not okay return -1; - const uint32 magicDWord = runtimeEntry->magicDWord; // is platform-specific BE/LE form, so that the later match will work + // magicDWord is in platform-specific BE/LE form, so that the later match will work, this was done for performance const uint32 searchLimit = scriptSize - 3; uint32 DWordOffset = 0; // first search for the magic DWORD while (DWordOffset < searchLimit) { if (magicDWord == READ_UINT32(scriptData + DWordOffset)) { // magic DWORD found, check if actual signature matches - uint32 offset = DWordOffset + runtimeEntry->magicOffset; + uint32 offset = DWordOffset + magicOffset; - if (verifySignature(offset, patchEntry->signatureData, patchEntry->description, scriptData, scriptSize)) + if (verifySignature(offset, signatureData, patchDescription, scriptData, scriptSize)) return offset; } DWordOffset++; @@ -3396,22 +3779,146 @@ int32 ScriptPatcher::findSignature(const SciScriptPatcherEntry *patchEntry, SciS return -1; } -// This method calculates the magic DWORD for each entry in the signature table -// and it also initializes the selector table for selectors used in the signatures/patches of the current game -void ScriptPatcher::initSignature(const SciScriptPatcherEntry *patchTable) { - const SciScriptPatcherEntry *curEntry = patchTable; - SciScriptPatcherRuntimeEntry *curRuntimeEntry; +int32 ScriptPatcher::findSignature(const SciScriptPatcherEntry *patchEntry, const SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize) { + return findSignature(runtimeEntry->magicDWord, runtimeEntry->magicOffset, patchEntry->signatureData, patchEntry->description, scriptData, scriptSize); +} + +// Attention: Magic DWord is returns using platform specific byte order. This is done on purpose for performance. +void ScriptPatcher::calculateMagicDWordAndVerify(const char *signatureDescription, const uint16 *signatureData, bool magicDWordIncluded, uint32 &calculatedMagicDWord, int &calculatedMagicDWordOffset) { Selector curSelector = -1; - int step; int magicOffset; byte magicDWord[4]; int magicDWordLeft = 0; - const uint16 *curData; uint16 curWord; uint16 curCommand; uint32 curValue; byte byte1 = 0; byte byte2 = 0; + + memset(magicDWord, 0, sizeof(magicDWord)); + + curWord = *signatureData; + magicOffset = 0; + while (curWord != SIG_END) { + curCommand = curWord & SIG_COMMANDMASK; + curValue = curWord & SIG_VALUEMASK; + switch (curCommand) { + case SIG_MAGICDWORD: { + if (magicDWordIncluded) { + if ((calculatedMagicDWord) || (magicDWordLeft)) + error("Script-Patcher: Magic-DWORD specified multiple times in signature\nFaulty patch: '%s'", signatureDescription); + magicDWordLeft = 4; + calculatedMagicDWordOffset = magicOffset; + } else { + error("Script-Patcher: Magic-DWORD sequence found in patch data\nFaulty patch: '%s'", signatureDescription); + } + break; + } + case SIG_CODE_ADDTOOFFSET: { + magicOffset -= curValue; + if (magicDWordLeft) + error("Script-Patcher: Magic-DWORD contains AddToOffset command\nFaulty patch: '%s'", signatureDescription); + break; + } + case SIG_CODE_UINT16: + case SIG_CODE_SELECTOR16: { + // UINT16 or 1 + switch (curCommand) { + case SIG_CODE_UINT16: { + signatureData++; curWord = *signatureData; + if (curWord & SIG_COMMANDMASK) + error("Script-Patcher: signature entry inconsistent\nFaulty patch: '%s'", signatureDescription); + if (!_isMacSci11) { + byte1 = curValue; + byte2 = curWord & SIG_BYTEMASK; + } else { + byte1 = curWord & SIG_BYTEMASK; + byte2 = curValue; + } + break; + } + case SIG_CODE_SELECTOR16: { + curSelector = _selectorIdTable[curValue]; + if (curSelector == -1) { + curSelector = g_sci->getKernel()->findSelector(selectorNameTable[curValue]); + _selectorIdTable[curValue] = curSelector; + } + if (!_isMacSci11) { + byte1 = curSelector & 0x00FF; + byte2 = curSelector >> 8; + } else { + byte1 = curSelector >> 8; + byte2 = curSelector & 0x00FF; + } + break; + } + } + magicOffset -= 2; + if (magicDWordLeft) { + // Remember current word for Magic DWORD + magicDWord[4 - magicDWordLeft] = byte1; + magicDWordLeft--; + if (magicDWordLeft) { + magicDWord[4 - magicDWordLeft] = byte2; + magicDWordLeft--; + } + if (!magicDWordLeft) { + // Magic DWORD is now known, convert to platform specific byte order + calculatedMagicDWord = READ_LE_UINT32(magicDWord); + } + } + break; + } + case SIG_CODE_BYTE: + case SIG_CODE_SELECTOR8: { + if (curCommand == SIG_CODE_SELECTOR8) { + curSelector = _selectorIdTable[curValue]; + if (curSelector == -1) { + curSelector = g_sci->getKernel()->findSelector(selectorNameTable[curValue]); + _selectorIdTable[curValue] = curSelector; + if (curSelector != -1) { + if (curSelector & 0xFF00) + error("Script-Patcher: 8 bit selector required, game uses 16 bit selector\nFaulty patch: '%s'", signatureDescription); + } + } + curValue = curSelector; + } + magicOffset--; + if (magicDWordLeft) { + // Remember current byte for Magic DWORD + magicDWord[4 - magicDWordLeft] = (byte)curValue; + magicDWordLeft--; + if (!magicDWordLeft) { + calculatedMagicDWord = READ_LE_UINT32(magicDWord); + } + } + break; + } + case PATCH_CODE_GETORIGINALBYTEADJUST: { + signatureData++; // skip over extra uint16 + break; + } + default: + break; + } + signatureData++; + curWord = *signatureData; + } + + if (magicDWordLeft) + error("Script-Patcher: Magic-DWORD beyond End-Of-Signature\nFaulty patch: '%s'", signatureDescription); + if (magicDWordIncluded) { + if (!calculatedMagicDWord) { + error("Script-Patcher: Magic-DWORD not specified in signature\nFaulty patch: '%s'", signatureDescription); + } + } +} + +// This method calculates the magic DWORD for each entry in the signature table +// and it also initializes the selector table for selectors used in the signatures/patches of the current game +void ScriptPatcher::initSignature(const SciScriptPatcherEntry *patchTable) { + const SciScriptPatcherEntry *curEntry = patchTable; + SciScriptPatcherRuntimeEntry *curRuntimeEntry; int patchEntryCount = 0; // Count entries and allocate runtime data @@ -3425,120 +3932,14 @@ void ScriptPatcher::initSignature(const SciScriptPatcherEntry *patchTable) { curRuntimeEntry = _runtimeTable; while (curEntry->signatureData) { // process signature - memset(magicDWord, 0, sizeof(magicDWord)); - curRuntimeEntry->active = curEntry->defaultActive; curRuntimeEntry->magicDWord = 0; curRuntimeEntry->magicOffset = 0; - for (step = 0; step < 2; step++) { - switch (step) { - case 0: curData = curEntry->signatureData; break; - case 1: curData = curEntry->patchData; break; - } - - curWord = *curData; - magicOffset = 0; - while (curWord != SIG_END) { - curCommand = curWord & SIG_COMMANDMASK; - curValue = curWord & SIG_VALUEMASK; - switch (curCommand) { - case SIG_MAGICDWORD: { - if (step == 0) { - if ((curRuntimeEntry->magicDWord) || (magicDWordLeft)) - error("Script-Patcher: Magic-DWORD specified multiple times in signature\nFaulty patch: '%s'", curEntry->description); - magicDWordLeft = 4; - curRuntimeEntry->magicOffset = magicOffset; - } - break; - } - case SIG_CODE_ADDTOOFFSET: { - magicOffset -= curValue; - if (magicDWordLeft) - error("Script-Patcher: Magic-DWORD contains AddToOffset command\nFaulty patch: '%s'", curEntry->description); - break; - } - case SIG_CODE_UINT16: - case SIG_CODE_SELECTOR16: { - // UINT16 or 1 - switch (curCommand) { - case SIG_CODE_UINT16: { - curData++; curWord = *curData; - if (curWord & SIG_COMMANDMASK) - error("Script-Patcher: signature entry inconsistent\nFaulty patch: '%s'", curEntry->description); - if (!_isMacSci11) { - byte1 = curValue; - byte2 = curWord & SIG_BYTEMASK; - } else { - byte1 = curWord & SIG_BYTEMASK; - byte2 = curValue; - } - break; - } - case SIG_CODE_SELECTOR16: { - curSelector = _selectorIdTable[curValue]; - if (curSelector == -1) { - curSelector = g_sci->getKernel()->findSelector(selectorNameTable[curValue]); - _selectorIdTable[curValue] = curSelector; - } - if (!_isMacSci11) { - byte1 = curSelector & 0x00FF; - byte2 = curSelector >> 8; - } else { - byte1 = curSelector >> 8; - byte2 = curSelector & 0x00FF; - } - break; - } - } - magicOffset -= 2; - if (magicDWordLeft) { - // Remember current word for Magic DWORD - magicDWord[4 - magicDWordLeft] = byte1; - magicDWordLeft--; - if (magicDWordLeft) { - magicDWord[4 - magicDWordLeft] = byte2; - magicDWordLeft--; - } - if (!magicDWordLeft) { - curRuntimeEntry->magicDWord = READ_LE_UINT32(magicDWord); - } - } - break; - } - case SIG_CODE_BYTE: - case SIG_CODE_SELECTOR8: { - if (curCommand == SIG_CODE_SELECTOR8) { - curSelector = _selectorIdTable[curValue]; - if (curSelector == -1) { - curSelector = g_sci->getKernel()->findSelector(selectorNameTable[curValue]); - _selectorIdTable[curValue] = curSelector; - if (curSelector != -1) { - if (curSelector & 0xFF00) - error("Script-Patcher: 8 bit selector required, game uses 16 bit selector\nFaulty patch: '%s'", curEntry->description); - } - } - curValue = curSelector; - } - magicOffset--; - if (magicDWordLeft) { - // Remember current byte for Magic DWORD - magicDWord[4 - magicDWordLeft] = (byte)curValue; - magicDWordLeft--; - if (!magicDWordLeft) { - curRuntimeEntry->magicDWord = READ_LE_UINT32(magicDWord); - } - } - } - } - curData++; - curWord = *curData; - } - } - if (magicDWordLeft) - error("Script-Patcher: Magic-DWORD beyond End-Of-Signature\nFaulty patch: '%s'", curEntry->description); - if (!curRuntimeEntry->magicDWord) - error("Script-Patcher: Magic-DWORD not specified in signature\nFaulty patch: '%s'", curEntry->description); + // We verify the signature data and remember the calculated magic DWord from the signature data + calculateMagicDWordAndVerify(curEntry->description, curEntry->signatureData, true, curRuntimeEntry->magicDWord, curRuntimeEntry->magicOffset); + // We verify the patch data + calculateMagicDWordAndVerify(curEntry->description, curEntry->patchData, false, curRuntimeEntry->magicDWord, curRuntimeEntry->magicOffset); curEntry++; curRuntimeEntry++; } @@ -3596,6 +3997,9 @@ void ScriptPatcher::processScript(uint16 scriptNr, byte *scriptData, const uint3 case GID_KQ6: signatureTable = kq6Signatures; break; + case GID_LAURABOW: + signatureTable = laurabow1Signatures; + break; case GID_LAURABOW2: signatureTable = laurabow2Signatures; break; diff --git a/engines/sci/engine/script_patches.h b/engines/sci/engine/script_patches.h index d15fce321b..645e0946b3 100644 --- a/engines/sci/engine/script_patches.h +++ b/engines/sci/engine/script_patches.h @@ -90,13 +90,32 @@ public: ScriptPatcher(); ~ScriptPatcher(); + // Calculates the magic DWord for fast search and verifies signature/patch data + // Returns the magic DWord in platform-specific byte-order. This is done on purpose for performance. + void calculateMagicDWordAndVerify(const char *signatureDescription, const uint16 *signatureData, bool magicDWordIncluded, uint32 &calculatedMagicDWord, int &calculatedMagicDWordOffset); + + // Called when a script is loaded to check for signature matches and apply patches in such cases void processScript(uint16 scriptNr, byte *scriptData, const uint32 scriptSize); + + // Verifies, if a given signature matches the given script data (pointed to by additional byte offset) bool verifySignature(uint32 byteOffset, const uint16 *signatureData, const char *signatureDescription, const byte *scriptData, const uint32 scriptSize); + // searches for a given signature inside script data + // returns -1 in case it was not found or an offset to the matching data + int32 findSignature(uint32 magicDWord, int magicOffset, const uint16 *signatureData, const char *patchDescription, const byte *scriptData, const uint32 scriptSize); + private: + // Initializes a patch table and creates run time information for it (for enabling/disabling), also calculates magic DWORD) void initSignature(const SciScriptPatcherEntry *patchTable); + + // Enables a patch inside the patch table (used for optional patches like CD+Text support for KQ6 & LB2) void enablePatch(const SciScriptPatcherEntry *patchTable, const char *searchDescription); - int32 findSignature(const SciScriptPatcherEntry *patchEntry, SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize); + + // Searches for a given signature entry inside script data + // returns -1 in case it was not found or an offset to the matching data + int32 findSignature(const SciScriptPatcherEntry *patchEntry, const SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize); + + // Applies a patch to a given script + offset (overwrites parts) void applyPatch(const SciScriptPatcherEntry *patchEntry, byte *scriptData, const uint32 scriptSize, int32 signatureOffset); Selector *_selectorIdTable; diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index f0157a6569..7d70f30d55 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -499,7 +499,7 @@ void Kernel::dumpScriptClass(char *data, int seeker, int objsize) { void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) { int objectctr[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - unsigned int _seeker = 0; + uint32 _seeker = 0; Resource *script = _resMan->findResource(ResourceId(kResourceTypeScript, scriptNumber), 0); if (!script) { @@ -510,7 +510,7 @@ void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) { while (_seeker < script->size) { int objType = (int16)READ_SCI11ENDIAN_UINT16(script->data + _seeker); int objsize; - unsigned int seeker = _seeker + 4; + uint32 seeker = _seeker + 4; if (!objType) { debugN("End of script object (#0) encountered.\n"); diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index 23b1fdae23..8090b1861d 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -837,10 +837,13 @@ byte *SegManager::allocDynmem(int size, const char *descr, reg_t *addr) { d._size = size; - if (size == 0) + // Original SCI only zeroed out heap memory on initialize + // They didn't do it again for every allocation + if (size) { + d._buf = (byte *)calloc(size, 1); + } else { d._buf = NULL; - else - d._buf = (byte *)malloc(size); + } d._description = descr; diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index de7f60ac16..2699bc2e5b 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -203,7 +203,7 @@ struct List { struct Hunk { void *mem; - unsigned int size; + uint32 size; const char *type; }; diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp index 910f1f885f..ac621f58ae 100644 --- a/engines/sci/engine/selector.cpp +++ b/engines/sci/engine/selector.cpp @@ -179,6 +179,8 @@ void Kernel::mapSelectors() { FIND_SELECTOR(fore); FIND_SELECTOR(back); FIND_SELECTOR(skip); + FIND_SELECTOR(borderColor); + FIND_SELECTOR(width); FIND_SELECTOR(fixPriority); FIND_SELECTOR(mirrored); FIND_SELECTOR(visible); @@ -187,6 +189,17 @@ void Kernel::mapSelectors() { FIND_SELECTOR(inLeft); FIND_SELECTOR(inBottom); FIND_SELECTOR(inRight); + FIND_SELECTOR(textTop); + FIND_SELECTOR(textLeft); + FIND_SELECTOR(textBottom); + FIND_SELECTOR(textRight); + FIND_SELECTOR(title); + FIND_SELECTOR(titleFont); + FIND_SELECTOR(titleFore); + FIND_SELECTOR(titleBack); + FIND_SELECTOR(magnifier); + FIND_SELECTOR(frameOut); + FIND_SELECTOR(casts); #endif } @@ -199,6 +212,16 @@ reg_t readSelector(SegManager *segMan, reg_t object, Selector selectorId) { return *address.getPointer(segMan); } +#ifdef ENABLE_SCI32 +void updateInfoFlagViewVisible(Object *obj, int index) { + // TODO: Make this correct for all SCI versions + // Selectors 26 through 44 are selectors for View script objects in SQ6 + if (index >= 26 && index <= 44 && getSciVersion() >= SCI_VERSION_2) { + obj->setInfoSelectorFlag(kInfoFlagViewVisible); + } +} +#endif + void writeSelector(SegManager *segMan, reg_t object, Selector selectorId, reg_t value) { ObjVarRef address; @@ -211,8 +234,12 @@ void writeSelector(SegManager *segMan, reg_t object, Selector selectorId, reg_t if (lookupSelector(segMan, object, selectorId, &address, NULL) != kSelectorVariable) error("Selector '%s' of object at %04x:%04x could not be" " written to", g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object)); - else + else { *address.getPointer(segMan) = value; +#ifdef ENABLE_SCI32 + updateInfoFlagViewVisible(segMan->getObject(object), selectorId); +#endif + } } void invokeSelector(EngineState *s, reg_t object, int selectorId, diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h index b3dd393708..f2d06d1cf4 100644 --- a/engines/sci/engine/selector.h +++ b/engines/sci/engine/selector.h @@ -146,6 +146,8 @@ struct SelectorCache { Selector back; Selector skip; Selector dimmed; + Selector borderColor; + Selector width; Selector fixPriority; Selector mirrored; @@ -153,6 +155,12 @@ struct SelectorCache { Selector useInsetRect; Selector inTop, inLeft, inBottom, inRight; + Selector textTop, textLeft, textBottom, textRight; + Selector title, titleFont, titleFore, titleBack; + + Selector magnifier; + Selector frameOut; + Selector casts; // needed for sync'ing screen items/planes with scripts, when our save/restore code is patched in (see GfxFrameout::syncWithScripts) #endif }; @@ -191,6 +199,16 @@ void writeSelector(SegManager *segMan, reg_t object, Selector selectorId, reg_t void invokeSelector(EngineState *s, reg_t object, int selectorId, int k_argc, StackPtr k_argp, int argc = 0, const reg_t *argv = 0); +#ifdef ENABLE_SCI32 +/** + * SCI32 set kInfoFlagViewVisible in the -info- selector if a certain + * range of properties was written to. + * This function checks if index is in the right range, and sets the flag + * on obj.-info- if it is. + */ +void updateInfoFlagViewVisible(Object *obj, int index); +#endif + } // End of namespace Sci #endif // SCI_ENGINE_KERNEL_H diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index d53e6b48c8..fda78317b5 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -95,6 +95,7 @@ void EngineState::reset(bool isRestoring) { // reset delayed restore game functionality _delayedRestoreGame = false; _delayedRestoreGameId = 0; + _delayedRestoreFromLauncher = false; executionStackBase = 0; _executionStackPosChanged = false; diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index 0f04e32fe5..cf9a753f5c 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -138,10 +138,12 @@ public: // see detection.cpp / SciEngine::loadGameState() bool _delayedRestoreGame; // boolean, that triggers delayed restore (triggered by ScummVM menu) int _delayedRestoreGameId; // the saved game id, that it supposed to get restored (triggered by ScummVM menu) + bool _delayedRestoreFromLauncher; // is set, when the the delayed restore game was triggered from launcher uint _chosenQfGImportItem; // Remembers the item selected in QfG import rooms bool _cursorWorkaroundActive; // Refer to GfxCursor::setPosition() + int16 _cursorWorkaroundPosCount; // When the cursor is reported to be at the previously set coordinate, we won't disable the workaround unless it happened for this many times Common::Point _cursorWorkaroundPoint; Common::Rect _cursorWorkaroundRect; diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 3729fc5236..64e6c045db 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -258,6 +258,10 @@ static void _exec_varselectors(EngineState *s) { if (xs.argc) { // write? *var = xs.variables_argp[1]; +#ifdef ENABLE_SCI32 + updateInfoFlagViewVisible(s->_segMan->getObject(xs.addr.varp.obj), xs.addr.varp.varindex); +#endif + } else // No, read s->r_acc = *var; } @@ -1095,6 +1099,9 @@ void run_vm(EngineState *s) { case op_aTop: // 0x32 (50) // Accumulator To Property validate_property(s, obj, opparams[0]) = s->r_acc; +#ifdef ENABLE_SCI32 + updateInfoFlagViewVisible(obj, opparams[0]>>1); +#endif break; case op_pTos: // 0x33 (51) @@ -1105,6 +1112,9 @@ void run_vm(EngineState *s) { case op_sTop: // 0x34 (52) // Stack To Property validate_property(s, obj, opparams[0]) = POP32(); +#ifdef ENABLE_SCI32 + updateInfoFlagViewVisible(obj, opparams[0]>>1); +#endif break; case op_ipToa: // 0x35 (53) @@ -1119,7 +1129,9 @@ void run_vm(EngineState *s) { opProperty += 1; else opProperty -= 1; - +#ifdef ENABLE_SCI32 + updateInfoFlagViewVisible(obj, opparams[0]>>1); +#endif if (opcode == op_ipToa || opcode == op_dpToa) s->r_acc = opProperty; else diff --git a/engines/sci/engine/vm_types.cpp b/engines/sci/engine/vm_types.cpp index cf008c45e1..d74e2b194c 100644 --- a/engines/sci/engine/vm_types.cpp +++ b/engines/sci/engine/vm_types.cpp @@ -210,12 +210,30 @@ reg_t reg_t::operator^(const reg_t right) const { return lookForWorkaround(right, "bitwise XOR"); } +#ifdef ENABLE_SCI32 +reg_t reg_t::operator&(int16 right) const { + return *this & make_reg(0, right); +} + +reg_t reg_t::operator|(int16 right) const { + return *this | make_reg(0, right); +} + +reg_t reg_t::operator^(int16 right) const { + return *this ^ make_reg(0, right); +} +#endif + int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const { if (getSegment() == right.getSegment()) { // can compare things in the same segment if (treatAsUnsigned || !isNumber()) return toUint16() - right.toUint16(); else return toSint16() - right.toSint16(); +#ifdef ENABLE_SCI32 + } else if (getSciVersion() >= SCI_VERSION_2) { + return sci32Comparison(right); +#endif } else if (pointerComparisonWithInteger(right)) { return 1; } else if (right.pointerComparisonWithInteger(*this)) { @@ -224,6 +242,26 @@ int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const { return lookForWorkaround(right, "comparison").toSint16(); } +#ifdef ENABLE_SCI32 +int reg_t::sci32Comparison(const reg_t right) const { + // In SCI32, MemIDs are normally indexes into the memory manager's handle + // list, but the engine reserves indexes at and above 20000 for objects + // that were created inside the engine (as opposed to inside the VM). The + // engine compares these as a tiebreaker for graphics objects that are at + // the same priority, and it is necessary to at least minimally handle + // this situation. + // This is obviously a bogus comparision, but then, this entire thing is + // bogus. For the moment, it just needs to be deterministic. + if (isNumber() && !right.isNumber()) { + return 1; + } else if (right.isNumber() && !isNumber()) { + return -1; + } + + return getOffset() - right.getOffset(); +} +#endif + bool reg_t::pointerComparisonWithInteger(const reg_t right) const { // This function handles the case where a script tries to compare a pointer // to a number. Normally, we would not want to allow that. However, SCI0 - diff --git a/engines/sci/engine/vm_types.h b/engines/sci/engine/vm_types.h index af78bd0b84..e60f52e85c 100644 --- a/engines/sci/engine/vm_types.h +++ b/engines/sci/engine/vm_types.h @@ -136,6 +136,19 @@ struct reg_t { reg_t operator|(const reg_t right) const; reg_t operator^(const reg_t right) const; +#ifdef ENABLE_SCI32 + reg_t operator&(int16 right) const; + reg_t operator|(int16 right) const; + reg_t operator^(int16 right) const; + + void operator&=(const reg_t &right) { *this = *this & right; } + void operator|=(const reg_t &right) { *this = *this | right; } + void operator^=(const reg_t &right) { *this = *this ^ right; } + void operator&=(int16 right) { *this = *this & right; } + void operator|=(int16 right) { *this = *this | right; } + void operator^=(int16 right) { *this = *this ^ right; } +#endif + private: /** * Compares two reg_t's. @@ -147,6 +160,10 @@ private: int cmp(const reg_t right, bool treatAsUnsigned) const; reg_t lookForWorkaround(const reg_t right, const char *operation) const; bool pointerComparisonWithInteger(const reg_t right) const; + +#ifdef ENABLE_SCI32 + int sci32Comparison(const reg_t right) const; +#endif }; static inline reg_t make_reg(SegmentId segment, uint16 offset) { diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index aab32032f7..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 }; @@ -630,7 +631,7 @@ const SciWorkaroundEntry kGraphUpdateBox_workarounds[] = { // gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround const SciWorkaroundEntry kIsObject_workarounds[] = { - { GID_GK1, 50, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // GK1 demo, when asking Grace for messages it gets called with an invalid parameter (type "error") - bug #4950 + { GID_GK1DEMO, 50, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // GK1 demo, when asking Grace for messages it gets called with an invalid parameter (type "error") - bug #4950 { GID_ISLANDBRAIN, -1, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // when going to the game options, choosing "Info" and selecting anything from the list, gets called with an invalid parameter (type "error") - bug #4989 { GID_QFG3, -1, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // when asking for something, gets called with type error parameter SCI_WORKAROUNDENTRY_TERMINATOR @@ -656,6 +657,12 @@ const SciWorkaroundEntry kNewWindow_workarounds[] = { }; // gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround +const SciWorkaroundEntry kPalVarySetPercent_workarounds[] = { + { GID_GK1, 370, 370, 0, "graceComeOut", "changeState", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // there's an extra parameter in GK1, when changing chapters. This extra parameter seems to be a bug or just unimplemented functionality, as there's no visible change from the original in the chapter change room + SCI_WORKAROUNDENTRY_TERMINATOR +}; + +// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround const SciWorkaroundEntry kReadNumber_workarounds[] = { { GID_CNICK_LAURABOW,100, 101, 0, "dominoes.opt", "doit", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // When dominoes.opt is present, the game scripts call kReadNumber with an extra integer parameter - bug #6425 { GID_HOYLE3, 100, 101, 0, "dominoes.opt", "doit", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // When dominoes.opt is present, the game scripts call kReadNumber with an extra integer parameter - bug #6425 @@ -664,7 +671,7 @@ const SciWorkaroundEntry kReadNumber_workarounds[] = { // gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround const SciWorkaroundEntry kPaletteUnsetFlag_workarounds[] = { - { GID_QFG4, 100, 100, 0, "doMovie", "changeState", NULL, 0, { WORKAROUND_IGNORE, 0 } }, // after the Sierra logo, no flags are passed, thus the call is meaningless - bug #4947 + { GID_QFG4DEMO, 100, 100, 0, "doMovie", "changeState", NULL, 0, { WORKAROUND_IGNORE, 0 } }, // after the Sierra logo, no flags are passed, thus the call is meaningless - bug #4947 SCI_WORKAROUNDENTRY_TERMINATOR }; diff --git a/engines/sci/engine/workarounds.h b/engines/sci/engine/workarounds.h index 46059a175c..8f519a8c9c 100644 --- a/engines/sci/engine/workarounds.h +++ b/engines/sci/engine/workarounds.h @@ -89,6 +89,7 @@ extern const SciWorkaroundEntry kIsObject_workarounds[]; extern const SciWorkaroundEntry kMemory_workarounds[]; extern const SciWorkaroundEntry kMoveCursor_workarounds[]; extern const SciWorkaroundEntry kNewWindow_workarounds[]; +extern const SciWorkaroundEntry kPalVarySetPercent_workarounds[]; extern const SciWorkaroundEntry kReadNumber_workarounds[]; extern const SciWorkaroundEntry kPaletteUnsetFlag_workarounds[]; extern const SciWorkaroundEntry kSetCursor_workarounds[]; diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp index f8285c26f2..34f1618514 100644 --- a/engines/sci/event.cpp +++ b/engines/sci/event.cpp @@ -29,6 +29,9 @@ #include "sci/console.h" #include "sci/engine/state.h" #include "sci/engine/kernel.h" +#ifdef ENABLE_SCI32 +#include "sci/graphics/frameout.h" +#endif #include "sci/graphics/screen.h" namespace Sci { @@ -44,7 +47,7 @@ static const ScancodeRow scancodeAltifyRows[] = { { 0x2c, "ZXCVBNM,./" } }; -static const byte codepagemap_88591toDOS[0x80] = { +static const byte codePageMap88591ToDOS[0x80] = { '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0x8x '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0x9x '?', 0xad, 0x9b, 0x9c, '?', 0x9d, '?', 0x9e, '?', '?', 0xa6, 0xae, 0xaa, '?', '?', '?', // 0xAx @@ -133,8 +136,13 @@ static int altify(int ch) { } SciEvent EventManager::getScummVMEvent() { - SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point(0, 0) }; - SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point(0, 0) }; +#ifdef ENABLE_SCI32 + SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() }; + SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() }; +#else + SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point() }; + SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point() }; +#endif Common::EventManager *em = g_system->getEventManager(); Common::Event ev; @@ -155,7 +163,20 @@ SciEvent EventManager::getScummVMEvent() { // via pollEvent. // We also adjust the position based on the scaling of the screen. Common::Point mousePos = em->getMousePos(); - g_sci->_gfxScreen->adjustBackUpscaledCoordinates(mousePos.y, mousePos.x); + +#if ENABLE_SCI32 + if (getSciVersion() >= SCI_VERSION_2) { + Buffer &screen = g_sci->_gfxFrameout->getCurrentBuffer(); + + Common::Point mousePosSci = mousePos; + mulru(mousePosSci, Ratio(screen.scriptWidth, screen.screenWidth), Ratio(screen.scriptHeight, screen.screenHeight)); + noEvent.mousePosSci = input.mousePosSci = mousePosSci; + } else { +#endif + g_sci->_gfxScreen->adjustBackUpscaledCoordinates(mousePos.y, mousePos.x); +#if ENABLE_SCI32 + } +#endif noEvent.mousePos = input.mousePos = mousePos; @@ -173,7 +194,7 @@ SciEvent EventManager::getScummVMEvent() { return input; } - int scummVMKeyFlags; + int scummVMKeyFlags; switch (ev.type) { case Common::EVENT_KEYDOWN: @@ -265,7 +286,7 @@ SciEvent EventManager::getScummVMEvent() { return noEvent; // Convert 8859-1 characters to DOS (cp850/437) for // multilingual SCI01 games - input.character = codepagemap_88591toDOS[input.character & 0x7f]; + input.character = codePageMap88591ToDOS[input.character & 0x7f]; } if (scummVMKeycode == Common::KEYCODE_TAB) { input.character = SCI_KEY_TAB; @@ -302,6 +323,11 @@ SciEvent EventManager::getScummVMEvent() { input.character = altify(input.character); if (getSciVersion() <= SCI_VERSION_1_MIDDLE && (scummVMKeyFlags & Common::KBD_CTRL) && input.character > 0 && input.character < 27) input.character += 96; // 0x01 -> 'a' +#ifdef ENABLE_SCI32 + if (getSciVersion() >= SCI_VERSION_2 && (scummVMKeyFlags & Common::KBD_CTRL) && input.character == 'c') { + input.character = SCI_KEY_ETX; + } +#endif // If no actual key was pressed (e.g. if only a modifier key was pressed), // ignore the event @@ -328,8 +354,12 @@ void EventManager::updateScreen() { } } -SciEvent EventManager::getSciEvent(unsigned int mask) { - SciEvent event = { SCI_EVENT_NONE, 0, 0, Common::Point(0, 0) }; +SciEvent EventManager::getSciEvent(uint32 mask) { +#ifdef ENABLE_SCI32 + SciEvent event = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() }; +#else + SciEvent event = { SCI_EVENT_NONE, 0, 0, Common::Point() }; +#endif EventManager::updateScreen(); @@ -342,7 +372,7 @@ SciEvent EventManager::getSciEvent(unsigned int mask) { // Search for matching event in queue Common::List<SciEvent>::iterator iter = _events.begin(); - while (iter != _events.end() && !((*iter).type & mask)) + while (iter != _events.end() && !(iter->type & mask)) ++iter; if (iter != _events.end()) { @@ -364,17 +394,17 @@ SciEvent EventManager::getSciEvent(unsigned int mask) { void SciEngine::sleep(uint32 msecs) { uint32 time; - const uint32 wakeup_time = g_system->getMillis() + msecs; + const uint32 wakeUpTime = g_system->getMillis() + msecs; while (true) { // let backend process events and update the screen _eventMan->getSciEvent(SCI_EVENT_PEEK); time = g_system->getMillis(); - if (time + 10 < wakeup_time) { + if (time + 10 < wakeUpTime) { g_system->delayMillis(10); } else { - if (time < wakeup_time) - g_system->delayMillis(wakeup_time - time); + if (time < wakeUpTime) + g_system->delayMillis(wakeUpTime - time); break; } diff --git a/engines/sci/event.h b/engines/sci/event.h index 76c884aba4..15a94b3e73 100644 --- a/engines/sci/event.h +++ b/engines/sci/event.h @@ -39,11 +39,18 @@ struct SciEvent { uint16 character; /** - * The mouse position at the time the event was created. - * - * These are display coordinates! + * The mouse position at the time the event was created, + * in display coordinates. */ Common::Point mousePos; + +#ifdef ENABLE_SCI32 + /** + * The mouse position at the time the event was created, + * in script coordinates. + */ + Common::Point mousePosSci; +#endif }; /*Values for type*/ @@ -59,6 +66,9 @@ struct SciEvent { #define SCI_EVENT_ANY 0x7fff /* Keycodes of special keys: */ +#ifdef ENABLE_SCI32 +#define SCI_KEY_ETX 3 +#endif #define SCI_KEY_ESC 27 #define SCI_KEY_BACKSPACE 8 #define SCI_KEY_ENTER 13 @@ -121,7 +131,7 @@ public: ~EventManager(); void updateScreen(); - SciEvent getSciEvent(unsigned int mask); + SciEvent getSciEvent(uint32 mask); private: SciEvent getScummVMEvent(); diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp index 7957ed6a55..98278397b7 100644 --- a/engines/sci/graphics/animate.cpp +++ b/engines/sci/graphics/animate.cpp @@ -28,6 +28,7 @@ #include "sci/sci.h" #include "sci/event.h" #include "sci/engine/kernel.h" +#include "sci/engine/script_patches.h" #include "sci/engine/state.h" #include "sci/engine/selector.h" #include "sci/engine/vm.h" @@ -44,8 +45,8 @@ namespace Sci { -GfxAnimate::GfxAnimate(EngineState *state, GfxCache *cache, GfxPorts *ports, GfxPaint16 *paint16, GfxScreen *screen, GfxPalette *palette, GfxCursor *cursor, GfxTransitions *transitions) - : _s(state), _cache(cache), _ports(ports), _paint16(paint16), _screen(screen), _palette(palette), _cursor(cursor), _transitions(transitions) { +GfxAnimate::GfxAnimate(EngineState *state, ScriptPatcher *scriptPatcher, GfxCache *cache, GfxPorts *ports, GfxPaint16 *paint16, GfxScreen *screen, GfxPalette *palette, GfxCursor *cursor, GfxTransitions *transitions) + : _s(state), _scriptPatcher(scriptPatcher), _cache(cache), _ports(ports), _paint16(paint16), _screen(screen), _palette(palette), _cursor(cursor), _transitions(transitions) { init(); } @@ -55,16 +56,77 @@ GfxAnimate::~GfxAnimate() { void GfxAnimate::init() { _lastCastData.clear(); - _ignoreFastCast = false; - // fastCast object is not found in any SCI games prior SCI1 - if (getSciVersion() <= SCI_VERSION_01) - _ignoreFastCast = true; - // Also if fastCast object exists at gamestartup, we can assume that the interpreter doesnt do kAnimate aborts - // (found in Larry 1) - if (getSciVersion() > SCI_VERSION_0_EARLY) { - if (!_s->_segMan->findObjectByName("fastCast").isNull()) - _ignoreFastCast = true; + _fastCastEnabled = false; + if (getSciVersion() == SCI_VERSION_1_1) { + // Seems to have been available for all SCI1.1 games + _fastCastEnabled = true; + } else if (getSciVersion() >= SCI_VERSION_1_EARLY) { + // fastCast only exists for some games between SCI1 early and SCI1 late + // Try to detect it by code signature + // It's extremely important, that we only enable it for games that actually need it + if (detectFastCast()) { + _fastCastEnabled = true; + } + } +} + +// Signature for fastCast detection +static const uint16 fastCastSignature[] = { + SIG_MAGICDWORD, + 0x35, 0x00, // ldi 00 + 0xa1, 84, // sag global[84d] + SIG_END +}; + +// Fast cast in games: + +// SCI1 Early: +// KQ5 - no fastcast, LSL1 (demo) - no fastcast, Mixed Up Fairy Tales - *has fastcast*, XMas Card 1990 - no fastcast, +// SQ4Floppy - no fastcast, Mixed Up Mother Goose - no fastcast +// +// SCI1 Middle: +// LSL5 demo - no fastfast, Conquest of the Longbow demo - no fastcast, LSL1 - no fastcast, +// Astro Chicken II - no fastcast +// +// SCI1 Late: +// Castle of Dr. Brain demo - has fastcast, Castle of Dr. Brain - has fastcast, +// Conquests of the Longbow - has fastcast, Space Quest 1 EGA - has fastcast, +// King's Quest 5 multilingual - *NO* fastcast, Police Quest 3 demo - *NO* fastcast, +// LSL5 multilingual - has fastcast, Police Quest 3 - has fastcast, +// EcoQuest 1 - has fastcast, Mixed Up Fairy Tales demo - has fastcast, +// Space Quest 4 multilingual - *NO* fastcast +// +// SCI1.1 +// Quest for Glory 3 demo - has fastcast, Police Quest 1 - hast fastcast, Quest for Glory 1 - has fastcast +// Laura Bow 2 Floppy - has fastcast, Mixed Up Mother Goose - has fastcast, Quest for Glory 3 - has fastcast +// Island of Dr. Brain - has fastcast, King's Quest 6 - has fastcast, Space Quest 5 - has fastcast +// Hoyle 4 - has fastcast, Laura Bow 2 CD - has fastcast, Freddy Pharkas CD - has fastcast +bool GfxAnimate::detectFastCast() { + SegManager *segMan = _s->_segMan; + const reg_t gameVMObject = g_sci->getGameObject(); + reg_t gameSuperVMObject = segMan->getObject(gameVMObject)->getSuperClassSelector(); + uint32 magicDWord = 0; // platform-specific BE/LE for performance + int magicDWordOffset = 0; + + if (gameSuperVMObject.isNull()) { + gameSuperVMObject = gameVMObject; // Just in case. According to sci.cpp this may happen in KQ5CD, when loading saved games before r54510 + } + + Script *objectScript = segMan->getScript(gameSuperVMObject.getSegment()); + byte *scriptData = const_cast<byte *>(objectScript->getBuf(0)); + uint32 scriptSize = objectScript->getBufSize(); + + _scriptPatcher->calculateMagicDWordAndVerify("fast cast detection", fastCastSignature, true, magicDWord, magicDWordOffset); + + // Signature is found for multilingual King's Quest 5 too, but it looks as if the fast cast global is never set + // within that game. Which means even though we detect it as having the capability, it's never actually used. + // The original multilingual KQ5 interpreter did have this feature disabled. + // Sierra probably used latest system scripts and that's why we detect it. + if (_scriptPatcher->findSignature(magicDWord, magicDWordOffset, fastCastSignature, "fast cast detection", scriptData, scriptSize) >= 0) { + // Signature found, game seems to use fast cast for kAnimate + return true; } + return false; } void GfxAnimate::disposeLastCast() { @@ -80,12 +142,14 @@ bool GfxAnimate::invoke(List *list, int argc, reg_t *argv) { while (curNode) { curObject = curNode->value; - if (!_ignoreFastCast) { + if (_fastCastEnabled) { // Check if the game has a fastCast object set // if we don't abort kAnimate processing, at least in kq5 there will be animation cels drawn into speech boxes. if (!_s->variables[VAR_GLOBAL][84].isNull()) { - if (!strcmp(_s->_segMan->getObjectName(_s->variables[VAR_GLOBAL][84]), "fastCast")) - return false; + // This normally points to an object called "fastCast", + // but for example in Eco Quest 1 it may also point to an object called "EventHandler" (see bug #5170) + // Original SCI only checked, if this global was not 0. + return false; } } diff --git a/engines/sci/graphics/animate.h b/engines/sci/graphics/animate.h index 6c1822c903..ac7078093c 100644 --- a/engines/sci/graphics/animate.h +++ b/engines/sci/graphics/animate.h @@ -87,9 +87,13 @@ class GfxView; */ class GfxAnimate { public: - GfxAnimate(EngineState *state, GfxCache *cache, GfxPorts *ports, GfxPaint16 *paint16, GfxScreen *screen, GfxPalette *palette, GfxCursor *cursor, GfxTransitions *transitions); + GfxAnimate(EngineState *state, ScriptPatcher *scriptPatcher, GfxCache *cache, GfxPorts *ports, GfxPaint16 *paint16, GfxScreen *screen, GfxPalette *palette, GfxCursor *cursor, GfxTransitions *transitions); virtual ~GfxAnimate(); + bool isFastCastEnabled() { + return _fastCastEnabled; + } + void disposeLastCast(); bool invoke(List *list, int argc, reg_t *argv); void makeSortedList(List *list); @@ -110,6 +114,7 @@ public: private: void init(); + bool detectFastCast(); void addToPicSetPicNotValid(); void animateShowPic(); @@ -119,6 +124,7 @@ private: void setNsRect(GfxView *view, AnimateList::iterator it); EngineState *_s; + ScriptPatcher *_scriptPatcher; GfxCache *_cache; GfxPorts *_ports; GfxPaint16 *_paint16; @@ -130,7 +136,7 @@ private: AnimateList _list; AnimateArray _lastCastData; - bool _ignoreFastCast; + bool _fastCastEnabled; }; } // End of namespace Sci 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 new file mode 100644 index 0000000000..693bc5f196 --- /dev/null +++ b/engines/sci/graphics/celobj32.cpp @@ -0,0 +1,1050 @@ +/* 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 "sci/resource.h" +#include "sci/engine/seg_manager.h" +#include "sci/engine/state.h" +#include "sci/graphics/celobj32.h" +#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" + +namespace Sci { +#pragma mark CelScaler +CelScaler *CelObj::_scaler = nullptr; + +void CelScaler::activateScaleTables(const Ratio &scaleX, const Ratio &scaleY) { + const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth; + const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight; + + for (int i = 0; i < ARRAYSIZE(_scaleTables); ++i) { + if (_scaleTables[i].scaleX == scaleX && _scaleTables[i].scaleY == scaleY) { + _activeIndex = i; + return; + } + } + + int i = 1 - _activeIndex; + _activeIndex = i; + CelScalerTable &table = _scaleTables[i]; + + if (table.scaleX != scaleX) { + assert(screenWidth <= ARRAYSIZE(table.valuesX)); + buildLookupTable(table.valuesX, scaleX, screenWidth); + table.scaleX = scaleX; + } + + if (table.scaleY != scaleY) { + assert(screenHeight <= ARRAYSIZE(table.valuesY)); + buildLookupTable(table.valuesY, scaleY, screenHeight); + table.scaleY = scaleY; + } +} + +void CelScaler::buildLookupTable(int *table, const Ratio &ratio, const int size) { + int value = 0; + int remainder = 0; + int num = ratio.getNumerator(); + for (int i = 0; i < size; ++i) { + *table++ = value; + remainder += ratio.getDenominator(); + if (remainder >= num) { + value += remainder / num; + remainder %= num; + } + } +} + +const CelScalerTable *CelScaler::getScalerTable(const Ratio &scaleX, const Ratio &scaleY) { + activateScaleTables(scaleX, scaleY); + return &_scaleTables[_activeIndex]; +} + +#pragma mark - +#pragma mark CelObj + +void CelObj::init() { + CelObj::deinit(); + _nextCacheId = 1; + _scaler = new CelScaler(); + _cache = new CelCache; + _cache->resize(100); +} + +void CelObj::deinit() { + delete _scaler; + _scaler = nullptr; + if (_cache != nullptr) { + for (CelCache::iterator it = _cache->begin(); it != _cache->end(); ++it) { + delete it->celObj; + } + } + delete _cache; + _cache = nullptr; +} + +#pragma mark - +#pragma mark CelObj - Scalers + +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, const Common::Point &scaledPosition) : + _reader(celObj, FLIP ? celObj._width : maxWidth), + _lastIndex(celObj._width - 1), + _sourceX(scaledPosition.x), + _sourceY(scaledPosition.y) {} + + inline void setTarget(const int16 x, const int16 y) { + _row = _reader.getRow(y - _sourceY); + + if (FLIP) { +#ifndef NDEBUG + _rowEdge = _row - 1; +#endif + _row += _lastIndex - (x - _sourceX); + assert(_row > _rowEdge); + } else { +#ifndef NDEBUG + _rowEdge = _row + _lastIndex + 1; +#endif + _row += x - _sourceX; + assert(_row < _rowEdge); + } + } + + inline byte read() { + assert(_row != _rowEdge); + + if (FLIP) { + return *_row--; + } else { + return *_row++; + } + } +}; + +template<bool FLIP, typename READER> +struct SCALER_Scale { +#ifndef NDEBUG + int16 _maxX; +#endif + const byte *_row; + READER _reader; + int16 _x; + static int16 _valuesX[1024]; + static int16 _valuesY[1024]; + + 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) { + // 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) { + int lastIndex = celObj._width - 1; + for (int16 x = targetRect.left; x < targetRect.right; ++x) { + _valuesX[x] = lastIndex - (table->valuesX[x] - unscaledX); + } + } else { + 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() { + 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; + } +}; + +struct READER_Compressed { +private: + byte *_resource; + byte _buffer[1024]; + uint32 _controlOffset; + uint32 _dataOffset; + uint32 _uncompressedDataOffset; + int16 _y; + const int16 _sourceHeight; + const uint8 _transparentColor; + const int16 _maxWidth; + +public: + READER_Compressed(const CelObj &celObj, const int16 maxWidth) : + _resource(celObj.getResPointer()), + _y(-1), + _sourceHeight(celObj._height), + _transparentColor(celObj._transparentColor), + _maxWidth(maxWidth) { + assert(maxWidth <= celObj._width); + + byte *celHeader = _resource + celObj._celHeaderOffset; + _dataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 24); + _uncompressedDataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 28); + _controlOffset = READ_SCI11ENDIAN_UINT32(celHeader + 32); + } + + 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); + + // uncompressed data segment for row + byte *literal = _resource + _uncompressedDataOffset + READ_SCI11ENDIAN_UINT32(_resource + _controlOffset + _sourceHeight * 4 + y * 4); + + uint8 length; + for (int16 i = 0; i < _maxWidth; i += length) { + byte controlByte = *row++; + length = controlByte; + + // Run-length encoded + if (controlByte & 0x80) { + length &= 0x3F; + assert(i + length < (int)sizeof(_buffer)); + + // Fill with skip color + if (controlByte & 0x40) { + memset(_buffer + i, _transparentColor, length); + // Next value is fill color + } else { + memset(_buffer + i, *literal, length); + ++literal; + } + // Uncompressed + } else { + assert(i + length < (int)sizeof(_buffer)); + memcpy(_buffer + i, literal, length); + literal += length; + } + } + _y = y; + } + + return _buffer; + } +}; + +#pragma mark - +#pragma mark CelObj - Remappers + +struct MAPPER_NoMD { + inline void draw(byte *target, const byte pixel, const uint8 skipColor) const { + if (pixel != skipColor) { + *target = pixel; + } + } +}; +struct MAPPER_NoMDNoSkip { + inline void draw(byte *target, const byte pixel, const uint8) const { + *target = pixel; + } +}; + +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 Common::Point &scaledPosition = screenItem._scaledPosition; + const Ratio &scaleX = screenItem._ratioX; + const Ratio &scaleY = screenItem._ratioY; + + if (_remap) { + // 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, targetRect, scaledPosition); + } else { + drawUncompNoFlipMap(target, targetRect, scaledPosition); + } + } else { + if (_drawMirrored) { + drawHzFlipMap(target, targetRect, scaledPosition); + } else { + drawNoFlipMap(target, targetRect, scaledPosition); + } + } + } else { + if (_compressionType == kCelCompressionNone) { + scaleDrawUncompMap(target, scaleX, scaleY, targetRect, scaledPosition); + } else { + scaleDrawMap(target, scaleX, scaleY, 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); + } + } + } else { + if (_compressionType == kCelCompressionNone) { + scaleDrawUncomp(target, scaleX, scaleY, targetRect, scaledPosition); + } else { + scaleDraw(target, scaleX, scaleY, 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); + } + } + } else { + if (_compressionType == kCelCompressionNone) { + scaleDrawUncompNoMD(target, scaleX, scaleY, targetRect, scaledPosition); + } else { + scaleDrawNoMD(target, scaleX, scaleY, targetRect, scaledPosition); + } + } + } +} + +void CelObj::draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, bool mirrorX) { + _drawMirrored = mirrorX; + draw(target, screenItem, targetRect); +} + +void CelObj::draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) { + _drawMirrored = mirrorX; + Ratio square; + drawTo(target, targetRect, scaledPosition, square, square); +} + +void CelObj::drawTo(Buffer &target, Common::Rect const &targetRect, Common::Point const &scaledPosition, Ratio const &scaleX, Ratio const &scaleY) const { + if (_remap) { + if (scaleX.isOne() && scaleY.isOne()) { + if (_compressionType == kCelCompressionNone) { + if (_drawMirrored) { + drawUncompHzFlipMap(target, targetRect, scaledPosition); + } else { + drawUncompNoFlipMap(target, targetRect, scaledPosition); + } + } else { + if (_drawMirrored) { + drawHzFlipMap(target, targetRect, scaledPosition); + } else { + drawNoFlipMap(target, targetRect, scaledPosition); + } + } + } else { + if (_compressionType == kCelCompressionNone) { + scaleDrawUncompMap(target, scaleX, scaleY, targetRect, scaledPosition); + } else { + scaleDrawMap(target, scaleX, scaleY, targetRect, scaledPosition); + } + } + } else { + if (scaleX.isOne() && scaleY.isOne()) { + if (_compressionType == kCelCompressionNone) { + if (_drawMirrored) { + drawUncompHzFlipNoMD(target, targetRect, scaledPosition); + } else { + drawUncompNoFlipNoMD(target, targetRect, scaledPosition); + } + } else { + if (_drawMirrored) { + drawHzFlipNoMD(target, targetRect, scaledPosition); + } else { + drawNoFlipNoMD(target, targetRect, scaledPosition); + } + } + } else { + if (_compressionType == kCelCompressionNone) { + scaleDrawUncompNoMD(target, scaleX, scaleY, targetRect, scaledPosition); + } else { + scaleDrawNoMD(target, scaleX, scaleY, targetRect, scaledPosition); + } + } + } +} + +uint8 CelObj::readPixel(uint16 x, const uint16 y, bool mirrorX) const { + if (mirrorX) { + x = _width - x - 1; + } + + if (_compressionType == kCelCompressionNone) { + READER_Uncompressed reader(*this, x + 1); + return reader.getRow(y)[x]; + } else { + READER_Compressed reader(*this, x + 1); + return reader.getRow(y)[x]; + } +} + +void CelObj::submitPalette() const { + if (_hunkPaletteOffset) { + Palette palette; + + byte *res = getResPointer(); + // NOTE: In SCI engine this uses HunkPalette::Init. + // TODO: Use a better size value + g_sci->_gfxPalette32->createFromData(res + _hunkPaletteOffset, 999999, &palette); + g_sci->_gfxPalette32->submit(palette); + } +} + +#pragma mark - +#pragma mark CelObj - Caching +int CelObj::_nextCacheId = 1; +CelCache *CelObj::_cache = nullptr; + +int CelObj::searchCache(const CelInfo32 &celInfo, int *nextInsertIndex) const { + int oldestId = _nextCacheId + 1; + int oldestIndex = -1; + + for (int i = 0, len = _cache->size(); i < len; ++i) { + CelCacheEntry &entry = (*_cache)[i]; + + if (entry.celObj != nullptr) { + if (entry.celObj->_info == celInfo) { + entry.id = ++_nextCacheId; + return i; + } + + if (oldestId > entry.id) { + oldestId = entry.id; + oldestIndex = i; + } + } else if (oldestIndex == -1) { + oldestIndex = i; + } + } + + // NOTE: Unlike the original SCI engine code, the out-param + // here is only updated if there was not a cache hit. + *nextInsertIndex = oldestIndex; + return -1; +} + +void CelObj::putCopyInCache(const int cacheIndex) const { + if (cacheIndex == -1) { + error("Invalid cache index"); + } + + CelCacheEntry &entry = (*_cache)[cacheIndex]; + + if (entry.celObj != nullptr) { + delete entry.celObj; + } + + entry.celObj = duplicate(); + entry.id = ++_nextCacheId; +} + +#pragma mark - +#pragma mark CelObj - Drawing + +template<typename MAPPER, typename SCALER> +struct RENDERER { + MAPPER &_mapper; + SCALER &_scaler; + const uint8 _skipColor; + + RENDERER(MAPPER &mapper, SCALER &scaler, const uint8 skipColor) : + _mapper(mapper), + _scaler(scaler), + _skipColor(skipColor) {} + + inline void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const { + 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 (int16 y = 0; y < targetHeight; ++y) { + _scaler.setTarget(targetRect.left, targetRect.top + y); + + for (int16 x = 0; x < targetWidth; ++x) { + _mapper.draw(targetPixel++, _scaler.read(), _skipColor); + } + + targetPixel += skipStride; + } + } +}; + +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(), scaledPosition); + RENDERER<MAPPER, SCALER> renderer(mapper, scaler, _transparentColor); + renderer.draw(target, targetRect, scaledPosition); +} + +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, scaledPosition, scaleX, scaleY); + RENDERER<MAPPER, SCALER> renderer(mapper, scaler, _transparentColor); + renderer.draw(target, targetRect, scaledPosition); +} + +void dummyFill(Buffer &target, const Common::Rect &targetRect) { + target.fillRect(targetRect, 250); +} + +void CelObj::drawHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + render<MAPPER_NoMD, SCALER_NoScale<false, READER_Compressed> >(target, targetRect, scaledPosition); +} + +void CelObj::drawHzFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const { + render<MAPPER_NoMD, SCALER_NoScale<true, READER_Compressed> >(target, targetRect, scaledPosition); +} + +void CelObj::drawUncompNoFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const { + render<MAPPER_NoMD, SCALER_NoScale<false, READER_Uncompressed> >(target, targetRect, scaledPosition); +} + +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) + render<MAPPER_NoMD, SCALER_Scale<true, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY); + 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) + render<MAPPER_NoMD, SCALER_Scale<true, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY); + else + render<MAPPER_NoMD, SCALER_Scale<false, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY); +} + +#pragma mark - +#pragma mark CelObjView +CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo) { + _info.type = kCelTypeView; + _info.resourceId = viewId; + _info.loopNo = loopNo; + _info.celNo = celNo; + _mirrorX = false; + _compressionType = kCelCompressionInvalid; + _transparent = true; + + int cacheInsertIndex; + int cacheIndex = searchCache(_info, &cacheInsertIndex); + if (cacheIndex != -1) { + CelCacheEntry &entry = (*_cache)[cacheIndex]; + *this = *dynamic_cast<CelObjView *>(entry.celObj); + entry.id = ++_nextCacheId; + return; + } + + // TODO: The next code should be moved to a common file that + // generates view resource metadata for both SCI16 and SCI32 + // implementations + + Resource *resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, viewId), false); + + // NOTE: SCI2.1/SQ6 just silently returns here. + if (!resource) { + warning("View resource %d not loaded", viewId); + return; + } + + byte *data = resource->data; + + _scaledWidth = READ_SCI11ENDIAN_UINT16(data + 14); + _scaledHeight = READ_SCI11ENDIAN_UINT16(data + 16); + + if (_scaledWidth == 0 || _scaledHeight == 0) { + byte sizeFlag = data[5]; + if (sizeFlag == 0) { + _scaledWidth = 320; + _scaledHeight = 200; + } else if (sizeFlag == 1) { + _scaledWidth = 640; + _scaledHeight = 480; + } else if (sizeFlag == 2) { + _scaledWidth = 640; + _scaledHeight = 400; + } + } + + uint16 loopCount = data[2]; + if (_info.loopNo >= loopCount) { + _info.loopNo = loopCount - 1; + } + + // NOTE: This is the actual check, in the actual location, + // from SCI engine. + if (loopNo < 0) { + error("Loop is less than 0!"); + } + + const uint16 viewHeaderSize = READ_SCI11ENDIAN_UINT16(data); + const uint8 loopHeaderSize = data[12]; + const uint8 viewHeaderFieldSize = 2; + + byte *loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * _info.loopNo); + + if ((int8)loopHeader[0] != -1) { + if (loopHeader[1] == 1) { + _mirrorX = true; + } + + loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * (int8)loopHeader[0]); + } + + uint8 celCount = loopHeader[2]; + if (_info.celNo >= celCount) { + _info.celNo = celCount - 1; + } + + _hunkPaletteOffset = READ_SCI11ENDIAN_UINT32(data + 8); + _celHeaderOffset = READ_SCI11ENDIAN_UINT32(loopHeader + 12) + (data[13] * _info.celNo); + + byte *celHeader = data + _celHeaderOffset; + + _width = READ_SCI11ENDIAN_UINT16(celHeader); + _height = READ_SCI11ENDIAN_UINT16(celHeader + 2); + _displace.x = _width / 2 - (int16)READ_SCI11ENDIAN_UINT16(celHeader + 4); + _displace.y = _height - (int16)READ_SCI11ENDIAN_UINT16(celHeader + 6) - 1; + _transparentColor = celHeader[8]; + _compressionType = (CelCompressionType)celHeader[9]; + + if (_compressionType != kCelCompressionNone && _compressionType != kCelCompressionRLE) { + error("Compression type not supported - V: %d L: %d C: %d", _info.resourceId, _info.loopNo, _info.celNo); + } + + if (celHeader[10] & 128) { + // NOTE: This is correct according to SCI2.1/SQ6/DOS; + // the engine re-reads the byte value as a word value + uint16 flags = READ_SCI11ENDIAN_UINT16(celHeader + 10); + _transparent = flags & 1 ? true : false; + _remap = flags & 2 ? true : false; + } else if (_compressionType == kCelCompressionNone) { + _remap = analyzeUncompressedForRemap(); + } else { + _remap = analyzeForRemap(); + } + + putCopyInCache(cacheInsertIndex); +} + +bool CelObjView::analyzeUncompressedForRemap() const { + byte *pixels = getResPointer() + READ_SCI11ENDIAN_UINT32(getResPointer() + _celHeaderOffset + 24); + for (int i = 0; i < _width * _height; ++i) { + byte pixel = pixels[i]; + if (pixel >= g_sci->_gfxRemap32->getStartColor() && pixel <= g_sci->_gfxRemap32->getEndColor() && pixel != _transparentColor) { + return true; + } + } + return false; +} + +bool CelObjView::analyzeForRemap() const { + 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; +} + +void CelObjView::draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, bool mirrorX, const Ratio &scaleX, const Ratio &scaleY) { + _drawMirrored = mirrorX; + drawTo(target, targetRect, scaledPosition, scaleX, scaleY); +} + +CelObjView *CelObjView::duplicate() const { + return new CelObjView(*this); +} + +byte *CelObjView::getResPointer() const { + return g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _info.resourceId), false)->data; +} + +#pragma mark - +#pragma mark CelObjPic +CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) { + _info.type = kCelTypePic; + _info.resourceId = picId; + _info.loopNo = 0; + _info.celNo = celNo; + _mirrorX = false; + _compressionType = kCelCompressionInvalid; + _transparent = true; + _remap = false; + + int cacheInsertIndex; + int cacheIndex = searchCache(_info, &cacheInsertIndex); + if (cacheIndex != -1) { + CelCacheEntry &entry = (*_cache)[cacheIndex]; + *this = *dynamic_cast<CelObjPic *>(entry.celObj); + entry.id = ++_nextCacheId; + return; + } + + Resource *resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypePic, picId), false); + + // NOTE: SCI2.1/SQ6 just silently returns here. + if (!resource) { + warning("Pic resource %d not loaded", picId); + return; + } + + byte *data = resource->data; + + _celCount = data[2]; + + if (_info.celNo >= _celCount) { + error("Cel number %d greater than cel count %d", _info.celNo, _celCount); + } + + _celHeaderOffset = READ_SCI11ENDIAN_UINT16(data) + (READ_SCI11ENDIAN_UINT16(data + 4) * _info.celNo); + _hunkPaletteOffset = READ_SCI11ENDIAN_UINT32(data + 6); + + byte *celHeader = data + _celHeaderOffset; + + _width = READ_SCI11ENDIAN_UINT16(celHeader); + _height = READ_SCI11ENDIAN_UINT16(celHeader + 2); + _displace.x = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 4); + _displace.y = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 6); + _transparentColor = celHeader[8]; + _compressionType = (CelCompressionType)celHeader[9]; + _priority = READ_SCI11ENDIAN_UINT16(celHeader + 36); + _relativePosition.x = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 38); + _relativePosition.y = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 40); + + uint16 sizeFlag1 = READ_SCI11ENDIAN_UINT16(data + 10); + uint16 sizeFlag2 = READ_SCI11ENDIAN_UINT16(data + 12); + + if (sizeFlag2) { + _scaledWidth = sizeFlag1; + _scaledHeight = sizeFlag2; + } else if (sizeFlag1 == 0) { + _scaledWidth = 320; + _scaledHeight = 200; + } else if (sizeFlag1 == 1) { + _scaledWidth = 640; + _scaledHeight = 480; + } else if (sizeFlag1 == 2) { + _scaledWidth = 640; + _scaledHeight = 400; + } + + if (celHeader[10] & 128) { + // NOTE: This is correct according to SCI2.1/SQ6/DOS; + // the engine re-reads the byte value as a word value + uint16 flags = READ_SCI11ENDIAN_UINT16(celHeader + 10); + _transparent = flags & 1 ? true : false; + _remap = flags & 2 ? true : false; + } else { + _transparent = _compressionType != kCelCompressionNone ? true : analyzeUncompressedForSkip(); + + if (_compressionType != kCelCompressionNone && _compressionType != kCelCompressionRLE) { + error("Compression type not supported - P: %d C: %d", picId, celNo); + } + } + + putCopyInCache(cacheInsertIndex); +} + +bool CelObjPic::analyzeUncompressedForSkip() const { + byte *resource = getResPointer(); + byte *pixels = resource + READ_SCI11ENDIAN_UINT32(resource + _celHeaderOffset + 24); + for (int i = 0; i < _width * _height; ++i) { + uint8 pixel = pixels[i]; + if (pixel == _transparentColor) { + return true; + } + } + + return false; +} + +void CelObjPic::draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) { + Ratio square; + _drawMirrored = mirrorX; + drawTo(target, targetRect, scaledPosition, square, square); +} + +CelObjPic *CelObjPic::duplicate() const { + return new CelObjPic(*this); +} + +byte *CelObjPic::getResPointer() const { + return g_sci->getResMan()->findResource(ResourceId(kResourceTypePic, _info.resourceId), false)->data; +} + +#pragma mark - +#pragma mark CelObjMem +CelObjMem::CelObjMem(const reg_t bitmapObject) { + _info.type = kCelTypeMem; + _info.bitmap = bitmapObject; + _mirrorX = false; + _compressionType = kCelCompressionNone; + _celHeaderOffset = 0; + _transparent = true; + + BitmapResource bitmap(bitmapObject); + _width = bitmap.getWidth(); + _height = bitmap.getHeight(); + _displace = bitmap.getDisplace(); + _transparentColor = bitmap.getSkipColor(); + _scaledWidth = bitmap.getScaledWidth(); + _scaledHeight = bitmap.getScaledHeight(); + _hunkPaletteOffset = bitmap.getHunkPaletteOffset(); + _remap = bitmap.getRemap(); +} + +CelObjMem *CelObjMem::duplicate() const { + return new CelObjMem(*this); +} + +byte *CelObjMem::getResPointer() const { + return g_sci->getEngineState()->_segMan->getHunkPointer(_info.bitmap); +} + +#pragma mark - +#pragma mark CelObjColor +CelObjColor::CelObjColor(const uint8 color, const int16 width, const int16 height) { + _info.type = kCelTypeColor; + _info.color = color; + _displace.x = 0; + _displace.y = 0; + _scaledWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + _scaledHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + _hunkPaletteOffset = 0; + _mirrorX = false; + _remap = false; + _width = width; + _height = height; +} + +void CelObjColor::draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, const bool mirrorX) { + // TODO: The original engine sets this flag but why? One cannot + // draw a solid color mirrored. + _drawMirrored = mirrorX; + draw(target, targetRect); +} +void CelObjColor::draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, bool mirrorX) { + error("Unsupported method"); +} +void CelObjColor::draw(Buffer &target, const Common::Rect &targetRect) const { + target.fillRect(targetRect, _info.color); +} + +CelObjColor *CelObjColor::duplicate() const { + return new CelObjColor(*this); +} + +byte *CelObjColor::getResPointer() const { + error("Unsupported method"); +} +} // End of namespace Sci diff --git a/engines/sci/graphics/celobj32.h b/engines/sci/graphics/celobj32.h new file mode 100644 index 0000000000..0bb4b03ae2 --- /dev/null +++ b/engines/sci/graphics/celobj32.h @@ -0,0 +1,581 @@ +/* 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 SCI_GRAPHICS_CELOBJ32_H +#define SCI_GRAPHICS_CELOBJ32_H + +#include "common/rational.h" +#include "common/rect.h" +#include "sci/resource.h" +#include "sci/engine/vm_types.h" + +namespace Sci { +typedef Common::Rational Ratio; + +enum CelType { + kCelTypeView = 0, + kCelTypePic = 1, + kCelTypeMem = 2, + kCelTypeColor = 3 +}; + +enum CelCompressionType { + kCelCompressionNone = 0, + kCelCompressionRLE = 138, + kCelCompressionInvalid = 1000 +}; + +/** + * A CelInfo32 object describes the basic properties of a + * cel object. + */ +struct CelInfo32 { + /** + * The type of the cel object. + */ + CelType type; + + /** + * For cel objects that draw from resources, the ID of + * the resource to load. + */ + GuiResourceId resourceId; + + /** + * For CelObjView, the loop number to draw from the + * view resource. + */ + int16 loopNo; + + /** + * For CelObjView and CelObjPic, the cel number to draw + * from the view or pic resource. + */ + int16 celNo; + + /** + * For CelObjMem, a segment register pointing to a heap + * resource containing headered bitmap data. + */ + reg_t bitmap; + + /** + * For CelObjColor, the fill color. + */ + uint8 color; + + // NOTE: In at least SCI2.1/SQ6, color is left + // uninitialised. + CelInfo32() : + type(kCelTypeMem), + resourceId(0), + loopNo(0), + celNo(0), + bitmap(NULL_REG) {} + + // NOTE: This is the equivalence criteria used by + // CelObj::searchCache in at least SCI2.1/SQ6. Notably, + // it does not check the color field. + inline bool operator==(const CelInfo32 &other) { + return ( + type == other.type && + resourceId == other.resourceId && + loopNo == other.loopNo && + celNo == other.celNo && + bitmap == other.bitmap + ); + } + + inline bool operator!=(const CelInfo32 &other) { + return !(*this == other); + } +}; + +class CelObj; +struct CelCacheEntry { + /** + * A monotonically increasing cache ID used to identify + * the least recently used item in the cache for + * replacement. + */ + int id; + CelObj *celObj; + CelCacheEntry() : id(0), celObj(nullptr) {} +}; + +typedef Common::Array<CelCacheEntry> CelCache; + +#pragma mark - +#pragma mark CelScaler + +struct CelScalerTable { + /** + * A lookup table of indexes that should be used to find + * the correct column to read from the source bitmap + * when drawing a scaled version of the source bitmap. + */ + int valuesX[1024]; + + /** + * The ratio used to generate the x-values. + */ + Ratio scaleX; + + /** + * A lookup table of indexes that should be used to find + * the correct row to read from a source bitmap when + * drawing a scaled version of the source bitmap. + */ + int valuesY[1024]; + + /** + * The ratio used to generate the y-values. + */ + Ratio scaleY; +}; + +class CelScaler { + /** + * Cached scale tables. + */ + CelScalerTable _scaleTables[2]; + + /** + * The index of the most recently used scale table. + */ + int _activeIndex; + + /** + * Activates a scale table for the given X and Y ratios. + * If there is no table that matches the given ratios, + * the least most recently used table will be replaced + * and activated. + */ + void activateScaleTables(const Ratio &scaleX, const Ratio &scaleY); + + /** + * Builds a pixel lookup table in `table` for the given + * ratio. The table will be filled up to the specified + * size, which should be large enough to draw across the + * entire target buffer. + */ + void buildLookupTable(int *table, const Ratio &ratio, const int size); + +public: + CelScaler() : + _scaleTables(), + _activeIndex(0) { + 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]; + } + } + + /** + * Retrieves scaler tables for the given X and Y ratios. + */ + const CelScalerTable *getScalerTable(const Ratio &scaleX, const Ratio &scaleY); +}; + +#pragma mark - +#pragma mark CelObj + +class ScreenItem; +/** + * A cel object is the lowest-level rendering primitive in + * the SCI engine and draws itself directly to a target + * pixel buffer. + */ +class CelObj { +protected: + /** + * When true, this cel will be horizontally mirrored + * when it is drawn. This is an internal flag that is + * set by draw methods based on the combination of the + * cel's `_mirrorX` property and the owner screen item's + * `_mirrorX` property. + */ + bool _drawMirrored; + +public: + static CelScaler *_scaler; + + /** + * The basic identifying information for this cel. This + * information effectively acts as a composite key for + * a cel object, and any cel object can be recreated + * from this data alone. + */ + CelInfo32 _info; + + /** + * The offset to the cel header for this cel within the + * raw resource data. + */ + uint32 _celHeaderOffset; + + /** + * The offset to the embedded palette for this cel + * within the raw resource data. + */ + uint32 _hunkPaletteOffset; + + /** + * The natural dimensions of the cel. + */ + uint16 _width, _height; + + /** + * TODO: Documentation + */ + Common::Point _displace; + + /** + * The dimensions of the original coordinate system for + * the cel. Used to scale cels from their native size + * to the correct size on screen. + * + * @note This is set to scriptWidth/Height for + * CelObjColor. For other cel objects, the value comes + * from the raw resource data. For text bitmaps, this is + * the width/height of the coordinate system used to + * generate the text, which also defaults to + * scriptWidth/Height but seems to typically be changed + * to more closely match the native screen resolution. + */ + uint16 _scaledWidth, _scaledHeight; + + /** + * The skip (transparent) color for the cel. When + * compositing, any pixels matching this color will not + * be copied to the buffer. + */ + uint8 _transparentColor; + + /** + * Whether or not this cel has any transparent regions. + * This is used for optimised drawing of non-transparent + * cels. + */ + bool _transparent; // TODO: probably "skip"? + + /** + * The compression type for the pixel data for this cel. + */ + CelCompressionType _compressionType; + + /** + * Whether or not this cel should be palette-remapped? + */ + bool _remap; + + /** + * If true, the cel contains pre-mirrored picture data. + * This value comes directly from the resource data and + * is XORed with the `_mirrorX` property of the owner + * screen item when rendering. + */ + bool _mirrorX; + + /** + * Initialises static CelObj members. + */ + static void init(); + + /** + * Frees static CelObj members. + */ + static void deinit(); + + virtual ~CelObj() {}; + + /** + * Draws the cel to the target buffer using the priority + * and positioning information from the given screen + * item. The mirroring of the cel will be unchanged from + * any previous call to draw. + */ + void draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect) const; + + /** + * Draws the cel to the target buffer using the priority + * and positioning information from the given screen + * item and the given mirror flag. + * + * @note In SCI engine, this function was a virtual + * function, but CelObjView, CelObjPic, and CelObjMem + * all used the same function and the compiler + * deduplicated the copies; we deduplicate the source by + * putting the implementation on CelObj instead of + * copying it to 3/4 of the subclasses. + */ + virtual void draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, const bool mirrorX); + + /** + * Draws the cel to the target buffer using the + * positioning and mirroring information from the + * provided arguments. + * + * @note In SCI engine, this function was a virtual + * function, but CelObjView, CelObjPic, and CelObjMem + * all used the same function and the compiler + * deduplicated the copies; we deduplicate the source by + * putting the implementation on CelObj instead of + * copying it to 3/4 of the subclasses. + */ + virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX); + + /** + * Draws the cel to the target buffer using the given + * position and scaling parameters. The mirroring of the + * cel will be unchanged from any previous call to draw. + */ + void drawTo(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const Ratio &scaleX, const Ratio &scaleY) const; + + /** + * Creates a copy of this cel on the free store and + * returns a pointer to the new object. The new cel will + * point to a shared copy of bitmap/resource data. + */ + virtual CelObj *duplicate() const = 0; + + /** + * Retrieves a pointer to the raw resource data for this + * cel. This method cannot be used with a CelObjColor. + */ + virtual byte *getResPointer() const = 0; + + /** + * Reads the pixel at the given coordinates. This method + * is valid only for CelObjView and CelObjPic. + */ + virtual uint8 readPixel(uint16 x, uint16 y, bool mirrorX) const; + + /** + * Submits the palette from this cel to the palette + * manager for integration into the master screen + * palette. + */ + void submitPalette() const; + +#pragma mark - +#pragma mark CelObj - Drawing +private: + template<typename MAPPER, typename SCALER> + void render(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + + template<typename MAPPER, typename SCALER> + void render(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const Ratio &scaleX, const Ratio &scaleY) const; + + void drawHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void drawNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void drawUncompNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + 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; + // 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; + void drawUncompNoFlipNoMDNoSkip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void drawUncompHzFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + 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; + // 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 +protected: + /** + * A monotonically increasing cache ID used to identify + * the least recently used item in the cache for + * replacement. + */ + static int _nextCacheId; + + /** + * A cache of cel objects used to avoid reinitialisation + * overhead for cels with the same CelInfo32. + */ + // NOTE: At least SQ6 uses a fixed cache size of 100. + static CelCache *_cache; + + /** + * Searches the cel cache for a CelObj matching the + * provided CelInfo32. If not found, -1 is returned. + * nextInsertIndex will receive the index of the oldest + * item in the cache, which can be used to replace + * the oldest item with a newer item. + */ + int searchCache(const CelInfo32 &celInfo, int *nextInsertIndex) const; + + /** + * Puts a copy of this CelObj into the cache at the + * given cache index. + */ + void putCopyInCache(int index) const; +}; + +#pragma mark - +#pragma mark CelObjView + +/** + * A CelObjView is the drawing primitive for a View type + * resource. Each CelObjView corresponds to a single cel + * within a single loop of a view. + */ +class CelObjView : public CelObj { +private: + /** + * Analyses resources without baked-in remap flags + * to determine whether or not they should be remapped. + */ + bool analyzeUncompressedForRemap() const; + + /** + * Analyses compressed resources without baked-in remap + * flags to determine whether or not they should be + * remapped. + */ + bool analyzeForRemap() const; + +public: + CelObjView(GuiResourceId viewId, int16 loopNo, int16 celNo); + virtual ~CelObjView() override {}; + + using CelObj::draw; + + /** + * Draws the cel to the target buffer using the + * positioning, mirroring, and scaling information from + * the provided arguments. + */ + void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, bool mirrorX, const Ratio &scaleX, const Ratio &scaleY); + + virtual CelObjView *duplicate() const override; + virtual byte *getResPointer() const override; +}; + +#pragma mark - +#pragma mark CelObjPic + +/** + * A CelObjPic is the drawing primitive for a Picture type + * resource. Each CelObjPic corresponds to a single cel + * within a picture. + */ +class CelObjPic : public CelObj { +private: + /** + * Analyses uncompressed resources without baked-in skip + * flags to determine whether or not they can use fast + * blitting. + */ + bool analyzeUncompressedForSkip() const; + +public: + /** + * The number of cels in the original picture resource. + */ + uint8 _celCount; + + /** + * The position of this cel relative to the top-left + * corner of the picture. + */ + Common::Point _relativePosition; + + /** + * The z-buffer priority for this cel. Higher prorities + * are drawn on top of lower priorities. + */ + int16 _priority; + + CelObjPic(GuiResourceId pictureId, int16 celNo); + virtual ~CelObjPic() override {}; + + using CelObj::draw; + virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) override; + + virtual CelObjPic *duplicate() const override; + virtual byte *getResPointer() const override; +}; + +#pragma mark - +#pragma mark CelObjMem + +/** + * A CelObjMem is the drawing primitive for arbitrary + * bitmaps generated in memory. Generated bitmaps in SCI32 + * include text & vector drawings and per-pixel screen + * transitions like dissolves. + */ +class CelObjMem : public CelObj { +public: + CelObjMem(reg_t bitmap); + virtual ~CelObjMem() override {}; + + virtual CelObjMem *duplicate() const override; + virtual byte *getResPointer() const override; +}; + +#pragma mark - +#pragma mark CelObjColor + +/** + * A CelObjColor is the drawing primitive for fast, + * low-memory, flat color fills. + */ +class CelObjColor : public CelObj { +public: + CelObjColor(uint8 color, int16 width, int16 height); + virtual ~CelObjColor() override {}; + + using CelObj::draw; + /** + * Block fills the target buffer with the cel color. + */ + void draw(Buffer &target, const Common::Rect &targetRect) const; + virtual void draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, const bool mirrorX) override; + virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) override; + + virtual CelObjColor *duplicate() const override; + virtual byte *getResPointer() const override; +}; +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/compare.cpp b/engines/sci/graphics/compare.cpp index 716a366b7c..729eeeaf81 100644 --- a/engines/sci/graphics/compare.cpp +++ b/engines/sci/graphics/compare.cpp @@ -67,7 +67,7 @@ uint16 GfxCompare::isOnControl(uint16 screenMask, const Common::Rect &rect) { return result; } -reg_t GfxCompare::canBeHereCheckRectList(reg_t checkObject, const Common::Rect &checkRect, List *list) { +reg_t GfxCompare::canBeHereCheckRectList(const reg_t checkObject, const Common::Rect &checkRect, const List *list, const uint16 signalFlags) const { reg_t curAddress = list->first; Node *curNode = _segMan->lookupNode(curAddress); reg_t curObject; @@ -78,7 +78,7 @@ reg_t GfxCompare::canBeHereCheckRectList(reg_t checkObject, const Common::Rect & curObject = curNode->value; if (curObject != checkObject) { signal = readSelectorValue(_segMan, curObject, SELECTOR(signal)); - if (!(signal & (kSignalIgnoreActor | kSignalRemoveView | kSignalNoUpdate))) { + if (!(signal & signalFlags)) { curRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft)); curRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop)); curRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight)); @@ -112,11 +112,6 @@ void GfxCompare::kernelSetNowSeen(reg_t objectReference) { GfxView *view = NULL; Common::Rect celRect(0, 0); GuiResourceId viewId = (GuiResourceId)readSelectorValue(_segMan, objectReference, SELECTOR(view)); - - // HACK: Ignore invalid views for now (perhaps unimplemented text views?) - if (viewId == 0xFFFF) // invalid view - return; - int16 loopNo = readSelectorValue(_segMan, objectReference, SELECTOR(loop)); int16 celNo = readSelectorValue(_segMan, objectReference, SELECTOR(cel)); int16 x = (int16)readSelectorValue(_segMan, objectReference, SELECTOR(x)); @@ -126,26 +121,8 @@ void GfxCompare::kernelSetNowSeen(reg_t objectReference) { z = (int16)readSelectorValue(_segMan, objectReference, SELECTOR(z)); view = _cache->getView(viewId); - -#ifdef ENABLE_SCI32 - if (view->isSci2Hires()) - view->adjustToUpscaledCoordinates(y, x); - else if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE)) - _coordAdjuster->fromScriptToDisplay(y, x); -#endif - view->getCelRect(loopNo, celNo, x, y, z, celRect); -#ifdef ENABLE_SCI32 - if (view->isSci2Hires()) { - view->adjustBackUpscaledCoordinates(celRect.top, celRect.left); - view->adjustBackUpscaledCoordinates(celRect.bottom, celRect.right); - } else if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE)) { - _coordAdjuster->fromDisplayToScript(celRect.top, celRect.left); - _coordAdjuster->fromDisplayToScript(celRect.bottom, celRect.right); - } -#endif - if (lookupSelector(_segMan, objectReference, SELECTOR(nsTop), NULL, NULL) == kSelectorVariable) { setNSRect(objectReference, celRect); } @@ -153,32 +130,57 @@ void GfxCompare::kernelSetNowSeen(reg_t objectReference) { reg_t GfxCompare::kernelCanBeHere(reg_t curObject, reg_t listReference) { Common::Rect checkRect; - Common::Rect adjustedRect; - uint16 signal, controlMask; uint16 result; checkRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft)); checkRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop)); checkRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight)); checkRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom)); + uint16 signal = readSelectorValue(_segMan, curObject, SELECTOR(signal)); if (!checkRect.isValidRect()) { // can occur in Iceman and Mother Goose - HACK? TODO: is this really occuring in sierra sci? check this warning("kCan(t)BeHere - invalid rect %d, %d -> %d, %d", checkRect.left, checkRect.top, checkRect.right, checkRect.bottom); return NULL_REG; // this means "can be here" } - adjustedRect = _coordAdjuster->onControl(checkRect); - - signal = readSelectorValue(_segMan, curObject, SELECTOR(signal)); - controlMask = readSelectorValue(_segMan, curObject, SELECTOR(illegalBits)); + Common::Rect adjustedRect = _coordAdjuster->onControl(checkRect); + uint16 controlMask = readSelectorValue(_segMan, curObject, SELECTOR(illegalBits)); result = isOnControl(GFX_SCREEN_MASK_CONTROL, adjustedRect) & controlMask; if ((!result) && (signal & (kSignalIgnoreActor | kSignalRemoveView)) == 0) { List *list = _segMan->lookupList(listReference); if (!list) error("kCanBeHere called with non-list as parameter"); - return canBeHereCheckRectList(curObject, checkRect, list); + return canBeHereCheckRectList(curObject, checkRect, list, kSignalIgnoreActor | kSignalRemoveView | kSignalNoUpdate); } + + return make_reg(0, result); +} + +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)), + readSelectorValue(_segMan, curObject, SELECTOR(brRight)), + readSelectorValue(_segMan, curObject, SELECTOR(brBottom)) + ); + + uint16 result = 0; + uint16 signal = readSelectorValue(_segMan, curObject, SELECTOR(signal)); + const uint16 signalFlags = kSignalIgnoreActor | kSignalHidden; + + if ((signal & signalFlags) == 0) { + List *list = _segMan->lookupList(listReference); + if (!list) { + error("kCantBeHere called with non-list as parameter"); + } + result = !canBeHereCheckRectList(curObject, checkRect, list, signalFlags).isNull(); + } + return make_reg(0, result); } @@ -201,15 +203,9 @@ void GfxCompare::kernelBaseSetter(reg_t object) { GuiResourceId viewId = readSelectorValue(_segMan, object, SELECTOR(view)); int16 loopNo = readSelectorValue(_segMan, object, SELECTOR(loop)); int16 celNo = readSelectorValue(_segMan, object, SELECTOR(cel)); - - // HACK: Ignore invalid views for now (perhaps unimplemented text views?) - if (viewId == 0xFFFF) // invalid view - return; - uint16 scaleSignal = 0; - if (getSciVersion() >= SCI_VERSION_1_1) { + if (getSciVersion() >= SCI_VERSION_1_1) scaleSignal = readSelectorValue(_segMan, object, SELECTOR(scaleSignal)); - } Common::Rect celRect; diff --git a/engines/sci/graphics/compare.h b/engines/sci/graphics/compare.h index 88b44aeeb1..c7005980d0 100644 --- a/engines/sci/graphics/compare.h +++ b/engines/sci/graphics/compare.h @@ -40,6 +40,7 @@ public: uint16 kernelOnControl(byte screenMask, const Common::Rect &rect); void kernelSetNowSeen(reg_t objectReference); reg_t kernelCanBeHere(reg_t curObject, reg_t listReference); + reg_t kernelCantBeHere32(const reg_t curObject, const reg_t listReference) const; bool kernelIsItSkip(GuiResourceId viewId, int16 loopNo, int16 celNo, Common::Point position); void kernelBaseSetter(reg_t object); Common::Rect getNSRect(reg_t object); @@ -58,7 +59,7 @@ private: * *different* from checkObject, has a brRect which is contained inside * checkRect. */ - reg_t canBeHereCheckRectList(reg_t checkObject, const Common::Rect &checkRect, List *list); + reg_t canBeHereCheckRectList(const reg_t checkObject, const Common::Rect &checkRect, const List *list, const uint16 signalFlags) const; }; } // End of namespace Sci diff --git a/engines/sci/graphics/controls16.cpp b/engines/sci/graphics/controls16.cpp index e2e250cf9d..b4bd92699a 100644 --- a/engines/sci/graphics/controls16.cpp +++ b/engines/sci/graphics/controls16.cpp @@ -151,7 +151,7 @@ void GfxControls16::kernelTexteditChange(reg_t controlObject, reg_t eventObject) Common::Rect rect; if (textReference.isNull()) - error("kEditControl called on object that doesnt have a text reference"); + error("kEditControl called on object that doesn't have a text reference"); text = _segMan->getString(textReference); uint16 oldCursorPos = cursorPos; diff --git a/engines/sci/graphics/controls32.cpp b/engines/sci/graphics/controls32.cpp index 1bd497ce98..a877d8c276 100644 --- a/engines/sci/graphics/controls32.cpp +++ b/engines/sci/graphics/controls32.cpp @@ -23,9 +23,11 @@ #include "common/system.h" #include "sci/sci.h" +#include "sci/console.h" #include "sci/event.h" #include "sci/engine/kernel.h" #include "sci/engine/seg_manager.h" +#include "sci/engine/state.h" #include "sci/graphics/cache.h" #include "sci/graphics/compare.h" #include "sci/graphics/controls32.h" @@ -34,171 +36,321 @@ #include "sci/graphics/text32.h" namespace Sci { +GfxControls32::GfxControls32(SegManager *segMan, GfxCache *cache, GfxText32 *text) : + _segMan(segMan), + _gfxCache(cache), + _gfxText32(text), + _overwriteMode(false), + _nextCursorFlashTick(0) {} -GfxControls32::GfxControls32(SegManager *segMan, GfxCache *cache, GfxText32 *text) - : _segMan(segMan), _cache(cache), _text(text) { -} +reg_t GfxControls32::kernelEditText(const reg_t controlObject) { + SegManager *segMan = _segMan; -GfxControls32::~GfxControls32() { -} + TextEditor editor; + reg_t textObject = readSelector(_segMan, controlObject, SELECTOR(text)); + editor.text = _segMan->getString(textObject); + editor.foreColor = readSelectorValue(_segMan, controlObject, SELECTOR(fore)); + editor.backColor = readSelectorValue(_segMan, controlObject, SELECTOR(back)); + editor.skipColor = readSelectorValue(_segMan, controlObject, SELECTOR(skip)); + editor.fontId = readSelectorValue(_segMan, controlObject, SELECTOR(font)); + editor.maxLength = readSelectorValue(_segMan, controlObject, SELECTOR(width)); + editor.bitmap = readSelector(_segMan, controlObject, SELECTOR(bitmap)); + editor.cursorCharPosition = 0; + editor.cursorIsDrawn = false; + editor.borderColor = readSelectorValue(_segMan, controlObject, SELECTOR(borderColor)); -void GfxControls32::kernelTexteditChange(reg_t controlObject) { - SciEvent curEvent; - uint16 maxChars = 40; //readSelectorValue(_segMan, controlObject, SELECTOR(max)); // TODO - reg_t textReference = readSelector(_segMan, controlObject, SELECTOR(text)); - GfxFont *font = _cache->getFont(readSelectorValue(_segMan, controlObject, SELECTOR(font))); - Common::String text; - uint16 textSize; - bool textChanged = false; - bool textAddChar = false; - Common::Rect rect; + reg_t titleObject = readSelector(_segMan, controlObject, SELECTOR(title)); + + int16 titleHeight = 0; + GuiResourceId titleFontId = readSelectorValue(_segMan, controlObject, SELECTOR(titleFont)); + if (!titleObject.isNull()) { + GfxFont *titleFont = _gfxCache->getFont(titleFontId); + titleHeight += _gfxText32->scaleUpHeight(titleFont->getHeight()) + 1; + if (editor.borderColor != -1) { + titleHeight += 2; + } + } - if (textReference.isNull()) - error("kEditControl called on object that doesnt have a text reference"); - text = _segMan->getString(textReference); + int16 width = 0; + int16 height = titleHeight; - // TODO: Finish this - warning("kEditText ('%s')", text.c_str()); - return; + GfxFont *editorFont = _gfxCache->getFont(editor.fontId); + height += _gfxText32->scaleUpHeight(editorFont->getHeight()) + 1; + _gfxText32->setFont(editor.fontId); + int16 emSize = _gfxText32->getCharWidth('M', true); + width += editor.maxLength * emSize + 1; + if (editor.borderColor != -1) { + width += 4; + height += 2; + } - uint16 cursorPos = 0; - //uint16 oldCursorPos = cursorPos; - bool captureEvents = true; - EventManager* eventMan = g_sci->getEventManager(); + Common::Rect editorPlaneRect(width, height); + editorPlaneRect.translate(readSelectorValue(_segMan, controlObject, SELECTOR(x)), readSelectorValue(_segMan, controlObject, SELECTOR(y))); - while (captureEvents) { - curEvent = g_sci->getEventManager()->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK); + reg_t planeObj = readSelector(_segMan, controlObject, SELECTOR(plane)); + Plane *sourcePlane = g_sci->_gfxFrameout->getVisiblePlanes().findByObject(planeObj); + if (sourcePlane == nullptr) { + error("Could not find plane %04x:%04x", PRINT_REG(planeObj)); + } + editorPlaneRect.translate(sourcePlane->_gameRect.left, sourcePlane->_gameRect.top); - if (curEvent.type == SCI_EVENT_NONE) { - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event + editor.textRect = Common::Rect(2, titleHeight + 2, width - 1, height - 1); + editor.width = width; + + if (editor.bitmap.isNull()) { + TextAlign alignment = (TextAlign)readSelectorValue(_segMan, controlObject, SELECTOR(mode)); + + if (titleObject.isNull()) { + bool dimmed = readSelectorValue(_segMan, controlObject, SELECTOR(dimmed)); + editor.bitmap = _gfxText32->createFontBitmap(width, height, editor.textRect, editor.text, editor.foreColor, editor.backColor, editor.skipColor, editor.fontId, alignment, editor.borderColor, dimmed, true); } else { - textSize = text.size(); + Common::String title = _segMan->getString(titleObject); + int16 titleBackColor = readSelectorValue(_segMan, controlObject, SELECTOR(titleBack)); + int16 titleForeColor = readSelectorValue(_segMan, controlObject, SELECTOR(titleFore)); + editor.bitmap = _gfxText32->createTitledBitmap(width, height, editor.textRect, editor.text, editor.foreColor, editor.backColor, editor.skipColor, editor.fontId, alignment, editor.borderColor, title, titleForeColor, titleBackColor, titleFontId, true); + } + } + + drawCursor(editor); - switch (curEvent.type) { - case SCI_EVENT_MOUSE_PRESS: - // TODO: Implement mouse support for cursor change + Plane *plane = new Plane(editorPlaneRect, kPlanePicTransparent); + plane->changePic(); + g_sci->_gfxFrameout->addPlane(*plane); + + CelInfo32 celInfo; + celInfo.type = kCelTypeMem; + celInfo.bitmap = editor.bitmap; + + ScreenItem *screenItem = new ScreenItem(plane->_object, celInfo, Common::Point(), ScaleInfo()); + plane->_screenItemList.add(screenItem); + + // frameOut must be called after the screen item is + // created, and before it is updated at the end of the + // event loop, otherwise it has both created and updated + // flags set which crashes the engine (it runs updates + // before creations) + g_sci->_gfxFrameout->frameOut(true); + + EventManager *eventManager = g_sci->getEventManager(); + bool clearTextOnInput = true; + bool textChanged = false; + for (;;) { + // We peek here because the last event needs to be allowed to + // dispatch a second time to the normal event handling system. + // In the actual engine, the event is always consumed and then + // the last event just gets posted back to the event manager for + // reprocessing, but instead, we only remove the event from the + // queue *after* we have determined it is not a defocusing event + const SciEvent event = eventManager->getSciEvent(SCI_EVENT_ANY | SCI_EVENT_PEEK); + + bool focused = true; + // Original engine did not have a QUIT event but we have to handle it + if (event.type == SCI_EVENT_QUIT) { + focused = false; + break; + } else if (event.type == SCI_EVENT_MOUSE_PRESS && !editorPlaneRect.contains(event.mousePosSci)) { + focused = false; + } else if (event.type == SCI_EVENT_KEYBOARD) { + switch (event.character) { + case SCI_KEY_ESC: + case SCI_KEY_UP: + case SCI_KEY_DOWN: + case SCI_KEY_TAB: + case SCI_KEY_SHIFT_TAB: + case SCI_KEY_ENTER: + focused = false; break; - case SCI_EVENT_KEYBOARD: - switch (curEvent.character) { - case SCI_KEY_BACKSPACE: - if (cursorPos > 0) { - cursorPos--; text.deleteChar(cursorPos); - textChanged = true; - } - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; - case SCI_KEY_DELETE: - if (cursorPos < textSize) { - text.deleteChar(cursorPos); - textChanged = true; - } - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; - case SCI_KEY_HOME: // HOME - cursorPos = 0; textChanged = true; - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; - case SCI_KEY_END: // END - cursorPos = textSize; textChanged = true; - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; - case SCI_KEY_LEFT: // LEFT - if (cursorPos > 0) { - cursorPos--; textChanged = true; - } - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; - case SCI_KEY_RIGHT: // RIGHT - if (cursorPos + 1 <= textSize) { - cursorPos++; textChanged = true; - } - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; - case 3: // returned in SCI1 late and newer when Control - C is pressed - if (curEvent.modifiers & SCI_KEYMOD_CTRL) { - // Control-C erases the whole line - cursorPos = 0; text.clear(); - textChanged = true; + } + } + + if (!focused) { + break; + } + + // Consume the event now that we know it is not one of the + // defocusing events above + eventManager->getSciEvent(SCI_EVENT_ANY); + + // NOTE: In the original engine, the font and bitmap were + // reset here on each iteration through the loop, but it + // doesn't seem like this should be necessary since + // control is not yielded back to the VM until input is + // received, which means there is nothing that could modify + // the GfxText32's state with a different font in the + // meantime + + bool shouldDeleteChar = false; + bool shouldRedrawText = false; + uint16 lastCursorPosition = editor.cursorCharPosition; + if (event.type == SCI_EVENT_KEYBOARD) { + switch (event.character) { + case SCI_KEY_LEFT: + clearTextOnInput = false; + if (editor.cursorCharPosition > 0) { + --editor.cursorCharPosition; + } + break; + + case SCI_KEY_RIGHT: + clearTextOnInput = false; + if (editor.cursorCharPosition < editor.text.size()) { + ++editor.cursorCharPosition; + } + break; + + case SCI_KEY_HOME: + clearTextOnInput = false; + editor.cursorCharPosition = 0; + break; + + case SCI_KEY_END: + clearTextOnInput = false; + editor.cursorCharPosition = editor.text.size(); + break; + + case SCI_KEY_INSERT: + clearTextOnInput = false; + // Redrawing also changes the cursor rect to + // reflect the new insertion mode + shouldRedrawText = true; + _overwriteMode = !_overwriteMode; + break; + + case SCI_KEY_DELETE: + clearTextOnInput = false; + if (editor.cursorCharPosition < editor.text.size()) { + shouldDeleteChar = true; + } + break; + + case SCI_KEY_BACKSPACE: + clearTextOnInput = false; + shouldDeleteChar = true; + if (editor.cursorCharPosition > 0) { + --editor.cursorCharPosition; + } + break; + + case SCI_KEY_ETX: + editor.text.clear(); + editor.cursorCharPosition = 0; + shouldRedrawText = true; + break; + + default: { + if (event.character >= 20 && event.character < 257) { + if (clearTextOnInput) { + clearTextOnInput = false; + editor.text.clear(); } - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; - case SCI_KEY_UP: - case SCI_KEY_DOWN: - case SCI_KEY_ENTER: - case SCI_KEY_ESC: - case SCI_KEY_TAB: - case SCI_KEY_SHIFT_TAB: - captureEvents = false; - break; - default: - if ((curEvent.modifiers & SCI_KEYMOD_CTRL) && curEvent.character == 'c') { - // Control-C in earlier SCI games (SCI0 - SCI1 middle) - // Control-C erases the whole line - cursorPos = 0; text.clear(); - textChanged = true; - } else if (curEvent.character > 31 && curEvent.character < 256 && textSize < maxChars) { - // insert pressed character - textAddChar = true; - textChanged = true; + + if ( + (_overwriteMode && editor.cursorCharPosition < editor.maxLength) || + (editor.text.size() < editor.maxLength && _gfxText32->getCharWidth(event.character, true) + _gfxText32->getStringWidth(editor.text) < editor.textRect.width()) + ) { + if (_overwriteMode && editor.cursorCharPosition < editor.text.size()) { + editor.text.setChar(event.character, editor.cursorCharPosition); + } else { + editor.text.insertChar(event.character, editor.cursorCharPosition); + } + + ++editor.cursorCharPosition; + shouldRedrawText = true; } - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; } - break; + } } } - if (textChanged) { - rect = g_sci->_gfxCompare->getNSRect(controlObject); + if (shouldDeleteChar) { + shouldRedrawText = true; + if (editor.cursorCharPosition < editor.text.size()) { + editor.text.deleteChar(editor.cursorCharPosition); + } + } - if (textAddChar) { - const char *textPtr = text.c_str(); + if (shouldRedrawText) { + eraseCursor(editor); + _gfxText32->erase(editor.textRect, true); + _gfxText32->drawTextBox(editor.text); + drawCursor(editor); + textChanged = true; + screenItem->_updated = g_sci->_gfxFrameout->getScreenCount(); + } else if (editor.cursorCharPosition != lastCursorPosition) { + eraseCursor(editor); + drawCursor(editor); + screenItem->_updated = g_sci->_gfxFrameout->getScreenCount(); + } else { + flashCursor(editor); + screenItem->_updated = g_sci->_gfxFrameout->getScreenCount(); + } - // We check if we are really able to add the new char - uint16 textWidth = 0; - while (*textPtr) - textWidth += font->getCharWidth((byte)*textPtr++); - textWidth += font->getCharWidth(curEvent.character); + g_sci->_gfxFrameout->frameOut(true); + g_sci->getSciDebugger()->onFrame(); + g_sci->getEngineState()->speedThrottler(16); + g_sci->getEngineState()->_throttleTrigger = true; + } - // Does it fit? - if (textWidth >= rect.width()) { - return; - } + g_sci->_gfxFrameout->deletePlane(*plane); + if (readSelectorValue(segMan, controlObject, SELECTOR(frameOut))) { + g_sci->_gfxFrameout->frameOut(true); + } - text.insertChar(curEvent.character, cursorPos++); + _segMan->freeHunkEntry(editor.bitmap); - // Note: the following checkAltInput call might make the text - // too wide to fit, but SSCI fails to check that too. - } + if (textChanged) { + editor.text.trim(); + SciString *string = _segMan->lookupString(textObject); + string->fromString(editor.text); + } + + return make_reg(0, textChanged); +} - reg_t hunkId = readSelector(_segMan, controlObject, SELECTOR(bitmap)); - Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(controlObject); - //texteditCursorErase(); // TODO: Cursor +void GfxControls32::drawCursor(TextEditor &editor) { + if (!editor.cursorIsDrawn) { + editor.cursorRect.left = editor.textRect.left + _gfxText32->getTextWidth(editor.text, 0, editor.cursorCharPosition); - // Write back string - _segMan->strcpy(textReference, text.c_str()); - // Modify the buffer and show it - _text->createTextBitmap(controlObject, 0, 0, hunkId); + const int16 scaledFontHeight = _gfxText32->scaleUpHeight(_gfxText32->_font->getHeight()); - _text->drawTextBitmap(0, 0, nsRect, controlObject); - //texteditCursorDraw(rect, text.c_str(), cursorPos); // TODO: Cursor - g_system->updateScreen(); + // NOTE: The original code branched on borderColor here but + // the two branches appeared to be identical, differing only + // because the compiler decided to be differently clever + // when optimising multiplication in each branch + if (_overwriteMode) { + editor.cursorRect.top = editor.textRect.top; + editor.cursorRect.setHeight(scaledFontHeight); } else { - // TODO: Cursor - /* - if (g_system->getMillis() >= _texteditBlinkTime) { - _paint16->invertRect(_texteditCursorRect); - _paint16->bitsShow(_texteditCursorRect); - _texteditCursorVisible = !_texteditCursorVisible; - texteditSetBlinkTime(); - } - */ + editor.cursorRect.top = editor.textRect.top + scaledFontHeight - 1; + editor.cursorRect.setHeight(1); } - textAddChar = false; - textChanged = false; - g_sci->sleep(10); - } // while + const char currentChar = editor.cursorCharPosition < editor.text.size() ? editor.text[editor.cursorCharPosition] : ' '; + editor.cursorRect.setWidth(_gfxText32->getCharWidth(currentChar, true)); + + _gfxText32->invertRect(editor.bitmap, editor.width, editor.cursorRect, editor.foreColor, editor.backColor, true); + + editor.cursorIsDrawn = true; + } + + _nextCursorFlashTick = g_sci->getTickCount() + 30; +} + +void GfxControls32::eraseCursor(TextEditor &editor) { + if (editor.cursorIsDrawn) { + _gfxText32->invertRect(editor.bitmap, editor.width, editor.cursorRect, editor.foreColor, editor.backColor, true); + editor.cursorIsDrawn = false; + } + + _nextCursorFlashTick = g_sci->getTickCount() + 30; } +void GfxControls32::flashCursor(TextEditor &editor) { + if (g_sci->getTickCount() > _nextCursorFlashTick) { + _gfxText32->invertRect(editor.bitmap, editor.width, editor.cursorRect, editor.foreColor, editor.backColor, true); + + editor.cursorIsDrawn = !editor.cursorIsDrawn; + _nextCursorFlashTick = g_sci->getTickCount() + 30; + } +} } // End of namespace Sci diff --git a/engines/sci/graphics/controls32.h b/engines/sci/graphics/controls32.h index 5af7c20f16..1bb7679ddd 100644 --- a/engines/sci/graphics/controls32.h +++ b/engines/sci/graphics/controls32.h @@ -29,20 +29,95 @@ class GfxCache; class GfxScreen; class GfxText32; +struct TextEditor { + /** + * The bitmap where the editor is rendered. + */ + reg_t bitmap; + + /** + * The width of the editor, in bitmap pixels. + */ + int16 width; + + /** + * The text in the editor. + */ + Common::String text; + + /** + * The rect where text should be drawn into the editor, + * in bitmap pixels. + */ + Common::Rect textRect; + + /** + * The color of the border. -1 indicates no border. + */ + int16 borderColor; + + /** + * The text color. + */ + uint8 foreColor; + + /** + * The background color. + */ + uint8 backColor; + + /** + * The transparent color. + */ + uint8 skipColor; + + /** + * The font used to render the text in the editor. + */ + GuiResourceId fontId; + + /** + * The current position of the cursor within the editor. + */ + uint16 cursorCharPosition; + + /** + * Whether or not the cursor is currently drawn to the + * screen. + */ + bool cursorIsDrawn; + + /** + * The rectangle for drawing the input cursor, in bitmap + * pixels. + */ + Common::Rect cursorRect; + + /** + * The maximum allowed text length, in characters. + */ + uint16 maxLength; +}; + /** * Controls class, handles drawing of controls in SCI32 (SCI2, SCI2.1, SCI3) games */ class GfxControls32 { public: GfxControls32(SegManager *segMan, GfxCache *cache, GfxText32 *text); - ~GfxControls32(); - void kernelTexteditChange(reg_t controlObject); + reg_t kernelEditText(const reg_t controlObject); private: SegManager *_segMan; - GfxCache *_cache; - GfxText32 *_text; + GfxCache *_gfxCache; + GfxText32 *_gfxText32; + + bool _overwriteMode; + uint32 _nextCursorFlashTick; + void drawCursor(TextEditor &editor); + void eraseCursor(TextEditor &editor); + void flashCursor(TextEditor &editor); }; } // End of namespace Sci diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp index 1a58de073c..f5dd473959 100644 --- a/engines/sci/graphics/cursor.cpp +++ b/engines/sci/graphics/cursor.cpp @@ -336,6 +336,9 @@ void GfxCursor::setPosition(Common::Point pos) { && ((workaround->newPositionX == pos.x) && (workaround->newPositionY == pos.y))) { EngineState *s = g_sci->getEngineState(); s->_cursorWorkaroundActive = true; + // At least on OpenPandora it seems that the cursor is actually set, but a bit afterwards + // touch screen controls will overwrite the position. More information see kGetEvent in kevent.cpp. + s->_cursorWorkaroundPosCount = 5; // should be enough for OpenPandora s->_cursorWorkaroundPoint = pos; s->_cursorWorkaroundRect = Common::Rect(workaround->rectLeft, workaround->rectTop, workaround->rectRight, workaround->rectBottom); return; @@ -453,6 +456,15 @@ void GfxCursor::kernelClearZoomZone() { void GfxCursor::kernelSetZoomZone(byte multiplier, Common::Rect zone, GuiResourceId viewNum, int loopNum, int celNum, GuiResourceId picNum, byte zoomColor) { kernelClearZoomZone(); + // This function is a stub in the Mac version of Freddy Pharkas. + // This function was only used in two games (LB2 and Pharkas), but there + // was no version of LB2 for the Macintosh platform. + // CHECKME: This wasn't verified against disassembly, one might want + // to check against it, in case there's some leftover code in the stubbed + // function (although it does seem that this was completely removed). + if (g_sci->getPlatform() == Common::kPlatformMacintosh) + return; + _zoomMultiplier = multiplier; if (_zoomMultiplier != 1 && _zoomMultiplier != 2 && _zoomMultiplier != 4) diff --git a/engines/sci/graphics/cursor.h b/engines/sci/graphics/cursor.h index c2d7998eb3..8d125c45b3 100644 --- a/engines/sci/graphics/cursor.h +++ b/engines/sci/graphics/cursor.h @@ -77,8 +77,18 @@ public: */ void kernelSetMoveZone(Common::Rect zone); - void kernelClearZoomZone(); + /** + * Creates a dynamic zoom cursor, that is used to zoom on specific parts of the screen, + * using a separate larger picture. This was only used by two SCI1.1 games, Laura Bow 2 + * (for examining the glyphs), and Freddy Pharkas (for examining the prescription with + * the whisky glass). + * + * In the Mac version of Freddy Pharkas, this was removed completely, and the scene has + * been redesigned to work without this functionality. There was no version of LB2 for + * the Macintosh platform. + */ void kernelSetZoomZone(byte multiplier, Common::Rect zone, GuiResourceId viewNum, int loopNum, int celNum, GuiResourceId picNum, byte zoomColor); + void kernelClearZoomZone(); void kernelSetPos(Common::Point pos); void kernelMoveCursor(Common::Point pos); diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index cb81fe8d61..6454a1eb32 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -21,6 +21,7 @@ */ #include "common/algorithm.h" +#include "common/config-manager.h" #include "common/events.h" #include "common/keyboard.h" #include "common/list.h" @@ -46,964 +47,1484 @@ #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" #include "sci/graphics/frameout.h" #include "sci/video/robot_decoder.h" namespace Sci { -// TODO/FIXME: This is all guesswork - -enum SciSpeciaPlanelPictureCodes { - kPlaneTranslucent = 0xfffe, // -2 - kPlanePlainColored = 0xffff // -1 +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 } +}; +static int16 divisionsDefaults[2][16] = { + /* SCI2.1early- */ { 1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 40, 40, 101, 101 }, + /* SCI2.1mid+ */ { 1, 20, 20, 20, 20, 10, 10, 10, 10, 20, 20, 6, 10, 101, 101, 2 } +}; +static int16 unknownCDefaults[2][16] = { + /* SCI2.1early- */ { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 0, 0, 0, 0 }, + /* SCI2.1mid+ */ { 0, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 0, 0, 7, 7, 0 } }; -GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette32 *palette, GfxPaint32 *paint32) - : _segMan(segMan), _resMan(resMan), _cache(cache), _screen(screen), _palette(palette), _paint32(paint32), _isHiRes(false) { - - _coordAdjuster = (GfxCoordAdjuster32 *)coordAdjuster; - _curScrollText = -1; - _showScrollText = false; - _maxScrollTexts = 0; +GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette32 *palette, GfxPaint32 *paint32) : + _isHiRes(false), + _cache(cache), + _palette(palette), + _resMan(resMan), + _screen(screen), + _segMan(segMan), + _paint32(paint32), + _showStyles(nullptr), + // TODO: Stop using _gfxScreen + _currentBuffer(screen->getDisplayWidth(), screen->getDisplayHeight(), nullptr), + _remapOccurred(false), + _frameNowVisible(false), + _screenRect(screen->getDisplayWidth(), screen->getDisplayHeight()), + _overdrawThreshold(0), + _palMorphIsOn(false) { + + _currentBuffer.setPixels(calloc(1, screen->getDisplayWidth() * screen->getDisplayHeight())); + + for (int i = 0; i < 236; i += 2) { + _styleRanges[i] = 0; + _styleRanges[i + 1] = -1; + } + for (int i = 236; i < ARRAYSIZE(_styleRanges); ++i) { + _styleRanges[i] = 0; + } // TODO: Make hires detection work uniformly across all SCI engine // versions (this flag is normally passed by SCI::MakeGraphicsMgr - // to the GraphicsMgr constructor depending upon video configuration) + // to the GraphicsMgr constructor depending upon video configuration, + // so should be handled upstream based on game configuration instead + // of here) if (getSciVersion() >= SCI_VERSION_2_1_EARLY && _resMan->detectHires()) { _isHiRes = true; } + + if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) { + _dissolveSequenceSeeds = dissolveSequences[0]; + _defaultDivisions = divisionsDefaults[0]; + _defaultUnknownC = unknownCDefaults[0]; + } else { + _dissolveSequenceSeeds = dissolveSequences[1]; + _defaultDivisions = divisionsDefaults[1]; + _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 + // frameOut, and (2) functions do a very simple lookup of the + // plane and arithmetic with the plane's gameRect. In + // principle, CoordAdjuster could be reused for + // convertGameRectToPlaneRect, but it is not super clear yet + // what the benefit would be to do that. + _coordAdjuster = (GfxCoordAdjuster32 *)coordAdjuster; + + // TODO: Script resolution is hard-coded per game; + // also this must be set or else the engine will crash + _coordAdjuster->setScriptsResolution(_currentBuffer.scriptWidth, _currentBuffer.scriptHeight); } GfxFrameout::~GfxFrameout() { clear(); + CelObj::deinit(); + free(_currentBuffer.getPixels()); } +void GfxFrameout::run() { + CelObj::init(); + Plane::init(); + ScreenItem::init(); + + // NOTE: This happens in SCI::InitPlane in the actual engine, + // and is a background fill plane to ensure hidden planes + // (planes with a priority of -1) are never drawn + Plane *initPlane = new Plane(Common::Rect(_currentBuffer.scriptWidth, _currentBuffer.scriptHeight)); + initPlane->_priority = 0; + _planes.add(initPlane); +} + +// SCI32 actually did not clear anything at all it seems on restore. The scripts actually cleared up +// planes + screen items right before restoring. And after restoring they sync'd its internal planes list +// as well. void GfxFrameout::clear() { - deletePlaneItems(NULL_REG); _planes.clear(); - deletePlanePictures(NULL_REG); - clearScrollTexts(); -} - -void GfxFrameout::clearScrollTexts() { - _scrollTexts.clear(); - _curScrollText = -1; -} - -void GfxFrameout::addScrollTextEntry(Common::String &text, reg_t kWindow, uint16 x, uint16 y, bool replace) { - //reg_t bitmapHandle = g_sci->_gfxText32->createScrollTextBitmap(text, kWindow); - // HACK: We set the container dimensions manually - reg_t bitmapHandle = g_sci->_gfxText32->createScrollTextBitmap(text, kWindow, 480, 70); - ScrollTextEntry textEntry; - textEntry.bitmapHandle = bitmapHandle; - textEntry.kWindow = kWindow; - textEntry.x = x; - textEntry.y = y; - if (!replace || _scrollTexts.size() == 0) { - if (_scrollTexts.size() > _maxScrollTexts) { - _scrollTexts.remove_at(0); - _curScrollText--; - } - _scrollTexts.push_back(textEntry); - _curScrollText++; - } else { - _scrollTexts.pop_back(); - _scrollTexts.push_back(textEntry); - } + _visiblePlanes.clear(); + _showList.clear(); } -void GfxFrameout::showCurrentScrollText() { - if (!_showScrollText || _curScrollText < 0) +// This is what Game::restore does, only needed when our ScummVM dialogs are patched in +// It actually does one pass before actual restore deleting screen items + planes +// And after restore it does another pass adding screen items + planes. +// Attention: at least Space Quest 6's option plane seems to stay in memory right from the start and is not re-created. +void GfxFrameout::syncWithScripts(bool addElements) { + EngineState *engineState = g_sci->getEngineState(); + SegManager *segMan = engineState->_segMan; + + // In case original save/restore dialogs are active, don't do anything + if (ConfMan.getBool("originalsaveload")) return; - uint16 size = (uint16)_scrollTexts.size(); - if (size > 0) { - assert(_curScrollText < size); - ScrollTextEntry textEntry = _scrollTexts[_curScrollText]; - g_sci->_gfxText32->drawScrollTextBitmap(textEntry.kWindow, textEntry.bitmapHandle, textEntry.x, textEntry.y); - } -} - -extern void showScummVMDialog(const Common::String &message); - -void GfxFrameout::kernelAddPlane(reg_t object) { - PlaneEntry newPlane; - - if (_planes.empty()) { - // There has to be another way for sierra sci to do this or maybe script resolution is compiled into - // interpreter (TODO) - uint16 scriptWidth = readSelectorValue(_segMan, object, SELECTOR(resX)); - uint16 scriptHeight = readSelectorValue(_segMan, object, SELECTOR(resY)); - - // Phantasmagoria 2 doesn't specify a script width/height - if (g_sci->getGameId() == GID_PHANTASMAGORIA2) { - scriptWidth = 640; - scriptHeight = 480; - } - - assert(scriptWidth > 0 && scriptHeight > 0); - _coordAdjuster->setScriptsResolution(scriptWidth, scriptHeight); - } - - // Import of QfG character files dialog is shown in QFG4. - // Display additional popup information before letting user use it. - // For the SCI0-SCI1.1 version of this, check kDrawControl(). - if (g_sci->inQfGImportRoom() && !strcmp(_segMan->getObjectName(object), "DSPlane")) { - showScummVMDialog("Characters saved inside ScummVM are shown " - "automatically. Character files saved in the original " - "interpreter need to be put inside ScummVM's saved games " - "directory and a prefix needs to be added depending on which " - "game it was saved in: 'qfg1-' for Quest for Glory 1, 'qfg2-' " - "for Quest for Glory 2, 'qfg3-' for Quest for Glory 3. " - "Example: 'qfg2-thief.sav'."); - } - - newPlane.object = object; - newPlane.priority = readSelectorValue(_segMan, object, SELECTOR(priority)); - newPlane.lastPriority = -1; // hidden - newPlane.planeOffsetX = 0; - newPlane.planeOffsetY = 0; - newPlane.pictureId = kPlanePlainColored; - newPlane.planePictureMirrored = false; - newPlane.planeBack = 0; - _planes.push_back(newPlane); - - kernelUpdatePlane(object); -} - -void GfxFrameout::kernelUpdatePlane(reg_t object) { - for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) { - if (it->object == object) { - // Read some information - it->priority = readSelectorValue(_segMan, object, SELECTOR(priority)); - GuiResourceId lastPictureId = it->pictureId; - it->pictureId = readSelectorValue(_segMan, object, SELECTOR(picture)); - if (lastPictureId != it->pictureId) { - // picture got changed, load new picture - deletePlanePictures(object); - // Draw the plane's picture if it's not a translucent/plane colored frame - if ((it->pictureId != kPlanePlainColored) && (it->pictureId != kPlaneTranslucent)) { - // SQ6 gives us a bad picture number for the control menu - if (_resMan->testResource(ResourceId(kResourceTypePic, it->pictureId))) - addPlanePicture(object, it->pictureId, 0); - } - } - it->planeRect.top = readSelectorValue(_segMan, object, SELECTOR(top)); - it->planeRect.left = readSelectorValue(_segMan, object, SELECTOR(left)); - it->planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)); - it->planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)); - - _coordAdjuster->fromScriptToDisplay(it->planeRect.top, it->planeRect.left); - _coordAdjuster->fromScriptToDisplay(it->planeRect.bottom, it->planeRect.right); - - // We get negative left in kq7 in scrolling rooms - if (it->planeRect.left < 0) { - it->planeOffsetX = -it->planeRect.left; - it->planeRect.left = 0; - } else { - it->planeOffsetX = 0; - } + // Get planes list object + reg_t planesListObject = engineState->variables[VAR_GLOBAL][10]; + reg_t planesListElements = readSelector(segMan, planesListObject, SELECTOR(elements)); - if (it->planeRect.top < 0) { - it->planeOffsetY = -it->planeRect.top; - it->planeRect.top = 0; - } else { - it->planeOffsetY = 0; - } + List *planesList = segMan->lookupList(planesListElements); + reg_t planesNodeObject = planesList->first; - // We get bad plane-bottom in sq6 - if (it->planeRect.right > _screen->getWidth()) - it->planeRect.right = _screen->getWidth(); - if (it->planeRect.bottom > _screen->getHeight()) - it->planeRect.bottom = _screen->getHeight(); - - it->planeClipRect = Common::Rect(it->planeRect.width(), it->planeRect.height()); - it->upscaledPlaneRect = it->planeRect; - it->upscaledPlaneClipRect = it->planeClipRect; - if (_screen->getUpscaledHires()) { - _screen->adjustToUpscaledCoordinates(it->upscaledPlaneRect.top, it->upscaledPlaneRect.left); - _screen->adjustToUpscaledCoordinates(it->upscaledPlaneRect.bottom, it->upscaledPlaneRect.right); - _screen->adjustToUpscaledCoordinates(it->upscaledPlaneClipRect.top, it->upscaledPlaneClipRect.left); - _screen->adjustToUpscaledCoordinates(it->upscaledPlaneClipRect.bottom, it->upscaledPlaneClipRect.right); - } + // Go through all elements of planes::elements + while (!planesNodeObject.isNull()) { + Node *planesNode = segMan->lookupNode(planesNodeObject); + reg_t planeObject = planesNode->value; + + if (addElements) { + // Add this plane object + kernelAddPlane(planeObject); + } + + reg_t planeCastsObject = readSelector(segMan, planeObject, SELECTOR(casts)); + reg_t setListElements = readSelector(segMan, planeCastsObject, SELECTOR(elements)); + + // Now go through all elements of plane::casts::elements + List *planeCastsList = segMan->lookupList(setListElements); + reg_t planeCastsNodeObject = planeCastsList->first; + + while (!planeCastsNodeObject.isNull()) { + Node *castsNode = segMan->lookupNode(planeCastsNodeObject); + reg_t castsObject = castsNode->value; + + reg_t castsListElements = readSelector(segMan, castsObject, SELECTOR(elements)); + + List *castsList = segMan->lookupList(castsListElements); + reg_t castNodeObject = castsList->first; - it->planePictureMirrored = readSelectorValue(_segMan, object, SELECTOR(mirrored)); - it->planeBack = readSelectorValue(_segMan, object, SELECTOR(back)); + while (!castNodeObject.isNull()) { + Node *castNode = segMan->lookupNode(castNodeObject); + reg_t castObject = castNode->value; - sortPlanes(); + // read selector "-info-" of this object + // TODO: Seems to have been changed for SCI3 + // Do NOT use getInfoSelector in here. SCI3 games did not use infoToa, but an actual selector. + // Maybe that selector is just a straight copy, but it needs to get verified/checked. + uint16 castInfoSelector = readSelectorValue(segMan, castObject, SELECTOR(_info_)); - // Update the items in the plane - for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { - reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane)); - if (object == itemPlane) { - kernelUpdateScreenItem((*listIterator)->object); + if (castInfoSelector & kInfoFlagViewInserted) { + if (addElements) { + // Flag set, so add this screen item + kernelAddScreenItem(castObject); + } else { + // Flag set, so delete this screen item + kernelDeleteScreenItem(castObject); + } } + + castNodeObject = castNode->succ; } - return; + planeCastsNodeObject = castsNode->succ; + } + + if (!addElements) { + // Delete this plane object + kernelDeletePlane(planeObject); } + + planesNodeObject = planesNode->succ; } - error("kUpdatePlane called on plane that wasn't added before"); } -void GfxFrameout::kernelDeletePlane(reg_t object) { - deletePlaneItems(object); - deletePlanePictures(object); +#pragma mark - +#pragma mark Screen items + +void GfxFrameout::kernelAddScreenItem(const reg_t object) { + const reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane)); - for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) { - if (it->object == object) { - _planes.erase(it); - Common::Rect planeRect; - planeRect.top = readSelectorValue(_segMan, object, SELECTOR(top)); - planeRect.left = readSelectorValue(_segMan, object, SELECTOR(left)); - planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)); - planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)); + _segMan->getObject(object)->setInfoSelectorFlag(kInfoFlagViewInserted); + + Plane *plane = _planes.findByObject(planeObject); + if (plane == nullptr) { + error("kAddScreenItem: Plane %04x:%04x not found for screen item %04x:%04x", PRINT_REG(planeObject), PRINT_REG(object)); + } + + ScreenItem *screenItem = plane->_screenItemList.findByObject(object); + if (screenItem != nullptr) { + screenItem->update(object); + } else { + screenItem = new ScreenItem(object); + plane->_screenItemList.add(screenItem); + } +} - _coordAdjuster->fromScriptToDisplay(planeRect.top, planeRect.left); - _coordAdjuster->fromScriptToDisplay(planeRect.bottom, planeRect.right); +void GfxFrameout::kernelUpdateScreenItem(const reg_t object) { + const reg_t magnifierObject = readSelector(_segMan, object, SELECTOR(magnifier)); + if (magnifierObject.isNull()) { + const reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane)); + Plane *plane = _planes.findByObject(planeObject); + if (plane == nullptr) { + error("kUpdateScreenItem: Plane %04x:%04x not found for screen item %04x:%04x", PRINT_REG(planeObject), PRINT_REG(object)); + } - // Blackout removed plane rect - _paint32->fillRect(planeRect, 0); - return; + ScreenItem *screenItem = plane->_screenItemList.findByObject(object); + if (screenItem == nullptr) { + error("kUpdateScreenItem: Screen item %04x:%04x not found in plane %04x:%04x", PRINT_REG(object), PRINT_REG(planeObject)); } + + screenItem->update(object); + } else { + error("Magnifier view is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!"); } } -void GfxFrameout::addPlanePicture(reg_t object, GuiResourceId pictureId, uint16 startX, uint16 startY) { - if (pictureId == kPlanePlainColored || pictureId == kPlaneTranslucent) // sanity check +void GfxFrameout::kernelDeleteScreenItem(const reg_t object) { + _segMan->getObject(object)->clearInfoSelectorFlag(kInfoFlagViewInserted); + + const reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane)); + Plane *plane = _planes.findByObject(planeObject); + if (plane == nullptr) { + return; + } + + ScreenItem *screenItem = plane->_screenItemList.findByObject(object); + if (screenItem == nullptr) { return; + } - PlanePictureEntry newPicture; - newPicture.object = object; - newPicture.pictureId = pictureId; - newPicture.picture = new GfxPicture(_resMan, _coordAdjuster, 0, _screen, _palette, pictureId, false); - newPicture.startX = startX; - newPicture.startY = startY; - newPicture.pictureCels = 0; - _planePictures.push_back(newPicture); + if (screenItem->_created == 0) { + screenItem->_created = 0; + screenItem->_updated = 0; + screenItem->_deleted = getScreenCount(); + } else { + plane->_screenItemList.erase(screenItem); + plane->_screenItemList.pack(); + } } -void GfxFrameout::deletePlanePictures(reg_t object) { - PlanePictureList::iterator it = _planePictures.begin(); +#pragma mark - +#pragma mark Planes - while (it != _planePictures.end()) { - if (it->object == object || object.isNull()) { - delete it->pictureCels; - delete it->picture; - it = _planePictures.erase(it); - } else { - ++it; - } +void GfxFrameout::kernelAddPlane(const reg_t object) { + Plane *plane = _planes.findByObject(object); + if (plane != nullptr) { + plane->update(object); + updatePlane(*plane); + } else { + plane = new Plane(object); + addPlane(*plane); } } -// Provides the same functionality as kGraph(DrawLine) -reg_t GfxFrameout::addPlaneLine(reg_t object, Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control) { - for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) { - if (it->object == object) { - PlaneLineEntry line; - line.hunkId = _segMan->allocateHunkEntry("PlaneLine()", 1); // we basically use this for a unique ID - line.startPoint = startPoint; - line.endPoint = endPoint; - line.color = color; - line.priority = priority; - line.control = control; - it->lines.push_back(line); - return line.hunkId; - } +void GfxFrameout::kernelUpdatePlane(const reg_t object) { + Plane *plane = _planes.findByObject(object); + if (plane == nullptr) { + error("kUpdatePlane: Plane %04x:%04x not found", PRINT_REG(object)); } - return NULL_REG; + plane->update(object); + updatePlane(*plane); } -void GfxFrameout::updatePlaneLine(reg_t object, reg_t hunkId, Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control) { - // Check if we're asked to update a line that was never added - if (hunkId.isNull()) - return; +void GfxFrameout::kernelDeletePlane(const reg_t object) { + Plane *plane = _planes.findByObject(object); + if (plane == nullptr) { + error("kDeletePlane: Plane %04x:%04x not found", PRINT_REG(object)); + } - for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) { - if (it->object == object) { - for (PlaneLineList::iterator it2 = it->lines.begin(); it2 != it->lines.end(); ++it2) { - if (it2->hunkId == hunkId) { - it2->startPoint = startPoint; - it2->endPoint = endPoint; - it2->color = color; - it2->priority = priority; - it2->control = control; - return; - } - } - } + if (plane->_created) { + // NOTE: The original engine calls some `AbortPlane` function that + // just ends up doing this anyway so we skip the extra indirection + _planes.erase(plane); + } else { + plane->_created = 0; + plane->_deleted = g_sci->_gfxFrameout->getScreenCount(); } } -void GfxFrameout::deletePlaneLine(reg_t object, reg_t hunkId) { - // Check if we're asked to delete a line that was never added (happens during the intro of LSL6) - if (hunkId.isNull()) - return; +void GfxFrameout::deletePlane(Plane &planeToFind) { + Plane *plane = _planes.findByObject(planeToFind._object); + if (plane == nullptr) { + error("deletePlane: Plane %04x:%04x not found", PRINT_REG(planeToFind._object)); + } - for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) { - if (it->object == object) { - for (PlaneLineList::iterator it2 = it->lines.begin(); it2 != it->lines.end(); ++it2) { - if (it2->hunkId == hunkId) { - _segMan->freeHunkEntry(hunkId); - it2 = it->lines.erase(it2); - return; - } - } - } + if (plane->_created) { + _planes.erase(plane); + } else { + plane->_created = 0; + plane->_moved = 0; + plane->_deleted = getScreenCount(); } } -// Adapted from GfxAnimate::applyGlobalScaling() -void GfxFrameout::applyGlobalScaling(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 celHeight) { - // Global scaling uses global var 2 and some other stuff to calculate scaleX/scaleY - int16 maxScale = readSelectorValue(_segMan, itemEntry->object, SELECTOR(maxScale)); - int16 maxCelHeight = (maxScale * celHeight) >> 7; - reg_t globalVar2 = g_sci->getEngineState()->variables[VAR_GLOBAL][2]; // current room object - int16 vanishingY = readSelectorValue(_segMan, globalVar2, SELECTOR(vanishingY)); +void GfxFrameout::kernelMovePlaneItems(const reg_t object, const int16 deltaX, const int16 deltaY, const bool scrollPics) { + Plane *plane = _planes.findByObject(object); + if (plane == nullptr) { + error("kMovePlaneItems: Plane %04x:%04x not found", PRINT_REG(object)); + } - int16 fixedPortY = planeRect.bottom - vanishingY; - int16 fixedEntryY = itemEntry->y - vanishingY; - if (!fixedEntryY) - fixedEntryY = 1; + plane->scrollScreenItems(deltaX, deltaY, scrollPics); - if ((celHeight == 0) || (fixedPortY == 0)) - error("global scaling panic"); + for (ScreenItemList::iterator it = plane->_screenItemList.begin(); it != plane->_screenItemList.end(); ++it) { + ScreenItem &screenItem = **it; - itemEntry->scaleY = (maxCelHeight * fixedEntryY) / fixedPortY; - itemEntry->scaleY = (itemEntry->scaleY * maxScale) / celHeight; + // If object is a number, the screen item from the + // engine, not a script, and should be ignored + if (screenItem._object.isNumber()) { + continue; + } - // Make sure that the calculated value is sane - if (itemEntry->scaleY < 1 /*|| itemEntry->scaleY > 128*/) - itemEntry->scaleY = 128; + if (deltaX != 0) { + writeSelectorValue(_segMan, screenItem._object, SELECTOR(x), readSelectorValue(_segMan, screenItem._object, SELECTOR(x)) + deltaX); + } - itemEntry->scaleX = itemEntry->scaleY; + if (deltaY != 0) { + writeSelectorValue(_segMan, screenItem._object, SELECTOR(y), readSelectorValue(_segMan, screenItem._object, SELECTOR(y)) + deltaY); + } + } +} - // and set objects scale selectors - //writeSelectorValue(_segMan, itemEntry->object, SELECTOR(scaleX), itemEntry->scaleX); - //writeSelectorValue(_segMan, itemEntry->object, SELECTOR(scaleY), itemEntry->scaleY); +int16 GfxFrameout::kernelGetHighPlanePri() { + return _planes.getTopSciPlanePriority(); } -void GfxFrameout::kernelAddScreenItem(reg_t object) { - // Ignore invalid items - if (!_segMan->isObject(object)) { - warning("kernelAddScreenItem: Attempt to add an invalid object (%04x:%04x)", PRINT_REG(object)); - return; +void GfxFrameout::addPlane(Plane &plane) { + if (_planes.findByObject(plane._object) == nullptr) { + plane.clipScreenRect(_screenRect); + _planes.add(&plane); + } else { + plane._deleted = 0; + if (plane._created == 0) { + plane._moved = g_sci->_gfxFrameout->getScreenCount(); + } + _planes.sort(); } +} + +void GfxFrameout::updatePlane(Plane &plane) { + // NOTE: This assertion comes from SCI engine code. + assert(_planes.findByObject(plane._object) == &plane); - FrameoutEntry *itemEntry = new FrameoutEntry(); - memset(itemEntry, 0, sizeof(FrameoutEntry)); - itemEntry->object = object; - itemEntry->givenOrderNr = _screenItems.size(); - itemEntry->visible = true; - _screenItems.push_back(itemEntry); + Plane *visiblePlane = _visiblePlanes.findByObject(plane._object); + plane.sync(visiblePlane, _screenRect); + // NOTE: updateScreenRect was originally called a second time here, + // but it is already called at the end of the Plane::Update call + // in the original engine anyway. - kernelUpdateScreenItem(object); + _planes.sort(); } -void GfxFrameout::kernelUpdateScreenItem(reg_t object) { - // Ignore invalid items - if (!_segMan->isObject(object)) { - warning("kernelUpdateScreenItem: Attempt to update an invalid object (%04x:%04x)", PRINT_REG(object)); - return; - } +#pragma mark - +#pragma mark Pics - FrameoutEntry *itemEntry = findScreenItem(object); - if (!itemEntry) { - warning("kernelUpdateScreenItem: invalid object %04x:%04x", PRINT_REG(object)); - return; +void GfxFrameout::kernelAddPicAt(const reg_t planeObject, const GuiResourceId pictureId, const int16 x, const int16 y, const bool mirrorX) { + Plane *plane = _planes.findByObject(planeObject); + if (plane == nullptr) { + error("kAddPicAt: Plane %04x:%04x not found", PRINT_REG(planeObject)); } + plane->addPic(pictureId, Common::Point(x, y), mirrorX); +} - itemEntry->viewId = readSelectorValue(_segMan, object, SELECTOR(view)); - itemEntry->loopNo = readSelectorValue(_segMan, object, SELECTOR(loop)); - itemEntry->celNo = readSelectorValue(_segMan, object, SELECTOR(cel)); - itemEntry->x = readSelectorValue(_segMan, object, SELECTOR(x)); - itemEntry->y = readSelectorValue(_segMan, object, SELECTOR(y)); - itemEntry->z = readSelectorValue(_segMan, object, SELECTOR(z)); - itemEntry->priority = readSelectorValue(_segMan, object, SELECTOR(priority)); - if (readSelectorValue(_segMan, object, SELECTOR(fixPriority)) == 0) - itemEntry->priority = itemEntry->y; +#pragma mark - +#pragma mark Rendering - itemEntry->signal = readSelectorValue(_segMan, object, SELECTOR(signal)); - itemEntry->scaleSignal = readSelectorValue(_segMan, object, SELECTOR(scaleSignal)); +void GfxFrameout::frameOut(const bool shouldShowBits, const Common::Rect &rect) { +// TODO: Robot +// if (_robot != nullptr) { +// _robot.doRobot(); +// } - if (itemEntry->scaleSignal & kScaleSignalDoScaling32) { - itemEntry->scaleX = readSelectorValue(_segMan, object, SELECTOR(scaleX)); - itemEntry->scaleY = readSelectorValue(_segMan, object, SELECTOR(scaleY)); - } else { - itemEntry->scaleX = 128; - itemEntry->scaleY = 128; - } - itemEntry->visible = true; + // NOTE: The original engine allocated these as static arrays of 100 + // pointers to ScreenItemList / RectList + ScreenItemListList screenItemLists; + EraseListList eraseLists; - // Check if the entry can be hidden - if (lookupSelector(_segMan, object, SELECTOR(visible), NULL, NULL) != kSelectorNone) - itemEntry->visible = readSelectorValue(_segMan, object, SELECTOR(visible)); -} + screenItemLists.resize(_planes.size()); + eraseLists.resize(_planes.size()); -void GfxFrameout::kernelDeleteScreenItem(reg_t object) { - FrameoutEntry *itemEntry = findScreenItem(object); - // If the item could not be found, it may already have been deleted - if (!itemEntry) - return; + if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) { + remapMarkRedraw(); + } - _screenItems.remove(itemEntry); - delete itemEntry; -} + calcLists(screenItemLists, eraseLists, rect); -void GfxFrameout::deletePlaneItems(reg_t planeObject) { - FrameoutList::iterator listIterator = _screenItems.begin(); + for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) { + list->sort(); + } - while (listIterator != _screenItems.end()) { - bool objectMatches = false; - if (!planeObject.isNull()) { - reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane)); - objectMatches = (planeObject == itemPlane); - } else { - objectMatches = true; + for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) { + for (DrawList::iterator drawItem = list->begin(); drawItem != list->end(); ++drawItem) { + (*drawItem)->screenItem->getCelObj().submitPalette(); } + } - if (objectMatches) { - FrameoutEntry *itemEntry = *listIterator; - listIterator = _screenItems.erase(listIterator); - delete itemEntry; - } else { - ++listIterator; - } + _remapOccurred = _palette->updateForFrame(); + + // NOTE: SCI engine set this to false on each loop through the + // planelist iterator below. Since that is a waste, we only set + // it once. + _frameNowVisible = false; + + for (PlaneList::size_type i = 0; i < _planes.size(); ++i) { + drawEraseList(eraseLists[i], *_planes[i]); + drawScreenItemList(screenItemLists[i]); } -} -FrameoutEntry *GfxFrameout::findScreenItem(reg_t object) { - for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { - FrameoutEntry *itemEntry = *listIterator; - if (itemEntry->object == object) - return itemEntry; +// TODO: Robot +// if (_robot != nullptr) { +// _robot->frameAlmostVisible(); +// } + + _palette->updateHardware(); + + if (shouldShowBits) { + showBits(); } - return NULL; -} + _frameNowVisible = true; -int16 GfxFrameout::kernelGetHighPlanePri() { - sortPlanes(); - return readSelectorValue(g_sci->getEngineState()->_segMan, _planes.back().object, SELECTOR(priority)); +// TODO: Robot +// if (_robot != nullptr) { +// robot->frameNowVisible(); +// } } -void GfxFrameout::kernelAddPicAt(reg_t planeObj, GuiResourceId pictureId, int16 pictureX, int16 pictureY) { - addPlanePicture(planeObj, pictureId, pictureX, pictureY); -} +// Determine the parts of 'r' that aren't overlapped by 'other'. +// Returns -1 if r and other have no intersection. +// Returns number of returned parts (in outRects) otherwise. +// (In particular, this returns 0 if r is contained in other.) +int splitRects(Common::Rect r, const Common::Rect &other, Common::Rect(&outRects)[4]) { + if (!r.intersects(other)) { + return -1; + } -bool sortHelper(const FrameoutEntry* entry1, const FrameoutEntry* entry2) { - if (entry1->priority == entry2->priority) { - if (entry1->y == entry2->y) - return (entry1->givenOrderNr < entry2->givenOrderNr); - return (entry1->y < entry2->y); + int count = 0; + if (r.top < other.top) { + Common::Rect &t = outRects[count++]; + t = r; + t.bottom = other.top; + r.top = other.top; } - return (entry1->priority < entry2->priority); -} -bool planeSortHelper(const PlaneEntry &entry1, const PlaneEntry &entry2) { - if (entry1.priority < 0) - return true; + if (r.bottom > other.bottom) { + Common::Rect &t = outRects[count++]; + t = r; + t.top = other.bottom; + r.bottom = other.bottom; + } - if (entry2.priority < 0) - return false; + if (r.left < other.left) { + Common::Rect &t = outRects[count++]; + t = r; + t.right = other.left; + r.left = other.left; + } - return entry1.priority < entry2.priority; + if (r.right > other.right) { + Common::Rect &t = outRects[count++]; + t = r; + t.left = other.right; + } + + return count; } -void GfxFrameout::sortPlanes() { - // First, remove any invalid planes - for (PlaneList::iterator it = _planes.begin(); it != _planes.end();) { - if (!_segMan->isObject(it->object)) - it = _planes.erase(it); - else - it++; +void GfxFrameout::calcLists(ScreenItemListList &drawLists, EraseListList &eraseLists, const Common::Rect &calcRect) { + RectList rectlist; + Common::Rect outRects[4]; + + int deletedPlaneCount = 0; + bool addedToRectList = false; + int planeCount = _planes.size(); + bool foundTransparentPlane = false; + + if (!calcRect.isEmpty()) { + addedToRectList = true; + rectlist.add(calcRect); } - // Sort the rest of them - Common::sort(_planes.begin(), _planes.end(), planeSortHelper); -} + for (int outerPlaneIndex = 0; outerPlaneIndex < planeCount; ++outerPlaneIndex) { + Plane *outerPlane = _planes[outerPlaneIndex]; -void GfxFrameout::showVideo() { - bool skipVideo = false; - RobotDecoder *videoDecoder = g_sci->_robotDecoder; - uint16 x = videoDecoder->getPos().x; - uint16 y = videoDecoder->getPos().y; - uint16 screenWidth = _screen->getWidth(); - uint16 screenHeight = _screen->getHeight(); - uint16 outputWidth; - uint16 outputHeight; + if (outerPlane->_type == kPlaneTypeTransparent) { + foundTransparentPlane = true; + } - if (videoDecoder->hasDirtyPalette()) - g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256); + Plane *visiblePlane = _visiblePlanes.findByObject(outerPlane->_object); - while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { - if (videoDecoder->needsUpdate()) { - const Graphics::Surface *frame = videoDecoder->decodeNextFrame(); - if (frame) { - // We need to clip here - // At least Phantasmagoria shows a 640x390 video on a 630x450 screen during the intro - outputWidth = frame->w > screenWidth ? screenWidth : frame->w; - outputHeight = frame->h > screenHeight ? screenHeight : frame->h; - g_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, outputWidth, outputHeight); + if (outerPlane->_deleted) { + if (visiblePlane != nullptr) { + if (!visiblePlane->_screenRect.isEmpty()) { + addedToRectList = true; + rectlist.add(visiblePlane->_screenRect); + } + } + ++deletedPlaneCount; + } else if (visiblePlane != nullptr) { + if (outerPlane->_updated) { + --outerPlane->_updated; + + int splitcount = splitRects(visiblePlane->_screenRect, outerPlane->_screenRect, outRects); + if (splitcount) { + if (splitcount == -1) { + if (!visiblePlane->_screenRect.isEmpty()) { + rectlist.add(visiblePlane->_screenRect); + } + } else { + for (int i = 0; i < splitcount; ++i) { + rectlist.add(outRects[i]); + } + } - if (videoDecoder->hasDirtyPalette()) - g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256); + addedToRectList = true; + } - g_system->updateScreen(); + if (!outerPlane->_redrawAllCount) { + int splitCount = splitRects(outerPlane->_screenRect, visiblePlane->_screenRect, outRects); + if (splitCount) { + for (int i = 0; i < splitCount; ++i) { + rectlist.add(outRects[i]); + } + addedToRectList = true; + } + } } } - Common::Event event; - while (g_system->getEventManager()->pollEvent(event)) { - if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP) - skipVideo = true; - } + if (addedToRectList) { + for (RectList::iterator rect = rectlist.begin(); rect != rectlist.end(); ++rect) { + for (int innerPlaneIndex = _planes.size() - 1; innerPlaneIndex >= 0; --innerPlaneIndex) { + Plane *innerPlane = _planes[innerPlaneIndex]; + + if (!innerPlane->_deleted && innerPlane->_type != kPlaneTypeTransparent && innerPlane->_screenRect.intersects(**rect)) { + if (innerPlane->_redrawAllCount == 0) { + eraseLists[innerPlaneIndex].add(innerPlane->_screenRect.findIntersectingRect(**rect)); + } + + int splitCount = splitRects(**rect, innerPlane->_screenRect, outRects); + for (int i = 0; i < splitCount; ++i) { + rectlist.add(outRects[i]); + } + + rectlist.erase(rect); + break; + } + } + } - g_system->delayMillis(10); + rectlist.pack(); + } } -} -void GfxFrameout::createPlaneItemList(reg_t planeObject, FrameoutList &itemList) { - // Copy screen items of the current frame to the list of items to be drawn - for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { - reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane)); - if (planeObject == itemPlane) { - kernelUpdateScreenItem((*listIterator)->object); // TODO: Why is this necessary? - itemList.push_back(*listIterator); + // clean up deleted planes + if (deletedPlaneCount) { + for (int planeIndex = planeCount - 1; planeIndex >= 0; --planeIndex) { + Plane *plane = _planes[planeIndex]; + + if (plane->_deleted) { + --plane->_deleted; + if (plane->_deleted <= 0) { + PlaneList::iterator visiblePlaneIt = Common::find_if(_visiblePlanes.begin(), _visiblePlanes.end(), FindByObject<Plane *>(plane->_object)); + if (visiblePlaneIt != _visiblePlanes.end()) { + _visiblePlanes.erase(visiblePlaneIt); + } + + _planes.remove_at(planeIndex); + eraseLists.remove_at(planeIndex); + drawLists.remove_at(planeIndex); + } + + if (--deletedPlaneCount <= 0) { + break; + } + } } } - for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) { - if (pictureIt->object == planeObject) { - GfxPicture *planePicture = pictureIt->picture; - // Allocate memory for picture cels - pictureIt->pictureCels = new FrameoutEntry[planePicture->getSci32celCount()]; + planeCount = _planes.size(); + for (int outerIndex = 0; outerIndex < planeCount; ++outerIndex) { + // "outer" just refers to the outer loop + Plane *outerPlane = _planes[outerIndex]; + if (outerPlane->_priorityChanged) { + --outerPlane->_priorityChanged; + + Plane *visibleOuterPlane = _visiblePlanes.findByObject(outerPlane->_object); + + rectlist.add(outerPlane->_screenRect.findIntersectingRect(visibleOuterPlane->_screenRect)); + + for (int innerIndex = planeCount - 1; innerIndex >= 0; --innerIndex) { + // "inner" just refers to the inner loop + Plane *innerPlane = _planes[innerIndex]; + Plane *visibleInnerPlane = _visiblePlanes.findByObject(innerPlane->_object); + + int rectCount = rectlist.size(); + for (int rectIndex = 0; rectIndex < rectCount; ++rectIndex) { + int splitCount = splitRects(*rectlist[rectIndex], _planes[innerIndex]->_screenRect, outRects); + + if (splitCount == 0) { + if (visibleInnerPlane != nullptr) { + // same priority, or relative priority between inner/outer changed + if ((visibleOuterPlane->_priority - visibleInnerPlane->_priority) * (outerPlane->_priority - innerPlane->_priority) <= 0) { + if (outerPlane->_priority <= innerPlane->_priority) { + eraseLists[innerIndex].add(*rectlist[rectIndex]); + } else { + eraseLists[outerIndex].add(*rectlist[rectIndex]); + } + } + } + + rectlist.erase_at(rectIndex); + } else if (splitCount != -1) { + for (int i = 0; i < splitCount; ++i) { + rectlist.add(outRects[i]); + } + + if (visibleInnerPlane != nullptr) { + // same priority, or relative priority between inner/outer changed + if ((visibleOuterPlane->_priority - visibleInnerPlane->_priority) * (outerPlane->_priority - innerPlane->_priority) <= 0) { + *rectlist[rectIndex] = outerPlane->_screenRect.findIntersectingRect(innerPlane->_screenRect); + if (outerPlane->_priority <= innerPlane->_priority) { + eraseLists[innerIndex].add(*rectlist[rectIndex]); + } + else { + eraseLists[outerIndex].add(*rectlist[rectIndex]); + } + } + } + rectlist.erase_at(rectIndex); + } + } + rectlist.pack(); + } + } + } - // Add following cels to the itemlist - FrameoutEntry *picEntry = pictureIt->pictureCels; - int planePictureCels = planePicture->getSci32celCount(); - for (int pictureCelNr = 0; pictureCelNr < planePictureCels; pictureCelNr++) { - picEntry->celNo = pictureCelNr; - picEntry->object = NULL_REG; - picEntry->picture = planePicture; - picEntry->y = planePicture->getSci32celY(pictureCelNr); - picEntry->x = planePicture->getSci32celX(pictureCelNr); - picEntry->picStartX = pictureIt->startX; - picEntry->picStartY = pictureIt->startY; - picEntry->visible = true; + for (int planeIndex = 0; planeIndex < planeCount; ++planeIndex) { + Plane *plane = _planes[planeIndex]; + Plane *visiblePlane = nullptr; - picEntry->priority = planePicture->getSci32celPriority(pictureCelNr); + PlaneList::iterator visiblePlaneIt = Common::find_if(_visiblePlanes.begin(), _visiblePlanes.end(), FindByObject<Plane *>(plane->_object)); + if (visiblePlaneIt != _visiblePlanes.end()) { + visiblePlane = *visiblePlaneIt; + } - itemList.push_back(picEntry); - picEntry++; + if (plane->_redrawAllCount) { + plane->redrawAll(visiblePlane, _planes, drawLists[planeIndex], eraseLists[planeIndex]); + } else { + if (visiblePlane == nullptr) { + error("Missing visible plane for source plane %04x:%04x", PRINT_REG(plane->_object)); } + + plane->calcLists(*visiblePlane, _planes, drawLists[planeIndex], eraseLists[planeIndex]); + } + + if (plane->_created) { + _visiblePlanes.add(new Plane(*plane)); + --plane->_created; + } else if (plane->_moved) { + assert(visiblePlaneIt != _visiblePlanes.end()); + **visiblePlaneIt = *plane; + --plane->_moved; } } - // Now sort our itemlist - Common::sort(itemList.begin(), itemList.end(), sortHelper); -} + if (foundTransparentPlane) { + for (int planeIndex = 0; planeIndex < planeCount; ++planeIndex) { + for (int i = planeIndex + 1; i < planeCount; ++i) { + if (_planes[i]->_type == kPlaneTypeTransparent) { + _planes[i]->filterUpEraseRects(drawLists[i], eraseLists[planeIndex]); + } + } -bool GfxFrameout::isPictureOutOfView(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 planeOffsetX, int16 planeOffsetY) { - // Out of view horizontally (sanity checks) - int16 pictureCelStartX = itemEntry->picStartX + itemEntry->x; - int16 pictureCelEndX = pictureCelStartX + itemEntry->picture->getSci32celWidth(itemEntry->celNo); - int16 planeStartX = planeOffsetX; - int16 planeEndX = planeStartX + planeRect.width(); - if (pictureCelEndX < planeStartX) - return true; - if (pictureCelStartX > planeEndX) - return true; + if (_planes[planeIndex]->_type == kPlaneTypeTransparent) { + for (int i = planeIndex - 1; i >= 0; --i) { + _planes[i]->filterDownEraseRects(drawLists[i], eraseLists[i], eraseLists[planeIndex]); + } - // Out of view vertically (sanity checks) - int16 pictureCelStartY = itemEntry->picStartY + itemEntry->y; - int16 pictureCelEndY = pictureCelStartY + itemEntry->picture->getSci32celHeight(itemEntry->celNo); - int16 planeStartY = planeOffsetY; - int16 planeEndY = planeStartY + planeRect.height(); - if (pictureCelEndY < planeStartY) - return true; - if (pictureCelStartY > planeEndY) - return true; + if (eraseLists[planeIndex].size() > 0) { + error("Transparent plane's erase list not absorbed"); + } + } - return false; + for (int i = planeIndex + 1; i < planeCount; ++i) { + if (_planes[i]->_type == kPlaneTypeTransparent) { + _planes[i]->filterUpDrawRects(drawLists[i], drawLists[planeIndex]); + } + } + } + } } -void GfxFrameout::drawPicture(FrameoutEntry *itemEntry, int16 planeOffsetX, int16 planeOffsetY, bool planePictureMirrored) { - int16 pictureOffsetX = planeOffsetX; - int16 pictureX = itemEntry->x; - if ((planeOffsetX) || (itemEntry->picStartX)) { - if (planeOffsetX <= itemEntry->picStartX) { - pictureX += itemEntry->picStartX - planeOffsetX; - pictureOffsetX = 0; - } else { - pictureOffsetX = planeOffsetX - itemEntry->picStartX; - } +void GfxFrameout::drawEraseList(const RectList &eraseList, const Plane &plane) { + if (plane._type != kPlaneTypeColored) { + return; } - int16 pictureOffsetY = planeOffsetY; - int16 pictureY = itemEntry->y; - if ((planeOffsetY) || (itemEntry->picStartY)) { - if (planeOffsetY <= itemEntry->picStartY) { - pictureY += itemEntry->picStartY - planeOffsetY; - pictureOffsetY = 0; - } else { - pictureOffsetY = planeOffsetY - itemEntry->picStartY; + for (RectList::const_iterator it = eraseList.begin(); it != eraseList.end(); ++it) { + mergeToShowList(**it, _showList, _overdrawThreshold); + _currentBuffer.fillRect(**it, plane._back); + } +} + +void GfxFrameout::drawScreenItemList(const DrawList &screenItemList) { + for (DrawList::const_iterator it = screenItemList.begin(); it != screenItemList.end(); ++it) { + DrawItem &drawItem = **it; + mergeToShowList(drawItem.rect, _showList, _overdrawThreshold); + ScreenItem &screenItem = *drawItem.screenItem; + // TODO: Remove +// debug("Drawing item %04x:%04x to %d %d %d %d", PRINT_REG(screenItem._object), PRINT_RECT(drawItem.rect)); + CelObj &celObj = *screenItem._celObj; + celObj.draw(_currentBuffer, screenItem, drawItem.rect, screenItem._mirrorX ^ celObj._mirrorX); + } +} + +void GfxFrameout::mergeToShowList(const Common::Rect &drawRect, RectList &showList, const int overdrawThreshold) { + Common::Rect merged(drawRect); + + bool didDelete = true; + RectList::size_type count = showList.size(); + while (didDelete && count) { + didDelete = false; + + for (RectList::size_type i = 0; i < count; ++i) { + Common::Rect existing = *showList[i]; + Common::Rect candidate; + candidate.left = MIN(merged.left, existing.left); + candidate.top = MIN(merged.top, existing.top); + candidate.right = MAX(merged.right, existing.right); + candidate.bottom = MAX(merged.bottom, existing.bottom); + + if (candidate.height() * candidate.width() - merged.width() * merged.height() - existing.width() * existing.height() <= overdrawThreshold) { + merged = candidate; + showList.erase_at(i); + didDelete = true; + } } + + count = showList.pack(); } - itemEntry->picture->drawSci32Vga(itemEntry->celNo, pictureX, itemEntry->y, pictureOffsetX, pictureOffsetY, planePictureMirrored); - // warning("picture cel %d %d", itemEntry->celNo, itemEntry->priority); + showList.add(merged); } -/* TODO: This is the proper implementation of GraphicsMgr::FrameOut transcribed from SQ6 SCI engine disassembly. -static DrawList* g_drawLists[100]; -static RectList* g_rectLists[100]; -void GfxFrameout::FrameOut(bool shouldShowBits, SOL_Rect *rect) { - if (robot) { - robot.doRobot(); +void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry *showStyle) { + Palette sourcePalette(*_palette->getNextPalette()); + alterVmap(sourcePalette, sourcePalette, -1, styleRanges); + + int16 prevRoom = g_sci->getEngineState()->variables[VAR_GLOBAL][12].toSint16(); + + Common::Rect rect(_screen->getDisplayWidth(), _screen->getDisplayHeight()); + _showList.add(rect); + showBits(); + + Common::Rect calcRect(0, 0); + + // NOTE: The original engine allocated these as static arrays of 100 + // pointers to ScreenItemList / RectList + ScreenItemListList screenItemLists; + EraseListList eraseLists; + + screenItemLists.resize(_planes.size()); + eraseLists.resize(_planes.size()); + + if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) { + remapMarkRedraw(); } - auto planeCount = screen.planeList.planeCount; - if (planeCount > 0) { - for (int planeIndex = 0; planeIndex < planeCount; ++planeIndex) { - Plane plane = *screen.planeList[planeIndex]; + calcLists(screenItemLists, eraseLists, calcRect); + for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) { + list->sort(); + } - DrawList* drawList = new DrawList(); - g_drawLists[planeIndex] = drawList; - RectList* rectList = new RectList(); - g_rectLists[planeIndex] = rectList; + for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) { + for (DrawList::iterator drawItem = list->begin(); drawItem != list->end(); ++drawItem) { + (*drawItem)->screenItem->getCelObj().submitPalette(); } } - - if (g_Remap_numActiveRemaps > 0 && remapNeeded) { - screen.RemapMarkRedraw(); + + _remapOccurred = _palette->updateForFrame(); + _frameNowVisible = false; + + for (PlaneList::size_type i = 0; i < _planes.size(); ++i) { + drawEraseList(eraseLists[i], *_planes[i]); + drawScreenItemList(screenItemLists[i]); } - - CalcLists(&g_drawLists, &g_rectLists, rect); - // SCI engine stores reference *after* CalcLists - planeCount = screen.planeList.planeCount; - if (planeCount > 0) { - for (int drawListIndex = 0; drawListIndex < planeCount; ++i) { - DrawList* drawList = g_drawLists[drawListIndex]; - drawList->Sort(); - } + Palette nextPalette(*_palette->getNextPalette()); - for (int drawListIndex = 0; drawListIndex < planeCount; ++i) { - DrawList* drawList = g_drawLists[drawListIndex]; - if (drawList == nullptr || drawList->count == 0) { - continue; + 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]; + sourcePalette.colors[i].used = true; } - - for (int screenItemIndex = 0, screenItemCount = drawList->count; screenItemIndex < screenItemCount; ++screenItemIndex) { - ScreenItem* screenItem = drawList->items[screenItemIndex]; - screenItem->GetCelObj()->SubmitPalette(); + } + } else { + for (int i = 0; i < ARRAYSIZE(sourcePalette.colors); ++i) { + if (styleRanges[i] == -1 || (styleRanges[i] == 0 && i > 71 && i < 104)) { + sourcePalette.colors[i] = nextPalette.colors[i]; + sourcePalette.colors[i].used = true; } } } - // UpdateForFrame is where all palette mutations occur (cycles, varies, etc.) - bool remapNeeded = GPalette().UpdateForFrame(); - if (planeCount > 0) { - frameNowVisible = false; + _palette->submit(sourcePalette); + _palette->updateFFrame(); + _palette->updateHardware(); + alterVmap(nextPalette, sourcePalette, 1, _styleRanges); - for (int planeIndex = 0; planeIndex < planeCount; ++planeIndex) { - Plane* plane = screen.planeList[planeIndex]; + if (showStyle && showStyle->type != kShowStyleUnknown) { +// TODO: SCI2.1mid transition effects +// processEffects(); + warning("Transition %d not implemented!", showStyle->type); + } else { + showBits(); + } + + _frameNowVisible = true; - DrawEraseList(g_rectLists[planeIndex], plane); - DrawScreenItemsList(g_drawLists[planeIndex]); + for (PlaneList::iterator plane = _planes.begin(); plane != _planes.end(); ++plane) { + (*plane)->_redrawAllCount = getScreenCount(); + } + + if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) { + remapMarkRedraw(); + } + + calcLists(screenItemLists, eraseLists, calcRect); + for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) { + list->sort(); + } + + for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) { + for (DrawList::iterator drawItem = list->begin(); drawItem != list->end(); ++drawItem) { + (*drawItem)->screenItem->getCelObj().submitPalette(); } } - if (robot) { - robot.FrameAlmostVisible(); + _remapOccurred = _palette->updateForFrame(); + // NOTE: During this second loop, `_frameNowVisible = false` is + // inside the next loop in SCI2.1mid + _frameNowVisible = false; + + for (PlaneList::size_type i = 0; i < _planes.size(); ++i) { + drawEraseList(eraseLists[i], *_planes[i]); + drawScreenItemList(screenItemLists[i]); } - GPalette().UpdateHardware(); + _palette->submit(nextPalette); + _palette->updateFFrame(); + _palette->updateHardware(); + showBits(); - if (shouldShowBits) { - ShowBits(); + _frameNowVisible = true; +} + +// TODO: What does the bit masking for the show rects do, +// and does it cause an off-by-one error in rect calculations +// since SOL_Rect is BR inclusive and Common::Rect is BR +// exclusive? +void GfxFrameout::showBits() { + for (RectList::const_iterator rect = _showList.begin(); rect != _showList.end(); ++rect) { + Common::Rect rounded(**rect); + // NOTE: SCI engine used BR-inclusive rects so used slightly + // different masking here to ensure that the width of rects + // was always even. + rounded.left &= ~1; + rounded.right = (rounded.right + 1) & ~1; + + // TODO: + // _cursor->GonnaPaint(rounded); } - frameNowVisible = true; + // TODO: + // _cursor->PaintStarting(); + + for (RectList::const_iterator rect = _showList.begin(); rect != _showList.end(); ++rect) { + Common::Rect rounded(**rect); + // NOTE: SCI engine used BR-inclusive rects so used slightly + // different masking here to ensure that the width of rects + // was always even. + rounded.left &= ~1; + rounded.right = (rounded.right + 1) & ~1; - if (robot) { - robot.FrameNowVisible(); + byte *sourceBuffer = (byte *)_currentBuffer.getPixels() + rounded.top * _currentBuffer.screenWidth + rounded.left; + + g_system->copyRectToScreen(sourceBuffer, _currentBuffer.screenWidth, rounded.left, rounded.top, rounded.width(), rounded.height()); } - if (planeCount > 0) { - for (int planeIndex = 0; planeIndex < planeCount; ++planeIndex) { - if (g_rectLists[planeIndex] != nullptr) { - delete g_rectLists[planeIndex]; + // TODO: + // _cursor->DonePainting(); + + _showList.clear(); +} + +void GfxFrameout::alterVmap(const Palette &palette1, const Palette &palette2, const int8 style, const int8 *const styleRanges) { + uint8 clut[256]; + + for (int paletteIndex = 0; paletteIndex < ARRAYSIZE(palette1.colors); ++paletteIndex) { + int outerR = palette1.colors[paletteIndex].r; + int outerG = palette1.colors[paletteIndex].g; + int outerB = palette1.colors[paletteIndex].b; + + if (styleRanges[paletteIndex] == style) { + int minDiff = 262140; + int minDiffIndex; + + for (int i = 0; i < 236; ++i) { + if (styleRanges[i] != style) { + int r = palette1.colors[i].r; + int g = palette1.colors[i].g; + int b = palette1.colors[i].b; + int diffSquared = (outerR - r) * (outerR - r) + (outerG - g) * (outerG - g) + (outerB - b) * (outerB - b); + if (diffSquared < minDiff) { + minDiff = diffSquared; + minDiffIndex = i; + } + } } - if (g_drawLists[planeIndex] != nullptr) { - delete g_drawLists[planeIndex]; + + clut[paletteIndex] = minDiffIndex; + } + + if (style == 1 && styleRanges[paletteIndex] == 0) { + int minDiff = 262140; + int minDiffIndex; + + for (int i = 0; i < 236; ++i) { + int r = palette2.colors[i].r; + int g = palette2.colors[i].g; + int b = palette2.colors[i].b; + + int diffSquared = (outerR - r) * (outerR - r) + (outerG - g) * (outerG - g) + (outerB - b) * (outerB - b); + if (diffSquared < minDiff) { + minDiff = diffSquared; + minDiffIndex = i; + } } + + clut[paletteIndex] = minDiffIndex; + } + } + + // NOTE: This is currBuffer->ptr in SCI engine + byte *pixels = (byte *)_currentBuffer.getPixels(); + + for (int pixelIndex = 0, numPixels = _currentBuffer.screenWidth * _currentBuffer.screenHeight; pixelIndex < numPixels; ++pixelIndex) { + byte currentValue = pixels[pixelIndex]; + int8 styleRangeValue = styleRanges[currentValue]; + if (styleRangeValue == -1 && styleRangeValue == style) { + currentValue = pixels[pixelIndex] = 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 ( + (styleRangeValue == 1 && styleRangeValue == style) || + (styleRangeValue == 0 && style == 1) + ) { + pixels[pixelIndex] = clut[currentValue]; } } } -void GfxFrameout::CalcLists(DrawList **drawLists, RectList **rectLists, SOL_Rect *rect) { - screen.CalcLists(&visibleScreen, drawLists, rectLists, rect); -} -*/ -void GfxFrameout::kernelFrameout() { - if (g_sci->_robotDecoder->isVideoLoaded()) { - showVideo(); + +void GfxFrameout::kernelSetPalStyleRange(const uint8 fromColor, const uint8 toColor) { + if (toColor > fromColor) { return; } - _palette->updateForFrame(); + for (int i = fromColor; i < toColor; ++i) { + _styleRanges[i] = 0; + } +} - // TODO: Tons of drawing stuff should be here, see commented out implementation above +inline ShowStyleEntry * GfxFrameout::findShowStyleForPlane(const reg_t planeObj) const { + ShowStyleEntry *entry = _showStyles; + while (entry != nullptr) { + if (entry->plane == planeObj) { + break; + } + entry = entry->next; + } - _palette->updateHardware(); + return entry; +} - for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); it++) { - reg_t planeObject = it->object; +inline ShowStyleEntry *GfxFrameout::deleteShowStyleInternal(ShowStyleEntry *const showStyle) { + ShowStyleEntry *lastEntry = nullptr; - // Draw any plane lines, if they exist - // These are drawn on invisible planes as well. (e.g. "invisiblePlane" in LSL6 hires) - // FIXME: Lines aren't always drawn (e.g. when the narrator speaks in LSL6 hires). - // Perhaps something is painted over them? - for (PlaneLineList::iterator it2 = it->lines.begin(); it2 != it->lines.end(); ++it2) { - Common::Point startPoint = it2->startPoint; - Common::Point endPoint = it2->endPoint; - _coordAdjuster->kernelLocalToGlobal(startPoint.x, startPoint.y, it->object); - _coordAdjuster->kernelLocalToGlobal(endPoint.x, endPoint.y, it->object); - _screen->drawLine(startPoint, endPoint, it2->color, it2->priority, it2->control); + for (ShowStyleEntry *testEntry = _showStyles; testEntry != nullptr; testEntry = testEntry->next) { + if (testEntry == showStyle) { + break; } + lastEntry = testEntry; + } - int16 planeLastPriority = it->lastPriority; + if (lastEntry == nullptr) { + _showStyles = showStyle->next; + lastEntry = _showStyles; + } else { + lastEntry->next = showStyle->next; + } - // Update priority here, sq6 sets it w/o UpdatePlane - int16 planePriority = it->priority = readSelectorValue(_segMan, planeObject, SELECTOR(priority)); + delete[] showStyle->fadeColorRanges; + delete showStyle; - it->lastPriority = planePriority; - if (planePriority < 0) { // Plane currently not meant to be shown - // If plane was shown before, delete plane rect - if (planePriority != planeLastPriority) - _paint32->fillRect(it->planeRect, 0); - continue; - } + // TODO: Verify that this is the correct entry to return + // for the loop in processShowStyles to work correctly + return lastEntry; +} - // There is a race condition lurking in SQ6, which causes the game to hang in the intro, when teleporting to Polysorbate LX. - // Since I first wrote the patch, the race has stopped occurring for me though. - // I'll leave this for investigation later, when someone can reproduce. - //if (it->pictureId == kPlanePlainColored) // FIXME: This is what SSCI does, and fixes the intro of LSL7, but breaks the dialogs in GK1 (adds black boxes) - if (it->pictureId == kPlanePlainColored && (it->planeBack || g_sci->getGameId() != GID_GK1)) - _paint32->fillRect(it->planeRect, it->planeBack); +// TODO: 10-argument version is only in SCI3; argc checks are currently wrong for this version +// 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, reg_t pFadeArray, int16 divisions, const int16 blackScreen) { + + bool hasDivisions = false; + bool hasFadeArray = false; + + // 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) { + hasDivisions = argc > 8; + hasFadeArray = argc > 7; + } else { + hasDivisions = argc > 9; + hasFadeArray = argc > 8; + } - _coordAdjuster->pictureSetDisplayArea(it->planeRect); - // Invoking drewPicture() with an invalid picture ID in SCI32 results in - // invalidating the palVary palette when a palVary effect is active. This - // is quite obvious in QFG4, where the day time palette is incorrectly - // shown when exiting the caves, and the correct night time palette - // flashes briefly each time that kPalVaryInit is called. - if (it->pictureId != 0xFFFF) - _palette->drewPicture(it->pictureId); + bool isFadeUp; + int16 color; + if (back != -1) { + isFadeUp = false; + color = back; + } else { + isFadeUp = true; + color = 0; + } - FrameoutList itemList; + if ((getSciVersion() < SCI_VERSION_2_1_MIDDLE && type == 15) || type > 15) { + error("Illegal show style %d for plane %04x:%04x", type, PRINT_REG(planeObj)); + } - createPlaneItemList(planeObject, itemList); + Plane *plane = _planes.findByObject(planeObj); + if (plane == nullptr) { + error("Plane %04x:%04x is not present in active planes list", PRINT_REG(planeObj)); + } - for (FrameoutList::iterator listIterator = itemList.begin(); listIterator != itemList.end(); listIterator++) { - FrameoutEntry *itemEntry = *listIterator; + bool createNewEntry = true; + ShowStyleEntry *entry = findShowStyleForPlane(planeObj); + if (entry != nullptr) { + // TODO: SCI2.1early has different criteria for show style reuse + bool useExisting = true; - if (!itemEntry->visible) - continue; + if (useExisting) { + useExisting = entry->divisions == (hasDivisions ? divisions : _defaultDivisions[type]) && entry->unknownC == _defaultUnknownC[type]; + } - if (itemEntry->object.isNull()) { - // Picture cel data - _coordAdjuster->fromScriptToDisplay(itemEntry->y, itemEntry->x); - _coordAdjuster->fromScriptToDisplay(itemEntry->picStartY, itemEntry->picStartX); + if (useExisting) { + createNewEntry = false; + isFadeUp = true; + entry->currentStep = 0; + } else { + isFadeUp = true; + color = entry->color; + deleteShowStyleInternal(entry/*, true*/); + entry = nullptr; + } + } - if (!isPictureOutOfView(itemEntry, it->planeRect, it->planeOffsetX, it->planeOffsetY)) - drawPicture(itemEntry, it->planeOffsetX, it->planeOffsetY, it->planePictureMirrored); - } else { - GfxView *view = (itemEntry->viewId != 0xFFFF) ? _cache->getView(itemEntry->viewId) : NULL; - int16 dummyX = 0; - - if (view && view->isSci2Hires()) { - view->adjustToUpscaledCoordinates(itemEntry->y, itemEntry->x); - view->adjustToUpscaledCoordinates(itemEntry->z, dummyX); - } else if (getSciVersion() >= SCI_VERSION_2_1_EARLY) { - _coordAdjuster->fromScriptToDisplay(itemEntry->y, itemEntry->x); - _coordAdjuster->fromScriptToDisplay(itemEntry->z, dummyX); + if (type > 0) { + if (createNewEntry) { + entry = new ShowStyleEntry; + // NOTE: SCI2.1 engine tests if allocation returned a null pointer + // but then only avoids setting currentStep if this is so. Since + // this is a nonsensical approach, we do not do that here + entry->currentStep = 0; + entry->unknownC = _defaultUnknownC[type]; + entry->processed = false; + entry->divisions = hasDivisions ? divisions : _defaultDivisions[type]; + entry->plane = planeObj; + + 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; + } + } - // Adjust according to current scroll position - itemEntry->x -= it->planeOffsetX; - itemEntry->y -= it->planeOffsetY; - - uint16 useInsetRect = readSelectorValue(_segMan, itemEntry->object, SELECTOR(useInsetRect)); - if (useInsetRect) { - itemEntry->celRect.top = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inTop)); - itemEntry->celRect.left = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inLeft)); - itemEntry->celRect.bottom = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inBottom)); - itemEntry->celRect.right = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inRight)); - if (view && view->isSci2Hires()) { - view->adjustToUpscaledCoordinates(itemEntry->celRect.top, itemEntry->celRect.left); - view->adjustToUpscaledCoordinates(itemEntry->celRect.bottom, itemEntry->celRect.right); - } - itemEntry->celRect.translate(itemEntry->x, itemEntry->y); - // TODO: maybe we should clip the cels rect with this, i'm not sure - // the only currently known usage is game menu of gk1 - } else if (view) { - // Process global scaling, if needed. - // TODO: Seems like SCI32 always processes global scaling for scaled objects - // TODO: We can only process symmetrical scaling for now (i.e. same value for scaleX/scaleY) - if ((itemEntry->scaleSignal & kScaleSignalDoScaling32) && - !(itemEntry->scaleSignal & kScaleSignalDisableGlobalScaling32) && - (itemEntry->scaleX == itemEntry->scaleY) && - itemEntry->scaleX != 128) - applyGlobalScaling(itemEntry, it->planeRect, view->getHeight(itemEntry->loopNo, itemEntry->celNo)); - - if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128)) - view->getCelRect(itemEntry->loopNo, itemEntry->celNo, - itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->celRect); - else - view->getCelScaledRect(itemEntry->loopNo, itemEntry->celNo, - itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->scaleX, - itemEntry->scaleY, itemEntry->celRect); - - Common::Rect nsRect = itemEntry->celRect; - // Translate back to actual coordinate within scrollable plane - nsRect.translate(it->planeOffsetX, it->planeOffsetY); - - if (g_sci->getGameId() == GID_PHANTASMAGORIA2) { - // HACK: Some (?) objects in Phantasmagoria 2 have no NS rect. Skip them for now. - // TODO: Remove once we figure out how Phantasmagoria 2 draws objects on screen. - if (lookupSelector(_segMan, itemEntry->object, SELECTOR(nsLeft), NULL, NULL) != kSelectorVariable) - continue; - } + // NOTE: The original engine had no nullptr check and would just crash + // if it got to here + if (entry == nullptr) { + error("Cannot edit non-existing ShowStyle entry"); + } - if (view && view->isSci2Hires()) { - view->adjustBackUpscaledCoordinates(nsRect.top, nsRect.left); - view->adjustBackUpscaledCoordinates(nsRect.bottom, nsRect.right); - g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect); - } else if (getSciVersion() >= SCI_VERSION_2_1_EARLY && _isHiRes) { - _coordAdjuster->fromDisplayToScript(nsRect.top, nsRect.left); - _coordAdjuster->fromDisplayToScript(nsRect.bottom, nsRect.right); - g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect); - } + entry->fadeUp = isFadeUp; + entry->color = color; + entry->nextTick = g_sci->getTickCount(); + entry->type = type; + entry->animate = animate; + entry->delay = (seconds * 60 + entry->divisions - 1) / entry->divisions; - // TODO: For some reason, the top left nsRect coordinates get - // swapped in the GK1 inventory screen, investigate why. - // This is also needed for GK1 rooms 710 and 720 (catacombs, inner and - // outer circle), for handling the tiles and talking to Wolfgang. - // HACK: Fix the coordinates by explicitly setting them here for GK1. - // Also check bug #6729, for another case where this is needed. - if (g_sci->getGameId() == GID_GK1) - g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect); - } + if (entry->delay == 0) { + if (entry->fadeColorRanges != nullptr) { + delete[] entry->fadeColorRanges; + } + delete entry; + error("ShowStyle has no duration"); + } - // Don't attempt to draw sprites that are outside the visible - // screen area. An example is the random people walking in - // Jackson Square in GK1. - if (itemEntry->celRect.bottom < 0 || itemEntry->celRect.top >= _screen->getDisplayHeight() || - itemEntry->celRect.right < 0 || itemEntry->celRect.left >= _screen->getDisplayWidth()) - continue; - - Common::Rect clipRect, translatedClipRect; - clipRect = itemEntry->celRect; - - if (view && view->isSci2Hires()) { - clipRect.clip(it->upscaledPlaneClipRect); - translatedClipRect = clipRect; - translatedClipRect.translate(it->upscaledPlaneRect.left, it->upscaledPlaneRect.top); - } else { - // QFG4 passes invalid rectangles when a battle is starting - if (!clipRect.isValidRect()) - continue; - clipRect.clip(it->planeClipRect); - translatedClipRect = clipRect; - translatedClipRect.translate(it->planeRect.left, it->planeRect.top); - } + if (frameOutNow) { + Common::Rect frameOutRect(0, 0); + frameOut(false, frameOutRect); + } + + if (createNewEntry) { + // TODO: Implement SCI2.1early and SCI3 + entry->next = _showStyles; + _showStyles = entry; + } + } +} - if (view) { - if (!clipRect.isEmpty()) { - if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128)) - view->draw(itemEntry->celRect, clipRect, translatedClipRect, - itemEntry->loopNo, itemEntry->celNo, 255, 0, view->isSci2Hires()); - else - view->drawScaled(itemEntry->celRect, clipRect, translatedClipRect, - itemEntry->loopNo, itemEntry->celNo, 255, itemEntry->scaleX, itemEntry->scaleY); +// 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 +// SCI3 implements 0, 1/3/5/7/9, 2/4/6/8/10, 11, 12/15, 13, 14 +// TODO: Sierra code needs to be replaced with code that uses the +// computed entry->delay property instead of just counting divisors, +// as the latter is machine-speed-dependent and leads to wrong +// transition speeds +void GfxFrameout::processShowStyles() { + uint32 now = g_sci->getTickCount(); + + bool continueProcessing; + + // TODO: Change to bool? Engine uses inc to set the value to true, + // but there does not seem to be any reason to actually count how + // many times it was set + int doFrameOut; + do { + continueProcessing = false; + doFrameOut = 0; + ShowStyleEntry *showStyle = _showStyles; + while (showStyle != nullptr) { + bool retval = false; + + if (!showStyle->animate) { + ++doFrameOut; + } + + if (showStyle->nextTick < now || !showStyle->animate) { + // TODO: Different versions of SCI use different processors! + // This is the SQ6/KQ7/SCI2.1mid table. + switch (showStyle->type) { + case kShowStyleNone: { + retval = processShowStyleNone(showStyle); + break; + } + case kShowStyleHShutterOut: + case kShowStyleVShutterOut: + case kShowStyleWipeLeft: + case kShowStyleWipeUp: + case kShowStyleIrisOut: + case kShowStyleHShutterIn: + case kShowStyleVShutterIn: + case kShowStyleWipeRight: + case kShowStyleWipeDown: + case kShowStyleIrisIn: + case kShowStyle11: + case kShowStyle12: + case kShowStyleUnknown: { + retval = processShowStyleMorph(showStyle); + break; + } + case kShowStyleFadeOut: { + retval = processShowStyleFade(-1, showStyle); + break; + } + case kShowStyleFadeIn: { + retval = processShowStyleFade(1, showStyle); + break; } } + } - // Draw text, if it exists - if (lookupSelector(_segMan, itemEntry->object, SELECTOR(text), NULL, NULL) == kSelectorVariable) { - g_sci->_gfxText32->drawTextBitmap(itemEntry->x, itemEntry->y, it->planeRect, itemEntry->object); - } + if (!retval) { + continueProcessing = true; } - } - for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) { - if (pictureIt->object == planeObject) { - delete[] pictureIt->pictureCels; - pictureIt->pictureCels = 0; + if (retval && showStyle->processed) { + showStyle = deleteShowStyleInternal(showStyle); + } else { + showStyle = showStyle->next; } } - } - showCurrentScrollText(); + if (doFrameOut) { + frameOut(true); + + // TODO: Transitions without the “animate†flag are too + // fast, but the throttle value is arbitrary. Someone on + // real hardware probably needs to test what the actual + // speed of these transitions should be + EngineState *state = g_sci->getEngineState(); + state->speedThrottler(33); + state->_throttleTrigger = true; + } + } while(continueProcessing && doFrameOut); +} - _screen->copyToScreen(); +bool GfxFrameout::processShowStyleNone(ShowStyleEntry *const showStyle) { + if (showStyle->fadeUp) { + _palette->setFade(100, 0, 255); + } else { + _palette->setFade(0, 0, 255); + } - g_sci->getEngineState()->_throttleTrigger = true; + showStyle->processed = true; + return true; } -void GfxFrameout::printPlaneList(Console *con) { - for (PlaneList::const_iterator it = _planes.begin(); it != _planes.end(); ++it) { - PlaneEntry p = *it; - Common::String curPlaneName = _segMan->getObjectName(p.object); - Common::Rect r = p.upscaledPlaneRect; - Common::Rect cr = p.upscaledPlaneClipRect; - - con->debugPrintf("%04x:%04x (%s): prio %d, lastprio %d, offsetX %d, offsetY %d, pic %d, mirror %d, back %d\n", - PRINT_REG(p.object), curPlaneName.c_str(), - (int16)p.priority, (int16)p.lastPriority, - p.planeOffsetX, p.planeOffsetY, p.pictureId, - p.planePictureMirrored, p.planeBack); - con->debugPrintf(" rect: (%d, %d, %d, %d), clip rect: (%d, %d, %d, %d)\n", - r.left, r.top, r.right, r.bottom, - cr.left, cr.top, cr.right, cr.bottom); - - if (p.pictureId != 0xffff && p.pictureId != 0xfffe) { - con->debugPrintf("Pictures:\n"); - - for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) { - if (pictureIt->object == p.object) { - con->debugPrintf(" Picture %d: x %d, y %d\n", pictureIt->pictureId, pictureIt->startX, pictureIt->startY); - } +bool GfxFrameout::processShowStyleMorph(ShowStyleEntry *const showStyle) { + palMorphFrameOut(_styleRanges, showStyle); + showStyle->processed = true; + return true; +} + +// TODO: Normalise use of 'entry' vs 'showStyle' +bool GfxFrameout::processShowStyleFade(const int direction, ShowStyleEntry *const showStyle) { + bool unchanged = true; + if (showStyle->currentStep < showStyle->divisions) { + int percent; + if (direction <= 0) { + percent = showStyle->divisions - showStyle->currentStep - 1; + } else { + percent = showStyle->currentStep; + } + + percent *= 100; + percent /= showStyle->divisions - 1; + + if (showStyle->fadeColorRangesCount > 0) { + for (int i = 0, len = showStyle->fadeColorRangesCount; i < len; i += 2) { + _palette->setFade(percent, showStyle->fadeColorRanges[i], showStyle->fadeColorRanges[i + 1]); } + } else { + _palette->setFade(percent, 0, 255); } + + ++showStyle->currentStep; + showStyle->nextTick += showStyle->delay; + unchanged = false; + } + + if (showStyle->currentStep >= showStyle->divisions && unchanged) { + if (direction > 0) { + showStyle->processed = true; + } + + return true; + } + + return false; +} + +void GfxFrameout::kernelFrameOut(const bool shouldShowBits) { + if (_showStyles != nullptr) { + processShowStyles(); + } else if (_palMorphIsOn) { + palMorphFrameOut(_styleRanges, nullptr); + _palMorphIsOn = false; + } else { +// TODO: Window scroll +// if (g_PlaneScroll) { +// processScrolls(); +// } + + frameOut(shouldShowBits); + } +} + +#pragma mark - +#pragma mark Mouse cursor + +reg_t GfxFrameout::kernelIsOnMe(const reg_t object, const Common::Point &position, bool checkPixel) const { + const reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane)); + Plane *plane = _visiblePlanes.findByObject(planeObject); + if (plane == nullptr) { + return make_reg(0, 0); + } + + ScreenItem *screenItem = plane->_screenItemList.findByObject(object); + if (screenItem == nullptr) { + 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)); } -void GfxFrameout::printPlaneItemList(Console *con, reg_t planeObject) { - for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { - FrameoutEntry *e = *listIterator; - reg_t itemPlane = readSelector(_segMan, e->object, SELECTOR(plane)); +bool GfxFrameout::isOnMe(const ScreenItem &screenItem, const Plane &plane, const Common::Point &position, const bool checkPixel) const { + + Common::Point scaledPosition(position); + mulru(scaledPosition, Ratio(_currentBuffer.screenWidth, _currentBuffer.scriptWidth), Ratio(_currentBuffer.screenHeight, _currentBuffer.scriptHeight)); + scaledPosition.x += plane._planeRect.left; + scaledPosition.y += plane._planeRect.top; + + if (!screenItem._screenRect.contains(scaledPosition)) { + return false; + } + + if (checkPixel) { + CelObj &celObj = screenItem.getCelObj(); + + bool mirrorX = screenItem._mirrorX ^ celObj._mirrorX; + + scaledPosition.x -= screenItem._scaledPosition.x; + scaledPosition.y -= screenItem._scaledPosition.y; - if (planeObject == itemPlane) { - Common::String curItemName = _segMan->getObjectName(e->object); - Common::Rect icr = e->celRect; - GuiResourceId picId = e->picture ? e->picture->getResourceId() : 0; + mulru(scaledPosition, Ratio(celObj._scaledWidth, _currentBuffer.screenWidth), Ratio(celObj._scaledHeight, _currentBuffer.screenHeight)); - con->debugPrintf("%d: %04x:%04x (%s), view %d, loop %d, cel %d, x %d, y %d, z %d, " - "signal %d, scale signal %d, scaleX %d, scaleY %d, rect (%d, %d, %d, %d), " - "pic %d, picX %d, picY %d, visible %d\n", - e->givenOrderNr, PRINT_REG(e->object), curItemName.c_str(), - e->viewId, e->loopNo, e->celNo, e->x, e->y, e->z, - e->signal, e->scaleSignal, e->scaleX, e->scaleY, - icr.left, icr.top, icr.right, icr.bottom, - picId, e->picStartX, e->picStartY, e->visible); + if (screenItem._scale.signal != kScaleSignalNone && screenItem._scale.x && screenItem._scale.y) { + scaledPosition.x = scaledPosition.x * 128 / screenItem._scale.x; + scaledPosition.y = scaledPosition.y * 128 / screenItem._scale.y; } + + uint8 pixel = celObj.readPixel(scaledPosition.x, scaledPosition.y, mirrorX); + return pixel != celObj._transparentColor; } + + return true; +} + +void GfxFrameout::kernelSetNowSeen(const reg_t screenItemObject) const { + const reg_t planeObject = readSelector(_segMan, screenItemObject, SELECTOR(plane)); + + Plane *plane = _planes.findByObject(planeObject); + if (plane == nullptr) { + error("kSetNowSeen: Plane %04x:%04x not found for screen item %04x:%04x", PRINT_REG(planeObject), PRINT_REG(screenItemObject)); + } + + ScreenItem *screenItem = plane->_screenItemList.findByObject(screenItemObject); + if (screenItem == nullptr) { + error("kSetNowSeen: Screen item %04x:%04x not found in plane %04x:%04x", PRINT_REG(screenItemObject), PRINT_REG(planeObject)); + } + + Common::Rect result = screenItem->getNowSeenRect(*plane); + writeSelectorValue(_segMan, screenItemObject, SELECTOR(nsLeft), result.left); + writeSelectorValue(_segMan, screenItemObject, SELECTOR(nsTop), result.top); + writeSelectorValue(_segMan, screenItemObject, SELECTOR(nsRight), result.right - 1); + 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 + +void GfxFrameout::printPlaneListInternal(Console *con, const PlaneList &planeList) const { + for (PlaneList::const_iterator it = planeList.begin(); it != planeList.end(); ++it) { + Plane *p = *it; + p->printDebugInfo(con); + } +} + +void GfxFrameout::printPlaneList(Console *con) const { + printPlaneListInternal(con, _planes); +} + +void GfxFrameout::printVisiblePlaneList(Console *con) const { + printPlaneListInternal(con, _visiblePlanes); +} + +void GfxFrameout::printPlaneItemListInternal(Console *con, const ScreenItemList &screenItemList) const { + ScreenItemList::size_type i = 0; + for (ScreenItemList::const_iterator sit = screenItemList.begin(); sit != screenItemList.end(); sit++) { + ScreenItem *screenItem = *sit; + con->debugPrintf("%2d: ", i++); + screenItem->printDebugInfo(con); + } +} + +void GfxFrameout::printPlaneItemList(Console *con, const reg_t planeObject) const { + Plane *p = _planes.findByObject(planeObject); + + if (p == nullptr) { + con->debugPrintf("Plane does not exist"); + return; + } + + printPlaneItemListInternal(con, p->_screenItemList); +} + +void GfxFrameout::printVisiblePlaneItemList(Console *con, const reg_t planeObject) const { + Plane *p = _visiblePlanes.findByObject(planeObject); + + if (p == nullptr) { + con->debugPrintf("Plane does not exist"); + return; + } + + printPlaneItemListInternal(con, p->_screenItemList); } } // End of namespace Sci diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h index d1a706e8de..8ed95a00de 100644 --- a/engines/sci/graphics/frameout.h +++ b/engines/sci/graphics/frameout.h @@ -23,86 +23,132 @@ #ifndef SCI_GRAPHICS_FRAMEOUT_H #define SCI_GRAPHICS_FRAMEOUT_H -namespace Sci { +#include "sci/graphics/plane32.h" +#include "sci/graphics/screen_item32.h" -class GfxPicture; +namespace Sci { +// TODO: Don't do this this way +int splitRects(Common::Rect r, const Common::Rect &other, Common::Rect(&outRects)[4]); -struct PlaneLineEntry { - reg_t hunkId; - Common::Point startPoint; - Common::Point endPoint; - byte color; - byte priority; - byte control; +// TODO: Verify display styles and adjust names appropriately for +// types 1 through 12 & 15 (others are correct) +// Names should be: +// * VShutterIn, VShutterOut +// * HShutterIn, HShutterOut +// * WipeLeft, WipeRight, WipeDown, WipeUp +// * PixelDissolve +// * ShutDown and Kill? (and Plain and Fade?) +enum ShowStyleType /* : uint8 */ { + kShowStyleNone = 0, + kShowStyleHShutterOut = 1, + kShowStyleHShutterIn = 2, + kShowStyleVShutterOut = 3, + kShowStyleVShutterIn = 4, + kShowStyleWipeLeft = 5, + kShowStyleWipeRight = 6, + kShowStyleWipeUp = 7, + kShowStyleWipeDown = 8, + kShowStyleIrisOut = 9, + kShowStyleIrisIn = 10, + kShowStyle11 = 11, + kShowStyle12 = 12, + kShowStyleFadeOut = 13, + kShowStyleFadeIn = 14, + // TODO: Only in SCI3 + kShowStyleUnknown = 15 }; -typedef Common::List<PlaneLineEntry> PlaneLineList; - -struct PlaneEntry { - reg_t object; - int16 priority; - int16 lastPriority; - int16 planeOffsetX; - int16 planeOffsetY; - GuiResourceId pictureId; - Common::Rect planeRect; - Common::Rect planeClipRect; - Common::Rect upscaledPlaneRect; - Common::Rect upscaledPlaneClipRect; - bool planePictureMirrored; - byte planeBack; - PlaneLineList lines; -}; +/** + * Show styles represent transitions applied to draw planes. + * One show style per plane can be active at a time. + */ +struct ShowStyleEntry { + /** + * The ID of the plane this show style belongs to. + * In SCI2.1mid (at least SQ6), per-plane transitions + * were removed and a single plane ID is used. + */ + reg_t plane; -typedef Common::List<PlaneEntry> PlaneList; - -struct FrameoutEntry { - uint16 givenOrderNr; - reg_t object; - GuiResourceId viewId; - int16 loopNo; - int16 celNo; - int16 x, y, z; - int16 priority; - uint16 signal; - uint16 scaleSignal; - int16 scaleX; - int16 scaleY; - Common::Rect celRect; - GfxPicture *picture; - int16 picStartX; - int16 picStartY; - bool visible; -}; + /** + * The type of the transition. + */ + ShowStyleType type; -typedef Common::List<FrameoutEntry *> FrameoutList; + // TODO: This name is probably incorrect + bool fadeUp; -struct PlanePictureEntry { - reg_t object; - int16 startX; - int16 startY; - GuiResourceId pictureId; - GfxPicture *picture; - FrameoutEntry *pictureCels; // temporary -}; + /** + * The number of steps for the show style. + */ + int16 divisions; -typedef Common::List<PlanePictureEntry> PlanePictureList; + // NOTE: This property exists from SCI2 through at least + // SCI2.1mid but is never used in the actual processing + // of the styles? + int unknownC; -struct ScrollTextEntry { - reg_t bitmapHandle; - reg_t kWindow; - uint16 x; - uint16 y; -}; + /** + * The color used by transitions that draw CelObjColor + * screen items. -1 for transitions that do not draw + * screen items. + */ + int16 color; + + // TODO: Probably uint32 + // TODO: This field probably should be used in order to + // provide time-accurate processing of show styles. In the + // actual SCI engine (at least 2–2.1mid) it appears that + // style transitions are drawn “as fast as possibleâ€, one + // step per loop, even though this delay field exists + int delay; + + // TODO: Probably bool, but never seems to be true? + int animate; -typedef Common::Array<ScrollTextEntry> ScrollTextList; + /** + * The wall time at which the next step of the animation + * should execute. + */ + uint32 nextTick; -enum ViewScaleSignals32 { - kScaleSignalDoScaling32 = 0x0001, // enables scaling when drawing that cel (involves scaleX and scaleY) - kScaleSignalUnk1 = 0x0002, // unknown - kScaleSignalDisableGlobalScaling32 = 0x0004 + /** + * During playback of the show style, the current step + * (out of divisions). + */ + int currentStep; + + /** + * The next show style. + */ + ShowStyleEntry *next; + + /** + * Whether or not this style has finished running and + * is ready for disposal. + */ + bool processed; + + // + // Engine specific properties for SCI2.1mid through SCI3 + // + + /** + * The number of entries in the fadeColorRanges array. + */ + uint8 fadeColorRangesCount; + + /** + * A pointer to an dynamically sized array of palette + * indexes, in the order [ fromColor, toColor, ... ]. + * Only colors within this range are transitioned. + */ + uint16 *fadeColorRanges; }; +typedef Common::Array<DrawList> ScreenItemListList; +typedef Common::Array<RectList> EraseListList; + class GfxCache; class GfxCoordAdjuster32; class GfxPaint32; @@ -114,69 +160,293 @@ class GfxScreen; * Roughly equivalent to GraphicsMgr in the actual SCI engine. */ class GfxFrameout { +private: + bool _isHiRes; + GfxCache *_cache; + GfxCoordAdjuster32 *_coordAdjuster; + GfxPalette32 *_palette; + ResourceManager *_resMan; + GfxScreen *_screen; + SegManager *_segMan; + GfxPaint32 *_paint32; + public: GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette32 *palette, GfxPaint32 *paint32); ~GfxFrameout(); - void kernelAddPlane(reg_t object); - void kernelUpdatePlane(reg_t object); - void kernelDeletePlane(reg_t object); - void applyGlobalScaling(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 celHeight); - void kernelAddScreenItem(reg_t object); - void kernelUpdateScreenItem(reg_t object); - void kernelDeleteScreenItem(reg_t object); - void deletePlaneItems(reg_t planeObject); - FrameoutEntry *findScreenItem(reg_t object); - int16 kernelGetHighPlanePri(); - void kernelAddPicAt(reg_t planeObj, GuiResourceId pictureId, int16 pictureX, int16 pictureY); - void kernelFrameout(); - - void addPlanePicture(reg_t object, GuiResourceId pictureId, uint16 startX, uint16 startY = 0); - void deletePlanePictures(reg_t object); - reg_t addPlaneLine(reg_t object, Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control); - void updatePlaneLine(reg_t object, reg_t hunkId, Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control); - void deletePlaneLine(reg_t object, reg_t hunkId); void clear(); + void syncWithScripts(bool addElements); // this is what Game::restore does, only needed when our ScummVM dialogs are patched in + void run(); - // Scroll text functions - void addScrollTextEntry(Common::String &text, reg_t kWindow, uint16 x, uint16 y, bool replace); - void showCurrentScrollText(); - void initScrollText(uint16 maxItems) { _maxScrollTexts = maxItems; } - void clearScrollTexts(); - void firstScrollText() { if (_scrollTexts.size() > 0) _curScrollText = 0; } - void lastScrollText() { if (_scrollTexts.size() > 0) _curScrollText = _scrollTexts.size() - 1; } - void prevScrollText() { if (_curScrollText > 0) _curScrollText--; } - void nextScrollText() { if (_curScrollText + 1 < (uint16)_scrollTexts.size()) _curScrollText++; } - void toggleScrollText(bool show) { _showScrollText = show; } +#pragma mark - +#pragma mark Screen items +private: + void deleteScreenItem(ScreenItem *screenItem, const reg_t plane); + void remapMarkRedraw(); - void printPlaneList(Console *con); - void printPlaneItemList(Console *con, reg_t planeObject); +public: + void kernelAddScreenItem(const reg_t object); + void kernelUpdateScreenItem(const reg_t object); + void kernelDeleteScreenItem(const reg_t object); + void kernelSetNowSeen(const reg_t screenItemObject) const; +#pragma mark - +#pragma mark Planes private: - bool _isHiRes; + /** + * The list of planes (i.e. layers) that have been added + * to the screen. + * + * @note This field is on `GraphicsMgr.screen` in SCI + * engine. + */ + PlaneList _planes; - void showVideo(); - void createPlaneItemList(reg_t planeObject, FrameoutList &itemList); - bool isPictureOutOfView(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 planeOffsetX, int16 planeOffsetY); - void drawPicture(FrameoutEntry *itemEntry, int16 planeOffsetX, int16 planeOffsetY, bool planePictureMirrored); + /** + * Updates an existing plane with properties from the + * given VM object. + */ + void updatePlane(Plane &plane); - SegManager *_segMan; - ResourceManager *_resMan; - GfxCoordAdjuster32 *_coordAdjuster; - GfxCache *_cache; - GfxPalette32 *_palette; - GfxScreen *_screen; - GfxPaint32 *_paint32; +public: + /** + * Creates and adds a new plane to the plane list, or + * cancels deletion and updates an already-existing + * plane if a plane matching the given plane VM object + * already exists within the current plane list. + * + * @note This method is on Screen in SCI engine, but it + * is only ever called on `GraphicsMgr.screen`. + */ + void addPlane(Plane &plane); - FrameoutList _screenItems; - PlaneList _planes; - PlanePictureList _planePictures; - ScrollTextList _scrollTexts; - int16 _curScrollText; - bool _showScrollText; - uint16 _maxScrollTexts; + /** + * Deletes a plane within the current plane list. + * + * @note This method is on Screen in SCI engine, but it + * is only ever called on `GraphicsMgr.screen`. + */ + void deletePlane(Plane &plane); - void sortPlanes(); + const PlaneList &getPlanes() const { + return _planes; + } + const PlaneList &getVisiblePlanes() const { + return _visiblePlanes; + } + void kernelAddPlane(const reg_t object); + void kernelUpdatePlane(const reg_t object); + void kernelDeletePlane(const reg_t object); + void kernelMovePlaneItems(const reg_t object, const int16 deltaX, const int16 deltaY, const bool scrollPics); + int16 kernelGetHighPlanePri(); + +#pragma mark - +#pragma mark Pics +public: + void kernelAddPicAt(const reg_t planeObject, const GuiResourceId pictureId, const int16 pictureX, const int16 pictureY, const bool mirrorX); + +#pragma mark - + + // TODO: Remap-related? + void kernelSetPalStyleRange(const uint8 fromColor, const uint8 toColor); + +#pragma mark - +#pragma mark Transitions +private: + int *_dissolveSequenceSeeds; + int16 *_defaultDivisions; + int16 *_defaultUnknownC; + + /** + * TODO: Documentation + */ + ShowStyleEntry *_showStyles; + + inline ShowStyleEntry *findShowStyleForPlane(const reg_t planeObj) const; + inline ShowStyleEntry *deleteShowStyleInternal(ShowStyleEntry *const showStyle); + void processShowStyles(); + bool processShowStyleNone(ShowStyleEntry *showStyle); + bool processShowStyleMorph(ShowStyleEntry *showStyle); + bool processShowStyleFade(const int direction, ShowStyleEntry *showStyle); + +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, reg_t pFadeArray, int16 divisions, const int16 blackScreen); + +#pragma mark - +#pragma mark Rendering +private: + /** + * TODO: Documentation + */ + int8 _styleRanges[256]; + + /** + * The internal display pixel buffer. During frameOut, + * this buffer is drawn into according to the draw and + * erase rects calculated by `calcLists`, then drawn out + * to the hardware surface according to the `_showList` + * rects (which are also calculated by `calcLists`). + */ + Buffer _currentBuffer; + + /** + * TODO: Documentation + */ + bool _remapOccurred; + + /** + * Whether or not the data in the current buffer is what + * is visible to the user. During rendering updates, + * this flag is set to false. + */ + bool _frameNowVisible; + + /** + * TODO: Document + * TODO: Depending upon if the engine ever modifies this + * rect, it may be stupid to store it separately instead + * of just getting width/height from GfxScreen. + * + * @note This field is on `GraphicsMgr.screen` in SCI + * engine. + */ + Common::Rect _screenRect; + + /** + * A list of rectangles, in display coordinates, that + * represent portions of the internal screen buffer that + * should be drawn to the hardware display surface. + * + * @note This field is on `GraphicsMgr.screen` in SCI + * engine. + */ + RectList _showList; + + /** + * The amount of extra overdraw that is acceptable when + * merging two show list rectangles together into a + * single larger rectangle. + * + * @note This field is on `GraphicsMgr.screen` in SCI + * engine. + */ + int _overdrawThreshold; + + /** + * A list of planes that are currently drawn to the + * hardware display surface. Used to calculate + * differences in plane properties between the last + * frame and current frame. + * + * @note This field is on `GraphicsMgr.visibleScreen` in + * SCI engine. + */ + PlaneList _visiblePlanes; + + /** + * Calculates the location and dimensions of dirty rects + * over the entire screen for rendering the next frame. + * The draw and erase lists in `drawLists` and + * `eraseLists` each represent one plane on the screen. + */ + void calcLists(ScreenItemListList &drawLists, EraseListList &eraseLists, const Common::Rect &calcRect); + + /** + * Erases the areas in the given erase list from the + * visible screen buffer by filling them with the color + * from the corresponding plane. This is an optimisation + * for colored-type planes only; other plane types have + * to be redrawn from pixel data. + */ + void drawEraseList(const RectList &eraseList, const Plane &plane); + + /** + * Draws all screen items from the given draw list to + * the visible screen buffer. + */ + void drawScreenItemList(const DrawList &screenItemList); + + /** + * Adds a new rectangle to the list of regions to write + * out to the hardware. The provided rect may be merged + * into an existing rectangle to reduce the number of + * blit operations. + */ + void mergeToShowList(const Common::Rect &drawRect, RectList &showList, const int overdrawThreshold); + + /** + * TODO: Documentation + */ + void palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry *showStyle); + + /** + * Writes the internal frame buffer out to hardware and + * clears the show list. + */ + void showBits(); + +public: + /** + * Whether palMorphFrameOut should be used instead of + * frameOut for rendering. Used by kMorphOn to + * explicitly enable palMorphFrameOut for one frame. + */ + bool _palMorphIsOn; + + inline Buffer &getCurrentBuffer() { + return _currentBuffer; + } + + void kernelFrameOut(const bool showBits); + + /** + * Updates the internal screen buffer for the next + * frame. If `shouldShowBits` is true, also sends the + * buffer to hardware. + */ + void frameOut(const bool shouldShowBits, const Common::Rect &rect = Common::Rect()); + + /** + * Modifies the raw pixel data for the next frame with + * new palette indexes based on matched style ranges. + */ + void alterVmap(const Palette &palette1, const Palette &palette2, const int8 style, const int8 *const styleRanges); + + // 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, + // SQ6/DOS, SQ6/Win, and Phant2/Win, this function simply returns 1. If + // you know of any game/environment where this function returns some + // value other than 1, or if you used to work at Sierra and can explain + // why this is a thing (and if anyone needs to care about it), please + // open a ticket!! + inline int getScreenCount() const { + return 1; + }; + +#pragma mark - +#pragma mark Mouse cursor +private: + /** + * Determines whether or not the point given by + * `position` is inside of the given screen item. + */ + bool isOnMe(const ScreenItem &screenItem, const Plane &plane, const Common::Point &position, const bool checkPixel) const; + +public: + reg_t kernelIsOnMe(const reg_t object, const Common::Point &position, const bool checkPixel) const; + +#pragma mark - +#pragma mark Debugging +public: + void printPlaneList(Console *con) const; + void printVisiblePlaneList(Console *con) const; + void printPlaneListInternal(Console *con, const PlaneList &planeList) const; + void printPlaneItemList(Console *con, const reg_t planeObject) const; + void printVisiblePlaneItemList(Console *con, const reg_t planeObject) const; + void printPlaneItemListInternal(Console *con, const ScreenItemList &screenItemList) const; }; } // End of namespace Sci diff --git a/engines/sci/graphics/helpers.h b/engines/sci/graphics/helpers.h index e5b9f2aaed..19dddd74b8 100644 --- a/engines/sci/graphics/helpers.h +++ b/engines/sci/graphics/helpers.h @@ -26,6 +26,11 @@ #include "common/endian.h" // for READ_LE_UINT16 #include "common/rect.h" #include "common/serializer.h" +#ifdef ENABLE_SCI32 +#include "common/rational.h" +#include "graphics/pixelformat.h" +#include "graphics/surface.h" +#endif #include "sci/engine/vm_types.h" namespace Sci { @@ -45,6 +50,9 @@ typedef int16 TextAlignment; #define PORTS_FIRSTWINDOWID 2 #define PORTS_FIRSTSCRIPTWINDOWID 3 +#ifdef ENABLE_SCI32 +#define PRINT_RECT(x) (x).left,(x).top,(x).right,(x).bottom +#endif struct Port { uint16 id; @@ -118,6 +126,102 @@ struct Window : public Port, public Common::Serializable { } }; +#ifdef ENABLE_SCI32 +/** + * Multiplies a rectangle by two ratios with default + * rounding. Modifies the rect directly. + */ +inline void mul(Common::Rect &rect, const Common::Rational &ratioX, const Common::Rational &ratioY) { + rect.left = (rect.left * ratioX).toInt(); + rect.top = (rect.top * ratioY).toInt(); + rect.right = (rect.right * ratioX).toInt(); + rect.bottom = (rect.bottom * ratioY).toInt(); +} + +/** + * Multiplies a rectangle by two ratios with default + * rounding. Modifies the rect directly. Uses inclusive + * rectangle rounding. + */ +inline void mulinc(Common::Rect &rect, const Common::Rational &ratioX, const Common::Rational &ratioY) { + rect.left = (rect.left * ratioX).toInt(); + rect.top = (rect.top * ratioY).toInt(); + rect.right = ((rect.right - 1) * ratioX).toInt() + 1; + rect.bottom = ((rect.bottom - 1) * ratioY).toInt() + 1; +} + +/** + * Multiplies a number by a rational number, rounding up to + * the nearest whole number. + */ +inline int mulru(const int value, const Common::Rational &ratio, const int extra = 0) { + int num = (value + extra) * ratio.getNumerator(); + int result = num / ratio.getDenominator(); + if (num > ratio.getDenominator() && num % ratio.getDenominator()) { + ++result; + } + return result - extra; +} + +/** + * Multiplies a point by two rational numbers for X and Y, + * rounding up to the nearest whole number. Modifies the + * point directly. + */ +inline void mulru(Common::Point &point, const Common::Rational &ratioX, const Common::Rational &ratioY) { + point.x = mulru(point.x, ratioX); + point.y = mulru(point.y, ratioY); +} + +/** + * Multiplies a point by two rational numbers for X and Y, + * rounding up to the nearest whole number. Modifies the + * rect directly. + */ +inline void mulru(Common::Rect &rect, const Common::Rational &ratioX, const Common::Rational &ratioY, const int extra) { + rect.left = mulru(rect.left, ratioX); + rect.top = mulru(rect.top, ratioY); + rect.right = mulru(rect.right - 1, ratioX, extra) + 1; + rect.bottom = mulru(rect.bottom - 1, ratioY, extra) + 1; +} + +struct Buffer : public Graphics::Surface { + uint16 screenWidth; + uint16 screenHeight; + uint16 scriptWidth; + uint16 scriptHeight; + + Buffer(const uint16 width, const uint16 height, uint8 *const pix) : + screenWidth(width), + screenHeight(height), + // TODO: These values are not correct for all games. Script + // dimensions were hard-coded per game in the original + // interpreter. Search all games for their internal script + // dimensions and set appropriately. (This code does not + // appear to exist at all in SCI3, which uses 640x480.) + scriptWidth(320), + scriptHeight(200) { + init(width, height, width, pix, Graphics::PixelFormat::createFormatCLUT8()); + } + + void clear(const uint8 value) { + memset(pixels, value, w * h); + } + + inline uint8 *getAddress(const uint16 x, const uint16 y) { + return (uint8 *)getBasePtr(x, y); + } + + inline uint8 *getAddressSimRes(const uint16 x, const uint16 y) { + return (uint8*)pixels + (y * w * screenHeight / scriptHeight) + (x * screenWidth / scriptWidth); + } + + bool isNull() { + return pixels == nullptr; + } +}; +#endif + struct Color { byte used; byte r, g, b; @@ -146,7 +250,7 @@ struct Palette { } } - return false; + return true; } inline bool operator!=(const Palette &other) const { return !(*this == other); diff --git a/engines/sci/graphics/lists32.h b/engines/sci/graphics/lists32.h new file mode 100644 index 0000000000..4f74c77325 --- /dev/null +++ b/engines/sci/graphics/lists32.h @@ -0,0 +1,192 @@ +/* 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 SCI_GRAPHICS_LISTS32_H +#define SCI_GRAPHICS_LISTS32_H + +#include "common/array.h" + +namespace Sci { + +/** + * StablePointerArray holds pointers in a fixed-size array + * that maintains position of erased items until `pack` is + * called. It is used by DrawList, RectList, and + * ScreenItemList. StablePointerArray takes ownership of + * all pointers that are passed to it and deletes them when + * calling `erase` or when destroying the + * StablePointerArray. + */ +template<class T, uint N> +class StablePointerArray { + uint _size; + T *_items[N]; + +public: + typedef T **iterator; + typedef T *const *const_iterator; + typedef T *value_type; + typedef uint size_type; + + StablePointerArray() : _size(0), _items() {} + StablePointerArray(const StablePointerArray &other) : _size(other._size) { + for (size_type i = 0; i < _size; ++i) { + if (other._items[i] == nullptr) { + _items[i] = nullptr; + } else { + _items[i] = new T(*other._items[i]); + } + } + } + ~StablePointerArray() { + for (size_type i = 0; i < _size; ++i) { + delete _items[i]; + } + } + + void operator=(const StablePointerArray &other) { + clear(); + _size = other._size; + for (size_type i = 0; i < _size; ++i) { + if (other._items[i] == nullptr) { + _items[i] = nullptr; + } else { + _items[i] = new T(*other._items[i]); + } + } + } + + T *const &operator[](size_type index) const { + assert(index < _size); + return _items[index]; + } + + T *&operator[](size_type index) { + assert(index < _size); + return _items[index]; + } + + /** + * Adds a new pointer to the array. + */ + void add(T *item) { + assert(_size < N); + _items[_size++] = item; + } + + iterator begin() { + return _items; + } + + const_iterator begin() const { + return _items; + } + + void clear() { + for (size_type i = 0; i < _size; ++i) { + delete _items[i]; + _items[i] = nullptr; + } + + _size = 0; + } + + iterator end() { + return _items + _size; + } + + const_iterator end() const { + return _items + _size; + } + + /** + * Erases the object pointed to by the given iterator. + */ + void erase(T *item) { + for (iterator it = begin(); it != end(); ++it) { + if (*it == item) { + delete *it; + *it = nullptr; + break; + } + } + } + + /** + * Erases the object pointed to by the given iterator. + */ + void erase(iterator &it) { + assert(it >= _items && it < _items + _size); + delete *it; + *it = nullptr; + } + + /** + * Erases the object pointed to at the given index. + */ + void erase_at(size_type index) { + assert(index < _size); + + delete _items[index]; + _items[index] = nullptr; + } + + /** + * Removes freed pointers from the pointer list. + */ + size_type pack() { + iterator freePtr = begin(); + size_type newSize = 0; + + for (iterator it = begin(), last = end(); it != last; ++it) { + if (*it != nullptr) { + *freePtr = *it; + ++freePtr; + ++newSize; + } + } + + _size = newSize; + return newSize; + } + + /** + * The number of populated slots in the array. The size + * of the array will only go down once `pack` is called. + */ + size_type size() const { + return _size; + } +}; + +template<typename T> +class FindByObject { + const reg_t &_object; +public: + FindByObject(const reg_t &object) : _object(object) {} + bool operator()(const T entry) const { + return entry && entry->_object == _object; + } +}; + +} // End of namespace Sci +#endif diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp index 106924ecd3..1514ad838f 100644 --- a/engines/sci/graphics/palette.cpp +++ b/engines/sci/graphics/palette.cpp @@ -32,6 +32,7 @@ #include "sci/graphics/cache.h" #include "sci/graphics/maciconbar.h" #include "sci/graphics/palette.h" +#include "sci/graphics/remap.h" #include "sci/graphics/screen.h" #include "sci/graphics/view.h" @@ -103,9 +104,6 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen) default: error("GfxPalette: Unknown view type"); } - - _remapOn = false; - resetRemapping(); } GfxPalette::~GfxPalette() { @@ -310,7 +308,7 @@ void GfxPalette::set(Palette *newPalette, bool force, bool forceRealMerge) { uint32 systime = _sysPalette.timestamp; if (force || newPalette->timestamp != systime) { - // SCI1.1+ doesnt do real merging anymore, but simply copying over the used colors from other palettes + // SCI1.1+ doesn't do real merging anymore, but simply copying over the used colors from other palettes // There are some games with inbetween SCI1.1 interpreters, use real merging for them (e.g. laura bow 2 demo) if ((forceRealMerge) || (_useMerging)) _sysPaletteChanged |= merge(newPalette, force, forceRealMerge); @@ -336,79 +334,6 @@ void GfxPalette::set(Palette *newPalette, bool force, bool forceRealMerge) { } } -byte GfxPalette::remapColor(byte remappedColor, byte screenColor) { - assert(_remapOn); - if (_remappingType[remappedColor] == kRemappingByRange) - return _remappingByRange[screenColor]; - else if (_remappingType[remappedColor] == kRemappingByPercent) - return _remappingByPercent[screenColor]; - else - error("remapColor(): Color %d isn't remapped", remappedColor); - - return 0; // should never reach here -} - -void GfxPalette::resetRemapping() { - _remapOn = false; - _remappingPercentToSet = 0; - - for (int i = 0; i < 256; i++) { - _remappingType[i] = kRemappingNone; - _remappingByPercent[i] = i; - _remappingByRange[i] = i; - } -} - -void GfxPalette::setRemappingPercent(byte color, byte percent) { - _remapOn = true; - - // 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; - - for (int i = 0; i < 256; i++) { - byte r = _sysPalette.colors[i].r * _remappingPercentToSet / 100; - byte g = _sysPalette.colors[i].g * _remappingPercentToSet / 100; - byte b = _sysPalette.colors[i].b * _remappingPercentToSet / 100; - _remappingByPercent[i] = kernelFindColor(r, g, b); - } - - _remappingType[color] = kRemappingByPercent; -} - -void GfxPalette::setRemappingPercentGray(byte color, byte percent) { - _remapOn = true; - - // 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; - - // 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); - } - - _remappingType[color] = kRemappingByPercent; -} - -void GfxPalette::setRemappingRange(byte color, byte from, byte to, byte base) { - _remapOn = true; - - for (int i = from; i <= to; i++) { - _remappingByRange[i] = i + base; - } - - _remappingType[color] = kRemappingByRange; -} - bool GfxPalette::insert(Palette *newPalette, Palette *destPalette) { bool paletteChanged = false; @@ -589,15 +514,8 @@ void GfxPalette::copySysPaletteToScreen() { } } - // Check if we need to reset remapping by percent with the new colors. - if (_remappingPercentToSet) { - for (int i = 0; i < 256; i++) { - byte r = _sysPalette.colors[i].r * _remappingPercentToSet / 100; - byte g = _sysPalette.colors[i].g * _remappingPercentToSet / 100; - byte b = _sysPalette.colors[i].b * _remappingPercentToSet / 100; - _remappingByPercent[i] = kernelFindColor(r, g, b); - } - } + if (g_sci->_gfxRemap16) + g_sci->_gfxRemap16->updateRemapping(); g_system->getPaletteManager()->setPalette(bpal, 0, 256); } diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h index 61a8d36cb9..7335dc59d0 100644 --- a/engines/sci/graphics/palette.h +++ b/engines/sci/graphics/palette.h @@ -35,12 +35,6 @@ class GfxScreen; #define SCI_PALETTE_MATCH_PERFECT 0x8000 #define SCI_PALETTE_MATCH_COLORMASK 0xFF -enum ColorRemappingType { - kRemappingNone = 0, - kRemappingByRange = 1, - kRemappingByPercent = 2 -}; - /** * Palette class, handles palette operations like changing intensity, setting up the palette, merging different palettes */ @@ -64,15 +58,6 @@ public: void getSys(Palette *pal); uint16 getTotalColorCount() const { return _totalScreenColors; } - void resetRemapping(); - void setRemappingPercent(byte color, byte percent); - void setRemappingPercentGray(byte color, byte percent); - void setRemappingRange(byte color, byte from, byte to, byte base); - bool isRemapped(byte color) const { - return _remapOn && (_remappingType[color] != kRemappingNone); - } - byte remapColor(byte remappedColor, byte screenColor); - void setOnScreen(); void copySysPaletteToScreen(); @@ -138,12 +123,6 @@ protected: int _palVarySignal; uint16 _totalScreenColors; - bool _remapOn; - ColorRemappingType _remappingType[256]; - byte _remappingByPercent[256]; - byte _remappingByRange[256]; - uint16 _remappingPercentToSet; - void loadMacIconBarPalette(); byte *_macClut; }; diff --git a/engines/sci/graphics/palette32.cpp b/engines/sci/graphics/palette32.cpp index e330b5620b..6844011675 100644 --- a/engines/sci/graphics/palette32.cpp +++ b/engines/sci/graphics/palette32.cpp @@ -28,29 +28,41 @@ #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 { - + GfxPalette32::GfxPalette32(ResourceManager *resMan, GfxScreen *screen) : GfxPalette(resMan, screen), + // Palette versioning + _version(1), + _versionUpdated(false), + _sourcePalette(_sysPalette), + _nextPalette(_sysPalette), + // Clut _clutTable(nullptr), - // Palette cycling - _cyclers(), _cycleMap(), // Palette varying - _sourcePalette(_sysPalette), _nextPalette(_sysPalette), - _varyTime(0), _varyDirection(0), _varyTargetPercent(0), - _varyTargetPalette(nullptr), _varyStartPalette(nullptr), - _varyFromColor(0), _varyToColor(255), _varyNumTimesPaused(0), - _varyPercent(_varyTargetPercent), _varyLastTick(0), - // Palette versioning - _version(1), _versionUpdated(false) { - memset(_fadeTable, 100, sizeof(_fadeTable)); - + _varyStartPalette(nullptr), + _varyTargetPalette(nullptr), + _varyFromColor(0), + _varyToColor(255), + _varyLastTick(0), + _varyTime(0), + _varyDirection(0), + _varyTargetPercent(0), + _varyNumTimesPaused(0), + // Palette cycling + _cyclers(), + _cycleMap() { + _varyPercent = _varyTargetPercent; + for (int i = 0, len = ARRAYSIZE(_fadeTable); i < len; ++i) { + _fadeTable[i] = 100; + } // NOTE: In SCI engine, the palette manager constructor loads // the default palette, but in ScummVM this initialisation // is performed by SciEngine::run; see r49523 for details - } +} GfxPalette32::~GfxPalette32() { unloadClut(); @@ -59,13 +71,17 @@ GfxPalette32::~GfxPalette32() { } inline void mergePaletteInternal(Palette *const to, const Palette *const from) { - for (int i = 0; i < ARRAYSIZE(to->colors); ++i) { + for (int i = 0, len = ARRAYSIZE(to->colors); i < len; ++i) { if (from->colors[i].used) { to->colors[i] = from->colors[i]; } } } +const Palette *GfxPalette32::getNextPalette() const { + return &_nextPalette; +} + void GfxPalette32::submit(Palette &palette) { // TODO: The resource manager in SCI32 retains raw data of palettes from // the ResourceManager (ResourceMgr) through SegManager (MemoryMgr), and @@ -205,17 +221,22 @@ int16 GfxPalette32::matchColor(const byte r, const byte g, const byte b, const i return bestIndex; } -void GfxPalette32::updateForFrame() { +bool GfxPalette32::updateForFrame() { applyAll(); _versionUpdated = false; - // TODO: Implement remapping - // g_sci->_gfxFrameout->remapAllTables(_nextPalette != _sysPalette); + return g_sci->_gfxRemap32->remapAllTables(_nextPalette != _sysPalette); +} + +void GfxPalette32::updateFFrame() { + for (int i = 0; i < ARRAYSIZE(_nextPalette.colors); ++i) { + _nextPalette.colors[i] = _sourcePalette.colors[i]; + } + _versionUpdated = false; + g_sci->_gfxRemap32->remapAllTables(_nextPalette != _sysPalette); } void GfxPalette32::updateHardware() { if (_sysPalette == _nextPalette) { - // TODO: This condition has never been encountered yet - debug("Skipping hardware update because palettes are identical"); return; } @@ -246,9 +267,8 @@ void GfxPalette32::applyAll() { applyFade(); } -// -// Clut -// +#pragma mark - +#pragma mark Colour look-up bool GfxPalette32::loadClut(uint16 clutId) { // loadClut() will load a color lookup table from a clu file and set @@ -300,9 +320,8 @@ void GfxPalette32::unloadClut() { _clutTable = nullptr; } -// -// Palette vary -// +#pragma mark - +#pragma mark Varying inline bool GfxPalette32::createPaletteFromResourceInternal(const GuiResourceId paletteId, Palette *const out) const { Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, paletteId), false); @@ -409,7 +428,7 @@ void GfxPalette32::setVaryPercent(const int16 percent, const int time, const int } int16 GfxPalette32::getVaryPercent() const { - return abs(_varyPercent); + return ABS(_varyPercent); } void GfxPalette32::varyOff() { @@ -542,9 +561,8 @@ void GfxPalette32::applyVary() { } } -// -// Palette cycling -// +#pragma mark - +#pragma mark Cycling inline void GfxPalette32::clearCycleMap(const uint16 fromColor, const uint16 numColorsToClear) { bool *mapEntry = _cycleMap + fromColor; @@ -677,14 +695,8 @@ void GfxPalette32::cycleAllOn() { } void GfxPalette32::cycleAllPause() { - // TODO: The SCI SQ6 cycleAllPause function does not seem to perform - // nullptr checking?? This would definitely cause null pointer - // dereference in SCI code. I have not seen anything actually call - // this function yet, so it is possible it is just unused and broken - // in SCI SQ6. This assert exists so that if this function is called, - // it is noticed and can be rechecked in the actual engine. - // Obviously this code *does* do nullptr checks instead of crashing. :) - assert(0); + // NOTE: The original engine did not check for null pointers in the + // palette cyclers pointer array. for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) { PalCycler *cycler = _cyclers[i]; if (cycler != nullptr) { @@ -768,11 +780,16 @@ void GfxPalette32::applyCycles() { } } -// -// Palette fading -// +#pragma mark - +#pragma mark Fading -void GfxPalette32::setFade(uint8 percent, uint8 fromColor, uint16 numColorsToFade) { +// NOTE: There are some game scripts (like SQ6 Sierra logo and main menu) that call +// setFade with numColorsToFade set to 256, but other parts of the engine like +// processShowStyleNone use 255 instead of 256. It is not clear if this is because +// the last palette entry is intentionally left unmodified, or if this is a bug +// in the engine. It certainly seems confused because all other places that accept +// color ranges typically receive values in the range of 0–255. +void GfxPalette32::setFade(uint16 percent, uint8 fromColor, uint16 numColorsToFade) { if (fromColor > numColorsToFade) { return; } @@ -794,9 +811,10 @@ void GfxPalette32::applyFade() { Color &color = _nextPalette.colors[i]; - color.r = (int16)color.r * _fadeTable[i] / 100; - color.g = (int16)color.g * _fadeTable[i] / 100; - color.b = (int16)color.b * _fadeTable[i] / 100; + color.r = MIN(255, (uint16)color.r * _fadeTable[i] / 100); + color.g = MIN(255, (uint16)color.g * _fadeTable[i] / 100); + color.b = MIN(255, (uint16)color.b * _fadeTable[i] / 100); } } -} + +} // End of namespace Sci diff --git a/engines/sci/graphics/palette32.h b/engines/sci/graphics/palette32.h index 8744687e4c..a5450776dc 100644 --- a/engines/sci/graphics/palette32.h +++ b/engines/sci/graphics/palette32.h @@ -25,6 +25,7 @@ #include "sci/graphics/palette.h" +namespace Sci { enum PalCyclerDirection { PalCycleBackward = 0, PalCycleForward = 1 @@ -71,188 +72,213 @@ struct PalCycler { uint16 numTimesPaused; }; -namespace Sci { - class GfxPalette32 : public GfxPalette { - public: - GfxPalette32(ResourceManager *resMan, GfxScreen *screen); - ~GfxPalette32(); - - protected: - /** - * The palette revision version. Increments once per game - * loop that changes the source palette. TODO: Possibly - * other areas also change _version, double-check once it - * is all implemented. - */ - uint32 _version; - - /** - * Whether or not the palette manager version was updated - * during this loop. - */ - bool _versionUpdated; - - /** - * The unmodified source palette loaded by kPalette. Additional - * palette entries may be mixed into the source palette by - * CelObj objects, which contain their own palettes. - */ - Palette _sourcePalette; - - /** - * The palette to be used when the hardware is next updated. - * On update, _nextPalette is transferred to _sysPalette. - */ - Palette _nextPalette; - - // SQ6 defines 10 cyclers - PalCycler *_cyclers[10]; - - /** - * The cycle map is used to detect overlapping cyclers. - * According to SCI engine code, when two cyclers overlap, - * a fatal error has occurred and the engine will display - * an error and then exit. - */ - bool _cycleMap[256]; - inline void clearCycleMap(uint16 fromColor, uint16 numColorsToClear); - inline void setCycleMap(uint16 fromColor, uint16 numColorsToClear); - inline PalCycler *getCycler(uint16 fromColor); - - /** - * The fade table records the expected intensity level of each pixel - * in the palette that will be displayed on the next frame. - */ - byte _fadeTable[256]; - - /** - * An optional lookup table used to remap RGB565 colors to a palette - * index. Used by Phantasmagoria 2 in 8-bit color environments. - */ - byte *_clutTable; - - /** - * An optional palette used to describe the source colors used - * in a palette vary operation. If this palette is not specified, - * sourcePalette is used instead. - */ - Palette *_varyStartPalette; - - /** - * An optional palette used to describe the target colors used - * in a palette vary operation. - */ - Palette *_varyTargetPalette; - - /** - * The minimum palette index that has been varied from the - * source palette. 0–255 - */ - uint8 _varyFromColor; - - /** - * The maximum palette index that is has been varied from the - * source palette. 0-255 - */ - uint8 _varyToColor; - - /** - * The tick at the last time the palette vary was updated. - */ - uint32 _varyLastTick; - - /** - * TODO: Document - * The velocity of change in percent? - */ - int _varyTime; - - /** - * TODO: Better documentation - * The direction of change, -1, 0, or 1. - */ - int16 _varyDirection; - - /** - * The amount, in percent, that the vary color is currently - * blended into the source color. - */ - int16 _varyPercent; - - /** - * The target amount that a vary color will be blended into - * the source color. - */ - int16 _varyTargetPercent; - - /** - * The number of time palette varying has been paused. - */ - uint16 _varyNumTimesPaused; - - /** - * Submits a palette to display. Entries marked as “used†in the - * submitted palette are merged into the existing entries of - * _sourcePalette. - */ - void submit(Palette &palette); - - public: - virtual void saveLoadWithSerializer(Common::Serializer &s) override; - - bool kernelSetFromResource(GuiResourceId resourceId, bool force) override; - int16 kernelFindColor(uint16 r, uint16 g, uint16 b) override; - void set(Palette *newPalette, bool force, bool forceRealMerge = false) override; - int16 matchColor(const byte matchRed, const byte matchGreen, const byte matchBlue, const int defaultDifference, int &lastCalculatedDifference, const bool *const matchTable); - - void updateForFrame(); - void updateHardware(); - void applyAll(); - - bool loadClut(uint16 clutId); - byte matchClutColor(uint16 color); - void unloadClut(); - - void kernelPalVarySet(const GuiResourceId paletteId, const int16 percent, const int time, const int16 fromColor, const int16 toColor); - void kernelPalVaryMergeTarget(const GuiResourceId paletteId); - void kernelPalVarySetTarget(const GuiResourceId paletteId); - void kernelPalVarySetStart(const GuiResourceId paletteId); - void kernelPalVaryMergeStart(const GuiResourceId paletteId); - virtual void kernelPalVaryPause(bool pause) override; - - void setVary(const Palette *const targetPalette, const int16 percent, const int time, const int16 fromColor, const int16 toColor); - void setVaryPercent(const int16 percent, const int time, const int16 fromColor, const int16 fromColorAlternate); - int16 getVaryPercent() const; - void varyOff(); - void mergeTarget(const Palette *const palette); - void varyPause(); - void varyOn(); - void setVaryTime(const int time); - void setTarget(const Palette *const palette); - void setStart(const Palette *const palette); - void mergeStart(const Palette *const palette); - private: - bool createPaletteFromResourceInternal(const GuiResourceId paletteId, Palette *const out) const; - Palette getPaletteFromResourceInternal(const GuiResourceId paletteId) const; - void setVaryTimeInternal(const int16 percent, const int time); - public: - void applyVary(); - - void setCycle(const uint8 fromColor, const uint8 toColor, const int16 direction, const int16 delay); - void doCycle(const uint8 fromColor, const int16 speed); - void cycleOn(const uint8 fromColor); - void cyclePause(const uint8 fromColor); - void cycleAllOn(); - void cycleAllPause(); - void cycleOff(const uint8 fromColor); - void cycleAllOff(); - void applyAllCycles(); - void applyCycles(); - - void setFade(const uint8 percent, const uint8 fromColor, const uint16 toColor); - void fadeOff(); - void applyFade(); - }; -} +class GfxPalette32 : public GfxPalette { +public: + GfxPalette32(ResourceManager *resMan, GfxScreen *screen); + ~GfxPalette32(); + +private: + // NOTE: currentPalette in SCI engine is called _sysPalette + // here. + + /** + * The palette revision version. Increments once per game + * loop that changes the source palette. TODO: Possibly + * other areas also change _version, double-check once it + * is all implemented. + */ + uint32 _version; + + /** + * Whether or not the palette manager version was updated + * during this loop. + */ + bool _versionUpdated; + + /** + * The unmodified source palette loaded by kPalette. Additional + * palette entries may be mixed into the source palette by + * CelObj objects, which contain their own palettes. + */ + Palette _sourcePalette; + + /** + * The palette to be used when the hardware is next updated. + * On update, _nextPalette is transferred to _sysPalette. + */ + Palette _nextPalette; + + bool createPaletteFromResourceInternal(const GuiResourceId paletteId, Palette *const out) const; + Palette getPaletteFromResourceInternal(const GuiResourceId paletteId) const; + +public: + virtual void saveLoadWithSerializer(Common::Serializer &s) override; + const Palette *getNextPalette() const; + + bool kernelSetFromResource(GuiResourceId resourceId, bool force) override; + int16 kernelFindColor(uint16 r, uint16 g, uint16 b) override; + void set(Palette *newPalette, bool force, bool forceRealMerge = false) override; + int16 matchColor(const byte matchRed, const byte matchGreen, const byte matchBlue, const int defaultDifference, int &lastCalculatedDifference, const bool *const matchTable); + + /** + * Submits a palette to display. Entries marked as “used†in the + * submitted palette are merged into the existing entries of + * _sourcePalette. + */ + void submit(Palette &palette); + + bool updateForFrame(); + void updateFFrame(); + void updateHardware(); + void applyAll(); + +#pragma mark - +#pragma mark color look-up +private: + /** + * An optional lookup table used to remap RGB565 colors to a palette + * index. Used by Phantasmagoria 2 in 8-bit color environments. + */ + byte *_clutTable; + +public: + bool loadClut(uint16 clutId); + byte matchClutColor(uint16 color); + void unloadClut(); + +#pragma mark - +#pragma mark Varying +private: + /** + * An optional palette used to describe the source colors used + * in a palette vary operation. If this palette is not specified, + * sourcePalette is used instead. + */ + Palette *_varyStartPalette; + + /** + * An optional palette used to describe the target colors used + * in a palette vary operation. + */ + Palette *_varyTargetPalette; + + /** + * The minimum palette index that has been varied from the + * source palette. 0–255 + */ + uint8 _varyFromColor; + + /** + * The maximum palette index that is has been varied from the + * source palette. 0-255 + */ + uint8 _varyToColor; + + /** + * The tick at the last time the palette vary was updated. + */ + uint32 _varyLastTick; + + /** + * The amount of time to elapse, in ticks, between each cycle + * of a palette vary animation. + */ + int _varyTime; + + /** + * The direction of change: -1, 0, or 1. + */ + int16 _varyDirection; + + /** + * The amount, in percent, that the vary color is currently + * blended into the source color. + */ + int16 _varyPercent; + + /** + * The target amount that a vary color will be blended into + * the source color. + */ + int16 _varyTargetPercent; + + /** + * The number of time palette varying has been paused. + */ + uint16 _varyNumTimesPaused; + +public: + void kernelPalVarySet(const GuiResourceId paletteId, const int16 percent, const int time, const int16 fromColor, const int16 toColor); + void kernelPalVaryMergeTarget(const GuiResourceId paletteId); + void kernelPalVarySetTarget(const GuiResourceId paletteId); + void kernelPalVarySetStart(const GuiResourceId paletteId); + void kernelPalVaryMergeStart(const GuiResourceId paletteId); + virtual void kernelPalVaryPause(bool pause) override; + + void setVary(const Palette *const targetPalette, const int16 percent, const int time, const int16 fromColor, const int16 toColor); + void setVaryPercent(const int16 percent, const int time, const int16 fromColor, const int16 fromColorAlternate); + int16 getVaryPercent() const; + void varyOff(); + void mergeTarget(const Palette *const palette); + void varyPause(); + void varyOn(); + void setVaryTime(const int time); + void setTarget(const Palette *const palette); + void setStart(const Palette *const palette); + void mergeStart(const Palette *const palette); + void setVaryTimeInternal(const int16 percent, const int time); + void applyVary(); + +#pragma mark - +#pragma mark Cycling +private: + // SQ6 defines 10 cyclers + PalCycler *_cyclers[10]; + + /** + * The cycle map is used to detect overlapping cyclers. + * According to SCI engine code, when two cyclers overlap, + * a fatal error has occurred and the engine will display + * an error and then exit. + */ + bool _cycleMap[256]; + inline void clearCycleMap(uint16 fromColor, uint16 numColorsToClear); + inline void setCycleMap(uint16 fromColor, uint16 numColorsToClear); + inline PalCycler *getCycler(uint16 fromColor); + +public: + void setCycle(const uint8 fromColor, const uint8 toColor, const int16 direction, const int16 delay); + void doCycle(const uint8 fromColor, const int16 speed); + void cycleOn(const uint8 fromColor); + void cyclePause(const uint8 fromColor); + void cycleAllOn(); + void cycleAllPause(); + void cycleOff(const uint8 fromColor); + void cycleAllOff(); + void applyAllCycles(); + void applyCycles(); + const bool *getCyclemap() { return _cycleMap; } + +#pragma mark - +#pragma mark Fading +private: + /** + * The fade table records the expected intensity level of each pixel + * in the palette that will be displayed on the next frame. + */ + uint16 _fadeTable[256]; + +public: + /** + * Sets the intensity level for a range of palette + * entries. An intensity of zero indicates total + * darkness. Intensity may be set to over 100 percent. + */ + void setFade(const uint16 percent, const uint8 fromColor, const uint16 toColor); + void fadeOff(); + void applyFade(); +}; + +} // End of namespace Sci #endif diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp index d7ef84dc1e..2eab391afd 100644 --- a/engines/sci/graphics/picture.cpp +++ b/engines/sci/graphics/picture.cpp @@ -209,12 +209,12 @@ void GfxPicture::drawSci32Vga(int16 celNo, int16 drawX, int16 drawY, int16 pictu } // Header - // [headerSize:WORD] [celCount:BYTE] [Unknown:BYTE] [Unknown:WORD] [paletteOffset:DWORD] [Unknown:DWORD] + // 0[headerSize:WORD] 2[celCount:BYTE] 3[Unknown:BYTE] 4[celHeaderSize:WORD] 6[paletteOffset:DWORD] 10[Unknown:WORD] 12[Unknown:WORD] // cel-header follow afterwards, each is 42 bytes // Cel-Header - // [width:WORD] [height:WORD] [displaceX:WORD] [displaceY:WORD] [clearColor:BYTE] [compressed:BYTE] + // 0[width:WORD] 2[height:WORD] 4[displaceX:WORD] 6[displaceY:WORD] 8[clearColor:BYTE] 9[compressed:BYTE] // offset 10-23 is unknown - // [rleOffset:DWORD] [literalOffset:DWORD] [Unknown:WORD] [Unknown:WORD] [priority:WORD] [relativeXpos:WORD] [relativeYpos:WORD] + // 24[rleOffset:DWORD] 28[literalOffset:DWORD] 32[Unknown:WORD] 34[Unknown:WORD] 36[priority:WORD] 38[relativeXpos:WORD] 40[relativeYpos:WORD] cel_headerPos += 42 * celNo; diff --git a/engines/sci/graphics/picture.h b/engines/sci/graphics/picture.h index 2404f99b41..942fa0f107 100644 --- a/engines/sci/graphics/picture.h +++ b/engines/sci/graphics/picture.h @@ -38,6 +38,9 @@ enum { class GfxPorts; class GfxScreen; class GfxPalette; +class GfxCoordAdjuster; +class ResourceManager; +class Resource; /** * Picture class, handles loading and displaying of picture resources diff --git a/engines/sci/graphics/plane32.cpp b/engines/sci/graphics/plane32.cpp new file mode 100644 index 0000000000..d05e4f79e1 --- /dev/null +++ b/engines/sci/graphics/plane32.cpp @@ -0,0 +1,907 @@ +/* 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 "sci/console.h" +#include "sci/engine/kernel.h" +#include "sci/engine/selector.h" +#include "sci/engine/state.h" +#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" + +namespace Sci { +#pragma mark DrawList +void DrawList::add(ScreenItem *screenItem, const Common::Rect &rect) { + DrawItem *drawItem = new DrawItem; + drawItem->screenItem = screenItem; + drawItem->rect = rect; + DrawListBase::add(drawItem); +} + +#pragma mark - +#pragma mark Plane +uint16 Plane::_nextObjectId = 20000; + +Plane::Plane(const Common::Rect &gameRect, PlanePictureCodes pictureId) : +_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth), +_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight), +_pictureId(pictureId), +_mirrored(false), +_back(0), +_priorityChanged(0), +_object(make_reg(0, _nextObjectId++)), +_redrawAllCount(g_sci->_gfxFrameout->getScreenCount()), +_created(g_sci->_gfxFrameout->getScreenCount()), +_updated(0), +_deleted(0), +_moved(0), +_gameRect(gameRect) { + convertGameRectToPlaneRect(); + _priority = MAX(10000, g_sci->_gfxFrameout->getPlanes().getTopPlanePriority() + 1); + setType(); + _screenRect = _planeRect; +} + +Plane::Plane(reg_t object) : +_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth), +_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight), +_priorityChanged(false), +_object(object), +_redrawAllCount(g_sci->_gfxFrameout->getScreenCount()), +_created(g_sci->_gfxFrameout->getScreenCount()), +_updated(0), +_deleted(0), +_moved(0) { + SegManager *segMan = g_sci->getEngineState()->_segMan; + _vanishingPoint.x = readSelectorValue(segMan, object, SELECTOR(vanishingX)); + _vanishingPoint.y = readSelectorValue(segMan, object, SELECTOR(vanishingY)); + + _gameRect.left = readSelectorValue(segMan, object, SELECTOR(inLeft)); + _gameRect.top = readSelectorValue(segMan, object, SELECTOR(inTop)); + _gameRect.right = readSelectorValue(segMan, object, SELECTOR(inRight)) + 1; + _gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom)) + 1; + convertGameRectToPlaneRect(); + + _back = readSelectorValue(segMan, object, SELECTOR(back)); + _priority = readSelectorValue(segMan, object, SELECTOR(priority)); + _pictureId = readSelectorValue(segMan, object, SELECTOR(picture)); + setType(); + + _mirrored = readSelectorValue(segMan, object, SELECTOR(mirrored)); + _screenRect = _planeRect; + changePic(); +} + +Plane::Plane(const Plane &other) : +_pictureId(other._pictureId), +_mirrored(other._mirrored), +_field_34(other._field_34), _field_38(other._field_38), +_field_3C(other._field_3C), _field_40(other._field_40), +_back(other._back), +_object(other._object), +_priority(other._priority), +_planeRect(other._planeRect), +_gameRect(other._gameRect), +_screenRect(other._screenRect), +_screenItemList(other._screenItemList) {} + +void Plane::operator=(const Plane &other) { + _gameRect = other._gameRect; + _planeRect = other._planeRect; + _vanishingPoint = other._vanishingPoint; + _pictureId = other._pictureId; + _type = other._type; + _mirrored = other._mirrored; + _priority = other._priority; + _back = other._back; + _width = other._width; + _field_34 = other._field_34; + _height = other._height; + _screenRect = other._screenRect; + _field_3C = other._field_3C; + _priorityChanged = other._priorityChanged; +} + +void Plane::init() { + _nextObjectId = 20000; +} + +void Plane::convertGameRectToPlaneRect() { + const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth; + const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight; + const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + + const Ratio ratioX = Ratio(screenWidth, scriptWidth); + const Ratio ratioY = Ratio(screenHeight, scriptHeight); + + _planeRect = _gameRect; + mulru(_planeRect, ratioX, ratioY, 1); +} + +void Plane::printDebugInfo(Console *con) const { + Common::String name; + + if (_object.isNumber()) { + name = "-scummvm-"; + } else { + name = g_sci->getEngineState()->_segMan->getObjectName(_object); + } + + con->debugPrintf("%04x:%04x (%s): type %d, prio %d, pic %d, mirror %d, back %d\n", + PRINT_REG(_object), + name.c_str(), + _type, + _priority, + _pictureId, + _mirrored, + _back + ); + con->debugPrintf(" game rect: (%d, %d, %d, %d), plane rect: (%d, %d, %d, %d)\n screen rect: (%d, %d, %d, %d)\n", + PRINT_RECT(_gameRect), + PRINT_RECT(_planeRect), + PRINT_RECT(_screenRect) + ); + con->debugPrintf(" # screen items: %d\n", _screenItemList.size()); +} + +#pragma mark - +#pragma mark Plane - Pic + +void Plane::addPicInternal(const GuiResourceId pictureId, const Common::Point *position, const bool mirrorX) { + + uint16 celCount = 1000; + for (uint16 celNo = 0; celNo < celCount; ++celNo) { + CelObjPic *celObj = new CelObjPic(pictureId, celNo); + if (celCount == 1000) { + celCount = celObj->_celCount; + } + + ScreenItem *screenItem = new ScreenItem(_object, celObj->_info); + screenItem->_pictureId = pictureId; + screenItem->_mirrorX = mirrorX; + screenItem->_priority = celObj->_priority; + screenItem->_fixPriority = true; + if (position != nullptr) { + screenItem->_position = *position + celObj->_relativePosition; + } else { + screenItem->_position = celObj->_relativePosition; + } + _screenItemList.add(screenItem); + + delete screenItem->_celObj; + screenItem->_celObj = celObj; + } +} + +void Plane::addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX) { + deletePic(pictureId); + addPicInternal(pictureId, &position, mirrorX); + // NOTE: In SCI engine this method returned the pictureId of the + // plane, but this return value was never used +} + +void Plane::changePic() { + _pictureChanged = false; + + if (_type != kPlaneTypePicture) { + return; + } + + addPicInternal(_pictureId, nullptr, _mirrored); +} + +void Plane::deletePic(const GuiResourceId pictureId) { + for (ScreenItemList::iterator it = _screenItemList.begin(); it != _screenItemList.end(); ++it) { + ScreenItem *screenItem = *it; + if (screenItem->_pictureId == pictureId) { + screenItem->_created = 0; + screenItem->_updated = 0; + screenItem->_deleted = g_sci->_gfxFrameout->getScreenCount(); + } + } +} + +void Plane::deletePic(const GuiResourceId oldPictureId, const GuiResourceId newPictureId) { + deletePic(oldPictureId); + _pictureId = newPictureId; +} + +void Plane::deleteAllPics() { + for (ScreenItemList::iterator it = _screenItemList.begin(); it != _screenItemList.end(); ++it) { + ScreenItem *screenItem = *it; + if (screenItem != nullptr && screenItem->_celInfo.type == kCelTypePic) { + if (screenItem->_created == 0) { + screenItem->_created = 0; + screenItem->_updated = 0; + screenItem->_deleted = g_sci->_gfxFrameout->getScreenCount(); + } else { + _screenItemList.erase(it); + } + } + } + + _screenItemList.pack(); +} + +#pragma mark - +#pragma mark Plane - Rendering + +void Plane::breakDrawListByPlanes(DrawList &drawList, const PlaneList &planeList) const { + int index = planeList.findIndexByObject(_object); + + for (DrawList::size_type i = 0; i < drawList.size(); ++i) { + for (PlaneList::size_type j = index + 1; j < planeList.size(); ++j) { + if (planeList[j]->_type != kPlaneTypeTransparent) { + Common::Rect ptr[4]; + int count = splitRects(drawList[i]->rect, planeList[j]->_screenRect, ptr); + if (count != -1) { + for (int k = count - 1; k >= 0; --k) { + drawList.add(drawList[i]->screenItem, ptr[k]); + } + + drawList.erase_at(i); + break; + } + } + } + } + drawList.pack(); +} + +void Plane::breakEraseListByPlanes(RectList &eraseList, const PlaneList &planeList) const { + int index = planeList.findIndexByObject(_object); + + for (RectList::size_type i = 0; i < eraseList.size(); ++i) { + for (PlaneList::size_type j = index + 1; j < planeList.size(); ++j) { + if (planeList[j]->_type != kPlaneTypeTransparent) { + Common::Rect ptr[4]; + + int count = splitRects(*eraseList[i], planeList[j]->_screenRect, ptr); + if (count != -1) { + for (int k = count - 1; k >= 0; --k) { + eraseList.add(ptr[k]); + } + + eraseList.erase_at(i); + break; + } + } + } + } + eraseList.pack(); +} + +void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList) { + ScreenItemList::size_type planeItemCount = _screenItemList.size(); + ScreenItemList::size_type visiblePlaneItemCount = visiblePlane._screenItemList.size(); + + for (ScreenItemList::size_type i = 0; i < planeItemCount; ++i) { + ScreenItem *vitem = nullptr; + // NOTE: The original engine used an array without bounds checking + // so could just get the visible screen item directly; we need to + // verify that the index is actually within the valid range for + // the visible plane before accessing the item to avoid a range + // error. + if (i < visiblePlaneItemCount) { + vitem = visiblePlane._screenItemList[i]; + } + ScreenItem *item = _screenItemList[i]; + + if (i < _screenItemList.size() && item != nullptr) { + if (item->_deleted) { + // add item's rect to erase list + if ( + i < visiblePlane._screenItemList.size() && + vitem != nullptr && + !vitem->_screenRect.isEmpty() + ) { + if (g_sci->_gfxRemap32->getRemapCount()) { + mergeToRectList(vitem->_screenRect, eraseList); + } else { + eraseList.add(vitem->_screenRect); + } + } + } else if (item->_created) { + // add item to draw list + item->calcRects(*this); + + if(!item->_screenRect.isEmpty()) { + if (g_sci->_gfxRemap32->getRemapCount()) { + drawList.add(item, item->_screenRect); + mergeToRectList(item->_screenRect, eraseList); + } else { + drawList.add(item, item->_screenRect); + } + } + } else if (item->_updated) { + // add old rect to erase list, new item to draw list + item->calcRects(*this); + if (g_sci->_gfxRemap32->getRemapCount()) { + // if item and vitem don't overlap, ... + if (item->_screenRect.isEmpty() || + i >= visiblePlaneItemCount || + vitem == nullptr || + vitem->_screenRect.isEmpty() || + !vitem->_screenRect.intersects(item->_screenRect) + ) { + // add item to draw list, and old rect to erase list + if (!item->_screenRect.isEmpty()) { + drawList.add(item, item->_screenRect); + mergeToRectList(item->_screenRect, eraseList); + } + if ( + i < visiblePlaneItemCount && + vitem != nullptr && + !vitem->_screenRect.isEmpty() + ) { + mergeToRectList(vitem->_screenRect, eraseList); + } + } else { + // otherwise, add bounding box of old+new to erase list, + // and item to draw list + + // TODO: This was changed from disasm, verify please! + Common::Rect extendedScreenRect = vitem->_screenRect; + extendedScreenRect.extend(item->_screenRect); + + drawList.add(item, item->_screenRect); + mergeToRectList(extendedScreenRect, eraseList); + } + } else { + // if no active remaps, just add item to draw list and old rect + // to erase list + if (!item->_screenRect.isEmpty()) { + drawList.add(item, item->_screenRect); + } + if ( + i < visiblePlaneItemCount && + vitem != nullptr && + !vitem->_screenRect.isEmpty() + ) { + eraseList.add(vitem->_screenRect); + } + } + } + } + } + + // Remove parts of eraselist/drawlist that are covered by other planes + breakEraseListByPlanes(eraseList, planeList); + breakDrawListByPlanes(drawList, planeList); + + // We store the current size of the drawlist, as we want to loop + // over the currently inserted entries later. + DrawList::size_type drawListSizePrimary = drawList.size(); + + if (/* TODO: dword_C6288 */ false) { // "high resolution pictures"???? + _screenItemList.sort(); + bool encounteredPic = false; + bool v81 = false; + + for (RectList::size_type i = 0; i < eraseList.size(); ++i) { + const Common::Rect *rect = eraseList[i]; + + for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) { + ScreenItem *item = _screenItemList[j]; + + if (j < _screenItemList.size() && item != nullptr) { + if (rect->intersects(item->_screenRect)) { + const Common::Rect intersection = rect->findIntersectingRect(item->_screenRect); + if (!item->_deleted) { + if (encounteredPic) { + if (item->_celInfo.type == kCelTypePic) { + if (v81 || item->_celInfo.celNo == 0) { + drawList.add(item, intersection); + } + } else { + if (!item->_updated && !item->_created) { + drawList.add(item, intersection); + } + v81 = true; + } + } else { + if (!item->_updated && !item->_created) { + drawList.add(item, intersection); + } + if (item->_celInfo.type == kCelTypePic) { + encounteredPic = true; + } + } + } + } + } + } + } + + _screenItemList.unsort(); + } else { + // add all items overlapping the erase list to the draw list + for (RectList::size_type i = 0; i < eraseList.size(); ++i) { + for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) { + ScreenItem *item = _screenItemList[j]; + if ( + item != nullptr && + !item->_created && !item->_updated && !item->_deleted && + eraseList[i]->intersects(item->_screenRect) + ) { + drawList.add(item, eraseList[i]->findIntersectingRect(item->_screenRect)); + } + } + } + } + + if (g_sci->_gfxRemap32->getRemapCount() == 0) { // no remaps active? + // Add all items that overlap with items in the drawlist and have higher + // priority. + + // We only loop over "primary" items in the draw list, skipping + // those that were added because of the erase list in the previous loop, + // or those to be added in this loop. + for (DrawList::size_type i = 0; i < drawListSizePrimary; ++i) { + DrawItem *dli = drawList[i]; + + for (ScreenItemList::size_type j = 0; j < planeItemCount; ++j) { + ScreenItem *sli = _screenItemList[j]; + + if ( + i < drawList.size() && dli != nullptr && + j < _screenItemList.size() && sli != nullptr && + !sli->_created && !sli->_updated && !sli->_deleted + ) { + ScreenItem *item = dli->screenItem; + + if ( + (sli->_priority > item->_priority || (sli->_priority == item->_priority && sli->_object > item->_object)) && + dli->rect.intersects(sli->_screenRect) + ) { + drawList.add(sli, dli->rect.findIntersectingRect(sli->_screenRect)); + } + } + } + } + } + + decrementScreenItemArrayCounts(&visiblePlane, false); + _screenItemList.pack(); + visiblePlane._screenItemList.pack(); +} + +void Plane::decrementScreenItemArrayCounts(Plane *visiblePlane, const bool forceUpdate) { + // The size of the screenItemList may change, so it is + // critical to re-check the size on each iteration + for (ScreenItemList::size_type i = 0; i < _screenItemList.size(); ++i) { + ScreenItem *item = _screenItemList[i]; + + if (item != nullptr) { + // update item in visiblePlane if item is updated + if ( + item->_updated || + ( + forceUpdate && + visiblePlane != nullptr && + visiblePlane->_screenItemList.findByObject(item->_object) != nullptr + ) + ) { + *visiblePlane->_screenItemList[i] = *_screenItemList[i]; + } + + if (item->_updated) { + item->_updated--; + } + + // create new item in visiblePlane if item was added + if (item->_created) { + item->_created--; + if (visiblePlane != nullptr) { + visiblePlane->_screenItemList.add(new ScreenItem(*item)); + } + } + + // delete item from both planes if it was deleted + if (item->_deleted) { + item->_deleted--; + if (!item->_deleted) { + visiblePlane->_screenItemList.erase_at(i); + _screenItemList.erase_at(i); + } + } + } + } +} + +void Plane::filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &transparentEraseList) const { + if (_type == kPlaneTypeTransparent) { + for (RectList::size_type i = 0; i < transparentEraseList.size(); ++i) { + const Common::Rect *r = transparentEraseList[i]; + for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) { + ScreenItem *item = _screenItemList[j]; + if (item != nullptr) { + if (r->intersects(item->_screenRect)) { + mergeToDrawList(j, *r, drawList); + } + } + } + } + } else { + for (RectList::size_type i = 0; i < transparentEraseList.size(); ++i) { + Common::Rect *r = transparentEraseList[i]; + if (r->intersects(_screenRect)) { + r->clip(_screenRect); + mergeToRectList(*r, eraseList); + + for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) { + ScreenItem *item = _screenItemList[j]; + + if (item != nullptr) { + if (r->intersects(item->_screenRect)) { + mergeToDrawList(j, *r, drawList); + } + } + } + + Common::Rect ptr[4]; + const Common::Rect *r2 = transparentEraseList[i]; + int count = splitRects(*r2, *r, ptr); + for (int k = count - 1; k >= 0; --k) { + transparentEraseList.add(ptr[k]); + } + transparentEraseList.erase_at(i); + } + } + + transparentEraseList.pack(); + } +} + +void Plane::filterUpDrawRects(DrawList &transparentDrawList, const DrawList &drawList) const { + for (DrawList::size_type i = 0; i < drawList.size(); ++i) { + const Common::Rect &r = drawList[i]->rect; + + for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) { + ScreenItem *item = _screenItemList[j]; + if (item != nullptr) { + if (r.intersects(item->_screenRect)) { + mergeToDrawList(j, r, transparentDrawList); + } + } + } + } +} + +void Plane::filterUpEraseRects(DrawList &drawList, RectList &eraseList) const { + for (RectList::size_type i = 0; i < eraseList.size(); ++i) { + const Common::Rect &r = *eraseList[i]; + for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) { + ScreenItem *item = _screenItemList[j]; + + if (item != nullptr) { + if (r.intersects(item->_screenRect)) { + mergeToDrawList(j, r, drawList); + } + } + } + } +} + +void Plane::mergeToDrawList(const ScreenItemList::size_type index, const Common::Rect &rect, DrawList &drawList) const { + RectList rects; + + ScreenItem *item = _screenItemList[index]; + Common::Rect r = item->_screenRect; + r.clip(rect); + rects.add(r); + + for (RectList::size_type i = 0; i < rects.size(); ++i) { + r = *rects[i]; + + for (DrawList::size_type j = 0; j < drawList.size(); ++j) { + const DrawItem *drawitem = drawList[j]; + if (item->_object == drawitem->screenItem->_object) { + if (drawitem->rect.contains(r)) { + rects.erase_at(i); + break; + } + + Common::Rect outRects[4]; + const int count = splitRects(r, drawitem->rect, outRects); + if (count != -1) { + for (int k = count - 1; k >= 0; --k) { + rects.add(outRects[k]); + } + + rects.erase_at(i); + + // proceed to the next rect + r = *rects[++i]; + } + } + } + } + + rects.pack(); + + for (RectList::size_type i = 0; i < rects.size(); ++i) { + drawList.add(item, *rects[i]); + } +} + +void Plane::mergeToRectList(const Common::Rect &rect, RectList &rectList) const { + RectList temp; + temp.add(rect); + + for (RectList::size_type i = 0; i < temp.size(); ++i) { + Common::Rect r = *temp[i]; + + for (RectList::size_type j = 0; j < rectList.size(); ++j) { + const Common::Rect *innerRect = rectList[j]; + if (innerRect->contains(r)) { + temp.erase_at(i); + break; + } + + Common::Rect out[4]; + const int count = splitRects(r, *innerRect, out); + if (count != -1) { + for (int k = count - 1; k >= 0; --k) { + temp.add(out[k]); + } + + temp.erase_at(i); + + // proceed to the next rect + r = *temp[++i]; + } + } + } + + temp.pack(); + + for (RectList::size_type i = 0; i < temp.size(); ++i) { + rectList.add(*temp[i]); + } +} + +void Plane::redrawAll(Plane *visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList) { + for (ScreenItemList::const_iterator screenItemPtr = _screenItemList.begin(); screenItemPtr != _screenItemList.end(); ++screenItemPtr) { + if (*screenItemPtr != nullptr) { + ScreenItem &screenItem = **screenItemPtr; + if (!screenItem._deleted) { + screenItem.calcRects(*this); + if (!screenItem._screenRect.isEmpty()) { + drawList.add(&screenItem, screenItem._screenRect); + } + } + } + } + + eraseList.clear(); + + if (!_screenRect.isEmpty() && _type != kPlaneTypePicture && _type != kPlaneTypeOpaque) { + eraseList.add(_screenRect); + } + breakEraseListByPlanes(eraseList, planeList); + breakDrawListByPlanes(drawList, planeList); + --_redrawAllCount; + decrementScreenItemArrayCounts(visiblePlane, true); + _screenItemList.pack(); + if (visiblePlane != nullptr) { + visiblePlane->_screenItemList.pack(); + } +} + +void Plane::setType() { + if (_pictureId == kPlanePicOpaque) { + _type = kPlaneTypeOpaque; + } else if (_pictureId == kPlanePicTransparent) { + _type = kPlaneTypeTransparent; + } else if (_pictureId == kPlanePicColored) { + _type = kPlaneTypeColored; + } else { + _type = kPlaneTypePicture; + } +} + +void Plane::sync(const Plane *other, const Common::Rect &screenRect) { + if (other == nullptr) { + if (_pictureChanged) { + deleteAllPics(); + setType(); + changePic(); + _redrawAllCount = g_sci->_gfxFrameout->getScreenCount(); + } else { + setType(); + } + } else { + if ( + _planeRect.top != other->_planeRect.top || + _planeRect.left != other->_planeRect.left || + _planeRect.right > other->_planeRect.right || + _planeRect.bottom > other->_planeRect.bottom + ) { + _redrawAllCount = g_sci->_gfxFrameout->getScreenCount(); + _updated = g_sci->_gfxFrameout->getScreenCount(); + } else if (_planeRect != other->_planeRect) { + _updated = g_sci->_gfxFrameout->getScreenCount(); + } + + if (_priority != other->_priority) { + _priorityChanged = g_sci->_gfxFrameout->getScreenCount(); + } + + if (_pictureId != other->_pictureId || _mirrored != other->_mirrored || _pictureChanged) { + deleteAllPics(); + setType(); + changePic(); + _redrawAllCount = g_sci->_gfxFrameout->getScreenCount(); + } + + if (_back != other->_back) { + _redrawAllCount = g_sci->_gfxFrameout->getScreenCount(); + } + } + + _deleted = 0; + if (_created == 0) { + _moved = g_sci->_gfxFrameout->getScreenCount(); + } + + convertGameRectToPlaneRect(); + _width = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + _height = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + _screenRect = _planeRect; + // NOTE: screenRect originally was retrieved through globals + // instead of being passed into the function + clipScreenRect(screenRect); +} + +void Plane::update(const reg_t object) { + SegManager *segMan = g_sci->getEngineState()->_segMan; + _vanishingPoint.x = readSelectorValue(segMan, object, SELECTOR(vanishingX)); + _vanishingPoint.y = readSelectorValue(segMan, object, SELECTOR(vanishingY)); + _gameRect.left = readSelectorValue(segMan, object, SELECTOR(inLeft)); + _gameRect.top = readSelectorValue(segMan, object, SELECTOR(inTop)); + _gameRect.right = readSelectorValue(segMan, object, SELECTOR(inRight)) + 1; + _gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom)) + 1; + convertGameRectToPlaneRect(); + + _priority = readSelectorValue(segMan, object, SELECTOR(priority)); + GuiResourceId pictureId = readSelectorValue(segMan, object, SELECTOR(picture)); + if (_pictureId != pictureId) { + _pictureId = pictureId; + _pictureChanged = true; + } + + _mirrored = readSelectorValue(segMan, object, SELECTOR(mirrored)); + _back = readSelectorValue(segMan, object, SELECTOR(back)); +} + +void Plane::scrollScreenItems(const int16 deltaX, const int16 deltaY, const bool scrollPics) { + _redrawAllCount = g_sci->_gfxFrameout->getScreenCount(); + + for (ScreenItemList::iterator it = _screenItemList.begin(); it != _screenItemList.end(); ++it) { + if (*it != nullptr) { + ScreenItem &screenItem = **it; + if (!screenItem._deleted && (screenItem._celInfo.type != kCelTypePic || scrollPics)) { + screenItem._position.x += deltaX; + screenItem._position.y += deltaY; + } + } + } +} + +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) { + for (iterator it = begin(); it != end(); ++it) { + if ((*it)->_priority > plane->_priority) { + insert(it, plane); + return; + } + } + + push_back(plane); +} + +void PlaneList::clear() { + for (iterator it = begin(); it != end(); ++it) { + delete *it; + } + + PlaneListBase::clear(); +} + +void PlaneList::erase(Plane *plane) { + for (iterator it = begin(); it != end(); ++it) { + if (*it == plane) { + erase(it); + break; + } + } +} + +PlaneList::iterator PlaneList::erase(iterator it) { + delete *it; + return PlaneListBase::erase(it); +} + +int PlaneList::findIndexByObject(const reg_t object) const { + for (size_type i = 0; i < size(); ++i) { + if ((*this)[i] != nullptr && (*this)[i]->_object == object) { + return i; + } + } + + return -1; +} + +Plane *PlaneList::findByObject(const reg_t object) const { + const_iterator planeIt = Common::find_if(begin(), end(), FindByObject<Plane *>(object)); + + if (planeIt == end()) { + return nullptr; + } + + return *planeIt; +} + +int16 PlaneList::getTopPlanePriority() const { + if (size() > 0) { + return (*this)[size() - 1]->_priority; + } + + return 0; +} + +int16 PlaneList::getTopSciPlanePriority() const { + int16 priority = 0; + + for (const_iterator it = begin(); it != end(); ++it) { + if ((*it)->_priority >= 10000) { + break; + } + + priority = (*it)->_priority; + } + + return priority; +} + +void PlaneList::remove_at(size_type index) { + delete PlaneListBase::remove_at(index); +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/plane32.h b/engines/sci/graphics/plane32.h new file mode 100644 index 0000000000..770a6fa445 --- /dev/null +++ b/engines/sci/graphics/plane32.h @@ -0,0 +1,485 @@ +/* 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 SCI_GRAPHICS_PLANE32_H +#define SCI_GRAPHICS_PLANE32_H + +#include "common/array.h" +#include "common/rect.h" +#include "sci/engine/vm_types.h" +#include "sci/graphics/helpers.h" +#include "sci/graphics/lists32.h" +#include "sci/graphics/screen_item32.h" + +namespace Sci { +enum PlaneType { + kPlaneTypeColored = 0, + kPlaneTypePicture = 1, + kPlaneTypeTransparent = 2, + kPlaneTypeOpaque = 3 +}; + +enum PlanePictureCodes { + // NOTE: Any value at or below 65532 means the plane + // is a kPlaneTypePicture. + kPlanePic = 65532, + kPlanePicOpaque = 65533, + kPlanePicTransparent = 65534, + kPlanePicColored = 65535 +}; + +#pragma mark - +#pragma mark RectList + +typedef StablePointerArray<Common::Rect, 200> RectListBase; +class RectList : public RectListBase { +public: + void add(const Common::Rect &rect) { + RectListBase::add(new Common::Rect(rect)); + } +}; + +#pragma mark - +#pragma mark DrawList + +struct DrawItem { + ScreenItem *screenItem; + Common::Rect rect; + + inline bool operator<(const DrawItem &other) const { + return *screenItem < *other.screenItem; + } +}; + +typedef StablePointerArray<DrawItem, 250> DrawListBase; +class DrawList : public DrawListBase { +private: + inline static bool sortHelper(const DrawItem *a, const DrawItem *b) { + return *a < *b; + } +public: + void add(ScreenItem *screenItem, const Common::Rect &rect); + inline void sort() { + pack(); + Common::sort(begin(), end(), sortHelper); + } +}; + +class PlaneList; + +#pragma mark - +#pragma mark Plane + +/** + * A plane is a grouped layer of screen items. + */ +class Plane { +private: + /** + * A serial used for planes that are generated inside + * the graphics engine, rather than the interpreter. + */ + static uint16 _nextObjectId; + + /** + * The dimensions of the plane, in game script + * coordinates. + * TODO: These are never used and are always + * scriptWidth x scriptHeight in SCI engine? The actual + * dimensions of the plane are always in + * gameRect/planeRect. + */ + int16 _width, _height; + + /** + * For planes that are used to render picture data, the + * resource ID of the picture to be displayed. This + * value may also be one of the special + * PlanePictureCodes, in which case the plane becomes a + * non-picture plane. + */ + GuiResourceId _pictureId; + + /** + * Whether or not the contents of picture planes should + * be drawn horizontally mirrored. Only applies to + * planes of type kPlaneTypePicture. + */ + bool _mirrored; + + /** + * Whether the picture ID for this plane has changed. + * This flag is set when the plane is created or updated + * from a VM object, and is cleared when the plane is + * synchronised to another plane (which calls + * changePic). + */ + bool _pictureChanged; + + // TODO: Are these ever actually used? + int _field_34, _field_38; // probably a point or ratio + int _field_3C, _field_40; // probably a point or ratio + + /** + * Converts the dimensions of the game rect used by + * scripts to the dimensions of the plane rect used to + * render content to the screen. Coordinates with + * remainders are rounded up to the next whole pixel. + */ + void convertGameRectToPlaneRect(); + + /** + * Sets the type of the plane according to its assigned + * picture resource ID. + */ + void setType(); + +public: + /** + * The color to use when erasing the plane. Only + * applies to planes of type kPlaneTypeColored. + */ + byte _back; + + /** + * Whether the priority of this plane has changed. + * This flag is set when the plane is updated from + * another plane and cleared when draw list calculation + * occurs. + */ + int _priorityChanged; + + /** + * A handle to the VM object corresponding to this + * plane. Some planes are generated purely within the + * graphics engine and have a numeric object value. + */ + reg_t _object; + + /** + * The rendering priority of the plane. Higher + * priorities are drawn above lower priorities. + */ + int16 _priority; + + /** + * 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; + + PlaneType _type; + + /** + * Flags indicating the state of the plane. + * - `created` is set when the plane is first created, + * either from a VM object or from within the engine + * itself + * - `updated` is set when the plane is updated from + * another plane and the two planes' `planeRect`s do + * not match + * - `deleted` is set when the plane is deleted by a + * kernel call + * - `moved` is set when the plane is synchronised from + * another plane and is not already in the "created" + * state + */ + int _created, _updated, _deleted, _moved; + + /** + * The vanishing point for the plane. Used when + * calculating the correct scaling of the plane's screen + * items according to their position. + */ + Common::Point _vanishingPoint; + + /** + * The position & dimensions of the plane in screen + * coordinates. This rect is not clipped to the screen, + * so may include coordinates that are offscreen. + */ + Common::Rect _planeRect; + + /** + * The position & dimensions of the plane in game script + * coordinates. + */ + Common::Rect _gameRect; + + /** + * The position & dimensions of the plane in screen + * coordinates. This rect is clipped to the screen. + */ + Common::Rect _screenRect; + + /** + * The list of screen items grouped within this plane. + */ + ScreenItemList _screenItemList; + +public: + /** + * Initialises static Plane members. + */ + static void init(); + + // NOTE: This constructor signature originally did not accept a + // picture ID, but some calls to construct planes with this signature + // immediately set the picture ID and then called setType again, so + // it made more sense to just make the picture ID a parameter instead. + Plane(const Common::Rect &gameRect, PlanePictureCodes pictureId = kPlanePicColored); + + Plane(const reg_t object); + + Plane(const Plane &other); + + void operator=(const Plane &other); + + inline bool operator<(const Plane &other) const { + if (_priority < other._priority) { + return true; + } + + if (_priority == other._priority) { + return _object < other._object; + } + + return false; + } + + /** + * Clips the screen rect of this plane to fit within the + * given screen rect. + */ + inline void clipScreenRect(const Common::Rect &screenRect) { + if (_screenRect.intersects(screenRect)) { + _screenRect.clip(screenRect); + } else { + _screenRect.left = 0; + _screenRect.top = 0; + _screenRect.right = 0; + _screenRect.bottom = 0; + } + } + + void printDebugInfo(Console *con) const; + + /** + * Compares the properties of the current plane against + * the properties of the `other` plane (which is the + * corresponding plane from the visible plane list) to + * discover which properties have been changed on this + * plane by a call to `update(reg_t)`. + * + * @note This method was originally called UpdatePlane + * in SCI engine. + */ + void sync(const Plane *other, const Common::Rect &screenRect); + + /** + * Updates the plane to match the state of the plane + * object from the virtual machine. + * + * @note This method was originally called UpdatePlane + * in SCI engine. + */ + void update(const reg_t object); + + /** + * Modifies the position of all non-pic screen items + * by the given delta. If `scrollPics` is true, pic + * items are also repositioned. + */ + void scrollScreenItems(const int16 deltaX, const int16 deltaY, const bool scrollPics); + +#pragma mark - +#pragma mark Plane - Pic +private: + /** + * Adds all cels from the specified picture resource to + * the plane as screen items. If a position is provided, + * the screen items will be given that position; + * otherwise, the default relative positions for each + * cel will be taken from the picture resource data. + */ + inline void addPicInternal(const GuiResourceId pictureId, const Common::Point *position, const bool mirrorX); + + /** + * Marks all screen items to be deleted that are within + * this plane and match the given picture ID. + */ + void deletePic(const GuiResourceId pictureId); + + /** + * Marks all screen items to be deleted that are within + * this plane and match the given picture ID, then sets + * the picture ID of the plane to the new picture ID + * without adding any screen items. + */ + void deletePic(const GuiResourceId oldPictureId, const GuiResourceId newPictureId); + + /** + * Marks all screen items to be deleted that are within + * this plane and are picture cels. + */ + void deleteAllPics(); + +public: + /** + * Marks all existing screen items matching the current + * picture to be deleted, then adds all cels from the + * new picture resource to the plane at the given + * position. + */ + void addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX); + + /** + * If the plane is a picture plane, re-adds all cels + * from its picture resource to the plane. Otherwise, + * just clears the _pictureChanged flag. + */ + void changePic(); + +#pragma mark - +#pragma mark Plane - Rendering +private: + /** + * Splits all rects in the given draw list at the edges + * of all non-transparent planes above the current + * plane. + */ + void breakDrawListByPlanes(DrawList &drawList, const PlaneList &planeList) const; + + /** + * Splits all rects in the given erase list rects at the + * edges of all non-transparent planes above the current + * plane. + */ + void breakEraseListByPlanes(RectList &eraseList, const PlaneList &planeList) const; + + /** + * Synchronises changes to screen items from the current + * plane to the visible plane and deletes screen items + * from the current plane that have been marked as + * deleted. If `forceUpdate` is true, all screen items + * on the visible plane will be updated, even if they + * are not marked as having changed. + */ + void decrementScreenItemArrayCounts(Plane *visiblePlane, const bool forceUpdate); + + /** + * Merges the screen item from this plane at the given + * index into the given draw list, clipped to the given + * rect. TODO: Finish documenting + */ + void mergeToDrawList(const DrawList::size_type index, const Common::Rect &rect, DrawList &drawList) const; + + /** + * Adds the given rect into the given rect list, + * merging it with other rects already inside the list, + * if possible, to avoid overdraw. TODO: Finish + * documenting + */ + void mergeToRectList(const Common::Rect &rect, RectList &rectList) const; + +public: + /** + * Calculates the location and dimensions of dirty rects + * of the screen items in this plane and adds them to + * the given draw and erase lists, and synchronises this + * plane's list of screen items to the given visible + * plane. + */ + void calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList); + + /** + * TODO: Documentation + */ + void filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &transparentEraseList) const; + + /** + * TODO: Documentation + */ + void filterUpEraseRects(DrawList &drawList, RectList &eraseList) const; + + /** + * TODO: Documentation + */ + void filterUpDrawRects(DrawList &transparentDrawList, const DrawList &drawList) const; + + /** + * Updates all of the plane's non-deleted screen items + * 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 - +#pragma mark PlaneList + +typedef Common::Array<Plane *> PlaneListBase; +class PlaneList : public PlaneListBase { +private: + inline static bool sortHelper(const Plane *a, const Plane *b) { + return *a < *b; + } + + using PlaneListBase::push_back; + +public: + // A method for finding the index of a plane inside a + // PlaneList is used because entries in the main plane + // list and visible plane list of GfxFrameout are + // synchronised by index + int findIndexByObject(const reg_t object) const; + Plane *findByObject(const reg_t object) const; + + /** + * Gets the priority of the top plane in the plane list. + */ + int16 getTopPlanePriority() const; + + /** + * Gets the priority of the top plane in the plane list + * created by a game script. + */ + int16 getTopSciPlanePriority() const; + + void add(Plane *plane); + void clear(); + iterator erase(iterator it); + void erase(Plane *plane); + inline void sort() { + Common::sort(begin(), end(), sortHelper); + } + void remove_at(size_type index); +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/remap.cpp b/engines/sci/graphics/remap.cpp new file mode 100644 index 0000000000..e331eaf971 --- /dev/null +++ b/engines/sci/graphics/remap.cpp @@ -0,0 +1,386 @@ +/* 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 "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" + +namespace Sci { + +#pragma mark - +#pragma mark SCI16 remapping (QFG4 demo) + +GfxRemap::GfxRemap(GfxPalette *palette) + : _palette(palette) { + _remapOn = false; + resetRemapping(); +} + +GfxRemap::~GfxRemap() { +} + +byte GfxRemap::remapColor(byte remappedColor, byte screenColor) { + assert(_remapOn); + if (_remappingType[remappedColor] == kRemappingByRange) + return _remappingByRange[screenColor]; + else if (_remappingType[remappedColor] == kRemappingByPercent) + return _remappingByPercent[screenColor]; + else + error("remapColor(): Color %d isn't remapped", remappedColor); + + return 0; // should never reach here +} + +void GfxRemap::resetRemapping() { + _remapOn = false; + _remappingPercentToSet = 0; + + for (int i = 0; i < 256; i++) { + _remappingType[i] = kRemappingNone; + _remappingByPercent[i] = i; + _remappingByRange[i] = i; + } +} + +void GfxRemap::setRemappingPercent(byte color, byte percent) { + _remapOn = true; + + // 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; + + for (int i = 0; i < 256; i++) { + byte r = _palette->_sysPalette.colors[i].r * _remappingPercentToSet / 100; + byte g = _palette->_sysPalette.colors[i].g * _remappingPercentToSet / 100; + byte b = _palette->_sysPalette.colors[i].b * _remappingPercentToSet / 100; + _remappingByPercent[i] = _palette->kernelFindColor(r, g, b); + } + + _remappingType[color] = kRemappingByPercent; +} + +void GfxRemap::setRemappingRange(byte color, byte from, byte to, byte base) { + _remapOn = true; + + for (int i = from; i <= to; i++) { + _remappingByRange[i] = i + base; + } + + _remappingType[color] = kRemappingByRange; +} + +void GfxRemap::updateRemapping() { + // Check if we need to reset remapping by percent with the new colors. + if (_remappingPercentToSet) { + for (int i = 0; i < 256; i++) { + byte r = _palette->_sysPalette.colors[i].r * _remappingPercentToSet / 100; + byte g = _palette->_sysPalette.colors[i].g * _remappingPercentToSet / 100; + byte b = _palette->_sysPalette.colors[i].b * _remappingPercentToSet / 100; + _remappingByPercent[i] = _palette->kernelFindColor(r, g, b); + } + } +} + +#pragma mark - +#pragma mark SCI32 remapping + +#ifdef ENABLE_SCI32 + +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; + + // 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--; + } + + _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 new file mode 100644 index 0000000000..d012568f7f --- /dev/null +++ b/engines/sci/graphics/remap.h @@ -0,0 +1,154 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef SCI_GRAPHICS_REMAP_H +#define SCI_GRAPHICS_REMAP_H + +#include "common/array.h" +#include "sci/graphics/helpers.h" + +namespace Sci { + +class GfxScreen; + +enum ColorRemappingType { + kRemappingNone = 0, + kRemappingByRange = 1, + 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(GfxPalette *_palette); + ~GfxRemap(); + + void resetRemapping(); + void setRemappingPercent(byte color, byte percent); + void setRemappingRange(byte color, byte from, byte to, byte base); + bool isRemapped(byte color) const { + return _remapOn && (_remappingType[color] != kRemappingNone); + } + byte remapColor(byte remappedColor, byte screenColor); + void updateRemapping(); + +private: + GfxScreen *_screen; + GfxPalette *_palette; + + bool _remapOn; + ColorRemappingType _remappingType[256]; + byte _remappingByPercent[256]; + byte _remappingByRange[256]; + uint16 _remappingPercentToSet; +}; + +#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(GfxPalette32 *palette); + ~GfxRemap32() {} + + 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 + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp index 4cd6344600..c977a93817 100644 --- a/engines/sci/graphics/screen.cpp +++ b/engines/sci/graphics/screen.cpp @@ -214,36 +214,6 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) { error("Unknown SCI1.1 Mac game"); } else initGraphics(_displayWidth, _displayHeight, _displayWidth > 320); - - // Initialize code pointers - _vectorAdjustCoordinatePtr = &GfxScreen::vectorAdjustCoordinateNOP; - _vectorAdjustLineCoordinatesPtr = &GfxScreen::vectorAdjustLineCoordinatesNOP; - _vectorIsFillMatchPtr = &GfxScreen::vectorIsFillMatchNormal; - _vectorPutPixelPtr = &GfxScreen::putPixelNormal; - _vectorPutLinePixelPtr = &GfxScreen::putPixel; - _vectorGetPixelPtr = &GfxScreen::getPixelNormal; - _putPixelPtr = &GfxScreen::putPixelNormal; - _getPixelPtr = &GfxScreen::getPixelNormal; - - switch (_upscaledHires) { - case GFX_SCREEN_UPSCALED_480x300: - _vectorAdjustCoordinatePtr = &GfxScreen::vectorAdjustCoordinate480x300Mac; - _vectorAdjustLineCoordinatesPtr = &GfxScreen::vectorAdjustLineCoordinates480x300Mac; - // vectorPutPixel -> we already adjust coordinates for vector code, that's why we can set pixels directly - // vectorGetPixel -> see vectorPutPixel - _vectorPutLinePixelPtr = &GfxScreen::vectorPutLinePixel480x300Mac; - _putPixelPtr = &GfxScreen::putPixelAllUpscaled; - _getPixelPtr = &GfxScreen::getPixelUpscaled; - break; - case GFX_SCREEN_UPSCALED_640x400: - case GFX_SCREEN_UPSCALED_640x440: - case GFX_SCREEN_UPSCALED_640x480: - _vectorPutPixelPtr = &GfxScreen::putPixelDisplayUpscaled; - _putPixelPtr = &GfxScreen::putPixelDisplayUpscaled; - break; - case GFX_SCREEN_UPSCALED_DISABLED: - break; - } } GfxScreen::~GfxScreen() { @@ -270,17 +240,26 @@ void GfxScreen::copyToScreen() { } void GfxScreen::copyFromScreen(byte *buffer) { - // TODO this ignores the pitch Graphics::Surface *screen = g_system->lockScreen(); - memcpy(buffer, screen->getPixels(), _displayPixels); + + if (screen->pitch == _displayWidth) { + memcpy(buffer, screen->getPixels(), _displayPixels); + } else { + const byte *src = (const byte *)screen->getPixels(); + uint height = _displayHeight; + + while (height--) { + memcpy(buffer, src, _displayWidth); + buffer += _displayWidth; + src += screen->pitch; + } + } + g_system->unlockScreen(); } void GfxScreen::kernelSyncWithFramebuffer() { - // TODO this ignores the pitch - Graphics::Surface *screen = g_system->lockScreen(); - memcpy(_displayScreen, screen->getPixels(), _displayPixels); - g_system->unlockScreen(); + copyFromScreen(_displayScreen); } void GfxScreen::copyRectToScreen(const Common::Rect &rect) { @@ -325,40 +304,68 @@ byte GfxScreen::getDrawingMask(byte color, byte prio, byte control) { return flag; } -void GfxScreen::vectorAdjustCoordinateNOP(int16 *x, int16 *y) { +void GfxScreen::vectorAdjustLineCoordinates(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) { + switch (_upscaledHires) { + case GFX_SCREEN_UPSCALED_480x300: { + int16 displayLeft = (*left * 3) / 2; + int16 displayRight = (*right * 3) / 2; + int16 displayTop = (*top * 3) / 2; + int16 displayBottom = (*bottom * 3) / 2; + + if (displayLeft < displayRight) { + // one more pixel to the left, one more pixel to the right + if (displayLeft > 0) + vectorPutLinePixel(displayLeft - 1, displayTop, drawMask, color, priority, control); + vectorPutLinePixel(displayRight + 1, displayBottom, drawMask, color, priority, control); + } else if (displayLeft > displayRight) { + if (displayRight > 0) + vectorPutLinePixel(displayRight - 1, displayBottom, drawMask, color, priority, control); + vectorPutLinePixel(displayLeft + 1, displayTop, drawMask, color, priority, control); + } + *left = displayLeft; + *top = displayTop; + *right = displayRight; + *bottom = displayBottom; + break; + } + default: + break; + } } -void GfxScreen::vectorAdjustCoordinate480x300Mac(int16 *x, int16 *y) { - *x = _upscaledWidthMapping[*x]; - *y = _upscaledHeightMapping[*y]; +// This is called from vector drawing to put a pixel at a certain location +void GfxScreen::vectorPutLinePixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + if (_upscaledHires == GFX_SCREEN_UPSCALED_480x300) { + vectorPutLinePixel480x300(x, y, drawMask, color, priority, control); + return; + } + + // For anything else forward to the regular putPixel + putPixel(x, y, drawMask, color, priority, control); } -void GfxScreen::vectorAdjustLineCoordinatesNOP(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) { +// Special 480x300 Mac putPixel for vector line drawing, also draws an additional pixel below the actual one +void GfxScreen::vectorPutLinePixel480x300(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + int offset = y * _width + x; + + if (drawMask & GFX_SCREEN_MASK_VISUAL) { + // also set pixel below actual pixel + _visualScreen[offset] = color; + _visualScreen[offset + _width] = color; + _displayScreen[offset] = color; + _displayScreen[offset + _displayWidth] = color; + } + if (drawMask & GFX_SCREEN_MASK_PRIORITY) { + _priorityScreen[offset] = priority; + _priorityScreen[offset + _width] = priority; + } + if (drawMask & GFX_SCREEN_MASK_CONTROL) { + _controlScreen[offset] = control; + _controlScreen[offset + _width] = control; + } } -void GfxScreen::vectorAdjustLineCoordinates480x300Mac(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) { - int16 displayLeft = _upscaledWidthMapping[*left]; - int16 displayRight = _upscaledWidthMapping[*right]; - int16 displayTop = _upscaledHeightMapping[*top]; - int16 displayBottom = _upscaledHeightMapping[*bottom]; - - if (displayLeft < displayRight) { - // one more pixel to the left, one more pixel to the right - if (displayLeft > 0) - vectorPutLinePixel(displayLeft - 1, displayTop, drawMask, color, priority, control); - vectorPutLinePixel(displayRight + 1, displayBottom, drawMask, color, priority, control); - } else if (displayLeft > displayRight) { - if (displayRight > 0) - vectorPutLinePixel(displayRight - 1, displayBottom, drawMask, color, priority, control); - vectorPutLinePixel(displayLeft + 1, displayTop, drawMask, color, priority, control); - } - *left = displayLeft; - *top = displayTop; - *right = displayRight; - *bottom = displayBottom; -} - -byte GfxScreen::vectorIsFillMatchNormal(int16 x, int16 y, byte screenMask, byte checkForColor, byte checkForPriority, byte checkForControl, bool isEGA) { +byte GfxScreen::vectorIsFillMatch(int16 x, int16 y, byte screenMask, byte checkForColor, byte checkForPriority, byte checkForControl, bool isEGA) { int offset = y * _width + x; byte match = 0; @@ -388,132 +395,6 @@ byte GfxScreen::vectorIsFillMatchNormal(int16 x, int16 y, byte screenMask, byte return match; } -// Special 480x300 Mac putPixel for vector line drawing, also draws an additional pixel below the actual one -void GfxScreen::vectorPutLinePixel480x300Mac(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { - int offset = y * _width + x; - - if (drawMask & GFX_SCREEN_MASK_VISUAL) { - _visualScreen[offset] = color; - _visualScreen[offset + _width] = color; - _displayScreen[offset] = color; - // also set pixel below actual pixel - _displayScreen[offset + _displayWidth] = color; - } - if (drawMask & GFX_SCREEN_MASK_PRIORITY) { - _priorityScreen[offset] = priority; - _priorityScreen[offset + _width] = priority; - } - if (drawMask & GFX_SCREEN_MASK_CONTROL) { - _controlScreen[offset] = control; - _controlScreen[offset + _width] = control; - } -} - -// Directly sets a pixel on various screens, display is not upscaled -void GfxScreen::putPixelNormal(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { - int offset = y * _width + x; - - if (drawMask & GFX_SCREEN_MASK_VISUAL) { - _visualScreen[offset] = color; - _displayScreen[offset] = color; - } - if (drawMask & GFX_SCREEN_MASK_PRIORITY) - _priorityScreen[offset] = priority; - if (drawMask & GFX_SCREEN_MASK_CONTROL) - _controlScreen[offset] = control; -} - -// Directly sets a pixel on various screens, display IS upscaled -void GfxScreen::putPixelDisplayUpscaled(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { - int offset = y * _width + x; - - if (drawMask & GFX_SCREEN_MASK_VISUAL) { - _visualScreen[offset] = color; - putScaledPixelOnScreen(_displayScreen, x, y, color); - } - if (drawMask & GFX_SCREEN_MASK_PRIORITY) - _priorityScreen[offset] = priority; - if (drawMask & GFX_SCREEN_MASK_CONTROL) - _controlScreen[offset] = control; -} - -// Directly sets a pixel on various screens, ALL screens ARE upscaled -void GfxScreen::putPixelAllUpscaled(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { - if (drawMask & GFX_SCREEN_MASK_VISUAL) { - putScaledPixelOnScreen(_visualScreen, x, y, color); - putScaledPixelOnScreen(_displayScreen, x, y, color); - } - if (drawMask & GFX_SCREEN_MASK_PRIORITY) - putScaledPixelOnScreen(_priorityScreen, x, y, priority); - if (drawMask & GFX_SCREEN_MASK_CONTROL) - putScaledPixelOnScreen(_controlScreen, x, y, control); -} - -/** - * This is used to put font pixels onto the screen - we adjust differently, so that we won't - * do triple pixel lines in any case on upscaled hires. That way the font will not get distorted - * Sierra SCI didn't do this - */ -void GfxScreen::putFontPixel(int16 startingY, int16 x, int16 y, byte color) { - int16 actualY = startingY + y; - if (_fontIsUpscaled) { - // Do not scale ourselves, but put it on the display directly - putPixelOnDisplay(x, actualY, color); - } else { - int offset = actualY * _width + x; - - _visualScreen[offset] = color; - switch (_upscaledHires) { - case GFX_SCREEN_UPSCALED_DISABLED: - _displayScreen[offset] = color; - break; - case GFX_SCREEN_UPSCALED_640x400: - case GFX_SCREEN_UPSCALED_640x440: - case GFX_SCREEN_UPSCALED_640x480: { - // to 1-> 4 pixels upscaling for all of those, so that fonts won't look weird - int displayOffset = (_upscaledHeightMapping[startingY] + y * 2) * _displayWidth + x * 2; - _displayScreen[displayOffset] = color; - _displayScreen[displayOffset + 1] = color; - displayOffset += _displayWidth; - _displayScreen[displayOffset] = color; - _displayScreen[displayOffset + 1] = color; - break; - } - default: - putScaledPixelOnScreen(_displayScreen, x, actualY, color); - break; - } - } -} - -/** - * This will just change a pixel directly on displayscreen. It is supposed to be - * only used on upscaled-Hires games where hires content needs to get drawn ONTO - * the upscaled display screen (like japanese fonts, hires portraits, etc.). - */ -void GfxScreen::putPixelOnDisplay(int16 x, int16 y, byte color) { - int offset = y * _displayWidth + x; - _displayScreen[offset] = color; -} - -//void GfxScreen::putScaledPixelOnDisplay(int16 x, int16 y, byte color) { -//} - -void GfxScreen::putScaledPixelOnScreen(byte *screen, int16 x, int16 y, byte data) { - int displayOffset = _upscaledHeightMapping[y] * _displayWidth + _upscaledWidthMapping[x]; - int heightOffsetBreak = (_upscaledHeightMapping[y + 1] - _upscaledHeightMapping[y]) * _displayWidth; - int heightOffset = 0; - int widthOffsetBreak = _upscaledWidthMapping[x + 1] - _upscaledWidthMapping[x]; - do { - int widthOffset = 0; - do { - screen[displayOffset + heightOffset + widthOffset] = data; - widthOffset++; - } while (widthOffset != widthOffsetBreak); - heightOffset += _displayWidth; - } while (heightOffset != heightOffsetBreak); -} - /** * Sierra's Bresenham line drawing. * WARNING: Do not replace this with Graphics::drawLine(), as this causes issues @@ -595,16 +476,6 @@ void GfxScreen::putKanjiChar(Graphics::FontSJIS *commonFont, int16 x, int16 y, u commonFont->drawChar(displayPtr, chr, _displayWidth, 1, color, 0, -1, -1); } -byte GfxScreen::getPixelNormal(byte *screen, int16 x, int16 y) { - return screen[y * _width + x]; -} - -byte GfxScreen::getPixelUpscaled(byte *screen, int16 x, int16 y) { - int16 mappedX = _upscaledWidthMapping[x]; - int16 mappedY = _upscaledHeightMapping[y]; - return screen[mappedY * _width + mappedX]; -} - int GfxScreen::bitsGetDataSize(Common::Rect rect, byte mask) { int byteCount = sizeof(rect) + sizeof(mask); int pixels = rect.width() * rect.height(); @@ -615,7 +486,7 @@ int GfxScreen::bitsGetDataSize(Common::Rect rect, byte mask) { } else { int rectHeight = _upscaledHeightMapping[rect.bottom] - _upscaledHeightMapping[rect.top]; int rectWidth = _upscaledWidthMapping[rect.right] - _upscaledWidthMapping[rect.left]; - byteCount += rectHeight * rect.width() * rectWidth; // _displayScreen (upscaled hires) + byteCount += rectHeight * rectWidth; // _displayScreen (upscaled hires) } } if (mask & GFX_SCREEN_MASK_PRIORITY) { @@ -629,7 +500,6 @@ int GfxScreen::bitsGetDataSize(Common::Rect rect, byte mask) { error("bitsGetDataSize() called w/o being in upscaled hires mode"); byteCount += pixels; // _displayScreen (coordinates actually are given to us for hires displayScreen) } - return byteCount; } @@ -796,7 +666,7 @@ void GfxScreen::dither(bool addToFlag) { *displayPtr = color; break; default: - putScaledPixelOnScreen(_displayScreen, x, y, color); + putScaledPixelOnDisplay(x, y, color); break; } *visualPtr = color; @@ -828,7 +698,7 @@ void GfxScreen::dither(bool addToFlag) { *displayPtr = ditheredColor; break; default: - putScaledPixelOnScreen(_displayScreen, x, y, ditheredColor); + putScaledPixelOnDisplay(x, y, ditheredColor); break; } color = ((x^y) & 1) ? color >> 4 : color & 0x0F; diff --git a/engines/sci/graphics/screen.h b/engines/sci/graphics/screen.h index 1c946ef02f..65416252f6 100644 --- a/engines/sci/graphics/screen.h +++ b/engines/sci/graphics/screen.h @@ -76,6 +76,11 @@ public: byte getColorWhite() { return _colorWhite; } byte getColorDefaultVectorData() { return _colorDefaultVectorData; } +#ifdef ENABLE_SCI32 + byte *getDisplayScreen() { return _displayScreen; } + byte *getPriorityScreen() { return _priorityScreen; } +#endif + void clearForRestoreGame(); void copyToScreen(); void copyFromScreen(byte *buffer); @@ -84,51 +89,16 @@ public: void copyDisplayRectToScreen(const Common::Rect &rect); void copyRectToScreen(const Common::Rect &rect, int16 x, int16 y); - // calls to code pointers - void inline vectorAdjustCoordinate (int16 *x, int16 *y) { - (this->*_vectorAdjustCoordinatePtr)(x, y); - } - void inline vectorAdjustLineCoordinates (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) { - (this->*_vectorAdjustLineCoordinatesPtr)(left, top, right, bottom, drawMask, color, priority, control); - } - byte inline vectorIsFillMatch (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA) { - return (this->*_vectorIsFillMatchPtr)(x, y, screenMask, t_color, t_pri, t_con, isEGA); - } - void inline vectorPutPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { - (this->*_vectorPutPixelPtr)(x, y, drawMask, color, priority, control); - } - void inline vectorPutLinePixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { - (this->*_vectorPutLinePixelPtr)(x, y, drawMask, color, priority, control); - } - byte inline vectorGetVisual(int16 x, int16 y) { - return (this->*_vectorGetPixelPtr)(_visualScreen, x, y); - } - byte inline vectorGetPriority(int16 x, int16 y) { - return (this->*_vectorGetPixelPtr)(_priorityScreen, x, y); - } - byte inline vectorGetControl(int16 x, int16 y) { - return (this->*_vectorGetPixelPtr)(_controlScreen, x, y); - } - - - void inline putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { - (this->*_putPixelPtr)(x, y, drawMask, color, priority, control); - } + // Vector drawing +private: + void vectorPutLinePixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + void vectorPutLinePixel480x300(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); - byte inline getVisual(int16 x, int16 y) { - return (this->*_getPixelPtr)(_visualScreen, x, y); - } - byte inline getPriority(int16 x, int16 y) { - return (this->*_getPixelPtr)(_priorityScreen, x, y); - } - byte inline getControl(int16 x, int16 y) { - return (this->*_getPixelPtr)(_controlScreen, x, y); - } +public: + void vectorAdjustLineCoordinates(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control); + byte vectorIsFillMatch(int16 x, int16 y, byte screenMask, byte checkForColor, byte checkForPriority, byte checkForControl, bool isEGA); byte getDrawingMask(byte color, byte prio, byte control); - //void putPixel(int16 x, int16 y, byte drawMask, byte color, byte prio, byte control); - void putFontPixel(int16 startingY, int16 x, int16 y, byte color); - void putPixelOnDisplay(int16 x, int16 y, byte color); void drawLine(Common::Point startPoint, Common::Point endPoint, byte color, byte prio, byte control); void drawLine(int16 left, int16 top, int16 right, int16 bottom, byte color, byte prio, byte control) { drawLine(Common::Point(left, top), Common::Point(right, bottom), color, prio, control); @@ -206,8 +176,8 @@ private: byte *_controlScreen; /** - * This screen is the one that is actually displayed to the user. It may be - * 640x400 for japanese SCI1 games. SCI0 games may be undithered in here. + * This screen is the one, where pixels are copied out of into the frame buffer. + * It may be 640x400 for japanese SCI1 games. SCI0 games may be undithered in here. * Only read from this buffer for Save/ShowBits usage. */ byte *_displayScreen; @@ -215,8 +185,8 @@ private: ResourceManager *_resMan; /** - * Pointer to the currently active screen (changing it only required for - * debug purposes). + * Pointer to the currently active screen (changing only required for + * debug purposes, to show for example the priority screen). */ byte *_activeScreen; @@ -239,38 +209,241 @@ private: */ bool _fontIsUpscaled; - // dynamic code - void (GfxScreen::*_vectorAdjustCoordinatePtr) (int16 *x, int16 *y); - void vectorAdjustCoordinateNOP (int16 *x, int16 *y); - void vectorAdjustCoordinate480x300Mac (int16 *x, int16 *y); - void (GfxScreen::*_vectorAdjustLineCoordinatesPtr) (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control); - void vectorAdjustLineCoordinatesNOP (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control); - void vectorAdjustLineCoordinates480x300Mac (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control); - - byte (GfxScreen::*_vectorIsFillMatchPtr) (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA); - byte vectorIsFillMatchNormal (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA); - byte vectorIsFillMatch480x300Mac (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA); + // pixel related code, in header so that it can be inlined for performance +public: + void putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + if (_upscaledHires == GFX_SCREEN_UPSCALED_480x300) { + putPixel480x300(x, y, drawMask, color, priority, control); + return; + } + + // Set pixel for visual, priority and control map directly, those are not upscaled + int offset = y * _width + x; + + if (drawMask & GFX_SCREEN_MASK_VISUAL) { + _visualScreen[offset] = color; + + int displayOffset = 0; + + switch (_upscaledHires) { + case GFX_SCREEN_UPSCALED_DISABLED: + displayOffset = offset; + _displayScreen[displayOffset] = color; + break; + + case GFX_SCREEN_UPSCALED_640x400: + case GFX_SCREEN_UPSCALED_640x440: + case GFX_SCREEN_UPSCALED_640x480: + putScaledPixelOnDisplay(x, y, color); + break; + default: + break; + } + } + if (drawMask & GFX_SCREEN_MASK_PRIORITY) { + _priorityScreen[offset] = priority; + } + if (drawMask & GFX_SCREEN_MASK_CONTROL) { + _controlScreen[offset] = control; + } + } - void (GfxScreen::*_vectorPutPixelPtr) (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); - void vectorPutPixel480x300Mac (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + void putPixel480x300(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + int offset = ((y * 3) / 2 * _width) + ((x * 3) / 2); + + // All maps are upscaled + // TODO: figure out, what Sierra exactly did on Mac for these games + if (drawMask & GFX_SCREEN_MASK_VISUAL) { + putPixel480x300Worker(x, y, offset, _visualScreen, color); + putPixel480x300Worker(x, y, offset, _displayScreen, color); + } + if (drawMask & GFX_SCREEN_MASK_PRIORITY) { + putPixel480x300Worker(x, y, offset, _priorityScreen, priority); + } + if (drawMask & GFX_SCREEN_MASK_CONTROL) { + putPixel480x300Worker(x, y, offset, _controlScreen, control); + } + } + void putPixel480x300Worker(int16 x, int16 y, int offset, byte *screen, byte byteToSet) { + screen[offset] = byteToSet; + if (x & 1) + screen[offset + 1] = byteToSet; + if (y & 1) + screen[offset + _width] = byteToSet; + if ((x & 1) && (y & 1)) + screen[offset + _width + 1] = byteToSet; + } - void (GfxScreen::*_vectorPutLinePixelPtr) (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); - void vectorPutLinePixel480x300Mac (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + // This is called from vector drawing to put a pixel at a certain location + void vectorPutPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + switch (_upscaledHires) { + case GFX_SCREEN_UPSCALED_640x400: + case GFX_SCREEN_UPSCALED_640x440: + case GFX_SCREEN_UPSCALED_640x480: + // For regular upscaled modes forward to the regular putPixel + putPixel(x, y, drawMask, color, priority, control); + return; + break; + + default: + break; + } + + // For non-upscaled mode and 480x300 Mac put pixels directly + int offset = y * _width + x; + + if (drawMask & GFX_SCREEN_MASK_VISUAL) { + _visualScreen[offset] = color; + _displayScreen[offset] = color; + } + if (drawMask & GFX_SCREEN_MASK_PRIORITY) { + _priorityScreen[offset] = priority; + } + if (drawMask & GFX_SCREEN_MASK_CONTROL) { + _controlScreen[offset] = control; + } + } - byte (GfxScreen::*_vectorGetPixelPtr) (byte *screen, int16 x, int16 y); + /** + * This will just change a pixel directly on displayscreen. It is supposed to be + * only used on upscaled-Hires games where hires content needs to get drawn ONTO + * the upscaled display screen (like japanese fonts, hires portraits, etc.). + */ + void putPixelOnDisplay(int16 x, int16 y, byte color) { + int offset = y * _displayWidth + x; + _displayScreen[offset] = color; + } - void (GfxScreen::*_putPixelPtr) (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); - void putPixelNormal (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); - void putPixelDisplayUpscaled (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); - void putPixelAllUpscaled (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + // Upscales a pixel and puts it on display screen only + void putScaledPixelOnDisplay(int16 x, int16 y, byte color) { + int displayOffset = 0; + + switch (_upscaledHires) { + case GFX_SCREEN_UPSCALED_640x400: + displayOffset = (y * 2) * _displayWidth + x * 2; // straight 1 pixel -> 2 mapping + + _displayScreen[displayOffset] = color; + _displayScreen[displayOffset + 1] = color; + _displayScreen[displayOffset + _displayWidth] = color; + _displayScreen[displayOffset + _displayWidth + 1] = color; + break; + + case GFX_SCREEN_UPSCALED_640x440: { + int16 startY = (y * 11) / 5; + int16 endY = ((y + 1) * 11) / 5; + displayOffset = (startY * _displayWidth) + x * 2; + + for (int16 curY = startY; curY < endY; curY++) { + _displayScreen[displayOffset] = color; + _displayScreen[displayOffset + 1] = color; + displayOffset += _displayWidth; + } + break; + } + case GFX_SCREEN_UPSCALED_640x480: { + int16 startY = (y * 12) / 5; + int16 endY = ((y + 1) * 12) / 5; + displayOffset = (startY * _displayWidth) + x * 2; + + for (int16 curY = startY; curY < endY; curY++) { + _displayScreen[displayOffset] = color; + _displayScreen[displayOffset + 1] = color; + displayOffset += _displayWidth; + } + break; + } + default: + break; + } + } - byte (GfxScreen::*_getPixelPtr) (byte *screen, int16 x, int16 y); - byte getPixelNormal (byte *screen, int16 x, int16 y); - byte getPixelUpscaled (byte *screen, int16 x, int16 y); + /** + * This is used to put font pixels onto the screen - we adjust differently, so that we won't + * do triple pixel lines in any case on upscaled hires. That way the font will not get distorted + * Sierra SCI didn't do this + */ + void putFontPixel(int16 startingY, int16 x, int16 y, byte color) { + int16 actualY = startingY + y; + if (_fontIsUpscaled) { + // Do not scale ourselves, but put it on the display directly + putPixelOnDisplay(x, actualY, color); + } else { + int offset = actualY * _width + x; + + _visualScreen[offset] = color; + switch (_upscaledHires) { + case GFX_SCREEN_UPSCALED_DISABLED: + _displayScreen[offset] = color; + break; + case GFX_SCREEN_UPSCALED_640x400: + case GFX_SCREEN_UPSCALED_640x440: + case GFX_SCREEN_UPSCALED_640x480: { + // to 1-> 4 pixels upscaling for all of those, so that fonts won't look weird + int displayOffset = (_upscaledHeightMapping[startingY] + y * 2) * _displayWidth + x * 2; + _displayScreen[displayOffset] = color; + _displayScreen[displayOffset + 1] = color; + displayOffset += _displayWidth; + _displayScreen[displayOffset] = color; + _displayScreen[displayOffset + 1] = color; + break; + } + default: + putScaledPixelOnDisplay(x, actualY, color); + break; + } + } + } - // pixel helper - void putScaledPixelOnScreen(byte *screen, int16 x, int16 y, byte color); + byte getPixel(byte *screen, int16 x, int16 y) { + switch (_upscaledHires) { + case GFX_SCREEN_UPSCALED_480x300: { + int offset = ((y * 3) / 2) * _width + ((y * 3) / 2); + + return screen[offset]; + break; + } + default: + break; + } + return screen[y * _width + x]; + } + + byte getVisual(int16 x, int16 y) { + return getPixel(_visualScreen, x, y); + } + byte getPriority(int16 x, int16 y) { + return getPixel(_priorityScreen, x, y); + } + byte getControl(int16 x, int16 y) { + return getPixel(_controlScreen, x, y); + } + + // Vector related public code - in here, so that it can be inlined + byte vectorGetPixel(byte *screen, int16 x, int16 y) { + return screen[y * _width + x]; + } + + byte vectorGetVisual(int16 x, int16 y) { + return vectorGetPixel(_visualScreen, x, y); + } + byte vectorGetPriority(int16 x, int16 y) { + return vectorGetPixel(_priorityScreen, x, y); + } + byte vectorGetControl(int16 x, int16 y) { + return vectorGetPixel(_controlScreen, x, y); + } + + void vectorAdjustCoordinate(int16 *x, int16 *y) { + switch (_upscaledHires) { + case GFX_SCREEN_UPSCALED_480x300: + *x = (*x * 3) / 2; + *y = (*y * 3) / 2; + break; + default: + break; + } + } }; } // End of namespace Sci diff --git a/engines/sci/graphics/screen_item32.cpp b/engines/sci/graphics/screen_item32.cpp new file mode 100644 index 0000000000..c3fdbb6845 --- /dev/null +++ b/engines/sci/graphics/screen_item32.cpp @@ -0,0 +1,647 @@ +/* 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 "sci/console.h" +#include "sci/resource.h" +#include "sci/engine/kernel.h" +#include "sci/engine/selector.h" +#include "sci/engine/state.h" +#include "sci/graphics/celobj32.h" +#include "sci/graphics/frameout.h" +#include "sci/graphics/screen_item32.h" +#include "sci/graphics/view.h" + +namespace Sci { +#pragma mark ScreenItem + +uint16 ScreenItem::_nextObjectId = 20000; + +ScreenItem::ScreenItem(const reg_t object) : +_celObj(nullptr), +_object(object), +_pictureId(-1), +_created(g_sci->_gfxFrameout->getScreenCount()), +_updated(0), +_deleted(0), +_mirrorX(false) { + SegManager *segMan = g_sci->getEngineState()->_segMan; + + setFromObject(segMan, object, true, true); + _plane = readSelector(segMan, object, SELECTOR(plane)); +} + +ScreenItem::ScreenItem(const reg_t plane, const CelInfo32 &celInfo) : +_plane(plane), +_useInsetRect(false), +_z(0), +_celInfo(celInfo), +_celObj(nullptr), +_fixPriority(false), +_position(0, 0), +_object(make_reg(0, _nextObjectId++)), +_pictureId(-1), +_created(g_sci->_gfxFrameout->getScreenCount()), +_updated(0), +_deleted(0), +_mirrorX(false) {} + +ScreenItem::ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect) : +_plane(plane), +_useInsetRect(false), +_z(0), +_celInfo(celInfo), +_celObj(nullptr), +_fixPriority(false), +_position(rect.left, rect.top), +_object(make_reg(0, _nextObjectId++)), +_pictureId(-1), +_created(g_sci->_gfxFrameout->getScreenCount()), +_updated(0), +_deleted(0), +_mirrorX(false) { + if (celInfo.type == kCelTypeColor) { + _insetRect = rect; + } +} + +ScreenItem::ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Point &position, const ScaleInfo &scaleInfo) : +_plane(plane), +_scale(scaleInfo), +_useInsetRect(false), +_z(0), +_celInfo(celInfo), +_celObj(nullptr), +_fixPriority(false), +_position(position), +_object(make_reg(0, _nextObjectId++)), +_pictureId(-1), +_created(g_sci->_gfxFrameout->getScreenCount()), +_updated(0), +_deleted(0), +_mirrorX(false) {} + +ScreenItem::ScreenItem(const ScreenItem &other) : +_plane(other._plane), +_scale(other._scale), +_useInsetRect(other._useInsetRect), +_celInfo(other._celInfo), +_celObj(nullptr), +_object(other._object), +_mirrorX(other._mirrorX), +_scaledPosition(other._scaledPosition), +_screenRect(other._screenRect) { + if (other._useInsetRect) { + _insetRect = other._insetRect; + } +} + +void ScreenItem::operator=(const ScreenItem &other) { + // 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; + if (other._useInsetRect) { + _insetRect = other._insetRect; + } + _scale = other._scale; + _scaledPosition = other._scaledPosition; +} + +ScreenItem::~ScreenItem() { + delete _celObj; +} + +void ScreenItem::init() { + _nextObjectId = 20000; +} + +void ScreenItem::setFromObject(SegManager *segMan, const reg_t object, const bool updateCel, const bool updateBitmap) { + _position.x = readSelectorValue(segMan, object, SELECTOR(x)); + _position.y = readSelectorValue(segMan, object, SELECTOR(y)); + _scale.x = readSelectorValue(segMan, object, SELECTOR(scaleX)); + _scale.y = readSelectorValue(segMan, object, SELECTOR(scaleY)); + _scale.max = readSelectorValue(segMan, object, SELECTOR(maxScale)); + _scale.signal = (ScaleSignals32)(readSelectorValue(segMan, object, SELECTOR(scaleSignal)) & 3); + + if (updateCel) { + _celInfo.resourceId = (GuiResourceId)readSelectorValue(segMan, object, SELECTOR(view)); + _celInfo.loopNo = readSelectorValue(segMan, object, SELECTOR(loop)); + _celInfo.celNo = readSelectorValue(segMan, object, SELECTOR(cel)); + + if (_celInfo.resourceId <= kPlanePic) { + // TODO: Enhance GfxView or ResourceManager to allow + // metadata for resources to be retrieved once, from a + // single location + Resource *view = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _celInfo.resourceId), false); + if (!view) { + error("Failed to load resource %d", _celInfo.resourceId); + } + + // NOTE: +2 because the header size field itself is excluded from + // the header size in the data + const uint16 headerSize = READ_SCI11ENDIAN_UINT16(view->data) + 2; + const uint8 loopCount = view->data[2]; + const uint8 loopSize = view->data[12]; + + if (_celInfo.loopNo >= loopCount) { + const int maxLoopNo = loopCount - 1; + _celInfo.loopNo = maxLoopNo; + writeSelectorValue(segMan, object, SELECTOR(loop), maxLoopNo); + } + + byte *loopData = view->data + headerSize + (_celInfo.loopNo * loopSize); + const int8 seekEntry = loopData[0]; + if (seekEntry != -1) { + loopData = view->data + headerSize + (seekEntry * loopSize); + } + const uint8 celCount = loopData[2]; + if (_celInfo.celNo >= celCount) { + const int maxCelNo = celCount - 1; + _celInfo.celNo = maxCelNo; + writeSelectorValue(segMan, object, SELECTOR(cel), maxCelNo); + } + } + } + + if (updateBitmap) { + const reg_t bitmap = readSelector(segMan, object, SELECTOR(bitmap)); + if (!bitmap.isNull()) { + _celInfo.bitmap = bitmap; + _celInfo.type = kCelTypeMem; + } else { + _celInfo.bitmap = NULL_REG; + _celInfo.type = kCelTypeView; + } + } + + if (updateCel || updateBitmap) { + delete _celObj; + _celObj = nullptr; + } + + if (readSelectorValue(segMan, object, SELECTOR(fixPriority))) { + _fixPriority = true; + _priority = readSelectorValue(segMan, object, SELECTOR(priority)); + } else { + _fixPriority = false; + writeSelectorValue(segMan, object, SELECTOR(priority), _position.y); + } + + _z = readSelectorValue(segMan, object, SELECTOR(z)); + _position.y -= _z; + + if (readSelectorValue(segMan, object, SELECTOR(useInsetRect))) { + _useInsetRect = true; + _insetRect.left = readSelectorValue(segMan, object, SELECTOR(inLeft)); + _insetRect.top = readSelectorValue(segMan, object, SELECTOR(inTop)); + _insetRect.right = readSelectorValue(segMan, object, SELECTOR(inRight)) + 1; + _insetRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom)) + 1; + } else { + _useInsetRect = false; + } + + segMan->getObject(object)->clearInfoSelectorFlag(kInfoFlagViewVisible); +} + +void ScreenItem::calcRects(const Plane &plane) { + const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth; + const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight; + + const CelObj &celObj = getCelObj(); + + Common::Rect celRect(celObj._width, celObj._height); + if (_useInsetRect) { + if (_insetRect.intersects(celRect)) { + _insetRect.clip(celRect); + } else { + _insetRect = Common::Rect(); + } + } else { + _insetRect = celRect; + } + + Ratio scaleX, scaleY; + + if (_scale.signal & kScaleSignalDoScaling32) { + if (_scale.signal & kScaleSignalUseVanishingPoint) { + int num = _scale.max * (_position.y - plane._vanishingPoint.y) / (scriptWidth - plane._vanishingPoint.y); + scaleX = Ratio(num, 128); + scaleY = Ratio(num, 128); + } else { + scaleX = Ratio(_scale.x, 128); + scaleY = Ratio(_scale.y, 128); + } + } + + 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) { + const Ratio scriptToCelX(celObj._scaledWidth, scriptWidth); + const Ratio scriptToCelY(celObj._scaledHeight, scriptHeight); + mulru(_screenItemRect, scriptToCelX, scriptToCelY, 0); + + if (_screenItemRect.intersects(celRect)) { + _screenItemRect.clip(celRect); + } else { + _screenItemRect = Common::Rect(); + } + } + + int displaceX = celObj._displace.x; + int displaceY = celObj._displace.y; + + if (_mirrorX != celObj._mirrorX && _celInfo.type != kCelTypePic) { + displaceX = celObj._width - celObj._displace.x - 1; + } + + if (!scaleX.isOne() || !scaleY.isOne()) { + mulinc(_screenItemRect, scaleX, scaleY); + displaceX = (displaceX * scaleX).toInt(); + displaceY = (displaceY * scaleY).toInt(); + } + + mulinc(_screenItemRect, celToScreenX, celToScreenY); + displaceX = (displaceX * celToScreenX).toInt(); + displaceY = (displaceY * celToScreenY).toInt(); + + 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 * scriptToScreenX).toInt() - displaceX; + _scaledPosition.y = (_position.y * scriptToScreenY).toInt() - displaceY; + } + + _screenItemRect.translate(_scaledPosition.x, _scaledPosition.y); + + if (_mirrorX != celObj._mirrorX && _celInfo.type == kCelTypePic) { + Common::Rect temp(_insetRect); + + if (!scaleX.isOne()) { + mulinc(temp, scaleX, Ratio()); + } + + mulinc(temp, celToScreenX, Ratio()); + + CelObjPic *celObjPic = dynamic_cast<CelObjPic *>(_celObj); + temp.translate((celObjPic->_relativePosition.x * scriptToScreenX).toInt() - displaceX, 0); + + // TODO: This is weird. + int deltaX = plane._planeRect.width() - temp.right - 1 - temp.left; + + _scaledPosition.x += deltaX; + _screenItemRect.translate(deltaX, 0); + } + + _scaledPosition.x += plane._planeRect.left; + _scaledPosition.y += plane._planeRect.top; + _screenItemRect.translate(plane._planeRect.left, plane._planeRect.top); + + _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 (!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 + _screenItemRect.right -= 1; + _screenItemRect.bottom -= 1; + } + + _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 (!scaleX.isOne()) { + mulinc(temp, scaleX, Ratio()); + temp.right -= 1; + } + + CelObjPic *celObjPic = dynamic_cast<CelObjPic *>(_celObj); + 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; + + _scaledPosition.x += deltaX; + _screenItemRect.translate(deltaX, 0); + } + + _scaledPosition.x += plane._gameRect.left; + _scaledPosition.y += plane._gameRect.top; + _screenItemRect.translate(plane._gameRect.left, plane._gameRect.top); + + if (celObj._scaledWidth != screenWidth || celObj._scaledHeight != screenHeight) { + mulru(_scaledPosition, celToScreenX, celToScreenY); + mulru(_screenItemRect, celToScreenX, celToScreenY, 1); + } + + _ratioX = scaleX * celToScreenX; + _ratioY = scaleY * celToScreenY; + } + + _screenRect = _screenItemRect; + + if (_screenRect.intersects(plane._screenRect)) { + _screenRect.clip(plane._screenRect); + } else { + _screenRect.right = 0; + _screenRect.bottom = 0; + _screenRect.left = 0; + _screenRect.top = 0; + } + + if (!_fixPriority) { + _priority = _z + _position.y; + } + } else { + _screenRect.left = 0; + _screenRect.top = 0; + _screenRect.right = 0; + _screenRect.bottom = 0; + } +} + +CelObj &ScreenItem::getCelObj() const { + if (_celObj == nullptr) { + switch (_celInfo.type) { + case kCelTypeView: + _celObj = new CelObjView(_celInfo.resourceId, _celInfo.loopNo, _celInfo.celNo); + break; + case kCelTypePic: + error("Internal error, pic screen item with no cel."); + break; + case kCelTypeMem: + _celObj = new CelObjMem(_celInfo.bitmap); + break; + case kCelTypeColor: + _celObj = new CelObjColor(_celInfo.color, _insetRect.width(), _insetRect.height()); + break; + } + } + + return *_celObj; +} + +void ScreenItem::printDebugInfo(Console *con) const { + con->debugPrintf("%04x:%04x (%s), prio %d, x %d, y %d, z: %d, scaledX: %d, scaledY: %d flags: %d\n", + _object.getSegment(), _object.getOffset(), + g_sci->getEngineState()->_segMan->getObjectName(_object), + _priority, + _position.x, + _position.y, + _z, + _scaledPosition.x, + _scaledPosition.y, + _created | (_updated << 1) | (_deleted << 2) + ); + con->debugPrintf(" screen rect (%d, %d, %d, %d)\n", PRINT_RECT(_screenRect)); + if (_useInsetRect) { + con->debugPrintf(" inset rect: (%d, %d, %d, %d)\n", PRINT_RECT(_insetRect)); + } + + Common::String celType; + switch (_celInfo.type) { + case kCelTypePic: + celType = "pic"; + break; + case kCelTypeView: + celType = "view"; + break; + case kCelTypeColor: + celType = "color"; + break; + case kCelTypeMem: + celType = "mem"; + break; + } + + con->debugPrintf(" type: %s, res %d, loop %d, cel %d, bitmap %04x:%04x, color: %d\n", + celType.c_str(), + _celInfo.resourceId, + _celInfo.loopNo, + _celInfo.celNo, + PRINT_REG(_celInfo.bitmap), + _celInfo.color + ); + if (_celObj != nullptr) { + con->debugPrintf(" width %d, height %d, scaledWidth %d, scaledHeight %d\n", + _celObj->_width, + _celObj->_height, + _celObj->_scaledWidth, + _celObj->_scaledHeight + ); + } +} + +void ScreenItem::update(const reg_t object) { + SegManager *segMan = g_sci->getEngineState()->_segMan; + + const GuiResourceId view = readSelectorValue(segMan, object, SELECTOR(view)); + const int16 loopNo = readSelectorValue(segMan, object, SELECTOR(loop)); + const int16 celNo = readSelectorValue(segMan, object, SELECTOR(cel)); + + const bool updateCel = ( + _celInfo.resourceId != view || + _celInfo.loopNo != loopNo || + _celInfo.celNo != celNo + ); + + const bool updateBitmap = !readSelector(segMan, object, SELECTOR(bitmap)).isNull(); + + setFromObject(segMan, object, updateCel, updateBitmap); + + if (!_created) { + _updated = g_sci->_gfxFrameout->getScreenCount(); + } + + _deleted = 0; +} + +// TODO: This code is quite similar to calcRects, so try to deduplicate +// if possible +Common::Rect ScreenItem::getNowSeenRect(const Plane &plane) const { + CelObj &celObj = getCelObj(); + + Common::Rect celObjRect(celObj._width, celObj._height); + Common::Rect nsRect; + + if (_useInsetRect) { + // TODO: This is weird. Checking to see if the inset rect is + // fully inside the bounds of the celObjRect, and then + // clipping to the celObjRect, is pretty useless. + if (_insetRect.right > 0 && _insetRect.bottom > 0 && _insetRect.left < celObj._width && _insetRect.top < celObj._height) { + nsRect = _insetRect; + nsRect.clip(celObjRect); + } else { + nsRect = Common::Rect(); + } + } else { + nsRect = celObjRect; + } + + const uint16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + const uint16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + + Ratio scaleX, scaleY; + if (_scale.signal & kScaleSignalDoScaling32) { + if (_scale.signal & kScaleSignalUseVanishingPoint) { + int num = _scale.max * (_position.y - plane._vanishingPoint.y) / (scriptWidth - plane._vanishingPoint.y); + scaleX = Ratio(num, 128); + scaleY = Ratio(num, 128); + } else { + scaleX = Ratio(_scale.x, 128); + scaleY = Ratio(_scale.y, 128); + } + } + + if (scaleX.getNumerator() == 0 || scaleY.getNumerator() == 0) { + return Common::Rect(); + } + + int16 displaceX = celObj._displace.x; + int16 displaceY = celObj._displace.y; + + if (_mirrorX != celObj._mirrorX && _celInfo.type != kCelTypePic) { + displaceX = celObj._width - displaceX - 1; + } + + if (celObj._scaledWidth != scriptWidth || celObj._scaledHeight != scriptHeight) { + if (_useInsetRect) { + 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 + // clipping to the celObjRect, is pretty useless. + if (nsRect.right > 0 && nsRect.bottom > 0 && nsRect.left < celObj._width && nsRect.top < celObj._height) { + nsRect.clip(celObjRect); + } else { + nsRect = Common::Rect(); + } + } + + if (!scaleX.isOne() || !scaleY.isOne()) { + mulinc(nsRect, 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 + nsRect.right -= 1; + nsRect.bottom -= 1; + } + + Ratio celToScriptX(scriptWidth, celObj._scaledWidth); + Ratio celToScriptY(scriptHeight, celObj._scaledHeight); + + displaceX = (displaceX * scaleX * celToScriptX).toInt(); + displaceY = (displaceY * scaleY * celToScriptY).toInt(); + + mulinc(nsRect, celToScriptX, celToScriptY); + nsRect.translate(_position.x - displaceX, _position.y - displaceY); + } else { + if (!scaleX.isOne() || !scaleY.isOne()) { + mulinc(nsRect, 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 + nsRect.right -= 1; + nsRect.bottom -= 1; + } + + displaceX = (displaceX * scaleX).toInt(); + displaceY = (displaceY * scaleY).toInt(); + nsRect.translate(_position.x - displaceX, _position.y - displaceY); + + if (_mirrorX != celObj._mirrorX && _celInfo.type != kCelTypePic) { + nsRect.translate(plane._gameRect.width() - nsRect.width(), 0); + } + } + + return nsRect; +} + +#pragma mark - +#pragma mark ScreenItemList +ScreenItem *ScreenItemList::findByObject(const reg_t object) const { + const_iterator screenItemIt = Common::find_if(begin(), end(), FindByObject<ScreenItem *>(object)); + + if (screenItemIt == end()) { + return nullptr; + } + + return *screenItemIt; +} +void ScreenItemList::sort() { + // TODO: SCI engine used _unsorted as an array of indexes into the + // list itself and then performed the same swap operations on the + // _unsorted array as the _storage array during sorting, but the + // only reason to do this would be if some of the pointers in the + // list were replaced so the pointer values themselves couldn’t + // simply be recorded and then restored later. It is not yet + // verified whether this simplification of the sort/unsort is + // safe. + for (size_type i = 0; i < size(); ++i) { + _unsorted[i] = (*this)[i]; + } + + Common::sort(begin(), end(), sortHelper); +} +void ScreenItemList::unsort() { + for (size_type i = 0; i < size(); ++i) { + (*this)[i] = _unsorted[i]; + } +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/screen_item32.h b/engines/sci/graphics/screen_item32.h new file mode 100644 index 0000000000..977d80ebad --- /dev/null +++ b/engines/sci/graphics/screen_item32.h @@ -0,0 +1,288 @@ +/* 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 SCI_GRAPHICS_SCREEN_ITEM32_H +#define SCI_GRAPHICS_SCREEN_ITEM32_H + +#include "common/rect.h" +#include "sci/graphics/celobj32.h" +#include "sci/graphics/lists32.h" + +namespace Sci { + +enum ScaleSignals32 { + kScaleSignalNone = 0, + kScaleSignalDoScaling32 = 1, // enables scaling when drawing that cel (involves scaleX and scaleY) + kScaleSignalUseVanishingPoint = 2, + // TODO: Is this actually a thing? I have not seen it and + // the original engine masks &3 where it uses scale signals. + kScaleSignalDisableGlobalScaling32 = 4 +}; + +struct ScaleInfo { + int x, y, max; + ScaleSignals32 signal; + ScaleInfo() : x(128), y(128), max(100), signal(kScaleSignalNone) {} +}; + +class CelObj; +class Plane; +class SegManager; + +#pragma mark - +#pragma mark ScreenItem + +/** + * A ScreenItem is the engine-side representation of a + * game script View. + */ +class ScreenItem { +private: + /** + * A serial used for screen items that are generated + * inside the graphics engine, rather than the + * interpreter. + */ + static uint16 _nextObjectId; + + /** + * The parent plane of this screen item. + */ + reg_t _plane; + +public: + /** + * Scaling data used to calculate the final screen + * dimensions of the screen item as well as the scaling + * ratios used when drawing the item to screen. + */ + ScaleInfo _scale; + +private: + /** + * The position & dimensions of the screen item in + * screen coordinates. This rect includes the offset + * of the parent plane, but is not clipped to the + * screen, so may include coordinates that are + * offscreen. + */ + Common::Rect _screenItemRect; + + /** + * TODO: Document + */ + bool _useInsetRect; + + /** + * TODO: Documentation + * The insetRect is also used to describe the fill + * rectangle of a screen item that is drawn using + * CelObjColor. + */ + Common::Rect _insetRect; + + /** + * The z-index of the screen item in pseudo-3D space. + * Higher values are drawn on top of lower values. + */ + int _z; + + /** + * Sets the common properties of a screen item that must + * be set both during creation and update of a screen + * item. + */ + void setFromObject(SegManager *segMan, const reg_t object, const bool updateCel, const bool updateBitmap); + +public: + /** + * A descriptor for the cel object represented by the + * screen item. + */ + CelInfo32 _celInfo; + + /** + * The cel object used to actually render the screen + * item. This member is populated by calling + * `getCelObj`. + */ + mutable CelObj *_celObj; + + /** + * If set, the priority for this screen item is fixed + * in place. Otherwise, the priority of the screen item + * is calculated from its y-position + z-index. + */ + bool _fixPriority; + + /** + * The rendering priority of the screen item, relative + * only to the other screen items within the same plane. + * Higher priorities are drawn above lower priorities. + */ + int16 _priority; + + /** + * The top-left corner of the screen item, in game + * script coordinates, relative to the parent plane. + */ + Common::Point _position; + + /** + * The associated View script object that was + * used to create the ScreenItem, or a numeric + * value in the case of a ScreenItem that was + * generated outside of the VM. + */ + reg_t _object; + + /** + * For screen items representing picture resources, + * the resource ID of the picture. + */ + GuiResourceId _pictureId; + + /** + * Flags indicating the state of the screen item. + * - `created` is set when the screen item is first + * created, either from a VM object or from within the + * engine itself + * - `updated` is set when `created` is not already set + * and the screen item is updated from a VM object + * - `deleted` is set by the parent plane, if the parent + * plane is a pic type and its picture resource ID has + * changed + */ + int _created, _updated, _deleted; // ? + + /** + * For screen items that represent picture cels, this + * value is set to match the `_mirrorX` property of the + * parent plane and indicates that the cel should be + * drawn horizontally mirrored. For final drawing, it is + * XORed with the `_mirrorX` property of the cel object. + * The cel object's `_mirrorX` property comes from the + * resource data itself. + */ + bool _mirrorX; + + /** + * The scaling ratios to use when drawing this screen + * item. These values are calculated according to the + * scale info whenever the screen item is updated. + */ + Ratio _ratioX, _ratioY; + + /** + * The top-left corner of the screen item, in screen + * coordinates. + */ + Common::Point _scaledPosition; + + /** + * The position & dimensions of the screen item in + * screen coordinates. This rect includes the offset of + * the parent plane and is clipped to the screen. + */ + Common::Rect _screenRect; + + /** + * Initialises static Plane members. + */ + static void init(); + + ScreenItem(const reg_t screenItem); + ScreenItem(const reg_t plane, const CelInfo32 &celInfo); + ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect); + ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Point &position, const ScaleInfo &scaleInfo); + ScreenItem(const ScreenItem &other); + ~ScreenItem(); + void operator=(const ScreenItem &); + + inline bool operator<(const ScreenItem &other) const { + if (_priority < other._priority) { + return true; + } + + if (_priority == other._priority) { + if (_position.y + _z < other._position.y + other._z) { + return true; + } + + if (_position.y + _z == other._position.y + other._z) { + return _object < other._object; + } + } + + return false; + } + + /** + * Calculates the dimensions and scaling parameters for + * the screen item, using the given plane as the parent + * plane for screen rect positioning. + * + * @note This method was called Update in SCI engine. + */ + void calcRects(const Plane &plane); + + /** + * Retrieves the corresponding cel object for this + * screen item. If a cel object does not already exist, + * one will be created and assigned. + */ + CelObj &getCelObj() const; + + void printDebugInfo(Console *con) const; + + /** + * Updates the properties of the screen item from a + * VM object. + */ + void update(const reg_t object); + + /** + * Gets the "now seen" rect for the screen item, which + * represents the current size and position of the + * screen item on the screen in script coordinates. + */ + Common::Rect getNowSeenRect(const Plane &plane) const; +}; + +#pragma mark - +#pragma mark ScreenItemList + +typedef StablePointerArray<ScreenItem, 250> ScreenItemListBase; +class ScreenItemList : public ScreenItemListBase { + static bool inline sortHelper(const ScreenItem *a, const ScreenItem *b) { + return *a < *b; + } +public: + ScreenItem *_unsorted[250]; + + ScreenItem *findByObject(const reg_t object) const; + void sort(); + void unsort(); +}; +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp index 56ce73e8fa..99ffc6e328 100644 --- a/engines/sci/graphics/text32.cpp +++ b/engines/sci/graphics/text32.cpp @@ -29,363 +29,629 @@ #include "sci/engine/selector.h" #include "sci/engine/state.h" #include "sci/graphics/cache.h" +#include "sci/graphics/celobj32.h" #include "sci/graphics/compare.h" #include "sci/graphics/font.h" +#include "sci/graphics/frameout.h" #include "sci/graphics/screen.h" #include "sci/graphics/text32.h" namespace Sci { -#define BITMAP_HEADER_SIZE 46 +int16 GfxText32::_defaultFontId = 0; + +GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts) : + _segMan(segMan), + _cache(fonts), + _scaledWidth(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth), + _scaledHeight(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight), + // Not a typo, the original engine did not initialise height, only width + _width(0), + _text(""), + _field_20(0), + _field_2C(2), + _field_30(0), + _field_34(0), + _field_38(0), + _field_3C(0), + _bitmap(NULL_REG) { + _fontId = _defaultFontId; + _font = _cache->getFont(_defaultFontId); + } -#define SCI_TEXT32_ALIGNMENT_RIGHT -1 -#define SCI_TEXT32_ALIGNMENT_CENTER 1 -#define SCI_TEXT32_ALIGNMENT_LEFT 0 +reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, const bool dimmed, const bool doScaling) { -GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen) - : _segMan(segMan), _cache(fonts), _screen(screen) { -} + _field_22 = 0; + _borderColor = borderColor; + _text = text; + _textRect = rect; + _width = width; + _height = height; + _foreColor = foreColor; + _backColor = backColor; + _skipColor = skipColor; + _alignment = alignment; + _dimmed = dimmed; -GfxText32::~GfxText32() { -} + setFont(fontId); -reg_t GfxText32::createScrollTextBitmap(Common::String text, reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) { - return createTextBitmapInternal(text, textObject, maxWidth, maxHeight, prevHunk); + if (doScaling) { + int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; -} -reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) { - reg_t stringObject = readSelector(_segMan, textObject, SELECTOR(text)); - // The object in the text selector of the item can be either a raw string - // or a Str object. In the latter case, we need to access the object's data - // selector to get the raw string. - if (_segMan->isHeapObject(stringObject)) - stringObject = readSelector(_segMan, stringObject, SELECTOR(data)); + Ratio scaleX(_scaledWidth, scriptWidth); + Ratio scaleY(_scaledHeight, scriptHeight); - Common::String text = _segMan->getString(stringObject); + _width = (_width * scaleX).toInt(); + _height = (_height * scaleY).toInt(); + mulinc(_textRect, scaleX, scaleY); + } - return createTextBitmapInternal(text, textObject, maxWidth, maxHeight, prevHunk); -} + // _textRect represents where text is drawn inside the + // bitmap; clipRect is the entire bitmap + Common::Rect bitmapRect(_width, _height); -reg_t GfxText32::createTextBitmapInternal(Common::String &text, reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) { - // HACK: The character offsets of the up and down arrow buttons are off by one - // in GK1, for some unknown reason. Fix them here. - if (text.size() == 1 && (text[0] == 29 || text[0] == 30)) { - text.setChar(text[0] + 1, 0); - } - GuiResourceId fontId = readSelectorValue(_segMan, textObject, SELECTOR(font)); - GfxFont *font = _cache->getFont(fontId); - bool dimmed = readSelectorValue(_segMan, textObject, SELECTOR(dimmed)); - int16 alignment = readSelectorValue(_segMan, textObject, SELECTOR(mode)); - uint16 foreColor = readSelectorValue(_segMan, textObject, SELECTOR(fore)); - uint16 backColor = readSelectorValue(_segMan, textObject, SELECTOR(back)); - - Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(textObject); - uint16 width = nsRect.width() + 1; - uint16 height = nsRect.height() + 1; - - // Limit rectangle dimensions, if requested - if (maxWidth > 0) - width = maxWidth; - if (maxHeight > 0) - height = maxHeight; - - // Upscale the coordinates/width if the fonts are already upscaled - if (_screen->fontIsUpscaled()) { - width = width * _screen->getDisplayWidth() / _screen->getWidth(); - height = height * _screen->getDisplayHeight() / _screen->getHeight(); + if (_textRect.intersects(bitmapRect)) { + _textRect.clip(bitmapRect); + } else { + _textRect = Common::Rect(); } - int entrySize = width * height + BITMAP_HEADER_SIZE; - reg_t memoryId = NULL_REG; - if (prevHunk.isNull()) { - memoryId = _segMan->allocateHunkEntry("TextBitmap()", entrySize); + BitmapResource bitmap(_segMan, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false); + _bitmap = bitmap.getObject(); - // Scroll text objects have no bitmap selector! - ObjVarRef varp; - if (lookupSelector(_segMan, textObject, SELECTOR(bitmap), &varp, NULL) == kSelectorVariable) - writeSelector(_segMan, textObject, SELECTOR(bitmap), memoryId); - } else { - memoryId = prevHunk; + erase(bitmapRect, false); + + if (_borderColor > -1) { + drawFrame(bitmapRect, 1, _borderColor, false); } - byte *memoryPtr = _segMan->getHunkPointer(memoryId); - if (prevHunk.isNull()) - memset(memoryPtr, 0, BITMAP_HEADER_SIZE); + drawTextBox(); + return _bitmap; +} - byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; - memset(bitmap, backColor, width * height); +reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed) { + _field_22 = 0; + _borderColor = borderColor; + _text = text; + _textRect = rect; + _foreColor = foreColor; + _dimmed = dimmed; - // Save totalWidth, totalHeight - WRITE_LE_UINT16(memoryPtr, width); - WRITE_LE_UINT16(memoryPtr + 2, height); + setFont(fontId); - int16 charCount = 0; - uint16 curX = 0, curY = 0; - const char *txt = text.c_str(); - int16 textWidth, textHeight, totalHeight = 0, offsetX = 0, offsetY = 0; - uint16 start = 0; + int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; - // Calculate total text height - while (*txt) { - charCount = GetLongest(txt, width, font); - if (charCount == 0) - break; + int borderSize = 1; + mulinc(_textRect, Ratio(_scaledWidth, scriptWidth), Ratio(_scaledHeight, scriptHeight)); - Width(txt, 0, (int16)strlen(txt), fontId, textWidth, textHeight, true); + CelObjView view(celInfo.resourceId, celInfo.loopNo, celInfo.celNo); + _skipColor = view._transparentColor; + _width = view._width * _scaledWidth / view._scaledWidth; + _height = view._height * _scaledHeight / view._scaledHeight; - totalHeight += textHeight; - txt += charCount; - while (*txt == ' ') - txt++; // skip over breaking spaces + Common::Rect bitmapRect(_width, _height); + if (_textRect.intersects(bitmapRect)) { + _textRect.clip(bitmapRect); + } else { + _textRect = Common::Rect(); } - txt = text.c_str(); - - // Draw text in buffer - while (*txt) { - charCount = GetLongest(txt, width, font); - if (charCount == 0) - break; - Width(txt, start, charCount, fontId, textWidth, textHeight, true); - - switch (alignment) { - case SCI_TEXT32_ALIGNMENT_RIGHT: - offsetX = width - textWidth; - break; - case SCI_TEXT32_ALIGNMENT_CENTER: - // Center text both horizontally and vertically - offsetX = (width - textWidth) / 2; - offsetY = (height - totalHeight) / 2; - break; - case SCI_TEXT32_ALIGNMENT_LEFT: - offsetX = 0; - break; - - default: - warning("Invalid alignment %d used in TextBox()", alignment); - } + BitmapResource bitmap(_segMan, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false); + _bitmap = bitmap.getObject(); + Buffer buffer(_width, _height, bitmap.getPixels()); + + // NOTE: The engine filled the bitmap pixels with 11 here, which is silly + // because then it just erased the bitmap using the skip color. So we don't + // fill the bitmap redundantly here. - byte curChar; - - for (int i = 0; i < charCount; i++) { - curChar = txt[i]; - - switch (curChar) { - case 0x0A: - case 0x0D: - case 0: - break; - case 0x7C: - warning("Code processing isn't implemented in SCI32"); - break; - default: - font->drawToBuffer(curChar, curY + offsetY, curX + offsetX, foreColor, dimmed, bitmap, width, height); - curX += font->getCharWidth(curChar); - break; + _backColor = _skipColor; + erase(bitmapRect, false); + _backColor = backColor; + + view.draw(buffer, bitmapRect, Common::Point(0, 0), false, Ratio(_scaledWidth, view._scaledWidth), Ratio(_scaledHeight, view._scaledHeight)); + + if (_backColor != skipColor && _foreColor != skipColor) { + erase(_textRect, false); + } + + if (text.size() > 0) { + if (_foreColor == skipColor) { + error("TODO: Implement transparent text"); + } else { + if (borderColor != -1) { + drawFrame(bitmapRect, borderSize, _borderColor, false); } - } - curX = 0; - curY += font->getHeight(); - txt += charCount; - while (*txt == ' ') - txt++; // skip over breaking spaces + drawTextBox(); + } } - return memoryId; + return _bitmap; } -void GfxText32::disposeTextBitmap(reg_t hunkId) { - _segMan->freeHunkEntry(hunkId); +reg_t GfxText32::createTitledBitmap(const int16 width, const int16 height, const Common::Rect &textRect, const Common::String &text, const int16 foreColor, const int16 backColor, const int16 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, Common::String &title, const int16 titleForeColor, const int16 titleBackColor, const GuiResourceId titleFontId, const bool doScaling) { + warning("TODO: createTitledBitmap incomplete !"); + return createFontBitmap(width, height, textRect, text, foreColor, backColor, skipColor, fontId, alignment, borderColor, false, doScaling); } -void GfxText32::drawTextBitmap(int16 x, int16 y, Common::Rect planeRect, reg_t textObject) { - reg_t hunkId = readSelector(_segMan, textObject, SELECTOR(bitmap)); - drawTextBitmapInternal(x, y, planeRect, textObject, hunkId); +void GfxText32::setFont(const GuiResourceId fontId) { + // NOTE: In SCI engine this calls FontMgr::BuildFontTable and then a font + // table is built on the FontMgr directly; instead, because we already have + // font resources, this code just grabs a font out of GfxCache. + if (fontId != _fontId) { + _fontId = fontId == -1 ? _defaultFontId : fontId; + _font = _cache->getFont(_fontId); + } } -void GfxText32::drawScrollTextBitmap(reg_t textObject, reg_t hunkId, uint16 x, uint16 y) { - /*reg_t plane = readSelector(_segMan, textObject, SELECTOR(plane)); - Common::Rect planeRect; - planeRect.top = readSelectorValue(_segMan, plane, SELECTOR(top)); - planeRect.left = readSelectorValue(_segMan, plane, SELECTOR(left)); - planeRect.bottom = readSelectorValue(_segMan, plane, SELECTOR(bottom)); - planeRect.right = readSelectorValue(_segMan, plane, SELECTOR(right)); +void GfxText32::drawFrame(const Common::Rect &rect, const int16 size, const uint8 color, const bool doScaling) { + Common::Rect targetRect = doScaling ? scaleRect(rect) : rect; - drawTextBitmapInternal(x, y, planeRect, textObject, hunkId);*/ + byte *bitmap = _segMan->getHunkPointer(_bitmap); + byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28) + rect.top * _width + rect.left; - // HACK: we pretty much ignore the plane rect and x, y... - drawTextBitmapInternal(0, 0, Common::Rect(20, 390, 600, 460), textObject, hunkId); + // NOTE: Not fully disassembled, but this should be right + int16 rectWidth = targetRect.width(); + int16 sidesHeight = targetRect.height() - size * 2; + int16 centerWidth = rectWidth - size * 2; + int16 stride = _width - rectWidth; + + for (int16 y = 0; y < size; ++y) { + memset(pixels, color, rectWidth); + pixels += _width; + } + for (int16 y = 0; y < sidesHeight; ++y) { + for (int16 x = 0; x < size; ++x) { + *pixels++ = color; + } + pixels += centerWidth; + for (int16 x = 0; x < size; ++x) { + *pixels++ = color; + } + pixels += stride; + } + for (int16 y = 0; y < size; ++y) { + memset(pixels, color, rectWidth); + pixels += _width; + } } -void GfxText32::drawTextBitmapInternal(int16 x, int16 y, Common::Rect planeRect, reg_t textObject, reg_t hunkId) { - int16 backColor = (int16)readSelectorValue(_segMan, textObject, SELECTOR(back)); - // Sanity check: Check if the hunk is set. If not, either the game scripts - // didn't set it, or an old saved game has been loaded, where it wasn't set. - if (hunkId.isNull()) - return; +void GfxText32::drawChar(const char charIndex) { + byte *bitmap = _segMan->getHunkPointer(_bitmap); + byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28); - // Negative coordinates indicate that text shouldn't be displayed - if (x < 0 || y < 0) - return; + _font->drawToBuffer(charIndex, _drawPosition.y, _drawPosition.x, _foreColor, _dimmed, pixels, _width, _height); + _drawPosition.x += _font->getCharWidth(charIndex); +} - byte *memoryPtr = _segMan->getHunkPointer(hunkId); +uint16 GfxText32::getCharWidth(const char charIndex, const bool doScaling) const { + uint16 width = _font->getCharWidth(charIndex); + if (doScaling) { + width = scaleUpWidth(width); + } + return width; +} - if (!memoryPtr) { - // Happens when restoring in some SCI32 games (e.g. SQ6). - // Commented out to reduce console spam - //warning("Attempt to draw an invalid text bitmap"); +void GfxText32::drawTextBox() { + if (_text.size() == 0) { return; } - byte *surface = memoryPtr + BITMAP_HEADER_SIZE; + const char *text = _text.c_str(); + const char *sourceText = text; + int16 textRectWidth = _textRect.width(); + _drawPosition.y = _textRect.top; + uint charIndex = 0; + if (getLongest(&charIndex, textRectWidth) == 0) { + error("DrawTextBox GetLongest=0"); + } + + charIndex = 0; + uint nextCharIndex = 0; + while (*text != '\0') { + _drawPosition.x = _textRect.left; + + uint length = getLongest(&nextCharIndex, textRectWidth); + int16 textWidth = getTextWidth(charIndex, length); + + if (_alignment == kTextAlignCenter) { + _drawPosition.x += (textRectWidth - textWidth) / 2; + } else if (_alignment == kTextAlignRight) { + _drawPosition.x += textRectWidth - textWidth; + } + + drawText(charIndex, length); + charIndex = nextCharIndex; + text = sourceText + charIndex; + _drawPosition.y += _font->getHeight(); + } +} + +void GfxText32::drawTextBox(const Common::String &text) { + _text = text; + drawTextBox(); +} + +void GfxText32::drawText(const uint index, uint length) { + assert(index + length <= _text.size()); + + // NOTE: This draw loop implementation is somewhat different than the + // implementation in the actual engine, but should be accurate. Primarily + // the changes revolve around eliminating some extra temporaries and + // fixing the logic to match. + const char *text = _text.c_str() + index; + while (length-- > 0) { + char currentChar = *text++; + + if (currentChar == '|') { + const char controlChar = *text++; + --length; + + if (length == 0) { + return; + } + + if (controlChar == 'a' || controlChar == 'c' || controlChar == 'f') { + uint16 value = 0; + + while (length > 0) { + const char valueChar = *text; + if (valueChar < '0' || valueChar > '9') { + break; + } + + ++text; + --length; + value = 10 * value + (valueChar - '0'); + } + + if (length == 0) { + return; + } + + if (controlChar == 'a') { + _alignment = (TextAlign)value; + } else if (controlChar == 'c') { + _foreColor = value; + } else if (controlChar == 'f') { + setFont(value); + } + } + + while (length > 0 && *text != '|') { + ++text; + --length; + } + } else { + drawChar(currentChar); + } + } +} + +void GfxText32::invertRect(const reg_t bitmap, int16 bitmapStride, const Common::Rect &rect, const uint8 foreColor, const uint8 backColor, const bool doScaling) { + Common::Rect targetRect = rect; + if (doScaling) { + bitmapStride = bitmapStride * _scaledWidth / g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + targetRect = scaleRect(rect); + } + + byte *bitmapData = _segMan->getHunkPointer(bitmap); - int curByte = 0; - int16 skipColor = (int16)readSelectorValue(_segMan, textObject, SELECTOR(skip)); - uint16 textX = planeRect.left + x; - uint16 textY = planeRect.top + y; - // Get totalWidth, totalHeight - uint16 width = READ_LE_UINT16(memoryPtr); - uint16 height = READ_LE_UINT16(memoryPtr + 2); + // NOTE: SCI code is super weird here; it seems to be trying to look at the + // entire size of the bitmap including the header, instead of just the pixel + // data size. We just look at the pixel size. This function generally is an + // odd duck since the stride dimension for a bitmap is built in to the bitmap + // header, so perhaps it was once an unheadered bitmap format and this + // function was never updated to match? Or maybe they exploit the + // configurable stride length somewhere else to do stair stepping inverts... + uint32 invertSize = targetRect.height() * bitmapStride + targetRect.width(); + uint32 bitmapSize = READ_SCI11ENDIAN_UINT32(bitmapData + 12); - // Upscale the coordinates/width if the fonts are already upscaled - if (_screen->fontIsUpscaled()) { - textX = textX * _screen->getDisplayWidth() / _screen->getWidth(); - textY = textY * _screen->getDisplayHeight() / _screen->getHeight(); + if (invertSize >= bitmapSize) { + error("InvertRect too big: %u >= %u", invertSize, bitmapSize); } - bool translucent = (skipColor == -1 && backColor == -1); + // NOTE: Actual engine just added the bitmap header size hardcoded here + byte *pixel = bitmapData + READ_SCI11ENDIAN_UINT32(bitmapData + 28) + bitmapStride * targetRect.top + targetRect.left; - for (int curY = 0; curY < height; curY++) { - for (int curX = 0; curX < width; curX++) { - byte pixel = surface[curByte++]; - if ((!translucent && pixel != skipColor && pixel != backColor) || - (translucent && pixel != 0xFF)) - _screen->putFontPixel(textY, curX + textX, curY, pixel); + int16 stride = bitmapStride - targetRect.width(); + int16 targetHeight = targetRect.height(); + int16 targetWidth = targetRect.width(); + + for (int16 y = 0; y < targetHeight; ++y) { + for (int16 x = 0; x < targetWidth; ++x) { + if (*pixel == foreColor) { + *pixel = backColor; + } else if (*pixel == backColor) { + *pixel = foreColor; + } + + ++pixel; } + + pixel += stride; } } -int16 GfxText32::GetLongest(const char *text, int16 maxWidth, GfxFont *font) { - uint16 curChar = 0; - int16 maxChars = 0, curCharCount = 0; - uint16 width = 0; - - while (width <= maxWidth) { - curChar = (*(const byte *)text++); - - switch (curChar) { - // We need to add 0xD, 0xA and 0xD 0xA to curCharCount and then exit - // which means, we split text like - // 'Mature, experienced software analyst available.' 0xD 0xA - // 'Bug installation a proven speciality. "No version too clean."' (normal game text, this is from lsl2) - // and 0xA '-------' 0xA (which is the official sierra subtitle separator) - // Sierra did it the same way. - case 0xD: - // Check, if 0xA is following, if so include it as well - if ((*(const unsigned char *)text) == 0xA) - curCharCount++; - // it's meant to pass through here - case 0xA: - curCharCount++; - // and it's also meant to pass through here - case 0: - return curCharCount; - case ' ': - maxChars = curCharCount; // return count up to (but not including) breaking space - break; +uint GfxText32::getLongest(uint *charIndex, const int16 width) { + assert(width > 0); + + uint testLength = 0; + uint length = 0; + + const uint initialCharIndex = *charIndex; + + // The index of the next word after the last word break + uint lastWordBreakIndex = *charIndex; + + const char *text = _text.c_str() + *charIndex; + + char currentChar; + while ((currentChar = *text++) != '\0') { + // NOTE: In the original engine, the font, color, and alignment were + // reset here to their initial values + + // The text to render contains a line break; stop at the line break + if (currentChar == '\r' || currentChar == '\n') { + // Skip the rest of the line break if it is a Windows-style + // \r\n or non-standard \n\r + // NOTE: In the original engine, the `text` pointer had not been + // advanced yet so the indexes used to access characters were + // one higher + if ( + (currentChar == '\r' && text[0] == '\n') || + (currentChar == '\n' && text[0] == '\r' && text[1] != '\n') + ) { + ++*charIndex; + } + + // We are at the end of a line but the last word in the line made + // it too wide to fit in the text area; return up to the previous + // word + if (length && getTextWidth(initialCharIndex, testLength) > width) { + *charIndex = lastWordBreakIndex; + return length; + } + + // Skip the line break and return all text seen up to now + // NOTE: In original engine, the font, color, and alignment were + // reset, then getTextWidth was called to use its side-effects to + // set font, color, and alignment according to the text from + // `initialCharIndex` to `testLength` + ++*charIndex; + return testLength; + } else if (currentChar == ' ') { + // The last word in the line made it too wide to fit in the text area; + // return up to the previous word, then collapse the whitespace + // between that word and its next sibling word into the line break + if (getTextWidth(initialCharIndex, testLength) > width) { + *charIndex = lastWordBreakIndex; + const char *nextChar = _text.c_str() + lastWordBreakIndex; + while (*nextChar++ == ' ') { + ++*charIndex; + } + + // NOTE: In original engine, the font, color, and alignment were + // set here to the values that were seen at the last space character + return length; + } + + // NOTE: In the original engine, the values of _fontId, _foreColor, + // and _alignment were stored for use in the return path mentioned + // just above here + + // We found a word break that was within the text area, memorise it + // and continue processing. +1 on the character index because it has + // not been incremented yet so currently points to the word break + // and not the word after the break + length = testLength; + lastWordBreakIndex = *charIndex + 1; + } + + // In the middle of a line, keep processing + ++*charIndex; + ++testLength; + + // NOTE: In the original engine, the font, color, and alignment were + // reset here to their initial values + + // The text to render contained no word breaks yet but is already too + // wide for the text area; just split the word in half at the point + // where it overflows + if (length == 0 && getTextWidth(initialCharIndex, testLength) > width) { + *charIndex = --testLength + lastWordBreakIndex; + return testLength; } - if (width + font->getCharWidth(curChar) > maxWidth) - break; - width += font->getCharWidth(curChar); - curCharCount++; } - return maxChars; + // The complete text to render was a single word, or was narrower than + // the text area, so return the entire line + if (length == 0 || getTextWidth(initialCharIndex, testLength) <= width) { + // NOTE: In original engine, the font, color, and alignment were + // reset, then getTextWidth was called to use its side-effects to + // set font, color, and alignment according to the text from + // `initialCharIndex` to `testLength` + return testLength; + } + + // The last word in the line made it wider than the text area, so return + // up to the penultimate word + *charIndex = lastWordBreakIndex; + return length; } -void GfxText32::kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight) { - Common::Rect rect(0, 0, 0, 0); - Size(rect, text, font, maxWidth); - *textWidth = rect.width(); - *textHeight = rect.height(); +int16 GfxText32::getTextWidth(const uint index, uint length) const { + int16 width = 0; + + const char *text = _text.c_str() + index; + + GfxFont *font = _font; + + char currentChar = *text++; + while (length > 0 && currentChar != '\0') { + // Control codes are in the format `|<code><value>|` + if (currentChar == '|') { + // NOTE: Original engine code changed the global state of the + // FontMgr here upon encountering any color, alignment, or + // font control code. + // To avoid requiring all callers to manually restore these + // values on every call, we ignore control codes other than + // font change (since alignment and color do not change the + // width of characters), and simply update the font pointer + // on stack instead of the member property font. + currentChar = *text++; + --length; + + if (length > 0 && currentChar == 'f') { + GuiResourceId fontId = 0; + do { + currentChar = *text++; + --length; + + fontId = fontId * 10 + currentChar - '0'; + } while (length > 0 && currentChar >= '0' && currentChar <= '9'); + + if (length > 0) { + font = _cache->getFont(fontId); + } + } + + // Forward through any more unknown control character data + while (length > 0 && currentChar != '|') { + ++text; + --length; + } + } else { + width += font->getCharWidth(currentChar); + } + + currentChar = *text++; + --length; + } + + return width; } -void GfxText32::StringWidth(const char *str, GuiResourceId fontId, int16 &textWidth, int16 &textHeight) { - Width(str, 0, (int16)strlen(str), fontId, textWidth, textHeight, true); +int16 GfxText32::getTextWidth(const Common::String &text, const uint index, const uint length) { + _text = text; + return scaleUpWidth(getTextWidth(index, length)); } -void GfxText32::Width(const char *text, int16 from, int16 len, GuiResourceId fontId, int16 &textWidth, int16 &textHeight, bool restoreFont) { - byte curChar; - textWidth = 0; textHeight = 0; - - GfxFont *font = _cache->getFont(fontId); - - if (font) { - text += from; - while (len--) { - curChar = (*(const byte *)text++); - switch (curChar) { - case 0x0A: - case 0x0D: - textHeight = MAX<int16> (textHeight, font->getHeight()); - break; - case 0x7C: - warning("Code processing isn't implemented in SCI32"); - break; - default: - textHeight = MAX<int16> (textHeight, font->getHeight()); - textWidth += font->getCharWidth(curChar); - break; +Common::Rect GfxText32::getTextSize(const Common::String &text, int16 maxWidth, bool doScaling) { + // NOTE: Like most of the text rendering code, this function was pretty + // weird in the original engine. The initial result rectangle was actually + // a 1x1 rectangle (0, 0, 0, 0), which was then "fixed" after the main + // text size loop finished running by subtracting 1 from the right and + // bottom edges. Like other functions in SCI32, this has been converted + // to use exclusive rects with inclusive rounding. + + Common::Rect result; + + int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + + maxWidth = maxWidth * _scaledWidth / scriptWidth; + + _text = text; + + if (maxWidth >= 0) { + if (maxWidth == 0) { + // TODO: This was hardcoded to 192, but guessing + // that it was originally 60% of the scriptWidth + // before the compiler took over. + // Verify this by looking at a game that uses a + // scriptWidth other than 320, like LSL7 + maxWidth = _scaledWidth * (scriptWidth * 0.6) / scriptWidth; + } + + result.right = maxWidth; + + int16 textWidth = 0; + if (_text.size() > 0) { + const char *rawText = _text.c_str(); + const char *sourceText = rawText; + uint charIndex = 0; + uint nextCharIndex = 0; + while (*rawText != '\0') { + uint length = getLongest(&nextCharIndex, result.width()); + textWidth = MAX(textWidth, getTextWidth(charIndex, length)); + charIndex = nextCharIndex; + rawText = sourceText + charIndex; + // TODO: Due to getLongest and getTextWidth not having side + // effects, it is possible that the currently loaded font's + // height is wrong for this line if it was changed inline + result.bottom += _font->getHeight(); } } + + if (textWidth < maxWidth) { + result.right = textWidth; + } + } else { + result.right = getTextWidth(0, 10000); + // NOTE: In the original engine code, the bottom was not decremented + // by 1, which means that the rect was actually a pixel taller than + // the height of the font. This was not the case in the other branch, + // which decremented the bottom by 1 at the end of the loop. + result.bottom = _font->getHeight() + 1; } + + if (doScaling) { + // NOTE: The original engine code also scaled top/left but these are + // always zero so there is no reason to do that. + result.right = ((result.right - 1) * scriptWidth + _scaledWidth - 1) / _scaledWidth + 1; + result.bottom = ((result.bottom - 1) * scriptHeight + _scaledHeight - 1) / _scaledHeight + 1; + } + + return result; } -int16 GfxText32::Size(Common::Rect &rect, const char *text, GuiResourceId fontId, int16 maxWidth) { - int16 charCount; - int16 maxTextWidth = 0, textWidth; - int16 totalHeight = 0, textHeight; +void GfxText32::erase(const Common::Rect &rect, const bool doScaling) { + Common::Rect targetRect = doScaling ? scaleRect(rect) : rect; - // Adjust maxWidth if we're using an upscaled font - if (_screen->fontIsUpscaled()) - maxWidth = maxWidth * _screen->getDisplayWidth() / _screen->getWidth(); + byte *bitmap = _segMan->getHunkPointer(_bitmap); + byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28); - rect.top = rect.left = 0; - GfxFont *font = _cache->getFont(fontId); + // NOTE: There is an extra optimisation within the SCI code to + // do a single memset if the scaledRect is the same size as + // the bitmap, not implemented here. + Buffer buffer(_width, _height, pixels); + buffer.fillRect(targetRect, _backColor); +} - if (maxWidth < 0) { // force output as single line - StringWidth(text, fontId, textWidth, textHeight); - rect.bottom = textHeight; - rect.right = textWidth; - } else { - // rect.right=found widest line with RTextWidth and GetLongest - // rect.bottom=num. lines * GetPointSize - rect.right = (maxWidth ? maxWidth : 192); - const char *curPos = text; - while (*curPos) { - charCount = GetLongest(curPos, rect.right, font); - if (charCount == 0) - break; - Width(curPos, 0, charCount, fontId, textWidth, textHeight, false); - maxTextWidth = MAX(textWidth, maxTextWidth); - totalHeight += textHeight; - curPos += charCount; - while (*curPos == ' ') - curPos++; // skip over breaking spaces - } - rect.bottom = totalHeight; - rect.right = maxWidth ? maxWidth : MIN(rect.right, maxTextWidth); +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)); } - // Adjust the width/height if we're using an upscaled font - // for the scripts - if (_screen->fontIsUpscaled()) { - rect.right = rect.right * _screen->getWidth() / _screen->getDisplayWidth(); - rect.bottom = rect.bottom * _screen->getHeight() / _screen->getDisplayHeight(); + 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); } - return rect.right; + _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 7ba7df50e4..5768ea0c59 100644 --- a/engines/sci/graphics/text32.h +++ b/engines/sci/graphics/text32.h @@ -23,34 +23,455 @@ #ifndef SCI_GRAPHICS_TEXT32_H #define SCI_GRAPHICS_TEXT32_H +#include "sci/graphics/celobj32.h" +#include "sci/graphics/frameout.h" + namespace Sci { +enum TextAlign { + kTextAlignLeft = 0, + kTextAlignCenter = 1, + kTextAlignRight = 2 +}; + +enum BitmapFlags { + kBitmapRemap = 2 +}; + +#define BITMAP_PROPERTY(size, property, offset)\ +inline uint##size get##property() const {\ + return READ_SCI11ENDIAN_UINT##size(_bitmap + (offset));\ +}\ +inline void set##property(uint##size value) {\ + WRITE_SCI11ENDIAN_UINT##size(_bitmap + (offset), (value));\ +} + /** - * Text32 class, handles text calculation and displaying of text for SCI2, SCI21 and SCI3 games + * A convenience class for creating and modifying in-memory + * bitmaps. */ -class GfxText32 { +class BitmapResource { + byte *_bitmap; + reg_t _object; + + /** + * Gets the size of the bitmap header for the current + * engine version. + */ + static inline uint16 getBitmapHeaderSize() { + // TODO: These values are accurate for each engine, but there may be no reason + // to not simply just always use size 40, since SCI2.1mid does not seem to + // actually store any data above byte 40, and SCI2 did not allow bitmaps with + // scaling resolutions other than the default (320x200). Perhaps SCI3 used + // the extra bytes, or there is some reason why they tried to align the header + // size with other headers like pic headers? +// uint32 bitmapHeaderSize; +// if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) { +// bitmapHeaderSize = 46; +// } else if (getSciVersion() == SCI_VERSION_2_1_EARLY) { +// bitmapHeaderSize = 40; +// } else { +// bitmapHeaderSize = 36; +// } +// return bitmapHeaderSize; + return 46; + } + + /** + * Gets the byte size of a bitmap with the given width + * and height. + */ + static inline uint32 getBitmapSize(const uint16 width, const uint16 height) { + return width * height + getBitmapHeaderSize(); + } + public: - GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen); - ~GfxText32(); - reg_t createTextBitmap(reg_t textObject, uint16 maxWidth = 0, uint16 maxHeight = 0, reg_t prevHunk = NULL_REG); - reg_t createScrollTextBitmap(Common::String text, reg_t textObject, uint16 maxWidth = 0, uint16 maxHeight = 0, reg_t prevHunk = NULL_REG); - void drawTextBitmap(int16 x, int16 y, Common::Rect planeRect, reg_t textObject); - void drawScrollTextBitmap(reg_t textObject, reg_t hunkId, uint16 x, uint16 y); - void disposeTextBitmap(reg_t hunkId); - int16 GetLongest(const char *text, int16 maxWidth, GfxFont *font); + /** + * Create a bitmap resource for an existing bitmap. + * Ownership of the bitmap is retained by the caller. + */ + inline BitmapResource(reg_t bitmap) : + _bitmap(g_sci->getEngineState()->_segMan->getHunkPointer(bitmap)), + _object(bitmap) { + if (_bitmap == nullptr || getUncompressedDataOffset() != getBitmapHeaderSize()) { + error("Invalid Text bitmap %04x:%04x", PRINT_REG(bitmap)); + } + } - void kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight); + /** + * Allocates and initialises a new bitmap in the given + * segment manager. + */ + inline BitmapResource(SegManager *segMan, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 hunkPaletteOffset, const bool remap) { -private: - reg_t createTextBitmapInternal(Common::String &text, reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t hunkId); - void drawTextBitmapInternal(int16 x, int16 y, Common::Rect planeRect, reg_t textObject, reg_t hunkId); - int16 Size(Common::Rect &rect, const char *text, GuiResourceId fontId, int16 maxWidth); - void Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight, bool restoreFont); - void StringWidth(const char *str, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight); + _object = segMan->allocateHunkEntry("Bitmap()", getBitmapSize(width, height)); + _bitmap = segMan->getHunkPointer(_object); + + const uint16 bitmapHeaderSize = getBitmapHeaderSize(); + + setWidth(width); + setHeight(height); + setDisplace(Common::Point(displaceX, displaceY)); + setSkipColor(skipColor); + _bitmap[9] = 0; + WRITE_SCI11ENDIAN_UINT16(_bitmap + 10, 0); + setRemap(remap); + setDataSize(width * height); + WRITE_SCI11ENDIAN_UINT32(_bitmap + 16, 0); + setHunkPaletteOffset(hunkPaletteOffset); + setDataOffset(bitmapHeaderSize); + setUncompressedDataOffset(bitmapHeaderSize); + setControlOffset(0); + setScaledWidth(scaledWidth); + setScaledHeight(scaledHeight); + } + + reg_t getObject() const { + return _object; + } + + BITMAP_PROPERTY(16, Width, 0); + BITMAP_PROPERTY(16, Height, 2); + + inline Common::Point getDisplace() const { + return Common::Point( + (int16)READ_SCI11ENDIAN_UINT16(_bitmap + 4), + (int16)READ_SCI11ENDIAN_UINT16(_bitmap + 6) + ); + } + + inline void setDisplace(const Common::Point &displace) { + WRITE_SCI11ENDIAN_UINT16(_bitmap + 4, (uint16)displace.x); + WRITE_SCI11ENDIAN_UINT16(_bitmap + 6, (uint16)displace.y); + } + + inline uint8 getSkipColor() const { + return _bitmap[8]; + } + + inline void setSkipColor(const uint8 skipColor) { + _bitmap[8] = skipColor; + } + + inline bool getRemap() const { + return READ_SCI11ENDIAN_UINT16(_bitmap + 10) & kBitmapRemap; + } + + inline void setRemap(const bool remap) { + uint16 flags = READ_SCI11ENDIAN_UINT16(_bitmap + 10); + if (remap) { + flags |= kBitmapRemap; + } else { + flags &= ~kBitmapRemap; + } + WRITE_SCI11ENDIAN_UINT16(_bitmap + 10, flags); + } + BITMAP_PROPERTY(32, DataSize, 12); + + inline uint32 getHunkPaletteOffset() const { + return READ_SCI11ENDIAN_UINT32(_bitmap + 20); + } + + void setHunkPaletteOffset(uint32 hunkPaletteOffset) { + if (hunkPaletteOffset) { + hunkPaletteOffset += getBitmapHeaderSize(); + } + + WRITE_SCI11ENDIAN_UINT32(_bitmap + 20, hunkPaletteOffset); + } + + BITMAP_PROPERTY(32, DataOffset, 24); + + // NOTE: This property is used as a "magic number" for + // validating that a block of memory is a valid bitmap, + // and so is always set to the size of the header. + BITMAP_PROPERTY(32, UncompressedDataOffset, 28); + + // NOTE: This property always seems to be zero + BITMAP_PROPERTY(32, ControlOffset, 32); + + inline uint16 getScaledWidth() const { + if (getDataOffset() >= 40) { + return READ_SCI11ENDIAN_UINT16(_bitmap + 36); + } + + // SCI2 bitmaps did not have scaling ability + return 320; + } + + inline void setScaledWidth(uint16 scaledWidth) { + if (getDataOffset() >= 40) { + WRITE_SCI11ENDIAN_UINT16(_bitmap + 36, scaledWidth); + } + } + + inline uint16 getScaledHeight() const { + if (getDataOffset() >= 40) { + return READ_SCI11ENDIAN_UINT16(_bitmap + 38); + } + + // SCI2 bitmaps did not have scaling ability + return 200; + } + + inline void setScaledHeight(uint16 scaledHeight) { + if (getDataOffset() >= 40) { + WRITE_SCI11ENDIAN_UINT16(_bitmap + 38, scaledHeight); + } + } + + inline byte *getPixels() { + return _bitmap + getUncompressedDataOffset(); + } +}; + +class GfxFont; + +/** + * This class handles text calculation and rendering for + * SCI32 games. The text calculation system in SCI32 is + * nearly the same as SCI16, which means this class behaves + * similarly. Notably, GfxText32 maintains drawing + * parameters across multiple calls. + */ +class GfxText32 { +private: SegManager *_segMan; GfxCache *_cache; - GfxScreen *_screen; + + /** + * The resource ID of the default font used by the game. + * + * @todo Check all SCI32 games to learn what their + * default font is. + */ + static int16 _defaultFontId; + + /** + * The width and height of the currently active text + * bitmap, in text-system coordinates. + * + * @note These are unsigned in the actual engine. + */ + int16 _width, _height; + + /** + * The color used to draw text. + */ + uint8 _foreColor; + + /** + * The background color of the text box. + */ + uint8 _backColor; + + /** + * The transparent color of the text box. Used when + * compositing the bitmap onto the screen. + */ + uint8 _skipColor; + + /** + * The rect where the text is drawn within the bitmap. + * This rect is clipped to the dimensions of the bitmap. + */ + Common::Rect _textRect; + + /** + * The text being drawn to the currently active text + * bitmap. + */ + Common::String _text; + + /** + * The font being used to draw the text. + */ + GuiResourceId _fontId; + + /** + * The color of the text box border. + */ + int16 _borderColor; + + /** + * TODO: Document + */ + bool _dimmed; + + /** + * The text alignment for the drawn text. + */ + TextAlign _alignment; + + int16 _field_20; + + /** + * TODO: Document + */ + int16 _field_22; + + int _field_2C, _field_30, _field_34, _field_38; + + int16 _field_3C; + + /** + * The position of the text draw cursor. + */ + Common::Point _drawPosition; + + void drawFrame(const Common::Rect &rect, const int16 size, const uint8 color, const bool doScaling); + + void drawChar(const char charIndex); + void drawText(const uint index, uint length); + + /** + * Gets the length of the longest run of text available + * within the currently loaded text, starting from the + * given `charIndex` and running for up to `maxWidth` + * pixels. Returns the number of characters that can be + * written, and mutates the value pointed to by + * `charIndex` to point to the index of the next + * character to render. + */ + uint getLongest(uint *charIndex, const int16 maxWidth); + + /** + * Gets the pixel width of a substring of the currently + * loaded text, without scaling. + */ + int16 getTextWidth(const uint index, uint length) const; + + inline Common::Rect scaleRect(const Common::Rect &rect) { + Common::Rect scaledRect(rect); + int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + Ratio scaleX(_scaledWidth, scriptWidth); + Ratio scaleY(_scaledHeight, scriptHeight); + mulinc(scaledRect, scaleX, scaleY); + return scaledRect; + } + +public: + GfxText32(SegManager *segMan, GfxCache *fonts); + + /** + * The memory handle of the currently active bitmap. + */ + reg_t _bitmap; + + /** + * The size of the x-dimension of the coordinate system + * used by the text renderer. + */ + int16 _scaledWidth; + + /** + * The size of the y-dimension of the coordinate system + * used by the text renderer. + */ + int16 _scaledHeight; + + /** + * The currently active font resource used to write text + * into the bitmap. + * + * @note SCI engine builds the font table directly + * inside of FontMgr; we use GfxFont instead. + */ + GfxFont *_font; + + /** + * Creates a plain font bitmap with a flat color + * background. + */ + reg_t createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, TextAlign alignment, const int16 borderColor, bool dimmed, const bool doScaling); + + /** + * Creates a font bitmap with a view background. + */ + reg_t createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed); + + /** + * Creates a font bitmap with a title. + */ + reg_t createTitledBitmap(const int16 width, const int16 height, const Common::Rect &textRect, const Common::String &text, const int16 foreColor, const int16 backColor, const int16 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, Common::String &title, const int16 titleForeColor, const int16 titleBackColor, const GuiResourceId titleFontId, const bool doScaling); + + inline int scaleUpWidth(int value) const { + const int scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + return (value * scriptWidth + _scaledWidth - 1) / _scaledWidth; + } + + inline int scaleUpHeight(int value) const { + const int scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + return (value * scriptHeight + _scaledHeight - 1) / _scaledHeight; + } + + /** + * Draws the text to the bitmap. + */ + void drawTextBox(); + + /** + * Draws the given text to the bitmap. + * + * @note The original engine holds a reference to a + * shared string which lets the text be updated from + * outside of the font manager. Instead, we give this + * extra signature to send the text to draw. + * + * TODO: Use shared string instead? + */ + void drawTextBox(const Common::String &text); + + /** + * Erases the given rect by filling with the background + * color. + */ + void erase(const Common::Rect &rect, const bool doScaling); + + void invertRect(const reg_t bitmap, const int16 bitmapStride, const Common::Rect &rect, const uint8 foreColor, const uint8 backColor, const bool doScaling); + + /** + * Sets the font to be used for rendering and + * calculation of text dimensions. + */ + void setFont(const GuiResourceId fontId); + + /** + * Gets the width of a character. + */ + uint16 getCharWidth(const char charIndex, const bool doScaling) const; + + /** + * Retrieves the width and height of a block of text. + */ + Common::Rect getTextSize(const Common::String &text, const int16 maxWidth, bool doScaling); + + /** + * Gets the pixel width of a substring of the currently + * loaded text, with scaling. + */ + int16 getTextWidth(const Common::String &text, const uint index, const uint length); + + /** + * 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 2ee18b5c9a..1939e66179 100644 --- a/engines/sci/graphics/view.cpp +++ b/engines/sci/graphics/view.cpp @@ -25,6 +25,7 @@ #include "sci/engine/state.h" #include "sci/graphics/screen.h" #include "sci/graphics/palette.h" +#include "sci/graphics/remap.h" #include "sci/graphics/coordadjuster.h" #include "sci/graphics/view.h" @@ -833,19 +834,6 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const bitmap += (clipRect.top - rect.top) * celWidth + (clipRect.left - rect.left); - // WORKAROUND: EcoQuest French and German draw the fish and anemone sprites - // with priority 15 in scene 440. Afterwards, a dialog is shown on top of - // these sprites with priority 15 as well. This is undefined behavior - // actually, as the sprites and dialog share the same priority, so in our - // implementation the sprites get drawn incorrectly on top of the dialog. - // Perhaps this worked by mistake in SSCI because of subtle differences in - // how sprites are drawn. We compensate for this by resetting the priority - // of all sprites that have a priority of 15 in scene 440 to priority 14, - // so that the speech bubble can be drawn correctly on top of them. Fixes - // bug #3040625. - if (g_sci->getGameId() == GID_ECOQUEST && g_sci->getEngineState()->currentRoomNumber() == 440 && priority == 15) - priority = 14; - if (!_EGAmapping) { for (y = 0; y < height; y++, bitmap += celWidth) { for (x = 0; x < width; x++) { @@ -855,12 +843,11 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const const int y2 = clipRectTranslated.top + y; if (!upscaledHires) { if (priority >= _screen->getPriority(x2, y2)) { - if (!_palette->isRemapped(palette->mapping[color])) { - _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0); - } else { - byte remappedColor = _palette->remapColor(palette->mapping[color], _screen->getVisual(x2, y2)); - _screen->putPixel(x2, y2, drawMask, remappedColor, priority, 0); - } + byte outputColor = palette->mapping[color]; + // SCI16 remapping (QFG4 demo) + if (g_sci->_gfxRemap16 && g_sci->_gfxRemap16->isRemapped(outputColor)) + outputColor = g_sci->_gfxRemap16->remapColor(outputColor, _screen->getVisual(x2, y2)); + _screen->putPixel(x2, y2, drawMask, outputColor, priority, 0); } } else { // UpscaledHires means view is hires and is supposed to @@ -970,12 +957,11 @@ void GfxView::drawScaled(const Common::Rect &rect, const Common::Rect &clipRect, const int x2 = clipRectTranslated.left + x; const int y2 = clipRectTranslated.top + y; if (color != clearKey && priority >= _screen->getPriority(x2, y2)) { - if (!_palette->isRemapped(palette->mapping[color])) { - _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0); - } else { - byte remappedColor = _palette->remapColor(palette->mapping[color], _screen->getVisual(x2, y2)); - _screen->putPixel(x2, y2, drawMask, remappedColor, priority, 0); - } + byte outputColor = palette->mapping[color]; + // SCI16 remapping (QFG4 demo) + if (g_sci->_gfxRemap16 && g_sci->_gfxRemap16->isRemapped(outputColor)) + outputColor = g_sci->_gfxRemap16->remapColor(outputColor, _screen->getVisual(x2, y2)); + _screen->putPixel(x2, y2, drawMask, outputColor, priority, 0); } } } @@ -989,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/module.mk b/engines/sci/module.mk index 08e5ea84d8..a02147e4d0 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -57,6 +57,7 @@ MODULE_OBJS := \ graphics/picture.o \ graphics/portrait.o \ graphics/ports.o \ + graphics/remap.o \ graphics/screen.o \ graphics/text16.o \ graphics/transitions.o \ @@ -81,10 +82,13 @@ MODULE_OBJS := \ ifdef ENABLE_SCI32 MODULE_OBJS += \ engine/kgraphics32.o \ + graphics/celobj32.o \ graphics/controls32.o \ graphics/frameout.o \ graphics/paint32.o \ + graphics/plane32.o \ graphics/palette32.o \ + graphics/screen_item32.o \ graphics/text32.o \ video/robot_decoder.o endif diff --git a/engines/sci/parser/vocabulary.cpp b/engines/sci/parser/vocabulary.cpp index 828a57abeb..a09ba8f3ce 100644 --- a/engines/sci/parser/vocabulary.cpp +++ b/engines/sci/parser/vocabulary.cpp @@ -121,7 +121,7 @@ bool Vocabulary::loadParserWords() { } } - unsigned int seeker; + uint32 seeker; if (resourceType == kVocabularySCI1) seeker = 255 * 2; // vocab.900 starts with 255 16-bit pointers which we don't use else @@ -202,7 +202,7 @@ bool Vocabulary::loadSuffixes() { if (!resource) return false; // No vocabulary found - unsigned int seeker = 1; + uint32 seeker = 1; while ((seeker < resource->size - 1) && (resource->data[seeker + 1] != 0xff)) { suffix_t suffix; @@ -288,7 +288,7 @@ bool Vocabulary::loadAltInputs() { AltInput t; t._input = data; - unsigned int l = strlen(data); + uint32 l = strlen(data); t._inputLength = l; data += l + 1; @@ -325,15 +325,15 @@ bool Vocabulary::checkAltInput(Common::String& text, uint16& cursorPos) { return false; bool ret = false; - unsigned int loopCount = 0; + uint32 loopCount = 0; bool changed; do { changed = false; const char* t = text.c_str(); - unsigned int tlen = text.size(); + uint32 tlen = text.size(); - for (unsigned int p = 0; p < tlen && !changed; ++p) { + for (uint32 p = 0; p < tlen && !changed; ++p) { unsigned char s = t[p]; if (s >= _altInputs.size() || _altInputs[s].empty()) continue; @@ -351,7 +351,7 @@ bool Vocabulary::checkAltInput(Common::String& text, uint16& cursorPos) { cursorPos = p + strlen(i->_replacement); } - for (unsigned int j = 0; j < i->_inputLength; ++j) + for (uint32 j = 0; j < i->_inputLength; ++j) text.deleteChar(p); const char *r = i->_replacement; while (*r) diff --git a/engines/sci/parser/vocabulary.h b/engines/sci/parser/vocabulary.h index f4adee6e55..59558ce18a 100644 --- a/engines/sci/parser/vocabulary.h +++ b/engines/sci/parser/vocabulary.h @@ -156,7 +156,7 @@ typedef Common::Array<synonym_t> SynonymList; struct AltInput { const char *_input; const char *_replacement; - unsigned int _inputLength; + uint32 _inputLength; bool _prefix; }; diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 54ef4b3363..6a5af1a6d6 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -307,7 +307,7 @@ bool Resource::loadPatch(Common::SeekableReadStream *file) { error("Can't allocate %d bytes needed for loading %s", res->size + res->_headerSize, res->_id.toString().c_str()); } - unsigned int really_read; + uint32 really_read; if (res->_headerSize > 0) { really_read = file->read(res->_header, res->_headerSize); if (really_read != res->_headerSize) @@ -565,12 +565,11 @@ Resource *ResourceManager::testResource(ResourceId id) { } int ResourceManager::addAppropriateSources() { - Common::ArchiveMemberList files; - if (Common::File::exists("resource.map")) { // SCI0-SCI2 file naming scheme ResourceSource *map = addExternalMap("resource.map"); + Common::ArchiveMemberList files; SearchMan.listMatchingMembers(files, "resource.0??"); for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) { @@ -587,20 +586,20 @@ int ResourceManager::addAppropriateSources() { #endif } else if (Common::MacResManager::exists("Data1")) { // Mac SCI1.1+ file naming scheme - SearchMan.listMatchingMembers(files, "Data?*"); + Common::StringArray files; + Common::MacResManager::listFiles(files, "Data?"); - for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) { - Common::String filename = (*x)->getName(); - addSource(new MacResourceForkResourceSource(filename, atoi(filename.c_str() + 4))); + for (Common::StringArray::const_iterator x = files.begin(); x != files.end(); ++x) { + addSource(new MacResourceForkResourceSource(*x, atoi(x->c_str() + 4))); } #ifdef ENABLE_SCI32 // There can also be a "Patches" resource fork with patches - if (Common::File::exists("Patches")) + if (Common::MacResManager::exists("Patches")) addSource(new MacResourceForkResourceSource("Patches", 100)); } else { // SCI2.1-SCI3 file naming scheme - Common::ArchiveMemberList mapFiles; + Common::ArchiveMemberList mapFiles, files; SearchMan.listMatchingMembers(mapFiles, "resmap.0??"); SearchMan.listMatchingMembers(files, "ressci.0??"); @@ -865,6 +864,7 @@ ResourceManager::ResourceManager() { } void ResourceManager::init() { + _maxMemoryLRU = 256 * 1024; // 256KiB _memoryLocked = 0; _memoryLRU = 0; _LRU.clear(); @@ -918,6 +918,14 @@ void ResourceManager::init() { debugC(1, kDebugLevelResMan, "resMan: Detected %s", getSciVersionDesc(getSciVersion())); + // Resources in SCI32 games are significantly larger than SCI16 + // games and can cause immediate exhaustion of the LRU resource + // cache, leading to constant decompression of picture resources + // and making the renderer very slow. + if (getSciVersion() >= SCI_VERSION_2) { + _maxMemoryLRU = 2048 * 1024; // 2MiB + } + switch (_viewType) { case kViewEga: debugC(1, kDebugLevelResMan, "resMan: Detected EGA graphic resources"); @@ -935,35 +943,14 @@ void ResourceManager::init() { debugC(1, kDebugLevelResMan, "resMan: Detected SCI1.1 VGA graphic resources"); break; default: -#ifdef ENABLE_SCI32 - error("resMan: Couldn't determine view type"); -#else - if (getSciVersion() >= SCI_VERSION_2) { - // SCI support isn't built in, thus the view type won't be determined for - // SCI2+ games. This will be handled further up, so throw no error here - } else { - error("resMan: Couldn't determine view type"); - } -#endif + // Throw a warning, but do not error out here, because this is called from the + // fallback detector, and the user could be pointing to a folder with a non-SCI + // game, but with SCI-like file names (e.g. Pinball Creep) + warning("resMan: Couldn't determine view type"); + break; } } -void ResourceManager::initForDetection() { - assert(!g_sci); - - _memoryLocked = 0; - _memoryLRU = 0; - _LRU.clear(); - _resMap.clear(); - _audioMapSCI1 = NULL; - - _mapVersion = detectMapVersion(); - _volVersion = detectVolVersion(); - - scanNewSources(); - detectSciVersion(); -} - ResourceManager::~ResourceManager() { // freeing resources ResourceMap::iterator itr = _resMap.begin(); @@ -998,9 +985,9 @@ void ResourceManager::addToLRU(Resource *res) { _LRU.push_front(res); _memoryLRU += res->size; #if SCI_VERBOSE_RESMAN - debug("Adding %s.%03d (%d bytes) to lru control: %d bytes total", - getResourceTypeName(res->type), res->number, res->size, - mgr->_memoryLRU); + debug("Adding %s (%d bytes) to lru control: %d bytes total", + res->_id.toString().c_str(), res->size, + _memoryLRU); #endif res->_status = kResStatusEnqueued; } @@ -1023,13 +1010,13 @@ void ResourceManager::printLRU() { } void ResourceManager::freeOldResources() { - while (MAX_MEMORY < _memoryLRU) { + while (_maxMemoryLRU < _memoryLRU) { assert(!_LRU.empty()); Resource *goner = *_LRU.reverse_begin(); removeFromLRU(goner); goner->unalloc(); #ifdef SCI_VERBOSE_RESMAN - debug("resMan-debug: LRU: Freeing %s.%03d (%d bytes)", getResourceTypeName(goner->type), goner->number, goner->size); + debug("resMan-debug: LRU: Freeing %s (%d bytes)", goner->_id.toString().c_str(), goner->size); #endif } } @@ -2474,7 +2461,9 @@ bool ResourceManager::hasOldScriptHeader() { Resource *res = findResource(ResourceId(kResourceTypeScript, 0), 0); if (!res) { - error("resMan: Failed to find script.000"); + // Script 0 missing -> corrupted / non-SCI resource files. + // Don't error out here, because this might have been called + // from the fallback detector return false; } @@ -2679,7 +2668,9 @@ Common::String ResourceManager::findSierraGameId() { return ""; // Seek to the name selector of the first export - byte *seeker = heap->data + READ_UINT16(heap->data + gameObjectOffset + nameSelector * 2); + byte *offsetPtr = heap->data + gameObjectOffset + nameSelector * 2; + uint16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr); + byte *seeker = heap->data + offset; Common::String sierraId; sierraId += (const char *)seeker; diff --git a/engines/sci/resource.h b/engines/sci/resource.h index eb5b508254..ef474d97c2 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -315,11 +315,6 @@ public: void init(); /** - * Similar to the function above, only called from the fallback detector - */ - void initForDetection(); - - /** * Adds all of the resource files for a game */ int addAppropriateSources(); @@ -426,9 +421,7 @@ protected: // Note: maxMemory will not be interpreted as a hard limit, only as a restriction // for resources which are not explicitly locked. However, a warning will be // issued whenever this limit is exceeded. - enum { - MAX_MEMORY = 256 * 1024 // 256KB - }; + int _maxMemoryLRU; ViewType _viewType; // Used to determine if the game has EGA or VGA graphics Common::List<ResourceSource *> _sources; diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp index 6869e6379e..5717a09121 100644 --- a/engines/sci/resource_audio.cpp +++ b/engines/sci/resource_audio.cpp @@ -139,7 +139,7 @@ bool Resource::loadFromAudioVolumeSCI1(Common::SeekableReadStream *file) { error("Can't allocate %d bytes needed for loading %s", size, _id.toString().c_str()); } - unsigned int really_read = file->read(data, size); + uint32 really_read = file->read(data, size); if (really_read != size) warning("Read %d bytes from %s but expected %d", really_read, _id.toString().c_str(), size); @@ -688,6 +688,12 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers channel->data = resource->data + dataOffset; channel->size = READ_LE_UINT16(data + 4); + + if (dataOffset + channel->size > resource->size) { + warning("Invalid size inside sound resource %d: track %d, channel %d", resourceNr, trackNr, channelNr); + channel->size = resource->size - dataOffset; + } + channel->curPos = 0; channel->number = *channel->data; diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 1232b6559b..e14d12b918 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -58,6 +58,7 @@ #include "sci/graphics/picture.h" #include "sci/graphics/ports.h" #include "sci/graphics/palette.h" +#include "sci/graphics/remap.h" #include "sci/graphics/screen.h" #include "sci/graphics/text16.h" #include "sci/graphics/transitions.h" @@ -163,6 +164,7 @@ SciEngine::~SciEngine() { delete _gfxText32; delete _robotDecoder; delete _gfxFrameout; + delete _gfxRemap32; #endif delete _gfxMenu; delete _gfxControls16; @@ -175,6 +177,7 @@ SciEngine::~SciEngine() { delete _gfxPorts; delete _gfxCache; delete _gfxPalette16; + delete _gfxRemap16; delete _gfxCursor; delete _gfxScreen; @@ -238,13 +241,7 @@ Common::Error SciEngine::run() { // Only DOS+Windows switch (_gameId) { case GID_KQ6: - if (isCD()) - _forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics"); - break; case GID_GK1: - if ((isCD()) && (!isDemo())) - _forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics"); - break; case GID_PQ4: if (isCD()) _forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics"); @@ -316,6 +313,7 @@ Common::Error SciEngine::run() { if (directSaveSlotLoading >= 0) { _gamestate->_delayedRestoreGame = true; _gamestate->_delayedRestoreGameId = directSaveSlotLoading; + _gamestate->_delayedRestoreFromLauncher = true; // Jones only initializes its menus when restarting/restoring, thus set // the gameIsRestarting flag here before initializing. Fixes bug #6536. @@ -529,7 +527,7 @@ void SciEngine::patchGameSaveRestore() { byte kernelIdSave = 0; switch (_gameId) { - case GID_HOYLE1: // gets confused, although the game doesnt support saving/restoring at all + case GID_HOYLE1: // gets confused, although the game doesn't support saving/restoring at all case GID_HOYLE2: // gets confused, see hoyle1 case GID_JONES: // gets confused, when we patch us in, the game is only able to save to 1 slot, so hooking is not required case GID_MOTHERGOOSE: // mother goose EGA saves/restores directly and has no save/restore dialogs @@ -576,17 +574,29 @@ void SciEngine::patchGameSaveRestore() { } } + const Object *patchObjectSave = nullptr; + + if (getSciVersion() < SCI_VERSION_2) { + // Patch gameobject ::save for now for SCI0 - SCI1.1 + // TODO: It seems this was never adjusted to superclass, but adjusting it now may cause + // issues with some game. Needs to get checked and then possibly changed. + patchObjectSave = gameObject; + } else { + // Patch superclass ::save for SCI32 + patchObjectSave = gameSuperObject; + } + // Search for gameobject ::save, if there is one patch that one too - uint16 gameObjectMethodCount = gameObject->getMethodCount(); - for (uint16 methodNr = 0; methodNr < gameObjectMethodCount; methodNr++) { - uint16 selectorId = gameObject->getFuncSelector(methodNr); + uint16 patchObjectMethodCount = patchObjectSave->getMethodCount(); + for (uint16 methodNr = 0; methodNr < patchObjectMethodCount; methodNr++) { + uint16 selectorId = patchObjectSave->getFuncSelector(methodNr); Common::String methodName = _kernel->getSelectorName(selectorId); if (methodName == "save") { if (_gameId != GID_FAIRYTALES) { // Fairy Tales saves automatically without a dialog if (kernelIdSave != kernelIdRestore) - patchGameSaveRestoreCode(segMan, gameObject->getFunction(methodNr), kernelIdSave); + patchGameSaveRestoreCode(segMan, patchObjectSave->getFunction(methodNr), kernelIdSave); else - patchGameSaveRestoreCodeSci21(segMan, gameObject->getFunction(methodNr), kernelIdSave, false); + patchGameSaveRestoreCodeSci21(segMan, patchObjectSave->getFunction(methodNr), kernelIdSave, false); } break; } @@ -653,6 +663,7 @@ void SciEngine::initGraphics() { _gfxPaint = 0; _gfxPaint16 = 0; _gfxPalette16 = 0; + _gfxRemap16 = 0; _gfxPorts = 0; _gfxText16 = 0; _gfxTransitions = 0; @@ -663,6 +674,7 @@ void SciEngine::initGraphics() { _gfxFrameout = 0; _gfxPaint32 = 0; _gfxPalette32 = 0; + _gfxRemap32 = 0; #endif if (hasMacIconBar()) @@ -672,9 +684,12 @@ void SciEngine::initGraphics() { if (getSciVersion() >= SCI_VERSION_2) { _gfxPalette32 = new GfxPalette32(_resMan, _gfxScreen); _gfxPalette16 = _gfxPalette32; + _gfxRemap32 = new GfxRemap32(_gfxPalette32); } else { #endif _gfxPalette16 = new GfxPalette(_resMan, _gfxScreen); + if (getGameId() == GID_QFG4DEMO) + _gfxRemap16 = new GfxRemap(_gfxPalette16); #ifdef ENABLE_SCI32 } #endif @@ -690,10 +705,11 @@ void SciEngine::initGraphics() { _gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxCoordAdjuster); _gfxPaint32 = new GfxPaint32(_resMan, _gfxCoordAdjuster, _gfxScreen, _gfxPalette32); _gfxPaint = _gfxPaint32; - _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache, _gfxScreen); - _gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32); _robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh); _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette32, _gfxPaint32); + _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache); + _gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32); + _gfxFrameout->run(); } else { #endif // SCI0-SCI1.1 graphic objects creation @@ -704,7 +720,7 @@ void SciEngine::initGraphics() { _gfxTransitions = new GfxTransitions(_gfxScreen, _gfxPalette16); _gfxPaint16 = new GfxPaint16(_resMan, _gamestate->_segMan, _gfxCache, _gfxPorts, _gfxCoordAdjuster, _gfxScreen, _gfxPalette16, _gfxTransitions, _audio); _gfxPaint = _gfxPaint16; - _gfxAnimate = new GfxAnimate(_gamestate, _gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen, _gfxPalette16, _gfxCursor, _gfxTransitions); + _gfxAnimate = new GfxAnimate(_gamestate, _scriptPatcher, _gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen, _gfxPalette16, _gfxCursor, _gfxTransitions); _gfxText16 = new GfxText16(_gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen); _gfxControls16 = new GfxControls16(_gamestate->_segMan, _gfxPorts, _gfxPaint16, _gfxText16, _gfxScreen); _gfxMenu = new GfxMenu(_eventMan, _gamestate->_segMan, _gfxPorts, _gfxPaint16, _gfxText16, _gfxScreen, _gfxCursor); @@ -820,7 +836,7 @@ Console *SciEngine::getSciDebugger() { } const char *SciEngine::getGameIdStr() const { - return _gameDescription->gameid; + return _gameDescription->gameId; } Common::Language SciEngine::getLanguage() const { @@ -897,12 +913,30 @@ int SciEngine::inQfGImportRoom() const { void SciEngine::setLauncherLanguage() { if (_gameDescription->flags & ADGF_ADDENGLISH) { // If game is multilingual - if (Common::parseLanguage(ConfMan.get("language")) == Common::EN_ANY) { + Common::Language chosenLanguage = Common::parseLanguage(ConfMan.get("language")); + uint16 languageToSet = 0; + + switch (chosenLanguage) { + case Common::EN_ANY: // and English was selected as language - if (SELECTOR(printLang) != -1) // set text language to English - writeSelectorValue(_gamestate->_segMan, _gameObjectAddress, SELECTOR(printLang), K_LANG_ENGLISH); - if (SELECTOR(parseLang) != -1) // and set parser language to English as well - writeSelectorValue(_gamestate->_segMan, _gameObjectAddress, SELECTOR(parseLang), K_LANG_ENGLISH); + languageToSet = K_LANG_ENGLISH; + break; + case Common::JA_JPN: { + // Set Japanese for FM-Towns games + // KQ5 on FM-Towns has no initial language set + if (g_sci->getPlatform() == Common::kPlatformFMTowns) { + languageToSet = K_LANG_JAPANESE; + } + } + default: + break; + } + + if (languageToSet) { + if (SELECTOR(printLang) != -1) // set text language + writeSelectorValue(_gamestate->_segMan, _gameObjectAddress, SELECTOR(printLang), languageToSet); + if (SELECTOR(parseLang) != -1) // and set parser language as well + writeSelectorValue(_gamestate->_segMan, _gameObjectAddress, SELECTOR(parseLang), languageToSet); } } } diff --git a/engines/sci/sci.h b/engines/sci/sci.h index 5c86d92355..7df3d38163 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -71,6 +71,8 @@ class GfxPaint16; class GfxPaint32; class GfxPalette; class GfxPalette32; +class GfxRemap; +class GfxRemap32; class GfxPorts; class GfxScreen; class GfxText16; @@ -128,6 +130,7 @@ enum SciGameId { GID_FAIRYTALES, GID_FREDDYPHARKAS, GID_FUNSEEKER, + GID_GK1DEMO, // We have a separate ID for GK1 demo, because it's actually a completely different game (SCI1.1 vs SCI2/SCI2.1) GID_GK1, GID_GK2, GID_HOYLE1, @@ -165,12 +168,14 @@ enum SciGameId { GID_PQ2, GID_PQ3, GID_PQ4, + GID_PQ4DEMO, // We have a separate ID for PQ4 demo, because it's actually a completely different game (SCI1.1 vs SCI2/SCI2.1) GID_PQSWAT, GID_QFG1, GID_QFG1VGA, GID_QFG2, GID_QFG3, GID_QFG4, + GID_QFG4DEMO, // We have a separate ID for QFG4 demo, because it's actually a completely different game (SCI1.1 vs SCI2/SCI2.1) GID_RAMA, GID_SHIVERS, //GID_SHIVERS2, // Not SCI @@ -201,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 }; @@ -282,7 +287,7 @@ public: inline EngineState *getEngineState() const { return _gamestate; } inline Vocabulary *getVocabulary() const { return _vocabulary; } inline EventManager *getEventManager() const { return _eventMan; } - inline reg_t getGameObject() const { return _gameObjectAddress; } + inline reg_t getGameObject() const { return _gameObjectAddress; } // Gets the game object VM address Common::RandomSource &getRNG() { return _rng; } @@ -349,6 +354,8 @@ public: GfxMenu *_gfxMenu; // Menu for 16-bit gfx GfxPalette *_gfxPalette16; GfxPalette32 *_gfxPalette32; // Palette for 32-bit gfx + GfxRemap *_gfxRemap16; // Remapping for the QFG4 demo + GfxRemap32 *_gfxRemap32; // Remapping for 32-bit gfx GfxPaint *_gfxPaint; GfxPaint16 *_gfxPaint16; // Painting in 16-bit gfx GfxPaint32 *_gfxPaint32; // Painting in 32-bit gfx diff --git a/engines/sci/sound/drivers/amigamac.cpp b/engines/sci/sound/drivers/amigamac.cpp index 5ce49086ca..0f93b19e7c 100644 --- a/engines/sci/sound/drivers/amigamac.cpp +++ b/engines/sci/sound/drivers/amigamac.cpp @@ -497,7 +497,7 @@ MidiDriver_AmigaMac::InstrumentSample *MidiDriver_AmigaMac::readInstrumentSCI0(C } instrument->samples = (int8 *) malloc(size + 1); - if (file.read(instrument->samples, size) < (unsigned int)size) { + if (file.read(instrument->samples, size) < (uint32)size) { warning("Amiga/Mac driver: failed to read instrument samples"); free(instrument->samples); delete instrument; diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index ee5903fda2..e7b25eb1fc 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -44,7 +44,7 @@ SoundCommandParser::SoundCommandParser(ResourceManager *resMan, SegManager *segM // resource number, but it's totally unrelated to the menu music). // The GK1 demo (very late SCI1.1) does the same thing // TODO: Check the QFG4 demo - _useDigitalSFX = (getSciVersion() >= SCI_VERSION_2 || g_sci->getGameId() == GID_GK1 || ConfMan.getBool("prefer_digitalsfx")); + _useDigitalSFX = (getSciVersion() >= SCI_VERSION_2 || g_sci->getGameId() == GID_GK1DEMO || ConfMan.getBool("prefer_digitalsfx")); _music = new SciMusic(_soundVersion, _useDigitalSFX); _music->init(); diff --git a/engines/sci/util.cpp b/engines/sci/util.cpp index c72d3beb19..ccec41a1ab 100644 --- a/engines/sci/util.cpp +++ b/engines/sci/util.cpp @@ -69,4 +69,13 @@ void WRITE_SCI11ENDIAN_UINT16(void *ptr, uint16 val) { WRITE_LE_UINT16(ptr, val); } +#ifdef ENABLE_SCI32 +void WRITE_SCI11ENDIAN_UINT32(void *ptr, uint32 val) { + if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1) + WRITE_BE_UINT32(ptr, val); + else + WRITE_LE_UINT32(ptr, val); +} +#endif + } // End of namespace Sci diff --git a/engines/sci/util.h b/engines/sci/util.h index 378030939c..b0fee5151e 100644 --- a/engines/sci/util.h +++ b/engines/sci/util.h @@ -37,6 +37,9 @@ void WRITE_SCIENDIAN_UINT16(void *ptr, uint16 val); uint16 READ_SCI11ENDIAN_UINT16(const void *ptr); uint32 READ_SCI11ENDIAN_UINT32(const void *ptr); void WRITE_SCI11ENDIAN_UINT16(void *ptr, uint16 val); +#ifdef ENABLE_SCI32 +void WRITE_SCI11ENDIAN_UINT32(void *ptr, uint32 val); +#endif // Wrappers for reading integer values in resources that are // LE in SCI1.1 Mac, but BE in SCI32 Mac diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index 0d7ea39ec2..3a69b5f03c 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -861,7 +861,7 @@ L2C36:; stopActorMoving(); return; } - // 2C98: Yes, an exact copy of what just occured.. the original does this, so im doing it... + // 2C98: Yes, an exact copy of what just occurred.. the original does this, so im doing it... // Just to keep me sane when going over it :) if (A == 0xFF) { setActorFromTmp(); diff --git a/engines/scumm/charset-fontdata.cpp b/engines/scumm/charset-fontdata.cpp index 23e89b1878..a1e92a9950 100644 --- a/engines/scumm/charset-fontdata.cpp +++ b/engines/scumm/charset-fontdata.cpp @@ -591,35 +591,40 @@ CharsetRendererV2::CharsetRendererV2(ScummEngine *vm, Common::Language language) _fontHeight = 8; _curId = 0; - const byte *replacementData = NULL; + const byte *replacementMap = NULL, *replacementData = NULL; int replacementChars = 0; switch (language) { case Common::DE_DEU: if (_vm->_game.version == 0) { - replacementData = germanCharsetDataV0; + replacementMap = germanCharsetDataV0; replacementChars = sizeof(germanCharsetDataV0) / 2; } else { - replacementData = germanCharsetDataV2; + replacementMap = germanCharsetDataV2; replacementChars = sizeof(germanCharsetDataV2) / 2; } + replacementData = specialCharsetData; break; case Common::FR_FRA: - replacementData = frenchCharsetDataV2; + replacementMap = frenchCharsetDataV2; replacementChars = sizeof(frenchCharsetDataV2) / 2; + replacementData = specialCharsetData; break; case Common::IT_ITA: - replacementData = italianCharsetDataV2; + replacementMap = italianCharsetDataV2; replacementChars = sizeof(italianCharsetDataV2) / 2; + replacementData = specialCharsetData; break; case Common::ES_ESP: - replacementData = spanishCharsetDataV2; + replacementMap = spanishCharsetDataV2; replacementChars = sizeof(spanishCharsetDataV2) / 2; + replacementData = specialCharsetData; break; case Common::RU_RUS: if (((_vm->_game.id == GID_MANIAC) || (_vm->_game.id == GID_ZAK)) && (_vm->_game.version == 2)) { - replacementData = russCharsetDataV2; + replacementMap = russCharsetDataV2; replacementChars = sizeof(russCharsetDataV2) / 2; + replacementData = russianCharsetDataV2; } else { _fontPtr = russianCharsetDataV2; } @@ -629,20 +634,16 @@ CharsetRendererV2::CharsetRendererV2(ScummEngine *vm, Common::Language language) break; } - if (replacementData) { + if (replacementMap && replacementData) { _fontPtr = new byte[sizeof(englishCharsetDataV2)]; _deleteFontPtr = true; memcpy(const_cast<byte *>(_fontPtr), englishCharsetDataV2, sizeof(englishCharsetDataV2)); for (int i = 0; i < replacementChars; i++) { - int ch1 = replacementData[2 * i]; - int ch2 = replacementData[2 * i + 1]; + int ch1 = replacementMap[2 * i]; + int ch2 = replacementMap[2 * i + 1]; - if (((_vm->_game.id == GID_MANIAC) || (_vm->_game.id == GID_ZAK)) && (_vm->_game.version == 2)) { - memcpy(const_cast<byte *>(_fontPtr) + 8 * ch1, russianCharsetDataV2 + 8 * ch2, 8); - } else { - memcpy(const_cast<byte *>(_fontPtr) + 8 * ch1, specialCharsetData + 8 * ch2, 8); - } + memcpy(const_cast<byte *>(_fontPtr) + 8 * ch1, replacementData + 8 * ch2, 8); } } else _deleteFontPtr = false; diff --git a/engines/scumm/configure.engine b/engines/scumm/configure.engine index e1de788061..e8962a371e 100644 --- a/engines/scumm/configure.engine +++ b/engines/scumm/configure.engine @@ -2,4 +2,4 @@ # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] add_engine scumm "SCUMM" yes "scumm_7_8 he" "v0-v6 games" add_engine scumm_7_8 "v7 & v8 games" yes -add_engine he "HE71+ games" yes +add_engine he "HE71+ games" yes "" "" "highres" diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index e5bbad15e6..9264a6443b 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -1271,7 +1271,6 @@ SaveStateList ScummMetaEngine::listSaves(const char *target) const { pattern += ".s##"; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -1288,6 +1287,8 @@ SaveStateList ScummMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/scumm/he/sound_he.cpp b/engines/scumm/he/sound_he.cpp index a78aff96f8..b806a9f3cc 100644 --- a/engines/scumm/he/sound_he.cpp +++ b/engines/scumm/he/sound_he.cpp @@ -636,7 +636,7 @@ void SoundHE::playHESound(int soundID, int heOffset, int heChannel, int heFlags) if (heFlags & 1) { _heChannel[heChannel].timer = 0; } else { - _heChannel[heChannel].timer = size * 1000 / rate; + _heChannel[heChannel].timer = size * 1000 / (rate * blockAlign); } _mixer->stopHandle(_heSoundChannels[heChannel]); @@ -658,7 +658,7 @@ void SoundHE::playHESound(int soundID, int heOffset, int heChannel, int heFlags) _heChannel[heChannel].rate = rate; if (_heChannel[heChannel].timer) - _heChannel[heChannel].timer = size * 1000 / rate; + _heChannel[heChannel].timer = size * 1000 / (rate * blockAlign); // makeADPCMStream returns a stream in native endianness, but RawMemoryStream // defaults to big endian. If we're on a little endian system, set the LE flag. diff --git a/engines/scumm/imuse_digi/dimuse_track.cpp b/engines/scumm/imuse_digi/dimuse_track.cpp index b7abdd074e..28ad64670c 100644 --- a/engines/scumm/imuse_digi/dimuse_track.cpp +++ b/engines/scumm/imuse_digi/dimuse_track.cpp @@ -352,9 +352,9 @@ Track *IMuseDigital::cloneToFadeOutTrack(Track *track, int fadeDelay) { // leaving bug number for now #1635361 ImuseDigiSndMgr::SoundDesc *soundDesc = _sound->cloneSound(track->soundDesc); if (!soundDesc) { - // it fail load open old song after switch to diffrent CDs + // it fail load open old song after switch to different CDs // so gave up - error("Game not supported while playing on 2 diffrent CDs"); + error("Game not supported while playing on 2 different CDs"); } track->soundDesc = soundDesc; 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/scumm/players/player_v4a.cpp b/engines/scumm/players/player_v4a.cpp index bd8ce3f7ad..58f53a6d7f 100644 --- a/engines/scumm/players/player_v4a.cpp +++ b/engines/scumm/players/player_v4a.cpp @@ -174,7 +174,7 @@ int Player_V4A::getMusicTimer() { return 2000; if (_musicId) { // The titlesong (and a few others) is running with ~70 ticks per second and the scale seems to be based on that. - // The Game itself doesnt get the timing from the Tfmx Player however, so we just use the elapsed time + // The Game itself doesn't get the timing from the Tfmx Player however, so we just use the elapsed time // 357 ~ 1000 * 25 * (1 / 70) return _mixer->getSoundElapsedTime(_musicHandle) / 357; } @@ -183,7 +183,7 @@ int Player_V4A::getMusicTimer() { int Player_V4A::getSoundStatus(int nr) const { // For music the game queues a variable the Tfmx Player sets through a special command. - // For sfx there seems to be no way to queue them, and the game doesnt try to. + // For sfx there seems to be no way to queue them, and the game doesn't try to. return (nr == _musicId) ? _signal : 0; } diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index e5673c1803..f3df24ff51 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -1303,7 +1303,7 @@ void ScummEngine::saveOrLoad(Serializer *s) { if (hasTownsData) { // Skip FM-Towns specific data - for (int i = 69 * sizeof(uint8) + 44 * sizeof(int16); i; i--) + for (i = 69 * sizeof(uint8) + 44 * sizeof(int16); i; i--) s->loadByte(); } diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index 24d676a1ff..89d2d3dc72 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -2611,8 +2611,12 @@ bool ScummEngine::startManiac() { Common::String path = dom.getVal("path"); if (path.hasPrefix(currentPath)) { - path.erase(0, currentPath.size() + 1); - if (path.equalsIgnoreCase("maniac")) { + path.erase(0, currentPath.size()); + // Do a case-insensitive non-path-mode match of the remainder. + // While strictly speaking it's too broad, this matchString + // ignores the presence or absence of trailing path separators + // in either currentPath or path. + if (path.matchString("*maniac*", true, false)) { maniacTarget = iter->_key; break; } diff --git a/engines/scumm/scumm_v4.h b/engines/scumm/scumm_v4.h index 28f619ceaa..a008023ff9 100644 --- a/engines/scumm/scumm_v4.h +++ b/engines/scumm/scumm_v4.h @@ -35,7 +35,7 @@ class ScummEngine_v4 : public ScummEngine_v5 { public: /** - * Prepared savegame used by the orginal save/load dialog. + * Prepared savegame used by the original save/load dialog. * Must be valid as long as the savescreen is active. As we are not * notified when the savescreen is closed, memory is only freed on a game * reset, at the destruction of the engine or when the original save/load diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index 84d2b37f96..4d70ee8482 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -240,7 +240,7 @@ void Sound::playSound(int soundID) { // mentioned in the bug report above; in case it is, I put a check here. assert(soundID == 39); - // The samplerate is copied from the sound resouce 39 of the PC CD/VGA + // The samplerate is copied from the sound resource 39 of the PC CD/VGA // version of Monkey Island. // Read info from the header diff --git a/engines/sherlock/POTFILES b/engines/sherlock/POTFILES new file mode 100644 index 0000000000..b9f1c1249f --- /dev/null +++ b/engines/sherlock/POTFILES @@ -0,0 +1,3 @@ +engines/sherlock/detection.cpp +engines/sherlock/scalpel/scalpel.cpp +engines/sherlock/tattoo/widget_files.cpp diff --git a/engines/sherlock/animation.cpp b/engines/sherlock/animation.cpp index 681e71d0f6..4442c1da85 100644 --- a/engines/sherlock/animation.cpp +++ b/engines/sherlock/animation.cpp @@ -23,6 +23,8 @@ #include "sherlock/animation.h" #include "sherlock/sherlock.h" #include "sherlock/scalpel/scalpel_screen.h" +#include "sherlock/scalpel/3do/scalpel_3do_screen.h" + #include "common/algorithm.h" namespace Sherlock { @@ -89,7 +91,7 @@ bool Animation::play(const Common::String &filename, bool intro, int minDelay, i // Draw the sprite. Note that we explicitly use the raw frame below, rather than the ImageFrame, // since we don't want the offsets in the image file to be used, just the explicit position we specify - screen.transBlitFrom(images[imageFrame]._frame, pt); + screen.SHtransBlitFrom(images[imageFrame]._frame, pt); } else { // At this point, either the sprites for the frame has been complete, or there weren't any sprites // at all to draw for the frame @@ -201,7 +203,7 @@ bool Animation::play3DO(const Common::String &filename, bool intro, int minDelay // Draw the sprite. Note that we explicitly use the raw frame below, rather than the ImageFrame, // since we don't want the offsets in the image file to be used, just the explicit position we specify - screen._backBuffer1.transBlitFrom(images[imageFrame]._frame, pt); + screen._backBuffer1.SHtransBlitFrom(images[imageFrame]._frame, pt); if (!fadeActive) screen.slamArea(pt.x, pt.y, images[imageFrame]._frame.w, images[imageFrame]._frame.h); } else { diff --git a/engines/sherlock/events.cpp b/engines/sherlock/events.cpp index 4b0b7dfb3f..6cfee5d822 100644 --- a/engines/sherlock/events.cpp +++ b/engines/sherlock/events.cpp @@ -143,7 +143,7 @@ void Events::setCursor(CursorId cursorId, const Common::Point &cursorPos, const // Form a single surface containing both frames Surface s(r.width(), r.height()); - s.fill(TRANSPARENCY); + s.clear(TRANSPARENCY); // Draw the passed image Common::Point drawPos; @@ -151,11 +151,11 @@ void Events::setCursor(CursorId cursorId, const Common::Point &cursorPos, const drawPos.x = -cursorPt.x; if (cursorPt.y < 0) drawPos.y = -cursorPt.y; - s.blitFrom(surface, Common::Point(drawPos.x, drawPos.y)); + s.SHblitFrom(surface, Common::Point(drawPos.x, drawPos.y)); // Draw the cursor image drawPos = Common::Point(MAX(cursorPt.x, (int16)0), MAX(cursorPt.y, (int16)0)); - s.transBlitFrom(cursorImg, Common::Point(drawPos.x, drawPos.y)); + s.SHtransBlitFrom(cursorImg, Common::Point(drawPos.x, drawPos.y)); // Set up hotspot position for cursor, adjusting for cursor image's position within the surface Common::Point hotspot; @@ -163,7 +163,7 @@ void Events::setCursor(CursorId cursorId, const Common::Point &cursorPos, const hotspot = Common::Point(8, 8); hotspot += drawPos; // Set the cursor - setCursor(s.getRawSurface(), hotspot.x, hotspot.y); + setCursor(s, hotspot.x, hotspot.y); } void Events::animateCursorIfNeeded() { diff --git a/engines/sherlock/fixed_text.cpp b/engines/sherlock/fixed_text.cpp index cbee944120..4679fe58b8 100644 --- a/engines/sherlock/fixed_text.cpp +++ b/engines/sherlock/fixed_text.cpp @@ -27,6 +27,183 @@ namespace Sherlock { +static const char *const fixedJournalTextEN[] = { + // Holmes asked/said... + "Holmes asked me, ", + "Holmes asked the Inspector, ", + "Holmes asked %s, ", + "Holmes said to me, ", + "Holmes said to the Inspector, ", + "Holmes said to %s, ", + // I asked/said... + "I replied, ", + "The reply was, ", + // Holmes/I/The Inspector/Person asked/said (without "Then" prefix) + "Holmes asked, ", + "Holmes said, ", + "I asked, ", + "I said, ", + "The Inspector asked, ", + "The Inspector said, ", + "%s asked, ", + "%s said, ", + // Then Holmes/I/The Inspector/Person asked/said + "Then Holmes asked, ", + "Then Holmes said, ", + "Then I asked, ", + "Then I said, ", + "Then the Inspector asked, ", + "Then the Inspector said, ", + "Then %s asked, ", + "Then %s said, " +}; + +static const char *const fixedJournalTextDE[] = { + // Holmes asked/said... + "Holmes fragte mich, ", + "Holmes fragte Inspektor Lestrade, ", + "Holmes fragte %s, ", + "Holmes sagte mir, ", + "Holmes sagte Inspektor Lestrade, ", + "Holmes sagte %s, ", + // I asked/said... + "Ich antwortete, ", + "Die Antwort lautete, ", + // Holmes/I/The Inspector/Person asked/said (without "Then" prefix) + "Holmes fragte, ", // original: "fragte Holmes" + "Holmes sagte, ", // original: "sagte Holmes" + "Ich fragte, ", // original: "fragte Ich" + "Ich sagte, ", // original: "sagte Ich" + "Der Inspektor fragte, ", + "Der Inspektor sagte, ", + "%s fragte, ", + "%s sagte, ", + // Then Holmes/I/The Inspector/Person asked/said + "Dann fragte Holmes, ", + "Dann sagte Holmes, ", + "Dann fragte ich, ", // original: "Dann sagte Ich" + "Dann sagte ich, ", // original: "Dann sagte Ich" + "Dann fragte der Inspektor, ", + "Dann sagte der Inspektor, ", + "Dann fragte %s, ", + "Dann sagte %s, " +}; + +// Only used for Sherlock Holmes 2, so special characters should use the SH2 charset +// small a w/ accent grave: 0x85 / octal 205 +// small e w/ accent acute: 0x82 / octal 202 +// small e w/ accent grave: 0x8A / octal 212 +// small e w/ circonflexe: 0x88 / octal 210 +// small cedilla: 0x87 / octal 207 +static const char *const fixedJournalTextFR[] = { + // Holmes asked/said... + "Holmes me demanda, ", // original: "Holmes m'a demand\202, " + "Holmes demanda \205 l'inspecteur, ", // original: "Holmes a demand\202 \205 l'inspecteur, " + "Holmes demanda \205 %s, ", // original: "Holmes a demand\202 \205 %s, " + "Holmes me dit, ", // original: "Holmes m'a dit, " + "Holmes dit \205 l'inspecteur, ", // original: "Holmes a dit \205 l'inspecteur, " + "Holmes dit \205 %s, ", // original: "Holmes a dit \205 %s, " + // I asked/said... + "Je r\202pondis, ", // original: "J'ai r\202pondu, ", + "La r\202ponse fut, ", + // Holmes/I/The Inspector/Person asked/said (without "Then" prefix) + "Holmes demanda, ", // original: "Holmes a demand\202, " + "Holmes dit, ", + "Je demandai, ", // original: "J'ai demand\202, " + "Je dis, ", // original: "J'ai dit, " + "L'inspecteur demanda, ", // original: ""L'inspecteur a demand\202, " + "L'inspecteur dit, ", + "%s demanda, ", // original: "%s a demand\202, " + "%s dit, ", + // Then Holmes/I/The Inspector/Person asked/said + "Alors Holmes demanda, ", // original: it seems "puis"/"then" was not used/removed. They instead added a space character, so sentences looked weird + "Alors Holmes dit, ", + "Alors je demandai, ", + "Alors je dis, ", + "Alors l'inspecteur demanda, ", + "Alors l'inspecteur dit, ", + "Alors %s demanda, ", + "Alors %s dit, " +}; + +// Sherlock Holmes 1+2: +// small e w/ accent bottom to top : 0x82 / octal 202 +// big E w/ accent bottom to top : 0x90 / octal 220 +// small a w/ accent bottom to top : 0xA0 / octal 240 +// small i w/ accent bottom to top : 0xA1 / octal 241 +// small o w/ accent bottom to top : 0xA2 / octal 242 +// small u w/ accent bottom to top : 0xA3 / octal 243 +// small n w/ wavy line : 0xA4 / octal 244 +// big N w/ wavy line : 0xA5 / octal 245 +// small a w/ under line : 0xA6 / octal 246 +// small o w/ under line : 0xA7 / octal 247 +// inverted question mark : 0xA8 / octal 250 +static const char *const fixedJournalTextES[] = { + // Holmes asked/said... + "Holmes me pregunt\242, ", // original: "Holmes me pidi\242, ", + "Holmes pregunt\242 al Inspector, ", // original: "el inspector"? + "Holmes pregunt\242 %s, ", + "Holmes me dijo, ", + "Holmes dijo al Inspector, ", // original: "el inspector"? + "Holmes dijo a %s, ", // original: "Holmes dijo a %s, " + // I asked/said... + "Yo content\202, ", // original: "Yo respond\241, ", + "La respuesta fue, ", + // Holmes/I/The Inspector/Person asked/said (without "Then" prefix) + "Holmes pregunt\242, ", + "Holmes dijo, ", + "Yo pregunt\202, ", // original: "Yo pregunt\242, ", + "Yo dije, ", + "El Inspector pregunt\242, ", + "El Inspector dijo, ", + "%s pregunt\242, ", + "%s dijo, ", + // Then Holmes/I/The Inspector/Person asked/said + "Despu\202s Holmes pregunt\242, ", // original: added "Entonces" instead of "Despues" + "Despu\202s Holmes dijo, ", + "Despu\202s yo pregunt\202, ", // "pregunt\242, " + "Despu\202s yo dije, ", + "Despu\202s el Inspector pregunt\242, ", + "Despu\202s el Inspector dijo, ", + "Despu\202s %s pregunt\242, ", + "Despu\202s %s dijo, " +}; + +FixedText::FixedText(SherlockEngine *vm) { + _vm = vm; + + // Figure out which fixed texts to use + Common::Language curLanguage = _vm->getLanguage(); + + switch (curLanguage) { + case Common::EN_ANY: + // Used by Sherlock Holmes 1+2 + _fixedJournalTextArray = fixedJournalTextEN; + _fixedObjectPickedUpText = "Picked up %s"; + break; + case Common::DE_DEU: + // Used by Sherlock Holmes 1+2 + _fixedJournalTextArray = fixedJournalTextDE; + _fixedObjectPickedUpText = "%s eingesteckt"; + break; + case Common::FR_FRA: + // Used by Sherlock Holmes 2 + _fixedJournalTextArray = fixedJournalTextFR; + _fixedObjectPickedUpText = ""; // Not used, because there is no French Sherlock Holmes 1 + break; + case Common::ES_ESP: + // Used by Sherlock Holmes 1+2 + _fixedJournalTextArray = fixedJournalTextES; + _fixedObjectPickedUpText = "Cogido/a %s"; + break; + default: + // Default to English + _fixedJournalTextArray = fixedJournalTextEN; + _fixedObjectPickedUpText = "Picked up %s"; + break; + } +} + FixedText *FixedText::init(SherlockEngine *vm) { if (vm->getGameID() == GType_SerratedScalpel) return new Scalpel::ScalpelFixedText(vm); @@ -34,5 +211,12 @@ FixedText *FixedText::init(SherlockEngine *vm) { return new Tattoo::TattooFixedText(vm); } +const char *FixedText::getJournalText(int fixedJournalTextId) { + return _fixedJournalTextArray[fixedJournalTextId]; +} + +const char *FixedText::getObjectPickedUpText() { + return _fixedObjectPickedUpText; +} } // End of namespace Sherlock diff --git a/engines/sherlock/fixed_text.h b/engines/sherlock/fixed_text.h index 40444f4052..3eae60e1c3 100644 --- a/engines/sherlock/fixed_text.h +++ b/engines/sherlock/fixed_text.h @@ -39,13 +39,44 @@ enum FixedTextActionId { kFixedTextAction_Use }; +enum FixedJournalTextId { + // Holmes asked/said... + kFixedJournalText_HolmesAskedMe = 0, + kFixedJournalText_HolmesAskedTheInspector, + kFixedJournalText_HolmesAskedPerson, + kFixedJournalText_HolmesSaidToMe, + kFixedJournalText_HolmesSaidToTheInspector, + kFixedJournalText_HolmesSaidToPerson, + // I asked/said + kFixedJournalText_IReplied, + kFixedJournalText_TheReplyWas, + // Holmes/I/The Inspector/Person asked/said (without "Then" prefix) + kFixedJournalText_HolmesAsked, + kFixedJournalText_HolmesSaid, + kFixedJournalText_IAsked, + kFixedJournalText_ISaid, + kFixedJournalText_TheInspectorAsked, + kFixedJournalText_TheInspectorSaid, + kFixedJournalText_PersonAsked, + kFixedJournalText_PersonSaid, + // Then Holmes/I/The Inspector/Person asked/said + kFixedJournalText_ThenHolmesAsked, + kFixedJournalText_ThenHolmesSaid, + kFixedJournalText_ThenIAsked, + kFixedJournalText_ThenISaid, + kFixedJournalText_ThenTheInspectorAsked, + kFixedJournalText_ThenTheInspectorSaid, + kFixedJournalText_ThenPersonAsked, + kFixedJournalText_ThenPersonSaid +}; + class SherlockEngine; class FixedText { protected: SherlockEngine *_vm; - FixedText(SherlockEngine *vm) : _vm(vm) {} + FixedText(SherlockEngine *vm); public: static FixedText *init(SherlockEngine *vm); virtual ~FixedText() {} @@ -59,6 +90,20 @@ public: * Get action message */ virtual const Common::String getActionMessage(FixedTextActionId actionId, int messageIndex) = 0; + + /** + * Gets journal text + */ + const char *getJournalText(int fixedJournalTextId); + + /** + * Gets object "Picked Up" text + */ + const char *getObjectPickedUpText(); + +private: + const char *const *_fixedJournalTextArray; + const char *_fixedObjectPickedUpText; }; } // End of namespace Sherlock diff --git a/engines/sherlock/fonts.cpp b/engines/sherlock/fonts.cpp index 8e36c3908a..5a14881f1c 100644 --- a/engines/sherlock/fonts.cpp +++ b/engines/sherlock/fonts.cpp @@ -43,7 +43,7 @@ void Fonts::setVm(SherlockEngine *vm) { _charCount = 0; } -void Fonts::free() { +void Fonts::freeFont() { delete _font; } @@ -213,7 +213,7 @@ void Fonts::writeString(Surface *surface, const Common::String &str, if (curChar < _charCount) { ImageFrame &frame = (*_font)[curChar]; - surface->transBlitFrom(frame, Common::Point(charPos.x, charPos.y + _yOffsets[curChar]), false, overrideColor); + surface->SHtransBlitFrom(frame, Common::Point(charPos.x, charPos.y + _yOffsets[curChar]), false, overrideColor); charPos.x += frame._frame.w + 1; } else { warning("Invalid character encountered - %d", (int)curChar); diff --git a/engines/sherlock/fonts.h b/engines/sherlock/fonts.h index a527cc73c0..3594d466c2 100644 --- a/engines/sherlock/fonts.h +++ b/engines/sherlock/fonts.h @@ -57,7 +57,7 @@ public: /** * Frees the font manager */ - static void free(); + static void freeFont(); /** * Set the font to use for writing text on the screen diff --git a/engines/sherlock/image_file.h b/engines/sherlock/image_file.h index da260ab30b..778332b726 100644 --- a/engines/sherlock/image_file.h +++ b/engines/sherlock/image_file.h @@ -46,6 +46,11 @@ struct ImageFrame { Graphics::Surface _frame; /** + * Converts an ImageFrame record to a surface for convenience in passing to drawing methods + */ + operator const Graphics::Surface &() { return _frame; } + + /** * Decompress a single frame for the sprite */ void decompressFrame(const byte *src, bool isRoseTattoo); diff --git a/engines/sherlock/journal.cpp b/engines/sherlock/journal.cpp index a30734c4f5..8763af31dd 100644 --- a/engines/sherlock/journal.cpp +++ b/engines/sherlock/journal.cpp @@ -299,6 +299,7 @@ bool Journal::drawJournal(int direction, int howFar) { } void Journal::loadJournalFile(bool alreadyLoaded) { + FixedText &fixedText = *_vm->_fixedText; People &people = *_vm->_people; Screen &screen = *_vm->_screen; Talk &talk = *_vm->_talk; @@ -381,20 +382,34 @@ void Journal::loadJournalFile(bool alreadyLoaded) { // If Holmes has something to say first, then take care of it if (!replyOnly) { // Handle the grammar - journalString += "Holmes "; + bool asked = false; + if (talk[journalEntry._statementNum]._statement.hasSuffix("?")) - journalString += "asked "; - else - journalString += "said to "; + asked = true; if (talk._talkTo == 1) { - journalString += "me"; + if (asked) + journalString += fixedText.getJournalText(kFixedJournalText_HolmesAskedMe); + else + journalString += fixedText.getJournalText(kFixedJournalText_HolmesSaidToTheInspector); + } else if ((talk._talkTo == 2 && IS_SERRATED_SCALPEL) || (talk._talkTo == 18 && IS_ROSE_TATTOO)) { - journalString += "the Inspector"; + if (asked) + journalString += fixedText.getJournalText(kFixedJournalText_HolmesAskedTheInspector); + else + journalString += fixedText.getJournalText(kFixedJournalText_HolmesSaidToMe); + } else { - journalString += people._characters[talk._talkTo]._name; + const char *text = nullptr; + if (asked) + text = fixedText.getJournalText(kFixedJournalText_HolmesAskedPerson); + else + text = fixedText.getJournalText(kFixedJournalText_HolmesSaidToPerson); + + journalString += Common::String::format(text, people._characters[talk._talkTo]._name); } - journalString += ", \""; + + journalString += "\""; // Add the statement journalString += statement._statement; @@ -457,29 +472,46 @@ void Journal::loadJournalFile(bool alreadyLoaded) { journalString += "\"\n"; if (talk._talkTo == 1) - journalString += "I replied, \""; + journalString += fixedText.getJournalText(kFixedJournalText_IReplied); else - journalString += "The reply was, \""; + journalString += fixedText.getJournalText(kFixedJournalText_TheReplyWas); } else { - if (talk._talkTo == 1) - journalString += "I"; - else if (talk._talkTo == inspectorId) - journalString += "The Inspector"; - else - journalString += people._characters[talk._talkTo]._name; - const byte *strP = replyP + 1; byte v; do { v = *strP++; } while (v && (v < opcodes[0]) && (v != '.') && (v != '!') && (v != '?')); + bool asked = false; + if (v == '?') - journalString += " asked, \""; - else - journalString += " said, \""; + asked = true; + + if (talk._talkTo == 1) { + if (asked) + journalString += fixedText.getJournalText(kFixedJournalText_IAsked); + else + journalString += fixedText.getJournalText(kFixedJournalText_ISaid); + + } else if (talk._talkTo == inspectorId) { + if (asked) + journalString += fixedText.getJournalText(kFixedJournalText_TheInspectorAsked); + else + journalString += fixedText.getJournalText(kFixedJournalText_TheInspectorSaid); + + } else { + const char *text = nullptr; + if (asked) + text = fixedText.getJournalText(kFixedJournalText_PersonAsked); + else + text = fixedText.getJournalText(kFixedJournalText_PersonSaid); + + journalString += Common::String::format(text, people._characters[talk._talkTo]._name); + } } + journalString += "\""; + startOfReply = false; } @@ -502,11 +534,13 @@ void Journal::loadJournalFile(bool alreadyLoaded) { justChangedSpeaker = true; } + bool addPrefixThen = false; + if (!startOfReply) { if (!commentFlag && !commentJustPrinted) journalString += "\"\n"; - journalString += "Then "; + addPrefixThen = true; // "Then" should get added to the sentence commentFlag = false; } else if (!replyOnly) { journalString += "\"\n"; @@ -517,15 +551,6 @@ void Journal::loadJournalFile(bool alreadyLoaded) { if (IS_ROSE_TATTOO) replyP++; - if (c == 0) - journalString += "Holmes"; - else if (c == 1) - journalString += "I"; - else if (c == inspectorId) - journalString += "the Inspector"; - else - journalString += people._characters[c]._name; - if (IS_SERRATED_SCALPEL && _vm->getLanguage() == Common::DE_DEU) Scalpel::ScalpelTalk::skipBadText(replyP); @@ -535,10 +560,70 @@ void Journal::loadJournalFile(bool alreadyLoaded) { v = *strP++; } while (v && v < opcodes[0] && v != '.' && v != '!' && v != '?'); + bool asked = false; + if (v == '?') - journalString += " asked, \""; - else - journalString += " said, \""; + asked = true; + + if (c == 0) { + // Holmes + if (addPrefixThen) { + if (asked) + journalString += fixedText.getJournalText(kFixedJournalText_ThenHolmesAsked); + else + journalString += fixedText.getJournalText(kFixedJournalText_ThenHolmesSaid); + } else { + if (asked) + journalString += fixedText.getJournalText(kFixedJournalText_HolmesAsked); + else + journalString += fixedText.getJournalText(kFixedJournalText_HolmesSaid); + } + } else if (c == 1) { + // I (Watson) + if (addPrefixThen) { + if (asked) + journalString += fixedText.getJournalText(kFixedJournalText_ThenIAsked); + else + journalString += fixedText.getJournalText(kFixedJournalText_ThenISaid); + } else { + if (asked) + journalString += fixedText.getJournalText(kFixedJournalText_IAsked); + else + journalString += fixedText.getJournalText(kFixedJournalText_ISaid); + } + } else if (c == inspectorId) { + // The Inspector + if (addPrefixThen) { + if (asked) + journalString += fixedText.getJournalText(kFixedJournalText_ThenTheInspectorAsked); + else + journalString += fixedText.getJournalText(kFixedJournalText_ThenTheInspectorSaid); + } else { + if (asked) + journalString += fixedText.getJournalText(kFixedJournalText_TheInspectorAsked); + else + journalString += fixedText.getJournalText(kFixedJournalText_TheInspectorSaid); + } + } else { + // Person + const char *text = nullptr; + if (addPrefixThen) { + if (asked) + text = fixedText.getJournalText(kFixedJournalText_ThenPersonAsked); + else + text = fixedText.getJournalText(kFixedJournalText_ThenPersonSaid); + } else { + if (asked) + text = fixedText.getJournalText(kFixedJournalText_PersonAsked); + else + text = fixedText.getJournalText(kFixedJournalText_PersonSaid); + } + + journalString += Common::String::format(text, people._characters[c]._name); + } + + journalString += "\""; + } else { if (IS_SERRATED_SCALPEL) { // Control code, so move past it and any parameters @@ -718,8 +803,7 @@ bool Journal::isPrintable(byte ch) const { if (ch < opcodes[0]) return true; - if (_vm->getGameID() == GType_SerratedScalpel && _vm->getLanguage() == Common::DE_DEU - && ch >= 0xe0) + if (_vm->getLanguage() == Common::DE_DEU && ch == 0xe1) // accept German Sharp-S character return true; return false; diff --git a/engines/sherlock/module.mk b/engines/sherlock/module.mk index 7fa7896691..0d17d0b249 100644 --- a/engines/sherlock/module.mk +++ b/engines/sherlock/module.mk @@ -3,6 +3,7 @@ MODULE := engines/sherlock MODULE_OBJS = \ scalpel/scalpel.o \ scalpel/3do/movie_decoder.o \ + scalpel/3do/scalpel_3do_screen.o \ scalpel/drivers/adlib.o \ scalpel/drivers/mt32.o \ scalpel/tsage/logo.o \ @@ -30,6 +31,7 @@ MODULE_OBJS = \ tattoo/tattoo_people.o \ tattoo/tattoo_resources.o \ tattoo/tattoo_scene.o \ + tattoo/tattoo_screen.o \ tattoo/tattoo_talk.o \ tattoo/tattoo_user_interface.o \ tattoo/widget_base.o \ diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp index e70b707404..644c0c74c9 100644 --- a/engines/sherlock/objects.cpp +++ b/engines/sherlock/objects.cpp @@ -365,8 +365,8 @@ bool BaseObject::checkEndOfSequence() { if (seq == 99) { --_frameNumber; - screen._backBuffer1.transBlitFrom(*_imageFrame, _position); - screen._backBuffer2.transBlitFrom(*_imageFrame, _position); + screen._backBuffer1.SHtransBlitFrom(*_imageFrame, _position); + screen._backBuffer2.SHtransBlitFrom(*_imageFrame, _position); _type = INVALID; } else if (IS_ROSE_TATTOO && _talkSeq && seq == 0) { setObjTalkSequence(_talkSeq); @@ -1061,6 +1061,11 @@ void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) { for (int idx = 0; idx < 6; ++idx) _use[idx].load(s, true); + // WORKAROUND: Fix German version using hatpin/pin in pillow in Pratt's loft + if (_use[1]._target == "Nadel" && _use[1]._verb == "Untersuche" + && _use[2]._target == "Nadel" && _use[2]._verb == "Untersuche") + _use[1]._target = "Alte Nadel"; + _quickDraw = s.readByte(); _scaleVal = s.readUint16LE(); _requiredFlag[1] = s.readSint16LE(); @@ -1338,7 +1343,7 @@ void Object::adjustObject() { frame = 0; int imgNum = _sequences[frame]; - if (imgNum > _maxFrames) + if (imgNum > _maxFrames || imgNum == 0) imgNum = 1; _imageFrame = &(*_images)[imgNum - 1]; @@ -1424,8 +1429,19 @@ int Object::pickUpObject(FixedTextActionId fixedTextActionId) { ui.clearInfo(); Common::String itemName = _description; - itemName.setChar(tolower(itemName[0]), 0); - screen.print(Common::Point(0, INFO_LINE + 1), COL_INFO_FOREGROUND, "Picked up %s", itemName.c_str()); + + // It's an item, make it lowercase + switch (_vm->getLanguage()) { + case Common::DE_DEU: + // don't do this for German version + break; + default: + // do it for English + Spanish version + itemName.setChar(tolower(itemName[0]), 0); + break; + } + + screen.print(Common::Point(0, INFO_LINE + 1), COL_INFO_FOREGROUND, fixedText.getObjectPickedUpText(), itemName.c_str()); ui._menuCounter = 25; } } diff --git a/engines/sherlock/scalpel/3do/scalpel_3do_screen.cpp b/engines/sherlock/scalpel/3do/scalpel_3do_screen.cpp new file mode 100644 index 0000000000..f848394864 --- /dev/null +++ b/engines/sherlock/scalpel/3do/scalpel_3do_screen.cpp @@ -0,0 +1,286 @@ +/* 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 "sherlock/scalpel/scalpel_screen.h" +#include "sherlock/scalpel/scalpel.h" +#include "sherlock/scalpel/3do/scalpel_3do_screen.h" + +namespace Sherlock { + +namespace Scalpel { + +Scalpel3DOScreen::Scalpel3DOScreen(SherlockEngine *vm): ScalpelScreen(vm) { +} + +void Scalpel3DOScreen::SHblitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds) { + if (!_vm->_isScreenDoubled) { + ScalpelScreen::SHblitFrom(src, pt, srcBounds); + return; + } + + Common::Rect srcRect = srcBounds; + Common::Rect destRect(pt.x, pt.y, pt.x + srcRect.width(), pt.y + srcRect.height()); + + if (!srcRect.isValidRect() || !clip(srcRect, destRect)) + return; + + // Add dirty area remapped to the 640x200 surface + addDirtyRect(Common::Rect(destRect.left * 2, destRect.top * 2, destRect.right * 2, destRect.bottom * 2)); + + // Transfer the area, doubling each pixel + for (int yp = 0; yp < srcRect.height(); ++yp) { + const uint16 *srcP = (const uint16 *)src.getBasePtr(srcRect.left, srcRect.top + yp); + uint16 *destP = (uint16 *)getBasePtr(destRect.left * 2, (destRect.top + yp) * 2); + + for (int xp = srcRect.left; xp < srcRect.right; ++xp, ++srcP, destP += 2) { + *destP = *srcP; + *(destP + 1) = *srcP; + *(destP + 640) = *srcP; + *(destP + 640 + 1) = *srcP; + } + } +} + +void Scalpel3DOScreen::transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt, + bool flipped, int overrideColor) { + error("TODO: Refactor"); +#if 0 + if (!_vm->_isScreenDoubled) { + ScalpelScreen::transBlitFromUnscaled(src, pt, flipped, overrideColor); + return; + } + + Common::Rect drawRect(0, 0, src.w, src.h); + Common::Rect destRect(pt.x, pt.y, pt.x + src.w, pt.y + src.h); + + // Clip the display area to on-screen + if (!clip(drawRect, destRect)) + // It's completely off-screen + return; + + if (flipped) + drawRect = Common::Rect(src.w - drawRect.right, src.h - drawRect.bottom, + src.w - drawRect.left, src.h - drawRect.top); + + Common::Point destPt(destRect.left, destRect.top); + addDirtyRect(Common::Rect(destPt.x * 2, destPt.y * 2, (destPt.x + drawRect.width()) * 2, + (destPt.y + drawRect.height()) * 2)); + + assert(src.format.bytesPerPixel == 2 && _surface.format.bytesPerPixel == 2); + + for (int yp = 0; yp < drawRect.height(); ++yp) { + const uint16 *srcP = (const uint16 *)src.getBasePtr( + flipped ? drawRect.right - 1 : drawRect.left, drawRect.top + yp); + uint16 *destP = (uint16 *)getBasePtr(destPt.x * 2, (destPt.y + yp) * 2); + + for (int xp = 0; xp < drawRect.width(); ++xp, destP += 2) { + // RGB 0, 0, 0 -> transparent on 3DO + if (*srcP) { + *destP = *srcP; + *(destP + 1) = *srcP; + *(destP + 640) = *srcP; + *(destP + 640 + 1) = *srcP; + } + + srcP = flipped ? srcP - 1 : srcP + 1; + } + } +#endif +} + +void Scalpel3DOScreen::fillRect(const Common::Rect &r, uint color) { + if (_vm->_isScreenDoubled) + ScalpelScreen::fillRect(Common::Rect(r.left * 2, r.top * 2, r.right * 2, r.bottom * 2), color); + else + ScalpelScreen::fillRect(r, color); +} + +void Scalpel3DOScreen::fadeIntoScreen3DO(int speed) { + Events &events = *_vm->_events; + uint16 *currentScreenBasePtr = (uint16 *)getPixels(); + uint16 *targetScreenBasePtr = (uint16 *)_backBuffer->getPixels(); + uint16 currentScreenPixel = 0; + uint16 targetScreenPixel = 0; + + uint16 currentScreenPixelRed = 0; + uint16 currentScreenPixelGreen = 0; + uint16 currentScreenPixelBlue = 0; + + uint16 targetScreenPixelRed = 0; + uint16 targetScreenPixelGreen = 0; + uint16 targetScreenPixelBlue = 0; + + uint16 screenWidth = SHERLOCK_SCREEN_WIDTH; + uint16 screenHeight = SHERLOCK_SCREEN_HEIGHT; + uint16 screenX = 0; + uint16 screenY = 0; + uint16 pixelsChanged = 0; + + clearDirtyRects(); + + do { + pixelsChanged = 0; + uint16 *currentScreenPtr = currentScreenBasePtr; + uint16 *targetScreenPtr = targetScreenBasePtr; + + for (screenY = 0; screenY < screenHeight; screenY++) { + for (screenX = 0; screenX < screenWidth; screenX++) { + currentScreenPixel = *currentScreenPtr; + targetScreenPixel = *targetScreenPtr; + + if (currentScreenPixel != targetScreenPixel) { + // pixel doesn't match, adjust accordingly + currentScreenPixelRed = currentScreenPixel & 0xF800; + currentScreenPixelGreen = currentScreenPixel & 0x07E0; + currentScreenPixelBlue = currentScreenPixel & 0x001F; + targetScreenPixelRed = targetScreenPixel & 0xF800; + targetScreenPixelGreen = targetScreenPixel & 0x07E0; + targetScreenPixelBlue = targetScreenPixel & 0x001F; + + if (currentScreenPixelRed != targetScreenPixelRed) { + if (currentScreenPixelRed < targetScreenPixelRed) { + currentScreenPixelRed += 0x0800; + } else { + currentScreenPixelRed -= 0x0800; + } + } + if (currentScreenPixelGreen != targetScreenPixelGreen) { + // Adjust +2/-2 because we are running RGB555 at RGB565 + if (currentScreenPixelGreen < targetScreenPixelGreen) { + currentScreenPixelGreen += 0x0040; + } else { + currentScreenPixelGreen -= 0x0040; + } + } + if (currentScreenPixelBlue != targetScreenPixelBlue) { + if (currentScreenPixelBlue < targetScreenPixelBlue) { + currentScreenPixelBlue += 0x0001; + } else { + currentScreenPixelBlue -= 0x0001; + } + } + + uint16 v = currentScreenPixelRed | currentScreenPixelGreen | currentScreenPixelBlue; + *currentScreenPtr = v; + if (_vm->_isScreenDoubled) { + *(currentScreenPtr + 1) = v; + *(currentScreenPtr + 640) = v; + *(currentScreenPtr + 640 + 1) = v; + } + + pixelsChanged++; + } + + currentScreenPtr += _vm->_isScreenDoubled ? 2 : 1; + targetScreenPtr++; + } + + if (_vm->_isScreenDoubled) + currentScreenPtr += 640; + } + + // Too much considered dirty at the moment + if (_vm->_isScreenDoubled) + addDirtyRect(Common::Rect(0, 0, screenWidth * 2, screenHeight * 2)); + else + addDirtyRect(Common::Rect(0, 0, screenWidth, screenHeight)); + + events.pollEvents(); + events.delay(10 * speed); + } while ((pixelsChanged) && (!_vm->shouldQuit())); +} + +void Scalpel3DOScreen::blitFrom3DOcolorLimit(uint16 limitColor) { + uint16 *currentScreenPtr = (uint16 *)getPixels(); + uint16 *targetScreenPtr = (uint16 *)_backBuffer->getPixels(); + uint16 currentScreenPixel = 0; + + uint16 screenWidth = SHERLOCK_SCREEN_WIDTH; + uint16 screenHeight = SHERLOCK_SCREEN_HEIGHT; + uint16 screenX = 0; + uint16 screenY = 0; + + uint16 currentScreenPixelRed = 0; + uint16 currentScreenPixelGreen = 0; + uint16 currentScreenPixelBlue = 0; + + uint16 limitPixelRed = limitColor & 0xF800; + uint16 limitPixelGreen = limitColor & 0x07E0; + uint16 limitPixelBlue = limitColor & 0x001F; + + for (screenY = 0; screenY < screenHeight; screenY++) { + for (screenX = 0; screenX < screenWidth; screenX++) { + currentScreenPixel = *targetScreenPtr; + + currentScreenPixelRed = currentScreenPixel & 0xF800; + currentScreenPixelGreen = currentScreenPixel & 0x07E0; + currentScreenPixelBlue = currentScreenPixel & 0x001F; + + if (currentScreenPixelRed < limitPixelRed) + currentScreenPixelRed = limitPixelRed; + if (currentScreenPixelGreen < limitPixelGreen) + currentScreenPixelGreen = limitPixelGreen; + if (currentScreenPixelBlue < limitPixelBlue) + currentScreenPixelBlue = limitPixelBlue; + + uint16 v = currentScreenPixelRed | currentScreenPixelGreen | currentScreenPixelBlue; + *currentScreenPtr = v; + if (_vm->_isScreenDoubled) { + *(currentScreenPtr + 1) = v; + *(currentScreenPtr + 640) = v; + *(currentScreenPtr + 640 + 1) = v; + } + + currentScreenPtr += _vm->_isScreenDoubled ? 2 : 1; + targetScreenPtr++; + } + + if (_vm->_isScreenDoubled) + currentScreenPtr += 640; + } + + // Too much considered dirty at the moment + if (_vm->_isScreenDoubled) + addDirtyRect(Common::Rect(0, 0, screenWidth * 2, screenHeight * 2)); + else + addDirtyRect(Common::Rect(0, 0, screenWidth, screenHeight)); +} + +uint16 Scalpel3DOScreen::width() const { + return _vm->_isScreenDoubled ? this->w / 2 : this->w; +} + +uint16 Scalpel3DOScreen::height() const { + return _vm->_isScreenDoubled ? this->h / 2 : this->h; +} + +void Scalpel3DOScreen::rawBlitFrom(const Graphics::Surface &src, const Common::Point &pt) { + Common::Rect srcRect(0, 0, src.w, src.h); + Common::Rect destRect(pt.x, pt.y, pt.x + src.w, pt.y + src.h); + + addDirtyRect(destRect); + copyRectToSurface(src, destRect.left, destRect.top, srcRect); +} + +} // End of namespace Scalpel + +} // End of namespace Sherlock diff --git a/engines/sherlock/scalpel/3do/scalpel_3do_screen.h b/engines/sherlock/scalpel/3do/scalpel_3do_screen.h new file mode 100644 index 0000000000..422f588b17 --- /dev/null +++ b/engines/sherlock/scalpel/3do/scalpel_3do_screen.h @@ -0,0 +1,76 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef SHERLOCK_SCALPEL_3DO_SCREEN_H +#define SHERLOCK_SCALPEL_3DO_SCREEN_H + +#include "sherlock/scalpel/scalpel_screen.h" + +namespace Sherlock { + +class SherlockEngine; + +namespace Scalpel { + +class Scalpel3DOScreen : public ScalpelScreen { +protected: + /** + * Draws a sub-section of a surface at a given position within this surface + * Overriden for the 3DO to automatically double the size of everything to the underlying 640x400 surface + */ + virtual void SHblitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds); + + /** + * Draws a surface at a given position within this surface with transparency + */ + virtual void transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt, bool flipped, + int overrideColor); +public: + Scalpel3DOScreen(SherlockEngine *vm); + virtual ~Scalpel3DOScreen() {} + + /** + * Draws a sub-section of a surface at a given position within this surface + */ + void rawBlitFrom(const Graphics::Surface &src, const Common::Point &pt); + + /** + * Fade backbuffer 1 into screen (3DO RGB!) + */ + void fadeIntoScreen3DO(int speed); + + void blitFrom3DOcolorLimit(uint16 color); + + /** + * Fill a given area of the surface with a given color + */ + virtual void fillRect(const Common::Rect &r, uint color); + + virtual uint16 width() const; + virtual uint16 height() const; +}; + +} // End of namespace Scalpel + +} // End of namespace Sherlock + +#endif diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp index b17f38b218..cbb202095f 100644 --- a/engines/sherlock/scalpel/scalpel.cpp +++ b/engines/sherlock/scalpel/scalpel.cpp @@ -29,6 +29,7 @@ #include "sherlock/scalpel/scalpel_people.h" #include "sherlock/scalpel/scalpel_scene.h" #include "sherlock/scalpel/scalpel_screen.h" +#include "sherlock/scalpel/3do/scalpel_3do_screen.h" #include "sherlock/scalpel/tsage/logo.h" #include "sherlock/sherlock.h" #include "sherlock/music.h" @@ -371,8 +372,8 @@ bool ScalpelEngine::showCityCutscene() { if (finished) { ImageFile titleImages_LondonNovember("title2.vgs", true); - _screen->_backBuffer1.blitFrom(*_screen); - _screen->_backBuffer2.blitFrom(*_screen); + _screen->_backBuffer1.SHblitFrom(*_screen); + _screen->_backBuffer2.SHblitFrom(*_screen); Common::Point londonPosition; @@ -386,19 +387,19 @@ bool ScalpelEngine::showCityCutscene() { } // London, England - _screen->_backBuffer1.transBlitFrom(titleImages_LondonNovember[0], londonPosition); + _screen->_backBuffer1.SHtransBlitFrom(titleImages_LondonNovember[0], londonPosition); _screen->randomTransition(); finished = _events->delay(1000, true); // November, 1888 if (finished) { - _screen->_backBuffer1.transBlitFrom(titleImages_LondonNovember[1], Common::Point(100, 100)); + _screen->_backBuffer1.SHtransBlitFrom(titleImages_LondonNovember[1], Common::Point(100, 100)); _screen->randomTransition(); finished = _events->delay(5000, true); } // Transition out the title - _screen->_backBuffer1.blitFrom(_screen->_backBuffer2); + _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2); _screen->randomTransition(); } @@ -407,8 +408,8 @@ bool ScalpelEngine::showCityCutscene() { if (finished) { ImageFile titleImages_SherlockHolmesTitle("title.vgs", true); - _screen->_backBuffer1.blitFrom(*_screen); - _screen->_backBuffer2.blitFrom(*_screen); + _screen->_backBuffer1.SHblitFrom(*_screen); + _screen->_backBuffer2.SHblitFrom(*_screen); Common::Point lostFilesPosition; Common::Point sherlockHolmesPosition; @@ -427,17 +428,17 @@ bool ScalpelEngine::showCityCutscene() { } // The Lost Files of - _screen->_backBuffer1.transBlitFrom(titleImages_SherlockHolmesTitle[0], lostFilesPosition); + _screen->_backBuffer1.SHtransBlitFrom(titleImages_SherlockHolmesTitle[0], lostFilesPosition); // Sherlock Holmes - _screen->_backBuffer1.transBlitFrom(titleImages_SherlockHolmesTitle[1], sherlockHolmesPosition); + _screen->_backBuffer1.SHtransBlitFrom(titleImages_SherlockHolmesTitle[1], sherlockHolmesPosition); // copyright - _screen->_backBuffer1.transBlitFrom(titleImages_SherlockHolmesTitle[2], copyrightPosition); + _screen->_backBuffer1.SHtransBlitFrom(titleImages_SherlockHolmesTitle[2], copyrightPosition); _screen->verticalTransition(); finished = _events->delay(4000, true); if (finished) { - _screen->_backBuffer1.blitFrom(_screen->_backBuffer2); + _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2); _screen->randomTransition(); finished = _events->delay(2000); } @@ -461,7 +462,7 @@ bool ScalpelEngine::showCityCutscene() { // English, width 175, height 38 alleyPosition = Common::Point(72, 51); } - _screen->transBlitFrom(titleImages_SherlockHolmesTitle[3], alleyPosition); + _screen->SHtransBlitFrom(titleImages_SherlockHolmesTitle[3], alleyPosition); _screen->fadeIn(palette, 3); // Wait until the track got looped and the first few notes were played @@ -537,7 +538,7 @@ bool ScalpelEngine::showAlleyCutscene() { earlyTheFollowingMorningPosition = Common::Point(35, 52); } - _screen->transBlitFrom(titleImages_EarlyTheFollowingMorning[0], earlyTheFollowingMorningPosition); + _screen->SHtransBlitFrom(titleImages_EarlyTheFollowingMorning[0], earlyTheFollowingMorningPosition); // fast fade-in _screen->fadeIn(palette, 1); @@ -641,23 +642,23 @@ bool ScalpelEngine::scrollCredits() { delete stream; // Save a copy of the screen background for use in drawing each credit frame - _screen->_backBuffer1.blitFrom(*_screen); + _screen->_backBuffer1.SHblitFrom(*_screen); // Loop for showing the credits for(int idx = 0; idx < 600 && !_events->kbHit() && !shouldQuit(); ++idx) { // Copy the entire screen background before writing text - _screen->blitFrom(_screen->_backBuffer1); + _screen->SHblitFrom(_screen->_backBuffer1); // Write the text appropriate for the next frame if (idx < 400) - _screen->transBlitFrom(creditsImages[0], Common::Point(10, 200 - idx), false, 0); + _screen->SHtransBlitFrom(creditsImages[0], Common::Point(10, 200 - idx), false, 0); if (idx > 200) - _screen->transBlitFrom(creditsImages[1], Common::Point(10, 400 - idx), false, 0); + _screen->SHtransBlitFrom(creditsImages[1], Common::Point(10, 400 - idx), false, 0); // Don't show credit text on the top and bottom ten rows of the screen - _screen->blitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, _screen->w(), 10)); - _screen->blitFrom(_screen->_backBuffer1, Common::Point(0, _screen->h() - 10), - Common::Rect(0, _screen->h() - 10, _screen->w(), _screen->h())); + _screen->SHblitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, _screen->width(), 10)); + _screen->SHblitFrom(_screen->_backBuffer1, Common::Point(0, _screen->height() - 10), + Common::Rect(0, _screen->height() - 10, _screen->width(), _screen->height())); _events->delay(100); } @@ -670,7 +671,7 @@ bool ScalpelEngine::show3DOSplash() { // 3DO EA Splash screen ImageFile3DO titleImage_3DOSplash("3DOSplash.cel", kImageFile3DOType_Cel); - _screen->transBlitFrom(titleImage_3DOSplash[0]._frame, Common::Point(0, -20)); + _screen->SHtransBlitFrom(titleImage_3DOSplash[0]._frame, Common::Point(0, -20)); bool finished = _events->delay(3000, true); if (finished) { @@ -706,7 +707,7 @@ bool ScalpelEngine::showCityCutscene3DO() { _sound->playAiff("prologue/sounds/rain.aiff", 15, true); // Fade screen to grey - screen._backBuffer1.fill(0xCE59); // RGB565: 25, 50, 25 (grey) + screen._backBuffer1.clear(0xCE59); // RGB565: 25, 50, 25 (grey) screen.fadeIntoScreen3DO(2); } @@ -715,16 +716,16 @@ bool ScalpelEngine::showCityCutscene3DO() { } if (finished) { - screen._backBuffer1.fill(0); // fill backbuffer with black to avoid issues during fade from white + screen._backBuffer1.clear(0); // fill backbuffer with black to avoid issues during fade from white finished = _animation->play3DO("26open1", true, 1, true, 2); } if (finished) { - screen._backBuffer2.blitFrom(screen._backBuffer1); + screen._backBuffer2.SHblitFrom(screen._backBuffer1); // "London, England" ImageFile3DO titleImage_London("title2a.cel", kImageFile3DOType_Cel); - screen._backBuffer1.transBlitFrom(titleImage_London[0]._frame, Common::Point(30, 50)); + screen._backBuffer1.SHtransBlitFrom(titleImage_London[0]._frame, Common::Point(30, 50)); screen.fadeIntoScreen3DO(1); finished = _events->delay(1500, true); @@ -732,7 +733,7 @@ bool ScalpelEngine::showCityCutscene3DO() { if (finished) { // "November, 1888" ImageFile3DO titleImage_November("title2b.cel", kImageFile3DOType_Cel); - screen._backBuffer1.transBlitFrom(titleImage_November[0]._frame, Common::Point(100, 100)); + screen._backBuffer1.SHtransBlitFrom(titleImage_November[0]._frame, Common::Point(100, 100)); screen.fadeIntoScreen3DO(1); finished = _music->waitUntilMSec(14700, 0, 0, 5000); @@ -740,8 +741,8 @@ bool ScalpelEngine::showCityCutscene3DO() { if (finished) { // Restore screen - _screen->_backBuffer1.blitFrom(screen._backBuffer2); - _screen->blitFrom(screen._backBuffer1); + _screen->_backBuffer1.SHblitFrom(screen._backBuffer2); + _screen->SHblitFrom(screen._backBuffer1); } } @@ -751,7 +752,7 @@ bool ScalpelEngine::showCityCutscene3DO() { if (finished) { // "Sherlock Holmes" (title) ImageFile3DO titleImage_SherlockHolmesTitle("title1ab.cel", kImageFile3DOType_Cel); - screen._backBuffer1.transBlitFrom(titleImage_SherlockHolmesTitle[0]._frame, Common::Point(34, 5)); + screen._backBuffer1.SHtransBlitFrom(titleImage_SherlockHolmesTitle[0]._frame, Common::Point(34, 5)); // Blend in screen.fadeIntoScreen3DO(2); @@ -761,7 +762,7 @@ bool ScalpelEngine::showCityCutscene3DO() { if (finished) { ImageFile3DO titleImage_Copyright("title1c.cel", kImageFile3DOType_Cel); - screen.transBlitFrom(titleImage_Copyright[0]._frame, Common::Point(20, 190)); + screen.SHtransBlitFrom(titleImage_Copyright[0]._frame, Common::Point(20, 190)); finished = _events->delay(3500, true); } } @@ -780,7 +781,7 @@ bool ScalpelEngine::showCityCutscene3DO() { if (finished) { // "In the alley behind the Regency Theatre..." ImageFile3DO titleImage_InTheAlley("title1d.cel", kImageFile3DOType_Cel); - screen._backBuffer1.transBlitFrom(titleImage_InTheAlley[0]._frame, Common::Point(72, 51)); + screen._backBuffer1.SHtransBlitFrom(titleImage_InTheAlley[0]._frame, Common::Point(72, 51)); // Fade in screen.fadeIntoScreen3DO(4); @@ -819,7 +820,7 @@ bool ScalpelEngine::showAlleyCutscene3DO() { ImageFile3DO titleImage_ScreamingVictim("scream.cel", kImageFile3DOType_Cel); screen.clear(); - screen.transBlitFrom(titleImage_ScreamingVictim[0]._frame, Common::Point(0, 0)); + screen.SHtransBlitFrom(titleImage_ScreamingVictim[0]._frame, Common::Point(0, 0)); // Play "scream.aiff" if (_sound->_voices) @@ -848,7 +849,7 @@ bool ScalpelEngine::showAlleyCutscene3DO() { if (finished) { // "Early the following morning on Baker Street..." ImageFile3DO titleImage_EarlyTheFollowingMorning("title3.cel", kImageFile3DOType_Cel); - screen._backBuffer1.transBlitFrom(titleImage_EarlyTheFollowingMorning[0]._frame, Common::Point(35, 51)); + screen._backBuffer1.SHtransBlitFrom(titleImage_EarlyTheFollowingMorning[0]._frame, Common::Point(35, 51)); // Fade in screen.fadeIntoScreen3DO(4); @@ -908,7 +909,7 @@ bool ScalpelEngine::showOfficeCutscene3DO() { ImageFile3DO titleImage_CoffeeNote("note.cel", kImageFile3DOType_Cel); _screen->clear(); - _screen->transBlitFrom(titleImage_CoffeeNote[0]._frame, Common::Point(0, 0)); + _screen->SHtransBlitFrom(titleImage_CoffeeNote[0]._frame, Common::Point(0, 0)); if (_sound->_voices) { finished = _sound->playSound("prologue/sounds/note.aiff", WAIT_KBD_OR_FINISH); @@ -937,7 +938,7 @@ bool ScalpelEngine::showOfficeCutscene3DO() { // TODO: Brighten the image, possibly by doing a partial fade // to white. - _screen->_backBuffer2.blitFrom(_screen->_backBuffer1); + _screen->_backBuffer2.SHblitFrom(_screen->_backBuffer1); for (int nr = 1; finished && nr <= 4; nr++) { char filename[15]; @@ -945,8 +946,8 @@ bool ScalpelEngine::showOfficeCutscene3DO() { ImageFile3DO *creditsImage = new ImageFile3DO(filename, kImageFile3DOType_Cel); ImageFrame *creditsFrame = &(*creditsImage)[0]; for (int i = 0; finished && i < 200 + creditsFrame->_height; i++) { - _screen->blitFrom(_screen->_backBuffer2); - _screen->transBlitFrom(creditsFrame->_frame, Common::Point((320 - creditsFrame->_width) / 2, 200 - i)); + _screen->SHblitFrom(_screen->_backBuffer2); + _screen->SHtransBlitFrom(creditsFrame->_frame, Common::Point((320 - creditsFrame->_width) / 2, 200 - i)); if (!_events->delay(70, true)) finished = false; } @@ -998,7 +999,7 @@ void ScalpelEngine::showLBV(const Common::String &filename) { delete stream; _screen->setPalette(images._palette); - _screen->_backBuffer1.blitFrom(images[0]); + _screen->_backBuffer1.SHblitFrom(images[0]); _screen->verticalTransition(); } @@ -1156,7 +1157,7 @@ void ScalpelEngine::eraseBrumwellMirror() { // If player is in range of the mirror, then restore background from the secondary back buffer if (Common::Rect(70, 100, 200, 200).contains(pt)) { - _screen->_backBuffer1.blitFrom(_screen->_backBuffer2, Common::Point(137, 18), + _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(137, 18), Common::Rect(137, 18, 184, 74)); } } @@ -1218,20 +1219,20 @@ void ScalpelEngine::doBrumwellMirror() { bool flipped = people[HOLMES]._sequenceNumber == WALK_LEFT || people[HOLMES]._sequenceNumber == STOP_LEFT || people[HOLMES]._sequenceNumber == WALK_UPRIGHT || people[HOLMES]._sequenceNumber == STOP_UPRIGHT || people[HOLMES]._sequenceNumber == WALK_DOWNLEFT || people[HOLMES]._sequenceNumber == STOP_DOWNLEFT; - _screen->_backBuffer1.transBlitFrom(imageFrame, pt + Common::Point(38, -imageFrame._frame.h - 25), flipped); + _screen->_backBuffer1.SHtransBlitFrom(imageFrame, pt + Common::Point(38, -imageFrame._frame.h - 25), flipped); // Redraw the mirror borders to prevent the drawn image of Holmes from appearing outside of the mirror - _screen->_backBuffer1.blitFrom(_screen->_backBuffer2, Common::Point(114, 18), + _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(114, 18), Common::Rect(114, 18, 137, 114)); - _screen->_backBuffer1.blitFrom(_screen->_backBuffer2, Common::Point(137, 70), + _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(137, 70), Common::Rect(137, 70, 142, 114)); - _screen->_backBuffer1.blitFrom(_screen->_backBuffer2, Common::Point(142, 71), + _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(142, 71), Common::Rect(142, 71, 159, 114)); - _screen->_backBuffer1.blitFrom(_screen->_backBuffer2, Common::Point(159, 72), + _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(159, 72), Common::Rect(159, 72, 170, 116)); - _screen->_backBuffer1.blitFrom(_screen->_backBuffer2, Common::Point(170, 73), + _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(170, 73), Common::Rect(170, 73, 184, 114)); - _screen->_backBuffer1.blitFrom(_screen->_backBuffer2, Common::Point(184, 18), + _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(184, 18), Common::Rect(184, 18, 212, 114)); } } @@ -1272,7 +1273,7 @@ void ScalpelEngine::showScummVMRestoreDialog() { bool ScalpelEngine::play3doMovie(const Common::String &filename, const Common::Point &pos, bool isPortrait) { Scalpel3DOScreen &screen = *(Scalpel3DOScreen *)_screen; Scalpel3DOMovieDecoder *videoDecoder = new Scalpel3DOMovieDecoder(); - Graphics::Surface tempSurface; + Graphics::ManagedSurface tempSurface; Common::Point framePos(pos.x, pos.y); ImageFile3DO *frameImageFile = nullptr; @@ -1307,7 +1308,7 @@ bool ScalpelEngine::play3doMovie(const Common::String &filename, const Common::P // If we're to show the movie at half-size, we'll need a temporary intermediate surface if (halfSize) - tempSurface.create(width / 2, height / 2, _screen->getPixelFormat()); + tempSurface.create(width / 2, height / 2); while (!shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { if (videoDecoder->needsUpdate()) { @@ -1371,19 +1372,19 @@ bool ScalpelEngine::play3doMovie(const Common::String &filename, const Common::P } // Point the drawing frame to the temporary surface - frame = &tempSurface; + frame = &tempSurface.rawSurface(); } if (isPortrait && !frameShown) { // Draw the frame (not the frame of the video, but a frame around the video) itself - _screen->transBlitFrom(frameImage->_frame, framePos); + _screen->SHtransBlitFrom(frameImage->_frame, framePos); frameShown = true; } if (isPortrait && !halfSize) { screen.rawBlitFrom(*frame, Common::Point(pos.x * 2, pos.y * 2)); } else { - _screen->blitFrom(*frame, pos); + _screen->SHblitFrom(*frame, pos); } _screen->update(); @@ -1413,9 +1414,9 @@ bool ScalpelEngine::play3doMovie(const Common::String &filename, const Common::P } // Restore scene - screen._backBuffer1.blitFrom(screen._backBuffer2); + screen._backBuffer1.SHblitFrom(screen._backBuffer2); _scene->updateBackground(); - screen.slamArea(0, 0, screen.w(), CONTROLS_Y); + screen.slamArea(0, 0, screen.width(), CONTROLS_Y); return !skipVideo; } diff --git a/engines/sherlock/scalpel/scalpel_darts.cpp b/engines/sherlock/scalpel/scalpel_darts.cpp index 87f4566837..c5ba8032f3 100644 --- a/engines/sherlock/scalpel/scalpel_darts.cpp +++ b/engines/sherlock/scalpel/scalpel_darts.cpp @@ -102,7 +102,7 @@ void Darts::playDarts() { score -= lastDart; _roundScore += lastDart; - screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(DART_INFO_X, DART_INFO_Y - 1), + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(DART_INFO_X, DART_INFO_Y - 1), Common::Rect(DART_INFO_X, DART_INFO_Y - 1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); screen.print(Common::Point(DART_INFO_X, DART_INFO_Y), DART_COL_FORE, "Dart # %d", idx + 1); screen.print(Common::Point(DART_INFO_X, DART_INFO_Y + 10), DART_COL_FORE, "Scored %d points", lastDart); @@ -154,7 +154,7 @@ void Darts::playDarts() { events.wait(20); } - screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(DART_INFO_X, DART_INFO_Y - 1), + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(DART_INFO_X, DART_INFO_Y - 1), Common::Rect(DART_INFO_X, DART_INFO_Y - 1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); } @@ -166,8 +166,8 @@ void Darts::playDarts() { done |= _vm->shouldQuit(); if (!done) { - screen._backBuffer2.blitFrom((*_dartImages)[0], Common::Point(0, 0)); - screen._backBuffer1.blitFrom(screen._backBuffer2); + screen._backBuffer2.SHblitFrom((*_dartImages)[0], Common::Point(0, 0)); + screen._backBuffer1.SHblitFrom(screen._backBuffer2); screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); } } while (!done); @@ -185,7 +185,7 @@ void Darts::loadDarts() { _dartImages = new ImageFile("darts.vgs"); screen.setPalette(_dartImages->_palette); - screen._backBuffer1.blitFrom((*_dartImages)[0], Common::Point(0, 0)); + screen._backBuffer1.SHblitFrom((*_dartImages)[0], Common::Point(0, 0)); screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); } @@ -245,7 +245,7 @@ void Darts::showNames(int playerNum) { screen.slamArea(STATUS_INFO_X + 50, STATUS_INFO_Y + 10, 81, 12); // Make a copy of the back buffer to the secondary one - screen._backBuffer2.blitFrom(screen._backBuffer1); + screen._backBuffer2.SHblitFrom(screen._backBuffer1); } void Darts::showStatus(int playerNum) { @@ -253,7 +253,7 @@ void Darts::showStatus(int playerNum) { byte color; // Copy scoring screen from secondary back buffer. This will erase any previously displayed status/score info - screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10), + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10), Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + 10, SHERLOCK_SCREEN_WIDTH, STATUS_INFO_Y + 48)); color = (playerNum == 0) ? PLAYER_COLOR : DART_COL_FORE; @@ -292,7 +292,7 @@ int Darts::throwDart(int dartNum, int computer) { if (_vm->shouldQuit()) return 0; - screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(DART_INFO_X, DART_INFO_Y - 1), + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(DART_INFO_X, DART_INFO_Y - 1), Common::Rect(DART_INFO_X, DART_INFO_Y - 1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); screen.slamRect(Common::Rect(DART_INFO_X, DART_INFO_Y - 1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); @@ -309,9 +309,9 @@ int Darts::throwDart(int dartNum, int computer) { // Copy the bars to the secondary back buffer so that they remain fixed at their selected values // whilst the dart is being animated at being thrown at the board - screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(DARTBARHX - 1, DARTHORIZY - 1), + screen._backBuffer2.SHblitFrom(screen._backBuffer1, Common::Point(DARTBARHX - 1, DARTHORIZY - 1), Common::Rect(DARTBARHX - 1, DARTHORIZY - 1, DARTBARHX + DARTBARSIZE + 3, DARTHORIZY + 10)); - screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(DARTBARVX - 1, DARTHEIGHTY - 1), + screen._backBuffer2.SHblitFrom(screen._backBuffer1, Common::Point(DARTBARVX - 1, DARTHEIGHTY - 1), Common::Rect(DARTBARVX - 1, DARTHEIGHTY - 1, DARTBARVX + 11, DARTHEIGHTY + DARTBARSIZE + 3)); // Convert height and width to relative range of -50 to 50, where 0,0 is the exact centre of the board @@ -344,7 +344,7 @@ void Darts::drawDartThrow(const Common::Point &pt) { // Draw the dart Common::Point drawPos(pos.x - frame._width / 2, pos.y - frame._height); - screen._backBuffer1.transBlitFrom(frame, drawPos); + screen._backBuffer1.SHtransBlitFrom(frame, drawPos); screen.slamArea(drawPos.x, drawPos.y, frame._width, frame._height); // Handle erasing old dart frame area @@ -352,14 +352,14 @@ void Darts::drawDartThrow(const Common::Point &pt) { screen.slamRect(oldDrawBounds); oldDrawBounds = Common::Rect(drawPos.x, drawPos.y, drawPos.x + frame._width, drawPos.y + frame._height); - screen._backBuffer1.blitFrom(screen._backBuffer2, drawPos, oldDrawBounds); + screen._backBuffer1.SHblitFrom(screen._backBuffer2, drawPos, oldDrawBounds); events.wait(2); } // Draw dart in final "stuck to board" form - screen._backBuffer1.transBlitFrom((*_dartImages)[22], Common::Point(oldDrawBounds.left, oldDrawBounds.top)); - screen._backBuffer2.transBlitFrom((*_dartImages)[22], Common::Point(oldDrawBounds.left, oldDrawBounds.top)); + screen._backBuffer1.SHtransBlitFrom((*_dartImages)[22], Common::Point(oldDrawBounds.left, oldDrawBounds.top)); + screen._backBuffer2.SHtransBlitFrom((*_dartImages)[22], Common::Point(oldDrawBounds.left, oldDrawBounds.top)); screen.slamRect(oldDrawBounds); } @@ -368,8 +368,8 @@ void Darts::erasePowerBars() { screen._backBuffer1.fillRect(Common::Rect(DARTBARHX, DARTHORIZY, DARTBARHX + DARTBARSIZE, DARTHORIZY + 10), BLACK); screen._backBuffer1.fillRect(Common::Rect(DARTBARVX, DARTHEIGHTY, DARTBARVX + 10, DARTHEIGHTY + DARTBARSIZE), BLACK); - screen._backBuffer1.transBlitFrom((*_dartImages)[2], Common::Point(DARTBARHX - 1, DARTHORIZY - 1)); - screen._backBuffer1.transBlitFrom((*_dartImages)[3], Common::Point(DARTBARVX - 1, DARTHEIGHTY - 1)); + screen._backBuffer1.SHtransBlitFrom((*_dartImages)[2], Common::Point(DARTBARHX - 1, DARTHORIZY - 1)); + screen._backBuffer1.SHtransBlitFrom((*_dartImages)[3], Common::Point(DARTBARVX - 1, DARTHEIGHTY - 1)); screen.slamArea(DARTBARHX - 1, DARTHORIZY - 1, DARTBARSIZE + 3, 11); screen.slamArea(DARTBARVX - 1, DARTHEIGHTY - 1, 11, DARTBARSIZE + 3); } @@ -398,11 +398,11 @@ int Darts::doPowerBar(const Common::Point &pt, byte color, int goToPower, bool i if (isVertical) { screen._backBuffer1.hLine(pt.x, pt.y + DARTBARSIZE - 1 - idx, pt.x + 8, color); - screen._backBuffer1.transBlitFrom((*_dartImages)[3], Common::Point(pt.x - 1, pt.y - 1)); + screen._backBuffer1.SHtransBlitFrom((*_dartImages)[3], Common::Point(pt.x - 1, pt.y - 1)); screen.slamArea(pt.x, pt.y + DARTBARSIZE - 1 - idx, 8, 2); } else { screen._backBuffer1.vLine(pt.x + idx, pt.y, pt.y + 8, color); - screen._backBuffer1.transBlitFrom((*_dartImages)[2], Common::Point(pt.x - 1, pt.y - 1)); + screen._backBuffer1.SHtransBlitFrom((*_dartImages)[2], Common::Point(pt.x - 1, pt.y - 1)); screen.slamArea(pt.x + idx, pt.y, 1, 8); } diff --git a/engines/sherlock/scalpel/scalpel_fixed_text.cpp b/engines/sherlock/scalpel/scalpel_fixed_text.cpp index 8932fb29c5..d76136a1db 100644 --- a/engines/sherlock/scalpel/scalpel_fixed_text.cpp +++ b/engines/sherlock/scalpel/scalpel_fixed_text.cpp @@ -105,6 +105,14 @@ static const char *const fixedTextEN[] = { "Tarot Cards", "An ornate key", "A pawn ticket", + // SH1: User Interface + "No, thank you.", + "You can't do that.", + "Done...", + "Use ", + " on %s", + "Give ", + " to %s", // SH1: People names "Sherlock Holmes", "Dr. Watson", @@ -250,6 +258,14 @@ static const char *const fixedTextDE[] = { "Ein Tarot-Kartenspiel", // original interpreter: "Ein Tarock-Kartenspiel" [sic] "Ein verzierter Schl\201ssel", "Ein Pfandschein", + // SH1: User Interface + "Nein, vielen Dank.", + "Nein, das geht wirklich nicht.", // original: "Nein, das geht wirklich nicht" + "Fertig...", + "Benutze ", + " mit %s", + "Gib ", // original: "Gebe " + " an %s", // original: " zu %s" // SH1: People names "Sherlock Holmes", "Dr. Watson", @@ -316,6 +332,7 @@ static const char *const fixedTextDE[] = { // up-side down exclamation mark - 0xAD / octal 255 // up-side down question mark - 0xA8 / octal 250 // n with a wave on top - 0xA4 / octal 244 +// more characters see engines/sherlock/fixed_text.cpp static const char *const fixedTextES[] = { // Game hotkeys "VMHTACIUDNFO", @@ -394,6 +411,14 @@ static const char *const fixedTextES[] = { "Unas cartas de Tarot", "Una llave muy vistosa", "Una papeleta de empe\244o", + // SH1: User Interface + "No, gracias.", + "No puedes hacerlo.", // original: "No puedes hacerlo" + "Hecho...", + "Usar ", + " sobre %s", + "Dar ", + " a %s", // SH1: People names "Sherlock Holmes", "Dr. Watson", @@ -517,7 +542,7 @@ static const char *const fixedTextDE_ActionMove[] = { "L\204\341t sich nicht bewegen", "Festged\201belt in der Erde...", "Oha, VIEL zu schwer", - "Der andere Kiste ist im Weg" // [sic] + "Die andere Kiste ist im Weg" // original: "Der andere Kiste ist im Weg" }; static const char *const fixedTextES_ActionMove[] = { @@ -616,8 +641,6 @@ static const FixedTextActionEntry fixedTextES_Actions[] = { // ========================================= -// TODO: -// It seems there was a French version of Sherlock Holmes 2 static const FixedTextLanguageEntry fixedTextLanguages[] = { { Common::DE_DEU, fixedTextDE, fixedTextDE_Actions }, { Common::ES_ESP, fixedTextES, fixedTextES_Actions }, diff --git a/engines/sherlock/scalpel/scalpel_fixed_text.h b/engines/sherlock/scalpel/scalpel_fixed_text.h index 841d602408..d9b3bbed79 100644 --- a/engines/sherlock/scalpel/scalpel_fixed_text.h +++ b/engines/sherlock/scalpel/scalpel_fixed_text.h @@ -107,6 +107,14 @@ enum FixedTextId { kFixedText_InitInventory_Tarot, kFixedText_InitInventory_OrnateKey, kFixedText_InitInventory_PawnTicket, + // SH1: User Interface + kFixedText_UserInterface_NoThankYou, + kFixedText_UserInterface_YouCantDoThat, + kFixedText_UserInterface_Done, + kFixedText_UserInterface_Use, + kFixedText_UserInterface_UseOn, + kFixedText_UserInterface_Give, + kFixedText_UserInterface_GiveTo, // People names kFixedText_People_SherlockHolmes, kFixedText_People_DrWatson, diff --git a/engines/sherlock/scalpel/scalpel_inventory.cpp b/engines/sherlock/scalpel/scalpel_inventory.cpp index c3e20295fd..e8d4d3b934 100644 --- a/engines/sherlock/scalpel/scalpel_inventory.cpp +++ b/engines/sherlock/scalpel/scalpel_inventory.cpp @@ -201,7 +201,7 @@ void ScalpelInventory::highlight(int index, byte color) { ImageFrame &frame = (*_invShapes[slot])[0]; bb.fillRect(Common::Rect(8 + slot * 52, 165, (slot + 1) * 52, 194), color); - bb.transBlitFrom(frame, Common::Point(6 + slot * 52 + ((47 - frame._width) / 2), + bb.SHtransBlitFrom(frame, Common::Point(6 + slot * 52 + ((47 - frame._width) / 2), 163 + ((33 - frame._height) / 2))); screen.slamArea(8 + slot * 52, 165, 44, 30); } @@ -217,12 +217,12 @@ void ScalpelInventory::refreshInv() { ui._infoFlag = true; ui.clearInfo(); - screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(0, CONTROLS_Y), + screen._backBuffer2.SHblitFrom(screen._backBuffer1, Common::Point(0, CONTROLS_Y), Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); ui.examine(); if (!talk._talkToAbort) { - screen._backBuffer2.blitFrom((*ui._controlPanel)[0], Common::Point(0, CONTROLS_Y)); + screen._backBuffer2.SHblitFrom((*ui._controlPanel)[0], Common::Point(0, CONTROLS_Y)); loadInv(); } } @@ -264,7 +264,7 @@ void ScalpelInventory::putInv(InvSlamMode slamIt) { // Draw the item image ImageFrame &frame = (*_invShapes[itemNum])[0]; - bb.transBlitFrom(frame, Common::Point(6 + itemNum * 52 + ((47 - frame._width) / 2), + bb.SHtransBlitFrom(frame, Common::Point(6 + itemNum * 52 + ((47 - frame._width) / 2), 163 + ((33 - frame._height) / 2))); } diff --git a/engines/sherlock/scalpel/scalpel_map.cpp b/engines/sherlock/scalpel/scalpel_map.cpp index 0924581e38..ba14b5b300 100644 --- a/engines/sherlock/scalpel/scalpel_map.cpp +++ b/engines/sherlock/scalpel/scalpel_map.cpp @@ -167,13 +167,13 @@ int ScalpelMap::show() { setupSprites(); if (!IS_3DO) { - screen._backBuffer1.blitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y)); - screen._backBuffer1.blitFrom((*bigMap)[1], Common::Point(-_bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); - screen._backBuffer1.blitFrom((*bigMap)[2], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, -_bigPos.y)); - screen._backBuffer1.blitFrom((*bigMap)[3], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); + screen._backBuffer1.SHblitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y)); + screen._backBuffer1.SHblitFrom((*bigMap)[1], Common::Point(-_bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); + screen._backBuffer1.SHblitFrom((*bigMap)[2], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, -_bigPos.y)); + screen._backBuffer1.SHblitFrom((*bigMap)[3], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); } else { - screen._backBuffer1.blitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y)); - screen.blitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y)); + screen._backBuffer1.SHblitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y)); + screen.SHblitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y)); } _drawMap = true; @@ -238,12 +238,12 @@ int ScalpelMap::show() { changed = false; if (!IS_3DO) { - screen._backBuffer1.blitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y)); - screen._backBuffer1.blitFrom((*bigMap)[1], Common::Point(-_bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); - screen._backBuffer1.blitFrom((*bigMap)[2], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, -_bigPos.y)); - screen._backBuffer1.blitFrom((*bigMap)[3], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); + screen._backBuffer1.SHblitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y)); + screen._backBuffer1.SHblitFrom((*bigMap)[1], Common::Point(-_bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); + screen._backBuffer1.SHblitFrom((*bigMap)[2], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, -_bigPos.y)); + screen._backBuffer1.SHblitFrom((*bigMap)[3], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); } else { - screen._backBuffer1.blitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y)); + screen._backBuffer1.SHblitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y)); } showPlaces(); @@ -359,7 +359,6 @@ void ScalpelMap::freeSprites() { delete _mapCursors; delete _shapes; delete _iconShapes; - _iconSave.free(); } void ScalpelMap::showPlaces() { @@ -376,7 +375,7 @@ void ScalpelMap::showPlaces() { if (pt.x >= _bigPos.x && (pt.x - _bigPos.x) < SHERLOCK_SCREEN_WIDTH && pt.y >= _bigPos.y && (pt.y - _bigPos.y) < SHERLOCK_SCREEN_HEIGHT) { if (_vm->readFlags(idx)) { - screen._backBuffer1.transBlitFrom((*_iconShapes)[pt._translate], + screen._backBuffer1.SHtransBlitFrom((*_iconShapes)[pt._translate], Common::Point(pt.x - _bigPos.x - 6, pt.y - _bigPos.y - 12)); } } @@ -388,13 +387,13 @@ void ScalpelMap::showPlaces() { } void ScalpelMap::saveTopLine() { - _topLine.blitFrom(_vm->_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, 12)); + _topLine.SHblitFrom(_vm->_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, 12)); } void ScalpelMap::eraseTopLine() { Screen &screen = *_vm->_screen; - screen._backBuffer1.blitFrom(_topLine, Common::Point(0, 0)); - screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, _topLine.h()); + screen._backBuffer1.SHblitFrom(_topLine, Common::Point(0, 0)); + screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, _topLine.height()); } void ScalpelMap::showPlaceName(int idx, bool highlighted) { @@ -409,7 +408,7 @@ void ScalpelMap::showPlaceName(int idx, bool highlighted) { bool flipped = people[HOLMES]._sequenceNumber == MAP_DOWNLEFT || people[HOLMES]._sequenceNumber == MAP_LEFT || people[HOLMES]._sequenceNumber == MAP_UPLEFT; - screen._backBuffer1.transBlitFrom(*people[HOLMES]._imageFrame, _lDrawnPos, flipped); + screen._backBuffer1.SHtransBlitFrom(*people[HOLMES]._imageFrame, _lDrawnPos, flipped); } if (highlighted) { @@ -451,9 +450,9 @@ void ScalpelMap::updateMap(bool flushScreen) { saveIcon(people[HOLMES]._imageFrame, hPos); if (people[HOLMES]._sequenceNumber == MAP_DOWNLEFT || people[HOLMES]._sequenceNumber == MAP_LEFT || people[HOLMES]._sequenceNumber == MAP_UPLEFT) - screen._backBuffer1.transBlitFrom(*people[HOLMES]._imageFrame, hPos, true); + screen._backBuffer1.SHtransBlitFrom(*people[HOLMES]._imageFrame, hPos, true); else - screen._backBuffer1.transBlitFrom(*people[HOLMES]._imageFrame, hPos, false); + screen._backBuffer1.SHtransBlitFrom(*people[HOLMES]._imageFrame, hPos, false); if (flushScreen) { screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); @@ -553,8 +552,8 @@ void ScalpelMap::saveIcon(ImageFrame *src, const Common::Point &pt) { return; } - assert(size.x <= _iconSave.w() && size.y <= _iconSave.h()); - _iconSave.blitFrom(screen._backBuffer1, Common::Point(0, 0), + assert(size.x <= _iconSave.width() && size.y <= _iconSave.height()); + _iconSave.SHblitFrom(screen._backBuffer1, Common::Point(0, 0), Common::Rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y)); _savedPos = pos; _savedSize = size; @@ -565,7 +564,7 @@ void ScalpelMap::restoreIcon() { if (_savedPos.x >= 0 && _savedPos.y >= 0 && _savedPos.x <= SHERLOCK_SCREEN_WIDTH && _savedPos.y < SHERLOCK_SCREEN_HEIGHT) - screen._backBuffer1.blitFrom(_iconSave, _savedPos, Common::Rect(0, 0, _savedSize.x, _savedSize.y)); + screen._backBuffer1.SHblitFrom(_iconSave, _savedPos, Common::Rect(0, 0, _savedSize.x, _savedSize.y)); } void ScalpelMap::highlightIcon(const Common::Point &pt) { diff --git a/engines/sherlock/scalpel/scalpel_scene.cpp b/engines/sherlock/scalpel/scalpel_scene.cpp index b62703e0fb..83e49bb3fa 100644 --- a/engines/sherlock/scalpel/scalpel_scene.cpp +++ b/engines/sherlock/scalpel/scalpel_scene.cpp @@ -71,26 +71,26 @@ void ScalpelScene::drawAllShapes() { // Draw all active shapes which are behind the person for (uint idx = 0; idx < _bgShapes.size(); ++idx) { if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE && _bgShapes[idx]._misc == BEHIND) - screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, _bgShapes[idx]._flags & OBJ_FLIPPED); + screen._backBuffer->SHtransBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, _bgShapes[idx]._flags & OBJ_FLIPPED); } // Draw all canimations which are behind the person for (uint idx = 0; idx < _canimShapes.size(); ++idx) { if (_canimShapes[idx]->_type == ACTIVE_BG_SHAPE && _canimShapes[idx]->_misc == BEHIND) - screen._backBuffer->transBlitFrom(*_canimShapes[idx]->_imageFrame, + screen._backBuffer->SHtransBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position, _canimShapes[idx]->_flags & OBJ_FLIPPED); } // Draw all active shapes which are normal and behind the person for (uint idx = 0; idx < _bgShapes.size(); ++idx) { if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE && _bgShapes[idx]._misc == NORMAL_BEHIND) - screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, _bgShapes[idx]._flags & OBJ_FLIPPED); + screen._backBuffer->SHtransBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, _bgShapes[idx]._flags & OBJ_FLIPPED); } // Draw all canimations which are normal and behind the person for (uint idx = 0; idx < _canimShapes.size(); ++idx) { if (_canimShapes[idx]->_type == ACTIVE_BG_SHAPE && _canimShapes[idx]->_misc == NORMAL_BEHIND) - screen._backBuffer->transBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position, + screen._backBuffer->SHtransBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position, _canimShapes[idx]->_flags & OBJ_FLIPPED); } @@ -103,7 +103,7 @@ void ScalpelScene::drawAllShapes() { p._sequenceNumber == WALK_UPLEFT || p._sequenceNumber == STOP_UPLEFT || p._sequenceNumber == WALK_DOWNRIGHT || p._sequenceNumber == STOP_DOWNRIGHT); - screen._backBuffer->transBlitFrom(*p._imageFrame, Common::Point(p._position.x / FIXED_INT_MULTIPLIER, + screen._backBuffer->SHtransBlitFrom(*p._imageFrame, Common::Point(p._position.x / FIXED_INT_MULTIPLIER, p._position.y / FIXED_INT_MULTIPLIER - p.frameHeight()), flipped); } } @@ -112,7 +112,7 @@ void ScalpelScene::drawAllShapes() { for (uint idx = 0; idx < _bgShapes.size(); ++idx) { if ((_bgShapes[idx]._type == ACTIVE_BG_SHAPE || _bgShapes[idx]._type == STATIC_BG_SHAPE) && _bgShapes[idx]._misc == NORMAL_FORWARD) - screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, + screen._backBuffer->SHtransBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, _bgShapes[idx]._flags & OBJ_FLIPPED); } @@ -120,7 +120,7 @@ void ScalpelScene::drawAllShapes() { for (uint idx = 0; idx < _canimShapes.size(); ++idx) { if ((_canimShapes[idx]->_type == ACTIVE_BG_SHAPE || _canimShapes[idx]->_type == STATIC_BG_SHAPE) && _canimShapes[idx]->_misc == NORMAL_FORWARD) - screen._backBuffer->transBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position, + screen._backBuffer->SHtransBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position, _canimShapes[idx]->_flags & OBJ_FLIPPED); } @@ -132,7 +132,7 @@ void ScalpelScene::drawAllShapes() { if ((_bgShapes[idx]._type == ACTIVE_BG_SHAPE || _bgShapes[idx]._type == STATIC_BG_SHAPE) && _bgShapes[idx]._misc == FORWARD) - screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, + screen._backBuffer->SHtransBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, _bgShapes[idx]._flags & OBJ_FLIPPED); } @@ -140,7 +140,7 @@ void ScalpelScene::drawAllShapes() { for (uint idx = 0; idx < _canimShapes.size(); ++idx) { if ((_canimShapes[idx]->_type == ACTIVE_BG_SHAPE || _canimShapes[idx]->_type == STATIC_BG_SHAPE) && _canimShapes[idx]->_misc == FORWARD) - screen._backBuffer->transBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position, + screen._backBuffer->SHtransBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position, _canimShapes[idx]->_flags & OBJ_FLIPPED); } @@ -242,7 +242,7 @@ void ScalpelScene::doBgAnim() { if (people[HOLMES]._type == CHARACTER) screen.restoreBackground(bounds); else if (people[HOLMES]._type == REMOVE) - screen._backBuffer->blitFrom(screen._backBuffer2, pt, bounds); + screen._backBuffer->SHblitFrom(screen._backBuffer2, pt, bounds); for (uint idx = 0; idx < _bgShapes.size(); ++idx) { Object &o = _bgShapes[idx]; @@ -261,7 +261,7 @@ void ScalpelScene::doBgAnim() { Object &o = _bgShapes[idx]; if (o._type == NO_SHAPE && ((o._flags & OBJ_BEHIND) == 0)) { // Restore screen area - screen._backBuffer->blitFrom(screen._backBuffer2, o._position, + screen._backBuffer->SHblitFrom(screen._backBuffer2, o._position, Common::Rect(o._position.x, o._position.y, o._position.x + o._noShapeSize.x, o._position.y + o._noShapeSize.y)); @@ -309,14 +309,14 @@ void ScalpelScene::doBgAnim() { for (uint idx = 0; idx < _bgShapes.size(); ++idx) { Object &o = _bgShapes[idx]; if (o._type == ACTIVE_BG_SHAPE && o._misc == BEHIND) - screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); + screen._backBuffer->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); } // Draw all canimations which are behind the person for (uint idx = 0; idx < _canimShapes.size(); ++idx) { Object &o = *_canimShapes[idx]; if (o._type == ACTIVE_BG_SHAPE && o._misc == BEHIND) { - screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); + screen._backBuffer->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); } } @@ -324,14 +324,14 @@ void ScalpelScene::doBgAnim() { for (uint idx = 0; idx < _bgShapes.size(); ++idx) { Object &o = _bgShapes[idx]; if (o._type == ACTIVE_BG_SHAPE && o._misc == NORMAL_BEHIND) - screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); + screen._backBuffer->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); } // Draw all canimations which are NORMAL and behind the person for (uint idx = 0; idx < _canimShapes.size(); ++idx) { Object &o = *_canimShapes[idx]; if (o._type == ACTIVE_BG_SHAPE && o._misc == NORMAL_BEHIND) { - screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); + screen._backBuffer->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); } } @@ -344,7 +344,7 @@ void ScalpelScene::doBgAnim() { bool flipped = people[HOLMES]._sequenceNumber == WALK_LEFT || people[HOLMES]._sequenceNumber == STOP_LEFT || people[HOLMES]._sequenceNumber == WALK_UPLEFT || people[HOLMES]._sequenceNumber == STOP_UPLEFT || people[HOLMES]._sequenceNumber == WALK_DOWNRIGHT || people[HOLMES]._sequenceNumber == STOP_DOWNRIGHT; - screen._backBuffer->transBlitFrom(*people[HOLMES]._imageFrame, + screen._backBuffer->SHtransBlitFrom(*people[HOLMES]._imageFrame, Common::Point(tempX, people[HOLMES]._position.y / FIXED_INT_MULTIPLIER - people[HOLMES]._imageFrame->_frame.h), flipped); } @@ -352,14 +352,14 @@ void ScalpelScene::doBgAnim() { for (uint idx = 0; idx < _bgShapes.size(); ++idx) { Object &o = _bgShapes[idx]; if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == NORMAL_FORWARD) - screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); + screen._backBuffer->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); } // Draw all static and active canimations that are NORMAL and are in front of the person for (uint idx = 0; idx < _canimShapes.size(); ++idx) { Object &o = *_canimShapes[idx]; if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == NORMAL_FORWARD) { - screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); + screen._backBuffer->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); } } @@ -367,19 +367,19 @@ void ScalpelScene::doBgAnim() { for (uint idx = 0; idx < _bgShapes.size(); ++idx) { Object &o = _bgShapes[idx]; if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == FORWARD) - screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); + screen._backBuffer->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); } // Draw any active portrait if (people._portraitLoaded && people._portrait._type == ACTIVE_BG_SHAPE) - screen._backBuffer->transBlitFrom(*people._portrait._imageFrame, + screen._backBuffer->SHtransBlitFrom(*people._portrait._imageFrame, people._portrait._position, people._portrait._flags & OBJ_FLIPPED); // Draw all static and active canimations that are in front of the person for (uint idx = 0; idx < _canimShapes.size(); ++idx) { Object &o = *_canimShapes[idx]; if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == FORWARD) { - screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); + screen._backBuffer->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); } } @@ -387,7 +387,7 @@ void ScalpelScene::doBgAnim() { for (uint idx = 0; idx < _bgShapes.size(); ++idx) { Object &o = _bgShapes[idx]; if (o._type == NO_SHAPE && (o._flags & OBJ_BEHIND) == 0) - screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); + screen._backBuffer->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); } // Bring the newly built picture to the screen diff --git a/engines/sherlock/scalpel/scalpel_screen.cpp b/engines/sherlock/scalpel/scalpel_screen.cpp index 197a2a2634..37e5294c02 100644 --- a/engines/sherlock/scalpel/scalpel_screen.cpp +++ b/engines/sherlock/scalpel/scalpel_screen.cpp @@ -28,6 +28,8 @@ namespace Sherlock { namespace Scalpel { ScalpelScreen::ScalpelScreen(SherlockEngine *vm) : Screen(vm) { + _backBuffer1.create(320, 200); + _backBuffer2.create(320, 200); } void ScalpelScreen::makeButton(const Common::Rect &bounds, int textX, @@ -123,255 +125,6 @@ void ScalpelScreen::makeField(const Common::Rect &r) { _backBuffer->vLine(r.right - 1, r.top + 1, r.bottom - 2, BUTTON_TOP); } -/*----------------------------------------------------------------*/ - -void Scalpel3DOScreen::blitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds) { - if (!_vm->_isScreenDoubled) { - ScalpelScreen::blitFrom(src, pt, srcBounds); - return; - } - - Common::Rect srcRect = srcBounds; - Common::Rect destRect(pt.x, pt.y, pt.x + srcRect.width(), pt.y + srcRect.height()); - - if (!srcRect.isValidRect() || !clip(srcRect, destRect)) - return; - - // Add dirty area remapped to the 640x200 surface - addDirtyRect(Common::Rect(destRect.left * 2, destRect.top * 2, destRect.right * 2, destRect.bottom * 2)); - - // Transfer the area, doubling each pixel - for (int yp = 0; yp < srcRect.height(); ++yp) { - const uint16 *srcP = (const uint16 *)src.getBasePtr(srcRect.left, srcRect.top + yp); - uint16 *destP = (uint16 *)getBasePtr(destRect.left * 2, (destRect.top + yp) * 2); - - for (int xp = srcRect.left; xp < srcRect.right; ++xp, ++srcP, destP += 2) { - *destP = *srcP; - *(destP + 1) = *srcP; - *(destP + 640) = *srcP; - *(destP + 640 + 1) = *srcP; - } - } -} - -void Scalpel3DOScreen::transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt, - bool flipped, int overrideColor) { - if (!_vm->_isScreenDoubled) { - ScalpelScreen::transBlitFromUnscaled(src, pt, flipped, overrideColor); - return; - } - - Common::Rect drawRect(0, 0, src.w, src.h); - Common::Rect destRect(pt.x, pt.y, pt.x + src.w, pt.y + src.h); - - // Clip the display area to on-screen - if (!clip(drawRect, destRect)) - // It's completely off-screen - return; - - if (flipped) - drawRect = Common::Rect(src.w - drawRect.right, src.h - drawRect.bottom, - src.w - drawRect.left, src.h - drawRect.top); - - Common::Point destPt(destRect.left, destRect.top); - addDirtyRect(Common::Rect(destPt.x * 2, destPt.y * 2, (destPt.x + drawRect.width()) * 2, - (destPt.y + drawRect.height()) * 2)); - - assert(src.format.bytesPerPixel == 2 && _surface.format.bytesPerPixel == 2); - - for (int yp = 0; yp < drawRect.height(); ++yp) { - const uint16 *srcP = (const uint16 *)src.getBasePtr( - flipped ? drawRect.right - 1 : drawRect.left, drawRect.top + yp); - uint16 *destP = (uint16 *)getBasePtr(destPt.x * 2, (destPt.y + yp) * 2); - - for (int xp = 0; xp < drawRect.width(); ++xp, destP += 2) { - // RGB 0, 0, 0 -> transparent on 3DO - if (*srcP) { - *destP = *srcP; - *(destP + 1) = *srcP; - *(destP + 640) = *srcP; - *(destP + 640 + 1) = *srcP; - } - - srcP = flipped ? srcP - 1 : srcP + 1; - } - } -} - -void Scalpel3DOScreen::fillRect(const Common::Rect &r, uint color) { - if (_vm->_isScreenDoubled) - ScalpelScreen::fillRect(Common::Rect(r.left * 2, r.top * 2, r.right * 2, r.bottom * 2), color); - else - ScalpelScreen::fillRect(r, color); -} - -void Scalpel3DOScreen::fadeIntoScreen3DO(int speed) { - Events &events = *_vm->_events; - uint16 *currentScreenBasePtr = (uint16 *)getPixels(); - uint16 *targetScreenBasePtr = (uint16 *)_backBuffer->getPixels(); - uint16 currentScreenPixel = 0; - uint16 targetScreenPixel = 0; - - uint16 currentScreenPixelRed = 0; - uint16 currentScreenPixelGreen = 0; - uint16 currentScreenPixelBlue = 0; - - uint16 targetScreenPixelRed = 0; - uint16 targetScreenPixelGreen = 0; - uint16 targetScreenPixelBlue = 0; - - uint16 screenWidth = SHERLOCK_SCREEN_WIDTH; - uint16 screenHeight = SHERLOCK_SCREEN_HEIGHT; - uint16 screenX = 0; - uint16 screenY = 0; - uint16 pixelsChanged = 0; - - clearDirtyRects(); - - do { - pixelsChanged = 0; - uint16 *currentScreenPtr = currentScreenBasePtr; - uint16 *targetScreenPtr = targetScreenBasePtr; - - for (screenY = 0; screenY < screenHeight; screenY++) { - for (screenX = 0; screenX < screenWidth; screenX++) { - currentScreenPixel = *currentScreenPtr; - targetScreenPixel = *targetScreenPtr; - - if (currentScreenPixel != targetScreenPixel) { - // pixel doesn't match, adjust accordingly - currentScreenPixelRed = currentScreenPixel & 0xF800; - currentScreenPixelGreen = currentScreenPixel & 0x07E0; - currentScreenPixelBlue = currentScreenPixel & 0x001F; - targetScreenPixelRed = targetScreenPixel & 0xF800; - targetScreenPixelGreen = targetScreenPixel & 0x07E0; - targetScreenPixelBlue = targetScreenPixel & 0x001F; - - if (currentScreenPixelRed != targetScreenPixelRed) { - if (currentScreenPixelRed < targetScreenPixelRed) { - currentScreenPixelRed += 0x0800; - } else { - currentScreenPixelRed -= 0x0800; - } - } - if (currentScreenPixelGreen != targetScreenPixelGreen) { - // Adjust +2/-2 because we are running RGB555 at RGB565 - if (currentScreenPixelGreen < targetScreenPixelGreen) { - currentScreenPixelGreen += 0x0040; - } else { - currentScreenPixelGreen -= 0x0040; - } - } - if (currentScreenPixelBlue != targetScreenPixelBlue) { - if (currentScreenPixelBlue < targetScreenPixelBlue) { - currentScreenPixelBlue += 0x0001; - } else { - currentScreenPixelBlue -= 0x0001; - } - } - - uint16 v = currentScreenPixelRed | currentScreenPixelGreen | currentScreenPixelBlue; - *currentScreenPtr = v; - if (_vm->_isScreenDoubled) { - *(currentScreenPtr + 1) = v; - *(currentScreenPtr + 640) = v; - *(currentScreenPtr + 640 + 1) = v; - } - - pixelsChanged++; - } - - currentScreenPtr += _vm->_isScreenDoubled ? 2 : 1; - targetScreenPtr++; - } - - if (_vm->_isScreenDoubled) - currentScreenPtr += 640; - } - - // Too much considered dirty at the moment - if (_vm->_isScreenDoubled) - addDirtyRect(Common::Rect(0, 0, screenWidth * 2, screenHeight * 2)); - else - addDirtyRect(Common::Rect(0, 0, screenWidth, screenHeight)); - - events.pollEvents(); - events.delay(10 * speed); - } while ((pixelsChanged) && (!_vm->shouldQuit())); -} - -void Scalpel3DOScreen::blitFrom3DOcolorLimit(uint16 limitColor) { - uint16 *currentScreenPtr = (uint16 *)getPixels(); - uint16 *targetScreenPtr = (uint16 *)_backBuffer->getPixels(); - uint16 currentScreenPixel = 0; - - uint16 screenWidth = SHERLOCK_SCREEN_WIDTH; - uint16 screenHeight = SHERLOCK_SCREEN_HEIGHT; - uint16 screenX = 0; - uint16 screenY = 0; - - uint16 currentScreenPixelRed = 0; - uint16 currentScreenPixelGreen = 0; - uint16 currentScreenPixelBlue = 0; - - uint16 limitPixelRed = limitColor & 0xF800; - uint16 limitPixelGreen = limitColor & 0x07E0; - uint16 limitPixelBlue = limitColor & 0x001F; - - for (screenY = 0; screenY < screenHeight; screenY++) { - for (screenX = 0; screenX < screenWidth; screenX++) { - currentScreenPixel = *targetScreenPtr; - - currentScreenPixelRed = currentScreenPixel & 0xF800; - currentScreenPixelGreen = currentScreenPixel & 0x07E0; - currentScreenPixelBlue = currentScreenPixel & 0x001F; - - if (currentScreenPixelRed < limitPixelRed) - currentScreenPixelRed = limitPixelRed; - if (currentScreenPixelGreen < limitPixelGreen) - currentScreenPixelGreen = limitPixelGreen; - if (currentScreenPixelBlue < limitPixelBlue) - currentScreenPixelBlue = limitPixelBlue; - - uint16 v = currentScreenPixelRed | currentScreenPixelGreen | currentScreenPixelBlue; - *currentScreenPtr = v; - if (_vm->_isScreenDoubled) { - *(currentScreenPtr + 1) = v; - *(currentScreenPtr + 640) = v; - *(currentScreenPtr + 640 + 1) = v; - } - - currentScreenPtr += _vm->_isScreenDoubled ? 2 : 1; - targetScreenPtr++; - } - - if (_vm->_isScreenDoubled) - currentScreenPtr += 640; - } - - // Too much considered dirty at the moment - if (_vm->_isScreenDoubled) - addDirtyRect(Common::Rect(0, 0, screenWidth * 2, screenHeight * 2)); - else - addDirtyRect(Common::Rect(0, 0, screenWidth, screenHeight)); -} - -uint16 Scalpel3DOScreen::w() const { - return _vm->_isScreenDoubled ? _surface.w / 2 : _surface.w; -} - -uint16 Scalpel3DOScreen::h() const { - return _vm->_isScreenDoubled ? _surface.h / 2 : _surface.h; -} - -void Scalpel3DOScreen::rawBlitFrom(const Graphics::Surface &src, const Common::Point &pt) { - Common::Rect srcRect(0, 0, src.w, src.h); - Common::Rect destRect(pt.x, pt.y, pt.x + src.w, pt.y + src.h); - - addDirtyRect(destRect); - _surface.copyRectToSurface(src, destRect.left, destRect.top, srcRect); -} - } // End of namespace Scalpel } // End of namespace Sherlock diff --git a/engines/sherlock/scalpel/scalpel_screen.h b/engines/sherlock/scalpel/scalpel_screen.h index cee33b8c6c..d9be29c8b2 100644 --- a/engines/sherlock/scalpel/scalpel_screen.h +++ b/engines/sherlock/scalpel/scalpel_screen.h @@ -61,44 +61,6 @@ public: void makeField(const Common::Rect &r); }; -class Scalpel3DOScreen : public ScalpelScreen { -protected: - /** - * Draws a sub-section of a surface at a given position within this surface - * Overriden for the 3DO to automatically double the size of everything to the underlying 640x400 surface - */ - virtual void blitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds); - - /** - * Draws a surface at a given position within this surface with transparency - */ - virtual void transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt, bool flipped, - int overrideColor); -public: - Scalpel3DOScreen(SherlockEngine *vm) : ScalpelScreen(vm) {} - virtual ~Scalpel3DOScreen() {} - - /** - * Draws a sub-section of a surface at a given position within this surface - */ - void rawBlitFrom(const Graphics::Surface &src, const Common::Point &pt); - - /** - * Fade backbuffer 1 into screen (3DO RGB!) - */ - void fadeIntoScreen3DO(int speed); - - void blitFrom3DOcolorLimit(uint16 color); - - /** - * Fill a given area of the surface with a given color - */ - virtual void fillRect(const Common::Rect &r, uint color); - - virtual uint16 w() const; - virtual uint16 h() const; -}; - } // End of namespace Scalpel } // End of namespace Sherlock diff --git a/engines/sherlock/scalpel/scalpel_user_interface.cpp b/engines/sherlock/scalpel/scalpel_user_interface.cpp index 4e7cf5c378..6534f61a87 100644 --- a/engines/sherlock/scalpel/scalpel_user_interface.cpp +++ b/engines/sherlock/scalpel/scalpel_user_interface.cpp @@ -148,23 +148,24 @@ void ScalpelUserInterface::reset() { void ScalpelUserInterface::drawInterface(int bufferNum) { Screen &screen = *_vm->_screen; - const ImageFrame &src = (*_controlPanel)[0]; + const Graphics::Surface &src = (*_controlPanel)[0]._frame; int16 x = (!IS_3DO) ? 0 : UI_OFFSET_3DO; if (bufferNum & 1) { if (IS_3DO) screen._backBuffer1.fillRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), BLACK); - screen._backBuffer1.transBlitFrom(src, Common::Point(x, CONTROLS_Y)); + screen._backBuffer1.SHtransBlitFrom(src, Common::Point(x, CONTROLS_Y)); } if (bufferNum & 2) { if (IS_3DO) screen._backBuffer2.fillRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), BLACK); - screen._backBuffer2.transBlitFrom(src, Common::Point(x, CONTROLS_Y)); + screen._backBuffer2.SHtransBlitFrom(src, Common::Point(x, CONTROLS_Y)); } if (bufferNum == 3) - screen._backBuffer2.fillRect(0, INFO_LINE, SHERLOCK_SCREEN_WIDTH, INFO_LINE + 10, INFO_BLACK); + screen._backBuffer2.SHfillRect(Common::Rect(0, INFO_LINE, + SHERLOCK_SCREEN_WIDTH, INFO_LINE + 10), INFO_BLACK); } void ScalpelUserInterface::handleInput() { @@ -426,7 +427,7 @@ void ScalpelUserInterface::depressButton(int num) { offsetButton3DO(pt, num); ImageFrame &frame = (*_controls)[num]; - screen._backBuffer1.transBlitFrom(frame, pt); + screen._backBuffer1.SHtransBlitFrom(frame, pt); screen.slamArea(pt.x, pt.y, pt.x + frame._width, pt.y + frame._height); } @@ -442,7 +443,7 @@ void ScalpelUserInterface::restoreButton(int num) { events.setCursor(ARROW); // Restore the UI on the back buffer - screen._backBuffer1.blitFrom(screen._backBuffer2, pt, + screen._backBuffer1.SHblitFrom(screen._backBuffer2, pt, Common::Rect(pt.x, pt.y, pt.x + 90, pt.y + 19)); screen.slamArea(pt.x, pt.y, pt.x + frame.w, pt.y + frame.h); @@ -489,7 +490,7 @@ void ScalpelUserInterface::toggleButton(uint16 num) { ImageFrame &frame = (*_controls)[num]; Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]); offsetButton3DO(pt, num); - screen._backBuffer1.transBlitFrom(frame, pt); + screen._backBuffer1.SHtransBlitFrom(frame, pt); screen.slamArea(pt.x, pt.y, pt.x + frame._width, pt.y + frame._height); } } else { @@ -501,7 +502,7 @@ void ScalpelUserInterface::toggleButton(uint16 num) { void ScalpelUserInterface::clearInfo() { if (_infoFlag) { - _vm->_screen->vgaBar(Common::Rect(IS_3DO ? 33 : 16, INFO_LINE, + _vm->_screen->vgaBar(Common::Rect(IS_3DO ? 33 : 16, INFO_LINE, SHERLOCK_SCREEN_WIDTH - (IS_3DO ? 33 : 19), INFO_LINE + 10), INFO_BLACK); _infoFlag = false; _oldLook = -1; @@ -605,74 +606,92 @@ void ScalpelUserInterface::lookScreen(const Common::Point &pt) { // If inventory is active and an item is selected for a Use or Give action if ((_menuMode == INV_MODE || _menuMode == USE_MODE || _menuMode == GIVE_MODE) && (inv._invMode == INVMODE_USE || inv._invMode == INVMODE_GIVE)) { - int width1 = 0, width2 = 0; - int x, width; + int width1 = 0, width2 = 0, width3 = 0; + int x; + if (inv._invMode == INVMODE_USE) { // Using an object - x = width = screen.stringWidth("Use "); + Common::String useText1 = FIXED(UserInterface_Use); + Common::String useText2; + Common::String useText3; - if (temp < 1000 && scene._bgShapes[temp]._aType != PERSON) - // It's not a person, so make it lowercase - tempStr.setChar(tolower(tempStr[0]), 0); + x = width1 = screen.stringWidth(useText1); - x += screen.stringWidth(tempStr); + if (temp < 1000 && scene._bgShapes[temp]._aType != PERSON) { + // It's not a person, so make it lowercase + switch (_vm->getLanguage()) { + case Common::DE_DEU: + case Common::ES_ESP: + // don't do this for German + Spanish version + break; + default: + tempStr.setChar(tolower(tempStr[0]), 0); + break; + } + } // If we're using an inventory object, add in the width // of the object name and the " on " if (_selector != -1) { - width1 = screen.stringWidth(inv[_selector]._name); - x += width1; - width2 = screen.stringWidth(" on "); + useText2 = inv[_selector]._name; + width2 = screen.stringWidth(useText2); x += width2; + + useText3 = Common::String::format(FIXED(UserInterface_UseOn), tempStr.c_str()); + + } else { + useText3 = tempStr; } + width3 = screen.stringWidth(useText3); + x += width3; + // If the line will be too long, keep cutting off characters // until the string will fit while (x > 280) { - x -= screen.charWidth(tempStr.lastChar()); - tempStr.deleteLastChar(); + x -= screen.charWidth(useText3.lastChar()); + useText3.deleteLastChar(); } int xStart = (SHERLOCK_SCREEN_WIDTH - x) / 2; screen.print(Common::Point(xStart, INFO_LINE + 1), - INFO_FOREGROUND, "Use "); + INFO_FOREGROUND, "%s", useText1.c_str()); if (_selector != -1) { - screen.print(Common::Point(xStart + width, INFO_LINE + 1), - TALK_FOREGROUND, "%s", inv[_selector]._name.c_str()); - screen.print(Common::Point(xStart + width + width1, INFO_LINE + 1), - INFO_FOREGROUND, " on "); - screen.print(Common::Point(xStart + width + width1 + width2, INFO_LINE + 1), - INFO_FOREGROUND, "%s", tempStr.c_str()); + screen.print(Common::Point(xStart + width1, INFO_LINE + 1), + TALK_FOREGROUND, "%s", useText2.c_str()); + screen.print(Common::Point(xStart + width1 + width2, INFO_LINE + 1), + INFO_FOREGROUND, "%s", useText3.c_str()); } else { - screen.print(Common::Point(xStart + width, INFO_LINE + 1), - INFO_FOREGROUND, "%s", tempStr.c_str()); + screen.print(Common::Point(xStart + width1, INFO_LINE + 1), + INFO_FOREGROUND, "%s", useText3.c_str()); } } else if (temp >= 0 && temp < 1000 && _selector != -1 && scene._bgShapes[temp]._aType == PERSON) { + Common::String giveText1 = FIXED(UserInterface_Give); + Common::String giveText2 = inv[_selector]._name; + Common::String giveText3 = Common::String::format(FIXED(UserInterface_GiveTo), tempStr.c_str()); + // Giving an object to a person - width1 = screen.stringWidth(inv[_selector]._name); - x = width = screen.stringWidth("Give "); - x += width1; - width2 = screen.stringWidth(" to "); + x = width1 = screen.stringWidth(giveText1); + width2 = screen.stringWidth(giveText2); x += width2; - x += screen.stringWidth(tempStr); + width3 = screen.stringWidth(giveText3); + x += width3; // Ensure string will fit on-screen while (x > 280) { - x -= screen.charWidth(tempStr.lastChar()); - tempStr.deleteLastChar(); + x -= screen.charWidth(giveText3.lastChar()); + giveText3.deleteLastChar(); } int xStart = (SHERLOCK_SCREEN_WIDTH - x) / 2; screen.print(Common::Point(xStart, INFO_LINE + 1), - INFO_FOREGROUND, "Give "); - screen.print(Common::Point(xStart + width, INFO_LINE + 1), - TALK_FOREGROUND, "%s", inv[_selector]._name.c_str()); - screen.print(Common::Point(xStart + width + width1, INFO_LINE + 1), - INFO_FOREGROUND, " to "); - screen.print(Common::Point(xStart + width + width1 + width2, INFO_LINE + 1), - INFO_FOREGROUND, "%s", tempStr.c_str()); + INFO_FOREGROUND, "%s", giveText1.c_str()); + screen.print(Common::Point(xStart + width1, INFO_LINE + 1), + TALK_FOREGROUND, "%s", giveText2.c_str()); + screen.print(Common::Point(xStart + width1 + width2, INFO_LINE + 1), + INFO_FOREGROUND, "%s", giveText3.c_str()); } } else { screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", tempStr.c_str()); @@ -909,7 +928,7 @@ void ScalpelUserInterface::doEnvControl() { } while (saves._savegameIndex < (MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT) && moreKeys); } else if ((found == 5 && events._released) || _key == saves._hotkeyQuit) { clearWindow(); - screen.print(Common::Point(0, CONTROLS_Y + 20), INV_FOREGROUND, saves._fixedTextQuitGameQuestion.c_str()); + screen.print(Common::Point(0, CONTROLS_Y + 20), INV_FOREGROUND, "%s", saves._fixedTextQuitGameQuestion.c_str()); screen.vgaBar(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y + 10), BORDER_COLOR); screen.makeButton(Common::Rect(112, CONTROLS_Y, 160, CONTROLS_Y + 10), 136, saves._fixedTextQuitGameYes); @@ -1254,7 +1273,7 @@ void ScalpelUserInterface::doLookControl() { // Need to close the window and depress the Look button Common::Point pt(MENU_POINTS[0][0], MENU_POINTS[0][1]); offsetButton3DO(pt, 0); - screen._backBuffer2.blitFrom((*_controls)[0], pt); + screen._backBuffer2.SHblitFrom((*_controls)[0], pt); banishWindow(true); _windowBounds.top = CONTROLS_Y1; @@ -1278,14 +1297,14 @@ void ScalpelUserInterface::doLookControl() { // Looking at an inventory object // Backup the user interface Surface tempSurface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT - CONTROLS_Y1); - tempSurface.blitFrom(screen._backBuffer2, Common::Point(0, 0), + tempSurface.SHblitFrom(screen._backBuffer2, Common::Point(0, 0), Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); inv.drawInventory(INVENTORY_DONT_DISPLAY); banishWindow(true); // Restore the ui - screen._backBuffer2.blitFrom(tempSurface, Common::Point(0, CONTROLS_Y1)); + screen._backBuffer2.SHblitFrom(tempSurface, Common::Point(0, CONTROLS_Y1)); _windowBounds.top = CONTROLS_Y1; _key = _oldKey = _hotkeyLook; @@ -1869,7 +1888,7 @@ void ScalpelUserInterface::journalControl() { // Reset the palette screen.setPalette(screen._cMap); - screen._backBuffer1.blitFrom(screen._backBuffer2); + screen._backBuffer1.SHblitFrom(screen._backBuffer2); scene.updateBackground(); screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); } @@ -1903,9 +1922,9 @@ void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool first Common::Point pt(MENU_POINTS[0][0], MENU_POINTS[0][1]); offsetButton3DO(pt, 0); - tempSurface.blitFrom(screen._backBuffer2, Common::Point(0, 0), - Common::Rect(pt.x, pt.y, pt.x + tempSurface.w(), pt.y + tempSurface.h())); - screen._backBuffer2.transBlitFrom((*_controls)[0], pt); + tempSurface.SHblitFrom(screen._backBuffer2, Common::Point(0, 0), + Common::Rect(pt.x, pt.y, pt.x + tempSurface.width(), pt.y + tempSurface.height())); + screen._backBuffer2.SHtransBlitFrom((*_controls)[0], pt); banishWindow(1); events.setCursor(MAGNIFY); @@ -1915,7 +1934,7 @@ void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool first _menuMode = LOOK_MODE; events.clearEvents(); - screen._backBuffer2.blitFrom(tempSurface, pt); + screen._backBuffer2.SHblitFrom(tempSurface, pt); } else { events.setCursor(ARROW); banishWindow(true); @@ -2053,9 +2072,9 @@ void ScalpelUserInterface::summonWindow(const Surface &bgSurface, bool slideUp) if (slideUp) { // Gradually slide up the display of the window - for (int idx = 1; idx <= bgSurface.h(); idx += 2) { - screen._backBuffer->blitFrom(bgSurface, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - idx), - Common::Rect(0, 0, bgSurface.w(), idx)); + for (int idx = 1; idx <= bgSurface.height(); idx += 2) { + screen._backBuffer->SHblitFrom(bgSurface, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - idx), + Common::Rect(0, 0, bgSurface.width(), idx)); screen.slamRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - idx, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); @@ -2063,21 +2082,21 @@ void ScalpelUserInterface::summonWindow(const Surface &bgSurface, bool slideUp) } } else { // Gradually slide down the display of the window - for (int idx = 1; idx <= bgSurface.h(); idx += 2) { - screen._backBuffer->blitFrom(bgSurface, - Common::Point(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h()), - Common::Rect(0, bgSurface.h() - idx, bgSurface.w(), bgSurface.h())); - screen.slamRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h(), - SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT - bgSurface.h() + idx)); + for (int idx = 1; idx <= bgSurface.height(); idx += 2) { + screen._backBuffer->SHblitFrom(bgSurface, + Common::Point(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.height()), + Common::Rect(0, bgSurface.height() - idx, bgSurface.width(), bgSurface.height())); + screen.slamRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.height(), + SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT - bgSurface.height() + idx)); events.delay(10); } } // Final display of the entire window - screen._backBuffer->blitFrom(bgSurface, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h()), - Common::Rect(0, 0, bgSurface.w(), bgSurface.h())); - screen.slamArea(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h(), bgSurface.w(), bgSurface.h()); + screen._backBuffer->SHblitFrom(bgSurface, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.height()), + Common::Rect(0, 0, bgSurface.width(), bgSurface.height())); + screen.slamArea(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.height(), bgSurface.width(), bgSurface.height()); _windowOpen = true; } @@ -2088,10 +2107,10 @@ void ScalpelUserInterface::summonWindow(bool slideUp, int height) { // Extract the window that's been drawn on the back buffer Surface tempSurface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT - height); Common::Rect r(0, height, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); - tempSurface.blitFrom(screen._backBuffer1, Common::Point(0, 0), r); + tempSurface.SHblitFrom(screen._backBuffer1, Common::Point(0, 0), r); // Remove drawn window with original user interface - screen._backBuffer1.blitFrom(screen._backBuffer2, + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(0, height), r); // Display the window gradually on-screen @@ -2115,7 +2134,7 @@ void ScalpelUserInterface::banishWindow(bool slideUp) { Common::copy_backward(pSrc, pSrcEnd, pDest); // Restore lines from the ui in the secondary back buffer - screen._backBuffer1.blitFrom(screen._backBuffer2, + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(0, CONTROLS_Y), Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y + idx)); @@ -2125,14 +2144,14 @@ void ScalpelUserInterface::banishWindow(bool slideUp) { } // Restore final two old lines - screen._backBuffer1.blitFrom(screen._backBuffer2, + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - 2), Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 2, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); screen.slamArea(0, SHERLOCK_SCREEN_HEIGHT - 2, SHERLOCK_SCREEN_WIDTH, 2); } else { // Restore old area to completely erase window - screen._backBuffer1.blitFrom(screen._backBuffer2, + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(0, CONTROLS_Y), Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, @@ -2152,7 +2171,7 @@ void ScalpelUserInterface::banishWindow(bool slideUp) { } // Show entire final area - screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(0, CONTROLS_Y1), + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(0, CONTROLS_Y1), Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); screen.slamRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); } @@ -2234,7 +2253,7 @@ void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::Stri if (scene._goToScene != 1 && !printed && !talk._talkToAbort) { _infoFlag = true; clearInfo(); - screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "Done..."); + screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", FIXED(UserInterface_Done)); _menuCounter = 25; } } @@ -2244,9 +2263,9 @@ void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::Stri clearInfo(); if (giveMode) { - screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "No, thank you."); + screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", FIXED(UserInterface_NoThankYou)); } else if (fixedTextActionId == kFixedTextAction_Invalid) { - screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "You can't do that."); + screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", FIXED(UserInterface_YouCantDoThat)); } else { Common::String errorMessage = fixedText.getActionMessage(fixedTextActionId, 0); screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", errorMessage.c_str()); diff --git a/engines/sherlock/scalpel/tsage/logo.cpp b/engines/sherlock/scalpel/tsage/logo.cpp index 273d26df74..a885057f35 100644 --- a/engines/sherlock/scalpel/tsage/logo.cpp +++ b/engines/sherlock/scalpel/tsage/logo.cpp @@ -217,7 +217,7 @@ void Object::erase() { Screen &screen = *_vm->_screen; if (_visage.isLoaded() && !_oldBounds.isEmpty()) - screen.blitFrom(screen._backBuffer1, Common::Point(_oldBounds.left, _oldBounds.top), _oldBounds); + screen.SHblitFrom(screen._backBuffer1, Common::Point(_oldBounds.left, _oldBounds.top), _oldBounds); } void Object::update() { @@ -246,9 +246,9 @@ void Object::update() { _visage.getFrame(s, _frame); // Display the frame - _oldBounds = Common::Rect(_position.x, _position.y, _position.x + s.w(), _position.y + s.h()); + _oldBounds = Common::Rect(_position.x, _position.y, _position.x + s.width(), _position.y + s.height()); _oldBounds.translate(-s._centroid.x, -s._centroid.y); - screen.transBlitFrom(s, Common::Point(_oldBounds.left, _oldBounds.top)); + screen.SHtransBlitFrom(s, Common::Point(_oldBounds.left, _oldBounds.top)); } } @@ -652,7 +652,7 @@ void Logo::loadBackground() { screen.setPalette(palette); // Copy the surface to the screen - screen.blitFrom(screen._backBuffer1); + screen.SHblitFrom(screen._backBuffer1); } void Logo::fade(const byte palette[PALETTE_SIZE], int step) { diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp index 6f9ef179a3..78d0cd862c 100644 --- a/engines/sherlock/scene.cpp +++ b/engines/sherlock/scene.cpp @@ -27,6 +27,7 @@ #include "sherlock/scalpel/scalpel_people.h" #include "sherlock/scalpel/scalpel_scene.h" #include "sherlock/scalpel/scalpel_screen.h" +#include "sherlock/scalpel/3do/scalpel_3do_screen.h" #include "sherlock/tattoo/tattoo.h" #include "sherlock/tattoo/tattoo_scene.h" #include "sherlock/tattoo/tattoo_user_interface.h" @@ -356,7 +357,7 @@ bool Scene::loadScene(const Common::String &filename) { if (IS_ROSE_TATTOO) { // Resize the screen if necessary int fullWidth = SHERLOCK_SCREEN_WIDTH + bgHeader._scrollSize; - if (screen._backBuffer1.w() != fullWidth) { + if (screen._backBuffer1.width() != fullWidth) { screen._backBuffer1.create(fullWidth, SHERLOCK_SCREEN_HEIGHT); screen._backBuffer2.create(fullWidth, SHERLOCK_SCREEN_HEIGHT); } @@ -649,7 +650,7 @@ bool Scene::loadScene(const Common::String &filename) { } // Backup the image and set the palette - screen._backBuffer2.blitFrom(screen._backBuffer1); + screen._backBuffer2.SHblitFrom(screen._backBuffer1); screen.setPalette(screen._cMap); delete rrmStream; @@ -996,12 +997,12 @@ bool Scene::loadScene(const Common::String &filename) { #if 0 // code to show the background - screen.blitFrom(screen._backBuffer1); + screen.SHblitFrom(screen._backBuffer1); _vm->_events->wait(10000); #endif // Backup the image - screen._backBuffer2.blitFrom(screen._backBuffer1); + screen._backBuffer2.SHblitFrom(screen._backBuffer1); } // Handle drawing any on-screen interface @@ -1236,7 +1237,7 @@ void Scene::transitionToScene() { // If the scene is capable of scrolling, set the current scroll so that whoever has control // of the scroll code is in the middle of the screen - if (screen._backBuffer1.w() > SHERLOCK_SCREEN_WIDTH) + if (screen._backBuffer1.width() > SHERLOCK_SCREEN_WIDTH) people[people._walkControl].centerScreenOnPerson(); for (uint objIdx = 0; objIdx < _bgShapes.size(); ++objIdx) { diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp index 74da2a80ea..85d47c84dc 100644 --- a/engines/sherlock/screen.cpp +++ b/engines/sherlock/screen.cpp @@ -23,6 +23,8 @@ #include "sherlock/screen.h" #include "sherlock/sherlock.h" #include "sherlock/scalpel/scalpel_screen.h" +#include "sherlock/scalpel/3do/scalpel_3do_screen.h" +#include "sherlock/tattoo/tattoo_screen.h" #include "common/system.h" #include "common/util.h" #include "graphics/palette.h" @@ -31,17 +33,14 @@ namespace Sherlock { Screen *Screen::init(SherlockEngine *vm) { if (vm->getGameID() == GType_RoseTattoo) - return new Screen(vm); + return new Tattoo::TattooScreen(vm); else if (vm->getPlatform() == Common::kPlatform3DO) return new Scalpel::Scalpel3DOScreen(vm); else return new Scalpel::ScalpelScreen(vm); } -Screen::Screen(SherlockEngine *vm) : Surface(g_system->getWidth(), g_system->getHeight()), _vm(vm), - _backBuffer1(vm->getGameID() == GType_RoseTattoo ? 640 : 320, vm->getGameID() == GType_RoseTattoo ? 480 : 200), - _backBuffer2(vm->getGameID() == GType_RoseTattoo ? 640 : 320, vm->getGameID() == GType_RoseTattoo ? 480 : 200), - _backBuffer(&_backBuffer1) { +Screen::Screen(SherlockEngine *vm) : Graphics::Screen(), _vm(vm), _backBuffer(&_backBuffer1) { _transitionSeed = 1; _fadeStyle = false; Common::fill(&_cMap[0], &_cMap[PALETTE_SIZE], 0); @@ -58,37 +57,7 @@ Screen::Screen(SherlockEngine *vm) : Surface(g_system->getWidth(), g_system->get } Screen::~Screen() { - Fonts::free(); -} - -void Screen::update() { - // Merge the dirty rects - mergeDirtyRects(); - - // Loop through copying dirty areas to the physical screen - Common::List<Common::Rect>::iterator i; - for (i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i) { - const Common::Rect &r = *i; - const byte *srcP = (const byte *)getBasePtr(r.left, r.top); - g_system->copyRectToScreen(srcP, _surface.pitch, r.left, r.top, - r.width(), r.height()); - } - - // Signal the physical screen to update - g_system->updateScreen(); - _dirtyRects.clear(); -} - -void Screen::makeAllDirty() { - addDirtyRect(Common::Rect(0, 0, this->w(), this->h())); -} - -void Screen::getPalette(byte palette[PALETTE_SIZE]) { - g_system->getPaletteManager()->grabPalette(palette, 0, PALETTE_COUNT); -} - -void Screen::setPalette(const byte palette[PALETTE_SIZE]) { - g_system->getPaletteManager()->setPalette(palette, 0, PALETTE_COUNT); + Fonts::freeFont(); } int Screen::equalizePalette(const byte palette[PALETTE_SIZE]) { @@ -124,7 +93,7 @@ void Screen::fadeToBlack(int speed) { } setPalette(tempPalette); - fillRect(Common::Rect(0, 0, _surface.w, _surface.h), 0); + fillRect(Common::Rect(0, 0, this->w, this->h), 0); } void Screen::fadeIn(const byte palette[PALETTE_SIZE], int speed) { @@ -136,59 +105,23 @@ void Screen::fadeIn(const byte palette[PALETTE_SIZE], int speed) { setPalette(palette); } -void Screen::addDirtyRect(const Common::Rect &r) { - _dirtyRects.push_back(r); - assert(r.width() > 0 && r.height() > 0); -} - -void Screen::mergeDirtyRects() { - Common::List<Common::Rect>::iterator rOuter, rInner; - - // Process the dirty rect list to find any rects to merge - for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) { - rInner = rOuter; - while (++rInner != _dirtyRects.end()) { - - if ((*rOuter).intersects(*rInner)) { - // these two rectangles overlap or - // are next to each other - merge them - - unionRectangle(*rOuter, *rOuter, *rInner); - - // remove the inner rect from the list - _dirtyRects.erase(rInner); - - // move back to beginning of list - rInner = rOuter; - } - } - } -} - -bool Screen::unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2) { - destRect = src1; - destRect.extend(src2); - - return !destRect.isEmpty(); -} - void Screen::randomTransition() { Events &events = *_vm->_events; const int TRANSITION_MULTIPLIER = 0x15a4e35; - _dirtyRects.clear(); + clearDirtyRects(); assert(IS_SERRATED_SCALPEL); for (int idx = 0; idx <= 65535 && !_vm->shouldQuit(); ++idx) { _transitionSeed = _transitionSeed * TRANSITION_MULTIPLIER + 1; int offset = _transitionSeed & 0xFFFF; - if (offset < (this->w() * this->h())) + if (offset < (this->width() * this->height())) *((byte *)getPixels() + offset) = *((const byte *)_backBuffer->getPixels() + offset); if (idx != 0 && (idx % 300) == 0) { // Ensure there's a full screen dirty rect for the next frame update - if (_dirtyRects.empty()) - addDirtyRect(Common::Rect(0, 0, _surface.w, _surface.h)); + if (!isDirty()) + addDirtyRect(Common::Rect(0, 0, this->w, this->h)); events.pollEvents(); events.delay(1); @@ -196,7 +129,7 @@ void Screen::randomTransition() { } // Make sure everything has been transferred - blitFrom(*_backBuffer); + SHblitFrom(*_backBuffer); } void Screen::verticalTransition() { @@ -205,13 +138,13 @@ void Screen::verticalTransition() { byte table[640]; Common::fill(&table[0], &table[640], 0); - for (int yp = 0; yp < this->h(); ++yp) { - for (int xp = 0; xp < this->w(); ++xp) { - int temp = (table[xp] >= (this->h() - 3)) ? this->h() - table[xp] : + for (int yp = 0; yp < this->height(); ++yp) { + for (int xp = 0; xp < this->width(); ++xp) { + int temp = (table[xp] >= (this->height() - 3)) ? this->height() - table[xp] : _vm->getRandomNumber(3) + 1; if (temp) { - blitFrom(_backBuffer1, Common::Point(xp, table[xp]), + SHblitFrom(_backBuffer1, Common::Point(xp, table[xp]), Common::Rect(xp, table[xp], xp + 1, table[xp] + temp)); table[xp] += temp; } @@ -223,7 +156,7 @@ void Screen::verticalTransition() { void Screen::restoreBackground(const Common::Rect &r) { if (r.width() > 0 && r.height() > 0) - _backBuffer->blitFrom(_backBuffer2, Common::Point(r.left, r.top), r); + _backBuffer->SHblitFrom(_backBuffer2, Common::Point(r.left, r.top), r); } void Screen::slamArea(int16 xp, int16 yp, int16 width, int16 height) { @@ -254,11 +187,10 @@ void Screen::slamRect(const Common::Rect &r) { } if (srcRect.isValidRect()) - blitFrom(*_backBuffer, Common::Point(destRect.left, destRect.top), srcRect); + SHblitFrom(*_backBuffer, Common::Point(destRect.left, destRect.top), srcRect); } } - void Screen::flushImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp, int16 *width, int16 *height) { Common::Point imgPos = pt + frame->_offset; @@ -335,7 +267,7 @@ void Screen::blockMove(const Common::Rect &r) { } void Screen::blockMove() { - blockMove(Common::Rect(0, 0, w(), h())); + blockMove(Common::Rect(0, 0, width(), height())); } void Screen::print(const Common::Point &pt, uint color, const char *formatStr, ...) { @@ -351,13 +283,13 @@ void Screen::print(const Common::Point &pt, uint color, const char *formatStr, . pos.y--; // Font is always drawing one line higher if (!pos.x) // Center text horizontally - pos.x = (this->w() - width) / 2; + pos.x = (this->width() - width) / 2; Common::Rect textBounds(pos.x, pos.y, pos.x + width, pos.y + _fontHeight); - if (textBounds.right > this->w()) - textBounds.moveTo(this->w() - width, textBounds.top); - if (textBounds.bottom > this->h()) - textBounds.moveTo(textBounds.left, this->h() - _fontHeight); + if (textBounds.right > this->width()) + textBounds.moveTo(this->width() - width, textBounds.top); + if (textBounds.bottom > this->height()) + textBounds.moveTo(textBounds.left, this->height() - _fontHeight); // Write out the string at the given position writeString(str, Common::Point(textBounds.left, textBounds.top), color); @@ -387,7 +319,8 @@ void Screen::vgaBar(const Common::Rect &r, int color) { } void Screen::setDisplayBounds(const Common::Rect &r) { - _sceneSurface.setPixels(_backBuffer1.getBasePtr(r.left, r.top), r.width(), r.height(), _backBuffer1.getPixelFormat()); + _sceneSurface.setPixels((byte *)_backBuffer1.getBasePtr(r.left, r.top), + r.width(), r.height(), _backBuffer1.format); _backBuffer = &_sceneSurface; } @@ -397,8 +330,8 @@ void Screen::resetDisplayBounds() { } Common::Rect Screen::getDisplayBounds() { - return (_backBuffer == &_sceneSurface) ? Common::Rect(0, 0, _sceneSurface.w(), _sceneSurface.h()) : - Common::Rect(0, 0, this->w(), this->h()); + return (_backBuffer == &_sceneSurface) ? Common::Rect(0, 0, _sceneSurface.width(), _sceneSurface.height()) : + Common::Rect(0, 0, this->width(), this->height()); } void Screen::synchronize(Serializer &s) { diff --git a/engines/sherlock/screen.h b/engines/sherlock/screen.h index 04a0c1e505..ceeb1297a3 100644 --- a/engines/sherlock/screen.h +++ b/engines/sherlock/screen.h @@ -25,52 +25,30 @@ #include "common/list.h" #include "common/rect.h" +#include "graphics/screen.h" +#include "sherlock/image_file.h" #include "sherlock/surface.h" #include "sherlock/resources.h" #include "sherlock/saveload.h" namespace Sherlock { -#define PALETTE_SIZE 768 -#define PALETTE_COUNT 256 #define VGA_COLOR_TRANS(x) ((x) * 255 / 63) #define BG_GREYSCALE_RANGE_END 229 #define BLACK 0 class SherlockEngine; -class Screen : public Surface { +class Screen : virtual public Graphics::Screen, virtual public Surface { private: - Common::List<Common::Rect> _dirtyRects; uint32 _transitionSeed; Surface _sceneSurface; // Rose Tattoo fields int _fadeBytesRead, _fadeBytesToRead; int _oldFadePercent; -private: - /** - * Merges together overlapping dirty areas of the screen - */ - void mergeDirtyRects(); - - /** - * Returns the union of two dirty area rectangles - */ - bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2); protected: SherlockEngine *_vm; - - /** - * Clear the current dirty rects list - */ - void clearDirtyRects() { _dirtyRects.clear(); } - - /** - * Adds a rectangle to the list of modified areas of the screen during the - * current frame - */ - virtual void addDirtyRect(const Common::Rect &r); public: Surface _backBuffer1, _backBuffer2; Surface *_backBuffer; @@ -86,26 +64,6 @@ public: virtual ~Screen(); /** - * Handles updating any dirty areas of the screen Surface object to the physical screen - */ - void update(); - - /** - * Makes the whole screen dirty - */ - void makeAllDirty(); - - /** - * Return the currently active palette - */ - void getPalette(byte palette[PALETTE_SIZE]); - - /** - * Set the palette - */ - void setPalette(const byte palette[PALETTE_SIZE]); - - /** * Fades from the currently active palette to the passed palette */ int equalizePalette(const byte palette[PALETTE_SIZE]); diff --git a/engines/sherlock/sherlock.h b/engines/sherlock/sherlock.h index b85321c385..d3b2d0cac8 100644 --- a/engines/sherlock/sherlock.h +++ b/engines/sherlock/sherlock.h @@ -63,9 +63,9 @@ enum GameType { GType_RoseTattoo = 1 }; -#define SHERLOCK_SCREEN_WIDTH _vm->_screen->w() -#define SHERLOCK_SCREEN_HEIGHT _vm->_screen->h() -#define SHERLOCK_SCENE_WIDTH _vm->_screen->_backBuffer1.w() +#define SHERLOCK_SCREEN_WIDTH _vm->_screen->width() +#define SHERLOCK_SCREEN_HEIGHT _vm->_screen->height() +#define SHERLOCK_SCENE_WIDTH _vm->_screen->_backBuffer1.width() #define SHERLOCK_SCENE_HEIGHT (IS_SERRATED_SCALPEL ? 138 : 480) #define SCENES_COUNT (IS_SERRATED_SCALPEL ? 63 : 101) #define MAX_BGSHAPES (IS_SERRATED_SCALPEL ? 64 : 150) diff --git a/engines/sherlock/sound.cpp b/engines/sherlock/sound.cpp index 5a9f0c2ec6..e5b1099123 100644 --- a/engines/sherlock/sound.cpp +++ b/engines/sherlock/sound.cpp @@ -120,7 +120,9 @@ byte Sound::decodeSample(byte sample, byte &reference, int16 &scale) { } bool Sound::playSound(const Common::String &name, WaitType waitType, int priority, const char *libraryFilename) { - stopSound(); + // Scalpel has only a single sound handle, so it must be stopped before starting a new sound + if (IS_SERRATED_SCALPEL) + stopSound(); Common::String filename = formFilename(name); diff --git a/engines/sherlock/surface.cpp b/engines/sherlock/surface.cpp index b7fc76325c..46304e1b2f 100644 --- a/engines/sherlock/surface.cpp +++ b/engines/sherlock/surface.cpp @@ -21,245 +21,24 @@ */ #include "sherlock/surface.h" -#include "sherlock/sherlock.h" -#include "sherlock/resources.h" -#include "common/system.h" -#include "graphics/palette.h" +#include "sherlock/fonts.h" namespace Sherlock { -Surface::Surface(uint16 width, uint16 height) : Fonts(), _freePixels(true) { - create(width, height); -} - -Surface::Surface() : Fonts(), _freePixels(false) { -} - -Surface::~Surface() { - if (_freePixels) - _surface.free(); -} - -void Surface::create(uint16 width, uint16 height) { - if (_freePixels) - _surface.free(); - - if (_vm->getPlatform() == Common::kPlatform3DO) { - _surface.create(width, height, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); - } else { - _surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); - } - _freePixels = true; -} - -Graphics::PixelFormat Surface::getPixelFormat() { - return _surface.format; -} - -void Surface::blitFrom(const Surface &src) { - blitFrom(src, Common::Point(0, 0)); -} - -void Surface::blitFrom(const ImageFrame &src) { - blitFrom(src._frame, Common::Point(0, 0)); -} - -void Surface::blitFrom(const Graphics::Surface &src) { - blitFrom(src, Common::Point(0, 0)); -} - -void Surface::blitFrom(const Surface &src, const Common::Point &pt) { - blitFrom(src, pt, Common::Rect(0, 0, src._surface.w, src._surface.h)); -} - -void Surface::blitFrom(const ImageFrame &src, const Common::Point &pt) { - blitFrom(src._frame, pt, Common::Rect(0, 0, src._frame.w, src._frame.h)); -} - -void Surface::blitFrom(const Graphics::Surface &src, const Common::Point &pt) { - blitFrom(src, pt, Common::Rect(0, 0, src.w, src.h)); -} - -void Surface::blitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds) { - Common::Rect srcRect = srcBounds; - Common::Rect destRect(pt.x, pt.y, pt.x + srcRect.width(), pt.y + srcRect.height()); - - if (srcRect.isValidRect() && clip(srcRect, destRect)) { - // Surface is at least partially or completely on-screen - addDirtyRect(destRect); - _surface.copyRectToSurface(src, destRect.left, destRect.top, srcRect); - } -} - -void Surface::blitFrom(const ImageFrame &src, const Common::Point &pt, const Common::Rect &srcBounds) { - blitFrom(src._frame, pt, srcBounds); -} - -void Surface::blitFrom(const Surface &src, const Common::Point &pt, const Common::Rect &srcBounds) { - blitFrom(src._surface, pt, srcBounds); -} - -void Surface::transBlitFrom(const ImageFrame &src, const Common::Point &pt, - bool flipped, int overrideColor, int scaleVal) { - Common::Point drawPt(pt.x + src.sDrawXOffset(scaleVal), pt.y + src.sDrawYOffset(scaleVal)); - transBlitFrom(src._frame, drawPt, flipped, overrideColor, scaleVal); -} - -void Surface::transBlitFrom(const Surface &src, const Common::Point &pt, - bool flipped, int overrideColor, int scaleVal) { - const Graphics::Surface &s = src._surface; - transBlitFrom(s, pt, flipped, overrideColor, scaleVal); -} - -void Surface::transBlitFrom(const Graphics::Surface &src, const Common::Point &pt, - bool flipped, int overrideColor, int scaleVal) { - if (scaleVal == SCALE_THRESHOLD) { - transBlitFromUnscaled(src, pt, flipped, overrideColor); - return; - } - - int destWidth = src.w * SCALE_THRESHOLD / scaleVal; - int destHeight = src.h * SCALE_THRESHOLD / scaleVal; - - // Loop through drawing output lines - for (int destY = pt.y, scaleYCtr = 0; destY < (pt.y + destHeight); ++destY, scaleYCtr += scaleVal) { - if (destY < 0 || destY >= this->h()) - continue; - const byte *srcLine = (const byte *)src.getBasePtr(0, scaleYCtr / SCALE_THRESHOLD); - byte *destLine = (byte *)getBasePtr(pt.x, destY); - - // Loop through drawing individual rows - for (int xCtr = 0, scaleXCtr = 0; xCtr < destWidth; ++xCtr, scaleXCtr += scaleVal) { - int destX = pt.x + xCtr; - if (destX < 0 || destX >= this->w()) - continue; - - byte srcVal = srcLine[flipped ? src.w - scaleXCtr / SCALE_THRESHOLD - 1 : scaleXCtr / SCALE_THRESHOLD]; - if (srcVal != TRANSPARENCY) - destLine[xCtr] = srcVal; - } - } - - // Mark the affected area - addDirtyRect(Common::Rect(pt.x, pt.y, pt.x + destWidth, pt.y + destHeight)); -} - -void Surface::transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt, - bool flipped, int overrideColor) { - Common::Rect drawRect(0, 0, src.w, src.h); - Common::Rect destRect(pt.x, pt.y, pt.x + src.w, pt.y + src.h); - - // Clip the display area to on-screen - if (!clip(drawRect, destRect)) - // It's completely off-screen - return; - - if (flipped) - drawRect = Common::Rect(src.w - drawRect.right, drawRect.top, - src.w - drawRect.left, drawRect.bottom); - - Common::Point destPt(destRect.left, destRect.top); - addDirtyRect(Common::Rect(destPt.x, destPt.y, destPt.x + drawRect.width(), - destPt.y + drawRect.height())); - - switch (src.format.bytesPerPixel) { - case 1: - // 8-bit palettized: Draw loop - assert(_surface.format.bytesPerPixel == 1); // Security check - for (int yp = 0; yp < drawRect.height(); ++yp) { - const byte *srcP = (const byte *)src.getBasePtr( - flipped ? drawRect.right - 1 : drawRect.left, drawRect.top + yp); - byte *destP = (byte *)getBasePtr(destPt.x, destPt.y + yp); - - for (int xp = 0; xp < drawRect.width(); ++xp, ++destP) { - if (*srcP != TRANSPARENCY) - *destP = overrideColor ? overrideColor : *srcP; - - srcP = flipped ? srcP - 1 : srcP + 1; - } - } - break; - case 2: - // 3DO 15-bit RGB565: Draw loop - assert(_surface.format.bytesPerPixel == 2); // Security check - for (int yp = 0; yp < drawRect.height(); ++yp) { - const uint16 *srcP = (const uint16 *)src.getBasePtr( - flipped ? drawRect.right - 1 : drawRect.left, drawRect.top + yp); - uint16 *destP = (uint16 *)getBasePtr(destPt.x, destPt.y + yp); - - for (int xp = 0; xp < drawRect.width(); ++xp, ++destP) { - if (*srcP) // RGB 0, 0, 0 -> transparent on 3DO - *destP = *srcP; // overrideColor ? overrideColor : *srcP; - - srcP = flipped ? srcP - 1 : srcP + 1; - } - } - break; - default: - error("Surface: unsupported bytesperpixel"); - break; - } +Surface::Surface() : Graphics::ManagedSurface(), Fonts() { } -void Surface::fillRect(int x1, int y1, int x2, int y2, uint color) { - fillRect(Common::Rect(x1, y1, x2, y2), color); -} - -void Surface::fillRect(const Common::Rect &r, uint color) { - _surface.fillRect(r, color); - addDirtyRect(r); -} - -void Surface::fill(uint color) { - fillRect(Common::Rect(_surface.w, _surface.h), color); -} - -bool Surface::clip(Common::Rect &srcBounds, Common::Rect &destBounds) { - if (destBounds.left >= w() || destBounds.top >= h() || - destBounds.right <= 0 || destBounds.bottom <= 0) - return false; - - // Clip the bounds if necessary to fit on-screen - if (destBounds.right > w()) { - srcBounds.right -= destBounds.right - w(); - destBounds.right = w(); - } - - if (destBounds.bottom > h()) { - srcBounds.bottom -= destBounds.bottom - h(); - destBounds.bottom = h(); - } - - if (destBounds.top < 0) { - srcBounds.top += -destBounds.top; - destBounds.top = 0; - } - - if (destBounds.left < 0) { - srcBounds.left += -destBounds.left; - destBounds.left = 0; - } - - return true; -} - -void Surface::clear() { - fillRect(Common::Rect(0, 0, w(), h()), 0); -} - -void Surface::free() { - if (_freePixels) { - _surface.free(); - _freePixels = false; - } +Surface::Surface(int width, int height) : Graphics::ManagedSurface(width, height), + Fonts() { + create(width, height); } -void Surface::setPixels(byte *pixels, int width, int height, Graphics::PixelFormat pixelFormat) { - _surface.format = pixelFormat; - _surface.w = width; - _surface.h = height; - _surface.pitch = width * pixelFormat.bytesPerPixel; - _surface.setPixels(pixels); +void Surface::setPixels(byte *pixelsPtr, int sizeX, int sizeY, const Graphics::PixelFormat &pixFormat) { + Graphics::ManagedSurface::setPixels(pixelsPtr); + this->format = pixFormat; + this->w = sizeX; + this->h = sizeY; + this->pitch = sizeX * pixFormat.bytesPerPixel; } void Surface::writeString(const Common::String &str, const Common::Point &pt, uint overrideColor) { @@ -278,4 +57,21 @@ void Surface::writeFancyString(const Common::String &str, const Common::Point &p writeString(str, Common::Point(pt.x + 1, pt.y + 1), overrideColor2); } +void Surface::SHtransBlitFrom(const ImageFrame &src, const Common::Point &pt, + bool flipped, int overrideColor, int scaleVal) { + Common::Point drawPt(pt.x + src.sDrawXOffset(scaleVal), pt.y + src.sDrawYOffset(scaleVal)); + SHtransBlitFrom(src._frame, drawPt, flipped, overrideColor, scaleVal); +} + +void Surface::SHtransBlitFrom(const Graphics::Surface &src, const Common::Point &pt, + bool flipped, int overrideColor, int scaleVal) { + Common::Rect srcRect(0, 0, src.w, src.h); + Common::Rect destRect(pt.x, pt.y, pt.x + src.w * SCALE_THRESHOLD / scaleVal, + pt.y + src.h * SCALE_THRESHOLD / scaleVal); + + Graphics::ManagedSurface::transBlitFrom(src, srcRect, destRect, TRANSPARENCY, + flipped, overrideColor); +} + + } // End of namespace Sherlock diff --git a/engines/sherlock/surface.h b/engines/sherlock/surface.h index 378c9be9cd..648b121852 100644 --- a/engines/sherlock/surface.h +++ b/engines/sherlock/surface.h @@ -20,165 +20,101 @@ * */ -#ifndef SHERLOCK_GRAPHICS_H -#define SHERLOCK_GRAPHICS_H +#ifndef SHERLOCK_SURFACE_H +#define SHERLOCK_SURFACE_H #include "common/rect.h" #include "common/platform.h" -#include "graphics/surface.h" +#include "graphics/managed_surface.h" #include "sherlock/fonts.h" +#include "sherlock/image_file.h" namespace Sherlock { #define SCALE_THRESHOLD 0x100 #define TRANSPARENCY 255 -struct ImageFrame; - -class Surface: public Fonts { -private: - bool _freePixels; - - /** - * Copy a surface into this one - */ - void blitFrom(const Graphics::Surface &src); -protected: - Graphics::Surface _surface; - - /** - * Clips the given source bounds so the passed destBounds will be entirely on-screen - */ - bool clip(Common::Rect &srcBounds, Common::Rect &destBounds); - - /** - * Base method stub for signalling dirty rect areas - */ - virtual void addDirtyRect(const Common::Rect &r) {} - - /** - * Draws a sub-section of a surface at a given position within this surface - */ - virtual void blitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds); - +/** + * Implements a descendent surface that combines both a managed surface and the font + * drawing code. It also introduces a series of drawing method stubs that the 3DO + * Serrated Scalpel screen overrides to implement sprite doubling + */ +class Surface: virtual public Graphics::ManagedSurface, public Fonts { +public: /** - * Draws a surface at a given position within this surface with transparency + * Constructor */ - virtual void transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt, bool flipped, - int overrideColor); -public: - Surface(uint16 width, uint16 height); Surface(); - virtual ~Surface(); - + /** - * Sets up an internal surface with the specified dimensions that will be automatically freed - * when the surface object is destroyed + * Constructor */ - void create(uint16 width, uint16 height); - - Graphics::PixelFormat getPixelFormat(); + Surface(int width, int height); /** - * Copy a surface into this one + * Set the surface details */ - void blitFrom(const Surface &src); + void setPixels(byte *pixelsPtr, int sizeX, int sizeY, const Graphics::PixelFormat &pixFormat); /** - * Copy an image frame into this surface + * Draws a surface on this surface */ - void blitFrom(const ImageFrame &src); + virtual void SHblitFrom(const Graphics::Surface &src) { + Graphics::ManagedSurface::blitFrom(src); + } /** * Draws a surface at a given position within this surface */ - void blitFrom(const Surface &src, const Common::Point &pt); - - /** - * Copy an image frame onto this surface at a given position - */ - void blitFrom(const ImageFrame &src, const Common::Point &pt); + virtual void SHblitFrom(const Graphics::Surface &src, const Common::Point &destPos) { + Graphics::ManagedSurface::blitFrom(src, destPos); + } /** * Draws a sub-section of a surface at a given position within this surface */ - void blitFrom(const Surface &src, const Common::Point &pt, const Common::Rect &srcBounds); - - /** - * Copy a sub-area of a source image frame into this surface at a given position - */ - void blitFrom(const ImageFrame &src, const Common::Point &pt, const Common::Rect &srcBounds); - - /** - * Draws a surface at a given position within this surface - */ - void blitFrom(const Graphics::Surface &src, const Common::Point &pt); + virtual void SHblitFrom(const Graphics::Surface &src, const Common::Point &destPos, const Common::Rect &srcBounds) { + Graphics::ManagedSurface::blitFrom(src, srcBounds, destPos); + } /** * Draws an image frame at a given position within this surface with transparency */ - void transBlitFrom(const ImageFrame &src, const Common::Point &pt, - bool flipped = false, int overrideColor = 0, int scaleVal = 256); - - /** - * Draws a surface at a given position within this surface with transparency - */ - void transBlitFrom(const Surface &src, const Common::Point &pt, - bool flipped = false, int overrideColor = 0, int scaleVal = 256); + void SHtransBlitFrom(const ImageFrame &src, const Common::Point &pt, + bool flipped = false, int overrideColor = 0, int scaleVal = SCALE_THRESHOLD); /** - * Draws a surface at a given position within this surface with transparency + * Draws an image frame at a given position within this surface with transparency */ - void transBlitFrom(const Graphics::Surface &src, const Common::Point &pt, - bool flipped = false, int overrideColor = 0, int scaleVal = 256); + void SHtransBlitFrom(const Graphics::Surface &src, const Common::Point &pt, + bool flipped = false, int overrideColor = 0, int scaleVal = SCALE_THRESHOLD); /** * Fill a given area of the surface with a given color */ - void fillRect(int x1, int y1, int x2, int y2, uint color); - - /** - * Fill a given area of the surface with a given color - */ - virtual void fillRect(const Common::Rect &r, uint color); - - void fill(uint color); - - /** - * Clear the surface - */ - void clear(); + virtual void SHfillRect(const Common::Rect &r, uint color) { + Graphics::ManagedSurface::fillRect(r, color); + } /** - * Free the underlying surface + * Return the width of the surface */ - void free(); - + virtual uint16 width() const { return this->w; } + /** - * Returns true if the surface is empty + * Return the height of the surface */ - bool empty() const { return _surface.getPixels() == nullptr; } + virtual uint16 height() const { return this->h; } /** - * Set the pixels for the surface to an existing data block + * Draws the given string into the back buffer using the images stored in _font */ - void setPixels(byte *pixels, int width, int height, Graphics::PixelFormat format); - + void writeString(const Common::String &str, const Common::Point &pt, uint overrideColor); + /** - * Draws the given string into the back buffer using the images stored in _font + * Draws a fancy version of the given string at the given position */ - virtual void writeString(const Common::String &str, const Common::Point &pt, uint overrideColor); void writeFancyString(const Common::String &str, const Common::Point &pt, uint overrideColor1, uint overrideColor2); - - inline virtual uint16 w() const { return _surface.w; } - inline virtual uint16 h() const { return _surface.h; } - inline const byte *getPixels() const { return (const byte *)_surface.getPixels(); } - inline byte *getPixels() { return (byte *)_surface.getPixels(); } - inline byte *getBasePtr(int x, int y) { return (byte *)_surface.getBasePtr(x, y); } - inline const byte *getBasePtr(int x, int y) const { return (const byte *)_surface.getBasePtr(x, y); } - inline Graphics::Surface &getRawSurface() { return _surface; } - inline void hLine(int x, int y, int x2, uint color) { _surface.hLine(x, y, x2, color); } - inline void vLine(int x, int y, int y2, uint color) { _surface.vLine(x, y, y2, color); } }; } // End of namespace Sherlock diff --git a/engines/sherlock/tattoo/tattoo_darts.cpp b/engines/sherlock/tattoo/tattoo_darts.cpp index 512358933d..cbc3ea1fe8 100644 --- a/engines/sherlock/tattoo/tattoo_darts.cpp +++ b/engines/sherlock/tattoo/tattoo_darts.cpp @@ -83,7 +83,9 @@ void Darts::playDarts(GameType gameType) { int numHits = 0; bool gameOver = false; bool done = false; - const char *const NUM_HITS_STR[3] = { "a", FIXED(Double), FIXED(Triple) }; + + // Set the game mode + _gameType = gameType; screen.setFont(7); _spacing = screen.fontHeight() + 2; @@ -161,51 +163,84 @@ void Darts::playDarts(GameType gameType) { // Show scores showStatus(playerNum); - screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(_dartInfo.left, _dartInfo.top - 1), + screen._backBuffer2.SHblitFrom(screen._backBuffer1, Common::Point(_dartInfo.left, _dartInfo.top - 1), Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1)); - screen.print(Common::Point(_dartInfo.left, _dartInfo.top), 0, "%s # %d", FIXED(Dart), idx + 1); + screen.print(Common::Point(_dartInfo.left, _dartInfo.top), 0, FIXED(DartsCurrentDart), idx + 1); if (_gameType == GAME_301) { - if (_vm->getLanguage() == Common::FR_FRA) - screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, - "%s %s: %d", FIXED(Scored), FIXED(Points), lastDart); - else - screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, - "%s %d %s", FIXED(Scored), lastDart, FIXED(Points)); + // "Scored x points" + Common::String scoredPoints; + + // original treated 1 point and multiple points the same. Wrote "Scored 1 points" + if (lastDart == 1) { + scoredPoints = Common::String::format(FIXED(DartsScoredPoint), lastDart); + } else { + scoredPoints = Common::String::format(FIXED(DartsScoredPoints), lastDart); + } + + screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, "%s", scoredPoints.c_str()); } else { - if (lastDart != 25) - screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, - "%s %s %d", FIXED(Hit), NUM_HITS_STR[numHits - 1], lastDart); - else - screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, - "%s %s %s", FIXED(Hit), NUM_HITS_STR[numHits - 1], FIXED(Bullseye)); + Common::String hitText; + + if (lastDart != 25) { + // Regular hit + switch (numHits) { + case 1: // "Hit a X" + hitText = Common::String::format(FIXED(DartsHitSingle), lastDart); + break; + case 2: // "Hit double X" + hitText = Common::String::format(FIXED(DartsHitDouble), lastDart); + break; + case 3: // "Hit triple X" + hitText = Common::String::format(FIXED(DartsHitTriple), lastDart); + break; + default: + break; + } + } else { + // Bullseye + switch (numHits) { + case 1: + hitText = Common::String(FIXED(DartsHitSingleBullseye)); + break; + case 2: + hitText = Common::String(FIXED(DartsHitDoubleBullseye)); + break; + case 3: + hitText = Common::String(FIXED(DartsHitTripleBullseye)); + break; + default: + break; + } + } + screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, "%s", hitText.c_str()); } if (score != 0 && playerNum == 0 && !gameOver) screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 3), 0, - "%s", FIXED(PressAKey)); + "%s", FIXED(DartsPressKey)); if (gameOver) { screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 3), - 0, "%s", FIXED(GameOver)); + 0, "%s", FIXED(DartsGameOver)); if (playerNum == 0) { screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 4), 0, - "%s %s", FIXED(Holmes), FIXED(Wins)); + FIXED(DartsWins), FIXED(DartsPlayerHolmes)); _vm->setFlagsDirect(531); } else { screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 4), 0, - "%s %s!", _opponent.c_str(), FIXED(Wins)); + FIXED(DartsWins), _opponent.c_str()); _vm->setFlagsDirect(530); } screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 5), 0, - "%s", FIXED(PressAKey)); + "%s", FIXED(DartsPressKey)); done = true; idx = 10; } else if (_gameType == GAME_301 && score < 0) { screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 2), 0, - "%s!", FIXED(Busted)); + "%s!", FIXED(DartsBusted)); // End turn idx = 10; @@ -224,13 +259,19 @@ void Darts::playDarts(GameType gameType) { done = true; break; } + // Wait for keypress + do { + events.pollEventsAndWait(); + events.setButtonState(); + } while (!_vm->shouldQuit() && !events.kbHit() && !events._pressed); } else { - events.wait(20); + events.wait(40); } - screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_dartInfo.left, _dartInfo.top - 1), + // Clears the status part of the board + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(_dartInfo.left, _dartInfo.top - 1), Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1)); - screen.blitFrom(screen._backBuffer1); + screen.SHblitFrom(screen._backBuffer1); } playerNum ^= 1; @@ -238,9 +279,9 @@ void Darts::playDarts(GameType gameType) { ++_roundNum; if (!done) { - screen._backBuffer2.blitFrom((*_dartBoard)[0], Common::Point(0, 0)); - screen._backBuffer1.blitFrom(screen._backBuffer2); - screen.blitFrom(screen._backBuffer2); + screen._backBuffer2.SHblitFrom((*_dartBoard)[0], Common::Point(0, 0)); + screen._backBuffer1.SHblitFrom(screen._backBuffer2); + screen.SHblitFrom(screen._backBuffer2); } } @@ -303,7 +344,7 @@ void Darts::initDarts() { } } - _opponent = FIXED(Jock); + _opponent = FIXED(DartsPlayerJock); } void Darts::loadDarts() { @@ -327,9 +368,9 @@ void Darts::loadDarts() { delete stream; // Load the initial background - screen._backBuffer1.blitFrom((*_dartBoard)[0], Common::Point(0, 0)); - screen._backBuffer2.blitFrom(screen._backBuffer1); - screen.blitFrom(screen._backBuffer1); + screen._backBuffer1.SHblitFrom((*_dartBoard)[0], Common::Point(0, 0)); + screen._backBuffer2.SHblitFrom(screen._backBuffer1); + screen.SHblitFrom(screen._backBuffer1); } void Darts::closeDarts() { @@ -346,7 +387,7 @@ void Darts::showNames(int playerNum) { byte color; color = playerNum == 0 ? PLAYER_COLOR : DART_COLOR_FORE; - screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y), 0, "%s", FIXED(Holmes)); + screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y), 0, "%s", FIXED(DartsPlayerHolmes)); screen._backBuffer1.fillRect(Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + _spacing + 1, STATUS_INFO_X + 50, STATUS_INFO_Y + _spacing + 3), color); screen.fillRect(Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + _spacing + 1, @@ -359,14 +400,14 @@ void Darts::showNames(int playerNum) { screen.fillRect(Common::Rect(STATUS2_INFO_X, STATUS_INFO_Y + _spacing + 1, STATUS2_INFO_X + 50, STATUS_INFO_Y + _spacing + 3), color); - screen._backBuffer2.blitFrom(screen._backBuffer1); + screen._backBuffer2.SHblitFrom(screen._backBuffer1); } void Darts::showStatus(int playerNum) { Screen &screen = *_vm->_screen; - const char *const CRICKET_SCORE_NAME[7] = { "20", "19", "18", "17", "16", "15", FIXED(Bull) }; + const char *const CRICKET_SCORE_NAME[7] = { "20", "19", "18", "17", "16", "15", FIXED(DartsBull) }; - screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10), + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10), Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + 10, STATUS_INFO_X + STATUS_INFO_WIDTH, STATUS_INFO_Y + STATUS_INFO_HEIGHT - 10)); screen.print(Common::Point(STATUS_INFO_X + 30, STATUS_INFO_Y + _spacing + 4), 0, "%d", _score1); @@ -374,10 +415,15 @@ void Darts::showStatus(int playerNum) { screen.print(Common::Point(STATUS2_INFO_X + 30, STATUS_INFO_Y + _spacing + 4), 0, "%d", _score2); int temp = (_gameType == GAME_CRICKET) ? STATUS_INFO_Y + 10 * _spacing + 5 : STATUS_INFO_Y + 55; - screen.print(Common::Point(STATUS_INFO_X, temp), 0, "%s: %d", FIXED(Round), _roundNum); + + // "Round: x" + Common::String dartsRoundStatus = Common::String::format(FIXED(DartsCurrentRound), _roundNum); + screen.print(Common::Point(STATUS_INFO_X, temp), 0, "%s", dartsRoundStatus.c_str()); if (_gameType == GAME_301) { - screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 75), 0, "%s: %d", FIXED(TurnTotal), _roundScore); + // "Turn Total: x" + Common::String dartsTotalPoints = Common::String::format(FIXED(DartsCurrentTotalPoints), _roundScore); + screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 75), 0, "%s", dartsTotalPoints.c_str()); } else { // Show cricket scores for (int x = 0; x < 7; ++x) { @@ -402,7 +448,7 @@ void Darts::showStatus(int playerNum) { } } - screen.blitFrom(screen._backBuffer1, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10), + screen.SHblitFrom(screen._backBuffer1, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10), Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + 10, STATUS_INFO_X + STATUS_INFO_WIDTH, STATUS_INFO_Y + STATUS_INFO_HEIGHT - 10)); } @@ -412,7 +458,7 @@ void Darts::erasePowerBars() { // Erase the old power bars and replace them with empty ones screen._backBuffer1.fillRect(Common::Rect(DART_BAR_VX, DART_HEIGHT_Y, DART_BAR_VX + 9, DART_HEIGHT_Y + DART_BAR_SIZE), 0); - screen._backBuffer1.transBlitFrom((*_dartGraphics)[0], Common::Point(DART_BAR_VX - 1, DART_HEIGHT_Y - 1)); + screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[0], Common::Point(DART_BAR_VX - 1, DART_HEIGHT_Y - 1)); screen.slamArea(DART_BAR_VX - 1, DART_HEIGHT_Y - 1, 10, DART_BAR_SIZE + 2); } @@ -452,7 +498,7 @@ int Darts::doPowerBar(const Common::Point &pt, byte color, int goToPower, int or } screen._backBuffer1.hLine(pt.x, pt.y + DART_BAR_SIZE- 1 - idx, pt.x + 8, color); - screen._backBuffer1.transBlitFrom((*_dartGraphics)[0], Common::Point(pt.x - 1, pt.y - 1)); + screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[0], Common::Point(pt.x - 1, pt.y - 1)); screen.slamArea(pt.x, pt.y + DART_BAR_SIZE - 1 - idx, 8, 2); if (!(idx % 8)) @@ -499,7 +545,7 @@ int Darts::drawHand(int goToPower, int computer) { break; } - screen._backBuffer1.transBlitFrom((*hands)[0], pt); + screen._backBuffer1.SHtransBlitFrom((*hands)[0], pt); screen.slamArea(pt.x - 1, pt.y, _handSize.x + 1, _handSize.y); screen.restoreBackground(Common::Rect(pt.x, pt.y, pt.x + _handSize.x, pt.y + _handSize.y)); @@ -586,7 +632,7 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) { _handSize.y = hands[idx]._offset.y + hands[idx]._height; int handCy = SHERLOCK_SCREEN_HEIGHT - _handSize.y; - screen._backBuffer1.transBlitFrom(hands[idx], Common::Point(_handX, handCy)); + screen._backBuffer1.SHtransBlitFrom(hands[idx], Common::Point(_handX, handCy)); screen.slamArea(_handX, handCy, _handSize.x + 1, _handSize.y); screen.slamArea(handOCx, handOCy, handOldxSize, handOldySize); screen.restoreBackground(Common::Rect(_handX, handCy, _handX + _handSize.x, handCy + _handSize.y)); @@ -608,7 +654,7 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) { ocy = drawPos.y = cy - (*_dartGraphics)[dartNum]._height; // Draw dart - screen._backBuffer1.transBlitFrom((*_dartGraphics)[dartNum], drawPos); + screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[dartNum], drawPos); if (drawPos.x < 0) { xSize += drawPos.x; @@ -630,7 +676,7 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) { // Flush the erased dart area screen.slamArea(oldDrawPos.x, oldDrawPos.y, oldxSize, oldySize); - screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(drawPos.x, drawPos.y), + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(drawPos.x, drawPos.y), Common::Rect(drawPos.x, drawPos.y, drawPos.x + xSize, drawPos.y + ySize)); oldDrawPos.x = drawPos.x; @@ -651,7 +697,7 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) { if (oldDrawPos.x != -1) screen.slamArea(oldDrawPos.x, oldDrawPos.y, oldxSize, oldySize); - screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(drawPos.x, drawPos.y), + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(drawPos.x, drawPos.y), Common::Rect(drawPos.x, drawPos.y, drawPos.x + xSize, drawPos.y + ySize)); cx = dartPos.x; @@ -677,7 +723,7 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) { ocx = drawPos.x = cx - (*_dartGraphics)[dartNum]._width / 2; ocy = drawPos.y = cy - (*_dartGraphics)[dartNum]._height; - screen._backBuffer1.transBlitFrom((*_dartGraphics)[dartNum], Common::Point(drawPos.x, drawPos.y)); + screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[dartNum], Common::Point(drawPos.x, drawPos.y)); if (drawPos.x < 0) { xSize += drawPos.x; @@ -699,7 +745,7 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) { screen.slamArea(oldDrawPos.x, oldDrawPos.y, oldxSize, oldySize); if (idx != 23) - screen._backBuffer1.blitFrom(screen._backBuffer2, drawPos, + screen._backBuffer1.SHblitFrom(screen._backBuffer2, drawPos, Common::Rect(drawPos.x, drawPos.y, drawPos.x + xSize, drawPos.y + ySize)); // erase dart events.wait(1); @@ -716,8 +762,8 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) { ySize = (*_dartGraphics)[dartNum]._height; // Draw final dart on the board - screen._backBuffer1.transBlitFrom((*_dartGraphics)[dartNum], Common::Point(ocx, ocy)); - screen._backBuffer2.transBlitFrom((*_dartGraphics)[dartNum], Common::Point(ocx, ocy)); + screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[dartNum], Common::Point(ocx, ocy)); + screen._backBuffer2.SHtransBlitFrom((*_dartGraphics)[dartNum], Common::Point(ocx, ocy)); screen.slamArea(ocx, ocy, xSize, ySize); } @@ -887,13 +933,16 @@ int Darts::throwDart(int dartNum, int computer) { events.clearEvents(); erasePowerBars(); - screen.print(Common::Point(_dartInfo.left, _dartInfo.top), 0, "%s # %d", FIXED(Dart), dartNum); + + // "Dart # x" + Common::String currentDart = Common::String::format(FIXED(DartsCurrentDart), dartNum); + screen.print(Common::Point(_dartInfo.left, _dartInfo.top), 0, "%s", currentDart.c_str()); drawDartsLeft(dartNum, computer); if (!computer) { - screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, "%s", FIXED(HitAKey)); - screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 2), 0, "%s", FIXED(ToStart)); + screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, "%s", FIXED(DartsStartPressKey1)); + screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 2), 0, "%s", FIXED(DartsStartPressKey2)); } if (!computer) { @@ -907,9 +956,9 @@ int Darts::throwDart(int dartNum, int computer) { } drawDartsLeft(dartNum + 1, computer); - screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_dartInfo.left, _dartInfo.top - 1), + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(_dartInfo.left, _dartInfo.top - 1), Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1)); - screen.blitFrom(screen._backBuffer1, Common::Point(_dartInfo.left, _dartInfo.top - 1), + screen.SHblitFrom(screen._backBuffer1, Common::Point(_dartInfo.left, _dartInfo.top - 1), Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1)); if (computer) { @@ -931,7 +980,7 @@ int Darts::throwDart(int dartNum, int computer) { height = 101 - height; // Copy power bars to the secondary back buffer - screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(DART_BAR_VX - 1, DART_HEIGHT_Y - 1), + screen._backBuffer2.SHblitFrom(screen._backBuffer1, Common::Point(DART_BAR_VX - 1, DART_HEIGHT_Y - 1), Common::Rect(DART_BAR_VX - 1, DART_HEIGHT_Y - 1, DART_BAR_VX - 1 + 10, DART_HEIGHT_Y - 1 + DART_BAR_SIZE + 2)); @@ -975,14 +1024,14 @@ void Darts::drawDartsLeft(int dartNum, int computer) { const int DART_X2[3] = { 393, 441, 502 }; const int DART_Y2[3] = { 373, 373, 373 }; - screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(DART_X1[0], DART_Y1[0]), + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(DART_X1[0], DART_Y1[0]), Common::Rect(DART_X1[0], DART_Y1[0], SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); for (int idx = 2; idx >= dartNum - 1; --idx) { if (computer) - screen._backBuffer1.transBlitFrom((*_dartsLeft)[idx + 3], Common::Point(DART_X2[idx], DART_Y2[idx])); + screen._backBuffer1.SHtransBlitFrom((*_dartsLeft)[idx + 3], Common::Point(DART_X2[idx], DART_Y2[idx])); else - screen._backBuffer1.transBlitFrom((*_dartsLeft)[idx], Common::Point(DART_X1[idx], DART_Y1[idx])); + screen._backBuffer1.SHtransBlitFrom((*_dartsLeft)[idx], Common::Point(DART_X1[idx], DART_Y1[idx])); } screen.slamArea(DART_X1[0], DART_Y1[0], SHERLOCK_SCREEN_WIDTH - DART_X1[0], SHERLOCK_SCREEN_HEIGHT - DART_Y1[0]); diff --git a/engines/sherlock/tattoo/tattoo_fixed_text.cpp b/engines/sherlock/tattoo/tattoo_fixed_text.cpp index 38acd78aba..e41cb1f5eb 100644 --- a/engines/sherlock/tattoo/tattoo_fixed_text.cpp +++ b/engines/sherlock/tattoo/tattoo_fixed_text.cpp @@ -66,25 +66,27 @@ static const char *const fixedTextEN[] = { "Search Backwards", "Search Forwards", "Text Not Found !", - + // Darts "Holmes", "Jock", "Bull", - "Round", - "Turn Total", - "Dart", - "to start", + "Round: %d", + "Turn Total: %d", + "Dart # %d", "Hit a key", + "To start", "Press a key", - "bullseye", // ?? - "GAME OVER", - "BUSTED", - "Wins", - "Scored", - "points", - "Hit %s %d", - "Double", - "Triple", + "GAME OVER!", + "BUSTED!", + "%s Wins", + "Scored %d point", // original: treated 1 point and multiple points the same ("Scored 1 points") + "Scored %d points", + "Hit a %d", + "Hit double %d", + "Hit triple %d", + "Hit a bullseye", + "Hit double bullseye", + "Hit triple bullseye", "Apply", "Water", @@ -106,6 +108,8 @@ static const char *const fixedTextEN[] = { "No", "Enter Password", "Going East", // correct password, was not and should not to be translated + "Watson's Journal", + "Journal saved as journal.txt", // SH2: People names "Sherlock Holmes", "Dr. Watson", @@ -235,7 +239,7 @@ static const char *const fixedTextDE[] = { "Tagebuch", "Tasche", "Optionen", - "L\224osen", + "L\224sen", "mit", "Keine Wirkung...", "Diese Person wei\341 im Augenblick nichts zu berichten.", @@ -243,31 +247,33 @@ static const char *const fixedTextDE[] = { "Seite %d", "Schlie\341en", - "Lessen", // <-- - "In Datei sichern", + "Durchsuchen", // original: "Lessen" + "In Datei sichern", // original: "Speichern" "Suche abbrechen", "R\201ckw\204rts suchen ", - "Vorwarts suchen ", + "Vorw\204rts suchen ", "Text nicht gefunden", - + // Darts "Holmes", "Jock", "Bull", "Runde: %d", "Gesamt: %d", "Pfeil # %d", - "zum Starten", "Taste dr\201cken", + "zum Starten", "Taste dr\201cken", - "Bullseye", // ?? "SPIEL BEENDET!", "VERLOREN!", - "Gewinnt!", // "Holmes Gewinnt!", "%s Gewinnt!" + "%s gewinnt!", // "Holmes Gewinnt!", "%s Gewinnt!", original: "%s Gewinnt!" + "Erzielte %d Punkt", // original: treated 1 point and multiple points the same ("Scored 1 points") "Erzielte %d Punkte", - "Punkte", // ?? - "Treffer %s %d", - "Doppel", - "Dreifach", + "%d getroffen", // original: "Treffer %s %d" + "Doppel %d getroffen", // original: see above + "Dreifach %d getroffen", // original: see above + "Bullseye getroffen", + "Doppel Bullseye getroffen", + "Dreifach Bullseye getroffen", "Benutze", "Wasser", @@ -289,6 +295,8 @@ static const char *const fixedTextDE[] = { "Nein", "Pa\341wort eingeben", "Going East", // correct password, was not and should not to be translated + "Watsons Tagebuch", + "Journal gespeichert als journal.txt", // SH2: People names "Sherlock Holmes", // note: People names were not translated in the German interpreter "Dr. Watson", @@ -426,31 +434,33 @@ static const char *const fixedTextFR[] = { "Page %d", "Fermer", - "Lessen", // <-- + "Rechercher", "Sauvegarder", "Annuler ", "Chercher avant", "Chercher apr\212s", "Texte introuvable !", - + // Darts "Holmes", "Jock", "Bull", "Tour: %d", "Total: %d", "Fl\202chette # %d", - "pour commencer", "Appuyez sur C", + "pour commencer", "Appuyez sur C", - "Bullseye", // ?? "FIN DE LA PARTIE!", // original: "Fin de la partie!" "FIASCO!", - "Gagnant!", // "Holmes Gagnant!", "%s Gagnant!" - "Total des points: %d", - "Punkte", // ?? - "Treffer %s %d", - "double", - "triple", + "%s a gagn\202!", // "Holmes Gagnant!", "%s Gagnant!" + "Rapporte %d point", // original: treated 1 point and multiple points the same ("Scored 1 points") + "Rapporte %d points", // original: Total des points: %d", + "Touche un %d", // original: ??? + "Touche double %d", + "Touche triple %d", + "Touche le Bullseye", + "Touche double Bullseye", + "Touche triple Bullseye", "Mouillez", "Puis", @@ -472,6 +482,8 @@ static const char *const fixedTextFR[] = { "Non", "Entrez le mot de passe", "Going East", // correct password, was not and should not to be translated + "Journal de Watson", + "Journal enregistree comme journal.txt", // SH2: People names "Sherlock Holmes", "Dr. Watson", @@ -610,7 +622,7 @@ static const char *const fixedTextES[] = { "P\240gina %d", "Cerrar Diario", - "Lessen", // <-- not included?!?! + "Buscar en Diario", "Salvar en Archivo", "Detener B\243squeda", "Buscar Hacia Atr\240s", @@ -623,18 +635,20 @@ static const char *const fixedTextES[] = { "Vuelta: %d", "Total del Turno: %d", "Dardo # %d", - "para empezar", "Pulsa una tecla", + "para empezar", "Pulsa una tecla", - "Golpe %s ojo de buey", // ?? "FIN DE LA PARTIDA!", "ROTO!", - "Gana!", // "Holmes Gana!", "%s Gana!" + "%s gana!", // "Holmes Gana!", "%s Gana!", original: "%s Gana!" + "Puntuado %d punto", // original: treated 1 point and multiple points the same ("Scored 1 points") "Puntuado %d puntos", - "puntos", // ?? - "Golpe %s %d", - "doble", - "triple", + "Golpe un %d", + "Gople doble %d", + "Gople triple %d", + "Golpe un ojo de buey", + "Gople doble ojo de buey", + "Gople triple ojo de buey", "aplicar", "Agua", @@ -656,6 +670,8 @@ static const char *const fixedTextES[] = { "Non", "Introducir Palabra Clave", "Vas al Este", // correct password, was translated in Spanish version (???) + "Diario de Watson", + "Diario guarda como journal.txt", // SH2: People names "Sherlock Holmes", "Dr. Watson", @@ -755,7 +771,6 @@ static const char *const fixedTextES[] = { "Cochero" }; -// TODO: There also was a Spanish version of Sherlock Holmes 2 static const FixedTextLanguageEntry fixedTextLanguages[] = { { Common::DE_DEU, fixedTextDE }, { Common::ES_ESP, fixedTextES }, diff --git a/engines/sherlock/tattoo/tattoo_fixed_text.h b/engines/sherlock/tattoo/tattoo_fixed_text.h index 48d237db3c..7dbe13bbb3 100644 --- a/engines/sherlock/tattoo/tattoo_fixed_text.h +++ b/engines/sherlock/tattoo/tattoo_fixed_text.h @@ -68,24 +68,26 @@ enum FixedTextId { kFixedText_SearchForwards, kFixedText_TextNotFound, - kFixedText_Holmes, - kFixedText_Jock, - kFixedText_Bull, - kFixedText_Round, - kFixedText_TurnTotal, - kFixedText_Dart, - kFixedText_ToStart, - kFixedText_HitAKey, - kFixedText_PressAKey, - kFixedText_Bullseye, - kFixedText_GameOver, - kFixedText_Busted, - kFixedText_Wins, - kFixedText_Scored, - kFixedText_Points, - kFixedText_Hit, - kFixedText_Double, - kFixedText_Triple, + kFixedText_DartsPlayerHolmes, + kFixedText_DartsPlayerJock, + kFixedText_DartsBull, + kFixedText_DartsCurrentRound, + kFixedText_DartsCurrentTotalPoints, + kFixedText_DartsCurrentDart, + kFixedText_DartsStartPressKey1, + kFixedText_DartsStartPressKey2, + kFixedText_DartsPressKey, + kFixedText_DartsGameOver, + kFixedText_DartsBusted, + kFixedText_DartsWins, + kFixedText_DartsScoredPoint, + kFixedText_DartsScoredPoints, + kFixedText_DartsHitSingle, + kFixedText_DartsHitDouble, + kFixedText_DartsHitTriple, + kFixedText_DartsHitSingleBullseye, + kFixedText_DartsHitDoubleBullseye, + kFixedText_DartsHitTripleBullseye, kFixedText_Apply, kFixedText_Water, @@ -107,6 +109,8 @@ enum FixedTextId { kFixedText_No, kFixedText_EnterPassword, kFixedText_CorrectPassword, + kFixedText_WatsonsJournal, + kFixedText_JournalSaved, // SH2: People names kFixedText_People_SherlockHolmes, kFixedText_People_DrWatson, diff --git a/engines/sherlock/tattoo/tattoo_journal.cpp b/engines/sherlock/tattoo/tattoo_journal.cpp index e836cca620..918887f320 100644 --- a/engines/sherlock/tattoo/tattoo_journal.cpp +++ b/engines/sherlock/tattoo/tattoo_journal.cpp @@ -20,6 +20,7 @@ * */ +#include "common/savefile.h" #include "sherlock/tattoo/tattoo_journal.h" #include "sherlock/tattoo/tattoo_fixed_text.h" #include "sherlock/tattoo/tattoo_scene.h" @@ -64,7 +65,7 @@ void TattooJournal::show() { delete stream; // Set screen to black, and set background - screen._backBuffer1.blitFrom((*_journalImages)[0], Common::Point(0, 0)); + screen._backBuffer1.SHblitFrom((*_journalImages)[0], Common::Point(0, 0)); screen.empty(); screen.setPalette(palette); @@ -130,7 +131,7 @@ void TattooJournal::handleKeyboardEvents() { events.warpMouse(Common::Point(r.left + r.width() / 3 - 10, r.top + screen.fontHeight() + 2)); } else { if (_selector == JH_CLOSE) - _selector = JH_PRINT; + _selector = JH_SAVE; else --_selector; @@ -232,7 +233,7 @@ void TattooJournal::handleKeyboardEvents() { if (_selector == JH_NONE) { events.warpMouse(Common::Point(r.left + r.width() / 3 - 10, r.top + screen.fontHeight() + 2)); } else { - if (_selector == JH_PRINT) + if (_selector == JH_SAVE) _selector = JH_NONE; else ++_selector; @@ -378,8 +379,13 @@ void TattooJournal::handleButtons() { break; } - case JH_PRINT: - // Print Journal - not implemented in ScummVM + case JH_SAVE: + // Save journal to file + disableControls(); + saveJournal(); + drawFrame(); + drawJournal(0, 0); + screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); break; default: @@ -455,7 +461,7 @@ void TattooJournal::loadLocations() { void TattooJournal::drawFrame() { Screen &screen = *_vm->_screen; - screen._backBuffer1.blitFrom((*_journalImages)[0], Common::Point(0, 0)); + screen._backBuffer1.SHblitFrom((*_journalImages)[0], Common::Point(0, 0)); drawControls(0); } @@ -480,10 +486,10 @@ void TattooJournal::drawControls(int mode) { screen._backBuffer1.fillRect(inner, MENU_BACKGROUND); // Draw the four corners of the info box - screen._backBuffer1.transBlitFrom(images[0], Common::Point(r.left, r.top)); - screen._backBuffer1.transBlitFrom(images[1], Common::Point(r.right - images[1]._width, r.top)); - screen._backBuffer1.transBlitFrom(images[1], Common::Point(r.left, r.bottom - images[1]._height)); - screen._backBuffer1.transBlitFrom(images[1], Common::Point(r.right - images[1]._width, r.bottom - images[1]._height)); + screen._backBuffer1.SHtransBlitFrom(images[0], Common::Point(r.left, r.top)); + screen._backBuffer1.SHtransBlitFrom(images[1], Common::Point(r.right - images[1]._width, r.top)); + screen._backBuffer1.SHtransBlitFrom(images[1], Common::Point(r.left, r.bottom - images[1]._height)); + screen._backBuffer1.SHtransBlitFrom(images[1], Common::Point(r.right - images[1]._width, r.bottom - images[1]._height)); // Draw the top of the info box screen._backBuffer1.hLine(r.left + images[0]._width, r.top, r.right - images[0]._height, INFO_TOP); @@ -507,8 +513,8 @@ void TattooJournal::drawControls(int mode) { // Draw the sides of the separator bar above the scroll bar int yp = r.top + screen.fontHeight() + 7; - screen._backBuffer1.transBlitFrom(images[4], Common::Point(r.left, yp - 1)); - screen._backBuffer1.transBlitFrom(images[5], Common::Point(r.right - images[5]._width, yp - 1)); + screen._backBuffer1.SHtransBlitFrom(images[4], Common::Point(r.left, yp - 1)); + screen._backBuffer1.SHtransBlitFrom(images[5], Common::Point(r.right - images[5]._width, yp - 1)); // Draw the bar above the scroll bar screen._backBuffer1.hLine(r.left + images[4]._width, yp, r.right - images[5]._width, INFO_TOP); @@ -519,8 +525,8 @@ void TattooJournal::drawControls(int mode) { // Draw the Bars separating the Journal Commands int xp = r.right / 3; for (int idx = 0; idx < 2; ++idx) { - screen._backBuffer1.transBlitFrom(images[6], Common::Point(xp - 2, r.top + 1)); - screen._backBuffer1.transBlitFrom(images[7], Common::Point(xp - 2, yp - 1)); + screen._backBuffer1.SHtransBlitFrom(images[6], Common::Point(xp - 2, r.top + 1)); + screen._backBuffer1.SHtransBlitFrom(images[7], Common::Point(xp - 2, yp - 1)); screen._backBuffer1.hLine(xp - 1, r.top + 4, yp - 2, INFO_TOP); screen._backBuffer1.hLine(xp, r.top + 4, yp - 2, INFO_MIDDLE); @@ -592,7 +598,7 @@ void TattooJournal::highlightJournalControls(bool slamIt) { } // See if the Search was selected, but is not available - if (_journal.empty() && (_selector == JH_SEARCH || _selector == JH_PRINT)) + if (_journal.empty() && (_selector == JH_SEARCH || _selector == JH_SAVE)) _selector = JH_NONE; if (_selector == JH_PAGE_LEFT && _oldSelector == JH_PAGE_RIGHT) @@ -618,7 +624,10 @@ void TattooJournal::highlightJournalControls(bool slamIt) { color, "%s", FIXED(SearchJournal)); xp += r.width() / 3; - color = INFO_BOTTOM; + if (!_journal.empty()) + color = (_selector == JH_SAVE) ? COMMAND_HIGHLIGHTED : INFO_TOP; + else + color = INFO_BOTTOM; screen.gPrint(Common::Point(xp - screen.stringWidth(FIXED(SaveJournal)) / 2, r.top + 5), color, "%s", FIXED(SaveJournal)); @@ -737,7 +746,7 @@ void TattooJournal::disableControls() { // Print the Journal commands int xp = r.left + r.width() / 6; - for (int idx = 0; idx < 2; ++idx) { + for (int idx = 0; idx < 3; ++idx) { screen.gPrint(Common::Point(xp - screen.stringWidth(JOURNAL_COMMANDS[idx]) / 2, r.top + 5), INFO_BOTTOM, "%s", JOURNAL_COMMANDS[idx]); @@ -770,7 +779,7 @@ int TattooJournal::getFindName(bool printError) { // Backup the area under the text entry Surface bgSurface(r.width() - 6, screen.fontHeight()); - bgSurface.blitFrom(screen._backBuffer1, Common::Point(0, 0), Common::Rect(r.left + 3, cursorY, + bgSurface.SHblitFrom(screen._backBuffer1, Common::Point(0, 0), Common::Rect(r.left + 3, cursorY, r.right - 3, cursorY + screen.fontHeight())); if (printError) { @@ -801,7 +810,7 @@ int TattooJournal::getFindName(bool printError) { events.clearEvents(); // Restore the text background - screen._backBuffer1.blitFrom(bgSurface, Common::Point(r.left, cursorY)); + screen._backBuffer1.SHblitFrom(bgSurface, Common::Point(r.left, cursorY)); // If there was a name already entered, copy it to name and display it if (!_find.empty()) { @@ -837,7 +846,7 @@ int TattooJournal::getFindName(bool printError) { } else { // Erase cursor by restoring background and writing current text - screen._backBuffer1.blitFrom(bgSurface, Common::Point(r.left + 3, cursorY)); + screen._backBuffer1.SHblitFrom(bgSurface, Common::Point(r.left + 3, cursorY)); screen.gPrint(Common::Point(r.left + screen.widestChar() + 3, cursorY), COMMAND_HIGHLIGHTED, "%s", name.c_str()); screen.slamArea(r.left + 3, cursorY, r.width() - 3, screen.fontHeight()); } @@ -880,11 +889,11 @@ int TattooJournal::getFindName(bool printError) { } else { if (keyState.keycode & Common::KBD_SHIFT) { if (_selector == JH_CLOSE) - _selector = JH_PRINT; + _selector = JH_SAVE; else --_selector; } else { - if (_selector == JH_PRINT) + if (_selector == JH_SAVE) _selector = JH_CLOSE; else ++_selector; @@ -903,7 +912,7 @@ int TattooJournal::getFindName(bool printError) { } // Redraw the text - screen._backBuffer1.blitFrom(bgSurface, Common::Point(r.left + 3, cursorY)); + screen._backBuffer1.SHblitFrom(bgSurface, Common::Point(r.left + 3, cursorY)); screen.gPrint(Common::Point(r.left + screen.widestChar() + 3, cursorY), COMMAND_HIGHLIGHTED, "%s", name.c_str()); screen.slamArea(r.left + 3, cursorY, r.right - 3, screen.fontHeight()); @@ -949,6 +958,173 @@ void TattooJournal::record(int converseNum, int statementNum, bool replyOnly) { Journal::record(converseNum, statementNum, replyOnly); } +void TattooJournal::saveJournal() { + Talk &talk = *_vm->_talk; + Common::OutSaveFile *file = g_system->getSavefileManager()->openForSaving("journal.txt", false); + int tempIndex = _index; + + _index = 0; + talk._converseNum = -1; + + file->writeString(" "); + file->writeString(FIXED(WatsonsJournal)); + file->writeString("\n\n"); + + // Loop through saving each page of the journal + do { + // Print a single talk file + Common::String text; + int line = 0; + + // Copy all of the talk files entries into one big string + do { + if (_lines[line].hasPrefix("@")) { + text += Common::String(_lines[line].c_str() + 1); + if ((line + 1) < (int)_lines.size() && _lines[line + 1].hasPrefix("@")) + text += "\n"; + else + text += " "; + } else { + text += _lines[line]; + text += " "; + + // Check for embedded location names embedded in comment fields, + // which show up as a blank line with the next line starting + // with a '@'. We have to add a line break here because the '@' handler + // previously assumes that they're always following a blank line + + if ((_lines[line].empty() || _lines[line] == " ") + && (line + 1) < (int)_lines.size() && _lines[line + 1].hasPrefix("@")) + text += "\n"; + } + + ++line; + } while (line < (int)_lines.size()); + + // Now write out the text in 80 column lines + do { + if (text.size() > 80) { + const char *msgP = text.c_str() + 80; + + if (Common::String(text.c_str(), msgP).contains("\n")) { + // The 80 characters contain a carriage return, + // so we can print out that line + const char *cr = strchr(text.c_str(), '\n'); + file->writeString(Common::String(text.c_str(), cr)); + text = Common::String(cr + 1); + } else { + // Move backwards to find a word break + while (*msgP != ' ') + --msgP; + + // Write out the figured out line + file->writeString(Common::String(text.c_str(), msgP)); + + // Remove the line that was written out + while (*msgP == ' ') + ++msgP; + text = Common::String(msgP); + } + } else { + // The remainder of the string is under 80 characters. + // Check to see if has any line ends + if (text.contains("\n")) { + // Write out the line up to the carraige return + const char *cr = strchr(text.c_str(), '\n'); + file->writeString(Common::String(text.c_str(), cr)); + text = Common::String(cr + 1); + } else { + // Write out the final line + file->writeString(text); + text = ""; + } + } + + file->writeString("\n"); + } while (!text.empty()); + + // Move to next talk file + do { + ++_index; + + if (_index < (int)_journal.size()) + loadJournalFile(false); + } while (_index < (int)_journal.size() && _lines.empty()); + + // Don't immediately exit if there are no loaded lines for + // the next page, since it's probably a stealth file and + // can simply be skipped + file->writeString("\n"); + } while (_index < (int)_journal.size()); + + file->finalize(); + delete file; + + // Free up any talk file in memory + talk.freeTalkVars(); + + // Show the message for the journal having been saved + showSavedDialog(); + + // Reset the previous settings of the journal + _index = tempIndex; +} + +void TattooJournal::showSavedDialog() { + TattooEngine &vm = *(TattooEngine *)_vm; + Events &events = *vm._events; + Screen &screen = *vm._screen; + TattooUserInterface &ui = *(TattooUserInterface *)vm._ui; + ImageFile &images = *ui._interfaceImages; + disableControls(); + + Common::String msg = FIXED(JournalSaved); + Common::Rect inner(0, 0, screen.stringWidth(msg), screen.fontHeight()); + inner.moveTo((SHERLOCK_SCREEN_WIDTH - inner.width()) / 2, + (SHERLOCK_SCREEN_HEIGHT / 2) - (screen.fontHeight() / 2)); + + Common::Rect r = inner; + r.grow(10); + + if (vm._transparentMenus) + ui.makeBGArea(r); + else + screen._backBuffer1.fillRect(r, MENU_BACKGROUND); + + // Draw the four corners of the info box + screen._backBuffer1.transBlitFrom(images[0], Common::Point(r.left, r.top)); + screen._backBuffer1.transBlitFrom(images[1], Common::Point(r.right - images[1]._width, r.top)); + screen._backBuffer1.transBlitFrom(images[1], Common::Point(r.left, r.bottom - images[1]._height)); + screen._backBuffer1.transBlitFrom(images[1], Common::Point(r.right - images[1]._width, r.bottom - images[1]._height)); + + // Draw the top of the info box + screen._backBuffer1.hLine(r.left + images[0]._width, r.top, r.right - images[0]._height, INFO_TOP); + screen._backBuffer1.hLine(r.left + images[0]._width, r.top + 1, r.right - images[0]._height, INFO_MIDDLE); + screen._backBuffer1.hLine(r.left + images[0]._width, r.top + 2, r.right - images[0]._height, INFO_BOTTOM); + + // Draw the bottom of the info box + screen._backBuffer1.hLine(r.left + images[0]._width, r.bottom - 3, r.right - images[0]._height, INFO_TOP); + screen._backBuffer1.hLine(r.left + images[0]._width, r.bottom - 2, r.right - images[0]._height, INFO_MIDDLE); + screen._backBuffer1.hLine(r.left + images[0]._width, r.bottom - 1, r.right - images[0]._height, INFO_BOTTOM); + + // Draw the left side of the info box + screen._backBuffer1.vLine(r.left, r.top + images[0]._height, r.bottom - images[2]._height, INFO_TOP); + screen._backBuffer1.vLine(r.left + 1, r.top + images[0]._height, r.bottom - images[2]._height, INFO_MIDDLE); + screen._backBuffer1.vLine(r.left + 2, r.top + images[0]._height, r.bottom - images[2]._height, INFO_BOTTOM); + + // Draw the right side of the info box + screen._backBuffer1.vLine(r.right - 3, r.top + images[0]._height, r.bottom - images[2]._height, INFO_TOP); + screen._backBuffer1.vLine(r.right - 2, r.top + images[0]._height, r.bottom - images[2]._height, INFO_MIDDLE); + screen._backBuffer1.vLine(r.right - 1, r.top + images[0]._height, r.bottom - images[2]._height, INFO_BOTTOM); + + // Draw the text + screen._backBuffer1.writeString(msg, Common::Point(inner.left, inner.top), INFO_TOP); + screen.slamRect(r); + + // Five second pause + events.delay(5000, true); +} + } // End of namespace Tattoo } // End of namespace Sherlock diff --git a/engines/sherlock/tattoo/tattoo_journal.h b/engines/sherlock/tattoo/tattoo_journal.h index 96c1c6cab4..9f0fa1fc9b 100644 --- a/engines/sherlock/tattoo/tattoo_journal.h +++ b/engines/sherlock/tattoo/tattoo_journal.h @@ -31,7 +31,7 @@ namespace Sherlock { namespace Tattoo { enum JournalHighlight { - JH_NONE = -1, JH_CLOSE = 0, JH_SEARCH = 1, JH_PRINT = 2, + JH_NONE = -1, JH_CLOSE = 0, JH_SEARCH = 1, JH_SAVE = 2, JH_SCROLL_LEFT = 3, JH_PAGE_LEFT = 4, JH_PAGE_RIGHT = 5, JH_SCROLL_RIGHT = 6, JH_THUMBNAIL = 7 }; @@ -86,6 +86,16 @@ private: * Get in a name to search through the journal for */ int getFindName(bool printError); + + /** + * Save the journal to file + */ + void saveJournal(); + + /** + * Show a message that the journal has been saved to file + */ + void showSavedDialog(); public: TattooJournal(SherlockEngine *vm); virtual ~TattooJournal() {} diff --git a/engines/sherlock/tattoo/tattoo_map.cpp b/engines/sherlock/tattoo/tattoo_map.cpp index 4c7e8c8fef..0839e46260 100644 --- a/engines/sherlock/tattoo/tattoo_map.cpp +++ b/engines/sherlock/tattoo/tattoo_map.cpp @@ -105,7 +105,7 @@ int TattooMap::show() { // Load the map image and draw it to the back buffer ImageFile *map = new ImageFile("map.vgs"); screen._backBuffer1.create(SHERLOCK_SCREEN_WIDTH * 2, SHERLOCK_SCREEN_HEIGHT * 2); - screen._backBuffer1.blitFrom((*map)[0], Common::Point(0, 0)); + screen._backBuffer1.SHblitFrom((*map)[0], Common::Point(0, 0)); delete map; screen.clear(); @@ -114,7 +114,7 @@ int TattooMap::show() { // Copy the map drawn in the back buffer to the secondary back buffer screen._backBuffer2.create(SHERLOCK_SCREEN_WIDTH * 2, SHERLOCK_SCREEN_HEIGHT * 2); - screen._backBuffer2.blitFrom(screen._backBuffer1); + screen._backBuffer2.SHblitFrom(screen._backBuffer1); // Display the built map to the screen screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); @@ -148,12 +148,12 @@ int TattooMap::show() { if (_targetScroll.x < 0) _targetScroll.x = 0; - if ((_targetScroll.x + SHERLOCK_SCREEN_WIDTH) > screen._backBuffer1.w()) - _targetScroll.x = screen._backBuffer1.w() - SHERLOCK_SCREEN_WIDTH; + if ((_targetScroll.x + SHERLOCK_SCREEN_WIDTH) > screen._backBuffer1.width()) + _targetScroll.x = screen._backBuffer1.width() - SHERLOCK_SCREEN_WIDTH; if (_targetScroll.y < 0) _targetScroll.y = 0; - if ((_targetScroll.y + SHERLOCK_SCREEN_HEIGHT) > screen._backBuffer1.h()) - _targetScroll.y = screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT; + if ((_targetScroll.y + SHERLOCK_SCREEN_HEIGHT) > screen._backBuffer1.height()) + _targetScroll.y = screen._backBuffer1.height() - SHERLOCK_SCREEN_HEIGHT; // Check the keyboard if (events.kbHit()) { @@ -166,8 +166,8 @@ int TattooMap::show() { break; case Common::KEYCODE_END: - _targetScroll.x = screen._backBuffer1.w() - SHERLOCK_SCREEN_WIDTH; - _targetScroll.y = screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT; + _targetScroll.x = screen._backBuffer1.width() - SHERLOCK_SCREEN_WIDTH; + _targetScroll.y = screen._backBuffer1.height() - SHERLOCK_SCREEN_HEIGHT; break; case Common::KEYCODE_PAGEUP: @@ -178,8 +178,8 @@ int TattooMap::show() { case Common::KEYCODE_PAGEDOWN: _targetScroll.y += SHERLOCK_SCREEN_HEIGHT; - if (_targetScroll.y > (screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT)) - _targetScroll.y = screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT; + if (_targetScroll.y > (screen._backBuffer1.height() - SHERLOCK_SCREEN_HEIGHT)) + _targetScroll.y = screen._backBuffer1.height() - SHERLOCK_SCREEN_HEIGHT; break; case Common::KEYCODE_SPACE: @@ -304,7 +304,7 @@ void TattooMap::drawMapIcons() { if (_data[idx]._iconNum != -1 && _vm->readFlags(idx + 1)) { MapEntry &mapEntry = _data[idx]; ImageFrame &img = (*_iconImages)[mapEntry._iconNum]; - screen._backBuffer1.transBlitFrom(img._frame, Common::Point(mapEntry.x - img._width / 2, + screen._backBuffer1.SHtransBlitFrom(img._frame, Common::Point(mapEntry.x - img._width / 2, mapEntry.y - img._height / 2)); } } @@ -355,10 +355,10 @@ void TattooMap::restoreArea(const Common::Rect &bounds) { Screen &screen = *_vm->_screen; Common::Rect r = bounds; - r.clip(Common::Rect(0, 0, screen._backBuffer1.w(), screen._backBuffer1.h())); + r.clip(Common::Rect(0, 0, screen._backBuffer1.width(), screen._backBuffer1.height())); if (!r.isEmpty()) - screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(r.left, r.top), r); + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(r.left, r.top), r); } void TattooMap::showCloseUp(int closeUpNum) { @@ -407,7 +407,7 @@ void TattooMap::showCloseUp(int closeUpNum) { screen._currentScroll.y + closeUp.y / 100 - picSize.y / 2); restoreArea(oldBounds); - screen._backBuffer1.transBlitFrom(pic[0], pt, false, 0, scaleVal); + screen._backBuffer1.SHtransBlitFrom(pic[0], pt, false, 0, scaleVal); screen.slamRect(oldBounds); screen.slamArea(pt.x, pt.y, picSize.x, picSize.y); @@ -426,7 +426,7 @@ void TattooMap::showCloseUp(int closeUpNum) { screen._currentScroll.y + SHERLOCK_SCREEN_HEIGHT / 2 - pic[0]._height / 2 + pic[0]._height); restoreArea(oldBounds); - screen._backBuffer1.transBlitFrom(pic[0], Common::Point(r.left, r.top)); + screen._backBuffer1.SHtransBlitFrom(pic[0], Common::Point(r.left, r.top)); screen.slamRect(oldBounds); screen.slamRect(r); diff --git a/engines/sherlock/tattoo/tattoo_people.cpp b/engines/sherlock/tattoo/tattoo_people.cpp index 0af8deff9f..65cc283b66 100644 --- a/engines/sherlock/tattoo/tattoo_people.cpp +++ b/engines/sherlock/tattoo/tattoo_people.cpp @@ -1042,7 +1042,7 @@ void TattooPerson::walkHolmesToNPC() { holmes._walkDest.x = MAX(_position.x / FIXED_INT_MULTIPLIER - imgFrame.sDrawXSize(scaleVal), 0); } else { holmes._walkDest.x = MIN(_position.x / FIXED_INT_MULTIPLIER + imgFrame.sDrawXSize(scaleVal) * 2, - screen._backBuffer1.w() - 1); + screen._backBuffer1.width() - 1); } // See where Holmes is with respect to the NPC (y coords) @@ -1168,7 +1168,7 @@ void TattooPerson::centerScreenOnPerson() { TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui; ui._targetScroll.x = CLIP(_position.x / FIXED_INT_MULTIPLIER - SHERLOCK_SCREEN_WIDTH / 2, - 0, screen._backBuffer1.w() - SHERLOCK_SCREEN_WIDTH); + 0, screen._backBuffer1.width() - SHERLOCK_SCREEN_WIDTH); screen._currentScroll = ui._targetScroll; // Reset the default look position to the center of the screen @@ -1354,6 +1354,7 @@ void TattooPeople::setTalkSequence(int speaker, int sequenceNum) { int TattooPeople::findSpeaker(int speaker) { + speaker &= 0x7f; int result = People::findSpeaker(speaker); const char *portrait = _characters[speaker]._portrait; @@ -1477,7 +1478,7 @@ const Common::Point TattooPeople::restrictToZone(int zoneId, const Common::Point Screen &screen = *_vm->_screen; Common::Rect &r = scene._zones[zoneId]; - if (destPos.x < 0 || destPos.x > screen._backBuffer1.w()) + if (destPos.x < 0 || destPos.x > screen._backBuffer1.width()) return destPos; else if (destPos.y < r.top && r.left < destPos.x && destPos.x < r.right) return Common::Point(destPos.x, r.top); diff --git a/engines/sherlock/tattoo/tattoo_scene.cpp b/engines/sherlock/tattoo/tattoo_scene.cpp index 27f37665dc..00015cb189 100644 --- a/engines/sherlock/tattoo/tattoo_scene.cpp +++ b/engines/sherlock/tattoo/tattoo_scene.cpp @@ -141,15 +141,15 @@ void TattooScene::drawAllShapes() { if (obj._type == ACTIVE_BG_SHAPE && obj._misc == BEHIND) { if (obj._quickDraw && obj._scaleVal == SCALE_THRESHOLD) - screen._backBuffer1.blitFrom(*obj._imageFrame, obj._position); + screen._backBuffer1.SHblitFrom(*obj._imageFrame, obj._position); else - screen._backBuffer1.transBlitFrom(*obj._imageFrame, obj._position, obj._flags & OBJ_FLIPPED, 0, obj._scaleVal); + screen._backBuffer1.SHtransBlitFrom(*obj._imageFrame, obj._position, obj._flags & OBJ_FLIPPED, 0, obj._scaleVal); } } // Draw the animation if it is behind the person if (_activeCAnim.active() && _activeCAnim._zPlacement == BEHIND) - screen._backBuffer1.transBlitFrom(_activeCAnim._imageFrame, _activeCAnim._position, + screen._backBuffer1.SHtransBlitFrom(_activeCAnim._imageFrame, _activeCAnim._position, (_activeCAnim._flags & 4) >> 1, 0, _activeCAnim._scaleVal); screen.resetDisplayBounds(); @@ -194,13 +194,13 @@ void TattooScene::drawAllShapes() { if (se._shape) { // it's a bg shape if (se._shape->_quickDraw && se._shape->_scaleVal == SCALE_THRESHOLD) - screen._backBuffer1.blitFrom(*se._shape->_imageFrame, se._shape->_position); + screen._backBuffer1.SHblitFrom(*se._shape->_imageFrame, se._shape->_position); else - screen._backBuffer1.transBlitFrom(*se._shape->_imageFrame, se._shape->_position, + screen._backBuffer1.SHtransBlitFrom(*se._shape->_imageFrame, se._shape->_position, se._shape->_flags & OBJ_FLIPPED, 0, se._shape->_scaleVal); } else if (se._isAnimation) { // It's an active animation - screen._backBuffer1.transBlitFrom(_activeCAnim._imageFrame, _activeCAnim._position, + screen._backBuffer1.SHtransBlitFrom(_activeCAnim._imageFrame, _activeCAnim._position, (_activeCAnim._flags & 4) >> 1, 0, _activeCAnim._scaleVal); } else { // Drawing person @@ -212,7 +212,7 @@ void TattooScene::drawAllShapes() { if (p._tempScaleVal == SCALE_THRESHOLD) { p._tempX += adjust.x; - screen._backBuffer1.transBlitFrom(*p._imageFrame, Common::Point(p._tempX, p._position.y / FIXED_INT_MULTIPLIER + screen._backBuffer1.SHtransBlitFrom(*p._imageFrame, Common::Point(p._tempX, p._position.y / FIXED_INT_MULTIPLIER - p.frameHeight() - adjust.y), p._walkSequences[p._sequenceNumber]._horizFlip, 0, p._tempScaleVal); } else { if (adjust.x) { @@ -242,7 +242,7 @@ void TattooScene::drawAllShapes() { ++adjust.y; } - screen._backBuffer1.transBlitFrom(*p._imageFrame, Common::Point(p._tempX, p._position.y / FIXED_INT_MULTIPLIER + screen._backBuffer1.SHtransBlitFrom(*p._imageFrame, Common::Point(p._tempX, p._position.y / FIXED_INT_MULTIPLIER - p._imageFrame->sDrawYSize(p._tempScaleVal) - adjust.y), p._walkSequences[p._sequenceNumber]._horizFlip, 0, p._tempScaleVal); } } @@ -255,15 +255,15 @@ void TattooScene::drawAllShapes() { if (obj._type == ACTIVE_BG_SHAPE && obj._misc == FORWARD) { if (obj._quickDraw && obj._scaleVal == SCALE_THRESHOLD) - screen._backBuffer1.blitFrom(*obj._imageFrame, obj._position); + screen._backBuffer1.SHblitFrom(*obj._imageFrame, obj._position); else - screen._backBuffer1.transBlitFrom(*obj._imageFrame, obj._position, obj._flags & OBJ_FLIPPED, 0, obj._scaleVal); + screen._backBuffer1.SHtransBlitFrom(*obj._imageFrame, obj._position, obj._flags & OBJ_FLIPPED, 0, obj._scaleVal); } } // Draw the canimation if it is set as FORWARD if (_activeCAnim.active() && _activeCAnim._zPlacement == FORWARD) - screen._backBuffer1.transBlitFrom(_activeCAnim._imageFrame, _activeCAnim._position, (_activeCAnim._flags & 4) >> 1, 0, _activeCAnim._scaleVal); + screen._backBuffer1.SHtransBlitFrom(_activeCAnim._imageFrame, _activeCAnim._position, (_activeCAnim._flags & 4) >> 1, 0, _activeCAnim._scaleVal); // Draw all NO_SHAPE shapes which have their flag bits clear for (uint idx = 0; idx < _bgShapes.size(); ++idx) { diff --git a/engines/sherlock/tattoo/tattoo_screen.cpp b/engines/sherlock/tattoo/tattoo_screen.cpp new file mode 100644 index 0000000000..c98ae2679d --- /dev/null +++ b/engines/sherlock/tattoo/tattoo_screen.cpp @@ -0,0 +1,37 @@ +/* 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 "sherlock/tattoo/tattoo_screen.h" +#include "sherlock/tattoo/tattoo.h" + +namespace Sherlock { + +namespace Tattoo { + +TattooScreen::TattooScreen(SherlockEngine *vm) : Screen(vm) { + _backBuffer1.create(640, 480); + _backBuffer2.create(640, 480); +} + +} // End of namespace Tattoo + +} // End of namespace Sherlock diff --git a/engines/sherlock/tattoo/tattoo_screen.h b/engines/sherlock/tattoo/tattoo_screen.h new file mode 100644 index 0000000000..b55e9bb0dd --- /dev/null +++ b/engines/sherlock/tattoo/tattoo_screen.h @@ -0,0 +1,44 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef SHERLOCK_TATTOO_SCREEN_H +#define SHERLOCK_TATTOO_SCREEN_H + +#include "sherlock/screen.h" + +namespace Sherlock { + +class SherlockEngine; + +namespace Tattoo { + +class TattooScreen : public Screen { +public: + TattooScreen(SherlockEngine *vm); + virtual ~TattooScreen() {} +}; + +} // End of namespace Tattoo + +} // End of namespace Sherlock + +#endif diff --git a/engines/sherlock/tattoo/tattoo_talk.cpp b/engines/sherlock/tattoo/tattoo_talk.cpp index a5ada7b63e..e6b9a9627e 100644 --- a/engines/sherlock/tattoo/tattoo_talk.cpp +++ b/engines/sherlock/tattoo/tattoo_talk.cpp @@ -795,7 +795,10 @@ OpcodeReturn TattooTalk::cmdTalkInterruptsDisable(const byte *&str) { error("Dum // Dummy opcode OpcodeReturn TattooTalk::cmdTalkInterruptsEnable(const byte *&str) { error("Dummy opcode cmdTalkInterruptsEnable called"); } -OpcodeReturn TattooTalk::cmdTurnSoundsOff(const byte *&str) { error("TODO: script opcode (cmdTurnSoundsOff)"); } +OpcodeReturn TattooTalk::cmdTurnSoundsOff(const byte *&str) { + _vm->_sound->stopSound(); + return RET_SUCCESS; +} OpcodeReturn TattooTalk::cmdWalkHolmesAndNPCToCAnimation(const byte *&str) { int npcNum = *++str; diff --git a/engines/sherlock/tattoo/tattoo_user_interface.cpp b/engines/sherlock/tattoo/tattoo_user_interface.cpp index ee028f89c2..677a662535 100644 --- a/engines/sherlock/tattoo/tattoo_user_interface.cpp +++ b/engines/sherlock/tattoo/tattoo_user_interface.cpp @@ -72,7 +72,7 @@ TattooUserInterface::~TattooUserInterface() { void TattooUserInterface::initScrollVars() { Screen &screen = *_vm->_screen; - _scrollSize = screen._backBuffer1.w() - SHERLOCK_SCREEN_WIDTH; + _scrollSize = screen._backBuffer1.width() - SHERLOCK_SCREEN_WIDTH; _targetScroll = Common::Point(0, 0); screen._currentScroll = Common::Point(0, 0); } @@ -233,7 +233,7 @@ void TattooUserInterface::doJournal() { Common::copy(&lookupTable1[0], &lookupTable1[PALETTE_COUNT], &_lookupTable1[0]); // Restore the scene - screen._backBuffer1.blitFrom(screen._backBuffer2); + screen._backBuffer1.SHblitFrom(screen._backBuffer2); scene.updateBackground(); screen.slamArea(screen._currentScroll.x, screen._currentScroll.y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); } @@ -727,7 +727,7 @@ void TattooUserInterface::doBgAnimEraseBackground() { if (_mask != nullptr) { // Since a mask is active, restore the screen from the secondary back buffer prior to applying the mask - screen._backBuffer1.blitFrom(screen._backBuffer2, screen._currentScroll, Common::Rect(screen._currentScroll.x, 0, + screen._backBuffer1.SHblitFrom(screen._backBuffer2, screen._currentScroll, Common::Rect(screen._currentScroll.x, 0, screen._currentScroll.x + SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); switch (scene._currentScene) { @@ -757,7 +757,7 @@ void TattooUserInterface::doBgAnimEraseBackground() { case 53: if (++_maskCounter == 2) { _maskCounter = 0; - if (++_maskOffset.x == screen._backBuffer1.w()) + if (++_maskOffset.x == screen._backBuffer1.width()) _maskOffset.x = 0; } break; @@ -779,7 +779,7 @@ void TattooUserInterface::doBgAnimEraseBackground() { if ((obj._type == ACTIVE_BG_SHAPE && (obj._maxFrames > 1 || obj._delta.x != 0 || obj._delta.y != 0)) || obj._type == HIDE_SHAPE || obj._type == REMOVE) - screen._backBuffer1.blitFrom(screen._backBuffer2, obj._oldPosition, + screen._backBuffer1.SHblitFrom(screen._backBuffer2, obj._oldPosition, Common::Rect(obj._oldPosition.x, obj._oldPosition.y, obj._oldPosition.x + obj._oldSize.x, obj._oldPosition.y + obj._oldSize.y)); } @@ -793,7 +793,7 @@ void TattooUserInterface::doBgAnimEraseBackground() { Object &obj = scene._bgShapes[idx]; if (obj._type == NO_SHAPE && (obj._flags & 1) == 0) { - screen._backBuffer1.blitFrom(screen._backBuffer2, obj._position, obj.getNoShapeBounds()); + screen._backBuffer1.SHblitFrom(screen._backBuffer2, obj._position, obj.getNoShapeBounds()); obj._oldPosition = obj._position; obj._oldSize = obj._noShapeSize; @@ -870,7 +870,7 @@ void TattooUserInterface::maskArea(Common::SeekableReadStream &mask, const Commo int pixel, len, xp, yp; for (yp = 0; yp < ySize; ++yp) { - byte *ptr = bb1.getBasePtr(pt.x, pt.y + yp); + byte *ptr = (byte *)bb1.getBasePtr(pt.x, pt.y + yp); for (xp = 0; xp < xSize;) { // The mask data consists of pairs of pixel/lengths, where all non-zero pixels means that the @@ -893,7 +893,7 @@ void TattooUserInterface::makeBGArea(const Common::Rect &r) { Screen &screen = *_vm->_screen; for (int yp = r.top; yp < r.bottom; ++yp) { - byte *ptr = screen._backBuffer1.getBasePtr(r.left, yp); + byte *ptr = (byte *)screen._backBuffer1.getBasePtr(r.left, yp); for (int xp = r.left; xp < r.right; ++xp, ++ptr) *ptr = _lookupTable[*ptr]; diff --git a/engines/sherlock/tattoo/widget_base.cpp b/engines/sherlock/tattoo/widget_base.cpp index 8f0649130a..a35f4e5d74 100644 --- a/engines/sherlock/tattoo/widget_base.cpp +++ b/engines/sherlock/tattoo/widget_base.cpp @@ -88,7 +88,7 @@ void WidgetBase::erase() { if (_oldBounds.width() > 0) { // Restore the affected area from the secondary back buffer into the first one, and then copy to screen - screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldBounds.left, _oldBounds.top), _oldBounds); + screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(_oldBounds.left, _oldBounds.top), _oldBounds); screen.slamRect(_oldBounds); // Reset the old bounds so it won't be erased again @@ -111,7 +111,7 @@ void WidgetBase::draw() { drawBackground(); // Draw the widget onto the back buffer and then slam it to the screen - screen._backBuffer1.transBlitFrom(_surface, Common::Point(_bounds.left, _bounds.top)); + screen._backBuffer1.SHtransBlitFrom(_surface, Common::Point(_bounds.left, _bounds.top)); screen.slamRect(_bounds); // Store a copy of the drawn area for later erasing @@ -183,8 +183,8 @@ void WidgetBase::restrictToScreen() { _bounds.moveTo(_bounds.left, 0); if (_bounds.right > (screen._currentScroll.x + SHERLOCK_SCREEN_WIDTH)) _bounds.moveTo(screen._currentScroll.x + SHERLOCK_SCREEN_WIDTH - _bounds.width(), _bounds.top); - if (_bounds.bottom > screen._backBuffer1.h()) - _bounds.moveTo(_bounds.left, screen._backBuffer1.h() - _bounds.height()); + if (_bounds.bottom > screen._backBuffer1.height()) + _bounds.moveTo(_bounds.left, screen._backBuffer1.height() - _bounds.height()); } void WidgetBase::makeInfoArea(Surface &s) { @@ -192,30 +192,30 @@ void WidgetBase::makeInfoArea(Surface &s) { ImageFile &images = *ui._interfaceImages; // Draw the four corners of the Info Box - s.transBlitFrom(images[0], Common::Point(0, 0)); - s.transBlitFrom(images[1], Common::Point(s.w() - images[1]._width, 0)); - s.transBlitFrom(images[2], Common::Point(0, s.h() - images[2]._height)); - s.transBlitFrom(images[3], Common::Point(s.w() - images[3]._width, s.h())); + s.SHtransBlitFrom(images[0], Common::Point(0, 0)); + s.SHtransBlitFrom(images[1], Common::Point(s.width() - images[1]._width, 0)); + s.SHtransBlitFrom(images[2], Common::Point(0, s.height() - images[2]._height)); + s.SHtransBlitFrom(images[3], Common::Point(s.width() - images[3]._width, s.height())); // Draw the top of the Info Box - s.hLine(images[0]._width, 0, s.w() - images[1]._width, INFO_TOP); - s.hLine(images[0]._width, 1, s.w() - images[1]._width, INFO_MIDDLE); - s.hLine(images[0]._width, 2, s.w() - images[1]._width, INFO_BOTTOM); + s.hLine(images[0]._width, 0, s.width() - images[1]._width, INFO_TOP); + s.hLine(images[0]._width, 1, s.width() - images[1]._width, INFO_MIDDLE); + s.hLine(images[0]._width, 2, s.width() - images[1]._width, INFO_BOTTOM); // Draw the bottom of the Info Box - s.hLine(images[0]._width, s.h()- 3, s.w() - images[1]._width, INFO_TOP); - s.hLine(images[0]._width, s.h()- 2, s.w() - images[1]._width, INFO_MIDDLE); - s.hLine(images[0]._width, s.h()- 1, s.w() - images[1]._width, INFO_BOTTOM); + s.hLine(images[0]._width, s.height()- 3, s.width() - images[1]._width, INFO_TOP); + s.hLine(images[0]._width, s.height()- 2, s.width() - images[1]._width, INFO_MIDDLE); + s.hLine(images[0]._width, s.height()- 1, s.width() - images[1]._width, INFO_BOTTOM); // Draw the left Side of the Info Box - s.vLine(0, images[0]._height, s.h()- images[2]._height, INFO_TOP); - s.vLine(1, images[0]._height, s.h()- images[2]._height, INFO_MIDDLE); - s.vLine(2, images[0]._height, s.h()- images[2]._height, INFO_BOTTOM); + s.vLine(0, images[0]._height, s.height()- images[2]._height, INFO_TOP); + s.vLine(1, images[0]._height, s.height()- images[2]._height, INFO_MIDDLE); + s.vLine(2, images[0]._height, s.height()- images[2]._height, INFO_BOTTOM); // Draw the right Side of the Info Box - s.vLine(s.w() - 3, images[0]._height, s.h()- images[2]._height, INFO_TOP); - s.vLine(s.w() - 2, images[0]._height, s.h()- images[2]._height, INFO_MIDDLE); - s.vLine(s.w() - 1, images[0]._height, s.h()- images[2]._height, INFO_BOTTOM); + s.vLine(s.width() - 3, images[0]._height, s.height()- images[2]._height, INFO_TOP); + s.vLine(s.width() - 2, images[0]._height, s.height()- images[2]._height, INFO_MIDDLE); + s.vLine(s.width() - 1, images[0]._height, s.height()- images[2]._height, INFO_BOTTOM); } void WidgetBase::makeInfoArea() { diff --git a/engines/sherlock/tattoo/widget_credits.cpp b/engines/sherlock/tattoo/widget_credits.cpp index b8e297709f..1c878daaf6 100644 --- a/engines/sherlock/tattoo/widget_credits.cpp +++ b/engines/sherlock/tattoo/widget_credits.cpp @@ -37,7 +37,7 @@ void WidgetCredits::initCredits() { Screen &screen = *_vm->_screen; Common::SeekableReadStream *stream = res.load("credits.txt"); int spacing = screen.fontHeight() * 2; - int yp = screen.h(); + int yp = screen.height(); _creditsActive = true; _creditLines.clear(); @@ -60,7 +60,7 @@ void WidgetCredits::initCredits() { } else { int width = screen.stringWidth(line) + 2; - _creditLines.push_back(CreditLine(line, Common::Point((screen.w() - width) / 2 + 1, yp), width)); + _creditLines.push_back(CreditLine(line, Common::Point((screen.width() - width) / 2 + 1, yp), width)); yp += spacing; } } @@ -120,10 +120,10 @@ void WidgetCredits::close() { void WidgetCredits::drawCredits() { Screen &screen = *_vm->_screen; - Common::Rect screenRect(0, 0, screen.w(), screen.h()); + Common::Rect screenRect(0, 0, screen.width(), screen.height()); Surface &bb1 = screen._backBuffer1; - for (uint idx = 0; idx < _creditLines.size() && _creditLines[idx]._position.y < screen.h(); ++idx) { + for (uint idx = 0; idx < _creditLines.size() && _creditLines[idx]._position.y < screen.height(); ++idx) { if (screenRect.contains(_creditLines[idx]._position)) { if (!_creditLines[idx]._line2.empty()) { int x1 = _creditLines[idx]._position.x; @@ -176,7 +176,7 @@ void WidgetCredits::drawCredits() { void WidgetCredits::blitCredits() { Screen &screen = *_vm->_screen; - Common::Rect screenRect(0, -_creditSpeed, screen.w(), screen.h() + _creditSpeed); + Common::Rect screenRect(0, -_creditSpeed, screen.width(), screen.height() + _creditSpeed); for (uint idx = 0; idx < _creditLines.size(); ++idx) { if (screenRect.contains(_creditLines[idx]._position)) { @@ -185,14 +185,12 @@ void WidgetCredits::blitCredits() { screen.slamRect(r); } - - _creditLines[idx]._position.y -= _creditSpeed; } } void WidgetCredits::eraseCredits() { Screen &screen = *_vm->_screen; - Common::Rect screenRect(0, -_creditSpeed, screen.w(), screen.h() + _creditSpeed); + Common::Rect screenRect(0, -_creditSpeed, screen.width(), screen.height() + _creditSpeed); for (uint idx = 0; idx < _creditLines.size(); ++idx) { if (screenRect.contains(_creditLines[idx]._position)) { @@ -200,7 +198,10 @@ void WidgetCredits::eraseCredits() { r.moveTo(_creditLines[idx]._position.x, _creditLines[idx]._position.y - 1 + _creditSpeed); screen.restoreBackground(r); + screen.slamRect(r); } + + _creditLines[idx]._position.y -= _creditSpeed; } if (_creditLines[_creditLines.size() - 1]._position.y < -_creditSpeed) { diff --git a/engines/sherlock/tattoo/widget_files.cpp b/engines/sherlock/tattoo/widget_files.cpp index ff8cb83dca..7666e81480 100644 --- a/engines/sherlock/tattoo/widget_files.cpp +++ b/engines/sherlock/tattoo/widget_files.cpp @@ -107,36 +107,36 @@ void WidgetFiles::render(FilesRenderMode mode) { byte color; if (mode == RENDER_ALL) { - _surface.fill(TRANSPARENCY); + _surface.clear(TRANSPARENCY); makeInfoArea(); switch (_fileMode) { case SAVEMODE_LOAD: _surface.writeString(FIXED(LoadGame), - Common::Point((_surface.w() - _surface.stringWidth(FIXED(LoadGame))) / 2, 5), INFO_TOP); + Common::Point((_surface.width() - _surface.stringWidth(FIXED(LoadGame))) / 2, 5), INFO_TOP); break; case SAVEMODE_SAVE: _surface.writeString(FIXED(SaveGame), - Common::Point((_surface.w() - _surface.stringWidth(FIXED(SaveGame))) / 2, 5), INFO_TOP); + Common::Point((_surface.width() - _surface.stringWidth(FIXED(SaveGame))) / 2, 5), INFO_TOP); break; default: break; } - _surface.hLine(3, _surface.fontHeight() + 7, _surface.w() - 4, INFO_TOP); - _surface.hLine(3, _surface.fontHeight() + 8, _surface.w() - 4, INFO_MIDDLE); - _surface.hLine(3, _surface.fontHeight() + 9, _surface.w() - 4, INFO_BOTTOM); - _surface.transBlitFrom(images[4], Common::Point(0, _surface.fontHeight() + 6)); - _surface.transBlitFrom(images[5], Common::Point(_surface.w() - images[5]._width, _surface.fontHeight() + 6)); + _surface.hLine(3, _surface.fontHeight() + 7, _surface.width() - 4, INFO_TOP); + _surface.hLine(3, _surface.fontHeight() + 8, _surface.width() - 4, INFO_MIDDLE); + _surface.hLine(3, _surface.fontHeight() + 9, _surface.width() - 4, INFO_BOTTOM); + _surface.SHtransBlitFrom(images[4], Common::Point(0, _surface.fontHeight() + 6)); + _surface.SHtransBlitFrom(images[5], Common::Point(_surface.width() - images[5]._width, _surface.fontHeight() + 6)); - int xp = _surface.w() - BUTTON_SIZE - 6; + int xp = _surface.width() - BUTTON_SIZE - 6; _surface.vLine(xp, _surface.fontHeight() + 10, _bounds.height() - 4, INFO_TOP); _surface.vLine(xp + 1, _surface.fontHeight() + 10, _bounds.height() - 4, INFO_MIDDLE); _surface.vLine(xp + 2, _surface.fontHeight() + 10, _bounds.height() - 4, INFO_BOTTOM); - _surface.transBlitFrom(images[6], Common::Point(xp - 1, _surface.fontHeight() + 8)); - _surface.transBlitFrom(images[7], Common::Point(xp - 1, _bounds.height() - 4)); + _surface.SHtransBlitFrom(images[6], Common::Point(xp - 1, _surface.fontHeight() + 8)); + _surface.SHtransBlitFrom(images[7], Common::Point(xp - 1, _bounds.height() - 4)); } int xp = _surface.stringWidth("00.") + _surface.widestChar() + 5; @@ -149,7 +149,7 @@ void WidgetFiles::render(FilesRenderMode mode) { color = INFO_TOP; if (mode == RENDER_NAMES_AND_SCROLLBAR) - _surface.fillRect(Common::Rect(4, yp, _surface.w() - BUTTON_SIZE - 9, yp + _surface.fontHeight()), TRANSPARENCY); + _surface.fillRect(Common::Rect(4, yp, _surface.width() - BUTTON_SIZE - 9, yp + _surface.fontHeight()), TRANSPARENCY); Common::String numStr = Common::String::format("%d.", idx + 1); _surface.writeString(numStr, Common::Point(_surface.widestChar(), yp), color); @@ -324,7 +324,7 @@ bool WidgetFiles::getFilename() { filename.setChar(' ', index); } - _surface.fillRect(Common::Rect(pt.x, pt.y, _surface.w() - BUTTON_SIZE - 9, pt.y + _surface.fontHeight() - 1), TRANSPARENCY); + _surface.fillRect(Common::Rect(pt.x, pt.y, _surface.width() - BUTTON_SIZE - 9, pt.y + _surface.fontHeight() - 1), TRANSPARENCY); _surface.writeString(filename.c_str() + index, pt, COMMAND_HIGHLIGHTED); } else if ((keyState.keycode == Common::KEYCODE_LEFT && index > 0) @@ -387,7 +387,7 @@ bool WidgetFiles::getFilename() { } if ((keyState.ascii >= ' ') && (keyState.ascii <= 'z') && (index < 50)) { - if (pt.x + _surface.charWidth(keyState.ascii) < _surface.w() - BUTTON_SIZE - 20) { + if (pt.x + _surface.charWidth(keyState.ascii) < _surface.w - BUTTON_SIZE - 20) { if (insert) filename.insertChar(keyState.ascii, index); else diff --git a/engines/sherlock/tattoo/widget_foolscap.cpp b/engines/sherlock/tattoo/widget_foolscap.cpp index c8df71e873..8225946838 100644 --- a/engines/sherlock/tattoo/widget_foolscap.cpp +++ b/engines/sherlock/tattoo/widget_foolscap.cpp @@ -103,7 +103,7 @@ void WidgetFoolscap::show() { // Set up the window background _surface.create(_bounds.width(), _bounds.height()); - _surface.blitFrom(paperFrame, Common::Point(0, 0)); + _surface.SHblitFrom(paperFrame, Common::Point(0, 0)); // If they have already solved the puzzle, put the answer on the graphic if (_vm->readFlags(299)) { @@ -265,7 +265,7 @@ void WidgetFoolscap::handleKeyboardEvents() { void WidgetFoolscap::restoreChar() { Screen &screen = *_vm->_screen; ImageFrame &bgFrame = (*_images)[0]; - _surface.blitFrom(bgFrame, _cursorPos, Common::Rect(_cursorPos.x, _cursorPos.y, + _surface.SHblitFrom(bgFrame, _cursorPos, Common::Rect(_cursorPos.x, _cursorPos.y, _cursorPos.x + screen.widestChar(), _cursorPos.y + screen.fontHeight())); } diff --git a/engines/sherlock/tattoo/widget_inventory.cpp b/engines/sherlock/tattoo/widget_inventory.cpp index b49e30b30d..34331f0eae 100644 --- a/engines/sherlock/tattoo/widget_inventory.cpp +++ b/engines/sherlock/tattoo/widget_inventory.cpp @@ -94,7 +94,7 @@ void WidgetInventoryTooltip::setText(const Common::String &str) { // Allocate a fresh surface for the new string _bounds = Common::Rect(width, height); _surface.create(width, height); - _surface.fill(TRANSPARENCY); + _surface.clear(TRANSPARENCY); if (line2.empty()) { _surface.writeFancyString(str, Common::Point(0, 0), BLACK, INFO_TOP); @@ -338,7 +338,7 @@ void WidgetInventoryVerbs::load() { // Create the surface _surface.create(_bounds.width(), _bounds.height()); - _surface.fill(TRANSPARENCY); + _surface.clear(TRANSPARENCY); makeInfoArea(); // Draw the Verb commands and the lines separating them @@ -352,8 +352,8 @@ void WidgetInventoryVerbs::load() { _surface.vLine(3, (_surface.fontHeight() + 7) * (idx + 1) + 1, _bounds.right - 4, INFO_MIDDLE); _surface.vLine(3, (_surface.fontHeight() + 7) * (idx + 1) + 2, _bounds.right - 4, INFO_BOTTOM); - _surface.transBlitFrom(images[4], Common::Point(0, (_surface.fontHeight() + 7) * (idx + 1))); - _surface.transBlitFrom(images[5], Common::Point(_bounds.width() - images[5]._width, + _surface.SHtransBlitFrom(images[4], Common::Point(0, (_surface.fontHeight() + 7) * (idx + 1))); + _surface.SHtransBlitFrom(images[5], Common::Point(_bounds.width() - images[5]._width, (_surface.fontHeight() + 7) * (idx + 1) - 1)); } } @@ -515,7 +515,7 @@ void WidgetInventory::load(int mode) { // Redraw the inventory menu on the widget surface _surface.create(_bounds.width(), _bounds.height()); - _surface.fill(TRANSPARENCY); + _surface.clear(TRANSPARENCY); // Draw the window background and then the inventory on top of it makeInfoArea(_surface); @@ -531,7 +531,7 @@ void WidgetInventory::drawBars() { _surface.hLine(3, INVENTORY_YSIZE + 3, _bounds.width() - 4, INFO_TOP); _surface.hLine(3, INVENTORY_YSIZE + 4, _bounds.width() - 4, INFO_MIDDLE); _surface.hLine(3, INVENTORY_YSIZE + 5, _bounds.width() - 4, INFO_BOTTOM); - _surface.transBlitFrom(images[4], Common::Point(0, INVENTORY_YSIZE + 2)); + _surface.SHtransBlitFrom(images[4], Common::Point(0, INVENTORY_YSIZE + 2)); for (int idx = 1; idx <= NUM_INVENTORY_SHOWN / 2; ++idx) { x = idx * (INVENTORY_XSIZE + 3); @@ -540,10 +540,10 @@ void WidgetInventory::drawBars() { _surface.vLine(x + 1, 3, _bounds.height() - 4, INFO_MIDDLE); _surface.vLine(x + 2, 3, _bounds.height() - 4, INFO_BOTTOM); - _surface.transBlitFrom(images[6], Common::Point(x - 1, 1)); - _surface.transBlitFrom(images[7], Common::Point(x - 1, _bounds.height() - 4)); - _surface.transBlitFrom(images[6], Common::Point(x - 1, INVENTORY_YSIZE + 5)); - _surface.transBlitFrom(images[7], Common::Point(x - 1, INVENTORY_YSIZE + 2)); + _surface.SHtransBlitFrom(images[6], Common::Point(x - 1, 1)); + _surface.SHtransBlitFrom(images[7], Common::Point(x - 1, _bounds.height() - 4)); + _surface.SHtransBlitFrom(images[6], Common::Point(x - 1, INVENTORY_YSIZE + 5)); + _surface.SHtransBlitFrom(images[7], Common::Point(x - 1, INVENTORY_YSIZE + 2)); } _surface.hLine(x + 2, INVENTORY_YSIZE + 2, INVENTORY_YSIZE + 8, INFO_BOTTOM); @@ -566,7 +566,7 @@ void WidgetInventory::drawInventory() { // Draw the item if (itemId < inv._holdings) { ImageFrame &img = (*inv._invShapes[idx])[0]; - _surface.transBlitFrom(img, Common::Point(pt.x + (INVENTORY_XSIZE - img._width) / 2, + _surface.SHtransBlitFrom(img, Common::Point(pt.x + (INVENTORY_XSIZE - img._width) / 2, pt.y + (INVENTORY_YSIZE - img._height) / 2)); } } diff --git a/engines/sherlock/tattoo/widget_options.cpp b/engines/sherlock/tattoo/widget_options.cpp index 92bd10bbf6..81f50f3bc5 100644 --- a/engines/sherlock/tattoo/widget_options.cpp +++ b/engines/sherlock/tattoo/widget_options.cpp @@ -257,17 +257,17 @@ void WidgetOptions::render(OptionRenderMode mode) { // Setup the dialog _surface.create(_bounds.width(), _bounds.height()); - _surface.fill(TRANSPARENCY); + _surface.clear(TRANSPARENCY); makeInfoArea(); // Draw the lines separating options in the dialog int yp = _surface.fontHeight() + 7; for (int idx = 0; idx < 7; ++idx) { - _surface.transBlitFrom(images[4], Common::Point(0, yp - 1)); - _surface.transBlitFrom(images[5], Common::Point(_surface.w() - images[5]._width, yp - 1)); - _surface.hLine(3, yp, _surface.w() - 4, INFO_TOP); - _surface.hLine(3, yp + 1, _surface.w() - 4, INFO_MIDDLE); - _surface.hLine(3, yp + 2, _surface.w() - 4, INFO_BOTTOM); + _surface.SHtransBlitFrom(images[4], Common::Point(0, yp - 1)); + _surface.SHtransBlitFrom(images[5], Common::Point(_surface.width() - images[5]._width, yp - 1)); + _surface.hLine(3, yp, _surface.width() - 4, INFO_TOP); + _surface.hLine(3, yp + 1, _surface.width() - 4, INFO_MIDDLE); + _surface.hLine(3, yp + 2, _surface.width() - 4, INFO_BOTTOM); yp += _surface.fontHeight() + 7; if (idx == 1) @@ -281,7 +281,7 @@ void WidgetOptions::render(OptionRenderMode mode) { for (int idx = 0, yp = 5; idx < 11; ++idx, yp += _surface.fontHeight() + 7) { if (mode == OP_ALL || idx == _selector || idx == _oldSelector) { if (mode == OP_NAMES) - _surface.fillRect(Common::Rect(4, yp, _surface.w() - 5, yp + _surface.fontHeight() - 1), TRANSPARENCY); + _surface.fillRect(Common::Rect(4, yp, _surface.width() - 5, yp + _surface.fontHeight() - 1), TRANSPARENCY); byte color = (idx == _selector) ? COMMAND_HIGHLIGHTED : INFO_TOP; Common::String str; @@ -302,11 +302,11 @@ void WidgetOptions::render(OptionRenderMode mode) { int num = (_surface.fontHeight() + 4) & 0xfe; int sliderY = yp + num / 2 - 8; - _surface.fillRect(Common::Rect(4, sliderY - (num - 6) / 2, _surface.w() - 5, + _surface.fillRect(Common::Rect(4, sliderY - (num - 6) / 2, _surface.width() - 5, sliderY - (num - 6) / 2 + num - 1), TRANSPARENCY); _surface.fillRect(Common::Rect(_surface.widestChar(), sliderY + 2, - _surface.w() - _surface.widestChar() - 1, sliderY + 3), INFO_MIDDLE); - drawDialogRect(Common::Rect(_surface.widestChar(), sliderY, _surface.w() - _surface.widestChar(), sliderY + 6)); + _surface.width() - _surface.widestChar() - 1, sliderY + 3), INFO_MIDDLE); + drawDialogRect(Common::Rect(_surface.widestChar(), sliderY, _surface.width() - _surface.widestChar(), sliderY + 6)); _surface.fillRect(Common::Rect(_midiSliderX - 1, sliderY - (num - 6) / 2 + 2, _midiSliderX + 1, sliderY - (num - 6) / 2 + num - 3), INFO_MIDDLE); @@ -315,7 +315,7 @@ void WidgetOptions::render(OptionRenderMode mode) { if (_midiSliderX - 4 > _surface.widestChar()) _surface.fillRect(Common::Rect(_midiSliderX - 4, sliderY, _midiSliderX - 4, sliderY + 4), INFO_BOTTOM); - if (_midiSliderX + 4 < _surface.w() - _surface.widestChar()) + if (_midiSliderX + 4 < _surface.width() - _surface.widestChar()) _surface.fillRect(Common::Rect(_midiSliderX + 4, sliderY, _midiSliderX + 4, sliderY + 4), INFO_BOTTOM); break; } @@ -332,18 +332,18 @@ void WidgetOptions::render(OptionRenderMode mode) { int num = (_surface.fontHeight() + 4) & 0xfe; int sliderY = yp + num / 2 - 8; - _surface.fillRect(Common::Rect(4, sliderY - (num - 6) / 2, _surface.w() - 5, + _surface.fillRect(Common::Rect(4, sliderY - (num - 6) / 2, _surface.width() - 5, sliderY - (num - 6) / 2 + num - 1), TRANSPARENCY); - _surface.fillRect(Common::Rect(_surface.widestChar(), sliderY + 2, _surface.w() - _surface.widestChar() - 1, + _surface.fillRect(Common::Rect(_surface.widestChar(), sliderY + 2, _surface.width() - _surface.widestChar() - 1, sliderY + 3), INFO_MIDDLE); - drawDialogRect(Common::Rect(_surface.widestChar(), sliderY, _surface.w() - _surface.widestChar(), sliderY + 6)); + drawDialogRect(Common::Rect(_surface.widestChar(), sliderY, _surface.width() - _surface.widestChar(), sliderY + 6)); _surface.fillRect(Common::Rect(_digiSliderX - 1, sliderY - (num - 6) / 2 + 2, _digiSliderX + 1, sliderY - (num - 6) / 2 + num - 3), INFO_MIDDLE); drawDialogRect(Common::Rect(_digiSliderX - 3, sliderY - (num - 6) / 2, _digiSliderX + 4, sliderY - (num - 6) / 2 + num)); if (_digiSliderX - 4 > _surface.widestChar()) _surface.fillRect(Common::Rect(_digiSliderX - 4, sliderY, _digiSliderX - 4, sliderY + 4), INFO_BOTTOM); - if (_digiSliderX + 4 < _surface.w() - _surface.widestChar()) + if (_digiSliderX + 4 < _surface.width() - _surface.widestChar()) _surface.fillRect(Common::Rect(_digiSliderX + 4, sliderY, _digiSliderX + 4, sliderY + 4), INFO_BOTTOM); break; } @@ -375,7 +375,7 @@ void WidgetOptions::render(OptionRenderMode mode) { // Unless we're doing one of the Slider Controls, print the text for the line if (idx != 3 && idx != 6) { - int xp = (_surface.w() - _surface.stringWidth(str)) / 2; + int xp = (_surface.width() - _surface.stringWidth(str)) / 2; _surface.writeString(str, Common::Point(xp, yp), color); } } diff --git a/engines/sherlock/tattoo/widget_password.cpp b/engines/sherlock/tattoo/widget_password.cpp index 57a5e02653..2a2921026d 100644 --- a/engines/sherlock/tattoo/widget_password.cpp +++ b/engines/sherlock/tattoo/widget_password.cpp @@ -47,7 +47,7 @@ void WidgetPassword::show() { // Create the surface _surface.create(_bounds.width(), _bounds.height()); - _surface.fill(TRANSPARENCY); + _surface.clear(TRANSPARENCY); makeInfoArea(); // Draw the header area @@ -55,8 +55,8 @@ void WidgetPassword::show() { _surface.hLine(3, _surface.fontHeight() + 7, _bounds.width() - 4, INFO_TOP); _surface.hLine(3, _surface.fontHeight() + 8, _bounds.width() - 4, INFO_MIDDLE); _surface.hLine(3, _surface.fontHeight() + 9, _bounds.width() - 4, INFO_BOTTOM); - _surface.transBlitFrom(images[4], Common::Point(0, _surface.fontHeight() + 7 - 1)); - _surface.transBlitFrom(images[5], Common::Point(_bounds.width() - images[5]._width, _surface.fontHeight() + 7 - 1)); + _surface.SHtransBlitFrom(images[4], Common::Point(0, _surface.fontHeight() + 7 - 1)); + _surface.SHtransBlitFrom(images[5], Common::Point(_bounds.width() - images[5]._width, _surface.fontHeight() + 7 - 1)); // Set the password entry data _cursorPos = Common::Point(_surface.widestChar(), _surface.fontHeight() + 12); diff --git a/engines/sherlock/tattoo/widget_quit.cpp b/engines/sherlock/tattoo/widget_quit.cpp index f853e7f47f..ea8f2e080c 100644 --- a/engines/sherlock/tattoo/widget_quit.cpp +++ b/engines/sherlock/tattoo/widget_quit.cpp @@ -48,22 +48,22 @@ void WidgetQuit::show() { // Create the surface _surface.create(_bounds.width(), _bounds.height()); - _surface.fill(TRANSPARENCY); + _surface.clear(TRANSPARENCY); makeInfoArea(); // Draw the message text - _surface.writeString(FIXED(AreYouSureYou), Common::Point((_surface.w() - _surface.stringWidth(FIXED(AreYouSureYou))) / 2, 5), INFO_TOP); - _surface.writeString(FIXED(WishToQuit), Common::Point((_surface.w() - _surface.stringWidth(FIXED(WishToQuit))) / 2, + _surface.writeString(FIXED(AreYouSureYou), Common::Point((_surface.width() - _surface.stringWidth(FIXED(AreYouSureYou))) / 2, 5), INFO_TOP); + _surface.writeString(FIXED(WishToQuit), Common::Point((_surface.width() - _surface.stringWidth(FIXED(WishToQuit))) / 2, _surface.fontHeight() + 9), INFO_TOP); // Draw the horizontal bars seperating the commands and the message int yp = (_surface.fontHeight() + 4) * 2 + 3; for (int idx = 0; idx < 2; ++idx) { - _surface.transBlitFrom(images[4], Common::Point(0, yp - 1)); - _surface.transBlitFrom(images[5], Common::Point(_surface.w() - images[5]._width, yp - 1)); - _surface.hLine(3, yp, _surface.w() - 4, INFO_TOP); - _surface.hLine(3, yp + 1, _surface.w() - 4, INFO_MIDDLE); - _surface.hLine(3, yp + 2, _surface.w() - 4, INFO_BOTTOM); + _surface.SHtransBlitFrom(images[4], Common::Point(0, yp - 1)); + _surface.SHtransBlitFrom(images[5], Common::Point(_surface.width() - images[5]._width, yp - 1)); + _surface.hLine(3, yp, _surface.width() - 4, INFO_TOP); + _surface.hLine(3, yp + 1, _surface.width() - 4, INFO_MIDDLE); + _surface.hLine(3, yp + 2, _surface.width() - 4, INFO_BOTTOM); const char *btn = (idx == 0) ? YES : NO; _surface.writeString(btn, Common::Point((_bounds.width() - _surface.stringWidth(btn)) / 2, yp + 5), INFO_TOP); @@ -129,11 +129,11 @@ void WidgetQuit::handleEvents() { if (_select != _oldSelect) { byte color = (_select == 1) ? COMMAND_HIGHLIGHTED : INFO_TOP; int yp = (_surface.fontHeight() + 4) * 2 + 8; - _surface.writeString(FIXED(Yes), Common::Point((_surface.w() - _surface.stringWidth(FIXED(Yes))) / 2, yp), color); + _surface.writeString(FIXED(Yes), Common::Point((_surface.width() - _surface.stringWidth(FIXED(Yes))) / 2, yp), color); color = (_select == 0) ? COMMAND_HIGHLIGHTED : INFO_TOP; yp += (_surface.fontHeight() + 7); - _surface.writeString(FIXED(No), Common::Point((_surface.w() - _surface.stringWidth(FIXED(No))) / 2, yp), color); + _surface.writeString(FIXED(No), Common::Point((_surface.width() - _surface.stringWidth(FIXED(No))) / 2, yp), color); } _oldSelect = _select; diff --git a/engines/sherlock/tattoo/widget_talk.cpp b/engines/sherlock/tattoo/widget_talk.cpp index 6e7bde292f..b673f32d31 100644 --- a/engines/sherlock/tattoo/widget_talk.cpp +++ b/engines/sherlock/tattoo/widget_talk.cpp @@ -100,7 +100,7 @@ void WidgetTalk::load() { // Set up the surface _surface.create(_bounds.width(), _bounds.height()); - _surface.fill(TRANSPARENCY); + _surface.clear(TRANSPARENCY); // Form the background for the new window makeInfoArea(); @@ -389,7 +389,7 @@ void WidgetTalk::render(Highlight highlightMode) { if (highlightMode == HL_NO_HIGHLIGHTING || _statementLines[idx]._num == _selector || _statementLines[idx]._num == _oldSelector) { // Erase the line contents - _surface.fillRect(Common::Rect(3, yp, _surface.w() - BUTTON_SIZE - 3, yp + _surface.fontHeight()), TRANSPARENCY); + _surface.fillRect(Common::Rect(3, yp, _surface.width() - BUTTON_SIZE - 3, yp + _surface.fontHeight()), TRANSPARENCY); // Different coloring based on whether the option has been previously chosen or not byte color = (!talk._talkHistory[talk._converseNum][_statementLines[idx]._num]) ? diff --git a/engines/sherlock/tattoo/widget_text.cpp b/engines/sherlock/tattoo/widget_text.cpp index 86aa067301..a29cd2700f 100644 --- a/engines/sherlock/tattoo/widget_text.cpp +++ b/engines/sherlock/tattoo/widget_text.cpp @@ -80,6 +80,7 @@ void WidgetText::centerWindowOnSpeaker(int speaker) { TattooScene &scene = *(TattooScene *)_vm->_scene; Common::Point pt; + speaker &= 0x7f; bool flag = _vm->readFlags(FLAG_PLAYER_IS_HOLMES); if (people[HOLMES]._type == CHARACTER && ((speaker == HOLMES && flag) || (speaker == WATSON && !flag))) { // Place the window centered above the player @@ -165,7 +166,7 @@ void WidgetText::render(const Common::String &str) { // Allocate a surface for the window _surface.create(_bounds.width(), _bounds.height()); - _surface.fill(TRANSPARENCY); + _surface.clear(TRANSPARENCY); // Form the background for the new window makeInfoArea(); @@ -194,7 +195,7 @@ void WidgetMessage::load(const Common::String &str, int time) { // Allocate a surface for the window _surface.create(_bounds.width(), _bounds.height()); - _surface.fill(TRANSPARENCY); + _surface.clear(TRANSPARENCY); // Form the background for the new window and write the line of text makeInfoArea(); diff --git a/engines/sherlock/tattoo/widget_tooltip.cpp b/engines/sherlock/tattoo/widget_tooltip.cpp index b29f45f531..1560cb9a80 100644 --- a/engines/sherlock/tattoo/widget_tooltip.cpp +++ b/engines/sherlock/tattoo/widget_tooltip.cpp @@ -47,7 +47,7 @@ void WidgetTooltipBase::draw() { // Draw the widget directly onto the screen. Unlike other widgets, we don't draw to the back buffer, // since nothing should be drawing on top of tooltips, so there's no need to store in the back buffer - screen.transBlitFrom(_surface, Common::Point(_bounds.left - screen._currentScroll.x, + screen.SHtransBlitFrom(_surface, Common::Point(_bounds.left - screen._currentScroll.x, _bounds.top - screen._currentScroll.y)); // Store a copy of the drawn area for later erasing @@ -126,7 +126,7 @@ void WidgetTooltip::setText(const Common::String &str) { // Reallocate the text surface with the new size _surface.create(width, height); - _surface.fill(TRANSPARENCY); + _surface.clear(TRANSPARENCY); if (line2.empty()) { // Only a single line diff --git a/engines/sherlock/tattoo/widget_verbs.cpp b/engines/sherlock/tattoo/widget_verbs.cpp index 499afb2e79..5041888ffb 100644 --- a/engines/sherlock/tattoo/widget_verbs.cpp +++ b/engines/sherlock/tattoo/widget_verbs.cpp @@ -127,7 +127,7 @@ void WidgetVerbs::render() { // Create the drawing surface _surface.create(_bounds.width(), _bounds.height()); - _surface.fill(TRANSPARENCY); + _surface.clear(TRANSPARENCY); // Draw basic background makeInfoArea(); @@ -142,8 +142,8 @@ void WidgetVerbs::render() { _surface.hLine(3, (_surface.fontHeight() + 7) * (idx + 1) + 1, _bounds.width() - 4, INFO_MIDDLE); _surface.hLine(3, (_surface.fontHeight() + 7) * (idx + 1) + 2, _bounds.width() - 4, INFO_BOTTOM); - _surface.transBlitFrom(images[4], Common::Point(0, (_surface.fontHeight() + 7) * (idx + 1) - 1)); - _surface.transBlitFrom(images[5], Common::Point(_bounds.width() - images[5]._width, + _surface.SHtransBlitFrom(images[4], Common::Point(0, (_surface.fontHeight() + 7) * (idx + 1) - 1)); + _surface.SHtransBlitFrom(images[5], Common::Point(_bounds.width() - images[5]._width, (_surface.fontHeight() + 7) * (idx + 1) - 1)); } } diff --git a/engines/sky/detection.cpp b/engines/sky/detection.cpp index 8a8967629d..4b91f50a61 100644 --- a/engines/sky/detection.cpp +++ b/engines/sky/detection.cpp @@ -136,7 +136,7 @@ const ExtraGuiOptions SkyMetaEngine::getExtraGuiOptions(const Common::String &ta } GameDescriptor SkyMetaEngine::findGame(const char *gameid) const { - if (0 == scumm_stricmp(gameid, skySetting.gameid)) + if (0 == scumm_stricmp(gameid, skySetting.gameId)) return skySetting; return GameDescriptor(); } @@ -175,7 +175,7 @@ GameList SkyMetaEngine::detectGames(const Common::FSList &fslist) const { // Match found, add to list of candidates, then abort inner loop. // The game detector uses US English by default. We want British // English to match the recorded voices better. - GameDescriptor dg(skySetting.gameid, skySetting.description, Common::UNK_LANG, Common::kPlatformUnknown); + GameDescriptor dg(skySetting.gameId, skySetting.description, Common::UNK_LANG, Common::kPlatformUnknown); const SkyVersion *sv = skyVersions; while (sv->dinnerTableEntries) { if (dinnerTableEntries == sv->dinnerTableEntries && @@ -223,7 +223,6 @@ SaveStateList SkyMetaEngine::listSaves(const char *target) const { // Find all saves Common::StringArray filenames; filenames = saveFileMan->listSavefiles("SKY-VM.###"); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) // Slot 0 is the autosave, if it exists. // TODO: Check for the existence of the autosave -- but this require us @@ -243,6 +242,8 @@ SaveStateList SkyMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/sword1/configure.engine b/engines/sword1/configure.engine index 0578d176a9..1d17903b69 100644 --- a/engines/sword1/configure.engine +++ b/engines/sword1/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine sword1 "Broken Sword" yes +add_engine sword1 "Broken Sword" yes "" "" "highres" diff --git a/engines/sword1/detection.cpp b/engines/sword1/detection.cpp index 99c4bda9e9..0edf856125 100644 --- a/engines/sword1/detection.cpp +++ b/engines/sword1/detection.cpp @@ -128,17 +128,17 @@ GameList SwordMetaEngine::getSupportedGames() const { } GameDescriptor SwordMetaEngine::findGame(const char *gameid) const { - if (0 == scumm_stricmp(gameid, sword1FullSettings.gameid)) + if (0 == scumm_stricmp(gameid, sword1FullSettings.gameId)) return sword1FullSettings; - if (0 == scumm_stricmp(gameid, sword1DemoSettings.gameid)) + if (0 == scumm_stricmp(gameid, sword1DemoSettings.gameId)) return sword1DemoSettings; - if (0 == scumm_stricmp(gameid, sword1MacFullSettings.gameid)) + if (0 == scumm_stricmp(gameid, sword1MacFullSettings.gameId)) return sword1MacFullSettings; - if (0 == scumm_stricmp(gameid, sword1MacDemoSettings.gameid)) + if (0 == scumm_stricmp(gameid, sword1MacDemoSettings.gameId)) return sword1MacDemoSettings; - if (0 == scumm_stricmp(gameid, sword1PSXSettings.gameid)) + if (0 == scumm_stricmp(gameid, sword1PSXSettings.gameId)) return sword1PSXSettings; - if (0 == scumm_stricmp(gameid, sword1PSXDemoSettings.gameid)) + if (0 == scumm_stricmp(gameid, sword1PSXDemoSettings.gameId)) return sword1PSXDemoSettings; return GameDescriptor(); } @@ -241,7 +241,6 @@ SaveStateList SwordMetaEngine::listSaves(const char *target) const { char saveName[40]; Common::StringArray filenames = saveFileMan->listSavefiles("sword1.###"); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) int slotNum = 0; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -259,6 +258,8 @@ SaveStateList SwordMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/sword1/objectman.cpp b/engines/sword1/objectman.cpp index 07f19154a0..651e47f211 100644 --- a/engines/sword1/objectman.cpp +++ b/engines/sword1/objectman.cpp @@ -119,7 +119,7 @@ char *ObjectMan::lockText(uint32 textId, uint8 lang) { return NULL; addr += sizeof(Header); if ((textId & ITM_ID) >= _resMan->readUint32(addr)) { - // Workaround for missing sentences in some langages in the demo. + // Workaround for missing sentences in some languages in the demo. switch(textId) { case 8455194: return const_cast<char *>(_translationId8455194[lang]); @@ -160,7 +160,7 @@ char *ObjectMan::lockText(uint32 textId, uint8 lang) { } uint32 offset = _resMan->readUint32(addr + ((textId & ITM_ID) + 1) * 4); if (offset == 0) { - // Workaround bug for missing sentence in some langages in Syria (see bug #1977094). + // Workaround bug for missing sentence in some languages in Syria (see bug #1977094). // We use the hardcoded text in this case. if (textId == 2950145) return const_cast<char *>(_translationId2950145[lang]); @@ -223,7 +223,7 @@ void ObjectMan::saveLiveList(uint16 *dest) { } // String displayed when a subtitle sentence is missing in the cluster file. -// It happens with at least one sentence in Syria in some langages (see bug +// It happens with at least one sentence in Syria in some languages (see bug // #1977094). // Note: an empty string or a null pointer causes a crash. diff --git a/engines/sword1/objectman.h b/engines/sword1/objectman.h index fef1a8da3a..79be82c02f 100644 --- a/engines/sword1/objectman.h +++ b/engines/sword1/objectman.h @@ -62,7 +62,7 @@ private: uint16 _liveList[TOTAL_SECTIONS]; //which sections are active uint8 *_cptData[TOTAL_SECTIONS]; static char _missingSubTitleStr[]; - static const char *const _translationId2950145[7]; //translation for textId 2950145 (missing from cluster file for some langages) + static const char *const _translationId2950145[7]; //translation for textId 2950145 (missing from cluster file for some languages) static const char *const _translationId8455194[7]; //translation for textId 8455194 (missing in the demo) static const char *const _translationId8455195[7]; //translation for textId 8455195 (missing in the demo) static const char *const _translationId8455196[7]; //translation for textId 8455196 (missing in the demo) diff --git a/engines/sword1/router.cpp b/engines/sword1/router.cpp index 72c8440e1c..0c2e9569b6 100644 --- a/engines/sword1/router.cpp +++ b/engines/sword1/router.cpp @@ -1455,7 +1455,7 @@ int32 Router::newCheck(int32 status, int32 x1, int32 y1, int32 x2, int32 y2) { * newCheck differs from check in that that 4 route options are * considered corresponding to actual walked routes. * - * Note distance doesnt take account of shrinking ??? + * Note distance doesn't take account of shrinking ??? * * Note Bars array must be properly calculated ie min max dx dy co *********************************************************************/ diff --git a/engines/sword2/configure.engine b/engines/sword2/configure.engine index 7153605433..a794e7287c 100644 --- a/engines/sword2/configure.engine +++ b/engines/sword2/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine sword2 "Broken Sword II" yes +add_engine sword2 "Broken Sword II" yes "" "" "highres" diff --git a/engines/sword2/router.cpp b/engines/sword2/router.cpp index d3f274dd2c..e95fa367a0 100644 --- a/engines/sword2/router.cpp +++ b/engines/sword2/router.cpp @@ -1712,7 +1712,7 @@ int32 Router::newCheck(int32 status, int32 x1, int32 y1, int32 x2, int32 y2) { * newCheck differs from check in that that 4 route options are * considered corresponding to actual walked routes. * - * Note distance doesnt take account of shrinking ??? + * Note distance doesn't take account of shrinking ??? * * Note Bars array must be properly calculated ie min max dx dy co *********************************************************************/ diff --git a/engines/sword2/sword2.cpp b/engines/sword2/sword2.cpp index baedecb52f..44371bf6cf 100644 --- a/engines/sword2/sword2.cpp +++ b/engines/sword2/sword2.cpp @@ -234,7 +234,6 @@ SaveStateList Sword2MetaEngine::listSaves(const char *target) const { pattern += ".###"; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -252,6 +251,8 @@ SaveStateList Sword2MetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/sword25/POTFILES b/engines/sword25/POTFILES new file mode 100644 index 0000000000..f4b0e6fc27 --- /dev/null +++ b/engines/sword25/POTFILES @@ -0,0 +1 @@ +engines/sword25/detection.cpp diff --git a/engines/sword25/configure.engine b/engines/sword25/configure.engine index 6a9428c758..f805483f54 100644 --- a/engines/sword25/configure.engine +++ b/engines/sword25/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine sword25 "Broken Sword 2.5" yes "" "" "png zlib 16bit" +add_engine sword25 "Broken Sword 2.5" yes "" "" "png zlib 16bit highres" diff --git a/engines/sword25/detection.cpp b/engines/sword25/detection.cpp index df68d11609..4ca565c972 100644 --- a/engines/sword25/detection.cpp +++ b/engines/sword25/detection.cpp @@ -21,6 +21,7 @@ */ #include "base/plugins.h" +#include "common/translation.h" #include "engines/advancedDetector.h" #include "sword25/sword25.h" @@ -41,10 +42,17 @@ static const char *directoryGlobs[] = { 0 }; +static const ExtraGuiOption sword25ExtraGuiOption = { + _s("Use English speech"), + _s("Use English speech instead of German for every language other than German"), + "english_speech", + false +}; + class Sword25MetaEngine : public AdvancedMetaEngine { public: Sword25MetaEngine() : AdvancedMetaEngine(Sword25::gameDescriptions, sizeof(ADGameDescription), sword25Game) { - _guioptions = GUIO1(GUIO_NOMIDI); + _guiOptions = GUIO1(GUIO_NOMIDI); _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } @@ -58,6 +66,7 @@ public: virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; virtual bool hasFeature(MetaEngineFeature f) const; + virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const; virtual int getMaximumSaveSlot() const { return Sword25::PersistenceService::getSlotCount(); } virtual SaveStateList listSaves(const char *target) const; }; @@ -74,6 +83,12 @@ bool Sword25MetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSupportsListSaves); } +const ExtraGuiOptions Sword25MetaEngine::getExtraGuiOptions(const Common::String &target) const { + ExtraGuiOptions options; + options.push_back(sword25ExtraGuiOption); + return options; +} + SaveStateList Sword25MetaEngine::listSaves(const char *target) const { Common::String pattern = target; pattern = pattern + ".???"; diff --git a/engines/sword25/detection_tables.h b/engines/sword25/detection_tables.h index b58f430fcf..927060bf18 100644 --- a/engines/sword25/detection_tables.h +++ b/engines/sword25/detection_tables.h @@ -29,7 +29,7 @@ static const ADGameDescription gameDescriptions[] = { AD_ENTRY1s("data.b25c", "f8b6e03ada2d2f6cf27fbc11ad1572e9", 654310588), Common::EN_ANY, Common::kPlatformUnknown, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO1(GUIO_NOASPECT) }, { @@ -38,7 +38,7 @@ static const ADGameDescription gameDescriptions[] = { AD_ENTRY1s("lang_fr.b25c", "690caf157387e06d2c3d1ca53c43f428", 1006043), Common::FR_FRA, Common::kPlatformUnknown, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO1(GUIO_NOASPECT) }, { @@ -47,7 +47,7 @@ static const ADGameDescription gameDescriptions[] = { AD_ENTRY1s("data.b25c", "f8b6e03ada2d2f6cf27fbc11ad1572e9", 654310588), Common::DE_DEU, Common::kPlatformUnknown, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO1(GUIO_NOASPECT) }, { @@ -56,7 +56,7 @@ static const ADGameDescription gameDescriptions[] = { AD_ENTRY1s("lang_hr.b25c", "e881054d1f8ec1e527422fc521c25405", 1273217), Common::HR_HRV, Common::kPlatformUnknown, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO1(GUIO_NOASPECT) }, { @@ -65,7 +65,7 @@ static const ADGameDescription gameDescriptions[] = { AD_ENTRY1s("lang_it.b25c", "f3325666da0515cc2b42062e953c0889", 996197), Common::IT_ITA, Common::kPlatformUnknown, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO1(GUIO_NOASPECT) }, { @@ -74,7 +74,7 @@ static const ADGameDescription gameDescriptions[] = { AD_ENTRY1s("lang_pl.b25c", "49dc1a20f95391a808e475c49be2bac0", 1281799), Common::PL_POL, Common::kPlatformUnknown, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO1(GUIO_NOASPECT) }, { @@ -83,7 +83,7 @@ static const ADGameDescription gameDescriptions[] = { AD_ENTRY1s("lang_pt.b25c", "1df701432f9e13dcefe1adeb890b9c69", 993812), Common::PT_BRA, Common::kPlatformUnknown, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO1(GUIO_NOASPECT) }, { @@ -92,7 +92,7 @@ static const ADGameDescription gameDescriptions[] = { AD_ENTRY1s("lang_ru.b25c", "deb33dd2f90a71ff60181918a8ce5063", 1235378), Common::RU_RUS, Common::kPlatformUnknown, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO1(GUIO_NOASPECT) }, { @@ -101,7 +101,7 @@ static const ADGameDescription gameDescriptions[] = { AD_ENTRY1s("lang_es.b25c", "384c19072d83725f351bb9ecb4d3f02b", 987965), Common::ES_ESP, Common::kPlatformUnknown, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO1(GUIO_NOASPECT) }, // Hungarian "psylog" version. @@ -112,7 +112,7 @@ static const ADGameDescription gameDescriptions[] = { AD_ENTRY1s("lang_hu.b25c", "7de51a3b4926a192549e75b1a7d81667", 1864915), Common::HU_HUN, Common::kPlatformUnknown, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO1(GUIO_NOASPECT) }, @@ -126,19 +126,22 @@ static const ADGameDescription gameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformUnknown, - GF_EXTRACTED | ADGF_TESTING, + GF_EXTRACTED | ADGF_NO_FLAGS, GUIO1(GUIO_NOASPECT) }, // Distributed by ScummVM // Contains all language packs, English voice-overs and Hungarian version + // Mark it as Unknown Language since it contains multiple languages. If we + // mark it as English, then changing the language in-game causes the detection + // to fail the next time we try to start the engine. { "sword25", "Latest version", AD_ENTRY1s("data.b25c", "880a8a67faf4a4e7ab62cf114b771428", 827397764), - Common::EN_ANY, + Common::UNK_LANG, Common::kPlatformUnknown, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO1(GUIO_NOASPECT) }, 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/sword25/fmv/movieplayer.h b/engines/sword25/fmv/movieplayer.h index 95fb05ee60..b59b223b4c 100644 --- a/engines/sword25/fmv/movieplayer.h +++ b/engines/sword25/fmv/movieplayer.h @@ -67,7 +67,7 @@ public: * movie file, it will be unloaded and, if necessary, stopped playing. * @param Filename The filename of the movie file to be loaded * @param Z Z indicates the position of the film on the main graphics layer - * @return Returns false if an error occured while loading, otherwise true. + * @return Returns false if an error occurred while loading, otherwise true. */ bool loadMovie(const Common::String &filename, uint z); diff --git a/engines/sword25/gfx/animationresource.cpp b/engines/sword25/gfx/animationresource.cpp index 431d466658..423a2b86b4 100644 --- a/engines/sword25/gfx/animationresource.cpp +++ b/engines/sword25/gfx/animationresource.cpp @@ -211,8 +211,9 @@ bool AnimationResource::precacheAllFrames() const { error("Could not precache \"%s\".", (*iter).fileName.c_str()); return false; } -#else - Kernel::getInstance()->getResourceManager()->requestResource((*iter).fileName); +#else + Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource((*iter).fileName); + pResource->release(); //unlock precached resource #endif } diff --git a/engines/sword25/gfx/fontresource.cpp b/engines/sword25/gfx/fontresource.cpp index c4d4c3c52e..1d7aedcb6e 100644 --- a/engines/sword25/gfx/fontresource.cpp +++ b/engines/sword25/gfx/fontresource.cpp @@ -103,8 +103,9 @@ bool FontResource::parserCallback_font(ParserNode *node) { if (!_pKernel->getResourceManager()->precacheResource(_bitmapFileName)) { error("Could not precache \"%s\".", _bitmapFileName.c_str()); } -#else - _pKernel->getResourceManager()->requestResource(_bitmapFileName); +#else + Resource *pResource = _pKernel->getResourceManager()->requestResource(_bitmapFileName); + pResource->release(); //unlock precached resource #endif return true; diff --git a/engines/sword25/gfx/text.cpp b/engines/sword25/gfx/text.cpp index d409c538c0..769c9b1162 100644 --- a/engines/sword25/gfx/text.cpp +++ b/engines/sword25/gfx/text.cpp @@ -77,7 +77,8 @@ bool Text::setFont(const Common::String &font) { return false; } #else - getResourceManager()->requestResource(font); + Resource *pResource = getResourceManager()->requestResource(font); + pResource->release(); //unlock precached resource _font = font; updateFormat(); forceRefresh(); diff --git a/engines/sword25/kernel/kernel_script.cpp b/engines/sword25/kernel/kernel_script.cpp index 1b7c6a6f14..40dcbd5b98 100644 --- a/engines/sword25/kernel/kernel_script.cpp +++ b/engines/sword25/kernel/kernel_script.cpp @@ -257,6 +257,7 @@ static int processMessages(lua_State *L) { // to the closeWanted() opcode; see also the TODO comment in there. lua_pushbooleancpp(L, !Engine::shouldQuit()); + g_system->delayMillis(10); return 1; } diff --git a/engines/sword25/package/packagemanager.cpp b/engines/sword25/package/packagemanager.cpp index 2db4f2da74..457dda6268 100644 --- a/engines/sword25/package/packagemanager.cpp +++ b/engines/sword25/package/packagemanager.cpp @@ -56,7 +56,8 @@ static Common::String normalizePath(const Common::String &path, const Common::St PackageManager::PackageManager(Kernel *pKernel) : Service(pKernel), _currentDirectory(PATH_SEPARATOR), - _rootFolder(ConfMan.get("path")) { + _rootFolder(ConfMan.get("path")), + _useEnglishSpeech(ConfMan.getBool("english_speech")) { if (!registerScriptBindings()) error("Script bindings could not be registered."); else @@ -71,14 +72,34 @@ PackageManager::~PackageManager() { } +Common::String PackageManager::ensureSpeechLang(const Common::String &fileName) { + if (!_useEnglishSpeech || fileName.size() < 9 || !fileName.hasPrefix("/speech/")) + return fileName; + + // Always keep German speech as a fallback in case the English speech pack is not present. + // However this means we cannot play with German text and English voice. + if (fileName.hasPrefix("/speech/de")) + return fileName; + + Common::String newFileName = "/speech/en"; + int fileIdx = 9; + while (fileIdx < fileName.size() && fileName[fileIdx] != '/') + ++fileIdx; + if (fileIdx < fileName.size()) + newFileName += fileName.c_str() + fileIdx; + + return newFileName; +} + /** * Scans through the archive list for a specified file */ Common::ArchiveMemberPtr PackageManager::getArchiveMember(const Common::String &fileName) { + Common::String fileName2 = ensureSpeechLang(fileName); // Loop through checking each archive Common::List<ArchiveEntry *>::iterator i; for (i = _archiveList.begin(); i != _archiveList.end(); ++i) { - if (!fileName.hasPrefix((*i)->_mountPath)) { + if (!fileName2.hasPrefix((*i)->_mountPath)) { // The mount path is in different subtree. Skipping continue; } @@ -87,7 +108,7 @@ Common::ArchiveMemberPtr PackageManager::getArchiveMember(const Common::String & Common::Archive *archiveFolder = (*i)->archive; // Construct relative path - Common::String resPath(&fileName.c_str()[(*i)->_mountPath.size()]); + Common::String resPath(&fileName2.c_str()[(*i)->_mountPath.size()]); if (archiveFolder->hasFile(resPath)) { return archiveFolder->getMember(resPath); @@ -203,23 +224,29 @@ bool PackageManager::changeDirectory(const Common::String &directory) { } Common::String PackageManager::getAbsolutePath(const Common::String &fileName) { - return normalizePath(fileName, _currentDirectory); + return normalizePath(ensureSpeechLang(fileName), _currentDirectory); } bool PackageManager::fileExists(const Common::String &fileName) { // FIXME: The current Zip implementation doesn't support getting a folder entry, which is needed for detecting - // the English voick pack - if (fileName == "/speech/en") { + // the English voice pack + Common::String fileName2 = ensureSpeechLang(fileName); + if (fileName2 == "/speech/en") { // To get around this, change to detecting one of the files in the folder - return getArchiveMember(normalizePath(fileName + "/APO0001.ogg", _currentDirectory)); + bool exists = getArchiveMember(normalizePath(fileName2 + "/APO0001.ogg", _currentDirectory)); + if (!exists && _useEnglishSpeech) { + _useEnglishSpeech = false; + warning("English speech not found"); + } + return exists; } - Common::ArchiveMemberPtr fileNode = getArchiveMember(normalizePath(fileName, _currentDirectory)); + Common::ArchiveMemberPtr fileNode = getArchiveMember(normalizePath(fileName2, _currentDirectory)); return fileNode; } int PackageManager::doSearch(Common::ArchiveMemberList &list, const Common::String &filter, const Common::String &path, uint typeFilter) { - Common::String normalizedFilter = normalizePath(filter, _currentDirectory); + Common::String normalizedFilter = normalizePath(ensureSpeechLang(filter), _currentDirectory); int num = 0; if (path.size() > 0) diff --git a/engines/sword25/package/packagemanager.h b/engines/sword25/package/packagemanager.h index a1806a4046..5475cb02fc 100644 --- a/engines/sword25/package/packagemanager.h +++ b/engines/sword25/package/packagemanager.h @@ -87,6 +87,9 @@ private: Common::String _currentDirectory; Common::FSNode _rootFolder; Common::List<ArchiveEntry *> _archiveList; + + bool _useEnglishSpeech; + Common::String ensureSpeechLang(const Common::String &fileName); Common::ArchiveMemberPtr getArchiveMember(const Common::String &fileName); diff --git a/engines/sword25/script/luacallback.cpp b/engines/sword25/script/luacallback.cpp index 72f7e01612..acfda498c6 100644 --- a/engines/sword25/script/luacallback.cpp +++ b/engines/sword25/script/luacallback.cpp @@ -119,7 +119,7 @@ void LuaCallback::invokeCallbackFunctions(lua_State *L, uint objectHandle) { // Lua_pcall the function and the parameters pop themselves from the stack if (lua_pcall(L, argumentCount, 0, 0) != 0) { // An error has occurred - error("An error occured executing a callback function: %s", lua_tostring(L, -1)); + error("An error occurred executing a callback function: %s", lua_tostring(L, -1)); // Pop error message from the stack lua_pop(L, 1); diff --git a/engines/sword25/script/luascript.cpp b/engines/sword25/script/luascript.cpp index e93289596b..3aca6676ac 100644 --- a/engines/sword25/script/luascript.cpp +++ b/engines/sword25/script/luascript.cpp @@ -214,7 +214,7 @@ bool LuaScriptEngine::executeBuffer(const byte *data, uint size, const Common::S // Run buffer contents if (lua_pcall(_state, 0, 0, -2) != 0) { - error("An error occured while executing \"%s\":\n%s.", + error("An error occurred while executing \"%s\":\n%s.", name.c_str(), lua_tostring(_state, -1)); lua_pop(_state, 2); diff --git a/engines/sword25/sword25.cpp b/engines/sword25/sword25.cpp index 5223481d50..b6f2641714 100644 --- a/engines/sword25/sword25.cpp +++ b/engines/sword25/sword25.cpp @@ -120,7 +120,7 @@ Common::Error Sword25Engine::appStart() { // Pass the command line to the script engine. ScriptEngine *scriptPtr = Kernel::getInstance()->getScript(); if (!scriptPtr) { - error("Script intialization failed."); + error("Script initialization failed."); return Common::kUnknownError; } diff --git a/engines/sword25/util/lua/lbaselib.cpp b/engines/sword25/util/lua/lbaselib.cpp index 659c61d956..ec044970ad 100644 --- a/engines/sword25/util/lua/lbaselib.cpp +++ b/engines/sword25/util/lua/lbaselib.cpp @@ -492,7 +492,7 @@ static int costatus (lua_State *L, lua_State *co) { else return CO_SUS; /* initial state */ } - default: /* some error occured */ + default: /* some error occurred */ return CO_DEAD; } } diff --git a/engines/sword25/util/lua/ldo.cpp b/engines/sword25/util/lua/ldo.cpp index a230097f2a..f4139cb9fc 100644 --- a/engines/sword25/util/lua/ldo.cpp +++ b/engines/sword25/util/lua/ldo.cpp @@ -111,10 +111,9 @@ static const char* luaErrorDescription[] = { void luaD_throw (lua_State *L, int errcode) { if (L->errorJmp) { L->errorJmp->status = errcode; - // LUAI_THROW has been replaced with an error message in ScummVM, together - // with the LUA error code and description - //LUAI_THROW(L, L->errorJmp); - error("LUA error occured, error code is %d (%s)", errcode, luaErrorDescription[errcode]); + // LUAI_THROW is sometimes used to ignore the error and restore LUA state + LUAI_THROW(L, L->errorJmp); + error("LUA error occurred, error code is %d (%s)", errcode, luaErrorDescription[errcode]); } else { L->status = cast_byte(errcode); diff --git a/engines/sword25/util/lua/luaconf.h b/engines/sword25/util/lua/luaconf.h index fb85983998..53d0f55290 100644 --- a/engines/sword25/util/lua/luaconf.h +++ b/engines/sword25/util/lua/luaconf.h @@ -621,7 +621,7 @@ union luai_Cast { double l_d; long l_l; }; #else /* default handling with long jumps */ -//#define LUAI_THROW(L,c) longjmp((c)->b, 1) // replaced with error() in ScummVM +#define LUAI_THROW(L,c) longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf diff --git a/engines/teenagent/detection.cpp b/engines/teenagent/detection.cpp index 4fd3a06311..caa7bdbec9 100644 --- a/engines/teenagent/detection.cpp +++ b/engines/teenagent/detection.cpp @@ -88,7 +88,7 @@ enum { class TeenAgentMetaEngine : public AdvancedMetaEngine { public: TeenAgentMetaEngine() : AdvancedMetaEngine(teenAgentGameDescriptions, sizeof(ADGameDescription), teenAgentGames) { - _singleid = "teenagent"; + _singleId = "teenagent"; } virtual const char *getName() const { @@ -128,7 +128,6 @@ public: pattern += ".##"; Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles(pattern); - Common::sort(filenames.begin(), filenames.end()); SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -145,6 +144,8 @@ public: saveList.push_back(SaveStateDescriptor(slot, buf)); } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/testbed/detection.cpp b/engines/testbed/detection.cpp index 348ade62b0..7aff7a1805 100644 --- a/engines/testbed/detection.cpp +++ b/engines/testbed/detection.cpp @@ -49,7 +49,7 @@ class TestbedMetaEngine : public AdvancedMetaEngine { public: TestbedMetaEngine() : AdvancedMetaEngine(testbedDescriptions, sizeof(ADGameDescription), testbed_setting) { _md5Bytes = 512; - _singleid = "testbed"; + _singleId = "testbed"; } virtual const char *getName() const { diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp index 7cb291275c..2fde6e788a 100644 --- a/engines/tinsel/detection.cpp +++ b/engines/tinsel/detection.cpp @@ -85,7 +85,7 @@ static const PlainGameDescriptor tinselGames[] = { class TinselMetaEngine : public AdvancedMetaEngine { public: TinselMetaEngine() : AdvancedMetaEngine(Tinsel::gameDescriptions, sizeof(Tinsel::TinselGameDescription), tinselGames) { - _singleid = "tinsel"; + _singleId = "tinsel"; } virtual const char *getName() const { @@ -136,7 +136,6 @@ SaveStateList TinselMetaEngine::listSaves(const char *target) const { Common::String pattern = target; pattern = pattern + ".###"; Common::StringArray files = g_system->getSavefileManager()->listSavefiles(pattern); - sort(files.begin(), files.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; int slotNum = 0; @@ -160,6 +159,8 @@ SaveStateList TinselMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } @@ -227,8 +228,8 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFile // Check which files are included in some dw2 ADGameDescription *and* present // in fslist without a '1' suffix character. Compute MD5s and file sizes for these files. - for (g = &Tinsel::gameDescriptions[0]; g->desc.gameid != 0; ++g) { - if (strcmp(g->desc.gameid, "dw2") != 0) + for (g = &Tinsel::gameDescriptions[0]; g->desc.gameId != 0; ++g) { + if (strcmp(g->desc.gameId, "dw2") != 0) continue; for (fileDesc = g->desc.filesDescriptions; fileDesc->fileName; fileDesc++) { @@ -264,8 +265,8 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFile int maxFilesMatched = 0; // MD5 based matching - for (g = &Tinsel::gameDescriptions[0]; g->desc.gameid != 0; ++g) { - if (strcmp(g->desc.gameid, "dw2") != 0) + for (g = &Tinsel::gameDescriptions[0]; g->desc.gameId != 0; ++g) { + if (strcmp(g->desc.gameId, "dw2") != 0) continue; bool fileMissing = false; diff --git a/engines/tinsel/graphics.cpp b/engines/tinsel/graphics.cpp index 0282aff3cb..2ff96a9b64 100644 --- a/engines/tinsel/graphics.cpp +++ b/engines/tinsel/graphics.cpp @@ -164,7 +164,7 @@ static void t0WrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool apply // Horizontal loop for (int x = 0; x < pObj->width; ) { - uint32 numBytes = READ_UINT32(srcP); + uint32 numBytes = READ_LE_UINT32(srcP); srcP += sizeof(uint32); bool repeatFlag = (numBytes & 0x80000000L) != 0; numBytes &= 0x7fffffff; diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp index 2a9804263a..e0c1f8d1f9 100644 --- a/engines/tinsel/music.cpp +++ b/engines/tinsel/music.cpp @@ -381,11 +381,25 @@ MidiMusicPlayer::MidiMusicPlayer(TinselEngine *vm) { bool milesAudioEnabled = false; if (vm->getPlatform() == Common::kPlatformDOS) { - // Enable Miles Audio for DOS only - milesAudioEnabled = true; + // Enable Miles Audio for DOS platform only... + switch (vm->getGameID()) { + case GID_DW1: + if (!vm->getIsADGFDemo()) { + // ...for Discworld 1 + milesAudioEnabled = true; + } else { + if (vm->isV1CD()) { + // ...and for Discworld 1 CD Demo + milesAudioEnabled = true; + } + } + break; + default: + break; + } } - if ((vm->getGameId() == GID_DW1) && (milesAudioEnabled)) { + if (milesAudioEnabled) { // Discworld 1 (DOS) uses Miles Audio 3 // use our own Miles Audio drivers // diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index 77932a5cdf..2adddca4fd 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -820,7 +820,7 @@ const char *const TinselEngine::_textFiles[][3] = { TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc), _random("tinsel"), - _sound(0), _midiMusic(0), _pcmMusic(0), _bmv(0) { + _console(0), _sound(0), _midiMusic(0), _pcmMusic(0), _bmv(0) { _vm = this; _config = new Config(this); diff --git a/engines/toltecs/configure.engine b/engines/toltecs/configure.engine index be5533efa2..8310a6d6ef 100644 --- a/engines/toltecs/configure.engine +++ b/engines/toltecs/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine toltecs "3 Skulls of the Toltecs" yes +add_engine toltecs "3 Skulls of the Toltecs" yes "" "" "highres" diff --git a/engines/toltecs/detection.cpp b/engines/toltecs/detection.cpp index fb7d8121ff..7c707895e6 100644 --- a/engines/toltecs/detection.cpp +++ b/engines/toltecs/detection.cpp @@ -206,7 +206,7 @@ static const ExtraGuiOption toltecsExtraGuiOption = { class ToltecsMetaEngine : public AdvancedMetaEngine { public: ToltecsMetaEngine() : AdvancedMetaEngine(Toltecs::gameDescriptions, sizeof(Toltecs::ToltecsGameDescription), toltecsGames) { - _singleid = "toltecs"; + _singleId = "toltecs"; } virtual const char *getName() const { @@ -266,7 +266,6 @@ SaveStateList ToltecsMetaEngine::listSaves(const char *target) const { Common::StringArray filenames; filenames = saveFileMan->listSavefiles(pattern.c_str()); - Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -284,6 +283,8 @@ SaveStateList ToltecsMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/tony/configure.engine b/engines/tony/configure.engine index f85f45d158..2df4434982 100644 --- a/engines/tony/configure.engine +++ b/engines/tony/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine tony "Tony Tough and the Night of Roasted Moths" yes "" "" "16bit" +add_engine tony "Tony Tough and the Night of Roasted Moths" yes "" "" "16bit highres" diff --git a/engines/tony/detection.cpp b/engines/tony/detection.cpp index 2f05c0abea..ec0b3e186b 100644 --- a/engines/tony/detection.cpp +++ b/engines/tony/detection.cpp @@ -118,7 +118,6 @@ SaveStateList TonyMetaEngine::listSaves(const char *target) const { Common::String pattern = "tony.0##"; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -137,6 +136,8 @@ SaveStateList TonyMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/toon/POTFILES b/engines/toon/POTFILES new file mode 100644 index 0000000000..5bdfa37e5f --- /dev/null +++ b/engines/toon/POTFILES @@ -0,0 +1 @@ +engines/toon/toon.cpp diff --git a/engines/toon/configure.engine b/engines/toon/configure.engine index 00c98f7d8a..689bce1c02 100644 --- a/engines/toon/configure.engine +++ b/engines/toon/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine toon "Toonstruck" yes +add_engine toon "Toonstruck" yes "" "" "highres" diff --git a/engines/toon/detection.cpp b/engines/toon/detection.cpp index e38ae3d2f5..5d2e0a9bca 100644 --- a/engines/toon/detection.cpp +++ b/engines/toon/detection.cpp @@ -127,7 +127,7 @@ static const char * const directoryGlobs[] = { class ToonMetaEngine : public AdvancedMetaEngine { public: ToonMetaEngine() : AdvancedMetaEngine(Toon::gameDescriptions, sizeof(ADGameDescription), toonGames) { - _singleid = "toon"; + _singleId = "toon"; _maxScanDepth = 3; _directoryGlobs = directoryGlobs; } @@ -176,7 +176,6 @@ SaveStateList ToonMetaEngine::listSaves(const char *target) const { pattern += ".###"; filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) { @@ -208,6 +207,8 @@ SaveStateList ToonMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp index 9e2905f454..3ab23a1e51 100644 --- a/engines/toon/toon.cpp +++ b/engines/toon/toon.cpp @@ -27,6 +27,7 @@ #include "common/config-manager.h" #include "common/savefile.h" #include "common/memstream.h" +#include "common/translation.h" #include "engines/advancedDetector.h" #include "engines/util.h" @@ -3334,7 +3335,7 @@ bool ToonEngine::saveGame(int32 slot, const Common::String &saveGameDesc) { Common::String savegameDescription; if (slot == -1) { - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); savegameId = dialog->runModalWithCurrentTarget(); savegameDescription = dialog->getResultString(); delete dialog; @@ -3426,7 +3427,7 @@ bool ToonEngine::loadGame(int32 slot) { int16 savegameId; if (slot == -1) { - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false); savegameId = dialog->runModalWithCurrentTarget(); delete dialog; } else { diff --git a/engines/touche/configure.engine b/engines/touche/configure.engine index 777578e623..f35940ef47 100644 --- a/engines/touche/configure.engine +++ b/engines/touche/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine touche "Touche: The Adventures of the Fifth Musketeer" yes +add_engine touche "Touche: The Adventures of the Fifth Musketeer" yes "" "" "highres" diff --git a/engines/touche/detection.cpp b/engines/touche/detection.cpp index 1d0e136d69..dcb58ffae6 100644 --- a/engines/touche/detection.cpp +++ b/engines/touche/detection.cpp @@ -128,7 +128,7 @@ class ToucheMetaEngine : public AdvancedMetaEngine { public: ToucheMetaEngine() : AdvancedMetaEngine(Touche::gameDescriptions, sizeof(ADGameDescription), toucheGames) { _md5Bytes = 4096; - _singleid = "touche"; + _singleId = "touche"; _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } diff --git a/engines/tsage/blue_force/blueforce_dialogs.cpp b/engines/tsage/blue_force/blueforce_dialogs.cpp index 5be27c9ae7..3697ca700e 100644 --- a/engines/tsage/blue_force/blueforce_dialogs.cpp +++ b/engines/tsage/blue_force/blueforce_dialogs.cpp @@ -161,7 +161,7 @@ void RightClickDialog::execute() { } g_system->delayMillis(10); - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); } // Deactivate the graphics manager used for the dialog @@ -242,7 +242,7 @@ void AmmoBeltDialog::execute() { } g_system->delayMillis(10); - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); } _gfxManager.deactivate(); diff --git a/engines/tsage/blue_force/blueforce_logic.cpp b/engines/tsage/blue_force/blueforce_logic.cpp index e6e71399dc..2c5f9bd738 100644 --- a/engines/tsage/blue_force/blueforce_logic.cpp +++ b/engines/tsage/blue_force/blueforce_logic.cpp @@ -859,7 +859,7 @@ void SceneExt::endStrip() { } void SceneExt::clearScreen() { - BF_GLOBALS._screenSurface.fillRect(BF_GLOBALS._screenSurface.getBounds(), 0); + BF_GLOBALS._screen.clear(); } /*--------------------------------------------------------------------------*/ @@ -1411,7 +1411,7 @@ void SceneMessage::process(Event &event) { void SceneMessage::draw() { - GfxSurface &surface = BF_GLOBALS._screenSurface; + GfxSurface &surface = BF_GLOBALS._screen; // Clear the game area surface.fillRect(Rect(0, 0, SCREEN_WIDTH, UI_INTERFACE_Y), 0); diff --git a/engines/tsage/blue_force/blueforce_scenes6.cpp b/engines/tsage/blue_force/blueforce_scenes6.cpp index 92534d3095..0d6b5c2487 100644 --- a/engines/tsage/blue_force/blueforce_scenes6.cpp +++ b/engines/tsage/blue_force/blueforce_scenes6.cpp @@ -78,7 +78,7 @@ void Scene600::Action1::signal() { pObj->animate(ANIM_MODE_NONE, NULL); } - BF_GLOBALS._screenSurface.fillRect(BF_GLOBALS._screenSurface.getBounds(), 0); + BF_GLOBALS._screen.fillRect(BF_GLOBALS._screen.getBounds(), 0); scene->loadScene(999); setDelay(5); break; @@ -275,7 +275,7 @@ void Scene666::postInit(SceneObjectList *OwnerList) { SceneExt::postInit(); BF_GLOBALS._interfaceY = SCREEN_HEIGHT; loadScene(999); - BF_GLOBALS._screenSurface.fillRect(BF_GLOBALS._screenSurface.getBounds(), 0); + BF_GLOBALS._screen.fillRect(BF_GLOBALS._screen.getBounds(), 0); if (BF_GLOBALS._dayNumber == 0) { BF_GLOBALS._dayNumber = 1; diff --git a/engines/tsage/converse.cpp b/engines/tsage/converse.cpp index d1faca5dac..7240c91720 100644 --- a/engines/tsage/converse.cpp +++ b/engines/tsage/converse.cpp @@ -469,7 +469,7 @@ int ConversationChoiceDialog::execute(const Common::StringArray &choiceList) { while (!g_globals->_events.getEvent(event, EVENT_KEYPRESS | EVENT_BUTTON_DOWN | EVENT_MOUSE_MOVE) && !g_vm->shouldQuit()) { g_system->delayMillis(10); - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); } if (g_vm->shouldQuit()) break; diff --git a/engines/tsage/core.cpp b/engines/tsage/core.cpp index d4068c25c9..985d16b031 100644 --- a/engines/tsage/core.cpp +++ b/engines/tsage/core.cpp @@ -1467,7 +1467,7 @@ void ScenePalette::fade(const byte *adjustData, bool fullAdjust, int percent) { // Set the altered palette g_system->getPaletteManager()->setPalette((const byte *)&tempPalette[0], 0, 256); - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); } PaletteRotation *ScenePalette::addRotation(int start, int end, int rotationMode, int duration, Action *action) { @@ -1524,11 +1524,11 @@ void ScenePalette::changeBackground(const Rect &bounds, FadeMode fadeMode) { if (g_vm->getGameID() != GType_Ringworld && g_vm->getGameID() != GType_Sherlock1) tempRect.setHeight(T2_GLOBALS._interfaceY); - g_globals->_screenSurface.copyFrom(g_globals->_sceneManager._scene->_backSurface, + g_globals->_screen.copyFrom(g_globals->_sceneManager._scene->_backSurface, tempRect, Rect(0, 0, tempRect.width(), tempRect.height()), NULL); if (g_vm->getGameID() == GType_Ringworld2 && !GLOBALS._player._uiEnabled && T2_GLOBALS._interfaceY == UI_INTERFACE_Y) { - g_globals->_screenSurface.fillRect(Rect(0, UI_INTERFACE_Y, SCREEN_WIDTH, SCREEN_HEIGHT - 1), 0); + g_globals->_screen.fillRect(Rect(0, UI_INTERFACE_Y, SCREEN_WIDTH, SCREEN_HEIGHT - 1), 0); } for (SynchronizedList<PaletteModifier *>::iterator i = tempPalette._listeners.begin(); i != tempPalette._listeners.end(); ++i) @@ -1796,7 +1796,7 @@ void SceneItem::display(int resNum, int lineNum, ...) { // Keep event on-screen until a mouse or keypress while (!g_vm->shouldQuit() && !g_globals->_events.getEvent(event, EVENT_BUTTON_DOWN | EVENT_KEYPRESS)) { - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); g_system->delayMillis(10); if ((g_vm->getGameID() == GType_Ringworld2) && (R2_GLOBALS._speechSubtitles & SPEECH_VOICE)) { @@ -2816,7 +2816,7 @@ void SceneObject::updateScreen() { destRect.translate(-sceneBounds.left, -sceneBounds.top); srcRect.translate(-g_globals->_sceneOffset.x, -g_globals->_sceneOffset.y); - g_globals->_screenSurface.copyFrom(g_globals->_sceneManager._scene->_backSurface, srcRect, destRect); + g_globals->_screen.copyFrom(g_globals->_sceneManager._scene->_backSurface, srcRect, destRect); } } diff --git a/engines/tsage/detection.cpp b/engines/tsage/detection.cpp index f85d8433f3..fe555f2fdb 100644 --- a/engines/tsage/detection.cpp +++ b/engines/tsage/detection.cpp @@ -40,7 +40,7 @@ struct tSageGameDescription { }; const char *TSageEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } uint32 TSageEngine::getGameID() const { @@ -75,7 +75,7 @@ enum { class TSageMetaEngine : public AdvancedMetaEngine { public: TSageMetaEngine() : AdvancedMetaEngine(TsAGE::gameDescriptions, sizeof(TsAGE::tSageGameDescription), tSageGameTitles) { - _singleid = "tsage"; + _singleId = "tsage"; } virtual const char *getName() const { @@ -117,7 +117,6 @@ public: pattern += ".###"; Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); TsAGE::tSageSavegameHeader header; SaveStateList saveList; @@ -141,6 +140,8 @@ public: } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/tsage/detection_tables.h b/engines/tsage/detection_tables.h index 109ac353e6..f331ecdab5 100644 --- a/engines/tsage/detection_tables.h +++ b/engines/tsage/detection_tables.h @@ -165,7 +165,7 @@ static const tSageGameDescription gameDescriptions[] = { AD_ENTRY1s("r2rw.rlb", "df6c25622387007788ca36d99362c1f0", 47586928), Common::EN_ANY, Common::kPlatformDOS, - ADGF_CD | ADGF_TESTING, + ADGF_CD, GUIO0() }, GType_Ringworld2, @@ -179,7 +179,7 @@ static const tSageGameDescription gameDescriptions[] = { AD_ENTRY1s("r2rw.rlb", "c8e1a82c67c3caf57368eadde13dc15f", 32384464), Common::EN_ANY, Common::kPlatformDOS, - ADGF_CD | ADGF_TESTING, + ADGF_CD, GUIO0() }, GType_Ringworld2, diff --git a/engines/tsage/events.cpp b/engines/tsage/events.cpp index 0491c043a4..1fa17022de 100644 --- a/engines/tsage/events.cpp +++ b/engines/tsage/events.cpp @@ -50,7 +50,7 @@ bool EventsClass::pollEvent() { ++_frameNumber; // Update screen - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); } if (!g_system->getEventManager()->pollEvent(_event)) return false; @@ -400,7 +400,7 @@ void EventsClass::delay(int numFrames) { _priorFrameTime = g_system->getMillis(); } - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); _prevDelayFrame = _frameNumber; _priorFrameTime = g_system->getMillis(); } diff --git a/engines/tsage/globals.cpp b/engines/tsage/globals.cpp index b880f35007..b95bea3b23 100644 --- a/engines/tsage/globals.cpp +++ b/engines/tsage/globals.cpp @@ -59,7 +59,7 @@ static SavedObject *classFactoryProc(const Common::String &className) { /*--------------------------------------------------------------------------*/ -Globals::Globals() : _dialogCenter(160, 140), _gfxManagerInstance(_screenSurface), +Globals::Globals() : _dialogCenter(160, 140), _gfxManagerInstance(_screen), _randomSource("tsage"), _color1(0), _color2(255), _color3(255) { reset(); _stripNum = 0; @@ -119,7 +119,7 @@ Globals::Globals() : _dialogCenter(160, 140), _gfxManagerInstance(_screenSurface _color3 = 4; _dialogCenter.y = 100; } - _screenSurface.setScreenSurface(); + _gfxManagers.push_back(&_gfxManagerInstance); _sceneObjects = &_sceneObjectsInstance; diff --git a/engines/tsage/globals.h b/engines/tsage/globals.h index 1194fe8b9c..e1ebe261dc 100644 --- a/engines/tsage/globals.h +++ b/engines/tsage/globals.h @@ -30,6 +30,7 @@ #include "tsage/events.h" #include "tsage/sound.h" #include "tsage/saveload.h" +#include "tsage/screen.h" #include "tsage/user_interface.h" namespace TsAGE { @@ -38,7 +39,7 @@ class Globals : public SavedObject { private: static void dispatchSound(ASound *obj); public: - GfxSurface _screenSurface; + Screen _screen; GfxManager _gfxManagerInstance; Common::List<GfxManager *> _gfxManagers; SceneHandler *_sceneHandler; diff --git a/engines/tsage/graphics.cpp b/engines/tsage/graphics.cpp index 156503fb51..58fa5b8094 100644 --- a/engines/tsage/graphics.cpp +++ b/engines/tsage/graphics.cpp @@ -229,123 +229,43 @@ void Rect::synchronize(Serializer &s) { /*--------------------------------------------------------------------------*/ -GfxSurface::GfxSurface() : _bounds(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) { +GfxSurface::GfxSurface() : Graphics::ManagedSurface(), _bounds(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) { _disableUpdates = false; _lockSurfaceCtr = 0; - _customSurface = NULL; _transColor = -1; - _trackDirtyRects = false; _flags = 0; } -GfxSurface::GfxSurface(const GfxSurface &s) { +GfxSurface::GfxSurface(const GfxSurface &s): Graphics::ManagedSurface() { _lockSurfaceCtr = 0; - _customSurface = NULL; - _trackDirtyRects = false; - *this = s; + + operator=(s); } GfxSurface::~GfxSurface() { - clear(); + // Sanity check.. GfxSurface should always be just referencing _rawSurface, + // and not directly managing it's own surface + assert(disposeAfterUse() == DisposeAfterUse::NO); } -void GfxSurface::clear() { - if (_customSurface) { - _customSurface->free(); - delete _customSurface; - _customSurface = NULL; - } -} - -/** - * Specifies that the surface will encapsulate the ScummVM screen surface - */ -void GfxSurface::setScreenSurface() { - _trackDirtyRects = true; - create(SCREEN_WIDTH, SCREEN_HEIGHT); -} - -/** - * Updates the physical screen with the screen surface buffer - */ -void GfxSurface::updateScreen() { - assert(_trackDirtyRects); - - // Merge any overlapping dirty rects - mergeDirtyRects(); - - // Loop through the dirty rect list to copy the affected areas to the sc - for (Common::List<Rect>::iterator i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i) { - Rect r = *i; - - // Make sure that there is something to update. If not, skip this - // rectangle. An example case is the speedbike closeup at the beginning - // of Ringworld (third screen). - if (r.isEmpty()) - continue; - - const byte *srcP = (const byte *)_customSurface->getBasePtr(r.left, r.top); - g_system->copyRectToScreen(srcP, _customSurface->pitch, r.left, r.top, - r.width(), r.height()); - } - - // Update the physical screen - g_system->updateScreen(); - - // Now that the dirty rects have been copied, clear the dirty rect list - _dirtyRects.clear(); -} +void GfxSurface::create(uint16 width, uint16 height) { + free(); -/** - * Adds a rect to the dirty rect list - */ -void GfxSurface::addDirtyRect(const Rect &r) { - if (_trackDirtyRects) { - // Get the bounds and adjust to allow for sub-screen areas - Rect r2 = r; - r2.translate(_bounds.left, _bounds.top); - - // Add to the dirty rect list - r2.right = MIN(r2.right + 1, SCREEN_WIDTH); - r2.bottom = MIN(r2.bottom + 1, SCREEN_HEIGHT); - - if (r2.isValidRect()) - _dirtyRects.push_back(r2); - } + _rawSurface.create(width, height); + setBounds(Rect(0, 0, width, height)); } - - -/** - * Specifies that the surface should maintain it's own internal surface - */ -void GfxSurface::create(int width, int height) { - assert((width >= 0) && (height >= 0)); - - if (_customSurface) { - _customSurface->free(); - delete _customSurface; - } - _customSurface = new Graphics::Surface(); - _customSurface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); - Common::fill((byte *)_customSurface->getPixels(), (byte *)_customSurface->getBasePtr(0, height), 0); - _bounds = Rect(0, 0, width, height); +void GfxSurface::setBounds(const Rect &bounds) { + _bounds = bounds; + Graphics::ManagedSurface::create(_rawSurface, bounds); } /** * Locks the surface for access, and returns a raw ScummVM surface to manipulate it */ -Graphics::Surface GfxSurface::lockSurface() { +Graphics::ManagedSurface &GfxSurface::lockSurface() { ++_lockSurfaceCtr; - - Graphics::Surface *src = _customSurface; - assert(src); - - // Setup the returned surface either as one pointing to the same pixels as the source, or - // as a subset of the source one based on the currently set bounds - Graphics::Surface result; - result.init(_bounds.width(), _bounds.height(), src->pitch, src->getBasePtr(_bounds.left, _bounds.top), src->format); - return result; + return *this; } /** @@ -367,69 +287,43 @@ void GfxSurface::synchronize(Serializer &s) { if (s.isSaving()) { // Save contents of the surface - if (_customSurface) { - s.syncAsSint16LE(_customSurface->w); - s.syncAsSint16LE(_customSurface->h); - s.syncBytes((byte *)_customSurface->getPixels(), _customSurface->w * _customSurface->h); + if (disposeAfterUse() == DisposeAfterUse::YES) { + s.syncAsSint16LE(this->w); + s.syncAsSint16LE(this->h); + s.syncBytes((byte *)getPixels(), this->w * this->h); } else { int zero = 0; s.syncAsSint16LE(zero); s.syncAsSint16LE(zero); } } else { - int w = 0, h = 0; - s.syncAsSint16LE(w); - s.syncAsSint16LE(h); - - if ((w == 0) || (h == 0)) { - if (_customSurface) - delete _customSurface; - _customSurface = NULL; + int xSize = 0, ySize = 0; + s.syncAsSint16LE(xSize); + s.syncAsSint16LE(ySize); + + if (xSize == 0 || ySize == 0) { + free(); } else { - create(w, h); - s.syncBytes((byte *)_customSurface->getPixels(), w * h); + create(xSize, ySize); + s.syncBytes((byte *)getPixels(), xSize * ySize); } } } -/** - * Fills a specified rectangle on the surface with the specified color - * - * @bounds Area to fill - * @color Color to use - */ -void GfxSurface::fillRect(const Rect &bounds, int color) { - Graphics::Surface surface = lockSurface(); - surface.fillRect(bounds, color); - unlockSurface(); - addDirtyRect(bounds); -} - GfxSurface &GfxSurface::operator=(const GfxSurface &s) { assert(_lockSurfaceCtr == 0); assert(s._lockSurfaceCtr == 0); - if (_customSurface) { - _customSurface->free(); - delete _customSurface; - } - - _customSurface = s._customSurface; _disableUpdates = s._disableUpdates; _bounds = s._bounds; _centroid = s._centroid; _transColor = s._transColor; _flags = s._flags; - if (_customSurface) { - // Surface owns the internal data, so replicate it so new surface owns it's own - _customSurface = new Graphics::Surface(); - _customSurface->create(s._customSurface->w, s._customSurface->h, Graphics::PixelFormat::createFormatCLUT8()); - const byte *srcP = (const byte *)s._customSurface->getPixels(); - byte *destP = (byte *)_customSurface->getPixels(); - - Common::copy(srcP, srcP + (_bounds.width() * _bounds.height()), destP); - } + // Copy the source's surface + create(s.w, s.h); + blitFrom(s); + setBounds(s.getBounds()); return *this; } @@ -474,7 +368,7 @@ bool GfxSurface::displayText(const Common::String &msg, const Common::Point &pt) /** * Loads a quarter of a screen from a resource */ -void GfxSurface::loadScreenSection(Graphics::Surface &dest, int xHalf, int yHalf, int xSection, int ySection) { +void GfxSurface::loadScreenSection(Graphics::ManagedSurface &dest, int xHalf, int yHalf, int xSection, int ySection) { int screenNum = g_globals->_sceneManager._scene->_activeScreenNumber; Rect updateRect(0, 0, 160, 100); updateRect.translate(xHalf * 160, yHalf * 100); @@ -682,50 +576,6 @@ void GfxSurface::draw(const Common::Point &pt, Rect *rect) { } } -/** - * Merges any clipping rectangles that overlap to try and reduce - * the total number of clip rectangles. - */ -void GfxSurface::mergeDirtyRects() { - if (_dirtyRects.size() <= 1) - return; - - Common::List<Rect>::iterator rOuter, rInner; - - for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) { - rInner = rOuter; - while (++rInner != _dirtyRects.end()) { - - if ((*rOuter).intersects(*rInner)) { - // these two rectangles overlap or - // are next to each other - merge them - - unionRectangle(*rOuter, *rOuter, *rInner); - - // remove the inner rect from the list - _dirtyRects.erase(rInner); - - // move back to beginning of list - rInner = rOuter; - } - } - } -} - -/** - * Creates the union of two rectangles. - * Returns True if there is a union. - * @param pDest destination rectangle that is to receive the new union - * @param pSrc1 a source rectangle - * @param pSrc2 a source rectangle - */ -bool GfxSurface::unionRectangle(Common::Rect &destRect, const Rect &src1, const Rect &src2) { - destRect = src1; - destRect.extend(src2); - - return !destRect.isEmpty(); -} - /*--------------------------------------------------------------------------*/ GfxElement::GfxElement() { @@ -762,17 +612,16 @@ void GfxElement::highlight() { Rect tempRect(_bounds); tempRect.collapse(g_globals->_gfxEdgeAdjust - 1, g_globals->_gfxEdgeAdjust - 1); - for (int yp = tempRect.top; yp < tempRect.bottom; ++yp) { - byte *lineP = (byte *)surface.getBasePtr(tempRect.left, yp); - for (int xp = tempRect.left; xp < tempRect.right; ++xp, ++lineP) { + Graphics::Surface dest = surface.getSubArea(tempRect); + + for (int yp = 0; yp < dest.h; ++yp) { + byte *lineP = (byte *)dest.getBasePtr(0, yp); + for (int xp = 0; xp < tempRect.right; ++xp, ++lineP) { if (*lineP == _colors.background) *lineP = _colors.foreground; else if (*lineP == _colors.foreground) *lineP = _colors.background; } } - // Mark the affected area as dirty - gfxManager.getSurface().addDirtyRect(tempRect); - // Release the surface gfxManager.unlockSurface(); } @@ -816,10 +665,11 @@ void GfxElement::drawFrame() { // Loop through the surface area to replace each pixel // with its proper shaded replacement - Graphics::Surface surface = gfxManager.lockSurface(); - for (int y = tempRect.top; y < tempRect.bottom; ++y) { - byte *lineP = (byte *)surface.getBasePtr(tempRect.left, y); - for (int x = 0; x < tempRect.width(); ++x) { + Graphics::Surface dest = gfxManager.getSurface().getSubArea(tempRect); + + for (int y = 0; y < dest.h; ++y) { + byte *lineP = (byte *)dest.getBasePtr(0, y); + for (int x = 0; x < dest.w; ++x) { *lineP = transList[*lineP]; lineP++; } @@ -827,27 +677,24 @@ void GfxElement::drawFrame() { // Draw the edge frame // Outer frame border - surface.hLine(tempRect.left + 2, tempRect.top, tempRect.right - 2, 0); - surface.hLine(tempRect.left + 2, tempRect.bottom, tempRect.right - 2, 0); - surface.vLine(tempRect.left, tempRect.top + 2, tempRect.bottom - 2, 0); - surface.vLine(tempRect.right, tempRect.top + 2, tempRect.bottom - 2, 0); - *((byte *)surface.getBasePtr(tempRect.left + 1, tempRect.top + 1)) = 0; - *((byte *)surface.getBasePtr(tempRect.right - 1, tempRect.top + 1)) = 0; - *((byte *)surface.getBasePtr(tempRect.left + 1, tempRect.bottom - 1)) = 0; - *((byte *)surface.getBasePtr(tempRect.right - 1, tempRect.bottom - 1)) = 0; + dest.hLine(2, 0, dest.w - 2, 0); + dest.hLine(2, dest.h - 1, dest.w - 2, 0); + dest.vLine(0, 2, dest.h - 2, 0); + dest.vLine(tempRect.right, 2, dest.h - 2, 0); + *((byte *)dest.getBasePtr(1, 1)) = 0; + *((byte *)dest.getBasePtr(dest.w - 1, 1)) = 0; + *((byte *)dest.getBasePtr(1, dest.h - 1)) = 0; + *((byte *)dest.getBasePtr(dest.w - 1, dest.h - 1)) = 0; // Inner frame border - surface.hLine(tempRect.left + 2, tempRect.top + 1, tempRect.right - 2, R2_GLOBALS._frameEdgeColor); - surface.hLine(tempRect.left + 2, tempRect.bottom - 1, tempRect.right - 2, R2_GLOBALS._frameEdgeColor); - surface.vLine(tempRect.left + 1, tempRect.top + 2, tempRect.bottom - 2, R2_GLOBALS._frameEdgeColor); - surface.vLine(tempRect.right - 1, tempRect.top + 2, tempRect.bottom - 2, R2_GLOBALS._frameEdgeColor); - *((byte *)surface.getBasePtr(tempRect.left + 2, tempRect.top + 2)) = R2_GLOBALS._frameEdgeColor; - *((byte *)surface.getBasePtr(tempRect.right - 2, tempRect.top + 2)) = R2_GLOBALS._frameEdgeColor; - *((byte *)surface.getBasePtr(tempRect.left + 2, tempRect.bottom - 2)) = R2_GLOBALS._frameEdgeColor; - *((byte *)surface.getBasePtr(tempRect.right - 2, tempRect.bottom - 2)) = R2_GLOBALS._frameEdgeColor; - - gfxManager.unlockSurface(); - gfxManager.getSurface().addDirtyRect(tempRect); + dest.hLine(2, 1, dest.w - 2, R2_GLOBALS._frameEdgeColor); + dest.hLine(2, dest.h - 1, dest.w - 2, R2_GLOBALS._frameEdgeColor); + dest.vLine(1, 2, dest.h - 2, R2_GLOBALS._frameEdgeColor); + dest.vLine(dest.w - 1, 2, dest.h - 2, R2_GLOBALS._frameEdgeColor); + *((byte *)dest.getBasePtr(2, 2)) = R2_GLOBALS._frameEdgeColor; + *((byte *)dest.getBasePtr(dest.w - 2, 2)) = R2_GLOBALS._frameEdgeColor; + *((byte *)dest.getBasePtr(2, dest.h - 2)) = R2_GLOBALS._frameEdgeColor; + *((byte *)dest.getBasePtr(dest.w - 2, dest.h - 2)) = R2_GLOBALS._frameEdgeColor; } else { // Fill dialog content with specified background color @@ -1236,7 +1083,7 @@ GfxButton *GfxDialog::execute(GfxButton *defaultButton) { } g_system->delayMillis(10); - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); } _gfxManager.deactivate(); @@ -1269,7 +1116,7 @@ void GfxDialog::setPalette() { /*--------------------------------------------------------------------------*/ -GfxManager::GfxManager() : _surface(g_globals->_screenSurface), _oldManager(NULL) { +GfxManager::GfxManager() : _surface(g_globals->_screen), _oldManager(NULL) { _font.setOwner(this); _font._fillFlag = false; _bounds = Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); @@ -1563,23 +1410,24 @@ int GfxFont::writeChar(const char ch) { int yOffset = (_fontData[charOffset + 1] >> 3) & 0x1f; const uint8 *dataP = &_fontData[charOffset + 2]; - // Lock the surface for access - Graphics::Surface surfacePtr = _gfxManager->lockSurface(); - Rect charRect; charRect.set(0, 0, charWidth, _fontSize.y); charRect.translate(_topLeft.x + _position.x, _topLeft.y + _position.y + yOffset); + // Get the sub-section of the screen to update + Graphics::Surface dest = _gfxManager->getSurface().getSubArea(charRect); + if (_fillFlag) - surfacePtr.fillRect(charRect, _colors.background); + dest.fillRect(charRect, _colors.background); charRect.bottom = charRect.top + charHeight; + assert(charRect.height() <= dest.h); // Display the character int bitCtr = 0; uint8 v = 0; - for (int yp = charRect.top; yp < charRect.bottom; ++yp) { - byte *destP = (byte *)surfacePtr.getBasePtr(charRect.left, yp); + for (int yp = 0; yp < charHeight; ++yp) { + byte *destP = (byte *)dest.getBasePtr(0, yp); for (int xs = 0; xs < charRect.width(); ++xs, ++destP) { // Get the next color index to use @@ -1599,13 +1447,9 @@ int GfxFont::writeChar(const char ch) { } } - // Mark the affected area as dirty - _gfxManager->getSurface().addDirtyRect(charRect); - // Move the text writing position _position.x += charWidth; - _gfxManager->unlockSurface(); return charWidth; } diff --git a/engines/tsage/graphics.h b/engines/tsage/graphics.h index 25f7aea8cd..3b395b7625 100644 --- a/engines/tsage/graphics.h +++ b/engines/tsage/graphics.h @@ -28,7 +28,7 @@ #include "common/list.h" #include "common/rect.h" #include "common/system.h" -#include "graphics/surface.h" +#include "graphics/managed_surface.h" namespace TsAGE { @@ -73,20 +73,13 @@ public: enum FrameFlag { FRAME_FLIP_CENTROID_X = 4, FRAME_FLIP_CENTROID_Y = 8 }; -class GfxSurface { +class GfxSurface: virtual public Graphics::ManagedSurface { private: - Graphics::Surface *_customSurface; int _lockSurfaceCtr; + Graphics::ManagedSurface _rawSurface; bool _disableUpdates; Rect _bounds; - - bool _trackDirtyRects; - Common::List<Rect> _dirtyRects; - - void mergeDirtyRects(); - bool unionRectangle(Common::Rect &destRect, const Rect &src1, const Rect &src2); - public: Common::Point _centroid; int _transColor; @@ -95,17 +88,13 @@ public: public: GfxSurface(); GfxSurface(const GfxSurface &s); - ~GfxSurface(); + virtual ~GfxSurface(); - void setScreenSurface(); - void updateScreen(); - void addDirtyRect(const Rect &r); - Graphics::Surface lockSurface(); + Graphics::ManagedSurface &lockSurface(); void unlockSurface(); void synchronize(Serializer &s); - void create(int width, int height); - void clear(); - void setBounds(const Rect &bounds) { _bounds = bounds; } + virtual void create(uint16 width, uint16 height); + void setBounds(const Rect &bounds); const Rect &getBounds() const { return _bounds; } void copyFrom(GfxSurface &src, Rect srcBounds, Rect destBounds, @@ -119,10 +108,9 @@ public: copyFrom(src, tempRect, priorityRegion); } void draw(const Common::Point &pt, Rect *rect = NULL); - void fillRect(const Rect &bounds, int color); GfxSurface &operator=(const GfxSurface &s); - static void loadScreenSection(Graphics::Surface &dest, int xHalf, int yHalf, int xSection, int ySection); + static void loadScreenSection(Graphics::ManagedSurface &dest, int xHalf, int yHalf, int xSection, int ySection); static bool displayText(const Common::String &msg, const Common::Point &pt = Common::Point(160, 100)); }; @@ -281,7 +269,7 @@ public: void getStringBounds(const char *s, Rect &bounds, int maxWidth); void setDialogPalette(); - Graphics::Surface lockSurface() { + Graphics::ManagedSurface lockSurface() { _surface.setBounds(_bounds); return _surface.lockSurface(); } diff --git a/engines/tsage/module.mk b/engines/tsage/module.mk index e23b157a95..b58c748567 100644 --- a/engines/tsage/module.mk +++ b/engines/tsage/module.mk @@ -47,6 +47,7 @@ MODULE_OBJS := \ ringworld2/ringworld2_vampire.o \ saveload.o \ scenes.o \ + screen.o \ sherlock/sherlock_logo.o \ sound.o \ staticres.o \ diff --git a/engines/tsage/ringworld/ringworld_dialogs.cpp b/engines/tsage/ringworld/ringworld_dialogs.cpp index 1dd3bc158b..9fa17f3920 100644 --- a/engines/tsage/ringworld/ringworld_dialogs.cpp +++ b/engines/tsage/ringworld/ringworld_dialogs.cpp @@ -181,7 +181,7 @@ void RightClickDialog::execute() { } g_system->delayMillis(10); - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); } _gfxManager.deactivate(); @@ -391,7 +391,7 @@ void InventoryDialog::execute() { Event event; while (!g_globals->_events.getEvent(event) && !g_vm->shouldQuit()) { g_system->delayMillis(10); - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); } if (g_vm->shouldQuit()) break; @@ -439,7 +439,7 @@ void InventoryDialog::execute() { // Inventory item selected InvObject *invObject = static_cast<GfxInvImage *>(hiliteObj)->_invObject; if (lookFlag) { - g_globals->_screenSurface.displayText(invObject->_description); + g_globals->_screen.displayText(invObject->_description); } else { RING_INVENTORY._selectedItem = invObject; invObject->setCursor(); diff --git a/engines/tsage/ringworld/ringworld_logic.cpp b/engines/tsage/ringworld/ringworld_logic.cpp index 1d8293cffd..354c86abfc 100644 --- a/engines/tsage/ringworld/ringworld_logic.cpp +++ b/engines/tsage/ringworld/ringworld_logic.cpp @@ -320,7 +320,7 @@ void SceneArea::wait() { // Wait until a mouse or keypress Event event; while (!g_vm->shouldQuit() && !g_globals->_events.getEvent(event)) { - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); g_system->delayMillis(10); } diff --git a/engines/tsage/ringworld/ringworld_scenes3.cpp b/engines/tsage/ringworld/ringworld_scenes3.cpp index a515224964..a9ed7af870 100644 --- a/engines/tsage/ringworld/ringworld_scenes3.cpp +++ b/engines/tsage/ringworld/ringworld_scenes3.cpp @@ -532,7 +532,7 @@ void Scene2100::Action1::signal() { // Wait for an event Event event; if (!g_globals->_events.getEvent(event)) { - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); g_system->delayMillis(10); continue; } @@ -2265,7 +2265,7 @@ void Scene2150::Action1::signal() { // Wait for an event Event event; if (!g_globals->_events.getEvent(event)) { - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); g_system->delayMillis(10); continue; } @@ -5119,7 +5119,7 @@ void Scene2320::Action3::signal() { // Wait for an event Event event; if (!g_globals->_events.getEvent(event)) { - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); g_system->delayMillis(10); continue; } diff --git a/engines/tsage/ringworld/ringworld_scenes5.cpp b/engines/tsage/ringworld/ringworld_scenes5.cpp index cb8a89de80..98859f32ee 100644 --- a/engines/tsage/ringworld/ringworld_scenes5.cpp +++ b/engines/tsage/ringworld/ringworld_scenes5.cpp @@ -2813,7 +2813,7 @@ void Scene4150::Action1::signal() { case 4: { for (int idx = 100; idx >= 0; idx -= 5) { g_globals->_scenePalette.fade(adjustData, false, idx); - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); g_system->delayMillis(10); } @@ -2841,7 +2841,7 @@ void Scene4150::Action1::signal() { case 7: for (int idx = 100; idx >= 0; idx -= 5) { g_globals->_scenePalette.fade(adjustData, false, idx); - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); g_system->delayMillis(10); } diff --git a/engines/tsage/ringworld2/ringworld2_dialogs.cpp b/engines/tsage/ringworld2/ringworld2_dialogs.cpp index 99f88a1687..027fb558db 100644 --- a/engines/tsage/ringworld2/ringworld2_dialogs.cpp +++ b/engines/tsage/ringworld2/ringworld2_dialogs.cpp @@ -154,7 +154,7 @@ int RightClickDialog::execute() { } g_system->delayMillis(10); - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); } // Execute the specified action diff --git a/engines/tsage/ringworld2/ringworld2_logic.cpp b/engines/tsage/ringworld2/ringworld2_logic.cpp index d24541932f..ecaa671bd7 100644 --- a/engines/tsage/ringworld2/ringworld2_logic.cpp +++ b/engines/tsage/ringworld2/ringworld2_logic.cpp @@ -351,7 +351,7 @@ SceneExt::SceneExt(): Scene() { _preventSaving = false; // Reset screen clipping area - R2_GLOBALS._screenSurface._clipRect = Rect(); + R2_GLOBALS._screen._clipRect = Rect(); // WORKAROUND: In the original, playing animations don't reset the global _animationCtr // counter as scene changes unless the playing animation explicitly finishes. For now, @@ -513,7 +513,7 @@ void SceneExt::endStrip() { } void SceneExt::clearScreen() { - R2_GLOBALS._screenSurface.fillRect(R2_GLOBALS._screenSurface.getBounds(), 0); + R2_GLOBALS._screen.fillRect(R2_GLOBALS._screen.getBounds(), 0); } void SceneExt::refreshBackground(int xAmount, int yAmount) { @@ -543,15 +543,12 @@ void SceneExt::refreshBackground(int xAmount, int yAmount) { int screenSize = g_vm->_memoryManager.getSize(dataP); // Lock the background for update - Graphics::Surface s = _backSurface.lockSurface(); - assert(screenSize == (s.w * s.h)); + assert(screenSize == (_backSurface.w * _backSurface.h)); + Graphics::Surface s = _backSurface.getSubArea(Common::Rect(0, 0, _backSurface.w, _backSurface.h)); - // Copy the data + // Copy the data into the surface byte *destP = (byte *)s.getPixels(); Common::copy(dataP, dataP + (s.w * s.h), destP); - _backSurface.unlockSurface(); - - R2_GLOBALS._screenSurface.addDirtyRect(_backSurface.getBounds()); // Free the resource data DEALLOCATE(dataP); @@ -601,7 +598,7 @@ void SceneExt::loadBlankScene() { _backSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT * 3 / 2); _backSurface.fillRect(_backSurface.getBounds(), 0); - R2_GLOBALS._screenSurface.fillRect(R2_GLOBALS._screenSurface.getBounds(), 0); + R2_GLOBALS._screen.fillRect(R2_GLOBALS._screen.getBounds(), 0); } /*--------------------------------------------------------------------------*/ @@ -1966,10 +1963,9 @@ void AnimationPlayer::drawFrame(int sliceIndex) { byte *sliceData1 = sliceDataStart; Rect playerBounds = _screenBounds; - int y = _screenBounds.top; - R2_GLOBALS._screenSurface.addDirtyRect(playerBounds); - Graphics::Surface surface = R2_GLOBALS._screenSurface.lockSurface(); + Graphics::Surface dest = R2_GLOBALS._screen.getSubArea(playerBounds); + int y = 0; // Handle different drawing modes switch (slice._drawMode) { @@ -1980,7 +1976,7 @@ void AnimationPlayer::drawFrame(int sliceIndex) { // TODO: Check of _subData._drawType was done for two different kinds of // line slice drawing in original const byte *pSrc = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData1 + sliceNum * 2); - byte *pDest = (byte *)surface.getBasePtr(playerBounds.left, y++); + byte *pDest = (byte *)dest.getBasePtr(0, y++); Common::copy(pSrc, pSrc + _subData._sliceSize, pDest); } @@ -1997,7 +1993,7 @@ void AnimationPlayer::drawFrame(int sliceIndex) { if (offset) { const byte *pSrc = (const byte *)sliceDataStart + offset; - byte *pDest = (byte *)surface.getBasePtr(playerBounds.left, playerBounds.top); + byte *pDest = (byte *)dest.getBasePtr(0, 0); //Common::copy(pSrc, pSrc + playerBounds.width(), pDest); rleDecode(pSrc, pDest, playerBounds.width()); @@ -2012,7 +2008,7 @@ void AnimationPlayer::drawFrame(int sliceIndex) { // TODO: Check of _subData._drawType was done for two different kinds of // line slice drawing in original const byte *pSrc = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData1 + sliceNum * 2); - byte *pDest = (byte *)surface.getBasePtr(playerBounds.left, playerBounds.top); + byte *pDest = (byte *)dest.getBasePtr(0, 0); rleDecode(pSrc, pDest, _subData._sliceSize); } @@ -2027,7 +2023,7 @@ void AnimationPlayer::drawFrame(int sliceIndex) { for (int yIndex = 0; yIndex < _sliceHeight; ++yIndex) { const byte *pSrc1 = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData2 + sliceNum * 2); const byte *pSrc2 = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData1 + sliceNum * 2); - byte *pDest = (byte *)surface.getBasePtr(playerBounds.left, y++); + byte *pDest = (byte *)dest.getBasePtr(0, y++); if (slice2._drawMode == 0) { // Uncompressed background, foreground compressed @@ -2047,17 +2043,14 @@ void AnimationPlayer::drawFrame(int sliceIndex) { break; } - // Unlock the screen surface - R2_GLOBALS._screenSurface.unlockSurface(); - if (_objectMode == ANIMOBJMODE_42) { _screenBounds.expandPanes(); // Copy the drawn frame to the back surface - Rect srcRect = R2_GLOBALS._screenSurface.getBounds(); + Rect srcRect = R2_GLOBALS._screen.getBounds(); Rect destRect = srcRect; destRect.translate(-g_globals->_sceneOffset.x, -g_globals->_sceneOffset.y); - R2_GLOBALS._sceneManager._scene->_backSurface.copyFrom(R2_GLOBALS._screenSurface, + R2_GLOBALS._sceneManager._scene->_backSurface.copyFrom(R2_GLOBALS._screen, srcRect, destRect); // Draw any objects into the scene diff --git a/engines/tsage/ringworld2/ringworld2_outpost.cpp b/engines/tsage/ringworld2/ringworld2_outpost.cpp index cad21b4623..8c64970bda 100644 --- a/engines/tsage/ringworld2/ringworld2_outpost.cpp +++ b/engines/tsage/ringworld2/ringworld2_outpost.cpp @@ -4689,7 +4689,7 @@ GfxButton *Scene1337::OptionsDialog::execute(GfxButton *defaultButton) { } g_system->delayMillis(10); - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); } _gfxManager.deactivate(); diff --git a/engines/tsage/ringworld2/ringworld2_scenes0.cpp b/engines/tsage/ringworld2/ringworld2_scenes0.cpp index 573cbbb29a..63879b0366 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes0.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes0.cpp @@ -1613,7 +1613,7 @@ void Scene180::signal() { case 43: case 47: _helpEnabled = false; - R2_GLOBALS._screenSurface.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0); + R2_GLOBALS._screen.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0); _palette.loadPalette(0); _palette.loadPalette(9998); R2_GLOBALS._scenePalette.addFader(_palette._palette, 256, 8, this); @@ -1815,7 +1815,7 @@ void Scene180::signal() { _shipDisplay.remove(); _backSurface.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0); - R2_GLOBALS._screenSurface.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0); + R2_GLOBALS._screen.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0); R2_GLOBALS._sound2.fadeOut2(NULL); R2_GLOBALS._sound1.fadeOut2(this); break; @@ -1880,7 +1880,7 @@ void Scene180::signal() { R2_GLOBALS._paneRefreshFlag[0] = 3; _backSurface.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0); - R2_GLOBALS._screenSurface.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0); + R2_GLOBALS._screen.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0); setSceneDelay(1); break; diff --git a/engines/tsage/saveload.cpp b/engines/tsage/saveload.cpp index 9954b929b2..3cb8e52692 100644 --- a/engines/tsage/saveload.cpp +++ b/engines/tsage/saveload.cpp @@ -289,10 +289,10 @@ void Saver::writeSavegameHeader(Common::OutSaveFile *out, tSageSavegameHeader &h // Create a thumbnail and save it Graphics::Surface *thumb = new Graphics::Surface(); - Graphics::Surface s = g_globals->_screenSurface.lockSurface(); + Graphics::Surface s = g_globals->_screen.lockSurface(); ::createThumbnail(thumb, (const byte *)s.getPixels(), SCREEN_WIDTH, SCREEN_HEIGHT, thumbPalette); Graphics::saveThumbnail(*out, *thumb); - g_globals->_screenSurface.unlockSurface(); + g_globals->_screen.unlockSurface(); thumb->free(); delete thumb; diff --git a/engines/tsage/scenes.cpp b/engines/tsage/scenes.cpp index 80ce1e3ecc..095c0d7ab5 100644 --- a/engines/tsage/scenes.cpp +++ b/engines/tsage/scenes.cpp @@ -139,7 +139,7 @@ void SceneManager::fadeInIfNecessary() { percent = 100; g_globals->_scenePalette.fade((const byte *)&adjustData, false, percent); - GLOBALS._screenSurface.updateScreen(); + GLOBALS._screen.update(); g_system->delayMillis(10); } @@ -175,7 +175,7 @@ void SceneManager::changeScene(int newSceneNumber) { } // Blank out the screen - g_globals->_screenSurface.fillRect(g_globals->_screenSurface.getBounds(), 0); + g_globals->_screen.fillRect(g_globals->_screen.getBounds(), 0); // If there are any fading sounds, wait until fading is complete while (g_globals->_soundManager.isFading()) { @@ -463,7 +463,7 @@ void Scene::refreshBackground(int xAmount, int yAmount) { // Check if the section is already loaded if ((_enabledSections[xp * 16 + yp] == 0xffff) || ((xAmount == 0) && (yAmount == 0))) { // Chunk isn't loaded, so load it in - Graphics::Surface s = _backSurface.lockSurface(); + Graphics::ManagedSurface s = _backSurface.lockSurface(); GfxSurface::loadScreenSection(s, xp - xHalfOffset, yp - yHalfOffset, xp, yp); _backSurface.unlockSurface(); changedFlag = true; diff --git a/engines/tsage/screen.cpp b/engines/tsage/screen.cpp new file mode 100644 index 0000000000..f11c384797 --- /dev/null +++ b/engines/tsage/screen.cpp @@ -0,0 +1,46 @@ +/* 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/scummsys.h" +#include "tsage/screen.h" + +namespace TsAGE { + +Screen::Screen(): GfxSurface(), Graphics::Screen() { + create(SCREEN_WIDTH, SCREEN_HEIGHT); +} + +void Screen::update() { + // When dialogs are active, the screen surface may be remapped to + // sub-sections of the screen. But for drawing we'll need to temporarily + // remove any such remappings and use the entirety of the screen + Rect clipBounds = getBounds(); + setBounds(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)); + + // Update the screen + Graphics::Screen::update(); + + // Reset the clipping + setBounds(clipBounds); +} + +} // End of namespace TsAGE diff --git a/engines/tsage/screen.h b/engines/tsage/screen.h new file mode 100644 index 0000000000..bf5057e4d6 --- /dev/null +++ b/engines/tsage/screen.h @@ -0,0 +1,59 @@ +/* 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 TSAGE_SCREEN_H +#define TSAGE_SCREEN_H + +#include "common/scummsys.h" +#include "common/array.h" +#include "graphics/screen.h" +#include "tsage/graphics.h" + +namespace TsAGE { + +#define SCREEN_WIDTH 320 +#define SCREEN_HEIGHT 200 +#define SCREEN_CENTER_X 160 +#define SCREEN_CENTER_Y 100 +#define UI_INTERFACE_Y 168 + +class Screen : virtual public Graphics::Screen, virtual public GfxSurface { +public: + /** + * Constructor + */ + Screen(); + + /** + * Destructor + */ + virtual ~Screen() {} + + /** + * Update the screen + */ + virtual void update(); +}; + +} // End of namespace TsAGE + +#endif /* MADS_SCREEN_H */ diff --git a/engines/tsage/tsage.h b/engines/tsage/tsage.h index 667a8daa59..1a29700a10 100644 --- a/engines/tsage/tsage.h +++ b/engines/tsage/tsage.h @@ -62,12 +62,6 @@ enum { struct tSageGameDescription; -#define SCREEN_WIDTH 320 -#define SCREEN_HEIGHT 200 -#define SCREEN_CENTER_X 160 -#define SCREEN_CENTER_Y 100 -#define UI_INTERFACE_Y 168 - class TSageEngine : public Engine { private: const tSageGameDescription *_gameDescription; diff --git a/engines/tsage/user_interface.cpp b/engines/tsage/user_interface.cpp index 3ee585d5ef..fffc0dc16c 100644 --- a/engines/tsage/user_interface.cpp +++ b/engines/tsage/user_interface.cpp @@ -253,7 +253,7 @@ void UICollection::show() { void UICollection::erase() { if (_clearScreen) { Rect tempRect(0, UI_INTERFACE_Y, SCREEN_WIDTH, SCREEN_HEIGHT); - GLOBALS._screenSurface.fillRect(tempRect, 0); + GLOBALS._screen.fillRect(tempRect, 0); GLOBALS._sceneManager._scene->_backSurface.fillRect(tempRect, 0); _clearScreen = false; } @@ -274,7 +274,7 @@ void UICollection::draw() { _objList[idx]->draw(); // Draw the resulting UI onto the screen - GLOBALS._screenSurface.copyFrom(GLOBALS._sceneManager._scene->_backSurface, + GLOBALS._screen.copyFrom(GLOBALS._sceneManager._scene->_backSurface, Rect(0, UI_INTERFACE_Y, SCREEN_WIDTH, SCREEN_HEIGHT), Rect(0, UI_INTERFACE_Y, SCREEN_WIDTH, SCREEN_HEIGHT)); @@ -293,12 +293,12 @@ void UICollection::r2rDrawFrame() { GfxSurface vertLineRight = visage.getFrame(3); GfxSurface horizLine = visage.getFrame(2); - GLOBALS._screenSurface.copyFrom(horizLine, 0, 0); - GLOBALS._screenSurface.copyFrom(vertLineLeft, 0, 3); - GLOBALS._screenSurface.copyFrom(vertLineRight, SCREEN_WIDTH - 4, 3); + GLOBALS._screen.copyFrom(horizLine, 0, 0); + GLOBALS._screen.copyFrom(vertLineLeft, 0, 3); + GLOBALS._screen.copyFrom(vertLineRight, SCREEN_WIDTH - 4, 3); // Restrict drawing area to exclude the borders at the edge of the screen - R2_GLOBALS._screenSurface._clipRect = Rect(4, 3, SCREEN_WIDTH - 4, + R2_GLOBALS._screen._clipRect = Rect(4, 3, SCREEN_WIDTH - 4, SCREEN_HEIGHT - 3); } diff --git a/engines/tucker/detection.cpp b/engines/tucker/detection.cpp index 3d7859e4fd..2447e15d6b 100644 --- a/engines/tucker/detection.cpp +++ b/engines/tucker/detection.cpp @@ -116,7 +116,7 @@ class TuckerMetaEngine : public AdvancedMetaEngine { public: TuckerMetaEngine() : AdvancedMetaEngine(tuckerGameDescriptions, sizeof(ADGameDescription), tuckerGames) { _md5Bytes = 512; - _singleid = "tucker"; + _singleId = "tucker"; } virtual const char *getName() const { @@ -182,6 +182,8 @@ public: saveList.push_back(SaveStateDescriptor(slot, description)); } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } 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/tucker/sequences.cpp b/engines/tucker/sequences.cpp index d9f284e443..0151c55eb1 100644 --- a/engines/tucker/sequences.cpp +++ b/engines/tucker/sequences.cpp @@ -54,6 +54,7 @@ void TuckerEngine::handleCreditsSequence() { int counter2 = 0; int counter1 = 0; loadCharset2(); + showCursor(false); stopSounds(); _locationNum = 74; _flagsTable[236] = 74; @@ -159,12 +160,16 @@ void TuckerEngine::handleCreditsSequence() { redrawScreen(0); waitForTimer(2); } while (_fadePaletteCounter > 0); + showCursor(true); } void TuckerEngine::handleCongratulationsSequence() { + // This method is only called right before the program terminates, + // so it doesn't bother restoring the palette _timerCounter2 = 0; _fadePaletteCounter = 0; stopSounds(); + showCursor(false); loadImage("congrat.pcx", _loadTempBuf, 1); Graphics::copyRect(_locationBackgroundGfxBuf, 640, _loadTempBuf, 320, 320, 200); _fullRedraw = true; @@ -176,11 +181,13 @@ void TuckerEngine::handleCongratulationsSequence() { } waitForTimer(3); } + showCursor(true); } void TuckerEngine::handleNewPartSequence() { char filename[40]; + showCursor(false); stopSounds(); if (_flagsTable[219] == 1) { _flagsTable[219] = 0; @@ -244,7 +251,7 @@ void TuckerEngine::handleNewPartSequence() { _inputKeys[kInputKeyEscape] = false; break; } - } while (isSpeechSoundPlaying()); + } while (isSpeechSoundPlaying() && !_quitGame); stopSpeechSound(); do { if (_fadePaletteCounter > 0) { @@ -257,8 +264,9 @@ void TuckerEngine::handleNewPartSequence() { drawSprite(0); redrawScreen(0); waitForTimer(3); - } while (_fadePaletteCounter > 0); + } while (_fadePaletteCounter > 0 && !_quitGame); _locationNum = currentLocation; + showCursor(true); } void TuckerEngine::handleMeanwhileSequence() { @@ -280,8 +288,9 @@ void TuckerEngine::handleMeanwhileSequence() { strcpy(filename, "loc80.pcx"); } loadImage(filename, _quadBackgroundGfxBuf + 89600, 1); + showCursor(false); _fadePaletteCounter = 0; - for (int i = 0; i < 60; ++i) { + for (int i = 0; i < 60 && !_quitGame; ++i) { if (_fadePaletteCounter < 16) { fadeOutPalette(); ++_fadePaletteCounter; @@ -290,7 +299,10 @@ void TuckerEngine::handleMeanwhileSequence() { _fullRedraw = true; redrawScreen(0); waitForTimer(3); - ++i; + if (_inputKeys[kInputKeyEscape]) { + _inputKeys[kInputKeyEscape] = false; + break; + } } do { if (_fadePaletteCounter > 0) { @@ -301,9 +313,10 @@ void TuckerEngine::handleMeanwhileSequence() { _fullRedraw = true; redrawScreen(0); waitForTimer(3); - } while (_fadePaletteCounter > 0); + } while (_fadePaletteCounter > 0 && !_quitGame); memcpy(_currentPalette, backupPalette, 256 * 3); _fullRedraw = true; + showCursor(true); } void TuckerEngine::handleMapSequence() { diff --git a/engines/tucker/tucker.cpp b/engines/tucker/tucker.cpp index de555cd7b6..ad455c5ded 100644 --- a/engines/tucker/tucker.cpp +++ b/engines/tucker/tucker.cpp @@ -710,6 +710,10 @@ void TuckerEngine::setCursorType(int type) { CursorMan.showMouse(_cursorType < 2); } +void TuckerEngine::showCursor(bool visible) { + CursorMan.showMouse(visible); +} + void TuckerEngine::setupNewLocation() { debug(2, "setupNewLocation() current %d next %d", _locationNum, _nextLocationNum); _locationNum = _nextLocationNum; diff --git a/engines/tucker/tucker.h b/engines/tucker/tucker.h index 3bbf6a57f5..2ab94dedbc 100644 --- a/engines/tucker/tucker.h +++ b/engines/tucker/tucker.h @@ -300,6 +300,7 @@ protected: void updateCursorPos(int x, int y); void setCursorNum(int num); void setCursorType(int type); + void showCursor(bool visible); void setupNewLocation(); void copyLocBitmap(const char *filename, int offset, bool isMask); void updateMouseState(); diff --git a/engines/voyeur/animation.cpp b/engines/voyeur/animation.cpp index 62b37346da..d5d58a2fd3 100644 --- a/engines/voyeur/animation.cpp +++ b/engines/voyeur/animation.cpp @@ -470,7 +470,7 @@ void RL2Decoder::play(VoyeurEngine *vm, int resourceOffset, if (hasDirtyPalette()) { const byte *palette = getPalette(); - vm->_graphicsManager->setPalette128(palette, paletteStart, paletteCount); + vm->_screen->setPalette128(palette, paletteStart, paletteCount); } if (needsUpdate()) { @@ -482,15 +482,14 @@ void RL2Decoder::play(VoyeurEngine *vm, int resourceOffset, Common::Point pt(READ_LE_UINT16(imgPos + 4 * picCtr) - 32, READ_LE_UINT16(imgPos + 4 * picCtr + 2) - 20); - vm->_graphicsManager->sDrawPic(newPic, &videoFrame, pt); + vm->_screen->sDrawPic(newPic, &videoFrame, pt); ++picCtr; } } // Decode the next frame and display const Graphics::Surface *frame = decodeNextFrame(); - Common::copy((const byte *)frame->getPixels(), (const byte *)frame->getPixels() + 320 * 200, - (byte *)vm->_graphicsManager->_screenSurface.getPixels()); + vm->_screen->blitFrom(*frame); } vm->_eventsManager->getMouseInfo(); diff --git a/engines/voyeur/data.cpp b/engines/voyeur/data.cpp index b8c987f18b..4d6e32436d 100644 --- a/engines/voyeur/data.cpp +++ b/engines/voyeur/data.cpp @@ -240,10 +240,10 @@ void SVoy::reviewAnEvidEvent(int eventIndex) { int frameOff = e._computerOff; if (_vm->_bVoy->getBoltGroup(_vm->_playStampGroupId)) { - _vm->_graphicsManager->_backColors = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 1)._cMapResource; - _vm->_graphicsManager->_backgroundPage = _vm->_bVoy->boltEntry(_vm->_playStampGroupId)._picResource; - _vm->_graphicsManager->_vPort->setupViewPort(_vm->_graphicsManager->_backgroundPage); - _vm->_graphicsManager->_backColors->startFade(); + _vm->_screen->_backColors = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 1)._cMapResource; + _vm->_screen->_backgroundPage = _vm->_bVoy->boltEntry(_vm->_playStampGroupId)._picResource; + _vm->_screen->_vPort->setupViewPort(_vm->_screen->_backgroundPage); + _vm->_screen->_backColors->startFade(); _vm->doEvidDisplay(frameOff, e._dead); _vm->_bVoy->freeBoltGroup(_vm->_playStampGroupId); @@ -262,10 +262,10 @@ void SVoy::reviewComputerEvent(int eventIndex) { _computerTextId = e._computerOn; if (_vm->_bVoy->getBoltGroup(_vm->_playStampGroupId)) { - _vm->_graphicsManager->_backColors = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 1)._cMapResource; - _vm->_graphicsManager->_backgroundPage = _vm->_bVoy->boltEntry(_vm->_playStampGroupId)._picResource; - _vm->_graphicsManager->_vPort->setupViewPort(_vm->_graphicsManager->_backgroundPage); - _vm->_graphicsManager->_backColors->startFade(); + _vm->_screen->_backColors = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 1)._cMapResource; + _vm->_screen->_backgroundPage = _vm->_bVoy->boltEntry(_vm->_playStampGroupId)._picResource; + _vm->_screen->_vPort->setupViewPort(_vm->_screen->_backgroundPage); + _vm->_screen->_backColors->startFade(); _vm->flipPageAndWaitForFade(); _vm->getComputerBrush(); diff --git a/engines/voyeur/debugger.cpp b/engines/voyeur/debugger.cpp index e9a12180da..ebfa123eb6 100644 --- a/engines/voyeur/debugger.cpp +++ b/engines/voyeur/debugger.cpp @@ -21,7 +21,7 @@ */ #include "voyeur/debugger.h" -#include "voyeur/graphics.h" +#include "voyeur/screen.h" #include "voyeur/voyeur.h" #include "voyeur/staticres.h" diff --git a/engines/voyeur/detection.cpp b/engines/voyeur/detection.cpp index 80a23d3c35..9e5320aac8 100644 --- a/engines/voyeur/detection.cpp +++ b/engines/voyeur/detection.cpp @@ -117,7 +117,6 @@ SaveStateList VoyeurMetaEngine::listSaves(const char *target) const { Common::String pattern = Common::String::format("%s.0##", target); filenames = saveFileMan->listSavefiles(pattern); - sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order SaveStateList saveList; Voyeur::VoyeurSavegameHeader header; @@ -139,6 +138,8 @@ SaveStateList VoyeurMetaEngine::listSaves(const char *target) const { } } + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } diff --git a/engines/voyeur/events.cpp b/engines/voyeur/events.cpp index 34ef507ad3..020fe4b692 100644 --- a/engines/voyeur/events.cpp +++ b/engines/voyeur/events.cpp @@ -111,18 +111,18 @@ void EventsManager::mainVoyeurIntFunc() { } void EventsManager::sWaitFlip() { - Common::Array<ViewPortResource *> &viewPorts = _vm->_graphicsManager->_viewPortListPtr->_entries; + Common::Array<ViewPortResource *> &viewPorts = _vm->_screen->_viewPortListPtr->_entries; for (uint idx = 0; idx < viewPorts.size(); ++idx) { ViewPortResource &viewPort = *viewPorts[idx]; - if (_vm->_graphicsManager->_saveBack && (viewPort._flags & DISPFLAG_40)) { - Common::Rect *clipPtr = _vm->_graphicsManager->_clipPtr; - _vm->_graphicsManager->_clipPtr = &viewPort._clipRect; + if (_vm->_screen->_saveBack && (viewPort._flags & DISPFLAG_40)) { + Common::Rect *clipPtr = _vm->_screen->_clipPtr; + _vm->_screen->_clipPtr = &viewPort._clipRect; if (viewPort._restoreFn) - (_vm->_graphicsManager->*viewPort._restoreFn)(&viewPort); + (_vm->_screen->*viewPort._restoreFn)(&viewPort); - _vm->_graphicsManager->_clipPtr = clipPtr; + _vm->_screen->_clipPtr = clipPtr; viewPort._rectListCount[viewPort._pageIndex] = 0; viewPort._rectListPtr[viewPort._pageIndex]->clear(); viewPort._flags &= ~DISPFLAG_40; @@ -158,9 +158,7 @@ void EventsManager::checkForNextFrameCounter() { showMousePosition(); // Display the frame - g_system->copyRectToScreen((byte *)_vm->_graphicsManager->_screenSurface.getPixels(), - SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); - g_system->updateScreen(); + _vm->_screen->update(); // Signal the ScummVM debugger _vm->_debugger->onFrame(); @@ -178,10 +176,8 @@ void EventsManager::showMousePosition() { mousePos += Common::String::format(" - (%d,%d)", pt.x, pt.y); } - _vm->_graphicsManager->_screenSurface.fillRect( - Common::Rect(0, 0, 110, font.getFontHeight()), 0); - font.drawString(&_vm->_graphicsManager->_screenSurface, mousePos, - 0, 0, 110, 63); + _vm->_screen->fillRect(Common::Rect(0, 0, 110, font.getFontHeight()), 0); + font.drawString(_vm->_screen, mousePos, 0, 0, 110, 63); } void EventsManager::voyeurTimer() { @@ -299,11 +295,11 @@ void EventsManager::startFade(CMapResource *cMap) { if (cMap->_steps > 0) { _fadeStatus = cMap->_fadeStatus | 1; - byte *vgaP = &_vm->_graphicsManager->_VGAColors[_fadeFirstCol * 3]; + byte *vgaP = &_vm->_screen->_VGAColors[_fadeFirstCol * 3]; int mapIndex = 0; for (int idx = _fadeFirstCol; idx <= _fadeLastCol; ++idx, vgaP += 3) { - ViewPortPalEntry &palEntry = _vm->_graphicsManager->_viewPortListPtr->_palette[idx]; + ViewPortPalEntry &palEntry = _vm->_screen->_viewPortListPtr->_palette[idx]; palEntry._rEntry = vgaP[0] << 8; int rDiff = (cMap->_entries[mapIndex * 3] << 8) - palEntry._rEntry; palEntry._rChange = rDiff / cMap->_steps; @@ -325,7 +321,7 @@ void EventsManager::startFade(CMapResource *cMap) { _intPtr._skipFading = true; _fadeIntNode._flags &= ~1; } else { - byte *vgaP = &_vm->_graphicsManager->_VGAColors[_fadeFirstCol * 3]; + byte *vgaP = &_vm->_screen->_VGAColors[_fadeFirstCol * 3]; int mapIndex = 0; for (int idx = _fadeFirstCol; idx <= _fadeLastCol; ++idx, vgaP += 3) { @@ -371,8 +367,8 @@ void EventsManager::vDoFadeInt() { } for (int i = _fadeFirstCol; i <= _fadeLastCol; ++i) { - ViewPortPalEntry &palEntry = _vm->_graphicsManager->_viewPortListPtr->_palette[i]; - byte *vgaP = &_vm->_graphicsManager->_VGAColors[palEntry._palIndex * 3]; + ViewPortPalEntry &palEntry = _vm->_screen->_viewPortListPtr->_palette[i]; + byte *vgaP = &_vm->_screen->_VGAColors[palEntry._palIndex * 3]; palEntry._rEntry += palEntry._rChange; palEntry._gEntry += palEntry._gChange; @@ -395,7 +391,7 @@ void EventsManager::vDoCycleInt() { for (int idx = 3; idx >= 0; --idx) { if (_cyclePtr->_type[idx] && --_cycleTime[idx] <= 0) { byte *pSrc = _cycleNext[idx]; - byte *pPal = _vm->_graphicsManager->_VGAColors; + byte *pPal = _vm->_screen->_VGAColors; if (_cyclePtr->_type[idx] != 1) { // New palette data being specified - loop to set entries @@ -521,7 +517,7 @@ void EventsManager::setCursor(PictureResource *pic) { cursor._bounds = pic->_bounds; cursor._flags = DISPFLAG_CURSOR; - _vm->_graphicsManager->sDrawPic(pic, &cursor, Common::Point()); + _vm->_screen->sDrawPic(pic, &cursor, Common::Point()); } void EventsManager::setCursor(byte *cursorData, int width, int height, int keyColor) { @@ -531,16 +527,16 @@ void EventsManager::setCursor(byte *cursorData, int width, int height, int keyCo void EventsManager::setCursorColor(int idx, int mode) { switch (mode) { case 0: - _vm->_graphicsManager->setColor(idx, 90, 90, 232); + _vm->_screen->setColor(idx, 90, 90, 232); break; case 1: - _vm->_graphicsManager->setColor(idx, 232, 90, 90); + _vm->_screen->setColor(idx, 232, 90, 90); break; case 2: - _vm->_graphicsManager->setColor(idx, 90, 232, 90); + _vm->_screen->setColor(idx, 90, 232, 90); break; case 3: - _vm->_graphicsManager->setColor(idx, 90, 232, 232); + _vm->_screen->setColor(idx, 90, 232, 232); break; default: break; @@ -564,12 +560,12 @@ void EventsManager::getMouseInfo() { if (_cursorBlinked) { _cursorBlinked = false; - _vm->_graphicsManager->setOneColor(128, 220, 20, 20); - _vm->_graphicsManager->setColor(128, 220, 20, 20); + _vm->_screen->setOneColor(128, 220, 20, 20); + _vm->_screen->setColor(128, 220, 20, 20); } else { _cursorBlinked = true; - _vm->_graphicsManager->setOneColor(128, 220, 220, 220); - _vm->_graphicsManager->setColor(128, 220, 220, 220); + _vm->_screen->setOneColor(128, 220, 220, 220); + _vm->_screen->setColor(128, 220, 220, 220); } } } @@ -585,11 +581,11 @@ void EventsManager::getMouseInfo() { void EventsManager::startCursorBlink() { if (_vm->_voy->_eventFlags & EVTFLAG_RECORDING) { - _vm->_graphicsManager->setOneColor(128, 55, 5, 5); - _vm->_graphicsManager->setColor(128, 220, 20, 20); + _vm->_screen->setOneColor(128, 55, 5, 5); + _vm->_screen->setColor(128, 220, 20, 20); _intPtr._hasPalette = true; - _vm->_graphicsManager->drawDot(); + _vm->_screen->drawDot(); //copySection(); } } diff --git a/engines/voyeur/files.cpp b/engines/voyeur/files.cpp index 300e086f75..46b195ecaf 100644 --- a/engines/voyeur/files.cpp +++ b/engines/voyeur/files.cpp @@ -21,7 +21,7 @@ */ #include "voyeur/files.h" -#include "voyeur/graphics.h" +#include "voyeur/screen.h" #include "voyeur/voyeur.h" #include "voyeur/staticres.h" @@ -359,7 +359,7 @@ void BoltFile::resolveIt(uint32 id, byte **p) { } } -void BoltFile::resolveFunction(uint32 id, GraphicMethodPtr *fn) { +void BoltFile::resolveFunction(uint32 id, ScreenMethodPtr *fn) { if ((int32)id == -1) *fn = NULL; else @@ -485,8 +485,8 @@ void BVoyBoltFile::initViewPortList() { _state._curMemberPtr->_viewPortListResource = res = new ViewPortListResource( _state, _state._curMemberPtr->_data); - _state._vm->_graphicsManager->_viewPortListPtr = res; - _state._vm->_graphicsManager->_vPort = res->_entries[0]; + _state._vm->_screen->_viewPortListPtr = res; + _state._vm->_screen->_vPort = res->_entries[0]; } void BVoyBoltFile::initFontInfo() { @@ -752,24 +752,24 @@ DisplayResource::DisplayResource(VoyeurEngine *vm) { void DisplayResource::sFillBox(int width, int height) { assert(_vm); - bool saveBack = _vm->_graphicsManager->_saveBack; - _vm->_graphicsManager->_saveBack = false; + bool saveBack = _vm->_screen->_saveBack; + _vm->_screen->_saveBack = false; PictureResource pr; pr._flags = DISPFLAG_1; pr._select = 0xff; pr._pick = 0; - pr._onOff = _vm->_graphicsManager->_drawPtr->_penColor; + pr._onOff = _vm->_screen->_drawPtr->_penColor; pr._bounds = Common::Rect(0, 0, width, height); - _vm->_graphicsManager->sDrawPic(&pr, this, _vm->_graphicsManager->_drawPtr->_pos); - _vm->_graphicsManager->_saveBack = saveBack; + _vm->_screen->sDrawPic(&pr, this, _vm->_screen->_drawPtr->_pos); + _vm->_screen->_saveBack = saveBack; } bool DisplayResource::clipRect(Common::Rect &rect) { Common::Rect clippingRect; - if (_vm->_graphicsManager->_clipPtr) { - clippingRect = *_vm->_graphicsManager->_clipPtr; + if (_vm->_screen->_clipPtr) { + clippingRect = *_vm->_screen->_clipPtr; } else if (_flags & DISPFLAG_VIEWPORT) { clippingRect = ((ViewPortResource *)this)->_clipRect; } else { @@ -804,18 +804,18 @@ bool DisplayResource::clipRect(Common::Rect &rect) { } int DisplayResource::drawText(const Common::String &msg) { - GraphicsManager &gfxManager = *_vm->_graphicsManager; - assert(gfxManager._fontPtr); - assert(gfxManager._fontPtr->_curFont); - FontInfoResource &fontInfo = *gfxManager._fontPtr; - PictureResource &fontChar = *_vm->_graphicsManager->_fontChar; + Screen &screen = *_vm->_screen; + assert(screen._fontPtr); + assert(screen._fontPtr->_curFont); + FontInfoResource &fontInfo = *screen._fontPtr; + PictureResource &fontChar = *_vm->_screen->_fontChar; FontResource &fontData = *fontInfo._curFont; int xShadows[9] = { 0, 1, 1, 1, 0, -1, -1, -1, 0 }; int yShadows[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 }; - Common::Rect *clipPtr = gfxManager._clipPtr; + Common::Rect *clipPtr = screen._clipPtr; if (!(fontInfo._picFlags & DISPFLAG_1)) - gfxManager._clipPtr = NULL; + screen._clipPtr = NULL; int minChar = fontData._minChar; int padding = fontData._padding; @@ -834,7 +834,7 @@ int DisplayResource::drawText(const Common::String &msg) { (ViewPortResource *)this; if ((fontInfo._fontFlags & DISPFLAG_1) || fontInfo._justify || - (gfxManager._saveBack && fontInfo._fontSaveBack && (_flags & DISPFLAG_VIEWPORT))) { + (screen._saveBack && fontInfo._fontSaveBack && (_flags & DISPFLAG_VIEWPORT))) { msgWidth = viewPort->textWidth(msg); yp = pos.y; xp = pos.x; @@ -898,18 +898,18 @@ int DisplayResource::drawText(const Common::String &msg) { } } - if (gfxManager._saveBack && fontInfo._fontSaveBack && (_flags & DISPFLAG_VIEWPORT)) { + if (screen._saveBack && fontInfo._fontSaveBack && (_flags & DISPFLAG_VIEWPORT)) { viewPort->addSaveRect(viewPort->_pageIndex, viewPort->_fontRect); } if (fontInfo._fontFlags & DISPFLAG_1) { - gfxManager._drawPtr->_pos = Common::Point(viewPort->_fontRect.left, viewPort->_fontRect.top); - gfxManager._drawPtr->_penColor = fontInfo._backColor; + screen._drawPtr->_pos = Common::Point(viewPort->_fontRect.left, viewPort->_fontRect.top); + screen._drawPtr->_penColor = fontInfo._backColor; sFillBox(viewPort->_fontRect.width(), viewPort->_fontRect.height()); } - bool saveBack = gfxManager._saveBack; - gfxManager._saveBack = false; + bool saveBack = screen._saveBack; + screen._saveBack = false; int count = 0; if (fontInfo._fontFlags & DISPFLAG_4) @@ -970,7 +970,7 @@ int DisplayResource::drawText(const Common::String &msg) { uint16 offset = READ_LE_UINT16(fontData._charOffsets + charValue * 2); fontChar._imgData = fontData._charImages + offset * 2; - gfxManager.sDrawPic(&fontChar, this, Common::Point(xp, yp)); + screen.sDrawPic(&fontChar, this, Common::Point(xp, yp)); fontChar._imgData = NULL; xp += charWidth + padding; @@ -982,8 +982,8 @@ int DisplayResource::drawText(const Common::String &msg) { if (fontInfo._justify == ALIGN_LEFT) fontInfo._pos.x = xp; - gfxManager._saveBack = saveBack; - gfxManager._clipPtr = clipPtr; + screen._saveBack = saveBack; + screen._clipPtr = clipPtr; return msgWidth; } @@ -993,7 +993,7 @@ int DisplayResource::textWidth(const Common::String &msg) { return 0; const char *msgP = msg.c_str(); - FontResource &fontData = *_vm->_graphicsManager->_fontPtr->_curFont; + FontResource &fontData = *_vm->_screen->_fontPtr->_curFont; int minChar = fontData._minChar; int maxChar = fontData._maxChar; int padding = fontData._padding; @@ -1085,9 +1085,9 @@ PictureResource::PictureResource(BoltFilesState &state, const byte *src): mode = 226; } - if (mode != state._vm->_graphicsManager->_SVGAMode) { - state._vm->_graphicsManager->_SVGAMode = mode; - state._vm->_graphicsManager->clearPalette(); + if (mode != state._vm->_screen->_SVGAMode) { + state._vm->_screen->_SVGAMode = mode; + state._vm->_screen->clearPalette(); } int screenOffset = READ_LE_UINT32(&src[18]) & 0xffff; @@ -1096,13 +1096,14 @@ PictureResource::PictureResource(BoltFilesState &state, const byte *src): if (_flags & PICFLAG_CLEAR_SCREEN) { // Clear screen picture. That's right. This game actually has a picture // resource flag to clear the screen! Bizarre. - Graphics::Surface &s = state._vm->_graphicsManager->_screenSurface; - s.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0); + state._vm->_screen->clear(); } else { // Direct screen loading picture. In this case, the raw data of the resource // is directly decompressed into the screen surface. Again, bizarre. - byte *pDest = (byte *)state._vm->_graphicsManager->_screenSurface.getPixels(); + Screen &screen = *state._vm->_screen; + byte *pDest = (byte *)screen.getPixels(); state.decompress(pDest, SCREEN_WIDTH * SCREEN_HEIGHT, state._curMemberPtr->_mode); + screen.markAllDirty(); } } else { if (_flags & PICFLAG_CLEAR_SCREEN00) { @@ -1249,13 +1250,13 @@ ViewPortResource::ViewPortResource(BoltFilesState &state, const byte *src): ys + READ_LE_UINT16(src + 0x4C)); state._curLibPtr->resolveIt(READ_LE_UINT32(src + 0x7A), &dummy); - state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x7E), (GraphicMethodPtr *)&_fn1); - state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x82), (GraphicMethodPtr *)&_setupFn); - state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x86), (GraphicMethodPtr *)&_addFn); - state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x8A), (GraphicMethodPtr *)&_restoreFn); + state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x7E), (ScreenMethodPtr *)&_fn1); + state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x82), (ScreenMethodPtr *)&_setupFn); + state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x86), (ScreenMethodPtr *)&_addFn); + state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x8A), (ScreenMethodPtr *)&_restoreFn); if (!_restoreFn && _addFn) - _addFn = &GraphicsManager::addRectNoSaveBack; + _addFn = &Screen::addRectNoSaveBack; } ViewPortResource::~ViewPortResource() { @@ -1327,19 +1328,19 @@ void ViewPortResource::setupViewPort(PictureResource *page, Common::Rect *clippi _restoreFn = restoreFn; if (setupFn) - (_state._vm->_graphicsManager->*setupFn)(this); + (_state._vm->_screen->*setupFn)(this); } void ViewPortResource::setupViewPort() { - setupViewPort(_state._vm->_graphicsManager->_backgroundPage, NULL, - &GraphicsManager::setupMCGASaveRect, &GraphicsManager::addRectOptSaveRect, - &GraphicsManager::restoreMCGASaveRect); + setupViewPort(_state._vm->_screen->_backgroundPage, NULL, + &Screen::setupMCGASaveRect, &Screen::addRectOptSaveRect, + &Screen::restoreMCGASaveRect); } void ViewPortResource::setupViewPort(PictureResource *pic, Common::Rect *clippingRect) { setupViewPort(pic, clippingRect, - &GraphicsManager::setupMCGASaveRect, &GraphicsManager::addRectOptSaveRect, - &GraphicsManager::restoreMCGASaveRect); + &Screen::setupMCGASaveRect, &Screen::addRectOptSaveRect, + &Screen::restoreMCGASaveRect); } void ViewPortResource::addSaveRect(int pageIndex, const Common::Rect &r) { @@ -1347,7 +1348,7 @@ void ViewPortResource::addSaveRect(int pageIndex, const Common::Rect &r) { if (clipRect(rect)) { if (_addFn) { - (_state._vm->_graphicsManager->*_addFn)(this, pageIndex, rect); + (_state._vm->_screen->*_addFn)(this, pageIndex, rect); } else if (_rectListCount[pageIndex] != -1) { _rectListPtr[pageIndex]->push_back(rect); } @@ -1355,26 +1356,26 @@ void ViewPortResource::addSaveRect(int pageIndex, const Common::Rect &r) { } void ViewPortResource::fillPic(byte onOff) { - _state._vm->_graphicsManager->fillPic(this, onOff); + _state._vm->_screen->fillPic(this, onOff); } void ViewPortResource::drawIfaceTime() { // Hour display - _state._vm->_graphicsManager->drawANumber(_state._vm->_graphicsManager->_vPort, + _state._vm->_screen->drawANumber(_state._vm->_screen->_vPort, (_state._vm->_gameHour / 10) == 0 ? 10 : _state._vm->_gameHour / 10, Common::Point(161, 25)); - _state._vm->_graphicsManager->drawANumber(_state._vm->_graphicsManager->_vPort, + _state._vm->_screen->drawANumber(_state._vm->_screen->_vPort, _state._vm->_gameHour % 10, Common::Point(172, 25)); // Minute display - _state._vm->_graphicsManager->drawANumber(_state._vm->_graphicsManager->_vPort, + _state._vm->_screen->drawANumber(_state._vm->_screen->_vPort, _state._vm->_gameMinute / 10, Common::Point(190, 25)); - _state._vm->_graphicsManager->drawANumber(_state._vm->_graphicsManager->_vPort, + _state._vm->_screen->drawANumber(_state._vm->_screen->_vPort, _state._vm->_gameMinute % 10, Common::Point(201, 25)); // AM/PM indicator PictureResource *pic = _state._vm->_bVoy->boltEntry(_state._vm->_voy->_isAM ? 272 : 273)._picResource; - _state._vm->_graphicsManager->sDrawPic(pic, _state._vm->_graphicsManager->_vPort, + _state._vm->_screen->sDrawPic(pic, _state._vm->_screen->_vPort, Common::Point(215, 27)); } @@ -1382,9 +1383,9 @@ void ViewPortResource::drawPicPerm(PictureResource *pic, const Common::Point &pt Common::Rect bounds = pic->_bounds; bounds.translate(pt.x, pt.y); - bool saveBack = _state._vm->_graphicsManager->_saveBack; - _state._vm->_graphicsManager->_saveBack = false; - _state._vm->_graphicsManager->sDrawPic(pic, this, pt); + bool saveBack = _state._vm->_screen->_saveBack; + _state._vm->_screen->_saveBack = false; + _state._vm->_screen->sDrawPic(pic, this, pt); clipRect(bounds); for (int pageIndex = 0; pageIndex < _pageCount; ++pageIndex) { @@ -1393,7 +1394,7 @@ void ViewPortResource::drawPicPerm(PictureResource *pic, const Common::Point &pt } } - _state._vm->_graphicsManager->_saveBack = saveBack; + _state._vm->_screen->_saveBack = saveBack; } /*------------------------------------------------------------------------*/ @@ -1526,7 +1527,7 @@ CMapResource::CMapResource(BoltFilesState &state, const byte *src): _vm(state._v _entries = new byte[count * 3]; Common::copy(src + 6, src + 6 + 3 * count, _entries); - int palIndex = state._vm->_graphicsManager->_viewPortListPtr->_palIndex; + int palIndex = state._vm->_screen->_viewPortListPtr->_palIndex; if (_end > palIndex) _end = palIndex; if (_start > palIndex) diff --git a/engines/voyeur/files.h b/engines/voyeur/files.h index eef5df497c..8726b38ddf 100644 --- a/engines/voyeur/files.h +++ b/engines/voyeur/files.h @@ -27,7 +27,7 @@ #include "common/file.h" #include "common/rect.h" #include "common/str.h" -#include "voyeur/graphics.h" +#include "voyeur/screen.h" namespace Voyeur { @@ -112,7 +112,7 @@ public: byte *memberAddr(uint32 id); byte *memberAddrOffset(uint32 id); void resolveIt(uint32 id, byte **p); - void resolveFunction(uint32 id, GraphicMethodPtr *fn); + void resolveFunction(uint32 id, ScreenMethodPtr *fn); BoltEntry &boltEntry(uint16 id); BoltEntry &getBoltEntryFromLong(uint32 id); @@ -340,7 +340,7 @@ public: int _rectListCount[3]; Common::Rect _clipRect; - GraphicMethodPtr _fn1; + ScreenMethodPtr _fn1; ViewPortSetupPtr _setupFn; ViewPortAddPtr _addFn; ViewPortRestorePtr _restoreFn; diff --git a/engines/voyeur/files_threads.cpp b/engines/voyeur/files_threads.cpp index 9908324043..bbd3dfe4e9 100644 --- a/engines/voyeur/files_threads.cpp +++ b/engines/voyeur/files_threads.cpp @@ -21,7 +21,7 @@ */ #include "voyeur/files.h" -#include "voyeur/graphics.h" +#include "voyeur/screen.h" #include "voyeur/voyeur.h" #include "voyeur/staticres.h" @@ -461,7 +461,7 @@ void ThreadResource::parsePlayCommands() { pic = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + i * 2)._picResource; pal = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + i * 2 + 1)._cMapResource; - _vm->_graphicsManager->_vPort->setupViewPort(pic); + _vm->_screen->_vPort->setupViewPort(pic); pal->startFade(); _vm->flipPageAndWaitForFade(); @@ -980,10 +980,10 @@ int ThreadResource::doApt() { _vm->_soundManager->startVOCPlay(_vm->_soundManager->getVOCFileName(_vm->_currentVocId)); _vm->_currentVocId = 151; - _vm->_graphicsManager->setColor(129, 82, 82, 82); - _vm->_graphicsManager->setColor(130, 112, 112, 112); - _vm->_graphicsManager->setColor(131, 215, 215, 215); - _vm->_graphicsManager->setColor(132, 235, 235, 235); + _vm->_screen->setColor(129, 82, 82, 82); + _vm->_screen->setColor(130, 112, 112, 112); + _vm->_screen->setColor(131, 215, 215, 215); + _vm->_screen->setColor(132, 235, 235, 235); _vm->_eventsManager->_intPtr._hasPalette = true; @@ -1044,7 +1044,7 @@ int ThreadResource::doApt() { // Draw the text description for the highlighted hotspot pic = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + hotspotId + 6)._picResource; - _vm->_graphicsManager->sDrawPic(pic, _vm->_graphicsManager->_vPort, + _vm->_screen->sDrawPic(pic, _vm->_screen->_vPort, Common::Point(106, 200)); } @@ -1112,10 +1112,10 @@ void ThreadResource::doRoom() { if (!vm._bVoy->getBoltGroup(vm._playStampGroupId)) return; - vm._graphicsManager->_backColors = vm._bVoy->boltEntry(vm._playStampGroupId + 1)._cMapResource; - vm._graphicsManager->_backgroundPage = vm._bVoy->boltEntry(vm._playStampGroupId)._picResource; - vm._graphicsManager->_vPort->setupViewPort(vm._graphicsManager->_backgroundPage); - vm._graphicsManager->_backColors->startFade(); + vm._screen->_backColors = vm._bVoy->boltEntry(vm._playStampGroupId + 1)._cMapResource; + vm._screen->_backgroundPage = vm._bVoy->boltEntry(vm._playStampGroupId)._picResource; + vm._screen->_vPort->setupViewPort(vm._screen->_backgroundPage); + vm._screen->_backColors->startFade(); voy._fadingStep1 = 2; voy._fadingStep2 = 0; @@ -1144,7 +1144,7 @@ void ThreadResource::doRoom() { bool breakFlag = false; while (!vm.shouldQuit() && !breakFlag) { _vm->_voyeurArea = AREA_ROOM; - vm._graphicsManager->setColor(128, 0, 255, 0); + vm._screen->setColor(128, 0, 255, 0); vm._eventsManager->_intPtr._hasPalette = true; do { @@ -1186,7 +1186,7 @@ void ThreadResource::doRoom() { } vm._eventsManager->_intPtr._hasPalette = true; - vm._graphicsManager->flipPage(); + vm._screen->flipPage(); vm._eventsManager->sWaitFlip(); } while (!vm.shouldQuit() && !vm._eventsManager->_mouseClicked); @@ -1234,13 +1234,13 @@ void ThreadResource::doRoom() { // WORKAROUND: Skipped code from the original, that freed the group, // reloaded it, and reloaded the cursors - vm._graphicsManager->_backColors = vm._bVoy->boltEntry( + vm._screen->_backColors = vm._bVoy->boltEntry( vm._playStampGroupId + 1)._cMapResource; - vm._graphicsManager->_backgroundPage = vm._bVoy->boltEntry( + vm._screen->_backgroundPage = vm._bVoy->boltEntry( vm._playStampGroupId)._picResource; - vm._graphicsManager->_vPort->setupViewPort(); - vm._graphicsManager->_backColors->startFade(); + vm._screen->_vPort->setupViewPort(); + vm._screen->_backColors->startFade(); _vm->flipPageAndWait(); while (!vm.shouldQuit() && (vm._eventsManager->_fadeStatus & 1)) @@ -1265,7 +1265,7 @@ void ThreadResource::doRoom() { _vm->flipPageAndWait(); - vm._graphicsManager->fadeUpICF1(); + vm._screen->fadeUpICF1(); voy._eventFlags &= EVTFLAG_RECORDING; vm._eventsManager->showCursor(); } @@ -1350,7 +1350,7 @@ int ThreadResource::doInterface() { _vm->_soundManager->startVOCPlay(fname); _vm->_eventsManager->getMouseInfo(); - _vm->_graphicsManager->setColor(240, 220, 220, 220); + _vm->_screen->setColor(240, 220, 220, 220); _vm->_eventsManager->_intPtr._hasPalette = true; _vm->_voy->_eventFlags &= ~EVTFLAG_TIME_DISABLED; @@ -1424,20 +1424,20 @@ int ThreadResource::doInterface() { // Regularly update the time display if (_vm->_voy->_RTANum & 2) { - _vm->_graphicsManager->drawANumber(_vm->_graphicsManager->_vPort, + _vm->_screen->drawANumber(_vm->_screen->_vPort, _vm->_gameMinute / 10, Common::Point(190, 25)); - _vm->_graphicsManager->drawANumber(_vm->_graphicsManager->_vPort, + _vm->_screen->drawANumber(_vm->_screen->_vPort, _vm->_gameMinute % 10, Common::Point(201, 25)); if (_vm->_voy->_RTANum & 4) { int v = _vm->_gameHour / 10; - _vm->_graphicsManager->drawANumber(_vm->_graphicsManager->_vPort, + _vm->_screen->drawANumber(_vm->_screen->_vPort, v == 0 ? 10 : v, Common::Point(161, 25)); - _vm->_graphicsManager->drawANumber(_vm->_graphicsManager->_vPort, + _vm->_screen->drawANumber(_vm->_screen->_vPort, _vm->_gameHour % 10, Common::Point(172, 25)); pic = _vm->_bVoy->boltEntry(_vm->_voy->_isAM ? 272 : 273)._picResource; - _vm->_graphicsManager->sDrawPic(pic, _vm->_graphicsManager->_vPort, + _vm->_screen->sDrawPic(pic, _vm->_screen->_vPort, Common::Point(215, 27)); } } @@ -1605,16 +1605,16 @@ void ThreadResource::loadTheApt() { _vm->_bVoy->getBoltGroup(_vm->_playStampGroupId); _vm->_voy->_aptLoadMode = -1; - _vm->_graphicsManager->_backgroundPage = _vm->_bVoy->boltEntry( + _vm->_screen->_backgroundPage = _vm->_bVoy->boltEntry( _vm->_playStampGroupId + 5)._picResource; - _vm->_graphicsManager->_vPort->setupViewPort( - _vm->_graphicsManager->_backgroundPage); + _vm->_screen->_vPort->setupViewPort( + _vm->_screen->_backgroundPage); } else { _vm->_bVoy->getBoltGroup(_vm->_playStampGroupId); - _vm->_graphicsManager->_backgroundPage = _vm->_bVoy->boltEntry( + _vm->_screen->_backgroundPage = _vm->_bVoy->boltEntry( _vm->_playStampGroupId + 5)._picResource; - _vm->_graphicsManager->_vPort->setupViewPort( - _vm->_graphicsManager->_backgroundPage); + _vm->_screen->_vPort->setupViewPort( + _vm->_screen->_backgroundPage); } CMapResource *pal = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 4)._cMapResource; @@ -1624,10 +1624,10 @@ void ThreadResource::loadTheApt() { } void ThreadResource::freeTheApt() { - _vm->_graphicsManager->fadeDownICF1(5); + _vm->_screen->fadeDownICF1(5); _vm->flipPageAndWaitForFade(); - _vm->_graphicsManager->fadeUpICF1(); + _vm->_screen->fadeUpICF1(); if (_vm->_currentVocId != -1) { _vm->_soundManager->stopVOCPlay(); @@ -1635,17 +1635,17 @@ void ThreadResource::freeTheApt() { } if (_vm->_voy->_aptLoadMode == -1) { - _vm->_graphicsManager->fadeDownICF(6); + _vm->_screen->fadeDownICF(6); } else { doAptAnim(2); } if (_vm->_voy->_aptLoadMode == 140) { - _vm->_graphicsManager->screenReset(); - _vm->_graphicsManager->resetPalette(); + _vm->_screen->screenReset(); + _vm->_screen->resetPalette(); } - _vm->_graphicsManager->_vPort->setupViewPort(nullptr); + _vm->_screen->_vPort->setupViewPort(nullptr); _vm->_bVoy->freeBoltGroup(_vm->_playStampGroupId); _vm->_playStampGroupId = -1; _vm->_voy->_viewBounds = nullptr; @@ -1705,7 +1705,7 @@ void ThreadResource::doAptAnim(int mode) { for (int idx = 0; (idx < 6) && !_vm->shouldQuit(); ++idx) { PictureResource *pic = _vm->_bVoy->boltEntry(id + idx + 1)._picResource; - _vm->_graphicsManager->_vPort->setupViewPort(pic); + _vm->_screen->_vPort->setupViewPort(pic); pal->startFade(); _vm->flipPageAndWait(); diff --git a/engines/voyeur/module.mk b/engines/voyeur/module.mk index aab254cf36..a38bdd9ab2 100644 --- a/engines/voyeur/module.mk +++ b/engines/voyeur/module.mk @@ -8,7 +8,7 @@ MODULE_OBJS := \ events.o \ files.o \ files_threads.o \ - graphics.o \ + screen.o \ sound.o \ staticres.o \ voyeur.o \ diff --git a/engines/voyeur/graphics.cpp b/engines/voyeur/screen.cpp index a20e9f6006..62f609c5c7 100644 --- a/engines/voyeur/graphics.cpp +++ b/engines/voyeur/screen.cpp @@ -20,7 +20,7 @@ * */ -#include "voyeur/graphics.h" +#include "voyeur/screen.h" #include "voyeur/voyeur.h" #include "voyeur/staticres.h" #include "engines/util.h" @@ -38,7 +38,8 @@ DrawInfo::DrawInfo(int penColor, const Common::Point &pos) { /*------------------------------------------------------------------------*/ -GraphicsManager::GraphicsManager(VoyeurEngine *vm) : _defaultDrawInfo(1, Common::Point()), _drawPtr(&_defaultDrawInfo), _vm(vm) { +Screen::Screen(VoyeurEngine *vm) : Graphics::Screen(), _vm(vm), _drawPtr(&_defaultDrawInfo), + _defaultDrawInfo(1, Common::Point()) { _SVGAMode = 0; _planeSelect = 0; _saveBack = true; @@ -52,18 +53,17 @@ GraphicsManager::GraphicsManager(VoyeurEngine *vm) : _defaultDrawInfo(1, Common: _backColors = nullptr; } -void GraphicsManager::sInitGraphics() { +void Screen::sInitGraphics() { initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT, false); - _screenSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8()); + create(SCREEN_WIDTH, SCREEN_HEIGHT); clearPalette(); } -GraphicsManager::~GraphicsManager() { - _screenSurface.free(); +Screen::~Screen() { delete _fontChar; } -void GraphicsManager::setupMCGASaveRect(ViewPortResource *viewPort) { +void Screen::setupMCGASaveRect(ViewPortResource *viewPort) { if (viewPort->_activePage) { viewPort->_activePage->_flags |= DISPFLAG_1; Common::Rect *clipRect = _clipPtr; @@ -77,7 +77,7 @@ void GraphicsManager::setupMCGASaveRect(ViewPortResource *viewPort) { viewPort->_rectListCount[1] = -1; } -void GraphicsManager::addRectOptSaveRect(ViewPortResource *viewPort, int idx, const Common::Rect &bounds) { +void Screen::addRectOptSaveRect(ViewPortResource *viewPort, int idx, const Common::Rect &bounds) { if (viewPort->_rectListCount[idx] == -1) return; @@ -86,7 +86,7 @@ void GraphicsManager::addRectOptSaveRect(ViewPortResource *viewPort, int idx, co ++viewPort->_rectListCount[idx]; } -void GraphicsManager::restoreMCGASaveRect(ViewPortResource *viewPort) { +void Screen::restoreMCGASaveRect(ViewPortResource *viewPort) { if (viewPort->_rectListCount[0] != -1) { for (int i = 0; i < viewPort->_rectListCount[0]; ++i) { addRectOptSaveRect(viewPort, 1, (*viewPort->_rectListPtr[0])[i]); @@ -106,11 +106,11 @@ void GraphicsManager::restoreMCGASaveRect(ViewPortResource *viewPort) { viewPort->_rectListCount[1] = count; } -void GraphicsManager::addRectNoSaveBack(ViewPortResource *viewPort, int idx, const Common::Rect &bounds) { +void Screen::addRectNoSaveBack(ViewPortResource *viewPort, int idx, const Common::Rect &bounds) { // Stubbed/dummy method in the original. } -void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *destDisplay, +void Screen::sDrawPic(DisplayResource *srcDisplay, DisplayResource *destDisplay, const Common::Point &initialOffset) { int width1, width2; int widthDiff, widthDiff2; @@ -128,7 +128,8 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des int runLength; byte *srcImgData, *destImgData; - byte *srcP, *destP; + const byte *srcP; + byte *destP; byte byteVal, byteVal2; PictureResource *srcPic; @@ -292,7 +293,7 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des // loc_2566F if (srcFlags & DISPFLAG_2) { // loc_256FA - srcP = (byte *)_screenSurface.getPixels() + srcOffset; + srcP = (const byte *)getPixels() + srcOffset; for (int yp = 0; yp < height1; ++yp) { for (int xp = 0; xp < width2; ++xp, ++srcP, ++destP) { @@ -325,13 +326,16 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des } } else { // loc_25829 - destP = (byte *)_screenSurface.getPixels() + screenOffset; + destP = (byte *)getPixels() + screenOffset; for (int yp = 0; yp < height1; ++yp) { Common::copy(srcP, srcP + width2, destP); srcP += width2 + widthDiff; destP += width2 + widthDiff2; } + + addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2, + offset.y + height1)); } } } else { @@ -341,13 +345,16 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des error("TODO: sDrawPic variation"); } else { // loc_2606D - destP = (byte *)_screenSurface.getPixels() + screenOffset; + destP = (byte *)getPixels() + screenOffset; for (int yp = 0; yp < height1; ++yp) { Common::copy(srcP, srcP + width2, destP); destP += width2 + widthDiff2; srcP += width2 + widthDiff; } + + addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2, + offset.y + height1)); } } } else { @@ -530,11 +537,14 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des // loc_27477 if (destFlags & DISPFLAG_8) { // loc_27481 - destP = (byte *)_screenSurface.getPixels() + screenOffset; + destP = (byte *)getPixels() + screenOffset; for (int yp = 0; yp < height1; ++yp) { Common::fill(destP, destP + width2, onOff); destP += width2 + widthDiff2; } + + addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2, + offset.y + height1)); } else { // loc_2753C destP = destImgData + screenOffset; @@ -561,7 +571,7 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des if (srcFlags & PICFLAG_100) { if (isClipped) { // loc_266E3 - destP = (byte *)_screenSurface.getPixels() + screenOffset; + destP = (byte *)getPixels() + screenOffset; tmpWidth = (tmpWidth < 0) ? -tmpWidth : 0; int xMax = tmpWidth + width2; tmpHeight = (tmpHeight < 0) ? -tmpHeight : 0; @@ -592,9 +602,12 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des if (yp >= tmpHeight) destP += widthDiff2; } + + addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2, + offset.y + height1)); } else { // loc_26815 - destP = (byte *)_screenSurface.getPixels() + screenOffset; + destP = (byte *)getPixels() + screenOffset; for (int yp = 0; yp < height1; ++yp) { for (int xi = 0; xi < width2; ++xi, ++destP) { @@ -618,10 +631,13 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des destP += widthDiff2; } + + addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2, + offset.y + height1)); } } else { // Direct screen write - destP = (byte *)_screenSurface.getPixels() + screenOffset; + destP = (byte *)getPixels() + screenOffset; for (int yp = 0; yp < height1; ++yp) { for (int xp = 0; xp < width2; ++xp, ++srcP, ++destP) { @@ -631,6 +647,9 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des destP += widthDiff2; srcP += widthDiff; } + + addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2, + offset.y + height1)); } } else if (srcFlags & PICFLAG_100) { srcP = srcImgData; @@ -663,7 +682,7 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des } } else { // loc_26BD5 - destP = (byte *)_screenSurface.getPixels() + screenOffset; + destP = (byte *)getPixels() + screenOffset; for (int yp = 0; yp < height1; ++yp) { byteVal2 = 0; @@ -684,10 +703,13 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des destP += widthDiff2; } + + addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2, + offset.y + height1)); } } else { // loc_26C9A - destP = (byte *)_screenSurface.getPixels() + screenOffset; + destP = (byte *)getPixels() + screenOffset; for (int yp = 0; yp < height1; ++yp) { for (int xp = 0; xp < width2; ++xp, ++srcP, ++destP) { @@ -696,6 +718,9 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des destP += widthDiff2; srcP += widthDiff; } + + addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2, + offset.y + height1)); } } else { // loc_26D2F @@ -850,12 +875,12 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des } } -void GraphicsManager::drawANumber(DisplayResource *display, int num, const Common::Point &pt) { +void Screen::drawANumber(DisplayResource *display, int num, const Common::Point &pt) { PictureResource *pic = _vm->_bVoy->boltEntry(num + 261)._picResource; sDrawPic(pic, display, pt); } -void GraphicsManager::fillPic(DisplayResource *display, byte onOff) { +void Screen::fillPic(DisplayResource *display, byte onOff) { PictureResource *pic; if (display->_flags & DISPFLAG_VIEWPORT) { pic = ((ViewPortResource *)display)->_currentPic; @@ -876,11 +901,11 @@ void GraphicsManager::fillPic(DisplayResource *display, byte onOff) { /** * Queues the given picture for display */ -void GraphicsManager::sDisplayPic(PictureResource *pic) { +void Screen::sDisplayPic(PictureResource *pic) { _vm->_eventsManager->_intPtr._flipWait = true; } -void GraphicsManager::flipPage() { +void Screen::flipPage() { Common::Array<ViewPortResource *> &viewPorts = _viewPortListPtr->_entries; bool flipFlag = false; @@ -907,7 +932,7 @@ void GraphicsManager::flipPage() { } } -void GraphicsManager::restoreBack(Common::Array<Common::Rect> &rectList, int rectListCount, +void Screen::restoreBack(Common::Array<Common::Rect> &rectList, int rectListCount, PictureResource *srcPic, PictureResource *destPic) { // WORKAROUND: Since _backgroundPage can point to a resource freed at the end of display methods, // I'm now explicitly resetting it to null in screenReset(), so at this point it can be null @@ -929,33 +954,26 @@ void GraphicsManager::restoreBack(Common::Array<Common::Rect> &rectList, int rec _saveBack = saveBack; } -void GraphicsManager::clearPalette() { - byte palette[768]; - Common::fill(&palette[0], &palette[768], 0); - g_system->getPaletteManager()->setPalette(&palette[0], 0, 256); -} - -void GraphicsManager::setPalette(const byte *palette, int start, int count) { - g_system->getPaletteManager()->setPalette(palette, start, count); +void Screen::setPalette(const byte *palette, int start, int count) { + Graphics::Screen::setPalette(palette, start, count); _vm->_eventsManager->_gameData._hasPalette = false; } -void GraphicsManager::setPalette128(const byte *palette, int start, int count) { +void Screen::setPalette128(const byte *palette, int start, int count) { byte rgb[3]; - g_system->getPaletteManager()->grabPalette(&rgb[0], 128, 1); - g_system->getPaletteManager()->setPalette(palette, start, count); - g_system->getPaletteManager()->setPalette(&rgb[0], 128, 1); + getPalette(&rgb[0], 128, 1); + Graphics::Screen::setPalette(palette, start, count); + Graphics::Screen::setPalette(&rgb[0], 128, 1); } - -void GraphicsManager::resetPalette() { +void Screen::resetPalette() { for (int i = 0; i < 256; ++i) setColor(i, 0, 0, 0); _vm->_eventsManager->_intPtr._hasPalette = true; } -void GraphicsManager::setColor(int idx, byte r, byte g, byte b) { +void Screen::setColor(int idx, byte r, byte g, byte b) { byte *vgaP = &_VGAColors[idx * 3]; vgaP[0] = r; vgaP[1] = g; @@ -965,7 +983,7 @@ void GraphicsManager::setColor(int idx, byte r, byte g, byte b) { _vm->_eventsManager->_intPtr._palEndIndex = MAX(_vm->_eventsManager->_intPtr._palEndIndex, idx); } -void GraphicsManager::setOneColor(int idx, byte r, byte g, byte b) { +void Screen::setOneColor(int idx, byte r, byte g, byte b) { byte palEntry[3]; palEntry[0] = r; palEntry[1] = g; @@ -973,7 +991,7 @@ void GraphicsManager::setOneColor(int idx, byte r, byte g, byte b) { g_system->getPaletteManager()->setPalette(&palEntry[0], idx, 1); } -void GraphicsManager::setColors(int start, int count, const byte *pal) { +void Screen::setColors(int start, int count, const byte *pal) { for (int i = 0; i < count; ++i) { if ((i + start) != 128) { const byte *rgb = pal + i * 3; @@ -984,7 +1002,7 @@ void GraphicsManager::setColors(int start, int count, const byte *pal) { _vm->_eventsManager->_intPtr._hasPalette = true; } -void GraphicsManager::screenReset() { +void Screen::screenReset() { resetPalette(); _backgroundPage = NULL; @@ -994,7 +1012,7 @@ void GraphicsManager::screenReset() { _vm->flipPageAndWait(); } -void GraphicsManager::fadeDownICF1(int steps) { +void Screen::fadeDownICF1(int steps) { if (steps > 0) { int stepAmount = _vm->_voy->_fadingAmount2 / steps; @@ -1007,7 +1025,7 @@ void GraphicsManager::fadeDownICF1(int steps) { _vm->_voy->_fadingAmount2 = 0; } -void GraphicsManager::fadeUpICF1(int steps) { +void Screen::fadeUpICF1(int steps) { if (steps > 0) { int stepAmount = (63 - _vm->_voy->_fadingAmount2) / steps; @@ -1020,7 +1038,7 @@ void GraphicsManager::fadeUpICF1(int steps) { _vm->_voy->_fadingAmount2 = 63; } -void GraphicsManager::fadeDownICF(int steps) { +void Screen::fadeDownICF(int steps) { if (steps > 0) { _vm->_eventsManager->hideCursor(); int stepAmount1 = _vm->_voy->_fadingAmount1 / steps; @@ -1037,14 +1055,19 @@ void GraphicsManager::fadeDownICF(int steps) { _vm->_voy->_fadingAmount2 = 0; } -void GraphicsManager::drawDot() { - for (int y = 0; y < 9; ++y) { - byte *pDest = (byte *)_screenSurface.getPixels() + DOT_LINE_START[y] + DOT_LINE_OFFSET[y]; - Common::fill(pDest, pDest + DOT_LINE_LENGTH[y], 0x80); +void Screen::drawDot() { + for (int idx = 0; idx < 9; ++idx) { + uint offset = DOT_LINE_START[idx] + DOT_LINE_OFFSET[idx]; + int xp = offset % SCREEN_WIDTH; + int yp = offset / SCREEN_WIDTH; + + byte *pDest = (byte *)getPixels() + offset; + Common::fill(pDest, pDest + DOT_LINE_LENGTH[idx], 0x80); + addDirtyRect(Common::Rect(xp, yp, xp + DOT_LINE_LENGTH[idx], yp + 1)); } } -void GraphicsManager::synchronize(Common::Serializer &s) { +void Screen::synchronize(Common::Serializer &s) { s.syncBytes(&_VGAColors[0], PALETTE_SIZE); } diff --git a/engines/voyeur/graphics.h b/engines/voyeur/screen.h index e4d0b38650..aaf61747a4 100644 --- a/engines/voyeur/graphics.h +++ b/engines/voyeur/screen.h @@ -27,17 +27,15 @@ #include "common/array.h" #include "common/rect.h" #include "common/serializer.h" -#include "graphics/surface.h" +#include "graphics/screen.h" namespace Voyeur { #define SCREEN_WIDTH 320 #define SCREEN_HEIGHT 200 -#define PALETTE_COUNT 256 -#define PALETTE_SIZE (256 * 3) class VoyeurEngine; -class GraphicsManager; +class Screen; class DisplayResource; class PictureResource; class ViewPortResource; @@ -54,12 +52,12 @@ public: DrawInfo(int penColor, const Common::Point &pos); }; -typedef void (GraphicsManager::*GraphicMethodPtr)(); -typedef void (GraphicsManager::*ViewPortSetupPtr)(ViewPortResource *); -typedef void (GraphicsManager::*ViewPortAddPtr)(ViewPortResource *, int idx, const Common::Rect &bounds); -typedef void (GraphicsManager::*ViewPortRestorePtr)(ViewPortResource *); +typedef void (Screen::*ScreenMethodPtr)(); +typedef void (Screen::*ViewPortSetupPtr)(ViewPortResource *); +typedef void (Screen::*ViewPortAddPtr)(ViewPortResource *, int idx, const Common::Rect &bounds); +typedef void (Screen::*ViewPortRestorePtr)(ViewPortResource *); -class GraphicsManager { +class Screen: public Graphics::Screen { public: byte _VGAColors[PALETTE_SIZE]; PictureResource *_backgroundPage; @@ -69,7 +67,6 @@ public: bool _saveBack; Common::Rect *_clipPtr; uint _planeSelect; - Graphics::Surface _screenSurface; CMapResource *_backColors; FontInfoResource *_fontPtr; PictureResource *_fontChar; @@ -81,8 +78,8 @@ private: void restoreBack(Common::Array<Common::Rect> &rectList, int rectListCount, PictureResource *srcPic, PictureResource *destPic); public: - GraphicsManager(VoyeurEngine *vm); - ~GraphicsManager(); + Screen(VoyeurEngine *vm); + virtual ~Screen(); void sInitGraphics(); @@ -96,7 +93,6 @@ public: void sDisplayPic(PictureResource *pic); void drawANumber(DisplayResource *display, int num, const Common::Point &pt); void flipPage(); - void clearPalette(); void setPalette(const byte *palette, int start, int count); void setPalette128(const byte *palette, int start, int count); void resetPalette(); diff --git a/engines/voyeur/voyeur.cpp b/engines/voyeur/voyeur.cpp index cbb6846340..01b76a72d1 100644 --- a/engines/voyeur/voyeur.cpp +++ b/engines/voyeur/voyeur.cpp @@ -22,7 +22,7 @@ #include "voyeur/voyeur.h" #include "voyeur/animation.h" -#include "voyeur/graphics.h" +#include "voyeur/screen.h" #include "voyeur/staticres.h" #include "common/scummsys.h" #include "common/config-manager.h" @@ -40,7 +40,7 @@ VoyeurEngine::VoyeurEngine(OSystem *syst, const VoyeurGameDescription *gameDesc) _debugger = nullptr; _eventsManager = nullptr; _filesManager = nullptr; - _graphicsManager = nullptr; + _screen = nullptr; _soundManager = nullptr; _voy = nullptr; _bVoy = NULL; @@ -65,13 +65,6 @@ VoyeurEngine::VoyeurEngine(OSystem *syst, const VoyeurGameDescription *gameDesc) DebugMan.addDebugChannel(kDebugScripts, "scripts", "Game scripts"); - _debugger = new Debugger(this); - _eventsManager = new EventsManager(this); - _filesManager = new FilesManager(this); - _graphicsManager = new GraphicsManager(this); - _soundManager = new SoundManager(_mixer); - _voy = new SVoy(this); - _stampLibPtr = nullptr; _controlGroupPtr = nullptr; _stampData = nullptr; @@ -88,7 +81,7 @@ VoyeurEngine::~VoyeurEngine() { delete _bVoy; delete _voy; delete _soundManager; - delete _graphicsManager; + delete _screen; delete _filesManager; delete _eventsManager; delete _debugger; @@ -126,15 +119,22 @@ void VoyeurEngine::ESP_Init() { } void VoyeurEngine::globalInitBolt() { + _debugger = new Debugger(this); + _eventsManager = new EventsManager(this); + _filesManager = new FilesManager(this); + _screen = new Screen(this); + _soundManager = new SoundManager(_mixer); + _voy = new SVoy(this); + initBolt(); _filesManager->openBoltLib("bvoy.blt", _bVoy); _bVoy->getBoltGroup(0x000); _bVoy->getBoltGroup(0x100); - _graphicsManager->_fontPtr = &_defaultFontInfo; - _graphicsManager->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource; - assert(_graphicsManager->_fontPtr->_curFont); + _screen->_fontPtr = &_defaultFontInfo; + _screen->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource; + assert(_screen->_fontPtr->_curFont); // Setup default flags _voy->_viewBounds = nullptr; @@ -144,13 +144,13 @@ void VoyeurEngine::globalInitBolt() { void VoyeurEngine::initBolt() { vInitInterrupts(); - _graphicsManager->sInitGraphics(); + _screen->sInitGraphics(); _eventsManager->vInitColor(); initInput(); } void VoyeurEngine::vInitInterrupts() { - _eventsManager->_intPtr._palette = &_graphicsManager->_VGAColors[0]; + _eventsManager->_intPtr._palette = &_screen->_VGAColors[0]; } void VoyeurEngine::initInput() { @@ -213,8 +213,8 @@ bool VoyeurEngine::doHeadTitle() { } void VoyeurEngine::showConversionScreen() { - _graphicsManager->_backgroundPage = _bVoy->boltEntry(0x502)._picResource; - _graphicsManager->_vPort->setupViewPort(); + _screen->_backgroundPage = _bVoy->boltEntry(0x502)._picResource; + _screen->_vPort->setupViewPort(); flipPageAndWait(); // Immediate palette load to show the initial screen @@ -237,7 +237,7 @@ void VoyeurEngine::showConversionScreen() { flipPageAndWaitForFade(); - _graphicsManager->screenReset(); + _screen->screenReset(); } bool VoyeurEngine::doLock() { @@ -249,28 +249,28 @@ bool VoyeurEngine::doLock() { if (_bVoy->getBoltGroup(0x700)) { Common::String password = "3333"; - _graphicsManager->_backgroundPage = _bVoy->getPictureResource(0x700); - _graphicsManager->_backColors = _bVoy->getCMapResource(0x701); + _screen->_backgroundPage = _bVoy->getPictureResource(0x700); + _screen->_backColors = _bVoy->getCMapResource(0x701); PictureResource *cursorPic = _bVoy->getPictureResource(0x702); _voy->_viewBounds = _bVoy->boltEntry(0x704)._rectResource; Common::Array<RectEntry> &hotspots = _bVoy->boltEntry(0x705)._rectResource->_entries; assert(cursorPic); - _graphicsManager->_vPort->setupViewPort(); + _screen->_vPort->setupViewPort(); - _graphicsManager->_backColors->startFade(); - _graphicsManager->_vPort->_parent->_flags |= DISPFLAG_8; - _graphicsManager->flipPage(); + _screen->_backColors->startFade(); + _screen->_vPort->_parent->_flags |= DISPFLAG_8; + _screen->flipPage(); _eventsManager->sWaitFlip(); while (!shouldQuit() && (_eventsManager->_fadeStatus & 1)) _eventsManager->delay(1); _eventsManager->setCursorColor(127, 0); - _graphicsManager->setColor(1, 64, 64, 64); - _graphicsManager->setColor(2, 96, 96, 96); - _graphicsManager->setColor(3, 160, 160, 160); - _graphicsManager->setColor(4, 224, 224, 224); + _screen->setColor(1, 64, 64, 64); + _screen->setColor(2, 96, 96, 96); + _screen->setColor(3, 160, 160, 160); + _screen->setColor(4, 224, 224, 224); // Set up the cursor _eventsManager->setCursor(cursorPic); @@ -278,9 +278,9 @@ bool VoyeurEngine::doLock() { _eventsManager->_intPtr._hasPalette = true; - _graphicsManager->_fontPtr->_curFont = _bVoy->boltEntry(0x708)._fontResource; - _graphicsManager->_fontPtr->_fontSaveBack = 0; - _graphicsManager->_fontPtr->_fontFlags = DISPFLAG_NONE; + _screen->_fontPtr->_curFont = _bVoy->boltEntry(0x708)._fontResource; + _screen->_fontPtr->_fontSaveBack = 0; + _screen->_fontPtr->_fontFlags = DISPFLAG_NONE; Common::String dateString = "ScummVM"; Common::String displayString = Common::String::format("Last Play %s", dateString.c_str()); @@ -288,16 +288,16 @@ bool VoyeurEngine::doLock() { bool firstLoop = true; bool breakFlag = false; while (!breakFlag && !shouldQuit()) { - _graphicsManager->_vPort->setupViewPort(); + _screen->_vPort->setupViewPort(); flipPageAndWait(); // Display the last play time - _graphicsManager->_fontPtr->_pos = Common::Point(0, 97); - _graphicsManager->_fontPtr->_justify = ALIGN_CENTER; - _graphicsManager->_fontPtr->_justifyWidth = 384; - _graphicsManager->_fontPtr->_justifyHeight = 97; + _screen->_fontPtr->_pos = Common::Point(0, 97); + _screen->_fontPtr->_justify = ALIGN_CENTER; + _screen->_fontPtr->_justifyWidth = 384; + _screen->_fontPtr->_justifyHeight = 97; - _graphicsManager->_vPort->drawText(displayString); + _screen->_vPort->drawText(displayString); flipPageAndWait(); if (firstLoop) { @@ -356,7 +356,7 @@ bool VoyeurEngine::doLock() { } else if (key == 11) { // New code if ((password.empty() && displayString.empty()) || (password != displayString)) { - _graphicsManager->_vPort->setupViewPort(); + _screen->_vPort->setupViewPort(); password = displayString; displayString = ""; continue; @@ -373,9 +373,9 @@ bool VoyeurEngine::doLock() { _soundManager->playVOCMap(wrongVoc, wrongVocSize); } - _graphicsManager->fillPic(_graphicsManager->_vPort, 0); + _screen->fillPic(_screen->_vPort, 0); flipPageAndWait(); - _graphicsManager->resetPalette(); + _screen->resetPalette(); _voy->_viewBounds = nullptr; _bVoy->freeBoltGroup(0x700); @@ -393,9 +393,9 @@ void VoyeurEngine::showTitleScreen() { if (!_bVoy->getBoltGroup(0x500)) return; - _graphicsManager->_backgroundPage = _bVoy->getPictureResource(0x500); + _screen->_backgroundPage = _bVoy->getPictureResource(0x500); - _graphicsManager->_vPort->setupViewPort(); + _screen->_vPort->setupViewPort(); flipPageAndWait(); // Immediate palette load to show the initial screen @@ -422,18 +422,18 @@ void VoyeurEngine::showTitleScreen() { return; } - _graphicsManager->screenReset(); + _screen->screenReset(); _eventsManager->delayClick(200); // Voyeur title playRL2Video("a1100100.rl2"); - _graphicsManager->screenReset(); + _screen->screenReset(); _bVoy->freeBoltGroup(0x500); } void VoyeurEngine::doOpening() { - _graphicsManager->screenReset(); + _screen->screenReset(); if (!_bVoy->getBoltGroup(0x200)) return; @@ -459,10 +459,10 @@ void VoyeurEngine::doOpening() { _voy->_eventFlags &= ~EVTFLAG_TIME_DISABLED; for (int i = 0; i < 256; ++i) - _graphicsManager->setColor(i, 8, 8, 8); + _screen->setColor(i, 8, 8, 8); _eventsManager->_intPtr._hasPalette = true; - _graphicsManager->_vPort->setupViewPort(); + _screen->_vPort->setupViewPort(); flipPageAndWait(); RL2Decoder decoder; @@ -472,14 +472,12 @@ void VoyeurEngine::doOpening() { while (!shouldQuit() && !decoder.endOfVideo() && !_eventsManager->_mouseClicked) { if (decoder.hasDirtyPalette()) { const byte *palette = decoder.getPalette(); - _graphicsManager->setPalette(palette, 0, 256); + _screen->setPalette(palette, 0, 256); } if (decoder.needsUpdate()) { const Graphics::Surface *frame = decoder.decodeNextFrame(); - - Common::copy((const byte *)frame->getPixels(), (const byte *)frame->getPixels() + 320 * 200, - (byte *)_graphicsManager->_screenSurface.getPixels()); + _screen->blitFrom(*frame); if (decoder.getCurFrame() >= (int32)READ_LE_UINT32(frameTable + frameIndex * 4)) { if (creditShow) { @@ -499,7 +497,7 @@ void VoyeurEngine::doOpening() { } if (textPic) { - _graphicsManager->sDrawPic(textPic, _graphicsManager->_vPort, textPos); + _screen->sDrawPic(textPic, _screen->_vPort, textPos); } flipPageAndWait(); @@ -527,14 +525,12 @@ void VoyeurEngine::playRL2Video(const Common::String &filename) { while (!shouldQuit() && !decoder.endOfVideo() && !_eventsManager->_mouseClicked) { if (decoder.hasDirtyPalette()) { const byte *palette = decoder.getPalette(); - _graphicsManager->setPalette(palette, 0, 256); + _screen->setPalette(palette, 0, 256); } if (decoder.needsUpdate()) { const Graphics::Surface *frame = decoder.decodeNextFrame(); - - Common::copy((const byte *)frame->getPixels(), (const byte *)frame->getPixels() + 320 * 200, - (byte *)_graphicsManager->_screenSurface.getPixels()); + _screen->blitFrom(*frame); } _eventsManager->getMouseInfo(); @@ -573,17 +569,16 @@ void VoyeurEngine::playAVideoDuration(int videoId, int duration) { (decoder.getCurFrame() < endFrame)) { if (decoder.needsUpdate()) { const Graphics::Surface *frame = decoder.decodeNextFrame(); + _screen->blitFrom(*frame); - Common::copy((const byte *)frame->getPixels(), (const byte *)frame->getPixels() + 320 * 200, - (byte *)_graphicsManager->_screenSurface.getPixels()); if (_voy->_eventFlags & EVTFLAG_RECORDING) - _graphicsManager->drawDot(); + _screen->drawDot(); } if (decoder.hasDirtyPalette()) { const byte *palette = decoder.getPalette(); - _graphicsManager->setPalette(palette, 0, decoder.getPaletteCount()); - _graphicsManager->setOneColor(128, 220, 20, 20); + _screen->setPalette(palette, 0, decoder.getPaletteCount()); + _screen->setOneColor(128, 220, 20, 20); } _eventsManager->getMouseInfo(); @@ -591,13 +586,13 @@ void VoyeurEngine::playAVideoDuration(int videoId, int duration) { } // RL2 finished - _graphicsManager->screenReset(); + _screen->screenReset(); _voy->_eventFlags &= ~EVTFLAG_RECORDING; if (_voy->_eventFlags & EVTFLAG_8) { assert(pic); - byte *imgData = _graphicsManager->_vPort->_currentPic->_imgData; - _graphicsManager->_vPort->_currentPic->_imgData = pic->_imgData; + byte *imgData = _screen->_vPort->_currentPic->_imgData; + _screen->_vPort->_currentPic->_imgData = pic->_imgData; pic->_imgData = imgData; _voy->_eventFlags &= ~EVTFLAG_8; } @@ -608,13 +603,13 @@ void VoyeurEngine::playAVideoDuration(int videoId, int duration) { void VoyeurEngine::playAudio(int audioId) { _bVoy->getBoltGroup(0x7F00); - _graphicsManager->_backgroundPage = _bVoy->boltEntry(0x7F00 + + _screen->_backgroundPage = _bVoy->boltEntry(0x7F00 + BLIND_TABLE[audioId] * 2)._picResource; - _graphicsManager->_backColors = _bVoy->boltEntry(0x7F01 + + _screen->_backColors = _bVoy->boltEntry(0x7F01 + BLIND_TABLE[audioId] * 2)._cMapResource; - _graphicsManager->_vPort->setupViewPort(); - _graphicsManager->_backColors->startFade(); + _screen->_vPort->setupViewPort(); + _screen->_backColors->startFade(); flipPageAndWaitForFade(); _voy->_eventFlags &= ~EVTFLAG_TIME_DISABLED; @@ -633,26 +628,26 @@ void VoyeurEngine::playAudio(int audioId) { _soundManager->stopVOCPlay(); _bVoy->freeBoltGroup(0x7F00); - _graphicsManager->_vPort->setupViewPort(NULL); + _screen->_vPort->setupViewPort(NULL); _voy->_eventFlags &= ~EVTFLAG_RECORDING; _voy->_playStampMode = 129; } void VoyeurEngine::doTransitionCard(const Common::String &time, const Common::String &location) { - _graphicsManager->setColor(128, 16, 16, 16); - _graphicsManager->setColor(224, 220, 220, 220); + _screen->setColor(128, 16, 16, 16); + _screen->setColor(224, 220, 220, 220); _eventsManager->_intPtr._hasPalette = true; - _graphicsManager->_vPort->setupViewPort(NULL); - _graphicsManager->_vPort->fillPic(0x80); - _graphicsManager->flipPage(); + _screen->_vPort->setupViewPort(NULL); + _screen->_vPort->fillPic(0x80); + _screen->flipPage(); _eventsManager->sWaitFlip(); flipPageAndWait(); - _graphicsManager->_vPort->fillPic(0x80); + _screen->_vPort->fillPic(0x80); - FontInfoResource &fi = *_graphicsManager->_fontPtr; + FontInfoResource &fi = *_screen->_fontPtr; fi._curFont = _bVoy->boltEntry(257)._fontResource; fi._foreColor = 224; fi._fontSaveBack = 0; @@ -661,7 +656,7 @@ void VoyeurEngine::doTransitionCard(const Common::String &time, const Common::St fi._justifyWidth = 384; fi._justifyHeight = 120; - _graphicsManager->_vPort->drawText(time); + _screen->_vPort->drawText(time); if (!location.empty()) { fi._pos = Common::Point(0, 138); @@ -669,7 +664,7 @@ void VoyeurEngine::doTransitionCard(const Common::String &time, const Common::St fi._justifyWidth = 384; fi._justifyHeight = 140; - _graphicsManager->_vPort->drawText(location); + _screen->_vPort->drawText(location); } flipPageAndWait(); @@ -680,8 +675,8 @@ void VoyeurEngine::saveLastInplay() { } void VoyeurEngine::flipPageAndWait() { - _graphicsManager->_vPort->_flags |= DISPFLAG_8; - _graphicsManager->flipPage(); + _screen->_vPort->_flags |= DISPFLAG_8; + _screen->flipPage(); _eventsManager->sWaitFlip(); } @@ -702,7 +697,7 @@ void VoyeurEngine::showEndingNews() { PictureResource *pic = _bVoy->boltEntry(_playStampGroupId)._picResource; CMapResource *pal = _bVoy->boltEntry(_playStampGroupId + 1)._cMapResource; - _graphicsManager->_vPort->setupViewPort(pic); + _screen->_vPort->setupViewPort(pic); pal->startFade(); flipPageAndWaitForFade(); @@ -717,7 +712,7 @@ void VoyeurEngine::showEndingNews() { pal = _bVoy->boltEntry(_playStampGroupId + idx * 2 + 1)._cMapResource; } - _graphicsManager->_vPort->setupViewPort(pic); + _screen->_vPort->setupViewPort(pic); pal->startFade(); flipPageAndWaitForFade(); @@ -852,7 +847,7 @@ void VoyeurEngine::synchronize(Common::Serializer &s) { // Sub-systems _voy->synchronize(s); - _graphicsManager->synchronize(s); + _screen->synchronize(s); _mainThread->synchronize(s); _controlPtr->_state->synchronize(s); } @@ -906,8 +901,8 @@ void VoyeurSavegameHeader::write(Common::OutSaveFile *f, VoyeurEngine *vm, const // Create a thumbnail and save it Graphics::Surface *thumb = new Graphics::Surface(); - ::createThumbnail(thumb, (byte *)vm->_graphicsManager->_screenSurface.getPixels(), - SCREEN_WIDTH, SCREEN_HEIGHT, vm->_graphicsManager->_VGAColors); + ::createThumbnail(thumb, (const byte *)vm->_screen->getPixels(), + SCREEN_WIDTH, SCREEN_HEIGHT, vm->_screen->_VGAColors); Graphics::saveThumbnail(*f, *thumb); thumb->free(); delete thumb; diff --git a/engines/voyeur/voyeur.h b/engines/voyeur/voyeur.h index e0bb734fa8..9cda85fd51 100644 --- a/engines/voyeur/voyeur.h +++ b/engines/voyeur/voyeur.h @@ -27,7 +27,7 @@ #include "voyeur/data.h" #include "voyeur/events.h" #include "voyeur/files.h" -#include "voyeur/graphics.h" +#include "voyeur/screen.h" #include "voyeur/sound.h" #include "common/scummsys.h" #include "common/system.h" @@ -164,7 +164,7 @@ public: Debugger *_debugger; EventsManager *_eventsManager; FilesManager *_filesManager; - GraphicsManager *_graphicsManager; + Screen *_screen; SoundManager *_soundManager; SVoy *_voy; diff --git a/engines/voyeur/voyeur_game.cpp b/engines/voyeur/voyeur_game.cpp index 13ef31839a..e9591955fc 100644 --- a/engines/voyeur/voyeur_game.cpp +++ b/engines/voyeur/voyeur_game.cpp @@ -149,8 +149,8 @@ void VoyeurEngine::playStamp() { case 130: { // user selected to send the tape if (_bVoy->getBoltGroup(_playStampGroupId)) { - _graphicsManager->_backgroundPage = _bVoy->boltEntry(_playStampGroupId)._picResource; - _graphicsManager->_backColors = _bVoy->boltEntry(_playStampGroupId + 1)._cMapResource; + _screen->_backgroundPage = _bVoy->boltEntry(_playStampGroupId)._picResource; + _screen->_backColors = _bVoy->boltEntry(_playStampGroupId + 1)._cMapResource; buttonId = getChooseButton(); if (_eventsManager->_rightClick) @@ -158,7 +158,7 @@ void VoyeurEngine::playStamp() { buttonId = 4; _bVoy->freeBoltGroup(_playStampGroupId); - _graphicsManager->screenReset(); + _screen->screenReset(); _playStampGroupId = -1; flag = true; @@ -232,8 +232,8 @@ void VoyeurEngine::closeStamp() { } void VoyeurEngine::doTailTitle() { - _graphicsManager->_vPort->setupViewPort(NULL); - _graphicsManager->screenReset(); + _screen->_vPort->setupViewPort(NULL); + _screen->screenReset(); if (_bVoy->getBoltGroup(0x600)) { RL2Decoder decoder; @@ -245,12 +245,12 @@ void VoyeurEngine::doTailTitle() { doClosingCredits(); if (!shouldQuit() && !_eventsManager->_mouseClicked) { - _graphicsManager->screenReset(); + _screen->screenReset(); PictureResource *pic = _bVoy->boltEntry(0x602)._picResource; CMapResource *pal = _bVoy->boltEntry(0x603)._cMapResource; - _graphicsManager->_vPort->setupViewPort(pic); + _screen->_vPort->setupViewPort(pic); pal->startFade(); flipPageAndWaitForFade(); _eventsManager->delayClick(300); @@ -258,7 +258,7 @@ void VoyeurEngine::doTailTitle() { pic = _bVoy->boltEntry(0x604)._picResource; pal = _bVoy->boltEntry(0x605)._cMapResource; - _graphicsManager->_vPort->setupViewPort(pic); + _screen->_vPort->setupViewPort(pic); pal->startFade(); flipPageAndWaitForFade(); _eventsManager->delayClick(120); @@ -283,26 +283,26 @@ void VoyeurEngine::doClosingCredits() { const char *msg = (const char *)_bVoy->memberAddr(0x404); const byte *creditList = (const byte *)_bVoy->memberAddr(0x405); - _graphicsManager->_vPort->setupViewPort(NULL); - _graphicsManager->setColor(1, 180, 180, 180); - _graphicsManager->setColor(2, 200, 200, 200); + _screen->_vPort->setupViewPort(NULL); + _screen->setColor(1, 180, 180, 180); + _screen->setColor(2, 200, 200, 200); _eventsManager->_intPtr._hasPalette = true; - _graphicsManager->_fontPtr->_curFont = _bVoy->boltEntry(0x402)._fontResource; - _graphicsManager->_fontPtr->_foreColor = 2; - _graphicsManager->_fontPtr->_backColor = 2; - _graphicsManager->_fontPtr->_fontSaveBack = false; - _graphicsManager->_fontPtr->_fontFlags = DISPFLAG_NONE; + _screen->_fontPtr->_curFont = _bVoy->boltEntry(0x402)._fontResource; + _screen->_fontPtr->_foreColor = 2; + _screen->_fontPtr->_backColor = 2; + _screen->_fontPtr->_fontSaveBack = false; + _screen->_fontPtr->_fontFlags = DISPFLAG_NONE; _soundManager->startVOCPlay(152); - FontInfoResource &fi = *_graphicsManager->_fontPtr; + FontInfoResource &fi = *_screen->_fontPtr; for (int idx = 0; idx < 78; ++idx) { const byte *entry = creditList + idx * 6; int flags = READ_LE_UINT16(entry + 4); if (flags & 0x10) - _graphicsManager->_vPort->fillPic(0); + _screen->_vPort->fillPic(0); if (flags & 1) { fi._foreColor = 1; @@ -312,7 +312,7 @@ void VoyeurEngine::doClosingCredits() { fi._justifyHeight = 240; fi._pos = Common::Point(0, READ_LE_UINT16(entry)); - _graphicsManager->_vPort->drawText(msg); + _screen->_vPort->drawText(msg); msg += strlen(msg) + 1; } @@ -324,7 +324,7 @@ void VoyeurEngine::doClosingCredits() { fi._justifyHeight = 240; fi._pos = Common::Point(0, READ_LE_UINT16(entry)); - _graphicsManager->_vPort->drawText(msg); + _screen->_vPort->drawText(msg); msg += strlen(msg) + 1; } @@ -336,7 +336,7 @@ void VoyeurEngine::doClosingCredits() { fi._justifyHeight = 240; fi._pos = Common::Point(38, READ_LE_UINT16(entry)); - _graphicsManager->_vPort->drawText(msg); + _screen->_vPort->drawText(msg); msg += strlen(msg) + 1; fi._foreColor = 2; @@ -345,7 +345,7 @@ void VoyeurEngine::doClosingCredits() { fi._justifyHeight = 240; fi._pos = Common::Point(198, READ_LE_UINT16(entry)); - _graphicsManager->_vPort->drawText(msg); + _screen->_vPort->drawText(msg); msg += strlen(msg) + 1; } @@ -357,7 +357,7 @@ void VoyeurEngine::doClosingCredits() { fi._justifyHeight = 240; fi._pos = Common::Point(0, READ_LE_UINT16(entry)); - _graphicsManager->_vPort->drawText(msg); + _screen->_vPort->drawText(msg); msg += strlen(msg) + 1; fi._foreColor = 2; @@ -367,7 +367,7 @@ void VoyeurEngine::doClosingCredits() { fi._justifyHeight = 240; fi._pos = Common::Point(0, READ_LE_UINT16(entry) + 13); - _graphicsManager->_vPort->drawText(msg); + _screen->_vPort->drawText(msg); msg += strlen(msg) + 1; } @@ -381,19 +381,19 @@ void VoyeurEngine::doClosingCredits() { } _soundManager->stopVOCPlay(); - _graphicsManager->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource; + _screen->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource; _bVoy->freeBoltGroup(0x400); } void VoyeurEngine::doPiracy() { - _graphicsManager->screenReset(); - _graphicsManager->setColor(1, 0, 0, 0); - _graphicsManager->setColor(2, 255, 255, 255); + _screen->screenReset(); + _screen->setColor(1, 0, 0, 0); + _screen->setColor(2, 255, 255, 255); _eventsManager->_intPtr._hasPalette = true; - _graphicsManager->_vPort->setupViewPort(NULL); - _graphicsManager->_vPort->fillPic(1); + _screen->_vPort->setupViewPort(NULL); + _screen->_vPort->fillPic(1); - FontInfoResource &fi = *_graphicsManager->_fontPtr; + FontInfoResource &fi = *_screen->_fontPtr; fi._curFont = _bVoy->boltEntry(0x101)._fontResource; fi._foreColor = 2; fi._backColor = 2; @@ -406,7 +406,7 @@ void VoyeurEngine::doPiracy() { // Loop through the piracy message array to draw each line for (int idx = 0, yp = 33; idx < 10; ++idx) { fi._pos = Common::Point(0, yp); - _graphicsManager->_vPort->drawText(PIRACY_MESSAGE[idx]); + _screen->_vPort->drawText(PIRACY_MESSAGE[idx]); yp += fi._curFont->_fontHeight + 4; } @@ -439,27 +439,27 @@ void VoyeurEngine::reviewTape() { _voy->_viewBounds = _bVoy->boltEntry(0x907)._rectResource; Common::Array<RectEntry> &hotspots = _bVoy->boltEntry(0x906)._rectResource->_entries; - _graphicsManager->_backColors = _bVoy->boltEntry(0x902)._cMapResource; - _graphicsManager->_backgroundPage = _bVoy->boltEntry(0x901)._picResource; - _graphicsManager->_vPort->setupViewPort(_graphicsManager->_backgroundPage); - _graphicsManager->_backColors->startFade(); + _screen->_backColors = _bVoy->boltEntry(0x902)._cMapResource; + _screen->_backgroundPage = _bVoy->boltEntry(0x901)._picResource; + _screen->_vPort->setupViewPort(_screen->_backgroundPage); + _screen->_backColors->startFade(); flipPageAndWaitForFade(); - _graphicsManager->setColor(1, 32, 32, 32); - _graphicsManager->setColor(2, 96, 96, 96); - _graphicsManager->setColor(3, 160, 160, 160); - _graphicsManager->setColor(4, 224, 224, 224); - _graphicsManager->setColor(9, 24, 64, 24); - _graphicsManager->setColor(10, 64, 132, 64); - _graphicsManager->setColor(11, 100, 192, 100); - _graphicsManager->setColor(12, 120, 248, 120); + _screen->setColor(1, 32, 32, 32); + _screen->setColor(2, 96, 96, 96); + _screen->setColor(3, 160, 160, 160); + _screen->setColor(4, 224, 224, 224); + _screen->setColor(9, 24, 64, 24); + _screen->setColor(10, 64, 132, 64); + _screen->setColor(11, 100, 192, 100); + _screen->setColor(12, 120, 248, 120); _eventsManager->setCursorColor(128, 1); _eventsManager->_intPtr._hasPalette = true; - _graphicsManager->_fontPtr->_curFont = _bVoy->boltEntry(0x909)._fontResource; - _graphicsManager->_fontPtr->_fontSaveBack = false; - _graphicsManager->_fontPtr->_fontFlags = DISPFLAG_NONE; + _screen->_fontPtr->_curFont = _bVoy->boltEntry(0x909)._fontResource; + _screen->_fontPtr->_fontSaveBack = false; + _screen->_fontPtr->_fontFlags = DISPFLAG_NONE; _eventsManager->getMouseInfo(); if (newX == -1) { @@ -481,37 +481,37 @@ void VoyeurEngine::reviewTape() { needRedraw = false; flipPageAndWait(); - _graphicsManager->_drawPtr->_penColor = 0; - _graphicsManager->_drawPtr->_pos = Common::Point(tempRect.left, tempRect.top); - _graphicsManager->_backgroundPage->sFillBox(tempRect.width(), tempRect.height()); + _screen->_drawPtr->_penColor = 0; + _screen->_drawPtr->_pos = Common::Point(tempRect.left, tempRect.top); + _screen->_backgroundPage->sFillBox(tempRect.width(), tempRect.height()); int yp = 45; int eventNum = eventStart; for (int lineNum = 0; lineNum < 8 && eventNum < _voy->_eventCount; ++lineNum, ++eventNum) { - _graphicsManager->_fontPtr->_picFlags = DISPFLAG_NONE; - _graphicsManager->_fontPtr->_picSelect = 0xff; - _graphicsManager->_fontPtr->_picPick = 7; - _graphicsManager->_fontPtr->_picOnOff = (lineNum == eventLine) ? 8 : 0; - _graphicsManager->_fontPtr->_pos = Common::Point(68, yp); - _graphicsManager->_fontPtr->_justify = ALIGN_LEFT; - _graphicsManager->_fontPtr->_justifyWidth = 0; - _graphicsManager->_fontPtr->_justifyHeight = 0; + _screen->_fontPtr->_picFlags = DISPFLAG_NONE; + _screen->_fontPtr->_picSelect = 0xff; + _screen->_fontPtr->_picPick = 7; + _screen->_fontPtr->_picOnOff = (lineNum == eventLine) ? 8 : 0; + _screen->_fontPtr->_pos = Common::Point(68, yp); + _screen->_fontPtr->_justify = ALIGN_LEFT; + _screen->_fontPtr->_justifyWidth = 0; + _screen->_fontPtr->_justifyHeight = 0; Common::String msg = _eventsManager->getEvidString(eventNum); - _graphicsManager->_backgroundPage->drawText(msg); + _screen->_backgroundPage->drawText(msg); yp += 15; } - _graphicsManager->_vPort->addSaveRect( - _graphicsManager->_vPort->_lastPage, tempRect); + _screen->_vPort->addSaveRect( + _screen->_vPort->_lastPage, tempRect); flipPageAndWait(); - _graphicsManager->_vPort->addSaveRect( - _graphicsManager->_vPort->_lastPage, tempRect); + _screen->_vPort->addSaveRect( + _screen->_vPort->_lastPage, tempRect); } - _graphicsManager->sDrawPic(cursor, _graphicsManager->_vPort, + _screen->sDrawPic(cursor, _screen->_vPort, _eventsManager->getMousePos()); flipPageAndWait(); @@ -543,34 +543,34 @@ void VoyeurEngine::reviewTape() { flipPageAndWait(); - _graphicsManager->_drawPtr->_penColor = 0; - _graphicsManager->_drawPtr->_pos = Common::Point(tempRect.left, tempRect.top); - _graphicsManager->_backgroundPage->sFillBox(tempRect.width(), tempRect.height()); + _screen->_drawPtr->_penColor = 0; + _screen->_drawPtr->_pos = Common::Point(tempRect.left, tempRect.top); + _screen->_backgroundPage->sFillBox(tempRect.width(), tempRect.height()); int yp = 45; int eventNum = eventStart; for (int idx = 0; idx < 8 && eventNum < _voy->_eventCount; ++idx, ++eventNum) { - _graphicsManager->_fontPtr->_picFlags = DISPFLAG_NONE; - _graphicsManager->_fontPtr->_picSelect = 0xff; - _graphicsManager->_fontPtr->_picPick = 7; - _graphicsManager->_fontPtr->_picOnOff = (idx == eventLine) ? 8 : 0; - _graphicsManager->_fontPtr->_pos = Common::Point(68, yp); - _graphicsManager->_fontPtr->_justify = ALIGN_LEFT; - _graphicsManager->_fontPtr->_justifyWidth = 0; - _graphicsManager->_fontPtr->_justifyHeight = 0; + _screen->_fontPtr->_picFlags = DISPFLAG_NONE; + _screen->_fontPtr->_picSelect = 0xff; + _screen->_fontPtr->_picPick = 7; + _screen->_fontPtr->_picOnOff = (idx == eventLine) ? 8 : 0; + _screen->_fontPtr->_pos = Common::Point(68, yp); + _screen->_fontPtr->_justify = ALIGN_LEFT; + _screen->_fontPtr->_justifyWidth = 0; + _screen->_fontPtr->_justifyHeight = 0; Common::String msg = _eventsManager->getEvidString(eventNum); - _graphicsManager->_backgroundPage->drawText(msg); + _screen->_backgroundPage->drawText(msg); yp += 15; } - _graphicsManager->_vPort->addSaveRect( - _graphicsManager->_vPort->_lastPage, tempRect); + _screen->_vPort->addSaveRect( + _screen->_vPort->_lastPage, tempRect); flipPageAndWait(); - _graphicsManager->_vPort->addSaveRect( - _graphicsManager->_vPort->_lastPage, tempRect); + _screen->_vPort->addSaveRect( + _screen->_vPort->_lastPage, tempRect); flipPageAndWait(); _eventsManager->getMouseInfo(); @@ -650,7 +650,7 @@ void VoyeurEngine::reviewTape() { newY = _eventsManager->getMousePos().y; _voy->_fadingType = 0; _voy->_viewBounds = nullptr; - _graphicsManager->_vPort->setupViewPort(NULL); + _screen->_vPort->setupViewPort(NULL); if (_currentVocId != -1) { _voy->_vocSecondsOffset = _voy->_RTVNum - _voy->_musicStartTime; @@ -673,13 +673,13 @@ void VoyeurEngine::reviewTape() { _voy->_vocSecondsOffset = e._computerOn; _bVoy->getBoltGroup(0x7F00); - _graphicsManager->_backgroundPage = _bVoy->boltEntry(0x7F00 + + _screen->_backgroundPage = _bVoy->boltEntry(0x7F00 + BLIND_TABLE[_audioVideoId])._picResource; - _graphicsManager->_backColors = _bVoy->boltEntry(0x7F01 + + _screen->_backColors = _bVoy->boltEntry(0x7F01 + BLIND_TABLE[_audioVideoId])._cMapResource; - _graphicsManager->_vPort->setupViewPort(_graphicsManager->_backgroundPage); - _graphicsManager->_backColors->startFade(); + _screen->_vPort->setupViewPort(_screen->_backgroundPage); + _screen->_backColors->startFade(); flipPageAndWaitForFade(); _eventsManager->_intPtr._flashStep = 1; @@ -725,16 +725,16 @@ void VoyeurEngine::reviewTape() { } } - _graphicsManager->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource; + _screen->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource; - _graphicsManager->_vPort->fillPic(0); + _screen->_vPort->fillPic(0); flipPageAndWait(); _bVoy->freeBoltGroup(0x900); } void VoyeurEngine::doGossip() { - _graphicsManager->resetPalette(); - _graphicsManager->screenReset(); + _screen->resetPalette(); + _screen->screenReset(); if (!_bVoy->getBoltGroup(0x300)) return; @@ -752,7 +752,7 @@ void VoyeurEngine::doGossip() { // Transfer initial background to video decoder PictureResource videoFrame(decoder.getRL2VideoTrack()->getBackSurface()); bgPic->_bounds.moveTo(0, 0); - _graphicsManager->sDrawPic(bgPic, &videoFrame, Common::Point(0, 0)); + _screen->sDrawPic(bgPic, &videoFrame, Common::Point(0, 0)); byte *frameNumsP = _bVoy->memberAddr(0x309); byte *posP = _bVoy->boltEntry(0x30A)._data; @@ -762,8 +762,8 @@ void VoyeurEngine::doGossip() { decoder.close(); // Reset the palette and clear the screen - _graphicsManager->resetPalette(); - _graphicsManager->screenReset(); + _screen->resetPalette(); + _screen->screenReset(); // Play interview video RL2Decoder decoder2; @@ -775,7 +775,7 @@ void VoyeurEngine::doGossip() { decoder2.close(); _bVoy->freeBoltGroup(0x300); - _graphicsManager->screenReset(); + _screen->screenReset(); } void VoyeurEngine::doTapePlaying() { @@ -783,14 +783,14 @@ void VoyeurEngine::doTapePlaying() { return; _eventsManager->getMouseInfo(); - _graphicsManager->_backColors = _bVoy->boltEntry(0xA01)._cMapResource; - _graphicsManager->_backgroundPage = _bVoy->boltEntry(0xA00)._picResource; + _screen->_backColors = _bVoy->boltEntry(0xA01)._cMapResource; + _screen->_backgroundPage = _bVoy->boltEntry(0xA00)._picResource; PictureResource *pic = _bVoy->boltEntry(0xA02)._picResource; VInitCycleResource *cycle = _bVoy->boltEntry(0xA05)._vInitCycleResource; - _graphicsManager->_vPort->setupViewPort(_graphicsManager->_backgroundPage); - _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort, Common::Point(57, 30)); - _graphicsManager->_backColors->startFade(); + _screen->_vPort->setupViewPort(_screen->_backgroundPage); + _screen->sDrawPic(pic, _screen->_vPort, Common::Point(57, 30)); + _screen->_backColors->startFade(); flipPageAndWaitForFade(); cycle->vStartCycle(); @@ -932,9 +932,9 @@ int VoyeurEngine::getChooseButton() { + 6)._rectResource->_entries; int selectedIndex = -1; - _graphicsManager->_vPort->setupViewPort(_graphicsManager->_backgroundPage); - _graphicsManager->_backColors->_steps = 0; - _graphicsManager->_backColors->startFade(); + _screen->_vPort->setupViewPort(_screen->_backgroundPage); + _screen->_backColors->_steps = 0; + _screen->_backColors->startFade(); flipPageAndWait(); _voy->_viewBounds = _bVoy->boltEntry(_playStampGroupId + 7)._rectResource; @@ -955,7 +955,7 @@ int VoyeurEngine::getChooseButton() { selectedIndex = idx; if (selectedIndex != prevIndex) { PictureResource *btnPic = _bVoy->boltEntry(_playStampGroupId + 8 + idx)._picResource; - _graphicsManager->sDrawPic(btnPic, _graphicsManager->_vPort, + _screen->sDrawPic(btnPic, _screen->_vPort, Common::Point(106, 200)); cursorPic = _bVoy->boltEntry(_playStampGroupId + 4)._picResource; @@ -967,11 +967,11 @@ int VoyeurEngine::getChooseButton() { if (selectedIndex == -1) { cursorPic = _bVoy->boltEntry(_playStampGroupId + 2)._picResource; PictureResource *btnPic = _bVoy->boltEntry(_playStampGroupId + 12)._picResource; - _graphicsManager->sDrawPic(btnPic, _graphicsManager->_vPort, + _screen->sDrawPic(btnPic, _screen->_vPort, Common::Point(106, 200)); } - _graphicsManager->sDrawPic(cursorPic, _graphicsManager->_vPort, + _screen->sDrawPic(cursorPic, _screen->_vPort, Common::Point(pt.x + 13, pt.y - 12)); flipPageAndWait(); @@ -982,9 +982,9 @@ int VoyeurEngine::getChooseButton() { } void VoyeurEngine::makeViewFinder() { - _graphicsManager->_backgroundPage = _bVoy->boltEntry(0x103)._picResource; - _graphicsManager->sDrawPic(_graphicsManager->_backgroundPage, - _graphicsManager->_vPort, Common::Point(0, 0)); + _screen->_backgroundPage = _bVoy->boltEntry(0x103)._picResource; + _screen->sDrawPic(_screen->_backgroundPage, + _screen->_vPort, Common::Point(0, 0)); CMapResource *pal = _bVoy->boltEntry(0x104)._cMapResource; int palOffset = 0; @@ -1016,22 +1016,22 @@ void VoyeurEngine::makeViewFinder() { break; } - _graphicsManager->_vPort->drawIfaceTime(); + _screen->_vPort->drawIfaceTime(); doTimeBar(); pal->startFade(); flipPageAndWaitForFade(); - _graphicsManager->setColor(241, 105, 105, 105); - _graphicsManager->setColor(242, 105, 105, 105); - _graphicsManager->setColor(243, 105, 105, 105); - _graphicsManager->setColor(palOffset + 241, 219, 235, 235); + _screen->setColor(241, 105, 105, 105); + _screen->setColor(242, 105, 105, 105); + _screen->setColor(243, 105, 105, 105); + _screen->setColor(palOffset + 241, 219, 235, 235); _eventsManager->_intPtr._hasPalette = true; } void VoyeurEngine::makeViewFinderP() { - _graphicsManager->screenReset(); + _screen->screenReset(); } void VoyeurEngine::initIFace() { @@ -1077,7 +1077,7 @@ void VoyeurEngine::initIFace() { void VoyeurEngine::doScroll(const Common::Point &pt) { Common::Rect clipRect(72, 47, 72 + 240, 47 + 148); - _graphicsManager->_vPort->setupViewPort(NULL, &clipRect); + _screen->_vPort->setupViewPort(NULL, &clipRect); int base = 0; switch (_voy->_transitionId) { @@ -1101,18 +1101,18 @@ void VoyeurEngine::doScroll(const Common::Point &pt) { if (base) { PictureResource *pic = _bVoy->boltEntry(base + 3)._picResource; - _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y - 104)); + _screen->sDrawPic(pic, _screen->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y - 104)); pic = _bVoy->boltEntry(base + 4)._picResource; - _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y - 44)); + _screen->sDrawPic(pic, _screen->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y - 44)); pic = _bVoy->boltEntry(base + 5)._picResource; - _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y + 16)); + _screen->sDrawPic(pic, _screen->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y + 16)); pic = _bVoy->boltEntry(base + 6)._picResource; - _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y + 76)); + _screen->sDrawPic(pic, _screen->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y + 76)); pic = _bVoy->boltEntry(base + 7)._picResource; - _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y + 136)); + _screen->sDrawPic(pic, _screen->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y + 136)); } - _graphicsManager->_vPort->setupViewPort(NULL); + _screen->_vPort->setupViewPort(NULL); } void VoyeurEngine::checkTransition() { @@ -1124,7 +1124,7 @@ void VoyeurEngine::checkTransition() { // Only proceed if a valid day string was returned if (!day.empty()) { - _graphicsManager->fadeDownICF(6); + _screen->fadeDownICF(6); // Get the time of day string time = getTimeOfDay(); @@ -1163,7 +1163,7 @@ Common::String VoyeurEngine::getTimeOfDay() { } int VoyeurEngine::doComputerText(int maxLen) { - FontInfoResource &font = *_graphicsManager->_fontPtr; + FontInfoResource &font = *_screen->_fontPtr; int totalChars = 0; font._curFont = _bVoy->boltEntry(0x4910)._fontResource; @@ -1180,7 +1180,7 @@ int VoyeurEngine::doComputerText(int maxLen) { font._justifyWidth = 384; font._justifyHeight = 100; font._pos = Common::Point(128, 100); - _graphicsManager->_vPort->drawText(END_OF_MESSAGE); + _screen->_vPort->drawText(END_OF_MESSAGE); } else if (_voy->_RTVNum < _voy->_computerTimeMin && maxLen == 9999) { if (_currentVocId != -1) _soundManager->startVOCPlay(_currentVocId); @@ -1188,7 +1188,7 @@ int VoyeurEngine::doComputerText(int maxLen) { font._justifyWidth = 384; font._justifyHeight = 100; font._pos = Common::Point(120, 100); - _graphicsManager->_vPort->drawText(START_OF_MESSAGE); + _screen->_vPort->drawText(START_OF_MESSAGE); } else { char *msg = (char *)_bVoy->memberAddr(0x4900 + _voy->_computerTextId); font._pos = Common::Point(96, 60); @@ -1206,14 +1206,14 @@ int VoyeurEngine::doComputerText(int maxLen) { if (c == '\0') { if (showEnd) { _eventsManager->delay(90); - _graphicsManager->_drawPtr->_pos = Common::Point(96, 54); - _graphicsManager->_drawPtr->_penColor = 254; - _graphicsManager->_vPort->sFillBox(196, 124); - _graphicsManager->_fontPtr->_justify = ALIGN_LEFT; - _graphicsManager->_fontPtr->_justifyWidth = 384; - _graphicsManager->_fontPtr->_justifyHeight = 100; - _graphicsManager->_fontPtr->_pos = Common::Point(128, 100); - _graphicsManager->_vPort->drawText(END_OF_MESSAGE); + _screen->_drawPtr->_pos = Common::Point(96, 54); + _screen->_drawPtr->_penColor = 254; + _screen->_vPort->sFillBox(196, 124); + _screen->_fontPtr->_justify = ALIGN_LEFT; + _screen->_fontPtr->_justifyWidth = 384; + _screen->_fontPtr->_justifyHeight = 100; + _screen->_fontPtr->_pos = Common::Point(128, 100); + _screen->_vPort->drawText(END_OF_MESSAGE); } break; } @@ -1223,20 +1223,20 @@ int VoyeurEngine::doComputerText(int maxLen) { yp += 10; } else { _eventsManager->delay(90); - _graphicsManager->_drawPtr->_pos = Common::Point(96, 54); - _graphicsManager->_drawPtr->_penColor = 255; - _graphicsManager->_vPort->sFillBox(196, 124); + _screen->_drawPtr->_pos = Common::Point(96, 54); + _screen->_drawPtr->_penColor = 255; + _screen->_vPort->sFillBox(196, 124); yp = 60; } - _graphicsManager->_fontPtr->_pos = Common::Point(96, yp); + _screen->_fontPtr->_pos = Common::Point(96, yp); } else if (c == '_') { showEnd = false; } else { - _graphicsManager->_fontPtr->_justify = ALIGN_LEFT; - _graphicsManager->_fontPtr->_justifyWidth = 0; - _graphicsManager->_fontPtr->_justifyHeight = 0; - _graphicsManager->_vPort->drawText(Common::String(c)); + _screen->_fontPtr->_justify = ALIGN_LEFT; + _screen->_fontPtr->_justifyWidth = 0; + _screen->_fontPtr->_justifyHeight = 0; + _screen->_vPort->drawText(Common::String(c)); _eventsManager->delay(4); } @@ -1251,7 +1251,7 @@ int VoyeurEngine::doComputerText(int maxLen) { flipPageAndWait(); - _graphicsManager->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource; + _screen->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource; return totalChars; } @@ -1263,7 +1263,7 @@ void VoyeurEngine::getComputerBrush() { int xp = (384 - pic->_bounds.width()) / 2; int yp = (240 - pic->_bounds.height()) / 2 - 4; - _graphicsManager->_vPort->drawPicPerm(pic, Common::Point(xp, yp)); + _screen->_vPort->drawPicPerm(pic, Common::Point(xp, yp)); CMapResource *pal = _bVoy->boltEntry(0x490F)._cMapResource; pal->startFade(); @@ -1280,17 +1280,17 @@ void VoyeurEngine::doTimeBar() { int height = ((_voy->_RTVLimit - _voy->_RTVNum) * 59) / _voy->_RTVLimit; int fullHeight = MAX(151 - height, 93); - _graphicsManager->_drawPtr->_penColor = 134; - _graphicsManager->_drawPtr->_pos = Common::Point(39, 92); + _screen->_drawPtr->_penColor = 134; + _screen->_drawPtr->_pos = Common::Point(39, 92); - _graphicsManager->_vPort->sFillBox(6, fullHeight - 92); + _screen->_vPort->sFillBox(6, fullHeight - 92); if (height > 0) { - _graphicsManager->setColor(215, 238, 238, 238); + _screen->setColor(215, 238, 238, 238); _eventsManager->_intPtr._hasPalette = true; - _graphicsManager->_drawPtr->_penColor = 215; - _graphicsManager->_drawPtr->_pos = Common::Point(39, fullHeight); - _graphicsManager->_vPort->sFillBox(6, height); + _screen->_drawPtr->_penColor = 215; + _screen->_drawPtr->_pos = Common::Point(39, fullHeight); + _screen->_vPort->sFillBox(6, height); } } } @@ -1303,9 +1303,9 @@ void VoyeurEngine::flashTimeBar() { _flashTimeVal = _eventsManager->_intPtr._flashTimer; if (_flashTimeFlag) - _graphicsManager->setColor(240, 220, 20, 20); + _screen->setColor(240, 220, 20, 20); else - _graphicsManager->setColor(240, 220, 220, 220); + _screen->setColor(240, 220, 220, 220); _eventsManager->_intPtr._hasPalette = true; _flashTimeFlag = !_flashTimeFlag; @@ -1343,7 +1343,7 @@ void VoyeurEngine::doEvidDisplay(int evidId, int eventId) { _bVoy->getBoltGroup(_voy->_boltGroupId2); PictureResource *pic = _bVoy->boltEntry(_voy->_boltGroupId2 + evidId * 2)._picResource; - _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort, Common::Point( + _screen->sDrawPic(pic, _screen->_vPort, Common::Point( (384 - pic->_bounds.width()) / 2, (240 - pic->_bounds.height()) / 2)); _bVoy->freeBoltMember(_voy->_boltGroupId2 + evidId * 2); @@ -1394,7 +1394,7 @@ void VoyeurEngine::doEvidDisplay(int evidId, int eventId) { continue; pic = _voy->_evPicPtrs[arrIndex]; - _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort, + _screen->sDrawPic(pic, _screen->_vPort, Common::Point((384 - pic->_bounds.width()) / 2, (240 - pic->_bounds.height()) / 2)); _voy->_evCmPtrs[arrIndex]->startFade(); diff --git a/engines/wage/combat.cpp b/engines/wage/combat.cpp new file mode 100644 index 0000000000..4f2956d7d2 --- /dev/null +++ b/engines/wage/combat.cpp @@ -0,0 +1,916 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "wage/wage.h" +#include "wage/entities.h" +#include "wage/randomhat.h" +#include "wage/world.h" + +namespace Wage { + +Obj *WageEngine::getOffer() { + if (_offer != NULL) { + Chr *owner = _offer->_currentOwner; + if (owner == NULL || owner->_playerCharacter || owner->_currentScene != _world->_player->_currentScene) { + _offer = NULL; + } + } + return _offer; +} + +Chr *WageEngine::getMonster() { + if (_monster != NULL && _monster->_currentScene != _world->_player->_currentScene) { + _monster = NULL; + } + return _monster; +} + +void WageEngine::encounter(Chr *player, Chr *chr) { + char buf[512]; + + snprintf(buf, 512, "You encounter %s%s.", chr->_nameProperNoun ? "" : getIndefiniteArticle(chr->_name), + chr->_name.c_str()); + appendText(buf); + + if (!chr->_initialComment.empty()) + appendText(chr->_initialComment.c_str()); + + if (chr->_armor[Chr::HEAD_ARMOR] != NULL) { + snprintf(buf, 512, "%s%s is wearing %s.", chr->getDefiniteArticle(true), chr->_name.c_str(), + getIndefiniteArticle(chr->_armor[Chr::HEAD_ARMOR]->_name)); + appendText(buf); + } + if (chr->_armor[Chr::BODY_ARMOR] != NULL) { + snprintf(buf, 512, "%s is protected by %s%s.", getGenderSpecificPronoun(chr->_gender, true), + prependGenderSpecificPronoun(chr->_gender), chr->_armor[Chr::BODY_ARMOR]->_name.c_str()); + appendText(buf); + } + if (chr->_armor[Chr::SHIELD_ARMOR] != NULL) { + Obj *obj = chr->_armor[Chr::SHIELD_ARMOR]; + + snprintf(buf, 512, "%s carries %s%s.", getGenderSpecificPronoun(chr->_gender, true), + obj->_namePlural ? "" : getIndefiniteArticle(obj->_name), obj->_name.c_str()); + appendText(buf); + } +} + +void WageEngine::performCombatAction(Chr *npc, Chr *player) { + if (npc->_context._frozen) + return; + + RandomHat hat(_rnd); + + bool winning = (npc->_context._statVariables[PHYS_HIT_CUR] > player->_context._statVariables[PHYS_HIT_CUR]); + int validMoves = getValidMoveDirections(npc); + ObjArray *weapons = npc->getWeapons(false); + ObjArray *magics = npc->getMagicalObjects(); + // TODO: Figure out under what circumstances we need to add +1 + // for the chance (e.g. only when all values were set to 0?). + if (winning) { + if (!_world->_weaponMenuDisabled) { + if (!weapons->empty()) + hat.addTokens(kTokWeapons, npc->_winningWeapons + 1); + if (!magics->empty()) + hat.addTokens(kTokMagic, npc->_winningMagic); + } + if (validMoves != 0) + hat.addTokens(kTokRun, npc->_winningRun + 1); + if (!npc->_inventory.empty()) + hat.addTokens(kTokOffer, npc->_winningOffer + 1); + } else { + if (!_world->_weaponMenuDisabled) { + if (!weapons->empty()) + hat.addTokens(kTokWeapons, npc->_losingWeapons + 1); + if (!magics->empty()) + hat.addTokens(kTokMagic, npc->_losingMagic); + } + if (validMoves != 0) + hat.addTokens(kTokRun, npc->_losingRun + 1); + if (!npc->_inventory.empty()) + hat.addTokens(kTokOffer, npc->_losingOffer + 1); + } + + ObjList *objs = &npc->_currentScene->_objs; + if (npc->_inventory.size() < npc->_maximumCarriedObjects) { + int cnt = 0; + for (ObjList::const_iterator it = objs->begin(); it != objs->end(); ++it, ++cnt) { + if ((*it)->_type != Obj::IMMOBILE_OBJECT) { + // TODO: I'm not sure what the chance should be here. + hat.addTokens(cnt, 123); + } + } + } + + int token = hat.drawToken(); + switch (token) { + case kTokWeapons: + // TODO: I think the monster should choose the "best" weapon. + performAttack(npc, player, weapons->operator[](_rnd->getRandomNumber(weapons->size() - 1))); + break; + case kTokMagic: + // TODO: I think the monster should choose the "best" magic. + performMagic(npc, player, magics->operator[](_rnd->getRandomNumber(magics->size() - 1))); + break; + case kTokRun: + performMove(npc, validMoves); + break; + case kTokOffer: + performOffer(npc, player); + break; + case kTokNone: + break; + default: + { + int cnt = 0; + for (ObjList::const_iterator it = objs->begin(); it != objs->end(); ++it, ++cnt) + if (cnt == token) + performTake(npc, *it); + break; + } + } + + delete weapons; + delete magics; +} + +static const char *const targets[] = { "head", "chest", "side" }; + +void WageEngine::performAttack(Chr *attacker, Chr *victim, Obj *weapon) { + if (_world->_weaponMenuDisabled) + return; + + // TODO: verify that a player not aiming will always target the chest?? + int targetIndex = -1; + char buf[256]; + + if (weapon->_type != Obj::MAGICAL_OBJECT) { + if (attacker->_playerCharacter) { + targetIndex = _aim; + } else { + targetIndex = _rnd->getRandomNumber(ARRAYSIZE(targets) - 1); + _opponentAim = targetIndex + 1; + } + + if (!attacker->_playerCharacter) { + snprintf(buf, 256, "%s%s %ss %s%s at %s%s's %s.", + attacker->getDefiniteArticle(true), attacker->_name.c_str(), + weapon->_operativeVerb.c_str(), + prependGenderSpecificPronoun(attacker->_gender), weapon->_name.c_str(), + victim->getDefiniteArticle(true), victim->_name.c_str(), + targets[targetIndex]); + appendText(buf); + } + } else if (!attacker->_playerCharacter) { + snprintf(buf, 256, "%s%s %ss %s%s at %s%s.", + attacker->getDefiniteArticle(true), attacker->_name.c_str(), + weapon->_operativeVerb.c_str(), + prependGenderSpecificPronoun(attacker->_gender), weapon->_name.c_str(), + victim->getDefiniteArticle(true), victim->_name.c_str()); + appendText(buf); + } + + playSound(weapon->_sound); + + bool usesDecremented = false; + int chance = _rnd->getRandomNumber(255); + // TODO: what about obj accuracy + if (chance < attacker->_physicalAccuracy) { + usesDecremented = attackHit(attacker, victim, weapon, targetIndex); + } else if (weapon->_type != Obj::MAGICAL_OBJECT) { + appendText("A miss!"); + } else if (attacker->_playerCharacter) { + appendText("The spell has no effect."); + } + + if (!usesDecremented) { + decrementUses(weapon); + } +} + +void WageEngine::decrementUses(Obj *obj) { + int numberOfUses = obj->_numberOfUses; + if (numberOfUses != -1) { + numberOfUses--; + if (numberOfUses > 0) { + obj->_numberOfUses = numberOfUses; + } else { + if (!obj->_failureMessage.empty()) { + appendText(obj->_failureMessage.c_str()); + } + if (obj->_returnToRandomScene) { + _world->move(obj, _world->getRandomScene()); + } else { + _world->move(obj, _world->_storageScene); + } + obj->resetState(obj->_currentOwner, obj->_currentScene); + } + } +} + +bool WageEngine::attackHit(Chr *attacker, Chr *victim, Obj *weapon, int targetIndex) { + bool receivedHitTextPrinted = false; + char buf[512]; + + if (targetIndex != -1) { + Obj *armor = victim->_armor[targetIndex]; + if (armor != NULL) { + // TODO: Absorb some damage. + snprintf(buf, 512, "%s%s's %s weakens the impact of %s%s's %s.", + victim->getDefiniteArticle(true), victim->_name.c_str(), + victim->_armor[targetIndex]->_name.c_str(), + attacker->getDefiniteArticle(false), attacker->_name.c_str(), + weapon->_name.c_str()); + appendText(buf); + decrementUses(armor); + } else { + snprintf(buf, 512, "A hit to the %s!", targets[targetIndex]); + appendText(buf); + } + playSound(attacker->_scoresHitSound); + appendText(attacker->_scoresHitComment.c_str()); + playSound(victim->_receivesHitSound); + appendText(victim->_receivesHitComment.c_str()); + receivedHitTextPrinted = true; + } else if (weapon->_type == Obj::MAGICAL_OBJECT) { + appendText(weapon->_useMessage.c_str()); + appendText("The spell is effective!"); + } + + bool causesPhysicalDamage = true; + bool causesSpiritualDamage = false; + bool freezesOpponent = false; + bool usesDecremented = false; + + if (weapon->_type == Obj::THROW_WEAPON) { + _world->move(weapon, victim->_currentScene); + } else if (weapon->_type == Obj::MAGICAL_OBJECT) { + int type = weapon->_attackType; + causesPhysicalDamage = (type == Obj::CAUSES_PHYSICAL_DAMAGE || type == Obj::CAUSES_PHYSICAL_AND_SPIRITUAL_DAMAGE); + causesSpiritualDamage = (type == Obj::CAUSES_SPIRITUAL_DAMAGE || type == Obj::CAUSES_PHYSICAL_AND_SPIRITUAL_DAMAGE); + freezesOpponent = (type == Obj::FREEZES_OPPONENT); + } + + if (causesPhysicalDamage) { + victim->_context._userVariables[PHYS_HIT_CUR] -= weapon->_damage; + + /* Do it here to get the right order of messages in case of death. */ + decrementUses(weapon); + usesDecremented = true; + + if (victim->_context._userVariables[PHYS_HIT_CUR] < 0) { + playSound(victim->_dyingSound); + appendText(victim->_dyingWords.c_str()); + snprintf(buf, 512, "%s%s is dead!", victim->getDefiniteArticle(true), victim->_name.c_str()); + appendText(buf); + + attacker->_context._kills++; + attacker->_context._experience += victim->_context._userVariables[SPIR_HIT_CUR] + victim->_context._userVariables[PHYS_HIT_CUR]; + + if (!victim->_playerCharacter && !victim->_inventory.empty()) { + Scene *currentScene = victim->_currentScene; + + for (int i = victim->_inventory.size() - 1; i >= 0; i--) { + _world->move(victim->_inventory[i], currentScene); + } + Common::String *s = getGroundItemsList(currentScene); + appendText(s->c_str()); + delete s; + } + _world->move(victim, _world->_storageScene); + } else if (attacker->_playerCharacter && !receivedHitTextPrinted) { + double physicalPercent = (double)victim->_context._userVariables[SPIR_HIT_CUR] / + victim->_context._userVariables[SPIR_HIT_BAS]; + snprintf(buf, 512, "%s%s's condition appears to be %s.", + victim->getDefiniteArticle(true), victim->_name.c_str(), + getPercentMessage(physicalPercent)); + appendText(buf); + } + } + + if (causesSpiritualDamage) { + /* TODO */ + warning("TODO: Spiritual damage"); + } + + if (freezesOpponent) { + victim->_context._frozen = true; + } + + return usesDecremented; +} + +void WageEngine::performMagic(Chr *attacker, Chr *victim, Obj *magicalObject) { + switch (magicalObject->_attackType) { + case Obj::HEALS_PHYSICAL_DAMAGE: + case Obj::HEALS_SPIRITUAL_DAMAGE: + case Obj::HEALS_PHYSICAL_AND_SPIRITUAL_DAMAGE: + performHealingMagic(attacker, magicalObject); + return; + } + + performAttack(attacker, victim, magicalObject); +} + +void WageEngine::performHealingMagic(Chr *chr, Obj *magicalObject) { + char buf[512]; + + if (!chr->_playerCharacter) { + snprintf(buf, 512, "%s%s %ss %s%s.", + chr->getDefiniteArticle(true), chr->_name.c_str(), + magicalObject->_operativeVerb.c_str(), + getIndefiniteArticle(magicalObject->_name), magicalObject->_name.c_str()); + appendText(buf); + } + + uint chance = _rnd->getRandomNumber(255); + if (chance < magicalObject->_accuracy) { + int type = magicalObject->_attackType; + + if (type == Obj::HEALS_PHYSICAL_DAMAGE || type == Obj::HEALS_PHYSICAL_AND_SPIRITUAL_DAMAGE) + chr->_context._statVariables[PHYS_HIT_CUR] += magicalObject->_damage; + + if (type == Obj::HEALS_SPIRITUAL_DAMAGE || type == Obj::HEALS_PHYSICAL_AND_SPIRITUAL_DAMAGE) + chr->_context._statVariables[SPIR_HIT_CUR] += magicalObject->_damage; + + playSound(magicalObject->_sound); + appendText(magicalObject->_useMessage.c_str()); + + // TODO: what if enemy heals himself? + if (chr->_playerCharacter) { + double physicalPercent = (double)chr->_context._statVariables[PHYS_HIT_CUR] / chr->_context._statVariables[PHYS_HIT_BAS]; + double spiritualPercent = (double)chr->_context._statVariables[SPIR_HIT_CUR] / chr->_context._statVariables[SPIR_HIT_BAS]; + snprintf(buf, 256, "Your physical condition is %s.", getPercentMessage(physicalPercent)); + appendText(buf); + + snprintf(buf, 256, "Your spiritual condition is %s.", getPercentMessage(spiritualPercent)); + appendText(buf); + } + } + + decrementUses(magicalObject); +} + +static const int directionsX[] = { 0, 0, 1, -1 }; +static const int directionsY[] = { -1, 1, 0, 0 }; +static const char *const directionsS[] = { "north", "south", "east", "west" }; + +void WageEngine::performMove(Chr *chr, int validMoves) { + // count how many valid moves we have + int numValidMoves = 0; + + for (int i = 0; i < 4; i++) + if ((validMoves & (1 << i)) != 0) + numValidMoves++; + + // Now pick random dir + int dirNum = _rnd->getRandomNumber(numValidMoves - 1); + int dir = 0; + + // And get it + for (int i = 0; i < 4; i++) + if ((validMoves & (1 << i)) != 0) { + if (dirNum == 0) { + dir = i; + break; + } + dirNum--; + } + + char buf[256]; + snprintf(buf, 256, "%s%s runs %s.", chr->getDefiniteArticle(true), chr->_name.c_str(), directionsS[dir]); + appendText(buf); + + _running = chr; + Scene *currentScene = chr->_currentScene; + int destX = currentScene->_worldX + directionsX[dir]; + int destY = currentScene->_worldY + directionsY[dir]; + + _world->move(chr, _world->getSceneAt(destX, destY)); +} + +void WageEngine::performOffer(Chr *attacker, Chr *victim) { + /* TODO: choose in a smarter way? */ + Obj *obj = attacker->_inventory[0]; + char buf[512]; + + snprintf(buf, 512, "%s%s offers %s%s.", attacker->getDefiniteArticle(true), attacker->_name.c_str(), + obj->_namePlural ? "some " : getIndefiniteArticle(obj->_name), obj->_name.c_str()); + + appendText(buf); + + _offer = obj; +} + +void WageEngine::performTake(Chr *npc, Obj *obj) { + char buf[512]; + + snprintf(buf, 512, "%s%s picks up the %s%s.", npc->getDefiniteArticle(true), npc->_name.c_str(), + getIndefiniteArticle(obj->_name), obj->_name.c_str()); + + appendText(buf); + + _world->move(obj, npc); +} + +int WageEngine::getValidMoveDirections(Chr *npc) { + int directions = 0; + Scene *currentScene = npc->_currentScene; + for (int dir = 0; dir < 4; dir++) { + if (!currentScene->_blocked[dir]) { + int destX = currentScene->_worldX + directionsX[dir]; + int destY = currentScene->_worldY + directionsY[dir]; + + Scene *scene = _world->getSceneAt(destX, destY); + + if (scene != NULL && scene->_chrs.empty()) { + directions |= (1 << dir); + } + } + } + + return directions; +} + +void WageEngine::regen() { + Chr *player = _world->_player; + int curHp = player->_context._statVariables[PHYS_HIT_CUR]; + int maxHp = player->_context._statVariables[PHYS_HIT_BAS]; + int delta = maxHp - curHp; + + if (delta > 0) { + int bonus = (int)(delta / (8 + _rnd->getRandomNumber(2))); + player->_context._statVariables[PHYS_HIT_CUR] += bonus; + } +} + +void WageEngine::takeObj(Obj *obj) { + if (_world->_player->_inventory.size() >= _world->_player->_maximumCarriedObjects) { + appendText("Your pack is full, you must drop something."); + } else { + char buf[256]; + + _world->move(obj, _world->_player); + int type = _world->_player->wearObjIfPossible(obj); + if (type == Chr::HEAD_ARMOR) { + snprintf(buf, 256, "You are now wearing the %s.", obj->_name.c_str()); + appendText(buf); + } else if (type == Chr::BODY_ARMOR) { + snprintf(buf, 256, "You are now wearing the %s.", obj->_name.c_str()); + appendText(buf); + } else if (type == Chr::SHIELD_ARMOR) { + snprintf(buf, 256, "You are now wearing the %s.", obj->_name.c_str()); + appendText(buf); + } else if (type == Chr::MAGIC_ARMOR) { + snprintf(buf, 256, "You are now wearing the %s.", obj->_name.c_str()); + appendText(buf); + } else { + snprintf(buf, 256, "You now have the %s.", obj->_name.c_str()); + appendText(buf); + } + appendText(obj->_clickMessage.c_str()); + } +} + +bool WageEngine::handleMoveCommand(Directions dir, const char *dirName) { + Scene *playerScene = _world->_player->_currentScene; + const char *msg = playerScene->_messages[dir].c_str(); + + if (!playerScene->_blocked[dir]) { + int destX = playerScene->_worldX + directionsX[dir]; + int destY = playerScene->_worldY + directionsY[dir]; + + Scene *scene = _world->getSceneAt(destX, destY); + + if (scene != NULL) { + if (strlen(msg) > 0) { + appendText(msg); + } + _world->move(_world->_player, scene); + return true; + } + } + if (strlen(msg) > 0) { + appendText(msg); + } else { + Common::String txt("You can't go "); + txt += dirName; + txt += "."; + appendText(txt.c_str()); + } + + return true; +} + +bool WageEngine::handleLookCommand() { + appendText(_world->_player->_currentScene->_text.c_str()); + + Common::String *items = getGroundItemsList(_world->_player->_currentScene); + if (items != NULL) { + appendText(items->c_str()); + + delete items; + } + + return true; +} + +Common::String *WageEngine::getGroundItemsList(Scene *scene) { + ObjArray objs; + + for (ObjList::const_iterator it = scene->_objs.begin(); it != scene->_objs.end(); ++it) + if ((*it)->_type != Obj::IMMOBILE_OBJECT) + objs.push_back(*it); + + if (!objs.empty()) { + Common::String *res = new Common::String("On the ground you see "); + appendObjNames(*res, objs); + return res; + } + return NULL; +} + +void WageEngine::appendObjNames(Common::String &str, const ObjArray &objs) { + for (uint i = 0; i < objs.size(); i++) { + Obj *obj = objs[i]; + + if (!obj->_namePlural) + str += getIndefiniteArticle(obj->_name); + else + str += "some "; + + str += obj->_name; + + if (i == objs.size() - 1) { + str += "."; + } else if (i == objs.size() - 2) { + if (objs.size() > 2) + str += ","; + str += " and "; + } else { + str += ", "; + } + } +} + +bool WageEngine::handleInventoryCommand() { + Chr *player = _world->_player; + ObjArray objs; + + for (ObjArray::const_iterator it = player->_inventory.begin(); it != player->_inventory.end(); ++it) + if (!player->isWearing(*it)) + objs.push_back(*it); + + if (objs.empty()) { + appendText("Your pack is empty."); + } else { + Common::String res("Your pack contains "); + appendObjNames(res, objs); + appendText(res.c_str()); + } + + return true; +} + +static const char *const armorMessages[] = { + "Head protection:", + "Chest protection:", + "Shield protection:", // TODO: check message + "Magical protection:" +}; + +bool WageEngine::handleStatusCommand() { + Chr *player = _world->_player; + char buf[512]; + + snprintf(buf, 512, "Character name: %s%s", player->getDefiniteArticle(false), player->_name.c_str()); + appendText(buf); + snprintf(buf, 512, "Experience: %d", player->_context._experience); + appendText(buf); + + int wealth = 0; + for (ObjArray::const_iterator it = player->_inventory.begin(); it != player->_inventory.end(); ++it) + wealth += (*it)->_value; + + snprintf(buf, 512, "Wealth: %d", wealth); + appendText(buf); + + for (int i = 0; i < Chr::NUMBER_OF_ARMOR_TYPES; i++) { + if (player->_armor[i] != NULL) { + snprintf(buf, 512, "%s %s", armorMessages[i], player->_armor[i]->_name.c_str()); + appendText(buf); + } + } + + for (ObjArray::const_iterator it = player->_inventory.begin(); it != player->_inventory.end(); ++it) { + int uses = (*it)->_numberOfUses; + + if (uses > 0) { + snprintf(buf, 512, "Your %s has %d uses left.", (*it)->_name.c_str(), uses); + appendText(buf); + } + } + + printPlayerCondition(player); + + _commandWasQuick = true; + + return true; +} + +bool WageEngine::handleRestCommand() { + if (getMonster() != NULL) { + appendText("This is no time to rest!"); + _commandWasQuick = true; + } else { + regen(); + printPlayerCondition(_world->_player); + } + + return true; +} + +bool WageEngine::handleAcceptCommand() { + Chr *chr = _offer->_currentOwner; + + char buf[512]; + snprintf(buf, 512, "%s%s lays the %s on the ground and departs peacefully.", + chr->getDefiniteArticle(true), chr->_name.c_str(), _offer->_name.c_str()); + appendText(buf); + + _world->move(_offer, chr->_currentScene); + _world->move(chr, _world->_storageScene); + + return true; +} + +bool WageEngine::handleTakeCommand(const char *target) { + Common::String t(target); + bool handled = false; + + for (ObjList::const_iterator it = _world->_player->_currentScene->_objs.begin(); it != _world->_player->_currentScene->_objs.end(); ++it) { + Common::String n((*it)->_name); + n.toLowercase(); + + if (t.contains(n)) { + if ((*it)->_type == Obj::IMMOBILE_OBJECT) { + appendText("You can't move it."); + } else { + takeObj(*it); + } + + handled = true; + break; + } + } + + return handled; +} + +bool WageEngine::handleDropCommand(const char *target) { + Common::String t(target); + bool handled = false; + + t.toLowercase(); + + for (ObjArray::const_iterator it = _world->_player->_inventory.begin(); it != _world->_player->_inventory.end(); ++it) { + Common::String n((*it)->_name); + n.toLowercase(); + + if (t.contains(n)) { + char buf[256]; + + snprintf(buf, 256, "You no longer have the %s.", (*it)->_name.c_str()); + appendText(buf); + _world->move(*it, _world->_player->_currentScene); + + handled = true; + break; + } + } + + return handled; +} + +bool WageEngine::handleAimCommand(const char *t) { + bool wasHandled = true; + Common::String target(t); + + target.toLowercase(); + + if (target.contains("head")) { + _aim = Chr::HEAD; + } else if (target.contains("chest")) { + _aim = Chr::CHEST; + } else if (target.contains("side")) { + _aim = Chr::SIDE; + } else { + wasHandled = false; + appendText("Please aim for the head, chest, or side."); + } + + _commandWasQuick = true; + + return wasHandled; +} + +bool WageEngine::handleWearCommand(const char *t) { + Chr *player = _world->_player; + char buf[512]; + Common::String target(t); + bool handled = false; + + target.toLowercase(); + + for (ObjArray::const_iterator it = _world->_player->_inventory.begin(); it != _world->_player->_inventory.end(); ++it) { + Common::String n((*it)->_name); + + if (target.contains(n)) { + if ((*it)->_type == Obj::HELMET) { + wearObj(*it, Chr::HEAD_ARMOR); + } else if ((*it)->_type == Obj::CHEST_ARMOR) { + wearObj(*it, Chr::BODY_ARMOR); + } else if ((*it)->_type == Obj::SHIELD) { + wearObj(*it, Chr::SHIELD_ARMOR); + } else if ((*it)->_type == Obj::SPIRITUAL_ARMOR) { + wearObj(*it, Chr::MAGIC_ARMOR); + } else { + appendText("You cannot wear that object."); + } + + handled = true; + break; + } + } + + for (ObjList::const_iterator it = player->_currentScene->_objs.begin(); it != player->_currentScene->_objs.end(); ++it) { + Common::String n((*it)->_name); + n.toLowercase(); + if (target.contains(n)) { + snprintf(buf, 512, "First you must get the %s.", (*it)->_name.c_str()); + appendText(buf); + + handled = true; + break; + } + } + + return handled; +} + +void WageEngine::wearObj(Obj *o, int pos) { + Chr *player = _world->_player; + char buf[512]; + + if (player->_armor[pos] == o) { + snprintf(buf, 512, "You are already wearing the %s.", o->_name.c_str()); + appendText(buf); + } else { + if (player->_armor[pos] != NULL) { + snprintf(buf, 512, "You are no longer wearing the %s.", player->_armor[pos]->_name.c_str()); + appendText(buf); + } + + player->_armor[pos] = o; + snprintf(buf, 512, "You are now wearing the %s.", o->_name.c_str()); + appendText(buf); + } +} + + +bool WageEngine::handleOfferCommand(const char *target) { + Chr *player = _world->_player; + Chr *enemy = getMonster(); + + if (enemy != NULL) { + Common::String t(target); + t.toLowercase(); + + for (ObjArray::const_iterator it = player->_inventory.begin(); it != player->_inventory.end(); ++it) { + Common::String n((*it)->_name); + n.toLowercase(); + + if (t.contains(n)) { + if ((*it)->_value < enemy->_rejectsOffers) { + appendText("Your offer is rejected."); + } else { + appendText("Your offer is accepted."); + appendText(enemy->_acceptsOfferComment.c_str()); + _world->move(*it, enemy); + _world->move(enemy, _world->_storageScene); + } + + return true; + } + } + } + + return false; +} + +bool WageEngine::tryAttack(const Obj *weapon, const Common::String &input) { + Common::String w(weapon->_name); + w.toLowercase(); + Common::String i(input); + i.toLowercase(); + Common::String v(weapon->_operativeVerb); + v.toLowercase(); + + return i.contains(w) && i.contains(v); +} + +bool WageEngine::handleAttack(Obj *weapon) { + Chr *player = _world->_player; + Chr *enemy = getMonster(); + + if (weapon->_type == Obj::MAGICAL_OBJECT) { + switch (weapon->_attackType) { + case Obj::HEALS_PHYSICAL_AND_SPIRITUAL_DAMAGE: + case Obj::HEALS_PHYSICAL_DAMAGE: + case Obj::HEALS_SPIRITUAL_DAMAGE: + performMagic(player, enemy, weapon); + return true; + } + } + if (enemy != NULL) + performAttack(player, enemy, weapon); + else if (weapon->_type == Obj::MAGICAL_OBJECT) + appendText("There is nobody to cast a spell at."); + else + appendText("There is no one to fight."); + + return true; +} + +const char *WageEngine::getPercentMessage(double percent) { + if (percent < 0.40) { + return "very bad"; + } else if (percent < 0.55) { + return "bad"; + } else if (percent < 0.70) { + return "average"; + } else if (percent < 0.85) { + return "good"; + } else if (percent <= 1.00) { + return "very good"; + } else { + return "enhanced"; + } +} + +void WageEngine::printPlayerCondition(Chr *player) { + double physicalPercent = (double)player->_context._statVariables[PHYS_HIT_CUR] / player->_context._statVariables[PHYS_HIT_BAS]; + double spiritualPercent = (double)player->_context._statVariables[SPIR_HIT_CUR] / player->_context._statVariables[SPIR_HIT_BAS]; + char buf[256]; + + snprintf(buf, 256, "Your physical condition is %s.", getPercentMessage(physicalPercent)); + appendText(buf); + + snprintf(buf, 256, "Your spiritual condition is %s.", getPercentMessage(spiritualPercent)); + appendText(buf); +} + +} // End of namespace Wage diff --git a/engines/wage/configure.engine b/engines/wage/configure.engine new file mode 100644 index 0000000000..6205211158 --- /dev/null +++ b/engines/wage/configure.engine @@ -0,0 +1,3 @@ +# This file is included from the main "configure" script +# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] +add_engine wage "WAGE" no 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 new file mode 100644 index 0000000000..907a1ec435 --- /dev/null +++ b/engines/wage/design.cpp @@ -0,0 +1,599 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "graphics/primitives.h" +#include "wage/wage.h" +#include "wage/design.h" + +namespace Wage { + +struct PlotData { + Graphics::Surface *surface; + Patterns *patterns; + uint fillType; + int thickness; + Design *design; + + PlotData(Graphics::Surface *s, Patterns *p, int f, int t, Design *d) : + surface(s), patterns(p), fillType(f), thickness(t), design(d) {} +}; + +void drawPixel(int x, int y, int color, void *data); +void drawPixelPlain(int x, int y, int color, void *data); + +Design::Design(Common::SeekableReadStream *data) { + _len = data->readUint16BE() - 2; + _data = (byte *)malloc(_len); + data->read(_data, _len); + + _surface = NULL; + _bounds = NULL; + + _boundsCalculationMode = false; +} + +Design::~Design() { + free(_data); + if (_surface) + _surface->free(); + delete _surface; +} + +void Design::paint(Graphics::Surface *surface, Patterns &patterns, int x, int y) { + bool needRender = false; + + if (_surface == NULL) { + _boundsCalculationMode = true; + _bounds->debugPrint(4, "Internal bounds:"); + render(patterns); + _boundsCalculationMode = false; + if (_bounds->right == -10000) { + _bounds->left = _bounds->top = _bounds->right = _bounds->bottom = 0; + } + _bounds->debugPrint(4, "Calculated bounds:"); + + _surface = new Graphics::Surface; + _surface->create(_bounds->width(), _bounds->height(), Graphics::PixelFormat::createFormatCLUT8()); + + Common::Rect r(0, 0, _bounds->width(), _bounds->height()); + _surface->fillRect(r, kColorGreen); + + needRender = true; + } + + _bounds->debugPrint(4, "Using bounds:"); +#if 0 + PlotData pd(_surface, &patterns, 8, 1, this); + int x1 = 50, y1 = 50, x2 = 200, y2 = 200, borderThickness = 30; + Common::Rect inn(x1-5, y1-5, x2+5, y2+5); + drawRoundRect(inn, 6, kColorGray, false, drawPixelPlain, &pd); + + drawThickLine(x1, y1, x2-borderThickness, y1, borderThickness, kColorBlack, drawPixel, &pd); + drawThickLine(x2-borderThickness, y1, x2-borderThickness, y2, borderThickness, kColorBlack, drawPixel, &pd); + drawThickLine(x2-borderThickness, y2-borderThickness, x1, y2-borderThickness, borderThickness, kColorBlack, drawPixel, &pd); + drawThickLine(x1, y2-borderThickness, x1, y1, borderThickness, kColorBlack, drawPixel, &pd); + drawThickLine(x2+10, y2+10, x2+100, y2+100, borderThickness, kColorBlack, drawPixel, &pd); + + g_system->copyRectToScreen(_surface->getPixels(), _surface->pitch, 0, 0, _surface->w, _surface->h); + + while (true) { + ((WageEngine *)g_engine)->processEvents(); + g_system->updateScreen(); + g_system->delayMillis(50); + } + return; +#endif + + if (needRender) + render(patterns); + + if (_bounds->width() && _bounds->height()) { + const int padding = 3; + for (int i = padding; i < _bounds->height() - 2 * padding; i++) { + const byte *src = (const byte *)_surface->getBasePtr(padding, i); + byte *dst = (byte *)surface->getBasePtr(x + padding, y+i); + for (int j = padding; j < _bounds->width() - 2 * padding; j++) { + if (*src != kColorGreen) + *dst = *src; + src++; + dst++; + } + } + } +} + +void Design::render(Patterns &patterns) { + Common::MemoryReadStream in(_data, _len); + bool needRender = true; + + while (needRender) { + byte fillType = in.readByte(); + byte borderThickness = in.readByte(); + byte borderFillType = in.readByte(); + int type = in.readByte(); + + if (in.eos()) + break; + + debug(8, "fill: %d borderFill: %d border: %d type: %d", fillType, borderFillType, borderThickness, type); + switch (type) { + case 4: + drawRect(_surface, in, patterns, fillType, borderThickness, borderFillType); + break; + case 8: + drawRoundRect(_surface, in, patterns, fillType, borderThickness, borderFillType); + break; + case 12: + drawOval(_surface, in, patterns, fillType, borderThickness, borderFillType); + break; + case 16: + case 20: + drawPolygon(_surface, in, patterns, fillType, borderThickness, borderFillType); + break; + case 24: + drawBitmap(_surface, in); + break; + default: + warning("Unknown type => %d", type); + break; + } + + //g_system->copyRectToScreen(_surface->getPixels(), _surface->pitch, 0, 0, _surface->w, _surface->h); + //((WageEngine *)g_engine)->processEvents(); + //g_system->updateScreen(); + //g_system->delayMillis(500); + } +} + +bool Design::isPointOpaque(int x, int y) { + if (_surface == NULL) + error("Surface is null"); + + byte pixel = ((byte *)_surface->getBasePtr(x, y))[0]; + + return pixel != kColorGreen; +} + +void Design::adjustBounds(int16 x, int16 y) { + _bounds->right = MAX(x, _bounds->right); + _bounds->bottom = MAX(y, _bounds->bottom); +} + +void drawPixel(int x, int y, int color, void *data) { + PlotData *p = (PlotData *)data; + + if (p->fillType > p->patterns->size()) + return; + + if (p->design && p->design->isBoundsCalculation()) { + if (x < 0 || y < 0) + return; + if (p->thickness == 1) { + p->design->adjustBounds(x, y); + } else { + int x1 = x - p->thickness / 2; + int x2 = x1 + p->thickness; + int y1 = y - p->thickness / 2; + int y2 = y1 + p->thickness; + + for (y = y1; y < y2; y++) + for (x = x1; x < x2; x++) + p->design->adjustBounds(x, y); + } + + return; + } + + byte *pat = p->patterns->operator[](p->fillType - 1); + + if (p->thickness == 1) { + if (x >= 0 && x < p->surface->w && y >= 0 && y < p->surface->h) { + uint xu = (uint)x; // for letting compiler optimize it + uint yu = (uint)y; + + *((byte *)p->surface->getBasePtr(xu, yu)) = + (pat[yu % 8] & (1 << (7 - xu % 8))) ? + color : kColorWhite; + } + } else { + int x1 = x - p->thickness / 2; + int x2 = x1 + p->thickness; + int y1 = y - p->thickness / 2; + int y2 = y1 + p->thickness; + + for (y = y1; y < y2; y++) + for (x = x1; x < x2; x++) + if (x >= 0 && x < p->surface->w && y >= 0 && y < p->surface->h) { + uint xu = (uint)x; // for letting compiler optimize it + uint yu = (uint)y; + *((byte *)p->surface->getBasePtr(xu, yu)) = + (pat[yu % 8] & (1 << (7 - xu % 8))) ? + color : kColorWhite; + } + } +} + +void drawPixelPlain(int x, int y, int color, void *data) { + PlotData *p = (PlotData *)data; + + if (p->design && p->design->isBoundsCalculation()) { + p->design->adjustBounds(x, y); + return; + } + + if (x >= 0 && x < p->surface->w && y >= 0 && y < p->surface->h) + *((byte *)p->surface->getBasePtr(x, y)) = (byte)color; +} + +void Design::drawRect(Graphics::Surface *surface, Common::ReadStream &in, + Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType) { + int16 y1 = in.readSint16BE(); + int16 x1 = in.readSint16BE(); + int16 y2 = in.readSint16BE(); + int16 x2 = in.readSint16BE(); + + if (x1 > x2) + SWAP(x1, x2); + if (y1 > y2) + SWAP(y1, y2); + + Common::Rect r(x1, y1, x2, y2); + PlotData pd(surface, &patterns, fillType, 1, this); + + if (fillType <= patterns.size()) + Graphics::drawFilledRect(r, kColorBlack, drawPixel, &pd); + + pd.fillType = borderFillType; + pd.thickness = borderThickness; + + if (borderThickness > 0 && borderFillType <= patterns.size()) { + Graphics::drawLine(x1, y1, x2, y1, kColorBlack, drawPixel, &pd); + Graphics::drawLine(x2, y1, x2, y2, kColorBlack, drawPixel, &pd); + Graphics::drawLine(x2, y2, x1, y2, kColorBlack, drawPixel, &pd); + Graphics::drawLine(x1, y2, x1, y1, kColorBlack, drawPixel, &pd); + } +} + +void Design::drawRoundRect(Graphics::Surface *surface, Common::ReadStream &in, + Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType) { + int16 y1 = in.readSint16BE(); + int16 x1 = in.readSint16BE(); + int16 y2 = in.readSint16BE(); + int16 x2 = in.readSint16BE(); + int16 arc = in.readSint16BE(); + + if (x1 > x2) + SWAP(x1, x2); + if (y1 > y2) + SWAP(y1, y2); + + Common::Rect r(x1, y1, x2, y2); + PlotData pd(surface, &patterns, fillType, 1, this); + + if (fillType <= patterns.size()) + Graphics::drawRoundRect(r, arc / 2, kColorBlack, true, drawPixel, &pd); + + pd.fillType = borderFillType; + pd.thickness = borderThickness; + + if (borderThickness > 0 && borderFillType <= patterns.size()) + Graphics::drawRoundRect(r, arc / 2, kColorBlack, false, drawPixel, &pd); +} + +void Design::drawPolygon(Graphics::Surface *surface, Common::ReadStream &in, + Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType) { + + byte ignored = in.readSint16BE(); // ignored + + if (ignored) + warning("Ignored: %d", ignored); + + int numBytes = in.readSint16BE(); // #bytes used by polygon data, including the numBytes + int16 by1 = in.readSint16BE(); + int16 bx1 = in.readSint16BE(); + int16 by2 = in.readSint16BE(); + int16 bx2 = in.readSint16BE(); + Common::Rect bbox(bx1, by1, bx2, by2); + + numBytes -= 8; + + int y1 = in.readSint16BE(); + int x1 = in.readSint16BE(); + + Common::Array<int> xcoords; + Common::Array<int> ycoords; + + numBytes -= 6; + + while (numBytes > 0) { + int y2 = y1; + int x2 = x1; + int b = in.readSByte(); + if (b == -128) { + y2 = in.readSint16BE(); + numBytes -= 3; + } else { + y2 += b; + numBytes -= 1; + } + b = in.readSByte(); + if (b == -128) { + x2 = in.readSint16BE(); + numBytes -= 3; + } else { + x2 += b; + numBytes -= 1; + } + xcoords.push_back(x1); + ycoords.push_back(y1); + x1 = x2; + y1 = y2; + } + xcoords.push_back(x1); + ycoords.push_back(y1); + + int npoints = xcoords.size(); + int *xpoints = (int *)calloc(npoints, sizeof(int)); + int *ypoints = (int *)calloc(npoints, sizeof(int)); + for (int i = 0; i < npoints; i++) { + xpoints[i] = xcoords[i]; + ypoints[i] = ycoords[i]; + } + + PlotData pd(surface, &patterns, fillType, 1, this); + + if (fillType <= patterns.size()) { + Graphics::drawPolygonScan(xpoints, ypoints, npoints, bbox, kColorBlack, drawPixel, &pd); + } + + pd.fillType = borderFillType; + pd.thickness = borderThickness; + if (borderThickness > 0 && borderFillType <= patterns.size()) { + for (int i = 1; i < npoints; i++) + Graphics::drawLine(xpoints[i-1], ypoints[i-1], xpoints[i], ypoints[i], kColorBlack, drawPixel, &pd); + } + + free(xpoints); + free(ypoints); +} + +void Design::drawOval(Graphics::Surface *surface, Common::ReadStream &in, + Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType) { + int16 y1 = in.readSint16BE(); + int16 x1 = in.readSint16BE(); + int16 y2 = in.readSint16BE(); + int16 x2 = in.readSint16BE(); + PlotData pd(surface, &patterns, fillType, 1, this); + + if (fillType <= patterns.size()) + Graphics::drawEllipse(x1, y1, x2-1, y2-1, kColorBlack, true, drawPixel, &pd); + + pd.fillType = borderFillType; + pd.thickness = borderThickness; + + if (borderThickness > 0 && borderFillType <= patterns.size()) + Graphics::drawEllipse(x1, y1, x2-1, y2-1, kColorBlack, false, drawPixel, &pd); +} + +void Design::drawBitmap(Graphics::Surface *surface, Common::SeekableReadStream &in) { + int numBytes = in.readSint16BE(); + int y1 = in.readSint16BE(); + int x1 = in.readSint16BE(); + int y2 = in.readSint16BE(); + int x2 = in.readSint16BE(); + int w = x2 - x1; + int h = y2 - y1; + Graphics::Surface tmp; + + tmp.create(w, h, Graphics::PixelFormat::createFormatCLUT8()); + + numBytes -= 10; + + int x = 0, y = 0; + while (numBytes > 0 && y < h) { + int n = in.readSByte(); + int count; + int b = 0; + int state = 0; + + numBytes--; + + if ((n >= 0) && (n <= 127)) { // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + count = n + 1; + state = 1; + } else if ((n >= -127) && (n <= -1)) { // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + b = in.readByte(); + numBytes--; + count = -n + 1; + state = 2; + } else { // Else if n is -128, noop. + count = 0; + } + + for (int i = 0; i < count && y < h; i++) { + byte color = 0; + if (state == 1) { + color = in.readByte(); + numBytes--; + } else if (state == 2) + color = b; + + for (int c = 0; c < 8; c++) { + if (_boundsCalculationMode) { + adjustBounds(x1 + x, y1 + y); + } else if (x1 + x >= 0 && x1 + x < surface->w && y1 + y >= 0 && y1 + y < surface->h) + *((byte *)tmp.getBasePtr(x, y)) = (color & (1 << (7 - c % 8))) ? kColorBlack : kColorWhite; + x++; + if (x == w) { + y++; + x = 0; + break; + } + } + } + } + + in.skip(numBytes); + + if (_boundsCalculationMode) + return; + + FloodFill ff(&tmp, kColorWhite, kColorGreen); + for (int yy = 0; yy < h; yy++) { + ff.addSeed(0, yy); + ff.addSeed(w - 1, yy); + } + for (int xx = 0; xx < w; xx++) { + ff.addSeed(xx, 0); + ff.addSeed(xx, h - 1); + } + ff.fill(); + + for (y = 0; y < h && y1 + y < surface->h; y++) { + byte *src = (byte *)tmp.getBasePtr(0, y); + byte *dst = (byte *)surface->getBasePtr(x1, y1 + y); + for (x = 0; x < w; x++) { + if (*src != kColorGreen) + *dst = *src; + src++; + dst++; + } + } + + tmp.free(); +} + +void Design::drawRect(Graphics::Surface *surface, Common::Rect &rect, int thickness, int color, Patterns &patterns, byte fillType) { + drawRect(surface, rect.left, rect.top, rect.right, rect.bottom, thickness, color, patterns, fillType); +} + +void Design::drawRect(Graphics::Surface *surface, int x1, int y1, int x2, int y2, int thickness, int color, Patterns &patterns, byte fillType) { + PlotData pd(surface, &patterns, fillType, thickness, nullptr); + + Graphics::drawLine(x1, y1, x2, y1, kColorBlack, drawPixel, &pd); + Graphics::drawLine(x2, y1, x2, y2, kColorBlack, drawPixel, &pd); + Graphics::drawLine(x2, y2, x1, y2, kColorBlack, drawPixel, &pd); + Graphics::drawLine(x1, y2, x1, y1, kColorBlack, drawPixel, &pd); +} + + +void Design::drawFilledRect(Graphics::Surface *surface, Common::Rect &rect, int color, Patterns &patterns, byte fillType) { + PlotData pd(surface, &patterns, fillType, 1, nullptr); + + for (int y = rect.top; y <= rect.bottom; y++) + Graphics::drawHLine(rect.left, rect.right, y, color, drawPixel, &pd); +} + +void Design::drawFilledRoundRect(Graphics::Surface *surface, Common::Rect &rect, int arc, int color, Patterns &patterns, byte fillType) { + PlotData pd(surface, &patterns, fillType, 1, nullptr); + + Graphics::drawRoundRect(rect, arc, color, true, drawPixel, &pd); +} + +void Design::drawHLine(Graphics::Surface *surface, int x1, int x2, int y, int thickness, int color, Patterns &patterns, byte fillType) { + PlotData pd(surface, &patterns, fillType, thickness, nullptr); + + Graphics::drawHLine(x1, x2, y, color, drawPixel, &pd); +} + +void Design::drawVLine(Graphics::Surface *surface, int x, int y1, int y2, int thickness, int color, Patterns &patterns, byte fillType) { + PlotData pd(surface, &patterns, fillType, thickness, nullptr); + + Graphics::drawVLine(x, y1, y2, color, drawPixel, &pd); +} + +FloodFill::FloodFill(Graphics::Surface *surface, byte color1, byte color2) { + _surface = surface; + _color1 = color1; + _color2 = color2; + _w = surface->w; + _h = surface->h; + + _visited = (byte *)calloc(_w * _h, 1); +} + +FloodFill::~FloodFill() { + while(!_queue.empty()) { + Common::Point *p = _queue.front(); + + delete p; + _queue.pop_front(); + } + + free(_visited); +} + +void FloodFill::addSeed(int x, int y) { + byte *p; + + if (x >= 0 && x < _w && y >= 0 && y < _h) { + if (!_visited[y * _w + x] && *(p = (byte *)_surface->getBasePtr(x, y)) == _color1) { + _visited[y * _w + x] = 1; + *p = _color2; + + Common::Point *pt = new Common::Point(x, y); + + _queue.push_back(pt); + } + } +} + +void FloodFill::fill() { + while (!_queue.empty()) { + Common::Point *p = _queue.front(); + _queue.pop_front(); + addSeed(p->x , p->y - 1); + addSeed(p->x - 1, p->y ); + addSeed(p->x , p->y + 1); + addSeed(p->x + 1, p->y ); + + delete p; + } +} + + +} // End of namespace Wage diff --git a/engines/wage/design.h b/engines/wage/design.h new file mode 100644 index 0000000000..e8f42f4e04 --- /dev/null +++ b/engines/wage/design.h @@ -0,0 +1,119 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef WAGE_DESIGN_H +#define WAGE_DESIGN_H + +#include "graphics/surface.h" +#include "common/memstream.h" +#include "common/rect.h" + +namespace Wage { + +class Design { +public: + Design(Common::SeekableReadStream *data); + ~Design(); + + void setBounds(Common::Rect *bounds) { + _bounds = bounds; + } + + Common::Rect *getBounds() { + return _bounds; + } + + void paint(Graphics::Surface *canvas, Patterns &patterns, int x, int y); + bool isPointOpaque(int x, int y); + static void drawRect(Graphics::Surface *surface, Common::Rect &rect, int thickness, int color, Patterns &patterns, byte fillType); + static void drawRect(Graphics::Surface *surface, int x1, int y1, int x2, int y2, int thickness, int color, Patterns &patterns, byte fillType); + static void drawFilledRect(Graphics::Surface *surface, Common::Rect &rect, int color, Patterns &patterns, byte fillType); + static void drawFilledRoundRect(Graphics::Surface *surface, Common::Rect &rect, int arc, int color, Patterns &patterns, byte fillType); + static void drawHLine(Graphics::Surface *surface, int x1, int x2, int y, int thickness, int color, Patterns &patterns, byte fillType); + static void drawVLine(Graphics::Surface *surface, int x, int y1, int y2, int thickness, int color, Patterns &patterns, byte fillType); + + bool isBoundsCalculation() { return _boundsCalculationMode; } + void adjustBounds(int16 x, int16 y); + +private: + byte *_data; + int _len; + Common::Rect *_bounds; + Graphics::Surface *_surface; + bool _boundsCalculationMode; + +private: + void render(Patterns &patterns); + void drawRect(Graphics::Surface *surface, Common::ReadStream &in, + Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType); + void drawRoundRect(Graphics::Surface *surface, Common::ReadStream &in, + Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType); + void drawPolygon(Graphics::Surface *surface, Common::ReadStream &in, + Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType); + void drawOval(Graphics::Surface *surface, Common::ReadStream &in, + Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType); + void drawBitmap(Graphics::Surface *surface, Common::SeekableReadStream &in); +}; + +class FloodFill { +public: + FloodFill(Graphics::Surface *surface, byte color1, byte color2); + ~FloodFill(); + void addSeed(int x, int y); + void fill(); + +private: + Common::List<Common::Point *> _queue; + Graphics::Surface *_surface; + byte _color1, _color2; + byte *_visited; + int _w, _h; +}; + +} // End of namespace Wage + +#endif diff --git a/engines/wage/detection.cpp b/engines/wage/detection.cpp new file mode 100644 index 0000000000..512d432e54 --- /dev/null +++ b/engines/wage/detection.cpp @@ -0,0 +1,151 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + + +#include "base/plugins.h" + +#include "engines/advancedDetector.h" +#include "common/system.h" +#include "common/savefile.h" + +#include "wage/wage.h" + +namespace Wage { + +const char *WageEngine::getGameFile() const { + return _gameDescription->filesDescriptions[0].fileName; +} + +} + +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!"}, + {"wage", "WAGE"}, + {0, 0} +}; + +#include "wage/detection_tables.h" + +class WageMetaEngine : public AdvancedMetaEngine { +public: + WageMetaEngine() : AdvancedMetaEngine(Wage::gameDescriptions, sizeof(ADGameDescription), wageGames) { + _singleId = "wage"; + _guiOptions = GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI); + } + + virtual const char *getName() const { + return "World Adventure Game Engine"; + } + + virtual const char *getOriginalCopyright() const { + return "World Builder (C) Silicon Beach Software"; + } + + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; + virtual bool hasFeature(MetaEngineFeature f) const; + virtual SaveStateList listSaves(const char *target) const; + virtual int getMaximumSaveSlot() const; + virtual void removeSaveState(const char *target, int slot) const; +}; + +bool WageMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsListSaves) || + (f == kSupportsLoadingDuringStartup) || + (f == kSupportsDeleteSave); +} + +bool Wage::WageEngine::hasFeature(EngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsLoadingDuringRuntime) || + (f == kSupportsSavingDuringRuntime); +} + +bool WageMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + if (desc) { + *engine = new Wage::WageEngine(syst, desc); + } + return desc != 0; +} + +SaveStateList WageMetaEngine::listSaves(const char *target) const { + const uint32 WAGEflag = MKTAG('W','A','G','E'); + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringArray filenames; + char saveDesc[31]; + Common::String pattern = target; + pattern += ".???"; + + filenames = saveFileMan->listSavefiles(pattern); + + SaveStateList saveList; + for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { + // Obtain the last 3 digits of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 3); + + if (slotNum >= 0 && slotNum <= 999) { + Common::InSaveFile *in = saveFileMan->openForLoading(*file); + if (in) { + uint32 type = in->readUint32BE(); + if (type == WAGEflag) + in->read(saveDesc, 31); + saveList.push_back(SaveStateDescriptor(slotNum, saveDesc)); + delete in; + } + } + } + + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); + return saveList; +} + +int WageMetaEngine::getMaximumSaveSlot() const { return 999; } + +void WageMetaEngine::removeSaveState(const char *target, int slot) const { + g_system->getSavefileManager()->removeSavefile(Common::String::format("%s.%03d", target, slot)); +} + +#if PLUGIN_ENABLED_DYNAMIC(WAGE) + REGISTER_PLUGIN_DYNAMIC(WAGE, PLUGIN_TYPE_ENGINE, WageMetaEngine); +#else + REGISTER_PLUGIN_STATIC(WAGE, PLUGIN_TYPE_ENGINE, WageMetaEngine); +#endif + +namespace Wage { + +bool WageEngine::canLoadGameStateCurrently() { + return false; +} + +bool WageEngine::canSaveGameStateCurrently() { + return false; +} + +} // End of namespace Wage diff --git a/engines/wage/detection_tables.h b/engines/wage/detection_tables.h new file mode 100644 index 0000000000..e164ea70cd --- /dev/null +++ b/engines/wage/detection_tables.h @@ -0,0 +1,121 @@ +/* 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. + * + */ + +namespace Wage { + +#define ADGF_DEFAULT (ADGF_DROPLANGUAGE|ADGF_DROPPLATFORM|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[] = { + FANGAME("3rd Floor", "913812a1ac7a6b0e48dadd1afa1c7763", 281409), + BIGGAME("afm", "v1.8", "Another Fine Mess 1.8", "94a9c4f8b3dabd1846d76215a49bd221", 1420723), + BIGGAME("amot", "v1.8", "A Mess O' Trouble 1.8", "26207bdf0bb539464f136f0669af885f", 1843104), + FANGAME("Bug Hunt", "595117cbed33e8de1ab3714b33880205", 195699), + 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 + FANGAMEN("Enchanted Pencils", "Enchanted Pencils 0.99 (PG)", "595117cbed33e8de1ab3714b33880205", 408913), + FANGAME("Escape from School!", "913812a1ac7a6b0e48dadd1afa1c7763", 50105), + FANGAME("Exploration Zeta!", "c477921aeee6ed0f8997ba44447eb2d0", 366599), + // 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), + 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 +}; + +} // End of namespace Wage diff --git a/engines/wage/dialog.cpp b/engines/wage/dialog.cpp new file mode 100644 index 0000000000..263570bddc --- /dev/null +++ b/engines/wage/dialog.cpp @@ -0,0 +1,241 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "common/system.h" +#include "common/events.h" + +#include "wage/wage.h" +#include "wage/design.h" +#include "wage/gui.h" +#include "wage/dialog.h" + +namespace Wage { + +enum { + kDialogHeight = 113 +}; + +Dialog::Dialog(Gui *gui, int width, const char *text, DialogButtonArray *buttons, uint defaultButton) : + _gui(gui), _text(text), _buttons(buttons), _defaultButton(defaultButton) { + assert(_gui->_engine); + assert(_gui->_engine->_world); + + _font = getDialogFont(); + + _tempSurface.create(width + 1, kDialogHeight + 1, Graphics::PixelFormat::createFormatCLUT8()); + + _bbox.left = (_gui->_screen.w - width) / 2; + _bbox.top = (_gui->_screen.h - kDialogHeight) / 2; + _bbox.right = (_gui->_screen.w + width) / 2; + _bbox.bottom = (_gui->_screen.h + kDialogHeight) / 2; + + _pressedButton = -1; + + _mouseOverPressedButton = false; + + // Adjust button positions + for (uint i = 0; i < _buttons->size(); i++) + _buttons->operator[](i)->bounds.translate(_bbox.left, _bbox.top); + + _needsRedraw = true; +} + +Dialog::~Dialog() { +} + +const Graphics::Font *Dialog::getDialogFont() { + return _gui->getFont("Chicago-12", Graphics::FontManager::kBigGUIFont); +} + +void Dialog::paint() { + Design::drawFilledRect(&_gui->_screen, _bbox, kColorWhite, _gui->_patterns, kPatternSolid); + _font->drawString(&_gui->_screen, _text, _bbox.left + 24, _bbox.top + 16, _bbox.width(), kColorBlack); + + static int boxOutline[] = { 1, 0, 0, 1, 1 }; + drawOutline(_bbox, boxOutline, ARRAYSIZE(boxOutline)); + + for (uint i = 0; i < _buttons->size(); i++) { + DialogButton *button = _buttons->operator[](i); + static int buttonOutline[] = { 0, 0, 0, 0, 1 }; + + if (i == _defaultButton) { + buttonOutline[0] = buttonOutline[1] = 1; + } else { + buttonOutline[0] = buttonOutline[1] = 0; + } + + int color = kColorBlack; + + if ((int)i == _pressedButton && _mouseOverPressedButton) { + Common::Rect bb(button->bounds.left + 5, button->bounds.top + 5, + button->bounds.right - 5, button->bounds.bottom - 5); + + Design::drawFilledRect(&_gui->_screen, bb, kColorBlack, _gui->_patterns, kPatternSolid); + + color = kColorWhite; + } + int w = _font->getStringWidth(button->text); + int x = button->bounds.left + (button->bounds.width() - w) / 2; + int y = button->bounds.top + 6; + + _font->drawString(&_gui->_screen, button->text, x, y, _bbox.width(), color); + + drawOutline(button->bounds, buttonOutline, ARRAYSIZE(buttonOutline)); + } + + g_system->copyRectToScreen(_gui->_screen.getBasePtr(_bbox.left, _bbox.top), _gui->_screen.pitch, + _bbox.left, _bbox.top, _bbox.width() + 1, _bbox.height() + 1); + + _needsRedraw = false; +} + +void Dialog::drawOutline(Common::Rect &bounds, int *spec, int speclen) { + for (int i = 0; i < speclen; i++) + if (spec[i] != 0) + Design::drawRect(&_gui->_screen, bounds.left + i, bounds.top + i, bounds.right - i, bounds.bottom - i, + 1, kColorBlack, _gui->_patterns, kPatternSolid); +} + +int Dialog::run() { + bool shouldQuit = false; + Common::Rect r(_bbox); + + _tempSurface.copyRectToSurface(_gui->_screen.getBasePtr(_bbox.left, _bbox.top), _gui->_screen.pitch, 0, 0, _bbox.width() + 1, _bbox.height() + 1); + _gui->pushArrowCursor(); + + while (!shouldQuit) { + Common::Event event; + + while (_gui->_engine->_eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_QUIT: + _gui->_engine->_shouldQuit = true; + shouldQuit = true; + break; + case Common::EVENT_MOUSEMOVE: + mouseMove(event.mouse.x, event.mouse.y); + break; + case Common::EVENT_LBUTTONDOWN: + mouseClick(event.mouse.x, event.mouse.y); + break; + case Common::EVENT_LBUTTONUP: + shouldQuit = mouseRaise(event.mouse.x, event.mouse.y); + break; + case Common::EVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_ESCAPE: + _pressedButton = -1; + shouldQuit = true; + default: + break; + } + break; + default: + break; + } + } + + if (_needsRedraw) + paint(); + + g_system->updateScreen(); + g_system->delayMillis(50); + } + + _gui->_screen.copyRectToSurface(_tempSurface.getBasePtr(0, 0), _tempSurface.pitch, _bbox.left, _bbox.top, _bbox.width() + 1, _bbox.height() + 1); + g_system->copyRectToScreen(_gui->_screen.getBasePtr(r.left, r.top), _gui->_screen.pitch, r.left, r.top, r.width() + 1, r.height() + 1); + + _gui->popCursor(); + + return _pressedButton; +} + +int Dialog::matchButton(int x, int y) { + for (uint i = 0; i < _buttons->size(); i++) + if (_buttons->operator[](i)->bounds.contains(x, y)) + return i; + + return -1; +} + +void Dialog::mouseMove(int x, int y) { + if (_pressedButton != -1) { + int match = matchButton(x, y); + + if (_mouseOverPressedButton && match != _pressedButton) { + _mouseOverPressedButton = false; + _needsRedraw = true; + } else if (!_mouseOverPressedButton && match == _pressedButton) { + _mouseOverPressedButton = true; + _needsRedraw = true; + } + } +} + +void Dialog::mouseClick(int x, int y) { + int match = matchButton(x, y); + + if (match != -1) { + _pressedButton = match; + _mouseOverPressedButton = true; + + _needsRedraw = true; + } +} + +int Dialog::mouseRaise(int x, int y) { + bool res = false; + + if (_pressedButton != -1) { + if (matchButton(x, y) == _pressedButton) + res = true; + } + + return res; +} + +} // End of namespace Wage diff --git a/engines/wage/dialog.h b/engines/wage/dialog.h new file mode 100644 index 0000000000..c5878acc95 --- /dev/null +++ b/engines/wage/dialog.h @@ -0,0 +1,101 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef WAGE_DIALOG_H +#define WAGE_DIALOG_H + +namespace Wage { + +struct DialogButton { + Common::String text; + Common::Rect bounds; + + DialogButton(const char *t, int x1, int y1, int w, int h) { + text = t; + bounds.left = x1; + bounds.top = y1; + bounds.right = x1 + w - 1; + bounds.bottom = y1 + h - 1; + } +}; + +typedef Common::Array<DialogButton *> DialogButtonArray; + +class Dialog { +public: + Dialog(Gui *gui, int width, const char *text, DialogButtonArray *buttons, uint defaultButton); + ~Dialog(); + + int run(); + +private: + Gui *_gui; + Graphics::Surface _tempSurface; + Common::Rect _bbox; + Common::String _text; + + const Graphics::Font *_font; + DialogButtonArray *_buttons; + int _pressedButton; + uint _defaultButton; + bool _mouseOverPressedButton; + + bool _needsRedraw; + +private: + const Graphics::Font *getDialogFont(); + void drawOutline(Common::Rect &bounds, int *spec, int speclen); + void paint(); + void mouseMove(int x, int y); + void mouseClick(int x, int y); + int mouseRaise(int x, int y); + int matchButton(int x, int y); +}; + +} // End of namespace Wage + +#endif diff --git a/engines/wage/entities.cpp b/engines/wage/entities.cpp new file mode 100644 index 0000000000..a2648c49fe --- /dev/null +++ b/engines/wage/entities.cpp @@ -0,0 +1,514 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "wage/wage.h" +#include "wage/entities.h" +#include "wage/design.h" +#include "wage/script.h" +#include "wage/world.h" + +#include "common/memstream.h" + +namespace Wage { + +void Designed::setDesignBounds(Common::Rect *bounds) { + _designBounds = bounds; + _design->setBounds(bounds); +} + +Designed::~Designed() { + delete _design; + delete _designBounds; +} + +Context::Context() { + _visits = 0; + _kills = 0; + _experience = 0; + _frozen = false; + + for (int i = 0; i < 26 * 9; i++) + _userVariables[i] = 0; + + for (int i = 0; i < 18; i++) + _statVariables[i] = 0; +} + +Scene::Scene() { + _script = NULL; + _design = NULL; + _textBounds = NULL; + _fontSize = 0; + _fontType = 0; + + for (int i = 0; i < 4; i++) + _blocked[i] = false; + + _soundFrequency = 0; + _soundType = 0; + _worldX = 0; + _worldY = 0; + + _visited = false; +} + +Scene::Scene(Common::String name, Common::SeekableReadStream *data) { + debug(9, "Creating scene: %s", name.c_str()); + + _name = name; + _classType = SCENE; + _design = new Design(data); + + _script = NULL; + _textBounds = NULL; + _fontSize = 0; + _fontType = 0; + + setDesignBounds(readRect(data)); + _worldY = data->readSint16BE(); + _worldX = data->readSint16BE(); + _blocked[NORTH] = (data->readByte() != 0); + _blocked[SOUTH] = (data->readByte() != 0); + _blocked[EAST] = (data->readByte() != 0); + _blocked[WEST] = (data->readByte() != 0); + _soundFrequency = data->readSint16BE(); + _soundType = data->readByte(); + data->readByte(); // unknown + _messages[NORTH] = readPascalString(data); + _messages[SOUTH] = readPascalString(data); + _messages[EAST] = readPascalString(data); + _messages[WEST] = readPascalString(data); + _soundName = readPascalString(data); + + _visited = false; + + delete data; +} + +Scene::~Scene() { + delete _script; + delete _textBounds; +} + +void Scene::paint(Graphics::Surface *surface, int x, int y) { + Common::Rect r(x + 5, y + 5, _design->getBounds()->width() + x - 10, _design->getBounds()->height() + y - 10); + surface->fillRect(r, kColorWhite); + + _design->paint(surface, ((WageEngine *)g_engine)->_world->_patterns, x, y); + + for (ObjList::const_iterator it = _objs.begin(); it != _objs.end(); ++it) { + debug(2, "paining Obj: %s", (*it)->_name.c_str()); + (*it)->_design->paint(surface, ((WageEngine *)g_engine)->_world->_patterns, x, y); + } + + for (ChrList::const_iterator it = _chrs.begin(); it != _chrs.end(); ++it) { + debug(2, "paining Chr: %s", (*it)->_name.c_str()); + (*it)->_design->paint(surface, ((WageEngine *)g_engine)->_world->_patterns, x, y); + } +} + +// Source: Apple IIGS Technical Note #41, "Font Family Numbers" +// http://apple2.boldt.ca/?page=til/tn.iigs.041 +static const char *const fontNames[] = { + "Chicago", // system font + "Geneva", // application font + "New York", + "Geneva", + + "Monaco", + "Venice", + "London", + "Athens", + + "San Francisco", + "Toronto", + NULL, + "Cairo", + "Los Angeles", // 12 + + "Zapf Dingbats", + "Bookman", + "Helvetica Narrow", + "Palatino", + NULL, + "Zapf Chancery", + NULL, + + "Times", // 20 + "Helvetica", + "Courier", + "Symbol", + "Taliesin", // mobile? + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, // 30 + NULL, + NULL, + "Avant Garde", + "New Century Schoolbook" +}; + +const char *Scene::getFontName() { + if (_fontType >= 0 && _fontType < ARRAYSIZE(fontNames) && fontNames[_fontType] != NULL) { + return fontNames[_fontType]; + } + return "Unknown"; +} + +Obj::Obj() : _currentOwner(NULL), _currentScene(NULL) { + _index = 0; + _namePlural = false; + _value = 0; + _attackType = 0; + _numberOfUses = 0; + _returnToRandomScene = false; + _type = 0; + _accuracy = 0; + _damage = 0; +} + +Obj::Obj(Common::String name, Common::SeekableReadStream *data) { + _name = name; + _classType = OBJ; + _currentOwner = NULL; + _currentScene = NULL; + + _index = 0; + + _design = new Design(data); + + setDesignBounds(readRect(data)); + + int16 namePlural = data->readSint16BE(); + + if (namePlural == 256) + _namePlural = true; // TODO: other flags? + else if (namePlural == 0) + _namePlural = false; + else + error("Obj <%s> had weird namePlural set (%d)", name.c_str(), namePlural); + + if (data->readSint16BE() != 0) + error("Obj <%s> had short set", name.c_str()); + + if (data->readByte() != 0) + error("Obj <%s> had byte set", name.c_str()); + + _accuracy = data->readByte(); + _value = data->readByte(); + _type = data->readSByte(); + _damage = data->readByte(); + _attackType = data->readSByte(); + _numberOfUses = data->readSint16BE(); + int16 returnTo = data->readSint16BE(); + if (returnTo == 256) // TODO any other possibilities? + _returnToRandomScene = true; + else if (returnTo == 0) + _returnToRandomScene = false; + else + error("Obj <%s> had weird returnTo set", name.c_str()); + + _sceneOrOwner = readPascalString(data); + _clickMessage = readPascalString(data); + _operativeVerb = readPascalString(data); + _failureMessage = readPascalString(data); + _useMessage = readPascalString(data); + _sound = readPascalString(data); + + delete data; +} + +Obj::~Obj() { +} + +Chr *Obj::removeFromChr() { + if (_currentOwner != NULL) { + for (int i = (int)_currentOwner->_inventory.size() - 1; i >= 0; i--) + if (_currentOwner->_inventory[i] == this) + _currentOwner->_inventory.remove_at(i); + + for (int i = 0; i < Chr::NUMBER_OF_ARMOR_TYPES; i++) { + if (_currentOwner->_armor[i] == this) { + _currentOwner->_armor[i] = NULL; + } + } + } + + return _currentOwner; +} + +Designed *Obj::removeFromCharOrScene() { + Designed *from = removeFromChr(); + + if (_currentScene != NULL) { + _currentScene->_objs.remove(this); + from = _currentScene; + } + + return from; +} + +void Obj::resetState(Chr *owner, Scene *scene) { + warning("STUB: Obj::resetState()"); +} + +Chr::Chr(Common::String name, Common::SeekableReadStream *data) { + _name = name; + _classType = CHR; + _design = new Design(data); + + _index = 0; + _currentScene = NULL; + + setDesignBounds(readRect(data)); + + _physicalStrength = data->readByte(); + _physicalHp = data->readByte(); + _naturalArmor = data->readByte(); + _physicalAccuracy = data->readByte(); + + _spiritualStength = data->readByte(); + _spiritialHp = data->readByte(); + _resistanceToMagic = data->readByte(); + _spiritualAccuracy = data->readByte(); + + _runningSpeed = data->readByte(); + _rejectsOffers = data->readByte(); + _followsOpponent = data->readByte(); + + data->readSByte(); // TODO: ??? + data->readSint32BE(); // TODO: ??? + + _weaponDamage1 = data->readByte(); + _weaponDamage2 = data->readByte(); + + data->readSByte(); // TODO: ??? + + if (data->readSByte() == 1) + _playerCharacter = true; + else + _playerCharacter = false; + + _maximumCarriedObjects = data->readByte(); + _returnTo = data->readSByte(); + + _winningWeapons = data->readByte(); + _winningMagic = data->readByte(); + _winningRun = data->readByte(); + _winningOffer = data->readByte(); + _losingWeapons = data->readByte(); + _losingMagic = data->readByte(); + _losingRun = data->readByte(); + _losingOffer = data->readByte(); + + _gender = data->readSByte(); + if (data->readSByte() == 1) + _nameProperNoun = true; + else + _nameProperNoun = false; + + _initialScene = readPascalString(data); + _nativeWeapon1 = readPascalString(data); + _operativeVerb1 = readPascalString(data); + _nativeWeapon2 = readPascalString(data); + _operativeVerb2 = readPascalString(data); + + _initialComment = readPascalString(data); + _scoresHitComment = readPascalString(data); + _receivesHitComment = readPascalString(data); + _makesOfferComment = readPascalString(data); + _rejectsOfferComment = readPascalString(data); + _acceptsOfferComment = readPascalString(data); + _dyingWords = readPascalString(data); + + _initialSound = readPascalString(data); + _scoresHitSound = readPascalString(data); + _receivesHitSound = readPascalString(data); + _dyingSound = readPascalString(data); + + _weaponSound1 = readPascalString(data); + _weaponSound2 = readPascalString(data); + + for (int i = 0; i < NUMBER_OF_ARMOR_TYPES; i++) + _armor[i] = NULL; + + _weapon1 = NULL; + _weapon2 = NULL; + + // Create native weapons + if (!_nativeWeapon1.empty() && !_operativeVerb1.empty()) { + _weapon1 = new Obj; + + _weapon1->_name = _nativeWeapon1; + _weapon1->_operativeVerb = _operativeVerb1; + _weapon1->_type = Obj::REGULAR_WEAPON; + _weapon1->_accuracy = 0; + _weapon1->_damage = _weaponDamage1; + _weapon1->_sound = _weaponSound1; + } + + if (!_nativeWeapon2.empty() && !_operativeVerb2.empty()) { + _weapon2 = new Obj; + + _weapon2->_name = _nativeWeapon2; + _weapon2->_operativeVerb = _operativeVerb2; + _weapon2->_type = Obj::REGULAR_WEAPON; + _weapon2->_accuracy = 0; + _weapon2->_damage = _weaponDamage2; + _weapon2->_sound = _weaponSound2; + } + + delete data; +} + +void Chr::resetState() { + _context._statVariables[PHYS_STR_BAS] = _context._statVariables[PHYS_STR_CUR] = _physicalStrength; + _context._statVariables[PHYS_HIT_BAS] = _context._statVariables[PHYS_HIT_CUR] = _physicalHp; + _context._statVariables[PHYS_ARM_BAS] = _context._statVariables[PHYS_ARM_CUR] = _naturalArmor; + _context._statVariables[PHYS_ACC_BAS] = _context._statVariables[PHYS_ACC_CUR] = _physicalAccuracy; + + _context._statVariables[SPIR_STR_BAS] = _context._statVariables[SPIR_STR_CUR] = _spiritualStength; + _context._statVariables[SPIR_HIT_BAS] = _context._statVariables[SPIR_HIT_CUR] = _spiritialHp; + _context._statVariables[SPIR_ARM_BAS] = _context._statVariables[SPIR_ARM_CUR] = _naturalArmor; + _context._statVariables[SPIR_ACC_BAS] = _context._statVariables[SPIR_ACC_CUR] = _physicalAccuracy; + + _context._statVariables[PHYS_SPE_BAS] = _context._statVariables[PHYS_SPE_CUR] = _runningSpeed; +} + +ObjArray *Chr::getWeapons(bool includeMagic) { + ObjArray *list = new ObjArray; + + if (_weapon1) + list->push_back(_weapon1); + + if (_weapon2) + list->push_back(_weapon2); + + for (uint i = 0; i < _inventory.size(); i++) + switch (_inventory[i]->_type) { + case Obj::REGULAR_WEAPON: + case Obj::THROW_WEAPON: + list->push_back(_inventory[i]); + break; + case Obj::MAGICAL_OBJECT: + if (includeMagic) + list->push_back(_inventory[i]); + break; + default: + break; + } + + return list; +} + +ObjArray *Chr::getMagicalObjects() { + ObjArray *list = new ObjArray; + + for (uint i = 0; i < _inventory.size(); i++) + if (_inventory[i]->_type == Obj::MAGICAL_OBJECT) + list->push_back(_inventory[i]); + + return list; +} + +void Chr::wearObjs() { + for (uint i = 0; i < _inventory.size(); i++) + wearObjIfPossible(_inventory[i]); +} + +int Chr::wearObjIfPossible(Obj *obj) { + switch (obj->_type) { + case Obj::HELMET: + if (_armor[HEAD_ARMOR] == NULL) { + _armor[HEAD_ARMOR] = obj; + return Chr::HEAD_ARMOR; + } + break; + case Obj::CHEST_ARMOR: + if (_armor[BODY_ARMOR] == NULL) { + _armor[BODY_ARMOR] = obj; + return Chr::BODY_ARMOR; + } + break; + case Obj::SHIELD: + if (_armor[SHIELD_ARMOR] == NULL) { + _armor[SHIELD_ARMOR] = obj; + return Chr::SHIELD_ARMOR; + } + break; + case Obj::SPIRITUAL_ARMOR: + if (_armor[MAGIC_ARMOR] == NULL) { + _armor[MAGIC_ARMOR] = obj; + return Chr::MAGIC_ARMOR; + } + break; + default: + return -1; + } + + return -1; +} + +const char *Chr::getDefiniteArticle(bool capitalize) { + if (!_nameProperNoun) + return capitalize ? "The " : "the "; + + return ""; +} + +bool Chr::isWearing(Obj *obj) { + for (int i = 0; i < NUMBER_OF_ARMOR_TYPES; i++) + if (_armor[i] == obj) + return true; + + return false; +} + +} // End of namespace Wage diff --git a/engines/wage/entities.h b/engines/wage/entities.h new file mode 100644 index 0000000000..33cf087322 --- /dev/null +++ b/engines/wage/entities.h @@ -0,0 +1,336 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef WAGE_ENTITIES_H +#define WAGE_ENTITIES_H + +namespace Graphics { + struct Surface; +} + +namespace Wage { + +class Design; +class Script; + +enum StatVariable { +/** The base physical accuracy of the player. */ + PHYS_ACC_BAS = 0, +/** The current physical accuracy of the player. */ + PHYS_ACC_CUR = 1, +/** The base physical armor of the player. */ + PHYS_ARM_BAS = 2, +/** The current physical armor of the player. */ + PHYS_ARM_CUR = 3, +/** The base physical hit points of the player. */ + PHYS_HIT_BAS = 4, +/** The current physical hit points of the player. */ + PHYS_HIT_CUR = 5, +/** The base physical speed of the player. */ + PHYS_SPE_BAS = 6, +/** The current physical speed of the player. */ + PHYS_SPE_CUR = 7, +/** The base physical strength of the player. */ + PHYS_STR_BAS = 8, +/** The current physical strength of the player. */ + PHYS_STR_CUR = 9, +/** The base spiritual accuracy of the player. */ + SPIR_ACC_BAS = 10, +/** The current spiritual accuracy of the player. */ + SPIR_ACC_CUR = 11, +/** The base spiritual armor of the player. */ + SPIR_ARM_BAS = 12, +/** The current spiritual armor of the player. */ + SPIR_ARM_CUR = 13, +/** The base spiritual hit points of the player. */ + SPIR_HIT_BAS = 14, +/** The current spiritual hit points of the player. */ + SPIR_HIT_CUR = 15, +/** The base spiritual strength of the player. */ + SPIR_STR_BAS = 16, +/** The current spiritual strength of the player. */ + SPIR_STR_CUR = 17 +}; + +class Context { +public: + Context(); + + int16 _visits; // Number of scenes visited, including repeated visits + int16 _kills; // Number of characters killed + int16 _experience; + bool _frozen; + int16 _userVariables[26 * 9]; + int16 _statVariables[18]; +}; + +class Designed { +public: + Designed() : _design(NULL), _designBounds(NULL), _classType(UNKNOWN) {} + ~Designed(); + + Common::String _name; + Design *_design; + Common::Rect *_designBounds; + OperandType _classType; + + Common::Rect *getDesignBounds() { + return _designBounds == NULL ? NULL : new Common::Rect(*_designBounds); + } + + void setDesignBounds(Common::Rect *bounds); + + Common::String toString() { if (!this) return "<NULL>"; return _name; } +}; + +class Chr : public Designed { +public: + enum ChrDestination { + RETURN_TO_STORAGE = 0, + RETURN_TO_RANDOM_SCENE = 1, + RETURN_TO_INITIAL_SCENE = 2 + }; + + enum ChrPart { + HEAD = 0, + CHEST = 1, + SIDE = 2 + }; + + enum ChrArmorType { + HEAD_ARMOR = 0, + BODY_ARMOR = 1, + SHIELD_ARMOR = 2, + MAGIC_ARMOR = 3, + NUMBER_OF_ARMOR_TYPES = 4 + }; + + Chr(Common::String name, Common::SeekableReadStream *data); + + int _index; + Common::String _initialScene; + int _gender; + bool _nameProperNoun; + bool _playerCharacter; + uint _maximumCarriedObjects; + int _returnTo; + + int _physicalStrength; + int _physicalHp; + int _naturalArmor; + int _physicalAccuracy; + int _spiritualStength; + int _spiritialHp; + int _resistanceToMagic; + int _spiritualAccuracy; + int _runningSpeed; + uint _rejectsOffers; + int _followsOpponent; + + Common::String _initialSound; + Common::String _scoresHitSound; + Common::String _receivesHitSound; + Common::String _dyingSound; + + Common::String _nativeWeapon1; + Common::String _operativeVerb1; + int _weaponDamage1; + Common::String _weaponSound1; + + Common::String _nativeWeapon2; + Common::String _operativeVerb2; + int _weaponDamage2; + Common::String _weaponSound2; + + int _winningWeapons; + int _winningMagic; + int _winningRun; + int _winningOffer; + int _losingWeapons; + int _losingMagic; + int _losingRun; + int _losingOffer; + + Common::String _initialComment; + Common::String _scoresHitComment; + Common::String _receivesHitComment; + Common::String _makesOfferComment; + Common::String _rejectsOfferComment; + Common::String _acceptsOfferComment; + Common::String _dyingWords; + + Scene *_currentScene; + ObjArray _inventory; + + Obj *_armor[NUMBER_OF_ARMOR_TYPES]; + + Context _context; + + ObjArray *getWeapons(bool includeMagic); + ObjArray *getMagicalObjects(); + const char *getDefiniteArticle(bool capitalize); + + Obj *_weapon1; + Obj *_weapon2; + +public: + int wearObjIfPossible(Obj *obj); + void wearObjs(); + + void resetState(); + + bool isWearing(Obj *obj); +}; + +class Obj : public Designed { +public: + Obj(); + Obj(Common::String name, Common::SeekableReadStream *data); + ~Obj(); + + enum ObjectType { + REGULAR_WEAPON = 1, + THROW_WEAPON = 2, + MAGICAL_OBJECT = 3, + HELMET = 4, + SHIELD = 5, + CHEST_ARMOR = 6, + SPIRITUAL_ARMOR = 7, + MOBILE_OBJECT = 8, + IMMOBILE_OBJECT = 9 + }; + + enum AttackType { + CAUSES_PHYSICAL_DAMAGE = 0, + CAUSES_SPIRITUAL_DAMAGE = 1, + CAUSES_PHYSICAL_AND_SPIRITUAL_DAMAGE = 2, + HEALS_PHYSICAL_DAMAGE = 3, + HEALS_SPIRITUAL_DAMAGE = 4, + HEALS_PHYSICAL_AND_SPIRITUAL_DAMAGE = 5, + FREEZES_OPPONENT = 6 + }; + +public: + int _index; + bool _namePlural; + uint _value; + int _attackType; + int _numberOfUses; + bool _returnToRandomScene; + Common::String _sceneOrOwner; + Common::String _clickMessage; + Common::String _failureMessage; + Common::String _useMessage; + + Scene *_currentScene; + Chr *_currentOwner; + + int _type; + uint _accuracy; + Common::String _operativeVerb; + int _damage; + Common::String _sound; + +public: + void setCurrentOwner(Chr *currentOwner) { + _currentOwner = currentOwner; + if (currentOwner != NULL) + _currentScene = NULL; + } + + void setCurrentScene(Scene *currentScene) { + _currentScene = currentScene; + if (currentScene != NULL) + _currentOwner = NULL; + } + + Chr *removeFromChr(); + Designed *removeFromCharOrScene(); + + void resetState(Chr *owner, Scene *scene); +}; + +class Scene : public Designed { +public: + enum SceneTypes { + PERIODIC = 0, + RANDOM = 1 + }; + + Script *_script; + Common::String _text; + Common::Rect *_textBounds; + int _fontSize; + int _fontType; // 3 => Geneva, 22 => Courier, param to TextFont() function + bool _blocked[4]; + Common::String _messages[4]; + int _soundFrequency; // times a minute, max 3600 + int _soundType; + Common::String _soundName; + int _worldX; + int _worldY; + bool _visited; + + ObjList _objs; + ChrList _chrs; + + Scene(); + Scene(Common::String name, Common::SeekableReadStream *data); + ~Scene(); + + Common::Rect *getTextBounds() { + return _textBounds == NULL ? NULL : new Common::Rect(*_textBounds); + } + + void paint(Graphics::Surface *screen, int x, int y); + + const char *getFontName(); +}; + +} // End of namespace Wage + +#endif diff --git a/engines/wage/gui-console.cpp b/engines/wage/gui-console.cpp new file mode 100644 index 0000000000..ab5df637ec --- /dev/null +++ b/engines/wage/gui-console.cpp @@ -0,0 +1,430 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "common/timer.h" +#include "common/unzip.h" +#include "graphics/cursorman.h" +#include "graphics/fonts/bdf.h" +#include "graphics/palette.h" + +#include "wage/wage.h" +#include "wage/design.h" +#include "wage/entities.h" +#include "wage/menu.h" +#include "wage/gui.h" +#include "wage/world.h" + +namespace Wage { + +const Graphics::Font *Gui::getConsoleFont() { + char fontName[128]; + Scene *scene = _engine->_world->_player->_currentScene; + + snprintf(fontName, 128, "%s-%d", scene->getFontName(), scene->_fontSize); + + return getFont(fontName, Graphics::FontManager::kConsoleFont); +} + +void Gui::clearOutput() { + _out.clear(); + _lines.clear(); + _consoleFullRedraw = true; +} + +void Gui::appendText(const char *s) { + Common::String str(s); + _consoleDirty = true; + + if (!str.contains('\n')) { + _out.push_back(str); + flowText(str); + return; + } + + // Okay, we got new lines, need to split it + // and push substrings individually + Common::String tmp; + + for (uint i = 0; i < str.size(); i++) { + if (str[i] == '\n') { + _out.push_back(tmp); + flowText(tmp); + tmp.clear(); + continue; + } + + tmp += str[i]; + } + + _out.push_back(tmp); + flowText(tmp); +} + +enum { + kConWOverlap = 20, + kConHOverlap = 20, + kConWPadding = 3, + kConHPadding = 4, + kConOverscan = 3 +}; + +void Gui::flowText(Common::String &str) { + Common::StringArray wrappedLines; + int textW = _consoleTextArea.width() - kConWPadding * 2; + const Graphics::Font *font = getConsoleFont(); + + font->wordWrapText(str, textW, wrappedLines); + + if (wrappedLines.empty()) // Sometimes we have empty lines + _lines.push_back(""); + + for (Common::StringArray::const_iterator j = wrappedLines.begin(); j != wrappedLines.end(); ++j) + _lines.push_back(*j); + + uint pos = _scrollPos; + _scrollPos = MAX<int>(0, (_lines.size() - 1 - _consoleNumLines) * _consoleLineHeight); + + _cursorX = kConWPadding; + + if (_scrollPos) + _cursorY = (_consoleNumLines) * _consoleLineHeight + kConHPadding; + else + _cursorY = (_lines.size() - 1) * _consoleLineHeight + kConHPadding; + + if (pos != _scrollPos) + _consoleFullRedraw = true; + + if (!_engine->_temporarilyHidden) + draw(); +} + +void Gui::renderConsole(Graphics::Surface *g, Common::Rect &r) { + bool fullRedraw = _consoleFullRedraw; + bool textReflow = false; + int surfW = r.width() + kConWOverlap * 2; + int surfH = r.height() + kConHOverlap * 2; + + Common::Rect boundsR(kConWOverlap - kConOverscan, kConHOverlap - kConOverscan, + r.width() + kConWOverlap + kConOverscan, r.height() + kConHOverlap + kConOverscan); + Common::Rect fullR(0, 0, surfW, surfH); + + if (_console.w != surfW || _console.h != surfH) { + if (_console.w != surfW) + textReflow = true; + + _console.free(); + + _console.create(surfW, surfH, Graphics::PixelFormat::createFormatCLUT8()); + fullRedraw = true; + } + + if (fullRedraw) + _console.fillRect(fullR, kColorWhite); + + const Graphics::Font *font = getConsoleFont(); + + _consoleLineHeight = font->getFontHeight(); + int textW = r.width() - kConWPadding * 2; + int textH = r.height() - kConHPadding * 2; + + if (textReflow) { + _lines.clear(); + + for (uint i = 0; i < _out.size(); i++) + flowText(_out[i]); + } + + const int firstLine = _scrollPos / _consoleLineHeight; + const int lastLine = MIN((_scrollPos + textH) / _consoleLineHeight + 1, _lines.size()); + const int xOff = kConWOverlap; + const int yOff = kConHOverlap; + int x1 = xOff + kConWPadding; + int y1 = yOff - (_scrollPos % _consoleLineHeight) + kConHPadding; + + if (fullRedraw) + _consoleNumLines = (r.height() - 2 * kConWPadding) / _consoleLineHeight - 2; + + for (int line = firstLine; line < lastLine; line++) { + const char *str = _lines[line].c_str(); + int color = kColorBlack; + + if ((line > _selectionStartY && line < _selectionEndY) || + (line > _selectionEndY && line < _selectionStartY)) { + color = kColorWhite; + Common::Rect trect(0, y1, _console.w, y1 + _consoleLineHeight); + + Design::drawFilledRect(&_console, trect, kColorBlack, _patterns, kPatternSolid); + } + + if (line == _selectionStartY || line == _selectionEndY) { + if (_selectionStartY != _selectionEndY) { + int color1 = kColorBlack; + int color2 = kColorWhite; + int midpoint = _selectionStartX; + + if (_selectionStartY > _selectionEndY) + SWAP(color1, color2); + + if (line == _selectionEndY) { + SWAP(color1, color2); + midpoint = _selectionEndX; + } + + Common::String beg(_lines[line].c_str(), &_lines[line].c_str()[midpoint]); + Common::String end(&_lines[line].c_str()[midpoint]); + + int rectW = font->getStringWidth(beg) + kConWPadding + kConWOverlap; + Common::Rect trect(0, y1, _console.w, y1 + _consoleLineHeight); + if (color1 == kColorWhite) + trect.right = rectW; + else + trect.left = rectW; + + Design::drawFilledRect(&_console, trect, kColorBlack, _patterns, kPatternSolid); + + font->drawString(&_console, beg, x1, y1, textW, color1); + font->drawString(&_console, end, x1 + rectW - kConWPadding - kConWOverlap, y1, textW, color2); + } else { + int startPos = _selectionStartX; + int endPos = _selectionEndX; + + if (startPos > endPos) + SWAP(startPos, endPos); + + Common::String beg(_lines[line].c_str(), &_lines[line].c_str()[startPos]); + Common::String mid(&_lines[line].c_str()[startPos], &_lines[line].c_str()[endPos]); + Common::String end(&_lines[line].c_str()[endPos]); + + int rectW1 = font->getStringWidth(beg) + kConWPadding + kConWOverlap; + int rectW2 = rectW1 + font->getStringWidth(mid); + Common::Rect trect(rectW1, y1, rectW2, y1 + _consoleLineHeight); + + Design::drawFilledRect(&_console, trect, kColorBlack, _patterns, kPatternSolid); + + font->drawString(&_console, beg, x1, y1, textW, kColorBlack); + font->drawString(&_console, mid, x1 + rectW1 - kConWPadding - kConWOverlap, y1, textW, kColorWhite); + font->drawString(&_console, end, x1 + rectW2 - kConWPadding - kConWOverlap, y1, textW, kColorBlack); + } + } else { + if (*str) + font->drawString(&_console, _lines[line], x1, y1, textW, color); + } + + y1 += _consoleLineHeight; + } + + // Now we need to clip it to the screen + int xcon = r.left - kConOverscan; + int ycon = r.top - kConOverscan; + if (xcon < 0) { + boundsR.left -= xcon; + xcon = 0; + } + if (ycon < 0) { + boundsR.top -= ycon; + ycon = 0; + } + if (xcon + boundsR.width() >= g->w) + boundsR.right -= xcon + boundsR.width() - g->w; + if (ycon + boundsR.height() >= g->h) + boundsR.bottom -= ycon + boundsR.height() - g->h; + + Common::Rect rr(r); + if (rr.right > _screen.w - 1) + rr.right = _screen.w - 1; + if (rr.bottom > _screen.h - 1) + rr.bottom = _screen.h - 1; + + g->copyRectToSurface(_console, xcon, ycon, boundsR); + g_system->copyRectToScreen(g->getBasePtr(rr.left, rr.top), g->pitch, rr.left, rr.top, rr.width(), rr.height()); +} + +void Gui::drawInput() { + if (!_screen.getPixels()) + return; + + if (_sceneIsActive) { + _sceneIsActive = false; + _bordersDirty = true; + } + + _out.pop_back(); + _lines.pop_back(); + appendText(_engine->_inputText.c_str()); + _inputTextLineNum = _out.size() - 1; + + const Graphics::Font *font = getConsoleFont(); + + if (_engine->_inputText.contains('\n')) { + _consoleDirty = true; + } else { + int x = kConWPadding + _consoleTextArea.left; + int y = _cursorY + _consoleTextArea.top; + + Common::Rect r(x, y, x + _consoleTextArea.width() - kConWPadding, y + font->getFontHeight()); + _screen.fillRect(r, kColorWhite); + + undrawCursor(); + + font->drawString(&_screen, _out[_inputTextLineNum], x, y, _screen.w, kColorBlack); + + g_system->copyRectToScreen(_screen.getBasePtr(x, y), _screen.pitch, x, y, _consoleTextArea.width(), font->getFontHeight()); + } + + _cursorX = font->getStringWidth(_out[_inputTextLineNum]) + kConHPadding; +} + +void Gui::actionCopy() { + if (_selectionStartX == -1) + return; + + int startX = _selectionStartX; + int startY = _selectionStartY; + int endX = _selectionEndX; + int endY = _selectionEndY; + + if (startY > endY) { + SWAP(startX, endX); + SWAP(endX, endY); + } + + _clipboard.clear(); + + for (int i = startY; i <= endY; i++) { + if (startY == endY) { + _clipboard = Common::String(&_lines[i].c_str()[startX], &_lines[i].c_str()[endX]); + break; + } + + if (i == startY) { + _clipboard += &_lines[i].c_str()[startX]; + _clipboard += '\n'; + } else if (i == endY) { + _clipboard += Common::String(_lines[i].c_str(), &_lines[i].c_str()[endX]); + } else { + _clipboard += _lines[i]; + _clipboard += '\n'; + } + } + + _menu->enableCommand(kMenuEdit, kMenuActionPaste, true); +} + +void Gui::actionPaste() { + _undobuffer = _engine->_inputText; + _engine->_inputText += _clipboard; + drawInput(); + _engine->_inputText = _out.back(); // Set last part of the multiline text + + _menu->enableCommand(kMenuEdit, kMenuActionUndo, true); +} + +void Gui::actionUndo() { + _engine->_inputText = _undobuffer; + drawInput(); + + _menu->enableCommand(kMenuEdit, kMenuActionUndo, false); +} + +void Gui::actionClear() { + int startPos = _selectionStartX; + int endPos = _selectionEndX; + + if (startPos > endPos) + SWAP(startPos, endPos); + + Common::String beg(_lines[_selectionStartY].c_str(), &_lines[_selectionStartY].c_str()[startPos]); + Common::String end(&_lines[_selectionStartY].c_str()[endPos]); + + _undobuffer = _engine->_inputText; + _engine->_inputText = beg + end; + drawInput(); + + _menu->enableCommand(kMenuEdit, kMenuActionUndo, true); + + _selectionStartY = -1; + _selectionEndY = -1; +} + +void Gui::actionCut() { + int startPos = _selectionStartX; + int endPos = _selectionEndX; + + if (startPos > endPos) + SWAP(startPos, endPos); + + Common::String beg(_lines[_selectionStartY].c_str(), &_lines[_selectionStartY].c_str()[startPos]); + Common::String mid(&_lines[_selectionStartY].c_str()[startPos], &_lines[_selectionStartY].c_str()[endPos]); + Common::String end(&_lines[_selectionStartY].c_str()[endPos]); + + _undobuffer = _engine->_inputText; + _engine->_inputText = beg + end; + _clipboard = mid; + drawInput(); + + _menu->enableCommand(kMenuEdit, kMenuActionUndo, true); + _menu->enableCommand(kMenuEdit, kMenuActionPaste, true); + + _selectionStartY = -1; + _selectionEndY = -1; +} + +void Gui::disableUndo() { + _menu->enableCommand(kMenuEdit, kMenuActionUndo, false); +} + +void Gui::disableAllMenus() { + _menu->disableAllMenus(); +} + +void Gui::enableNewGameMenus() { + _menu->enableCommand(kMenuFile, kMenuActionNew, true); + _menu->enableCommand(kMenuFile, kMenuActionOpen, true); + _menu->enableCommand(kMenuFile, kMenuActionQuit, true); +} + +} // End of namespace Wage diff --git a/engines/wage/gui.cpp b/engines/wage/gui.cpp new file mode 100644 index 0000000000..9dd1a24b3c --- /dev/null +++ b/engines/wage/gui.cpp @@ -0,0 +1,675 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "common/timer.h" +#include "common/unzip.h" +#include "graphics/cursorman.h" +#include "graphics/fonts/bdf.h" +#include "graphics/palette.h" + +#include "wage/wage.h" +#include "wage/design.h" +#include "wage/entities.h" +#include "wage/menu.h" +#include "wage/gui.h" +#include "wage/world.h" + +namespace Wage { + +static const byte palette[] = { + 0, 0, 0, // Black + 0x80, 0x80, 0x80, // Gray + 0xff, 0xff, 0xff, // White + 0x00, 0xff, 0x00 // Green +}; + +static byte fillPatterns[][8] = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, // kPatternSolid + { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }, // kPatternStripes + { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 }, // kPatternCheckers + { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa } // kPatternCheckers2 +}; + +static const byte macCursorArrow[] = { + 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 0, 0, 2, 3, 3, 3, 3, 3, 3, 3, + 2, 0, 0, 0, 2, 3, 3, 3, 3, 3, 3, + 2, 0, 0, 0, 0, 2, 3, 3, 3, 3, 3, + 2, 0, 0, 0, 0, 0, 2, 3, 3, 3, 3, + 2, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3, + 2, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, + 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, + 2, 0, 0, 2, 0, 0, 2, 3, 3, 3, 3, + 2, 0, 2, 3, 2, 0, 0, 2, 3, 3, 3, + 2, 2, 3, 3, 2, 0, 0, 2, 3, 3, 3, + 2, 3, 3, 3, 3, 2, 0, 0, 2, 3, 3, + 3, 3, 3, 3, 3, 2, 0, 0, 2, 3, 3, + 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3 +}; + +static const byte macCursorBeam[] = { + 0, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3, + 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3, + 0, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3, +}; + +static void cursorTimerHandler(void *refCon) { + Gui *gui = (Gui *)refCon; + + int x = gui->_cursorX; + int y = gui->_cursorY; + + if (x == 0 && y == 0) + return; + + if (!gui->_screen.getPixels()) + return; + + x += gui->_consoleTextArea.left; + y += gui->_consoleTextArea.top; + + gui->_screen.vLine(x, y, y + kCursorHeight, gui->_cursorState ? kColorBlack : kColorWhite); + + if (!gui->_cursorOff) + gui->_cursorState = !gui->_cursorState; + + gui->_cursorRect.left = x; + gui->_cursorRect.right = MIN<uint16>(x + 1, gui->_screen.w); + gui->_cursorRect.top = y; + gui->_cursorRect.bottom = MIN<uint16>(y + kCursorHeight, gui->_screen.h); + + gui->_cursorDirty = true; +} + +Gui::Gui(WageEngine *engine) { + _engine = engine; + _scene = NULL; + _sceneDirty = true; + _consoleDirty = true; + _bordersDirty = true; + _menuDirty = true; + _cursorDirty = false; + _consoleFullRedraw = true; + _screen.create(g_system->getWidth(), g_system->getHeight(), Graphics::PixelFormat::createFormatCLUT8()); + + _scrollPos = 0; + _consoleLineHeight = 8; // Dummy value which makes sense + _consoleNumLines = 24; // Dummy value + _builtInFonts = false; + _sceneIsActive = false; + + _cursorX = 0; + _cursorY = 0; + _cursorState = false; + _cursorOff = false; + + _inTextSelection = false; + _selectionStartX = _selectionStartY = -1; + _selectionEndX = _selectionEndY = -1; + + _inputTextLineNum = 0; + + g_system->getPaletteManager()->setPalette(palette, 0, 4); + + CursorMan.replaceCursorPalette(palette, 0, 4); + CursorMan.replaceCursor(macCursorArrow, 11, 16, 1, 1, 3); + _cursorIsArrow = true; + CursorMan.showMouse(true); + + for (int i = 0; i < ARRAYSIZE(fillPatterns); i++) + _patterns.push_back(fillPatterns[i]); + + loadFonts(); + + g_system->getTimerManager()->installTimerProc(&cursorTimerHandler, 200000, this, "wageCursor"); + + _menu = new Menu(this); +} + +Gui::~Gui() { + _screen.free(); + _console.free(); + g_system->getTimerManager()->removeTimerProc(&cursorTimerHandler); + delete _menu; +} + +void Gui::undrawCursor() { + _cursorOff = true; + _cursorState = false; + cursorTimerHandler(this); + _cursorOff = false; +} + +const Graphics::Font *Gui::getFont(const char *name, Graphics::FontManager::FontUsage fallback) { + const Graphics::Font *font = 0; + + if (!_builtInFonts) { + font = FontMan.getFontByName(name); + + if (!font) + warning("Cannot load font %s", name); + } + + if (_builtInFonts || !font) + font = FontMan.getFontByUsage(fallback); + + return font; +} + +const Graphics::Font *Gui::getTitleFont() { + return getFont("Chicago-12", Graphics::FontManager::kBigGUIFont); +} + +void Gui::drawDesktop() { + // Draw desktop + Common::Rect r(0, 0, _screen.w - 1, _screen.h - 1); + Design::drawFilledRoundRect(&_screen, r, kDesktopArc, kColorBlack, _patterns, kPatternCheckers); + g_system->copyRectToScreen(_screen.getPixels(), _screen.pitch, 0, 0, _screen.w, _screen.h); +} + +void Gui::draw() { + if (_engine->_isGameOver) { + if (_menuDirty) { + drawDesktop(); + _menu->render(); + } + + _menuDirty = false; + + return; + } + + if (_scene != _engine->_world->_player->_currentScene || _sceneDirty) { + _scene = _engine->_world->_player->_currentScene; + + drawDesktop(); + + _sceneDirty = true; + _consoleDirty = true; + _menuDirty = true; + _consoleFullRedraw = true; + + _scene->paint(&_screen, _scene->_designBounds->left, _scene->_designBounds->top); + + _sceneArea.left = _scene->_designBounds->left + kBorderWidth - 2; + _sceneArea.top = _scene->_designBounds->top + kBorderWidth - 2; + _sceneArea.setWidth(_scene->_designBounds->width() - 2 * kBorderWidth); + _sceneArea.setHeight(_scene->_designBounds->height() - 2 * kBorderWidth); + + _consoleTextArea.left = _scene->_textBounds->left + kBorderWidth - 2; + _consoleTextArea.top = _scene->_textBounds->top + kBorderWidth - 2; + _consoleTextArea.setWidth(_scene->_textBounds->width() - 2 * kBorderWidth); + _consoleTextArea.setHeight(_scene->_textBounds->height() - 2 * kBorderWidth); + } + + if (_scene && (_bordersDirty || _sceneDirty)) + paintBorder(&_screen, _sceneArea, kWindowScene); + + // Render console + if (_consoleDirty || _consoleFullRedraw) + renderConsole(&_screen, _consoleTextArea); + + if (_bordersDirty || _consoleDirty || _consoleFullRedraw) + paintBorder(&_screen, _consoleTextArea, kWindowConsole); + + if (_menuDirty) + _menu->render(); + + if (_cursorDirty) { + g_system->copyRectToScreen(_screen.getBasePtr(_cursorRect.left, _cursorRect.top), _screen.pitch, + _cursorRect.left, _cursorRect.top, _cursorRect.width(), _cursorRect.height()); + + _cursorDirty = false; + } + + _sceneDirty = false; + _consoleDirty = false; + _bordersDirty = false; + _menuDirty = false; + _consoleFullRedraw = false; +} + +void Gui::drawBox(Graphics::Surface *g, int x, int y, int w, int h) { + Common::Rect r(x, y, x + w + 1, y + h + 1); + + g->fillRect(r, kColorWhite); + g->frameRect(r, kColorBlack); +} + +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, color); +} + +#define ARROW_W 12 +#define ARROW_H 6 +const int arrowPixels[ARROW_H][ARROW_W] = { + {0,0,0,0,0,1,1,0,0,0,0,0}, + {0,0,0,0,1,1,1,1,0,0,0,0}, + {0,0,0,1,1,1,1,1,1,0,0,0}, + {0,0,1,1,1,1,1,1,1,1,0,0}, + {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, 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; + int width = r.width() + 2 * size; + int height = r.height() + 2 * size; + + switch (windowType) { + case kWindowScene: + active = _sceneIsActive; + scrollable = false; + closeable = _sceneIsActive; + drawTitle = true; + break; + case kWindowConsole: + active = !_sceneIsActive; + scrollable = true; + closeable = !_sceneIsActive; + drawTitle = false; + break; + } + + drawBox(g, x, y, size, size); + drawBox(g, x + width - size - 1, y, size, size); + drawBox(g, x + width - size - 1, y + height - size - 1, size, size); + drawBox(g, x, y + height - size - 1, size, size); + drawBox(g, x + size, y + 2, width - 2 * size - 1, size - 4); + drawBox(g, x + size, y + height - size + 1, width - 2 * size - 1, size - 4); + drawBox(g, x + 2, y + size, size - 4, height - 2 * size - 1); + drawBox(g, x + width - size + 1, y + size, size - 4, height - 2 * size - 1); + + if (active) { + fillRect(g, x + size, y + 5, width - 2 * size - 1, 8); + fillRect(g, x + size, y + height - 13, width - 2 * size - 1, 8); + fillRect(g, x + 5, y + size, 8, height - 2 * size - 1); + if (!scrollable) { + fillRect(g, x + width - 13, y + size, 8, height - 2 * size - 1); + } 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, color1); + } else { + g->hLine(x1 + xx, y1 + yy, x1 + xx, color2); + } + } + } + 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, color1); + } else { + g->hLine(x1 + xx, y1 + yy, x1 + xx, color2); + } + } + } + } + if (closeable) { + if (highlightedPart == kBorderCloseButton) { + fillRect(g, x + 6, y + 6, 6, 6); + } else { + drawBox(g, x + 5, y + 5, 7, 7); + } + } + } + + if (drawTitle) { + const Graphics::Font *font = getTitleFont(); + int yOff = _builtInFonts ? 3 : 1; + + int w = font->getStringWidth(_scene->_name) + 10; + int maxWidth = width - size * 2 - 7; + if (w > maxWidth) + w = maxWidth; + drawBox(g, x + (width - w) / 2, y, w, size); + font->drawString(g, _scene->_name, x + (width - w) / 2 + 5, y + yOff, w, kColorBlack); + } + + if (x < 0) { + width += x; + x = 0; + } + if (y < 0) { + height += y; + y = 0; + } + if (x + width > _screen.w) + width = _screen.w - x; + if (y + height > _screen.h) + height = _screen.h - y; + + g_system->copyRectToScreen(g->getBasePtr(x, y), g->pitch, x, y, width, height); +} + +void Gui::loadFonts() { + Common::Archive *dat; + + dat = Common::makeZipArchive("wage.dat"); + + if (!dat) { + warning("Could not find wage.dat. Falling back to built-in fonts"); + _builtInFonts = true; + + return; + } + + Common::ArchiveMemberList list; + dat->listMembers(list); + + for (Common::ArchiveMemberList::iterator it = list.begin(); it != list.end(); ++it) { + Common::SeekableReadStream *stream = dat->createReadStreamForMember((*it)->getName()); + + Graphics::BdfFont *font = Graphics::BdfFont::loadFont(*stream); + + delete stream; + + Common::String fontName = (*it)->getName(); + + // Trim the .bdf extension + for (int i = fontName.size() - 1; i >= 0; --i) { + if (fontName[i] == '.') { + while ((uint)i < fontName.size()) { + fontName.deleteLastChar(); + } + break; + } + } + + FontMan.assignFontToName(fontName, font); + + debug(2, " %s", fontName.c_str()); + } + + _builtInFonts = false; + + delete dat; +} + +void Gui::regenCommandsMenu() { + _menu->regenCommandsMenu(); +} + +void Gui::regenWeaponsMenu() { + _menu->regenWeaponsMenu(); +} + +void Gui::processMenuShortCut(byte flags, uint16 ascii) { + _menu->processMenuShortCut(flags, ascii); +} + +void Gui::mouseMove(int x, int y) { + if (_menu->_menuActivated) { + if (_menu->mouseMove(x, y)) + _menuDirty = true; + + return; + } + + if (_inTextSelection) { + updateTextSelection(x, y); + return; + } + + if (_consoleTextArea.contains(x, y)) { + if (_cursorIsArrow) { + CursorMan.replaceCursor(macCursorBeam, 11, 16, 3, 8, 3); + _cursorIsArrow = false; + } + } else if (_cursorIsArrow == false) { + CursorMan.replaceCursor(macCursorArrow, 11, 16, 1, 1, 3); + _cursorIsArrow = true; + } +} + +void Gui::pushArrowCursor() { + CursorMan.pushCursor(macCursorArrow, 11, 16, 1, 1, 3); +} + +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)) { + _sceneDirty = true; + _consoleDirty = true; + _bordersDirty = true; + _menuDirty = true; + } + + return NULL; + } + + if (_inTextSelection) { + _inTextSelection = false; + + if (_selectionEndY == -1 || + (_selectionEndX == _selectionStartX && _selectionEndY == _selectionStartY)) { + _selectionStartY = _selectionEndY = -1; + _consoleFullRedraw = true; + _menu->enableCommand(kMenuEdit, kMenuActionCopy, false); + } else { + _menu->enableCommand(kMenuEdit, kMenuActionCopy, true); + + bool cutAllowed = false; + + if (_selectionStartY == _selectionEndY && _selectionStartY == (int)_lines.size() - 1) + cutAllowed = true; + + _menu->enableCommand(kMenuEdit, kMenuActionCut, cutAllowed); + _menu->enableCommand(kMenuEdit, kMenuActionClear, cutAllowed); + } + } + + int borderClick; + + if (_sceneArea.contains(x, y)) { + if (!_sceneIsActive) { + _sceneIsActive = true; + _bordersDirty = true; + } + + for (ObjList::const_iterator it = _scene->_objs.begin(); it != _scene->_objs.end(); ++it) { + if ((*it)->_design->isPointOpaque(x - _sceneArea.left + kBorderWidth, y - _sceneArea.top + kBorderWidth)) + return *it; + } + + for (ChrList::const_iterator it = _scene->_chrs.begin(); it != _scene->_chrs.end(); ++it) { + if ((*it)->_design->isPointOpaque(x - _sceneArea.left + kBorderWidth, y - _sceneArea.top + kBorderWidth)) + return *it; + } + } else if (_consoleTextArea.contains(x, y)) { + if (_sceneIsActive) { + _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); + } +} + +int Gui::calcTextX(int x, int textLine) { + const Graphics::Font *font = getConsoleFont(); + + if ((uint)textLine >= _lines.size()) + return 0; + + Common::String str = _lines[textLine]; + + x -= _consoleTextArea.left; + + for (int i = str.size(); i >= 0; i--) { + if (font->getStringWidth(str) < x) { + return i; + } + + str.deleteLastChar(); + } + + return 0; +} + +int Gui::calcTextY(int y) { + y -= _consoleTextArea.top; + + if (y < 0) + y = 0; + + const int firstLine = _scrollPos / _consoleLineHeight; + int textLine = (y - _scrollPos % _consoleLineHeight) / _consoleLineHeight + firstLine; + + return textLine; +} + +void Gui::startMarking(int x, int y) { + _selectionStartY = calcTextY(y); + _selectionStartX = calcTextX(x, _selectionStartY); + + _selectionEndY = -1; + + _inTextSelection = true; +} + +void Gui::updateTextSelection(int x, int y) { + _selectionEndY = calcTextY(y); + _selectionEndX = calcTextX(x, _selectionEndY); + + _consoleFullRedraw = true; +} + +} // End of namespace Wage diff --git a/engines/wage/gui.h b/engines/wage/gui.h new file mode 100644 index 0000000000..73814d39b4 --- /dev/null +++ b/engines/wage/gui.h @@ -0,0 +1,189 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef WAGE_GUI_H +#define WAGE_GUI_H + +#include "common/str-array.h" +#include "graphics/font.h" +#include "graphics/fontman.h" +#include "graphics/surface.h" +#include "common/rect.h" + +namespace Wage { + +class Menu; + +enum WindowType { + kWindowScene, + kWindowConsole +}; + +enum { + kMenuHeight = 20, + kMenuLeftMargin = 7, + kMenuSpacing = 13, + kMenuPadding = 16, + kMenuDropdownPadding = 14, + kMenuDropdownItemHeight = 16, + kMenuItemHeight = 20, + kBorderWidth = 17, + kDesktopArc = 7, + kComponentsPadding = 10, + kCursorHeight = 12 +}; + +enum { + kPatternSolid = 1, + kPatternStripes = 2, + kPatternCheckers = 3, + kPatternCheckers2 = 4 +}; + +enum { + kBorderNone = 0, + kBorderScrollUp, + kBorderScrollDown, + kBorderCloseButton +}; + +class Gui { +public: + Gui(WageEngine *engine); + ~Gui(); + + void draw(); + void appendText(const char *str); + void clearOutput(); + void mouseMove(int x, int y); + void mouseDown(int x, int y); + Designed *mouseUp(int x, int y); + void drawInput(); + void setSceneDirty() { _sceneDirty = true; } + const Graphics::Font *getFont(const char *name, Graphics::FontManager::FontUsage fallback); + void regenCommandsMenu(); + void regenWeaponsMenu(); + void processMenuShortCut(byte flags, uint16 ascii); + void pushArrowCursor(); + void popCursor(); + + void actionCopy(); + void actionPaste(); + void actionUndo(); + void actionClear(); + void actionCut(); + void disableUndo(); + void disableAllMenus(); + void enableNewGameMenus(); + +private: + void undrawCursor(); + void drawDesktop(); + 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, int color = kColorBlack); + void loadFonts(); + void flowText(Common::String &str); + const Graphics::Font *getConsoleFont(); + const Graphics::Font *getTitleFont(); + void startMarking(int x, int y); + int calcTextX(int x, int textLine); + int calcTextY(int y); + void updateTextSelection(int x, int y); + +public: + Graphics::Surface _screen; + int _cursorX, _cursorY; + bool _cursorState; + Common::Rect _consoleTextArea; + + bool _builtInFonts; + WageEngine *_engine; + + Patterns _patterns; + + bool _cursorDirty; + Common::Rect _cursorRect; + bool _cursorOff; + + bool _menuDirty; + +private: + Graphics::Surface _console; + Menu *_menu; + Scene *_scene; + bool _sceneDirty; + bool _consoleDirty; + bool _bordersDirty; + + Common::StringArray _out; + Common::StringArray _lines; + uint _scrollPos; + int _consoleLineHeight; + uint _consoleNumLines; + bool _consoleFullRedraw; + + Common::Rect _sceneArea; + bool _sceneIsActive; + bool _cursorIsArrow; + + bool _inTextSelection; + int _selectionStartX; + int _selectionStartY; + int _selectionEndX; + int _selectionEndY; + + Common::String _clipboard; + Common::String _undobuffer; + + int _inputTextLineNum; +}; + +} // End of namespace Wage + +#endif diff --git a/engines/wage/menu.cpp b/engines/wage/menu.cpp new file mode 100644 index 0000000000..12ef8c2219 --- /dev/null +++ b/engines/wage/menu.cpp @@ -0,0 +1,571 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "common/system.h" +#include "common/keyboard.h" + +#include "wage/wage.h" +#include "wage/entities.h" +#include "wage/design.h" +#include "wage/gui.h" +#include "wage/menu.h" +#include "wage/world.h" + +namespace Wage { + +struct MenuSubItem { + Common::String text; + int action; + int style; + char shortcut; + bool enabled; + Common::Rect bbox; + + MenuSubItem(const char *t, int a, int s = 0, char sh = 0, bool e = true) : text(t), action(a), style(s), shortcut(sh), enabled(e) {} +}; + +typedef Common::Array<MenuSubItem *> SubItemArray; + +struct MenuItem { + Common::String name; + SubItemArray subitems; + Common::Rect bbox; + Common::Rect subbbox; + + MenuItem(const char *n) : name(n) {} +}; + +struct MenuData { + int menunum; + const char *title; + int action; + byte shortcut; + bool enabled; +} static const menuSubItems[] = { + { kMenuFile, "New", kMenuActionNew, 0, false }, + { kMenuFile, "Open...", kMenuActionOpen, 0, false }, + { kMenuFile, "Close", kMenuActionClose, 0, true }, + { kMenuFile, "Save", kMenuActionSave, 0, false }, + { kMenuFile, "Save as...", kMenuActionSaveAs, 0, true }, + { kMenuFile, "Revert", kMenuActionRevert, 0, false }, + { kMenuFile, "Quit", kMenuActionQuit, 0, true }, + + { kMenuEdit, "Undo", kMenuActionUndo, 'Z', false }, + { kMenuEdit, NULL, 0, 0, false }, + { kMenuEdit, "Cut", kMenuActionCut, 'K', false }, + { kMenuEdit, "Copy", kMenuActionCopy, 'C', false }, + { kMenuEdit, "Paste", kMenuActionPaste, 'V', false }, + { kMenuEdit, "Clear", kMenuActionClear, 'B', false }, + + { 0, NULL, 0, 0, false } +}; + +Menu::Menu(Gui *gui) : _gui(gui) { + assert(_gui->_engine); + assert(_gui->_engine->_world); + + _font = getMenuFont(); + + MenuItem *about = new MenuItem(_gui->_builtInFonts ? "\xa9" : "\xf0"); // (c) Symbol as the most resembling apple + _items.push_back(about); + _items[0]->subitems.push_back(new MenuSubItem(_gui->_engine->_world->getAboutMenuItemName(), kMenuActionAbout)); + + MenuItem *file = new MenuItem("File"); + _items.push_back(file); + + MenuItem *edit = new MenuItem("Edit"); + _items.push_back(edit); + + for (int i = 0; menuSubItems[i].menunum; i++) { + const MenuData *m = &menuSubItems[i]; + + _items[m->menunum]->subitems.push_back(new MenuSubItem(m->title, m->action, 0, m->shortcut, m->enabled)); + } + + _commands = new MenuItem(_gui->_engine->_world->_commandsMenuName.c_str()); + _items.push_back(_commands); + regenCommandsMenu(); + + _weapons = NULL; + + if (!_gui->_engine->_world->_weaponMenuDisabled) { + _weapons = new MenuItem(_gui->_engine->_world->_weaponsMenuName.c_str()); + _items.push_back(_weapons); + + regenWeaponsMenu(); + } + + // Calculate menu dimensions + int y = 1; + int x = 18; + + for (uint i = 0; i < _items.size(); i++) { + int w = _font->getStringWidth(_items[i]->name); + + if (_items[i]->bbox.bottom == 0) { + _items[i]->bbox.left = x - kMenuLeftMargin; + _items[i]->bbox.top = y; + _items[i]->bbox.right = x + w + kMenuSpacing - kMenuLeftMargin; + _items[i]->bbox.bottom = y + _font->getFontHeight() + (_gui->_builtInFonts ? 3 : 2); + } + + calcMenuBounds(_items[i]); + + x += w + kMenuSpacing; + } + + _bbox.left = 0; + _bbox.top = 0; + _bbox.right = _gui->_screen.w - 1; + _bbox.bottom = kMenuHeight - 1; + + _menuActivated = false; + _activeItem = -1; + _activeSubItem = -1; + + _screenCopy.create(_gui->_screen.w, _gui->_screen.h, Graphics::PixelFormat::createFormatCLUT8()); + _tempSurface.create(_gui->_screen.w, _font->getFontHeight(), Graphics::PixelFormat::createFormatCLUT8()); +} + +Menu::~Menu() { + for (uint i = 0; i < _items.size(); i++) { + for (uint j = 0; j < _items[i]->subitems.size(); j++) + delete _items[i]->subitems[j]; + delete _items[i]; + } +} + +void Menu::regenCommandsMenu() { + for (uint j = 0; j < _commands->subitems.size(); j++) + delete _commands->subitems[j]; + + _commands->subitems.clear(); + + createCommandsMenu(_commands); + calcMenuBounds(_commands); +} + +void Menu::createCommandsMenu(MenuItem *menu) { + Common::String string(_gui->_engine->_world->_commandsMenu); + + Common::String item; + + for (uint i = 0; i < string.size(); i++) { + while(i < string.size() && string[i] != ';') // Read token + item += string[i++]; + + if (item == "(-") { + menu->subitems.push_back(new MenuSubItem(NULL, 0)); + } else { + bool enabled = true; + int style = 0; + char shortcut = 0; + const char *shortPtr = strrchr(item.c_str(), '/'); + if (shortPtr != NULL) { + if (strlen(shortPtr) >= 2) { + shortcut = shortPtr[1]; + 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()); + } + } + + while (item.size() >= 2 && item[item.size() - 2] == '<') { + char c = item.lastChar(); + if (c == 'B') { + style |= kFontStyleBold; + } else if (c == 'I') { + style |= kFontStyleItalic; + } else if (c == 'U') { + style |= kFontStyleUnderline; + } else if (c == 'O') { + style |= kFontStyleOutline; + } else if (c == 'S') { + style |= kFontStyleShadow; + } else if (c == 'C') { + style |= kFontStyleCondensed; + } else if (c == 'E') { + style |= kFontStyleExtended; + } + item.deleteLastChar(); + item.deleteLastChar(); + } + + Common::String tmpitem(item); + tmpitem.trim(); + if (tmpitem[0] == '(') { + enabled = false; + + for (uint j = 0; j < item.size(); j++) + if (item[j] == '(') { + item.deleteChar(j); + break; + } + } + + menu->subitems.push_back(new MenuSubItem(item.c_str(), kMenuActionCommand, style, shortcut, enabled)); + } + + item.clear(); + } +} + +void Menu::regenWeaponsMenu() { + if (_gui->_engine->_world->_weaponMenuDisabled) + return; + + for (uint j = 0; j < _weapons->subitems.size(); j++) + delete _weapons->subitems[j]; + + _weapons->subitems.clear(); + + createWeaponsMenu(_weapons); + calcMenuBounds(_weapons); +} + +void Menu::createWeaponsMenu(MenuItem *menu) { + Chr *player = _gui->_engine->_world->_player; + ObjArray *weapons = player->getWeapons(true); + + for (uint i = 0; i < weapons->size(); i++) { + Obj *obj = (*weapons)[i]; + if (obj->_type == Obj::REGULAR_WEAPON || + obj->_type == Obj::THROW_WEAPON || + obj->_type == Obj::MAGICAL_OBJECT) { + Common::String command(obj->_operativeVerb); + command += " "; + command += obj->_name; + + menu->subitems.push_back(new MenuSubItem(command.c_str(), kMenuActionCommand, 0, 0, true)); + } + } + delete weapons; + + if (menu->subitems.empty()) + menu->subitems.push_back(new MenuSubItem("You have no weapons", 0, 0, 0, false)); +} + +const Graphics::Font *Menu::getMenuFont() { + return _gui->getFont("Chicago-12", Graphics::FontManager::kBigGUIFont); +} + +const char *Menu::getAcceleratorString(MenuSubItem *item, const char *prefix) { + static char res[20]; + *res = 0; + + if (item->shortcut != 0) + sprintf(res, "%s%c%c", prefix, (_gui->_builtInFonts ? '^' : '\x11'), item->shortcut); + + return res; +} + +int Menu::calculateMenuWidth(MenuItem *menu) { + int maxWidth = 0; + for (uint i = 0; i < menu->subitems.size(); i++) { + MenuSubItem *item = menu->subitems[i]; + if (!item->text.empty()) { + Common::String text(item->text); + Common::String acceleratorText(getAcceleratorString(item, " ")); + if (!acceleratorText.empty()) { + text += acceleratorText; + } + + int width = _font->getStringWidth(text); + if (width > maxWidth) { + maxWidth = width; + } + } + } + return maxWidth; +} + +void Menu::calcMenuBounds(MenuItem *menu) { + // TODO: cache maxWidth + int maxWidth = calculateMenuWidth(menu); + int x1 = menu->bbox.left - 1; + int y1 = menu->bbox.bottom + 1; + int x2 = x1 + maxWidth + kMenuDropdownPadding * 2 - 4; + int y2 = y1 + menu->subitems.size() * kMenuDropdownItemHeight + 2; + + menu->subbbox.left = x1; + menu->subbbox.top = y1; + menu->subbbox.right = x2; + menu->subbbox.bottom = y2; +} + +void Menu::render() { + Common::Rect r(_bbox); + + Design::drawFilledRoundRect(&_gui->_screen, r, kDesktopArc, kColorWhite, _gui->_patterns, kPatternSolid); + r.top = 7; + Design::drawFilledRect(&_gui->_screen, r, kColorWhite, _gui->_patterns, kPatternSolid); + r.top = kMenuHeight - 1; + Design::drawFilledRect(&_gui->_screen, r, kColorBlack, _gui->_patterns, kPatternSolid); + + for (uint i = 0; i < _items.size(); i++) { + int color = kColorBlack; + MenuItem *it = _items[i]; + + if ((uint)_activeItem == i) { + Common::Rect hbox = it->bbox; + + hbox.left -= 1; + hbox.right += 2; + + Design::drawFilledRect(&_gui->_screen, hbox, kColorBlack, _gui->_patterns, kPatternSolid); + color = kColorWhite; + + if (!it->subitems.empty()) + renderSubmenu(it); + } + + _font->drawString(&_gui->_screen, it->name, it->bbox.left + kMenuLeftMargin, it->bbox.top + (_gui->_builtInFonts ? 2 : 1), it->bbox.width(), color); + } + + g_system->copyRectToScreen(_gui->_screen.getPixels(), _gui->_screen.pitch, 0, 0, _gui->_screen.w, kMenuHeight); +} + +void Menu::renderSubmenu(MenuItem *menu) { + Common::Rect *r = &menu->subbbox; + + if (r->width() == 0 || r->height() == 0) + return; + + Design::drawFilledRect(&_gui->_screen, *r, kColorWhite, _gui->_patterns, kPatternSolid); + Design::drawRect(&_gui->_screen, *r, 1, kColorBlack, _gui->_patterns, kPatternSolid); + Design::drawVLine(&_gui->_screen, r->right + 1, r->top + 3, r->bottom + 1, 1, kColorBlack, _gui->_patterns, kPatternSolid); + Design::drawHLine(&_gui->_screen, r->left + 3, r->right + 1, r->bottom + 1, 1, kColorBlack, _gui->_patterns, kPatternSolid); + + int x = r->left + kMenuDropdownPadding; + int y = r->top + 1; + for (uint i = 0; i < menu->subitems.size(); i++) { + Common::String text(menu->subitems[i]->text); + Common::String acceleratorText(getAcceleratorString(menu->subitems[i], "")); + int accelX = r->right - 25; + + int color = kColorBlack; + if (i == (uint)_activeSubItem && !text.empty() && menu->subitems[i]->enabled) { + color = kColorWhite; + Common::Rect trect(r->left, y - (_gui->_builtInFonts ? 1 : 0), r->right, y + _font->getFontHeight()); + + Design::drawFilledRect(&_gui->_screen, trect, kColorBlack, _gui->_patterns, kPatternSolid); + } + + if (!text.empty()) { + Graphics::Surface *s = &_gui->_screen; + int tx = x, ty = y; + + if (!menu->subitems[i]->enabled) { + s = &_tempSurface; + tx = 0; + ty = 0; + accelX -= x; + + _tempSurface.fillRect(Common::Rect(0, 0, _tempSurface.w, _tempSurface.h), kColorGreen); + } + + _font->drawString(s, text, tx, ty, r->width(), color); + + if (!acceleratorText.empty()) + _font->drawString(s, acceleratorText, accelX, ty, r->width(), color); + + if (!menu->subitems[i]->enabled) { + // I am lazy to extend drawString() with plotProc as a parameter, so + // fake it here + for (int ii = 0; ii < _tempSurface.h; ii++) { + const byte *src = (const byte *)_tempSurface.getBasePtr(0, ii); + byte *dst = (byte *)_gui->_screen.getBasePtr(x, y+ii); + byte pat = _gui->_patterns[kPatternCheckers2 - 1][ii % 8]; + for (int j = 0; j < r->width(); j++) { + if (*src != kColorGreen && (pat & (1 << (7 - (x + j) % 8)))) + *dst = *src; + src++; + dst++; + } + } + } + } else { // Delimiter + Design::drawHLine(&_gui->_screen, r->left + 1, r->right - 1, y + kMenuDropdownItemHeight / 2, 1, kColorBlack, _gui->_patterns, kPatternStripes); + } + + y += kMenuDropdownItemHeight; + } + + g_system->copyRectToScreen(_gui->_screen.getBasePtr(r->left, r->top), _gui->_screen.pitch, r->left, r->top, r->width() + 3, r->height() + 3); +} + +bool Menu::mouseClick(int x, int y) { + if (_bbox.contains(x, y)) { + if (!_menuActivated) + _screenCopy.copyFrom(_gui->_screen); + + for (uint i = 0; i < _items.size(); i++) + if (_items[i]->bbox.contains(x, y)) { + if ((uint)_activeItem == i) + return false; + + if (_activeItem != -1) { // Restore background + Common::Rect r(_items[_activeItem]->subbbox); + r.right += 3; + r.bottom += 3; + + _gui->_screen.copyRectToSurface(_screenCopy, r.left, r.top, r); + g_system->copyRectToScreen(_gui->_screen.getBasePtr(r.left, r.top), _gui->_screen.pitch, r.left, r.top, r.width() + 1, r.height() + 1); + } + + _activeItem = i; + _activeSubItem = -1; + _menuActivated = true; + + return true; + } + } else if (_menuActivated && _items[_activeItem]->subbbox.contains(x, y)) { + MenuItem *it = _items[_activeItem]; + int numSubItem = (y - it->subbbox.top) / kMenuDropdownItemHeight; + + if (numSubItem != _activeSubItem) { + _activeSubItem = numSubItem; + + renderSubmenu(_items[_activeItem]); + } + } else if (_menuActivated && _activeItem != -1) { + _activeSubItem = -1; + + renderSubmenu(_items[_activeItem]); + } + + return false; +} + +bool Menu::mouseMove(int x, int y) { + if (_menuActivated) + if (mouseClick(x, y)) + return true; + + return false; +} + +bool Menu::mouseRelease(int x, int y) { + if (_menuActivated) { + _menuActivated = false; + + if (_activeItem != -1 && _activeSubItem != -1 && _items[_activeItem]->subitems[_activeSubItem]->enabled) + executeCommand(_items[_activeItem]->subitems[_activeSubItem]); + + _activeItem = -1; + _activeSubItem = -1; + + return true; + } + + return false; +} + +void Menu::executeCommand(MenuSubItem *subitem) { + switch(subitem->action) { + case kMenuActionAbout: + case kMenuActionNew: + case kMenuActionOpen: + case kMenuActionClose: + case kMenuActionSave: + case kMenuActionSaveAs: + case kMenuActionRevert: + case kMenuActionQuit: + + case kMenuActionUndo: + _gui->actionUndo(); + break; + case kMenuActionCut: + _gui->actionCut(); + break; + case kMenuActionCopy: + _gui->actionCopy(); + break; + case kMenuActionPaste: + _gui->actionPaste(); + break; + case kMenuActionClear: + _gui->actionClear(); + break; + + case kMenuActionCommand: + _gui->_engine->processTurn(&subitem->text, NULL); + break; + + default: + warning("Unknown action: %d", subitem->action); + + } +} + +void Menu::processMenuShortCut(byte flags, uint16 ascii) { + ascii = tolower(ascii); + + if (flags & (Common::KBD_CTRL | Common::KBD_META)) { + for (uint i = 0; i < _items.size(); i++) + for (uint j = 0; j < _items[i]->subitems.size(); j++) + if (_items[i]->subitems[j]->enabled && tolower(_items[i]->subitems[j]->shortcut) == ascii) { + executeCommand(_items[i]->subitems[j]); + break; + } + } +} + +void Menu::enableCommand(int menunum, int action, bool state) { + for (uint i = 0; i < _items[menunum]->subitems.size(); i++) + if (_items[menunum]->subitems[i]->action == action) + _items[menunum]->subitems[i]->enabled = state; +} + +void Menu::disableAllMenus() { + for (uint i = 1; i < _items.size(); i++) // Leave About menu on + for (uint j = 0; j < _items[i]->subitems.size(); j++) + _items[i]->subitems[j]->enabled = false; +} + +} // End of namespace Wage diff --git a/engines/wage/menu.h b/engines/wage/menu.h new file mode 100644 index 0000000000..3550356bc6 --- /dev/null +++ b/engines/wage/menu.h @@ -0,0 +1,139 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef WAGE_MENU_H +#define WAGE_MENU_H + +namespace Wage { + +struct MenuItem; +struct MenuSubItem; + +enum { + kFontStyleBold = 1, + kFontStyleItalic = 2, + kFontStyleUnderline = 4, + kFontStyleOutline = 8, + kFontStyleShadow = 16, + kFontStyleCondensed = 32, + kFontStyleExtended = 64 +}; + +enum { + kMenuAbout = 0, + kMenuFile = 1, + kMenuEdit = 2, + kMenuCommands = 3, + kMenuWeapons = 4 +}; + +enum { + kMenuActionAbout, + kMenuActionNew, + kMenuActionOpen, + kMenuActionClose, + kMenuActionSave, + kMenuActionSaveAs, + kMenuActionRevert, + kMenuActionQuit, + + kMenuActionUndo, + kMenuActionCut, + kMenuActionCopy, + kMenuActionPaste, + kMenuActionClear, + + kMenuActionCommand +}; + +class Menu { +public: + Menu(Gui *gui); + ~Menu(); + + void render(); + bool mouseClick(int x, int y); + bool mouseRelease(int x, int y); + bool mouseMove(int x, int y); + + void regenCommandsMenu(); + void regenWeaponsMenu(); + void processMenuShortCut(byte flags, uint16 ascii); + void enableCommand(int menunum, int action, bool state); + void disableAllMenus(); + + bool _menuActivated; + Common::Rect _bbox; + +private: + Gui *_gui; + Graphics::Surface _screenCopy; + Graphics::Surface _tempSurface; + +private: + const Graphics::Font *getMenuFont(); + const char *getAcceleratorString(MenuSubItem *item, const char *prefix); + int calculateMenuWidth(MenuItem *menu); + void calcMenuBounds(MenuItem *menu); + void renderSubmenu(MenuItem *menu); + void createCommandsMenu(MenuItem *menu); + void createWeaponsMenu(MenuItem *menu); + void executeCommand(MenuSubItem *subitem); + + Common::Array<MenuItem *> _items; + MenuItem *_weapons; + MenuItem *_commands; + + const Graphics::Font *_font; + + int _activeItem; + int _activeSubItem; +}; + +} // End of namespace Wage + +#endif diff --git a/engines/wage/module.mk b/engines/wage/module.mk new file mode 100644 index 0000000000..21316bbf83 --- /dev/null +++ b/engines/wage/module.mk @@ -0,0 +1,29 @@ +MODULE := engines/wage + +MODULE_OBJS := \ + combat.o \ + debugger.o \ + design.o \ + detection.o \ + dialog.o \ + entities.o \ + gui.o \ + gui-console.o \ + menu.o \ + randomhat.o \ + script.o \ + sound.o \ + util.o \ + wage.o \ + world.o + +MODULE_DIRS += \ + engines/wage + +# This module can be built as a plugin +ifeq ($(ENABLE_WAGE), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/wage/randomhat.cpp b/engines/wage/randomhat.cpp new file mode 100644 index 0000000000..9371140398 --- /dev/null +++ b/engines/wage/randomhat.cpp @@ -0,0 +1,83 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "common/random.h" + +#include "common/hashmap.h" +#include "wage/randomhat.h" + +namespace Wage { + +void RandomHat::addTokens(int type, int count) { + _tokens.setVal(type, _tokens.getVal(type, 0) + count); +} + +int RandomHat::countTokens() { + int count = 0; + for (Common::HashMap<int, int>::const_iterator it = _tokens.begin(); it != _tokens.end(); ++it) + count += it->_value; + + return count; +} + +int RandomHat::drawToken() { + int total = countTokens(); + if (total > 0) { + int random = _rnd->getRandomNumber(total - 1); + int count = 0; + for (Common::HashMap<int, int>::iterator it = _tokens.begin(); it != _tokens.end(); ++it) { + if (random >= count && random < count + it->_value) { + it->_value--; + return it->_key; + } + count += it->_value; + } + } + return kTokNone; +} + +} // End of namespace Wage diff --git a/engines/wage/randomhat.h b/engines/wage/randomhat.h new file mode 100644 index 0000000000..254cd2ae8d --- /dev/null +++ b/engines/wage/randomhat.h @@ -0,0 +1,77 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef WAGE_RANDOMHAT_H +#define WAGE_RANDOMHAT_H + +namespace Wage { + +enum { + kTokWeapons = -400, + kTokMagic = -300, + kTokRun = -200, + kTokOffer = -100, + kTokNone = -100000 +}; + +class RandomHat { +public: + RandomHat(Common::RandomSource *rnd) : _rnd(rnd) {} + + void addTokens(int type, int count); + int drawToken(); + +private: + Common::RandomSource *_rnd; + Common::HashMap<int, int> _tokens; + + int countTokens(); +}; + +} // End of namespace Wage + +#endif diff --git a/engines/wage/script.cpp b/engines/wage/script.cpp new file mode 100644 index 0000000000..294c08ed82 --- /dev/null +++ b/engines/wage/script.cpp @@ -0,0 +1,1175 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "wage/wage.h" +#include "wage/entities.h" +#include "wage/script.h" +#include "wage/world.h" + +#include "common/stream.h" + +namespace Wage { + +Common::String Script::Operand::toString() { + switch(_type) { + case NUMBER: + return Common::String::format("%d", _value.number); + case STRING: + case TEXT_INPUT: + return *_value.string; + case OBJ: + return _value.obj->toString(); + case CHR: + return _value.chr->toString(); + case SCENE: + return _value.scene->toString(); + case CLICK_INPUT: + return _value.inputClick->toString(); + default: + error("Unhandled operand type: _type"); + } +} + +Script::Script(Common::SeekableReadStream *data) : _data(data) { + _engine = NULL; + _world = NULL; + + _loopCount = 0; + _inputText = NULL; + _inputClick = NULL; + + _handled = false; + + convertToText(); +} + +Script::~Script() { + for (uint i = 0; i < _scriptText.size(); i++) { + delete _scriptText[i]; + } + + delete _data; +} + +void Script::print() { + for (uint i = 0; i < _scriptText.size(); i++) { + debug(4, "%d [%04x]: %s", i, _scriptText[i]->offset, _scriptText[i]->line.c_str()); + } +} + +void Script::printLine(int offset) { + for (uint i = 0; i < _scriptText.size(); i++) + if (_scriptText[i]->offset >= offset) { + debug(4, "%d [%04x]: %s", i, _scriptText[i]->offset, _scriptText[i]->line.c_str()); + break; + } +} + +bool Script::execute(World *world, int loopCount, Common::String *inputText, Designed *inputClick, WageEngine *engine) { + _world = world; + _loopCount = loopCount; + _inputText = inputText; + _inputClick = inputClick; + _engine = engine; + _handled = false; + Common::String input; + + if (inputText) + input = *inputText; + + _data->seek(12); + while (_data->pos() < _data->size()) { + printLine(_data->pos()); + + byte command = _data->readByte(); + + switch(command) { + case 0x80: // IF + processIf(); + break; + case 0x87: // EXIT + debug(6, "exit at offset %d", _data->pos() - 1); + + return true; + case 0x89: // MOVE + { + Scene *currentScene = _world->_player->_currentScene; + processMove(); + if (_world->_player->_currentScene != currentScene) + return true; + break; + } + case 0x8B: // PRINT + { + Operand *op = readOperand(); + // TODO check op type is string or number, or something good... + _handled = true; + _engine->appendText(op->toString().c_str()); + delete op; + byte d = _data->readByte(); + if (d != 0xFD) + warning("Operand 0x8B (PRINT) End Byte != 0xFD"); + break; + } + case 0x8C: // SOUND + { + Operand *op = readOperand(); + // TODO check op type is string. + _handled = true; + _engine->playSound(op->toString()); + delete op; + byte d = _data->readByte(); + if (d != 0xFD) + warning("Operand 0x8B (PRINT) End Byte != 0xFD"); + break; + } + case 0x8E: // LET + processLet(); + break; + case 0x95: // MENU + { + Operand *op = readStringOperand(); // allows empty menu + // TODO check op type is string. + _engine->setMenu(op->toString()); + delete op; + byte d = _data->readByte(); + if (d != 0xFD) + warning("Operand 0x8B (PRINT) End Byte != 0xFD"); + } + case 0x88: // END + break; + default: + debug(0, "Unknown opcode: %d", _data->pos()); + } + } + + if (_world->_globalScript != this) { + debug(1, "Executing global script..."); + bool globalHandled = _world->_globalScript->execute(_world, _loopCount, &input, _inputClick, _engine); + if (globalHandled) + _handled = true; + } else if (!input.empty()) { + if (input.contains("north")) { + _handled = _engine->handleMoveCommand(NORTH, "north"); + } else if (input.contains("east")) { + _handled = _engine->handleMoveCommand(EAST, "east"); + } else if (input.contains("south")) { + _handled = _engine->handleMoveCommand(SOUTH, "south"); + } else if (input.contains("west")) { + _handled = _engine->handleMoveCommand(WEST, "west"); + } else if (input.hasPrefix("take ")) { + _handled = _engine->handleTakeCommand(&input.c_str()[5]); + } else if (input.hasPrefix("get ")) { + _handled = _engine->handleTakeCommand(&input.c_str()[4]); + } else if (input.hasPrefix("pick up ")) { + _handled = _engine->handleTakeCommand(&input.c_str()[8]); + } else if (input.hasPrefix("drop ")) { + _handled = _engine->handleDropCommand(&input.c_str()[5]); + } else if (input.hasPrefix("aim ")) { + _handled = _engine->handleAimCommand(&input.c_str()[4]); + } else if (input.hasPrefix("wear ")) { + _handled = _engine->handleWearCommand(&input.c_str()[5]); + } else if (input.hasPrefix("put on ")) { + _handled = _engine->handleWearCommand(&input.c_str()[7]); + } else if (input.hasPrefix("offer ")) { + _handled = _engine->handleOfferCommand(&input.c_str()[6]); + } else if (input.contains("look")) { + _handled = _engine->handleLookCommand(); + } else if (input.contains("inventory")) { + _handled = _engine->handleInventoryCommand(); + } else if (input.contains("status")) { + _handled = _engine->handleStatusCommand(); + } else if (input.contains("rest") || input.equals("wait")) { + _handled = _engine->handleRestCommand(); + } else if (_engine->getOffer() != NULL && input.contains("accept")) { + _handled = _engine->handleAcceptCommand(); + } else { + Chr *player = _world->_player; + ObjArray *weapons = player->getWeapons(true); + for (ObjArray::const_iterator weapon = weapons->begin(); weapon != weapons->end(); ++weapon) { + if (_engine->tryAttack(*weapon, input)) { + _handled = _engine->handleAttack(*weapon); + break; + } + } + + delete weapons; + } + // TODO: weapons, offer, etc... + } else if (_inputClick->_classType == OBJ) { + Obj *obj = (Obj *)_inputClick; + if (obj->_type != Obj::IMMOBILE_OBJECT) { + _engine->takeObj(obj); + } else { + _engine->appendText(obj->_clickMessage.c_str()); + } + + _handled = true; + } + + return _handled; +} + +Script::Operand *Script::readOperand() { + byte operandType = _data->readByte(); + + debug(7, "%x: readOperand: 0x%x", _data->pos(), operandType); + + Context *cont = &_world->_player->_context; + switch (operandType) { + case 0xA0: // TEXT$ + return new Operand(_inputText, TEXT_INPUT); + case 0xA1: + return new Operand(_inputClick, CLICK_INPUT); + case 0xC0: // STORAGE@ + return new Operand(_world->_storageScene, SCENE); + case 0xC1: // SCENE@ + return new Operand(_world->_player->_currentScene, SCENE); + case 0xC2: // PLAYER@ + return new Operand(_world->_player, CHR); + case 0xC3: // MONSTER@ + return new Operand(_engine->getMonster(), CHR); + case 0xC4: // RANDOMSCN@ + return new Operand(_world->_orderedScenes[_engine->_rnd->getRandomNumber(_world->_orderedScenes.size())], SCENE); + case 0xC5: // RANDOMCHR@ + return new Operand(_world->_orderedChrs[_engine->_rnd->getRandomNumber(_world->_orderedChrs.size())], CHR); + case 0xC6: // RANDOMOBJ@ + return new Operand(_world->_orderedObjs[_engine->_rnd->getRandomNumber(_world->_orderedObjs.size())], OBJ); + case 0xB0: // VISITS# + return new Operand(cont->_visits, NUMBER); + case 0xB1: // RANDOM# for Star Trek, but VISITS# for some other games? + return new Operand(1 + _engine->_rnd->getRandomNumber(100), NUMBER); + case 0xB5: // RANDOM# // A random number between 1 and 100. + return new Operand(1 + _engine->_rnd->getRandomNumber(100), NUMBER); + case 0xB2: // LOOP# + return new Operand(_loopCount, NUMBER); + case 0xB3: // VICTORY# + return new Operand(cont->_kills, NUMBER); + case 0xB4: // BADCOPY# + return new Operand(0, NUMBER); // \?\?\?? + case 0xFF: + { + // user variable + int value = _data->readByte(); + + // TODO: Verify that we're using the right index. + return new Operand(cont->_userVariables[value - 1], NUMBER); + } + case 0xD0: + return new Operand(cont->_statVariables[PHYS_STR_BAS], NUMBER); + case 0xD1: + return new Operand(cont->_statVariables[PHYS_HIT_BAS], NUMBER); + case 0xD2: + return new Operand(cont->_statVariables[PHYS_ARM_BAS], NUMBER); + case 0xD3: + return new Operand(cont->_statVariables[PHYS_ACC_BAS], NUMBER); + case 0xD4: + return new Operand(cont->_statVariables[SPIR_STR_BAS], NUMBER); + case 0xD5: + return new Operand(cont->_statVariables[SPIR_HIT_BAS], NUMBER); + case 0xD6: + return new Operand(cont->_statVariables[SPIR_ARM_BAS], NUMBER); + case 0xD7: + return new Operand(cont->_statVariables[SPIR_ACC_BAS], NUMBER); + case 0xD8: + return new Operand(cont->_statVariables[PHYS_SPE_BAS], NUMBER); + case 0xE0: + return new Operand(cont->_statVariables[PHYS_STR_CUR], NUMBER); + case 0xE1: + return new Operand(cont->_statVariables[PHYS_HIT_CUR], NUMBER); + case 0xE2: + return new Operand(cont->_statVariables[PHYS_ARM_CUR], NUMBER); + case 0xE3: + return new Operand(cont->_statVariables[PHYS_ACC_CUR], NUMBER); + case 0xE4: + return new Operand(cont->_statVariables[SPIR_STR_CUR], NUMBER); + case 0xE5: + return new Operand(cont->_statVariables[SPIR_HIT_CUR], NUMBER); + case 0xE6: + return new Operand(cont->_statVariables[SPIR_ARM_CUR], NUMBER); + case 0xE7: + return new Operand(cont->_statVariables[SPIR_ACC_CUR], NUMBER); + case 0xE8: + return new Operand(cont->_statVariables[PHYS_SPE_CUR], NUMBER); + default: + if (operandType >= 0x20 && operandType < 0x80) { + _data->seek(-1, SEEK_CUR); + return readStringOperand(); + } else { + debug("Dunno what %x is (index=%d)!\n", operandType, _data->pos()-1); + } + return NULL; + } +} + +void Script::assign(byte operandType, int uservar, uint16 value) { + Context *cont = &_world->_player->_context; + + switch (operandType) { + case 0xFF: + cont->_userVariables[uservar - 1] = value; + break; + case 0xD0: + cont->_statVariables[PHYS_STR_BAS] = value; + break; + case 0xD1: + cont->_statVariables[PHYS_HIT_BAS] = value; + break; + case 0xD2: + cont->_statVariables[PHYS_ARM_BAS] = value; + break; + case 0xD3: + cont->_statVariables[PHYS_ACC_BAS] = value; + break; + case 0xD4: + cont->_statVariables[SPIR_STR_BAS] = value; + break; + case 0xD5: + cont->_statVariables[SPIR_HIT_BAS] = value; + break; + case 0xD6: + cont->_statVariables[SPIR_ARM_BAS] = value; + break; + case 0xD7: + cont->_statVariables[SPIR_ACC_BAS] = value; + break; + case 0xD8: + cont->_statVariables[PHYS_SPE_BAS] = value; + break; + case 0xE0: + cont->_statVariables[PHYS_STR_CUR] = value; + break; + case 0xE1: + cont->_statVariables[PHYS_HIT_CUR] = value; + break; + case 0xE2: + cont->_statVariables[PHYS_ARM_CUR] = value; + break; + case 0xE3: + cont->_statVariables[PHYS_ACC_CUR] = value; + break; + case 0xE4: + cont->_statVariables[SPIR_STR_CUR] = value; + break; + case 0xE5: + cont->_statVariables[SPIR_HIT_CUR] = value; + break; + case 0xE6: + cont->_statVariables[SPIR_ARM_CUR] = value; + break; + case 0xE7: + cont->_statVariables[SPIR_ACC_CUR] = value; + break; + case 0xE8: + cont->_statVariables[PHYS_SPE_CUR] = value; + break; + default: + debug("No idea what I'm supposed to assign! (%x at %d)!\n", operandType, _data->pos()-1); + } +} + +Script::Operand *Script::readStringOperand() { + Common::String *str; + bool allDigits = true; + + str = new Common::String(); + + while (true) { + byte c = _data->readByte(); + if (c >= 0x20 && c < 0x80) + *str += c; + else + break; + if (c < '0' || c > '9') + allDigits = false; + } + _data->seek(-1, SEEK_CUR); + + if (allDigits && !str->empty()) { + int r = atol(str->c_str()); + delete str; + + return new Operand(r, NUMBER); + } else { + // TODO: This string could be a room name or something like that. + return new Operand(str, STRING); + } +} + +const char *Script::readOperator() { + byte cmd = _data->readByte(); + + debug(7, "readOperator: 0x%x", cmd); + switch (cmd) { + case 0x81: + return "="; + case 0x82: + return "<"; + case 0x83: + return ">"; + case 0x8f: + return "+"; + case 0x90: + return "-"; + case 0x91: + return "*"; + case 0x92: + return "/"; + case 0x93: + return "=="; + case 0x94: + return ">>"; + case 0xfd: + return ";"; + default: + warning("UNKNOWN OP %x", cmd); + } + return NULL; +} + +void Script::processIf() { + int logicalOp = 0; // 0 => initial, 1 => and, 2 => or + bool result = true; + bool done = false; + + do { + Operand *lhs = readOperand(); + const char *op = readOperator(); + Operand *rhs = readOperand(); + + bool condResult = eval(lhs, op, rhs); + + delete lhs; + delete rhs; + + if (logicalOp == 1) { + result = (result && condResult); + } else if (logicalOp == 2) { + result = (result || condResult); + } else { // logicalOp == 0 + result = condResult; + } + + byte logical = _data->readByte(); + + if (logical == 0x84) { + logicalOp = 1; // and + } else if (logical == 0x85) { + logicalOp = 2; // or + } else if (logical == 0xFE) { + done = true; // then + } + } while (!done); + + if (result == false) { + skipBlock(); + } +} + +void Script::skipIf() { + do { + Operand *lhs = readOperand(); + readOperator(); + Operand *rhs = readOperand(); + + delete lhs; + delete rhs; + } while (_data->readByte() != 0xFE); +} + +void Script::skipBlock() { + int nesting = 1; + + while (true) { + byte op = _data->readByte(); + + if (_data->eos()) + return; + + if (op == 0x80) { // IF + nesting++; + skipIf(); + } else if (op == 0x88 || op == 0x87) { // END or EXIT + nesting--; + if (nesting == 0) { + return; + } + } else switch (op) { + case 0x8B: // PRINT + case 0x8C: // SOUND + case 0x8E: // LET + case 0x95: // MENU + while (_data->readByte() != 0xFD) + ; + } + } +} + +enum { + kCompEqNumNum, + kCompEqObjScene, + kCompEqChrScene, + kCompEqObjChr, + kCompEqChrChr, + kCompEqSceneScene, + kCompEqStringTextInput, + kCompEqTextInputString, + kCompEqNumberTextInput, + kCompEqTextInputNumber, + kCompLtNumNum, + kCompLtStringTextInput, + kCompLtTextInputString, + kCompLtObjChr, + kCompLtChrObj, + kCompLtObjScene, + kCompGtNumNum, + kCompGtStringString, + kCompGtChrScene, + kMoveObjChr, + kMoveObjScene, + kMoveChrScene +}; + +static const char *typeNames[] = { + "OBJ", + "CHR", + "SCENE", + "NUMBER", + "STRING", + "CLICK_INPUT", + "TEXT_INPUT" +}; + +static const char *operandTypeToStr(int type) { + if (type < 0 || type > 6) + return "UNKNOWN"; + + return typeNames[type]; +} + +struct Comparator { + char op; + OperandType o1; + OperandType o2; + int cmp; +} static comparators[] = { + { '=', NUMBER, NUMBER, kCompEqNumNum }, + { '=', OBJ, SCENE, kCompEqObjScene }, + { '=', CHR, SCENE, kCompEqChrScene }, + { '=', OBJ, CHR, kCompEqObjChr }, + { '=', CHR, CHR, kCompEqChrChr }, + { '=', SCENE, SCENE, kCompEqSceneScene }, + { '=', STRING, TEXT_INPUT, kCompEqStringTextInput }, + { '=', TEXT_INPUT, STRING, kCompEqTextInputString }, + { '=', NUMBER, TEXT_INPUT, kCompEqNumberTextInput }, + { '=', TEXT_INPUT, NUMBER, kCompEqTextInputNumber }, + + { '<', NUMBER, NUMBER, kCompLtNumNum }, + { '<', STRING, TEXT_INPUT, kCompLtStringTextInput }, + { '<', TEXT_INPUT, STRING, kCompLtTextInputString }, + { '<', OBJ, CHR, kCompLtObjChr }, + { '<', CHR, OBJ, kCompLtChrObj }, + { '<', OBJ, SCENE, kCompLtObjScene }, + { '<', CHR, CHR, kCompEqChrChr }, // Same logic as = + { '<', SCENE, SCENE, kCompEqSceneScene }, + + { '>', NUMBER, NUMBER, kCompGtNumNum }, + { '>', TEXT_INPUT, STRING, kCompLtTextInputString }, // Same logic as < + //FIXME: this prevents the below cases from working due to exact + //matches taking precedence over conversions... + //{ '>', STRING, STRING, kCompGtStringString }, // Same logic as < + { '>', OBJ, CHR, kCompLtObjChr }, // Same logic as < + { '>', OBJ, SCENE, kCompLtObjScene }, // Same logic as < + { '>', CHR, SCENE, kCompGtChrScene }, + + { 'M', OBJ, CHR, kMoveObjChr }, + { 'M', OBJ, SCENE, kMoveObjScene }, + { 'M', CHR, SCENE, kMoveChrScene }, + { 0, OBJ, OBJ, 0 } +}; + +bool Script::compare(Operand *o1, Operand *o2, int comparator) { + switch(comparator) { + case kCompEqNumNum: + return o1->_value.number == o2->_value.number; + case kCompEqObjScene: + for (ObjList::const_iterator it = o2->_value.scene->_objs.begin(); it != o2->_value.scene->_objs.end(); ++it) + if (*it == o1->_value.obj) + return true; + return false; + case kCompEqChrScene: + for (ChrList::const_iterator it = o2->_value.scene->_chrs.begin(); it != o2->_value.scene->_chrs.end(); ++it) + if (*it == o1->_value.chr) + return true; + return false; + case kCompEqObjChr: + for (ObjArray::const_iterator it = o2->_value.chr->_inventory.begin(); it != o2->_value.chr->_inventory.end(); ++it) + if (*it == o1->_value.obj) + return true; + return false; + case kCompEqChrChr: + return o1->_value.chr == o2->_value.chr; + case kCompEqSceneScene: + return o1->_value.scene == o2->_value.scene; + case kCompEqStringTextInput: + if (_inputText == NULL) { + return false; + } else { + Common::String s1(*_inputText), s2(*o1->_value.string); + s1.toLowercase(); + s2.toLowercase(); + + return s1.contains(s2); + } + case kCompEqTextInputString: + return compare(o2, o1, kCompEqStringTextInput); + case kCompEqNumberTextInput: + if (_inputText == NULL) { + return false; + } else { + Common::String s1(*_inputText), s2(o1->toString()); + s1.toLowercase(); + s2.toLowercase(); + + return s1.contains(s2); + } + case kCompEqTextInputNumber: + if (_inputText == NULL) { + return false; + } else { + Common::String s1(*_inputText), s2(o2->toString()); + s1.toLowercase(); + s2.toLowercase(); + + return s1.contains(s2); + } + case kCompLtNumNum: + return o1->_value.number < o2->_value.number; + case kCompLtStringTextInput: + return !compare(o1, o2, kCompEqStringTextInput); + case kCompLtTextInputString: + return !compare(o2, o1, kCompEqStringTextInput); + case kCompLtObjChr: + return o1->_value.obj->_currentOwner != o2->_value.chr; + case kCompLtChrObj: + return compare(o2, o1, kCompLtObjChr); + case kCompLtObjScene: + return o1->_value.obj->_currentScene != o2->_value.scene; + case kCompGtNumNum: + return o1->_value.number > o2->_value.number; + case kCompGtStringString: + return o1->_value.string == o2->_value.string; + case kCompGtChrScene: + return (o1->_value.chr != NULL && o1->_value.chr->_currentScene != o2->_value.scene); + case kMoveObjChr: + if (o1->_value.obj->_currentOwner != o2->_value.chr) { + _world->move(o1->_value.obj, o2->_value.chr); + _handled = true; // TODO: Is this correct? + } + break; + case kMoveObjScene: + if (o1->_value.obj->_currentScene != o2->_value.scene) { + _world->move(o1->_value.obj, o2->_value.scene); + // Note: This shouldn't call setHandled() - see + // Sultan's Palace 'Food and Drink' scene. + } + break; + case kMoveChrScene: + _world->move(o1->_value.chr, o2->_value.scene); + _handled = true; // TODO: Is this correct? + break; + } + + return false; +} + +bool Script::evaluatePair(Operand *lhs, const char *op, Operand *rhs) { + debug(7, "HANDLING CASE: [lhs=%s/%s, op=%s rhs=%s/%s]", + operandTypeToStr(lhs->_type), lhs->toString().c_str(), op, operandTypeToStr(rhs->_type), rhs->toString().c_str()); + + for (int cmp = 0; comparators[cmp].op != 0; cmp++) { + if (comparators[cmp].op != op[0]) + continue; + + if (comparators[cmp].o1 == lhs->_type && comparators[cmp].o2 == rhs->_type) + return compare(lhs, rhs, comparators[cmp].cmp); + } + + // Now, try partial matches. + Operand *c1, *c2; + for (int cmp = 0; comparators[cmp].op != 0; cmp++) { + if (comparators[cmp].op != op[0]) + continue; + + if (comparators[cmp].o1 == lhs->_type && + (c2 = convertOperand(rhs, comparators[cmp].o2)) != NULL) { + bool res = compare(lhs, c2, comparators[cmp].cmp); + delete c2; + return res; + } else if (comparators[cmp].o2 == rhs->_type && + (c1 = convertOperand(lhs, comparators[cmp].o1)) != NULL) { + bool res = compare(c1, rhs, comparators[cmp].cmp); + delete c1; + return res; + } + } + + // Now, try double conversion. + for (int cmp = 0; comparators[cmp].op != 0; cmp++) { + if (comparators[cmp].op != op[0]) + continue; + + if (comparators[cmp].o1 == lhs->_type || comparators[cmp].o2 == rhs->_type) + continue; + + if ((c1 = convertOperand(lhs, comparators[cmp].o1)) != NULL) { + if ((c2 = convertOperand(rhs, comparators[cmp].o2)) != NULL) { + bool res = compare(c1, c2, comparators[cmp].cmp); + delete c1; + delete c2; + return res; + } + delete c1; + } + } + + warning("UNHANDLED CASE: [lhs=%s/%s, op=%s rhs=%s/%s]", + operandTypeToStr(lhs->_type), lhs->toString().c_str(), op, operandTypeToStr(rhs->_type), rhs->toString().c_str()); + + return false; +} + +bool Script::eval(Operand *lhs, const char *op, Operand *rhs) { + bool result = false; + + if (lhs->_type == CLICK_INPUT || rhs->_type == CLICK_INPUT) { + return evalClickCondition(lhs, op, rhs); + } else if (!strcmp(op, "==") || !strcmp(op, ">>")) { + // TODO: check if >> can be used for click inputs and if == can be used for other things + // exact string match + if (lhs->_type == TEXT_INPUT) { + if ((rhs->_type != STRING && rhs->_type != NUMBER) || _inputText == NULL) { + result = false; + } else { + result = _inputText->equalsIgnoreCase(rhs->toString()); + } + } else if (rhs->_type == TEXT_INPUT) { + if ((lhs->_type != STRING && lhs->_type != NUMBER) || _inputText == NULL) { + result = false; + } else { + result = _inputText->equalsIgnoreCase(lhs->toString()); + } + } else { + error("UNHANDLED CASE: [lhs=%s/%s, rhs=%s/%s]", + operandTypeToStr(lhs->_type), lhs->toString().c_str(), operandTypeToStr(rhs->_type), rhs->toString().c_str()); + } + if (!strcmp(op, ">>")) { + result = !result; + } + + return result; + } else { + return evaluatePair(lhs, op, rhs); + } + + return false; +} + +Script::Operand *Script::convertOperand(Operand *operand, int type) { + if (operand->_type == type) + error("Incorrect conversion to type %d", type); + + if (type == SCENE) { + if (operand->_type == STRING || operand->_type == NUMBER) { + Common::String key(operand->toString()); + key.toLowercase(); + if (_world->_scenes.contains(key)) + return new Operand(_world->_scenes[key], SCENE); + } + } else if (type == OBJ) { + if (operand->_type == STRING || operand->_type == NUMBER) { + Common::String key = operand->toString(); + key.toLowercase(); + if (_world->_objs.contains(key)) + return new Operand(_world->_objs[key], OBJ); + } else if (operand->_type == CLICK_INPUT) { + if (_inputClick->_classType == OBJ) + return new Operand(_inputClick, OBJ); + } + } else if (type == CHR) { + if (operand->_type == STRING || operand->_type == NUMBER) { + Common::String key = operand->toString(); + key.toLowercase(); + if (_world->_chrs.contains(key)) + return new Operand(_world->_chrs[key], CHR); + } else if (operand->_type == CLICK_INPUT) { + if (_inputClick->_classType == CHR) + return new Operand(_inputClick, CHR); + } + } + + return NULL; +} + +bool Script::evalClickEquality(Operand *lhs, Operand *rhs, bool partialMatch) { + bool result = false; + if (lhs->_value.obj == NULL || rhs->_value.obj == NULL) { + result = false; + } else if (lhs->_value.obj == rhs->_value.obj) { + result = true; + } else if (rhs->_type == STRING) { + Common::String str = rhs->toString(); + str.toLowercase(); + + debug(9, "evalClickEquality(%s, %s, %d)", lhs->_value.designed->_name.c_str(), rhs->_value.designed->_name.c_str(), partialMatch); + debug(9, "l: %s r: %s)", operandTypeToStr(lhs->_type), operandTypeToStr(rhs->_type)); + debug(9, "class: %d", lhs->_value.inputClick->_classType); + + if (lhs->_value.inputClick->_classType == CHR || lhs->_value.inputClick->_classType == OBJ) { + Common::String name = lhs->_value.designed->_name; + name.toLowercase(); + + if (partialMatch) + result = name.contains(str); + else + result = name.equals(str); + } + + debug(9, "result: %d", result); + } + return result; +} + +bool Script::evalClickCondition(Operand *lhs, const char *op, Operand *rhs) { + // TODO: check if >> can be used for click inputs + if (strcmp(op, "==") && strcmp(op, "=") && strcmp(op, "<") && strcmp(op, ">")) { + error("Unknown operation '%s' for Script::evalClickCondition", op); + } + + bool partialMatch = strcmp(op, "=="); + bool result; + if (lhs->_type == CLICK_INPUT) { + result = evalClickEquality(lhs, rhs, partialMatch); + } else { + result = evalClickEquality(rhs, lhs, partialMatch); + } + if (!strcmp(op, "<") || !strcmp(op, ">")) { + // CLICK$<FOO only matches if there was a click + if (_inputClick == NULL) { + result = false; + } else { + result = !result; + } + } + return result; +} + +void Script::processMove() { + Operand *what = readOperand(); + byte skip = _data->readByte(); + if (skip != 0x8a) + error("Incorrect operator for MOVE: %02x", skip); + + Operand *to = readOperand(); + + skip = _data->readByte(); + if (skip != 0xfd) + error("No end for MOVE: %02x", skip); + + evaluatePair(what, "M", to); + + delete what; + delete to; +} + +void Script::processLet() { + const char *lastOp = NULL; + int16 result = 0; + int operandType = _data->readByte(); + int uservar = 0; + + if (operandType == 0xff) { + uservar = _data->readByte(); + } + + byte eq = _data->readByte(); // skip "=" operator + + debug(7, "processLet: 0x%x, uservar: 0x%x, eq: 0x%x", operandType, uservar, eq); + + do { + Operand *operand = readOperand(); + // TODO assert that value is NUMBER + int16 value = operand->_value.number; + delete operand; + if (lastOp != NULL) { + if (lastOp[0] == '+') + result += value; + else if (lastOp[0] == '-') + result -= value; + else if (lastOp[0] == '/') + result = (int16)(value == 0 ? 0 : result / value); + else if (lastOp[0] == '*') + result *= value; + } else { + result = value; + } + lastOp = readOperator(); + + if (lastOp[0] == ';') + break; + } while (true); + //System.out.println("processLet " + buildStringFromOffset(oldIndex - 1, index - oldIndex + 1) + "}"); + + assign(operandType, uservar, result); +} + +enum { + BLOCK_START, + BLOCK_END, + STATEMENT, + OPERATOR, + OPCODE +}; + +struct Mapping { + const char *cmd; + int type; +} static const mapping[] = { + { "IF{", STATEMENT }, // 0x80 + { "=", OPERATOR }, + { "<", OPERATOR }, + { ">", OPERATOR }, + { "}AND{", OPCODE }, + { "}OR{", OPCODE }, + { "\?\?\?(0x86)", OPCODE }, + { "EXIT\n", BLOCK_END }, + { "END\n", BLOCK_END }, // 0x88 + { "MOVE{", STATEMENT }, + { "}TO{", OPCODE }, + { "PRINT{", STATEMENT }, + { "SOUND{", STATEMENT }, + { "\?\?\?(0x8d)", OPCODE }, + { "LET{", STATEMENT }, + { "+", OPERATOR }, + { "-", OPERATOR }, // 0x90 + { "*", OPERATOR }, + { "/", OPERATOR }, + { "==", OPERATOR }, + { ">>", OPERATOR }, + { "MENU{", STATEMENT }, + { "\?\?\?(0x96)", OPCODE }, + { "\?\?\?(0x97)", OPCODE }, + { "\?\?\?(0x98)", OPCODE }, // 0x98 + { "\?\?\?(0x99)", OPCODE }, + { "\?\?\?(0x9a)", OPCODE }, + { "\?\?\?(0x9b)", OPCODE }, + { "\?\?\?(0x9c)", OPCODE }, + { "\?\?\?(0x9d)", OPCODE }, + { "\?\?\?(0x9e)", OPCODE }, + { "\?\?\?(0x9f)", OPCODE }, + { "TEXT$", OPCODE }, // 0xa0 + { "CLICK$", OPCODE }, + { "\?\?\?(0xa2)", OPCODE }, + { "\?\?\?(0xa3)", OPCODE }, + { "\?\?\?(0xa4)", OPCODE }, + { "\?\?\?(0xa5)", OPCODE }, + { "\?\?\?(0xa6)", OPCODE }, + { "\?\?\?(0xa7)", OPCODE }, + { "\?\?\?(0xa8)", OPCODE }, // 0xa8 + { "\?\?\?(0xa9)", OPCODE }, + { "\?\?\?(0xaa)", OPCODE }, + { "\?\?\?(0xab)", OPCODE }, + { "\?\?\?(0xac)", OPCODE }, + { "\?\?\?(0xad)", OPCODE }, + { "\?\?\?(0xae)", OPCODE }, + { "\?\?\?(0xaf)", OPCODE }, + { "VISITS#", OPCODE }, // 0xb0 // The number of scenes the player has visited, including repeated visits. + { "RANDOM#", OPCODE }, // RANDOM# for Star Trek, but VISITS# for some other games? + { "LOOP#", OPCODE }, // The number of commands the player has given in the current scene. + { "VICTORY#", OPCODE }, // The number of characters killed. + { "BADCOPY#", OPCODE }, + { "RANDOM#", OPCODE }, // A random number between 1 and 100. + { "\?\?\?(0xb6)", OPCODE }, + { "\?\?\?(0xb7)", OPCODE }, + { "\?\?\?(0xb8)", OPCODE }, // 0xb8 + { "\?\?\?(0xb9)", OPCODE }, + { "\?\?\?(0xba)", OPCODE }, + { "\?\?\?(0xbb)", OPCODE }, + { "\?\?\?(0xbc)", OPCODE }, + { "\?\?\?(0xbd)", OPCODE }, + { "\?\?\?(0xbe)", OPCODE }, + { "\?\?\?(0xbf)", OPCODE }, + { "STORAGE@", OPCODE }, // 0xc0 + { "SCENE@", OPCODE }, + { "PLAYER@", OPCODE }, + { "MONSTER@", OPCODE }, + { "RANDOMSCN@", OPCODE }, + { "RANDOMCHR@", OPCODE }, + { "RANDOMOBJ@", OPCODE }, + { "\?\?\?(0xc7)", OPCODE }, + { "\?\?\?(0xc8)", OPCODE }, // 0xc8 + { "\?\?\?(0xc9)", OPCODE }, + { "\?\?\?(0xca)", OPCODE }, + { "\?\?\?(0xcb)", OPCODE }, + { "\?\?\?(0xcc)", OPCODE }, + { "\?\?\?(0xcd)", OPCODE }, + { "\?\?\?(0xce)", OPCODE }, + { "\?\?\?(0xcf)", OPCODE }, + { "PHYS.STR.BAS#", OPCODE }, // 0xd0 + { "PHYS.HIT.BAS#", OPCODE }, + { "PHYS.ARM.BAS#", OPCODE }, + { "PHYS.ACC.BAS#", OPCODE }, + { "SPIR.STR.BAS#", OPCODE }, + { "SPIR.HIT.BAS#", OPCODE }, + { "SPIR.ARM.BAS#", OPCODE }, + { "SPIR.ACC.BAS#", OPCODE }, + { "PHYS.SPE.BAS#", OPCODE }, // 0xd8 + { "\?\?\?(0xd9)", OPCODE }, + { "\?\?\?(0xda)", OPCODE }, + { "\?\?\?(0xdb)", OPCODE }, + { "\?\?\?(0xdc)", OPCODE }, + { "\?\?\?(0xdd)", OPCODE }, + { "\?\?\?(0xde)", OPCODE }, + { "\?\?\?(0xdf)", OPCODE }, + { "PHYS.STR.CUR#", OPCODE }, // 0xe0 + { "PHYS.HIT.CUR#", OPCODE }, + { "PHYS.ARM.CUR#", OPCODE }, + { "PHYS.ACC.CUR#", OPCODE }, + { "SPIR.STR.CUR#", OPCODE }, + { "SPIR.HIT.CUR#", OPCODE }, + { "SPIR.ARM.CUR#", OPCODE }, + { "SPIR.ACC.CUR#", OPCODE }, + { "PHYS.SPE.CUR#", OPCODE }, // 0xe8 + { "\?\?\?(0xe9)", OPCODE }, + { "\?\?\?(0xea)", OPCODE }, + { "\?\?\?(0xeb)", OPCODE }, + { "\?\?\?(0xec)", OPCODE }, + { "\?\?\?(0xed)", OPCODE }, + { "\?\?\?(0xee)", OPCODE }, + { "\?\?\?(0xef)", OPCODE }, + { "\?\?\?(0xf0)", OPCODE }, + { "\?\?\?(0xf1)", OPCODE }, + { "\?\?\?(0xf2)", OPCODE }, + { "\?\?\?(0xf3)", OPCODE }, + { "\?\?\?(0xf4)", OPCODE }, + { "\?\?\?(0xf5)", OPCODE }, + { "\?\?\?(0xf6)", OPCODE }, + { "\?\?\?(0xf7)", OPCODE }, + { "\?\?\?(0xf8)", OPCODE }, // 0xa8 + { "\?\?\?(0xf9)", OPCODE }, + { "\?\?\?(0xfa)", OPCODE }, + { "\?\?\?(0xfb)", OPCODE }, + { "\?\?\?(0xfc)", OPCODE }, + { "}\n", OPCODE }, + { "}THEN\n", BLOCK_START }, + { "\?\?\?(0xff)", OPCODE } // Uservar +}; + +void Script::convertToText() { + _data->seek(12); + + int indentLevel = 0; + ScriptText *scr = new ScriptText; + scr->offset = _data->pos(); + + while(true) { + int c = _data->readByte(); + + if (_data->eos()) + break; + + if (c < 0x80) { + if (c < 0x20) + error("convertToText: Unknown code 0x%02x at %d", c, _data->pos()); + + do { + scr->line += c; + c = _data->readByte(); + } while (c < 0x80); + + _data->seek(-1, SEEK_CUR); + } else if (c == 0xff) { + int value = _data->readByte(); + value -= 1; + scr->line += (char)('A' + (value / 9)); + scr->line += (char)('0' + (value % 9) + 1); + scr->line += '#'; + } else { + const char *cmd = mapping[c - 0x80].cmd; + int type = mapping[c - 0x80].type; + + if (type == STATEMENT) { + for (int i = 0; i < indentLevel; i++) + scr->line += ' '; + } else if (type == BLOCK_START) { + indentLevel += 2; + } else if (type == BLOCK_END) { + indentLevel -= 2; + for (int i = 0; i < indentLevel; i++) + scr->line += ' '; + } + + scr->line += cmd; + + if (strchr(cmd, '\n')) { + scr->line.deleteLastChar(); + + _scriptText.push_back(scr); + + scr = new ScriptText; + scr->offset = _data->pos(); + } + } + } + + if (!scr->line.empty()) + _scriptText.push_back(scr); + else + delete scr; +} + +} // End of namespace Wage diff --git a/engines/wage/script.h b/engines/wage/script.h new file mode 100644 index 0000000000..de9476228c --- /dev/null +++ b/engines/wage/script.h @@ -0,0 +1,161 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef WAGE_SCRIPT_H +#define WAGE_SCRIPT_H + +namespace Wage { + +class Script { +public: + Script(Common::SeekableReadStream *data); + ~Script(); + +private: + Common::SeekableReadStream *_data; + + WageEngine *_engine; + World *_world; + int _loopCount; + Common::String *_inputText; + Designed *_inputClick; + bool _handled; + + class Operand { + public: + union { + Obj *obj; + Chr *chr; + Designed *designed; + Scene *scene; + int16 number; + Common::String *string; + Designed *inputClick; + } _value; + OperandType _type; + + Operand(Obj *value, OperandType type) { + _value.obj = value; + assert(type == OBJ); + _type = type; + } + + Operand(Chr *value, OperandType type) { + _value.chr = value; + assert(type == CHR); + _type = type; + } + + Operand(Scene *value, OperandType type) { + _value.scene = value; + assert(type == SCENE); + _type = type; + } + + Operand(int value, OperandType type) { + _value.number = value; + assert(type == NUMBER); + _type = type; + } + + Operand(Common::String *value, OperandType type) { + _value.string = value; + assert(type == STRING || type == TEXT_INPUT); + _type = type; + } + + Operand(Designed *value, OperandType type) { + _value.inputClick = value; + assert(type == CLICK_INPUT); + _type = type; + } + + ~Operand() { + if (_type == STRING) + delete _value.string; + } + + Common::String toString(); + }; + + struct ScriptText { + int offset; + Common::String line; + }; + +public: + void print(); + void printLine(int offset); + bool execute(World *world, int loopCount, Common::String *inputText, Designed *inputClick, WageEngine *engine); + +private: + Operand *readOperand(); + Operand *readStringOperand(); + const char *readOperator(); + void processIf(); + void skipBlock(); + void skipIf(); + bool compare(Operand *o1, Operand *o2, int comparator); + bool eval(Operand *lhs, const char *op, Operand *rhs); + bool evaluatePair(Operand *lhs, const char *op, Operand *rhs); + Operand *convertOperand(Operand *operand, int type); + bool evalClickCondition(Operand *lhs, const char *op, Operand *rhs); + bool evalClickEquality(Operand *lhs, Operand *rhs, bool partialMatch); + void processMove(); + void processLet(); + + void assign(byte operandType, int uservar, uint16 value); + + void convertToText(); + +public: + Common::Array<ScriptText *> _scriptText; +}; + +} // End of namespace Wage + +#endif diff --git a/engines/wage/sound.cpp b/engines/wage/sound.cpp new file mode 100644 index 0000000000..bcb274cab9 --- /dev/null +++ b/engines/wage/sound.cpp @@ -0,0 +1,86 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "common/stream.h" + +#include "wage/wage.h" +#include "wage/sound.h" + +namespace Wage { + +static const int8 deltas[] = { 0,-49,-36,-25,-16,-9,-4,-1,0,1,4,9,16,25,36,49 }; + +Sound::Sound(Common::String name, Common::SeekableReadStream *data) : _name(name) { + int size = data->size() - 20; + _data = (byte *)calloc(2 * size, 1); + + data->skip(20); // Skip header + + byte value = 0x80; + for (int i = 0; i < size; i++) { + byte d = data->readByte(); + value += deltas[d & 0xf]; + _data[i * 2] = value; + value += deltas[(d >> 4) & 0xf]; + _data[i * 2 + 1] = value; + } +} + +Sound::~Sound() { + free(_data); +} + +void WageEngine::playSound(Common::String soundName) { + warning("STUB: WageEngine::playSound(%s)", soundName.c_str()); +} + +void WageEngine::updateSoundTimerForScene(Scene *scene, bool firstTime) { + //warning("STUB: WageEngine::updateSoundTimerForScene()"); +} + + +} // End of namespace Wage diff --git a/engines/wage/sound.h b/engines/wage/sound.h new file mode 100644 index 0000000000..eccfe33170 --- /dev/null +++ b/engines/wage/sound.h @@ -0,0 +1,64 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef WAGE_SOUND_H +#define WAGE_SOUND_H + +namespace Wage { + +class Sound { +public: + Sound(Common::String name, Common::SeekableReadStream *data); + ~Sound(); + + Common::String _name; + byte *_data; +}; + +} // End of namespace Wage + +#endif diff --git a/engines/wage/util.cpp b/engines/wage/util.cpp new file mode 100644 index 0000000000..f31a83ca04 --- /dev/null +++ b/engines/wage/util.cpp @@ -0,0 +1,125 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "common/stream.h" + +#include "wage/wage.h" + +namespace Wage { + +Common::String readPascalString(Common::SeekableReadStream *in) { + Common::String s; + char *buf; + int len; + int i; + + len = in->readByte(); + buf = (char *)malloc(len + 1); + for (i = 0; i < len; i++) { + buf[i] = in->readByte(); + if (buf[i] == 0x0d) + buf[i] = '\n'; + } + + buf[i] = 0; + + s = buf; + free(buf); + + return s; +} + +Common::Rect *readRect(Common::SeekableReadStream *in) { + int x1, y1, x2, y2; + + y1 = in->readUint16BE(); + x1 = in->readUint16BE(); + y2 = in->readUint16BE() + 4; + x2 = in->readUint16BE() + 4; + + debug(9, "readRect: %d, %d, %d, %d", x1, y1, x2, y2); + + return new Common::Rect(x1, y1, x2, y2); +} + +const char *getIndefiniteArticle(const Common::String &word) { + switch (word[0]) { + case 'a': case 'A': + case 'e': case 'E': + case 'i': case 'I': + case 'o': case 'O': + case 'u': case 'U': + return "an "; + } + return "a "; +} + +enum { + GENDER_MALE = 0, + GENDER_FEMALE = 1, + GENDER_NEUTRAL = 2 +}; + +const char *prependGenderSpecificPronoun(int gender) { + if (gender == GENDER_MALE) + return "his "; + else if (gender == GENDER_FEMALE) + return "her "; + else + return "its "; +} + +const char *getGenderSpecificPronoun(int gender, bool capitalize) { + if (gender == GENDER_MALE) + return capitalize ? "He" : "he"; + else if (gender == GENDER_FEMALE) + return capitalize ? "She" : "she"; + else + return capitalize ? "It" : "it"; +} + +} // End of namespace Wage diff --git a/engines/wage/wage.cpp b/engines/wage/wage.cpp new file mode 100644 index 0000000000..e0299c8da2 --- /dev/null +++ b/engines/wage/wage.cpp @@ -0,0 +1,515 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "common/debug-channels.h" +#include "common/error.h" +#include "common/events.h" +#include "common/system.h" + +#include "engines/engine.h" +#include "engines/util.h" + +#include "wage/wage.h" +#include "wage/entities.h" +#include "wage/gui.h" +#include "wage/dialog.h" +#include "wage/script.h" +#include "wage/world.h" + +namespace Wage { + +WageEngine::WageEngine(OSystem *syst, const ADGameDescription *desc) : Engine(syst), _gameDescription(desc) { + _rnd = new Common::RandomSource("wage"); + + _aim = -1; + _opponentAim = -1; + _temporarilyHidden = false; + _isGameOver = false; + _monster = NULL; + _running = NULL; + _lastScene = NULL; + + _loopCount = 0; + _turn = 0; + + _commandWasQuick = false; + + _shouldQuit = false; + + _gui = NULL; + _world = NULL; + _console = NULL; + _offer = NULL; + + _resManager = NULL; + + debug("WageEngine::WageEngine()"); +} + +WageEngine::~WageEngine() { + debug("WageEngine::~WageEngine()"); + + DebugMan.clearAllDebugChannels(); + delete _world; + delete _resManager; + delete _gui; + delete _rnd; + delete _console; +} + +Common::Error WageEngine::run() { + debug("WageEngine::init"); + + initGraphics(512, 342, true); + + // Create debugger console. It requires GFX to be initialized + _console = new Console(this); + + _debugger = new Debugger(this); + + // Your main event loop should be (invoked from) here. + _resManager = new Common::MacResManager(); + if (!_resManager->open(getGameFile())) + error("Could not open %s as a resource fork", getGameFile()); + + _world = new World(this); + + if (!_world->loadWorld(_resManager)) + return Common::kNoGameDataFoundError; + + _gui = new Gui(this); + + _temporarilyHidden = true; + performInitialSetup(); + Common::String input("look"); + processTurn(&input, NULL); + _temporarilyHidden = false; + + _shouldQuit = false; + + while (!_shouldQuit) { + _debugger->onFrame(); + + processEvents(); + + _gui->draw(); + g_system->updateScreen(); + g_system->delayMillis(50); + } + + return Common::kNoError; +} + +void WageEngine::processEvents() { + Common::Event event; + + while (_eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_QUIT: + if (saveDialog()) + _shouldQuit = true; + break; + case Common::EVENT_MOUSEMOVE: + _gui->mouseMove(event.mouse.x, event.mouse.y); + break; + case Common::EVENT_LBUTTONDOWN: + _gui->mouseDown(event.mouse.x, event.mouse.y); + break; + case Common::EVENT_LBUTTONUP: + { + Designed *obj = _gui->mouseUp(event.mouse.x, event.mouse.y); + if (obj != NULL) + processTurn(NULL, obj); + } + break; + case Common::EVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_BACKSPACE: + if (!_inputText.empty()) { + _inputText.deleteLastChar(); + _gui->drawInput(); + } + break; + + case Common::KEYCODE_RETURN: + if (_inputText.empty()) + break; + + processTurn(&_inputText, NULL); + _gui->disableUndo(); + 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); + } + break; + } + + if (event.kbd.ascii >= 0x20 && event.kbd.ascii <= 0x7f) { + _inputText += (char)event.kbd.ascii; + _gui->drawInput(); + } + + break; + } + break; + + default: + break; + } + } +} + +void WageEngine::setMenu(Common::String menu) { + _world->_commandsMenu = menu; + + _gui->regenCommandsMenu(); +} + +void WageEngine::appendText(const char *str) { + _gui->appendText(str); + + _inputText.clear(); +} + +void WageEngine::gameOver() { + DialogButtonArray buttons; + + buttons.push_back(new DialogButton("OK", 66, 67, 68, 28)); + + Dialog gameOverDialog(_gui, 199, _world->_gameOverMessage->c_str(), &buttons, 0); + + gameOverDialog.run(); + + doClose(); + + _gui->disableAllMenus(); + _gui->enableNewGameMenus(); + _gui->_menuDirty = true; +} + +bool WageEngine::saveDialog() { + DialogButtonArray buttons; + + buttons.push_back(new DialogButton("No", 19, 67, 68, 28)); + buttons.push_back(new DialogButton("Yes", 112, 67, 68, 28)); + buttons.push_back(new DialogButton("Cancel", 205, 67, 68, 28)); + + Dialog save(_gui, 291, "Save changes before closing?", &buttons, 1); + + int button = save.run(); + + if (button == 2) // Cancel + return false; + + if (button == 1) + saveGame(); + + doClose(); + + return true; +} + +void WageEngine::saveGame() { + warning("STUB: saveGame()"); +} + +void WageEngine::performInitialSetup() { + debug(5, "Resetting Objs: %d", _world->_orderedObjs.size()); + for (uint i = 0; i < _world->_orderedObjs.size() - 1; i++) + _world->move(_world->_orderedObjs[i], _world->_storageScene, true); + + _world->move(_world->_orderedObjs[_world->_orderedObjs.size() - 1], _world->_storageScene); + + debug(5, "Resetting Chrs: %d", _world->_orderedChrs.size()); + for (uint i = 0; i < _world->_orderedChrs.size() - 1; i++) + _world->move(_world->_orderedChrs[i], _world->_storageScene, true); + + _world->move(_world->_orderedChrs[_world->_orderedChrs.size() - 1], _world->_storageScene); + + debug(5, "Resetting Owners: %d", _world->_orderedObjs.size()); + for (uint i = 0; i < _world->_orderedObjs.size(); i++) { + Obj *obj = _world->_orderedObjs[i]; + if (!obj->_sceneOrOwner.equalsIgnoreCase(STORAGESCENE)) { + Common::String location = obj->_sceneOrOwner; + location.toLowercase(); + if (_world->_scenes.contains(location)) { + _world->move(obj, _world->_scenes[location]); + } else { + if (!_world->_chrs.contains(location)) { + // Note: PLAYER@ is not a valid target here. + warning("Couldn't move %s to %s", obj->_name.c_str(), obj->_sceneOrOwner.c_str()); + } else { + // TODO: Add check for max items. + _world->move(obj, _world->_chrs[location]); + } + } + } + } + + bool playerPlaced = false; + for (uint i = 0; i < _world->_orderedChrs.size(); i++) { + Chr *chr = _world->_orderedChrs[i]; + if (!chr->_initialScene.equalsIgnoreCase(STORAGESCENE)) { + Common::String key = chr->_initialScene; + key.toLowercase(); + if (_world->_scenes.contains(key) && _world->_scenes[key] != NULL) { + _world->move(chr, _world->_scenes[key]); + + if (chr->_playerCharacter) + debug(0, "Initial scene: %s", key.c_str()); + } else { + _world->move(chr, _world->getRandomScene()); + } + if (chr->_playerCharacter) { + playerPlaced = true; + } + } + chr->wearObjs(); + } + if (!playerPlaced) { + _world->move(_world->_player, _world->getRandomScene()); + } +} + +void WageEngine::doClose() { + warning("STUB: doClose()"); +} + +Scene *WageEngine::getSceneByName(Common::String &location) { + Scene *scene; + if (location.equals("random@")) { + scene = _world->getRandomScene(); + } else { + scene = _world->_scenes[location]; + } + return scene; +} + +void WageEngine::onMove(Designed *what, Designed *from, Designed *to) { + Chr *player = _world->_player; + Scene *currentScene = player->_currentScene; + if (currentScene == _world->_storageScene && !_temporarilyHidden) { + if (!_isGameOver) { + _isGameOver = true; + gameOver(); + } + return; + } + + if (from == currentScene || to == currentScene || + (what->_classType == CHR && ((Chr *)what)->_currentScene == currentScene) || + (what->_classType == OBJ && ((Obj *)what)->_currentScene == currentScene)) + _gui->setSceneDirty(); + + if ((from == player || to == player) && !_temporarilyHidden) + _gui->regenWeaponsMenu(); + + if (what != player && what->_classType == CHR) { + Chr *chr = (Chr *)what; + if (to == _world->_storageScene) { + int returnTo = chr->_returnTo; + if (returnTo != Chr::RETURN_TO_STORAGE) { + Common::String returnToSceneName; + if (returnTo == Chr::RETURN_TO_INITIAL_SCENE) { + returnToSceneName = chr->_initialScene; + returnToSceneName.toLowercase(); + } else { + returnToSceneName = "random@"; + } + Scene *scene = getSceneByName(returnToSceneName); + if (scene != NULL && scene != _world->_storageScene) { + _world->move(chr, scene); + // To avoid sleeping twice, return if the above move command would cause a sleep. + if (scene == currentScene) + return; + } + } + } else if (to == player->_currentScene) { + if (getMonster() == NULL) { + _monster = chr; + encounter(player, chr); + } + } + } + if (!_temporarilyHidden) { + if (to == currentScene || from == currentScene) { + redrawScene(); + g_system->delayMillis(100); + } + } +} + +void WageEngine::redrawScene() { + Scene *currentScene = _world->_player->_currentScene; + + if (currentScene != NULL) { + bool firstTime = (_lastScene != currentScene); + + updateSoundTimerForScene(currentScene, firstTime); + } +} + +void WageEngine::processTurnInternal(Common::String *textInput, Designed *clickInput) { + Scene *playerScene = _world->_player->_currentScene; + if (playerScene == _world->_storageScene) + return; + + bool shouldEncounter = false; + + if (playerScene != _lastScene) { + _loopCount = 0; + _lastScene = playerScene; + _monster = NULL; + _running = NULL; + _offer = NULL; + + for (ChrList::const_iterator it = playerScene->_chrs.begin(); it != playerScene->_chrs.end(); ++it) { + if (!(*it)->_playerCharacter) { + _monster = *it; + shouldEncounter = true; + break; + } + } + } + + bool monsterWasNull = (_monster == NULL); + Script *script = playerScene->_script != NULL ? playerScene->_script : _world->_globalScript; + bool handled = script->execute(_world, _loopCount++, textInput, clickInput, this); + + playerScene = _world->_player->_currentScene; + + if (playerScene == _world->_storageScene) + return; + + if (playerScene != _lastScene) { + _temporarilyHidden = true; + _gui->clearOutput(); + regen(); + Common::String input("look"); + processTurnInternal(&input, NULL); + redrawScene(); + _temporarilyHidden = false; + } else if (_loopCount == 1) { + redrawScene(); + if (shouldEncounter && getMonster() != NULL) { + encounter(_world->_player, _monster); + } + } else if (textInput != NULL && !handled) { + if (monsterWasNull && getMonster() != NULL) + return; + + const char *rant = _rnd->getRandomNumber(1) ? "What?" : "Huh?"; + + appendText(rant); + _commandWasQuick = true; + } +} + +void WageEngine::processTurn(Common::String *textInput, Designed *clickInput) { + _commandWasQuick = false; + Scene *prevScene = _world->_player->_currentScene; + Chr *prevMonster = getMonster(); + Common::String input; + + if (textInput) + input = *textInput; + + input.toLowercase(); + if (input.equals("e")) + input = "east"; + else if (input.equals("w")) + input = "west"; + else if (input.equals("n")) + input = "north"; + else if (input.equals("s")) + input = "south"; + + processTurnInternal(&input, clickInput); + Scene *playerScene = _world->_player->_currentScene; + + if (prevScene != playerScene && playerScene != _world->_storageScene) { + if (prevMonster != NULL) { + bool followed = false; + if (getMonster() == NULL) { + // TODO: adjacent scenes doesn't contain up/down etc... verify that monsters can't follow these... + if (_world->scenesAreConnected(playerScene, prevMonster->_currentScene)) { + int chance = _rnd->getRandomNumber(255); + followed = (chance < prevMonster->_followsOpponent); + } + } + + char buf[512]; + + if (followed) { + snprintf(buf, 512, "%s%s follows you.", prevMonster->getDefiniteArticle(true), prevMonster->_name.c_str()); + appendText(buf); + + _world->move(prevMonster, playerScene); + } else { + snprintf(buf, 512, "You escape %s%s.", prevMonster->getDefiniteArticle(false), prevMonster->_name.c_str()); + appendText(buf); + } + } + } + if (!_commandWasQuick && getMonster() != NULL) { + performCombatAction(getMonster(), _world->_player); + } + + _inputText.clear(); + _gui->appendText(""); +} + + +} // End of namespace Wage diff --git a/engines/wage/wage.h b/engines/wage/wage.h new file mode 100644 index 0000000000..8ca306aea3 --- /dev/null +++ b/engines/wage/wage.h @@ -0,0 +1,239 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef WAGE_WAGE_H +#define WAGE_WAGE_H + +#include "engines/engine.h" +#include "common/debug.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 { + +class Console; +class Chr; +class Designed; +class Dialog; +class Gui; +class Obj; +class Scene; +class World; + +typedef Common::Array<Obj *> ObjArray; +typedef Common::Array<Chr *> ChrArray; +typedef Common::List<Obj *> ObjList; +typedef Common::List<Chr *> ChrList; + +enum OperandType { + OBJ = 0, + CHR = 1, + SCENE = 2, + NUMBER = 3, + STRING = 4, + CLICK_INPUT = 5, + TEXT_INPUT = 6, + UNKNOWN = 100 +}; + +enum Directions { + NORTH = 0, + SOUTH = 1, + EAST = 2, + WEST = 3 +}; + +// our engine debug levels +enum { + kWageDebugExample = 1 << 0, + kWageDebugExample2 = 1 << 1 + // next new level must be 1 << 2 (4) + // the current limitation is 32 debug levels (1 << 31 is the last one) +}; + +enum { + kColorBlack = 0, + kColorGray = 1, + kColorWhite = 2, + kColorGreen = 3 +}; + +Common::String readPascalString(Common::SeekableReadStream *in); +Common::Rect *readRect(Common::SeekableReadStream *in); +const char *getIndefiniteArticle(const Common::String &word); +const char *prependGenderSpecificPronoun(int gender); +const char *getGenderSpecificPronoun(int gender, bool capitalize); + + +typedef Common::Array<byte *> Patterns; + +class WageEngine : public Engine { + friend class Dialog; +public: + WageEngine(OSystem *syst, const ADGameDescription *gameDesc); + ~WageEngine(); + + virtual bool hasFeature(EngineFeature f) const; + + virtual Common::Error run(); + + bool canLoadGameStateCurrently(); + bool canSaveGameStateCurrently(); + + const char *getGameFile() const; + void processTurn(Common::String *textInput, Designed *clickInput); + void regen(); + +private: + bool loadWorld(Common::MacResManager *resMan); + void performInitialSetup(); + void wearObjs(Chr *chr); + void processTurnInternal(Common::String *textInput, Designed *clickInput); + void performCombatAction(Chr *npc, Chr *player); + int getValidMoveDirections(Chr *npc); + void performAttack(Chr *attacker, Chr *victim, Obj *weapon); + void performMagic(Chr *attacker, Chr *victim, Obj *magicalObject); + void performMove(Chr *chr, int validMoves); + void performOffer(Chr *attacker, Chr *victim); + void performTake(Chr *npc, Obj *obj); + void decrementUses(Obj *obj); + bool attackHit(Chr *attacker, Chr *victim, Obj *weapon, int targetIndex); + void performHealingMagic(Chr *chr, Obj *magicalObject); + + void doClose(); + void updateSoundTimerForScene(Scene *scene, bool firstTime); + +public: + void takeObj(Obj *obj); + + bool handleMoveCommand(Directions dir, const char *dirName); + bool handleLookCommand(); + Common::String *getGroundItemsList(Scene *scene); + void appendObjNames(Common::String &str, const ObjArray &objs); + bool handleInventoryCommand(); + bool handleStatusCommand(); + bool handleRestCommand(); + bool handleAcceptCommand(); + + bool handleTakeCommand(const char *target); + bool handleDropCommand(const char *target); + bool handleAimCommand(const char *target); + bool handleWearCommand(const char *target); + bool handleOfferCommand(const char *target); + + void wearObj(Obj *o, int pos); + + bool tryAttack(const Obj *weapon, const Common::String &input); + bool handleAttack(Obj *weapon); + + void printPlayerCondition(Chr *player); + const char *getPercentMessage(double percent); + +public: + Common::RandomSource *_rnd; + + Debugger *_debugger; + + Gui *_gui; + World *_world; + + Scene *_lastScene; + int _loopCount; + int _turn; + Chr *_monster; + Chr *_running; + Obj *_offer; + int _aim; + int _opponentAim; + bool _temporarilyHidden; + bool _isGameOver; + bool _commandWasQuick; + + Common::String _inputText; + + void playSound(Common::String soundName); + void setMenu(Common::String soundName); + void appendText(const char *str); + void gameOver(); + bool saveDialog(); + Obj *getOffer(); + Chr *getMonster(); + void processEvents(); + Scene *getSceneByName(Common::String &location); + void onMove(Designed *what, Designed *from, Designed *to); + void encounter(Chr *player, Chr *chr); + void redrawScene(); + void saveGame(); + + virtual GUI::Debugger *getDebugger() { return _debugger; } + +private: + Console *_console; + + const ADGameDescription *_gameDescription; + + Common::MacResManager *_resManager; + + bool _shouldQuit; +}; + +// Example console class +class Console : public GUI::Debugger { +public: + Console(WageEngine *vm) {} + virtual ~Console(void) {} +}; + +} // End of namespace Wage + +#endif diff --git a/engines/wage/world.cpp b/engines/wage/world.cpp new file mode 100644 index 0000000000..40b1555e35 --- /dev/null +++ b/engines/wage/world.cpp @@ -0,0 +1,523 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "common/file.h" + +#include "wage/wage.h" +#include "wage/entities.h" +#include "wage/script.h" +#include "wage/sound.h" +#include "wage/world.h" + +namespace Wage { + +World::World(WageEngine *engine) { + _storageScene = new Scene; + _storageScene->_name = STORAGESCENE; + + _orderedScenes.push_back(_storageScene); + _scenes[STORAGESCENE] = _storageScene; + + _gameOverMessage = nullptr; + _saveBeforeQuitMessage = nullptr; + _saveBeforeCloseMessage = nullptr; + _revertMessage = nullptr; + + _globalScript = nullptr; + _player = nullptr; + + _weaponMenuDisabled = true; + + _engine = engine; +} + +World::~World() { + for (uint i = 0; i < _orderedObjs.size(); i++) + delete _orderedObjs[i]; + + for (uint i = 0; i < _orderedChrs.size(); i++) + delete _orderedChrs[i]; + + for (uint i = 0; i < _orderedSounds.size(); i++) + delete _orderedSounds[i]; + + for (uint i = 0; i < _orderedScenes.size(); i++) + delete _orderedScenes[i]; + + for (uint i = 0; i < _patterns.size(); i++) + free(_patterns[i]); + + delete _globalScript; + + delete _gameOverMessage; + delete _saveBeforeQuitMessage; + delete _saveBeforeCloseMessage; + delete _revertMessage; + +} + +bool World::loadWorld(Common::MacResManager *resMan) { + Common::MacResIDArray resArray; + Common::SeekableReadStream *res; + Common::MacResIDArray::const_iterator iter; + + if ((resArray = resMan->getResIDArray(MKTAG('G','C','O','D'))).size() == 0) + return false; + + // Load global script + res = resMan->getResource(MKTAG('G','C','O','D'), resArray[0]); + _globalScript = new Script(res); + + // TODO: read creator + + // Load main configuration + if ((resArray = resMan->getResIDArray(MKTAG('V','E','R','S'))).size() == 0) + return false; + + _name = resMan->getBaseFileName(); + + if (resArray.size() > 1) + warning("Too many VERS resources"); + + if (!resArray.empty()) { + debug(3, "Loading version info"); + + res = resMan->getResource(MKTAG('V','E','R','S'), resArray[0]); + + res->skip(10); + byte b = res->readByte(); + _weaponMenuDisabled = (b != 0); + if (b != 0 && b != 1) + error("Unexpected value for weapons menu"); + + res->skip(3); + _aboutMessage = readPascalString(res); + + if (!scumm_stricmp(resMan->getBaseFileName().c_str(), "Scepters")) + res->skip(1); // ???? + + _soundLibrary1 = readPascalString(res); + _soundLibrary2 = readPascalString(res); + + delete res; + } + + Common::String *message; + if ((message = loadStringFromDITL(resMan, 2910, 1)) != NULL) { + message->trim(); + debug(2, "_gameOverMessage: %s", message->c_str()); + _gameOverMessage = message; + } + if ((message = loadStringFromDITL(resMan, 2480, 3)) != NULL) { + message->trim(); + debug(2, "_saveBeforeQuitMessage: %s", message->c_str()); + _saveBeforeQuitMessage = message; + } + if ((message = loadStringFromDITL(resMan, 2490, 3)) != NULL) { + message->trim(); + debug(2, "_saveBeforeCloseMessage: %s", message->c_str()); + _saveBeforeCloseMessage = message; + } + if ((message = loadStringFromDITL(resMan, 2940, 2)) != NULL) { + message->trim(); + debug(2, "_revertMessage: %s", message->c_str()); + _revertMessage = message; + } + + // Load scenes + resArray = resMan->getResIDArray(MKTAG('A','S','C','N')); + debug(3, "Loading %d scenes", resArray.size()); + + for (iter = resArray.begin(); iter != resArray.end(); ++iter) { + res = resMan->getResource(MKTAG('A','S','C','N'), *iter); + Scene *scene = new Scene(resMan->getResName(MKTAG('A','S','C','N'), *iter), res); + + res = resMan->getResource(MKTAG('A','C','O','D'), *iter); + if (res != NULL) + scene->_script = new Script(res); + + res = resMan->getResource(MKTAG('A','T','X','T'), *iter); + if (res != NULL) { + scene->_textBounds = readRect(res); + scene->_fontType = res->readUint16BE(); + scene->_fontSize = res->readUint16BE(); + + Common::String text; + while (res->pos() < res->size()) { + char c = res->readByte(); + if (c == 0x0d) + c = '\n'; + text += c; + } + scene->_text = text; + + delete res; + } + addScene(scene); + } + + // Load Objects + resArray = resMan->getResIDArray(MKTAG('A','O','B','J')); + debug(3, "Loading %d objects", resArray.size()); + + for (iter = resArray.begin(); iter != resArray.end(); ++iter) { + res = resMan->getResource(MKTAG('A','O','B','J'), *iter); + addObj(new Obj(resMan->getResName(MKTAG('A','O','B','J'), *iter), res)); + } + + // Load Characters + resArray = resMan->getResIDArray(MKTAG('A','C','H','R')); + debug(3, "Loading %d characters", resArray.size()); + + for (iter = resArray.begin(); iter != resArray.end(); ++iter) { + res = resMan->getResource(MKTAG('A','C','H','R'), *iter); + Chr *chr = new Chr(resMan->getResName(MKTAG('A','C','H','R'), *iter), res); + + addChr(chr); + // TODO: What if there's more than one player character? + if (chr->_playerCharacter) + _player = chr; + } + + // Load Sounds + resArray = resMan->getResIDArray(MKTAG('A','S','N','D')); + debug(3, "Loading %d sounds", resArray.size()); + + for (iter = resArray.begin(); iter != resArray.end(); ++iter) { + res = resMan->getResource(MKTAG('A','S','N','D'), *iter); + addSound(new Sound(resMan->getResName(MKTAG('A','S','N','D'), *iter), res)); + } + + if (!_soundLibrary1.empty()) { + loadExternalSounds(_soundLibrary1); + } + if (!_soundLibrary2.empty()) { + loadExternalSounds(_soundLibrary2); + } + + // Load Patterns + res = resMan->getResource(MKTAG('P','A','T','#'), 900); + if (res != NULL) { + int count = res->readUint16BE(); + debug(3, "Loading %d patterns", count); + + for (int i = 0; i < count; i++) { + byte *pattern = (byte *)malloc(8); + + res->read(pattern, 8); + _patterns.push_back(pattern); + } + + delete res; + } else { + /* Enchanted Scepters did not use the PAT# resource for the textures. */ + res = resMan->getResource(MKTAG('C','O','D','E'), 1); + if (res != NULL) { + res->skip(0x55ac); + for (int i = 0; i < 29; i++) { + byte *pattern = (byte *)malloc(8); + + res->read(pattern, 8); + _patterns.push_back(pattern); + } + } + delete res; + } + + res = resMan->getResource(MKTAG('M','E','N','U'), 2001); + if (res != NULL) { + Common::StringArray *menu = readMenu(res); + _aboutMenuItemName.clear(); + Common::String string = menu->operator[](1); + + for (uint i = 0; i < string.size() && string[i] != ';'; i++) // Read token + _aboutMenuItemName += string[i]; + + delete menu; + delete res; + } + res = resMan->getResource(MKTAG('M','E','N','U'), 2004); + if (res != NULL) { + Common::StringArray *menu = readMenu(res); + _commandsMenuName = menu->operator[](0); + _commandsMenu = menu->operator[](1); + delete menu; + delete res; + } + res = resMan->getResource(MKTAG('M','E','N','U'), 2005); + if (res != NULL) { + Common::StringArray *menu = readMenu(res); + _weaponsMenuName = menu->operator[](0); + delete menu; + delete res; + } + // TODO: Read Apple menu and get the name of that menu item.. + + // store global info in state object for use with save/load actions + //world.setCurrentState(initialState); // pass off the state object to the world + + return true; +} + +void World::addSound(Sound *sound) { + Common::String s = sound->_name; + s.toLowercase(); + _sounds[s] = sound; + _orderedSounds.push_back(sound); +} + +Common::StringArray *World::readMenu(Common::SeekableReadStream *res) { + res->skip(10); + int enableFlags = res->readUint32BE(); + Common::String menuName = readPascalString(res); + Common::String menuItem = readPascalString(res); + int menuItemNumber = 1; + Common::String menu; + byte itemData[4]; + + while (!menuItem.empty()) { + if (!menu.empty()) { + menu += ';'; + } + if ((enableFlags & (1 << menuItemNumber)) == 0) { + menu += '('; + } + menu += menuItem; + res->read(itemData, 4); + static const char styles[] = {'B', 'I', 'U', 'O', 'S', 'C', 'E', 0}; + for (int i = 0; styles[i] != 0; i++) { + if ((itemData[3] & (1 << i)) != 0) { + menu += '<'; + menu += styles[i]; + } + } + if (itemData[1] != 0) { + menu += '/'; + menu += (char)itemData[1]; + } + menuItem = readPascalString(res); + menuItemNumber++; + } + + Common::StringArray *result = new Common::StringArray; + result->push_back(menuName); + result->push_back(menu); + + debug(4, "menuName: %s", menuName.c_str()); + debug(4, "menu: %s", menu.c_str()); + + return result; +} + +void World::loadExternalSounds(Common::String fname) { + Common::File in; + + in.open(fname); + if (!in.isOpen()) { + warning("Cannot load sound file <%s>", fname.c_str()); + return; + } + in.close(); + + Common::MacResManager resMan; + resMan.open(fname); + + Common::MacResIDArray resArray; + Common::SeekableReadStream *res; + Common::MacResIDArray::const_iterator iter; + + resArray = resMan.getResIDArray(MKTAG('A','S','N','D')); + for (iter = resArray.begin(); iter != resArray.end(); ++iter) { + res = resMan.getResource(MKTAG('A','S','N','D'), *iter); + addSound(new Sound(resMan.getResName(MKTAG('A','S','N','D'), *iter), res)); + } +} + +Common::String *World::loadStringFromDITL(Common::MacResManager *resMan, int resourceId, int itemIndex) { + Common::SeekableReadStream *res = resMan->getResource(MKTAG('D','I','T','L'), resourceId); + if (res) { + int itemCount = res->readSint16BE(); + for (int i = 0; i <= itemCount; i++) { + // int placeholder; short rect[4]; byte flags; pstring str; + res->skip(13); + Common::String message = readPascalString(res); + if (i == itemIndex) { + Common::String *msg = new Common::String(message); + delete res; + return msg; + } + } + + delete res; + } + + return NULL; +} + +static bool invComparator(const Obj *l, const Obj *r) { + return l->_index < r->_index; +} + +void World::move(Obj *obj, Chr *chr) { + if (obj == NULL) + return; + + Designed *from = obj->removeFromCharOrScene(); + obj->_currentOwner = chr; + chr->_inventory.push_back(obj); + + Common::sort(chr->_inventory.begin(), chr->_inventory.end(), invComparator); + + _engine->onMove(obj, from, chr); +} + +static bool objComparator(const Obj *o1, const Obj *o2) { + bool o1Immobile = (o1->_type == Obj::IMMOBILE_OBJECT); + bool o2Immobile = (o2->_type == Obj::IMMOBILE_OBJECT); + if (o1Immobile == o2Immobile) { + return o1->_index - o2->_index; + } + return o1Immobile; +} + +void World::move(Obj *obj, Scene *scene, bool skipSort) { + if (obj == NULL) + return; + + Designed *from = obj->removeFromCharOrScene(); + obj->_currentScene = scene; + scene->_objs.push_back(obj); + + if (!skipSort) + Common::sort(scene->_objs.begin(), scene->_objs.end(), objComparator); + + _engine->onMove(obj, from, scene); +} + +static bool chrComparator(const Chr *l, const Chr *r) { + return l->_index < r->_index; +} + +void World::move(Chr *chr, Scene *scene, bool skipSort) { + if (chr == NULL) + return; + Scene *from = chr->_currentScene; + if (from == scene) + return; + if (from != NULL) + from->_chrs.remove(chr); + scene->_chrs.push_back(chr); + + if (!skipSort) + Common::sort(scene->_chrs.begin(), scene->_chrs.end(), chrComparator); + + if (scene == _storageScene) { + chr->resetState(); + } else if (chr->_playerCharacter) { + scene->_visited = true; + _player->_context._visits++; + } + chr->_currentScene = scene; + + _engine->onMove(chr, from, scene); +} + +Scene *World::getRandomScene() { + // Not including storage: + return _orderedScenes[1 + _engine->_rnd->getRandomNumber(_orderedScenes.size() - 2)]; +} + +Scene *World::getSceneAt(int x, int y) { + for (uint i = 0; i < _orderedScenes.size(); i++) { + Scene *scene = _orderedScenes[i]; + + if (scene != _storageScene && scene->_worldX == x && scene->_worldY == y) { + return scene; + } + } + return NULL; +} + +static const int directionsX[] = { 0, 0, 1, -1 }; +static const int directionsY[] = { -1, 1, 0, 0 }; + +bool World::scenesAreConnected(Scene *scene1, Scene *scene2) { + if (!scene1 || !scene2) + return false; + + int x = scene2->_worldX; + int y = scene2->_worldY; + + for (int dir = 0; dir < 4; dir++) + if (!scene2->_blocked[dir]) + if (getSceneAt(x + directionsX[dir], y + directionsY[dir]) == scene1) + return true; + + return false; +} + +const char *World::getAboutMenuItemName() { + static char menu[256]; + + *menu = '\0'; + + if (_aboutMenuItemName.empty()) { + sprintf(menu, "About %s...", _name.c_str()); + } else { // Replace '@' with name + const char *str = _aboutMenuItemName.c_str(); + const char *pos = strchr(str, '@'); + if (pos) { + strncat(menu, str, (pos - str)); + strncat(menu, _name.c_str(), 255); + strncat(menu, pos + 1, 255); + } + } + + return menu; +} + +} // End of namespace Wage diff --git a/engines/wage/world.h b/engines/wage/world.h new file mode 100644 index 0000000000..e9041139df --- /dev/null +++ b/engines/wage/world.h @@ -0,0 +1,138 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef WAGE_WORLD_H +#define WAGE_WORLD_H + +namespace Wage { + +#define STORAGESCENE "STORAGE@" + +class Sound; + +class World { +public: + World(WageEngine *engine); + ~World(); + + bool loadWorld(Common::MacResManager *resMan); + void loadExternalSounds(Common::String fname); + Common::String *loadStringFromDITL(Common::MacResManager *resMan, int resourceId, int itemIndex); + void move(Obj *obj, Chr *chr); + void move(Obj *obj, Scene *scene, bool skipSort = false); + void move(Chr *chr, Scene *scene, bool skipSort = false); + Scene *getRandomScene(); + Scene *getSceneAt(int x, int y); + bool scenesAreConnected(Scene *scene1, Scene *scene2); + const char *getAboutMenuItemName(); + + WageEngine *_engine; + + Common::String _name; + Common::String _aboutMessage; + Common::String _soundLibrary1; + Common::String _soundLibrary2; + + bool _weaponMenuDisabled; + Script *_globalScript; + Common::HashMap<Common::String, Scene *> _scenes; + Common::HashMap<Common::String, Obj *> _objs; + Common::HashMap<Common::String, Chr *> _chrs; + Common::HashMap<Common::String, Sound *> _sounds; + Common::Array<Scene *> _orderedScenes; + ObjArray _orderedObjs; + ChrArray _orderedChrs; + Common::Array<Sound *> _orderedSounds; + Patterns _patterns; + Scene *_storageScene; + Chr *_player; + //List<MoveListener> moveListeners; + + Common::String *_gameOverMessage; + Common::String *_saveBeforeQuitMessage; + Common::String *_saveBeforeCloseMessage; + Common::String *_revertMessage; + + Common::String _aboutMenuItemName; + Common::String _commandsMenuName; + Common::String _commandsMenu; + Common::String _weaponsMenuName; + + void addScene(Scene *room) { + if (!room->_name.empty()) { + Common::String s = room->_name; + s.toLowercase(); + _scenes[s] = room; + } + _orderedScenes.push_back(room); + } + + void addObj(Obj *obj) { + Common::String s = obj->_name; + s.toLowercase(); + _objs[s] = obj; + obj->_index = _orderedObjs.size(); + _orderedObjs.push_back(obj); + } + + void addChr(Chr *chr) { + Common::String s = chr->_name; + s.toLowercase(); + _chrs[s] = chr; + chr->_index = _orderedChrs.size(); + _orderedChrs.push_back(chr); + } + + void addSound(Sound *sound); + +private: + Common::StringArray *readMenu(Common::SeekableReadStream *res); +}; + +} // End of namespace Wage + +#endif diff --git a/engines/wintermute/ad/ad_actor.cpp b/engines/wintermute/ad/ad_actor.cpp index 9d5a35464a..4661d3bca0 100644 --- a/engines/wintermute/ad/ad_actor.cpp +++ b/engines/wintermute/ad/ad_actor.cpp @@ -958,13 +958,13 @@ bool AdActor::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, stack->correctParams(1); ScValue *val = stack->pop(); if (!val->isNative()) { - script->runtimeError("actor.%s method accepts an entity refrence only", name); + script->runtimeError("actor.%s method accepts an entity reference only", name); stack->pushNULL(); return STATUS_OK; } AdObject *obj = (AdObject *)val->getNative(); if (!obj || obj->getType() != OBJECT_ENTITY) { - script->runtimeError("actor.%s method accepts an entity refrence only", name); + script->runtimeError("actor.%s method accepts an entity reference only", name); stack->pushNULL(); return STATUS_OK; } diff --git a/engines/wintermute/base/base_engine.h b/engines/wintermute/base/base_engine.h index 0f4a6b0775..cbf5d92d00 100644 --- a/engines/wintermute/base/base_engine.h +++ b/engines/wintermute/base/base_engine.h @@ -74,7 +74,7 @@ public: static const Timer *getTimer(); static const Timer *getLiveTimer(); static void LOG(bool res, const char *fmt, ...); - const char *getGameTargetName() const { return _targetName.c_str(); } + Common::String getGameTargetName() const { return _targetName; } Common::String getGameId() const { return _gameId; } Common::Language getLanguage() const { return _language; } WMETargetExecutable getTargetExecutable() const { diff --git a/engines/wintermute/base/base_persistence_manager.cpp b/engines/wintermute/base/base_persistence_manager.cpp index bb5e0c4091..39462f7a15 100644 --- a/engines/wintermute/base/base_persistence_manager.cpp +++ b/engines/wintermute/base/base_persistence_manager.cpp @@ -56,7 +56,7 @@ namespace Wintermute { #define SAVE_MAGIC_3 0x12564154 ////////////////////////////////////////////////////////////////////////// -BasePersistenceManager::BasePersistenceManager(const char *savePrefix, bool deleteSingleton) { +BasePersistenceManager::BasePersistenceManager(const Common::String &savePrefix, bool deleteSingleton) { _saving = false; _offset = 0; _saveStream = nullptr; @@ -91,7 +91,7 @@ BasePersistenceManager::BasePersistenceManager(const char *savePrefix, bool dele _thumbnailDataSize = 0; _thumbnailData = nullptr; - if (savePrefix) { + if (savePrefix != "") { _savePrefix = savePrefix; } else if (_gameRef) { _savePrefix = _gameRef->getGameTargetName(); @@ -215,8 +215,8 @@ bool BasePersistenceManager::getSaveExists(int slot) { } ////////////////////////////////////////////////////////////////////////// -bool BasePersistenceManager::initSave(const char *desc) { - if (!desc) { +bool BasePersistenceManager::initSave(const Common::String &desc) { + if (desc == "") { return STATUS_FAILED; } @@ -297,11 +297,11 @@ bool BasePersistenceManager::initSave(const char *desc) { uint32 dataOffset = _offset + sizeof(uint32) + // data offset - sizeof(uint32) + strlen(desc) + 1 + // description + sizeof(uint32) + strlen(desc.c_str()) + 1 + // description sizeof(uint32); // timestamp putDWORD(dataOffset); - putString(desc); + putString(desc.c_str()); g_system->getTimeAndDate(_savedTimestamp); putTimeDate(_savedTimestamp); diff --git a/engines/wintermute/base/base_persistence_manager.h b/engines/wintermute/base/base_persistence_manager.h index 373d1580de..760b45c907 100644 --- a/engines/wintermute/base/base_persistence_manager.h +++ b/engines/wintermute/base/base_persistence_manager.h @@ -63,7 +63,7 @@ public: uint32 getMaxUsedSlot(); bool getSaveExists(int slot); bool initLoad(const Common::String &filename); - bool initSave(const char *desc); + bool initSave(const Common::String &desc); bool getBytes(byte *buffer, uint32 size); bool putBytes(byte *buffer, uint32 size); uint32 _offset; @@ -86,7 +86,7 @@ public: bool transferCharPtr(const char *name, char **val); bool transferString(const char *name, Common::String *val); bool transferVector2(const char *name, Vector2 *val); - BasePersistenceManager(const char *savePrefix = nullptr, bool deleteSingleton = false); + BasePersistenceManager(const Common::String &savePrefix = "", bool deleteSingleton = false); virtual ~BasePersistenceManager(); bool checkVersion(byte verMajor, byte verMinor, byte verBuild); diff --git a/engines/wintermute/base/base_sub_frame.cpp b/engines/wintermute/base/base_sub_frame.cpp index 4388942064..6d0c48ff17 100644 --- a/engines/wintermute/base/base_sub_frame.cpp +++ b/engines/wintermute/base/base_sub_frame.cpp @@ -268,7 +268,7 @@ bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, fl Common::Point origin(x, y); Common::Point newOrigin; Rect32 oldRect1 = getRect(); - Common::Rect oldRect(oldRect1.top, oldRect1.left, oldRect1.bottom, oldRect1.right); + Common::Rect oldRect(oldRect1.left, oldRect1.top, oldRect1.right, oldRect1.bottom); Common::Point newHotspot; Graphics::TransformStruct transform = Graphics::TransformStruct(zoomX, zoomY, (uint32)rotate, _hotspotX, _hotspotY, blendMode, alpha, _mirrorX, _mirrorY, 0, 0); Rect32 newRect = Graphics::TransformTools::newRect(oldRect, transform, &newHotspot); diff --git a/engines/wintermute/base/file/base_disk_file.cpp b/engines/wintermute/base/file/base_disk_file.cpp index 82a9e24dfb..d0c51616f4 100644 --- a/engines/wintermute/base/file/base_disk_file.cpp +++ b/engines/wintermute/base/file/base_disk_file.cpp @@ -113,13 +113,28 @@ Common::SeekableReadStream *openDiskFile(const Common::String &filename) { Common::String fixedFilename = filename; correctSlashes(fixedFilename); - // Absolute path: TODO: Add specific fallbacks here. + // HACK: There are a few games around which mistakenly refer to absolute paths in the scripts. + // The original interpreter on Windows usually simply ignores them when it can't find them. + // We try to turn the known ones into relative paths. if (fixedFilename.contains(':')) { - if (fixedFilename.hasPrefix("c:/windows/fonts/")) { // East Side Story refers to "c:\windows\fonts\framd.ttf" - fixedFilename = filename.c_str() + 14; - } else if (fixedFilename.hasPrefix("c:/carol6/svn/data/")) { // Carol Reed 6: Black Circle refers to "c:\carol6\svn\data\sprites\system\help.png" - fixedFilename = fixedFilename.c_str() + 19; - } else { + const char* const knownPrefixes[] = { // Known absolute paths + "c:/windows/fonts/", // East Side Story refers to "c:\windows\fonts\framd.ttf" + "c:/carol6/svn/data/", // Carol Reed 6: Black Circle refers to "c:\carol6\svn\data\sprites\system\help.png" + "f:/dokument/spel 5/demo/data/" // Carol Reed 5 (non-demo) refers to "f:\dokument\spel 5\demo\data\scenes\credits\op_cred_00\op_cred_00.jpg" + }; + + bool matched = false; + + for (uint i = 0; i < ARRAYSIZE(knownPrefixes); i++) { + if (fixedFilename.hasPrefix(knownPrefixes[i])) { + fixedFilename = fixedFilename.c_str() + strlen(knownPrefixes[i]); + matched = true; + } + } + + if (!matched) { + // fixedFilename is unchanged and thus still broken, none of the above workarounds worked. + // We can only bail out error("openDiskFile::Absolute path or invalid filename used in %s", filename.c_str()); } } diff --git a/engines/wintermute/configure.engine b/engines/wintermute/configure.engine index bdaf49de3f..55385776de 100644 --- a/engines/wintermute/configure.engine +++ b/engines/wintermute/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine wintermute "Wintermute" yes "" "" "jpeg png zlib vorbis 16bit" +add_engine wintermute "Wintermute" yes "" "" "jpeg png zlib vorbis 16bit highres" diff --git a/engines/wintermute/detection.cpp b/engines/wintermute/detection.cpp index aca682ae99..f77eb5c64d 100644 --- a/engines/wintermute/detection.cpp +++ b/engines/wintermute/detection.cpp @@ -75,8 +75,8 @@ static const char *directoryGlobs[] = { class WintermuteMetaEngine : public AdvancedMetaEngine { public: WintermuteMetaEngine() : AdvancedMetaEngine(Wintermute::gameDescriptions, sizeof(WMEGameDescription), Wintermute::wintermuteGames, gameGuiOptions) { - _singleid = "wintermute"; - _guioptions = GUIO2(GUIO_NOMIDI, GAMEOPTION_SHOW_FPS); + _singleId = "wintermute"; + _guiOptions = GUIO2(GUIO_NOMIDI, GAMEOPTION_SHOW_FPS); _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } @@ -94,8 +94,8 @@ public: s_fallbackDesc.language = Common::UNK_LANG; s_fallbackDesc.flags = ADGF_UNSTABLE; s_fallbackDesc.platform = Common::kPlatformWindows; // default to Windows - s_fallbackDesc.gameid = "wintermute"; - s_fallbackDesc.guioptions = GUIO0(); + s_fallbackDesc.gameId = "wintermute"; + s_fallbackDesc.guiOptions = GUIO0(); if (allFiles.contains("data.dcp")) { Common::String name, caption; @@ -109,7 +109,7 @@ public: // Prefix to avoid collisions with actually known games name = "wmeunk-" + name; Common::strlcpy(s_fallbackGameIdBuf, name.c_str(), sizeof(s_fallbackGameIdBuf) - 1); - s_fallbackDesc.gameid = s_fallbackGameIdBuf; + s_fallbackDesc.gameId = s_fallbackGameIdBuf; if (caption != name) { caption += " (unknown version) "; char *offset = s_fallbackGameIdBuf + name.size() + 1; diff --git a/engines/wintermute/detection_tables.h b/engines/wintermute/detection_tables.h index 25a01766e4..ca30204462 100644 --- a/engines/wintermute/detection_tables.h +++ b/engines/wintermute/detection_tables.h @@ -181,10 +181,13 @@ static const WMEGameDescription gameDescriptions[] = { WME_ENTRY1s("data.dcp", "b3f8b09bb4b05ee3e9d14697525257f9", 59296246), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Carol Reed 4 - East Side Story WME_WINENTRY("carolreed4", "", - WME_ENTRY1s("data.dcp", "b26377797f060afc2d440d820100c1ce", 529320536), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), + WME_ENTRY1s("data.dcp", "b26377797f060afc2d440d820100c1ce", 529320536), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Carol Reed 5 - The Colour of Murder WME_WINENTRY("carolreed5", "", WME_ENTRY1s("data.dcp", "3fcfca44209545d0e26774156427b494", 603660415), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), + // Carol Reed 5 - The Colour of Murder (1.0 Demo) + WME_WINENTRY("carolreed5", "Demo", + WME_ENTRY1s("data.dcp", "27b3efc018ade5ee8f4adf08b4e3c0dd", 92019500), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Carol Reed 6 - Black Circle WME_WINENTRY("carolreed6", "", WME_ENTRY1s("data.dcp", "0e4c532beecf23d85012168753f41189", 456258147), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp index e35bb60c3d..955f2dc1c2 100644 --- a/engines/wintermute/wintermute.cpp +++ b/engines/wintermute/wintermute.cpp @@ -133,7 +133,7 @@ Common::Error WintermuteEngine::run() { } int WintermuteEngine::init() { - BaseEngine::createInstance(_targetName, _gameDescription->adDesc.gameid, _gameDescription->adDesc.language, _gameDescription->targetExecutable); + BaseEngine::createInstance(_targetName, _gameDescription->adDesc.gameId, _gameDescription->adDesc.language, _gameDescription->targetExecutable); _game = new AdGame(_targetName); if (!_game) { return 1; diff --git a/engines/zvision/configure.engine b/engines/zvision/configure.engine index 226870c3fd..8681522a35 100644 --- a/engines/zvision/configure.engine +++ b/engines/zvision/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine zvision "Z-Vision" yes "" "" "freetype2 16bit" +add_engine zvision "Z-Vision" yes "" "" "freetype2 16bit highres" diff --git a/engines/zvision/detection.cpp b/engines/zvision/detection.cpp index 5fdf17cd2b..cc967070d9 100644 --- a/engines/zvision/detection.cpp +++ b/engines/zvision/detection.cpp @@ -61,7 +61,7 @@ public: ZVisionMetaEngine() : AdvancedMetaEngine(ZVision::gameDescriptions, sizeof(ZVision::ZVisionGameDescription), ZVision::zVisionGames, ZVision::optionsList) { _maxScanDepth = 2; _directoryGlobs = ZVision::directoryGlobs; - _singleid = "zvision"; + _singleId = "zvision"; } virtual const char *getName() const { @@ -132,7 +132,6 @@ SaveStateList ZVisionMetaEngine::listSaves(const char *target) const { Common::StringArray filenames; filenames = saveFileMan->listSavefiles(pattern.c_str()); - Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)*/ SaveStateList saveList; // We only use readSaveGameHeader() here, which doesn't need an engine callback @@ -155,6 +154,8 @@ SaveStateList ZVisionMetaEngine::listSaves(const char *target) const { delete zvisionSaveMan; + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); return saveList; } @@ -164,26 +165,7 @@ int ZVisionMetaEngine::getMaximumSaveSlot() const { void ZVisionMetaEngine::removeSaveState(const char *target, int slot) const { Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); - Common::String filename = Common::String::format("%s.%03u", target, slot); - - saveFileMan->removeSavefile(filename.c_str()); - - Common::StringArray filenames; - Common::String pattern = target; - pattern += ".###"; - filenames = saveFileMan->listSavefiles(pattern.c_str()); - Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) - - for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { - // Obtain the last 3 digits of the filename, since they correspond to the save slot - int slotNum = atoi(file->c_str() + file->size() - 3); - - // Rename every slot greater than the deleted slot, - if (slotNum > slot) { - saveFileMan->renameSavefile(file->c_str(), filename.c_str()); - filename = Common::String::format("%s.%03u", target, ++slot); - } - } + saveFileMan->removeSavefile(Common::String::format("%s.%03u", target, slot)); } SaveStateDescriptor ZVisionMetaEngine::querySaveMetaInfos(const char *target, int slot) const { diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp index 81a0c04441..26f0ced625 100644 --- a/graphics/VectorRendererSpec.cpp +++ b/graphics/VectorRendererSpec.cpp @@ -441,13 +441,14 @@ template<typename PixelType> void VectorRendererSpec<PixelType>:: gradientFill(PixelType *ptr, int width, int x, int y) { bool ox = ((y & 1) == 1); - int stripSize; int curGrad = 0; while (_gradIndexes[curGrad + 1] <= y) curGrad++; - stripSize = _gradIndexes[curGrad + 1] - _gradIndexes[curGrad]; + // precalcGradient assures that _gradIndexes entries always differ in + // their value. This assures stripSize is always different from zero. + int stripSize = _gradIndexes[curGrad + 1] - _gradIndexes[curGrad]; int grad = (((y - _gradIndexes[curGrad]) % stripSize) << 2) / stripSize; @@ -773,8 +774,8 @@ drawLine(int x1, int y1, int x2, int y2) { SWAP(y1, y2); } - int dx = ABS(x2 - x1); - int dy = ABS(y2 - y1); + uint dx = ABS(x2 - x1); + uint dy = ABS(y2 - y1); // this is a point, not a line. stoopid. if (dy == 0 && dx == 0) @@ -803,7 +804,7 @@ drawLine(int x1, int y1, int x2, int y2) { ptr += pitch; } - } else if (ABS(dx) == ABS(dy)) { // diagonal lines + } else if (dx == dy) { // diagonal lines // these ones also use a fixed pitch increase pitch += (x2 > x1) ? 1 : -1; @@ -1034,6 +1035,11 @@ drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) { template<typename PixelType> void VectorRendererSpec<PixelType>:: drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer::FillMode fill_m, int baseLeft, int baseRight) { + // Don't draw anything for empty rects. + if (w <= 0 || h <= 0) { + return; + } + int f, ddF_x, ddF_y; int x, y, px, py; int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; @@ -1238,6 +1244,11 @@ drawBevelTabAlg(int x, int y, int w, int h, int bevel, PixelType top_color, Pixe template<typename PixelType> void VectorRendererSpec<PixelType>:: drawSquareAlg(int x, int y, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { + // Do not draw anything for empty rects. + if (w <= 0 || h <= 0) { + return; + } + PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x, y); int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; int max_h = h; @@ -1326,7 +1337,7 @@ drawBevelSquareAlg(int x, int y, int w, int h, int bevel, PixelType top_color, P /** GENERIC LINE ALGORITHM **/ template<typename PixelType> void VectorRendererSpec<PixelType>:: -drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { +drawLineAlg(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) { PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1); int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; int xdir = (x2 > x1) ? 1 : -1; @@ -1393,6 +1404,12 @@ drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { template<typename PixelType> void VectorRendererSpec<PixelType>:: drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) { + // Don't draw anything for empty rects. This assures dy is always different + // from zero. + if (w <= 0 || h <= 0) { + return; + } + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; int gradient_h = 0; if (!inverted) { @@ -1422,6 +1439,9 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color blendPixelPtr(floor, color, 50); #if FIXED_POINT + // In this branch dx is always different from zero. This is because + // abs(dx) is strictly greater than abs(dy), and abs returns zero + // as minimal value. int gradient = (dy << 8) / dx; int intery = (y1 << 8) + gradient; #else @@ -1564,6 +1584,11 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color template<typename PixelType> void VectorRendererSpec<PixelType>:: drawTriangleFast(int x1, int y1, int size, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) { + // Do not draw anything for empty rects. + if (size <= 0) { + return; + } + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; if (!inverted) { @@ -1685,6 +1710,11 @@ drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, template<typename PixelType> void VectorRendererSpec<PixelType>:: drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { + // Do not draw empty space rounded squares. + if (w <= 0 || h <= 0) { + return; + } + int f, ddF_x, ddF_y; int x, y, px, py; int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; @@ -1835,6 +1865,11 @@ drawCircleAlg(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode f template<typename PixelType> void VectorRendererSpec<PixelType>:: drawSquareShadow(int x, int y, int w, int h, int offset) { + // Do nothing for empty rects or no shadow offset. + if (w <= 0 || h <= 0 || offset <= 0) { + return; + } + PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x + w - 1, y + offset); int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; int i, j; @@ -1956,8 +1991,7 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) { /** LINES **/ template<typename PixelType> void VectorRendererAA<PixelType>:: -drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { - +drawLineAlg(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) { PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel; int xdir = (x2 > x1) ? 1 : -1; @@ -1967,7 +2001,7 @@ drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { *ptr = (PixelType)color; if (dx > dy) { - gradient = (uint32)(dy << 16) / (uint32)dx; + gradient = (dy << 16) / dx; error_acc = 0; while (--dx) { @@ -1983,8 +2017,8 @@ drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { this->blendPixelPtr(ptr, color, ~alpha); this->blendPixelPtr(ptr + pitch, color, alpha); } - } else { - gradient = (uint32)(dx << 16) / (uint32)dy; + } else if (dy != 0) { + gradient = (dx << 16) / dy; error_acc = 0; while (--dy) { @@ -2009,6 +2043,11 @@ drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { template<typename PixelType> void VectorRendererAA<PixelType>:: drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer::FillMode fill_m, int baseLeft, int baseRight) { + // Don't draw anything for empty rects. + if (w <= 0 || h <= 0) { + return; + } + int x, y, px, py; int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel; int sw = 0, sp = 0, hp = 0; @@ -2217,6 +2256,11 @@ drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, template<typename PixelType> void VectorRendererAA<PixelType>:: drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { + // Do not draw empty space rounded squares. + if (w <= 0 || h <= 0) { + return; + } + int x, y; const int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel; int px, py; diff --git a/graphics/VectorRendererSpec.h b/graphics/VectorRendererSpec.h index f47cc3997a..3e54608b8e 100644 --- a/graphics/VectorRendererSpec.h +++ b/graphics/VectorRendererSpec.h @@ -150,7 +150,7 @@ protected: * @see VectorRendererAA::drawCircleAlg */ virtual void drawLineAlg(int x1, int y1, int x2, int y2, - int dx, int dy, PixelType color); + uint dx, uint dy, PixelType color); virtual void drawCircleAlg(int x, int y, int r, PixelType color, FillMode fill_m); @@ -278,7 +278,7 @@ protected: * * @see VectorRenderer::drawLineAlg() */ - virtual void drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color); + virtual void drawLineAlg(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color); /** * "Wu's Circle Antialiasing Algorithm" as published by Xiaolin Wu, July 1991 diff --git a/graphics/font.cpp b/graphics/font.cpp index dba48249bc..d709758948 100644 --- a/graphics/font.cpp +++ b/graphics/font.cpp @@ -21,6 +21,7 @@ */ #include "graphics/font.h" +#include "graphics/managed_surface.h" #include "common/array.h" #include "common/util.h" @@ -273,6 +274,16 @@ void Font::drawString(Surface *dst, const Common::U32String &str, int x, int y, drawStringImpl(*this, dst, str, x, y, w, color, align, 0); } +void Font::drawString(ManagedSurface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const { + drawString(&dst->_innerSurface, str, x, y, w, color, align, deltax, useEllipsis); + dst->addDirtyRect(Common::Rect(x, y, x + w, y + getFontHeight())); +} + +void Font::drawString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align) const { + drawString(&dst->_innerSurface, str, x, y, w, color, align); + dst->addDirtyRect(Common::Rect(x, y, x + w, y + getFontHeight())); +} + int Font::wordWrapText(const Common::String &str, int maxWidth, Common::Array<Common::String> &lines) const { return wordWrapTextImpl(*this, str, maxWidth, lines); } diff --git a/graphics/font.h b/graphics/font.h index 35f6792d7f..62e71a8568 100644 --- a/graphics/font.h +++ b/graphics/font.h @@ -34,6 +34,7 @@ template<class T> class Array; namespace Graphics { struct Surface; +class ManagedSurface; /** Text alignment modes */ enum TextAlign { @@ -145,6 +146,8 @@ public: // TODO: Add doxygen comments to this void drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const; void drawString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft) const; + void drawString(ManagedSurface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const; + void drawString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft) const; /** * Compute and return the width the string str has when rendered using this font. diff --git a/graphics/managed_surface.cpp b/graphics/managed_surface.cpp new file mode 100644 index 0000000000..e493ab9f4e --- /dev/null +++ b/graphics/managed_surface.cpp @@ -0,0 +1,260 @@ +/* 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 "graphics/managed_surface.h" +#include "common/algorithm.h" +#include "common/textconsole.h" + +namespace Graphics { + +const int SCALE_THRESHOLD = 0x100; + +ManagedSurface::ManagedSurface() : + w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format), + _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) { +} + +ManagedSurface::ManagedSurface(const ManagedSurface &surf) : + w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format), + _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) { + *this = surf; +} + +ManagedSurface::ManagedSurface(int width, int height) : + w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format), + _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) { + create(width, height); +} + +ManagedSurface::ManagedSurface(int width, int height, const Graphics::PixelFormat &pixelFormat) : + w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format), + _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) { + create(width, height, format); +} + +ManagedSurface::ManagedSurface(ManagedSurface &surf, const Common::Rect &bounds) : + w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format), + _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) { + create(surf, bounds); +} + +ManagedSurface::~ManagedSurface() { + free(); +} + +ManagedSurface &ManagedSurface::operator=(const ManagedSurface &surf) { + // Free any current surface + free(); + + if (surf._disposeAfterUse == DisposeAfterUse::YES) { + // Create a new surface and copy the pixels from the source surface + create(surf.w, surf.h, surf.format); + Common::copy((const byte *)surf.getPixels(), (const byte *)surf.getPixels() + + surf.w * surf.h * surf.format.bytesPerPixel, (byte *)this->getPixels()); + } else { + // Source isn't managed, so simply copy its fields + _owner = surf._owner; + _offsetFromOwner = surf._offsetFromOwner; + void *srcPixels = (void *)surf._innerSurface.getPixels(); + _innerSurface.setPixels(srcPixels); + _innerSurface.w = surf.w; + _innerSurface.h = surf.h; + _innerSurface.pitch = surf.pitch; + this->format = surf.format; + } + + return *this; +} + +void ManagedSurface::setPixels(void *newPixels) { + free(); + _innerSurface.setPixels(newPixels); +} + +void ManagedSurface::create(uint16 width, uint16 height) { + create(width, height, PixelFormat::createFormatCLUT8()); +} + +void ManagedSurface::create(uint16 width, uint16 height, const PixelFormat &pixelFormat) { + free(); + _innerSurface.create(width, height, pixelFormat); + + _disposeAfterUse = DisposeAfterUse::YES; + markAllDirty(); +} + +void ManagedSurface::create(ManagedSurface &surf, const Common::Rect &bounds) { + free(); + + _offsetFromOwner = Common::Point(bounds.left, bounds.top); + _innerSurface.setPixels(surf.getBasePtr(bounds.left, bounds.top)); + _innerSurface.pitch = surf.pitch; + _innerSurface.format = surf.format; + _innerSurface.w = bounds.width(); + _innerSurface.h = bounds.height(); + _owner = &surf; + _disposeAfterUse = DisposeAfterUse::NO; +} + +void ManagedSurface::free() { + if (_disposeAfterUse == DisposeAfterUse::YES) + _innerSurface.free(); + + _disposeAfterUse = DisposeAfterUse::NO; + _owner = nullptr; + _offsetFromOwner = Common::Point(0, 0); +} + +bool ManagedSurface::clip(Common::Rect &srcBounds, Common::Rect &destBounds) { + if (destBounds.left >= this->w || destBounds.top >= this->h || + destBounds.right <= 0 || destBounds.bottom <= 0) + return false; + + // Clip the bounds if necessary to fit on-screen + if (destBounds.right > this->w) { + srcBounds.right -= destBounds.right - this->w; + destBounds.right = this->w; + } + + if (destBounds.bottom > this->h) { + srcBounds.bottom -= destBounds.bottom - this->h; + destBounds.bottom = this->h; + } + + if (destBounds.top < 0) { + srcBounds.top += -destBounds.top; + destBounds.top = 0; + } + + if (destBounds.left < 0) { + srcBounds.left += -destBounds.left; + destBounds.left = 0; + } + + return true; +} + +void ManagedSurface::blitFrom(const Surface &src) { + blitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Point(0, 0)); +} + +void ManagedSurface::blitFrom(const Surface &src, const Common::Point &destPos) { + blitFrom(src, Common::Rect(0, 0, src.w, src.h), destPos); +} + +void ManagedSurface::blitFrom(const Surface &src, const Common::Rect &srcRect, + const Common::Point &destPos) { + Common::Rect srcBounds = srcRect; + Common::Rect destBounds(destPos.x, destPos.y, destPos.x + srcRect.width(), + destPos.y + srcRect.height()); + assert(src.format.bytesPerPixel == format.bytesPerPixel); + + if (!srcRect.isValidRect() || !clip(srcBounds, destBounds)) + return; + + for (int y = 0; y < srcBounds.height(); ++y) { + const byte *srcP = (const byte *)src.getBasePtr(srcBounds.left, srcBounds.top + y); + byte *destP = (byte *)getBasePtr(destBounds.left, destBounds.top + y); + Common::copy(srcP, srcP + srcBounds.width() * format.bytesPerPixel, destP); + } + + addDirtyRect(Common::Rect(0, 0, this->w, this->h)); +} + +void ManagedSurface::transBlitFrom(const Surface &src, uint transColor, bool flipped, uint overrideColor) { + transBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Rect(0, 0, this->w, this->h), + transColor, false, overrideColor); +} + +void ManagedSurface::transBlitFrom(const Surface &src, const Common::Point &destPos, + uint transColor, bool flipped, uint overrideColor) { + transBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Rect(destPos.x, destPos.y, + destPos.x + src.w, destPos.y + src.h), transColor, false, overrideColor); +} + +void ManagedSurface::transBlitFrom(const Surface &src, const Common::Rect &srcRect, + const Common::Point &destPos, uint transColor, bool flipped, uint overrideColor) { + transBlitFrom(src, srcRect, Common::Rect(destPos.x, destPos.y, + destPos.x + src.w, destPos.y + src.h), transColor, false, overrideColor); +} + +template<typename T> +void transBlit(const Surface &src, const Common::Rect &srcRect, const Surface *dest, const Common::Rect &destRect, uint transColor, bool flipped, uint overrideColor) { + int scaleX = SCALE_THRESHOLD * srcRect.width() / destRect.width(); + int scaleY = SCALE_THRESHOLD * srcRect.height() / destRect.height(); + + // Loop through drawing output lines + for (int destY = destRect.top, scaleYCtr = 0; destY < destRect.bottom; ++destY, scaleYCtr += scaleY) { + if (destY < 0 || destY >= dest->h) + continue; + const T *srcLine = (const T *)src.getBasePtr(0, scaleYCtr / SCALE_THRESHOLD); + T *destLine = (T *)dest->getBasePtr(destRect.left, destY); + + // Loop through drawing the pixels of the row + for (int destX = destRect.left, xCtr = 0, scaleXCtr = 0; destX < destRect.right; ++destX, ++xCtr, scaleXCtr += scaleX) { + if (destX < 0 || destX >= dest->w) + continue; + + T srcVal = srcLine[flipped ? src.w - scaleXCtr / SCALE_THRESHOLD - 1 : scaleXCtr / SCALE_THRESHOLD]; + if (srcVal != transColor) { + destLine[xCtr] = overrideColor ? overrideColor : srcVal; + } + } + } +} + +void ManagedSurface::transBlitFrom(const Surface &src, const Common::Rect &srcRect, + const Common::Rect &destRect, uint transColor, bool flipped, uint overrideColor) { + if (src.w == 0 || src.h == 0 || destRect.width() == 0 || destRect.height() == 0) + return; + + if (format.bytesPerPixel == 1) + transBlit<byte>(src, srcRect, &_innerSurface, destRect, transColor, flipped, overrideColor); + else if (format.bytesPerPixel == 2) + transBlit<uint16>(src, srcRect, &_innerSurface, destRect, transColor, flipped, overrideColor); + else if (format.bytesPerPixel == 4) + transBlit<uint32>(src, srcRect, &_innerSurface, destRect, transColor, flipped, overrideColor); + else + error("Surface::transBlitFrom: bytesPerPixel must be 1, 2, or 4"); + + // Mark the affected area + addDirtyRect(destRect); +} + +void ManagedSurface::markAllDirty() { + addDirtyRect(Common::Rect(0, 0, this->w, this->h)); +} + +void ManagedSurface::addDirtyRect(const Common::Rect &r) { + if (_owner) { + Common::Rect bounds = r; + bounds.clip(Common::Rect(0, 0, this->w, this->h)); + bounds.translate(_offsetFromOwner.x, _offsetFromOwner.y); + _owner->addDirtyRect(bounds); + } +} + +void ManagedSurface::clear(uint color) { + fillRect(getBounds(), color); +} + +} // End of namespace Graphics diff --git a/graphics/managed_surface.h b/graphics/managed_surface.h new file mode 100644 index 0000000000..bd0632a493 --- /dev/null +++ b/graphics/managed_surface.h @@ -0,0 +1,376 @@ +/* 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 GRAPHICS_MANAGED_SURFACE_H +#define GRAPHICS_MANAGED_SURFACE_H + +#include "graphics/pixelformat.h" +#include "graphics/surface.h" +#include "common/rect.h" +#include "common/types.h" + +namespace Graphics { + +class Font; + +/** + * A derived graphics surface, which handles automatically managing the allocated + * surface data block, as well as introducing several new blitting methods + */ +class ManagedSurface { + friend class Font; +private: + /** + * The Graphics::Surface that the managed surface encapsulates + */ + Surface _innerSurface; + + /** + * If set, the inner surface will be freed when the surface is recreated, + * as well as when the surface is destroyed + */ + DisposeAfterUse::Flag _disposeAfterUse; + + /** + * Stores the owning surface if this If this managed surface represents + * a sub-section of another + */ + ManagedSurface *_owner; + + /** + * For sub-section areas of an owning parent managed surface, this represents + * the offset from the parent's top-left corner this sub-surface starts at + */ + Common::Point _offsetFromOwner; +protected: + /** + * Clips the given source bounds so the passed destBounds will be entirely on-screen + */ + bool clip(Common::Rect &srcBounds, Common::Rect &destBounds); + + /** + * Base method that descendent classes can override for recording affected + * dirty areas of the surface + */ + virtual void addDirtyRect(const Common::Rect &r); +public: + uint16 &w; + uint16 &h; + uint16 &pitch; + PixelFormat &format; +public: + /** + * Create the managed surface + */ + ManagedSurface(); + + /** + * Create a managed surface from another one. + * If the source surface is maintaining it's own surface data, then + * this surface will create it's own surface of the same size and copy + * the contents from the source surface + */ + ManagedSurface(const ManagedSurface &surf); + + /** + * Create the managed surface + */ + ManagedSurface(int width, int height); + + /** + * Create the managed surface + */ + ManagedSurface(int width, int height, const Graphics::PixelFormat &pixelFormat); + + /** + * Create the managed surface + */ + ManagedSurface(ManagedSurface &surf, const Common::Rect &bounds); + + /** + * Destroy the managed surface + */ + virtual ~ManagedSurface(); + + /** + * Implements automatic conversion to a Graphics::Surface by + * simply returning the inner surface. This must be const, + * because we don't want changes being done directly to it, + * since it would bypass dirty rect handling + */ + operator const Surface &() const { return _innerSurface; } + const Surface &rawSurface() const { return _innerSurface; } + + /** + * Reassign one managed surface to another one + * Note that if the source has a managed surface, it will be duplicated + */ + ManagedSurface &operator=(const ManagedSurface &surf); + + /** + * Returns true if the surface has not yet been allocated + */ + bool empty() const { return w == 0 || h == 0 || _innerSurface.getPixels() == nullptr; } + + /** + * Returns true if the surface is managing its own pixels + */ + DisposeAfterUse::Flag disposeAfterUse() const { return _disposeAfterUse; } + + /** + * Return a pointer to the pixel at the specified point. + * + * @param x The x coordinate of the pixel. + * @param y The y coordinate of the pixel. + * @return Pointer to the pixel. + */ + inline const void *getBasePtr(int x, int y) const { + return _innerSurface.getBasePtr(x, y); + } + + /** + * Return a pointer to the pixel at the specified point. + * + * @param x The x coordinate of the pixel. + * @param y The y coordinate of the pixel. + * @return Pointer to the pixel. + */ + inline void *getBasePtr(int x, int y) { + return _innerSurface.getBasePtr(x, y); + } + + /** + * Get a reference to the pixel data + */ + inline void *getPixels() { return _innerSurface.getPixels(); } + inline const void *getPixels() const { return _innerSurface.getPixels(); } + + /** + * Sets the pixel data. + */ + virtual void setPixels(void *newPixels); + + /** + * Allocate memory for the pixel data of the surface. + */ + virtual void create(uint16 width, uint16 height); + + /** + * Allocate memory for the pixel data of the surface. + */ + virtual void create(uint16 width, uint16 height, const PixelFormat &pixelFormat); + + /** + * Sets up the surface as a sub-section of another passed parent surface. This surface + * will not own the pixels, and any dirty rect notifications will automatically be + * passed to the original parent surface. + * @remarks Note that this differs from Graphics::Surface::getSubArea, in that that + * method only adds a single initial dirty rect for the whole area, and then none further + */ + virtual void create(ManagedSurface &surf, const Common::Rect &bounds); + + /** + * Release the memory used by the pixels memory of this surface. This is the + * counterpart to create(). + */ + virtual void free(); + + /** + * Clears any pending dirty rects that have been generated for the surface + */ + virtual void clearDirtyRects() {} + + /** + * When the managed surface is a sub-section of a parent surface, returns the + * the offset in the parent surface that the surface starts at + */ + const Common::Point getOffsetFromOwner() const { return _offsetFromOwner; } + + /** + * Return a rect giving the bounds of the surface + */ + const Common::Rect getBounds() const { + return Common::Rect(0, 0, this->w, this->h); + } + + /** + * Copies another surface into this one + */ + void blitFrom(const Surface &src); + + /** + * Copies another surface into this one at a given destination position + */ + void blitFrom(const Surface &src, const Common::Point &destPos); + + /** + * Copies another surface into this one at a given destination position + */ + void blitFrom(const Surface &src, const Common::Rect &srcRect, + const Common::Point &destPos); + + /** + * Copies another surface into this one ignoring pixels of a designated transparent color + * @param src Source surface + * @param transColor Transparency color to ignore copying + * @param flipped Specifies whether to horizontally flip the image + * @param overrideColor Optional color to use instead of non-transparent pixels from + * the source surface + */ + void transBlitFrom(const Surface &src, uint transColor = 0, bool flipped = false, uint overrideColor = 0); + + /** + * Copies another surface into this one ignoring pixels of a designated transparent color + * @param src Source surface + * @param destPos Destination position to draw the surface + * @param transColor Transparency color to ignore copying + * @param flipped Specifies whether to horizontally flip the image + * @param overrideColor Optional color to use instead of non-transparent pixels from + * the source surface + */ + void transBlitFrom(const Surface &src, const Common::Point &destPos, + uint transColor = 0, bool flipped = false, uint overrideColor = 0); + + /** + * Copies another surface into this one ignoring pixels of a designated transparent color + * @param src Source surface + * @param srcRect Sub-section of source surface to draw + * @param destPos Destination position to draw the surface + * @param transColor Transparency color to ignore copying + * @param flipped Specifies whether to horizontally flip the image + * @param overrideColor Optional color to use instead of non-transparent pixels from + * the source surface + */ + void transBlitFrom(const Surface &src, const Common::Rect &srcRect, const Common::Point &destPos, + uint transColor = 0, bool flipped = false, uint overrideColor = 0); + + /** + * Copies another surface into this one ignoring pixels of a designated transparent color + * @param src Source surface + * @param srcRect Sub-section of source surface to draw + * @param destRect Destination area to draw the surface in. This can be sized differently + * then srcRect, allowing for arbitrary scaling of the image + * @param transColor Transparency color to ignore copying + * @param flipped Specifies whether to horizontally flip the image + * @param overrideColor Optional color to use instead of non-transparent pixels from + * the source surface + */ + void transBlitFrom(const Surface &src, const Common::Rect &srcRect, const Common::Rect &destRect, + uint transColor = 0, bool flipped = false, uint overrideColor = 0); + + /** + * Clear the entire surface + */ + void clear(uint color = 0); + + /** + * Mark the entire surface as dirty + */ + void markAllDirty(); + + /** + * Copies a bitmap to the Surface internal buffer. The pixel format + * of buffer must match the pixel format of the Surface. + */ + void copyRectToSurface(const void *buffer, int srcPitch, int destX, int destY, int width, int height) { + _innerSurface.copyRectToSurface(buffer, srcPitch, destX, destY, width, height); + } + + /** + * Copies a bitmap to the Surface internal buffer. The pixel format + * of buffer must match the pixel format of the Surface. + */ + void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY, const Common::Rect subRect) { + _innerSurface.copyRectToSurface(srcSurface, destX, destY, subRect); + } + + /** + * Copy the data from another Surface, reinitializing the + * surface to match the dimensions of the passed surface + */ + void copyFrom(const ManagedSurface &surf) { + clearDirtyRects(); + _innerSurface.copyFrom(surf._innerSurface); + } + + /** + * Draw a line. + */ + void drawLine(int x0, int y0, int x1, int y1, uint32 color) { + _innerSurface.drawLine(x0, y0, x1, y1, color); + addDirtyRect(Common::Rect(x0, y0, x1, y1)); + } + + /** + * Draw a thick line. + */ + void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, uint32 color) { + _innerSurface.drawThickLine(x0, y0, x1, y1, penX, penY, color); + addDirtyRect(Common::Rect(x0, y0, x1 + penX, y1 + penY)); + } + + /** + * Draw a horizontal line. + */ + void hLine(int x, int y, int x2, uint32 color) { + _innerSurface.hLine(x, y, x2, color); + addDirtyRect(Common::Rect(x, y, x2 + 1, y + 1)); + } + + /** + * Draw a vertical line. + */ + void vLine(int x, int y, int y2, uint32 color) { + _innerSurface.vLine(x, y, y2, color); + addDirtyRect(Common::Rect(x, y, x + 1, y2 + 1)); + } + + /** + * Fill a rect with a given color. + */ + void fillRect(Common::Rect r, uint32 color) { + _innerSurface.fillRect(r, color); + addDirtyRect(r); + } + + /** + * Draw a frame around a specified rect. + */ + void frameRect(const Common::Rect &r, uint32 color) { + _innerSurface.frameRect(r, color); + addDirtyRect(r); + } + + /** + * Returns a sub-area of the screen, but only adds a single initial dirty rect + * for the retrieved area. + */ + Surface getSubArea(const Common::Rect &area) { + addDirtyRect(area); + return _innerSurface.getSubArea(area); + } +}; + +} // End of namespace Graphics + + +#endif diff --git a/graphics/module.mk b/graphics/module.mk index b6919cf1ab..90f6a3199c 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -12,10 +12,12 @@ MODULE_OBJS := \ fonts/ttf.o \ fonts/winfont.o \ maccursor.o \ + managed_surface.o \ pixelformat.o \ primitives.o \ scaler.o \ scaler/thumbnail_intern.o \ + screen.o \ sjis.o \ surface.o \ transform_struct.o \ diff --git a/graphics/primitives.cpp b/graphics/primitives.cpp index 564bdb9673..ac1c58b1d8 100644 --- a/graphics/primitives.cpp +++ b/graphics/primitives.cpp @@ -20,7 +20,9 @@ * */ +#include "common/algorithm.h" #include "common/util.h" +#include "graphics/primitives.h" namespace Graphics { @@ -62,6 +64,22 @@ void drawLine(int x0, int y0, int x1, int y1, int color, void (*plotProc)(int, i } } +void drawHLine(int x1, int x2, int y, int color, void (*plotProc)(int, int, int, void *), void *data) { + if (x1 > x2) + SWAP(x1, x2); + + for (int x = x1; x <= x2; x++) + (*plotProc)(x, y, color, data); +} + +void drawVLine(int x, int y1, int y2, int color, void (*plotProc)(int, int, int, void *), void *data) { + if (y1 > y2) + SWAP(y1, y2); + + for (int y = y1; y <= y2; y++) + (*plotProc)(x, y, color, data); +} + void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, int color, void (*plotProc)(int, int, int, void *), void *data) { assert(penX > 0 && penY > 0); @@ -79,4 +97,335 @@ void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, int color drawLine(x0 + x, y0 + y, x1 + x, y1 + y, color, plotProc, data); } +/* Bresenham as presented in Foley & Van Dam */ +/* Code is based on GD lib http://libgd.github.io/ */ +void drawThickLine2(int x1, int y1, int x2, int y2, int thick, int color, void (*plotProc)(int, int, int, void *), void *data) { + int incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag; + int wid; + int w, wstart; + + int dx = abs(x2 - x1); + int dy = abs(y2 - y1); + + if (dx == 0) { + if (y1 > y2) + SWAP(y1, y2); + Common::Rect r(x1, y1, x1 + thick - 1, y2); + drawFilledRect(r, color, plotProc, data); + return; + } else if (dy == 0) { + if (x1 > x2) + SWAP(x1, x2); + Common::Rect r(x1, y1, x2, y1 + thick - 1); + drawFilledRect(r, color, plotProc, data); + return; + } + + if (dy <= dx) { + /* More-or-less horizontal. use wid for vertical stroke */ + /* Doug Claar: watch out for NaN in atan2 (2.0.5) */ + + /* 2.0.12: Michael Schwartz: divide rather than multiply; + TBB: but watch out for /0! */ + double ac = cos(atan2((double)dy, (double)dx)); + if (ac != 0) { + wid = thick / ac; + } else { + wid = 1; + } + if (wid == 0) { + wid = 1; + } + d = 2 * dy - dx; + incr1 = 2 * dy; + incr2 = 2 * (dy - dx); + if (x1 > x2) { + x = x2; + y = y2; + ydirflag = (-1); + xend = x1; + } else { + x = x1; + y = y1; + ydirflag = 1; + xend = x2; + } + + /* Set up line thickness */ + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) + (*plotProc)(x, y, color, data); + + if (((y2 - y1) * ydirflag) > 0) { + while (x < xend) { + x++; + if (d < 0) { + d += incr1; + } else { + y++; + d += incr2; + } + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) + (*plotProc)(x, w, color, data); + } + } else { + while (x < xend) { + x++; + if (d < 0) { + d += incr1; + } else { + y--; + d += incr2; + } + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) + (*plotProc)(x, w, color, data); + } + } + } else { + /* More-or-less vertical. use wid for horizontal stroke */ + /* 2.0.12: Michael Schwartz: divide rather than multiply; + TBB: but watch out for /0! */ + double as = sin(atan2((double)dy, (double)dx)); + if (as != 0) { + wid = thick / as; + } else { + wid = 1; + } + if (wid == 0) + wid = 1; + + d = 2 * dx - dy; + incr1 = 2 * dx; + incr2 = 2 * (dx - dy); + if (y1 > y2) { + y = y2; + x = x2; + yend = y1; + xdirflag = (-1); + } else { + y = y1; + x = x1; + yend = y2; + xdirflag = 1; + } + + /* Set up line thickness */ + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) + (*plotProc)(w, y, color, data); + + if (((x2 - x1) * xdirflag) > 0) { + while (y < yend) { + y++; + if (d < 0) { + d += incr1; + } else { + x++; + d += incr2; + } + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) + (*plotProc)(w, y, color, data); + } + } else { + while (y < yend) { + y++; + if (d < 0) { + d += incr1; + } else { + x--; + d += incr2; + } + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) + (*plotProc)(w, y, color, data); + } + } + } +} + +void drawFilledRect(Common::Rect &rect, int color, void (*plotProc)(int, int, int, void *), void *data) { + for (int y = rect.top; y <= rect.bottom; y++) + drawHLine(rect.left, rect.right, y, color, plotProc, data); +} + +// http://members.chello.at/easyfilter/bresenham.html +void drawRoundRect(Common::Rect &rect, int arc, int color, bool filled, void (*plotProc)(int, int, int, void *), void *data) { + if (rect.height() < rect.width()) { + int x = -arc, y = 0, err = 2-2*arc; /* II. Quadrant */ + int dy = rect.height() - arc * 2; + int r = arc; + int stop = 0; + int lastx = 0, lasty = 0; + if (dy < 0) + stop = -dy / 2; + + do { + if (filled) { + drawHLine(rect.left+x+r, rect.right-x-r, rect.top-y+r-stop, color, plotProc, data); + drawHLine(rect.left+x+r, rect.right-x-r, rect.bottom+y-r+stop, color, plotProc, data); + } else { + (*plotProc)(rect.left+x+r, rect.top-y+r-stop, color, data); + (*plotProc)(rect.right-x-r, rect.top-y+r-stop, color, data); + (*plotProc)(rect.left+x+r, rect.bottom+y-r+stop, color, data); + (*plotProc)(rect.right-x-r, rect.bottom+y-r+stop, color, data); + + lastx = x; + lasty = y; + } + arc = err; + if (arc <= y) err += ++y*2+1; /* e_xy+e_y < 0 */ + if (arc > x || err > y) err += ++x*2+1; /* e_xy+e_x > 0 or no 2nd y-step */ + if (stop && y > stop) + break; + } while (x < 0); + + if (!filled) { + x = lastx; + y = lasty; + + drawHLine(rect.left+x+r, rect.right-x-r, rect.top-y+r-stop, color, plotProc, data); + drawHLine(rect.left+x+r, rect.right-x-r, rect.bottom+y-r+stop, color, plotProc, data); + } + + for (int i = 0; i < dy; i++) { + if (filled) { + drawHLine(rect.left, rect.right, rect.top + r + i, color, plotProc, data); + } else { + (*plotProc)(rect.left, rect.top + r + i, color, data); + (*plotProc)(rect.right, rect.top + r + i, color, data); + } + } + } else { + int y = -arc, x = 0, err = 2-2*arc; /* II. Quadrant */ + int dx = rect.width() - arc * 2; + int r = arc; + int stop = 0; + int lastx = 0, lasty = 0; + if (dx < 0) + stop = -dx / 2; + + do { + if (filled) { + drawVLine(rect.left-x+r-stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data); + drawVLine(rect.right+x-r+stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data); + } else { + (*plotProc)(rect.left-x+r-stop, rect.top+y+r, color, data); + (*plotProc)(rect.left-x+r-stop, rect.bottom-y-r, color, data); + (*plotProc)(rect.right+x-r+stop, rect.top+y+r, color, data); + (*plotProc)(rect.right+x-r+stop, rect.bottom-y-r, color, data); + + lastx = x; + lasty = y; + } + + arc = err; + if (arc <= x) err += ++x*2+1; /* e_xy+e_y < 0 */ + if (arc > y || err > x) err += ++y*2+1; /* e_xy+e_x > 0 or no 2nd y-step */ + if (stop && x > stop) + break; + } while (y < 0); + + if (!filled) { + x = lastx; + y = lasty; + drawVLine(rect.left-x+r-stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data); + drawVLine(rect.right+x-r+stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data); + } + + for (int i = 0; i < dx; i++) { + if (filled) { + drawVLine(rect.left + r + i, rect.top, rect.bottom, color, plotProc, data); + } else { + (*plotProc)(rect.left + r + i, rect.top, color, data); + (*plotProc)(rect.left + r + i, rect.bottom, color, data); + } + } + } +} + +// Based on public-domain code by Darel Rex Finley, 2007 +// http://alienryderflex.com/polygon_fill/ +void drawPolygonScan(int *polyX, int *polyY, int npoints, Common::Rect &bbox, int color, void (*plotProc)(int, int, int, void *), void *data) { + int *nodeX = (int *)calloc(npoints, sizeof(int)); + int i, j; + + // Loop through the rows of the image. + for (int pixelY = bbox.top; pixelY < bbox.bottom; pixelY++) { + // Build a list of nodes. + int nodes = 0; + j = npoints - 1; + + for (i = 0; i < npoints; i++) { + if ((polyY[i] < pixelY && polyY[j] >= pixelY) || (polyY[j] < pixelY && polyY[i] >= pixelY)) { + nodeX[nodes++] = (int)(polyX[i] + (double)(pixelY - polyY[i]) / (double)(polyY[j]-polyY[i]) * + (double)(polyX[j] - polyX[i]) + 0.5); + } + j = i; + } + + // Sort the nodes + Common::sort(nodeX, &nodeX[nodes]); + + // Fill the pixels between node pairs. + for (i = 0; i < nodes; i += 2) { + if (nodeX[i ] >= bbox.right) + break; + if (nodeX[i + 1] > bbox.left) { + nodeX[i] = MAX<int16>(nodeX[i], bbox.left); + nodeX[i + 1] = MIN<int16>(nodeX[i + 1], bbox.right); + + drawHLine(nodeX[i], nodeX[i + 1], pixelY, color, plotProc, data); + } + } + } + + free(nodeX); +} + +// http://members.chello.at/easyfilter/bresenham.html +void drawEllipse(int x0, int y0, int x1, int y1, int color, bool filled, void (*plotProc)(int, int, int, void *), void *data) { + int a = abs(x1-x0), b = abs(y1-y0), b1 = b&1; /* values of diameter */ + long dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; /* error increment */ + long err = dx+dy+b1*a*a, e2; /* error of 1.step */ + + if (x0 > x1) { x0 = x1; x1 += a; } /* if called with swapped points */ + if (y0 > y1) y0 = y1; /* .. exchange them */ + y0 += (b+1)/2; y1 = y0-b1; /* starting pixel */ + a *= 8*a; b1 = 8*b*b; + + do { + if (filled) { + drawHLine(x0, x1, y0, color, plotProc, data); + drawHLine(x0, x1, y1, color, plotProc, data); + } else { + (*plotProc)(x1, y0, color, data); /* I. Quadrant */ + (*plotProc)(x0, y0, color, data); /* II. Quadrant */ + (*plotProc)(x0, y1, color, data); /* III. Quadrant */ + (*plotProc)(x1, y1, color, data); /* IV. Quadrant */ + } + e2 = 2*err; + if (e2 <= dy) { y0++; y1--; err += dy += a; } /* y step */ + if (e2 >= dx || 2*err > dy) { x0++; x1--; err += dx += b1; } /* x step */ + } while (x0 <= x1); + + while (y0-y1 < b) { /* too early stop of flat ellipses a=1 */ + if (filled) { + drawHLine(x0-1, x0-1, y0, color, plotProc, data); /* -> finish tip of ellipse */ + drawHLine(x1+1, x1+1, y0, color, plotProc, data); + drawHLine(x0-1, x0-1, y1, color, plotProc, data); + drawHLine(x1+1, x1+1, y1, color, plotProc, data); + } else { + (*plotProc)(x0-1, y0, color, data); /* -> finish tip of ellipse */ + (*plotProc)(x1+1, y0, color, data); + (*plotProc)(x0-1, y1, color, data); + (*plotProc)(x1+1, y1, color, data); + } + y0++; + y1--; + } +} + } // End of namespace Graphics diff --git a/graphics/primitives.h b/graphics/primitives.h index a3e8ab1565..62dc10bfdf 100644 --- a/graphics/primitives.h +++ b/graphics/primitives.h @@ -23,10 +23,21 @@ #ifndef GRAPHICS_PRIMITIVES_H #define GRAPHICS_PRIMITIVES_H +#include "common/rect.h" + namespace Graphics { void drawLine(int x0, int y0, int x1, int y1, int color, void (*plotProc)(int, int, int, void *), void *data); +void drawHLine(int x1, int x2, int y, int color, void (*plotProc)(int, int, int, void *), void *data); +void drawVLine(int x, int y1, int y2, int color, void (*plotProc)(int, int, int, void *), void *data); void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, int color, void (*plotProc)(int, int, int, void *), void *data); +void drawThickLine2(int x1, int y1, int x2, int y2, int thick, int color, + void (*plotProc)(int, int, int, void *), void *data); +void drawFilledRect(Common::Rect &rect, int color, void (*plotProc)(int, int, int, void *), void *data); +void drawRoundRect(Common::Rect &rect, int arc, int color, bool filled, void (*plotProc)(int, int, int, void *), void *data); +void drawPolygonScan(int *polyX, int *polyY, int npoints, Common::Rect &bbox, int color, + void (*plotProc)(int, int, int, void *), void *data); +void drawEllipse(int x0, int y0, int x1, int y1, int color, bool filled, void (*plotProc)(int, int, int, void *), void *data); } // End of namespace Graphics diff --git a/graphics/screen.cpp b/graphics/screen.cpp new file mode 100644 index 0000000000..4169c98035 --- /dev/null +++ b/graphics/screen.cpp @@ -0,0 +1,129 @@ +/* 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/system.h" +#include "common/algorithm.h" +#include "graphics/screen.h" +#include "graphics/palette.h" + +namespace Graphics { + +Screen::Screen(): ManagedSurface() { + create(g_system->getWidth(), g_system->getHeight()); +} + +Screen::Screen(int width, int height): ManagedSurface() { + create(width, height); +} + +Screen::Screen(int width, int height, PixelFormat pixelFormat): ManagedSurface() { + create(width, height, pixelFormat); +} + +void Screen::update() { + // Merge the dirty rects + mergeDirtyRects(); + + // Loop through copying dirty areas to the physical screen + Common::List<Common::Rect>::iterator i; + for (i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i) { + const Common::Rect &r = *i; + const byte *srcP = (const byte *)getBasePtr(r.left, r.top); + g_system->copyRectToScreen(srcP, pitch, r.left, r.top, + r.width(), r.height()); + } + + // Signal the physical screen to update + g_system->updateScreen(); + _dirtyRects.clear(); +} + + +void Screen::addDirtyRect(const Common::Rect &r) { + Common::Rect bounds = r; + bounds.clip(getBounds()); + bounds.translate(getOffsetFromOwner().x, getOffsetFromOwner().y); + + if (bounds.width() > 0 && bounds.height() > 0) + _dirtyRects.push_back(bounds); +} + +void Screen::makeAllDirty() { + addDirtyRect(Common::Rect(0, 0, this->w, this->h)); +} + +void Screen::mergeDirtyRects() { + Common::List<Common::Rect>::iterator rOuter, rInner; + + // Process the dirty rect list to find any rects to merge + for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) { + rInner = rOuter; + while (++rInner != _dirtyRects.end()) { + + if ((*rOuter).intersects(*rInner)) { + // These two rectangles overlap, so merge them + unionRectangle(*rOuter, *rOuter, *rInner); + + // remove the inner rect from the list + _dirtyRects.erase(rInner); + + // move back to beginning of list + rInner = rOuter; + } + } + } +} + +bool Screen::unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2) { + destRect = src1; + destRect.extend(src2); + + return !destRect.isEmpty(); +} + +void Screen::getPalette(byte palette[PALETTE_SIZE]) { + assert(format.bytesPerPixel == 1); + g_system->getPaletteManager()->grabPalette(palette, 0, PALETTE_COUNT); +} + +void Screen::getPalette(byte *palette, uint start, uint num) { + assert(format.bytesPerPixel == 1); + g_system->getPaletteManager()->grabPalette(palette, start, num); +} + +void Screen::setPalette(const byte palette[PALETTE_SIZE]) { + assert(format.bytesPerPixel == 1); + g_system->getPaletteManager()->setPalette(palette, 0, PALETTE_COUNT); +} + +void Screen::setPalette(const byte *palette, uint start, uint num) { + assert(format.bytesPerPixel == 1); + g_system->getPaletteManager()->setPalette(palette, start, num); +} + +void Screen::clearPalette() { + byte palette[PALETTE_SIZE]; + Common::fill(&palette[0], &palette[PALETTE_SIZE], 0); + setPalette(palette); +} + +} // End of namespace Graphics diff --git a/graphics/screen.h b/graphics/screen.h new file mode 100644 index 0000000000..29816120f1 --- /dev/null +++ b/graphics/screen.h @@ -0,0 +1,118 @@ +/* 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 GRAPHICS_SCREEN_H +#define GRAPHICS_SCREEN_H + +#include "graphics/managed_surface.h" +#include "graphics/pixelformat.h" +#include "common/list.h" +#include "common/rect.h" + +namespace Graphics { + +#define PALETTE_COUNT 256 +#define PALETTE_SIZE (256 * 3) + +/** + * Implements a specialised surface that represents the screen. + * It keeps track of any areas of itself that are updated by drawing + * calls, and provides an update that method that blits the affected + * areas to the physical screen + */ +class Screen : virtual public ManagedSurface { +private: + /** + * List of affected areas of the screen + */ + Common::List<Common::Rect> _dirtyRects; +private: + /** + * Merges together overlapping dirty areas of the screen + */ + void mergeDirtyRects(); + + /** + * Returns the union of two dirty area rectangles + */ + bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2); +protected: + /** + * Adds a rectangle to the list of modified areas of the screen during the + * current frame + */ + virtual void addDirtyRect(const Common::Rect &r); +public: + Screen(); + Screen(int width, int height); + Screen(int width, int height, PixelFormat pixelFormat); + + /** + * Returns true if there are any pending screen updates (dirty areas) + */ + bool isDirty() const { return !_dirtyRects.empty(); } + + /** + * Marks the whole screen as dirty. This forces the next call to update + * to copy the entire screen contents + */ + void makeAllDirty(); + + /** + * Clear the current dirty rects list + */ + virtual void clearDirtyRects() { _dirtyRects.clear(); } + + /** + * Updates the screen by copying any affected areas to the system + */ + virtual void update(); + + /** + * Return the currently active palette + */ + void getPalette(byte palette[PALETTE_SIZE]); + + /** + * Return a portion of the currently active palette + */ + void getPalette(byte *palette, uint start, uint num); + + /** + * Set the palette + */ + void setPalette(const byte palette[PALETTE_SIZE]); + + /** + * Set a subsection of the palette + */ + void setPalette(const byte *palette, uint start, uint num); + + /** + * Clears the current palette, setting all entries to black + */ + void clearPalette(); +}; + +} // End of namespace Graphics + +#endif diff --git a/graphics/thumbnail.cpp b/graphics/thumbnail.cpp index 802ad09cbb..a3037e5ad5 100644 --- a/graphics/thumbnail.cpp +++ b/graphics/thumbnail.cpp @@ -67,7 +67,7 @@ HeaderState loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header, header.size = in.readUint32BE(); header.version = in.readByte(); - // Do a check whether any read errors had occured. If so we cannot use the + // Do a check whether any read errors had occurred. If so we cannot use the // values obtained for size and version because they might be bad. if (in.err() || in.eos()) { // TODO: We fake that there is no header. This is actually not quite diff --git a/gui/credits.h b/gui/credits.h index cda523bb79..cb9a10fec4 100644 --- a/gui/credits.h +++ b/gui/credits.h @@ -347,6 +347,9 @@ static const char *credits[] = { "C1""Dreamcast", "C0""Marcus Comstedt", "", +"C1""GCW0", +"C0""Eugene Sandulenko", +"", "C1""GPH Devices (GP2X, GP2XWiz & Caanoo)", "C0""John Willis", "", diff --git a/gui/predictivedialog.cpp b/gui/predictivedialog.cpp index 6ff10267db..9557da1206 100644 --- a/gui/predictivedialog.cpp +++ b/gui/predictivedialog.cpp @@ -724,6 +724,10 @@ int PredictiveDialog::binarySearch(const char *const *const dictLine, const Comm } bool PredictiveDialog::matchWord() { + // If there is no dictionary, then there is no match. + if (_unitedDict.dictLineCount <= 0) + return false; + // If no text has been entered, then there is no match. if (_currentCode.empty()) return false; @@ -981,6 +985,7 @@ void PredictiveDialog::loadAllDictionary(Dict &dict) { Common::File *inFile = new Common::File(); if (!inFile->open(ConfMan.get(dict.nameDict))) { warning("Predictive Dialog: cannot read file: %s", dict.defaultFilename.c_str()); + delete inFile; return; } loadDictionary(inFile, dict); diff --git a/gui/predictivedialog.h b/gui/predictivedialog.h index 37c80a2a14..4c167c3efa 100644 --- a/gui/predictivedialog.h +++ b/gui/predictivedialog.h @@ -85,6 +85,7 @@ private: struct Dict { Dict() : dictLine(nullptr), dictText(nullptr), dictActLine(nullptr), dictLineCount(0), dictTextSize(0) {} + ~Dict() { free(dictText); } char **dictLine; char *dictText; char *dictActLine; // using only for united dict... diff --git a/gui/themes/translations.dat b/gui/themes/translations.dat Binary files differindex 58e1b5b2b2..b0da793cdf 100644 --- a/gui/themes/translations.dat +++ b/gui/themes/translations.dat diff --git a/image/codecs/indeo3.cpp b/image/codecs/indeo3.cpp index af9120ca93..560658d1f5 100644 --- a/image/codecs/indeo3.cpp +++ b/image/codecs/indeo3.cpp @@ -391,6 +391,11 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, int rle_v1, rle_v2, rle_v3; uint16 res; + if ((width & 3) != 0) { + // This isn't a valid width according to http://wiki.multimedia.cx/index.php?title=Indeo_3 + warning("Indeo3 file with width not divisible by 4. This will cause unaligned writes"); + } + bit_buf = 0; ref_vectors = NULL; @@ -479,7 +484,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, if (cmd == 0 || ref_vectors != NULL) { for (lp1 = 0; lp1 < blks_width; lp1++) { for (i = 0, j = 0; i < blks_height; i++, j += width_tbl[1]) - ((uint32 *)cur_frm_pos)[j] = ((uint32 *)ref_frm_pos)[j]; + ((uint32 *)cur_frm_pos)[j] = READ_UINT32(((uint32 *)ref_frm_pos)+j); cur_frm_pos += 4; ref_frm_pos += 4; } @@ -526,7 +531,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, switch (correction_type_sp[0][k]) { case 0: - *cur_lp = FROM_LE_32(((FROM_LE_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1); + *cur_lp = FROM_LE_32(((READ_LE_UINT32(ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1); lp2++; break; case 1: @@ -540,9 +545,9 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, //warning("Glitch"); return; } - res = ((FROM_LE_16(((uint16 *)(ref_lp))[0]) >> 1) + correction_lp[lp2 & 0x01][*buf1]) << 1; + res = ((READ_LE_UINT16(((uint16 *)(ref_lp))) >> 1) + correction_lp[lp2 & 0x01][*buf1]) << 1; ((uint16 *)cur_lp)[0] = FROM_LE_16(res); - res = ((FROM_LE_16(((uint16 *)(ref_lp))[1]) >> 1) + correction_lp[lp2 & 0x01][k]) << 1; + res = ((READ_LE_UINT16(((uint16 *)(ref_lp))+1) >> 1) + correction_lp[lp2 & 0x01][k]) << 1; ((uint16 *)cur_lp)[1] = FROM_LE_16(res); buf1++; lp2++; @@ -550,14 +555,14 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, case 2: if (lp2 == 0) { for (i = 0, j = 0; i < 2; i++, j += width_tbl[1]) - cur_lp[j] = ref_lp[j]; + cur_lp[j] = READ_UINT32(ref_lp+j); lp2 += 2; } break; case 3: if (lp2 < 2) { for (i = 0, j = 0; i < (3 - lp2); i++, j += width_tbl[1]) - cur_lp[j] = ref_lp[j]; + cur_lp[j] = READ_UINT32(ref_lp+j); lp2 = 3; } break; @@ -567,7 +572,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, if (rle_v1 == 1 || ref_vectors != NULL) { for (i = 0, j = 0; i < 4; i++, j += width_tbl[1]) - cur_lp[j] = ref_lp[j]; + cur_lp[j] = READ_UINT32(ref_lp+j); } RLE_V2_CHECK(buf1,rle_v2, rle_v3,lp2) @@ -580,7 +585,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, LP2_CHECK(buf1,rle_v3,lp2) case 4: for (i = 0, j = 0; i < (4 - lp2); i++, j += width_tbl[1]) - cur_lp[j] = ref_lp[j]; + cur_lp[j] = READ_UINT32(ref_lp+j); lp2 = 4; break; @@ -600,7 +605,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, } if (ref_vectors != NULL) { for (i = 0, j = 0; i < 4; i++, j += width_tbl[1]) - cur_lp[j] = ref_lp[j]; + cur_lp[j] = READ_UINT32(ref_lp+j); } lp2 = 4; break; @@ -645,18 +650,18 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, switch (correction_type_sp[lp2 & 0x01][k]) { case 0: - cur_lp[width_tbl[1]] = FROM_LE_32(((FROM_LE_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1); + cur_lp[width_tbl[1]] = FROM_LE_32(((READ_LE_UINT32(ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1); if (lp2 > 0 || flag1 == 0 || strip->ypos != 0) cur_lp[0] = ((cur_lp[-width_tbl[1]] >> 1) + (cur_lp[width_tbl[1]] >> 1)) & 0xFEFEFEFE; else - cur_lp[0] = FROM_LE_32(((FROM_LE_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1); + cur_lp[0] = FROM_LE_32(((READ_LE_UINT32(ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1); lp2++; break; case 1: - res = ((FROM_LE_16(((uint16 *)ref_lp)[0]) >> 1) + correction_lp[lp2 & 0x01][*buf1]) << 1; + res = ((READ_LE_UINT16(((uint16 *)ref_lp)) >> 1) + correction_lp[lp2 & 0x01][*buf1]) << 1; ((uint16 *)cur_lp)[width_tbl[2]] = FROM_LE_16(res); - res = ((FROM_LE_16(((uint16 *)ref_lp)[1]) >> 1) + correction_lp[lp2 & 0x01][k]) << 1; + res = ((READ_LE_UINT16(((uint16 *)ref_lp)+1) >> 1) + correction_lp[lp2 & 0x01][k]) << 1; ((uint16 *)cur_lp)[width_tbl[2]+1] = FROM_LE_16(res); if (lp2 > 0 || flag1 == 0 || strip->ypos != 0) @@ -670,7 +675,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, case 2: if (lp2 == 0) { for (i = 0, j = 0; i < 4; i++, j += width_tbl[1]) - cur_lp[j] = *ref_lp; + cur_lp[j] = READ_UINT32(ref_lp); lp2 += 2; } break; @@ -678,7 +683,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, case 3: if (lp2 < 2) { for (i = 0, j = 0; i < 6 - (lp2 * 2); i++, j += width_tbl[1]) - cur_lp[j] = *ref_lp; + cur_lp[j] = READ_UINT32(ref_lp); lp2 = 3; } break; @@ -703,7 +708,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, if (rle_v1 == 1) { for (i = 0, j = 0; i < 8; i++, j += width_tbl[1]) - cur_lp[j] = ref_lp[j]; + cur_lp[j] = READ_UINT32(ref_lp+j); } RLE_V2_CHECK(buf1,rle_v2, rle_v3,lp2) @@ -716,7 +721,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, LP2_CHECK(buf1,rle_v3,lp2) case 4: for (i = 0, j = 0; i < 8 - (lp2 * 2); i++, j += width_tbl[1]) - cur_lp[j] = *ref_lp; + cur_lp[j] = READ_UINT32(ref_lp); lp2 = 4; break; @@ -756,8 +761,8 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, k = *buf1++; cur_lp = ((uint32 *)cur_frm_pos) + width_tbl[lp2 * 2]; ref_lp = ((uint32 *)cur_frm_pos) + width_tbl[(lp2 * 2) - 1]; - lv1 = ref_lp[0]; - lv2 = ref_lp[1]; + lv1 = READ_UINT32(ref_lp); + lv2 = READ_UINT32(ref_lp+1); if (lp2 == 0 && flag1 != 0) { #if defined(SCUMM_BIG_ENDIAN) lv1 = lv1 & 0xFF00FF00; @@ -936,28 +941,28 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, case 0: lv1 = correctionloworder_lp[lp2 & 0x01][k]; lv2 = correctionhighorder_lp[lp2 & 0x01][k]; - cur_lp[0] = FROM_LE_32(((FROM_LE_32(ref_lp[0]) >> 1) + lv1) << 1); - cur_lp[1] = FROM_LE_32(((FROM_LE_32(ref_lp[1]) >> 1) + lv2) << 1); - cur_lp[width_tbl[1]] = FROM_LE_32(((FROM_LE_32(ref_lp[width_tbl[1]]) >> 1) + lv1) << 1); - cur_lp[width_tbl[1]+1] = FROM_LE_32(((FROM_LE_32(ref_lp[width_tbl[1]+1]) >> 1) + lv2) << 1); + cur_lp[0] = FROM_LE_32(((READ_LE_UINT32(ref_lp) >> 1) + lv1) << 1); + cur_lp[1] = FROM_LE_32(((READ_LE_UINT32(ref_lp+1) >> 1) + lv2) << 1); + cur_lp[width_tbl[1]] = FROM_LE_32(((READ_LE_UINT32(ref_lp+width_tbl[1]) >> 1) + lv1) << 1); + cur_lp[width_tbl[1]+1] = FROM_LE_32(((READ_LE_UINT32(ref_lp+width_tbl[1]+1) >> 1) + lv2) << 1); lp2++; break; case 1: lv1 = correctionloworder_lp[lp2 & 0x01][*buf1++]; lv2 = correctionloworder_lp[lp2 & 0x01][k]; - cur_lp[0] = FROM_LE_32(((FROM_LE_32(ref_lp[0]) >> 1) + lv1) << 1); - cur_lp[1] = FROM_LE_32(((FROM_LE_32(ref_lp[1]) >> 1) + lv2) << 1); - cur_lp[width_tbl[1]] = FROM_LE_32(((FROM_LE_32(ref_lp[width_tbl[1]]) >> 1) + lv1) << 1); - cur_lp[width_tbl[1]+1] = FROM_LE_32(((FROM_LE_32(ref_lp[width_tbl[1]+1]) >> 1) + lv2) << 1); + cur_lp[0] = FROM_LE_32(((READ_LE_UINT32(ref_lp) >> 1) + lv1) << 1); + cur_lp[1] = FROM_LE_32(((READ_LE_UINT32(ref_lp+1) >> 1) + lv2) << 1); + cur_lp[width_tbl[1]] = FROM_LE_32(((READ_LE_UINT32(ref_lp+width_tbl[1]) >> 1) + lv1) << 1); + cur_lp[width_tbl[1]+1] = FROM_LE_32(((READ_LE_UINT32(ref_lp+width_tbl[1]+1) >> 1) + lv2) << 1); lp2++; break; case 2: if (lp2 == 0) { for (i = 0, j = 0; i < 4; i++, j += width_tbl[1]) { - cur_lp[j] = ref_lp[j]; - cur_lp[j+1] = ref_lp[j+1]; + cur_lp[j] = READ_UINT32(ref_lp+j); + cur_lp[j+1] = READ_UINT32(ref_lp+j+1); } lp2 += 2; } @@ -966,8 +971,8 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, case 3: if (lp2 < 2) { for (i = 0, j = 0; i < 6 - (lp2 * 2); i++, j += width_tbl[1]) { - cur_lp[j] = ref_lp[j]; - cur_lp[j+1] = ref_lp[j+1]; + cur_lp[j] = READ_UINT32(ref_lp+j); + cur_lp[j+1] = READ_UINT32(ref_lp+j+1); } lp2 = 3; } @@ -977,8 +982,8 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, if (lp2 == 0) { RLE_V3_CHECK(buf1,rle_v1,rle_v2,rle_v3) for (i = 0, j = 0; i < 8; i++, j += width_tbl[1]) { - ((uint32 *)cur_frm_pos)[j] = ((uint32 *)ref_frm_pos)[j]; - ((uint32 *)cur_frm_pos)[j+1] = ((uint32 *)ref_frm_pos)[j+1]; + ((uint32 *)cur_frm_pos)[j] = READ_UINT32(((uint32 *)ref_frm_pos)+j); + ((uint32 *)cur_frm_pos)[j+1] = READ_UINT32(((uint32 *)ref_frm_pos)+j+1); } RLE_V2_CHECK(buf1,rle_v2, rle_v3,lp2) break; @@ -992,8 +997,8 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, case 6: case 4: for (i = 0, j = 0; i < 8 - (lp2 * 2); i++, j += width_tbl[1]) { - cur_lp[j] = ref_lp[j]; - cur_lp[j+1] = ref_lp[j+1]; + cur_lp[j] = READ_UINT32(ref_lp+j); + cur_lp[j+1] = READ_UINT32(ref_lp+j+1); } lp2 = 4; break; @@ -1037,8 +1042,8 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, switch (correction_type_sp[lp2 & 0x01][k]) { case 0: - cur_lp[0] = FROM_LE_32(((FROM_LE_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1); - cur_lp[width_tbl[1]] = FROM_LE_32(((FROM_LE_32(ref_lp[width_tbl[1]]) >> 1) + correction_lp[lp2 & 0x01][k]) << 1); + cur_lp[0] = FROM_LE_32(((READ_LE_UINT32(ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1); + cur_lp[width_tbl[1]] = FROM_LE_32(((READ_LE_UINT32(ref_lp+width_tbl[1]) >> 1) + correction_lp[lp2 & 0x01][k]) << 1); lp2++; break; @@ -1051,13 +1056,13 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, lv1 = (uint16)(correction_lp[lp2 & 0x01][*buf1++]); lv2 = (uint16)(correction_lp[lp2 & 0x01][k]); - res = (uint16)(((FROM_LE_16(((uint16 *)ref_lp)[0]) >> 1) + lv1) << 1); + res = (uint16)(((READ_LE_UINT16(((uint16 *)ref_lp)) >> 1) + lv1) << 1); ((uint16 *)cur_lp)[0] = FROM_LE_16(res); - res = (uint16)(((FROM_LE_16(((uint16 *)ref_lp)[1]) >> 1) + lv2) << 1); + res = (uint16)(((READ_LE_UINT16(((uint16 *)ref_lp)+1) >> 1) + lv2) << 1); ((uint16 *)cur_lp)[1] = FROM_LE_16(res); - res = (uint16)(((FROM_LE_16(((uint16 *)ref_lp)[width_tbl[2]]) >> 1) + lv1) << 1); + res = (uint16)(((READ_LE_UINT16(((uint16 *)ref_lp)+width_tbl[2]) >> 1) + lv1) << 1); ((uint16 *)cur_lp)[width_tbl[2]] = FROM_LE_16(res); - res = (uint16)(((FROM_LE_16(((uint16 *)ref_lp)[width_tbl[2]+1]) >> 1) + lv2) << 1); + res = (uint16)(((READ_LE_UINT16(((uint16 *)ref_lp)+width_tbl[2]+1) >> 1) + lv2) << 1); ((uint16 *)cur_lp)[width_tbl[2]+1] = FROM_LE_16(res); lp2++; break; @@ -1065,7 +1070,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, case 2: if (lp2 == 0) { for (i = 0, j = 0; i < 4; i++, j += width_tbl[1]) - cur_lp[j] = ref_lp[j]; + cur_lp[j] = READ_UINT32(ref_lp+j); lp2 += 2; } break; @@ -1073,7 +1078,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, case 3: if (lp2 < 2) { for (i = 0, j = 0; i < 6 - (lp2 * 2); i++, j += width_tbl[1]) - cur_lp[j] = ref_lp[j]; + cur_lp[j] = READ_UINT32(ref_lp+j); lp2 = 3; } break; @@ -1083,7 +1088,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, RLE_V3_CHECK(buf1,rle_v1,rle_v2,rle_v3) for (i = 0, j = 0; i < 8; i++, j += width_tbl[1]) - cur_lp[j] = ref_lp[j]; + cur_lp[j] = READ_UINT32(ref_lp+j); RLE_V2_CHECK(buf1,rle_v2, rle_v3,lp2) break; @@ -1097,7 +1102,7 @@ void Indeo3Decoder::decodeChunk(byte *cur, byte *ref, int width, int height, case 4: case 6: for (i = 0, j = 0; i < 8 - (lp2 * 2); i++, j += width_tbl[1]) - cur_lp[j] = ref_lp[j]; + cur_lp[j] = READ_UINT32(ref_lp+j); lp2 = 4; break; diff --git a/image/codecs/rpza.cpp b/image/codecs/rpza.cpp index 8d648e1cc1..db0d512f45 100644 --- a/image/codecs/rpza.cpp +++ b/image/codecs/rpza.cpp @@ -50,6 +50,7 @@ RPZADecoder::~RPZADecoder() { } delete[] _ditherPalette; + delete[] _colorMap; } #define ADVANCE_BLOCK() \ diff --git a/po/be_BY.po b/po/be_BY.po index 9f72e650d2..5b80dc19aa 100644 --- a/po/be_BY.po +++ b/po/be_BY.po @@ -7,16 +7,17 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.8.0git\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" -"PO-Revision-Date: 2016-02-02 23:16+0300\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" +"PO-Revision-Date: 2016-02-21 23:32+0300\n" "Last-Translator: Ivan Lukyanov <greencis@mail.ru>\n" "Language-Team: Ivan Lukyanov <greencis@mail.ru>\n" "Language: Belarusian\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-5\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Poedit 1.8.6\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Poedit 1.8.7\n" #: gui/about.cpp:94 #, c-format @@ -37,7 +38,7 @@ msgstr "¿ÐÚÐ×ÒÐæì áåÐÒÐÝëï äÐÙÛë" #: gui/browser.cpp:68 msgid "Show files marked with the hidden attribute" -msgstr "¿ÐÚÐ×ÒÐæì äÐÙÛë × ÐâàëÑãâÐÜ \"áåÐÒÐæì\"" +msgstr "¿ÐÚÐ×ÒÐæì äÐÙÛë × ÐâàëÑãâÐÜ \"áåÐÒÐÝë\"" #: gui/browser.cpp:72 msgid "Go up" @@ -190,11 +191,11 @@ msgstr "»öÝÕÙÝÐï" #: gui/fluidsynth-dialog.cpp:145 msgid "Fourth-order" -msgstr "ÇÐæÒñàâÐÓÐ ßÐàÐÔÚÐ" +msgstr "ÇÐæÒñàâÐÓÐ ßÐàÐÔÚã" #: gui/fluidsynth-dialog.cpp:146 msgid "Seventh-order" -msgstr "ÁñÜÐÓÐ ßÐàÐÔÚÐ" +msgstr "ÁñÜÐÓÐ ßÐàÐÔÚã" #: gui/fluidsynth-dialog.cpp:150 msgid "Reset" @@ -224,7 +225,8 @@ msgid "OK" msgstr "OK" #: gui/fluidsynth-dialog.cpp:217 -msgid "Do you really want to reset all FluidSynth settings to their default values?" +msgid "" +"Do you really want to reset all FluidSynth settings to their default values?" msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ áÚöÝãæì ÝÐÛÐÔë FluidSynth ßÐ ×ÜÐþçÐÝÝö?" #: gui/gui-manager.cpp:119 backends/keymapper/remap-dialog.cpp:53 @@ -289,8 +291,12 @@ 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 "ºÐàÞâÚö öÔíÝâëäöÚÐâÐà, ÒëÚÐàëáâÞþÒÐÝë ÔÛï öÜñÝÐþ ×ÐåÐÒÐÝÝïþ ÓãÛìÝïþ ö ÔÛï ×ÐßãáÚã × ÚÐÜÐÝÔÝÐÓÐ àÐÔÚÐ" +msgid "" +"Short game identifier used for referring to saved games and running the game " +"from the command line" +msgstr "" +"ºÐàÞâÚö öÔíÝâëäöÚÐâÐà, ÒëÚÐàëáâÞþÒÐÝë ÔÛï öÜñÝÐþ ×ÐåÐÒÐÝÝïþ ÓãÛìÝïþ ö ÔÛï " +"×ÐßãáÚã × ÚÐÜÐÝÔÝÐÓÐ àÐÔÚÐ" #: gui/launcher.cpp:199 msgctxt "lowres" @@ -311,8 +317,12 @@ msgid "Language:" msgstr "¼ÞÒÐ:" #: gui/launcher.cpp:210 gui/launcher.cpp:211 -msgid "Language of the game. This will not turn your Spanish game version into English" -msgstr "¼ÞÒÐ ÓãÛìÝö. ·ÜÕÝÐ ÓíâÐÙ ÝÐÛÐÔë ÝÕ ßÕàÐâÒÞàëæì àãáÚãî ÒÕàáöî ÓãÛìÝö þ ÑÕÛÐàãáÚãî" +msgid "" +"Language of the game. This will not turn your Spanish game version into " +"English" +msgstr "" +"¼ÞÒÐ ÓãÛìÝö. ·ÜÕÝÐ ÓíâÐÙ ÝÐÛÐÔë ÝÕ ßÕàÐâÒÞàëæì àãáÚãî ÒÕàáöî ÓãÛìÝö þ " +"ÑÕÛÐàãáÚãî" #: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87 #: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208 @@ -580,23 +590,27 @@ msgid "Search:" msgstr "¿ÞèãÚ:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "·ÐÓàã×öæì ÓãÛìÝî:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "·ÐÓàã×öæì" #: 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 "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ×Ðßãáæöæì ÔíâíÚâÐà ãáöå ÓãÛìÝïþ? ³íâÐ ßÐâíÝæëïÛìÝÐ ÜÞÖÐ ÔÐÔÐæì ÒïÛöÚãî ÚÞÛìÚÐáæì ÓãÛìÝïþ." +msgid "" +"Do you really want to run the mass game detector? This could potentially add " +"a huge number of games." +msgstr "" +"²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ×Ðßãáæöæì ÔíâíÚâÐà ãáöå ÓãÛìÝïþ? ³íâÐ ßÐâíÝæëïÛìÝÐ ÜÞÖÐ " +"ÔÐÔÐæì ÒïÛöÚãî ÚÞÛìÚÐáæì ÓãÛìÝïþ." #: gui/launcher.cpp:843 msgid "ScummVM couldn't open the specified directory!" @@ -748,7 +762,7 @@ msgid "Special dithering modes supported by some games" msgstr "ÁßÕæëïÛìÝëï àíÖëÜë àíÝÔíàëÝÓã, ßÐÔâàëÜÞþÒÐÝëï ÝÕÚÐâÞàëÜö ÓãÛìÝïÜö" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "¿ÞþÝÐíÚàÐÝÝë àíÖëÜ" @@ -799,8 +813,12 @@ msgid "Output rate:" msgstr "ÇÐèçëÝï ÓãÚã:" #: gui/options.cpp:809 gui/options.cpp:810 -msgid "Higher value specifies better sound quality but may be not supported by your soundcard" -msgstr "±ÞÛìèëï ×ÝÐçíÝÝö ×ÐÔÐîæì ÛÕßèãî ïÚÐáæì ÓãÚã, ÐÔÝÐÚ ïÝë ÜÞÓãæì ÝÕ ßÐÔâàëÜÛöÒÐææÐ ÒÐèÐÙ ÓãÚÐÒÞÙ ÚÐàâÐÙ" +msgid "" +"Higher value specifies better sound quality but may be not supported by your " +"soundcard" +msgstr "" +"±ÞÛìèëï ×ÝÐçíÝÝö ×ÐÔÐîæì ÛÕßèãî ïÚÐáæì ÓãÚã, ÐÔÝÐÚ ïÝë ÜÞÓãæì ÝÕ " +"ßÐÔâàëÜÛöÒÐææÐ ÒÐèÐÙ ÓãÚÐÒÞÙ ÚÐàâÐÙ" #: gui/options.cpp:820 msgid "GM Device:" @@ -824,7 +842,9 @@ 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 "SoundFont'ë ßÐÔâàëÜÛöÒÐîææÐ ÝÕÚÐâÞàëÜö ÓãÚÐÒëÜö ÚÐàâÐÜö, FluidSynth Ôë Timidity" +msgstr "" +"SoundFont'ë ßÐÔâàëÜÛöÒÐîææÐ ÝÕÚÐâÞàëÜö ÓãÚÐÒëÜö ÚÐàâÐÜö, FluidSynth Ôë " +"Timidity" #: gui/options.cpp:856 msgctxt "lowres" @@ -853,15 +873,21 @@ msgstr "½ÐÛ. MT-32:" #: gui/options.cpp:879 msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output" -msgstr "¿ÐÚÐ×ÒÐÕ ÓãÚÐÒãî ßàëÛÐÔã ßÐ ×ÜÐþçÐÝÝö ÔÛï ÒëÒÐÔã ÝÐ Roland MT-32/LAPC1/CM32l/CM64" +msgstr "" +"¿ÐÚÐ×ÒÐÕ ÓãÚÐÒãî ßàëÛÐÔã ßÐ ×ÜÐþçÐÝÝö ÔÛï ÒëÒÐÔã ÝÐ Roland MT-32/LAPC1/CM32l/" +"CM64" #: gui/options.cpp:884 msgid "True Roland MT-32 (disable GM emulation)" msgstr "ÁÐßàÐþÔÝë Roland MT-32 (×ÐÑÐàÐÝöæì íÜãÛïæëî GM)" #: 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 "°Ô×ÝÐçæÕ, ÚÐÛö þ ÒÐá ßÐÔÚÛîçÐÝÐ Roland-áãÜïèçÐÛìÝÐï ÓãÚÐÒÐï ßàëÛÐÔÐ ö Òë ÖÐÔÐÕæÕ ïÕ ÒëÚÐàëáâÞþÒÐæì" +msgid "" +"Check if you want to use your real hardware Roland-compatible sound device " +"connected to your computer" +msgstr "" +"°Ô×ÝÐçæÕ, ÚÐÛö þ ÒÐá ßÐÔÚÛîçÐÝÐ Roland-áãÜïèçÐÛìÝÐï ÓãÚÐÒÐï ßàëÛÐÔÐ ö Òë " +"ÖÐÔÐÕæÕ ïÕ ÒëÚÐàëáâÞþÒÐæì" #: gui/options.cpp:886 msgctxt "lowres" @@ -873,8 +899,12 @@ msgid "Roland GS Device (enable MT-32 mappings)" msgstr "ÀíÖëÜ Roland GS (ÔÐ×ÒÞÛöæì ÜÐßöÝÓ MT-32)" #: gui/options.cpp:889 -msgid "Check if you want to enable patch mappings to emulate an MT-32 on a Roland GS device" -msgstr "°Ô×ÝÐçæÕ, ÚÐÛö ÖÐÔÐÕæÕ ÔÐ×ÒÞÛöæì ÜÐßöÝÓ ÔÛï íÜãÛïæëö MT-32 ÝÐ ßàëÛÐÔ×Õ Rolans GS" +msgid "" +"Check if you want to enable patch mappings to emulate an MT-32 on a Roland " +"GS device" +msgstr "" +"°Ô×ÝÐçæÕ, ÚÐÛö ÖÐÔÐÕæÕ ÔÐ×ÒÞÛöæì ÜÐßöÝÓ ÔÛï íÜãÛïæëö MT-32 ÝÐ ßàëÛÐÔ×Õ " +"Rolans GS" #: gui/options.cpp:898 msgid "Don't use Roland MT-32 music" @@ -973,7 +1003,9 @@ msgstr "ÈÛïå ÔÐ âíÜ:" #: 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 "¿ÐÚÐ×ÒÐÕ èÛïå ÔÐ ÔÐÔÐâÚÞÒëå äÐÙÛÐþ ÔÐÔ×ÕÝëå, ÒëÚÐàëáâÞþÒÐÝëå ãáöÜö ÓãÛìÝïÜö ÐÑÞ ScummVM" +msgstr "" +"¿ÐÚÐ×ÒÐÕ èÛïå ÔÐ ÔÐÔÐâÚÞÒëå äÐÙÛÐþ ÔÐÔ×ÕÝëå, ÒëÚÐàëáâÞþÒÐÝëå ãáöÜö ÓãÛìÝïÜö " +"ÐÑÞ ScummVM" #: gui/options.cpp:1157 msgid "Plugins Path:" @@ -1039,8 +1071,12 @@ msgid "Select directory for plugins" msgstr "°ÑïàëæÕ ÔëàíÚâÞàëî × ßÛÐÓöÝÐÜö" #: 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 "ÂíÜÐ, ÐÑàÐÝÐï ÒÐÜö, ÝÕ ßÐÔâàëÜÛöÒÐÕ ÑïÓãçãî ÜÞÒã. ºÐÛö Òë ÖÐÔÐÕæÕ ÒëÚÐàëáâÞþÒÐæì Óíâãî âíÜã, ÒÐÜ ÝÕÐÑåÞÔÝÐ áßÐçÐâÚã ßÕàÐÚÛîçëææÐ ÝÐ öÝèãî ÜÞÒã." +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 "" +"ÂíÜÐ, ÐÑàÐÝÐï ÒÐÜö, ÝÕ ßÐÔâàëÜÛöÒÐÕ ÑïÓãçãî ÜÞÒã. ºÐÛö Òë ÖÐÔÐÕæÕ " +"ÒëÚÐàëáâÞþÒÐæì Óíâãî âíÜã, ÒÐÜ ÝÕÐÑåÞÔÝÐ áßÐçÐâÚã ßÕàÐÚÛîçëææÐ ÝÐ öÝèãî ÜÞÒã." #. I18N: You must leave "#" as is, only word 'next' is translatable #: gui/predictivedialog.cpp:86 @@ -1324,12 +1360,12 @@ msgstr "PC-9821 (256 ÚÞÛÕàÐþ)" msgid "PC-9801 (16 Colors)" msgstr "PC-9801 (16 ÚÞÛÕàÐþ)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Hercules ·ïÛñÝë" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Hercules ±ãàèâëÝÐÒë" @@ -1341,7 +1377,8 @@ msgstr "·ÔÐÕææÐ, èâÞ ÓãÛìÝï '%s' ïèçí ÝÕÒïÔÞÜÐ." #: engines/advancedDetector.cpp:318 msgid "Please, report the following data to the ScummVM team along with name" -msgstr "ºÐÛö ÛÐáÚÐ, ßÕàÐÔÐÙæÕ ÝÐáâãßÝëï ÔÐÔ×ÕÝëï ÚÐÜÐÝÔ×Õ ScummVM àÐ×ÐÜ × ÝÐ×ÒÐÙ" +msgstr "" +"ºÐÛö ÛÐáÚÐ, ßÕàÐÔÐÙæÕ ÝÐáâãßÝëï ÔÐÔ×ÕÝëï ÚÐÜÐÝÔ×Õ ScummVM àÐ×ÐÜ × ÝÐ×ÒÐÙ" #: engines/advancedDetector.cpp:320 msgid "of the game you tried to add and its version/language/etc.:" @@ -1380,11 +1417,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "³~Ð~ÛÞþÝÐÕ ÜÕÝî" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "·ÐåÐÒÐæì ÓãÛìÝî:" @@ -1393,22 +1434,37 @@ msgstr "·ÐåÐÒÐæì ÓãÛìÝî:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "·ÐåÐÒÐæì" #: 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 "¿àÐÑÐçæÕ, ÐÛÕ Óíâë àãåÐÒöçÞÚ ßÐÚãÛì ÝÕ ßÐÔÐÕ ÔÐßÐÜÞÓö þÝãâàë ÓãÛìÝö. ºÐÛö ÛÐáÚÐ, ×ÒïàÝöæÕáï ÔÐ äÐÙÛÐ README ×Ð ÑÐ×ÐÒÐÙ öÝäÐàÜÐæëïÙ, Ð âÐÚáÐÜÐ öÝáâàãÚæëïÜö ßàÐ âÞÕ, ïÚ ÐâàëÜÐæì ÔÐÛÕÙèãî ÔÐßÐÜÞÓã." +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 "" +"¿àÐÑÐçæÕ, ÐÛÕ Óíâë àãåÐÒöçÞÚ ßÐÚãÛì ÝÕ ßÐÔÐÕ ÔÐßÐÜÞÓö þÝãâàë ÓãÛìÝö. ºÐÛö " +"ÛÐáÚÐ, ×ÒïàÝöæÕáï ÔÐ äÐÙÛÐ README ×Ð ÑÐ×ÐÒÐÙ öÝäÐàÜÐæëïÙ, Ð âÐÚáÐÜÐ " +"öÝáâàãÚæëïÜö ßàÐ âÞÕ, ïÚ ÐâàëÜÐæì ÔÐÛÕÙèãî ÔÐßÐÜÞÓã." #: 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 "½Õ ÐâàëÜÐÛÐáï ×ÐåÐÒÐæì ÓãÛìÝî (%s)! ºÐÛö ÛÐáÚÐ, ×ÒïàÝöæÕáï ÔÐ äÐÙÛÐ README ×Ð ÑÐ×ÐÒÐÙ öÝäÐàÜÐæëïÙ, Ð âÐÚáÐÜÐ öÝáâàãÚæëïÜö ßàÐ âÞÕ, ïÚ ÐâàëÜÐæì ÔÐÛÕÙèãî ÔÐßÐÜÞÓã." +msgid "" +"Gamestate save failed (%s)! Please consult the README for basic information, " +"and for instructions on how to obtain further assistance." +msgstr "" +"½Õ ÐâàëÜÐÛÐáï ×ÐåÐÒÐæì ÓãÛìÝî (%s)! ºÐÛö ÛÐáÚÐ, ×ÒïàÝöæÕáï ÔÐ äÐÙÛÐ README " +"×Ð ÑÐ×ÐÒÐÙ öÝäÐàÜÐæëïÙ, Ð âÐÚáÐÜÐ öÝáâàãÚæëïÜö ßàÐ âÞÕ, ïÚ ÐâàëÜÐæì ÔÐÛÕÙèãî " +"ÔÐßÐÜÞÓã." #: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109 #: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106 @@ -1441,24 +1497,28 @@ msgid "Could not apply fullscreen setting." msgstr "½Õ ÜÐÓã þÖëæì ßÞþÝÐíÚàÐÝÝë àíÖëÜ." #: engines/engine.cpp:461 -msgid "You appear to be playing this game directly\n" +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 "·ÔÐÕææÐ, Òë áßàÐÑãÕæÕ ×Ðßãáæöæì Óíâã ÓãÛìÝî ßàÐÜÐ\n" +msgstr "" +"·ÔÐÕææÐ, Òë áßàÐÑãÕæÕ ×Ðßãáæöæì Óíâã ÓãÛìÝî ßàÐÜÐ\n" "× CD. ³íâÐ ×ÒëçÐÙÝÐ ÒëÚÛöÚÐÕ ßàÐÑÛÕÜë, ö âÐÜã\n" "Üë àíÚÐÜÕÝÔãÕÜ áÚÐßöïÒÐæì äÐÙÛë ÔÐÔ×ÕÝëå ÓãÛìÝö\n" "ÝÐ ÖÞàáâÚö ÔëáÚ. ¿ÐÔàÐÑï×ÝÐáæö ÜÞÖÝÐ ×ÝÐÙáæö þ\n" "äÐÙÛÕ README." #: engines/engine.cpp:472 -msgid "This game has audio tracks in its disk. These\n" +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 "´ëáÚ ÓíâÐÙ ÓãÛìÝö þâàëÜÞþÒÐÕ ÓãÚÐÒëï ÔÐàÞÖÚö. ¦å\n" +msgstr "" +"´ëáÚ ÓíâÐÙ ÓãÛìÝö þâàëÜÞþÒÐÕ ÓãÚÐÒëï ÔÐàÞÖÚö. ¦å\n" "ÝÕÐÑåÞÔÝÐ ßÕàÐßöáÐæì × ÔëáÚÐ × ÔÐßÐÜÞÓÐÙ\n" "ÐÔßÐÒÕÔÝÐÙ ßàÐÓàÐÜë ÔÛï ÚÐßöïÒÐÝÝï\n" "ÐþÔëñ ÔëáÚÐþ, ö âÞÛìÚö ßÐáÛï ÓíâÐÓÐ þ ÓãÛìÝö\n" @@ -1467,12 +1527,23 @@ msgstr "´ëáÚ ÓíâÐÙ ÓãÛìÝö þâàëÜÞþÒÐÕ ÓãÚÐÒëï ÔÐàÞÖÚö. ¦å\n" #: 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 "½Õ ÐâàëÜÐÛÐáï ßàÐçëâÐæì ×ÐåÐÒÐÝÝÕ ÓãÛìÝö (%s)! ºÐÛö ÛÐáÚÐ, ×ÒïàÝöæÕáï þ äÐÙÛ README ×Ð ÑÐ×ÐÒÐÙ öÝäÐàÜÐæëïÙ, Ð âÐÚáÐÜÐ öÝáâàãÚæëïÜö ßàÐ âÞÕ, ïÚ ÐâàëÜÐæì ÔÐÛÕÙèãî ÔÐßÐÜÞÓã." +msgid "" +"Gamestate load failed (%s)! Please consult the README for basic information, " +"and for instructions on how to obtain further assistance." +msgstr "" +"½Õ ÐâàëÜÐÛÐáï ßàÐçëâÐæì ×ÐåÐÒÐÝÝÕ ÓãÛìÝö (%s)! ºÐÛö ÛÐáÚÐ, ×ÒïàÝöæÕáï þ äÐÙÛ " +"README ×Ð ÑÐ×ÐÒÐÙ öÝäÐàÜÐæëïÙ, Ð âÐÚáÐÜÐ öÝáâàãÚæëïÜö ßàÐ âÞÕ, ïÚ ÐâàëÜÐæì " +"ÔÐÛÕÙèãî ÔÐßÐÜÞÓã." #: 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 "¿°¿ÏÀÍ´¶°½½µ: ³ãÛìÝï, ïÚãî Òë ×ÑöàÐÕæÕáï ×Ðßãáæöæì, ïèçí ÝÕ ßÐÔâàëÜÛöÒÐÕææÐ ScummVM æÐÛÚÐÜ. ÏÝÐ, åãâçíÙ ×Ð þáñ, ÝÕ ÑãÔ×Õ ßàÐæÐÒÐæì áâÐÑöÛìÝÐ, ö ×ÐåÐÒÐÝÝö ÓãÛìÝïþ ÜÞÓãæì ÝÕ ßàÐæÐÒÐæì ã ÑãÔãçëå ÒÕàáöïå ScummVM." +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 "" +"¿°¿ÏÀÍ´¶°½½µ: ³ãÛìÝï, ïÚãî Òë ×ÑöàÐÕæÕáï ×Ðßãáæöæì, ïèçí ÝÕ ßÐÔâàëÜÛöÒÐÕææÐ " +"ScummVM æÐÛÚÐÜ. ÏÝÐ, åãâçíÙ ×Ð þáñ, ÝÕ ÑãÔ×Õ ßàÐæÐÒÐæì áâÐÑöÛìÝÐ, ö " +"×ÐåÐÒÐÝÝö ÓãÛìÝïþ ÜÞÓãæì ÝÕ ßàÐæÐÒÐæì ã ÑãÔãçëå ÒÕàáöïå ScummVM." #: engines/engine.cpp:546 msgid "Start anyway" @@ -1496,8 +1567,12 @@ msgstr "¿àÐÜë FM ALSA" #: audio/mididrv.cpp:209 #, c-format -msgid "The selected audio device '%s' was not found (e.g. might be turned off or disconnected)." -msgstr "°ÑàÐÝÐï ÓãÚÐÒÐï ßàëÛÐÔÐ '%s' ÝÕ ÑëÛÐ ×ÝÞÙÔ×ÕÝÐ (ÜÐÓçëÜÐ, ïÝÐ ÒëÚÛîçÐÝÐ æö ÝÕ ßÐÔÚÛîçÐÝÐ)." +msgid "" +"The selected audio device '%s' was not found (e.g. might be turned off or " +"disconnected)." +msgstr "" +"°ÑàÐÝÐï ÓãÚÐÒÐï ßàëÛÐÔÐ '%s' ÝÕ ÑëÛÐ ×ÝÞÙÔ×ÕÝÐ (ÜÐÓçëÜÐ, ïÝÐ ÒëÚÛîçÐÝÐ æö ÝÕ " +"ßÐÔÚÛîçÐÝÐ)." #: audio/mididrv.cpp:209 audio/mididrv.cpp:221 audio/mididrv.cpp:257 #: audio/mididrv.cpp:272 @@ -1506,18 +1581,30 @@ msgstr "ÁßàÐÑãî ÒëÚÐàëáâÐæì öÝèãî ÔÐáâãßÝãî ßàëÛÐÔã..." #: audio/mididrv.cpp:221 #, c-format -msgid "The selected audio device '%s' cannot be used. See log file for more information." -msgstr "°ÑàÐÝÐï ÓãÚÐÒÐï ßàëÛÐÔÐ '%s' ÝÕ ÜÞÖÐ Ñëæì áÚÐàëáâÐÝÐ. ³ÛïÔ×öæÕ äÐÙÛ ßàÐâÐÚÞÛã ÔÛï ÑÞÛìè ßÐÔàÐÑï×ÝÐÙ öÝäÐàÜÐæëö." +msgid "" +"The selected audio device '%s' cannot be used. See log file for more " +"information." +msgstr "" +"°ÑàÐÝÐï ÓãÚÐÒÐï ßàëÛÐÔÐ '%s' ÝÕ ÜÞÖÐ Ñëæì áÚÐàëáâÐÝÐ. ³ÛïÔ×öæÕ äÐÙÛ " +"ßàÐâÐÚÞÛã ÔÛï ÑÞÛìè ßÐÔàÐÑï×ÝÐÙ öÝäÐàÜÐæëö." #: audio/mididrv.cpp:257 #, c-format -msgid "The preferred audio device '%s' was not found (e.g. might be turned off or disconnected)." -msgstr "¿ÕàÐÒÐÖÝÐï ÓãÚÐÒÐï ßàëÛÐÔÐ '%s' ÝÕ ÑëÛÐ ×ÝÞÙÔ×ÕÝÐ (ÜÐÓçëÜÐ, ïÝÐ ÒëÚÛîçÐÝÐ æö ÝÕ ßÐÔÚÛîçÐÝÐ)." +msgid "" +"The preferred audio device '%s' was not found (e.g. might be turned off or " +"disconnected)." +msgstr "" +"¿ÕàÐÒÐÖÝÐï ÓãÚÐÒÐï ßàëÛÐÔÐ '%s' ÝÕ ÑëÛÐ ×ÝÞÙÔ×ÕÝÐ (ÜÐÓçëÜÐ, ïÝÐ ÒëÚÛîçÐÝÐ æö " +"ÝÕ ßÐÔÚÛîçÐÝÐ)." #: audio/mididrv.cpp:272 #, c-format -msgid "The preferred audio device '%s' cannot be used. See log file for more information." -msgstr "¿ÕàÐÒÐÖÝÐï ÓãÚÐÒÐï ßàëÛÐÔÐ '%s' ÝÕ ÜÞÖÐ Ñëæì áÚÐàëáâÐÝÐ. ³ÛïÔ×öæÕ äÐÙÛ ßàÐâÐÚÞÛã ÔÛï ÑÞÛìè ßÐÔàÐÑï×ÝÐÙ öÝäÐàÜÐæëö." +msgid "" +"The preferred audio device '%s' cannot be used. See log file for more " +"information." +msgstr "" +"¿ÕàÐÒÐÖÝÐï ÓãÚÐÒÐï ßàëÛÐÔÐ '%s' ÝÕ ÜÞÖÐ Ñëæì áÚÐàëáâÐÝÐ. ³ÛïÔ×öæÕ äÐÙÛ " +"ßàÐâÐÚÞÛã ÔÛï ÑÞÛìè ßÐÔàÐÑï×ÝÐÙ öÝäÐàÜÐæëö." #: audio/mods/paula.cpp:196 msgid "Amiga Audio Emulator" @@ -1683,19 +1770,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "±Õ× ßÐÒÕÛöçíÝÝï" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "ºÐàíÚæëï áãÐÔÝÞáöÝ ÑÐÚÞþ ãÚÛîçÐÝÐ" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "ºÐàíÚæëï áãÐÔÝÞáöÝ ÑÐÚÞþ ÒëÚÛîçÐÝÐ" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "°ÚâëþÝë ÓàÐäöçÝë äöÛìâà:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "°ÚÞÝÝë àíÖëÜ" @@ -2193,7 +2280,8 @@ msgstr "¿àë×ÝÐçëæì Ô×ÕïÝÝÕ ßÐ ßàÐÒÐÙ ßáâàëçæë" #: backends/platform/wince/wince-sdl.cpp:520 msgid "You must map a key to the 'Right Click' action to play this game" -msgstr "²ë ßÐÒöÝÝë ßàë×ÝÐçëæì ÚÛÐÒöèã ÝÐ Ô×ÕïÝÝÕ 'Right Click' ÔÛï ÓíâÐÙ ÓãÛìÝö" +msgstr "" +"²ë ßÐÒöÝÝë ßàë×ÝÐçëæì ÚÛÐÒöèã ÝÐ Ô×ÕïÝÝÕ 'Right Click' ÔÛï ÓíâÐÙ ÓãÛìÝö" #: backends/platform/wince/wince-sdl.cpp:529 msgid "Map hide toolbar action" @@ -2201,7 +2289,8 @@ msgstr "¿àë×ÝÐçëæì Ô×ÕïÝÝÕ 'áåÐÒÐæì ßÐÝíÛì öÝáâàãÜÕÝâÐþ'" #: backends/platform/wince/wince-sdl.cpp:533 msgid "You must map a key to the 'Hide toolbar' action to play this game" -msgstr "²ë ßÐÒöÝÝë ßàë×ÝÐçëæì ÚÛÐÒöèã ÝÐ Ô×ÕïÝÝÕ 'Hide toolbar' ÔÛï ÓíâÐÙ ÓãÛìÝö" +msgstr "" +"²ë ßÐÒöÝÝë ßàë×ÝÐçëæì ÚÛÐÒöèã ÝÐ Ô×ÕïÝÝÕ 'Hide toolbar' ÔÛï ÓíâÐÙ ÓãÛìÝö" #: backends/platform/wince/wince-sdl.cpp:542 msgid "Map Zoom Up action (optional)" @@ -2212,8 +2301,11 @@ msgid "Map Zoom Down action (optional)" msgstr "¿àë×ÝÐçëæì Ô×ÕïÝÝÕ ¿ÐÜÕÝèëæì ¼ÐèâÐÑ (ÝÕÐÑÐÒï×ÚÞÒÐ)" #: 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 "½Õ ×ÐÑãÔ×ìæÕáï ßàë×ÝÐçëæì ÚÛÐÒöèã ÔÛï Ô×ÕïÝÝï 'Hide Toolbar', ÚÐÑ ãÑÐçëæì ãÒÕáì öÝÒÕÝâÐà ã ÓãÛìÝö" +msgid "" +"Don't forget to map a key to 'Hide Toolbar' action to see the whole inventory" +msgstr "" +"½Õ ×ÐÑãÔ×ìæÕáï ßàë×ÝÐçëæì ÚÛÐÒöèã ÔÛï Ô×ÕïÝÝï 'Hide Toolbar', ÚÐÑ ãÑÐçëæì " +"ãÒÕáì öÝÒÕÝâÐà ã ÓãÛìÝö" #: backends/updates/macosx/macosx-updates.mm:67 msgid "Check for Updates..." @@ -2224,67 +2316,90 @@ msgstr "¿àÐÒïàÐî ÐÑÝÐþÛÕÝÝö..." #: 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 "²ëÚÐàëáâÞþÒÐæì ÐàëÓöÝÐÛìÝëï íÚàÐÝë ×Ðßöáã/çëâÐÝÝö ÓãÛìÝö" +msgstr "²ëÚÐàëáâÞþÒÐæì ÐàëÓöÝÐÛìÝëï íÚàÐÝë ×Ðßöáã/çëâÐÝÝï ÓãÛìÝö" #: 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 "²ëÚÐàëáâÞþÒÐæì ÐàëÓöÝÐÛìÝëï íÚàÐÝë ×Ðßöáã ö ×ÐåÐÒÐÝÝï ÓãÛìÝö ×ÐÜÕáâ ×àÞÑÛÕÝëå ã ScummVM" +msgstr "" +"²ëÚÐàëáâÞþÒÐæì ÐàëÓöÝÐÛìÝëï íÚàÐÝë çëâÐÝÝï ö ×ÐåÐÒÐÝÝï ÓãÛìÝö ×ÐÜÕáâ " +"×àÞÑÛÕÝëå ã ScummVM" #: engines/agi/detection.cpp:157 msgid "Use an alternative palette" msgstr "²ëÚÐàëáâÞþÒÐæì ÐÛìâíàÝÐâëþÝãî ßÐÛöâàã" #: engines/agi/detection.cpp:158 -msgid "Use an alternative palette, common for all Amiga games. This was the old behavior" -msgstr "²ëÚÐàëáâÞþÒÐæì ÐÛìâíàÝÐâëþÝãî ßÐÛöâàã ÔÛï þáöå ÓãÛìÝïþ Amiga. ³íâÐ ÑëÛö áâÐàëï ßÐÒÞÔ×öÝë" +msgid "" +"Use an alternative palette, common for all Amiga games. This was the old " +"behavior" +msgstr "" +"²ëÚÐàëáâÞþÒÐæì ÐÛìâíàÝÐâëþÝãî ßÐÛöâàã ÔÛï þáöå ÓãÛìÝïþ Amiga. ³íâÐ ÑëÛö " +"áâÐàëï ßÐÒÞÔ×öÝë" #: engines/agi/detection.cpp:167 msgid "Mouse support" msgstr "¿ÐÔâàëÜÚÐ Üëèë" #: engines/agi/detection.cpp:168 -msgid "Enables mouse support. Allows to use mouse for movement and in game menus." -msgstr "ÃÚÛîçÐÕ ßÐÔâàëÜÚã Üëèë. ´Ð×ÒÐÛïÕ ÒëÚÐàëáâÞþÒÐæì Üëè ÔÛï ßÕàÐÜïèçíÝÝï ö þ ÜÕÝî ÓãÛìÝö." - -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +msgid "" +"Enables mouse support. Allows to use mouse for movement and in game menus." +msgstr "" +"ÃÚÛîçÐÕ ßÐÔâàëÜÚã Üëèë. ´Ð×ÒÐÛïÕ ÒëÚÐàëáâÞþÒÐæì Üëè ÔÛï ßÕàÐÜïèçíÝÝï ö þ " +"ÜÕÝî ÓãÛìÝö." + +#: 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 "Ã×ÝÐÒöæì ÓãÛìÝî:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Ã×ÝÐÒöæì" #: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377 #, c-format -msgid "Failed to load game state from file:\n" +msgid "" +"Failed to load game state from file:\n" "\n" "%s" -msgstr "½Õ ÐâàëÜÐÛÐáï ×ÐÓàã×öæì ÓãÛìÝî × äÐÙÛÐ:\n" +msgstr "" +"½Õ ÐâàëÜÐÛÐáï ×ÐÓàã×öæì ÓãÛìÝî × äÐÙÛÐ:\n" "\n" "%s" #: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370 #, c-format -msgid "Failed to save game state to file:\n" +msgid "" +"Failed to save game state to file:\n" "\n" "%s" -msgstr "½Õ ÐâàëÜÐÛÐáï ×ÐßöáÐæì ÓãÛìÝî þ äÐÙÛ:\n" +msgstr "" +"½Õ ÐâàëÜÐÛÐáï ×ÐßöáÐæì ÓãÛìÝî þ äÐÙÛ:\n" "\n" "%s" #: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388 #, c-format -msgid "Successfully saved game state in file:\n" +msgid "" +"Successfully saved game state in file:\n" "\n" "%s" -msgstr "³ãÛìÝï ßÐáßïåÞÒÐ ×ÐåÐÒÐÝÐ þ äÐÙÛ:\n" +msgstr "" +"³ãÛìÝï ßÐáßïåÞÒÐ ×ÐåÐÒÐÝÐ þ äÐÙÛ:\n" "\n" "%s" @@ -2302,16 +2417,21 @@ msgid "Enable Color Blind Mode by default" msgstr "ÃÚÛîçëæì àíÖëÜ ÔÛï ÛîÔ×ÕÙ áÐ áÛÐÑëÜ ãáßàëÜÐÝÝÕÜ ÚÞÛÕàã" #: 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" +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 ÒëïÒöþ ã ÒÐá ×ÐåÐÒÐÝÝö ÓãÛìÝö Drascula ã áâÐàëÜ äÐàÜÐæÕ.\n" -"ÁâÐàë äÐàÜÐâ ÑÞÛìè ÝÕ ßÐÔâàëÜÛöÒÐÕææÐ, ö, ÚÐÑ ×ÐÓàã×öæì ×ÐåÐÒÐÝÝö, ïÝë ßÐÒöÝÝë Ñëæì ßÕàÐÒÕÔ×ÕÝë þ ÝÞÒë äÐàÜÐâ.\n" +"Press OK to convert them now, otherwise you will be asked again the next " +"time you start the game.\n" +msgstr "" +"ScummVM ÒëïÒöþ ã ÒÐá ×ÐåÐÒÐÝÝö ÓãÛìÝö Drascula ã áâÐàëÜ äÐàÜÐæÕ.\n" +"ÁâÐàë äÐàÜÐâ ÑÞÛìè ÝÕ ßÐÔâàëÜÛöÒÐÕææÐ, ö, ÚÐÑ ×ÐÓàã×öæì ×ÐåÐÒÐÝÝö, ïÝë " +"ßÐÒöÝÝë Ñëæì ßÕàÐÒÕÔ×ÕÝë þ ÝÞÒë äÐàÜÐâ.\n" "\n" -"½ÐæöáÝöæÕ ¾º, ÚÐÑ ßÕàÐÒÕáæö öå ã ÝÞÒë äÐàÜÐâ ×ÐàÐ×, ã ÐÔÒÐàÞâÝëÜ ÒëßÐÔÚã ÓíâÐ ßÐÒÕÔÐÜÛÕÝÝÕ ×'ïÒöææÐ ×ÝÞþ ßàë ÝÐáâãßÝëÜ ×ÐßãáÚã ÓãÛìÝö.\n" -"" +"½ÐæöáÝöæÕ ¾º, ÚÐÑ ßÕàÐÒÕáæö öå ã ÝÞÒë äÐàÜÐâ ×ÐàÐ×, ã ÐÔÒÐàÞâÝëÜ ÒëßÐÔÚã " +"ÓíâÐ ßÐÒÕÔÐÜÛÕÝÝÕ ×'ïÒöææÐ ×ÝÞþ ßàë ÝÐáâãßÝëÜ ×ÐßãáÚã ÓãÛìÝö.\n" #: engines/dreamweb/detection.cpp:57 msgid "Use bright palette mode" @@ -2462,12 +2582,14 @@ msgid "Choose Spell" msgstr "°ÑàÐæì ×ÐÓÐÒÞà" #: engines/kyra/sound_midi.cpp:477 -msgid "You appear to be using a General MIDI device,\n" +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 "·ÔÐÕææÐ, Òë áßàÐÑãÕæÕ ÒëÚÐàëáâÞþÒÐæì ßàëÛÐÔã\n" +msgstr "" +"·ÔÐÕææÐ, Òë áßàÐÑãÕæÕ ÒëÚÐàëáâÞþÒÐæì ßàëÛÐÔã\n" "General MIDI, ÐÛÕ ÓíâÐï ÓãÛìÝï ßÐÔâàëÜÛöÒÐÕ âÞÛìÚö\n" "Roland MT32 MIDI. ¼ë ßÐáßàÐÑãÕÜ ßÐÔÐÑàÐæì General\n" "MIDI-ßàëÛÐÔë, ßÐÔÞÑÝëï ÔÐ Roland MT32, ÐÛÕ\n" @@ -2476,42 +2598,45 @@ msgstr "·ÔÐÕææÐ, Òë áßàÐÑãÕæÕ ÒëÚÐàëáâÞþÒÐæì ßàëÛÐÔã\n" #: engines/kyra/saveload_eob.cpp:557 #, c-format -msgid "The following original save game file has been found in your game path:\n" +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 "½öÖíÙ×ÓÐÔÐÝë äÐÙÛ ×ÐåÐÒÐÝÝï × ÐàëÓöÝÐÛìÝÐÙ ÓãÛìÝö Ñëþ ×ÝÞÙÔ×ÕÝë þ ÒÐèÐÙ ÓãÛìÝïÒÞÙ ÔëàíÚâÞàëö:\n" +msgstr "" +"½öÖíÙ×ÓÐÔÐÝë äÐÙÛ ×ÐåÐÒÐÝÝï × ÐàëÓöÝÐÛìÝÐÙ ÓãÛìÝö Ñëþ ×ÝÞÙÔ×ÕÝë þ ÒÐèÐÙ " +"ÓãÛìÝïÒÞÙ ÔëàíÚâÞàëö:\n" "\n" "%s %s\n" "\n" "Æö ÖÐÔÐÕæÕ ÒëÚÐàëáâÞþÒÐæì ÓíâÐÕ ×ÐåÐÒÐÝÝÕ þ ScummVM?\n" "\n" -"" #: engines/kyra/saveload_eob.cpp:590 #, c-format -msgid "A save game file was found in the specified slot %d. Overwrite?\n" +msgid "" +"A save game file was found in the specified slot %d. Overwrite?\n" "\n" -"" -msgstr "à Ð×ÝÐçÐÝëÜ áÛÞæÕ %d ãÖÞ ñáæì ×ÐåÐÒÐÝÝÕ ÓãÛìÝö. ¿ÕàÐ×ÐßöáÐæì?\n" +msgstr "" +"à Ð×ÝÐçÐÝëÜ áÛÞæÕ %d ãÖÞ ñáæì ×ÐåÐÒÐÝÝÕ ÓãÛìÝö. ¿ÕàÐ×ÐßöáÐæì?\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" +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 ÐàëÓöÝÐÛìÝëå äÐÙÛÐþ ×ÐåÐÒÐÝÝï ÑëÛö ßÐáßïåÞÒÐ öÜßÐàâÐÒÐÝë þ ScummVM.\n" +msgstr "" +"%d ÐàëÓöÝÐÛìÝëå äÐÙÛÐþ ×ÐåÐÒÐÝÝï ÑëÛö ßÐáßïåÞÒÐ öÜßÐàâÐÒÐÝë þ ScummVM.\n" "ºÐÛö Òë ßÐÖÐÔÐÕæÕ öÜßÐàâÐÒÐæì ÐàëÓöÝÐÛìÝëï ×ÐåÐÒÐÝÝö, ÒÐÜ âàíÑÐ ÑãÔ×Õ\n" "ÐÔÚàëæì ÐÔÛÐÔÐçÝãî ÚÐÝáÞÛì ScummVM ö þÒÕáæö ÚÐÜÐÝÔã 'import_savefile'.\n" "\n" -"" #. I18N: Option for fast scene switching #: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167 @@ -2557,41 +2682,58 @@ msgstr "ÀÐáæïÓÒÐÕ ÒöÔíÐ ßàÐ áâÒÐàíÝÝÕ ÓãÛìÝö âÐÚ, èâÞ ïÝÞ ×ÐÙÜÐÕ þÒÕáì íÚàÐÝ" #: engines/parallaction/saveload.cpp:133 #, c-format -msgid "Can't save game in slot %i\n" +msgid "" +"Can't save game in slot %i\n" "\n" -"" -msgstr "½Õ ÜÐÓã ×ÐåÐÒÐæì ÓãÛìÝî þ ßÐ×öæëî %i\n" +msgstr "" +"½Õ ÜÐÓã ×ÐåÐÒÐæì ÓãÛìÝî þ ßÐ×öæëî %i\n" "\n" -"" + +#: engines/parallaction/saveload.cpp:197 +msgid "Load file" +msgstr "·ÐÓàã×öæì äÐÙÛ" #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "·ÐÓàãÖÐî ÓãÛìÝî..." +#: engines/parallaction/saveload.cpp:212 +msgid "Save file" +msgstr "·ÐåÐÒÐæì äÐÙÛ" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "·ÐåÞþÒÐî ÓãÛìÝî..." #: 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" +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 ×ÝÐÙèÞþ ã ÒÐá áâÐàëï ×ÐåÐÒÐÝÝö ÓãÛìÝö Nippon Safes, ïÚöï ÝÕÐÑåÞÔÝÐ ßÕàÐÝÐ×ÒÐæì. ÁâÐàëï ÝÐ×Òë ÑÞÛìè ÝÕ ßÐÔâàëÜÛöÒÐîææÐ, ö âÐÜã Òë ÝÕ ×ÜÞÖÐæÕ ×ÐÓàã×öæì ×ÐåÐÒÐÝÝö, ÚÐÛö ÝÕ ßÕàÐÝÐ×ÐÒïæÕ öå.\n" +msgstr "" +"ScummVM ×ÝÐÙèÞþ ã ÒÐá áâÐàëï ×ÐåÐÒÐÝÝö ÓãÛìÝö Nippon Safes, ïÚöï ÝÕÐÑåÞÔÝÐ " +"ßÕàÐÝÐ×ÒÐæì. ÁâÐàëï ÝÐ×Òë ÑÞÛìè ÝÕ ßÐÔâàëÜÛöÒÐîææÐ, ö âÐÜã Òë ÝÕ ×ÜÞÖÐæÕ " +"×ÐÓàã×öæì ×ÐåÐÒÐÝÝö, ÚÐÛö ÝÕ ßÕàÐÝÐ×ÐÒïæÕ öå.\n" "\n" -"½ÐæöáÝöæÕ ¾º, ÚÐÑ ßÕàÐÝÐ×ÒÐæì öå ×ÐàÐ×, ã ÐÔÒÐàÞâÝëÜ ÒëßÐÔÚã ÓíâÐÕ Ö ßÐÒÕÔÐÜÛÕÝÝÕ ×'ïÒöææÐ ßàë ÝÐáâãßÝëÜ ×ÐßãáÚã ÓãÛìÝö.\n" -"" +"½ÐæöáÝöæÕ ¾º, ÚÐÑ ßÕàÐÝÐ×ÒÐæì öå ×ÐàÐ×, ã ÐÔÒÐàÞâÝëÜ ÒëßÐÔÚã ÓíâÐÕ Ö " +"ßÐÒÕÔÐÜÛÕÝÝÕ ×'ïÒöææÐ ßàë ÝÐáâãßÝëÜ ×ÐßãáÚã ÓãÛìÝö.\n" #: engines/parallaction/saveload.cpp:319 msgid "ScummVM successfully converted all your savefiles." msgstr "ScummVM ßÐáßïåÞÒÐ ßÕàÐþâÒÐàëþ ãáÕ ÒÐèë ×ÐåÐÒÐÝÝö ÓãÛìÝïþ." #: 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" +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 ÝÐßöáÐþ ÝÕÚÐÛìÚö ßÐßïàíÔÖÐÝÝïþ ã ÐÚÝÞ ÚÐÝáÞÛö ö ÝÕ ×ÜÞÓ ßÕàÐþâÒÐàëæì ãáÕ äÐÙÛë.\n" +msgstr "" +"ScummVM ÝÐßöáÐþ ÝÕÚÐÛìÚö ßÐßïàíÔÖÐÝÝïþ ã ÐÚÝÞ ÚÐÝáÞÛö ö ÝÕ ×ÜÞÓ ßÕàÐþâÒÐàëæì " +"ãáÕ äÐÙÛë.\n" "\n" "ºÐÛö ÛÐáÚÐ, ßÐÒÕÔÐÜöæÕ ßàÐ ÓíâÐ ÚÐÜÐÝÔ×Õ ScummVM." @@ -2601,7 +2743,7 @@ msgstr "½ïßàÐÒöÛìÝÐÕ öÜï äÐÙÛÐ ×ÐåÐÒÐÝÝï" #: engines/pegasus/pegasus.cpp:2507 msgid "Up/Zoom In/Move Forward/Open Doors" -msgstr "ÃÒÕàå/¼ÐèâÐÑ+/½ÐßÕàÐÔ/°ÔçëÝöæì Ô×ÒÕàë" +msgstr "ÃÒÕàå/¿ÐÒïÛ. ÜÐèâÐÑ/½ÐßÕàÐÔ/°ÔçëÝöæì Ô×ÒÕàë" #: engines/pegasus/pegasus.cpp:2508 msgid "Down/Zoom Out" @@ -2645,7 +2787,9 @@ msgstr "½Õ àÐÑöæì ÐßàÐÚáöÜÐæëî ÚÞÛÕàÐþ EGA (ßÞþÝÐÚÐÛïàÞÒëï äÞÝë)" #: engines/sci/detection.cpp:375 msgid "Skip dithering pass in EGA games, graphics are shown with full colors" -msgstr "¿àÐßãáÚÐÕ ßàÐåÞÔ ÐßàÐÚáöÜÐæëö ÚÞÛÕàÐþ EGA, ÓàÐäöÚÐ ÑãÔ×Õ ßÐÚÐ×ÐÝÐ × ãáöÜö ÚÞÛÕàÐÜö" +msgstr "" +"¿àÐßãáÚÐÕ ßàÐåÞÔ ÐßàÐÚáöÜÐæëö ÚÞÛÕàÐþ EGA, ÓàÐäöÚÐ ÑãÔ×Õ ßÐÚÐ×ÐÝÐ × ãáöÜö " +"ÚÞÛÕàÐÜö" #: engines/sci/detection.cpp:384 msgid "Enable high resolution graphics" @@ -2668,8 +2812,12 @@ msgid "Use IMF/Yamaha FB-01 for MIDI output" msgstr "²ëÚÐàëáâÞþÒÐæì IMF/Yamaha FB-01 ÔÛï ÒëÒÐÔã MIDI" #: engines/sci/detection.cpp:415 -msgid "Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI output" -msgstr "²ëÚÐàëáâÞþÒÐæì ÓãÚÐÒãî ÚÐàâã IBM Music Feature æö ÜÞÔãÛì áöÝâí×ã Yamaha FB-01 FM ÔÛï MIDI" +msgid "" +"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI " +"output" +msgstr "" +"²ëÚÐàëáâÞþÒÐæì ÓãÚÐÒãî ÚÐàâã IBM Music Feature æö ÜÞÔãÛì áöÝâí×ã Yamaha " +"FB-01 FM ÔÛï MIDI" #: engines/sci/detection.cpp:425 msgid "Use CD audio" @@ -2677,23 +2825,30 @@ msgstr "²ëÚÐàëáâÞþÒÐæì CD-ÐþÔëñ" #: engines/sci/detection.cpp:426 msgid "Use CD audio instead of in-game audio, if available" -msgstr "²ëÚÐàëáâÞþÒÐæì ÓãÚÐÒëï ÔÐàÞÖÚö × CD ×ÐÜÕáâ Üã×ëÚö × äÐÙÛÐþ ÓãÛìÝö (ÚÐÛö ÔÐáâãßÝÐ)" +msgstr "" +"²ëÚÐàëáâÞþÒÐæì ÓãÚÐÒëï ÔÐàÞÖÚö × CD ×ÐÜÕáâ Üã×ëÚö × äÐÙÛÐþ ÓãÛìÝö (ÚÐÛö " +"ÔÐáâãßÝÐ)" #: engines/sci/detection.cpp:436 msgid "Use Windows cursors" msgstr "²ëÚÐàëáâÞþÒÐæì ÚãàáÞàë Windows" #: engines/sci/detection.cpp:437 -msgid "Use the Windows cursors (smaller and monochrome) instead of the DOS ones" -msgstr "²ëÚÐàëáâÞþÒÐæì ÚãàáÞàë Windows (ÜÕÝèëï ßÐ ßÐÜÕàë ö ÐÔÝÐÚÐÛïàÞÒëï) ×ÐÜÕáâ ÚãàáÞàÐþ DOS" +msgid "" +"Use the Windows cursors (smaller and monochrome) instead of the DOS ones" +msgstr "" +"²ëÚÐàëáâÞþÒÐæì ÚãàáÞàë Windows (ÜÕÝèëï ßÐ ßÐÜÕàë ö ÐÔÝÐÚÐÛïàÞÒëï) ×ÐÜÕáâ " +"ÚãàáÞàÐþ DOS" #: engines/sci/detection.cpp:447 msgid "Use silver cursors" msgstr "²ëÚÐàëáâÞþÒÐæì áàíÑÝëï ÚãàáÞàë" #: engines/sci/detection.cpp:448 -msgid "Use the alternate set of silver cursors, instead of the normal golden ones" -msgstr "²ëÚÐàëáâÞþÒÐæì ÐÛìâíàÝÐâëþÝë ÝÐÑÞà áàíÑÝëå ÚãàáÞàÐþ ×ÐÜÕáâ ×ÒëçÐÙÝëå ×ÐÛÐâëå" +msgid "" +"Use the alternate set of silver cursors, instead of the normal golden ones" +msgstr "" +"²ëÚÐàëáâÞþÒÐæì ÐÛìâíàÝÐâëþÝë ÝÐÑÞà áàíÑÝëå ÚãàáÞàÐþ ×ÐÜÕáâ ×ÒëçÐÙÝëå ×ÐÛÐâëå" #: engines/scumm/dialogs.cpp:176 #, c-format @@ -2871,7 +3026,7 @@ msgstr "³ãçÝÐáæì Üã×ëÚö ßÐÒïÛöçëæì / ßÐÜÕÝèëæì" #: engines/scumm/help.cpp:89 msgid "Text speed slower / faster" -msgstr "ÅãâÚÐáæì âíÚáâã åãâçíÙ / ßÐÒÞÛìÝÕÙ" +msgstr "ÅãâÚÐáæì âíÚáâã ßÐÒÞÛìÝÕÙ / åãâçíÙ" #: engines/scumm/help.cpp:90 msgid "Simulate left mouse button" @@ -3362,37 +3517,111 @@ msgstr "ÅãâÚÐáæì âëâàÐþ: " #: engines/scumm/scumm.cpp:1832 #, c-format -msgid "Native MIDI support requires the Roland Upgrade from LucasArts,\n" +msgid "" +"Native MIDI support requires the Roland Upgrade from LucasArts,\n" "but %s is missing. Using AdLib instead." -msgstr "ÀíÖëÜ \"àÞÔÝÐÓÐ\" MIDI ßÐâàÐÑãÕ ÐÑÝÐþÛÕÝÝÕ Roland Upgrade ÐÔ\n" +msgstr "" +"ÀíÖëÜ \"àÞÔÝÐÓÐ\" MIDI ßÐâàÐÑãÕ ÐÑÝÐþÛÕÝÝÕ Roland Upgrade ÐÔ\n" "LucasArts, ÐÛÕ ÝÕ åÐßÐÕ %s. ¿ÕàÐÚÛîçÐîáï ÝÐ 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 "·ÐàÐ× ßÐÒöÝÝÐ ×ÐßãáæöææÐ ÓãÛìÝï Maniac Mansion. °ÛÕ ÚÐÑ ÓíâÐ ßàÐæÐÒÐÛÐ, äÐÙÛë ÓãÛìÝö Maniac Mansion ßÐÒöÝÝë Ñëæì áÚÐßöïÒÐÝë þ ÔëàíÚâÞàëî 'Maniac' ãÝãâàë ÔëàíÚâÞàëö ÓãÛìÝö Tentacle ö áÐÜÐ ÓãÛìÝï ßÐÒöÝÝÐ Ñëæì ÔÐÔÐÔ×ÕÝÐ þ ScummVM." +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 "" +"·ÐàÐ× ßÐÒöÝÝÐ ×ÐßãáæöææÐ ÓãÛìÝï Maniac Mansion. °ÛÕ ÚÐÑ ÓíâÐ ßàÐæÐÒÐÛÐ, " +"äÐÙÛë ÓãÛìÝö Maniac Mansion ßÐÒöÝÝë Ñëæì áÚÐßöïÒÐÝë þ ÔëàíÚâÞàëî 'Maniac' " +"ãÝãâàë ÔëàíÚâÞàëö ÓãÛìÝö Tentacle ö áÐÜÐ ÓãÛìÝï ßÐÒöÝÝÐ Ñëæì ÔÐÔÐÔ×ÕÝÐ þ " +"ScummVM." #: engines/scumm/players/player_v3m.cpp:129 -msgid "Could not find the 'Loom' Macintosh executable to read the\n" +msgid "" +"Could not find the 'Loom' Macintosh executable to read the\n" "instruments from. Music will be disabled." -msgstr "½Õ ÐâàëÜÐÛÐáï ×ÝÐÙáæö ÒëÚÐÝÐÛìÝë äÐÙÛ 'Loom' Macintosh, ÚÐÑ ßàÐçëâÐæì\n" +msgstr "" +"½Õ ÐâàëÜÐÛÐáï ×ÝÐÙáæö ÒëÚÐÝÐÛìÝë äÐÙÛ 'Loom' Macintosh, ÚÐÑ ßàÐçëâÐæì\n" "ÔÐÔ×ÕÝëï ßàÐ öÝáâàãÜÕÝâë. ¼ã×ëÚÐ ÑãÔ×Õ ÒëÚÛîçÐÝÐ." #: engines/scumm/players/player_v5m.cpp:107 -msgid "Could not find the 'Monkey Island' Macintosh executable to read the\n" +msgid "" +"Could not find the 'Monkey Island' Macintosh executable to read the\n" "instruments from. Music will be disabled." -msgstr "½Õ ÐâàëÜÐÛÐáï ×ÝÐÙáæö ÒëÚÐÝÐÛìÝë äÐÙÛ 'Monkey Island' Macintosh, ÚÐÑ ßàÐçëâÐæì\n" +msgstr "" +"½Õ ÐâàëÜÐÛÐáï ×ÝÐÙáæö ÒëÚÐÝÐÛìÝë äÐÙÛ 'Monkey Island' Macintosh, ÚÐÑ " +"ßàÐçëâÐæì\n" "ÔÐÔ×ÕÝëï ßàÐ öÝáâàãÜÕÝâë. ¼ã×ëÚÐ ÑãÔ×Õ ÒëÚÛîçÐÝÐ." +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "²ëÚÐàëáâÞþÒÐæì ÐàëÓöÝÐÛìÝëï íÚàÐÝë ×Ðßöáã/çëâÐÝÝï ÓãÛìÝö" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" +"ºÝÞßÚÐ \"ÄÐÙÛë\" þ ÓãÛìÝö ßÐÚÐ×ÒÐÕ ÐàëÓöÝÐÛìÝë ÔëïÛÞÓ ×ÐåÐÒÐÝÝï, Ð ÝÕ ÜÕÝî " +"ScummVM" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "¿ÕàÐåÞÔë ßÐÜöÖ áæíÝÐÜö × ßöÚáÕÛö×ÐæëïÙ" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "¿àë ×ÜÕÝÕ áæíÝ ÐÔÑëÒÐÕææÐ ßÕàÐåÞÔ × àÐÝÔÐÜö×ÐÒÐÝëÜö ßöÚáÕÛïÜö" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "½Õ ßÐÚÐ×ÒÐæì åÞâáßÞâë ßàë ÝÐÒïÔ×ÕÝÝö Üëèèã" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" +"¿ÐÚÐ×ÒÐæì ÝÐ×Òë åÞâáßÞâÐþ âÞÛìÚö ßÐáÛï ÚÛöÚã ßÐ öå ÐÑÞ ßÐáÛï ÝÐæöáÚã ÝÐ " +"ÚÝÞßÚã Ô×ÕïÝÝï" + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "¿ÐÚÐ×ÒÐæì ßÐàâàíâë ÓÕàÞïþ" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "¿ÐÚÐ×ÒÐæì ßÐàâàíâë ÓÕàÞïþ ßÐÔçÐá ÔëïÛÞÓÐþ" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "´ëïÛÞÓö ×Ðï×ÔÖÐîæì" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "´ëïÛÞÓö ÑãÔãæì ×Ðï×ÔÖÐæì, Ð ÝÕ ßÐÚÐ×ÒÐææÐ öÜÓÝÕÝÝÐ" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "¿àÐ×àëáâëï ÒÞÚÝë" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "¿ÐÚÐ×ÒÐæì ÒÞÚÝë × çÐáâÚÞÒÐ ßàÐ×àëáâëÜ äÞÝÐÜ" + #: engines/sky/compact.cpp:130 -msgid "Unable to find \"sky.cpt\" file!\n" +msgid "" +"Unable to find \"sky.cpt\" file!\n" "Please download it from www.scummvm.org" -msgstr "°ÔáãâÝöçÐÕ äÐÙÛ sky.cpt!\n" +msgstr "" +"°ÔáãâÝöçÐÕ äÐÙÛ sky.cpt!\n" "ºÐÛö ÛÐáÚÐ, ×ÐßÐÜßãÙæÕ ïÓÞ × www.scummvm.org" #: engines/sky/compact.cpp:141 -msgid "The \"sky.cpt\" file has an incorrect size.\n" +msgid "" +"The \"sky.cpt\" file has an incorrect size.\n" "Please (re)download it from www.scummvm.org" -msgstr "ÄÐÙÛ sky.cpt ÜÐÕ ÝïßàÐÒöÛìÝë ßÐÜÕà.\n" +msgstr "" +"ÄÐÙÛ sky.cpt ÜÐÕ ÝïßàÐÒöÛìÝë ßÐÜÕà.\n" "ºÐÛö ÛÐáÚÐ, ×ÐßÐÜßãÙæÕ ïÓÞ ÝÐÝÞÒÐ × www.scummvm.org" #: engines/sky/detection.cpp:44 @@ -3410,11 +3639,15 @@ msgstr "·ÐáâÐþÚÐ PSX '%s' ÝÕ ÜÞÖÐ Ñëæì ßàÐÙÓàÐÝÐ þ àíÖëÜÕ × ßÐÛöâàÐÙ" #: engines/sword1/animation.cpp:545 engines/sword2/animation.cpp:445 msgid "DXA cutscenes found but ScummVM has been built without zlib" -msgstr "·ÝÞÙÔ×ÕÝë ×ÐáâÐþÚö þ äÐàÜÐæÕ DXA, ÐÛÕ ScummVM Ñëþ áÐÑàÐÝë ÑÕ× ßÐÔâàëÜÚö zlib" +msgstr "" +"·ÝÞÙÔ×ÕÝë ×ÐáâÐþÚö þ äÐàÜÐæÕ DXA, ÐÛÕ ScummVM Ñëþ áÐÑàÐÝë ÑÕ× ßÐÔâàëÜÚö zlib" #: 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, ÐÛÕ ScummVM Ñëþ áÐÑàÐÝë ÑÕ× ßÐÔâàëÜÚö MPEG-2" +msgid "" +"MPEG-2 cutscenes found but ScummVM has been built without MPEG-2 support" +msgstr "" +"·ÝÞÙÔ×ÕÝë ×ÐáâÐþÚö þ äÐàÜÐæÕ MPEG-2, ÐÛÕ ScummVM Ñëþ áÐÑàÐÝë ÑÕ× ßÐÔâàëÜÚö " +"MPEG-2" #: engines/sword1/animation.cpp:568 engines/sword2/animation.cpp:470 #, c-format @@ -3422,25 +3655,30 @@ msgid "Cutscene '%s' not found" msgstr "·ÐáâÐþÚÐ '%s' ÝÕ ×ÝÞÙÔ×ÕÝÐ" #: 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" +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 ÒëïÒöþ ã ÒÐá ×ÐåÐÒÐÝÝö ÓãÛìÝö Broken Sword 1 ã áâÐàëÜ äÐàÜÐæÕ.\n" -"ÁâÐàë äÐàÜÐâ ÑÞÛìè ÝÕ ßÐÔâàëÜÛöÒÐÕææÐ, ö, ÚÐÑ ×ÐÓàã×öæì ×ÐåÐÒÐÝÝö, ïÝë ßÐÒöÝÝë Ñëæì ßÕàÐÒÕÔ×ÕÝë þ ÝÞÒë äÐàÜÐâ.\n" +"Press OK to convert them now, otherwise you will be asked again the next " +"time you start the game.\n" +msgstr "" +"ScummVM ÒëïÒöþ ã ÒÐá ×ÐåÐÒÐÝÝö ÓãÛìÝö Broken Sword 1 ã áâÐàëÜ äÐàÜÐæÕ.\n" +"ÁâÐàë äÐàÜÐâ ÑÞÛìè ÝÕ ßÐÔâàëÜÛöÒÐÕææÐ, ö, ÚÐÑ ×ÐÓàã×öæì ×ÐåÐÒÐÝÝö, ïÝë " +"ßÐÒöÝÝë Ñëæì ßÕàÐÒÕÔ×ÕÝë þ ÝÞÒë äÐàÜÐâ.\n" "\n" -"½ÐæöáÝöæÕ ¾º, ÚÐÑ ßÕàÐÒÕáæö öå ã ÝÞÒë äÐàÜÐâ ×ÐàÐ×, ã ÐÔÒÐàÞâÝëÜ ÒëßÐÔÚã ÓíâÐ ßÐÒÕÔÐÜÛÕÝÝÕ ×'ïÒöææÐ ×ÝÞþ ßàë ÝÐáâãßÝëÜ ×ÐßãáÚã ÓãÛìÝö.\n" -"" +"½ÐæöáÝöæÕ ¾º, ÚÐÑ ßÕàÐÒÕáæö öå ã ÝÞÒë äÐàÜÐâ ×ÐàÐ×, ã ÐÔÒÐàÞâÝëÜ ÒëßÐÔÚã " +"ÓíâÐ ßÐÒÕÔÐÜÛÕÝÝÕ ×'ïÒöææÐ ×ÝÞþ ßàë ÝÐáâãßÝëÜ ×ÐßãáÚã ÓãÛìÝö.\n" #: engines/sword1/control.cpp:1232 #, c-format -msgid "Target new save game already exists!\n" +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 "·ÐåÐÒÐÝÝÕ ÓãÛìÝö × âÐÚöÜ öÜÕÜ ãÖÞ öáÝãÕ!\n" +msgstr "" +"·ÐåÐÒÐÝÝÕ ÓãÛìÝö × âÐÚöÜ öÜÕÜ ãÖÞ öáÝãÕ!\n" "²ë ÖÐÔÐÕæÕ ßÐÚöÝãæì áâÐàãî ÝÐ×Òã (%s) æö ×àÐÑöæì ÝÞÒãî (%s)?\n" -"" #: engines/sword1/control.cpp:1235 msgid "Keep the old one" @@ -3455,8 +3693,11 @@ msgid "This is the end of the Broken Sword 1 Demo" msgstr "³íâÐ ×ÐÒïàèíÝÝÕ ÔíÜÐ Broken Sword 1" #: engines/sword2/animation.cpp:425 -msgid "PSX cutscenes found but ScummVM has been built without RGB color support" -msgstr "·ÝÞÙÔ×ÕÝë ×ÐáâÐþÚö þ äÐàÜÐæÕ PSX, ÐÛÕ ScummVM Ñëþ áÐÑàÐÝë ÑÕ× ßÐÔâàëÜÚö RGB-ÚÞÛÕàÐþ" +msgid "" +"PSX cutscenes found but ScummVM has been built without RGB color support" +msgstr "" +"·ÝÞÙÔ×ÕÝë ×ÐáâÐþÚö þ äÐàÜÐæÕ PSX, ÐÛÕ ScummVM Ñëþ áÐÑàÐÝë ÑÕ× ßÐÔâàëÜÚö RGB-" +"ÚÞÛÕàÐþ" #: engines/sword2/sword2.cpp:79 msgid "Show object labels" @@ -3467,12 +3708,18 @@ msgid "Show labels for objects on mouse hover" msgstr "¿ÐÚÐ×ÒÐÕ ÝÐ×Òë ÐÑ'ÕÚâÐþ ßàë ÝÐÒïÔ×ÕÝÝö ÚãàáÞàÐ Üëèë" #: engines/teenagent/resources.cpp:95 -msgid "You're missing the 'teenagent.dat' file. Get it from the ScummVM website" -msgstr "à ÒÐá ÐÔáãâÝöçÐÕ äÐÙÛ 'teenagent.dat'. ·ÐßÐÜßãÙæÕ ïÓÞ × ÒíÑ-áÐÙâÐ ScummVM" +msgid "" +"You're missing the 'teenagent.dat' file. Get it from the ScummVM website" +msgstr "" +"à ÒÐá ÐÔáãâÝöçÐÕ äÐÙÛ 'teenagent.dat'. ·ÐßÐÜßãÙæÕ ïÓÞ × ÒíÑ-áÐÙâÐ ScummVM" #: 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 ×ÖÐâë, ÐÛÕ zlib ÝÕ þÚÛîçÐÝë þ Óíâã ßàÐÓàÐÜã. ºÐÛö ÛÐáÚÐ, àÐáßÐÚãÙæÕ ïÓÞ" +msgid "" +"The teenagent.dat file is compressed and zlib hasn't been included in this " +"executable. Please decompress it" +msgstr "" +"ÄÐÙÛ teenagent.dat ×ÖÐâë, ÐÛÕ zlib ÝÕ þÚÛîçÐÝë þ Óíâã ßàÐÓàÐÜã. ºÐÛö ÛÐáÚÐ, " +"àÐáßÐÚãÙæÕ ïÓÞ" #: engines/wintermute/detection.cpp:58 msgid "Show FPS-counter" @@ -3484,7 +3731,9 @@ msgstr "¿ÐÚÐ×Ðæì ã ÒÕàåÝöÜ ÛÕÒëÜ ÚãæÕ ÑïÓãçãî ÚÞÛìÚÐáæì ÚÐÔàÐþ ã áÕÚãÝÔã" #: engines/zvision/detection_tables.h:52 msgid "Use the original save/load screens instead of the ScummVM interface" -msgstr "²ëÚÐàëáâÞþÒÐæì ÐàëÓöÝÐÛìÝëï íÚàÐÝë ×Ðßöáã ö ×ÐåÐÒÐÝÝï ÓãÛìÝö ×ÐÜÕáâ ×àÞÑÛÕÝëå ã ScummVM" +msgstr "" +"²ëÚÐàëáâÞþÒÐæì ÐàëÓöÝÐÛìÝëï íÚàÐÝë ×Ðßöáã ö ×ÐåÐÒÐÝÝï ÓãÛìÝö ×ÐÜÕáâ " +"×àÞÑÛÕÝëå ã ScummVM" #: engines/zvision/detection_tables.h:61 msgid "Double FPS" @@ -3516,7 +3765,9 @@ msgstr "²ëÚÐàëáâÞþÒÐæì ÒöÔíÐ MPEG ÒëáÞÚÐÓÐ ÐÔàÞ×ÝÕÝÝï" #: engines/zvision/detection_tables.h:92 msgid "Use MPEG video from the DVD version, instead of lower resolution AVI" -msgstr "²ëÚÐàëáâÞþÒÐæì MPEG-ÒöÔíÐ × DVD-ÒÕàáöö ×ÐÜÕáâ ÒöÔíÐ Ýö×ÚÐÓÐ ÐÔàÞ×ÝÕÝÝï þ äÐàÜÐæÕ AVI" +msgstr "" +"²ëÚÐàëáâÞþÒÐæì MPEG-ÒöÔíÐ × DVD-ÒÕàáöö ×ÐÜÕáâ ÒöÔíÐ Ýö×ÚÐÓÐ ÐÔàÞ×ÝÕÝÝï þ " +"äÐàÜÐæÕ AVI" #~ msgid "EGA undithering" #~ msgstr "EGA ÑÕ× àÐáâàã" @@ -3569,9 +3820,6 @@ msgstr "²ëÚÐàëáâÞþÒÐæì MPEG-ÒöÔíÐ × DVD-ÒÕàáöö ×ÐÜÕáâ ÒöÔíÐ Ýö×ÚÐÓÐ ÐÔàÞ×ÝÕÝÝï þ #~ msgid "Enable Roland GS Mode" #~ msgstr "ÃÚÛîçëæì àíÖëÜ Roland GS" -#~ msgid "Save game failed!" -#~ msgstr "½Õ ãÔÐÛÞáì áÞåàÐÝØâì ØÓàã!" - #~ msgctxt "lowres" #~ msgid "Add Game..." #~ msgstr "´ÞÑ. ØÓàã" diff --git a/po/ca_ES.po b/po/ca_ES.po index 8b9d333d4f..857e7de99e 100644 --- a/po/ca_ES.po +++ b/po/ca_ES.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.6.0git\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" "PO-Revision-Date: 2013-05-05 14:16+0100\n" "Last-Translator: Jordi Vilalta Prat <jvprat@jvprat.com>\n" "Language-Team: Catalan <scummvm-devel@lists.sf.net>\n" @@ -593,16 +593,16 @@ msgid "Search:" msgstr "Cerca:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Carrega partida:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Carrega" @@ -770,7 +770,7 @@ msgid "Special dithering modes supported by some games" msgstr "Modes de tramat especials suportats per alguns jocs" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Mode pantalla completa" @@ -1375,12 +1375,12 @@ msgstr "" msgid "PC-9801 (16 Colors)" msgstr "" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "" @@ -1432,11 +1432,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "~R~etorna al Llançador" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Desa la partida:" @@ -1445,11 +1449,15 @@ msgstr "Desa la partida:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Desa" @@ -1776,19 +1784,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Normal (no escalat)" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "S'ha activat la correcció de la relació d'aspecte" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "S'ha desactivat la correcció de la relació d'aspecte" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Filtre de gràfics actiu:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Mode de finestra" @@ -2354,15 +2362,23 @@ msgid "" "Enables mouse support. Allows to use mouse for movement and in game menus." msgstr "" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Recupera la partida:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Restaura" @@ -2673,10 +2689,20 @@ msgstr "" "No s'ha pogut desar a l'espai %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +#, fuzzy +msgid "Load file" +msgstr "Carrega partida:" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Carregant la partida..." +#: engines/parallaction/saveload.cpp:212 +#, fuzzy +msgid "Save file" +msgstr "Desa la partida:" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Desant la partida..." @@ -3530,6 +3556,60 @@ msgid "" "instruments from. Music will be disabled." msgstr "" +#: engines/sherlock/detection.cpp:71 +#, fuzzy +msgid "Use original savegame dialog" +msgstr "Utilitza les pantalles originals de desat/càrrega" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" + +#: engines/sherlock/detection.cpp:101 +#, fuzzy +msgid "Show character portraits" +msgstr "Commuta el personatge" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "" + #: engines/sky/compact.cpp:130 msgid "" "Unable to find \"sky.cpt\" file!\n" diff --git a/po/cs_CZ.po b/po/cs_CZ.po index 988191d535..3a308f977c 100644 --- a/po/cs_CZ.po +++ b/po/cs_CZ.po @@ -1,15 +1,15 @@ # Czech translation for ScummVM. # Copyright (C) 2001-2016 The ScummVM Team # This file is distributed under the same license as the ScummVM package. -# ZbynÄ›k Schwarz <zbynek.schwarz@gmail.com>, 2011-2013. +# Zbynìk Schwarz <zbynek.schwarz@gmail.com>, 2011-2013. # msgid "" msgstr "" "Project-Id-Version: ScummVM 1.7.0git\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" -"PO-Revision-Date: 2015-12-24 13:37+0100\n" -"Last-Translator: ZbynÄ›k Schwarz <zbynek.schwarz@gmail.com>\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" +"PO-Revision-Date: 2016-02-03 22:59+0100\n" +"Last-Translator: Zbynìk Schwarz <zbynek.schwarz@gmail.com>\n" "Language-Team: \n" "Language: Cesky\n" "MIME-Version: 1.0\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "X-Poedit-SourceCharset: iso-8859-2\n" -"X-Generator: Poedit 1.8.6\n" +"X-Generator: Poedit 1.8.7\n" "X-Poedit-Basepath: ..\n" #: gui/about.cpp:94 @@ -27,32 +27,32 @@ msgstr "(sestaveno %s)" #: gui/about.cpp:101 msgid "Features compiled in:" -msgstr "Zakompilované funkce:" +msgstr "Zakompilované funkce:" #: gui/about.cpp:110 msgid "Available engines:" -msgstr "Dostupná jádra:" +msgstr "Dostupná jádra:" #: gui/browser.cpp:68 gui/browser_osx.mm:104 msgid "Show hidden files" -msgstr "Zobrazit skryté soubory" +msgstr "Zobrazit skryté soubory" #: gui/browser.cpp:68 msgid "Show files marked with the hidden attribute" -msgstr "Zobrazit soubory s vlastnostà skryté" +msgstr "Zobrazit soubory s vlastností skryté" #: gui/browser.cpp:72 msgid "Go up" -msgstr "JÃt nahoru" +msgstr "Jít nahoru" #: gui/browser.cpp:72 gui/browser.cpp:74 msgid "Go to previous directory level" -msgstr "JÃt na pÅ™edchozà úroveň adresáře" +msgstr "Jít na pøedchozí úroveò adresáøe" #: gui/browser.cpp:74 msgctxt "lowres" msgid "Go up" -msgstr "JÃt nahoru" +msgstr "Jít nahoru" #: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67 #: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152 @@ -67,7 +67,7 @@ msgstr "JÃt nahoru" #: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191 #: engines/sword1/control.cpp:865 msgid "Cancel" -msgstr "ZruÅ¡it" +msgstr "Zru¹it" #: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47 #: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56 @@ -80,11 +80,11 @@ msgstr "Autor:" #: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204 msgid "Name:" -msgstr "Jméno" +msgstr "Jméno" #: gui/editrecorddialog.cpp:60 msgid "Notes:" -msgstr "Poznámky:" +msgstr "Poznámky:" #: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74 msgid "Ok" @@ -92,15 +92,15 @@ msgstr "Ok" #: gui/filebrowser-dialog.cpp:49 msgid "Choose file for loading" -msgstr "Zvolte soubor pro naÄtenÃ" +msgstr "Zvolte soubor pro naètení" #: gui/filebrowser-dialog.cpp:49 msgid "Enter filename for saving" -msgstr "Zadejte název souboru pro uloženÃ" +msgstr "Zadejte název souboru pro ulo¾ení" #: gui/filebrowser-dialog.cpp:132 msgid "Do you really want to overwrite the file?" -msgstr "Opravdu chcete tento soubor pÅ™epsat?" +msgstr "Opravdu chcete tento soubor pøepsat?" #: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217 #: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002 @@ -128,23 +128,23 @@ msgstr "Dozvuk" #: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102 msgid "Active" -msgstr "AktivnÃ" +msgstr "Aktivní" #: gui/fluidsynth-dialog.cpp:72 msgid "Room:" -msgstr "MÃstnost:" +msgstr "Místnost:" #: gui/fluidsynth-dialog.cpp:79 msgid "Damp:" -msgstr "TlumenÃ:" +msgstr "Tlumení:" #: gui/fluidsynth-dialog.cpp:86 msgid "Width:" -msgstr "Å ÃÅ™ka:" +msgstr "©íøka:" #: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111 msgid "Level:" -msgstr "Úroveň:" +msgstr "Úroveò:" #: gui/fluidsynth-dialog.cpp:100 msgid "Chorus" @@ -172,11 +172,11 @@ msgstr "Sinus" #: gui/fluidsynth-dialog.cpp:136 msgid "Triangle" -msgstr "TrojúhrlnÃk" +msgstr "Trojúhrlník" #: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168 msgid "Misc" -msgstr "Různé" +msgstr "Rùzné" #: gui/fluidsynth-dialog.cpp:140 msgid "Interpolation:" @@ -184,19 +184,19 @@ msgstr "Interpolace:" #: gui/fluidsynth-dialog.cpp:143 msgid "None (fastest)" -msgstr "Žádná (NejrychlejÅ¡Ã)" +msgstr "®ádná (Nejrychlej¹í)" #: gui/fluidsynth-dialog.cpp:144 msgid "Linear" -msgstr "LineárnÃ" +msgstr "Lineární" #: gui/fluidsynth-dialog.cpp:145 msgid "Fourth-order" -msgstr "Interpolace Ätvrtého řádu" +msgstr "Interpolace ètvrtého øádu" #: gui/fluidsynth-dialog.cpp:146 msgid "Seventh-order" -msgstr "Interpolace sedmého řádu" +msgstr "Interpolace sedmého øádu" #: gui/fluidsynth-dialog.cpp:150 msgid "Reset" @@ -204,7 +204,7 @@ msgstr "Resetovat" #: gui/fluidsynth-dialog.cpp:150 msgid "Reset all FluidSynth settings to their default values." -msgstr "Resetovat veÅ¡kerá nastavenà FludSynth n ajejich výchozà hodnoty." +msgstr "Resetovat ve¹kerá nastavení FludSynth n ajejich výchozí hodnoty." #: 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 @@ -229,7 +229,7 @@ msgstr "OK" msgid "" "Do you really want to reset all FluidSynth settings to their default values?" msgstr "" -"Opravdu chcete resetovat veÅ¡kerá nastavenà FluidSynth na jejich výchozà " +"Opravdu chcete resetovat ve¹kerá nastavení FluidSynth na jejich výchozí " "hodnoty?" #: gui/gui-manager.cpp:119 backends/keymapper/remap-dialog.cpp:53 @@ -237,23 +237,23 @@ msgstr "" #: engines/scumm/help.cpp:166 engines/scumm/help.cpp:192 #: engines/scumm/help.cpp:210 msgid "Close" -msgstr "ZavÅ™Ãt" +msgstr "Zavøít" #: gui/gui-manager.cpp:122 msgid "Mouse click" -msgstr "Kliknutà myÅ¡Ã" +msgstr "Kliknutí my¹í" #: gui/gui-manager.cpp:126 base/main.cpp:322 msgid "Display keyboard" -msgstr "Zobrazit klávesnici" +msgstr "Zobrazit klávesnici" #: gui/gui-manager.cpp:130 base/main.cpp:326 msgid "Remap keys" -msgstr "PÅ™emapovat klávesy" +msgstr "Pøemapovat klávesy" #: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87 msgid "Toggle fullscreen" -msgstr "PÅ™epnout celou obrazovku" +msgstr "Pøepnout celou obrazovku" #: gui/KeysDialog.cpp:41 msgid "Map" @@ -261,29 +261,29 @@ msgstr "Mapovat" #: gui/KeysDialog.cpp:49 msgid "Select an action and click 'Map'" -msgstr "Zvolte Äinnost a kliknÄ›te 'Mapovat'" +msgstr "Zvolte èinnost a kliknìte 'Mapovat'" #: gui/KeysDialog.cpp:80 gui/KeysDialog.cpp:102 gui/KeysDialog.cpp:141 #, c-format msgid "Associated key : %s" -msgstr "PÅ™iÅ™azená klávesa: %s" +msgstr "Pøiøazená klávesa: %s" #: gui/KeysDialog.cpp:82 gui/KeysDialog.cpp:104 gui/KeysDialog.cpp:143 #, c-format msgid "Associated key : none" -msgstr "PÅ™iÅ™azená klávesa: žádná" +msgstr "Pøiøazená klávesa: ¾ádná" #: gui/KeysDialog.cpp:90 msgid "Please select an action" -msgstr "ProsÃm vyberte Äinnost" +msgstr "Prosím vyberte èinnost" #: gui/KeysDialog.cpp:106 msgid "Press the key to associate" -msgstr "ZmáÄknÄ›te klávesu pro pÅ™iÅ™azenÃ" +msgstr "Zmáèknìte klávesu pro pøiøazení" #: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36 msgid "Choose an action to map" -msgstr "Zvolte Äinnost k mapovánÃ" +msgstr "Zvolte èinnost k mapování" #: gui/launcher.cpp:193 msgid "Game" @@ -298,8 +298,8 @@ msgid "" "Short game identifier used for referring to saved games and running the game " "from the command line" msgstr "" -"Krátký identifikátor her, použÃvaný jako odkaz k uloženým hrám a " -"spuÅ¡tÄ›nà hry z pÅ™Ãkazového řádku" +"Krátký identifikátor her, pou¾ívaný jako odkaz k ulo¾eným hrám a spu¹tìní " +"hry z pøíkazového øádku" #: gui/launcher.cpp:199 msgctxt "lowres" @@ -308,12 +308,12 @@ msgstr "ID:" #: gui/launcher.cpp:204 gui/launcher.cpp:206 gui/launcher.cpp:207 msgid "Full title of the game" -msgstr "Úplný název hry" +msgstr "Úplný název hry" #: gui/launcher.cpp:206 msgctxt "lowres" msgid "Name:" -msgstr "Jméno:" +msgstr "Jméno:" #: gui/launcher.cpp:210 msgid "Language:" @@ -323,13 +323,13 @@ msgstr "Jazyk:" msgid "" "Language of the game. This will not turn your Spanish game version into " "English" -msgstr "Jazyk hry. Toto z vaÅ¡Ã Å panÄ›lské verze neudÄ›lá Anglickou" +msgstr "Jazyk hry. Toto z va¹í ©panìlské verze neudìlá Anglickou" #: 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 "<výchozÃ>" +msgstr "<výchozí>" #: gui/launcher.cpp:222 msgid "Platform:" @@ -337,7 +337,7 @@ msgstr "Platforma:" #: gui/launcher.cpp:222 gui/launcher.cpp:224 gui/launcher.cpp:225 msgid "Platform the game was originally designed for" -msgstr "Platforma, pro kterou byla hra původnÄ› vytvoÅ™ena" +msgstr "Platforma, pro kterou byla hra pùvodnì vytvoøena" #: gui/launcher.cpp:224 msgctxt "lowres" @@ -346,7 +346,7 @@ msgstr "Platforma:" #: gui/launcher.cpp:237 msgid "Engine" -msgstr "Jádro" +msgstr "Jádro" #: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088 msgid "Graphics" @@ -358,12 +358,12 @@ msgstr "GFX" #: gui/launcher.cpp:248 msgid "Override global graphic settings" -msgstr "PotlaÄit globálnà nastavenà obrazu" +msgstr "Potlaèit globální nastavení obrazu" #: gui/launcher.cpp:250 msgctxt "lowres" msgid "Override global graphic settings" -msgstr "PotlaÄit globálnà nastavenà obrazu" +msgstr "Potlaèit globální nastavení obrazu" #: gui/launcher.cpp:257 gui/options.cpp:1094 msgid "Audio" @@ -371,12 +371,12 @@ msgstr "Zvuk" #: gui/launcher.cpp:260 msgid "Override global audio settings" -msgstr "PotlaÄit globálnà nastavenà zvuku" +msgstr "Potlaèit globální nastavení zvuku" #: gui/launcher.cpp:262 msgctxt "lowres" msgid "Override global audio settings" -msgstr "PotlaÄit globálnà nastavenà zvuku" +msgstr "Potlaèit globální nastavení zvuku" #: gui/launcher.cpp:271 gui/options.cpp:1099 msgid "Volume" @@ -389,12 +389,12 @@ msgstr "Hlasitost" #: gui/launcher.cpp:276 msgid "Override global volume settings" -msgstr "PotlaÄit globálnà nastavenà hlasitosti" +msgstr "Potlaèit globální nastavení hlasitosti" #: gui/launcher.cpp:278 msgctxt "lowres" msgid "Override global volume settings" -msgstr "PotlaÄit globálnà nastavenà hlasitosti" +msgstr "Potlaèit globální nastavení hlasitosti" #: gui/launcher.cpp:286 gui/options.cpp:1109 msgid "MIDI" @@ -402,12 +402,12 @@ msgstr "MIDI" #: gui/launcher.cpp:289 msgid "Override global MIDI settings" -msgstr "PotlaÄit globálnà nastavenà MIDI" +msgstr "Potlaèit globální nastavení MIDI" #: gui/launcher.cpp:291 msgctxt "lowres" msgid "Override global MIDI settings" -msgstr "PotlaÄit globálnà nastavenà MIDI" +msgstr "Potlaèit globální nastavení MIDI" #: gui/launcher.cpp:300 gui/options.cpp:1115 msgid "MT-32" @@ -415,12 +415,12 @@ msgstr "MT-32" #: gui/launcher.cpp:303 msgid "Override global MT-32 settings" -msgstr "PotlaÄit globálnà nastavenà MT-32" +msgstr "Potlaèit globální nastavení MT-32" #: gui/launcher.cpp:305 msgctxt "lowres" msgid "Override global MT-32 settings" -msgstr "PotlaÄit globálnà nastavenà MT-32" +msgstr "Potlaèit globální nastavení MT-32" #: gui/launcher.cpp:314 gui/options.cpp:1122 msgid "Paths" @@ -442,30 +442,30 @@ msgstr "Cesta Hry:" #: gui/launcher.cpp:330 gui/options.cpp:1148 msgid "Extra Path:" -msgstr "DodateÄná Cesta:" +msgstr "Dodateèná Cesta:" #: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333 msgid "Specifies path to additional data used by the game" -msgstr "Stanovà cestu pro dodateÄná data použitá ve hÅ™e" +msgstr "Stanoví cestu pro dodateèná data pou¾itá ve høe" #: gui/launcher.cpp:332 gui/options.cpp:1150 msgctxt "lowres" msgid "Extra Path:" -msgstr "DodateÄná Cesta:" +msgstr "Dodateèná Cesta:" #: gui/launcher.cpp:339 gui/options.cpp:1132 msgid "Save Path:" -msgstr "Cesta pro uloženÃ:" +msgstr "Cesta pro ulo¾ení:" #: 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 "Stanovuje, kam jsou umÃstÄ›ny vaÅ¡e uložené hry" +msgstr "Stanovuje, kam jsou umístìny va¹e ulo¾ené hry" #: gui/launcher.cpp:341 gui/options.cpp:1134 msgctxt "lowres" msgid "Save Path:" -msgstr "Cesta pro uloženÃ:" +msgstr "Cesta pro ulo¾ení:" #: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517 #: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151 @@ -475,13 +475,13 @@ msgstr "Cesta pro uloženÃ:" #: gui/options.cpp:1440 msgctxt "path" msgid "None" -msgstr "Žádné" +msgstr "®ádné" #: 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 "VýchozÃ" +msgstr "Výchozí" #: gui/launcher.cpp:510 gui/options.cpp:1434 msgid "Select SoundFont" @@ -489,27 +489,27 @@ msgstr "Vybrat SoundFont" #: gui/launcher.cpp:529 gui/launcher.cpp:682 msgid "Select directory with game data" -msgstr "Vyberte adresář s daty hry" +msgstr "Vyberte adresáø s daty hry" #: gui/launcher.cpp:547 msgid "Select additional game directory" -msgstr "Vyberte dodateÄný adresář hry" +msgstr "Vyberte dodateèný adresáø hry" #: gui/launcher.cpp:559 gui/options.cpp:1377 msgid "Select directory for saved games" -msgstr "Vyberte adresář pro uložené hry" +msgstr "Vyberte adresáø pro ulo¾ené hry" #: gui/launcher.cpp:586 msgid "This game ID is already taken. Please choose another one." -msgstr "Toto ID hry je už zabrané. Vyberte si, prosÃm, jiné." +msgstr "Toto ID hry je u¾ zabrané. Vyberte si, prosím, jiné." #: gui/launcher.cpp:626 engines/dialogs.cpp:111 msgid "~Q~uit" -msgstr "~U~konÄit" +msgstr "~U~konèit" #: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106 msgid "Quit ScummVM" -msgstr "UkonÄit ScummVM" +msgstr "Ukonèit ScummVM" #: gui/launcher.cpp:627 msgid "A~b~out..." @@ -525,7 +525,7 @@ msgstr "~V~olby..." #: gui/launcher.cpp:628 msgid "Change global ScummVM options" -msgstr "ZmÄ›nit globálnà volby ScummVM" +msgstr "Zmìnit globální volby ScummVM" #: gui/launcher.cpp:630 msgid "~S~tart" @@ -537,19 +537,19 @@ msgstr "Spustit zvolenou hru" #: gui/launcher.cpp:633 msgid "~L~oad..." -msgstr "~N~ahrát..." +msgstr "~N~ahrát..." #: gui/launcher.cpp:633 msgid "Load saved game for selected game" -msgstr "Nahrát uloženou pozici pro zvolenou hru" +msgstr "Nahrát ulo¾enou pozici pro zvolenou hru" #: gui/launcher.cpp:638 msgid "~A~dd Game..." -msgstr "~P~Å™idat hru..." +msgstr "~P~øidat hru..." #: gui/launcher.cpp:638 gui/launcher.cpp:645 msgid "Hold Shift for Mass Add" -msgstr "Podržte Shift pro Hromadné PÅ™idánÃ" +msgstr "Podr¾te Shift pro Hromadné Pøidání" #: gui/launcher.cpp:640 msgid "~E~dit Game..." @@ -557,7 +557,7 @@ msgstr "~U~pravit Hru..." #: gui/launcher.cpp:640 gui/launcher.cpp:647 msgid "Change game options" -msgstr "ZmÄ›nit volby hry" +msgstr "Zmìnit volby hry" #: gui/launcher.cpp:642 msgid "~R~emove Game" @@ -565,12 +565,12 @@ msgstr "~O~dstranit Hru" #: gui/launcher.cpp:642 gui/launcher.cpp:649 msgid "Remove game from the list. The game data files stay intact" -msgstr "Odstranit hru ze seznamu. Hernà data zůstanou zachována" +msgstr "Odstranit hru ze seznamu. Herní data zùstanou zachována" #: gui/launcher.cpp:645 msgctxt "lowres" msgid "~A~dd Game..." -msgstr "~P~Å™idat hru..." +msgstr "~P~øidat hru..." #: gui/launcher.cpp:647 msgctxt "lowres" @@ -591,35 +591,35 @@ msgid "Search:" msgstr "Hledat:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" -msgstr "Nahrát hru:" +msgstr "Nahrát hru:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Nahrát" +msgstr "Nahrát" #: 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 "" -"Opravdu chcete spustit hromadnou detekci her? Toto by mohlo potenciálnÄ› " -"pÅ™idat velkou spoustu her. " +"Opravdu chcete spustit hromadnou detekci her? Toto by mohlo potenciálnì " +"pøidat velkou spoustu her. " #: gui/launcher.cpp:843 msgid "ScummVM couldn't open the specified directory!" -msgstr "ScummVM nemohl tento adresář otevÅ™Ãt!" +msgstr "ScummVM nemohl tento adresáø otevøít!" #: gui/launcher.cpp:855 msgid "ScummVM could not find any game in the specified directory!" -msgstr "ScummVM nemohl v zadaném adresáři najÃt žádnou hru!" +msgstr "ScummVM nemohl v zadaném adresáøi najít ¾ádnou hru!" #: gui/launcher.cpp:869 msgid "Pick the game:" @@ -627,50 +627,50 @@ msgstr "Vybrat hru:" #: gui/launcher.cpp:943 msgid "Do you really want to remove this game configuration?" -msgstr "Opravdu chcete odstranit nastavenà této hry?" +msgstr "Opravdu chcete odstranit nastavení této hry?" #: gui/launcher.cpp:1001 msgid "Do you want to load saved game?" -msgstr "Chcete naÄÃst uloženou pozici?" +msgstr "Chcete naèíst ulo¾enou pozici?" #: gui/launcher.cpp:1050 msgid "This game does not support loading games from the launcher." -msgstr "Tato hra nepodporuje spouÅ¡tÄ›nà her ze spouÅ¡tÄ›Äe" +msgstr "Tato hra nepodporuje spou¹tìní her ze spou¹tìèe" #: gui/launcher.cpp:1054 msgid "ScummVM could not find any engine capable of running the selected game!" -msgstr "ScummVM nemohl najÃt žádné jádro schopné vybranou hru spustit!" +msgstr "ScummVM nemohl najít ¾ádné jádro schopné vybranou hru spustit!" #: gui/launcher.cpp:1161 msgid "Mass Add..." -msgstr "Hromadné PÅ™idánÃ..." +msgstr "Hromadné Pøidání..." #: gui/launcher.cpp:1163 msgid "Record..." -msgstr "Nahrát..." +msgstr "Nahrát..." #: gui/massadd.cpp:79 gui/massadd.cpp:82 msgid "... progress ..." -msgstr "... průbÄ›h ..." +msgstr "... prùbìh ..." #: gui/massadd.cpp:259 msgid "Scan complete!" -msgstr "Hledánà dokonÄeno!" +msgstr "Hledání dokonèeno!" #: gui/massadd.cpp:262 #, c-format msgid "Discovered %d new games, ignored %d previously added games." -msgstr "Objeveno %d nových her, ignorováno %d dÅ™Ãve pÅ™idaných her." +msgstr "Objeveno %d nových her, ignorováno %d døíve pøidaných her." #: gui/massadd.cpp:266 #, c-format msgid "Scanned %d directories ..." -msgstr "Prohledáno %d adresářů..." +msgstr "Prohledáno %d adresáøù..." #: gui/massadd.cpp:269 #, c-format msgid "Discovered %d new games, ignored %d previously added games ..." -msgstr "Objeveno %d nových her, ignorováno %d dÅ™Ãve pÅ™idaných her ..." +msgstr "Objeveno %d nových her, ignorováno %d døíve pøidaných her ..." #: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103 msgid "Stop" @@ -678,15 +678,15 @@ msgstr "Zastavit" #: gui/onscreendialog.cpp:106 msgid "Edit record description" -msgstr "Upravit popis záznamu" +msgstr "Upravit popis záznamu" #: gui/onscreendialog.cpp:108 msgid "Switch to Game" -msgstr "PÅ™epnout do hry" +msgstr "Pøepnout do hry" #: gui/onscreendialog.cpp:110 msgid "Fast replay" -msgstr "Rychlé pÅ™ehrávánÃ" +msgstr "Rychlé pøehrávání" #: gui/options.cpp:85 msgid "Never" @@ -694,19 +694,19 @@ msgstr "Nikdy" #: gui/options.cpp:85 msgid "every 5 mins" -msgstr "Každých 5 min" +msgstr "Ka¾dých 5 min" #: gui/options.cpp:85 msgid "every 10 mins" -msgstr "Každých 10 min" +msgstr "Ka¾dých 10 min" #: gui/options.cpp:85 msgid "every 15 mins" -msgstr "Každých 15 min" +msgstr "Ka¾dých 15 min" #: gui/options.cpp:85 msgid "every 30 mins" -msgstr "Každých 30 min" +msgstr "Ka¾dých 30 min" #: gui/options.cpp:87 msgid "8 kHz" @@ -732,110 +732,110 @@ msgstr "48 kHz" #: gui/options.cpp:649 gui/options.cpp:857 msgctxt "soundfont" msgid "None" -msgstr "Žádné" +msgstr "®ádné" #: gui/options.cpp:389 msgid "Failed to apply some of the graphic options changes:" -msgstr "Nelze použÃt nÄ›které zmÄ›ny možnostà grafiky:" +msgstr "Nelze pou¾ít nìkteré zmìny mo¾ností grafiky:" #: gui/options.cpp:401 msgid "the video mode could not be changed." -msgstr "režim obrazu nemohl být zmÄ›nÄ›n." +msgstr "re¾im obrazu nemohl být zmìnìn." #: gui/options.cpp:407 msgid "the fullscreen setting could not be changed" -msgstr "nastavenà celé obrazovky nemohlo být zmÄ›nÄ›no" +msgstr "nastavení celé obrazovky nemohlo být zmìnìno" #: gui/options.cpp:413 msgid "the aspect ratio setting could not be changed" -msgstr "nastavenà pomÄ›ru stran nemohlo být zmÄ›nÄ›no" +msgstr "nastavení pomìru stran nemohlo být zmìnìno" #: gui/options.cpp:732 msgid "Graphics mode:" -msgstr "Režim obrazu:" +msgstr "Re¾im obrazu:" #: gui/options.cpp:746 msgid "Render mode:" -msgstr "Režim vykreslenÃ:" +msgstr "Re¾im vykreslení:" #: gui/options.cpp:746 gui/options.cpp:747 msgid "Special dithering modes supported by some games" -msgstr "Speciálnà režimy chvÄ›nà podporované nÄ›kterými hrami" +msgstr "Speciální re¾imy chvìní podporované nìkterými hrami" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" -msgstr "Režim celé obrazovky" +msgstr "Re¾im celé obrazovky" #: gui/options.cpp:761 msgid "Aspect ratio correction" -msgstr "Korekce pomÄ›ru stran" +msgstr "Korekce pomìru stran" #: gui/options.cpp:761 msgid "Correct aspect ratio for 320x200 games" -msgstr "Korigovat pomÄ›r stran pro hry 320x200" +msgstr "Korigovat pomìr stran pro hry 320x200" #: gui/options.cpp:769 msgid "Preferred Device:" -msgstr "Prioritnà ZaÅ™ÃzenÃ:" +msgstr "Prioritní Zaøízení:" #: gui/options.cpp:769 msgid "Music Device:" -msgstr "Hudebnà zaÅ™ÃzenÃ" +msgstr "Hudební zaøízení" #: gui/options.cpp:769 gui/options.cpp:771 msgid "Specifies preferred sound device or sound card emulator" -msgstr "Stanovà prioritnà zvukové zaÅ™Ãzenà nebo emulátor zvukové karty" +msgstr "Stanoví prioritní zvukové zaøízení nebo emulátor zvukové karty" #: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772 msgid "Specifies output sound device or sound card emulator" -msgstr "Stanovà výstupnà zvukové zaÅ™Ãzenà nebo emulátor zvukové karty" +msgstr "Stanoví výstupní zvukové zaøízení nebo emulátor zvukové karty" #: gui/options.cpp:771 msgctxt "lowres" msgid "Preferred Dev.:" -msgstr "Prioritnà ZaÅ™.:" +msgstr "Prioritní Zaø.:" #: gui/options.cpp:771 msgctxt "lowres" msgid "Music Device:" -msgstr "Hudebnà zaÅ™ÃzenÃ" +msgstr "Hudební zaøízení" #: gui/options.cpp:798 msgid "AdLib emulator:" -msgstr "AdLib emulátor" +msgstr "AdLib emulátor" #: gui/options.cpp:798 gui/options.cpp:799 msgid "AdLib is used for music in many games" -msgstr "AdLib se použÃvá pro hudbu v mnoha hrách" +msgstr "AdLib se pou¾ívá pro hudbu v mnoha hrách" #: gui/options.cpp:809 msgid "Output rate:" -msgstr "Výstup. frekvence:" +msgstr "Výstup. frekvence:" #: gui/options.cpp:809 gui/options.cpp:810 msgid "" "Higher value specifies better sound quality but may be not supported by your " "soundcard" msgstr "" -"VyÅ¡Å¡Ã hodnota způsobà lepÅ¡Ã kvalitu zvuku, ale nemusà být podporována " -"VaÅ¡i zvukovou kartou" +"Vy¹¹í hodnota zpùsobí lep¹í kvalitu zvuku, ale nemusí být podporována Va¹i " +"zvukovou kartou" #: gui/options.cpp:820 msgid "GM Device:" -msgstr "GM ZaÅ™ÃzenÃ:" +msgstr "GM Zaøízení:" #: gui/options.cpp:820 msgid "Specifies default sound device for General MIDI output" -msgstr "Stanovà výchozà zvukové zaÅ™Ãzenà pro výstup General MIDI" +msgstr "Stanoví výchozí zvukové zaøízení pro výstup General MIDI" #: gui/options.cpp:831 msgid "Don't use General MIDI music" -msgstr "NepoužÃvat hudbu General MIDI" +msgstr "Nepou¾ívat hudbu General MIDI" #: gui/options.cpp:842 gui/options.cpp:908 msgid "Use first available device" -msgstr "PoužÃt prvnà dostupné zaÅ™ÃzenÃ" +msgstr "Pou¾ít první dostupné zaøízení" #: gui/options.cpp:854 msgid "SoundFont:" @@ -844,7 +844,7 @@ 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 "" -"SoundFont je podporován nÄ›kterými zvukovými kartami, FluidSynth a Timidity" +"SoundFont je podporován nìkterými zvukovými kartami, FluidSynth a Timidity" #: gui/options.cpp:856 msgctxt "lowres" @@ -853,70 +853,69 @@ msgstr "SoundFont:" #: gui/options.cpp:862 msgid "Mixed AdLib/MIDI mode" -msgstr "SmÃÅ¡ený režim AdLib/MIDI" +msgstr "Smí¹ený re¾im AdLib/MIDI" #: gui/options.cpp:862 msgid "Use both MIDI and AdLib sound generation" -msgstr "PoužÃt obÄ› zvukové generace MIDI a AdLib" +msgstr "Pou¾ít obì zvukové generace MIDI a AdLib" #: gui/options.cpp:865 msgid "MIDI gain:" -msgstr "ZesÃlenà MIDI:" +msgstr "Zesílení MIDI:" #: gui/options.cpp:872 msgid "FluidSynth Settings" -msgstr "Nastavenà FluidSynth" +msgstr "Nastavení FluidSynth" #: gui/options.cpp:879 msgid "MT-32 Device:" -msgstr "ZaÅ™Ãzenà MT-32:" +msgstr "Zaøízení MT-32:" #: gui/options.cpp:879 msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output" msgstr "" -"Stanovà výchozà zvukové výstupnà zaÅ™Ãzenà pro Roland MT-32/LAPC1/CM32l/" -"CM64" +"Stanoví výchozí zvukové výstupní zaøízení pro Roland MT-32/LAPC1/CM32l/CM64" #: gui/options.cpp:884 msgid "True Roland MT-32 (disable GM emulation)" -msgstr "Opravdový Roland MT-32 (vypne GM emulaci)" +msgstr "Opravdový Roland MT-32 (vypne GM emulaci)" #: 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 "" -"ZaÅ¡krtnÄ›te, pokud chcete použÃt pravé hardwarové zaÅ™Ãzenà kompatibilnà s " -"Roland, pÅ™ipojené k vaÅ¡emu poÄÃtaÄi" +"Za¹krtnìte, pokud chcete pou¾ít pravé hardwarové zaøízení kompatibilní s " +"Roland, pøipojené k va¹emu poèítaèi" #: gui/options.cpp:886 msgctxt "lowres" msgid "True Roland MT-32 (no GM emulation)" -msgstr "Opravdový Roland MT-32 (žádná GM emulace)" +msgstr "Opravdový Roland MT-32 (¾ádná GM emulace)" #: gui/options.cpp:889 msgid "Roland GS Device (enable MT-32 mappings)" -msgstr "ZaÅ™Ãzenà Roland GS (zapne mapovánà MT-32)" +msgstr "Zaøízení Roland GS (zapne mapování MT-32)" #: gui/options.cpp:889 msgid "" "Check if you want to enable patch mappings to emulate an MT-32 on a Roland " "GS device" msgstr "" -"ZaÅ¡krtnÄ›te, pokud chcete povolit záplaty mapovánà umožňujÃcà emulovat " -"MT-32 na zaÅ™Ãzenà Roland GS" +"Za¹krtnìte, pokud chcete povolit záplaty mapování umo¾òující emulovat MT-32 " +"na zaøízení Roland GS" #: gui/options.cpp:898 msgid "Don't use Roland MT-32 music" -msgstr "NepoužÃvat hudbu Roland MT-32" +msgstr "Nepou¾ívat hudbu Roland MT-32" #: gui/options.cpp:925 msgid "Text and Speech:" -msgstr "Text a ŘeÄ" +msgstr "Text a Øeè" #: gui/options.cpp:929 gui/options.cpp:939 msgid "Speech" -msgstr "ŘeÄ" +msgstr "Øeè" #: gui/options.cpp:930 gui/options.cpp:940 msgid "Subtitles" @@ -928,16 +927,16 @@ msgstr "Oba" #: gui/options.cpp:933 msgid "Subtitle speed:" -msgstr "Rychlost titulků:" +msgstr "Rychlost titulkù:" #: gui/options.cpp:935 msgctxt "lowres" msgid "Text and Speech:" -msgstr "Text a ŘeÄ:" +msgstr "Text a Øeè:" #: gui/options.cpp:939 msgid "Spch" -msgstr "ŘeÄ" +msgstr "Øeè" #: gui/options.cpp:940 msgid "Subs" @@ -950,12 +949,12 @@ msgstr "Oba" #: gui/options.cpp:941 msgid "Show subtitles and play speech" -msgstr "Zobrazit titulky a pÅ™ehrávat Å™eÄ" +msgstr "Zobrazit titulky a pøehrávat øeè" #: gui/options.cpp:943 msgctxt "lowres" msgid "Subtitle speed:" -msgstr "Rychlost titulků" +msgstr "Rychlost titulkù" #: gui/options.cpp:959 msgid "Music volume:" @@ -968,29 +967,29 @@ msgstr "Hlasitost hudby" #: gui/options.cpp:968 msgid "Mute All" -msgstr "Ztlumit VÅ¡e" +msgstr "Ztlumit V¹e" #: gui/options.cpp:971 msgid "SFX volume:" -msgstr "Hlasitost zvuků" +msgstr "Hlasitost zvukù" #: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974 msgid "Special sound effects volume" -msgstr "Hlasitost speciálnÃch zvukových efektů" +msgstr "Hlasitost speciálních zvukových efektù" #: gui/options.cpp:973 msgctxt "lowres" msgid "SFX volume:" -msgstr "Hlasitost zvuků" +msgstr "Hlasitost zvukù" #: gui/options.cpp:981 msgid "Speech volume:" -msgstr "Hlasitost Å™eÄi" +msgstr "Hlasitost øeèi" #: gui/options.cpp:983 msgctxt "lowres" msgid "Speech volume:" -msgstr "Hlasitost Å™eÄi" +msgstr "Hlasitost øeèi" #: gui/options.cpp:1140 msgid "Theme Path:" @@ -1003,22 +1002,21 @@ msgstr "Cesta ke Vzhledu:" #: 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 "" -"Stanovà cestu k dodateÄným datům použÃvaná vÅ¡emi hrami nebo ScummVM" +msgstr "Stanoví cestu k dodateèným datùm pou¾ívaná v¹emi hrami nebo ScummVM" #: gui/options.cpp:1157 msgid "Plugins Path:" -msgstr "Cesta k Pluginům:" +msgstr "Cesta k Pluginùm:" #: gui/options.cpp:1159 msgctxt "lowres" msgid "Plugins Path:" -msgstr "Cesta k Pluginům:" +msgstr "Cesta k Pluginùm:" #: gui/options.cpp:1170 msgctxt "lowres" msgid "Misc" -msgstr "Různé" +msgstr "Rùzné" #: gui/options.cpp:1172 msgid "Theme:" @@ -1026,20 +1024,20 @@ msgstr "Vzhled:" #: gui/options.cpp:1176 msgid "GUI Renderer:" -msgstr "GUI VykreslovaÄ:" +msgstr "GUI Vykreslovaè:" #: gui/options.cpp:1188 msgid "Autosave:" -msgstr "AutoukládánÃ:" +msgstr "Autoukládání:" #: gui/options.cpp:1190 msgctxt "lowres" msgid "Autosave:" -msgstr "AutoukládánÃ:" +msgstr "Autoukládání:" #: gui/options.cpp:1198 msgid "Keys" -msgstr "Klávesy" +msgstr "Klávesy" #: gui/options.cpp:1205 msgid "GUI Language:" @@ -1051,40 +1049,40 @@ msgstr "Jazyk GUI ScummVM" #: gui/options.cpp:1364 msgid "You have to restart ScummVM before your changes will take effect." -msgstr "Pro použità tÄ›chto nastavenà musÃte restartovat ScummVM." +msgstr "Pro pou¾ití tìchto nastavení musíte restartovat ScummVM." #: gui/options.cpp:1384 msgid "The chosen directory cannot be written to. Please select another one." -msgstr "Do zvoleného adresáře nelze zapisovat. Vyberte, prosÃm, jiný." +msgstr "Do zvoleného adresáøe nelze zapisovat. Vyberte, prosím, jiný." #: gui/options.cpp:1393 msgid "Select directory for GUI themes" -msgstr "Vyberte adresář pro vhledy GUI" +msgstr "Vyberte adresáø pro vhledy GUI" #: gui/options.cpp:1403 msgid "Select directory for extra files" -msgstr "Vyberte adresář pro dodateÄné soubory" +msgstr "Vyberte adresáø pro dodateèné soubory" #: gui/options.cpp:1414 msgid "Select directory for plugins" -msgstr "Vyberte adresář pro zásuvné moduly" +msgstr "Vyberte adresáø pro zásuvné moduly" #: 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 "" -"Vzhled, který jste zvolili, nepodporuje Váš souÄasný jazyk. Pokud chcete " -"tento vzhled použÃt, musÃte nejdÅ™Ãve pÅ™epnout na jiný jazyk." +"Vzhled, který jste zvolili, nepodporuje Vá¹ souèasný jazyk. Pokud chcete " +"tento vzhled pou¾ít, musíte nejdøíve pøepnout na jiný jazyk." #. I18N: You must leave "#" as is, only word 'next' is translatable #: gui/predictivedialog.cpp:86 msgid "# next" -msgstr "# dalÅ¡Ã" +msgstr "# dal¹í" #: gui/predictivedialog.cpp:87 msgid "add" -msgstr "pÅ™idat" +msgstr "pøidat" #: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164 msgid "Delete char" @@ -1097,21 +1095,21 @@ msgstr "<" #. I18N: Pre means 'Predictive', leave '*' as is #: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572 msgid "* Pre" -msgstr "* PrediktivnÃ" +msgstr "* Prediktivní" #. I18N: 'Num' means Numbers #: gui/predictivedialog.cpp:575 msgid "* Num" -msgstr "" +msgstr "* Èísla" #. I18N: 'Abc' means Latin alphabet input #: gui/predictivedialog.cpp:578 msgid "* Abc" -msgstr "" +msgstr "* Abc" #: gui/recorderdialog.cpp:64 msgid "Recorder or Playback Gameplay" -msgstr "Nahrávat nebo pÅ™ehrát hru" +msgstr "Nahrávat nebo pøehrát hru" #: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156 #: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276 @@ -1120,11 +1118,11 @@ msgstr "Smazat" #: gui/recorderdialog.cpp:71 msgid "Record" -msgstr "Nahrát" +msgstr "Nahrát" #: gui/recorderdialog.cpp:72 msgid "Playback" -msgstr "PÅ™ehrát" +msgstr "Pøehrát" #: gui/recorderdialog.cpp:74 msgid "Edit" @@ -1138,15 +1136,15 @@ msgstr "Autor:" #: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244 #: gui/recorderdialog.cpp:254 msgid "Notes: " -msgstr "Poznámky:" +msgstr "Poznámky:" #: gui/recorderdialog.cpp:155 msgid "Do you really want to delete this record?" -msgstr "Opravdu chcete tento záznam smazat?" +msgstr "Opravdu chcete tento záznam smazat?" #: gui/recorderdialog.cpp:174 msgid "Unknown Author" -msgstr "Neznámý autor" +msgstr "Neznámý autor" #: gui/saveload-dialog.cpp:167 msgid "List view" @@ -1154,23 +1152,23 @@ msgstr "Seznam" #: gui/saveload-dialog.cpp:168 msgid "Grid view" -msgstr "MřÞka" +msgstr "Møí¾ka" #: gui/saveload-dialog.cpp:211 gui/saveload-dialog.cpp:360 msgid "No date saved" -msgstr "Neuložena žádná data" +msgstr "Neulo¾ena ¾ádná data" #: gui/saveload-dialog.cpp:212 gui/saveload-dialog.cpp:361 msgid "No time saved" -msgstr "Žádný uložený Äas" +msgstr "®ádný ulo¾ený èas" #: gui/saveload-dialog.cpp:213 gui/saveload-dialog.cpp:362 msgid "No playtime saved" -msgstr "Žádná uložená doba hranÃ" +msgstr "®ádná ulo¾ená doba hraní" #: gui/saveload-dialog.cpp:275 msgid "Do you really want to delete this saved game?" -msgstr "Opravdu chcete tuto uloženou hru vymazat" +msgstr "Opravdu chcete tuto ulo¾enou hru vymazat" #: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884 msgid "Date: " @@ -1178,35 +1176,35 @@ msgstr "Datum:" #: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890 msgid "Time: " -msgstr "ÄŒas:" +msgstr "Èas:" #: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898 msgid "Playtime: " -msgstr "Doba hranÃ:" +msgstr "Doba hraní:" #: gui/saveload-dialog.cpp:408 gui/saveload-dialog.cpp:496 msgid "Untitled savestate" -msgstr "Bezejmenný uložený stav" +msgstr "Bezejmenný ulo¾ený stav" #: gui/saveload-dialog.cpp:548 msgid "Next" -msgstr "DalÅ¡Ã" +msgstr "Dal¹í" #: gui/saveload-dialog.cpp:551 msgid "Prev" -msgstr "PÅ™edchozÃ" +msgstr "Pøedchozí" #: gui/saveload-dialog.cpp:748 msgid "New Save" -msgstr "Nová uložená pozice" +msgstr "Nová ulo¾ená pozice" #: gui/saveload-dialog.cpp:748 msgid "Create a new save game" -msgstr "VytvoÅ™it novou uloženou hru." +msgstr "Vytvoøit novou ulo¾enou hru." #: gui/saveload-dialog.cpp:877 msgid "Name: " -msgstr "Název:" +msgstr "Název:" #: gui/saveload-dialog.cpp:949 #, c-format @@ -1219,37 +1217,37 @@ msgstr "Vyberte Vzhled" #: gui/ThemeEngine.cpp:347 msgid "Disabled GFX" -msgstr "GFX zakázáno" +msgstr "GFX zakázáno" #: gui/ThemeEngine.cpp:347 msgctxt "lowres" msgid "Disabled GFX" -msgstr "GFX zakázáno" +msgstr "GFX zakázáno" #: gui/ThemeEngine.cpp:348 msgid "Standard Renderer" -msgstr "Standardnà VykreslovaÄ" +msgstr "Standardní Vykreslovaè" #: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663 msgid "Standard" -msgstr "StandardnÃ" +msgstr "Standardní" #: gui/ThemeEngine.cpp:350 msgid "Antialiased Renderer" -msgstr "VykreslovaÄ s vyhlazenými hranami" +msgstr "Vykreslovaè s vyhlazenými hranami" #: gui/ThemeEngine.cpp:350 msgid "Antialiased" -msgstr "S vyhlazenými hranami" +msgstr "S vyhlazenými hranami" #: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333 msgid "Clear value" -msgstr "VyÄistit hodnotu" +msgstr "Vyèistit hodnotu" #: base/main.cpp:237 #, c-format msgid "Engine does not support debug level '%s'" -msgstr "Jádro nepodporuje úroveň ladÄ›nà '%s'" +msgstr "Jádro nepodporuje úroveò ladìní '%s'" #: base/main.cpp:309 msgid "Menu" @@ -1259,7 +1257,7 @@ msgstr "Menu" #: backends/platform/wince/CEActionsPocket.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:46 msgid "Skip" -msgstr "PÅ™eskoÄit" +msgstr "Pøeskoèit" #: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50 #: backends/platform/wince/CEActionsPocket.cpp:42 @@ -1268,19 +1266,19 @@ msgstr "Pauza" #: base/main.cpp:318 msgid "Skip line" -msgstr "PÅ™eskoÄit řádek" +msgstr "Pøeskoèit øádek" #: base/main.cpp:510 msgid "Error running game:" -msgstr "Chyba pÅ™i spuÅ¡tÄ›nà hry:" +msgstr "Chyba pøi spu¹tìní hry:" #: base/main.cpp:557 msgid "Could not find any engine capable of running the selected game" -msgstr "Nelze nalézt žádné jádro schopné vybranou hru spustit" +msgstr "Nelze nalézt ¾ádné jádro schopné vybranou hru spustit" #: common/error.cpp:38 msgid "No error" -msgstr "Žádná chyba" +msgstr "®ádná chyba" #: common/error.cpp:40 msgid "Game data not found" @@ -1288,19 +1286,19 @@ msgstr "Data hry nenalezena" #: common/error.cpp:42 msgid "Game id not supported" -msgstr "Id hry nenà podporováno" +msgstr "Id hry není podporováno" #: common/error.cpp:44 msgid "Unsupported color mode" -msgstr "Nepodporovaný barevný režim" +msgstr "Nepodporovaný barevný re¾im" #: common/error.cpp:47 msgid "Read permission denied" -msgstr "OprávnÄ›nà ke Ätenà zamÃtnuto" +msgstr "Oprávnìní ke ètení zamítnuto" #: common/error.cpp:49 msgid "Write permission denied" -msgstr "OprávnÄ›nà k zápisu zamÃtnuto" +msgstr "Oprávnìní k zápisu zamítnuto" #: common/error.cpp:52 msgid "Path does not exist" @@ -1308,91 +1306,91 @@ msgstr "Cesta neexistuje" #: common/error.cpp:54 msgid "Path not a directory" -msgstr "Cesta nenà adresář" +msgstr "Cesta není adresáø" #: common/error.cpp:56 msgid "Path not a file" -msgstr "Cesta nenà soubor" +msgstr "Cesta není soubor" #: common/error.cpp:59 msgid "Cannot create file" -msgstr "Nelze vytvoÅ™it soubor" +msgstr "Nelze vytvoøit soubor" #: common/error.cpp:61 msgid "Reading data failed" -msgstr "ÄŒtenà dat selhalo" +msgstr "Ètení dat selhalo" #: common/error.cpp:63 msgid "Writing data failed" -msgstr "Zápis dat selhal" +msgstr "Zápis dat selhal" #: common/error.cpp:66 msgid "Could not find suitable engine plugin" -msgstr "Nelze nalézt vhodný zás. modul jádra" +msgstr "Nelze nalézt vhodný zás. modul jádra" #: common/error.cpp:68 msgid "Engine plugin does not support save states" -msgstr "Zás. modul jádra nepodporuje uložené stavy" +msgstr "Zás. modul jádra nepodporuje ulo¾ené stavy" #: common/error.cpp:71 msgid "User canceled" -msgstr "ZruÅ¡eno uživatelem" +msgstr "Zru¹eno u¾ivatelem" #: common/error.cpp:75 msgid "Unknown error" -msgstr "Neznámá chyba" +msgstr "Neznámá chyba" #. I18N: Hercules is graphics card name #: common/rendermode.cpp:35 msgid "Hercules Green" -msgstr "Hercules Zelená" +msgstr "Hercules Zelená" #: common/rendermode.cpp:36 msgid "Hercules Amber" -msgstr "Hercules Jantarová" +msgstr "Hercules Jantarová" #: common/rendermode.cpp:42 msgid "PC-9821 (256 Colors)" -msgstr "" +msgstr "PC-9821 (256 barev)" #: common/rendermode.cpp:43 msgid "PC-9801 (16 Colors)" -msgstr "" +msgstr "PC-9801 (16 barev)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" -msgstr "Hercules Zelená" +msgstr "Hercules Zelená" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" -msgstr "Hercules Jantarová" +msgstr "Hercules Jantarová" #: engines/advancedDetector.cpp:317 #, c-format msgid "The game in '%s' seems to be unknown." -msgstr "Hra v '%s' se zdá být neznámá." +msgstr "Hra v '%s' se zdá být neznámá." #: engines/advancedDetector.cpp:318 msgid "Please, report the following data to the ScummVM team along with name" -msgstr "ProsÃm nahlaste následujÃcà data týmu ScummVM spolu se jménem" +msgstr "Prosím nahlaste následující data týmu ScummVM spolu se jménem" #: engines/advancedDetector.cpp:320 msgid "of the game you tried to add and its version/language/etc.:" -msgstr "hry, kterou jste se pokusili pÅ™idat a jejà verzi/jazyk/atd.:" +msgstr "hry, kterou jste se pokusili pøidat a její verzi/jazyk/atd.:" #: engines/dialogs.cpp:85 msgid "~R~esume" -msgstr "~P~okraÄovat" +msgstr "~P~okraèovat" #: engines/dialogs.cpp:87 msgid "~L~oad" -msgstr "~N~ahrát" +msgstr "~N~ahrát" #: engines/dialogs.cpp:91 msgid "~S~ave" -msgstr "~U~ložit" +msgstr "~U~lo¾it" #: engines/dialogs.cpp:95 msgid "~O~ptions" @@ -1400,7 +1398,7 @@ msgstr "~V~olby" #: engines/dialogs.cpp:100 msgid "~H~elp" -msgstr "~N~ápovÄ›da" +msgstr "~N~ápovìda" #: engines/dialogs.cpp:102 msgid "~A~bout" @@ -1408,33 +1406,41 @@ msgstr "~O~ programu" #: engines/dialogs.cpp:105 engines/dialogs.cpp:181 msgid "~R~eturn to Launcher" -msgstr "~N~ávrat do SpouÅ¡tÄ›Äe" +msgstr "~N~ávrat do Spou¹tìèe" #: engines/dialogs.cpp:107 engines/dialogs.cpp:183 msgctxt "lowres" msgid "~R~eturn to Launcher" -msgstr "~N~ávrat do SpouÅ¡tÄ›Äe" +msgstr "~N~ávrat do Spou¹tìèe" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Uložit hru:" +msgstr "Ulo¾it hru:" #: 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:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Uložit" +msgstr "Ulo¾it" #: engines/dialogs.cpp:145 msgid "" @@ -1442,9 +1448,9 @@ msgid "" "the README for basic information, and for instructions on how to obtain " "further assistance." msgstr "" -"Je nám lÃto, ale toto jádro v souÄasnosti nepodporuje hernà nápovÄ›du. " -"ProsÃm prohlédnÄ›te si README pro základnà informace a pro instrukce jak zÃ" -"skat dalÅ¡Ã pomoc." +"Je nám líto, ale toto jádro v souèasnosti nepodporuje herní nápovìdu. Prosím " +"prohlédnìte si README pro základní informace a pro instrukce jak získat " +"dal¹í pomoc." #: engines/dialogs.cpp:234 engines/pegasus/pegasus.cpp:393 #, c-format @@ -1452,8 +1458,8 @@ msgid "" "Gamestate save failed (%s)! Please consult the README for basic information, " "and for instructions on how to obtain further assistance." msgstr "" -"Uloženà stavu hry selhalo (%s)! ProsÃm pÅ™eÄtÄ›te si dokumentaci pro " -"základnà informace a pokyny k zÃskánà dalÅ¡Ã podpory." +"Ulo¾ení stavu hry selhalo (%s)! Prosím pøeètìte si dokumentaci pro základní " +"informace a pokyny k získání dal¹í podpory." #: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109 #: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106 @@ -1463,27 +1469,27 @@ msgstr "~O~K" #: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110 #: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107 msgid "~C~ancel" -msgstr "~Z~ruÅ¡it" +msgstr "~Z~ru¹it" #: engines/dialogs.cpp:311 msgid "~K~eys" -msgstr "~K~lávesy" +msgstr "~K~lávesy" #: engines/engine.cpp:339 msgid "Could not initialize color format." -msgstr "Nelze zavést barevný formát." +msgstr "Nelze zavést barevný formát." #: engines/engine.cpp:347 msgid "Could not switch to video mode: '" -msgstr "Nelze pÅ™epnout na režim obrazu: '" +msgstr "Nelze pøepnout na re¾im obrazu: '" #: engines/engine.cpp:356 msgid "Could not apply aspect ratio setting." -msgstr "Nelze použÃt nastavenà pomÄ›ru stran." +msgstr "Nelze pou¾ít nastavení pomìru stran." #: engines/engine.cpp:361 msgid "Could not apply fullscreen setting." -msgstr "Nelze použÃt nastavenà celé obrazovky." +msgstr "Nelze pou¾ít nastavení celé obrazovky." #: engines/engine.cpp:461 msgid "" @@ -1493,11 +1499,11 @@ msgid "" "the data files to your hard disk instead.\n" "See the README file for details." msgstr "" -"Vypadá to, že tuto hru hrajete pÅ™Ãmo z\n" -" CD. Je známo, že toto způsobuje problémy\n" -" a je tedy doporuÄeno, aÅ¥ mÃsto toho zkopÃrujete\n" -"datové soubory na Váš pevný disk.\n" -"Pro podrobnosti si pÅ™eÄtÄ›te README." +"Vypadá to, ¾e tuto hru hrajete pøímo z\n" +" CD. Je známo, ¾e toto zpùsobuje problémy\n" +" a je tedy doporuèeno, a» místo toho zkopírujete\n" +"datové soubory na Vá¹ pevný disk.\n" +"Pro podrobnosti si pøeètìte README." #: engines/engine.cpp:472 msgid "" @@ -1507,11 +1513,11 @@ msgid "" "order to listen to the game's music.\n" "See the README file for details." msgstr "" -"Tato hra má na svém disku zvukové stopy. Tyto\n" -"stopy musà být z disku zkopÃrovány použitÃm\n" -"vhodného nástroje pro extrakci zvuku z CD,\n" -"abyste mohli poslouchat hudbu ve hÅ™e.\n" -"Pro podrobnosti si pÅ™eÄtÄ›te README." +"Tato hra má na svém disku zvukové stopy. Tyto\n" +"stopy musí být z disku zkopírovány pou¾itím\n" +"vhodného nástroje pro extrakci zvuku z CD,\n" +"abyste mohli poslouchat hudbu ve høe.\n" +"Pro podrobnosti si pøeètìte README." #: engines/engine.cpp:530 #, c-format @@ -1519,8 +1525,8 @@ msgid "" "Gamestate load failed (%s)! Please consult the README for basic information, " "and for instructions on how to obtain further assistance." msgstr "" -"NaÄtenà stavu hry selhalo (%s)! ProsÃm pÅ™eÄtÄ›te si dokumentaci pro základnà " -"informace a pokyny k zÃskánà dalÅ¡Ã podpory." +"Naètení stavu hry selhalo (%s)! Prosím pøeètìte si dokumentaci pro základní " +"informace a pokyny k získání dal¹í podpory." #: engines/engine.cpp:543 msgid "" @@ -1528,29 +1534,29 @@ msgid "" "ScummVM. As such, it is likely to be unstable, and any saves you make might " "not work in future versions of ScummVM." msgstr "" -"VAROVÃNÃ: Hra, kterou se chystáte spustit, nenà jeÅ¡tÄ› plnÄ› podporována " -"ScummVM. Proto je možné, že bude nestabilnà a jakékoli uložené hry " -"nemusà fungovat v budoucÃch verzÃch ScummVM." +"VAROVÁNÍ: Hra, kterou se chystáte spustit, není je¹tì plnì podporována " +"ScummVM. Proto je mo¾né, ¾e bude nestabilní a jakékoli ulo¾ené hry nemusí " +"fungovat v budoucích verzích ScummVM." #: engines/engine.cpp:546 msgid "Start anyway" -msgstr "PÅ™esto spustit" +msgstr "Pøesto spustit" #: audio/adlib.cpp:2291 msgid "AdLib Emulator" -msgstr "AdLib Emulátor" +msgstr "AdLib Emulátor" #: audio/fmopl.cpp:62 msgid "MAME OPL emulator" -msgstr "MAME OPL Emulátor" +msgstr "MAME OPL Emulátor" #: audio/fmopl.cpp:64 msgid "DOSBox OPL emulator" -msgstr "DOSBox OPL Emulátor" +msgstr "DOSBox OPL Emulátor" #: audio/fmopl.cpp:67 msgid "ALSA Direct FM" -msgstr "ALSA PÅ™Ãmá FM" +msgstr "ALSA Pøímá FM" #: audio/mididrv.cpp:209 #, c-format @@ -1558,13 +1564,13 @@ msgid "" "The selected audio device '%s' was not found (e.g. might be turned off or " "disconnected)." msgstr "" -"Zvolené zvukové zaÅ™Ãzenà '%s' nebylo nalezeno (napÅ™. může být vypnuto " -"nebo odpojeno)." +"Zvolené zvukové zaøízení '%s' nebylo nalezeno (napø. mù¾e být vypnuto nebo " +"odpojeno)." #: 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 "Pokus o navrácenà na nejbližšà dostupné zaÅ™ÃzenÃ..." +msgstr "Pokus o navrácení na nejbli¾¹í dostupné zaøízení..." #: audio/mididrv.cpp:221 #, c-format @@ -1572,8 +1578,8 @@ msgid "" "The selected audio device '%s' cannot be used. See log file for more " "information." msgstr "" -"Zvolené zvukové zaÅ™Ãzenà '%s' nelze použÃt. PodÃvejte se na záznam pro vÃ" -"ce informacÃ." +"Zvolené zvukové zaøízení '%s' nelze pou¾ít. Podívejte se na záznam pro více " +"informací." #: audio/mididrv.cpp:257 #, c-format @@ -1581,7 +1587,7 @@ msgid "" "The preferred audio device '%s' was not found (e.g. might be turned off or " "disconnected)." msgstr "" -"UpÅ™ednostňované zvukové zaÅ™Ãzenà '%s' nebylo nalezeno (napÅ™. může být " +"Upøednostòované zvukové zaøízení '%s' nebylo nalezeno (napø. mù¾e být " "vypnuto nebo odpojeno)." #: audio/mididrv.cpp:272 @@ -1590,12 +1596,12 @@ msgid "" "The preferred audio device '%s' cannot be used. See log file for more " "information." msgstr "" -"UpÅ™ednostňované zvukové zaÅ™Ãzenà '%s' nelze použÃt. PodÃvejte se na " -"záznam pro vÃce informacÃ." +"Upøednostòované zvukové zaøízení '%s' nelze pou¾ít. Podívejte se na záznam " +"pro více informací." #: audio/mods/paula.cpp:196 msgid "Amiga Audio Emulator" -msgstr "Emulátor zvuku Amiga" +msgstr "Emulátor zvuku Amiga" #: audio/null.h:44 msgid "No music" @@ -1603,53 +1609,51 @@ msgstr "Bez hudby" #: audio/softsynth/appleiigs.cpp:33 msgid "Apple II GS Emulator (NOT IMPLEMENTED)" -msgstr "Apple II GS Emulátor (NENà ZAVEDEN)" +msgstr "Apple II GS Emulátor (NENÍ ZAVEDEN)" #: audio/softsynth/cms.cpp:350 msgid "Creative Music System Emulator" -msgstr "" +msgstr "Emulátor hudebního systému Creative" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33 -#, fuzzy msgid "FM-Towns Audio" -msgstr "FM Towns Emulátor" +msgstr "Zvuk FM-Towns" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58 -#, fuzzy msgid "PC-98 Audio" -msgstr "Zvuk" +msgstr "Zvuk PC-98" #: audio/softsynth/mt32.cpp:200 msgid "Initializing MT-32 Emulator" -msgstr "ZavádÃm MT-32 Emulátor" +msgstr "Zavádím MT-32 Emulátor" #: audio/softsynth/mt32.cpp:426 msgid "MT-32 Emulator" -msgstr "MT-32 Emulátor" +msgstr "MT-32 Emulátor" #: audio/softsynth/pcspk.cpp:139 msgid "PC Speaker Emulator" -msgstr "PC Speaker Emulátor" +msgstr "PC Speaker Emulátor" #: audio/softsynth/pcspk.cpp:158 msgid "IBM PCjr Emulator" -msgstr "IBM PCjr Emulátor" +msgstr "IBM PCjr Emulátor" #: audio/softsynth/sid.cpp:1430 msgid "C64 Audio Emulator" -msgstr "Emulátor zvuku C64" +msgstr "Emulátor zvuku C64" #: backends/events/default/default-events.cpp:196 msgid "Do you really want to return to the Launcher?" -msgstr "Opravdu se chcete vrátit do SpouÅ¡tÄ›Äe?" +msgstr "Opravdu se chcete vrátit do Spou¹tìèe?" #: backends/events/default/default-events.cpp:196 msgid "Launcher" -msgstr "SpouÅ¡tÄ›Ä" +msgstr "Spou¹tìè" #: backends/events/default/default-events.cpp:218 msgid "Do you really want to quit?" -msgstr "Opravdu chcete skonÄit?" +msgstr "Opravdu chcete skonèit?" #: backends/events/default/default-events.cpp:218 #: backends/platform/symbian/src/SymbianActions.cpp:52 @@ -1658,88 +1662,87 @@ msgstr "Opravdu chcete skonÄit?" #: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83 #: engines/scumm/help.cpp:85 msgid "Quit" -msgstr "UkonÄit" +msgstr "Ukonèit" #: 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 "'Režim ŤuknutÃ' Dotykové Obrazovky - Levé KliknutÃ" +msgstr "'Re¾im «uknutí' Dotykové Obrazovky - Levé Kliknutí" #: 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 "'Režim ŤuknutÃ' Dotykové Obrazovky - Pravé KliknutÃ" +msgstr "'Re¾im «uknutí' Dotykové Obrazovky - Pravé Kliknutí" #: 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 "'Režim ŤuknutÃ' Dotykové Obrazovky - Najetà (Bez KliknutÃ)" +msgstr "'Re¾im «uknutí' Dotykové Obrazovky - Najetí (Bez Kliknutí)" #: backends/events/gph/gph-events.cpp:409 msgid "Maximum Volume" -msgstr "Maximálnà Hlasitost" +msgstr "Maximální Hlasitost" #: backends/events/gph/gph-events.cpp:411 msgid "Increasing Volume" -msgstr "ZvyÅ¡uji Hlasitost" +msgstr "Zvy¹uji Hlasitost" #: backends/events/gph/gph-events.cpp:417 msgid "Minimal Volume" -msgstr "Minimálnà Hlasitost" +msgstr "Minimální Hlasitost" #: backends/events/gph/gph-events.cpp:419 msgid "Decreasing Volume" -msgstr "Snižuji Hlasitost" +msgstr "Sni¾uji Hlasitost" #: backends/events/maemosdl/maemosdl-events.cpp:180 msgid "Clicking Enabled" -msgstr "Kliknutà Povoleno" +msgstr "Kliknutí Povoleno" #: backends/events/maemosdl/maemosdl-events.cpp:180 msgid "Clicking Disabled" -msgstr "Kliknutà Zakázáno" +msgstr "Kliknutí Zakázáno" #: backends/events/openpandora/op-events.cpp:174 msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)" -msgstr "'Režim ŤuknutÃ' Dotykové Obrazovky - Najetà (Dpad kliká)" +msgstr "'Re¾im «uknutí' Dotykové Obrazovky - Najetí (Dpad kliká)" #: backends/events/symbiansdl/symbiansdl-events.cpp:186 msgid "Do you want to quit ?" -msgstr "Chcete ukonÄit ?" +msgstr "Chcete ukonèit ?" #. I18N: Trackpad mode toggle status. #: backends/events/webossdl/webossdl-events.cpp:308 -#, fuzzy msgid "Trackpad mode is now" -msgstr "Touchpad režim vypnut" +msgstr "Re¾im trackpadu je nyní" #. 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 "" +msgstr "ZAPNUT" #: backends/events/webossdl/webossdl-events.cpp:311 #: backends/events/webossdl/webossdl-events.cpp:338 msgid "OFF" -msgstr "" +msgstr "VYPNUT" #: backends/events/webossdl/webossdl-events.cpp:315 msgid "Swipe two fingers to the right to toggle." -msgstr "" +msgstr "Pro zapnutí pøejeïte dvìma prsty doprava." #. I18N: Auto-drag toggle status. #: backends/events/webossdl/webossdl-events.cpp:335 msgid "Auto-drag mode is now" -msgstr "" +msgstr "Re¾im automatického ta¾ení je nyní" #: backends/events/webossdl/webossdl-events.cpp:342 msgid "Swipe three fingers to the right to toggle." -msgstr "" +msgstr "Pro zapnutí pøejeïte tøemi prsty doprava." #: backends/graphics/opengl/opengl-graphics.cpp:119 msgid "OpenGL" @@ -1747,54 +1750,54 @@ msgstr "OpenGL" #: backends/graphics/opengl/opengl-graphics.cpp:120 msgid "OpenGL (No filtering)" -msgstr "OpenGL (bez filtrovánÃ)" +msgstr "OpenGL (bez filtrování)" #: 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 "Normálnà (bez zmÄ›ny velikosti)" +msgstr "Normální (bez zmìny velikosti)" #: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66 msgctxt "lowres" msgid "Normal (no scaling)" -msgstr "Normálnà (bez zmÄ›ny velikosti)" +msgstr "Normální (bez zmìny velikosti)" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" -msgstr "Povolena korekce pomÄ›ru stran" +msgstr "Povolena korekce pomìru stran" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" -msgstr "Zakázána korekce pomÄ›ru stran" +msgstr "Zakázána korekce pomìru stran" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" -msgstr "Aktivnà grafický filtr:" +msgstr "Aktivní grafický filtr:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" -msgstr "Režim do okna" +msgstr "Re¾im do okna" #: backends/keymapper/remap-dialog.cpp:48 msgid "Keymap:" -msgstr "Mapa Kláves:" +msgstr "Mapa Kláves:" #: backends/keymapper/remap-dialog.cpp:67 msgid " (Effective)" -msgstr " (AktivnÃ)" +msgstr " (Aktivní)" #: backends/keymapper/remap-dialog.cpp:107 msgid " (Active)" -msgstr "(AktivnÃ)" +msgstr "(Aktivní)" #: backends/keymapper/remap-dialog.cpp:107 msgid " (Blocked)" -msgstr " (Blokováno)" +msgstr " (Blokováno)" #: backends/keymapper/remap-dialog.cpp:120 msgid " (Global)" -msgstr "(GlobálnÃ)" +msgstr "(Globální)" #: backends/keymapper/remap-dialog.cpp:128 msgid " (Game)" @@ -1807,43 +1810,43 @@ msgstr "Windows MIDI" #: backends/platform/ds/arm9/source/dsoptions.cpp:56 #: engines/scumm/dialogs.cpp:291 msgid "~C~lose" -msgstr "~Z~avÅ™Ãt" +msgstr "~Z~avøít" #: backends/platform/ds/arm9/source/dsoptions.cpp:57 msgid "ScummVM Main Menu" -msgstr "Hlavnà Menu ScummVM" +msgstr "Hlavní Menu ScummVM" #: backends/platform/ds/arm9/source/dsoptions.cpp:63 msgid "~L~eft handed mode" -msgstr "~R~ežim pro leváky" +msgstr "~R~e¾im pro leváky" #: backends/platform/ds/arm9/source/dsoptions.cpp:64 msgid "~I~ndy fight controls" -msgstr "~O~vládánà Indyho boje" +msgstr "~O~vládání Indyho boje" #: backends/platform/ds/arm9/source/dsoptions.cpp:65 msgid "Show mouse cursor" -msgstr "Zobrazit kurzor myÅ¡i" +msgstr "Zobrazit kurzor my¹i" #: backends/platform/ds/arm9/source/dsoptions.cpp:66 msgid "Snap to edges" -msgstr "PÅ™ichytit k okrajům" +msgstr "Pøichytit k okrajùm" #: backends/platform/ds/arm9/source/dsoptions.cpp:68 msgid "Touch X Offset" -msgstr "Dotykové vyrovnáni na ose X" +msgstr "Dotykové vyrovnáni na ose X" #: backends/platform/ds/arm9/source/dsoptions.cpp:75 msgid "Touch Y Offset" -msgstr "Dotykové vyrovnáni na ose Y" +msgstr "Dotykové vyrovnáni na ose Y" #: backends/platform/ds/arm9/source/dsoptions.cpp:87 msgid "Use laptop trackpad-style cursor control" -msgstr "PoužÃt styl kontroly kurzoru jako u ovládacà poduÅ¡ky laptopu" +msgstr "Pou¾ít styl kontroly kurzoru jako u ovládací podu¹ky laptopu" #: backends/platform/ds/arm9/source/dsoptions.cpp:88 msgid "Tap for left click, double tap right click" -msgstr "ŤuknÄ›te pro levé kliknutÃ, dvakrát pro pravé kliknutÃ" +msgstr "«uknìte pro levé kliknutí, dvakrát pro pravé kliknutí" #: backends/platform/ds/arm9/source/dsoptions.cpp:90 msgid "Sensitivity" @@ -1851,23 +1854,23 @@ msgstr "Citlivost" #: backends/platform/ds/arm9/source/dsoptions.cpp:99 msgid "Initial top screen scale:" -msgstr "PoÄáteÄnà zmÄ›na velikosti hornà obrazovky:" +msgstr "Poèáteèní zmìna velikosti horní obrazovky:" #: backends/platform/ds/arm9/source/dsoptions.cpp:105 msgid "Main screen scaling:" -msgstr "ZmÄ›na velikosti hlavnà obrazovky:" +msgstr "Zmìna velikosti hlavní obrazovky:" #: backends/platform/ds/arm9/source/dsoptions.cpp:107 msgid "Hardware scale (fast, but low quality)" -msgstr "Hardwarová zmÄ›na velikosti (rychlé, ale nÃzká kvalita)" +msgstr "Hardwarová zmìna velikosti (rychlé, ale nízká kvalita)" #: backends/platform/ds/arm9/source/dsoptions.cpp:108 msgid "Software scale (good quality, but slower)" -msgstr "Softwarová zmÄ›na velikosti (dobrá kvalita, ale pomalejÅ¡Ã)" +msgstr "Softwarová zmìna velikosti (dobrá kvalita, ale pomalej¹í)" #: backends/platform/ds/arm9/source/dsoptions.cpp:109 msgid "Unscaled (you must scroll left and right)" -msgstr "Beze zmÄ›ny velikosti (musÃte posunovat doleva a doprava)" +msgstr "Beze zmìny velikosti (musíte posunovat doleva a doprava)" #: backends/platform/ds/arm9/source/dsoptions.cpp:111 msgid "Brightness:" @@ -1875,39 +1878,39 @@ msgstr "Jas:" #: backends/platform/ds/arm9/source/dsoptions.cpp:121 msgid "High quality audio (slower) (reboot)" -msgstr "Vysoká kvalita zvuku (pomalejÅ¡Ã) (restart) " +msgstr "Vysoká kvalita zvuku (pomalej¹í) (restart) " #: backends/platform/ds/arm9/source/dsoptions.cpp:122 msgid "Disable power off" -msgstr "Zakázat vypnutÃ" +msgstr "Zakázat vypnutí" #: 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 "Režim pÅ™etáhnutà myÅ¡i zapnut." +msgstr "Re¾im pøetáhnutí my¹i zapnut." #: 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 "Režim pÅ™etáhnutà myÅ¡i vypnut." +msgstr "Re¾im pøetáhnutí my¹i vypnut." #: 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 "Touchpad režim zapnut" +msgstr "Touchpad re¾im zapnut" #: 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 "Touchpad režim vypnut" +msgstr "Touchpad re¾im vypnut" #: backends/platform/maemo/maemo.cpp:208 msgid "Click Mode" -msgstr "Režim kliknutÃ" +msgstr "Re¾im kliknutí" #: backends/platform/maemo/maemo.cpp:214 #: backends/platform/symbian/src/SymbianActions.cpp:42 @@ -1915,30 +1918,30 @@ msgstr "Režim kliknutÃ" #: backends/platform/wince/CEActionsPocket.cpp:60 #: backends/platform/wince/CEActionsSmartphone.cpp:43 msgid "Left Click" -msgstr "Levé KliknutÃ" +msgstr "Levé Kliknutí" #: backends/platform/maemo/maemo.cpp:217 msgid "Middle Click" -msgstr "Kliknutà prostÅ™ednÃm tlaÄÃtkem" +msgstr "Kliknutí prostøedním tlaèítkem" #: 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 "Pravé kliknutÃ" +msgstr "Pravé kliknutí" #: backends/platform/sdl/macosx/appmenu_osx.mm:88 msgid "Hide ScummVM" -msgstr "Skrýt ScummVM" +msgstr "Skrýt ScummVM" #: backends/platform/sdl/macosx/appmenu_osx.mm:93 msgid "Hide Others" -msgstr "Skrýt OstatnÃ" +msgstr "Skrýt Ostatní" #: backends/platform/sdl/macosx/appmenu_osx.mm:98 msgid "Show All" -msgstr "Zobrazit VÅ¡e" +msgstr "Zobrazit V¹e" #: backends/platform/sdl/macosx/appmenu_osx.mm:120 #: backends/platform/sdl/macosx/appmenu_osx.mm:131 @@ -1957,7 +1960,7 @@ msgstr "Nahoru" #: backends/platform/symbian/src/SymbianActions.cpp:39 #: backends/platform/wince/CEActionsSmartphone.cpp:40 msgid "Down" -msgstr "Dolů" +msgstr "Dolù" #: backends/platform/symbian/src/SymbianActions.cpp:40 #: backends/platform/wince/CEActionsSmartphone.cpp:41 @@ -1982,35 +1985,35 @@ msgstr "Multi Funkce" #: backends/platform/symbian/src/SymbianActions.cpp:48 msgid "Swap character" -msgstr "ZamÄ›nit znaky" +msgstr "Zamìnit znaky" #: backends/platform/symbian/src/SymbianActions.cpp:49 msgid "Skip text" -msgstr "PÅ™eskoÄit text" +msgstr "Pøeskoèit text" #: backends/platform/symbian/src/SymbianActions.cpp:51 msgid "Fast mode" -msgstr "Rychlý režim" +msgstr "Rychlý re¾im" #: backends/platform/symbian/src/SymbianActions.cpp:53 msgid "Debugger" -msgstr "LadÃcà program" +msgstr "Ladící program" #: backends/platform/symbian/src/SymbianActions.cpp:54 msgid "Global menu" -msgstr "Globálnà menu" +msgstr "Globální menu" #: backends/platform/symbian/src/SymbianActions.cpp:55 msgid "Virtual keyboard" -msgstr "Virtuálnà klávesnice" +msgstr "Virtuální klávesnice" #: backends/platform/symbian/src/SymbianActions.cpp:56 msgid "Key mapper" -msgstr "MapovaÄ kláves" +msgstr "Mapovaè kláves" #: backends/platform/tizen/form.cpp:263 msgid "Right Click Once" -msgstr "Pravé kliknutà jednou" +msgstr "Pravé kliknutí jednou" #: backends/platform/tizen/form.cpp:271 msgid "Move Only" @@ -2018,7 +2021,7 @@ msgstr "Pouze Pohyb" #: backends/platform/tizen/form.cpp:294 msgid "Escape Key" -msgstr "Klávesa Escape" +msgstr "Klávesa Escape" #: backends/platform/tizen/form.cpp:299 msgid "Game Menu" @@ -2026,32 +2029,31 @@ msgstr "Menu Hry" #: backends/platform/tizen/form.cpp:304 msgid "Show Keypad" -msgstr "Zobrazit Klávesnici" +msgstr "Zobrazit Klávesnici" #: backends/platform/tizen/form.cpp:309 msgid "Control Mouse" -msgstr "Ovládánà MyÅ¡i" +msgstr "Ovládání My¹i" #: backends/platform/tizen/fs.cpp:259 msgid "[ Data ]" -msgstr "" +msgstr "[ Data ]" #: backends/platform/tizen/fs.cpp:263 msgid "[ Resources ]" -msgstr "" +msgstr "[ Zdroje ]" #: backends/platform/tizen/fs.cpp:267 msgid "[ SDCard ]" -msgstr "" +msgstr "[ SD Karta ]" #: backends/platform/tizen/fs.cpp:271 msgid "[ Media ]" -msgstr "" +msgstr "[ Média ]" #: backends/platform/tizen/fs.cpp:275 -#, fuzzy msgid "[ Shared ]" -msgstr "SdÃlenÃ:" +msgstr "[ Sdílené ]" #: backends/platform/wii/options.cpp:51 msgid "Video" @@ -2059,19 +2061,19 @@ msgstr "Video" #: backends/platform/wii/options.cpp:54 msgid "Current video mode:" -msgstr "SouÄasný režim obrazu:" +msgstr "Souèasný re¾im obrazu:" #: backends/platform/wii/options.cpp:56 msgid "Double-strike" -msgstr "Dvojité pÅ™eÅ¡krtnutÃ" +msgstr "Dvojité pøe¹krtnutí" #: backends/platform/wii/options.cpp:60 msgid "Horizontal underscan:" -msgstr "Horizontálnà zmenÅ¡enÃ" +msgstr "Horizontální zmen¹ení" #: backends/platform/wii/options.cpp:66 msgid "Vertical underscan:" -msgstr "Vertikálnà zmenÅ¡enÃ" +msgstr "Vertikální zmen¹ení" #: backends/platform/wii/options.cpp:71 msgid "Input" @@ -2083,7 +2085,7 @@ msgstr "Citlivost GC Padu" #: backends/platform/wii/options.cpp:80 msgid "GC Pad acceleration:" -msgstr "Zrychlenà GC Padu" +msgstr "Zrychlení GC Padu" #: backends/platform/wii/options.cpp:86 msgid "DVD" @@ -2095,11 +2097,11 @@ msgstr "Stav:" #: backends/platform/wii/options.cpp:90 backends/platform/wii/options.cpp:102 msgid "Unknown" -msgstr "Neznámé" +msgstr "Neznámé" #: backends/platform/wii/options.cpp:93 msgid "Mount DVD" -msgstr "PÅ™ipojit DVD" +msgstr "Pøipojit DVD" #: backends/platform/wii/options.cpp:94 msgid "Unmount DVD" @@ -2115,11 +2117,11 @@ msgstr "Server:" #: backends/platform/wii/options.cpp:110 msgid "Share:" -msgstr "SdÃlenÃ:" +msgstr "Sdílení:" #: backends/platform/wii/options.cpp:114 msgid "Username:" -msgstr "Uživatelské jméno" +msgstr "U¾ivatelské jméno" #: backends/platform/wii/options.cpp:118 msgid "Password:" @@ -2127,11 +2129,11 @@ msgstr "Heslo" #: backends/platform/wii/options.cpp:121 msgid "Init network" -msgstr "Spustit sÃÅ¥" +msgstr "Spustit sí»" #: backends/platform/wii/options.cpp:123 msgid "Mount SMB" -msgstr "PÅ™ipojit SMB" +msgstr "Pøipojit SMB" #: backends/platform/wii/options.cpp:124 msgid "Unmount SMB" @@ -2139,56 +2141,56 @@ msgstr "Odpojit SMB" #: backends/platform/wii/options.cpp:143 msgid "DVD Mounted successfully" -msgstr "DVD úspěšnÄ› pÅ™ipojeno" +msgstr "DVD úspì¹nì pøipojeno" #: backends/platform/wii/options.cpp:146 msgid "Error while mounting the DVD" -msgstr "Chyba pÅ™i pÅ™ipojovánà DVD" +msgstr "Chyba pøi pøipojování DVD" #: backends/platform/wii/options.cpp:148 msgid "DVD not mounted" -msgstr "DVD nepÅ™ipojeno" +msgstr "DVD nepøipojeno" #: backends/platform/wii/options.cpp:161 msgid "Network up, share mounted" -msgstr "SÃÅ¥ je zapnuta, sdÃlenà pÅ™ipojeno" +msgstr "Sí» je zapnuta, sdílení pøipojeno" #: backends/platform/wii/options.cpp:163 msgid "Network up" -msgstr "SÃÅ¥ je zapnuta" +msgstr "Sí» je zapnuta" #: backends/platform/wii/options.cpp:166 msgid ", error while mounting the share" -msgstr ", chyba pÅ™i pÅ™ipojovánà sdÃlenÃ" +msgstr ", chyba pøi pøipojování sdílení" #: backends/platform/wii/options.cpp:168 msgid ", share not mounted" -msgstr ", sdÃlenà nenà pÅ™ipojeno" +msgstr ", sdílení není pøipojeno" #: backends/platform/wii/options.cpp:174 msgid "Network down" -msgstr "SÃÅ¥ je nedostupná" +msgstr "Sí» je nedostupná" #: backends/platform/wii/options.cpp:178 msgid "Initializing network" -msgstr "ZavádÃm sÃÅ¥" +msgstr "Zavádím sí»" #: backends/platform/wii/options.cpp:182 msgid "Timeout while initializing network" -msgstr "PÅ™i zavádÄ›nà sÃtÄ› vyprÅ¡el limit" +msgstr "Pøi zavádìní sítì vypr¹el limit" #: backends/platform/wii/options.cpp:186 #, c-format msgid "Network not initialized (%d)" -msgstr "SÃÅ¥ nenà zavedena (%d)" +msgstr "Sí» není zavedena (%d)" #: backends/platform/wince/CEActionsPocket.cpp:46 msgid "Hide Toolbar" -msgstr "Skrýt Panel nástrojů" +msgstr "Skrýt Panel nástrojù" #: backends/platform/wince/CEActionsPocket.cpp:47 msgid "Show Keyboard" -msgstr "Zobrazit klávesnici" +msgstr "Zobrazit klávesnici" #: backends/platform/wince/CEActionsPocket.cpp:48 msgid "Sound on/off" @@ -2196,66 +2198,66 @@ msgstr "Zvuk zapnout/vypnout" #: backends/platform/wince/CEActionsPocket.cpp:49 msgid "Right click" -msgstr "Pravé kliknutÃ" +msgstr "Pravé kliknutí" #: backends/platform/wince/CEActionsPocket.cpp:50 msgid "Show/Hide Cursor" -msgstr "Ukázat/Skrýt Kurzor" +msgstr "Ukázat/Skrýt Kurzor" #: backends/platform/wince/CEActionsPocket.cpp:51 msgid "Free look" -msgstr "RozhlÞenà pomocà myÅ¡i" +msgstr "Rozhlí¾ení pomocí my¹i" #: backends/platform/wince/CEActionsPocket.cpp:52 msgid "Zoom up" -msgstr "PÅ™iblÞenà nahoru" +msgstr "Pøiblí¾ení nahoru" #: backends/platform/wince/CEActionsPocket.cpp:53 msgid "Zoom down" -msgstr "PÅ™iblÞenà dolů" +msgstr "Pøiblí¾ení dolù" #: backends/platform/wince/CEActionsPocket.cpp:55 #: backends/platform/wince/CEActionsSmartphone.cpp:49 msgid "Bind Keys" -msgstr "PÅ™iÅ™adit klávesy" +msgstr "Pøiøadit klávesy" #: backends/platform/wince/CEActionsPocket.cpp:56 msgid "Cursor Up" -msgstr "Å ipka Nahoru" +msgstr "©ipka Nahoru" #: backends/platform/wince/CEActionsPocket.cpp:57 msgid "Cursor Down" -msgstr "Å ipka Dolů" +msgstr "©ipka Dolù" #: backends/platform/wince/CEActionsPocket.cpp:58 msgid "Cursor Left" -msgstr "Å ipka Doleva" +msgstr "©ipka Doleva" #: backends/platform/wince/CEActionsPocket.cpp:59 msgid "Cursor Right" -msgstr "Å ipka Doprava" +msgstr "©ipka Doprava" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:231 msgid "Do you want to load or save the game?" -msgstr "Chcete hru nahrát nebo uložit?" +msgstr "Chcete hru nahrát nebo ulo¾it?" #: backends/platform/wince/CEActionsPocket.cpp:326 #: backends/platform/wince/CEActionsSmartphone.cpp:287 msgid " Are you sure you want to quit ? " -msgstr " Jste si jisti, že chcete odejÃt ? " +msgstr " Jste si jisti, ¾e chcete odejít ? " #: backends/platform/wince/CEActionsSmartphone.cpp:50 msgid "Keyboard" -msgstr "Klávesnice" +msgstr "Klávesnice" #: backends/platform/wince/CEActionsSmartphone.cpp:51 msgid "Rotate" -msgstr "OtáÄet" +msgstr "Otáèet" #: backends/platform/wince/CELauncherDialog.cpp:56 msgid "Using SDL driver " -msgstr "PoužÃvá ovladaÄ SDL" +msgstr "Pou¾ívá ovladaè SDL" #: backends/platform/wince/CELauncherDialog.cpp:60 msgid "Display " @@ -2263,42 +2265,42 @@ msgstr "Displej" #: backends/platform/wince/CELauncherDialog.cpp:83 msgid "Do you want to perform an automatic scan ?" -msgstr "Chcete provést automatické hledánà ?" +msgstr "Chcete provést automatické hledání ?" #: backends/platform/wince/wince-sdl.cpp:516 msgid "Map right click action" -msgstr "Mapovat Äinnost pravé kliknutÃ" +msgstr "Mapovat èinnost pravé kliknutí" #: backends/platform/wince/wince-sdl.cpp:520 msgid "You must map a key to the 'Right Click' action to play this game" msgstr "" -"MusÃte namapovat klávesu pro Äinnost 'Pravé KliknutÃ', abyste tuto hru " -"mohli hrát" +"Musíte namapovat klávesu pro èinnost 'Pravé Kliknutí', abyste tuto hru mohli " +"hrát" #: backends/platform/wince/wince-sdl.cpp:529 msgid "Map hide toolbar action" -msgstr "Mapovat Äinnost skrýt panel nástrojů" +msgstr "Mapovat èinnost skrýt panel nástrojù" #: backends/platform/wince/wince-sdl.cpp:533 msgid "You must map a key to the 'Hide toolbar' action to play this game" msgstr "" -"MusÃte namapovat klávesu pro Äinnost 'Skrýt Panel nástrojů', abyste tuto " -"hru mohli hrát" +"Musíte namapovat klávesu pro èinnost 'Skrýt Panel nástrojù', abyste tuto hru " +"mohli hrát" #: backends/platform/wince/wince-sdl.cpp:542 msgid "Map Zoom Up action (optional)" -msgstr "Namapovat Äinnost PÅ™iblÞit Nahoru (nepovinné)" +msgstr "Namapovat èinnost Pøiblí¾it Nahoru (nepovinné)" #: backends/platform/wince/wince-sdl.cpp:545 msgid "Map Zoom Down action (optional)" -msgstr "Namapovat Äinnost PÅ™iblÞit Dolů (nepovinné)" +msgstr "Namapovat èinnost Pøiblí¾it Dolù (nepovinné)" #: 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 "" -"Nezapomeňte namapovat klávesu k Äinnosti 'Skrýt Panel Nástrojů, abyste " -"vidÄ›li celý inventář" +"Nezapomeòte namapovat klávesu k èinnosti 'Skrýt Panel Nástrojù, abyste " +"vidìli celý inventáø" #: backends/updates/macosx/macosx-updates.mm:67 msgid "Check for Updates..." @@ -2309,47 +2311,55 @@ msgstr "Zkontrolovat Aktualizace..." #: 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 "PoužÃt původnà obrazovky naÄtenÃ/uloženÃ" +msgstr "Pou¾ít pùvodní obrazovky naètení/ulo¾ení" #: 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 "PoužÃt původnà obrazovky naÄtenÃ/uloženà mÃsto ze ScummVM" +msgstr "Pou¾ít pùvodní obrazovky naètení/ulo¾ení místo ze ScummVM" #: engines/agi/detection.cpp:157 msgid "Use an alternative palette" -msgstr "PoužÃt jinou paletu" +msgstr "Pou¾ít jinou paletu" #: engines/agi/detection.cpp:158 msgid "" "Use an alternative palette, common for all Amiga games. This was the old " "behavior" msgstr "" -"PoužÃt alternativnà paletu, běžné pro hry Amiga. Toto byl původnà starý " +"Pou¾ít alternativní paletu, bì¾né pro hry Amiga. Toto byl pùvodní starý " "standard" #: engines/agi/detection.cpp:167 msgid "Mouse support" -msgstr "Podpora myÅ¡i" +msgstr "Podpora my¹i" #: engines/agi/detection.cpp:168 msgid "" "Enables mouse support. Allows to use mouse for movement and in game menus." msgstr "" -"Povolà podporu myÅ¡i. Umožnà použÃt myÅ¡ pro pohyb a pro ovládánà hernÃ" -"ch nabÃdek." +"Povolí podporu my¹i. Umo¾ní pou¾ít my¹ pro pohyb a pro ovládání herních " +"nabídek." -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Obnovit hru" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Obnovit" @@ -2360,7 +2370,7 @@ msgid "" "\n" "%s" msgstr "" -"Nahránà stavu hry selhalo ze souboru:\n" +"Nahrání stavu hry selhalo ze souboru:\n" "\n" "%s" @@ -2371,7 +2381,7 @@ msgid "" "\n" "%s" msgstr "" -"Uloženà stavu hry selhalo do souboru:\n" +"Ulo¾ení stavu hry selhalo do souboru:\n" "\n" "%s" @@ -2382,7 +2392,7 @@ msgid "" "\n" "%s" msgstr "" -"Stav hry úspěšnÄ› uložen do:\n" +"Stav hry úspì¹nì ulo¾en do:\n" "\n" "%s" @@ -2393,11 +2403,11 @@ msgstr "Soubor videa '%s' nenalezen'" #: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101 msgid "Color Blind Mode" -msgstr "Režim pro barvoslepé" +msgstr "Re¾im pro barvoslepé" #: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102 msgid "Enable Color Blind Mode by default" -msgstr "StandardnÄ› zapÃnat režim pro barvoslepé" +msgstr "Standardnì zapínat re¾im pro barvoslepé" #: engines/drascula/saveload.cpp:47 msgid "" @@ -2409,31 +2419,31 @@ msgid "" "Press OK to convert them now, otherwise you will be asked again the next " "time you start the game.\n" msgstr "" -"ScummVM zjistil, že máte staré uložené pozice pro Drascula, které by " -"mÄ›ly být pÅ™evedeny.\n" -"Starý formát uložených her již nenà podporován, takže pokud je " -"nepÅ™evedete, nebudete moci vaÅ¡e hry naÄÃst.\n" +"ScummVM zjistil, ¾e máte staré ulo¾ené pozice pro Drascula, které by mìly " +"být pøevedeny.\n" +"Starý formát ulo¾ených her ji¾ není podporován, tak¾e pokud je nepøevedete, " +"nebudete moci va¹e hry naèíst.\n" "\n" -"StisknÄ›te OK, abyste je pÅ™evedli teÄ, jinak budete požádáni znovu, pÅ™i " -"spuÅ¡tÄ›nà této hry.\n" +"Stisknìte OK, abyste je pøevedli teï, jinak budete po¾ádáni znovu, pøi " +"spu¹tìní této hry.\n" #: engines/dreamweb/detection.cpp:57 msgid "Use bright palette mode" -msgstr "PoužÃt režim jasné palety" +msgstr "Pou¾ít re¾im jasné palety" #: engines/dreamweb/detection.cpp:58 msgid "Display graphics using the game's bright palette" -msgstr "Zobrazit grafiku pomocà jasné palety hry" +msgstr "Zobrazit grafiku pomocí jasné palety hry" #: 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 "Nelze naÄÃst stav hry ze souboru." +msgstr "Nelze naèíst stav hry ze souboru." #: 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 "Nelze uložit stav hry do souboru." +msgstr "Nelze ulo¾it stav hry do souboru." #: engines/gob/inter_v5.cpp:107 msgid "Failed to delete file." @@ -2441,23 +2451,23 @@ msgstr "Nelze smazat soubor." #: engines/groovie/detection.cpp:312 msgid "Fast movie speed" -msgstr "Zvýšená rychlost videa" +msgstr "Zvý¹ená rychlost videa" #: engines/groovie/detection.cpp:313 msgid "Play movies at an increased speed" -msgstr "PÅ™ehrát videa se zvýšenou rychlostÃ" +msgstr "Pøehrát videa se zvý¹enou rychlostí" #: engines/groovie/script.cpp:408 msgid "Failed to save game" -msgstr "Nelze uložit hru." +msgstr "Nelze ulo¾it hru." #: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86 msgid "Gore Mode" -msgstr "Povolit násilné scény" +msgstr "Povolit násilné scény" #: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87 msgid "Enable Gore Mode when available" -msgstr "Povolit násilné scény, jsou-li dostupné" +msgstr "Povolit násilné scény, jsou-li dostupné" #. I18N: Studio audience adds an applause and cheering sounds whenever #. Malcolm makes a joke. @@ -2472,66 +2482,66 @@ msgstr "Povolit publikum ve studiu" #. I18N: This option allows the user to skip text and cutscenes. #: engines/kyra/detection.cpp:73 msgid "Skip support" -msgstr "Podpora pÅ™eskoÄenÃ" +msgstr "Podpora pøeskoèení" #: engines/kyra/detection.cpp:74 msgid "Allow text and cutscenes to be skipped" -msgstr "Umožnit, aby text a videa mohly být pÅ™eskoÄeny" +msgstr "Umo¾nit, aby text a videa mohly být pøeskoèeny" #. I18N: Helium mode makes people sound like they've inhaled Helium. #: engines/kyra/detection.cpp:84 msgid "Helium mode" -msgstr "Héliový režim" +msgstr "Héliový re¾im" #: engines/kyra/detection.cpp:85 msgid "Enable helium mode" -msgstr "Zapnout héliový režim" +msgstr "Zapnout héliový re¾im" #. I18N: When enabled, this option makes scrolling smoother when #. changing from one screen to another. #: engines/kyra/detection.cpp:99 msgid "Smooth scrolling" -msgstr "Plynulé posunovánÃ" +msgstr "Plynulé posunování" #: engines/kyra/detection.cpp:100 msgid "Enable smooth scrolling when walking" -msgstr "Povolit plynulé posunovánà pÅ™i chůzi" +msgstr "Povolit plynulé posunování pøi chùzi" #. 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 "Plovoucà kurzory" +msgstr "Plovoucí kurzory" #: engines/kyra/detection.cpp:113 msgid "Enable floating cursors" -msgstr "Povolit plovoucà kurzory" +msgstr "Povolit plovoucí kurzory" #. I18N: HP stands for Hit Points #: engines/kyra/detection.cpp:127 msgid "HP bar graphs" -msgstr "Sloupcový indikátor zdravÃ" +msgstr "Sloupcový indikátor zdraví" #: engines/kyra/detection.cpp:128 msgid "Enable hit point bar graphs" -msgstr "Povolit sloupcový indikátor zdravÃ" +msgstr "Povolit sloupcový indikátor zdraví" #: engines/kyra/lol.cpp:478 msgid "Attack 1" -msgstr "Útok 1" +msgstr "Útok 1" #: engines/kyra/lol.cpp:479 msgid "Attack 2" -msgstr "Útok 2" +msgstr "Útok 2" #: engines/kyra/lol.cpp:480 msgid "Attack 3" -msgstr "Útok 3" +msgstr "Útok 3" #: engines/kyra/lol.cpp:481 msgid "Move Forward" -msgstr "VpÅ™ed" +msgstr "Vpøed" #: engines/kyra/lol.cpp:482 msgid "Move Back" @@ -2539,23 +2549,23 @@ msgstr "Vzad" #: engines/kyra/lol.cpp:483 msgid "Slide Left" -msgstr "PÅ™esunout se Doleva" +msgstr "Pøesunout se Doleva" #: engines/kyra/lol.cpp:484 msgid "Slide Right" -msgstr "PÅ™esunout se Doprava" +msgstr "Pøesunout se Doprava" #: engines/kyra/lol.cpp:485 engines/pegasus/pegasus.cpp:2509 msgid "Turn Left" -msgstr "OtoÄit se doleva" +msgstr "Otoèit se doleva" #: engines/kyra/lol.cpp:486 engines/pegasus/pegasus.cpp:2510 msgid "Turn Right" -msgstr "OtoÄit se doprava" +msgstr "Otoèit se doprava" #: engines/kyra/lol.cpp:487 msgid "Rest" -msgstr "OdpoÄinout si" +msgstr "Odpoèinout si" #: engines/kyra/lol.cpp:488 msgid "Options" @@ -2573,11 +2583,11 @@ msgid "" "General MIDI ones. It is still possible that\n" "some tracks sound incorrect." msgstr "" -"Zdá se, že použÃváte zaÅ™Ãzenà General MIDI,\n" -"ale vaÅ¡e hra podporuje pouze Roland MT32 MIDI.\n" -"SnažÃme se mapovat nástroje Roland MT32 na\n" -"ty od General MIDI. Je stále možné, že\n" -"nÄ›které stopy nebudou znÃt správnÄ›." +"Zdá se, ¾e pou¾íváte zaøízení General MIDI,\n" +"ale va¹e hra podporuje pouze Roland MT32 MIDI.\n" +"Sna¾íme se mapovat nástroje Roland MT32 na\n" +"ty od General MIDI. Je stále mo¾né, ¾e\n" +"nìkteré stopy nebudou znít správnì." #: engines/kyra/saveload_eob.cpp:557 #, c-format @@ -2589,11 +2599,11 @@ msgid "" "Do you wish to use this save game file with ScummVM?\n" "\n" msgstr "" -"V cestÄ› vaÅ¡Ã hry byl nalezen následujÃcà soubor s uloženou hrou:\n" +"V cestì va¹í hry byl nalezen následující soubor s ulo¾enou hrou:\n" "\n" "%s %s\n" "\n" -"Chcete tento soubor použÃt v ScummVM?\n" +"Chcete tento soubor pou¾ít v ScummVM?\n" "\n" #: engines/kyra/saveload_eob.cpp:590 @@ -2602,7 +2612,7 @@ msgid "" "A save game file was found in the specified slot %d. Overwrite?\n" "\n" msgstr "" -"V urÄené pozici %d byl nalezen soubor s uloženou hrou. PÅ™epsat?\n" +"V urèené pozici %d byl nalezen soubor s ulo¾enou hrou. Pøepsat?\n" "\n" #: engines/kyra/saveload_eob.cpp:623 @@ -2615,24 +2625,24 @@ msgid "" "'import_savefile'.\n" "\n" msgstr "" -"%d původnÃch souborů s uloženou hrou bylo úspěšnÄ› importováno do\n" -"ScummVM. Pokud chcete pozdÄ›ji toto uÄinit znovu ruÄnÄ›, je tÅ™eba otevÅ™Ãt\n" -"ladÃcà konzoli ScummVM a použÃt pÅ™Ãkaz 'import_savefile'.\n" +"%d pùvodních souborù s ulo¾enou hrou bylo úspì¹nì importováno do\n" +"ScummVM. Pokud chcete pozdìji toto uèinit znovu ruènì, je tøeba otevøít\n" +"ladící konzoli ScummVM a pou¾ít pøíkaz '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 "~R~ežim SviÅ¡tÄ›nà Aktivován" +msgstr "~R~e¾im Svi¹tìní Aktivován" #: engines/mohawk/dialogs.cpp:93 msgid "~T~ransitions Enabled" -msgstr "~P~Å™echody zapnuty" +msgstr "~P~øechody zapnuty" #. I18N: Drop book page #: engines/mohawk/dialogs.cpp:95 msgid "~D~rop Page" -msgstr "~Z~ahodit Stránku" +msgstr "~Z~ahodit Stránku" #: engines/mohawk/dialogs.cpp:99 msgid "~S~how Map" @@ -2640,7 +2650,7 @@ msgstr "~Z~obrazit Mapu" #: engines/mohawk/dialogs.cpp:105 msgid "~M~ain Menu" -msgstr "~H~lavnà Menu" +msgstr "~H~lavní Menu" #: engines/mohawk/dialogs.cpp:168 msgid "~W~ater Effect Enabled" @@ -2648,19 +2658,19 @@ msgstr "~E~fekt Vody Zapnut" #: engines/neverhood/detection.cpp:167 msgid "Skip the Hall of Records storyboard scenes" -msgstr "PÅ™eskoÄit scény v SÃni záznamů" +msgstr "Pøeskoèit scény v Síni záznamù" #: engines/neverhood/detection.cpp:168 msgid "Allows the player to skip past the Hall of Records storyboard scenes" -msgstr "Umožňuje hráÄi pÅ™eskoÄit scény v SÃni záznamů" +msgstr "Umo¾òuje hráèi pøeskoèit scény v Síni záznamù" #: engines/neverhood/detection.cpp:174 msgid "Scale the making of videos to full screen" -msgstr "ZvÄ›tÅ¡it filmy o výrobÄ› na celou obrazovku" +msgstr "Zvìt¹it filmy o výrobì na celou obrazovku" #: engines/neverhood/detection.cpp:175 msgid "Scale the making of videos, so that they use the whole screen" -msgstr "ZvÄ›tÅ¡it filmy o výrobÄ› tak, aby využivaly celou obrazovku" +msgstr "Zvìt¹it filmy o výrobì tak, aby vyu¾ivaly celou obrazovku" #: engines/parallaction/saveload.cpp:133 #, c-format @@ -2668,16 +2678,26 @@ msgid "" "Can't save game in slot %i\n" "\n" msgstr "" -"Nelze uložit hru do pozice %i\n" +"Nelze ulo¾it hru do pozice %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +#, fuzzy +msgid "Load file" +msgstr "Nahrát hru:" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." -msgstr "Nahrávánà hry..." +msgstr "Nahrávání hry..." + +#: engines/parallaction/saveload.cpp:212 +#, fuzzy +msgid "Save file" +msgstr "Ukládání hry selhalo!" #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." -msgstr "Ukládánà hry..." +msgstr "Ukládání hry..." #: engines/parallaction/saveload.cpp:272 msgid "" @@ -2688,16 +2708,16 @@ msgid "" "\n" "Press OK to convert them now, otherwise you will be asked next time.\n" msgstr "" -"ScummVM zjistil, že máte staré uložené pozice pro Nippon Safes, které " -"by mÄ›ly být pÅ™ejmenovány.\n" -"Staré názvy již nejsou podporovány, takže pokud je nepÅ™evedete, " -"nebudete moci vaÅ¡e hry naÄÃst.\n" +"ScummVM zjistil, ¾e máte staré ulo¾ené pozice pro Nippon Safes, které by " +"mìly být pøejmenovány.\n" +"Staré názvy ji¾ nejsou podporovány, tak¾e pokud je nepøevedete, nebudete " +"moci va¹e hry naèíst.\n" "\n" -"StisknÄ›te OK, abyste je pÅ™evedli teÄ, jinak budete požádáni pÅ™ÃÅ¡tÄ›.\n" +"Stisknìte OK, abyste je pøevedli teï, jinak budete po¾ádáni pøí¹tì.\n" #: engines/parallaction/saveload.cpp:319 msgid "ScummVM successfully converted all your savefiles." -msgstr "ScummVM úspěšnÄ› pÅ™evedl vÅ¡echny vaÅ¡e uložené pozice. " +msgstr "ScummVM úspì¹nì pøevedl v¹echny va¹e ulo¾ené pozice. " #: engines/parallaction/saveload.cpp:321 msgid "" @@ -2706,211 +2726,208 @@ msgid "" "\n" "Please report to the team." msgstr "" -"ScummVM vytiskl nÄ›která varovánà ve vaÅ¡em oknÄ› konzole a nemůže " -"zaruÄit, že vÅ¡echny vaÅ¡e soubory byly pÅ™evedeny.\n" +"ScummVM vytiskl nìkterá varování ve va¹em oknì konzole a nemù¾e zaruèit, ¾e " +"v¹echny va¹e soubory byly pøevedeny.\n" "\n" -"ProsÃm nahlaste to týmu" +"Prosím nahlaste to týmu" #: engines/pegasus/pegasus.cpp:714 msgid "Invalid save file name" -msgstr "Neplatný název souboru" +msgstr "Neplatný název souboru" #: engines/pegasus/pegasus.cpp:2507 msgid "Up/Zoom In/Move Forward/Open Doors" -msgstr "Nahoru/PÅ™iblÞit/Pohyb dopÅ™edu/OtevÅ™Ãt dveÅ™e" +msgstr "Nahoru/Pøiblí¾it/Pohyb dopøedu/Otevøít dveøe" #: engines/pegasus/pegasus.cpp:2508 msgid "Down/Zoom Out" -msgstr "Dolů/OddálenÃ" +msgstr "Dolù/Oddálení" #: engines/pegasus/pegasus.cpp:2511 msgid "Display/Hide Inventory Tray" -msgstr "Zobrazit/Skrýt podnos inventáře" +msgstr "Zobrazit/Skrýt podnos inventáøe" #: engines/pegasus/pegasus.cpp:2512 msgid "Display/Hide Biochip Tray" -msgstr "Zobrazit/Skrýt podnos bioÄipu" +msgstr "Zobrazit/Skrýt podnos bioèipu" #: engines/pegasus/pegasus.cpp:2513 msgid "Action/Select" -msgstr "ÄŒinnost/Vybrat" +msgstr "Èinnost/Vybrat" #: engines/pegasus/pegasus.cpp:2514 msgid "Toggle Center Data Display" -msgstr "PÅ™epnout centrálnà datovou obrazovku" +msgstr "Pøepnout centrální datovou obrazovku" #: engines/pegasus/pegasus.cpp:2515 msgid "Display/Hide Info Screen" -msgstr "Zobrazit/Skrýto obrazovku informacÃ" +msgstr "Zobrazit/Skrýto obrazovku informací" #: engines/pegasus/pegasus.cpp:2516 msgid "Display/Hide Pause Menu" -msgstr "Zobrazit/Skrýt " +msgstr "Zobrazit/Skrýt " #: engines/queen/detection.cpp:56 msgid "Alternative intro" -msgstr "Alternativnà úvod" +msgstr "Alternativní úvod" #: engines/queen/detection.cpp:57 msgid "Use an alternative game intro (CD version only)" -msgstr "PoužÃt jinou verzi úvodu (Pouze verze CD)" +msgstr "Pou¾ít jinou verzi úvodu (Pouze verze CD)" #: engines/sci/detection.cpp:374 msgid "Skip EGA dithering pass (full color backgrounds)" -msgstr "PÅ™ekoÄit průchod rozkladu barev EGA (pozadà v plných barvách)" +msgstr "Pøekoèit prùchod rozkladu barev EGA (pozadí v plných barvách)" #: engines/sci/detection.cpp:375 msgid "Skip dithering pass in EGA games, graphics are shown with full colors" msgstr "" -"PÅ™eskoÄit průchod rozkladu barev EGA, obraze je zobrazen v plných barvách" +"Pøeskoèit prùchod rozkladu barev EGA, obraze je zobrazen v plných barvách" #: engines/sci/detection.cpp:384 -#, fuzzy msgid "Enable high resolution graphics" -msgstr "Povolit sloupcový indikátor zdravÃ" +msgstr "Povolit grafiku ve vysokém rozli¹ení" #: engines/sci/detection.cpp:385 -#, fuzzy msgid "Enable high resolution graphics/content" -msgstr "Povolit sloupcový indikátor zdravÃ" +msgstr "Povolit grafiku/obsah ve vysokém rozli¹ení" #: engines/sci/detection.cpp:394 msgid "Prefer digital sound effects" -msgstr "UpÅ™ednostňovat digitálnà zvukové efekty" +msgstr "Upøednostòovat digitální zvukové efekty" #: engines/sci/detection.cpp:395 msgid "Prefer digital sound effects instead of synthesized ones" -msgstr "UpÅ™ednostňovat digitálnà zvukové efekty pÅ™ed syntetizovanými" +msgstr "Upøednostòovat digitální zvukové efekty pøed syntetizovanými" #: engines/sci/detection.cpp:414 msgid "Use IMF/Yamaha FB-01 for MIDI output" -msgstr "PoužÃt IMF/Yamaha FB-01 pro výstup MIDI" +msgstr "Pou¾ít IMF/Yamaha FB-01 pro výstup MIDI" #: engines/sci/detection.cpp:415 msgid "" "Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI " "output" msgstr "" -"PoužÃt kartu IBM Music Feature nebo modul syntetizátoru Yamaha FB-01 FM " -"pro výstup MIDI" +"Pou¾ít kartu IBM Music Feature nebo modul syntetizátoru Yamaha FB-01 FM pro " +"výstup MIDI" #: engines/sci/detection.cpp:425 msgid "Use CD audio" -msgstr "PoužÃt zvuky na CD" +msgstr "Pou¾ít zvuky na CD" #: engines/sci/detection.cpp:426 msgid "Use CD audio instead of in-game audio, if available" -msgstr "PoužÃt zvuky na CD mÃsto ve hÅ™e, pokud je dostupné" +msgstr "Pou¾ít zvuky na CD místo ve høe, pokud je dostupné" #: engines/sci/detection.cpp:436 msgid "Use Windows cursors" -msgstr "PoužÃt kurzory Windows" +msgstr "Pou¾ít kurzory Windows" #: engines/sci/detection.cpp:437 msgid "" "Use the Windows cursors (smaller and monochrome) instead of the DOS ones" -msgstr "PoužÃt kurzory Windows (menÅ¡Ã a ÄernobÃlé) mÃsto kurzorů z DOS" +msgstr "Pou¾ít kurzory Windows (men¹í a èernobílé) místo kurzorù z DOS" #: engines/sci/detection.cpp:447 msgid "Use silver cursors" -msgstr "PoužÃt stÅ™Ãbrné kurzory" +msgstr "Pou¾ít støíbrné kurzory" #: engines/sci/detection.cpp:448 msgid "" "Use the alternate set of silver cursors, instead of the normal golden ones" -msgstr "" -"PoužÃt alternativnà sadu stÅ™Ãbrných kurzorů mÃsto standardnÃch zlatých" +msgstr "Pou¾ít alternativní sadu støíbrných kurzorù místo standardních zlatých" #: engines/scumm/dialogs.cpp:176 #, c-format msgid "Insert Disk %c and Press Button to Continue." -msgstr "Vložte Disk %c a StisknÄ›te TlaÄÃtko Pro PokraÄovánÃ." +msgstr "Vlo¾te Disk %c a Stisknìte Tlaèítko Pro Pokraèování." #: engines/scumm/dialogs.cpp:177 #, c-format msgid "Unable to Find %s, (%c%d) Press Button." -msgstr "Nelze NajÃt %s, (%c%d) StisknÄ›te TlaÄÃtko." +msgstr "Nelze Najít %s, (%c%d) Stisknìte Tlaèítko." #: engines/scumm/dialogs.cpp:178 #, c-format msgid "Error reading disk %c, (%c%d) Press Button." -msgstr "Chyba pÅ™i Ätenà disku %c, (%c%d) StisknÄ›te TlaÄÃtko." +msgstr "Chyba pøi ètení disku %c, (%c%d) Stisknìte Tlaèítko." #: engines/scumm/dialogs.cpp:179 msgid "Game Paused. Press SPACE to Continue." -msgstr "Hra Pozastavena. StisknÄ›te MEZERNÃK pro pokraÄovánÃ." +msgstr "Hra Pozastavena. Stisknìte MEZERNÍK pro pokraèování." #. 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 "Jste si jisti, že chcete restartovat? (A/N)A" +msgstr "Jste si jisti, ¾e chcete restartovat? (A/N)A" #. 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 "Jste si jisti, že chcete odejÃt? (A/N)A" +msgstr "Jste si jisti, ¾e chcete odejít? (A/N)A" #: engines/scumm/dialogs.cpp:190 msgid "Play" -msgstr "Hrát" +msgstr "Hrát" #: engines/scumm/dialogs.cpp:194 msgid "Insert save/load game disk" -msgstr "Vložte hernà disk pro uloženÃ/naÄtenÃ" +msgstr "Vlo¾te herní disk pro ulo¾ení/naètení" #: engines/scumm/dialogs.cpp:195 msgid "You must enter a name" -msgstr "MusÃte zadat jméno" +msgstr "Musíte zadat jméno" #: engines/scumm/dialogs.cpp:196 msgid "The game was NOT saved (disk full?)" -msgstr "Hra NEBYLA uložena (plný disk?)" +msgstr "Hra NEBYLA ulo¾ena (plný disk?)" #: engines/scumm/dialogs.cpp:197 msgid "The game was NOT loaded" -msgstr "Hra NEBYLA naÄtena" +msgstr "Hra NEBYLA naètena" #: engines/scumm/dialogs.cpp:198 #, c-format msgid "Saving '%s'" -msgstr "Ukládám '%s'" +msgstr "Ukládám '%s'" #: engines/scumm/dialogs.cpp:199 #, c-format msgid "Loading '%s'" -msgstr "NaÄÃtám '%s'" +msgstr "Naèítám '%s'" #: engines/scumm/dialogs.cpp:200 msgid "Name your SAVE game" -msgstr "Pojmenujte svoji ULOŽENOU hru" +msgstr "Pojmenujte svoji ULO®ENOU hru" #: engines/scumm/dialogs.cpp:201 msgid "Select a game to LOAD" -msgstr "Vyberte hru k NAÄŒTENÃ" +msgstr "Vyberte hru k NAÈTENÍ" #: engines/scumm/dialogs.cpp:202 msgid "Game title)" -msgstr "Název hry" +msgstr "Název hry" #. I18N: Previous page button #: engines/scumm/dialogs.cpp:288 msgid "~P~revious" -msgstr "~P~Å™edchozÃ" +msgstr "~P~øedchozí" #. I18N: Next page button #: engines/scumm/dialogs.cpp:290 msgid "~N~ext" -msgstr "~D~alÅ¡Ã" +msgstr "~D~al¹í" #: engines/scumm/dialogs.cpp:602 msgid "Speech Only" -msgstr "Pouze ŘeÄ" +msgstr "Pouze Øeè" #: engines/scumm/dialogs.cpp:603 msgid "Speech and Subtitles" -msgstr "ŘeÄ a Titulky" +msgstr "Øeè a Titulky" #: engines/scumm/dialogs.cpp:604 msgid "Subtitles Only" @@ -2919,47 +2936,47 @@ msgstr "Pouze Titulky" #: engines/scumm/dialogs.cpp:612 msgctxt "lowres" msgid "Speech & Subs" -msgstr "ŘeÄ a Titulky" +msgstr "Øeè a Titulky" #: engines/scumm/dialogs.cpp:658 msgid "Select a Proficiency Level." -msgstr "Vyberte úroveň odbornosti." +msgstr "Vyberte úroveò odbornosti." #: engines/scumm/dialogs.cpp:660 msgid "Refer to your Loom(TM) manual for help." -msgstr "Pro nápovÄ›du si pÅ™eÄtÄ›te manuál Loom(TM)." +msgstr "Pro nápovìdu si pøeètìte manuál Loom(TM)." #: engines/scumm/dialogs.cpp:664 msgid "Practice" -msgstr "CviÄenÃ" +msgstr "Cvièení" #: engines/scumm/dialogs.cpp:665 msgid "Expert" -msgstr "PokroÄilý" +msgstr "Pokroèilý" #: engines/scumm/help.cpp:74 msgid "Common keyboard commands:" -msgstr "Běžné klávesové pÅ™Ãkazy" +msgstr "Bì¾né klávesové pøíkazy" #: engines/scumm/help.cpp:75 msgid "Save / Load dialog" -msgstr "Dialog Nahrát / Uložit" +msgstr "Dialog Nahrát / Ulo¾it" #: engines/scumm/help.cpp:77 msgid "Skip line of text" -msgstr "PÅ™eskoÄit řádek textu" +msgstr "Pøeskoèit øádek textu" #: engines/scumm/help.cpp:78 msgid "Esc" -msgstr "MezernÃk" +msgstr "Mezerník" #: engines/scumm/help.cpp:78 msgid "Skip cutscene" -msgstr "PÅ™eskoÄit video" +msgstr "Pøeskoèit video" #: engines/scumm/help.cpp:79 msgid "Space" -msgstr "MezernÃk" +msgstr "Mezerník" #: engines/scumm/help.cpp:79 msgid "Pause game" @@ -2975,7 +2992,7 @@ msgstr "Ctrl" #: engines/scumm/help.cpp:80 msgid "Load game state 1-10" -msgstr "Nahrát stav hry 1-10" +msgstr "Nahrát stav hry 1-10" #: engines/scumm/help.cpp:81 engines/scumm/help.cpp:85 #: engines/scumm/help.cpp:87 engines/scumm/help.cpp:101 @@ -2985,7 +3002,7 @@ msgstr "Alt" #: engines/scumm/help.cpp:81 msgid "Save game state 1-10" -msgstr "Uložit stav hry 1-10" +msgstr "Ulo¾it stav hry 1-10" #: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90 msgid "Enter" @@ -2993,15 +3010,15 @@ msgstr "Enter" #: engines/scumm/help.cpp:88 msgid "Music volume up / down" -msgstr "Hlasitost hudby nahoru / dolů" +msgstr "Hlasitost hudby nahoru / dolù" #: engines/scumm/help.cpp:89 msgid "Text speed slower / faster" -msgstr "Zvýšit / SnÞit rychlost textu" +msgstr "Zvý¹it / Sní¾it rychlost textu" #: engines/scumm/help.cpp:90 msgid "Simulate left mouse button" -msgstr "Napodobit levé tlaÄÃtko myÅ¡i" +msgstr "Napodobit levé tlaèítko my¹i" #: engines/scumm/help.cpp:91 msgid "Tab" @@ -3009,116 +3026,116 @@ msgstr "Tab" #: engines/scumm/help.cpp:91 msgid "Simulate right mouse button" -msgstr "Napodobit pravé tlaÄÃtko myÅ¡i" +msgstr "Napodobit pravé tlaèítko my¹i" #: engines/scumm/help.cpp:94 msgid "Special keyboard commands:" -msgstr "Speciálnà klávesové pÅ™Ãkazy" +msgstr "Speciální klávesové pøíkazy" #: engines/scumm/help.cpp:95 msgid "Show / Hide console" -msgstr "Ukázat / Skrýt konzoli" +msgstr "Ukázat / Skrýt konzoli" #: engines/scumm/help.cpp:96 msgid "Start the debugger" -msgstr "Spustit ladÃcà program" +msgstr "Spustit ladící program" #: engines/scumm/help.cpp:97 msgid "Show memory consumption" -msgstr "Zobrazit spotÅ™ebu pamÄ›ti" +msgstr "Zobrazit spotøebu pamìti" #: engines/scumm/help.cpp:98 msgid "Run in fast mode (*)" -msgstr "Spustit v rychlém režimu (*)" +msgstr "Spustit v rychlém re¾imu (*)" #: engines/scumm/help.cpp:99 msgid "Run in really fast mode (*)" -msgstr "Spustit ve velmi rychlém režimu (*)" +msgstr "Spustit ve velmi rychlém re¾imu (*)" #: engines/scumm/help.cpp:100 msgid "Toggle mouse capture" -msgstr "Povolit zachycovánà myÅ¡i" +msgstr "Povolit zachycování my¹i" #: engines/scumm/help.cpp:101 msgid "Switch between graphics filters" -msgstr "PÅ™epÃnat mezi grafickými filtry" +msgstr "Pøepínat mezi grafickými filtry" #: engines/scumm/help.cpp:102 msgid "Increase / Decrease scale factor" -msgstr "ZvÄ›tÅ¡it / ZmenÅ¡it faktor zmÄ›ny velikosti" +msgstr "Zvìt¹it / Zmen¹it faktor zmìny velikosti" #: engines/scumm/help.cpp:103 msgid "Toggle aspect-ratio correction" -msgstr "Povolit korekci pomÄ›ru stran" +msgstr "Povolit korekci pomìru stran" #: engines/scumm/help.cpp:108 msgid "* Note that using ctrl-f and" -msgstr "Upozorňujeme, že použÃvánà ctrl-f a" +msgstr "Upozoròujeme, ¾e pou¾ívání ctrl-f a" #: engines/scumm/help.cpp:109 msgid " ctrl-g are not recommended" -msgstr " ctrl-g nenà doporuÄeno" +msgstr " ctrl-g není doporuèeno" #: engines/scumm/help.cpp:110 msgid " since they may cause crashes" -msgstr "jelikož můžou způsobit pád" +msgstr "jeliko¾ mù¾ou zpùsobit pád" #: engines/scumm/help.cpp:111 msgid " or incorrect game behavior." -msgstr " nebo nesprávné chovánà hry." +msgstr " nebo nesprávné chování hry." #: engines/scumm/help.cpp:115 msgid "Spinning drafts on the keyboard:" -msgstr "Pletenà náÄrtků na klávesnici:" +msgstr "Pletení náèrtkù na klávesnici:" #: engines/scumm/help.cpp:117 msgid "Main game controls:" -msgstr "Hlavnà ovládacà prvky:" +msgstr "Hlavní ovládací prvky:" #: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137 #: engines/scumm/help.cpp:162 msgid "Push" -msgstr "TlaÄit" +msgstr "Tlaèit" #: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138 #: engines/scumm/help.cpp:163 msgid "Pull" -msgstr "Táhnout" +msgstr "Táhnout" #: 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 "Dát" +msgstr "Dát" #: 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 "OtevÅ™Ãt" +msgstr "Otevøít" #: engines/scumm/help.cpp:127 msgid "Go to" -msgstr "JÃt do" +msgstr "Jít do" #: engines/scumm/help.cpp:128 msgid "Get" -msgstr "VzÃt" +msgstr "Vzít" #: 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 "PoužÃt" +msgstr "Pou¾ít" #: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142 msgid "Read" -msgstr "PÅ™eÄÃst" +msgstr "Pøeèíst" #: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148 msgid "New kid" -msgstr "Nové dÃtÄ›" +msgstr "Nové dítì" #: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154 #: engines/scumm/help.cpp:172 @@ -3133,7 +3150,7 @@ msgstr "Vypnout" #: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168 #: engines/scumm/help.cpp:195 msgid "Walk to" -msgstr "PÅ™ejÃt na" +msgstr "Pøejít na" #: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169 #: engines/scumm/help.cpp:196 engines/scumm/help.cpp:211 @@ -3151,11 +3168,11 @@ msgstr "Odemknout" #: engines/scumm/help.cpp:150 msgid "Put on" -msgstr "Obléct" +msgstr "Obléct" #: engines/scumm/help.cpp:151 msgid "Take off" -msgstr "Svléct" +msgstr "Svléct" #: engines/scumm/help.cpp:157 msgid "Fix" @@ -3163,11 +3180,11 @@ msgstr "Spravit" #: engines/scumm/help.cpp:159 msgid "Switch" -msgstr "PÅ™epnout" +msgstr "Pøepnout" #: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229 msgid "Look" -msgstr "DÃvat se" +msgstr "Dívat se" #: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224 msgid "Talk" @@ -3184,43 +3201,43 @@ msgstr "Henrymu / Indymu" #. I18N: These are different musical notes #: engines/scumm/help.cpp:180 msgid "play C minor on distaff" -msgstr "zahrát c moll na pÅ™eslici" +msgstr "zahrát c moll na pøeslici" #: engines/scumm/help.cpp:181 msgid "play D on distaff" -msgstr "zahrát D na pÅ™eslici" +msgstr "zahrát D na pøeslici" #: engines/scumm/help.cpp:182 msgid "play E on distaff" -msgstr "zahrát E na pÅ™eslici" +msgstr "zahrát E na pøeslici" #: engines/scumm/help.cpp:183 msgid "play F on distaff" -msgstr "zahrát F na pÅ™eslici" +msgstr "zahrát F na pøeslici" #: engines/scumm/help.cpp:184 msgid "play G on distaff" -msgstr "zahrát G na pÅ™eslici" +msgstr "zahrát G na pøeslici" #: engines/scumm/help.cpp:185 msgid "play A on distaff" -msgstr "zahrát A na pÅ™eslici" +msgstr "zahrát A na pøeslici" #: engines/scumm/help.cpp:186 msgid "play B on distaff" -msgstr "zahrát B na pÅ™eslici" +msgstr "zahrát B na pøeslici" #: engines/scumm/help.cpp:187 msgid "play C major on distaff" -msgstr "zahrát C dur na pÅ™eslici" +msgstr "zahrát C dur na pøeslici" #: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215 msgid "puSh" -msgstr "tlaÄIt" +msgstr "tlaèIt" #: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216 msgid "pull (Yank)" -msgstr "táhnout (Å kubnout)" +msgstr "táhnout (©kubnout)" #: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213 #: engines/scumm/help.cpp:249 @@ -3229,7 +3246,7 @@ msgstr "Mluvit s" #: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212 msgid "Look at" -msgstr "DÃvat se na" +msgstr "Dívat se na" #: engines/scumm/help.cpp:201 msgid "turn oN" @@ -3241,28 +3258,28 @@ msgstr "vypnoUt" #: engines/scumm/help.cpp:218 msgid "KeyUp" -msgstr "KlávesaNahoru" +msgstr "KlávesaNahoru" #: engines/scumm/help.cpp:218 msgid "Highlight prev dialogue" -msgstr "Zvýraznit pÅ™edchozà dialog" +msgstr "Zvýraznit pøedchozí dialog" #: engines/scumm/help.cpp:219 msgid "KeyDown" -msgstr "KlávesaDolů" +msgstr "KlávesaDolù" #: engines/scumm/help.cpp:219 msgid "Highlight next dialogue" -msgstr "Zvýraznit následujÃcà dialog" +msgstr "Zvýraznit následující dialog" #: engines/scumm/help.cpp:223 msgid "Walk" -msgstr "JÃt" +msgstr "Jít" #: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235 #: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250 msgid "Inventory" -msgstr "Inventář" +msgstr "Inventáø" #: engines/scumm/help.cpp:227 msgid "Object" @@ -3270,11 +3287,11 @@ msgstr "Objekt" #: engines/scumm/help.cpp:230 msgid "Black and White / Color" -msgstr "ÄŒernobÃlé / Barva" +msgstr "Èernobílé / Barva" #: engines/scumm/help.cpp:233 msgid "Eyes" -msgstr "OÄi" +msgstr "Oèi" #: engines/scumm/help.cpp:234 msgid "Tongue" @@ -3282,7 +3299,7 @@ msgstr "Jazyk" #: engines/scumm/help.cpp:236 msgid "Punch" -msgstr "UdeÅ™it" +msgstr "Udeøit" #: engines/scumm/help.cpp:237 msgid "Kick" @@ -3290,11 +3307,11 @@ msgstr "Kopnout" #: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248 msgid "Examine" -msgstr "Prohlédnout" +msgstr "Prohlédnout" #: engines/scumm/help.cpp:241 msgid "Regular cursor" -msgstr "ObyÄejný kurzor" +msgstr "Obyèejný kurzor" #. I18N: Comm is a communication device #: engines/scumm/help.cpp:244 @@ -3303,15 +3320,15 @@ msgstr "Komunikace" #: engines/scumm/help.cpp:247 msgid "Save / Load / Options" -msgstr "Uložit / Nahrát / Volby" +msgstr "Ulo¾it / Nahrát / Volby" #: engines/scumm/help.cpp:256 msgid "Other game controls:" -msgstr "DalÅ¡Ã ovládacà prvky hry" +msgstr "Dal¹í ovládací prvky hry" #: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268 msgid "Inventory:" -msgstr "Inventář:" +msgstr "Inventáø:" #: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275 msgid "Scroll list up" @@ -3323,63 +3340,63 @@ msgstr "Posunout seznam dolu" #: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269 msgid "Upper left item" -msgstr "Položka vlevo nahoÅ™e" +msgstr "Polo¾ka vlevo nahoøe" #: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271 msgid "Lower left item" -msgstr "Položka vlevo dole" +msgstr "Polo¾ka vlevo dole" #: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272 msgid "Upper right item" -msgstr "Položka vpravo nahoÅ™e" +msgstr "Polo¾ka vpravo nahoøe" #: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274 msgid "Lower right item" -msgstr "Položka vpravo dole" +msgstr "Polo¾ka vpravo dole" #: engines/scumm/help.cpp:270 msgid "Middle left item" -msgstr "Položka vlevo uprostÅ™ed" +msgstr "Polo¾ka vlevo uprostøed" #: engines/scumm/help.cpp:273 msgid "Middle right item" -msgstr "Položka vpravo uprostÅ™ed" +msgstr "Polo¾ka vpravo uprostøed" #: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285 msgid "Switching characters:" -msgstr "MÄ›nÄ›nà postav:" +msgstr "Mìnìní postav:" #: engines/scumm/help.cpp:282 msgid "Second kid" -msgstr "Druhé dÃtÄ›" +msgstr "Druhé dítì" #: engines/scumm/help.cpp:283 msgid "Third kid" -msgstr "TÅ™età dÃtÄ›" +msgstr "Tøetí dítì" #: engines/scumm/help.cpp:292 msgid "Toggle Inventory/IQ Points display" -msgstr "PÅ™epÃnat zobrazenà inventáře/chytrostnÃch bodů" +msgstr "Pøepínat zobrazení inventáøe/chytrostních bodù" #: engines/scumm/help.cpp:293 msgid "Toggle Keyboard/Mouse Fighting (*)" -msgstr "PÅ™epÃnat bojovánà pomocà kláves/myÅ¡i (*)" +msgstr "Pøepínat bojování pomocí kláves/my¹i (*)" #: engines/scumm/help.cpp:295 msgid "* Keyboard Fighting is always on," -msgstr "* Bojovánà pomocà klávesnice je vždy zapnuto," +msgstr "* Bojování pomocí klávesnice je v¾dy zapnuto," #: engines/scumm/help.cpp:296 msgid " so despite the in-game message this" -msgstr " takže nehledÄ› a to, co Å™Ãká hra," +msgstr " tak¾e nehledì a to, co øíká hra," #: engines/scumm/help.cpp:297 msgid " actually toggles Mouse Fighting Off/On" -msgstr " toto ve skuteÄnosti ovládá bojovánà s myÅ¡Ã" +msgstr " toto ve skuteènosti ovládá bojování s my¹í" #: engines/scumm/help.cpp:304 msgid "Fighting controls (numpad):" -msgstr "Ovládánà boje (num. kláv.)" +msgstr "Ovládání boje (num. kláv.)" #: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306 #: engines/scumm/help.cpp:307 @@ -3388,31 +3405,31 @@ msgstr "Ustoupit" #: engines/scumm/help.cpp:308 msgid "Block high" -msgstr "Bránit nahoÅ™e" +msgstr "Bránit nahoøe" #: engines/scumm/help.cpp:309 msgid "Block middle" -msgstr "Bránit uprostÅ™ed" +msgstr "Bránit uprostøed" #: engines/scumm/help.cpp:310 msgid "Block low" -msgstr "Bránit dole" +msgstr "Bránit dole" #: engines/scumm/help.cpp:311 msgid "Punch high" -msgstr "UdeÅ™it nahoru" +msgstr "Udeøit nahoru" #: engines/scumm/help.cpp:312 msgid "Punch middle" -msgstr "UdeÅ™it doprostÅ™ed" +msgstr "Udeøit doprostøed" #: engines/scumm/help.cpp:313 msgid "Punch low" -msgstr "UdeÅ™it dolů" +msgstr "Udeøit dolù" #: engines/scumm/help.cpp:315 msgid "Sucker punch" -msgstr "NeÄekaná rána" +msgstr "Neèekaná rána" #: engines/scumm/help.cpp:318 msgid "These are for Indy on left." @@ -3420,63 +3437,63 @@ msgstr "Tyto jsou pro Indyho nalevo." #: engines/scumm/help.cpp:319 msgid "When Indy is on the right," -msgstr "Když je Indy napravo," +msgstr "Kdy¾ je Indy napravo," #: engines/scumm/help.cpp:320 msgid "7, 4, and 1 are switched with" -msgstr "7, 4 a 1 jsou zamÄ›nÄ›ny s" +msgstr "7, 4 a 1 jsou zamìnìny s" #: engines/scumm/help.cpp:321 msgid "9, 6, and 3, respectively." -msgstr "9, 6 a 3, v tomto poÅ™adÃ." +msgstr "9, 6 a 3, v tomto poøadí." #: engines/scumm/help.cpp:328 msgid "Biplane controls (numpad):" -msgstr "Kontrola dvojploÅ¡nÃku (numerická klávesnice)" +msgstr "Kontrola dvojplo¹níku (numerická klávesnice)" #: engines/scumm/help.cpp:329 msgid "Fly to upper left" -msgstr "LetÄ›t doprava nahoru" +msgstr "Letìt doprava nahoru" #: engines/scumm/help.cpp:330 msgid "Fly to left" -msgstr "LetÄ›t doleva" +msgstr "Letìt doleva" #: engines/scumm/help.cpp:331 msgid "Fly to lower left" -msgstr "LetÄ›t doleva dolů" +msgstr "Letìt doleva dolù" #: engines/scumm/help.cpp:332 msgid "Fly upwards" -msgstr "LetÄ›t nahoru" +msgstr "Letìt nahoru" #: engines/scumm/help.cpp:333 msgid "Fly straight" -msgstr "LetÄ›t rovnÄ›" +msgstr "Letìt rovnì" #: engines/scumm/help.cpp:334 msgid "Fly down" -msgstr "LetÄ›t dolů" +msgstr "Letìt dolù" #: engines/scumm/help.cpp:335 msgid "Fly to upper right" -msgstr "LetÄ›t doprava nahoru" +msgstr "Letìt doprava nahoru" #: engines/scumm/help.cpp:336 msgid "Fly to right" -msgstr "LetÄ›t doprava" +msgstr "Letìt doprava" #: engines/scumm/help.cpp:337 msgid "Fly to lower right" -msgstr "LetÄ›t doprava dolů" +msgstr "Letìt doprava dolù" #: engines/scumm/input.cpp:580 msgid "Snap scroll on" -msgstr "PÅ™ichycenà pÅ™i posunovánà zapnuto" +msgstr "Pøichycení pøi posunování zapnuto" #: engines/scumm/input.cpp:582 msgid "Snap scroll off" -msgstr "PÅ™ichycenà pÅ™i posunovánà zapnuto" +msgstr "Pøichycení pøi posunování zapnuto" #: engines/scumm/input.cpp:595 msgid "Music volume: " @@ -3484,7 +3501,7 @@ msgstr "Hlasitost hudby:" #: engines/scumm/input.cpp:612 msgid "Subtitle speed: " -msgstr "Rychlost titulkù:" +msgstr "Rychlost titulkù:" #: engines/scumm/scumm.cpp:1832 #, c-format @@ -3492,8 +3509,8 @@ msgid "" "Native MIDI support requires the Roland Upgrade from LucasArts,\n" "but %s is missing. Using AdLib instead." msgstr "" -"PÅ™irozená podpora MIDI vyžaduje Aktualizaci Roland od LucasArts,\n" -"ale %s chybÃ. MÃsto toho je použit AdLib." +"Pøirozená podpora MIDI vy¾aduje Aktualizaci Roland od LucasArts,\n" +"ale %s chybí. Místo toho je pou¾it AdLib." #: engines/scumm/scumm.cpp:2644 msgid "" @@ -3501,54 +3518,108 @@ msgid "" "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 "" -"NormálnÄ› by teÄ byl spuÅ¡tÄ›n Maniac Mansion. Ale aby toto mohlo fungovat, " -"musà být soubory se hrou umÃstÄ›ny do složky 'Maniac' uvnitÅ™ složky se " -"hrou Tentacle a hra musà být pÅ™idána do ScummVM." +"Normálnì by teï byl spu¹tìn Maniac Mansion. Ale aby toto mohlo fungovat, " +"musí být soubory se hrou umístìny do slo¾ky 'Maniac' uvnitø slo¾ky se hrou " +"Tentacle a hra musí být pøidána do ScummVM." #: 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 "" -"Nelze najÃt spustitelný soubor 'Loom' pro Macintosh z jehož\n" -"majà být naÄteny hudebnà nástroje. Hudba bude zakázána." +"Nelze najít spustitelný soubor 'Loom' pro Macintosh z jeho¾\n" +"mají být naèteny hudební nástroje. Hudba bude zakázána." #: 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 "" -"Nelze najÃt spustitelný soubor 'Monkey Island' pro Macintosh z\n" -"jehož majà být naÄteny hudebnà nástroje. Hudba bude zakázána." +"Nelze najít spustitelný soubor 'Monkey Island' pro Macintosh z\n" +"jeho¾ mají být naèteny hudební nástroje. Hudba bude zakázána." + +#: engines/sherlock/detection.cpp:71 +#, fuzzy +msgid "Use original savegame dialog" +msgstr "Pou¾ít pùvodní obrazovky naètení/ulo¾ení" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" + +#: engines/sherlock/detection.cpp:101 +#, fuzzy +msgid "Show character portraits" +msgstr "Zamìnit znaky" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "" #: engines/sky/compact.cpp:130 msgid "" "Unable to find \"sky.cpt\" file!\n" "Please download it from www.scummvm.org" msgstr "" -"Nelze nalézt soubor \"sky.cpt\"!\n" -"StáhnÄ›te si ho, prosÃm z www.scummvm.org" +"Nelze nalézt soubor \"sky.cpt\"!\n" +"Stáhnìte si ho, prosím z www.scummvm.org" #: engines/sky/compact.cpp:141 msgid "" "The \"sky.cpt\" file has an incorrect size.\n" "Please (re)download it from www.scummvm.org" msgstr "" -"Soubor \"sky.cpt\" má nesprávnou velikost.\n" -"StáhnÄ›te si ho, prosÃm, (znovu) z www.scummvm.org" +"Soubor \"sky.cpt\" má nesprávnou velikost.\n" +"Stáhnìte si ho, prosím, (znovu) z www.scummvm.org" #: engines/sky/detection.cpp:44 msgid "Floppy intro" -msgstr "Úvod z diskety" +msgstr "Úvod z diskety" #: engines/sky/detection.cpp:45 msgid "Use the floppy version's intro (CD version only)" -msgstr "PoužÃt verzi úvodu z diskety (Pouze verze CD)" +msgstr "Pou¾ít verzi úvodu z diskety (Pouze verze CD)" #: engines/sword1/animation.cpp:524 #, c-format msgid "PSX stream cutscene '%s' cannot be played in paletted mode" -msgstr "Proud videa PSX '%s' nemůže být pÅ™ehrán v režimu palety" +msgstr "Proud videa PSX '%s' nemù¾e být pøehrán v re¾imu palety" #: engines/sword1/animation.cpp:545 engines/sword2/animation.cpp:445 msgid "DXA cutscenes found but ScummVM has been built without zlib" @@ -3574,13 +3645,13 @@ msgid "" "Press OK to convert them now, otherwise you will be asked again the next " "time you start the game.\n" msgstr "" -"ScummVM zjistil, že máte staré uložené pozice pro Broken Sword 1, " -"které by mÄ›ly být pÅ™evedeny.\n" -"Starý formát uložených her již nenà podporován, takže pokud je " -"nepÅ™evedete, nebudete moci vaÅ¡e hry naÄÃst.\n" +"ScummVM zjistil, ¾e máte staré ulo¾ené pozice pro Broken Sword 1, které by " +"mìly být pøevedeny.\n" +"Starý formát ulo¾ených her ji¾ není podporován, tak¾e pokud je nepøevedete, " +"nebudete moci va¹e hry naèíst.\n" "\n" -"StisknÄ›te OK, abyste je pÅ™evedli teÄ, jinak budete požádáni znovu, pÅ™i " -"spuÅ¡tÄ›nà této hry.\n" +"Stisknìte OK, abyste je pøevedli teï, jinak budete po¾ádáni znovu, pøi " +"spu¹tìní této hry.\n" #: engines/sword1/control.cpp:1232 #, c-format @@ -3588,8 +3659,8 @@ 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 "" -"Nová cÃlová uložená hra již existuje!\n" -"ChtÄ›li byste ponechat starou uloženou hru (%s), nebo novou (%s)?\n" +"Nová cílová ulo¾ená hra ji¾ existuje!\n" +"Chtìli byste ponechat starou ulo¾enou hru (%s), nebo novou (%s)?\n" #: engines/sword1/control.cpp:1235 msgid "Keep the old one" @@ -3610,45 +3681,44 @@ msgstr "Videa PSX nalezena, ale ScummVM byl sestaven bez podpory barev RGB" #: engines/sword2/sword2.cpp:79 msgid "Show object labels" -msgstr "Zobrazit jmenovky objektů" +msgstr "Zobrazit jmenovky objektù" #: engines/sword2/sword2.cpp:80 msgid "Show labels for objects on mouse hover" -msgstr "Zobrazit jmenovky objektů pÅ™i najetà myÅ¡i" +msgstr "Zobrazit jmenovky objektù pøi najetí my¹i" #: engines/teenagent/resources.cpp:95 msgid "" "You're missing the 'teenagent.dat' file. Get it from the ScummVM website" -msgstr "" -"Chybà vám soubor 'teenagent.dat'. Můžete ho zÃskat ze stránky ScummVM." +msgstr "Chybí vám soubor 'teenagent.dat'. Mù¾ete ho získat ze stránky ScummVM." #: 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 "" -"Soubor teenagent.dat je komprimován a zlib nenà souÄástà spustitelného " -"souboru. ProsÃm dekomprimujte ho" +"Soubor teenagent.dat je komprimován a zlib není souèástí spustitelného " +"souboru. Prosím dekomprimujte ho" #: engines/wintermute/detection.cpp:58 msgid "Show FPS-counter" -msgstr "Zobrazit poÄÃtadlo FPS" +msgstr "Zobrazit poèítadlo FPS" #: engines/wintermute/detection.cpp:59 msgid "Show the current number of frames per second in the upper left corner" -msgstr "Zobrazit souÄasný poÄet snÃmků za sekundu v hornÃm levém rohu" +msgstr "Zobrazit souèasný poèet snímkù za sekundu v horním levém rohu" #: engines/zvision/detection_tables.h:52 msgid "Use the original save/load screens instead of the ScummVM interface" -msgstr "PoužÃt původnà obrazovky naÄtenÃ/uloženà mÃsto rozhranà ScummVM" +msgstr "Pou¾ít pùvodní obrazovky naètení/ulo¾ení místo rozhraní ScummVM" #: engines/zvision/detection_tables.h:61 msgid "Double FPS" -msgstr "Dvojité snÃmky za sekundu" +msgstr "Dvojité snímky za sekundu" #: engines/zvision/detection_tables.h:62 msgid "Increase framerate from 30 to 60 FPS" -msgstr "Zvýšit snÃmkovou frekvenci z 30 na 60" +msgstr "Zvý¹it snímkovou frekvenci z 30 na 60" #: engines/zvision/detection_tables.h:71 msgid "Enable Venus" @@ -3656,118 +3726,117 @@ msgstr "Povolit Venus" #: engines/zvision/detection_tables.h:72 msgid "Enable the Venus help system" -msgstr "Povolit systém nápovÄ›dy Venus" +msgstr "Povolit systém nápovìdy Venus" #: engines/zvision/detection_tables.h:81 msgid "Disable animation while turning" -msgstr "Zakázat animaci pÅ™i otáÄenÃ" +msgstr "Zakázat animaci pøi otáèení" #: engines/zvision/detection_tables.h:82 msgid "Disable animation while turning in panorama mode" -msgstr "Zakázat animaci pÅ™i otáÄenà v panoramatickém režimu" +msgstr "Zakázat animaci pøi otáèení v panoramatickém re¾imu" #: engines/zvision/detection_tables.h:91 msgid "Use high resolution MPEG video" -msgstr "PoužÃt video MPEG ve vysokém rozliÅ¡enÃ" +msgstr "Pou¾ít video MPEG ve vysokém rozli¹ení" #: engines/zvision/detection_tables.h:92 msgid "Use MPEG video from the DVD version, instead of lower resolution AVI" msgstr "" -"PoužÃt video MPEG pocházejÃcà z DVD verze, namÃsto videa AVI v nÃzkém " -"rozliÅ¡enÃ." +"Pou¾ít video MPEG pocházející z DVD verze, namísto videa AVI v nízkém " +"rozli¹ení." #~ msgid "EGA undithering" -#~ msgstr "Nerozkládánà EGA" +#~ msgstr "Nerozkládání EGA" #~ msgid "Enable undithering in EGA games" -#~ msgstr "Povolit nerozkládánà v EGA hrách" +#~ msgstr "Povolit nerozkládání v EGA hrách" #~ msgid "Are you sure you want to restart? (Y/N)" -#~ msgstr "Jste si jisti, že chcete restartovat? (A/N)A" +#~ msgstr "Jste si jisti, ¾e chcete restartovat? (A/N)A" #~ msgid "Are you sure you want to quit? (Y/N)" -#~ msgstr "Jste si jisti, že chcete odejÃt? (A/N)A" +#~ msgstr "Jste si jisti, ¾e chcete odejít? (A/N)A" #~ msgid "" #~ "Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. " #~ "To play it, go to 'Add Game' in the ScummVM start menu and select the " #~ "'Maniac' directory inside the Tentacle game directory." #~ msgstr "" -#~ "NormálnÄ› by teÄ Maniac Mansion byl spuÅ¡tÄ›n. Ale ScummVM toto zatÃm " -#~ "nedÄ›lá. Abyste toto mohli hrát, pÅ™ejdÄ›te do 'PÅ™idat Hru' v poÄáteÄnÃm " -#~ "menu ScummVM a vyberte adresář 'Maniac' uvnitÅ™ hernÃho adresáře " -#~ "Tentacle." +#~ "Normálnì by teï Maniac Mansion byl spu¹tìn. Ale ScummVM toto zatím " +#~ "nedìlá. Abyste toto mohli hrát, pøejdìte do 'Pøidat Hru' v poèáteèním " +#~ "menu ScummVM a vyberte adresáø 'Maniac' uvnitø herního adresáøe Tentacle." #~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2" #~ msgstr "Videa MPEG-2 nalezena, ale ScummVM byl sestaven bez MPEG-2" #~ msgctxt "lowres" #~ msgid "Mass Add..." -#~ msgstr "Hromadné PÅ™idánÃ..." +#~ msgstr "Hromadné Pøidání..." #~ msgid "" #~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack" #~ msgstr "" -#~ "Vypne mapovánà General MIDI pro hry s Roland MT-32 zvukovým doprovodem" +#~ "Vypne mapování General MIDI pro hry s Roland MT-32 zvukovým doprovodem" #~ msgid "Standard (16bpp)" -#~ msgstr "Standardnà (16bpp)" +#~ msgstr "Standardní (16bpp)" #~ msgid "MPEG2 cutscenes are no longer supported" -#~ msgstr "Videa MPGE2 již nejsou podporována" +#~ msgstr "Videa MPGE2 ji¾ nejsou podporována" #~ msgid "OpenGL Normal" -#~ msgstr "OpenGL NormálnÃ" +#~ msgstr "OpenGL Normální" #~ msgid "OpenGL Conserve" -#~ msgstr "OpenGL ZachovávajÃcÃ" +#~ msgstr "OpenGL Zachovávající" #~ msgid "OpenGL Original" -#~ msgstr "OpenGL PůvodnÃ" +#~ msgstr "OpenGL Pùvodní" #~ msgid "Current display mode" -#~ msgstr "SouÄasný režim obrazu" +#~ msgstr "Souèasný re¾im obrazu" #~ msgid "Current scale" -#~ msgstr "SouÄasná velikost" +#~ msgstr "Souèasná velikost" #~ msgid "Active filter mode: Linear" -#~ msgstr "Aktivnà režim filtru: LineárnÃ" +#~ msgstr "Aktivní re¾im filtru: Lineární" #~ msgid "Active filter mode: Nearest" -#~ msgstr "Aktivnà režim filtru: NejbližšÃ" +#~ msgstr "Aktivní re¾im filtru: Nejbli¾¹í" #~ msgid "Enable Roland GS Mode" -#~ msgstr "Zapnout režim Roland GS" - -#~ msgid "Save game failed!" -#~ msgstr "Ukládánà hry selhalo!" +#~ msgstr "Zapnout re¾im Roland GS" #~ msgctxt "lowres" #~ msgid "Add Game..." -#~ msgstr "PÅ™idat Hru..." +#~ msgstr "Pøidat Hru..." #~ msgid "Add Game..." -#~ msgstr "PÅ™idat Hru..." +#~ msgstr "Pøidat Hru..." #~ msgid "" #~ "Your game version has been detected using filename matching as a variant " #~ "of %s." #~ msgstr "" -#~ "Bylo zjiÅ¡tÄ›no, že VaÅ¡e verze hry použÃvá jméno souboru shodujÃcà se " -#~ "s variantou %s." +#~ "Bylo zji¹tìno, ¾e Va¹e verze hry pou¾ívá jméno souboru shodující se s " +#~ "variantou %s." #~ msgid "If this is an original and unmodified version, please report any" -#~ msgstr "Pokud je toto původnà a nezmÄ›nÄ›ná verze, ohlaste prosÃm jakékoli" +#~ msgstr "Pokud je toto pùvodní a nezmìnìná verze, ohlaste prosím jakékoli" #~ msgid "information previously printed by ScummVM to the team." -#~ msgstr "pÅ™edeÅ¡le vypsané informace od ScummVM zpátky týmu." +#~ msgstr "pøede¹le vypsané informace od ScummVM zpátky týmu." #~ msgid "Discovered %d new games." -#~ msgstr "Objeveno %d nových her." +#~ msgstr "Objeveno %d nových her." #~ msgid "Command line argument not processed" -#~ msgstr "Argument pÅ™Ãkazové řádky nebyl zpracován" +#~ msgstr "Argument pøíkazové øádky nebyl zpracován" + +#~ msgid "FM Towns Emulator" +#~ msgstr "FM Towns Emulátor" #~ msgid "Invalid Path" -#~ msgstr "Neplatná Cesta" +#~ msgstr "Neplatná Cesta" diff --git a/po/da_DA.po b/po/da_DK.po index 9684b82833..934297bd80 100644 --- a/po/da_DA.po +++ b/po/da_DK.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.3.0svn\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" -"PO-Revision-Date: 2014-07-09 17:34+0100\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" +"PO-Revision-Date: 2016-02-25 21:08+0100\n" "Last-Translator: Steffen Nyeland <steffen@nyeland.dk>\n" "Language-Team: Steffen Nyeland <steffen@nyeland.dk>\n" "Language: Dansk\n" @@ -74,7 +74,7 @@ msgstr "Vælg" #: gui/editrecorddialog.cpp:58 msgid "Author:" -msgstr "" +msgstr "Forfatter:" #: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204 msgid "Name:" @@ -82,24 +82,23 @@ msgstr "Navn:" #: gui/editrecorddialog.cpp:60 msgid "Notes:" -msgstr "" +msgstr "Noter:" #: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74 msgid "Ok" -msgstr "" +msgstr "OK" #: gui/filebrowser-dialog.cpp:49 msgid "Choose file for loading" -msgstr "" +msgstr "Vælg fil til indlæsning" #: gui/filebrowser-dialog.cpp:49 msgid "Enter filename for saving" -msgstr "" +msgstr "Indtast filnavn til at gemme" #: gui/filebrowser-dialog.cpp:132 -#, fuzzy msgid "Do you really want to overwrite the file?" -msgstr "Vil du virkelig slette denne gemmer?" +msgstr "Vil du virkelig overskrive filen?" #: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217 #: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002 @@ -592,16 +591,16 @@ msgid "Search:" msgstr "Søg:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Indlæs spil:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Indlæs" @@ -649,7 +648,7 @@ msgstr "Tilføj flere..." #: gui/launcher.cpp:1163 msgid "Record..." -msgstr "" +msgstr "Optag..." #: gui/massadd.cpp:79 gui/massadd.cpp:82 msgid "... progress ..." @@ -676,21 +675,19 @@ msgstr "Fundet %d nye spil, ignorer %d tidligere tilføjede spil ..." #: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103 msgid "Stop" -msgstr "" +msgstr "Stop" #: gui/onscreendialog.cpp:106 msgid "Edit record description" -msgstr "" +msgstr "Ret optag beskrivelse" #: gui/onscreendialog.cpp:108 -#, fuzzy msgid "Switch to Game" -msgstr "Skift" +msgstr "Skift til Spil" #: gui/onscreendialog.cpp:110 -#, fuzzy msgid "Fast replay" -msgstr "Hurtig tilstand" +msgstr "Hurtig afspil" #: gui/options.cpp:85 msgid "Never" @@ -767,7 +764,7 @@ msgid "Special dithering modes supported by some games" msgstr "Speciel farvereduceringstilstand understøttet a nogle spil" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Fuldskærms tilstand" @@ -1080,39 +1077,38 @@ msgstr "" #. I18N: You must leave "#" as is, only word 'next' is translatable #: gui/predictivedialog.cpp:86 msgid "# next" -msgstr "" +msgstr "# næste" #: gui/predictivedialog.cpp:87 msgid "add" -msgstr "" +msgstr "tilføj" #: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164 -#, fuzzy msgid "Delete char" -msgstr "Slet" +msgstr "Slet tegn" #: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168 msgid "<" -msgstr "" +msgstr "<" #. I18N: Pre means 'Predictive', leave '*' as is #: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572 msgid "* Pre" -msgstr "" +msgstr "* Præ" #. I18N: 'Num' means Numbers #: gui/predictivedialog.cpp:575 msgid "* Num" -msgstr "" +msgstr "* Num" #. I18N: 'Abc' means Latin alphabet input #: gui/predictivedialog.cpp:578 msgid "* Abc" -msgstr "" +msgstr "* Abc" #: gui/recorderdialog.cpp:64 msgid "Recorder or Playback Gameplay" -msgstr "" +msgstr "Optag eller Afspil Gameplay" #: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156 #: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276 @@ -1121,36 +1117,33 @@ msgstr "Slet" #: gui/recorderdialog.cpp:71 msgid "Record" -msgstr "" +msgstr "Optag" #: gui/recorderdialog.cpp:72 -#, fuzzy msgid "Playback" -msgstr "Spil" +msgstr "Afspil" #: gui/recorderdialog.cpp:74 msgid "Edit" -msgstr "" +msgstr "Ret" #: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243 #: gui/recorderdialog.cpp:253 msgid "Author: " -msgstr "" +msgstr "Forfatter: " #: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244 #: gui/recorderdialog.cpp:254 msgid "Notes: " -msgstr "" +msgstr "Noter: " #: gui/recorderdialog.cpp:155 -#, fuzzy msgid "Do you really want to delete this record?" -msgstr "Vil du virkelig slette denne gemmer?" +msgstr "Vil du virkelig slette denne optagelse?" #: gui/recorderdialog.cpp:174 -#, fuzzy msgid "Unknown Author" -msgstr "Ukendt fejl" +msgstr "Ukendt forfatter" #: gui/saveload-dialog.cpp:167 msgid "List view" @@ -1357,18 +1350,18 @@ msgstr "Hercules brun" #: common/rendermode.cpp:42 msgid "PC-9821 (256 Colors)" -msgstr "" +msgstr "PC-9821 (256 Farver)" #: common/rendermode.cpp:43 msgid "PC-9801 (16 Colors)" -msgstr "" +msgstr "PC-9801 (16 Farver)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Hercules grøn" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Hercules brun" @@ -1420,11 +1413,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "~R~etur til oversigt" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Gemmer:" @@ -1433,11 +1430,15 @@ msgstr "Gemmer:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Gem" @@ -1556,7 +1557,7 @@ msgstr "DOSBox OPL emulator" #: audio/fmopl.cpp:67 msgid "ALSA Direct FM" -msgstr "" +msgstr "ALSA Direct FM" #: audio/mididrv.cpp:209 #, c-format @@ -1612,17 +1613,15 @@ msgstr "Apple II GS emulator (IKKE IMPLEMENTERET)" #: audio/softsynth/cms.cpp:350 msgid "Creative Music System Emulator" -msgstr "" +msgstr "Creative Music System Emulator" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33 -#, fuzzy msgid "FM-Towns Audio" -msgstr "FM Towns emulator" +msgstr "FM Towns lyd" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58 -#, fuzzy msgid "PC-98 Audio" -msgstr "Lyd" +msgstr "PC-98 lyd" #: audio/softsynth/mt32.cpp:200 msgid "Initializing MT-32 Emulator" @@ -1717,34 +1716,33 @@ msgstr "Vil du afslutte?" #. I18N: Trackpad mode toggle status. #: backends/events/webossdl/webossdl-events.cpp:308 -#, fuzzy msgid "Trackpad mode is now" -msgstr "Pegeplade tilstand deaktiveret." +msgstr "Pegeplade-tilstand er nu" #. 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 "" +msgstr "TIL" #: backends/events/webossdl/webossdl-events.cpp:311 #: backends/events/webossdl/webossdl-events.cpp:338 msgid "OFF" -msgstr "" +msgstr "FRA" #: backends/events/webossdl/webossdl-events.cpp:315 msgid "Swipe two fingers to the right to toggle." -msgstr "" +msgstr "Før to fingre til højre for at skifte." #. I18N: Auto-drag toggle status. #: backends/events/webossdl/webossdl-events.cpp:335 msgid "Auto-drag mode is now" -msgstr "" +msgstr "Auto-træk tilstand er nu" #: backends/events/webossdl/webossdl-events.cpp:342 msgid "Swipe three fingers to the right to toggle." -msgstr "" +msgstr "Før tre fingre til højre for at skifte." #: backends/graphics/opengl/opengl-graphics.cpp:119 msgid "OpenGL" @@ -1765,19 +1763,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Normal (ingen skalering)" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "Aktivér billedformat korrektion" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "Deaktivér billedformat korrektion" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Aktive grafik filtre:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Vindue tilstand" @@ -2039,24 +2037,23 @@ msgstr "Kontrollér mus" #: backends/platform/tizen/fs.cpp:259 msgid "[ Data ]" -msgstr "" +msgstr "[ Data ]" #: backends/platform/tizen/fs.cpp:263 msgid "[ Resources ]" -msgstr "" +msgstr "[ Ressourcer ]" #: backends/platform/tizen/fs.cpp:267 msgid "[ SDCard ]" -msgstr "" +msgstr "[ SDKort ]" #: backends/platform/tizen/fs.cpp:271 msgid "[ Media ]" -msgstr "" +msgstr "[ Medie ]" #: backends/platform/tizen/fs.cpp:275 -#, fuzzy msgid "[ Shared ]" -msgstr "Mappe:" +msgstr "[ Delt ]" #: backends/platform/wii/options.cpp:51 msgid "Video" @@ -2323,35 +2320,45 @@ msgid "Use the original save/load screens, instead of the ScummVM ones" msgstr "Brug de originale gem/indlæs skærme, istedet for dem fra ScummVM" #: engines/agi/detection.cpp:157 -#, fuzzy msgid "Use an alternative palette" -msgstr "Brug en alternativ spil intro (kun CD version)" +msgstr "Brug en alternativ palette" #: engines/agi/detection.cpp:158 msgid "" "Use an alternative palette, common for all Amiga games. This was the old " "behavior" msgstr "" +"Brug en alternativ palet, fælles for alle Amiga spil. Dette var den gamle " +"adfærd" #: engines/agi/detection.cpp:167 -#, fuzzy msgid "Mouse support" -msgstr "Spring over støtte" +msgstr "Understøt mus" #: engines/agi/detection.cpp:168 msgid "" "Enables mouse support. Allows to use mouse for movement and in game menus." msgstr "" +"Aktivér muse support. Gør det muligt at bruge musen til bevægelse og i spil " +"menuer." -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Gendan spil:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Gendan" @@ -2394,13 +2401,12 @@ msgid "Cutscene file '%s' not found!" msgstr "Filmsekvens fil '%s' ikke fundet!" #: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101 -#, fuzzy msgid "Color Blind Mode" -msgstr "Klik tilstand" +msgstr "Farveblind-tilstand" #: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102 msgid "Enable Color Blind Mode by default" -msgstr "" +msgstr "Aktivér Farveblind tilstand som standard" #: engines/drascula/saveload.cpp:47 msgid "" @@ -2456,11 +2462,11 @@ msgstr "Mislykkedes at gemme spil" #: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86 msgid "Gore Mode" -msgstr "" +msgstr "Splatter-tilstand" #: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87 msgid "Enable Gore Mode when available" -msgstr "" +msgstr "Aktiver Splatter-tilstand når mulig" #. I18N: Studio audience adds an applause and cheering sounds whenever #. Malcolm makes a joke. @@ -2592,6 +2598,12 @@ msgid "" "Do you wish to use this save game file with ScummVM?\n" "\n" msgstr "" +"Følgende originale savegame fil er blevet fundet i din spil sti:\n" +"\n" +"%s %s\n" +"\n" +"Ønsker du at bruge denne savegame fil med ScummVM?\n" +"\n" #: engines/kyra/saveload_eob.cpp:590 #, c-format @@ -2599,6 +2611,8 @@ msgid "" "A save game file was found in the specified slot %d. Overwrite?\n" "\n" msgstr "" +"En savegame fil blev fundet på den angivne plads %d. Overskriv?\n" +"\n" #: engines/kyra/saveload_eob.cpp:623 #, c-format @@ -2610,6 +2624,12 @@ msgid "" "'import_savefile'.\n" "\n" msgstr "" +"%d originale savegame filer, er med succes er blevet importeret i\n" +"ScummVM. Hvis du manuelt vil importere original savegame filer senere, vil " +"du være\n" +"nødt til at åbne ScummVM debug konsol og bruge kommandoen " +"'import_savefile'.\n" +"\n" #. I18N: Option for fast scene switching #: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167 @@ -2664,10 +2684,18 @@ msgstr "" "Kan ikke gemme spil på plads %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +msgid "Load file" +msgstr "Indlæs fil" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Indlæser spil..." +#: engines/parallaction/saveload.cpp:212 +msgid "Save file" +msgstr "Gem fil" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Gemmer spil..." @@ -2750,21 +2778,21 @@ msgstr "Brug en alternativ spil intro (kun CD version)" #: engines/sci/detection.cpp:374 msgid "Skip EGA dithering pass (full color backgrounds)" -msgstr "" +msgstr "Skip EGA farvereducering (fuldfarvet baggrunde)" #: engines/sci/detection.cpp:375 msgid "Skip dithering pass in EGA games, graphics are shown with full colors" msgstr "" +"Spring farvereducering i EGA spil over, grafikken bliver vist med fulde " +"farver" #: engines/sci/detection.cpp:384 -#, fuzzy msgid "Enable high resolution graphics" -msgstr "Aktivér træfpoint (HP) søjlediagrammer" +msgstr "Aktivér grafik i høj opløsning" #: engines/sci/detection.cpp:385 -#, fuzzy msgid "Enable high resolution graphics/content" -msgstr "Aktivér træfpoint (HP) søjlediagrammer" +msgstr "Aktivér høj opløsnings grafik/indhold" #: engines/sci/detection.cpp:394 msgid "Prefer digital sound effects" @@ -2836,15 +2864,13 @@ msgstr "Spil sat på pause. Tryk MELLEMRUM for at fortsætte." #. "Moechten Sie wirklich neu starten? (J/N)J" #. Will react to J as 'Yes' #: engines/scumm/dialogs.cpp:183 -#, fuzzy msgid "Are you sure you want to restart? (Y/N)Y" -msgstr "Er du sikker på at du vil genstarte? (J/N) " +msgstr "Er du sikker på at du vil genstarte? (J/N)J" #. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment #: engines/scumm/dialogs.cpp:185 -#, fuzzy msgid "Are you sure you want to quit? (Y/N)Y" -msgstr "Er du sikker på at du vil afslutte? (J/N) " +msgstr "Er du sikker på at du vil afslutte? (J/N)J" #: engines/scumm/dialogs.cpp:190 msgid "Play" @@ -3352,25 +3378,24 @@ msgid "Third kid" msgstr "Tredie barn" #: engines/scumm/help.cpp:292 -#, fuzzy msgid "Toggle Inventory/IQ Points display" -msgstr "Skift Center Data Display" +msgstr "Skift Inventory/IQ Points display " #: engines/scumm/help.cpp:293 msgid "Toggle Keyboard/Mouse Fighting (*)" -msgstr "" +msgstr "Skift Tastatur/Muse Kamp (*)" #: engines/scumm/help.cpp:295 msgid "* Keyboard Fighting is always on," -msgstr "" +msgstr "* Tastatur Kamp er altid slået til," #: engines/scumm/help.cpp:296 msgid " so despite the in-game message this" -msgstr "" +msgstr " så på trods af in-game beskeden, denne" #: engines/scumm/help.cpp:297 msgid " actually toggles Mouse Fighting Off/On" -msgstr "" +msgstr " skifter faktisk Muse Kamp Fra/Til" #: engines/scumm/help.cpp:304 msgid "Fighting controls (numpad):" @@ -3407,7 +3432,7 @@ msgstr "Slå lavt" #: engines/scumm/help.cpp:315 msgid "Sucker punch" -msgstr "" +msgstr "Mavepuster" #: engines/scumm/help.cpp:318 msgid "These are for Indy on left." @@ -3466,23 +3491,20 @@ msgid "Fly to lower right" msgstr "Flyv nederst til højre" #: engines/scumm/input.cpp:580 -#, fuzzy msgid "Snap scroll on" -msgstr "Jævn bevægelse" +msgstr "Jævn bevægelse til" #: engines/scumm/input.cpp:582 msgid "Snap scroll off" -msgstr "" +msgstr "Jævn bevægelse fra" #: engines/scumm/input.cpp:595 -#, fuzzy msgid "Music volume: " -msgstr "Musik lydstyrke:" +msgstr "Musik lydstyrke: " #: engines/scumm/input.cpp:612 -#, fuzzy msgid "Subtitle speed: " -msgstr "Tekst hastighed:" +msgstr "Tekst hastighed: " #: engines/scumm/scumm.cpp:1832 #, c-format @@ -3494,27 +3516,86 @@ msgstr "" "men %s mangler. Bruger AdLib i stedet." #: engines/scumm/scumm.cpp:2644 -#, fuzzy 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 "" -"Normalt ville Maniac Mansion begynde nu. Men ScummVM kan ikke gøre det " -"endnu. For at spille det, gå til 'Tilføj spil' i ScummVM start-menuen og " -"vælg 'Maniac' mappen inde i Tentacle spillets mappe." +"Normalt ville Maniac Mansion starte nu. Men for at det skal fungere, skal " +"spil filerne til Maniac Mansion skal være i \"Maniac\" mappen inde i " +"Tentacle spil biblioteket, og spillet skal tilføjes til ScummVM." #: 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 "" +"Kunne ikke finde den 'Loom' Macintosh eksekverbare fil, til\n" +"at læse instrumenterne fra. Musik bliver deaktiveret." #: 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 "" +"Kunne ikke finde den 'Monkey Island' Macintosh eksekverbare fil, til\n" +"at læse instrumenterne fra. Musik bliver deaktiveret." + +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "Brug original gem/indlæs dialog" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" +"Knappen Files i spillet viser original gem/indlæs dialog snarere end ScummVM " +"menuen" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "Pixelleret scene overgange" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "Ved sceneskift, bruges en tilfældig pixelleret overgang" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "Vis ikke hotspots, når du flytter musen" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" +"Vis kun hotspot navne efter du rent faktisk klikker på et hotspot eller en " +"handlingsknap" + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "Vis person portrætter" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "Vis portrætter for personer når de taler" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "Skub dialoger til syne" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "Skub dialoger til syne, i stedet for blot at vise dem straks" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "Gennemsigtige vinduer" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "Vis vinduer med delvis gennemsigtig baggrund" #: engines/sky/compact.cpp:130 msgid "" @@ -3629,52 +3710,49 @@ msgstr "" #: engines/wintermute/detection.cpp:58 msgid "Show FPS-counter" -msgstr "" +msgstr "Vis FPS-tæller" #: engines/wintermute/detection.cpp:59 msgid "Show the current number of frames per second in the upper left corner" -msgstr "" +msgstr "Vis det nuværende antal billeder per sekund i øverste venstre hjørne" #: engines/zvision/detection_tables.h:52 -#, fuzzy msgid "Use the original save/load screens instead of the ScummVM interface" -msgstr "Brug de originale gem/indlæs skærme, istedet for dem fra ScummVM" +msgstr "" +"Brug de originale gem/indlæs skærme, i stedet for dem fra ScummVM " +"brugerfladen" #: engines/zvision/detection_tables.h:61 msgid "Double FPS" -msgstr "" +msgstr "Dobbelt FPS" #: engines/zvision/detection_tables.h:62 msgid "Increase framerate from 30 to 60 FPS" -msgstr "" +msgstr "Øger billedhastighed fra 30 til 60 FPS" #: engines/zvision/detection_tables.h:71 -#, fuzzy msgid "Enable Venus" -msgstr "Aktivér helium tilstand" +msgstr "Aktivér Venus" #: engines/zvision/detection_tables.h:72 -#, fuzzy msgid "Enable the Venus help system" -msgstr "Aktivér helium tilstand" +msgstr "Aktivér Venus hjælpe systemmet" #: engines/zvision/detection_tables.h:81 msgid "Disable animation while turning" -msgstr "" +msgstr "Deaktiver animation, mens du drejer" #: engines/zvision/detection_tables.h:82 msgid "Disable animation while turning in panorama mode" -msgstr "" +msgstr "Deaktiver animation mens du drejer i panorama-tilstand" #: engines/zvision/detection_tables.h:91 msgid "Use high resolution MPEG video" -msgstr "" +msgstr "Brug høj opløsning MPEG-video" #: engines/zvision/detection_tables.h:92 -#, fuzzy msgid "Use MPEG video from the DVD version, instead of lower resolution AVI" -msgstr "" -"Brug det alternative sæt af sølv markører, i stedet for de normale gyldne" +msgstr "Brug MPEG-video fra DVD-versionen, i stedet for lavere opløsning AVI" #~ msgid "EGA undithering" #~ msgstr "EGA farveforøgelse" @@ -3723,10 +3801,6 @@ msgstr "" #~ msgid "Enable Roland GS Mode" #~ msgstr "Aktivér Roland GS tilstand" -#, fuzzy -#~ msgid "Save game failed!" -#~ msgstr "Gemmer:" - #~ msgctxt "lowres" #~ msgid "Add Game..." #~ msgstr "Tilføj spil..." diff --git a/po/de_DE.po b/po/de_DE.po index 06c04917b6..dbfeba57d5 100644 --- a/po/de_DE.po +++ b/po/de_DE.po @@ -1,15 +1,15 @@ # German translation for ScummVM. # Copyright (C) 2010-2016 The ScummVM Team # This file is distributed under the same license as the ScummVM package. -# Simon Sawatzki <SimSaw@gmx.de>, Lothar Serra Mari <scummvm@rootfather.de>, 2015. +# Simon Sawatzki <SimSaw@gmx.de>, Lothar Serra Mari <scummvm@rootfather.de>, 2016. # msgid "" msgstr "" "Project-Id-Version: ScummVM 1.8.0git\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" -"PO-Revision-Date: 2016-01-28 19:00+0100\n" -"Last-Translator: Lothar Serra Mari <scummvm@rootfather.de>\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" +"PO-Revision-Date: 2016-02-22 20:53+0100\n" +"Last-Translator: Simon Sawatzki <SimSaw@gmx.de>\n" "Language-Team: Simon Sawatzki <SimSaw@gmx.de>, Lothar Serra Mari " "<scummvm@rootfather.de>\n" "Language: Deutsch\n" @@ -595,16 +595,16 @@ msgid "Search:" msgstr "Suchen:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Spiel laden:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Laden" @@ -770,7 +770,7 @@ msgstr "" "Spezielle Farbmischungsmethoden werden von manchen Spielen unterstützt." #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Vollbildmodus" @@ -1373,12 +1373,12 @@ msgstr "PC-9821 (256 Farben)" msgid "PC-9801 (16 Colors)" msgstr "PC-9801 (16 Farben)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Hercules Grün" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Hercules Bernst." @@ -1433,11 +1433,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "Zur Spiele~l~iste" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Speichern:" @@ -1446,11 +1450,15 @@ msgstr "Speichern:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Speichern" @@ -1778,19 +1786,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Normal ohn.Skalieren" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "Seitenverhältniskorrektur an" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "Seitenverhältniskorrektur aus" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Aktiver Grafikfilter:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Fenstermodus" @@ -2359,15 +2367,23 @@ msgstr "" "Aktiviere Maus-Unterstützung. Erlaubt die Verwendung der Maus zur Bewegung " "und in Menüs innerhalb des Spiels." -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Spiel laden:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Laden" @@ -2698,10 +2714,18 @@ msgstr "" "Kann Spiel nicht speichern auf Speicherplatz %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +msgid "Load file" +msgstr "Datei laden" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Spiel wird geladen..." +#: engines/parallaction/saveload.cpp:212 +msgid "Save file" +msgstr "Datei speichern" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Spiel wird gespeichert..." @@ -3553,6 +3577,58 @@ msgstr "" "Macintosh-Programmdatei für Instrumente in \"Monkey Island\" nicht\n" "gefunden. Musik wird abgeschaltet." +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "Originale Spielstand-Menüs verwenden" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "Dateien-Schaltfläche im Spiel zeigt originales Spielstand-Menü statt dem von ScummVM." + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "Verpixelte Szenenübergänge" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "Bei Szenenwechseln wird ein zufälliger Pixelübergang verwendet." + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "Bei Mausbewegung keine Klickpunkte anzeigen" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "Zeigt Klickpunktnamen nur nach Klick auf selbigen oder auf einen Aktionspunkt." + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "Figurenportraits zeigen" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "Zeigt Portraits der Figuren bei Gesprächen." + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "Menüs in Blickfeld gleiten lassen" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "Lässt Menüs in Blickfeld gleiten anstatt sie einfach sofort anzuzeigen." + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "Transparente Fenster" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "Zeigt Fenster mit teilweise transparentem Hintergrund" + #: engines/sky/compact.cpp:130 msgid "" "Unable to find \"sky.cpt\" file!\n" @@ -3771,9 +3847,6 @@ msgstr "" #~ msgid "Enable Roland GS Mode" #~ msgstr "Roland-GS-Modus" -#~ msgid "Save game failed!" -#~ msgstr "Konnte Spielstand nicht speichern!" - #~ msgid "" #~ "Your game version has been detected using filename matching as a variant " #~ "of %s." diff --git a/po/es_ES.po b/po/es_ES.po index 8af41273d2..1593d4f815 100644 --- a/po/es_ES.po +++ b/po/es_ES.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.4.0svn\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" -"PO-Revision-Date: 2014-07-06 20:39+0100\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" +"PO-Revision-Date: 2016-02-24 18:01+0100\n" "Last-Translator: \n" "Language-Team: \n" "Language: Espanol\n" @@ -73,7 +73,7 @@ msgstr "Aceptar" #: gui/editrecorddialog.cpp:58 msgid "Author:" -msgstr "" +msgstr "Autor:" #: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204 msgid "Name:" @@ -81,24 +81,23 @@ msgstr "Nombre:" #: gui/editrecorddialog.cpp:60 msgid "Notes:" -msgstr "" +msgstr "Notas:" #: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74 msgid "Ok" -msgstr "" +msgstr "Aceptar" #: gui/filebrowser-dialog.cpp:49 msgid "Choose file for loading" -msgstr "" +msgstr "Elegir el archivo para cargar" #: gui/filebrowser-dialog.cpp:49 msgid "Enter filename for saving" -msgstr "" +msgstr "Escribir el nombre del archivo" #: gui/filebrowser-dialog.cpp:132 -#, fuzzy msgid "Do you really want to overwrite the file?" -msgstr "¿Seguro que quieres borrar esta partida?" +msgstr "¿Seguro que quieres sobrescribir esta partida?" #: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217 #: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002 @@ -591,16 +590,16 @@ msgid "Search:" msgstr "Buscar:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Cargar juego:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Cargar" @@ -648,7 +647,7 @@ msgstr "Añadir varios..." #: gui/launcher.cpp:1163 msgid "Record..." -msgstr "" +msgstr "Grabar..." #: gui/massadd.cpp:79 gui/massadd.cpp:82 msgid "... progress ..." @@ -675,21 +674,19 @@ msgstr "%d juegos nuevos encontrados. %d juegos ignorados (ya añadidos)..." #: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103 msgid "Stop" -msgstr "" +msgstr "Detener" #: gui/onscreendialog.cpp:106 msgid "Edit record description" -msgstr "" +msgstr "Editar la descripción de la grabación" #: gui/onscreendialog.cpp:108 -#, fuzzy msgid "Switch to Game" -msgstr "Cambiar" +msgstr "Volver al juego" #: gui/onscreendialog.cpp:110 -#, fuzzy msgid "Fast replay" -msgstr "Modo rápido" +msgstr "Repetición rápida" #: gui/options.cpp:85 msgid "Never" @@ -763,10 +760,10 @@ msgstr "Renderizado:" #: gui/options.cpp:746 gui/options.cpp:747 msgid "Special dithering modes supported by some games" -msgstr "Modos especiales de expansión compatibles con algunos juegos" +msgstr "Modos especiales de difuminado compatibles con algunos juegos" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Pantalla completa" @@ -1087,39 +1084,38 @@ msgstr "" #. I18N: You must leave "#" as is, only word 'next' is translatable #: gui/predictivedialog.cpp:86 msgid "# next" -msgstr "" +msgstr "# siguiente" #: gui/predictivedialog.cpp:87 msgid "add" -msgstr "" +msgstr "añadir" #: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164 -#, fuzzy msgid "Delete char" -msgstr "Borrar" +msgstr "Borrar personaje" #: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168 msgid "<" -msgstr "" +msgstr "<" #. I18N: Pre means 'Predictive', leave '*' as is #: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572 msgid "* Pre" -msgstr "" +msgstr "* Pre" #. I18N: 'Num' means Numbers #: gui/predictivedialog.cpp:575 msgid "* Num" -msgstr "" +msgstr "* Num" #. I18N: 'Abc' means Latin alphabet input #: gui/predictivedialog.cpp:578 msgid "* Abc" -msgstr "" +msgstr "* Abc" #: gui/recorderdialog.cpp:64 msgid "Recorder or Playback Gameplay" -msgstr "" +msgstr "Grabar o reproducir vídeos" #: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156 #: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276 @@ -1128,36 +1124,33 @@ msgstr "Borrar" #: gui/recorderdialog.cpp:71 msgid "Record" -msgstr "" +msgstr "Grabar" #: gui/recorderdialog.cpp:72 -#, fuzzy msgid "Playback" -msgstr "Jugar" +msgstr "Reproducción" #: gui/recorderdialog.cpp:74 msgid "Edit" -msgstr "" +msgstr "Editar" #: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243 #: gui/recorderdialog.cpp:253 msgid "Author: " -msgstr "" +msgstr "Autor:" #: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244 #: gui/recorderdialog.cpp:254 msgid "Notes: " -msgstr "" +msgstr "Notas:" #: gui/recorderdialog.cpp:155 -#, fuzzy msgid "Do you really want to delete this record?" -msgstr "¿Seguro que quieres borrar esta partida?" +msgstr "¿Seguro que quieres borrar esta grabación?" #: gui/recorderdialog.cpp:174 -#, fuzzy msgid "Unknown Author" -msgstr "Error desconocido" +msgstr "Autor desconocido" #: gui/saveload-dialog.cpp:167 msgid "List view" @@ -1364,18 +1357,18 @@ msgstr "Hercules ámbar" #: common/rendermode.cpp:42 msgid "PC-9821 (256 Colors)" -msgstr "" +msgstr "PC-9821 (256 colores)" #: common/rendermode.cpp:43 msgid "PC-9801 (16 Colors)" -msgstr "" +msgstr "PC-9801 (16 colores)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Hercules verde" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Hercules ámbar" @@ -1426,11 +1419,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "~V~olver al lanzador" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Guardar partida" @@ -1439,11 +1436,15 @@ msgstr "Guardar partida" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Guardar" @@ -1563,7 +1564,7 @@ msgstr "Emulador OPL de DOSBox" #: audio/fmopl.cpp:67 msgid "ALSA Direct FM" -msgstr "" +msgstr "ALSA Direct FM" #: audio/mididrv.cpp:209 #, c-format @@ -1620,16 +1621,15 @@ msgstr "Emulador de Apple II GS (NO IMPLEMENTADO)" #: audio/softsynth/cms.cpp:350 msgid "Creative Music System Emulator" -msgstr "" +msgstr "Emulador de Creative Music System" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33 msgid "FM-Towns Audio" -msgstr "" +msgstr "FM-Towns Audio" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58 -#, fuzzy msgid "PC-98 Audio" -msgstr "Sonido" +msgstr "PC-98 Audio" #: audio/softsynth/mt32.cpp:200 msgid "Initializing MT-32 Emulator" @@ -1724,34 +1724,33 @@ msgstr "¿Quieres salir?" #. I18N: Trackpad mode toggle status. #: backends/events/webossdl/webossdl-events.cpp:308 -#, fuzzy msgid "Trackpad mode is now" -msgstr "Modo Touchpad desactivado." +msgstr "El modo trackpad está" #. 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 "" +msgstr "activado" #: backends/events/webossdl/webossdl-events.cpp:311 #: backends/events/webossdl/webossdl-events.cpp:338 msgid "OFF" -msgstr "" +msgstr "desactivado" #: backends/events/webossdl/webossdl-events.cpp:315 msgid "Swipe two fingers to the right to toggle." -msgstr "" +msgstr "Desliza dos dedos hacia la derecha para cambiar de modo." #. I18N: Auto-drag toggle status. #: backends/events/webossdl/webossdl-events.cpp:335 msgid "Auto-drag mode is now" -msgstr "" +msgstr "El modo de arrastre automático está" #: backends/events/webossdl/webossdl-events.cpp:342 msgid "Swipe three fingers to the right to toggle." -msgstr "" +msgstr "Desliza tres dedos hacia la derecha para cambiar de modo." #: backends/graphics/opengl/opengl-graphics.cpp:119 msgid "OpenGL" @@ -1772,19 +1771,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Normal" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "Activar la corrección de aspecto" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "Desactivar la corrección de aspecto" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Filtro de gráficos activo:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Modo ventana" @@ -2046,24 +2045,23 @@ msgstr "Control del ratón" #: backends/platform/tizen/fs.cpp:259 msgid "[ Data ]" -msgstr "" +msgstr "[ Datos ]" #: backends/platform/tizen/fs.cpp:263 msgid "[ Resources ]" -msgstr "" +msgstr "[ Recursos ]" #: backends/platform/tizen/fs.cpp:267 msgid "[ SDCard ]" -msgstr "" +msgstr "[ Tarjeta SD ]" #: backends/platform/tizen/fs.cpp:271 msgid "[ Media ]" -msgstr "" +msgstr "[ Media ]" #: backends/platform/tizen/fs.cpp:275 -#, fuzzy msgid "[ Shared ]" -msgstr "Disco compartido:" +msgstr "[ Compartido ]" #: backends/platform/wii/options.cpp:51 msgid "Video" @@ -2331,36 +2329,45 @@ msgstr "" "Utilizar las pantallas de guardar/cargar originales, en vez de las de ScummVM" #: engines/agi/detection.cpp:157 -#, fuzzy msgid "Use an alternative palette" -msgstr "" -"Usa una introducción alternativa para el juego (solo para la versión CD)" +msgstr "Usar paleta alternativa" #: engines/agi/detection.cpp:158 msgid "" "Use an alternative palette, common for all Amiga games. This was the old " "behavior" msgstr "" +"Usar una paleta alternativa, común para todos los juegos de Amiga. Esta es " +"la opción que se usaba antes." #: engines/agi/detection.cpp:167 -#, fuzzy msgid "Mouse support" -msgstr "Permitir omisiones" +msgstr "Compatibilidad de ratón" #: engines/agi/detection.cpp:168 msgid "" "Enables mouse support. Allows to use mouse for movement and in game menus." msgstr "" +"Activa el ratón. Permite usar el ratón para moverse en el juego y en los " +"menús." -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Cargar partida:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Cargar" @@ -2403,13 +2410,12 @@ msgid "Cutscene file '%s' not found!" msgstr "No se ha encontrado el vídeo '%s'" #: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101 -#, fuzzy msgid "Color Blind Mode" -msgstr "Modo clic" +msgstr "Modo para daltónicos" #: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102 msgid "Enable Color Blind Mode by default" -msgstr "" +msgstr "Activar por defecto el modo para daltónicos" #: engines/drascula/saveload.cpp:47 msgid "" @@ -2465,11 +2471,11 @@ msgstr "Fallo al guardar la partida" #: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86 msgid "Gore Mode" -msgstr "" +msgstr "Modo sangriento" #: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87 msgid "Enable Gore Mode when available" -msgstr "" +msgstr "Activar el modo sangriento si está disponible" #. I18N: Studio audience adds an applause and cheering sounds whenever #. Malcolm makes a joke. @@ -2601,6 +2607,12 @@ msgid "" "Do you wish to use this save game file with ScummVM?\n" "\n" msgstr "" +"Se ha encontrado esta partida guardada en el directorio del juego:\n" +"\n" +"%s %s\n" +"\n" +"Do you wish to use this save game file with ScummVM?\n" +"\n" #: engines/kyra/saveload_eob.cpp:590 #, c-format @@ -2608,6 +2620,8 @@ msgid "" "A save game file was found in the specified slot %d. Overwrite?\n" "\n" msgstr "" +"Ya hay una partida guardada en la ranura %d. ¿Quieres sobrescribirla?\n" +"\n" #: engines/kyra/saveload_eob.cpp:623 #, c-format @@ -2619,6 +2633,11 @@ msgid "" "'import_savefile'.\n" "\n" msgstr "" +"Se han importado %d partidas guardadas originales.\n" +"Si más adelante quieres importar manualmente más partidas guardadas\n" +"originales, tendrás que abrir la consola de ScummVM y usar el comando " +"'import_savefile'.\n" +"\n" #. I18N: Option for fast scene switching #: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167 @@ -2672,10 +2691,18 @@ msgstr "" "No se puede guardar en la ranura %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +msgid "Load file" +msgstr "Cargar partida" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Cargando partida..." +#: engines/parallaction/saveload.cpp:212 +msgid "Save file" +msgstr "Guardar partida" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Guardando partida..." @@ -2760,21 +2787,21 @@ msgstr "" #: engines/sci/detection.cpp:374 msgid "Skip EGA dithering pass (full color backgrounds)" -msgstr "" +msgstr "Omitir difuminado EGA (colores completos)" #: engines/sci/detection.cpp:375 msgid "Skip dithering pass in EGA games, graphics are shown with full colors" msgstr "" +"Omitir pasada de difuminado en los juegos EGA. Los gráficos se muestran con " +"los colores completos" #: engines/sci/detection.cpp:384 -#, fuzzy msgid "Enable high resolution graphics" -msgstr "Activar las barras de energía" +msgstr "Activar gráficos de alta resolución" #: engines/sci/detection.cpp:385 -#, fuzzy msgid "Enable high resolution graphics/content" -msgstr "Activar las barras de energía" +msgstr "Activar gráficos/contenido de alta resolución" #: engines/sci/detection.cpp:394 msgid "Prefer digital sound effects" @@ -2847,13 +2874,11 @@ msgstr "Juego pausado. Pulsa Espacio para continuar." #. "Moechten Sie wirklich neu starten? (J/N)J" #. Will react to J as 'Yes' #: engines/scumm/dialogs.cpp:183 -#, fuzzy msgid "Are you sure you want to restart? (Y/N)Y" msgstr "¿Seguro que quieres reiniciar? (S/N)S" #. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment #: engines/scumm/dialogs.cpp:185 -#, fuzzy msgid "Are you sure you want to quit? (Y/N)Y" msgstr "¿Seguro que quieres salir? (S/N)S" @@ -3363,25 +3388,24 @@ msgid "Third kid" msgstr "Tercer chaval" #: engines/scumm/help.cpp:292 -#, fuzzy msgid "Toggle Inventory/IQ Points display" -msgstr "Activar/Desactivar pantalla de datos" +msgstr "Alternar entre el inventario y la pantalla de puntuación" #: engines/scumm/help.cpp:293 msgid "Toggle Keyboard/Mouse Fighting (*)" -msgstr "" +msgstr "Alternar entre modo de lucha con teclado o con ratón (*)" #: engines/scumm/help.cpp:295 msgid "* Keyboard Fighting is always on," -msgstr "" +msgstr "* El modo de lucha con teclado siempre está activo," #: engines/scumm/help.cpp:296 msgid " so despite the in-game message this" -msgstr "" +msgstr " así que, independientemente de lo que diga el juego," #: engines/scumm/help.cpp:297 msgid " actually toggles Mouse Fighting Off/On" -msgstr "" +msgstr " esta opción activa/desactiva el modo de lucha con ratón" #: engines/scumm/help.cpp:304 msgid "Fighting controls (numpad):" @@ -3418,7 +3442,7 @@ msgstr "Puñetazo bajo" #: engines/scumm/help.cpp:315 msgid "Sucker punch" -msgstr "" +msgstr "Puñetazo a traición" #: engines/scumm/help.cpp:318 msgid "These are for Indy on left." @@ -3477,21 +3501,18 @@ msgid "Fly to lower right" msgstr "Volar abajo y a la derecha" #: engines/scumm/input.cpp:580 -#, fuzzy msgid "Snap scroll on" -msgstr "Desplazamiento suave" +msgstr "Desplazamiento mediante toques" #: engines/scumm/input.cpp:582 msgid "Snap scroll off" -msgstr "" +msgstr "Desplazamiento normal" #: engines/scumm/input.cpp:595 -#, fuzzy msgid "Music volume: " -msgstr "Música:" +msgstr "Volumen de la música:" #: engines/scumm/input.cpp:612 -#, fuzzy msgid "Subtitle speed: " msgstr "Vel. de subtítulos:" @@ -3505,27 +3526,88 @@ msgstr "" "pero %s no está disponible. Se usará AdLib." #: engines/scumm/scumm.cpp:2644 -#, fuzzy 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 "" -"Maniac Mansion debería arrancar en este momento, pero ScummVM aún no lo " -"permite. Para jugar, ve a 'Añadir juego' en el menú de inicio de ScummVM y " -"selecciona el directorio 'Maniac', dentro del directorio de DOTT." +"Maniac Mansion debería arrancar en este momento, pero para que esto sea " +"posible debes mover los archivos de Maniac Mansion al directorio 'Maniac', " +"dentro del directorio de DOTT, y añadir el juego a ScummVM." #: 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 "" +"No se ha podido encontrar el ejecutable de Macintosh de 'Loom'\n" +"para reproducir los instrumentos. Se ha desactivado la música." #: 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 "" +"No se ha podido encontrar el ejecutable de Macintosh de 'Monkey Island'\n" +"para reproducir los instrumentos. Se ha desactivado la música." + +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "Usar menús originales al guardar/cargar" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" +"Se usan los menús originales para guardar y cargar partida en vez de los " +"menús de ScummVM" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "Transiciones pixeladas" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "Al cambiar de escena, se utiliza una transición aleatoria de píxeles" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "No mostrar los puntos interactivos al mover el ratón" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" +"El nombre de los puntos interactivos solo aparece al hacer clic en uno de " +"ellos o en un botón de acción." + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "Mostrar retratos" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "Mostrar retratos de los personajes durante las conversaciones" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "Utilizar una transición al mostrar los diálogos" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "" +"Los diálogos se muestran con una transición, en vez de aparecer " +"inmediatamente" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "Ventanas transparentes" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "Mostrar las ventanas con un fondo parcialmente transparente" #: engines/sky/compact.cpp:130 msgid "" @@ -3646,53 +3728,50 @@ msgstr "" #: engines/wintermute/detection.cpp:58 msgid "Show FPS-counter" -msgstr "" +msgstr "Mostrar contador de FPS" #: engines/wintermute/detection.cpp:59 msgid "Show the current number of frames per second in the upper left corner" msgstr "" +"El número de fotogramas por segundo aparece en la esquina superior izquierda" #: engines/zvision/detection_tables.h:52 -#, fuzzy msgid "Use the original save/load screens instead of the ScummVM interface" msgstr "" -"Utilizar las pantallas de guardar/cargar originales, en vez de las de ScummVM" +"Utilizar los menús originales para guardar/cargar, en vez de los de ScummVM" #: engines/zvision/detection_tables.h:61 msgid "Double FPS" -msgstr "" +msgstr "Duplicar FPS" #: engines/zvision/detection_tables.h:62 msgid "Increase framerate from 30 to 60 FPS" -msgstr "" +msgstr "Aumenta el número de fotogramas por segundo de 30 a 60" #: engines/zvision/detection_tables.h:71 -#, fuzzy msgid "Enable Venus" -msgstr "Activar el modo helio" +msgstr "Activar Venus" #: engines/zvision/detection_tables.h:72 -#, fuzzy msgid "Enable the Venus help system" -msgstr "Activar el modo helio" +msgstr "Activar el modo de ayuda Venus" #: engines/zvision/detection_tables.h:81 msgid "Disable animation while turning" -msgstr "" +msgstr "Desactivar animación al girar" #: engines/zvision/detection_tables.h:82 msgid "Disable animation while turning in panorama mode" -msgstr "" +msgstr "Desactivar la animación al girar en el modo panorama" #: engines/zvision/detection_tables.h:91 msgid "Use high resolution MPEG video" -msgstr "" +msgstr "Usar vídeos MPEG de alta resolución" #: engines/zvision/detection_tables.h:92 -#, fuzzy msgid "Use MPEG video from the DVD version, instead of lower resolution AVI" msgstr "" -"Usar los cursores plateados alternativos, en vez de los dorados normales" +"Usar los vídeos MPEG de la versión DVD, en vez de los AVI de baja resolución" #~ msgid "EGA undithering" #~ msgstr "Difuminado EGA" @@ -3742,6 +3821,3 @@ msgstr "" #~ msgid "Enable Roland GS Mode" #~ msgstr "Activar modo Roland GS" - -#~ msgid "Save game failed!" -#~ msgstr "No se ha podido guardar la partida." @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.5.0git\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" "PO-Revision-Date: 2011-12-15 14:53+0100\n" "Last-Translator: Mikel Iturbe Urretxa <mikel@hamahiru.org>\n" "Language-Team: Librezale <librezale@librezale.org>\n" @@ -30,13 +30,12 @@ msgid "Available engines:" msgstr "Motore erabilgarriak:" #: gui/browser.cpp:68 gui/browser_osx.mm:104 -#, fuzzy msgid "Show hidden files" -msgstr "Kontsola erakutsi / ezkutatu" +msgstr "Erakutsi fitxategi ezkutuak" #: gui/browser.cpp:68 msgid "Show files marked with the hidden attribute" -msgstr "" +msgstr "Erakutsi ezkutu modura markaturiko fitxategiak" #: gui/browser.cpp:72 msgid "Go up" @@ -73,7 +72,7 @@ msgstr "Aukeratu" #: gui/editrecorddialog.cpp:58 msgid "Author:" -msgstr "" +msgstr "Egilea:" #: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204 msgid "Name:" @@ -81,24 +80,23 @@ msgstr "Izena:" #: gui/editrecorddialog.cpp:60 msgid "Notes:" -msgstr "" +msgstr "Oharrak:" #: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74 msgid "Ok" -msgstr "" +msgstr "Ados" #: gui/filebrowser-dialog.cpp:49 msgid "Choose file for loading" -msgstr "" +msgstr "Aukeratu kargatzeko fitxategia" #: gui/filebrowser-dialog.cpp:49 msgid "Enter filename for saving" -msgstr "" +msgstr "Sartu gordetzeko fitxategi-izena" #: gui/filebrowser-dialog.cpp:132 -#, fuzzy msgid "Do you really want to overwrite the file?" -msgstr "Ezabatu partida gorde hau?" +msgstr "Gainidatzi fitxategia?" #: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217 #: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002 @@ -121,59 +119,56 @@ msgid "No" msgstr "Ez" #: gui/fluidsynth-dialog.cpp:68 -#, fuzzy msgid "Reverb" -msgstr "Inoiz ez" +msgstr "Erreberberazioa" #: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102 -#, fuzzy msgid "Active" -msgstr "(Aktiboa)" +msgstr "Aktiboa" #: gui/fluidsynth-dialog.cpp:72 msgid "Room:" -msgstr "" +msgstr "Gela:" #: gui/fluidsynth-dialog.cpp:79 msgid "Damp:" -msgstr "" +msgstr "Moteltzea:" #: gui/fluidsynth-dialog.cpp:86 msgid "Width:" -msgstr "" +msgstr "Zabalera:" #: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111 msgid "Level:" -msgstr "" +msgstr "Maila:" #: gui/fluidsynth-dialog.cpp:100 msgid "Chorus" -msgstr "" +msgstr "Koroa" #: gui/fluidsynth-dialog.cpp:104 msgid "N:" -msgstr "" +msgstr "N:" #: gui/fluidsynth-dialog.cpp:118 -#, fuzzy msgid "Speed:" -msgstr "Ahotsa" +msgstr "Abiadura:" #: gui/fluidsynth-dialog.cpp:125 msgid "Depth:" -msgstr "" +msgstr "Sakonera:" #: gui/fluidsynth-dialog.cpp:132 msgid "Type:" -msgstr "" +msgstr "Mota:" #: gui/fluidsynth-dialog.cpp:135 msgid "Sine" -msgstr "" +msgstr "Sinua" #: gui/fluidsynth-dialog.cpp:136 msgid "Triangle" -msgstr "" +msgstr "Triangelua" #: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168 msgid "Misc" @@ -181,31 +176,31 @@ msgstr "Beste" #: gui/fluidsynth-dialog.cpp:140 msgid "Interpolation:" -msgstr "" +msgstr "Interpolazioa:" #: gui/fluidsynth-dialog.cpp:143 msgid "None (fastest)" -msgstr "" +msgstr "Bat ere ez (azkarrena)" #: gui/fluidsynth-dialog.cpp:144 msgid "Linear" -msgstr "" +msgstr "Lineala" #: gui/fluidsynth-dialog.cpp:145 msgid "Fourth-order" -msgstr "" +msgstr "Laugarren ordena" #: gui/fluidsynth-dialog.cpp:146 msgid "Seventh-order" -msgstr "" +msgstr "Zazpigarren ordena" #: gui/fluidsynth-dialog.cpp:150 msgid "Reset" -msgstr "" +msgstr "Berrezarri" #: gui/fluidsynth-dialog.cpp:150 msgid "Reset all FluidSynth settings to their default values." -msgstr "" +msgstr "Berrazarri FluidSynth-en ezarpen guztiak bere balio lehenetsietara" #: 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 @@ -227,10 +222,9 @@ msgid "OK" msgstr "Ados" #: gui/fluidsynth-dialog.cpp:217 -#, fuzzy msgid "" "Do you really want to reset all FluidSynth settings to their default values?" -msgstr "Ziur zaude abiarazlera itzuli nahi duzula?" +msgstr "FluidSynth-en ezarpen guztiak berrezarri balio lehenetsietara?" #: gui/gui-manager.cpp:119 backends/keymapper/remap-dialog.cpp:53 #: engines/scumm/help.cpp:126 engines/scumm/help.cpp:141 @@ -245,11 +239,11 @@ msgstr "Sagu-klika" #: gui/gui-manager.cpp:126 base/main.cpp:322 msgid "Display keyboard" -msgstr "Teklatua erakutsi" +msgstr "Erakutsi teklatua" #: gui/gui-manager.cpp:130 base/main.cpp:326 msgid "Remap keys" -msgstr "Teklak esleitu" +msgstr "Esleitu teklak" #: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87 msgid "Toggle fullscreen" @@ -346,9 +340,8 @@ msgid "Platform:" msgstr "Plataforma:" #: gui/launcher.cpp:237 -#, fuzzy msgid "Engine" -msgstr "Aztertu" +msgstr "Motorea" #: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088 msgid "Graphics" @@ -593,16 +586,16 @@ msgid "Search:" msgstr "Bilatu:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Jokoa kargatu:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Kargatu" @@ -632,9 +625,8 @@ msgid "Do you really want to remove this game configuration?" msgstr "Benetan ezabatu nahi duzu joko-konfigurazio hau?" #: gui/launcher.cpp:1001 -#, fuzzy msgid "Do you want to load saved game?" -msgstr "Jokoa kargatu edo gorde nahi duzu?" +msgstr "Gordetako jokoa kargatu?" #: gui/launcher.cpp:1050 msgid "This game does not support loading games from the launcher." @@ -648,11 +640,11 @@ msgstr "" #: gui/launcher.cpp:1161 msgid "Mass Add..." -msgstr "Hainbat gehitu..." +msgstr "Gehitu hainbat..." #: gui/launcher.cpp:1163 msgid "Record..." -msgstr "" +msgstr "Grabatu..." #: gui/massadd.cpp:79 gui/massadd.cpp:82 msgid "... progress ..." @@ -681,21 +673,19 @@ msgstr "" #: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103 msgid "Stop" -msgstr "" +msgstr "Gelditu" #: gui/onscreendialog.cpp:106 msgid "Edit record description" -msgstr "" +msgstr "Editatu grabazioaren desribapena" #: gui/onscreendialog.cpp:108 -#, fuzzy msgid "Switch to Game" -msgstr "Aldatu" +msgstr "Aldatu jokora" #: gui/onscreendialog.cpp:110 -#, fuzzy msgid "Fast replay" -msgstr "Modu bizkorra" +msgstr "Errepikappen bizkorra" #: gui/options.cpp:85 msgid "Never" @@ -772,7 +762,7 @@ msgid "Special dithering modes supported by some games" msgstr "Joko batzuk onarturiko lausotze-modu bereziak" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Pantaila osoa" @@ -875,7 +865,7 @@ msgstr "MIDI irabazia:" #: gui/options.cpp:872 msgid "FluidSynth Settings" -msgstr "" +msgstr "FluidSynth Ezarpenak" #: gui/options.cpp:879 msgid "MT-32 Device:" @@ -905,15 +895,16 @@ msgid "True Roland MT-32 (no GM emulation)" msgstr "Benetako Roland MT-32 (GM emulazio gabe)" #: gui/options.cpp:889 -#, fuzzy msgid "Roland GS Device (enable MT-32 mappings)" -msgstr "Benetako Roland MT-32 (GM emulazio gabe)" +msgstr "Roland GS Gailua (gaitu MT-32 bihurketak)" #: gui/options.cpp:889 msgid "" "Check if you want to enable patch mappings to emulate an MT-32 on a Roland " "GS device" msgstr "" +"Markatu Roland GS gailu batean MT-32 bat emulatzea ahalbidetzen " +"dutenbihurketak gaitzeko" #: gui/options.cpp:898 msgid "Don't use Roland MT-32 music" @@ -1089,39 +1080,38 @@ msgstr "" #. I18N: You must leave "#" as is, only word 'next' is translatable #: gui/predictivedialog.cpp:86 msgid "# next" -msgstr "" +msgstr "# hurrengoa" #: gui/predictivedialog.cpp:87 msgid "add" -msgstr "" +msgstr "gehitu" #: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164 -#, fuzzy msgid "Delete char" -msgstr "Ezabatu" +msgstr "Ezabatu karakterea" #: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168 msgid "<" -msgstr "" +msgstr "<" #. I18N: Pre means 'Predictive', leave '*' as is #: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572 msgid "* Pre" -msgstr "" +msgstr "* Pre" #. I18N: 'Num' means Numbers #: gui/predictivedialog.cpp:575 msgid "* Num" -msgstr "" +msgstr "* Zenb" #. I18N: 'Abc' means Latin alphabet input #: gui/predictivedialog.cpp:578 msgid "* Abc" -msgstr "" +msgstr "* Abc" #: gui/recorderdialog.cpp:64 msgid "Recorder or Playback Gameplay" -msgstr "" +msgstr "Grabatu edo erreproduzitu jokoko akzioa" #: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156 #: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276 @@ -1130,44 +1120,41 @@ msgstr "Ezabatu" #: gui/recorderdialog.cpp:71 msgid "Record" -msgstr "" +msgstr "Grabatu" #: gui/recorderdialog.cpp:72 -#, fuzzy msgid "Playback" -msgstr "Jolastu" +msgstr "Erreproduzitu" #: gui/recorderdialog.cpp:74 msgid "Edit" -msgstr "" +msgstr "Editatu" #: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243 #: gui/recorderdialog.cpp:253 msgid "Author: " -msgstr "" +msgstr "Egilea: " #: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244 #: gui/recorderdialog.cpp:254 msgid "Notes: " -msgstr "" +msgstr "Oharrak: " #: gui/recorderdialog.cpp:155 -#, fuzzy msgid "Do you really want to delete this record?" -msgstr "Ezabatu partida gorde hau?" +msgstr "Ezabatu grabazio hau?" #: gui/recorderdialog.cpp:174 -#, fuzzy msgid "Unknown Author" -msgstr "Errore ezezaguna" +msgstr "Egile ezezaguna" #: gui/saveload-dialog.cpp:167 msgid "List view" -msgstr "" +msgstr "Zerrenda ikuspegia" #: gui/saveload-dialog.cpp:168 msgid "Grid view" -msgstr "" +msgstr "Sareta ikuspegia " #: gui/saveload-dialog.cpp:211 gui/saveload-dialog.cpp:360 msgid "No date saved" @@ -1191,43 +1178,40 @@ msgstr "Data:" #: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890 msgid "Time: " -msgstr "Ordua" +msgstr "Ordua: " #: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898 msgid "Playtime: " -msgstr "Denbora:" +msgstr "Denbora: " #: gui/saveload-dialog.cpp:408 gui/saveload-dialog.cpp:496 msgid "Untitled savestate" -msgstr "Titulurik gabeko partida" +msgstr "Titulurik gabeko joko gordea" #: gui/saveload-dialog.cpp:548 msgid "Next" -msgstr "" +msgstr "Aurr." #: gui/saveload-dialog.cpp:551 msgid "Prev" -msgstr "" +msgstr "Hurr." #: gui/saveload-dialog.cpp:748 -#, fuzzy msgid "New Save" msgstr "Gorde" #: gui/saveload-dialog.cpp:748 -#, fuzzy msgid "Create a new save game" -msgstr "Ezin izan da jokoa gorde" +msgstr "Sortu joko gorde berria" #: gui/saveload-dialog.cpp:877 -#, fuzzy msgid "Name: " -msgstr "Izena:" +msgstr "Izena: " #: gui/saveload-dialog.cpp:949 #, c-format msgid "Enter a description for slot %d:" -msgstr "" +msgstr "Sartu deskribapena %d zirrikiturako: " #: gui/themebrowser.cpp:45 msgid "Select a Theme" @@ -1243,23 +1227,20 @@ msgid "Disabled GFX" msgstr "GFX desgaituta" #: gui/ThemeEngine.cpp:348 -#, fuzzy msgid "Standard Renderer" -msgstr "Estandarra (16bpp)" +msgstr "Errendatzaile estandarra" #: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663 msgid "Standard" msgstr "Estandarra" #: gui/ThemeEngine.cpp:350 -#, fuzzy msgid "Antialiased Renderer" -msgstr "Lausotua (16bpp)" +msgstr "Errendatzaile lausotua" #: gui/ThemeEngine.cpp:350 -#, fuzzy msgid "Antialiased" -msgstr "Lausotua (16bpp)" +msgstr "Lausotua" #: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333 msgid "Clear value" @@ -1372,18 +1353,18 @@ msgstr "Herkules anbar-kolorekoa" #: common/rendermode.cpp:42 msgid "PC-9821 (256 Colors)" -msgstr "" +msgstr "PC-9821 (256 Kolore)" #: common/rendermode.cpp:43 msgid "PC-9801 (16 Colors)" -msgstr "" +msgstr "PC-9801 (16 kolore)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Herkules berdea" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Herkules anbar-kolorekoa" @@ -1434,11 +1415,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "It~z~uli abiarazlera" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Gorde jokoa:" @@ -1447,11 +1432,15 @@ msgstr "Gorde jokoa:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Gorde" @@ -1568,7 +1557,7 @@ msgstr "DOSBox OPL emuladorea" #: audio/fmopl.cpp:67 msgid "ALSA Direct FM" -msgstr "" +msgstr "ALSA FM zuzena" #: audio/mididrv.cpp:209 #, c-format @@ -1625,16 +1614,15 @@ msgstr "Apple II GS emuladorea (INPLEMENTATU GABE)" #: audio/softsynth/cms.cpp:350 msgid "Creative Music System Emulator" -msgstr "" +msgstr "Creative musika sistema emuladorea" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33 msgid "FM-Towns Audio" -msgstr "" +msgstr "FM-Towns soinua" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58 -#, fuzzy msgid "PC-98 Audio" -msgstr "Soinua" +msgstr "PC-98 Soinua" #: audio/softsynth/mt32.cpp:200 msgid "Initializing MT-32 Emulator" @@ -1720,53 +1708,50 @@ msgid "Clicking Disabled" msgstr "Klikatzea desgaituta" #: backends/events/openpandora/op-events.cpp:174 -#, fuzzy msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)" -msgstr "Ukimen-pantailako 'kolpetxo modua' - Flotatu (klikik ez)" +msgstr "Ukimen-pantailako 'kolpetxo modua' - Flotatu (DPad klikak)" #: backends/events/symbiansdl/symbiansdl-events.cpp:186 msgid "Do you want to quit ?" -msgstr "Irten nahi al duzu?" +msgstr "Benetan irten?" #. I18N: Trackpad mode toggle status. #: backends/events/webossdl/webossdl-events.cpp:308 -#, fuzzy msgid "Trackpad mode is now" -msgstr "Touchpad modua desgaituta." +msgstr "Trackpad modua orain:" #. 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 "" +msgstr "ON" #: backends/events/webossdl/webossdl-events.cpp:311 #: backends/events/webossdl/webossdl-events.cpp:338 msgid "OFF" -msgstr "" +msgstr "OFF" #: backends/events/webossdl/webossdl-events.cpp:315 msgid "Swipe two fingers to the right to toggle." -msgstr "" +msgstr "Pasatu bi atzamara eskuinean gaitu/desgaitzeko." #. I18N: Auto-drag toggle status. #: backends/events/webossdl/webossdl-events.cpp:335 msgid "Auto-drag mode is now" -msgstr "" +msgstr "Auto-arrastatzea orain:" #: backends/events/webossdl/webossdl-events.cpp:342 msgid "Swipe three fingers to the right to toggle." -msgstr "" +msgstr "Pasatu hiru atzamar eskuinean gaitu/desgaitzeko." #: backends/graphics/opengl/opengl-graphics.cpp:119 -#, fuzzy msgid "OpenGL" -msgstr "Ireki" +msgstr "OpenGL" #: backends/graphics/opengl/opengl-graphics.cpp:120 msgid "OpenGL (No filtering)" -msgstr "" +msgstr "OpenGL (Iragazi gabe)" #: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:47 #: backends/graphics/wincesdl/wincesdl-graphics.cpp:88 @@ -1779,19 +1764,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Normala" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "Formatu-ratio zuzenketa gaituta" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "Formatu-ratio zuzenketa desgaituta" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Filtro grafiko aktiboa:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Leiho modua" @@ -2053,24 +2038,23 @@ msgstr "Saguaren kontrola" #: backends/platform/tizen/fs.cpp:259 msgid "[ Data ]" -msgstr "" +msgstr "[ Datuak ]" #: backends/platform/tizen/fs.cpp:263 msgid "[ Resources ]" -msgstr "" +msgstr "[ Baliabideak ]" #: backends/platform/tizen/fs.cpp:267 msgid "[ SDCard ]" -msgstr "" +msgstr "[ SD Txartela ]" #: backends/platform/tizen/fs.cpp:271 msgid "[ Media ]" -msgstr "" +msgstr "[ Multimedia ]" #: backends/platform/tizen/fs.cpp:275 -#, fuzzy msgid "[ Shared ]" -msgstr "Konpartituriko direktorioa:" +msgstr "[ Konpartitua ]" #: backends/platform/wii/options.cpp:51 msgid "Video" @@ -2327,7 +2311,7 @@ msgstr "Eguneraketak bilatzen..." #: 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 "" +msgstr "Erabili jatorrizko gorde/kargatu pantailak" #: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71 #: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48 @@ -2335,35 +2319,48 @@ msgstr "" #: engines/toltecs/detection.cpp:201 msgid "Use the original save/load screens, instead of the ScummVM ones" msgstr "" +"Erabili jatorrizko gorde/kargatu pantailak, ScummVM-renak erabilibeharrean" #: engines/agi/detection.cpp:157 msgid "Use an alternative palette" -msgstr "" +msgstr "Erabili paleta alternatiboa" #: engines/agi/detection.cpp:158 msgid "" "Use an alternative palette, common for all Amiga games. This was the old " "behavior" msgstr "" +"Erabili kolore-paleta alternatiboa, Amiga joko guztientzako komuna. Hau zen " +"konportamendu zaharra" #: engines/agi/detection.cpp:167 msgid "Mouse support" -msgstr "" +msgstr "Saguaren euskarria" #: engines/agi/detection.cpp:168 msgid "" "Enables mouse support. Allows to use mouse for movement and in game menus." msgstr "" +"Saguaren euskarria giatzen du. Sagua mugitzeko eta jokoko menuetan " +"erabiltzea ahalbidetzen du" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Jokoa kargatu:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Kargatu" @@ -2406,16 +2403,14 @@ msgid "Cutscene file '%s' not found!" msgstr "'%s' bideo fitxategia ez da aurkitu!" #: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101 -#, fuzzy msgid "Color Blind Mode" -msgstr "Klikatzeko modua" +msgstr "Daltonikoentzako modua" #: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102 msgid "Enable Color Blind Mode by default" -msgstr "" +msgstr "Gaitu daltonikoentzako modua lehenetsi modura" #: engines/drascula/saveload.cpp:47 -#, fuzzy msgid "" "ScummVM found that you have old savefiles for Drascula that should be " "converted.\n" @@ -2425,8 +2420,8 @@ msgid "" "Press OK to convert them now, otherwise you will be asked again the next " "time you start the game.\n" msgstr "" -"ScummVM-k aurkitu du konbertitu beharko liratekeen Broken Sword 1-eko " -"partida gorde zaharrak dituzula.\n" +"ScummVM-k aurkitu du konbertitu beharko liratekeen Drascula-ko partida gorde " +"zaharrak dituzula.\n" "Partida gordeen formatu zaharra ez da bateragarria jada, eta beraz ezingo " "dituzu zure partidak kargatu ez badituzu formatu berrira pasatzen.\n" "\n" @@ -2434,13 +2429,12 @@ msgstr "" "martxan jartzen duzunean.\n" #: engines/dreamweb/detection.cpp:57 -#, fuzzy msgid "Use bright palette mode" -msgstr "Goiko eskuineko objektua" +msgstr "Erabili paleta argia" #: engines/dreamweb/detection.cpp:58 msgid "Display graphics using the game's bright palette" -msgstr "" +msgstr "Erakutsi grafikoak jokoaren paleta argia erabilita" #: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470 #: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532 @@ -2457,13 +2451,12 @@ msgid "Failed to delete file." msgstr "Ezin izan da fitxategia ezabatu" #: engines/groovie/detection.cpp:312 -#, fuzzy msgid "Fast movie speed" -msgstr "Modu bizkorra" +msgstr "Bideo abiadura azkarra" #: engines/groovie/detection.cpp:313 msgid "Play movies at an increased speed" -msgstr "" +msgstr "Erreproduzitu bidoeak abiadura handiagoan" #: engines/groovie/script.cpp:408 msgid "Failed to save game" @@ -2471,71 +2464,69 @@ msgstr "Ezin izan da jokoa gorde" #: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86 msgid "Gore Mode" -msgstr "" +msgstr "Gore modua" #: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87 msgid "Enable Gore Mode when available" -msgstr "" +msgstr "Gaitu Gore modua eskuragarri dagoenean" #. I18N: Studio audience adds an applause and cheering sounds whenever #. Malcolm makes a joke. #: engines/kyra/detection.cpp:62 msgid "Studio audience" -msgstr "" +msgstr "Estudio ingurunea" #: engines/kyra/detection.cpp:63 msgid "Enable studio audience" -msgstr "" +msgstr "Gaitu estudio ingurunea" #. I18N: This option allows the user to skip text and cutscenes. #: engines/kyra/detection.cpp:73 msgid "Skip support" -msgstr "" +msgstr "Jauzi egin" #: engines/kyra/detection.cpp:74 msgid "Allow text and cutscenes to be skipped" -msgstr "" +msgstr "Utzi testua eta bideoak saltatzen" #. I18N: Helium mode makes people sound like they've inhaled Helium. #: engines/kyra/detection.cpp:84 msgid "Helium mode" -msgstr "" +msgstr "Helio modua" #: engines/kyra/detection.cpp:85 -#, fuzzy msgid "Enable helium mode" -msgstr "Roland GS modua gaitu" +msgstr "Gaitu helio modua" #. I18N: When enabled, this option makes scrolling smoother when #. changing from one screen to another. #: engines/kyra/detection.cpp:99 msgid "Smooth scrolling" -msgstr "" +msgstr "Korritze leuna" #: engines/kyra/detection.cpp:100 msgid "Enable smooth scrolling when walking" -msgstr "" +msgstr "Gaitu korritze leuna oinez ibiltzean" #. 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 -#, fuzzy msgid "Floating cursors" -msgstr "Kurtsore normala" +msgstr "Kurtsore flotatzaileak" #: engines/kyra/detection.cpp:113 msgid "Enable floating cursors" -msgstr "" +msgstr "Gaitu kurtsore flotatzaileak" #. I18N: HP stands for Hit Points #: engines/kyra/detection.cpp:127 msgid "HP bar graphs" -msgstr "" +msgstr "HP barrak" #: engines/kyra/detection.cpp:128 msgid "Enable hit point bar graphs" -msgstr "" +msgstr "Gaitu bizitza barrak" #: engines/kyra/lol.cpp:478 msgid "Attack 1" @@ -2575,7 +2566,7 @@ msgstr "Eskuinera biratu" #: engines/kyra/lol.cpp:487 msgid "Rest" -msgstr "Kargatu" +msgstr "Atsedena" #: engines/kyra/lol.cpp:488 msgid "Options" @@ -2586,7 +2577,6 @@ msgid "Choose Spell" msgstr "Sorginkeria aukeratu" #: engines/kyra/sound_midi.cpp:477 -#, fuzzy msgid "" "You appear to be using a General MIDI device,\n" "but your game only supports Roland MT32 MIDI.\n" @@ -2610,6 +2600,12 @@ msgid "" "Do you wish to use this save game file with ScummVM?\n" "\n" msgstr "" +"Hurrengo jatorrizko gordetako fitxategia aurkitu da bidean:\n" +"\n" +"%s %s\n" +"\n" +"Gordetako jokoaren fitxategia ScummVM-rekin erabili?\n" +"\n" #: engines/kyra/saveload_eob.cpp:590 #, c-format @@ -2617,6 +2613,9 @@ msgid "" "A save game file was found in the specified slot %d. Overwrite?\n" "\n" msgstr "" +"Joko gorde baten fitxategia aurkitu da zehaztutako %d zirrikituan." +"Gainidatzi?\n" +"\n" #: engines/kyra/saveload_eob.cpp:623 #, c-format @@ -2628,6 +2627,10 @@ msgid "" "'import_savefile'.\n" "\n" msgstr "" +"Jatorrizko %d gordetako joko fitxategi ondo inportatu dira \n" +"ScummVM-era. Geroago eskuz jatorrizko joko gordeak inportatu\n" +"nahi izanez gero ScummVM debug konsola ireki eta 'import_savefile'\n" +"agindau erabili.\n" #. I18N: Option for fast scene switching #: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167 @@ -2657,19 +2660,20 @@ msgstr "~U~r-efektua gaituta" #: engines/neverhood/detection.cpp:167 msgid "Skip the Hall of Records storyboard scenes" -msgstr "" +msgstr "Saltatu Hall of Records-eko eszenak" #: engines/neverhood/detection.cpp:168 msgid "Allows the player to skip past the Hall of Records storyboard scenes" msgstr "" +"Erabiltzaileari Halls of Records-eko eszenak ez ikusteko aukera ematen dio" #: engines/neverhood/detection.cpp:174 msgid "Scale the making of videos to full screen" -msgstr "" +msgstr "Eskalatu bideoen egitea pantaila osora" #: engines/neverhood/detection.cpp:175 msgid "Scale the making of videos, so that they use the whole screen" -msgstr "" +msgstr "Eskalatu bideoak egiteko era, pantaila osoa erabili dezaten" #: engines/parallaction/saveload.cpp:133 #, c-format @@ -2680,10 +2684,18 @@ msgstr "" "Ezin da partida gorde %i zirrikituan\n" "\n" +#: engines/parallaction/saveload.cpp:197 +msgid "Load file" +msgstr "Kargatu fitxategia:" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Jokoa kargatzen..." +#: engines/parallaction/saveload.cpp:212 +msgid "Save file" +msgstr "Gorde fitxategia" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Jokoa gordetzen..." @@ -2723,110 +2735,114 @@ msgstr "" #: engines/pegasus/pegasus.cpp:714 msgid "Invalid save file name" -msgstr "" +msgstr "Gordetako jokoko fitxategi-izen baliogabea" #: engines/pegasus/pegasus.cpp:2507 msgid "Up/Zoom In/Move Forward/Open Doors" -msgstr "" +msgstr "Gora/Zoom-a hurbildu/Mugitu aurrera/Ireki ateak" #: engines/pegasus/pegasus.cpp:2508 -#, fuzzy msgid "Down/Zoom Out" -msgstr "Zoom-a hurbildu" +msgstr "Behera/Zoom-a urrundu" #: engines/pegasus/pegasus.cpp:2511 msgid "Display/Hide Inventory Tray" -msgstr "" +msgstr "Erakutsi/Ezkutatu inbentorioaren erretilua" #: engines/pegasus/pegasus.cpp:2512 msgid "Display/Hide Biochip Tray" -msgstr "" +msgstr "Erakutsi/Ezkutatu Biochip erretilua" #: engines/pegasus/pegasus.cpp:2513 msgid "Action/Select" -msgstr "" +msgstr "Ekintza/Aukeratu" #: engines/pegasus/pegasus.cpp:2514 msgid "Toggle Center Data Display" -msgstr "" +msgstr "Erakutsi/Ezkutatu Datu Zentroa" #: engines/pegasus/pegasus.cpp:2515 msgid "Display/Hide Info Screen" -msgstr "" +msgstr "Erakutsi/Ezkutatu informazio pantaila" #: engines/pegasus/pegasus.cpp:2516 msgid "Display/Hide Pause Menu" -msgstr "" +msgstr "Erakutsi/Ezkutatu pausa menua" #: engines/queen/detection.cpp:56 msgid "Alternative intro" -msgstr "" +msgstr "Sarrera alternatiboa" #: engines/queen/detection.cpp:57 msgid "Use an alternative game intro (CD version only)" -msgstr "" +msgstr "Erabili sarrera alternatiboa (CD bertsioa soilik)" #: engines/sci/detection.cpp:374 msgid "Skip EGA dithering pass (full color backgrounds)" -msgstr "" +msgstr "Saihestu EGA leuntze pausua (koloretako hondoak)" #: engines/sci/detection.cpp:375 msgid "Skip dithering pass in EGA games, graphics are shown with full colors" msgstr "" +"Saihestu leuntzea EGA jokoetan, grafikoak kolore guztiekin erakustendira" #: engines/sci/detection.cpp:384 msgid "Enable high resolution graphics" -msgstr "" +msgstr "Gaitu erresoluzio altuko grafikoak" #: engines/sci/detection.cpp:385 msgid "Enable high resolution graphics/content" -msgstr "" +msgstr "Gaitu erresoluzio altuko grafikoak/edukiak" #: engines/sci/detection.cpp:394 -#, fuzzy msgid "Prefer digital sound effects" -msgstr "Soinu efektu berezien bolumena" +msgstr "Lehenetsi soinu efektu digitalak" #: engines/sci/detection.cpp:395 msgid "Prefer digital sound effects instead of synthesized ones" -msgstr "" +msgstr "Lehenetsi soinu efektu digitalak sintetizatuen ordez" #: engines/sci/detection.cpp:414 msgid "Use IMF/Yamaha FB-01 for MIDI output" -msgstr "" +msgstr "Erabili IMF/Yamaha FB-01 MIDI irteerarako" #: engines/sci/detection.cpp:415 msgid "" "Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI " "output" msgstr "" +"Erabili IBM Music Feature txartela edo Yamaha FB-01 FM " +"sintetizatzailemodulua MIDI irteerarako" #: engines/sci/detection.cpp:425 msgid "Use CD audio" -msgstr "" +msgstr "Erabili audio CDa" #: engines/sci/detection.cpp:426 msgid "Use CD audio instead of in-game audio, if available" -msgstr "" +msgstr "Erabili CD-ko audioa jokokoa beharrean, eskurarri badago" #: engines/sci/detection.cpp:436 msgid "Use Windows cursors" -msgstr "" +msgstr "Erabili Windows-eko kurtsoreak" #: engines/sci/detection.cpp:437 msgid "" "Use the Windows cursors (smaller and monochrome) instead of the DOS ones" msgstr "" +"Erabili Windows-eko kurtsoreak (txikiagoak eta monokromoak) DOS-ekoak " +"erabilibeharrean" #: engines/sci/detection.cpp:447 -#, fuzzy msgid "Use silver cursors" -msgstr "Kurtsore normala" +msgstr "Erabili zilarrezko kurtsoreak" #: engines/sci/detection.cpp:448 msgid "" "Use the alternate set of silver cursors, instead of the normal golden ones" msgstr "" +"Erabili zilar kolorezko kurtsore multzo alternatiboa, urre-koloreko " +"kursorenormalak erabili beharrean" #: engines/scumm/dialogs.cpp:176 #, c-format @@ -2851,15 +2867,13 @@ msgstr "Joko pausatua. Sakatu ZURIUNEA jarraitzeko." #. "Moechten Sie wirklich neu starten? (J/N)J" #. Will react to J as 'Yes' #: engines/scumm/dialogs.cpp:183 -#, fuzzy msgid "Are you sure you want to restart? (Y/N)Y" -msgstr "Ziur zaude berrabiarazi nahi duzula (B/E)B" +msgstr "Berrabiarazi? (B/E)B" #. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment #: engines/scumm/dialogs.cpp:185 -#, fuzzy msgid "Are you sure you want to quit? (Y/N)Y" -msgstr "Ziur zaude irten nahi duzula? (B/E)B" +msgstr "Irten? (B/E)B" #: engines/scumm/dialogs.cpp:190 msgid "Play" @@ -2994,7 +3008,7 @@ msgstr "Alt" #: engines/scumm/help.cpp:81 msgid "Save game state 1-10" -msgstr "1-10 partida gorde" +msgstr "Gorde 1-10 jokoa" #: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90 msgid "Enter" @@ -3368,23 +3382,23 @@ msgstr "Hirugarren gaztea" #: engines/scumm/help.cpp:292 msgid "Toggle Inventory/IQ Points display" -msgstr "" +msgstr "Txandakatu Inbentarioa/IQ puntuak" #: engines/scumm/help.cpp:293 msgid "Toggle Keyboard/Mouse Fighting (*)" -msgstr "" +msgstr "Txandakatu teklatu/sagu bidezko borroka (*)" #: engines/scumm/help.cpp:295 msgid "* Keyboard Fighting is always on," -msgstr "" +msgstr "* Teklatu bidezko borroka beti dago gaituta" #: engines/scumm/help.cpp:296 msgid " so despite the in-game message this" -msgstr "" +msgstr " beraz, nahiz eta honelako mezuak erakutsi" #: engines/scumm/help.cpp:297 msgid " actually toggles Mouse Fighting Off/On" -msgstr "" +msgstr " benetan sagu bidezko borroka gaitu/desgaitzen du" #: engines/scumm/help.cpp:304 msgid "Fighting controls (numpad):" @@ -3421,7 +3435,7 @@ msgstr "Ukabilkada baxua" #: engines/scumm/help.cpp:315 msgid "Sucker punch" -msgstr "" +msgstr "Ukabilkada inuzentea" #: engines/scumm/help.cpp:318 msgid "These are for Indy on left." @@ -3480,21 +3494,18 @@ msgid "Fly to lower right" msgstr "Behera eta eskuinera hegan egin" #: engines/scumm/input.cpp:580 -#, fuzzy msgid "Snap scroll on" -msgstr "Behera" +msgstr "Heldutako korritze barra gaituta" #: engines/scumm/input.cpp:582 msgid "Snap scroll off" -msgstr "" +msgstr "Heldutako korritze barra desgaituta" #: engines/scumm/input.cpp:595 -#, fuzzy msgid "Music volume: " -msgstr "Musika:" +msgstr "Musika: " #: engines/scumm/input.cpp:612 -#, fuzzy msgid "Subtitle speed: " msgstr "Azpitit. abiadura:" @@ -3508,27 +3519,87 @@ msgstr "" "baina %s ez dago eskuragarri. AdLib erabiliko da." #: engines/scumm/scumm.cpp:2644 -#, fuzzy 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 "" -"Maniac Mansion orain hasi beharko litzateke, baina ScummVM-k ez du " -"baimentzen oraindik. Jolasteko , joan 'Jokoa gehitu' hasierako menura eta " -"aukeratu 'Maniac' direktorioa Tentacle-ren joko-direktorioaren barruan." +"Maniac Mansion orain hasi beharko litzateke, baina horretarako, jokoko " +"fitxategiak 'Maniac' direktorio barruan egon behar dira, Tentacle jokoko " +"direktorioan, eta jokoa ScummVM-ra gehitu behar da." #: 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 "" +"Ezin izan da 'Loom' Macintosh exekutagarria aurkitu instrumentuak\n" +"bertatik irakurtzeko. Musika desgaituta egongo da." #: 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 "" +"Ezin izan da 'Monkey Island' Macintosh exekutagarria aurkitu instrumentuak\n" +"bertatik irakurtzeko. Musika desgaituta egongo da." + +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "Erabili jatorrizko jokoa gordetzeko elkarrizketak" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" +"Jokoko Fitxategiak botoiak jatorrizko jokoa gordetzeko elkarrizketak erakusten " +"ditu, ScummVM-ren elkarrizketak erakutsi beharrean" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "Eszena trantsizio pixelatuak" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "Eszenak aldatzean, ausazko pixel trantsizioa egiten da" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "Ez erakutsi puntu interesgarriak sagua mugitzean" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" +"Erakutsi puntu interesgarrien izenak haien gainean edota ekintza botoiaren " +"gainean klik egin eta gero bakarrik " + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "Erakutsi pertsonaien erretratuak" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "Erakutsi pertsonaien erretratuak elkarrizketetan" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "Irristatu elkarrizketak" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "Irristatu UI elkarrizketak pantailara, osorik bat-batean erakutsi " +"beharrean" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "Leiho gardenak" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "Erakutsi leihoak partzialki gardena den fondoarekin" #: engines/sky/compact.cpp:130 msgid "" @@ -3548,16 +3619,16 @@ msgstr "" #: engines/sky/detection.cpp:44 msgid "Floppy intro" -msgstr "" +msgstr "Floppy introa" #: engines/sky/detection.cpp:45 msgid "Use the floppy version's intro (CD version only)" -msgstr "" +msgstr "Erabili floppy bertsioko sarrera (CD bertsioa soilik)" #: engines/sword1/animation.cpp:524 #, c-format msgid "PSX stream cutscene '%s' cannot be played in paletted mode" -msgstr "" +msgstr "'%s' PSX eszena ezin da erreproduzitu paletatutako moduan" #: engines/sword1/animation.cpp:545 engines/sword2/animation.cpp:445 msgid "DXA cutscenes found but ScummVM has been built without zlib" @@ -3565,11 +3636,10 @@ msgstr "" "DXA bideoak aurkitu dira, baina ScummVM zlib euskarri gabe konpilatu da" #: engines/sword1/animation.cpp:561 engines/sword2/animation.cpp:461 -#, fuzzy msgid "" "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2 support" msgstr "" -"DXA bideoak aurkitu dira, baina ScummVM zlib euskarri gabe konpilatu da" +"MPEG-2 bideoak aurkitu dira, baina ScummVM MPEG-2 euskarri gabe konpilatu da" #: engines/sword1/animation.cpp:568 engines/sword2/animation.cpp:470 #, c-format @@ -3624,68 +3694,69 @@ msgstr "" #: engines/sword2/sword2.cpp:79 msgid "Show object labels" -msgstr "" +msgstr "Erakutsi objektuen etiketak" #: engines/sword2/sword2.cpp:80 msgid "Show labels for objects on mouse hover" -msgstr "" +msgstr "Erakutsi objektuen etiketak sagua pasatzean" #: engines/teenagent/resources.cpp:95 msgid "" "You're missing the 'teenagent.dat' file. Get it from the ScummVM website" -msgstr "" +msgstr "'teenagent.dat' fitxategia falta da. Eskuratu ScummVM webgunean" #: 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 fitxategia konprimituta dago eta zlib ez dago txertatuta " +"exekutagarri honetan. Deskonprimitu" #: engines/wintermute/detection.cpp:58 msgid "Show FPS-counter" -msgstr "" +msgstr "Erakutsi FPS kontatzailea" #: engines/wintermute/detection.cpp:59 msgid "Show the current number of frames per second in the upper left corner" -msgstr "" +msgstr "Erakutsi momentuko FPS (frames per second) goiko ezkerreko ertzean" #: engines/zvision/detection_tables.h:52 msgid "Use the original save/load screens instead of the ScummVM interface" msgstr "" +"Erabili jatorrizko gorde/kargatu pantailak ScummVM interfazearenak beharrean" #: engines/zvision/detection_tables.h:61 msgid "Double FPS" -msgstr "" +msgstr "Bikoiztu FPSa" #: engines/zvision/detection_tables.h:62 msgid "Increase framerate from 30 to 60 FPS" -msgstr "" +msgstr "Areagotu framerate-a 30etik 60 FPSra" #: engines/zvision/detection_tables.h:71 -#, fuzzy msgid "Enable Venus" -msgstr "Roland GS modua gaitu" +msgstr "Gaitu Venus" #: engines/zvision/detection_tables.h:72 -#, fuzzy msgid "Enable the Venus help system" -msgstr "Roland GS modua gaitu" +msgstr "Gaitu Venus laguntza sistema" #: engines/zvision/detection_tables.h:81 msgid "Disable animation while turning" -msgstr "" +msgstr "Desgaitu animazioak biratzean" #: engines/zvision/detection_tables.h:82 msgid "Disable animation while turning in panorama mode" -msgstr "" +msgstr "Desgaitu animazioak panorama moduan biratzean" #: engines/zvision/detection_tables.h:91 msgid "Use high resolution MPEG video" -msgstr "" +msgstr "Erabili bereizmen altuko MPEG bideoa" #: engines/zvision/detection_tables.h:92 msgid "Use MPEG video from the DVD version, instead of lower resolution AVI" -msgstr "" +msgstr "Erabili DVD bertsioko MPEG bideoa, bereizmen baxuagoko AVI-a beharrean" #~ msgid "EGA undithering" #~ msgstr "EGA lausotzea" @@ -3738,6 +3809,3 @@ msgstr "" #~ msgid "Enable Roland GS Mode" #~ msgstr "Roland GS modua gaitu" - -#~ msgid "Save game failed!" -#~ msgstr "Partida gordeak huts egin du!" diff --git a/po/fi_FI.po b/po/fi_FI.po index f4a26a0429..a306d8e537 100644 --- a/po/fi_FI.po +++ b/po/fi_FI.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.6.0git\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" "PO-Revision-Date: 2012-12-01 19:37+0200\n" "Last-Translator: Toni Saarela <saarela@gmail.com>\n" "Language-Team: Finnish\n" @@ -594,16 +594,16 @@ msgid "Search:" msgstr "Etsi:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Lataa peli:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Lataa" @@ -773,7 +773,7 @@ msgid "Special dithering modes supported by some games" msgstr "Erityiset dithering asetukset joita jotkut pelit tukevat" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Kokoruututila" @@ -1376,12 +1376,12 @@ msgstr "" msgid "PC-9801 (16 Colors)" msgstr "" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "" @@ -1434,11 +1434,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "Palaa p~e~livalitsimeen" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Tallenna peli:" @@ -1447,11 +1451,15 @@ msgstr "Tallenna peli:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Tallenna" @@ -1777,19 +1785,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Normaali (ei skaalausta)" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "Kuvasuhteen korjaus päällä" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "Kuvasuhteen korjaus pois päältä" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Valittu grafiikkafiltteri:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Ikkunoitu tila" @@ -2358,15 +2366,23 @@ msgid "" "Enables mouse support. Allows to use mouse for movement and in game menus." msgstr "" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Lataa pelitallenne:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Lataa tallenne" @@ -2675,10 +2691,20 @@ msgstr "" "Pelin tallennus kohtaan ei onnistunut kohtaan %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +#, fuzzy +msgid "Load file" +msgstr "Lataa peli:" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Ladataan peliä..." +#: engines/parallaction/saveload.cpp:212 +#, fuzzy +msgid "Save file" +msgstr "Tallenna peli:" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Tallennetaan peliä..." @@ -3526,6 +3552,60 @@ msgid "" "instruments from. Music will be disabled." msgstr "" +#: engines/sherlock/detection.cpp:71 +#, fuzzy +msgid "Use original savegame dialog" +msgstr "Käytä alkuperäisiä tallenna/lataa valikkoja" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" + +#: engines/sherlock/detection.cpp:101 +#, fuzzy +msgid "Show character portraits" +msgstr "Vaihda hahmoa" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "" + #: engines/sky/compact.cpp:130 msgid "" "Unable to find \"sky.cpt\" file!\n" diff --git a/po/fr_FR.po b/po/fr_FR.po index e1247dd4ef..e223a96a54 100644 --- a/po/fr_FR.po +++ b/po/fr_FR.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.8.0git\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" -"PO-Revision-Date: 2016-01-25 21:35-0000\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" +"PO-Revision-Date: 2016-02-20 23:17+0000\n" "Last-Translator: Thierry Crozat <criezy@scummvm.org>\n" "Language-Team: French <scummvm-devel@lists.sf.net>\n" "Language: Francais\n" @@ -16,7 +16,7 @@ msgstr "" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n>1;\n" -"X-Generator: Poedit 1.6.6\n" +"X-Generator: Poedit 1.8.6\n" #: gui/about.cpp:94 #, c-format @@ -591,16 +591,16 @@ msgid "Search:" msgstr "Filtre :" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Charger le jeu :" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Charger" @@ -765,7 +765,7 @@ msgid "Special dithering modes supported by some games" msgstr "Mode spécial de tramage supporté par certains jeux" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Plein écran" @@ -1368,12 +1368,12 @@ msgstr "PC-9821 (256 couleurs)" msgid "PC-9801 (16 Colors)" msgstr "PC-9801 (16 couleurs)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Hercules Vert" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Hercules Ambre" @@ -1426,11 +1426,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "Retour au ~L~anceur" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Sauvegarde :" @@ -1439,11 +1443,15 @@ msgstr "Sauvegarde :" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Sauver" @@ -1768,19 +1776,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Normal" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "Activer la correction du rapport d'aspect" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "Désactiver la correction du rapport d'aspect" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Mode graphique actif:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Mode Fenêtre" @@ -2350,15 +2358,23 @@ msgstr "" "Activer le support de la souris. Cela permet d'utiliser la souris pour les " "mouvements et la navigation dans les menus." -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Charger le jeu :" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Charger" @@ -2685,10 +2701,18 @@ msgstr "" "Erreur lors de la sauvegarde dans l'emplacement %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +msgid "Load file" +msgstr "Charger une partie" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Chargement en cours..." +#: engines/parallaction/saveload.cpp:212 +msgid "Save file" +msgstr "Sauver une partie" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Sauvegarde en cours..." @@ -3537,6 +3561,66 @@ msgstr "" "L'exécutable Macintosh de 'Monkey Island' n'a pas été trouvé pour\n" "y lire les instruments. La musique sera désactivée." +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "Utiliser le dialogue de sauvegarde d'origine" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" +"Le bouton Fichiers du jeu ouvre le dialogue de sauvegarde d'origine au lieu " +"d'ouvrir celui de ScummVM" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "Transitions de scènes pixélisées" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "" +"Lors du changement de scène une transition avec des pixels aléatoires est " +"utilisée" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "Ne pas afficher les zones actives lors du déplacement de la souris" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" +"Afficher le nom des zones actives uniquement après avoir cliqué sur la zone " +"ou le bouton d'action" + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "Afficher le portrait des personnages" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "Afficher le portrait des personnages lors des conversations" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "Utiliser une transition pour les dialogues" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "" +"Utiliser une transition pour faire apparaître les dialogues au lieu de les " +"afficher immédiatement" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "Fenêtres transparentes" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "Afficher les fenêtres avec un fond partiellement transparent" + #: engines/sky/compact.cpp:130 msgid "" "Unable to find \"sky.cpt\" file!\n" @@ -3752,9 +3836,6 @@ msgstr "" #~ msgid "Enable Roland GS Mode" #~ msgstr "Activer le mode Roland GS" -#~ msgid "Save game failed!" -#~ msgstr "Échec de la sauvegarde!" - #~ msgctxt "lowres" #~ msgid "Add Game..." #~ msgstr "Ajouter..." diff --git a/po/gl_ES.po b/po/gl_ES.po index 45408c5fc1..22b99fe2a7 100644 --- a/po/gl_ES.po +++ b/po/gl_ES.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.8.0git\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" -"PO-Revision-Date: 2016-02-02 09:10+0100\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" +"PO-Revision-Date: 2016-02-21 00:43+0100\n" "Last-Translator: Santiago G. Sanz <s.sanz@uvigo.es>\n" "Language-Team: Santiago G. Sanz <s.sanz@uvigo.es>\n" "Language: Galego\n" @@ -589,16 +589,16 @@ msgid "Search:" msgstr "Buscar:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Cargar partida:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Cargar" @@ -761,7 +761,7 @@ msgid "Special dithering modes supported by some games" msgstr "Modos de interpolación de cores compatibles con algúns xogos" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Pantalla completa" @@ -1357,12 +1357,12 @@ msgstr "PC-9821 (256 cores)" msgid "PC-9801 (16 Colors)" msgstr "PC-9801 (16 cores)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Hercules verde" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Hercules ámbar" @@ -1413,11 +1413,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "~V~olver ao Iniciador" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Gardar partida:" @@ -1426,11 +1430,15 @@ msgstr "Gardar partida:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Gardar" @@ -1755,19 +1763,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Normal (sen escala)" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "Corrección de proporción activada" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "Corrección de proporción desactivada" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Filtro de gráficos activo:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Modo en ventá" @@ -2334,15 +2342,23 @@ msgstr "" "Activa a compatibilidade co rato. Permite o uso do rato para o movemento e " "os menús do xogo." -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Restaurar xogo:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Restaurar" @@ -2666,10 +2682,18 @@ msgstr "" "Non se pode gardar a partida no espazo %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +msgid "Load file" +msgstr "Cargar ficheiro" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Cargando..." +#: engines/parallaction/saveload.cpp:212 +msgid "Save file" +msgstr "Gardar ficheiro" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Gardando..." @@ -3519,6 +3543,62 @@ msgstr "" "Erro ao buscar o executable de Monkey Island para Macintosh\n" "do que empregar os instrumentos. A música desactivarase." +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "Empregar pantalla orixinal de gardado" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" +"O botón de ficheiros do xogo mostra a pantalla orixinal de gardado no canto " +"do menú de ScummVM." + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "Transicións de escenas pixeladas" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "Ao mudar de escena, mostrase una transición pixelada aleatoria." + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "Non mostrar puntos de acceso ao mover o rato" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" +"Só mostra os nomes dos puntos de acceso despois de premer nun punto de " +"acceso ou un botón de acción." + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "Mostrar retratos de personaxes" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "Mostra os retratos dos personaxes nas conversas." + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "Deslizar pantallas" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "Desliza as pantallas da IU, no canto de mostralas directamente." + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "Ventás transparentes" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "Mostra ventás cun fondo parcialmente transparente." + #: engines/sky/compact.cpp:130 msgid "" "Unable to find \"sky.cpt\" file!\n" @@ -3541,7 +3621,7 @@ msgstr "Intro de disquete" #: engines/sky/detection.cpp:45 msgid "Use the floppy version's intro (CD version only)" -msgstr "Empregar a introdución da versión en disquete (só versión en CD)" +msgstr "Emprega a introdución da versión en disquete (só versión en CD)." #: engines/sword1/animation.cpp:524 #, c-format @@ -3618,7 +3698,7 @@ msgstr "Mostrar etiquetas" #: engines/sword2/sword2.cpp:80 msgid "Show labels for objects on mouse hover" -msgstr "Mostrar as etiquetas dos obxectos ao apuntar co rato" +msgstr "Mostra as etiquetas dos obxectos ao apuntar co rato." #: engines/teenagent/resources.cpp:95 msgid "" diff --git a/po/hu_HU.po b/po/hu_HU.po index 35c4856975..02878f4fbc 100644 --- a/po/hu_HU.po +++ b/po/hu_HU.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.3.0svn\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" -"PO-Revision-Date: 2016-01-27 06:57+0200\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" +"PO-Revision-Date: 2016-02-21 06:24+0200\n" "Last-Translator: George Kormendi <grubycza@hotmail.com>\n" "Language-Team: Hungarian\n" "Language: Magyar\n" @@ -588,16 +588,16 @@ msgid "Search:" msgstr "Keresés:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Játék betöltése:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Betöltés" @@ -761,7 +761,7 @@ msgid "Special dithering modes supported by some games" msgstr "Néhány játék támogatja a speciális árnyalási módokat" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Teljesképernyõs mód:" @@ -1353,12 +1353,12 @@ msgstr "PC-9821 (256 Szín)" msgid "PC-9801 (16 Colors)" msgstr "PC-9801 (16 Szín)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Hercules Zöld" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Hercules Sárga" @@ -1409,11 +1409,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "Visszatérés az indítóba" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Játék mentése:" @@ -1422,11 +1426,15 @@ msgstr "Játék mentése:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Mentés" @@ -1748,19 +1756,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Normál (nincs átméretezés)" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "Méretarány korrekció engedélyezve" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "Méretarány korrekció letiltva" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Aktív grafikus szûrõk:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Ablakos mód" @@ -2324,15 +2332,23 @@ msgstr "" "Egérmód engélyezve. Lehetõvé teszi az egérrel mozgatást játékban és " "játékmenükben." -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Játékmenet visszaállítása:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Visszaállítás" @@ -2655,10 +2671,18 @@ msgstr "" "Játékállás nem menthetõ %i slotba\n" "\n" +#: engines/parallaction/saveload.cpp:197 +msgid "Load file" +msgstr "Fájl betöltése" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Játék betöltés..." +#: engines/parallaction/saveload.cpp:212 +msgid "Save file" +msgstr "Fájl mentése" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Játék mentés..." @@ -3502,6 +3526,63 @@ msgstr "" "Nem található a 'Monkey Island' Macintosh futtató állomány, hogy \n" "beolvassa a hangszereket. Zene le lessz tiltva." +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "Eredeti játékmentés párbeszéd használata" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" +"Fájl gomb a játékban, az eredeti játékmentés párbeszédet jeleníti meg a " +"ScummVM-é helyett" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "Pixeles képátmenetek" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "Helyszínek váltásánál, egy randomizált pixel átmenet történik" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "Aktív pontok nem látszanak egérmozgatás közben" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" +"Aktív pontok neve csak akkor látszik, ha ténylegesen rákattint vagy " +"akciógombot nyom" + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "Karakter képe látható" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "A karakterek képe látható beszélgetés közben" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "Párbeszéd csúsztatás nézet" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "" +"UI párbeszédek csúsztatása ahelyett, hogy egyszerûen megjelenítené azonnal" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "Átlátszó ablakok" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "Ablakok megjelenítése részben átlászó háttérrel" + #: engines/sky/compact.cpp:130 msgid "" "Unable to find \"sky.cpt\" file!\n" @@ -3707,9 +3788,6 @@ msgstr "MPEG videót használ DVD verziónál, a kisebb felbontású AVI helyett" #~ msgid "Enable Roland GS Mode" #~ msgstr "Roland GS Mód engedélyezve" -#~ msgid "Save game failed!" -#~ msgstr "Játék mentése nem sikerült!" - #~ msgctxt "lowres" #~ msgid "Add Game..." #~ msgstr "Játék hozzáadás" diff --git a/po/it_IT.po b/po/it_IT.po index fb40057b41..880c0ca7df 100644 --- a/po/it_IT.po +++ b/po/it_IT.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.3.0svn\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" "PO-Revision-Date: 2014-07-03 17:59-0600\n" "Last-Translator: Matteo 'Maff' Angelino <matteo.maff at gmail dot com>\n" "Language-Team: Italian\n" @@ -590,16 +590,16 @@ msgid "Search:" msgstr "Cerca:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Carica gioco:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Carica" @@ -768,7 +768,7 @@ msgid "Special dithering modes supported by some games" msgstr "Modalità di resa grafica speciali supportate da alcuni giochi" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Modalità a schermo intero" @@ -1369,12 +1369,12 @@ msgstr "" msgid "PC-9801 (16 Colors)" msgstr "" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Hercules verde" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Hercules ambra" @@ -1425,11 +1425,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "~V~ai a elenco giochi" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Salva gioco:" @@ -1438,11 +1442,15 @@ msgstr "Salva gioco:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Salva" @@ -1772,19 +1780,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Normale (no ridim.)" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "Correzione proporzioni attivata" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "Correzione proporzioni disattivata" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Filtro grafico attivo:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Modalità finestra" @@ -2351,15 +2359,23 @@ msgid "" "Enables mouse support. Allows to use mouse for movement and in game menus." msgstr "" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Ripristina gioco:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Ripristina" @@ -2670,10 +2686,20 @@ msgstr "" "Impossibile salvare nella posizione %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +#, fuzzy +msgid "Load file" +msgstr "Carica gioco:" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Caricamento..." +#: engines/parallaction/saveload.cpp:212 +#, fuzzy +msgid "Save file" +msgstr "Salvataggio fallito!" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Salvataggio..." @@ -3526,6 +3552,60 @@ msgid "" "instruments from. Music will be disabled." msgstr "" +#: engines/sherlock/detection.cpp:71 +#, fuzzy +msgid "Use original savegame dialog" +msgstr "Usa schermate di salvataggio originali" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" + +#: engines/sherlock/detection.cpp:101 +#, fuzzy +msgid "Show character portraits" +msgstr "Cambia personaggio" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "" + #: engines/sky/compact.cpp:130 msgid "" "Unable to find \"sky.cpt\" file!\n" @@ -3743,9 +3823,6 @@ msgstr "" #~ msgid "Enable Roland GS Mode" #~ msgstr "Attiva la modalità Roland GS" -#~ msgid "Save game failed!" -#~ msgstr "Salvataggio fallito!" - #~ msgctxt "lowres" #~ msgid "Add Game..." #~ msgstr "Agg. gioco..." diff --git a/po/nb_NO.po b/po/nb_NO.po index 0d778341ae..8f105c6d55 100644 --- a/po/nb_NO.po +++ b/po/nb_NO.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.3.0svn\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" -"PO-Revision-Date: 2014-07-11 00:02+0100\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" +"PO-Revision-Date: 2016-02-25 23:42+0100\n" "Last-Translator: Einar Johan Trøan Sømåen <einarjohants@gmail.com>\n" "Language-Team: somaen <einarjohants@gmail.com>\n" "Language: Norsk (bokmaal)\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SourceCharset: iso-8859-1\n" -"X-Generator: Poedit 1.5.5\n" +"X-Generator: Poedit 1.8.7\n" #: gui/about.cpp:94 #, c-format @@ -75,7 +75,7 @@ msgstr "Velg" #: gui/editrecorddialog.cpp:58 msgid "Author:" -msgstr "" +msgstr "Forfatter:" #: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204 msgid "Name:" @@ -83,24 +83,23 @@ msgstr "Navn:" #: gui/editrecorddialog.cpp:60 msgid "Notes:" -msgstr "" +msgstr "Notater:" #: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74 msgid "Ok" -msgstr "" +msgstr "Ok" #: gui/filebrowser-dialog.cpp:49 msgid "Choose file for loading" -msgstr "" +msgstr "Velg fil for lasting" #: gui/filebrowser-dialog.cpp:49 msgid "Enter filename for saving" -msgstr "" +msgstr "Skriv inn filnavn for lagring" #: gui/filebrowser-dialog.cpp:132 -#, fuzzy msgid "Do you really want to overwrite the file?" -msgstr "Vil du virkelig slette dette lagrede spillet?" +msgstr "Vil du virkelig overskrive denne filen?" #: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217 #: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002 @@ -132,7 +131,7 @@ msgstr "Aktiv" #: gui/fluidsynth-dialog.cpp:72 msgid "Room:" -msgstr "" +msgstr "Rom:" #: gui/fluidsynth-dialog.cpp:79 msgid "Damp:" @@ -592,16 +591,16 @@ msgid "Search:" msgstr "Søk:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Åpne spill:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Åpne" @@ -678,21 +677,19 @@ msgstr "" #: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103 msgid "Stop" -msgstr "" +msgstr "Stopp" #: gui/onscreendialog.cpp:106 msgid "Edit record description" msgstr "" #: gui/onscreendialog.cpp:108 -#, fuzzy msgid "Switch to Game" -msgstr "Bytt" +msgstr "Bytt til Spill" #: gui/onscreendialog.cpp:110 -#, fuzzy msgid "Fast replay" -msgstr "Rask modus" +msgstr "Rask replay" #: gui/options.cpp:85 msgid "Never" @@ -769,7 +766,7 @@ msgid "Special dithering modes supported by some games" msgstr "Spesiel dithering-modus støttet av enkelte spill" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Fullskjermsmodus" @@ -906,6 +903,8 @@ msgid "" "Check if you want to enable patch mappings to emulate an MT-32 on a Roland " "GS device" msgstr "" +"Aktiver hvis du vil slå på patch mappinger for å emulere en MT-32 eller " +"Roland GS enhet" #: gui/options.cpp:898 msgid "Don't use Roland MT-32 music" @@ -1080,20 +1079,19 @@ msgstr "" #. I18N: You must leave "#" as is, only word 'next' is translatable #: gui/predictivedialog.cpp:86 msgid "# next" -msgstr "" +msgstr "# neste" #: gui/predictivedialog.cpp:87 msgid "add" msgstr "" #: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164 -#, fuzzy msgid "Delete char" -msgstr "Slett" +msgstr "" #: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168 msgid "<" -msgstr "" +msgstr "<" #. I18N: Pre means 'Predictive', leave '*' as is #: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572 @@ -1103,12 +1101,12 @@ msgstr "" #. I18N: 'Num' means Numbers #: gui/predictivedialog.cpp:575 msgid "* Num" -msgstr "" +msgstr "* Tall" #. I18N: 'Abc' means Latin alphabet input #: gui/predictivedialog.cpp:578 msgid "* Abc" -msgstr "" +msgstr "* Abc" #: gui/recorderdialog.cpp:64 msgid "Recorder or Playback Gameplay" @@ -1124,33 +1122,30 @@ msgid "Record" msgstr "" #: gui/recorderdialog.cpp:72 -#, fuzzy msgid "Playback" -msgstr "Spill" +msgstr "" #: gui/recorderdialog.cpp:74 msgid "Edit" -msgstr "" +msgstr "Rediger" #: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243 #: gui/recorderdialog.cpp:253 msgid "Author: " -msgstr "" +msgstr "Forfatter: " #: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244 #: gui/recorderdialog.cpp:254 msgid "Notes: " -msgstr "" +msgstr "Notater: " #: gui/recorderdialog.cpp:155 -#, fuzzy msgid "Do you really want to delete this record?" -msgstr "Vil du virkelig slette dette lagrede spillet?" +msgstr "" #: gui/recorderdialog.cpp:174 -#, fuzzy msgid "Unknown Author" -msgstr "Ukjent feil" +msgstr "Ukjent Forfatter" #: gui/saveload-dialog.cpp:167 msgid "List view" @@ -1357,18 +1352,18 @@ msgstr "Hercules Oransje" #: common/rendermode.cpp:42 msgid "PC-9821 (256 Colors)" -msgstr "" +msgstr "PC-9821 (256 Farger)" #: common/rendermode.cpp:43 msgid "PC-9801 (16 Colors)" -msgstr "" +msgstr "PC-9801 (16 Farger)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Hercules Grønn" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Hercules Oransje" @@ -1420,11 +1415,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "~T~ilbake til oppstarter" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Lagret spill:" @@ -1433,11 +1432,15 @@ msgstr "Lagret spill:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Lagre" @@ -1555,7 +1558,7 @@ msgstr "DOSBox OPL emulator" #: audio/fmopl.cpp:67 msgid "ALSA Direct FM" -msgstr "" +msgstr "ALSA Direct FM" #: audio/mididrv.cpp:209 #, c-format @@ -1612,17 +1615,15 @@ msgstr "Apple II GS Emulator (IKKE IMPLEMENTERT)" #: audio/softsynth/cms.cpp:350 msgid "Creative Music System Emulator" -msgstr "" +msgstr "Creative Music System Emulator" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33 -#, fuzzy msgid "FM-Towns Audio" -msgstr "FM Towns Emulator" +msgstr "FM Towns Lyd" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58 -#, fuzzy msgid "PC-98 Audio" -msgstr "Lyd" +msgstr "PC-98 Lyd" #: audio/softsynth/mt32.cpp:200 msgid "Initializing MT-32 Emulator" @@ -1717,34 +1718,33 @@ msgstr "Vil du avslutte?" #. I18N: Trackpad mode toggle status. #: backends/events/webossdl/webossdl-events.cpp:308 -#, fuzzy msgid "Trackpad mode is now" -msgstr "Touchpad-modus deaktivert." +msgstr "Trackpadmodus er nå" #. 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 "" +msgstr "PÅ" #: backends/events/webossdl/webossdl-events.cpp:311 #: backends/events/webossdl/webossdl-events.cpp:338 msgid "OFF" -msgstr "" +msgstr "AV" #: backends/events/webossdl/webossdl-events.cpp:315 msgid "Swipe two fingers to the right to toggle." -msgstr "" +msgstr "Sveip to fingre til høyre for å slå av/på" #. I18N: Auto-drag toggle status. #: backends/events/webossdl/webossdl-events.cpp:335 msgid "Auto-drag mode is now" -msgstr "" +msgstr "Auto-dramodus er nå" #: backends/events/webossdl/webossdl-events.cpp:342 msgid "Swipe three fingers to the right to toggle." -msgstr "" +msgstr "Sveip tre fingre til høyre for å veksle" #: backends/graphics/opengl/opengl-graphics.cpp:119 msgid "OpenGL" @@ -1765,19 +1765,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Normal (ingen skalering)" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "Aspekt-rate korrigering aktivert" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "Aspekt-rate korrigering deaktivert" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Aktivt grafikkfilter:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Vindusmodus" @@ -2039,24 +2039,23 @@ msgstr "Styr Mus" #: backends/platform/tizen/fs.cpp:259 msgid "[ Data ]" -msgstr "" +msgstr "[ Data ]" #: backends/platform/tizen/fs.cpp:263 msgid "[ Resources ]" -msgstr "" +msgstr "[ Ressurser ]" #: backends/platform/tizen/fs.cpp:267 msgid "[ SDCard ]" -msgstr "" +msgstr "[ SDKort ]" #: backends/platform/tizen/fs.cpp:271 msgid "[ Media ]" -msgstr "" +msgstr "[ Media ]" #: backends/platform/tizen/fs.cpp:275 -#, fuzzy msgid "[ Shared ]" -msgstr "Delt Ressurs:" +msgstr "[ Delt ]" #: backends/platform/wii/options.cpp:51 msgid "Video" @@ -2323,35 +2322,44 @@ msgid "Use the original save/load screens, instead of the ScummVM ones" msgstr "Bruk de originale lagre/laste-skjermene, istedenfor ScummVM-variantene" #: engines/agi/detection.cpp:157 -#, fuzzy msgid "Use an alternative palette" -msgstr "Bruk en alternativ intro (Kun for CD-versjon)" +msgstr "Bruk en alternativ palett" #: engines/agi/detection.cpp:158 msgid "" "Use an alternative palette, common for all Amiga games. This was the old " "behavior" msgstr "" +"Bruk en alternativ palett, fells for alle Amigaspill. Dette var den gamle " +"oppførselen" #: engines/agi/detection.cpp:167 -#, fuzzy msgid "Mouse support" -msgstr "Hopp over" +msgstr "Musstøtte" #: engines/agi/detection.cpp:168 msgid "" "Enables mouse support. Allows to use mouse for movement and in game menus." msgstr "" +"Aktiver musstøtte. Tillater å bruke mus for bevegelse og i spillmenyer." -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Gjennopprett spill:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Gjenopprett" @@ -2394,13 +2402,12 @@ msgid "Cutscene file '%s' not found!" msgstr "Fant ikke cutscenefil '%s'!" #: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101 -#, fuzzy msgid "Color Blind Mode" -msgstr "Klikkmodus" +msgstr "Fargeblindmodus" #: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102 msgid "Enable Color Blind Mode by default" -msgstr "" +msgstr "Aktiver fargeblindmodus som standard" #: engines/drascula/saveload.cpp:47 msgid "" @@ -2456,11 +2463,11 @@ msgstr "Klarte ikke å lagre spill." #: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86 msgid "Gore Mode" -msgstr "" +msgstr "Gørrmodus" #: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87 msgid "Enable Gore Mode when available" -msgstr "" +msgstr "Aktiver gørrmodus når tilgjengelig" #. I18N: Studio audience adds an applause and cheering sounds whenever #. Malcolm makes a joke. @@ -2474,9 +2481,8 @@ msgstr "Aktiver studiopublikum" #. I18N: This option allows the user to skip text and cutscenes. #: engines/kyra/detection.cpp:73 -#, fuzzy msgid "Skip support" -msgstr "Hopp over" +msgstr "Hopp over-støtte" #: engines/kyra/detection.cpp:74 msgid "Allow text and cutscenes to be skipped" @@ -2593,6 +2599,12 @@ msgid "" "Do you wish to use this save game file with ScummVM?\n" "\n" msgstr "" +"Det følgende originale lagrede spillet ble funnet i spillstien din:\n" +"\n" +"%s %s\n" +"\n" +"Vil du bruke dette lagrede spillet med ScummVM?\n" +"\n" #: engines/kyra/saveload_eob.cpp:590 #, c-format @@ -2600,6 +2612,8 @@ msgid "" "A save game file was found in the specified slot %d. Overwrite?\n" "\n" msgstr "" +"Et lagret spill ble funnet i den valgte posisjonen %d. Overskrive?\n" +"\n" #: engines/kyra/saveload_eob.cpp:623 #, c-format @@ -2611,6 +2625,10 @@ msgid "" "'import_savefile'.\n" "\n" msgstr "" +"%d originale lagrede spill har blitt importert vellykket til ScummVM.\n" +"Hvis du vil importere flere originale lagrede spill senere, må du åpne\n" +"ScummVM debugkonsollen og bruke kommandoen «import_savefile»\n" +"\n" #. I18N: Option for fast scene switching #: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167 @@ -2663,10 +2681,18 @@ msgstr "" "Kan ikke lagre spilltilstand i posisjon %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +msgid "Load file" +msgstr "Last fil" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Laster spill..." +#: engines/parallaction/saveload.cpp:212 +msgid "Save file" +msgstr "Lagre fil" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Lagrer spill..." @@ -2750,21 +2776,19 @@ msgstr "Bruk en alternativ intro (Kun for CD-versjon)" #: engines/sci/detection.cpp:374 msgid "Skip EGA dithering pass (full color backgrounds)" -msgstr "" +msgstr "Hopp over EGA dithering (fullfarge bakgrunner)" #: engines/sci/detection.cpp:375 msgid "Skip dithering pass in EGA games, graphics are shown with full colors" msgstr "" #: engines/sci/detection.cpp:384 -#, fuzzy msgid "Enable high resolution graphics" -msgstr "Aktiver hit point-bar grafer" +msgstr "Aktiver høyoppløselig grafikk" #: engines/sci/detection.cpp:385 -#, fuzzy msgid "Enable high resolution graphics/content" -msgstr "Aktiver hit point-bar grafer" +msgstr "Aktiver høyoppløselig grafikk/innhold" #: engines/sci/detection.cpp:394 msgid "Prefer digital sound effects" @@ -2836,15 +2860,13 @@ msgstr "Spill pauset. Trykk på MELLOMROMstasten for å fortsette." #. "Moechten Sie wirklich neu starten? (J/N)J" #. Will react to J as 'Yes' #: engines/scumm/dialogs.cpp:183 -#, fuzzy msgid "Are you sure you want to restart? (Y/N)Y" -msgstr "Er du sikker på at du vil avslutte? (Y/N)" +msgstr "Er du sikker på at du vil starte på nytt? (J/N)J" #. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment #: engines/scumm/dialogs.cpp:185 -#, fuzzy msgid "Are you sure you want to quit? (Y/N)Y" -msgstr "Er du sikker på at du vil avslutte? (Y/N)" +msgstr "Er du sikker på at du vil avslutte? (J/N)J" #: engines/scumm/dialogs.cpp:190 msgid "Play" @@ -3357,19 +3379,19 @@ msgstr "" #: engines/scumm/help.cpp:293 msgid "Toggle Keyboard/Mouse Fighting (*)" -msgstr "" +msgstr "Velg Tastatur/Mus-slåssing (*)" #: engines/scumm/help.cpp:295 msgid "* Keyboard Fighting is always on," -msgstr "" +msgstr "* Tastaturslåssing er alltid på," #: engines/scumm/help.cpp:296 msgid " so despite the in-game message this" -msgstr "" +msgstr " så til tross for beskjeden i spillet, vil" #: engines/scumm/help.cpp:297 msgid " actually toggles Mouse Fighting Off/On" -msgstr "" +msgstr " dette faktisk slå musslåssing av/på" #: engines/scumm/help.cpp:304 msgid "Fighting controls (numpad):" @@ -3465,23 +3487,20 @@ msgid "Fly to lower right" msgstr "Fly til nedre høyre" #: engines/scumm/input.cpp:580 -#, fuzzy msgid "Snap scroll on" -msgstr "Myk scrolling" +msgstr "" #: engines/scumm/input.cpp:582 msgid "Snap scroll off" msgstr "" #: engines/scumm/input.cpp:595 -#, fuzzy msgid "Music volume: " -msgstr "Musikkvolum:" +msgstr "Musikkvolum: " #: engines/scumm/input.cpp:612 -#, fuzzy msgid "Subtitle speed: " -msgstr "Teksthastighet:" +msgstr "Teksthastighet: " #: engines/scumm/scumm.cpp:1832 #, c-format @@ -3493,27 +3512,86 @@ msgstr "" "men %s mangler. Bruker AdLib istedet." #: engines/scumm/scumm.cpp:2644 -#, fuzzy 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 "" -"Vanligvis, ville Maniac Mansion ha startet nå. Men ScummVM støtter ikke det " -"ennå. Så, for å spille Maniac Mansion, gå til 'Legg til spill' i ScummVM-" -"hovedmenyen og velg 'Maniac'-undermappa i Tentacle-mappa." +"Vanligvis, ville Maniac Mansion ha startet nå. Men for at det skal fungere " +"må Maniac Mansion-filene ligge i «Maniac» mappa inni Tentacle-spillmappa, og " +"spillet må være lagt til i ScummVM." #: 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 "" +"Kunne ikke finne Macintosh binærfila «Loom» for å lese instrumenter\n" +"fra den. Musikk vil bli deaktivert." #: 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 "" +"Kunne ikke finne Macintosh-binærfila «Monkey Island» for å lese\n" +"instrumenter fra den. Musikk vil bli deaktivert." + +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "Bruk original lagringsdialog" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" +"«Files»-knappen i spillet viser original lagre/laste-dialog istedenfor " +"ScummVM menyen" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "Pikselerte sceneoverganger" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "Under scenskifter vil en tilfeldig pikselovergang bli gjort" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "Ikke vis hotspots når du beveger musa" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" +"Vis hotspots først etter at du faktisk har klikket på en hotspot eller " +"handlingsknapp" + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "Vis karakterportretter" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "Vis portretter for karakterene når de snakker sammen" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "Gjennomsiktige vinduer" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "Vis vinduer med en delvis gjennomsiktig bakgrunn" #: engines/sky/compact.cpp:130 msgid "" @@ -3625,52 +3703,52 @@ msgstr "" #: engines/wintermute/detection.cpp:58 msgid "Show FPS-counter" -msgstr "" +msgstr "Vis FPS-teller" #: engines/wintermute/detection.cpp:59 msgid "Show the current number of frames per second in the upper left corner" msgstr "" +"Vis det gjeldende antall bilder per sekund (FPS) i øvre venstre hjørne av " +"skjermen" #: engines/zvision/detection_tables.h:52 -#, fuzzy msgid "Use the original save/load screens instead of the ScummVM interface" -msgstr "Bruk de originale lagre/laste-skjermene, istedenfor ScummVM-variantene" +msgstr "" +"Bruk de originale lagre/laste-skjermene istedenfor ScummVM-grensesnittet" #: engines/zvision/detection_tables.h:61 msgid "Double FPS" -msgstr "" +msgstr "Dobbel FPS" #: engines/zvision/detection_tables.h:62 msgid "Increase framerate from 30 to 60 FPS" -msgstr "" +msgstr "Øk bilderate fra 30 til 60 FPS" #: engines/zvision/detection_tables.h:71 -#, fuzzy msgid "Enable Venus" -msgstr "Aktiver helium-modus" +msgstr "Aktiver Venus" #: engines/zvision/detection_tables.h:72 -#, fuzzy msgid "Enable the Venus help system" -msgstr "Aktiver helium-modus" +msgstr "Aktiver Venus hjelpesystemet" #: engines/zvision/detection_tables.h:81 msgid "Disable animation while turning" -msgstr "" +msgstr "Deaktiver animasjoner under snuing" #: engines/zvision/detection_tables.h:82 msgid "Disable animation while turning in panorama mode" -msgstr "" +msgstr "Deaktiver animasjoner under snuing i panoramamodus" #: engines/zvision/detection_tables.h:91 msgid "Use high resolution MPEG video" -msgstr "" +msgstr "Bruk høyoppløst MPEG-video" #: engines/zvision/detection_tables.h:92 -#, fuzzy msgid "Use MPEG video from the DVD version, instead of lower resolution AVI" msgstr "" -"Bruk det alternative settet med sølvmuspekere, istedenfor de normale gylne." +"Bruk MPEG-video fra DVD-versjonen istedenfor AVI-versjonen med lavere " +"oppløsning" #~ msgid "EGA undithering" #~ msgstr "EGA av-dithering" @@ -3719,9 +3797,6 @@ msgstr "" #~ msgid "Enable Roland GS Mode" #~ msgstr "Aktiver Roland GS-modus" -#~ msgid "Save game failed!" -#~ msgstr "Lagret spill:" - #~ msgctxt "lowres" #~ msgid "Add Game..." #~ msgstr "Legg til spill..." diff --git a/po/nl_NL.po b/po/nl_NL.po index 42becb84a6..99d1400b04 100644 --- a/po/nl_NL.po +++ b/po/nl_NL.po @@ -7,15 +7,15 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.8.0git\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" -"PO-Revision-Date: 2016-02-02 12:05+0100\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" +"PO-Revision-Date: 2016-02-21 13:05+0100\n" "Last-Translator: Ben Castricum <scummvm@bencastricum.nl>\n" "Language-Team: Ben Castricum <scummvm@bencastricum.nl>\n" "Language: Nederlands\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.6.10\n" +"X-Generator: Poedit 1.8.7\n" "X-Poedit-SourceCharset: iso-8859-1\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -594,16 +594,16 @@ msgid "Search:" msgstr "Zoeken:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Laad spel:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Laden" @@ -772,7 +772,7 @@ msgid "Special dithering modes supported by some games" msgstr "Speciale ditheringmodi die door sommige games ondersteund worden." #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Volledig-scherm modus" @@ -1370,12 +1370,12 @@ msgstr "PC-9821 (256 Kleuren)" msgid "PC-9801 (16 Colors)" msgstr "PC-9801 (16 Kleuren)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Hercules Groen" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Hercules Amber" @@ -1427,11 +1427,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "S~t~artmenu" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Spel opslaan:" @@ -1440,11 +1444,15 @@ msgstr "Spel opslaan:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Opslaan" @@ -1772,19 +1780,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Normaal (niet schalen)" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "Pixelverhoudingcorrectie ingeschakeld" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "Pixelverhoudingcorrectie uitgeschakeld" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Actieve grafische filter:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Venstermodus" @@ -1994,7 +2002,7 @@ msgstr "Meerdere Functies" #: backends/platform/symbian/src/SymbianActions.cpp:48 msgid "Swap character" -msgstr "Verwissel karakter" +msgstr "Verwissel personage" #: backends/platform/symbian/src/SymbianActions.cpp:49 msgid "Skip text" @@ -2353,15 +2361,23 @@ msgstr "" "Zet muis ondersteuning aan. Maakt het mogelijk om de muis te gebruiken voor " "bewegen en in spelmenus." -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Laad opgeslagen spel:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Laad" @@ -2686,10 +2702,18 @@ msgstr "" "Spel opslaan in slot %i mislukt\n" "\n" +#: engines/parallaction/saveload.cpp:197 +msgid "Load file" +msgstr "Laad bestand" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Spel laden..." +#: engines/parallaction/saveload.cpp:212 +msgid "Save file" +msgstr "Bestand opslaan" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Spel opslaan..." @@ -3366,7 +3390,7 @@ msgstr "Rechter middelste voorwerp" #: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285 msgid "Switching characters:" -msgstr "Verwissel karakters:" +msgstr "Verwissel personages:" #: engines/scumm/help.cpp:282 msgid "Second kid" @@ -3540,6 +3564,63 @@ msgstr "" "De 'Monkey Island' Macintosh executable is niet gevonden om de instrumenten " "van te laden. Muziek wordt uitgeschakeld." +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "Gebruik originele spel-opslaan schermen" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" +"In-game knop Files toont originele spel opslaan dialoogvenster in plaats van " +"het ScummVM menu" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "Pixellated scèneovergangen" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "" +"Bij scene wijzigingen wordt er een willekeurig pixel transitie gebruikt" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "Toon geen hotspots als de muis beweegt" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" +"Toon alleen hotspots wanneer er daadwerkelijk op hotspot of actieknop " +"geklikt word" + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "Toon personage portretfoto's" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "Toon portretten van de personages bij het converseren" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "Schuif dialoogvensters in beeld" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "Schuif dialoogvensters in beeld, in plaats van onmiddellijk tonen" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "Transparante vensters" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "Toon vensters met een gedeeltelijk transparante achtergrond" + #: engines/sky/compact.cpp:130 msgid "" "Unable to find \"sky.cpt\" file!\n" diff --git a/po/nn_NO.po b/po/nn_NO.po index b8cdd24cce..62f7c07beb 100644 --- a/po/nn_NO.po +++ b/po/nn_NO.po @@ -7,9 +7,9 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.3.0svn\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" -"PO-Revision-Date: 2014-07-11 00:04+0100\n" -"Last-Translator: Einar Johan Trøan Sømåen <einarjohants@gmail.com>\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" +"PO-Revision-Date: 2016-02-26 00:37+0100\n" +"Last-Translator: Einar Johan Trøan SømÃ¥en <einarjohants@gmail.com>\n" "Language-Team: somaen <einarjohants@gmail.com>\n" "Language: Norsk (nynorsk)\n" "MIME-Version: 1.0\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-SourceCharset: iso-8859-1\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 1.5.5\n" +"X-Generator: Poedit 1.8.7\n" #: gui/about.cpp:94 #, c-format @@ -75,7 +75,7 @@ msgstr "Vel" #: gui/editrecorddialog.cpp:58 msgid "Author:" -msgstr "" +msgstr "Forfattar:" #: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204 msgid "Name:" @@ -83,24 +83,23 @@ msgstr "Namn:" #: gui/editrecorddialog.cpp:60 msgid "Notes:" -msgstr "" +msgstr "Notatar:" #: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74 msgid "Ok" -msgstr "" +msgstr "Ok" #: gui/filebrowser-dialog.cpp:49 msgid "Choose file for loading" -msgstr "" +msgstr "Vel fil for lasting" #: gui/filebrowser-dialog.cpp:49 msgid "Enter filename for saving" -msgstr "" +msgstr "Skriv inn filnamn for lagring" #: gui/filebrowser-dialog.cpp:132 -#, fuzzy msgid "Do you really want to overwrite the file?" -msgstr "Vil du verkeleg slette det lagra spelet?" +msgstr "Vil du verkeleg overskrive fila?" #: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217 #: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002 @@ -132,7 +131,7 @@ msgstr "Aktiv" #: gui/fluidsynth-dialog.cpp:72 msgid "Room:" -msgstr "" +msgstr "Rom:" #: gui/fluidsynth-dialog.cpp:79 msgid "Damp:" @@ -226,10 +225,10 @@ msgid "OK" msgstr "OK" #: gui/fluidsynth-dialog.cpp:217 -#, fuzzy msgid "" "Do you really want to reset all FluidSynth settings to their default values?" -msgstr "Vil du verkeleg slette det lagra spelet?" +msgstr "" +"Vil du verkeleg sette alle FluidSynth-innstillingar til standardverdiar?" #: gui/gui-manager.cpp:119 backends/keymapper/remap-dialog.cpp:53 #: engines/scumm/help.cpp:126 engines/scumm/help.cpp:141 @@ -447,7 +446,7 @@ msgstr "Ekstrasti:" #: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333 msgid "Specifies path to additional data used by the game" -msgstr "" +msgstr "Veljer sti til tilleggsdata nytta av spelet" #: gui/launcher.cpp:332 gui/options.cpp:1150 msgctxt "lowres" @@ -461,7 +460,7 @@ msgstr "Lagringssti:" #: 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 "" +msgstr "Veljer kor lagra spel vert lagra" #: gui/launcher.cpp:341 gui/options.cpp:1134 msgctxt "lowres" @@ -493,9 +492,8 @@ msgid "Select directory with game data" msgstr "Vel mappe med speldata" #: gui/launcher.cpp:547 -#, fuzzy msgid "Select additional game directory" -msgstr "Vel mappe med speldata" +msgstr "Vel mappe med tileggsdata for spelet" #: gui/launcher.cpp:559 gui/options.cpp:1377 msgid "Select directory for saved games" @@ -503,7 +501,7 @@ msgstr "Vel mappe for lagra spel" #: gui/launcher.cpp:586 msgid "This game ID is already taken. Please choose another one." -msgstr "" +msgstr "Denne spel-IDen er allerede teken. Vær vennleg og vel ein anna." #: gui/launcher.cpp:626 engines/dialogs.cpp:111 msgid "~Q~uit" @@ -567,7 +565,7 @@ msgstr "~F~jern spel" #: gui/launcher.cpp:642 gui/launcher.cpp:649 msgid "Remove game from the list. The game data files stay intact" -msgstr "" +msgstr "Fjern spel frå lista. Speldataene forblir intakte" #: gui/launcher.cpp:645 msgctxt "lowres" @@ -593,16 +591,16 @@ msgid "Search:" msgstr "Søk:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Åpne spel:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Åpne" @@ -670,27 +668,26 @@ msgid "Scanned %d directories ..." msgstr "Søkt i %d mappar ..." #: gui/massadd.cpp:269 -#, fuzzy, c-format +#, c-format msgid "Discovered %d new games, ignored %d previously added games ..." -msgstr "Oppdaga %d nye spel ..." +msgstr "" +"Oppdaga %d nye spel, ignorerte %d spel som har vorte lagt til tidlegare..." #: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103 msgid "Stop" -msgstr "" +msgstr "Stopp" #: gui/onscreendialog.cpp:106 msgid "Edit record description" msgstr "" #: gui/onscreendialog.cpp:108 -#, fuzzy msgid "Switch to Game" -msgstr "Bytt" +msgstr "Bytt til spel" #: gui/onscreendialog.cpp:110 -#, fuzzy msgid "Fast replay" -msgstr "Rask modus" +msgstr "" #: gui/options.cpp:85 msgid "Never" @@ -740,7 +737,7 @@ msgstr "Ingen" #: gui/options.cpp:389 msgid "Failed to apply some of the graphic options changes:" -msgstr "" +msgstr "Klarte ikkje å aktivere nokre av grafikkvalendringane:" #: gui/options.cpp:401 msgid "the video mode could not be changed." @@ -752,7 +749,7 @@ msgstr "Fullskjerminstillinga kunne ikkje endrast" #: gui/options.cpp:413 msgid "the aspect ratio setting could not be changed" -msgstr "" +msgstr "aspektrate-innstillinga kunne ikkje endrast" #: gui/options.cpp:732 msgid "Graphics mode:" @@ -767,7 +764,7 @@ msgid "Special dithering modes supported by some games" msgstr "Spesielle dithering-modus som støttast av nokre spel" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Fullskjermsmodus" @@ -796,16 +793,14 @@ msgid "Specifies output sound device or sound card emulator" msgstr "" #: gui/options.cpp:771 -#, fuzzy msgctxt "lowres" msgid "Preferred Dev.:" -msgstr "Føretrukken eining:" +msgstr "" #: gui/options.cpp:771 -#, fuzzy msgctxt "lowres" msgid "Music Device:" -msgstr "Ingen musikk" +msgstr "Musikkeining:" #: gui/options.cpp:798 msgid "AdLib emulator:" @@ -833,7 +828,7 @@ msgstr "GM Eining:" #: gui/options.cpp:820 msgid "Specifies default sound device for General MIDI output" -msgstr "" +msgstr "Veljer standard lydeining for General MIDI avspeling" #: gui/options.cpp:831 msgid "Don't use General MIDI music" @@ -878,7 +873,7 @@ msgstr "MT-32 Eining:" #: gui/options.cpp:879 msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output" -msgstr "" +msgstr "Veljer standard lydeining for Roland MT-32/LAPC1/CM32l/CM64 avspeling" #: gui/options.cpp:884 msgid "True Roland MT-32 (disable GM emulation)" @@ -889,6 +884,8 @@ msgid "" "Check if you want to use your real hardware Roland-compatible sound device " "connected to your computer" msgstr "" +"Vel om du vil nytte din Roland-kompatible lydeining som du har tilkopla " +"datamaskina di." #: gui/options.cpp:886 msgctxt "lowres" @@ -896,9 +893,8 @@ msgid "True Roland MT-32 (no GM emulation)" msgstr "Ekte Roland MT-32 (ingen GS-emulering)" #: gui/options.cpp:889 -#, fuzzy msgid "Roland GS Device (enable MT-32 mappings)" -msgstr "Ekte Roland MT-32 (deaktiver GM-emulering)" +msgstr "" #: gui/options.cpp:889 msgid "" @@ -976,7 +972,7 @@ msgstr "Lydeffektvolum:" #: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974 msgid "Special sound effects volume" -msgstr "" +msgstr "Spesiallydeffekt volum" #: gui/options.cpp:973 msgctxt "lowres" @@ -1079,20 +1075,19 @@ msgstr "" #. I18N: You must leave "#" as is, only word 'next' is translatable #: gui/predictivedialog.cpp:86 msgid "# next" -msgstr "" +msgstr "# neste" #: gui/predictivedialog.cpp:87 msgid "add" msgstr "" #: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164 -#, fuzzy msgid "Delete char" -msgstr "Slett" +msgstr "" #: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168 msgid "<" -msgstr "" +msgstr "<" #. I18N: Pre means 'Predictive', leave '*' as is #: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572 @@ -1102,12 +1097,12 @@ msgstr "" #. I18N: 'Num' means Numbers #: gui/predictivedialog.cpp:575 msgid "* Num" -msgstr "" +msgstr "* Tal" #. I18N: 'Abc' means Latin alphabet input #: gui/predictivedialog.cpp:578 msgid "* Abc" -msgstr "" +msgstr "* Abc" #: gui/recorderdialog.cpp:64 msgid "Recorder or Playback Gameplay" @@ -1123,33 +1118,30 @@ msgid "Record" msgstr "" #: gui/recorderdialog.cpp:72 -#, fuzzy msgid "Playback" -msgstr "Spel" +msgstr "" #: gui/recorderdialog.cpp:74 msgid "Edit" -msgstr "" +msgstr "Rediger" #: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243 #: gui/recorderdialog.cpp:253 msgid "Author: " -msgstr "" +msgstr "Forfattar: " #: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244 #: gui/recorderdialog.cpp:254 msgid "Notes: " -msgstr "" +msgstr "Notatar: " #: gui/recorderdialog.cpp:155 -#, fuzzy msgid "Do you really want to delete this record?" -msgstr "Vil du verkeleg slette det lagra spelet?" +msgstr "" #: gui/recorderdialog.cpp:174 -#, fuzzy msgid "Unknown Author" -msgstr "Ukjend feil" +msgstr "Ukjend Forfattar" #: gui/saveload-dialog.cpp:167 msgid "List view" @@ -1339,7 +1331,7 @@ msgstr "Spelmotor-plugin støttar ikkje lagra tilstandar." #: common/error.cpp:71 msgid "User canceled" -msgstr "" +msgstr "Brukar avbraut" #: common/error.cpp:75 msgid "Unknown error" @@ -1356,18 +1348,18 @@ msgstr "Hercules Raudgul" #: common/rendermode.cpp:42 msgid "PC-9821 (256 Colors)" -msgstr "" +msgstr "PC-9821 (256 Fargar)" #: common/rendermode.cpp:43 msgid "PC-9801 (16 Colors)" -msgstr "" +msgstr "PC-9801 (16 Fargar)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Hercules Grønn" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Hercules Raudgul" @@ -1419,11 +1411,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "Tilbake til Oppsta~r~tar" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Lagra spel:" @@ -1432,11 +1428,15 @@ msgstr "Lagra spel:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Lagre" @@ -1446,6 +1446,9 @@ msgid "" "the README for basic information, and for instructions on how to obtain " "further assistance." msgstr "" +"Orsak, men denne spelmotoren støtter for augeblikket ikkje hjelp i spelet. " +"Vennlegst se i README-fila for grunnlegjande informasjon, og for " +"instruksjonar om korleis du kan få ytterlegare hjelp." #: engines/dialogs.cpp:234 engines/pegasus/pegasus.cpp:393 #, c-format @@ -1453,6 +1456,9 @@ msgid "" "Gamestate save failed (%s)! Please consult the README for basic information, " "and for instructions on how to obtain further assistance." msgstr "" +"Speltilstandslagring feila (%s)!. Vennligst sjå i README-fila for " +"grunnlegjande informasjon, og for instruskjonar om korleis du kan få " +"ytterlegare hjelp." #: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109 #: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106 @@ -1470,20 +1476,19 @@ msgstr "~T~astar" #: engines/engine.cpp:339 msgid "Could not initialize color format." -msgstr "" +msgstr "Høgkvalitetslyd (treigare) (omstart)" #: engines/engine.cpp:347 msgid "Could not switch to video mode: '" msgstr "Kunne ikkje veksle til videomodus: '" #: engines/engine.cpp:356 -#, fuzzy msgid "Could not apply aspect ratio setting." -msgstr "Veksle aspekt-korrigering" +msgstr "Kunne ikkje slå på aspekt-korrigering" #: engines/engine.cpp:361 msgid "Could not apply fullscreen setting." -msgstr "" +msgstr "Kunne ikkje aktiver fullskjermsinnstilling." #: engines/engine.cpp:461 msgid "" @@ -1493,6 +1498,11 @@ msgid "" "the data files to your hard disk instead.\n" "See the README file for details." msgstr "" +"Det ser ut til at du speler dette spelet rett frå\n" +"CD. Dette er kjend for å skape problemar,\n" +"og det er derfor tilråda at du kopierar\n" +"datafilane til harddisken din istaden. \n" +"Sjå README-fila for detaljar." #: engines/engine.cpp:472 msgid "" @@ -1509,6 +1519,9 @@ msgid "" "Gamestate load failed (%s)! Please consult the README for basic information, " "and for instructions on how to obtain further assistance." msgstr "" +"Speltilstandslasting feila (%s)!. Vennligst sjå i README-fila for " +"grunnlegjande informasjon, og for instruskjonar om korleis du kan få " +"ytterlegare hjelp." #: engines/engine.cpp:543 msgid "" @@ -1538,7 +1551,7 @@ msgstr "DOSBox OPL emulator" #: audio/fmopl.cpp:67 msgid "ALSA Direct FM" -msgstr "" +msgstr "ALSA Direct FM" #: audio/mididrv.cpp:209 #, c-format @@ -1546,11 +1559,13 @@ msgid "" "The selected audio device '%s' was not found (e.g. might be turned off or " "disconnected)." msgstr "" +"Den valde lydeininga '%s' vart ikkje funne (t.d. kan den vere avslått eller " +"fråkopla)" #: 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 "" +msgstr "Prøver å nytte den neste tilgjengelege eininga..." #: audio/mididrv.cpp:221 #, c-format @@ -1558,6 +1573,8 @@ msgid "" "The selected audio device '%s' cannot be used. See log file for more " "information." msgstr "" +"Den foretrukne lydeininga '%s' kan ikkje nyttast. Sjå loggfila for meir " +"informasjon." #: audio/mididrv.cpp:257 #, c-format @@ -1565,6 +1582,8 @@ msgid "" "The preferred audio device '%s' was not found (e.g. might be turned off or " "disconnected)." msgstr "" +"Den foretrukne lydeininga '%s' vart ikkje funne (t.d. kan den vere avslått " +"eller fråkopla)" #: audio/mididrv.cpp:272 #, c-format @@ -1572,6 +1591,8 @@ msgid "" "The preferred audio device '%s' cannot be used. See log file for more " "information." msgstr "" +"Den foretrukne lydeininga '%s' kan ikkje nyttast. Sjå loggfila for meir " +"informasjon." #: audio/mods/paula.cpp:196 msgid "Amiga Audio Emulator" @@ -1587,22 +1608,19 @@ msgstr "Apple II GS Emulator (IKKJE IMPLEMENTERT)" #: audio/softsynth/cms.cpp:350 msgid "Creative Music System Emulator" -msgstr "" +msgstr "Creative Music System Emulator" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33 -#, fuzzy msgid "FM-Towns Audio" -msgstr "FM Towns Emulator" +msgstr "FM-Towns Lyd" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58 -#, fuzzy msgid "PC-98 Audio" -msgstr "Lyd" +msgstr "PC-98 Lyd" #: audio/softsynth/mt32.cpp:200 -#, fuzzy msgid "Initializing MT-32 Emulator" -msgstr "MT-32 Emulator" +msgstr "Initialiserar MT-32 Emulator" #: audio/softsynth/mt32.cpp:426 msgid "MT-32 Emulator" @@ -1644,16 +1662,14 @@ msgstr "Avslutt" #: backends/events/gph/gph-events.cpp:385 #: backends/events/gph/gph-events.cpp:428 #: backends/events/openpandora/op-events.cpp:168 -#, fuzzy msgid "Touchscreen 'Tap Mode' - Left Click" -msgstr "Tap for venstre-klikk, dobbelt-tap for høgre-klikk" +msgstr "Touchscreen 'Tap Mode' - Venstreklikk" #: backends/events/gph/gph-events.cpp:387 #: backends/events/gph/gph-events.cpp:430 #: backends/events/openpandora/op-events.cpp:170 -#, fuzzy msgid "Touchscreen 'Tap Mode' - Right Click" -msgstr "Tap for venstre-klikk, dobbelt-tap for høgre-klikk" +msgstr "Touchscreen 'Tap Mode' - Høgreklikk" #: backends/events/gph/gph-events.cpp:389 #: backends/events/gph/gph-events.cpp:432 @@ -1666,24 +1682,20 @@ msgid "Maximum Volume" msgstr "Maks Volum" #: backends/events/gph/gph-events.cpp:411 -#, fuzzy msgid "Increasing Volume" -msgstr "Volum" +msgstr "Auker Volum" #: backends/events/gph/gph-events.cpp:417 -#, fuzzy msgid "Minimal Volume" -msgstr "Volum" +msgstr "Minste Volum" #: backends/events/gph/gph-events.cpp:419 -#, fuzzy msgid "Decreasing Volume" -msgstr "Volum" +msgstr "Senkar Volum" #: backends/events/maemosdl/maemosdl-events.cpp:180 -#, fuzzy msgid "Clicking Enabled" -msgstr "~O~vergangar aktivert" +msgstr "Klikking aktivert" #: backends/events/maemosdl/maemosdl-events.cpp:180 msgid "Clicking Disabled" @@ -1699,21 +1711,20 @@ msgstr "Vil du avslutte?" #. I18N: Trackpad mode toggle status. #: backends/events/webossdl/webossdl-events.cpp:308 -#, fuzzy msgid "Trackpad mode is now" -msgstr "Deaktivert GFX" +msgstr "Trackpadmodus er no" #. 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 "" +msgstr "PÅ" #: backends/events/webossdl/webossdl-events.cpp:311 #: backends/events/webossdl/webossdl-events.cpp:338 msgid "OFF" -msgstr "" +msgstr "AV" #: backends/events/webossdl/webossdl-events.cpp:315 msgid "Swipe two fingers to the right to toggle." @@ -1726,7 +1737,7 @@ msgstr "" #: backends/events/webossdl/webossdl-events.cpp:342 msgid "Swipe three fingers to the right to toggle." -msgstr "" +msgstr "Sveip tre fingre til høgre for å veksle" #: backends/graphics/opengl/opengl-graphics.cpp:119 msgid "OpenGL" @@ -1747,21 +1758,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Normal (ikkje skaler)" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 -#, fuzzy +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" -msgstr "Aspekt-korrigering" +msgstr "Aspekt-korrigering aktivert" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 -#, fuzzy +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" -msgstr "Aspekt-korrigering" +msgstr "Aspekt-korrigering ikkje aktivert" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Aktivt grafikkfilter:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Vindusmodus" @@ -1770,9 +1779,8 @@ msgid "Keymap:" msgstr "Tastkopling:" #: backends/keymapper/remap-dialog.cpp:67 -#, fuzzy msgid " (Effective)" -msgstr " (Aktivt)" +msgstr "" #: backends/keymapper/remap-dialog.cpp:107 msgid " (Active)" @@ -1886,16 +1894,14 @@ msgstr "" #: backends/platform/ios7/ios7_osys_events.cpp:322 #: backends/platform/ios7/ios7_osys_events.cpp:540 #: backends/platform/iphone/osys_events.cpp:313 -#, fuzzy msgid "Touchpad mode enabled." -msgstr "~O~vergangar aktivert" +msgstr "Touchpadmodus påslått." #: backends/platform/ios7/ios7_osys_events.cpp:324 #: backends/platform/ios7/ios7_osys_events.cpp:542 #: backends/platform/iphone/osys_events.cpp:315 -#, fuzzy msgid "Touchpad mode disabled." -msgstr "Deaktivert GFX" +msgstr "Touchpadmodus avslått." #: backends/platform/maemo/maemo.cpp:208 msgid "Click Mode" @@ -1970,16 +1976,15 @@ msgstr "Sone" #: backends/platform/wince/CEActionsPocket.cpp:54 #: backends/platform/wince/CEActionsSmartphone.cpp:48 msgid "Multi Function" -msgstr "" +msgstr "Multifunksjon" #: backends/platform/symbian/src/SymbianActions.cpp:48 msgid "Swap character" -msgstr "" +msgstr "Bytt karakter" #: backends/platform/symbian/src/SymbianActions.cpp:49 -#, fuzzy msgid "Skip text" -msgstr "Hopp over tekstlinje" +msgstr "Hopp over tekst" #: backends/platform/symbian/src/SymbianActions.cpp:51 msgid "Fast mode" @@ -2002,14 +2007,12 @@ msgid "Key mapper" msgstr "Tastkopler" #: backends/platform/tizen/form.cpp:263 -#, fuzzy msgid "Right Click Once" -msgstr "Høgreklikk" +msgstr "Høgreklikk ein gong" #: backends/platform/tizen/form.cpp:271 -#, fuzzy msgid "Move Only" -msgstr "Tale" +msgstr "" #: backends/platform/tizen/form.cpp:294 msgid "Escape Key" @@ -2024,30 +2027,28 @@ msgid "Show Keypad" msgstr "Syn taltastatur" #: backends/platform/tizen/form.cpp:309 -#, fuzzy msgid "Control Mouse" -msgstr "Musklikk" +msgstr "" #: backends/platform/tizen/fs.cpp:259 msgid "[ Data ]" -msgstr "" +msgstr "[ Data ]" #: backends/platform/tizen/fs.cpp:263 msgid "[ Resources ]" -msgstr "" +msgstr "[ Ressursar ]" #: backends/platform/tizen/fs.cpp:267 msgid "[ SDCard ]" -msgstr "" +msgstr "[ SDKort ]" #: backends/platform/tizen/fs.cpp:271 msgid "[ Media ]" -msgstr "" +msgstr "[ Media ]" #: backends/platform/tizen/fs.cpp:275 -#, fuzzy msgid "[ Shared ]" -msgstr ", delt ressurs ikkje montert" +msgstr "[ Delt ]" #: backends/platform/wii/options.cpp:51 msgid "Video" @@ -2074,9 +2075,8 @@ msgid "Input" msgstr "Input" #: backends/platform/wii/options.cpp:74 -#, fuzzy msgid "GC Pad sensitivity:" -msgstr "Sensitivitet" +msgstr "GC Pad Sensitivitet" #: backends/platform/wii/options.cpp:80 msgid "GC Pad acceleration:" @@ -2111,9 +2111,8 @@ msgid "Server:" msgstr "Teinar:" #: backends/platform/wii/options.cpp:110 -#, fuzzy msgid "Share:" -msgstr ", delt ressurs ikkje montert" +msgstr "Delt:" #: backends/platform/wii/options.cpp:114 msgid "Username:" @@ -2156,9 +2155,8 @@ msgid "Network up" msgstr "Nettverket er oppe" #: backends/platform/wii/options.cpp:166 -#, fuzzy msgid ", error while mounting the share" -msgstr "Feil under montering av DVD" +msgstr ", feil under montering av delt ressurs" #: backends/platform/wii/options.cpp:168 msgid ", share not mounted" @@ -2169,19 +2167,17 @@ msgid "Network down" msgstr "Nettverket er nede" #: backends/platform/wii/options.cpp:178 -#, fuzzy msgid "Initializing network" -msgstr "Init nettverk" +msgstr "Initialiserar nettverk" #: backends/platform/wii/options.cpp:182 -#, fuzzy msgid "Timeout while initializing network" -msgstr "Initialiserer nettverk" +msgstr "" #: backends/platform/wii/options.cpp:186 -#, fuzzy, c-format +#, c-format msgid "Network not initialized (%d)" -msgstr "Init nettverk" +msgstr "Nettverk ikkje initialisert (%d)" #: backends/platform/wince/CEActionsPocket.cpp:46 msgid "Hide Toolbar" @@ -2317,9 +2313,8 @@ msgid "Use the original save/load screens, instead of the ScummVM ones" msgstr "" #: engines/agi/detection.cpp:157 -#, fuzzy msgid "Use an alternative palette" -msgstr "Nytt diskettversjonens åpning (Kun CD-versjon)" +msgstr "Nytt ein alternativ palett" #: engines/agi/detection.cpp:158 msgid "" @@ -2328,24 +2323,31 @@ msgid "" msgstr "" #: engines/agi/detection.cpp:167 -#, fuzzy msgid "Mouse support" -msgstr "Hopp over" +msgstr "Musstøtte" #: engines/agi/detection.cpp:168 msgid "" "Enables mouse support. Allows to use mouse for movement and in game menus." msgstr "" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Gjenopprett spel:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Gjenopprett" @@ -2379,13 +2381,12 @@ msgid "Cutscene file '%s' not found!" msgstr "" #: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101 -#, fuzzy msgid "Color Blind Mode" -msgstr "Klikkmodus" +msgstr "Fargeblindmodus" #: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102 msgid "Enable Color Blind Mode by default" -msgstr "" +msgstr "Slå på fargeblindmodus som standard" #: engines/drascula/saveload.cpp:47 msgid "" @@ -2397,11 +2398,17 @@ msgid "" "Press OK to convert them now, otherwise you will be asked again the next " "time you start the game.\n" msgstr "" +"ScummVM oppdaga at du har gamle spellagringar for Drascula som vi kan " +"konvertere.\n" +"Det gamle spellagringsformatet er ikkje lenger støtta, så du vil ikkje vere " +"i stand til å laste dei om du ikkje konverterar dei\n" +"\n" +"Trykk OK for å konvertere dei no, ellers kjem du til å verte spurt neste " +"gong du startar spelet.\n" #: engines/dreamweb/detection.cpp:57 -#, fuzzy msgid "Use bright palette mode" -msgstr "Øvre høgre gjenstand" +msgstr "Nytt lys palett-modus" #: engines/dreamweb/detection.cpp:58 msgid "Display graphics using the game's bright palette" @@ -2422,26 +2429,24 @@ msgid "Failed to delete file." msgstr "Klarte ikkje slette fil." #: engines/groovie/detection.cpp:312 -#, fuzzy msgid "Fast movie speed" -msgstr "Rask modus" +msgstr "Rask filmfart" #: engines/groovie/detection.cpp:313 msgid "Play movies at an increased speed" msgstr "Spel filmar med auka hastighet" #: engines/groovie/script.cpp:408 -#, fuzzy msgid "Failed to save game" -msgstr "Lagra spel:" +msgstr "Klarte ikkje lagre spel" #: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86 msgid "Gore Mode" -msgstr "" +msgstr "Gørrmodus" #: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87 msgid "Enable Gore Mode when available" -msgstr "" +msgstr "Slå på gørrmodus når tilgjengeleg" #. I18N: Studio audience adds an applause and cheering sounds whenever #. Malcolm makes a joke. @@ -2455,46 +2460,42 @@ msgstr "Aktiver studiopublikum" #. I18N: This option allows the user to skip text and cutscenes. #: engines/kyra/detection.cpp:73 -#, fuzzy msgid "Skip support" -msgstr "Hopp over" +msgstr "Hopp over-støtte" #: engines/kyra/detection.cpp:74 msgid "Allow text and cutscenes to be skipped" -msgstr "" +msgstr "Tillat å hoppe over tekst og cutscenes" #. I18N: Helium mode makes people sound like they've inhaled Helium. #: engines/kyra/detection.cpp:84 -#, fuzzy msgid "Helium mode" -msgstr "Grafikkmodus:" +msgstr "Heliummodus" #: engines/kyra/detection.cpp:85 -#, fuzzy msgid "Enable helium mode" -msgstr "Grafikkmodus:" +msgstr "Slå på heliummodus" #. I18N: When enabled, this option makes scrolling smoother when #. changing from one screen to another. #: engines/kyra/detection.cpp:99 msgid "Smooth scrolling" -msgstr "" +msgstr "Mjuk rulling" #: engines/kyra/detection.cpp:100 msgid "Enable smooth scrolling when walking" -msgstr "" +msgstr "Slå på mjuk rulling under gåing" #. 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 -#, fuzzy msgid "Floating cursors" -msgstr "Vanleg peikar" +msgstr "Flytande peikarar" #: engines/kyra/detection.cpp:113 msgid "Enable floating cursors" -msgstr "" +msgstr "Slå på flytande peikarar" #. I18N: HP stands for Hit Points #: engines/kyra/detection.cpp:127 @@ -2506,61 +2507,52 @@ msgid "Enable hit point bar graphs" msgstr "" #: engines/kyra/lol.cpp:478 -#, fuzzy msgid "Attack 1" -msgstr "byttast 7, 4, og 1 med" +msgstr "Åtak 1" #: engines/kyra/lol.cpp:479 msgid "Attack 2" -msgstr "" +msgstr "Åtak 2" #: engines/kyra/lol.cpp:480 -#, fuzzy msgid "Attack 3" -msgstr "9, 6, og 3, henhaldsvis." +msgstr "Åtak 3" #: engines/kyra/lol.cpp:481 msgid "Move Forward" -msgstr "" +msgstr "Beveg Framover" #: engines/kyra/lol.cpp:482 -#, fuzzy msgid "Move Back" -msgstr "Bakoversteg" +msgstr "Beveg Bakover" #: engines/kyra/lol.cpp:483 -#, fuzzy msgid "Slide Left" -msgstr "Venstre" +msgstr "Skli til Venstre" #: engines/kyra/lol.cpp:484 -#, fuzzy msgid "Slide Right" -msgstr "Høgre" +msgstr "Skli til Høyre" #: engines/kyra/lol.cpp:485 engines/pegasus/pegasus.cpp:2509 -#, fuzzy msgid "Turn Left" -msgstr "Slå på" +msgstr "Snu til Venstre" #: engines/kyra/lol.cpp:486 engines/pegasus/pegasus.cpp:2510 -#, fuzzy msgid "Turn Right" -msgstr "Slå på" +msgstr "Snu til Høyre" #: engines/kyra/lol.cpp:487 -#, fuzzy msgid "Rest" -msgstr "Gjenopprett" +msgstr "Kvil" #: engines/kyra/lol.cpp:488 msgid "Options" msgstr "Val" #: engines/kyra/lol.cpp:489 -#, fuzzy msgid "Choose Spell" -msgstr "Vel" +msgstr "" #: engines/kyra/sound_midi.cpp:477 msgid "" @@ -2611,9 +2603,8 @@ msgstr "~O~vergangar aktivert" #. I18N: Drop book page #: engines/mohawk/dialogs.cpp:95 -#, fuzzy msgid "~D~rop Page" -msgstr "Søkt i %d mappar ..." +msgstr "" #: engines/mohawk/dialogs.cpp:99 msgid "~S~how Map" @@ -2652,10 +2643,18 @@ msgstr "" "Kan ikkje lagre spel i spor %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +msgid "Load file" +msgstr "Last fil:" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Lastar spel..." +#: engines/parallaction/saveload.cpp:212 +msgid "Save file" +msgstr "Lagra fil:" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Lagrar spel..." @@ -2691,9 +2690,8 @@ msgid "Up/Zoom In/Move Forward/Open Doors" msgstr "" #: engines/pegasus/pegasus.cpp:2508 -#, fuzzy msgid "Down/Zoom Out" -msgstr "Zoom ned" +msgstr "Ned/Zoom Ut" #: engines/pegasus/pegasus.cpp:2511 msgid "Display/Hide Inventory Tray" @@ -2704,9 +2702,8 @@ msgid "Display/Hide Biochip Tray" msgstr "" #: engines/pegasus/pegasus.cpp:2513 -#, fuzzy msgid "Action/Select" -msgstr "Vel ei handling, og klikk 'Kople'" +msgstr "Handling/Vel" #: engines/pegasus/pegasus.cpp:2514 msgid "Toggle Center Data Display" @@ -2722,12 +2719,11 @@ msgstr "Skjul/Vis pausemeny" #: engines/queen/detection.cpp:56 msgid "Alternative intro" -msgstr "" +msgstr "Alternativ intro" #: engines/queen/detection.cpp:57 -#, fuzzy msgid "Use an alternative game intro (CD version only)" -msgstr "Nytt diskettversjonens åpning (Kun CD-versjon)" +msgstr "Nytt alternativ spillåpning (Kun CD-versjon)" #: engines/sci/detection.cpp:374 msgid "Skip EGA dithering pass (full color backgrounds)" @@ -2739,11 +2735,11 @@ msgstr "" #: engines/sci/detection.cpp:384 msgid "Enable high resolution graphics" -msgstr "" +msgstr "Nytt høgoppløyseleg grafikk" #: engines/sci/detection.cpp:385 msgid "Enable high resolution graphics/content" -msgstr "" +msgstr "Nytt høgoppløyseleg grafikk/innhald" #: engines/sci/detection.cpp:394 msgid "Prefer digital sound effects" @@ -2762,6 +2758,8 @@ msgid "" "Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI " "output" msgstr "" +"Nytt eit IBM Music Feature-kort eller ein Yamaha FB-01 FM synth modul for " +"MIDI avspeling" #: engines/sci/detection.cpp:425 msgid "Use CD audio" @@ -2792,7 +2790,7 @@ msgstr "Nytt det alternative settet med sølvpeikarar, istaden for dei gylne" #: engines/scumm/dialogs.cpp:176 #, c-format msgid "Insert Disk %c and Press Button to Continue." -msgstr "" +msgstr "Sett inn disk %c og trykk på knappen for å fortsette." #: engines/scumm/dialogs.cpp:177 #, c-format @@ -2812,33 +2810,29 @@ msgstr "Spelet er pausa. Trykk MELLOMROM for å fortsette." #. "Moechten Sie wirklich neu starten? (J/N)J" #. Will react to J as 'Yes' #: engines/scumm/dialogs.cpp:183 -#, fuzzy msgid "Are you sure you want to restart? (Y/N)Y" -msgstr "Er du sikker på at du vil starte på nytt (Y/N)?" +msgstr "Er du sikker på at du vil starte på nytt (J/N)J" #. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment #: engines/scumm/dialogs.cpp:185 -#, fuzzy msgid "Are you sure you want to quit? (Y/N)Y" -msgstr "Er du sikker på at du vil avslutte (Y/N)?" +msgstr "Er du sikker på at du vil avslutte (J/N)J" #: engines/scumm/dialogs.cpp:190 msgid "Play" msgstr "Spel" #: engines/scumm/dialogs.cpp:194 -#, fuzzy msgid "Insert save/load game disk" -msgstr "Vil du åpne eller lagre spelet?" +msgstr "Sett in lagre/laste speldisk" #: engines/scumm/dialogs.cpp:195 msgid "You must enter a name" msgstr "Du må skrive eit namn" #: engines/scumm/dialogs.cpp:196 -#, fuzzy msgid "The game was NOT saved (disk full?)" -msgstr "Full speltittel:" +msgstr "Spelet vart IKKJE lagra (full disk?)" #: engines/scumm/dialogs.cpp:197 msgid "The game was NOT loaded" @@ -2894,9 +2888,8 @@ msgid "Speech & Subs" msgstr "Tekst & Tale" #: engines/scumm/dialogs.cpp:658 -#, fuzzy msgid "Select a Proficiency Level." -msgstr "Gå til forrige mappenivå" +msgstr "" #: engines/scumm/dialogs.cpp:660 msgid "Refer to your Loom(TM) manual for help." @@ -2904,7 +2897,7 @@ msgstr "Sjå i Loom(TM)-manualen for hjelp." #: engines/scumm/dialogs.cpp:664 msgid "Practice" -msgstr "" +msgstr "Øving" #: engines/scumm/dialogs.cpp:665 msgid "Expert" @@ -3037,9 +3030,8 @@ msgid " since they may cause crashes" msgstr " dei kan forårsake kræsj og" #: engines/scumm/help.cpp:111 -#, fuzzy msgid " or incorrect game behavior." -msgstr "Spel" +msgstr " eller feilaktig speloppførsel." #: engines/scumm/help.cpp:115 msgid "Spinning drafts on the keyboard:" @@ -3445,23 +3437,20 @@ msgid "Fly to lower right" msgstr "Fly til nedre høgre" #: engines/scumm/input.cpp:580 -#, fuzzy msgid "Snap scroll on" -msgstr "Bla liste ned" +msgstr "" #: engines/scumm/input.cpp:582 msgid "Snap scroll off" msgstr "" #: engines/scumm/input.cpp:595 -#, fuzzy msgid "Music volume: " msgstr "Musikkvolum:" #: engines/scumm/input.cpp:612 -#, fuzzy msgid "Subtitle speed: " -msgstr "Undertekstfart:" +msgstr "Subtitle speed: " #: engines/scumm/scumm.cpp:1832 #, c-format @@ -3471,27 +3460,82 @@ msgid "" msgstr "" #: engines/scumm/scumm.cpp:2644 -#, fuzzy 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 "" -"Opprinneleg, skulle Maniac Mansion ha starta no. Men ScummVM støttar ikkje " -"det enno. For å spele Maniac Mansion, gå til 'Legg til spel' i ScummVM-" -"menyen og vel 'Maniac'-undermappa i 'Tentacle'-mappa." +"Opprinneleg, skulle Maniac Mansion ha starta no. Men for at det skal virke " +"må du ha datafilane til Maniac Mansion i «Maniac»-mappa inni «Tentacle»-" +"spelmappa, og spelet må vere lagt til i ScummVM." #: 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 "" +"Kunne ikkje finne Macintosh-binærfila «Loom» for å lese\n" +"instrumenter frå den. Musikk vert deaktivert." #: 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 "" +"Kunne ikkje finne Macintosh-binærfila «Monkey Island» for å lese\n" +"instrumentar frå den. Musikk vert deaktivert." + +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "Nytt opprinnelege skjerm for lagring/lasting" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "Pikselerte sceneovergangar" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "Syn karakterportrettar" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "Gjennomsiktige vindauge" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "" #: engines/sky/compact.cpp:130 msgid "" @@ -3518,21 +3562,21 @@ msgstr "Nytt diskettversjonens åpning (Kun CD-versjon)" #: engines/sword1/animation.cpp:524 #, c-format msgid "PSX stream cutscene '%s' cannot be played in paletted mode" -msgstr "" +msgstr "PSX strømme cutscene '%s' kan ikkje avspelast i pallettmodus" #: engines/sword1/animation.cpp:545 engines/sword2/animation.cpp:445 msgid "DXA cutscenes found but ScummVM has been built without zlib" -msgstr "" +msgstr "DXA cutscenar funne, men ScummVM vart bygd utan zlib" #: 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 "" +msgstr "MPEG-2 cutscenar funne, men ScummVM er bygd utan MPEG-2 støtte" #: engines/sword1/animation.cpp:568 engines/sword2/animation.cpp:470 -#, fuzzy, c-format +#, c-format msgid "Cutscene '%s' not found" -msgstr "Hopp over cutscene" +msgstr "Cutscene '%s' ikkje funne" #: engines/sword1/control.cpp:863 msgid "" @@ -3544,6 +3588,13 @@ msgid "" "Press OK to convert them now, otherwise you will be asked again the next " "time you start the game.\n" msgstr "" +"ScummVM oppdaga at du har gamle lagra speltilstandar for Broken Sword 1 som " +"vi kan konvertere.\n" +"Det gamle formatet for lagra speltilstandar støttast ikkje lengre, så du vil " +"ikkje kunne laste dei utan å konvertere dei.\n" +"\n" +"Trykk OK for å konvertere dei no, ellers vil du bli spurt igjen neste gong " +"du starter spelet.\n" #: engines/sword1/control.cpp:1232 #, c-format @@ -3551,6 +3602,9 @@ 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 "" +"Målet for den lagrede speltilstanden finst!\n" +"Vil du ta vare på den gamle tilstanden (%s) eller den nye (%s)?\n" +" \n" #: engines/sword1/control.cpp:1235 msgid "Keep the old one" @@ -3567,16 +3621,15 @@ msgstr "Dette er slutten på Broken Sword 1-demoen" #: engines/sword2/animation.cpp:425 msgid "" "PSX cutscenes found but ScummVM has been built without RGB color support" -msgstr "" +msgstr "PSX cutscenar vart funne, men ScummVM er bygd utan RGB fargestøtte" #: engines/sword2/sword2.cpp:79 -#, fuzzy msgid "Show object labels" -msgstr "Objekt" +msgstr "Syn objektmerkelappar" #: engines/sword2/sword2.cpp:80 msgid "Show labels for objects on mouse hover" -msgstr "" +msgstr "Syn merkelappar for objekt når musa er over dei" #: engines/teenagent/resources.cpp:95 msgid "" @@ -3588,54 +3641,57 @@ msgid "" "The teenagent.dat file is compressed and zlib hasn't been included in this " "executable. Please decompress it" msgstr "" +"Fila teenagent.dat er komprimert og zlib er ikkje inkludert i binærfila, " +"vennlegs dekomprimer den." #: engines/wintermute/detection.cpp:58 msgid "Show FPS-counter" -msgstr "" +msgstr "Syn FPS-teller" #: engines/wintermute/detection.cpp:59 msgid "Show the current number of frames per second in the upper left corner" msgstr "" +"Vis det gjeldande antall bilete per sekund i øvre venstre hjørne av skjermen" #: engines/zvision/detection_tables.h:52 -#, fuzzy msgid "Use the original save/load screens instead of the ScummVM interface" -msgstr "Nytt opprinnelege skjermar for lagring/lasting" +msgstr "" +"Nytt opprinnelege skjermar for lagring/lasting istadenfor ScummVM " +"grensesnittet" #: engines/zvision/detection_tables.h:61 msgid "Double FPS" -msgstr "" +msgstr "Dobbel FPS" #: engines/zvision/detection_tables.h:62 msgid "Increase framerate from 30 to 60 FPS" -msgstr "" +msgstr "Auk bilderate frå 30 til 60 FPS" #: engines/zvision/detection_tables.h:71 -#, fuzzy msgid "Enable Venus" -msgstr "Grafikkmodus:" +msgstr "Slå på Venus" #: engines/zvision/detection_tables.h:72 -#, fuzzy msgid "Enable the Venus help system" -msgstr "Grafikkmodus:" +msgstr "Slå på Venus-hjelpesystemet" #: engines/zvision/detection_tables.h:81 msgid "Disable animation while turning" -msgstr "" +msgstr "Slå av animasjonar under snuing" #: engines/zvision/detection_tables.h:82 msgid "Disable animation while turning in panorama mode" -msgstr "" +msgstr "Slå av animasjonar under snuing i panoramamodus" #: engines/zvision/detection_tables.h:91 msgid "Use high resolution MPEG video" -msgstr "" +msgstr "Nytt høgoppløyseleg MPEG-video" #: engines/zvision/detection_tables.h:92 -#, fuzzy msgid "Use MPEG video from the DVD version, instead of lower resolution AVI" -msgstr "Nytt det alternative settet med sølvpeikarar, istaden for dei gylne" +msgstr "" +"Nytt MPEG video frå DVD-versjonen, framfor AVI-versjonen med lågare " +"oppløysning" #~ msgctxt "lowres" #~ msgid "Mass Add..." @@ -3664,10 +3720,6 @@ msgstr "Nytt det alternative settet med sølvpeikarar, istaden for dei gylne" #~ msgid "Enable Roland GS Mode" #~ msgstr "Aktiver Roland GS-modus" -#, fuzzy -#~ msgid "Save game failed!" -#~ msgstr "Lagra spel:" - #~ msgctxt "lowres" #~ msgid "Add Game..." #~ msgstr "Legg til spill..." diff --git a/po/pl_PL.po b/po/pl_PL.po index ff719a3e9f..6546259ade 100644 --- a/po/pl_PL.po +++ b/po/pl_PL.po @@ -7,14 +7,16 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.3.0\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" -"PO-Revision-Date: 2014-07-02 12:28+0100\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" +"PO-Revision-Date: 2016-02-20 23:43+0100\n" "Last-Translator: Micha³ Zi±bkowski <mziab@o2.pl>\n" "Language-Team: Grajpopolsku.pl <grajpopolsku@gmail.com>\n" "Language: Polski\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-2\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=((n==1) ? 0 : ((n%10>=2 && n%10<=4 && (n" +"%100<10 || n%100>=20)) ? 1 : 2));\n" "X-Poedit-KeywordsList: _;gettext;gettext_noop\n" "X-Poedit-Basepath: .\n" "X-Poedit-Language: Polish\n" @@ -76,7 +78,7 @@ msgstr "Wybierz" #: gui/editrecorddialog.cpp:58 msgid "Author:" -msgstr "" +msgstr "Autor:" #: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204 msgid "Name:" @@ -84,24 +86,23 @@ msgstr "Nazwa:" #: gui/editrecorddialog.cpp:60 msgid "Notes:" -msgstr "" +msgstr "Uwagi:" #: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74 msgid "Ok" -msgstr "" +msgstr "Ok" #: gui/filebrowser-dialog.cpp:49 msgid "Choose file for loading" -msgstr "" +msgstr "Wybierz plik do wczytania" #: gui/filebrowser-dialog.cpp:49 msgid "Enter filename for saving" -msgstr "" +msgstr "Podaj nazwê pliku do zapisania" #: gui/filebrowser-dialog.cpp:132 -#, fuzzy msgid "Do you really want to overwrite the file?" -msgstr "Na pewno chcesz skasowaæ ten zapis?" +msgstr "Na pewno chcesz nadpisaæ ten plik?" #: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217 #: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002 @@ -266,7 +267,7 @@ msgstr "Wybierz akcjê i kliknij 'Przypisz'" #: gui/KeysDialog.cpp:80 gui/KeysDialog.cpp:102 gui/KeysDialog.cpp:141 #, c-format msgid "Associated key : %s" -msgstr "Przypisany klawisz : %s" +msgstr "Przypisany klawisz: %s" #: gui/KeysDialog.cpp:82 gui/KeysDialog.cpp:104 gui/KeysDialog.cpp:143 #, c-format @@ -591,16 +592,16 @@ msgid "Search:" msgstr "Szukaj" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Wczytaj grê:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Wczytaj" @@ -642,11 +643,11 @@ msgstr "ScummVM nie znalaz³ silnika zdolnego uruchomiæ wybran± grê!" #: gui/launcher.cpp:1161 msgid "Mass Add..." -msgstr "Masowe dodawanie..." +msgstr "Przeszukaj..." #: gui/launcher.cpp:1163 msgid "Record..." -msgstr "" +msgstr "Nagraj..." #: gui/massadd.cpp:79 gui/massadd.cpp:82 msgid "... progress ..." @@ -659,35 +660,33 @@ msgstr "Skanowanie zakoñczone!" #: gui/massadd.cpp:262 #, c-format msgid "Discovered %d new games, ignored %d previously added games." -msgstr "Wykryto %d nowych gier, zignorowano %d poprzednio dodanych." +msgstr "Wykryto %d now± grê, zignorowano %d poprzednio dodanych." #: gui/massadd.cpp:266 #, c-format msgid "Scanned %d directories ..." -msgstr "Przeskanowano %d katalogów ..." +msgstr "Przeskanowano %d katalog..." #: gui/massadd.cpp:269 #, c-format msgid "Discovered %d new games, ignored %d previously added games ..." -msgstr "Wykryto %d nowych gier, zignorowano %d poprzednio dodanych..." +msgstr "Wykryto %d now± grê, zignorowano %d poprzednio dodanych..." #: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103 msgid "Stop" -msgstr "" +msgstr "Stop" #: gui/onscreendialog.cpp:106 msgid "Edit record description" -msgstr "" +msgstr "Edytuj opis nagrania" #: gui/onscreendialog.cpp:108 -#, fuzzy msgid "Switch to Game" -msgstr "Prze³±cz" +msgstr "Prze³±cz do gry" #: gui/onscreendialog.cpp:110 -#, fuzzy msgid "Fast replay" -msgstr "Tryb szybki" +msgstr "Szybka powtórka" #: gui/options.cpp:85 msgid "Never" @@ -764,7 +763,7 @@ msgid "Special dithering modes supported by some games" msgstr "Specjalne tryby ditheringu wspierane przez niektóre gry" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Pe³ny ekran" @@ -1080,39 +1079,38 @@ msgstr "" #. I18N: You must leave "#" as is, only word 'next' is translatable #: gui/predictivedialog.cpp:86 msgid "# next" -msgstr "" +msgstr "# nastêpny" #: gui/predictivedialog.cpp:87 msgid "add" -msgstr "" +msgstr "dodaj" #: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164 -#, fuzzy msgid "Delete char" -msgstr "Skasuj" +msgstr "Usuñ znak" #: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168 msgid "<" -msgstr "" +msgstr "<" #. I18N: Pre means 'Predictive', leave '*' as is #: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572 msgid "* Pre" -msgstr "" +msgstr "* Pre" #. I18N: 'Num' means Numbers #: gui/predictivedialog.cpp:575 msgid "* Num" -msgstr "" +msgstr "* Num" #. I18N: 'Abc' means Latin alphabet input #: gui/predictivedialog.cpp:578 msgid "* Abc" -msgstr "" +msgstr "* Abc" #: gui/recorderdialog.cpp:64 msgid "Recorder or Playback Gameplay" -msgstr "" +msgstr "Nagrywanie/odtwarzanie rozgrywki" #: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156 #: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276 @@ -1121,36 +1119,33 @@ msgstr "Skasuj" #: gui/recorderdialog.cpp:71 msgid "Record" -msgstr "" +msgstr "Nagrywaj" #: gui/recorderdialog.cpp:72 -#, fuzzy msgid "Playback" -msgstr "Uruchom" +msgstr "Odtwarzaj" #: gui/recorderdialog.cpp:74 msgid "Edit" -msgstr "" +msgstr "Edytuj" #: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243 #: gui/recorderdialog.cpp:253 msgid "Author: " -msgstr "" +msgstr "Autor: " #: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244 #: gui/recorderdialog.cpp:254 msgid "Notes: " -msgstr "" +msgstr "Uwagi: " #: gui/recorderdialog.cpp:155 -#, fuzzy msgid "Do you really want to delete this record?" -msgstr "Na pewno chcesz skasowaæ ten zapis?" +msgstr "Na pewno chcesz usun±æ to nagranie?" #: gui/recorderdialog.cpp:174 -#, fuzzy msgid "Unknown Author" -msgstr "Nieznany b³±d" +msgstr "Nieznany autor" #: gui/saveload-dialog.cpp:167 msgid "List view" @@ -1357,18 +1352,18 @@ msgstr "Bursztynowy Hercules" #: common/rendermode.cpp:42 msgid "PC-9821 (256 Colors)" -msgstr "" +msgstr "PC-9821 (256 kolorów)" #: common/rendermode.cpp:43 msgid "PC-9801 (16 Colors)" -msgstr "" +msgstr "PC-9801 (16 kolorów)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Zielony Hercules" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Bursztynowy Hercules" @@ -1419,11 +1414,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "~P~owrót do launchera" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Zapis:" @@ -1432,11 +1431,15 @@ msgstr "Zapis:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Zapisz" @@ -1550,7 +1553,7 @@ msgstr "Emulator OPL DOSBox" #: audio/fmopl.cpp:67 msgid "ALSA Direct FM" -msgstr "" +msgstr "Bezpo¶rednie FM Alsa" #: audio/mididrv.cpp:209 #, c-format @@ -1607,17 +1610,15 @@ msgstr "Emulator Apple II GS (NIE ZAIMPLEMENTOWANY)" #: audio/softsynth/cms.cpp:350 msgid "Creative Music System Emulator" -msgstr "" +msgstr "Emulator Creative Music System" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33 -#, fuzzy msgid "FM-Towns Audio" -msgstr "Emulator FM Towns" +msgstr "D¼wiêk FM-Towns" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58 -#, fuzzy msgid "PC-98 Audio" -msgstr "D¼wiêk" +msgstr "D¼wiêk PC-98" #: audio/softsynth/mt32.cpp:200 msgid "Initializing MT-32 Emulator" @@ -1712,34 +1713,33 @@ msgstr "Chcesz wyj¶æ?" #. I18N: Trackpad mode toggle status. #: backends/events/webossdl/webossdl-events.cpp:308 -#, fuzzy msgid "Trackpad mode is now" -msgstr "Tryb touchpada wy³±czony." +msgstr "Tryb g³adzika jest" #. 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 "" +msgstr "w³±czony" #: backends/events/webossdl/webossdl-events.cpp:311 #: backends/events/webossdl/webossdl-events.cpp:338 msgid "OFF" -msgstr "" +msgstr "wy³±czony" #: backends/events/webossdl/webossdl-events.cpp:315 msgid "Swipe two fingers to the right to toggle." -msgstr "" +msgstr "Przesuñ dwoma palcami, ¿eby zmieniæ." #. I18N: Auto-drag toggle status. #: backends/events/webossdl/webossdl-events.cpp:335 msgid "Auto-drag mode is now" -msgstr "" +msgstr "Tryb automatycznego przeci±gania jest" #: backends/events/webossdl/webossdl-events.cpp:342 msgid "Swipe three fingers to the right to toggle." -msgstr "" +msgstr "Przesuñ trzema palcami, ¿eby zmieniæ." #: backends/graphics/opengl/opengl-graphics.cpp:119 msgid "OpenGL" @@ -1760,19 +1760,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Zwyk³y (bez skalowania)" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "W³±czono korekcjê formatu obrazu" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "Wy³±czono korekcjê formatu obrazu" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Aktywny filtr graficzny:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Okno" @@ -1839,7 +1839,7 @@ msgstr "Przesuniêcie Y ekranu do dotykania" #: backends/platform/ds/arm9/source/dsoptions.cpp:87 msgid "Use laptop trackpad-style cursor control" -msgstr "U¿yj kursora w stylu trackpada z laptopa do sterowania" +msgstr "U¿yj kursora w stylu g³adzika laptopa do sterowania" #: backends/platform/ds/arm9/source/dsoptions.cpp:88 msgid "Tap for left click, double tap right click" @@ -2034,24 +2034,23 @@ msgstr "Steruj myszk±" #: backends/platform/tizen/fs.cpp:259 msgid "[ Data ]" -msgstr "" +msgstr "[ Dane ]" #: backends/platform/tizen/fs.cpp:263 msgid "[ Resources ]" -msgstr "" +msgstr "[ Zasoby ]" #: backends/platform/tizen/fs.cpp:267 msgid "[ SDCard ]" -msgstr "" +msgstr "[ Karta SD ]" #: backends/platform/tizen/fs.cpp:271 msgid "[ Media ]" -msgstr "" +msgstr "[ Media ]" #: backends/platform/tizen/fs.cpp:275 -#, fuzzy msgid "[ Shared ]" -msgstr "Udzia³:" +msgstr "[ Wspó³dzielone ]" #: backends/platform/wii/options.cpp:51 msgid "Video" @@ -2315,35 +2314,45 @@ msgid "Use the original save/load screens, instead of the ScummVM ones" msgstr "U¿yj oryginalnych ekranów odczytu/zapisu zamiast tych ze ScummVM" #: engines/agi/detection.cpp:157 -#, fuzzy msgid "Use an alternative palette" -msgstr "U¿yj alternatywnego intra (tylko dla wersji CD)" +msgstr "U¿yj alternatywnej palety" #: engines/agi/detection.cpp:158 msgid "" "Use an alternative palette, common for all Amiga games. This was the old " "behavior" msgstr "" +"U¿yj alternatywnej palety dla wszystkich amigowych gier. Takie by³o dawne " +"zachowanie" #: engines/agi/detection.cpp:167 -#, fuzzy msgid "Mouse support" -msgstr "Obs³uga pomijania" +msgstr "Obs³uga myszki" #: engines/agi/detection.cpp:168 msgid "" "Enables mouse support. Allows to use mouse for movement and in game menus." msgstr "" +"W³±cza obs³ugê myszki. Pozwala na u¿ycie myszki do przemieszczania i w menu " +"gry." -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Wznów grê:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Wznów" @@ -2386,13 +2395,12 @@ msgid "Cutscene file '%s' not found!" msgstr "Nie znaleziono pliku przerywnika '%s'!" #: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101 -#, fuzzy msgid "Color Blind Mode" -msgstr "Tryb klikania" +msgstr "Tryb dla daltonistów" #: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102 msgid "Enable Color Blind Mode by default" -msgstr "" +msgstr "Domy¶lnie w³±cz tryb dla daltonistów" #: engines/drascula/saveload.cpp:47 msgid "" @@ -2447,11 +2455,11 @@ msgstr "Nie uda³o siê zapisaæ stanu gry" #: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86 msgid "Gore Mode" -msgstr "" +msgstr "Tryb krwi" #: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87 msgid "Enable Gore Mode when available" -msgstr "" +msgstr "W³±cz tryb krwi, je¶li jest dostêpny" #. I18N: Studio audience adds an applause and cheering sounds whenever #. Malcolm makes a joke. @@ -2582,6 +2590,12 @@ msgid "" "Do you wish to use this save game file with ScummVM?\n" "\n" msgstr "" +"W ¶cie¿ce gry znaleziono oryginalny zapis gry:\n" +"\n" +"%s %s\n" +"\n" +"Chcesz u¿yæ tego zapisu w ScummVM?\n" +"\n" #: engines/kyra/saveload_eob.cpp:590 #, c-format @@ -2589,6 +2603,8 @@ msgid "" "A save game file was found in the specified slot %d. Overwrite?\n" "\n" msgstr "" +"W wybranym slocie %d znaleziono zapis gry. Nadpisaæ?\n" +"\n" #: engines/kyra/saveload_eob.cpp:623 #, c-format @@ -2600,6 +2616,10 @@ msgid "" "'import_savefile'.\n" "\n" msgstr "" +"Pomy¶lnie zaimportowano %d oryginalny zapis gry do ScummVM. Je¶li pó¼niej " +"zechcesz zaimportowaæ oryginalne zapisy, bêdziesz musia³ otworzyæ konsolê " +"debugowania ScummVM i u¿yæ komendy 'import_savefile'.\n" +"\n" #. I18N: Option for fast scene switching #: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167 @@ -2652,10 +2672,18 @@ msgstr "" "Nie mo¿na zapisaæ w slocie %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +msgid "Load file" +msgstr "Wczytaj plik" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Wczytywanie stanu gry..." +#: engines/parallaction/saveload.cpp:212 +msgid "Save file" +msgstr "Zapisz plik" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Zapisywanie stanu gry..." @@ -2738,21 +2766,20 @@ msgstr "U¿yj alternatywnego intra (tylko dla wersji CD)" #: engines/sci/detection.cpp:374 msgid "Skip EGA dithering pass (full color backgrounds)" -msgstr "" +msgstr "Pomiñ dithering EGA (t³a w pe³nym kolorze)" #: engines/sci/detection.cpp:375 msgid "Skip dithering pass in EGA games, graphics are shown with full colors" msgstr "" +"Pomiñ dithering w grach EGA, grafika bêdzie wy¶wietlana w pe³nym kolorze" #: engines/sci/detection.cpp:384 -#, fuzzy msgid "Enable high resolution graphics" -msgstr "W³±cz histogramy punktów ¿ycia" +msgstr "W³±cz grafikê wysokiej rozdzielczo¶ci" #: engines/sci/detection.cpp:385 -#, fuzzy msgid "Enable high resolution graphics/content" -msgstr "W³±cz histogramy punktów ¿ycia" +msgstr "W³±cz grafikê/zawarto¶æ wysokiej rozdzielczo¶ci" #: engines/sci/detection.cpp:394 msgid "Prefer digital sound effects" @@ -2825,15 +2852,13 @@ msgstr "Gra wstrzymana. Naci¶nij spacjê, aby wznowiæ." #. "Moechten Sie wirklich neu starten? (J/N)J" #. Will react to J as 'Yes' #: engines/scumm/dialogs.cpp:183 -#, fuzzy msgid "Are you sure you want to restart? (Y/N)Y" -msgstr "Na pewno chcesz zrestartowaæ grê? (T/N)T" +msgstr "Na pewno chcesz zrestartowaæ? (T/N)T" #. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment #: engines/scumm/dialogs.cpp:185 -#, fuzzy msgid "Are you sure you want to quit? (Y/N)Y" -msgstr "Na pewno chcesz wyj¶æ? (T/N)T" +msgstr "Na pewno chcesz wyj¶æ? (T/N)T" #: engines/scumm/dialogs.cpp:190 msgid "Play" @@ -3341,25 +3366,24 @@ msgid "Third kid" msgstr "Trzeci dzieciak" #: engines/scumm/help.cpp:292 -#, fuzzy msgid "Toggle Inventory/IQ Points display" -msgstr "W³±cz/wy³±cz widok danych" +msgstr "W³±cz/wy³±cz widok ekwipunku/punktów IQ" #: engines/scumm/help.cpp:293 msgid "Toggle Keyboard/Mouse Fighting (*)" -msgstr "" +msgstr "Prze³±cz miêdzy walk± klawiatur± a mysz± (*)" #: engines/scumm/help.cpp:295 msgid "* Keyboard Fighting is always on," -msgstr "" +msgstr "* Walka klawiatur± jest zawsze w³±czona," #: engines/scumm/help.cpp:296 msgid " so despite the in-game message this" -msgstr "" +msgstr " wiêc wbrew komunikatowi w grze" #: engines/scumm/help.cpp:297 msgid " actually toggles Mouse Fighting Off/On" -msgstr "" +msgstr " to ustawienie w³±cza/wy³±cza walkê mysz±" #: engines/scumm/help.cpp:304 msgid "Fighting controls (numpad):" @@ -3396,7 +3420,7 @@ msgstr "Niskie uderzenie" #: engines/scumm/help.cpp:315 msgid "Sucker punch" -msgstr "" +msgstr "Cios z zaskoczenia" #: engines/scumm/help.cpp:318 msgid "These are for Indy on left." @@ -3455,23 +3479,20 @@ msgid "Fly to lower right" msgstr "Leæ w dó³, w prawo" #: engines/scumm/input.cpp:580 -#, fuzzy msgid "Snap scroll on" -msgstr "P³ynne przewijanie" +msgstr "Przesuwanie skokowe w³±czone" #: engines/scumm/input.cpp:582 msgid "Snap scroll off" -msgstr "" +msgstr "Przesuwanie skokowe wy³±czone" #: engines/scumm/input.cpp:595 -#, fuzzy msgid "Music volume: " -msgstr "G³o¶no¶æ muzyki:" +msgstr "G³o¶no¶æ muzyki: " #: engines/scumm/input.cpp:612 -#, fuzzy msgid "Subtitle speed: " -msgstr "Prêd. napisów:" +msgstr "Prêd. napisów: " #: engines/scumm/scumm.cpp:1832 #, c-format @@ -3483,27 +3504,86 @@ msgstr "" "ale brakuje %s. Prze³±czam na tryb AdLib." #: engines/scumm/scumm.cpp:2644 -#, fuzzy 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 "" -"Zwykle w tym momencie uruchomi³oby siê Maniac Mansion, ale ScummVM jeszcze " -"tego nie obs³uguje. Aby zagraæ, u¿yj \"Dodaj grê...\" z menu startowego " -"ScummVM i wybierz podkatalog \"Maniac\" z katalogu gry Tentacle." +"Zwykle w tym momencie uruchomi³oby siê Maniac Mansion. Ale ¿eby to " +"zadzia³a³o, pliki Maniac Mansion musz± znajdowaæ siê w podkatalogu \"Maniac" +"\" w katalogu gry Day of the Tentacle, a gra musi byæ dodana do ScummVM." #: 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 "" +"Nie znaleziono pliku wykonywalnego \"Loom\" dla Macintosha do odczytania " +"instrumentów. Muzyka bêdzie wy³±czona." #: 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 "" +"Nie znaleziono pliku wykonywalnego \"Monkey Island\" dla Macintosha do " +"odczytania instrumentów. Muzyka bêdzie wy³±czona." + +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "U¿ywaj oryginalnego ekranu odczytu/zapisu" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" +"Przycisk zapisu w grze wy¶wietla oryginalny ekran odczytu/zapisu zamiast " +"menu ScummVM" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "Pikselizowane przej¶cia miêdzy scenami" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "U¿ywaj losowej pikselizacji przy zmianie sceny" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "Nie wy¶wietlaj hotspotów przy poruszaniu mysz±" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" +"Wy¶wietlaj nazwy hotspotów dopiero po klikniêciu ich lub u¿yciu przycisku " +"akcji" + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "Wy¶wietl portrety postaci" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "Wy¶wietl portrety postaci podczas rozmowy" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "Przysuñ okna" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "Przysuñ okna interfejsu zamiast wy¶wietliæ je od razu" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "Przezroczyste okna" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "Wy¶wietlaj okna z pó³przezroczystym t³em" #: engines/sky/compact.cpp:130 msgid "" @@ -3611,7 +3691,7 @@ msgstr "Poka¿ etykiety obiektów przy najechaniu myszk±" #: engines/teenagent/resources.cpp:95 msgid "" "You're missing the 'teenagent.dat' file. Get it from the ScummVM website" -msgstr "Nie masz pliku 'teenagent.dat'. Pobierz go ze strony ScummVM" +msgstr "Nie masz pliku \"teenagent.dat\". Pobierz go ze strony ScummVM" #: engines/teenagent/resources.cpp:116 msgid "" @@ -3623,52 +3703,47 @@ msgstr "" #: engines/wintermute/detection.cpp:58 msgid "Show FPS-counter" -msgstr "" +msgstr "Poka¿ licznik klatek na sekundê" #: engines/wintermute/detection.cpp:59 msgid "Show the current number of frames per second in the upper left corner" -msgstr "" +msgstr "Wy¶wietl aktualn± liczbê klatek na sekundê w lewym, górnym logu" #: engines/zvision/detection_tables.h:52 -#, fuzzy msgid "Use the original save/load screens instead of the ScummVM interface" -msgstr "U¿yj oryginalnych ekranów odczytu/zapisu zamiast tych ze ScummVM" +msgstr "U¿yj oryginalnych ekranów odczytu/zapisu zamiast interfejsu ScummVM" #: engines/zvision/detection_tables.h:61 msgid "Double FPS" -msgstr "" +msgstr "Podwójna liczba klatek" #: engines/zvision/detection_tables.h:62 msgid "Increase framerate from 30 to 60 FPS" -msgstr "" +msgstr "Zwiêksz liczbê klatek na sekundê z 30 do 60" #: engines/zvision/detection_tables.h:71 -#, fuzzy msgid "Enable Venus" -msgstr "W³±cz tryb helowy" +msgstr "W³±cz Venus" #: engines/zvision/detection_tables.h:72 -#, fuzzy msgid "Enable the Venus help system" -msgstr "W³±cz tryb helowy" +msgstr "W³±cz system pomocy Venus" #: engines/zvision/detection_tables.h:81 msgid "Disable animation while turning" -msgstr "" +msgstr "Wy³±cz animacjê podczas obrotu" #: engines/zvision/detection_tables.h:82 msgid "Disable animation while turning in panorama mode" -msgstr "" +msgstr "Wy³±cz animacjê podczas trybu panoramy" #: engines/zvision/detection_tables.h:91 msgid "Use high resolution MPEG video" -msgstr "" +msgstr "U¿yj wideo MPEG w wysokiej rozdzielczo¶ci" #: engines/zvision/detection_tables.h:92 -#, fuzzy msgid "Use MPEG video from the DVD version, instead of lower resolution AVI" -msgstr "" -"U¿yj alternatywnego zestawu srebrnych kursorów zamiast zwyk³ych z³otych" +msgstr "U¿yj wideo MPEG z wersji DVD zamiast AVI ni¿szej rozdzielczo¶ci" #~ msgid "EGA undithering" #~ msgstr "Anty-dithering EGA" @@ -3720,9 +3795,6 @@ msgstr "" #~ msgid "Enable Roland GS Mode" #~ msgstr "W³±cz tryb Roland GS" -#~ msgid "Save game failed!" -#~ msgstr "Nie uda³o siê zapisaæ stanu gry!" - #~ msgctxt "lowres" #~ msgid "Add Game..." #~ msgstr "Dodaj grê..." diff --git a/po/pt_BR.po b/po/pt_BR.po index 73b6fc8bae..b42ccf2bff 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.3.0svn\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" "PO-Revision-Date: 2011-10-21 21:30-0300\n" "Last-Translator: Saulo Benigno <saulobenigno@gmail.com>\n" "Language-Team: ScummBR (www.scummbr.com) <scummbr@yahoo.com.br>\n" @@ -598,16 +598,16 @@ msgid "Search:" msgstr "Pesquisar:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Carregar jogo:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Carregar" @@ -779,7 +779,7 @@ msgid "Special dithering modes supported by some games" msgstr "Modos especiais de dithering suportados por alguns jogos" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Modo Tela Cheia" @@ -1387,12 +1387,12 @@ msgstr "" msgid "PC-9801 (16 Colors)" msgstr "" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Hercules Green" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Hercules Amber" @@ -1444,11 +1444,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "~V~oltar ao menu" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Salvar jogo:" @@ -1457,11 +1461,15 @@ msgstr "Salvar jogo:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Salvar" @@ -1793,19 +1801,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Normal (sem escala)" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "Correção de proporção habilitada" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "Correção de proporção desabilitada" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Ativa os filtros gráficos" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Modo janela" @@ -2371,15 +2379,23 @@ msgid "" "Enables mouse support. Allows to use mouse for movement and in game menus." msgstr "" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Restaurar jogo:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Restaurar" @@ -2707,10 +2723,20 @@ msgstr "" "Não é possível salvar o jogo na posição %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +#, fuzzy +msgid "Load file" +msgstr "Carregar jogo:" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Carregando jogo..." +#: engines/parallaction/saveload.cpp:212 +#, fuzzy +msgid "Save file" +msgstr "Falha ao salvar jogo!" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Salvando jogo..." @@ -3559,6 +3585,59 @@ msgid "" "instruments from. Music will be disabled." msgstr "" +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" + +#: engines/sherlock/detection.cpp:101 +#, fuzzy +msgid "Show character portraits" +msgstr "Trocador de caracteres" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "" + #: engines/sky/compact.cpp:130 msgid "" "Unable to find \"sky.cpt\" file!\n" @@ -3772,9 +3851,6 @@ msgstr "" #~ msgid "Enable Roland GS Mode" #~ msgstr "Ligar modo Roland GS" -#~ msgid "Save game failed!" -#~ msgstr "Falha ao salvar jogo!" - #~ msgctxt "lowres" #~ msgid "Add Game..." #~ msgstr "Adicionar Jogo..." diff --git a/po/ru_RU.po b/po/ru_RU.po index be2d972979..ba91013bb5 100644 --- a/po/ru_RU.po +++ b/po/ru_RU.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.8.0svn\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" -"PO-Revision-Date: 2016-02-02 20:38+0300\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" +"PO-Revision-Date: 2016-02-21 23:32+0300\n" "Last-Translator: Eugene Sandulenko <sev@scummvm.org>\n" "Language-Team: Russian\n" "Language: Russian\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Poedit 1.8.6\n" +"X-Generator: Poedit 1.8.7\n" #: gui/about.cpp:94 #, c-format @@ -591,16 +591,16 @@ msgid "Search:" msgstr "¿ÞØáÚ:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "·ÐÓàã×Øâì ØÓàã:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "·ÐÓàã×Øâì" @@ -763,7 +763,7 @@ msgid "Special dithering modes supported by some games" msgstr "ÁßÕæØÐÛìÝëÕ àÕÖØÜë àÕÝÔÕàØÝÓÐ, ßÞÔÔÕàÖØÒÐÕÜëÕ ÝÕÚÞâÞàëÜØ ØÓàÐÜØ" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "¿ÞÛÝÞíÚàÐÝÝëÙ àÕÖØÜ" @@ -1362,12 +1362,12 @@ msgstr "PC-9821 (256 æÒÕâÞÒ)" msgid "PC-9801 (16 Colors)" msgstr "PC-9801 (16 æÒÕâÞÒ)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Hercules ·ÕÛñÝëÙ" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Hercules ÏÝâÐàÝëÙ" @@ -1419,11 +1419,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "~²~ ÓÛÐÒÝÞÕ ÜÕÝî" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "ÁÞåàÐÝØâì ØÓàã:" @@ -1432,11 +1436,15 @@ msgstr "ÁÞåàÐÝØâì ØÓàã:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "ÁÞåàÐÝØâì" @@ -1634,7 +1642,7 @@ msgstr "ÍÜãÛïâÞà MT-32" #: audio/softsynth/pcspk.cpp:139 msgid "PC Speaker Emulator" -msgstr "ÍÜãÛïâÞà PC áßØÚÕàÐ" +msgstr "ÍÜãÛïâÞà PC-áßØÚÕàÐ" #: audio/softsynth/pcspk.cpp:158 msgid "IBM PCjr Emulator" @@ -1718,7 +1726,7 @@ msgstr "²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ÒëÙâØ?" #. I18N: Trackpad mode toggle status. #: backends/events/webossdl/webossdl-events.cpp:308 msgid "Trackpad mode is now" -msgstr "ÀÕÖØÜ âàÕÚßÐÔÐ ÒÚÛîçÕÝ." +msgstr "ÀÕÖØÜ âàÕÚßÐÔÐ áÕÙçÐá" #. I18N: Trackpad mode on or off. #. I18N: Auto-drag on or off. @@ -1739,7 +1747,7 @@ msgstr "¿àÞÒÕÔØâÕ ÔÒãÜï ßÐÛìæÐÜØ ÝÐßàÐÒÞ ÔÛï ßÕàÕÚÛîçÕÝØï." #. I18N: Auto-drag toggle status. #: backends/events/webossdl/webossdl-events.cpp:335 msgid "Auto-drag mode is now" -msgstr "ÀÕÖØÜ ÐÒâÞ-ÔàÕÓ ÒÚÛîçÕÝ" +msgstr "ÀÕÖØÜ ÐÒâÞÔàíÓÐ áÕÙçÐá" #: backends/events/webossdl/webossdl-events.cpp:342 msgid "Swipe three fingers to the right to toggle." @@ -1764,19 +1772,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "±Õ× ãÒÕÛØçÕÝØï" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "ºÞààÕÚæØï áÞÞâÝÞèÕÝØï áâÞàÞÝ ÒÚÛîçÕÝÐ" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "ºÞààÕÚæØï áÞÞâÝÞèÕÝØï áâÞàÞÝ ÒëÚÛîçÕÝÐ" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "°ÚâØÒÝëÙ ÓàÐäØçÕáÚØÙ äØÛìâà:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "¾ÚÞÝÝëÙ àÕÖØÜ" @@ -1951,7 +1959,7 @@ msgstr "¾ÚÝÞ" #: backends/platform/sdl/macosx/appmenu_osx.mm:125 msgid "Minimize" -msgstr "ÃÑàÐâì Ò Dock" +msgstr "ÁÒÕàÝãâì" #: backends/platform/symbian/src/SymbianActions.cpp:38 #: backends/platform/wince/CEActionsSmartphone.cpp:39 @@ -2082,11 +2090,11 @@ msgstr "²ÒÞÔ" #: backends/platform/wii/options.cpp:74 msgid "GC Pad sensitivity:" -msgstr "ÇãÒáâÒØâÕÛìÝÞáâì GC ßÐÔÐ:" +msgstr "ÇãÒáâÒØâÕÛìÝÞáâì GC-ßÐÔÐ:" #: backends/platform/wii/options.cpp:80 msgid "GC Pad acceleration:" -msgstr "ÃáÚÞàÕÝØÕ GC ßÐÔÐ:" +msgstr "ÃáÚÞàÕÝØÕ GC-ßÐÔÐ:" #: backends/platform/wii/options.cpp:86 msgid "DVD" @@ -2282,7 +2290,7 @@ msgstr "½Ð×ÝÐçØâì ÔÕÙáâÒØÕ 'áßàïâÐâì ßÐÝÕÛì ØÝáâàãÜÕÝâÞÒ'" #: backends/platform/wince/wince-sdl.cpp:533 msgid "You must map a key to the 'Hide toolbar' action to play this game" -msgstr "²ë ÔÞÛÖÝë ÝÐ×ÝÐçØâì ÚÛÐÒØèã ÝÐ ÔÕÙâáâÒØÕ 'Hide toolbar' ÔÛï íâÞÙ ØÓàë" +msgstr "²ë ÔÞÛÖÝë ÝÐ×ÝÐçØâì ÚÛÐÒØèã ÝÐ ÔÕÙáâÒØÕ 'Hide toolbar' ÔÛï íâÞÙ ØÓàë" #: backends/platform/wince/wince-sdl.cpp:542 msgid "Map Zoom Up action (optional)" @@ -2316,7 +2324,7 @@ msgstr "¸áßÞÛì×ÞÒÐâì ÞàØÓØÝÐÛìÝëÕ íÚàÐÝë ×ÐßØáØ/çâÕÝØï ØÓàë" #: engines/toltecs/detection.cpp:201 msgid "Use the original save/load screens, instead of the ScummVM ones" msgstr "" -"¸áßÞÛì×ÞÒÐâì ÞàØÓØÝÐÛìÝëÕ íÚàÐÝë ×ÐßØáØ Ø áÞåàÐÝÕÝØï ØÓàë ÒÜÕáâÞ áÔÕÛÐÝÝëå Ò " +"¸áßÞÛì×ÞÒÐâì ÞàØÓØÝÐÛìÝëÕ íÚàÐÝë çâÕÝØï Ø áÞåàÐÝÕÝØï ØÓàë ÒÜÕáâÞ áÔÕÛÐÝÝëå Ò " "ScummVM" #: engines/agi/detection.cpp:157 @@ -2342,15 +2350,23 @@ msgstr "" "²ÚÛîçÐÕâ ßÞÔÔÕàÖÚã ÜëèØ. ¿Þ×ÒÞÛïÕâ ØáßÞÛì×ÞÒÐâì Üëèì ÔÛï ßÕàÕÜÕéÕÝØï Ø Ò " "ÜÕÝî ØÓàë." -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "²ÞááâÐÝÞÒØâì ØÓàã:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "²ÞááâÐÝÞÒØâì" @@ -2596,7 +2612,7 @@ msgstr "" "\n" "%s %s\n" "\n" -"½Õ ÖÕÛÐÕâÕ ÛØ ØáßÞÛì×ÞÒÐâì íâÞ áÞåàÐÝÕÝØÕ Ò ScummVM?\n" +"²ë åÞâØâÕ ØáßÞÛì×ÞÒÐâì íâÞ áÞåàÐÝÕÝØÕ Ò ScummVM?\n" "\n" #: engines/kyra/saveload_eob.cpp:590 @@ -2674,10 +2690,18 @@ msgstr "" "½Õ ÜÞÓã áÞåàÐÝØâì ØÓàã Ò ßÞ×ØæØî %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +msgid "Load file" +msgstr "·ÐÓàã×Øâì äÐÙÛ" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "·ÐÓàãÖÐî ØÓàã..." +#: engines/parallaction/saveload.cpp:212 +msgid "Save file" +msgstr "ÁÞåàÐÝØâì äÐÙÛ" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "ÁÞåàÐÝïî ØÓàã..." @@ -2721,11 +2745,11 @@ msgstr "½ÕÒÕàÝÞÕ ØÜï äÐÙÛÐ áÞåàÐÝÕÝØï" #: engines/pegasus/pegasus.cpp:2507 msgid "Up/Zoom In/Move Forward/Open Doors" -msgstr "²ÒÕàå/ÃÜÕÝìèØâì ÜÐáèâÐÑ/²ßÕàñÔ/¾âÚàëâì ÔÒÕàØ" +msgstr "²ÒÕàå/ÃÒÕÛ. ÜÐáèâÐÑ/²ßÕàñÔ/¾âÚàëâì ÔÒÕàØ" #: engines/pegasus/pegasus.cpp:2508 msgid "Down/Zoom Out" -msgstr "²ÝØ×/ÃÒÕÛ. ÜÐáèâÐÑ" +msgstr "²ÝØ×/ÃÜÕÝìè. ÜÐáèâÐÑ" #: engines/pegasus/pegasus.cpp:2511 msgid "Display/Hide Inventory Tray" @@ -2757,7 +2781,7 @@ msgstr "°ÛìâÕàÝÐâØÒÝÞÕ ÒáâãßÛÕÝØÕ" #: engines/queen/detection.cpp:57 msgid "Use an alternative game intro (CD version only)" -msgstr "¸áßÞÛì×ÞÒÐâì ÐÛìâÕàÝÐâØÒÝÞÕ ÒáâãßÛÕÝØÕ (âÞÛìÚÞ ÔÛï CD ÒÕàáØØ ØÓàë)" +msgstr "¸áßÞÛì×ÞÒÐâì ÐÛìâÕàÝÐâØÒÝÞÕ ÒáâãßÛÕÝØÕ (âÞÛìÚÞ ÔÛï CD-ÒÕàáØØ ØÓàë)" #: engines/sci/detection.cpp:374 msgid "Skip EGA dithering pass (full color backgrounds)" @@ -2935,7 +2959,7 @@ msgstr "²ëÑÕàØâÕ ãàÞÒÕÝì áÛÞÖÝÞáâØ." #: engines/scumm/dialogs.cpp:660 msgid "Refer to your Loom(TM) manual for help." -msgstr "·Ð ßÞÜÞéìî ÞÑàÐâØâÕáì Ú ØÝáâãÚæØØ Loom(TM)" +msgstr "·Ð ßÞÜÞéìî ÞÑàÐâØâÕáì Ú ØÝáâàãÚæØØ Loom(TM)." #: engines/scumm/dialogs.cpp:664 msgid "Practice" @@ -3005,7 +3029,7 @@ msgstr "³àÞÜÚÞáâì Üã×ëÚØ ãÒÕÛØçØâì / ãÜÕÝìèØâì" #: engines/scumm/help.cpp:89 msgid "Text speed slower / faster" -msgstr "ÁÚÞàÞáâì âÕÚáâÐ ÑëáâàÕÕ / ÜÕÔÛÕÝÝÕÕ" +msgstr "ÁÚÞàÞáâì âÕÚáâÐ ÜÕÔÛÕÝÝÕÕ / ÑëáâàÕÕ" #: engines/scumm/help.cpp:90 msgid "Simulate left mouse button" @@ -3025,7 +3049,7 @@ msgstr "ÁßÕæØÐÛìÝëÕ ÚÛÐÒØÐâãàÝëÕ ÚÞÜÐÝÔë:" #: engines/scumm/help.cpp:95 msgid "Show / Hide console" -msgstr "¿ÞÚÐ×Ðâì / ÃÑàÐâì ÚÞÝáÞÛì" +msgstr "¿ÞÚÐ×Ðâì / ãÑàÐâì ÚÞÝáÞÛì" #: engines/scumm/help.cpp:96 msgid "Start the debugger" @@ -3053,7 +3077,7 @@ msgstr "¿ÕàÕÚÛîçÕÝØÕ ÜÕÖÔã ÓàÐäØçÕáÚØÜØ äØÛìâàÐÜØ" #: engines/scumm/help.cpp:102 msgid "Increase / Decrease scale factor" -msgstr "ÃÒÕÛØçØâì/ãÜÕÝìèØâì ÜÐáèâÐÑ" +msgstr "ÃÒÕÛØçØâì / ãÜÕÝìèØâì ÜÐáèâÐÑ" #: engines/scumm/help.cpp:103 msgid "Toggle aspect-ratio correction" @@ -3187,7 +3211,7 @@ msgstr "¿ãâÕèÕáâÒÞÒÐâì" #: engines/scumm/help.cpp:176 msgid "To Henry / To Indy" -msgstr "³ÕÝàØ/¸ÝÔØ" +msgstr "³ÕÝàØ / ¸ÝÔØ" #. I18N: These are different musical notes #: engines/scumm/help.cpp:180 @@ -3371,7 +3395,7 @@ msgstr "¿ÕàÕÚÛîçØâì ßÞÚÐ× ØÝÒÕÝâÐàï/ÞçÚÞÒ IQ" #: engines/scumm/help.cpp:293 msgid "Toggle Keyboard/Mouse Fighting (*)" -msgstr "¿ÕàÕÚÛîçØâì ãßàÐÒÛÕÝØÕ ÑÞïÜØ ºÛÐÒØÐâãàÞÙ/¼ëèìî (*)" +msgstr "¿ÕàÕÚÛîçØâì ãßàÐÒÛÕÝØÕ ÑÞïÜØ ÚÛÐÒØÐâãàÞÙ/Üëèìî (*)" #: engines/scumm/help.cpp:295 msgid "* Keyboard Fighting is always on," @@ -3484,7 +3508,7 @@ msgstr "¿àÞÚàãâÚÐ áÚÐçÚÐÜØ ÒÚÛîçÕÝÐ" #: engines/scumm/input.cpp:582 msgid "Snap scroll off" -msgstr "¿àÞÚàãâÚÐ áÚÐçÚÐÜØ ÒëÚÛ" +msgstr "¿àÞÚàãâÚÐ áÚÐçÚÐÜØ ÒëÚÛîçÕÝÐ" #: engines/scumm/input.cpp:595 msgid "Music volume: " @@ -3529,6 +3553,62 @@ msgstr "" "½Õ ãÔÐÛÞáì ÝÐÙâØ ØáßÞÛÝØÜëÙ äÐÙÛ 'Monkey Island' Macintosh, çâÞÑë ßàÞçØâÐâì\n" "ÔÐÝÝëÕ ÞÑ ØÝáâàãÜÕÝâÐå. ¼ã×ëÚÐ ÑãÔÕâ ÒëÚÛîçÕÝÐ." +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "¸áßÞÛì×ÞÒÐâì ÞàØÓØÝÐÛìÝëÕ íÚàÐÝë ×ÐßØáØ/çâÕÝØï ØÓàë" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" +"ºÝÞßÚÐ \"ÄÐÙÛë\" Ò ØÓàÕ ßÞÚÐ×ëÒÐÕâ ÞàØÓØÝÐÛìÝëÙ ÔØÐÛÞÓ áÞåàÐÝÕÝØï, Ð ÝÕ ÜÕÝî " +"ScummVM" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "¿ÕàÕåÞÔë ÜÕÖÔã áæÕÝÐÜØ á ßØÚáÕÛØ×ÐæØÕÙ" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "¿àØ áÜÕÝÕ áæÕÝ ßàÞØáåÞÔØâ ßÕàÕåÞÔ á àÐÝÔÞÜØ×ØàÞÒÐÝÝëÜØ ßØÚáÕÛïÜØ" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "½Õ ßÞÚÐ×ëÒÐâì åÞâáßÞâë ßàØ ÝÐÒÕÔÕÝØØ Üëèìî" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" +"¿ÞÚÐ×ëÒÐâì ÝÐ×ÒÐÝØï åÞâáßÞâÞÒ âÞÛìÚÞ ßÞáÛÕ ÚÛØÚÐ ßÞ ÝØÜ ÛØÑÞ ßÞáÛÕ ÝÐÖÐâØï " +"ÝÐ ÚÝÞßÚã ÔÕÙáâÒØï" + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "¿ÞÚÐ×ëÒÐâì ßÞàâàÕâë ÓÕàÞÕÒ" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "¿ÞÚÐ×ëÒÐâì ßÞàâàÕâë ÓÕàÞÕÒ ÒÞ ÒàÕÜï ÔØÐÛÞÓÞÒ" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "²êÕ×ÖÐîéØÕ ÔØÐÛÞÓØ" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "´ØÐÛÞÓØ ÑãÔãâ ÒêÕ×ÖÐâì, Ð ÝÕ ßÞÚÐ×ëÒÐâìáï ÜÓÝÞÒÕÝÝÞ" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "¿àÞ×àÐçÝëÕ ÞÚÝÐ" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "¿ÞÚÐ×ëÒÐâì ÞÚÝÐ á çÐáâØçÝÞ ßàÞ×àÐçÝëÜ äÞÝÞÜ" + #: engines/sky/compact.cpp:130 msgid "" "Unable to find \"sky.cpt\" file!\n" @@ -3547,7 +3627,7 @@ msgstr "" #: engines/sky/detection.cpp:44 msgid "Floppy intro" -msgstr "²áâãßÛÕÝØÕ á äÛÞßßØÚÞÒ" +msgstr "²áâãßÛÕÝØÕ á ÔØáÚÕâ" #: engines/sky/detection.cpp:45 msgid "Use the floppy version's intro (CD version only)" @@ -3584,7 +3664,8 @@ msgid "" "Press OK to convert them now, otherwise you will be asked again the next " "time you start the game.\n" msgstr "" -"ScummVM ÞÑÝÐàãÖØÛ ã ÒÐá áÞåàÐÝÕÝØï ØÓàë ÁÛÞÜÐÝÝëÙ ¼Õç Ò áâÐàÞÜ äÞàÜÐâÕ.\n" +"ScummVM ÞÑÝÐàãÖØÛ ã ÒÐá áÞåàÐÝÕÝØï ØÓàë \"ÁÛÞÜÐÝÝëÙ ÜÕç 1\" Ò áâÐàÞÜ " +"äÞàÜÐâÕ.\n" "ÁâÐàëÙ äÞàÜÐâ ÑÞÛìèÕ ÝÕ ßÞÔÔÕàÖØÒÐÕâáï, Ø, çâÞÑë ×ÐÓàã×Øâì áÞåàÐÝÕÝØï, ÞÝØ " "ÔÞÛÖÝë Ñëâì ßÕàÕÒÕÔÕÝë Ò ÝÞÒëÙ äÞàÜÐâ.\n" "\n" @@ -3610,13 +3691,13 @@ msgstr "ÁÔÕÛÐâì ÝÞÒÞÕ" #: engines/sword1/logic.cpp:1633 msgid "This is the end of the Broken Sword 1 Demo" -msgstr "ÍâÞ ×ÐÒÕàèÕÝØÕ ÔÕÜÞ ÁÛÞÜÐÝÝÞÓÞ ¼ÕçÐ 1" +msgstr "ÍâÞ ×ÐÒÕàèÕÝØÕ ÔÕÜÞ \"ÁÛÞÜÐÝÝÞÓÞ ÜÕçÐ 1\"" #: engines/sword2/animation.cpp:425 msgid "" "PSX cutscenes found but ScummVM has been built without RGB color support" msgstr "" -"½ÐÙÔÕÝë ×ÐáâÐÒÚØ Ò äÞàÜÐâÕ PSX, ÝÞ ScummVM ÑëÛ áÞÑàÐÝ ÑÕ× ßÞÔÔÕàÖÚØ RGB " +"½ÐÙÔÕÝë ×ÐáâÐÒÚØ Ò äÞàÜÐâÕ PSX, ÝÞ ScummVM ÑëÛ áÞÑàÐÝ ÑÕ× ßÞÔÔÕàÖÚØ RGB-" "æÒÕâÞÒ" #: engines/sword2/sword2.cpp:79 @@ -3740,9 +3821,6 @@ msgstr "" #~ msgid "Enable Roland GS Mode" #~ msgstr "²ÚÛîçØâì àÕÖØÜ Roland GS" -#~ msgid "Save game failed!" -#~ msgstr "½Õ ãÔÐÛÞáì áÞåàÐÝØâì ØÓàã!" - #~ msgctxt "lowres" #~ msgid "Add Game..." #~ msgstr "´ÞÑ. ØÓàã" diff --git a/po/scummvm.pot b/po/scummvm.pot index 255200110d..1edbe00e20 100644 --- a/po/scummvm.pot +++ b/po/scummvm.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: ScummVM 1.8.0git\n" +"Project-Id-Version: ScummVM 1.9.0git\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -584,16 +584,16 @@ msgid "Search:" msgstr "" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "" @@ -754,7 +754,7 @@ msgid "Special dithering modes supported by some games" msgstr "" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "" @@ -1338,12 +1338,12 @@ msgstr "" msgid "PC-9801 (16 Colors)" msgstr "" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "" @@ -1394,11 +1394,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "" @@ -1407,11 +1411,15 @@ msgstr "" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "" @@ -1708,19 +1716,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "" @@ -2278,15 +2286,23 @@ msgid "" "Enables mouse support. Allows to use mouse for movement and in game menus." msgstr "" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "" @@ -2573,10 +2589,18 @@ msgid "" "\n" msgstr "" +#: engines/parallaction/saveload.cpp:197 +msgid "Load file" +msgstr "" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "" +#: engines/parallaction/saveload.cpp:212 +msgid "Save file" +msgstr "" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "" @@ -3398,6 +3422,58 @@ msgid "" "instruments from. Music will be disabled." msgstr "" +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "" + #: engines/sky/compact.cpp:130 msgid "" "Unable to find \"sky.cpt\" file!\n" diff --git a/po/se_SE.po b/po/sv_SE.po index a3a644501f..82357b4dc2 100644 --- a/po/se_SE.po +++ b/po/sv_SE.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.5.0svn\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" -"PO-Revision-Date: 2014-07-02 16:30+0100\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" +"PO-Revision-Date: 2016-02-25 23:06+0100\n" "Last-Translator: Hampus Flink <hampus.flink@gmail.com>\n" "Language-Team: \n" "Language: Svenska\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SourceCharset: iso-8859-1\n" -"X-Generator: Poedit 1.6.5\n" +"X-Generator: Poedit 1.8.7\n" #: gui/about.cpp:94 #, c-format @@ -30,7 +30,7 @@ msgstr "Funktioner kompilerade i:" #: gui/about.cpp:110 msgid "Available engines:" -msgstr "Tillgängliga motorer" +msgstr "Tillgängliga motorer:" #: gui/browser.cpp:68 gui/browser_osx.mm:104 msgid "Show hidden files" @@ -75,7 +75,7 @@ msgstr "Välj" #: gui/editrecorddialog.cpp:58 msgid "Author:" -msgstr "" +msgstr "Skapare:" #: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204 msgid "Name:" @@ -83,24 +83,23 @@ msgstr "Namn:" #: gui/editrecorddialog.cpp:60 msgid "Notes:" -msgstr "" +msgstr "Anteckningar:" #: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74 msgid "Ok" -msgstr "" +msgstr "OK" #: gui/filebrowser-dialog.cpp:49 msgid "Choose file for loading" -msgstr "" +msgstr "Välj en fil att ladda" #: gui/filebrowser-dialog.cpp:49 msgid "Enter filename for saving" -msgstr "" +msgstr "Ange ett filnamn för att spara" #: gui/filebrowser-dialog.cpp:132 -#, fuzzy msgid "Do you really want to overwrite the file?" -msgstr "Vill du verkligen radera den här spardatan?" +msgstr "Vill du verkligen skriva över filen?" #: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217 #: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002 @@ -594,16 +593,16 @@ msgid "Search:" msgstr "Sök:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "Ladda spel:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "Ladda" @@ -651,7 +650,7 @@ msgstr "Masstillägg..." #: gui/launcher.cpp:1163 msgid "Record..." -msgstr "" +msgstr "Spela in..." #: gui/massadd.cpp:79 gui/massadd.cpp:82 msgid "... progress ..." @@ -678,21 +677,19 @@ msgstr "Upptäckte %d nya spel, ignorerade %d tidigare tillagda spel ..." #: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103 msgid "Stop" -msgstr "" +msgstr "Stopp" #: gui/onscreendialog.cpp:106 msgid "Edit record description" -msgstr "" +msgstr "Redigera beskrivning av inspelning" #: gui/onscreendialog.cpp:108 -#, fuzzy msgid "Switch to Game" -msgstr "Byt" +msgstr "Växla till spelet" #: gui/onscreendialog.cpp:110 -#, fuzzy msgid "Fast replay" -msgstr "Snabbläge" +msgstr "Snabb uppspelning" #: gui/options.cpp:85 msgid "Never" @@ -769,7 +766,7 @@ msgid "Special dithering modes supported by some games" msgstr "Speciella gitterlägen stödda av vissa spel" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "Fullskärmsläge" @@ -1085,39 +1082,38 @@ msgstr "" #. I18N: You must leave "#" as is, only word 'next' is translatable #: gui/predictivedialog.cpp:86 msgid "# next" -msgstr "" +msgstr "# nästa" #: gui/predictivedialog.cpp:87 msgid "add" -msgstr "" +msgstr "Lägg till" #: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164 -#, fuzzy msgid "Delete char" -msgstr "Radera" +msgstr "Radera tecken" #: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168 msgid "<" -msgstr "" +msgstr "<" #. I18N: Pre means 'Predictive', leave '*' as is #: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572 msgid "* Pre" -msgstr "" +msgstr "* Pre." #. I18N: 'Num' means Numbers #: gui/predictivedialog.cpp:575 msgid "* Num" -msgstr "" +msgstr "* 123" #. I18N: 'Abc' means Latin alphabet input #: gui/predictivedialog.cpp:578 msgid "* Abc" -msgstr "" +msgstr "* ABC" #: gui/recorderdialog.cpp:64 msgid "Recorder or Playback Gameplay" -msgstr "" +msgstr "Inspelare eller återuppspelning" #: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156 #: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276 @@ -1126,36 +1122,33 @@ msgstr "Radera" #: gui/recorderdialog.cpp:71 msgid "Record" -msgstr "" +msgstr "Spela in" #: gui/recorderdialog.cpp:72 -#, fuzzy msgid "Playback" -msgstr "Spela" +msgstr "Spela upp" #: gui/recorderdialog.cpp:74 msgid "Edit" -msgstr "" +msgstr "Redigera" #: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243 #: gui/recorderdialog.cpp:253 msgid "Author: " -msgstr "" +msgstr "Skapare: " #: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244 #: gui/recorderdialog.cpp:254 msgid "Notes: " -msgstr "" +msgstr "Anteckningar: " #: gui/recorderdialog.cpp:155 -#, fuzzy msgid "Do you really want to delete this record?" -msgstr "Vill du verkligen radera den här spardatan?" +msgstr "Vill du verkligen radera den här inspelningen?" #: gui/recorderdialog.cpp:174 -#, fuzzy msgid "Unknown Author" -msgstr "Okänt fel" +msgstr "Okänd skapare" #: gui/saveload-dialog.cpp:167 msgid "List view" @@ -1362,18 +1355,18 @@ msgstr "Herkules bärnsten" #: common/rendermode.cpp:42 msgid "PC-9821 (256 Colors)" -msgstr "" +msgstr "PC-9821 (256 färger)" #: common/rendermode.cpp:43 msgid "PC-9801 (16 Colors)" -msgstr "" +msgstr "PC-9801 (16 färger)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Herkules grön" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Herkules bärnsten" @@ -1425,11 +1418,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "Åte~r~vänd till launcher" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Spara spelet:" @@ -1438,11 +1435,15 @@ msgstr "Spara spelet:" #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "Spara" @@ -1560,7 +1561,7 @@ msgstr "DOSBox OPL-emulator" #: audio/fmopl.cpp:67 msgid "ALSA Direct FM" -msgstr "" +msgstr "ALSA Direct FM" #: audio/mididrv.cpp:209 #, c-format @@ -1617,17 +1618,15 @@ msgstr "Apple II GS-emulator (INTE IMPLEMENTERAD)" #: audio/softsynth/cms.cpp:350 msgid "Creative Music System Emulator" -msgstr "" +msgstr "Creative Music System-emulator" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33 -#, fuzzy msgid "FM-Towns Audio" -msgstr "FM Towns-emulator" +msgstr "FM Towns-ljud" #: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58 -#, fuzzy msgid "PC-98 Audio" -msgstr "Ljud" +msgstr "PC-98 ljud" #: audio/softsynth/mt32.cpp:200 msgid "Initializing MT-32 Emulator" @@ -1722,34 +1721,33 @@ msgstr "Vill du avsluta?" #. I18N: Trackpad mode toggle status. #: backends/events/webossdl/webossdl-events.cpp:308 -#, fuzzy msgid "Trackpad mode is now" -msgstr "Touchpad-läge inaktiverat." +msgstr "Trackpad-läge " #. 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 "" +msgstr "PÅ" #: backends/events/webossdl/webossdl-events.cpp:311 #: backends/events/webossdl/webossdl-events.cpp:338 msgid "OFF" -msgstr "" +msgstr "AV" #: backends/events/webossdl/webossdl-events.cpp:315 msgid "Swipe two fingers to the right to toggle." -msgstr "" +msgstr "Svep åt höger med två fingrar för att byta läge." #. I18N: Auto-drag toggle status. #: backends/events/webossdl/webossdl-events.cpp:335 msgid "Auto-drag mode is now" -msgstr "" +msgstr "Automatiskt dragläge " #: backends/events/webossdl/webossdl-events.cpp:342 msgid "Swipe three fingers to the right to toggle." -msgstr "" +msgstr "Svep åt höger med tre fingrar för att byta läge." #: backends/graphics/opengl/opengl-graphics.cpp:119 msgid "OpenGL" @@ -1770,19 +1768,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "Normalt (ingen skalning)" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "Korrektion av bildförhållande på" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "Korrektion av bildförhållande av" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "Aktivt grafikfilter:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "Fönsterläge" @@ -2044,24 +2042,23 @@ msgstr "Kontrollera musen" #: backends/platform/tizen/fs.cpp:259 msgid "[ Data ]" -msgstr "" +msgstr "[ Data ]" #: backends/platform/tizen/fs.cpp:263 msgid "[ Resources ]" -msgstr "" +msgstr "[ Resurser ]" #: backends/platform/tizen/fs.cpp:267 msgid "[ SDCard ]" -msgstr "" +msgstr "[ SD-kort ]" #: backends/platform/tizen/fs.cpp:271 msgid "[ Media ]" -msgstr "" +msgstr "[ Media ]" #: backends/platform/tizen/fs.cpp:275 -#, fuzzy msgid "[ Shared ]" -msgstr "Delad:" +msgstr "[ Delad ]" #: backends/platform/wii/options.cpp:51 msgid "Video" @@ -2328,35 +2325,45 @@ msgid "Use the original save/load screens, instead of the ScummVM ones" msgstr "Använder originalskärmarna för spara/ladda istället för ScummVM:s" #: engines/agi/detection.cpp:157 -#, fuzzy msgid "Use an alternative palette" -msgstr "Använd alternativt spelintro (endast CD-version)" +msgstr "Använd alternativ färgkarta" #: engines/agi/detection.cpp:158 msgid "" "Use an alternative palette, common for all Amiga games. This was the old " "behavior" msgstr "" +"Använd en alternativ färgkarta typisk för alla Amiga-spel. Det här är det " +"mala beteendet" #: engines/agi/detection.cpp:167 -#, fuzzy msgid "Mouse support" -msgstr "Skipp-stöd" +msgstr "Musstöd" #: engines/agi/detection.cpp:168 msgid "" "Enables mouse support. Allows to use mouse for movement and in game menus." msgstr "" +"Aktiverar musstöd. Möjliggör användning av musen för rörelser och i " +"spelmenyer." -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Återställ spel:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "Återställ" @@ -2399,13 +2406,12 @@ msgid "Cutscene file '%s' not found!" msgstr "Filmscensfilen '%s' hittades ej!" #: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101 -#, fuzzy msgid "Color Blind Mode" -msgstr "Klickläge" +msgstr "Färgblint läge" #: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102 msgid "Enable Color Blind Mode by default" -msgstr "" +msgstr "Aktivera färgblint läge som standard" #: engines/drascula/saveload.cpp:47 msgid "" @@ -2461,11 +2467,11 @@ msgstr "Kunde inte spara spelet." #: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86 msgid "Gore Mode" -msgstr "" +msgstr "Våldsamt läge" #: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87 msgid "Enable Gore Mode when available" -msgstr "" +msgstr "Aktivera våldsamt läge om tillgängligt" #. I18N: Studio audience adds an applause and cheering sounds whenever #. Malcolm makes a joke. @@ -2597,6 +2603,13 @@ msgid "" "Do you wish to use this save game file with ScummVM?\n" "\n" msgstr "" +"Följande originalspardata hittades i sökvägen för ditt spel:\n" +"\n" +"%s %s\n" +"\n" +"Vill du använda den här spardatan med ScummVM?\n" +"\n" +"\n" #: engines/kyra/saveload_eob.cpp:590 #, c-format @@ -2604,6 +2617,8 @@ msgid "" "A save game file was found in the specified slot %d. Overwrite?\n" "\n" msgstr "" +"En sparfil hittades på den angivna platsen %d. Vill du skriva över den?\n" +"\n" #: engines/kyra/saveload_eob.cpp:623 #, c-format @@ -2615,6 +2630,11 @@ msgid "" "'import_savefile'.\n" "\n" msgstr "" +"%d originalspardata har importerats till ScummVM.\n" +"Om du vill importera originalspardata manuellt måste du öppna " +"debuggkonsolen\n" +"och använda kommandot 'import_savefile'.\n" +"\n" #. I18N: Option for fast scene switching #: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167 @@ -2667,10 +2687,20 @@ msgstr "" "Kan inte spara data i position %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +#, fuzzy +msgid "Load file" +msgstr "Ladda spel:" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "Laddar speldata..." +#: engines/parallaction/saveload.cpp:212 +#, fuzzy +msgid "Save file" +msgstr "Spara spelet:" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "Sparar speldata..." @@ -2754,21 +2784,19 @@ msgstr "Använd alternativt spelintro (endast CD-version)" #: engines/sci/detection.cpp:374 msgid "Skip EGA dithering pass (full color backgrounds)" -msgstr "" +msgstr "Skippa EGA-gitterpass (bakgrunder i full färg)" #: engines/sci/detection.cpp:375 msgid "Skip dithering pass in EGA games, graphics are shown with full colors" -msgstr "" +msgstr "Skippa gitterpass i EGA-spel. Grafik visas i full färg." #: engines/sci/detection.cpp:384 -#, fuzzy msgid "Enable high resolution graphics" -msgstr "Aktivera livmätare" +msgstr "Aktivera högupplöst grafik" #: engines/sci/detection.cpp:385 -#, fuzzy msgid "Enable high resolution graphics/content" -msgstr "Aktivera livmätare" +msgstr "Aktivera högupplöst grafik/innehåll" #: engines/sci/detection.cpp:394 msgid "Prefer digital sound effects" @@ -2841,13 +2869,11 @@ msgstr "Spelet pausat. Tryck MELLANSLAG för att fortsätta." #. "Moechten Sie wirklich neu starten? (J/N)J" #. Will react to J as 'Yes' #: engines/scumm/dialogs.cpp:183 -#, fuzzy msgid "Are you sure you want to restart? (Y/N)Y" msgstr "Är du säker på att du vill starta om? (J/N)J" #. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment #: engines/scumm/dialogs.cpp:185 -#, fuzzy msgid "Are you sure you want to quit? (Y/N)Y" msgstr "Är du säker på att du vill avsluta? (J/N)J" @@ -3357,25 +3383,24 @@ msgid "Third kid" msgstr "Tredje ungen" #: engines/scumm/help.cpp:292 -#, fuzzy msgid "Toggle Inventory/IQ Points display" -msgstr "Aktivera centrerad dataskärm" +msgstr "Visa inventarie/IQ-poäng" #: engines/scumm/help.cpp:293 msgid "Toggle Keyboard/Mouse Fighting (*)" -msgstr "" +msgstr "Aktivera slagsmål med tangentbord/mus (*)" #: engines/scumm/help.cpp:295 msgid "* Keyboard Fighting is always on," -msgstr "" +msgstr "(*) Slagsmål med tangentbord är alltid på," #: engines/scumm/help.cpp:296 msgid " so despite the in-game message this" -msgstr "" +msgstr "så trots meddelandet i spelet" #: engines/scumm/help.cpp:297 msgid " actually toggles Mouse Fighting Off/On" -msgstr "" +msgstr "aktiverar det här endast slagsmål med mus." #: engines/scumm/help.cpp:304 msgid "Fighting controls (numpad):" @@ -3412,7 +3437,7 @@ msgstr "Slå lågt" #: engines/scumm/help.cpp:315 msgid "Sucker punch" -msgstr "" +msgstr "Smocka" #: engines/scumm/help.cpp:318 msgid "These are for Indy on left." @@ -3471,23 +3496,20 @@ msgid "Fly to lower right" msgstr "Flyg åt nedre höger" #: engines/scumm/input.cpp:580 -#, fuzzy msgid "Snap scroll on" -msgstr "Mjuk rullning" +msgstr "Snäpprullning på" #: engines/scumm/input.cpp:582 msgid "Snap scroll off" -msgstr "" +msgstr "Snäpprullning av" #: engines/scumm/input.cpp:595 -#, fuzzy msgid "Music volume: " -msgstr "Musikvolym:" +msgstr "Musikvolym: " #: engines/scumm/input.cpp:612 -#, fuzzy msgid "Subtitle speed: " -msgstr "Texthastighet:" +msgstr "Texthastighet: " #: engines/scumm/scumm.cpp:1832 #, c-format @@ -3499,27 +3521,88 @@ msgstr "" "men %s saknas. Använder AdLib istället." #: engines/scumm/scumm.cpp:2644 -#, fuzzy 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 "" -"Vanligtvis hade Maniac Mansion startat nu, men ScummVM kan inte göra detta " -"än. För att spela spelet, gå till \"Lägg till spel\" i ScummVM:s huvudmeny " -"och välj \"Maniac\"-katalogen inuti \"Tentacle\" katalogen." +"Vanligtvis hade Maniac Mansion startat nu, men för att det ska fungera måste " +"Maniac Mansion-filerna placeras i 'Maniac'-katalogen i 'Tentacle'-katalogen. " +"Spelet måste även läggas till i ScummVM." #: 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 "" +"Kunde inte hitta Macintosh-programmet för 'Loom'\n" +"för att läsa instrumenten. Musiken kommer att avaktiveras." #: 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 "" +"Kunde inte hitta Macintosh-programmet för 'Monkey Island'\n" +"för att läsa instrumenten. Musiken kommer att avaktiveras." + +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "Använd originalskärmar för spara/ladda" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" +"Filknappen i spelet visar originalskärmen för spara/ladda istället för " +"ScummVM-menyn" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "Pixliga scenövergångar" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "En slumpmässig pixelövergång visas vid scenbyten" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "Visa inte aktiveringspunkter vid musrörelse" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" +"Visar endast namn för aktiveringspunkter när du klickar på en " +"aktiveringspunkt eller handlingsknapp" + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "Visa karaktärsporträtt" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "Visa porträtt för karaktärerna under dialoger" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "Låt dialogrutor glida in" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "" +"Låter gränssnittets dialogrutor glida in i bilden istället för att bara visa " +"dem direkt" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "Genomskinliga fönster" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "Visar fönster med en delvis genomskinlig bakgrund" #: engines/sky/compact.cpp:130 msgid "" @@ -3601,7 +3684,7 @@ msgstr "Behåll den nya" #: engines/sword1/logic.cpp:1633 msgid "This is the end of the Broken Sword 1 Demo" -msgstr "Här slutar Broken Sword 1 demon" +msgstr "Här slutar Broken Sword 1-demon" #: engines/sword2/animation.cpp:425 msgid "" @@ -3627,56 +3710,53 @@ msgid "" "executable. Please decompress it" msgstr "" "Teenagent.dat-filen är komprimerad och zlib har inte inkluderats i det här " -"programmet. Var god dekomprimera den" +"programmet. Var god dekomprimera den" #: engines/wintermute/detection.cpp:58 msgid "Show FPS-counter" -msgstr "" +msgstr "Visa FPS-räknare" #: engines/wintermute/detection.cpp:59 msgid "Show the current number of frames per second in the upper left corner" msgstr "" +"Visar det aktuella antalet bildrutor per sekund i det övre vänstra hörnet" #: engines/zvision/detection_tables.h:52 -#, fuzzy msgid "Use the original save/load screens instead of the ScummVM interface" -msgstr "Använder originalskärmarna för spara/ladda istället för ScummVM:s" +msgstr "Använd originalskärmarna för spara/ladda istället för ScummVM:s" #: engines/zvision/detection_tables.h:61 msgid "Double FPS" -msgstr "" +msgstr "Dubbel FPS" #: engines/zvision/detection_tables.h:62 msgid "Increase framerate from 30 to 60 FPS" -msgstr "" +msgstr "Öka antalet bildrutor per sekund från 30 till 60" #: engines/zvision/detection_tables.h:71 -#, fuzzy msgid "Enable Venus" -msgstr "Aktivera heliumläge" +msgstr "Aktivera Venus" #: engines/zvision/detection_tables.h:72 -#, fuzzy msgid "Enable the Venus help system" -msgstr "Aktivera heliumläge" +msgstr "Aktivera Venus-hjälpsystemet" #: engines/zvision/detection_tables.h:81 msgid "Disable animation while turning" -msgstr "" +msgstr "Avaktivera animering när skärmen vänds" #: engines/zvision/detection_tables.h:82 msgid "Disable animation while turning in panorama mode" -msgstr "" +msgstr "Avaktivera animering medan skärmen vänds i panorama-läge" #: engines/zvision/detection_tables.h:91 msgid "Use high resolution MPEG video" -msgstr "" +msgstr "Använd högupplöst MPEG-video" #: engines/zvision/detection_tables.h:92 -#, fuzzy msgid "Use MPEG video from the DVD version, instead of lower resolution AVI" msgstr "" -"Använd de alternativa silverpekarna istället för de normala guldpekarna" +"Använd högupplöst MPEG-video från DVD-versionen istället för lågupplöst AVI" #~ msgid "EGA undithering" #~ msgstr "EGA anti-gitter" @@ -3726,10 +3806,6 @@ msgstr "" #~ msgid "Enable Roland GS Mode" #~ msgstr "Aktivera Roland GS-läge" -#, fuzzy -#~ msgid "Save game failed!" -#~ msgstr "Spara spelet:" - #~ msgctxt "lowres" #~ msgid "Add Game..." #~ msgstr "Lägg till spel..." diff --git a/po/uk_UA.po b/po/uk_UA.po index 940b86d605..5ab87a4155 100644 --- a/po/uk_UA.po +++ b/po/uk_UA.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ScummVM 1.3.0svn\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2016-02-01 21:58+0000\n" +"POT-Creation-Date: 2016-02-20 21:22+0000\n" "PO-Revision-Date: 2015-11-06 10:07+0300\n" "Last-Translator: Eugene Sandulenko <sev@scummvm.org>\n" "Language-Team: Ukrainian\n" @@ -592,16 +592,16 @@ msgid "Search:" msgstr "¿ÞèãÚ:" #: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214 -#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:718 -#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:600 +#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: engines/tsage/scenes.cpp:600 msgid "Load game:" msgstr "·ÐÒÐÝâÐÖØâØ Óàã:" #: 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/myst.cpp:245 -#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353 +#: 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 "·ÐÒÐÝâÐÖØâØ" @@ -764,7 +764,7 @@ msgid "Special dithering modes supported by some games" msgstr "ÁßÕæöÐÛìÝö àÕÖØÜØ àÐáâàãÒÐÝÝï, ïÚö ßöÔâàØÜãîâì ÔÕïÚö öÓàØ" #: gui/options.cpp:758 -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2313 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316 msgid "Fullscreen mode" msgstr "¿ÞÒÝÞÕÚàÐÝÝØÙ àÕÖØÜ" @@ -1361,12 +1361,12 @@ msgstr "PC-9821 (256 ÚÞÛìÞàöÒ)" msgid "PC-9801 (16 Colors)" msgstr "PC-9801 (16 ÚÞÛìÞàöÒ)" -#: common/rendermode.cpp:71 +#: common/rendermode.cpp:73 msgctxt "lowres" msgid "Hercules Green" msgstr "Hercules ×ÕÛÕÝØÙ" -#: common/rendermode.cpp:72 +#: common/rendermode.cpp:74 msgctxt "lowres" msgid "Hercules Amber" msgstr "Hercules ÑãàèâØÝÝØÙ" @@ -1417,11 +1417,15 @@ msgctxt "lowres" msgid "~R~eturn to Launcher" msgstr "~¿~ÞÒÕà.Ò ÓÞÛÞÒÝÕ ÜÕÝî" -#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:714 -#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 -#: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:877 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:769 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "·ÑÕàÕÓâØ Óàã: " @@ -1430,11 +1434,15 @@ msgstr "·ÑÕàÕÓâØ Óàã: " #: backends/platform/wince/CEActionsPocket.cpp:267 #: backends/platform/wince/CEActionsSmartphone.cpp:45 #: backends/platform/wince/CEActionsSmartphone.cpp:231 -#: engines/agi/saveload.cpp:714 engines/cruise/menu.cpp:212 -#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 -#: engines/neverhood/menumodule.cpp:877 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:769 engines/scumm/dialogs.cpp:188 -#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 +#: 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 "·ÐßØáÐâØ" @@ -1759,19 +1767,19 @@ msgctxt "lowres" msgid "Normal (no scaling)" msgstr "±Õ× ×ÑöÛìèÕÝÝï" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2212 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215 msgid "Enabled aspect ratio correction" msgstr "ºÞàÕÚæöî áßöÒÒöÔÝÞèÕÝÝï áâÞàöÝ ãÒöÜÚÝÕÝÞ" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2218 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221 msgid "Disabled aspect ratio correction" msgstr "ºÞàÕÚæöî áßöÒÒöÔÝÞèÕÝÝï áâÞàöÝ ÒØÜÚÝÕÝÞ" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2273 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276 msgid "Active graphics filter:" msgstr "¿ÞâÞçÝØÙ ÓàÐäöçÝØÙ äöÛìâà:" -#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2315 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318 msgid "Windowed mode" msgstr "²öÚÞÝÝØÙ àÕÖØÜ" @@ -2338,15 +2346,23 @@ msgstr "" "²ÚÛîçÐô ßöÔâàØÜÚã ÜØèö. ´Þ×ÒÞÛïô ÒØÚÞàØáâÞÒãÒÐâØ ÜØèã ÔÛï ßÕàÕáãÒÐÝÝï âÐ " "ãßàÐÒÛöÝÝï ÜÕÝî." -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "²öÔÝÞÒØâØ Óàã:" -#: engines/agi/saveload.cpp:727 engines/drascula/saveload.cpp:349 -#: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:890 -#: engines/sci/engine/kfile.cpp:868 engines/toltecs/menu.cpp:256 +#: 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 "²öÔÝÞÒØâØ" @@ -2668,10 +2684,18 @@ msgstr "" "½Õ ÜÞÖã ×ÑÕàÕÓâØ Óàã ã áÛÞâ %i\n" "\n" +#: engines/parallaction/saveload.cpp:197 +msgid "Load file" +msgstr "·ÐÒÐÝâÐÖØâØ äÐÙÛ" + #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." msgstr "·ÐÒÐÝâÐÖãî Óàã..." +#: engines/parallaction/saveload.cpp:212 +msgid "Save file" +msgstr "·ÑÕàÕÓâØ äÐÙÛ" + #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." msgstr "·ÑÕàÕÖãî Óàã..." @@ -3518,6 +3542,62 @@ msgstr "" "½Õ ÒÐÔÛÞáï ×ÝÐÙâØ äÐÙÛ ßàÞÓàÐÜØ 'Monkey Island' Macintosh ÐÑØ ßàÞçØâÐâØ\n" "× ÝìÞÓÞ öÝáâàãÜÕÝâØ. ¼ã×ØÚã ÑãÛÞ ÒØÜÚÝÕÝÞ." +#: engines/sherlock/detection.cpp:71 +msgid "Use original savegame dialog" +msgstr "²ØÚÞàØáâÞÒãÒÐâØ ÞàØÓöÝÐÛìÝØÙ ÕÚàÐÝ ×ÑÕàÕÖÕÝÝï" + +#: engines/sherlock/detection.cpp:72 +msgid "" +"Files button in-game shows original savegame dialog rather than the ScummVM " +"menu" +msgstr "" +"ºÝÞßÚÐ \"ÄÐÙÛØ\" ã Óàö ßÞÚÐ×ãÒÐâØÜÕ ÞàØÓöÝÐÛìÝØÙ ÕÚàÐÝ ×ÑÕàÕÖÕÝÝï " +"×ÐÜöáâì ÜÕÝî ScummVM" + +#: engines/sherlock/detection.cpp:81 +msgid "Pixellated scene transitions" +msgstr "¿öÕáÕÛìÞÒÐÝö ßÕàÕåÞÔØ ÜöÖ áæÕÝÐÜØ" + +#: engines/sherlock/detection.cpp:82 +msgid "When changing scenes, a randomized pixel transition is done" +msgstr "¿àØ ×ÜöÝö áæÕÝ ÑãÔÕ ÒöÔÑãÒÐâØáï ßÕàÕåöÔ ã ÒØÓÛïÔö ÒØßÐÔÚÞÒØå ßöÚáÕÛöÒ" + +#: engines/sherlock/detection.cpp:91 +msgid "Don't show hotspots when moving mouse" +msgstr "½Õ ßÞÚÐ×ãÒÐâØ æöÚÐÒö âÞçÚØ ßàØ ÝÐÒÕÔÕÝÝö ÜØèÕî" + +#: engines/sherlock/detection.cpp:92 +msgid "" +"Only show hotspot names after you actually click on a hotspot or action " +"button" +msgstr "" +"¿ÞÚÐ×ãÒÐâØ ÝÐ×ÒØ æöÚÐÒØå âÞçÞÚ âöÛìÚØ ßöáÛï ÑÕ×ßÞáÕàÕÔÝìÞÓÞ ÚÛöÚã ßÞ ÝØÜ " +"ÐÑÞ Ôö÷ × ÝØÜØ" + +#: engines/sherlock/detection.cpp:101 +msgid "Show character portraits" +msgstr "¿ÞÚÐ×ãÒÐâØ ßÞàâàÕâØ ÓÕàÞ÷Ò" + +#: engines/sherlock/detection.cpp:102 +msgid "Show portraits for the characters when conversing" +msgstr "¿ÞÚÐ×ãÒÐâØ ßÞàâàÕâØ ÓÕàÞ÷Ò ßöÔ çÐá áßöÛÚãÒÐÝÝï" + +#: engines/sherlock/detection.cpp:111 +msgid "Slide dialogs into view" +msgstr "·ÐÒÞÔØâØ ÔöÐÛÞÓØ ÔÞ ÞÑ×Þàã" + +#: engines/sherlock/detection.cpp:112 +msgid "Slide UI dialogs into view, rather than simply showing them immediately" +msgstr "·ÐÒÞÔØâØ ÔöÐÛÞÓØ ÔÞ ÞÑ×Þàã ×ÐÜöáâì ÜØââôÒÞÓÞ ßÞÚÐ×ã" + +#: engines/sherlock/detection.cpp:121 +msgid "Transparent windows" +msgstr "¿àÞ×Þàö ÒöÚÝÐ" + +#: engines/sherlock/detection.cpp:122 +msgid "Show windows with a partially transparent background" +msgstr "¿ÞÚÐ×ãÒÐâØ ÒöÚÝÐ × çÐáâÚÞÒÞ ßàÞ×ÞàØÜ âÛÞÜ" + #: engines/sky/compact.cpp:130 msgid "" "Unable to find \"sky.cpt\" file!\n" 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 @@ -341,7 +343,7 @@ osxsnap: bundle mkdir ScummVM-snapshot/doc/se cp $(srcdir)/doc/se/LasMig ./ScummVM-snapshot/doc/se/LasMig cp $(srcdir)/doc/se/Snabbstart ./ScummVM-snapshot/doc/se/Snabbstart - /Developer/Tools/SetFile -t ttro -c ttxt ./ScummVM-snapshot/* + $(XCODETOOLSPATH)/SetFile -t ttro -c ttxt ./ScummVM-snapshot/* xattr -w "com.apple.TextEncoding" "utf-8;134217984" ./ScummVM-snapshot/doc/cz/* xattr -w "com.apple.TextEncoding" "utf-8;134217984" ./ScummVM-snapshot/doc/da/* xattr -w "com.apple.TextEncoding" "utf-8;134217984" ./ScummVM-snapshot/doc/de/* @@ -350,11 +352,11 @@ osxsnap: bundle xattr -w "com.apple.TextEncoding" "utf-8;134217984" ./ScummVM-snapshot/doc/it/* xattr -w "com.apple.TextEncoding" "utf-8;134217984" ./ScummVM-snapshot/doc/no-nb/* xattr -w "com.apple.TextEncoding" "utf-8;134217984" ./ScummVM-snapshot/doc/se/* - /Developer/Tools/CpMac -r $(bundle_name) ./ScummVM-snapshot/ + $(XCODETOOLSPATH)/CpMac -r $(bundle_name) ./ScummVM-snapshot/ cp $(srcdir)/dists/macosx/DS_Store ./ScummVM-snapshot/.DS_Store cp $(srcdir)/dists/macosx/background.jpg ./ScummVM-snapshot/background.jpg - /Developer/Tools/SetFile -a V ./ScummVM-snapshot/.DS_Store - /Developer/Tools/SetFile -a V ./ScummVM-snapshot/background.jpg + $(XCODETOOLSPATH)/SetFile -a V ./ScummVM-snapshot/.DS_Store + $(XCODETOOLSPATH)/SetFile -a V ./ScummVM-snapshot/background.jpg hdiutil create -ov -format UDZO -imagekey zlib-level=9 -fs HFS+ \ -srcfolder ScummVM-snapshot \ -volname "ScummVM" \ diff --git a/test/common/array.h b/test/common/array.h index f0027ec201..64354abc00 100644 --- a/test/common/array.h +++ b/test/common/array.h @@ -44,6 +44,48 @@ class ArrayTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS(iter, array.end()); } + void test_erase_iterator() { + Common::Array<int> array; + Common::Array<int>::iterator iter; + + // Fill the array with some random data + array.push_back(17); + array.push_back(33); + array.push_back(-11); + + iter = array.begin(); + ++iter; + + iter = array.erase(iter); + TS_ASSERT_DIFFERS(iter, array.end()); + TS_ASSERT_EQUALS(*iter, -11); + TS_ASSERT_EQUALS(array.size(), (unsigned int)2); + TS_ASSERT_EQUALS(array[0], 17); + TS_ASSERT_EQUALS(array[1], -11); + } + + void test_insert_iterator() { + Common::Array<int> array; + Common::Array<int>::iterator iter; + + // Fill the array with some random data + array.push_back(17); + array.push_back(33); + array.push_back(-11); + + iter = array.begin(); + ++iter; + + array.insert(iter, 99); + + TS_ASSERT_EQUALS(*iter, 99); + TS_ASSERT_EQUALS(array.size(), (unsigned int)4); + TS_ASSERT_EQUALS(array[0], 17); + TS_ASSERT_EQUALS(array[1], 99); + TS_ASSERT_EQUALS(array[2], 33); + TS_ASSERT_EQUALS(array[3], -11); + } + void test_direct_access() { Common::Array<int> array; diff --git a/test/common/rational.h b/test/common/rational.h index 46dfc278c7..23d0c10acd 100644 --- a/test/common/rational.h +++ b/test/common/rational.h @@ -130,4 +130,15 @@ public: TS_ASSERT_EQUALS(r1 / 2, Common::Rational(1, 4)); TS_ASSERT_EQUALS(2 / r1, Common::Rational(4, 1)); } + + void test_isOne() { + Common::Rational r0(5, 5); + Common::Rational r1(1, 2); + Common::Rational r2(2, 1); + Common::Rational r3(1, 1); + TS_ASSERT(r0.isOne()); + TS_ASSERT(!r1.isOne()); + TS_ASSERT(!r2.isOne()); + TS_ASSERT(r3.isOne()); + } }; diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp index 324bf65294..49034aad17 100644 --- a/video/qt_decoder.cpp +++ b/video/qt_decoder.cpp @@ -447,7 +447,9 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame() } // Update the edit list, if applicable - if (endOfCurEdit()) { + // FIXME: Add support for playing backwards videos with more than one edit + // For now, stay on the first edit for reversed playback + if (endOfCurEdit() && !_reversed) { _curEdit++; if (atLastEdit()) |