diff options
author | Paul Gilbert | 2015-05-22 22:31:21 -0400 |
---|---|---|
committer | Paul Gilbert | 2015-05-22 22:31:21 -0400 |
commit | b4b6bf63dbfd3f952f4ca207467315396b53bd23 (patch) | |
tree | 48e6390df9c5487e73bc1b0ded246d0076561bcd | |
parent | 40f7fff42977d01c8bac81d462580c2c8ec39dc3 (diff) | |
parent | 2db07a9d39cc9557d292908d84d3fc146635fd75 (diff) | |
download | scummvm-rg350-b4b6bf63dbfd3f952f4ca207467315396b53bd23.tar.gz scummvm-rg350-b4b6bf63dbfd3f952f4ca207467315396b53bd23.tar.bz2 scummvm-rg350-b4b6bf63dbfd3f952f4ca207467315396b53bd23.zip |
Merge branch 'master' into sherlock2
171 files changed, 3828 insertions, 2573 deletions
@@ -11,6 +11,15 @@ For a more comprehensive changelog of the latest experimental code, see: General: - Updated Munt MT-32 emulation code to version 1.5.0. + 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). + + AGOS: + - Fixed arpeggio effect used in music of Amiga version of Elvira 1. + - Fixed loading and saving progress in the PC version of Waxworks. + Broken Sword 1: - Fix speech endianness detection on big endian systems for the mac version (bug #6720). @@ -20,8 +29,11 @@ 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, which are too numerous to - mention here. + - 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) + - Restoring from the ScummVM in-game menu should now work all the time. + - Improve support for Japanese PC-9801 games. SCUMM: - It is now possible to play Maniac Mansion from within Day of the @@ -1013,7 +1013,11 @@ site, please see the section on reporting bugs. Inherit the Earth: Quest for the Orb - Amiga versions aren't supported - Simon the Sorcerer 1: + Lure of the Temptress + - No Roland MT-32 support + - Sound support is incomplete and doesn't sound like original + + Simon the Sorcerer 1: - Subtitles aren't available in the English and German CD versions as they are missing the majority of subtitles. @@ -2264,6 +2268,10 @@ Sierra games using the AGI engine add the following non-standard keywords: originalsaveload bool If true, the original save/load screens are used instead of the enhanced ScummVM ones + altamigapalette bool Use an alternative palette, common for all + Amiga games. This was the old behavior + mousesupport bool Enables mouse support. Allows to use mouse + for movement and in game menus Sierra games using the SCI engine add the following non-standard keywords: @@ -2275,6 +2283,12 @@ Sierra games using the SCI engine add the following non-standard keywords: native_fb01 bool If true, the music driver for an IBM Music Feature card or a Yamaha FB-01 FM synth module is used for MIDI output + use_cdaudio bool Use CD audio instead of in-game audio, + when available + windows_cursors bool Use the Windows cursors (smaller and monochrome) + instead of the DOS ones (King's Quest 6) + silver_cursors bool Use the alternate set of silver cursors, + instead of the normal golden ones (Space Quest 4) Broken Sword II adds the following non-standard keywords: diff --git a/audio/mods/protracker.cpp b/audio/mods/protracker.cpp index 82067f67bd..2578e9488a 100644 --- a/audio/mods/protracker.cpp +++ b/audio/mods/protracker.cpp @@ -219,11 +219,10 @@ void ProtrackerStream::updateRow() { case 0x0: if (exy) { _track[track].arpeggio = true; - if (note.period) { - _track[track].arpeggioNotes[0] = note.note; - _track[track].arpeggioNotes[1] = note.note + ex; - _track[track].arpeggioNotes[2] = note.note + ey; - } + byte trackNote = _module.periodToNote(_track[track].period); + _track[track].arpeggioNotes[0] = trackNote; + _track[track].arpeggioNotes[1] = trackNote + ex; + _track[track].arpeggioNotes[2] = trackNote + ey; } break; case 0x1: diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp index c71b9c9219..a2b172f14a 100644 --- a/backends/graphics/openglsdl/openglsdl-graphics.cpp +++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp @@ -57,7 +57,10 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(uint desktopWidth, uint deskt } #else const SDL_Rect *const *availableModes = SDL_ListModes(NULL, SDL_OPENGL | SDL_FULLSCREEN); - if (availableModes != (void *)-1) { + // TODO: NULL means that there are no fullscreen modes supported. We + // should probably use this information and disable any fullscreen support + // in this case. + if (availableModes != NULL && availableModes != (void *)-1) { for (;*availableModes; ++availableModes) { const SDL_Rect *mode = *availableModes; diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp index d08925349a..9cb14525ee 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp @@ -125,6 +125,8 @@ SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSou _hwscreen(0), #if SDL_VERSION_ATLEAST(2, 0, 0) _renderer(nullptr), _screenTexture(nullptr), +#else + _originalBitsPerPixel(0), #endif _screen(0), _tmpscreen(0), #ifdef USE_RGB_COLOR @@ -796,7 +798,15 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() { _hwscreen = g_eventRec.getSurface(_videoMode.hardwareWidth, _videoMode.hardwareHeight); } else #endif - { + { + // Save the original bpp to be able to restore the video mode on unload +#if !SDL_VERSION_ATLEAST(2, 0, 0) + if (_originalBitsPerPixel == 0) { + const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo(); + _originalBitsPerPixel = videoInfo->vfmt->BitsPerPixel; + } +#endif + _hwscreen = SDL_SetVideoMode(_videoMode.hardwareWidth, _videoMode.hardwareHeight, 16, _videoMode.fullscreen ? (SDL_FULLSCREEN|SDL_SWSURFACE) : SDL_SWSURFACE ); @@ -929,6 +939,13 @@ 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 (_originalBitsPerPixel != 0) + SDL_SetVideoMode(_videoMode.screenWidth, _videoMode.screenHeight, _originalBitsPerPixel, _videoMode.fullscreen ? (SDL_FULLSCREEN | SDL_SWSURFACE) : SDL_SWSURFACE); +#endif } bool SurfaceSdlGraphicsManager::hotswapGFXMode() { diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.h b/backends/graphics/surfacesdl/surfacesdl-graphics.h index 4ba15a304b..2431ce8664 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.h +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.h @@ -236,6 +236,9 @@ protected: }; VideoState _videoMode, _oldVideoMode; + // Original BPP to restore the video mode on unload + uint8 _originalBitsPerPixel; + /** Force full redraw on next updateScreen */ bool _forceFull; diff --git a/devtools/scumm-md5.txt b/devtools/scumm-md5.txt index e56f1a6a99..305c1724ed 100644 --- a/devtools/scumm-md5.txt +++ b/devtools/scumm-md5.txt @@ -314,7 +314,7 @@ tentacle Day of the Tentacle 4fbbe9f64b8bc547503a379a301183ce -1 it All? - CD - Andrea Petrucci 883af4b0af4f77a92f1dcf1d0a283140 -1 es All? - CD - Andrea Petrucci cc04a076779379524ed4d9c5ee3c6fb1 282467632 en Mac - CD Mac bundle Fingolfin, Joachim Eberhard - ede149fda3edfc1dbd7347e0737cb583 -1 fr Mac - CD Mac bundle ThierryFR + ede149fda3edfc1dbd7347e0737cb583 282830409 fr Mac - CD Mac bundle ThierryFR, Thierry Crozat f73883f13b5a302749a5bad31d909780 -1 de Mac - CD Mac bundle morrissey c83079157ec765a28de445aec9768d60 7477 en All - Demo - Fingolfin @@ -337,7 +337,7 @@ samnmax Sam & Max Hit the Road 4ba7fb331296c283e73d8f5b2096e551 -1 es All? - CD - Andrea Petrucci d43352a805d78b5f4936c6d7779bf575 -1 ru DOS - CD - 166553538ff320c69edafeee29525419 199195304 en Mac - CD Mac bundle Joachim Eberhard - 3a5d13675e9a23aedac0bac7730f0ac1 -1 fr Mac - CD Mac bundle ThierryFR + 3a5d13675e9a23aedac0bac7730f0ac1 228446581 fr Mac - CD Mac bundle ThierryFR, Thierry Crozat c3196c5349e53e387aaff1533d95e53a -1 en DOS Floppy Demo - 0e4c5d54a0ad4b26132e78b5ea76642a 6485 en DOS Floppy Demo WIP Fingolfin @@ -358,6 +358,7 @@ ft Full Throttle e72bb4c2b613db2cf50f89ff6350e70a -1 es All? - - - fe381e45117878b1e942cb876b050fd6 513243679 en Mac - - Mac bundle Fingolfin 04401d747f1a2c1c4b388daff71ed378 535405461 de Mac - - Mac bundle Fingolfin + 403d2ec4d60d3cdae925e6cbf67716d6 489436643 fr Mac - - Mac bundle Thierry Crozat 32a433dea56b86a55b59e4ff7d755711 -1 en DOS Demo Demo - 9d7b67be003fea60be4dcbd193611936 11164 en Mac Demo Demo - Fingolfin diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp index 1e663ec29a..2b5d7137bc 100644 --- a/engines/agi/agi.cpp +++ b/engines/agi/agi.cpp @@ -97,50 +97,62 @@ void AgiEngine::processEvents() { } break; case Common::EVENT_LBUTTONDOWN: - key = BUTTON_LEFT; - _mouse.button = kAgiMouseButtonLeft; - keyEnqueue(key); - _mouse.x = event.mouse.x; - _mouse.y = event.mouse.y; + if (_game.mouseEnabled) { + key = BUTTON_LEFT; + _mouse.button = kAgiMouseButtonLeft; + keyEnqueue(key); + _mouse.x = event.mouse.x; + _mouse.y = event.mouse.y; + } break; case Common::EVENT_RBUTTONDOWN: - key = BUTTON_RIGHT; - _mouse.button = kAgiMouseButtonRight; - keyEnqueue(key); - _mouse.x = event.mouse.x; - _mouse.y = event.mouse.y; + if (_game.mouseEnabled) { + key = BUTTON_RIGHT; + _mouse.button = kAgiMouseButtonRight; + keyEnqueue(key); + _mouse.x = event.mouse.x; + _mouse.y = event.mouse.y; + } break; case Common::EVENT_WHEELUP: - key = WHEEL_UP; - keyEnqueue(key); + if (_game.mouseEnabled) { + key = WHEEL_UP; + keyEnqueue(key); + } break; case Common::EVENT_WHEELDOWN: - key = WHEEL_DOWN; - keyEnqueue(key); + if (_game.mouseEnabled) { + key = WHEEL_DOWN; + keyEnqueue(key); + } break; case Common::EVENT_MOUSEMOVE: - _mouse.x = event.mouse.x; - _mouse.y = event.mouse.y; - - if (!_game.mouseFence.isEmpty()) { - if (_mouse.x < _game.mouseFence.left) - _mouse.x = _game.mouseFence.left; - if (_mouse.x > _game.mouseFence.right) - _mouse.x = _game.mouseFence.right; - if (_mouse.y < _game.mouseFence.top) - _mouse.y = _game.mouseFence.top; - if (_mouse.y > _game.mouseFence.bottom) - _mouse.y = _game.mouseFence.bottom; - - g_system->warpMouse(_mouse.x, _mouse.y); + if (_game.mouseEnabled) { + _mouse.x = event.mouse.x; + _mouse.y = event.mouse.y; + + if (!_game.mouseFence.isEmpty()) { + if (_mouse.x < _game.mouseFence.left) + _mouse.x = _game.mouseFence.left; + if (_mouse.x > _game.mouseFence.right) + _mouse.x = _game.mouseFence.right; + if (_mouse.y < _game.mouseFence.top) + _mouse.y = _game.mouseFence.top; + if (_mouse.y > _game.mouseFence.bottom) + _mouse.y = _game.mouseFence.bottom; + + g_system->warpMouse(_mouse.x, _mouse.y); + } } break; case Common::EVENT_LBUTTONUP: case Common::EVENT_RBUTTONUP: - _mouse.button = kAgiMouseButtonUp; - _mouse.x = event.mouse.x; - _mouse.y = event.mouse.y; + if (_game.mouseEnabled) { + _mouse.button = kAgiMouseButtonUp; + _mouse.x = event.mouse.x; + _mouse.y = event.mouse.y; + } break; case Common::EVENT_KEYDOWN: if (event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_d) { @@ -496,12 +508,15 @@ AgiBase::AgiBase(OSystem *syst, const AGIGameDescription *gameDesc) : Engine(sys // Assign default values to the config manager, in case settings are missing ConfMan.registerDefault("originalsaveload", "false"); ConfMan.registerDefault("altamigapalette", "false"); + ConfMan.registerDefault("mousesupport", "true"); _noSaveLoadAllowed = false; _rnd = new Common::RandomSource("agi"); _sound = 0; + _fontData = NULL; + initFeatures(); initVersion(); } @@ -550,6 +565,19 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas memset(&_debug, 0, sizeof(struct AgiDebug)); memset(&_mouse, 0, sizeof(struct Mouse)); + _game.mouseEnabled = true; + if (!ConfMan.getBool("mousesupport")) { + // we effectively disable the mouse for games, that explicitly do not want mouse support to be enabled + _game.mouseEnabled = false; + } + + // We are currently using the custom font for all fanmade games + if (!(getFeatures() & (GF_FANMADE | GF_AGDS))) { + _fontData = fontData_Sierra; // original Sierra font + } else { + _fontData = fontData_FanGames; // our (own?) custom font, that supports umlauts etc. + } + _game._vm = this; _game.clockEnabled = false; @@ -708,7 +736,9 @@ Common::Error AgiBase::init() { } Common::Error AgiEngine::go() { - CursorMan.showMouse(true); + if (_game.mouseEnabled) { + CursorMan.showMouse(true); + } setTotalPlayTime(0); if (_game.state < STATE_LOADED) { diff --git a/engines/agi/agi.h b/engines/agi/agi.h index 6256de05d2..04e02dcf87 100644 --- a/engines/agi/agi.h +++ b/engines/agi/agi.h @@ -643,6 +643,7 @@ struct AgiGame { int simpleSave; /**< select simple savegames */ Common::Rect mouseFence; /**< rectangle set by fence.mouse command */ + bool mouseEnabled; /**< if mouse is supposed to be active */ // IF condition handling int testResult; @@ -780,6 +781,8 @@ protected: void initRenderMode(); + const uint8 *_fontData; + public: GfxMgr *_gfx; @@ -839,6 +842,8 @@ public: bool canLoadGameStateCurrently(); bool canSaveGameStateCurrently(); + + const uint8 *getFontData() { return _fontData; }; }; typedef void (*AgiCommand)(AgiGame *state, uint8 *p); diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index 3230b4e5d3..823ec7be66 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -138,21 +138,41 @@ static const PlainGameDescriptor agiGames[] = { {0, 0} }; -static const ExtraGuiOption agiExtraGuiOption = { - _s("Use original save/load screens"), - _s("Use the original save/load screens, instead of the ScummVM ones"), - "originalsaveload", - false -}; +#include "agi/detection_tables.h" -static const ExtraGuiOption agiExtraGuiOptionAmiga = { - _s("Use an alternative palette"), - _s("Use an alternative palette, common for all Amiga games. This was the old behavior"), - "altamigapalette", - false -}; +static const ADExtraGuiOptionsMap optionsList[] = { + { + GAMEOPTION_ORIGINAL_SAVELOAD, + { + _s("Use original save/load screens"), + _s("Use the original save/load screens, instead of the ScummVM ones"), + "originalsaveload", + false + } + }, + + { + GAMEOPTION_AMIGA_ALTERNATIVE_PALETTE, + { + _s("Use an alternative palette"), + _s("Use an alternative palette, common for all Amiga games. This was the old behavior"), + "altamigapalette", + false + } + }, + + { + GAMEOPTION_DISABLE_MOUSE, + { + _s("Mouse support"), + _s("Enables mouse support. Allows to use mouse for movement and in game menus."), + "mousesupport", + true + } + }, -#include "agi/detection_tables.h" + AD_EXTRA_GUI_OPTIONS_TERMINATOR +}; using namespace Agi; @@ -161,7 +181,7 @@ class AgiMetaEngine : public AdvancedMetaEngine { mutable Common::String _extra; public: - AgiMetaEngine() : AdvancedMetaEngine(Agi::gameDescriptions, sizeof(Agi::AGIGameDescription), agiGames) { + AgiMetaEngine() : AdvancedMetaEngine(Agi::gameDescriptions, sizeof(Agi::AGIGameDescription), agiGames, optionsList) { _singleid = "agi"; _guioptions = GUIO1(GUIO_NOSPEECH); } @@ -175,7 +195,6 @@ public: virtual bool hasFeature(MetaEngineFeature f) const; virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; - virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const; virtual SaveStateList listSaves(const char *target) const; virtual int getMaximumSaveSlot() const; virtual void removeSaveState(const char *target, int slot) const; @@ -234,14 +253,6 @@ bool AgiMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameD return res; } -const ExtraGuiOptions AgiMetaEngine::getExtraGuiOptions(const Common::String &target) const { - ExtraGuiOptions options; - options.push_back(agiExtraGuiOption); - if (target.contains("-amiga")) - options.push_back(agiExtraGuiOptionAmiga); - return options; -} - SaveStateList AgiMetaEngine::listSaves(const char *target) const { const uint32 AGIflag = MKTAG('A','G','I',':'); Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h index 2d7fba3507..0ae822a538 100644 --- a/engines/agi/detection_tables.h +++ b/engines/agi/detection_tables.h @@ -22,7 +22,16 @@ namespace Agi { -#define GAME_LVFPN(id,extra,fname,md5,size,lang,ver,features,gid,platform,interp) { \ +#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1 +#define GAMEOPTION_AMIGA_ALTERNATIVE_PALETTE GUIO_GAMEOPTIONS2 +#define GAMEOPTION_DISABLE_MOUSE GUIO_GAMEOPTIONS3 +// 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 GAME_LVFPN(id,extra,fname,md5,size,lang,ver,features,gid,platform,interp,guioptions) { \ { \ id, \ extra, \ @@ -30,7 +39,7 @@ namespace Agi { lang, \ platform, \ ADGF_NO_FLAGS, \ - GUIO0() \ + guioptions \ }, \ gid, \ interp, \ @@ -38,7 +47,7 @@ namespace Agi { ver \ } -#define GAME_LVFPNF(id,name,fname,md5,size,lang,ver,features,gid,platform,interp) { \ +#define GAME_LVFPNF(id,name,fname,md5,size,lang,ver,features,gid,platform,interp,guioptions) { \ { \ id, \ name, \ @@ -46,7 +55,7 @@ namespace Agi { lang, \ platform, \ ADGF_USEEXTRAASTITLE, \ - GUIO0() \ + guioptions \ }, \ gid, \ interp, \ @@ -54,43 +63,52 @@ namespace Agi { ver \ } -#define BOOTER2(id,extra,fname,md5,size,ver,gid) GAME_LVFPN(id,extra,fname,md5,size,Common::EN_ANY,ver,0,gid,Common::kPlatformDOS,GType_V2) -#define GAME(id,extra,md5,ver,gid) GAME_LVFPN(id,extra,"logdir",md5,-1,Common::EN_ANY,ver,0,gid,Common::kPlatformDOS,GType_V2) -#define GAME3(id,extra,fname,md5,ver,gid) GAME_LVFPN(id,extra,fname,md5,-1,Common::EN_ANY,ver,0,gid,Common::kPlatformDOS,GType_V3) +#define BOOTER2(id,extra,fname,md5,size,ver,gid) GAME_LVFPN(id,extra,fname,md5,size,Common::EN_ANY,ver,0,gid,Common::kPlatformDOS,GType_V2,GAMEOPTIONS_DEFAULT) +#define GAME(id,extra,md5,ver,gid) GAME_LVFPN(id,extra,"logdir",md5,-1,Common::EN_ANY,ver,0,gid,Common::kPlatformDOS,GType_V2,GAMEOPTIONS_DEFAULT) +#define GAME3(id,extra,fname,md5,ver,gid) GAME_LVFPN(id,extra,fname,md5,-1,Common::EN_ANY,ver,0,gid,Common::kPlatformDOS,GType_V3,GAMEOPTIONS_DEFAULT) -#define GAME_P(id,extra,md5,ver,gid,platform) GAME_LVFPN(id,extra,"logdir",md5,-1,Common::EN_ANY,ver,0,gid,platform,GType_V2) +#define GAME_P(id,extra,md5,ver,gid,platform) GAME_LVFPN(id,extra,"logdir",md5,-1,Common::EN_ANY,ver,0,gid,platform,GType_V2,GAMEOPTIONS_DEFAULT) +#define GAME_PO(id,extra,md5,ver,gid,platform,guioptions) GAME_LVFPN(id,extra,"logdir",md5,-1,Common::EN_ANY,ver,0,gid,platform,GType_V2,guioptions) -#define GAME_FP(id,extra,md5,ver,flags,gid,platform) GAME_LVFPN(id,extra,"logdir",md5,-1,Common::EN_ANY,ver,flags,gid,platform,GType_V2) +#define GAME_FP(id,extra,md5,ver,flags,gid,platform) GAME_LVFPN(id,extra,"logdir",md5,-1,Common::EN_ANY,ver,flags,gid,platform,GType_V2,GAMEOPTIONS_DEFAULT) +#define GAME_FPO(id,extra,md5,ver,flags,gid,platform,guioptions) GAME_LVFPN(id,extra,"logdir",md5,-1,Common::EN_ANY,ver,flags,gid,platform,GType_V2,guioptions) #define GAME_F(id,extra,md5,ver,flags,gid) GAME_FP(id,extra,md5,ver,flags,gid,Common::kPlatformDOS) +#define GAME_FO(id,extra,md5,ver,flags,gid,guioptions) GAME_FPO(id,extra,md5,ver,flags,gid,Common::kPlatformDOS,guioptions) -#define GAME_PS(id,extra,md5,size,ver,gid,platform) GAME_LVFPN(id,extra,"logdir",md5,size,Common::EN_ANY,ver,0,gid,platform,GType_V2) +#define GAME_PS(id,extra,md5,size,ver,gid,platform) GAME_LVFPN(id,extra,"logdir",md5,size,Common::EN_ANY,ver,0,gid,platform,GType_V2,GAMEOPTIONS_DEFAULT) -#define GAME_LPS(id,extra,md5,size,lang,ver,gid,platform) GAME_LVFPN(id,extra,"logdir",md5,size,lang,ver,0,gid,platform,GType_V2) +#define GAME_LPS(id,extra,md5,size,lang,ver,gid,platform) GAME_LVFPN(id,extra,"logdir",md5,size,lang,ver,0,gid,platform,GType_V2,GAMEOPTIONS_DEFAULT) -#define GAME_LFPS(id,extra,md5,size,lang,ver,flags,gid,platform) GAME_LVFPN(id,extra,"logdir",md5,size,lang,ver,flags,gid,platform,GType_V2) +#define GAME_LFPS(id,extra,md5,size,lang,ver,flags,gid,platform) GAME_LVFPN(id,extra,"logdir",md5,size,lang,ver,flags,gid,platform,GType_V2,GAMEOPTIONS_DEFAULT) -#define GAME3_P(id,extra,fname,md5,ver,flags,gid,platform) GAME_LVFPN(id,extra,fname,md5,-1,Common::EN_ANY,ver,flags,gid,platform,GType_V3) +#define GAME3_P(id,extra,fname,md5,ver,flags,gid,platform) GAME_LVFPN(id,extra,fname,md5,-1,Common::EN_ANY,ver,flags,gid,platform,GType_V3,GAMEOPTIONS_DEFAULT) +#define GAME3_PO(id,extra,fname,md5,ver,flags,gid,platform,guioptions) GAME_LVFPN(id,extra,fname,md5,-1,Common::EN_ANY,ver,flags,gid,platform,GType_V3,guioptions) -#define GAMEpre_P(id,extra,fname,md5,ver,gid,platform) GAME_LVFPN(id,extra,fname,md5,-1,Common::EN_ANY,ver,0,gid,platform,GType_PreAGI) +#define GAMEpre_P(id,extra,fname,md5,ver,gid,platform) GAME_LVFPN(id,extra,fname,md5,-1,Common::EN_ANY,ver,0,gid,platform,GType_PreAGI,GAMEOPTIONS_DEFAULT) +#define GAMEpre_PO(id,extra,fname,md5,ver,gid,platform,guioptions) GAME_LVFPN(id,extra,fname,md5,-1,Common::EN_ANY,ver,0,gid,platform,GType_PreAGI,guioptions) -#define GAMEpre_PS(id,extra,fname,md5,size,ver,gid,platform) GAME_LVFPN(id,extra,fname,md5,size,Common::EN_ANY,ver,0,gid,platform,GType_PreAGI) +#define GAMEpre_PS(id,extra,fname,md5,size,ver,gid,platform) GAME_LVFPN(id,extra,fname,md5,size,Common::EN_ANY,ver,0,gid,platform,GType_PreAGI,GAMEOPTIONS_DEFAULT) -#define GAME3_PS(id,extra,fname,md5,size,ver,flags,gid,platform) GAME_LVFPN(id,extra,fname,md5,size,Common::EN_ANY,ver,flags,gid,platform,GType_V3) +#define GAME3_PS(id,extra,fname,md5,size,ver,flags,gid,platform) GAME_LVFPN(id,extra,fname,md5,size,Common::EN_ANY,ver,flags,gid,platform,GType_V3,GAMEOPTIONS_DEFAULT) +#define GAME3_PSO(id,extra,fname,md5,size,ver,flags,gid,platform,guioptions) GAME_LVFPN(id,extra,fname,md5,size,Common::EN_ANY,ver,flags,gid,platform,GType_V3,guioptions) -#define FANMADE_ILVF(id,name,md5,lang,ver,features) GAME_LVFPNF(id,name,"logdir",md5,-1,lang,ver,(GF_FANMADE|features),GID_FANMADE,Common::kPlatformDOS,GType_V2) +#define FANMADE_ILVFO(id,name,md5,lang,ver,features,guioptions) GAME_LVFPNF(id,name,"logdir",md5,-1,lang,ver,(GF_FANMADE|features),GID_FANMADE,Common::kPlatformDOS,GType_V2,guioptions) -#define FANMADE_ISVP(id,name,md5,size,ver,platform) GAME_LVFPNF(id,name,"logdir",md5,size,Common::EN_ANY,ver,GF_FANMADE,GID_FANMADE,platform,GType_V2) -#define FANMADE_SVP(name,md5,size,ver,platform) FANMADE_ISVP("agi-fanmade",name,md5,size,ver,platform) +#define FANMADE_ISVPO(id,name,md5,size,ver,platform,guioptions) GAME_LVFPNF(id,name,"logdir",md5,size,Common::EN_ANY,ver,GF_FANMADE,GID_FANMADE,platform,GType_V2,guioptions) +#define FANMADE_SVP(name,md5,size,ver,platform) FANMADE_ISVPO("agi-fanmade",name,md5,size,ver,platform,GAMEOPTIONS_DEFAULT) -#define FANMADE_LVF(name,md5,lang,ver,features) FANMADE_ILVF("agi-fanmade",name,md5,lang,ver,features) +#define FANMADE_LVFO(name,md5,lang,ver,features,guioptions) FANMADE_ILVFO("agi-fanmade",name,md5,lang,ver,features,guioptions) -#define FANMADE_LF(name,md5,lang,features) FANMADE_LVF(name,md5,lang,0x2917,features) +#define FANMADE_LF(name,md5,lang,features) FANMADE_LVFO(name,md5,lang,0x2917,features,GAMEOPTIONS_DEFAULT) +#define FANMADE_LFO(name,md5,lang,features,guioptions) FANMADE_LVFO(name,md5,lang,0x2917,features,guioptions) #define FANMADE_IF(id,name,md5,features) FANMADE_ILVF(id,name,md5,Common::EN_ANY,0x2917,features) -#define FANMADE_V(name,md5,ver) FANMADE_LVF(name,md5,Common::EN_ANY,ver,0) +#define FANMADE_V(name,md5,ver) FANMADE_LVFO(name,md5,Common::EN_ANY,ver,0,GAMEOPTIONS_DEFAULT) #define FANMADE_F(name,md5,features) FANMADE_LF(name,md5,Common::EN_ANY,features) +#define FANMADE_FO(name,md5,features,guioptions) FANMADE_LFO(name,md5,Common::EN_ANY,features,guioptions) #define FANMADE_L(name,md5,lang) FANMADE_LF(name,md5,lang,0) #define FANMADE_I(id,name,md5) FANMADE_IF(id,name,md5,0) +#define FANMADE_O(name,md5,guioptions) FANMADE_FO(name,md5,0,guioptions) #define FANMADE(name,md5) FANMADE_F(name,md5,0) @@ -130,7 +148,7 @@ static const AGIGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS, - GUIO0() + GAMEOPTIONS_DEFAULT }, GID_BC, GType_V1, @@ -151,7 +169,7 @@ static const AGIGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS, - GUIO0() + GAMEOPTIONS_DEFAULT }, GID_BC, GType_V1, @@ -172,7 +190,7 @@ static const AGIGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS, - GUIO0() + GAMEOPTIONS_DEFAULT }, GID_BC, GType_V1, @@ -181,7 +199,7 @@ static const AGIGameDescription gameDescriptions[] = { }, // Black Cauldron (Amiga) 2.00 6/14/87 - GAME_P("bc", "2.00 1987-06-14", "7b01694af21213b4727bb94476f64eb5", 0x2440, GID_BC, Common::kPlatformAmiga), + GAME_PO("bc", "2.00 1987-06-14", "7b01694af21213b4727bb94476f64eb5", 0x2440, GID_BC, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA), // Black Cauldron (Apple IIgs) 1.0O 2/24/89 (CE) // Menus not tested @@ -210,7 +228,7 @@ static const AGIGameDescription gameDescriptions[] = { // Donald Duck's Playground (Amiga) 1.0C // Menus not tested - GAME_P("ddp", "1.0C 1987-04-27", "550971d196f65190a5c760d2479406ef", 0x2272, GID_DDP, Common::kPlatformAmiga), + GAME_PO("ddp", "1.0C 1987-04-27", "550971d196f65190a5c760d2479406ef", 0x2272, GID_DDP, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA), // Donald Duck's Playground (ST) 1.0A 8/8/86 // Menus not tested @@ -221,7 +239,7 @@ static const AGIGameDescription gameDescriptions[] = { GAME_PS("ddp", "1.0C 1986-06-09", "550971d196f65190a5c760d2479406ef", 132, 0x2272, GID_DDP, Common::kPlatformDOS), // Gold Rush! (Amiga) 1.01 1/13/89 aka 2.05 3/9/89 # 2.316 - GAME3_PS("goldrush", "1.01 1989-01-13 aka 2.05 1989-03-09", "dirs", "a1d4de3e75c2688c1e2ca2634ffc3bd8", 2399, 0x3149, 0, GID_GOLDRUSH, Common::kPlatformAmiga), + GAME3_PSO("goldrush", "1.01 1989-01-13 aka 2.05 1989-03-09", "dirs", "a1d4de3e75c2688c1e2ca2634ffc3bd8", 2399, 0x3149, 0, GID_GOLDRUSH, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA), // Gold Rush! (Apple IIgs) 1.0M 2/28/89 (CE) aka 2.01 12/22/88 // Menus not tested @@ -252,7 +270,7 @@ static const AGIGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO0() + GAMEOPTIONS_DEFAULT }, GID_GOLDRUSH, GType_V3, @@ -269,7 +287,7 @@ static const AGIGameDescription gameDescriptions[] = { // King's Quest 1 (Amiga) 1.0U # 2.082 // The original game did not have menus, they are enabled under ScummVM - GAME_FP("kq1", "1.0U 1986", "246c695324f1c514aee2b904fa352fad", 0x2440, GF_MENUS, GID_KQ1, Common::kPlatformAmiga), + GAME_FPO("kq1", "1.0U 1986", "246c695324f1c514aee2b904fa352fad", 0x2440, GF_MENUS, GID_KQ1, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA), // King's Quest 1 (ST) 1.0V // The original game did not have menus, they are enabled under ScummVM @@ -298,7 +316,7 @@ static const AGIGameDescription gameDescriptions[] = { GAME_P("kq2", "2.0A 1988-06-16 (CE)", "5203c8b95250a2ecfee93ddb99414753", 0x2917, GID_KQ2, Common::kPlatformApple2GS), // King's Quest 2 (Amiga) 2.0J - GAME_P("kq2", "2.0J 1987-01-29", "b866f0fab2fad91433a637a828cfa410", 0x2440, GID_KQ2, Common::kPlatformAmiga), + GAME_PO("kq2", "2.0J 1987-01-29", "b866f0fab2fad91433a637a828cfa410", 0x2440, GID_KQ2, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA), // King's Quest 2 (Mac) 2.0R GAME_P("kq2", "2.0R 1988-03-23", "cbdb0083317c8e7cfb7ac35da4bc7fdc", 0x2440, GID_KQ2, Common::kPlatformMacintosh), @@ -324,7 +342,7 @@ static const AGIGameDescription gameDescriptions[] = { // King's Quest 3 (Amiga) 1.01 11/8/86 // The original game did not have menus, they are enabled under ScummVM - GAME_FP("kq3", "1.01 1986-11-08", "8ab343306df0e2d98f136be4e8cfd0ef", 0x2440, GF_MENUS, GID_KQ3, Common::kPlatformAmiga), + GAME_FPO("kq3", "1.01 1986-11-08", "8ab343306df0e2d98f136be4e8cfd0ef", 0x2440, GF_MENUS, GID_KQ3, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA), // King's Quest 3 (ST) 1.02 11/18/86 // Does not have menus, crashes if menus are enforced. Therefore, ESC pauses the game @@ -340,7 +358,7 @@ static const AGIGameDescription gameDescriptions[] = { // Original pauses with ESC, has menus accessible with mouse. // ver = 0x3086 -> menus accessible with ESC or mouse, bug #2835581 (KQ3: Game Crash When Leaving Tavern as Fly). // ver = 0x3149 -> menus accessible with mouse, ESC pauses game, bug #2835581 disappears. - GAME3_PS("kq3", "2.15 1989-11-15", "dirs", "8e35bded2bc5cf20f5eec2b15523b155", 1805, 0x3149, 0, GID_KQ3, Common::kPlatformAmiga), + GAME3_PSO("kq3", "2.15 1989-11-15", "dirs", "8e35bded2bc5cf20f5eec2b15523b155", 1805, 0x3149, 0, GID_KQ3, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA), // King's Quest 3 (PC) 1.01 11/08/86 [AGI 2.272] // Does not have menus, crashes if menus are enforced. Therefore, ESC pauses the game @@ -405,7 +423,7 @@ static const AGIGameDescription gameDescriptions[] = { GAME_P("lsl1", "1.04 1987-06-18", "8b579f8673fe9448c2538f5ed9887cf0", 0x2440, GID_LSL1, Common::kPlatformAtariST), // Leisure Suit Larry 1 (Amiga) 1.05 6/26/87 # x.yyy - GAME_P("lsl1", "1.05 1987-06-26", "3f5d26d8834ca49c147fb60936869d56", 0x2440, GID_LSL1, Common::kPlatformAmiga), + GAME_PO("lsl1", "1.05 1987-06-26", "3f5d26d8834ca49c147fb60936869d56", 0x2440, GID_LSL1, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA), // Leisure Suit Larry 1 (IIgs) 1.0E GAME_P("lsl1", "1.0E 1987", "5f9e1dd68d626c6d303131c119582ad4", 0x2440, GID_LSL1, Common::kPlatformApple2GS), @@ -423,7 +441,7 @@ static const AGIGameDescription gameDescriptions[] = { GAME3_P("mh1", "2.0E 1988-10-05 (CE)", "mhdir", "2f1509f76f24e6e7d213f2dadebbf156", 0x3149, 0, GID_MH1, Common::kPlatformApple2GS), // Manhunter NY (Amiga) 1.06 3/18/89 - GAME3_P("mh1", "1.06 1989-03-18", "dirs", "92c6183042d1c2bb76236236a7d7a847", 0x3149, GF_OLDAMIGAV20, GID_MH1, Common::kPlatformAmiga), + GAME3_PO("mh1", "1.06 1989-03-18", "dirs", "92c6183042d1c2bb76236236a7d7a847", 0x3149, GF_OLDAMIGAV20, GID_MH1, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA), // reported by Filippos (thebluegr) in bugreport #1654500 // Manhunter NY (PC 5.25") 1.22 8/31/88 [AGI 3.002.107] @@ -442,7 +460,7 @@ static const AGIGameDescription gameDescriptions[] = { GAME3_P("mh2", "1.0 1989-07-29", "mh2dir", "5e3581495708b952fea24438a6c7e040", 0x3149, 0, GID_MH1, Common::kPlatformAtariST), // Manhunter SF (Amiga) 3.06 8/17/89 # 2.333 - GAME3_PS("mh2", "3.06 1989-08-17", "dirs", "b412e8a126368b76696696f7632d4c16", 2573, 0x3086, GF_OLDAMIGAV20, GID_MH2, Common::kPlatformAmiga), + GAME3_PSO("mh2", "3.06 1989-08-17", "dirs", "b412e8a126368b76696696f7632d4c16", 2573, 0x3086, GF_OLDAMIGAV20, GID_MH2, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA), // Manhunter SF (PC 5.25") 3.03 8/17/89 [AGI 3.002.149] GAME3("mh2", "3.03 1989-08-17 5.25\"", "mh2dir", "b90e4795413c43de469a715fb3c1fa93", 0x3149, GID_MH2), @@ -464,7 +482,7 @@ static const AGIGameDescription gameDescriptions[] = { // Mixed-Up Mother Goose (Amiga) 1.1 // Problematic: crashes // Menus not tested - GAME3_PS("mixedup", "1.1 1986-12-10", "dirs", "5c1295fe6daaf95831195ba12894dbd9", 2021, 0x3086, 0, GID_MIXEDUP, Common::kPlatformAmiga), + GAME3_PSO("mixedup", "1.1 1986-12-10", "dirs", "5c1295fe6daaf95831195ba12894dbd9", 2021, 0x3086, 0, GID_MIXEDUP, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA), #endif // Mixed Up Mother Goose (IIgs) @@ -486,7 +504,7 @@ static const AGIGameDescription gameDescriptions[] = { GAME_P("pq1", "2.0B 1988-04-21", "e7c175918372336461e3811d594f482f", 0x2917, GID_PQ1, Common::kPlatformApple2GS), // Police Quest 1 (Amiga) 2.0B 2/22/89 # 2.310 - GAME3_PS("pq1", "2.0B 1989-02-22", "dirs", "cfa93e5f2aa7378bddd10ad6746a2ffb", 1613, 0x3149, 0, GID_PQ1, Common::kPlatformAmiga), + GAME3_PSO("pq1", "2.0B 1989-02-22", "dirs", "cfa93e5f2aa7378bddd10ad6746a2ffb", 1613, 0x3149, 0, GID_PQ1, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA), // Police Quest 1 (IIgs) 2.0A-88318 GAME_P("pq1", "2.0A 1988-03-18", "8994e39d0901de3d07cecfb954075bb5", 0x2917, GID_PQ1, Common::kPlatformApple2GS), @@ -524,7 +542,7 @@ static const AGIGameDescription gameDescriptions[] = { // Space Quest 1 (Amiga) 1.2 # 2.082 // The original game did not have menus, they are enabled under ScummVM - GAME_FP("sq1", "1.2 1986", "0b216d931e95750f1f4837d6a4b821e5", 0x2440, GF_MENUS | GF_OLDAMIGAV20, GID_SQ1, Common::kPlatformAmiga), + GAME_FPO("sq1", "1.2 1986", "0b216d931e95750f1f4837d6a4b821e5", 0x2440, GF_MENUS | GF_OLDAMIGAV20, GID_SQ1, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA), // Space Quest 1 (Mac) 1.5D GAME_P("sq1", "1.5D 1987-04-02", "ce88419aadd073d1c6682d859b3d8aa2", 0x2440, GID_SQ1, Common::kPlatformMacintosh), @@ -570,7 +588,7 @@ static const AGIGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO0() + GAMEOPTIONS_AMIGA }, GID_SQ2, GType_V2, @@ -616,7 +634,7 @@ static const AGIGameDescription gameDescriptions[] = { GAMEpre_P("winnie", "", "title.pic", "2e7900c1ccaa7671d65405f6d1efed30", 0x0000, GID_WINNIE, Common::kPlatformDOS), // Winnie the Pooh in the Hundred Acre Wood (Amiga) - GAMEpre_P("winnie", "", "title", "2e7900c1ccaa7671d65405f6d1efed30", 0x0000, GID_WINNIE, Common::kPlatformAmiga), + GAMEpre_PO("winnie", "", "title", "2e7900c1ccaa7671d65405f6d1efed30", 0x0000, GID_WINNIE, Common::kPlatformAmiga, GAMEOPTIONS_AMIGA), // Winnie the Pooh in the Hundred Acre Wood (C64) GAMEpre_P("winnie", "", "title.pic", "d4eb97cffc866110f71e1ec9f84fe643", 0x0000, GID_WINNIE, Common::kPlatformC64), @@ -630,15 +648,15 @@ static const AGIGameDescription gameDescriptions[] = { // Xmas Card 1986 (CoCo3 360k) [AGI 2.072] GAME_PS("xmascard", "", "25ad35e9628fc77e5e0dd35852a272b6", 768, 0x2440, GID_XMASCARD, Common::kPlatformCoCo3), - FANMADE_F("2 Player Demo", "4279f46b3cebd855132496476b1d2cca", GF_AGIMOUSE), + FANMADE_FO("2 Player Demo", "4279f46b3cebd855132496476b1d2cca", GF_AGIMOUSE, GAMEOPTIONS_FANMADE_MOUSE), FANMADE("AGI Combat", "0be6a8a9e19203dcca0067d280798871"), FANMADE("AGI Contest 1 Template", "d879aed25da6fc655564b29567358ae2"), FANMADE("AGI Contest 2 Template", "5a2fb2894207eff36c72f5c1b08bcc07"), - FANMADE("AGI Mouse Demo 0.60 demo 1", "c07e2519de674c67386cb2cc6f2e3904"), - FANMADE("AGI Mouse Demo 0.60 demo 2", "cc49d8b88ed6faf4f53ce92c84e0fe1b"), - FANMADE("AGI Mouse Demo 0.70", "3497c291e4afb6f758e61740678a2aec"), - FANMADE_F("AGI Mouse Demo 1.00", "20397f0bf0ef936f416bb321fb768fc7", GF_AGIMOUSE), - FANMADE_F("AGI Mouse Demo 1.10", "f4ad396b496d6167635ad0b410312ab8", GF_AGIMOUSE|GF_AGIPAL), + FANMADE_O("AGI Mouse Demo 0.60 demo 1", "c07e2519de674c67386cb2cc6f2e3904", GAMEOPTIONS_FANMADE_MOUSE), + FANMADE_O("AGI Mouse Demo 0.60 demo 2", "cc49d8b88ed6faf4f53ce92c84e0fe1b", GAMEOPTIONS_FANMADE_MOUSE), + FANMADE_O("AGI Mouse Demo 0.70", "3497c291e4afb6f758e61740678a2aec", GAMEOPTIONS_FANMADE_MOUSE), + FANMADE_FO("AGI Mouse Demo 1.00", "20397f0bf0ef936f416bb321fb768fc7", GF_AGIMOUSE, GAMEOPTIONS_FANMADE_MOUSE), + FANMADE_FO("AGI Mouse Demo 1.10", "f4ad396b496d6167635ad0b410312ab8", GF_AGIMOUSE|GF_AGIPAL, GAMEOPTIONS_FANMADE_MOUSE), FANMADE("AGI Piano (v1.0)", "8778b3d89eb93c1d50a70ef06ef10310"), FANMADE("AGI Quest (v1.46-TJ0)", "1cf1a5307c1a0a405f5039354f679814"), GAME("tetris", "", "7a874e2db2162e7a4ce31c9130248d8a", 0x2917, GID_FANMADE), @@ -657,15 +675,15 @@ static const AGIGameDescription gameDescriptions[] = { FANMADE("Al Pond 1 - Al Lives Forever (v1.0)", "e8921c3043b749b056ff51f56d1b451b"), FANMADE("Al Pond 1 - Al Lives Forever (v1.3)", "fb4699474054962e0dbfb4cf12ca52f6"), FANMADE("Apocalyptic Quest (v0.03 Teaser)", "42ced528b67965d3bc3b52c635f94a57"), - FANMADE_F("Apocalyptic Quest (v4.00 Alpha 1)", "e15581628d84949b8d352d224ec3184b", GF_AGIMOUSE), - FANMADE_F("Apocalyptic Quest (v4.00 Alpha 2)", "0eee850005860e46345b38fea093d194", GF_AGIMOUSE), - FANMADE_F("Band Quest (Demo)", "7326abefd793571cc17ed0db647bdf34", GF_AGIMOUSE), - FANMADE_F("Band Quest (Early Demo)", "de4758dd34676b248c8301b32d93bc6f", GF_AGIMOUSE), + FANMADE_FO("Apocalyptic Quest (v4.00 Alpha 1)", "e15581628d84949b8d352d224ec3184b", GF_AGIMOUSE, GAMEOPTIONS_FANMADE_MOUSE), + FANMADE_FO("Apocalyptic Quest (v4.00 Alpha 2)", "0eee850005860e46345b38fea093d194", GF_AGIMOUSE, GAMEOPTIONS_FANMADE_MOUSE), + FANMADE_FO("Band Quest (Demo)", "7326abefd793571cc17ed0db647bdf34", GF_AGIMOUSE, GAMEOPTIONS_FANMADE_MOUSE), + FANMADE_FO("Band Quest (Early Demo)", "de4758dd34676b248c8301b32d93bc6f", GF_AGIMOUSE, GAMEOPTIONS_FANMADE_MOUSE), FANMADE("Beyond the Titanic 2", "9b8de38dc64ffb3f52b7877ea3ebcef9"), FANMADE("Biri Quest 1", "1b08f34f2c43e626c775c9d6649e2f17"), FANMADE("Bob The Farmboy", "e4b7df9d0830addee5af946d380e66d7"), - FANMADE_F("Boring Man 1: The Toad to Robinland", "d74481cbd227f67ace37ce6a5493039f", GF_AGIMOUSE), - FANMADE_F("Boring Man 2: Ho Man! This Game Sucks!", "250032ba105bdf7c1bc4fed767c2d37e", GF_AGIMOUSE), + FANMADE_FO("Boring Man 1: The Toad to Robinland", "d74481cbd227f67ace37ce6a5493039f", GF_AGIMOUSE, GAMEOPTIONS_FANMADE_MOUSE), + FANMADE_FO("Boring Man 2: Ho Man! This Game Sucks!", "250032ba105bdf7c1bc4fed767c2d37e", GF_AGIMOUSE, GAMEOPTIONS_FANMADE_MOUSE), FANMADE("Botz", "a8fabe4e807adfe5ec02bfec6d983695"), FANMADE("Brian's Quest (v1.0)", "0964aa79b9cdcff7f33a12b1d7e04b9c"), FANMADE("CPU-21 (v1.0)", "35b7cdb4d17e890e4c52018d96e9cbf4"), @@ -676,12 +694,12 @@ static const AGIGameDescription gameDescriptions[] = { FANMADE("Coco Coq (English) - Coco Coq In Grostesteing's Base (v.1.0.3)", "97631f8e710544a58bd6da9e780f9320"), FANMADE_L("Coco Coq (French) - Coco Coq Dans la Base de Grostesteing (v1.0.2)", "ef579ebccfe5e356f9a557eb3b2d8649", Common::FR_FRA), FANMADE("Corby's Murder Mystery (v1.0)", "4ebe62ac24c5a8c7b7898c8eb070efe5"), - FANMADE_F("DG: The AGIMouse Adventure (English v1.1)", "efe453b92bc1487ea69fbebede4d5f26", GF_AGIMOUSE|GF_AGIPAL), - FANMADE_LF("DG: The AGIMouse Adventure (French v1.1)", "eb3d17ca466d672cbb95947e8d6e846a", Common::FR_FRA, GF_AGIMOUSE|GF_AGIPAL), + FANMADE_FO("DG: The AGIMouse Adventure (English v1.1)", "efe453b92bc1487ea69fbebede4d5f26", GF_AGIMOUSE|GF_AGIPAL, GAMEOPTIONS_FANMADE_MOUSE), + FANMADE_LFO("DG: The AGIMouse Adventure (French v1.1)", "eb3d17ca466d672cbb95947e8d6e846a", Common::FR_FRA, GF_AGIMOUSE|GF_AGIPAL, GAMEOPTIONS_FANMADE_MOUSE), FANMADE("DG: The Adventure Game (English v1.1)", "0d6376d493fa7a21ec4da1a063e12b25"), FANMADE_L("DG: The Adventure Game (French v1.1)", "258bdb3bb8e61c92b71f2f456cc69e23", Common::FR_FRA), FANMADE("Dashiki (16 Colors)", "9b2c7b9b0283ab9f12bedc0cb6770a07"), - FANMADE_F("Dashiki (256 Colors)", "c68052bb209e23b39b55ff3d759958e6", GF_AGIMOUSE|GF_AGI256), + FANMADE_FO("Dashiki (256 Colors)", "c68052bb209e23b39b55ff3d759958e6", GF_AGIMOUSE|GF_AGI256, GAMEOPTIONS_FANMADE_MOUSE), FANMADE("Date Quest 1 (v1.0)", "ba3dcb2600645be53a13170aa1a12e69"), FANMADE("Date Quest 2 (v1.0 Demo)", "1602d6a2874856e928d9a8c8d2d166e9"), FANMADE("Date Quest 2 (v1.0)", "f13f6fc85aa3e6e02b0c20408fb63b47"), @@ -708,20 +726,20 @@ static const AGIGameDescription gameDescriptions[] = { FANMADE("Good Man (demo v3.41)", "3facd8a8f856b7b6e0f6c3200274d88c"), GAME_LVFPNF("agi-fanmade", "Groza (russian) [AGDS sample]", "logdir", "421da3a18004122a966d64ab6bd86d2e", -1, - Common::RU_RUS, 0x2440, GF_AGDS, GID_FANMADE, Common::kPlatformDOS,GType_V2), + Common::RU_RUS, 0x2440, GF_AGDS, GID_FANMADE, Common::kPlatformDOS,GType_V2,GAMEOPTIONS_DEFAULT), GAME_LVFPNF("agi-fanmade", "Get Outta Space Quest", "logdir", "aaea5b4a348acb669d13b0e6f22d4dc9", -1, - Common::EN_ANY, 0x2440, GF_FANMADE, GID_GETOUTTASQ, Common::kPlatformDOS,GType_V2), + Common::EN_ANY, 0x2440, GF_FANMADE, GID_GETOUTTASQ, Common::kPlatformDOS,GType_V2,GAMEOPTIONS_DEFAULT), - FANMADE_F("Half-Death - Terror At White-Mesa", "b62c05d0ace878261392073f57ae788c", GF_AGIMOUSE), + FANMADE_FO("Half-Death - Terror At White-Mesa", "b62c05d0ace878261392073f57ae788c", GF_AGIMOUSE, GAMEOPTIONS_FANMADE_MOUSE), FANMADE("Hank's Quest (v1.0 English) - Victim of Society", "64c15b3d0483d17888129100dc5af213"), FANMADE("Hank's Quest (v1.1 English) - Victim of Society", "86d1f1dd9b0c4858d096e2a60cca8a14"), FANMADE_L("Hank's Quest (v1.81 Dutch) - Slachtoffer Van Het Gebeuren", "41e53972d55ff3dff9e90d15fe1b659f", Common::NL_NLD), FANMADE("Hank's Quest (v1.81 English) - Victim of Society", "7a776383282f62a57c3a960dafca62d1"), FANMADE("Herbao (v0.2)", "6a5186fc8383a9060517403e85214fc2"), - FANMADE_F("Hitler's Legacy (v.0004q)", "a412881269ba34584bd0a3268e5a9863", GF_AGIMOUSE), + FANMADE_FO("Hitler's Legacy (v.0004q)", "a412881269ba34584bd0a3268e5a9863", GF_AGIMOUSE, GAMEOPTIONS_FANMADE_MOUSE), FANMADE("Hobbits", "4a1c1ef3a7901baf0ab45fde0cfadd89"), - FANMADE_F("Isabella Coq - A Present For My Dad", "55c6819f2330c4d5d6459874c9f123d9", GF_AGIMOUSE), + FANMADE_FO("Isabella Coq - A Present For My Dad", "55c6819f2330c4d5d6459874c9f123d9", GF_AGIMOUSE, GAMEOPTIONS_FANMADE_MOUSE), FANMADE("Jack & Julia - VAMPYR", "8aa0b9a26f8d5a4421067ab8cc3706f6"), FANMADE("Jeff's Quest (v.5 alpha Jun 1)", "10f1720eed40c12b02a0f32df3e72ded"), FANMADE("Jeff's Quest (v.5 alpha May 31)", "51ff71c0ed90db4e987a488ed3bf0551"), @@ -730,8 +748,8 @@ static const AGIGameDescription gameDescriptions[] = { FANMADE("Jiggy Jiggy Uh! Uh!", "bc331588a71e7a1c8840f6cc9b9487e4"), FANMADE("Jimmy In: The Alien Attack (v0.1)", "a4e9db0564a494728de7873684a4307c"), FANMADE("Joe McMuffin In \"What's Cooking, Doc\" (v1.0)", "8a3de7e61a99cb605fa6d233dd91c8e1"), - FANMADE_LVF("Jolimie, le Village Maudit (v0.5)", "21818501636b3cb8ad5de5c1a66de5c2", Common::FR_FRA, 0x2936, GF_AGIMOUSE|GF_AGIPAL), - FANMADE_LVF("Jolimie, le Village Maudit (v1.1)", "68d7aef1161bb5972fe03efdf29ccb7f", Common::FR_FRA, 0x2936, GF_AGIMOUSE|GF_AGIPAL), + FANMADE_LVFO("Jolimie, le Village Maudit (v0.5)", "21818501636b3cb8ad5de5c1a66de5c2", Common::FR_FRA, 0x2936, GF_AGIMOUSE|GF_AGIPAL, GAMEOPTIONS_FANMADE_MOUSE), + FANMADE_LVFO("Jolimie, le Village Maudit (v1.1)", "68d7aef1161bb5972fe03efdf29ccb7f", Common::FR_FRA, 0x2936, GF_AGIMOUSE|GF_AGIPAL, GAMEOPTIONS_FANMADE_MOUSE), FANMADE("Journey Of Chef", "aa0a0b5a6364801ae65fdb96d6741df5"), FANMADE("Jukebox (v1.0)", "c4b9c5528cc67f6ba777033830de7751"), FANMADE("Justin Quest (v1.0 in development)", "103050989da7e0ffdc1c5e1793a4e1ec"), @@ -747,18 +765,18 @@ static const AGIGameDescription gameDescriptions[] = { FANMADE("MD Quest - The Search for Michiel (v0.10)", "2a6fcb21d2b5e4144c38ed817fabe8ee"), FANMADE("Maale Adummin Quest", "ddfbeb33feb7cf78504fe4dba14ec63b"), FANMADE("Monkey Man", "2322d03f997e8cc235d4578efff69cfa"), - FANMADE_F("Napalm Quest (v0.5)", "b659afb491d967bb34810d1c6ce22093", GF_AGIMOUSE), + FANMADE_FO("Napalm Quest (v0.5)", "b659afb491d967bb34810d1c6ce22093", GF_AGIMOUSE, GAMEOPTIONS_FANMADE_MOUSE), FANMADE("Naturette 1 (English v1.2)", "0a75884e7f010974a230bdf269651117"), FANMADE("Naturette 1 (English v1.3)", "f15bbf999ac55ebd404aa1eb84f7c1d9"), FANMADE_L("Naturette 1 (French v1.2)", "d3665622cc41aeb9c7ecf4fa43f20e53", Common::FR_FRA), - FANMADE_F("Naturette 2: Daughter of the Moon (v1.0)", "bdf76a45621c7f56d1c9d40292c6137a", GF_AGIMOUSE|GF_AGIPAL), - FANMADE_F("Naturette 3: Adventure in Treeworld (v1.0a)", "6dbb0e7fc75fec442e6d9e5a06f1530e", GF_AGIMOUSE|GF_AGIPAL), - FANMADE_F("Naturette 4: From a Planet to Another Planet (Not Finished)", "13be8cd9cf35aeff0a39b8757057fbc8", GF_AGIMOUSE), + FANMADE_FO("Naturette 2: Daughter of the Moon (v1.0)", "bdf76a45621c7f56d1c9d40292c6137a", GF_AGIMOUSE|GF_AGIPAL, GAMEOPTIONS_FANMADE_MOUSE), + FANMADE_FO("Naturette 3: Adventure in Treeworld (v1.0a)", "6dbb0e7fc75fec442e6d9e5a06f1530e", GF_AGIMOUSE|GF_AGIPAL, GAMEOPTIONS_FANMADE_MOUSE), + FANMADE_FO("Naturette 4: From a Planet to Another Planet (Not Finished)", "13be8cd9cf35aeff0a39b8757057fbc8", GF_AGIMOUSE, GAMEOPTIONS_FANMADE_MOUSE), // FIXME: Actually Naturette 4 has both English and French language support built into it. How to add that information? - FANMADE_F("Naturette 4: From a Planet to Another Planet (2007-10-05)", "8253706b6ef5423a79413b216760297c", GF_AGIMOUSE|GF_AGIPAL), + FANMADE_FO("Naturette 4: From a Planet to Another Planet (2007-10-05)", "8253706b6ef5423a79413b216760297c", GF_AGIMOUSE|GF_AGIPAL, GAMEOPTIONS_FANMADE_MOUSE), FANMADE("New AGI Hangman Test", "d69c0e9050ccc29fd662b74d9fc73a15"), FANMADE("Nick's Quest - In Pursuit of QuakeMovie (v2.1 Gold)", "e29cbf9222551aee40397fabc83eeca0"), - FANMADE_F("Open Mic Night (v0.1)", "70000a2f67aac27d1133d019df70246d", GF_AGIMOUSE|GF_AGIPAL), + FANMADE_FO("Open Mic Night (v0.1)", "70000a2f67aac27d1133d019df70246d", GF_AGIMOUSE|GF_AGIPAL, GAMEOPTIONS_FANMADE_MOUSE), FANMADE("Operation: Recon", "0679ce8405411866ccffc8a6743370d0"), FANMADE("Patrick's Quest (Demo v1.0)", "f254f5b894b98fec5f92acc07fb62841"), FANMADE("Phantasmagoria", "87d20c1c11aee99a4baad3797b63146b"), @@ -802,14 +820,14 @@ static const AGIGameDescription gameDescriptions[] = { FANMADE("Save Santa (v1.3)", "f8afdb6efc5af5e7c0228b44633066af"), FANMADE("Schiller (preview 1)", "ade39dea968c959cfebe1cf935d653e9"), FANMADE("Schiller (preview 2)", "62cd1f8fc758bf6b4aa334e553624cef"), - GAME_F("serguei1", "v1.0", "b86725f067e456e10cdbdf5f58e01dec", 0x2917, GF_FANMADE|GF_AGIMOUSE|GF_AGIPAL, GID_FANMADE), + GAME_FO("serguei1", "v1.0", "b86725f067e456e10cdbdf5f58e01dec", 0x2917, GF_FANMADE|GF_AGIMOUSE|GF_AGIPAL, GID_FANMADE, GAMEOPTIONS_FANMADE_MOUSE), // FIXME: The following two entries have identical MD5 checksums? - GAME_F("serguei1", "v1.1 2002 Sep 5", "91975c1fb4b13b0f9a8e9ff74731030d", 0x2917, GF_FANMADE|GF_AGIMOUSE|GF_AGIPAL, GID_FANMADE), - GAME_F("serguei1", "v1.1 2003 Apr 10", "91975c1fb4b13b0f9a8e9ff74731030d", 0x2917, GF_FANMADE|GF_AGIMOUSE|GF_AGIPAL, GID_FANMADE), - GAME_F("serguei2", "v0.1.1 Demo", "906ccbc2ddedb29b63141acc6d10cd28", 0x2917, GF_FANMADE|GF_AGIMOUSE, GID_FANMADE), - GAME_F("serguei2", "v1.3.1 Demo (March 22nd 2008)", "ad1308fcb8f48723cd388e012ebf5e20", 0x2917, GF_FANMADE|GF_AGIMOUSE|GF_AGIPAL, GID_FANMADE), + GAME_FO("serguei1", "v1.1 2002 Sep 5", "91975c1fb4b13b0f9a8e9ff74731030d", 0x2917, GF_FANMADE|GF_AGIMOUSE|GF_AGIPAL, GID_FANMADE, GAMEOPTIONS_FANMADE_MOUSE), + GAME_FO("serguei1", "v1.1 2003 Apr 10", "91975c1fb4b13b0f9a8e9ff74731030d", 0x2917, GF_FANMADE|GF_AGIMOUSE|GF_AGIPAL, GID_FANMADE, GAMEOPTIONS_FANMADE_MOUSE), + GAME_FO("serguei2", "v0.1.1 Demo", "906ccbc2ddedb29b63141acc6d10cd28", 0x2917, GF_FANMADE|GF_AGIMOUSE, GID_FANMADE, GAMEOPTIONS_FANMADE_MOUSE), + GAME_FO("serguei2", "v1.3.1 Demo (March 22nd 2008)", "ad1308fcb8f48723cd388e012ebf5e20", 0x2917, GF_FANMADE|GF_AGIMOUSE|GF_AGIPAL, GID_FANMADE, GAMEOPTIONS_FANMADE_MOUSE), FANMADE("Shifty (v1.0)", "2a07984d27b938364bf6bd243ac75080"), - FANMADE_F("Sliding Tile Game (v1.00)", "949bfff5d8a81c3139152eed4d84ca75", GF_AGIMOUSE), + FANMADE_FO("Sliding Tile Game (v1.00)", "949bfff5d8a81c3139152eed4d84ca75", GF_AGIMOUSE, GAMEOPTIONS_FANMADE_MOUSE), FANMADE("Snowboarding Demo (v1.0)", "24bb8f29f1eddb5c0a099705267c86e4"), FANMADE("Solar System Tour", "b5a3d0f392dfd76a6aa63f3d5f578403"), FANMADE("Sorceror's Appraisal", "fe62615557b3cb7b08dd60c9d35efef1"), @@ -819,7 +837,7 @@ static const AGIGameDescription gameDescriptions[] = { GAME("sqx", "v10.0 Feb 05", "c992ae2f8ab18360404efdf16fa9edd1", 0x2917, GID_FANMADE), GAME("sqx", "v10.0 Jul 18", "812edec45cefad559d190ffde2f9c910", 0x2917, GID_FANMADE), GAME_PS("sqx", "", "f0a59044475a5fa37c055d8c3eb4d1a7", 768, 0x2440, GID_FANMADE, Common::kPlatformCoCo3), - FANMADE_F("Space Quest 3.5", "c077bc28d7b36213dd99dc9ecb0147fc", GF_AGIMOUSE|GF_AGIPAL), + FANMADE_FO("Space Quest 3.5", "c077bc28d7b36213dd99dc9ecb0147fc", GF_AGIMOUSE|GF_AGIPAL, GAMEOPTIONS_FANMADE_MOUSE), FANMADE_F("Space Trek (v1.0)", "807a1aeadb2ace6968831d36ab5ea37a", GF_CLIPCOORDS), FANMADE("Special Delivery", "88764dfe61126b8e73612c851b510a33"), FANMADE("Speeder Bike Challenge (v1.0)", "2deb25bab379285ca955df398d96c1e7"), @@ -862,7 +880,7 @@ static const AGIGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformDOS, ADGF_USEEXTRAASTITLE, - GUIO0() + GAMEOPTIONS_DEFAULT }, GID_FANMADE, GType_V3, @@ -890,7 +908,7 @@ static AGIGameDescription g_fallbackDesc = { Common::UNK_LANG, Common::kPlatformDOS, ADGF_NO_FLAGS, - GUIO0() + GAMEOPTIONS_DEFAULT }, GID_FANMADE, GType_V2, diff --git a/engines/agi/font.h b/engines/agi/font.h index c77d8cf0c3..0e6b15f06b 100644 --- a/engines/agi/font.h +++ b/engines/agi/font.h @@ -26,7 +26,7 @@ namespace Agi { // 8x8 font patterns -static const uint8 curFont[] = { +static const uint8 fontData_Sierra[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, // cursor hollow 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, // cursor solid @@ -59,6 +59,267 @@ static const uint8 curFont[] = { 0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, + // original sierra font starts here + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 Space + 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00, + 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, + 0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00, + 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00, + 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00, + 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, + 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, + 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, + 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, + 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, + 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, + 0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00, // 0x30 + 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00, + 0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00, + 0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00, + 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00, + 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00, + 0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00, + 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, + 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00, + 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, + 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60, + 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, + 0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, // 0x40 + 0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, + 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00, + 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, + 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00, + 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00, + 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00, + 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00, + 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, + 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00, + 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, + 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, + 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, + 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, // 0x50 + 0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00, + 0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00, + 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, + 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00, + 0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00, + 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00, + 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00, + 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, + 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, + 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, + 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60 + 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00, + 0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00, + 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, + 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, + 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, + 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00, + 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, + 0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, // 0x70 + 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E, + 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00, + 0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00, + 0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, + 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00, + 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, + 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00, + 0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00, + 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, + 0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00, + 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // custom font starting here at 0x80 + 0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, // 0x80 + 0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, + 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, + 0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, + 0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6, + 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00, + 0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00, + 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00, + 0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, + 0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, + 0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00, + 0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, + 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, + 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, + 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, + 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00, + 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00, + 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00, + 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00, + 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03, + 0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03, + 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, + 0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00, + 0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, + 0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00, + 0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00, + 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00, + 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00, + 0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00, + 0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00, + 0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6, + 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, + 0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00, + 0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00, + 0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00, + 0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00, + 0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00, + 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, + 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, + 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, + 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36, + 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, + 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, + 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, + 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, + 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36, + 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00, + 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00, + 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03, + 0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00, + 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00, + 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03, + 0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00, + 0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00, + 0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00, + 0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00, + 0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00, + 0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, + 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00, + 0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, + 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, + 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70, + 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, + 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00, + 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, + 0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10, + 0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C, + 0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00 +}; + +static const uint8 fontData_FanGames[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, /* cursor hollow */ + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, /* cursor solid */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* cursor empty */ + 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, + 0x3C, 0x3C, 0x18, 0xFF, 0xE7, 0x18, 0x3C, 0x00, + 0x10, 0x38, 0x7C, 0xFE, 0xEE, 0x10, 0x38, 0x00, + 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, + 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, + 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* \n */ + 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78, + 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, + 0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00, + 0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C, + 0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00, + 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00, + 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00, + 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, + 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00, + 0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00, + 0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E, + 0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00, + 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, + 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, + 0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00, + 0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00, 0x6C, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -154,9 +415,7 @@ static const uint8 curFont[] = { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xE0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xE0, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - //0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //replacement 0x7F - + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /*replacement 0x7F */ 0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, 0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, @@ -287,7 +546,7 @@ static const uint8 curFont[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00 }; -static const uint8 mickey_fontdata[] = { +static const uint8 fontData_Mickey[] = { 0x00, 0x36, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00, 0x3F, 0x20, 0x2F, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, @@ -546,7 +805,7 @@ static const uint8 mickey_fontdata[] = { 0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00, }; -static const uint8 ibm_fontdata[] = { +static const uint8 fontData_IBM[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E, 0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp index 2b1bd8c829..32d0fdc06a 100644 --- a/engines/agi/graphics.cpp +++ b/engines/agi/graphics.cpp @@ -616,6 +616,8 @@ void GfxMgr::putTextCharacter(int l, int x, int y, unsigned char c, int fg, int int x1, y1, xx, yy, cc; const uint8 *p; + assert(font); + p = font + ((unsigned int)c * CHAR_LINES); for (y1 = 0; y1 < CHAR_LINES; y1++) { for (x1 = 0; x1 < CHAR_COLS; x1++) { @@ -699,7 +701,7 @@ void GfxMgr::printCharacter(int x, int y, char c, int fg, int bg) { x *= CHAR_COLS; y *= CHAR_LINES; - putTextCharacter(0, x, y, c, fg, bg); + putTextCharacter(0, x, y, c, fg, bg, false, _vm->getFontData()); // redundant! already inside put_text_character! // flush_block (x, y, x + CHAR_COLS - 1, y + CHAR_LINES - 1); } @@ -754,7 +756,7 @@ void GfxMgr::rawDrawButton(int x, int y, const char *s, int fgcolor, int bgcolor drawRectangle(x1, y1, x2, y2, border ? BUTTON_BORDER : MSG_BOX_COLOR); while (*s) { - putTextCharacter(0, x + textOffset, y + textOffset, *s++, fgcolor, bgcolor); + putTextCharacter(0, x + textOffset, y + textOffset, *s++, fgcolor, bgcolor, false, _vm->getFontData()); x += CHAR_COLS; } diff --git a/engines/agi/graphics.h b/engines/agi/graphics.h index 15668fbed3..506a9d93d6 100644 --- a/engines/agi/graphics.h +++ b/engines/agi/graphics.h @@ -56,7 +56,7 @@ public: void gfxPutBlock(int x1, int y1, int x2, int y2); - void putTextCharacter(int, int, int, unsigned char, int, int, bool checkerboard = false, const uint8 *font = curFont); + void putTextCharacter(int, int, int, unsigned char, int, int, bool checkerboard = false, const uint8 *font = fontData_Sierra); void shakeScreen(int); void shakeStart(); void shakeEnd(); diff --git a/engines/agi/preagi.cpp b/engines/agi/preagi.cpp index daadb5ffef..c368c7b195 100644 --- a/engines/agi/preagi.cpp +++ b/engines/agi/preagi.cpp @@ -59,6 +59,12 @@ void PreAgiEngine::initialize() { _gfx = new GfxMgr(this); _picture = new PictureMgr(this, _gfx); + if (getGameID() == GID_MICKEY) { + _fontData = fontData_Mickey; + } else { + _fontData = fontData_IBM; + } + _gfx->initMachine(); _game.gameFlags = 0; @@ -137,7 +143,7 @@ void PreAgiEngine::drawStr(int row, int col, int attr, const char *buffer) { break; default: - _gfx->putTextCharacter(1, col * 8 , row * 8, static_cast<char>(code), attr & 0x0f, (attr & 0xf0) / 0x10, false, getGameID() == GID_MICKEY ? mickey_fontdata : ibm_fontdata); + _gfx->putTextCharacter(1, col * 8 , row * 8, static_cast<char>(code), attr & 0x0f, (attr & 0xf0) / 0x10, false, _fontData); if (++col == 320 / 8) { col = 0; diff --git a/engines/agi/sound_pcjr.cpp b/engines/agi/sound_pcjr.cpp index 51b2d067a4..ea7a2789e0 100644 --- a/engines/agi/sound_pcjr.cpp +++ b/engines/agi/sound_pcjr.cpp @@ -120,8 +120,6 @@ SoundGenPCJr::SoundGenPCJr(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMi else _dissolveMethod = 0; - _dissolveMethod = 3; - memset(_channel, 0, sizeof(_channel)); memset(_tchannel, 0, sizeof(_tchannel)); @@ -207,9 +205,6 @@ int SoundGenPCJr::volumeCalc(SndGenChan *chan) { chan->attenuationCopy = attenuation; attenuation &= 0x0F; - attenuation += _mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 17; - if (attenuation > 0x0F) - attenuation = 0x0F; } } //if (computer_type == 2) && (attenuation < 8) @@ -411,7 +406,7 @@ int SoundGenPCJr::chanGen(int chan, int16 *stream, int len) { if (tpcm->noteCount <= 0) { // get new tone data if ((tpcm->avail) && (getNextNote(chan) == 0)) { - tpcm->atten = _channel[chan].attenuation; + tpcm->atten = volumeCalc(&_channel[chan]); tpcm->freqCount = _channel[chan].freqCount; tpcm->genType = _channel[chan].genType; @@ -477,8 +472,9 @@ int SoundGenPCJr::fillSquare(ToneChan *t, int16 *buf, int len) { count = len; + int16 amp = (int16)(volTable[t->atten] * _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) / Audio::Mixer::kMaxMixerVolume); while (count > 0) { - *(buf++) = t->sign ? volTable[t->atten] : -volTable[t->atten]; + *(buf++) = t->sign ? amp : -amp; count--; // get next sample @@ -515,8 +511,9 @@ int SoundGenPCJr::fillNoise(ToneChan *t, int16 *buf, int len) { count = len; + int16 amp = (int16)(volTable[t->atten] * _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) / Audio::Mixer::kMaxMixerVolume); while (count > 0) { - *(buf++) = t->sign ? volTable[t->atten] : -volTable[t->atten]; + *(buf++) = t->sign ? amp : -amp; count--; // get next sample diff --git a/engines/agi/text.cpp b/engines/agi/text.cpp index eb48857bf2..16c8284ce0 100644 --- a/engines/agi/text.cpp +++ b/engines/agi/text.cpp @@ -50,7 +50,7 @@ void AgiEngine::printText2(int l, const char *msg, int foff, int xoff, int yoff, // FR: strings with len == 1 were not printed if (len == 1) { - _gfx->putTextCharacter(l, xoff + foff, yoff, *msg, fg, bg, checkerboard); + _gfx->putTextCharacter(l, xoff + foff, yoff, *msg, fg, bg, checkerboard, _fontData); maxx = 1; minx = 0; ofoff = foff; @@ -74,7 +74,7 @@ void AgiEngine::printText2(int l, const char *msg, int foff, int xoff, int yoff, if (xpos >= GFX_WIDTH) continue; - _gfx->putTextCharacter(l, xpos, ypos, *m, fg, bg, checkerboard); + _gfx->putTextCharacter(l, xpos, ypos, *m, fg, bg, checkerboard, _fontData); if (x1 > maxx) maxx = x1; diff --git a/engines/agos/rooms.cpp b/engines/agos/rooms.cpp index 6185653d42..d1d6f2b99d 100644 --- a/engines/agos/rooms.cpp +++ b/engines/agos/rooms.cpp @@ -383,7 +383,7 @@ bool AGOSEngine::loadRoomItems(uint16 room) { for (uint16 z = minNum; z <= maxNum; z++) { uint16 itemNum = z + 2; item = derefItem(itemNum); - item->parent = 0; + _itemArrayPtr[itemNum] = 0; uint16 num = (itemNum - _itemArrayInited); _roomStates[num].state = item->state; @@ -453,6 +453,7 @@ bool AGOSEngine::loadRoomItems(uint16 room) { item->classFlags = _roomStates[num].classFlags; SubRoom *subRoom = (SubRoom *)findChildOfType(item, kRoomType); subRoom->roomExitStates = _roomStates[num].roomExitStates; + } in.close(); diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp index 5d5e2d7b03..b968ae645c 100644 --- a/engines/agos/saveload.cpp +++ b/engines/agos/saveload.cpp @@ -1261,7 +1261,6 @@ bool AGOSEngine_Elvira2::loadGame(const Common::String &filename, bool restartMo uint16 room = _currentRoom; _currentRoom = f->readUint16BE(); - if (_roomsListPtr) { byte *p = _roomsListPtr; if (room == _currentRoom) { @@ -1293,8 +1292,7 @@ bool AGOSEngine_Elvira2::loadGame(const Common::String &filename, bool restartMo for (uint16 z = minNum; z <= maxNum; z++) { uint16 itemNum = z + 2; - Item *item = derefItem(itemNum); - item->parent = 0; + _itemArrayPtr[itemNum] = 0; } } } @@ -1318,6 +1316,9 @@ bool AGOSEngine_Elvira2::loadGame(const Common::String &filename, bool restartMo uint parent = f->readUint16BE(); uint next = f->readUint16BE(); + if (getGameType() == GType_WW && getPlatform() == Common::kPlatformDOS && derefItem(item->parent) == NULL) + item->parent = 0; + parent_item = derefItem(parent); setItemParent(item, parent_item); diff --git a/engines/cine/detection_tables.h b/engines/cine/detection_tables.h index 6069e3a99b..1188deb1a6 100644 --- a/engines/cine/detection_tables.h +++ b/engines/cine/detection_tables.h @@ -379,6 +379,20 @@ static const CINEGameDescription gameDescriptions[] = { { { "os", + "Demo", + AD_ENTRY1("demo_os", "043859e4cfe3977ad95b6efd00b21c62"), + Common::EN_GRB, + Common::kPlatformDOS, + ADGF_DEMO | ADGF_UNSTABLE, + GUIO0() + }, + GType_OS, + GF_DEMO, + }, + + { + { + "os", "", AD_ENTRY1("procs0", "a9da5531ead0ebf9ad387fa588c0cbb0"), Common::EN_GRB, diff --git a/engines/fullpipe/scene.cpp b/engines/fullpipe/scene.cpp index 00dd70c1b2..5a3fbe34b6 100644 --- a/engines/fullpipe/scene.cpp +++ b/engines/fullpipe/scene.cpp @@ -672,11 +672,6 @@ void Scene::drawContent(int minPri, int maxPri, bool drawBg) { debug(1, "_bigPict: %d objlist: %d", _bigPictureArray1Count, _picObjList.size()); - for (uint i = 0; i < _picObjList.size(); i++) { - debug(1, "%d: %d", i, ((PictureObject *)_picObjList[i])->_priority); - } - - if (drawBg && _bigPictureArray1Count && _picObjList.size()) { _bigPictureArray[0][0]->getDimensions(&point); @@ -743,7 +738,6 @@ void Scene::drawContent(int minPri, int maxPri, bool drawBg) { for (uint i = 1; i < _picObjList.size(); i++) { PictureObject *obj = (PictureObject *)_picObjList[i]; - debug(8, "pri: %d", obj->_priority); if (obj->_priority < minPri || obj->_priority >= maxPri) continue; diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp index 89ee41e859..c0e0f67b8e 100644 --- a/engines/kyra/sound_adlib.cpp +++ b/engines/kyra/sound_adlib.cpp @@ -947,15 +947,10 @@ void AdLibDriver::unkOutput2(uint8 chan) { // // This is very strange behavior, and causes problems with the ancient // FMOPL code we borrowed from AdPlug. I've added a workaround. See - // fmopl.cpp for more details. + // audio/softsynth/opl/mame.cpp for more details. // - // More recent versions of the MAME FMOPL don't seem to have this - // problem, but cannot currently be used because of licensing and - // performance issues. - // - // Ken Silverman's AdLib emulator (which can be found on his Web page - - // http://www.advsys.net/ken - and as part of AdPlug) also seems to be - // immune, but is apparently not as feature complete as MAME's. + // Fortunately, the more modern DOSBox FMOPL code does not seem to have + // any trouble with this. writeOPL(0xB0 + chan, 0x20); } diff --git a/engines/mads/action.cpp b/engines/mads/action.cpp index 628f03526f..f1c562675f 100644 --- a/engines/mads/action.cpp +++ b/engines/mads/action.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/action.h b/engines/mads/action.h index cfd5a3be3f..3ea10cd964 100644 --- a/engines/mads/action.h +++ b/engines/mads/action.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/animation.cpp b/engines/mads/animation.cpp index cf02e7b0b5..e4f44fc308 100644 --- a/engines/mads/animation.cpp +++ b/engines/mads/animation.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/animation.h b/engines/mads/animation.h index 1c87273e62..46ef85c5eb 100644 --- a/engines/mads/animation.h +++ b/engines/mads/animation.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/assets.cpp b/engines/mads/assets.cpp index a2d495f311..1d4634e383 100644 --- a/engines/mads/assets.cpp +++ b/engines/mads/assets.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/assets.h b/engines/mads/assets.h index 155590f9bd..8a0dc2cd44 100644 --- a/engines/mads/assets.h +++ b/engines/mads/assets.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/audio.cpp b/engines/mads/audio.cpp index def2cd6c62..8f33f22243 100644 --- a/engines/mads/audio.cpp +++ b/engines/mads/audio.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/audio.h b/engines/mads/audio.h index 13c540bf85..5c3cd5e682 100644 --- a/engines/mads/audio.h +++ b/engines/mads/audio.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/compression.cpp b/engines/mads/compression.cpp index 79cd1786de..1f6f1ee202 100644 --- a/engines/mads/compression.cpp +++ b/engines/mads/compression.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/compression.h b/engines/mads/compression.h index f7381e4af3..b560ed33c1 100644 --- a/engines/mads/compression.h +++ b/engines/mads/compression.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/debugger.cpp b/engines/mads/debugger.cpp index 99251f9fbb..a6a4d3edbc 100644 --- a/engines/mads/debugger.cpp +++ b/engines/mads/debugger.cpp @@ -8,12 +8,12 @@ * 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 + * 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. diff --git a/engines/mads/debugger.h b/engines/mads/debugger.h index c8fee5f5b2..70b2cadc65 100644 --- a/engines/mads/debugger.h +++ b/engines/mads/debugger.h @@ -8,12 +8,12 @@ * 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 + * 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. diff --git a/engines/mads/detection.cpp b/engines/mads/detection.cpp index ea71fc8539..57f4776e82 100644 --- a/engines/mads/detection.cpp +++ b/engines/mads/detection.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/detection_tables.h b/engines/mads/detection_tables.h index faf73996ac..56df09577c 100644 --- a/engines/mads/detection_tables.h +++ b/engines/mads/detection_tables.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/dialogs.cpp b/engines/mads/dialogs.cpp index 7f0b02bc65..d9b27ce926 100644 --- a/engines/mads/dialogs.cpp +++ b/engines/mads/dialogs.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/dialogs.h b/engines/mads/dialogs.h index 317c7bd792..efd2871d89 100644 --- a/engines/mads/dialogs.h +++ b/engines/mads/dialogs.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.cpp b/engines/mads/dragonsphere/dragonsphere_scenes.cpp index f32d17d9c9..ff01c32174 100644 --- a/engines/mads/dragonsphere/dragonsphere_scenes.cpp +++ b/engines/mads/dragonsphere/dragonsphere_scenes.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.h b/engines/mads/dragonsphere/dragonsphere_scenes.h index a6c778eca7..173cc667ce 100644 --- a/engines/mads/dragonsphere/dragonsphere_scenes.h +++ b/engines/mads/dragonsphere/dragonsphere_scenes.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/dragonsphere/game_dragonsphere.cpp b/engines/mads/dragonsphere/game_dragonsphere.cpp index 3836adb6d2..b07eab9daa 100644 --- a/engines/mads/dragonsphere/game_dragonsphere.cpp +++ b/engines/mads/dragonsphere/game_dragonsphere.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/dragonsphere/game_dragonsphere.h b/engines/mads/dragonsphere/game_dragonsphere.h index 7869dc87b4..b57f8833c6 100644 --- a/engines/mads/dragonsphere/game_dragonsphere.h +++ b/engines/mads/dragonsphere/game_dragonsphere.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/events.cpp b/engines/mads/events.cpp index 52569af375..7ba9098935 100644 --- a/engines/mads/events.cpp +++ b/engines/mads/events.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/events.h b/engines/mads/events.h index 1a92754f10..1a2579cae0 100644 --- a/engines/mads/events.h +++ b/engines/mads/events.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/font.cpp b/engines/mads/font.cpp index f7c1c52703..3e6d23fe6f 100644 --- a/engines/mads/font.cpp +++ b/engines/mads/font.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/font.h b/engines/mads/font.h index 47df647637..486cadcfff 100644 --- a/engines/mads/font.h +++ b/engines/mads/font.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/game.cpp b/engines/mads/game.cpp index 3d1c194612..91f6cd5630 100644 --- a/engines/mads/game.cpp +++ b/engines/mads/game.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/game.h b/engines/mads/game.h index d246aa501e..95b54b0d1a 100644 --- a/engines/mads/game.h +++ b/engines/mads/game.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/game_data.cpp b/engines/mads/game_data.cpp index 70e9e6c30b..6421d057e8 100644 --- a/engines/mads/game_data.cpp +++ b/engines/mads/game_data.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/game_data.h b/engines/mads/game_data.h index 65a9ae1553..e9bf45d8a5 100644 --- a/engines/mads/game_data.h +++ b/engines/mads/game_data.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/globals.cpp b/engines/mads/globals.cpp index 1d088992ea..e4a681d551 100644 --- a/engines/mads/globals.cpp +++ b/engines/mads/globals.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/globals.h b/engines/mads/globals.h index a6c9b628dd..27553a2b06 100644 --- a/engines/mads/globals.h +++ b/engines/mads/globals.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/hotspots.cpp b/engines/mads/hotspots.cpp index 2af421a112..bd28645504 100644 --- a/engines/mads/hotspots.cpp +++ b/engines/mads/hotspots.cpp @@ -8,12 +8,12 @@ * 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 + * 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. diff --git a/engines/mads/hotspots.h b/engines/mads/hotspots.h index f9334eace8..902275bb21 100644 --- a/engines/mads/hotspots.h +++ b/engines/mads/hotspots.h @@ -8,12 +8,12 @@ * 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 + * 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. diff --git a/engines/mads/inventory.cpp b/engines/mads/inventory.cpp index ca05575ec5..fe1d24baea 100644 --- a/engines/mads/inventory.cpp +++ b/engines/mads/inventory.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/inventory.h b/engines/mads/inventory.h index cf82de59f1..2897f950e4 100644 --- a/engines/mads/inventory.h +++ b/engines/mads/inventory.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp index 374e373035..8c7b6b1ce3 100644 --- a/engines/mads/mads.cpp +++ b/engines/mads/mads.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/mads.h b/engines/mads/mads.h index 1d641e7c87..901035320a 100644 --- a/engines/mads/mads.h +++ b/engines/mads/mads.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/menu_views.cpp b/engines/mads/menu_views.cpp index 319f5b0f87..cfc3b09461 100644 --- a/engines/mads/menu_views.cpp +++ b/engines/mads/menu_views.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/menu_views.h b/engines/mads/menu_views.h index f39ea4c3b5..6c8a2a8bdd 100644 --- a/engines/mads/menu_views.h +++ b/engines/mads/menu_views.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/messages.cpp b/engines/mads/messages.cpp index 304c79aa46..d88806150d 100644 --- a/engines/mads/messages.cpp +++ b/engines/mads/messages.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/messages.h b/engines/mads/messages.h index 22ae0b24b5..764477a7fc 100644 --- a/engines/mads/messages.h +++ b/engines/mads/messages.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp index 702b9e5f08..f768624278 100644 --- a/engines/mads/msurface.cpp +++ b/engines/mads/msurface.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h index 754e70bf7f..80891afb83 100644 --- a/engines/mads/msurface.h +++ b/engines/mads/msurface.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/dialogs_nebular.cpp b/engines/mads/nebular/dialogs_nebular.cpp index 5b9942db07..960a2cc2f4 100644 --- a/engines/mads/nebular/dialogs_nebular.cpp +++ b/engines/mads/nebular/dialogs_nebular.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/dialogs_nebular.h b/engines/mads/nebular/dialogs_nebular.h index 0f086f6ec1..4935ee4b8c 100644 --- a/engines/mads/nebular/dialogs_nebular.h +++ b/engines/mads/nebular/dialogs_nebular.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/game_nebular.cpp b/engines/mads/nebular/game_nebular.cpp index e9a3d0b716..e8e0a4f42c 100644 --- a/engines/mads/nebular/game_nebular.cpp +++ b/engines/mads/nebular/game_nebular.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/game_nebular.h b/engines/mads/nebular/game_nebular.h index 1b89d11412..3cf7aefc18 100644 --- a/engines/mads/nebular/game_nebular.h +++ b/engines/mads/nebular/game_nebular.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/globals_nebular.cpp b/engines/mads/nebular/globals_nebular.cpp index 9f8b8a7888..c44506e546 100644 --- a/engines/mads/nebular/globals_nebular.cpp +++ b/engines/mads/nebular/globals_nebular.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/globals_nebular.h b/engines/mads/nebular/globals_nebular.h index 8d0c26d96d..7c7069892e 100644 --- a/engines/mads/nebular/globals_nebular.h +++ b/engines/mads/nebular/globals_nebular.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/menu_nebular.cpp b/engines/mads/nebular/menu_nebular.cpp index 2fdef3443d..6fe17f3beb 100644 --- a/engines/mads/nebular/menu_nebular.cpp +++ b/engines/mads/nebular/menu_nebular.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/menu_nebular.h b/engines/mads/nebular/menu_nebular.h index 77b8b6fc6e..35af0bb34f 100644 --- a/engines/mads/nebular/menu_nebular.h +++ b/engines/mads/nebular/menu_nebular.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/nebular_scenes.cpp b/engines/mads/nebular/nebular_scenes.cpp index 14cf71d0fc..eb6f7a5610 100644 --- a/engines/mads/nebular/nebular_scenes.cpp +++ b/engines/mads/nebular/nebular_scenes.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/nebular_scenes.h b/engines/mads/nebular/nebular_scenes.h index db7738f13b..58a6d1c98f 100644 --- a/engines/mads/nebular/nebular_scenes.h +++ b/engines/mads/nebular/nebular_scenes.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/nebular_scenes1.cpp b/engines/mads/nebular/nebular_scenes1.cpp index c9eda08859..fd97f71727 100644 --- a/engines/mads/nebular/nebular_scenes1.cpp +++ b/engines/mads/nebular/nebular_scenes1.cpp @@ -8,12 +8,12 @@ * 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 + * 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. diff --git a/engines/mads/nebular/nebular_scenes1.h b/engines/mads/nebular/nebular_scenes1.h index 1afa7fccc1..d8c9059846 100644 --- a/engines/mads/nebular/nebular_scenes1.h +++ b/engines/mads/nebular/nebular_scenes1.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/nebular_scenes2.cpp b/engines/mads/nebular/nebular_scenes2.cpp index 84910c4de3..1cbd6f56ef 100644 --- a/engines/mads/nebular/nebular_scenes2.cpp +++ b/engines/mads/nebular/nebular_scenes2.cpp @@ -8,12 +8,12 @@ * 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 + * 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. diff --git a/engines/mads/nebular/nebular_scenes2.h b/engines/mads/nebular/nebular_scenes2.h index c860db9470..0ea4702eea 100644 --- a/engines/mads/nebular/nebular_scenes2.h +++ b/engines/mads/nebular/nebular_scenes2.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/nebular_scenes3.cpp b/engines/mads/nebular/nebular_scenes3.cpp index 4e7781e7a2..5a6edbf995 100644 --- a/engines/mads/nebular/nebular_scenes3.cpp +++ b/engines/mads/nebular/nebular_scenes3.cpp @@ -8,12 +8,12 @@ * 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 + * 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. diff --git a/engines/mads/nebular/nebular_scenes3.h b/engines/mads/nebular/nebular_scenes3.h index 9efd38e9a4..cf925b3867 100644 --- a/engines/mads/nebular/nebular_scenes3.h +++ b/engines/mads/nebular/nebular_scenes3.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/nebular_scenes4.cpp b/engines/mads/nebular/nebular_scenes4.cpp index 29b17c42c0..c981f6a6e4 100644 --- a/engines/mads/nebular/nebular_scenes4.cpp +++ b/engines/mads/nebular/nebular_scenes4.cpp @@ -8,12 +8,12 @@ * 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 + * 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. diff --git a/engines/mads/nebular/nebular_scenes4.h b/engines/mads/nebular/nebular_scenes4.h index fbd5ce81f0..de11bd4129 100644 --- a/engines/mads/nebular/nebular_scenes4.h +++ b/engines/mads/nebular/nebular_scenes4.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/nebular_scenes5.cpp b/engines/mads/nebular/nebular_scenes5.cpp index 2470137b2e..95eb429193 100644 --- a/engines/mads/nebular/nebular_scenes5.cpp +++ b/engines/mads/nebular/nebular_scenes5.cpp @@ -8,12 +8,12 @@ * 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 + * 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. diff --git a/engines/mads/nebular/nebular_scenes5.h b/engines/mads/nebular/nebular_scenes5.h index 2face26508..f314ae8513 100644 --- a/engines/mads/nebular/nebular_scenes5.h +++ b/engines/mads/nebular/nebular_scenes5.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/nebular_scenes6.cpp b/engines/mads/nebular/nebular_scenes6.cpp index d94fb17fd4..d97e37ea0b 100644 --- a/engines/mads/nebular/nebular_scenes6.cpp +++ b/engines/mads/nebular/nebular_scenes6.cpp @@ -8,12 +8,12 @@ * 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 + * 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. diff --git a/engines/mads/nebular/nebular_scenes6.h b/engines/mads/nebular/nebular_scenes6.h index c5cac56626..4fc4a2e8ae 100644 --- a/engines/mads/nebular/nebular_scenes6.h +++ b/engines/mads/nebular/nebular_scenes6.h @@ -8,12 +8,12 @@ * 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 + * 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. diff --git a/engines/mads/nebular/nebular_scenes7.cpp b/engines/mads/nebular/nebular_scenes7.cpp index b40a8054f7..c2a249e5f8 100644 --- a/engines/mads/nebular/nebular_scenes7.cpp +++ b/engines/mads/nebular/nebular_scenes7.cpp @@ -8,12 +8,12 @@ * 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 + * 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. diff --git a/engines/mads/nebular/nebular_scenes7.h b/engines/mads/nebular/nebular_scenes7.h index dfb3c0f16e..b5aeba818c 100644 --- a/engines/mads/nebular/nebular_scenes7.h +++ b/engines/mads/nebular/nebular_scenes7.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/nebular_scenes8.cpp b/engines/mads/nebular/nebular_scenes8.cpp index 5f8417cee1..a904569624 100644 --- a/engines/mads/nebular/nebular_scenes8.cpp +++ b/engines/mads/nebular/nebular_scenes8.cpp @@ -8,12 +8,12 @@ * 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 + * 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. diff --git a/engines/mads/nebular/nebular_scenes8.h b/engines/mads/nebular/nebular_scenes8.h index 7f2c34a843..439815f05c 100644 --- a/engines/mads/nebular/nebular_scenes8.h +++ b/engines/mads/nebular/nebular_scenes8.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/sound_nebular.cpp b/engines/mads/nebular/sound_nebular.cpp index 9716e6d522..240c18f6dc 100644 --- a/engines/mads/nebular/sound_nebular.cpp +++ b/engines/mads/nebular/sound_nebular.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/nebular/sound_nebular.h b/engines/mads/nebular/sound_nebular.h index d2fc552eec..9bc1a49458 100644 --- a/engines/mads/nebular/sound_nebular.h +++ b/engines/mads/nebular/sound_nebular.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/palette.cpp b/engines/mads/palette.cpp index b5ea136abd..36c9e5694f 100644 --- a/engines/mads/palette.cpp +++ b/engines/mads/palette.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/palette.h b/engines/mads/palette.h index 5d3bc3a82e..6c98947384 100644 --- a/engines/mads/palette.h +++ b/engines/mads/palette.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/phantom/game_phantom.cpp b/engines/mads/phantom/game_phantom.cpp index 0b2531ef65..cbeb6b0d26 100644 --- a/engines/mads/phantom/game_phantom.cpp +++ b/engines/mads/phantom/game_phantom.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/phantom/game_phantom.h b/engines/mads/phantom/game_phantom.h index 99cc2c1230..5504054bcf 100644 --- a/engines/mads/phantom/game_phantom.h +++ b/engines/mads/phantom/game_phantom.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/phantom/phantom_scenes.cpp b/engines/mads/phantom/phantom_scenes.cpp index 7fd7ce642d..c2cec47bd9 100644 --- a/engines/mads/phantom/phantom_scenes.cpp +++ b/engines/mads/phantom/phantom_scenes.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/phantom/phantom_scenes.h b/engines/mads/phantom/phantom_scenes.h index cd295a28b6..0e22610086 100644 --- a/engines/mads/phantom/phantom_scenes.h +++ b/engines/mads/phantom/phantom_scenes.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/player.cpp b/engines/mads/player.cpp index f61a5a1592..bb747f4b52 100644 --- a/engines/mads/player.cpp +++ b/engines/mads/player.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/player.h b/engines/mads/player.h index 671ac9d16e..e5765a9bca 100644 --- a/engines/mads/player.h +++ b/engines/mads/player.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/rails.cpp b/engines/mads/rails.cpp index 322e6e7cb3..9b2ec71de6 100644 --- a/engines/mads/rails.cpp +++ b/engines/mads/rails.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/rails.h b/engines/mads/rails.h index e6cab08f85..c95f5c47a6 100644 --- a/engines/mads/rails.h +++ b/engines/mads/rails.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/resources.cpp b/engines/mads/resources.cpp index 1fb75e6ba2..d5352fb205 100644 --- a/engines/mads/resources.cpp +++ b/engines/mads/resources.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/resources.h b/engines/mads/resources.h index 8d9ab1e39f..95ea17d3c4 100644 --- a/engines/mads/resources.h +++ b/engines/mads/resources.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp index 463d4a62fd..5662d8349a 100644 --- a/engines/mads/scene.cpp +++ b/engines/mads/scene.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/scene.h b/engines/mads/scene.h index 5927f4e70f..c0784c3812 100644 --- a/engines/mads/scene.h +++ b/engines/mads/scene.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/screen.cpp b/engines/mads/screen.cpp index 3e2fe22611..3c27001ae0 100644 --- a/engines/mads/screen.cpp +++ b/engines/mads/screen.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/screen.h b/engines/mads/screen.h index 85c55419ca..d910e88633 100644 --- a/engines/mads/screen.h +++ b/engines/mads/screen.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/sequence.cpp b/engines/mads/sequence.cpp index ba0111a844..e5bf1631c2 100644 --- a/engines/mads/sequence.cpp +++ b/engines/mads/sequence.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/sequence.h b/engines/mads/sequence.h index 8b236af15e..c3a277c5a5 100644 --- a/engines/mads/sequence.h +++ b/engines/mads/sequence.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/sound.cpp b/engines/mads/sound.cpp index 4036ee8112..7b9388eee3 100644 --- a/engines/mads/sound.cpp +++ b/engines/mads/sound.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/sound.h b/engines/mads/sound.h index 5884323474..16128f8284 100644 --- a/engines/mads/sound.h +++ b/engines/mads/sound.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/sprites.cpp b/engines/mads/sprites.cpp index f15d6456d3..0a1c0b710d 100644 --- a/engines/mads/sprites.cpp +++ b/engines/mads/sprites.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/sprites.h b/engines/mads/sprites.h index bb5fdbe964..3db922c40b 100644 --- a/engines/mads/sprites.h +++ b/engines/mads/sprites.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/staticres.cpp b/engines/mads/staticres.cpp index 189e5f72e7..b659d9a27c 100644 --- a/engines/mads/staticres.cpp +++ b/engines/mads/staticres.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/staticres.h b/engines/mads/staticres.h index 560fd12e67..b805729327 100644 --- a/engines/mads/staticres.h +++ b/engines/mads/staticres.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/user_interface.cpp b/engines/mads/user_interface.cpp index 1e5a1d80d2..62fd036c03 100644 --- a/engines/mads/user_interface.cpp +++ b/engines/mads/user_interface.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/mads/user_interface.h b/engines/mads/user_interface.h index 71c6f64c2a..1366aa2c32 100644 --- a/engines/mads/user_interface.h +++ b/engines/mads/user_interface.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/queen/walk.cpp b/engines/queen/walk.cpp index dd7e46c765..17d12b0b9f 100644 --- a/engines/queen/walk.cpp +++ b/engines/queen/walk.cpp @@ -130,7 +130,7 @@ void Walk::animateJoe() { _vm->logic()->joeScale(pbs->scale); pbs->scaleWalkSpeed(6); _vm->update(true); - if (_vm->input()->cutawayQuit() || _vm->logic()->joeWalk() == JWM_EXECUTE) { + if (_vm->input()->cutawayQuit() || _vm->logic()->joeWalk() == JWM_EXECUTE || _vm->shouldQuit()) { stopJoe(); break; } @@ -249,7 +249,7 @@ void Walk::animatePerson(const MovePersonData *mpd, uint16 image, uint16 bobNum, _vm->update(); pbs->scale = pwd->area->calcScale(pbs->y); pbs->scaleWalkSpeed(mpd->moveSpeed); - if (_vm->input()->cutawayQuit()) { + if (_vm->input()->cutawayQuit() || _vm->shouldQuit()) { stopPerson(bobNum); break; } diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp index f19645dd99..4fa15d09e5 100644 --- a/engines/saga/scene.cpp +++ b/engines/saga/scene.cpp @@ -835,13 +835,14 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) { loadSceneParams.sceneProc(SCENE_BEGIN, this); } - // We probably don't want "followers" to go into scene -1 , 0. At the very - // least we don't want garbage to be drawn that early in the ITE intro. - if (_sceneNumber > 0 && _sceneNumber != ITE_SCENE_PUZZLE) - _vm->_actor->updateActorsScene(loadSceneParams.actorsEntrance); - - if (_sceneNumber == ITE_SCENE_PUZZLE) + if (_vm->getGameId() == GID_ITE && _sceneNumber == ITE_SCENE_PUZZLE) { _vm->_puzzle->execute(); + } else { + // We probably don't want "followers" to go into scene -1 , 0. At the very + // least we don't want garbage to be drawn that early in the ITE intro. + if (_sceneNumber > 0) + _vm->_actor->updateActorsScene(loadSceneParams.actorsEntrance); + } if (getFlags() & kSceneFlagShowCursor) { // Activate user interface diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index bc9ad362ab..1e95393e4d 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -209,8 +209,11 @@ Console::Console(SciEngine *engine) : GUI::Debugger(), registerCmd("bpe", WRAP_METHOD(Console, cmdBreakpointFunction)); // alias // VM registerCmd("script_steps", WRAP_METHOD(Console, cmdScriptSteps)); + registerCmd("script_objects", WRAP_METHOD(Console, cmdScriptObjects)); + registerCmd("scro", WRAP_METHOD(Console, cmdScriptObjects)); registerCmd("script_strings", WRAP_METHOD(Console, cmdScriptStrings)); registerCmd("scrs", WRAP_METHOD(Console, cmdScriptStrings)); + registerCmd("script_said", WRAP_METHOD(Console, cmdScriptSaid)); registerCmd("vm_varlist", WRAP_METHOD(Console, cmdVMVarlist)); registerCmd("vmvarlist", WRAP_METHOD(Console, cmdVMVarlist)); // alias registerCmd("vl", WRAP_METHOD(Console, cmdVMVarlist)); // alias @@ -2830,28 +2833,86 @@ bool Console::cmdScriptSteps(int argc, const char **argv) { return true; } -bool Console::cmdScriptStrings(int argc, const char **argv) { - SegManager *segMan = _engine->_gamestate->_segMan; +bool Console::cmdScriptObjects(int argc, const char **argv) { int curScriptNr = -1; - SegmentId curSegmentNr; - Common::List<SegmentId> segmentNrList; - SegmentType curSegmentType = SEG_TYPE_INVALID; - SegmentObj *curSegmentObj = NULL; - Script *curScriptObj = NULL; + if (argc < 2) { + debugPrintf("Shows all objects inside a specified script.\n"); + debugPrintf("Usage: %s <script number>\n", argv[0]); + debugPrintf("Example: %s 999\n", argv[0]); + debugPrintf("<script number> may be * to show objects inside all loaded scripts\n"); + return true; + } + + if (strcmp(argv[1], "*") == 0) { + // get said-strings of all currently loaded scripts + curScriptNr = -1; + } else { + curScriptNr = atoi(argv[1]); + } + + printOffsets(curScriptNr, SCI_SCR_OFFSET_TYPE_OBJECT); + return true; +} + +bool Console::cmdScriptStrings(int argc, const char **argv) { + int curScriptNr = -1; if (argc < 2) { - debugPrintf("Shows the strings inside a specified script.\n"); + debugPrintf("Shows all strings inside a specified script.\n"); debugPrintf("Usage: %s <script number>\n", argv[0]); debugPrintf("Example: %s 999\n", argv[0]); debugPrintf("<script number> may be * to show strings inside all loaded scripts\n"); return true; } - segmentNrList.clear(); - if (strcmp(argv[1], "*") == 0) { // get strings of all currently loaded scripts + curScriptNr = -1; + } else { + curScriptNr = atoi(argv[1]); + } + + printOffsets(curScriptNr, SCI_SCR_OFFSET_TYPE_STRING); + return true; +} + +bool Console::cmdScriptSaid(int argc, const char **argv) { + int curScriptNr = -1; + + if (argc < 2) { + debugPrintf("Shows all said-strings inside a specified script.\n"); + debugPrintf("Usage: %s <script number>\n", argv[0]); + debugPrintf("Example: %s 999\n", argv[0]); + debugPrintf("<script number> may be * to show said-strings inside all loaded scripts\n"); + return true; + } + + if (strcmp(argv[1], "*") == 0) { + // get said-strings of all currently loaded scripts + curScriptNr = -1; + } else { + curScriptNr = atoi(argv[1]); + } + + printOffsets(curScriptNr, SCI_SCR_OFFSET_TYPE_SAID); + return true; +} + +void Console::printOffsets(int scriptNr, uint16 showType) { + SegManager *segMan = _engine->_gamestate->_segMan; + Vocabulary *vocab = _engine->_vocabulary; + SegmentId curSegmentNr; + Common::List<SegmentId> segmentNrList; + + SegmentType curSegmentType = SEG_TYPE_INVALID; + SegmentObj *curSegmentObj = NULL; + Script *curScriptObj = NULL; + const byte *curScriptData = NULL; + + segmentNrList.clear(); + if (scriptNr < 0) { + // get offsets of all currently loaded scripts for (curSegmentNr = 0; curSegmentNr < segMan->_heap.size(); curSegmentNr++) { curSegmentObj = segMan->_heap[curSegmentNr]; if (curSegmentObj && curSegmentObj->getType() == SEG_TYPE_SCRIPT) { @@ -2860,15 +2921,23 @@ bool Console::cmdScriptStrings(int argc, const char **argv) { } } else { - curScriptNr = atoi(argv[1]); - curSegmentNr = segMan->getScriptSegment(curScriptNr); + curSegmentNr = segMan->getScriptSegment(scriptNr); if (!curSegmentNr) { - debugPrintf("Script %d is currently not loaded/available\n", curScriptNr); - return true; + debugPrintf("Script %d is currently not loaded/available\n", scriptNr); + return; } segmentNrList.push_back(curSegmentNr); } + const offsetLookupArrayType *scriptOffsetLookupArray; + offsetLookupArrayType::const_iterator arrayIterator; + int showTypeCount = 0; + + reg_t objectPos; + const char *objectNamePtr = NULL; + const byte *stringPtr = NULL; + const byte *saidPtr = NULL; + Common::List<SegmentId>::iterator it; const Common::List<SegmentId>::iterator end = segmentNrList.end(); @@ -2884,15 +2953,64 @@ bool Console::cmdScriptStrings(int argc, const char **argv) { continue; curScriptObj = (Script *)curSegmentObj; - debugPrintf("=== SCRIPT %d from Segment %d ===\n", curScriptObj->getScriptNumber(), curSegmentNr); - debugN("=== SCRIPT %d from Segment %d ===\n", curScriptObj->getScriptNumber(), curSegmentNr); + debugPrintf("=== SCRIPT %d inside Segment %d ===\n", curScriptObj->getScriptNumber(), curSegmentNr); + debugN("=== SCRIPT %d inside Segment %d ===\n", curScriptObj->getScriptNumber(), curSegmentNr); + + // now print the list + scriptOffsetLookupArray = curScriptObj->getOffsetArray(); + curScriptData = curScriptObj->getBuf(); + showTypeCount = 0; + + for (arrayIterator = scriptOffsetLookupArray->begin(); arrayIterator != scriptOffsetLookupArray->end(); arrayIterator++) { + if (arrayIterator->type == showType) { + switch (showType) { + case SCI_SCR_OFFSET_TYPE_OBJECT: + objectPos = make_reg(curSegmentNr, arrayIterator->offset); + objectNamePtr = segMan->getObjectName(objectPos); + debugPrintf(" %03d:%04x: %s\n", arrayIterator->id, arrayIterator->offset, objectNamePtr); + debugN(" %03d:%04x: %s\n", arrayIterator->id, arrayIterator->offset, objectNamePtr); + break; + case SCI_SCR_OFFSET_TYPE_STRING: + stringPtr = curScriptData + arrayIterator->offset; + debugPrintf(" %03d:%04x: '%s' (size %d)\n", arrayIterator->id, arrayIterator->offset, stringPtr, arrayIterator->stringSize); + debugN(" %03d:%04x: '%s' (size %d)\n", arrayIterator->id, arrayIterator->offset, stringPtr, arrayIterator->stringSize); + break; + case SCI_SCR_OFFSET_TYPE_SAID: + saidPtr = curScriptData + arrayIterator->offset; + debugPrintf(" %03d:%04x:\n", arrayIterator->id, arrayIterator->offset); + debugN(" %03d:%04x: ", arrayIterator->id, arrayIterator->offset); + vocab->debugDecipherSaidBlock(saidPtr); + debugN("\n"); + break; + default: + break; + } + showTypeCount++; + } + } + + if (showTypeCount == 0) { + switch (showType) { + case SCI_SCR_OFFSET_TYPE_OBJECT: + debugPrintf(" no objects\n"); + debugN(" no objects\n"); + break; + case SCI_SCR_OFFSET_TYPE_STRING: + debugPrintf(" no strings\n"); + debugN(" no strings\n"); + break; + case SCI_SCR_OFFSET_TYPE_SAID: + debugPrintf(" no said-strings\n"); + debugN(" no said-strings\n"); + break; + default: + break; + } + } - // now print the string list - curScriptObj->debugPrintStrings(this); debugPrintf("\n"); debugN("\n"); } - return true; } bool Console::cmdBacktrace(int argc, const char **argv) { @@ -3374,6 +3492,7 @@ bool Console::cmdSend(int argc, const char **argv) { // We call run_engine explictly so we can restore the value of r_acc // after execution. run_vm(_engine->_gamestate); + _engine->_gamestate->xs = old_xstack; } diff --git a/engines/sci/console.h b/engines/sci/console.h index 00d95b511f..8b10912fbe 100644 --- a/engines/sci/console.h +++ b/engines/sci/console.h @@ -147,7 +147,9 @@ private: bool cmdBreakpointFunction(int argc, const char **argv); // VM bool cmdScriptSteps(int argc, const char **argv); + bool cmdScriptObjects(int argc, const char **argv); bool cmdScriptStrings(int argc, const char **argv); + bool cmdScriptSaid(int argc, const char **argv); bool cmdVMVarlist(int argc, const char **argv); bool cmdVMVars(int argc, const char **argv); bool cmdStack(int argc, const char **argv); @@ -167,6 +169,7 @@ private: void printList(List *list); int printNode(reg_t addr); void hexDumpReg(const reg_t *data, int len, int regsPerLine = 4, int startOffset = 0, bool isArray = false); + void printOffsets(int scriptNr, uint16 showType); private: /** diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index 312069025b..7cadcfc27e 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -904,16 +904,14 @@ 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) }, -#if 0 // TODO: unknown if these files are corrupt - // Hoyle 1 - English Amiga (from www.back2roots.org) - // SCI interpreter version 0.000.519 - FIXME: some have 0.000.530, others x.yyy.zzz + // Hoyle 1 - English Amiga (from www.back2roots.org - verified by waltervn in bug report #6870) + // Game version 1.000.139, SCI interpreter version x.yyy.zzz {"hoyle1", "", { {"resource.map", 0, "2a72b1aba65fa6e339370eb86d8601d1", 5166}, {"resource.001", 0, "e0dd44069a62a463fd124974b915f10d", 218755}, {"resource.002", 0, "e0dd44069a62a463fd124974b915f10d", 439502}, AD_LISTEND}, Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, -#endif // Hoyle 2 - English DOS // SCI interpreter version 0.000.572 diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 69f52495e0..6034378ef6 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -65,7 +65,11 @@ void Script::freeScript() { _lockers = 1; _markedAsDeleted = false; _objects.clear(); - _stringLookupList.clear(); + + _offsetLookupArray.clear(); + _offsetLookupObjectCount = 0; + _offsetLookupStringCount = 0; + _offsetLookupSaidCount = 0; } void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptPatcher) { @@ -208,39 +212,45 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP } // find all strings of this script - identifyStrings(); + identifyOffsets(); } -void Script::identifyStrings() { - stringLookupListEntry listEntry; - byte *scriptDataPtr = NULL; - byte *stringStartPtr = NULL; - byte *stringDataPtr = NULL; - int scriptDataLeft = 0; - int stringDataLeft = 0; +void Script::identifyOffsets() { + offsetLookupArrayEntry arrayEntry; + const byte *scriptDataPtr = NULL; + const byte *stringStartPtr = NULL; + const byte *stringDataPtr = NULL; + uint32 scriptDataLeft = 0; + uint32 stringDataLeft = 0; byte stringDataByte = 0; + uint16 typeObject_id = 0; + uint16 typeString_id = 0; + uint16 typeSaid_id = 0; + + uint16 blockType = 0; + uint16 blockSize = 0; - _stringLookupList.clear(); - //stringLookupListType _stringLookupList; // Table of string data, that is inside the currently loaded script + _offsetLookupArray.clear(); + _offsetLookupObjectCount = 0; + _offsetLookupStringCount = 0; + _offsetLookupSaidCount = 0; if (getSciVersion() < SCI_VERSION_1_1) { + // SCI0 + SCI1 scriptDataPtr = _buf; scriptDataLeft = _bufSize; - // Go through all SCI_OBJ_STRINGS blocks + // Go through all blocks if (getSciVersion() == SCI_VERSION_0_EARLY) { if (scriptDataLeft < 2) - error("Script::identifyStrings(): unexpected end of script"); + error("Script::identifyOffsets(): unexpected end of script %d", _nr); scriptDataPtr += 2; scriptDataLeft -= 2; } - - uint16 blockType; - uint16 blockSize; do { if (scriptDataLeft < 2) - error("Script::identifyStrings(): unexpected end of script"); + error("Script::identifyOffsets(): unexpected end of script %d", _nr); blockType = READ_LE_UINT16(scriptDataPtr); scriptDataPtr += 2; @@ -249,29 +259,50 @@ void Script::identifyStrings() { break; if (scriptDataLeft < 2) - error("Script::identifyStrings(): unexpected end of script"); + error("Script::identifyOffsets(): unexpected end of script %d", _nr); blockSize = READ_LE_UINT16(scriptDataPtr); if (blockSize < 4) - error("Script::identifyStrings(): invalid block size"); + error("Script::identifyOffsets(): invalid block size in script %d", _nr); blockSize -= 4; // block size includes block-type UINT16 and block-size UINT16 scriptDataPtr += 2; scriptDataLeft -= 2; if (scriptDataLeft < blockSize) - error("Script::identifyStrings(): invalid block size"); - - if (blockType == SCI_OBJ_STRINGS) { + error("Script::identifyOffsets(): invalid block size in script %d", _nr); + + switch (blockType) { + case SCI_OBJ_OBJECT: + case SCI_OBJ_CLASS: + typeObject_id++; + arrayEntry.type = SCI_SCR_OFFSET_TYPE_OBJECT; + arrayEntry.id = typeObject_id; + arrayEntry.offset = scriptDataPtr - _buf + 8; // Calculate offset inside script data (VM uses +8) + arrayEntry.stringSize = 0; + _offsetLookupArray.push_back(arrayEntry); + _offsetLookupObjectCount++; + break; + + case SCI_OBJ_STRINGS: // string block detected, we now grab all NUL terminated strings out of this block stringDataPtr = scriptDataPtr; stringDataLeft = blockSize; + arrayEntry.type = SCI_SCR_OFFSET_TYPE_STRING; + do { if (stringDataLeft < 1) // no more bytes left break; stringStartPtr = stringDataPtr; - listEntry.ptrOffset = stringStartPtr - _buf; // Calculate offset inside script data + + if (stringDataLeft == 1) { + // only 1 byte left and that byte is a [00], in that case we also exit + stringDataByte = *stringStartPtr; + if (stringDataByte == 0x00) + break; + } + // now look for terminating [NUL] do { stringDataByte = *stringDataPtr; @@ -279,13 +310,77 @@ void Script::identifyStrings() { stringDataLeft--; if (!stringDataByte) // NUL found, exit this loop break; + if (stringDataLeft < 1) { + // no more bytes left + warning("Script::identifyOffsets(): string without terminating NUL in script %d", _nr); + break; + } + } while (1); + + if (stringDataByte) + break; + + typeString_id++; + arrayEntry.id = typeString_id; + arrayEntry.offset = stringStartPtr - _buf; // Calculate offset inside script data + arrayEntry.stringSize = stringDataPtr - stringStartPtr; + _offsetLookupArray.push_back(arrayEntry); + _offsetLookupStringCount++; + } while (1); + break; + + case SCI_OBJ_SAID: + // said block detected, we now try to find every single said "string" inside this block + // said strings are terminated with a 0xFF, the string itself may contain words (2 bytes), where + // the second byte of a word may also be a 0xFF. + stringDataPtr = scriptDataPtr; + stringDataLeft = blockSize; + + arrayEntry.type = SCI_SCR_OFFSET_TYPE_SAID; + + do { + if (stringDataLeft < 1) // no more bytes left + break; + + stringStartPtr = stringDataPtr; + if (stringDataLeft == 1) { + // only 1 byte left and that byte is a [00], in that case we also exit + // happens in some scripts, for example Conquests of Camelot, script 997 + // may have been a bug in the compiler or just an intentional filler byte + stringDataByte = *stringStartPtr; + if (stringDataByte == 0x00) + break; + } + + // now look for terminating 0xFF + do { + stringDataByte = *stringDataPtr; + stringDataPtr++; + stringDataLeft--; + if (stringDataByte == 0xFF) // Terminator found, exit this loop + break; if (stringDataLeft < 1) // no more bytes left - error("Script::identifyStrings(): string without terminating NUL"); + error("Script::identifyOffsets(): said-string without terminator in script %d", _nr); + if (stringDataByte < 0xF0) { + // Part of a word, skip second byte + stringDataPtr++; + stringDataLeft--; + if (stringDataLeft < 1) // no more bytes left + error("Script::identifyOffsets(): said-string without terminator in script %d", _nr); + } } while (1); - listEntry.stringSize = stringDataPtr - stringStartPtr; - _stringLookupList.push_back(listEntry); + typeSaid_id++; + arrayEntry.id = typeSaid_id; + arrayEntry.offset = stringStartPtr - _buf; // Calculate offset inside script data + arrayEntry.stringSize = 0; + _offsetLookupArray.push_back(arrayEntry); + _offsetLookupSaidCount++; } while (1); + break; + + default: + break; } scriptDataPtr += blockSize; @@ -293,33 +388,30 @@ void Script::identifyStrings() { } while (1); } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { - // Strings in SCI1.1 come after the object instances + // Strings in SCI1.1 up to SCI2 come after the object instances scriptDataPtr = _heapStart; scriptDataLeft = _heapSize; if (scriptDataLeft < 4) - error("Script::identifyStrings(): unexpected end of script"); + error("Script::identifyOffsets(): unexpected end of script in script %d", _nr); uint16 endOfStringOffset = READ_SCI11ENDIAN_UINT16(scriptDataPtr); uint16 objectStartOffset = READ_SCI11ENDIAN_UINT16(scriptDataPtr + 2) * 2 + 4; if (scriptDataLeft < objectStartOffset) - error("Script::identifyStrings(): object start is beyond heap size"); + error("Script::identifyOffsets(): object start is beyond heap size in script %d", _nr); if (scriptDataLeft < endOfStringOffset) - error("Script::identifyStrings(): end of string is beyond heap size"); + error("Script::identifyOffsets(): end of string is beyond heap size in script %d", _nr); - byte *endOfStringPtr = scriptDataPtr + endOfStringOffset; + const byte *endOfStringPtr = scriptDataPtr + endOfStringOffset; scriptDataPtr += objectStartOffset; scriptDataLeft -= objectStartOffset; - uint16 blockType; - uint16 blockSize; - - // skip all objects + // go through all objects do { if (scriptDataLeft < 2) - error("Script::identifyStrings(): unexpected end of script"); + error("Script::identifyOffsets(): unexpected end of script %d", _nr); blockType = READ_SCI11ENDIAN_UINT16(scriptDataPtr); scriptDataPtr += 2; @@ -327,15 +419,26 @@ void Script::identifyStrings() { if (blockType != SCRIPT_OBJECT_MAGIC_NUMBER) break; + // Object found, add offset of object + typeObject_id++; + arrayEntry.type = SCI_SCR_OFFSET_TYPE_OBJECT; + arrayEntry.id = typeObject_id; + arrayEntry.offset = scriptDataPtr - _buf - 2; // the VM uses a pointer to the Magic-Number + arrayEntry.stringSize = 0; + _offsetLookupArray.push_back(arrayEntry); + _offsetLookupObjectCount++; + if (scriptDataLeft < 2) - error("Script::identifyStrings(): unexpected end of script"); + error("Script::identifyOffsets(): unexpected end of script in script %d", _nr); blockSize = READ_SCI11ENDIAN_UINT16(scriptDataPtr) * 2; + if (blockSize < 4) + error("Script::identifyOffsets(): invalid block size in script %d", _nr); scriptDataPtr += 2; scriptDataLeft -= 2; blockSize -= 4; // blocksize contains UINT16 type and UINT16 size if (scriptDataLeft < blockSize) - error("Script::identifyStrings(): invalid block size"); + error("Script::identifyOffsets(): invalid block size in script %d", _nr); scriptDataPtr += blockSize; scriptDataLeft -= blockSize; @@ -343,17 +446,17 @@ void Script::identifyStrings() { // now scriptDataPtr points to right at the start of the strings if (scriptDataPtr > endOfStringPtr) - error("Script::identifyStrings(): string block / end-of-string block mismatch"); + error("Script::identifyOffsets(): string block / end-of-string block mismatch in script %d", _nr); stringDataPtr = scriptDataPtr; stringDataLeft = endOfStringPtr - scriptDataPtr; // Calculate byte count within string-block + arrayEntry.type = SCI_SCR_OFFSET_TYPE_STRING; do { if (stringDataLeft < 1) // no more bytes left break; stringStartPtr = stringDataPtr; - listEntry.ptrOffset = stringStartPtr - _buf; // Calculate offset inside script data // now look for terminating [NUL] do { stringDataByte = *stringDataPtr; @@ -361,35 +464,142 @@ void Script::identifyStrings() { stringDataLeft--; if (!stringDataByte) // NUL found, exit this loop break; - if (stringDataLeft < 1) // no more bytes left - error("Script::identifyStrings(): string without terminating NUL"); + if (stringDataLeft < 1) { + // no more bytes left + warning("Script::identifyOffsets(): string without terminating NUL in script %d", _nr); + break; + } } while (1); - listEntry.stringSize = stringDataPtr - stringStartPtr; - _stringLookupList.push_back(listEntry); + if (stringDataByte) + break; + + typeString_id++; + arrayEntry.id = typeString_id; + arrayEntry.offset = stringStartPtr - _buf; // Calculate offset inside script data + arrayEntry.stringSize = stringDataPtr - stringStartPtr; + _offsetLookupArray.push_back(arrayEntry); + _offsetLookupStringCount++; } while (1); } else if (getSciVersion() == SCI_VERSION_3) { - warning("TODO: identifyStrings(): Implement SCI3 variant"); - return; - } -} + // SCI3 + uint32 sci3StringOffset = 0; + uint32 sci3RelocationOffset = 0; + uint32 sci3BoundaryOffset = 0; -void Script::debugPrintStrings(Console *con) { - stringLookupListType::iterator it; - const stringLookupListType::iterator end = _stringLookupList.end(); - byte *stringPtr; + if (_bufSize < 22) + error("Script::identifyOffsets(): script %d smaller than expected SCI3-header", _nr); - if (!_stringLookupList.size()) { - con->debugPrintf(" no strings\n"); - debugN(" no strings\n"); - return; - } + sci3StringOffset = READ_LE_UINT32(_buf + 4); + sci3RelocationOffset = READ_LE_UINT32(_buf + 8); + + if (sci3RelocationOffset > _bufSize) + error("Script::identifyOffsets(): relocation offset is beyond end of script %d", _nr); + + // First we get all the objects + scriptDataPtr = getSci3ObjectsPointer(); + scriptDataLeft = _bufSize - (scriptDataPtr - _buf); + do { + if (scriptDataLeft < 2) + error("Script::identifyOffsets(): unexpected end of script %d", _nr); + + blockType = READ_SCI11ENDIAN_UINT16(scriptDataPtr); + scriptDataPtr += 2; + scriptDataLeft -= 2; + if (blockType != SCRIPT_OBJECT_MAGIC_NUMBER) + break; + + // Object found, add offset of object + typeObject_id++; + arrayEntry.type = SCI_SCR_OFFSET_TYPE_OBJECT; + arrayEntry.id = typeObject_id; + arrayEntry.offset = scriptDataPtr - _buf - 2; // the VM uses a pointer to the Magic-Number + arrayEntry.stringSize = 0; + _offsetLookupArray.push_back(arrayEntry); + _offsetLookupObjectCount++; + + if (scriptDataLeft < 2) + error("Script::identifyOffsets(): unexpected end of script in script %d", _nr); - for (it = _stringLookupList.begin(); it != end; ++it) { - stringPtr = _buf + it->ptrOffset; - con->debugPrintf(" %04x: '%s' (size %d)\n", it->ptrOffset, stringPtr, it->stringSize); - debugN(" %04x: '%s' (size %d)\n", it->ptrOffset, stringPtr, it->stringSize); + blockSize = READ_SCI11ENDIAN_UINT16(scriptDataPtr); + if (blockSize < 4) + error("Script::identifyOffsets(): invalid block size in script %d", _nr); + scriptDataPtr += 2; + scriptDataLeft -= 2; + blockSize -= 4; // blocksize contains UINT16 type and UINT16 size + if (scriptDataLeft < blockSize) + error("Script::identifyOffsets(): invalid block size in script %d", _nr); + + scriptDataPtr += blockSize; + scriptDataLeft -= blockSize; + } while (1); + + // And now we get all the strings + if (sci3StringOffset > 0) { + // string offset set, we expect strings + if (sci3StringOffset > _bufSize) + error("Script::identifyOffsets(): string offset is beyond end of script %d", _nr); + + if (sci3RelocationOffset < sci3StringOffset) + error("Script::identifyOffsets(): string offset points beyond relocation offset in script %d", _nr); + + stringDataPtr = _buf + sci3StringOffset; + stringDataLeft = sci3RelocationOffset - sci3StringOffset; + + arrayEntry.type = SCI_SCR_OFFSET_TYPE_STRING; + + do { + if (stringDataLeft < 1) // no more bytes left + break; + + stringStartPtr = stringDataPtr; + + if (stringDataLeft == 1) { + // only 1 byte left and that byte is a [00], in that case we also exit + stringDataByte = *stringStartPtr; + if (stringDataByte == 0x00) + break; + } + + // now look for terminating [NUL] + do { + stringDataByte = *stringDataPtr; + stringDataPtr++; + stringDataLeft--; + if (!stringDataByte) // NUL found, exit this loop + break; + if (stringDataLeft < 1) { + // no more bytes left + warning("Script::identifyOffsets(): string without terminating NUL in script %d", _nr); + break; + } + } while (1); + + if (stringDataByte) + break; + + typeString_id++; + arrayEntry.id = typeString_id; + arrayEntry.offset = stringStartPtr - _buf; // Calculate offset inside script data + arrayEntry.stringSize = stringDataPtr - stringStartPtr; + _offsetLookupArray.push_back(arrayEntry); + _offsetLookupStringCount++; + + // SCI3 seems to have aligned all string on DWORD boundaries + sci3BoundaryOffset = stringDataPtr - _buf; // Calculate current offset inside script data + sci3BoundaryOffset = sci3BoundaryOffset & 3; // Check boundary offset + if (sci3BoundaryOffset) { + // lower 2 bits are set? Then we have to adjust the offset + sci3BoundaryOffset = 4 - sci3BoundaryOffset; + if (stringDataLeft < sci3BoundaryOffset) + error("Script::identifyOffsets(): SCI3 string boundary adjustment goes beyond end of string block in script %d", _nr); + stringDataLeft -= sci3BoundaryOffset; + stringDataPtr += sci3BoundaryOffset; + } + } while (1); + } + return; } } diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h index fe774aeab5..755e2f3698 100644 --- a/engines/sci/engine/script.h +++ b/engines/sci/engine/script.h @@ -49,12 +49,20 @@ enum ScriptObjectTypes { typedef Common::HashMap<uint16, Object> ObjMap; -struct stringLookupListEntry { - uint16 ptrOffset; // offset of the string +enum ScriptOffsetEntryTypes { + SCI_SCR_OFFSET_TYPE_OBJECT = 0, // classes are handled by this type as well + SCI_SCR_OFFSET_TYPE_STRING, + SCI_SCR_OFFSET_TYPE_SAID +}; + +struct offsetLookupArrayEntry { + uint16 type; // type of entry + uint16 id; // id of this type, first item inside script data is 1, second item is 2, etc. + uint32 offset; // offset of entry within script resource data uint16 stringSize; // size of string, including terminating [NUL] }; -typedef Common::List<stringLookupListEntry> stringLookupListType; +typedef Common::Array<offsetLookupArrayEntry> offsetLookupArrayType; class Script : public SegmentObj { private: @@ -82,7 +90,13 @@ private: ObjMap _objects; /**< Table for objects, contains property variables */ - stringLookupListType _stringLookupList; // Table of string data, that is inside the currently loaded script +protected: + offsetLookupArrayType _offsetLookupArray; // Table of all elements of currently loaded script, that may get pointed to + +private: + uint16 _offsetLookupObjectCount; + uint16 _offsetLookupStringCount; + uint16 _offsetLookupSaidCount; public: int getLocalsOffset() const { return _localsOffset; } @@ -258,9 +272,12 @@ public: int getCodeBlockOffsetSci3() { return READ_SCI11ENDIAN_UINT32(_buf); } /** - * Print string lookup table (list) to debug console + * Get the offset array */ - void debugPrintStrings(Console *con); + const offsetLookupArrayType *getOffsetArray() { return &_offsetLookupArray; }; + uint16 getOffsetObjectCount() { return _offsetLookupObjectCount; }; + uint16 getOffsetStringCount() { return _offsetLookupStringCount; }; + uint16 getOffsetSaidCount() { return _offsetLookupSaidCount; }; private: /** @@ -310,9 +327,9 @@ private: LocalVariables *allocLocalsSegment(SegManager *segMan); /** - * Identifies strings within script data and set up lookup-table + * Identifies certain offsets within script data and set up lookup-table */ - void identifyStrings(); + void identifyOffsets(); }; } // End of namespace Sci diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp index 4011273ca3..6915e12a0e 100644 --- a/engines/sci/engine/script_patches.cpp +++ b/engines/sci/engine/script_patches.cpp @@ -2123,21 +2123,30 @@ static const uint16 qfg1vgaPatchMoveToCrusher[] = { // Same pathfinding bug as above, where Ego is set to move to an impossible // spot when sneaking. In GuardsTrumpet::changeState, we change the final -// location where Ego is moved from 111, 111 to 114, 114. +// location where Ego is moved from 111, 111 to 116, 116. +// target coordinate is really problematic here. +// +// 114, 114 works when the speed slider is all the way up, but doesn't work +// when the speed slider is not. +// +// It seems that this bug was fixed by Sierra for the Macintosh version. +// +// Applies to at least: English PC floppy +// Responsible method: GuardsTrumpet::changeState(8) // Fixes bug: #6248 static const uint16 qfg1vgaSignatureMoveToCastleGate[] = { + 0x51, SIG_ADDTOOFFSET(+1), // class MoveTo SIG_MAGICDWORD, - 0x51, 0x1f, // class MoveTo 0x36, // push - 0x39, 0x6f, // pushi 6f (111 - x) - 0x3c, // dup (111 - y) + 0x39, 0x6f, // pushi 6f (111d) + 0x3c, // dup (111d) - coordinates 111, 111 0x7c, // pushSelf SIG_END }; static const uint16 qfg1vgaPatchMoveToCastleGate[] = { PATCH_ADDTOOFFSET(+3), - 0x39, 0x72, // pushi 72 (114 - x) + 0x39, 0x74, // pushi 74 (116d), changes coordinates to 116, 116 PATCH_END }; @@ -2335,29 +2344,37 @@ static const SciScriptPatcherEntry qfg1vgaSignatures[] = { // which finally re-enables controls // // A fix is difficult to implement. The code in script 20 is generic and used by multiple objects -// That's why I have decided to change the responsible globals (66h and A1h) during mountSaurus::changeState(5) // -// This fix could cause issues in case there is a cutscene, that contains ego getting on a saurus and -// requires controls not getting re-enabled after getting back up on the saurus. +// Originally I decided to change the responsible globals (66h and A1h) during mountSaurus::changeState(5). +// This worked as far as for controls, but mountSaurus::init changes a few selectors of ego as well, which +// won't get restored in that situation, which then messes up room changes and other things. +// +// I have now decided to change sheepScript::changeState(2) in script 665 instead. +// +// This fix could cause issues in case there is a cutscene, where ego is supposed to get onto the saurus using +// sheepScript. // // Applies to at least: English PC Floppy, English Amiga Floppy // Responsible method: mountSaurus::changeState(), mountSaurus::init(), mountSaurus::dispose() // Fixes bug: #5156 static const uint16 qfg2SignatureSaurusFreeze[] = { 0x3c, // dup - 0x35, 0x05, // ldi 5 + 0x35, 0x02, // ldi 5 SIG_MAGICDWORD, 0x1a, // eq? - 0x30, SIG_UINT16(0x004e), // bnt [ret] - 0x39, SIG_SELECTOR8(contains), // pushi [selector contains] - 0x78, // push1 + 0x30, SIG_UINT16(0x0043), // bnt [ret] + 0x76, // push0 + SIG_ADDTOOFFSET(+61), // skip to dispose code + 0x39, SIG_SELECTOR8(dispose), // pushi "dispose" + 0x76, // push0 + 0x54, 0x04, // self 04 SIG_END }; static const uint16 qfg2PatchSaurusFreeze[] = { - 0x35, 0x01, // ldi 1 - 0xa1, 0x66, // sag 66h - 0xa0, SIG_UINT16(0x00a1), // sag 00A1h + 0x81, 0x66, // lag 66h + 0x2e, SIG_UINT16(0x0040), // bt [to dispose code] + 0x35, 0x00, // ldi 0 (waste 2 bytes) PATCH_END }; @@ -2441,7 +2458,7 @@ static const uint16 qfg2PatchImportCharType[] = { // script, description, signature patch static const SciScriptPatcherEntry qfg2Signatures[] = { - { true, 660, "getting back on saurus freeze fix", 1, qfg2SignatureSaurusFreeze, qfg2PatchSaurusFreeze }, + { true, 665, "getting back on saurus freeze fix", 1, qfg2SignatureSaurusFreeze, qfg2PatchSaurusFreeze }, { true, 805, "import character type fix", 1, qfg2SignatureImportCharType, qfg2PatchImportCharType }, { true, 944, "import dialog continuous calls", 1, qfg2SignatureImportDialog, qfg2PatchImportDialog }, SCI_SIGNATUREENTRY_TERMINATOR @@ -2758,9 +2775,64 @@ static const uint16 sq4CdSignatureWalkInFromBelowRoom45[] = { static const uint16 sq4CdPatchWalkInFromBelowRoom45[] = { PATCH_ADDTOOFFSET(+2), - 0x38, PATCH_UINT16(0x00bc), // pushi 00BCh + 0x38, PATCH_UINT16(0x00bc), // pushi 00BCh PATCH_ADDTOOFFSET(+15), - 0x38, PATCH_UINT16(0x00bb), // pushi 00BBh + 0x38, PATCH_UINT16(0x00bb), // pushi 00BBh + PATCH_END +}; + +// It seems that Sierra forgot to set a script flag, when cleaning out the bank account +// in Space Quest 4 CD. This was probably caused by the whole bank account interaction +// getting a rewrite and polish in the CD version. +// +// Because of this bug, points for changing back clothes will not get awarded, which +// makes it impossible to get a perfect point score in the CD version of the game. +// The points are awarded by rm371::doit in script 371. +// +// We fix this. Bug also happened, when using the original interpreter. +// Bug does not happen for PC floppy. +// +// Attention: Some Let's Plays on youtube show that points are in fact awarded. Which is true. +// But those Let's Plays were actually created by playing a hacked Space Quest 4 version +// (which is part Floppy, part CD version - we consider it to be effectively pirated) +// and not the actual CD version of Space Quest 4. +// It's easy to identify - talkie + store called "Radio Shack" -> is hacked version. +// +// Applies to at least: English PC CD +// Responsible method: but2Script::changeState(2) +// Fixes bug: #6866 +static const uint16 sq4CdSignatureGetPointsForChangingBackClothes[] = { + 0x35, 0x02, // ldi 02 + SIG_MAGICDWORD, + 0x1a, // eq? + 0x30, SIG_UINT16(0x006a), // bnt [state 3] + 0x76, + SIG_ADDTOOFFSET(+46), // jump over "withdraw funds" code + 0x33, 0x33, // jmp [end of state 2, set cycles code] + SIG_ADDTOOFFSET(+51), // jump over "clean bank account" code + 0x35, 0x02, // ldi 02 + 0x65, 0x1a, // aTop cycles + 0x33, 0x0b, // jmp [toss/ret] + 0x3c, // dup + 0x35, 0x03, // ldi 03 + 0x1a, // eq? + 0x31, 0x05, // bnt [toss/ret] + SIG_END +}; + +static const uint16 sq4CdPatchGetPointsForChangingBackClothes[] = { + PATCH_ADDTOOFFSET(+3), + 0x30, PATCH_UINT16(0x0070), // bnt [state 3] + PATCH_ADDTOOFFSET(+47), // "withdraw funds" code + 0x33, 0x39, // jmp [end of state 2, set cycles code] + PATCH_ADDTOOFFSET(+51), + 0x78, // push1 + 0x39, 0x1d, // ldi 1Dh + 0x45, 0x07, 0x02, // call export 7 of script 0 (set flag) -> effectively sets global 73h, bit 2 + 0x35, 0x02, // ldi 02 + 0x65, 0x1c, // aTop cycles + 0x33, 0x05, // jmp [toss/ret] + // check for state 3 code removed to save 6 bytes PATCH_END }; @@ -2859,6 +2931,7 @@ static const SciScriptPatcherEntry sq4Signatures[] = { { true, 298, "Floppy: endless flight", 1, sq4FloppySignatureEndlessFlight, sq4FloppyPatchEndlessFlight }, { 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, 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 }, diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index ea3443e551..aab32032f7 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -603,8 +603,8 @@ const SciWorkaroundEntry kGraphRedrawBox_workarounds[] = { { GID_SQ4, 405, 405, 0, "swimAfterEgo", "changeState", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air - accidental additional parameter specified { GID_SQ4, 405, 405, 0, "", "changeState", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air... Russian version - bug #5573 { GID_SQ4, 406, 406, 0, "egoFollowed", "changeState", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // FLOPPY: when getting shot by the police - accidental additional parameter specified - { GID_SQ4, 406, 406, 0, "swimAndShoot", "changeState", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air - accidental additional parameter specified - { GID_SQ4, 406, 406, 0, "", "changeState", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air... Russian version - bug #5573 (is for both egoFollowed and swimAndShoot) + { GID_SQ4, -1, 406, 0, "swimAndShoot", "changeState", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air - accidental additional parameter specified + { GID_SQ4, -1, 406, 0, "", "changeState", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air... Russian version - bug #5573 (is for both egoFollowed and swimAndShoot) { GID_SQ4, 410, 410, 0, "swimAfterEgo", "changeState", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air - accidental additional parameter specified { GID_SQ4, 410, 410, 0, "", "changeState", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air... Russian version - bug #5573 { GID_SQ4, 411, 411, 0, "swimAndShoot", "changeState", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air - accidental additional parameter specified diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index bac7a4665b..1cbefee105 100644 --- a/engines/scumm/scumm-md5.h +++ b/engines/scumm/scumm-md5.h @@ -1,5 +1,5 @@ /* - This file was generated by the md5table tool on Thu May 7 20:24:51 2015 + This file was generated by the md5table tool on Sun May 10 14:23:43 2015 DO NOT EDIT MANUALLY! */ @@ -180,7 +180,7 @@ static const MD5Table md5table[] = { { "3a03dab514e4038df192d8a8de469788", "atlantis", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformAmiga }, { "3a0c35f3c147b98a2bdf8d400cfc4ab5", "indy3", "FM-TOWNS", "", -1, Common::JA_JPN, Common::kPlatformFMTowns }, { "3a3e592b074f595489f7f11e150c398d", "puttzoo", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformWindows }, - { "3a5d13675e9a23aedac0bac7730f0ac1", "samnmax", "", "CD", -1, Common::FR_FRA, Common::kPlatformMacintosh }, + { "3a5d13675e9a23aedac0bac7730f0ac1", "samnmax", "", "CD", 228446581, Common::FR_FRA, Common::kPlatformMacintosh }, { "3a5ec90d556d4920976c5578bfbfaf79", "maniac", "NES", "", -1, Common::DE_DEU, Common::kPlatformNES }, { "3ae7f002d9256b8bdf76aaf8a3a069f8", "freddi", "HE 100", "", 34837, Common::EN_GRB, Common::kPlatformWii }, { "3af61c5edf8e15b43dbafd285b2e9777", "puttcircus", "", "Demo", -1, Common::HE_ISR, Common::kPlatformWindows }, @@ -193,6 +193,7 @@ static const MD5Table md5table[] = { { "3df6ead57930488bc61e6e41901d0e97", "fbear", "HE 62", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "3e48298920fab9b7aec5a971e1bd1fab", "pajama3", "", "Demo", -1, Common::EN_GRB, Common::kPlatformWindows }, { "3e861421f494711bc6f619d4aba60285", "airport", "", "", 93231, Common::RU_RUS, Common::kPlatformWindows }, + { "403d2ec4d60d3cdae925e6cbf67716d6", "ft", "", "", 489436643, Common::FR_FRA, Common::kPlatformMacintosh }, { "40564ec47da48a67787d1f9bd043902a", "maniac", "V2 Demo", "V2 Demo", 1988, Common::EN_ANY, Common::kPlatformDOS }, { "4167a92a1d46baa4f4127d918d561f88", "tentacle", "", "CD", 7932, Common::EN_ANY, Common::kPlatformUnknown }, { "41958e24d03181ff9a381a66d048a581", "ft", "", "", -1, Common::PT_BRA, Common::kPlatformUnknown }, @@ -643,7 +644,7 @@ static const MD5Table md5table[] = { { "ecc4340c2b801f5af8da4e00c0e432d9", "puttcircus", "", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "ed2b074bc3166087a747acb2a3c6abb0", "freddi3", "HE 98.5", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "ed361270102e355afe5236954216aba2", "lost", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, - { "ede149fda3edfc1dbd7347e0737cb583", "tentacle", "", "CD", -1, Common::FR_FRA, Common::kPlatformMacintosh }, + { "ede149fda3edfc1dbd7347e0737cb583", "tentacle", "", "CD", 282830409, Common::FR_FRA, Common::kPlatformMacintosh }, { "edfdb24a499d92c59f824c52987c0eec", "atlantis", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformDOS }, { "ee41f6afbc5b26fa475754b56fe92048", "puttputt", "HE 61", "", 8032, Common::JA_JPN, Common::kPlatform3DO }, { "ee785fe2569bc9965526e774f7ab86f1", "spyfox", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, diff --git a/engines/sherlock/animation.cpp b/engines/sherlock/animation.cpp index 1d6c12f668..21d63633d3 100644 --- a/engines/sherlock/animation.cpp +++ b/engines/sherlock/animation.cpp @@ -28,19 +28,15 @@ namespace Sherlock { static const int NO_FRAMES = FRAMES_END; -Animation::Animation(SherlockEngine *vm): _vm(vm) { +Animation::Animation(SherlockEngine *vm) : _vm(vm) { } -/** - * Play a full-screen animation - */ bool Animation::play(const Common::String &filename, int minDelay, int fade, bool setPalette, int speed) { Events &events = *_vm->_events; Screen &screen = *_vm->_screen; Sound &sound = *_vm->_sound; int soundNumber = 0; - sound._playingEpilogue = true; // Check for any any sound frames for the given animation const int *soundFrames = checkForSoundFrames(filename); @@ -50,8 +46,8 @@ bool Animation::play(const Common::String &filename, int minDelay, int fade, // Load the animation Common::SeekableReadStream *stream; - if (!_vm->_titleOverride.empty()) - stream = _vm->_res->load(vdxName, _vm->_titleOverride); + if (!_gfxLibraryFilename.empty()) + stream = _vm->_res->load(vdxName, _gfxLibraryFilename); else if (_vm->_useEpilogue2) stream = _vm->_res->load(vdxName, "epilog2.lib"); else @@ -106,12 +102,12 @@ bool Animation::play(const Common::String &filename, int minDelay, int fade, if (frameNumber++ == *soundFrames) { ++soundNumber; ++soundFrames; - Common::String fname = _vm->_soundOverride.empty() ? + Common::String fname = _soundLibraryFilename.empty() ? Common::String::format("%s%01d", filename.c_str(), soundNumber) : Common::String::format("%s%02d", filename.c_str(), soundNumber); if (sound._voices) - sound.playSound(fname, WAIT_RETURN_IMMEDIATELY); + sound.playSound(fname, WAIT_RETURN_IMMEDIATELY, 100, _soundLibraryFilename.c_str()); } events.wait(speed * 3); @@ -133,23 +129,16 @@ bool Animation::play(const Common::String &filename, int minDelay, int fade, events.clearEvents(); sound.stopSound(); delete stream; - sound._playingEpilogue = false; return !skipped && !_vm->shouldQuit(); } -/** - * Load the prologue name array - */ void Animation::setPrologueNames(const char *const *names, int count) { - for (int idx = 0; idx < count; ++idx, names++) { + for (int idx = 0; idx < count; ++idx, ++names) { _prologueNames.push_back(*names); } } -/** - * Load the prologue frame array - */ void Animation::setPrologueFrames(const int *frames, int count, int maxFrames) { _prologueFrames.resize(count); @@ -159,18 +148,12 @@ void Animation::setPrologueFrames(const int *frames, int count, int maxFrames) { } } -/** - * Load the title name array - */ void Animation::setTitleNames(const char *const *names, int count) { - for (int idx = 0; idx < count; ++idx, names++) { + for (int idx = 0; idx < count; ++idx, ++names) { _titleNames.push_back(*names); } } -/** - * Load the title frame array - */ void Animation::setTitleFrames(const int *frames, int count, int maxFrames) { _titleFrames.resize(count); @@ -180,21 +163,18 @@ void Animation::setTitleFrames(const int *frames, int count, int maxFrames) { } } -/** - * Checks for whether an animation is being played that has associated sound - */ const int *Animation::checkForSoundFrames(const Common::String &filename) { const int *frames = &NO_FRAMES; - if (_vm->_soundOverride.empty()) { - for (Common::Array<const char *>::size_type idx = 0; idx < _prologueNames.size(); ++idx) { + if (_soundLibraryFilename.empty()) { + for (uint idx = 0; idx < _prologueNames.size(); ++idx) { if (filename.equalsIgnoreCase(_prologueNames[idx])) { frames = &_prologueFrames[idx][0]; break; } } } else { - for (Common::Array<const char *>::size_type idx = 0; idx < _titleNames.size(); ++idx) { + for (uint idx = 0; idx < _titleNames.size(); ++idx) { if (filename.equalsIgnoreCase(_titleNames[idx])) { frames = &_titleFrames[idx][0]; break; diff --git a/engines/sherlock/animation.h b/engines/sherlock/animation.h index 06614df6b1..b7811d3fa8 100644 --- a/engines/sherlock/animation.h +++ b/engines/sherlock/animation.h @@ -39,21 +39,42 @@ private: Common::Array<const char *> _prologueNames; Common::Array<Common::Array<int> > _prologueFrames; - Common::Array<const char *> _titleNames; Common::Array<Common::Array<int> > _titleFrames; + /** + * Checks for whether an animation is being played that has associated sound + */ const int *checkForSoundFrames(const Common::String &filename); public: + Common::String _soundLibraryFilename; + Common::String _gfxLibraryFilename; public: Animation(SherlockEngine *vm); + /** + * Load the prologue name array + */ void setPrologueNames(const char *const *names, int count); + + /** + * Load the prologue frame array + */ void setPrologueFrames(const int *frames, int count, int maxFrames); + /** + * Load the title name array + */ void setTitleNames(const char *const *names, int count); + + /** + * Load the title frame array + */ void setTitleFrames(const int *frames, int count, int maxFrames); + /** + * Play a full-screen animation + */ bool play(const Common::String &filename, int minDelay, int fade, bool setPalette, int speed); }; diff --git a/engines/sherlock/debugger.cpp b/engines/sherlock/debugger.cpp index ecd3f2ee08..cfbea2bc24 100644 --- a/engines/sherlock/debugger.cpp +++ b/engines/sherlock/debugger.cpp @@ -30,9 +30,6 @@ Debugger::Debugger(SherlockEngine *vm) : GUI::Debugger(), _vm(vm) { registerCmd("scene", WRAP_METHOD(Debugger, cmdScene)); } -/** - * Converts a decimal or hexadecimal string into a number - */ int Debugger::strToInt(const char *s) { if (!*s) // No string at all @@ -49,9 +46,6 @@ int Debugger::strToInt(const char *s) { return (int)tmp; } -/** - * Switch to another scene - */ bool Debugger::cmdScene(int argc, const char **argv) { if (argc != 2) { debugPrintf("Format: scene <room>\n"); diff --git a/engines/sherlock/debugger.h b/engines/sherlock/debugger.h index 6021bb7d0d..e6a3aba828 100644 --- a/engines/sherlock/debugger.h +++ b/engines/sherlock/debugger.h @@ -34,8 +34,14 @@ class Debugger : public GUI::Debugger { private: SherlockEngine *_vm; + /** + * Converts a decimal or hexadecimal string into a number + */ int strToInt(const char *s); + /** + * Switch to another scene + */ bool cmdScene(int argc, const char **argv); public: Debugger(SherlockEngine *vm); diff --git a/engines/sherlock/detection.cpp b/engines/sherlock/detection.cpp index 2804ec1d31..ea68d79a1b 100644 --- a/engines/sherlock/detection.cpp +++ b/engines/sherlock/detection.cpp @@ -36,16 +36,10 @@ struct SherlockGameDescription { GameType gameID; }; -/** - * Returns the Id of the game - */ GameType SherlockEngine::getGameID() const { return _gameDescription->gameID; } -/** - * Returns the platform the game's datafiles are for - */ Common::Platform SherlockEngine::getPlatform() const { return _gameDescription->desc.platform; } @@ -60,26 +54,71 @@ static const PlainGameDescriptor sherlockGames[] = { #define GAMEOPTION_ORIGINAL_SAVES GUIO_GAMEOPTIONS1 +#define GAMEOPTION_FADE_STYLE GUIO_GAMEOPTIONS2 +#define GAMEOPTION_HELP_STYLE GUIO_GAMEOPTIONS3 +#define GAMEOPTION_PORTRAITS_ON GUIO_GAMEOPTIONS4 +#define GAMEOPTION_WINDOW_STYLE GUIO_GAMEOPTIONS5 static const ADExtraGuiOptionsMap optionsList[] = { { GAMEOPTION_ORIGINAL_SAVES, { _s("Use original savegame dialog"), - _s("Files button in-game shows original savegame dialog rather than ScummVM menu"), + _s("Files button in-game shows original savegame dialog rather than the ScummVM menu"), "originalsaveload", false } }, + { + GAMEOPTION_FADE_STYLE, + { + _s("Pixellated scene transitions"), + _s("When changing scenes, a randomized pixel transition is done"), + "fade_style", + true + } + }, + + { + GAMEOPTION_HELP_STYLE, + { + _s("Don't show hotspots when moving mouse"), + _s("Only show hotspot names after you actually click on a hotspot or action button"), + "help_style", + false + } + }, + + { + GAMEOPTION_PORTRAITS_ON, + { + _s("Show character portraits"), + _s("Show portraits for the characters when conversing"), + "portraits_on", + true + } + }, + + { + GAMEOPTION_WINDOW_STYLE, + { + _s("Slide dialogs into view"), + _s("Slide UI dialogs into view, rather than simply showing them immediately"), + "window_style", + true + } + }, + AD_EXTRA_GUI_OPTIONS_TERMINATOR }; + #include "sherlock/detection_tables.h" class SherlockMetaEngine : public AdvancedMetaEngine { public: - SherlockMetaEngine() : AdvancedMetaEngine(Sherlock::gameDescriptions, sizeof(Sherlock::SherlockGameDescription), + SherlockMetaEngine() : AdvancedMetaEngine(Sherlock::gameDescriptions, sizeof(Sherlock::SherlockGameDescription), sherlockGames, optionsList) {} virtual const char *getName() const { @@ -90,17 +129,37 @@ public: return "Sherlock Engine (C) 1992-1996 Mythos Software, 1992-1996 (C) Electronic Arts"; } + /** + * Creates an instance of the game engine + */ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; + + /** + * Returns a list of features the game's MetaEngine support + */ virtual bool hasFeature(MetaEngineFeature f) const; + + /** + * Return a list of savegames + */ virtual SaveStateList listSaves(const char *target) const; + + /** + * Returns the maximum number of allowed save slots + */ virtual int getMaximumSaveSlot() const; + + /** + * Deletes a savegame in the specified slot + */ virtual void removeSaveState(const char *target, int slot) const; + + /** + * Given a specified savegame slot, returns extended information for the save + */ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; }; -/** - * Creates an instance of the game engine - */ bool SherlockMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { const Sherlock::SherlockGameDescription *gd = (const Sherlock::SherlockGameDescription *)desc; if (gd) { @@ -119,9 +178,6 @@ bool SherlockMetaEngine::createInstance(OSystem *syst, Engine **engine, const AD return gd != 0; } -/** - * Returns a list of features the game's MetaEngine support - */ bool SherlockMetaEngine::hasFeature(MetaEngineFeature f) const { return (f == kSupportsListSaves) || @@ -131,9 +187,6 @@ bool SherlockMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSavesSupportThumbnail); } -/** - * Returns a list of features the game itself supports - */ bool Sherlock::SherlockEngine::hasFeature(EngineFeature f) const { return (f == kSupportsRTL) || @@ -141,38 +194,23 @@ bool Sherlock::SherlockEngine::hasFeature(EngineFeature f) const { (f == kSupportsSavingDuringRuntime); } -/** - * Returns whether the version is a demo - */ -bool Sherlock::SherlockEngine::getIsDemo() const { +bool Sherlock::SherlockEngine::isDemo() const { return _gameDescription->desc.flags & ADGF_DEMO; } -/** - * Return a list of savegames - */ SaveStateList SherlockMetaEngine::listSaves(const char *target) const { return Sherlock::SaveManager::getSavegameList(target); } -/** - * Returns the maximum number of allowed save slots - */ int SherlockMetaEngine::getMaximumSaveSlot() const { return MAX_SAVEGAME_SLOTS; } -/** - * Deletes a savegame in the specified slot - */ void SherlockMetaEngine::removeSaveState(const char *target, int slot) const { Common::String filename = Sherlock::SaveManager(nullptr, target).generateSaveName(slot); g_system->getSavefileManager()->removeSavefile(filename); } -/** - * Given a specified savegame slot, returns extended information for the save - */ SaveStateDescriptor SherlockMetaEngine::querySaveMetaInfos(const char *target, int slot) const { Common::String filename = Sherlock::SaveManager(nullptr, target).generateSaveName(slot); Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(filename); @@ -197,7 +235,7 @@ SaveStateDescriptor SherlockMetaEngine::querySaveMetaInfos(const char *target, i #if PLUGIN_ENABLED_DYNAMIC(SHERLOCK) -REGISTER_PLUGIN_DYNAMIC(SHERLOCK, PLUGIN_TYPE_ENGINE, SherlockMetaEngine); + REGISTER_PLUGIN_DYNAMIC(SHERLOCK, PLUGIN_TYPE_ENGINE, SherlockMetaEngine); #else -REGISTER_PLUGIN_STATIC(SHERLOCK, PLUGIN_TYPE_ENGINE, SherlockMetaEngine); + REGISTER_PLUGIN_STATIC(SHERLOCK, PLUGIN_TYPE_ENGINE, SherlockMetaEngine); #endif diff --git a/engines/sherlock/detection_tables.h b/engines/sherlock/detection_tables.h index 8300a0ffcf..208b6710af 100644 --- a/engines/sherlock/detection_tables.h +++ b/engines/sherlock/detection_tables.h @@ -32,8 +32,9 @@ static const SherlockGameDescription gameDescriptions[] = { AD_ENTRY1s("talk.lib", "ad0c4d6865edf15da4e9204c08815875", 238928), Common::EN_ANY, Common::kPlatformDOS, - ADGF_UNSTABLE | ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVES) + ADGF_UNSTABLE, + GUIO6(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_FADE_STYLE, GAMEOPTION_HELP_STYLE, + GAMEOPTION_PORTRAITS_ON, GAMEOPTION_WINDOW_STYLE) }, GType_SerratedScalpel, }, @@ -79,7 +80,8 @@ static const SherlockGameDescription gameDescriptions[] = { Common::kPlatformDOS, ADGF_UNSTABLE, GUIO0() - } + }, + GType_RoseTattoo }, { @@ -97,6 +99,21 @@ static const SherlockGameDescription gameDescriptions[] = { GType_RoseTattoo, }, + { + // Case of the Rose Tattoo - German CD + // Provided by m_kiewitz + { + "rosetattoo", + "CD", + AD_ENTRY1s("talk.lib", "5027aa72f0d263ed3b1c764a6c397911", 873864), + Common::DE_DEU, + Common::kPlatformDOS, + ADGF_UNSTABLE, + GUIO0() + }, + GType_RoseTattoo, + }, + { AD_TABLE_END_MARKER, (GameType)0 } }; diff --git a/engines/sherlock/events.cpp b/engines/sherlock/events.cpp index 3b0b0dacc6..94ddc9a792 100644 --- a/engines/sherlock/events.cpp +++ b/engines/sherlock/events.cpp @@ -30,6 +30,8 @@ namespace Sherlock { +enum ButtonFlag { LEFT_BUTTON = 1, RIGHT_BUTTON = 2 }; + Events::Events(SherlockEngine *vm) { _vm = vm; _cursorImages = nullptr; @@ -46,9 +48,6 @@ Events::~Events() { delete _cursorImages; } -/** - * Load a set of cursors from the specified file - */ void Events::loadCursors(const Common::String &filename) { hideCursor(); delete _cursorImages; @@ -57,9 +56,6 @@ void Events::loadCursors(const Common::String &filename) { _cursorId = INVALID_CURSOR; } -/** - * Set the cursor to show - */ void Events::setCursor(CursorId cursorId) { if (cursorId == _cursorId) return; @@ -67,58 +63,36 @@ void Events::setCursor(CursorId cursorId) { _cursorId = cursorId; // Set the cursor data - Graphics::Surface &s = (*_cursorImages)[cursorId]; + Graphics::Surface &s = (*_cursorImages)[cursorId]._frame; setCursor(s); } -/** - * Set the cursor to show from a passed frame - */ void Events::setCursor(const Graphics::Surface &src) { CursorMan.replaceCursor(src.getPixels(), src.w, src.h, 0, 0, 0xff); showCursor(); } -/** - * Show the mouse cursor - */ void Events::showCursor() { CursorMan.showMouse(true); } -/** - * Hide the mouse cursor - */ void Events::hideCursor() { CursorMan.showMouse(false); } -/** - * Returns the cursor - */ CursorId Events::getCursor() const { return _cursorId; } -/** - * Returns true if the mouse cursor is visible - */ bool Events::isCursorVisible() const { return CursorMan.isVisible(); } -/** - * Move the mouse - */ void Events::moveMouse(const Common::Point &pt) { g_system->warpMouse(pt.x, pt.y); } - -/** - * Check for any pending events - */ void Events::pollEvents() { checkForNextFrameCounter(); @@ -143,38 +117,28 @@ void Events::pollEvents() { case Common::EVENT_KEYUP: return; case Common::EVENT_LBUTTONDOWN: - _mouseButtons |= 1; + _mouseButtons |= LEFT_BUTTON; return; case Common::EVENT_RBUTTONDOWN: - _mouseButtons |= 2; + _mouseButtons |= RIGHT_BUTTON; return; case Common::EVENT_LBUTTONUP: - _mouseButtons &= ~1; + _mouseButtons &= ~LEFT_BUTTON; return; case Common::EVENT_RBUTTONUP: - _mouseButtons &= ~2; + _mouseButtons &= ~RIGHT_BUTTON; return; - case Common::EVENT_MOUSEMOVE: - _mousePos = event.mouse; - break; default: break; } } } -/** - * Poll for events and introduce a small delay, to allow the system to - * yield to other running programs - */ void Events::pollEventsAndWait() { pollEvents(); g_system->delayMillis(10); } -/** - * Check whether it's time to display the next screen frame - */ bool Events::checkForNextFrameCounter() { // Check for next game frame uint32 milli = g_system->getMillis(); @@ -194,20 +158,14 @@ bool Events::checkForNextFrameCounter() { return false; } -/** - * Get a pending keypress - */ -Common::KeyState Events::getKey() { - Common::KeyState keyState = _pendingKeys.pop(); - if ((keyState.flags & Common::KBD_SHIFT) != 0) - keyState.ascii = toupper(keyState.ascii); +Common::Point Events::mousePos() const { + return g_system->getEventManager()->getMousePos(); +} - return keyState; +Common::KeyState Events::getKey() { + return _pendingKeys.pop(); } -/** - * Clear any current keypress or mouse click - */ void Events::clearEvents() { _pendingKeys.clear(); _mouseButtons = 0; @@ -216,24 +174,15 @@ void Events::clearEvents() { _oldButtons = _oldRightButton = false; } -/** - * Clear any pending keyboard inputs - */ void Events::clearKeyboard() { _pendingKeys.clear(); } -/** - * Delay for a given number of game frames, where each frame is 1/60th of a second - */ void Events::wait(int numFrames) { uint32 totalMilli = numFrames * 1000 / GAME_FRAME_RATE; delay(totalMilli); } -/** - * Does a delay of the specified number of milliseconds - */ bool Events::delay(uint32 time, bool interruptable) { // Different handling for really short versus extended times if (time < 10) { @@ -263,34 +212,25 @@ bool Events::delay(uint32 time, bool interruptable) { } } -/** - * Sets the pressed and released button flags on the raw button state previously set in pollEvents calls. - * @remarks The events manager has separate variables for the raw immediate and old button state - * versus the current buttons states for the frame. This method is expected to be called only once - * per game frame - */ void Events::setButtonState() { _released = _rightReleased = false; - if (_mouseButtons & 1) + if (_mouseButtons & LEFT_BUTTON) _pressed = _oldButtons = true; - if ((_mouseButtons & 1) == 0 && _oldButtons) { + if ((_mouseButtons & LEFT_BUTTON) == 0 && _oldButtons) { _pressed = _oldButtons = false; _released = true; } - if (_mouseButtons & 2) + if (_mouseButtons & RIGHT_BUTTON) _rightPressed = _oldRightButton = true; - if ((_mouseButtons & 2) == 0 && _oldRightButton) { + if ((_mouseButtons & RIGHT_BUTTON) == 0 && _oldRightButton) { _rightPressed = _oldRightButton = false; _rightReleased = true; } } -/** - * Checks to see to see if a key or a mouse button is pressed. - */ bool Events::checkInput() { setButtonState(); return kbHit() || _pressed || _released || _rightPressed || _rightReleased; diff --git a/engines/sherlock/events.h b/engines/sherlock/events.h index 199e14f03a..c19a92de8c 100644 --- a/engines/sherlock/events.h +++ b/engines/sherlock/events.h @@ -42,10 +42,12 @@ private: SherlockEngine *_vm; uint32 _frameCounter; uint32 _priorFrameTime; - Common::Point _mousePos; ImageFile *_cursorImages; int _mouseButtons; + /** + * Check whether it's time to display the next screen frame + */ bool checkForNextFrameCounter(); public: CursorId _cursorId; @@ -60,42 +62,102 @@ public: Events(SherlockEngine *vm); ~Events(); + /** + * Load a set of cursors from the specified file + */ void loadCursors(const Common::String &filename); + /** + * Set the cursor to show + */ void setCursor(CursorId cursorId); + + /** + * Set the cursor to show from a passed frame + */ void setCursor(const Graphics::Surface &src); + /** + * Show the mouse cursor + */ void showCursor(); + /** + * Hide the mouse cursor + */ void hideCursor(); + /** + * Returns the cursor + */ CursorId getCursor() const; + /** + * Returns true if the mouse cursor is visible + */ bool isCursorVisible() const; + /** + * Move the mouse + */ void moveMouse(const Common::Point &pt); + /** + * Check for any pending events + */ void pollEvents(); + /** + * Poll for events and introduce a small delay, to allow the system to + * yield to other running programs + */ void pollEventsAndWait(); - Common::Point mousePos() const { return _mousePos; } + /** + * Get the current mouse position + */ + Common::Point mousePos() const; uint32 getFrameCounter() const { return _frameCounter; } bool kbHit() const { return !_pendingKeys.empty(); } + /** + * Get a pending keypress + */ Common::KeyState getKey(); + /** + * Clear any current keypress or mouse click + */ void clearEvents(); + + /** + * Clear any pending keyboard inputs + */ void clearKeyboard(); + /** + * Delay for a given number of game frames, where each frame is 1/60th of a second + */ void wait(int numFrames); + /** + * Does a delay of the specified number of milliseconds + */ bool delay(uint32 time, bool interruptable = false); + /** + * Sets the pressed and released button flags on the raw button state previously set in pollEvents calls. + * @remarks The events manager has separate variables for the raw immediate and old button state + * versus the current buttons states for the frame. This method is expected to be called only once + * per game frame + */ void setButtonState(); + /** + * Checks to see to see if a key or a mouse button is pressed. + */ bool checkInput(); }; diff --git a/engines/sherlock/inventory.cpp b/engines/sherlock/inventory.cpp index 397575dfd9..bbb7c75aea 100644 --- a/engines/sherlock/inventory.cpp +++ b/engines/sherlock/inventory.cpp @@ -31,9 +31,6 @@ InventoryItem::InventoryItem(int requiredFlag, const Common::String &name, _examine(examine), _lookFlag(0) { } -/** - * Synchronize the data for an inventory item - */ void InventoryItem::synchronize(Common::Serializer &s) { s.syncAsSint16LE(_requiredFlag); s.syncAsSint16LE(_lookFlag); @@ -50,15 +47,14 @@ Inventory::Inventory(SherlockEngine *vm) : Common::Array<InventoryItem>(), _vm(v _invIndex = 0; _holdings = 0; _invMode = INVMODE_EXIT; + for (int i = 0; i < 6; ++i) + _invShapes[i] = nullptr; } Inventory::~Inventory() { freeGraphics(); } -/** - * Free inventory data - */ void Inventory::freeInv() { freeGraphics(); @@ -66,9 +62,6 @@ void Inventory::freeInv() { _invGraphicsLoaded = false; } -/** - * Free any loaded inventory graphics - */ void Inventory::freeGraphics() { for (uint idx = 0; idx < MAX_VISIBLE_INVENTORY; ++idx) delete _invShapes[idx]; @@ -77,10 +70,6 @@ void Inventory::freeGraphics() { _invGraphicsLoaded = false; } -/** - * Load the list of names the inventory items correspond to, if not already loaded, - * and then calls loadGraphics to load the associated graphics - */ void Inventory::loadInv() { // Exit if the inventory names are already loaded if (_names.size() > 0) @@ -104,9 +93,6 @@ void Inventory::loadInv() { loadGraphics(); } -/** - * Load the list of names of graphics for the inventory - */ void Inventory::loadGraphics() { if (_invGraphicsLoaded) return; @@ -126,38 +112,29 @@ void Inventory::loadGraphics() { _invGraphicsLoaded = true; } -/** - * Searches through the list of names that correspond to the inventory items - * and returns the numer that matches the passed name - */ int Inventory::findInv(const Common::String &name) { for (int idx = 0; idx < (int)_names.size(); ++idx) { - if (scumm_stricmp(name.c_str(), _names[idx].c_str()) == 0) + if (name.equalsIgnoreCase(_names[idx])) return idx; } - return 1; + // Couldn't find the desired item + error("Couldn't find inventory item - %s", name.c_str()); } -/** - * Display the character's inventory. The slamIt parameter specifies: - * 0 = Draw it on the back buffer, and don't display it - * 1 = Draw it on the back buffer, and then display it - * 2 = Draw it on the secondary back buffer, and don't display it - */ -void Inventory::putInv(int slamIt) { +void Inventory::putInv(InvSlamMode slamIt) { Screen &screen = *_vm->_screen; UserInterface &ui = *_vm->_ui; // If an inventory item has disappeared (due to using it or giving it), - // a blank space slot may haave appeared. If so, adjust the inventory + // a blank space slot may have appeared. If so, adjust the inventory if (_invIndex > 0 && _invIndex > (_holdings - 6)) { --_invIndex; freeGraphics(); loadGraphics(); } - if (slamIt != 2) { + if (slamIt != SLAM_SECONDARY_BUFFER) { screen.makePanel(Common::Rect(6, 163, 54, 197)); screen.makePanel(Common::Rect(58, 163, 106, 197)); screen.makePanel(Common::Rect(110, 163, 158, 197)); @@ -169,53 +146,45 @@ void Inventory::putInv(int slamIt) { // Iterate through displaying up to 6 objects at a time for (int idx = _invIndex; idx < _holdings && (idx - _invIndex) < MAX_VISIBLE_INVENTORY; ++idx) { int itemNum = idx - _invIndex; - Surface &bb = slamIt == 2 ? screen._backBuffer2 : screen._backBuffer1; + Surface &bb = slamIt == SLAM_SECONDARY_BUFFER ? screen._backBuffer2 : screen._backBuffer1; Common::Rect r(8 + itemNum * 52, 165, 51 + itemNum * 52, 194); // Draw the background if (idx == ui._selector) { bb.fillRect(r, 235); - } else if (slamIt == 2) { + } else if (slamIt == SLAM_SECONDARY_BUFFER) { bb.fillRect(r, BUTTON_MIDDLE); } // Draw the item image - Graphics::Surface &img = (*_invShapes[itemNum])[0]._frame; - bb.transBlitFrom(img, Common::Point(6 + itemNum * 52 + ((47 - img.w) / 2), - 163 + ((33 - img.h) / 2))); + ImageFrame &frame = (*_invShapes[itemNum])[0]; + bb.transBlitFrom(frame, Common::Point(6 + itemNum * 52 + ((47 - frame._width) / 2), + 163 + ((33 - frame._height) / 2))); } - if (slamIt == 1) + if (slamIt == SLAM_DISPLAY) screen.slamArea(6, 163, 308, 34); - if (slamIt != 2) + if (slamIt != SLAM_SECONDARY_BUFFER) ui.clearInfo(); if (slamIt == 0) { invCommands(0); - } else if (slamIt == 2) { + } else if (slamIt == SLAM_SECONDARY_BUFFER) { screen._backBuffer = &screen._backBuffer2; invCommands(0); screen._backBuffer = &screen._backBuffer1; } } -/** - * Put the game into inventory mode and open the interface window. - * The flag parameter specifies the mode: - * 0 = plain inventory mode - * 2 = use inventory mode - * 3 = give inventory mode - * 128 = Draw window in the back buffer, but don't display it - */ -void Inventory::drawInventory(int flag) { +void Inventory::drawInventory(InvNewMode mode) { Screen &screen = *_vm->_screen; UserInterface &ui = *_vm->_ui; - int tempFlag = flag; + InvNewMode tempMode = mode; loadInv(); - if (flag == 128) { + if (mode == INVENTORY_DONT_DISPLAY) { screen._backBuffer = &screen._backBuffer2; } @@ -248,21 +217,21 @@ void Inventory::drawInventory(int flag) { screen.makeButton(Common::Rect(INVENTORY_POINTS[7][0], CONTROLS_Y1, INVENTORY_POINTS[7][1], CONTROLS_Y1 + 10), INVENTORY_POINTS[7][2], "__"); - if (tempFlag == 128) - flag = 1; - _invMode = (InvMode)flag; + if (tempMode == INVENTORY_DONT_DISPLAY) + mode = LOOK_INVENTORY_MODE; + _invMode = (InvMode)mode; - if (flag) { - ui._oldKey = INVENTORY_COMMANDS[flag]; + if (mode != PLAIN_INVENTORY) { + ui._oldKey = INVENTORY_COMMANDS[(int)mode]; } else { ui._oldKey = -1; } invCommands(0); - putInv(0); + putInv(SLAM_DONT_DISPLAY); - if (tempFlag != 128) { - if (!ui._windowStyle) { + if (tempMode != INVENTORY_DONT_DISPLAY) { + if (!ui._slideWindows) { screen.slamRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); } else { ui.summonWindow(false, CONTROLS_Y1); @@ -278,26 +247,22 @@ void Inventory::drawInventory(int flag) { ((ScalpelUserInterface *)_vm->_ui)->_oldUse = -1; } -/** - * Prints the line of inventory commands at the top of an inventory window with - * the correct highlighting - */ void Inventory::invCommands(bool slamIt) { Screen &screen = *_vm->_screen; UserInterface &ui = *_vm->_ui; if (slamIt) { screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1), - _invMode == 0 ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND, + _invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND, true, "Exit"); screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1), - _invMode == 1 ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND, + _invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND, true, "Look"); screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1), - _invMode == 2 ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND, + _invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND, true, "Use"); screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1), - _invMode == 3 ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND, + _invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND, true, "Give"); screen.print(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1), _invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND, @@ -311,20 +276,20 @@ void Inventory::invCommands(bool slamIt) { screen.print(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1 + 1), (_holdings - _invIndex <= 6) ? COMMAND_NULL : COMMAND_FOREGROUND, "__"); - if (_invMode != 1) + if (_invMode != INVMODE_LOOK) ui.clearInfo(); } else { screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1), - _invMode == 0 ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND, + _invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND, false, "Exit"); screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1), - _invMode == 1 ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND, + _invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND, false, "Look"); screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1), - _invMode == 2 ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND, + _invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND, false, "Use"); screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1), - _invMode == 3 ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND, + _invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND, false, "Give"); screen.gPrint(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1), _invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND, @@ -341,31 +306,49 @@ void Inventory::invCommands(bool slamIt) { } } -/** - * Set the highlighting color of a given inventory item - */ void Inventory::highlight(int index, byte color) { Screen &screen = *_vm->_screen; Surface &bb = *screen._backBuffer; int slot = index - _invIndex; - Graphics::Surface &img = (*_invShapes[slot])[0]._frame; + ImageFrame &frame = (*_invShapes[slot])[0]; bb.fillRect(Common::Rect(8 + slot * 52, 165, (slot + 1) * 52, 194), color); - bb.transBlitFrom(img, Common::Point(6 + slot * 52 + ((47 - img.w) / 2), - 163 + ((33 - img.h) / 2))); + bb.transBlitFrom(frame, Common::Point(6 + slot * 52 + ((47 - frame._width) / 2), + 163 + ((33 - frame._height) / 2))); screen.slamArea(8 + slot * 52, 165, 44, 30); } -/** - * Adds a shape from the scene to the player's inventory - */ +void Inventory::refreshInv() { + if (IS_ROSE_TATTOO) + return; + + Screen &screen = *_vm->_screen; + Talk &talk = *_vm->_talk; + ScalpelUserInterface &ui = *(ScalpelUserInterface *)_vm->_ui; + + ui._invLookFlag = true; + freeInv(); + + ui._infoFlag = true; + ui.clearInfo(); + + screen._backBuffer2.blitFrom(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)); + loadInv(); + } +} + int Inventory::putNameInInventory(const Common::String &name) { Scene &scene = *_vm->_scene; int matches = 0; for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) { Object &o = scene._bgShapes[idx]; - if (scumm_stricmp(name.c_str(), o._name.c_str()) == 0 && o._type != INVALID) { + if (name.equalsIgnoreCase(o._name) && o._type != INVALID) { putItemInInventory(o); ++matches; } @@ -374,10 +357,6 @@ int Inventory::putNameInInventory(const Common::String &name) { return matches; } -/** - * Moves a specified item into the player's inventory If the item has a *PICKUP* use action, - * then the item in the use action are added to the inventory. - */ int Inventory::putItemInInventory(Object &obj) { Scene &scene = *_vm->_scene; int matches = 0; @@ -386,14 +365,14 @@ int Inventory::putItemInInventory(Object &obj) { if (obj._pickupFlag) _vm->setFlags(obj._pickupFlag); - for (int useNum = 0; useNum < 4; ++useNum) { - if (scumm_stricmp(obj._use[useNum]._target.c_str(), "*PICKUP*") == 0) { + for (int useNum = 0; useNum < USE_COUNT; ++useNum) { + if (obj._use[useNum]._target.equalsIgnoreCase("*PICKUP*")) { pickupFound = true; - for (int namesNum = 0; namesNum < 4; ++namesNum) { + for (int namesNum = 0; namesNum < NAMES_COUNT; ++namesNum) { for (uint bgNum = 0; bgNum < scene._bgShapes.size(); ++bgNum) { Object &bgObj = scene._bgShapes[bgNum]; - if (scumm_stricmp(obj._use[useNum]._names[namesNum].c_str(), bgObj._name.c_str()) == 0) { + if (obj._use[useNum]._names[namesNum].equalsIgnoreCase(bgObj._name)) { copyToInventory(bgObj); if (bgObj._pickupFlag) _vm->setFlags(bgObj._pickupFlag); @@ -439,9 +418,6 @@ int Inventory::putItemInInventory(Object &obj) { return matches; } -/** - * Copy the passed object into the inventory - */ void Inventory::copyToInventory(Object &obj) { InventoryItem invItem; invItem._name = obj._name; @@ -454,14 +430,11 @@ void Inventory::copyToInventory(Object &obj) { ++_holdings; } -/** - * Deletes a specified item from the player's inventory - */ int Inventory::deleteItemFromInventory(const Common::String &name) { int invNum = -1; for (int idx = 0; idx < (int)size() && invNum == -1; ++idx) { - if (scumm_stricmp(name.c_str(), (*this)[idx]._name.c_str()) == 0) + if (name.equalsIgnoreCase((*this)[idx]._name)) invNum = idx; } @@ -476,9 +449,6 @@ int Inventory::deleteItemFromInventory(const Common::String &name) { return 1; } -/** - * Synchronize the data for a savegame - */ void Inventory::synchronize(Common::Serializer &s) { s.syncAsSint16LE(_holdings); diff --git a/engines/sherlock/inventory.h b/engines/sherlock/inventory.h index 5b9374d7a7..02f570f5da 100644 --- a/engines/sherlock/inventory.h +++ b/engines/sherlock/inventory.h @@ -47,6 +47,14 @@ enum InvMode { INVMODE_USE55 = 255 }; +enum InvNewMode { + PLAIN_INVENTORY = 0, LOOK_INVENTORY_MODE = 1, USE_INVENTORY_MODE = 2, + GIVE_INVENTORY_MODE = 3, INVENTORY_DONT_DISPLAY = 128 +}; + +enum InvSlamMode { SLAM_DONT_DISPLAY, SLAM_DISPLAY = 1, SLAM_SECONDARY_BUFFER }; + + struct InventoryItem { int _requiredFlag; Common::String _name; @@ -58,6 +66,9 @@ struct InventoryItem { InventoryItem(int requiredFlag, const Common::String &name, const Common::String &description, const Common::String &examine); + /** + * Synchronize the data for an inventory item + */ void synchronize(Common::Serializer &s); }; @@ -66,6 +77,9 @@ private: SherlockEngine *_vm; Common::StringArray _names; + /** + * Copy the passed object into the inventory + */ void copyToInventory(Object &obj); public: ImageFile *_invShapes[MAX_VISIBLE_INVENTORY]; @@ -74,32 +88,81 @@ public: int _invIndex; int _holdings; // Used to hold number of visible items in active inventory. // Since Inventory array also contains some special hidden items + /** + * Free any loaded inventory graphics + */ void freeGraphics(); public: Inventory(SherlockEngine *vm); ~Inventory(); + /** + * Free inventory data + */ void freeInv(); + /** + * Load the list of names the inventory items correspond to, if not already loaded, + * and then calls loadGraphics to load the associated graphics + */ void loadInv(); + /** + * Load the list of names of graphics for the inventory + */ void loadGraphics(); + /** + * Searches through the list of names that correspond to the inventory items + * and returns the number that matches the passed name + */ int findInv(const Common::String &name); - void putInv(int slamIt); + /** + * Display the character's inventory. The slamIt parameter specifies: + */ + void putInv(InvSlamMode slamIt); - void drawInventory(int flag); + /** + * Put the game into inventory mode and open the interface window. + */ + void drawInventory(InvNewMode flag); + /** + * Prints the line of inventory commands at the top of an inventory window with + * the correct highlighting + */ void invCommands(bool slamIt); + /** + * Set the highlighting color of a given inventory item + */ void highlight(int index, byte color); + /** + * Support method for refreshing the display of the inventory + */ + void refreshInv(); + + /** + * Adds a shape from the scene to the player's inventory + */ int putNameInInventory(const Common::String &name); + + /** + * Moves a specified item into the player's inventory If the item has a *PICKUP* use action, + * then the item in the use action are added to the inventory. + */ int putItemInInventory(Object &obj); + /** + * Deletes a specified item from the player's inventory + */ int deleteItemFromInventory(const Common::String &name); + /** + * Synchronize the data for a savegame + */ void synchronize(Common::Serializer &s); }; diff --git a/engines/sherlock/journal.cpp b/engines/sherlock/journal.cpp index 2a7aeb4f2d..564db59042 100644 --- a/engines/sherlock/journal.cpp +++ b/engines/sherlock/journal.cpp @@ -27,9 +27,13 @@ namespace Sherlock { #define JOURNAL_BUTTONS_Y 178 #define LINES_PER_PAGE 11 +#define JOURNAL_SEARCH_LEFT 15 +#define JOURNAL_SEARCH_TOP 186 +#define JOURNAL_SEARCH_RIGHT 296 +#define JOURNAL_SEACRH_MAX_CHARS 50 // Positioning of buttons in the journal view -const int JOURNAL_POINTS[9][3] = { +static const int JOURNAL_POINTS[9][3] = { { 6, 68, 37 }, { 69, 131, 100 }, { 132, 192, 162 }, @@ -41,7 +45,7 @@ const int JOURNAL_POINTS[9][3] = { { 237, 313, 275 } }; -const int SEARCH_POINTS[3][3] = { +static const int SEARCH_POINTS[3][3] = { { 51, 123, 86 }, { 124, 196, 159 }, { 197, 269, 232 } @@ -49,7 +53,7 @@ const int SEARCH_POINTS[3][3] = { /*----------------------------------------------------------------*/ -Journal::Journal(SherlockEngine *vm): _vm(vm) { +Journal::Journal(SherlockEngine *vm) : _vm(vm) { // Initialize fields _maxPage = 0; _index = 0; @@ -57,14 +61,12 @@ Journal::Journal(SherlockEngine *vm): _vm(vm) { _up = _down = false; _page = 1; - // Load the journal directory and location names - loadJournalLocations(); + if (_vm->_interactiveFl) { + // Load the journal directory and location names + loadJournalLocations(); + } } -/** - * Records statements that are said, in the order which they are said. The player - * can then read the journal to review them - */ void Journal::record(int converseNum, int statementNum, bool replyOnly) { int saveIndex = _index; int saveSub = _sub; @@ -90,9 +92,6 @@ void Journal::record(int converseNum, int statementNum, bool replyOnly) { } } -/** - * Load the list of location names that the journal will make reference to - */ void Journal::loadJournalLocations() { Resources &res = *_vm->_res; @@ -131,19 +130,16 @@ void Journal::loadJournalLocations() { delete loc; } -/** - * Loads the description for the current display index in the journal, and then - * word wraps the result to prepare it for being displayed - * @param alreadyLoaded Indicates whether the journal file is being loaded for the - * first time, or being reloaded - */ void Journal::loadJournalFile(bool alreadyLoaded) { + People &people = *_vm->_people; Screen &screen = *_vm->_screen; Talk &talk = *_vm->_talk; JournalEntry &journalEntry = _journal[_index]; Common::String dirFilename = _directory[journalEntry._converseNum]; bool replyOnly = journalEntry._replyOnly; + + // Get the location number from within the filename Common::String locStr(dirFilename.c_str() + 4, dirFilename.c_str() + 6); int newLocation = atoi(locStr.c_str()); @@ -156,8 +152,8 @@ void Journal::loadJournalFile(bool alreadyLoaded) { // Find the person being referred to talk._talkTo = -1; - for (int idx = 0; idx < MAX_PEOPLE; ++idx) { - Common::String portrait = PORTRAITS[idx]; + for (int idx = 0; idx < (int)people._characters.size(); ++idx) { + Common::String portrait = people[idx]._portrait; Common::String numStr(portrait.c_str(), portrait.c_str() + 4); if (locStr == numStr) { @@ -193,11 +189,11 @@ void Journal::loadJournalFile(bool alreadyLoaded) { // See if title can fit into a single line, or requires splitting on 2 lines int width = screen.stringWidth(journalString.c_str() + 1); - if (width > 230) { + if (width > JOURNAL_MAX_WIDTH) { // Scan backwards from end of title to find a space between a word // where the width is less than the maximum allowed for the line const char *lineP = journalString.c_str() + journalString.size() - 1; - while (width > 230 || *lineP != ' ') + while (width > JOURNAL_MAX_WIDTH || *lineP != ' ') width -= screen.charWidth(*lineP--); // Split the header into two lines, and add a '@' prefix @@ -227,7 +223,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) { journalString += "the Inspector"; break; default: - journalString += NAMES[talk._talkTo]; + journalString += people._characters[talk._talkTo]._name; break; } journalString += ", \""; @@ -247,8 +243,8 @@ void Journal::loadJournalFile(bool alreadyLoaded) { byte c = *replyP++; // Is it a control character? - if (c < 128) { - // Nope. Set flag for allowing control coes to insert spaces + if (c < SWITCH_SPEAKER) { + // Nope. Set flag for allowing control codes to insert spaces ctrlSpace = true; assert(c >= ' '); @@ -288,13 +284,13 @@ void Journal::loadJournalFile(bool alreadyLoaded) { else if (talk._talkTo == 2) journalString += "The Inspector"; else - journalString += NAMES[talk._talkTo]; + journalString += people._characters[talk._talkTo]._name; const byte *strP = replyP + 1; byte v; do { v = *strP++; - } while (v && (v < 128) && (v != '.') && (v != '!') && (v != '?')); + } while (v && (v < SWITCH_SPEAKER) && (v != '.') && (v != '!') && (v != '?')); if (v == '?') journalString += " asked, \""; @@ -310,11 +306,11 @@ void Journal::loadJournalFile(bool alreadyLoaded) { journalString += c; do { journalString += *replyP++; - } while (*replyP && *replyP < 128 && *replyP != '{' && *replyP != '}'); + } while (*replyP && *replyP < SWITCH_SPEAKER && *replyP != '{' && *replyP != '}'); commentJustPrinted = false; } - } else if (c == 128) { + } else if (c == SWITCH_SPEAKER) { if (!startOfReply) { if (!commentFlag && !commentJustPrinted) journalString += "\"\n"; @@ -335,13 +331,13 @@ void Journal::loadJournalFile(bool alreadyLoaded) { else if (c == 2) journalString += "the Inspector"; else - journalString += NAMES[c]; + journalString += people._characters[c]._name; const byte *strP = replyP; byte v; do { v = *strP++; - } while (v && v < 128 && v != '.' && v != '!' && v != '?'); + } while (v && v < SWITCH_SPEAKER && v != '.' && v != '!' && v != '?'); if (v == '?') journalString += " asked, \""; @@ -401,7 +397,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) { // Put a space in the output for a control character, unless it's // immediately coming after another control character - if (ctrlSpace && c != 130 && c != 161 && !commentJustPrinted) { + if (ctrlSpace && c != ASSIGN_PORTRAIT_LOCATION && c != CARRIAGE_RETURN && !commentJustPrinted) { journalString += " "; ctrlSpace = false; } @@ -427,11 +423,11 @@ void Journal::loadJournalFile(bool alreadyLoaded) { // Build up chacters until a full line is found int width = 0; const char *endP = startP; - while (width < 230 && *endP && *endP != '\n' && (endP - startP) < 79) + while (width < JOURNAL_MAX_WIDTH && *endP && *endP != '\n' && (endP - startP) < (JOURNAL_MAX_CHARS - 1)) width += screen.charWidth(*endP++); // If word wrapping, move back to end of prior word - if (width >= 230 || (endP - startP) >= 79) { + if (width >= JOURNAL_MAX_WIDTH || (endP - startP) >= (JOURNAL_MAX_CHARS - 1)) { while (*--endP != ' ') ; } @@ -451,9 +447,6 @@ void Journal::loadJournalFile(bool alreadyLoaded) { } } -/** - * Draw the journal background, frame, and interface buttons - */ void Journal::drawJournalFrame() { Resources &res = *_vm->_res; Screen &screen = *_vm->_screen; @@ -504,19 +497,16 @@ void Journal::drawJournalFrame() { screen.makeButton(Common::Rect(JOURNAL_POINTS[8][0], JOURNAL_BUTTONS_Y + 11, JOURNAL_POINTS[8][1], JOURNAL_BUTTONS_Y + 21), JOURNAL_POINTS[8][2] - screen.stringWidth("Print Text") / 2, "Print Text"); - screen.buttonPrint(Common::Point(JOURNAL_POINTS[8][2], JOURNAL_BUTTONS_Y + 11), + screen.buttonPrint(Common::Point(JOURNAL_POINTS[8][2], JOURNAL_BUTTONS_Y + 11), COMMAND_NULL, false, "Print Text"); } -/** - * Display the journal - */ void Journal::drawInterface() { Screen &screen = *_vm->_screen; drawJournalFrame(); - if (_journal.size() == 0) { + if (_journal.empty()) { _up = _down = 0; } else { drawJournal(0, 0); @@ -528,9 +518,6 @@ void Journal::drawInterface() { screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); } -/** - * Display the arrows that can be used to scroll up and down pages - */ void Journal::doArrows() { Screen &screen = *_vm->_screen; byte color; @@ -552,9 +539,6 @@ void Journal::doArrows() { screen.buttonPrint(Common::Point(JOURNAL_POINTS[6][2], JOURNAL_BUTTONS_Y + 11), color, false, "First Page"); } -/** - * Displays a page of the journal at the current index - */ bool Journal::drawJournal(int direction, int howFar) { Events &events = *_vm->_events; Screen &screen = *_vm->_screen; @@ -562,7 +546,7 @@ bool Journal::drawJournal(int direction, int howFar) { int yp = 37; int startPage = _page; bool endJournal = false; - bool firstOccurance = false; + bool firstOccurance = true; bool searchSuccessful = false; bool endFlag = false; int lineNum = 0; @@ -749,26 +733,26 @@ bool Journal::drawJournal(int direction, int howFar) { screen.gPrint(Common::Point(53, yp), 15, "%s", lineStart.c_str() + 1); } else { width = screen.stringWidth(lineStart.c_str()); - screen.gPrint(Common::Point(53, yp), PEN_COLOR, lineStart.c_str()); - } + screen.gPrint(Common::Point(53, yp), PEN_COLOR, "%s", lineStart.c_str()); + } // Print out the found keyword Common::String lineMatch(matchP, matchP + _find.size()); - screen.gPrint(Common::Point(53 + width, yp), INV_FOREGROUND, lineMatch.c_str()); + screen.gPrint(Common::Point(53 + width, yp), INV_FOREGROUND, "%s", lineMatch.c_str()); width += screen.stringWidth(lineMatch.c_str()); // Print remainder of line - screen.gPrint(Common::Point(53 + width, yp), PEN_COLOR, matchP + _find.size()); + screen.gPrint(Common::Point(53 + width, yp), PEN_COLOR, "%s", matchP + _find.size()); } else if (_lines[temp].hasPrefix("@")) { - screen.gPrint(Common::Point(53, yp), 15, _lines[temp].c_str() + 1); + screen.gPrint(Common::Point(53, yp), 15, "%s", _lines[temp].c_str() + 1); } else { - screen.gPrint(Common::Point(53, yp), PEN_COLOR, _lines[temp].c_str()); + screen.gPrint(Common::Point(53, yp), PEN_COLOR, "%s", _lines[temp].c_str()); } } else { if (_lines[temp].hasPrefix("@")) { - screen.gPrint(Common::Point(53, yp), 15, _lines[temp].c_str() + 1); + screen.gPrint(Common::Point(53, yp), 15, "%s", _lines[temp].c_str() + 1); } else { - screen.gPrint(Common::Point(53, yp), PEN_COLOR, _lines[temp].c_str()); + screen.gPrint(Common::Point(53, yp), PEN_COLOR, "%s", _lines[temp].c_str()); } } @@ -800,72 +784,90 @@ bool Journal::drawJournal(int direction, int howFar) { return direction >= 3 && searchSuccessful; } -/** - * Handle events whilst the journal is being displayed - */ +JournalButton Journal::getHighlightedButton(const Common::Point &pt) { + if (pt.x > JOURNAL_POINTS[0][0] && pt.x < JOURNAL_POINTS[0][1] && pt.y >= JOURNAL_BUTTONS_Y && + pt.y < (JOURNAL_BUTTONS_Y + 10)) + return BTN_EXIT; + + if (pt.x > JOURNAL_POINTS[1][0] && pt.x < JOURNAL_POINTS[1][1] && pt.y >= JOURNAL_BUTTONS_Y && + pt.y < (JOURNAL_BUTTONS_Y + 10) && _page > 1) + return BTN_BACK10; + + if (pt.x > JOURNAL_POINTS[2][0] && pt.x < JOURNAL_POINTS[2][1] && pt.y >= JOURNAL_BUTTONS_Y && + pt.y < (JOURNAL_BUTTONS_Y + 10) && _up) + return BTN_UP; + + if (pt.x > JOURNAL_POINTS[3][0] && pt.x < JOURNAL_POINTS[3][1] && pt.y >= JOURNAL_BUTTONS_Y && + pt.y < (JOURNAL_BUTTONS_Y + 10) && _down) + return BTN_DOWN; + + if (pt.x > JOURNAL_POINTS[4][0] && pt.x < JOURNAL_POINTS[4][1] && pt.y >= JOURNAL_BUTTONS_Y && + pt.y < (JOURNAL_BUTTONS_Y + 10) && _down) + return BTN_AHEAD110; + + if (pt.x > JOURNAL_POINTS[5][0] && pt.x < JOURNAL_POINTS[5][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) && + pt.y < (JOURNAL_BUTTONS_Y + 20) && !_journal.empty()) + return BTN_SEARCH; + + if (pt.x > JOURNAL_POINTS[6][0] && pt.x < JOURNAL_POINTS[6][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) && + pt.y < (JOURNAL_BUTTONS_Y + 20) && _up) + return BTN_FIRST_PAGE; + + if (pt.x > JOURNAL_POINTS[7][0] && pt.x < JOURNAL_POINTS[7][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) && + pt.y < (JOURNAL_BUTTONS_Y + 20) && _down) + return BTN_LAST_PAGE; + + if (pt.x > JOURNAL_POINTS[8][0] && pt.x < JOURNAL_POINTS[8][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) && + pt.y < (JOURNAL_BUTTONS_Y + 20) && !_journal.empty()) + return BTN_PRINT_TEXT; + + return BTN_NONE; +} + bool Journal::handleEvents(int key) { Events &events = *_vm->_events; Screen &screen = *_vm->_screen; bool doneFlag = false; + Common::Point pt = events.mousePos(); + JournalButton btn = getHighlightedButton(pt); byte color; - enum Button { - BTN_NONE, BTN_EXIT, BTN_BACK10, BTN_UP, BTN_DOWN, BTN_AHEAD110, BTN_SEARCH, - BTN_FIRST_PAGE, BTN_LAST_PAGE, BTN_PRINT_TEXT - }; - Button found = BTN_NONE; if (events._pressed || events._released) { // Exit button - if (pt.x > JOURNAL_POINTS[0][0] && pt.x < JOURNAL_POINTS[0][1] && pt.y >= JOURNAL_BUTTONS_Y && - pt.y < (JOURNAL_BUTTONS_Y + 10)) { - found = BTN_EXIT; - color = COMMAND_HIGHLIGHTED; - } else { - color = COMMAND_FOREGROUND; - } + color = (btn == BTN_EXIT) ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND; screen.buttonPrint(Common::Point(JOURNAL_POINTS[0][2], JOURNAL_BUTTONS_Y), color, true, "Exit"); // Back 10 button - if (pt.x > JOURNAL_POINTS[1][0] && pt.x < JOURNAL_POINTS[1][1] && pt.y >= JOURNAL_BUTTONS_Y && - pt.y < (JOURNAL_BUTTONS_Y + 10) && _page > 1) { - found = BTN_BACK10; + if (btn == BTN_BACK10) { screen.buttonPrint(Common::Point(JOURNAL_POINTS[1][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, "Back 10"); } else if (_page > 1) { screen.buttonPrint(Common::Point(JOURNAL_POINTS[1][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, "Back 10"); } // Up button - if (pt.x > JOURNAL_POINTS[2][0] && pt.x < JOURNAL_POINTS[2][1] && pt.y >= JOURNAL_BUTTONS_Y && - pt.y < (JOURNAL_BUTTONS_Y + 10) && _up) { - found = BTN_UP; + if (btn == BTN_UP) { screen.buttonPrint(Common::Point(JOURNAL_POINTS[2][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, "Up"); } else if (_up) { screen.buttonPrint(Common::Point(JOURNAL_POINTS[2][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, "Up"); } // Down button - if (pt.x > JOURNAL_POINTS[3][0] && pt.x < JOURNAL_POINTS[3][1] && pt.y >= JOURNAL_BUTTONS_Y && - pt.y < (JOURNAL_BUTTONS_Y + 10) && _down) { - found = BTN_DOWN; + if (btn == BTN_DOWN) { screen.buttonPrint(Common::Point(JOURNAL_POINTS[3][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, "Down"); } else if (_down) { screen.buttonPrint(Common::Point(JOURNAL_POINTS[3][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, "Down"); } // Ahead 10 button - if (pt.x > JOURNAL_POINTS[4][0] && pt.x < JOURNAL_POINTS[4][1] && pt.y >= JOURNAL_BUTTONS_Y && - pt.y < (JOURNAL_BUTTONS_Y + 10) && _down) { - found = BTN_AHEAD110; + if (btn == BTN_AHEAD110) { screen.buttonPrint(Common::Point(JOURNAL_POINTS[4][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, "Ahead 10"); } else if (_down) { screen.buttonPrint(Common::Point(JOURNAL_POINTS[4][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, "Ahead 10"); } // Search button - if (pt.x > JOURNAL_POINTS[5][0] && pt.x < JOURNAL_POINTS[5][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) && - pt.y < (JOURNAL_BUTTONS_Y + 20) && !_journal.empty()) { - found = BTN_SEARCH; + if (btn == BTN_SEARCH) { color = COMMAND_HIGHLIGHTED; } else if (_journal.empty()) { color = COMMAND_NULL; @@ -875,9 +877,7 @@ bool Journal::handleEvents(int key) { screen.buttonPrint(Common::Point(JOURNAL_POINTS[5][2], JOURNAL_BUTTONS_Y + 11), color, true, "Search"); // First Page button - if (pt.x > JOURNAL_POINTS[6][0] && pt.x < JOURNAL_POINTS[6][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) && - pt.y < (JOURNAL_BUTTONS_Y + 20) && _up) { - found = BTN_FIRST_PAGE; + if (btn == BTN_FIRST_PAGE) { color = COMMAND_HIGHLIGHTED; } else if (_up) { color = COMMAND_FOREGROUND; @@ -887,9 +887,7 @@ bool Journal::handleEvents(int key) { screen.buttonPrint(Common::Point(JOURNAL_POINTS[6][2], JOURNAL_BUTTONS_Y + 11), color, true, "First Page"); // Last Page button - if (pt.x > JOURNAL_POINTS[7][0] && pt.x < JOURNAL_POINTS[7][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) && - pt.y < (JOURNAL_BUTTONS_Y + 20) && _down) { - found = BTN_LAST_PAGE; + if (btn == BTN_LAST_PAGE) { color = COMMAND_HIGHLIGHTED; } else if (_down) { color = COMMAND_FOREGROUND; @@ -898,20 +896,15 @@ bool Journal::handleEvents(int key) { } screen.buttonPrint(Common::Point(JOURNAL_POINTS[7][2], JOURNAL_BUTTONS_Y + 11), color, true, "Last Page"); - // Print Text button - if (pt.x > JOURNAL_POINTS[8][0] && pt.x < JOURNAL_POINTS[8][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) && - pt.y < (JOURNAL_BUTTONS_Y + 20) && !_journal.empty()) { - found = BTN_PRINT_TEXT; - } screen.buttonPrint(Common::Point(JOURNAL_POINTS[8][2], JOURNAL_BUTTONS_Y + 11), COMMAND_NULL, true, "Print Text"); } - if (found == BTN_EXIT && events._released) + if (btn == BTN_EXIT && events._released) { // Exit button pressed doneFlag = true; - if (((found == BTN_BACK10 && events._released) || key == 'B') && (_page > 1)) { + } else if (((btn == BTN_BACK10 && events._released) || key == 'B') && (_page > 1)) { // Scrolll up 10 pages if (_page < 11) drawJournal(1, (_page - 1) * LINES_PER_PAGE); @@ -920,23 +913,20 @@ bool Journal::handleEvents(int key) { doArrows(); screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); - } - if (((found == BTN_UP && events._released) || key =='U') && _up) { + } else if (((btn == BTN_UP && events._released) || key == 'U') && _up) { // Scroll up drawJournal(1, LINES_PER_PAGE); doArrows(); screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); - } - if (((found == BTN_DOWN && events._released) || key =='D') && _down) { + } else if (((btn == BTN_DOWN && events._released) || key == 'D') && _down) { // Scroll down drawJournal(2, LINES_PER_PAGE); doArrows(); screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); - } - if (((found == BTN_AHEAD110 && events._released) || key == 'A') && _down) { + } else if (((btn == BTN_AHEAD110 && events._released) || key == 'A') && _down) { // Scroll down 10 pages if ((_page + 10) > _maxPage) drawJournal(2, (_maxPage - _page) * LINES_PER_PAGE); @@ -945,16 +935,14 @@ bool Journal::handleEvents(int key) { doArrows(); screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); - } - if (((found == BTN_SEARCH && events._released) || key == 'S') && !_journal.empty()) { + } else if (((btn == BTN_SEARCH && events._released) || key == 'S') && !_journal.empty()) { screen.buttonPrint(Common::Point(JOURNAL_POINTS[5][2], JOURNAL_BUTTONS_Y + 11), COMMAND_FOREGROUND, true, "Search"); bool notFound = false; - do { int dir; - if ((dir = getFindName(notFound)) != 0) { + if ((dir = getSearchString(notFound)) != 0) { int savedIndex = _index; int savedSub = _sub; int savedPage = _page; @@ -978,9 +966,8 @@ bool Journal::handleEvents(int key) { } } while (!doneFlag); doneFlag = false; - } - if (((found == BTN_FIRST_PAGE && events._released) || key == 'F') && _up) { + } else if (((btn == BTN_FIRST_PAGE && events._released) || key == 'F') && _up) { // First page _index = _sub = 0; _up = _down = false; @@ -990,9 +977,8 @@ bool Journal::handleEvents(int key) { drawJournal(0, 0); doArrows(); screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); - } - if (((found == BTN_LAST_PAGE && events._released) || key == 'L') && _down) { + } else if (((btn == BTN_LAST_PAGE && events._released) || key == 'L') && _down) { // Last page if ((_page + 10) > _maxPage) drawJournal(2, (_maxPage - _page) * LINES_PER_PAGE); @@ -1008,10 +994,7 @@ bool Journal::handleEvents(int key) { return doneFlag; } -/** - * Show the search submenu - */ -int Journal::getFindName(bool printError) { +int Journal::getSearchString(bool printError) { enum Button { BTN_NONE, BTN_EXIT, BTN_BACKWARD, BTN_FORWARD }; Events &events = *_vm->_events; @@ -1032,10 +1015,14 @@ int Journal::getFindName(bool printError) { SEARCH_POINTS[1][2] - screen.stringWidth("Backward") / 2, "Backward"); screen.makeButton(Common::Rect(SEARCH_POINTS[2][0], yp, SEARCH_POINTS[2][1], yp + 10), SEARCH_POINTS[2][2] - screen.stringWidth("Forward") / 2, "Forward"); + screen.gPrint(Common::Point(SEARCH_POINTS[0][2] - screen.stringWidth("Exit") / 2, yp), + COMMAND_FOREGROUND, "E"); + screen.gPrint(Common::Point(SEARCH_POINTS[1][2] - screen.stringWidth("Backward") / 2, yp), + COMMAND_FOREGROUND, "B"); + screen.gPrint(Common::Point(SEARCH_POINTS[2][2] - screen.stringWidth("Forward") / 2, yp), + COMMAND_FOREGROUND, "F"); - screen.gPrint(Common::Point(SEARCH_POINTS[0][2] - screen.stringWidth("Exit") / 2, yp), COMMAND_FOREGROUND, "E"); - screen.gPrint(Common::Point(SEARCH_POINTS[1][2] - screen.stringWidth("Backward") / 2, yp), COMMAND_FOREGROUND, "B"); - screen.gPrint(Common::Point(SEARCH_POINTS[2][2] - screen.stringWidth("Forward") / 2, yp), COMMAND_FOREGROUND, "F"); + screen.makeField(Common::Rect(12, 185, 307, 196)); screen.fillRect(Common::Rect(12, 185, 307, 186), BUTTON_BOTTOM); screen.vLine(12, 185, 195, BUTTON_BOTTOM); @@ -1047,7 +1034,7 @@ int Journal::getFindName(bool printError) { INV_FOREGROUND, "Text Not Found !"); } else if (!_find.empty()) { // There's already a search term, display it already - screen.gPrint(Common::Point(15, 185), TALK_FOREGROUND, _find.c_str()); + screen.gPrint(Common::Point(15, 185), TALK_FOREGROUND, "%s", _find.c_str()); name = _find; } @@ -1055,6 +1042,7 @@ int Journal::getFindName(bool printError) { if (printError) { // Give time for user to see the message + events.setButtonState(); for (int idx = 0; idx < 40 && !_vm->shouldQuit() && !events.kbHit() && !events._released; ++idx) { events.pollEvents(); events.setButtonState(); @@ -1062,18 +1050,18 @@ int Journal::getFindName(bool printError) { } events.clearKeyboard(); - screen.fillRect(Common::Rect(13, 186, 306, 195), BUTTON_MIDDLE); + screen._backBuffer1.fillRect(Common::Rect(13, 186, 306, 195), BUTTON_MIDDLE); if (!_find.empty()) { - screen.gPrint(Common::Point(15, 185), TALK_FOREGROUND, _find.c_str()); + screen.gPrint(Common::Point(15, 185), TALK_FOREGROUND, "%s", _find.c_str()); name = _find; } screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); } - xp = 15 + screen.stringWidth(name); - yp = 186; + xp = JOURNAL_SEARCH_LEFT + screen.stringWidth(name); + yp = JOURNAL_SEARCH_TOP; do { events._released = false; @@ -1128,23 +1116,21 @@ int Journal::getFindName(bool printError) { xp -= screen.charWidth(name.lastChar()); screen.vgaBar(Common::Rect(xp, yp, xp + 8, yp + 9), INV_FOREGROUND); name.deleteLastChar(); - } - if (keyState.keycode == Common::KEYCODE_RETURN) + } else if (keyState.keycode == Common::KEYCODE_RETURN) { done = 1; - if (keyState.keycode == Common::KEYCODE_ESCAPE) { + } else if (keyState.keycode == Common::KEYCODE_ESCAPE) { screen.vgaBar(Common::Rect(xp, yp, xp + 8, yp + 9), BUTTON_MIDDLE); done = -1; - } - if (keyState.keycode >= Common::KEYCODE_SPACE && keyState.keycode <= Common::KEYCODE_z - && keyState.keycode != Common::KEYCODE_AT && name.size() < 50 - && (xp + screen.charWidth(keyState.keycode)) < 296) { + } else if (keyState.ascii >= ' ' && keyState.ascii <= 'z' && keyState.keycode != Common::KEYCODE_AT && + name.size() < JOURNAL_SEACRH_MAX_CHARS && (xp + screen.charWidth(keyState.ascii)) < JOURNAL_SEARCH_RIGHT) { + char ch = toupper(keyState.ascii); screen.vgaBar(Common::Rect(xp, yp, xp + 8, yp + 9), BUTTON_MIDDLE); - screen.print(Common::Point(xp, yp), TALK_FOREGROUND, "%c", (char)keyState.keycode); - xp += screen.charWidth((char)keyState.keycode); - name += (char)keyState.keycode; + screen.print(Common::Point(xp, yp), TALK_FOREGROUND, "%c", ch); + xp += screen.charWidth(ch); + name += ch; } } @@ -1160,7 +1146,7 @@ int Journal::getFindName(bool printError) { break; } } - } while (!done); + } while (!done && !_vm->shouldQuit()); if (done != -1) { _find = name; @@ -1176,17 +1162,11 @@ int Journal::getFindName(bool printError) { return done; } -/** - * Reset viewing position to the start of the journal - */ void Journal::resetPosition() { _index = _sub = _up = _down = 0; _page = 1; } -/** - * Synchronize the data for a savegame - */ void Journal::synchronize(Common::Serializer &s) { s.syncAsSint16LE(_index); s.syncAsSint16LE(_sub); diff --git a/engines/sherlock/journal.h b/engines/sherlock/journal.h index be5c4d77c3..d62b8338c0 100644 --- a/engines/sherlock/journal.h +++ b/engines/sherlock/journal.h @@ -25,12 +25,22 @@ #include "common/scummsys.h" #include "common/array.h" +#include "common/rect.h" #include "common/serializer.h" #include "common/str-array.h" #include "common/stream.h" namespace Sherlock { +#define JOURNAL_MAX_WIDTH 230 +#define JOURNAL_MAX_CHARS 80 + +enum JournalButton { + BTN_NONE, BTN_EXIT, BTN_BACK10, BTN_UP, BTN_DOWN, BTN_AHEAD110, BTN_SEARCH, + BTN_FIRST_PAGE, BTN_LAST_PAGE, BTN_PRINT_TEXT +}; + + struct JournalEntry { int _converseNum; bool _replyOnly; @@ -57,28 +67,70 @@ private: int _page; Common::String _find; + /** + * Load the list of location names that the journal will make reference to + */ void loadJournalLocations(); + /** + * Loads the description for the current display index in the journal, and then + * word wraps the result to prepare it for being displayed + * @param alreadyLoaded Indicates whether the journal file is being loaded for the + * first time, or being reloaded + */ void loadJournalFile(bool alreadyLoaded); + /** + * Display the arrows that can be used to scroll up and down pages + */ void doArrows(); + /** + * Displays a page of the journal at the current index + */ bool drawJournal(int direction, int howFar); - int getFindName(bool printError); + /** + * Show the search submenu and allow the player to enter a search string + */ + int getSearchString(bool printError); + /** + * Draw the journal background, frame, and interface buttons + */ void drawJournalFrame(); + + /** + * Returns the button, if any, that is under the specified position + */ + JournalButton getHighlightedButton(const Common::Point &pt); public: Journal(SherlockEngine *vm); + /** + * Records statements that are said, in the order which they are said. The player + * can then read the journal to review them + */ void record(int converseNum, int statementNum, bool replyOnly = false); + /** + * Display the journal + */ void drawInterface(); + /** + * Handle events whilst the journal is being displayed + */ bool handleEvents(int key); + /** + * Reset viewing position to the start of the journal + */ void resetPosition(); + /** + * Synchronize the data for a savegame + */ void synchronize(Common::Serializer &s); }; diff --git a/engines/sherlock/map.cpp b/engines/sherlock/map.cpp index 46e233bf7a..44ca7cd44c 100644 --- a/engines/sherlock/map.cpp +++ b/engines/sherlock/map.cpp @@ -26,9 +26,10 @@ namespace Sherlock { -/** - * Load the data for the paths between locations on the map - */ +MapPaths::MapPaths() { + _numLocations = 0; +} + void MapPaths::load(int numLocations, Common::SeekableReadStream &s) { _numLocations = numLocations; _paths.resize(_numLocations * _numLocations); @@ -44,9 +45,6 @@ void MapPaths::load(int numLocations, Common::SeekableReadStream &s) { } } -/** - * Get the path between two locations on the map - */ const byte *MapPaths::getPath(int srcLocation, int destLocation) { return &_paths[srcLocation * _numLocations + destLocation][0]; } @@ -64,36 +62,27 @@ Map::Map(SherlockEngine *vm): _vm(vm), _topLine(g_system->getWidth(), 12) { _drawMap = false; _overPos = Common::Point(13000, 12600); _charPoint = 0; - _oldCharPoint = 39; + _oldCharPoint = 0; _frameChangeFlag = false; for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx) Common::fill(&_sequences[idx][0], &_sequences[idx][MAX_FRAME], 0); - if (!_vm->getIsDemo()) + if (!_vm->isDemo()) loadData(); } -/** - * Loads the list of points for locations on the map for each scene - */ void Map::loadPoints(int count, const int *xList, const int *yList, const int *transList) { for (int idx = 0; idx < count; ++idx, ++xList, ++yList, ++transList) { _points.push_back(MapEntry(*xList, *yList, *transList)); } } -/** - * Load the sequence data for player icon animations - */ void Map::loadSequences(int count, const byte *seq) { for (int idx = 0; idx < count; ++idx, seq += MAX_FRAME) Common::copy(seq, seq + MAX_FRAME, &_sequences[idx][0]); } -/** - * Load data needed for the map - */ void Map::loadData() { // TODO: Remove this if (_vm->getGameID() == GType_RoseTattoo) @@ -131,9 +120,6 @@ void Map::loadData() { delete pathStream; } -/** - * Show the map - */ int Map::show() { Events &events = *_vm->_events; People &people = *_vm->_people; @@ -252,7 +238,7 @@ int Map::show() { // Show wait cursor _cursorIndex = 1; - events.setCursor((*_mapCursors)[_cursorIndex]); + events.setCursor((*_mapCursors)[_cursorIndex]._frame); } } @@ -285,19 +271,15 @@ int Map::show() { return _charPoint; } -/** - * Load and initialize all the sprites that are needed for the map display - */ void Map::setupSprites() { Events &events = *_vm->_events; People &people = *_vm->_people; Scene &scene = *_vm->_scene; - typedef byte Sequences[16][MAX_FRAME]; _savedPos.x = -1; _mapCursors = new ImageFile("omouse.vgs"); _cursorIndex = 0; - events.setCursor((*_mapCursors)[_cursorIndex]); + events.setCursor((*_mapCursors)[_cursorIndex]._frame); _shapes = new ImageFile("mapicon.vgs"); _iconShapes = new ImageFile("overicon.vgs"); @@ -325,9 +307,6 @@ void Map::setupSprites() { scene._bgShapes.clear(); } -/** - * Free the sprites and data used by the map - */ void Map::freeSprites() { delete _mapCursors; delete _shapes; @@ -335,9 +314,6 @@ void Map::freeSprites() { _iconSave.free(); } -/** - * Draws an icon for every place that's currently known - */ void Map::showPlaces() { Screen &screen = *_vm->_screen; @@ -356,25 +332,16 @@ void Map::showPlaces() { } } -/** - * Makes a copy of the top rows of the screen that are used to display location names - */ void Map::saveTopLine() { _topLine.blitFrom(_vm->_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, 12)); } -/** - * Erases anything shown in the top line by restoring the previously saved original map background - */ void Map::eraseTopLine() { Screen &screen = *_vm->_screen; screen._backBuffer1.blitFrom(_topLine, Common::Point(0, 0)); - screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, _topLine.h); + screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, _topLine.h()); } -/** - * Prints the name of the specified icon - */ void Map::showPlaceName(int idx, bool highlighted) { People &people = *_vm->_people; Screen &screen = *_vm->_screen; @@ -387,22 +354,19 @@ void Map::showPlaceName(int idx, bool highlighted) { bool flipped = people[AL]._sequenceNumber == MAP_DOWNLEFT || people[AL]._sequenceNumber == MAP_LEFT || people[AL]._sequenceNumber == MAP_UPLEFT; - screen._backBuffer1.transBlitFrom(people[AL]._imageFrame->_frame, _lDrawnPos, flipped); + screen._backBuffer1.transBlitFrom(*people[AL]._imageFrame, _lDrawnPos, flipped); } if (highlighted) { int xp = (SHERLOCK_SCREEN_WIDTH - screen.stringWidth(name)) / 2; - screen.gPrint(Common::Point(xp + 2, 2), 0, name.c_str()); - screen.gPrint(Common::Point(xp + 1, 1), 0, name.c_str()); - screen.gPrint(Common::Point(xp, 0), 12, name.c_str()); + screen.gPrint(Common::Point(xp + 2, 2), 0, "%s", name.c_str()); + screen.gPrint(Common::Point(xp + 1, 1), 0, "%s", name.c_str()); + screen.gPrint(Common::Point(xp, 0), 12, "%s", name.c_str()); screen.slamArea(xp, 0, width + 2, 15); } } -/** - * Update all on-screen sprites to account for any scrolling of the map - */ void Map::updateMap(bool flushScreen) { Events &events = *_vm->_events; People &people = *_vm->_people; @@ -415,7 +379,7 @@ void Map::updateMap(bool flushScreen) { if (++_cursorIndex > (1 + 8)) _cursorIndex = 1; - events.setCursor((*_mapCursors)[(_cursorIndex + 1) / 2]); + events.setCursor((*_mapCursors)[(_cursorIndex + 1) / 2]._frame); } if (!_drawMap && !flushScreen) @@ -432,9 +396,9 @@ void Map::updateMap(bool flushScreen) { saveIcon(people[AL]._imageFrame, hPos); if (people[AL]._sequenceNumber == MAP_DOWNLEFT || people[AL]._sequenceNumber == MAP_LEFT || people[AL]._sequenceNumber == MAP_UPLEFT) - screen._backBuffer1.transBlitFrom(people[AL]._imageFrame->_frame, hPos, true); + screen._backBuffer1.transBlitFrom(*people[AL]._imageFrame, hPos, true); else - screen._backBuffer1.transBlitFrom(people[AL]._imageFrame->_frame, hPos, false); + screen._backBuffer1.transBlitFrom(*people[AL]._imageFrame, hPos, false); if (flushScreen) { screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); @@ -449,9 +413,6 @@ void Map::updateMap(bool flushScreen) { } } -/** - * Handle moving icon for player from their previous location on the map to a destination location - */ void Map::walkTheStreets() { People &people = *_vm->_people; Common::Array<Common::Point> tempPath; @@ -510,9 +471,6 @@ void Map::walkTheStreets() { people._walkTo.push(destPos); } -/** - * Save the area under the player's icon - */ void Map::saveIcon(ImageFrame *src, const Common::Point &pt) { Screen &screen = *_vm->_screen; Common::Point size(src->_width, src->_height); @@ -540,16 +498,13 @@ void Map::saveIcon(ImageFrame *src, const Common::Point &pt) { return; } - assert(size.x <= _iconSave.w && size.y <= _iconSave.h); + assert(size.x <= _iconSave.w() && size.y <= _iconSave.h()); _iconSave.blitFrom(screen._backBuffer1, Common::Point(0, 0), Common::Rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y)); _savedPos = pos; _savedSize = size; } -/** - * Restore the area under the player's icon - */ void Map::restoreIcon() { Screen &screen = *_vm->_screen; @@ -558,9 +513,6 @@ void Map::restoreIcon() { screen._backBuffer1.blitFrom(_iconSave, _savedPos, Common::Rect(0, 0, _savedSize.x, _savedSize.y)); } -/** - * Handles highlighting map icons, showing their names - */ void Map::highlightIcon(const Common::Point &pt) { int oldPoint = _point; @@ -599,9 +551,6 @@ void Map::highlightIcon(const Common::Point &pt) { } } -/** -* Synchronize the data for a savegame -*/ void Map::synchronize(Common::Serializer &s) { s.syncAsSint16LE(_bigPos.x); s.syncAsSint16LE(_bigPos.y); diff --git a/engines/sherlock/map.h b/engines/sherlock/map.h index 4a418138b2..ab70b0885f 100644 --- a/engines/sherlock/map.h +++ b/engines/sherlock/map.h @@ -48,9 +48,18 @@ class MapPaths { private: int _numLocations; Common::Array< Common::Array<byte> > _paths; + public: + MapPaths(); + + /** + * Load the data for the paths between locations on the map + */ void load(int numLocations, Common::SeekableReadStream &s); + /** + * Get the path between two locations on the map + */ const byte *getPath(int srcLocation, int destLocation); }; @@ -75,24 +84,64 @@ private: bool _drawMap; Surface _iconSave; private: + /** + * Load data needed for the map + */ void loadData(); + /** + * Load and initialize all the sprites that are needed for the map display + */ void setupSprites(); + + /** + * Free the sprites and data used by the map + */ void freeSprites(); + /** + * Draws an icon for every place that's currently known + */ void showPlaces(); + /** + * Makes a copy of the top rows of the screen that are used to display location names + */ void saveTopLine(); + + /** + * Erases anything shown in the top line by restoring the previously saved original map background + */ void eraseTopLine(); + + /** + * Prints the name of the specified icon + */ void showPlaceName(int idx, bool highlighted); + /** + * Update all on-screen sprites to account for any scrolling of the map + */ void updateMap(bool flushScreen); + /** + * Handle moving icon for player from their previous location on the map to a destination location + */ void walkTheStreets(); + /** + * Save the area under the player's icon + */ void saveIcon(ImageFrame *src, const Common::Point &pt); + + /** + * Restore the area under the player's icon + */ void restoreIcon(); + /** + * Handles highlighting map icons, showing their names + */ void highlightIcon(const Common::Point &pt); public: bool _active; @@ -105,11 +154,24 @@ public: const MapEntry &operator[](int idx) { return _points[idx]; } + /** + * Loads the list of points for locations on the map for each scene + */ void loadPoints(int count, const int *xList, const int *yList, const int *transList); + + /** + * Load the sequence data for player icon animations + */ void loadSequences(int count, const byte *seq); + /** + * Show the map + */ int show(); + /** + * Synchronize the data for a savegame + */ void synchronize(Common::Serializer &s); }; diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp index 2576ff04d6..f3803518ee 100644 --- a/engines/sherlock/objects.cpp +++ b/engines/sherlock/objects.cpp @@ -41,9 +41,6 @@ namespace Sherlock { SherlockEngine *Sprite::_vm; -/** - * Reset the data for the sprite - */ void Sprite::clear() { _name = ""; _description = ""; @@ -68,18 +65,12 @@ void Sprite::clear() { _numFrames = 0; } -/** - * Updates the image frame poiner for the sprite - */ void Sprite::setImageFrame() { int imageNumber = (*_sequences)[_sequenceNumber][_frameNumber] + (*_sequences)[_sequenceNumber][0] - 2; _imageFrame = &(*_images)[imageNumber]; } -/** - * This adjusts the sprites position, as well as it's animation sequence: - */ void Sprite::adjustSprite() { Map &map = *_vm->_map; People &people = *_vm->_people; @@ -175,9 +166,6 @@ void Sprite::adjustSprite() { } } -/** - * Checks the sprite's position to see if it's collided with any special objects - */ void Sprite::checkSprite() { Events &events = *_vm->_events; People &people = *_vm->_people; @@ -364,9 +352,6 @@ void Sprite::checkSprite() { /*----------------------------------------------------------------*/ -/** - * Load the data for the action - */ void ActionType::load(Common::SeekableReadStream &s) { char buffer[12]; @@ -375,7 +360,7 @@ void ActionType::load(Common::SeekableReadStream &s) { if (_cAnimSpeed & 0x80) _cAnimSpeed = -(_cAnimSpeed & 0x7f); - for (int idx = 0; idx < 4; ++idx) { + for (int idx = 0; idx < NAMES_COUNT; ++idx) { s.read(buffer, 12); _names[idx] = Common::String(buffer); } @@ -386,13 +371,8 @@ void ActionType::load(Common::SeekableReadStream &s) { UseType::UseType() { _cAnimNum = _cAnimSpeed = 0; _useFlag = 0; - _dFlag[0] = 0; - _lFlag[0] = _lFlag[1] = 0; } -/** - * Load the data for the UseType - */ void UseType::load(Common::SeekableReadStream &s, bool isRoseTattoo) { char buffer[12]; @@ -406,18 +386,15 @@ void UseType::load(Common::SeekableReadStream &s, bool isRoseTattoo) { if (_cAnimSpeed & 0x80) _cAnimSpeed = -(_cAnimSpeed & 0x7f); - for (int idx = 0; idx < 4; ++idx) { + for (int idx = 0; idx < NAMES_COUNT; ++idx) { s.read(buffer, 12); _names[idx] = Common::String(buffer); } _useFlag = s.readSint16LE(); - if (!isRoseTattoo) { - _dFlag[0] = s.readSint16LE(); - _lFlag[0] = s.readSint16LE(); - _lFlag[1] = s.readSint16LE(); - } + if (!isRoseTattoo) + s.skip(6); s.read(buffer, 12); _target = Common::String(buffer); @@ -473,9 +450,6 @@ Object::Object() { _restoreSlot = 0; } -/** - * Load the data for the object - */ void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) { char buffer[41]; s.read(buffer, 12); @@ -560,9 +534,6 @@ void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) { } } -/** - * Toggle the type of an object between hidden and active - */ void Object::toggleHidden() { if (_type != HIDDEN && _type != HIDE_SHAPE && _type != INVALID) { if (_seqTo != 0) @@ -598,13 +569,10 @@ void Object::toggleHidden() { } } -/** - * Check the state of the object - */ void Object::checkObject() { Scene &scene = *_vm->_scene; Sound &sound = *_vm->_sound; - int checkFrame = _allow ? MAX_FRAME : 32000; + int checkFrame = _allow ? MAX_FRAME : FRAMES_END; bool codeFound; if (_seqTo) { @@ -640,7 +608,7 @@ void Object::checkObject() { _seqCounter2 = _seqCounter; _seqStack = _frameNumber + 1; setObjSequence(v, false); - } else if (v >= SOUND_CODE && (v <= (SOUND_CODE + 29))) { + } else if (v >= SOUND_CODE && (v < (SOUND_CODE + 30))) { codeFound = true; ++_frameNumber; v -= SOUND_CODE; @@ -649,7 +617,7 @@ void Object::checkObject() { if (!scene._sounds[v - 1]._name.empty() && sound._digitized) sound.playLoadedSound(v - 1, WAIT_RETURN_IMMEDIATELY); } - } else if (v >= FLIP_CODE && v <= (FLIP_CODE + 2)) { + } else if (v >= FLIP_CODE && v < (FLIP_CODE + 3)) { // Flip code codeFound = true; ++_frameNumber; @@ -659,15 +627,15 @@ void Object::checkObject() { switch (v) { case 0: // Clear the flag - _flags &= ~2; + _flags &= ~OBJ_FLIPPED; break; case 1: // Set the flag - _flags |= 2; + _flags |= OBJ_FLIPPED; break; case 2: // Toggle the flag - _flags ^= 2; + _flags ^= OBJ_FLIPPED; break; default: break; @@ -709,8 +677,8 @@ void Object::checkObject() { _delta = pt; _frameNumber += 2; - } else if (v < 4) { - for (int idx = 0; idx < 4; ++idx) { + } else if (v < USE_COUNT) { + for (int idx = 0; idx < NAMES_COUNT; ++idx) { checkNameForCodes(_use[v]._names[idx], nullptr); } @@ -724,14 +692,9 @@ void Object::checkObject() { } while (codeFound); } -/** - * This will check to see if the object has reached the end of a sequence. - * If it has, it switch to whichever next sequence should be started. - * @returns true if the end of a sequence was reached - */ bool Object::checkEndOfSequence() { Screen &screen = *_vm->_screen; - int checkFrame = _allow ? MAX_FRAME : 32000; + int checkFrame = _allow ? MAX_FRAME : FRAMES_END; bool result = false; if (_type == REMOVE || _type == INVALID) @@ -781,13 +744,9 @@ bool Object::checkEndOfSequence() { return result; } -/** - * Scans through the sequences array and finds the designated sequence. - * It then sets the frame number of the start of that sequence - */ void Object::setObjSequence(int seq, bool wait) { Scene &scene = *_vm->_scene; - int checkFrame = _allow ? MAX_FRAME : 32000; + int checkFrame = _allow ? MAX_FRAME : FRAMES_END; if (seq >= 128) { // Loop the sequence until the count exceeded @@ -858,12 +817,6 @@ void Object::setObjSequence(int seq, bool wait) { } } -/** - * Checks for codes - * @param name The name to check for codes - * @param messages Provides a lookup list of messages that can be printed - * @returns 0 if no codes are found, 1 if codes were found - */ int Object::checkNameForCodes(const Common::String &name, const char *const messages[]) { Map &map = *_vm->_map; People &people = *_vm->_people; @@ -945,13 +898,13 @@ int Object::checkNameForCodes(const Common::String &name, const char *const mess int messageNum = atoi(name.c_str() + 1); ui._infoFlag = true; ui.clearInfo(); - screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, messages[messageNum]); + screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", messages[messageNum]); ui._menuCounter = 25; } else if (name.hasPrefix("@")) { // Message attached to canimation ui._infoFlag = true; ui.clearInfo(); - screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, name.c_str() + 1); + screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", name.c_str() + 1); printed = true; ui._menuCounter = 25; } @@ -959,14 +912,11 @@ int Object::checkNameForCodes(const Common::String &name, const char *const mess return printed; } -/** - * Handle setting any flags associated with the object - */ void Object::setFlagsAndToggles() { Scene &scene = *_vm->_scene; Talk &talk = *_vm->_talk; - for (int useIdx = 0; useIdx < 4; ++useIdx) { + for (int useIdx = 0; useIdx < USE_COUNT; ++useIdx) { if (_use[useIdx]._useFlag) { if (!_vm->readFlags(_use[useIdx]._useFlag)) _vm->setFlags(_use[useIdx]._useFlag); @@ -981,16 +931,12 @@ void Object::setFlagsAndToggles() { } if (!talk._talkToAbort) { - for (int idx = 0; idx < 4; ++idx) + for (int idx = 0; idx < NAMES_COUNT; ++idx) scene.toggleObject(_use[useIdx]._names[idx]); } } } -/** - * Adjusts the sprite's position and animation sequence, advancing by 1 frame. - * If the end of the sequence is reached, the appropriate action is taken. - */ void Object::adjustObject() { if (_type == REMOVE) return; @@ -1013,10 +959,6 @@ void Object::adjustObject() { } } -/** - * Handles trying to pick up an object. If allowed, plays an y necessary animation for picking - * up the item, and then adds it to the player's inventory - */ int Object::pickUpObject(const char *const messages[]) { Inventory &inv = *_vm->_inventory; People &people = *_vm->_people; @@ -1029,7 +971,7 @@ int Object::pickUpObject(const char *const messages[]) { int numObjects = 0; if (pickup == 99) { - for (int idx = 0; idx < 4 && !talk._talkToAbort; ++idx) { + for (int idx = 0; idx < NAMES_COUNT && !talk._talkToAbort; ++idx) { if (checkNameForCodes(_use[0]._names[idx], nullptr)) { if (!talk._talkToAbort) printed = true; @@ -1046,7 +988,7 @@ int Object::pickUpObject(const char *const messages[]) { ui._infoFlag = true; ui.clearInfo(); - screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, messages[message]); + screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", messages[message]); ui._menuCounter = 30; } else { // Pick it up @@ -1076,7 +1018,7 @@ int Object::pickUpObject(const char *const messages[]) { ui._temp1 = 1; } - for (int idx = 0; idx < 4 && !talk._talkToAbort; ++idx) { + for (int idx = 0; idx < NAMES_COUNT && !talk._talkToAbort; ++idx) { if (checkNameForCodes(_use[0]._names[idx], nullptr)) { if (!talk._talkToAbort) printed = true; @@ -1103,9 +1045,6 @@ int Object::pickUpObject(const char *const messages[]) { return numObjects; } -/** - * Returns the current bounds for the sprite - */ const Common::Rect Object::getNewBounds() const { Common::Point pt = _position; if (_imageFrame) @@ -1114,17 +1053,11 @@ const Common::Rect Object::getNewBounds() const { return Common::Rect(pt.x, pt.y, pt.x + frameWidth(), pt.y + frameHeight()); } -/** - * Returns the bounds for a sprite without a shape - */ const Common::Rect Object::getNoShapeBounds() const { return Common::Rect(_position.x, _position.y, _position.x + _noShapeSize.x, _position.y + _noShapeSize.y); } -/** - * Returns the old bounsd for the sprite from the previous frame - */ const Common::Rect Object::getOldBounds() const { return Common::Rect(_oldPosition.x, _oldPosition.y, _oldPosition.x + _oldSize.x, _oldPosition.y + _oldSize.y); @@ -1132,9 +1065,6 @@ const Common::Rect Object::getOldBounds() const { /*----------------------------------------------------------------*/ -/** - * Load the data for the animation - */ void CAnim::load(Common::SeekableReadStream &s, bool isRoseTattoo) { char buffer[12]; s.read(buffer, 12); diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h index fd4a103a8d..b61e7e24fe 100644 --- a/engines/sherlock/objects.h +++ b/engines/sherlock/objects.h @@ -102,8 +102,8 @@ class Sprite { private: static SherlockEngine *_vm; public: - Common::String _name; // Name - Common::String _description; // Description + Common::String _name; + Common::String _description; Common::StringArray _examine; // Examine in-depth description Common::String _pickUp; // Message for if you can't pick up object @@ -120,7 +120,6 @@ public: Common::Point _oldSize; // Image's old size Common::Point _goto; // Walk destination SpriteType _type; // Type of object - int _pickup; Common::Point _noShapeSize; // Size of a NO_SHAPE int _status; // Status: open/closed, moved/not moved int8 _misc; // Miscellaneous use @@ -129,48 +128,85 @@ public: Sprite() { clear(); } static void setVm(SherlockEngine *vm) { _vm = vm; } + /** + * Reset the data for the sprite + */ void clear(); + /** + * Updates the image frame poiner for the sprite + */ void setImageFrame(); + /** + * This adjusts the sprites position, as well as it's animation sequence: + */ void adjustSprite(); + /** + * Checks the sprite's position to see if it's collided with any special objects + */ void checkSprite(); + /** + * Return frame width + */ int frameWidth() const { return _imageFrame ? _imageFrame->_frame.w : 0; } + + /** + * Return frame height + */ int frameHeight() const { return _imageFrame ? _imageFrame->_frame.h : 0; } }; enum { REVERSE_DIRECTION = 0x80 }; +#define NAMES_COUNT 4 struct ActionType { int _cAnimNum; int _cAnimSpeed; - Common::String _names[4]; + Common::String _names[NAMES_COUNT]; + /** + * Load the data for the action + */ void load(Common::SeekableReadStream &s); }; struct UseType { int _cAnimNum; int _cAnimSpeed; - Common::String _names[4]; + Common::String _names[NAMES_COUNT]; int _useFlag; // Which flag USE will set (if any) - int _dFlag[1]; - int _lFlag[2]; Common::String _target; Common::String _verb; UseType(); + + /** + * Load the data for the UseType + */ void load(Common::SeekableReadStream &s, bool isRoseTattoo); }; +enum { OBJ_BEHIND = 1, OBJ_FLIPPED = 2, OBJ_FORWARD = 4, TURNON_OBJ = 0x20, TURNOFF_OBJ = 0x40 }; +#define USE_COUNT 4 + class Object { private: static SherlockEngine *_vm; + /** + * This will check to see if the object has reached the end of a sequence. + * If it has, it switch to whichever next sequence should be started. + * @returns true if the end of a sequence was reached + */ bool checkEndOfSequence(); + /** + * Scans through the sequences array and finds the designated sequence. + * It then sets the frame number of the start of that sequence + */ void setObjSequence(int seq, bool wait); public: static bool _countCAnimFrames; @@ -233,24 +269,69 @@ public: Object(); + /** + * Load the data for the object + */ void load(Common::SeekableReadStream &s, bool isRoseTattoo); + /** + * Toggle the type of an object between hidden and active + */ void toggleHidden(); + /** + * Check the state of the object + */ void checkObject(); + /** + * Checks for codes + * @param name The name to check for codes + * @param messages Provides a lookup list of messages that can be printed + * @returns 0 if no codes are found, 1 if codes were found + */ int checkNameForCodes(const Common::String &name, const char *const messages[]); + /** + * Handle setting any flags associated with the object + */ void setFlagsAndToggles(); + /** + * Adjusts the sprite's position and animation sequence, advancing by 1 frame. + * If the end of the sequence is reached, the appropriate action is taken. + */ void adjustObject(); + /** + * Handles trying to pick up an object. If allowed, plays an y necessary animation for picking + * up the item, and then adds it to the player's inventory + */ int pickUpObject(const char *const messages[]); + /** + * Return the frame width + */ int frameWidth() const { return _imageFrame ? _imageFrame->_frame.w : 0; } + + /** + * Return the frame height + */ int frameHeight() const { return _imageFrame ? _imageFrame->_frame.h : 0; } + + /** + * Returns the current bounds for the sprite + */ const Common::Rect getNewBounds() const; + + /** + * Returns the bounds for a sprite without a shape + */ const Common::Rect getNoShapeBounds() const; + + /** + * Returns the old bounsd for the sprite from the previous frame + */ const Common::Rect getOldBounds() const; }; @@ -271,6 +352,9 @@ struct CAnim { // Rose Tattoo specific int _scaleVal; // How much the canim is scaled + /** + * Load the data for the animation + */ void load(Common::SeekableReadStream &s, bool isRoseTattoo); }; diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp index 0eda40c03f..3a630fdd99 100644 --- a/engines/sherlock/people.cpp +++ b/engines/sherlock/people.cpp @@ -50,144 +50,6 @@ static const uint8 CHARACTER_SEQUENCES[MAX_HOLMES_SEQUENCE][MAX_FRAME] = { { 52, 1, 2, 3, 4, 0 } // Goto Stand Down Left }; -const char PORTRAITS[MAX_PEOPLE][5] = { - { "HOLM" }, // Sherlock Holmes - { "WATS" }, // Dr. Watson - { "LEST" }, // Inspector Lestrade - { "CON1" }, // Constable O'Brien - { "CON2" }, // Constable Lewis - { "SHEI" }, // Sheila Parker - { "HENR" }, // Henry Carruthers - { "LESL" }, // Lesley (flower girl) - { "USH1" }, // Usher #1 - { "USH2" }, // Usher #2 - { "FRED" }, // Fredrick Epstein - { "WORT" }, // Mrs. Worthington - { "COAC" }, // Coach - { "PLAY" }, // Player - { "WBOY" }, // Tim (Waterboy) - { "JAME" }, // James Sanders - { "BELL" }, // Belle (perfumerie) - { "GIRL" }, // Cleaning Girl (perfumerie) - { "EPST" }, // Epstien in the Opera Balcony - { "WIGG" }, // Wiggins - { "PAUL" }, // Paul (Brumwell / Carroway) - { "BART" }, // Bartender - { "DIRT" }, // Dirty Drunk - { "SHOU" }, // Shouting Drunk - { "STAG" }, // Staggering Drunk - { "BOUN" }, // Bouncer - { "SAND" }, // James Sanders - At Home - { "CORO" }, // The Coroner - { "EQUE" }, // The Equestrian Shop Keeper - { "GEOR" }, // George Blackwood - { "LARS" }, // Lars - { "PARK" }, // Sheila Parker (happy) - { "CHEM" }, // Chemist - { "GREG" }, // Inspector Gregson - { "LAWY" }, // Jacob Farthington Lawyer - { "MYCR" }, // Mycroft - { "SHER" }, // Old Sherman - { "CHMB" }, // Richard Chemist Stock boy - { "BARM" }, // Barman - { "DAND" }, // Dandy Player - { "ROUG" }, // Rough-looking Player - { "SPEC" }, // Spectator - { "HUNT" }, // Robert Hunt - { "VIOL" }, // Violet Secretary - { "PETT" }, // Pettigrew - { "APPL" }, // Augie (apple seller) - { "ANNA" }, // Anna Carroway - { "GUAR" }, // Guard - { "ANTO" }, // Antonio Caruso - { "TOBY" }, // Toby the Dog - { "KING" }, // Simon Kingsley - { "ALFR" }, // Alfred Tobacco Clerk - { "LADY" }, // Lady Brumwell - { "ROSA" }, // Madame Rosa - { "LADB" }, // Lady Brumwell - { "MOOR" }, // Joseph Moorehead - { "BEAL" }, // Mrs. Beale - { "LION" }, // Felix the Lion - { "HOLL" }, // Hollingston - { "CALL" }, // Constable Callaghan - { "JERE" }, // Sergeant Jeremy Duncan - { "LORD" }, // Lord Brumwell - { "NIGE" }, // Nigel Jameson - { "JONA" }, // Jonas (newspaper seller) - { "DUGA" }, // Constable Dugan - { "INSP" } // Inspector Lestrade (Scotland Yard) -}; - -const char *const NAMES[MAX_PEOPLE] = { - "Sherlock Holmes", - "Dr. Watson", - "Inspector Lestrade", - "Constable O'Brien", - "Constable Lewis", - "Sheila Parker", - "Henry Carruthers", - "Lesley", - "An Usher", - "An Usher", - "Fredrick Epstein", - "Mrs. Worthington", - "The Coach", - "A Player", - "Tim", - "James Sanders", - "Belle", - "Cleaning Girl", - "Fredrick Epstein", - "Wiggins", - "Paul", - "The Bartender", - "A Dirty Drunk", - "A Shouting Drunk", - "A Staggering Drunk", - "The Bouncer", - "James Sanders", - "The Coroner", - "Reginald Snipes", - "George Blackwood", - "Lars", - "Sheila Parker", - "The Chemist", - "Inspector Gregson", - "Jacob Farthington", - "Mycroft", - "Old Sherman", - "Richard", - "The Barman", - "A Dandy Player", - "A Rough-looking Player", - "A Spectator", - "Robert Hunt", - "Violet", - "Pettigrew", - "Augie", - "Anna Carroway", - "A Guard", - "Antonio Caruso", - "Toby the Dog", - "Simon Kingsley", - "Alfred", - "Lady Brumwell", - "Madame Rosa", - "Lady Brumwell", - "Joseph Moorehead", - "Mrs. Beale", - "Felix", - "Hollingston", - "Constable Callaghan", - "Sergeant Duncan", - "Lord Brumwell", - "Nigel Jaimeson", - "Jonas", - "Constable Dugan", - "Inspector Lestrade" -}; - /*----------------------------------------------------------------*/ People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) { @@ -217,11 +79,8 @@ People::~People() { delete[] _portrait._sequences; } -/** - * Reset the player data - */ void People::reset() { - // Note: The engine has theoretical support for two player charactersm but only the first one is used. + // Note: The engine has theoretical support for two player characters but only the first one is used. // Watson is, instead, handled by a different sprite in each scene, with a very simple initial movement, if any Sprite &p = _data[PLAYER]; @@ -247,9 +106,6 @@ void People::reset() { _walkTo.clear(); } -/** - * Load the walking images for Sherlock - */ bool People::loadWalk() { if (_walkLoaded) { return false; @@ -262,9 +118,6 @@ bool People::loadWalk() { } } -/** - * If the walk data has been loaded, then it will be freed - */ bool People::freeWalk() { if (_walkLoaded) { delete _player._images; @@ -277,11 +130,6 @@ bool People::freeWalk() { } } -/** - * Set the variables for moving a character from one poisition to another - * in a straight line - goAllTheWay must have been previously called to - * check for any obstacles in the path. - */ void People::setWalking() { Map &map = *_vm->_map; Scene &scene = *_vm->_scene; @@ -427,10 +275,6 @@ void People::setWalking() { _player._frameNumber = oldFrame; } -/** - * Bring a moving character to a standing position. If the Scalpel chessboard - * is being displayed, then the chraracter will always face down. - */ void People::gotoStand(Sprite &sprite) { Map &map = *_vm->_map; _walkTo.clear(); @@ -481,9 +325,6 @@ void People::gotoStand(Sprite &sprite) { _allowWalkAbort = true; } -/** - * Walk to the co-ordinates passed, and then face the given direction - */ void People::walkToCoords(const Common::Point &destPos, int destDir) { Events &events = *_vm->_events; Scene &scene = *_vm->_scene; @@ -516,11 +357,6 @@ void People::walkToCoords(const Common::Point &destPos, int destDir) { } } -/** - * Called to set the character walking to the current cursor location. - * It uses the zones and the inter-zone points to determine a series - * of steps to walk to get to that position. - */ void People::goAllTheWay() { Scene &scene = *_vm->_scene; Common::Point srcPt(_player._position.x / 100 + _player.frameWidth() / 2, @@ -608,9 +444,6 @@ void People::goAllTheWay() { } } -/** - * Finds the scene background object corresponding to a specified speaker - */ int People::findSpeaker(int speaker) { Scene &scene = *_vm->_scene; @@ -620,7 +453,7 @@ int People::findSpeaker(int speaker) { if (obj._type == ACTIVE_BG_SHAPE) { Common::String name(obj._name.c_str(), obj._name.c_str() + 4); - if (scumm_stricmp(PORTRAITS[speaker], name.c_str()) == 0 + if (name.equalsIgnoreCase(_characters[speaker]._portrait) && obj._name[4] >= '0' && obj._name[4] <= '9') return idx; } @@ -629,9 +462,6 @@ int People::findSpeaker(int speaker) { return -1; } -/** - * Turn off any currently active portraits, and removes them from being drawn - */ void People::clearTalking() { Scene &scene = *_vm->_scene; Screen &screen = *_vm->_screen; @@ -662,9 +492,6 @@ void People::clearTalking() { } } -/** - * Setup the data for an animating speaker portrait at the top of the screen - */ void People::setTalking(int speaker) { Resources &res = *_vm->_res; @@ -674,7 +501,7 @@ void People::setTalking(int speaker) { if (_portraitsOn) { delete _talkPics; - Common::String filename = Common::String::format("%s.vgs", PORTRAITS[speaker]); + Common::String filename = Common::String::format("%s.vgs", _characters[speaker]._portrait); _talkPics = new ImageFile(filename); // Load portrait sequences @@ -724,9 +551,6 @@ void People::setTalking(int speaker) { } } -/** - * Synchronize the data for a savegame - */ void People::synchronize(Common::Serializer &s) { s.syncAsByte(_holmesOn); s.syncAsSint16LE(_player._position.x); diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h index f98c3db867..8244fd9b59 100644 --- a/engines/sherlock/people.h +++ b/engines/sherlock/people.h @@ -30,13 +30,13 @@ namespace Sherlock { -// People definitions +// Player definitions. The game has theoretical support for two player characters but only the first one is used. +// Watson is, instead, handled by a different sprite in each scene, with a very simple initial movement, if any enum PeopleId { PLAYER = 0, AL = 0, PEG = 1, - NUM_OF_PEOPLE = 2, // Holmes and Watson - MAX_PEOPLE = 66 // Total of all NPCs + MAX_PLAYERS = 2 }; // Animation sequence identifiers for characters @@ -53,12 +53,19 @@ enum { MAP_DOWN = 5, MAP_DOWNLEFT = 6, MAP_LEFT = 2, MAP_UPLEFT = 8 }; -extern const char *const NAMES[MAX_PEOPLE]; -extern const char PORTRAITS[MAX_PEOPLE][5]; +struct PersonData { + const char *_name; + const char *_portrait; + const byte *_stillSequences; + const byte *_talkSequences; + + PersonData(const char *name, const char *portrait, const byte *stillSequences, const byte *talkSequences) : + _name(name), _portrait(portrait), _stillSequences(stillSequences), _talkSequences(talkSequences) {} +}; class SherlockEngine; -class Person: public Sprite { +class Person : public Sprite { public: Person() : Sprite() {} @@ -68,11 +75,12 @@ public: class People { private: SherlockEngine *_vm; - Person _data[NUM_OF_PEOPLE]; + Person _data[MAX_PLAYERS]; bool _walkLoaded; int _oldWalkSequence; int _srcZone, _destZone; public: + Common::Array<PersonData> _characters; ImageFile *_talkPics; Common::Point _walkDest; Common::Point _hSavedPos; @@ -94,35 +102,77 @@ public: ~People(); Person &operator[](PeopleId id) { - assert(id < NUM_OF_PEOPLE); + assert(id < MAX_PLAYERS); return _data[id]; } Person &operator[](int idx) { - assert(idx < NUM_OF_PEOPLE); + assert(idx < MAX_PLAYERS); return _data[idx]; } + /** + * Returns true if Sherlock is visible on the screen and enabled + */ bool isHolmesActive() const { return _walkLoaded && _holmesOn; } + /** + * Reset the player data + */ void reset(); + /** + * Load the walking images for Sherlock + */ bool loadWalk(); + /** + * If the walk data has been loaded, then it will be freed + */ bool freeWalk(); + /** + * Set the variables for moving a character from one poisition to another + * in a straight line - goAllTheWay must have been previously called to + * check for any obstacles in the path. + */ void setWalking(); + /** + * Bring a moving character to a standing position. If the Scalpel chessboard + * is being displayed, then the chraracter will always face down. + */ void gotoStand(Sprite &sprite); + /** + * Walk to the co-ordinates passed, and then face the given direction + */ void walkToCoords(const Common::Point &destPos, int destDir); + /** + * Called to set the character walking to the current cursor location. + * It uses the zones and the inter-zone points to determine a series + * of steps to walk to get to that position. + */ void goAllTheWay(); + /** + * Finds the scene background object corresponding to a specified speaker + */ int findSpeaker(int speaker); + /** + * Turn off any currently active portraits, and removes them from being drawn + */ void clearTalking(); + + /** + * Setup the data for an animating speaker portrait at the top of the screen + */ void setTalking(int speaker); + /** + * Synchronize the data for a savegame + */ void synchronize(Common::Serializer &s); }; diff --git a/engines/sherlock/resources.cpp b/engines/sherlock/resources.cpp index 24fef3f235..864622e74b 100644 --- a/engines/sherlock/resources.cpp +++ b/engines/sherlock/resources.cpp @@ -28,21 +28,13 @@ namespace Sherlock { -Cache::Cache(SherlockEngine *vm): _vm(vm) { +Cache::Cache(SherlockEngine *vm) : _vm(vm) { } -/** - * Returns true if a given file is currently being cached - */ bool Cache::isCached(const Common::String &filename) const { return _resources.contains(filename); } -/** - * Loads a file into the cache if it's not already present, and returns it. - * If the file is LZW compressed, automatically decompresses it and loads - * the uncompressed version into memory - */ void Cache::load(const Common::String &name) { // First check if the entry already exists if (_resources.contains(name)) @@ -58,9 +50,6 @@ void Cache::load(const Common::String &name) { f.close(); } -/** - * Load a cache entry based on a passed stream - */ void Cache::load(const Common::String &name, Common::SeekableReadStream &stream) { // First check if the entry already exists if (_resources.contains(name)) @@ -88,9 +77,6 @@ void Cache::load(const Common::String &name, Common::SeekableReadStream &stream) } } -/** - * Get a file from the cache - */ Common::SeekableReadStream *Cache::get(const Common::String &filename) const { // Return a memory stream that encapsulates the data const CacheEntry &cacheEntry = _resources[filename]; @@ -99,18 +85,18 @@ Common::SeekableReadStream *Cache::get(const Common::String &filename) const { /*----------------------------------------------------------------*/ -Resources::Resources(SherlockEngine *vm): _vm(vm), _cache(vm) { +Resources::Resources(SherlockEngine *vm) : _vm(vm), _cache(vm) { _resourceIndex = -1; - addToCache("vgs.lib"); - addToCache("talk.lib"); - addToCache("journal.txt"); + if (_vm->_interactiveFl) { + addToCache("vgs.lib"); + addToCache("talk.lib"); + addToCache("sequence.txt"); + addToCache("journal.txt"); + addToCache("portrait.lib"); + } } -/** - * Adds the specified file to the cache. If it's a library file, takes care of - * loading it's index for future use - */ void Resources::addToCache(const Common::String &filename) { _cache.load(filename); @@ -126,9 +112,6 @@ void Resources::addToCache(const Common::String &filename) { delete stream; } -/** - * Adds a resource from a library file to the cache - */ void Resources::addToCache(const Common::String &filename, const Common::String &libFilename) { // Get the resource Common::SeekableReadStream *stream = load(filename, libFilename); @@ -138,16 +121,10 @@ void Resources::addToCache(const Common::String &filename, const Common::String delete stream; } -/** - * Adds a given stream to the cache under the given name - */ void Resources::addToCache(const Common::String &filename, Common::SeekableReadStream &stream) { _cache.load(filename, stream); } -/** - * Returns a stream for a given file - */ Common::SeekableReadStream *Resources::load(const Common::String &filename) { // First check if the file is directly in the cache if (_cache.isCached(filename)) @@ -155,30 +132,19 @@ Common::SeekableReadStream *Resources::load(const Common::String &filename) { // Secondly, iterate through any loaded library file looking for a resource // that has the same name - LibraryIndexes::iterator i; - for (i = _indexes.begin(); i != _indexes.end(); ++i) { - if ((*i)._value.contains(filename)) { + for (LibraryIndexes::iterator i = _indexes.begin(); i != _indexes.end(); ++i) { + if (i->_value.contains(filename)) { // Get a stream reference to the given library file - Common::SeekableReadStream *stream = load((*i)._key); - LibraryEntry &entry = (*i)._value[filename]; + Common::SeekableReadStream *stream = load(i->_key); + LibraryEntry &entry = i->_value[filename]; _resourceIndex = entry._index; stream->seek(entry._offset); Common::SeekableReadStream *resStream = stream->readStream(entry._size); + decompressIfNecessary(resStream); - // Check whether the file is compressed - if (resStream->readUint32BE() == MKTAG('L', 'Z', 'V', 26)) { - resStream->seek(0); - // It's compressed, so decompress the sub-file and return it - Common::SeekableReadStream *decompressed = decompress(*resStream); - delete stream; - delete resStream; - return decompressed; - } else { - resStream->seek(0); - delete stream; - return resStream; - } + delete stream; + return resStream; } } @@ -189,13 +155,24 @@ Common::SeekableReadStream *Resources::load(const Common::String &filename) { Common::SeekableReadStream *stream = f.readStream(f.size()); f.close(); + decompressIfNecessary(stream); return stream; } -/** - * Loads a specific resource from a given library file - */ +void Resources::decompressIfNecessary(Common::SeekableReadStream *&stream) { + bool isCompressed = stream->readUint32BE() == MKTAG('L', 'Z', 'V', 26); + + if (isCompressed) { + int outSize = stream->readUint32LE(); + Common::SeekableReadStream *newStream = decompressLZ(*stream, outSize); + delete stream; + stream = newStream; + } else { + stream->seek(-4, SEEK_CUR); + } +} + Common::SeekableReadStream *Resources::load(const Common::String &filename, const Common::String &libraryFile) { // Open up the library for access Common::SeekableReadStream *libStream = load(libraryFile); @@ -208,22 +185,17 @@ Common::SeekableReadStream *Resources::load(const Common::String &filename, cons LibraryEntry &entry = _indexes[libraryFile][filename]; libStream->seek(entry._offset); Common::SeekableReadStream *stream = libStream->readStream(entry._size); + decompressIfNecessary(stream); delete libStream; return stream; } -/** - * Returns true if the given file exists on disk or in the cache - */ bool Resources::exists(const Common::String &filename) const { Common::File f; return f.exists(filename) || _cache.isCached(filename); } -/** - * Reads in the index from a library file, and caches it's index for later use - */ void Resources::loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream, bool isNewStyle) { uint32 offset, nextOffset; @@ -263,15 +235,84 @@ void Resources::loadLibraryIndex(const Common::String &libFilename, } } -/** - * Returns the index of the last loaded resource in it's given library file. - * This will be used primarily when loading talk files, so the engine can - * update the given conversation number in the journal - */ int Resources::resourceIndex() const { return _resourceIndex; } +Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source) { + // This variation can't be used by Rose Tattoo, since compressed resources include the input size, + // not the output size. Which means their decompression has to be done via passed buffers + assert(_vm->getGameID() == GType_SerratedScalpel); + + uint32 id = source.readUint32BE(); + assert(id == MKTAG('L', 'Z', 'V', 0x1A)); + + uint32 outputSize = source.readUint32LE(); + return decompressLZ(source, outputSize); +} + +Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source, uint32 outSize) { + int inSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readUint32LE() : -1; + byte *outBuffer = (byte *)malloc(outSize); + Common::MemoryReadStream *outStream = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES); + + decompressLZ(source, outBuffer, outSize, inSize); + + return outStream; +} + +void Resources::decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize) { + int inputSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readUint32LE() : -1; + + decompressLZ(source, buffer, outSize, inputSize); +} + +Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &source, uint32 outSize) { + byte *dataOut = (byte *)malloc(outSize); + decompressLZ(source, dataOut, outSize, -1); + + return new Common::MemoryReadStream(dataOut, outSize, DisposeAfterUse::YES); +} + +void Resources::decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize) { + byte lzWindow[4096]; + uint16 lzWindowPos; + uint16 cmd; + + byte *outBufferEnd = outBuffer + outSize; + int endPos = source.pos() + inSize; + + memset(lzWindow, 0xFF, 0xFEE); + lzWindowPos = 0xFEE; + cmd = 0; + + do { + cmd >>= 1; + if (!(cmd & 0x100)) + cmd = source.readByte() | 0xFF00; + + if (cmd & 1) { + byte literal = source.readByte(); + *outBuffer++ = literal; + lzWindow[lzWindowPos] = literal; + lzWindowPos = (lzWindowPos + 1) & 0x0FFF; + } else { + int copyPos, copyLen; + copyPos = source.readByte(); + copyLen = source.readByte(); + copyPos = copyPos | ((copyLen & 0xF0) << 4); + copyLen = (copyLen & 0x0F) + 3; + while (copyLen--) { + byte literal = lzWindow[copyPos]; + copyPos = (copyPos + 1) & 0x0FFF; + *outBuffer++ = literal; + lzWindow[lzWindowPos] = literal; + lzWindowPos = (lzWindowPos + 1) & 0x0FFF; + } + } + } while ((outSize == -1 || outBuffer < outBufferEnd) || (inSize == -1 || source.pos() < endPos)); +} + /*----------------------------------------------------------------*/ SherlockEngine *ImageFile::_vm; @@ -299,9 +340,6 @@ ImageFile::~ImageFile() { (*this)[idx]._frame.free(); } -/** - * Load the data of the sprite - */ void ImageFile::load(Common::SeekableReadStream &stream, bool skipPalette, bool animImages) { loadPalette(stream); @@ -348,9 +386,6 @@ void ImageFile::load(Common::SeekableReadStream &stream, bool skipPalette, bool } } -/** - * Gets the palette at the start of the sprite file - */ void ImageFile::loadPalette(Common::SeekableReadStream &stream) { // Check for palette int v1 = stream.readUint16LE() + 1; @@ -370,9 +405,6 @@ void ImageFile::loadPalette(Common::SeekableReadStream &stream) { } } -/** - * Decompress a single frame for the sprite - */ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) { frame._frame.create(frame._width, frame._height, Graphics::PixelFormat::createFormatCLUT8()); @@ -431,90 +463,4 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) { } } -/** - * Decompress an LZW compressed resource - */ -Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source) { - // This variation can't be used by Rose Tattoo, since compressed resources include the input size, - // not the output size. Which means their decompression has to be done via passed buffers - assert(_vm->getGameID() == GType_SerratedScalpel); - - uint32 id = source.readUint32BE(); - assert(id == MKTAG('L', 'Z', 'V', 0x1A)); - - uint32 outputSize = source.readUint32LE(); - return decompressLZ(source, outputSize); -} - -/** - * Decompress an LZW compressed resource - */ -Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source, uint32 outSize) { - int inSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readUint32LE() : -1; - byte *outBuffer = (byte *)malloc(outSize); - Common::MemoryReadStream *outStream = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES); - - decompressLZ(source, outBuffer, outSize, inSize); - - return outStream; -} - -/** - * Decompress an LZW compressed resource - */ -void Resources::decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize) { - int inputSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readUint32LE() : -1; - - decompressLZ(source, buffer, outSize, inputSize); -} - -/** - * Decompresses an LZW block of data with a specified output size - */ -Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &source, uint32 outSize) { - byte *outBuffer = (byte *)malloc(outSize); - Common::MemoryReadStream *outStream = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES); - - decompressLZ(source, outBuffer, outSize, -1); - return outStream; -} - -void Resources::decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize) { - byte lzWindow[4096]; - uint16 lzWindowPos; - uint16 cmd; - byte *outBufferEnd = outBuffer + outSize; - int32 endPos = source.pos() + inSize; - - memset(lzWindow, 0xFF, 0xFEE); - lzWindowPos = 0xFEE; - cmd = 0; - - do { - cmd >>= 1; - if (!(cmd & 0x100)) - cmd = source.readByte() | 0xFF00; - - if (cmd & 1) { - byte literal = source.readByte(); - *outBuffer++ = literal; - lzWindow[lzWindowPos] = literal; - lzWindowPos = (lzWindowPos + 1) & 0x0FFF; - } else { - int copyPos, copyLen; - copyPos = source.readByte(); - copyLen = source.readByte(); - copyPos = copyPos | ((copyLen & 0xF0) << 4); - copyLen = (copyLen & 0x0F) + 3; - while (copyLen--) { - byte literal = lzWindow[copyPos]; - copyPos = (copyPos + 1) & 0x0FFF; - *outBuffer++ = literal; - lzWindow[lzWindowPos] = literal; - lzWindowPos = (lzWindowPos + 1) & 0x0FFF; - } - } - } while ((!outSize || outBuffer < outBufferEnd) && (!inSize || source.pos() < endPos)); -} - } // End of namespace Sherlock diff --git a/engines/sherlock/resources.h b/engines/sherlock/resources.h index a3208520ea..659ecf0110 100644 --- a/engines/sherlock/resources.h +++ b/engines/sherlock/resources.h @@ -57,11 +57,26 @@ private: public: Cache(SherlockEngine *_vm); + /** + * Returns true if a given file is currently being cached + */ bool isCached(const Common::String &filename) const; + /** + * Loads a file into the cache if it's not already present, and returns it. + * If the file is LZW compressed, automatically decompresses it and loads + * the uncompressed version into memory + */ void load(const Common::String &name); + + /** + * Load a cache entry based on a passed stream + */ void load(const Common::String &name, Common::SeekableReadStream &stream); + /** + * Get a file from the cache + */ Common::SeekableReadStream *get(const Common::String &filename) const; }; @@ -72,29 +87,82 @@ private: LibraryIndexes _indexes; int _resourceIndex; - void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream, - bool isNewStyle); + /** + * Reads in the index from a library file, and caches it's index for later use + */ + void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream, bool isNewStyle); public: Resources(SherlockEngine *vm); + /** + * Adds the specified file to the cache. If it's a library file, takes care of + * loading it's index for future use + */ void addToCache(const Common::String &filename); + + /** + * Adds a resource from a library file to the cache + */ void addToCache(const Common::String &filename, const Common::String &libFilename); + + /** + * Adds a given stream to the cache under the given name + */ void addToCache(const Common::String &filename, Common::SeekableReadStream &stream); + bool isInCache(const Common::String &filename) const { return _cache.isCached(filename); } + /** + * Checks the passed stream, and if is compressed, deletes it and replaces it with it's uncompressed data + */ + void decompressIfNecessary(Common::SeekableReadStream *&stream); + + /** + * Returns a stream for a given file + */ Common::SeekableReadStream *load(const Common::String &filename); + /** + * Loads a specific resource from a given library file + */ Common::SeekableReadStream *load(const Common::String &filename, const Common::String &libraryFile); + /** + * Returns true if the given file exists on disk or in the cache + */ bool exists(const Common::String &filename) const; + /** + * Returns the index of the last loaded resource in it's given library file. + * This will be used primarily when loading talk files, so the engine can + * update the given conversation number in the journal + */ int resourceIndex() const; + /** + * Decompresses LZW compressed data + */ Common::SeekableReadStream *decompress(Common::SeekableReadStream &source); + + /** + * Decompresses LZW compressed data + */ Common::SeekableReadStream *decompress(Common::SeekableReadStream &source, uint32 outSize); + + /** + * Decompresses LZW compressed data + */ void decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize); - static void decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize); + + /** + * Decompresses LZW compressed data + */ static Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source, uint32 outSize); + + /** + * Decompresses LZW compressed data + */ + static void decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize); }; struct ImageFrame { @@ -105,16 +173,25 @@ struct ImageFrame { Common::Point _offset; byte _rleMarker; Graphics::Surface _frame; - - operator Graphics::Surface &() { return _frame; } }; class ImageFile : public Common::Array<ImageFrame> { private: static SherlockEngine *_vm; + /** + * Load the data of the sprite + */ void load(Common::SeekableReadStream &stream, bool skipPalette, bool animImages); + + /** + * Gets the palette at the start of the sprite file + */ void loadPalette(Common::SeekableReadStream &stream); + + /** + * Decompress a single frame for the sprite + */ void decompressFrame(ImageFrame &frame, const byte *src); public: byte _palette[256 * 3]; diff --git a/engines/sherlock/saveload.cpp b/engines/sherlock/saveload.cpp index b9ac3e79d6..ddf4917a34 100644 --- a/engines/sherlock/saveload.cpp +++ b/engines/sherlock/saveload.cpp @@ -38,6 +38,10 @@ const int ENV_POINTS[6][3] = { { 241, 280, 261 } // Quit }; +static const char *const EMPTY_SAVEGAME_SLOT = "-EMPTY-"; +static const char *const SAVEGAME_STR = "SHLK"; +#define SAVEGAME_STR_SIZE 4 + /*----------------------------------------------------------------*/ SaveManager::SaveManager(SherlockEngine *vm, const Common::String &target) : @@ -55,9 +59,6 @@ SaveManager::~SaveManager() { } } -/** - * Shows the in-game dialog interface for loading and saving games - */ void SaveManager::drawInterface() { Screen &screen = *_vm->_screen; UserInterface &ui = *_vm->_ui; @@ -87,18 +88,17 @@ void SaveManager::drawInterface() { if (!_savegameIndex) screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), COMMAND_NULL, 0, "Up"); - if (_savegameIndex == MAX_SAVEGAME_SLOTS - 5) + if (_savegameIndex == MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT) screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), COMMAND_NULL, 0, "Down"); - for (int idx = _savegameIndex; idx < _savegameIndex + 5; ++idx) - { + for (int idx = _savegameIndex; idx < _savegameIndex + ONSCREEN_FILES_COUNT; ++idx) { screen.gPrint(Common::Point(6, CONTROLS_Y + 11 + (idx - _savegameIndex) * 10), INV_FOREGROUND, "%d.", idx + 1); screen.gPrint(Common::Point(24, CONTROLS_Y + 11 + (idx - _savegameIndex) * 10), INV_FOREGROUND, "%s", _savegames[idx].c_str()); } - if (!ui._windowStyle) { + if (!ui._slideWindows) { screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); } else { ui.summonWindow(); @@ -107,15 +107,12 @@ void SaveManager::drawInterface() { _envMode = SAVEMODE_NONE; } -/** - * Build up a savegame list, with empty slots given an explicit Empty message - */ void SaveManager::createSavegameList() { Screen &screen = *_vm->_screen; _savegames.clear(); for (int idx = 0; idx < MAX_SAVEGAME_SLOTS; ++idx) - _savegames.push_back("-EMPTY-"); + _savegames.push_back(EMPTY_SAVEGAME_SLOT); SaveStateList saveList = getSavegameList(_target); for (uint idx = 0; idx < saveList.size(); ++idx) { @@ -137,9 +134,6 @@ void SaveManager::createSavegameList() { } } -/** - * Load a list of savegames - */ SaveStateList SaveManager::getSavegameList(const Common::String &target) { Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); Common::StringArray filenames; @@ -172,12 +166,6 @@ SaveStateList SaveManager::getSavegameList(const Common::String &target) { return saveList; } -const char *const SAVEGAME_STR = "SHLK"; -#define SAVEGAME_STR_SIZE 4 - -/** - * Read in the header information for a savegame - */ bool SaveManager::readSavegameHeader(Common::InSaveFile *in, SherlockSavegameHeader &header) { char saveIdentBuffer[SAVEGAME_STR_SIZE + 1]; header._thumbnail = nullptr; @@ -212,9 +200,6 @@ bool SaveManager::readSavegameHeader(Common::InSaveFile *in, SherlockSavegameHea return true; } -/** - * Write out the header information for a savegame - */ void SaveManager::writeSavegameHeader(Common::OutSaveFile *out, SherlockSavegameHeader &header) { // Write out a savegame header out->write(SAVEGAME_STR, SAVEGAME_STR_SIZE + 1); @@ -245,9 +230,6 @@ void SaveManager::writeSavegameHeader(Common::OutSaveFile *out, SherlockSavegame out->writeUint32LE(_vm->_events->getFrameCounter()); } -/** - * Creates a thumbnail for the current on-screen contents - */ void SaveManager::createThumbnail() { if (_saveThumb) { _saveThumb->free(); @@ -260,9 +242,6 @@ void SaveManager::createThumbnail() { ::createThumbnail(_saveThumb, (const byte *)_vm->_screen->getPixels(), SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT, thumbPalette); } -/** - * Return the index of the button the mouse is over, if any - */ int SaveManager::getHighlightedButton() const { Common::Point pt = _vm->_events->mousePos(); @@ -275,21 +254,18 @@ int SaveManager::getHighlightedButton() const { return -1; } -/** - * Handle highlighting buttons - */ void SaveManager::highlightButtons(int btnIndex) { Screen &screen = *_vm->_screen; byte color = (btnIndex == 0) ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND; screen.buttonPrint(Common::Point(ENV_POINTS[0][2], CONTROLS_Y), color, 1, "Exit"); - if ((btnIndex == 1) || ((_envMode == 1) && (btnIndex != 2))) + if ((btnIndex == 1) || ((_envMode == SAVEMODE_LOAD) && (btnIndex != 2))) screen.buttonPrint(Common::Point(ENV_POINTS[1][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Load"); else screen.buttonPrint(Common::Point(ENV_POINTS[1][2], CONTROLS_Y), COMMAND_FOREGROUND, true, "Load"); - if ((btnIndex == 2) || ((_envMode == 2) && (btnIndex != 1))) + if ((btnIndex == 2) || ((_envMode == SAVEMODE_SAVE) && (btnIndex != 1))) screen.buttonPrint(Common::Point(ENV_POINTS[2][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Save"); else screen.buttonPrint(Common::Point(ENV_POINTS[2][2], CONTROLS_Y), COMMAND_FOREGROUND, true, "Save"); @@ -309,9 +285,6 @@ void SaveManager::highlightButtons(int btnIndex) { screen.buttonPrint(Common::Point(ENV_POINTS[5][2], CONTROLS_Y), color, 1, "Quit"); } -/** - * Load the game in the specified slot - */ void SaveManager::loadGame(int slot) { Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading( generateSaveName(slot)); @@ -335,9 +308,6 @@ void SaveManager::loadGame(int slot) { delete saveFile; } -/** - * Save the game in the specified slot with the given name - */ void SaveManager::saveGame(int slot, const Common::String &name) { Common::OutSaveFile *out = g_system->getSavefileManager()->openForSaving( generateSaveName(slot)); @@ -354,17 +324,10 @@ void SaveManager::saveGame(int slot, const Common::String &name) { delete out; } -/** - * Support method that generates a savegame name - * @param slot Slot number - */ Common::String SaveManager::generateSaveName(int slot) { return Common::String::format("%s.%03d", _target.c_str(), slot); } -/** - * Synchronize the data for a savegame - */ void SaveManager::synchronize(Common::Serializer &s) { Inventory &inv = *_vm->_inventory; Journal &journal = *_vm->_journal; @@ -391,14 +354,11 @@ void SaveManager::synchronize(Common::Serializer &s) { _justLoaded = true; } -/** - * Make sure that the selected savegame is on-screen - */ bool SaveManager::checkGameOnScreen(int slot) { Screen &screen = *_vm->_screen; // Check if it's already on-screen - if (slot != -1 && (slot < _savegameIndex || slot >= (_savegameIndex + 5))) { + if (slot != -1 && (slot < _savegameIndex || slot >= (_savegameIndex + ONSCREEN_FILES_COUNT))) { _savegameIndex = slot; screen._backBuffer1.fillRect(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2, @@ -425,7 +385,7 @@ bool SaveManager::checkGameOnScreen(int slot) { return false; } -bool SaveManager::getFilename(int slot) { +bool SaveManager::promptForDescription(int slot) { Events &events = *_vm->_events; Scene &scene = *_vm->_scene; Screen &screen = *_vm->_screen; @@ -441,7 +401,7 @@ bool SaveManager::getFilename(int slot) { screen.buttonPrint(Common::Point(ENV_POINTS[5][2], CONTROLS_Y), COMMAND_NULL, true, "Quit"); Common::String saveName = _savegames[slot]; - if (scumm_stricmp(saveName.c_str(), "-EMPTY-") == 0) { + if (isSlotEmpty(slot)) { // It's an empty slot, so start off with an empty save name saveName = ""; @@ -485,18 +445,16 @@ bool SaveManager::getFilename(int slot) { xp -= screen.charWidth(saveName.lastChar()); screen.vgaBar(Common::Rect(xp, yp - 1, xp + 8, yp + 9), INV_FOREGROUND); saveName.deleteLastChar(); - } - - if (keyState.keycode == Common::KEYCODE_RETURN) + + } else if (keyState.keycode == Common::KEYCODE_RETURN && saveName.compareToIgnoreCase(EMPTY_SAVEGAME_SLOT)) { done = 1; - if (keyState.keycode == Common::KEYCODE_ESCAPE) { + } else if (keyState.keycode == Common::KEYCODE_ESCAPE) { screen.vgaBar(Common::Rect(xp, yp - 1, xp + 8, yp + 9), INV_BACKGROUND); done = -1; - } - - if (keyState.keycode >= ' ' && keyState.keycode <= 'z' && saveName.size() < 50 - && (xp + screen.charWidth(keyState.keycode)) < 308) { + + } else if (keyState.ascii >= ' ' && keyState.ascii <= 'z' && saveName.size() < 50 + && (xp + screen.charWidth(keyState.ascii)) < 308) { char c = (char)keyState.ascii; screen.vgaBar(Common::Rect(xp, yp - 1, xp + 8, yp + 9), INV_BACKGROUND); @@ -519,4 +477,8 @@ bool SaveManager::getFilename(int slot) { return done == 1; } +bool SaveManager::isSlotEmpty(int slot) const { + return _savegames[slot].equalsIgnoreCase(EMPTY_SAVEGAME_SLOT); +} + } // End of namespace Sherlock diff --git a/engines/sherlock/saveload.h b/engines/sherlock/saveload.h index c9a7286c6b..a7ed852a5f 100644 --- a/engines/sherlock/saveload.h +++ b/engines/sherlock/saveload.h @@ -33,6 +33,7 @@ namespace Sherlock { #define MAX_SAVEGAME_SLOTS 99 +#define ONSCREEN_FILES_COUNT 5 #define SHERLOCK_SAVEGAME_VERSION 1 enum SaveMode { SAVEMODE_NONE = 0, SAVEMODE_LOAD = 1, SAVEMODE_SAVE = 2 }; @@ -56,8 +57,14 @@ private: Common::String _target; Graphics::Surface *_saveThumb; + /** + * Build up a savegame list, with empty slots given an explicit Empty message + */ void createSavegameList(); + /** + * Synchronize the data for a savegame + */ void synchronize(Common::Serializer &s); public: Common::StringArray _savegames; @@ -68,28 +75,71 @@ public: SaveManager(SherlockEngine *vm, const Common::String &target); ~SaveManager(); + /** + * Shows the in-game dialog interface for loading and saving games + */ void drawInterface(); + /** + * Creates a thumbnail for the current on-screen contents + */ void createThumbnail(); + /** + * Load a list of savegames + */ static SaveStateList getSavegameList(const Common::String &target); + /** + * Support method that generates a savegame name + * @param slot Slot number + */ Common::String generateSaveName(int slot); + /** + * Write out the header information for a savegame + */ void writeSavegameHeader(Common::OutSaveFile *out, SherlockSavegameHeader &header); + /** + * Read in the header information for a savegame + */ static bool readSavegameHeader(Common::InSaveFile *in, SherlockSavegameHeader &header); + /** + * Return the index of the button the mouse is over, if any + */ int getHighlightedButton() const; + /** + * Handle highlighting buttons + */ void highlightButtons(int btnIndex); + /** + * Load the game in the specified slot + */ void loadGame(int slot); + + /** + * Save the game in the specified slot with the given name + */ void saveGame(int slot, const Common::String &name); + /** + * Make sure that the selected savegame is on-screen + */ bool checkGameOnScreen(int slot); - bool getFilename(int slot); + /** + * Prompts the user to enter a description in a given slot + */ + bool promptForDescription(int slot); + + /** + * Returns true if the given save slot is empty + */ + bool isSlotEmpty(int slot) const; }; } // End of namespace Sherlock diff --git a/engines/sherlock/scalpel/darts.cpp b/engines/sherlock/scalpel/darts.cpp index 6da8d6848e..b567d58ab4 100644 --- a/engines/sherlock/scalpel/darts.cpp +++ b/engines/sherlock/scalpel/darts.cpp @@ -44,9 +44,10 @@ enum { DART_COL_FORE = 5, PLAYER_COLOR = 11 }; +#define OPPONENTS_COUNT 4 -const char *const OPPONENT_NAMES[5] = { - "Skipper", "Willy", "Micky", "Tom", "Bartender" +const char *const OPPONENT_NAMES[OPPONENTS_COUNT] = { + "Skipper", "Willy", "Micky", "Tom" }; /*----------------------------------------------------------------*/ @@ -63,9 +64,6 @@ Darts::Darts(ScalpelEngine *vm) : _vm(vm) { _oldDartButtons = false; } -/** - * Main method for playing darts game - */ void Darts::playDarts() { Events &events = *_vm->_events; Screen &screen = *_vm->_screen; @@ -118,7 +116,7 @@ void Darts::playDarts() { if (playerNumber == 0) { screen.print(Common::Point(DART_INFO_X, DART_INFO_Y + 30), PLAYER_COLOR, "Holmes Wins!"); - if (_level < 4) + if (_level < OPPONENTS_COUNT) setFlagsForDarts(318 + _level); } else { screen.print(Common::Point(DART_INFO_X, DART_INFO_Y + 30), PLAYER_COLOR, "%s Wins!", _opponent.c_str()); @@ -181,9 +179,6 @@ void Darts::playDarts() { screen.setFont(oldFont); } -/** - * Load the graphics needed for the dart game - */ void Darts::loadDarts() { Screen &screen = *_vm->_screen; @@ -194,9 +189,6 @@ void Darts::loadDarts() { screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); } -/** - * Initializes the variables needed for the dart game - */ void Darts::initDarts() { _dartScore1 = _dartScore2 = 301; _roundNumber = 1; @@ -210,7 +202,7 @@ void Darts::initDarts() { _computerPlayer = 2; } else { // Check flags for opponents - for (int idx = 0; idx < 4; ++idx) { + for (int idx = 0; idx < OPPONENTS_COUNT; ++idx) { if (_vm->readFlags(314 + idx)) _level = idx; } @@ -219,17 +211,11 @@ void Darts::initDarts() { _opponent = OPPONENT_NAMES[_level]; } -/** - * Frees the images used by the dart game - */ void Darts::closeDarts() { delete _dartImages; _dartImages = nullptr; } -/** - * Show the names of the people playing, Holmes and his opponent - */ void Darts::showNames(int playerNum) { Screen &screen = *_vm->_screen; byte color = playerNum == 0 ? PLAYER_COLOR : DART_COL_FORE; @@ -249,10 +235,10 @@ void Darts::showNames(int playerNum) { if (playerNum != 0) screen.print(Common::Point(STATUS_INFO_X + 50, STATUS_INFO_Y), PLAYER_COLOR + 3, - _opponent.c_str()); + "%s", _opponent.c_str()); else screen.print(Common::Point(STATUS_INFO_X + 50, STATUS_INFO_Y), color, - _opponent.c_str()); + "%s", _opponent.c_str()); screen._backBuffer1.fillRect(Common::Rect(STATUS_INFO_X + 50, STATUS_INFO_Y + 10, STATUS_INFO_X + 81, STATUS_INFO_Y + 12), color); @@ -262,9 +248,6 @@ void Darts::showNames(int playerNum) { screen._backBuffer2.blitFrom(screen._backBuffer1); } -/** - * Show the player score and game status - */ void Darts::showStatus(int playerNum) { Screen &screen = *_vm->_screen; byte color; @@ -283,12 +266,6 @@ void Darts::showStatus(int playerNum) { screen.slamRect(Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + 10, SHERLOCK_SCREEN_WIDTH, STATUS_INFO_Y + 48)); } -/** - * Throws a single dart. - * @param dartNum Dart number - * @param computer 0 = Player, 1 = 1st player computer, 2 = 2nd player computer - * @returns Score for what dart hit - */ int Darts::throwDart(int dartNum, int computer) { Events &events = *_vm->_events; Screen &screen = *_vm->_screen; @@ -347,9 +324,6 @@ int Darts::throwDart(int dartNum, int computer) { return dartScore(dartPos); } -/** - * Draw a dart moving towards the board - */ void Darts::drawDartThrow(const Common::Point &pt) { Events &events = *_vm->_events; Screen &screen = *_vm->_screen; @@ -358,7 +332,7 @@ void Darts::drawDartThrow(const Common::Point &pt) { int delta = 9; for (int idx = 4; idx < 23; ++idx) { - Graphics::Surface &frame = (*_dartImages)[idx]._frame; + ImageFrame &frame = (*_dartImages)[idx]; // Adjust draw position for animating dart if (idx < 13) @@ -369,15 +343,15 @@ void Darts::drawDartThrow(const Common::Point &pt) { pos.y += delta++; // Draw the dart - Common::Point drawPos(pos.x - frame.w / 2, pos.y - frame.h); + Common::Point drawPos(pos.x - frame._width / 2, pos.y - frame._height); screen._backBuffer1.transBlitFrom(frame, drawPos); - screen.slamArea(drawPos.x, drawPos.y, frame.w, frame.h); + screen.slamArea(drawPos.x, drawPos.y, frame._width, frame._height); - // Handle erasing old dart strs + // Handle erasing old dart frame area if (!oldDrawBounds.isEmpty()) screen.slamRect(oldDrawBounds); - oldDrawBounds = Common::Rect(drawPos.x, drawPos.y, drawPos.x + frame.w, drawPos.y + frame.h); + oldDrawBounds = Common::Rect(drawPos.x, drawPos.y, drawPos.x + frame._width, drawPos.y + frame._height); screen._backBuffer1.blitFrom(screen._backBuffer2, drawPos, oldDrawBounds); events.wait(2); @@ -389,9 +363,6 @@ void Darts::drawDartThrow(const Common::Point &pt) { screen.slamRect(oldDrawBounds); } -/** - * Erases the power bars - */ void Darts::erasePowerBars() { Screen &screen = *_vm->_screen; @@ -403,11 +374,6 @@ void Darts::erasePowerBars() { screen.slamArea(DARTBARVX - 1, DARTHEIGHTY - 1, 11, DARTBARSIZE + 3); } -/** - * Show a gradually incrementing incrementing power that bar. If goToPower is provided, it will - * increment to that power level ignoring all keyboard input (ie. for computer throws). - * Otherwise, it will increment until either a key/mouse button is pressed, or it reaches the end - */ int Darts::doPowerBar(const Common::Point &pt, byte color, int goToPower, bool isVertical) { Events &events = *_vm->_events; Screen &screen = *_vm->_screen; @@ -447,20 +413,15 @@ int Darts::doPowerBar(const Common::Point &pt, byte color, int goToPower, bool i if (sound._musicOn) { if (!(idx % 3)) sound.waitTimerRoland(1); - } else { - if (!(idx % 8)) - events.wait(1); - } - + } else if (!(idx % 8)) + events.wait(1); + ++idx; } while (!done); return MIN(idx * 100 / DARTBARSIZE, 100); } -/** - * Returns true if a mouse button or key is pressed. - */ bool Darts::dartHit() { Events &events = *_vm->_events; @@ -480,9 +441,6 @@ bool Darts::dartHit() { return (events._pressed && !_oldDartButtons) ? 1 : 0; } -/** - * Return the score of the given location on the dart-board - */ int Darts::dartScore(const Common::Point &pt) { Common::Point pos(pt.x - 37, pt.y - 33); Graphics::Surface &scoreImg = (*_dartImages)[1]._frame; @@ -496,10 +454,6 @@ int Darts::dartScore(const Common::Point &pt) { return score; } -/** - * Calculates where a computer player is trying to throw their dart, and choose the actual - * point that was hit with some margin of error - */ Common::Point Darts::getComputerDartDest(int playerNum) { Common::Point target; int score = playerNum == 0 ? _dartScore1 : _dartScore2; @@ -555,9 +509,6 @@ Common::Point Darts::getComputerDartDest(int playerNum) { return target; } -/** - * Returns the center position for the area of the dartboard with a given number - */ bool Darts::findNumberOnBoard(int aim, Common::Point &pt) { ImageFrame &board = (*_dartImages)[1]; @@ -597,10 +548,6 @@ bool Darts::findNumberOnBoard(int aim, Common::Point &pt) { return done; } -/** - * Set a global flag to 0 or 1 depending on whether the passed flag is negative or positive. - * @remarks We don't use the global setFlags method because we don't want to check scene flags - */ void Darts::setFlagsForDarts(int flagNum) { _vm->_flags[ABS(flagNum)] = flagNum >= 0; } diff --git a/engines/sherlock/scalpel/darts.h b/engines/sherlock/scalpel/darts.h index a9624442e2..42990f8056 100644 --- a/engines/sherlock/scalpel/darts.h +++ b/engines/sherlock/scalpel/darts.h @@ -44,30 +44,88 @@ private: int _roundScore; bool _oldDartButtons; + /** + * Load the graphics needed for the dart game + */ void loadDarts(); + + /** + * Initializes the variables needed for the dart game + */ void initDarts(); + + /** + * Frees the images used by the dart game + */ void closeDarts(); + /** + * Show the names of the people playing, Holmes and his opponent + */ void showNames(int playerNum); + + /** + * Show the player score and game status + */ void showStatus(int playerNum); + /** + * Throws a single dart. + * @param dartNum Dart number + * @param computer 0 = Player, 1 = 1st player computer, 2 = 2nd player computer + * @returns Score for what dart hit + */ int throwDart(int dartNum, int computer); + + /** + * Draw a dart moving towards the board + */ void drawDartThrow(const Common::Point &pt); + /** + * Erases the power bars + */ void erasePowerBars(); + + /** + * Show a gradually incrementing incrementing power that bar. If goToPower is provided, it will + * increment to that power level ignoring all keyboard input (ie. for computer throws). + * Otherwise, it will increment until either a key/mouse button is pressed, or it reaches the end + */ int doPowerBar(const Common::Point &pt, byte color, int goToPower, bool isVertical); + /** + * Returns true if a mouse button or key is pressed. + */ bool dartHit(); + + /** + * Return the score of the given location on the dart-board + */ int dartScore(const Common::Point &pt); + /** + * Calculates where a computer player is trying to throw their dart, and choose the actual + * point that was hit with some margin of error + */ Common::Point getComputerDartDest(int playerNum); + /** + * Returns the center position for the area of the dartboard with a given number + */ bool findNumberOnBoard(int aim, Common::Point &pt); + /** + * Set a global flag to 0 or 1 depending on whether the passed flag is negative or positive. + * @remarks We don't use the global setFlags method because we don't want to check scene flags + */ void setFlagsForDarts(int flagNum); public: Darts(ScalpelEngine *vm); + /** + * Main method for playing darts game + */ void playDarts(); }; diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp index eff589874d..ccc9c8abca 100644 --- a/engines/sherlock/scalpel/scalpel.cpp +++ b/engines/sherlock/scalpel/scalpel.cpp @@ -64,24 +64,25 @@ static const int TITLE_FRAMES[7][9] = { }; #define NUM_PLACES 100 -const int MAP_X[NUM_PLACES] = { + +static const int MAP_X[NUM_PLACES] = { 0, 368, 0, 219, 0, 282, 0, 43, 0, 0, 396, 408, 0, 0, 0, 568, 37, 325, 28, 0, 263, 36, 148, 469, 342, 143, 443, 229, 298, 0, 157, 260, 432, 174, 0, 351, 0, 528, 0, 136, 0, 0, 0, 555, 165, 0, 506, 0, 0, 344, 0, 0 }; -const int MAP_Y[NUM_PLACES] = { +static const int MAP_Y[NUM_PLACES] = { 0, 147, 0, 166, 0, 109, 0, 61, 0, 0, 264, 70, 0, 0, 0, 266, 341, 30, 275, 0, 294, 146, 311, 230, 184, 268, 133, 94, 207, 0, 142, 142, 330, 255, 0, 37, 0, 70, 0, 116, 0, 0, 0, 50, 21, 0, 303, 0, 0, 229, 0, 0 }; -const int MAP_TRANSLATE[NUM_PLACES] = { +static const int MAP_TRANSLATE[NUM_PLACES] = { 0, 0, 0, 1, 0, 2, 0, 3, 4, 0, 4, 6, 0, 0, 0, 8, 9, 10, 11, 0, 12, 13, 14, 7, 15, 16, 17, 18, 19, 0, 20, 21, 22, 23, 0, 24, 0, 25, 0, 26, 0, 0, 0, 27, 28, 0, 29, 0, 0, 30, 0 }; -const byte MAP_SEQUENCES[3][MAX_FRAME] = { +static const byte MAP_SEQUENCES[3][MAX_FRAME] = { { 1, 1, 2, 3, 4, 0 }, // Overview Still { 5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0 }, { 5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0 } @@ -89,7 +90,145 @@ const byte MAP_SEQUENCES[3][MAX_FRAME] = { #define MAX_PEOPLE 66 -const byte STILL_SEQUENCES[MAX_PEOPLE][MAX_TALK_SEQUENCES] = { +const char PEOPLE_PORTRAITS[MAX_PEOPLE][5] = { + { "HOLM" }, // Sherlock Holmes + { "WATS" }, // Dr. Watson + { "LEST" }, // Inspector Lestrade + { "CON1" }, // Constable O'Brien + { "CON2" }, // Constable Lewis + { "SHEI" }, // Sheila Parker + { "HENR" }, // Henry Carruthers + { "LESL" }, // Lesley (flower girl) + { "USH1" }, // Usher #1 + { "USH2" }, // Usher #2 + { "FRED" }, // Fredrick Epstein + { "WORT" }, // Mrs. Worthington + { "COAC" }, // Coach + { "PLAY" }, // Player + { "WBOY" }, // Tim (Waterboy) + { "JAME" }, // James Sanders + { "BELL" }, // Belle (perfumerie) + { "GIRL" }, // Cleaning Girl (perfumerie) + { "EPST" }, // Epstien in the Opera Balcony + { "WIGG" }, // Wiggins + { "PAUL" }, // Paul (Brumwell / Carroway) + { "BART" }, // Bartender + { "DIRT" }, // Dirty Drunk + { "SHOU" }, // Shouting Drunk + { "STAG" }, // Staggering Drunk + { "BOUN" }, // Bouncer + { "SAND" }, // James Sanders - At Home + { "CORO" }, // The Coroner + { "EQUE" }, // The Equestrian Shop Keeper + { "GEOR" }, // George Blackwood + { "LARS" }, // Lars + { "PARK" }, // Sheila Parker (happy) + { "CHEM" }, // Chemist + { "GREG" }, // Inspector Gregson + { "LAWY" }, // Jacob Farthington Lawyer + { "MYCR" }, // Mycroft + { "SHER" }, // Old Sherman + { "CHMB" }, // Richard Chemist Stock boy + { "BARM" }, // Barman + { "DAND" }, // Dandy Player + { "ROUG" }, // Rough-looking Player + { "SPEC" }, // Spectator + { "HUNT" }, // Robert Hunt + { "VIOL" }, // Violet Secretary + { "PETT" }, // Pettigrew + { "APPL" }, // Augie (apple seller) + { "ANNA" }, // Anna Carroway + { "GUAR" }, // Guard + { "ANTO" }, // Antonio Caruso + { "TOBY" }, // Toby the Dog + { "KING" }, // Simon Kingsley + { "ALFR" }, // Alfred Tobacco Clerk + { "LADY" }, // Lady Brumwell + { "ROSA" }, // Madame Rosa + { "LADB" }, // Lady Brumwell + { "MOOR" }, // Joseph Moorehead + { "BEAL" }, // Mrs. Beale + { "LION" }, // Felix the Lion + { "HOLL" }, // Hollingston + { "CALL" }, // Constable Callaghan + { "JERE" }, // Sergeant Jeremy Duncan + { "LORD" }, // Lord Brumwell + { "NIGE" }, // Nigel Jameson + { "JONA" }, // Jonas (newspaper seller) + { "DUGA" }, // Constable Dugan + { "INSP" } // Inspector Lestrade (Scotland Yard) +}; + +const char *const PEOPLE_NAMES[MAX_PEOPLE] = { + "Sherlock Holmes", + "Dr. Watson", + "Inspector Lestrade", + "Constable O'Brien", + "Constable Lewis", + "Sheila Parker", + "Henry Carruthers", + "Lesley", + "An Usher", + "An Usher", + "Fredrick Epstein", + "Mrs. Worthington", + "The Coach", + "A Player", + "Tim", + "James Sanders", + "Belle", + "Cleaning Girl", + "Fredrick Epstein", + "Wiggins", + "Paul", + "The Bartender", + "A Dirty Drunk", + "A Shouting Drunk", + "A Staggering Drunk", + "The Bouncer", + "James Sanders", + "The Coroner", + "Reginald Snipes", + "George Blackwood", + "Lars", + "Sheila Parker", + "The Chemist", + "Inspector Gregson", + "Jacob Farthington", + "Mycroft", + "Old Sherman", + "Richard", + "The Barman", + "A Dandy Player", + "A Rough-looking Player", + "A Spectator", + "Robert Hunt", + "Violet", + "Pettigrew", + "Augie", + "Anna Carroway", + "A Guard", + "Antonio Caruso", + "Toby the Dog", + "Simon Kingsley", + "Alfred", + "Lady Brumwell", + "Madame Rosa", + "Lady Brumwell", + "Joseph Moorehead", + "Mrs. Beale", + "Felix", + "Hollingston", + "Constable Callaghan", + "Sergeant Duncan", + "Lord Brumwell", + "Nigel Jaimeson", + "Jonas", + "Constable Dugan", + "Inspector Lestrade" +}; + +static const byte PEOPLE_STILL_SEQUENCES[MAX_PEOPLE][MAX_TALK_SEQUENCES] = { { 1, 0, 0 }, // Sherlock Holmes { 6, 0, 0 }, // Dr. Watson { 4, 0, 0 }, // Inspector Lestrade @@ -158,7 +297,7 @@ const byte STILL_SEQUENCES[MAX_PEOPLE][MAX_TALK_SEQUENCES] = { { 4, 0, 0 } // Inspector Lestrade (Yard) }; -byte TALK_SEQUENCES[MAX_PEOPLE][MAX_TALK_SEQUENCES] = { +static const byte PEOPLE_TALK_SEQUENCES[MAX_PEOPLE][MAX_TALK_SEQUENCES] = { { 1, 0, 0 }, // Sherlock Holmes { 5, 5, 6, 7, 8, 7, 8, 6, 0, 0 }, // Dr. Watson { 2, 0, 0 }, // Inspector Lestrade @@ -239,9 +378,6 @@ ScalpelEngine::~ScalpelEngine() { delete _darts; } -/** - * Game initialization - */ void ScalpelEngine::initialize() { initGraphics(320, 200, false); @@ -261,15 +397,20 @@ void ScalpelEngine::initialize() { _res->addToCache("snd.snd"); _res->addToCache("title.snd"); - // Load the map co-ordinates for each scene and sequence data - _map->loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0], &MAP_TRANSLATE[0]); - _map->loadSequences(3, &MAP_SEQUENCES[0][0]); + if (!isDemo()) { + // Load the map co-ordinates for each scene and sequence data + _map->loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0], &MAP_TRANSLATE[0]); + _map->loadSequences(3, &MAP_SEQUENCES[0][0]); + _map->_oldCharPoint = BAKER_ST_EXTERIOR; + } // Load the inventory loadInventory(); - // Set up constants used by the talk system - _talk->setSequences(&TALK_SEQUENCES[0][0], &STILL_SEQUENCES[0][0], MAX_PEOPLE); + // Set up list of people + for (int idx = 0; idx < MAX_PEOPLE; ++idx) + _people->_characters.push_back(PersonData(PEOPLE_NAMES[idx], PEOPLE_PORTRAITS[idx], + PEOPLE_STILL_SEQUENCES[idx], PEOPLE_TALK_SEQUENCES[idx])); _animation->setPrologueNames(&PROLOGUE_NAMES[0], PROLOGUE_NAMES_COUNT); _animation->setPrologueFrames(&PROLOGUE_FRAMES[0][0], 6, 9); @@ -278,17 +419,14 @@ void ScalpelEngine::initialize() { _animation->setTitleFrames(&TITLE_FRAMES[0][0], 7, 9); // Starting scene - if (getIsDemo()) + if (isDemo() && _interactiveFl) _scene->_goToScene = 3; else _scene->_goToScene = 4; } -/** - * Show the opening sequence - */ void ScalpelEngine::showOpening() { - if (getIsDemo()) + if (isDemo() && _interactiveFl) return; if (!showCityCutscene()) @@ -304,21 +442,18 @@ void ScalpelEngine::showOpening() { _sound->stopMusic(); } -/** - * Show the starting city cutscene which shows the game title - */ bool ScalpelEngine::showCityCutscene() { byte palette[PALETTE_SIZE]; _sound->playMusic("prolog1.mus"); - _titleOverride = "title.lib"; - _soundOverride = "title.snd"; + _animation->_gfxLibraryFilename = "title.lib"; + _animation->_soundLibraryFilename = "title.snd"; bool finished = _animation->play("26open1", 1, 255, true, 2); if (finished) { ImageFile titleImages("title2.vgs", true); - _screen->_backBuffer1.copyFrom(*_screen); - _screen->_backBuffer2.copyFrom(*_screen); + _screen->_backBuffer1.blitFrom(*_screen); + _screen->_backBuffer2.blitFrom(*_screen); // London, England _screen->_backBuffer1.transBlitFrom(titleImages[0], Common::Point(10, 11)); @@ -342,8 +477,8 @@ bool ScalpelEngine::showCityCutscene() { if (finished) { ImageFile titleImages("title.vgs", true); - _screen->_backBuffer1.copyFrom(*_screen); - _screen->_backBuffer2.copyFrom(*_screen); + _screen->_backBuffer1.blitFrom(*_screen); + _screen->_backBuffer2.blitFrom(*_screen); // The Lost Files of _screen->_backBuffer1.transBlitFrom(titleImages[0], Common::Point(75, 6)); @@ -374,20 +509,17 @@ bool ScalpelEngine::showCityCutscene() { } } - _titleOverride = ""; - _soundOverride = ""; + _animation->_gfxLibraryFilename = ""; + _animation->_soundLibraryFilename = ""; return finished; } -/** - * Show the back alley where the initial murder takes place - */ bool ScalpelEngine::showAlleyCutscene() { byte palette[PALETTE_SIZE]; _sound->playMusic("prolog2.mus"); - _titleOverride = "TITLE.LIB"; - _soundOverride = "TITLE.SND"; + _animation->_gfxLibraryFilename = "TITLE.LIB"; + _animation->_soundLibraryFilename = "TITLE.SND"; bool finished = _animation->play("27PRO1", 1, 3, true, 2); if (finished) @@ -401,12 +533,12 @@ bool ScalpelEngine::showAlleyCutscene() { if (finished) finished = _animation->play("27PRO3", 1, 0, true, 2); - if(finished) { + if (finished) { _screen->getPalette(palette); _screen->fadeToBlack(2); } - if(finished) { + if (finished) { ImageFile titleImages("title3.vgs", true); // "Early the following morning on Baker Street..." _screen->_backBuffer1.transBlitFrom(titleImages[0], Common::Point(35, 51), false, 0); @@ -414,17 +546,14 @@ bool ScalpelEngine::showAlleyCutscene() { finished = _events->delay(1000); } - _titleOverride = ""; - _soundOverride = ""; + _animation->_gfxLibraryFilename = ""; + _animation->_soundLibraryFilename = ""; return finished; } -/** - * Show the Baker Street outside cutscene - */ bool ScalpelEngine::showStreetCutscene() { - _titleOverride = "TITLE.LIB"; - _soundOverride = "TITLE.SND"; + _animation->_gfxLibraryFilename = "TITLE.LIB"; + _animation->_soundLibraryFilename = "TITLE.SND"; _sound->playMusic("PROLOG3.MUS"); @@ -433,14 +562,12 @@ bool ScalpelEngine::showStreetCutscene() { if (finished) finished = _animation->play("14NOTE", 1, 0, false, 2); - _titleOverride = ""; - _soundOverride = ""; + _animation->_gfxLibraryFilename = ""; + _animation->_soundLibraryFilename = ""; return finished; } -/** - * Show the game credits - */ + bool ScalpelEngine::scrollCredits() { // Load the images for displaying credit text Common::SeekableReadStream *stream = _res->load("credits.vgs", "title.lib"); @@ -463,9 +590,9 @@ bool ScalpelEngine::scrollCredits() { _screen->transBlitFrom(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->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())); _events->delay(100); } @@ -473,13 +600,10 @@ bool ScalpelEngine::scrollCredits() { return true; } -/** - * Show Holmes and Watson at the breakfast table, lestrade's note, and then the scrolling credits - */ bool ScalpelEngine::showOfficeCutscene() { _sound->playMusic("PROLOG4.MUS"); - _titleOverride = "TITLE2.LIB"; - _soundOverride = "TITLE.SND"; + _animation->_gfxLibraryFilename = "TITLE2.LIB"; + _animation->_soundLibraryFilename = "TITLE.SND"; bool finished = _animation->play("COFF1", 1, 3, true, 3); if (finished) @@ -498,8 +622,10 @@ bool ScalpelEngine::showOfficeCutscene() { } else finished = _events->delay(19000); - _events->clearEvents(); - finished = _events->delay(500); + if (finished) { + _events->clearEvents(); + finished = _events->delay(500); + } } if (finished) @@ -514,16 +640,11 @@ bool ScalpelEngine::showOfficeCutscene() { if (finished) _screen->fadeToBlack(3); - _titleOverride = ""; - _soundOverride = ""; + _animation->_gfxLibraryFilename = ""; + _animation->_soundLibraryFilename = ""; return finished; } -/** - * Load the default inventory for the game, which includes both the initial active inventory, - * as well as special pending inventory items which can appear automatically in the player's - * inventory once given required flags are set - */ void ScalpelEngine::loadInventory() { Inventory &inv = *_inventory; @@ -545,24 +666,18 @@ void ScalpelEngine::loadInventory() { inv.push_back(InventoryItem(586, "Pawn ticket", "A pawn ticket", "_ITEM16A")); } -/** - * Transition to show an image - */ void ScalpelEngine::showLBV(const Common::String &filename) { Common::SeekableReadStream *stream = _res->load(filename, "title.lib"); ImageFile images(*stream); delete stream; _screen->setPalette(images._palette); - _screen->_backBuffer1.blitFrom(images[0]._frame); + _screen->_backBuffer1.blitFrom(images[0]); _screen->verticalTransition(); } -/** - * Starting a scene within the game - */ void ScalpelEngine::startScene() { - if (_scene->_goToScene == 100 || _scene->_goToScene == 98) { + if (_scene->_goToScene == OVERHEAD_MAP || _scene->_goToScene == OVERHEAD_MAP2) { // Show the map if (_sound->_musicOn) { if (_sound->loadSong(100)) { @@ -585,17 +700,17 @@ void ScalpelEngine::startScene() { // 55: Fade out and exit // 70: Brumwell suicide switch (_scene->_goToScene) { - case 2: - case 52: - case 53: - case 70: + case BLACKWOOD_CAPTURE: + case RESCUE_ANNA: + case MOOREHEAD_DEATH: + case BRUMWELL_SUICIDE: if (_sound->_musicOn && _sound->loadSong(_scene->_goToScene)) { if (_sound->_music) _sound->startSong(); } switch (_scene->_goToScene) { - case 2: + case BLACKWOOD_CAPTURE: // Blackwood's capture _res->addToCache("final2.vda", "epilogue.lib"); _res->addToCache("final2.vdx", "epilogue.lib"); @@ -603,7 +718,7 @@ void ScalpelEngine::startScene() { _animation->play("final2", 1, 0, false, 4); break; - case 52: + case RESCUE_ANNA: // Rescuing Anna _res->addToCache("finalr2.vda", "epilogue.lib"); _res->addToCache("finalr2.vdx", "epilogue.lib"); @@ -638,7 +753,7 @@ void ScalpelEngine::startScene() { _useEpilogue2 = false; break; - case 53: + case MOOREHEAD_DEATH: // Moorehead's death / subway train _res->addToCache("SUBWAY2.vda", "epilogue.lib"); _res->addToCache("SUBWAY2.vdx", "epilogue.lib"); @@ -654,7 +769,7 @@ void ScalpelEngine::startScene() { _screen->_fadeStyle = false; break; - case 70: + case BRUMWELL_SUICIDE: // Brumwell suicide _animation->play("suicid", 1, 3, true, 4); break; @@ -663,31 +778,31 @@ void ScalpelEngine::startScene() { } // Except for the Moorehead Murder scene, fade to black first - if (_scene->_goToScene != 53) { + if (_scene->_goToScene != MOOREHEAD_DEATH) { _events->wait(40); _screen->fadeToBlack(3); } switch (_scene->_goToScene) { case 52: - _scene->_goToScene = 27; // Go to the Lawyer's Office + _scene->_goToScene = LAWYER_OFFICE; // Go to the Lawyer's Office _map->_bigPos = Common::Point(0, 0); // Overland scroll position _map->_overPos = Common::Point(22900 - 600, 9400 + 900); // Overland position - _map->_oldCharPoint = 27; + _map->_oldCharPoint = LAWYER_OFFICE; break; case 53: - _scene->_goToScene = 17; // Go to St. Pancras Station + _scene->_goToScene = STATION; // Go to St. Pancras Station _map->_bigPos = Common::Point(0, 0); // Overland scroll position _map->_overPos = Common::Point(32500 - 600, 3000 + 900); // Overland position - _map->_oldCharPoint = 17; + _map->_oldCharPoint = STATION; break; default: - _scene->_goToScene = 4; // Back to Baker st. + _scene->_goToScene = BAKER_STREET; // Back to Baker st. _map->_bigPos = Common::Point(0, 0); // Overland scroll position _map->_overPos = Common::Point(14500 - 600, 8400 + 900); // Overland position - _map->_oldCharPoint = 4; + _map->_oldCharPoint = BAKER_STREET; break; } @@ -695,7 +810,7 @@ void ScalpelEngine::startScene() { _sound->freeSong(); break; - case 55: + case EXIT_GAME: // Exit game _screen->fadeToBlack(3); quitGame(); @@ -711,15 +826,12 @@ void ScalpelEngine::startScene() { if (_scene->_goToScene == 99) { // Darts Board minigame _darts->playDarts(); - _mapResult = _scene->_goToScene = 19; // Go back to the bar + _mapResult = _scene->_goToScene = PUB_INTERIOR; } _mapResult = _scene->_goToScene; } -/** - * Takes care of clearing the mirror in scene 12, in case anything drew over it - */ void ScalpelEngine::eraseMirror12() { Common::Point pt((*_people)[AL]._position.x / 100, (*_people)[AL]._position.y / 100); @@ -730,9 +842,6 @@ void ScalpelEngine::eraseMirror12() { } } -/** - * Takes care of drawing Holme's reflection onto the mirror in scene 12 - */ void ScalpelEngine::doMirror12() { People &people = *_people; Common::Point pt((*_people)[AL]._position.x / 100, (*_people)[AL]._position.y / 100); @@ -806,9 +915,6 @@ void ScalpelEngine::doMirror12() { } } -/** - * This clears the mirror in scene 12 in case anything messed draw over it - */ void ScalpelEngine::flushMirror12() { Common::Point pt((*_people)[AL]._position.x / 100, (*_people)[AL]._position.y / 100); diff --git a/engines/sherlock/scalpel/scalpel.h b/engines/sherlock/scalpel/scalpel.h index 40e4937b5d..8743bfb7a9 100644 --- a/engines/sherlock/scalpel/scalpel.h +++ b/engines/sherlock/scalpel/scalpel.h @@ -30,32 +30,83 @@ namespace Sherlock { namespace Scalpel { +enum { BLACKWOOD_CAPTURE = 2, BAKER_STREET = 4, DRAWING_ROOM = 12, STATION = 17, PUB_INTERIOR = 19, + LAWYER_OFFICE = 27, BAKER_ST_EXTERIOR = 39, RESCUE_ANNA = 52, MOOREHEAD_DEATH = 53, EXIT_GAME = 55, + BRUMWELL_SUICIDE = 70, OVERHEAD_MAP2 = 98, DARTS_GAME = 99, OVERHEAD_MAP = 100 }; + class ScalpelEngine : public SherlockEngine { private: Darts *_darts; int _mapResult; + /** + * Show the starting city cutscene which shows the game title + */ bool showCityCutscene(); + + /** + * Show the back alley where the initial murder takes place + */ bool showAlleyCutscene(); + + /** + * Show the Baker Street outside cutscene + */ bool showStreetCutscene(); + + /** + * Show Holmes and Watson at the breakfast table, lestrade's note, and then the scrolling credits + */ bool showOfficeCutscene(); + + /** + * Show the game credits + */ bool scrollCredits(); + /** + * Load the default inventory for the game, which includes both the initial active inventory, + * as well as special pending inventory items which can appear automatically in the player's + * inventory once given required flags are set + */ void loadInventory(); + /** + * Transition to show an image + */ void showLBV(const Common::String &filename); protected: + /** + * Game initialization + */ virtual void initialize(); + /** + * Show the opening sequence + */ virtual void showOpening(); + /** + * Starting a scene within the game + */ virtual void startScene(); public: ScalpelEngine(OSystem *syst, const SherlockGameDescription *gameDesc); virtual ~ScalpelEngine(); + /** + * Takes care of clearing the mirror in scene 12 (mansion drawing room), in case anything drew over it + */ void eraseMirror12(); + + /** + * Takes care of drawing Holme's reflection onto the mirror in scene 12 (mansion drawing room) + */ void doMirror12(); + + /** + * This clears the mirror in scene 12 (mansion drawing room) in case anything messed draw over it + */ void flushMirror12(); }; diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp index 96cfac0683..2c80bfbd39 100644 --- a/engines/sherlock/scene.cpp +++ b/engines/sherlock/scene.cpp @@ -27,6 +27,13 @@ namespace Sherlock { +static const int FS_TRANS[8] = { + STOP_UP, STOP_UPRIGHT, STOP_RIGHT, STOP_DOWNRIGHT, STOP_DOWN, + STOP_DOWNLEFT, STOP_LEFT, STOP_UPLEFT +}; + +/*----------------------------------------------------------------*/ + BgFileHeader::BgFileHeader() { _numStructs = -1; _numImages = -1; @@ -44,7 +51,7 @@ BgFileHeader::BgFileHeader() { Common::fill(&_palette[0], &_palette[PALETTE_SIZE], 0); } -void BgFileHeader::synchronize(Common::SeekableReadStream &s, bool isRoseTattoo) { +void BgFileHeader::load(Common::SeekableReadStream &s, bool isRoseTattoo) { _numStructs = s.readUint16LE(); _numImages = s.readUint16LE(); _numcAnimations = s.readUint16LE(); @@ -63,10 +70,7 @@ void BgFileHeader::synchronize(Common::SeekableReadStream &s, bool isRoseTattoo) /*----------------------------------------------------------------*/ -/** - * Load the data for the object - */ -void BgfileheaderInfo::load(Common::SeekableReadStream &s) { +void BgFileHeaderInfo::load(Common::SeekableReadStream &s) { _filesize = s.readUint32LE(); _maxFrames = s.readByte(); @@ -77,9 +81,6 @@ void BgfileheaderInfo::load(Common::SeekableReadStream &s) { /*----------------------------------------------------------------*/ -/** - * Load the data for the object - */ void Exit::load(Common::SeekableReadStream &s, bool isRoseTattoo) { if (isRoseTattoo) { char buffer[41]; @@ -108,9 +109,6 @@ void Exit::load(Common::SeekableReadStream &s, bool isRoseTattoo) { /*----------------------------------------------------------------*/ -/** - * Load the data for the object - */ void SceneEntry::load(Common::SeekableReadStream &s) { _startPosition.x = s.readSint16LE(); _startPosition.y = s.readSint16LE(); @@ -118,9 +116,6 @@ void SceneEntry::load(Common::SeekableReadStream &s) { _allow = s.readByte(); } -/** - * Load the data for the object - */ void SceneSound::load(Common::SeekableReadStream &s) { char buffer[9]; s.read(buffer, 8); @@ -132,9 +127,6 @@ void SceneSound::load(Common::SeekableReadStream &s) { /*----------------------------------------------------------------*/ -/** - * Retuurn the index of the passed object in the array - */ int ObjectArray::indexOf(const Object &obj) const { for (uint idx = 0; idx < size(); ++idx) { if (&(*this)[idx] == &obj) @@ -146,9 +138,6 @@ int ObjectArray::indexOf(const Object &obj) const { /*----------------------------------------------------------------*/ -/** - * Load the data for the object - */ void ScaleZone::load(Common::SeekableReadStream &s) { left = s.readSint16LE(); top = s.readSint16LE(); @@ -167,16 +156,12 @@ Scene::Scene(SherlockEngine *vm): _vm(vm) { _currentScene = -1; _goToScene = -1; _loadingSavedGame = false; - _changes = false; - _keyboardInput = 0; _walkedInScene = false; _version = 0; _lzwMode = false; _invGraphicItems = 0; _cAnimFramePause = 0; _restoreFlag = false; - _invLookFlag = false; - _lookHelp = false; _animating = 0; _doBgAnimDone = true; _tempFadeStyle = 0; @@ -187,9 +172,6 @@ Scene::~Scene() { freeScene(); } -/** - * Handles loading the scene specified by _goToScene - */ void Scene::selectScene() { Events &events = *_vm->_events; People &people = *_vm->_people; @@ -200,9 +182,6 @@ void Scene::selectScene() { // Reset fields ui._windowOpen = ui._infoFlag = false; ui._menuMode = STD_MODE; - _keyboardInput = 0; - _oldKey = _help = _oldHelp = 0; - _oldTemp = _temp = 0; // Free any previous scene freeScene(); @@ -215,7 +194,7 @@ void Scene::selectScene() { loadScene(sceneFile); - // If the fade style was changed from running amovie, then reset it + // If the fade style was changed from running a movie, then reset it if (_tempFadeStyle) { screen._fadeStyle = _tempFadeStyle; _tempFadeStyle = 0; @@ -227,15 +206,12 @@ void Scene::selectScene() { _restoreFlag = true; events.clearEvents(); - // If there were any scripst waiting to be run, but were interrupt by a running + // If there were any scripts waiting to be run, but were interrupt by a running // canimation (probably the last scene's exit canim), clear the _scriptMoreFlag if (talk._scriptMoreFlag == 3) talk._scriptMoreFlag = 0; } -/** - * Fres all the graphics and other dynamically allocated data for the scene - */ void Scene::freeScene() { if (_currentScene == -1) return; @@ -265,15 +241,6 @@ void Scene::freeScene() { _currentScene = -1; } -/** - * Loads the data associated for a given scene. The .BGD file's format is: - * BGHEADER: Holds an index for the rest of the file - * STRUCTS: The objects for the scene - * IMAGES: The graphic information for the structures - * - * The _misc field of the structures contains the number of the graphic image - * that it should point to after loading; _misc is then set to 0. - */ bool Scene::loadScene(const Common::String &filename) { Events &events = *_vm->_events; Map &map = *_vm->_map; @@ -284,7 +251,6 @@ bool Scene::loadScene(const Common::String &filename) { Sound &sound = *_vm->_sound; UserInterface &ui = *_vm->_ui; bool flag; - Common::Array<BgfileheaderInfo> bgInfo; _walkedInScene = false; @@ -319,7 +285,7 @@ bool Scene::loadScene(const Common::String &filename) { rrmStream->seek(rrmStream->readUint32LE()); BgFileHeader bgHeader; - bgHeader.synchronize(*rrmStream, IS_ROSE_TATTOO); + bgHeader.load(*rrmStream, IS_ROSE_TATTOO); _invGraphicItems = bgHeader._numImages + 1; if (IS_ROSE_TATTOO) { @@ -338,6 +304,7 @@ bool Scene::loadScene(const Common::String &filename) { } // Read in the shapes header info + Common::Array<BgFileHeaderInfo> bgInfo; bgInfo.resize(bgHeader._numStructs); for (uint idx = 0; idx < bgInfo.size(); ++idx) @@ -364,30 +331,51 @@ bool Scene::loadScene(const Common::String &filename) { if (_lzwMode) delete infoStream; + } else if (!_lzwMode) { + _bgShapes.resize(bgHeader._numStructs); + for (int idx = 0; idx < bgHeader._numStructs; ++idx) + _bgShapes[idx].load(*rrmStream, false); + + if (bgHeader._descSize) { + _descText.resize(bgHeader._descSize); + rrmStream->read(&_descText[0], bgHeader._descSize); + } + + if (bgHeader._seqSize) { + _sequenceBuffer.resize(bgHeader._seqSize); + rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize); + } } else { - // Load shapes - Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream : res.decompress(*rrmStream, bgHeader._numStructs * 625); + Common::SeekableReadStream *infoStream; + + // Read shapes + infoStream = Resources::decompressLZ(*rrmStream, bgHeader._numStructs * 569); _bgShapes.resize(bgHeader._numStructs); for (int idx = 0; idx < bgHeader._numStructs; ++idx) - _bgShapes[idx].load(*infoStream, true); + _bgShapes[idx].load(*infoStream, false); + + delete infoStream; + + // Read description texts + if (bgHeader._descSize) { + infoStream = Resources::decompressLZ(*rrmStream, bgHeader._descSize); + + _descText.resize(bgHeader._descSize); + infoStream->read(&_descText[0], bgHeader._descSize); - if (_lzwMode) delete infoStream; + } - // Load description text - _descText.resize(bgHeader._descSize); - if (_lzwMode) - res.decompress(*rrmStream, (byte *)&_descText[0], bgHeader._descSize); - else - rrmStream->read(&_descText[0], bgHeader._descSize); + // Read sequences + if (bgHeader._seqSize) { + infoStream = Resources::decompressLZ(*rrmStream, bgHeader._seqSize); - // Load sequences - _sequenceBuffer.resize(bgHeader._seqSize); - if (_lzwMode) - res.decompress(*rrmStream, &_sequenceBuffer[0], bgHeader._seqSize); - else - rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize); + _sequenceBuffer.resize(bgHeader._seqSize); + infoStream->read(&_sequenceBuffer[0], bgHeader._seqSize); + + delete infoStream; + } } // Set up the list of images used by the scene @@ -545,7 +533,6 @@ bool Scene::loadScene(const Common::String &filename) { // Clear user interface area and draw controls ui.drawInterface(); - _changes = false; checkSceneStatus(); if (!saves._justLoaded) { @@ -556,13 +543,13 @@ bool Scene::loadScene(const Common::String &filename) { // Check for TURNON objects for (uint idx = 0; idx < _bgShapes.size(); ++idx) { - if (_bgShapes[idx]._type == HIDDEN && (_bgShapes[idx]._flags & 0x20)) + if (_bgShapes[idx]._type == HIDDEN && (_bgShapes[idx]._flags & TURNON_OBJ)) _bgShapes[idx].toggleHidden(); } // Check for TURNOFF objects for (uint idx = 0; idx < _bgShapes.size(); ++idx) { - if (_bgShapes[idx]._type != HIDDEN && (_bgShapes[idx]._flags & 0x40) && + if (_bgShapes[idx]._type != HIDDEN && (_bgShapes[idx]._flags & TURNOFF_OBJ) && _bgShapes[idx]._type != INVALID) _bgShapes[idx].toggleHidden(); if (_bgShapes[idx]._type == HIDE_SHAPE) @@ -590,7 +577,7 @@ bool Scene::loadScene(const Common::String &filename) { _walkedInScene = false; saves._justLoaded = false; - if (!_vm->getIsDemo()) { + if (!_vm->isDemo()) { // Reset the previous map location and position on overhead map map._oldCharPoint = _currentScene; map._overPos.x = map[_currentScene].x * 100 - 600; @@ -601,9 +588,6 @@ bool Scene::loadScene(const Common::String &filename) { return flag; } -/** - * Load all the sound effects specified for the current scene - */ void Scene::loadSceneSounds() { Sound &sound = *_vm->_sound; @@ -611,10 +595,6 @@ void Scene::loadSceneSounds() { sound.loadSound(_sounds[idx]._name, _sounds[idx]._priority); } -/** - * Set objects to their current persistent state. This includes things such as - * opening or moving them - */ void Scene::checkSceneStatus() { if (_sceneStats[_currentScene][64]) { for (uint idx = 0; idx < 64; ++idx) { @@ -640,10 +620,6 @@ void Scene::checkSceneStatus() { } } -/** - * Restores objects to the correct status. This ensures that things like being opened or moved - * will remain the same on future visits to the scene - */ void Scene::saveSceneStatus() { // Flag any objects for the scene that have been altered int count = MIN((int)_bgShapes.size(), 64); @@ -657,11 +633,6 @@ void Scene::saveSceneStatus() { _sceneStats[_currentScene][64] = true; } -/** - * Check the scene's objects against the game flags. If false is passed, - * it means the scene has just been loaded. A value of true means that the scene - * is in use (ie. not just loaded) - */ void Scene::checkSceneFlags(bool flag) { SpriteType mode = flag ? HIDE_SHAPE : HIDDEN; @@ -714,16 +685,10 @@ void Scene::checkSceneFlags(bool flag) { } } -/** - * Checks scene objects against the player's inventory items. If there are any - * matching names, it means the given item has already been picked up, and should - * be hidden in the scene. - */ void Scene::checkInventory() { for (uint shapeIdx = 0; shapeIdx < _bgShapes.size(); ++shapeIdx) { for (int invIdx = 0; invIdx < _vm->_inventory->_holdings; ++invIdx) { - if (scumm_stricmp(_bgShapes[shapeIdx]._name.c_str(), - (*_vm->_inventory)[invIdx]._name.c_str()) == 0) { + if (_bgShapes[shapeIdx]._name.equalsIgnoreCase((*_vm->_inventory)[invIdx]._name)) { _bgShapes[shapeIdx]._type = INVALID; break; } @@ -731,10 +696,6 @@ void Scene::checkInventory() { } } -/** - * Set up any entrance co-ordinates or entrance canimations, and then transition - * in the scene - */ void Scene::transitionToScene() { People &people = *_vm->_people; SaveManager &saves = *_vm->_saves; @@ -743,11 +704,6 @@ void Scene::transitionToScene() { Common::Point &hSavedPos = people._hSavedPos; int &hSavedFacing = people._hSavedFacing; - const int FS_TRANS[8] = { - STOP_UP, STOP_UPRIGHT, STOP_RIGHT, STOP_DOWNRIGHT, STOP_DOWN, - STOP_DOWNLEFT, STOP_LEFT, STOP_UPLEFT - }; - if (hSavedPos.x < 1) { // No exit information from last scene-check entrance info if (_entrance._startPosition.x < 1) { @@ -812,14 +768,14 @@ void Scene::transitionToScene() { // player is clear of the box switch (obj._aType) { case FLAG_SET: - for (int useNum = 0; useNum < 4; ++useNum) { + for (int useNum = 0; useNum < USE_COUNT; ++useNum) { if (obj._use[useNum]._useFlag) { if (!_vm->readFlags(obj._use[useNum]._useFlag)) _vm->setFlags(obj._use[useNum]._useFlag); } if (!talk._talkToAbort) { - for (int nameIdx = 0; nameIdx < 4; ++nameIdx) { + for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) { toggleObject(obj._use[useNum]._names[nameIdx]); } } @@ -854,15 +810,11 @@ void Scene::transitionToScene() { } } -/** - * Scans through the object list to find one with a matching name, and will - * call toggleHidden with all matches found. Returns the numer of matches found - */ int Scene::toggleObject(const Common::String &name) { int count = 0; for (uint idx = 0; idx < _bgShapes.size(); ++idx) { - if (scumm_stricmp(name.c_str(), _bgShapes[idx]._name.c_str()) == 0) { + if (name.equalsIgnoreCase(_bgShapes[idx]._name)) { ++count; _bgShapes[idx].toggleHidden(); } @@ -871,10 +823,6 @@ int Scene::toggleObject(const Common::String &name) { return count; } -/** - * Update the screen back buffer with all of the scene objects which need - * to be drawn - */ void Scene::updateBackground() { People &people = *_vm->_people; Screen &screen = *_vm->_screen; @@ -894,27 +842,27 @@ void Scene::updateBackground() { // 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 & 2); + screen._backBuffer->transBlitFrom(*_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, - _canimShapes[idx]._position, _canimShapes[idx]._flags & 2); + _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 & 2); + screen._backBuffer->transBlitFrom(*_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, - _canimShapes[idx]._flags & 2); + _canimShapes[idx]._flags & OBJ_FLIPPED); } // Draw the player if he's active @@ -931,7 +879,8 @@ void Scene::updateBackground() { 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, _bgShapes[idx]._flags & 2); + screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, + _bgShapes[idx]._flags & OBJ_FLIPPED); } // Draw all static and active canimations that are NORMAL and are in front of the player @@ -939,7 +888,7 @@ void Scene::updateBackground() { 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, - _canimShapes[idx]._flags & 2); + _canimShapes[idx]._flags & OBJ_FLIPPED); } // Draw all static and active shapes that are FORWARD @@ -950,7 +899,8 @@ void Scene::updateBackground() { 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, _bgShapes[idx]._flags & 2); + screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, + _bgShapes[idx]._flags & OBJ_FLIPPED); } // Draw all static and active canimations that are forward @@ -958,15 +908,12 @@ void Scene::updateBackground() { 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, - _canimShapes[idx]._flags & 2); + _canimShapes[idx]._flags & OBJ_FLIPPED); } screen.resetDisplayBounds(); } -/** - * Check whether the passed area intersects with one of the scene's exits - */ Exit *Scene::checkForExit(const Common::Rect &r) { for (uint idx = 0; idx < _exits.size(); ++idx) { if (_exits[idx].intersects(r)) @@ -976,11 +923,6 @@ Exit *Scene::checkForExit(const Common::Rect &r) { return nullptr; } -/** - * Checks all the background shapes. If a background shape is animating, - * it will flag it as needing to be drawn. If a non-animating shape is - * colliding with another shape, it will also flag it as needing drawing - */ void Scene::checkBgShapes(ImageFrame *frame, const Common::Point &pt) { // Iterate through the shapes for (uint idx = 0; idx < _bgShapes.size(); ++idx) { @@ -989,9 +931,9 @@ void Scene::checkBgShapes(ImageFrame *frame, const Common::Point &pt) { if ((obj._flags & 5) == 1) { obj._misc = (pt.y < (obj._position.y + obj.frameHeight() - 1)) ? NORMAL_FORWARD : NORMAL_BEHIND; - } else if (!(obj._flags & 1)) { + } else if (!(obj._flags & OBJ_BEHIND)) { obj._misc = BEHIND; - } else if (obj._flags & 4) { + } else if (obj._flags & OBJ_FORWARD) { obj._misc = FORWARD; } } @@ -1015,14 +957,6 @@ void Scene::checkBgShapes(ImageFrame *frame, const Common::Point &pt) { } } -/** - * Attempt to start a canimation sequence. It will load the requisite graphics, and - * then copy the canim object into the _canimShapes array to start the animation. - * - * @param cAnimNum The canim object within the current scene - * @param playRate Play rate. 0 is invalid; 1=normal speed, 2=1/2 speed, etc. - * A negative playRate can also be specified to play the animation in reverse - */ int Scene::startCAnim(int cAnimNum, int playRate) { Events &events = *_vm->_events; Map &map = *_vm->_map; @@ -1070,7 +1004,7 @@ int Scene::startCAnim(int cAnimNum, int playRate) { if (talk._talkToAbort) return 1; - // Add new anim shape entry for displaying the animationo + // Add new anim shape entry for displaying the animation _canimShapes.push_back(Object()); Object &cObj = _canimShapes[_canimShapes.size() - 1]; @@ -1235,9 +1169,6 @@ int Scene::startCAnim(int cAnimNum, int playRate) { return 1; } -/** - * Animate all objects and people. - */ void Scene::doBgAnim() { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; @@ -1333,7 +1264,7 @@ void Scene::doBgAnim() { for (uint idx = 0; idx < _bgShapes.size(); ++idx) { Object &o = _bgShapes[idx]; - if (o._type == NO_SHAPE && ((o._flags & 1) == 0)) { + if (o._type == NO_SHAPE && ((o._flags & OBJ_BEHIND) == 0)) { // Restore screen area screen._backBuffer->blitFrom(screen._backBuffer2, o._position, Common::Rect(o._position.x, o._position.y, @@ -1384,14 +1315,14 @@ void Scene::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 & 2); + screen._backBuffer->transBlitFrom(*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 & 2); + screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); } } @@ -1399,14 +1330,14 @@ void Scene::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 & 2); + screen._backBuffer->transBlitFrom(*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 & 2); + screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); } } @@ -1427,14 +1358,14 @@ void Scene::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 & 2); + screen._backBuffer->transBlitFrom(*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 & 2); + screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); } } @@ -1442,27 +1373,27 @@ void Scene::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 & 2); + screen._backBuffer->transBlitFrom(*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, - people._portrait._position, people._portrait._flags & 2); + 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 & 2); + screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); } } // Draw all NO_SHAPE shapes which have flag bit 0 clear for (uint idx = 0; idx < _bgShapes.size(); ++idx) { Object &o = _bgShapes[idx]; - if (o._type == NO_SHAPE && (o._flags & 1) == 0) - screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & 2); + if (o._type == NO_SHAPE && (o._flags & OBJ_BEHIND) == 0) + screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED); } // Bring the newly built picture to the screen @@ -1470,7 +1401,7 @@ void Scene::doBgAnim() { _animating = 0; screen.slamRect(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT)); } else { - if (people[AL]._type != INVALID && ((_goToScene == -1 || _canimShapes.size() == 0))) { + if (people[AL]._type != INVALID && ((_goToScene == -1 || _canimShapes.empty()))) { if (people[AL]._type == REMOVE) { screen.slamRect(Common::Rect( people[AL]._oldPosition.x, people[AL]._oldPosition.y, @@ -1517,7 +1448,7 @@ void Scene::doBgAnim() { if (_goToScene == -1) { for (uint idx = 0; idx < _bgShapes.size(); ++idx) { Object &o = _bgShapes[idx]; - if (o._type == NO_SHAPE && (o._flags & 1) == 0) { + if (o._type == NO_SHAPE && (o._flags & OBJ_BEHIND) == 0) { screen.slamArea(o._position.x, o._position.y, o._oldSize.x, o._oldSize.y); screen.slamArea(o._oldPosition.x, o._oldPosition.y, o._oldSize.x, o._oldSize.y); } else if (o._type == HIDE_SHAPE) { @@ -1565,10 +1496,6 @@ void Scene::doBgAnim() { } } -/** - * Attempts to find a background shape within the passed bounds. If found, - * it will return the shape number, or -1 on failure. - */ int Scene::findBgShape(const Common::Rect &r) { if (!_doBgAnimDone) // New frame hasn't been drawn yet @@ -1589,10 +1516,6 @@ int Scene::findBgShape(const Common::Rect &r) { return -1; } -/** - * Checks to see if the given position in the scene belongs to a given zone type. - * If it is, the zone is activated and used just like a TAKL zone or aFLAG_SET zone. - */ int Scene::checkForZones(const Common::Point &pt, int zoneType) { int matches = 0; @@ -1612,9 +1535,6 @@ int Scene::checkForZones(const Common::Point &pt, int zoneType) { return matches; } -/** - * Check which zone the the given position is located in. - */ int Scene::whichZone(const Common::Point &pt) { for (uint idx = 0; idx < _zones.size(); ++idx) { if (_zones[idx].contains(pt)) @@ -1624,9 +1544,6 @@ int Scene::whichZone(const Common::Point &pt) { return -1; } -/** - * Returns the index of the closest zone to a given point. - */ int Scene::closestZone(const Common::Point &pt) { int dist = 1000; int zone = -1; @@ -1646,9 +1563,6 @@ int Scene::closestZone(const Common::Point &pt) { return zone; } -/** - * Synchronize the data for a savegame - */ void Scene::synchronize(Common::Serializer &s) { if (s.isSaving()) saveSceneStatus(); diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h index 9454a4e20b..0cbd775c56 100644 --- a/engines/sherlock/scene.h +++ b/engines/sherlock/scene.h @@ -57,14 +57,21 @@ struct BgFileHeader { BgFileHeader(); - void synchronize(Common::SeekableReadStream &s, bool isRoseTattoo); + + /** + * Load the data for the object + */ + void load(Common::SeekableReadStream &s, bool isRoseTattoo); }; -struct BgfileheaderInfo { +struct BgFileHeaderInfo { int _filesize; // How long images are int _maxFrames; // How many unique frames in object Common::String _filename; // Filename of object + /** + * Load the data for the object + */ void load(Common::SeekableReadStream &s); }; @@ -78,6 +85,9 @@ public: Common::String _dest; int _image; // Arrow image to use + /** + * Load the data for the object + */ void load(Common::SeekableReadStream &s, bool isRoseTattoo); }; @@ -86,6 +96,9 @@ struct SceneEntry { int _startDir; int _allow; + /** + * Load the data for the object + */ void load(Common::SeekableReadStream &s); }; @@ -93,11 +106,17 @@ struct SceneSound { Common::String _name; int _priority; + /** + * Load the data for the object + */ void load(Common::SeekableReadStream &s); }; -class ObjectArray: public Common::Array<Object> { +class ObjectArray : public Common::Array<Object> { public: + /** + * Retuurn the index of the passed object in the array + */ int indexOf(const Object &obj) const; }; @@ -113,33 +132,61 @@ class Scene { private: SherlockEngine *_vm; Common::String _rrmName; - int _selector; - bool _lookHelp; bool _loadingSavedGame; + /** + * Loads the data associated for a given scene. The .BGD file's format is: + * BGHEADER: Holds an index for the rest of the file + * STRUCTS: The objects for the scene + * IMAGES: The graphic information for the structures + * + * The _misc field of the structures contains the number of the graphic image + * that it should point to after loading; _misc is then set to 0. + */ bool loadScene(const Common::String &filename); + /** + * Loads sounds for the scene + */ void loadSceneSounds(); + /** + * Set objects to their current persistent state. This includes things such as + * opening or moving them + */ void checkSceneStatus(); + /** + * Checks scene objects against the player's inventory items. If there are any + * matching names, it means the given item has already been picked up, and should + * be hidden in the scene. + */ void checkInventory(); + /** + * Set up any entrance co-ordinates or entrance canimations, and then transition + * in the scene + */ void transitionToScene(); + /** + * Checks all the background shapes. If a background shape is animating, + * it will flag it as needing to be drawn. If a non-animating shape is + * colliding with another shape, it will also flag it as needing drawing + */ void checkBgShapes(ImageFrame *frame, const Common::Point &pt); + /** + * Restores objects to the correct status. This ensures that things like being opened or moved + * will remain the same on future visits to the scene + */ void saveSceneStatus(); public: int _currentScene; int _goToScene; - bool _changes; bool _sceneStats[SCENES_COUNT][65]; bool _savedStats[SCENES_COUNT][9]; - int _keyboardInput; - int _oldKey, _help, _oldHelp; - int _oldTemp, _temp; bool _walkedInScene; int _version; bool _lzwMode; @@ -165,37 +212,84 @@ public: bool _doBgAnimDone; int _tempFadeStyle; int _cAnimFramePause; - bool _invLookFlag; public: Scene(SherlockEngine *vm); ~Scene(); + /** + * Handles loading the scene specified by _goToScene + */ void selectScene(); + /** + * Fres all the graphics and other dynamically allocated data for the scene + */ void freeScene(); + /** + * Check the scene's objects against the game flags. If false is passed, + * it means the scene has just been loaded. A value of true means that the scene + * is in use (ie. not just loaded) + */ void checkSceneFlags(bool mode); + /** + * Check whether the passed area intersects with one of the scene's exits + */ Exit *checkForExit(const Common::Rect &r); + /** + * Attempt to start a canimation sequence. It will load the requisite graphics, and + * then copy the canim object into the _canimShapes array to start the animation. + * + * @param cAnimNum The canim object within the current scene + * @param playRate Play rate. 0 is invalid; 1=normal speed, 2=1/2 speed, etc. + * A negative playRate can also be specified to play the animation in reverse + */ int startCAnim(int cAnimNum, int playRate); + /** + * Scans through the object list to find one with a matching name, and will + * call toggleHidden with all matches found. Returns the numer of matches found + */ int toggleObject(const Common::String &name); + /** + * Animate all objects and people. + */ void doBgAnim(); - void clearInfo(); - + /** + * Attempts to find a background shape within the passed bounds. If found, + * it will return the shape number, or -1 on failure. + */ int findBgShape(const Common::Rect &r); + /** + * Checks to see if the given position in the scene belongs to a given zone type. + * If it is, the zone is activated and used just like a TAKL zone or aFLAG_SET zone. + */ int checkForZones(const Common::Point &pt, int zoneType); + /** + * Check which zone the the given position is located in. + */ int whichZone(const Common::Point &pt); + /** + * Returns the index of the closest zone to a given point. + */ int closestZone(const Common::Point &pt); + /** + * Update the screen back buffer with all of the scene objects which need + * to be drawn + */ void updateBackground(); + /** + * Synchronize the data for a savegame + */ void synchronize(Common::Serializer &s); }; diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp index 349bf4d024..24f7660743 100644 --- a/engines/sherlock/screen.cpp +++ b/engines/sherlock/screen.cpp @@ -41,10 +41,6 @@ Screen::Screen(SherlockEngine *vm) : Surface(g_system->getWidth(), g_system->get Common::fill(&_tMap[0], &_tMap[PALETTE_SIZE], 0); setFont(1); - // Set dummy surface used for restricted scene drawing - _sceneSurface.format = Graphics::PixelFormat::createFormatCLUT8(); - _sceneSurface.pitch = pitch; - // Rose Tattoo specific fields _fadeBytesRead = _fadeBytesToRead = 0; _oldFadePercent = 0; @@ -57,10 +53,11 @@ Screen::~Screen() { delete _font; } -/** - * Set the font to use for writing text on the screen - */ void Screen::setFont(int fontNumb) { + // Interactive demo doesn't use fonts + if (!_vm->_interactiveFl) + return; + _fontNumber = fontNumb; Common::String fname = Common::String::format("FONT%d.VGS", fontNumb + 1); @@ -74,9 +71,6 @@ void Screen::setFont(int fontNumb) { _fontHeight = MAX((uint16)_fontHeight, (*_font)[idx]._frame.h); } -/** - * Handles updating any dirty areas of the screen Surface object to the physical screen - */ void Screen::update() { // Merge the dirty rects mergeDirtyRects(); @@ -86,7 +80,7 @@ void Screen::update() { 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, + g_system->copyRectToScreen(srcP, _surface.pitch, r.left, r.top, r.width(), r.height()); } @@ -95,23 +89,14 @@ void Screen::update() { _dirtyRects.clear(); } -/** - * Return the currently active palette - */ void Screen::getPalette(byte palette[PALETTE_SIZE]) { g_system->getPaletteManager()->grabPalette(palette, 0, PALETTE_COUNT); } -/** - * Set the palette - */ void Screen::setPalette(const byte palette[PALETTE_SIZE]) { g_system->getPaletteManager()->setPalette(palette, 0, PALETTE_COUNT); } -/** - * Fades from the currently active palette to the passed palette - */ int Screen::equalizePalette(const byte palette[PALETTE_SIZE]) { int total = 0; byte tempPalette[PALETTE_SIZE]; @@ -120,8 +105,7 @@ int Screen::equalizePalette(const byte palette[PALETTE_SIZE]) { // For any palette component that doesn't already match the given destination // palette, change by 1 towards the reference palette component for (int idx = 0; idx < PALETTE_SIZE; ++idx) { - if (tempPalette[idx] > palette[idx]) - { + if (tempPalette[idx] > palette[idx]) { tempPalette[idx] = MAX((int)palette[idx], (int)tempPalette[idx] - 4); ++total; } else if (tempPalette[idx] < palette[idx]) { @@ -137,9 +121,6 @@ int Screen::equalizePalette(const byte palette[PALETTE_SIZE]) { return total; } -/** - * Fade out the palette to black - */ void Screen::fadeToBlack(int speed) { byte tempPalette[PALETTE_SIZE]; Common::fill(&tempPalette[0], &tempPalette[PALETTE_SIZE], 0); @@ -149,12 +130,9 @@ void Screen::fadeToBlack(int speed) { } setPalette(tempPalette); - fillRect(Common::Rect(0, 0, this->w, this->h), 0); + fillRect(Common::Rect(0, 0, _surface.w, _surface.h), 0); } -/** - * Fade in a given palette - */ void Screen::fadeIn(const byte palette[PALETTE_SIZE], int speed) { int count = 50; while (equalizePalette(palette) && --count) { @@ -164,18 +142,11 @@ void Screen::fadeIn(const byte palette[PALETTE_SIZE], int speed) { setPalette(palette); } -/** - * Adds a rectangle to the list of modified areas of the screen during the - * current frame - */ void Screen::addDirtyRect(const Common::Rect &r) { _dirtyRects.push_back(r); assert(r.width() > 0 && r.height() > 0); } -/** - * Merges together overlapping dirty areas of the screen - */ void Screen::mergeDirtyRects() { Common::List<Common::Rect>::iterator rOuter, rInner; @@ -200,9 +171,6 @@ void Screen::mergeDirtyRects() { } } -/** - * Returns the union of two dirty area rectangles - */ bool Screen::unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2) { destRect = src1; destRect.extend(src2); @@ -210,9 +178,6 @@ bool Screen::unionRectangle(Common::Rect &destRect, const Common::Rect &src1, co return !destRect.isEmpty(); } -/** - * Do a random pixel transition in from _backBuffer surface to the screen - */ void Screen::randomTransition() { Events &events = *_vm->_events; const int TRANSITION_MULTIPLIER = 0x15a4e35; @@ -220,15 +185,15 @@ void Screen::randomTransition() { for (int idx = 0; idx <= 65535 && !_vm->shouldQuit(); ++idx) { _transitionSeed = _transitionSeed * TRANSITION_MULTIPLIER + 1; - int offset = _transitionSeed & 65535; + int offset = _transitionSeed & 0xFFFF; - if (offset < (this->w * this->h)) + if (offset < (this->w() * this->h())) *((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, this->w, this->h)); + addDirtyRect(Common::Rect(0, 0, _surface.w, _surface.h)); events.pollEvents(); events.delay(1); @@ -239,18 +204,15 @@ void Screen::randomTransition() { blitFrom(*_backBuffer); } -/** - * Transition to the surface from _backBuffer using a vertical transition - */ void Screen::verticalTransition() { Events &events = *_vm->_events; 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->h(); ++yp) { + for (int xp = 0; xp < this->w(); ++xp) { + int temp = (table[xp] >= (this->h() - 3)) ? this->h() - table[xp] : _vm->getRandomNumber(3) + 1; if (temp) { @@ -264,43 +226,30 @@ void Screen::verticalTransition() { } } -/** - * Copies a section of the second back buffer into the main back buffer - */ void Screen::restoreBackground(const Common::Rect &r) { if (r.width() > 0 && r.height() > 0) { Common::Rect tempRect = r; - tempRect.clip(Common::Rect(0, 0, this->w, SHERLOCK_SCENE_HEIGHT)); + tempRect.clip(Common::Rect(0, 0, this->w(), SHERLOCK_SCENE_HEIGHT)); if (tempRect.isValidRect()) _backBuffer1.blitFrom(_backBuffer2, Common::Point(tempRect.left, tempRect.top), tempRect); } } -/** - * Copies a given area to the screen - */ void Screen::slamArea(int16 xp, int16 yp, int16 width, int16 height) { slamRect(Common::Rect(xp, yp, xp + width, yp + height)); } -/** - * Copies a given area to the screen - */ void Screen::slamRect(const Common::Rect &r) { if (r.width() && r.height() > 0) { Common::Rect tempRect = r; - tempRect.clip(Common::Rect(0, 0, this->w, this->h)); + tempRect.clip(Common::Rect(0, 0, this->w(), this->h())); if (tempRect.isValidRect()) blitFrom(*_backBuffer, Common::Point(tempRect.left, tempRect.top), tempRect); } } -/** - * Copy an image from the back buffer to the screen, taking care of both the - * new area covered by the shape as well as the old area, which must be restored - */ void Screen::flushImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp, int16 *width, int16 *height) { Common::Point imgPos = pt + frame->_offset; @@ -327,19 +276,12 @@ void Screen::flushImage(ImageFrame *frame, const Common::Point &pt, *height = newBounds.height(); } -/** - * Prints the text passed onto the back buffer at the given position and color. - * The string is then blitted to the screen - */ void Screen::print(const Common::Point &pt, byte color, const char *formatStr, ...) { // Create the string to display - char buffer[100]; va_list args; - va_start(args, formatStr); - vsprintf(buffer, formatStr, args); + Common::String str = Common::String::vformat(formatStr, args); va_end(args); - Common::String str(buffer); // Figure out area to draw text in Common::Point pos = pt; @@ -347,13 +289,13 @@ void Screen::print(const Common::Point &pt, byte 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->w() - 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->w()) + textBounds.moveTo(this->w() - width, textBounds.top); + if (textBounds.bottom > this->h()) + textBounds.moveTo(textBounds.left, this->h() - _fontHeight); // Write out the string at the given position writeString(str, Common::Point(textBounds.left, textBounds.top), color); @@ -362,27 +304,17 @@ void Screen::print(const Common::Point &pt, byte color, const char *formatStr, . slamRect(textBounds); } -/** - * Print a strings onto the back buffer without blitting it to the screen - */ void Screen::gPrint(const Common::Point &pt, byte color, const char *formatStr, ...) { // Create the string to display - char buffer[100]; va_list args; - va_start(args, formatStr); - vsprintf(buffer, formatStr, args); + Common::String str = Common::String::vformat(formatStr, args); va_end(args); - Common::String str(buffer); // Print the text writeString(str, pt, color); } - -/** - * Returns the width of a string in pixels - */ int Screen::stringWidth(const Common::String &str) { int width = 0; @@ -392,21 +324,15 @@ int Screen::stringWidth(const Common::String &str) { return width; } -/** - * Returns the width of a character in pixels - */ int Screen::charWidth(char c) { if (c == ' ') return 5; - else if (c > ' ' && c <= '~') + else if (Common::isPrint(c)) return (*_font)[c - 33]._frame.w + 1; else return 0; } -/** - * Draws the given string into the back buffer using the images stored in _font - */ void Screen::writeString(const Common::String &str, const Common::Point &pt, byte color) { Common::Point charPos = pt; @@ -414,7 +340,7 @@ void Screen::writeString(const Common::String &str, const Common::Point &pt, byt if (*c == ' ') charPos.x += 5; else { - assert(*c > ' ' && *c <= '~'); + assert(Common::isPrint(*c)); ImageFrame &frame = (*_font)[*c - 33]; _backBuffer->transBlitFrom(frame, charPos, false, color); charPos.x += frame._frame.w + 1; @@ -422,17 +348,11 @@ void Screen::writeString(const Common::String &str, const Common::Point &pt, byt } } -/** - * Fills an area on the back buffer, and then copies it to the screen - */ void Screen::vgaBar(const Common::Rect &r, int color) { _backBuffer->fillRect(r, color); slamRect(r); } -/** - * Draws a button for use in the inventory, talk, and examine dialogs. - */ void Screen::makeButton(const Common::Rect &bounds, int textX, const Common::String &str) { @@ -448,10 +368,6 @@ void Screen::makeButton(const Common::Rect &bounds, int textX, COMMAND_FOREGROUND, "%s", str.c_str() + 1); } -/** - * Prints an interface command with the first letter highlighted to indicate - * what keyboard shortcut is associated with it - */ void Screen::buttonPrint(const Common::Point &pt, byte color, bool slamIt, const Common::String &str) { int xStart = pt.x - stringWidth(str) / 2; @@ -461,22 +377,19 @@ void Screen::buttonPrint(const Common::Point &pt, byte color, bool slamIt, if (slamIt) { print(Common::Point(xStart, pt.y + 1), COMMAND_HIGHLIGHTED, "%c", str[0]); print(Common::Point(xStart + charWidth(str[0]), pt.y + 1), - COMMAND_FOREGROUND, str.c_str() + 1); + COMMAND_FOREGROUND, "%s", str.c_str() + 1); } else { gPrint(Common::Point(xStart, pt.y), COMMAND_HIGHLIGHTED, "%c", str[0]); gPrint(Common::Point(xStart + charWidth(str[0]), pt.y), - COMMAND_FOREGROUND, str.c_str() + 1); + COMMAND_FOREGROUND, "%s", str.c_str() + 1); } } else if (slamIt) { - print(Common::Point(xStart, pt.y + 1), color, str.c_str()); + print(Common::Point(xStart, pt.y + 1), color, "%s", str.c_str()); } else { - gPrint(Common::Point(xStart, pt.y), color, str.c_str()); + gPrint(Common::Point(xStart, pt.y), color, "%s", str.c_str()); } } -/** - * Draw a panel in th eback buffer with a raised area effect around the edges - */ void Screen::makePanel(const Common::Rect &r) { _backBuffer->fillRect(r, BUTTON_MIDDLE); _backBuffer->hLine(r.left, r.top, r.right - 2, BUTTON_TOP); @@ -490,36 +403,30 @@ void Screen::makePanel(const Common::Rect &r) { _backBuffer->hLine(r.left + 1, r.bottom - 2, r.right - 1, BUTTON_BOTTOM); } -/** - * Sets the active back buffer pointer to a restricted sub-area of the first back buffer - */ +void Screen::makeField(const Common::Rect &r) { + _backBuffer->fillRect(r, BUTTON_MIDDLE); + _backBuffer->hLine(r.left, r.top, r.right - 1, BUTTON_BOTTOM); + _backBuffer->hLine(r.left + 1, r.bottom - 1, r.right - 1, BUTTON_TOP); + _backBuffer->vLine(r.left, r.top + 1, r.bottom - 1, BUTTON_BOTTOM); + _backBuffer->vLine(r.right - 1, r.top + 1, r.bottom - 2, BUTTON_TOP); +} + void Screen::setDisplayBounds(const Common::Rect &r) { assert(r.left == 0 && r.top == 0); - _sceneSurface.setPixels(_backBuffer1.getPixels()); - _sceneSurface.w = r.width(); - _sceneSurface.h = r.height(); + _sceneSurface.setPixels(_backBuffer1.getPixels(), r.width(), r.height()); _backBuffer = &_sceneSurface; } -/** - * Resets the active buffer pointer to point back to the full first back buffer - */ void Screen::resetDisplayBounds() { _backBuffer = &_backBuffer1; } -/** - * Return the size of the current display window - */ 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.w(), _sceneSurface.h()) : + Common::Rect(0, 0, this->w(), this->h()); } -/** - * Synchronize the data for a savegame - */ void Screen::synchronize(Common::Serializer &s) { int fontNumb = _fontNumber; s.syncAsByte(fontNumb); diff --git a/engines/sherlock/screen.h b/engines/sherlock/screen.h index 8a8eca13fc..f4cd6fd955 100644 --- a/engines/sherlock/screen.h +++ b/engines/sherlock/screen.h @@ -36,22 +36,22 @@ namespace Sherlock { #define VGA_COLOR_TRANS(x) ((x) * 255 / 63) enum { - INFO_BLACK = 1, - INFO_FOREGROUND = 11, - INFO_BACKGROUND = 1, - BORDER_COLOR = 237, - INV_FOREGROUND = 14, - INV_BACKGROUND = 1, - COMMAND_HIGHLIGHTED = 10, - COMMAND_FOREGROUND = 15, - COMMAND_BACKGROUND = 4, - COMMAND_NULL = 248, - BUTTON_TOP = 233, - BUTTON_MIDDLE = 244, - BUTTON_BOTTOM = 248, - TALK_FOREGROUND = 12, - TALK_NULL = 16, - PEN_COLOR = 250 + INFO_BLACK = 1, + INFO_FOREGROUND = 11, + INFO_BACKGROUND = 1, + BORDER_COLOR = 237, + INV_FOREGROUND = 14, + INV_BACKGROUND = 1, + COMMAND_HIGHLIGHTED = 10, + COMMAND_FOREGROUND = 15, + COMMAND_BACKGROUND = 4, + COMMAND_NULL = 248, + BUTTON_TOP = 233, + BUTTON_MIDDLE = 244, + BUTTON_BOTTOM = 248, + TALK_FOREGROUND = 12, + TALK_NULL = 16, + PEN_COLOR = 250 }; class SherlockEngine; @@ -75,12 +75,25 @@ private: int _currentScroll; int _targetScroll; 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); + /** + * Draws the given string into the back buffer using the images stored in _font + */ void writeString(const Common::String &str, const Common::Point &pt, byte color); 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: Surface _backBuffer1, _backBuffer2; @@ -93,53 +106,141 @@ public: Screen(SherlockEngine *vm); virtual ~Screen(); + /** + * Set the font to use for writing text on the screen + */ void setFont(int fontNumber); + /** + * Handles updating any dirty areas of the screen Surface object to the physical screen + */ void update(); + /** + * 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]); + /** + * Fade out the palette to black + */ void fadeToBlack(int speed = 2); + /** + * Fade in a given palette + */ void fadeIn(const byte palette[PALETTE_SIZE], int speed = 2); + /** + * Do a random pixel transition in from _backBuffer surface to the screen + */ void randomTransition(); + /** + * Transition to the surface from _backBuffer using a vertical transition + */ void verticalTransition(); - void print(const Common::Point &pt, byte color, const char *formatStr, ...); - void gPrint(const Common::Point &pt, byte color, const char *formatStr, ...); + /** + * Prints the text passed onto the back buffer at the given position and color. + * The string is then blitted to the screen + */ + void print(const Common::Point &pt, byte color, const char *formatStr, ...) GCC_PRINTF(4, 5); + /** + * Print a strings onto the back buffer without blitting it to the screen + */ + void gPrint(const Common::Point &pt, byte color, const char *formatStr, ...) GCC_PRINTF(4, 5); + + /** + * Copies a section of the second back buffer into the main back buffer + */ void restoreBackground(const Common::Rect &r); + /** + * Copies a given area to the screen + */ void slamArea(int16 xp, int16 yp, int16 width, int16 height); + + /** + * Copies a given area to the screen + */ void slamRect(const Common::Rect &r); + /** + * Copy an image from the back buffer to the screen, taking care of both the + * new area covered by the shape as well as the old area, which must be restored + */ void flushImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp, int16 *width, int16 *height); + /** + * Returns the width of a string in pixels + */ int stringWidth(const Common::String &str); + /** + * Returns the width of a character in pixels + */ int charWidth(char c); + /** + * Fills an area on the back buffer, and then copies it to the screen + */ void vgaBar(const Common::Rect &r, int color); + /** + * Draws a button for use in the inventory, talk, and examine dialogs. + */ void makeButton(const Common::Rect &bounds, int textX, const Common::String &str); + /** + * Prints an interface command with the first letter highlighted to indicate + * what keyboard shortcut is associated with it + */ void buttonPrint(const Common::Point &pt, byte color, bool slamIt, const Common::String &str); + /** + * Draw a panel in the back buffer with a raised area effect around the edges + */ void makePanel(const Common::Rect &r); + /** + * Draw a field in the back buffer with a raised area effect around the edges, + * suitable for text input. + */ + void makeField(const Common::Rect &r); + + /** + * Sets the active back buffer pointer to a restricted sub-area of the first back buffer + */ void setDisplayBounds(const Common::Rect &r); + + /** + * Resets the active buffer pointer to point back to the full first back buffer + */ void resetDisplayBounds(); + + /** + * Return the size of the current display window + */ Common::Rect getDisplayBounds(); int fontNumber() const { return _fontNumber; } + /** + * Synchronize the data for a savegame + */ void synchronize(Common::Serializer &s); // Rose Tattoo specific methods diff --git a/engines/sherlock/settings.cpp b/engines/sherlock/settings.cpp index 73c99bfa82..cae5c6c67a 100644 --- a/engines/sherlock/settings.cpp +++ b/engines/sherlock/settings.cpp @@ -25,7 +25,7 @@ namespace Sherlock { -const int SETUP_POINTS[12][4] = { +static const int SETUP_POINTS[12][4] = { { 4, 154, 101, 53 }, // Exit { 4, 165, 101, 53 }, // Music Toggle { 219, 165, 316, 268 }, // Voice Toggle @@ -40,21 +40,17 @@ const int SETUP_POINTS[12][4] = { { 219, 187, 316, 268 } // _key Pad Accel. Toggle }; -const char *const SETUP_STRS0[2] = { "off", "on" }; -const char *const SETUP_STRS1[2] = { "Directly", "by Pixel" }; -const char *const SETUP_STRS2[2] = { "Left", "Right" }; -const char *const SETUP_STRS3[2] = { "Appear", "Slide" }; -const char *const SETUP_STRS4[2] = { "Slow", "Fast" }; -const char *const SETUP_STRS5[2] = { "Left", "Right" }; -const char *const SETUP_NAMES[12] = { +static const char *const SETUP_STRS0[2] = { "off", "on" }; +static const char *const SETUP_STRS1[2] = { "Directly", "by Pixel" }; +static const char *const SETUP_STRS2[2] = { "Left", "Right" }; +static const char *const SETUP_STRS3[2] = { "Appear", "Slide" }; +static const char *const SETUP_STRS5[2] = { "Left", "Right" }; +static const char *const SETUP_NAMES[12] = { "Exit", "M", "V", "S", "B", "New Font Style", "J", "Calibrate Joystick", "F", "W", "P", "K" }; /*----------------------------------------------------------------*/ -/** - * Draws the interface for the settings window - */ void Settings::drawInteface(bool flag) { People &people = *_vm->_people; Screen &screen = *_vm->_screen; @@ -108,7 +104,7 @@ void Settings::drawInteface(bool flag) { screen.makeButton(Common::Rect(SETUP_POINTS[8][0], SETUP_POINTS[8][1], SETUP_POINTS[8][2], SETUP_POINTS[8][1] + 10), SETUP_POINTS[8][3] - screen.stringWidth(tempStr) / 2, tempStr); - tempStr = Common::String::format("Windows %s", ui._windowStyle ? "Slide" : "Appear"); + tempStr = Common::String::format("Windows %s", ui._slideWindows ? "Slide" : "Appear"); screen.makeButton(Common::Rect(SETUP_POINTS[9][0], SETUP_POINTS[9][1], SETUP_POINTS[9][2], SETUP_POINTS[9][1] + 10), SETUP_POINTS[9][3] - screen.stringWidth(tempStr) / 2, tempStr); @@ -123,7 +119,7 @@ void Settings::drawInteface(bool flag) { // Show the window immediately, or slide it on-screen if (!flag) { - if (!ui._windowStyle) { + if (!ui._slideWindows) { screen.slamRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); } else { ui.summonWindow(true, CONTROLS_Y1); @@ -135,9 +131,6 @@ void Settings::drawInteface(bool flag) { } } -/** - * Draws the buttons for the settings dialog - */ int Settings::drawButtons(const Common::Point &pt, int _key) { Events &events = *_vm->_events; People &people = *_vm->_people; @@ -150,7 +143,7 @@ int Settings::drawButtons(const Common::Point &pt, int _key) { for (int idx = 0; idx < 12; ++idx) { if ((pt.x > SETUP_POINTS[idx][0] && pt.x < SETUP_POINTS[idx][2] && pt.y > SETUP_POINTS[idx][1] - && pt.y < (SETUP_POINTS[idx][1] + 10) && (events._released || events._released)) + && pt.y < (SETUP_POINTS[idx][1] + 10) && (events._pressed || events._released)) || (_key == SETUP_NAMES[idx][0])) { found = idx; color = COMMAND_HIGHLIGHTED; @@ -189,7 +182,7 @@ int Settings::drawButtons(const Common::Point &pt, int _key) { screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr); break; case 9: - tempStr = Common::String::format("Windows %s", SETUP_STRS3[ui._windowStyle]); + tempStr = Common::String::format("Windows %s", SETUP_STRS3[ui._slideWindows]); screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr); break; case 10: @@ -209,13 +202,6 @@ int Settings::drawButtons(const Common::Point &pt, int _key) { return found; } - -/** -* Handles input when the settings window is being shown -* @remarks Whilst this would in theory be better in the Journal class, since it displays in -* the user interface, it uses so many internal UI fields, that it sort of made some sense -* to put it in the UserInterface class. -*/ void Settings::show(SherlockEngine *vm) { Events &events = *vm->_events; People &people = *vm->_people; @@ -255,7 +241,7 @@ void Settings::show(SherlockEngine *vm) { if (ui._key == Common::KEYCODE_RETURN || ui._key == Common::KEYCODE_SPACE) { events._pressed = false; events._oldButtons = 0; - ui._keycode = Common::KEYCODE_INVALID; + ui._keyPress = '\0'; events._released = true; } } @@ -323,7 +309,7 @@ void Settings::show(SherlockEngine *vm) { if ((found == 9 && events._released) || ui._key == 'W') { // Window style - ui._windowStyle ^= 1; + ui._slideWindows = !ui._slideWindows; updateConfig = true; settings.drawInteface(true); } @@ -341,7 +327,7 @@ void Settings::show(SherlockEngine *vm) { if (updateConfig) vm->saveConfig(); - ui._keycode = Common::KEYCODE_INVALID; + ui._keyPress = '\0'; ui._keyboardInput = false; ui._windowBounds.top = CONTROLS_Y1; ui._key = -1; diff --git a/engines/sherlock/settings.h b/engines/sherlock/settings.h index 25d27d48df..fc5fb2959f 100644 --- a/engines/sherlock/settings.h +++ b/engines/sherlock/settings.h @@ -36,10 +36,22 @@ private: Settings(SherlockEngine *vm) : _vm(vm) {} + /** + * Draws the interface for the settings window + */ void drawInteface(bool flag); + /** + * Draws the buttons for the settings dialog + */ int drawButtons(const Common::Point &pt, int key); public: + /** + * Handles input when the settings window is being shown + * @remarks Whilst this would in theory be better in the Journal class, since it displays in + * the user interface, it uses so many internal UI fields, that it sort of made some sense + * to put it in the UserInterface class. + */ static void show(SherlockEngine *vm); }; diff --git a/engines/sherlock/sherlock.cpp b/engines/sherlock/sherlock.cpp index 80a4383bdf..5973823f96 100644 --- a/engines/sherlock/sherlock.cpp +++ b/engines/sherlock/sherlock.cpp @@ -48,6 +48,7 @@ SherlockEngine::SherlockEngine(OSystem *syst, const SherlockGameDescription *gam _loadGameSlot = -1; _canLoadSave = false; _showOriginalSavesDialog = false; + _interactiveFl = true; } SherlockEngine::~SherlockEngine() { @@ -67,15 +68,21 @@ SherlockEngine::~SherlockEngine() { delete _res; } -/** - * Does basic initialization of the game engine - */ void SherlockEngine::initialize() { DebugMan.addDebugChannel(kDebugScript, "scripts", "Script debug level"); ImageFile::setVm(this); Object::setVm(this); Sprite::setVm(this); + + if (isDemo()) { + Common::File f; + // The interactive demo doesn't have an intro thus doesn't include TITLE.SND + // At the opposite, the non-interactive demo is only the intro. + if (f.exists("TITLE.SND")) + _interactiveFl = false; + } + _res = new Resources(this); _animation = new Animation(this); _debugger = new Debugger(this); @@ -95,9 +102,6 @@ void SherlockEngine::initialize() { loadConfig(); } -/** - * Main method for running the game - */ Common::Error SherlockEngine::run() { // Initialize the engine initialize(); @@ -116,7 +120,9 @@ Common::Error SherlockEngine::run() { _saves->loadGame(_loadGameSlot); _loadGameSlot = -1; } else { - showOpening(); + do + showOpening(); + while (!shouldQuit() && !_interactiveFl); } while (!shouldQuit()) { @@ -145,9 +151,6 @@ Common::Error SherlockEngine::run() { return Common::kNoError; } -/** - * Main loop for displaying a scene and handling all that occurs within it - */ void SherlockEngine::sceneLoop() { while (!shouldQuit() && _scene->_goToScene == -1) { // See if a script needs to be completed from either a goto room code, @@ -172,9 +175,6 @@ void SherlockEngine::sceneLoop() { } -/** - * Handle all player input - */ void SherlockEngine::handleInput() { _canLoadSave = true; _events->pollEventsAndWait(); @@ -186,9 +186,6 @@ void SherlockEngine::handleInput() { _ui->handleInput(); } -/** - * Read the state of a global flag - */ bool SherlockEngine::readFlags(int flagNum) { bool value = _flags[ABS(flagNum)]; if (flagNum < 0) @@ -197,40 +194,25 @@ bool SherlockEngine::readFlags(int flagNum) { return value; } -/** - * Sets a global flag to either true or false depending on whether the specified - * flag is positive or negative - */ void SherlockEngine::setFlags(int flagNum) { _flags[ABS(flagNum)] = flagNum >= 0; _scene->checkSceneFlags(true); } -/** - * Load game configuration esttings - */ void SherlockEngine::loadConfig() { // Load sound settings syncSoundSettings(); ConfMan.registerDefault("font", 1); - ConfMan.registerDefault("fade_style", true); - ConfMan.registerDefault("help_style", false); - ConfMan.registerDefault("window_style", 1); - ConfMan.registerDefault("portraits_on", true); - ConfMan.registerDefault("originalsaveload", false); _screen->setFont(ConfMan.getInt("font")); _screen->_fadeStyle = ConfMan.getBool("fade_style"); _ui->_helpStyle = ConfMan.getBool("help_style"); - _ui->_windowStyle = ConfMan.getInt("window_style"); + _ui->_slideWindows = ConfMan.getBool("window_style"); _people->_portraitsOn = ConfMan.getBool("portraits_on"); } -/** - * Saves game configuration information - */ void SherlockEngine::saveConfig() { ConfMan.setBool("mute", !_sound->_digitized); ConfMan.setBool("music_mute", !_sound->_music); @@ -239,15 +221,12 @@ void SherlockEngine::saveConfig() { ConfMan.setInt("font", _screen->fontNumber()); ConfMan.setBool("fade_style", _screen->_fadeStyle); ConfMan.setBool("help_style", _ui->_helpStyle); - ConfMan.setInt("window_style", _ui->_windowStyle); + ConfMan.setBool("window_style", _ui->_slideWindows); ConfMan.setBool("portraits_on", _people->_portraitsOn); ConfMan.flushToDisk(); } -/** - * Called by the engine when sound settings are updated - */ void SherlockEngine::syncSoundSettings() { Engine::syncSoundSettings(); @@ -255,39 +234,24 @@ void SherlockEngine::syncSoundSettings() { _sound->syncSoundSettings(); } -/** - * Synchronize the data for a savegame - */ void SherlockEngine::synchronize(Common::Serializer &s) { for (uint idx = 0; idx < _flags.size(); ++idx) s.syncAsByte(_flags[idx]); } -/** - * Returns true if a savegame can be loaded - */ bool SherlockEngine::canLoadGameStateCurrently() { return _canLoadSave; } -/** - * Returns true if the game can be saved - */ bool SherlockEngine::canSaveGameStateCurrently() { return _canLoadSave; } -/** - * Called by the GMM to load a savegame - */ Common::Error SherlockEngine::loadGameState(int slot) { _saves->loadGame(slot); return Common::kNoError; } -/** - * Called by the GMM to save the game - */ Common::Error SherlockEngine::saveGameState(int slot, const Common::String &desc) { _saves->saveGame(slot, desc); return Common::kNoError; diff --git a/engines/sherlock/sherlock.h b/engines/sherlock/sherlock.h index 2688b51d4c..bf8c0d6aaf 100644 --- a/engines/sherlock/sherlock.h +++ b/engines/sherlock/sherlock.h @@ -50,10 +50,6 @@ namespace Sherlock { enum { - kFileTypeHash -}; - -enum { kDebugScript = 1 << 0 }; @@ -62,8 +58,8 @@ enum GameType { GType_RoseTattoo = 1 }; -#define SHERLOCK_SCREEN_WIDTH _vm->_screen->w -#define SHERLOCK_SCREEN_HEIGHT _vm->_screen->h +#define SHERLOCK_SCREEN_WIDTH _vm->_screen->w() +#define SHERLOCK_SCREEN_HEIGHT _vm->_screen->h() #define SHERLOCK_SCENE_HEIGHT 138 struct SherlockGameDescription; @@ -72,18 +68,33 @@ class Resource; class SherlockEngine : public Engine { private: + /** + * Main loop for displaying a scene and handling all that occurs within it + */ void sceneLoop(); + /** + * Handle all player input + */ void handleInput(); + /** + * Load game configuration esttings + */ void loadConfig(); protected: + /** + * Does basic initialization of the game engine + */ virtual void initialize(); virtual void showOpening() = 0; virtual void startScene() {} + /** + * Returns a list of features the game itself supports + */ virtual bool hasFeature(EngineFeature f) const; public: const SherlockGameDescription *_gameDescription; @@ -103,39 +114,86 @@ public: UserInterface *_ui; Common::RandomSource _randomSource; Common::Array<bool> _flags; - Common::String _soundOverride; - Common::String _titleOverride; bool _useEpilogue2; int _loadGameSlot; bool _canLoadSave; bool _showOriginalSavesDialog; + bool _interactiveFl; public: SherlockEngine(OSystem *syst, const SherlockGameDescription *gameDesc); virtual ~SherlockEngine(); + /** + * Main method for running the game + */ virtual Common::Error run(); + /** + * Returns true if a savegame can be loaded + */ virtual bool canLoadGameStateCurrently(); + + /** + * Returns true if the game can be saved + */ virtual bool canSaveGameStateCurrently(); + + /** + * Called by the GMM to load a savegame + */ virtual Common::Error loadGameState(int slot); + + /** + * Called by the GMM to save the game + */ virtual Common::Error saveGameState(int slot, const Common::String &desc); + + /** + * Called by the engine when sound settings are updated + */ virtual void syncSoundSettings(); - virtual bool getIsDemo() const; + /** + * Returns whether the version is a demo + */ + virtual bool isDemo() const; + + /** + * Returns the Id of the game + */ GameType getGameID() const; - Common::Language getLanguage() const; - Common::Platform getPlatform() const; - Common::String getGameFile(int fileType); + /** + * Returns the platform the game's datafiles are for + */ + Common::Platform getPlatform() const; + /** + * Return a random number + */ int getRandomNumber(int limit) { return _randomSource.getRandomNumber(limit - 1); } + /** + * Read the state of a global flag + * @remarks If a negative value is specified, it will return the inverse value + * of the positive flag number + */ bool readFlags(int flagNum); + /** + * Sets a global flag to either true or false depending on whether the specified + * flag is positive or negative + */ void setFlags(int flagNum); + /** + * Saves game configuration information + */ void saveConfig(); + /** + * Synchronize the data for a savegame + */ void synchronize(Common::Serializer &s); }; diff --git a/engines/sherlock/sound.cpp b/engines/sherlock/sound.cpp index 3a308644a8..06f6a0f264 100644 --- a/engines/sherlock/sound.cpp +++ b/engines/sherlock/sound.cpp @@ -30,11 +30,30 @@ namespace Sherlock { -Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer): _vm(vm), _mixer(mixer) { +static const int8 creativeADPCM_ScaleMap[64] = { + 0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7, + 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15, + 2, 6, 10, 14, 18, 22, 26, 30, -2, -6, -10, -14, -18, -22, -26, -30, + 4, 12, 20, 28, 36, 44, 52, 60, -4, -12, -20, -28, -36, -44, -52, -60 +}; + +static const uint8 creativeADPCM_AdjustMap[64] = { + 0, 0, 0, 0, 0, 16, 16, 16, + 0, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 0, 0, 0, + 240, 0, 0, 0, 0, 0, 0, 0 +}; + +/*----------------------------------------------------------------*/ + +Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) { _digitized = false; _music = false; _voices = 0; - _playingEpilogue = false; _diskSoundPlaying = false; _soundPlaying = false; _soundIsOn = &_soundPlaying; @@ -45,11 +64,19 @@ Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer): _vm(vm), _mixer(mixer) { _speechOn = true; _vm->_res->addToCache("MUSIC.LIB"); + if (!_vm->_interactiveFl) + _vm->_res->addToCache("TITLE.SND"); + else { + _vm->_res->addToCache("MUSIC.LIB"); + _vm->_res->addToCache("SND.SND"); + + if (!_vm->isDemo()) { + _vm->_res->addToCache("TITLE.SND"); + _vm->_res->addToCache("EPILOGUE.SND"); + } + } } -/** - * Saves sound-related settings - */ void Sound::syncSoundSettings() { _digitized = !ConfMan.getBool("mute"); _music = !ConfMan.getBool("mute") && !ConfMan.getBool("music_mute"); @@ -58,41 +85,41 @@ void Sound::syncSoundSettings() { void Sound::loadSound(const Common::String &name, int priority) { // No implementation required in ScummVM + warning("loadSound"); } -char Sound::decodeSample(char sample, byte& prediction, int& step) { - char diff = ((sample & 0x07) << step); - - if (sample & 0x08) { - if (prediction > diff) - prediction = prediction - ((sample & 0x07) << step); - else - prediction = 0; - } else { - if (prediction < 0xff - diff) - prediction = prediction + ((sample&0x07) << step); - else - prediction = 0xff; - } +byte Sound::decodeSample(byte sample, byte &reference, int16 &scale) { + int16 samp = sample + scale; + int16 ref = 0; + // clip bad ADPCM-4 sample + samp = CLIP<int16>(samp, 0, 63); - if ((sample & 0x07) >= 5 && step < 3) { - step ++; - } else if ((sample & 0x07) == 0 && step > 0) { - step --; + ref = reference + creativeADPCM_ScaleMap[samp]; + if (ref > 0xff) { + reference = 0xff; + } else { + if (ref < 0x00) { + reference = 0; + } else { + reference = (uint8)(ref & 0xff); + } } - return prediction; + scale = (scale + creativeADPCM_AdjustMap[samp]) & 0xff; + return reference; } -bool Sound::playSound(const Common::String &name, WaitType waitType, int priority) { +bool Sound::playSound(const Common::String &name, WaitType waitType, int priority, const char *libraryFilename) { + Resources &res = *_vm->_res; stopSound(); Common::String filename = name; if (!filename.contains('.')) filename += ".SND"; - - Common::SeekableReadStream *stream = _vm->_res->load(filename); + + Common::String libFilename(libraryFilename); + Common::SeekableReadStream *stream = libFilename.empty() ? res.load(filename) : res.load(filename, libFilename); if (!stream) error("Unable to find sound file '%s'", filename.c_str()); @@ -104,16 +131,18 @@ bool Sound::playSound(const Common::String &name, WaitType waitType, int priorit byte *ptr = data; stream->read(ptr, size); + assert(size > 2); + byte *decoded = (byte *)malloc((size - 1) * 2); - // +127 to eliminate the pop when the sound starts (signed vs unsigned PCM). Still does not help with the pop at the end - byte prediction = (ptr[0] & 0x0f) + 127; - int step = 0; + // Holmes uses Creative ADPCM 4-bit data int counter = 0; + byte reference = ptr[0]; + int16 scale = 0; for(int i = 1; i < size; i++) { - decoded[counter++] = decodeSample((ptr[i]>>4)&0x0f, prediction, step); - decoded[counter++] = decodeSample((ptr[i]>>0)&0x0f, prediction, step); + decoded[counter++] = decodeSample((ptr[i]>>4)&0x0f, reference, scale); + decoded[counter++] = decodeSample((ptr[i]>>0)&0x0f, reference, scale); } free(data); @@ -146,7 +175,7 @@ bool Sound::playSound(const Common::String &name, WaitType waitType, int priorit break; } } while (!_vm->shouldQuit() && _mixer->isSoundHandleActive(_effectsHandle)); - + _soundPlaying = false; _mixer->stopHandle(_effectsHandle); @@ -231,3 +260,4 @@ void Sound::freeDigiSound() { } } // End of namespace Sherlock + diff --git a/engines/sherlock/sound.h b/engines/sherlock/sound.h index 659df57bc3..689e615a36 100644 --- a/engines/sherlock/sound.h +++ b/engines/sherlock/sound.h @@ -46,7 +46,7 @@ private: Audio::SoundHandle _effectsHandle; int _curPriority; - char decodeSample(char sample, byte& prediction, int& step); + byte decodeSample(byte sample, byte& reference, int16& scale); public: bool _digitized; bool _music; @@ -54,7 +54,6 @@ public: bool _soundOn; bool _musicOn; bool _speechOn; - bool _playingEpilogue; bool _diskSoundPlaying; bool _soundPlaying; bool *_soundIsOn; @@ -62,19 +61,61 @@ public: public: Sound(SherlockEngine *vm, Audio::Mixer *mixer); + /** + * Saves sound-related settings + */ void syncSoundSettings(); + + /** + * Load a sound + */ void loadSound(const Common::String &name, int priority); - bool playSound(const Common::String &name, WaitType waitType, int priority = 100); + + /** + * Play the sound in the specified resource + */ + bool playSound(const Common::String &name, WaitType waitType, int priority = 100, const char *libraryFilename = nullptr); + + /** + * Play a previously loaded sound + */ void playLoadedSound(int bufNum, WaitType waitType); + + /** + * Free any previously loaded sounds + */ void freeLoadedSounds(); + + /** + * Stop playing any active sound + */ void stopSound(); + /** + * Load a specified song + */ int loadSong(int songNumber); + + /** + * Start playing a song + */ void startSong(); + + /** + * Free any currently loaded song + */ void freeSong(); + /** + * Play the specified music resource + */ void playMusic(const Common::String &name); + + /** + * Stop playing the music + */ void stopMusic(); + void stopSndFuncPtr(int v1, int v2); void waitTimerRoland(uint time); void freeDigiSound(); @@ -83,3 +124,4 @@ public: } // End of namespace Sherlock #endif + diff --git a/engines/sherlock/surface.cpp b/engines/sherlock/surface.cpp index 36e625794c..80495a398c 100644 --- a/engines/sherlock/surface.cpp +++ b/engines/sherlock/surface.cpp @@ -22,12 +22,13 @@ #include "sherlock/surface.h" #include "sherlock/sherlock.h" +#include "sherlock/resources.h" #include "common/system.h" #include "graphics/palette.h" namespace Sherlock { -Surface::Surface(uint16 width, uint16 height): _freePixels(true) { +Surface::Surface(uint16 width, uint16 height) : _freePixels(true) { create(width, height); } @@ -36,61 +37,65 @@ Surface::Surface() : _freePixels(false) { Surface::~Surface() { if (_freePixels) - free(); + _surface.free(); } -/** - * Sets up an internal surface with the specified dimensions that will be automatically freed - * when the surface object is destroyed - */ void Surface::create(uint16 width, uint16 height) { if (_freePixels) - free(); + _surface.free(); - Graphics::Surface::create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + _surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); _freePixels = true; } -/** - * Copy a surface into this one - */ +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)); } -/** - * Draws a surface at a given position within this surface - */ +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)); } -/** - * Draws a sub-section of a surface at a given position within this surface - */ -void Surface::blitFrom(const Graphics::Surface &src, const Common::Point &pt, - const Common::Rect &srcBounds) { +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); - copyRectToSurface(src, destRect.left, destRect.top, srcRect); + _surface.copyRectToSurface(src, destRect.left, destRect.top, srcRect); } } -/** -* Draws an image frame at a given position within this surface with transparency -*/ +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) { transBlitFrom(src._frame, pt + src._offset, flipped, overrideColor); } -/** -* Draws a surface at a given position within this surface with transparency -*/ void Surface::transBlitFrom(const Graphics::Surface &src, const Common::Point &pt, bool flipped, int overrideColor) { Common::Rect drawRect(0, 0, src.w, src.h); @@ -125,38 +130,29 @@ void Surface::transBlitFrom(const Graphics::Surface &src, const Common::Point &p } } -/** - * Fill a given area of the surface with a given color - */ void Surface::fillRect(int x1, int y1, int x2, int y2, byte color) { fillRect(Common::Rect(x1, y1, x2, y2), color); } -/** - * Fill a given area of the surface with a given color - */ void Surface::fillRect(const Common::Rect &r, byte color) { - Graphics::Surface::fillRect(r, color); + _surface.fillRect(r, color); addDirtyRect(r); } -/** - * Clips the given source bounds so the passed destBounds will be entirely on-screen - */ bool Surface::clip(Common::Rect &srcBounds, Common::Rect &destBounds) { - if (destBounds.left >= this->w || destBounds.top >= this->h || - destBounds.right <= 0 || destBounds.bottom <= 0) + if (destBounds.left >= _surface.w || destBounds.top >= _surface.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.right > _surface.w) { + srcBounds.right -= destBounds.right - _surface.w; + destBounds.right = _surface.w; } - if (destBounds.bottom > this->h) { - srcBounds.bottom -= destBounds.bottom - this->h; - destBounds.bottom = this->h; + if (destBounds.bottom > _surface.h) { + srcBounds.bottom -= destBounds.bottom - _surface.h; + destBounds.bottom = _surface.h; } if (destBounds.top < 0) { @@ -172,11 +168,22 @@ bool Surface::clip(Common::Rect &srcBounds, Common::Rect &destBounds) { return true; } -/** - * Clear the screen - */ void Surface::clear() { - fillRect(Common::Rect(0, 0, this->w, this->h), 0); + fillRect(Common::Rect(0, 0, _surface.w, _surface.h), 0); +} + +void Surface::free() { + if (_freePixels) { + _surface.free(); + _freePixels = false; + } +} + +void Surface::setPixels(byte *pixels, int width, int height) { + _surface.format = Graphics::PixelFormat::createFormatCLUT8(); + _surface.w = _surface.pitch = width; + _surface.h = height; + _surface.setPixels(pixels); } } // End of namespace Sherlock diff --git a/engines/sherlock/surface.h b/engines/sherlock/surface.h index b2a759aa8d..ccabf02a23 100644 --- a/engines/sherlock/surface.h +++ b/engines/sherlock/surface.h @@ -25,36 +25,130 @@ #include "common/rect.h" #include "graphics/surface.h" -#include "sherlock/resources.h" namespace Sherlock { -class Surface : public Graphics::Surface { +struct ImageFrame; + +class Surface { private: bool _freePixels; + /** + * Clips the given source bounds so the passed destBounds will be entirely on-screen + */ bool clip(Common::Rect &srcBounds, Common::Rect &destBounds); + + /** + * Copy a surface into this one + */ + void blitFrom(const Graphics::Surface &src); + + /** + * Draws a surface at a given position within this surface + */ + void blitFrom(const Graphics::Surface &src, const Common::Point &pt); + + /** + * Draws a sub-section of a surface at a given position within this surface + */ + void blitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds); protected: + Graphics::Surface _surface; + virtual void addDirtyRect(const Common::Rect &r) {} 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 + */ void create(uint16 width, uint16 height); - void blitFrom(const Graphics::Surface &src); - void blitFrom(const Graphics::Surface &src, const Common::Point &pt); - void blitFrom(const Graphics::Surface &src, const Common::Point &pt, - const Common::Rect &srcBounds); + + /** + * Copy a surface into this one + */ + void blitFrom(const Surface &src); + + /** + * Copy an image frame into this surface + */ + void blitFrom(const ImageFrame &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); + + /** + * 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 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); + + /** + * 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); + + /** + * Draws a surface 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); + /** + * Fill a given area of the surface with a given color + */ void fillRect(int x1, int y1, int x2, int y2, byte color); + + /** + * Fill a given area of the surface with a given color + */ void fillRect(const Common::Rect &r, byte color); + /** + * Clear the screen + */ void clear(); + + /** + * Free the underlying surface + */ + void free(); + + /** + * Set the pixels for the surface to an existing data block + */ + void setPixels(byte *pixels, int width, int height); + + inline uint16 w() const { return _surface.w; } + inline 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 void hLine(int x, int y, int x2, uint32 color) { _surface.hLine(x, y, x2, color); } + inline void vLine(int x, int y, int y2, uint32 color) { _surface.vLine(x, y, y2, color); } }; } // End of namespace Sherlock diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp index c67b98b35e..1a926a543d 100644 --- a/engines/sherlock/talk.cpp +++ b/engines/sherlock/talk.cpp @@ -26,6 +26,8 @@ namespace Sherlock { +#define SPEAKER_REMOVE 0x80 + SequenceEntry::SequenceEntry() { _objNum = 0; _frameNumber = 0; @@ -34,9 +36,6 @@ SequenceEntry::SequenceEntry() { /*----------------------------------------------------------------*/ -/** - * Load the data for a single statement within a talk file - */ void Statement::synchronize(Common::SeekableReadStream &s) { int length; @@ -91,7 +90,7 @@ void TalkSequences::clear() { /*----------------------------------------------------------------*/ -Talk::Talk(SherlockEngine *vm): _vm(vm) { +Talk::Talk(SherlockEngine *vm) : _vm(vm) { _talkCounter = 0; _talkToAbort = false; _speaker = 0; @@ -106,26 +105,6 @@ Talk::Talk(SherlockEngine *vm): _vm(vm) { _scriptSaveIndex = -1; } -/** - * Sets talk sequences - */ -void Talk::setSequences(const byte *talkSequences, const byte *stillSequences, int maxPeople) { - for (int idx = 0; idx < maxPeople; ++idx) { - STILL_SEQUENCES.push_back(TalkSequences(stillSequences)); - TALK_SEQUENCES.push_back(TalkSequences(talkSequences)); - stillSequences += MAX_TALK_SEQUENCES; - talkSequences += MAX_TALK_SEQUENCES; - } -} - -/** - * Called whenever a conversation or item script needs to be run. For standard conversations, - * it opens up a description window similar to how 'talk' does, but shows a 'reply' directly - * instead of waiting for a statement option. - * @remarks It seems that at some point, all item scripts were set up to use this as well. - * In their case, the conversation display is simply suppressed, and control is passed on to - * doScript to implement whatever action is required. - */ void Talk::talkTo(const Common::String &filename) { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; @@ -158,7 +137,7 @@ void Talk::talkTo(const Common::String &filename) { } // Save the ui mode temporarily and switch to talk mode - int savedMode = ui._menuMode; + MenuMode savedMode = ui._menuMode; ui._menuMode = TALK_MODE; // Turn on the Exit option @@ -196,7 +175,7 @@ void Talk::talkTo(const Common::String &filename) { if (IS_SERRATED_SCALPEL) { // Restore any pressed button if (!ui._windowOpen && savedMode != STD_MODE) - ((ScalpelUserInterface *)_vm->_ui)->restoreButton(savedMode - 1); + ((ScalpelUserInterface *)_vm->_ui)->restoreButton((int)(savedMode - 1)); } // Clear the ui counter so that anything displayed on the info line @@ -223,7 +202,7 @@ void Talk::talkTo(const Common::String &filename) { break; case TALK_MODE: - if (_speaker < 128) + if (_speaker < SPEAKER_REMOVE) people.clearTalking(); if (_talkCounter) return; @@ -272,6 +251,9 @@ void Talk::talkTo(const Common::String &filename) { events._pressed = events._released = events._oldButtons = 0; abortFlag = true; break; + + default: + break; } } @@ -387,7 +369,7 @@ void Talk::talkTo(const Common::String &filename) { } else { screen.buttonPrint(Common::Point(119, CONTROLS_Y), color, false, "Exit"); - if (!ui._windowStyle) { + if (!ui._slideWindows) { screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); } else { @@ -450,12 +432,6 @@ void Talk::talkTo(const Common::String &filename) { events.setCursor(ARROW); } -/** - * Main method for handling conversations when a character to talk to has been - * selected. It will make Holmes walk to the person to talk to, draws the - * interface window for the conversation and passes on control to give the - * player a list of options to make a selection from - */ void Talk::talk(int objNum) { Events &events = *_vm->_events; People &people = *_vm->_people; @@ -466,7 +442,7 @@ void Talk::talk(int objNum) { ui._windowBounds.top = CONTROLS_Y; ui._infoFlag = true; - _speaker = 128; + _speaker = SPEAKER_REMOVE; loadTalkFile(scene._bgShapes[objNum]._name); // Find the first statement with the correct flags @@ -534,7 +510,7 @@ void Talk::talk(int objNum) { displayTalk(false); ui._selector = ui._oldSelector = -1; - if (!ui._windowStyle) { + if (!ui._slideWindows) { screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); } else { @@ -549,18 +525,12 @@ void Talk::talk(int objNum) { } } -/** - * Clear loaded talk data - */ void Talk::freeTalkVars() { _statements.clear(); } -/** - * Opens the talk file 'talk.tlk' and searches the index for the specified - * conversation. If found, the data for that conversation is loaded - */ void Talk::loadTalkFile(const Common::String &filename) { + People &people = *_vm->_people; Resources &res = *_vm->_res; Sound &sound = *_vm->_sound; @@ -569,8 +539,8 @@ void Talk::loadTalkFile(const Common::String &filename) { // Check for an existing person being talked to _talkTo = -1; - for (int idx = 0; idx < MAX_PEOPLE; ++idx) { - if (!scumm_strnicmp(filename.c_str(), PORTRAITS[idx], 4)) { + for (int idx = 0; idx < (int)people._characters.size(); ++idx) { + if (!scumm_strnicmp(filename.c_str(), people._characters[idx]._portrait, 4)) { _talkTo = idx; break; } @@ -596,9 +566,6 @@ void Talk::loadTalkFile(const Common::String &filename) { setTalkMap(); } -/** - * Remove any voice commands from a loaded statement list - */ void Talk::stripVoiceCommands() { for (uint sIdx = 0; sIdx < _statements.size(); ++sIdx) { Statement &statement = _statements[sIdx]; @@ -622,9 +589,6 @@ void Talk::stripVoiceCommands() { } } -/** - * Form a table of the display indexes for statements - */ void Talk::setTalkMap() { int statementNum = 0; @@ -642,9 +606,6 @@ void Talk::setTalkMap() { } } -/** - * Draws the interface for conversation display - */ void Talk::drawInterface() { Screen &screen = *_vm->_screen; Surface &bb = *screen._backBuffer; @@ -673,10 +634,6 @@ void Talk::drawInterface() { } } -/** - * Display a list of statements in a window at the bottom of the scren that the - * player can select from. - */ bool Talk::displayTalk(bool slamIt) { Screen &screen = *_vm->_screen; int yp = CONTROLS_Y + 14; @@ -761,9 +718,6 @@ bool Talk::displayTalk(bool slamIt) { return done; } -/** - * Prints a single conversation option in the interface window - */ int Talk::talkLine(int lineNum, int stateNum, byte color, int lineY, bool slamIt) { Screen &screen = *_vm->_screen; int idx = lineNum; @@ -771,11 +725,11 @@ int Talk::talkLine(int lineNum, int stateNum, byte color, int lineY, bool slamIt bool numberFlag = false; // Get the statement to display as well as optional number prefix - if (idx < 128) { + if (idx < SPEAKER_REMOVE) { number = Common::String::format("%d.", stateNum + 1); numberFlag = true; } else { - idx -= 128; + idx -= SPEAKER_REMOVE; } msg = _statements[idx]._statement; @@ -812,23 +766,23 @@ int Talk::talkLine(int lineNum, int stateNum, byte color, int lineY, bool slamIt // Are we drawing the first line? if (lineStartP == msg.c_str()) { // We are, so print the number and then the text - screen.print(Common::Point(16, lineY), color, number.c_str()); + screen.print(Common::Point(16, lineY), color, "%s", number.c_str()); } // Draw the line with an indent - screen.print(Common::Point(30, lineY), color, sLine.c_str()); + screen.print(Common::Point(30, lineY), color, "%s", sLine.c_str()); } else { - screen.print(Common::Point(16, lineY), color, sLine.c_str()); + screen.print(Common::Point(16, lineY), color, "%s", sLine.c_str()); } } else { if (numberFlag) { if (lineStartP == msg.c_str()) { - screen.gPrint(Common::Point(16, lineY - 1), color, number.c_str()); + screen.gPrint(Common::Point(16, lineY - 1), color, "%s", number.c_str()); } - screen.gPrint(Common::Point(30, lineY - 1), color, sLine.c_str()); + screen.gPrint(Common::Point(30, lineY - 1), color, "%s", sLine.c_str()); } else { - screen.gPrint(Common::Point(16, lineY - 1), color, sLine.c_str()); + screen.gPrint(Common::Point(16, lineY - 1), color, "%s", sLine.c_str()); } } @@ -852,17 +806,10 @@ int Talk::talkLine(int lineNum, int stateNum, byte color, int lineY, bool slamIt return lineY; } -/** - * Clears the stack of pending object sequences associated with speakers in the scene - */ void Talk::clearSequences() { _sequenceStack.clear(); } -/** - * Pulls a background object sequence from the sequence stack and restore's the - * object's sequence - */ void Talk::pullSequence() { Scene &scene = *_vm->_scene; @@ -885,10 +832,6 @@ void Talk::pullSequence() { } } -/** - * Push the sequence of a background object that's an NPC that needs to be - * saved onto the sequence stack. - */ void Talk::pushSequence(int speaker) { People &people = *_vm->_people; Scene &scene = *_vm->_scene; @@ -918,9 +861,6 @@ void Talk::pushSequence(int speaker) { error("script stack overflow"); } -/** - * Change the sequence of the scene background object associated with the current speaker. - */ void Talk::setSequence(int speaker) { People &people = *_vm->_people; Scene &scene = *_vm->_scene; @@ -938,8 +878,8 @@ void Talk::setSequence(int speaker) { warning("Tried to copy too many talk frames"); } else { for (int idx = 0; idx < MAX_TALK_SEQUENCES; ++idx) { - obj._sequences[idx] = TALK_SEQUENCES[speaker][idx]; - if (idx > 0 && !TALK_SEQUENCES[speaker][idx] && !TALK_SEQUENCES[speaker][idx - 1]) + obj._sequences[idx] = people._characters[speaker]._talkSequences[idx]; + if (idx > 0 && !obj._sequences[idx] && !obj._sequences[idx - 1]) return; obj._frameNumber = 0; @@ -950,10 +890,6 @@ void Talk::setSequence(int speaker) { } } -/** - * Change the sequence of a background object corresponding to a given speaker. - * The new sequence will display the character as "listening" - */ void Talk::setStillSeq(int speaker) { People &people = *_vm->_people; Scene &scene = *_vm->_scene; @@ -971,8 +907,9 @@ void Talk::setStillSeq(int speaker) { warning("Tried to copy too few still frames"); } else { for (uint idx = 0; idx < MAX_TALK_SEQUENCES; ++idx) { - obj._sequences[idx] = STILL_SEQUENCES[speaker][idx]; - if (idx > 0 && !TALK_SEQUENCES[speaker][idx] && !TALK_SEQUENCES[speaker][idx - 1]) + obj._sequences[idx] = people._characters[speaker]._stillSequences[idx]; + if (idx > 0 && !people._characters[speaker]._talkSequences[idx] && + !people._characters[speaker]._talkSequences[idx - 1]) break; } @@ -983,10 +920,6 @@ void Talk::setStillSeq(int speaker) { } } -/** - * Parses a reply for control codes and display text. The found text is printed within - * the text window, handles delays, animations, and animating portraits. - */ void Talk::doScript(const Common::String &script) { Animation &anim = *_vm->_animation; Events &events = *_vm->_events; @@ -1021,7 +954,7 @@ void Talk::doScript(const Common::String &script) { // Check if the script begins with a Stealh Mode Active command if (str[0] == STEALTH_MODE_ACTIVE || _talkStealth) { _talkStealth = 2; - _speaker |= 128; + _speaker |= SPEAKER_REMOVE; } else { pushSequence(_speaker); ui.clearWindow(); @@ -1079,11 +1012,11 @@ void Talk::doScript(const Common::String &script) { // Start of comment, so skip over it while (*str++ != '}') ; - } else if (c >= 128) { + } else if (c >= SWITCH_SPEAKER) { // Handle control code switch (c) { case SWITCH_SPEAKER: - if (!(_speaker & 128)) + if (!(_speaker & SPEAKER_REMOVE)) people.clearTalking(); if (_talkToAbort) return; @@ -1101,7 +1034,7 @@ void Talk::doScript(const Common::String &script) { case RUN_CANIMATION: ++str; - scene.startCAnim((str[0] - 1) & 127, (str[0] & 128) ? -1 : 1); + scene.startCAnim((str[0] - 1) & 127, (str[0] & 0x80) ? -1 : 1); if (_talkToAbort) return; @@ -1137,13 +1070,13 @@ void Talk::doScript(const Common::String &script) { break; case REMOVE_PORTRAIT: - if (_speaker >= 0 && _speaker < 128) + if (_speaker >= 0 && _speaker < SPEAKER_REMOVE) people.clearTalking(); pullSequence(); if (_talkToAbort) return; - _speaker |= 128; + _speaker |= SPEAKER_REMOVE; break; case CLEAR_WINDOW: @@ -1162,14 +1095,14 @@ void Talk::doScript(const Common::String &script) { // Scan for object int objId = -1; for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) { - if (scumm_stricmp(tempString.c_str(), scene._bgShapes[idx]._name.c_str()) == 0) + if (tempString.equalsIgnoreCase(scene._bgShapes[idx]._name)) objId = idx; } if (objId == -1) error("Could not find object %s to change", tempString.c_str()); // Should the script be overwritten? - if (str[0] > 128) { + if (str[0] > 0x80) { // Save the current sequence _savedSequences.push(SequenceEntry()); SequenceEntry &seqEntry = _savedSequences.top(); @@ -1218,14 +1151,14 @@ void Talk::doScript(const Common::String &script) { break; case BANISH_WINDOW: - if (!(_speaker & 128)) + if (!(_speaker & SPEAKER_REMOVE)) people.clearTalking(); pullSequence(); if (_talkToAbort) return; - _speaker |= 128; + _speaker |= SPEAKER_REMOVE; ui.banishWindow(); ui._menuMode = TALK_MODE; noTextYet = true; @@ -1369,12 +1302,12 @@ void Talk::doScript(const Common::String &script) { tempString += str[idx + 1]; // Set comparison state according to if we want to hide or unhide - bool state = (str[0] >= 128); + bool state = (str[0] >= SPEAKER_REMOVE); str += str[0] & 127; for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) { Object &object = scene._bgShapes[idx]; - if (scumm_stricmp(tempString.c_str(), object._name.c_str()) == 0) { + if (tempString.equalsIgnoreCase(object._name)) { // Only toggle the object if it's not in the desired state already if ((object._type == HIDDEN && state) || (object._type != HIDDEN && !state)) object.toggleHidden(); @@ -1429,7 +1362,7 @@ void Talk::doScript(const Common::String &script) { tempString += str[idx + 1]; str += str[0]; - screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, tempString.c_str()); + screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", tempString.c_str()); ui._menuCounter = 30; break; @@ -1484,29 +1417,31 @@ void Talk::doScript(const Common::String &script) { } // If it's the first line, display the speaker - if (!line && _speaker >= 0 && _speaker < MAX_PEOPLE) { + if (!line && _speaker >= 0 && _speaker < (int)people._characters.size()) { // If the window is open, display the name directly on-screen. // Otherwise, simply draw it on the back buffer if (ui._windowOpen) { - screen.print(Common::Point(16, yp), TALK_FOREGROUND, NAMES[_speaker & 127]); + screen.print(Common::Point(16, yp), TALK_FOREGROUND, "%s", + people._characters[_speaker & 127]._name); } else { - screen.gPrint(Common::Point(16, yp - 1), TALK_FOREGROUND, NAMES[_speaker & 127]); + screen.gPrint(Common::Point(16, yp - 1), TALK_FOREGROUND, "%s", + people._characters[_speaker & 127]._name); openTalkWindow = true; } yp += 9; } - // Find amound of text that will fit on the line + // Find amount of text that will fit on the line int width = 0, idx = 0; do { width += screen.charWidth(str[idx]); ++idx; ++charCount; - } while (width < 298 && str[idx] && str[idx] != '{' && str[idx] < 128); + } while (width < 298 && str[idx] && str[idx] != '{' && str[idx] < SWITCH_SPEAKER); if (str[idx] || width >= 298) { - if (str[idx] < 128 && str[idx] != '{') { + if (str[idx] < SWITCH_SPEAKER && str[idx] != '{') { --idx; --charCount; } @@ -1528,16 +1463,16 @@ void Talk::doScript(const Common::String &script) { // If the speaker indicates a description file, print it in yellow if (_speaker != -1) { if (ui._windowOpen) { - screen.print(Common::Point(16, yp), COMMAND_FOREGROUND, lineStr.c_str()); + screen.print(Common::Point(16, yp), COMMAND_FOREGROUND, "%s", lineStr.c_str()); } else { - screen.gPrint(Common::Point(16, yp - 1), COMMAND_FOREGROUND, lineStr.c_str()); + screen.gPrint(Common::Point(16, yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str()); openTalkWindow = true; } } else { if (ui._windowOpen) { - screen.print(Common::Point(16, yp), COMMAND_FOREGROUND, lineStr.c_str()); + screen.print(Common::Point(16, yp), COMMAND_FOREGROUND, "%s", lineStr.c_str()); } else { - screen.gPrint(Common::Point(16, yp - 1), COMMAND_FOREGROUND, lineStr.c_str()); + screen.gPrint(Common::Point(16, yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str()); openTalkWindow = true; } } @@ -1546,7 +1481,7 @@ void Talk::doScript(const Common::String &script) { str += idx; // If line wrap occurred, then move to after the separating space between the words - if (str[0] < 128 && str[0] != '{') + if (str[0] < SWITCH_SPEAKER && str[0] != '{') ++str; yp += 9; @@ -1576,8 +1511,8 @@ void Talk::doScript(const Common::String &script) { } // Open window if it wasn't already open, and text has already been printed - if ((openTalkWindow && wait) || (openTalkWindow && str[0] >= 128 && str[0] != CARRIAGE_RETURN)) { - if (!ui._windowStyle) { + if ((openTalkWindow && wait) || (openTalkWindow && str[0] >= SWITCH_SPEAKER && str[0] != CARRIAGE_RETURN)) { + if (!ui._slideWindows) { screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); } else { ui.summonWindow(); @@ -1626,15 +1561,11 @@ void Talk::doScript(const Common::String &script) { } pullSequence(); - if (_speaker >= 0 && _speaker < 128) + if (_speaker >= 0 && _speaker < SPEAKER_REMOVE) people.clearTalking(); } } -/** - * When the talk window has been displayed, waits a period of time proportional to - * the amount of text that's been displayed - */ int Talk::waitForMore(int delay) { Events &events = *_vm->_events; People &people = *_vm->_people; @@ -1665,7 +1596,7 @@ int Talk::waitForMore(int delay) { if (events.kbHit()) { Common::KeyState keyState = events.getKey(); - if (keyState.keycode >= 32 && keyState.keycode < 128) + if (Common::isPrint(keyState.ascii)) key2 = keyState.keycode; } @@ -1714,9 +1645,6 @@ int Talk::waitForMore(int delay) { return key2; } -/** - * Pops an entry off of the script stack - */ void Talk::popStack() { if (!_scriptStack.empty()) { ScriptStackEntry scriptEntry = _scriptStack.pop(); @@ -1727,9 +1655,6 @@ void Talk::popStack() { } } -/** - * Synchronize the data for a savegame - */ void Talk::synchronize(Common::Serializer &s) { for (int idx = 0; idx < MAX_TALK_FILES; ++idx) { TalkHistoryEntry &he = _talkHistory[idx]; diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h index 5c87d793f3..48290e965e 100644 --- a/engines/sherlock/talk.h +++ b/engines/sherlock/talk.h @@ -99,6 +99,9 @@ struct Statement { int _talkMap; Common::Rect _talkPos; + /** + * Load the data for a single statement within a talk file + */ void synchronize(Common::SeekableReadStream &s); }; @@ -125,9 +128,6 @@ class ScalpelUserInterface; class Talk { friend class ScalpelUserInterface; private: - Common::Array<TalkSequences> STILL_SEQUENCES; - Common::Array<TalkSequences> TALK_SEQUENCES; -private: SherlockEngine *_vm; Common::Stack<SequenceEntry> _savedSequences; Common::Stack<SequenceEntry> _sequenceStack; @@ -141,15 +141,37 @@ private: int _talkToFlag; int _scriptSaveIndex; private: + /** + * Remove any voice commands from a loaded statement list + */ void stripVoiceCommands(); + + /** + * Form a table of the display indexes for statements + */ void setTalkMap(); + /** + * Display a list of statements in a window at the bottom of the screen that the + * player can select from. + */ bool displayTalk(bool slamIt); + /** + * Prints a single conversation option in the interface window + */ int talkLine(int lineNum, int stateNum, byte color, int lineY, bool slamIt); + /** + * Parses a reply for control codes and display text. The found text is printed within + * the text window, handles delays, animations, and animating portraits. + */ void doScript(const Common::String &script); + /** + * When the talk window has been displayed, waits a period of time proportional to + * the amount of text that's been displayed + */ int waitForMore(int delay); public: bool _talkToAbort; @@ -161,30 +183,87 @@ public: int _converseNum; public: Talk(SherlockEngine *vm); - void setSequences(const byte *talkSequences, const byte *stillSequences, - int maxPeople); + /** + * Return a given talk statement + */ Statement &operator[](int idx) { return _statements[idx]; } + /** + * Called whenever a conversation or item script needs to be run. For standard conversations, + * it opens up a description window similar to how 'talk' does, but shows a 'reply' directly + * instead of waiting for a statement option. + * @remarks It seems that at some point, all item scripts were set up to use this as well. + * In their case, the conversation display is simply suppressed, and control is passed on to + * doScript to implement whatever action is required. + */ void talkTo(const Common::String &filename); + /** + * Main method for handling conversations when a character to talk to has been + * selected. It will make Holmes walk to the person to talk to, draws the + * interface window for the conversation and passes on control to give the + * player a list of options to make a selection from + */ void talk(int objNum); + /** + * Clear loaded talk data + */ void freeTalkVars(); + /** + * Draws the interface for conversation display + */ void drawInterface(); + /** + * Opens the talk file 'talk.tlk' and searches the index for the specified + * conversation. If found, the data for that conversation is loaded + */ void loadTalkFile(const Common::String &filename); + /** + * Change the sequence of a background object corresponding to a given speaker. + * The new sequence will display the character as "listening" + */ void setStillSeq(int speaker); + + /** + * Clears the stack of pending object sequences associated with speakers in the scene + */ void clearSequences(); + + /** + * Pulls a background object sequence from the sequence stack and restore's the + * object's sequence + */ void pullSequence(); + + /** + * Push the sequence of a background object that's an NPC that needs to be + * saved onto the sequence stack. + */ void pushSequence(int speaker); + + /** + * Change the sequence of the scene background object associated with the current speaker. + */ void setSequence(int speaker); + + /** + * Returns true if the script stack is empty + */ bool isSequencesEmpty() const { return _scriptStack.empty(); } + /** + * Pops an entry off of the script stack + */ void popStack(); + /** + * Synchronize the data for a savegame + */ void synchronize(Common::Serializer &s); }; diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp index efe6c8ef59..7a6722a218 100644 --- a/engines/sherlock/user_interface.cpp +++ b/engines/sherlock/user_interface.cpp @@ -94,11 +94,12 @@ UserInterface::UserInterface(SherlockEngine *vm) : _vm(vm) { _windowOpen = false; _endKeyActive = true; _invLookFlag = 0; - _windowStyle = 1; // Sliding windows + _slideWindows = true; _helpStyle = false; + _windowBounds = Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH - 1, SHERLOCK_SCREEN_HEIGHT - 1); _lookScriptFlag = false; - _key = _oldKey = 0; + _key = _oldKey = '\0'; _selector = _oldSelector = -1; _temp = _oldTemp = 0; _temp1 = 0; @@ -110,16 +111,17 @@ UserInterface::UserInterface(SherlockEngine *vm) : _vm(vm) { ScalpelUserInterface::ScalpelUserInterface(SherlockEngine *vm): UserInterface(vm) { _controls = new ImageFile("menu.all"); _controlPanel = new ImageFile("controls.vgs"); + _keyPress = '\0'; + _lookHelp = 0; _bgFound = 0; _oldBgFound = -1; - _keycode = Common::KEYCODE_INVALID; _help = _oldHelp = 0; - _oldLook = false; + _key = _oldKey = '\0'; + _temp = _oldTemp = 0; + _oldLook = 0; _keyboardInput = false; _pause = false; _cNum = 0; - _windowBounds = Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH - 1, - SHERLOCK_SCREEN_HEIGHT - 1); _find = 0; _oldUse = 0; } @@ -129,18 +131,12 @@ ScalpelUserInterface::~ScalpelUserInterface() { delete _controlPanel; } -/** - * Resets the user interface - */ void ScalpelUserInterface::reset() { _oldKey = -1; _help = _oldHelp = -1; _oldTemp = _temp = -1; } -/** - * Draw the user interface onto the screen's back buffers - */ void ScalpelUserInterface::drawInterface(int bufferNum) { Screen &screen = *_vm->_screen; @@ -152,9 +148,6 @@ void ScalpelUserInterface::drawInterface(int bufferNum) { screen._backBuffer2.fillRect(0, INFO_LINE, SHERLOCK_SCREEN_WIDTH, INFO_LINE + 10, INFO_BLACK); } -/** - * Main input handler for the user interface - */ void ScalpelUserInterface::handleInput() { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; @@ -168,13 +161,13 @@ void ScalpelUserInterface::handleInput() { Common::Point pt = events.mousePos(); _bgFound = scene.findBgShape(Common::Rect(pt.x, pt.y, pt.x + 1, pt.y + 1)); - _keycode = Common::KEYCODE_INVALID; + _keyPress = '\0'; // Check kbd and set the mouse released flag if Enter or space is pressed. // Otherwise, the pressed _key is stored for later use if (events.kbHit()) { Common::KeyState keyState = events.getKey(); - _keycode = keyState.ascii; + _keyPress = keyState.ascii; if (keyState.keycode == Common::KEYCODE_x && keyState.flags & Common::KBD_ALT) { _vm->quitGame(); @@ -246,7 +239,7 @@ void ScalpelUserInterface::handleInput() { if (_help != -1 && !scene._bgShapes[_bgFound]._description.empty() && scene._bgShapes[_bgFound]._description[0] != ' ') screen.print(Common::Point(0, INFO_LINE + 1), - INFO_FOREGROUND, scene._bgShapes[_bgFound]._description.c_str()); + INFO_FOREGROUND, "%s", scene._bgShapes[_bgFound]._description.c_str()); _oldBgFound = _bgFound; } @@ -316,7 +309,7 @@ void ScalpelUserInterface::handleInput() { case USE_MODE: case GIVE_MODE: case INV_MODE: - if (inv._invMode == 1 || inv._invMode == 2 || inv._invMode == 3) { + if (inv._invMode == INVMODE_LOOK || inv._invMode == INVMODE_USE || inv._invMode == INVMODE_GIVE) { if (pt.y > CONTROLS_Y) lookInv(); else @@ -331,8 +324,7 @@ void ScalpelUserInterface::handleInput() { // // Do input processing // - if (events._pressed || events._released || events._rightPressed || - _keycode != Common::KEYCODE_INVALID || _pause) { + if (events._pressed || events._released || events._rightPressed || _keyPress || _pause) { if (((events._released && (_helpStyle || _help == -1)) || (events._rightReleased && !_helpStyle)) && (pt.y <= CONTROLS_Y) && (_menuMode == STD_MODE)) { // The mouse was clicked in the playing area with no action buttons down. @@ -399,33 +391,25 @@ void ScalpelUserInterface::handleInput() { // As long as there isn't an open window, do main input processing. // Windows are opened when in TALK, USE, INV, and GIVE modes if ((!_windowOpen && !_menuCounter && pt.y > CONTROLS_Y) || - _keycode != Common::KEYCODE_INVALID) { - if (events._pressed || events._released || _pause || - _keycode != Common::KEYCODE_INVALID) + _keyPress) { + if (events._pressed || events._released || _pause || _keyPress) doMainControl(); } - if (pt.y < CONTROLS_Y && events._pressed && _oldTemp != (_menuMode - 1) && _oldKey != -1) + if (pt.y < CONTROLS_Y && events._pressed && _oldTemp != (int)(_menuMode - 1) && _oldKey != -1) restoreButton(_oldTemp); } } -/** - * Draws the image for a user interface button in the down/pressed state. - */ void ScalpelUserInterface::depressButton(int num) { Screen &screen = *_vm->_screen; Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]); - Graphics::Surface &s = (*_controls)[num]._frame; - screen._backBuffer1.transBlitFrom(s, pt); - screen.slamArea(pt.x, pt.y, pt.x + s.w, pt.y + s.h); + ImageFrame &frame = (*_controls)[num]; + screen._backBuffer1.transBlitFrom(frame, pt); + screen.slamArea(pt.x, pt.y, pt.x + frame._width, pt.y + frame._height); } -/** - * Draws the image for the given user interface button in the up - * (not selected) position - */ void ScalpelUserInterface::restoreButton(int num) { Screen &screen = *_vm->_screen; Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]); @@ -441,10 +425,6 @@ void ScalpelUserInterface::restoreButton(int num) { } } -/** - * If he mouse button is pressed, then calls depressButton to draw the button - * as pressed; if not, it will show it as released with a call to "restoreButton". - */ void ScalpelUserInterface::pushButton(int num) { Events &events = *_vm->_events; _oldKey = -1; @@ -462,15 +442,10 @@ void ScalpelUserInterface::pushButton(int num) { restoreButton(num); } -/** - * By the time this method has been called, the graphics for the button change - * have already been drawn. This simply takes care of switching the mode around - * accordingly - */ void ScalpelUserInterface::toggleButton(int num) { Screen &screen = *_vm->_screen; - if (_menuMode != (num + 1)) { + if (_menuMode != (MenuMode)(num + 1)) { _menuMode = (MenuMode)(num + 1); _oldKey = COMMANDS[num]; _oldTemp = num; @@ -483,10 +458,10 @@ void ScalpelUserInterface::toggleButton(int num) { _keyboardInput = false; - Graphics::Surface &s = (*_controls)[num]._frame; + ImageFrame &frame = (*_controls)[num]; Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]); - screen._backBuffer1.transBlitFrom(s, pt); - screen.slamArea(pt.x, pt.y, pt.x + s.w, pt.y + s.h); + screen._backBuffer1.transBlitFrom(frame, pt); + screen.slamArea(pt.x, pt.y, pt.x + frame._width, pt.y + frame._height); } } else { _menuMode = STD_MODE; @@ -495,9 +470,6 @@ void ScalpelUserInterface::toggleButton(int num) { } } -/** - * Clears the info line of the screen - */ void ScalpelUserInterface::clearInfo() { if (_infoFlag) { _vm->_screen->vgaBar(Common::Rect(16, INFO_LINE, SHERLOCK_SCREEN_WIDTH - 19, @@ -507,9 +479,6 @@ void ScalpelUserInterface::clearInfo() { } } -/** - * Clear any active text window - */ void ScalpelUserInterface::clearWindow() { if (_windowOpen) { _vm->_screen->vgaBar(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2, @@ -517,9 +486,6 @@ void ScalpelUserInterface::clearWindow() { } } -/** - * Handles counting down whilst checking for input, then clears the info line. - */ void ScalpelUserInterface::whileMenuCounter() { if (!(--_menuCounter) || _vm->_events->checkInput()) { _menuCounter = 0; @@ -528,10 +494,6 @@ void ScalpelUserInterface::whileMenuCounter() { } } -/** - * Creates a text window and uses it to display the in-depth description - * of the highlighted object - */ void ScalpelUserInterface::examine() { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; @@ -568,7 +530,7 @@ void ScalpelUserInterface::examine() { } if (_invLookFlag) { - // Dont close the inventory window when starting an examine display, since it's + // Don't close the inventory window when starting an examine display, since its // window will slide up to replace the inventory display _windowOpen = false; _menuMode = LOOK_MODE; @@ -583,9 +545,6 @@ void ScalpelUserInterface::examine() { } } -/** - * Print the name of an object in the scene - */ void ScalpelUserInterface::lookScreen(const Common::Point &pt) { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; @@ -616,10 +575,10 @@ void ScalpelUserInterface::lookScreen(const Common::Point &pt) { if (!tempStr.empty() && tempStr[0] != ' ') { // 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 == 2 || inv._invMode == 3)) { + (inv._invMode == INVMODE_USE || inv._invMode == INVMODE_GIVE)) { int width1 = 0, width2 = 0; int x, width; - if (inv._invMode == 2) { + if (inv._invMode == INVMODE_USE) { // Using an object x = width = screen.stringWidth("Use "); @@ -651,14 +610,14 @@ void ScalpelUserInterface::lookScreen(const Common::Point &pt) { if (_selector != -1) { screen.print(Common::Point(xStart + width, INFO_LINE + 1), - TALK_FOREGROUND, inv[_selector]._name.c_str()); + 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, tempStr.c_str()); + INFO_FOREGROUND, "%s", tempStr.c_str()); } else { screen.print(Common::Point(xStart + width, INFO_LINE + 1), - INFO_FOREGROUND, tempStr.c_str()); + INFO_FOREGROUND, "%s", tempStr.c_str()); } } else if (temp >= 0 && temp < 1000 && _selector != -1 && scene._bgShapes[temp]._aType == PERSON) { @@ -680,14 +639,14 @@ void ScalpelUserInterface::lookScreen(const Common::Point &pt) { screen.print(Common::Point(xStart, INFO_LINE + 1), INFO_FOREGROUND, "Give "); screen.print(Common::Point(xStart + width, INFO_LINE + 1), - TALK_FOREGROUND, inv[_selector]._name.c_str()); + 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, tempStr.c_str()); + INFO_FOREGROUND, "%s", tempStr.c_str()); } } else { - screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, tempStr.c_str()); + screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", tempStr.c_str()); } _infoFlag = true; @@ -699,9 +658,6 @@ void ScalpelUserInterface::lookScreen(const Common::Point &pt) { } } -/** - * Gets the item in the inventory the mouse is on and display's it's description - */ void ScalpelUserInterface::lookInv() { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; @@ -715,7 +671,7 @@ void ScalpelUserInterface::lookInv() { if (temp < inv._holdings) { clearInfo(); screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, - inv[temp]._description.c_str()); + "%s", inv[temp]._description.c_str()); _infoFlag = true; _oldLook = temp; } @@ -727,9 +683,6 @@ void ScalpelUserInterface::lookInv() { } } -/** - * Handles input when the file list window is being displayed - */ void ScalpelUserInterface::doEnvControl() { Events &events = *_vm->_events; SaveManager &saves = *_vm->_saves; @@ -738,25 +691,24 @@ void ScalpelUserInterface::doEnvControl() { Talk &talk = *_vm->_talk; Common::Point mousePos = events.mousePos(); static const char ENV_COMMANDS[7] = "ELSUDQ"; + byte color; _key = _oldKey = -1; _keyboardInput = false; int found = saves.getHighlightedButton(); - if (events._pressed || events._released) - { + if (events._pressed || events._released) { events.clearKeyboard(); // Check for a filename entry being highlighted - if ((events._pressed || events._released) && mousePos.y > (CONTROLS_Y + 10)) - { + if ((events._pressed || events._released) && mousePos.y > (CONTROLS_Y + 10)) { int found1 = 0; - for (_selector = 0; (_selector < 5) && !found1; ++_selector) + for (_selector = 0; (_selector < ONSCREEN_FILES_COUNT) && !found1; ++_selector) if (mousePos.y > (CONTROLS_Y + 11 + _selector * 10) && mousePos.y < (CONTROLS_Y + 21 + _selector * 10)) found1 = 1; - if (_selector + saves._savegameIndex - 1 < MAX_SAVEGAME_SLOTS + (saves._envMode != 1)) + if (_selector + saves._savegameIndex - 1 < MAX_SAVEGAME_SLOTS + (saves._envMode != SAVEMODE_LOAD)) _selector = _selector + saves._savegameIndex - 1; else _selector = -1; @@ -772,8 +724,8 @@ void ScalpelUserInterface::doEnvControl() { saves._envMode = SAVEMODE_NONE; } - if (_keycode) { - _key = toupper(_keycode); + if (_keyPress) { + _key = toupper(_keyPress); // Escape _key will close the dialog if (_key == Common::KEYCODE_ESCAPE) @@ -790,7 +742,7 @@ void ScalpelUserInterface::doEnvControl() { } else if (_key >= '1' && _key <= '9') { _keyboardInput = true; _selector = _key - '1'; - if (_selector >= MAX_SAVEGAME_SLOTS + (saves._envMode == 1 ? 0 : 1)) + if (_selector >= MAX_SAVEGAME_SLOTS + (saves._envMode == SAVEMODE_LOAD ? 0 : 1)) _selector = -1; if (saves.checkGameOnScreen(_selector)) @@ -802,7 +754,7 @@ void ScalpelUserInterface::doEnvControl() { } if (_selector != _oldSelector) { - if (_oldSelector != -1 && _oldSelector >= saves._savegameIndex && _oldSelector < (saves._savegameIndex + 5)) { + if (_oldSelector != -1 && _oldSelector >= saves._savegameIndex && _oldSelector < (saves._savegameIndex + ONSCREEN_FILES_COUNT)) { screen.print(Common::Point(6, CONTROLS_Y + 12 + (_oldSelector - saves._savegameIndex) * 10), INV_FOREGROUND, "%d.", _oldSelector + 1); screen.print(Common::Point(24, CONTROLS_Y + 12 + (_oldSelector - saves._savegameIndex) * 10), @@ -825,7 +777,7 @@ void ScalpelUserInterface::doEnvControl() { _windowBounds.top = CONTROLS_Y1; events._pressed = events._released = _keyboardInput = false; - _keycode = Common::KEYCODE_INVALID; + _keyPress = '\0'; } else if ((found == 1 && events._released) || _key == 'L') { saves._envMode = SAVEMODE_LOAD; if (_selector != -1) { @@ -837,13 +789,13 @@ void ScalpelUserInterface::doEnvControl() { if (saves.checkGameOnScreen(_selector)) _oldSelector = _selector; - if (saves.getFilename(_selector)) { + if (saves.promptForDescription(_selector)) { saves.saveGame(_selector + 1, saves._savegames[_selector]); banishWindow(1); _windowBounds.top = CONTROLS_Y1; _key = _oldKey = -1; - _keycode = Common::KEYCODE_INVALID; + _keyPress = '\0'; _keyboardInput = false; } else { if (!talk._talkToAbort) { @@ -866,9 +818,9 @@ void ScalpelUserInterface::doEnvControl() { screen._backBuffer1.fillRect(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2, SHERLOCK_SCREEN_HEIGHT - 1), INV_BACKGROUND); - for (int idx = saves._savegameIndex; idx < (saves._savegameIndex + 5); ++idx) { + for (int idx = saves._savegameIndex; idx < (saves._savegameIndex + ONSCREEN_FILES_COUNT); ++idx) { color = INV_FOREGROUND; - if (idx == _selector && idx >= saves._savegameIndex && idx < (saves._savegameIndex + 5)) + if (idx == _selector && idx >= saves._savegameIndex && idx < (saves._savegameIndex + ONSCREEN_FILES_COUNT)) color = TALK_FOREGROUND; screen.gPrint(Common::Point(6, CONTROLS_Y + 11 + (idx - saves._savegameIndex) * 10), color, "%d.", idx + 1); @@ -879,10 +831,10 @@ void ScalpelUserInterface::doEnvControl() { color = !saves._savegameIndex ? COMMAND_NULL : COMMAND_FOREGROUND; screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), color, true, "Up"); - color = (saves._savegameIndex == MAX_SAVEGAME_SLOTS - 5) ? COMMAND_NULL : COMMAND_FOREGROUND; + color = (saves._savegameIndex == MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT) ? COMMAND_NULL : COMMAND_FOREGROUND; screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), color, true, "Down"); - // Check for there are more pending U keys pressed + // Check whether there are more pending U keys pressed moreKeys = false; if (events.kbHit()) { Common::KeyState keyState = events.getKey(); @@ -891,15 +843,15 @@ void ScalpelUserInterface::doEnvControl() { moreKeys = _key == 'U'; } } while ((saves._savegameIndex) && moreKeys); - } else if (((found == 4 && events._released) || _key == 'D') && saves._savegameIndex < (MAX_SAVEGAME_SLOTS - 5)) { + } else if (((found == 4 && events._released) || _key == 'D') && saves._savegameIndex < (MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT)) { bool moreKeys; do { saves._savegameIndex++; screen._backBuffer1.fillRect(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2, SHERLOCK_SCREEN_HEIGHT - 1), INV_BACKGROUND); - for (int idx = saves._savegameIndex; idx < (saves._savegameIndex + 5); ++idx) { - if (idx == _selector && idx >= saves._savegameIndex && idx < (saves._savegameIndex + 5)) + for (int idx = saves._savegameIndex; idx < (saves._savegameIndex + ONSCREEN_FILES_COUNT); ++idx) { + if (idx == _selector && idx >= saves._savegameIndex && idx < (saves._savegameIndex + ONSCREEN_FILES_COUNT)) color = TALK_FOREGROUND; else color = INV_FOREGROUND; @@ -915,10 +867,10 @@ void ScalpelUserInterface::doEnvControl() { color = (!saves._savegameIndex) ? COMMAND_NULL : COMMAND_FOREGROUND; screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), color, true, "Up"); - color = (saves._savegameIndex == MAX_SAVEGAME_SLOTS - 5) ? COMMAND_NULL : COMMAND_FOREGROUND; + color = (saves._savegameIndex == MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT) ? COMMAND_NULL : COMMAND_FOREGROUND; screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), color, true, "Down"); - // Check for there are more pending D keys pressed + // Check whether there are more pending D keys pressed moreKeys = false; if (events.kbHit()) { Common::KeyState keyState; @@ -926,7 +878,7 @@ void ScalpelUserInterface::doEnvControl() { moreKeys = _key == 'D'; } - } while (saves._savegameIndex < (MAX_SAVEGAME_SLOTS - 5) && moreKeys); + } while (saves._savegameIndex < (MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT) && moreKeys); } else if ((found == 5 && events._released) || _key == 'Q') { clearWindow(); screen.print(Common::Point(0, CONTROLS_Y + 20), INV_FOREGROUND, "Are you sure you wish to Quit ?"); @@ -959,11 +911,11 @@ void ScalpelUserInterface::doEnvControl() { if (_key == Common::KEYCODE_ESCAPE) _key = 'N'; - if (_key == Common::KEYCODE_RETURN || _key == Common::KEYCODE_SPACE) { + if (_key == Common::KEYCODE_RETURN || _key == ' ') { events._pressed = false; events._released = true; events._oldButtons = 0; - _keycode = Common::KEYCODE_INVALID; + _keyPress = '\0'; } } @@ -1003,17 +955,17 @@ void ScalpelUserInterface::doEnvControl() { // Are we already in Load mode? if (saves._envMode == SAVEMODE_LOAD) { saves.loadGame(_selector + 1); - } else if (saves._envMode == SAVEMODE_SAVE || _selector == MAX_SAVEGAME_SLOTS) { - // We're alreaady in save mode, or pointed to an empty save slot + } else if (saves._envMode == SAVEMODE_SAVE || saves.isSlotEmpty(_selector)) { + // We're already in save mode, or pointing to an empty save slot if (saves.checkGameOnScreen(_selector)) _oldSelector = _selector; - if (saves.getFilename(_selector)) { + if (saves.promptForDescription(_selector)) { saves.saveGame(_selector + 1, saves._savegames[_selector]); banishWindow(); _windowBounds.top = CONTROLS_Y1; _key = _oldKey = -1; - _keycode = Common::KEYCODE_INVALID; + _keyPress = '\0'; _keyboardInput = false; } else { if (!talk._talkToAbort) { @@ -1033,16 +985,12 @@ void ScalpelUserInterface::doEnvControl() { } } -/** - * Handle input whilst the inventory is active - */ void ScalpelUserInterface::doInvControl() { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; Scene &scene = *_vm->_scene; Screen &screen = *_vm->_screen; Talk &talk = *_vm->_talk; - UserInterface &ui = *_vm->_ui; int colors[8]; Common::Point mousePos = events.mousePos(); @@ -1065,7 +1013,7 @@ void ScalpelUserInterface::doInvControl() { events.clearKeyboard(); if (found != -1) - // If a slot highlighted, set it's color + // If a slot highlighted, set its color colors[found] = COMMAND_HIGHLIGHTED; screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1), colors[0], true, "Exit"); @@ -1088,7 +1036,7 @@ void ScalpelUserInterface::doInvControl() { } bool flag = false; - if (inv._invMode == 1 || inv._invMode == 2 || inv._invMode == 3) { + if (inv._invMode == INVMODE_LOOK || inv._invMode == INVMODE_USE || inv._invMode == INVMODE_GIVE) { Common::Rect r(15, CONTROLS_Y1 + 11, 314, SHERLOCK_SCREEN_HEIGHT - 2); if (r.contains(mousePos)) { _selector = (mousePos.x - 6) / 52 + inv._invIndex; @@ -1101,22 +1049,22 @@ void ScalpelUserInterface::doInvControl() { _selector = -1; } - if (_keycode != Common::KEYCODE_INVALID) { - _key = toupper(_keycode); + if (_keyPress) { + _key = toupper(_keyPress); if (_key == Common::KEYCODE_ESCAPE) // Escape will also 'E'xit out of inventory display - _key = Common::KEYCODE_e; + _key = 'E'; if (_key == 'E' || _key == 'L' || _key == 'U' || _key == 'G' || _key == '-' || _key == '+') { - int temp = inv._invMode; + InvMode temp = inv._invMode; const char *chP = strchr(INVENTORY_COMMANDS, _key); inv._invMode = !chP ? INVMODE_INVALID : (InvMode)(chP - INVENTORY_COMMANDS); inv.invCommands(true); - inv._invMode = (InvMode)temp; + inv._invMode = temp; _keyboardInput = true; if (_key == 'E') inv._invMode = INVMODE_EXIT; @@ -1164,23 +1112,21 @@ void ScalpelUserInterface::doInvControl() { COMMAND_HIGHLIGHTED, "^^"); inv.freeGraphics(); inv.loadGraphics(); - inv.putInv(1); + inv.putInv(SLAM_DISPLAY); inv.invCommands(true); - } else if (((found == 5 && events._released) || _key == Common::KEYCODE_MINUS - || _key == Common::KEYCODE_KP_MINUS) && inv._invIndex > 0) { + } else if (((found == 5 && events._released) || _key == '-') && inv._invIndex > 0) { --inv._invIndex; screen.print(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1), COMMAND_HIGHLIGHTED, "^"); inv.freeGraphics(); inv.loadGraphics(); - inv.putInv(1); + inv.putInv(SLAM_DISPLAY); inv.invCommands(true); - } else if (((found == 6 && events._released) || _key == Common::KEYCODE_PLUS - || _key == Common::KEYCODE_KP_PLUS) && (inv._holdings - inv._invIndex) > 6) { + } else if (((found == 6 && events._released) || _key == '+') && (inv._holdings - inv._invIndex) > 6) { ++inv._invIndex; screen.print(Common::Point(INVENTORY_POINTS[6][2], CONTROLS_Y1 + 1), COMMAND_HIGHLIGHTED, "_"); inv.freeGraphics(); inv.loadGraphics(); - inv.putInv(1); + inv.putInv(SLAM_DISPLAY); inv.invCommands(true); } else if (((found == 7 && events._released) || _key == '.') && (inv._holdings - inv._invIndex) > 6) { inv._invIndex += 6; @@ -1190,11 +1136,11 @@ void ScalpelUserInterface::doInvControl() { screen.print(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1 + 1), COMMAND_HIGHLIGHTED, "_"); inv.freeGraphics(); inv.loadGraphics(); - inv.putInv(1); + inv.putInv(SLAM_DISPLAY); inv.invCommands(true); } else { - // If something is being given, make sure it's to a person - if (inv._invMode == 3) { + // If something is being given, make sure it's being given to a person + if (inv._invMode == INVMODE_GIVE) { if (_bgFound != -1 && scene._bgShapes[_bgFound]._aType == PERSON) _find = _bgFound; else @@ -1203,10 +1149,10 @@ void ScalpelUserInterface::doInvControl() { _find = _bgFound; } - if ((mousePos.y < CONTROLS_Y1) && (inv._invMode == 1) && (_find >= 0) && (_find < 1000)) { + if ((mousePos.y < CONTROLS_Y1) && (inv._invMode == INVMODE_LOOK) && (_find >= 0) && (_find < 1000)) { if (!scene._bgShapes[_find]._examine.empty() && scene._bgShapes[_find]._examine[0] >= ' ') - ui.doInvJF(); + inv.refreshInv(); } else if (_selector != -1 || _find >= 0) { // Selector is the inventory object that was clicked on, or selected. // If it's -1, then no inventory item is highlighted yet. Otherwise, @@ -1214,29 +1160,29 @@ void ScalpelUserInterface::doInvControl() { if (_selector != -1 && inv._invMode == INVMODE_LOOK && mousePos.y >(CONTROLS_Y1 + 11)) - ui.doInvJF(); + inv.refreshInv(); if (talk._talkToAbort) return; - // Now check for the Use and Give actions. If inv_mode is 3, + // Now check for the Use and Give actions. If inv_mode is INVMODE_GIVE, // that means GIVE is in effect, _selector is the object being // given, and _find is the target. // The same applies to USE, except if _selector is -1, then USE // is being tried on an object in the scene without an inventory // object being highlighted first. - if ((inv._invMode == 2 || (_selector != -1 && inv._invMode == 3)) && _find >= 0) { + if ((inv._invMode == INVMODE_USE || (_selector != -1 && inv._invMode == INVMODE_GIVE)) && _find >= 0) { events._pressed = events._released = false; _infoFlag = true; clearInfo(); - int temp = _selector; // Save the selector + int tempSel = _selector; // Save the selector _selector = -1; - inv.putInv(1); - _selector = temp; // Restore it - temp = inv._invMode; + inv.putInv(SLAM_DISPLAY); + _selector = tempSel; // Restore it + InvMode tempMode = inv._invMode; inv._invMode = INVMODE_USE55; inv.invCommands(true); @@ -1247,12 +1193,13 @@ void ScalpelUserInterface::doInvControl() { inv.freeInv(); + bool giveFl = (tempMode >= INVMODE_GIVE); if (_selector >= 0) // Use/Give inv object with scene object - checkUseAction(&scene._bgShapes[_find]._use[0], inv[_selector]._name, MUSE, _find, temp - 2); + checkUseAction(&scene._bgShapes[_find]._use[0], inv[_selector]._name, MUSE, _find, giveFl); else // Now inv object has been highlighted - checkUseAction(&scene._bgShapes[_find]._use[0], "*SELF*", MUSE, _find, temp - 2); + checkUseAction(&scene._bgShapes[_find]._use[0], "*SELF*", MUSE, _find, giveFl); _selector = _oldSelector = -1; } @@ -1261,16 +1208,13 @@ void ScalpelUserInterface::doInvControl() { } } -/** - * Handles waiting whilst an object's description window is open. - */ void ScalpelUserInterface::doLookControl() { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; Screen &screen = *_vm->_screen; _key = _oldKey = -1; - _keyboardInput = (_keycode != Common::KEYCODE_INVALID); + _keyboardInput = (_keyPress != '\0'); if (events._released || events._rightReleased || _keyboardInput) { // Is an inventory object being looked at? @@ -1281,7 +1225,7 @@ void ScalpelUserInterface::doLookControl() { } else if (!_lookHelp) { // Need to close the window and depress the Look button Common::Point pt(MENU_POINTS[0][0], MENU_POINTS[0][1]); - screen._backBuffer2.blitFrom((*_controls)[0]._frame, pt); + screen._backBuffer2.blitFrom((*_controls)[0], pt); banishWindow(true); _windowBounds.top = CONTROLS_Y1; @@ -1308,7 +1252,7 @@ void ScalpelUserInterface::doLookControl() { tempSurface.blitFrom(screen._backBuffer2, Common::Point(0, 0), Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); - inv.drawInventory(128); + inv.drawInventory(INVENTORY_DONT_DISPLAY); banishWindow(true); // Restore the ui @@ -1325,9 +1269,6 @@ void ScalpelUserInterface::doLookControl() { } } -/** - * Handles input until one of the user interface buttons/commands is selected - */ void ScalpelUserInterface::doMainControl() { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; @@ -1346,12 +1287,12 @@ void ScalpelUserInterface::doMainControl() { _key = COMMANDS[_temp]; } --_temp; - } else if (_keycode != Common::KEYCODE_INVALID) { + } else if (_keyPress) { // Keyboard control _keyboardInput = true; - if (_keycode >= Common::KEYCODE_a && _keycode <= Common::KEYCODE_z) { - const char *c = strchr(COMMANDS, _keycode); + if (_keyPress >= 'A' && _keyPress <= 'Z') { + const char *c = strchr(COMMANDS, _keyPress); _temp = !c ? 12 : c - COMMANDS; } else { _temp = 12; @@ -1413,19 +1354,19 @@ void ScalpelUserInterface::doMainControl() { pushButton(6); _selector = _oldSelector = -1; _menuMode = INV_MODE; - inv.drawInventory(1); + inv.drawInventory(PLAIN_INVENTORY); break; case 'U': pushButton(7); _selector = _oldSelector = -1; _menuMode = USE_MODE; - inv.drawInventory(2); + inv.drawInventory(USE_INVENTORY_MODE); break; case 'G': pushButton(8); _selector = _oldSelector = -1; _menuMode = GIVE_MODE; - inv.drawInventory(3); + inv.drawInventory(GIVE_INVENTORY_MODE); break; case 'J': pushButton(9); @@ -1466,9 +1407,6 @@ void ScalpelUserInterface::doMainControl() { } } -/** - * Handles the input for the MOVE, OPEN, and CLOSE commands - */ void ScalpelUserInterface::doMiscControl(int allowed) { Events &events = *_vm->_events; Scene &scene = *_vm->_scene; @@ -1518,9 +1456,6 @@ void ScalpelUserInterface::doMiscControl(int allowed) { } } -/** - * Handles input for picking up items - */ void ScalpelUserInterface::doPickControl() { Events &events = *_vm->_events; Scene &scene = *_vm->_scene; @@ -1544,10 +1479,6 @@ void ScalpelUserInterface::doPickControl() { } } -/** - * Handles input when in talk mode. It highlights the buttons and available statements, - * and handles allowing the user to click on them - */ void ScalpelUserInterface::doTalkControl() { Events &events = *_vm->_events; Journal &journal = *_vm->_journal; @@ -1590,8 +1521,8 @@ void ScalpelUserInterface::doTalkControl() { _selector = -1; } - if (_keycode != Common::KEYCODE_INVALID) { - _key = toupper(_keycode); + if (_keyPress) { + _key = toupper(_keyPress); if (_key == Common::KEYCODE_ESCAPE) _key = 'E'; @@ -1798,12 +1729,6 @@ void ScalpelUserInterface::doTalkControl() { } } -/** - * Handles events when the Journal is active. - * @remarks Whilst this would in theory be better in the Journal class, since it displays in - * the user interface, it uses so many internal UI fields, that it sort of made some sense - * to put it in the UserInterface class. - */ void ScalpelUserInterface::journalControl() { Events &events = *_vm->_events; Journal &journal = *_vm->_journal; @@ -1838,7 +1763,7 @@ void ScalpelUserInterface::journalControl() { // Finish up _infoFlag = _keyboardInput = false; - _keycode = Common::KEYCODE_INVALID; + _keyPress = '\0'; _windowOpen = false; _windowBounds.top = CONTROLS_Y1; _key = -1; @@ -1852,9 +1777,6 @@ void ScalpelUserInterface::journalControl() { screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); } -/** -* Print the description of an object -*/ void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool firstTime) { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; @@ -1884,8 +1806,8 @@ void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool first Common::Point pt(MENU_POINTS[0][0], MENU_POINTS[0][1]); 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]._frame, pt); + Common::Rect(pt.x, pt.y, pt.x + tempSurface.w(), pt.y + tempSurface.h())); + screen._backBuffer2.transBlitFrom((*_controls)[0], pt); banishWindow(1); events.setCursor(MAGNIFY); @@ -1912,7 +1834,7 @@ void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool first // Reload the inventory graphics and draw the inventory inv.loadInv(); - inv.putInv(2); + inv.putInv(SLAM_SECONDARY_BUFFER); inv.freeInv(); banishWindow(1); @@ -1955,7 +1877,7 @@ void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool first // Loop through displaying up to five lines bool endOfStr = false; const char *msgP = str.c_str(); - for (int lineNum = 0; lineNum < 5 && !endOfStr; ++lineNum) { + for (int lineNum = 0; lineNum < ONSCREEN_FILES_COUNT && !endOfStr; ++lineNum) { int width = 0; const char *lineStartP = msgP; @@ -1980,7 +1902,7 @@ void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool first // Print out the line Common::String line(lineStartP, msgP); screen.gPrint(Common::Point(16, CONTROLS_Y + 12 + lineNum * 9), - INV_FOREGROUND, line.c_str()); + INV_FOREGROUND, "%s", line.c_str()); if (!endOfStr) // Start next line at start of the nxet word after space @@ -2007,7 +1929,7 @@ void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool first } if (firstTime) { - if (!_windowStyle) { + if (!_slideWindows) { screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); } else { @@ -2023,16 +1945,10 @@ void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool first } } -/** - * Print the previously selected object's decription - */ void ScalpelUserInterface::printObjectDesc() { printObjectDesc(_cAnimStr, true); } -/** - * Displays a passed window by gradually scrolling it vertically on-screen - */ void ScalpelUserInterface::summonWindow(const Surface &bgSurface, bool slideUp) { Events &events = *_vm->_events; Screen &screen = *_vm->_screen; @@ -2043,9 +1959,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) { + 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)); + Common::Rect(0, 0, bgSurface.w(), idx)); screen.slamRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - idx, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); @@ -2053,29 +1969,25 @@ 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) { + 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)); + 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)); 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->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()); _windowOpen = true; } -/** - * Slide the window stored in the back buffer onto the screen - */ void ScalpelUserInterface::summonWindow(bool slideUp, int height) { Screen &screen = *_vm->_screen; @@ -2093,19 +2005,15 @@ void ScalpelUserInterface::summonWindow(bool slideUp, int height) { summonWindow(tempSurface, slideUp); } -/** - * Close a currently open window - * @param flag 0 = slide old window down, 1 = slide prior UI back up - */ void ScalpelUserInterface::banishWindow(bool slideUp) { Events &events = *_vm->_events; Screen &screen = *_vm->_screen; if (_windowOpen) { - if (slideUp || !_windowStyle) { + if (slideUp || !_slideWindows) { // Slide window down // Only slide the window if the window style allows it - if (_windowStyle) { + if (_slideWindows) { for (int idx = 2; idx < (SHERLOCK_SCREEN_HEIGHT - CONTROLS_Y); idx += 2) { // Shift the window down by 2 lines byte *pSrc = (byte *)screen._backBuffer1.getBasePtr(0, CONTROLS_Y + idx - 2); @@ -2163,11 +2071,8 @@ void ScalpelUserInterface::banishWindow(bool slideUp) { _menuMode = STD_MODE; } -/** - * Checks to see whether a USE action is valid on the given object - */ void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::String &invName, - const char *const messages[], int objNum, int giveMode) { + const char *const messages[], int objNum, bool giveMode) { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; Scene &scene = *_vm->_scene; @@ -2190,18 +2095,18 @@ void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::Stri // Scan for target item int targetNum = -1; if (giveMode) { - for (int idx = 0; idx < 4 && targetNum == -1; ++idx) { - if ((scumm_stricmp(use[idx]._target.c_str(), "*GIVE*") == 0 || scumm_stricmp(use[idx]._target.c_str(), "*GIVEP*") == 0) - && scumm_stricmp(use[idx]._names[0].c_str(), invName.c_str()) == 0) { + for (int idx = 0; idx < USE_COUNT && targetNum == -1; ++idx) { + if ((use[idx]._target.equalsIgnoreCase("*GIVE*") || use[idx]._target.equalsIgnoreCase("*GIVEP*")) + && use[idx]._names[0].equalsIgnoreCase(invName)) { // Found a match targetNum = idx; - if (scumm_stricmp(use[idx]._target.c_str(), "*GIVE*") == 0) + if (use[idx]._target.equalsIgnoreCase("*GIVE*")) inv.deleteItemFromInventory(invName); } } } else { - for (int idx = 0; idx < 4 && targetNum == -1; ++idx) { - if (scumm_stricmp(use[idx]._target.c_str(), invName.c_str()) == 0) + for (int idx = 0; idx < USE_COUNT && targetNum == -1; ++idx) { + if (use[idx]._target.equalsIgnoreCase(invName)) targetNum = idx; } } @@ -2224,7 +2129,7 @@ void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::Stri if (!talk._talkToAbort) { Object &obj = scene._bgShapes[objNum]; - for (int idx = 0; idx < 4 && !talk._talkToAbort; ++idx) { + for (int idx = 0; idx < NAMES_COUNT && !talk._talkToAbort; ++idx) { if (obj.checkNameForCodes(action._names[idx], messages)) { if (!talk._talkToAbort) printed = true; @@ -2249,7 +2154,7 @@ void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::Stri } else if (messages == nullptr) { screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "You can't do that."); } else { - screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, messages[0]); + screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", messages[0]); } _infoFlag = true; @@ -2259,9 +2164,6 @@ void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::Stri events.setCursor(ARROW); } -/** - * Called for OPEN, CLOSE, and MOVE actions are being done - */ void ScalpelUserInterface::checkAction(ActionType &action, const char *const messages[], int objNum) { Events &events = *_vm->_events; People &people = *_vm->_people; @@ -2278,7 +2180,7 @@ void ScalpelUserInterface::checkAction(ActionType &action, const char *const mes // Invalid action, to print error message _infoFlag = true; clearInfo(); - screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, messages[action._cAnimNum]); + screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", messages[action._cAnimNum]); _infoFlag = true; // Set how long to show the message @@ -2316,7 +2218,7 @@ void ScalpelUserInterface::checkAction(ActionType &action, const char *const mes events.setCursor(WAIT); bool printed = false; - for (int nameIdx = 0; nameIdx < 4; ++nameIdx) { + for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) { if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2 && toupper(action._names[nameIdx][1]) == 'W') { if (obj.checkNameForCodes(Common::String(action._names[nameIdx].c_str() + 2), messages)) { @@ -2327,7 +2229,7 @@ void ScalpelUserInterface::checkAction(ActionType &action, const char *const mes } bool doCAnim = true; - for (int nameIdx = 0; nameIdx < 4; ++nameIdx) { + for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) { if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2) { char ch = toupper(action._names[nameIdx][1]); @@ -2357,7 +2259,7 @@ void ScalpelUserInterface::checkAction(ActionType &action, const char *const mes people.walkToCoords(pt, dir); } - for (int nameIdx = 0; nameIdx < 4; ++nameIdx) { + for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) { if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2 && toupper(action._names[nameIdx][1]) == 'F') { if (obj.checkNameForCodes(action._names[nameIdx].c_str() + 2, messages)) { @@ -2371,7 +2273,7 @@ void ScalpelUserInterface::checkAction(ActionType &action, const char *const mes scene.startCAnim(cAnimNum, action._cAnimSpeed); if (!talk._talkToAbort) { - for (int nameIdx = 0; nameIdx < 4 && !talk._talkToAbort; ++nameIdx) { + for (int nameIdx = 0; nameIdx < NAMES_COUNT && !talk._talkToAbort; ++nameIdx) { if (obj.checkNameForCodes(action._names[nameIdx], messages)) { if (!talk._talkToAbort) printed = true; @@ -2394,31 +2296,6 @@ void ScalpelUserInterface::checkAction(ActionType &action, const char *const mes events.setCursor(ARROW); } -/** - * Support method for updating the screen - */ -void ScalpelUserInterface::doInvJF() { - Inventory &inv = *_vm->_inventory; - Screen &screen = *_vm->_screen; - Talk &talk = *_vm->_talk; - - _invLookFlag = true; - inv.freeInv(); - - _infoFlag = true; - clearInfo(); - - screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(0, CONTROLS_Y), - Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); - examine(); - - if (!talk._talkToAbort) { - screen._backBuffer2.blitFrom((*_controlPanel)[0]._frame, - Common::Point(0, CONTROLS_Y)); - inv.loadInv(); - } -} - /*----------------------------------------------------------------*/ TattooUserInterface::TattooUserInterface(SherlockEngine *vm): UserInterface(vm) { diff --git a/engines/sherlock/user_interface.h b/engines/sherlock/user_interface.h index acbb0c0ed0..8a0f4f5613 100644 --- a/engines/sherlock/user_interface.h +++ b/engines/sherlock/user_interface.h @@ -74,14 +74,14 @@ public: bool _windowOpen; bool _endKeyActive; int _invLookFlag; - int _windowStyle; + bool _slideWindows; bool _helpStyle; Common::Rect _windowBounds; bool _lookScriptFlag; // TODO: Not so sure these should be in the base class. May want to refactor them to SherlockEngine, or refactor // various Scalpel dialogs to keep their own private state of key/selections - int _key, _oldKey; + char _key, _oldKey; int _selector, _oldSelector; int _temp, _oldTemp; int _temp1; @@ -89,17 +89,50 @@ public: public: static UserInterface *init(SherlockEngine *vm); + /** + * Resets the user interface + */ virtual void reset() {} + + /** + * Draw the user interface onto the screen's back buffers + */ virtual void drawInterface(int bufferNum = 3) {} + + /** + * Main input handler for the user interface + */ virtual void handleInput() {} - virtual void doInvJF() {} + /** + * Displays a passed window by gradually scrolling it vertically on-screen + */ virtual void summonWindow(const Surface &bgSurface, bool slideUp = true) {} + + /** + * Slide the window stored in the back buffer onto the screen + */ virtual void summonWindow(bool slideUp = true, int height = CONTROLS_Y) {} + + /** + * Close a currently open window + * @param flag 0 = slide old window down, 1 = slide prior UI back up + */ virtual void banishWindow(bool slideUp = true) {} + + /** + * Clears the info line of the screen + */ virtual void clearInfo() {} + + /** + * Clear any active text window + */ virtual void clearWindow() {} + /** + * Print the previously selected object's decription + */ virtual void printObjectDesc() {} }; @@ -110,10 +143,12 @@ class ScalpelUserInterface: public UserInterface { private: ImageFile *_controlPanel; ImageFile *_controls; - int _bgFound; - int _oldBgFound; - int _keycode; + char _keyPress; + int _lookHelp; + int _bgFound, _oldBgFound; int _help, _oldHelp; + char _key, _oldKey; + int _temp, _oldTemp; int _oldLook; bool _keyboardInput; bool _pause; @@ -123,54 +158,158 @@ private: int _find; int _oldUse; private: + /** + * Draws the image for a user interface button in the down/pressed state. + */ void depressButton(int num); + /** + * If he mouse button is pressed, then calls depressButton to draw the button + * as pressed; if not, it will show it as released with a call to "restoreButton". + */ void pushButton(int num); + /** + * By the time this method has been called, the graphics for the button change + * have already been drawn. This simply takes care of switching the mode around + * accordingly + */ void toggleButton(int num); + /** + * Creates a text window and uses it to display the in-depth description + * of the highlighted object + */ void examine(); + /** + * Print the name of an object in the scene + */ void lookScreen(const Common::Point &pt); + /** + * Gets the item in the inventory the mouse is on and display's it's description + */ void lookInv(); + /** + * Handles input when the file list window is being displayed + */ void doEnvControl(); + + /** + * Handle input whilst the inventory is active + */ void doInvControl(); + + /** + * Handles waiting whilst an object's description window is open. + */ void doLookControl(); + + /** + * Handles input until one of the user interface buttons/commands is selected + */ void doMainControl(); + + /** + * Handles the input for the MOVE, OPEN, and CLOSE commands + */ void doMiscControl(int allowed); + + /** + * Handles input for picking up items + */ void doPickControl(); + + /** + * Handles input when in talk mode. It highlights the buttons and available statements, + * and handles allowing the user to click on them + */ void doTalkControl(); + + /** + * Handles events when the Journal is active. + * @remarks Whilst this would in theory be better in the Journal class, since it displays in + * the user interface, it uses so many internal UI fields, that it sort of made some sense + * to put it in the UserInterface class. + */ void journalControl(); + /** + * Checks to see whether a USE action is valid on the given object + */ void checkUseAction(const UseType *use, const Common::String &invName, const char *const messages[], - int objNum, int giveMode); + int objNum, bool giveMode); + + /** + * Called for OPEN, CLOSE, and MOVE actions are being done + */ void checkAction(ActionType &action, const char *const messages[], int objNum); + /** + * Print the previously selected object's decription + */ void printObjectDesc(const Common::String &str, bool firstTime); public: ScalpelUserInterface(SherlockEngine *vm); ~ScalpelUserInterface(); + /** + * Handles counting down whilst checking for input, then clears the info line. + */ void whileMenuCounter(); + /** + * Draws the image for the given user interface button in the up + * (not selected) position + */ void restoreButton(int num); public: + /** + * Resets the user interface + */ virtual void reset(); + /** + * Main input handler for the user interface + */ virtual void handleInput(); + /** + * Draw the user interface onto the screen's back buffers + */ virtual void drawInterface(int bufferNum = 3); - virtual void doInvJF(); - + /** + * Displays a passed window by gradually scrolling it vertically on-screen + */ virtual void summonWindow(const Surface &bgSurface, bool slideUp = true); + + /** + * Slide the window stored in the back buffer onto the screen + */ virtual void summonWindow(bool slideUp = true, int height = CONTROLS_Y); + + /** + * Close a currently open window + * @param flag 0 = slide old window down, 1 = slide prior UI back up + */ virtual void banishWindow(bool slideUp = true); + + /** + * Clears the info line of the screen + */ virtual void clearInfo(); + + /** + * Clear any active text window + */ virtual void clearWindow(); + /** + * Print the previously selected object's decription + */ virtual void printObjectDesc(); }; @@ -178,6 +317,9 @@ class TattooUserInterface : public UserInterface { public: TattooUserInterface(SherlockEngine *vm); public: + /** + * Main input handler for the user interface + */ virtual void handleInput(); }; diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp index 09f865f798..9e2905f454 100644 --- a/engines/toon/toon.cpp +++ b/engines/toon/toon.cpp @@ -1785,7 +1785,7 @@ int32 ToonEngine::runEventScript(int32 x, int32 y, int32 mode, int32 id, int32 s _currentScriptRegion++; _script->start(status, 1); - while (_script->run(status)) + while (_script->run(status) && !_shouldQuit) waitForScriptStep(); _currentScriptRegion--; |