diff options
author | Kamil Zbróg | 2014-01-27 21:43:05 +0100 |
---|---|---|
committer | Kamil Zbróg | 2014-01-27 21:43:05 +0100 |
commit | 8eac80cfc59c34299899ebe18a3b0582ef76e0d2 (patch) | |
tree | 5d02a8fba0559c16f2a2045b14e3e292509c6924 | |
parent | 444934a0accec982f55db92c17ef65270fe18e66 (diff) | |
parent | 0f5eeaed7b3c9d2f74eee7dff2114c5f4dc63f00 (diff) | |
download | scummvm-rg350-8eac80cfc59c34299899ebe18a3b0582ef76e0d2.tar.gz scummvm-rg350-8eac80cfc59c34299899ebe18a3b0582ef76e0d2.tar.bz2 scummvm-rg350-8eac80cfc59c34299899ebe18a3b0582ef76e0d2.zip |
Merge remote-tracking branch 'sync/master' into prince-malik
161 files changed, 5325 insertions, 1755 deletions
@@ -62,7 +62,7 @@ ScummVM Team Oliver Kiehl - (retired) Ludvig Strigeus - (retired) - AVALANCHE: + Avalanche: Peter Bozso Arnaud Boutonne @@ -33,8 +33,9 @@ ifeq "$(HAVE_GCC)" "1" #CXXFLAGS+= -Wmissing-format-attribute ifneq "$(BACKEND)" "tizen" - # Disable RTTI and exceptions. These settings cause tizen apps to crash - CXXFLAGS+= -fno-rtti -fno-exceptions + # Disable exceptions. This setting causes tizen apps to crash + # TODO: Does this still apply after enabling RTTI again? + CXXFLAGS+= -fno-exceptions endif ifneq "$(HAVE_CLANG)" "1" @@ -5,6 +5,7 @@ For a more comprehensive changelog of the latest experimental code, see: New Games: - Added support for Return to Ringworld. - Added support for The Neverhood. + - Added support for Mortville Manor. General: - Updated Munt MT-32 emulation code to version 1.3.0. @@ -13,6 +14,12 @@ For a more comprehensive changelog of the latest experimental code, see: (NOTE: The change to libpng was done in version 1.6.0, but it was not added to the NEWS file). + Broken Sword 1: + - Added back support for MPEG-2 videos. + + Broken Sword 2: + - Added back support for MPEG-2 videos. + Gob: - Improved video quality in Urban Runner. @@ -29,11 +36,10 @@ For a more comprehensive changelog of the latest experimental code, see: - Improved the MIDI parser so that music event processing is done more properly. - Broken Sword 1: - - Added back support for MPEG-2 videos. - - Broken Sword 2: - - Added back support for MPEG-2 videos. + SCUMM: + - Changed the saved game naming scheme of HE games to always contain + the target name. + - Fixed having multiple coaches in Backyard Football. Tinsel: - Discworld 1 and 2 no longer crash on big-endian systems. diff --git a/audio/decoders/voc.cpp b/audio/decoders/voc.cpp index fa330c6f2c..ec589533eb 100644 --- a/audio/decoders/voc.cpp +++ b/audio/decoders/voc.cpp @@ -559,7 +559,7 @@ SeekableAudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flag SeekableAudioStream *audioStream = new VocStream(stream, (flags & Audio::FLAG_UNSIGNED) != 0, disposeAfterUse); - if (audioStream && audioStream->endOfData()) { + if (audioStream->endOfData()) { delete audioStream; return 0; } else { diff --git a/audio/midiparser.cpp b/audio/midiparser.cpp index 2454575413..61f82c4ca4 100644 --- a/audio/midiparser.cpp +++ b/audio/midiparser.cpp @@ -214,13 +214,16 @@ void MidiParser::onTimer() { activeNote(info.channel(), info.basic.param1, true); } - processEvent(info); - - if (_abortParse) - break; + // Player::metaEvent() in SCUMM will delete the parser object, + // so return immediately if that might have happened. + bool ret = processEvent(info); + if (!ret) + return; - _position._lastEventTime = eventTime; - parseNextEvent(_nextEvent); + if (!_abortParse) { + _position._lastEventTime = eventTime; + parseNextEvent(_nextEvent); + } } if (!_abortParse) { @@ -229,7 +232,7 @@ void MidiParser::onTimer() { } } -void MidiParser::processEvent(const EventInfo &info, bool fireEvents) { +bool MidiParser::processEvent(const EventInfo &info, bool fireEvents) { if (info.event == 0xF0) { // SysEx event // Check for trailing 0xF7 -- if present, remove it. @@ -252,8 +255,7 @@ void MidiParser::processEvent(const EventInfo &info, bool fireEvents) { if (fireEvents) _driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length); } - _abortParse = true; - return; + return false; } else if (info.ext.type == 0x51) { if (info.length >= 3) { setTempo(info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]); @@ -265,6 +267,8 @@ void MidiParser::processEvent(const EventInfo &info, bool fireEvents) { if (fireEvents) sendToDriver(info.event, info.basic.param1, info.basic.param2); } + + return true; } diff --git a/audio/midiparser.h b/audio/midiparser.h index 05d0cbe1db..9499d01512 100644 --- a/audio/midiparser.h +++ b/audio/midiparser.h @@ -294,7 +294,7 @@ protected: virtual void resetTracking(); virtual void allNotesOff(); virtual void parseNextEvent(EventInfo &info) = 0; - virtual void processEvent(const EventInfo &info, bool fireEvents = true); + virtual bool processEvent(const EventInfo &info, bool fireEvents = true); void activeNote(byte channel, byte note, bool active); void hangingNote(byte channel, byte note, uint32 ticksLeft, bool recycle = true); diff --git a/audio/softsynth/eas.cpp b/audio/softsynth/eas.cpp index ea79b25329..0631df2a7c 100644 --- a/audio/softsynth/eas.cpp +++ b/audio/softsynth/eas.cpp @@ -305,7 +305,7 @@ int MidiDriver_EAS::open() { warning("error opening EAS dump file"); #endif - g_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, + g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); diff --git a/audio/softsynth/fluidsynth.cpp b/audio/softsynth/fluidsynth.cpp index efcf1be615..218a06ecc0 100644 --- a/audio/softsynth/fluidsynth.cpp +++ b/audio/softsynth/fluidsynth.cpp @@ -184,8 +184,7 @@ int MidiDriver_FluidSynth::open() { MidiDriver_Emulated::open(); - // The MT-32 emulator uses kSFXSoundType here. I don't know why. - _mixer->playStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); return 0; } diff --git a/audio/softsynth/mt32.cpp b/audio/softsynth/mt32.cpp index 2a90b583f3..7f46e926bc 100644 --- a/audio/softsynth/mt32.cpp +++ b/audio/softsynth/mt32.cpp @@ -80,15 +80,6 @@ protected: void showLCDMessage(const char *message) { g_system->displayMessageOnOSD(message); } - void onDeviceReset() {} - void onDeviceReconfig() {} - void onNewReverbMode(Bit8u /* mode */) {} - void onNewReverbTime(Bit8u /* time */) {} - void onNewReverbLevel(Bit8u /* level */) {} - void onPartStateChanged(int /* partNum */, bool /* isActive */) {} - void onPolyStateChanged(int /* partNum */) {} - void onPartialStateChanged(int /* partialNum */, int /* oldPartialPhase */, int /* newPartialPhase */) {} - void onProgramChanged(int /* partNum */, char * /* patchName */) {} }; } // end of namespace MT32Emu @@ -230,7 +221,7 @@ int MidiDriver_MT32::open() { g_system->updateScreen(); - _mixer->playStream(Audio::Mixer::kSFXSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); return 0; } diff --git a/backends/events/maemosdl/maemosdl-events.cpp b/backends/events/maemosdl/maemosdl-events.cpp index dcdf0384e3..eaf2f48b60 100644 --- a/backends/events/maemosdl/maemosdl-events.cpp +++ b/backends/events/maemosdl/maemosdl-events.cpp @@ -188,7 +188,7 @@ bool MaemoSdlEventSource::handleMouseButtonUp(SDL_Event &ev, Common::Event &even bool MaemoSdlEventSource::toggleClickMode() { _clickEnabled = !_clickEnabled; - ((SurfaceSdlGraphicsManager *) _graphicsManager)->displayMessageOnOSD( + _graphicsManager->displayMessageOnOSD( _clickEnabled ? _("Clicking Enabled") : _("Clicking Disabled")); return _clickEnabled; diff --git a/backends/fs/amigaos4/amigaos4-fs.cpp b/backends/fs/amigaos4/amigaos4-fs.cpp index 6d713f10be..bd8bf1978a 100644 --- a/backends/fs/amigaos4/amigaos4-fs.cpp +++ b/backends/fs/amigaos4/amigaos4-fs.cpp @@ -81,6 +81,7 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode(const Common::String &p) { _sDisplayName = ::lastPathComponent(_sPath); _pFileLock = 0; _bIsDirectory = false; + _bIsValid = false; // Check whether the node exists and if it is a directory struct ExamineData * pExd = IDOS->ExamineObjectTags(EX_StringNameInput,_sPath.c_str(),TAG_END); @@ -305,12 +306,6 @@ bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b AbstractFSNode *AmigaOSFilesystemNode::getParent() const { ENTER(); - if (!_bIsDirectory) { - debug(6, "Not a directory"); - LEAVE(); - return 0; - } - if (_pFileLock == 0) { debug(6, "Root node"); LEAVE(); @@ -332,6 +327,9 @@ AbstractFSNode *AmigaOSFilesystemNode::getParent() const { } bool AmigaOSFilesystemNode::isReadable() const { + if (!_bIsValid) + return false; + // Regular RWED protection flags are low-active or inverted, thus the negation. // moreover pseudo root filesystem (null _pFileLock) is readable whatever the // protection says @@ -341,6 +339,9 @@ bool AmigaOSFilesystemNode::isReadable() const { } bool AmigaOSFilesystemNode::isWritable() const { + if (!_bIsValid) + return false; + // Regular RWED protection flags are low-active or inverted, thus the negation. // moreover pseudo root filesystem (null _pFileLock) is never writable whatever // the protection says (because of the pseudo nature) diff --git a/backends/fs/amigaos4/amigaos4-fs.h b/backends/fs/amigaos4/amigaos4-fs.h index c5ca61476f..7ce9981479 100644 --- a/backends/fs/amigaos4/amigaos4-fs.h +++ b/backends/fs/amigaos4/amigaos4-fs.h @@ -43,7 +43,13 @@ */ class AmigaOSFilesystemNode : public AbstractFSNode { protected: + /** + * The main file lock. + * If this is NULL but _bIsValid is true, then this Node references + * the virtual filesystem root. + */ BPTR _pFileLock; + Common::String _sDisplayName; Common::String _sPath; bool _bIsDirectory; diff --git a/backends/fs/wii/wii-fs-factory.cpp b/backends/fs/wii/wii-fs-factory.cpp index 760e5316e7..f234c1e300 100644 --- a/backends/fs/wii/wii-fs-factory.cpp +++ b/backends/fs/wii/wii-fs-factory.cpp @@ -33,6 +33,9 @@ #ifdef USE_WII_DI #include <di/di.h> #include <iso9660.h> +#ifdef GAMECUBE +#include <ogc/dvd.h> +#endif #endif #ifdef USE_WII_SMB @@ -125,6 +128,14 @@ bool WiiFilesystemFactory::failedToMount(FileSystemType type) { return false; } +#ifdef USE_WII_DI +#ifndef GAMECUBE + const DISC_INTERFACE* dvd = &__io_wiidvd; +#else + const DISC_INTERFACE* dvd = &__io_gcdvd; +#endif +#endif + void WiiFilesystemFactory::mount(FileSystemType type) { switch (type) { case kDVD: @@ -133,7 +144,7 @@ void WiiFilesystemFactory::mount(FileSystemType type) { break; printf("mount dvd\n"); - if (ISO9660_Mount()) { + if (ISO9660_Mount("dvd", dvd)) { _dvdMounted = true; _dvdError = false; printf("ISO9660 mounted\n"); @@ -179,7 +190,7 @@ void WiiFilesystemFactory::umount(FileSystemType type) { printf("umount dvd\n"); - ISO9660_Unmount(); + ISO9660_Unmount("dvd:"); _dvdMounted = false; _dvdError = false; diff --git a/backends/fs/wii/wii-fs.cpp b/backends/fs/wii/wii-fs.cpp index 4a19e18240..43f4f592b7 100644 --- a/backends/fs/wii/wii-fs.cpp +++ b/backends/fs/wii/wii-fs.cpp @@ -80,9 +80,9 @@ void WiiFilesystemNode::clearFlags() { void WiiFilesystemNode::setFlags(const struct stat *st) { _exists = true; - _isDirectory = S_ISDIR(st->st_mode); - _isReadable = (st->st_mode & S_IRUSR) > 0; - _isWritable = (st->st_mode & S_IWUSR) > 0; + _isDirectory = ( (st->st_mode & S_IFDIR) != 0 ); + _isReadable = ( (st->st_mode & S_IRUSR) != 0 ); + _isWritable = ( (st->st_mode & S_IWUSR) != 0 ); } WiiFilesystemNode::WiiFilesystemNode() { @@ -106,7 +106,7 @@ WiiFilesystemNode::WiiFilesystemNode(const Common::String &p) { _displayName = lastPathComponent(_path, '/'); struct stat st; - if (!stat(_path.c_str(), &st)) + if(stat(_path.c_str(), &st) != -1) setFlags(&st); else clearFlags(); @@ -152,33 +152,45 @@ bool WiiFilesystemNode::getChildren(AbstractFSList &list, ListMode mode, bool hi if (_path.empty()) return getDevopChildren(list, mode, hidden); - DIR_ITER* dp = diropen (_path.c_str()); + DIR* dp = opendir (_path.c_str()); + DIR* tmpdir; if (dp == NULL) return false; - char filename[MAXPATHLEN]; - struct stat st; + struct dirent *pent; - while (dirnext(dp, filename, &st) == 0) { - if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0) + while ((pent = readdir(dp)) != NULL) { + if (strcmp(pent->d_name, ".") == 0 || strcmp(pent->d_name, "..") == 0) continue; Common::String newPath(_path); if (newPath.lastChar() != '/') - newPath += '/'; - newPath += filename; - - bool isDir = S_ISDIR(st.st_mode); - + newPath += '/'; + newPath += pent->d_name; + + bool isDir = false; + tmpdir = opendir(newPath.c_str()); + if(tmpdir) + { + isDir = true; + closedir(tmpdir); + } + if ((mode == Common::FSNode::kListFilesOnly && isDir) || (mode == Common::FSNode::kListDirectoriesOnly && !isDir)) continue; - + + struct stat st; + st.st_mode = 0; + st.st_mode |= ( isDir ? S_IFDIR : 0 ); + st.st_mode |= S_IRUSR; + st.st_mode |= S_IWUSR; + list.push_back(new WiiFilesystemNode(newPath, &st)); } - dirclose(dp); + closedir(dp); return true; } diff --git a/backends/fs/wii/wii-fs.h b/backends/fs/wii/wii-fs.h index 11679d0c36..f785101099 100644 --- a/backends/fs/wii/wii-fs.h +++ b/backends/fs/wii/wii-fs.h @@ -51,7 +51,7 @@ public: * * @param path Common::String with the path the new node should point to. */ - WiiFilesystemNode(const Common::String &path); + WiiFilesystemNode(const Common::String &p); WiiFilesystemNode(const Common::String &p, const struct stat *st); virtual bool exists() const; diff --git a/backends/graphics/graphics.h b/backends/graphics/graphics.h index 74258b8910..24397228e6 100644 --- a/backends/graphics/graphics.h +++ b/backends/graphics/graphics.h @@ -37,27 +37,6 @@ class GraphicsManager : public PaletteManager { public: virtual ~GraphicsManager() {} - /** - * Makes this graphics manager active. That means it should be ready to - * process inputs now. However, even without being active it should be - * able to query the supported modes and other bits. - * - * HACK: Actually this is specific to SdlGraphicsManager subclasses. - * But sadly we cannot cast from GraphicsManager to SdlGraphicsManager - * because there is no relation between these two. - */ - virtual void activateManager() {} - - /** - * Makes this graphics manager inactive. This should allow another - * graphics manager to become active again. - * - * HACK: Actually this is specific to SdlGraphicsManager subclasses. - * But sadly we cannot cast from GraphicsManager to SdlGraphicsManager - * because there is no relation between these two. - */ - virtual void deactivateManager() {} - virtual bool hasFeature(OSystem::Feature f) = 0; virtual void setFeatureState(OSystem::Feature f, bool enable) = 0; virtual bool getFeatureState(OSystem::Feature f) = 0; diff --git a/backends/graphics/opengl/debug.cpp b/backends/graphics/opengl/debug.cpp index 69006bb975..d5d73fb5ec 100644 --- a/backends/graphics/opengl/debug.cpp +++ b/backends/graphics/opengl/debug.cpp @@ -52,9 +52,9 @@ Common::String getGLErrStr(GLenum error) { } // End of anonymous namespace void checkGLError(const char *expr, const char *file, int line) { - GLenum error = glGetError(); + GLenum error; - if (error != GL_NO_ERROR) { + while ((error = glGetError()) != GL_NO_ERROR) { // We cannot use error here because we do not know whether we have a // working screen or not. warning("GL ERROR: %s on %s (%s:%d)", getGLErrStr(error).c_str(), expr, file, line); diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h index d2d0358407..93c0c5bc83 100644 --- a/backends/graphics/opengl/opengl-graphics.h +++ b/backends/graphics/opengl/opengl-graphics.h @@ -47,7 +47,7 @@ enum { GFX_NEAREST = 1 }; -class OpenGLGraphicsManager : public GraphicsManager { +class OpenGLGraphicsManager : virtual public GraphicsManager { public: OpenGLGraphicsManager(); virtual ~OpenGLGraphicsManager(); diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp index e39cd35870..3f9fc1fbd5 100644 --- a/backends/graphics/openglsdl/openglsdl-graphics.cpp +++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp @@ -73,8 +73,7 @@ OpenGLSdlGraphicsManager::~OpenGLSdlGraphicsManager() { } void OpenGLSdlGraphicsManager::activateManager() { - OpenGLGraphicsManager::activateManager(); - initEventSource(); + SdlGraphicsManager::activateManager(); // Register the graphics manager as a event observer g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false); @@ -86,8 +85,7 @@ void OpenGLSdlGraphicsManager::deactivateManager() { g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this); } - deinitEventSource(); - OpenGLGraphicsManager::deactivateManager(); + SdlGraphicsManager::deactivateManager(); } bool OpenGLSdlGraphicsManager::hasFeature(OSystem::Feature f) { diff --git a/backends/graphics/sdl/sdl-graphics.cpp b/backends/graphics/sdl/sdl-graphics.cpp index 417f4faf54..40b97b267b 100644 --- a/backends/graphics/sdl/sdl-graphics.cpp +++ b/backends/graphics/sdl/sdl-graphics.cpp @@ -31,10 +31,10 @@ SdlGraphicsManager::SdlGraphicsManager(SdlEventSource *source) SdlGraphicsManager::~SdlGraphicsManager() { } -void SdlGraphicsManager::initEventSource() { +void SdlGraphicsManager::activateManager() { _eventSource->setGraphicsManager(this); } -void SdlGraphicsManager::deinitEventSource() { +void SdlGraphicsManager::deactivateManager() { _eventSource->setGraphicsManager(0); } diff --git a/backends/graphics/sdl/sdl-graphics.h b/backends/graphics/sdl/sdl-graphics.h index 4d4338af16..3791961cfa 100644 --- a/backends/graphics/sdl/sdl-graphics.h +++ b/backends/graphics/sdl/sdl-graphics.h @@ -23,6 +23,8 @@ #ifndef BACKENDS_GRAPHICS_SDL_SDLGRAPHICS_H #define BACKENDS_GRAPHICS_SDL_SDLGRAPHICS_H +#include "backends/graphics/graphics.h" + #include "common/rect.h" class SdlEventSource; @@ -31,16 +33,26 @@ class SdlEventSource; * Base class for a SDL based graphics manager. * * It features a few extra a few extra features required by SdlEventSource. - * FIXME/HACK: - * Note it does not inherit from GraphicsManager to avoid a diamond inheritance - * in the current OpenGLSdlGraphicsManager. */ -class SdlGraphicsManager { +class SdlGraphicsManager : virtual public GraphicsManager { public: SdlGraphicsManager(SdlEventSource *source); virtual ~SdlGraphicsManager(); /** + * Makes this graphics manager active. That means it should be ready to + * process inputs now. However, even without being active it should be + * able to query the supported modes and other bits. + */ + virtual void activateManager(); + + /** + * Makes this graphics manager inactive. This should allow another + * graphics manager to become active again. + */ + virtual void deactivateManager(); + + /** * Notify the graphics manager that the graphics needs to be redrawn, since * the application window was modified. * @@ -80,9 +92,6 @@ public: virtual void notifyMousePos(Common::Point mouse) = 0; protected: - void initEventSource(); - void deinitEventSource(); - SdlEventSource *_eventSource; }; diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp index 0a4dcf3ea3..b3af08e2e8 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp @@ -198,8 +198,7 @@ SurfaceSdlGraphicsManager::~SurfaceSdlGraphicsManager() { } void SurfaceSdlGraphicsManager::activateManager() { - GraphicsManager::activateManager(); - initEventSource(); + SdlGraphicsManager::activateManager(); // Register the graphics manager as a event observer g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false); @@ -211,8 +210,7 @@ void SurfaceSdlGraphicsManager::deactivateManager() { g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this); } - deinitEventSource(); - GraphicsManager::deactivateManager(); + SdlGraphicsManager::deactivateManager(); } bool SurfaceSdlGraphicsManager::hasFeature(OSystem::Feature f) { @@ -746,6 +744,8 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() { if (_screen == NULL) error("allocating _screen failed"); + // Avoid having SDL_SRCALPHA set even if we supplied an alpha-channel in the format. + SDL_SetAlpha(_screen, 0, 255); #else _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth, _videoMode.screenHeight, 8, 0, 0, 0, 0); if (_screen == NULL) diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.h b/backends/graphics/surfacesdl/surfacesdl-graphics.h index 00c05ff2bf..22b7780675 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.h +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.h @@ -75,7 +75,7 @@ public: /** * SDL graphics manager */ -class SurfaceSdlGraphicsManager : public GraphicsManager, public SdlGraphicsManager, public Common::EventObserver { +class SurfaceSdlGraphicsManager : public SdlGraphicsManager, public Common::EventObserver { public: SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSource); virtual ~SurfaceSdlGraphicsManager(); diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 0ce95a3cfb..9f6c759c75 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -94,6 +94,7 @@ Common::List<Graphics::PixelFormat> OSystem_Android::getSupportedFormats() const Common::List<Graphics::PixelFormat> res; res.push_back(GLES565Texture::pixelFormat()); res.push_back(GLES5551Texture::pixelFormat()); + res.push_back(GLES8888Texture::pixelFormat()); res.push_back(GLES4444Texture::pixelFormat()); res.push_back(Graphics::PixelFormat::createFormatCLUT8()); @@ -147,6 +148,8 @@ void OSystem_Android::initTexture(GLESBaseTexture **texture, *texture = new GLES565Texture(); else if (format_new == GLES5551Texture::pixelFormat()) *texture = new GLES5551Texture(); + else if (format_new == GLES8888Texture::pixelFormat()) + *texture = new GLES8888Texture(); else if (format_new == GLES4444Texture::pixelFormat()) *texture = new GLES4444Texture(); else { diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index cc41c0d8a6..87fd2d976c 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -259,11 +259,15 @@ void GLESTexture::fillBuffer(uint32 color) { assert(_surface.getPixels()); if (_pixelFormat.bytesPerPixel == 1 || - ((color & 0xff) == ((color >> 8) & 0xff))) + (_pixelFormat.bytesPerPixel == 2 && + ((color & 0xff) == ((color >> 8) & 0xff)))) memset(_pixels, color & 0xff, _surface.pitch * _surface.h); - else - Common::fill(_pixels, _pixels + _surface.pitch * _surface.h, + else if (_pixelFormat.bytesPerPixel == 2) + Common::fill((uint16 *)_pixels, (uint16 *)(_pixels + _surface.pitch * _surface.h), (uint16)color); + else + Common::fill((uint32 *)_pixels, (uint32 *)(_pixels + _surface.pitch * _surface.h), + color); setDirty(); } @@ -334,6 +338,13 @@ GLES565Texture::GLES565Texture() : GLES565Texture::~GLES565Texture() { } +GLES8888Texture::GLES8888Texture() : + GLESTexture(GL_RGBA, GL_UNSIGNED_BYTE, pixelFormat()) { +} + +GLES8888Texture::~GLES8888Texture() { +} + GLESFakePaletteTexture::GLESFakePaletteTexture(GLenum glFormat, GLenum glType, Graphics::PixelFormat pixelFormat) : GLESBaseTexture(glFormat, glType, pixelFormat), diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 4307b5a1bc..67f7343c98 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -224,6 +224,18 @@ public: } }; +// RGBA8888 texture +class GLES8888Texture : public GLESTexture { +public: + GLES8888Texture(); + virtual ~GLES8888Texture(); + + static inline Graphics::PixelFormat pixelFormat() { + // We assume LE since all Android platforms are LE. + return Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24); + } +}; + class GLESFakePaletteTexture : public GLESBaseTexture { protected: GLESFakePaletteTexture(GLenum glFormat, GLenum glType, diff --git a/backends/platform/sdl/posix/posix.cpp b/backends/platform/sdl/posix/posix.cpp index 954f404ac6..1752153f29 100644 --- a/backends/platform/sdl/posix/posix.cpp +++ b/backends/platform/sdl/posix/posix.cpp @@ -50,7 +50,7 @@ void OSystem_POSIX::init() { // Initialze File System Factory _fsFactory = new POSIXFilesystemFactory(); -#if defined(USE_TASKBAR) && defined(USE_TASKBAR_UNITY) +#if defined(USE_TASKBAR) && defined(USE_UNITY) // Initialize taskbar manager _taskbarManager = new UnityTaskbarManager(); #endif @@ -67,7 +67,7 @@ void OSystem_POSIX::initBackend() { // Invoke parent implementation of this method OSystem_SDL::initBackend(); -#if defined(USE_TASKBAR) && defined(USE_TASKBAR_UNITY) +#if defined(USE_TASKBAR) && defined(USE_UNITY) // Register the taskbar manager as an event source (this is necessary for the glib event loop to be run) _eventManager->getEventDispatcher()->registerSource((UnityTaskbarManager *)_taskbarManager, false); #endif diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index 178eeb96af..913ae51f69 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -91,7 +91,7 @@ OSystem_SDL::~OSystem_SDL() { delete _savefileManager; _savefileManager = 0; if (_graphicsManager) { - _graphicsManager->deactivateManager(); + dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->deactivateManager(); } delete _graphicsManager; _graphicsManager = 0; @@ -240,7 +240,7 @@ void OSystem_SDL::initBackend() { // so the virtual keyboard can be initialized, but we have to add the // graphics manager as an event observer after initializing the event // manager. - _graphicsManager->activateManager(); + dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->activateManager(); } #if defined(USE_TASKBAR) @@ -579,14 +579,14 @@ bool OSystem_SDL::setGraphicsMode(int mode) { // manager, delete and create the new mode graphics manager if (_graphicsMode >= _firstGLMode && mode < _firstGLMode) { debug(1, "switching to plain SDL graphics"); - _graphicsManager->deactivateManager(); + dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->deactivateManager(); delete _graphicsManager; _graphicsManager = new SurfaceSdlGraphicsManager(_eventSource); switchedManager = true; } else if (_graphicsMode < _firstGLMode && mode >= _firstGLMode) { debug(1, "switching to OpenGL graphics"); - _graphicsManager->deactivateManager(); + dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->deactivateManager(); delete _graphicsManager; _graphicsManager = new OpenGLSdlGraphicsManager(_desktopWidth, _desktopHeight, _eventSource); @@ -596,7 +596,7 @@ bool OSystem_SDL::setGraphicsMode(int mode) { _graphicsMode = mode; if (switchedManager) { - _graphicsManager->activateManager(); + dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->activateManager(); _graphicsManager->beginGFXTransaction(); #ifdef USE_RGB_COLOR diff --git a/backends/platform/wii/main.cpp b/backends/platform/wii/main.cpp index affe053b6a..ec6231522e 100644 --- a/backends/platform/wii/main.cpp +++ b/backends/platform/wii/main.cpp @@ -225,7 +225,8 @@ int main(int argc, char *argv[]) { printf("shutdown\n"); SYS_UnregisterResetFunc(&resetinfo); - fatUnmountDefault(); + fatUnmount("usb:/"); + fatUnmount("sd:/"); if (res) show_console(res); diff --git a/backends/platform/wii/osystem_events.cpp b/backends/platform/wii/osystem_events.cpp index 3ba66aed89..aa63c8aa22 100644 --- a/backends/platform/wii/osystem_events.cpp +++ b/backends/platform/wii/osystem_events.cpp @@ -188,7 +188,7 @@ void OSystem_Wii::initEvents() { _padAcceleration = 9 - ConfMan.getInt("wii_pad_acceleration"); #ifdef USE_WII_KBD - _kbd_active = KEYBOARD_Init() >= 0; + _kbd_active = KEYBOARD_Init(NULL) >= 0; #endif } diff --git a/backends/platform/wii/wii.mk b/backends/platform/wii/wii.mk index 7d2db68b4e..99ef46338c 100644 --- a/backends/platform/wii/wii.mk +++ b/backends/platform/wii/wii.mk @@ -17,10 +17,10 @@ geckoupload: $(WII_EXE_STRIPPED) $(DEVKITPPC)/bin/geckoupload $< wiigdb: - $(DEVKITPPC)/bin/powerpc-gekko-gdb -n $(EXECUTABLE) + $(DEVKITPPC)/bin/powerpc-eabi-gdb -n $(EXECUTABLE) wiidebug: - $(DEVKITPPC)/bin/powerpc-gekko-gdb -n $(EXECUTABLE) -x $(srcdir)/backends/platform/wii/gdb.txt + $(DEVKITPPC)/bin/powerpc-eabi-gdb -n $(EXECUTABLE) -x $(srcdir)/backends/platform/wii/gdb.txt # target to create a Wii snapshot wiidist: all diff --git a/backends/platform/wince/CEActionsPocket.cpp b/backends/platform/wince/CEActionsPocket.cpp index 5980a41caa..493a5e688c 100644 --- a/backends/platform/wince/CEActionsPocket.cpp +++ b/backends/platform/wince/CEActionsPocket.cpp @@ -236,7 +236,7 @@ CEActionsPocket::~CEActionsPocket() { bool CEActionsPocket::perform(GUI::ActionType action, bool pushed) { static bool keydialogrunning = false, quitdialog = false; - _graphicsMan = ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager()); + _graphicsMan = dynamic_cast<WINCESdlGraphicsManager *>(((OSystem_SDL *)g_system)->getGraphicsManager()); if (!pushed) { switch (action) { diff --git a/backends/platform/wince/CEActionsSmartphone.cpp b/backends/platform/wince/CEActionsSmartphone.cpp index 2cce288323..d2bc449dfc 100644 --- a/backends/platform/wince/CEActionsSmartphone.cpp +++ b/backends/platform/wince/CEActionsSmartphone.cpp @@ -202,7 +202,7 @@ CEActionsSmartphone::~CEActionsSmartphone() { bool CEActionsSmartphone::perform(GUI::ActionType action, bool pushed) { static bool keydialogrunning = false, quitdialog = false; - _graphicsMan = ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager()); + _graphicsMan = dynamic_cast<WINCESdlGraphicsManager *>(((OSystem_SDL *)g_system)->getGraphicsManager()); if (!pushed) { switch (action) { diff --git a/backends/platform/wince/CELauncherDialog.cpp b/backends/platform/wince/CELauncherDialog.cpp index dd6076e0af..3908294682 100644 --- a/backends/platform/wince/CELauncherDialog.cpp +++ b/backends/platform/wince/CELauncherDialog.cpp @@ -65,12 +65,12 @@ public: }; CELauncherDialog::CELauncherDialog() : GUI::LauncherDialog() { - ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->reset_panel(); + dynamic_cast<WINCESdlGraphicsManager *>(((OSystem_SDL *)g_system)->getGraphicsManager())->reset_panel(); } void CELauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { if ((cmd == 'STRT') || (cmd == kListItemActivatedCmd) || (cmd == kListItemDoubleClickedCmd)) { - ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->init_panel(); + dynamic_cast<WINCESdlGraphicsManager *>(((OSystem_SDL *)g_system)->getGraphicsManager())->init_panel(); } LauncherDialog::handleCommand(sender, cmd, data); if (cmd == 'ABOU') { diff --git a/backends/platform/wince/wince-sdl.cpp b/backends/platform/wince/wince-sdl.cpp index 1c5cd5565b..1c9c178460 100644 --- a/backends/platform/wince/wince-sdl.cpp +++ b/backends/platform/wince/wince-sdl.cpp @@ -422,7 +422,7 @@ void OSystem_WINCE3::initBackend() { if (_graphicsManager == 0) _graphicsManager = new WINCESdlGraphicsManager(_eventSource); - ((WINCESdlEventSource *)_eventSource)->init((WINCESdlGraphicsManager *)_graphicsManager); + ((WINCESdlEventSource *)_eventSource)->init(dynamic_cast<WINCESdlGraphicsManager *>(_graphicsManager)); // Call parent implementation of this method OSystem_SDL::initBackend(); @@ -486,15 +486,16 @@ void OSystem_WINCE3::swap_sound_master() { //WINCESdlGraphicsManager _graphicsManager - if (((WINCESdlGraphicsManager *)_graphicsManager)->_toolbarHandler.activeName() == NAME_MAIN_PANEL) - ((WINCESdlGraphicsManager *)_graphicsManager)->_toolbarHandler.forceRedraw(); // redraw sound icon + WINCESdlGraphicsManager *graphicsManager = dynamic_cast<WINCESdlGraphicsManager *>(_graphicsManager); + if (graphicsManager->_toolbarHandler.activeName() == NAME_MAIN_PANEL) + graphicsManager->_toolbarHandler.forceRedraw(); // redraw sound icon } void OSystem_WINCE3::engineInit() { check_mappings(); // called here to initialize virtual keys handling - ((WINCESdlGraphicsManager *)_graphicsManager)->update_game_settings(); + dynamic_cast<WINCESdlGraphicsManager *>(_graphicsManager)->update_game_settings(); // finalize mixer init _mixerManager->init(); } diff --git a/backends/taskbar/unity/unity-taskbar.cpp b/backends/taskbar/unity/unity-taskbar.cpp index f36e2bf628..1b82e58c8a 100644 --- a/backends/taskbar/unity/unity-taskbar.cpp +++ b/backends/taskbar/unity/unity-taskbar.cpp @@ -24,7 +24,7 @@ #define FORBIDDEN_SYMBOL_EXCEPTION_time_h #include "common/scummsys.h" -#if defined(POSIX) && defined(USE_TASKBAR) && defined(USE_TASKBAR_UNITY) +#if defined(POSIX) && defined(USE_TASKBAR) && defined(USE_UNITY) #include "backends/taskbar/unity/unity-taskbar.h" diff --git a/backends/taskbar/unity/unity-taskbar.h b/backends/taskbar/unity/unity-taskbar.h index d1d9430bcd..d818ed9ff1 100644 --- a/backends/taskbar/unity/unity-taskbar.h +++ b/backends/taskbar/unity/unity-taskbar.h @@ -23,7 +23,7 @@ #ifndef BACKEND_UNITY_TASKBAR_H #define BACKEND_UNITY_TASKBAR_H -#if defined(POSIX) && defined(USE_TASKBAR) && defined(USE_TASKBAR_UNITY) +#if defined(POSIX) && defined(USE_TASKBAR) && defined(USE_UNITY) #include "common/events.h" #include "common/str.h" diff --git a/base/main.cpp b/base/main.cpp index c993dfa57a..abf75b7e7e 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -197,7 +197,7 @@ static Common::Error runGame(const EnginePlugin *plugin, OSystem &system, const // // Add the game path to the directory search list - SearchMan.addDirectory(dir.getPath(), dir, 0, 4); + engine->initializePath(dir); // Add extrapath (if any) to the directory search list if (ConfMan.hasKey("extrapath")) { diff --git a/base/plugins.cpp b/base/plugins.cpp index b8cd097683..a232bb1427 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -295,7 +295,7 @@ bool PluginManagerUncached::loadPluginFromGameId(const Common::String &gameId) { if (domain->contains(gameId)) { Common::String filename = (*domain)[gameId]; - if (loadPluginByFileName(filename)) { + if (loadPluginByFileName(filename)) { return true; } } diff --git a/common/ini-file.cpp b/common/ini-file.cpp index be5247dcfb..9de0b38e93 100644 --- a/common/ini-file.cpp +++ b/common/ini-file.cpp @@ -53,7 +53,7 @@ bool INIFile::loadFromFile(const String &filename) { return false; } -bool INIFile::loadFromSaveFile(const char *filename) { +bool INIFile::loadFromSaveFile(const String &filename) { assert(g_system); SaveFileManager *saveFileMan = g_system->getSavefileManager(); SeekableReadStream *loadFile; @@ -181,7 +181,7 @@ bool INIFile::saveToFile(const String &filename) { return false; } -bool INIFile::saveToSaveFile(const char *filename) { +bool INIFile::saveToSaveFile(const String &filename) { assert(g_system); SaveFileManager *saveFileMan = g_system->getSavefileManager(); WriteStream *saveFile; diff --git a/common/ini-file.h b/common/ini-file.h index 1d94ce7bdc..a1505fe468 100644 --- a/common/ini-file.h +++ b/common/ini-file.h @@ -94,10 +94,10 @@ public: void clear(); bool loadFromFile(const String &filename); - bool loadFromSaveFile(const char *filename); + bool loadFromSaveFile(const String &filename); bool loadFromStream(SeekableReadStream &stream); bool saveToFile(const String &filename); - bool saveToSaveFile(const char *filename); + bool saveToSaveFile(const String &filename); bool saveToStream(WriteStream &stream); bool hasSection(const String §ion) const; diff --git a/common/quicktime.cpp b/common/quicktime.cpp index a3efc2b443..6ab5a42b89 100644 --- a/common/quicktime.cpp +++ b/common/quicktime.cpp @@ -368,9 +368,6 @@ int QuickTimeParser::readMVHD(Atom atom) { int QuickTimeParser::readTRAK(Atom atom) { Track *track = new Track(); - if (!track) - return -1; - track->codecType = CODEC_TYPE_MOV_OTHER; track->startTime = 0; // XXX: check _tracks.push_back(track); @@ -126,7 +126,7 @@ _opengl=auto _opengles=auto _readline=auto _freetype2=auto -_taskbar=yes +_taskbar=auto _updates=no _libunity=auto # Default option behavior yes/no @@ -1305,7 +1305,7 @@ ds) gamecube) _host_os=gamecube _host_cpu=ppc - _host_alias=powerpc-gekko + _host_alias=powerpc-eabi ;; gp2x) _host_os=gph-linux @@ -1428,7 +1428,7 @@ webos) wii) _host_os=wii _host_cpu=ppc - _host_alias=powerpc-gekko + _host_alias=powerpc-eabi ;; wince) _host_os=wince @@ -2046,18 +2046,21 @@ case $_host_os in CXXFLAGS="$CXXFLAGS -march=armv5te" CXXFLAGS="$CXXFLAGS -mtune=xscale" CXXFLAGS="$CXXFLAGS -msoft-float" + ABI="armeabi" ;; android-v7a) CXXFLAGS="$CXXFLAGS -march=armv7-a" CXXFLAGS="$CXXFLAGS -mfloat-abi=softfp" CXXFLAGS="$CXXFLAGS -mfpu=vfp" LDFLAGS="$LDFLAGS -Wl,--fix-cortex-a8" + ABI="armeabi-v7a" ;; ouya) CXXFLAGS="$CXXFLAGS -march=armv7-a" CXXFLAGS="$CXXFLAGS -mtune=cortex-a9" CXXFLAGS="$CXXFLAGS -mfloat-abi=softfp" CXXFLAGS="$CXXFLAGS -mfpu=neon" + ABI="armeabi-v7a" ;; esac CXXFLAGS="$CXXFLAGS --sysroot=$ANDROID_NDK/platforms/android-4/arch-arm" @@ -2083,6 +2086,8 @@ case $_host_os in CXXFLAGS="$CXXFLAGS -Wno-psabi" LDFLAGS="$LDFLAGS --sysroot=$ANDROID_NDK/platforms/android-4/arch-arm" LDFLAGS="$LDFLAGS -mthumb-interwork" + LDFLAGS="$LDFLAGS -L$ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/`$CXX -dumpversion`/libs/$ABI/" + LIBS="$LIBS -lsupc++" add_line_to_config_mk "ANDROID_SDK = $ANDROID_SDK" _seq_midi=no ;; @@ -2685,7 +2690,6 @@ if test -n "$_host"; then _backend="tizen" _port_mk="backends/platform/tizen/tizen.mk" _arm_asm=yes - _taskbar=no _build_scalers=no _seq_midi=no _mt32emu=no @@ -3726,7 +3730,7 @@ if test "$_libunity" = yes ; then LIBS="$LIBS $LIBUNITY_LIBS" INCLUDES="$INCLUDES $LIBUNITY_CFLAGS" fi -define_in_config_h_if_yes "$_libunity" 'USE_TASKBAR_UNITY' +define_in_config_h_if_yes "$_libunity" 'USE_UNITY' fi echo "$_libunity" @@ -3988,24 +3992,27 @@ fi # Check whether to build taskbar integration support # echo_n "Building taskbar integration support... " -define_in_config_if_yes $_taskbar 'USE_TASKBAR' -if test "$_taskbar" = yes; then +if test "$_taskbar" = "no"; then + echo "no" +else case $_host_os in mingw*) LIBS="$LIBS -lole32 -luuid" echo "win32" + _taskbar=yes ;; *) if test "$_libunity" = yes; then echo "unity" + _taskbar=yes else - echo "$_taskbar" + echo "no" + _taskbar=no fi ;; esac -else - echo "$_taskbar" fi +define_in_config_if_yes $_taskbar 'USE_TASKBAR' # # Check whether to build Bink video support diff --git a/devtools/create_project/config.h b/devtools/create_project/config.h index 9d4b101360..63bf3dee26 100644 --- a/devtools/create_project/config.h +++ b/devtools/create_project/config.h @@ -33,6 +33,6 @@ #define DISABLE_EDIT_AND_CONTINUE "tinsel,tony,scummvm" // Comma separated list of projects that need Edit&Continue to be disabled for co-routine support (the main project is automatically added) //#define ADDITIONAL_LIBRARY "" // Add a single library to the list of externally linked libraries -#define NEEDS_RTTI 0 // Enable RTTI globally +#define NEEDS_RTTI 1 // Enable RTTI globally #endif // TOOLS_CREATE_PROJECT_CONFIG_H diff --git a/devtools/credits.pl b/devtools/credits.pl index 03e086ce99..53f0d11307 100755 --- a/devtools/credits.pl +++ b/devtools/credits.pl @@ -553,7 +553,7 @@ begin_credits("Credits"); add_person("Ludvig Strigeus", "ludde", "(retired)"); end_section(); - begin_section("AVALANCHE"); + begin_section("Avalanche"); add_person("Peter Bozsó", "uruk", ""); add_person("Arnaud Boutonné", "Strangerke", ""); end_section(); diff --git a/dists/engine-data/README b/dists/engine-data/README index 9bbb006d17..e87f04c65b 100644 --- a/dists/engine-data/README +++ b/dists/engine-data/README @@ -21,6 +21,9 @@ File created partially by extracting font data from the French executable. It also contains the French and German translation, as well as a custom-made English translation. +neverhood.dat: +TODO + queen.tbl: 'queen.tbl' contains a list of filenames, filesizes and offsets for the individual files saved in QUEEN.1. This data was originally included in the @@ -38,4 +41,4 @@ tony.dat: This file contains the font table used by the different versions of the game. toon.dat: -'toon.dat' contains all the strings hardcoded in the original executables. +This file contains all the strings hardcoded in the original executables. diff --git a/engines/agos/agos.h b/engines/agos/agos.h index 87a1228c6a..0b8e585f57 100644 --- a/engines/agos/agos.h +++ b/engines/agos/agos.h @@ -25,7 +25,6 @@ #include "engines/engine.h" -#include "common/archive.h" #include "common/array.h" #include "common/error.h" #include "common/keyboard.h" @@ -187,27 +186,6 @@ class Debugger; # define _OPCODE(ver, x) { &ver::x, "" } #endif -class ArchiveMan : public Common::SearchSet { -public: - ArchiveMan(); - - void enableFallback(bool val) { _fallBack = val; } - -#ifdef ENABLE_AGOS2 - void registerArchive(const Common::String &filename, int priority); -#endif - - virtual bool hasFile(const Common::String &name) const; - virtual int listMatchingMembers(Common::ArchiveMemberList &list, const Common::String &pattern) const; - virtual int listMembers(Common::ArchiveMemberList &list) const; - - virtual const Common::ArchiveMemberPtr getMember(const Common::String &name) const; - virtual Common::SeekableReadStream *createReadStreamForMember(const Common::String &filename) const; - -private: - bool _fallBack; -}; - class AGOSEngine : public Engine { protected: friend class Debugger; @@ -622,8 +600,6 @@ public: AGOSEngine(OSystem *system, const AGOSGameDescription *gd); virtual ~AGOSEngine(); - ArchiveMan _archives; - byte *_curSfxFile; uint32 _curSfxFileSize; uint16 _sampleEnd, _sampleWait; diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp index 40c9d1d049..d438de049a 100644 --- a/engines/agos/animation.cpp +++ b/engines/agos/animation.cpp @@ -251,8 +251,8 @@ bool MoviePlayerDXA::load() { } Common::String videoName = Common::String::format("%s.dxa", baseName); - Common::SeekableReadStream *videoStream = _vm->_archives.createReadStreamForMember(videoName); - if (!videoStream) + Common::File *videoStream = new Common::File(); + if (!videoStream->open(videoName)) error("Failed to load video file %s", videoName.c_str()); if (!loadStream(videoStream)) error("Failed to load video stream from file %s", videoName.c_str()); @@ -421,8 +421,8 @@ MoviePlayerSMK::MoviePlayerSMK(AGOSEngine_Feeble *vm, const char *name) bool MoviePlayerSMK::load() { Common::String videoName = Common::String::format("%s.smk", baseName); - Common::SeekableReadStream *videoStream = _vm->_archives.createReadStreamForMember(videoName); - if (!videoStream) + Common::File *videoStream = new Common::File(); + if (!videoStream->open(videoName)) error("Failed to load video file %s", videoName.c_str()); if (!loadStream(videoStream)) error("Failed to load video stream from file %s", videoName.c_str()); @@ -532,25 +532,25 @@ MoviePlayer *makeMoviePlayer(AGOSEngine_Feeble *vm, const char *name) { memcpy(shortName, baseName, 6); sprintf(filename, "%s~1.dxa", shortName); - if (vm->_archives.hasFile(filename)) { + if (Common::File::exists(filename)) { memset(baseName, 0, sizeof(baseName)); memcpy(baseName, filename, 8); } sprintf(filename, "%s~1.smk", shortName); - if (vm->_archives.hasFile(filename)) { + if (Common::File::exists(filename)) { memset(baseName, 0, sizeof(baseName)); memcpy(baseName, filename, 8); } } sprintf(filename, "%s.dxa", baseName); - if (vm->_archives.hasFile(filename)) { + if (Common::File::exists(filename)) { return new MoviePlayerDXA(vm, baseName); } sprintf(filename, "%s.smk", baseName); - if (vm->_archives.hasFile(filename)) { + if (Common::File::exists(filename)) { return new MoviePlayerSMK(vm, baseName); } diff --git a/engines/agos/detection.cpp b/engines/agos/detection.cpp index a5a42a86ad..b6d3c2f020 100644 --- a/engines/agos/detection.cpp +++ b/engines/agos/detection.cpp @@ -28,6 +28,7 @@ #include "common/savefile.h" #include "common/system.h" #include "common/textconsole.h" +#include "common/installshield_cab.h" #include "agos/intern.h" #include "agos/agos.h" @@ -269,8 +270,12 @@ void AGOSEngine::loadArchives() { if (getFeatures() & GF_PACKED) { for (ag = _gameDescription->desc.filesDescriptions; ag->fileName; ag++) { - if (!_archives.hasArchive(ag->fileName)) - _archives.registerArchive(ag->fileName, ag->fileType); + if (!SearchMan.hasArchive(ag->fileName)) { + Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(ag->fileName); + + if (stream) + SearchMan.add(ag->fileName, Common::makeInstallShieldArchive(stream, DisposeAfterUse::YES), ag->fileType); + } } } } diff --git a/engines/agos/res.cpp b/engines/agos/res.cpp index cf1d062d96..1c79a073e8 100644 --- a/engines/agos/res.cpp +++ b/engines/agos/res.cpp @@ -24,7 +24,6 @@ #include "common/archive.h" -#include "common/installshield_cab.h" #include "common/file.h" #include "common/memstream.h" #include "common/textconsole.h" @@ -38,52 +37,6 @@ namespace AGOS { -ArchiveMan::ArchiveMan() { - _fallBack = true; -} - -#ifdef ENABLE_AGOS2 -void ArchiveMan::registerArchive(const Common::String &filename, int priority) { - Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(filename); - - if (stream) - add(filename, makeInstallShieldArchive(stream, DisposeAfterUse::YES), priority); -} -#endif - -bool ArchiveMan::hasFile(const Common::String &name) const { - if (_fallBack && SearchMan.hasFile(name)) - return true; - - return Common::SearchSet::hasFile(name); -} - -int ArchiveMan::listMatchingMembers(Common::ArchiveMemberList &list, const Common::String &pattern) const { - const int matches = _fallBack ? SearchMan.listMatchingMembers(list, pattern) : 0; - return matches + Common::SearchSet::listMatchingMembers(list, pattern); -} - -int ArchiveMan::listMembers(Common::ArchiveMemberList &list) const { - const int matches = _fallBack ? SearchMan.listMembers(list) : 0; - return matches + Common::SearchSet::listMembers(list); -} - -const Common::ArchiveMemberPtr ArchiveMan::getMember(const Common::String &name) const { - Common::ArchiveMemberPtr ptr = _fallBack ? SearchMan.getMember(name) : Common::ArchiveMemberPtr(); - if (ptr) - return ptr; - - return Common::SearchSet::getMember(name); -} - -Common::SeekableReadStream *ArchiveMan::createReadStreamForMember(const Common::String &filename) const { - if (_fallBack && SearchMan.hasFile(filename)) { - return SearchMan.createReadStreamForMember(filename); - } - - return Common::SearchSet::createReadStreamForMember(filename); -} - #ifdef ENABLE_AGOS2 uint16 AGOSEngine_Feeble::to16Wrapper(uint value) { return TO_LE_16(value); @@ -198,39 +151,35 @@ int AGOSEngine::allocGamePcVars(Common::SeekableReadStream *in) { } void AGOSEngine_PN::loadGamePcFile() { - Common::SeekableReadStream *in; - if (getFileName(GAME_BASEFILE) != NULL) { + Common::File in; // Read dataBase - in = _archives.createReadStreamForMember(getFileName(GAME_BASEFILE)); - if (!in) { + if (!in.open(getFileName(GAME_BASEFILE))) { error("loadGamePcFile: Can't load database file '%s'", getFileName(GAME_BASEFILE)); } - _dataBaseSize = in->size(); + _dataBaseSize = in.size(); _dataBase = (byte *)malloc(_dataBaseSize); if (_dataBase == NULL) error("loadGamePcFile: Out of memory for dataBase"); - in->read(_dataBase, _dataBaseSize); - delete in; + in.read(_dataBase, _dataBaseSize); if (_dataBase[31] != 0) error("Later version of system requested"); } if (getFileName(GAME_TEXTFILE) != NULL) { + Common::File in; // Read textBase - in = _archives.createReadStreamForMember(getFileName(GAME_TEXTFILE)); - if (!in) { + if (!in.open(getFileName(GAME_TEXTFILE))) { error("loadGamePcFile: Can't load textbase file '%s'", getFileName(GAME_TEXTFILE)); } - _textBaseSize = in->size(); + _textBaseSize = in.size(); _textBase = (byte *)malloc(_textBaseSize); if (_textBase == NULL) error("loadGamePcFile: Out of memory for textBase"); - in->read(_textBase, _textBaseSize); - delete in; + in.read(_textBase, _textBaseSize); if (_textBase[getlong(30L)] != 128) error("Unknown compression format"); @@ -238,20 +187,19 @@ void AGOSEngine_PN::loadGamePcFile() { } void AGOSEngine::loadGamePcFile() { - Common::SeekableReadStream *in; int fileSize; if (getFileName(GAME_BASEFILE) != NULL) { /* Read main gamexx file */ - in = _archives.createReadStreamForMember(getFileName(GAME_BASEFILE)); - if (!in) { + Common::File in; + if (!in.open(getFileName(GAME_BASEFILE))) { error("loadGamePcFile: Can't load gamexx file '%s'", getFileName(GAME_BASEFILE)); } if (getFeatures() & GF_CRUNCHED_GAMEPC) { - uint srcSize = in->size(); + uint srcSize = in.size(); byte *srcBuf = (byte *)malloc(srcSize); - in->read(srcBuf, srcSize); + in.read(srcBuf, srcSize); uint dstSize = READ_BE_UINT32(srcBuf + srcSize - 4); byte *dstBuf = (byte *)malloc(dstSize); @@ -262,25 +210,23 @@ void AGOSEngine::loadGamePcFile() { readGamePcFile(&stream); free(dstBuf); } else { - readGamePcFile(in); + readGamePcFile(&in); } - delete in; } if (getFileName(GAME_TBLFILE) != NULL) { /* Read list of TABLE resources */ - in = _archives.createReadStreamForMember(getFileName(GAME_TBLFILE)); - if (!in) { + Common::File in; + if (!in.open(getFileName(GAME_TBLFILE))) { error("loadGamePcFile: Can't load table resources file '%s'", getFileName(GAME_TBLFILE)); } - fileSize = in->size(); + fileSize = in.size(); _tblList = (byte *)malloc(fileSize); if (_tblList == NULL) error("loadGamePcFile: Out of memory for strip table list"); - in->read(_tblList, fileSize); - delete in; + in.read(_tblList, fileSize); /* Remember the current state */ _subroutineListOrg = _subroutineList; @@ -290,71 +236,67 @@ void AGOSEngine::loadGamePcFile() { if (getFileName(GAME_STRFILE) != NULL) { /* Read list of TEXT resources */ - in = _archives.createReadStreamForMember(getFileName(GAME_STRFILE)); - if (!in) + Common::File in; + if (!in.open(getFileName(GAME_STRFILE))) error("loadGamePcFile: Can't load text resources file '%s'", getFileName(GAME_STRFILE)); - fileSize = in->size(); + fileSize = in.size(); _strippedTxtMem = (byte *)malloc(fileSize); if (_strippedTxtMem == NULL) error("loadGamePcFile: Out of memory for strip text list"); - in->read(_strippedTxtMem, fileSize); - delete in; + in.read(_strippedTxtMem, fileSize); } if (getFileName(GAME_STATFILE) != NULL) { /* Read list of ROOM STATE resources */ - in = _archives.createReadStreamForMember(getFileName(GAME_STATFILE)); - if (!in) { + Common::File in; + if (!in.open(getFileName(GAME_STATFILE))) { error("loadGamePcFile: Can't load state resources file '%s'", getFileName(GAME_STATFILE)); } - _numRoomStates = in->size() / 8; + _numRoomStates = in.size() / 8; _roomStates = (RoomState *)calloc(_numRoomStates, sizeof(RoomState)); if (_roomStates == NULL) error("loadGamePcFile: Out of memory for room state list"); for (uint s = 0; s < _numRoomStates; s++) { - uint16 num = in->readUint16BE() - (_itemArrayInited - 2); + uint16 num = in.readUint16BE() - (_itemArrayInited - 2); - _roomStates[num].state = in->readUint16BE(); - _roomStates[num].classFlags = in->readUint16BE(); - _roomStates[num].roomExitStates = in->readUint16BE(); + _roomStates[num].state = in.readUint16BE(); + _roomStates[num].classFlags = in.readUint16BE(); + _roomStates[num].roomExitStates = in.readUint16BE(); } - delete in; } if (getFileName(GAME_RMSLFILE) != NULL) { /* Read list of ROOM ITEMS resources */ - in = _archives.createReadStreamForMember(getFileName(GAME_RMSLFILE)); - if (!in) { + Common::File in; + if (!in.open(getFileName(GAME_RMSLFILE))) { error("loadGamePcFile: Can't load room resources file '%s'", getFileName(GAME_RMSLFILE)); } - fileSize = in->size(); + fileSize = in.size(); _roomsList = (byte *)malloc(fileSize); if (_roomsList == NULL) error("loadGamePcFile: Out of memory for room items list"); - in->read(_roomsList, fileSize); - delete in; + in.read(_roomsList, fileSize); } if (getFileName(GAME_XTBLFILE) != NULL) { /* Read list of XTABLE resources */ - in = _archives.createReadStreamForMember(getFileName(GAME_XTBLFILE)); - if (!in) { + Common::File in; + if (!in.open(getFileName(GAME_XTBLFILE))) { error("loadGamePcFile: Can't load xtable resources file '%s'", getFileName(GAME_XTBLFILE)); } - fileSize = in->size(); + fileSize = in.size(); _xtblList = (byte *)malloc(fileSize); if (_xtblList == NULL) error("loadGamePcFile: Out of memory for strip xtable list"); - in->read(_xtblList, fileSize); - delete in; + in.read(_xtblList, fileSize); /* Remember the current state */ _xsubroutineListOrg = _subroutineList; @@ -828,7 +770,7 @@ void AGOSEngine::loadVGABeardFile(uint16 id) { uint32 offs, size; if (getFeatures() & GF_OLD_BUNDLE) { - Common::SeekableReadStream *in; + Common::File in; char filename[15]; if (id == 23) id = 112; @@ -844,22 +786,20 @@ void AGOSEngine::loadVGABeardFile(uint16 id) { sprintf(filename, "0%d.VGA", id); } - in = _archives.createReadStreamForMember(filename); - if (!in) + if (!in.open(filename)) error("loadSimonVGAFile: Can't load %s", filename); - size = in->size(); + size = in.size(); if (getFeatures() & GF_CRUNCHED) { byte *srcBuffer = (byte *)malloc(size); - if (in->read(srcBuffer, size) != size) + if (in.read(srcBuffer, size) != size) error("loadSimonVGAFile: Read failed"); decrunchFile(srcBuffer, _vgaBufferPointers[11].vgaFile2, size); free(srcBuffer); } else { - if (in->read(_vgaBufferPointers[11].vgaFile2, size) != size) + if (in.read(_vgaBufferPointers[11].vgaFile2, size) != size) error("loadSimonVGAFile: Read failed"); } - delete in; } else { offs = _gameOffsetsPtr[id]; @@ -869,7 +809,7 @@ void AGOSEngine::loadVGABeardFile(uint16 id) { } void AGOSEngine::loadVGAVideoFile(uint16 id, uint8 type, bool useError) { - Common::SeekableReadStream *in; + Common::File in; char filename[15]; byte *dst; uint32 file, offs, srcSize, dstSize; @@ -922,8 +862,7 @@ void AGOSEngine::loadVGAVideoFile(uint16 id, uint8 type, bool useError) { } } - in = _archives.createReadStreamForMember(filename); - if (!in) { + if (!in.open(filename)) { if (useError) error("loadVGAVideoFile: Can't load %s", filename); @@ -931,11 +870,11 @@ void AGOSEngine::loadVGAVideoFile(uint16 id, uint8 type, bool useError) { return; } - dstSize = srcSize = in->size(); + dstSize = srcSize = in.size(); if (getGameType() == GType_PN && getPlatform() == Common::kPlatformDOS && id == 17 && type == 2) { // The A2.out file isn't compressed in PC version of Personal Nightmare dst = allocBlock(dstSize + extraBuffer); - if (in->read(dst, dstSize) != dstSize) + if (in.read(dst, dstSize) != dstSize) error("loadVGAVideoFile: Read failed"); } else if (getGameType() == GType_PN && (getFeatures() & GF_CRUNCHED)) { Common::Stack<uint32> data; @@ -943,7 +882,7 @@ void AGOSEngine::loadVGAVideoFile(uint16 id, uint8 type, bool useError) { int dataOutSize = 0; for (uint i = 0; i < srcSize / 4; ++i) { - uint32 dataVal = in->readUint32BE(); + uint32 dataVal = in.readUint32BE(); // Correct incorrect byte, in corrupt 72.out file, included in some PC versions. if (dataVal == 168042714) data.push(168050906); @@ -957,7 +896,7 @@ void AGOSEngine::loadVGAVideoFile(uint16 id, uint8 type, bool useError) { delete[] dataOut; } else if (getFeatures() & GF_CRUNCHED) { byte *srcBuffer = (byte *)malloc(srcSize); - if (in->read(srcBuffer, srcSize) != srcSize) + if (in.read(srcBuffer, srcSize) != srcSize) error("loadVGAVideoFile: Read failed"); dstSize = READ_BE_UINT32(srcBuffer + srcSize - 4); @@ -966,10 +905,9 @@ void AGOSEngine::loadVGAVideoFile(uint16 id, uint8 type, bool useError) { free(srcBuffer); } else { dst = allocBlock(dstSize + extraBuffer); - if (in->read(dst, dstSize) != dstSize) + if (in.read(dst, dstSize) != dstSize) error("loadVGAVideoFile: Read failed"); } - delete in; } else { id = id * 2 + (type - 1); offs = _gameOffsetsPtr[id]; diff --git a/engines/agos/res_snd.cpp b/engines/agos/res_snd.cpp index 2777d4f269..86d24e0b07 100644 --- a/engines/agos/res_snd.cpp +++ b/engines/agos/res_snd.cpp @@ -450,17 +450,14 @@ static const char *const dimpSoundList[32] = { void AGOSEngine::loadSoundFile(const char* filename) { - Common::SeekableReadStream *in; - - in = _archives.createReadStreamForMember(filename); - if (!in) + Common::File in; + if (!in.open(filename)) error("loadSound: Can't load %s", filename); - uint32 dstSize = in->size(); + uint32 dstSize = in.size(); byte *dst = (byte *)malloc(dstSize); - if (in->read(dst, dstSize) != dstSize) + if (in.read(dst, dstSize) != dstSize) error("loadSound: Read failed"); - delete in; _sound->playSfxData(dst, 0, 0, 0); } @@ -469,21 +466,19 @@ void AGOSEngine::loadSound(uint16 sound, int16 pan, int16 vol, uint16 type) { byte *dst; if (getGameId() == GID_DIMP) { - Common::SeekableReadStream *in; + Common::File in; char filename[15]; assert(sound >= 1 && sound <= 32); sprintf(filename, "%s.wav", dimpSoundList[sound - 1]); - in = _archives.createReadStreamForMember(filename); - if (!in) + if (!in.open(filename)) error("loadSound: Can't load %s", filename); - uint32 dstSize = in->size(); + uint32 dstSize = in.size(); dst = (byte *)malloc(dstSize); - if (in->read(dst, dstSize) != dstSize) + if (in.read(dst, dstSize) != dstSize) error("loadSound: Read failed"); - delete in; } else if (getFeatures() & GF_ZLIBCOMP) { char filename[15]; diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp index 8eb7f066b3..8b133971de 100644 --- a/engines/agos/saveload.cpp +++ b/engines/agos/saveload.cpp @@ -1031,7 +1031,12 @@ bool AGOSEngine::loadGame(const Common::String &filename, bool restartMode) { if (restartMode) { // Load restart state - f = _archives.createReadStreamForMember(filename); + Common::File *file = new Common::File(); + if (!file->open(filename)) { + delete file; + file = nullptr; + } + f = file; } else { f = _saveFileMan->openForLoading(filename); } @@ -1205,7 +1210,12 @@ bool AGOSEngine_Elvira2::loadGame(const Common::String &filename, bool restartMo if (restartMode) { // Load restart state - f = _archives.createReadStreamForMember(filename); + Common::File *file = new Common::File(); + if (!file->open(filename)) { + delete file; + file = nullptr; + } + f = file; } else { f = _saveFileMan->openForLoading(filename); } diff --git a/engines/agos/subroutine.cpp b/engines/agos/subroutine.cpp index f5aad2dcc8..7a84a20808 100644 --- a/engines/agos/subroutine.cpp +++ b/engines/agos/subroutine.cpp @@ -266,8 +266,8 @@ Common::SeekableReadStream *AGOSEngine::openTablesFile(const char *filename) { } Common::SeekableReadStream *AGOSEngine::openTablesFile_simon1(const char *filename) { - Common::SeekableReadStream *in = _archives.createReadStreamForMember(filename); - if (!in) + Common::File *in = new Common::File(); + if (!in->open(filename)) error("openTablesFile: Can't open '%s'", filename); return in; } diff --git a/engines/avalanche/animation.cpp b/engines/avalanche/animation.cpp index 66097b2812..639abe99b3 100644 --- a/engines/avalanche/animation.cpp +++ b/engines/avalanche/animation.cpp @@ -1399,6 +1399,69 @@ void Animation::handleMoveKey(const Common::Event &event) { } } +/** +* Draws a part of the lightning bolt for thunder(). +* @remarks Originally called 'zl' +*/ +void Animation::drawLightning(int16 x1, int16 y1, int16 x2, int16 y2) { + _vm->_graphics->drawLine(x1, y1 - 1, x2, y2 - 1, 1, 3, kColorBlue); + _vm->_graphics->drawLine(x1, y1, x2, y2, 1, 1, kColorLightcyan); +} + +/** +* Plays the actual thunder animation when Avvy (the player) swears too much. +* @remarks Originally called 'zonk' +*/ +void Animation::thunder() { + _vm->_graphics->setBackgroundColor(kColorYellow); + + _vm->_graphics->saveScreen(); + + int x = _vm->_animation->_sprites[0]->_x + _vm->_animation->_sprites[0]->_xLength / 2; + int y = _vm->_animation->_sprites[0]->_y; + + for (int i = 0; i < 256; i++) { + _vm->_sound->playNote(270 - i, 1); + + drawLightning(640, 0, 0, y / 4); + drawLightning(0, y / 4, 640, y / 2); + drawLightning(640, y / 2, x, y); + _vm->_graphics->refreshScreen(); + + _vm->_sound->playNote(2700 - 10 * i, 5); + _vm->_system->delayMillis(5); + _vm->_sound->playNote(270 - i, 1); + + _vm->_graphics->restoreScreen(); + _vm->_sound->playNote(2700 - 10 * i, 5); + _vm->_system->delayMillis(5); + } + + _vm->_graphics->restoreScreen(); + _vm->_graphics->removeBackup(); + + _vm->_graphics->setBackgroundColor(kColorBlack); +} + +/** +* Makes the screen wobble. +*/ +void Animation::wobble() { + _vm->_graphics->saveScreen(); + + for (int i = 0; i < 26; i++) { + _vm->_graphics->shiftScreen(); + _vm->_graphics->refreshScreen(); + _vm->_system->delayMillis(i * 7); + + _vm->_graphics->restoreScreen(); + _vm->_system->delayMillis(i * 7); + } + + _vm->_graphics->restoreScreen(); + _vm->_graphics->removeBackup(); +} + void Animation::setDirection(Direction dir) { _direction = dir; } diff --git a/engines/avalanche/animation.h b/engines/avalanche/animation.h index cda5f05bd0..aa4e6482a4 100644 --- a/engines/avalanche/animation.h +++ b/engines/avalanche/animation.h @@ -125,6 +125,12 @@ public: void handleMoveKey(const Common::Event &event); void hideInCupboard(); + // These 2 functions are responsible for playing the thunder animation when the player swears too much. + void drawLightning(int16 x1, int16 y1, int16 x2, int16 y2); + void thunder(); + + void wobble(); + void setDirection(Direction dir); void setOldDirection(Direction dir); Direction getDirection(); diff --git a/engines/avalanche/avalanche.cpp b/engines/avalanche/avalanche.cpp index dbe434cde3..a7e7be0ad3 100644 --- a/engines/avalanche/avalanche.cpp +++ b/engines/avalanche/avalanche.cpp @@ -532,75 +532,9 @@ Common::Error AvalancheEngine::run() { do { runAvalot(); - -#if 0 - switch (_storage._operation) { - case kRunShootemup: - run("seu.avx", kJsb, kBflight, kNormal); - break; - case kRunDosshell: - dosShell(); - break; - case kRunGhostroom: - run("g-room.avx", kJsb, kNoBflight, kNormal); - break; - case kRunGolden: - run("golden.avx", kJsb, kBflight, kMusical); - break; - } -#endif - } while (!_letMeOut && !shouldQuit()); return Common::kNoError; } -#if 0 -void AvalancheEngine::run(Common::String what, bool withJsb, bool withBflight, Elm how) { - // Probably there'll be no need of this function, as all *.AVX-es will become classes. - warning("STUB: run(%s)", what.c_str()); -} - -Common::String AvalancheEngine::elmToStr(Elm how) { - switch (how) { - case kNormal: - case kMusical: - return Common::String("jsb"); - case kRegi: - return Common::String("REGI"); - case kElmpoyten: - return Common::String("ELMPOYTEN"); - // Useless, but silent a warning - default: - return Common::String(""); - } -} - -// Same as keypressed1(). -void AvalancheEngine::flushBuffer() { - warning("STUB: flushBuffer()"); -} - -void AvalancheEngine::dosShell() { - warning("STUB: dosShell()"); -} - -// Needed in dos_shell(). TODO: Remove later. -Common::String AvalancheEngine::commandCom() { - warning("STUB: commandCom()"); - return ("STUB: commandCom()"); -} - -// Needed for run_avalot()'s errors. TODO: Remove later. -void AvalancheEngine::explain(byte error) { - warning("STUB: explain()"); -} - -// Needed later. -void AvalancheEngine::quit() { - cursorOn(); -} - -#endif - } // End of namespace Avalanche diff --git a/engines/avalanche/avalanche.h b/engines/avalanche/avalanche.h index 7392bf3fae..fe13fa8d9e 100644 --- a/engines/avalanche/avalanche.h +++ b/engines/avalanche/avalanche.h @@ -42,6 +42,7 @@ #include "avalanche/closing.h" #include "avalanche/sound.h" #include "avalanche/nim.h" +#include "avalanche/clock.h" #include "common/serializer.h" @@ -127,43 +128,6 @@ private: AvalancheConsole *_console; Common::Platform _platform; -#if 0 - struct { - byte _operation; - uint16 _skellern; - byte _contents[1000]; - } _storage; - - static const int16 kRunShootemup = 1, kRunDosshell = 2, kRunGhostroom = 3, kRunGolden = 4; - static const int16 kReset = 0; - - static const bool kJsb = true, kNoJsb = false, kBflight = true, kNoBflight = false; - - // From bootstrp: - enum Elm {kNormal, kMusical, kElmpoyten, kRegi}; - - Common::String _argsWithNoFilename; - byte _originalMode; - byte *_old1c; - Common::String _segofs; - int32 _soundcard, _speed, _baseaddr, _irq, _dma; - bool _zoomy; - - void run(Common::String what, bool withJsb, bool withBflight, Elm how); - void bFlightOn(); - void bFlightOff(); - Common::String elmToStr(Elm how); - bool keyPressed(); - void flushBuffer(); - void dosShell(); - void bFlight(); - Common::String commandCom(); - void explain(byte error); - void cursorOff(); - void cursorOn(); - void quit(); -#endif - public: // For Thinkabout: static const bool kThing = true; @@ -172,7 +136,6 @@ public: static const char kSpludwicksOrder[3]; static const uint16 kNotes[12]; - static const TuneType kTune; bool _holdLeftMouse; diff --git a/engines/avalanche/avalot.cpp b/engines/avalanche/avalot.cpp index 9555bb4505..6648e8d961 100644 --- a/engines/avalanche/avalot.cpp +++ b/engines/avalanche/avalot.cpp @@ -76,11 +76,6 @@ namespace Avalanche { const char AvalancheEngine::kSpludwicksOrder[3] = {kObjectOnion, kObjectInk, kObjectMushroom}; const uint16 AvalancheEngine::kNotes[12] = {196, 220, 247, 262, 294, 330, 350, 392, 440, 494, 523, 587}; -const TuneType AvalancheEngine::kTune = { - kPitchHigher, kPitchHigher, kPitchLower, kPitchSame, kPitchHigher, kPitchHigher, kPitchLower, kPitchHigher, kPitchHigher, kPitchHigher, - kPitchLower, kPitchHigher, kPitchHigher, kPitchSame, kPitchHigher, kPitchLower, kPitchLower, kPitchLower, kPitchLower, kPitchHigher, - kPitchHigher, kPitchLower, kPitchLower, kPitchLower, kPitchLower, kPitchSame, kPitchLower, kPitchHigher, kPitchSame, kPitchLower, kPitchHigher -}; Room AvalancheEngine::_whereIs[29] = { // The Lads @@ -116,88 +111,7 @@ Room AvalancheEngine::_whereIs[29] = { kRoomWiseWomans // The Wise Woman. }; -Clock::Clock(AvalancheEngine *vm) { - _vm = vm; - // Magic value to determine if we just created the instance - _oldHour = _oldHourAngle = _oldMinute = 17717; - _hour = _minute = _second = 0; - _hourAngle = 0; -} - -void Clock::update() { - TimeDate t; - _vm->_system->getTimeAndDate(t); - _hour = t.tm_hour; - _minute = t.tm_min; - _second = t.tm_sec; - - _hourAngle = (_hour % 12) * 30 + _minute / 2; - - if (_oldHour != _hour) { - plotHands(); - chime(); - } - - if (_oldMinute != _minute) - plotHands(); - - if ((_hour == 0) && (_oldHour != 0) && (_oldHour != 17717)) { - Common::String tmpStr = Common::String::format("Good morning!%c%cYes, it's just past " \ - "midnight. Are you having an all-night Avvy session? Glad you like the game that much!", - kControlNewLine, kControlNewLine); - _vm->_dialogs->displayText(tmpStr); - } - _oldHour = _hour; - _oldHourAngle = _hourAngle; - _oldMinute = _minute; -} - -Common::Point Clock::calcHand(uint16 angle, uint16 length, Color color) { - if (angle > 900) { - return(Common::Point(177, 177)); - } - return(_vm->_graphics->drawScreenArc(kCenterX, kCenterY, 449 - angle, 450 - angle, length, color)); -} - -void Clock::drawHand(const Common::Point &endPoint, Color color) { - if (endPoint.x == 177) - return; - - _vm->_graphics->drawScreenLine(kCenterX, kCenterY, endPoint.x, endPoint.y, color); -} - -void Clock::plotHands() { - _clockHandHour = calcHand(_oldHourAngle, 14, kColorYellow); - _clockHandMinute = calcHand(_oldMinute * 6, 17, kColorYellow); - drawHand(_clockHandHour, kColorBrown); - drawHand(_clockHandMinute, kColorBrown); - - _clockHandHour = calcHand(_hourAngle, 14, kColorBrown); - _clockHandMinute = calcHand(_minute * 6, 17, kColorBrown); - drawHand(_clockHandHour, kColorYellow); - drawHand(_clockHandMinute, kColorYellow); -} - -void Clock::chime() { - // Too high - must be first time around - // Mute - skip the sound generation - if ((_oldHour == 17717) || (!_vm->_soundFx)) - return; - - byte hour = _hour % 12; - if (hour == 0) - hour = 12; - - _vm->_graphics->loadMouse(kCurWait); - - for (int i = 1; i <= hour; i++) { - for (int j = 1; j <= 3; j++) - _vm->_sound->playNote((i % 3) * 64 + 140 - j * 30, 50 - j * 12); - if (i != hour) - _vm->_system->delayMillis(100); - } -} void AvalancheEngine::handleKeyDown(Common::Event &event) { _sound->click(); @@ -338,13 +252,6 @@ void AvalancheEngine::init() { _also[i][j] = nullptr; } -#if 0 - if (_vm->_enhanced->atbios) - atkey = "f1"; - else - atkey = "alt-"; -#endif - _letMeOut = false; _currentMouse = 177; _dropsOk = true; @@ -1368,7 +1275,7 @@ void AvalancheEngine::minorRedraw() { } void AvalancheEngine::majorRedraw() { - warning("STUB: major_redraw()"); + _graphics->refreshScreen(); } uint16 AvalancheEngine::bearing(byte whichPed) { diff --git a/engines/avalanche/avalot.h b/engines/avalanche/avalot.h index f50ad28bc4..9afb4a7b63 100644 --- a/engines/avalanche/avalot.h +++ b/engines/avalanche/avalot.h @@ -35,33 +35,9 @@ namespace Avalanche { class AvalancheEngine; -class Clock { -public: - Clock(AvalancheEngine *vm); - - void update(); - -private: - static const int kCenterX = 510; - static const int kCenterY = 183; - - AvalancheEngine *_vm; - - uint16 _hour, _minute, _second, _hourAngle, _oldHour, _oldMinute, _oldHourAngle; - Common::Point _clockHandHour, _clockHandMinute; - - Common::Point calcHand(uint16 angle, uint16 length, Color color); - void drawHand(const Common::Point &endPoint, Color color); - void plotHands(); - void chime(); -}; - static const byte kObjectNum = 18; // always preface with a # static const int16 kCarryLimit = 12; // carry limit -static const int16 kNumlockCode = 32; // Code for Num Lock -static const int16 kMouseSize = 134; - struct PedType { int16 _x, _y; Direction _direction; @@ -80,8 +56,6 @@ struct LineType : public FieldType { Color _color; }; -typedef int8 TuneType[31]; - struct QuasipedType { byte _whichPed; Color _textColor; @@ -90,15 +64,6 @@ struct QuasipedType { People _who; }; -#if 0 -struct Sundry { // Things which must be saved over a backtobootstrap, outside DNA. - Common::String _qEnidFilename; - bool _qSoundFx; - byte _qThinks; - bool _qThinkThing; -}; -#endif - } // End of namespace Avalanche #endif // AVALANCHE_AVALOT_H diff --git a/engines/avalanche/clock.cpp b/engines/avalanche/clock.cpp new file mode 100644 index 0000000000..1c2c50c3bf --- /dev/null +++ b/engines/avalanche/clock.cpp @@ -0,0 +1,116 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +/* +* This code is based on the original source code of Lord Avalot d'Argent version 1.3. +* Copyright (c) 1994-1995 Mike: Mark and Thomas Thurman. +*/ + +#include "avalanche/clock.h" +#include "avalanche/avalanche.h" + +namespace Avalanche { + +Clock::Clock(AvalancheEngine *vm) { + _vm = vm; + // Magic value to determine if we just created the instance + _oldHour = _oldHourAngle = _oldMinute = 17717; + _hour = _minute = _second = 0; + _hourAngle = 0; +} + +void Clock::update() { + TimeDate t; + _vm->_system->getTimeAndDate(t); + _hour = t.tm_hour; + _minute = t.tm_min; + _second = t.tm_sec; + + _hourAngle = (_hour % 12) * 30 + _minute / 2; + + if (_oldHour != _hour) { + plotHands(); + chime(); + } + + if (_oldMinute != _minute) + plotHands(); + + if ((_hour == 0) && (_oldHour != 0) && (_oldHour != 17717)) { + Common::String tmpStr = Common::String::format("Good morning!%c%cYes, it's just past " \ + "midnight. Are you having an all-night Avvy session? Glad you like the game that much!", + kControlNewLine, kControlNewLine); + _vm->_dialogs->displayText(tmpStr); + } + _oldHour = _hour; + _oldHourAngle = _hourAngle; + _oldMinute = _minute; +} + +Common::Point Clock::calcHand(uint16 angle, uint16 length, Color color) { + if (angle > 900) { + return(Common::Point(177, 177)); + } + + return(_vm->_graphics->drawScreenArc(kCenterX, kCenterY, 449 - angle, 450 - angle, length, color)); +} + +void Clock::drawHand(const Common::Point &endPoint, Color color) { + if (endPoint.x == 177) + return; + + _vm->_graphics->drawScreenLine(kCenterX, kCenterY, endPoint.x, endPoint.y, color); +} + +void Clock::plotHands() { + _clockHandHour = calcHand(_oldHourAngle, 14, kColorYellow); + _clockHandMinute = calcHand(_oldMinute * 6, 17, kColorYellow); + drawHand(_clockHandHour, kColorBrown); + drawHand(_clockHandMinute, kColorBrown); + + _clockHandHour = calcHand(_hourAngle, 14, kColorBrown); + _clockHandMinute = calcHand(_minute * 6, 17, kColorBrown); + drawHand(_clockHandHour, kColorYellow); + drawHand(_clockHandMinute, kColorYellow); +} + +void Clock::chime() { + // Too high - must be first time around + // Mute - skip the sound generation + if ((_oldHour == 17717) || (!_vm->_soundFx)) + return; + + byte hour = _hour % 12; + if (hour == 0) + hour = 12; + + _vm->_graphics->loadMouse(kCurWait); + + for (int i = 1; i <= hour; i++) { + for (int j = 1; j <= 3; j++) + _vm->_sound->playNote((i % 3) * 64 + 140 - j * 30, 50 - j * 12); + if (i != hour) + _vm->_system->delayMillis(100); + } +} + +} // End of namespace Avalanche diff --git a/engines/avalanche/clock.h b/engines/avalanche/clock.h new file mode 100644 index 0000000000..68e8e119f0 --- /dev/null +++ b/engines/avalanche/clock.h @@ -0,0 +1,60 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +/* +* This code is based on the original source code of Lord Avalot d'Argent version 1.3. +* Copyright (c) 1994-1995 Mike: Mark and Thomas Thurman. +*/ + +#ifndef AVALANCHE_CLOCK_H +#define AVALANCHE_CLOCK_H + +#include "common/rect.h" +#include "avalanche/enums.h" + +namespace Avalanche { +class AvalancheEngine; + +class Clock { +public: + Clock(AvalancheEngine *vm); + + void update(); + +private: + static const int kCenterX = 510; + static const int kCenterY = 183; + + AvalancheEngine *_vm; + + uint16 _hour, _minute, _second, _hourAngle, _oldHour, _oldMinute, _oldHourAngle; + Common::Point _clockHandHour, _clockHandMinute; + + Common::Point calcHand(uint16 angle, uint16 length, Color color); + void drawHand(const Common::Point &endPoint, Color color); + void plotHands(); + void chime(); +}; + +} // End of namespace Avalanche + +#endif // AVALANCHE_CLOCK_H diff --git a/engines/avalanche/dialogs.cpp b/engines/avalanche/dialogs.cpp index c68ad4b002..2174df3580 100644 --- a/engines/avalanche/dialogs.cpp +++ b/engines/avalanche/dialogs.cpp @@ -34,6 +34,12 @@ namespace Avalanche { +const Dialogs::TuneType Dialogs::kTune = { + kPitchHigher, kPitchHigher, kPitchLower, kPitchSame, kPitchHigher, kPitchHigher, kPitchLower, kPitchHigher, kPitchHigher, kPitchHigher, + kPitchLower, kPitchHigher, kPitchHigher, kPitchSame, kPitchHigher, kPitchLower, kPitchLower, kPitchLower, kPitchLower, kPitchHigher, + kPitchHigher, kPitchLower, kPitchLower, kPitchLower, kPitchLower, kPitchSame, kPitchLower, kPitchHigher, kPitchSame, kPitchLower, kPitchHigher +}; + // A quasiped defines how people who aren't sprites talk. For example, quasiped // "A" is Dogfood. The rooms aren't stored because I'm leaving that to context. const QuasipedType Dialogs::kQuasipeds[16] = { @@ -270,7 +276,7 @@ bool Dialogs::theyMatch(TuneType &played) { byte mistakes = 0; for (unsigned int i = 0; i < sizeof(played); i++) { - if (played[i] != _vm->kTune[i]) + if (played[i] != kTune[i]) mistakes++; } diff --git a/engines/avalanche/dialogs.h b/engines/avalanche/dialogs.h index 43e6a4fec6..defd152db5 100644 --- a/engines/avalanche/dialogs.h +++ b/engines/avalanche/dialogs.h @@ -70,6 +70,9 @@ private: kFontStyleItalic }; + typedef int8 TuneType[31]; + + static const TuneType kTune; static const int16 kHalfIconWidth = 19; static const QuasipedType kQuasipeds[16]; diff --git a/engines/avalanche/graphics.cpp b/engines/avalanche/graphics.cpp index 4b8d667fbf..a8efc4be9b 100644 --- a/engines/avalanche/graphics.cpp +++ b/engines/avalanche/graphics.cpp @@ -198,7 +198,7 @@ void GraphicManager::drawToolbar() { Common::Point GraphicManager::drawArc(Graphics::Surface &surface, int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color) { Common::Point endPoint; - const float convfac = M_PI / 180.0; + const double convfac = M_PI / 180.0; int32 xRadius = radius; int32 yRadius = radius * kScreenWidth / (8 * kScreenHeight); // Just don't ask why... @@ -281,6 +281,10 @@ Common::Point GraphicManager::drawArc(Graphics::Surface &surface, int16 x, int16 return endPoint; } +void GraphicManager::drawLine(int x1, int y1, int x2, int y2, int penX, int penY, Color color) { + _surface.drawThickLine(x1, y1, x2, y2, penX, penY, color); +} + Common::Point GraphicManager::drawScreenArc(int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color) { return drawArc(_surface, x, y, stAngle, endAngle, radius, color); } @@ -573,6 +577,16 @@ Graphics::Surface GraphicManager::loadPictureSign(Common::File &file, int xl, in return picture; } +/** +* Shifts the whole screen down by one line and fills the gap with black. +*/ +void GraphicManager::shiftScreen() { + for (uint16 y = _surface.h - 1; y > 1; y--) + memcpy(_surface.getBasePtr(0, y), _surface.getBasePtr(0, y - 1), _surface.w); + + _surface.drawLine(0, 0, _surface.w, 0, kColorBlack); +} + void GraphicManager::clearAlso() { _magics.fillRect(Common::Rect(0, 0, 640, 200), 0); _magics.frameRect(Common::Rect(0, 45, 640, 161), 15); @@ -811,9 +825,12 @@ void GraphicManager::setDialogColor(Color bg, Color text) { _talkFontColor = text; } -// Original name background() -void GraphicManager::setBackgroundColor(Color x) { - warning("STUB: setBackgroundColor()"); +/** +* Changes the black color of the palette to the selected one. +* @remarks Originally called 'background' +*/ +void GraphicManager::setBackgroundColor(Color newColor) { + g_system->getPaletteManager()->setPalette(_egaPalette[kEgaPaletteIndex[newColor]], kColorBlack, 1); } } // End of namespace Avalanche diff --git a/engines/avalanche/graphics.h b/engines/avalanche/graphics.h index 0de23612a7..636ae6fdf9 100644 --- a/engines/avalanche/graphics.h +++ b/engines/avalanche/graphics.h @@ -58,6 +58,7 @@ public: void loadDigits(); void loadMouse(byte which); + void drawLine(int x1, int y1, int x2, int y2, int penX, int penY, Color color); Common::Point drawScreenArc(int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color); void drawPieSlice(int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color); void drawTriangle(Common::Point *p, Color color); @@ -86,6 +87,9 @@ public: void nimDrawLogo(); void nimFree(); + // Used in wobble() + void shiftScreen(); + void clearAlso(); void clearTextBar(); void setAlsoLine(int x1, int y1, int x2, int y2, Color color); @@ -107,7 +111,7 @@ public: void refreshScreen(); void loadBackground(Common::File &file); void refreshBackground(); - void setBackgroundColor(Color x); + void setBackgroundColor(Color newColor); void setDialogColor(Color bg, Color text); void zoomOut(int16 x, int16 y); @@ -115,10 +119,11 @@ public: void getNaturalPicture(SpriteType &sprite); void saveScreen(); - void removeBackup(); void restoreScreen(); + void removeBackup(); private: + static const int16 kMouseSize = 134; static const uint16 kBackgroundWidth = kScreenWidth; static const byte kEgaPaletteIndex[16]; static const byte kBackgroundHeight = 8 * 12080 / kScreenWidth; // With 640 width it's 151. diff --git a/engines/avalanche/module.mk b/engines/avalanche/module.mk index 0f66bb8213..39ca94e3f8 100644 --- a/engines/avalanche/module.mk +++ b/engines/avalanche/module.mk @@ -16,7 +16,8 @@ MODULE_OBJS = \ sequence.o \ sound.o \ timer.o \ - nim.o + nim.o \ + clock.o # This module can be built as a plugin ifeq ($(ENABLE_AVALANCHE), DYNAMIC_PLUGIN) diff --git a/engines/avalanche/parser.cpp b/engines/avalanche/parser.cpp index 7ba482f049..b0524a0d7e 100644 --- a/engines/avalanche/parser.cpp +++ b/engines/avalanche/parser.cpp @@ -1144,7 +1144,7 @@ void Parser::swallow() { return; } _vm->_dialogs->displayScrollChain('U', 1); - _vm->_pingo->wobble(); + _vm->_animation->wobble(); _vm->_dialogs->displayScrollChain('U', 2); _vm->_objects[kObjectWine - 1] = false; _vm->refreshObjectList(); @@ -1694,6 +1694,11 @@ void Parser::doThat() { // "Slip" object _thing -= 49; + if (_vm->_tiedUp) { + _vm->_dialogs->displayText("You better stay quiet now!"); + return; + } + if ((_verb != kVerbCodeLoad) && (_verb != kVerbCodeSave) && (_verb != kVerbCodeQuit) && (_verb != kVerbCodeInfo) && (_verb != kVerbCodeHelp) && (_verb != kVerbCodeLarrypass) && (_verb != kVerbCodePhaon) && (_verb != kVerbCodeBoss) && (_verb != kVerbCodeCheat) && (_verb != kVerbCodeRestart) && (_verb != kVerbCodeDir) && (_verb != kVerbCodeScore) && (_verb != kVerbCodeHiscores) && (_verb != kVerbCodeSmartAlec)) { @@ -1702,7 +1707,7 @@ void Parser::doThat() { "Try restarting, or restoring a saved game!"); return; } - if (!_vm->_avvyIsAwake && (_verb != kVerbCodeDie) && (_verb != kVerbCodeExpletive) && (_verb != kVerbCodeWake)) { + if (!_vm->_avvyIsAwake && (_verb != kVerbCodeWake)) { _vm->_dialogs->displayText("Talking in your sleep? Try waking up!"); return; } @@ -2108,7 +2113,7 @@ void Parser::doThat() { } break; default: { - _vm->_pingo->zonk(); + _vm->_animation->thunder(); Common::String tmpStr = Common::String::format("A crack of lightning shoots from the sky, and fries you." \ "%c%c(`Such is the anger of the gods, Avvy!\")", kControlNewLine, kControlNewLine); _vm->_dialogs->displayText(tmpStr); diff --git a/engines/avalanche/pingo.cpp b/engines/avalanche/pingo.cpp index 433924f594..40467ab839 100644 --- a/engines/avalanche/pingo.cpp +++ b/engines/avalanche/pingo.cpp @@ -56,18 +56,6 @@ void Pingo::copyPage(byte frp, byte top) { // taken from Copy02 (above) warning("STUB: Pingo::copyPage()"); } -void Pingo::wobble() { - warning("STUB: Pingo::wobble()"); -} - -void Pingo::zl(int16 x1, int16 y1, int16 x2, int16 y2) { - warning("STUB: Pingo::zl()"); -} - -void Pingo::zonk() { - warning("STUB: Pingo::zonk()"); -} - void Pingo::winningPic() { Common::File f; _vm->fadeOut(); diff --git a/engines/avalanche/pingo.h b/engines/avalanche/pingo.h index 72fdb54c2a..6eecaf6453 100644 --- a/engines/avalanche/pingo.h +++ b/engines/avalanche/pingo.h @@ -43,15 +43,12 @@ public: void copy02(); void copy03(); void copyPage(byte frp, byte top); - void wobble(); - void zonk(); void winningPic(); private: AvalancheEngine *_vm; void dPlot(int16 x, int16 y, Common::String z); - void zl(int16 x1, int16 y1, int16 x2, int16 y2); }; } // End of namespace Avalanche. diff --git a/engines/avalanche/timer.cpp b/engines/avalanche/timer.cpp index 40f2af529a..c8ea820c0e 100644 --- a/engines/avalanche/timer.cpp +++ b/engines/avalanche/timer.cpp @@ -492,7 +492,7 @@ void Timer::buyDrinks() { _vm->_malagauche = 0; _vm->_dialogs->displayScrollChain('D', _vm->_drinking); // Display message about it. - _vm->_pingo->wobble(); // Do the special effects. + _vm->_animation->wobble(); // Do the special effects. _vm->_dialogs->displayScrollChain('D', 1); // That'll be thruppence. if (_vm->decreaseMoney(3)) // Pay 3d. _vm->_dialogs->displayScrollChain('D', 3); // Tell 'em you paid up. diff --git a/engines/cge/bitmap.cpp b/engines/cge/bitmap.cpp index 989d2bbe99..5acd111c97 100644 --- a/engines/cge/bitmap.cpp +++ b/engines/cge/bitmap.cpp @@ -72,16 +72,16 @@ Bitmap::Bitmap(CGEEngine *vm, uint16 w, uint16 h, uint8 fill) // + room for wash table assert(v != NULL); - *(uint16 *) v = TO_LE_16(kBmpCPY | dsiz); // data chunk hader + WRITE_LE_UINT16(v, (kBmpCPY | dsiz)); // data chunk hader memset(v + 2, fill, dsiz); // data bytes - *(uint16 *)(v + lsiz - 2) = TO_LE_16(kBmpSKP | ((kScrWidth / 4) - dsiz)); // gap + WRITE_LE_UINT16(v + lsiz - 2, (kBmpSKP | ((kScrWidth / 4) - dsiz))); // gap // Replicate lines byte *destP; for (destP = v + lsiz; destP < (v + psiz); destP += lsiz) Common::copy(v, v + lsiz, destP); - *(uint16 *)(v + psiz - 2) = TO_LE_16(kBmpEOI); // plane trailer uint16 + WRITE_LE_UINT16(v + psiz - 2, kBmpEOI); // plane trailer uint16 // Replicate planes for (destP = v + psiz; destP < (v + 4 * psiz); destP += psiz) diff --git a/engines/cge/cge_main.cpp b/engines/cge/cge_main.cpp index 5325558f8b..602b36d6ef 100644 --- a/engines/cge/cge_main.cpp +++ b/engines/cge/cge_main.cpp @@ -539,14 +539,12 @@ void CGEEngine::setMapBrick(int x, int z) { debugC(1, kCGEDebugEngine, "CGEEngine::setMapBrick(%d, %d)", x, z); Square *s = new Square(this); - if (s) { - char n[6]; - s->gotoxy(x * kMapGridX, kMapTop + z * kMapGridZ); - sprintf(n, "%02d:%02d", x, z); - _clusterMap[z][x] = 1; - s->setName(n); - _vga->_showQ->insert(s, _vga->_showQ->first()); - } + char n[6]; + s->gotoxy(x * kMapGridX, kMapTop + z * kMapGridZ); + sprintf(n, "%02d:%02d", x, z); + _clusterMap[z][x] = 1; + s->setName(n); + _vga->_showQ->insert(s, _vga->_showQ->first()); } void CGEEngine::keyClick() { diff --git a/engines/cge/sound.cpp b/engines/cge/sound.cpp index b378898955..892b826318 100644 --- a/engines/cge/sound.cpp +++ b/engines/cge/sound.cpp @@ -186,6 +186,10 @@ DataCk *Fx::load(int idx, int ref) { DataCk *Fx::loadWave(EncryptedStream *file) { byte *data = (byte *)malloc(file->size()); + + if (!data) + return 0; + file->read(data, file->size()); return new DataCk(data, file->size()); diff --git a/engines/engine.cpp b/engines/engine.cpp index 52020c772e..8326a1fe89 100644 --- a/engines/engine.cpp +++ b/engines/engine.cpp @@ -154,6 +154,10 @@ Engine::~Engine() { CursorMan.popCursorPalette(); } +void Engine::initializePath(const Common::FSNode &gamePath) { + SearchMan.addDirectory(gamePath.getPath(), gamePath, 0, 4); +} + void initCommonGFX(bool defaultTo1XScaler) { const Common::ConfigManager::Domain *transientDomain = ConfMan.getDomain(Common::ConfigManager::kTransientDomain); const Common::ConfigManager::Domain *gameDomain = ConfMan.getActiveDomain(); diff --git a/engines/engine.h b/engines/engine.h index 4f4223384a..33416dda44 100644 --- a/engines/engine.h +++ b/engines/engine.h @@ -37,6 +37,7 @@ class Error; class EventManager; class SaveFileManager; class TimerManager; +class FSNode; } namespace GUI { class Debugger; @@ -142,6 +143,16 @@ public: virtual ~Engine(); /** + * Init SearchMan according to the game path. + * + * By default it adds the directory in non-flat mode with a depth of 4 as + * priority 0 to SearchMan. + * + * @param gamePath The base directory of the game data. + */ + virtual void initializePath(const Common::FSNode &gamePath); + + /** * Init the engine and start its main loop. * @return returns kNoError on success, else an error code. */ diff --git a/engines/fullpipe/constants.h b/engines/fullpipe/constants.h index cdb5dc6945..408f765fce 100644 --- a/engines/fullpipe/constants.h +++ b/engines/fullpipe/constants.h @@ -86,8 +86,81 @@ namespace Fullpipe { #define PIC_IN1_GAMETITLE 5169 #define PIC_IN1_PIPETITLE 5167 #define PIC_INV_MENU 991 +#define PIC_MAP_A01 5263 +#define PIC_MAP_A02 5264 +#define PIC_MAP_A03 5265 +#define PIC_MAP_A04 5266 +#define PIC_MAP_A05 5267 +#define PIC_MAP_A06 5268 +#define PIC_MAP_A07 5269 +#define PIC_MAP_A08 5270 +#define PIC_MAP_A09 5271 +#define PIC_MAP_A10 5272 +#define PIC_MAP_A11 5273 +#define PIC_MAP_A12 5274 #define PIC_MAP_A13 5275 +#define PIC_MAP_A14 5276 +#define PIC_MAP_I01 5295 +#define PIC_MAP_I02 5296 +#define PIC_MAP_P01 5277 +#define PIC_MAP_P02 5278 +#define PIC_MAP_P03 5279 +#define PIC_MAP_P04 5280 +#define PIC_MAP_P05 5281 +#define PIC_MAP_P06 5282 +#define PIC_MAP_P07 5283 +#define PIC_MAP_P08 5284 +#define PIC_MAP_P09 5285 +#define PIC_MAP_P10 5286 +#define PIC_MAP_P11 5287 +#define PIC_MAP_P12 5288 +#define PIC_MAP_P13 5289 +#define PIC_MAP_P14 5290 +#define PIC_MAP_P15 5291 +#define PIC_MAP_P16 5292 +#define PIC_MAP_P17 5293 +#define PIC_MAP_P18 5294 #define PIC_MAP_S01 5223 +#define PIC_MAP_S02 5224 +#define PIC_MAP_S03 5225 +#define PIC_MAP_S04 5226 +#define PIC_MAP_S05 5227 +#define PIC_MAP_S06 5228 +#define PIC_MAP_S07 5229 +#define PIC_MAP_S08 5231 +#define PIC_MAP_S09 5230 +#define PIC_MAP_S10 5232 +#define PIC_MAP_S11 5233 +#define PIC_MAP_S12 5234 +#define PIC_MAP_S13 5235 +#define PIC_MAP_S14 5236 +#define PIC_MAP_S15 5237 +#define PIC_MAP_S16 5238 +#define PIC_MAP_S17 5239 +#define PIC_MAP_S1819 5240 +#define PIC_MAP_S20 5241 +#define PIC_MAP_S21 5242 +#define PIC_MAP_S22 5243 +#define PIC_MAP_S23_1 5244 +#define PIC_MAP_S23_2 5245 +#define PIC_MAP_S24 5246 +#define PIC_MAP_S25 5247 +#define PIC_MAP_S26 5248 +#define PIC_MAP_S27 5249 +#define PIC_MAP_S28 5250 +#define PIC_MAP_S29 5251 +#define PIC_MAP_S30 5252 +#define PIC_MAP_S31_1 5253 +#define PIC_MAP_S31_2 5254 +#define PIC_MAP_S32_1 5255 +#define PIC_MAP_S32_2 5256 +#define PIC_MAP_S33 5257 +#define PIC_MAP_S34 5258 +#define PIC_MAP_S35 5259 +#define PIC_MAP_S36 5260 +#define PIC_MAP_S37 5261 +#define PIC_MAP_S38 5262 +#define PIC_TTL_CREDITS 5172 #define QU_INTR_STARTINTRO 5133 #define SC_1 301 #define SC_2 302 @@ -129,7 +202,6 @@ namespace Fullpipe { #define SC_38 2072 #define SC_COMMON 321 #define SC_DBGMENU 726 -#define SC_LDR 635 #define SC_FINAL1 4999 #define SC_FINAL2 5000 #define SC_FINAL3 5001 @@ -137,6 +209,9 @@ namespace Fullpipe { #define SC_INTRO1 3896 #define SC_INTRO2 3907 #define SC_INV 858 +#define SC_LDR 635 +#define SC_MAP 5222 +#define SC_TITLES 5166 #define SND_CMN_031 3516 #define SND_CMN_060 4921 #define SND_CMN_061 4922 @@ -144,25 +219,35 @@ namespace Fullpipe { #define SND_INTR_019 5220 #define ST_EGTR_SLIMSORROW 340 #define ST_FLY_FLY 4918 +#define ST_LBN_0H 2835 +#define ST_LBN_1H 2791 +#define ST_LBN_2H 2793 +#define ST_LBN_3H 2795 +#define ST_LBN_4H 2797 +#define ST_LBN_5H 2799 +#define ST_LBN_6H 2801 +#define ST_LBN_7H 2803 +#define ST_LBN_8H 2805 +#define ST_LBN_9H 2807 #define ST_LBN_0N 2832 -#define ST_LBN_0P 2833 #define ST_LBN_1N 2753 -#define ST_LBN_1P 2754 #define ST_LBN_2N 2756 -#define ST_LBN_2P 2757 #define ST_LBN_3N 2759 -#define ST_LBN_3P 2760 #define ST_LBN_4N 2762 -#define ST_LBN_4P 2763 #define ST_LBN_5N 2765 -#define ST_LBN_5P 2766 #define ST_LBN_6N 2768 -#define ST_LBN_6P 2769 #define ST_LBN_7N 2771 -#define ST_LBN_7P 2772 #define ST_LBN_8N 2774 -#define ST_LBN_8P 2775 #define ST_LBN_9N 2777 +#define ST_LBN_0P 2833 +#define ST_LBN_1P 2754 +#define ST_LBN_2P 2757 +#define ST_LBN_3P 2760 +#define ST_LBN_4P 2763 +#define ST_LBN_5P 2766 +#define ST_LBN_6P 2769 +#define ST_LBN_7P 2772 +#define ST_LBN_8P 2775 #define ST_LBN_9P 2778 #define ST_MAN_EMPTY 476 #define ST_MAN_GOU 459 @@ -745,6 +830,12 @@ namespace Fullpipe { #define ST_MUG17_EMPTY 2739 #define ST_SMG_SIT 1399 +// Scene 18 +#define PIC_SC18_RTRUBA 1520 + +// Scene 19 +#define PIC_SC19_RTRUBA3 1515 + // Scene 20 #define ANI_GRANDMA_20 2427 #define MSG_SC20_UPDATELOCKABLE 5217 @@ -1137,15 +1228,67 @@ namespace Fullpipe { // Scene 34 #define ANI_BOOT_34 4560 +#define ANI_BOX_34 2498 #define ANI_CACTUS_34 2381 #define ANI_LUK_34 2541 +#define ANI_STOOL_34 2486 #define ANI_VENT_34 2473 +#define MSG_SC34_CLIMB 2490 +#define MSG_SC34_CLIMBBOX 4571 +#define MSG_SC34_FROMCACTUS 4313 +#define MSG_SC34_LEAVEBOARD 2576 +#define MSG_SC34_ONBOARD 2550 +#define MSG_SC34_ONBUMP 5313 +#define MSG_SC34_ONCACTUS 2482 +#define MSG_SC34_RETRYVENT 5210 +#define MSG_SC34_SHOWBOX 2497 +#define MSG_SC34_SHOWVENT 2481 +#define MSG_SC34_TESTVENT 2557 +#define MSG_SC34_UNCLIMB 2492 +#define MV_MAN34_TRY 2485 +#define MV_MAN34_TRYTABUR 2489 +#define MV_MAN34_TURNVENT_L 4307 +#define MV_MAN34_TURNVENT_R 2500 #define QU_SC34_ENTERLIFT 2819 #define QU_SC34_EXITLIFT 2820 -#define ST_CTS34_EMPTY 2383 +#define QU_SC34_FROMBOX 2494 +#define QU_SC34_FROMBOX_FLOOR 4572 +#define QU_SC34_FROMCACTUS 4312 +#define QU_SC34_FROMSTOOL 2491 +#define QU_SC34_LEAVEBOARD 2575 +#define QU_SC34_SHOWSTOOL 2496 #define QU_CTS34_FALLEFT 4316 #define QU_CTS34_FALLRIGHT 4317 +#define QU_LUK34_CLOSE 2547 +#define QU_LUK34_OPEN 2546 +#define ST_CTS34_EMPTY 2383 #define ST_CTS34_GROWNEMPTY2 2475 +#define ST_LUK34_CLOSED 2543 +#define ST_LUK34_OPEN 2544 +#define ST_STL34_BOX2 4305 +#define ST_VNT34_RIGHT3 4318 +#define ST_VNT34_UP2 4310 + +// Scene 35 +#define ANI_HOSE 2424 +#define ANI_PUZODUV 2418 +#define MSG_SC35_CHECKPIPESOUND 4761 +#define MSG_SC35_PLUGHOSE 2524 +#define MSG_SC35_SHRINK 2570 +#define MSG_SC35_STARTFLOW 2523 +#define MSG_SC35_STOPFLOW 4864 +#define MSG_SC35_TRYFLY 4985 +#define QU_PDV_SML_BLINK 2553 +#define QU_PDV_SML_TRY 2554 +#define QU_SC35_EATHOZE 2540 +#define QU_SC35_ENTERLIFT 2815 +#define QU_SC35_EXITLIFT 2816 +#define SND_35_011 4509 +#define SND_35_012 4510 +#define SND_35_026 4863 +#define ST_HZE_NORM 2426 +#define ST_PDV_LARGE 2421 +#define ST_PDV_SMALL 2420 // Scene 36 #define ANI_SCISSORS_36 2647 @@ -1153,6 +1296,87 @@ namespace Fullpipe { #define PIC_SC36_MASK 5221 #define ST_RHT_OPEN 2362 +// Scene 37 +#define ANI_GUARD_37 2588 +#define ANI_RING 2604 +#define MSG_SC37_EXITLEFT 5006 +#define MSG_SC37_PULL 2945 +#define MV_GRD37_PULL 2589 +#define MV_RNG_CLOSE 2605 +#define MV_RNG_OPEN 4612 +#define PIC_SC37_MASK 2608 +#define SND_37_007 4547 +#define ST_GRD37_STAND 2590 +#define ST_RNG_CLOSED2 4865 +#define ST_RNG_OPEN 2606 + +// Scene 38 +#define ANI_BOTTLE38 2188 +#define ANI_DOMINO38 2200 +#define ANI_DOMINOS 3317 +#define ANI_DYLDA 2169 +#define ANI_GLAVAR 2154 +#define ANI_MALYSH 2165 +#define MSG_SC38_DRINK 2225 +#define MSG_SC38_HMRKICK 2224 +#define MSG_SC38_POINT 2226 +#define MSG_SC38_POSTHMRKICK 2256 +#define MSG_SC38_PROPOSE 2287 +#define MSG_SC38_TRYTAKEBOTTLE 3179 +#define MV_DMS_FOUR 3322 +#define MV_DMS_THREE 3321 +#define MV_GLV_LOOKMAN 2167 +#define ST_BTL38_FULL 3172 +#define ST_DMN38_6 2288 +#define ST_DMN38_NORM3 2251 +#define ST_DMN38_NORM4 2253 +#define ST_DMS_3 3319 +#define ST_DMS_4 3320 +#define ST_GLV_HAMMER 2156 +#define ST_GLV_NOHAMMER 2159 +#define ST_GLV_SLEEP2 2166 +#define ST_MLS_LEFT2 2291 +#define ST_MLS_RIGHT2 3323 +#define QU_DLD_BLINK 2216 +#define QU_DLD_DENY 2218 +#define QU_DLD_GLOT 2217 +#define QU_DLD_ICK 2219 +#define QU_DLD_TAKE1 2214 +#define QU_DLD_TAKE2 2215 +#define QU_GLV_DRINK 2210 +#define QU_GLV_DRINKBOTTLE 2286 +#define QU_GLV_DRINK_NOHMR 2211 +#define QU_GLV_HMRKICK 2207 +#define QU_GLV_PROPOSE 2280 +#define QU_GLV_PROPOSE_NOHMR 2281 +#define QU_GLV_TAKEDOMINO 2170 +#define QU_GLV_TAKEDOMINO_NOHMR 3182 +#define QU_GLV_TOSMALL 2208 +#define QU_GLV_TOSMALL_NOHMR 2209 +#define QU_MLS_BLINK 2222 +#define QU_MLS_HAND 2223 +#define QU_MLS_TURNL 2220 +#define QU_MLS_TURNR 2221 +#define QU_SC38_SHOWBOTTLE 2199 +#define QU_SC38_SHOWBOTTLE_ONTABLE 2838 +#define QU_SC38_ENTERLIFT 2836 +#define QU_SC38_EXITLIFT 2837 + +// Final scene +#define ANI_FIN_COIN 5014 +#define MSG_FIN_ENDFINAL 5109 +#define MSG_FIN_GOTO2 5024 +#define MSG_FIN_GOTO3 5071 +#define MSG_FIN_GOTO4 5075 +#define MSG_FIN_STARTFINAL 5025 +#define MSG_FN4_STARTMUSIC 5356 +#define QU_FIN1_FALLCOIN 5018 +#define QU_FIN1_TAKECOIN 5023 +#define QU_FN2_DOFINAL 5066 +#define QU_FN3_DOFINAL 5072 +#define QU_FN4_DOFINAL 5108 +#define ST_FCN_NORM 5017 + // Debug scene #define MSG_RESTARTGAME 4767 #define PIC_SCD_1 727 diff --git a/engines/fullpipe/fullpipe.cpp b/engines/fullpipe/fullpipe.cpp index 4cfa330a09..b1e366c3a1 100644 --- a/engines/fullpipe/fullpipe.cpp +++ b/engines/fullpipe/fullpipe.cpp @@ -82,6 +82,13 @@ FullpipeEngine::FullpipeEngine(OSystem *syst, const ADGameDescription *gameDesc) _modalObject = 0; + _liftEnterMQ = 0; + _liftExitMQ = 0; + _lift = 0; + _lastLiftButton = 0; + _liftX = 0; + _liftY = 0; + _gameContinue = true; _needRestart = false; _flgPlayIntro = true; @@ -451,21 +458,6 @@ void FullpipeEngine::setObjectState(const char *name, int state) { var->setSubVarAsInt(name, state); } -void FullpipeEngine::updateMapPiece(int mapId, int update) { - for (int i = 0; i < 200; i++) { - int hiWord = (_mapTable[i] >> 16) & 0xffff; - - if (hiWord == mapId) { - _mapTable[i] |= update; - return; - } - if (!hiWord) { - _mapTable[i] = (mapId << 16) | update; - return; - } - } -} - void FullpipeEngine::disableSaves(ExCommand *ex) { warning("STUB: FullpipeEngine::disableSaves()"); } diff --git a/engines/fullpipe/fullpipe.h b/engines/fullpipe/fullpipe.h index ecf3c12982..1e583279f5 100644 --- a/engines/fullpipe/fullpipe.h +++ b/engines/fullpipe/fullpipe.h @@ -60,6 +60,7 @@ class GameProject; class GameObject; class GlobalMessageQueueList; struct MessageHandler; +class MessageQueue; struct MovTable; class MGM; class NGIArchive; @@ -157,6 +158,7 @@ public: void stopSoundStream2(); void stopAllSoundStreams(); void stopAllSoundInstances(int id); + void updateSoundVolume(); int _sfxVolume; @@ -224,6 +226,8 @@ public: int (*_updateScreenCallback)(); int (*_updateCursorCallback)(); + void drawAlphaRectangle(int x1, int y1, int x2, int y2, int alpha); + int _cursorId; int _minCursorId; int _maxCursorId; @@ -266,12 +270,23 @@ public: void getAllInventory(); + StaticANIObject *_lastLiftButton; + MessageQueue *_liftEnterMQ; + MessageQueue *_liftExitMQ; + StaticANIObject *_lift; + int _liftX; + int _liftY; + int lift_getButtonIdP(int objid); + int lift_getButtonIdH(int objid); + int lift_getButtonIdN(int objid); void lift_setButton(const char *name, int state); - void lift_sub5(Scene *sc, int qu1, int qu2); + void lift_init(Scene *sc, int qu1, int qu2); + void lift_setButtonStatics(Scene *sc, int buttonId); void lift_exitSeq(ExCommand *ex); void lift_closedoorSeq(); - void lift_animation3(); + void lift_clickButton(); + void lift_walkAndGo(); void lift_goAnimation(); void lift_sub1(StaticANIObject *ani); void lift_startExitQueue(); diff --git a/engines/fullpipe/gfx.cpp b/engines/fullpipe/gfx.cpp index a67a4d7b19..2d68600dbb 100644 --- a/engines/fullpipe/gfx.cpp +++ b/engines/fullpipe/gfx.cpp @@ -1295,4 +1295,8 @@ DynamicPhase *Shadows::findSize(int width, int height) { return _items[idx].dynPhase; } +void FullpipeEngine::drawAlphaRectangle(int x1, int y1, int x2, int y2, int alpha) { + warning("STUB: FullpipeEngine::drawAlphaRectangle()"); +} + } // End of namespace Fullpipe diff --git a/engines/fullpipe/init.cpp b/engines/fullpipe/init.cpp index f661340665..8de37b5c9e 100644 --- a/engines/fullpipe/init.cpp +++ b/engines/fullpipe/init.cpp @@ -116,7 +116,7 @@ void FullpipeEngine::initObjectStates() { setObjectState(sO_BellyInflater, getObjectEnumState(sO_BellyInflater, sO_WithCork)); setObjectState(sO_Jawcrucnher, getObjectEnumState(sO_Jawcrucnher, sO_WithoutCarpet)); setObjectState(sO_Guard_1, getObjectEnumState(sO_Guard_1, sO_On)); - setObjectState(sO_Gurad_2, getObjectEnumState(sO_Gurad_2, sO_On)); + setObjectState(sO_Guard_2, getObjectEnumState(sO_Guard_2, sO_On)); setObjectState(sO_Guard_3, getObjectEnumState(sO_Guard_3, sO_On)); setObjectState(sO_Bottle_38, getObjectEnumState(sO_Bottle_38, sO_OnTheTable)); setObjectState(sO_Boss, getObjectEnumState(sO_Boss, sO_WithHammer)); diff --git a/engines/fullpipe/lift.cpp b/engines/fullpipe/lift.cpp index cb811d610c..aa0c19e475 100644 --- a/engines/fullpipe/lift.cpp +++ b/engines/fullpipe/lift.cpp @@ -26,43 +26,140 @@ #include "fullpipe/objectnames.h" #include "fullpipe/constants.h" +#include "fullpipe/scene.h" +#include "fullpipe/statics.h" +#include "fullpipe/messages.h" + namespace Fullpipe { int FullpipeEngine::lift_getButtonIdP(int objid) { switch (objid) { case ST_LBN_0N: return ST_LBN_0P; - break; + case ST_LBN_1N: return ST_LBN_1P; - break; + case ST_LBN_2N: return ST_LBN_2P; - break; + case ST_LBN_3N: return ST_LBN_3P; - break; + case ST_LBN_4N: return ST_LBN_4P; - break; + case ST_LBN_5N: return ST_LBN_5P; - break; + case ST_LBN_6N: return ST_LBN_6P; - break; + case ST_LBN_7N: return ST_LBN_7P; - break; + case ST_LBN_8N: return ST_LBN_8P; - break; + case ST_LBN_9N: return ST_LBN_9P; - break; + + default: + return 0; + } +} + +int FullpipeEngine::lift_getButtonIdH(int objid) { + switch (objid) { + case ST_LBN_0P: + return ST_LBN_0H; + + case ST_LBN_1P: + return ST_LBN_1H; + + case ST_LBN_2P: + return ST_LBN_2H; + + case ST_LBN_3P: + return ST_LBN_3H; + + case ST_LBN_4P: + return ST_LBN_4H; + + case ST_LBN_5P: + return ST_LBN_5H; + + case ST_LBN_6P: + return ST_LBN_6H; + + case ST_LBN_7P: + return ST_LBN_7H; + + case ST_LBN_8P: + return ST_LBN_8H; + + case ST_LBN_9P: + return ST_LBN_9H; + + default: + return 0; + } +} + +int FullpipeEngine::lift_getButtonIdN(int objid) { + switch (objid) { + case ST_LBN_0H: + case ST_LBN_0N: + case ST_LBN_0P: + return ST_LBN_0N; + + case ST_LBN_1H: + case ST_LBN_1N: + case ST_LBN_1P: + return ST_LBN_1N; + + case ST_LBN_2H: + case ST_LBN_2N: + case ST_LBN_2P: + return ST_LBN_2N; + + case ST_LBN_3H: + case ST_LBN_3N: + case ST_LBN_3P: + return ST_LBN_3N; + + case ST_LBN_4H: + case ST_LBN_4N: + case ST_LBN_4P: + return ST_LBN_4N; + + case ST_LBN_5H: + case ST_LBN_5N: + case ST_LBN_5P: + return ST_LBN_5N; + + case ST_LBN_6H: + case ST_LBN_6N: + case ST_LBN_6P: + return ST_LBN_6N; + + case ST_LBN_7H: + case ST_LBN_7N: + case ST_LBN_7P: + return ST_LBN_7N; + + case ST_LBN_8H: + case ST_LBN_8N: + case ST_LBN_8P: + return ST_LBN_8N; + + case ST_LBN_9H: + case ST_LBN_9N: + case ST_LBN_9P: + return ST_LBN_9N; + default: return 0; - break; } } @@ -73,8 +170,51 @@ void FullpipeEngine::lift_setButton(const char *name, int state) { var->setSubVarAsInt(name, state); } -void FullpipeEngine::lift_sub5(Scene *sc, int qu1, int qu2) { - warning("STUB: FullpipeEngine::lift_sub5()"); +void FullpipeEngine::lift_init(Scene *sc, int enterSeq, int exitSeq) { + _lastLiftButton = 0; + + _liftEnterMQ = sc->getMessageQueueById(enterSeq); + if (!_liftEnterMQ) + return; + + _liftExitMQ = sc->getMessageQueueById(exitSeq); + + if (!_liftExitMQ) + return; + + ExCommand *ex = _liftEnterMQ->getExCommandByIndex(0); + + if (!ex) + return; + + _liftX = ex->_x; + _liftY = ex->_y; + + _lift = sc->getStaticANIObject1ById(ANI_LIFT, -1); + + for (uint i = 0; i < sc->_staticANIObjectList1.size(); i++) { + StaticANIObject *ani = (StaticANIObject *)sc->_staticANIObjectList1[i]; + + if (ani->_id == ANI_LIFTBUTTON) + ani->_statics = ani->getStaticsById(lift_getButtonIdP(ani->_statics->_staticsId)); + } + + GameVar *var = getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons); + if (var) { + for (var = var->_subVars; var; var = var->_nextVarObj) { + for (uint i = 0; i < sc->_staticANIObjectList1.size(); i++) { + StaticANIObject *ani = (StaticANIObject *)sc->_staticANIObjectList1[i]; + + if (ani->_id == ANI_LIFTBUTTON) { + int id = lift_getButtonIdN(ani->_statics->_staticsId); + + if (id == var->_value.intValue) + ani->_statics = ani->getStaticsById(id); + } + + } + } + } } void FullpipeEngine::lift_exitSeq(ExCommand *ex) { @@ -85,8 +225,13 @@ void FullpipeEngine::lift_closedoorSeq() { warning("STUB: FullpipeEngine::lift_closedoorSeq()"); } -void FullpipeEngine::lift_animation3() { - warning("STUB: FullpipeEngine::lift_animation3()"); +void FullpipeEngine::lift_walkAndGo() { + warning("STUB: FullpipeEngine::lift_walkAndGo()"); +} + +void FullpipeEngine::lift_clickButton() { + if (_lastLiftButton) + lift_walkAndGo(); } void FullpipeEngine::lift_goAnimation() { @@ -98,7 +243,9 @@ void FullpipeEngine::lift_sub1(StaticANIObject *ani) { } void FullpipeEngine::lift_startExitQueue() { - warning("STUB: FullpipeEngine::lift_startExitQueue()"); + MessageQueue *mq = new MessageQueue(_liftExitMQ, 0, 0); + + mq->chain(0); } void FullpipeEngine::lift_sub05(ExCommand *ex) { @@ -111,4 +258,18 @@ bool FullpipeEngine::lift_checkButton(const char *varname) { return false; } +void FullpipeEngine::lift_setButtonStatics(Scene *sc, int buttonId) { + for (uint i = 0; i < sc->_staticANIObjectList1.size(); i++) { + StaticANIObject *ani = (StaticANIObject *)sc->_staticANIObjectList1[i]; + + if (ani->_id == ANI_LIFTBUTTON) { + int id = lift_getButtonIdN(ani->_statics->_staticsId); + + if (id == buttonId) + ani->_statics = ani->getStaticsById(id); + } + } +} + + } // End of namespace Fullpipe diff --git a/engines/fullpipe/modal.cpp b/engines/fullpipe/modal.cpp index 729b4035f0..f52dc95a7c 100644 --- a/engines/fullpipe/modal.cpp +++ b/engines/fullpipe/modal.cpp @@ -28,6 +28,8 @@ #include "fullpipe/scenes.h" #include "fullpipe/gameloader.h" +#include "fullpipe/constants.h" + #include "graphics/palette.h" #include "video/avi_decoder.h" @@ -193,6 +195,8 @@ bool ModalIntro::init(int counterdiff) { } void ModalIntro::update() { + warning("STUB: ModalIntro::update()"); + if (g_fp->_currentScene) { if (_introFlags & 1) { //sceneFade(virt, g_currentScene, 1); @@ -267,8 +271,488 @@ void ModalVideoPlayer::play(const char *filename) { } } +ModalMap::ModalMap() { + _mapScene = 0; + _pic = 0; + _isRunning = false; + _rect1 = g_fp->_sceneRect; + _x = g_fp->_currentScene->_x; + _y = g_fp->_currentScene->_y; + _flag = 0; + _mouseX = 0; + _mouseY = 0; + _field_38 = 0; + _field_3C = 0; + _field_40 = 12; + _rect2.top = 0; + _rect2.left = 0; + _rect2.bottom = 600; + _rect2.right = 800; +} + +ModalMap::~ModalMap() { + g_fp->_gameLoader->unloadScene(SC_MAP); + + g_fp->_sceneRect = _rect1; + + g_fp->_currentScene->_x = _x; + g_fp->_currentScene->_y = _y; +} + +bool ModalMap::init(int counterdiff) { + g_fp->setCursor(PIC_CSR_ITN); + + if (_flag) { + _rect2.left = _mouseX + _field_38 - g_fp->_mouseScreenPos.x; + _rect2.top = _mouseY + _field_3C - g_fp->_mouseScreenPos.y;; + _rect2.right = _rect2.left + 800; + _rect2.bottom = _rect2.top + 600; + + g_fp->_sceneRect =_rect2; + + _mapScene->updateScrolling2(); + + _rect2 = g_fp->_sceneRect; + } + + _field_40--; + + if (_field_40 <= 0) { + _field_40 = 12; + + if (_pic) + _pic->_flags ^= 4; + } + + return _isRunning; +} + +void ModalMap::update() { + g_fp->_sceneRect = _rect2; + + _mapScene->draw(); + + g_fp->drawArcadeOverlay(1); +} + +bool ModalMap::handleMessage(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return false; + + switch (cmd->_messageNum) { + case 29: + _flag = 1; + _mouseX = g_fp->_mouseScreenPos.x; + _mouseY = g_fp->_mouseScreenPos.x; + + _field_3C = _rect2.top; + _field_38 = _rect2.left; + + break; + + case 30: + _flag = 0; + break; + + case 36: + if (cmd->_keyCode != 9 && cmd->_keyCode != 27 ) + return false; + + break; + + case 107: + break; + + default: + return false; + } + + _isRunning = 0; + + return true; +} + +void ModalMap::initMap() { + _isRunning = 1; + + _mapScene = g_fp->accessScene(SC_MAP); + + if (!_mapScene) + error("ModalMap::initMap(): error accessing scene SC_MAP"); + + PictureObject *pic; + + for (int i = 0; i < 200; i++) { + if (!(g_fp->_mapTable[i] >> 16)) + break; + + pic = _mapScene->getPictureObjectById(g_fp->_mapTable[i] >> 16, 0); + + if ((g_fp->_mapTable[i] & 0xffff) == 1) + pic->_flags |= 4; + else + pic->_flags &= 0xfffb; + } + + pic = getScenePicture(); + + Common::Point point; + Common::Point point2; + + if (pic) { + pic->getDimensions(&point); + + _rect2.left = point.x / 2 + pic->_ox - 400; + _rect2.top = point.y / 2 + pic->_oy - 300; + _rect2.right = _rect2.left + 800; + _rect2.bottom = _rect2.top + 600; + + _mapScene->updateScrolling2(); + + _pic = _mapScene->getPictureObjectById(PIC_MAP_I02, 0); + _pic->getDimensions(&point2); + + _pic->setOXY(pic->_ox + point.x / 2 - point2.x / 2, point.y - point2.y / 2 + pic->_oy - 24); + _pic->_flags |= 4; + + _pic = _mapScene->getPictureObjectById(PIC_MAP_I01, 0); + _pic->getDimensions(&point2); + + _pic->setOXY(pic->_ox + point.x / 2 - point2.x / 2, point.y - point2.y / 2 + pic->_oy - 25); + _pic->_flags |= 4; + } + + g_fp->setArcadeOverlay(PIC_CSR_MAP); +} + +PictureObject *ModalMap::getScenePicture() { + int picId = 0; + + switch (g_fp->_currentScene->_sceneId) { + case SC_1: + picId = PIC_MAP_S01; + break; + case SC_2: + picId = PIC_MAP_S02; + break; + case SC_3: + picId = PIC_MAP_S03; + break; + case SC_4: + picId = PIC_MAP_S04; + break; + case SC_5: + picId = PIC_MAP_S05; + break; + case SC_6: + picId = PIC_MAP_S06; + break; + case SC_7: + picId = PIC_MAP_S07; + break; + case SC_8: + picId = PIC_MAP_S08; + break; + case SC_9: + picId = PIC_MAP_S09; + break; + case SC_10: + picId = PIC_MAP_S10; + break; + case SC_11: + picId = PIC_MAP_S11; + break; + case SC_12: + picId = PIC_MAP_S12; + break; + case SC_13: + picId = PIC_MAP_S13; + break; + case SC_14: + picId = PIC_MAP_S14; + break; + case SC_15: + picId = PIC_MAP_S15; + break; + case SC_16: + picId = PIC_MAP_S16; + break; + case SC_17: + picId = PIC_MAP_S17; + break; + case SC_18: + case SC_19: + picId = PIC_MAP_S1819; + break; + case SC_20: + picId = PIC_MAP_S20; + break; + case SC_21: + picId = PIC_MAP_S21; + break; + case SC_22: + picId = PIC_MAP_S22; + break; + case SC_23: + picId = PIC_MAP_S23_1; + break; + case SC_24: + picId = PIC_MAP_S24; + break; + case SC_25: + picId = PIC_MAP_S25; + break; + case SC_26: + picId = PIC_MAP_S26; + break; + case SC_27: + picId = PIC_MAP_S27; + break; + case SC_28: + picId = PIC_MAP_S28; + break; + case SC_29: + picId = PIC_MAP_S29; + break; + case SC_30: + picId = PIC_MAP_S30; + break; + case SC_31: + picId = PIC_MAP_S31_1; + break; + case SC_32: + picId = PIC_MAP_S32_1; + break; + case SC_33: + picId = PIC_MAP_S33; + break; + case SC_34: + picId = PIC_MAP_S34; + break; + case SC_35: + picId = PIC_MAP_S35; + break; + case SC_36: + picId = PIC_MAP_S36; + break; + case SC_37: + picId = PIC_MAP_S37; + break; + case SC_38: + picId = PIC_MAP_S38; + break; + case SC_FINAL1: + picId = PIC_MAP_S38; + break; + } + + if (picId) + return _mapScene->getPictureObjectById(picId, 0); + + error("ModalMap::getScenePicture(): Unknown scene id: %d", g_fp->_currentScene->_sceneId); +} + void FullpipeEngine::openMap() { - warning("STUB: FullpipeEngine::openMap()"); + if (!_modalObject) { + ModalMap *map = new ModalMap; + + _modalObject = map; + + map->initMap(); + } +} + +ModalFinal::ModalFinal() { + _flags = 0; + _counter = 255; + _sfxVolume = g_fp->_sfxVolume; +} + +ModalFinal::~ModalFinal() { + if (g_vars->sceneFinal_var01) { + g_fp->_gameLoader->unloadScene(SC_FINAL2); + g_fp->_gameLoader->unloadScene(SC_FINAL3); + g_fp->_gameLoader->unloadScene(SC_FINAL4); + + g_fp->_currentScene = g_fp->accessScene(SC_FINAL1); + + g_fp->stopAllSounds(); + + g_vars->sceneFinal_var01 = 0; + } + + g_fp->_sfxVolume = _sfxVolume; +} + +bool ModalFinal::init(int counterdiff) { + if (g_vars->sceneFinal_var01) { + g_fp->_gameLoader->updateSystems(42); + + return true; + } + + if (_counter > 0) { + _flags |= 2u; + + g_fp->_gameLoader->updateSystems(42); + + return true; + } + + unloadScenes(); + + g_fp->_modalObject = new ModalCredits(); + + return true; +} + +void ModalFinal::unloadScenes() { + g_fp->_gameLoader->unloadScene(SC_FINAL2); + g_fp->_gameLoader->unloadScene(SC_FINAL3); + g_fp->_gameLoader->unloadScene(SC_FINAL4); + + g_fp->_currentScene = g_fp->accessScene(SC_FINAL1); + + g_fp->stopAllSounds(); +} + +bool ModalFinal::handleMessage(ExCommand *cmd) { + if (cmd->_messageKind == 17 && cmd->_messageNum == 36 && cmd->_keyCode == 27) { + g_fp->_modalObject = new ModalMainMenu(); + g_fp->_modalObject->_parentObj = this; + + return true; + } + + return false; +} + +void ModalFinal::update() { + if (g_fp->_currentScene) { + g_fp->_currentScene->draw(); + + if (_flags & 1) { + g_fp->drawAlphaRectangle(0, 0, 800, 600, 0xff - _counter); + + _counter += 10; + + if (_counter >= 255) { + _counter = 255; + _flags &= 0xfe; + } + } else { + if (!(_flags & 2)) + return; + + g_fp->drawAlphaRectangle(0, 0, 800, 600, 0xff - _counter); + _counter -= 10; + + if (_counter <= 0) { + _counter = 0; + _flags &= 0xFD; + } + } + + g_fp->_sfxVolume = _counter * (_sfxVolume + 3000) / 255 - 3000; + + g_fp->updateSoundVolume(); + } +} + +ModalCredits::ModalCredits() { + Common::Point point; + + _sceneTitles = g_fp->accessScene(SC_TITLES); + + _creditsPic = _sceneTitles->getPictureObjectById(PIC_TTL_CREDITS, 0); + _creditsPic->_flags |= 4; + + _fadeIn = true; + _fadeOut = false; + + _creditsPic->getDimensions(&point); + + _countdown = point.y / 2 + 470; + _sfxVolume = g_fp->_sfxVolume; + + _currY = 630; + _maxY = -1000 - point.y; + + _currX = 400 - point.x / 2; + + _creditsPic->setOXY(_currX, _currY); +} + +ModalCredits::~ModalCredits() { + g_fp->_gameLoader->unloadScene(SC_TITLES); + + g_fp->_sfxVolume = _sfxVolume; +} + +bool ModalCredits::handleMessage(ExCommand *cmd) { + if (cmd->_messageKind == 17 && cmd->_messageNum == 36 && cmd->_keyCode == 27) { + _fadeIn = false; + + return true; + } + + return false; +} + +bool ModalCredits::init(int counterdiff) { + if (_fadeIn || _fadeOut) { + _countdown--; + + if (_countdown < 0) + _fadeIn = false; + + _creditsPic->setOXY(_currX, _currY); + + if (_currY > _maxY) + _currY -= 2; + } else { + if (_parentObj) + return 0; + + ModalMainMenu *menu = new ModalMainMenu; + + g_fp->_modalObject = menu; + + menu->_field_34 = 1; + } + + return true; +} + +void ModalCredits::update() { + warning("STUB: ModalCredits::update()"); + + if (_fadeOut) { + if (_fadeIn) { + _sceneTitles->draw(); + + return; + } + } else if (_fadeIn) { + //sceneFade(virt, this->_sceneTitles, 1); // TODO + _fadeOut = 1; + + return; + } + + if (_fadeOut) { + //sceneFade(virt, this->_sceneTitles, 0); // TODO + _fadeOut = 0; + return; + } + + _sceneTitles->draw(); +} + +ModalMainMenu::ModalMainMenu() { + warning("STUB: ModalMainMenu::ModalMainMenu()"); + + _field_34 = 0; } void FullpipeEngine::openHelp() { @@ -276,7 +760,11 @@ void FullpipeEngine::openHelp() { } void FullpipeEngine::openMainMenu() { - warning("STUB: FullpipeEngine::openMainMenu()"); + ModalMainMenu *menu = new ModalMainMenu; + + menu->_parentObj = g_fp->_modalObject; + + g_fp->_modalObject = menu; } } // End of namespace Fullpipe diff --git a/engines/fullpipe/modal.h b/engines/fullpipe/modal.h index b57d1fbd06..438e341c1c 100644 --- a/engines/fullpipe/modal.h +++ b/engines/fullpipe/modal.h @@ -25,6 +25,8 @@ namespace Fullpipe { +class PictureObject; + class BaseModalObject { public: @@ -75,6 +77,91 @@ public: void play(const char *fname); }; +class ModalMap : public BaseModalObject { + Scene *_mapScene; + PictureObject *_pic; + bool _isRunning; + Common::Rect _rect1; + int _x; + int _y; + int _flag; + int _mouseX; + int _mouseY; + int _field_38; + int _field_3C; + int _field_40; + Common::Rect _rect2; + + public: + ModalMap(); + virtual ~ModalMap(); + + virtual bool pollEvent() { return true; } + virtual bool handleMessage(ExCommand *message); + virtual bool init(int counterdiff); + virtual void update(); + virtual void saveload() {} + + void initMap(); + PictureObject *getScenePicture(); +}; + +class ModalFinal : public BaseModalObject { + int _flags; + int _counter; + int _sfxVolume; + + public: + ModalFinal(); + virtual ~ModalFinal(); + + virtual bool pollEvent() { return true; } + virtual bool handleMessage(ExCommand *message); + virtual bool init(int counterdiff); + virtual void update(); + virtual void saveload() {} + + void unloadScenes(); +}; + +class ModalCredits : public BaseModalObject { + Scene *_sceneTitles; + PictureObject *_creditsPic; + bool _fadeIn; + bool _fadeOut; + int _countdown; + int _sfxVolume; + int _currX; + int _currY; + int _maxY; + + public: + ModalCredits(); + virtual ~ModalCredits(); + + virtual bool pollEvent() { return true; } + virtual bool handleMessage(ExCommand *message); + virtual bool init(int counterdiff); + virtual void update(); + virtual void saveload() {} +}; + +class ModalMainMenu : public BaseModalObject { +public: + int _field_34; + +public: + ModalMainMenu(); + virtual ~ModalMainMenu() {} + + virtual bool pollEvent() { return true; } + virtual bool handleMessage(ExCommand *message) { return false; } + virtual bool init(int counterdiff) { return true; } + virtual void update() {} + virtual void saveload() {} +}; + + } // End of namespace Fullpipe #endif /* FULLPIPE_MODAL_H */ diff --git a/engines/fullpipe/module.mk b/engines/fullpipe/module.mk index ae259d907c..f6a94de421 100644 --- a/engines/fullpipe/module.mk +++ b/engines/fullpipe/module.mk @@ -55,7 +55,11 @@ MODULE_OBJS = \ scenes/scene32.o \ scenes/scene33.o \ scenes/scene34.o \ + scenes/scene35.o \ scenes/scene36.o \ + scenes/scene37.o \ + scenes/scene38.o \ + scenes/sceneFinal.o \ scenes/sceneDbg.o # This module can be built as a plugin diff --git a/engines/fullpipe/objectnames.h b/engines/fullpipe/objectnames.h index 8939f44975..eafdb2a8e7 100644 --- a/engines/fullpipe/objectnames.h +++ b/engines/fullpipe/objectnames.h @@ -217,7 +217,7 @@ namespace Fullpipe { #define sO_IsStandingInCorner "\xd1\xf2\xee\xe8\xf2 \xe2 \xf3\xe3\xeb\xf3" // "Стоит в углу" #define sO_Guardian "\xd1\xf2\xee\xf0\xee\xe6" // "Сторож" #define sO_Guard_1 "\xd1\xf2\xf0\xe0\xe6 1" // "Страж 1" -#define sO_Gurad_2 "\xd1\xf2\xf0\xe0\xe6 2" // "Страж 2" +#define sO_Guard_2 "\xd1\xf2\xf0\xe0\xe6 2" // "Страж 2" #define sO_Guard_3 "\xd1\xf2\xf0\xe0\xe6 3" // "Страж 3" #define sO_Stool_34 "\xd2\xe0\xe1\xf3\xf0\xe5\xf2_34" // "Табурет_34" #define sO_Pipe_9 "\xd2\xf0\xf3\xe1\xe0_9" // "Труба_9" diff --git a/engines/fullpipe/scenes.cpp b/engines/fullpipe/scenes.cpp index 11f8e19865..71c8b1efb5 100644 --- a/engines/fullpipe/scenes.cpp +++ b/engines/fullpipe/scenes.cpp @@ -339,22 +339,53 @@ Vars::Vars() { scene33_ventsState[i] = 0; } - scene34_var01 = 0; - scene34_var02 = 0; - scene34_var03 = 0; - scene34_var04 = 0; scene34_cactus = 0; scene34_vent = 0; scene34_hatch = 0; scene34_boot = 0; - scene34_var05 = 0; - scene34_var06 = 0; - scene34_var07 = 0; - scene34_var08 = 0; + scene34_dudeClimbed = false; + scene34_dudeOnBoard = false; + scene34_dudeOnCactus = false; + scene34_fliesCountdown = 0; + + scene35_hose = 0; + scene35_bellyInflater = 0; + scene35_flowCounter = 0; + scene35_fliesCounter = 0; scene36_rotohrust = 0; scene36_scissors = 0; + scene37_rings.clear(); + scene37_lastDudeX = -1; + scene37_cursorIsLocked = 0; + scene37_plusMinus1 = 0; + scene37_plusMinus2 = 0; + scene37_plusMinus3 = 0; + scene37_soundFlipper = 0; + scene37_dudeX = 0; + + scene38_boss = 0; + scene38_tally = 0; + scene38_shorty = 0; + scene38_domino0 = 0; + scene38_dominos = 0; + scene38_domino1 = 0; + scene38_bottle = 0; + scene38_bossCounter = 0; + scene38_lastBossAnim = 0; + scene38_bossAnimCounter = 0; + scene38_tallyCounter = 0; + scene38_lastTallyAnim = 0; + scene38_tallyAnimCounter = 0; + scene38_shortyCounter = 0; + scene38_lastShortyAnim = 0; + scene38_shortyAnimCounter = 0; + + sceneFinal_var01 = 0; + sceneFinal_var02 = 0; + sceneFinal_var03 = 0; + selector = 0; } @@ -899,7 +930,6 @@ bool FullpipeEngine::sceneSwitcher(EntranceInfo *entrance) { _updateCursorCallback = scene33_updateCursor; break; -#if 0 case SC_34: sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_34"); scene->preloadMovements(sceneVar); @@ -908,7 +938,7 @@ bool FullpipeEngine::sceneSwitcher(EntranceInfo *entrance) { scene->initObjectCursors("SC_34"); setSceneMusicParameters(sceneVar); insertMessageHandler(sceneHandler34, 2, 2); - scene34_sub_42DEE0(); + scene34_initBeh(); _updateCursorCallback = scene34_updateCursor; break; @@ -922,7 +952,6 @@ bool FullpipeEngine::sceneSwitcher(EntranceInfo *entrance) { insertMessageHandler(sceneHandler35, 2, 2); _updateCursorCallback = defaultUpdateCursor; break; -#endif case SC_36: sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_36"); @@ -935,7 +964,6 @@ bool FullpipeEngine::sceneSwitcher(EntranceInfo *entrance) { _updateCursorCallback = scene36_updateCursor; break; -#if 0 case SC_37: sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_37"); scene->preloadMovements(sceneVar); @@ -961,14 +989,13 @@ bool FullpipeEngine::sceneSwitcher(EntranceInfo *entrance) { case SC_FINAL1: sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_FINAL1"); scene->preloadMovements(sceneVar); - sceneFinal1_initScene(); + sceneFinal_initScene(); _behaviorManager->initBehavior(scene, sceneVar); scene->initObjectCursors("SC_FINAL1"); setSceneMusicParameters(sceneVar); - addMessageHandler(sceneHandlerFinal1, 2); - _updateCursorCallback = sceneFinal1_updateCursor; + addMessageHandler(sceneHandlerFinal, 2); + _updateCursorCallback = sceneFinal_updateCursor; break; -#endif case SC_DBGMENU: sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_DBGMENU"); @@ -997,6 +1024,337 @@ void FullpipeEngine::processArcade(ExCommand *ex) { warning("STUB: FullpipeEngine::processArcade()"); } +void FullpipeEngine::updateMapPiece(int mapId, int update) { + for (int i = 0; i < 200; i++) { + int hiWord = (_mapTable[i] >> 16) & 0xffff; + + if (hiWord == mapId) { + _mapTable[i] |= update; + return; + } + if (!hiWord) { + _mapTable[i] = (mapId << 16) | update; + return; + } + } +} + +void FullpipeEngine::updateMap(PreloadItem *pre) { + switch (pre->sceneId) { + case SC_1: + updateMapPiece(PIC_MAP_S01, 1); + + if (pre->keyCode == TrubaUp) + updateMapPiece(PIC_MAP_P01, 1); + + if (pre->keyCode == TrubaLeft) + updateMapPiece(PIC_MAP_A13, 1); + break; + + case SC_2: + updateMapPiece(PIC_MAP_S02, 1); + + if (pre->keyCode == TrubaLeft) + updateMapPiece(PIC_MAP_P01, 1); + + break; + + case SC_3: + updateMapPiece(PIC_MAP_S03, 1); + break; + + case SC_4: + updateMapPiece(PIC_MAP_S04, 1); + + if (pre->keyCode == TrubaRight) + updateMapPiece(PIC_MAP_P04, 1); + + break; + + case SC_5: + updateMapPiece(PIC_MAP_S05, 1); + + if (pre->keyCode == TrubaLeft) { + updateMapPiece(PIC_MAP_P04, 1); + } + + if (pre->keyCode == TrubaUp) { + updateMapPiece(PIC_MAP_P05, 1); + updateMapPiece(PIC_MAP_A11, 1); + } + + break; + + case SC_6: + updateMapPiece(PIC_MAP_S06, 1); + + if (pre->keyCode == TrubaUp) + updateMapPiece(PIC_MAP_A12, 1); + + break; + + case SC_7: + updateMapPiece(PIC_MAP_S07, 1); + + if (pre->keyCode == TrubaLeft) + updateMapPiece(PIC_MAP_P18, 1); + + break; + + case SC_8: + updateMapPiece(PIC_MAP_S08, 1); + + if (pre->keyCode == TrubaUp) + updateMapPiece(PIC_MAP_P11, 1); + + if (pre->keyCode == TrubaRight) + updateMapPiece(PIC_MAP_P18, 1); + + return; + + case SC_9: + updateMapPiece(PIC_MAP_S09, 1); + + if (pre->keyCode == TrubaDown) + updateMapPiece(PIC_MAP_P11, 1); + + return; + + case SC_10: + updateMapPiece(PIC_MAP_S10, 1); + + if (pre->keyCode == TrubaRight) + updateMapPiece(PIC_MAP_P02, 1); + + break; + + case SC_11: + updateMapPiece(PIC_MAP_S11, 1); + + if (pre->keyCode == TrubaLeft) + updateMapPiece(PIC_MAP_P02, 1); + + break; + + case SC_12: + updateMapPiece(PIC_MAP_S12, 1); + break; + + case SC_13: + updateMapPiece(PIC_MAP_S13, 1); + + if (pre->keyCode == TrubaUp) { + updateMapPiece(PIC_MAP_P06, 1); + updateMapPiece(PIC_MAP_A10, 1); + } + break; + + case SC_14: + updateMapPiece(PIC_MAP_S14, 1); + break; + + case SC_15: + updateMapPiece(PIC_MAP_S15, 1); + + if (pre->keyCode == TrubaUp) { + updateMapPiece(PIC_MAP_P08, 1); + updateMapPiece(PIC_MAP_A14, 1); + } + + break; + + case SC_16: + updateMapPiece(PIC_MAP_S16, 1); + break; + + case SC_17: + updateMapPiece(PIC_MAP_S17, 1); + break; + + case SC_18: + updateMapPiece(PIC_MAP_S1819, 1); + + if (pre->keyCode == PIC_SC18_RTRUBA) + updateMapPiece(PIC_MAP_P14, 1); + + break; + + case SC_19: + updateMapPiece(PIC_MAP_S1819, 1); + + if (pre->keyCode == PIC_SC19_RTRUBA3) { + updateMapPiece(PIC_MAP_P15, 1); + updateMapPiece(PIC_MAP_A09, 1); + } + + break; + + case SC_20: + updateMapPiece(PIC_MAP_S20, 1); + break; + + case SC_21: + updateMapPiece(PIC_MAP_S21, 1); + + if (pre->keyCode == TrubaLeft) { + updateMapPiece(PIC_MAP_P15, 1); + updateMapPiece(PIC_MAP_A09, 1); + } + + if (pre->keyCode == TrubaDown) + updateMapPiece(PIC_MAP_A08, 1); + + break; + + case SC_22: + updateMapPiece(PIC_MAP_S22, 1); + break; + + case SC_23: + if (getObjectState("Верхний люк_23") == getObjectEnumState("Верхний люк_23", "Открыт")) { + updateMapPiece(PIC_MAP_S23_1, 0); + updateMapPiece(PIC_MAP_S23_2, 1); + updateMapPiece(PIC_MAP_P07, 1); + } else { + updateMapPiece(PIC_MAP_S23_1, 1); + updateMapPiece(PIC_MAP_S23_2, 0); + } + break; + + case SC_24: + updateMapPiece(PIC_MAP_S24, 1); + + if (pre->keyCode == TrubaUp) + updateMapPiece(PIC_MAP_A08, 1); + + if (pre->keyCode == TrubaDown) { + updateMapPiece(PIC_MAP_P13, 1); + updateMapPiece(PIC_MAP_A07, 1); + } + break; + + case SC_25: + updateMapPiece(PIC_MAP_S25, 1); + break; + + case SC_26: + updateMapPiece(PIC_MAP_S26, 1); + + if (pre->keyCode == TrubaLeft) + updateMapPiece(PIC_MAP_A06, 1); + + if (pre->keyCode == TrubaUp) { + updateMapPiece(PIC_MAP_P13, 1); + updateMapPiece(PIC_MAP_A07, 1); + } + + break; + + case SC_27: + updateMapPiece(PIC_MAP_S27, 1); + break; + + case SC_28: + updateMapPiece(PIC_MAP_S28, 1); + + if (pre->keyCode == TrubaRight) + updateMapPiece(PIC_MAP_A06, 1); + + break; + + case SC_29: + updateMapPiece(PIC_MAP_S29, 1); + + if (pre->keyCode == TrubaUp) + updateMapPiece(PIC_MAP_A05, 1); + + break; + + case SC_30: + updateMapPiece(PIC_MAP_S30, 1); + + if (pre->keyCode == TrubaLeft) + updateMapPiece(PIC_MAP_P09, 1); + + if (pre->keyCode == TrubaRight) + updateMapPiece(PIC_MAP_A04, 1); + + break; + + case SC_31: + updateMapPiece(PIC_MAP_S31_2, 1); + + if (getObjectState("Кактус") == getObjectEnumState("Кактус", "Вырос")) + updateMapPiece(PIC_MAP_S31_1, 1); + + if (pre->keyCode == TrubaRight) + updateMapPiece(PIC_MAP_P09, 1); + + break; + + case SC_32: + updateMapPiece(PIC_MAP_S32_2, 1); + + if (getObjectState("Кактус") == getObjectEnumState("Кактус", "Вырос")) + updateMapPiece(PIC_MAP_S32_1, 1); + + break; + + case SC_33: + updateMapPiece(PIC_MAP_S33, 1); + break; + + case SC_34: + updateMapPiece(PIC_MAP_S34, 1); + + if (pre->keyCode == TrubaUp) + updateMapPiece(PIC_MAP_A03, 1); + + break; + + case SC_35: + updateMapPiece(PIC_MAP_S35, 1); + + if (pre->keyCode == TrubaLeft) + updateMapPiece(PIC_MAP_A02, 1); + + if (pre->keyCode == TrubaDown) + updateMapPiece(PIC_MAP_A03, 1); + + break; + + case SC_36: + updateMapPiece(PIC_MAP_S36, 1); + break; + + case SC_37: + updateMapPiece(PIC_MAP_S37, 1); + updateMapPiece(PIC_MAP_A01, 1); + break; + + case SC_38: + updateMapPiece(PIC_MAP_S38, 1); + + switch (pre->preloadId1) { + case SC_15: + updateMapPiece(PIC_MAP_P16, 1); + break; + + case SC_1: + updateMapPiece(PIC_MAP_P10, 1); + break; + + case SC_10: + updateMapPiece(PIC_MAP_P17, 1); + break; + + case SC_19: + updateMapPiece(PIC_MAP_P12, 1); + break; + } + break; + } +} } // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes.h b/engines/fullpipe/scenes.h index 1348740036..5f77f74706 100644 --- a/engines/fullpipe/scenes.h +++ b/engines/fullpipe/scenes.h @@ -26,9 +26,10 @@ namespace Fullpipe { struct BehaviorEntryInfo; -class StaticANIObject; -class MctlLadder; class MGM; +class MctlLadder; +struct Ring; +class StaticANIObject; int defaultUpdateCursor(); @@ -156,10 +157,29 @@ void scene33_setupMusic(); int sceneHandler33(ExCommand *cmd); int scene33_updateCursor(); +void scene34_initScene(Scene *sc); +void scene34_initBeh(); +int sceneHandler34(ExCommand *cmd); +int scene34_updateCursor(); + +void scene35_initScene(Scene *sc); +int sceneHandler35(ExCommand *cmd); + int scene36_updateCursor(); void scene36_initScene(Scene *sc); int sceneHandler36(ExCommand *cmd); +void scene37_initScene(Scene *sc); +int sceneHandler37(ExCommand *ex); +int scene37_updateCursor(); + +void scene38_initScene(Scene *sc); +int sceneHandler38(ExCommand *ex); + +int sceneFinal_updateCursor(); +void sceneFinal_initScene(); +int sceneHandlerFinal(ExCommand *cmd); + void sceneDbgMenu_initScene(Scene *sc); int sceneHandlerDbgMenu(ExCommand *cmd); @@ -477,25 +497,67 @@ public: int scene33_ventsX[9]; int scene33_ventsState[9]; - int scene34_var01; - int scene34_var02; - int scene34_var03; - int scene34_var04; StaticANIObject *scene34_cactus; StaticANIObject *scene34_vent; StaticANIObject *scene34_hatch; StaticANIObject *scene34_boot; - int scene34_var05; - int scene34_var06; - int scene34_var07; - int scene34_var08; + bool scene34_dudeClimbed; + bool scene34_dudeOnBoard; + bool scene34_dudeOnCactus; + int scene34_fliesCountdown; + + StaticANIObject *scene35_hose; + StaticANIObject *scene35_bellyInflater; + int scene35_flowCounter; + int scene35_fliesCounter; StaticANIObject *scene36_rotohrust; StaticANIObject *scene36_scissors; + Common::Array<Ring *> scene37_rings; + int scene37_lastDudeX; + bool scene37_cursorIsLocked; + StaticANIObject *scene37_plusMinus1; + StaticANIObject *scene37_plusMinus2; + StaticANIObject *scene37_plusMinus3; + int scene37_soundFlipper; + int scene37_dudeX; + + StaticANIObject *scene38_boss; + StaticANIObject *scene38_tally; + StaticANIObject *scene38_shorty; + StaticANIObject *scene38_domino0; + StaticANIObject *scene38_dominos; + StaticANIObject *scene38_domino1; + StaticANIObject *scene38_bottle; + int scene38_bossCounter; + int scene38_lastBossAnim; + int scene38_bossAnimCounter; + int scene38_tallyCounter; + int scene38_lastTallyAnim; + int scene38_tallyAnimCounter; + int scene38_shortyCounter; + int scene38_lastShortyAnim; + int scene38_shortyAnimCounter; + + int sceneFinal_var01; + int sceneFinal_var02; + int sceneFinal_var03; + PictureObject *selector; }; +struct Ring { + StaticANIObject *ani; + int x; + int y; + int numSubRings; + int subRings[10]; + bool state; + + Ring(); +}; + } // End of namespace Fullpipe #endif /* FULLPIPE_SCENES_H */ diff --git a/engines/fullpipe/scenes/scene03.cpp b/engines/fullpipe/scenes/scene03.cpp index 40e70e2ea5..9ba84a540a 100644 --- a/engines/fullpipe/scenes/scene03.cpp +++ b/engines/fullpipe/scenes/scene03.cpp @@ -59,7 +59,7 @@ void scene03_initScene(Scene *sc) { g_fp->lift_setButton(sO_Level2, ST_LBN_2N); - g_fp->lift_sub5(sc, QU_SC3_ENTERLIFT, QU_SC3_EXITLIFT); + g_fp->lift_init(sc, QU_SC3_ENTERLIFT, QU_SC3_EXITLIFT); } void scene03_setEaterState() { @@ -215,7 +215,7 @@ int sceneHandler03(ExCommand *ex) { break; case MSG_LIFT_CLICKBUTTON: - g_fp->lift_animation3(); + g_fp->lift_clickButton(); break; case MSG_SC3_HIDEDOMINO: diff --git a/engines/fullpipe/scenes/scene06.cpp b/engines/fullpipe/scenes/scene06.cpp index c352d27dd6..7d637d8306 100644 --- a/engines/fullpipe/scenes/scene06.cpp +++ b/engines/fullpipe/scenes/scene06.cpp @@ -531,7 +531,7 @@ void scene06_initScene(Scene *sc) { g_vars->scene06_mumsy->hide(); g_fp->lift_setButton(sO_Level3, ST_LBN_3N); - g_fp->lift_sub5(sc, QU_SC6_ENTERLIFT, QU_SC6_EXITLIFT); + g_fp->lift_init(sc, QU_SC6_ENTERLIFT, QU_SC6_EXITLIFT); g_fp->initArcadeKeys("SC_6"); sceneHandler06_setExits(sc); @@ -590,7 +590,7 @@ int sceneHandler06(ExCommand *ex) { break; case MSG_LIFT_CLICKBUTTON: - g_fp->lift_animation3(); + g_fp->lift_clickButton(); break; case MSG_SPINHANDLE: diff --git a/engines/fullpipe/scenes/scene10.cpp b/engines/fullpipe/scenes/scene10.cpp index f8d16b2759..9c00902bba 100644 --- a/engines/fullpipe/scenes/scene10.cpp +++ b/engines/fullpipe/scenes/scene10.cpp @@ -43,7 +43,7 @@ void scene10_initScene(Scene *sc) { g_vars->scene10_ladder = sc->getPictureObjectById(PIC_SC10_LADDER, 0); g_fp->lift_setButton(sO_Level1, ST_LBN_1N); - g_fp->lift_sub5(sc, QU_SC10_ENTERLIFT, QU_SC10_EXITLIFT); + g_fp->lift_init(sc, QU_SC10_ENTERLIFT, QU_SC10_EXITLIFT); if (g_fp->getObjectState(sO_Inflater) == g_fp->getObjectEnumState(sO_Inflater, sO_WithGum)) { g_vars->scene10_hasGum = 1; @@ -140,7 +140,7 @@ int sceneHandler10(ExCommand *ex) { break; case MSG_LIFT_CLICKBUTTON: - g_fp->lift_animation3(); + g_fp->lift_clickButton(); break; case MSG_SC10_LADDERTOBACK: diff --git a/engines/fullpipe/scenes/scene14.cpp b/engines/fullpipe/scenes/scene14.cpp index 4a09bc9cb6..ab0487974a 100644 --- a/engines/fullpipe/scenes/scene14.cpp +++ b/engines/fullpipe/scenes/scene14.cpp @@ -72,7 +72,7 @@ void scene14_initScene(Scene *sc) { } g_fp->lift_setButton(sO_Level4, ST_LBN_4N); - g_fp->lift_sub5(sc, QU_SC14_ENTERLIFT, QU_SC14_EXITLIFT); + g_fp->lift_init(sc, QU_SC14_ENTERLIFT, QU_SC14_EXITLIFT); g_fp->initArcadeKeys("SC_14"); g_fp->setArcadeOverlay(PIC_CSR_ARCADE6); @@ -665,7 +665,7 @@ int sceneHandler14(ExCommand *cmd) { break; case MSG_LIFT_CLICKBUTTON: - g_fp->lift_animation3(); + g_fp->lift_clickButton(); break; case MSG_SC14_SHOWBALLGMAHIT: diff --git a/engines/fullpipe/scenes/scene15.cpp b/engines/fullpipe/scenes/scene15.cpp index fa8db64497..155897619f 100644 --- a/engines/fullpipe/scenes/scene15.cpp +++ b/engines/fullpipe/scenes/scene15.cpp @@ -74,7 +74,7 @@ void scene15_initScene(Scene *sc) { g_vars->scene15_plusminus = sc->getStaticANIObject1ById(ANI_PLUSMINUS, -1); - if (g_fp->getObjectState(sO_Gurad_2) == g_fp->getObjectEnumState(sO_Gurad_2, sO_Off)) + if (g_fp->getObjectState(sO_Guard_2) == g_fp->getObjectEnumState(sO_Guard_2, sO_Off)) g_vars->scene15_plusminus->_statics = g_vars->scene15_plusminus->getStaticsById(ST_PMS_MINUS); else g_vars->scene15_plusminus->_statics = g_vars->scene15_plusminus->getStaticsById(ST_PMS_PLUS); @@ -88,7 +88,7 @@ void scene15_initScene(Scene *sc) { g_fp->_currentScene = oldsc; g_fp->lift_setButton(sO_Level5, ST_LBN_5N); - g_fp->lift_sub5(sc, QU_SC15_ENTERLIFT, QU_SC15_EXITLIFT); + g_fp->lift_init(sc, QU_SC15_ENTERLIFT, QU_SC15_EXITLIFT); } int scene15_updateCursor() { @@ -144,7 +144,7 @@ int sceneHandler15(ExCommand *cmd) { break; case MSG_LIFT_CLICKBUTTON: - g_fp->lift_animation3(); + g_fp->lift_clickButton(); break; case MSG_SC15_PULL: diff --git a/engines/fullpipe/scenes/scene30.cpp b/engines/fullpipe/scenes/scene30.cpp index 59cb83efcd..a807e692a7 100644 --- a/engines/fullpipe/scenes/scene30.cpp +++ b/engines/fullpipe/scenes/scene30.cpp @@ -73,7 +73,7 @@ void scene30_initScene(Scene *sc, int flag) { g_fp->lift_setButton(sO_Level8, ST_LBN_8N); - g_fp->lift_sub5(sc, QU_SC30_ENTERLIFT, QU_SC30_EXITLIFT); + g_fp->lift_init(sc, QU_SC30_ENTERLIFT, QU_SC30_EXITLIFT); } int scene30_updateCursor() { @@ -103,7 +103,7 @@ int sceneHandler30(ExCommand *cmd) { break; case MSG_LIFT_CLICKBUTTON: - g_fp->lift_animation3(); + g_fp->lift_clickButton(); break; case MSG_SC30_UPDATEPATH: diff --git a/engines/fullpipe/scenes/scene32.cpp b/engines/fullpipe/scenes/scene32.cpp index c93e888e51..597d3422f6 100644 --- a/engines/fullpipe/scenes/scene32.cpp +++ b/engines/fullpipe/scenes/scene32.cpp @@ -88,7 +88,7 @@ void scene32_initScene(Scene *sc) { } g_fp->lift_setButton(sO_Level9, ST_LBN_9N); - g_fp->lift_sub5(sc, QU_SC32_ENTERLIFT, QU_SC32_EXITLIFT); + g_fp->lift_init(sc, QU_SC32_ENTERLIFT, QU_SC32_EXITLIFT); g_fp->initArcadeKeys("SC_32"); } @@ -291,7 +291,7 @@ int sceneHandler32(ExCommand *cmd) { break; case MSG_LIFT_CLICKBUTTON: - g_fp->lift_animation3(); + g_fp->lift_clickButton(); break; case MSG_SC33_TRYKUBIK: diff --git a/engines/fullpipe/scenes/scene34.cpp b/engines/fullpipe/scenes/scene34.cpp index 0882c0f9e8..b3e0db75af 100644 --- a/engines/fullpipe/scenes/scene34.cpp +++ b/engines/fullpipe/scenes/scene34.cpp @@ -37,14 +37,28 @@ namespace Fullpipe { void sceneHandler34_setExits() { - warning("STUB: sceneHandler34_setExits()"); + int state; + + if (g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_NearPipeWithStool)) { + if (g_fp->getObjectState(sO_Hatch_34) == g_fp->getObjectEnumState(sO_Hatch_34, sO_Closed)) + state = g_fp->getObjectEnumState(sO_Plank_34, sO_ClosedWithBoot); + else + state = g_fp->getObjectEnumState(sO_Plank_34, sO_OpenedWithBoot); + } else { + if (g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_OnStool)) { + if (g_fp->getObjectState(sO_Hatch_34) == g_fp->getObjectEnumState(sO_Hatch_34, sO_Closed)) + state = g_fp->getObjectEnumState(sO_Plank_34, sO_IsClosed); + else + state = g_fp->getObjectEnumState(sO_Plank_34, sO_IsOpened); + } else { + state = g_fp->getObjectEnumState(sO_Plank_34, sO_Passive); + } + } + + g_fp->setObjectState(sO_Plank_34, state); } void scene34_initScene(Scene *sc) { - g_vars->scene34_var01 = 200; - g_vars->scene34_var02 = 200; - g_vars->scene34_var03 = 300; - g_vars->scene34_var04 = 300; g_vars->scene34_cactus = sc->getStaticANIObject1ById(ANI_CACTUS_34, -1); g_vars->scene34_vent = sc->getStaticANIObject1ById(ANI_VENT_34, -1); g_vars->scene34_hatch = sc->getStaticANIObject1ById(ANI_LUK_34, -1); @@ -70,15 +84,15 @@ void scene34_initScene(Scene *sc) { sceneHandler34_setExits(); - g_vars->scene34_var05 = 0; - g_vars->scene34_var06 = 0; - g_vars->scene34_var07 = 0; - g_vars->scene34_var08 = g_fp->_rnd->getRandomNumber(500) + 500; + g_vars->scene34_dudeClimbed = false; + g_vars->scene34_dudeOnBoard = false; + g_vars->scene34_dudeOnCactus = false; + g_vars->scene34_fliesCountdown = g_fp->_rnd->getRandomNumber(500) + 500; g_fp->_floaters->init(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_34")); g_fp->lift_setButton(sO_Level7, ST_LBN_7N); - g_fp->lift_sub5(sc, QU_SC34_ENTERLIFT, QU_SC34_EXITLIFT); + g_fp->lift_init(sc, QU_SC34_ENTERLIFT, QU_SC34_EXITLIFT); g_fp->initArcadeKeys("SC_34"); } @@ -89,17 +103,377 @@ void scene34_initBeh() { } int scene34_updateCursor() { -#if 0 g_fp->updateCursorCommon(); - if ((g_fp->_objectIdAtCursor != ANI_STOOL_34 || g_fp->getGameLoaderInventory()->getSelectedItemId() != ANI_INV_BOX) - && (g_fp->_objectIdAtCursor != ANI_BOX_34 || g_fp->getGameLoaderInventory()->getSelectedItemId() != ANI_INV_STOOL)) + if ((g_fp->_objectIdAtCursor != ANI_STOOL_34 || getGameLoaderInventory()->getSelectedItemId() != ANI_INV_BOX) + && (g_fp->_objectIdAtCursor != ANI_BOX_34 || getGameLoaderInventory()->getSelectedItemId() != ANI_INV_STOOL)) ; // emtpy else g_fp->_cursorId = PIC_CSR_ITN_INV; -#endif return g_fp->_cursorId; } +void sceneHandler34_leaveBoard() { + getCurrSceneSc2MotionController()->setEnabled(); + getGameLoaderInteractionController()->enableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1); + + g_vars->scene34_dudeOnBoard = false; +} + +void sceneHandler34_onBoard() { + getCurrSceneSc2MotionController()->clearEnabled(); + getGameLoaderInteractionController()->disableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0); + + g_vars->scene34_dudeOnBoard = true; +} + +void sceneHandler34_testVent() { + if (g_fp->_aniMan->_movement->_id == MV_MAN34_TURNVENT_R) { + g_vars->scene34_hatch->changeStatics2(ST_LUK34_CLOSED); + + chainQueue(QU_LUK34_OPEN, 0); + } else if (g_fp->_aniMan->_movement->_id == MV_MAN34_TURNVENT_L) { + g_vars->scene34_hatch->changeStatics2(ST_LUK34_OPEN); + + chainQueue(QU_LUK34_CLOSE, 0); + } +} + +void sceneHandler34_hideStool() { + g_fp->_currentScene->getStaticANIObject1ById(ANI_STOOL_34, -1)->hide(); +} + +void sceneHandler34_climb() { + getCurrSceneSc2MotionController()->clearEnabled(); + getGameLoaderInteractionController()->disableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0); + + g_vars->scene34_dudeClimbed = true; +} + +void sceneHandler34_genFlies() { + g_fp->_floaters->genFlies(g_fp->_currentScene, 1072, -50, 100, 4); + + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->countdown = 1; + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->val6 = 1072; + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->val7 = -50; + + g_vars->scene34_fliesCountdown = g_fp->_rnd->getRandomNumber(500) + 500; +} + +void sceneHandler34_fromCactus(ExCommand *cmd) { + if (g_fp->_aniMan->_movement || g_vars->scene34_cactus->_movement || (g_fp->_aniMan->_flags & 0x100)) { + cmd->_messageKind = 0; + + return; + } + + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC34_FROMCACTUS), 0, 0); + + ExCommand *ex = new ExCommand(ANI_MAN, 34, 256, 0, 0, 0, 1, 0, 0, 0); + + ex->_messageNum = 0; + ex->_excFlags |= 3; + ex->_field_14 = 256; + mq->addExCommandToEnd(ex); + + ex = cmd->createClone(); + mq->addExCommandToEnd(ex); + + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + + g_fp->_aniMan->_flags |= 1; +} + +void sceneHandler34_animateLeaveBoard(ExCommand *cmd) { + if (!g_fp->_aniMan->_movement) { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC34_LEAVEBOARD), 0, 0); + + mq->addExCommandToEnd(cmd->createClone()); + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + } + + cmd->_messageKind = 0; +} + +void sceneHandler34_animateAction(ExCommand *cmd) { + if (g_fp->_aniMan->_movement) + return; + + int ox = g_fp->_aniMan->_ox; + int oy = g_fp->_aniMan->_oy; + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(g_fp->_sceneRect.left + cmd->_x, g_fp->_sceneRect.top + cmd->_y); + + if (!ani || ani->_id != ANI_VENT_34) { + int qId = 0; + + if (ox == 887) { + if (oy != 370) + return; + + qId = QU_SC34_FROMSTOOL; + } else { + if (ox != 916) + return; + + if (oy == 286) { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC34_FROMBOX), 0, 0); + + mq->addExCommandToEnd(cmd->createClone()); + mq->chain(0); + + sceneHandler34_setExits(); + + return; + } + + if (oy != 345) + return; + + qId = QU_SC34_FROMBOX_FLOOR; + } + + if (qId) { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(qId), 0, 0); + + mq->addExCommandToEnd(cmd->createClone()); + mq->chain(0); + } + + return; + } + + if (ox == 887) { + if (oy == 370) + g_fp->_aniMan->startAnim(MV_MAN34_TRYTABUR, 0, -1); + + } else if (ox == 916) { + if (oy == 286) { + int id = g_vars->scene34_vent->_statics->_staticsId; + if (id == ST_VNT34_UP2) { + g_fp->_aniMan->startAnim(MV_MAN34_TURNVENT_R, 0, -1); + } else if (id == ST_VNT34_RIGHT3) { + g_fp->_aniMan->startAnim(MV_MAN34_TURNVENT_L, 0, -1); + } + } else if (oy == 345) { + g_fp->_aniMan->startAnim(MV_MAN34_TRY, 0, -1); + } + } +} + +void sceneHandler34_showVent() { + if (g_vars->scene34_vent->_statics->_staticsId == ST_VNT34_UP2) + g_vars->scene34_vent->changeStatics2(ST_VNT34_RIGHT3); + else if (g_vars->scene34_vent->_statics->_staticsId == ST_VNT34_RIGHT3) + g_vars->scene34_vent->changeStatics2(ST_VNT34_UP2); + + g_vars->scene34_vent->show1(-1, -1, -1, 0); +} + +void sceneHandler34_showBox() { + g_fp->_currentScene->getStaticANIObject1ById(ANI_STOOL_34, -1)->changeStatics2(ST_STL34_BOX2); +} + +void sceneHandler34_showStool() { + chainQueue(QU_SC34_SHOWSTOOL, 0); +} + +void sceneHandler34_unclimb() { + getCurrSceneSc2MotionController()->setEnabled(); + getGameLoaderInteractionController()->enableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1); + + g_vars->scene34_dudeClimbed = false; +} + +int sceneHandler34(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_SC4_HIDEBOOT: + g_vars->scene34_boot->_flags &= 0xFFFB; + break; + + case MSG_SC34_LEAVEBOARD: + sceneHandler34_leaveBoard(); + break; + + case MSG_SC34_ONBOARD: + sceneHandler34_onBoard(); + break; + + case MSG_SC34_TESTVENT: + sceneHandler34_testVent(); + break; + + case MSG_LIFT_CLICKBUTTON: + g_fp->lift_clickButton(); + break; + + case MSG_SC34_FROMCACTUS: + g_vars->scene34_dudeOnCactus = false; + + getCurrSceneSc2MotionController()->setEnabled(); + getGameLoaderInteractionController()->enableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1); + + break; + + case MSG_SC34_RETRYVENT: + if (!g_fp->_aniMan->isIdle()) + break; + + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT); + g_fp->_aniMan->_flags &= 0xFEFF; + + getGameLoaderInteractionController()->handleInteraction(g_fp->_aniMan, g_vars->scene34_vent, cmd->_keyCode); + + break; + + case MSG_SC34_ONBUMP: + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene34_cactus, ST_CTS34_GROWNEMPTY2, QU_CTS34_FALLEFT, 1); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene34_cactus, ST_CTS34_GROWNEMPTY2, QU_CTS34_FALLRIGHT, 1); + break; + + case MSG_LIFT_CLOSEDOOR: + g_fp->lift_closedoorSeq(); + break; + + case MSG_LIFT_EXITLIFT: + g_fp->lift_exitSeq(cmd); + break; + + case MSG_LIFT_STARTEXITQUEUE: + g_fp->lift_startExitQueue(); + break; + + case MSG_SC22_HIDESTOOL: + sceneHandler34_hideStool(); + break; + + case MSG_SC34_CLIMB: + sceneHandler34_climb(); + break; + + case MSG_SC34_UNCLIMB: + sceneHandler34_unclimb(); + break; + + case MSG_SC22_SHOWSTOOL: + sceneHandler34_showStool(); + break; + + case MSG_SC34_SHOWBOX: + sceneHandler34_showBox(); + break; + + case MSG_SC34_ONCACTUS: + g_vars->scene34_dudeOnCactus = true; + + getCurrSceneSc2MotionController()->clearEnabled(); + getGameLoaderInteractionController()->disableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0); + break; + + case MSG_SC34_SHOWVENT: + sceneHandler34_showVent(); + break; + + case 64: + g_fp->lift_sub05(cmd); + break; + + case MSG_LIFT_GO: + g_fp->lift_goAnimation(); + break; + + case 29: + { + if (g_vars->scene34_dudeClimbed) { + sceneHandler34_animateAction(cmd); + break; + } + + if (g_vars->scene34_dudeOnBoard) { + sceneHandler34_animateLeaveBoard(cmd); + break; + } + + if (g_vars->scene34_dudeOnCactus) { + sceneHandler34_fromCactus(cmd); + break; + } + + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(g_fp->_sceneRect.left + cmd->_x, g_fp->_sceneRect.top + cmd->_y); + + if (ani) { + if ((ani->_id == ANI_STOOL_34 && cmd->_keyCode == ANI_INV_BOX) || (ani->_id == ANI_BOX_34 && cmd->_keyCode == ANI_INV_STOOL)) { + getGameLoaderInteractionController()->handleInteraction(g_fp->_aniMan, g_vars->scene34_vent, cmd->_keyCode); + + cmd->_messageKind = 0; + } + + if (ani->_id == ANI_LIFTBUTTON) { + g_fp->lift_sub1(ani); + + cmd->_messageKind = 0; + + break; + } + } + + if (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_keyCode)) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_keyCode)) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) { + g_fp->processArcade(cmd); + break; + } + } + } + break; + } + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + --g_vars->scene34_fliesCountdown; + + if (!g_vars->scene34_fliesCountdown) + sceneHandler34_genFlies(); + + g_fp->_floaters->update(); + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + } // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene35.cpp b/engines/fullpipe/scenes/scene35.cpp new file mode 100644 index 0000000000..f10786b821 --- /dev/null +++ b/engines/fullpipe/scenes/scene35.cpp @@ -0,0 +1,264 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + +#include "fullpipe/floaters.h" + +namespace Fullpipe { + +void scene35_initScene(Scene *sc) { + g_vars->scene35_hose = sc->getStaticANIObject1ById(ANI_HOSE, -1); + g_vars->scene35_bellyInflater = sc->getStaticANIObject1ById(ANI_PUZODUV, -1); + g_vars->scene35_flowCounter = 0; + g_vars->scene35_fliesCounter = 0; + + MovGraphLink *lnk = getSc2MctlCompoundBySceneId(sc->_sceneId)->getLinkByName(sO_CloseThing); + + if (g_vars->scene35_bellyInflater->_statics->_staticsId == ST_PDV_LARGE) + lnk->_flags |= 0x20000000; + else + lnk->_flags &= 0xDFFFFFFF; + + int sndId = 0; + + if (g_fp->getObjectState(sO_Valve_35) == g_fp->getObjectEnumState(sO_Valve_35, sO_TurnedOn)) { + if ((g_vars->scene35_hose->_flags & 4) && g_vars->scene35_hose->_statics->_staticsId == ST_HZE_NORM) { + sndId = SND_35_012; + } else if (g_vars->scene35_bellyInflater->_statics->_staticsId == ST_PDV_SMALL) { + sndId = SND_35_011; + } + } + + if (sndId) + g_fp->playSound(sndId, 1); + + g_fp->lift_setButton(sO_Level6, ST_LBN_6N); + g_fp->lift_init(sc, QU_SC35_ENTERLIFT, QU_SC35_EXITLIFT); + + g_fp->initArcadeKeys("SC_35"); + + g_fp->_floaters->init(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_35")); +} + +void sceneHandler35_stopFlow() { + g_fp->setObjectState(sO_Valve_35, g_fp->getObjectEnumState(sO_Valve_35, sO_TurnedOff)); + g_fp->stopAllSoundInstances(SND_35_011); + g_fp->playSound(SND_35_026, 0); +} + +void sceneHandler35_shrink() { + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing, 0); +} + +void sceneHandler35_startFlow() { + if (g_fp->getObjectState(sO_Valve_35) == g_fp->getObjectEnumState(sO_Valve_35, sO_TurnedOn)) { + if ((g_vars->scene35_hose->_flags & 4) && g_vars->scene35_hose->_statics->_staticsId == ST_HZE_NORM) { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene35_bellyInflater, ST_PDV_SMALL, QU_PDV_SML_BLINK, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene35_bellyInflater, ST_PDV_SMALL, QU_PDV_SML_TRY, 0); + + g_vars->scene35_bellyInflater->changeStatics2(ST_PDV_SMALL); + g_vars->scene35_bellyInflater->_flags &= 0xFEFF; + + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC35_EATHOZE), 0, 0); + + mq->setFlags(mq->getFlags() | 1); + + ExCommand *cmd = new ExCommand(g_vars->scene35_bellyInflater->_id, 34, 256, 0, 0, 0, 1, 0, 0, 0); + + cmd->_excFlags |= 3; + cmd->_field_14 = 256; + cmd->_messageNum = 0; + + mq->addExCommandToEnd(cmd); + + if (!mq->chain(g_vars->scene35_bellyInflater)) + delete mq; + + g_vars->scene35_bellyInflater->_flags |= 1; + + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing, 1); + + g_fp->playSound(SND_35_012, 1); + } else { + if (!g_vars->scene35_flowCounter) + g_vars->scene35_flowCounter = 98; + + g_fp->playSound(SND_35_011, 1); + } + } +} + +void sceneHandler35_genFlies() { + StaticANIObject *fly = g_fp->_currentScene->getStaticANIObject1ById(ANI_FLY, -1); + + int xoff = 0; + if ((!fly || !(fly->_flags & 4)) && !(g_fp->_rnd->getRandomNumber(32767) % 30)) { + int x, y; + + if (g_fp->_rnd->getRandomNumber(1)) { + x = 600; + y = 0; + } else { + x = 0; + y = 600; + } + + int numFlies = g_fp->_rnd->getRandomNumber(3) + 1; + + while (numFlies--) { + g_fp->_floaters->genFlies(g_fp->_currentScene, g_fp->_rnd->getRandomNumber(55) + 1057, g_fp->_rnd->getRandomNumber(60) + x + xoff, 4, 1); + + xoff += 40; + + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->val2 = 1084; + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->val3 = y; + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->val11 = 8.0; + } + + g_vars->scene35_fliesCounter = 0; + } +} + +int sceneHandler35(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_LIFT_CLOSEDOOR: + g_fp->lift_closedoorSeq(); + break; + + case MSG_LIFT_EXITLIFT: + g_fp->lift_exitSeq(cmd); + break; + + case MSG_LIFT_STARTEXITQUEUE: + g_fp->lift_startExitQueue(); + break; + + case MSG_LIFT_CLICKBUTTON: + g_fp->lift_clickButton(); + break; + + case MSG_SC35_STOPFLOW: + sceneHandler35_stopFlow(); + break; + + case MSG_SC35_CHECKPIPESOUND: + if (g_fp->getObjectState(sO_Valve_35) == g_fp->getObjectEnumState(sO_Valve_35, sO_TurnedOn)) { + g_fp->stopAllSoundInstances(SND_35_011); + g_fp->playSound(SND_35_012, 1); + + g_vars->scene35_flowCounter = 0; + break; + } + break; + + case MSG_SC35_SHRINK: + sceneHandler35_shrink(); + break; + + case MSG_LIFT_GO: + g_fp->lift_goAnimation(); + break; + + case MSG_SC35_STARTFLOW: + case MSG_SC35_PLUGHOSE: + sceneHandler35_startFlow(); + break; + + case 64: + g_fp->lift_sub05(cmd); + break; + + case 29: + { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(g_fp->_sceneRect.left + cmd->_x, g_fp->_sceneRect.top + cmd->_y); + + if (ani) + if (ani->_id == ANI_LIFTBUTTON) { + g_fp->lift_sub1(ani); + cmd->_messageKind = 0; + break; + } + + if (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_keyCode)) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_keyCode)) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) { + g_fp->processArcade(cmd); + break; + } + } + } + break; + } + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + if (g_vars->scene35_flowCounter > 0) { + --g_vars->scene35_flowCounter; + + if (!g_vars->scene35_flowCounter) + sceneHandler35_stopFlow(); + } + + g_vars->scene35_fliesCounter++; + + if (g_vars->scene35_fliesCounter >= 160) + sceneHandler35_genFlies(); + + g_fp->_floaters->update(); + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene37.cpp b/engines/fullpipe/scenes/scene37.cpp new file mode 100644 index 0000000000..8324e00af7 --- /dev/null +++ b/engines/fullpipe/scenes/scene37.cpp @@ -0,0 +1,316 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +Ring::Ring() { + ani = 0; + x = 0; + y = 0; + numSubRings = 0; + + for (int i = 0; i < 10; i++) + subRings[i] = 0; + + state = false; +} + +void scene37_initScene(Scene *sc) { + Ring *ring; + StaticANIObject *ani; + + g_vars->scene37_lastDudeX = -1; + + ring = new Ring(); + ani = sc->getStaticANIObject1ById(ANI_GUARD_37, 0); + ring->ani = ani; + ring->x = ani->_ox - 40; + ring->y = ani->_ox + 40; + ring->numSubRings = 3; + ring->subRings[0] = 1; + ring->subRings[1] = 4; + ring->subRings[2] = 8; + ring->state = false; + g_vars->scene37_rings.push_back(ring); + + ring = new Ring(); + ani = sc->getStaticANIObject1ById(ANI_GUARD_37, 1); + ring->ani = ani; + ring->x = ani->_ox - 40; + ring->y = ani->_ox + 40; + ring->numSubRings = 3; + ring->subRings[0] = 2; + ring->subRings[1] = 5; + ring->subRings[2] = 9; + ring->state = false; + g_vars->scene37_rings.push_back(ring); + + ring = new Ring(); + ani = sc->getStaticANIObject1ById(ANI_GUARD_37, 2); + ring->ani = ani; + ring->x = ani->_ox - 40; + ring->y = ani->_ox + 40; + ring->numSubRings = 3; + ring->subRings[0] = 3; + ring->subRings[1] = 7; + ring->subRings[2] = 11; + ring->state = false; + g_vars->scene37_rings.push_back(ring); + + g_fp->setObjectState(sO_LeftPipe_37, g_fp->getObjectEnumState(sO_LeftPipe_37, sO_IsClosed)); + + Scene *oldsc = g_fp->_currentScene; + + g_fp->_currentScene = sc; + + g_vars->scene37_cursorIsLocked = false; + + g_vars->scene37_plusMinus1 = sc->getStaticANIObject1ById(ANI_PLUSMINUS, 1); + + for (int i = 0; i < g_vars->scene37_rings[0]->numSubRings; i++) { + ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_RING, g_vars->scene37_rings[0]->subRings[i]); + + if (g_fp->getObjectState(sO_Guard_1) == g_fp->getObjectEnumState(sO_Guard_1, sO_On)) { + g_vars->scene37_plusMinus1->_statics = g_vars->scene37_plusMinus1->getStaticsById(ST_PMS_PLUS); + ani->changeStatics2(ST_RNG_OPEN); + } else { + g_vars->scene37_plusMinus1->_statics = g_vars->scene37_plusMinus1->getStaticsById(ST_PMS_MINUS); + ani->changeStatics2(ST_RNG_CLOSED2); + } + } + + g_vars->scene37_plusMinus2 = sc->getStaticANIObject1ById(ANI_PLUSMINUS, 2); + + for (int i = 0; i < g_vars->scene37_rings[1]->numSubRings; i++) { + ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_RING, g_vars->scene37_rings[1]->subRings[i]); + + if (g_fp->getObjectState(sO_Guard_2) == g_fp->getObjectEnumState(sO_Guard_2, sO_On)) { + g_vars->scene37_plusMinus2->_statics = g_vars->scene37_plusMinus2->getStaticsById(ST_PMS_PLUS); + ani->changeStatics2(ST_RNG_OPEN); + } else { + g_vars->scene37_plusMinus2->_statics = g_vars->scene37_plusMinus2->getStaticsById(ST_PMS_MINUS); + ani->changeStatics2(ST_RNG_CLOSED2); + } + } + + g_vars->scene37_plusMinus3 = sc->getStaticANIObject1ById(ANI_PLUSMINUS, 3); + + for (int i = 0; i < g_vars->scene37_rings[2]->numSubRings; i++) { + ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_RING, g_vars->scene37_rings[2]->subRings[i]); + + if (g_fp->getObjectState(sO_Guard_3) == g_fp->getObjectEnumState(sO_Guard_3, sO_On)) { + g_vars->scene37_plusMinus3->_statics = g_vars->scene37_plusMinus3->getStaticsById(ST_PMS_PLUS); + ani->changeStatics2(ST_RNG_OPEN); + } else { + g_vars->scene37_plusMinus3->_statics = g_vars->scene37_plusMinus3->getStaticsById(ST_PMS_MINUS); + ani->changeStatics2(ST_RNG_CLOSED2); + } + } + + g_fp->_currentScene = oldsc; + + g_fp->initArcadeKeys("SC_37"); +} + +int scene37_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_cursorId == PIC_CSR_ITN && g_fp->_objectIdAtCursor == PIC_SC37_MASK) { + if (g_vars->scene37_cursorIsLocked) + g_fp->_cursorId = PIC_CSR_GOL; + } + + return g_fp->_cursorId; +} + +void sceneHandler37_updateRing(int ringNum) { + g_vars->scene37_rings[ringNum]->ani->changeStatics2(ST_GRD37_STAND); + g_vars->scene37_rings[ringNum]->ani->startAnim(MV_GRD37_PULL, 0, -1); + g_vars->scene37_rings[ringNum]->state = !g_vars->scene37_rings[ringNum]->state; + + StaticANIObject *ani; + + for (int i = 0; i < g_vars->scene37_rings[ringNum]->numSubRings; i++) { + ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_RING, g_vars->scene37_rings[ringNum]->subRings[i]); + + if ((ani->_movement && ani->_movement->_id != MV_RNG_CLOSE) || ani->_statics->_staticsId != ST_RNG_CLOSED2) { + ani->changeStatics2(ST_RNG_OPEN); + ani->startAnim(MV_RNG_CLOSE, 0, -1); + } else { + ani->changeStatics2(ST_RNG_CLOSED2); + ani->startAnim(MV_RNG_OPEN, 0, -1); + } + } + + g_vars->scene37_cursorIsLocked = true; + + for (uint j = 0; j < g_vars->scene37_rings.size(); j++) { + for (int i = 0; i < g_vars->scene37_rings[ringNum]->numSubRings; i++) { + ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_RING, g_vars->scene37_rings[j]->subRings[i]); + + if ((ani->_movement && ani->_movement->_id != MV_RNG_CLOSE) || ani->_statics->_staticsId != ST_RNG_CLOSED2) + g_vars->scene37_cursorIsLocked = false; + } + } + + int state; + + if (g_vars->scene37_cursorIsLocked) + state = g_fp->getObjectEnumState(sO_LeftPipe_37, sO_IsOpened); + else + state = g_fp->getObjectEnumState(sO_LeftPipe_37, sO_IsClosed); + + g_fp->setObjectState(sO_LeftPipe_37, state); +} + +void sceneHandler37_setRingsState() { + if (g_vars->scene37_lastDudeX == -1) { + g_vars->scene37_lastDudeX = g_vars->scene37_dudeX; + } else { + for (uint i = 0; i < g_vars->scene37_rings.size(); i++) { + int x = g_vars->scene37_rings[i]->x; + + if (g_vars->scene37_lastDudeX > x && g_vars->scene37_dudeX <= x && !g_vars->scene37_rings[i]->state) + sceneHandler37_updateRing(i); + + x = g_vars->scene37_rings[i]->y; + + if (g_vars->scene37_lastDudeX < x && g_vars->scene37_dudeX >= x) { + if (g_vars->scene37_rings[i]->state) + sceneHandler37_updateRing(i); + } + } + + g_vars->scene37_lastDudeX = g_vars->scene37_dudeX; + } +} + +int sceneHandler37(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch(cmd->_messageNum) { + case MSG_SC37_EXITLEFT: + sceneHandler37_updateRing(0); + sceneHandler37_updateRing(1); + sceneHandler37_updateRing(2); + + break; + + case 29: + { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_keyCode)) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_keyCode)) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) + || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) { + g_fp->processArcade(cmd); + break; + } + } + } + } + + break; + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + g_vars->scene37_dudeX = x; + + if (x >= 500) { + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + } else { + g_fp->_currentScene->_x = -g_fp->_sceneRect.left; + } + x = g_vars->scene37_dudeX; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + sceneHandler37_setRingsState(); + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + + ++g_vars->scene37_soundFlipper; + + break; + + case MSG_SC37_PULL: + if (g_vars->scene37_rings[0]->ani->_movement && g_vars->scene37_rings[0]->ani->_movement->_id == MV_GRD37_PULL) { + if ((g_fp->getObjectState(sO_Guard_1) == g_fp->getObjectEnumState(sO_Guard_1, sO_On) && !g_vars->scene37_rings[0]->state) + || (g_fp->getObjectState(sO_Guard_1) == g_fp->getObjectEnumState(sO_Guard_1, sO_Off) && g_vars->scene37_rings[0]->state)) { + g_vars->scene37_plusMinus1->_statics = g_vars->scene37_plusMinus1->getStaticsById(ST_PMS_PLUS); + } else { + g_vars->scene37_plusMinus1->_statics = g_vars->scene37_plusMinus1->getStaticsById(ST_PMS_MINUS); + } + } else if (g_vars->scene37_rings[1]->ani->_movement && g_vars->scene37_rings[1]->ani->_movement->_id == MV_GRD37_PULL) { + if ((g_fp->getObjectState(sO_Guard_2) == g_fp->getObjectEnumState(sO_Guard_2, sO_On) && !g_vars->scene37_rings[1]->state) + || (g_fp->getObjectState(sO_Guard_2) == g_fp->getObjectEnumState(sO_Guard_2, sO_Off) && g_vars->scene37_rings[1]->state)) { + g_vars->scene37_plusMinus2->_statics = g_vars->scene37_plusMinus2->getStaticsById(ST_PMS_PLUS); + } else { + g_vars->scene37_plusMinus2->_statics = g_vars->scene37_plusMinus2->getStaticsById(ST_PMS_MINUS); + } + } else if (g_vars->scene37_rings[2]->ani->_movement && g_vars->scene37_rings[2]->ani->_movement->_id == MV_GRD37_PULL) { + if ((g_fp->getObjectState(sO_Guard_3) == g_fp->getObjectEnumState(sO_Guard_3, sO_On) && !g_vars->scene37_rings[2]->state) + || (g_fp->getObjectState(sO_Guard_3) == g_fp->getObjectEnumState(sO_Guard_3, sO_Off) && g_vars->scene37_rings[2]->state)) { + g_vars->scene37_plusMinus3->_statics = g_vars->scene37_plusMinus3->getStaticsById(ST_PMS_PLUS); + } else { + g_vars->scene37_plusMinus3->_statics = g_vars->scene37_plusMinus3->getStaticsById(ST_PMS_MINUS); + } + } + + if (g_vars->scene37_soundFlipper) { + g_fp->playSound(SND_37_007, 0); + + g_vars->scene37_soundFlipper = 0; + } + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene38.cpp b/engines/fullpipe/scenes/scene38.cpp new file mode 100644 index 0000000000..016dc83c1b --- /dev/null +++ b/engines/fullpipe/scenes/scene38.cpp @@ -0,0 +1,409 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene38_setBottleState(Scene *sc) { + ExCommand *ex = sc->getMessageQueueById(QU_SC38_SHOWBOTTLE_ONTABLE)->getExCommandByIndex(0); + + if (g_vars->scene38_bottle->_ox == ex->_x && g_vars->scene38_bottle->_oy == ex->_y) { + if (g_fp->lift_checkButton(sO_Level5) ) { + ex = sc->getMessageQueueById(QU_SC38_SHOWBOTTLE)->getExCommandByIndex(0); + + g_vars->scene38_bottle->setOXY(ex->_x, ex->_y); + g_vars->scene38_bottle->_priority = ex->_field_14; + + g_fp->setObjectState(sO_Bottle_38, g_fp->getObjectEnumState(sO_Bottle_38, sO_Blocked)); + } + } +} + +void scene38_initScene(Scene *sc) { + g_vars->scene38_boss = sc->getStaticANIObject1ById(ANI_GLAVAR, -1); + g_vars->scene38_tally = sc->getStaticANIObject1ById(ANI_DYLDA, -1); + g_vars->scene38_shorty = sc->getStaticANIObject1ById(ANI_MALYSH, -1); + g_vars->scene38_domino0 = sc->getStaticANIObject1ById(ANI_DOMINO38, 0); + g_vars->scene38_dominos = sc->getStaticANIObject1ById(ANI_DOMINOS, 0); + g_vars->scene38_domino1 = sc->getStaticANIObject1ById(ANI_DOMINO38, 1); + g_vars->scene38_bottle = sc->getStaticANIObject1ById(ANI_BOTTLE38, 0); + g_vars->scene38_bossCounter = 0; + g_vars->scene38_lastBossAnim = 0; + g_vars->scene38_bossAnimCounter = 0; + g_vars->scene38_tallyCounter = 15; + g_vars->scene38_lastTallyAnim = 0; + g_vars->scene38_tallyAnimCounter = 0; + g_vars->scene38_shortyCounter = 30; + g_vars->scene38_lastShortyAnim = 0; + g_vars->scene38_shortyAnimCounter = 0; + + scene38_setBottleState(sc); + + if (g_fp->getObjectState(sO_Boss) == g_fp->getObjectEnumState(sO_Boss, sO_IsSleeping)) { + g_vars->scene38_shorty->_flags &= 0xFFFB; + + g_vars->scene38_tally->stopAnim_maybe(); + g_vars->scene38_tally->_flags &= 0xFFFB; + + g_vars->scene38_domino0->_flags &= 0xFFFB; + g_vars->scene38_dominos->_flags &= 0xFFFB; + g_vars->scene38_domino1->_flags &= 0xFFFB; + } + + g_fp->lift_init(sc, QU_SC38_ENTERLIFT, QU_SC38_EXITLIFT); + g_fp->lift_setButtonStatics(sc, ST_LBN_0N); +} + +void sceneHandler38_tryTakeBottle() { + g_vars->scene38_boss->changeStatics2(ST_GLV_NOHAMMER); + g_vars->scene38_boss->startAnim(MV_GLV_LOOKMAN, 0, -1); + + g_vars->scene38_bossCounter = 0; +} + +void sceneHandler38_postHammerKick() { + g_vars->scene38_domino1->setOXY(g_vars->scene38_domino1->_ox, g_vars->scene38_domino1->_oy + 2); +} + +void sceneHandler38_propose() { + if (!g_vars->scene38_tally->_movement) { + if (g_vars->scene38_tally->_flags & 4) { + if (!(g_vars->scene38_tally->_flags & 2) && g_vars->scene38_tallyCounter > 0 + && g_fp->_rnd->getRandomNumber(32767) < 32767) { + chainQueue(QU_DLD_DENY, 0); + g_vars->scene38_tallyCounter = 0; + } + } + } +} + +void sceneHandler38_point() { + if ((!g_vars->scene38_boss->_movement && ((g_vars->scene38_boss->_flags & 4) || !(g_vars->scene38_boss->_flags & 2))) + && g_vars->scene38_bossCounter > 0 + && g_fp->_rnd->getRandomNumber(32767) < 32767) { + if (g_vars->scene38_boss->_statics->_staticsId == ST_GLV_HAMMER) { + chainQueue(QU_GLV_TOSMALL, 0); + g_vars->scene38_bossCounter = 0; + } else { + if (g_vars->scene38_boss->_statics->_staticsId == ST_GLV_NOHAMMER) + chainQueue(QU_GLV_TOSMALL_NOHMR, 0); + + g_vars->scene38_bossCounter = 0; + } + } +} + +void sceneHandler38_hammerKick() { + if (!g_vars->scene38_shorty->_movement) { + if (g_vars->scene38_shorty->_flags & 4) { + if (!(g_vars->scene38_shorty->_flags & 2) && g_vars->scene38_shortyCounter > 1 + && g_vars->scene38_shorty->_statics->_staticsId == ST_MLS_LEFT2 + && g_fp->_rnd->getRandomNumber(32767) < 3276) { + chainQueue(QU_MLS_TURNR, 0); + g_vars->scene38_shortyCounter = 0; + } + } + } + + g_vars->scene38_domino1->setOXY(g_vars->scene38_domino1->_ox, g_vars->scene38_domino1->_oy - 2); + + if (g_vars->scene38_dominos->_statics->_staticsId == ST_DMS_3) + g_vars->scene38_dominos->startAnim(MV_DMS_THREE, 0, -1); + else if (g_vars->scene38_dominos->_statics->_staticsId == ST_DMS_4) + g_vars->scene38_dominos->startAnim(MV_DMS_FOUR, 0, -1); +} + +void sceneHandler38_drink() { + if (!g_vars->scene38_shorty->_movement) { + if (g_vars->scene38_shorty->_flags & 4) { + if (!(g_vars->scene38_shorty->_flags & 2) && g_vars->scene38_shortyCounter > 0 + && g_vars->scene38_shorty->_statics->_staticsId == ST_MLS_LEFT2 + && g_fp->_rnd->getRandomNumber(32767) < 3276) { + chainQueue(QU_MLS_TURNR, 0); + g_vars->scene38_shortyCounter = 0; + } + } + } +} + +void sceneHandler38_animateAlcoholics() { + MessageQueue *mq; + + if (g_vars->scene38_boss->_movement || !(g_vars->scene38_boss->_flags & 4) || (g_vars->scene38_boss->_flags & 2)) { + g_vars->scene38_bossCounter = 0; + } else { + g_vars->scene38_bossCounter++; + } + + if (g_vars->scene38_bossCounter >= 50) { + int bossSt = g_vars->scene38_boss->_statics->_staticsId; + + if (bossSt == ST_GLV_SLEEP2) { + g_vars->scene38_bossCounter = 0; + } else if ((g_vars->scene38_domino0->_flags & 4) && g_vars->scene38_domino0->_statics->_staticsId == ST_DMN38_6) { + if (bossSt == ST_GLV_HAMMER) { + chainQueue(QU_GLV_TAKEDOMINO, 1); + g_vars->scene38_bossCounter = 0; + } + + if (bossSt == ST_GLV_NOHAMMER) { + chainQueue(QU_GLV_TAKEDOMINO_NOHMR, 1); + g_vars->scene38_bossCounter = 0; + } + } else { + if ((g_vars->scene38_bottle->_flags & 4) && g_vars->scene38_bottle->_statics->_staticsId == ST_BTL38_FULL && bossSt == ST_GLV_NOHAMMER) { + chainQueue(QU_GLV_DRINKBOTTLE, 1); + g_vars->scene38_bossCounter = 0; + } else { + int bossAnim = 0; + + if (g_fp->_rnd->getRandomNumber(32767) >= 1310 || g_vars->scene38_boss->_statics->_staticsId != ST_GLV_HAMMER) { + if (g_fp->_rnd->getRandomNumber(32767) >= 1310) { + if (g_fp->_rnd->getRandomNumber(32767) < 1310) { + if (bossSt == ST_GLV_HAMMER) + bossAnim = QU_GLV_DRINK; + else if (bossSt == ST_GLV_NOHAMMER) + bossAnim = QU_GLV_DRINK_NOHMR; + } + } else { + if (bossSt == ST_GLV_HAMMER) + bossAnim = QU_GLV_PROPOSE; + else if (bossSt == ST_GLV_NOHAMMER) + bossAnim = QU_GLV_PROPOSE_NOHMR; + } + } else { + bossAnim = QU_GLV_HMRKICK; + } + + if (g_vars->scene38_lastBossAnim == bossAnim) { + g_vars->scene38_bossAnimCounter++; + + if (g_vars->scene38_bossAnimCounter > 2) + bossAnim = 0; + } else { + g_vars->scene38_lastBossAnim = bossAnim; + g_vars->scene38_bossAnimCounter = 1; + } + + if (bossAnim > 0) { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(bossAnim), 0, 0); + + mq->chain(0); + + g_vars->scene38_bossCounter = 0; + } + } + } + } + + if (g_vars->scene38_tally->_movement || !(g_vars->scene38_tally->_flags & 4) || (g_vars->scene38_tally->_flags & 2)) { + g_vars->scene38_tallyCounter = 0; + } else { + g_vars->scene38_tallyCounter++; + } + + if (g_vars->scene38_tallyCounter >= 50) { + int tallyAnim = 0; + + if (g_fp->_rnd->getRandomNumber(32767) >= 1310) { + if (g_fp->_rnd->getRandomNumber(32767) >= 1310) { + if (g_fp->_rnd->getRandomNumber(32767) >= 1310) { + if (g_fp->_rnd->getRandomNumber(32767) < 1310) + tallyAnim = QU_DLD_ICK; + } else { + tallyAnim = QU_DLD_GLOT; + } + } else { + tallyAnim = QU_DLD_BLINK; + } + } else { + if (g_vars->scene38_domino1->_statics->_staticsId == ST_DMN38_NORM3) { + tallyAnim = QU_DLD_TAKE1; + } else if (g_vars->scene38_domino1->_statics->_staticsId == ST_DMN38_NORM4) { + tallyAnim = QU_DLD_TAKE2; + } + } + + if (g_vars->scene38_lastTallyAnim == tallyAnim) { + g_vars->scene38_tallyAnimCounter++; + + if (g_vars->scene38_tallyAnimCounter++ > 2) + tallyAnim = 0; + } else { + g_vars->scene38_lastTallyAnim = tallyAnim; + g_vars->scene38_tallyAnimCounter = 1; + } + if (tallyAnim > 0) { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(tallyAnim), 0, 0); + + mq->chain(0); + g_vars->scene38_tallyCounter = 0; + } + } + + if (g_vars->scene38_shorty->_movement || !(g_vars->scene38_shorty->_flags & 4) || (g_vars->scene38_shorty->_flags & 2)) { + g_vars->scene38_shortyCounter = 0; + return; + } + + g_vars->scene38_shortyCounter++; + + if (g_vars->scene38_shortyCounter < 50) + return; + + int shortyAnim = 0; + + if (g_fp->_rnd->getRandomNumber(32767) >= 1310) { + if (g_fp->_rnd->getRandomNumber(32767) >= 1310 || g_vars->scene38_shorty->_statics->_staticsId != ST_MLS_LEFT2) { + if (g_vars->scene38_boss->_statics->_staticsId != ST_GLV_SLEEP2 && g_vars->scene38_bossCounter > 30 && g_fp->_rnd->getRandomNumber(32767) < 0x3FFF && g_vars->scene38_shorty->_statics->_staticsId == ST_MLS_LEFT2) + shortyAnim = QU_MLS_HAND; + } else { + shortyAnim = QU_MLS_BLINK; + } + } else { + if (g_vars->scene38_shorty->_statics->_staticsId == ST_MLS_RIGHT2) { + shortyAnim = QU_MLS_TURNL; + } else if (g_vars->scene38_shorty->_statics->_staticsId == ST_MLS_LEFT2) { + shortyAnim = QU_MLS_TURNR; + } + } + + if (g_vars->scene38_lastShortyAnim == shortyAnim) { + g_vars->scene38_shortyAnimCounter++; + if (g_vars->scene38_shortyAnimCounter > 2) + return; + } else { + g_vars->scene38_lastShortyAnim = shortyAnim; + g_vars->scene38_shortyAnimCounter = 1; + } + + if (shortyAnim > 0) { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(shortyAnim), 0, 0); + + mq->chain(0); + + g_vars->scene38_shortyCounter = 0; + } +} + +int sceneHandler38(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_LIFT_EXITLIFT: + g_fp->lift_exitSeq(cmd); + break; + + case MSG_LIFT_CLOSEDOOR: + g_fp->lift_closedoorSeq(); + break; + + case MSG_LIFT_STARTEXITQUEUE: + g_fp->lift_startExitQueue(); + break; + + case MSG_SC38_TRYTAKEBOTTLE: + sceneHandler38_tryTakeBottle(); + break; + + case MSG_SC38_POSTHMRKICK: + sceneHandler38_postHammerKick(); + break; + + case MSG_SC38_PROPOSE: + sceneHandler38_propose(); + break; + + case MSG_LIFT_CLICKBUTTON: + g_fp->lift_clickButton(); + break; + + case MSG_SC38_POINT: + sceneHandler38_point(); + break; + + case MSG_LIFT_GO: + g_fp->lift_goAnimation(); + break; + + case MSG_SC38_HMRKICK: + sceneHandler38_hammerKick(); + break; + + case MSG_SC38_DRINK: + sceneHandler38_drink(); + break; + + case 64: + g_fp->lift_sub05(cmd); + break; + + case 29: + { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(g_fp->_sceneRect.left + cmd->_x, g_fp->_sceneRect.top + cmd->_y); + + if (ani && ani->_id == ANI_LIFTBUTTON) { + g_fp->lift_sub1(ani); + + cmd->_messageKind = 0; + } + break; + } + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + sceneHandler38_animateAlcoholics(); + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/sceneFinal.cpp b/engines/fullpipe/scenes/sceneFinal.cpp new file mode 100644 index 0000000000..e483e8bab7 --- /dev/null +++ b/engines/fullpipe/scenes/sceneFinal.cpp @@ -0,0 +1,174 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + +#include "fullpipe/modal.h" + + +namespace Fullpipe { + +void sceneFinal_initScene() { + g_fp->_gameLoader->loadScene(SC_FINAL2); + g_fp->accessScene(SC_FINAL2)->setPictureObjectsFlag4(); + g_fp->_gameLoader->loadScene(SC_FINAL3); + g_fp->accessScene(SC_FINAL3)->setPictureObjectsFlag4(); + g_fp->_gameLoader->loadScene(SC_FINAL4); + g_fp->accessScene(SC_FINAL4)->setPictureObjectsFlag4(); + + getGameLoaderInventory()->setIsLocked(0); + getGameLoaderInventory()->slideIn(); + + g_fp->_updateFlag = 0; + g_fp->_flgCanOpenMap = 0; + + g_vars->sceneFinal_var01 = 0; + g_vars->sceneFinal_var02 = 0; + g_vars->sceneFinal_var03 = 0; +} + +int sceneFinal_updateCursor() { + if (g_vars->sceneFinal_var01) + g_fp->_cursorId = 0; + else + g_fp->updateCursorCommon(); + + return g_fp->_cursorId; +} + +void sceneHandlerFinal_endFinal() { + g_vars->sceneFinal_var01 = 0; +} + +void sceneHandlerFinal_startMusic(const char *track) { + warning("STUB: sceneHandlerFinal_startMusic()"); +} + +void sceneHandlerFinal_goto4() { + g_fp->_currentScene = g_fp->accessScene(SC_FINAL4); + + g_fp->_gameLoader->loadScene(SC_FINAL4); + + chainQueue(QU_FN4_DOFINAL, 1); +} + +void sceneHandlerFinal_goto3() { + g_fp->_currentScene = g_fp->accessScene(SC_FINAL3); + + chainQueue(QU_FN3_DOFINAL, 1); +} + +void sceneHandlerFinal_goto2() { + g_fp->_currentScene = g_fp->accessScene(SC_FINAL2); + + chainQueue(QU_FN2_DOFINAL, 1); +} + +void sceneHandlerFinal_startFinal() { + g_vars->sceneFinal_var01 = 1; + + getCurrSceneSc2MotionController()->clearEnabled(); + getGameLoaderInteractionController()->disableFlag24(); + + g_fp->_aniMan2 = 0; + + g_fp->_aniMan->_flags &= 0xFFFB; + + chainQueue(QU_FIN1_TAKECOIN, 1); + + g_fp->playTrack(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_FINAL1"), "MUSIC2", 1); + + g_fp->_modalObject = new ModalFinal; +} + +void sceneHandlerFinal_fallCoin() { + StaticANIObject *coin = g_fp->_currentScene->getStaticANIObject1ById(ANI_FIN_COIN, -1); + + if (!coin->_movement) { + if (!coin->_statics || coin->_statics->_staticsId != ST_FCN_NORM) + chainQueue(QU_FIN1_FALLCOIN, 1); + } +} + +int sceneHandlerFinal(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_FIN_ENDFINAL: + sceneHandlerFinal_endFinal(); + break; + + case MSG_FN4_STARTMUSIC: + sceneHandlerFinal_startMusic("track16.ogg"); + break; + + case MSG_FIN_GOTO4: + sceneHandlerFinal_goto4(); + + g_fp->playTrack(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_FINAL1"), "MUSIC3", 1); + break; + + case MSG_FIN_GOTO3: + sceneHandlerFinal_goto3(); + break; + + case MSG_FIN_GOTO2: + sceneHandlerFinal_goto2(); + break; + + case MSG_FIN_STARTFINAL: + sceneHandlerFinal_startFinal(); + break; + + case 33: + if (g_fp->_aniMan2) { + g_vars->sceneFinal_var03 = g_fp->_aniMan2->_ox; + + if (g_vars->sceneFinal_var03 < 450 && g_vars->sceneFinal_var02 >= 450 ) + sceneHandlerFinal_fallCoin(); + + g_vars->sceneFinal_var02 = g_vars->sceneFinal_var03; + } + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/sound.cpp b/engines/fullpipe/sound.cpp index cf66cb40a1..fd25e2c903 100644 --- a/engines/fullpipe/sound.cpp +++ b/engines/fullpipe/sound.cpp @@ -199,4 +199,8 @@ void FullpipeEngine::stopAllSoundInstances(int id) { } } +void FullpipeEngine::updateSoundVolume() { + debug(3, "STUB FullpipeEngine::updateSoundVolume()"); +} + } // End of namespace Fullpipe diff --git a/engines/fullpipe/stateloader.cpp b/engines/fullpipe/stateloader.cpp index fdf38ada1f..ccf77ff81a 100644 --- a/engines/fullpipe/stateloader.cpp +++ b/engines/fullpipe/stateloader.cpp @@ -328,8 +328,4 @@ bool PicAniInfo::load(MfcArchive &file) { return true; } -void FullpipeEngine::updateMap(PreloadItem *pre) { - warning("STUB: FullpipeEngine::updateMap()"); -} - } // End of namespace Fullpipe diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index 48ba96ec8b..a485ae47e4 100644 --- a/engines/kyra/kyra_mr.cpp +++ b/engines/kyra/kyra_mr.cpp @@ -378,7 +378,6 @@ void KyraEngine_MR::playVQA(const char *name) { _screen->fadeToBlack(60); _screen->clearPage(0); - vqa.setDrawPage(0); vqa.play(); vqa.close(); diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index c52b0a04ad..522e12faa4 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -1172,7 +1172,7 @@ void GUI_LoK::initStaticResource() { GUI_V1_MENU_ITEM(_menu[5].item[2], 1, 0, 0, 0, 0xA5, 0, 0x40, 0x80, 0x0F, 252, 253, 5, 0, 248, 249, 250, -1, 0, 0x10, 0x42, 0, 0); GUI_V1_MENU_ITEM(_menu[5].item[3], 1, 0, 0, 0, 0xA5, 0, 0x51, 0x80, 0x0F, 252, 253, 5, 0, 248, 249, 250, -1, 0, 0x10, 0x53, 0, 0); GUI_V1_MENU_ITEM(_menu[5].item[4], 1, 0, 0, 0, 0xA5, 0, 0x62, 0x80, 0x0F, 252, 253, 5, 0, 248, 249, 250, -1, 0, 0x10, 0x65, 0, 0); - GUI_V1_MENU_ITEM(_menu[5].item[5], 1, 0, 0, 0, -1, 0, 0x7F, 0x6C, 0x0F, 252, 253, -1, 255, 248, 249, 250, -1, -0, 0, 0, 0, 0); + GUI_V1_MENU_ITEM(_menu[5].item[5], 1, 0, 0, 0, -1, 0, 0x7F, 0x6C, 0x0F, 252, 253, -1, 255, 248, 249, 250, -1, 0, 0, 0, 0, 0); _menu[5].item[0].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::controlsChangeMusic); _menu[5].item[1].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::controlsChangeSounds); _menu[5].item[2].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::controlsChangeWalk); diff --git a/engines/kyra/vqa.cpp b/engines/kyra/vqa.cpp index 081d94a050..d9564e1306 100644 --- a/engines/kyra/vqa.cpp +++ b/engines/kyra/vqa.cpp @@ -28,644 +28,606 @@ // // The jung2.vqa movie does work, but only thanks to a grotesque hack. - +#include "kyra/kyra_v1.h" #include "kyra/vqa.h" -#include "kyra/resource.h" - -#include "common/system.h" +#include "kyra/screen.h" #include "audio/audiostream.h" -#include "audio/mixer.h" #include "audio/decoders/raw.h" -namespace Kyra { - -VQAMovie::VQAMovie(KyraEngine_v1 *vm, OSystem *system) { - _system = system; - _vm = vm; - _screen = _vm->screen(); - _opened = false; - _x = _y = _drawPage = -1; - _frame = 0; - _vectorPointers = 0; - _numPartialCodeBooks = 0; - _partialCodeBookSize = 0; - _compressedCodeBook = 0; - _partialCodeBook = 0; - _codeBook = 0; - _frameInfo = 0; - memset(_buffers, 0, sizeof(_buffers)); -} - -VQAMovie::~VQAMovie() { - close(); -} - -void VQAMovie::initBuffers() { - for (int i = 0; i < ARRAYSIZE(_buffers); i++) { - _buffers[i].data = 0; - _buffers[i].size = 0; - } -} - -void *VQAMovie::allocBuffer(int num, uint32 size) { - assert(num >= 0 && num < ARRAYSIZE(_buffers)); - assert(size > 0); - - if (size > _buffers[num].size) { - /* - * We could use realloc() here, but we don't actually need the - * old contents of the buffer. - */ - delete[] _buffers[num].data; - _buffers[num].data = new uint8[size]; - _buffers[num].size = size; - } - - assert(_buffers[num].data); +#include "common/system.h" +#include "common/events.h" - return _buffers[num].data; -} +#include "graphics/palette.h" +#include "graphics/surface.h" -void VQAMovie::freeBuffers() { - for (int i = 0; i < ARRAYSIZE(_buffers); i++) { - delete[] _buffers[i].data; - _buffers[i].data = NULL; - _buffers[i].size = 0; - } -} +namespace Kyra { -uint32 VQAMovie::readTag() { +static uint32 readTag(Common::SeekableReadStream *stream) { // Some tags have to be on an even offset, so they are padded with a // zero byte. Skip that. - uint32 tag = _file->readUint32BE(); + uint32 tag = stream->readUint32BE(); - if (_file->eos()) + if (stream->eos()) return 0; if (!(tag & 0xFF000000)) { - tag = (tag << 8) | _file->readByte(); + tag = (tag << 8) | stream->readByte(); } return tag; } -void VQAMovie::decodeSND1(byte *inbuf, uint32 insize, byte *outbuf, uint32 outsize) { - const int8 WSTable2Bit[] = { -2, -1, 0, 1 }; - const int8 WSTable4Bit[] = { - -9, -8, -6, -5, -4, -3, -2, -1, - 0, 1, 2, 3, 4, 5, 6, 8 - }; - - byte code; - int8 count; - uint16 input; - - int16 curSample = 0x80; - - while (outsize > 0) { - input = *inbuf++ << 2; - code = (input >> 8) & 0xFF; - count = (input & 0xFF) >> 2; - - switch (code) { - case 2: - if (count & 0x20) { - /* NOTE: count is signed! */ - count <<= 3; - curSample += (count >> 3); - *outbuf++ = curSample; - outsize--; - } else { - for (; count >= 0; count--) { - *outbuf++ = *inbuf++; - outsize--; - } - curSample = *(outbuf - 1); - } - break; - case 1: - for (; count >= 0; count--) { - code = *inbuf++; - - curSample += WSTable4Bit[code & 0x0F]; - curSample = CLIP<int16>(curSample, 0, 255); - *outbuf++ = curSample; - - curSample += WSTable4Bit[code >> 4]; - curSample = CLIP<int16>(curSample, 0, 255); - *outbuf++ = curSample; - - outsize -= 2; - } - break; - case 0: - for (; count >= 0; count--) { - code = *inbuf++; - - curSample += WSTable2Bit[code & 0x03]; - curSample = CLIP<int16>(curSample, 0, 255); - *outbuf++ = curSample; - - curSample += WSTable2Bit[(code >> 2) & 0x03]; - curSample = CLIP<int16>(curSample, 0, 255); - *outbuf++ = curSample; - - curSample += WSTable2Bit[(code >> 4) & 0x03]; - curSample = CLIP<int16>(curSample, 0, 255); - *outbuf++ = curSample; - - curSample += WSTable2Bit[(code >> 6) & 0x03]; - curSample = CLIP<int16>(curSample, 0, 255); - *outbuf++ = curSample; - - outsize -= 4; - } - break; - default: - for (; count >= 0; count--) { - *outbuf++ = curSample; - outsize--; - } - } - } +VQADecoder::VQADecoder() { + memset(&_header, 0, sizeof(_header)); } -bool VQAMovie::open(const char *filename) { +VQADecoder::~VQADecoder() { close(); + delete[] _frameInfo; +} - _file = _vm->resource()->createReadStream(filename); - if (!_file) - return false; +bool VQADecoder::loadStream(Common::SeekableReadStream *stream) { + close(); + _fileStream = stream; - if (_file->readUint32BE() != MKTAG('F','O','R','M')) { - warning("VQAMovie::open: Cannot find `FORM' tag"); + if (_fileStream->readUint32BE() != MKTAG('F','O','R','M')) { + warning("VQADecoder::loadStream(): Cannot find `FORM' tag"); return false; } - // For now, we ignore the size of the FORM chunk. - _file->readUint32BE(); + // Ignore the size of the FORM chunk. We're only interested in its + // children. + _fileStream->readUint32BE(); - if (_file->readUint32BE() != MKTAG('W','V','Q','A')) { - warning("WQAMovie::open: Cannot find `WVQA' tag"); + if (_fileStream->readUint32BE() != MKTAG('W','V','Q','A')) { + warning("VQADecoder::loadStream(): Cannot find `WVQA' tag"); return false; } - bool foundHeader = false; - bool foundFrameInfo = false; + // We want to find both a VQHD chunk containing the header, and a FINF + // chunk containing the frame offsets. + + bool foundVQHD = false; + bool foundFINF = false; + + VQAAudioTrack *audioTrack = NULL; // The information we need is stored in two chunks: VQHD and FINF. We // need both of them before we can begin decoding the movie. - while (!foundHeader || !foundFrameInfo) { - uint32 tag = readTag(); - uint32 size = _file->readUint32BE(); + while (!foundVQHD || !foundFINF) { + uint32 tag = readTag(stream); + uint32 size = _fileStream->readUint32BE(); switch (tag) { - case MKTAG('V','Q','H','D'): // VQA header - _header.version = _file->readUint16LE(); - _header.flags = _file->readUint16LE(); - _header.numFrames = _file->readUint16LE(); - _header.width = _file->readUint16LE(); - _header.height = _file->readUint16LE(); - _header.blockW = _file->readByte(); - _header.blockH = _file->readByte(); - _header.frameRate = _file->readByte(); - _header.cbParts = _file->readByte(); - _header.colors = _file->readUint16LE(); - _header.maxBlocks = _file->readUint16LE(); - _header.unk1 = _file->readUint32LE(); - _header.unk2 = _file->readUint16LE(); - _header.freq = _file->readUint16LE(); - _header.channels = _file->readByte(); - _header.bits = _file->readByte(); - _header.unk3 = _file->readUint32LE(); - _header.unk4 = _file->readUint16LE(); - _header.maxCBFZSize = _file->readUint32LE(); - _header.unk5 = _file->readUint32LE(); - - // Kyrandia 3 uses version 1 VQA files, and is the only - // known game to do so. This version of the format has - // some implicit default values. - - if (_header.version == 1) { - if (_header.freq == 0) - _header.freq = 22050; - if (_header.channels == 0) - _header.channels = 1; - if (_header.bits == 0) - _header.bits = 8; - } - - _x = (Screen::SCREEN_W - _header.width) / 2; - _y = (Screen::SCREEN_H - _header.height) / 2; - - _frameInfo = new uint32[_header.numFrames]; - _frame = new byte[_header.width * _header.height]; - - _codeBookSize = 0xF00 * _header.blockW * _header.blockH; - _codeBook = new byte[_codeBookSize]; - _partialCodeBook = new byte[_codeBookSize]; - memset(_codeBook, 0, _codeBookSize); - memset(_partialCodeBook, 0, _codeBookSize); - - _numVectorPointers = (_header.width / _header.blockW) * (_header.height * _header.blockH); - _vectorPointers = new uint16[_numVectorPointers]; - memset(_vectorPointers, 0, _numVectorPointers * sizeof(uint16)); - - _partialCodeBookSize = 0; - _numPartialCodeBooks = 0; - + case MKTAG('V','Q','H','D'): + handleVQHD(_fileStream); if (_header.flags & 1) { - // This VQA movie has sound. Kyrandia 3 uses - // 8-bit sound, and so far testing indicates - // that it's all mono. - // - // This is good, because it means we won't have - // to worry about the confusing parts of the - // VQA spec, where 8- and 16-bit data have - // different signedness and stereo sample - // layout varies between different games. - - assert(_header.bits == 8); - assert(_header.channels == 1); - - _stream = Audio::makeQueuingAudioStream(_header.freq, false); - } else { - _stream = NULL; + audioTrack = new VQAAudioTrack(&_header); + addTrack(audioTrack); } - - foundHeader = true; + foundVQHD = true; break; - - case MKTAG('F','I','N','F'): // Frame info - if (!foundHeader) { - warning("VQAMovie::open: Found `FINF' before `VQHD'"); + case MKTAG('F','I','N','F'): + if (!foundVQHD) { + warning("VQADecoder::loadStream(): Found `FINF' before `VQHD'"); return false; } - - if (size != 4 * (uint32)_header.numFrames) { - warning("VQAMovie::open: Expected size %d for `FINF' chunk, but got %u", 4 * _header.numFrames, size); + if (size != 4 * getFrameCount()) { + warning("VQADecoder::loadStream(): Expected size %d for `FINF' chunk, but got %u", 4 * getFrameCount(), size); return false; } + handleFINF(_fileStream); + foundFINF = true; + break; + default: + warning("VQADecoder::loadStream(): Unknown tag `%s'", tag2str(tag)); + _fileStream->seek(size, SEEK_CUR); + break; + } + } - foundFrameInfo = true; + return true; +} - for (int i = 0; i < _header.numFrames; i++) { - _frameInfo[i] = 2 * _file->readUint32LE(); - } +void VQADecoder::handleVQHD(Common::SeekableReadStream *stream) { + _header.version = stream->readUint16LE(); + _header.flags = stream->readUint16LE(); + _header.numFrames = stream->readUint16LE(); + _header.width = stream->readUint16LE(); + _header.height = stream->readUint16LE(); + _header.blockW = stream->readByte(); + _header.blockH = stream->readByte(); + _header.frameRate = stream->readByte(); + _header.cbParts = stream->readByte(); + _header.colors = stream->readUint16LE(); + _header.maxBlocks = stream->readUint16LE(); + _header.unk1 = stream->readUint32LE(); + _header.unk2 = stream->readUint16LE(); + _header.freq = stream->readUint16LE(); + _header.channels = stream->readByte(); + _header.bits = stream->readByte(); + _header.unk3 = stream->readUint32LE(); + _header.unk4 = stream->readUint16LE(); + _header.maxCBFZSize = stream->readUint32LE(); + _header.unk5 = stream->readUint32LE(); + + _frameInfo = new uint32[_header.numFrames + 1]; + + VQAVideoTrack *videoTrack = new VQAVideoTrack(&_header); + addTrack(videoTrack); + + // Kyrandia 3 uses version 1 VQA files, and is the only known game to + // do so. This version of the format has some implicit default values. + + if (_header.version == 1) { + if (_header.freq == 0) + _header.freq = 22050; + if (_header.channels == 0) + _header.channels = 1; + if (_header.bits == 0) + _header.bits = 8; + } - // HACK: This flag is set in jung2.vqa, and its - // purpose, if it has one, is unknown. It can't be a - // general purpose flag, because in large movies the - // frame offsets can be large enough to set this flag, - // though of course never for the first frame. - // - // At least in my copy of Kyrandia 3, _frameInfo[0] is - // 0x81000098, and the desired index is 0x4716. So the - // value should be 0x80004716, but I don't want to - // hard-code it. Instead, scan the file for the offset - // to the first VQFR chunk. - - if (_frameInfo[0] & 0x01000000) { - uint32 oldPos = _file->pos(); - - while (1) { - uint32 scanTag = readTag(); - uint32 scanSize = _file->readUint32BE(); - - if (_file->eos()) - break; - - if (scanTag == MKTAG('V','Q','F','R')) { - _frameInfo[0] = (_file->pos() - 8) | 0x80000000; - break; - } + if (_header.flags & 1) { + // Kyrandia 3 uses 8-bit sound, and so far testing indicates + // that it's all mono. + // + // This is good, because it means we won't have to worry about + // the confusing parts of the VQA spec, where 8- and 16-bit + // data have different signedness and stereo sample layout + // varies between different games. + + assert(_header.bits == 8); + assert(_header.channels == 1); + } +} - _file->seek(scanSize, SEEK_CUR); - } +void VQADecoder::handleFINF(Common::SeekableReadStream *stream) { + for (int i = 0; i < _header.numFrames; i++) { + _frameInfo[i] = 2 * stream->readUint32LE(); + } - _file->seek(oldPos); - } + // HACK: This flag is set in jung2.vqa, and its purpose - if it has + // one - is currently unknown. It can't be a general purpose flag, + // because in large movies the frame offset can be large enough to + // set this flag, though of course never for the first frame. + // + // At least in my copy of Kyrandia 3, _frameInfo[0] is 0x81000098, and + // the desired index is 0x4716. So the value should be 0x80004716, but + // I don't want to hard-code it. Instead, scan the file for the offset + // to the first VQFR chunk. - break; + if (_frameInfo[0] & 0x01000000) { + uint32 oldPos = stream->pos(); - default: - warning("VQAMovie::open: Unknown tag `%c%c%c%c'", char((tag >> 24) & 0xFF), char((tag >> 16) & 0xFF), char((tag >> 8) & 0xFF), char(tag & 0xFF)); - _file->seek(size, SEEK_CUR); - } - } + while (1) { + uint32 scanTag = readTag(stream); + uint32 scanSize = stream->readUint32BE(); - initBuffers(); + if (stream->eos()) + break; - _opened = true; - return true; -} + if (scanTag == MKTAG('V','Q','F','R')) { + _frameInfo[0] = (stream->pos() - 8) | 0x80000000; + break; + } -void VQAMovie::close() { - if (_opened) { - delete[] _frameInfo; - delete[] _frame; - delete[] _codeBook; - delete[] _partialCodeBook; - delete[] _vectorPointers; - - if (_vm->_mixer->isSoundHandleActive(_sound)) - _vm->_mixer->stopHandle(_sound); - - _frameInfo = NULL; - _frame = NULL; - _codeBookSize = 0; - _codeBook = NULL; - _partialCodeBook = NULL; - _vectorPointers = NULL; - _stream = NULL; - - delete _file; - _file = 0; - - freeBuffers(); - - _opened = false; + stream->seek(scanSize, SEEK_CUR); + } + + stream->seek(oldPos); } + + _frameInfo[_header.numFrames] = 0x7FFFFFFF; } -void VQAMovie::displayFrame(uint frameNum) { - if (frameNum >= _header.numFrames || !_opened) - return; +void VQADecoder::readNextPacket() { + VQAVideoTrack *videoTrack = (VQAVideoTrack *)getTrack(0); + VQAAudioTrack *audioTrack = (VQAAudioTrack *)getTrack(1); - bool foundSound = !_stream; - bool foundFrame = false; - uint i; + assert(videoTrack); - _file->seek(_frameInfo[frameNum] & 0x7FFFFFFF); + int curFrame = videoTrack->getCurFrame(); - while (!foundSound || !foundFrame) { - uint32 tag = readTag(); - uint32 size = _file->readUint32BE(); + // Stop if reading the tag is enough to put us ahead of the next frame + int32 end = (_frameInfo[curFrame + 1] & 0x7FFFFFFF) - 7; - if (_file->eos()) { - // This happens at the last frame. Apparently it has - // no sound? - break; + // At this point, we probably only need to adjust for the offset in the + // stream to be even. But we may as well do this to really make sure + // we have the correct offset. + if (curFrame >= 0) { + _fileStream->seek(_frameInfo[curFrame] & 0x7FFFFFFF); + if (_frameInfo[curFrame] & 0x80000000) { + videoTrack->setHasDirtyPalette(); } + } - byte *inbuf, *outbuf; - uint32 insize, outsize; - int32 end; + while (!_fileStream->eos() && _fileStream->pos() < end) { + uint32 tag = readTag(_fileStream); + uint32 size; switch (tag) { case MKTAG('S','N','D','0'): // Uncompressed sound - foundSound = true; - inbuf = (byte *)malloc(size); - _file->read(inbuf, size); - assert(_stream); - _stream->queueBuffer(inbuf, size, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); + assert(audioTrack); + audioTrack->handleSND0(_fileStream); break; - case MKTAG('S','N','D','1'): // Compressed sound, almost like AUD - foundSound = true; - outsize = _file->readUint16LE(); - insize = _file->readUint16LE(); - - inbuf = (byte *)malloc(insize); - _file->read(inbuf, insize); - - if (insize == outsize) { - assert(_stream); - _stream->queueBuffer(inbuf, insize, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); - } else { - outbuf = (byte *)malloc(outsize); - decodeSND1(inbuf, insize, outbuf, outsize); - assert(_stream); - _stream->queueBuffer(outbuf, outsize, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); - free(inbuf); - } + assert(audioTrack); + audioTrack->handleSND1(_fileStream); break; - case MKTAG('S','N','D','2'): // Compressed sound - foundSound = true; - warning("VQAMovie::displayFrame: `SND2' is not implemented"); - _file->seek(size, SEEK_CUR); + assert(audioTrack); + audioTrack->handleSND2(_fileStream); break; - case MKTAG('V','Q','F','R'): - foundFrame = true; - end = _file->pos() + size - 8; - - while (_file->pos() < end) { - tag = readTag(); - size = _file->readUint32BE(); - - switch (tag) { - case MKTAG('C','B','F','0'): // Full codebook - _file->read(_codeBook, size); - break; + videoTrack->handleVQFR(_fileStream); + break; + case MKTAG('C','M','D','S'): + // The purpose of this is unknown, but it's known to + // exist so don't warn about it. + size = _fileStream->readUint32BE(); + _fileStream->seek(size, SEEK_CUR); + break; + default: + warning("VQADecoder::readNextPacket(): Unknown tag `%s'", tag2str(tag)); + size = _fileStream->readUint32BE(); + _fileStream->seek(size, SEEK_CUR); + break; + } + } +} - case MKTAG('C','B','F','Z'): // Full codebook - inbuf = (byte *)allocBuffer(0, size); - _file->read(inbuf, size); - Screen::decodeFrame4(inbuf, _codeBook, _codeBookSize); - break; +// ----------------------------------------------------------------------- - case MKTAG('C','B','P','0'): // Partial codebook - _compressedCodeBook = false; - _file->read(_partialCodeBook + _partialCodeBookSize, size); - _partialCodeBookSize += size; - _numPartialCodeBooks++; - break; +VQADecoder::VQAAudioTrack::VQAAudioTrack(const VQAHeader *header) { + _audioStream = Audio::makeQueuingAudioStream(header->freq, false); +} - case MKTAG('C','B','P','Z'): // Partial codebook - _compressedCodeBook = true; - _file->read(_partialCodeBook + _partialCodeBookSize, size); - _partialCodeBookSize += size; - _numPartialCodeBooks++; - break; +VQADecoder::VQAAudioTrack::~VQAAudioTrack() { + delete _audioStream; +} - case MKTAG('C','P','L','0'): // Palette - assert(size <= 3 * 256); - _file->read(_screen->getPalette(0).getData(), size); - break; +Audio::AudioStream *VQADecoder::VQAAudioTrack::getAudioStream() const { + return _audioStream; +} - case MKTAG('C','P','L','Z'): // Palette - inbuf = (byte *)allocBuffer(0, size); - _file->read(inbuf, size); - Screen::decodeFrame4(inbuf, _screen->getPalette(0).getData(), 768); - break; +void VQADecoder::VQAAudioTrack::handleSND0(Common::SeekableReadStream *stream) { + uint32 size = stream->readUint32BE(); + byte *buf = (byte *)malloc(size); + stream->read(buf, size); + _audioStream->queueBuffer(buf, size, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); +} - case MKTAG('V','P','T','0'): // Frame data - assert(size / 2 <= _numVectorPointers); +void VQADecoder::VQAAudioTrack::handleSND1(Common::SeekableReadStream *stream) { + stream->readUint32BE(); + uint16 outsize = stream->readUint16LE(); + uint16 insize = stream->readUint16LE(); + byte *inbuf = (byte *)malloc(insize); + + stream->read(inbuf, insize); + + if (insize == outsize) { + _audioStream->queueBuffer(inbuf, insize, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); + } else { + const int8 WSTable2Bit[] = { -2, -1, 0, 1 }; + const int8 WSTable4Bit[] = { + -9, -8, -6, -5, -4, -3, -2, -1, + 0, 1, 2, 3, 4, 5, 6, 8 + }; + + byte *outbuf = (byte *)malloc(outsize); + byte *in = inbuf; + byte *out = outbuf; + int16 curSample = 0x80; + uint16 bytesLeft = outsize; + + while (bytesLeft > 0) { + uint16 input = *in++ << 2; + byte code = (input >> 8) & 0xFF; + int8 count = (input & 0xFF) >> 2; + int i; + + switch (code) { + case 2: + if (count & 0x20) { + /* NOTE: count is signed! */ + count <<= 3; + curSample += (count >> 3); + *out++ = curSample; + bytesLeft--; + } else { + for (; count >= 0; count--) { + *out++ = *in++; + bytesLeft--; + } + curSample = *(out - 1); + } + break; + case 1: + for (; count >= 0; count--) { + code = *in++; - for (i = 0; i < size / 2; i++) - _vectorPointers[i] = _file->readUint16LE(); - break; + for (i = 0; i < 2; i++) { + curSample += WSTable4Bit[code & 0x0F]; + curSample = CLIP<int16>(curSample, 0, 255); + code >>= 4; + *out++ = curSample; + } - case MKTAG('V','P','T','Z'): // Frame data - inbuf = (byte *)allocBuffer(0, size); - outbuf = (byte *)allocBuffer(1, 2 * _numVectorPointers); + bytesLeft -= 2; + } + break; + case 0: + for (; count >= 0; count--) { + code = *in++; - _file->read(inbuf, size); - size = Screen::decodeFrame4(inbuf, outbuf, 2 * _numVectorPointers); + for (i = 0; i < 4; i++) { + curSample += WSTable2Bit[code & 0x03]; + curSample = CLIP<int16>(curSample, 0, 255); + code >>= 2; + *out++ = curSample; + } - assert(size / 2 <= _numVectorPointers); + bytesLeft -= 4; + } + break; + default: + for (; count >= 0; count--) { + *out++ = curSample; + bytesLeft--; + } + break; + } + } + _audioStream->queueBuffer(outbuf, outsize, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); + free(inbuf); + } +} - for (i = 0; i < size / 2; i++) - _vectorPointers[i] = READ_LE_UINT16(outbuf + 2 * i); - break; +void VQADecoder::VQAAudioTrack::handleSND2(Common::SeekableReadStream *stream) { + uint32 size = stream->readUint32BE(); + warning("VQADecoder::VQAAudioTrack::handleSND2(): `SND2' is not implemented"); + stream->seek(size, SEEK_CUR); +} - default: - warning("VQAMovie::displayFrame: Unknown `VQFR' sub-tag `%c%c%c%c'", char((tag >> 24) & 0xFF), char((tag >> 16) & 0xFF), char((tag >> 8) & 0xFF), char(tag & 0xFF)); - _file->seek(size, SEEK_CUR); - } +// ----------------------------------------------------------------------- - } +VQADecoder::VQAVideoTrack::VQAVideoTrack(const VQAHeader *header) { + memset(_palette, 0, sizeof(_palette)); + _dirtyPalette = false; - break; + _width = header->width; + _height = header->height; + _blockW = header->blockW; + _blockH = header->blockH; + _cbParts = header->cbParts; - default: - warning("VQAMovie::displayFrame: Unknown tag `%c%c%c%c'", char((tag >> 24) & 0xFF), char((tag >> 16) & 0xFF), char((tag >> 8) & 0xFF), char(tag & 0xFF)); - _file->seek(size, SEEK_CUR); - } - } + _newFrame = false; - // The frame has been decoded + _curFrame = -1; + _frameCount = header->numFrames; + _frameRate = header->frameRate; - if (_frameInfo[frameNum] & 0x80000000) - _screen->setScreenPalette(_screen->getPalette(0)); + _codeBookSize = 0xF00 * header->blockW * header->blockH; + _compressedCodeBook = false; + _codeBook = new byte[_codeBookSize]; + _partialCodeBookSize = 0; + _numPartialCodeBooks = 0; + _partialCodeBook = new byte[_codeBookSize]; + _numVectorPointers = (header->width / header->blockW) * (header->height * header->blockH); + _vectorPointers = new uint16[_numVectorPointers]; - int blockPitch = _header.width / _header.blockW; + memset(_codeBook, 0, _codeBookSize); + memset(_partialCodeBook, 0, _codeBookSize); + memset(_vectorPointers, 0, _numVectorPointers); - for (int by = 0; by < _header.height / _header.blockH; by++) { - for (int bx = 0; bx < blockPitch; bx++) { - byte *dst = _frame + by * _header.width * _header.blockH + bx * _header.blockW; - int val = _vectorPointers[by * blockPitch + bx]; + _surface = new Graphics::Surface(); + _surface->create(header->width, header->height, Graphics::PixelFormat::createFormatCLUT8()); +} - if ((val & 0xFF00) == 0xFF00) { - // Solid color - for (i = 0; i < _header.blockH; i++) { - memset(dst, 255 - (val & 0xFF), _header.blockW); - dst += _header.width; - } - } else { - // Copy data from _vectorPointers. I'm not sure - // why we don't use the three least significant - // bits of 'val'. - byte *src = &_codeBook[(val >> 3) * _header.blockW * _header.blockH]; - - for (i = 0; i < _header.blockH; i++) { - memcpy(dst, src, _header.blockW); - src += _header.blockW; - dst += _header.width; - } - } - } - } +VQADecoder::VQAVideoTrack::~VQAVideoTrack() { + _surface->free(); + delete _surface; + delete[] _codeBook; + delete[] _partialCodeBook; + delete[] _vectorPointers; +} - if (_numPartialCodeBooks == _header.cbParts) { - if (_compressedCodeBook) { - Screen::decodeFrame4(_partialCodeBook, _codeBook, _codeBookSize); - } else { - memcpy(_codeBook, _partialCodeBook, _partialCodeBookSize); - } - _numPartialCodeBooks = 0; - _partialCodeBookSize = 0; - } +uint16 VQADecoder::VQAVideoTrack::getWidth() const { + return _width; +} - _screen->copyBlockToPage(_drawPage, _x, _y, _header.width, _header.height, _frame); +uint16 VQADecoder::VQAVideoTrack::getHeight() const { + return _height; } -void VQAMovie::play() { - uint32 startTick; +Graphics::PixelFormat VQADecoder::VQAVideoTrack::getPixelFormat() const { + return _surface->format; +} - if (!_opened) - return; +int VQADecoder::VQAVideoTrack::getCurFrame() const { + return _curFrame; +} - startTick = _system->getMillis(); +int VQADecoder::VQAVideoTrack::getFrameCount() const { + return _frameCount; +} - // First, handle any sound chunk that appears before the first frame. - // At least in some versions, it will contain half a second of audio, - // presumably to lessen the risk of audio underflow. - // - // In most movies, we will find a CMDS tag. The purpose of this is - // currently unknown. - // - // In cow1_0.vqa, cow1_1.vqa, jung0.vqa, and jung1.vqa we will find a - // VQFR tag. A frame before the first frame? Weird. It doesn't seem to - // be needed, though. +Common::Rational VQADecoder::VQAVideoTrack::getFrameRate() const { + return _frameRate; +} - byte *inbuf, *outbuf; - uint32 insize, outsize; +void VQADecoder::VQAVideoTrack::setHasDirtyPalette() { + _dirtyPalette = true; +} - if (_stream) { - while ((uint)_file->pos() < (_frameInfo[0] & 0x7FFFFFFF)) { - uint32 tag = readTag(); - uint32 size = _file->readUint32BE(); +bool VQADecoder::VQAVideoTrack::hasDirtyPalette() const { + return _dirtyPalette; +} - if (_file->eos()) { - warning("VQAMovie::play: Unexpected EOF"); - break; - } +const byte *VQADecoder::VQAVideoTrack::getPalette() const { + _dirtyPalette = false; + return _palette; +} - switch (tag) { - case MKTAG('S','N','D','0'): // Uncompressed sound - inbuf = (byte *)malloc(size); - _file->read(inbuf, size); - _stream->queueBuffer(inbuf, size, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); - break; +const Graphics::Surface *VQADecoder::VQAVideoTrack::decodeNextFrame() { + if (_newFrame) { + _newFrame = false; - case MKTAG('S','N','D','1'): // Compressed sound - outsize = _file->readUint16LE(); - insize = _file->readUint16LE(); + int blockPitch = _width / _blockW; - inbuf = (byte *)malloc(insize); - _file->read(inbuf, insize); + for (int by = 0; by < _height / _blockH; by++) { + for (int bx = 0; bx < blockPitch; bx++) { + byte *dst = (byte *)_surface->getBasePtr(bx * _blockW, by * _blockH); + int val = _vectorPointers[by * blockPitch + bx]; + int i; - if (insize == outsize) { - _stream->queueBuffer(inbuf, insize, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); + if ((val & 0xFF00) == 0xFF00) { + // Solid color + for (i = 0; i < _blockH; i++) { + memset(dst, 255 - (val & 0xFF), _blockW); + dst += _width; + } } else { - outbuf = (byte *)malloc(outsize); - decodeSND1(inbuf, insize, outbuf, outsize); - _stream->queueBuffer(outbuf, outsize, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); - free(inbuf); + // Copy data from _vectorPointers. I'm not sure + // why we don't use the three least significant + // bits of 'val'. + byte *src = &_codeBook[(val >> 3) * _blockW * _blockH]; + + for (i = 0; i < _blockH; i++) { + memcpy(dst, src, _blockW); + src += _blockW; + dst += _width; + } } - break; + } + } - case MKTAG('S','N','D','2'): // Compressed sound - warning("VQAMovie::play: `SND2' is not implemented"); - _file->seek(size, SEEK_CUR); - break; + if (_numPartialCodeBooks == _cbParts) { + if (_compressedCodeBook) { + Screen::decodeFrame4(_partialCodeBook, _codeBook, _codeBookSize); + } else { + memcpy(_codeBook, _partialCodeBook, _partialCodeBookSize); + } + _numPartialCodeBooks = 0; + _partialCodeBookSize = 0; + } + } - case MKTAG('C','M','D','S'): // Unused tag, always empty in kyra3 - _file->seek(size, SEEK_CUR); - break; + _curFrame++; + return _surface; +} - default: - warning("VQAMovie::play: Unknown tag `%c%c%c%c'", char((tag >> 24) & 0xFF), char((tag >> 16) & 0xFF), char((tag >> 8) & 0xFF), char(tag & 0xFF)); - _file->seek(size, SEEK_CUR); - } +void VQADecoder::VQAVideoTrack::handleVQFR(Common::SeekableReadStream *stream) { + uint32 size = stream->readUint32BE(); + int32 end = stream->pos() + size - 8; + byte *inbuf; + + _newFrame = true; + + while (stream->pos() < end) { + uint32 tag = readTag(stream); + uint32 i; + size = stream->readUint32BE(); + + switch (tag) { + case MKTAG('C','B','F','0'): // Full codebook + stream->read(_codeBook, size); + break; + case MKTAG('C','B','F','Z'): // Full codebook + inbuf = (byte *)malloc(size); + stream->read(inbuf, size); + Screen::decodeFrame4(inbuf, _codeBook, _codeBookSize); + free(inbuf); + break; + case MKTAG('C','B','P','0'): // Partial codebook + _compressedCodeBook = false; + stream->read(_partialCodeBook + _partialCodeBookSize, size); + _partialCodeBookSize += size; + _numPartialCodeBooks++; + break; + case MKTAG('C','B','P','Z'): // Partial codebook + _compressedCodeBook = true; + stream->read(_partialCodeBook + _partialCodeBookSize, size); + _partialCodeBookSize += size; + _numPartialCodeBooks++; + break; + case MKTAG('C','P','L','0'): // Palette + assert(size <= 3 * 256); + stream->read(_palette, size); + break; + case MKTAG('C','P','L','Z'): // Palette + inbuf = (byte *)malloc(size); + stream->read(inbuf, size); + Screen::decodeFrame4(inbuf, _palette, 3 * 256); + free(inbuf); + break; + case MKTAG('V','P','T','0'): // Frame data + assert(size / 2 <= _numVectorPointers); + for (i = 0; i < size / 2; i++) + _vectorPointers[i] = stream->readUint16LE(); + break; + case MKTAG('V','P','T','Z'): // Frame data + inbuf = (byte *)malloc(size); + stream->read(inbuf, size); + size = Screen::decodeFrame4(inbuf, (uint8 *)_vectorPointers, 2 * _numVectorPointers); + for (i = 0; i < size / 2; i++) + _vectorPointers[i] = TO_LE_16(_vectorPointers[i]); + free(inbuf); + break; + default: + warning("VQADecoder::VQAVideoTrack::handleVQFR(): Unknown `VQFR' sub-tag `%s'", tag2str(tag)); + stream->seek(size, SEEK_CUR); + break; } } +} - _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sound, _stream); - Common::EventManager *eventMan = _vm->getEventManager(); +// ----------------------------------------------------------------------- - for (uint i = 0; i < _header.numFrames; i++) { - displayFrame(i); +VQAMovie::VQAMovie(KyraEngine_v1 *vm, OSystem *system) { + _system = system; + _vm = vm; + _screen = _vm->screen(); + _decoder = new VQADecoder(); +} - // TODO: Implement frame skipping? +VQAMovie::~VQAMovie() { + close(); + delete _decoder; +} - while (1) { - uint32 elapsedTime; +bool VQAMovie::open(const char *filename) { + if (_file.open(filename)) { + return true; + } + return false; +} + +void VQAMovie::close() { + if (_file.isOpen()) { + _file.close(); + } +} + +void VQAMovie::play() { + if (_decoder->loadStream(&_file)) { + Common::EventManager *eventMan = _vm->getEventManager(); + int width = _decoder->getWidth(); + int height = _decoder->getHeight(); + int x = (Screen::SCREEN_W - width) / 2; + int y = (Screen::SCREEN_H - height) / 2; - if (_vm->_mixer->isSoundHandleActive(_sound)) - elapsedTime = _vm->_mixer->getSoundElapsedTime(_sound); - else - elapsedTime = _system->getMillis() - startTick; + _decoder->start(); - if (elapsedTime >= (i * 1000) / _header.frameRate) - break; + // Note that decoding starts at frame -1. That's because there + // is usually sound data before the first frame, probably to + // avoid sound underflow. + while (!_decoder->endOfVideo()) { Common::Event event; while (eventMan->pollEvent(event)) { switch (event.type) { @@ -673,23 +635,32 @@ void VQAMovie::play() { if (event.kbd.keycode == Common::KEYCODE_ESCAPE) return; break; - case Common::EVENT_RTL: case Common::EVENT_QUIT: return; - default: break; } } + if (_decoder->needsUpdate()) { + const Graphics::Surface *surface = _decoder->decodeNextFrame(); + if (_decoder->hasDirtyPalette()) { + const byte *decoderPalette = _decoder->getPalette(); + byte systemPalette[256 * 3]; + for (int i = 0; i < ARRAYSIZE(systemPalette); i++) { + systemPalette[i] = (decoderPalette[i] * 0xFF) / 0x3F; + } + _system->getPaletteManager()->setPalette(systemPalette, 0, 256); + } + + _system->copyRectToScreen((const byte *)surface->getBasePtr(0, 0), surface->pitch, x, y, width, height); + } + + _system->updateScreen(); _system->delayMillis(10); } - - _screen->updateScreen(); } - - // TODO: Wait for the sound to finish? } } // End of namespace Kyra diff --git a/engines/kyra/vqa.h b/engines/kyra/vqa.h index 839bf5ac48..f3890107a8 100644 --- a/engines/kyra/vqa.h +++ b/engines/kyra/vqa.h @@ -23,9 +23,9 @@ #ifndef KYRA_VQA_H #define KYRA_VQA_H -#include "common/scummsys.h" - -#include "audio/mixer.h" +#include "video/video_decoder.h" +#include "common/file.h" +#include "common/rational.h" class OSystem; @@ -33,40 +33,24 @@ namespace Audio { class QueuingAudioStream; } // End of namespace Audio -namespace Common { -class SeekableReadStream; -} // End of namespace Common - namespace Kyra { class KyraEngine_v1; class Screen; -class VQAMovie { +class VQADecoder : public Video::VideoDecoder { public: - VQAMovie(KyraEngine_v1 *vm, OSystem *system); - ~VQAMovie(); + VQADecoder(); + virtual ~VQADecoder(); - bool opened() { return _opened; } - int frames() { return _opened ? _header.numFrames : -1; } + bool loadStream(Common::SeekableReadStream *stream); + void readNextPacket(); - // It's unlikely that we ever want to change the movie position from - // its default. +private: + Common::SeekableReadStream *_fileStream; - void setDrawPage(int page) { _drawPage = page; } - - bool open(const char *filename); - void close(); - void play(); - -protected: - OSystem *_system; - KyraEngine_v1 *_vm; - Screen *_screen; - - bool _opened; - int _x, _y; - int _drawPage; + void handleVQHD(Common::SeekableReadStream *stream); + void handleFINF(Common::SeekableReadStream *stream); struct VQAHeader { uint16 version; @@ -91,40 +75,85 @@ protected: uint32 unk5; }; - struct Buffer { - uint8 *data; - uint32 size; - }; - - Buffer _buffers[2]; - - void initBuffers(); - void *allocBuffer(int num, uint32 size); - void freeBuffers(); + VQAHeader _header; + uint32 *_frameInfo; - void decodeSND1(byte *inbuf, uint32 insize, byte *outbuf, uint32 outsize); + class VQAAudioTrack : public AudioTrack { + public: + VQAAudioTrack(const VQAHeader *header); + ~VQAAudioTrack(); - void displayFrame(uint frameNum); + void handleSND0(Common::SeekableReadStream *stream); + void handleSND1(Common::SeekableReadStream *stream); + void handleSND2(Common::SeekableReadStream *stream); - Common::SeekableReadStream *_file; + protected: + Audio::AudioStream *getAudioStream() const; - VQAHeader _header; - uint32 *_frameInfo; - uint32 _codeBookSize; - byte *_codeBook; - byte *_partialCodeBook; - bool _compressedCodeBook; - int _partialCodeBookSize; - int _numPartialCodeBooks; - uint32 _numVectorPointers; - uint16 *_vectorPointers; + private: + Audio::QueuingAudioStream *_audioStream; + }; - byte *_frame; + class VQAVideoTrack : public FixedRateVideoTrack { + public: + VQAVideoTrack(const VQAHeader *header); + ~VQAVideoTrack(); + + uint16 getWidth() const; + uint16 getHeight() const; + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const; + int getFrameCount() const; + const Graphics::Surface *decodeNextFrame(); + + void setHasDirtyPalette(); + bool hasDirtyPalette() const; + const byte *getPalette() const; + + void handleVQFR(Common::SeekableReadStream *stream); + + protected: + Common::Rational getFrameRate() const; + + private: + Graphics::Surface *_surface; + byte _palette[3 * 256]; + mutable bool _dirtyPalette; + + bool _newFrame; + + uint16 _width, _height; + uint8 _blockW, _blockH; + uint8 _cbParts; + int _frameCount; + int _curFrame; + byte _frameRate; + + uint32 _codeBookSize; + bool _compressedCodeBook; + byte *_codeBook; + int _partialCodeBookSize; + int _numPartialCodeBooks; + byte *_partialCodeBook; + uint32 _numVectorPointers; + uint16 *_vectorPointers; + }; +}; - Audio::QueuingAudioStream *_stream; - Audio::SoundHandle _sound; +class VQAMovie { +public: + VQAMovie(KyraEngine_v1 *vm, OSystem *system); + ~VQAMovie(); - uint32 readTag(); + bool open(const char *filename); + void close(); + void play(); +private: + OSystem *_system; + KyraEngine_v1 *_vm; + Screen *_screen; + VQADecoder *_decoder; + Common::File _file; }; } // End of namespace Kyra diff --git a/engines/mortevielle/actions.cpp b/engines/mortevielle/actions.cpp index 6f57019cf2..c5d55066ba 100644 --- a/engines/mortevielle/actions.cpp +++ b/engines/mortevielle/actions.cpp @@ -208,22 +208,31 @@ void MortevielleEngine::fctTake() { if (_currBitIndex > 0) _coreVar._faithScore += 3; if (_obpart) { - if (_coreVar._currPlace == PURPLE_ROOM) + switch (_coreVar._currPlace) { + case PURPLE_ROOM: _coreVar._purpleRoomObjectId = 0; - if (_coreVar._currPlace == ATTIC) { + break; + case ATTIC: if (_coreVar._atticBallHoleObjectId == _caff) _coreVar._atticBallHoleObjectId = 0; if (_coreVar._atticRodHoleObjectId == _caff) _coreVar._atticRodHoleObjectId = 0; - } - if (_coreVar._currPlace == CELLAR) + break; + case CELLAR: _coreVar._cellarObjectId = 0; - if (_coreVar._currPlace == CRYPT) + break; + case CRYPT: _coreVar._cryptObjectId = 0; - if (_coreVar._currPlace == SECRET_PASSAGE) + break; + case SECRET_PASSAGE: _coreVar._secretPassageObjectId = 0; - if (_coreVar._currPlace == WELL) + break; + case WELL: _coreVar._wellObjectId = 0; + break; + default: + break; + } _menu->unsetSearchMenu(); _obpart = false; prepareDisplayText(); @@ -258,38 +267,54 @@ void MortevielleEngine::fctTake() { if (_currBitIndex > 0) _coreVar._faithScore += 3; _crep = 997; - if ((_coreVar._currPlace == PURPLE_ROOM) && (_coreVar._purpleRoomObjectId != 0)) - putInHand(_coreVar._purpleRoomObjectId); - if ((_coreVar._currPlace == ATTIC) && (_num == 1) && (_coreVar._atticBallHoleObjectId != 0)) { - putInHand(_coreVar._atticBallHoleObjectId); - if ((_crep != 997) && (_crep != 139)) - displayAnimFrame(2, 7); - } - if ((_coreVar._currPlace == ATTIC) && (_num == 2) && (_coreVar._atticRodHoleObjectId != 0)) { - putInHand(_coreVar._atticRodHoleObjectId); - if ((_crep != 997) && (_crep != 139)) - displayAnimFrame(2, 6); - } - if ((_coreVar._currPlace == CELLAR) && (_coreVar._cellarObjectId != 0)) { - putInHand(_coreVar._cellarObjectId); - if ((_crep != 997) && (_crep != 139)) - displayAnimFrame(2, 2); - } - if ((_coreVar._currPlace == CRYPT) && (_coreVar._cryptObjectId != 0)) - putInHand(_coreVar._cryptObjectId); - - if ((_coreVar._currPlace == SECRET_PASSAGE) && (_coreVar._secretPassageObjectId != 0)) { - putInHand(_coreVar._secretPassageObjectId); - if ((_crep != 997) && (_crep != 139)) { - _crep = 182; - displayAnimFrame(2, 1); + + switch (_coreVar._currPlace) { + case PURPLE_ROOM: + if (_coreVar._purpleRoomObjectId != 0) + putInHand(_coreVar._purpleRoomObjectId); + break; + case ATTIC: + if ((_num == 1) && (_coreVar._atticBallHoleObjectId != 0)) { + putInHand(_coreVar._atticBallHoleObjectId); + if ((_crep != 997) && (_crep != 139)) + displayAnimFrame(2, 7); + } else if ((_num == 2) && (_coreVar._atticRodHoleObjectId != 0)) { + putInHand(_coreVar._atticRodHoleObjectId); + if ((_crep != 997) && (_crep != 139)) + displayAnimFrame(2, 6); } + break; + case CELLAR: + if (_coreVar._cellarObjectId != 0) { + putInHand(_coreVar._cellarObjectId); + if ((_crep != 997) && (_crep != 139)) + displayAnimFrame(2, 2); + } + break; + case CRYPT: + if (_coreVar._cryptObjectId != 0) + putInHand(_coreVar._cryptObjectId); + break; + case SECRET_PASSAGE: + if (_coreVar._secretPassageObjectId != 0) { + putInHand(_coreVar._secretPassageObjectId); + if ((_crep != 997) && (_crep != 139)) { + _crep = 182; + displayAnimFrame(2, 1); + } + } + break; + case WELL: + if (_coreVar._wellObjectId != 0) { + putInHand(_coreVar._wellObjectId); + if ((_crep != 997) && (_crep != 139)) + displayAnimFrame(2, 1); + } + break; + default: + break; } - if ((_coreVar._currPlace == WELL) && (_coreVar._wellObjectId != 0)) { - putInHand(_coreVar._wellObjectId); - if ((_crep != 997) && (_crep != 139)) - displayAnimFrame(2, 1); - } + if ((_crep != 997) && (_crep != 182) && (_crep != 139)) _crep = 999; } @@ -1178,7 +1203,7 @@ void MortevielleEngine::fctEnter() { _coreVar._availableQuestion[8] = '*'; } else { int pres = 0; - if (!_blo) + if (!_outsideOnlyFl) pres = getPresence(_roomDoorId); if (pres != 0) { if ((_roomDoorId == TOILETS) || (_roomDoorId == BATHROOM)) @@ -1337,7 +1362,7 @@ void MortevielleEngine::fctWait() { do { ++_currentHourCount; prepareRoom(); - if (!_blo) + if (!_outsideOnlyFl) getPresence(_coreVar._currPlace); if ((_currBitIndex != 0) && (_savedBitIndex == 0)) { _crep = 998; diff --git a/engines/mortevielle/configure.engine b/engines/mortevielle/configure.engine index 14d6479e7a..a7fb2ccda6 100644 --- a/engines/mortevielle/configure.engine +++ b/engines/mortevielle/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine mortevielle "Mortevielle" no +add_engine mortevielle "Mortevielle" yes diff --git a/engines/mortevielle/menu.cpp b/engines/mortevielle/menu.cpp index 14fc8d4084..7979e3ce7f 100644 --- a/engines/mortevielle/menu.cpp +++ b/engines/mortevielle/menu.cpp @@ -56,7 +56,26 @@ Menu::Menu(MortevielleEngine *vm) { _opcodePlace = _opcodeOpen = _opcodeTake = _opcodeLook = OPCODE_NONE; _opcodeSmell = _opcodeSound = _opcodeLeave = _opcodeLift = OPCODE_NONE; _opcodeTurn = _opcodeSHide = _opcodeSSearch = _opcodeSRead = OPCODE_NONE; - _opcodeSPut = _opcodeSLook = OPCODE_NONE; + _opcodeSPut = _opcodeSLook = _msg3 = _msg4 = OPCODE_NONE; + + _menuActive = false; + _menuSelected = false; + _multiTitle = false; + _menuDisplayed = false; + for (int i = 0; i < 9; i++) { + _discussMenu[i]._menuId = MENU_NONE; + _discussMenu[i]._actionId = 0; + _inventoryMenu[i]._menuId = MENU_NONE; + _inventoryMenu[i]._actionId = 0; + } + for (int i = 0; i < 8; i++) { + _moveMenu[i]._menuId = MENU_NONE; + _moveMenu[i]._actionId = 0; + } + for (int i = 0; i < 12; i++) { + _actionMenu[i]._menuId = MENU_NONE; + _actionMenu[i]._actionId = 0; + } } void Menu::readVerbNums(Common::File &f, int dataSize) { diff --git a/engines/mortevielle/mortevielle.cpp b/engines/mortevielle/mortevielle.cpp index 34372ba32a..49876f1bf2 100644 --- a/engines/mortevielle/mortevielle.cpp +++ b/engines/mortevielle/mortevielle.cpp @@ -83,7 +83,7 @@ MortevielleEngine::MortevielleEngine(OSystem *system, const MortevielleGameDescr _keyPressedEsc = false; _reloadCFIEC = false; - _blo = false; + _outsideOnlyFl = true; _col = false; _syn = false; _obpart = false; @@ -101,6 +101,50 @@ MortevielleEngine::MortevielleEngine(OSystem *system, const MortevielleGameDescr _curPict = nullptr; _curAnim = nullptr; _rightFramePict = nullptr; + + resetCoreVar(); + + _maff = 0; + _crep = 0; + + _minute = 0; + _curSearchObjId = 0; + _controlMenu = 0; + _startTime = 0; + _endTime = 0; + _roomDoorId = OWN_ROOM; + _openObjCount = 0; + _takeObjCount = 0; + _num = 0; + _searchCount = 0; + _introSpeechPlayed = false; + _inGameHourDuration = 0; + _x = 0; + _y = 0; + _currentHourCount = 0; + _currentTime = 0; + _cfiecBuffer = nullptr; + _cfiecBufferSize = 0; + for (int i = 0; i < 601; i++) { + _dialogHintArray[i]._hintId = 0; + _dialogHintArray[i]._point = 0; + } + _currMenu = OPCODE_NONE; + _currAction = OPCODE_NONE; + _menuOpcode = OPCODE_NONE; + _addFix = 0; + _currBitIndex = 0; + _currDay = 0; + _currHour = 10; + _currHalfHour = 0; + _hour = 10; + _key = 0; + _manorDistance = 0; + _numpal = 0; + _savedBitIndex = 0; + _endGame = false; + _loseGame = false; + _txxFileFl = false; } MortevielleEngine::~MortevielleEngine() { diff --git a/engines/mortevielle/mortevielle.h b/engines/mortevielle/mortevielle.h index 579e495b65..7a673f42f9 100644 --- a/engines/mortevielle/mortevielle.h +++ b/engines/mortevielle/mortevielle.h @@ -122,7 +122,6 @@ const int kMaxPatt = 20; const int kResolutionScaler = 2; /* -9 "A glance at the forbidden$", 18 "It's already open$", 26 "A photograph$" */ @@ -135,11 +134,6 @@ enum Places { DOOR = 25, ROOM26 = 26, COAT_ARMS = 27 }; -struct Pattern { - byte _tay, _tax; - byte _des[kMaxPatt + 1][kMaxPatt + 1]; -}; - struct SaveStruct { int _faithScore; byte _pctHintFound[11]; @@ -391,6 +385,7 @@ private: void prepareNextObject(); void putObject(); void resetObjectPlace(); + void resetCoreVar(); void drawDiscussionBox(); void displayNarrativePicture(int af, int ob); void menuUp(); @@ -407,7 +402,7 @@ public: int _charAnswerMax[9]; byte _tabdon[4001]; bool _soundOff; - bool _blo; + bool _outsideOnlyFl; bool _destinationOk; bool _largestClearScreen; float _addFix; diff --git a/engines/mortevielle/outtext.cpp b/engines/mortevielle/outtext.cpp index 2518b317d5..b359860a82 100644 --- a/engines/mortevielle/outtext.cpp +++ b/engines/mortevielle/outtext.cpp @@ -299,7 +299,7 @@ void TextHandler::taffich() { if ((a < COAT_ARMS) && ((_vm->_maff < COAT_ARMS) || (_vm->_coreVar._currPlace == LANDING)) && (_vm->_currAction != _vm->_menu->_opcodeEnter)) { if ((a == ATTIC) || (a == CELLAR)) _vm->displayAloneText(); - else if (!_vm->_blo) + else if (!_vm->_outsideOnlyFl) _vm->getPresence(_vm->_coreVar._currPlace); _vm->_savedBitIndex = 0; } diff --git a/engines/mortevielle/sound.cpp b/engines/mortevielle/sound.cpp index c39c8e7024..db1f7578f1 100644 --- a/engines/mortevielle/sound.cpp +++ b/engines/mortevielle/sound.cpp @@ -73,6 +73,8 @@ SoundManager::SoundManager(MortevielleEngine *vm, Audio::Mixer *mixer) { _queue[i]._rep = 0; } _buildingSentence = false; + _ptr_oct = 0; + _cfiphBuffer = nullptr; } SoundManager::~SoundManager() { diff --git a/engines/mortevielle/utils.cpp b/engines/mortevielle/utils.cpp index 6e0f266f9b..29c9be2e0c 100644 --- a/engines/mortevielle/utils.cpp +++ b/engines/mortevielle/utils.cpp @@ -466,7 +466,7 @@ int MortevielleEngine::convertBitIndexToCharacterIndex(int bitIndex) { */ void MortevielleEngine::resetPresenceInRooms(int roomId) { if (roomId == DINING_ROOM) - _blo = false; + _outsideOnlyFl = false; if (roomId != GREEN_ROOM) { _roomPresenceLuc = false; @@ -1080,7 +1080,7 @@ void MortevielleEngine::initGame() { _place = MANOR_FRONT; _currentHourCount = 0; if (!_coreVar._alreadyEnteredManor) - _blo = true; + _outsideOnlyFl = true; _inGameHourDuration = kTime1; _currentTime = readclock(); } @@ -1285,7 +1285,7 @@ void MortevielleEngine::loseGame() { _roomDoorId = OWN_ROOM; _curSearchObjId = 0; _menu->unsetSearchMenu(); - if (!_blo) + if (!_outsideOnlyFl) getPresence(MANOR_FRONT); _loseGame = true; @@ -1393,7 +1393,7 @@ void MortevielleEngine::gotoDiningRoom() { _coreVar._currPlace = OWN_ROOM; prepareDisplayText(); resetPresenceInRooms(DINING_ROOM); - if (!_blo) + if (!_outsideOnlyFl) getPresence(OWN_ROOM); _currBitIndex = 0; _savedBitIndex = 0; @@ -1888,24 +1888,18 @@ void MortevielleEngine::resetObjectPlace() { _tabdon[i] = _tabdon[i + 390]; } -/** - * Engine function - When restarting the game, reset the main variables used by the engine - * @remarks Originally called 'inzon' - */ -void MortevielleEngine::resetVariables() { - resetObjectPlace(); - - _coreVar._alreadyEnteredManor = false; - _coreVar._selectedObjectId = 0; - _coreVar._cellarObjectId = 0; - _coreVar._atticBallHoleObjectId = 0; - _coreVar._atticRodHoleObjectId = 0; - _coreVar._wellObjectId = 0; - _coreVar._secretPassageObjectId = 0; - _coreVar._purpleRoomObjectId = 136; - _coreVar._cryptObjectId = 141; - _coreVar._faithScore = getRandomNumber(4, 10); - _coreVar._currPlace = MANOR_FRONT; +void MortevielleEngine::resetCoreVar() { + _saveStruct._alreadyEnteredManor = _coreVar._alreadyEnteredManor = false; + _saveStruct._selectedObjectId = _coreVar._selectedObjectId = 0; + _saveStruct._cellarObjectId = _coreVar._cellarObjectId = 0; + _saveStruct._atticBallHoleObjectId = _coreVar._atticBallHoleObjectId = 0; + _saveStruct._atticRodHoleObjectId = _coreVar._atticRodHoleObjectId = 0; + _saveStruct._wellObjectId = _coreVar._wellObjectId = 0; + _saveStruct._secretPassageObjectId = _coreVar._secretPassageObjectId = 0; + _saveStruct._purpleRoomObjectId = _coreVar._purpleRoomObjectId = 136; + _saveStruct._cryptObjectId = _coreVar._cryptObjectId = 141; + _saveStruct._faithScore = _coreVar._faithScore = getRandomNumber(4, 10); + _saveStruct._currPlace = _coreVar._currPlace = MANOR_FRONT; for (int i = 2; i <= 6; ++i) _coreVar._inventory[i] = 0; @@ -1913,7 +1907,7 @@ void MortevielleEngine::resetVariables() { // Only object in inventory: a gun _coreVar._inventory[1] = 113; - _coreVar._fullHour = (unsigned char)20; + _saveStruct._fullHour = _coreVar._fullHour = (unsigned char)20; for (int i = 1; i <= 10; ++i) _coreVar._pctHintFound[i] = ' '; @@ -1931,6 +1925,14 @@ void MortevielleEngine::resetVariables() { _coreVar._availableQuestion[i] = ' '; _coreVar._availableQuestion[33] = '*'; +} +/** + * Engine function - When restarting the game, reset the main variables used by the engine + * @remarks Originally called 'inzon' + */ +void MortevielleEngine::resetVariables() { + resetObjectPlace(); + resetCoreVar(); for (int i = 1; i <= 8; ++i) _charAnswerCount[i] = 0; @@ -2208,7 +2210,7 @@ void MortevielleEngine::prepareRoom() { if (_mouse->_pos.y < 12) return; - if (!_blo) { + if (!_outsideOnlyFl) { if ((hour == 12) || ((hour > 18) && (hour < 21)) || ((hour >= 0) && (hour < 7))) _inGameHourDuration = kTime2; else diff --git a/engines/neverhood/modules/module1100.cpp b/engines/neverhood/modules/module1100.cpp index e7dd6e4210..e40508e502 100644 --- a/engines/neverhood/modules/module1100.cpp +++ b/engines/neverhood/modules/module1100.cpp @@ -136,15 +136,20 @@ void Module1100::updateScene() { switch (_sceneNum) { case 0: _countdown = 0; - _vm->_soundMan->playTwoSounds(0x0002C818, 0x48498E46, 0x50399F64, 0); _vm->_soundMan->setSoundVolume(0x48498E46, 65); _vm->_soundMan->setSoundVolume(0x50399F64, 65); - if (_moduleResult == 0) + if (_moduleResult == 0) { + _vm->_soundMan->playTwoSounds(0x0002C818, 0x48498E46, 0x50399F64, 0); createScene(1, 0); - else if (_moduleResult == 1) + } else if (_moduleResult == 1) { + /* NOTE This fixes a bug in the original where the "tunnel" footstep + sounds are played instead of the correct footsteps. */ + _vm->_soundMan->playTwoSounds(0x0002C818, 0x41861371, 0x43A2507F, 0); createScene(8, 0); + } break; case 1: + _countdown = 0; _vm->_soundMan->playTwoSounds(0x0002C818, 0x41861371, 0x43A2507F, 0); if (getGlobalVar(V_ROBOT_HIT)) { if (_moduleResult == 0) diff --git a/engines/neverhood/sound.cpp b/engines/neverhood/sound.cpp index 04043692f8..023eda4c02 100644 --- a/engines/neverhood/sound.cpp +++ b/engines/neverhood/sound.cpp @@ -558,8 +558,10 @@ int NeverhoodAudioStream::readBuffer(int16 *buffer, const int numSamples) { *buffer++ = _prevValue << _shiftValue; } } else { - memcpy(buffer, _buffer, bytesRead); - buffer += samplesRead; + while (samplesRead--) { + *buffer++ = READ_LE_UINT16(src); + src += 2; + } } if (bytesRead < bytesToRead || _stream->pos() >= _stream->size() || _stream->err() || _stream->eos()) { diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp index 374f7208d8..caab1d80da 100644 --- a/engines/sci/graphics/picture.cpp +++ b/engines/sci/graphics/picture.cpp @@ -283,8 +283,6 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos // That needs to be done cause a mirrored picture may be requested pixelCount = width * height; celBitmap = new byte[pixelCount]; - if (!celBitmap) - error("Unable to allocate temporary memory for picture drawing"); if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2) { // See GfxView::unpackCel() for why this black/white swap is done diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp index 6d9dc03195..ed0013b491 100644 --- a/engines/sci/graphics/ports.cpp +++ b/engines/sci/graphics/ports.cpp @@ -300,11 +300,6 @@ Window *GfxPorts::addWindow(const Common::Rect &dims, const Common::Rect *restor Window *pwnd = new Window(id); Common::Rect r; - if (!pwnd) { - error("Can't open window"); - return 0; - } - _windowsById[id] = pwnd; // KQ1sci, KQ4, iceman, QfG2 always add windows to the back of the list. diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp index 6f250e0a3a..f776eb9b8d 100644 --- a/engines/sci/sound/midiparser_sci.cpp +++ b/engines/sci/sound/midiparser_sci.cpp @@ -601,11 +601,10 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) { }// switch (info.command()) } -void MidiParser_SCI::processEvent(const EventInfo &info, bool fireEvents) { +bool MidiParser_SCI::processEvent(const EventInfo &info, bool fireEvents) { if (!fireEvents) { // We don't do any processing that should be done while skipping events - MidiParser::processEvent(info, fireEvents); - return; + return MidiParser::processEvent(info, fireEvents); } switch (info.command()) { @@ -657,7 +656,7 @@ void MidiParser_SCI::processEvent(const EventInfo &info, bool fireEvents) { } // Done with this event. - return; + return true; } // Break to let parent handle the rest. @@ -684,7 +683,7 @@ void MidiParser_SCI::processEvent(const EventInfo &info, bool fireEvents) { switch (info.basic.param1) { case kSetReverb: // Already handled above - return; + return true; case kMidiHold: // Check if the hold ID marker is the same as the hold ID // marker set for that song by cmdSetSoundHold. @@ -692,9 +691,9 @@ void MidiParser_SCI::processEvent(const EventInfo &info, bool fireEvents) { if (info.basic.param2 == _pSnd->hold) { jumpToTick(_loopTick, false, false); // Done with this event. - return; + return true; } - return; + return true; case kUpdateCue: if (!_jumpingToTick) { int inc; @@ -715,17 +714,17 @@ void MidiParser_SCI::processEvent(const EventInfo &info, bool fireEvents) { debugC(4, kDebugLevelSound, "datainc %04x", inc); } - return; + return true; case kResetOnPause: _resetOnPause = info.basic.param2; - return; + return true; // Unhandled SCI commands case 0x46: // LSL3 - binoculars case 0x61: // Iceman (AdLib?) case 0x73: // Hoyle case 0xD1: // KQ4, when riding the unicorn // Obscure SCI commands - ignored - return; + return true; // Standard MIDI commands case 0x01: // mod wheel case 0x04: // foot controller @@ -740,10 +739,10 @@ void MidiParser_SCI::processEvent(const EventInfo &info, bool fireEvents) { case 0x4B: // voice mapping // TODO: is any support for this needed at the MIDI parser level? warning("Unhanded SCI MIDI command 0x%x - voice mapping (parameter %d)", info.basic.param1, info.basic.param2); - return; + return true; default: warning("Unhandled SCI MIDI command 0x%x (parameter %d)", info.basic.param1, info.basic.param2); - return; + return true; } } @@ -762,7 +761,7 @@ void MidiParser_SCI::processEvent(const EventInfo &info, bool fireEvents) { jumpToTick(_loopTick); // Done with this event. - return; + return true; } else { _pSnd->status = kSoundStopped; @@ -782,7 +781,7 @@ void MidiParser_SCI::processEvent(const EventInfo &info, bool fireEvents) { // Let parent handle the rest - MidiParser::processEvent(info, fireEvents); + return MidiParser::processEvent(info, fireEvents); } byte MidiParser_SCI::getSongReverb() { diff --git a/engines/sci/sound/midiparser_sci.h b/engines/sci/sound/midiparser_sci.h index 7e24c34144..7c3c5c3483 100644 --- a/engines/sci/sound/midiparser_sci.h +++ b/engines/sci/sound/midiparser_sci.h @@ -89,7 +89,7 @@ public: protected: void parseNextEvent(EventInfo &info); - void processEvent(const EventInfo &info, bool fireEvents = true); + bool processEvent(const EventInfo &info, bool fireEvents = true); byte *midiMixChannels(); byte *midiFilterChannels(int channelMask); byte midiGetNextChannel(long ticker); diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp index d01b456c8b..c736c6a04c 100644 --- a/engines/scumm/he/animation_he.cpp +++ b/engines/scumm/he/animation_he.cpp @@ -57,7 +57,7 @@ int MoviePlayer::getImageNum() { return _wizResNum; } -int MoviePlayer::load(const char *filename, int flags, int image) { +int MoviePlayer::load(const Common::String &filename, int flags, int image) { if (_video->isVideoLoaded()) _video->close(); @@ -65,13 +65,13 @@ int MoviePlayer::load(const char *filename, int flags, int image) { _video->setDefaultHighColorFormat(g_system->getScreenFormat()); if (!_video->loadFile(filename)) { - warning("Failed to load video file %s", filename); + warning("Failed to load video file %s", filename.c_str()); return -1; } _video->start(); - debug(1, "Playing video %s", filename); + debug(1, "Playing video %s", filename.c_str()); if (flags & 2) _vm->_wiz->createWizEmptyImage(image, 0, 0, _video->getWidth(), _video->getHeight()); diff --git a/engines/scumm/he/animation_he.h b/engines/scumm/he/animation_he.h index e17c1b9a39..48234b8072 100644 --- a/engines/scumm/he/animation_he.h +++ b/engines/scumm/he/animation_he.h @@ -25,8 +25,12 @@ #include "audio/mixer.h" +namespace Common { +class String; +} + namespace Video { - class VideoDecoder; +class VideoDecoder; } namespace Scumm { @@ -39,7 +43,7 @@ public: ~MoviePlayer(); int getImageNum(); - int load(const char *filename, int flags, int image = 0); + int load(const Common::String &filename, int flags, int image = 0); void copyFrameToBuffer(byte *dst, int dstType, uint x, uint y, uint pitch); void handleNextFrame(); diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h index a674288775..067f508d2c 100644 --- a/engines/scumm/he/intern_he.h +++ b/engines/scumm/he/intern_he.h @@ -81,10 +81,23 @@ protected: int virtScreenSave(byte *dst, int x1, int y1, int x2, int y2); void virtScreenLoad(int resIdx, int x1, int y1, int x2, int y2); - int convertFilePath(byte *dst, int dstSize); virtual void decodeParseString(int a, int b); void swapObjects(int object1, int object2); + Common::String convertFilePath(const byte *src); + Common::String convertSavePath(const byte *src); + Common::String convertSavePathOld(const byte *src); + + Common::SeekableReadStream *openFileForReading(const byte *fileName); + Common::SeekableReadStream *openSaveFileForReading(const byte *fileName); + Common::WriteStream *openSaveFileForWriting(const byte *fileName); + Common::WriteStream *openSaveFileForAppending(const byte *fileName); + void deleteSaveFile(const byte *fileName); + void renameSaveFile(const byte *from, const byte *to); + + Common::SeekableReadStream *openSaveFileForReading(int slot, bool compat, Common::String &fileName); + Common::WriteStream *openSaveFileForWriting(int slot, bool compat, Common::String &fileName); + /* HE version 60 script opcodes */ void o60_setState(); void o60_roomOps(); diff --git a/engines/scumm/he/logic/football.cpp b/engines/scumm/he/logic/football.cpp index ea990ca86b..215fdf0179 100644 --- a/engines/scumm/he/logic/football.cpp +++ b/engines/scumm/he/logic/football.cpp @@ -449,25 +449,26 @@ int LogicHEfootball2002::initScreenTranslations() { int LogicHEfootball2002::getPlaybookFiles(int32 *args) { // Get the pattern and then skip over the directory prefix ("*\" or "*:") - Common::String pattern = (const char *)_vm->getStringAddress(args[0] & ~0x33539000) + 2; + // Also prepend the target name + Common::String targetName = _vm->getTargetName(); + Common::String basePattern = ((const char *)_vm->getStringAddress(args[0] & ~0x33539000) + 2); + Common::String pattern = targetName + '-' + basePattern; // Prepare a buffer to hold the file names - char buffer[1000]; - buffer[0] = 0; + Common::String output; // Get the list of file names that match the pattern and iterate over it Common::StringArray fileList = _vm->getSaveFileManager()->listSavefiles(pattern); - for (uint32 i = 0; i < fileList.size() && strlen(buffer) < 970; i++) { + for (uint32 i = 0; i < fileList.size(); i++) { // Isolate the base part of the filename and concatenate it to our buffer - Common::String fileName = Common::String(fileList[i].c_str(), fileList[i].size() - (pattern.size() - 1)); - strcat(buffer, fileName.c_str()); - strcat(buffer, ">"); // names separated by '>' + Common::String fileName(fileList[i].c_str() + targetName.size() + 1, fileList[i].size() - (basePattern.size() - 1) - (targetName.size() + 1)); + output += fileName + '>'; // names separated by '>' } // Now store the result in an array - int array = _vm->setupStringArray(strlen(buffer)); - strcpy((char *)_vm->getStringAddress(array), buffer); + int array = _vm->setupStringArray(output.size()); + strcpy((char *)_vm->getStringAddress(array), output.c_str()); // And store the array index in variable 108 writeScummVar(108, array); diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp index 987f74957c..c26e3f57ea 100644 --- a/engines/scumm/he/script_v100he.cpp +++ b/engines/scumm/he/script_v100he.cpp @@ -1642,7 +1642,7 @@ void ScummEngine_v100he::o100_roomOps() { copyScriptString((byte *)buffer, sizeof(buffer)); - _saveLoadFileName = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); + _saveLoadFileName = (char *)buffer; debug(1, "o100_roomOps: case 137: filename %s", _saveLoadFileName.c_str()); _saveLoadFlag = pop(); @@ -2263,11 +2263,10 @@ void ScummEngine_v100he::o100_videoOps() { if (_videoParams.flags == 0) _videoParams.flags = 4; - const char *filename = (char *)_videoParams.filename + convertFilePath(_videoParams.filename, sizeof(_videoParams.filename)); if (_videoParams.flags == 2) { - VAR(119) = _moviePlay->load(filename, _videoParams.flags, _videoParams.wizResNum); + VAR(119) = _moviePlay->load(convertFilePath(_videoParams.filename), _videoParams.flags, _videoParams.wizResNum); } else { - VAR(119) = _moviePlay->load(filename, _videoParams.flags); + VAR(119) = _moviePlay->load(convertFilePath(_videoParams.filename), _videoParams.flags); } } else if (_videoParams.status == 19) { // Stop video diff --git a/engines/scumm/he/script_v60he.cpp b/engines/scumm/he/script_v60he.cpp index bbd8725904..409fb7edf7 100644 --- a/engines/scumm/he/script_v60he.cpp +++ b/engines/scumm/he/script_v60he.cpp @@ -90,59 +90,214 @@ void ScummEngine_v60he::setupOpcodes() { _opcodes[0xed].setProc(0, 0); } -int ScummEngine_v60he::convertFilePath(byte *dst, int dstSize) { - debug(1, "convertFilePath: original filePath is %s", dst); - - int len = resStrLen(dst); - - // Switch all \ to / for portablity - for (int i = 0; i < len; i++) - if (dst[i] == '\\') - dst[i] = '/'; - - if (_game.platform == Common::kPlatformMacintosh) { - // Remove : prefix in HE71 games - if (dst[0] == ':') { - len -= 1; - memmove(dst, dst + 1, len); - dst[len] = 0; +Common::String ScummEngine_v60he::convertFilePath(const byte *src) { + debug(2, "convertFilePath in: '%s'", (const char *)src); + + int srcSize = resStrLen(src); + int start = 0; + + if (srcSize > 2) { + if (src[0] == ':') { // Game Data Path (Macintosh) + // The default game data path is set to ':' by ScummVM + start = 1; + } else if (src[0] == '.' && src[1] == '\\') { // Game Data Path (Windows) + // The default game data path is set to '.\\' by ScummVM + start = 2; + } else if (src[0] == '*' && src[1] == '\\') { // Save Game Path (Windows HE72 - HE100) + // The default save game path is set to '*\\' by ScummVM + start = 2; + } else if (src[0] == '*' && src[1] == ':') { // Save Game Path (Macintosh HE72 - HE100) + // The default save game path is set to '*:' by ScummVM + start = 2; + } else if (src[0] == 'c' && src[1] == ':') { // Save Game Path (HE60 - HE71) + // The default save path is game path (DOS) or 'c:\\hegames\\' (Windows) + for (start = srcSize; start != 0; start--) + if (src[start - 1] == '\\') + break; + } else if (src[0] == 'u' && src[1] == 's') { // Save Game Path (Moonbase Commander) + // The default save path is 'user\\' + start = 5; } + } - // Switch all : to / for portablity - for (int i = 0; i < len; i++) { - if (dst[i] == ':') - dst[i] = '/'; - } + Common::String dst; + + for (int i = start; i < srcSize; i++) { + // Convert path separators + if (src[i] == '\\' || src[i] == ':') + dst += '/'; + else + dst += src[i]; } - // Strip path - int r = 0; - if (dst[len - 3] == 's' && dst[len - 2] == 'g') { // Save Game File - // Change filename prefix to target name, for save game files. - const char c = dst[len - 1]; - snprintf((char *)dst, dstSize, "%s.sg%c", _targetName.c_str(), c); - } else if (dst[0] == '.' && dst[1] == '/') { // Game Data Path - // The default game data path is set to './' by ScummVM - r = 2; - } else if (dst[0] == '*' && dst[1] == '/') { // Save Game Path (Windows HE72 - HE100) - // The default save game path is set to '*/' by ScummVM - r = 2; - } else if (dst[0] == '*' && dst[1] == ':') { // Save Game Path (Macintosh HE72 - HE100) - // The default save game path is set to ':/' by ScummVM - r = 2; - } else if (dst[0] == 'c' && dst[1] == ':') { // Save Game Path (HE60 - HE71) - // The default save path is game path (DOS) or 'c:/hegames/' (Windows) - for (r = len; r != 0; r--) { - if (dst[r - 1] == '/') - break; + // Sanity check + if (dst.lastChar() == '/') + dst.deleteLastChar(); + + debug(2, "convertFilePath out: '%s'", dst.c_str()); + + return dst; +} + +Common::String ScummEngine_v60he::convertSavePath(const byte *src) { + debug(2, "convertSavePath in: '%s'", (const char *)src); + + Common::String filePath = convertFilePath(src); + + // Strip us down to only the file + for (int32 i = filePath.size() - 1; i >= 0; i--) { + if (filePath[i] == '/') { + filePath = Common::String(filePath.c_str() + i + 1); + break; } - } else if (dst[0] == 'u' && dst[1] == 's') { // Save Game Path (Moonbase Commander) + } + + // Prepend the target name + filePath = _targetName + '-' + filePath; + + debug(2, "convertSavePath out: '%s'", filePath.c_str()); + + return filePath; +} + +Common::String ScummEngine_v60he::convertSavePathOld(const byte *src) { + // This is provided solely for loading older saved games. + // No new saves should go through this function. + + int srcSize = resStrLen(src); + + // Old hacky target name insertion + // (This breaks the soccer and football games) + if (src[srcSize - 3] == 's' && src[srcSize - 2] == 'g') + return _targetName + ".sg" + (char)src[srcSize - 1]; + + if (src[0] == 'u' && src[1] == 's') { + // Save Game Path (Moonbase Commander) // The default save path is 'user/' - r = 5; + return (const char *)src + 5; + } else if (src[0] == '*' && (src[1] == '\\' || src[1] == ':')) { + // Save Game Path (HE72 - HE100) + // The default save game path is set to '*\\' by ScummVM for Windows + // and '*:' for Macintosh + return (const char *)src + 2; + } else if (src[0] == 'c' && src[1] == ':') { + // The default save path is game path (DOS) or 'c:\\hegames\\' (Windows) + for (int i = srcSize; i > 0; i--) + if (src[i] == '\\') + return (const char *)src + i + 1; + } + + // Can't reach here + return ""; +} + +Common::SeekableReadStream *ScummEngine_v60he::openFileForReading(const byte *fileName) { + Common::SeekableReadStream *saveFile = openSaveFileForReading(fileName); + + if (saveFile) + return saveFile; + + return SearchMan.createReadStreamForMember(convertFilePath(fileName)); +} + +Common::SeekableReadStream *ScummEngine_v60he::openSaveFileForReading(const byte *fileName) { + Common::SeekableReadStream *file = _saveFileMan->openForLoading(convertSavePath(fileName)); + + if (file) + return file; + + return _saveFileMan->openForLoading(convertSavePathOld(fileName)); +} + +Common::WriteStream *ScummEngine_v60he::openSaveFileForWriting(const byte *fileName) { + return _saveFileMan->openForSaving(convertSavePath(fileName)); +} + +void ScummEngine_v60he::deleteSaveFile(const byte *fileName) { + Common::String convertedName = convertSavePath(fileName); + + if (!_saveFileMan->listSavefiles(convertedName).empty()) { + _saveFileMan->removeSavefile(convertedName); + return; } - debug(1, "convertFilePath: converted filePath is %s", dst + r); - return r; + convertedName = convertSavePathOld(fileName); + + if (!_saveFileMan->listSavefiles(convertedName).empty()) + _saveFileMan->removeSavefile(convertedName); +} + +void ScummEngine_v60he::renameSaveFile(const byte *from, const byte *to) { + Common::String toName = convertSavePath(to); + + if (_saveFileMan->renameSavefile(convertSavePathOld(from), toName)) + return; + + _saveFileMan->renameSavefile(convertSavePath(from), toName); +} + +Common::WriteStream *ScummEngine_v60he::openSaveFileForAppending(const byte *fileName) { + Common::SeekableReadStream *initialFile = openSaveFileForReading(fileName); + byte *initialData = 0; + uint32 initialDataSize = 0; + + if (initialFile) { + initialDataSize = initialFile->size(); + + if (initialDataSize > 0) { + initialData = new byte[initialDataSize]; + initialFile->read(initialData, initialDataSize); + } + + delete initialFile; + } + + Common::WriteStream *output = openSaveFileForWriting(fileName); + + if (!output) { + delete[] initialData; + return nullptr; + } + + if (initialData) { + output->write(initialData, initialDataSize); + delete[] initialData; + } + + return output; +} + +Common::SeekableReadStream *ScummEngine_v60he::openSaveFileForReading(int slot, bool compat, Common::String &fileName) { + if (slot == 255) { + // HACK: Allow custom filenames for save game system in HE Games + fileName = convertSavePath((const byte *)_saveLoadFileName.c_str()); + + Common::SeekableReadStream *stream = _saveFileMan->openForLoading(fileName); + if (stream) + return stream; + + Common::String oldFileName = convertSavePathOld((const byte *)_saveLoadFileName.c_str()); + stream = _saveFileMan->openForLoading(oldFileName); + + if (stream) { + fileName = oldFileName; + return stream; + } + + return 0; + } + + return ScummEngine::openSaveFileForReading(slot, compat, fileName); +} + +Common::WriteStream *ScummEngine_v60he::openSaveFileForWriting(int slot, bool compat, Common::String &fileName) { + if (slot == 255) { + // HACK: Allow custom filenames for save game system in HE Games + fileName = convertSavePath((const byte *)_saveLoadFileName.c_str()); + return _saveFileMan->openForSaving(fileName); + } + + return ScummEngine::openSaveFileForWriting(slot, compat, fileName); } void ScummEngine_v60he::o60_setState() { @@ -284,7 +439,7 @@ void ScummEngine_v60he::o60_roomOps() { len = resStrLen(_scriptPointer); _scriptPointer += len + 1; - _saveLoadFileName = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); + _saveLoadFileName = (char *)buffer; debug(1, "o60_roomOps: case 221: filename %s", _saveLoadFileName.c_str()); _saveLoadFlag = pop(); @@ -692,14 +847,12 @@ void virtScreenSavePackByte(vsPackCtx *ctx, uint8 *&dst, int len, uint8 b) { void ScummEngine_v60he::o60_openFile() { int mode, len, slot, i; byte buffer[100]; - const char *filename; convertMessageToString(_scriptPointer, buffer, sizeof(buffer)); len = resStrLen(_scriptPointer); _scriptPointer += len + 1; - filename = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); - debug(1, "Final filename to %s", filename); + debug(1, "Trying to open file '%s'", (char *)buffer); mode = pop(); slot = -1; @@ -713,14 +866,10 @@ void ScummEngine_v60he::o60_openFile() { if (slot != -1) { switch (mode) { case 1: - // TODO / FIXME: Consider using listSavefiles to avoid unneccessary openForLoading calls - _hInFileTable[slot] = _saveFileMan->openForLoading(filename); - if (_hInFileTable[slot] == 0) { - _hInFileTable[slot] = SearchMan.createReadStreamForMember(filename); - } + _hInFileTable[slot] = openFileForReading(buffer); break; case 2: - _hOutFileTable[slot] = _saveFileMan->openForSaving(filename); + _hOutFileTable[slot] = openSaveFileForWriting(buffer); break; default: error("o60_openFile(): wrong open file mode %d", mode); @@ -750,25 +899,19 @@ void ScummEngine_v60he::o60_closeFile() { void ScummEngine_v60he::o60_deleteFile() { int len; byte buffer[100]; - const char *filename; convertMessageToString(_scriptPointer, buffer, sizeof(buffer)); len = resStrLen(_scriptPointer); _scriptPointer += len + 1; - filename = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); - - debug(1, "o60_deleteFile (\"%s\")", filename); + debug(1, "o60_deleteFile (\"%s\")", (char *)buffer); - if (!_saveFileMan->listSavefiles(filename).empty()) { - _saveFileMan->removeSavefile(filename); - } + deleteSaveFile(buffer); } void ScummEngine_v60he::o60_rename() { int len; byte buffer1[100], buffer2[100]; - const char *newFilename, *oldFilename; convertMessageToString(_scriptPointer, buffer1, sizeof(buffer1)); len = resStrLen(_scriptPointer); @@ -778,12 +921,9 @@ void ScummEngine_v60he::o60_rename() { len = resStrLen(_scriptPointer); _scriptPointer += len + 1; - oldFilename = (char *)buffer1 + convertFilePath(buffer1, sizeof(buffer1)); - newFilename = (char *)buffer2 + convertFilePath(buffer2, sizeof(buffer2)); - - debug(1, "o60_rename (\"%s\" to \"%s\")", oldFilename, newFilename); + debug(1, "o60_rename (\"%s\" to \"%s\")", (char *)buffer1, (char *)buffer2); - _saveFileMan->renameSavefile(oldFilename, newFilename); + renameSaveFile(buffer1, buffer2); } int ScummEngine_v60he::readFileToArray(int slot, int32 size) { diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp index 42bf9a4bb6..cfa2be7275 100644 --- a/engines/scumm/he/script_v72he.cpp +++ b/engines/scumm/he/script_v72he.cpp @@ -710,7 +710,7 @@ void ScummEngine_v72he::o72_roomOps() { copyScriptString((byte *)buffer, sizeof(buffer)); - _saveLoadFileName = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); + _saveLoadFileName = (char *)buffer; debug(1, "o72_roomOps: case 221: filename %s", _saveLoadFileName.c_str()); _saveLoadFlag = pop(); @@ -1390,10 +1390,7 @@ void ScummEngine_v72he::o72_openFile() { mode = pop(); copyScriptString(buffer, sizeof(buffer)); - debug(1, "Original filename %s", buffer); - - const char *filename = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); - debug(1, "Final filename to %s", filename); + debug(1, "Trying to open file '%s'", (char *)buffer); slot = -1; for (i = 1; i < 17; i++) { @@ -1406,48 +1403,17 @@ void ScummEngine_v72he::o72_openFile() { if (slot != -1) { switch (mode) { case 1: // Read mode - if (!_saveFileMan->listSavefiles(filename).empty()) { - _hInFileTable[slot] = _saveFileMan->openForLoading(filename); - } else { - _hInFileTable[slot] = SearchMan.createReadStreamForMember(filename); - } + _hInFileTable[slot] = openFileForReading(buffer); break; case 2: // Write mode - if (!strchr(filename, '/')) { - _hOutFileTable[slot] = _saveFileMan->openForSaving(filename); + if (!strchr((char *)buffer, '/')) { + _hOutFileTable[slot] = openSaveFileForWriting(buffer); } break; - case 6: { // Append mode - if (strchr(filename, '/')) - break; - - // First check if the file already exists - Common::InSaveFile *initialState = 0; - if (!_saveFileMan->listSavefiles(filename).empty()) - initialState = _saveFileMan->openForLoading(filename); - else - initialState = SearchMan.createReadStreamForMember(filename); - - // Read in the data from the initial file - uint32 initialSize = 0; - byte *initialData = 0; - if (initialState) { - initialSize = initialState->size(); - initialData = new byte[initialSize]; - initialState->read(initialData, initialSize); - delete initialState; - } - - // Attempt to open a save file - _hOutFileTable[slot] = _saveFileMan->openForSaving(filename); - - // Begin us off with the data from the previous file - if (_hOutFileTable[slot] && initialData) { - _hOutFileTable[slot]->write(initialData, initialSize); - delete[] initialData; - } - - } break; + case 6: // Append mode + if (!strchr((char *)buffer, '/')) + _hOutFileTable[slot] = openSaveFileForAppending(buffer); + break; default: error("o72_openFile(): wrong open file mode %d", mode); } @@ -1565,13 +1531,10 @@ void ScummEngine_v72he::o72_deleteFile() { byte buffer[256]; copyScriptString(buffer, sizeof(buffer)); - const char *filename = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); - debug(1, "o72_deleteFile(%s)", filename); + debug(1, "o72_deleteFile(%s)", (char *)buffer); - if (!_saveFileMan->listSavefiles(filename).empty()) { - _saveFileMan->removeSavefile(filename); - } + deleteSaveFile(buffer); } void ScummEngine_v72he::o72_rename() { @@ -1580,12 +1543,9 @@ void ScummEngine_v72he::o72_rename() { copyScriptString(buffer1, sizeof(buffer1)); copyScriptString(buffer2, sizeof(buffer2)); - const char *newFilename = (char *)buffer1 + convertFilePath(buffer1, sizeof(buffer1)); - const char *oldFilename = (char *)buffer2 + convertFilePath(buffer2, sizeof(buffer2)); - - _saveFileMan->renameSavefile(oldFilename, newFilename); + debug(1, "o72_rename(%s to %s)", (char *)buffer2, (char *)buffer1); - debug(1, "o72_rename(%s to %s)", oldFilename, newFilename); + renameSaveFile(buffer2, buffer1); } void ScummEngine_v72he::o72_getPixel() { diff --git a/engines/scumm/he/script_v80he.cpp b/engines/scumm/he/script_v80he.cpp index ae43d714ad..7a8f230fc0 100644 --- a/engines/scumm/he/script_v80he.cpp +++ b/engines/scumm/he/script_v80he.cpp @@ -89,14 +89,8 @@ void ScummEngine_v80he::o80_getFileSize() { byte buffer[256]; copyScriptString(buffer, sizeof(buffer)); - const char *filename = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); - Common::SeekableReadStream *f = 0; - if (!_saveFileMan->listSavefiles(filename).empty()) { - f = _saveFileMan->openForLoading(filename); - } else { - f = SearchMan.createReadStreamForMember(filename); - } + Common::SeekableReadStream *f = openFileForReading(buffer); if (!f) { push(-1); @@ -143,14 +137,12 @@ void ScummEngine_v80he::o80_readConfigFile() { byte option[128], section[128], filename[256]; byte *data; Common::String entry; - int len, r; + int len; copyScriptString(option, sizeof(option)); copyScriptString(section, sizeof(section)); copyScriptString(filename, sizeof(filename)); - r = convertFilePath(filename, sizeof(filename)); - if (_game.id == GID_TREASUREHUNT) { // WORKAROUND: Remove invalid characters if (!strcmp((char *)section, "Blue'sTreasureHunt-Disc1")) @@ -159,13 +151,13 @@ void ScummEngine_v80he::o80_readConfigFile() { memcpy(section, "BluesTreasureHunt-Disc2\0", 24); } - if (!strcmp((const char *)filename, "map (i)")) { + if (!strcmp((const char *)filename, ":map (i)")) { // Mac resource fork config file // (as used by only mustard mac for map data?) Common::MacResManager resFork; - if (!resFork.open((const char *)filename) || !resFork.hasResFork()) - error("Could not open '%s'", filename); + if (!resFork.open("map (i)") || !resFork.hasResFork()) + error("Could not open 'map (i)'"); Common::String prefResName = Common::String::format("Pref:%s.%s", (const char *)section, (const char *)option); Common::SeekableReadStream *res = resFork.getResource(prefResName); @@ -180,13 +172,14 @@ void ScummEngine_v80he::o80_readConfigFile() { } } else { // Normal Windows INI files - Common::INIFile confFile; - if (!strcmp((char *)filename + r, "map.ini")) - confFile.loadFromFile((const char *)filename + r); - else - confFile.loadFromSaveFile((const char *)filename + r); + Common::SeekableReadStream *stream = openFileForReading(filename); - confFile.getKey((const char *)option, (const char *)section, entry); + if (stream) { + Common::INIFile iniFile; + iniFile.loadFromStream(*stream); + iniFile.getKey((const char *)option, (const char *)section, entry); + delete stream; + } } byte subOp = fetchScriptByte(); @@ -216,7 +209,7 @@ void ScummEngine_v80he::o80_readConfigFile() { void ScummEngine_v80he::o80_writeConfigFile() { byte filename[256], section[256], option[256], string[1024]; - int r, value; + int value; byte subOp = fetchScriptByte(); @@ -240,8 +233,6 @@ void ScummEngine_v80he::o80_writeConfigFile() { error("o80_writeConfigFile: default type %d", subOp); } - r = convertFilePath(filename, sizeof(filename)); - if (_game.id == GID_TREASUREHUNT) { // WORKAROUND: Remove invalid characters if (!strcmp((char *)section, "Blue'sTreasureHunt-Disc1")) @@ -250,10 +241,16 @@ void ScummEngine_v80he::o80_writeConfigFile() { memcpy(section, "BluesTreasureHunt-Disc2\0", 24); } - Common::INIFile ConfFile; - ConfFile.loadFromSaveFile((const char *)filename + r); - ConfFile.setKey((char *)option, (char *)section, (char *)string); - ConfFile.saveToSaveFile((const char *)filename + r); + Common::INIFile iniFile; + Common::SeekableReadStream *iniStream = openSaveFileForReading(filename); + + if (iniStream) { + iniFile.loadFromStream(*iniStream); + delete iniStream; + } + + iniFile.setKey((char *)option, (char *)section, (char *)string); + iniFile.saveToSaveFile(convertSavePath(filename)); debug(1,"o80_writeConfigFile: Filename %s Section %s Option %s String %s", filename, section, option, string); } diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp index 1ea9960a18..f844c51cc6 100644 --- a/engines/scumm/he/script_v90he.cpp +++ b/engines/scumm/he/script_v90he.cpp @@ -1429,11 +1429,10 @@ void ScummEngine_v90he::o90_videoOps() { if (_videoParams.flags == 0) _videoParams.flags = 4; - const char *filename = (char *)_videoParams.filename + convertFilePath(_videoParams.filename, sizeof(_videoParams.filename)); if (_videoParams.flags & 2) { - VAR(119) = _moviePlay->load(filename, _videoParams.flags, _videoParams.wizResNum); + VAR(119) = _moviePlay->load(convertFilePath(_videoParams.filename), _videoParams.flags, _videoParams.wizResNum); } else { - VAR(119) = _moviePlay->load(filename, _videoParams.flags); + VAR(119) = _moviePlay->load(convertFilePath(_videoParams.filename), _videoParams.flags); } } else if (_videoParams.status == 165) { // Stop video diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp index ca360803bd..b3511648bd 100644 --- a/engines/scumm/he/wiz_he.cpp +++ b/engines/scumm/he/wiz_he.cpp @@ -2355,8 +2355,6 @@ void Wiz::remapWizImagePal(const WizParameters *params) { } void Wiz::processWizImage(const WizParameters *params) { - byte buffer[260]; - debug(3, "processWizImage: processMode %d", params->processMode); switch (params->processMode) { case 0: @@ -2370,15 +2368,7 @@ void Wiz::processWizImage(const WizParameters *params) { break; case 3: if (params->processFlags & kWPFUseFile) { - Common::SeekableReadStream *f = NULL; - memcpy(buffer, params->filename, 260); - const char *filename = (char *)buffer + _vm->convertFilePath(buffer, sizeof(buffer)); - - if (!_vm->_saveFileMan->listSavefiles(filename).empty()) { - f = _vm->_saveFileMan->openForLoading(filename); - } else { - f = SearchMan.createReadStreamForMember(filename); - } + Common::SeekableReadStream *f = _vm->openFileForReading(params->filename); if (f) { uint32 id = f->readUint32BE(); @@ -2388,7 +2378,7 @@ void Wiz::processWizImage(const WizParameters *params) { byte *p = _vm->_res->createResource(rtImage, params->img.resNum, size); if (f->read(p, size) != size) { _vm->_res->nukeResource(rtImage, params->img.resNum); - error("i/o error when reading '%s'", filename); + error("i/o error when reading '%s'", params->filename); _vm->VAR(_vm->VAR_GAME_LOADED) = -2; _vm->VAR(119) = -2; } else { @@ -2404,16 +2394,12 @@ void Wiz::processWizImage(const WizParameters *params) { } else { _vm->VAR(_vm->VAR_GAME_LOADED) = -3; _vm->VAR(119) = -3; - debug(0, "Unable to open for read '%s'", filename); + debug(0, "Unable to open for read '%s'", params->filename); } } break; case 4: if (params->processFlags & kWPFUseFile) { - Common::OutSaveFile *f; - memcpy(buffer, params->filename, 260); - const char *filename = (char *)buffer + _vm->convertFilePath(buffer, sizeof(buffer)); - switch (params->fileWriteMode) { case 2: _vm->VAR(119) = -1; @@ -2421,15 +2407,17 @@ void Wiz::processWizImage(const WizParameters *params) { case 1: // TODO Write image to file break; - case 0: - if (!(f = _vm->_saveFileMan->openForSaving(filename))) { - debug(0, "Unable to open for write '%s'", filename); + case 0: { + Common::WriteStream *f = _vm->openSaveFileForWriting(params->filename); + + if (!f) { + debug(0, "Unable to open for write '%s'", params->filename); _vm->VAR(119) = -3; } else { byte *p = _vm->getResourceAddress(rtImage, params->img.resNum); uint32 size = READ_BE_UINT32(p + 4); if (f->write(p, size) != size) { - error("i/o error when writing '%s'", filename); + error("i/o error when writing '%s'", params->filename); _vm->VAR(119) = -2; } else { _vm->VAR(119) = 0; @@ -2438,6 +2426,7 @@ void Wiz::processWizImage(const WizParameters *params) { delete f; } break; + } default: error("processWizImage: processMode 4 unhandled fileWriteMode %d", params->fileWriteMode); } diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 5197e07819..848e288589 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -148,7 +148,17 @@ void ScummEngine::requestLoad(int slot) { _saveLoadFlag = 2; // 2 for load } -static bool saveSaveGameHeader(Common::OutSaveFile *out, SaveGameHeader &hdr) { +Common::SeekableReadStream *ScummEngine::openSaveFileForReading(int slot, bool compat, Common::String &fileName) { + fileName = makeSavegameName(slot, compat); + return _saveFileMan->openForLoading(fileName); +} + +Common::WriteStream *ScummEngine::openSaveFileForWriting(int slot, bool compat, Common::String &fileName) { + fileName = makeSavegameName(slot, compat); + return _saveFileMan->openForSaving(fileName); +} + +static bool saveSaveGameHeader(Common::WriteStream *out, SaveGameHeader &hdr) { hdr.type = MKTAG('S','C','V','M'); hdr.size = 0; hdr.ver = CURRENT_VER; @@ -160,7 +170,7 @@ static bool saveSaveGameHeader(Common::OutSaveFile *out, SaveGameHeader &hdr) { return true; } -bool ScummEngine::saveState(Common::OutSaveFile *out, bool writeHeader) { +bool ScummEngine::saveState(Common::WriteStream *out, bool writeHeader) { SaveGameHeader hdr; if (writeHeader) { @@ -177,20 +187,13 @@ bool ScummEngine::saveState(Common::OutSaveFile *out, bool writeHeader) { return true; } -bool ScummEngine::saveState(int slot, bool compat) { +bool ScummEngine::saveState(int slot, bool compat, Common::String &filename) { bool saveFailed; - Common::String filename; - Common::OutSaveFile *out; pauseEngine(true); - if (_saveLoadSlot == 255) { - // Allow custom filenames for save game system in HE Games - filename = _saveLoadFileName; - } else { - filename = makeSavegameName(slot, compat); - } - if (!(out = _saveFileMan->openForSaving(filename))) + Common::WriteStream *out = openSaveFileForWriting(slot, compat, filename); + if (!out) return false; saveFailed = false; @@ -307,18 +310,17 @@ static bool loadSaveGameHeader(Common::SeekableReadStream *in, SaveGameHeader &h } bool ScummEngine::loadState(int slot, bool compat) { + // Wrapper around the other variant Common::String filename; - Common::SeekableReadStream *in; + return loadState(slot, compat, filename); +} + +bool ScummEngine::loadState(int slot, bool compat, Common::String &filename) { SaveGameHeader hdr; int sb, sh; - if (_saveLoadSlot == 255) { - // Allow custom filenames for save game system in HE Games - filename = _saveLoadFileName; - } else { - filename = makeSavegameName(slot, compat); - } - if (!(in = _saveFileMan->openForLoading(filename))) + Common::SeekableReadStream *in = openSaveFileForReading(slot, compat, filename); + if (!in) return false; if (!loadSaveGameHeader(in, hdr)) { diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index cc8665e450..39fbae8147 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -2307,15 +2307,16 @@ void ScummEngine::scummLoop_handleSaveLoad() { if (_game.version == 8 && _saveTemporaryState) VAR(VAR_GAME_LOADED) = 0; + Common::String filename; if (_saveLoadFlag == 1) { - success = saveState(_saveLoadSlot, _saveTemporaryState); + success = saveState(_saveLoadSlot, _saveTemporaryState, filename); if (!success) errMsg = _("Failed to save game state to file:\n\n%s"); if (success && _saveTemporaryState && VAR_GAME_LOADED != 0xFF && _game.version <= 7) VAR(VAR_GAME_LOADED) = 201; } else { - success = loadState(_saveLoadSlot, _saveTemporaryState); + success = loadState(_saveLoadSlot, _saveTemporaryState, filename); if (!success) errMsg = _("Failed to load game state from file:\n\n%s"); @@ -2323,7 +2324,6 @@ void ScummEngine::scummLoop_handleSaveLoad() { VAR(VAR_GAME_LOADED) = (_game.version == 8) ? 1 : 203; } - Common::String filename = makeSavegameName(_saveLoadSlot, _saveTemporaryState); if (!success) { displayMessage(0, errMsg, filename.c_str()); } else if (_saveLoadFlag == 1 && _saveLoadSlot != 0 && !_saveTemporaryState) { diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index f192a1e256..7d3a01b895 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -595,14 +595,18 @@ protected: Common::String _saveLoadFileName; Common::String _saveLoadDescription; - bool saveState(Common::OutSaveFile *out, bool writeHeader = true); - bool saveState(int slot, bool compat); + bool saveState(Common::WriteStream *out, bool writeHeader = true); + bool saveState(int slot, bool compat, Common::String &fileName); bool loadState(int slot, bool compat); + bool loadState(int slot, bool compat, Common::String &fileName); virtual void saveOrLoad(Serializer *s); void saveResource(Serializer *ser, ResType type, ResId idx); void loadResource(Serializer *ser, ResType type, ResId idx); void loadResourceOLD(Serializer *ser, ResType type, ResId idx); // "Obsolete" + virtual Common::SeekableReadStream *openSaveFileForReading(int slot, bool compat, Common::String &fileName); + virtual Common::WriteStream *openSaveFileForWriting(int slot, bool compat, Common::String &fileName); + Common::String makeSavegameName(int slot, bool temporary) const { return makeSavegameName(_targetName, slot, temporary); } @@ -618,6 +622,8 @@ public: void requestSave(int slot, const Common::String &name); void requestLoad(int slot); + Common::String getTargetName() const { return _targetName; } + // thumbnail + info stuff public: static bool querySaveMetaInfos(const char *target, int slot, int heversion, Common::String &desc, Graphics::Surface *&thumbnail, SaveStateMetaInfos *&timeInfos); diff --git a/engines/teenagent/callbacks.cpp b/engines/teenagent/callbacks.cpp index 4761cabc78..9fe9e68a76 100644 --- a/engines/teenagent/callbacks.cpp +++ b/engines/teenagent/callbacks.cpp @@ -2386,6 +2386,10 @@ bool TeenAgentEngine::processCallback(uint16 addr) { fnEgoDefaultPosition(); break; + case 0x5634: + displayMessage(dsAddr_pullObjMsg2); // "I can't reach it" + break; + case 0x563b: playSound(5, 10); setOns(1, 0); @@ -3326,6 +3330,10 @@ bool TeenAgentEngine::processCallback(uint16 addr) { fnMansionIntrusionAttempt(); break; + case 0x830b: + displayMessage(dsAddr_noChainsawFuelMsg); // "There's no fuel in the chainsaw" + break; + case 0x8312: // hedgehog + plastic apple dialog->showMark(76, scene); setLan(1, 0); diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index 5d410e62c7..5ba3c5e80a 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -835,14 +835,6 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc) // Setup mixer syncSoundSettings(); - // Add DW2 subfolder to search path in case user is running directly from the CDs - const Common::FSNode gameDataDir(ConfMan.get("path")); - SearchMan.addSubDirectoryMatching(gameDataDir, "dw2"); - - // Add subfolders needed for psx versions of Discworld 1 - if (TinselV1PSX) - SearchMan.addDirectory(gameDataDir.getPath(), gameDataDir, 0, 3, true); - const GameSettings *g; const char *gameid = ConfMan.get("gameid").c_str(); @@ -892,6 +884,17 @@ Common::String TinselEngine::getSavegameFilename(int16 saveNum) const { return Common::String::format("%s.%03d", getTargetName().c_str(), saveNum); } +void TinselEngine::initializePath(const Common::FSNode &gamePath) { + if (TinselV1PSX) { + // Add subfolders needed for psx versions of Discworld 1 + SearchMan.addDirectory(gamePath.getPath(), gamePath, 0, 3, true); + } else { + // Add DW2 subfolder to search path in case user is running directly from the CDs + SearchMan.addSubDirectoryMatching(gamePath, "dw2"); + Engine::initializePath(gamePath); + } +} + Common::Error TinselEngine::run() { // Initialize backend if (getGameID() == GID_DW2) { diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h index d26153245d..efa9355dd5 100644 --- a/engines/tinsel/tinsel.h +++ b/engines/tinsel/tinsel.h @@ -161,6 +161,7 @@ class TinselEngine : public Engine { protected: // Engine APIs + virtual void initializePath(const Common::FSNode &gamePath); virtual Common::Error run(); virtual bool hasFeature(EngineFeature f) const; Common::Error loadGameState(int slot); diff --git a/engines/tony/mpal/mpal.cpp b/engines/tony/mpal/mpal.cpp index 5f2452dcfe..19e3d43df4 100644 --- a/engines/tony/mpal/mpal.cpp +++ b/engines/tony/mpal/mpal.cpp @@ -963,7 +963,7 @@ void LocationPollThread(CORO_PARAM, const void *param) { // Ok, we can perform the action. For convenience, we do it in a new process _ctx->newItem = (LpMpalItem)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(MpalItem)); - if (_ctx->newItem == false) { + if (!_ctx->newItem) { globalDestroy(_ctx->myThreads); globalDestroy(_ctx->myActions); diff --git a/engines/tony/sound.cpp b/engines/tony/sound.cpp index 547f31906e..74d32c7c0f 100644 --- a/engines/tony/sound.cpp +++ b/engines/tony/sound.cpp @@ -88,7 +88,7 @@ FPSound::~FPSound() { bool FPSound::createStream(FPStream **streamPtr) { (*streamPtr) = new FPStream(_soundSupported); - return (*streamPtr != NULL); + return true; } /** diff --git a/engines/tsage/globals.cpp b/engines/tsage/globals.cpp index 9b1b0f1dcb..f270e23ea5 100644 --- a/engines/tsage/globals.cpp +++ b/engines/tsage/globals.cpp @@ -63,6 +63,7 @@ Globals::Globals() : _dialogCenter(160, 140), _gfxManagerInstance(_screenSurface reset(); _stripNum = 0; _gfxEdgeAdjust = 3; + _gfxFontNumber = 0; if (g_vm->getGameID() == GType_Ringworld) { if (g_vm->getFeatures() & GF_DEMO) { diff --git a/engines/tsage/ringworld2/ringworld2_dialogs.cpp b/engines/tsage/ringworld2/ringworld2_dialogs.cpp index a0675bc292..708a3ccb45 100644 --- a/engines/tsage/ringworld2/ringworld2_dialogs.cpp +++ b/engines/tsage/ringworld2/ringworld2_dialogs.cpp @@ -203,13 +203,13 @@ void CharacterDialog::show() { GfxButton *btn = NULL; int oldCharacter = R2_GLOBALS._player._characterIndex; switch (oldCharacter) { - case 1: + case R2_QUINN: btn = &dlg->_btnQuinn; break; - case 2: + case R2_SEEKER: btn = &dlg->_btnSeeker; break; - case 3: + case R2_MIRANDA: btn = &dlg->_btnMiranda; break; default: @@ -384,6 +384,8 @@ void HelpDialog::show() { // If a action button was selected, dispatch to handle it if (evt.kbd.keycode != Common::KEYCODE_INVALID) R2_GLOBALS._game->processEvent(evt); + else + R2_GLOBALS._events.setCursorFromFlag(); } HelpDialog::HelpDialog() { diff --git a/engines/tsage/ringworld2/ringworld2_logic.cpp b/engines/tsage/ringworld2/ringworld2_logic.cpp index ef212bc52a..39e398023d 100644 --- a/engines/tsage/ringworld2/ringworld2_logic.cpp +++ b/engines/tsage/ringworld2/ringworld2_logic.cpp @@ -1128,7 +1128,6 @@ void Ringworld2Game::start() { R2_GLOBALS._sceneHandler->_loadGameSlot = slot; else { // Switch to the first title screen - R2_GLOBALS._events.setCursor(CURSOR_WALK); R2_GLOBALS._uiElements._active = true; R2_GLOBALS._sceneManager.setNewScene(180); } diff --git a/engines/tsage/ringworld2/ringworld2_scenes0.cpp b/engines/tsage/ringworld2/ringworld2_scenes0.cpp index e04f294b22..2fbce0646c 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes0.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes0.cpp @@ -2993,7 +2993,7 @@ void Scene300::Action4::signal() { bool Scene300::QuinnWorkstation::startAction(CursorType action, Event &event) { switch (action) { case CURSOR_USE: - if (R2_GLOBALS._player._characterIndex != 1) + if (R2_GLOBALS._player._characterIndex != R2_QUINN) SceneItem::display2(300, 46); else if (R2_GLOBALS.getFlag(44)) { R2_GLOBALS._player.setAction(NULL); @@ -3024,7 +3024,7 @@ bool Scene300::QuinnWorkstation::startAction(CursorType action, Event &event) { bool Scene300::MirandaWorkstation::startAction(CursorType action, Event &event) { switch (action) { case CURSOR_USE: - if (R2_GLOBALS._player._characterIndex != 3) + if (R2_GLOBALS._player._characterIndex != R2_MIRANDA) SceneItem::display2(300, 49); else R2_GLOBALS._sceneManager.changeScene(325); @@ -3054,7 +3054,7 @@ bool Scene300::SeekerWorkstation::startAction(CursorType action, Event &event) { break; case CURSOR_USE: - if (R2_GLOBALS._player._characterIndex != 2) + if (R2_GLOBALS._player._characterIndex != R2_SEEKER) SceneItem::display2(300, 48); else R2_GLOBALS._sceneManager.changeScene(325); @@ -3465,7 +3465,7 @@ void Scene300::postInit(SceneObjectList *OwnerList) { _background.setDetails(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 300, 0, -1, -1, 1, NULL); switch (R2_GLOBALS._player._characterIndex) { - case 1: + case R2_QUINN: _sceneMode = 300; switch (R2_GLOBALS._sceneManager._previousScene) { @@ -3554,7 +3554,7 @@ void Scene300::postInit(SceneObjectList *OwnerList) { } break; - case 3: + case R2_MIRANDA: if (R2_GLOBALS._sceneManager._previousScene == 1500) { R2_GLOBALS._player._oldCharacterScene[R2_MIRANDA] = 3150; R2_GLOBALS._player._characterScene[R2_MIRANDA] = 3150; @@ -3639,7 +3639,7 @@ void Scene300::signal() { default: R2_GLOBALS._player.enableControl(CURSOR_TALK); - if ((R2_GLOBALS._player._characterIndex != 1) || R2_GLOBALS.getFlag(44)) + if ((R2_GLOBALS._player._characterIndex != R2_QUINN) || R2_GLOBALS.getFlag(44)) R2_GLOBALS._player._canWalk = false; break; } @@ -5357,7 +5357,7 @@ void Scene500::PanelDialog::Button::doButtonPress() { &scene->_suit, &scene->_transparentDoor, NULL); } else { scene->_sound1.play(127); - scene->_suits.animate(ANIM_MODE_6, scene); + scene->_suits.animate(ANIM_MODE_5, scene); } break; diff --git a/engines/tsage/ringworld2/ringworld2_scenes3.cpp b/engines/tsage/ringworld2/ringworld2_scenes3.cpp index 5b41a85326..e55ae8ff70 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes3.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes3.cpp @@ -4469,7 +4469,7 @@ void Scene3600::postInit(SceneObjectList *OwnerList) { _quinn.changeZoom(-1); _quinn._effect = EFFECT_SHADED; - if (R2_GLOBALS._player._characterIndex != 1) + if (R2_GLOBALS._player._characterIndex != R2_QUINN) _quinn.setDetails(9001, 0, -1, -1, 1, (SceneItem *) NULL); _seeker.postInit(); @@ -4478,7 +4478,7 @@ void Scene3600::postInit(SceneObjectList *OwnerList) { _seeker.changeZoom(-1); _seeker._effect = EFFECT_SHADED; - if (R2_GLOBALS._player._characterIndex != 2) + if (R2_GLOBALS._player._characterIndex != R2_SEEKER) _seeker.setDetails(9002, 1, -1, -1, 1, (SceneItem *) NULL); _miranda.postInit(); @@ -4486,7 +4486,7 @@ void Scene3600::postInit(SceneObjectList *OwnerList) { _miranda.changeZoom(-1); _miranda._effect = EFFECT_SHADED; - if (R2_GLOBALS._player._characterIndex != 3) + if (R2_GLOBALS._player._characterIndex != R2_MIRANDA) _miranda.setDetails(9003, 1, -1, -1, 1, (SceneItem *) NULL); R2_GLOBALS._player.postInit(); diff --git a/engines/tsage/ringworld2/ringworld2_speakers.cpp b/engines/tsage/ringworld2/ringworld2_speakers.cpp index 675511ac10..494a31a829 100644 --- a/engines/tsage/ringworld2/ringworld2_speakers.cpp +++ b/engines/tsage/ringworld2/ringworld2_speakers.cpp @@ -335,7 +335,8 @@ void SpeakerCaptain3210::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4060, (_object2->_strip * 2) - 1, 1); _object1.animate(ANIM_MODE_5, this); } @@ -393,18 +394,21 @@ void SpeakerChief1100::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4080, 1, 1); _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4080, 3, 1); _object1.animate(ANIM_MODE_5, this); break; case 100: _numFrames = 0; - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setStrip(_object1._strip - 1); _object1.setFrame(_object1.getFrameCount()); _object1.animate(ANIM_MODE_6, this); @@ -448,7 +452,8 @@ void SpeakerGuard2800::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setZoom(75); _object1.setup(4060, 3, 1); _object1.animate(ANIM_MODE_5, this); @@ -488,7 +493,8 @@ void SpeakerJocko3200::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4060, (_object2->_strip * 2) - 1, 1); _object1.animate(ANIM_MODE_5, this); } @@ -511,7 +517,8 @@ void SpeakerJocko3220::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4060, (_object2->_strip * 2) - 1, 1); _object1.animate(ANIM_MODE_5, this); } @@ -534,7 +541,8 @@ void SpeakerJocko3230::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4060, (_object2->_strip * 2) - 1, 1); _object1.animate(ANIM_MODE_5, this); } @@ -579,13 +587,13 @@ void SpeakerMiranda300::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); } else if (v == 100) { _numFrames = 0; - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; _object1.setStrip(_object1._strip - 1); _object1.setFrame(_object1.getFrameCount()); _object1.animate(ANIM_MODE_6, this); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; if (v == 4) { _object1.setup(304, 5, 1); @@ -613,7 +621,8 @@ void SpeakerMiranda1625::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(1627, 3, 1); _object1.animate(ANIM_MODE_5, this); } @@ -634,7 +643,8 @@ void SpeakerMiranda3255::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(3257, 5, 1); _object1.animate(ANIM_MODE_5, this); } @@ -680,7 +690,8 @@ void SpeakerMiranda3375::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4051, 5, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -729,7 +740,8 @@ void SpeakerMiranda3385::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4051, 5, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -779,7 +791,8 @@ void SpeakerMiranda3395::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4051, 5, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -818,12 +831,14 @@ void SpeakerMiranda3400::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4051, 5, 1); _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4050, 3, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -864,12 +879,14 @@ void SpeakerMiranda3600::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4051, 1, 1); _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4050, 1, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -904,7 +921,8 @@ void SpeakerMiranda3700::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + scene->_quinn.setup(10, 6, 1); scene->_seeker.setup(20, 5, 1); _object2->setup(30, 1, 1); @@ -913,13 +931,15 @@ void SpeakerMiranda3700::animateSpeaker() { _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + scene->_miranda.setup(30, 8, 1); _object1.setup(4052, 3, 1); _object1.animate(ANIM_MODE_5, this); break; case 3: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + scene->_seeker.setup(20, 1, 1); scene->_miranda.setup(30, 1, 1); _object1.setup(4051, 7, 1); @@ -964,7 +984,8 @@ void SpeakerNej2700::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + switch (_object2->_visage) { case 2701: _object1.setup(4022, 3, 1); @@ -999,7 +1020,8 @@ void SpeakerNej2750::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + switch (_object2->_visage) { case 2705: _object1.setup(4022, 7, 1); @@ -1031,7 +1053,8 @@ void SpeakerNej2800::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4023, 3, 1); if (_object2->_visage == 2801) _object1.setPosition(Common::Point(R2_GLOBALS._player._position.x - 12, R2_GLOBALS._player._position.y)); @@ -1069,7 +1092,8 @@ void SpeakerPharisha2435::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4098, 5, 1); _object1.animate(ANIM_MODE_5, this); } @@ -1108,7 +1132,8 @@ void SpeakerPrivate3210::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4060, (_object2->_strip * 2) - 1, 1); _object1.animate(ANIM_MODE_5, this); } @@ -1157,7 +1182,8 @@ void SpeakerProtector3600::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + if (scene->_sceneMode != 3324) { _object1.setup(4125, 3, 1); _object1.animate(ANIM_MODE_5, this); @@ -1212,13 +1238,13 @@ void SpeakerQuinn300::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); } else if (v == 100) { _numFrames = 0; - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; _object1.setStrip(_object1._strip - 1); _object1.setFrame(_object1.getFrameCount()); _object1.animate(ANIM_MODE_6, this); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; switch (_object2->_visage) { case 10: @@ -1264,7 +1290,7 @@ void SpeakerQuinn500::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; switch (_object2->_visage) { case 10: @@ -1312,17 +1338,20 @@ void SpeakerQuinn1100::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(1108, 7, 1); _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(1109, 1, 1); _object1.animate(ANIM_MODE_5, this); break; case 3: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(1109, 5, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -1352,7 +1381,8 @@ void SpeakerQuinn2435::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object2->setStrip(7); _object1.setup(2020, 5, 1); _object1.animate(ANIM_MODE_5, this); @@ -1379,7 +1409,8 @@ void SpeakerQuinn2450::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + if (R2_GLOBALS.getFlag(61)) _object1.setup(2020, 3, 1); else @@ -1404,7 +1435,8 @@ void SpeakerQuinn2700::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + switch (_object2->_visage) { case 19: _object1.setup(4022, 5, 1); @@ -1435,7 +1467,8 @@ void SpeakerQuinn2750::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + switch (_object2->_visage) { case 19: _object1.setup(4022, 5, 1); @@ -1466,7 +1499,8 @@ void SpeakerQuinn2800::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + switch (_object2->_visage) { case 16: _object1.setZoom(75); @@ -1506,7 +1540,8 @@ void SpeakerQuinn3255::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(3257, 3, 1); _object1.animate(ANIM_MODE_5, this); } @@ -1547,13 +1582,13 @@ void SpeakerQuinn3375::animateSpeaker() { _object2->addMover(NULL); } - switch (v) { case 0: _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4010, 5, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -1598,13 +1633,13 @@ void SpeakerQuinn3385::animateSpeaker() { _object2->addMover(NULL); } - switch (v) { case 0: _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + if (R2_GLOBALS._player._characterIndex == R2_SEEKER) _object1.setup(4010, 3, 1); else @@ -1653,13 +1688,13 @@ void SpeakerQuinn3395::animateSpeaker() { _object2->addMover(NULL); } - switch (v) { case 0: _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + if (R2_GLOBALS._player._characterIndex == R2_SEEKER) _object1.setup(4010, 3, 1); else @@ -1702,17 +1737,20 @@ void SpeakerQuinn3400::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4010, 5, 1); _object1.animate(ANIM_MODE_5, NULL); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4010, 3, 1); _object1.animate(ANIM_MODE_5, this); break; case 3: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4012, 3, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -1750,17 +1788,20 @@ void SpeakerQuinn3600::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4021, 7, 1); _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4010, 1, 1); _object1.animate(ANIM_MODE_5, this); break; case 3: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4012, 1, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -1813,7 +1854,8 @@ void SpeakerQuinn3700::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + R2_GLOBALS._sound2.stop(); scene->_quinn.setup(10, 4, 1); scene->_miranda.setup(30, 7, 1); @@ -1821,14 +1863,16 @@ void SpeakerQuinn3700::animateSpeaker() { _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + scene->_seeker.setup(20, 1, 1); scene->_miranda.setup(30, 1, 1); _object1.setup(3702, 1, 1); _object1.animate(ANIM_MODE_5, this); break; case 3: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + scene->_quinn.setup(10, 2, 1); scene->_miranda.setup(30, 1, 1); _object1.setup(4011, 1, 1); @@ -1881,7 +1925,8 @@ void SpeakerRalf3245::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + switch (_object2->_visage) { case 3100: _object1.setup(4105, (_object2->_strip * 2) - 1, 1); @@ -1933,7 +1978,8 @@ void SpeakerRocko3200::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4060, (_object2->_strip * 2) - 1, 1); _object1.animate(ANIM_MODE_5, this); } @@ -1956,7 +2002,8 @@ void SpeakerRocko3220::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4060, (_object2->_strip * 2) - 1, 1); _object1.animate(ANIM_MODE_5, this); } @@ -1979,7 +2026,8 @@ void SpeakerRocko3230::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4111, (_object2->_strip * 2) - 1, 1); _object1.animate(ANIM_MODE_5, this); } @@ -2025,13 +2073,14 @@ void SpeakerSeeker300::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); } else if (v == 100) { _numFrames = 0; - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; _object1.setStrip(_object1._strip - 1); _object1.setFrame(_object1.getFrameCount()); _object1.animate(ANIM_MODE_6, this); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(306, v * 2 - 1, 1); _object1.animate(ANIM_MODE_5, this); } @@ -2063,7 +2112,7 @@ void SpeakerSeeker500::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; if (v == 1) _object1.setup(4041, 3, 1); @@ -2103,28 +2152,33 @@ void SpeakerSeeker1100::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(1108, 1, 1); _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(1108, 3, 1); _object1.animate(ANIM_MODE_5, this); break; case 3: _object1.setPosition(Common::Point(197, 134)); - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(1108, 5, 1); _object1.animate(ANIM_MODE_5, this); break; case 4: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(1109, 7, 1); _object1.animate(ANIM_MODE_5, this); break; case 5: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(1109, 3, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -2185,7 +2239,8 @@ void SpeakerSeeker2435::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object2->setStrip(7); _object1.setup(4099, 1, 1); _object1.animate(ANIM_MODE_5, this); @@ -2212,7 +2267,8 @@ void SpeakerSeeker2450::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4099, 3, 1); _object1.animate(ANIM_MODE_5, this); } @@ -2251,13 +2307,13 @@ void SpeakerSeeker3375::animateSpeaker() { _object2->addMover(NULL); } - switch (v) { case 0: _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4031, 1, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -2306,7 +2362,8 @@ void SpeakerSeeker3385::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4031, 3, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -2349,13 +2406,13 @@ void SpeakerSeeker3395::animateSpeaker() { _object2->addMover(NULL); } - switch (v) { case 0: _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4031, 3, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -2394,27 +2451,32 @@ void SpeakerSeeker3400::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4031, 1, 1); _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4031, 3, 1); _object1.animate(ANIM_MODE_5, this); break; case 3: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4030, 3, 1); _object1.animate(ANIM_MODE_5, this); break; case 4: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4031, 7, 1); _object1.animate(ANIM_MODE_5, this); break; case 5: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4033, 1, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -2456,12 +2518,14 @@ void SpeakerSeeker3600::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4031, 5, 1); _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4030, 1, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -2509,7 +2573,8 @@ void SpeakerSeeker3700::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + R2_GLOBALS._sound2.stop(); scene->_quinn.setup(10, 8, 1); scene->_seeker.setup(20, 7, 1); @@ -2518,7 +2583,8 @@ void SpeakerSeeker3700::animateSpeaker() { _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + scene->_quinn.setup(10, 2, 1); scene->_seeker.setup(20, 1, 1); scene->_miranda.setup(30, 1, 1); @@ -2572,7 +2638,8 @@ void SpeakerSocko3200::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4060, (_object2->_strip * 2) - 1, 1); _object1.animate(ANIM_MODE_5, this); } @@ -2612,7 +2679,8 @@ void SpeakerSoldier300::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(303, 3, 1); _object1.animate(ANIM_MODE_5, this); } @@ -2658,12 +2726,14 @@ void SpeakerTeal180::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(75, 5, 1); _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(77, 1, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -2691,7 +2761,8 @@ void SpeakerTeal300::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(303, 1, 1); _object1.animate(ANIM_MODE_5, this); } @@ -2715,7 +2786,8 @@ void SpeakerTeal1625::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(1627, 1, 1); _object1.animate(ANIM_MODE_5, this); } @@ -2738,7 +2810,8 @@ void SpeakerTeal3240::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4070, (_object2->_strip * 2) - 1, 1); _object1.animate(ANIM_MODE_5, this); } @@ -2776,22 +2849,26 @@ void SpeakerTeal3400::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4107, 5, 1); _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4107, 1, 1); _object1.animate(ANIM_MODE_5, this); break; case 3: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4107, 7, 1); _object1.animate(ANIM_MODE_5, this); break; case 4: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4107, 3, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -2832,22 +2909,26 @@ void SpeakerTeal3600::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4107, 5, 1); _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4107, 1, 1); _object1.animate(ANIM_MODE_5, this); break; case 3: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4107, 7, 1); _object1.animate(ANIM_MODE_5, this); break; case 4: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4107, 3, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -2890,7 +2971,8 @@ void SpeakerTomko3245::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + switch (_object2->_visage) { case 3100: _object1.setup(4105, (_object2->_strip * 2) - 1, 1); @@ -2946,17 +3028,20 @@ void SpeakerWebbster180::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(75, 7, 1); _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(76, 4, 1); _object1.animate(ANIM_MODE_5, this); break; case 3: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(76, 6, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -2983,7 +3068,8 @@ void SpeakerWebbster3240::animateSpeaker() { if (v == 0) { _object1.animate(ANIM_MODE_2, NULL); } else { - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4110, 5, 1); _object1.animate(ANIM_MODE_5, this); } @@ -3023,7 +3109,8 @@ void SpeakerWebbster3375::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4110, 5, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -3067,7 +3154,8 @@ void SpeakerWebbster3385::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4110, 5, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -3111,7 +3199,8 @@ void SpeakerWebbster3395::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4110, 5, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -3146,17 +3235,20 @@ void SpeakerWebbster3400::animateSpeaker() { _object1.animate(ANIM_MODE_2, NULL); break; case 1: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4110, 5, 1); _object1.animate(ANIM_MODE_5, this); break; case 2: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4110, 7, 1); _object1.animate(ANIM_MODE_5, this); break; case 3: - ((SceneItem *)_action)->_sceneRegionId = 0; + ((StripManager *)_action)->_useless = 0; + _object1.setup(4110, 3, 1); _object1.animate(ANIM_MODE_5, this); break; @@ -3210,6 +3302,5 @@ void SpeakerDutyOfficer180::animateSpeaker() { } } - } // End of namespace Ringworld2 } // End of namespace TsAGE diff --git a/engines/wintermute/base/base_game.h b/engines/wintermute/base/base_game.h index 742d6f548d..29d312fe97 100644 --- a/engines/wintermute/base/base_game.h +++ b/engines/wintermute/base/base_game.h @@ -251,6 +251,8 @@ public: void addMem(int32 bytes); bool _touchInterface; bool _constrainedMemory; + + bool stopVideo(); protected: BaseFont *_systemFont; BaseFont *_videoFont; @@ -319,7 +321,6 @@ private: BaseGameMusic *_musicSystem; bool isVideoPlaying(); - bool stopVideo(); BaseArray<BaseQuickMsg *> _quickMessages; BaseArray<UIWindow *> _windows; diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp index ff63789d18..35918b8e90 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp @@ -399,10 +399,23 @@ void BaseRenderOSystem::drawTickets() { return; } - // Apply the clear-color to the dirty rect. - _renderSurface->fillRect(*_dirtyRect, _clearColor); + it = _renderQueue.begin(); _lastFrameIter = _renderQueue.end(); - for (it = _renderQueue.begin(); it != _renderQueue.end(); ++it) { + // A special case: If the screen has one giant OPAQUE rect to be drawn, then we skip filling + // the background colour. Typical use-case: Fullscreen FMVs. + // Caveat: The FPS-counter will invalidate this. + if (it != _lastFrameIter && _renderQueue.front() == _renderQueue.back() && (*it)->_transform._alphaDisable == true) { + // If our single opaque rect fills the dirty rect, we can skip filling. + if (*_dirtyRect != (*it)->_dstRect) { + // Apply the clear-color to the dirty rect. + _renderSurface->fillRect(*_dirtyRect, _clearColor); + } + // Otherwise Do NOT fill. + } else { + // Apply the clear-color to the dirty rect. + _renderSurface->fillRect(*_dirtyRect, _clearColor); + } + for (; it != _renderQueue.end(); ++it) { RenderTicket *ticket = *it; if (ticket->_dstRect.intersects(*_dirtyRect)) { // dstClip is the area we want redrawn. diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp index 9ec8573a87..c33e8ba54b 100644 --- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp @@ -447,8 +447,14 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, bool BaseSurfaceOSystem::putSurface(const Graphics::Surface &surface, bool hasAlpha) { _loaded = true; - _surface->free(); - _surface->copyFrom(surface); + if (surface.format == _surface->format && surface.w == _surface->w && surface.h == _surface->h) { + const byte *src = (const byte *)surface.getBasePtr(0, 0); + byte *dst = (byte *)_surface->getBasePtr(0, 0); + memcpy(dst, src, surface.pitch * surface.h); + } else { + _surface->free(); + _surface->copyFrom(surface); + } if (hasAlpha) { _alphaType = TransparentSurface::ALPHA_FULL; } else { diff --git a/engines/wintermute/base/saveload.cpp b/engines/wintermute/base/saveload.cpp index 8d37909bb4..402041cda4 100644 --- a/engines/wintermute/base/saveload.cpp +++ b/engines/wintermute/base/saveload.cpp @@ -48,6 +48,7 @@ bool SaveLoad::loadGame(const Common::String &filename, BaseGame *gameRef) { bool ret; + gameRef->stopVideo(); gameRef->_renderer->initSaveLoad(false); gameRef->_loadInProgress = true; diff --git a/engines/wintermute/base/sound/base_sound_buffer.cpp b/engines/wintermute/base/sound/base_sound_buffer.cpp index 7666a441a3..85ba52e334 100644 --- a/engines/wintermute/base/sound/base_sound_buffer.cpp +++ b/engines/wintermute/base/sound/base_sound_buffer.cpp @@ -58,6 +58,7 @@ BaseSoundBuffer::BaseSoundBuffer(BaseGame *inGame) : BaseClass(inGame) { _file = nullptr; _privateVolume = 255; _volume = 255; + _pan = 0; _looping = false; _loopStart = 0; @@ -143,9 +144,9 @@ bool BaseSoundBuffer::play(bool looping, uint32 startSample) { _handle = new Audio::SoundHandle; if (_looping) { Audio::AudioStream *loopStream = new Audio::LoopingAudioStream(_stream, 0, DisposeAfterUse::NO); - g_system->getMixer()->playStream(_type, _handle, loopStream, -1, _volume, 0, DisposeAfterUse::YES); + g_system->getMixer()->playStream(_type, _handle, loopStream, -1, _volume, _pan, DisposeAfterUse::YES); } else { - g_system->getMixer()->playStream(_type, _handle, _stream, -1, _volume, 0, DisposeAfterUse::NO); + g_system->getMixer()->playStream(_type, _handle, _stream, -1, _volume, _pan, DisposeAfterUse::NO); } } @@ -268,8 +269,11 @@ bool BaseSoundBuffer::setLoopStart(uint32 pos) { ////////////////////////////////////////////////////////////////////////// bool BaseSoundBuffer::setPan(float pan) { + pan = MAX(pan, -1.0f); + pan = MIN(pan, 1.0f); + _pan = (int8)(pan * 127); if (_handle) { - g_system->getMixer()->setChannelBalance(*_handle, (int8)(pan * 127)); + g_system->getMixer()->setChannelBalance(*_handle, _pan); } return STATUS_OK; } diff --git a/engines/wintermute/base/sound/base_sound_buffer.h b/engines/wintermute/base/sound/base_sound_buffer.h index 53b86f64c6..c52b34fb23 100644 --- a/engines/wintermute/base/sound/base_sound_buffer.h +++ b/engines/wintermute/base/sound/base_sound_buffer.h @@ -93,6 +93,7 @@ private: bool _streamed; Common::SeekableReadStream *_file; int32 _volume; + int8 _pan; }; } // End of namespace Wintermute diff --git a/engines/wintermute/configure.engine b/engines/wintermute/configure.engine index 673549b46b..bdaf49de3f 100644 --- a/engines/wintermute/configure.engine +++ b/engines/wintermute/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine wintermute "Wintermute" no "" "" "jpeg png zlib vorbis 16bit" +add_engine wintermute "Wintermute" yes "" "" "jpeg png zlib vorbis 16bit" diff --git a/engines/wintermute/graphics/transparent_surface.cpp b/engines/wintermute/graphics/transparent_surface.cpp index 053acf29e9..79722439bd 100644 --- a/engines/wintermute/graphics/transparent_surface.cpp +++ b/engines/wintermute/graphics/transparent_surface.cpp @@ -519,9 +519,9 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p byte *ino= (byte *)img->getBasePtr(xp, yp); byte *outo = (byte *)target.getBasePtr(posX, posY); - if (color == 0xFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_OPAQUE) { + if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_OPAQUE) { doBlitOpaqueFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); - } else if (color == 0xFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_BINARY) { + } else if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_BINARY) { doBlitBinaryFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); } else { if (blendMode == BLEND_ADDITIVE) { diff --git a/engines/wintermute/video/video_theora_player.cpp b/engines/wintermute/video/video_theora_player.cpp index 44eecf93a8..299b64f915 100644 --- a/engines/wintermute/video/video_theora_player.cpp +++ b/engines/wintermute/video/video_theora_player.cpp @@ -305,8 +305,15 @@ bool VideoTheoraPlayer::update() { if (!_theoraDecoder->endOfVideo() && _theoraDecoder->getTimeToNextFrame() == 0) { const Graphics::Surface *decodedFrame = _theoraDecoder->decodeNextFrame(); if (decodedFrame) { - _surface.free(); - _surface.copyFrom(*decodedFrame); + if (decodedFrame->format == _surface.format && decodedFrame->w == _surface.w && decodedFrame->h == _surface.h) { + const byte *src = (const byte *)decodedFrame->getBasePtr(0, 0); + byte *dst = (byte *)_surface.getBasePtr(0, 0); + memcpy(dst, src, _surface.pitch * _surface.h); + } else { + _surface.free(); + _surface.copyFrom(*decodedFrame); + } + if (_texture) { writeVideo(); } diff --git a/graphics/sjis.cpp b/graphics/sjis.cpp index 33f0e562cb..59ee5af8c4 100644 --- a/graphics/sjis.cpp +++ b/graphics/sjis.cpp @@ -40,31 +40,25 @@ FontSJIS *FontSJIS::createFont(const Common::Platform platform) { // Try the font ROM of the specified platform if (platform == Common::kPlatformFMTowns) { ret = new FontTowns(); - if (ret) { - if (ret->loadData()) - return ret; - } + if (ret->loadData()) + return ret; delete ret; } else if (platform == Common::kPlatformPCEngine) { ret = new FontPCEngine(); - if (ret) { - if (ret->loadData()) - return ret; - } + if (ret->loadData()) + return ret; delete ret; } // TODO: PC98 font rom support /* else if (platform == Common::kPlatformPC98) { ret = new FontPC98(); - if (ret) { - if (ret->loadData()) - return ret; - } + if (ret->loadData()) + return ret; delete ret; }*/ // Try ScummVM's font. ret = new FontSjisSVM(platform); - if (ret && ret->loadData()) + if (ret->loadData()) return ret; delete ret; diff --git a/gui/credits.h b/gui/credits.h index a14622e1b1..bcace12d13 100644 --- a/gui/credits.h +++ b/gui/credits.h @@ -77,7 +77,7 @@ static const char *credits[] = { "C0""Ludvig Strigeus", "C2""(retired)", "", -"C1""AVALANCHE", +"C1""Avalanche", "A0""Peter Bozso", "C0""Peter Bozs\363", "A0""Arnaud Boutonne", diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index a3b45995a1..bae5b7babd 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -36,6 +36,7 @@ // Video Codecs #include "video/codecs/cinepak.h" #include "video/codecs/indeo3.h" +#include "video/codecs/mjpeg.h" #include "video/codecs/mpeg.h" #include "video/codecs/msvideo1.h" #include "video/codecs/msrle.h" @@ -82,6 +83,7 @@ namespace Video { #define ID_IV32 MKTAG('i','v','3','2') #define ID_DUCK MKTAG('D','U','C','K') #define ID_MPG2 MKTAG('m','p','g','2') +#define ID_MJPG MKTAG('m','j','p','g') // Stream Types enum { @@ -786,6 +788,8 @@ Codec *AVIDecoder::AVIVideoTrack::createCodec() { case ID_MPG2: return new MPEGDecoder(); #endif + case ID_MJPG: + return new MJPEGDecoder(); default: warning("Unknown/Unhandled compression format \'%s\'", tag2str(_vidsHeader.streamHandler)); } diff --git a/video/codecs/jpeg.cpp b/video/codecs/jpeg.cpp new file mode 100644 index 0000000000..f3886f334a --- /dev/null +++ b/video/codecs/jpeg.cpp @@ -0,0 +1,66 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/system.h" +#include "common/textconsole.h" +#include "graphics/surface.h" +#include "graphics/decoders/jpeg.h" + +#include "video/codecs/jpeg.h" + +namespace Common { +class SeekableReadStream; +} + +namespace Video { + +JPEGDecoder::JPEGDecoder() : Codec() { + _pixelFormat = g_system->getScreenFormat(); + _surface = NULL; +} + +JPEGDecoder::~JPEGDecoder() { + if (_surface) { + _surface->free(); + delete _surface; + } +} + +const Graphics::Surface *JPEGDecoder::decodeImage(Common::SeekableReadStream *stream) { + Graphics::JPEGDecoder jpeg; + + if (!jpeg.loadStream(*stream)) { + warning("Failed to decode JPEG frame"); + return 0; + } + + if (_surface) { + _surface->free(); + delete _surface; + } + + _surface = jpeg.getSurface()->convertTo(_pixelFormat); + + return _surface; +} + +} // End of namespace Video diff --git a/video/codecs/jpeg.h b/video/codecs/jpeg.h new file mode 100644 index 0000000000..1023d97779 --- /dev/null +++ b/video/codecs/jpeg.h @@ -0,0 +1,60 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef VIDEO_CODECS_JPEG_H +#define VIDEO_CODECS_JPEG_H + +#include "video/codecs/codec.h" +#include "graphics/pixelformat.h" + +namespace Common { +class SeekableReadStream; +} + +namespace Graphics { +struct Surface; +} + +namespace Video { + +/** + * JPEG decoder. + * + * Used in video: + * - QuickTimeDecoder + */ +class JPEGDecoder : public Codec { +public: + JPEGDecoder(); + ~JPEGDecoder(); + + const Graphics::Surface *decodeImage(Common::SeekableReadStream *stream); + Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; } + +private: + Graphics::PixelFormat _pixelFormat; + Graphics::Surface *_surface; +}; + +} // End of namespace Video + +#endif diff --git a/video/codecs/mjpeg.cpp b/video/codecs/mjpeg.cpp index 10fd9d7c50..61f9eb5881 100644 --- a/video/codecs/mjpeg.cpp +++ b/video/codecs/mjpeg.cpp @@ -20,6 +20,12 @@ * */ +// Based on LGPL MJPEG/AVI to JPEG/JFIF conversion code from libav +// Copyright (c) 2010 Adrian Daerr and Nicolas George +// That in turn was adapted from mjpeg2jpeg.c, with original copyright: +// Paris 2010 Adrian Daerr, public domain + +#include "common/memstream.h" #include "common/system.h" #include "common/textconsole.h" #include "graphics/surface.h" @@ -33,23 +39,168 @@ class SeekableReadStream; namespace Video { -JPEGDecoder::JPEGDecoder() : Codec() { +MJPEGDecoder::MJPEGDecoder() : Codec() { _pixelFormat = g_system->getScreenFormat(); - _surface = NULL; + _surface = 0; } -JPEGDecoder::~JPEGDecoder() { +MJPEGDecoder::~MJPEGDecoder() { if (_surface) { _surface->free(); delete _surface; } } -const Graphics::Surface *JPEGDecoder::decodeImage(Common::SeekableReadStream *stream) { +// Header to be inserted +static const byte s_jpegHeader[] = { + 0xff, 0xd8, // SOI + 0xff, 0xe0, // APP0 + 0x00, 0x10, // APP0 header size (including + // this field, but excluding preceding) + 'J', 'F', 'I', 'F', 0x00, // ID string 'JFIF\0' + 0x01, 0x01, // version + 0x00, // bits per type + 0x00, 0x00, // X density + 0x00, 0x00, // Y density + 0x00, // X thumbnail size + 0x00 +}; + +enum { + DHT_SEGMENT_SIZE = 420 +}; + +static const byte s_dhtSegmentHead[] = { 0xFF, 0xC4, 0x01, 0xA2, 0x00 }; +static const byte s_dhtSegmentFrag[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// Set up the standard Huffman tables (cf. JPEG standard section K.3) +// IMPORTANT: these are only valid for 8-bit data precision! +static const byte s_mjpegBitsDCLuminance[17] = { + /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 +}; + +static const byte s_mjpegValDC[12] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 +}; + +static const byte s_mjpegBitsDCChrominance[17] = { + /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 +}; + +static const byte s_mjpegBitsACLuminance[17] = { + /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d +}; + +static const byte s_mjpegValACLuminance[] = { + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa +}; + +static const byte s_mjpegBitsACChrominance[17] = { + /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 +}; + +static const byte s_mjpegValACChrominance[] = { + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa +}; + +const Graphics::Surface *MJPEGDecoder::decodeImage(Common::SeekableReadStream *stream) { + // We need to reconstruct an actual JPEG stream here, then feed it to the JPEG decoder + // Yes, this is a pain. + + stream->readUint32BE(); // Skip nonsense JPEG header + uint16 inputSkip = stream->readUint16BE() + 4; + uint32 tag = stream->readUint32BE(); + + if (tag != MKTAG('A', 'V', 'I', '1')) { + warning("Invalid MJPEG tag found"); + return 0; + } + + uint32 outputSize = stream->size() - inputSkip + sizeof(s_jpegHeader) + DHT_SEGMENT_SIZE; + byte *data = (byte *)malloc(outputSize); + + if (!data) { + warning("Failed to allocate data for MJPEG conversion"); + return 0; + } + + // Copy the header + memcpy(data, s_jpegHeader, sizeof(s_jpegHeader)); + uint32 dataOffset = sizeof(s_jpegHeader); + + // Write the fake DHT segment + memcpy(data + dataOffset, s_dhtSegmentHead, sizeof(s_dhtSegmentHead)); + dataOffset += sizeof(s_dhtSegmentHead); + memcpy(data + dataOffset, s_mjpegBitsDCLuminance + 1, 16); + dataOffset += 16; + memcpy(data + dataOffset, s_dhtSegmentFrag, sizeof(s_dhtSegmentFrag)); + dataOffset += sizeof(s_dhtSegmentFrag); + memcpy(data + dataOffset, s_mjpegValDC, 12); + dataOffset += 12; + data[dataOffset++] = 0x10; + memcpy(data + dataOffset, s_mjpegBitsACLuminance + 1, 16); + dataOffset += 16; + memcpy(data + dataOffset, s_mjpegValACLuminance, 162); + dataOffset += 162; + data[dataOffset++] = 0x11; + memcpy(data + dataOffset, s_mjpegBitsACChrominance + 1, 16); + dataOffset += 16; + memcpy(data + dataOffset, s_mjpegValACChrominance, 162); + dataOffset += 162; + + // Write the actual data + stream->seek(inputSkip); + stream->read(data + dataOffset, stream->size() - inputSkip); + + Common::MemoryReadStream convertedStream(data, outputSize, DisposeAfterUse::YES); Graphics::JPEGDecoder jpeg; - if (!jpeg.loadStream(*stream)) { - warning("Failed to decode JPEG frame"); + if (!jpeg.loadStream(convertedStream)) { + warning("Failed to decode MJPEG frame"); return 0; } diff --git a/video/codecs/mjpeg.h b/video/codecs/mjpeg.h index d71454799c..16eefa68a7 100644 --- a/video/codecs/mjpeg.h +++ b/video/codecs/mjpeg.h @@ -40,12 +40,12 @@ namespace Video { * Motion JPEG decoder. * * Used in video: - * - QuickTimeDecoder + * - AVIDecoder */ -class JPEGDecoder : public Codec { +class MJPEGDecoder : public Codec { public: - JPEGDecoder(); - ~JPEGDecoder(); + MJPEGDecoder(); + ~MJPEGDecoder(); const Graphics::Surface *decodeImage(Common::SeekableReadStream *stream); Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; } diff --git a/video/module.mk b/video/module.mk index a491947aaf..d836371182 100644 --- a/video/module.mk +++ b/video/module.mk @@ -12,6 +12,7 @@ MODULE_OBJS := \ codecs/cdtoons.o \ codecs/cinepak.o \ codecs/indeo3.o \ + codecs/jpeg.o \ codecs/mjpeg.o \ codecs/msrle.o \ codecs/msvideo1.o \ diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp index 7539d4a1e2..11a27beb10 100644 --- a/video/qt_decoder.cpp +++ b/video/qt_decoder.cpp @@ -40,7 +40,7 @@ // Video codecs #include "video/codecs/cinepak.h" -#include "video/codecs/mjpeg.h" +#include "video/codecs/jpeg.h" #include "video/codecs/qtrle.h" #include "video/codecs/rpza.h" #include "video/codecs/smc.h" @@ -296,7 +296,7 @@ void QuickTimeDecoder::VideoSampleDesc::initCodec() { warning("Sorenson Video 3 not yet supported"); break; case MKTAG('j','p','e','g'): - // Motion JPEG: Used by some Myst ME 10th Anniversary videos. + // JPEG: Used by some Myst ME 10th Anniversary videos. _videoCodec = new JPEGDecoder(); break; case MKTAG('Q','k','B','k'): |