diff options
author | Strangerke | 2013-09-08 14:49:34 +0200 |
---|---|---|
committer | Strangerke | 2013-09-08 14:49:34 +0200 |
commit | 599d2eeb06c937a4479cc751f4f9f5e94795c43b (patch) | |
tree | 6efd0f887d7a1fd5082209a585d609983031c92d | |
parent | 7df4c94aeb6c1408d26d6ada58d728b6eac17717 (diff) | |
parent | 03bf56ea82c0b89f4e61e5e0787a36473f999efa (diff) | |
download | scummvm-rg350-599d2eeb06c937a4479cc751f4f9f5e94795c43b.tar.gz scummvm-rg350-599d2eeb06c937a4479cc751f4f9f5e94795c43b.tar.bz2 scummvm-rg350-599d2eeb06c937a4479cc751f4f9f5e94795c43b.zip |
Merge branch 'master' into avalanche
804 files changed, 31671 insertions, 8962 deletions
diff --git a/.gitignore b/.gitignore index b834214a00..99c9296dba 100644 --- a/.gitignore +++ b/.gitignore @@ -93,6 +93,7 @@ project.xcworkspace /dists/msvc*/*.SAV /dists/msvc*/*.dat /dists/msvc*/*.dll +/dists/msvc*/test_runner.cpp /doc/*.aux /doc/*.dvi @@ -116,12 +117,14 @@ project.xcworkspace /devtools/create_kyradat/create_kyradat /devtools/create_lure/create_lure /devtools/create_mads/create_mads +/devtools/create_mortdat/create_mortdat /devtools/create_neverhood/create_neverhood /devtools/create_project/create_project /devtools/create_teenagent/create_teenagent /devtools/create_tony/create_tony /devtools/create_toon/create_toon /devtools/create_translations/create_translations +/devtools/extract_mort/extract_mort /devtools/qtable/qtable /devtools/skycpt/skycpt @@ -161,6 +164,10 @@ ipch/ #Ignore default Visual Studio build folders [Dd]ebug/ [Rr]elease/ +[Dd]ebug32/ +[Rr]elease32/ +[Dd]ebug64/ +[Rr]elease64/ #Ignore Qt Creator project files ScummVM.config @@ -170,3 +177,6 @@ ScummVM.includes #Ignore Komodo IDE/Edit project files *.komodoproject + +#Ignore Mac DS_Store files +.DS_Store @@ -238,9 +238,6 @@ ScummVM Team Andre Heider Angus Lees - BADA: - Chris Warren-Smith - Dreamcast: Marcus Comstedt @@ -288,6 +285,9 @@ ScummVM Team Jurgen Braam Lars Persson + Tizen / BADA: + Chris Warren-Smith + WebOS: Klaus Reimer @@ -32,8 +32,10 @@ ifeq "$(HAVE_GCC)" "1" # being helpful. #CXXFLAGS+= -Wmissing-format-attribute - # Disable RTTI and exceptions +ifneq "$(BACKEND)" "tizen" + # Disable RTTI and exceptions. These settings cause tizen apps to crash CXXFLAGS+= -fno-rtti -fno-exceptions +endif ifneq "$(HAVE_CLANG)" "1" # enable checking of pointers returned by "new", but only when we do not @@ -44,6 +46,11 @@ endif ifeq "$(HAVE_CLANG)" "1" CXXFLAGS+= -Wno-conversion -Wno-shorten-64-to-32 -Wno-sign-compare -Wno-four-char-constants + # We use a anonymous nested type declaration in an anonymous union in + # common/str.h. This is no standard construct and clang warns about it. + # It works for all our target systems though, thus we simply disable that + # warning. + CXXFLAGS+= -Wno-nested-anon-types endif ifeq "$(HAVE_ICC)" "1" diff --git a/Makefile.common b/Makefile.common index aec033f0c7..02c3408684 100644 --- a/Makefile.common +++ b/Makefile.common @@ -253,6 +253,9 @@ endif ifdef ENABLE_LURE DIST_FILES_ENGINEDATA+=lure.dat endif +ifdef ENABLE_MORTEVIELLE +DIST_FILES_ENGINEDATA+=mort.dat +endif ifdef ENABLE_NEVERHOOD DIST_FILES_ENGINEDATA+=neverhood.dat endif @@ -2,7 +2,14 @@ For a more comprehensive changelog of the latest experimental code, see: https://github.com/scummvm/scummvm/commits/ 1.7.0 (????-??-??) + Gob: + - Improved video quality in Urban Runner + + Broken Sword 1: + - Added back support for MPEG-2 videos + Broken Sword 2: + - Added back support for MPEG-2 videos 1.6.0 (2013-05-31) New Games: diff --git a/audio/mixer.cpp b/audio/mixer.cpp index 8ff364b98d..9e6e4596e2 100644 --- a/audio/mixer.cpp +++ b/audio/mixer.cpp @@ -20,6 +20,8 @@ * */ +#include "gui/EventRecorder.h" + #include "common/util.h" #include "common/system.h" #include "common/textconsole.h" @@ -427,6 +429,11 @@ void MixerImpl::pauseHandle(SoundHandle handle, bool paused) { bool MixerImpl::isSoundIDActive(int id) { Common::StackLock lock(_mutex); + +#ifdef ENABLE_EVENTRECORDER + g_eventRec.updateSubsystems(); +#endif + for (int i = 0; i != NUM_CHANNELS; i++) if (_channels[i] && _channels[i]->getId() == id) return true; @@ -443,6 +450,11 @@ int MixerImpl::getSoundID(SoundHandle handle) { bool MixerImpl::isSoundHandleActive(SoundHandle handle) { Common::StackLock lock(_mutex); + +#ifdef ENABLE_EVENTRECORDER + g_eventRec.updateSubsystems(); +#endif + const int index = handle._val % NUM_CHANNELS; return _channels[index] && _channels[index]->getHandle()._val == handle._val; } @@ -556,12 +568,12 @@ void Channel::pause(bool paused) { _pauseLevel++; if (_pauseLevel == 1) - _pauseStartTime = g_system->getMillis(); + _pauseStartTime = g_system->getMillis(true); } else if (_pauseLevel > 0) { _pauseLevel--; if (!_pauseLevel) { - _pauseTime = (g_system->getMillis() - _pauseStartTime); + _pauseTime = (g_system->getMillis(true) - _pauseStartTime); _pauseStartTime = 0; } } @@ -579,7 +591,7 @@ Timestamp Channel::getElapsedTime() { if (isPaused()) delta = _pauseStartTime - _mixerTimeStamp; else - delta = g_system->getMillis() - _mixerTimeStamp - _pauseTime; + delta = g_system->getMillis(true) - _mixerTimeStamp - _pauseTime; // Convert the number of samples into a time duration. @@ -599,13 +611,12 @@ int Channel::mix(int16 *data, uint len) { assert(_stream); int res = 0; - if (_stream->endOfData()) { // TODO: call drain method } else { assert(_converter); _samplesConsumed = _samplesDecoded; - _mixerTimeStamp = g_system->getMillis(); + _mixerTimeStamp = g_system->getMillis(true); _pauseTime = 0; res = _converter->flow(*_stream, data, len, _volL, _volR); _samplesDecoded += res; diff --git a/audio/softsynth/fluidsynth.cpp b/audio/softsynth/fluidsynth.cpp index 518e260175..efcf1be615 100644 --- a/audio/softsynth/fluidsynth.cpp +++ b/audio/softsynth/fluidsynth.cpp @@ -163,7 +163,7 @@ int MidiDriver_FluidSynth::open() { Common::String interpolation = ConfMan.get("fluidsynth_misc_interpolation"); int interpMethod = FLUID_INTERP_4THORDER; - + if (interpolation == "none") { interpMethod = FLUID_INTERP_NONE; } else if (interpolation == "linear") { diff --git a/audio/softsynth/mt32.cpp b/audio/softsynth/mt32.cpp index 00d0469356..29f5e3577c 100644 --- a/audio/softsynth/mt32.cpp +++ b/audio/softsynth/mt32.cpp @@ -62,7 +62,8 @@ protected: // Callback for debug messages, in vprintf() format void printDebug(const char *fmt, va_list list) { - debug(4, fmt, list); + Common::String out = Common::String::vformat(fmt, list); + debug(4, "%s", out.c_str()); } // Callbacks for reporting various errors and information diff --git a/audio/softsynth/mt32/Part.cpp b/audio/softsynth/mt32/Part.cpp index 62ba346c35..88404316eb 100644 --- a/audio/softsynth/mt32/Part.cpp +++ b/audio/softsynth/mt32/Part.cpp @@ -175,6 +175,7 @@ void Part::refresh() { patchCache[t].reverb = patchTemp->patch.reverbSwitch > 0; } memcpy(currentInstr, timbreTemp->common.name, 10); + synth->newTimbreSet(partNum, patchTemp->patch.timbreGroup, currentInstr); updatePitchBenderRange(); } @@ -207,7 +208,6 @@ void RhythmPart::setTimbre(TimbreParam * /*timbre*/) { void Part::setTimbre(TimbreParam *timbre) { *timbreTemp = *timbre; - synth->newTimbreSet(partNum, timbre->common.name); } unsigned int RhythmPart::getAbsTimbreNum() const { @@ -533,7 +533,6 @@ void Part::playPoly(const PatchCache cache[4], const MemParams::RhythmTemp *rhyt #if MT32EMU_MONITOR_PARTIALS > 1 synth->printPartialUsage(); #endif - synth->partStateChanged(partNum, true); synth->polyStateChanged(partNum); } @@ -614,9 +613,6 @@ void Part::partialDeactivated(Poly *poly) { freePolys.prepend(poly); synth->polyStateChanged(partNum); } - if (activePartialCount == 0) { - synth->partStateChanged(partNum, false); - } } //#define POLY_LIST_DEBUG diff --git a/audio/softsynth/mt32/Partial.cpp b/audio/softsynth/mt32/Partial.cpp index a0aec90ec4..b80a028515 100644 --- a/audio/softsynth/mt32/Partial.cpp +++ b/audio/softsynth/mt32/Partial.cpp @@ -87,7 +87,6 @@ void Partial::deactivate() { if (poly != NULL) { poly->partialDeactivated(this); } - synth->partialStateChanged(this, tva->getPhase(), TVA_PHASE_DEAD); #if MT32EMU_MONITOR_PARTIALS > 2 synth->printDebug("[+%lu] [Partial %d] Deactivated", sampleNum, debugPartialNum); synth->printPartialUsage(sampleNum); diff --git a/audio/softsynth/mt32/Synth.cpp b/audio/softsynth/mt32/Synth.cpp index b7af992b99..1e1be06bc9 100644 --- a/audio/softsynth/mt32/Synth.cpp +++ b/audio/softsynth/mt32/Synth.cpp @@ -201,25 +201,12 @@ void ReportHandler::printDebug(const char *fmt, va_list list) { printf("\n"); } -void Synth::partStateChanged(int partNum, bool isPartActive) { - reportHandler->onPartStateChanged(partNum, isPartActive); -} - void Synth::polyStateChanged(int partNum) { reportHandler->onPolyStateChanged(partNum); } -void Synth::partialStateChanged(const Partial * const partial, int oldPartialPhase, int newPartialPhase) { - for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) { - if (getPartial(i) == partial) { - reportHandler->onPartialStateChanged(i, oldPartialPhase, newPartialPhase); - break; - } - } -} - -void Synth::newTimbreSet(int partNum, char patchName[]) { - reportHandler->onProgramChanged(partNum, patchName); +void Synth::newTimbreSet(int partNum, Bit8u timbreGroup, const char patchName[]) { + reportHandler->onProgramChanged(partNum, timbreGroup, patchName); } void Synth::printDebug(const char *fmt, ...) { diff --git a/audio/softsynth/mt32/Synth.h b/audio/softsynth/mt32/Synth.h index 56e88e6156..b85e7ae507 100644 --- a/audio/softsynth/mt32/Synth.h +++ b/audio/softsynth/mt32/Synth.h @@ -249,10 +249,10 @@ protected: virtual void onNewReverbMode(Bit8u /* mode */) {} virtual void onNewReverbTime(Bit8u /* time */) {} virtual void onNewReverbLevel(Bit8u /* level */) {} - virtual void onPartStateChanged(int /* partNum */, bool /* isActive */) {} + virtual void onPartStateChanged(int /* partNum */, bool /* hasActiveNonReleasingPolys */) {} virtual void onPolyStateChanged(int /* partNum */) {} virtual void onPartialStateChanged(int /* partialNum */, int /* oldPartialPhase */, int /* newPartialPhase */) {} - virtual void onProgramChanged(int /* partNum */, char * /* patchName */) {} + virtual void onProgramChanged(int /* partNum */, int /* bankNum */, const char * /* patchName */) {} }; class Synth { @@ -370,10 +370,8 @@ private: void printPartialUsage(unsigned long sampleOffset = 0); - void partStateChanged(int partNum, bool isPartActive); void polyStateChanged(int partNum); - void partialStateChanged(const Partial * const partial, int oldPartialPhase, int newPartialPhase); - void newTimbreSet(int partNum, char patchName[]); + void newTimbreSet(int partNum, Bit8u timbreGroup, const char patchName[]); void printDebug(const char *fmt, ...); public: diff --git a/audio/softsynth/mt32/TVA.cpp b/audio/softsynth/mt32/TVA.cpp index 65e5256048..5438471fa4 100644 --- a/audio/softsynth/mt32/TVA.cpp +++ b/audio/softsynth/mt32/TVA.cpp @@ -34,9 +34,6 @@ TVA::TVA(const Partial *usePartial, LA32Ramp *useAmpRamp) : } void TVA::startRamp(Bit8u newTarget, Bit8u newIncrement, int newPhase) { - if (newPhase != phase) { - partial->getSynth()->partialStateChanged(partial, phase, newPhase); - } target = newTarget; phase = newPhase; ampRamp->startRamp(newTarget, newIncrement); @@ -46,9 +43,6 @@ void TVA::startRamp(Bit8u newTarget, Bit8u newIncrement, int newPhase) { } void TVA::end(int newPhase) { - if (newPhase != phase) { - partial->getSynth()->partialStateChanged(partial, phase, newPhase); - } phase = newPhase; playing = false; #if MT32EMU_MONITOR_TVA >= 1 diff --git a/backends/base-backend.cpp b/backends/base-backend.cpp index 3e0005dedd..3e95c3e26a 100644 --- a/backends/base-backend.cpp +++ b/backends/base-backend.cpp @@ -57,7 +57,7 @@ void BaseBackend::initBackend() { void BaseBackend::fillScreen(uint32 col) { Graphics::Surface *screen = lockScreen(); - if (screen && screen->pixels) - memset(screen->pixels, col, screen->h * screen->pitch); + if (screen && screen->getPixels()) + memset(screen->getPixels(), col, screen->h * screen->pitch); unlockScreen(); } diff --git a/backends/events/default/default-events.cpp b/backends/events/default/default-events.cpp index 38a0c8d46f..bf76bbc1cb 100644 --- a/backends/events/default/default-events.cpp +++ b/backends/events/default/default-events.cpp @@ -84,7 +84,8 @@ void DefaultEventManager::init() { } bool DefaultEventManager::pollEvent(Common::Event &event) { - uint32 time = g_system->getMillis(); + // Skip recording of these events + uint32 time = g_system->getMillis(true); bool result = false; _dispatcher.dispatch(); diff --git a/backends/events/sdl/sdl-events.cpp b/backends/events/sdl/sdl-events.cpp index 0ca5bbb059..e2ef7f6bf6 100644 --- a/backends/events/sdl/sdl-events.cpp +++ b/backends/events/sdl/sdl-events.cpp @@ -106,7 +106,9 @@ void SdlEventSource::processMouseEvent(Common::Event &event, int x, int y) { } void SdlEventSource::handleKbdMouse() { - uint32 curTime = g_system->getMillis(); + // Skip recording of these events + uint32 curTime = g_system->getMillis(true); + if (curTime >= _km.last_time + _km.delay_time) { _km.last_time = curTime; if (_km.x_down_count == 1) { diff --git a/backends/graphics/opengl/gltexture.h b/backends/graphics/opengl/gltexture.h index 8ff9838ff7..6ef80923ae 100644 --- a/backends/graphics/opengl/gltexture.h +++ b/backends/graphics/opengl/gltexture.h @@ -44,9 +44,9 @@ #define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(x[0]))) #endif -#if defined(BADA) +#if defined(TIZEN) #include <FGraphicsOpengl.h> -using namespace Osp::Graphics::Opengl; +using namespace Tizen::Graphics::Opengl; #elif defined(USE_GLES) #include <GLES/gl.h> #elif defined(SDL_BACKEND) diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp index 48e2663d44..84be83d524 100644 --- a/backends/graphics/opengl/opengl-graphics.cpp +++ b/backends/graphics/opengl/opengl-graphics.cpp @@ -357,7 +357,7 @@ void OpenGLGraphicsManager::copyRectToScreen(const void *buf, int pitch, int x, // Copy buffer data to game screen internal buffer const byte *src = (const byte *)buf; - byte *dst = (byte *)_screenData.pixels + y * _screenData.pitch + x * _screenData.format.bytesPerPixel; + byte *dst = (byte *)_screenData.getBasePtr(x, y); for (int i = 0; i < h; i++) { memcpy(dst, src, w * _screenData.format.bytesPerPixel); src += pitch; @@ -385,15 +385,15 @@ void OpenGLGraphicsManager::fillScreen(uint32 col) { #ifdef USE_RGB_COLOR if (_screenFormat.bytesPerPixel == 1) { - memset(_screenData.pixels, col, _screenData.h * _screenData.pitch); + memset(_screenData.getPixels(), col, _screenData.h * _screenData.pitch); } else if (_screenFormat.bytesPerPixel == 2) { - uint16 *pixels = (uint16 *)_screenData.pixels; + uint16 *pixels = (uint16 *)_screenData.getPixels(); uint16 col16 = (uint16)col; for (int i = 0; i < _screenData.w * _screenData.h; i++) { pixels[i] = col16; } } else if (_screenFormat.bytesPerPixel == 3) { - uint8 *pixels = (uint8 *)_screenData.pixels; + uint8 *pixels = (uint8 *)_screenData.getPixels(); byte r = (col >> 16) & 0xFF; byte g = (col >> 8) & 0xFF; byte b = col & 0xFF; @@ -404,13 +404,13 @@ void OpenGLGraphicsManager::fillScreen(uint32 col) { pixels += 3; } } else if (_screenFormat.bytesPerPixel == 4) { - uint32 *pixels = (uint32 *)_screenData.pixels; + uint32 *pixels = (uint32 *)_screenData.getPixels(); for (int i = 0; i < _screenData.w * _screenData.h; i++) { pixels[i] = col; } } #else - memset(_screenData.pixels, col, _screenData.h * _screenData.pitch); + memset(_screenData.getPixels(), col, _screenData.h * _screenData.pitch); #endif _screenNeedsRedraw = true; } @@ -463,12 +463,12 @@ Graphics::PixelFormat OpenGLGraphicsManager::getOverlayFormat() const { void OpenGLGraphicsManager::clearOverlay() { // Set all pixels to 0 - memset(_overlayData.pixels, 0, _overlayData.h * _overlayData.pitch); + memset(_overlayData.getPixels(), 0, _overlayData.h * _overlayData.pitch); _overlayNeedsRedraw = true; } void OpenGLGraphicsManager::grabOverlay(void *buf, int pitch) { - const byte *src = (byte *)_overlayData.pixels; + const byte *src = (byte *)_overlayData.getPixels(); byte *dst = (byte *)buf; for (int i = 0; i < _overlayData.h; i++) { // Copy overlay data to buffer @@ -509,7 +509,7 @@ void OpenGLGraphicsManager::copyRectToOverlay(const void *buf, int pitch, int x, return; // Copy buffer data to internal overlay surface - byte *dst = (byte *)_overlayData.pixels + y * _overlayData.pitch; + byte *dst = (byte *)_overlayData.getBasePtr(0, y); for (int i = 0; i < h; i++) { memcpy(dst + x * _overlayData.format.bytesPerPixel, src, w * _overlayData.format.bytesPerPixel); src += pitch; @@ -609,7 +609,7 @@ void OpenGLGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int _cursorData.create(w, h, _cursorFormat); // Save cursor data - memcpy(_cursorData.pixels, buf, h * _cursorData.pitch); + memcpy(_cursorData.getPixels(), buf, h * _cursorData.pitch); // Set cursor info _cursorState.w = w; @@ -688,7 +688,7 @@ void OpenGLGraphicsManager::refreshGameScreen() { byte *surface = new byte[w * h * 3]; // Convert the paletted buffer to RGB888 - const byte *src = (byte *)_screenData.pixels + y * _screenData.pitch; + const byte *src = (byte *)_screenData.getBasePtr(0, y); src += x * _screenData.format.bytesPerPixel; byte *dst = surface; for (int i = 0; i < h; i++) { @@ -708,8 +708,7 @@ void OpenGLGraphicsManager::refreshGameScreen() { delete[] surface; } else { // Update the texture - _gameTexture->updateBuffer((byte *)_screenData.pixels + y * _screenData.pitch + - x * _screenData.format.bytesPerPixel, _screenData.pitch, x, y, w, h); + _gameTexture->updateBuffer((byte *)_screenData.getBasePtr(x, y), _screenData.pitch, x, y, w, h); } _screenNeedsRedraw = false; @@ -730,7 +729,7 @@ void OpenGLGraphicsManager::refreshOverlay() { byte *surface = new byte[w * h * 3]; // Convert the paletted buffer to RGB888 - const byte *src = (byte *)_overlayData.pixels + y * _overlayData.pitch; + const byte *src = (byte *)_overlayData.getBasePtr(0, y); src += x * _overlayData.format.bytesPerPixel; byte *dst = surface; for (int i = 0; i < h; i++) { @@ -750,8 +749,7 @@ void OpenGLGraphicsManager::refreshOverlay() { delete[] surface; } else { // Update the texture - _overlayTexture->updateBuffer((byte *)_overlayData.pixels + y * _overlayData.pitch + - x * _overlayData.format.bytesPerPixel, _overlayData.pitch, x, y, w, h); + _overlayTexture->updateBuffer((byte *)_overlayData.getBasePtr(x, y), _overlayData.pitch, x, y, w, h); } _overlayNeedsRedraw = false; @@ -780,7 +778,7 @@ void OpenGLGraphicsManager::refreshCursor() { palette = _cursorPalette; // Convert the paletted cursor to RGBA8888 - const byte *src = (byte *)_cursorData.pixels; + const byte *src = (byte *)_cursorData.getPixels(); for (int i = 0; i < _cursorState.w * _cursorState.h; i++) { // Check for keycolor if (src[i] != _cursorKeyColor) { @@ -796,7 +794,7 @@ void OpenGLGraphicsManager::refreshCursor() { // Convert the RGB cursor to RGBA8888 if (_cursorFormat.bytesPerPixel == 2) { - const uint16 *src = (uint16 *)_cursorData.pixels; + const uint16 *src = (uint16 *)_cursorData.getPixels(); for (int i = 0; i < _cursorState.w * _cursorState.h; i++) { // Check for keycolor if (src[i] != _cursorKeyColor) { @@ -808,7 +806,7 @@ void OpenGLGraphicsManager::refreshCursor() { dst += 4; } } else if (_cursorFormat.bytesPerPixel == 4) { - const uint32 *src = (uint32 *)_cursorData.pixels; + const uint32 *src = (uint32 *)_cursorData.getPixels(); for (int i = 0; i < _cursorState.w * _cursorState.h; i++) { // Check for keycolor if (src[i] != _cursorKeyColor) { @@ -1356,7 +1354,7 @@ void OpenGLGraphicsManager::updateOSD() { _osdSurface.create(_osdTexture->getWidth(), _osdTexture->getHeight(), _overlayFormat); else // Clear everything - memset(_osdSurface.pixels, 0, _osdSurface.h * _osdSurface.pitch); + memset(_osdSurface.getPixels(), 0, _osdSurface.h * _osdSurface.pitch); // Determine a rect which would contain the message string (clipped to the // screen dimensions). @@ -1390,7 +1388,7 @@ void OpenGLGraphicsManager::updateOSD() { } // Update the texture - _osdTexture->updateBuffer(_osdSurface.pixels, _osdSurface.pitch, 0, 0, + _osdTexture->updateBuffer(_osdSurface.getPixels(), _osdSurface.pitch, 0, 0, _osdSurface.w, _osdSurface.h); } #endif diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp index 02e58ab319..871c6c49b2 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp @@ -40,6 +40,7 @@ #include "graphics/scaler.h" #include "graphics/scaler/aspect.h" #include "graphics/surface.h" +#include "gui/EventRecorder.h" static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { {"1x", _s("Normal (no scaling)"), GFX_NORMAL}, @@ -135,6 +136,7 @@ SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSou _paletteDirtyStart(0), _paletteDirtyEnd(0), _screenIsLocked(false), _graphicsMutex(0), + _displayDisabled(false), #ifdef USE_SDL_DEBUG_FOCUSRECT _enableFocusRectDebugCode(false), _enableFocusRect(false), _focusRect(), #endif @@ -765,9 +767,20 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() { fixupResolutionForAspectRatio(_videoMode.desiredAspectRatio, _videoMode.hardwareWidth, _videoMode.hardwareHeight); } - _hwscreen = SDL_SetVideoMode(_videoMode.hardwareWidth, _videoMode.hardwareHeight, 16, - _videoMode.fullscreen ? (SDL_FULLSCREEN|SDL_SWSURFACE) : SDL_SWSURFACE - ); + +#ifdef ENABLE_EVENTRECORDER + _displayDisabled = ConfMan.getBool("disable_display"); + + if (_displayDisabled) { + _hwscreen = g_eventRec.getSurface(_videoMode.hardwareWidth, _videoMode.hardwareHeight); + } else +#endif + { + _hwscreen = SDL_SetVideoMode(_videoMode.hardwareWidth, _videoMode.hardwareHeight, 16, + _videoMode.fullscreen ? (SDL_FULLSCREEN|SDL_SWSURFACE) : SDL_SWSURFACE + ); + } + #ifdef USE_RGB_COLOR detectSupportedFormats(); #endif @@ -1188,7 +1201,9 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() { #endif // Finally, blit all our changes to the screen - SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList); + if (!_displayDisabled) { + SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList); + } } _numDirtyRects = 0; @@ -1293,15 +1308,13 @@ Graphics::Surface *SurfaceSdlGraphicsManager::lockScreen() { if (SDL_LockSurface(_screen) == -1) error("SDL_LockSurface failed: %s", SDL_GetError()); - _framebuffer.pixels = _screen->pixels; - _framebuffer.w = _screen->w; - _framebuffer.h = _screen->h; - _framebuffer.pitch = _screen->pitch; + _framebuffer.init(_screen->w, _screen->h, _screen->pitch, _screen->pixels, #ifdef USE_RGB_COLOR - _framebuffer.format = _screenFormat; + _screenFormat #else - _framebuffer.format = Graphics::PixelFormat::createFormatCLUT8(); + Graphics::PixelFormat::createFormatCLUT8() #endif + ); return &_framebuffer; } @@ -1325,8 +1338,8 @@ void SurfaceSdlGraphicsManager::unlockScreen() { void SurfaceSdlGraphicsManager::fillScreen(uint32 col) { Graphics::Surface *screen = lockScreen(); - if (screen && screen->pixels) - memset(screen->pixels, col, screen->h * screen->pitch); + if (screen && screen->getPixels()) + memset(screen->getPixels(), col, screen->h * screen->pitch); unlockScreen(); } @@ -2047,15 +2060,12 @@ void SurfaceSdlGraphicsManager::displayMessageOnOSD(const char *msg) { error("displayMessageOnOSD: SDL_LockSurface failed: %s", SDL_GetError()); Graphics::Surface dst; - dst.pixels = _osdSurface->pixels; - dst.w = _osdSurface->w; - dst.h = _osdSurface->h; - dst.pitch = _osdSurface->pitch; - dst.format = Graphics::PixelFormat(_osdSurface->format->BytesPerPixel, - 8 - _osdSurface->format->Rloss, 8 - _osdSurface->format->Gloss, - 8 - _osdSurface->format->Bloss, 8 - _osdSurface->format->Aloss, - _osdSurface->format->Rshift, _osdSurface->format->Gshift, - _osdSurface->format->Bshift, _osdSurface->format->Ashift); + dst.init(_osdSurface->w, _osdSurface->h, _osdSurface->pitch, _osdSurface->pixels, + Graphics::PixelFormat(_osdSurface->format->BytesPerPixel, + 8 - _osdSurface->format->Rloss, 8 - _osdSurface->format->Gloss, + 8 - _osdSurface->format->Bloss, 8 - _osdSurface->format->Aloss, + _osdSurface->format->Rshift, _osdSurface->format->Gshift, + _osdSurface->format->Bshift, _osdSurface->format->Ashift)); // The font we are going to use: const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kLocalizedFont); diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.h b/backends/graphics/surfacesdl/surfacesdl-graphics.h index 21444cc25d..97de0f9c97 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.h +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.h @@ -232,6 +232,9 @@ protected: int _scalerType; int _transactionMode; + // Indicates whether it is needed to free _hwsurface in destructor + bool _displayDisabled; + bool _screenIsLocked; Graphics::Surface _framebuffer; diff --git a/backends/midi/timidity.cpp b/backends/midi/timidity.cpp index 5cefe668cd..d2c60bec9d 100644 --- a/backends/midi/timidity.cpp +++ b/backends/midi/timidity.cpp @@ -148,7 +148,7 @@ MidiDriver_TIMIDITY::MidiDriver_TIMIDITY() { int MidiDriver_TIMIDITY::open() { char *res; - char timidity_host[MAXHOSTNAMELEN]; + char timidity_host[NI_MAXHOST]; int timidity_port, data_port, i; /* count ourselves open */ diff --git a/backends/mixer/nullmixer/nullsdl-mixer.cpp b/backends/mixer/nullmixer/nullsdl-mixer.cpp new file mode 100644 index 0000000000..2fd652e19f --- /dev/null +++ b/backends/mixer/nullmixer/nullsdl-mixer.cpp @@ -0,0 +1,75 @@ +/* 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 "backends/mixer/nullmixer/nullsdl-mixer.h" +#include "common/savefile.h" + +NullSdlMixerManager::NullSdlMixerManager() : SdlMixerManager() { + _outputRate = 22050; + _callsCounter = 0; + _callbackPeriod = 10; + _samples = 8192; + while (_samples * 16 > _outputRate * 2) + _samples >>= 1; + _samplesBuf = new uint8[_samples * 4]; +} + +NullSdlMixerManager::~NullSdlMixerManager() { + delete _samplesBuf; +} + +void NullSdlMixerManager::init() { + _mixer = new Audio::MixerImpl(g_system, _outputRate); + assert(_mixer); + _mixer->setReady(true); +} + +void NullSdlMixerManager::suspendAudio() { + _audioSuspended = true; +} + +int NullSdlMixerManager::resumeAudio() { + if (!_audioSuspended) { + return -2; + } + _audioSuspended = false; + return 0; +} + + +void NullSdlMixerManager::startAudio() { +} + +void NullSdlMixerManager::callbackHandler(byte *samples, int len) { + assert(_mixer); + _mixer->mixCallback(samples, len); +} + +void NullSdlMixerManager::update() { + if (_audioSuspended) { + return; + } + _callsCounter++; + if ((_callsCounter % _callbackPeriod) == 0) { + callbackHandler(_samplesBuf, _samples); + } +} diff --git a/backends/mixer/nullmixer/nullsdl-mixer.h b/backends/mixer/nullmixer/nullsdl-mixer.h new file mode 100644 index 0000000000..94248ced66 --- /dev/null +++ b/backends/mixer/nullmixer/nullsdl-mixer.h @@ -0,0 +1,62 @@ +/* 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 BACKENDS_MIXER_NULLSDL_H +#define BACKENDS_MIXER_NULLSDL_H + +#include "backends/mixer/sdl/sdl-mixer.h" +#include "common/str.h" + +/** Audio mixer which in fact does not output audio. + * + * It is used by events recorder since the recorder is intentionally + * turning sound off to avoid stuttering. + * + * It returns correct output and shoots callbacks, so all OSystem + * users could work without modifications. + */ + +class NullSdlMixerManager : public SdlMixerManager { +public: + NullSdlMixerManager(); + virtual ~NullSdlMixerManager(); + + virtual void init(); + void update(); + + virtual void suspendAudio(); + virtual int resumeAudio(); + +protected: + + virtual void startAudio(); + virtual void callbackHandler(byte *samples, int len); + +private: + uint32 _outputRate; + uint32 _callsCounter; + uint8 _callbackPeriod; + uint32 _samples; + uint8 *_samplesBuf; +}; + +#endif diff --git a/backends/modular-backend.cpp b/backends/modular-backend.cpp index b46f33a2bc..6afe06aeca 100644 --- a/backends/modular-backend.cpp +++ b/backends/modular-backend.cpp @@ -26,6 +26,7 @@ #include "backends/graphics/graphics.h" #include "backends/mutex/mutex.h" +#include "gui/EventRecorder.h" #include "audio/mixer.h" #include "graphics/pixelformat.h" @@ -52,7 +53,7 @@ bool ModularBackend::hasFeature(Feature f) { } void ModularBackend::setFeatureState(Feature f, bool enable) { - return _graphicsManager->setFeatureState(f, enable); + _graphicsManager->setFeatureState(f, enable); } bool ModularBackend::getFeatureState(Feature f) { @@ -141,7 +142,15 @@ void ModularBackend::fillScreen(uint32 col) { } void ModularBackend::updateScreen() { +#ifdef ENABLE_EVENTRECORDER + g_eventRec.preDrawOverlayGui(); +#endif + _graphicsManager->updateScreen(); + +#ifdef ENABLE_EVENTRECORDER + g_eventRec.postDrawOverlayGui(); +#endif } void ModularBackend::setShakePos(int shakeOffset) { diff --git a/backends/module.mk b/backends/module.mk index a4f525d21d..31ac444750 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -70,7 +70,7 @@ MODULE_OBJS += \ mutex/sdl/sdl-mutex.o \ plugins/sdl/sdl-provider.o \ timer/sdl/sdl-timer.o - + # SDL 1.3 removed audio CD support ifndef USE_SDL13 MODULE_OBJS += \ @@ -120,9 +120,9 @@ MODULE_OBJS += \ mixer/sdl13/sdl13-mixer.o endif -ifeq ($(BACKEND),bada) +ifeq ($(BACKEND),tizen) MODULE_OBJS += \ - timer/bada/timer.o + timer/tizen/timer.o endif ifeq ($(BACKEND),ds) @@ -214,5 +214,11 @@ MODULE_OBJS += \ plugins/wii/wii-provider.o endif +ifdef ENABLE_EVENTRECORDER +MODULE_OBJS += \ + mixer/nullmixer/nullsdl-mixer.o \ + saves/recorder/recorder-saves.o +endif + # Include common rules include $(srcdir)/rules.mk diff --git a/backends/mutex/sdl/sdl-mutex.cpp b/backends/mutex/sdl/sdl-mutex.cpp index 8491ae468c..a51e6f0e38 100644 --- a/backends/mutex/sdl/sdl-mutex.cpp +++ b/backends/mutex/sdl/sdl-mutex.cpp @@ -33,15 +33,15 @@ OSystem::MutexRef SdlMutexManager::createMutex() { } void SdlMutexManager::lockMutex(OSystem::MutexRef mutex) { - SDL_mutexP((SDL_mutex *) mutex); + SDL_mutexP((SDL_mutex *)mutex); } void SdlMutexManager::unlockMutex(OSystem::MutexRef mutex) { - SDL_mutexV((SDL_mutex *) mutex); + SDL_mutexV((SDL_mutex *)mutex); } void SdlMutexManager::deleteMutex(OSystem::MutexRef mutex) { - SDL_DestroyMutex((SDL_mutex *) mutex); + SDL_DestroyMutex((SDL_mutex *)mutex); } #endif diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index f06e4be19e..ad80ea7f8c 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -450,7 +450,7 @@ bool OSystem_Android::getFeatureState(Feature f) { } } -uint32 OSystem_Android::getMillis() { +uint32 OSystem_Android::getMillis(bool skipRecord) { timeval curTime; gettimeofday(&curTime, 0); diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 5f2f40b726..b4813b3bdf 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -274,7 +274,7 @@ public: virtual void setCursorPalette(const byte *colors, uint start, uint num); virtual bool pollEvent(Common::Event &event); - virtual uint32 getMillis(); + virtual uint32 getMillis(bool skipRecord = false); virtual void delayMillis(uint msecs); virtual MutexRef createMutex(void); diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index cd0fd88484..882dcff9a4 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -552,7 +552,7 @@ Graphics::Surface *OSystem_Android::lockScreen() { GLTHREADCHECK; Graphics::Surface *surface = _game_texture->surface(); - assert(surface->pixels); + assert(surface->getPixels()); return surface; } @@ -645,7 +645,7 @@ void OSystem_Android::grabOverlay(void *buf, int pitch) { assert(surface->format.bytesPerPixel == sizeof(uint16)); byte *dst = (byte *)buf; - const byte *src = (const byte *)surface->pixels; + const byte *src = (const byte *)surface->getPixels(); uint h = surface->h; do { diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index b174e93191..cc41c0d8a6 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -233,7 +233,7 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) { _pixels = new byte[w * h * _surface.format.bytesPerPixel]; assert(_pixels); - _surface.pixels = _pixels; + _surface.setPixels(_pixels); fillBuffer(0); @@ -256,7 +256,7 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, } void GLESTexture::fillBuffer(uint32 color) { - assert(_surface.pixels); + assert(_surface.getPixels()); if (_pixelFormat.bytesPerPixel == 1 || ((color & 0xff) == ((color >> 8) & 0xff))) @@ -377,7 +377,7 @@ void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) { assert(_pixels); // fixup surface, for the outside this is a CLUT8 surface - _surface.pixels = _pixels; + _surface.setPixels(_pixels); fillBuffer(0); @@ -386,8 +386,8 @@ void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) { } void GLESFakePaletteTexture::fillBuffer(uint32 color) { - assert(_surface.pixels); - memset(_surface.pixels, color & 0xff, _surface.pitch * _surface.h); + assert(_surface.getPixels()); + memset(_surface.getPixels(), color & 0xff, _surface.pitch * _surface.h); setDirty(); } diff --git a/backends/platform/bada/bada.mk b/backends/platform/bada/bada.mk deleted file mode 100644 index 7c72d7752b..0000000000 --- a/backends/platform/bada/bada.mk +++ /dev/null @@ -1,5 +0,0 @@ -# Bada specific modules are built under eclipse - -$(EXECUTABLE): $(OBJS) - rm -f $@ - ar Tru $@ $(OBJS) diff --git a/backends/platform/bada/form.cpp b/backends/platform/bada/form.cpp deleted file mode 100644 index dfa72bce08..0000000000 --- a/backends/platform/bada/form.cpp +++ /dev/null @@ -1,464 +0,0 @@ -/* 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 <FAppApplication.h> - -#include "common/translation.h" -#include "base/main.h" - -#include "backends/platform/bada/form.h" -#include "backends/platform/bada/system.h" - -using namespace Osp::Base::Runtime; -using namespace Osp::Ui; -using namespace Osp::Ui::Controls; - -// number of volume levels -#define LEVEL_RANGE 5 - -// round down small Y touch values to 1 to allow the -// cursor to be positioned at the top of the screen -#define MIN_TOUCH_Y 10 - -// block for up to 2.5 seconds during shutdown to -// allow the game thread to exit gracefully. -#define EXIT_SLEEP_STEP 10 -#define EXIT_SLEEP 250 - -// -// BadaAppForm -// -BadaAppForm::BadaAppForm() : - _gameThread(0), - _state(kInitState), - _buttonState(kLeftButton), - _shortcut(kSetVolume) { - _eventQueueLock = new Mutex(); - _eventQueueLock->Create(); -} - -result BadaAppForm::Construct() { - result r = Form::Construct(Controls::FORM_STYLE_NORMAL); - if (IsFailed(r)) { - return r; - } - - BadaSystem *badaSystem = NULL; - _gameThread = NULL; - - badaSystem = new BadaSystem(this); - r = badaSystem != NULL ? E_SUCCESS : E_OUT_OF_MEMORY; - - if (!IsFailed(r)) { - r = badaSystem->Construct(); - } - - if (!IsFailed(r)) { - _gameThread = new Thread(); - r = _gameThread != NULL ? E_SUCCESS : E_OUT_OF_MEMORY; - } - - if (!IsFailed(r)) { - r = _gameThread->Construct(*this); - } - - if (IsFailed(r)) { - if (badaSystem != NULL) { - delete badaSystem; - } - if (_gameThread != NULL) { - delete _gameThread; - _gameThread = NULL; - } - } else { - g_system = badaSystem; - } - - return r; -} - -BadaAppForm::~BadaAppForm() { - logEntered(); - - if (_gameThread && _state != kErrorState) { - terminate(); - - _gameThread->Stop(); - if (_state != kErrorState) { - _gameThread->Join(); - } - - delete _gameThread; - _gameThread = NULL; - } - - if (_eventQueueLock) { - delete _eventQueueLock; - _eventQueueLock = NULL; - } - - logLeaving(); -} - -// -// abort the game thread -// -void BadaAppForm::terminate() { - if (_state == kActiveState) { - ((BadaSystem *)g_system)->setMute(true); - - _eventQueueLock->Acquire(); - - Common::Event e; - e.type = Common::EVENT_QUIT; - _eventQueue.push(e); - _state = kClosingState; - - _eventQueueLock->Release(); - - // block while thread ends - AppLog("waiting for shutdown"); - for (int i = 0; i < EXIT_SLEEP_STEP && _state == kClosingState; i++) { - Thread::Sleep(EXIT_SLEEP); - } - - if (_state == kClosingState) { - // failed to terminate - Join() will freeze - _state = kErrorState; - } - } -} - -void BadaAppForm::exitSystem() { - _state = kErrorState; - - if (_gameThread) { - _gameThread->Stop(); - delete _gameThread; - _gameThread = NULL; - } -} - -result BadaAppForm::OnInitializing(void) { - logEntered(); - - SetOrientation(ORIENTATION_LANDSCAPE); - AddOrientationEventListener(*this); - AddTouchEventListener(*this); - AddKeyEventListener(*this); - - // set focus to enable receiving key events - SetFocusable(true); - SetFocus(); - - return E_SUCCESS; -} - -result BadaAppForm::OnDraw(void) { - logEntered(); - - if (g_system) { - BadaSystem *system = (BadaSystem *)g_system; - BadaGraphicsManager *graphics = system->getGraphics(); - if (graphics && graphics->isReady()) { - g_system->updateScreen(); - } - } - - return E_SUCCESS; -} - -bool BadaAppForm::pollEvent(Common::Event &event) { - bool result = false; - - _eventQueueLock->Acquire(); - if (!_eventQueue.empty()) { - event = _eventQueue.pop(); - result = true; - } - _eventQueueLock->Release(); - - return result; -} - -void BadaAppForm::pushEvent(Common::EventType type, const Point ¤tPosition) { - BadaSystem *system = (BadaSystem *)g_system; - BadaGraphicsManager *graphics = system->getGraphics(); - if (graphics) { - // graphics could be NULL at startup or when - // displaying the system error screen - Common::Event e; - e.type = type; - e.mouse.x = currentPosition.x; - e.mouse.y = currentPosition.y > MIN_TOUCH_Y ? currentPosition.y : 1; - - bool moved = graphics->moveMouse(e.mouse.x, e.mouse.y); - - _eventQueueLock->Acquire(); - - if (moved && type != Common::EVENT_MOUSEMOVE) { - Common::Event moveEvent; - moveEvent.type = Common::EVENT_MOUSEMOVE; - moveEvent.mouse = e.mouse; - _eventQueue.push(moveEvent); - } - - _eventQueue.push(e); - _eventQueueLock->Release(); - } -} - -void BadaAppForm::pushKey(Common::KeyCode keycode) { - Common::Event e; - e.synthetic = false; - e.kbd.keycode = keycode; - e.kbd.ascii = keycode; - e.kbd.flags = 0; - - _eventQueueLock->Acquire(); - - e.type = Common::EVENT_KEYDOWN; - _eventQueue.push(e); - e.type = Common::EVENT_KEYUP; - _eventQueue.push(e); - - _eventQueueLock->Release(); -} - -void BadaAppForm::OnOrientationChanged(const Control &source, - OrientationStatus orientationStatus) { - logEntered(); - if (_state == kInitState) { - _state = kActiveState; - _gameThread->Start(); - } -} - -Object *BadaAppForm::Run(void) { - scummvm_main(0, 0); - - if (_state == kActiveState) { - Application::GetInstance()->SendUserEvent(USER_MESSAGE_EXIT, NULL); - } - _state = kDoneState; - return NULL; -} - -void BadaAppForm::setButtonShortcut() { - switch (_buttonState) { - case kLeftButton: - g_system->displayMessageOnOSD(_("Right Click Once")); - _buttonState = kRightButtonOnce; - break; - case kRightButtonOnce: - g_system->displayMessageOnOSD(_("Right Click")); - _buttonState = kRightButton; - break; - case kRightButton: - g_system->displayMessageOnOSD(_("Move Only")); - _buttonState = kMoveOnly; - break; - case kMoveOnly: - g_system->displayMessageOnOSD(_("Left Click")); - _buttonState = kLeftButton; - break; - } -} - -void BadaAppForm::setShortcut() { - // cycle to the next shortcut - switch (_shortcut) { - case kControlMouse: - g_system->displayMessageOnOSD(_("Escape Key")); - _shortcut = kEscapeKey; - break; - - case kEscapeKey: - g_system->displayMessageOnOSD(_("Game Menu")); - _shortcut = kGameMenu; - break; - - case kGameMenu: - g_system->displayMessageOnOSD(_("Show Keypad")); - _shortcut = kShowKeypad; - break; - - case kSetVolume: - // fallthru - - case kShowKeypad: - g_system->displayMessageOnOSD(_("Control Mouse")); - _shortcut = kControlMouse; - break; - } -} - -void BadaAppForm::setVolume(bool up, bool minMax) { - int level = ((BadaSystem *)g_system)->setVolume(up, minMax); - if (level != -1) { - char message[32]; - char ind[LEVEL_RANGE]; // 1..5 (0=off) - int j = LEVEL_RANGE - 1; // 0..4 - for (int i = 1; i <= LEVEL_RANGE; i++) { - ind[j--] = level >= i ? '|' : ' '; - } - snprintf(message, sizeof(message), "Volume: [ %c%c%c%c%c ]", - ind[0], ind[1], ind[2], ind[3], ind[4]); - g_system->displayMessageOnOSD(message); - } -} - -void BadaAppForm::showKeypad() { - // display the soft keyboard - _buttonState = kLeftButton; - pushKey(Common::KEYCODE_F7); -} - -void BadaAppForm::OnTouchDoublePressed(const Control &source, - const Point ¤tPosition, - const TouchEventInfo &touchInfo) { - if (_buttonState != kMoveOnly) { - pushEvent(_buttonState == kLeftButton ? Common::EVENT_LBUTTONDOWN : Common::EVENT_RBUTTONDOWN, - currentPosition); - pushEvent(_buttonState == kLeftButton ? Common::EVENT_LBUTTONDOWN : Common::EVENT_RBUTTONDOWN, - currentPosition); - } -} - -void BadaAppForm::OnTouchFocusIn(const Control &source, - const Point ¤tPosition, - const TouchEventInfo &touchInfo) { -} - -void BadaAppForm::OnTouchFocusOut(const Control &source, - const Point ¤tPosition, - const TouchEventInfo &touchInfo) { -} - -void BadaAppForm::OnTouchLongPressed(const Control &source, - const Point ¤tPosition, - const TouchEventInfo &touchInfo) { - if (_buttonState != kLeftButton) { - pushKey(Common::KEYCODE_RETURN); - } -} - -void BadaAppForm::OnTouchMoved(const Control &source, - const Point ¤tPosition, - const TouchEventInfo &touchInfo) { - pushEvent(Common::EVENT_MOUSEMOVE, currentPosition); -} - -void BadaAppForm::OnTouchPressed(const Control &source, - const Point ¤tPosition, - const TouchEventInfo &touchInfo) { - if (_buttonState != kMoveOnly) { - pushEvent(_buttonState == kLeftButton ? Common::EVENT_LBUTTONDOWN : Common::EVENT_RBUTTONDOWN, - currentPosition); - } -} - -void BadaAppForm::OnTouchReleased(const Control &source, - const Point ¤tPosition, - const TouchEventInfo &touchInfo) { - if (_buttonState != kMoveOnly) { - pushEvent(_buttonState == kLeftButton ? Common::EVENT_LBUTTONUP : Common::EVENT_RBUTTONUP, - currentPosition); - if (_buttonState == kRightButtonOnce) { - _buttonState = kLeftButton; - } - // flick to skip dialog - if (touchInfo.IsFlicked()) { - pushKey(Common::KEYCODE_PERIOD); - } - } -} - -void BadaAppForm::OnKeyLongPressed(const Control &source, KeyCode keyCode) { - logEntered(); - switch (keyCode) { - case KEY_SIDE_UP: - _shortcut = kSetVolume; - setVolume(true, true); - return; - - case KEY_SIDE_DOWN: - _shortcut = kSetVolume; - setVolume(false, true); - return; - - case KEY_CAMERA: - _shortcut = kShowKeypad; - showKeypad(); - return; - - default: - break; - } -} - -void BadaAppForm::OnKeyPressed(const Control &source, KeyCode keyCode) { - switch (keyCode) { - case KEY_SIDE_UP: - if (_shortcut != kSetVolume) { - _shortcut = kSetVolume; - } else { - setVolume(true, false); - } - return; - - case KEY_SIDE_DOWN: - switch (_shortcut) { - case kControlMouse: - setButtonShortcut(); - break; - - case kEscapeKey: - pushKey(Common::KEYCODE_ESCAPE); - break; - - case kGameMenu: - _buttonState = kLeftButton; - pushKey(Common::KEYCODE_F5); - break; - - case kShowKeypad: - showKeypad(); - break; - - default: - setVolume(false, false); - break; - } - break; - - case KEY_CAMERA: - setShortcut(); - break; - - default: - break; - } -} - -void BadaAppForm::OnKeyReleased(const Control &source, KeyCode keyCode) { -} diff --git a/backends/platform/bada/form.h b/backends/platform/bada/form.h deleted file mode 100644 index 3340e2216b..0000000000 --- a/backends/platform/bada/form.h +++ /dev/null @@ -1,108 +0,0 @@ -/* 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 BADA_FORM_H -#define BADA_FORM_H - -#include <FApp.h> -#include <FUi.h> -#include <FSystem.h> -#include <FBase.h> -#include <FUiITouchEventListener.h> -#include <FUiITextEventListener.h> - -#include "config.h" -#include "common/scummsys.h" -#include "common/events.h" -#include "common/queue.h" -#include "common/mutex.h" - -// -// BadaAppForm -// -class BadaAppForm : public Osp::Ui::Controls::Form, - public Osp::Ui::IOrientationEventListener, - public Osp::Ui::ITouchEventListener, - public Osp::Ui::IKeyEventListener, - public Osp::Base::Runtime::IRunnable { -public: - BadaAppForm(); - ~BadaAppForm(); - - result Construct(); - bool pollEvent(Common::Event &event); - bool isClosing() { return _state == kClosingState; } - void pushKey(Common::KeyCode keycode); - void exitSystem(); - -private: - Object *Run(); - result OnInitializing(void); - result OnDraw(void); - void OnOrientationChanged(const Osp::Ui::Control &source, - Osp::Ui::OrientationStatus orientationStatus); - void OnTouchDoublePressed(const Osp::Ui::Control &source, - const Osp::Graphics::Point ¤tPosition, - const Osp::Ui::TouchEventInfo &touchInfo); - void OnTouchFocusIn(const Osp::Ui::Control &source, - const Osp::Graphics::Point ¤tPosition, - const Osp::Ui::TouchEventInfo &touchInfo); - void OnTouchFocusOut(const Osp::Ui::Control &source, - const Osp::Graphics::Point ¤tPosition, - const Osp::Ui::TouchEventInfo &touchInfo); - void OnTouchLongPressed(const Osp::Ui::Control &source, - const Osp::Graphics::Point ¤tPosition, - const Osp::Ui::TouchEventInfo &touchInfo); - void OnTouchMoved(const Osp::Ui::Control &source, - const Osp::Graphics::Point ¤tPosition, - const Osp::Ui::TouchEventInfo &touchInfo); - void OnTouchPressed(const Osp::Ui::Control &source, - const Osp::Graphics::Point ¤tPosition, - const Osp::Ui::TouchEventInfo &touchInfo); - void OnTouchReleased(const Osp::Ui::Control &source, - const Osp::Graphics::Point ¤tPosition, - const Osp::Ui::TouchEventInfo &touchInfo); - void OnKeyLongPressed(const Osp::Ui::Control &source, - Osp::Ui::KeyCode keyCode); - void OnKeyPressed(const Osp::Ui::Control &source, - Osp::Ui::KeyCode keyCode); - void OnKeyReleased(const Osp::Ui::Control &source, - Osp::Ui::KeyCode keyCode); - - void pushEvent(Common::EventType type, - const Osp::Graphics::Point ¤tPosition); - void terminate(); - void setButtonShortcut(); - void setShortcut(); - void setVolume(bool up, bool minMax); - void showKeypad(); - - // event handling - Osp::Base::Runtime::Thread *_gameThread; - Osp::Base::Runtime::Mutex *_eventQueueLock; - Common::Queue<Common::Event> _eventQueue; - enum { kInitState, kActiveState, kClosingState, kDoneState, kErrorState } _state; - enum { kLeftButton, kRightButtonOnce, kRightButton, kMoveOnly } _buttonState; - enum { kControlMouse, kEscapeKey, kGameMenu, kShowKeypad, kSetVolume } _shortcut; -}; - -#endif diff --git a/backends/platform/dc/dc.h b/backends/platform/dc/dc.h index d41839d961..d62ced02e1 100644 --- a/backends/platform/dc/dc.h +++ b/backends/platform/dc/dc.h @@ -151,7 +151,7 @@ public: void setShakePos(int shake_pos); // Get the number of milliseconds since the program was started. - uint32 getMillis(); + uint32 getMillis(bool skipRecord = false); // Delay for a specified amount of milliseconds void delayMillis(uint msecs); diff --git a/backends/platform/dc/display.cpp b/backends/platform/dc/display.cpp index cc5798fc10..54ee6000ed 100644 --- a/backends/platform/dc/display.cpp +++ b/backends/platform/dc/display.cpp @@ -711,11 +711,7 @@ Graphics::Surface *OSystem_Dreamcast::lockScreen() if (!screen) return 0; - _framebuffer.pixels = screen; - _framebuffer.w = _screen_w; - _framebuffer.h = _screen_h; - _framebuffer.pitch = SCREEN_W*2; - _framebuffer.format = screenFormats[_screenFormat]; + _framebuffer.init(_screen_w, _screen_h, SCREEN_W*2, screen, screenFormats[_screenFormat]); return &_framebuffer; } diff --git a/backends/platform/dc/selector.cpp b/backends/platform/dc/selector.cpp index 339e5df62d..4026c7dde6 100644 --- a/backends/platform/dc/selector.cpp +++ b/backends/platform/dc/selector.cpp @@ -219,7 +219,7 @@ static int findGames(Game *games, int max, bool use_ini) if (use_ini) { ConfMan.loadDefaultConfigFile(); - Common::ConfigManager::DomainMap &game_domains = ConfMan.getGameDomains(); + const Common::ConfigManager::DomainMap &game_domains = ConfMan.getGameDomains(); for(Common::ConfigManager::DomainMap::const_iterator i = game_domains.begin(); curr_game < max && i != game_domains.end(); i++) { Common::String path = (*i)._value["path"]; diff --git a/backends/platform/dc/time.cpp b/backends/platform/dc/time.cpp index 8cc3a71e8d..1e5f44ec85 100644 --- a/backends/platform/dc/time.cpp +++ b/backends/platform/dc/time.cpp @@ -26,7 +26,7 @@ #include "dc.h" -uint32 OSystem_Dreamcast::getMillis() +uint32 OSystem_Dreamcast::getMillis(bool skipRecord) { static uint32 msecs=0; static unsigned int t0=0; diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp index 830c782b90..9dc66e80d7 100644 --- a/backends/platform/ds/arm9/source/dsmain.cpp +++ b/backends/platform/ds/arm9/source/dsmain.cpp @@ -2280,7 +2280,7 @@ void VBlankHandler(void) { //REG_IF = IRQ_VBLANK; } -int getMillis() { +int getMillis(bool skipRecord) { return currentTimeMillis; // return frameCount * FRAME_TIME; } diff --git a/backends/platform/ds/arm9/source/dsmain.h b/backends/platform/ds/arm9/source/dsmain.h index ad49ae276d..5e91fae13a 100644 --- a/backends/platform/ds/arm9/source/dsmain.h +++ b/backends/platform/ds/arm9/source/dsmain.h @@ -88,7 +88,7 @@ void setGamma(int gamma); // Timers void setTimerCallback(OSystem_DS::TimerProc proc, int interval); // Setup a callback function at a regular interval -int getMillis(); // Return the current runtime in milliseconds +int getMillis(bool skipRecord = false); // Return the current runtime in milliseconds void doTimerCallback(); // Call callback function if required // Sound diff --git a/backends/platform/ds/arm9/source/osystem_ds.cpp b/backends/platform/ds/arm9/source/osystem_ds.cpp index a4b9c842fc..f109983fbc 100644 --- a/backends/platform/ds/arm9/source/osystem_ds.cpp +++ b/backends/platform/ds/arm9/source/osystem_ds.cpp @@ -296,7 +296,7 @@ void OSystem_DS::copyRectToScreen(const void *buf, int pitch, int x, int y, int // to save a few pennies/euro cents on the hardware. if (_frameBufferExists) { - bg = (u16 *)_framebuffer.pixels; + bg = (u16 *)_framebuffer.getPixels(); stride = _framebuffer.pitch; } else { bg = (u16 *)DS::get8BitBackBuffer(); @@ -455,7 +455,7 @@ void OSystem_DS::copyRectToScreen(const void *buf, int pitch, int x, int y, int dmaCopyHalfWords(3, src, dest1, w); - if ((!_frameBufferExists) || (buf == _framebuffer.pixels)) { + if ((!_frameBufferExists) || (buf == _framebuffer.getPixels())) { dmaCopyHalfWords(2, src, dest2, w); } @@ -476,7 +476,7 @@ void OSystem_DS::updateScreen() { _frameBufferExists = false; // Copy temp framebuffer back to screen - copyRectToScreen((byte *)_framebuffer.pixels, _framebuffer.pitch, 0, 0, _framebuffer.w, _framebuffer.h); + copyRectToScreen((byte *)_framebuffer.getPixels(), _framebuffer.pitch, 0, 0, _framebuffer.w, _framebuffer.h); } DS::displayMode16BitFlipBuffer(); @@ -656,7 +656,7 @@ bool OSystem_DS::pollEvent(Common::Event &event) { return false; } -uint32 OSystem_DS::getMillis() { +uint32 OSystem_DS::getMillis(bool skipRecord) { return DS::getMillis(); } @@ -755,11 +755,8 @@ Graphics::Surface *OSystem_DS::createTempFrameBuffer() { if (DS::isCpuScalerEnabled()) { - _framebuffer.pixels = DS::getScalerBuffer(); - _framebuffer.w = DS::getGameWidth(); - _framebuffer.h = DS::getGameHeight(); - _framebuffer.pitch = DS::getGameWidth(); - _framebuffer.format = Graphics::PixelFormat::createFormatCLUT8(); + _framebuffer.init(DS::getGameWidth(), DS::getGameHeight(), DS::getGameWidth(), + DS::getScalerBuffer(), Graphics::PixelFormat::createFormatCLUT8()); } else { @@ -780,11 +777,7 @@ Graphics::Surface *OSystem_DS::createTempFrameBuffer() { dmaCopyHalfWords(3, srcLine, destLine, width); } - _framebuffer.pixels = dest; - _framebuffer.w = width; - _framebuffer.h = height; - _framebuffer.pitch = width; - _framebuffer.format = Graphics::PixelFormat::createFormatCLUT8(); + _framebuffer.init(width, height, width, dest, Graphics::PixelFormat::createFormatCLUT8()); } @@ -798,8 +791,8 @@ Graphics::Surface *OSystem_DS::createTempFrameBuffer() { for (int y = 0; y < DS::getGameHeight(); y++) { DC_FlushRange(image + (y * imageStrideInWords), DS::getGameWidth()); for (int x = 0; x < DS::getGameWidth() >> 1; x++) { - *(((u16 *) (_framebuffer.pixels)) + y * (DS::getGameWidth() >> 1) + x) = image[(y * imageStrideInWords) + x]; -// *(((u16 *) (surf->pixels)) + y * (DS::getGameWidth() >> 1) + x) = image[y * imageStrideInWords + x]; + *(((u16 *) (_framebuffer.getPixels())) + y * (DS::getGameWidth() >> 1) + x) = image[(y * imageStrideInWords) + x]; +// *(((u16 *) (surf->getPixels())) + y * (DS::getGameWidth() >> 1) + x) = image[y * imageStrideInWords + x]; } }*/ diff --git a/backends/platform/ds/arm9/source/osystem_ds.h b/backends/platform/ds/arm9/source/osystem_ds.h index a6001da764..4550e22b2c 100644 --- a/backends/platform/ds/arm9/source/osystem_ds.h +++ b/backends/platform/ds/arm9/source/osystem_ds.h @@ -117,7 +117,7 @@ public: virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, u32 keycolor, bool dontScale, const Graphics::PixelFormat *format); virtual bool pollEvent(Common::Event &event); - virtual uint32 getMillis(); + virtual uint32 getMillis(bool skipRecord = false); virtual void delayMillis(uint msecs); virtual void getTimeAndDate(TimeDate &t) const; diff --git a/backends/platform/iphone/iphone_video.mm b/backends/platform/iphone/iphone_video.mm index 0bfae30fc7..f2c1527658 100644 --- a/backends/platform/iphone/iphone_video.mm +++ b/backends/platform/iphone/iphone_video.mm @@ -365,7 +365,7 @@ const char *iPhone_getDocumentsDir() { _mouseTexCoords[5] = _mouseTexCoords[7] = _videoContext.mouseHeight / (GLfloat)_videoContext.mouseTexture.h; glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.mouseTexture.w, _videoContext.mouseTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.mouseTexture.pixels); printOpenGLError(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.mouseTexture.w, _videoContext.mouseTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.mouseTexture.getPixels()); printOpenGLError(); } - (void)updateMainSurface { @@ -377,7 +377,7 @@ const char *iPhone_getDocumentsDir() { // Unfortunately we have to update the whole texture every frame, since glTexSubImage2D is actually slower in all cases // due to the iPhone internals having to convert the whole texture back from its internal format when used. // In the future we could use several tiled textures instead. - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w, _videoContext.screenTexture.h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _videoContext.screenTexture.pixels); printOpenGLError(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w, _videoContext.screenTexture.h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _videoContext.screenTexture.getPixels()); printOpenGLError(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); } @@ -386,7 +386,7 @@ const char *iPhone_getDocumentsDir() { glTexCoordPointer(2, GL_FLOAT, 0, _overlayTexCoords); printOpenGLError(); glBindTexture(GL_TEXTURE_2D, _overlayTexture); printOpenGLError(); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.overlayTexture.w, _videoContext.overlayTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.overlayTexture.pixels); printOpenGLError(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.overlayTexture.w, _videoContext.overlayTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.overlayTexture.getPixels()); printOpenGLError(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); } diff --git a/backends/platform/iphone/osys_main.cpp b/backends/platform/iphone/osys_main.cpp index ed2c886213..a814495b80 100644 --- a/backends/platform/iphone/osys_main.cpp +++ b/backends/platform/iphone/osys_main.cpp @@ -77,8 +77,8 @@ OSystem_IPHONE::~OSystem_IPHONE() { delete _mixer; // Prevent accidental freeing of the screen texture here. This needs to be // checked since we might use the screen texture as framebuffer in the case - // of hi-color games for example. - if (_framebuffer.pixels == _videoContext->screenTexture.pixels) + // of hi-color games for example. Otherwise this can lead to a double free. + if (_framebuffer.getPixels() != _videoContext->screenTexture.getPixels()) _framebuffer.free(); _mouseBuffer.free(); } @@ -166,7 +166,7 @@ void OSystem_IPHONE::suspendLoop() { _timeSuspended += getMillis() - startTime; } -uint32 OSystem_IPHONE::getMillis() { +uint32 OSystem_IPHONE::getMillis(bool skipRecord) { //printf("getMillis()\n"); struct timeval currentTime; diff --git a/backends/platform/iphone/osys_main.h b/backends/platform/iphone/osys_main.h index 037125490d..811a8ddb2e 100644 --- a/backends/platform/iphone/osys_main.h +++ b/backends/platform/iphone/osys_main.h @@ -165,7 +165,7 @@ public: virtual void setCursorPalette(const byte *colors, uint start, uint num); virtual bool pollEvent(Common::Event &event); - virtual uint32 getMillis(); + virtual uint32 getMillis(bool skipRecord = false); virtual void delayMillis(uint msecs); virtual MutexRef createMutex(void); diff --git a/backends/platform/iphone/osys_video.mm b/backends/platform/iphone/osys_video.mm index a11bf32c54..ce7f94f5bd 100644 --- a/backends/platform/iphone/osys_video.mm +++ b/backends/platform/iphone/osys_video.mm @@ -76,8 +76,8 @@ void OSystem_IPHONE::initSize(uint width, uint height, const Graphics::PixelForm // In case we use the screen texture as frame buffer we reset the pixels // pointer here to avoid freeing the screen texture. - if (_framebuffer.pixels == _videoContext->screenTexture.pixels) - _framebuffer.pixels = 0; + if (_framebuffer.getPixels() == _videoContext->screenTexture.getPixels()) + _framebuffer.setPixels(0); // Create the screen texture right here. We need to do this here, since // when a game requests hi-color mode, we actually set the framebuffer @@ -310,7 +310,7 @@ void OSystem_IPHONE::hideOverlay() { void OSystem_IPHONE::clearOverlay() { //printf("clearOverlay()\n"); - bzero(_videoContext->overlayTexture.getBasePtr(0, 0), _videoContext->overlayTexture.h * _videoContext->overlayTexture.pitch); + bzero(_videoContext->overlayTexture.getPixels(), _videoContext->overlayTexture.h * _videoContext->overlayTexture.pitch); dirtyFullOverlayScreen(); } @@ -319,7 +319,7 @@ void OSystem_IPHONE::grabOverlay(void *buf, int pitch) { int h = _videoContext->overlayHeight; byte *dst = (byte *)buf; - const byte *src = (const byte *)_videoContext->overlayTexture.getBasePtr(0, 0); + const byte *src = (const byte *)_videoContext->overlayTexture.getPixels(); do { memcpy(dst, src, _videoContext->overlayWidth * sizeof(uint16)); src += _videoContext->overlayTexture.pitch; @@ -417,7 +417,7 @@ void OSystem_IPHONE::setMouseCursor(const void *buf, uint w, uint h, int hotspot #endif assert(pixelFormat.bytesPerPixel == 1 || pixelFormat.bytesPerPixel == 2); - if (_mouseBuffer.w != w || _mouseBuffer.h != h || _mouseBuffer.format != pixelFormat || !_mouseBuffer.pixels) + if (_mouseBuffer.w != w || _mouseBuffer.h != h || _mouseBuffer.format != pixelFormat || !_mouseBuffer.getPixels()) _mouseBuffer.create(w, h, pixelFormat); _videoContext->mouseWidth = w; @@ -428,7 +428,7 @@ void OSystem_IPHONE::setMouseCursor(const void *buf, uint w, uint h, int hotspot _mouseKeyColor = keycolor; - memcpy(_mouseBuffer.getBasePtr(0, 0), buf, h * _mouseBuffer.pitch); + memcpy(_mouseBuffer.getPixels(), buf, h * _mouseBuffer.pitch); _mouseDirty = true; _mouseNeedTextureUpdate = true; @@ -464,7 +464,7 @@ void OSystem_IPHONE::updateMouseTexture() { else palette = _gamePaletteRGBA5551; - uint16 *mouseBuf = (uint16 *)mouseTexture.getBasePtr(0, 0); + uint16 *mouseBuf = (uint16 *)mouseTexture.getPixels(); for (uint x = 0; x < _videoContext->mouseWidth; ++x) { for (uint y = 0; y < _videoContext->mouseHeight; ++y) { const byte color = *(const byte *)_mouseBuffer.getBasePtr(x, y); @@ -475,12 +475,12 @@ void OSystem_IPHONE::updateMouseTexture() { } } } else { - if (crossBlit((byte *)mouseTexture.getBasePtr(0, 0), (const byte *)_mouseBuffer.getBasePtr(0, 0), mouseTexture.pitch, + if (crossBlit((byte *)mouseTexture.getPixels(), (const byte *)_mouseBuffer.getPixels(), mouseTexture.pitch, _mouseBuffer.pitch, _mouseBuffer.w, _mouseBuffer.h, mouseTexture.format, _mouseBuffer.format)) { if (!_mouseBuffer.format.aBits()) { // Apply color keying since the original cursor had no alpha channel. - const uint16 *src = (const uint16 *)_mouseBuffer.getBasePtr(0, 0); - uint8 *dstRaw = (uint8 *)mouseTexture.getBasePtr(0, 0); + const uint16 *src = (const uint16 *)_mouseBuffer.getPixels(); + uint8 *dstRaw = (uint8 *)mouseTexture.getPixels(); for (uint y = 0; y < _mouseBuffer.h; ++y, dstRaw += mouseTexture.pitch) { uint16 *dst = (uint16 *)dstRaw; @@ -495,7 +495,7 @@ void OSystem_IPHONE::updateMouseTexture() { } else { // TODO: Log this! // Make the cursor all transparent... we really need a better fallback ;-). - memset(mouseTexture.getBasePtr(0, 0), 0, mouseTexture.h * mouseTexture.pitch); + memset(mouseTexture.getPixels(), 0, mouseTexture.h * mouseTexture.pitch); } } diff --git a/backends/platform/n64/osys_n64.h b/backends/platform/n64/osys_n64.h index bc6b3cb1a5..10138b230a 100644 --- a/backends/platform/n64/osys_n64.h +++ b/backends/platform/n64/osys_n64.h @@ -184,7 +184,7 @@ public: virtual void setCursorPalette(const byte *colors, uint start, uint num); virtual bool pollEvent(Common::Event &event); - virtual uint32 getMillis(); + virtual uint32 getMillis(bool skipRecord = false); virtual void delayMillis(uint msecs); virtual MutexRef createMutex(void); diff --git a/backends/platform/n64/osys_n64_base.cpp b/backends/platform/n64/osys_n64_base.cpp index 1e2aca9e51..36e5085764 100644 --- a/backends/platform/n64/osys_n64_base.cpp +++ b/backends/platform/n64/osys_n64_base.cpp @@ -605,11 +605,7 @@ void OSystem_N64::updateScreen() { } Graphics::Surface *OSystem_N64::lockScreen() { - _framebuffer.pixels = _offscreen_pal; - _framebuffer.w = _gameWidth; - _framebuffer.h = _gameHeight; - _framebuffer.pitch = _screenWidth; - _framebuffer.format = Graphics::PixelFormat::createFormatCLUT8(); + _framebuffer.init(_gameWidth, _gameHeight, _screenWidth, _offscreen_pal, Graphics::PixelFormat::createFormatCLUT8()); return &_framebuffer; } @@ -810,7 +806,7 @@ void OSystem_N64::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, return; } -uint32 OSystem_N64::getMillis() { +uint32 OSystem_N64::getMillis(bool skipRecord) { return getMilliTick(); } diff --git a/backends/platform/null/null.cpp b/backends/platform/null/null.cpp index 4690a67c55..9e05539799 100644 --- a/backends/platform/null/null.cpp +++ b/backends/platform/null/null.cpp @@ -49,7 +49,7 @@ public: virtual bool pollEvent(Common::Event &event); - virtual uint32 getMillis(); + virtual uint32 getMillis(bool skipRecord = false); virtual void delayMillis(uint msecs); virtual void getTimeAndDate(TimeDate &t) const {} diff --git a/backends/platform/ps2/Gs2dScreen.cpp b/backends/platform/ps2/Gs2dScreen.cpp index e818305c29..58667c0230 100644 --- a/backends/platform/ps2/Gs2dScreen.cpp +++ b/backends/platform/ps2/Gs2dScreen.cpp @@ -392,12 +392,8 @@ void Gs2dScreen::copyScreenRect(const uint8 *buf, int pitch, int x, int y, int w Graphics::Surface *Gs2dScreen::lockScreen() { WaitSema(g_DmacSema); - _framebuffer.pixels = _screenBuf; - _framebuffer.w = _width; - _framebuffer.h = _height; - _framebuffer.pitch = _width; // -not- _pitch; ! It's EE mem, not Tex - _framebuffer.format = Graphics::PixelFormat::createFormatCLUT8(); - + // -not- _pitch; ! It's EE mem, not Tex + _framebuffer.init(_width, _height, _width, _screenBuf, Graphics::PixelFormat::createFormatCLUT8()); return &_framebuffer; } diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp index 5628658381..a7d782b07c 100644 --- a/backends/platform/ps2/systemps2.cpp +++ b/backends/platform/ps2/systemps2.cpp @@ -571,7 +571,7 @@ void OSystem_PS2::displayMessageOnOSD(const char *msg) { printf("displayMessageOnOSD: %s\n", msg); } -uint32 OSystem_PS2::getMillis(void) { +uint32 OSystem_PS2::getMillis(bool skipRecord) { return msecCount; } diff --git a/backends/platform/ps2/systemps2.h b/backends/platform/ps2/systemps2.h index 99482d4da4..3ba40a70f9 100644 --- a/backends/platform/ps2/systemps2.h +++ b/backends/platform/ps2/systemps2.h @@ -82,7 +82,7 @@ public: virtual void warpMouse(int x, int y); virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = 0); - virtual uint32 getMillis(); + virtual uint32 getMillis(bool skipRecord = false); virtual void delayMillis(uint msecs); virtual bool pollEvent(Common::Event &event); diff --git a/backends/platform/psp/default_display_client.cpp b/backends/platform/psp/default_display_client.cpp index bc252144fa..6d6eb641f7 100644 --- a/backends/platform/psp/default_display_client.cpp +++ b/backends/platform/psp/default_display_client.cpp @@ -192,11 +192,8 @@ void Screen::setScummvmPixelFormat(const Graphics::PixelFormat *format) { Graphics::Surface *Screen::lockAndGetForEditing() { DEBUG_ENTER_FUNC(); - _frameBuffer.pixels = _buffer.getPixels(); - _frameBuffer.w = _buffer.getSourceWidth(); - _frameBuffer.h = _buffer.getSourceHeight(); - _frameBuffer.pitch = _buffer.getBytesPerPixel() * _buffer.getWidth(); - _frameBuffer.format = _pixelFormat; + _frameBuffer.init(_buffer.getSourceWidth(), _buffer.getSourceHeight(), _buffer.getBytesPerPixel() * _buffer.getWidth(), + _buffer.getPixels(), _pixelFormat); // We'll set to dirty once we unlock the screen return &_frameBuffer; diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp index fb8c1c60bf..8559066e53 100644 --- a/backends/platform/psp/osys_psp.cpp +++ b/backends/platform/psp/osys_psp.cpp @@ -349,7 +349,7 @@ bool OSystem_PSP::pollEvent(Common::Event &event) { return _inputHandler.getAllInputs(event); } -uint32 OSystem_PSP::getMillis() { +uint32 OSystem_PSP::getMillis(bool skipRecord) { return PspRtc::instance().getMillis(); } diff --git a/backends/platform/psp/osys_psp.h b/backends/platform/psp/osys_psp.h index 2afdabd0fc..f4591e476d 100644 --- a/backends/platform/psp/osys_psp.h +++ b/backends/platform/psp/osys_psp.h @@ -125,7 +125,7 @@ public: bool processInput(Common::Event &event); // Time - uint32 getMillis(); + uint32 getMillis(bool skipRecord = false); void delayMillis(uint msecs); // Timer diff --git a/backends/platform/psp/rtc.cpp b/backends/platform/psp/rtc.cpp index cbbb7d3f80..4f15e45535 100644 --- a/backends/platform/psp/rtc.cpp +++ b/backends/platform/psp/rtc.cpp @@ -52,7 +52,7 @@ void PspRtc::init() { // init our starting ticks // Note that after we fill up 32 bits ie 50 days we'll loop back to 0, which may cause // unpredictable results -uint32 PspRtc::getMillis() { +uint32 PspRtc::getMillis(bool skipRecord) { uint32 ticks[2]; sceRtcGetCurrentTick((u64 *)ticks); // can introduce weird thread delays diff --git a/backends/platform/psp/rtc.h b/backends/platform/psp/rtc.h index 45885c3e66..d2689681dd 100644 --- a/backends/platform/psp/rtc.h +++ b/backends/platform/psp/rtc.h @@ -40,7 +40,7 @@ public: init(); } void init(); - uint32 getMillis(); + uint32 getMillis(bool skipRecord = false); uint32 getMicros(); }; diff --git a/backends/platform/sdl/sdl-sys.h b/backends/platform/sdl/sdl-sys.h index ca3c586e03..eccf73815d 100644 --- a/backends/platform/sdl/sdl-sys.h +++ b/backends/platform/sdl/sdl-sys.h @@ -35,8 +35,11 @@ // it with an alternate slightly less unfriendly override. #if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_FILE) #undef FILE +// Solaris has typedef __FILE FILE in several places already +#if !defined(__sun) typedef struct { int FAKE; } FAKE_FILE; #define FILE FAKE_FILE +#endif // (__sun) #endif #if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_strcasecmp) diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index d54854352d..7ab367d4a4 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -30,7 +30,7 @@ #include "backends/platform/sdl/sdl.h" #include "common/config-manager.h" -#include "common/EventRecorder.h" +#include "gui/EventRecorder.h" #include "common/taskbar.h" #include "common/textconsole.h" @@ -97,7 +97,15 @@ OSystem_SDL::~OSystem_SDL() { _audiocdManager = 0; delete _mixerManager; _mixerManager = 0; + +#ifdef ENABLE_EVENTRECORDER + // HACK HACK HACK + // This is nasty. + delete g_eventRec.getTimerManager(); +#else delete _timerManager; +#endif + _timerManager = 0; delete _mutexManager; _mutexManager = 0; @@ -131,9 +139,6 @@ void OSystem_SDL::init() { if (_mutexManager == 0) _mutexManager = new SdlMutexManager(); - if (_timerManager == 0) - _timerManager = new SdlTimerManager(); - #if defined(USE_TASKBAR) if (_taskbarManager == 0) _taskbarManager = new Common::TaskbarManager(); @@ -191,11 +196,19 @@ void OSystem_SDL::initBackend() { if (_mixerManager == 0) { _mixerManager = new SdlMixerManager(); - // Setup and start mixer _mixerManager->init(); } +#ifdef ENABLE_EVENTRECORDER + g_eventRec.registerMixerManager(_mixerManager); + + g_eventRec.registerTimerManager(new SdlTimerManager()); +#else + if (_timerManager == 0) + _timerManager = new SdlTimerManager(); +#endif + if (_audiocdManager == 0) { // Audio CD support was removed with SDL 1.3 #if SDL_VERSION_ATLEAST(1, 3, 0) @@ -466,14 +479,21 @@ void OSystem_SDL::setupIcon() { free(icon); } -uint32 OSystem_SDL::getMillis() { + +uint32 OSystem_SDL::getMillis(bool skipRecord) { uint32 millis = SDL_GetTicks(); - g_eventRec.processMillis(millis); + +#ifdef ENABLE_EVENTRECORDER + g_eventRec.processMillis(millis, skipRecord); +#endif + return millis; } void OSystem_SDL::delayMillis(uint msecs) { - if (!g_eventRec.processDelayMillis(msecs)) +#ifdef ENABLE_EVENTRECORDER + if (!g_eventRec.processDelayMillis()) +#endif SDL_Delay(msecs); } @@ -491,12 +511,25 @@ void OSystem_SDL::getTimeAndDate(TimeDate &td) const { Audio::Mixer *OSystem_SDL::getMixer() { assert(_mixerManager); - return _mixerManager->getMixer(); + return getMixerManager()->getMixer(); } SdlMixerManager *OSystem_SDL::getMixerManager() { assert(_mixerManager); + +#ifdef ENABLE_EVENTRECORDER + return g_eventRec.getMixerManager(); +#else return _mixerManager; +#endif +} + +Common::TimerManager *OSystem_SDL::getTimerManager() { +#ifdef ENABLE_EVENTRECORDER + return g_eventRec.getTimerManager(); +#else + return _timerManager; +#endif } #ifdef USE_OPENGL diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h index f05207b482..840e73ff09 100644 --- a/backends/platform/sdl/sdl.h +++ b/backends/platform/sdl/sdl.h @@ -68,10 +68,11 @@ public: virtual void setWindowCaption(const char *caption); virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); - virtual uint32 getMillis(); + virtual uint32 getMillis(bool skipRecord = false); virtual void delayMillis(uint msecs); virtual void getTimeAndDate(TimeDate &td) const; virtual Audio::Mixer *getMixer(); + virtual Common::TimerManager *getTimerManager(); protected: bool _inited; diff --git a/backends/platform/bada/README.TXT b/backends/platform/tizen/README.TXT index c4a04d5450..def3da2cce 100644 --- a/backends/platform/bada/README.TXT +++ b/backends/platform/tizen/README.TXT @@ -1,77 +1,58 @@ -Build instructions: +Build instructions (using linux) -1. Install BADA SDK (requires free registration): - - http://developer.bada.com/apis/index.do - -2. Install Cygwin: - - http://www.cygwin.com/ +1. Install the Tizen SDK - Add the following to your cygwin .bash_profile: +http://www.tizen.org - alias mmake=/cygdrive/c/MinGW/bin/mingw32-make.exe - export BADA_SDK=/cygdrive/c/bada/1.2.1 - export ARM_BIN=c:/bada/1.2.1/Tools/Toolchains/ARM/bin - export CPPFLAGS="-fpic -fshort-wchar -mcpu=cortex-a8 -mfpu=vfpv3 \ - -mfloat-abi=hard -mlittle-endian -mthumb-interwork -Wno-psabi \ - -fno-strict-aliasing -fno-short-enums" - export LDFLAGS="-nostdlib -lc-newlib -lm-newlib -LC:/bada/1.2.1/Model/Wave_LP1/Target" - #export PATH=${BADA_SDK}/Tools/Toolchains/Win32/bin:${PATH} - export PATH=${BADA_SDK}/Tools/Toolchains/ARM/bin:~/utils:${PATH} - alias gcc=${ARM_BIN}/arm-samsung-nucleuseabi-gcc.exe - alias ar=${ARM_BIN}/arm-samsung-nucleuseabi-ar.exe +To use an alternative Java SDK to run the Tizen IDE (eclipse), edit ~/.profile - The following were added to ~/utils for zlib: +export JAVA_HOME=/opt/jdk1.6.0_45 +export PATH=${PATH}:${JAVA_HOME}/bin - ar: - #!/bin/sh - ${ARM_BIN}/arm-samsung-nucleuseabi-ar.exe $* +2. Add the following to your ~/.bashrc file - gcc: - #!/bin/sh - ${ARM_BIN}/arm-samsung-nucleuseabi-gcc.exe $* +export TIZEN_SDK=${HOME}/tizen-sdk +export TIZEN_ROOTSTRAP=${TIZEN_SDK}/platforms/tizen2.1/rootstraps/tizen-device-2.1.native +export TIZEN_BIN=${TIZEN_SDK}/tools/arm-linux-gnueabi-gcc-4.5/bin +export TIZEN_LIBS=${HOME}/tizen-lib +export PATH=${PATH}:${TIZEN_BIN}:~/bin +export CHOST=arm-linux-gnueabi +export LDFLAGS="--sysroot=${TIZEN_ROOTSTRAP} -L${TIZEN_LIBS}/lib" +export CPPFLAGS="--sysroot=${TIZEN_ROOTSTRAP} -fmessage-length=0 -fPIC\ + -I${TIZEN_ROOTSTRAP}/usr/include -I${TIZEN_LIBS}/include" +export CFLAGS=${CPPFLAGS} 3. Build dependencies - zlib, libogg, libvorbis, libmad, FLAC - - see: "Building the libraries" under: + See: "Building the libraries" under: http://wiki.scummvm.org/index.php/Compiling_ScummVM/MinGW#Building_the_libraries for instructions on how to obtain these modules - 3.1 For Target-Release configure ogg and mad with: - - ./configure --host=arm-samsung-nucleuseabi --disable-shared + 3.1 zlib - when building vorbis and flac: + $ ./configure --static --prefix=${TIZEN_LIBS} + $ make && make install - ./configure --host=arm-samsung-nucleuseabi --disable-shared --with-ogg=c:/cygwin/usr/local + 3.2 freetype, libtheora, libogg, libvorbis, libmad, FLAC - 3.2 for each module, after a successful configure, add the following - to the generated config.h (gzguts.h for zlib) + $ ./configure --host=arm-linux-gnueabi --prefix=${TIZEN_LIBS} --disable-shared + $ make && make install - #undef __MINGW32__ - #undef _WIN32 - #include "c:/src/scummvm/backends/platform/bada/portdefs.h" - - 3.3 Additional post configure edits: + Note: you can ignore the ranlib errors when doing make install. - - removed -fforce-mem from the libMAD Makefile - - in libvorbis/lib/Makefile comment lines with vorbis_selftests - - edit libFLAC/Makefile ... CFLAGS = $(OGG_CFLAGS) + Modify the resulting ~/tizen-lib/bin/freetype-config file to include -lz when printing libs - Note: you can ignore the ranlib errors when doing make install. + 3.3 Linker ordering: scummvm, freetype, theoradec, vorbis, vorbisfile, mad, FLAC, ogg, z 4. Build the ScummVM base library: - ./configure --host=bada --enable-release + ./configure --host=tizen --enable-release --with-freetype2-prefix=${TIZEN_LIBS}/bin - To target the Win32 simulator: + For development: - ./configure --host=bada --enable-debug + ./configure --host=tizen --enable-verbose-build --enable-debug -5. Build the front end application using BADA-Ide: +5. Build the front end application using Tizen IDE Copy the scummvm/dists/bada folder into a clean directory outside of the scummvm package. Start the BADA IDE then @@ -90,3 +71,38 @@ HelvB14 font files: Then run the following command: $ ./ucs2any.pl 100dpi/helvB14.bdf MAPPINGS/8859-1.TXT iso8859-1 \ MAPPINGS/8859-2.TXT iso8859-2 MAPPINGS/8859-3.TXT iso8859-3 + +===================================================================== +Archived build instruction for BADA/cygwin + +1. Install BADA SDK (requires free registration): + + http://developer.bada.com/apis/index.do + +2. Install Cygwin: + + http://www.cygwin.com/ + + Add the following to your cygwin .bash_profile: + + alias mmake=/cygdrive/c/MinGW/bin/mingw32-make.exe + export BADA_SDK=/cygdrive/c/bada/1.2.1 + export ARM_BIN=c:/bada/1.2.1/Tools/Toolchains/ARM/bin + export CPPFLAGS="-fpic -fshort-wchar -mcpu=cortex-a8 -mfpu=vfpv3 \ + -mfloat-abi=hard -mlittle-endian -mthumb-interwork -Wno-psabi \ + -fno-strict-aliasing -fno-short-enums" + export LDFLAGS="-nostdlib -lc-newlib -lm-newlib -LC:/bada/1.2.1/Model/Wave_LP1/Target" + #export PATH=${BADA_SDK}/Tools/Toolchains/Win32/bin:${PATH} + export PATH=${BADA_SDK}/Tools/Toolchains/ARM/bin:~/utils:${PATH} + alias gcc=${ARM_BIN}/arm-samsung-nucleuseabi-gcc.exe + alias ar=${ARM_BIN}/arm-samsung-nucleuseabi-ar.exe + + The following were added to ~/utils for zlib: + + ar: + #!/bin/sh + ${ARM_BIN}/arm-samsung-nucleuseabi-ar.exe $* + + gcc: + #!/bin/sh + ${ARM_BIN}/arm-samsung-nucleuseabi-gcc.exe $* diff --git a/backends/platform/bada/application.cpp b/backends/platform/tizen/application.cpp index e761649245..8236ebef67 100644 --- a/backends/platform/bada/application.cpp +++ b/backends/platform/tizen/application.cpp @@ -22,43 +22,55 @@ #include "engines/engine.h" -#include "backends/platform/bada/form.h" -#include "backends/platform/bada/system.h" -#include "backends/platform/bada/application.h" +#include "backends/platform/tizen/form.h" +#include "backends/platform/tizen/system.h" +#include "backends/platform/tizen/application.h" -using namespace Osp::System; -using namespace Osp::Ui::Controls; - -Application *BadaScummVM::createInstance() { - return new BadaScummVM(); +Application *TizenScummVM::createInstance() { + logEntered(); + return new TizenScummVM(); } -BadaScummVM::BadaScummVM() : _appForm(0) { +TizenScummVM::TizenScummVM() : _appForm(0) { + logEntered(); } -BadaScummVM::~BadaScummVM() { +TizenScummVM::~TizenScummVM() { logEntered(); if (g_system) { - BadaSystem *system = (BadaSystem *)g_system; + TizenSystem *system = (TizenSystem *)g_system; system->destroyBackend(); delete system; g_system = 0; } } -bool BadaScummVM::OnAppInitializing(AppRegistry &appRegistry) { +bool TizenScummVM::OnAppInitialized(void) { + logEntered(); + _appForm->SetOrientation(Tizen::Ui::ORIENTATION_LANDSCAPE); + return true; +} + +bool TizenScummVM::OnAppWillTerminate(void) { + logEntered(); + return true; +} + +bool TizenScummVM::OnAppInitializing(AppRegistry &appRegistry) { + logEntered(); _appForm = systemStart(this); return (_appForm != NULL); } -bool BadaScummVM::OnAppTerminating(AppRegistry &appRegistry, - bool forcedTermination) { +bool TizenScummVM::OnAppTerminating(AppRegistry &appRegistry, bool forcedTermination) { logEntered(); return true; } -void BadaScummVM::OnUserEventReceivedN(RequestId requestId, - Osp::Base::Collection::IList *args) { +void TizenScummVM::OnUserEventReceivedN(RequestId requestId, IList *args) { + MessageBox messageBox; + int modalResult; + logEntered(); if (requestId == USER_MESSAGE_EXIT) { @@ -73,39 +85,56 @@ void BadaScummVM::OnUserEventReceivedN(RequestId requestId, if (!message) { message = new String("Unknown error"); } - - MessageBox messageBox; messageBox.Construct(L"Oops...", *message, MSGBOX_STYLE_OK); - int modalResult; + messageBox.ShowAndWait(modalResult); + Terminate(); + } else if (requestId == USER_MESSAGE_EXIT_ERR_CONFIG) { + // the config file was corrupted + messageBox.Construct(L"Config file corrupted", + L"Settings have been reverted, please restart.", MSGBOX_STYLE_OK); messageBox.ShowAndWait(modalResult); Terminate(); } } -void BadaScummVM::OnForeground(void) { +void TizenScummVM::OnForeground(void) { logEntered(); pauseGame(false); } -void BadaScummVM::OnBackground(void) { +void TizenScummVM::OnBackground(void) { logEntered(); pauseGame(true); } -void BadaScummVM::OnBatteryLevelChanged(BatteryLevel batteryLevel) { +void TizenScummVM::OnBatteryLevelChanged(BatteryLevel batteryLevel) { + logEntered(); } -void BadaScummVM::OnLowMemory(void) { +void TizenScummVM::OnLowMemory(void) { + logEntered(); +} + +void TizenScummVM::OnScreenOn(void) { + logEntered(); +} + +void TizenScummVM::OnScreenOff(void) { + logEntered(); +} + +void TizenScummVM::OnScreenBrightnessChanged(int brightness) { + logEntered(); } -void BadaScummVM::pauseGame(bool pause) { +void TizenScummVM::pauseGame(bool pause) { if (_appForm) { if (pause && g_engine && !g_engine->isPaused()) { _appForm->pushKey(Common::KEYCODE_SPACE); } if (g_system) { - ((BadaSystem *)g_system)->setMute(pause); + ((TizenSystem *)g_system)->setMute(pause); } } } diff --git a/backends/platform/tizen/application.h b/backends/platform/tizen/application.h new file mode 100644 index 0000000000..f18ccb175b --- /dev/null +++ b/backends/platform/tizen/application.h @@ -0,0 +1,69 @@ +/* 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 TIZEN_APPLICATION_H +#define TIZEN_APPLICATION_H + +#include <FBase.h> +#include <FApp.h> +#include <FGraphics.h> +#include <FUi.h> +#include <FSystem.h> + +#include "backends/platform/tizen/system.h" +#include "backends/platform/tizen/form.h" + +using namespace Tizen::App; +using namespace Tizen::System; +using namespace Tizen::Ui; +using namespace Tizen::Ui::Controls; +using namespace Tizen::Base::Collection; + +class TizenScummVM : + public UiApp, + public IScreenEventListener { + +public: + TizenScummVM(); + virtual ~TizenScummVM(); + + static UiApp *createInstance(void); + + virtual bool OnAppInitializing(AppRegistry &appRegistry); + virtual bool OnAppInitialized(void); + virtual bool OnAppWillTerminate(void); + virtual bool OnAppTerminating(AppRegistry &appRegistry, bool forcedTermination = false); + virtual void OnLowMemory(void); + virtual void OnBatteryLevelChanged(BatteryLevel batteryLevel); + virtual void OnUserEventReceivedN(RequestId requestId, IList *pArgs); + virtual void OnForeground(void); + virtual void OnBackground(void); + virtual void OnScreenOn(void); + virtual void OnScreenOff(void); + virtual void OnScreenBrightnessChanged(int brightness); + +private: + void pauseGame(bool pause); + TizenAppForm *_appForm; +}; + +#endif diff --git a/backends/platform/bada/audio.cpp b/backends/platform/tizen/audio.cpp index 65a5a80fa5..313a10eaa8 100644 --- a/backends/platform/bada/audio.cpp +++ b/backends/platform/tizen/audio.cpp @@ -23,18 +23,11 @@ #include <FSysSettingInfo.h> #include <FAppAppRegistry.h> -#include "backends/platform/bada/audio.h" -#include "backends/platform/bada/system.h" +#include "backends/platform/tizen/audio.h" +#include "backends/platform/tizen/system.h" -#define TIMER_INCREMENT 10 -#define TIMER_INTERVAL 40 -#define MIN_TIMER_INTERVAL 10 -#define MAX_TIMER_INTERVAL 160 -#define INIT_LEVEL 3 -#define CONFIG_KEY L"audiovol" - -// sound level pre-sets -const int levels[] = {0, 1, 10, 45, 70, 99}; +#define TIMER_INTERVAL 10 +#define VOLUME 99 AudioThread::AudioThread() : _mixer(0), @@ -51,9 +44,7 @@ AudioThread::AudioThread() : Audio::MixerImpl *AudioThread::Construct(OSystem *system) { logEntered(); - if (IsFailed(Thread::Construct(THREAD_TYPE_EVENT_DRIVEN, - DEFAULT_STACK_SIZE, - THREAD_PRIORITY_HIGH))) { + if (IsFailed(EventDrivenThread::Construct(DEFAULT_STACK_SIZE, THREAD_PRIORITY_HIGH))) { AppLog("Failed to create AudioThread"); return NULL; } @@ -69,7 +60,7 @@ AudioThread::~AudioThread() { bool AudioThread::isSilentMode() { bool silentMode; String key(L"SilentMode"); - Osp::System::SettingInfo::GetValue(key, silentMode); + Tizen::System::SettingInfo::GetValue(key, silentMode); return silentMode; } @@ -79,59 +70,16 @@ void AudioThread::setMute(bool on) { if (on) { _timer->Cancel(); } else { - _timer->Start(_interval); - } - } -} - -int AudioThread::setVolume(bool up, bool minMax) { - int level = -1; - int numLevels = sizeof(levels) / sizeof(levels[0]); - - if (_audioOut) { - int volume = _audioOut->GetVolume(); - if (minMax) { - level = up ? numLevels - 1 : 0; - volume = levels[level]; - } else { - // adjust volume to be one of the preset values - for (int i = 0; i < numLevels && level == -1; i++) { - if (volume == levels[i]) { - level = i; - if (up) { - if (i + 1 < numLevels) { - level = i + 1; - } - } else if (i > 0) { - level = i - 1; - } - } - } - - // default to INIT_LEVEL when current not preset value - if (level == -1) { - level = INIT_LEVEL; - } - volume = levels[level]; - } - - _audioOut->SetVolume(volume); - - // remember the chosen setting - AppRegistry *registry = Application::GetInstance()->GetAppRegistry(); - if (registry) { - registry->Set(CONFIG_KEY, volume); + _timer->StartAsRepeatable(_interval); } } - return level; } bool AudioThread::OnStart(void) { logEntered(); - _audioOut = new Osp::Media::AudioOut(); - if (!_audioOut || - IsFailed(_audioOut->Construct(*this))) { + _audioOut = new Tizen::Media::AudioOut(); + if (!_audioOut || IsFailed(_audioOut->Construct(*this))) { AppLog("Failed to create AudioOut"); return false; } @@ -144,8 +92,7 @@ bool AudioThread::OnStart(void) { } if (IsFailed(_audioOut->Prepare(AUDIO_TYPE_PCM_S16_LE, - AUDIO_CHANNEL_TYPE_STEREO, - sampleRate))) { + AUDIO_CHANNEL_TYPE_STEREO, sampleRate))) { AppLog("Failed to prepare AudioOut %d", sampleRate); return false; } @@ -164,26 +111,14 @@ bool AudioThread::OnStart(void) { return false; } - if (IsFailed(_timer->Start(_interval))) { + if (IsFailed(_timer->StartAsRepeatable(_interval))) { AppLog("failed to start audio timer"); return false; } - // get the volume from the app-registry - int volume = levels[INIT_LEVEL]; - AppRegistry *registry = Application::GetInstance()->GetAppRegistry(); - if (registry) { - if (E_KEY_NOT_FOUND == registry->Get(CONFIG_KEY, volume)) { - registry->Add(CONFIG_KEY, volume); - volume = levels[INIT_LEVEL]; - } else { - AppLog("Setting volume: %d", volume); - } - } - _muted = false; _mixer->setReady(true); - _audioOut->SetVolume(isSilentMode() ? 0 : volume); + _audioOut->SetVolume(isSilentMode() ? 0 : VOLUME); _audioOut->Start(); return true; } @@ -206,20 +141,20 @@ void AudioThread::OnStop(void) { } } -void AudioThread::OnAudioOutErrorOccurred(Osp::Media::AudioOut &src, result r) { +void AudioThread::OnAudioOutErrorOccurred(Tizen::Media::AudioOut &src, result r) { logEntered(); } -void AudioThread::OnAudioOutInterrupted(Osp::Media::AudioOut &src) { +void AudioThread::OnAudioOutInterrupted(Tizen::Media::AudioOut &src) { logEntered(); } -void AudioThread::OnAudioOutReleased(Osp::Media::AudioOut &src) { +void AudioThread::OnAudioOutReleased(Tizen::Media::AudioOut &src) { logEntered(); _audioOut->Start(); } -void AudioThread::OnAudioOutBufferEndReached(Osp::Media::AudioOut &src) { +void AudioThread::OnAudioOutBufferEndReached(Tizen::Media::AudioOut &src) { if (_ready > 0) { _playing = _tail; _audioOut->WriteBuffer(_audioBuffer[_tail]); @@ -228,10 +163,6 @@ void AudioThread::OnAudioOutBufferEndReached(Osp::Media::AudioOut &src) { } else { // audio buffer empty: decrease timer inverval _playing = -1; - _interval -= TIMER_INCREMENT; - if (_interval < MIN_TIMER_INTERVAL) { - _interval = MIN_TIMER_INTERVAL; - } } } @@ -243,18 +174,8 @@ void AudioThread::OnTimerExpired(Timer &timer) { _head = (_head + 1) % NUM_AUDIO_BUFFERS; _ready++; } - } else { - // audio buffer full: increase timer inverval - _interval += TIMER_INCREMENT; - if (_interval > MAX_TIMER_INTERVAL) { - _interval = MAX_TIMER_INTERVAL; - } } - if (_ready && _playing == -1) { OnAudioOutBufferEndReached(*_audioOut); } - - _timer->Start(_interval); } - diff --git a/backends/platform/bada/audio.h b/backends/platform/tizen/audio.h index 72c537a942..8d7835042d 100644 --- a/backends/platform/bada/audio.h +++ b/backends/platform/tizen/audio.h @@ -20,8 +20,8 @@ * */ -#ifndef BADA_AUDIO_H -#define BADA_AUDIO_H +#ifndef TIZEN_AUDIO_H +#define TIZEN_AUDIO_H #include <FBase.h> #include <FMedia.h> @@ -33,17 +33,19 @@ #include "common/system.h" #include "audio/mixer_intern.h" -using namespace Osp::Base; -using namespace Osp::Base::Collection; -using namespace Osp::Base::Runtime; -using namespace Osp::Media; -using namespace Osp::Io; +using namespace Tizen::Base; +using namespace Tizen::Base::Collection; +using namespace Tizen::Base::Runtime; +using namespace Tizen::Media; +using namespace Tizen::Io; #define NUM_AUDIO_BUFFERS 2 -class AudioThread: public Osp::Media::IAudioOutEventListener, - public Osp::Base::Runtime::ITimerEventListener, - public Osp::Base::Runtime::Thread { +class AudioThread: + public Tizen::Media::IAudioOutEventListener, + public Tizen::Base::Runtime::ITimerEventListener, + public Tizen::Base::Runtime::EventDrivenThread { + public: AudioThread(void); ~AudioThread(void); @@ -51,21 +53,20 @@ public: Audio::MixerImpl *Construct(OSystem *system); bool isSilentMode(); void setMute(bool on); - int setVolume(bool up, bool minMax); bool OnStart(void); void OnStop(void); - void OnAudioOutErrorOccurred(Osp::Media::AudioOut &src, result r); - void OnAudioOutInterrupted(Osp::Media::AudioOut &src); - void OnAudioOutReleased(Osp::Media::AudioOut &src); - void OnAudioOutBufferEndReached(Osp::Media::AudioOut &src); + void OnAudioOutErrorOccurred(Tizen::Media::AudioOut &src, result r); + void OnAudioOutInterrupted(Tizen::Media::AudioOut &src); + void OnAudioOutReleased(Tizen::Media::AudioOut &src); + void OnAudioOutBufferEndReached(Tizen::Media::AudioOut &src); void OnTimerExpired(Timer &timer); private: Audio::MixerImpl *_mixer; - Osp::Base::Runtime::Timer *_timer; - Osp::Media::AudioOut *_audioOut; - Osp::Base::ByteBuffer _audioBuffer[NUM_AUDIO_BUFFERS]; + Tizen::Base::Runtime::Timer *_timer; + Tizen::Media::AudioOut *_audioOut; + Tizen::Base::ByteBuffer _audioBuffer[NUM_AUDIO_BUFFERS]; int _head, _tail, _ready, _interval, _playing; bool _muted; }; diff --git a/backends/platform/tizen/form.cpp b/backends/platform/tizen/form.cpp new file mode 100644 index 0000000000..5050699ca9 --- /dev/null +++ b/backends/platform/tizen/form.cpp @@ -0,0 +1,419 @@ +/* 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 <FApp.h> +#include <FSysSystemTime.h> + +#include "common/translation.h" +#include "base/main.h" + +#include "backends/platform/tizen/form.h" +#include "backends/platform/tizen/system.h" + +using namespace Tizen::Base::Collection; +using namespace Tizen::Base::Runtime; +using namespace Tizen::Ui::Controls; + +// round down small Y touch values to 1 to allow the +// cursor to be positioned at the top of the screen +#define MIN_TOUCH_Y 20 + +// block for up to 2.5 seconds during shutdown to +// allow the game thread to exit gracefully. +#define EXIT_SLEEP_STEP 10 +#define EXIT_SLEEP 250 + +// +// TizenAppForm +// +TizenAppForm::TizenAppForm() : + _gestureMode(false), + _osdMessage(NULL), + _gameThread(NULL), + _eventQueueLock(NULL), + _state(kInitState), + _buttonState(kLeftButton), + _shortcut(kShowKeypad) { +} + +result TizenAppForm::Construct() { + TizenSystem *tizenSystem = NULL; + result r = Form::Construct(FORM_STYLE_NORMAL); + if (!IsFailed(r)) { + tizenSystem = new TizenSystem(this); + r = tizenSystem != NULL ? E_SUCCESS : E_OUT_OF_MEMORY; + } + if (!IsFailed(r)) { + r = tizenSystem->Construct(); + } + if (!IsFailed(r)) { + _gameThread = new Thread(); + r = _gameThread != NULL ? E_SUCCESS : E_OUT_OF_MEMORY; + } + if (!IsFailed(r)) { + r = _gameThread->Construct(*this); + } + if (!IsFailed(r)) { + _eventQueueLock = new Mutex(); + r = _eventQueueLock != NULL ? E_SUCCESS : E_OUT_OF_MEMORY; + } + if (!IsFailed(r)) { + r = _eventQueueLock->Create(); + } + + if (!IsFailed(r)) { + g_system = tizenSystem; + } else { + AppLog("Form startup failed"); + delete tizenSystem; + delete _gameThread; + _gameThread = NULL; + } + return r; +} + +TizenAppForm::~TizenAppForm() { + logEntered(); + + if (_gameThread && _state != kErrorState) { + terminate(); + + _gameThread->Stop(); + if (_state != kErrorState) { + _gameThread->Join(); + } + + delete _gameThread; + _gameThread = NULL; + } + + delete _eventQueueLock; + _eventQueueLock = NULL; + + logLeaving(); +} + +// +// abort the game thread +// +void TizenAppForm::terminate() { + if (_state == kActiveState) { + ((TizenSystem *)g_system)->setMute(true); + + _eventQueueLock->Acquire(); + + Common::Event e; + e.type = Common::EVENT_QUIT; + _eventQueue.push(e); + _state = kClosingState; + + _eventQueueLock->Release(); + + // block while thread ends + AppLog("waiting for shutdown"); + for (int i = 0; i < EXIT_SLEEP_STEP && _state == kClosingState; i++) { + Thread::Sleep(EXIT_SLEEP); + } + + if (_state == kClosingState) { + // failed to terminate - Join() will freeze + _state = kErrorState; + } + } +} + +void TizenAppForm::exitSystem() { + _state = kErrorState; + + if (_gameThread) { + _gameThread->Stop(); + delete _gameThread; + _gameThread = NULL; + } +} + +result TizenAppForm::OnInitializing(void) { + logEntered(); + + AddOrientationEventListener(*this); + AddTouchEventListener(*this); + SetMultipointTouchEnabled(true); + + // set focus to enable receiving key events + SetEnabled(true); + SetFocusable(true); + SetFocus(); + + return E_SUCCESS; +} + +result TizenAppForm::OnDraw(void) { + logEntered(); + return E_SUCCESS; +} + +void TizenAppForm::OnOrientationChanged(const Control &source, OrientationStatus orientationStatus) { + logEntered(); + if (_state == kInitState) { + _state = kActiveState; + _gameThread->Start(); + } +} + +Tizen::Base::Object *TizenAppForm::Run() { + logEntered(); + + scummvm_main(0, 0); + if (_state == kActiveState) { + Tizen::App::Application::GetInstance()->SendUserEvent(USER_MESSAGE_EXIT, NULL); + } + _state = kDoneState; + return NULL; +} + +bool TizenAppForm::pollEvent(Common::Event &event) { + bool result = false; + + _eventQueueLock->Acquire(); + if (!_eventQueue.empty()) { + event = _eventQueue.pop(); + result = true; + } + if (_osdMessage) { + TizenSystem *system = (TizenSystem *)g_system; + TizenGraphicsManager *graphics = system->getGraphics(); + if (graphics) { + graphics->displayMessageOnOSD(_osdMessage); + _osdMessage = NULL; + } + } + _eventQueueLock->Release(); + + return result; +} + +void TizenAppForm::pushEvent(Common::EventType type, const Point ¤tPosition) { + TizenSystem *system = (TizenSystem *)g_system; + TizenGraphicsManager *graphics = system->getGraphics(); + if (graphics) { + // graphics could be NULL at startup or when + // displaying the system error screen + Common::Event e; + e.type = type; + e.mouse.x = currentPosition.x; + e.mouse.y = currentPosition.y > MIN_TOUCH_Y ? currentPosition.y : 1; + + bool moved = graphics->moveMouse(e.mouse.x, e.mouse.y); + + _eventQueueLock->Acquire(); + + if (moved && type != Common::EVENT_MOUSEMOVE) { + Common::Event moveEvent; + moveEvent.type = Common::EVENT_MOUSEMOVE; + moveEvent.mouse = e.mouse; + _eventQueue.push(moveEvent); + } + + _eventQueue.push(e); + _eventQueueLock->Release(); + } +} + +void TizenAppForm::pushKey(Common::KeyCode keycode) { + if (_eventQueueLock) { + Common::Event e; + e.synthetic = false; + e.kbd.keycode = keycode; + e.kbd.ascii = keycode; + e.kbd.flags = 0; + + _eventQueueLock->Acquire(); + e.type = Common::EVENT_KEYDOWN; + _eventQueue.push(e); + e.type = Common::EVENT_KEYUP; + _eventQueue.push(e); + _eventQueueLock->Release(); + } +} + +void TizenAppForm::setButtonShortcut() { + switch (_buttonState) { + case kLeftButton: + setMessage(_s("Right Click Once")); + _buttonState = kRightButtonOnce; + break; + case kRightButtonOnce: + setMessage(_s("Right Click")); + _buttonState = kRightButton; + break; + case kRightButton: + setMessage(_s("Move Only")); + _buttonState = kMoveOnly; + break; + case kMoveOnly: + setMessage(_s("Left Click")); + _buttonState = kLeftButton; + break; + } +} + +void TizenAppForm::setMessage(const char *message) { + if (_eventQueueLock) { + _eventQueueLock->Acquire(); + _osdMessage = message; + _eventQueueLock->Release(); + } +} + +void TizenAppForm::setShortcut() { + logEntered(); + // cycle to the next shortcut + switch (_shortcut) { + case kControlMouse: + setMessage(_s("Escape Key")); + _shortcut = kEscapeKey; + break; + + case kEscapeKey: + setMessage(_s("Game Menu")); + _shortcut = kGameMenu; + break; + + case kGameMenu: + setMessage(_s("Show Keypad")); + _shortcut = kShowKeypad; + break; + + case kShowKeypad: + setMessage(_s("Control Mouse")); + _shortcut = kControlMouse; + break; + } +} + +void TizenAppForm::invokeShortcut() { + logEntered(); + switch (_shortcut) { + case kControlMouse: + setButtonShortcut(); + break; + + case kEscapeKey: + pushKey(Common::KEYCODE_ESCAPE); + break; + + case kGameMenu: + _buttonState = kLeftButton; + pushKey(Common::KEYCODE_F5); + break; + + case kShowKeypad: + showKeypad(); + break; + } +} + +void TizenAppForm::showKeypad() { + // display the soft keyboard + if (_state == kActiveState) { + _buttonState = kLeftButton; + pushKey(Common::KEYCODE_F7); + } +} + +int TizenAppForm::getTouchCount() { + Tizen::Ui::TouchEventManager *touch = Tizen::Ui::TouchEventManager::GetInstance(); + IListT<TouchEventInfo *> *touchList = touch->GetTouchInfoListN(); + int touchCount = touchList->GetCount(); + touchList->RemoveAll(); + delete touchList; + return touchCount; +} + +void TizenAppForm::OnTouchDoublePressed(const Control &source, + const Point ¤tPosition, const TouchEventInfo &touchInfo) { + if (_buttonState != kMoveOnly) { + pushEvent(_buttonState == kLeftButton ? Common::EVENT_LBUTTONDOWN : Common::EVENT_RBUTTONDOWN, + currentPosition); + pushEvent(_buttonState == kLeftButton ? Common::EVENT_LBUTTONDOWN : Common::EVENT_RBUTTONDOWN, + currentPosition); + } +} + +void TizenAppForm::OnTouchFocusIn(const Control &source, + const Point ¤tPosition, const TouchEventInfo &touchInfo) { +} + +void TizenAppForm::OnTouchFocusOut(const Control &source, + const Point ¤tPosition, const TouchEventInfo &touchInfo) { +} + +void TizenAppForm::OnTouchLongPressed(const Control &source, + const Point ¤tPosition, const TouchEventInfo &touchInfo) { + logEntered(); + if (_buttonState != kLeftButton) { + pushKey(Common::KEYCODE_RETURN); + } +} + +void TizenAppForm::OnTouchMoved(const Control &source, + const Point ¤tPosition, const TouchEventInfo &touchInfo) { + if (!_gestureMode) { + pushEvent(Common::EVENT_MOUSEMOVE, currentPosition); + } +} + +void TizenAppForm::OnTouchPressed(const Control &source, + const Point ¤tPosition, const TouchEventInfo &touchInfo) { + if (getTouchCount() > 1) { + _gestureMode = true; + } else if (_buttonState != kMoveOnly) { + pushEvent(_buttonState == kLeftButton ? Common::EVENT_LBUTTONDOWN : Common::EVENT_RBUTTONDOWN, + currentPosition); + } +} + +void TizenAppForm::OnTouchReleased(const Control &source, + const Point ¤tPosition, const TouchEventInfo &touchInfo) { + if (_gestureMode) { + int touchCount = getTouchCount(); + if (touchCount == 1) { + setShortcut(); + } else { + if (touchCount == 2) { + invokeShortcut(); + } + _gestureMode = false; + } + } else if (_buttonState != kMoveOnly) { + pushEvent(_buttonState == kLeftButton ? Common::EVENT_LBUTTONUP : Common::EVENT_RBUTTONUP, + currentPosition); + if (_buttonState == kRightButtonOnce) { + _buttonState = kLeftButton; + } + // flick to skip dialog + if (touchInfo.IsFlicked()) { + pushKey(Common::KEYCODE_PERIOD); + } + } +} + diff --git a/backends/platform/tizen/form.h b/backends/platform/tizen/form.h new file mode 100644 index 0000000000..64c447d409 --- /dev/null +++ b/backends/platform/tizen/form.h @@ -0,0 +1,113 @@ +/* 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 TIZEN_FORM_H +#define TIZEN_FORM_H + +#include <FApp.h> +#include <FUi.h> +#include <FSystem.h> +#include <FBase.h> +#include <FUiITouchEventListener.h> +#include <FUiITextEventListener.h> + +#include "config.h" +#include "common/scummsys.h" +#include "common/events.h" +#include "common/queue.h" +#include "common/mutex.h" +#include "engines/engine.h" + +using namespace Tizen::Ui; +using namespace Tizen::Graphics; +using namespace Tizen::Base::Runtime; + +// +// TizenAppForm +// +class TizenAppForm : + public Controls::Form, + public IRunnable, + public IOrientationEventListener, + public ITouchEventListener { + +public: + TizenAppForm(); + virtual ~TizenAppForm(); + + result Construct(); + bool pollEvent(Common::Event &event); + bool isClosing() { return _state == kClosingState; } + bool isStarting() { return _state == kInitState; } + void pushKey(Common::KeyCode keycode); + void exitSystem(); + void showKeypad(); + +private: + Tizen::Base::Object *Run(); + result OnInitializing(void); + result OnDraw(void); + void OnOrientationChanged(const Control &source, + OrientationStatus orientationStatus); + void OnTouchDoublePressed(const Control &source, + const Point ¤tPosition, + const TouchEventInfo &touchInfo); + void OnTouchFocusIn(const Control &source, + const Point ¤tPosition, + const TouchEventInfo &touchInfo); + void OnTouchFocusOut(const Control &source, + const Point ¤tPosition, + const TouchEventInfo &touchInfo); + void OnTouchLongPressed(const Control &source, + const Point ¤tPosition, + const TouchEventInfo &touchInfo); + void OnTouchMoved(const Control &source, + const Point ¤tPosition, + const TouchEventInfo &touchInfo); + void OnTouchPressed(const Control &source, + const Point ¤tPosition, + const TouchEventInfo &touchInfo); + void OnTouchReleased(const Control &source, + const Point ¤tPosition, + const TouchEventInfo &touchInfo); + + void pushEvent(Common::EventType type, const Point ¤tPosition); + void terminate(); + void setButtonShortcut(); + void setMessage(const char *message); + void setShortcut(); + void invokeShortcut(); + int getTouchCount(); + bool gameActive() { return _state == kActiveState && g_engine != NULL && !g_engine->isPaused(); } + + // event handling + bool _gestureMode; + const char *_osdMessage; + Tizen::Base::Runtime::Thread *_gameThread; + Tizen::Base::Runtime::Mutex *_eventQueueLock; + Common::Queue<Common::Event> _eventQueue; + enum { kInitState, kActiveState, kClosingState, kDoneState, kErrorState } _state; + enum { kLeftButton, kRightButtonOnce, kRightButton, kMoveOnly } _buttonState; + enum { kControlMouse, kEscapeKey, kGameMenu, kShowKeypad } _shortcut; +}; + +#endif diff --git a/backends/platform/bada/fs.cpp b/backends/platform/tizen/fs.cpp index 37ca496d18..f8b32f4239 100644 --- a/backends/platform/bada/fs.cpp +++ b/backends/platform/tizen/fs.cpp @@ -20,33 +20,38 @@ */ #include "config.h" -#include "backends/platform/bada/system.h" -#include "backends/platform/bada/fs.h" +#include "common/translation.h" +#include "backends/platform/tizen/system.h" +#include "backends/platform/tizen/fs.h" + +#include <FAppApp.h> #define BUFFER_SIZE 1024 -// internal BADA paths -#define PATH_ROOT "/" -#define PATH_HOME "/Home" -#define PATH_HOME_SHARE "/Home/Share" -#define PATH_HOME_SHARE2 "/Home/Share2" -#define PATH_HOME_X "/Home/" -#define PATH_HOME_EXT "/HomeExt" -#define PATH_MEDIA "/Media" -#define PATH_CARD "/Storagecard" -#define PATH_CARD_MEDIA "/Storagecard/Media" +using namespace Tizen::App; + +// +// converts a Tizen (wchar) String into a scummVM (char) string +// +Common::String fromString(const Tizen::Base::String &in) { + ByteBuffer *buf = StringUtil::StringToUtf8N(in); + Common::String result((const char*)buf->GetPointer()); + delete buf; + return result; +} // -// BadaFileStream +// TizenFileStream // -class BadaFileStream : public Common::SeekableReadStream, - public Common::WriteStream, - public Common::NonCopyable { +class TizenFileStream : + public Common::SeekableReadStream, + public Common::WriteStream, + public Common::NonCopyable { public: - static BadaFileStream *makeFromPath(const String &path, bool writeMode); + static TizenFileStream *makeFromPath(const String &path, bool writeMode); - BadaFileStream(File *file, bool writeMode); - ~BadaFileStream(); + TizenFileStream(File *file, bool writeMode); + ~TizenFileStream(); bool err() const; void clearErr(); @@ -61,81 +66,81 @@ public: uint32 read(void *dataPtr, uint32 dataSize); private: - byte buffer[BUFFER_SIZE]; - uint32 bufferIndex; - uint32 bufferLength; - bool writeMode; - File *file; + byte _buffer[BUFFER_SIZE]; + uint32 _bufferIndex; + uint32 _bufferLength; + bool _writeMode; + File *_file; }; -BadaFileStream::BadaFileStream(File *ioFile, bool writeMode) : - bufferIndex(0), - bufferLength(0), - writeMode(writeMode), - file(ioFile) { +TizenFileStream::TizenFileStream(File *ioFile, bool writeMode) : + _bufferIndex(0), + _bufferLength(0), + _writeMode(writeMode), + _file(ioFile) { AppAssert(ioFile != 0); } -BadaFileStream::~BadaFileStream() { - if (file) { - if (writeMode) { +TizenFileStream::~TizenFileStream() { + if (_file) { + if (_writeMode) { flush(); } - delete file; + delete _file; } } -bool BadaFileStream::err() const { +bool TizenFileStream::err() const { result r = GetLastResult(); return (r != E_SUCCESS && r != E_END_OF_FILE); } -void BadaFileStream::clearErr() { +void TizenFileStream::clearErr() { SetLastResult(E_SUCCESS); } -bool BadaFileStream::eos() const { - return (bufferLength - bufferIndex == 0) && (GetLastResult() == E_END_OF_FILE); +bool TizenFileStream::eos() const { + return (_bufferLength - _bufferIndex == 0) && (GetLastResult() == E_END_OF_FILE); } -int32 BadaFileStream::pos() const { - return file->Tell() - (bufferLength - bufferIndex); +int32 TizenFileStream::pos() const { + return _file->Tell() - (_bufferLength - _bufferIndex); } -int32 BadaFileStream::size() const { - int32 oldPos = file->Tell(); - file->Seek(FILESEEKPOSITION_END, 0); +int32 TizenFileStream::size() const { + int32 oldPos = _file->Tell(); + _file->Seek(FILESEEKPOSITION_END, 0); - int32 length = file->Tell(); - SetLastResult(file->Seek(FILESEEKPOSITION_BEGIN, oldPos)); + int32 length = _file->Tell(); + SetLastResult(_file->Seek(FILESEEKPOSITION_BEGIN, oldPos)); return length; } -bool BadaFileStream::seek(int32 offs, int whence) { +bool TizenFileStream::seek(int32 offs, int whence) { bool result = false; switch (whence) { case SEEK_SET: // set from start of file - SetLastResult(file->Seek(FILESEEKPOSITION_BEGIN, offs)); + SetLastResult(_file->Seek(FILESEEKPOSITION_BEGIN, offs)); result = (E_SUCCESS == GetLastResult()); break; case SEEK_CUR: // set relative to offs - if (bufferIndex < bufferLength && bufferIndex > (uint32)-offs) { + if (_bufferIndex < _bufferLength && _bufferIndex > (uint32)-offs) { // re-position within the buffer SetLastResult(E_SUCCESS); - bufferIndex += offs; + _bufferIndex += offs; return true; } else { - offs -= (bufferLength - bufferIndex); - if (offs < 0 && file->Tell() + offs < 0) { + offs -= (_bufferLength - _bufferIndex); + if (offs < 0 && _file->Tell() + offs < 0) { // avoid negative positioning offs = 0; } if (offs != 0) { - SetLastResult(file->Seek(FILESEEKPOSITION_CURRENT, offs)); + SetLastResult(_file->Seek(FILESEEKPOSITION_CURRENT, offs)); result = (E_SUCCESS == GetLastResult()); } else { result = true; @@ -145,7 +150,7 @@ bool BadaFileStream::seek(int32 offs, int whence) { case SEEK_END: // set relative to end - positive will increase the file size - SetLastResult(file->Seek(FILESEEKPOSITION_END, offs)); + SetLastResult(_file->Seek(FILESEEKPOSITION_END, offs)); result = (E_SUCCESS == GetLastResult()); break; @@ -158,46 +163,46 @@ bool BadaFileStream::seek(int32 offs, int whence) { AppLog("seek failed"); } - bufferIndex = bufferLength = 0; + _bufferIndex = _bufferLength = 0; return result; } -uint32 BadaFileStream::read(void *ptr, uint32 len) { +uint32 TizenFileStream::read(void *ptr, uint32 len) { uint32 result = 0; if (!eos()) { - if (bufferIndex < bufferLength) { + if (_bufferIndex < _bufferLength) { // use existing buffer - uint32 available = bufferLength - bufferIndex; + uint32 available = _bufferLength - _bufferIndex; if (len <= available) { // use allocation - memcpy((byte *)ptr, &buffer[bufferIndex], len); - bufferIndex += len; + memcpy((byte *)ptr, &_buffer[_bufferIndex], len); + _bufferIndex += len; result = len; } else { // use remaining allocation - memcpy((byte *)ptr, &buffer[bufferIndex], available); + memcpy((byte *)ptr, &_buffer[_bufferIndex], available); uint32 remaining = len - available; result = available; if (remaining) { - result += file->Read(((byte *)ptr) + available, remaining); + result += _file->Read(((byte *)ptr) + available, remaining); } - bufferIndex = bufferLength = 0; + _bufferIndex = _bufferLength = 0; } } else if (len < BUFFER_SIZE) { // allocate and use buffer - bufferIndex = 0; - bufferLength = file->Read(buffer, BUFFER_SIZE); - if (bufferLength) { - if (bufferLength < len) { - len = bufferLength; + _bufferIndex = 0; + _bufferLength = _file->Read(_buffer, BUFFER_SIZE); + if (_bufferLength) { + if (_bufferLength < len) { + len = _bufferLength; } - memcpy((byte *)ptr, buffer, len); - result = bufferIndex = len; + memcpy((byte *)ptr, _buffer, len); + result = _bufferIndex = len; } } else { - result = file->Read((byte *)ptr, len); - bufferIndex = bufferLength = 0; + result = _file->Read((byte *)ptr, len); + _bufferIndex = _bufferLength = 0; } } else { AppLog("Attempted to read past EOS"); @@ -205,59 +210,77 @@ uint32 BadaFileStream::read(void *ptr, uint32 len) { return result; } -uint32 BadaFileStream::write(const void *ptr, uint32 len) { - result r = file->Write(ptr, len); +uint32 TizenFileStream::write(const void *ptr, uint32 len) { + result r = _file->Write(ptr, len); SetLastResult(r); return (r == E_SUCCESS ? len : 0); } -bool BadaFileStream::flush() { +bool TizenFileStream::flush() { logEntered(); - SetLastResult(file->Flush()); + SetLastResult(_file->Flush()); return (E_SUCCESS == GetLastResult()); } -BadaFileStream *BadaFileStream::makeFromPath(const String &path, bool writeMode) { +TizenFileStream *TizenFileStream::makeFromPath(const String &path, bool writeMode) { File *ioFile = new File(); String filePath = path; if (writeMode && (path[0] != '.' && path[0] != '/')) { - filePath.Insert(PATH_HOME_X, 0); + filePath.Insert(App::GetInstance()->GetAppDataPath() + L"/", 0); } AppLog("Open file %S", filePath.GetPointer()); - + TizenFileStream *stream; result r = ioFile->Construct(filePath, writeMode ? L"w" : L"r", writeMode); if (r == E_SUCCESS) { - return new BadaFileStream(ioFile, writeMode); + stream = new TizenFileStream(ioFile, writeMode); + } else { + AppLog("Failed to open file"); + delete ioFile; + stream = NULL; } - - AppLog("Failed to open file"); - delete ioFile; - return 0; -} - -// -// converts a bada (wchar) String into a scummVM (char) string -// -Common::String fromString(const Osp::Base::String &in) { - ByteBuffer *buf = StringUtil::StringToUtf8N(in); - Common::String result((const char*)buf->GetPointer()); - delete buf; - - return result; + return stream; } // -// BadaFilesystemNode +// TizenFilesystemNode // -BadaFilesystemNode::BadaFilesystemNode(const Common::String &nodePath) { +TizenFilesystemNode::TizenFilesystemNode(const Common::String &nodePath) { AppAssert(nodePath.size() > 0); init(nodePath); } -BadaFilesystemNode::BadaFilesystemNode(const Common::String &root, - const Common::String &nodePath) { +TizenFilesystemNode::TizenFilesystemNode(SystemPath systemPath) { + switch (systemPath) { + case kData: + _unicodePath = App::GetInstance()->GetAppDataPath(); + _displayName = _s("[ Data ]"); + break; + case kResource: + _unicodePath = App::GetInstance()->GetAppResourcePath(); + _displayName = _s("[ Resources ]"); + break; + case kSdCard: + _unicodePath = Tizen::System::Environment::GetExternalStoragePath(); + _displayName = _s("[ SDCard ]"); + break; + case kMedia: + _unicodePath = Tizen::System::Environment::GetMediaPath(); + _displayName = _s("[ Media ]"); + break; + case kShared: + _unicodePath = App::GetInstance()->GetAppSharedPath(); + _displayName = _s("[ Shared ]"); + break; + } + _path = ::fromString(_unicodePath); + _isValid = _isVirtualDir = !IsFailed(File::GetAttributes(_unicodePath, _attr)); +} + +TizenFilesystemNode::TizenFilesystemNode(const Common::String &root, const Common::String &nodePath) { + AppLog("TizenFilesystemNode '%s' '%s'", root.c_str(), nodePath.c_str()); + // Make sure the string contains no slashes AppAssert(!nodePath.contains('/')); @@ -272,71 +295,54 @@ BadaFilesystemNode::BadaFilesystemNode(const Common::String &root, init(newPath); } -void BadaFilesystemNode::init(const Common::String &nodePath) { +void TizenFilesystemNode::init(const Common::String &nodePath) { // Normalize the path (that is, remove unneeded slashes etc.) _path = Common::normalizePath(nodePath, '/'); _displayName = Common::lastPathComponent(_path, '/'); StringUtil::Utf8ToString(_path.c_str(), _unicodePath); - _isVirtualDir = (_path == PATH_ROOT || - _path == PATH_HOME || - _path == PATH_HOME_SHARE || - _path == PATH_HOME_SHARE2 || - _path == PATH_CARD); + _isVirtualDir = (_path == "/"); _isValid = _isVirtualDir || !IsFailed(File::GetAttributes(_unicodePath, _attr)); } -bool BadaFilesystemNode::exists() const { +bool TizenFilesystemNode::exists() const { return _isValid; } -bool BadaFilesystemNode::isReadable() const { +bool TizenFilesystemNode::isReadable() const { return _isVirtualDir || _isValid; } -bool BadaFilesystemNode::isDirectory() const { +bool TizenFilesystemNode::isDirectory() const { return _isVirtualDir || (_isValid && _attr.IsDirectory()); } -bool BadaFilesystemNode::isWritable() const { - bool result = (_isValid && !_isVirtualDir && !_attr.IsDirectory() && !_attr.IsReadOnly()); - if (_path == PATH_HOME || - _path == PATH_HOME_EXT || - _path == PATH_HOME_SHARE || - _path == PATH_HOME_SHARE2) { - result = true; +bool TizenFilesystemNode::isWritable() const { + bool result = (_isValid && !_attr.IsReadOnly()); + if (_unicodePath == App::GetInstance()->GetAppResourcePath()) { + result = false; } return result; } -AbstractFSNode *BadaFilesystemNode::getChild(const Common::String &n) const { +AbstractFSNode *TizenFilesystemNode::getChild(const Common::String &n) const { AppAssert(!_path.empty()); AppAssert(isDirectory()); - return new BadaFilesystemNode(_path, n); + return new TizenFilesystemNode(_path, n); } -bool BadaFilesystemNode::getChildren(AbstractFSList &myList, - ListMode mode, bool hidden) const { +bool TizenFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const { AppAssert(isDirectory()); bool result = false; - if (_isVirtualDir && mode != Common::FSNode::kListFilesOnly) { - // present well known BADA file system areas - if (_path == PATH_ROOT) { - myList.push_back(new BadaFilesystemNode(PATH_HOME)); - myList.push_back(new BadaFilesystemNode(PATH_HOME_EXT)); - myList.push_back(new BadaFilesystemNode(PATH_MEDIA)); - myList.push_back(new BadaFilesystemNode(PATH_CARD)); - result = true; // no more entries - } else if (_path == PATH_CARD) { - myList.push_back(new BadaFilesystemNode(PATH_CARD_MEDIA)); - result = true; // no more entries - } else if (_path == PATH_HOME) { - // ensure share path is always included - myList.push_back(new BadaFilesystemNode(PATH_HOME_SHARE)); - myList.push_back(new BadaFilesystemNode(PATH_HOME_SHARE2)); - } + if (_isVirtualDir && mode != Common::FSNode::kListFilesOnly && _path == "/") { + // present well known TIZEN file system areas + myList.push_back(new TizenFilesystemNode(kData)); + myList.push_back(new TizenFilesystemNode(kResource)); + myList.push_back(new TizenFilesystemNode(kSdCard)); + myList.push_back(new TizenFilesystemNode(kMedia)); + myList.push_back(new TizenFilesystemNode(kShared)); } if (!result) { @@ -358,7 +364,7 @@ bool BadaFilesystemNode::getChildren(AbstractFSList &myList, DirEntry dirEntry = pDirEnum->GetCurrentDirEntry(); // skip 'invisible' files if necessary - Osp::Base::String fileName = dirEntry.GetName(); + Tizen::Base::String fileName = dirEntry.GetName(); if (fileName[0] == '.' && !hidden) { continue; @@ -374,7 +380,7 @@ bool BadaFilesystemNode::getChildren(AbstractFSList &myList, (mode == Common::FSNode::kListDirectoriesOnly && !dirEntry.IsDirectory())) { continue; } - myList.push_back(new BadaFilesystemNode(_path, fromString(fileName))); + myList.push_back(new TizenFilesystemNode(_path, ::fromString(fileName))); } } @@ -392,9 +398,9 @@ bool BadaFilesystemNode::getChildren(AbstractFSList &myList, return result; } -AbstractFSNode *BadaFilesystemNode::getParent() const { - logEntered(); - if (_path == PATH_ROOT) { +AbstractFSNode *TizenFilesystemNode::getParent() const { + logEntered(); + if (_path == "/") { return 0; // The filesystem root has no parent } @@ -412,22 +418,22 @@ AbstractFSNode *BadaFilesystemNode::getParent() const { // there simply is no parent. // TODO: We could also resolve this by assuming that the parent is the // current working directory, and returning a node referring to that. - return 0; + return NULL; } - return new BadaFilesystemNode(Common::String(start, end)); + return new TizenFilesystemNode(Common::String(start, end)); } -Common::SeekableReadStream *BadaFilesystemNode::createReadStream() { - Common::SeekableReadStream *result = BadaFileStream::makeFromPath(_unicodePath, false); +Common::SeekableReadStream *TizenFilesystemNode::createReadStream() { + Common::SeekableReadStream *result = TizenFileStream::makeFromPath(_unicodePath, false); if (result != NULL) { _isValid = !IsFailed(File::GetAttributes(_unicodePath, _attr)); } return result; } -Common::WriteStream *BadaFilesystemNode::createWriteStream() { - Common::WriteStream *result = BadaFileStream::makeFromPath(_unicodePath, true); +Common::WriteStream *TizenFilesystemNode::createWriteStream() { + Common::WriteStream *result = TizenFileStream::makeFromPath(_unicodePath, true); if (result != NULL) { _isValid = !IsFailed(File::GetAttributes(_unicodePath, _attr)); } diff --git a/backends/platform/bada/fs.h b/backends/platform/tizen/fs.h index d7d368ac20..0356aaad33 100644 --- a/backends/platform/bada/fs.h +++ b/backends/platform/tizen/fs.h @@ -19,8 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef BADA_FILESYSTEM_H -#define BADA_FILESYSTEM_H +#ifndef TIZEN_FILESYSTEM_H +#define TIZEN_FILESYSTEM_H #include <FBaseString.h> #include <FBaseUtilStringUtil.h> @@ -32,23 +32,40 @@ #include "common/stream.h" #include "backends/fs/abstract-fs.h" -using namespace Osp::Io; -using namespace Osp::Base; -using namespace Osp::Base::Utility; +using namespace Tizen::Io; +using namespace Tizen::Base; +using namespace Tizen::Base::Utility; + +// +// converts a Tizen (wchar) String into a scummVM (char) string +// +Common::String fromString(const Tizen::Base::String &in); + +// +// Enumerates the possible system paths +// +enum SystemPath { kData, kResource, kSdCard, kMedia, kShared }; /** - * Implementation of the ScummVM file system API based on BADA. + * Implementation of the ScummVM file system API based on TIZEN. * * Parts of this class are documented in the base interface class, AbstractFSNode. */ -class BadaFilesystemNode : public AbstractFSNode { +class TizenFilesystemNode : public AbstractFSNode { public: /** - * Creates a BadaFilesystemNode for a given path. + * Creates a TizenFilesystemNode for a given path. + * + * @param path the path the new node should point to. + */ + TizenFilesystemNode(const Common::String &path); + + /** + * Creates a TizenFilesystemNode from the given Tizen internal path * * @param path the path the new node should point to. */ - BadaFilesystemNode(const Common::String &path); + TizenFilesystemNode(SystemPath systemPath); Common::String getDisplayName() const { return _displayName; } Common::String getName() const { return _displayName; } @@ -67,8 +84,7 @@ public: Common::WriteStream *createWriteStream(); protected: - BadaFilesystemNode(const Common::String &root, - const Common::String &p); + TizenFilesystemNode(const Common::String &root, const Common::String &p); void init(const Common::String &nodePath); Common::String _displayName; diff --git a/backends/platform/bada/graphics.cpp b/backends/platform/tizen/graphics.cpp index bd65c597c6..bf255cd264 100644 --- a/backends/platform/bada/graphics.cpp +++ b/backends/platform/tizen/graphics.cpp @@ -22,29 +22,40 @@ #include "graphics/fontman.h" -#include "backends/platform/bada/form.h" -#include "backends/platform/bada/system.h" -#include "backends/platform/bada/graphics.h" +#include "backends/platform/tizen/form.h" +#include "backends/platform/tizen/system.h" +#include "backends/platform/tizen/graphics.h" // -// BadaGraphicsManager +// TizenGraphicsManager // -BadaGraphicsManager::BadaGraphicsManager(BadaAppForm *appForm) : +TizenGraphicsManager::TizenGraphicsManager(TizenAppForm *appForm) : _appForm(appForm), _eglDisplay(EGL_DEFAULT_DISPLAY), _eglSurface(EGL_NO_SURFACE), - _eglConfig(0), + _eglConfig(NULL), _eglContext(EGL_NO_CONTEXT), _initState(true) { assert(appForm != NULL); _videoMode.fullscreen = true; } -const Graphics::Font *BadaGraphicsManager::getFontOSD() { +TizenGraphicsManager::~TizenGraphicsManager() { + logEntered(); + + if (_eglDisplay != EGL_NO_DISPLAY) { + eglMakeCurrent(_eglDisplay, NULL, NULL, NULL); + if (_eglContext != EGL_NO_CONTEXT) { + eglDestroyContext(_eglDisplay, _eglContext); + } + } +} + +const Graphics::Font *TizenGraphicsManager::getFontOSD() { return FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont); } -bool BadaGraphicsManager::moveMouse(int16 &x, int16 &y) { +bool TizenGraphicsManager::moveMouse(int16 &x, int16 &y) { int16 currentX = _cursorState.x; int16 currentY = _cursorState.y; @@ -62,7 +73,7 @@ bool BadaGraphicsManager::moveMouse(int16 &x, int16 &y) { return (currentX != x || currentY != y); } -Common::List<Graphics::PixelFormat> BadaGraphicsManager::getSupportedFormats() const { +Common::List<Graphics::PixelFormat> TizenGraphicsManager::getSupportedFormats() const { logEntered(); Common::List<Graphics::PixelFormat> res; @@ -73,33 +84,37 @@ Common::List<Graphics::PixelFormat> BadaGraphicsManager::getSupportedFormats() c return res; } -bool BadaGraphicsManager::hasFeature(OSystem::Feature f) { +bool TizenGraphicsManager::hasFeature(OSystem::Feature f) { bool result = (f == OSystem::kFeatureFullscreenMode || - f == OSystem::kFeatureVirtualKeyboard || - OpenGLGraphicsManager::hasFeature(f)); + f == OSystem::kFeatureVirtualKeyboard || + OpenGLGraphicsManager::hasFeature(f)); return result; } -void BadaGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) { - OpenGLGraphicsManager::setFeatureState(f, enable); +void TizenGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) { + if (f == OSystem::kFeatureVirtualKeyboard && enable) { + _appForm->showKeypad(); + } else { + OpenGLGraphicsManager::setFeatureState(f, enable); + } } -void BadaGraphicsManager::setReady() { +void TizenGraphicsManager::setReady() { _initState = false; } -void BadaGraphicsManager::updateScreen() { +void TizenGraphicsManager::updateScreen() { if (_transactionMode == kTransactionNone) { internUpdateScreen(); } } -bool BadaGraphicsManager::loadEgl() { +bool TizenGraphicsManager::loadEgl() { logEntered(); EGLint numConfigs = 1; EGLint eglConfigList[] = { - EGL_RED_SIZE, 5, + EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6, EGL_BLUE_SIZE, 5, EGL_ALPHA_SIZE, 0, @@ -132,8 +147,7 @@ bool BadaGraphicsManager::loadEgl() { return false; } - if (EGL_FALSE == eglChooseConfig(_eglDisplay, eglConfigList, - &_eglConfig, 1, &numConfigs) || + if (EGL_FALSE == eglChooseConfig(_eglDisplay, eglConfigList, &_eglConfig, 1, &numConfigs) || EGL_SUCCESS != eglGetError()) { systemError("eglChooseConfig() failed"); return false; @@ -144,15 +158,13 @@ bool BadaGraphicsManager::loadEgl() { return false; } - _eglSurface = eglCreateWindowSurface(_eglDisplay, _eglConfig, - (EGLNativeWindowType)_appForm, NULL); + _eglSurface = eglCreateWindowSurface(_eglDisplay, _eglConfig, (EGLNativeWindowType)_appForm, NULL); if (EGL_NO_SURFACE == _eglSurface || EGL_SUCCESS != eglGetError()) { systemError("eglCreateWindowSurface() failed. EGL_NO_SURFACE"); return false; } - _eglContext = eglCreateContext(_eglDisplay, _eglConfig, - EGL_NO_CONTEXT, eglContextList); + _eglContext = eglCreateContext(_eglDisplay, _eglConfig, EGL_NO_CONTEXT, eglContextList); if (EGL_NO_CONTEXT == _eglContext || EGL_SUCCESS != eglGetError()) { systemError("eglCreateContext() failed"); @@ -169,7 +181,7 @@ bool BadaGraphicsManager::loadEgl() { return true; } -bool BadaGraphicsManager::loadGFXMode() { +bool TizenGraphicsManager::loadGFXMode() { logEntered(); if (!loadEgl()) { @@ -181,35 +193,28 @@ bool BadaGraphicsManager::loadGFXMode() { _appForm->GetBounds(x, y, width, height); _videoMode.overlayWidth = _videoMode.hardwareWidth = width; _videoMode.overlayHeight = _videoMode.hardwareHeight = height; - _videoMode.scaleFactor = 3; // for proportional sized cursor in the launcher + _videoMode.scaleFactor = 4; // for proportional sized cursor in the launcher AppLog("screen size: %dx%d", _videoMode.hardwareWidth, _videoMode.hardwareHeight); return OpenGLGraphicsManager::loadGFXMode(); } -void BadaGraphicsManager::loadTextures() { +void TizenGraphicsManager::loadTextures() { logEntered(); - OpenGLGraphicsManager::loadTextures(); - - // prevent image skew in some games, see: - // http://www.opengl.org/resources/features/KilgardTechniques/oglpitfall - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); } -void BadaGraphicsManager::internUpdateScreen() { +void TizenGraphicsManager::internUpdateScreen() { if (!_initState) { OpenGLGraphicsManager::internUpdateScreen(); eglSwapBuffers(_eglDisplay, _eglSurface); - } else { - showSplash(); } } -void BadaGraphicsManager::unloadGFXMode() { +void TizenGraphicsManager::unloadGFXMode() { logEntered(); - if (EGL_NO_DISPLAY != _eglDisplay) { + if (_eglDisplay != EGL_NO_DISPLAY) { eglMakeCurrent(_eglDisplay, NULL, NULL, NULL); if (_eglContext != EGL_NO_CONTEXT) { @@ -227,35 +232,6 @@ void BadaGraphicsManager::unloadGFXMode() { } _eglConfig = NULL; - OpenGLGraphicsManager::unloadGFXMode(); logLeaving(); } - -// display a simple splash screen until launcher is ready -void BadaGraphicsManager::showSplash() { - Canvas canvas; - canvas.Construct(); - canvas.SetBackgroundColor(Color::COLOR_BLACK); - canvas.Clear(); - - int x = _videoMode.hardwareWidth / 3; - int y = _videoMode.hardwareHeight / 3; - - Font *pFont = new Font(); - pFont->Construct(FONT_STYLE_ITALIC | FONT_STYLE_BOLD, 55); - canvas.SetFont(*pFont); - canvas.SetForegroundColor(Color::COLOR_GREEN); - canvas.DrawText(Point(x, y), L"ScummVM"); - delete pFont; - - pFont = new Font(); - pFont->Construct(FONT_STYLE_ITALIC | FONT_STYLE_BOLD, 35); - canvas.SetFont(*pFont); - canvas.SetForegroundColor(Color::COLOR_WHITE); - canvas.DrawText(Point(x + 70, y + 50), L"Loading ..."); - delete pFont; - - canvas.Show(); - -} diff --git a/backends/platform/bada/graphics.h b/backends/platform/tizen/graphics.h index b2aaca43bc..27e5a6aaeb 100644 --- a/backends/platform/bada/graphics.h +++ b/backends/platform/tizen/graphics.h @@ -20,8 +20,8 @@ * */ -#ifndef BADA_GRAPHICS_H -#define BADA_GRAPHICS_H +#ifndef TIZEN_GRAPHICS_H +#define TIZEN_GRAPHICS_H #include <FBase.h> #include <FGraphics.h> @@ -33,15 +33,16 @@ #include "config.h" #include "backends/graphics/opengl/opengl-graphics.h" #include "graphics/font.h" -#include "backends/platform/bada/form.h" +#include "backends/platform/tizen/form.h" -using namespace Osp::Graphics; -using namespace Osp::Graphics::Opengl; -using namespace Osp::App; +using namespace Tizen::Graphics; +using namespace Tizen::Graphics::Opengl; +using namespace Tizen::App; -class BadaGraphicsManager : public OpenGLGraphicsManager { +class TizenGraphicsManager : public OpenGLGraphicsManager { public: - BadaGraphicsManager(BadaAppForm *appForm); + TizenGraphicsManager(TizenAppForm *appForm); + virtual ~TizenGraphicsManager(); Common::List<Graphics::PixelFormat> getSupportedFormats() const; bool hasFeature(OSystem::Feature f); @@ -61,7 +62,7 @@ private: void showSplash(); bool loadEgl(); - BadaAppForm *_appForm; + TizenAppForm *_appForm; EGLDisplay _eglDisplay; EGLSurface _eglSurface; EGLConfig _eglConfig; diff --git a/backends/platform/bada/main.cpp b/backends/platform/tizen/main.cpp index 8c40f24dd1..b12cc3adc9 100644 --- a/backends/platform/bada/main.cpp +++ b/backends/platform/tizen/main.cpp @@ -24,44 +24,28 @@ #include <FApp.h> #include <FSystem.h> -#include "backends/platform/bada/portdefs.h" -#include "backends/platform/bada/form.h" -#include "backends/platform/bada/system.h" -#include "backends/platform/bada/application.h" +#include "backends/platform/tizen/application.h" -using namespace Osp::Base; -using namespace Osp::Base::Collection; - -C_LINKAGE_BEGIN - -_EXPORT_ int OspMain(int argc, char *pArgv[]); +using namespace Tizen::Base; +using namespace Tizen::Base::Collection; /** - * The entry function of bada application called by the operating system. + * The entry function of tizen application called by the operating system. */ -int OspMain(int argc, char *pArgv[]) { +extern "C" _EXPORT_ int OspMain(int argc, char *pArgv[]) { result r = E_SUCCESS; AppLog("Application started."); - ArrayList *pArgs = new ArrayList(); - pArgs->Construct(); - + ArrayList args(SingleObjectDeleter); + args.Construct(); for (int i = 0; i < argc; i++) { - pArgs->Add(*(new String(pArgv[i]))); + args.Add(new (std::nothrow) String(pArgv[i])); } - r = Osp::App::Application::Execute(BadaScummVM::createInstance, pArgs); - if (IsFailed(r)) { - r &= 0x0000FFFF; - } - - pArgs->RemoveAll(true); - delete pArgs; + r = Tizen::App::UiApp::Execute(TizenScummVM::createInstance, &args); + TryLog(r == E_SUCCESS, "[%s] Application execution failed", GetErrorMessage(r)); AppLog("Application finished."); return static_cast<int>(r); } -C_LINKAGE_END - - diff --git a/backends/platform/bada/missing.cpp b/backends/platform/tizen/missing.cpp index 10d45ca4b5..5ac55d0f6c 100644 --- a/backends/platform/bada/missing.cpp +++ b/backends/platform/tizen/missing.cpp @@ -26,7 +26,7 @@ #include <FSystem.h> #include <FBase.h> -#include "backends/platform/bada/portdefs.h" +#include "backends/platform/tizen/portdefs.h" #include <stdio.h> #include <string.h> @@ -48,7 +48,7 @@ void __assert_func(const char *file, int line, systemError(buffer); } -void stderr_fprintf(void*, const char *format, ...) { +void stderr_fprintf(void *, const char *format, ...) { va_list ap; char buffer[BUF_SIZE]; @@ -59,7 +59,7 @@ void stderr_fprintf(void*, const char *format, ...) { AppLog(buffer); } -void stderr_vfprintf(void*, const char *format, va_list ap) { +void stderr_vfprintf(void *, const char *format, va_list ap) { char buffer[BUF_SIZE]; vsnprintf(buffer, sizeof(buffer), format, ap); AppLog(buffer); @@ -79,35 +79,4 @@ int printf(const char *format, ...) { return result; } -int sprintf(char *str, const char *format, ...) { - va_list ap; - int result; - char buffer[BUF_SIZE]; - - va_start(ap, format); - result = vsnprintf(buffer, sizeof(buffer), format, ap); - va_end(ap); - - strcpy(str, buffer); - - return result; -} - -char *strdup(const char *strSource) { - char *buffer; - int len = strlen(strSource) + 1; - buffer = (char *)malloc(len); - if (buffer) { - memcpy(buffer, strSource, len); - } - return buffer; -} - -int vsprintf(char *str, const char *format, va_list ap) { - char buffer[BUF_SIZE]; - int result = vsnprintf(buffer, sizeof(buffer), format, ap); - strcpy(str, buffer); - return result; -} - C_LINKAGE_END diff --git a/backends/platform/bada/portdefs.h b/backends/platform/tizen/portdefs.h index 813c5acde3..050ce7d1e0 100644 --- a/backends/platform/bada/portdefs.h +++ b/backends/platform/tizen/portdefs.h @@ -43,6 +43,9 @@ #define C_LINKAGE_END #endif +// value missing from osp gl headers +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 + C_LINKAGE_BEGIN // for libFLAC @@ -51,11 +54,11 @@ C_LINKAGE_BEGIN #define fseeko fseek #define ftello ftell -// overcome use of fprintf since bada/newlib (1.2) does not +// overcome use of fprintf since newlib (1.2) does not // support stderr/stdout (undefined reference to `_impure_ptr'). -void stderr_fprintf(void*, const char *format, ...); -void stderr_vfprintf(void*, const char *format, va_list ap); +void stderr_fprintf(void *, const char *format, ...); +void stderr_vfprintf(void *, const char *format, va_list ap); #undef fprintf #undef vfprintf @@ -75,10 +78,7 @@ void stderr_vfprintf(void*, const char *format, va_list ap); #define vfprintf stderr_vfprintf int printf(const char *format, ...); -int sprintf(char *str, const char *format, ...); int simple_sscanf(const char *buffer, const char *format, ...); -char *strdup(const char *s1); -int vsprintf(char *str, const char *format, va_list ap); C_LINKAGE_END diff --git a/backends/platform/bada/sscanf.cpp b/backends/platform/tizen/sscanf.cpp index aa846698f6..aa846698f6 100644 --- a/backends/platform/bada/sscanf.cpp +++ b/backends/platform/tizen/sscanf.cpp diff --git a/backends/platform/bada/system.cpp b/backends/platform/tizen/system.cpp index 3f862c2571..54d92146e5 100644 --- a/backends/platform/bada/system.cpp +++ b/backends/platform/tizen/system.cpp @@ -34,53 +34,53 @@ #include "backends/audiocd/default/default-audiocd.h" #include "backends/mutex/mutex.h" #include "backends/fs/fs-factory.h" -#include "backends/timer/bada/timer.h" +#include "backends/timer/tizen/timer.h" -#include "backends/platform/bada/form.h" -#include "backends/platform/bada/system.h" -#include "backends/platform/bada/graphics.h" -#include "backends/platform/bada/audio.h" +#include "backends/platform/tizen/form.h" +#include "backends/platform/tizen/system.h" +#include "backends/platform/tizen/graphics.h" +#include "backends/platform/tizen/audio.h" -using namespace Osp::Base; -using namespace Osp::Base::Runtime; -using namespace Osp::Locales; -using namespace Osp::Ui::Controls; -using namespace Osp::System; +using namespace Tizen::Base; +using namespace Tizen::Base::Runtime; +using namespace Tizen::Locales; +using namespace Tizen::Ui; +using namespace Tizen::Ui::Controls; +using namespace Tizen::System; -#define DEFAULT_CONFIG_FILE "/Home/scummvm.ini" -#define RESOURCE_PATH "/Res" +#define DEFAULT_CONFIG_FILE "scummvm.ini" #define MUTEX_BUFFER_SIZE 5 // -// BadaFilesystemFactory +// TizenFilesystemFactory // -class BadaFilesystemFactory : public FilesystemFactory { +class TizenFilesystemFactory : public FilesystemFactory { AbstractFSNode *makeRootFileNode() const; AbstractFSNode *makeCurrentDirectoryFileNode() const; AbstractFSNode *makeFileNodePath(const Common::String &path) const; }; -AbstractFSNode *BadaFilesystemFactory::makeRootFileNode() const { - return new BadaFilesystemNode("/"); +AbstractFSNode *TizenFilesystemFactory::makeRootFileNode() const { + return new TizenFilesystemNode("/"); } -AbstractFSNode *BadaFilesystemFactory::makeCurrentDirectoryFileNode() const { - return new BadaFilesystemNode("/Home"); +AbstractFSNode *TizenFilesystemFactory::makeCurrentDirectoryFileNode() const { + return new TizenFilesystemNode("/"); } -AbstractFSNode *BadaFilesystemFactory::makeFileNodePath(const Common::String &path) const { +AbstractFSNode *TizenFilesystemFactory::makeFileNodePath(const Common::String &path) const { AppAssert(!path.empty()); - return new BadaFilesystemNode(path); + return new TizenFilesystemNode(path); } // -// BadaSaveFileManager +// TizenSaveFileManager // -struct BadaSaveFileManager : public DefaultSaveFileManager { +struct TizenSaveFileManager : public DefaultSaveFileManager { bool removeSavefile(const Common::String &filename); }; -bool BadaSaveFileManager::removeSavefile(const Common::String &filename) { +bool TizenSaveFileManager::removeSavefile(const Common::String &filename) { Common::String savePathName = getSavePath(); checkPath(Common::FSNode(savePathName)); @@ -95,18 +95,18 @@ bool BadaSaveFileManager::removeSavefile(const Common::String &filename) { String unicodeFileName; StringUtil::Utf8ToString(file.getPath().c_str(), unicodeFileName); - switch (Osp::Io::File::Remove(unicodeFileName)) { + switch (Tizen::Io::File::Remove(unicodeFileName)) { case E_SUCCESS: return true; case E_ILLEGAL_ACCESS: setError(Common::kWritePermissionDenied, "Search or write permission denied: " + - file.getName()); + file.getName()); break; default: setError(Common::kPathDoesNotExist, "removeSavefile: '" + file.getName() + - "' does not exist or path is invalid"); + "' does not exist or path is invalid"); break; } @@ -114,40 +114,40 @@ bool BadaSaveFileManager::removeSavefile(const Common::String &filename) { } // -// BadaMutexManager +// TizenMutexManager // -struct BadaMutexManager : public MutexManager { - BadaMutexManager(); - ~BadaMutexManager(); +struct TizenMutexManager : public MutexManager { + TizenMutexManager(); + ~TizenMutexManager(); OSystem::MutexRef createMutex(); void lockMutex(OSystem::MutexRef mutex); void unlockMutex(OSystem::MutexRef mutex); void deleteMutex(OSystem::MutexRef mutex); private: - Mutex *buffer[MUTEX_BUFFER_SIZE]; + Mutex *_buffer[MUTEX_BUFFER_SIZE]; }; -BadaMutexManager::BadaMutexManager() { +TizenMutexManager::TizenMutexManager() { for (int i = 0; i < MUTEX_BUFFER_SIZE; i++) { - buffer[i] = NULL; + _buffer[i] = NULL; } } -BadaMutexManager::~BadaMutexManager() { +TizenMutexManager::~TizenMutexManager() { for (int i = 0; i < MUTEX_BUFFER_SIZE; i++) { - if (buffer[i] != NULL) { - delete buffer[i]; + if (_buffer[i] != NULL) { + delete _buffer[i]; } } } -OSystem::MutexRef BadaMutexManager::createMutex() { +OSystem::MutexRef TizenMutexManager::createMutex() { Mutex *mutex = new Mutex(); mutex->Create(); for (int i = 0; i < MUTEX_BUFFER_SIZE; i++) { - if (buffer[i] == NULL) { - buffer[i] = mutex; + if (_buffer[i] == NULL) { + _buffer[i] = mutex; break; } } @@ -155,22 +155,22 @@ OSystem::MutexRef BadaMutexManager::createMutex() { return (OSystem::MutexRef) mutex; } -void BadaMutexManager::lockMutex(OSystem::MutexRef mutex) { +void TizenMutexManager::lockMutex(OSystem::MutexRef mutex) { Mutex *m = (Mutex *)mutex; m->Acquire(); } -void BadaMutexManager::unlockMutex(OSystem::MutexRef mutex) { +void TizenMutexManager::unlockMutex(OSystem::MutexRef mutex) { Mutex *m = (Mutex *)mutex; m->Release(); } -void BadaMutexManager::deleteMutex(OSystem::MutexRef mutex) { +void TizenMutexManager::deleteMutex(OSystem::MutexRef mutex) { Mutex *m = (Mutex *)mutex; for (int i = 0; i < MUTEX_BUFFER_SIZE; i++) { - if (buffer[i] == m) { - buffer[i] = NULL; + if (_buffer[i] == m) { + _buffer[i] = NULL; } } @@ -178,84 +178,101 @@ void BadaMutexManager::deleteMutex(OSystem::MutexRef mutex) { } // -// BadaEventManager +// TizenEventManager // -struct BadaEventManager : public DefaultEventManager { - BadaEventManager(Common::EventSource *boss); +struct TizenEventManager : public DefaultEventManager { + TizenEventManager(Common::EventSource *boss); void init(); int shouldQuit() const; }; -BadaEventManager::BadaEventManager(Common::EventSource *boss) : +TizenEventManager::TizenEventManager(Common::EventSource *boss) : DefaultEventManager(boss) { } -void BadaEventManager::init() { +void TizenEventManager::init() { DefaultEventManager::init(); // theme and vkbd should have now loaded - clear the splash screen - BadaSystem *system = (BadaSystem *)g_system; - BadaGraphicsManager *graphics = system->getGraphics(); + TizenSystem *system = (TizenSystem *)g_system; + TizenGraphicsManager *graphics = system->getGraphics(); if (graphics) { graphics->setReady(); - graphics->updateScreen(); } } -int BadaEventManager::shouldQuit() const { - BadaSystem *system = (BadaSystem *)g_system; +int TizenEventManager::shouldQuit() const { + TizenSystem *system = (TizenSystem *)g_system; return DefaultEventManager::shouldQuit() || system->isClosing(); } // -// BadaSystem +// TizenAppFrame - avoid drawing the misplaced UiTheme at startup // -BadaSystem::BadaSystem(BadaAppForm *appForm) : +struct TizenAppFrame : Frame { + result OnDraw(void) { + logEntered(); + TizenAppForm *form = (TizenAppForm *)GetCurrentForm(); + if (form->isStarting()) { + Canvas *canvas = GetCanvasN(); + canvas->SetBackgroundColor(Color::GetColor(COLOR_ID_BLACK)); + canvas->Clear(); + delete canvas; + } + return E_SUCCESS; + } +}; + +// +// TizenSystem +// +TizenSystem::TizenSystem(TizenAppForm *appForm) : _appForm(appForm), _audioThread(0), _epoch(0) { } -result BadaSystem::Construct(void) { +result TizenSystem::Construct(void) { logEntered(); - _fsFactory = new BadaFilesystemFactory(); + _fsFactory = new TizenFilesystemFactory(); if (!_fsFactory) { return E_OUT_OF_MEMORY; } + _resourcePath = fromString(App::GetInstance()->GetAppResourcePath()); return E_SUCCESS; } -BadaSystem::~BadaSystem() { +TizenSystem::~TizenSystem() { logEntered(); } -result BadaSystem::initModules() { +result TizenSystem::initModules() { logEntered(); - _mutexManager = new BadaMutexManager(); + _mutexManager = new TizenMutexManager(); if (!_mutexManager) { return E_OUT_OF_MEMORY; } - _timerManager = new BadaTimerManager(); + _timerManager = new TizenTimerManager(); if (!_timerManager) { return E_OUT_OF_MEMORY; } - _savefileManager = new BadaSaveFileManager(); + _savefileManager = new TizenSaveFileManager(); if (!_savefileManager) { return E_OUT_OF_MEMORY; } - _graphicsManager = (GraphicsManager *)new BadaGraphicsManager(_appForm); + _graphicsManager = (GraphicsManager *)new TizenGraphicsManager(_appForm); if (!_graphicsManager) { return E_OUT_OF_MEMORY; } // depends on _graphicsManager when ENABLE_VKEYBD enabled - _eventManager = new BadaEventManager(this); + _eventManager = new TizenEventManager(this); if (!_eventManager) { return E_OUT_OF_MEMORY; } @@ -284,19 +301,21 @@ result BadaSystem::initModules() { return E_SUCCESS; } -void BadaSystem::initBackend() { +void TizenSystem::initBackend() { logEntered(); + Common::String dataPath = fromString(App::GetInstance()->GetAppDataPath()); + // use the mobile device theme - ConfMan.set("gui_theme", "/Res/scummmobile"); + ConfMan.set("gui_theme", _resourcePath + "scummmodern"); - // allow bada virtual keypad pack to be found - ConfMan.set("vkeybdpath", "/Res/vkeybd_bada"); + // allow tizen virtual keypad pack to be found + ConfMan.set("vkeybdpath", _resourcePath + "vkeybd_bada"); ConfMan.set("vkeybd_pack_name", "vkeybd_bada"); // set default save path to writable area if (!ConfMan.hasKey("savepath")) { - ConfMan.set("savepath", "/Home/Share"); + ConfMan.set("savepath", dataPath); } // default to no auto-save @@ -314,85 +333,93 @@ void BadaSystem::initBackend() { AppLog("initModules failed"); } else { OSystem::initBackend(); - } - // replace kBigGUIFont using the large font from the scummmobile theme - Common::File fontFile; - Common::String fileName = "/Res/scummmobile/helvB14-iso-8859-1.fcc"; - BadaFilesystemNode file(fileName); - if (file.exists()) { - Common::SeekableReadStream *stream = file.createReadStream(); - if (stream) { - if (fontFile.open(stream, fileName)) { + // replace kBigGUIFont for the vkbd and on-screen messages + Common::String fontCacheFile = dataPath + "helvR24.fcc"; + TizenFilesystemNode file(fontCacheFile); + if (!file.exists()) { + Common::String bdfFile = _resourcePath + "fonts/helvR24.bdf"; + TizenFilesystemNode file(bdfFile); + if (file.exists()) { + Common::SeekableReadStream *stream = file.createReadStream(); + Common::File fontFile; + if (stream && fontFile.open(stream, bdfFile)) { + Graphics::BdfFont *font = Graphics::BdfFont::loadFont(fontFile); + Graphics::BdfFont::cacheFontData(*font, fontCacheFile); + FontMan.setFont(Graphics::FontManager::kBigGUIFont, font); + } + } + } else { + Common::SeekableReadStream *stream = file.createReadStream(); + Common::File fontFile; + if (stream && fontFile.open(stream, fontCacheFile)) { Graphics::BdfFont *font = Graphics::BdfFont::loadFromCache(fontFile); if (font) { - // use this font for the vkbd and on-screen messages FontMan.setFont(Graphics::FontManager::kBigGUIFont, font); } } } } - logLeaving(); } -void BadaSystem::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { +void TizenSystem::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { // allow translations.dat and game .DAT files to be found - s.addDirectory(RESOURCE_PATH, RESOURCE_PATH, priority); + s.addDirectory(_resourcePath, _resourcePath, priority); } -void BadaSystem::destroyBackend() { +void TizenSystem::destroyBackend() { closeAudio(); delete _graphicsManager; - _graphicsManager = 0; + _graphicsManager = NULL; delete _savefileManager; - _savefileManager = 0; + _savefileManager = NULL; delete _fsFactory; - _fsFactory = 0; + _fsFactory = NULL; delete _mixer; - _mixer = 0; + _mixer = NULL; delete _audiocdManager; - _audiocdManager = 0; + _audiocdManager = NULL; delete _timerManager; - _timerManager = 0; + _timerManager = NULL; delete _eventManager; - _eventManager = 0; + _eventManager = NULL; delete _mutexManager; - _mutexManager = 0; + _mutexManager = NULL; } -bool BadaSystem::pollEvent(Common::Event &event) { +bool TizenSystem::pollEvent(Common::Event &event) { return _appForm->pollEvent(event); } -uint32 BadaSystem::getMillis() { +uint32 TizenSystem::getMillis(bool skipRecord) { long long result, ticks = 0; SystemTime::GetTicks(ticks); result = ticks - _epoch; return result; } -void BadaSystem::delayMillis(uint msecs) { +void TizenSystem::delayMillis(uint msecs) { if (!_appForm->isClosing()) { Thread::Sleep(msecs); } } -void BadaSystem::updateScreen() { +void TizenSystem::updateScreen() { if (_graphicsManager != NULL) { _graphicsManager->updateScreen(); } } -void BadaSystem::getTimeAndDate(TimeDate &td) const { +void TizenSystem::getTimeAndDate(TimeDate &td) const { DateTime currentTime; if (E_SUCCESS == SystemTime::GetCurrentTime(WALL_TIME, currentTime)) { @@ -410,11 +437,11 @@ void BadaSystem::getTimeAndDate(TimeDate &td) const { } } -void BadaSystem::fatalError() { +void TizenSystem::fatalError() { systemError("ScummVM: Fatal internal error."); } -void BadaSystem::exitSystem() { +void TizenSystem::exitSystem() { if (_appForm) { closeAudio(); closeGraphics(); @@ -422,7 +449,7 @@ void BadaSystem::exitSystem() { } } -void BadaSystem::logMessage(LogMessageType::Type type, const char *message) { +void TizenSystem::logMessage(LogMessageType::Type type, const char *message) { if (type == LogMessageType::kError) { systemError(message); } else { @@ -430,69 +457,70 @@ void BadaSystem::logMessage(LogMessageType::Type type, const char *message) { } } -Common::SeekableReadStream *BadaSystem::createConfigReadStream() { - BadaFilesystemNode file(DEFAULT_CONFIG_FILE); +Common::SeekableReadStream *TizenSystem::createConfigReadStream() { + TizenFilesystemNode file(fromString(App::GetInstance()->GetAppDataPath()) + DEFAULT_CONFIG_FILE); return file.createReadStream(); } -Common::WriteStream *BadaSystem::createConfigWriteStream() { - BadaFilesystemNode file(DEFAULT_CONFIG_FILE); +Common::WriteStream *TizenSystem::createConfigWriteStream() { + TizenFilesystemNode file(fromString(App::GetInstance()->GetAppDataPath()) + DEFAULT_CONFIG_FILE); return file.createWriteStream(); } -void BadaSystem::closeAudio() { +void TizenSystem::closeAudio() { if (_audioThread) { - _audioThread->Stop(); + _audioThread->Quit(); _audioThread->Join(); delete _audioThread; - _audioThread = 0; + _audioThread = NULL; } } -void BadaSystem::closeGraphics() { +void TizenSystem::closeGraphics() { if (_graphicsManager) { delete _graphicsManager; - _graphicsManager = 0; + _graphicsManager = NULL; } } -void BadaSystem::setMute(bool on) { +void TizenSystem::setMute(bool on) { // only change mute after eventManager init() has completed if (_audioThread) { - BadaGraphicsManager *graphics = getGraphics(); + TizenGraphicsManager *graphics = getGraphics(); if (graphics && graphics->isReady()) { _audioThread->setMute(on); } } } -int BadaSystem::setVolume(bool up, bool minMax) { - int level = -1; - if (_audioThread) { - level = _audioThread->setVolume(up, minMax); - } - return level; -} - // // create the ScummVM system // -BadaAppForm *systemStart(Osp::App::Application *app) { +TizenAppForm *systemStart(Tizen::App::Application *app) { logEntered(); - BadaAppForm *appForm = new BadaAppForm(); + Frame *appFrame = new (std::nothrow) TizenAppFrame(); + if (!appFrame || appFrame->Construct() == E_FAILURE) { + AppLog("Failed to create appFrame"); + return NULL; + } + app->AddFrame(*appFrame); + + TizenAppForm *appForm = new TizenAppForm(); if (!appForm) { AppLog("Failed to create appForm"); return NULL; } if (E_SUCCESS != appForm->Construct() || - E_SUCCESS != app->GetAppFrame()->GetFrame()->AddControl(*appForm)) { + E_SUCCESS != appFrame->AddControl(*appForm)) { delete appForm; AppLog("Failed to construct appForm"); return NULL; } + appFrame->SetCurrentForm(appForm); + logLeaving(); return appForm; } @@ -502,13 +530,18 @@ BadaAppForm *systemStart(Osp::App::Application *app) { void systemError(const char *message) { AppLog("Fatal system error: %s", message); - ArrayList *args = new ArrayList(); - args->Construct(); - args->Add(*(new String(message))); - Application::GetInstance()->SendUserEvent(USER_MESSAGE_EXIT_ERR, args); + if (strspn(message, "Config file buggy:") > 0) { + Tizen::Io::File::Remove(DEFAULT_CONFIG_FILE); + Application::GetInstance()->SendUserEvent(USER_MESSAGE_EXIT_ERR_CONFIG, NULL); + } else { + ArrayList *args = new ArrayList(); + args->Construct(); + args->Add(*(new String(message))); + Application::GetInstance()->SendUserEvent(USER_MESSAGE_EXIT_ERR, args); + } if (g_system) { - BadaSystem *system = (BadaSystem *)g_system; + TizenSystem *system = (TizenSystem *)g_system; system->exitSystem(); } } diff --git a/backends/platform/bada/system.h b/backends/platform/tizen/system.h index c28686cb3d..b38940cc95 100644 --- a/backends/platform/bada/system.h +++ b/backends/platform/tizen/system.h @@ -20,8 +20,8 @@ * */ -#ifndef BADA_SYSTEM_H -#define BADA_SYSTEM_H +#ifndef TIZEN_SYSTEM_H +#define TIZEN_SYSTEM_H #include <FApp.h> #include <FGraphics.h> @@ -34,47 +34,46 @@ #include "common/scummsys.h" #include "backends/modular-backend.h" -#include "backends/platform/bada/fs.h" -#include "backends/platform/bada/form.h" -#include "backends/platform/bada/audio.h" -#include "backends/platform/bada/graphics.h" +#include "backends/platform/tizen/fs.h" +#include "backends/platform/tizen/form.h" +#include "backends/platform/tizen/audio.h" +#include "backends/platform/tizen/graphics.h" #if defined(_DEBUG) -#define logEntered() AppLog("%s entered (%s %d)", \ - __FUNCTION__, __FILE__, __LINE__); -#define logLeaving() AppLog("%s leaving (%s %d)", \ - __FUNCTION__, __FILE__, __LINE__); +#define logEntered() AppLog("%s entered (%s %d)", __FUNCTION__, __FILE__, __LINE__); +#define logLeaving() AppLog("%s leaving (%s %d)", __FUNCTION__, __FILE__, __LINE__); #else #define logEntered() #define logLeaving() #endif -BadaAppForm *systemStart(Osp::App::Application *app); +TizenAppForm *systemStart(Tizen::App::Application *app); void systemError(const char *message); -#define USER_MESSAGE_EXIT 1000 -#define USER_MESSAGE_EXIT_ERR 1001 +#define USER_MESSAGE_EXIT 1000 +#define USER_MESSAGE_EXIT_ERR 1001 +#define USER_MESSAGE_EXIT_ERR_CONFIG 1002 // -// BadaSystem +// TizenSystem // -class BadaSystem : public ModularBackend, - Common::EventSource { +class TizenSystem : + public ModularBackend, + Common::EventSource { public: - BadaSystem(BadaAppForm *appForm); - ~BadaSystem(); + TizenSystem(TizenAppForm *appForm); + ~TizenSystem(); result Construct(); void closeAudio(); void closeGraphics(); void destroyBackend(); void setMute(bool on); - int setVolume(bool up, bool minMax); void exitSystem(); bool isClosing() { return _appForm->isClosing(); } - BadaGraphicsManager *getGraphics() { - return (BadaGraphicsManager *)_graphicsManager; + TizenGraphicsManager *getGraphics() { + return (TizenGraphicsManager *)_graphicsManager; } private: @@ -83,7 +82,7 @@ private: void updateScreen(); bool pollEvent(Common::Event &event); - uint32 getMillis(); + uint32 getMillis(bool skipRecord = false); void delayMillis(uint msecs); void getTimeAndDate(TimeDate &t) const; void fatalError(); @@ -94,9 +93,10 @@ private: Common::SeekableReadStream *createConfigReadStream(); Common::WriteStream *createConfigWriteStream(); - BadaAppForm *_appForm; + TizenAppForm *_appForm; AudioThread *_audioThread; long long _epoch; + Common::String _resourcePath; }; #endif diff --git a/backends/platform/tizen/tizen.mk b/backends/platform/tizen/tizen.mk new file mode 100644 index 0000000000..d8925b62dc --- /dev/null +++ b/backends/platform/tizen/tizen.mk @@ -0,0 +1,7 @@ +# port files built under eclipse + +MODULE := backends/platform/tizen + +$(EXECUTABLE): $(OBJS) + rm -f $@ + arm-linux-gnueabi-ar Tru $@ $(OBJS) diff --git a/backends/platform/wii/osystem.cpp b/backends/platform/wii/osystem.cpp index 22a6495f8f..9d3a7473e3 100644 --- a/backends/platform/wii/osystem.cpp +++ b/backends/platform/wii/osystem.cpp @@ -203,7 +203,7 @@ bool OSystem_Wii::getFeatureState(Feature f) { } } -uint32 OSystem_Wii::getMillis() { +uint32 OSystem_Wii::getMillis(bool skipRecord) { return ticks_to_millisecs(diff_ticks(_startup_time, gettime())); } diff --git a/backends/platform/wii/osystem.h b/backends/platform/wii/osystem.h index 5d6998d0b6..287c70ad6b 100644 --- a/backends/platform/wii/osystem.h +++ b/backends/platform/wii/osystem.h @@ -193,7 +193,7 @@ public: const Graphics::PixelFormat *format); virtual bool pollEvent(Common::Event &event); - virtual uint32 getMillis(); + virtual uint32 getMillis(bool skipRecord = false); virtual void delayMillis(uint msecs); virtual MutexRef createMutex(); diff --git a/backends/platform/wii/osystem_gfx.cpp b/backends/platform/wii/osystem_gfx.cpp index a9bcdbb8d1..92c890b0a9 100644 --- a/backends/platform/wii/osystem_gfx.cpp +++ b/backends/platform/wii/osystem_gfx.cpp @@ -528,16 +528,13 @@ void OSystem_Wii::updateScreen() { } Graphics::Surface *OSystem_Wii::lockScreen() { - _surface.pixels = _gamePixels; - _surface.w = _gameWidth; - _surface.h = _gameHeight; + _surface.init(_gameWidth, _gameHeight, #ifdef USE_RGB_COLOR - _surface.pitch = _gameWidth * _pfGame.bytesPerPixel; - _surface.format = _pfGame; + _gameWidth * _pfGame.bytesPerPixel, _gamePixels, _pfGame #else - _surface.pitch = _gameWidth; - _surface.format = Graphics::PixelFormat::createFormatCLUT8(); + _gameWidth, _gamePixels, Graphics::PixelFormat::createFormatCLUT8() #endif + ); return &_surface; } diff --git a/backends/saves/recorder/recorder-saves.cpp b/backends/saves/recorder/recorder-saves.cpp new file mode 100644 index 0000000000..49b4672913 --- /dev/null +++ b/backends/saves/recorder/recorder-saves.cpp @@ -0,0 +1,35 @@ +/* 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 "backends/saves/recorder/recorder-saves.h" +#include "gui/EventRecorder.h" +#include "common/savefile.h" + +Common::InSaveFile *RecorderSaveFileManager::openForLoading(const Common::String &filename) { + Common::InSaveFile *result = g_eventRec.processSaveStream(filename); + return result; +} + +Common::StringArray RecorderSaveFileManager::listSaveFiles(const Common::String &pattern) { + return g_eventRec.listSaveFiles(pattern); +} + diff --git a/backends/saves/recorder/recorder-saves.h b/backends/saves/recorder/recorder-saves.h new file mode 100644 index 0000000000..692aeca329 --- /dev/null +++ b/backends/saves/recorder/recorder-saves.h @@ -0,0 +1,36 @@ +/* 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 BACKEND_SAVES_RECORDER_H +#define BACKEND_SAVES_RECORDER_H + +#include "backends/saves/default/default-saves.h" + +/** + * Provides a savefile manager implementation for event recorder. + */ +class RecorderSaveFileManager : public DefaultSaveFileManager { + virtual Common::StringArray listSaveFiles(const Common::String &pattern); + virtual Common::InSaveFile *openForLoading(const Common::String &filename); +}; + +#endif diff --git a/backends/timer/default/default-timer.cpp b/backends/timer/default/default-timer.cpp index 9f56d58b12..ce93320f3d 100644 --- a/backends/timer/default/default-timer.cpp +++ b/backends/timer/default/default-timer.cpp @@ -80,7 +80,7 @@ DefaultTimerManager::~DefaultTimerManager() { void DefaultTimerManager::handler() { Common::StackLock lock(_mutex); - const uint32 curTime = g_system->getMillis(); + uint32 curTime = g_system->getMillis(true); // Repeat as long as there is a TimerSlot that is scheduled to fire. TimerSlot *slot = _head->next; diff --git a/backends/timer/bada/timer.cpp b/backends/timer/tizen/timer.cpp index e41ecd4864..fa226ce747 100644 --- a/backends/timer/bada/timer.cpp +++ b/backends/timer/tizen/timer.cpp @@ -20,15 +20,14 @@ * */ -#if defined(BADA) +#if defined(TIZEN) -#include "backends/timer/bada/timer.h" +#include "backends/timer/tizen/timer.h" // -// TimerSlot +// TimerSlot - an event driven thread // -TimerSlot::TimerSlot(Common::TimerManager::TimerProc callback, - uint32 interval, void *refCon) : +TimerSlot::TimerSlot(Common::TimerManager::TimerProc callback, uint32 interval, void *refCon) : _timer(0), _callback(callback), _interval(interval), @@ -36,16 +35,17 @@ TimerSlot::TimerSlot(Common::TimerManager::TimerProc callback, } TimerSlot::~TimerSlot() { + delete _timer; } bool TimerSlot::OnStart() { - _timer = new Osp::Base::Runtime::Timer(); + _timer = new Tizen::Base::Runtime::Timer(); if (!_timer || IsFailed(_timer->Construct(*this))) { AppLog("Failed to create timer"); return false; } - if (IsFailed(_timer->Start(_interval))) { + if (IsFailed(_timer->StartAsRepeatable(_interval))) { AppLog("failed to start timer"); return false; } @@ -65,28 +65,28 @@ void TimerSlot::OnStop() { void TimerSlot::OnTimerExpired(Timer &timer) { _callback(_refCon); - timer.Start(_interval); } // -// BadaTimerManager +// TizenTimerManager // -BadaTimerManager::BadaTimerManager() { +TizenTimerManager::TizenTimerManager() { } -BadaTimerManager::~BadaTimerManager() { - for (Common::List<TimerSlot>::iterator slot = _timers.begin(); - slot != _timers.end(); ) { - slot->Stop(); - slot = _timers.erase(slot); +TizenTimerManager::~TizenTimerManager() { + for (Common::List<TimerSlot *>::iterator it = _timers.begin(); it != _timers.end(); ) { + TimerSlot *slot = (*it); + slot->Quit(); + slot->Join(); + delete slot; + it = _timers.erase(it); } } -bool BadaTimerManager::installTimerProc(TimerProc proc, int32 interval, void *refCon, - const Common::String &id) { +bool TizenTimerManager::installTimerProc(TimerProc proc, int32 interval, void *refCon, const Common::String &id) { TimerSlot *slot = new TimerSlot(proc, interval / 1000, refCon); - if (IsFailed(slot->Construct(THREAD_TYPE_EVENT_DRIVEN))) { + if (IsFailed(slot->Construct())) { AppLog("Failed to create timer thread"); delete slot; return false; @@ -98,16 +98,18 @@ bool BadaTimerManager::installTimerProc(TimerProc proc, int32 interval, void *re return false; } - _timers.push_back(*slot); + _timers.push_back(slot); return true; } -void BadaTimerManager::removeTimerProc(TimerProc proc) { - for (Common::List<TimerSlot>::iterator slot = _timers.begin(); - slot != _timers.end(); ++slot) { +void TizenTimerManager::removeTimerProc(TimerProc proc) { + for (Common::List<TimerSlot *>::iterator it = _timers.begin(); it != _timers.end(); ++it) { + TimerSlot *slot = (*it); if (slot->_callback == proc) { - slot->Stop(); - slot = _timers.erase(slot); + slot->Quit(); + slot->Join(); + delete slot; + it = _timers.erase(it); } } } diff --git a/backends/timer/bada/timer.h b/backends/timer/tizen/timer.h index 826064d7ff..4b2596401a 100644 --- a/backends/timer/bada/timer.h +++ b/backends/timer/tizen/timer.h @@ -20,20 +20,18 @@ * */ -#ifndef BADA_TIMER_H -#define BADA_TIMER_H +#ifndef TIZEN_TIMER_H +#define TIZEN_TIMER_H #include <FBase.h> #include "common/timer.h" #include "common/list.h" -using namespace Osp::Base::Runtime; +using namespace Tizen::Base::Runtime; -struct TimerSlot: public ITimerEventListener, public Thread { - TimerSlot(Common::TimerManager::TimerProc callback, - uint32 interval, - void *refCon); +struct TimerSlot: public EventDrivenThread, public ITimerEventListener { + TimerSlot(Common::TimerManager::TimerProc callback, uint32 interval, void *refCon); ~TimerSlot(); bool OnStart(void); @@ -46,17 +44,16 @@ struct TimerSlot: public ITimerEventListener, public Thread { void *_refCon; }; -class BadaTimerManager : public Common::TimerManager { +class TizenTimerManager : public Common::TimerManager { public: - BadaTimerManager(); - ~BadaTimerManager(); + TizenTimerManager(); + ~TizenTimerManager(); - bool installTimerProc(TimerProc proc, int32 interval, void *refCon, - const Common::String &id); + bool installTimerProc(TimerProc proc, int32 interval, void *refCon, const Common::String &id); void removeTimerProc(TimerProc proc); private: - Common::List<TimerSlot> _timers; + Common::List<TimerSlot *> _timers; }; #endif diff --git a/backends/vkeybd/virtual-keyboard-gui.cpp b/backends/vkeybd/virtual-keyboard-gui.cpp index 75de86472f..ec4cbf1de2 100644 --- a/backends/vkeybd/virtual-keyboard-gui.cpp +++ b/backends/vkeybd/virtual-keyboard-gui.cpp @@ -32,11 +32,9 @@ namespace Common { -static void blit(Graphics::Surface *surf_dst, Graphics::Surface *surf_src, int16 x, int16 y, OverlayColor transparent) { - if (surf_dst->format.bytesPerPixel != sizeof(OverlayColor) || surf_src->format.bytesPerPixel != sizeof(OverlayColor)) - return; - - const OverlayColor *src = (const OverlayColor *)surf_src->pixels; +template<typename ColorType> +static void blitImplementation(Graphics::Surface *surf_dst, Graphics::Surface *surf_src, int16 x, int16 y, ColorType transparent) { + const ColorType *src = (const ColorType *)surf_src->getPixels(); int blitW = surf_src->w; int blitH = surf_src->h; @@ -58,13 +56,13 @@ static void blit(Graphics::Surface *surf_dst, Graphics::Surface *surf_src, int16 if (blitW <= 0 || blitH <= 0) return; - OverlayColor *dst = (OverlayColor *)surf_dst->getBasePtr(x, y); + ColorType *dst = (ColorType *)surf_dst->getBasePtr(x, y); int dstAdd = surf_dst->w - blitW; int srcAdd = surf_src->w - blitW; for (int i = 0; i < blitH; ++i) { for (int j = 0; j < blitW; ++j, ++dst, ++src) { - OverlayColor col = *src; + ColorType col = *src; if (col != transparent) *dst = col; } @@ -73,6 +71,16 @@ static void blit(Graphics::Surface *surf_dst, Graphics::Surface *surf_src, int16 } } +static void blit(Graphics::Surface *surf_dst, Graphics::Surface *surf_src, int16 x, int16 y, uint32 transparent) { + if (surf_dst->format.bytesPerPixel != surf_src->format.bytesPerPixel) + return; + + if (surf_dst->format.bytesPerPixel == 2) + blitImplementation<uint16>(surf_dst, surf_src, x, y, transparent); + else if (surf_dst->format.bytesPerPixel == 4) + blitImplementation<uint32>(surf_dst, surf_src, x, y, transparent); +} + VirtualKeyboardGUI::VirtualKeyboardGUI(VirtualKeyboard *kbd) : _kbd(kbd), _displaying(false), _drag(false), _drawCaret(false), _displayEnabled(false), _firstRun(true), @@ -111,7 +119,7 @@ void VirtualKeyboardGUI::initMode(VirtualKeyboard::Mode *mode) { } } -void VirtualKeyboardGUI::setupDisplayArea(Rect &r, OverlayColor forecolor) { +void VirtualKeyboardGUI::setupDisplayArea(Rect &r, uint32 forecolor) { _dispFont = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont); if (!fontIsSuitable(_dispFont, r)) { @@ -161,7 +169,7 @@ void VirtualKeyboardGUI::run() { _system->clearOverlay(); } _overlayBackup.create(_screenW, _screenH, _system->getOverlayFormat()); - _system->grabOverlay(_overlayBackup.pixels, _overlayBackup.pitch); + _system->grabOverlay(_overlayBackup.getPixels(), _overlayBackup.pitch); setupCursor(); @@ -171,7 +179,7 @@ void VirtualKeyboardGUI::run() { removeCursor(); - _system->copyRectToOverlay(_overlayBackup.pixels, _overlayBackup.pitch, 0, 0, _overlayBackup.w, _overlayBackup.h); + _system->copyRectToOverlay(_overlayBackup.getPixels(), _overlayBackup.pitch, 0, 0, _overlayBackup.w, _overlayBackup.h); if (!g_gui.isActive()) _system->hideOverlay(); _overlayBackup.free(); @@ -262,7 +270,7 @@ void VirtualKeyboardGUI::screenChanged() { _screenH = newScreenH; _overlayBackup.create(_screenW, _screenH, _system->getOverlayFormat()); - _system->grabOverlay(_overlayBackup.pixels, _overlayBackup.pitch); + _system->grabOverlay(_overlayBackup.getPixels(), _overlayBackup.pitch); if (!_kbd->checkModeResolutions()) { _displaying = false; @@ -356,13 +364,13 @@ void VirtualKeyboardGUI::redraw() { Graphics::Surface surf; surf.create(w, h, _system->getOverlayFormat()); - OverlayColor *dst = (OverlayColor *)surf.pixels; - const OverlayColor *src = (OverlayColor *) _overlayBackup.getBasePtr(_dirtyRect.left, _dirtyRect.top); + byte *dst = (byte *)surf.getPixels(); + const byte *src = (const byte *)_overlayBackup.getBasePtr(_dirtyRect.left, _dirtyRect.top); while (h--) { - memcpy(dst, src, surf.w * sizeof(OverlayColor)); - dst += surf.w; - src += _overlayBackup.w; + memcpy(dst, src, surf.pitch); + dst += surf.pitch; + src += _overlayBackup.pitch; } blit(&surf, _kbdSurface, _kbdBound.left - _dirtyRect.left, @@ -371,7 +379,7 @@ void VirtualKeyboardGUI::redraw() { blit(&surf, &_dispSurface, _dispX - _dirtyRect.left, _dispY - _dirtyRect.top, _dispBackColor); } - _system->copyRectToOverlay(surf.pixels, surf.pitch, + _system->copyRectToOverlay(surf.getPixels(), surf.pitch, _dirtyRect.left, _dirtyRect.top, surf.w, surf.h); surf.free(); diff --git a/backends/vkeybd/virtual-keyboard-gui.h b/backends/vkeybd/virtual-keyboard-gui.h index d0f9c884ed..a2000adea0 100644 --- a/backends/vkeybd/virtual-keyboard-gui.h +++ b/backends/vkeybd/virtual-keyboard-gui.h @@ -99,7 +99,7 @@ private: VirtualKeyboard *_kbd; Rect _kbdBound; Graphics::Surface *_kbdSurface; - OverlayColor _kbdTransparentColor; + uint32 _kbdTransparentColor; Point _dragPoint; bool _drag; @@ -113,7 +113,7 @@ private: const Graphics::Font *_dispFont; int16 _dispX, _dispY; uint _dispI; - OverlayColor _dispForeColor, _dispBackColor; + uint32 _dispForeColor, _dispBackColor; int _lastScreenChanged; int16 _screenW, _screenH; @@ -121,7 +121,7 @@ private: bool _displaying; bool _firstRun; - void setupDisplayArea(Rect &r, OverlayColor forecolor); + void setupDisplayArea(Rect &r, uint32 forecolor); void move(int16 x, int16 y); void moveToDefaultPosition(); void screenChanged(); diff --git a/backends/vkeybd/virtual-keyboard.h b/backends/vkeybd/virtual-keyboard.h index 4ab5ad446d..3b2b2196bd 100644 --- a/backends/vkeybd/virtual-keyboard.h +++ b/backends/vkeybd/virtual-keyboard.h @@ -112,11 +112,11 @@ protected: String resolution; String bitmapName; Graphics::Surface *image; - OverlayColor transparentColor; + uint32 transparentColor; ImageMap imageMap; VKEventMap events; Rect displayArea; - OverlayColor displayFontColor; + uint32 displayFontColor; Mode() : image(0) {} ~Mode() { diff --git a/base/commandLine.cpp b/base/commandLine.cpp index 42a3a64d34..a032f37a25 100644 --- a/base/commandLine.cpp +++ b/base/commandLine.cpp @@ -118,6 +118,13 @@ static const char HELP_STRING[] = " --aspect-ratio Enable aspect ratio correction\n" " --render-mode=MODE Enable additional render modes (cga, ega, hercGreen,\n" " hercAmber, amiga)\n" +#ifdef ENABLE_EVENTRECORDER + " --record-mode=MODE Specify record mode for event recorder (record, playback,\n" + " passthrough [default])\n" + " --record-file-name=FILE Specify record file name\n" + " --disable-display Disable any gfx output. Used for headless events\n" + " playback by Event Recorder\n" +#endif "\n" #if defined(ENABLE_SKY) || defined(ENABLE_QUEEN) " --alt-intro Use alternative intro for CD versions of Beneath a\n" @@ -232,10 +239,9 @@ void registerDefaults() { ConfMan.registerDefault("confirm_exit", false); ConfMan.registerDefault("disable_sdl_parachute", false); + ConfMan.registerDefault("disable_display", false); ConfMan.registerDefault("record_mode", "none"); ConfMan.registerDefault("record_file_name", "record.bin"); - ConfMan.registerDefault("record_temp_file_name", "record.tmp"); - ConfMan.registerDefault("record_time_file_name", "record.time"); ConfMan.registerDefault("gui_saveload_chooser", "grid"); ConfMan.registerDefault("gui_saveload_last_pos", "0"); @@ -424,6 +430,17 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha DO_OPTION_BOOL('f', "fullscreen") END_OPTION +#ifdef ENABLE_EVENTRECORDER + DO_LONG_OPTION_INT("disable-display") + END_OPTION + + DO_LONG_OPTION("record-mode") + END_OPTION + + DO_LONG_OPTION("record-file-name") + END_OPTION +#endif + DO_LONG_OPTION("opl-driver") END_OPTION @@ -569,18 +586,6 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha END_OPTION #endif - DO_LONG_OPTION("record-mode") - END_OPTION - - DO_LONG_OPTION("record-file-name") - END_OPTION - - DO_LONG_OPTION("record-temp-file-name") - END_OPTION - - DO_LONG_OPTION("record-time-file-name") - END_OPTION - #ifdef IPHONE // This is automatically set when launched from the Springboard. DO_LONG_OPTION_OPT("launchedFromSB", 0) @@ -822,9 +827,8 @@ void upgradeTargets() { printf("Upgrading all your existing targets\n"); - Common::ConfigManager::DomainMap &domains = ConfMan.getGameDomains(); - Common::ConfigManager::DomainMap::iterator iter = domains.begin(); - for (iter = domains.begin(); iter != domains.end(); ++iter) { + Common::ConfigManager::DomainMap::iterator iter = ConfMan.beginGameDomains(); + for (; iter != ConfMan.endGameDomains(); ++iter) { Common::ConfigManager::Domain &dom = iter->_value; Common::String name(iter->_key); Common::String gameid(dom.getVal("gameid")); diff --git a/base/main.cpp b/base/main.cpp index 355a65f883..103d743bbc 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -42,8 +42,11 @@ #include "common/debug.h" #include "common/debug-channels.h" /* for debug manager */ #include "common/events.h" -#include "common/EventRecorder.h" +#include "gui/EventRecorder.h" #include "common/fs.h" +#ifdef ENABLE_EVENTRECORDER +#include "common/recorderfile.h" +#endif #include "common/system.h" #include "common/textconsole.h" #include "common/tokenizer.h" @@ -409,7 +412,9 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { settings["gfx-mode"] = "default"; } } - + if (settings.contains("disable-display")) { + ConfMan.setInt("disable-display", 1, Common::ConfigManager::kTransientDomain); + } setupGraphics(system); // Init the different managers that are used by the engines. @@ -422,13 +427,15 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { // take place after the backend is initiated and the screen has been setup system.getEventManager()->init(); +#ifdef ENABLE_EVENTRECORDER // Directly after initializing the event manager, we will initialize our // event recorder. // // TODO: This is just to match the current behavior, when we further extend // our event recorder, we might do this at another place. Or even change // the whole API for that ;-). - g_eventRec.init(); + g_eventRec.RegisterEventSource(); +#endif // Now as the event manager is created, setup the keymapper setupKeymapper(system); @@ -448,12 +455,29 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { // to save memory PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_ENGINE, plugin); +#ifdef ENABLE_EVENTRECORDER + Common::String recordMode = ConfMan.get("record_mode"); + Common::String recordFileName = ConfMan.get("record_file_name"); + + if (recordMode == "record") { + g_eventRec.init(g_eventRec.generateRecordFileName(ConfMan.getActiveDomainName()), GUI::EventRecorder::kRecorderRecord); + } else if (recordMode == "playback") { + g_eventRec.init(recordFileName, GUI::EventRecorder::kRecorderPlayback); + } else if ((recordMode == "info") && (!recordFileName.empty())) { + Common::PlaybackFile record; + record.openRead(recordFileName); + debug("info:author=%s name=%s description=%s", record.getHeader().author.c_str(), record.getHeader().name.c_str(), record.getHeader().description.c_str()); + break; + } +#endif // Try to run the game Common::Error result = runGame(plugin, system, specialDebug); +#ifdef ENABLE_EVENTRECORDER // Flush Event recorder file. The recorder does not get reinitialized for next game // which is intentional. Only single game per session is allowed. g_eventRec.deinit(); +#endif #if defined(UNCACHED_PLUGINS) && defined(DYNAMIC_MODULES) // do our best to prevent fragmentation by unloading as soon as we can @@ -478,6 +502,11 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { #ifdef FORCE_RTL g_system->getEventManager()->resetQuit(); #endif + #ifdef ENABLE_EVENTRECORDER + if (g_eventRec.checkForContinueGame()) { + continue; + } + #endif // Discard any command line options. It's unlikely that the user // wanted to apply them to *all* games ever launched. @@ -501,7 +530,9 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { GUI::GuiManager::destroy(); Common::ConfigManager::destroy(); Common::DebugManager::destroy(); - Common::EventRecorder::destroy(); +#ifdef ENABLE_EVENTRECORDER + GUI::EventRecorder::destroy(); +#endif Common::SearchManager::destroy(); #ifdef USE_TRANSLATION Common::TranslationManager::destroy(); diff --git a/common/EventDispatcher.cpp b/common/EventDispatcher.cpp index 012a2dfce5..e60c1aa7ff 100644 --- a/common/EventDispatcher.cpp +++ b/common/EventDispatcher.cpp @@ -24,7 +24,7 @@ namespace Common { -EventDispatcher::EventDispatcher() : _mapper(0) { +EventDispatcher::EventDispatcher() : _autoFreeMapper(false), _mapper(0) { } EventDispatcher::~EventDispatcher() { @@ -38,7 +38,9 @@ EventDispatcher::~EventDispatcher() { delete i->observer; } - delete _mapper; + if (_autoFreeMapper) { + delete _mapper; + } _mapper = 0; } @@ -68,11 +70,15 @@ void EventDispatcher::dispatch() { } } -void EventDispatcher::registerMapper(EventMapper *mapper) { - delete _mapper; +void EventDispatcher::registerMapper(EventMapper *mapper, bool autoFree) { + if (_autoFreeMapper) { + delete _mapper; + } _mapper = mapper; + _autoFreeMapper = autoFree; } + void EventDispatcher::registerSource(EventSource *source, bool autoFree) { SourceEntry newEntry; diff --git a/common/EventRecorder.cpp b/common/EventRecorder.cpp deleted file mode 100644 index 5e24f128c3..0000000000 --- a/common/EventRecorder.cpp +++ /dev/null @@ -1,428 +0,0 @@ -/* 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/EventRecorder.h" - -#include "common/bufferedstream.h" -#include "common/config-manager.h" -#include "common/random.h" -#include "common/savefile.h" -#include "common/textconsole.h" - -namespace Common { - -DECLARE_SINGLETON(EventRecorder); - -#define RECORD_SIGNATURE 0x54455354 -#define RECORD_VERSION 1 - -uint32 readTime(ReadStream *inFile) { - uint32 d = inFile->readByte(); - if (d == 0xff) { - d = inFile->readUint32LE(); - } - - return d; -} - -void writeTime(WriteStream *outFile, uint32 d) { - //Simple RLE compression - if (d >= 0xff) { - outFile->writeByte(0xff); - outFile->writeUint32LE(d); - } else { - outFile->writeByte(d); - } -} - -void readRecord(SeekableReadStream *inFile, uint32 &diff, Event &event, uint32 &millis) { - millis = readTime(inFile); - - diff = inFile->readUint32LE(); - - event.type = (EventType)inFile->readUint32LE(); - - switch (event.type) { - case EVENT_KEYDOWN: - case EVENT_KEYUP: - event.kbd.keycode = (KeyCode)inFile->readSint32LE(); - event.kbd.ascii = inFile->readUint16LE(); - event.kbd.flags = inFile->readByte(); - break; - case EVENT_MOUSEMOVE: - case EVENT_LBUTTONDOWN: - case EVENT_LBUTTONUP: - case EVENT_RBUTTONDOWN: - case EVENT_RBUTTONUP: - case EVENT_WHEELUP: - case EVENT_WHEELDOWN: - case EVENT_MBUTTONDOWN: - case EVENT_MBUTTONUP: - event.mouse.x = inFile->readSint16LE(); - event.mouse.y = inFile->readSint16LE(); - break; - default: - break; - } -} - -void writeRecord(WriteStream *outFile, uint32 diff, const Event &event, uint32 millis) { - writeTime(outFile, millis); - - outFile->writeUint32LE(diff); - - outFile->writeUint32LE((uint32)event.type); - - switch (event.type) { - case EVENT_KEYDOWN: - case EVENT_KEYUP: - outFile->writeSint32LE(event.kbd.keycode); - outFile->writeUint16LE(event.kbd.ascii); - outFile->writeByte(event.kbd.flags); - break; - case EVENT_MOUSEMOVE: - case EVENT_LBUTTONDOWN: - case EVENT_LBUTTONUP: - case EVENT_RBUTTONDOWN: - case EVENT_RBUTTONUP: - case EVENT_WHEELUP: - case EVENT_WHEELDOWN: - case EVENT_MBUTTONDOWN: - case EVENT_MBUTTONUP: - outFile->writeSint16LE(event.mouse.x); - outFile->writeSint16LE(event.mouse.y); - break; - default: - break; - } -} - -EventRecorder::EventRecorder() { - _recordFile = NULL; - _recordTimeFile = NULL; - _playbackFile = NULL; - _playbackTimeFile = NULL; - _timeMutex = g_system->createMutex(); - _recorderMutex = g_system->createMutex(); - - _eventCount = 0; - _lastEventCount = 0; - _lastMillis = 0; - _lastEventMillis = 0; - - _recordMode = kPassthrough; -} - -EventRecorder::~EventRecorder() { - deinit(); - - g_system->deleteMutex(_timeMutex); - g_system->deleteMutex(_recorderMutex); -} - -void EventRecorder::init() { - String recordModeString = ConfMan.get("record_mode"); - if (recordModeString.compareToIgnoreCase("record") == 0) { - _recordMode = kRecorderRecord; - - debug(3, "EventRecorder: record"); - } else { - if (recordModeString.compareToIgnoreCase("playback") == 0) { - _recordMode = kRecorderPlayback; - debug(3, "EventRecorder: playback"); - } else { - _recordMode = kPassthrough; - debug(3, "EventRecorder: passthrough"); - } - } - - _recordFileName = ConfMan.get("record_file_name"); - if (_recordFileName.empty()) { - _recordFileName = "record.bin"; - } - _recordTempFileName = ConfMan.get("record_temp_file_name"); - if (_recordTempFileName.empty()) { - _recordTempFileName = "record.tmp"; - } - _recordTimeFileName = ConfMan.get("record_time_file_name"); - if (_recordTimeFileName.empty()) { - _recordTimeFileName = "record.time"; - } - - // recorder stuff - if (_recordMode == kRecorderRecord) { - _recordCount = 0; - _recordTimeCount = 0; - _recordFile = wrapBufferedWriteStream(g_system->getSavefileManager()->openForSaving(_recordTempFileName), 128 * 1024); - _recordTimeFile = wrapBufferedWriteStream(g_system->getSavefileManager()->openForSaving(_recordTimeFileName), 128 * 1024); - _recordSubtitles = ConfMan.getBool("subtitles"); - } - - uint32 sign; - uint32 randomSourceCount; - if (_recordMode == kRecorderPlayback) { - _playbackCount = 0; - _playbackTimeCount = 0; - _playbackFile = wrapBufferedSeekableReadStream(g_system->getSavefileManager()->openForLoading(_recordFileName), 128 * 1024, DisposeAfterUse::YES); - _playbackTimeFile = wrapBufferedSeekableReadStream(g_system->getSavefileManager()->openForLoading(_recordTimeFileName), 128 * 1024, DisposeAfterUse::YES); - - if (!_playbackFile) { - warning("Cannot open playback file %s. Playback was switched off", _recordFileName.c_str()); - _recordMode = kPassthrough; - } - - if (!_playbackTimeFile) { - warning("Cannot open playback time file %s. Playback was switched off", _recordTimeFileName.c_str()); - _recordMode = kPassthrough; - } - } - - if (_recordMode == kRecorderPlayback) { - sign = _playbackFile->readUint32LE(); - if (sign != RECORD_SIGNATURE) { - error("Unknown record file signature"); - } - - _playbackFile->readUint32LE(); // version - - // conf vars - ConfMan.setBool("subtitles", _playbackFile->readByte() != 0); - - _recordCount = _playbackFile->readUint32LE(); - _recordTimeCount = _playbackFile->readUint32LE(); - - randomSourceCount = _playbackFile->readUint32LE(); - for (uint i = 0; i < randomSourceCount; ++i) { - RandomSourceRecord rec; - rec.name = ""; - uint32 sLen = _playbackFile->readUint32LE(); - for (uint j = 0; j < sLen; ++j) { - char c = _playbackFile->readSByte(); - rec.name += c; - } - rec.seed = _playbackFile->readUint32LE(); - _randomSourceRecords.push_back(rec); - } - - _hasPlaybackEvent = false; - } - - g_system->getEventManager()->getEventDispatcher()->registerSource(this, false); - g_system->getEventManager()->getEventDispatcher()->registerObserver(this, EventManager::kEventRecorderPriority, false, true); -} - -void EventRecorder::deinit() { - debug(3, "EventRecorder: deinit"); - - g_system->getEventManager()->getEventDispatcher()->unregisterSource(this); - g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this); - - g_system->lockMutex(_timeMutex); - g_system->lockMutex(_recorderMutex); - _recordMode = kPassthrough; - g_system->unlockMutex(_timeMutex); - g_system->unlockMutex(_recorderMutex); - - delete _playbackFile; - delete _playbackTimeFile; - - if (_recordFile != NULL) { - _recordFile->finalize(); - delete _recordFile; - _recordTimeFile->finalize(); - delete _recordTimeFile; - - _playbackFile = g_system->getSavefileManager()->openForLoading(_recordTempFileName); - - assert(_playbackFile); - - _recordFile = g_system->getSavefileManager()->openForSaving(_recordFileName); - _recordFile->writeUint32LE(RECORD_SIGNATURE); - _recordFile->writeUint32LE(RECORD_VERSION); - - // conf vars - _recordFile->writeByte(_recordSubtitles ? 1 : 0); - - _recordFile->writeUint32LE(_recordCount); - _recordFile->writeUint32LE(_recordTimeCount); - - _recordFile->writeUint32LE(_randomSourceRecords.size()); - for (uint i = 0; i < _randomSourceRecords.size(); ++i) { - _recordFile->writeUint32LE(_randomSourceRecords[i].name.size()); - _recordFile->writeString(_randomSourceRecords[i].name); - _recordFile->writeUint32LE(_randomSourceRecords[i].seed); - } - - for (uint i = 0; i < _recordCount; ++i) { - uint32 tempDiff; - Event tempEvent; - uint32 millis; - readRecord(_playbackFile, tempDiff, tempEvent, millis); - writeRecord(_recordFile, tempDiff, tempEvent, millis); - } - - _recordFile->finalize(); - delete _recordFile; - delete _playbackFile; - - //TODO: remove recordTempFileName'ed file - } -} - -void EventRecorder::registerRandomSource(RandomSource &rnd, const String &name) { - if (_recordMode == kRecorderRecord) { - RandomSourceRecord rec; - rec.name = name; - rec.seed = rnd.getSeed(); - _randomSourceRecords.push_back(rec); - } - - if (_recordMode == kRecorderPlayback) { - for (uint i = 0; i < _randomSourceRecords.size(); ++i) { - if (_randomSourceRecords[i].name == name) { - rnd.setSeed(_randomSourceRecords[i].seed); - _randomSourceRecords.remove_at(i); - break; - } - } - } -} - -void EventRecorder::processMillis(uint32 &millis) { - uint32 d; - if (_recordMode == kPassthrough) { - return; - } - - g_system->lockMutex(_timeMutex); - if (_recordMode == kRecorderRecord) { - d = millis - _lastMillis; - writeTime(_recordTimeFile, d); - - _recordTimeCount++; - } - - if (_recordMode == kRecorderPlayback) { - if (_recordTimeCount > _playbackTimeCount) { - d = readTime(_playbackTimeFile); - - while ((_lastMillis + d > millis) && (_lastMillis + d - millis > 50)) { - _recordMode = kPassthrough; - g_system->delayMillis(50); - millis = g_system->getMillis(); - _recordMode = kRecorderPlayback; - } - - millis = _lastMillis + d; - _playbackTimeCount++; - } - } - - _lastMillis = millis; - g_system->unlockMutex(_timeMutex); -} - -bool EventRecorder::processDelayMillis(uint &msecs) { - if (_recordMode == kRecorderPlayback) { - _recordMode = kPassthrough; - - uint32 millis = g_system->getMillis(); - - _recordMode = kRecorderPlayback; - - if (_lastMillis > millis) { - // Skip delay if we're getting late - return true; - } - } - - return false; -} - -bool EventRecorder::notifyEvent(const Event &ev) { - if (_recordMode != kRecorderRecord) - return false; - - StackLock lock(_recorderMutex); - ++_eventCount; - - writeRecord(_recordFile, _eventCount - _lastEventCount, ev, _lastMillis - _lastEventMillis); - - _recordCount++; - _lastEventCount = _eventCount; - _lastEventMillis = _lastMillis; - - return false; -} - -bool EventRecorder::notifyPoll() { - if (_recordMode != kRecorderRecord) - return false; - - ++_eventCount; - - return false; -} - -bool EventRecorder::pollEvent(Event &ev) { - uint32 millis; - - if (_recordMode != kRecorderPlayback) - return false; - - StackLock lock(_recorderMutex); - ++_eventCount; - - if (!_hasPlaybackEvent) { - if (_recordCount > _playbackCount) { - readRecord(_playbackFile, const_cast<uint32&>(_playbackDiff), _playbackEvent, millis); - _playbackCount++; - _hasPlaybackEvent = true; - } - } - - if (_hasPlaybackEvent) { - if (_playbackDiff <= (_eventCount - _lastEventCount)) { - switch (_playbackEvent.type) { - case EVENT_MOUSEMOVE: - case EVENT_LBUTTONDOWN: - case EVENT_LBUTTONUP: - case EVENT_RBUTTONDOWN: - case EVENT_RBUTTONUP: - case EVENT_WHEELUP: - case EVENT_WHEELDOWN: - g_system->warpMouse(_playbackEvent.mouse.x, _playbackEvent.mouse.y); - break; - default: - break; - } - ev = _playbackEvent; - _hasPlaybackEvent = false; - _lastEventCount = _eventCount; - return true; - } - } - - return false; -} - -} // End of namespace Common diff --git a/common/EventRecorder.h b/common/EventRecorder.h deleted file mode 100644 index 43a08b08cd..0000000000 --- a/common/EventRecorder.h +++ /dev/null @@ -1,110 +0,0 @@ -/* 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 COMMON_EVENTRECORDER_H -#define COMMON_EVENTRECORDER_H - -#include "common/scummsys.h" -#include "common/events.h" -#include "common/singleton.h" -#include "common/mutex.h" -#include "common/array.h" - -#define g_eventRec (Common::EventRecorder::instance()) - -namespace Common { - -class RandomSource; -class SeekableReadStream; -class WriteStream; - -/** - * Our generic event recorder. - * - * TODO: Add more documentation. - */ -class EventRecorder : private EventSource, private EventObserver, public Singleton<EventRecorder> { - friend class Singleton<SingletonBaseType>; - EventRecorder(); - ~EventRecorder(); -public: - void init(); - void deinit(); - - /** Register random source so it can be serialized in game test purposes */ - void registerRandomSource(RandomSource &rnd, const String &name); - - /** TODO: Add documentation, this is only used by the backend */ - void processMillis(uint32 &millis); - - /** TODO: Add documentation, this is only used by the backend */ - bool processDelayMillis(uint &msecs); - -private: - bool notifyEvent(const Event &ev); - bool notifyPoll(); - bool pollEvent(Event &ev); - bool allowMapping() const { return false; } - - class RandomSourceRecord { - public: - String name; - uint32 seed; - }; - Array<RandomSourceRecord> _randomSourceRecords; - - bool _recordSubtitles; - volatile uint32 _recordCount; - volatile uint32 _lastRecordEvent; - volatile uint32 _recordTimeCount; - volatile uint32 _lastEventMillis; - WriteStream *_recordFile; - WriteStream *_recordTimeFile; - MutexRef _timeMutex; - MutexRef _recorderMutex; - volatile uint32 _lastMillis; - - volatile uint32 _playbackCount; - volatile uint32 _playbackDiff; - volatile bool _hasPlaybackEvent; - volatile uint32 _playbackTimeCount; - Event _playbackEvent; - SeekableReadStream *_playbackFile; - SeekableReadStream *_playbackTimeFile; - - volatile uint32 _eventCount; - volatile uint32 _lastEventCount; - - enum RecordMode { - kPassthrough = 0, - kRecorderRecord = 1, - kRecorderPlayback = 2 - }; - volatile RecordMode _recordMode; - String _recordFileName; - String _recordTempFileName; - String _recordTimeFileName; -}; - -} // End of namespace Common - -#endif diff --git a/common/config-manager.h b/common/config-manager.h index d43a7bec51..6bf56749c5 100644 --- a/common/config-manager.h +++ b/common/config-manager.h @@ -24,7 +24,6 @@ #define COMMON_CONFIG_MANAGER_H #include "common/array.h" -//#include "common/config-file.h" #include "common/hashmap.h" #include "common/singleton.h" #include "common/str.h" @@ -47,12 +46,33 @@ class ConfigManager : public Singleton<ConfigManager> { public: - class Domain : public StringMap { + class Domain { private: + StringMap _entries; StringMap _keyValueComments; String _domainComment; public: + typedef StringMap::const_iterator const_iterator; + const_iterator begin() const { return _entries.begin(); } + const_iterator end() const { return _entries.end(); } + + bool empty() const { return _entries.empty(); } + + bool contains(const String &key) const { return _entries.contains(key); } + + String &operator[](const String &key) { return _entries[key]; } + const String &operator[](const String &key) const { return _entries[key]; } + + void setVal(const String &key, const String &value) { _entries.setVal(key, value); } + + String &getVal(const String &key) { return _entries.getVal(key); } + const String &getVal(const String &key) const { return _entries.getVal(key); } + + void clear() { _entries.clear(); } + + void erase(const String &key) { _entries.erase(key); } + void setDomainComment(const String &comment); const String &getDomainComment() const; @@ -143,7 +163,8 @@ public: bool hasMiscDomain(const String &domName) const; const DomainMap & getGameDomains() const { return _gameDomains; } - DomainMap & getGameDomains() { return _gameDomains; } + DomainMap::iterator beginGameDomains() { return _gameDomains.begin(); } + DomainMap::iterator endGameDomains() { return _gameDomains.end(); } static void defragment(); // move in memory to reduce fragmentation void copyFrom(ConfigManager &source); diff --git a/common/debug.h b/common/debug.h index dc94839082..859f3c41b3 100644 --- a/common/debug.h +++ b/common/debug.h @@ -117,5 +117,9 @@ void debugCN(uint32 debugChannels, const char *s, ...) GCC_PRINTF(2, 3); */ extern int gDebugLevel; +//Global constant for EventRecorder debug channel +enum GlobalDebugLevels { + kDebugLevelEventRec = 1 << 30 +}; #endif diff --git a/common/events.h b/common/events.h index 7366c51d36..9029a4096a 100644 --- a/common/events.h +++ b/common/events.h @@ -288,11 +288,14 @@ public: * to the EventDispatcher, thus it will be deleted * with "delete", when EventDispatcher is destroyed. * - * Note there is only one mapper per EventDispatcher - * possible, thus when this method is called twice, - * the former mapper will be destroied. + * @param autoFree Destroy previous mapper [default] + * Normally we allow only one event mapper to exists, + * However Event Recorder must intervent into normal + * event flow without altering its semantics. Thus during + * Event Recorder playback and recording we allow + * two mappers. */ - void registerMapper(EventMapper *mapper); + void registerMapper(EventMapper *mapper, bool autoFree = true); /** * Queries the setup event mapper. @@ -326,6 +329,7 @@ public: */ void unregisterObserver(EventObserver *obs); private: + bool _autoFreeMapper; EventMapper *_mapper; struct Entry { diff --git a/common/config-file.cpp b/common/ini-file.cpp index 0ce6dcf0c8..be5247dcfb 100644 --- a/common/config-file.cpp +++ b/common/ini-file.cpp @@ -20,7 +20,7 @@ * */ -#include "common/config-file.h" +#include "common/ini-file.h" #include "common/file.h" #include "common/savefile.h" #include "common/system.h" @@ -28,24 +28,24 @@ namespace Common { -bool ConfigFile::isValidName(const String &name) { +bool INIFile::isValidName(const String &name) { const char *p = name.c_str(); while (*p && (isAlnum(*p) || *p == '-' || *p == '_' || *p == '.')) p++; return *p == 0; } -ConfigFile::ConfigFile() { +INIFile::INIFile() { } -ConfigFile::~ConfigFile() { +INIFile::~INIFile() { } -void ConfigFile::clear() { +void INIFile::clear() { _sections.clear(); } -bool ConfigFile::loadFromFile(const String &filename) { +bool INIFile::loadFromFile(const String &filename) { File file; if (file.open(filename)) return loadFromStream(file); @@ -53,7 +53,7 @@ bool ConfigFile::loadFromFile(const String &filename) { return false; } -bool ConfigFile::loadFromSaveFile(const char *filename) { +bool INIFile::loadFromSaveFile(const char *filename) { assert(g_system); SaveFileManager *saveFileMan = g_system->getSavefileManager(); SeekableReadStream *loadFile; @@ -67,7 +67,7 @@ bool ConfigFile::loadFromSaveFile(const char *filename) { return status; } -bool ConfigFile::loadFromStream(SeekableReadStream &stream) { +bool INIFile::loadFromStream(SeekableReadStream &stream) { Section section; KeyValue kv; String comment; @@ -112,9 +112,9 @@ bool ConfigFile::loadFromStream(SeekableReadStream &stream) { p++; if (*p == '\0') - error("ConfigFile::loadFromStream: missing ] in line %d", lineno); + error("INIFile::loadFromStream: missing ] in line %d", lineno); else if (*p != ']') - error("ConfigFile::loadFromStream: Invalid character '%c' occurred in section name in line %d", *p, lineno); + error("INIFile::loadFromStream: Invalid character '%c' occurred in section name in line %d", *p, lineno); // Previous section is finished now, store it. if (!section.name.empty()) @@ -140,7 +140,7 @@ bool ConfigFile::loadFromStream(SeekableReadStream &stream) { // If no section has been set, this config file is invalid! if (section.name.empty()) { - error("ConfigFile::loadFromStream: Key/value pair found outside a section in line %d", lineno); + error("INIFile::loadFromStream: Key/value pair found outside a section in line %d", lineno); } // Split string at '=' into 'key' and 'value'. First, find the "=" delimeter. @@ -173,7 +173,7 @@ bool ConfigFile::loadFromStream(SeekableReadStream &stream) { return (!stream.err() || stream.eos()); } -bool ConfigFile::saveToFile(const String &filename) { +bool INIFile::saveToFile(const String &filename) { DumpFile file; if (file.open(filename)) return saveToStream(file); @@ -181,7 +181,7 @@ bool ConfigFile::saveToFile(const String &filename) { return false; } -bool ConfigFile::saveToSaveFile(const char *filename) { +bool INIFile::saveToSaveFile(const char *filename) { assert(g_system); SaveFileManager *saveFileMan = g_system->getSavefileManager(); WriteStream *saveFile; @@ -195,7 +195,7 @@ bool ConfigFile::saveToSaveFile(const char *filename) { return status; } -bool ConfigFile::saveToStream(WriteStream &stream) { +bool INIFile::saveToStream(WriteStream &stream) { for (List<Section>::iterator i = _sections.begin(); i != _sections.end(); ++i) { // Write out the section comment, if any if (! i->comment.empty()) { @@ -226,7 +226,7 @@ bool ConfigFile::saveToStream(WriteStream &stream) { return !stream.err(); } -void ConfigFile::addSection(const String §ion) { +void INIFile::addSection(const String §ion) { Section *s = getSection(section); if (s) return; @@ -236,7 +236,7 @@ void ConfigFile::addSection(const String §ion) { _sections.push_back(newSection); } -void ConfigFile::removeSection(const String §ion) { +void INIFile::removeSection(const String §ion) { assert(isValidName(section)); for (List<Section>::iterator i = _sections.begin(); i != _sections.end(); ++i) { if (section.equalsIgnoreCase(i->name)) { @@ -246,13 +246,13 @@ void ConfigFile::removeSection(const String §ion) { } } -bool ConfigFile::hasSection(const String §ion) const { +bool INIFile::hasSection(const String §ion) const { assert(isValidName(section)); const Section *s = getSection(section); return s != 0; } -void ConfigFile::renameSection(const String &oldName, const String &newName) { +void INIFile::renameSection(const String &oldName, const String &newName) { assert(isValidName(oldName)); assert(isValidName(newName)); @@ -262,7 +262,7 @@ void ConfigFile::renameSection(const String &oldName, const String &newName) { // HACK: For now we just print a warning, for more info see the TODO // below. if (ns) - warning("ConfigFile::renameSection: Section name \"%s\" already used", newName.c_str()); + warning("INIFile::renameSection: Section name \"%s\" already used", newName.c_str()); else os->name = newName; } @@ -274,7 +274,7 @@ void ConfigFile::renameSection(const String &oldName, const String &newName) { } -bool ConfigFile::hasKey(const String &key, const String §ion) const { +bool INIFile::hasKey(const String &key, const String §ion) const { assert(isValidName(key)); assert(isValidName(section)); @@ -284,7 +284,7 @@ bool ConfigFile::hasKey(const String &key, const String §ion) const { return s->hasKey(key); } -void ConfigFile::removeKey(const String &key, const String §ion) { +void INIFile::removeKey(const String &key, const String §ion) { assert(isValidName(key)); assert(isValidName(section)); @@ -293,7 +293,7 @@ void ConfigFile::removeKey(const String &key, const String §ion) { s->removeKey(key); } -bool ConfigFile::getKey(const String &key, const String §ion, String &value) const { +bool INIFile::getKey(const String &key, const String §ion, String &value) const { assert(isValidName(key)); assert(isValidName(section)); @@ -307,7 +307,7 @@ bool ConfigFile::getKey(const String &key, const String §ion, String &value) return true; } -void ConfigFile::setKey(const String &key, const String §ion, const String &value) { +void INIFile::setKey(const String &key, const String §ion, const String &value) { assert(isValidName(key)); assert(isValidName(section)); // TODO: Verify that value is valid, too. In particular, it shouldn't @@ -329,13 +329,13 @@ void ConfigFile::setKey(const String &key, const String §ion, const String & } } -const ConfigFile::SectionKeyList ConfigFile::getKeys(const String §ion) const { +const INIFile::SectionKeyList INIFile::getKeys(const String §ion) const { const Section *s = getSection(section); return s->getKeys(); } -ConfigFile::Section *ConfigFile::getSection(const String §ion) { +INIFile::Section *INIFile::getSection(const String §ion) { for (List<Section>::iterator i = _sections.begin(); i != _sections.end(); ++i) { if (section.equalsIgnoreCase(i->name)) { return &(*i); @@ -344,7 +344,7 @@ ConfigFile::Section *ConfigFile::getSection(const String §ion) { return 0; } -const ConfigFile::Section *ConfigFile::getSection(const String §ion) const { +const INIFile::Section *INIFile::getSection(const String §ion) const { for (List<Section>::const_iterator i = _sections.begin(); i != _sections.end(); ++i) { if (section.equalsIgnoreCase(i->name)) { return &(*i); @@ -353,11 +353,11 @@ const ConfigFile::Section *ConfigFile::getSection(const String §ion) const { return 0; } -bool ConfigFile::Section::hasKey(const String &key) const { +bool INIFile::Section::hasKey(const String &key) const { return getKey(key) != 0; } -const ConfigFile::KeyValue* ConfigFile::Section::getKey(const String &key) const { +const INIFile::KeyValue* INIFile::Section::getKey(const String &key) const { for (List<KeyValue>::const_iterator i = keys.begin(); i != keys.end(); ++i) { if (key.equalsIgnoreCase(i->key)) { return &(*i); @@ -366,7 +366,7 @@ const ConfigFile::KeyValue* ConfigFile::Section::getKey(const String &key) const return 0; } -void ConfigFile::Section::setKey(const String &key, const String &value) { +void INIFile::Section::setKey(const String &key, const String &value) { for (List<KeyValue>::iterator i = keys.begin(); i != keys.end(); ++i) { if (key.equalsIgnoreCase(i->key)) { i->value = value; @@ -380,7 +380,7 @@ void ConfigFile::Section::setKey(const String &key, const String &value) { keys.push_back(newKV); } -void ConfigFile::Section::removeKey(const String &key) { +void INIFile::Section::removeKey(const String &key) { for (List<KeyValue>::iterator i = keys.begin(); i != keys.end(); ++i) { if (key.equalsIgnoreCase(i->key)) { keys.erase(i); diff --git a/common/config-file.h b/common/ini-file.h index 8bba851110..1d94ce7bdc 100644 --- a/common/config-file.h +++ b/common/ini-file.h @@ -20,8 +20,8 @@ * */ -#ifndef COMMON_CONFIG_FILE_H -#define COMMON_CONFIG_FILE_H +#ifndef COMMON_INI_FILE_H +#define COMMON_INI_FILE_H #include "common/hash-str.h" #include "common/list.h" @@ -34,9 +34,6 @@ class WriteStream; /** * This class allows reading/writing INI style config files. - * It is used by the ConfigManager for storage, but can also - * be used by other code if it needs to read/write custom INI - * files. * * Lines starting with a '#' are ignored (i.e. treated as comments). * Some effort is made to preserve comments, though. @@ -47,10 +44,8 @@ class WriteStream; * from/to files, but of course is not appropriate for fast access. * The main reason is that this class is indeed geared toward doing precisely * that! - * If you need fast access to the game config, use higher level APIs, like the - * one provided by ConfigManager. */ -class ConfigFile { +class INIFile { public: struct KeyValue { String key; @@ -60,12 +55,12 @@ public: typedef List<KeyValue> SectionKeyList; - /** A section in a config file. I.e. corresponds to something like this: + /** A section in a ini file. I.e. corresponds to something like this: * [mySection] * key=value * * Comments are also stored, to keep users happy who like editing their - * config files manually. + * ini files manually. */ struct Section { String name; @@ -82,8 +77,8 @@ public: typedef List<Section> SectionList; public: - ConfigFile(); - ~ConfigFile(); + INIFile(); + ~INIFile(); // TODO: Maybe add a copy constructor etc.? @@ -95,7 +90,7 @@ public: */ static bool isValidName(const String &name); - /** Reset everything stored in this config file. */ + /** Reset everything stored in this ini file. */ void clear(); bool loadFromFile(const String &filename); @@ -127,14 +122,6 @@ private: const Section *getSection(const String §ion) const; }; -/* -- ConfigMan owns a config file -- allow direct access to that config file (for the launcher) -- simplify and unify the regular ConfigMan API in exchange - - -*/ - } // End of namespace Common #endif diff --git a/common/macresman.cpp b/common/macresman.cpp index 00562f746a..ba44caafd9 100644 --- a/common/macresman.cpp +++ b/common/macresman.cpp @@ -102,18 +102,18 @@ String MacResManager::computeResForkMD5AsString(uint32 length) const { return computeStreamMD5AsString(resForkStream, MIN<uint32>(length, _resForkSize)); } -bool MacResManager::open(String filename) { +bool MacResManager::open(const String &fileName) { close(); #ifdef MACOSX // Check the actual fork on a Mac computer - String fullPath = ConfMan.get("path") + "/" + filename + "/..namedfork/rsrc"; + String fullPath = ConfMan.get("path") + "/" + fileName + "/..namedfork/rsrc"; FSNode resFsNode = FSNode(fullPath); if (resFsNode.exists()) { SeekableReadStream *macResForkRawStream = resFsNode.createReadStream(); if (macResForkRawStream && loadFromRawFork(*macResForkRawStream)) { - _baseFileName = filename; + _baseFileName = fileName; return true; } @@ -123,38 +123,39 @@ bool MacResManager::open(String filename) { File *file = new File(); - // First, let's try to see if the Mac converted name exists - if (file->open(constructAppleDoubleName(filename)) && loadFromAppleDouble(*file)) { - _baseFileName = filename; + // Prefer standalone files first, starting with raw forks + if (file->open(fileName + ".rsrc") && loadFromRawFork(*file)) { + _baseFileName = fileName; return true; } file->close(); - // Check .bin too - if (file->open(filename + ".bin") && loadFromMacBinary(*file)) { - _baseFileName = filename; + // Then try for AppleDouble using Apple's naming + if (file->open(constructAppleDoubleName(fileName)) && loadFromAppleDouble(*file)) { + _baseFileName = fileName; return true; } file->close(); - // Maybe we have a dumped fork? - if (file->open(filename + ".rsrc") && loadFromRawFork(*file)) { - _baseFileName = filename; + // Check .bin for MacBinary next + if (file->open(fileName + ".bin") && loadFromMacBinary(*file)) { + _baseFileName = fileName; return true; } file->close(); - // Fine, what about just the data fork? - if (file->open(filename)) { - _baseFileName = filename; + // As a last resort, see if just the data fork exists + if (file->open(fileName)) { + _baseFileName = fileName; + // FIXME: Is this really needed? if (isMacBinary(*file)) { - file->seek(0, SEEK_SET); + file->seek(0); if (loadFromMacBinary(*file)) return true; } - file->seek(0, SEEK_SET); + file->seek(0); _stream = file; return true; } @@ -165,18 +166,18 @@ bool MacResManager::open(String filename) { return false; } -bool MacResManager::open(FSNode path, String filename) { +bool MacResManager::open(const FSNode &path, const String &fileName) { close(); #ifdef MACOSX // Check the actual fork on a Mac computer - String fullPath = path.getPath() + "/" + filename + "/..namedfork/rsrc"; + String fullPath = path.getPath() + "/" + fileName + "/..namedfork/rsrc"; FSNode resFsNode = FSNode(fullPath); if (resFsNode.exists()) { SeekableReadStream *macResForkRawStream = resFsNode.createReadStream(); if (macResForkRawStream && loadFromRawFork(*macResForkRawStream)) { - _baseFileName = filename; + _baseFileName = fileName; return true; } @@ -184,52 +185,53 @@ bool MacResManager::open(FSNode path, String filename) { } #endif - // First, let's try to see if the Mac converted name exists - FSNode fsNode = path.getChild(constructAppleDoubleName(filename)); + // Prefer standalone files first, starting with raw forks + FSNode fsNode = path.getChild(fileName + ".rsrc"); if (fsNode.exists() && !fsNode.isDirectory()) { SeekableReadStream *stream = fsNode.createReadStream(); - if (loadFromAppleDouble(*stream)) { - _baseFileName = filename; + if (loadFromRawFork(*stream)) { + _baseFileName = fileName; return true; } delete stream; } - // Check .bin too - fsNode = path.getChild(filename + ".bin"); + // Then try for AppleDouble using Apple's naming + fsNode = path.getChild(constructAppleDoubleName(fileName)); if (fsNode.exists() && !fsNode.isDirectory()) { SeekableReadStream *stream = fsNode.createReadStream(); - if (loadFromMacBinary(*stream)) { - _baseFileName = filename; + if (loadFromAppleDouble(*stream)) { + _baseFileName = fileName; return true; } delete stream; } - // Maybe we have a dumped fork? - fsNode = path.getChild(filename + ".rsrc"); + // Check .bin for MacBinary next + fsNode = path.getChild(fileName + ".bin"); if (fsNode.exists() && !fsNode.isDirectory()) { SeekableReadStream *stream = fsNode.createReadStream(); - if (loadFromRawFork(*stream)) { - _baseFileName = filename; + if (loadFromMacBinary(*stream)) { + _baseFileName = fileName; return true; } delete stream; } - // Fine, what about just the data fork? - fsNode = path.getChild(filename); + // As a last resort, see if just the data fork exists + fsNode = path.getChild(fileName); if (fsNode.exists() && !fsNode.isDirectory()) { SeekableReadStream *stream = fsNode.createReadStream(); - _baseFileName = filename; + _baseFileName = fileName; + // FIXME: Is this really needed? if (isMacBinary(*stream)) { - stream->seek(0, SEEK_SET); + stream->seek(0); if (loadFromMacBinary(*stream)) return true; } - stream->seek(0, SEEK_SET); + stream->seek(0); _stream = stream; return true; } @@ -238,22 +240,22 @@ bool MacResManager::open(FSNode path, String filename) { return false; } -bool MacResManager::exists(const String &filename) { +bool MacResManager::exists(const String &fileName) { // Try the file name by itself - if (Common::File::exists(filename)) + if (File::exists(fileName)) return true; // Try the .rsrc extension - if (Common::File::exists(filename + ".rsrc")) + if (File::exists(fileName + ".rsrc")) return true; // Check if we have a MacBinary file - Common::File tempFile; - if (tempFile.open(filename + ".bin") && isMacBinary(tempFile)) + File tempFile; + if (tempFile.open(fileName + ".bin") && isMacBinary(tempFile)) return true; // Check if we have an AppleDouble file - if (tempFile.open(constructAppleDoubleName(filename)) && tempFile.readUint32BE() == 0x00051607) + if (tempFile.open(constructAppleDoubleName(fileName)) && tempFile.readUint32BE() == 0x00051607) return true; return false; @@ -480,10 +482,10 @@ SeekableReadStream *MacResManager::getResource(uint32 typeID, uint16 resID) { return _stream->readStream(len); } -SeekableReadStream *MacResManager::getResource(const String &filename) { +SeekableReadStream *MacResManager::getResource(const String &fileName) { for (uint32 i = 0; i < _resMap.numTypes; i++) { for (uint32 j = 0; j < _resTypes[i].items; j++) { - if (_resLists[i][j].nameOffset != -1 && filename.equalsIgnoreCase(_resLists[i][j].name)) { + if (_resLists[i][j].nameOffset != -1 && fileName.equalsIgnoreCase(_resLists[i][j].name)) { _stream->seek(_dataOffset + _resLists[i][j].dataOffset); uint32 len = _stream->readUint32BE(); @@ -499,13 +501,13 @@ SeekableReadStream *MacResManager::getResource(const String &filename) { return 0; } -SeekableReadStream *MacResManager::getResource(uint32 typeID, const String &filename) { +SeekableReadStream *MacResManager::getResource(uint32 typeID, const String &fileName) { for (uint32 i = 0; i < _resMap.numTypes; i++) { if (_resTypes[i].id != typeID) continue; for (uint32 j = 0; j < _resTypes[i].items; j++) { - if (_resLists[i][j].nameOffset != -1 && filename.equalsIgnoreCase(_resLists[i][j].name)) { + if (_resLists[i][j].nameOffset != -1 && fileName.equalsIgnoreCase(_resLists[i][j].name)) { _stream->seek(_dataOffset + _resLists[i][j].dataOffset); uint32 len = _stream->readUint32BE(); @@ -574,7 +576,7 @@ void MacResManager::readMap() { } } -Common::String MacResManager::constructAppleDoubleName(Common::String name) { +String MacResManager::constructAppleDoubleName(String name) { // Insert "._" before the last portion of a path name for (int i = name.size() - 1; i >= 0; i--) { if (i == 0) { diff --git a/common/macresman.h b/common/macresman.h index ed74da9cc6..cca6592f21 100644 --- a/common/macresman.h +++ b/common/macresman.h @@ -54,27 +54,32 @@ public: /** * Open a Mac data/resource fork pair. + * + * This uses SearchMan to find the data/resource forks. This should only be used + * from inside an engine. + * * @param filename The base file name of the file * @note This will check for the raw resource fork, MacBinary, and AppleDouble formats. * @return True on success */ - bool open(String filename); + bool open(const String &fileName); /** * Open a Mac data/resource fork pair. + * * @param path The path that holds the forks * @param filename The base file name of the file * @note This will check for the raw resource fork, MacBinary, and AppleDouble formats. * @return True on success */ - bool open(FSNode path, String filename); + bool open(const FSNode &path, const String &fileName); /** * See if a Mac data/resource fork pair exists. * @param filename The base file name of the file * @return True if either a data fork or resource fork with this name exists */ - static bool exists(const String &filename); + static bool exists(const String &fileName); /** * Close the Mac data/resource fork pair. @@ -94,12 +99,6 @@ public: bool hasResFork() const; /** - * Check if the given stream is in the MacBinary format. - * @param stream The stream we're checking - */ - static bool isMacBinary(SeekableReadStream &stream); - - /** * Read resource from the MacBinary file * @param typeID FourCC of the type * @param resID Resource ID to fetch @@ -176,7 +175,13 @@ private: bool loadFromMacBinary(SeekableReadStream &stream); bool loadFromAppleDouble(SeekableReadStream &stream); - static Common::String constructAppleDoubleName(Common::String name); + static String constructAppleDoubleName(String name); + + /** + * Check if the given stream is in the MacBinary format. + * @param stream The stream we're checking + */ + static bool isMacBinary(SeekableReadStream &stream); enum { kResForkNone = 0, diff --git a/common/math.h b/common/math.h index b85ec0d22a..ba137101e4 100644 --- a/common/math.h +++ b/common/math.h @@ -52,14 +52,6 @@ #endif #endif -#ifndef M_SQRT1_2 - #define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ -#endif - -#ifndef M_PI - #define M_PI 3.14159265358979323846 -#endif - #ifndef FLT_MIN #define FLT_MIN 1E-37 #endif diff --git a/common/memstream.h b/common/memstream.h index 260fb64d84..7fa6500753 100644 --- a/common/memstream.h +++ b/common/memstream.h @@ -89,8 +89,9 @@ public: */ class MemoryWriteStream : public WriteStream { private: - byte *_ptr; const uint32 _bufSize; +protected: + byte *_ptr; uint32 _pos; bool _err; public: @@ -117,6 +118,40 @@ public: }; /** + * MemoryWriteStream subclass with ability to set stream position indicator. + */ +class SeekableMemoryWriteStream : public MemoryWriteStream { +private: + byte *_ptrOrig; +public: + SeekableMemoryWriteStream(byte *buf, uint32 len) : MemoryWriteStream(buf, len), _ptrOrig(buf) {} + uint32 seek(uint32 offset, int whence = SEEK_SET) { + switch (whence) { + case SEEK_END: + // SEEK_END works just like SEEK_SET, only 'reversed', + // i.e. from the end. + offset = size() + offset; + // Fall through + case SEEK_SET: + _ptr = _ptrOrig + offset; + _pos = offset; + break; + case SEEK_CUR: + _ptr += offset; + _pos += offset; + break; + } + // Post-Condition + if (_pos > size()) { + _pos = size(); + _ptr = _ptrOrig + _pos; + } + return _pos; + } +}; + + +/** * A sort of hybrid between MemoryWriteStream and Array classes. A stream * that grows as it's written to. */ diff --git a/common/module.mk b/common/module.mk index d96b11ee40..1b34d151d0 100644 --- a/common/module.mk +++ b/common/module.mk @@ -2,7 +2,6 @@ MODULE := common MODULE_OBJS := \ archive.o \ - config-file.o \ config-manager.o \ coroutines.o \ dcl.o \ @@ -10,12 +9,12 @@ MODULE_OBJS := \ error.o \ EventDispatcher.o \ EventMapper.o \ - EventRecorder.o \ file.o \ fs.o \ gui_options.o \ hashmap.o \ iff_container.o \ + ini-file.o \ installshield_cab.o \ language.o \ localization.o \ @@ -51,5 +50,10 @@ MODULE_OBJS += \ rdft.o \ sinetables.o +ifdef ENABLE_EVENTRECORDER +MODULE_OBJS += \ + recorderfile.o +endif + # Include common rules include $(srcdir)/rules.mk diff --git a/common/random.cpp b/common/random.cpp index fd75534c44..de1269b485 100644 --- a/common/random.cpp +++ b/common/random.cpp @@ -21,7 +21,7 @@ #include "common/random.h" #include "common/system.h" -#include "common/EventRecorder.h" +#include "gui/EventRecorder.h" namespace Common { @@ -30,13 +30,12 @@ RandomSource::RandomSource(const String &name) { // Use system time as RNG seed. Normally not a good idea, if you are using // a RNG for security purposes, but good enough for our purposes. assert(g_system); - uint32 seed = g_system->getMillis(); - setSeed(seed); - // Register this random source with the event recorder. This may end - // up querying or resetting the current seed, so we must call it - // *after* the initial seed has been set. - g_eventRec.registerRandomSource(*this, name); +#ifdef ENABLE_EVENTRECORDER + setSeed(g_eventRec.getRandomSeed(name)); +#else + setSeed(g_system->getMillis()); +#endif } void RandomSource::setSeed(uint32 seed) { diff --git a/common/recorderfile.cpp b/common/recorderfile.cpp new file mode 100644 index 0000000000..d08bc599f1 --- /dev/null +++ b/common/recorderfile.cpp @@ -0,0 +1,714 @@ +/* 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 "gui/EventRecorder.h" +#include "common/md5.h" +#include "common/recorderfile.h" +#include "common/savefile.h" +#include "common/bufferedstream.h" +#include "graphics/thumbnail.h" +#include "graphics/surface.h" +#include "graphics/scaler.h" + +#define RECORD_VERSION 1 + +namespace Common { + +PlaybackFile::PlaybackFile() : _tmpRecordFile(_tmpBuffer, kRecordBuffSize), _tmpPlaybackFile(_tmpBuffer, kRecordBuffSize) { + _readStream = NULL; + _writeStream = NULL; + _screenshotsFile = NULL; + _mode = kClosed; + + _recordFile = 0; + _headerDumped = false; + _recordCount = 0; + _eventsSize = 0; + memset(_tmpBuffer, 1, kRecordBuffSize); +} + +PlaybackFile::~PlaybackFile() { + close(); +} + +bool PlaybackFile::openWrite(const String &fileName) { + close(); + _header.fileName = fileName; + _writeStream = wrapBufferedWriteStream(g_system->getSavefileManager()->openForSaving(fileName), 128 * 1024); + _headerDumped = false; + _recordCount = 0; + if (_writeStream == NULL) { + return false; + } + _mode = kWrite; + return true; +} + +bool PlaybackFile::openRead(const String &fileName) { + close(); + _header.fileName = fileName; + _eventsSize = 0; + _tmpPlaybackFile.seek(0); + _readStream = wrapBufferedSeekableReadStream(g_system->getSavefileManager()->openForLoading(fileName), 128 * 1024, DisposeAfterUse::YES); + if (_readStream == NULL) { + debugC(1, kDebugLevelEventRec, "playback:action=\"Load File\" result=fail reason=\"file %s not found\"", fileName.c_str()); + return false; + } + if (!parseHeader()) { + debugC(1, kDebugLevelEventRec, "playback:action=\"Load File\" result=fail reason=\"header parsing failed\""); + return false; + } + _screenshotsFile = wrapBufferedWriteStream(g_system->getSavefileManager()->openForSaving("screenshots.bin"), 128 * 1024); + debugC(1, kDebugLevelEventRec, "playback:action=\"Load File\" result=success"); + _mode = kRead; + return true; +} + +void PlaybackFile::close() { + delete _readStream; + _readStream = NULL; + if (_writeStream != NULL) { + dumpRecordsToFile(); + _writeStream->finalize(); + delete _writeStream; + _writeStream = NULL; + updateHeader(); + } + if (_screenshotsFile != NULL) { + _screenshotsFile->finalize(); + delete _screenshotsFile; + _screenshotsFile = NULL; + } + for (HashMap<String, SaveFileBuffer>::iterator i = _header.saveFiles.begin(); i != _header.saveFiles.end(); ++i) { + free(i->_value.buffer); + } + _header.saveFiles.clear(); + _mode = kClosed; +} + +bool PlaybackFile::parseHeader() { + PlaybackFileHeader result; + ChunkHeader nextChunk; + _playbackParseState = kFileStateCheckFormat; + if (!readChunkHeader(nextChunk)) { + _playbackParseState = kFileStateError; + return false; + } + while ((_playbackParseState != kFileStateDone) && (_playbackParseState != kFileStateError)) { + if (processChunk(nextChunk)) { + if (!readChunkHeader(nextChunk)) { + warning("Error in header parsing"); + _playbackParseState = kFileStateError; + } + } + } + return _playbackParseState == kFileStateDone; +} + +bool PlaybackFile::checkPlaybackFileVersion() { + uint32 version; + version = _readStream->readUint32LE(); + if (version != RECORD_VERSION) { + warning("Incorrect playback file version. Expected version %d, but got %d.", RECORD_VERSION, version); + return false; + } + return true; +} + + +String PlaybackFile::readString(int len) { + String result; + char buf[50]; + int readSize = 49; + while (len > 0) { + if (len <= 49) { + readSize = len; + } + _readStream->read(buf, readSize); + buf[readSize] = 0; + result += buf; + len -= readSize; + } + return result; +} + +bool PlaybackFile::readChunkHeader(PlaybackFile::ChunkHeader &nextChunk) { + nextChunk.id = (FileTag)_readStream->readUint32LE(); + nextChunk.len = _readStream->readUint32LE(); + return !_readStream->err() && !_readStream->eos(); +} + +bool PlaybackFile::processChunk(ChunkHeader &nextChunk) { + switch (_playbackParseState) { + case kFileStateCheckFormat: + if (nextChunk.id == kFormatIdTag) { + _playbackParseState = kFileStateCheckVersion; + } else { + warning("Unknown playback file signature"); + _playbackParseState = kFileStateError; + } + break; + case kFileStateCheckVersion: + if ((nextChunk.id == kVersionTag) && checkPlaybackFileVersion()) { + _playbackParseState = kFileStateSelectSection; + } else { + _playbackParseState = kFileStateError; + } + break; + case kFileStateSelectSection: + switch (nextChunk.id) { + case kHeaderSectionTag: + _playbackParseState = kFileStateProcessHeader; + break; + case kHashSectionTag: + _playbackParseState = kFileStateProcessHash; + break; + case kRandomSectionTag: + _playbackParseState = kFileStateProcessRandom; + break; + case kEventTag: + case kScreenShotTag: + _readStream->seek(-8, SEEK_CUR); + _playbackParseState = kFileStateDone; + return false; + case kSaveTag: + _playbackParseState = kFileStateProcessSave; + break; + case kSettingsSectionTag: + _playbackParseState = kFileStateProcessSettings; + warning("Loading record header"); + break; + default: + _readStream->skip(nextChunk.len); + break; + } + break; + case kFileStateProcessSave: + if (nextChunk.id == kSaveRecordTag) { + readSaveRecord(); + } else { + _playbackParseState = kFileStateSelectSection; + return false; + } + break; + case kFileStateProcessHeader: + switch (nextChunk.id) { + case kAuthorTag: + _header.author = readString(nextChunk.len); + break; + case kCommentsTag: + _header.notes = readString(nextChunk.len); + break; + case kNameTag: + _header.name = readString(nextChunk.len); + break; + default: + _playbackParseState = kFileStateSelectSection; + return false; + } + break; + case kFileStateProcessHash: + if (nextChunk.id == kHashRecordTag) { + readHashMap(nextChunk); + } else { + _playbackParseState = kFileStateSelectSection; + return false; + } + break; + case kFileStateProcessRandom: + if (nextChunk.id == kRandomRecordTag) { + processRndSeedRecord(nextChunk); + } else { + _playbackParseState = kFileStateSelectSection; + return false; + } + break; + case kFileStateProcessSettings: + if (nextChunk.id == kSettingsRecordTag) { + if (!processSettingsRecord()) { + _playbackParseState = kFileStateError; + return false; + } + } else { + _playbackParseState = kFileStateSelectSection; + return false; + } + break; + default: + return false; + } + return true; +} + +void PlaybackFile::returnToChunkHeader() { + _readStream->seek(-8, SEEK_CUR); +} + +void PlaybackFile::readHashMap(ChunkHeader chunk) { + String hashName = readString(chunk.len - 32); + String hashMd5 = readString(32); + _header.hashRecords[hashName] = hashMd5; +} + +void PlaybackFile::processRndSeedRecord(ChunkHeader chunk) { + String randomSourceName = readString(chunk.len - 4); + uint32 randomSourceSeed = _readStream->readUint32LE(); + _header.randomSourceRecords[randomSourceName] = randomSourceSeed; +} + +bool PlaybackFile::processSettingsRecord() { + ChunkHeader keyChunk; + if (!readChunkHeader(keyChunk) || (keyChunk.id != kSettingsRecordKeyTag)) { + warning("Invalid format of settings section"); + return false; + } + String key = readString(keyChunk.len); + ChunkHeader valueChunk; + if (!readChunkHeader(valueChunk) || (valueChunk.id != kSettingsRecordValueTag)) { + warning("Invalid format of settings section"); + return false; + } + String value = readString(valueChunk.len); + _header.settingsRecords[key] = value; + return true; +} + + +bool PlaybackFile::readSaveRecord() { + ChunkHeader fileNameChunk; + if (!readChunkHeader(fileNameChunk) || (fileNameChunk.id != kSaveRecordNameTag)) { + warning("Invalid format of save section"); + return false; + } + String fileName = readString(fileNameChunk.len); + ChunkHeader saveBufferChunk; + if (!readChunkHeader(saveBufferChunk) || (saveBufferChunk.id != kSaveRecordBufferTag)) { + warning("Invalid format of save section"); + return false; + } + SaveFileBuffer buf; + buf.size = saveBufferChunk.len; + buf.buffer = (byte *)malloc(saveBufferChunk.len); + _readStream->read(buf.buffer, buf.size); + _header.saveFiles[fileName] = buf; + debugC(1, kDebugLevelEventRec, "playback:action=\"Load save file\" filename=%s len=%d", fileName.c_str(), buf.size); + return true; +} + + + +RecorderEvent PlaybackFile::getNextEvent() { + assert(_mode == kRead); + if (isEventsBufferEmpty()) { + PlaybackFile::ChunkHeader header; + header.id = kFormatIdTag; + while (header.id != kEventTag) { + if (!readChunkHeader(header) || _readStream->eos()) { + break; + } + switch (header.id) { + case kEventTag: + readEventsToBuffer(header.len); + break; + case kScreenShotTag: + _readStream->seek(-4, SEEK_CUR); + header.len = _readStream->readUint32BE(); + _readStream->skip(header.len-8); + break; + case kMD5Tag: + checkRecordedMD5(); + break; + default: + _readStream->skip(header.len); + break; + } + } + } + RecorderEvent result; + readEvent(result); + return result; +} + +bool PlaybackFile::isEventsBufferEmpty() { + return (uint32)_tmpPlaybackFile.pos() == _eventsSize; +} + +void PlaybackFile::readEvent(RecorderEvent& event) { + event.recordedtype = (RecorderEventType)_tmpPlaybackFile.readByte(); + switch (event.recordedtype) { + case kRecorderEventTypeTimer: + event.time = _tmpPlaybackFile.readUint32LE(); + break; + case kRecorderEventTypeNormal: + event.type = (EventType)_tmpPlaybackFile.readUint32LE(); + switch (event.type) { + case EVENT_KEYDOWN: + case EVENT_KEYUP: + event.time = _tmpPlaybackFile.readUint32LE(); + event.kbd.keycode = (KeyCode)_tmpPlaybackFile.readSint32LE(); + event.kbd.ascii = _tmpPlaybackFile.readUint16LE(); + event.kbd.flags = _tmpPlaybackFile.readByte(); + break; + case EVENT_MOUSEMOVE: + case EVENT_LBUTTONDOWN: + case EVENT_LBUTTONUP: + case EVENT_RBUTTONDOWN: + case EVENT_RBUTTONUP: + case EVENT_WHEELUP: + case EVENT_WHEELDOWN: + case EVENT_MBUTTONDOWN: + case EVENT_MBUTTONUP: + event.time = _tmpPlaybackFile.readUint32LE(); + event.mouse.x = _tmpPlaybackFile.readSint16LE(); + event.mouse.y = _tmpPlaybackFile.readSint16LE(); + break; + default: + event.time = _tmpPlaybackFile.readUint32LE(); + break; + } + break; + } + event.synthetic = true; +} + +void PlaybackFile::readEventsToBuffer(uint32 size) { + _readStream->read(_tmpBuffer, size); + _tmpPlaybackFile.seek(0); + _eventsSize = size; +} + +void PlaybackFile::saveScreenShot(Graphics::Surface &screen, byte md5[16]) { + dumpRecordsToFile(); + _writeStream->writeUint32LE(kMD5Tag); + _writeStream->writeUint32LE(16); + _writeStream->write(md5, 16); + Graphics::saveThumbnail(*_writeStream, screen); +} + +void PlaybackFile::dumpRecordsToFile() { + if (!_headerDumped) { + dumpHeaderToFile(); + _headerDumped = true; + } + if (_recordCount == 0) { + return; + } + _writeStream->writeUint32LE(kEventTag); + _writeStream->writeUint32LE(_tmpRecordFile.pos()); + _writeStream->write(_tmpBuffer, _tmpRecordFile.pos()); + _tmpRecordFile.seek(0); + _recordCount = 0; +} + +void PlaybackFile::dumpHeaderToFile() { + _writeStream->writeUint32LE(kFormatIdTag); + // Specify size for first tag as NULL since we cannot calculate + // size of the file at time of the header dumping + _writeStream->writeUint32LE(0); + _writeStream->writeUint32LE(kVersionTag); + _writeStream->writeUint32LE(4); + _writeStream->writeUint32LE(RECORD_VERSION); + writeHeaderSection(); + writeGameHash(); + writeRandomRecords(); + writeGameSettings(); + writeSaveFilesSection(); +} + +void PlaybackFile::writeHeaderSection() { + uint32 headerSize = 0; + if (!_header.author.empty()) { + headerSize = _header.author.size() + 8; + } + if (!_header.notes.empty()) { + headerSize += _header.notes.size() + 8; + } + if (!_header.name.empty()) { + headerSize += _header.name.size() + 8; + } + if (headerSize == 0) { + return; + } + _writeStream->writeUint32LE(kHeaderSectionTag); + _writeStream->writeUint32LE(headerSize); + if (!_header.author.empty()) { + _writeStream->writeUint32LE(kAuthorTag); + _writeStream->writeUint32LE(_header.author.size()); + _writeStream->writeString(_header.author); + } + if (!_header.notes.empty()) { + _writeStream->writeUint32LE(kCommentsTag); + _writeStream->writeUint32LE(_header.notes.size()); + _writeStream->writeString(_header.notes); + } + if (!_header.name.empty()) { + _writeStream->writeUint32LE(kNameTag); + _writeStream->writeUint32LE(_header.name.size()); + _writeStream->writeString(_header.name); + } +} + +void PlaybackFile::writeGameHash() { + uint32 hashSectionSize = 0; + for (StringMap::iterator i = _header.hashRecords.begin(); i != _header.hashRecords.end(); ++i) { + hashSectionSize = hashSectionSize + i->_key.size() + i->_value.size() + 8; + } + if (_header.hashRecords.size() == 0) { + return; + } + _writeStream->writeUint32LE(kHashSectionTag); + _writeStream->writeUint32LE(hashSectionSize); + for (StringMap::iterator i = _header.hashRecords.begin(); i != _header.hashRecords.end(); ++i) { + _writeStream->writeUint32LE(kHashRecordTag); + _writeStream->writeUint32LE(i->_key.size() + i->_value.size()); + _writeStream->writeString(i->_key); + _writeStream->writeString(i->_value); + } +} + +void PlaybackFile::writeRandomRecords() { + uint32 randomSectionSize = 0; + for (RandomSeedsDictionary::iterator i = _header.randomSourceRecords.begin(); i != _header.randomSourceRecords.end(); ++i) { + randomSectionSize = randomSectionSize + i->_key.size() + 12; + } + if (_header.randomSourceRecords.size() == 0) { + return; + } + _writeStream->writeUint32LE(kRandomSectionTag); + _writeStream->writeUint32LE(randomSectionSize); + for (RandomSeedsDictionary::iterator i = _header.randomSourceRecords.begin(); i != _header.randomSourceRecords.end(); ++i) { + _writeStream->writeUint32LE(kRandomRecordTag); + _writeStream->writeUint32LE(i->_key.size() + 4); + _writeStream->writeString(i->_key); + _writeStream->writeUint32LE(i->_value); + } +} + +void PlaybackFile::writeEvent(const RecorderEvent &event) { + assert(_mode == kWrite); + _recordCount++; + _tmpRecordFile.writeByte(event.recordedtype); + switch (event.recordedtype) { + case kRecorderEventTypeTimer: + _tmpRecordFile.writeUint32LE(event.time); + break; + case kRecorderEventTypeNormal: + _tmpRecordFile.writeUint32LE((uint32)event.type); + switch(event.type) { + case EVENT_KEYDOWN: + case EVENT_KEYUP: + _tmpRecordFile.writeUint32LE(event.time); + _tmpRecordFile.writeSint32LE(event.kbd.keycode); + _tmpRecordFile.writeUint16LE(event.kbd.ascii); + _tmpRecordFile.writeByte(event.kbd.flags); + break; + case EVENT_MOUSEMOVE: + case EVENT_LBUTTONDOWN: + case EVENT_LBUTTONUP: + case EVENT_RBUTTONDOWN: + case EVENT_RBUTTONUP: + case EVENT_WHEELUP: + case EVENT_WHEELDOWN: + case EVENT_MBUTTONDOWN: + case EVENT_MBUTTONUP: + _tmpRecordFile.writeUint32LE(event.time); + _tmpRecordFile.writeSint16LE(event.mouse.x); + _tmpRecordFile.writeSint16LE(event.mouse.y); + break; + default: + _tmpRecordFile.writeUint32LE(event.time); + break; + } + break; + } + if (_recordCount == kMaxBufferedRecords) { + dumpRecordsToFile(); + } +} + +void PlaybackFile::writeGameSettings() { + _writeStream->writeUint32LE(kSettingsSectionTag); + uint32 settingsSectionSize = 0; + for (StringMap::iterator i = _header.settingsRecords.begin(); i != _header.settingsRecords.end(); ++i) { + settingsSectionSize += i->_key.size() + i->_value.size() + 24; + } + _writeStream->writeUint32LE(settingsSectionSize); + for (StringMap::iterator i = _header.settingsRecords.begin(); i != _header.settingsRecords.end(); ++i) { + _writeStream->writeUint32LE(kSettingsRecordTag); + _writeStream->writeUint32LE(i->_key.size() + i->_value.size() + 16); + _writeStream->writeUint32LE(kSettingsRecordKeyTag); + _writeStream->writeUint32LE(i->_key.size()); + _writeStream->writeString(i->_key); + _writeStream->writeUint32LE(kSettingsRecordValueTag); + _writeStream->writeUint32LE(i->_value.size()); + _writeStream->writeString(i->_value); + } +} + +int PlaybackFile::getScreensCount() { + if (_mode != kRead) { + return 0; + } + _readStream->seek(0); + int result = 0; + while (skipToNextScreenshot()) { + uint32 size = _readStream->readUint32BE(); + _readStream->skip(size-8); + ++result; + } + return result; +} + +bool PlaybackFile::skipToNextScreenshot() { + while (true) { + FileTag id = (FileTag)_readStream->readUint32LE(); + if (_readStream->eos()) { + break; + } + if (id == kScreenShotTag) { + return true; + } + else { + uint32 size = _readStream->readUint32LE(); + _readStream->skip(size); + } + } + return false; +} + +Graphics::Surface *PlaybackFile::getScreenShot(int number) { + if (_mode != kRead) { + return NULL; + } + _readStream->seek(0); + int screenCount = 1; + while (skipToNextScreenshot()) { + if (screenCount == number) { + screenCount++; + _readStream->seek(-4, SEEK_CUR); + return Graphics::loadThumbnail(*_readStream); + } else { + uint32 size = _readStream->readUint32BE(); + _readStream->skip(size-8); + screenCount++; + } + } + return NULL; +} + +void PlaybackFile::updateHeader() { + if (_mode == kWrite) { + _readStream = g_system->getSavefileManager()->openForLoading(_header.fileName); + } + _readStream->seek(0); + skipHeader(); + String tmpFilename = "_" + _header.fileName; + _writeStream = g_system->getSavefileManager()->openForSaving(tmpFilename); + dumpHeaderToFile(); + uint32 readedSize = 0; + do { + readedSize = _readStream->read(_tmpBuffer, kRecordBuffSize); + _writeStream->write(_tmpBuffer, readedSize); + } while (readedSize != 0); + delete _writeStream; + _writeStream = NULL; + delete _readStream; + _readStream = NULL; + g_system->getSavefileManager()->removeSavefile(_header.fileName); + g_system->getSavefileManager()->renameSavefile(tmpFilename, _header.fileName); + if (_mode == kRead) { + openRead(_header.fileName); + } +} + +void PlaybackFile::skipHeader() { + while (true) { + uint32 id = _readStream->readUint32LE(); + if (_readStream->eos()) { + break; + } + if ((id == kScreenShotTag) || (id == kEventTag) || (id == kMD5Tag)) { + _readStream->seek(-4, SEEK_CUR); + return; + } + else { + uint32 size = _readStream->readUint32LE(); + _readStream->skip(size); + } + } +} + +void PlaybackFile::addSaveFile(const String &fileName, InSaveFile *saveStream) { + uint oldPos = saveStream->pos(); + saveStream->seek(0); + _header.saveFiles[fileName].buffer = (byte *)malloc(saveStream->size()); + _header.saveFiles[fileName].size = saveStream->size(); + saveStream->read(_header.saveFiles[fileName].buffer, saveStream->size()); + saveStream->seek(oldPos); +} + +void PlaybackFile::writeSaveFilesSection() { + uint size = 0; + for (HashMap<String, SaveFileBuffer>::iterator i = _header.saveFiles.begin(); i != _header.saveFiles.end(); ++i) { + size += i->_value.size + i->_key.size() + 24; + } + if (size == 0) { + return; + } + _writeStream->writeSint32LE(kSaveTag); + _writeStream->writeSint32LE(size); + for (HashMap<String, SaveFileBuffer>::iterator i = _header.saveFiles.begin(); i != _header.saveFiles.end(); ++i) { + _writeStream->writeSint32LE(kSaveRecordTag); + _writeStream->writeSint32LE(i->_key.size() + i->_value.size + 16); + _writeStream->writeSint32LE(kSaveRecordNameTag); + _writeStream->writeSint32LE(i->_key.size()); + _writeStream->writeString(i->_key); + _writeStream->writeSint32LE(kSaveRecordBufferTag); + _writeStream->writeSint32LE(i->_value.size); + _writeStream->write(i->_value.buffer, i->_value.size); + } +} + + +void PlaybackFile::checkRecordedMD5() { + uint8 currentMD5[16]; + uint8 savedMD5[16]; + Graphics::Surface screen; + _readStream->read(savedMD5, 16); + if (!g_eventRec.grabScreenAndComputeMD5(screen, currentMD5)) { + return; + } + uint32 seconds = g_system->getMillis(true) / 1000; + String screenTime = String::format("%.2d:%.2d:%.2d", seconds / 3600 % 24, seconds / 60 % 60, seconds % 60); + if (memcmp(savedMD5, currentMD5, 16) != 0) { + debugC(1, kDebugLevelEventRec, "playback:action=\"Check screenshot\" time=%s result = fail", screenTime.c_str()); + warning("Recorded and current screenshots are different"); + } else { + debugC(1, kDebugLevelEventRec, "playback:action=\"Check screenshot\" time=%s result = success", screenTime.c_str()); + } + Graphics::saveThumbnail(*_screenshotsFile, screen); + screen.free(); +} + + +} diff --git a/common/recorderfile.h b/common/recorderfile.h new file mode 100644 index 0000000000..1c95e5a915 --- /dev/null +++ b/common/recorderfile.h @@ -0,0 +1,180 @@ +/* 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 COMMON_RECORDERFILE_H +#define COMMON_RECORDERFILE_H + +#include "common/scummsys.h" +#include "common/events.h" +#include "common/mutex.h" +#include "common/memstream.h" +#include "common/config-manager.h" +#include "common/savefile.h" + +//capacity of records buffer +#define kMaxBufferedRecords 10000 +#define kRecordBuffSize sizeof(RecorderEvent) * kMaxBufferedRecords + +namespace Common { + +enum RecorderEventType { + kRecorderEventTypeNormal = 0, + kRecorderEventTypeTimer = 1 +}; + +struct RecorderEvent : Event { + RecorderEventType recordedtype; + uint32 time; +}; + + + +class PlaybackFile { + typedef HashMap<String, uint32, IgnoreCase_Hash, IgnoreCase_EqualTo> RandomSeedsDictionary; + enum fileMode { + kRead = 0, + kWrite = 1, + kClosed = 2 + }; + enum PlaybackFileState { + kFileStateCheckFormat, + kFileStateCheckVersion, + kFileStateProcessHash, + kFileStateProcessHeader, + kFileStateProcessRandom, + kFileStateSelectSection, + kFileStateProcessSettings, + kFileStateProcessSave, + kFileStateDone, + kFileStateError + }; + enum FileTag { + kFormatIdTag = MKTAG('P','B','C','K'), + kVersionTag = MKTAG('V','E','R','S'), + kHeaderSectionTag = MKTAG('H','E','A','D'), + kHashSectionTag = MKTAG('H','A','S','H'), + kRandomSectionTag = MKTAG('R','A','N','D'), + kEventTag = MKTAG('E','V','N','T'), + kScreenShotTag = MKTAG('B','M','H','T'), + kSettingsSectionTag = MKTAG('S','E','T','T'), + kAuthorTag = MKTAG('H','A','U','T'), + kCommentsTag = MKTAG('H','C','M','T'), + kNameTag = MKTAG('H','N','A','M'), + kHashRecordTag = MKTAG('H','R','C','D'), + kRandomRecordTag = MKTAG('R','R','C','D'), + kSettingsRecordTag = MKTAG('S','R','E','C'), + kSettingsRecordKeyTag = MKTAG('S','K','E','Y'), + kSettingsRecordValueTag = MKTAG('S','V','A','L'), + kSaveTag = MKTAG('S','A','V','E'), + kSaveRecordTag = MKTAG('R','S','A','V'), + kSaveRecordNameTag = MKTAG('S','N','A','M'), + kSaveRecordBufferTag = MKTAG('S','B','U','F'), + kMD5Tag = MKTAG('M','D','5',' ') + }; + struct ChunkHeader { + FileTag id; + uint32 len; + }; +public: + struct SaveFileBuffer { + byte *buffer; + uint32 size; + }; + struct PlaybackFileHeader { + String fileName; + String author; + String name; + String notes; + String description; + StringMap hashRecords; + StringMap settingsRecords; + HashMap<String, SaveFileBuffer> saveFiles; + RandomSeedsDictionary randomSourceRecords; + }; + PlaybackFile(); + ~PlaybackFile(); + + bool openWrite(const String &fileName); + bool openRead(const String &fileName); + void close(); + + RecorderEvent getNextEvent(); + void writeEvent(const RecorderEvent &event); + + void saveScreenShot(Graphics::Surface &screen, byte md5[16]); + Graphics::Surface *getScreenShot(int number); + int getScreensCount(); + + bool isEventsBufferEmpty(); + PlaybackFileHeader &getHeader() {return _header;} + void updateHeader(); + void addSaveFile(const String &fileName, InSaveFile *saveStream); +private: + WriteStream *_recordFile; + WriteStream *_writeStream; + WriteStream *_screenshotsFile; + MemoryReadStream _tmpPlaybackFile; + SeekableReadStream *_readStream; + SeekableMemoryWriteStream _tmpRecordFile; + + fileMode _mode; + bool _headerDumped; + int _recordCount; + uint32 _eventsSize; + byte _tmpBuffer[kRecordBuffSize]; + PlaybackFileHeader _header; + PlaybackFileState _playbackParseState; + + void skipHeader(); + bool parseHeader(); + bool processChunk(ChunkHeader &nextChunk); + void returnToChunkHeader(); + + bool readSaveRecord(); + void checkRecordedMD5(); + bool readChunkHeader(ChunkHeader &nextChunk); + void processRndSeedRecord(ChunkHeader chunk); + bool processSettingsRecord(); + + bool checkPlaybackFileVersion(); + + void dumpHeaderToFile(); + void writeSaveFilesSection(); + void writeGameSettings(); + void writeHeaderSection(); + void writeGameHash(); + void writeRandomRecords(); + + void dumpRecordsToFile(); + + String readString(int len); + void readHashMap(ChunkHeader chunk); + + bool skipToNextScreenshot(); + void readEvent(RecorderEvent& event); + void readEventsToBuffer(uint32 size); + bool grabScreenAndComputeMD5(Graphics::Surface &screen, uint8 md5[16]); +}; + +} // End of namespace Common + +#endif diff --git a/common/scummsys.h b/common/scummsys.h index 291de87dc9..3e9d5ef063 100644 --- a/common/scummsys.h +++ b/common/scummsys.h @@ -144,6 +144,63 @@ #endif #endif +// The following math constants are usually defined by the system math.h header, but +// they are not part of the ANSI C++ standards and so can NOT be relied upon to be +// present i.e. when -std=c++11 is passed to GCC, enabling strict ANSI compliance. +// As we rely on these being present, we define them if they are not set. + +#ifndef M_E + #define M_E 2.7182818284590452354 /* e */ +#endif + +#ifndef M_LOG2E + #define M_LOG2E 1.4426950408889634074 /* log_2 e */ +#endif + +#ifndef M_LOG10E + #define M_LOG10E 0.43429448190325182765 /* log_10 e */ +#endif + +#ifndef M_LN2 + #define M_LN2 0.69314718055994530942 /* log_e 2 */ +#endif + +#ifndef M_LN10 + #define M_LN10 2.30258509299404568402 /* log_e 10 */ +#endif + +#ifndef M_PI + #define M_PI 3.14159265358979323846 /* pi */ +#endif + +#ifndef M_PI_2 + #define M_PI_2 1.57079632679489661923 /* pi/2 */ +#endif + +#ifndef M_PI_4 + #define M_PI_4 0.78539816339744830962 /* pi/4 */ +#endif + +#ifndef M_1_PI + #define M_1_PI 0.31830988618379067154 /* 1/pi */ +#endif + +#ifndef M_2_PI + #define M_2_PI 0.63661977236758134308 /* 2/pi */ +#endif + +#ifndef M_2_SQRTPI + #define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ +#endif + +#ifndef M_SQRT2 + #define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#endif + +#ifndef M_SQRT1_2 + #define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ +#endif + // Include our C++11 compatability header for pre-C++11 compilers. #if __cplusplus < 201103L #include "common/c++11-compat.h" diff --git a/common/str.cpp b/common/str.cpp index 5d647ee4f0..4a10792373 100644 --- a/common/str.cpp +++ b/common/str.cpp @@ -361,6 +361,25 @@ void String::deleteChar(uint32 p) { _size--; } +void String::erase(uint32 p, uint32 len) { + assert(p < _size); + + makeUnique(); + // If len == npos or p + len is over the end, remove all the way to the end + if (len == npos || p + len >= _size) { + // Delete char at p as well. So _size = (p - 1) + 1 + _size = p; + // Null terminate + _str[_size] = 0; + return; + } + + for ( ; p + len <= _size; p++) { + _str[p] = _str[p + len]; + } + _size -= len; +} + void String::clear() { decRefCount(_extern._refCount); diff --git a/common/str.h b/common/str.h index 5039130707..6b4475e1c4 100644 --- a/common/str.h +++ b/common/str.h @@ -43,6 +43,8 @@ namespace Common { * behavior in some operations. */ class String { +public: + static const uint32 npos = 0xFFFFFFFF; protected: /** * The size of the internal storage. Increasing this means less heap @@ -191,6 +193,9 @@ public: /** Remove the character at position p from the string. */ void deleteChar(uint32 p); + /** Remove all characters from position p to the p + len. If len = String::npos, removes all characters to the end */ + void erase(uint32 p, uint32 len = npos); + /** Set character c at position p, replacing the previous character there. */ void setChar(char c, uint32 p); diff --git a/common/system.cpp b/common/system.cpp index 59210544ab..d86b5b2b81 100644 --- a/common/system.cpp +++ b/common/system.cpp @@ -30,6 +30,9 @@ #include "common/taskbar.h" #include "common/updates.h" #include "common/textconsole.h" +#ifdef ENABLE_EVENTRECORDER +#include "gui/EventRecorder.h" +#endif #include "backends/audiocd/default/default-audiocd.h" #include "backends/fs/fs-factory.h" @@ -84,7 +87,7 @@ void OSystem::initBackend() { error("Backend failed to instantiate audio CD manager"); if (!_eventManager) error("Backend failed to instantiate event manager"); - if (!_timerManager) + if (!getTimerManager()) error("Backend failed to instantiate timer manager"); // TODO: We currently don't check _savefileManager, because at least @@ -152,3 +155,15 @@ Common::String OSystem::getDefaultConfigFileName() { Common::String OSystem::getSystemLanguage() const { return "en_US"; } + +Common::TimerManager *OSystem::getTimerManager() { + return _timerManager; +} + +Common::SaveFileManager *OSystem::getSavefileManager() { +#ifdef ENABLE_EVENTRECORDER + return g_eventRec.getSaveManager(_savefileManager); +#else + return _savefileManager; +#endif +} diff --git a/common/system.h b/common/system.h index 99b947d7f3..81c4bdf34e 100644 --- a/common/system.h +++ b/common/system.h @@ -890,8 +890,14 @@ public: /** @name Events and Time */ //@{ - /** Get the number of milliseconds since the program was started. */ - virtual uint32 getMillis() = 0; + /** Get the number of milliseconds since the program was started. + + @param skipRecord Skip recording of this value by event recorder. + This could be needed particularly when we are in + an on-screen GUI loop where player can pause + the recording. + */ + virtual uint32 getMillis(bool skipRecord = false) = 0; /** Delay/sleep for the specified amount of milliseconds. */ virtual void delayMillis(uint msecs) = 0; @@ -907,9 +913,7 @@ public: * Return the timer manager singleton. For more information, refer * to the TimerManager documentation. */ - inline Common::TimerManager *getTimerManager() { - return _timerManager; - } + virtual Common::TimerManager *getTimerManager(); /** * Return the event manager singleton. For more information, refer @@ -1086,9 +1090,7 @@ public: * and other modifiable persistent game data. For more information, * refer to the SaveFileManager documentation. */ - inline Common::SaveFileManager *getSavefileManager() { - return _savefileManager; - } + Common::SaveFileManager *getSavefileManager(); #if defined(USE_TASKBAR) /** diff --git a/common/util.h b/common/util.h index 4ca1c42929..392ced1ffe 100644 --- a/common/util.h +++ b/common/util.h @@ -41,10 +41,10 @@ #undef MAX #endif -template<typename T> inline T ABS (T x) { return (x>=0) ? x : -x; } -template<typename T> inline T MIN (T a, T b) { return (a<b) ? a : b; } -template<typename T> inline T MAX (T a, T b) { return (a>b) ? a : b; } -template<typename T> inline T CLIP (T v, T amin, T amax) +template<typename T> inline T ABS(T x) { return (x >= 0) ? x : -x; } +template<typename T> inline T MIN(T a, T b) { return (a < b) ? a : b; } +template<typename T> inline T MAX(T a, T b) { return (a > b) ? a : b; } +template<typename T> inline T CLIP(T v, T amin, T amax) { if (v < amin) return amin; else if (v > amax) return amax; else return v; } /** diff --git a/common/winexe.cpp b/common/winexe.cpp index 7cfc140452..877ab6baa1 100644 --- a/common/winexe.cpp +++ b/common/winexe.cpp @@ -73,7 +73,7 @@ String WinResourceID::toString() const { if (_idType == kIDTypeString) return _name; else if (_idType == kIDTypeNumerical) - return String::format("%08x", _id); + return String::format("0x%08x", _id); return ""; } diff --git a/common/winexe_ne.cpp b/common/winexe_ne.cpp index 8690f6795b..c3698d5fce 100644 --- a/common/winexe_ne.cpp +++ b/common/winexe_ne.cpp @@ -187,8 +187,8 @@ uint32 NEResources::getResourceTableOffset() { static const char *s_resTypeNames[] = { "", "cursor", "bitmap", "icon", "menu", "dialog", "string", "font_dir", "font", "accelerator", "rc_data", "msg_table", - "group_cursor", "group_icon", "version", "dlg_include", - "plug_play", "vxd", "ani_cursor", "ani_icon", "html", + "group_cursor", "group_icon", "", "", "version", "dlg_include", + "", "plug_play", "vxd", "ani_cursor", "ani_icon", "html", "manifest" }; @@ -200,9 +200,16 @@ bool NEResources::readResourceTable(uint32 offset) { return false; uint32 align = 1 << _exe->readUint16LE(); - uint16 typeID = _exe->readUint16LE(); + while (typeID != 0) { + // High bit of the type means integer type + WinResourceID type; + if (typeID & 0x8000) + type = typeID & 0x7FFF; + else + type = getResourceString(*_exe, offset + typeID); + uint16 resCount = _exe->readUint16LE(); _exe->skip(4); // reserved @@ -218,17 +225,18 @@ bool NEResources::readResourceTable(uint32 offset) { res.handle = _exe->readUint16LE(); res.usage = _exe->readUint16LE(); - res.type = typeID; + res.type = type; - if ((id & 0x8000) == 0) - res.id = getResourceString(*_exe, offset + id); - else + // High bit means integer type + if (id & 0x8000) res.id = id & 0x7FFF; + else + res.id = getResourceString(*_exe, offset + id); - if (typeID & 0x8000 && ((typeID & 0x7FFF) < ARRAYSIZE(s_resTypeNames))) + if (typeID & 0x8000 && ((typeID & 0x7FFF) < ARRAYSIZE(s_resTypeNames)) && s_resTypeNames[typeID & 0x7FFF][0] != 0) debug(2, "Found resource %s %s", s_resTypeNames[typeID & 0x7FFF], res.id.toString().c_str()); else - debug(2, "Found resource %04x %s", typeID, res.id.toString().c_str()); + debug(2, "Found resource %s %s", type.toString().c_str(), res.id.toString().c_str()); _resources.push_back(res); } @@ -257,7 +265,7 @@ String NEResources::getResourceString(SeekableReadStream &exe, uint32 offset) { return string; } -const NEResources::Resource *NEResources::findResource(uint16 type, WinResourceID id) const { +const NEResources::Resource *NEResources::findResource(const WinResourceID &type, const WinResourceID &id) const { for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it) if (it->type == type && it->id == id) return &*it; @@ -265,7 +273,7 @@ const NEResources::Resource *NEResources::findResource(uint16 type, WinResourceI return 0; } -SeekableReadStream *NEResources::getResource(uint16 type, WinResourceID id) { +SeekableReadStream *NEResources::getResource(const WinResourceID &type, const WinResourceID &id) { const Resource *res = findResource(type, id); if (!res) @@ -275,7 +283,7 @@ SeekableReadStream *NEResources::getResource(uint16 type, WinResourceID id) { return _exe->readStream(res->size); } -const Array<WinResourceID> NEResources::getIDList(uint16 type) const { +const Array<WinResourceID> NEResources::getIDList(const WinResourceID &type) const { Array<WinResourceID> idArray; for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it) diff --git a/common/winexe_ne.h b/common/winexe_ne.h index 4a1b2343df..f00941412f 100644 --- a/common/winexe_ne.h +++ b/common/winexe_ne.h @@ -34,27 +34,27 @@ class SeekableReadStream; /** The default Windows resources. */ enum NEResourceType { - kNECursor = 0x8001, - kNEBitmap = 0x8002, - kNEIcon = 0x8003, - kNEMenu = 0x8004, - kNEDialog = 0x8005, - kNEString = 0x8006, - kNEFontDir = 0x8007, - kNEFont = 0x8008, - kNEAccelerator = 0x8009, - kNERCData = 0x800A, - kNEMessageTable = 0x800B, - kNEGroupCursor = 0x800C, - kNEGroupIcon = 0x800D, - kNEVersion = 0x8010, - kNEDlgInclude = 0x8011, - kNEPlugPlay = 0x8013, - kNEVXD = 0x8014, - kNEAniCursor = 0x8015, - kNEAniIcon = 0x8016, - kNEHTML = 0x8017, - kNEManifest = 0x8018 + kNECursor = 0x01, + kNEBitmap = 0x02, + kNEIcon = 0x03, + kNEMenu = 0x04, + kNEDialog = 0x05, + kNEString = 0x06, + kNEFontDir = 0x07, + kNEFont = 0x08, + kNEAccelerator = 0x09, + kNERCData = 0x0A, + kNEMessageTable = 0x0B, + kNEGroupCursor = 0x0C, + kNEGroupIcon = 0x0D, + kNEVersion = 0x10, + kNEDlgInclude = 0x11, + kNEPlugPlay = 0x13, + kNEVXD = 0x14, + kNEAniCursor = 0x15, + kNEAniIcon = 0x16, + kNEHTML = 0x17, + kNEManifest = 0x18 }; /** @@ -81,17 +81,17 @@ public: bool loadFromEXE(SeekableReadStream *stream); /** Return a list of resources for a given type. */ - const Array<WinResourceID> getIDList(uint16 type) const; + const Array<WinResourceID> getIDList(const WinResourceID &type) const; /** Return a stream to the specified resource (or 0 if non-existent). */ - SeekableReadStream *getResource(uint16 type, WinResourceID id); + SeekableReadStream *getResource(const WinResourceID &type, const WinResourceID &id); private: /** A resource. */ struct Resource { WinResourceID id; - uint16 type; ///< Type of the resource. + WinResourceID type; ///< Type of the resource. uint32 offset; ///< Offset within the EXE. uint32 size; ///< Size of the data. @@ -112,7 +112,7 @@ private: bool readResourceTable(uint32 offset); /** Find a specific resource. */ - const Resource *findResource(uint16 type, WinResourceID id) const; + const Resource *findResource(const WinResourceID &type, const WinResourceID &id) const; /** Read a resource string. */ static String getResourceString(SeekableReadStream &exe, uint32 offset); @@ -113,6 +113,7 @@ _seq_midi=auto _sndio=auto _timidity=auto _zlib=auto +_mpeg2=auto _sparkle=auto _png=auto _theoradec=auto @@ -138,9 +139,10 @@ _build_hq_scalers=yes _enable_prof=no _global_constructors=no _bink=yes -# Default vkeybd/keymapper options +# Default vkeybd/keymapper/eventrec options _vkeybd=no _keymapper=no +_eventrec=auto # GUI translation options _translation=yes # Default platform settings @@ -816,7 +818,7 @@ Usage: $0 [OPTIONS]... Configuration: -h, --help display this help and exit - --backend=BACKEND backend to build (android, bada, dc, dingux, ds, gph, + --backend=BACKEND backend to build (android, tizen, dc, dingux, ds, gph, iphone, linuxmoto, maemo, n64, null, openpandora, ps2, psp, samsungtv, sdl, webos, wii, wince) [sdl] @@ -845,7 +847,7 @@ Fine tuning of the installation directories: Special configuration feature: --host=HOST cross-compile to target HOST (arm-linux, ...) special targets: android for Android - bada for Samsung BADA + tizen for Samsung Tizen caanoo for Caanoo dingux for Dingux dreamcast for Sega Dreamcast @@ -898,6 +900,10 @@ Optional Features: --disable-hq-scalers exclude HQ2x and HQ3x scalers --disable-translation don't build support for translated messages --disable-taskbar don't build support for taskbar and launcher integration + --enable-vkeybd build virtual keyboard support + --enable-keymapper build key mapper support + --enable-eventrecorder enable event recording functionality + --disable-eventrecorder disable event recording functionality --enable-updates build support for updates --enable-text-console use text console instead of graphical console --enable-verbose-build enable regular echoing of commands during build @@ -924,6 +930,9 @@ Optional Libraries: --with-zlib-prefix=DIR Prefix where zlib is installed (optional) --disable-zlib disable zlib (compression) support [autodetect] + --with-mpeg2-prefix=DIR Prefix where libmpeg2 is installed (optional) + --enable-mpeg2 enable mpeg2 codec for cutscenes [autodetect] + --with-opengl-prefix=DIR Prefix where OpenGL (ES) is installed (optional) --disable-opengl disable OpenGL (ES) support [autodetect] @@ -1004,6 +1013,8 @@ for ac_option in $@; do --disable-sparkle) _sparkle=no ;; --enable-nasm) _nasm=yes ;; --disable-nasm) _nasm=no ;; + --enable-mpeg2) _mpeg2=yes ;; + --disable-mpeg2) _mpeg2=no ;; --disable-png) _png=no ;; --enable-png) _png=yes ;; --disable-theoradec) _theoradec=no ;; @@ -1036,6 +1047,8 @@ for ac_option in $@; do --disable-vkeybd) _vkeybd=no ;; --enable-keymapper) _keymapper=yes ;; --disable-keymapper) _keymapper=no ;; + --enable-eventrecorder) _eventrec=yes ;; + --disable-eventrecorder) _eventrec=no ;; --enable-text-console) _text_console=yes ;; --disable-text-console) _text_console=no ;; --with-fluidsynth-prefix=*) @@ -1043,6 +1056,11 @@ for ac_option in $@; do FLUIDSYNTH_CFLAGS="-I$arg/include" FLUIDSYNTH_LIBS="-L$arg/lib" ;; + --with-mpeg2-prefix=*) + arg=`echo $ac_option | cut -d '=' -f 2` + MPEG2_CFLAGS="-I$arg/include" + MPEG2_LIBS="-L$arg/lib" + ;; --with-alsa-prefix=*) arg=`echo $ac_option | cut -d '=' -f 2` ALSA_CFLAGS="-I$arg/include" @@ -1247,16 +1265,6 @@ arm-riscos) _host_os=riscos _host_cpu=arm ;; -bada) - _host_os=bada - if test "$_debug_build" = yes; then - _host_cpu=i686 - _host_alias=i686-mingw32 - else - _host_cpu=arm - _host_alias=arm-samsung-nucleuseabi - fi - ;; caanoo) _host_os=gph-linux _host_cpu=arm @@ -1382,6 +1390,11 @@ samsungtv) _host_cpu=arm _host_alias=arm-linux-gnueabi ;; +tizen) + _host_os=tizen + _host_cpu=arm + _host_alias=arm-linux-gnueabi + ;; webos) _host_os=webos _host_cpu=arm @@ -1491,12 +1504,6 @@ android) exit 1 fi ;; -bada) - if test -z "$BADA_SDK"; then - echo "Please set BADA_SDK in your environment. export BADA_SDK=<path to Bada SDK>" - exit 1 - fi - ;; ds | gamecube | wii) if test -z "$DEVKITPRO"; then echo "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to devkitPRO>" @@ -1538,6 +1545,12 @@ psp) exit 1 fi ;; +tizen) + if test -z "$TIZEN_ROOTSTRAP"; then + echo "Please set TIZEN_ROOTSTRAP in your environment. export TIZEN_ROOTSTRAP=<path to Tizen SDK device profile>" + exit 1 + fi + ;; webos) if test -z "$WEBOS_SDK"; then echo "Please set WEBOS_SDK in your environment. export WEBOS_SDK=<path to WebOS SDK>" @@ -1731,7 +1744,7 @@ if test "$have_gcc" = yes ; then case $_host_os in # newlib-based system include files suppress non-C89 function # declarations under __STRICT_ANSI__ - amigaos* | android | bada | dreamcast | ds | gamecube | mingw* | n64 | psp | ps2 | ps3 | wii | wince ) + amigaos* | android | dreamcast | ds | gamecube | mingw* | n64 | psp | ps2 | ps3 | tizen | wii | wince ) ;; *) CXXFLAGS="$CXXFLAGS -ansi" @@ -1767,12 +1780,13 @@ echo $_use_cxx11 # However, some platforms use GNU extensions in system header files, so # for these we must not use -pedantic. case $_host_os in -android | gamecube | psp | wii | webos) +android | gamecube | psp | tizen | wii | webos) ;; *) # ICC does not support pedantic, while GCC and clang do. if test "$have_icc" = no ; then - CXXFLAGS="$CXXFLAGS -pedantic" + # We *do* want the 'long long' extension. + CXXFLAGS="$CXXFLAGS -pedantic -Wno-long-long" fi ;; esac @@ -1830,7 +1844,7 @@ esac # Determine a data type with the given length # find_type_with_size() { - for datatype in int short char long "long long" unknown; do + for datatype in int short char long "long long" __int64 "long long int" unknown; do cat > tmp_find_type_with_size.cpp << EOF typedef $datatype ac__type_sizeof_; int main() { @@ -2051,16 +2065,6 @@ case $_host_os in add_line_to_config_mk "ANDROID_SDK = $ANDROID_SDK" _seq_midi=no ;; - bada) - BADA_SDK_ROOT="`cygpath -m ${BADA_SDK}`" - add_line_to_config_mk "BADA_SDK = $BADA_SDK" - add_line_to_config_mk "BADA_SDK_ROOT = $BADA_SDK_ROOT" - - # assume dependencies have been installed in cygwin's /usr/local - CYGWIN_USR_LOCAL="`cygpath -m /usr/local`" - LDFLAGS="$LDFLAGS -L${CYGWIN_USR_LOCAL}/lib" - CXXFLAGS="$CXXFLAGS -I${CYGWIN_USR_LOCAL}/include" - ;; beos*) DEFINES="$DEFINES -DSYSTEM_NOT_SUPPORTING_D_TYPE" # Needs -lbind -lsocket for the timidity MIDI driver @@ -2176,7 +2180,7 @@ case $_host_os in # When not cross-compiling, enable large file support, but don't # care if getconf doesn't exist or doesn't recognize LFS_CFLAGS. if test -z "$_host"; then - CXXFLAGS="$CXXFLAGS $(getconf LFS_CFLAGS 2>/dev/null)" + CXXFLAGS="$CXXFLAGS `getconf LFS_CFLAGS 2>/dev/null`" fi ;; maemo) @@ -2238,6 +2242,12 @@ case $_host_os in # Needs -lbind -lsocket for the timidity MIDI driver LIBS="$LIBS -lnsl -lsocket" ;; + tizen) + add_line_to_config_mk "TIZEN_ROOTSTRAP = $TIZEN_ROOTSTRAP" + LDFLAGS="$LDFLAGS --sysroot=${TIZEN_ROOTSTRAP}" + LDFLAGS="$LDFLAGS -L${TIZEN_LIBS}/lib" + CXXFLAGS="$CXXFLAGS -I${TIZEN_LIBS}/include" + ;; webos) CXXFLAGS="$CXXFLAGS --sysroot=$WEBOS_PDK/arm-gcc/sysroot" CXXFLAGS="$CXXFLAGS -I$WEBOS_PDK/include" @@ -2316,22 +2326,6 @@ if test -n "$_host"; then arm-riscos|linupy) DEFINES="$DEFINES -DLINUPY" ;; - bada) - _unix=yes - _backend="bada" - _port_mk="backends/platform/bada/bada.mk" - if test "$_debug_build" = yes; then - _arm_asm=no - else - _arm_asm=yes - fi - _taskbar=no - _build_scalers=no - _seq_midi=no - _mt32emu=no - _timidity=no - _vkeybd=yes - ;; bfin*) ;; caanoo) @@ -2381,7 +2375,8 @@ if test -n "$_host"; then DEFINES="$DEFINES -DDISABLE_DEFAULT_SAVEFILEMANAGER" DEFINES="$DEFINES -DDISABLE_TEXT_CONSOLE" DEFINES="$DEFINES -DDISABLE_COMMAND_LINE" - if test "$_release_build" = yes; then + # Enable serial debugging output only when --enable-debug is passed + if test "$_release_build" = yes -o "$_debug_build" != yes; then DEFINES="$DEFINES -DNOSERIAL" fi _optimization_level=-O3 @@ -2644,6 +2639,18 @@ if test -n "$_host"; then _mt32emu=no _vkeybd=yes ;; + tizen) + _unix=yes + _backend="tizen" + _port_mk="backends/platform/tizen/tizen.mk" + _arm_asm=yes + _taskbar=no + _build_scalers=no + _seq_midi=no + _mt32emu=no + _timidity=no + _vkeybd=yes + ;; webos) _backend="webos" _port_mk="backends/platform/webos/webos.mk" @@ -2694,34 +2701,6 @@ case $_backend in LDFLAGS="$LDFLAGS -Wl,-z,noexecstack" INCLUDES="$INCLUDES -I$ANDROID_NDK/sources/cxx-stl/system/include" ;; - bada) - # dirent.h not available. NONSTANDARD_PORT==ensure portdefs.h is included - DEFINES="$DEFINES -DBADA -DDISABLE_STDIO_FILESTREAM -DNONSTANDARD_PORT" - DEFINES="$DEFINES -DNO_STDERR_STDOUT" - DEFINES="$DEFINES -DDISABLE_COMMAND_LINE" - INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/bada ' - INCLUDES="$INCLUDES "'-I$(BADA_SDK)/include' - INCLUDES="$INCLUDES "'-I$(BADA_SDK_ROOT)/Include' - if test "$_debug_build" = yes; then - # debug using with the simulator - CXXFLAGS="$CXXFLAGS -D_DEBUG -DSHP -DBUILD_DLL -fmessage-length=0" - else - # created a shared library for inclusion via the eclipse build - CXXFLAGS="$CXXFLAGS -DSHP" - CXXFLAGS="$CXXFLAGS -fpic" - CXXFLAGS="$CXXFLAGS -fshort-wchar" - CXXFLAGS="$CXXFLAGS -mcpu=cortex-a8" - CXXFLAGS="$CXXFLAGS -mfpu=vfpv3" - CXXFLAGS="$CXXFLAGS -mfloat-abi=hard" - CXXFLAGS="$CXXFLAGS -mlittle-endian" - CXXFLAGS="$CXXFLAGS -mthumb-interwork" - CXXFLAGS="$CXXFLAGS -Wno-psabi" - CXXFLAGS="$CXXFLAGS -fno-strict-aliasing" - CXXFLAGS="$CXXFLAGS -fno-short-enums" - fi - HOSTEXEPRE=lib - HOSTEXEEXT=.a - ;; dc) INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/dc' INCLUDES="$INCLUDES "'-isystem $(ronindir)/include' @@ -2729,7 +2708,8 @@ case $_backend in LDFLAGS="$LDFLAGS -nostartfiles" LDFLAGS="$LDFLAGS "'$(ronindir)/lib/crt0.o' LDFLAGS="$LDFLAGS "'-L$(ronindir)/lib' - if test "$_release_build" = yes; then + # Enable serial debugging output only when --enable-debug is passed + if test "$_release_build" = yes -o "$_debug_build" != yes; then LIBS="$LIBS -lronin-noserial -lm" else LIBS="$LIBS -lronin -lm" @@ -2804,6 +2784,25 @@ case $_backend in LDFLAGS="$LDFLAGS -shared" LDFLAGS="$LDFLAGS -fpic" ;; + tizen) + # dirent.h not available. NONSTANDARD_PORT==ensure portdefs.h is included + DEFINES="$DEFINES -DTIZEN -DDISABLE_STDIO_FILESTREAM -DNONSTANDARD_PORT" + DEFINES="$DEFINES -DNO_STDERR_STDOUT" + DEFINES="$DEFINES -DDISABLE_COMMAND_LINE" + INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/tizen' + INCLUDES="$INCLUDES "'-I$(TIZEN_ROOTSTRAP)/usr/include' + INCLUDES="$INCLUDES "'-I$(TIZEN_ROOTSTRAP)/usr/include/osp' + if test "$_debug_build" = yes; then + CXXFLAGS="$CXXFLAGS -D_DEBUG -DBUILD_DLL -O0 -g3" + fi + # created a shared library for inclusion via the eclipse build + CXXFLAGS="$CXXFLAGS -Wno-psabi" + CXXFLAGS="$CXXFLAGS --sysroot=${TIZEN_ROOTSTRAP}" + CXXFLAGS="$CXXFLAGS -fmessage-length=0" + CXXFLAGS="$CXXFLAGS -fPIC" + HOSTEXEPRE=lib + HOSTEXEEXT=.a + ;; webos) # There is no sdl-config in the WebOS PDK so we don't use find_sdlconfig here. # The PDL library acts as the WebOS device toolchain, and is required to control the virtual keyboard among other OS-level events. @@ -2869,7 +2868,7 @@ esac # Enable 16bit support only for backends which support it # case $_backend in - android | bada | dingux | dc | gph | iphone | maemo | openpandora | psp | samsungtv | sdl | webos | wii) + android | dingux | dc | gph | iphone | maemo | openpandora | psp | samsungtv | sdl | tizen | webos | wii) if test "$_16bit" = auto ; then _16bit=yes else @@ -2882,6 +2881,20 @@ case $_backend in esac # +# Enable Event Recorder only for backends that support it +# +case $_backend in + sdl) + if test "$_eventrec" = auto ; then + _eventrec=yes + fi + ;; + *) + _eventrec=no + ;; +esac + +# # Disable savegame timestamp support for backends which don't have a reliable real time clock # case $_backend in @@ -3461,6 +3474,52 @@ define_in_config_if_yes "$_zlib" 'USE_ZLIB' echo "$_zlib" # +# Check for LibMPEG2 +# +echocheck "libmpeg2 >= 0.4.0" +if test "$_mpeg2" = auto ; then + _mpeg2=no + cat > $TMPC << EOF +typedef signed $type_1_byte int8_t; +typedef signed $type_2_byte int16_t; +typedef signed $type_4_byte int32_t; + +typedef unsigned $type_1_byte uint8_t; +typedef unsigned $type_2_byte uint16_t; +typedef unsigned $type_4_byte uint32_t; + +extern "C" { +#include <mpeg2dec/mpeg2.h> +} + +int main(void) { + #if MPEG2_RELEASE < MPEG2_VERSION(0, 4, 0) + #error libmpeg2 version too low + #endif + + /* mpeg2_state_t first appears in 0.4.0 */ + mpeg2_state_t state; + + return 0; +} +EOF + + if test -n "$_host"; then + # don't execute while cross compiling + cc_check $MPEG2_CFLAGS $MPEG2_LIBS -lmpeg2 && _mpeg2=yes + else + cc_check_no_clean $MPEG2_CFLAGS $MPEG2_LIBS -lmpeg2 && $TMPO$HOSTEXEEXT && _mpeg2=yes + cc_check_clean + fi +fi +if test "$_mpeg2" = yes ; then + INCLUDES="$INCLUDES $MPEG2_CFLAGS" + LIBS="$LIBS $MPEG2_LIBS -lmpeg2" +fi +define_in_config_if_yes "$_mpeg2" 'USE_MPEG2' +echo "$_mpeg2" + +# # Check for Sparkle if updates support is enabled # echocheck "Sparkle" @@ -3563,8 +3622,8 @@ if test "$_libunity" = auto ; then ;; *) # Unity has a lots of dependencies, update the libs and cflags var with them - LIBUNITY_LIBS="$LIBUNITY_LIBS $(pkg-config --libs unity = 3.8.4 2>> "$TMPLOG")" - LIBUNITY_CFLAGS="$LIBUNITY_CFLAGS $(pkg-config --cflags unity = 3.8.4 2>> "$TMPLOG")" + LIBUNITY_LIBS="$LIBUNITY_LIBS `pkg-config --libs unity = 3.8.4 2>> "$TMPLOG"`" + LIBUNITY_CFLAGS="$LIBUNITY_CFLAGS `pkg-config --cflags unity = 3.8.4 2>> "$TMPLOG"`" _libunity=no cat > $TMPC << EOF #include <unity.h> @@ -3721,7 +3780,7 @@ EOF fi case $_host_os in - bada) + tizen) # components live in non-standard locations so just assume sane SDK _opengl=yes _opengles=yes @@ -3797,10 +3856,21 @@ fi define_in_config_if_yes $_nasm 'USE_NASM' # -# Enable vkeybd / keymapper +# Enable vkeybd / keymapper / event recorder # define_in_config_if_yes $_vkeybd 'ENABLE_VKEYBD' define_in_config_if_yes $_keymapper 'ENABLE_KEYMAPPER' +define_in_config_if_yes $_eventrec 'ENABLE_EVENTRECORDER' + +# +# Check if the keymapper and the event recorder are enabled simultaneously +# +if test "$_keymapper" = yes ; then + if test "$_eventrec" = yes ; then + echo "ERROR: The keymapper and the event recorder cannot be enabled simultaneously currently, please disable one of the two" + exit 1 + fi +fi # Check whether to build translation support # @@ -3879,7 +3949,14 @@ fi test "x$prefix" = xNONE && prefix=/usr/local test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' -DEFINES="$DEFINES -DDATA_PATH=\\\"$datadir\\\"" +case $_host_os in + mingw*) + # Windows stores all the external data files in executable file. + ;; + *) + DEFINES="$DEFINES -DDATA_PATH=\\\"$datadir\\\"" + ;; +esac case $_backend in openpandora) @@ -3946,7 +4023,11 @@ if test "$_vkeybd" = yes ; then fi if test "$_keymapper" = yes ; then - echo ", keymapper" + echo_n ", keymapper" +fi + +if test "$_eventrec" = yes ; then + echo ", event recorder" else echo fi diff --git a/devtools/README b/devtools/README index c7f08d6dfa..482c24edc2 100644 --- a/devtools/README +++ b/devtools/README @@ -63,6 +63,13 @@ create_lure (dreammaster) the lure.dat file. +create_mort (Strangerke) +----------- + Gathers several information found in the original DOS executable: + - Font data + - French, German and fan-made English translation + + create_project (LordHoto, Littleboy) -------------- Creates project files for Visual Studio 2005, 2008, 2010, 2012, Xcode and diff --git a/devtools/create_kyradat/create_kyradat.cpp b/devtools/create_kyradat/create_kyradat.cpp index ca809e0aac..01cde620e7 100644 --- a/devtools/create_kyradat/create_kyradat.cpp +++ b/devtools/create_kyradat/create_kyradat.cpp @@ -2350,8 +2350,10 @@ bool createIDMap(PAKFile &out, const ExtractInformation *eI, const int *needList for (const int *id = needList; *id != -1; ++id) { WRITE_BE_UINT16(dst, *id); dst += 2; const ExtractFilename *fDesc = getFilenameDesc(*id); - if (!fDesc) + if (!fDesc) { + delete[] map; return false; + } *dst++ = getTypeID(fDesc->type); WRITE_BE_UINT32(dst, getFilename(eI, *id)); dst += 4; } @@ -2359,15 +2361,18 @@ bool createIDMap(PAKFile &out, const ExtractInformation *eI, const int *needList char filename[12]; if (!getFilename(filename, eI, 0)) { fprintf(stderr, "ERROR: Could not create ID map for game\n"); + delete[] map; return false; } out.removeFile(filename); if (!out.addFile(filename, map, mapSize)) { fprintf(stderr, "ERROR: Could not add ID map \"%s\" to kyra.dat\n", filename); + delete[] map; return false; } + delete[] map; return true; } diff --git a/devtools/create_kyradat/pak.cpp b/devtools/create_kyradat/pak.cpp index 0203285a8f..0d085f563c 100644 --- a/devtools/create_kyradat/pak.cpp +++ b/devtools/create_kyradat/pak.cpp @@ -142,6 +142,7 @@ bool PAKFile::outputAllFiles() { printf("OK\n"); } else { printf("FAILED\n"); + fclose(file); return false; } fclose(file); @@ -168,6 +169,7 @@ bool PAKFile::outputFileAs(const char *f, const char *fn) { printf("OK\n"); } else { printf("FAILED\n"); + fclose(file); return false; } fclose(file); diff --git a/devtools/create_lure/process_actions.cpp b/devtools/create_lure/process_actions.cpp index db965730cb..d1ddbf03f2 100644 --- a/devtools/create_lure/process_actions.cpp +++ b/devtools/create_lure/process_actions.cpp @@ -149,6 +149,7 @@ uint16 process_action_sequence_entry(int supportIndex, byte *data, uint16 remain if (startOffset == 0x7328) { startOffset = 0x72ae; maxOffset = 0x7382; } if (startOffset == 0x702f) { startOffset = 0x6f3d; maxOffset = 0x70a3; } if (startOffset == 0x7886) { startOffset = 0x742a; maxOffset = 0x7896; } + break; case DE_DEU: if (startOffset == 0x7edb) { startOffset = 0x7ead; maxOffset = 0x7f05; } if (startOffset == 0x7ab8) { startOffset = 0x796c; maxOffset = 0x7ae2; } diff --git a/devtools/create_mortdat/create_mortdat.cpp b/devtools/create_mortdat/create_mortdat.cpp new file mode 100644 index 0000000000..00b9b1ce4a --- /dev/null +++ b/devtools/create_mortdat/create_mortdat.cpp @@ -0,0 +1,271 @@ +/* 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 is a utility for extracting needed resource data from different language + * version of the Lure of the Temptress lure.exe executable files into a new file + * lure.dat - this file is required for the ScummVM Lure of the Temptress module + * to work properly + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +// HACK to allow building with the SDL backend on MinGW +// see bug #1800764 "TOOLS: MinGW tools building broken" +#ifdef main +#undef main +#endif // main + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "common/endian.h" +#include "create_mortdat.h" +#include "enginetext.h" +#include "gametext.h" +#include "menudata.h" + + +bool File::open(const char *filename, AccessMode mode) { + f = fopen(filename, (mode == kFileReadMode) ? "rb" : "wb"); + return (f != NULL); +} + +void File::close() { + fclose(f); + f = NULL; +} + +int File::seek(int32 offset, int whence) { + return fseek(f, offset, whence); +} + +long File::read(void *buffer, int len) { + return fread(buffer, 1, len, f); +} +void File::write(const void *buffer, int len) { + fwrite(buffer, 1, len, f); +} + +byte File::readByte() { + byte v; + read(&v, sizeof(byte)); + return v; +} + +uint16 File::readWord() { + uint16 v; + read(&v, sizeof(uint16)); + return FROM_LE_16(v); +} + +uint32 File::readLong() { + uint32 v; + read(&v, sizeof(uint32)); + return FROM_LE_32(v); +} + +void File::writeByte(byte v) { + write(&v, sizeof(byte)); +} + +void File::writeWord(uint16 v) { + uint16 vTemp = TO_LE_16(v); + write(&vTemp, sizeof(uint16)); +} + +void File::writeLong(uint32 v) { + uint32 vTemp = TO_LE_32(v); + write(&vTemp, sizeof(uint32)); +} + +void File::writeString(const char *s) { + write(s, strlen(s) + 1); +} + +uint32 File::pos() { + return ftell(f); +} + +/*-------------------------------------------------------------------------*/ + +void openOutputFile(const char *outFilename) { + outputFile.open(outFilename, kFileWriteMode); + + // Write header + outputFile.write("MORT", 4); + outputFile.writeByte(VERSION_MAJOR); + outputFile.writeByte(VERSION_MINOR); +} + +/** + * Write out the data for the font + */ +void writeFontBlock() { + const int knownAddr[3] = {0x30cd, 0x36b0, 0x36c0}; + byte checkBuffer[7]; + byte fontBuffer[121 * 6]; + + // Move to just prior the font data and verify that we're reading the known mort.com + for (int i = 0; i <= 3; ++i) { + if ( i == 3) { + printf("Invalid mort.com input file"); + exit(0); + } + + mortCom.seek(knownAddr[i]); + mortCom.read(checkBuffer, 7); + + if ((checkBuffer[0] == 0x59) && (checkBuffer[1] == 0x5B) && (checkBuffer[2] == 0x58) && + (checkBuffer[3] == 0xC3) && (checkBuffer[4] == 0xE8) && (checkBuffer[5] == 0xD6) && + (checkBuffer[6] == 0x02)) { + break; + } + } + + // Read in the data + mortCom.read(fontBuffer, 121 * 6); + + // Write out a section header to the output file and the font data + const char fontHeader[4] = { 'F', 'O', 'N', 'T' }; + outputFile.write(fontHeader, 4); // Section Id + outputFile.writeWord(121 * 6); // Section size + + outputFile.write(fontBuffer, 121 * 6); +} + +void writeStaticStrings(const char **strings, DataType dataType, int languageId) { + // Write out a section header + const char sStaticStrings[4] = { 'S', 'S', 'T', 'R' }; + const char sGameStrings[4] = { 'G', 'S', 'T', 'R' }; + + if (dataType == kStaticStrings) + outputFile.write(sStaticStrings, 4); + else if (dataType == kGameStrings) + outputFile.write(sGameStrings, 4); + + // Figure out the block size + int blockSize = 1; + const char **s = &strings[0]; + while (*s) { + blockSize += strlen(*s) + 1; + ++s; + } + + outputFile.writeWord(blockSize); + + // Write out a byte indicating the language for this block + outputFile.writeByte(languageId); + + // Write out each of the strings + s = &strings[0]; + while (*s) { + outputFile.writeString(*s); + ++s; + } +} + +/** + * Write out the strings previously hard-coded into the engine + */ +void writeEngineStrings() { + writeStaticStrings(engineDataEn, kStaticStrings, 1); + writeStaticStrings(engineDataFr, kStaticStrings, 0); + writeStaticStrings(engineDataDe, kStaticStrings, 2); +} + +/** + * Write out the strings used in the game + */ +void writeGameStrings() { + writeStaticStrings(gameDataEn, kGameStrings, 1); + writeStaticStrings(gameDataFr, kGameStrings, 0); + writeStaticStrings(gameDataDe, kGameStrings, 2); +} + +/** + * Write out the data for the English menu + */ +void writeMenuBlock() { + // Write out a section header to the output file and the menu data + const char menuHeader[4] = { 'M', 'E', 'N', 'U' }; + outputFile.write(menuHeader, 4); // Section Id + outputFile.writeWord(strlen(menuDataEn) / 8); // Section size + // Write each 8-characters block as a byte (one bit per character) + // ' ' -> 0, anything else -> 1 + byte value; + int valueCpt = 0; + const char* str = menuDataEn; + while (*str != 0) { + if (*(str++) != ' ') + value |= (1 << (7 - valueCpt)); + ++valueCpt; + if (valueCpt == 8) { + outputFile.writeByte(value); + value = 0; + valueCpt = 0; + } + } +} + +void writeVerbNums(const int *verbs, int languageId) { + // Write out a section header to the output file + const char menuHeader[4] = { 'V', 'E', 'R', 'B' }; + outputFile.write(menuHeader, 4); // Section Id + int size = 52 + 1; // Language code + 26 words + outputFile.writeWord(size); + + outputFile.writeByte(languageId); + for (int i = 0; i < 26; i++) + outputFile.writeWord(verbs[i]); +} + +void writeMenuVerbs() { + writeVerbNums(verbsEn, 1); + writeVerbNums(verbsFr, 0); + writeVerbNums(verbsDe, 2); +} + +void process() { + writeFontBlock(); + writeGameStrings(); + writeEngineStrings(); + writeMenuVerbs(); + writeMenuBlock(); +} + +/** + * Main method + */ +int main(int argc, char *argv[]) { + if (argc != 2) { + printf("Usage:\n%s input_filename\nWhere input_filename is the name of the Mortevielle DOS executable.\n", argv[0]); + exit(0); + } + + mortCom.open(argv[1], kFileReadMode); + openOutputFile(MORT_DAT); + + process(); + + mortCom.close(); + outputFile.close(); +} diff --git a/devtools/create_mortdat/create_mortdat.h b/devtools/create_mortdat/create_mortdat.h new file mode 100644 index 0000000000..1ebbbe37e0 --- /dev/null +++ b/devtools/create_mortdat/create_mortdat.h @@ -0,0 +1,63 @@ +/* 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 is a utility for extracting needed resource data from different language + * version of the Mortevielle executable files into a new file mort.dat - this + * is required for the ScummVM Mortevielle module to work properly + */ + +#define VERSION_MAJOR 1 +#define VERSION_MINOR 1 + +enum AccessMode { + kFileReadMode = 1, + kFileWriteMode = 2 +}; + +enum DataType { + kStaticStrings = 0, + kGameStrings = 1, + kEncryptionArrays = 2 +}; + +#define MORT_DAT "mort.dat" + +class File { +private: + FILE *f; +public: + bool open(const char *filename, AccessMode mode = kFileReadMode); + void close(); + int seek(int32 offset, int whence = SEEK_SET); + uint32 pos(); + long read(void *buffer, int len); + void write(const void *buffer, int len); + + byte readByte(); + uint16 readWord(); + uint32 readLong(); + void writeByte(byte v); + void writeWord(uint16 v); + void writeLong(uint32 v); + void writeString(const char *s); +}; + +File outputFile, mortCom; + diff --git a/devtools/create_mortdat/enginetext.h b/devtools/create_mortdat/enginetext.h new file mode 100644 index 0000000000..e1c40f898b --- /dev/null +++ b/devtools/create_mortdat/enginetext.h @@ -0,0 +1,189 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * This is a utility for extracting needed resource data from different language + * version of the Mortevielle executable files into a new file mort.dat - this + * is required for the ScummVM Mortevielle module to work properly + */ + +#ifndef ENGINEDATA_H +#define ENGINEDATA_H + +const char *engineDataEn[] = { + "[2][ ][YES][NO]", + "Go to", + "Someone enters, looks surprised, but says nothing", + " Cool ", + "Oppressive", + " Tense ", + "Idem", + "You", + "are", + "Alone", + + "Gosh! You hear some noise...", + " | You should have noticed, | ", + "% of hints...", + "Do you want to wake up?", + "OK", + "", + " Save", + + " Load", + " Restart", + "F3: Repeat", + "F8: Proceed", + "Hide self", + "take", + " probe ", + " raise ", + " -MORE- ", + " -STOP- ", + "[1] [So, use the DEP menu] [Ok]", + "lift", + "read", + + "look", + "search", + "open", + "put", + "turn", + "tie", + "close", + "hit", + "pose", + "smash", + + "smell", + "scratch", + "probe", + "[1] [ | Before, use the DEP menu...] [Ok]", + "& day", + NULL +}; + +const char *engineDataFr[] = { + "[2][ ][OUI][NON]", + "aller", + "quelqu'un entre, parait \202tonn\202 mais ne dit rien", + "Cool", + " Lourde ", + "Malsaine", + "Idem", + "Vous", + "\210tes", + "SEUL", + + "Mince! Vous entendez du bruit...", + " | Vous devriez avoir remarqu\202| ", + "% des indices...", + "D\202sirez-vous vous r\202veiller?", + "OK", + "", + " Sauvegarde", + + " Chargement", + " Recommence ", + "F3: Encore", + "F8: Suite", + "se cacher", + + "prendre", + "sonder", + "soulever", + " -SUITE- ", + " -STOP- ", + "[1][Alors, utilisez le menu DEP...][ok]", + "soulever", + "lire", + + "regarder", + "fouiller", + "ouvrir", + "mettre", + "tourner", + "attacher", + "fermer", + "frapper", + "poser", + "d\202foncer", + + "sentir", + "gratter", + "sonder", + "[1][ | Avant, utilisez le menu DEP...][ok]", + "& jour", + NULL +}; + +const char *engineDataDe[] = { + "[2][ ][JA][NEIN]", + "gehen", + "Jemand kommt herein, scheint erstaunt, sagt nichts", + "Cool", + "Schwer", + "Ungesund", + "Idem", + "Sie", + "sind", + "allein", + + "Verdammt! Sie hoeren ein Geraeush...", + "Sie haetten ", + "% der Hinweise| bemerken muessen...", + "Moechten Sie aufwachen?", + "OK", + "", + " schreiben", + + " lesen", + " wieder ", + "F3: nochmals", + "F8: stop", + " sich verstecken", + " nehmen", + " sondieren", + " hochheben", + " -WEITER- ", + " -STOP- ", + "[1][ Benutzen Sie jetzt das Menue DEP...][OK]", + "hochheben", + "lesen", + + "anschauen", + "durchsuchen", + "oeffnen", + "setzen", + "drehen", + "befestigen", + "schliessen", + "klopfen", + "hinlegen", + "eindruecken", + + "fuehlen", + "abkratzen", + "sondieren", + "[1][ Benutzen Sie jetzt das Menue DEP...][OK]", + "& tag", + NULL +}; + +#endif diff --git a/devtools/create_mortdat/gametext.h b/devtools/create_mortdat/gametext.h new file mode 100644 index 0000000000..4f7b1f9776 --- /dev/null +++ b/devtools/create_mortdat/gametext.h @@ -0,0 +1,1794 @@ +/* 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 is a utility for extracting needed resource data from different language + * version of the Mortevielle executable files into a new file mort.dat - this + * is required for the ScummVM Mortevielle module to work properly + */ + +#ifndef GAMEDATA_H +#define GAMEDATA_H + +const char *gameDataEn[] = { + "Calm within the storm$", + "Discussed in colours$", + "Your mauve!$", + "Be kind enough to leave the room...$", + "If you're NOT overdrawn...$", + "If you're feeling blue...$", + "Read what's on the walls?$", + "Water sports$", + "Room for envy?$", + "A glance at the forbidden$", + "Smell of a woodfire and tobacco$", + "Tobacco and old books$", + "Onions, cinnamon and spirits$", + "A place seldom visited$", + "Humidity and decay$", + "Sorry, no ""door to door""$", + "Rotting corpse: deady cryptomania$", + "And what's more, there are disused traps$", + "It's already open$", + "Danger: avalanches$", + "Proper Charlie's place?$", + "An imposing building$", + "The other side of the mystery$", + "Strange horoscope$", + "Look out... but she wishes well?$", + "An oak door$", + "A photograph$", + "The coat of arms$", + "$", + "Max, the servant, welcomes you and shows you to your room$", + "Mortville 6/2/51@ My dear Jerome@Regarding my telegram, I must tell you the reason for my wor-@ries. A year ago, Murielle, my lady companion, disappeared. The de@part may have had something to do@with the financial success of themanor, or... A silence hard to un@derstand for my son Guy. Not ha@ving been able to see the light of day over this affair, I count @on you to sort things out. If my state of health doesn't improve, @take the decisions that you feel @are apropriate.@ Kind regards, Julia DEFRANCK$", + "Later, Guy will inform you of Leo's suicide after a@heavy bet at the races$", + "F3: AGAIN F8: STOP$", + "The master of the premises$", + "The future heir$", + "JULIA's son$", + "A pretty picture$", + "Superman!$", + "Ida's husband$", + "Interesting remarks?$", + "Service included!$", + "Nothing underneath$", + "You could hear a pin drop$", + "Half an hour passes: nothing! Wait any longer?$", + "Admire! Contemplate!$", + "No! Nothing!$", + "Impossible$", + "That stains!$", + "A treatise on the history of the area$", + "A few coins...$", + "First commandment...$", + "Pleasing to the nostrils!$", + "Spades, Hearts...$", + "Just a spoonful of sugar...$", + "A romantic novel$", + "Worth more than a penny, (whistle)$", + "Just needs a little patience$", + "Watch the sharp bends$", + "Deep and dark$", + "Normal sensations$", + "Sniff!$", + "Not discreet! Be content to watch!$", + "Bless you! Dusty!$", + "The canvas is signed, the wallpaper is not!$", + "Nothing, Unlucky!$", + "Be more discreet!$", + "The shutters are closed$", + "Snow! And more snow!$", + "Brilliant! The work of a master!$", + "No doubt at all! A genuine fake!$", + "Hmm! A cheap reproduction!$", + "A rare and valuable piece$", + "Nothing special$", + "Linen, personal belongings...$", + "Not just anywhere!$", + "It's not time!$", + "One doesn't speak with ones mouth full! So once the meal is over...$", + "Someone comes in, messes about then goes out again$", + "Someone's approaching your hiding-place$", + "Someone surprises you!$", + "Impossible! You're too loaded!$", + "Try again!$", + "Still puzzled!?$", + "You leave Mortville.In Paris a message awaits you...$", + "You hurt yourself$", + "Nothing more here$", + "The sound seems normal$", + "It doesn't move$", + "You are answered$", + "Not the right moment!$", + "The same matter, from another angle!$", + "The reflection is tarnished, but the frame is gold!$", + "Bric-a-brac$", + "Facing failure!$", + "Smells like something you'd rather not see!$", + "Cleaning products$", + "Got an itch?$", + "It's stuck, frozen. Brrr!$", + "All the locks are jammed!$", + "Papers$", + "No! Father christmas hasn't got himself stuck!$", + "It leads onto a corridor$", + "China, silverware...$", + "No! It's not Julia's remains!$", + "An old engraving$", + "You find a deep diamond-shaped opening$", + "The wall slides open! A passage! Do you follow it?$", + "The passageway closes$", + "A secret drawer: a notebook! Do you read it?$", + "The drawer shuts$", + "Nothing! Flesh and blood stuck to the stone$", + "Certain details lead you to believe death was not immediate!$", + "A rotten affair!$", + "Did she cling to dear life with just one finger?$", + "Has the treasure packed its trunk?$", + "A slot the size of a coin$", + "Part of the stone wall pivots.A crypt! Do you enter?$", + "The ring turns, the wall closes$", + "A stone column behind the altar$", + "There is a noise!$", + "Occupied!$", + "Take another chance?$", + "Too deep!$", + "The cellar wall pivots$", + "Nothing$", + "The one and only!$", + "The object slides to the bottom$", + "You have nothing in hand$", + "It is not open$", + "There is already something$", + "The door is locked$", + "No reply$", + "A solid wooden ball$", + "There's no more space$", + "A wooden ball pierced through the side$", + "? ?$", + "Your move$", + "OK !$", + "Suddenly Max arrives with your suitcase: \"Thank you for your visit!\".@Mister discreet \"private eye\" (in need of a private optician!). Thoroughly demoralised, you leave the manor. You are useless!$", + "Leo interrupts: \"The storm has died down,I am going into town in 1 hour. Get ready\".@You have lost time...but not your life$", + "Congestion, the deadly flu... You are stuck here! Your whole case sinks slowly beneath the water$", + "The water is rising fast, freezing your last illusions. Before you have time to react... you are dead$", + "As soon as you reach the bottom of the well, a hand cuts the rope Farewell sweet life!$", + "The storm covers your footprints.A wall of silence falls heavily on your shoulders. Slowly you succumb to frosbite...$", + "You're not completely alone! A cold blade plunges into your back. In future, be more careful!$", + "You don't know what implication Leo may have had in Murielle's death. Was she dead outright? In any case, the family problems that you have uncovered in the course of your enquiries would explain Leo's behaviour. You're not sure that's the reason Julia had asked for your help, but that's reason enough for you! Out of respect for her, after taking certain precautions you have a revealing talk with Leo.$", + "$", + "You don't have the keys to the manor. Your cries rest unheard You're going to catch... your death!$", + "With a circular movement, the sword slices across you. Guts and intestines spill out all over. A sorry state of affairs!$", + "Home, Sweet home !$", + "The mystery behind a closed door$", + "Bewitching charm of these old rooms$", + "An empty stomach$", + "Closer to heaven? Not so sure$", + "Afraid of the dark?$", + "Old rugs and a glint of gold$", + "Anguish!$", + "Safe? Perhaps not!$", + "A little ill at ease, eh!?$", + "Always further$", + "Your way of the cross!$", + "On the trail of...$", + "Watch what's hiding$", + "The road down to hell$", + "Feeling well? You look a little pale$", + "What lurks behind...?$", + "Close-up on:$", + "You notice, amongst other things$", + "And...$", + "That's all!$", + "A bit of reading$", + "The adventure awaits, you set off!$", + "Don't mess up YOUR next ADVENTURE!$", + "I don't understand$", + "There is an easier way$", + "No, not just now$", + "Too late$", + "$", + "Like a deep stony stare, a solitary eye that points towards the@stars; the artery that links hea-ven and hell. You must fathom@these depths keeping hold of that@which is, and will become. Monday, Tuesday, Wednesday, Sunday, from@the first Monday to the first Sunday,plunging from one day to the next your@\"IS\" or \"WILL BECOME\". Carrying your burden with love and light,@the smallest oversight will seal your fate.$", + "10/1/51: We think we've solved the mystery of the manuscript and@located the crypt. Is it the idea@of success in what seems like a dream that disturbs me so? I feel@I have committed myself rather too much, as far as Leo is @concerned... No! I mustgo on. @I should have put Guy in the picture but for a week now, I've had@no news of him$", + "Take your prayers as you would to the holy place. From the pillar@of wisdom, bring the sun to his@knees. Thus will it show you the place to offer alms of another@kind and like young Arthur, open the way of darkness.White is your@colour, golden your hearth. So@advance with caution Orpheus and light your way unto the sad@virgin. Offer her the circle of the man with three faces. That he@may regain the world and turn with it to its original@inglory!$", + "The mountains are the fangs in a monstrous mouth opening on the@finity of a celestial orgy, grin-ding the stars as we grind our@teeth into dust. You will drop your chord of stone at your feet.@The laugh of silence at the@highest pitch, and in your right hand, the measure of genius. Thus@will you pass between the two crescents beyond the abyss of the@wall of silence. The key to the melody is within your grasp. It@suffices to find the note that clashes.$", + " 9/12 INTER. 518 3/13 EXPENS. 23@ 9/12 SALES 1203 7/12 CHEQUE 1598@ TOTAL 1721 TOTAL 1721$", + " 5/1/51@@ Luc, my love@ Guy knows about us. After an argument I told him everything! I@think only of you. Max keeps pes-tering me, but it's finished with @him. He should stick to his pots and pans! When can you and I be alone together? For you I would@get a divorce.@I love you.@ Eva$", + " Mortville, 10/2/51@@ Pat@ I recall you owe me 50000 frs that I lent you for your business@I need that money, can you repay me quickly?@ Guy$", + " Mortville, 15/2/51@ Dear Sir@ I am writing to you on the sub-ject of our business deal. I have@decided to go all the way in the certainty that my partner, Pat@DEFRANCK, has been forging the accounts. @In spite of$", + " A pipe$", + " A pen$", + " A lighter$", + " A retort$", + " A shaving brush$", + " A tin of paint$", + " A flute$", + " An expensive ring$", + " A reel of thread$", + " An old book$", + " A wallet$", + " A dagger$", + " A pistol$", + " A bible$", + " A candle$", + " A jewellery box$", + " An iron$", + " A photo$", + " A pocket watch$", + " A rope$", + " Keys$", + " A pearl necklace$", + " A bottle of perfume$", + " Binoculars$", + " Glasses$", + " A leather purse$", + " A tennis ball$", + " Ammunition$", + " A cut-throat razor$", + " A hairbrush$", + " A clothes brush$", + " A pack of cards$", + " A shoe horn$", + " A screwdriver$", + " A hammer$", + " Keys$", + " Keys$", + " An ashtray$", + " A paintbrush$", + " A rope$", + " A wooden object$", + " Sleeping pills$", + " A gold ring$", + " A jewellery box$", + " An alarm clock$", + " A coat of armour$", + " A candlestick$", + " A pair of gloves$", + " A engraved goblet$", + " A parchment$", + " A dagger$", + " A dossier$", + " A parchment$", + " A parchment$", + " A dossier$", + " A dossier$", + " A letter$", + " A novel$", + " A wooden rod$", + " An envelope$", + " A letter$", + " An envelope$", + "Julia$", + "Julia's death$", + "Julia's relationships$", + "A message from Julia$", + "Julia's inheritance$", + "Julia's final actions$", + "Julia's gifts$", + "Julia's bedroom$", + "The photo at Julia's home$", + "Julia and yourself...$", + "L\202o's occupations$", + "Pat's occupations$", + "Guy's occupations$", + "Bob's occupations$", + "Eva's occupations$", + "Luc's occupations$", + "Ida's occupations$", + "Max's occupations$", + "Your occupations$", + "L\202o's relationships$", + "Pat's relationships$", + "Guy's relationships$", + "Bob's relationships$", + "Eva's relationships$", + "Luc's relationships$", + "Ida's relationships$", + "Max's relationships$", + "Your relationships$", + "Murielle$", + "Murielle's relationships$", + "Murielle and yourself...$", + "Murielle's disappearance$", + "The wall of silence$", + "The manuscripts$", + "The coat of arms$", + "Engravings in the cellar$", + "The well$", + "The secret passages$", + "The chapel$", + "The paintings$", + "The photo of the attic$", + "The body in the crypt$", + "$", + "$", + "END OF THE CONVERSATION$", + "That was the name old people gave to the mountain range that lies at the foot of the manor!$", + "These are the mountains one can see in front of the manor$", + "I don't know!$", + "She died from pulmonary embolism$", + "Mother died suddenly. And yet her health had seemed to improve\202$", + "Miss DEFRANCK died from a cold$", + "She died from pulmonary embolism$", + "Excuse me but I prefer to say nothing for now$", + "Only the good die young$", + "I loved my mother . My only regret is that she died in the DEFRANCK's manor$", + "That region has a lot of history and there is plenty to keep me busy. And also I love horses..$", + "He is a history enthusiast and a gambler. By the way he won a large sum one year ago$", + "He is already very busy with the management and maintenance of the mansion...$", + "I am the CEO of a small perfume company. But when I am here, I rest$", + "He is a dynamic man who has succeeded in perfurmes$", + "Him! He is an upstart rogue! Perfumes must have killed his common sense. Moreover, when he's here he spends his evenings in his room$", + "I was very concerned about my mother's health, and now I don't feel like doing anything at all$", + "He would have done better to look after me a bit more and a bit less after his mother$", + "It is not my business...$", + "He does not have much luck at the moment although his business is satisfactory$", + "I work with Pat but it's not going too well at the moment$", + "Oh really?! He has occupations? He should take them seriously then$", + "Him and Pat are patners. I think it's going pretty well$", + "I take care of myself and that's already lots. How about you?$", + "Oh for that I trust her! She knows how to keep herself busy$", + "What! You have not yet discovered her main occupation..?$", + "She is working in the decoration business, and tastefully with that. She is always very well dressed$", + "If you like jewels, I have some good deals to propose for a short while$", + "The jewels...$", + "I don't know, but I'd like him to give me a bit more slack!$", + "When one is a housewife, one always find something to do...$", + "She could stay there doing nothing, but no! She sews, she reads...$", + "She has probably not very fulfilling occupations...$", + "A woman like there is no more: She is interested in everything!$", + "With the cooking and the cleaning I do not have much time for you$", + "I do not know how he manages to do everything. That's wonderful!", + "He would do more if he showed less interest in gossip and alcohol$", + "I am very independant. As long as nobody interferes in my business: No problem$", + "He is selfish. I wonder if he likes something other than his horses and grimoires$", + "I think he gets along well with everyone, except, perhaps, with Guy$", + "He has a temper. You have to learn how to deal with him...$", + "Business is business. As for the family, I leave it as it is...$", + "Relations? Friendly relations? Financial relations, without a doubt$", + "Oh, I have no issue with this person$", + "He is a resourceful businessman. He sometimes tries to swim upstream but... he will always find a way to make it work$", + "They are all boring .. No! Not even that .. Even if .. some of them ..$", + "Contrary to his mother, he is a very shy person ! So when you say relations...$", + "He must be trying very hard to remain nice despite all his troubles$", + "His romantic relationship: it's over. His relationship with me: hasn't really started. As for the other ones: I don't follow the \"other ones\"$", + "I like everyone, as long as they are not trying to screw me over$", + "It is not enough to have a bit of money and to know how to talk for everyone to like you$", + "Not much to say about him... He is a nice and generous man. And what's more, he can be quite funny$", + "Nowadays I get along rather well with everyone. But, here, I am not going to say more about this$", + "Nice feathers, but a bird's brain... Ask her husband$", + "Is it for an appointment?$", + "She is very lively! She does not burden herself with stupids prejudices$", + "In my line of work, one mostly encounters beautiful women and gangsters$", + "The only sure thing he has going for him, it's his jewelery... And his wife, but he doesn't realize that$", + "It's an interesting character. Who is not always very easy to follow, but worth knowing$", + "I hate no one, but I like things and people when they stay where they should be$", + "This stays between us. But you see: when I speak with her, I soon start to feel a bit uncomfortable!$", + "You'd have to try hard to not get along with her$", + "You know, in my line of work you hear everything but don't remember anything, and service is well done$", + "He's a submissive hypocrite! Personally I don't trust him$", + "I don't know what he thinks deep down inside, but he's always polite and impeccable$", + "Someone who lived in the manor, a year ago... maybe more$", + "She was more than a friend to my mother. In these moments, I would have loved to have her by my side$", + "Murielle has been Julia's lady-in-waiting$", + "She, too, was doing some research....$", + "She was a very educated person. Her abrupt leaving, a year ago, surprised me and caused me great sorrow$", + "Her and Leo shared a common passion for history and the local area$", + "I think everyone liked her$", + "She got along with everyone. She loved her son dearly. As for the relations between mother-in-law and daughter-in-law...$", + "Apart from Leo, she got along very well with Max...$", + "Even if your relations were unfrequent, Jerome, there was still a place for you in her heart...$", + "Apart from her family, not a lot of people$", + "Oh right! I think she deeply regretted this friend's leaving... err! Marielle... or Mireille...$", + "No, nothing!$", + "No... Not that I know of$", + "I met Julia when buying the manor. It was the only thing she owned. But all my wealth was hers...$", + "Apart from a few personal belongings, I think she didn't own anything anymore$", + "I think all her fortune came from Leo. So, pfft!$", + "Apart from the letter for you I posted, nothing very important!$", + "I was very happy she gave me her bound bible as a present$", + "It happened fast and she didn't have time to make any particular will$", + "Her last gift suprised me$", + "Which gift?$", + "A chandelier...$", + "Yes, I got a present. My wife even got a bible$", + "Well yes! Like everyone, I believe$", + "A dagger$", + "I have never been looking around in the attic!$", + "You can either see through walls or pick a door$", + "The portrait of a young girl: it's Murielle...$", + "You know, I didn't know her that well$", + "She was very charming, but above all she was Julia's lady-in-waiting$", + "She was the only truly interesting woman I've met$", + "She had a great knowledge in history, and you learned a great deal when you asked her about it$", + "I've always wondered why some people fancied her!$", + "If the room is closed, ask Leo$", + "I closed her door after her death and I'd like it to remain this way for a while$", + "You know how it is: family relations$", + "All those years, I've never regretted serving her$", + "I loved her as much as she loved me, I think$", + "What made you think you could enter my wife's room?!!$", + "It must be the picture of Murielle with Julia's godson$", + "I don't remember$", + "This is Murielle. I took that picture, and actually they developed it backwards$", + "You sure are curious!... It's not worth anything$", + "Grimoires, parchment and manuscripts: it is Leo's realm$", + "Too bad the motto doesn't appear here...$", + "This is beautiful... And very old...$", + "Hey! That's a place I've never visited$", + "According to Leo, it seems that the Moons are more recent$", + "Even under this weather, you managed to find a sun...$", + "Profound and disturbing: Progress is good$", + "For me, it remains the biggest of all mysteries$", + "The last days she was talking about a trip. And then...$", + "A little over a year ago, one night, she decided to leave...$", + "In any case, she wasn't meant to live here$", + "What?! Whose body? Which crypt?$", + "If there are any, I have never found them...$", + "Of course! And ghosts too...$", + "It's the oldest in the area: it is from the 11th century$", + "It was slightly renovated after the French Revolution$", + "Julia loved paintings$", + "They are different in styles, but not all of them are worth a lot$", + "What are you doing h-$", + "I'm sure you are looking for something in here$", + "I'm listening$", + "What do you want?$", + "Yes?$", + "I'm all yours...$", + "What's the matter?$", + "Go ahead$", + "What is it about?$", + "Max: at your service, sir$", + "In any case you have no business being in here! Get out!!$", + "You are too curious!$", + "Jerome! It's been a while... I'm very sad to announce you that Julia died. Her family is here: Guy, her son; Eva, her daughter-in-law; Leo, her husband, of course; her son-in-law Pat; cousins, too: Bob, Ida, Luc. The storm is getting stronger, you must stay here. Meals are served at 12am and 7pm, and there is a mass at the chapel every day at 10am$", + "When I saw you I knew you would uncover the truth... I knew why you were here: I had found the draft of Julia's letter. But I love to play, so... She hadn't wanted your task to be too easy, to protect me, probably, but she couldn't die knowing this mystery would remain unsolved. Did you find out that the wall of silence is the name the builders gave, during the construction of the manor, to the wall on which the coat of arms hangs?... And those gifts Julia left before dying were as many false leads, and their true purpose was to highlight how important the parchments were... That's right, more than a year ago I was working with Murielle on the decryption of those manuscripts I had just found. My wife made the connection between our work and Murielle's disappearance, but she never had any proof. Except that ring she found one day while going through my belongings. One night, we went exploring the secret passage we had found. Murielle died by accident in the room of the Virgin. I quickly took the ring from her, found the treasure and ran away. I didn't think she was still alive, and I didn't say a word because I needed the money. I told everyone the money was coming from a winning bet at the horseraces... Leave now, since you're not a policeman. Leave me alone!$", + "February 1951... Occupation: private eye. The cold was freezing Paris off, and my cases as well, when...$", + "A letter, a call, memories from a childhood not that long ago. Echoes of the many games we played in the disused rooms of Mortville Manor... And Julia, now an old woman.$", + " to the office$", + " to the kitchen$", + " to the cellar$", + " to the landing$", + " outside$", + " to the dining room$", + " inside the manor$", + " front of the manor$", + " to the chapel$", + " to the well$", + " north$", + " behind the manor$", + " south$", + " east$", + " west$", + " towards the manor$", + " further$", + " in the water$", + " out of the well$", + " in the well$", + " choice on screen$", + "In the MYSTERY series...$", + "MORTVILLE MANOR$", + "$", + "From an original idea of...$", + "Bernard GRELAUD and Bruno GOURIER$", + "$", + "Directed by: KYILKHOR CREATION and LANGLOIS$", + "$", + "With the cooperation of...$", + "B\202atrice et Jean_Luc LANGLOIS$", + "for the music and the voices,$", + "Bernard GRELAUD for the graphic conception,$", + "MARIA-DOLORES for the graphic direction,$", + "Bruno GOURIER for the technical direction,$", + "Mick ANDON for the translation. $", + "$", + "Publisher: KYILKHOR and B&JL LANGLOIS $", + "COPYRIGHT 1987: KYILKHOR and B&JL LANGLOIS$", + "$", + "YOUR MOVE$", + " attach$", + " close$", + " eat$", + " enter$", + " force$", + " knock$", + " leave$", + " lift$", + " listen$", + " look$", + " open$", + " place$", + " read$", + " scratch$", + " search$", + " sleep$", + " smell$", + " sound$", + " take$", + " turn$", + " wait$", + " hide yourself$", + " look$", + " put$", + " read$", + " search$", + " Leo$", + " Pat$", + " Guy$", + " Eva$", + " Bob$", + " Luc$", + " Ida$", + " Max$", + "JULIA...$", + "- Did she commit suicide?$", + "- Was she murdered?$", + "- Did she die by accident?$", + "- Did she die of natural causes?$", + "Where did the money used for the@restoration of the manor come from?$", + "- Blackmail$", + "- Honest work$", + "- Inheritance$", + "- Races$", + "- Rents$", + "- Hold-up$", + "- Other$", + "What is Leo's hobby?$", + "- Historical research$", + "- Politics$", + "- Painting$", + "- Drugs$", + "- Occult sciences$", + "- Leader of a sect$", + "Julia left several clues that are@represented in one place. Which one?$", + "- Chapel$", + "- Outside$", + "- Cellar$", + "- Attic$", + "- Kitchen$", + "- Dining room$", + "- Julia's room$", + "- Leo's room$", + "- Pat's room$", + "- Bob's room$", + "- Max's room$", + "- Luc/Ida's room$", + "- Guy/Eva's room$", + "The main clue that lead you@to the underground door is:$", + "- A dagger$", + "- A ring$", + "- A book$", + "- A parchment$", + "- A letter$", + "- A pendulum$", + "How many parchments were there in the manor?$", + "- None$", + "- Just one$", + "- Two$", + "- Three$", + "- Four$", + "- Five$", + "How many persons are involved in@this story?@(including Julia, but not yourself)$", + "- Nine$", + "- Ten$", + "- Eleven$", + "What was the first name@of the unknown character?$", + "- Mireille$", + "- Fran\207oise$", + "- Maguy$", + "- Emilie$", + "- Murielle$", + "- Sophie$", + "Who did Murielle have an affair with?$", + "- Bob$", + "- Luc$", + "- Guy$", + "- Leo$", + "- Max$", + "Murielle shared an occupation@with one other person. Who?$", + "[1][You realize that certain elements of|this investigation remain a mystery for you.|Therefore, you decide first to learn|more before undertaking new risks..][ok]$", + "[3][ | insert disk 1 | in drive A ][ok]$", + "[1][ | Disk error | All stop... ][ok]$", + "[1][ | You should have noticed |00% of the clues ][ok]$", + "[3][ | insert disk 2 | in drive A ][ok]$", + "[1][ |Before going any further, you decide to| look back on the knowledge you gained][ok]$", + "TBT - MASTER .$", + "TBT - rorL$", + NULL +}; + +const char *gameDataFr[] = { + "Le calme dans la tourmente$", + "Des go\227ts et des couleurs!$", + "Mauve qui peut!$", + "Pri\212re de laisser en sortant...$", + "Trou noir troublant$", + "Bleu... comme \"peur bleue\"!$", + "Chambre de \"Saigneur\"!$", + "Histoire d'eaux$", + "Vert nid$", + "Coup d'oeil sur l'interdit$", + "Odeur de feux de bois et de tabac$", + "Tabac et vieux bouquins$", + "Oignons, cannelle et spiritueux$", + "Un endroit bien peu visit\202$", + "Humidit\202 et moisissure$", + "Avis aux colporteurs...$", + "Corps putr\202fi\202 : cryptomanie mortelle!$", + "Et en plus... des pi\212ges d\202samorc\202s!$", + "C'est d\202j\205 ouvert$", + "Danger : avalanches$", + "Une odeur de saintet\202!$", + "Une b\203tisse imposante$", + "L'envers du myst\212re!$", + "Dr\223le d'horoscope!$", + "Tant va la cruche...$", + "Une porte en ch\212ne$", + "Une photo$", + "Les armoiries$", + "$", + "Max, le domestique, vous accueille puis vous conduit \205 votre chambre$", + "Mortevielle, le 16/2/51@ Mon cher J\202r\223me,@ Suite \205 mon t\202l\202gramme, je vous fais part des raisons de mon inqui\202tude :il y a un an, Murielle, ma dame de compagnie, disparaissait . D\202part ayant rapport avec le renouveau financier du Manoir, ou... Silence difficile \205 comprendre, surtout pour mon fils Guy . N'ayant pu jusqu'\205 pr\202sent, faire le jour sur cette affaire, je compte sur vous pour la mener \205 bien . Si mon \202tat de sant\202 ne s'am\202liorait pas, prenez les d\202cisions qui vous sembleront le plus appropri\202es...@ Amiti\202s. JULIA DEFRANCK$", + "Plus tard, Guy vous apprendra le suicide de L\202o... apr\212s un pari insens\202 aux courses!$", + "F3: encore@F8: suite$", + "Le ma\214tre des lieux$", + "Le futur h\202ritier$", + "Le fils de JULIA$", + "Joli brin!!!$", + "Superman!$", + "Le mari d'Ida$", + "Propos int\202ressants?$", + "Service compris...$", + "Rien dessous!$", + "Un ange passe...$", + "Une 1/2 h passe: rien! Attendez-vous encore?$", + "Admirez! Contemplez!$", + "Non ! Rien !$", + "Impossible$", + "\207a tache !$", + "Un trait\202 sur l'histoire de la r\202gion$", + "Quelques pi\212ces$", + "Premier commandement...$", + "Des p\202tales plein les narines !$", + "Pique, Coeur...$", + "\207a ne manque pas de cachets !$", + "Un roman d'amour$", + "Souffler n'est pas jouer$", + "Pas une r\202ussite!$", + "Gare aux rebondissements !$", + "Sombre et profond...$", + "Sensations normales$", + "Sniff!$", + "Pas discret ! Contentez-vous de regarder !$", + "Atchoum! De la p... poussi\212re$", + "La toile est sign\202e... pas le papier peint !$", + "Pas de chance, rien !$", + "Soyez plus discret !$", + "Les volets sont clos$", + "De la neige, encore de la neige !$", + "G\202nial : une toile de ma\214tre !$", + "Aucun doute : une v\202ritable imitation$", + "Hum ! Vous tiquez : de l'antique en toc !$", + "Une pi\212ce rare de valeur !$", + "Rien de remarquable$", + "Linge, objets personnels...$", + "Pas n'importe o\227 !$", + "Ce n'est pas l'heure !$", + "On ne parle pas la bouche pleine ! Donc, une fois le repas termin\202...$", + "Quelqu'un entre, s'affaire, ressort...$", + "On s'approche de votre cachette !$", + "On vous surprend !$", + "Non : vous \210tes trop charg\202 !$", + "Essayez de nouveau$", + "Vous restez perplexe !?$", + "Vous quittez le Manoir. A Paris, un message vous attend...$", + "A\213e, a\213e, a\213e !$", + "Rien de plus$", + "Le son para\214t normal$", + "Ca ne bouge pas$", + "On vous r\202pond$", + "Pas le moment !$", + "M\210me mati\212re, autre face !$", + "Le reflet est piqu\202, mais le cadre est d'or$", + "Bibelots, babioles...$", + "Vous essuyez un \202chec !$", + "Il est des odeurs... qu'il vaut mieux ne pas voir !$", + "Des produits m\202nagers$", + "\207a vous d\202mange ?$", + "C'est coinc\202, gel\202 ! Brrrr...$", + "Les huisseries sont bloqu\202es !$", + "Des papiers...$", + "Non ! Le p\212re No\210l n'est pas coinc\202 !$", + "\207a donne sur un couloir$", + "Vaisselle, argenterie...$", + "Non ! Ce ne sont pas les restes de Julia !$", + "Une gravure ancienne$", + "Il y a une profonde ouverture en losange$", + "Le mur coulisse... Un passage ! L'empruntez-vous ?$", + "Le passage se ferme$", + "Un tiroir secret... Un livret ! Le lisez-vous ?$", + "Le tiroir se referme$", + "Rien ! Sang et chairs collent \205 la pierre !$", + "Des d\202tails vous font supposer que... la mort ne fut pas imm\202diate !$", + "Des projets v\202reux ?$", + "Sa vie n'aurait-elle tenu qu'\205 un doigt ?$", + "Un tr\202sor se serait-il fait la malle ?$", + "Une fente de la taille d'une pi\212ce !$", + "Quelques pierres pivotent... Une crypte ! Y p\202n\202trez-vous ?$", + "La bague tourne, le mur se referme...$", + "Une colonne de pierres derri\212re l'autel$", + "Il y a du bruit...$", + "Occup\202 !$", + "Retentez-vous votre chance ?$", + "Trop profond !$", + "Le mur de la cave pivote$", + "Nothing !$", + "L'unique !$", + "L'objet glisse au fond...$", + "Vous n'avez rien en main$", + "Ce n'est pas ouvert$", + "Il y a d\202j\205 quelque chose$", + "La porte est ferm\202e$", + "Pas de r\202ponse$", + "Une boule de bois pleine$", + "Il n'y a plus de place$", + "Une boule de bois perc\202e par le travers$", + "? ?$", + "A vous de jouer$", + "OK !$", + "Soudain Max survient avec votre valise : \"Merci de votre visite ! D\202tective \"priv\202\"... de bon sens et de discr\202tion sans doute\" . D\202\207u d\202moralis\202, vous quittez le manoir@Vous \212tes NUL !$", + "L\202o vous interrompt : \"la temp\212te est calm\202e. Je pars en ville dans 1 heure. Tenez-vous pr\210t!\"... Bon... Vous avez perdu du temps... mais pas la vie$", + "Congestion, grippe fatale : vous y restez ! Votre enqu\212te tombe \205 l'eau$", + "L'eau monte tr\212s vite et refroidit vos derni\212res illusions... Avant que vous n'ayez eu le temps de r\202agir, vous \212tes mort!$", + "A peine \212tes-vous au fond du puits qu'une main tranche la corde... Adieu la vie!$", + "La temp\212te recouvre vos traces . Un mur de silence s'abat sur vos \202paules . Lentement vous succombez \205 la morsure du froid !$", + "Pas si seul que \207a ! Une lame glac\202e s'enfonce dans votre dos. A l'avenir, soyez plus prudent!$", + "Vous ignorez la responsabilit\202 exacte de L\202o dans la mort de Murielle... Est-elle morte sur le coup ? De toutes fa\207ons les probl\212mes familiaux d\202couverts lors de votre enqu\212te justifient l'attitude de L\202o... Vous n'\212tes pas s\227r que Julia vous ait appel\202 pour \207a mais c'est suffisant pour vous ! Par respect pour elle, et apr\212s certaines pr\202cautions, vous avez une entrevue r\202v\202latrice avec L\202o$", + "$", + "Vous n'avez pas les clefs du Manoir . Vos appels restent sans r\202ponse . Vous allez attraper... la mort !$", + "D'un mouvement circulaire, l'\202p\202e vous fend par le travers : tripes et boyaux \205 l'air, bonjour les vers!$", + "Home, Sweet home !$", + "Myst\212re d'une porte close$", + "Charme envo\227tant de vieilles pi\212ces$", + "La faim au ventre$", + "Plus pr\212s du ciel? Pas s\227r !$", + "Peur du noir?$", + "Vieux tapis et reflets d'or$", + "Angoisse !$", + "Sauv\202 ? Pas certain !$", + "Mal \205 l'aise, hein !$", + "Toujours plus loin !$", + "Votre chemin de croix !$", + "A la d\202couverte de...$", + "Attention \205 ce que cache...$", + "Une descente aux Enfers !$", + "Si ce n'est pas dans vos cordes :@ ne soyez pas sot!$", + "Avant la mise en pi\212ce !$", + "Gros plan sur :$", + "Vous remarquez particuli\212rement...$", + "Et encore...$", + "C'est fini !$", + "Un peu de lecture$", + "L'aventure vous attend, vous partez...$", + "Ne ratez pas VOTRE prochaine AVENTURE...$", + "Je ne comprends pas$", + "Il y a plus simple$", + "Non ! Pas ce coup-ci$", + "Trop tard$", + "$", + "Comme un regard profond tout couvert de peaux-pierres, pointant son oeil obscur aux astres de lumi\212re, il est la gorge reliant le ciel et les enfers . Il faut aller au fond de cette art\212re comme un rat au coeur m\210me de la terre !@Lundi, Mardi, Mercredi, Dimanche du 1e lundi au 1e dimanche, tu installeras \"ce rat\" entre chacun des jours . N'omets rien car ta venue serait ta retenue !@Porte ton fardeau comme un oeuf nouveau et donne lui le jour avec force et amour.$", + "10/1/50: Nous avons r\202solu le myst\212re du manuscrit et localis\202 la crypte . Est-ce l'id\202e d'aboutir dans ce qui n'\202tait qu'un \"r\212ve\" qui me rend si anxieuse ?@Je regrette de m'\210tre engag\202e vis \205 vis de L\202o . Non! je dois continuer ! J'aurais d\227 mettre Guy au courant... mais, depuis une semaine, je n'ai aucune nouvelle .$", + "Porte ta pri\212re au lieu saint qui se doit, changes-en l'air, tu auras la mati\212re !@Du pilier de la haute sagesse, le soleil aux genoux te montrera l'espace par lequel ton \205me s'ouvrira un chemin et gagnera son \212re . Avance comme un Orph\202e peu soucieux des t\202n\212bres : le blanc est ta couleur, l'or ta demeure . Eclaire ton chemin jusqu'\205 la myst\202rieuse . Offre-lui le cercle de l'homme aux trois facettes . Qu'il regagne le monde et qu'il tourne avec lui dans la richesse premi\212re.$", + "Les montagnes sont les crocs d'une gueule dantesque ouverte \205 l'infini de quelqu' orgie c\202leste, mastiquant des \202toiles comme nous broyons du noir .@Tu d\202poseras l'accord de pierre \205 tes pieds, le rire du silence sur la gamme d'en haut et dans ta main droite, une toile d'un m\212tre . Tu passeras ainsi entre les deux croissants, par del\205 les ab\214mes du Mur du Silence . La Cl\202 des champs est \205 ta port\202e, tu n'as qu'\205 retrouver la note qui d\202note.$", + " DECEMBRE@ 9 REMISE 518 13 AGIOS 23@ 19 VIREMENT 1203 17 TRESOR 1598@ TOTAL 1721 TOTAL 1721$", + " Le 5/01/51@@ Luc, mon amour@ Guy conna\214t notre liaison . A la suite d'une dispute, je lui ai tout dit . Je ne pense qu'\205 toi ! Max me relance mais j'ai d\202finitivement rompu avec lui . Qu'il reste \205 ses gamelles . Quand pourrons-nous nous voir seuls ? Pour toi je divorcerai... Je t'aime .@ ton Eva$", + " Mortevielle, le 10/2/51@@ Pat,@ Je te rappelle que tu me dois 50000 F que je t'ai pr\202t\202s pour ton affaire . J'en ai besoin, peux-tu me les rendre assez vite?@ Guy$", + " Mortevielle, le 15/2/51@ Ma\214tre,@ Je vous \202cris au sujet de notre affaire. Je suis d\202cid\202 \205 aller jusqu'au bout, certain que mon associ\202, Pat DEFRANCK, a falsifi\202 un livre de comptes . Malgr\202$", + " Une pipe$", + " Un stylo \205 plume$", + " Un briquet \205 essence$", + " Une cornue$", + " Un blaireau$", + " Un pot de peinture$", + " Une flute$", + " Une bague de valeur$", + " Une bobine de fil$", + " Un vieux bouquin$", + " Un porte-monnaie$", + " Un poignard$", + " Un r\202volver$", + " Une bible$", + " Une bougie$", + " Un coffret \205 bijoux$", + " Un fer \205 repasser$", + " Une photo$", + " Une montre \205 gousset$", + " Une corde$", + " Des clefs$", + " Un collier de perles$", + " Un flacon de parfum$", + " Des jumelles$", + " Des lunettes$", + " Une bourse en cuir$", + " Une balle de tennis$", + " Des munitions$", + " Un rasoir \205 main$", + " Une brosse \205 cheveux$", + " Une brosse \205 linge$", + " Un jeu de cartes$", + " Un chausse pied$", + " Un tournevis$", + " Un marteau$", + " Des clefs$", + " Des clefs$", + " Un cendrier$", + " Un pinceau$", + " Une corde$", + " Un objet en bois$", + " Des somnif\212res$", + " Une bague en or$", + " Un coffret \205 bijoux$", + " Un r\202veil matin$", + " Une cotte de mailles$", + " Un chandellier$", + " Une paire de gants$", + " Une coupe cisel\202e$", + " Un parchemin$", + " Un poignard$", + " Un dossier$", + " Un parchemin$", + " Un parchemin$", + " Un dossier$", + " Un dossier$", + " Une lettre$", + " Un roman$", + " Une baguette en bois$", + " Une enveloppe$", + " Une lettre$", + " Une enveloppe$", + "Julia$", + "La mort de Julia$", + "Les relations de Julia$", + "Un message de Julia$", + "L'h\202ritage de Julia$", + "Derniers actes de Julia$", + "Les cadeaux de Julia$", + "La chambre de Julia$", + "La photo chez Julia$", + "Julia et vous...$", + "Les occupations de L\202o$", + "Les occupations de Pat$", + "Les occupations de Guy$", + "Les occupations de Bob$", + "Les occupations d'Eva$", + "Les occupations de Luc$", + "Les occupations d'Ida$", + "Les occupations de Max$", + "Vos occupations$", + "Les relations de L\202o$", + "Les relations de Pat$", + "Les relations de Guy$", + "Les relations de Bob$", + "Les relations d'Eva$", + "Les relations de Luc$", + "Les relations d'Ida$", + "Les relations de Max$", + "Vos relations$", + "Murielle$", + "Les relations de Murielle$", + "Murielle et vous...$", + "Disparition de Murielle$", + "Le mur du silence$", + "Les manuscrits$", + "Le blason$", + "Les gravures dans la cave$", + "Le puits$", + "Les passages secrets$", + "La chapelle$", + "Les tableaux$", + "La photo du grenier$", + "Le corps dans la crypte$", + "$", + "$", + "FIN DE LA CONVERSATION$", + "Les vieux appelaient ainsi la chaine de montagne qui se dresse au pied du manoir !$", + "C'est le massif montagneux que l'on aper\207oit devant le manoir$", + "Je n'en sais rien !$", + "Elle est morte d'une embolie pulmonaire$", + "Ma m\202re est morte soudainement . Son \202tat semblait pourtant s'\210tre am\202lior\202$", + "Madame DEFRANCK est morte d'un coup de froid$", + "Elle est morte d'une embolie pulmonaire$", + "Pardonnez moi mais je pr\202f\212re, actuellement garder le silence$", + "Ce sont toujours les meilleurs qui partent les premiers$", + "J'aimais beaucoup ma m\212re . Je regrette seulement qu'elle soit morte dans le manoir des DEFRANCK$", + "C'est une r\202gion qui a un pass\202 charg\202 et j'ai largement de quoi m'occuper . Et puis j'aime beaucoup les chevaux..$", + "C'est un passionn\202 d'histoire et un joueur inv\202t\202r\202 . D'ailleurs, voici un an il a gagn\202 une grosse somme$", + "Il a d\202j\205 beaucoup a faire avec la gestion et l'entretien du manoir...$", + "Je suis PDG d'une petite soci\202t\202 de parfums . Mais quand je suis ici, je me repose$", + "C'est un homme dynamique qui a r\202ussi dans le parfum$", + "Lui ! C'est un arriviste v\202reux ! Les parfums ont du endormir son bon sens . D'ailleurs ici il passe ses soir\202es dans sa chambre$", + "J'ai \202t\202 tr\212s pr\202occup\202 par la sant\202 de ma m\212re, et maintenant je n'ai plus go\226t \205 rien$", + "Il aurait mieux fait de s'occuper un peu plus de moi et un peu moins de sa m\212re$", + "Ce sont ses affaires...$", + "Il n'a pas trop de chance en ce moment bien que ses affaires soient satisfaisantes$", + "Je travaille avec Pat mais \207a ne va pas tr\212s fort en ce moment$", + "Ah oui ?! Il a des occupations ? Il ferait bien de s'en occuper s\202rieusement alors$", + "Lui et Pat sont associ\202s . Je crois que \207a ne va pas trop mal$", + "Je m'occupe de moi et c'est d\202j\205 beaucoup . Et vous ?$", + "Oh \207a ! Je lui fais confiance . Elle sait s'occuper$", + "Mais ! Vous n'avez pas encore d\202couvert son occupation principale..?$", + "Elle fait dans la d\202coration avec beaucoup dego\226t d'ailleurs. Elle est toujours tr\212s bien habill\202e$", + "Si les bijoux vous interessent, j'ai quelques affaires interessantes \205 saisir rapidement$", + "Les bijoux...$", + "Je ne sais pas, mais j'aimerais bien qu'il s'occupe un peu moins de mes affaires !$", + "Quand on est une femme d'int\202rieur on trouve toujours de quoi s'occuper...$", + "Elle pourrait rester sans rien faire, mais non ! Elle coud, elle lit ...$", + "Elle n'a s\226rement pas des occupations tr\212s \202panouissantes ...$", + "Une femme comme il n'y en a plus : Elle s'interesse a tout !$", + "Entre la cuisine et le m\202nage, je n'ai pas beaucoup de temps \205 vous accorder$", + "Je ne sais pas comment il s'y prend pour tout faire . C'est merveilleux !$", + "Il en ferait plus si il s'occupait moins des rag\223ts et de la bouteille$", + "Je suis tr\212s ind\202pendant . Tant qu'on ne s'occupe pas de mes affaires : Pas de probl\212me$", + "C'est un \202go\213ste . Je me demande si il aime autre chose que ses chevaux et ses grimoires$", + "Je crois qu'il s'entend bien avec tout le monde, mis \205 part, peut \210tre, avec Guy$", + "C'est un homme de caract\212re . Il faut savoir le prendre ..$", + "Les affaires sont les affaires . Quant \205 la famille, je la laisse pour ce qu'elle est ...$", + "Relations ? Relations amicales ? Relations financi\212res sans doute$", + "Moi je n'ai rien \205 lui reprocher$", + "C'est un homme d'affaire d\202brouillard . Il nage parfois \205 contre-courant mais ... il s'en sortira toujours$", + "Ils m'ennuient tous .. Non ! Ce n'est m\210me pas \207a .. Quoique .. certains ..$", + "A l'inverse de sa m\212re, c'est une personne tr\212s renferm\202e ! Alors question relations ..$", + "Il doit sans doute faire beaucoup d'effort pour rester agr\202able malgr\202 tous ses ennuis$", + "Ses relations amoureuses : C'est termin\202 . Ses relations avec moi : Pas vraiment commenc\202es . Quant aux autres : Je ne suis pas les \"autres\"$", + "J'aime bien tout le monde, tant qu'on ne m'escroque pas$", + "Il ne suffit pas d'avoir un peu d'argent et d'\210tre beau parleur pour plaire \205 tout le monde$", + "Sans histoire .. C'est quelqu'un d'agr\202able et g\202n\202reux . De plus, il ne manque pas d'humour$", + "Actuellement je m'entends plut\223t bien avec tout le monde . Mais, ici, je ne vais pas m'\202tendre sur le sujet$", + "Beau plumage, mais \207a ne vole pas haut ... Parlez en \205 son mari$", + "C'est pour un rendez-vous ?$", + "Elle est tr\212s vivante ! Elle ne s'embarrasse pas de pr\202jug\202s stupides$", + "Dans mon m\202tier, on c\223toit surtout des belles femmes et des truands$", + "La seule valeur s\226re chez lui, c'est ses bijoux .. Et sa femme, mais \207a il ne s'en rend pas compte$", + "C'est quelqu'un d'interessant . De pas toujours facile \205 comprendre, mais qui m\202rite le d\202tour$", + "Je ne d\202teste personne, mais j'aime les choses et les gens quand ils sont \205 leur place$", + "C'est entre nous . Mais voyez : quand je parle avec elle, je me sens vite \205 l'\202troit !$", + "Pour ne pas s'entendre avec elle, faut y mettre de la mauvaise volont\202$", + "Vous savez dans mon m\202tier on entend tout mais on ne retient rien, et le service est bien fait$", + "C'est un hypocrite, un larbin ! Personnellement je ne lui fais pas confiance$", + "Je ne connait pas le fond de sa pens\202e mais c'est quelqu'un de toujours tr\212s correct et impeccable$", + "C'\202tait une personne qui a v\202cu au manoir, il y a un an .. peut \210tre plus$", + "C'\202tait plus qu'une amie pour ma m\212re . En ces moments, j'aurais aim\202 qu'elle soit \205 mes cot\202s$", + "Murielle a \202t\202 la dame de compagnie de Julia$", + "Elle aussi, faisait des recherches ...$", + "C'\202tait une femme tr\212s cultiv\202e . Son brusque d\202part, il y a un an, m'a surpris et beaucoup chagrin\202$", + "Elle partageait avec L\202o sa passion de l'histoire et de la r\202gion$", + "Je crois que tout le monde l'aimait bien$", + "Elle s'entendait bien avec tout le monde . Elle aimait beaucoup son fils . Quant aux relations belle-m\212re, belle-fille ..$", + "A part L\202o, elle avait de tr\212s bon rapport avec Max ...$", + "Bien que vos relations furent peu soutenues, J\202r\223me, elle vous portait toujours dans son coeur ...$", + "A part sa famille, pas grand monde$", + "Ah oui ! Je crois qu'elle a beaucoup regrett\202 le d\202part de cette amie .. euh ! Marielle .. ou Mireille ...$", + "Non rien !$", + "Non ... Pas que le sache$", + "J'ai connu Julia en achetant le manoir . C'\202tait son seul bien . Mais toute ma fortune \202tait la sienne ...$", + "Si ce n'est quelques objets personnels, je crois qu'elle n'avait plus rien \205 elle$", + "Je crois que toute sa fortune venait de L\202o . Alors, Pfuuut !$", + "A part la lettre pour vous que j'ai post\202, rien de bien important !$", + "J'ai \202t\202 tr\212s heureuse qu'elle m'offre sa bible reli\202e$", + "Ca a \202t\202 rapide et elle n'a pas eu le temps de prendre des dispositions particuli\212res$", + "Son dernier pr\202sent m'a surpris$", + "Quel cadeau ?$", + "Un chandellier ...$", + "Oui, j'ai eu un cadeau . Ma femme a m\210me eu une bible$", + "Et bien oui ! Comme tout le monde, je crois$", + "Un poignard$", + "Je n'ai jamais \202t\202 fouiller dans le grenier !$", + "Vous avez un don de double-vue ou un passe-partout$", + "Le portrait d'une jeune fille : C'est Murielle ...$", + "Vous savez, je la connaissais assez peu$", + "Elle \202tait tr\212s charmante, mais c'\202tait surtout la dame de compagnie de Julia$", + "C'est la seule femme vraiment interessante que j'ai rencontr\202$", + "Elle avait de grandes connaissances historiques, et la consulter \202tait tr\212s enrichissant$", + "Je me suis toujours demand\202 ce que certains pouvaient lui trouver !$", + "Si la chambre est ferm\202e, demandez \205 L\202o$", + "J'ai ferm\202 sa chambre apr\212s sa mort et j'aimerais qu'il en soit ainsi encore un certain temps$", + "Vous savez ce que c'est : Des relations familiales$", + "Durant toutes ces ann\202es, je ne l'ai jamais servie \205 contre-coeur$", + "Je l'aimais autant qu'elle m'aimais, je crois$", + "De quel droit avez-vous p\202n\202tr\202 dans la chambre de ma femme ?!!$", + "C'est sans doute la photo de Murielle avec le filleul de Julia$", + "Je ne me rappelle pas$", + "C'est Murielle . C'est moi qui l'ai prise. et d'ailleurs elle est tir\202e \205 l'envers$", + "Vous \210tes bien curieux !... C'est sans valeur$", + "Grimoires, parchemins et manuscrits : C'est le domaine de L\202o$", + "Dommage que la devise soit manquante ...$", + "C'est tr\212s beau ... Et tr\212s vieux ...$", + "Tiens ! C'est un endroit que je n'ai jamais visit\202$", + "D'apr\202s L\202o, il semblerait que les Lunes soient plus r\202centes$", + "M\210me par ce temps, vous avez d\202nich\202 un soleil ...$", + "Profond et inqui\202tant : Le progr\212s a du bon$", + "Ca reste pour moi le plus grand des myst\212res$", + "Les derniers temps elle parlait d'un voyage . Et puis ...$", + "Il y a un peu plus d'un an, un soir, elle a d\202cid\202 de partir ...$", + "De toutes fa\207ons elle n'\202tait pas faite pour vivre ici$", + "Quoi ?! Quel corps ? Quel crypte ?$", + "Si il y en a, je ne les ai jamais trouv\202 ...$", + "Bien s\226r ! ... Et des fant\223mes aussi ...$", + "C'est la plus vielle de la r\202gion : Elle date du XI eme si\212cle$", + "Elle fut l\202g\212rement restaur\202e apr\212s la r\202volution$", + "Julia aimait beaucoup la peinture$", + "Ils ont diff\202rents styles, mais n'ont pas tous une tr\212s grande valeur$", + "Que faites-vous l\205 ?$", + "Je suis s\226r que vous cherchez quelque chose ici$", + "Je vous \202coute$", + "Que d\202sirez-vous ?$", + "Oui ?$", + "Je suis \205 vous ...$", + "C'est pourquoi ?$", + "Allez-y$", + "C'est \205 quel sujet ?$", + "Max : \205 votre service, monsieur$", + "De toutes fa\207ons vous n'avez rien \205 faire ici ! Sortez !!$", + "Vous \210tes trop curieux !$", + "J\202r\223me ! Il y a longtemps ... Quelle tristesse, Julia est morte . Sa famille est ici : Guy, son fils . Eva, sa brue . L\202o, son mari bien s\226r . Son beau fils, Pat . Des cousins : Bob, Ida, Luc . La temp\212te redouble, il vous faut rester . Les repas sont \205 12h et 19h et il y a un recueillement \205 la chapelle tous les jours \205 10h$", + "En vous voyant j'ai compris que vous decouvririez la v\202rit\202 ... Car je savais pourquoi vous veniez : J'avais retrouv\202 le brouillon de la lettre de Julia . Mais je suis tr\212s joueur, alors ... Elle n'avait pas voulu que votre t\203che soit trop facile, pour me prot\202ger, sans doute, mais elle n'a pu mourir avec cette incertitude sur la conscience . Avez vous d\202couvert que le mur du silence est le nom que les ma\207ons ont donn\202 au mur qui porte ce blason, lors de la construction du manoir ? .. Et ces cadeaux que Julia a laiss\202 avant de mourir \202taient autant de faux indices qui ne servaient qu'\205 faire ressortir l'importance des parchemins ... Effectivement, il y a plus d'un an, je travailais avec Murielle au d\202cryptage de ces manuscrits que je venais de trouver . Ma femme a fait la relation entre notre travail et la disparition de Murielle mais elle n'a jamais eu de preuves . Si ce n'est cette bague qu'elle a retrouv\202 un jour dans mes affaires . Une nuit, nous nous sommes aventur\202s dans le passage secret que nous avions d\202couvert . Murielle est morte par accident dans la pi\212ce de la vierge . J'ai r\202cup\202r\202 la bague rapidement, trouv\202 le tr\202sor et me suis enfuis . Je ne pensais pas qu'elle vivait encore, et je n'ai rien dit car j'avais besoin d'argent . J'ai fait passer cette somme sur le compte des courses de chevaux ...Partez maintenant, puisque vous n'\210tes pas de la police . Laissez moi seul !$", + "F\202vrier 1951 ... Profession : detective priv\202 . Le froid figeait Paris et mes affaires lorsque ...$", + "Une lettre, un appel, des souvenirs d'une enfance encore proche . Que de jeux dans les pi\212ces d\202labr\202es du manoir de Mortevielle . Julia, une vieille femme a pr\202sent .$", + " au bureau$", + " \205 la cuisine$", + " \205 la cave$", + " dans le couloir$", + " dehors$", + " la salle \205 manger$", + " dans le manoir$", + " devant le manoir$", + " \205 la chapelle$", + " devant le puits$", + " au nord$", + " derri\212re le manoir$", + " au sud$", + " \205 l'est$", + " \205 l'ouest$", + " vers le manoir$", + " plus loin$", + " dans l'eau$", + " hors du puits$", + " dans le puits$", + " choix sur \202cran$", + " Dans la serie MYSTERE...$", + " LE MANOIR DE MORTEVIELLE$", + "$", + " Sur une idee de...$", + " Bernard GRELAUD et Bruno GOURIER$", + "$", + " Realisation: LANKHOR$", + "$", + " Avec la participation de...$", + " Beatrice et Jean-Luc LANGLOIS$", + " pour la musique et les voix,$", + " Bernard GRELAUD pour la conception graphique,$", + " MARIA-DOLORES pour la realisation graphique,$", + " Bruno GOURIER pour la realisation technique,$", + " Clement ROQUES pour l'adaptation sur IBM PC et compatibles .$", + "$", + " Edition: LANKHOR$", + " COPYRIGHT 1988: LANKHOR$", + "$", + " A VOUS DE JOUER$", + " attacher$", + " attendre$", + " d\202foncer$", + " dormir$", + " \202couter$", + " entrer$", + " fermer$", + " fouiller$", + " frapper$", + " gratter$", + " lire$", + " manger$", + " mettre$", + " ouvrir$", + " prendre$", + " regarder$", + " sentir$", + " sonder$", + " sortir$", + " soulever$", + " tourner$", + " se cacher$", + " fouiller$", + " lire$", + " poser$", + " regarder$", + " L\202o$", + " Pat$", + " Guy$", + " Eva$", + " Bob$", + " Luc$", + " Ida$", + " Max$", + "Comment Julia est-elle morte ?$", + "Elle s'est suicid\202e$", + "Elle est morte assassin\202e$", + "Elle est morte accidentellement$", + "Elle est morte naturellement$", + "D'o\227 provenait l'argent qui a permis la restauration du manoir ?$", + "chantage$", + "travail$", + "h\202ritage$", + "courses$", + "rentes$", + "hold-up$", + "d\202couverte$", + "Quel est le hobby de L\202o ?$", + "recherches historiques$", + "politique$", + "peinture$", + "drogue$", + "sciences occultes$", + "direction d'une secte$", + "Julia a laiss\202 une s\202rie d'indices . Ceux-ci sont repr\202sent\202s en un seul lieu . Lequel ?$", + "Chapelle$", + "Ext\202rieur$", + "Cave$", + "Grenier$", + "Cuisine$", + "Salle \205 manger$", + "Chambre Julia$", + "Chambre L\202o$", + "Chambre Pat$", + "Chambre Bob$", + "Chambre Max$", + "Chambre Luc/Ida$", + "Chambre Guy/Eva$", + "L'indice principal qui vous a permis d'arriver \205 la porte du souterrain est :$", + "Un poignard$", + "Une bague$", + "Un livre$", + "Un parchemin$", + "Une lettre$", + "Un pendule$", + "Combien y avait-il de parchemin dans le manoir ?$", + "Aucun$", + "Un seul$", + "Deux$", + "Trois$", + "Quatre$", + "Cinq$", + "Combien de personnes sont m\202l\202es \205 cette histoire - Julia y comprise, vous except\202 - ?$", + "Neuf$", + "Dix$", + "Onze$", + "Quel \202tait le pr\202nom de la personne inconnue ?$", + "Mireille$", + "Fran\207oise$", + "Maguy$", + "Emilie$", + "Murielle$", + "Sophie$", + "De qui Murielle \202tait-elle la ma\214tresse ?$", + "Bob$", + "Luc$", + "Guy$", + "L\202o$", + "Max$", + "Murielle partageait une occupation avec une autre personne . Qui ?$", + "[1][ |Seul le hazard vous a permis d'arriver ici . Vous pr\202f\202rez|retourner enqu\202ter afin de mieux comprendre ...][ok]$", + "[1][ |Ins\202rez la disquette 1 dans le lecteur A][ok]$", + "[1][ |! ERREUR DISQUETTE !|On arrete tout][ok]$", + "[1][ |Vous devriez avoir remarqu\202|00% des indices][ok]$", + "[1][ |Ins\202rez la disquette 2 dans le lecteur A][ok]$", + "[1][ |Avant d'aller plus loin, vous faites|un point sur l'\202tat de vos connaissances][ok]$", + " MASTER .$", + " rorL$", +}; + +const char *gameDataDe[] = { + "Ruhe vor dem Sturm$", + "Geschmacklose Farben$", + "Lila, der letzte Versuch$", + "Diesen Ort bitte sauberhalten...$", + "Beaengstigendes schwarzes Loch$", + "Der blaue Salon$", + "Das blutrote Zimmer$", + "Wassersport$", + "Der gruene Star$", + "Ein Auge aufs Verbotene werfen$", + "Geruch von Kaminfeuer und Tabak$", + "Tabak und alte Buecher$", + "Zwiebeln, Zimt und Spirituosen$", + "Ein wenig besuchter Ort$", + "Feuchtigkeit und Moder$", + "Hausieren verboten!$", + "Ein verwester Koerper: toedliche Kryptomanie!$", + "Da wird einem angst$", + "Es ist schon offen$", + "Achtung: Lawinen$", + "Ein Hauch von \"Heiligkeit\"$", + "Eine grosses eindrucksvolles Gemaeuer...$", + "Die Kehrseite des Geheimnisses!$", + "Ein merkwuerdiges Horoskop!$", + "Der Krug geht so lange...$", + "Eine Eichentuer$", + "Ein Foto$", + "Die Wappen$", + "$", + "Max, der Diener, empfaengt Sie und wird Sie dann in Ihr Zimmer begleiten$", + " Morteville 16/2/51@ Mein lieber Jer\223me@Im Anschluss an mein Telegramm teile ich Ihnen die Gruende meiner Unruhe mit: vor 1 Jahr verschwand meine Gesellschafterin Murielle. Eventuell hat das Verschwinden etwas mit dem finanziel len Umschwung auf dem Landsitz zu tun, oder... Eine Stille, die schwer zu verstehen ist fuer mei-nen Sohn Guy. Da ich bis heute nichts bezueglich dieser Sache unternehmen konnte, zaehle ich auf Sie, um die Affaere zu regeln. Falls sich mein Gesundheitszustand nicht bessert, treffen Sie bitte die Entscheidungen, die Sie fuer richtig halten. @ In Freundschaft. JULIA DEFRANCK$", + "Spaeter erzaehlt Ihnen Guy von Leo's Selbstmord nach einer verrueckten Wette beim Rennen!$", + "F3: WIEDERHOLUNG@F8: STOP$", + "Der Hausherr$", + "Der Zukuenftige Erbe$", + "Julias Sohn$", + "Ein niedliches Maedchen!$", + "Superman!$", + "Der Mann von Ida$", + "Interessante Aeusserungen?$", + "Service inbegriffen!$", + "Nichts darunter!$", + "Kein Mucks...$", + "Eine halbe Stunde spaeter: nichts! Warten Sie immer noch?$", + "Bewundern Sie! Denken Sie nach!$", + "Nein! Nichts!$", + "Unmoeglich$", + "Das macht Flecken!$", + "Eine Abhandlung ueber die Geschichte der Gegend$", + "Einige Muenzen$", + "Erstes Gebot...$", + "Das riecht gut!$", + "Pik, Herz...$", + "Es mangelt nicht an Pillen!$", + "Ein Liebesroman$", + "Pusten heisst noch nicht spielen$", + "Kein Erfolg!$", + "Vorsicht vor Ueberraschungen!$", + "Dunkel und tief...$", + "Normale Gefuehle$", + "Sniff!$", + "Unverschaemt! Begnuegen Sie sich mit anschauen!$", + "Gesundheit! St... Staub$", + "Das Bild ist unterzeichnet... aber nicht die Tapeten$", + "Kein Glueck, Nichts!$", + "Seien Sie diskreter!$", + "Die Vorhaenge sind geschlossen$", + "Schnee! Und noch mehr Schnee!$", + "Genial: ein Bild vom Meister!$", + "Kein Zweifel, das ist eine Faelschung!$", + "Hum! Sie stutzen - Antikes oder Schund?$", + "Ein selten wertvolles Stueck!$", + "Nichts Bemerkenswertes$", + "Waesche, persoenliche Objekte...$", + "Nicht irgendwo!$", + "Das ist nicht der Zeitpunkt!$", + "Man spricht nicht mit vollem Mund! Nenn erst einmal das essen beendet ist$", + "Jemand kommt rein, beeilt sich und geht wieder raus$", + "Man naehert sich Ihrem Versteck!$", + "Man ueberrascht Sie!$", + "Unmoeglich! Sie sind ueberlastet!$", + "Versuchen Sie es aufs neue$", + "Sie sind perplex!?$", + "Sie verlassen Morteville. In Paris erwartet Sie eine Nachricht...$", + "Sie tun sich weh!$", + "Nichts weiteres mehr hier$", + "Der Ton erscheint normal$", + "Es bewegt sich nicht$", + "Man antwortet Ihnen$", + "Nicht der Augenblick!$", + "Gleiches Material, andere Seite!$", + "Der Widerschein ist fleckig, aber der Rahmen ist aus Gold$", + "Nippsachen, wertlose Dinge...$", + "Sie erleiden einen Misserfolg!$", + "Hier stinkt es... Besser nicht anschauen!$", + "Haushaltsprodukte$", + "Da juckt Ihnen das Fell?$", + "Das ist esklemmt, zugefroren! Brrrr...$", + "Die Fensterrahmen sind blockiert!$", + "Papiere...$", + "Nein! Der Weihnachtsmann hat keine Schwierigkeiten!$", + "Da geht es auf einen Flur$", + "Geschirr, Silber...$", + "Nein! Das sind nicht die Reste von Julia!$", + "Eine alte Gravur$", + "Sie entdecken eine tiefe rhombenfoermige Oeffnung$", + "Die Mauer gleitet zur Seite! Eine Passage! Benutzen Sie sie?$", + "Der Durchgang schliesst sich$", + "Eine Geheimschublade. Ein Buechlein... Lesen Sie es?$", + "Die Schublade schliesst sich wieder$", + "Nichts! Blut und Haut kleben am Stein!$", + "Die Details lassen Sie darauf schliessen, dass der Tod nicht unmitte lbar eingetreten ist!$", + "Verdorbene Vorhaben?$", + "Hing ihr Leben an einem \"Finger\"?$", + "Ein Schatz sei verschwunden?$", + "Eine Ritze in Groesse einer Muenze!$", + "Einige Steine bewegen sich... Eine Krypta! Gehen Siehinein?$", + "Der Ring dreht sich, die Mauer schliesst sich wieder$", + "Eine Steinsaeule hinter dem Altar$", + "Es war laut...$", + "Besetzt!$", + "Versuchen Sie noch einmal Ihr Glueck?$", + "Zu tief!$", + "Die Mauer am Ende des Ganges dreht sich$", + "Nothing!$", + "Der einzigue!$", + "Das Objekt faellt hinunter...$", + "Sie haben nichts in den Haenden$", + "Es ist nicht offen$", + "Das ist schon etwas$", + "Die Tuer ist zu$", + "Keine Antwort$", + "Eine volle Holzkugel$", + "Es ist kein Platz mehr$", + "Eine, in der Mitte durchbohrte, Holzkugel$", + "? ?$", + "Sie sind dran!$", + "OK!$", + "Ploetzlich erscheint Max mit Ihrem Koffer : \"Danke fuer Ihren Besuch\" Privatdetektiv mit gutem Gespuer und zweifellos diskret. Demoralisiert verlassen Sie den Landsitz. Sie sind UNBEDEUTEND!$", + "Leo unterbricht Sie:\"Das Unwetterhat sich beruhigt. In 1 Stunde gehe ich in die Stadt. Halten Siesich bereit.\" Sie haben Zeit verloren...aber noch nicht das Leben$", + "Hochrotes Gesicht, fatale Grippe.Sie bleiben da. Ihre Nachforschun gen fallen ins Wasser$", + "Das Wasser steigt sehr schnell und daempft Ihre letzten Illusionen ... Bevor Sie Zeit haben, zu reagiren, sind Sie tot!$", + "Sie sind kaum auf dem Grund des Brunnens, als eine Hand das Seil durchschneidet. Leben, adieu!$", + "Der Sturm verwischt Ihre Spuren. Eine Mauer des Schweigens huellt Sie ein. Langsam sterben Sie den Erfrierungstod!$", + "Sie sind nicht so allein wie Sie denken. Eine kalte Klinge bohrt sich in Ihren Ruecken. Seien Sie in Zukunft vorsichtiger!$", + "Sie ignorieren die Schuld von Leoam Tode Murielles. War sie sofort tot? Auf jeden Fall gerechtfertigen die familiaeren Probleme, die waehrend Ihrer Untersuchung aufgedeckt wurden, die Haltung Leos. Sie sind nicht sicher, ob Julia Sie deswegen angerufen hat, aber es genuegt Ihnen. Aus Respekt fuer sie und nach einigen Vorsichtsmassnahmen, fuehren Sie ein aufschlussreiches Gespraech mit Leo.$", + "$", + "Sie haben keinen Schluessel fuer den Landsitz. Ihre Rufe bleiben ohne Antwort. Sie werden sterben.$", + "Mit einem fuerchterlichen Rundschlag spaltet Sie das Schwert entzwei - das Innere kehrt sich nach aussen.$", + "Home, Sweet home!$", + "Geheimnis einer geschlossenen Tuer$", + "Charme verzaubert die alten Zimmer$", + "Leerer Magen$", + "Naeher 'gen Himmel? Nicht sicher!$", + "Angst vorm Dunkeln?$", + "Alte Teppiche und Goldschimmer$", + "Angst!$", + "Gerettet? Nicht sicher!$", + "Man fuehlt sich unwohl, was!$", + "Immer noch weiter!$", + "Ihr Kreuzweg!$", + "Bei der Entdeckung von...$", + "Achtung, auf das was sich versteckt...$", + "Abstieg in die Hoelle!$", + "Na fuehlen Sie sich gut? Sie sehen etwas@ blass aus!$", + "Vor dem Eintreten!$", + "Zoom:$", + "Unter anderem bemerken Sie...$", + "Und noch mal...$", + "Es ist zu Ende!$", + "Ein wenig Lektuere$", + "Das Abenteuer wartet auf Sie: also los!$", + "Verpassen Sie nicht IHR naechstes ABENTEUER!$", + "Ich verstehe nicht$", + "Es gibt Einfacheres$", + "Nein! Nicht Diesmal$", + "Zu spaet$", + "$", + "Wie ein tiefer verschleierter Blick, sein lebloses Auge auf die Sterne gerichtet, ist er wie der Schlund, der Himmel und Hoelle verbindet. Du musst in diese Tiefe vordringen, so wie eine Ratte in die Erde. Montag, Dienstag, Mittwoch, Sonntag, vom 1. Montag bis zum 1. Sonntag -so wird jeder Tag durch das SEIN oder WERDEN bestimmt. Vebersieh nichts, denn sonst ist Dein Schicksal besiegelt.$", + "10/1/50: Wir haben das Mysterium des Manuskriptes geloest und die Krypta lokalisiert. Ist es der Gedanke, in diesem Traum mein Ziel zu erreichen, der mir so angst macht? Ich bedauere, dass ich mich gegenueber Leo so engagiert habe. Nein, ich muss weitermachen Ich haette Guy informieren muessen, aber ich habe seit einer Woche nichts mehr von ihm gehoert$", + "Trag deine Bitte an den heiligen Ort - so wirst Du mehr erfahren! Der Pfeiler der Weisheit und die Sonne an den Knien werden Dir die Stelle zeigen , die Deiner Seele den Weg in eine neue Welt oeffnen Vorwaerts Orpheus, ohne Angst vordem Ungewissen: Weiss ist Deine Farbe, Gold ist Dein Zuhause. Be-leuchte Deinen Weg, bis hin zur traurigen Jungfrau. Gib ihr den Kreis des Mannes mit den drei Gesichtern, auf dass er die Welt wieder erreicht und sich dreht in seinem urspruenglichen Reichtum$", + "Die Berge sind die Zaehne eines gigantischen unendlichen Schlundes, einer himmlischen Orgie, die Sterne verschlingend, so wie uns die Dunkelheit verschlingt. Du laesst das Seil der Steine zu Dei nen Fuessen fallen. Das Lachen der Stille und in Deiner rechten Hand das Werk eines Meisters. Anschliessend wirst Du zwischen den beiden Monden hindurchgehen; jenseits des Abgrundes der Mauer des Schweigens wirst Du den Schluessel zur Melodie findenes fehlt nur noch die passende Note...$", + " DEZEMBER@ 9 ABZUG 518 13 ZINSEN 23@19 VEBERWE. 1203 17 GUTHAB 1598@ TOTAL 1721 TOTAL 1721@$", + " 5/01/51@ Luc, mein Liebling@ Guy weiss von unserer Beziehung.Nach einem Streit habe ich ihm alles gesagt. Ich liebe nur Dich. Max sitzt mir dauernd auf dem Hals, aber ich habe definitiv mitihm gebrochen. Soll er doch bei seinen Toepfen bleiben. Wann koennen wir uns allein sehen? Wegen dir wuerde ich mich scheiden lassen@ Deine Eva$", + " Morteville, 10/2/51@ Pat@ Ich erinnere Dich daran, dass Du mir noch FF 5000,- schuldest, die ich Dir fuer Dein Geschaeft geliehen habe. Ich brauche sie jetzt. Kannst Du sie mir bitte moeglichst schnell wiedergeben?@ Guy$", + " Morteville, 15/2/51@ Lieber Herr@ Ich schreibe Ihnen unser Geschaeft betreffend. Ich bin entschlossen, bis zum Aeusserstenzu gehen, da ich mir sicher bin, dass mein Teilhaber, Pat Defranck ein Rechnungsbuch gefaelscht hat.$", + "Eine Pfeife$", + "Ein Fuellfederhalter$", + "Ein Gasfeuerzeug$", + "Eine Retorte$", + "Ein Rasierpinsel$", + "Ein Farbeimer$", + "Eine Floete$", + "Ein wertvoller Ring$", + "Eine Garnrolle$", + "Ein altes Buch$", + "Ein Portemonnaie$", + "Ein Dolch$", + "Ein Revolver$", + "Eine Bibel$", + "Eine Kerze$", + "Ein Schmuckkoffer$", + "Ein Buegeleisen$", + "Ein Foto$", + "Eine Taschenuhr$", + "Ein Seil$", + "Schluessel$", + "Ein Perlenkollier$", + "Ein Parfumflakon$", + "Ein Fernglas$", + "Eine Brille$", + "Ein Ledergeldbeutel$", + "Ein Tennisball$", + "Munition$", + "Ein Nassrasierer$", + "Eine Haarbuerste$", + "Eine Kleiderbuerste$", + "Ein Kartenspiel$", + "Ein Schuhanzieher$", + "Ein Schraubenzieher$", + "Ein Hammer$", + "Schluessel$", + "Schluessel$", + "Ein Aschenbecher$", + "Ein Pinsel$", + "Ein Seil$", + "Ein Gegenstand aus Holz$", + "Schlafmittel$", + "Ein goldener Ring$", + "Ein Schmuckkoffer$", + "Ein Wecker$", + "Ein Panzerhemd$", + "Ein Kerzenhalter$", + "Ein Paar Handschuhe$", + "Ein Ziselierter Becher$", + "Ein Pergament$", + "Ein Dolch$", + "Ein Dossier$", + "Ein Pergament$", + "Ein Pergament$", + "Ein Dossier$", + "Ein Dossier$", + "Ein Brief$", + "Ein Roman$", + "Ein Holzstock$", + "Ein Umschlag$", + "Ein Brief$", + "Ein Umschlag$", + "Julia$", + "Julias Tod$", + "Julias Beziehungen$", + "eine Nachricht von Julia$", + "Julias Erbschaft$", + "letzte Handlungen Julias$", + "Geschenk von Julia$", + "Julias Zimmer$", + "die Fotos bei Julia$", + "Julia und Sie...$", + "die Geschaefte von Leo$", + "die Geschaefte von Pat$", + "die Geschaefte von Guy$", + "die Geschaefte von Bob$", + "die Geschaefte von Eva$", + "die Geschaefte von Luc$", + "die Geschaefte von Ida$", + "die Geschaefte von Max$", + "Ihre Geschaefte$", + "Leos Beziehungen$", + "Pats Beziehungen$", + "Guys Beziehungen$", + "Bobs Beziehungen$", + "Evas Beziehungen$", + "Lucs Beziehungen$", + "Idas Beziehungen$", + "Maxs Beziehungen$", + "Ihre Beziehungen$", + "Murielle$", + "Murielles Beziehungen$", + "Murielle und Sie...$", + "Murielles Vershwinden$", + "Die Mauer des Schweigens$", + "Die manuskripte$", + "Das Wappen$", + "Die Inschriften im Keller$", + "Der Brunnen$", + "Die Geheimgaenge$", + "Die Kapelle$", + "Die Bilder$", + "Die Fotos vom Dachboden$", + "Koerper in der Krypta$", + "$", + "$", + "ENDE DER UNTERHALTUNG$", + "Die Alten nannten die Bergkette am Fusse des Landsitzes so.$", + "Das ist das Bergmassiv, das man vor dem Landsitz sieht.$", + "Ich weiss nichts davon.$", + "Sie ist an einer Lungenembolie gestorben.$", + "Meine Mutter ist ploetzlich gestorben, obwohl es schien, dass sich ihr Zustand verbesserte.$", + "Frau Defranck ist gestorben.$", + "Sie ist an einer Lungenembolie gestorben.$", + "Verzeihen Sie mir, aber ich ziehe es vor, im Moment Schweigen zu bewahren.$", + "Es sind immer die Guten, die als erste gehen muessen.$", + "Ich habe meine Mutter sehr geliebt; ich bedauere, dass sie auf dem Gut der Defrancks gestorben ist.$", + "Dies ist eine Gegend, die eine sehr bewegte Vergangenheit hat und es gibt genug Dinge, um die ich mich kuemmern kann und ausserdem liebe ich Pferde.$", + "Er interessiert sich sehr fuer Geschichte und er ist ein erfolgloser Spieler. Uebrigens hat er vor einem Jahr eine bedeutende Summe gewonnen.$", + "Er hat schon viel zu tun mit der Buchhaltung und der Verwaltung des Gutes.$", + "Ich bin Direktor einer Parfumfirma. Aber hier... Erholung.$", + "Ein dymamischer Mann, der in der Parfumbranche viel erreicht hat.$", + "Das ist ein uebler Emporkoemmling. Die Parfums muessen seinen gesunden Menschenverstand eingeschlaefert haben. Hier verbringt er seine Abende in seinem Zimmer.$", + "Vorher galt meine Hauptsorge der Gesundheit meiner Mutter. Jetzt finde ich an nichts mehr Gefallen.$", + "Er haette gut daran getan, sich ein bisschen mehr um mich zu kuemmern und etwas weniger um seine Mutter.$", + "Das sind seine Angelegenheiten.$", + "Er hat nicht viel Glueck im Moment, obwohl seine Geschaefte zufriedenstellend sind.$", + "Ich arbeite mit Pat. Es geht nicht besonders gut im Moment.$", + "Ah ja! Hat er Beschaeftigungen? Er taete besser daran, sich ernsthaft zu beschaeftigen.$", + "Er und Pat sind Geschaeftspartner. Ich glaube, es laeuft gar nicht mal schlecht.$", + "Ich kuemmere mich um mich und das ist schon genug. Und Sie?$", + "Oh, ich vetraue ihr. Sie versteht, sich zu beschaeftigen.$", + "Aber haben Sie noch nicht ihre Hauptbeschaeftigung entdeckt?$", + "Sie arbeitet in der Dekoration mit sehr viel Geschmack. Ausserdem ist sie immer sehr gut angezogen.$", + "Interessiert sie der Schmuck. Ich habe ein Geschaeft vorzuschlagen.$", + "Der Schmuck...$", + "Ich weiss nicht, aber ich glaube, ich wuerde es vorziehen, wenn er sich ein bisschen weniger um meine Angelegenheiten kuemmern wuerde.$", + "Eine Hausfrau hat immer zu tun.$", + "Sie koennte auch ohne Arbeit auskommen. Aber nein, sie naeht, sie liest...$", + "Sie hat sicherlich keine sehr erheiternden Taetigkeiten.$", + "Eine aussergewoehnliche Frau. Sie interessiert sich fuer alles.$", + "Zwischen Kueche und Haushalt habe ich nicht viel Zeit fuer sie.$", + "Wie schafft er es nur, alles zu machen? Oh Wunder!$", + "Er taete gut daran, wenn er sich weniger mit Klatsch und der Flasche beschaeftigen wuerde.$", + "Ich bin sehr selbstaendig. Solange man sich nicht um meine Angelegenheiten kuemmert, gibt es keine Probleme.$", + "Er ist ein Egoist. Ich frage mich, ob es fuer ihn noch etwas anderes gibt, als seine Pferde und seine Maerchenbuecher.$", + "Er versteht sich gut mit allen, ausser vielleicht mit Guy.$", + "Er ist ein Mann mit Charakter. Man muss ihn zu nehmen wissen.$", + "Geschaeft ist Geschaeft. Was die Familie anbetrifft...$", + "Beziehungen? Freundschaften? Finanzen zweifellos.$", + "Ich habe ihm nichts vorzuwerfen.$", + "Er ist ein pfiffiger Geschaeftsmann. Manchmal schwimmt er gegen den Strom, aber er weiss sich immer zu helfen.$", + "Sie langweilen mich alle. Nein, obwohl... einige...$", + "Im Gegensatz zur Mutter ist es eine sehr verschlossene Person. Also Frage: Beziehung.$", + "Er muss sich zweifellos sehr anstrengen, um trotz seiner Sorgen freundlich zu bleiben.$", + "Seine Liebesaffairen? Aus und vorbei. Mit mir? Es hat nie richtig angefangen. Was die anderen betrifft... ich bin nicht \"die anderen\".$", + "Ich mag jeden, solange man mich nicht betruegt.$", + "Es reicht nicht, ein bisschen Geld zu haben und ein guter Redner zu sein, um bei allen beliebt zu sein.$", + "Jemand, der nett ist und ausserdem noch Humor hat.$", + "Ueber diese Sache kann ich mich nicht auslassen.$", + "Das ist nicht besonders intelligent. Sprechen Sie mit dem Ehemann darueber.$", + "Ist es wegen eines Rendez-vous?$", + "Sie ist sehr lebhaft. sie laesst sich nicht durch Vorurteile in Verwirrung brignen.$", + "In meinem Beruf ist man vor allem schoenen Frauen und Gaunern sehr nahe.$", + "Sein einziges Vermoegen sind sein Schmuck und seine Frau, aber er ist sich dessen nicht bewusst.$", + "Jemand interessantes, aber nicht immer leicht zu verstehen, der aber die Muehe wert ist.$", + "Ich verachte niemanden, aber ich mag es sehr, wenn alles und alle dort sind, wo sie hingehoeren.$", + "Unter uns.. sehen Sie, wenn ich mit ihr spreche, fuehle ich mich schnell beengt.$", + "Um sich nicht mit ihr zu verstehen, braucht man wirklich viel schlechten Willen.$", + "In meinem Beruf hoert man alles, aber behaelt nichts. Nur der Service zaehlt.$", + "Das ist ein Heuchler, ein Kriecher. Ich persoenlich habe kein Vertrauen zu Ihm.$", + "Ich kenne seine wahren Gedanken nicht, aber er war stets korrekt.$", + "Sie hat vor einem Jahr, vielleicht laenger, auf dem Landsitz gewohnt.$", + "Mehr als eine Freundin fuer meine Mutter. In solchen Augenblicken haette ich gewuenscht, dass sie da ist.$", + "Sie war die Hausdame von Julia.$", + "Sie hat ebenfalls Recherchen angestellt. Aber Guy, der sie besser kennt als jeder andere, kann Ihnen mehr sagen.$", + "Ihre Beziehungen?... Sie war sehr kultiviert. Ihr ploetzliches Verschwinden vor einem Jahr hat mich erstaunt.$", + "Sie teilte mit Leo ihre Leidenschaft fuer Geschichte und fuer die Gegend.$", + "Ich glaube, jeder hatte sie gern.$", + "Sie verstand sich mit allen gut, aber ganz besonders liebte sie ihren Sohn. Was die Beziehungen Schwiegermutter Scwiegertochter anbetrifft...$", + "Ausser zu Leo hatte sie auch gute Beziehungen zu Max.$", + "Obwohl ihre Beziehungen nicht von Dauer waren, lag ihr immer viel an ihnen.$", + "Ausser ihrer Familie, nicht viele.$", + "Aber ja. Sie hat das Weggehen dieser Freundin sehr bedauert. Eh, Mireille, oder Marielle.$", + "Nein, nichts.$", + "Nein, nicht das ich wuesste.$", + "Ich habe Julia kennengelernt, als ich das Landgut kaufte. Es war das einzige, was ihr gehoerte, aber mein Besitz war auch der ihre.$", + "Wenn nicht einige persoenliche Dinge gewesen waeren, ich glaube, dann haette sie nichts eigenes mehr gehabt.$", + "Ich glaube, all ihr Reichtum kam von Leo. Also!$", + "Ausser des Briefes, den ich fuer sie aufgegeben habe, nichts wichtiges.$", + "Ich war gluecklich, als sie mir ihre eingebundene Bibel schenkte.$", + "Es ging schnell und sie hatte nicht die Zeit, um spezielle Entscheidungen zu treffen.$", + "Ihr letztes Geschenk hat mich ueberrascht.$", + "Was fuer ein Geschenk?$", + "Ein Kerzenleuchter.$", + "Ja, ich habe ein Geschenk bekommen. Meine Frau hat sogar eine Bibel bekommen.$", + "Aber ja. wie jeder, glaube ich.$", + "Ein Dolch$", + "Ich habe nie den Dachboden durchwuehlt.$", + "Haben Sie die Gabe eines Hellsehers, oder haben Sie einen Dietrich?$", + "Das Portrait einer jungen Frau? Das ist Murielle.$", + "Ich kannte sie zu wenig.$", + "Sehr charmant. Sie war vor allem die Hausdame von Julia.$", + "Das war die einzige wirklich interessante Frau, die ich getroffen habe.$", + "Sie hatte ein grosses Wissen vorzuweisen. Sie zu besuchen, war stets sehr bereichernd.$", + "Ich habe mich immer gefragt, was manche an ihr fanden.$", + "Das Zimmer ist verschlossen? Fragen Sie Leo.$", + "Ich habe ihr Zimmer nach ihrem Tod abgeschlossen und ich moechte, dass das auch noch eine zeitlang so bleibt.$", + "Wissen Sie, was das sind? Familienbeziehungen.$", + "In all den Jahren habe ich sie niemals gegen meinen Willen bedient.$", + "Ich habe sie so sehr geliebt, wie sie mich, glaube ich.$", + "Mit welchem Recht sind Sie in das Zimmer meiner Frau eingedrungen?$", + "Zweifellos das Foto von Murielle mit dem Patenkind von Julia.$", + "Ich erinnere mich nicht.$", + "Das ist Murielle. Ich war es, der sie fotografiert hat. Uebrigens ist das Foto seitenverkehrt abgezogen.$", + "Sie sind wirklich neugierig. Das ist wertlos.$", + "Maerchen, Pergamente und Manuskripte das ist Leos Spezialitaet.$", + "Schade, dass die Losung fehlt.$", + "Das ist sehr schoen und sehr alt.$", + "Das ist ein Ort, den ich nie gesehen habe.$", + "Leos Meinung nach schien es, als seien die Monde spaeter gemacht worden.$", + "M\210me par ce temps, vous avez d\202nich\202 un soleil ...$", + "Tief und beunruhigend. Der Fortschritt hat gutes an sich.$", + "Der Rest bleibt fuer mich eines der groessten Raetsel.$", + "In letzter Zeit sprach sie oft von einer Reise und dann...$", + "An einem Abend vor mehr als einem Jahr hat sie sich entschieden wegzugehen.$", + "Auf jeden Fall war sie fuer das Leben hier nicht geschaffen.$", + "Welcher Koerper? Welche Krypta?$", + "Wenn es sie ueberhaupt gibt, ich habe sie nie gefunden.$", + "Aber sicher! Und die Fantome auch.$", + "Es ist die aelteste der Stadt. Sie stammt aus dem 11. Jahrhundert.$", + "Nach der Revolution wurde sie leicht restauriert.$", + "Julia liebte die Malerei sehr.$", + "Sie haben verschiedene Stilrichtungen, aber sie haben nicht alle Wert.$", + "Was machen Sie da ?$", + "Ich bin sicher, Sie suchen etwas!$", + "Ich hoere.$", + "Was wuenschen Sie?$", + "Ja ?$", + "Ich stehe zu Ihrer Verfuegung.$", + "Weswegen?$", + "Na los doch!$", + "Wegen was?$", + "Max: Zu Ihren Diensten, Monsieur.$", + "Auf jeden Fall haben Sie hier nichts zu suchen! Gehen Sie raus!$", + "Sie sind zu neugierig!$", + "Jerome, es ist lange her. Wie traurig, Julia ist tot. Ihre Familie ist hier. Guy, ihr Sohn, und Eva, ihre Schwiegertochter. Leo, ihr Mann, sowie ihr Schwiegersohn Pat und die Cousins Bob, Ida und Luc. Das Unwetter verstaerkt sich. Sie muessen noch bleiben. Die Mahlzeiten sind um 12 Uhr und um 19 Uhr und es findet jeden Tag um 10 Uhr eine Andacht in der Kapelle statt.$", + "Als ich Sie sah, habe ich sofort begriffen, dass Sie die Wahrheit aufdecken wuerden, da ich wusste, warum Sie gekommen sind. Ich hatte den Entwurf von Julias Brief gefunden. Aber ich bin ein begeisterter Spieler, also.... Sie haette nicht gewollte, dass ihre Aufgabe zu leicht ausfaellt, zweifellos, um mich zu schuetzen, aber sie konnten nicht sterben mit dieser Ungewissheit.Haben Sie herausgefunden, dass die \"Mauer des Schweigens\" der Name ist, den die Maurer waehrend des Baus des Landsitzes der Mauer gegeben haben, die das Wappen traegt...? Und die Geschenke, die Julia vor ihrem Tod hinterlassen hat waren sowohl falsche Hinweise wie auch ein Mittel, um die Wichtigkeit der Pergamente herauszustellen. Tatsaechlich arbeitete ich vor mehr als einem Jahr mit Murielle an der Entzifferung dieser Pergamente, die ich gefunden hatte. Meine Frau sah einen Zusammenhang zwischen unserer Arbeit und dem Verschwinden Murielles,aber sie hat nie Beweise dafuer gehabt; wenn da nicht dieser Ring gewesen waere, den sie eines Tages unter meinen Sachen wiedergefunden hat. Eines nachts sind wir in dem Geheimgang, den wir entdeckt hatten,auf Erkundung gegangen. Murielle ist durch einen Unfall im \"Jungfrauenzimmer\" ums Leben gekommen. Ich habe ihren Ring schnell an mich genommen, habe den Schatz entdeckt und mich dann aus dem Staub gemacht. Ich dachte nicht daran, dass sie unter Umstaenden noch leben koennte, und ich habe nichts gesagt, da ich Geld brauchte. Ich habe das Geld beim Pferderennen verspielt. Gehen Sie jetzt, da sie ja nicht von der Polizei sind. Lassen Sie mich allein.$", + "Februar '51, Beruf: Privatdetektiv. Die Kaelte laesst Paris und meine Unternehmungen erstarren, als...$", + "Julia, heute eine alte Frau. Nichts als Erinnerungen und Spiele in den alten Zimmern des Landsitzes von Morteville.$", + "im Buero$", + "in der Kueche$", + "im Keller$", + "auf dem Flur$", + "draussen$", + "im Esszimmer$", + "im Landsitz$", + "vor dem Landsitz$", + "in der Kapelle$", + "vor dem Brunnen$", + "im Norden$", + "hinter dem Landsitz$", + "im Sueden$", + "im Osten$", + "im Westen$", + "in Richtung Landsitz$", + "noch weiter$", + "im Wasser$", + "ausser des Brunnens$", + "im Brunnen$", + "Wahl auf dem Bild$", + " In der Reihe RAETSEL...$", + " DER LANDSITZ VON MORTEVILLE$", + "$", + " Nach einer Idee von...$", + " Bernard GRELAUD und Bruno GOURIER$", + "$", + " Realisation: LANKHOR$", + "$", + " in Zusammenarbeit mit...$", + " Beatrice und Jean-Luc LANGLOIS Musik und Stimmen,$", + " Bernard GRELAUD graphische Gestaltung,$", + " Dominique SABLONS graphische Realisation ,$", + " Bruno GOURIER technische Realisation,$", + " Gabi NURGE Uebersetzung,$", + " Clement ROQUES IBM PC Realisation.$", + "$", + " Ausgabe: LANKHOR$", + " COPYRIGHT 1989: LANKHOR$", + "$", + " SIE SIND AM ZUG$", + "abkratzen$", + "anschauen$", + "ausgehen$", + "befestig.$", + "drehen$", + "durchsuch$", + "eindrueck$", + "eintreten$", + "essen$", + "fuehlen$", + "hochheben$", + "klopfen$", + "lesen$", + "nehmen$", + "oeffnen$", + "schlafen$", + "schliess.$", + "setzen$", + "sondieren$", + "warten$", + "zuhoeren$", + "anschauen$", + "durchsuch.$", + "hinlegen$", + "lesen$", + "s. verstec$", + "Leo$", + "Pat$", + "Guy$", + "Eva$", + "Bob$", + "Luc$", + "Ida$", + "Max$", + " JULIA$", + "hat sie Selbstmord begangen ?$", + "ist sie ermordet worden ?$", + "ist sie durch Unfall gestorben ?$", + "ist sie eines natuerlichen Todes gestorben ?$", + " Woher kam das Geld, das die restaurierung des landsitzes erlaubte ?$", + "Erpressung$", + "Arbeit$", + "Erbschaft$", + "Rennen$", + "Renten$", + "Raub$", + "Verschiedenes$", + " Was ist Leos Hobby ?$", + "Historische Recherchen$", + "Politik$", + "Malerei$", + "Drogen$", + "Okkultismus$", + "Fuehrung einer Sekte$", + " Julia Hat verschiedene Indizien hinterlassen. Diese befinden sich an einem einzigen Ort. Welchem ?$", + "Kapelle$", + "Draussen$", + "Keller$", + "Dachboden$", + "Kueche$", + "Esszimmer$", + "Julias Zimmer$", + "Leos Zimmer$", + "Pats Zimmer$", + "Bobs Zimmer$", + "Maxs Zimmer$", + "Luc/Idas Zimmer$", + "Guy/Evas Zimmer$", + " Der entscheidende Hinweis, der es Ihnen ermoeglichte, bis an die Tuer des Souterrains zu gelangen, war :$", + "ein Dolch$", + "ein Ring$", + "ein Buch$", + "ein Pergament$", + "ein Brief$", + "ein Pendel$", + " Wievele Pergamente befinden sich auf dem Landsitz ?$", + "kein$", + "eins$", + "zwei$", + "drei$", + "vier$", + "f\201nf$", + " Wieviele Personen sind in die Geschichte verwickelt ? (Julia eingeschlossen, ausgenommen Sie)$", + "neun$", + "zehn$", + "elf$", + " Wie war der Name der unbekannten Person ?$", + "Mireille$", + "Fran\207oise$", + "Maguy$", + "Emilie$", + "Murielle$", + "Sophie$", + " Wessen Geliebte war Murielle ?$", + "Bob$", + "Luc$", + "Guy$", + "Leo$", + "Max$", + " Murielle teilte eine Beschaeftigung mit einer anderen Person. Mit wem ?$", + "[1][Allein der Zufall hat es Ihnen ermoeglicht bis hierher zu komen.| Gehen Sie zurueck und forschen Sie noch einmal nach,|damit Sie das Gaze besser verstehen...][ok]$", + "[1][Legen Sie die Diskette 1 ein][ok]$", + "[1][Problem mit der Diskette | Alles abstellen...][OK]$", + "[1][Sie haetten 00% der Hinweise| bemerken muessen][ OK ]$", + "[1][Legen Sie die Diskette 2 ein][ok]$", + "[1][Bevor Sie weitermachen, fassen Sie Ihre Kenntnisse Zusammen][ok]$", + " MASTER .$", + " sgaf", + NULL +}; +#endif diff --git a/devtools/create_mortdat/menudata.h b/devtools/create_mortdat/menudata.h new file mode 100644 index 0000000000..6a5f8dcfad --- /dev/null +++ b/devtools/create_mortdat/menudata.h @@ -0,0 +1,93 @@ +/* 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 is a utility for extracting needed resource data from different language + * version of the Mortevielle executable files into a new file mort.dat - this + * is required for the ScummVM Mortevielle module to work properly + */ + +#ifndef MENUDATA_H +#define MENUDATA_H + +const char *menuDataEn = + " @@@ " + " @ " + " @ @ @@ @@@ @@@ " + " @ @ @ @ @ " + " @ @ @ @ @ " + " @ @ @ @ @ " + "@@@ @@@ @@ @@ " + " " + " @@ @@ " + " @@ @ @ " + " @ @ @ @ @@@ @@@ @@@" + " @ @ @ @ @ @ @ " + " @ @ @ @ @ @ " + " @ @ @ @ @ @ " + "@@@ @@@ @@@@ @@ " + " " + " @ @ " + " @@ @ " + " @ @ @@@@ @@@@ " + " @ @ @ @ @ " + " @@@@@ @ @ " + " @ @ @ @ @ " + "@@@ @@@ @@@ @@ " + " " + " @@@@@ @@@ @@@" + " @ @ @ @ @" + " @ @@@ @ @ " + " @@@@ @ @ @ @@@ " + " @ @@@@@ @ @ " + " @ @ @ @ @ " + "@@@@@@ @@@ @@@ @@@ " + " " + "@@@@@@@ @@@ @@@ " + "@ @ @ @ @ " + " @ @@@@ @ @ @@" + " @ @ @ @ @@ @ " + " @ @ @ @ @ @@ " + " @ @ @ @ @ @ " + "@@@ @@@@ @@@ @@@ @@@" + " " + " @@@@@@@ @ @@@ " + " @ @ @ " + " @ @ @@ @ @@@ " + " @@@@ @ @ @ @" + " @ @ @ @ @@@@@ " + " @ @ @ @ " + "@@@ @@@ @@@ @@@ " + " "; + +const int verbsFr[26] = { 0x301, 0x302, 0x303, 0x304, 0x305, 0x306, 0x307, 0x308, + 0x309, 0x30a, 0x30b, 0x30c, 0x30d, 0x30e, 0x30f, 0x310, + 0x311, 0x312, 0x313, 0x314, 0x315, 0x401, 0x402, 0x403, + 0x404, 0x405 }; + +const int verbsEn[26] = { 0x301, 0x315, 0x305, 0x310, 0x309, 0x304, 0x302, 0x30f, + 0x306, 0x30d, 0x30e, 0x303, 0x30c, 0x30b, 0x313, 0x30a, + 0x311, 0x312, 0x307, 0x308, 0x314, 0x401, 0x405, 0x404, + 0x403, 0x402 }; + +const int verbsDe[26] = { 0x30a, 0x310, 0x313, 0x301, 0x315, 0x308, 0x303, 0x306, + 0x30c, 0x311, 0x314, 0x309, 0x30b, 0x30f, 0x30e, 0x304, + 0x307, 0x30d, 0x312, 0x302, 0x305, 0x405, 0x402, 0x404, + 0x403, 0x401 }; +#endif diff --git a/devtools/create_mortdat/module.mk b/devtools/create_mortdat/module.mk new file mode 100644 index 0000000000..86b14d8284 --- /dev/null +++ b/devtools/create_mortdat/module.mk @@ -0,0 +1,11 @@ + +MODULE := devtools/create_mortdat + +MODULE_OBJS := \ + create_mortdat.o \ + +# Set the name of the executable +TOOL_EXECUTABLE := create_mortdat + +# Include common rules +include $(srcdir)/rules.mk diff --git a/devtools/create_neverhood/create_neverhood.cpp b/devtools/create_neverhood/create_neverhood.cpp index 323066d8b1..446ee5ec3b 100644 --- a/devtools/create_neverhood/create_neverhood.cpp +++ b/devtools/create_neverhood/create_neverhood.cpp @@ -32,10 +32,16 @@ #include <vector> #include "create_neverhood.h" +#include "md5.h" #include "tables.h" const int DAT_VERSION = 0; +// The MD5 hash of the nhc.exe used to extract the tables from +const uint8 kNhcExeMd5[16] = { + 0x37, 0xD6, 0x54, 0xA2, 0xA7, 0xBB, 0xB0, 0x1F, + 0x8C, 0x41, 0x9A, 0xB8, 0x49, 0xFF, 0x29, 0xD4}; + uint32 dataSize; byte *data; uint32 dataStart = 0x004AE000; @@ -48,12 +54,33 @@ class NavigationList; void addMessageList(uint32 messageListCount, uint32 messageListOffset); -void loadExe(const char *filename) { +bool loadExe(const char *filename) { FILE *exe = fopen(filename, "rb"); + if (!exe) { + printf("Could not open nhc.exe for reading! Quitting...\n"); + return false; + } dataSize = fileSize(exe); data = new byte[dataSize]; fread(data, dataSize, 1, exe); fclose(exe); + return true; +} + +bool validateMd5() { + uint8 digest[16]; + + md5_buffer(data, dataSize, digest); + + printf("MD5 of nhc.exe is %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], + digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]); + + if (memcmp(kNhcExeMd5, digest, 16)) { + printf("MD5 hash of nhc.exe doesn't match the expected value! Quitting...\n"); + return false; + } + return true; } byte *getData(uint32 offset) { @@ -85,7 +112,7 @@ uint32 calcHash(const char *value) { struct HitRect { int16 x1, y1, x2, y2; uint16 messageNum; - + void load(uint32 offset) { byte *item = getData(offset); x1 = READ_LE_UINT16(item + 0); @@ -93,7 +120,7 @@ struct HitRect { x2 = READ_LE_UINT16(item + 4); y2 = READ_LE_UINT16(item + 6); messageNum = READ_LE_UINT16(item + 8); - } + } void save(FILE *fd) { writeUint16LE(fd, x1); @@ -102,11 +129,11 @@ struct HitRect { writeUint16LE(fd, y2); writeUint16LE(fd, messageNum); } - + int getItemSize() const { return 10; } - + }; struct MessageItem { @@ -114,22 +141,22 @@ struct MessageItem { uint32 messageParam; MessageItem() {} MessageItem(uint16 msgNum, uint32 msgParam) : messageNum(msgNum), messageParam(msgParam) {} - + void load(uint32 offset) { byte *item = getData(offset); messageNum = READ_LE_UINT16(item + 0); messageParam = READ_LE_UINT32(item + 4); - } + } void save(FILE *fd) { writeUint16LE(fd, messageNum); writeUint32LE(fd, messageParam); } - + int getItemSize() const { return 8; } - + }; struct SubRectItem { @@ -148,7 +175,7 @@ struct SubRectItem { // Add the message to the message list addMessageList(messageListCount, messageListOffset); } - + void save(FILE *fd) { writeUint16LE(fd, x1); writeUint16LE(fd, y1); @@ -156,11 +183,11 @@ struct SubRectItem { writeUint16LE(fd, y2); writeUint32LE(fd, messageListOffset); } - + int getItemSize() const { return 16; } - + }; struct RectItem { @@ -185,7 +212,7 @@ struct RectItem { subItemOffset += 16; subRectItems.push_back(subRectItem); } - } + } void save(FILE *fd) { writeUint16LE(fd, x1); @@ -196,11 +223,11 @@ struct RectItem { for (uint32 j = 0; j < subRectItems.size(); j++) subRectItems[j].save(fd); } - + int getItemSize() const { return 16; } - + }; struct NavigationItem { @@ -211,10 +238,10 @@ struct NavigationItem { byte interactive; byte middleFlag; uint32 mouseCursorFileHash; - + void load(uint32 offset) { byte *item = getData(offset); - fileHash = READ_LE_UINT32(item + 0); + fileHash = READ_LE_UINT32(item + 0); leftSmackerFileHash = READ_LE_UINT32(item + 4); rightSmackerFileHash = READ_LE_UINT32(item + 8); middleSmackerFileHash = READ_LE_UINT32(item + 12); @@ -236,7 +263,7 @@ struct NavigationItem { int getItemSize() const { return 24; } - + }; struct SceneInfo140Item { @@ -320,24 +347,24 @@ struct SceneInfo2700Item { template<class ITEMCLASS> class StaticDataList { public: - uint32 id; + uint32 id; std::vector<ITEMCLASS> items; - + virtual ~StaticDataList() { } - + void add(ITEMCLASS item) { items.push_back(item); } - + int getCount() const { return items.size(); } - + ITEMCLASS *getListItem(int index) { return &items[index]; } - + virtual bool specialLoadList(uint32 count, uint32 offset) { return false; } @@ -371,7 +398,7 @@ class RectList : public StaticDataList<RectItem> { }; class MessageList : public StaticDataList<MessageItem> { -public: +public: virtual bool specialLoadList(uint32 count, uint32 offset) { // Special code for message lists which are set at runtime (but otherwise constant) @@ -428,7 +455,7 @@ public: } return false; } - + }; class NavigationList : public StaticDataList<NavigationItem> { @@ -438,11 +465,11 @@ template<class LISTCLASS> class StaticDataListVector { public: std::vector<LISTCLASS*> lists; - + void add(LISTCLASS *list) { lists.push_back(list); } - + void loadListVector(const uint32 *offsets) { for (int i = 0; offsets[i] != 0; i += 2) { LISTCLASS *list = new LISTCLASS(); @@ -459,7 +486,7 @@ public: lists.push_back(list); } } - + void saveListVector(FILE *fd) { writeUint32LE(fd, lists.size()); for (typename std::vector<LISTCLASS*>::iterator it = lists.begin(); it != lists.end(); it++) { @@ -473,7 +500,7 @@ template<class ITEMCLASS> class StaticDataVector { public: std::vector<ITEMCLASS> items; - + void loadVector(const uint32 *offsets) { for (int i = 0; offsets[i] != 0; i++) { ITEMCLASS item; @@ -481,7 +508,7 @@ public: items.push_back(item); } } - + void saveVector(FILE *fd) { writeUint32LE(fd, items.size()); for (typename std::vector<ITEMCLASS>::iterator it = items.begin(); it != items.end(); it++) { @@ -495,8 +522,8 @@ StaticDataListVector<HitRectList> hitRectLists; StaticDataListVector<RectList> rectLists; StaticDataListVector<MessageList> messageLists; StaticDataListVector<NavigationList> navigationLists; -StaticDataVector<SceneInfo140Item> sceneInfo140Items; -StaticDataVector<SceneInfo2700Item> sceneInfo2700Items; +StaticDataVector<SceneInfo140Item> sceneInfo140Items; +StaticDataVector<SceneInfo2700Item> sceneInfo2700Items; void addMessageList(uint32 messageListCount, uint32 messageListOffset) { MessageList *messageList = new MessageList(); @@ -506,9 +533,11 @@ void addMessageList(uint32 messageListCount, uint32 messageListOffset) { int main(int argc, char *argv[]) { - FILE *datFile; + if (!loadExe("nhc.exe") || + !validateMd5()) + return 1; - loadExe("nhc.exe"); + FILE *datFile; hitRectLists.loadListVector(hitRectListOffsets); rectLists.loadListVector(rectListOffsets); @@ -516,12 +545,12 @@ int main(int argc, char *argv[]) { navigationLists.loadListVector(navigationListOffsets); sceneInfo140Items.loadVector(sceneInfo140Offsets); sceneInfo2700Items.loadVector(sceneInfo2700Offsets); - + datFile = fopen("neverhood.dat", "wb"); writeUint32LE(datFile, 0x11223344); // Some magic writeUint32LE(datFile, DAT_VERSION); - + messageLists.saveListVector(datFile); rectLists.saveListVector(datFile); hitRectLists.saveListVector(datFile); diff --git a/devtools/create_neverhood/md5.cpp b/devtools/create_neverhood/md5.cpp new file mode 100644 index 0000000000..50f7406a47 --- /dev/null +++ b/devtools/create_neverhood/md5.cpp @@ -0,0 +1,273 @@ +/* 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. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "md5.h" + +#define GET_UINT32(n, b, i) (n) = READ_LE_UINT32(b + i) +#define PUT_UINT32(n, b, i) WRITE_LE_UINT32(b + i, n) + +void md5_starts(md5_context *ctx) { + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +static void md5_process(md5_context *ctx, const uint8 data[64]) { + uint32 X[16], A, B, C, D; + + GET_UINT32(X[0], data, 0); + GET_UINT32(X[1], data, 4); + GET_UINT32(X[2], data, 8); + GET_UINT32(X[3], data, 12); + GET_UINT32(X[4], data, 16); + GET_UINT32(X[5], data, 20); + GET_UINT32(X[6], data, 24); + GET_UINT32(X[7], data, 28); + GET_UINT32(X[8], data, 32); + GET_UINT32(X[9], data, 36); + GET_UINT32(X[10], data, 40); + GET_UINT32(X[11], data, 44); + GET_UINT32(X[12], data, 48); + GET_UINT32(X[13], data, 52); + GET_UINT32(X[14], data, 56); + GET_UINT32(X[15], data, 60); + +#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define P(a, b, c, d, k, s, t) \ +{ \ + a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x, y, z) (z ^ (x & (y ^ z))) + + P(A, B, C, D, 0, 7, 0xD76AA478); + P(D, A, B, C, 1, 12, 0xE8C7B756); + P(C, D, A, B, 2, 17, 0x242070DB); + P(B, C, D, A, 3, 22, 0xC1BDCEEE); + P(A, B, C, D, 4, 7, 0xF57C0FAF); + P(D, A, B, C, 5, 12, 0x4787C62A); + P(C, D, A, B, 6, 17, 0xA8304613); + P(B, C, D, A, 7, 22, 0xFD469501); + P(A, B, C, D, 8, 7, 0x698098D8); + P(D, A, B, C, 9, 12, 0x8B44F7AF); + P(C, D, A, B, 10, 17, 0xFFFF5BB1); + P(B, C, D, A, 11, 22, 0x895CD7BE); + P(A, B, C, D, 12, 7, 0x6B901122); + P(D, A, B, C, 13, 12, 0xFD987193); + P(C, D, A, B, 14, 17, 0xA679438E); + P(B, C, D, A, 15, 22, 0x49B40821); + +#undef F + +#define F(x, y, z) (y ^ (z & (x ^ y))) + + P(A, B, C, D, 1, 5, 0xF61E2562); + P(D, A, B, C, 6, 9, 0xC040B340); + P(C, D, A, B, 11, 14, 0x265E5A51); + P(B, C, D, A, 0, 20, 0xE9B6C7AA); + P(A, B, C, D, 5, 5, 0xD62F105D); + P(D, A, B, C, 10, 9, 0x02441453); + P(C, D, A, B, 15, 14, 0xD8A1E681); + P(B, C, D, A, 4, 20, 0xE7D3FBC8); + P(A, B, C, D, 9, 5, 0x21E1CDE6); + P(D, A, B, C, 14, 9, 0xC33707D6); + P(C, D, A, B, 3, 14, 0xF4D50D87); + P(B, C, D, A, 8, 20, 0x455A14ED); + P(A, B, C, D, 13, 5, 0xA9E3E905); + P(D, A, B, C, 2, 9, 0xFCEFA3F8); + P(C, D, A, B, 7, 14, 0x676F02D9); + P(B, C, D, A, 12, 20, 0x8D2A4C8A); + +#undef F + +#define F(x, y, z) (x ^ y ^ z) + + P(A, B, C, D, 5, 4, 0xFFFA3942); + P(D, A, B, C, 8, 11, 0x8771F681); + P(C, D, A, B, 11, 16, 0x6D9D6122); + P(B, C, D, A, 14, 23, 0xFDE5380C); + P(A, B, C, D, 1, 4, 0xA4BEEA44); + P(D, A, B, C, 4, 11, 0x4BDECFA9); + P(C, D, A, B, 7, 16, 0xF6BB4B60); + P(B, C, D, A, 10, 23, 0xBEBFBC70); + P(A, B, C, D, 13, 4, 0x289B7EC6); + P(D, A, B, C, 0, 11, 0xEAA127FA); + P(C, D, A, B, 3, 16, 0xD4EF3085); + P(B, C, D, A, 6, 23, 0x04881D05); + P(A, B, C, D, 9, 4, 0xD9D4D039); + P(D, A, B, C, 12, 11, 0xE6DB99E5); + P(C, D, A, B, 15, 16, 0x1FA27CF8); + P(B, C, D, A, 2, 23, 0xC4AC5665); + +#undef F + +#define F(x, y, z) (y ^ (x | ~z)) + + P(A, B, C, D, 0, 6, 0xF4292244); + P(D, A, B, C, 7, 10, 0x432AFF97); + P(C, D, A, B, 14, 15, 0xAB9423A7); + P(B, C, D, A, 5, 21, 0xFC93A039); + P(A, B, C, D, 12, 6, 0x655B59C3); + P(D, A, B, C, 3, 10, 0x8F0CCC92); + P(C, D, A, B, 10, 15, 0xFFEFF47D); + P(B, C, D, A, 1, 21, 0x85845DD1); + P(A, B, C, D, 8, 6, 0x6FA87E4F); + P(D, A, B, C, 15, 10, 0xFE2CE6E0); + P(C, D, A, B, 6, 15, 0xA3014314); + P(B, C, D, A, 13, 21, 0x4E0811A1); + P(A, B, C, D, 4, 6, 0xF7537E82); + P(D, A, B, C, 11, 10, 0xBD3AF235); + P(C, D, A, B, 2, 15, 0x2AD7D2BB); + P(B, C, D, A, 9, 21, 0xEB86D391); + +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} + +void md5_update(md5_context *ctx, const uint8 *input, uint32 length) { + uint32 left, fill; + + if (!length) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += length; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < length) + ctx->total[1]++; + + if (left && length >= fill) { + memcpy((void *)(ctx->buffer + left), (const void *)input, fill); + md5_process(ctx, ctx->buffer); + length -= fill; + input += fill; + left = 0; + } + + while (length >= 64) { + md5_process(ctx, input); + length -= 64; + input += 64; + } + + if (length) { + memcpy((void *)(ctx->buffer + left), (const void *)input, length); + } +} + +static const uint8 md5_padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +void md5_finish(md5_context *ctx, uint8 digest[16]) { + uint32 last, padn; + uint32 high, low; + uint8 msglen[8]; + + high = (ctx->total[0] >> 29) | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + PUT_UINT32(low, msglen, 0); + PUT_UINT32(high, msglen, 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + md5_update(ctx, md5_padding, padn); + md5_update(ctx, msglen, 8); + + PUT_UINT32(ctx->state[0], digest, 0); + PUT_UINT32(ctx->state[1], digest, 4); + PUT_UINT32(ctx->state[2], digest, 8); + PUT_UINT32(ctx->state[3], digest, 12); +} + +bool md5_file(const char *name, uint8 digest[16], uint32 length) { + FILE *f; + + f = fopen(name, "rb"); + if (f == NULL) { + printf("md5_file couldn't open '%s'\n", name); + return false; + } + + md5_context ctx; + uint32 i; + unsigned char buf[1000]; + bool restricted = (length != 0); + int readlen; + + if (!restricted || sizeof(buf) <= length) + readlen = sizeof(buf); + else + readlen = length; + + md5_starts(&ctx); + + + while ((i = (uint32)fread(buf, 1, readlen, f)) > 0) { + md5_update(&ctx, buf, i); + + length -= i; + if (restricted && length == 0) + break; + + if (restricted && sizeof(buf) > length) + readlen = length; + } + + md5_finish(&ctx, digest); + fclose(f); + return true; +} + +void md5_buffer(byte *buf, uint32 len, uint8 digest[16]) { + md5_context ctx; + + md5_starts(&ctx); + md5_update(&ctx, buf, len); + md5_finish(&ctx, digest); +} + diff --git a/devtools/create_neverhood/md5.h b/devtools/create_neverhood/md5.h new file mode 100644 index 0000000000..81bc03ff83 --- /dev/null +++ b/devtools/create_neverhood/md5.h @@ -0,0 +1,41 @@ +/* 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 COMMON_MD5_H +#define COMMON_MD5_H + +#include "util.h" + +typedef struct { + uint32 total[2]; + uint32 state[4]; + uint8 buffer[64]; +} md5_context; + +void md5_starts(md5_context *ctx); +void md5_update(md5_context *ctx, const uint8 *input, uint32 length); +void md5_finish(md5_context *ctx, uint8 digest[16]); + +bool md5_file(const char *name, uint8 digest[16], uint32 length = 0); +void md5_buffer(byte *buf, uint32 len, uint8 digest[16]); + +#endif diff --git a/devtools/create_neverhood/module.mk b/devtools/create_neverhood/module.mk index 284e19105d..8e263559b5 100644 --- a/devtools/create_neverhood/module.mk +++ b/devtools/create_neverhood/module.mk @@ -3,6 +3,7 @@ MODULE := devtools/create_neverhood MODULE_OBJS := \ create_neverhood.o \ + md5.o \ util.o # Set the name of the executable diff --git a/devtools/create_neverhood/tables.h b/devtools/create_neverhood/tables.h index ea39aa807d..eb136491db 100644 --- a/devtools/create_neverhood/tables.h +++ b/devtools/create_neverhood/tables.h @@ -122,7 +122,7 @@ static const uint32 rectListOffsets[] = { // Scene2406 1, 0x004B78C8, 1, 0x004B78D8, - // Scene2501 + // Scene2501 1, 0x004B2608, // Scene2732 1, 0x004AE360, diff --git a/devtools/create_project/create_project.cpp b/devtools/create_project/create_project.cpp index a8e09ff5eb..3ee5fc4f97 100644 --- a/devtools/create_project/create_project.cpp +++ b/devtools/create_project/create_project.cpp @@ -109,7 +109,7 @@ enum ProjectType { int main(int argc, char *argv[]) { #ifndef USE_WIN32_API // Initialize random number generator for UUID creation - std::srand((uint)std::time(0)); + std::srand((unsigned int)std::time(0)); #endif if (argc < 2) { @@ -189,7 +189,7 @@ int main(int argc, char *argv[]) { msvcVersion = atoi(argv[++i]); - if (msvcVersion != 8 && msvcVersion != 9 && msvcVersion != 10 && msvcVersion != 11) { + if (msvcVersion != 8 && msvcVersion != 9 && msvcVersion != 10 && msvcVersion != 11 && msvcVersion != 12) { std::cerr << "ERROR: Unsupported version: \"" << msvcVersion << "\" passed to \"--msvc-version\"!\n"; return -1; } @@ -264,7 +264,7 @@ int main(int argc, char *argv[]) { setup.filePrefix.erase(setup.filePrefix.size() - 1); } else if (!std::strcmp(argv[i], "--output-dir")) { if (i + 1 >= argc) { - std::cerr << "ERROR: Missing \"path\" parameter for \"--output-dirx\"!\n"; + std::cerr << "ERROR: Missing \"path\" parameter for \"--output-dir\"!\n"; return -1; } @@ -279,12 +279,23 @@ int main(int argc, char *argv[]) { setup.createInstaller = true; } else if (!std::strcmp(argv[i], "--tools")) { setup.devTools = true; + } else if (!std::strcmp(argv[i], "--tests")) { + setup.tests = true; } else { std::cerr << "ERROR: Unknown parameter \"" << argv[i] << "\"\n"; return -1; } } + // When building tests, disable some features + if (setup.tests) { + setFeatureBuildState("mt32emu", setup.features, false); + setFeatureBuildState("eventrecorder", setup.features, false); + + for (EngineDescList::iterator j = setup.engines.begin(); j != setup.engines.end(); ++j) + j->enable = false; + } + // Print status cout << "Enabled engines:\n\n"; for (EngineDescList::const_iterator i = setup.engines.begin(); i != setup.engines.end(); ++i) { @@ -310,6 +321,23 @@ int main(int argc, char *argv[]) { cout << " " << i->description << '\n'; } + // Check if the keymapper and the event recorder are enabled simultaneously + bool keymapperEnabled = false; + for (FeatureList::const_iterator i = setup.features.begin(); i != setup.features.end(); ++i) { + if (i->enable && !strcmp(i->name, "keymapper")) + keymapperEnabled = true; + if (i->enable && !strcmp(i->name, "eventrecorder") && keymapperEnabled) { + std::cerr << "ERROR: The keymapper and the event recorder cannot be enabled simultaneously currently, please disable one of the two\n"; + return -1; + } + } + + // Check if tools and tests are enabled simultaneously + if (setup.devTools && setup.tests) { + std::cerr << "ERROR: The tools and tests projects cannot be created simultaneously\n"; + return -1; + } + // Setup defines and libraries setup.defines = getEngineDefines(setup.engines); setup.libraries = getFeatureLibraries(setup.features); @@ -347,8 +375,8 @@ int main(int argc, char *argv[]) { return -1; case kProjectCodeBlocks: - if (setup.devTools) { - std::cerr << "ERROR: Building tools is not supported for the CodeBlocks project type!\n"; + if (setup.devTools || setup.tests) { + std::cerr << "ERROR: Building tools or tests is not supported for the CodeBlocks project type!\n"; return -1; } @@ -520,8 +548,8 @@ int main(int argc, char *argv[]) { break; case kProjectXcode: - if (setup.devTools) { - std::cerr << "ERROR: Building tools is not supported for the XCode project type!\n"; + if (setup.devTools || setup.tests) { + std::cerr << "ERROR: Building tools or tests is not supported for the XCode project type!\n"; return -1; } @@ -562,6 +590,11 @@ int main(int argc, char *argv[]) { setup.projectDescription += "Tools"; } + if (setup.tests) { + setup.projectName += "-tests"; + setup.projectDescription += "Tests"; + } + provider->createProject(setup); delete provider; @@ -588,7 +621,7 @@ void displayHelp(const char *exe) { " Additionally there are the following switches for changing various settings:\n" "\n" "Project specific settings:\n" - " --codeblock build Code::Blocks project files\n" + " --codeblocks build Code::Blocks project files\n" " --msvc build Visual Studio project files\n" " --xcode build XCode project files\n" " --file-prefix prefix allow overwriting of relative file prefix in the\n" @@ -609,9 +642,12 @@ void displayHelp(const char *exe) { " (default: false)\n" " --installer Create NSIS installer after the build (implies --build-events)\n" " (default: false)\n" - " --tools Create project files for the devtools\n" - " (ignores --build-events and --installer, as well as engine settings)\n" - " (default: false)\n" + " --tools Create project files for the devtools\n" + " (ignores --build-events and --installer, as well as engine settings)\n" + " (default: false)\n" + " --tests Create project files for the tests\n" + " (ignores --build-events and --installer, as well as engine settings)\n" + " (default: false)\n" "\n" "Engines settings:\n" " --list-engines list all available engines and their default state\n" @@ -805,23 +841,26 @@ const Feature s_features[] = { { "vorbis", "USE_VORBIS", "libvorbisfile_static libvorbis_static libogg_static", true, "Ogg Vorbis support" }, { "flac", "USE_FLAC", "libFLAC_static", true, "FLAC support" }, { "png", "USE_PNG", "libpng", true, "libpng support" }, + { "faad", "USE_FAAD", "libfaad", false, "AAC support" }, + { "mpeg2", "USE_MPEG2", "libmpeg2", false, "MPEG-2 support" }, { "theora", "USE_THEORADEC", "libtheora_static", true, "Theora decoding support" }, {"freetype", "USE_FREETYPE2", "freetype", true, "FreeType support" }, // Feature flags - { "bink", "USE_BINK", "", true, "Bink video support" }, - { "scalers", "USE_SCALERS", "", true, "Scalers" }, - { "hqscalers", "USE_HQ_SCALERS", "", true, "HQ scalers" }, - { "16bit", "USE_RGB_COLOR", "", true, "16bit color support" }, - { "mt32emu", "USE_MT32EMU", "", true, "integrated MT-32 emulator" }, - { "nasm", "USE_NASM", "", true, "IA-32 assembly support" }, // This feature is special in the regard, that it needs additional handling. - { "opengl", "USE_OPENGL", "opengl32", true, "OpenGL support" }, - { "taskbar", "USE_TASKBAR", "", true, "Taskbar integration support" }, - { "translation", "USE_TRANSLATION", "", true, "Translation support" }, - { "vkeybd", "ENABLE_VKEYBD", "", false, "Virtual keyboard support"}, - { "keymapper","ENABLE_KEYMAPPER", "", false, "Keymapper support"}, - { "langdetect", "USE_DETECTLANG", "", true, "System language detection support" } // This feature actually depends on "translation", there - // is just no current way of properly detecting this... + { "bink", "USE_BINK", "", true, "Bink video support" }, + { "scalers", "USE_SCALERS", "", true, "Scalers" }, + { "hqscalers", "USE_HQ_SCALERS", "", true, "HQ scalers" }, + { "16bit", "USE_RGB_COLOR", "", true, "16bit color support" }, + { "mt32emu", "USE_MT32EMU", "", true, "integrated MT-32 emulator" }, + { "nasm", "USE_NASM", "", true, "IA-32 assembly support" }, // This feature is special in the regard, that it needs additional handling. + { "opengl", "USE_OPENGL", "opengl32", true, "OpenGL support" }, + { "taskbar", "USE_TASKBAR", "", true, "Taskbar integration support" }, + { "translation", "USE_TRANSLATION", "", true, "Translation support" }, + { "vkeybd", "ENABLE_VKEYBD", "", false, "Virtual keyboard support"}, + { "keymapper", "ENABLE_KEYMAPPER", "", false, "Keymapper support"}, + { "eventrecorder", "ENABLE_EVENTRECORDER", "", false, "Event recorder support"}, + { "langdetect", "USE_DETECTLANG", "", true, "System language detection support" } // This feature actually depends on "translation", there + // is just no current way of properly detecting this... }; const Tool s_tools[] = { @@ -829,7 +868,9 @@ const Tool s_tools[] = { { "create_hugo", true}, { "create_kyradat", true}, { "create_lure", true}, + { "create_neverhood", true}, { "create_teenagent", true}, + { "create_tony", true}, { "create_toon", true}, { "create_translations", true}, { "qtable", true} @@ -1114,69 +1155,66 @@ ProjectProvider::ProjectProvider(StringList &global_warnings, std::map<std::stri : _version(version), _globalWarnings(global_warnings), _projectWarnings(project_warnings) { } -void ProjectProvider::createProject(const BuildSetup &setup) { +void ProjectProvider::createProject(BuildSetup &setup) { + std::string targetFolder; + if (setup.devTools) { _uuidMap = createToolsUUIDMap(); + targetFolder = "/devtools/"; + } else if (!setup.tests) { + _uuidMap = createUUIDMap(setup); + targetFolder = "/engines/"; + } - // We also need to add the UUID of the main project file. - const std::string svmUUID = _uuidMap[setup.projectName] = createUUID(); - - createWorkspace(setup); - - StringList in, ex; - - // Create tools project files - for (UUIDMap::const_iterator i = _uuidMap.begin(); i != _uuidMap.end(); ++i) { - if (i->first == setup.projectName) - continue; - - in.clear(); ex.clear(); - const std::string moduleDir = setup.srcDir + "/devtools/" + i->first; + // We also need to add the UUID of the main project file. + const std::string svmUUID = _uuidMap[setup.projectName] = createUUID(); - createModuleList(moduleDir, setup.defines, in, ex); - createProjectFile(i->first, i->second, setup, moduleDir, in, ex); - } + createWorkspace(setup); - // Create other misc. build files - createOtherBuildFiles(setup); + StringList in, ex; - } else { - _uuidMap = createUUIDMap(setup); - - // We also need to add the UUID of the main project file. - const std::string svmUUID = _uuidMap[setup.projectName] = createUUID(); - - // Create Solution/Workspace file - createWorkspace(setup); + // Create project files + for (UUIDMap::const_iterator i = _uuidMap.begin(); i != _uuidMap.end(); ++i) { + if (i->first == setup.projectName) + continue; - StringList in, ex; + in.clear(); ex.clear(); + const std::string moduleDir = setup.srcDir + targetFolder + i->first; - // Create engine project files - for (UUIDMap::const_iterator i = _uuidMap.begin(); i != _uuidMap.end(); ++i) { - if (i->first == setup.projectName) - continue; + createModuleList(moduleDir, setup.defines, setup.testDirs, in, ex); + createProjectFile(i->first, i->second, setup, moduleDir, in, ex); + } - in.clear(); ex.clear(); - const std::string moduleDir = setup.srcDir + "/engines/" + i->first; + if (setup.tests) { + // Create the main project file. + in.clear(); ex.clear(); - createModuleList(moduleDir, setup.defines, in, ex); - createProjectFile(i->first, i->second, setup, moduleDir, in, ex); - } + createModuleList(setup.srcDir + "/backends", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/backends/platform/sdl", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/base", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/common", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/engines", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/graphics", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/gui", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/audio", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/test", setup.defines, setup.testDirs, in, ex); + createProjectFile(setup.projectName, svmUUID, setup, setup.srcDir, in, ex); + } else if (!setup.devTools) { // Last but not least create the main project file. in.clear(); ex.clear(); // File list for the Project file - createModuleList(setup.srcDir + "/backends", setup.defines, in, ex); - createModuleList(setup.srcDir + "/backends/platform/sdl", setup.defines, in, ex); - createModuleList(setup.srcDir + "/base", setup.defines, in, ex); - createModuleList(setup.srcDir + "/common", setup.defines, in, ex); - createModuleList(setup.srcDir + "/engines", setup.defines, in, ex); - createModuleList(setup.srcDir + "/graphics", setup.defines, in, ex); - createModuleList(setup.srcDir + "/gui", setup.defines, in, ex); - createModuleList(setup.srcDir + "/audio", setup.defines, in, ex); - createModuleList(setup.srcDir + "/audio/softsynth/mt32", setup.defines, in, ex); - createModuleList(setup.srcDir + "/video", setup.defines, in, ex); + createModuleList(setup.srcDir + "/backends", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/backends/platform/sdl", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/base", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/common", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/engines", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/graphics", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/gui", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/audio", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/audio/softsynth/mt32", setup.defines, setup.testDirs, in, ex); + createModuleList(setup.srcDir + "/video", setup.defines, setup.testDirs, in, ex); // Resource files in.push_back(setup.srcDir + "/icons/" + setup.projectName + ".ico"); @@ -1195,10 +1233,10 @@ void ProjectProvider::createProject(const BuildSetup &setup) { // Create the main project file. createProjectFile(setup.projectName, svmUUID, setup, setup.srcDir, in, ex); - - // Create other misc. build files - createOtherBuildFiles(setup); } + + // Create other misc. build files + createOtherBuildFiles(setup); } ProjectProvider::UUIDMap ProjectProvider::createUUIDMap(const BuildSetup &setup) const { @@ -1306,7 +1344,7 @@ void ProjectProvider::addFilesToProject(const std::string &dir, std::ofstream &p delete files; } -void ProjectProvider::createModuleList(const std::string &moduleDir, const StringList &defines, StringList &includeList, StringList &excludeList) const { +void ProjectProvider::createModuleList(const std::string &moduleDir, const StringList &defines, StringList &testDirs, StringList &includeList, StringList &excludeList) const { const std::string moduleMkFile = moduleDir + "/module.mk"; std::ifstream moduleMk(moduleMkFile.c_str()); if (!moduleMk) @@ -1437,6 +1475,59 @@ void ProjectProvider::createModuleList(const std::string &moduleDir, const Strin ++i; } } + } else if (*i == "TESTS") { + if (tokens.size() < 3) + error("Malformed TESTS definition in " + moduleMkFile); + ++i; + + if (*i != ":=" && *i != "+=" && *i != "=") + error("Malformed TESTS definition in " + moduleMkFile); + ++i; + + while (i != tokens.end()) { + // Read input + std::string folder = unifyPath(*i); + + // Get include folder + const std::string source_dir = "$(srcdir)/"; + const std::string selector = getLastPathComponent(folder); + const std::string module = getLastPathComponent(moduleDir); + + folder.replace(folder.find(source_dir), source_dir.length(), ""); + folder.replace(folder.find(selector), selector.length(), ""); + folder.replace(folder.find(module), module.length(), moduleDir); + + // Scan all files in the include folder + FileList files = listDirectory(folder); + + if (files.empty()) + continue; + + // Add to list of test folders + testDirs.push_back(folder); + + for (FileList::const_iterator f = files.begin(); f != files.end(); ++f) { + if (f->isDirectory) + continue; + + std::string filename = folder + f->name; + + if (shouldInclude.top()) { + // In case we should include a file, we need to make + // sure it is not in the exclude list already. If it + // is we just drop it from the exclude list. + excludeList.remove(filename); + + includeList.push_back(filename); + } else if (std::find(includeList.begin(), includeList.end(), filename) == includeList.end()) { + // We only add the file to the exclude list in case it + // has not yet been added to the include list. + excludeList.push_back(filename); + } + } + + ++i; + } } else if (*i == "ifdef") { if (tokens.size() < 2) error("Malformed ifdef in " + moduleMkFile); diff --git a/devtools/create_project/create_project.h b/devtools/create_project/create_project.h index de77793ee7..d0f2db364c 100644 --- a/devtools/create_project/create_project.h +++ b/devtools/create_project/create_project.h @@ -221,13 +221,16 @@ struct BuildSetup { StringList defines; ///< List of all defines for the build. StringList libraries; ///< List of all external libraries required for the build. + StringList testDirs; ///< List of all folders containing tests bool devTools; ///< Generate project files for the tools + bool tests; ///< Generate project files for the tests bool runBuildEvents; ///< Run build events as part of the build (generate revision number and copy engine/theme data & needed files to the build folder bool createInstaller; ///< Create NSIS installer after the build BuildSetup() { devTools = false; + tests = false; runBuildEvents = false; createInstaller = false; } @@ -339,7 +342,7 @@ public: * * @param setup Description of the desired build setup. */ - void createProject(const BuildSetup &setup); + void createProject(BuildSetup &setup); /** * Returns the last path component. @@ -430,10 +433,11 @@ protected: * * @param moduleDir Path to the module. * @param defines List of set defines. + * @param testDirs List of folders containing tests. * @param includeList Reference to a list, where included files should be added. * @param excludeList Reference to a list, where excluded files should be added. */ - void createModuleList(const std::string &moduleDir, const StringList &defines, StringList &includeList, StringList &excludeList) const; + void createModuleList(const std::string &moduleDir, const StringList &defines, StringList &testDirs, StringList &includeList, StringList &excludeList) const; /** * Creates an UUID for every enabled engine of the @@ -448,7 +452,7 @@ protected: * Creates an UUID for every enabled tool of the * passed build description. * - * @return A map, which includes UUIDs for all enabled engines. + * @return A map, which includes UUIDs for all enabled tools. */ UUIDMap createToolsUUIDMap() const; diff --git a/devtools/create_project/msbuild.cpp b/devtools/create_project/msbuild.cpp index 0f77d91852..60aa35b739 100644 --- a/devtools/create_project/msbuild.cpp +++ b/devtools/create_project/msbuild.cpp @@ -52,6 +52,9 @@ int MSBuildProvider::getVisualStudioVersion() { if (_version == 11) return 2012; + if (_version == 12) + return 2013; + error("Unsupported version passed to getVisualStudioVersion"); } @@ -66,7 +69,7 @@ inline void outputConfiguration(std::ostream &project, const std::string &config inline void outputConfigurationType(const BuildSetup &setup, std::ostream &project, const std::string &name, const std::string &config, int version) { project << "\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='" << config << "'\" Label=\"Configuration\">\n" - "\t\t<ConfigurationType>" << ((name == setup.projectName || setup.devTools) ? "Application" : "StaticLibrary") << "</ConfigurationType>\n" + "\t\t<ConfigurationType>" << ((name == setup.projectName || setup.devTools || setup.tests) ? "Application" : "StaticLibrary") << "</ConfigurationType>\n" "\t\t<PlatformToolset>v" << version << "0</PlatformToolset>\n" "\t</PropertyGroup>\n"; } @@ -88,7 +91,7 @@ void MSBuildProvider::createProjectFile(const std::string &name, const std::stri error("Could not open \"" + projectFile + "\" for writing"); project << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" - "<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n" + "<Project DefaultTargets=\"Build\" ToolsVersion=\"" << (_version >= 12 ? _version : 4) << ".0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n" "\t<ItemGroup Label=\"ProjectConfigurations\">\n"; outputConfiguration(project, "Debug", "Win32"); @@ -105,7 +108,7 @@ void MSBuildProvider::createProjectFile(const std::string &name, const std::stri "\t\t<ProjectGuid>{" << uuid << "}</ProjectGuid>\n" "\t\t<RootNamespace>" << name << "</RootNamespace>\n" "\t\t<Keyword>Win32Proj</Keyword>\n" - "\t\t<VCTargetsPath Condition=\"'$(VCTargetsPath11)' != '' and '$(VSVersion)' == '' and $(VisualStudioVersion) == ''\">$(VCTargetsPath11)</VCTargetsPath>\n" + "\t\t<VCTargetsPath Condition=\"'$(VCTargetsPath" << _version << ")' != '' and '$(VSVersion)' == '' and $(VisualStudioVersion) == ''\">$(VCTargetsPath" << _version << ")</VCTargetsPath>\n" "\t</PropertyGroup>\n"; // Shared configuration @@ -156,10 +159,26 @@ void MSBuildProvider::createProjectFile(const std::string &name, const std::stri if (name == setup.projectName) writeReferences(setup, project); + // Output auto-generated test runner + if (setup.tests) { + project << "\t<ItemGroup>\n"; + project << "\t\t<ClCompile Include=\"test_runner.cpp\" />\n"; + project << "\t</ItemGroup>\n"; + } + project << "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n" "\t<ImportGroup Label=\"ExtensionTargets\">\n" - "\t</ImportGroup>\n" - "</Project>\n"; + "\t</ImportGroup>\n"; + + if (setup.tests) { + // We override the normal target to ignore the exit code (this allows us to have a clean output and not message about the command exit code) + project << "\t\t<Target Name=\"PostBuildEvent\">\n" + << "\t\t\t<Message Text=\"Description: Run tests\" />\n" + << "\t\t\t<Exec Command=\"$(TargetPath)\" IgnoreExitCode=\"true\" />\n" + << "\t\t</Target>\n"; + } + + project << "</Project>\n"; // Output filter file if necessary createFiltersFile(setup, name); @@ -184,7 +203,7 @@ void MSBuildProvider::createFiltersFile(const BuildSetup &setup, const std::stri error("Could not open \"" + filtersFile + "\" for writing"); filters << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" - "<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"; + "<Project ToolsVersion=\"" << (_version >= 12 ? _version : 4) << ".0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"; // Output the list of filters filters << "\t<ItemGroup>\n"; @@ -245,7 +264,7 @@ void MSBuildProvider::outputProjectSettings(std::ofstream &project, const std::s bool disableEditAndContinue = find(_disableEditAndContinue.begin(), _disableEditAndContinue.end(), name) != _disableEditAndContinue.end(); // Nothing to add here, move along! - if (!setup.devTools && name != setup.projectName && !enableLanguageExtensions && !disableEditAndContinue && warningsIterator == _projectWarnings.end()) + if ((!setup.devTools || !setup.tests) && name != setup.projectName && !enableLanguageExtensions && !disableEditAndContinue && warningsIterator == _projectWarnings.end()) return; std::string warnings = ""; @@ -257,7 +276,7 @@ void MSBuildProvider::outputProjectSettings(std::ofstream &project, const std::s "\t\t<ClCompile>\n"; // Language Extensions - if (setup.devTools || name == setup.projectName || enableLanguageExtensions) + if (setup.devTools || setup.tests || name == setup.projectName || enableLanguageExtensions) project << "\t\t\t<DisableLanguageExtensions>false</DisableLanguageExtensions>\n"; // Edit and Continue @@ -271,18 +290,18 @@ void MSBuildProvider::outputProjectSettings(std::ofstream &project, const std::s project << "\t\t</ClCompile>\n"; // Link configuration for main project - if (name == setup.projectName || setup.devTools) { + if (name == setup.projectName || setup.devTools || setup.tests) { std::string libraries; for (StringList::const_iterator i = setup.libraries.begin(); i != setup.libraries.end(); ++i) libraries += *i + ".lib;"; project << "\t\t<Link>\n" - "\t\t\t<OutputFile>$(OutDir)" << (setup.devTools ? name : setup.projectName) << ".exe</OutputFile>\n" + "\t\t\t<OutputFile>$(OutDir)" << ((setup.devTools || setup.tests) ? name : setup.projectName) << ".exe</OutputFile>\n" "\t\t\t<AdditionalDependencies>" << libraries << "%(AdditionalDependencies)</AdditionalDependencies>\n" "\t\t</Link>\n"; - if (!setup.devTools && setup.runBuildEvents) { + if (!setup.devTools && !setup.tests && setup.runBuildEvents) { project << "\t\t<PreBuildEvent>\n" "\t\t\t<Message>Generate revision</Message>\n" "\t\t\t<Command>" << getPreBuildEvent() << "</Command>\n" @@ -293,6 +312,11 @@ void MSBuildProvider::outputProjectSettings(std::ofstream &project, const std::s "\t\t\t<Message>Copy data files to the build folder</Message>\n" "\t\t\t<Command>" << getPostBuildEvent(isWin32, setup.createInstaller) << "</Command>\n" "\t\t</PostBuildEvent>\n"; + } else if (setup.tests) { + project << "\t\t<PreBuildEvent>\n" + "\t\t\t<Message>Generate runner.cpp</Message>\n" + "\t\t\t<Command>" << getTestPreBuildEvent(setup) << "</Command>\n" + "\t\t</PreBuildEvent>\n"; } } @@ -314,9 +338,8 @@ void MSBuildProvider::outputGlobalPropFile(const BuildSetup &setup, std::ofstrea definesList += REVISION_DEFINE ";"; properties << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" - "<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n" + "<Project DefaultTargets=\"Build\" ToolsVersion=\"" << (_version >= 12 ? _version : 4) << ".0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n" "\t<PropertyGroup>\n" - "\t\t<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>\n" "\t\t<_PropertySheetDisplayName>" << setup.projectDescription << "_Global</_PropertySheetDisplayName>\n" "\t\t<ExecutablePath>$(" << LIBS_DEFINE << ")\\bin;$(ExecutablePath)</ExecutablePath>\n" "\t\t<LibraryPath>$(" << LIBS_DEFINE << ")\\lib\\" << (bits == 32 ? "x86" : "x64") << ";$(LibraryPath)</LibraryPath>\n" @@ -328,9 +351,9 @@ void MSBuildProvider::outputGlobalPropFile(const BuildSetup &setup, std::ofstrea "\t\t<ClCompile>\n" "\t\t\t<DisableLanguageExtensions>true</DisableLanguageExtensions>\n" "\t\t\t<DisableSpecificWarnings>" << warnings << ";%(DisableSpecificWarnings)</DisableSpecificWarnings>\n" - "\t\t\t<AdditionalIncludeDirectories>$(" << LIBS_DEFINE << ")\\include;" << prefix << ";" << prefix << "\\engines;$(TargetDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n" + "\t\t\t<AdditionalIncludeDirectories>$(" << LIBS_DEFINE << ")\\include;" << prefix << ";" << prefix << "\\engines;" << (setup.tests ? prefix + "\\test\\cxxtest;" : "") << "$(TargetDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n" "\t\t\t<PreprocessorDefinitions>" << definesList << "%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" - "\t\t\t<ExceptionHandling>" << (setup.devTools ? "Sync" : "") << "</ExceptionHandling>\n"; + "\t\t\t<ExceptionHandling>" << ((setup.devTools || setup.tests) ? "Sync" : "") << "</ExceptionHandling>\n"; #if NEEDS_RTTI properties << "\t\t\t<RuntimeTypeInfo>true</RuntimeTypeInfo>\n"; @@ -346,7 +369,7 @@ void MSBuildProvider::outputGlobalPropFile(const BuildSetup &setup, std::ofstrea "\t\t\t<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\n" "\t\t\t<SubSystem>Console</SubSystem>\n"; - if (!setup.devTools) + if (!setup.devTools && !setup.tests) properties << "\t\t\t<EntryPointSymbol>WinMainCRTStartup</EntryPointSymbol>\n"; properties << "\t\t</Link>\n" @@ -368,12 +391,11 @@ void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, b error("Could not open \"" + setup.outputDir + '/' + setup.projectDescription + "_" + outputType + (isWin32 ? "" : "64") + getPropertiesExtension() + "\" for writing"); properties << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" - "<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n" + "<Project DefaultTargets=\"Build\" ToolsVersion=\"" << (_version >= 12 ? _version : 4) << ".0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n" "\t<ImportGroup Label=\"PropertySheets\">\n" "\t\t<Import Project=\"" << setup.projectDescription << "_Global" << (isWin32 ? "" : "64") << ".props\" />\n" "\t</ImportGroup>\n" "\t<PropertyGroup>\n" - "\t\t<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>\n" "\t\t<_PropertySheetDisplayName>" << setup.projectDescription << "_" << outputType << outputBitness << "</_PropertySheetDisplayName>\n" "\t\t<LinkIncremental>" << (isRelease ? "false" : "true") << "</LinkIncremental>\n" "\t</PropertyGroup>\n" diff --git a/devtools/create_project/msvc.cpp b/devtools/create_project/msvc.cpp index b8d2401af9..2fedadcba5 100644 --- a/devtools/create_project/msvc.cpp +++ b/devtools/create_project/msvc.cpp @@ -161,6 +161,16 @@ std::string MSVCProvider::getPreBuildEvent() const { return cmdLine; } +std::string MSVCProvider::getTestPreBuildEvent(const BuildSetup &setup) const { + // Build list of folders containing tests + std::string target = ""; + + for (StringList::const_iterator it = setup.testDirs.begin(); it != setup.testDirs.end(); ++it) + target += " $(SolutionDir)" + *it + "*.h"; + + return ""$(SolutionDir)../../test/cxxtest/cxxtestgen.py" --runner=ParenPrinter --no-std --no-eh -o $(SolutionDir)test_runner.cpp" + target; +} + std::string MSVCProvider::getPostBuildEvent(bool isWin32, bool createInstaller) const { std::string cmdLine = ""; diff --git a/devtools/create_project/msvc.h b/devtools/create_project/msvc.h index 5a854b596a..b9b93fe109 100644 --- a/devtools/create_project/msvc.h +++ b/devtools/create_project/msvc.h @@ -88,6 +88,13 @@ protected: std::string getPreBuildEvent() const; /** + * Get the command line for the test generator + * + * @param setup Description of the desired build setup. + */ + std::string getTestPreBuildEvent(const BuildSetup &setup) const; + + /** * Get the command line for copying data files to the build directory. * * @param isWin32 Bitness of property file. diff --git a/devtools/create_project/msvc12/create_project.sln b/devtools/create_project/msvc12/create_project.sln new file mode 100644 index 0000000000..759d5430f5 --- /dev/null +++ b/devtools/create_project/msvc12/create_project.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "create_project", "create_project.vcxproj", "{CF177559-077D-4A08-AABE-BE0FD35F6C63}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.ActiveCfg = Debug|Win32 + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.Build.0 = Debug|Win32 + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.ActiveCfg = Release|Win32 + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/devtools/create_project/msvc12/create_project.vcxproj b/devtools/create_project/msvc12/create_project.vcxproj new file mode 100644 index 0000000000..c26b1e5f45 --- /dev/null +++ b/devtools/create_project/msvc12/create_project.vcxproj @@ -0,0 +1,132 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{CF177559-077D-4A08-AABE-BE0FD35F6C63}</ProjectGuid> + <RootNamespace>create_project</RootNamespace> + <VCTargetsPath Condition="'$(VCTargetsPath11)' != '' and '$(VSVersion)' == '' and $(VisualStudioVersion) == ''">$(VCTargetsPath11)</VCTargetsPath> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>MultiByte</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <MinimalRebuild>true</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>EditAndContinue</DebugInformationFormat> + <DisableLanguageExtensions>false</DisableLanguageExtensions> + <DisableSpecificWarnings>4003;4512;4127</DisableSpecificWarnings> + </ClCompile> + <Link> + <AdditionalDependencies>Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + <TargetMachine>MachineX86</TargetMachine> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + </Link> + <PostBuildEvent> + <Command>@echo off +xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc12\" +xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc11\" +xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc10\" +xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc9\" +xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc8\" +xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\codeblocks\" +xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\"</Command> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4003;4512;4127</DisableSpecificWarnings> + </ClCompile> + <Link> + <AdditionalDependencies>Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <TargetMachine>MachineX86</TargetMachine> + </Link> + <PostBuildEvent> + <Command>@echo off +xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc12\" +xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc11\" +xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc10\" +xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc9\" +xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\msvc8\" +xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\codeblocks\" +xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\"</Command> + </PostBuildEvent> + <PreBuildEvent> + <Command> + </Command> + </PreBuildEvent> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\codeblocks.cpp" /> + <ClCompile Include="..\create_project.cpp" /> + <ClCompile Include="..\msbuild.cpp" /> + <ClCompile Include="..\msvc.cpp" /> + <ClCompile Include="..\visualstudio.cpp" /> + <ClCompile Include="..\xcode.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\codeblocks.h" /> + <ClInclude Include="..\config.h" /> + <ClInclude Include="..\create_project.h" /> + <ClInclude Include="..\msbuild.h" /> + <ClInclude Include="..\msvc.h" /> + <ClInclude Include="..\visualstudio.h" /> + <ClInclude Include="..\xcode.h" /> + </ItemGroup> + <ItemGroup> + <None Include="..\scripts\installer.vbs" /> + <None Include="..\scripts\postbuild.cmd" /> + <None Include="..\scripts\prebuild.cmd" /> + <None Include="..\scripts\revision.vbs" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/devtools/create_project/msvc12/create_project.vcxproj.filters b/devtools/create_project/msvc12/create_project.vcxproj.filters new file mode 100644 index 0000000000..436d1d3436 --- /dev/null +++ b/devtools/create_project/msvc12/create_project.vcxproj.filters @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Header Files"> + <UniqueIdentifier>{2e3580c8-ec3a-4c81-8351-b668c668db2a}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files"> + <UniqueIdentifier>{31aaf58c-d3cb-4ed6-8eca-163b4a9b31a6}</UniqueIdentifier> + </Filter> + <Filter Include="scripts"> + <UniqueIdentifier>{f980f6fb-41b6-4161-b035-58b200c85cad}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\codeblocks.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\create_project.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\msvc.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\msbuild.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\visualstudio.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\xcode.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\codeblocks.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\create_project.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\msvc.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\msbuild.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\visualstudio.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\xcode.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <None Include="..\scripts\prebuild.cmd"> + <Filter>scripts</Filter> + </None> + <None Include="..\scripts\revision.vbs"> + <Filter>scripts</Filter> + </None> + <None Include="..\scripts\postbuild.cmd"> + <Filter>scripts</Filter> + </None> + <None Include="..\scripts\installer.vbs"> + <Filter>scripts</Filter> + </None> + </ItemGroup> +</Project> diff --git a/devtools/create_project/visualstudio.cpp b/devtools/create_project/visualstudio.cpp index de2df96d78..23225d3435 100644 --- a/devtools/create_project/visualstudio.cpp +++ b/devtools/create_project/visualstudio.cpp @@ -83,7 +83,7 @@ void VisualStudioProvider::createProjectFile(const std::string &name, const std: // Check for project-specific warnings: std::map< std::string, std::list<std::string> >::iterator warningsIterator = _projectWarnings.find(name); - if (setup.devTools || name == setup.projectName) { + if (setup.devTools || setup.tests || name == setup.projectName) { std::string libraries; for (StringList::const_iterator i = setup.libraries.begin(); i != setup.libraries.end(); ++i) @@ -140,6 +140,11 @@ void VisualStudioProvider::createProjectFile(const std::string &name, const std: else addFilesToProject(moduleDir, project, includeList, excludeList, setup.filePrefix); + // Output auto-generated test runner + if (setup.tests) { + project << "\t\t<File RelativePath=\"test_runner.cpp\" />\n"; + } + project << "\t</Files>\n" "</VisualStudioProject>\n"; } @@ -161,7 +166,7 @@ void VisualStudioProvider::outputConfiguration(const BuildSetup &setup, std::ost } void VisualStudioProvider::outputBuildEvents(std::ostream &project, const BuildSetup &setup, const bool isWin32) { - if (!setup.devTools && setup.runBuildEvents) { + if (!setup.devTools && !setup.tests && setup.runBuildEvents) { project << "\t\t\t<Tool\tName=\"VCPreBuildEventTool\"\n" "\t\t\t\tCommandLine=\"" << getPreBuildEvent() << "\"\n" "\t\t\t/>\n" @@ -169,6 +174,17 @@ void VisualStudioProvider::outputBuildEvents(std::ostream &project, const BuildS "\t\t\t\tCommandLine=\"" << getPostBuildEvent(isWin32, setup.createInstaller) << "\"\n" "\t\t\t/>\n"; } + + // Generate runner file before build for tests + if (setup.tests) { + project << "\t\t\t<Tool\tName=\"VCPreBuildEventTool\"\n" + "\t\t\t\tCommandLine=\"" << getTestPreBuildEvent(setup) << "\"\n" + "\t\t\t/>\n"; + + project << "\t\t\t<Tool\tName=\"VCPostBuildEventTool\"\n" + "\t\t\t\tCommandLine=\"$(TargetPath)\" IgnoreExitCode=\"true\"\n" + "\t\t\t/>\n"; + } } void VisualStudioProvider::writeReferences(const BuildSetup &setup, std::ofstream &output) { @@ -212,9 +228,9 @@ void VisualStudioProvider::outputGlobalPropFile(const BuildSetup &setup, std::of "\t\tName=\"VCCLCompilerTool\"\n" "\t\tDisableLanguageExtensions=\"" << (setup.devTools ? "false" : "true") << "\"\n" "\t\tDisableSpecificWarnings=\"" << warnings << "\"\n" - "\t\tAdditionalIncludeDirectories=\"" << prefix << ";" << prefix << "\\engines;$(" << LIBS_DEFINE << ")\\include;$(TargetDir)\"\n" + "\t\tAdditionalIncludeDirectories=\"" << prefix << ";" << prefix << "\\engines;$(" << LIBS_DEFINE << ")\\include;" << (setup.tests ? prefix + "\\test\\cxxtest;" : "") << "$(TargetDir)\"\n" "\t\tPreprocessorDefinitions=\"" << definesList << "\"\n" - "\t\tExceptionHandling=\"" << (setup.devTools ? "1" : "0") << "\"\n"; + "\t\tExceptionHandling=\"" << ((setup.devTools || setup.tests) ? "1" : "0") << "\"\n"; #if NEEDS_RTTI properties << "\t\tRuntimeTypeInfo=\"true\"\n"; @@ -235,7 +251,7 @@ void VisualStudioProvider::outputGlobalPropFile(const BuildSetup &setup, std::of "\t\tIgnoreDefaultLibraryNames=\"\"\n" "\t\tSubSystem=\"1\"\n"; - if (!setup.devTools) + if (!setup.devTools && !setup.tests) properties << "\t\tEntryPointSymbol=\"WinMainCRTStartup\"\n"; properties << "\t\tAdditionalLibraryDirectories=\"$(" << LIBS_DEFINE << ")\\lib\\" << ((bits == 32) ? "x86" : "x64") << "\"\n" diff --git a/devtools/create_teenagent/static_tables.h b/devtools/create_teenagent/static_tables.h index 6e7fdfe91c..5c9b5b3d21 100644 --- a/devtools/create_teenagent/static_tables.h +++ b/devtools/create_teenagent/static_tables.h @@ -15148,7 +15148,7 @@ const static char* dialog_162[] = { }; // Note: -// The usage of this in the engine overlaps the previous dialog i.e. the +// The usage of this in the engine overlaps the previous dialog i.e. the // starting offset used is two bytes early, thus implicitly changing the // first command of this dialog from NEW_LINE to CHANGE_CHARACTER. const static char* dialog_163[] = { diff --git a/devtools/credits.pl b/devtools/credits.pl index 06df7fa50e..7d39730c63 100755 --- a/devtools/credits.pl +++ b/devtools/credits.pl @@ -754,10 +754,6 @@ begin_credits("Credits"); add_person("Angus Lees", "Gus", ""); end_section(); - begin_section("BADA"); - add_person("Chris Warren-Smith", "", ""); - end_section(); - begin_section("Dreamcast"); add_person("Marcus Comstedt", "", ""); end_section(); @@ -818,6 +814,10 @@ begin_credits("Credits"); add_person("Lars Persson", "AnotherGuest", ""); end_section(); + begin_section("Tizen / BADA"); + add_person("Chris Warren-Smith", "", ""); + end_section(); + begin_section("WebOS"); add_person("Klaus Reimer", "kayahr", ""); end_section(); diff --git a/devtools/extract_mort/extract_mort.cpp b/devtools/extract_mort/extract_mort.cpp new file mode 100644 index 0000000000..159309c0fa --- /dev/null +++ b/devtools/extract_mort/extract_mort.cpp @@ -0,0 +1,428 @@ +/* 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 is a utility for extracting needed resource data from different language + * version of the Lure of the Temptress lure.exe executable files into a new file + * lure.dat - this file is required for the ScummVM Lure of the Temptress module + * to work properly + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +// HACK to allow building with the SDL backend on MinGW +// see bug #1800764 "TOOLS: MinGW tools building broken" +#ifdef main +#undef main +#endif // main + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "common/endian.h" + +enum AccessMode { + kFileReadMode = 1, + kFileWriteMode = 2 +}; + +class File { +private: + FILE *f; +public: + bool open(const char *filename, AccessMode mode = kFileReadMode) { + f = fopen(filename, (mode == kFileReadMode) ? "rb" : "wb"); + return (f != NULL); + } + void close() { + fclose(f); + f = NULL; + } + int seek(int32 offset, int whence = SEEK_SET) { + return fseek(f, offset, whence); + } + long read(void *buffer, int len) { + return fread(buffer, 1, len, f); + } + void write(const void *buffer, int len) { + fwrite(buffer, 1, len, f); + } + byte readByte() { + byte v; + read(&v, sizeof(byte)); + return v; + } + uint16 readWord() { + uint16 v; + read(&v, sizeof(uint16)); + return FROM_LE_16(v); + } + uint32 readLong() { + uint32 v; + read(&v, sizeof(uint32)); + return FROM_LE_32(v); + } + void readString(char *sLine) { + while ((*sLine = readByte()) != '\n') + ++sLine; + + *sLine = '\0'; + } + void writeByte(byte v) { + write(&v, sizeof(byte)); + } + void writeWord(uint16 v) { + uint16 vTemp = TO_LE_16(v); + write(&vTemp, sizeof(uint16)); + } + void writeLong(uint32 v) { + uint32 vTemp = TO_LE_32(v); + write(&vTemp, sizeof(uint32)); + } + void writeString(const char *s) { + fprintf(f, "%s", s); + } + uint32 pos() { + return ftell(f); + } + uint32 size() { + int pos = ftell(f); + fseek (f, 0, SEEK_END); + int end = ftell (f); + fseek (f, pos, SEEK_SET); + + return end; + } +}; + +File textFile, txxInp, txxNtp; +int _version; + +/*-------------------------------------------------------------------------*/ + +#define BUFFER_SIZE 32768 + +const byte tabdrFr[32] = { + 32, 101, 115, 97, 114, 105, 110, + 117, 116, 111, 108, 13, 100, 99, + 112, 109, 46, 118, 130, 39, 102, + 98, 44, 113, 104, 103, 33, 76, + 85, 106, 30, 31 +}; + +const byte tab30Fr[32] = { + 69, 67, 74, 138, 133, 120, 77, 122, + 121, 68, 65, 63, 73, 80, 83, 82, + 156, 45, 58, 79, 49, 86, 78, 84, + 71, 81, 64, 66, 135, 34, 136, 91 +}; + +const byte tab31Fr[32]= { + 93, 47, 48, 53, 50, 70, 124, 75, + 72, 147, 140, 150, 151, 57, 56, 51, + 107, 139, 55, 89, 131, 37, 54, 88, + 119, 0, 0, 0, 0, 0, 0, 0 +}; + +const byte tabdrDe[32] = { + 0x20, 0x65, 0x6E, 0x69, 0x73, 0x72, 0x74, + 0x68, 0x61, 0x75, 0x0D, 0x63, 0x6C, 0x64, + 0x6D, 0x6F, 0x67, 0x2E, 0x62, 0x66, 0x53, + 0x2C, 0x77, 0x45, 0x7A, 0x6B, 0x44, 0x76, + 0x9C, 0x47, 0x1E, 0x1F +}; + +const byte tab30De[32] = { + 0x49, 0x4D, 0x21, 0x42, 0x4C, 0x70, 0x41, 0x52, + 0x57, 0x4E, 0x48, 0x3F, 0x46, 0x50, 0x55, 0x4B, + 0x5A, 0x4A, 0x54, 0x31, 0x4F, 0x56, 0x79, 0x3A, + 0x6A, 0x5B, 0x5D, 0x40, 0x22, 0x2F, 0x30, 0x35 +}; + +const byte tab31De[32]= { + 0x78, 0x2D, 0x32, 0x82, 0x43, 0x39, 0x33, 0x38, + 0x7C, 0x27, 0x37, 0x3B, 0x25, 0x28, 0x29, 0x36, + 0x51, 0x59, 0x71, 0x81, 0x87, 0x88, 0x93, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const byte *tabdr, *tab30, *tab31; +uint16 ctrlChar; + +/** + * Extracts a single character from the game data + */ +static void extractCharacter(unsigned char &c, uint &idx, uint &pt, bool &the_end, const uint16 *strData) { + uint16 oct, ocd; + + /* 5-8 */ + oct = FROM_LE_16(strData[idx]); + + oct = ((uint16)(oct << (16 - pt))) >> (16 - pt); + if (pt < 6) { + idx = idx + 1; + oct = oct << (5 - pt); + pt = pt + 11; + oct = oct | (FROM_LE_16(strData[idx]) >> pt); + } else { + pt = pt - 5; + oct = (uint)oct >> pt; + } + + if (oct == ctrlChar) { + c = '$'; + the_end = true; + } else if (oct == 30 || oct == 31) { + ocd = FROM_LE_16(strData[idx]); + ocd = (uint16)(ocd << (16 - pt)) >> (16 - pt); + if (pt < 6) { + idx = idx + 1; + ocd = ocd << (5 - pt); + pt = pt + 11; + ocd = ocd | (FROM_LE_16(strData[idx]) >> pt); + } else { + pt = pt - 5; + ocd = (uint)ocd >> pt; + } + if (oct == 30) + c = (char)tab30[ocd]; + else + c = (char)tab31[ocd]; + + if (c == '\0') + the_end = true; + } else { + c = (char)tabdr[oct]; + } +} + +/** + * Puts a compressed 5-bit value into the string data buffer + */ +static void addCompressedValue(int oct, int &indis, int &point, uint16 *strData) { + // Write out the part of the value that fits into the current word + if (point < 5) + strData[indis] |= oct >> (5 - point); + else + strData[indis] |= oct << (point - 5); + + // Handling of there's any overlap into the next word + if (point < 5) { + // Overlapping into next word + ++indis; + + // Get the bits that fall into the next word and set it + int remainder = oct & ((1 << (5 - point)) - 1); + strData[indis] |= remainder << (16 - (5 - point)); + + point += -5 + 16; + } else { + point -= 5; + if (point == 0) { + point = 16; + ++indis; + } + } +} + +/** + * Compresses a single passed character and stores it in the compressed strings buffer + */ +static void compressCharacter(unsigned char ch, int &indis, int &point, uint16 *strData) { + if (ch == '$') { + // End of string + addCompressedValue(11, indis, point, strData); + return; + } + + // Scan through the tabdr array for a match + for (int idx = 0; idx < 30; ++idx) { + if ((idx != 11) && (tabdr[idx] == ch)) { + addCompressedValue(idx, indis, point, strData); + return; + } + } + + // Scan through the tab30 array + for (int idx = 0; idx < 32; ++idx) { + if (tab30[idx] == ch) { + addCompressedValue(30, indis, point, strData); + addCompressedValue(idx, indis, point, strData); + return; + } + } + + // Scan through the tab31 array + for (int idx = 0; idx < 32; ++idx) { + if (tab31[idx] == ch) { + addCompressedValue(31, indis, point, strData); + addCompressedValue(idx, indis, point, strData); + return; + } + } + + printf("Encountered invalid character '%c' when compressing strings\n", ch); + exit(1); +} + +/** + * string extractor + */ +static void export_strings(const char *textFilename) { + char buffer[BUFFER_SIZE]; + uint16 *strData; + + // Open input and output files + if (!txxInp.open("TXX.INP", kFileReadMode)) { + if (!txxInp.open("TXX.MOR", kFileReadMode)) { + printf("Missing TXX.INP/MOR"); + exit(-1); + } + } + if (!txxNtp.open("TXX.NTP", kFileReadMode)) { + if (!txxNtp.open("TXX.IND", kFileReadMode)) { + printf("Missing TXX.NTP/IND"); + exit(-1); + } + } + textFile.open(textFilename, kFileWriteMode); + + // Read all the compressed string data into a buffer + printf("%d %d", txxInp.size(), txxNtp.size()); + strData = (uint16 *)malloc(txxInp.size()); + txxInp.read(strData, txxInp.size()); + + // Loop through getting each string + for (unsigned int strIndex = 0; strIndex < (txxNtp.size() / 3); ++strIndex) { + uint indis = txxNtp.readWord(); + uint point = txxNtp.readByte(); + + // Extract the string + int charIndex = 0; + unsigned char ch; + bool endFlag = false; + do { + extractCharacter(ch, indis, point, endFlag, strData); + buffer[charIndex++] = ch; + if (charIndex == BUFFER_SIZE) { + printf("Extracted string exceeded allowed buffer size.\n"); + exit(1); + } + + if (indis >= (txxInp.size() / 2)) + endFlag = true; + } while (!endFlag); + + // Write out the string + buffer[charIndex++] = '\n'; + buffer[charIndex] = '\0'; + textFile.writeString(buffer); + } + + // Close the files and free the buffer + free(strData); + txxInp.close(); + txxNtp.close(); + textFile.close(); +} + +/** + * string importer + */ +static void import_strings(const char *textFilename) { + // Open input and output files + if (!txxInp.open("TXX.INP", kFileWriteMode)) { + printf("Missing TXX data file"); + exit(-1); + } + if (!txxNtp.open("TXX.NTP", kFileWriteMode)) { + printf("Missing TXX index file"); + exit(-1); + } + textFile.open(textFilename, kFileReadMode); + + // Set up a buffer for the output compressed strings + uint16 strData[BUFFER_SIZE]; + memset(strData, 0, BUFFER_SIZE); + char sLine[BUFFER_SIZE]; + + int indis = 0; + int point = 16; + + while (textFile.pos() < textFile.size()) { + // Read in the next source line + textFile.readString(sLine); + + // Write out the index entry for the string + txxNtp.writeWord(indis); + txxNtp.writeByte(point); + + // Loop through writing out the characters to the compressed data buffer + char *s = sLine; + while (*s) { + compressCharacter(*s, indis, point, strData); + ++s; + } + } + + // Write out the compressed data + if (point != 16) + ++indis; + txxInp.write(strData, indis * 2); + + // Close the files + txxInp.close(); + txxNtp.close(); + textFile.close(); +} + + +int main(int argc, char *argv[]) { + if (argc != 4) { + printf("Format: %s export|import v1|v2 output_file\n", argv[0]); + printf("where:\nv1: French DOS version\nv2: German DOS version\n"); + printf("The program must be run from the directory with the Mortville Manor game files.\n"); + exit(0); + } + + if (!strcmp(argv[2], "v1")) { + tab30 = tab30Fr; + tab31 = tab31Fr; + tabdr = tabdrFr; + ctrlChar = 11; + } else if (!strcmp(argv[2], "v2")) { + tab30 = tab30De; + tab31 = tab31De; + tabdr = tabdrDe; + ctrlChar = 10; + } else { + printf("Unknown version"); + exit(-1); + } + + // Do the processing + if (!strcmp(argv[1], "export")) + export_strings(argv[3]); + else if (!strcmp(argv[1], "import")) + import_strings(argv[3]); + else + printf("Unknown operation specified\n"); +} diff --git a/devtools/extract_mort/module.mk b/devtools/extract_mort/module.mk new file mode 100644 index 0000000000..cbdcd251d9 --- /dev/null +++ b/devtools/extract_mort/module.mk @@ -0,0 +1,11 @@ + +MODULE := devtools/extract_mort + +MODULE_OBJS := \ + extract_mort.o \ + +# Set the name of the executable +TOOL_EXECUTABLE := extract_mort + +# Include common rules +include $(srcdir)/rules.mk diff --git a/devtools/scumm-md5.txt b/devtools/scumm-md5.txt index 414a25e906..0dbcbf4792 100644 --- a/devtools/scumm-md5.txt +++ b/devtools/scumm-md5.txt @@ -346,7 +346,8 @@ ft Full Throttle 4bedb49943df95a9c900a5a82ccbe9de -1 fr All? - - - cyx 8bdb0bf87b5e303dd35693afb9351215 -1 de All? - - - dhewg 55518cd73cf9c6d23ea29c51ee06bdfe -1 it All? - - - delfino - 55e4cc866ff9046824e1c638ba2b8c7f -1 ru All? - - - sev + 55e4cc866ff9046824e1c638ba2b8c7f -1 ru All? - Akella - sev + 291fb06071e65897f755846611f5ad40 19697 ru All? - 7-Wolf - sev e72bb4c2b613db2cf50f89ff6350e70a -1 es All? - - - fe381e45117878b1e942cb876b050fd6 513243679 en Mac - - Mac bundle Fingolfin 04401d747f1a2c1c4b388daff71ed378 535405461 de Mac - - Mac bundle Fingolfin @@ -625,7 +626,8 @@ jungle Let's Explore the Jungle with Buzzy 8801fb4a1200b347f7a38523339526dd -1 en Windows - - - Kirben moonbase Moonbase Commander - cf400d20769fb70eb21766582f4924f7 -1 en Windows - - - Kirben + cf400d20769fb70eb21766582f4924f7 -1 en Windows 1.0 1.0 - Kirben + e1c9998826ce7fa8bde5cc3a5023edec -1 en Windows 1.1 1.1 - fuzzie ef71a322b6530ac45b1a070f7c0795f7 -1 en Windows Demo Demo - Kirben pajama Pajama Sam 1: No Need to Hide When It's Dark Outside @@ -653,6 +655,7 @@ pajama2 Pajama Sam 2: Thunder and Lightning Aren't so Frightening e5563c8358443c4352fcddf7402a5e0a -1 fr Windows HE 98.5 - - gist974 c6907d44f1166941d982864cd42cdc89 -1 de All HE 99 - - nachbarnebenan f8be685007a8b425ba2a455da732f59f -1 fr Mac HE 99 - - alamaz + 7477bc23d0383516c5e310cd8771dcc9 -1 fr Windows HE 99 - - Strangerke 32709cbeeb3044b34129950860a83f14 -1 ru Windows HE 99 - - sev 1af4eb581a33d808707d66d50e084dca -1 he Windows HE 99 - - Matan Bareket @@ -772,6 +775,7 @@ puttzoo Putt-Putt Saves the Zoo 3a3e592b074f595489f7f11e150c398d -1 us Windows HE 99 Updated - Adrian c5cc7cba02a2fbd539c4439e775b0536 43470 de Windows HE 99 Updated - Lightkey 5c9cecbd2952ccec14c9ecebf5822a34 -1 en iOS HE 100 - - clone2727 + 7b4ee071eecadc2d8cd0c3509110825c -1 en Windows HE 100 Remastered - Kirben 3486ede0f904789267d4bcc5537a46d4 14337 en Mac - Demo - khalek d220d154aafbfa12bd6f3ab1b2dae420 -1 de Mac - Demo - Joachim Eberhard diff --git a/devtools/skycpt/cptcompiler.cpp b/devtools/skycpt/cptcompiler.cpp index 2c7d33c73b..657f51b8a0 100644 --- a/devtools/skycpt/cptcompiler.cpp +++ b/devtools/skycpt/cptcompiler.cpp @@ -376,6 +376,7 @@ void doCompile(FILE *inf, FILE *debOutf, FILE *resOutf, TextFile *cptDef, FILE * uint32 asciiSize = (uint32)(asciiPos - asciiBuf); fwrite(&asciiSize, 1, 4, debOutf); fwrite(asciiBuf, 1, asciiSize, debOutf); + free(asciiBuf); // the direct links... fwrite(&dlinkCount, 2, 1, debOutf); @@ -438,6 +439,8 @@ void doCompile(FILE *inf, FILE *debOutf, FILE *resOutf, TextFile *cptDef, FILE * diffNo++; } } + fclose(dif); + free(resCpts); assert(diffDest <= 8192); fwrite(&diffNo, 1, 2, debOutf); fwrite(&diffDest, 1, 2, debOutf); diff --git a/dists/engine-data/README b/dists/engine-data/README index c9c4bd4817..9bbb006d17 100644 --- a/dists/engine-data/README +++ b/dists/engine-data/README @@ -16,6 +16,11 @@ scripts, from. lure.dat TODO +mort.dat: +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. + 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 diff --git a/dists/engine-data/mort.dat b/dists/engine-data/mort.dat Binary files differnew file mode 100644 index 0000000000..ae9579ee13 --- /dev/null +++ b/dists/engine-data/mort.dat diff --git a/dists/msvc10/create_msvc10.bat b/dists/msvc10/create_msvc10.bat index 5616c2cc8b..be0434fc50 100644 --- a/dists/msvc10/create_msvc10.bat +++ b/dists/msvc10/create_msvc10.bat @@ -10,6 +10,8 @@ if "%~1"=="/all" goto all if "%~1"=="/ALL" goto all if "%~1"=="/tools" goto tools if "%~1"=="/TOOLS" goto tools +if "%~1"=="/tests" goto tests +if "%~1"=="/TESTS" goto tests if "%~1"=="/clean" goto clean_check if "%~1"=="/CLEAN" goto clean_check if "%~1"=="/help" goto command_help @@ -70,6 +72,13 @@ echo. create_project ..\.. --tools --msvc --msvc-version 10 goto done +:tests +echo. +echo Creating tests project files +echo. +create_project ..\.. --tests --msvc --msvc-version 10 +goto done + :clean_check echo. set cleananswer=N @@ -88,6 +97,7 @@ del /Q *.props > NUL 2>&1 del /Q *.sln* > NUL 2>&1 del /Q scummvm* > NUL 2>&1 del /Q devtools* > NUL 2>&1 +del /Q test_runner.cpp > NUL 2>&1 goto done :done diff --git a/dists/msvc11/create_msvc11.bat b/dists/msvc11/create_msvc11.bat index b6a5413e3b..fc5471f46f 100644 --- a/dists/msvc11/create_msvc11.bat +++ b/dists/msvc11/create_msvc11.bat @@ -10,6 +10,8 @@ if "%~1"=="/all" goto all if "%~1"=="/ALL" goto all if "%~1"=="/tools" goto tools if "%~1"=="/TOOLS" goto tools +if "%~1"=="/tests" goto tests +if "%~1"=="/TESTS" goto tests if "%~1"=="/clean" goto clean_check if "%~1"=="/CLEAN" goto clean_check if "%~1"=="/help" goto command_help @@ -70,6 +72,13 @@ echo. create_project ..\.. --tools --msvc --msvc-version 11 goto done +:tests +echo. +echo Creating tests project files +echo. +create_project ..\.. --tests --msvc --msvc-version 11 +goto done + :clean_check echo. set cleananswer=N @@ -88,6 +97,7 @@ del /Q *.props > NUL 2>&1 del /Q *.sln* > NUL 2>&1 del /Q scummvm* > NUL 2>&1 del /Q devtools* > NUL 2>&1 +del /Q test_runner.cpp > NUL 2>&1 goto done :done diff --git a/dists/msvc12/create_msvc12.bat b/dists/msvc12/create_msvc12.bat new file mode 100644 index 0000000000..d99001edb1 --- /dev/null +++ b/dists/msvc12/create_msvc12.bat @@ -0,0 +1,105 @@ +@echo off + +echo. +echo Automatic creation of the MSVC12 project files +echo. + +if "%~1"=="/stable" goto stable +if "%~1"=="/STABLE" goto stable +if "%~1"=="/all" goto all +if "%~1"=="/ALL" goto all +if "%~1"=="/tools" goto tools +if "%~1"=="/TOOLS" goto tools +if "%~1"=="/tests" goto tests +if "%~1"=="/TESTS" goto tests +if "%~1"=="/clean" goto clean_check +if "%~1"=="/CLEAN" goto clean_check +if "%~1"=="/help" goto command_help +if "%~1"=="/HELP" goto command_help +if "%~1"=="/?" goto command_help + +if "%~1"=="" goto check_tool + +echo Invalid command parameter: %~1 +echo. + +:command_help +echo Valid command parameters are: +echo stable Generated stable engines project files +echo all Generate all engines project files +echo tools Generate project files for the devtools +echo clean Clean generated project files +echo help Show help message +goto done + +:check_tool +if not exist create_project.exe goto no_tool + +:question +echo. +set batchanswer=S +set /p batchanswer="Enable stable engines only, or all engines? (S/a)" +if "%batchanswer%"=="s" goto stable +if "%batchanswer%"=="S" goto stable +if "%batchanswer%"=="a" goto all +if "%batchanswer%"=="A" goto all +goto question + +:no_tool +echo create_project.exe not found in the current folder. +echo You need to build it first and copy it in this +echo folder +goto done + +:all +echo. +echo Creating project files with all engines enabled (stable and unstable) +echo. +create_project ..\.. --enable-all-engines --msvc --msvc-version 12 --build-events +goto done + +:stable +echo. +echo Creating normal project files, with only the stable engines enabled +echo. +create_project ..\.. --msvc --msvc-version 12 +goto done + +:tools +echo. +echo Creating tools project files +echo. +create_project ..\.. --tools --msvc --msvc-version 12 +goto done + +:tests +echo. +echo Creating tests project files +echo. +create_project ..\.. --tests --msvc --msvc-version 12 +goto done + +:clean_check +echo. +set cleananswer=N +set /p cleananswer="This will remove all project files. Are you sure you want to continue? (N/y)" +if "%cleananswer%"=="n" goto done +if "%cleananswer%"=="N" goto done +if "%cleananswer%"=="y" goto clean +if "%cleananswer%"=="Y" goto clean +goto clean_check + +:clean +echo. +echo Removing all project files +del /Q *.vcxproj* > NUL 2>&1 +del /Q *.props > NUL 2>&1 +del /Q *.sln* > NUL 2>&1 +del /Q scummvm* > NUL 2>&1 +del /Q devtools* > NUL 2>&1 +del /Q test_runner.cpp > NUL 2>&1 +goto done + +:done +echo. +pause diff --git a/dists/msvc12/readme.txt b/dists/msvc12/readme.txt new file mode 100644 index 0000000000..760f9ff601 --- /dev/null +++ b/dists/msvc12/readme.txt @@ -0,0 +1,6 @@ +The Visual Studio project files can now be created automatically from the GCC +files using the create_project tool inside the /devtools/create_project folder. + +To create the default project files, build create_project.exe, copy it inside +this folder and run the create_msvc12.bat file for a default build. You can run +create_project.exe with no parameters to check the possible command-line options diff --git a/dists/msvc8/create_msvc8.bat b/dists/msvc8/create_msvc8.bat index 2261c9bcec..1e0d339001 100644 --- a/dists/msvc8/create_msvc8.bat +++ b/dists/msvc8/create_msvc8.bat @@ -10,6 +10,8 @@ if "%~1"=="/all" goto all if "%~1"=="/ALL" goto all if "%~1"=="/tools" goto tools if "%~1"=="/TOOLS" goto tools +if "%~1"=="/tests" goto tests +if "%~1"=="/TESTS" goto tests if "%~1"=="/clean" goto clean_check if "%~1"=="/CLEAN" goto clean_check if "%~1"=="/help" goto command_help @@ -70,6 +72,13 @@ echo. create_project ..\.. --tools --msvc --msvc-version 8 goto done +:tests +echo. +echo Creating tests project files +echo. +create_project ..\.. --tests --msvc --msvc-version 8 +goto done + :clean_check echo. set cleananswer=N @@ -88,6 +97,7 @@ del /Q *.vsprops > NUL 2>&1 del /Q *.sln* > NUL 2>&1 del /Q scummvm* > NUL 2>&1 del /Q devtools* > NUL 2>&1 +del /Q test_runner.cpp goto done :done diff --git a/dists/msvc9/create_msvc9.bat b/dists/msvc9/create_msvc9.bat index 1622cd9037..34bcccdd7b 100644 --- a/dists/msvc9/create_msvc9.bat +++ b/dists/msvc9/create_msvc9.bat @@ -10,6 +10,8 @@ if "%~1"=="/all" goto all if "%~1"=="/ALL" goto all if "%~1"=="/tools" goto tools if "%~1"=="/TOOLS" goto tools +if "%~1"=="/tests" goto tests +if "%~1"=="/TESTS" goto tests if "%~1"=="/clean" goto clean_check if "%~1"=="/CLEAN" goto clean_check if "%~1"=="/help" goto command_help @@ -70,6 +72,13 @@ echo. create_project ..\.. --tools --msvc --msvc-version 9 goto done +:tests +echo. +echo Creating tests project files +echo. +create_project ..\.. --tests --msvc --msvc-version 9 +goto done + :clean_check echo. set cleananswer=N @@ -88,6 +97,7 @@ del /Q *.vsprops > NUL 2>&1 del /Q *.sln* > NUL 2>&1 del /Q scummvm* > NUL 2>&1 del /Q devtools* > NUL 2>&1 +del /Q test_runner.cpp goto done :done diff --git a/dists/scummvm.rc b/dists/scummvm.rc index f3fa14c95a..037db3ef62 100644 --- a/dists/scummvm.rc +++ b/dists/scummvm.rc @@ -32,6 +32,9 @@ kyra.dat FILE "dists/engine-data/kyra.dat" #if ENABLE_LURE == STATIC_PLUGIN lure.dat FILE "dists/engine-data/lure.dat" #endif +#if ENABLE_MORTEVIELLE == STATIC_PLUGIN +mort.dat FILE "dists/engine-data/mort.dat" +#endif #if ENABLE_NEVERHOOD == STATIC_PLUGIN neverhood.dat FILE "dists/engine-data/neverhood.dat" #endif diff --git a/dists/scummvm.rc.in b/dists/scummvm.rc.in index b7a87f4e3d..c18c18ef63 100644 --- a/dists/scummvm.rc.in +++ b/dists/scummvm.rc.in @@ -32,6 +32,9 @@ kyra.dat FILE "dists/engine-data/kyra.dat" #if ENABLE_LURE == STATIC_PLUGIN lure.dat FILE "dists/engine-data/lure.dat" #endif +#if ENABLE_MORTEVIELLE == STATIC_PLUGIN +mort.dat FILE "dists/engine-data/mort.dat" +#endif #if ENABLE_NEVERHOOD == STATIC_PLUGIN neverhood.dat FILE "dists/engine-data/neverhood.dat" #endif diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp index b1d1008b60..fd0c8dc2da 100644 --- a/engines/advancedDetector.cpp +++ b/engines/advancedDetector.cpp @@ -29,7 +29,7 @@ #include "common/system.h" #include "common/textconsole.h" #include "common/translation.h" - +#include "gui/EventRecorder.h" #include "engines/advancedDetector.h" #include "engines/obsolete.h" @@ -301,6 +301,7 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) return Common::kUserCanceled; debug(2, "Running %s", gameDescriptor.description().c_str()); + initSubSystems(agdDesc); if (!createInstance(syst, engine, agdDesc)) return Common::kNoGameDataFoundError; else @@ -606,3 +607,11 @@ AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, con _maxScanDepth = 1; _directoryGlobs = NULL; } + +void AdvancedMetaEngine::initSubSystems(const ADGameDescription *gameDesc) const { +#ifdef ENABLE_EVENTRECORDER + if (gameDesc) { + g_eventRec.processGameDescription(gameDesc); + } +#endif +} diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h index 3eec33abe5..71d2c4a446 100644 --- a/engines/advancedDetector.h +++ b/engines/advancedDetector.h @@ -280,6 +280,9 @@ protected: return 0; } +private: + void initSubSystems(const ADGameDescription *gameDesc) const; + protected: /** * Detect games in specified directory. diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp index 1c342183cd..57561c00ee 100644 --- a/engines/agi/agi.cpp +++ b/engines/agi/agi.cpp @@ -598,8 +598,8 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas _console = NULL; _egoHoldKey = false; - - + + } void AgiEngine::initialize() { diff --git a/engines/agi/preagi_troll.cpp b/engines/agi/preagi_troll.cpp index b7d2801076..17d980dfd8 100644 --- a/engines/agi/preagi_troll.cpp +++ b/engines/agi/preagi_troll.cpp @@ -190,6 +190,7 @@ void TrollEngine::inventory() { break; case IDI_TRO_MAX_TREASURE: drawStr(3, 17, kColorDefault, IDS_TRO_TREASURE_2); + break; default: sprintf(tmp, IDS_TRO_TREASURE_4, _treasuresLeft); drawStr(20, 10, kColorDefault, tmp); @@ -219,6 +220,7 @@ void TrollEngine::waitAnyKeyIntro() { switch (iMsg) { case 200: iMsg = 0; + // fall through case 0: drawStr(22, 3, kColorDefault, IDS_TRO_INTRO_2); _gfx->doUpdate(); diff --git a/engines/agi/preagi_winnie.cpp b/engines/agi/preagi_winnie.cpp index bbe9ddd0c6..1be385be37 100644 --- a/engines/agi/preagi_winnie.cpp +++ b/engines/agi/preagi_winnie.cpp @@ -985,6 +985,7 @@ void WinnieEngine::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) { } break; } + break; default: if (!event.kbd.flags) { // if the control/alt/shift keys are not pressed keyHelp(); diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp index 9176412e0e..40c9d1d049 100644 --- a/engines/agos/animation.cpp +++ b/engines/agos/animation.cpp @@ -272,7 +272,7 @@ void MoviePlayerDXA::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { if (!surface) return; - byte *src = (byte *)surface->pixels; + const byte *src = (const byte *)surface->getPixels(); dst += y * pitch + x; do { @@ -344,7 +344,7 @@ void MoviePlayerDXA::handleNextFrame() { bool MoviePlayerDXA::processFrame() { Graphics::Surface *screen = _vm->_system->lockScreen(); - copyFrameToBuffer((byte *)screen->pixels, (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, screen->pitch); + copyFrameToBuffer((byte *)screen->getPixels(), (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, screen->pitch); _vm->_system->unlockScreen(); uint32 soundTime = _mixer->getSoundElapsedTime(_bgSound); @@ -443,7 +443,7 @@ void MoviePlayerSMK::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { if (!surface) return; - byte *src = (byte *)surface->pixels; + const byte *src = (const byte *)surface->getPixels(); dst += y * pitch + x; do { @@ -495,7 +495,7 @@ void MoviePlayerSMK::nextFrame() { bool MoviePlayerSMK::processFrame() { Graphics::Surface *screen = _vm->_system->lockScreen(); - copyFrameToBuffer((byte *)screen->pixels, (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, screen->pitch); + copyFrameToBuffer((byte *)screen->getPixels(), (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, screen->pitch); _vm->_system->unlockScreen(); uint32 waitTime = getTimeToNextFrame(); diff --git a/engines/agos/charset-fontdata.cpp b/engines/agos/charset-fontdata.cpp index 262ae44f01..b6b90eefcc 100644 --- a/engines/agos/charset-fontdata.cpp +++ b/engines/agos/charset-fontdata.cpp @@ -2924,7 +2924,7 @@ void AGOSEngine::windowDrawChar(WindowBlock *window, uint x, uint y, byte chr) { Graphics::Surface *screen = _system->lockScreen(); if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) { - dst = (byte *)screen->pixels; + dst = (byte *)screen->getPixels(); dstPitch = screen->pitch; h = 8; w = 6; @@ -2961,7 +2961,7 @@ void AGOSEngine::windowDrawChar(WindowBlock *window, uint x, uint y, byte chr) { error("windowDrawChar: Unknown language %d", _language); } } else if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) { - dst = (byte *)screen->pixels; + dst = (byte *)screen->getPixels(); dstPitch = screen->pitch; h = 8; w = 6; @@ -2986,14 +2986,14 @@ void AGOSEngine::windowDrawChar(WindowBlock *window, uint x, uint y, byte chr) { error("windowDrawChar: Unknown language %d", _language); } } else if (getGameType() == GType_ELVIRA1) { - dst = (byte *)screen->pixels; + dst = (byte *)screen->getPixels(); dstPitch = screen->pitch; h = 8; w = 6; src = english_elvira1Font + (chr - 32) * 8; } else { - dst = (byte *)screen->pixels; + dst = (byte *)screen->getPixels(); dstPitch = screen->pitch; h = 8; w = 8; diff --git a/engines/agos/charset.cpp b/engines/agos/charset.cpp index f58f4397b5..eca9728643 100644 --- a/engines/agos/charset.cpp +++ b/engines/agos/charset.cpp @@ -362,7 +362,7 @@ void AGOSEngine::windowScroll(WindowBlock *window) { w = window->width * 8; h = (window->height -1) * 8; - dst = (byte *)screen->pixels + window->y * screen->pitch + window->x * 8; + dst = (byte *)screen->getBasePtr(window->x * 8, window->y); src = dst + 8 * screen->pitch; do { diff --git a/engines/agos/draw.cpp b/engines/agos/draw.cpp index cf3a12ceb8..d27aed29db 100644 --- a/engines/agos/draw.cpp +++ b/engines/agos/draw.cpp @@ -32,15 +32,15 @@ namespace AGOS { byte *AGOSEngine::getBackBuf() { - return (byte *)_backBuf->pixels; + return (byte *)_backBuf->getPixels(); } byte *AGOSEngine::getBackGround() { - return (byte *)_backGroundBuf->pixels; + return (byte *)_backGroundBuf->getPixels(); } byte *AGOSEngine::getScaleBuf() { - return (byte *)_scaleBuf->pixels; + return (byte *)_scaleBuf->getPixels(); } #ifdef ENABLE_AGOS2 @@ -226,7 +226,7 @@ void AGOSEngine::animateSprites() { debug(0, "Using special wall"); uint8 color, h, len; - byte *dst = (byte *)_window4BackScn->pixels; + byte *dst = (byte *)_window4BackScn->getPixels(); color = (_variableArray[293] & 1) ? 13 : 15; _wallOn = 2; @@ -256,7 +256,7 @@ void AGOSEngine::animateSprites() { } else if (getGameType() == GType_ELVIRA2 && _variableArray[71] & 2) { // Used by the Unholy Barrier spell uint8 color, h, len; - byte *dst = (byte *)_window4BackScn->pixels; + byte *dst = (byte *)_window4BackScn->getPixels(); color = 1; _wallOn = 2; @@ -491,7 +491,7 @@ void AGOSEngine::saveBackGround(VgaSprite *vsp) { int16 y = vsp->y - _scrollY; if (_window3Flag == 1) { - animTable->srcPtr = (const byte *)_window4BackScn->pixels; + animTable->srcPtr = (const byte *)_window4BackScn->getPixels(); } else { int xoffs = (_videoWindows[vsp->windowNum * 4 + 0] * 2 + x) * 8; int yoffs = (_videoWindows[vsp->windowNum * 4 + 1] + y); @@ -565,7 +565,7 @@ void AGOSEngine::displayBoxStars() { if (x_ >= 311) continue; - dst = (byte *)screen->pixels; + dst = (byte *)screen->getPixels(); dst += (((screen->pitch / 4) * y_) * 4) + x_; @@ -673,7 +673,7 @@ void AGOSEngine::scrollScreen() { if (getGameType() == GType_SIMON2) { src = getBackGround(); - dst = (byte *)_window4BackScn->pixels; + dst = (byte *)_window4BackScn->getPixels(); for (int i = 0; i < _scrollHeight; i++) { memcpy(dst, src, _screenWidth); src += _backGroundBuf->pitch; @@ -725,7 +725,7 @@ void AGOSEngine::fillBackFromBackGround(uint16 height, uint16 width) { void AGOSEngine::fillBackFromFront() { Graphics::Surface *screen = _system->lockScreen(); - byte *src = (byte *)screen->pixels; + byte *src = (byte *)screen->getPixels(); byte *dst = getBackBuf(); for (int i = 0; i < _screenHeight; i++) { @@ -748,7 +748,7 @@ void AGOSEngine::fillBackGroundFromBack() { void AGOSEngine::fillBackGroundFromFront() { Graphics::Surface *screen = _system->lockScreen(); - byte *src = (byte *)screen->pixels; + byte *src = (byte *)screen->getPixels(); byte *dst = getBackGround(); for (int i = 0; i < _screenHeight; i++) { @@ -785,7 +785,7 @@ void AGOSEngine::displayScreen() { Graphics::Surface *screen = _system->lockScreen(); if (getGameType() == GType_PP || getGameType() == GType_FF) { byte *src = getBackBuf(); - byte *dst = (byte *)screen->pixels; + byte *dst = (byte *)screen->getPixels(); for (int i = 0; i < _screenHeight; i++) { memcpy(dst, src, _screenWidth); src += _backBuf->pitch; @@ -798,9 +798,9 @@ void AGOSEngine::displayScreen() { _window4Flag = 0; uint16 srcWidth, width, height; - byte *dst = (byte *)screen->pixels; + byte *dst = (byte *)screen->getPixels(); - const byte *src = (const byte *)_window4BackScn->pixels; + const byte *src = (const byte *)_window4BackScn->getPixels(); if (_window3Flag == 1) { src = getBackGround(); } @@ -831,8 +831,8 @@ void AGOSEngine::displayScreen() { if (_window6Flag == 2) { _window6Flag = 0; - byte *src = (byte *)_window6BackScn->pixels; - byte *dst = (byte *)screen->pixels + 51 * screen->pitch; + byte *src = (byte *)_window6BackScn->getPixels(); + byte *dst = (byte *)screen->getBasePtr(0, 51); for (int i = 0; i < 80; i++) { memcpy(dst, src, _window6BackScn->w); dst += screen->pitch; diff --git a/engines/agos/event.cpp b/engines/agos/event.cpp index cc1c40c207..65c7f7fd77 100644 --- a/engines/agos/event.cpp +++ b/engines/agos/event.cpp @@ -365,7 +365,7 @@ void AGOSEngine::drawStuff(const byte *src, uint xoffs) { const uint8 y = (getPlatform() == Common::kPlatformAtariST) ? 132 : 135; Graphics::Surface *screen = _system->lockScreen(); - byte *dst = (byte *)screen->pixels + y * screen->pitch + xoffs; + byte *dst = (byte *)screen->getBasePtr(xoffs, y); for (uint h = 0; h < 6; h++) { memcpy(dst, src, 4); diff --git a/engines/agos/gfx.cpp b/engines/agos/gfx.cpp index db0817250b..266fcc9796 100644 --- a/engines/agos/gfx.cpp +++ b/engines/agos/gfx.cpp @@ -649,7 +649,7 @@ void AGOSEngine_Simon1::drawImage(VC10_state *state) { state->surf2_addr = getBackGround(); state->surf2_pitch = _backGroundBuf->pitch; - state->surf_addr = (byte *)_window4BackScn->pixels; + state->surf_addr = (byte *)_window4BackScn->getPixels(); state->surf_pitch = _window4BackScn->pitch; xoffs = ((vlut[0] - _videoWindows[16]) * 2 + state->x) * 8; @@ -666,7 +666,7 @@ void AGOSEngine_Simon1::drawImage(VC10_state *state) { state->surf2_addr = getBackGround(); state->surf2_pitch = _backGroundBuf->pitch; - state->surf_addr = (byte *)_window4BackScn->pixels; + state->surf_addr = (byte *)_window4BackScn->getPixels(); state->surf_pitch = _videoWindows[18] * 16; xoffs = ((vlut[0] - _videoWindows[16]) * 2 + state->x) * 8; @@ -678,7 +678,7 @@ void AGOSEngine_Simon1::drawImage(VC10_state *state) { _window4Flag = 1; } else { - state->surf_addr = (byte *)screen->pixels; + state->surf_addr = (byte *)screen->getPixels(); state->surf_pitch = screen->pitch; xoffs = (vlut[0] * 2 + state->x) * 8; @@ -696,7 +696,7 @@ void AGOSEngine_Simon1::drawImage(VC10_state *state) { state->surf2_addr = getBackGround(); state->surf2_pitch = _backGroundBuf->pitch; - state->surf_addr = (byte *)_window4BackScn->pixels; + state->surf_addr = (byte *)_window4BackScn->getPixels(); state->surf_pitch = _window4BackScn->pitch; } @@ -712,7 +712,7 @@ void AGOSEngine_Simon1::drawImage(VC10_state *state) { state->surf2_addr = getBackGround(); state->surf2_pitch = _backGroundBuf->pitch; - state->surf_addr = (byte *)screen->pixels; + state->surf_addr = (byte *)screen->getPixels(); state->surf_pitch = screen->pitch; xoffs = (vlut[0] * 2 + state->x) * 8; @@ -861,7 +861,7 @@ void AGOSEngine::drawImage(VC10_state *state) { uint16 xoffs = 0, yoffs = 0; if (getGameType() == GType_WW) { if (_windowNum == 4 || (_windowNum >= 10 && _windowNum <= 27)) { - state->surf_addr = (byte *)_window4BackScn->pixels; + state->surf_addr = (byte *)_window4BackScn->getPixels(); state->surf_pitch = _videoWindows[18] * 16; xoffs = ((vlut[0] - _videoWindows[16]) * 2 + state->x) * 8; @@ -873,7 +873,7 @@ void AGOSEngine::drawImage(VC10_state *state) { _window4Flag = 1; } else { - state->surf_addr = (byte *)screen->pixels; + state->surf_addr = (byte *)screen->getPixels(); state->surf_pitch = screen->pitch; xoffs = (vlut[0] * 2 + state->x) * 8; @@ -881,7 +881,7 @@ void AGOSEngine::drawImage(VC10_state *state) { } } else if (getGameType() == GType_ELVIRA2) { if (_windowNum == 4 || _windowNum >= 10) { - state->surf_addr = (byte *)_window4BackScn->pixels; + state->surf_addr = (byte *)_window4BackScn->getPixels(); state->surf_pitch = _videoWindows[18] * 16; xoffs = ((vlut[0] - _videoWindows[16]) * 2 + state->x) * 8; @@ -893,7 +893,7 @@ void AGOSEngine::drawImage(VC10_state *state) { _window4Flag = 1; } else { - state->surf_addr = (byte *)screen->pixels; + state->surf_addr = (byte *)screen->getPixels(); state->surf_pitch = screen->pitch; xoffs = (vlut[0] * 2 + state->x) * 8; @@ -901,19 +901,19 @@ void AGOSEngine::drawImage(VC10_state *state) { } } else if (getGameType() == GType_ELVIRA1) { if (_windowNum == 6) { - state->surf_addr = (byte *)_window6BackScn->pixels; + state->surf_addr = (byte *)_window6BackScn->getPixels(); state->surf_pitch = _window6BackScn->pitch; xoffs = state->x * 8; yoffs = state->y; } else if (_windowNum == 2 || _windowNum == 3) { - state->surf_addr = (byte *)screen->pixels; + state->surf_addr = (byte *)screen->getPixels(); state->surf_pitch = screen->pitch; xoffs = (vlut[0] * 2 + state->x) * 8; yoffs = vlut[1] + state->y; } else { - state->surf_addr = (byte *)_window4BackScn->pixels; + state->surf_addr = (byte *)_window4BackScn->getPixels(); state->surf_pitch = _videoWindows[18] * 16; xoffs = ((vlut[0] - _videoWindows[16]) * 2 + state->x) * 8; @@ -926,7 +926,7 @@ void AGOSEngine::drawImage(VC10_state *state) { _window4Flag = 1; } } else { - state->surf_addr = (byte *)screen->pixels; + state->surf_addr = (byte *)screen->getPixels(); state->surf_pitch = screen->pitch; xoffs = (vlut[0] * 2 + state->x) * 8; @@ -973,7 +973,7 @@ void AGOSEngine::horizontalScroll(VC10_state *state) { vcWriteVar(251, _scrollX); if (getGameType() == GType_SIMON2) { - dst = (byte *)_window4BackScn->pixels; + dst = (byte *)_window4BackScn->getPixels(); dstPitch = _window4BackScn->pitch; } else { dst = getBackBuf(); @@ -1375,10 +1375,10 @@ void AGOSEngine::setWindowImage(uint16 mode, uint16 vgaSpriteId, bool specialCas } else if (getGameType() == GType_SIMON1 && (getFeatures() & GF_DEMO)) { // The DOS Floppy demo was based off Waxworks engine if (updateWindow == 4 || updateWindow >= 10) { - src = (byte *)_window4BackScn->pixels; + src = (byte *)_window4BackScn->getPixels(); srcWidth = _videoWindows[18] * 16; } else if (updateWindow == 3 || updateWindow == 9) { - src = (byte *)screen->pixels + yoffs * screen->pitch + xoffs; + src = (byte *)screen->getBasePtr(xoffs, yoffs); srcWidth = screen->pitch; } else { _system->unlockScreen(); @@ -1387,13 +1387,13 @@ void AGOSEngine::setWindowImage(uint16 mode, uint16 vgaSpriteId, bool specialCas } } else if (getGameType() == GType_SIMON1) { if (updateWindow == 4) { - src = (byte *)_window4BackScn->pixels; + src = (byte *)_window4BackScn->getPixels(); srcWidth = _videoWindows[18] * 16; } else if (updateWindow >= 10) { - src = (byte *)_window4BackScn->pixels + xoffs + yoffs * 320; + src = (byte *)_window4BackScn->getBasePtr(xoffs, yoffs); srcWidth = _videoWindows[18] * 16; } else if (updateWindow == 0) { - src = (byte *)screen->pixels + yoffs * screen->pitch + xoffs; + src = (byte *)screen->getBasePtr(xoffs, yoffs); srcWidth = screen->pitch; } else { _system->unlockScreen(); @@ -1402,10 +1402,10 @@ void AGOSEngine::setWindowImage(uint16 mode, uint16 vgaSpriteId, bool specialCas } } else if (getGameType() == GType_WW) { if (updateWindow == 4 || updateWindow >= 10) { - src = (byte *)_window4BackScn->pixels; + src = (byte *)_window4BackScn->getPixels(); srcWidth = _videoWindows[18] * 16; } else if (updateWindow == 3 || updateWindow == 9) { - src = (byte *)screen->pixels + yoffs * screen->pitch + xoffs; + src = (byte *)screen->getBasePtr(xoffs, yoffs); srcWidth = screen->pitch; } else { _system->unlockScreen(); @@ -1414,10 +1414,10 @@ void AGOSEngine::setWindowImage(uint16 mode, uint16 vgaSpriteId, bool specialCas } } else if (getGameType() == GType_ELVIRA2) { if (updateWindow == 4 || updateWindow >= 10) { - src = (byte *)_window4BackScn->pixels; + src = (byte *)_window4BackScn->getPixels(); srcWidth = _videoWindows[18] * 16; } else if (updateWindow == 3) { - src = (byte *)screen->pixels + yoffs * screen->pitch + xoffs; + src = (byte *)screen->getBasePtr(xoffs, yoffs); srcWidth = screen->pitch; } else { _system->unlockScreen(); @@ -1427,17 +1427,17 @@ void AGOSEngine::setWindowImage(uint16 mode, uint16 vgaSpriteId, bool specialCas } else if (getGameType() == GType_ELVIRA1) { if (updateWindow == 6) { _window6Flag = 1; - src = (byte *)_window6BackScn->pixels; + src = (byte *)_window6BackScn->getPixels(); srcWidth = 48; } else if (updateWindow == 2 || updateWindow == 3) { - src = (byte *)screen->pixels + yoffs * screen->pitch + xoffs; + src = (byte *)screen->getBasePtr(xoffs, yoffs); srcWidth = screen->pitch; } else { - src = (byte *)_window4BackScn->pixels; + src = (byte *)_window4BackScn->getPixels(); srcWidth = _videoWindows[18] * 16; } } else { - src = (byte *)screen->pixels + yoffs * screen->pitch + xoffs; + src = (byte *)screen->getBasePtr(xoffs, yoffs); srcWidth = screen->pitch; } @@ -1451,13 +1451,13 @@ void AGOSEngine::setWindowImage(uint16 mode, uint16 vgaSpriteId, bool specialCas if (getGameType() == GType_PN && !_wiped && !specialCase) { uint8 color = (getPlatform() == Common::kPlatformDOS) ? 7 : 15; - dst = (byte *)screen->pixels + 48; + dst = (byte *)screen->getBasePtr(48, 0); memset(dst, color, 224); - dst = (byte *)screen->pixels + 132 * screen->pitch + 48; + dst = (byte *)screen->getBasePtr(48, 132); memset(dst, color, 224); } else if (getGameType() == GType_ELVIRA1 && updateWindow == 3 && _bottomPalette) { - dst = (byte *)screen->pixels + 133 * screen->pitch; + dst = (byte *)screen->getBasePtr(0, 133); for (int h = 0; h < 67; h++) { for (int w = 0; w < _screenWidth; w++) @@ -1479,7 +1479,7 @@ void AGOSEngine::drawEdging() { Graphics::Surface *screen = _system->lockScreen(); - dst = (byte *)screen->pixels + 136 * screen->pitch; + dst = (byte *)screen->getBasePtr(0, 136); uint8 len = 52; while (len--) { @@ -1488,7 +1488,7 @@ void AGOSEngine::drawEdging() { dst += screen->pitch; } - dst = (byte *)screen->pixels + 187 * screen->pitch; + dst = (byte *)screen->getBasePtr(0, 187); memset(dst, color, _screenWidth); _system->unlockScreen(); diff --git a/engines/agos/icons.cpp b/engines/agos/icons.cpp index 0ee1d62fde..6d4192da2a 100644 --- a/engines/agos/icons.cpp +++ b/engines/agos/icons.cpp @@ -202,7 +202,7 @@ void AGOSEngine_Simon2::drawIcon(WindowBlock *window, uint icon, uint x, uint y) _videoLockOut |= 0x8000; Graphics::Surface *screen = _system->lockScreen(); - dst = (byte *)screen->pixels; + dst = (byte *)screen->getPixels(); dst += 110; dst += x; @@ -228,7 +228,7 @@ void AGOSEngine_Simon1::drawIcon(WindowBlock *window, uint icon, uint x, uint y) _videoLockOut |= 0x8000; Graphics::Surface *screen = _system->lockScreen(); - dst = (byte *)screen->pixels; + dst = (byte *)screen->getPixels(); dst += (x + window->x) * 8; dst += (y * 25 + window->y) * screen->pitch; @@ -256,7 +256,7 @@ void AGOSEngine_Waxworks::drawIcon(WindowBlock *window, uint icon, uint x, uint _videoLockOut |= 0x8000; Graphics::Surface *screen = _system->lockScreen(); - dst = (byte *)screen->pixels; + dst = (byte *)screen->getPixels(); dst += (x + window->x) * 8; dst += (y * 20 + window->y) * screen->pitch; @@ -284,7 +284,7 @@ void AGOSEngine_Elvira2::drawIcon(WindowBlock *window, uint icon, uint x, uint y _videoLockOut |= 0x8000; Graphics::Surface *screen = _system->lockScreen(); - dst = (byte *)screen->pixels; + dst = (byte *)screen->getPixels(); dst += (x + window->x) * 8; dst += (y * 8 + window->y) * screen->pitch; @@ -312,7 +312,7 @@ void AGOSEngine_Elvira1::drawIcon(WindowBlock *window, uint icon, uint x, uint y _videoLockOut |= 0x8000; Graphics::Surface *screen = _system->lockScreen(); - dst = (byte *)screen->pixels; + dst = (byte *)screen->getPixels(); dst += (x + window->x) * 8; dst += (y * 8 + window->y) * screen->pitch; @@ -339,7 +339,7 @@ void AGOSEngine::drawIcon(WindowBlock *window, uint icon, uint x, uint y) { _videoLockOut |= 0x8000; Graphics::Surface *screen = _system->lockScreen(); - dst = (byte *)screen->pixels + y * screen->pitch + x * 8; + dst = (byte *)screen->getBasePtr(x * 8, y); src = _iconFilePtr + icon * 146; if (icon == 0xFF) { @@ -951,7 +951,7 @@ void AGOSEngine::drawArrow(uint16 x, uint16 y, int8 dir) { } Graphics::Surface *screen = _system->lockScreen(); - byte *dst = (byte *)screen->pixels + y * screen->pitch + x * 8; + byte *dst = (byte *)screen->getBasePtr(x * 8, y); for (h = 0; h < 19; h++) { for (w = 0; w < 16; w++) { @@ -1042,7 +1042,7 @@ static const byte hitBarData[12 * 7] = { // Personal Nightmare specific void AGOSEngine_PN::drawIconHitBar() { Graphics::Surface *screen = _system->lockScreen(); - byte *dst = (byte *)screen->pixels + 3 * screen->pitch + 6 * 8; + byte *dst = (byte *)screen->getBasePtr(6 * 8, 3); const byte *src = hitBarData; uint8 color = (getPlatform() == Common::kPlatformDOS) ? 7 : 15; diff --git a/engines/agos/menus.cpp b/engines/agos/menus.cpp index a0d2bdcaa0..85c50e421b 100644 --- a/engines/agos/menus.cpp +++ b/engines/agos/menus.cpp @@ -164,7 +164,7 @@ void AGOSEngine::unlightMenuStrip() { mouseOff(); Graphics::Surface *screen = _system->lockScreen(); - src = (byte *)screen->pixels + 8 * screen->pitch + 272; + src = (byte *)screen->getBasePtr(272, 8); w = 48; h = 82; @@ -192,7 +192,7 @@ void AGOSEngine::lightMenuBox(uint hitarea) { mouseOff(); Graphics::Surface *screen = _system->lockScreen(); - src = (byte *)screen->pixels + ha->y * screen->pitch + ha->x; + src = (byte *)screen->getBasePtr(ha->x, ha->y); w = ha->width; h = ha->height; diff --git a/engines/agos/verb.cpp b/engines/agos/verb.cpp index 93077ed83e..f5b57a01c8 100644 --- a/engines/agos/verb.cpp +++ b/engines/agos/verb.cpp @@ -973,7 +973,7 @@ void AGOSEngine::invertBox(HitArea *ha, byte a, byte b, byte c, byte d) { _videoLockOut |= 0x8000; Graphics::Surface *screen = _system->lockScreen(); - src = (byte *)screen->pixels + ha->y * screen->pitch + ha->x; + src = (byte *)screen->getBasePtr(ha->x, ha->y); // WORKAROUND: Hitareas for saved game names aren't adjusted for scrolling locations if (getGameType() == GType_SIMON2 && ha->id >= 208 && ha->id <= 213) { diff --git a/engines/agos/vga.cpp b/engines/agos/vga.cpp index 8541f579d6..cc5ede5f2c 100644 --- a/engines/agos/vga.cpp +++ b/engines/agos/vga.cpp @@ -1179,7 +1179,7 @@ void AGOSEngine::vc32_saveScreen() { if (getGameType() == GType_PN) { Graphics::Surface *screen = _system->lockScreen(); byte *dst = getBackGround(); - byte *src = (byte *)screen->pixels; + byte *src = (byte *)screen->getPixels(); for (int i = 0; i < _screenHeight; i++) { memcpy(dst, src, _screenWidth); dst += _backGroundBuf->pitch; @@ -1193,7 +1193,7 @@ void AGOSEngine::vc32_saveScreen() { uint16 height = _videoWindows[4 * 4 + 3]; byte *dst = (byte *)_backGroundBuf->getBasePtr(xoffs, yoffs); - byte *src = (byte *)_window4BackScn->pixels; + byte *src = (byte *)_window4BackScn->getPixels(); uint16 srcWidth = _videoWindows[4 * 4 + 2] * 16; for (; height > 0; height--) { memcpy(dst, src, width); @@ -1247,7 +1247,7 @@ void AGOSEngine::clearVideoWindow(uint16 num, uint16 color) { if (getGameType() == GType_ELVIRA1 && num == 3) { Graphics::Surface *screen = _system->lockScreen(); - byte *dst = (byte *)screen->pixels; + byte *dst = (byte *)screen->getPixels(); for (int i = 0; i < _screenHeight; i++) { memset(dst, color, _screenWidth); dst += screen->pitch; @@ -1258,7 +1258,10 @@ void AGOSEngine::clearVideoWindow(uint16 num, uint16 color) { uint16 xoffs = (vlut[0] - _videoWindows[16]) * 16; uint16 yoffs = (vlut[1] - _videoWindows[17]); uint16 dstWidth = _videoWindows[18] * 16; - byte *dst = (byte *)_window4BackScn->pixels + xoffs + yoffs * dstWidth; + // TODO: Is there any known connection between dstWidth and the pitch + // of the _window4BackScn Surface? If so, we might be able to pass + // yoffs as proper y parameter to getBasePtr. + byte *dst = (byte *)_window4BackScn->getBasePtr(xoffs, 0) + yoffs * dstWidth; setMoveRect(0, 0, vlut[2] * 16, vlut[3]); diff --git a/engines/agos/vga_e2.cpp b/engines/agos/vga_e2.cpp index d4aafd3d7b..4eb337c687 100644 --- a/engines/agos/vga_e2.cpp +++ b/engines/agos/vga_e2.cpp @@ -76,7 +76,7 @@ void AGOSEngine::vc45_setWindowPalette() { uint8 height = vlut[3]; if (num == 4) { - byte *dst = (byte *)_window4BackScn->pixels; + byte *dst = (byte *)_window4BackScn->getPixels(); for (uint8 h = 0; h < height; h++) { for (uint8 w = 0; w < width; w++) { @@ -223,11 +223,11 @@ void AGOSEngine::vc53_dissolveIn() { uint16 count = dissolveCheck * 2; while (count--) { Graphics::Surface *screen = _system->lockScreen(); - byte *dstPtr = (byte *)screen->pixels + x + y * screen->pitch; + byte *dstPtr = (byte *)screen->getBasePtr(x, y); yoffs = _rnd.getRandomNumber(dissolveY); dst = dstPtr + yoffs * screen->pitch; - src = (byte *)_window4BackScn->pixels + yoffs * _window4BackScn->pitch; + src = (byte *)_window4BackScn->getBasePtr(0, yoffs); xoffs = _rnd.getRandomNumber(dissolveX); dst += xoffs; @@ -296,7 +296,7 @@ void AGOSEngine::vc54_dissolveOut() { uint16 count = dissolveCheck * 2; while (count--) { Graphics::Surface *screen = _system->lockScreen(); - byte *dstPtr = (byte *)screen->pixels + x + y * screen->pitch; + byte *dstPtr = (byte *)screen->getBasePtr(x, y); color |= dstPtr[0] & 0xF0; yoffs = _rnd.getRandomNumber(dissolveY); @@ -378,7 +378,7 @@ void AGOSEngine::fullFade() { void AGOSEngine::vc56_fullScreen() { Graphics::Surface *screen = _system->lockScreen(); - byte *dst = (byte *)screen->pixels; + byte *dst = (byte *)screen->getPixels(); byte *src = _curVgaFile2 + 800; for (int i = 0; i < _screenHeight; i++) { diff --git a/engines/agos/vga_pn.cpp b/engines/agos/vga_pn.cpp index 1e7b2ba060..b7f80ebf91 100644 --- a/engines/agos/vga_pn.cpp +++ b/engines/agos/vga_pn.cpp @@ -155,7 +155,7 @@ void AGOSEngine::vc48_specialEffect() { if (getPlatform() == Common::kPlatformDOS) { if (num == 1) { Graphics::Surface *screen = _system->lockScreen(); - byte *dst = (byte *)screen->pixels; + byte *dst = (byte *)screen->getPixels(); for (uint h = 0; h < _screenHeight; h++) { for (uint w = 0; w < _screenWidth; w++) { @@ -205,7 +205,7 @@ void AGOSEngine_PN::clearVideoWindow(uint16 num, uint16 color) { uint16 yoffs = vlut[1]; Graphics::Surface *screen = _system->lockScreen(); - byte *dst = (byte *)screen->pixels + xoffs + yoffs * screen->pitch; + byte *dst = (byte *)screen->getBasePtr(xoffs, yoffs); for (uint h = 0; h < vlut[3]; h++) { memset(dst, color, vlut[2] * 16); dst += screen->pitch; diff --git a/engines/agos/vga_s2.cpp b/engines/agos/vga_s2.cpp index 9b9ed4e297..e0780b491a 100644 --- a/engines/agos/vga_s2.cpp +++ b/engines/agos/vga_s2.cpp @@ -213,7 +213,10 @@ void AGOSEngine_Simon2::clearVideoWindow(uint16 num, uint16 color) { uint16 xoffs = vlut[0] * 16; uint16 yoffs = vlut[1]; uint16 dstWidth = _videoWindows[18] * 16; - byte *dst = (byte *)_window4BackScn->pixels + xoffs + yoffs * dstWidth; + // TODO: Is there any known connection between dstWidth and the pitch + // of the _window4BackScn Surface? If so, we might be able to pass + // yoffs as proper y parameter to getBasePtr. + byte *dst = (byte *)_window4BackScn->getBasePtr(xoffs, 0) + yoffs * dstWidth; setMoveRect(0, 0, vlut[2] * 16, vlut[3]); diff --git a/engines/agos/vga_ww.cpp b/engines/agos/vga_ww.cpp index c74f0cf52b..ca93fa9fec 100644 --- a/engines/agos/vga_ww.cpp +++ b/engines/agos/vga_ww.cpp @@ -143,7 +143,7 @@ void AGOSEngine::vc61() { uint h, tmp; Graphics::Surface *screen = _system->lockScreen(); - dstPtr = (byte *)screen->pixels; + dstPtr = (byte *)screen->getPixels(); if (a == 6) { src = _curVgaFile2 + 800; diff --git a/engines/agos/window.cpp b/engines/agos/window.cpp index 0365c736d8..892df92554 100644 --- a/engines/agos/window.cpp +++ b/engines/agos/window.cpp @@ -170,7 +170,7 @@ void AGOSEngine::colorBlock(WindowBlock *window, uint16 x, uint16 y, uint16 w, u _videoLockOut |= 0x8000; Graphics::Surface *screen = _system->lockScreen(); - byte *dst = (byte *)screen->pixels + y * screen->pitch + x; + byte *dst = (byte *)screen->getBasePtr(x, y); uint8 color = window->fillColor; if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) @@ -232,7 +232,7 @@ void AGOSEngine::restoreBlock(uint16 x, uint16 y, uint16 w, uint16 h) { uint i; Graphics::Surface *screen = _system->lockScreen(); - dst = (byte *)screen->pixels; + dst = (byte *)screen->getPixels(); src = getBackGround(); dst += y * screen->pitch; diff --git a/engines/cge/cge.cpp b/engines/cge/cge.cpp index 6cc0c45963..af7e91f7eb 100644 --- a/engines/cge/cge.cpp +++ b/engines/cge/cge.cpp @@ -25,7 +25,6 @@ #include "common/debug.h" #include "common/debug-channels.h" #include "common/error.h" -#include "common/EventRecorder.h" #include "common/file.h" #include "common/fs.h" #include "engines/advancedDetector.h" diff --git a/engines/cge/cge_main.cpp b/engines/cge/cge_main.cpp index f4f1cd3e0b..ae4dee6090 100644 --- a/engines/cge/cge_main.cpp +++ b/engines/cge/cge_main.cpp @@ -358,7 +358,7 @@ void CGEEngine::writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &he // Create a thumbnail and save it Graphics::Surface *thumb = new Graphics::Surface(); Graphics::Surface *s = _vga->_page[0]; - ::createThumbnail(thumb, (const byte *)s->pixels, kScrWidth, kScrHeight, thumbPalette); + ::createThumbnail(thumb, (const byte *)s->getPixels(), kScrWidth, kScrHeight, thumbPalette); Graphics::saveThumbnail(*out, *thumb); thumb->free(); delete thumb; diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp index d29c1224fd..3b01421903 100644 --- a/engines/cge/detection.cpp +++ b/engines/cge/detection.cpp @@ -121,7 +121,7 @@ static const CgeGameDescription gameDescriptions[] = { "sfinx", "Sfinx Freeware", { {"vol.cat", 0, "21197b287d397c53261b6616bf0dd880", 129024}, - {"vol.dat", 0, "de14291869a8eb7c2732ab783c7542ef", 34180844}, + {"vol.dat", 0, "de14291869a8eb7c2732ab783c7542ef", 34180844}, AD_LISTEND }, Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO0() diff --git a/engines/cge/snail.cpp b/engines/cge/snail.cpp index edb8972040..b9030efb4d 100644 --- a/engines/cge/snail.cpp +++ b/engines/cge/snail.cpp @@ -494,7 +494,7 @@ void CGEEngine::snGame(Sprite *spr, int num) { _sprK3->step(newRandom(6)); // check the ALT key as it's the solution of the puzzle - // the test has been restricted to some specific OSes + // the test has been restricted to some specific OSes // in order to avoid some obvious issues (like Android, iOS, NDS, N64...) // Not perfect, but at least better than nothing. #if defined(WIN32) || defined(UNIX) || defined(MACOSX) || defined(MOTOEZX) || defined(LINUPY) || defined(LINUXMOTO_SDL) diff --git a/engines/cge/vga13h.cpp b/engines/cge/vga13h.cpp index 56a0754527..c0407cab42 100644 --- a/engines/cge/vga13h.cpp +++ b/engines/cge/vga13h.cpp @@ -826,7 +826,7 @@ void Vga::update() { } } - g_system->copyRectToScreen(Vga::_page[0]->getBasePtr(0, 0), kScrWidth, 0, 0, kScrWidth, kScrHeight); + g_system->copyRectToScreen(Vga::_page[0]->getPixels(), kScrWidth, 0, 0, kScrWidth, kScrHeight); g_system->updateScreen(); } @@ -845,7 +845,7 @@ void Bitmap::xShow(int16 x, int16 y) { debugC(4, kCGEDebugBitmap, "Bitmap::xShow(%d, %d)", x, y); const byte *srcP = (const byte *)_v; - byte *destEndP = (byte *)_vm->_vga->_page[1]->pixels + (kScrWidth * kScrHeight); + byte *destEndP = (byte *)_vm->_vga->_page[1]->getBasePtr(0, kScrHeight); byte *lookupTable = _m; // Loop through processing data for each plane. The game originally ran in plane mapped mode, where a @@ -898,7 +898,7 @@ void Bitmap::show(int16 x, int16 y) { debugC(5, kCGEDebugBitmap, "Bitmap::show(%d, %d)", x, y); const byte *srcP = (const byte *)_v; - byte *destEndP = (byte *)_vm->_vga->_page[1]->pixels + (kScrWidth * kScrHeight); + byte *destEndP = (byte *)_vm->_vga->_page[1]->getBasePtr(0, kScrHeight); // Loop through processing data for each plane. The game originally ran in plane mapped mode, where a // given plane holds each fourth pixel sequentially. So to handle an entire picture, each plane's data diff --git a/engines/composer/composer.h b/engines/composer/composer.h index 33a5356b3a..7d8022455a 100644 --- a/engines/composer/composer.h +++ b/engines/composer/composer.h @@ -23,7 +23,7 @@ #ifndef COMPOSER_H #define COMPOSER_H -#include "common/config-file.h" +#include "common/ini-file.h" #include "common/random.h" #include "common/system.h" #include "common/debug.h" @@ -174,7 +174,7 @@ private: Common::List<Sprite> _sprites; uint _directoriesToStrip; - Common::ConfigFile _bookIni; + Common::INIFile _bookIni; Common::String _bookGroup; Common::List<Library> _libraries; Common::Array<PendingPageChange> _pendingPageChanges; diff --git a/engines/composer/graphics.cpp b/engines/composer/graphics.cpp index 2b68fac233..caf3ba3a40 100644 --- a/engines/composer/graphics.cpp +++ b/engines/composer/graphics.cpp @@ -39,7 +39,7 @@ bool Sprite::contains(const Common::Point &pos) const { return false; if (adjustedPos.y < 0 || adjustedPos.y >= _surface.h) return false; - byte *pixels = (byte *)_surface.pixels; + const byte *pixels = (const byte *)_surface.getPixels(); return (pixels[(_surface.h - adjustedPos.y - 1) * _surface.w + adjustedPos.x] != 0); } @@ -541,7 +541,7 @@ void ComposerEngine::redraw() { for (uint i = 0; i < _dirtyRects.size(); i++) { const Common::Rect &rect = _dirtyRects[i]; - byte *pixels = (byte *)_screen.pixels + (rect.top * _screen.pitch) + rect.left; + byte *pixels = (byte *)_screen.getBasePtr(rect.left, rect.top); _system->copyRectToScreen(pixels, _screen.pitch, rect.left, rect.top, rect.width(), rect.height()); } _system->updateScreen(); @@ -794,7 +794,7 @@ bool ComposerEngine::initSprite(Sprite &sprite) { if (width > 0 && height > 0) { sprite._surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); - decompressBitmap(type, stream, (byte *)sprite._surface.pixels, size, width, height); + decompressBitmap(type, stream, (byte *)sprite._surface.getPixels(), size, width, height); } else { // there are some sprites (e.g. a -998x-998 one in Gregory's title screen) // which have an invalid size, but the original engine doesn't notice for @@ -814,13 +814,13 @@ void ComposerEngine::drawSprite(const Sprite &sprite) { int y = sprite._pos.y; // incoming data is BMP-style (bottom-up), so flip it - byte *pixels = (byte *)_screen.pixels; + byte *pixels = (byte *)_screen.getPixels(); for (int j = 0; j < sprite._surface.h; j++) { if (j + y < 0) continue; if (j + y >= _screen.h) break; - byte *in = (byte *)sprite._surface.pixels + (sprite._surface.h - j - 1) * sprite._surface.w; + const byte *in = (const byte *)sprite._surface.getBasePtr(0, sprite._surface.h - j - 1); byte *out = pixels + ((j + y) * _screen.w) + x; for (int i = 0; i < sprite._surface.w; i++) if ((x + i >= 0) && (x + i < _screen.w) && in[i]) diff --git a/engines/configure.engines b/engines/configure.engines index 0f059e6c61..7004f4111f 100644 --- a/engines/configure.engines +++ b/engines/configure.engines @@ -26,6 +26,7 @@ add_engine lastexpress "The Last Express" no "" "" "16bit" add_engine lure "Lure of the Temptress" yes add_engine made "MADE" yes add_engine mohawk "Mohawk" yes "cstime myst riven" "Living Books" +add_engine mortevielle "Mortevielle" no add_engine cstime "Where in Time is Carmen Sandiego?" no add_engine riven "Riven: The Sequel to Myst" no "" "" "16bit" add_engine myst "Myst" no "" "" "16bit" diff --git a/engines/cruise/cruise.h b/engines/cruise/cruise.h index 9782df8f09..3e49e77770 100644 --- a/engines/cruise/cruise.h +++ b/engines/cruise/cruise.h @@ -43,10 +43,6 @@ */ namespace Cruise { -enum CruiseGameType { - GType_CRUISE = 1 -}; - #define GAME_FRAME_DELAY_1 50 #define GAME_FRAME_DELAY_2 100 diff --git a/engines/cruise/detection.cpp b/engines/cruise/detection.cpp index b632e4ea7a..bce3f184db 100644 --- a/engines/cruise/detection.cpp +++ b/engines/cruise/detection.cpp @@ -20,8 +20,6 @@ * */ - - #include "base/plugins.h" #include "common/savefile.h" #include "common/system.h" @@ -34,21 +32,12 @@ namespace Cruise { struct CRUISEGameDescription { ADGameDescription desc; - - int gameType; - uint32 features; }; const char *CruiseEngine::getGameId() const { return _gameDescription->desc.gameid; } -int CruiseEngine::getGameType() const { - return _gameDescription->gameType; -} -uint32 CruiseEngine::getFeatures() const { - return _gameDescription->features; -} Common::Language CruiseEngine::getLanguage() const { return _gameDescription->desc.language; } @@ -77,8 +66,6 @@ static const CRUISEGameDescription gameDescriptions[] = { ADGF_NO_FLAGS, GUIO0() }, - GType_CRUISE, - 0, }, { { @@ -90,8 +77,6 @@ static const CRUISEGameDescription gameDescriptions[] = { ADGF_NO_FLAGS, GUIO0() }, - GType_CRUISE, - 0, }, { { @@ -103,8 +88,6 @@ static const CRUISEGameDescription gameDescriptions[] = { ADGF_NO_FLAGS, GUIO0() }, - GType_CRUISE, - 0, }, { { @@ -116,8 +99,6 @@ static const CRUISEGameDescription gameDescriptions[] = { ADGF_NO_FLAGS, GUIO0() }, - GType_CRUISE, - 0, }, { { @@ -129,8 +110,6 @@ static const CRUISEGameDescription gameDescriptions[] = { ADGF_NO_FLAGS, GUIO0() }, - GType_CRUISE, - 0, }, { { @@ -142,8 +121,6 @@ static const CRUISEGameDescription gameDescriptions[] = { ADGF_NO_FLAGS, GUIO0() }, - GType_CRUISE, - 0, }, { { @@ -155,8 +132,6 @@ static const CRUISEGameDescription gameDescriptions[] = { ADGF_NO_FLAGS, GUIO0() }, - GType_CRUISE, - 0, }, { // Amiga English US GOLD edition. { @@ -168,8 +143,6 @@ static const CRUISEGameDescription gameDescriptions[] = { ADGF_NO_FLAGS, GUIO0() }, - GType_CRUISE, - 0, }, { // Amiga Italian US GOLD edition. { @@ -181,8 +154,6 @@ static const CRUISEGameDescription gameDescriptions[] = { ADGF_NO_FLAGS, GUIO0() }, - GType_CRUISE, - 0, }, { // AtariST English KixxXL edition. { @@ -194,8 +165,6 @@ static const CRUISEGameDescription gameDescriptions[] = { ADGF_NO_FLAGS, GUIO0() }, - GType_CRUISE, - 0, }, { { @@ -207,8 +176,6 @@ static const CRUISEGameDescription gameDescriptions[] = { ADGF_NO_FLAGS, GUIO0() }, - GType_CRUISE, - 0, }, { { @@ -220,10 +187,8 @@ static const CRUISEGameDescription gameDescriptions[] = { ADGF_NO_FLAGS, GUIO0() }, - GType_CRUISE, - 0, }, - {AD_TABLE_END_MARKER, 0, 0} + {AD_TABLE_END_MARKER} }; } diff --git a/engines/draci/screen.cpp b/engines/draci/screen.cpp index 8c1a0c40f7..e43e367300 100644 --- a/engines/draci/screen.cpp +++ b/engines/draci/screen.cpp @@ -110,7 +110,7 @@ void Screen::copyToScreen() { // If a full update is needed, update the whole screen if (_surface->needsFullUpdate()) { - byte *ptr = (byte *)_surface->getBasePtr(0, 0); + byte *ptr = (byte *)_surface->getPixels(); _vm->_system->copyRectToScreen(ptr, kScreenWidth, 0, 0, kScreenWidth, kScreenHeight); @@ -138,7 +138,7 @@ void Screen::copyToScreen() { * Clears the screen and marks the whole screen dirty. */ void Screen::clearScreen() { - byte *ptr = (byte *)_surface->getBasePtr(0, 0); + byte *ptr = (byte *)_surface->getPixels(); _surface->markDirty(); diff --git a/engines/draci/surface.cpp b/engines/draci/surface.cpp index 8380f8777b..3676c6edac 100644 --- a/engines/draci/surface.cpp +++ b/engines/draci/surface.cpp @@ -80,7 +80,7 @@ void Surface::markClean() { * @brief Fills the surface with the specified color */ void Surface::fill(uint color) { - byte *ptr = (byte *)getBasePtr(0, 0); + byte *ptr = (byte *)getPixels(); memset(ptr, color, w * h); } diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h index e547503bee..c4d1c4c761 100644 --- a/engines/drascula/drascula.h +++ b/engines/drascula/drascula.h @@ -661,7 +661,7 @@ public: void animation_3_1(); // John talks with the bartender to book a room void animation_4_1(); // John talks with the pianist // - void animation_2_2(); // John enters the chapel via the window + void animation_2_2(); // John enters the chapel via the window void animation_4_2(); // John talks with the blind man (closeup) void animation_5_2(); // John breaks the chapel window with the pike void animation_6_2(); // The blind man (closeup) thanks John for giving him money and hands him the sickle diff --git a/engines/drascula/graphics.cpp b/engines/drascula/graphics.cpp index 3bdf724670..31d03a94a7 100644 --- a/engines/drascula/graphics.cpp +++ b/engines/drascula/graphics.cpp @@ -132,7 +132,7 @@ void DrasculaEngine::showFrame(Common::SeekableReadStream *stream, bool firstFra byte *prevFrame = (byte *)malloc(64000); Graphics::Surface *screenSurf = _system->lockScreen(); - byte *screenBuffer = (byte *)screenSurf->pixels; + byte *screenBuffer = (byte *)screenSurf->getPixels(); uint16 screenPitch = screenSurf->pitch; for (int y = 0; y < 200; y++) { memcpy(prevFrame+y*320, screenBuffer+y*screenPitch, 320); @@ -449,7 +449,7 @@ void DrasculaEngine::screenSaver() { int x1_, y1_, off1, off2; Graphics::Surface *screenSurf = _system->lockScreen(); - byte *screenBuffer = (byte *)screenSurf->pixels; + byte *screenBuffer = (byte *)screenSurf->getPixels(); uint16 screenPitch = screenSurf->pitch; for (int i = 0; i < 200; i++) { for (int j = 0; j < 320; j++) { @@ -538,7 +538,7 @@ int DrasculaEngine::playFrameSSN(Common::SeekableReadStream *stream) { waitFrameSSN(); Graphics::Surface *screenSurf = _system->lockScreen(); - byte *screenBuffer = (byte *)screenSurf->pixels; + byte *screenBuffer = (byte *)screenSurf->getPixels(); uint16 screenPitch = screenSurf->pitch; if (FrameSSN) mixVideo(screenBuffer, screenSurface, screenPitch); @@ -557,7 +557,7 @@ int DrasculaEngine::playFrameSSN(Common::SeekableReadStream *stream) { free(BufferSSN); waitFrameSSN(); Graphics::Surface *screenSurf = _system->lockScreen(); - byte *screenBuffer = (byte *)screenSurf->pixels; + byte *screenBuffer = (byte *)screenSurf->getPixels(); uint16 screenPitch = screenSurf->pitch; if (FrameSSN) mixVideo(screenBuffer, screenSurface, screenPitch); diff --git a/engines/dreamweb/dreamweb.cpp b/engines/dreamweb/dreamweb.cpp index c3ede46df2..08838a784a 100644 --- a/engines/dreamweb/dreamweb.cpp +++ b/engines/dreamweb/dreamweb.cpp @@ -23,7 +23,6 @@ #include "common/config-manager.h" #include "common/debug-channels.h" #include "common/events.h" -#include "common/EventRecorder.h" #include "common/file.h" #include "common/func.h" #include "common/system.h" diff --git a/engines/dreamweb/monitor.cpp b/engines/dreamweb/monitor.cpp index 1f9fa8d24f..108f9d2b60 100644 --- a/engines/dreamweb/monitor.cpp +++ b/engines/dreamweb/monitor.cpp @@ -104,7 +104,7 @@ void DreamWebEngine::useMon() { redrawMainScrn(); workToScreenM(); } - + int DreamWebEngine::findCommand(const char *const cmdList[]) { // Loop over all commands in the list and see if we get a match int cmd = 0; @@ -135,7 +135,7 @@ bool DreamWebEngine::execCommand() { "KEYS", NULL }; - + static const char *const comlistFR[] = { "SORTIR", "AIDE", @@ -145,7 +145,7 @@ bool DreamWebEngine::execCommand() { "TOUCHES", // should be CLES but it is translated as TOUCHES in the game... NULL }; - + static const char *const comlistDE[] = { "ENDE", "HILF", @@ -155,7 +155,7 @@ bool DreamWebEngine::execCommand() { "DATEN", NULL }; - + static const char *const comlistIT[] = { "ESCI", "AIUTO", @@ -165,7 +165,7 @@ bool DreamWebEngine::execCommand() { "CHIAVI", NULL }; - + static const char *const comlistES[] = { "SALIR", "AYUDA", diff --git a/engines/dreamweb/print.cpp b/engines/dreamweb/print.cpp index bc75b97e71..bec58322d5 100644 --- a/engines/dreamweb/print.cpp +++ b/engines/dreamweb/print.cpp @@ -67,7 +67,7 @@ void DreamWebEngine::printChar(const GraphicsFile &charSet, uint16* x, uint16 y, // characters (0 - 31). if (c < 32 || c == 255) return; - + uint8 dummyWidth, dummyHeight; if (width == NULL) width = &dummyWidth; diff --git a/engines/engines.mk b/engines/engines.mk index 4f38629dad..3401df37e5 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -140,6 +140,11 @@ DEFINES += -DENABLE_NEVERHOOD=$(ENABLE_NEVERHOOD) MODULES += engines/neverhood endif +ifdef ENABLE_MORTEVIELLE +DEFINES += -DENABLE_MORTEVIELLE=$(ENABLE_MORTEVIELLE) +MODULES += engines/mortevielle +endif + ifdef ENABLE_PARALLACTION DEFINES += -DENABLE_PARALLACTION=$(ENABLE_PARALLACTION) MODULES += engines/parallaction diff --git a/engines/gob/iniconfig.cpp b/engines/gob/iniconfig.cpp index bba531723c..032231bd4d 100644 --- a/engines/gob/iniconfig.cpp +++ b/engines/gob/iniconfig.cpp @@ -73,7 +73,7 @@ bool INIConfig::getConfig(const Common::String &file, Config &config) { } bool INIConfig::openConfig(const Common::String &file, Config &config) { - config.config = new Common::ConfigFile(); + config.config = new Common::INIFile(); config.created = false; if (!config.config->loadFromFile(file)) { @@ -89,7 +89,7 @@ bool INIConfig::openConfig(const Common::String &file, Config &config) { } bool INIConfig::createConfig(const Common::String &file, Config &config) { - config.config = new Common::ConfigFile(); + config.config = new Common::INIFile(); config.created = true; _configs.setVal(file, config); diff --git a/engines/gob/iniconfig.h b/engines/gob/iniconfig.h index bf60f2d125..c1890170dc 100644 --- a/engines/gob/iniconfig.h +++ b/engines/gob/iniconfig.h @@ -24,7 +24,7 @@ #define GOB_INICONFIG_H #include "common/str.h" -#include "common/config-file.h" +#include "common/ini-file.h" #include "common/hashmap.h" namespace Gob { @@ -43,7 +43,7 @@ public: private: struct Config { - Common::ConfigFile *config; + Common::INIFile *config; bool created; }; diff --git a/engines/gob/surface.cpp b/engines/gob/surface.cpp index 6b65eb6ab9..870b0f15b3 100644 --- a/engines/gob/surface.cpp +++ b/engines/gob/surface.cpp @@ -45,7 +45,7 @@ static void plotPixel(int x, int y, int color, void *data) { Pixel::Pixel(byte *vidMem, uint8 bpp, byte *min, byte *max) : _vidMem(vidMem), _bpp(bpp), _min(min), _max(max) { - assert((_bpp == 1) || (_bpp == 2)); + assert((_bpp == 1) || (_bpp == 2) || (_bpp == 4)); assert(_vidMem >= _min); assert(_vidMem < _max); } @@ -91,6 +91,8 @@ uint32 Pixel::get() const { return *((byte *) _vidMem); if (_bpp == 2) return *((uint16 *) _vidMem); + if (_bpp == 4) + return *((uint32 *) _vidMem); return 0; } @@ -103,6 +105,8 @@ void Pixel::set(uint32 p) { *((byte *) _vidMem) = (byte) p; if (_bpp == 2) *((uint16 *) _vidMem) = (uint16) p; + if (_bpp == 4) + *((uint32 *) _vidMem) = (uint32) p; } bool Pixel::isValid() const { @@ -113,7 +117,7 @@ bool Pixel::isValid() const { ConstPixel::ConstPixel(const byte *vidMem, uint8 bpp, const byte *min, const byte *max) : _vidMem(vidMem), _bpp(bpp), _min(min), _max(max) { - assert((_bpp == 1) || (_bpp == 2)); + assert((_bpp == 1) || (_bpp == 2) || (_bpp == 4)); assert(_vidMem >= _min); assert(_vidMem < _max); } @@ -159,6 +163,8 @@ uint32 ConstPixel::get() const { return *((const byte *) _vidMem); if (_bpp == 2) return *((const uint16 *) _vidMem); + if (_bpp == 4) + return *((const uint32 *) _vidMem); return 0; } @@ -172,7 +178,7 @@ Surface::Surface(uint16 width, uint16 height, uint8 bpp, byte *vidMem) : _width(width), _height(height), _bpp(bpp), _vidMem(vidMem) { assert((_width > 0) && (_height > 0)); - assert((_bpp == 1) || (_bpp == 2)); + assert((_bpp == 1) || (_bpp == 2) || (_bpp == 4)); if (!_vidMem) { _vidMem = new byte[_bpp * _width * _height]; @@ -187,7 +193,7 @@ Surface::Surface(uint16 width, uint16 height, uint8 bpp, const byte *vidMem) : _width(width), _height(height), _bpp(bpp), _vidMem(0) { assert((_width > 0) && (_height > 0)); - assert((_bpp == 1) || (_bpp == 2)); + assert((_bpp == 1) || (_bpp == 2) || (_bpp == 4)); _vidMem = new byte[_bpp * _width * _height]; _ownVidMem = true; @@ -504,7 +510,7 @@ void Surface::fillRect(uint16 left, uint16 top, uint16 right, uint16 bottom, uin return; } - assert(_bpp == 2); + assert((_bpp == 2) || (_bpp == 4)); // Otherwise, we have to fill by pixel @@ -815,7 +821,7 @@ bool Surface::loadIFF(Common::SeekableReadStream &stream) { return false; resize(decoder.getSurface()->w, decoder.getSurface()->h); - memcpy(_vidMem, decoder.getSurface()->pixels, decoder.getSurface()->w * decoder.getSurface()->h); + memcpy(_vidMem, decoder.getSurface()->getPixels(), decoder.getSurface()->w * decoder.getSurface()->h); return true; } diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp index a478492ccc..155989ccee 100644 --- a/engines/gob/videoplayer.cpp +++ b/engines/gob/videoplayer.cpp @@ -734,7 +734,11 @@ bool VideoPlayer::copyFrame(int slot, Surface &dest, if (!surface) return false; - Surface src(surface->w, surface->h, surface->format.bytesPerPixel, (byte *)surface->pixels); + // FIXME? This currently casts away const from the pixel data. However, it + // is only used read-only in this case (as far as I can tell). Not casting + // the const qualifier away will lead to an additional allocation and copy + // of the frame data which is undesirable. + Surface src(surface->w, surface->h, surface->format.bytesPerPixel, (byte *)const_cast<void *>(surface->getPixels())); dest.blit(src, left, top, left + width - 1, top + height - 1, x, y, transp); return true; diff --git a/engines/groovie/graphics.cpp b/engines/groovie/graphics.cpp index 73eb574dec..a4d8a4330c 100644 --- a/engines/groovie/graphics.cpp +++ b/engines/groovie/graphics.cpp @@ -82,8 +82,8 @@ void GraphicsMan::mergeFgAndBg() { uint32 i; byte *countf, *countb; - countf = (byte *)_foreground.getBasePtr(0, 0); - countb = (byte *)_background.getBasePtr(0, 0); + countf = (byte *)_foreground.getPixels(); + countb = (byte *)_background.getPixels(); for (i = 640 * 320; i; i--) { if (255 == *(countf)) { *(countf) = *(countb); @@ -94,7 +94,7 @@ void GraphicsMan::mergeFgAndBg() { } void GraphicsMan::updateScreen(Graphics::Surface *source) { - _vm->_system->copyRectToScreen(source->getBasePtr(0, 0), 640, 0, 80, 640, 320); + _vm->_system->copyRectToScreen(source->getPixels(), 640, 0, 80, 640, 320); change(); } diff --git a/engines/groovie/roq.cpp b/engines/groovie/roq.cpp index 72a61fefb2..f9a938bfd4 100644 --- a/engines/groovie/roq.cpp +++ b/engines/groovie/roq.cpp @@ -160,7 +160,7 @@ bool ROQPlayer::playFrameInternal() { if (_dirty) { // Update the screen - _syst->copyRectToScreen(_bg->getBasePtr(0, 0), _bg->pitch, 0, (_syst->getHeight() - _bg->h) / 2, _bg->w, _bg->h); + _syst->copyRectToScreen(_bg->getPixels(), _bg->pitch, 0, (_syst->getHeight() - _bg->h) / 2, _bg->w, _bg->h); _syst->updateScreen(); // Clear the dirty flag @@ -291,8 +291,8 @@ bool ROQPlayer::processBlockInfo(ROQBlockHeader &blockHeader) { } // Clear the buffers with black YUV values - byte *ptr1 = (byte *)_currBuf->getBasePtr(0, 0); - byte *ptr2 = (byte *)_prevBuf->getBasePtr(0, 0); + byte *ptr1 = (byte *)_currBuf->getPixels(); + byte *ptr2 = (byte *)_prevBuf->getPixels(); for (int i = 0; i < width * height; i++) { *ptr1++ = 0; *ptr1++ = 128; @@ -436,11 +436,11 @@ bool ROQPlayer::processBlockStill(ROQBlockHeader &blockHeader) { Graphics::JPEGDecoder *jpg = new Graphics::JPEGDecoder(); jpg->loadStream(*_file); - const byte *y = (const byte *)jpg->getComponent(1)->getBasePtr(0, 0); - const byte *u = (const byte *)jpg->getComponent(2)->getBasePtr(0, 0); - const byte *v = (const byte *)jpg->getComponent(3)->getBasePtr(0, 0); + const byte *y = (const byte *)jpg->getComponent(1)->getPixels(); + const byte *u = (const byte *)jpg->getComponent(2)->getPixels(); + const byte *v = (const byte *)jpg->getComponent(3)->getPixels(); - byte *ptr = (byte *)_currBuf->getBasePtr(0, 0); + byte *ptr = (byte *)_currBuf->getPixels(); for (int i = 0; i < _currBuf->w * _currBuf->h; i++) { *ptr++ = *y++; *ptr++ = *u++; diff --git a/engines/groovie/script.cpp b/engines/groovie/script.cpp index cbbdecc3e7..8e3bef9945 100644 --- a/engines/groovie/script.cpp +++ b/engines/groovie/script.cpp @@ -373,7 +373,7 @@ bool Script::hotspot(Common::Rect rect, uint16 address, uint8 cursor) { DebugMan.isDebugChannelEnabled(kGroovieDebugAll)) { rect.translate(0, -80); _vm->_graphicsMan->_foreground.frameRect(rect, 250); - _vm->_system->copyRectToScreen(_vm->_graphicsMan->_foreground.getBasePtr(0, 0), _vm->_graphicsMan->_foreground.pitch, 0, 80, 640, 320); + _vm->_system->copyRectToScreen(_vm->_graphicsMan->_foreground.getPixels(), _vm->_graphicsMan->_foreground.pitch, 0, 80, 640, 320); _vm->_system->updateScreen(); } @@ -983,7 +983,7 @@ void Script::o_strcmpnejmp_var() { // 0x21 void Script::o_copybgtofg() { // 0x22 debugScript(1, true, "COPY_BG_TO_FG"); - memcpy(_vm->_graphicsMan->_foreground.getBasePtr(0, 0), _vm->_graphicsMan->_background.getBasePtr(0, 0), 640 * 320); + memcpy(_vm->_graphicsMan->_foreground.getPixels(), _vm->_graphicsMan->_background.getPixels(), 640 * 320); } void Script::o_strcmpeqjmp() { // 0x23 diff --git a/engines/groovie/stuffit.cpp b/engines/groovie/stuffit.cpp index 37f12585e7..60a57a0129 100644 --- a/engines/groovie/stuffit.cpp +++ b/engines/groovie/stuffit.cpp @@ -249,7 +249,7 @@ void StuffItArchive::update14(uint16 first, uint16 last, byte *code, uint16 *fre do { while (++i < last && code[first] > code[i]) ; - + while (--j > first && code[first] < code[j]) ; diff --git a/engines/groovie/vdx.cpp b/engines/groovie/vdx.cpp index 8786e75488..59d966a22f 100644 --- a/engines/groovie/vdx.cpp +++ b/engines/groovie/vdx.cpp @@ -358,7 +358,7 @@ void VDXPlayer::getStill(Common::ReadStream *in) { byte *buf; if (_flagOne) { // Paint to the foreground - buf = (byte *)_fg->getBasePtr(0, 0); + buf = (byte *)_fg->getPixels(); if (_flag2Byte) { mask = 0xff; } else { @@ -370,7 +370,7 @@ void VDXPlayer::getStill(Common::ReadStream *in) { _flagFirstFrame = true; } else { // Paint to the background - buf = (byte *)_bg->getBasePtr(0, 0); + buf = (byte *)_bg->getPixels(); } // Read the palette @@ -486,9 +486,9 @@ void VDXPlayer::decodeBlockDelta(uint32 offset, byte *colors, uint16 imageWidth) // TODO: Verify just the else block is required //if (_flagOne) { // Paint to the foreground - //dest = (byte *)_fg->getBasePtr(0, 0) + offset; + //dest = (byte *)_fg->getPixels() + offset; //} else { - dest = (byte *)_bg->getBasePtr(0, 0) + offset; + dest = (byte *)_bg->getPixels() + offset; //} // Move the pointers to the beginning of the current block @@ -496,8 +496,8 @@ void VDXPlayer::decodeBlockDelta(uint32 offset, byte *colors, uint16 imageWidth) dest += blockOff; byte *fgBuf = 0; if (_flagSeven) { - fgBuf = (byte *)_fg->getBasePtr(0, 0) + offset + blockOff; - //byte *bgBuf = (byte *)_bg->getBasePtr(0, 0) + offset + blockOff; + fgBuf = (byte *)_fg->getPixels() + offset + blockOff; + //byte *bgBuf = (byte *)_bg->getPixels() + offset + blockOff; } for (int y = TILE_SIZE; y; y--) { @@ -550,7 +550,7 @@ void VDXPlayer::fadeIn(uint8 *targetpal) { // TODO: Is it required? If so, move to an appropiate place // Copy the foreground to the background - memcpy((byte *)_vm->_graphicsMan->_foreground.getBasePtr(0, 0), (byte *)_vm->_graphicsMan->_background.getBasePtr(0, 0), 640 * 320); + memcpy((byte *)_vm->_graphicsMan->_foreground.getPixels(), (byte *)_vm->_graphicsMan->_background.getPixels(), 640 * 320); // Start a fadein _vm->_graphicsMan->fadeIn(targetpal); diff --git a/engines/hopkins/computer.cpp b/engines/hopkins/computer.cpp index f7b923badf..c09d748b97 100644 --- a/engines/hopkins/computer.cpp +++ b/engines/hopkins/computer.cpp @@ -58,7 +58,7 @@ ComputerManager::ComputerManager(HopkinsEngine *vm) { _minBreakoutMoveSpeed = 0; _maxBreakoutMoveSpeed = 0; _lastBreakoutMoveSpeed = 0; - _breakoutHiscore = 0; + _lowestHiScore = 0; } /** @@ -579,26 +579,32 @@ void ComputerManager::displayGamesSubMenu() { */ void ComputerManager::loadHiscore() { byte *ptr = _vm->_globals->allocMemory(100); - _vm->_saveLoad->load("HISCORE.DAT", ptr); + memset(ptr, 0, 100); + + if (_vm->_saveLoad->saveExists(_vm->getTargetName() + "-highscore.dat")) + _vm->_saveLoad->load(_vm->getTargetName() + "-highscore.dat", ptr); for (int scoreIndex = 0; scoreIndex < 6; ++scoreIndex) { - for (int i = 0; i < 5; ++i) { + _score[scoreIndex]._name = " "; + _score[scoreIndex]._score = " "; + + for (int i = 0; i < 6; ++i) { char nextChar = ptr[(16 * scoreIndex) + i]; if (!nextChar) nextChar = ' '; - _score[scoreIndex]._name += nextChar; + _score[scoreIndex]._name.setChar(nextChar, i); } for (int i = 0; i < 9; ++i) { char nextChar = ptr[(scoreIndex * 16) + 6 + i]; if (!nextChar) nextChar = '0'; - _score[scoreIndex]._score += nextChar; + _score[scoreIndex]._score.setChar(nextChar, i); } } + _lowestHiScore = atol(_score[5]._score.c_str()); _vm->_globals->freeMemory(ptr); - _breakoutHiscore = atol(_score[5]._score.c_str()); } /** @@ -779,7 +785,7 @@ void ComputerManager::playBreakout() { _vm->_events->mouseOn(); _vm->_objectsMan->removeSprite(0); _vm->_objectsMan->removeSprite(1); - if (_breakoutScore > _breakoutHiscore) + if (_breakoutScore > _lowestHiScore) getScoreName(); if (displayHiscores() != 1) break; @@ -823,11 +829,11 @@ int ComputerManager::displayHiscores() { yp += 46; // Display the characters of the name - for (int i = 0; i <= 5; i++) + for (int i = 0; i < 6; i++) displayHiscoreLine(ptr, 9 * i + 69, yp, _score[scoreIndex]._name[i]); // Display the digits of the score - for (int i = 0; i <= 8; i++) + for (int i = 0; i < 9; i++) displayHiscoreLine(ptr, 9 * i + 199, yp, _score[scoreIndex]._score[i]); } @@ -864,6 +870,19 @@ void ComputerManager::getScoreName() { _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0); byte *ptr = _vm->_fileIO->loadFile("ALPHA.SPR"); _vm->_graphicsMan->fadeInBreakout(); + + // Figure out the line to put the new high score on + int scoreLine = 0; + while (scoreLine < 5 && _breakoutScore < atol(_score[scoreLine]._score.c_str())) + ++scoreLine; + + // If it's not the lasat line, move the lines down + for (int line = 5; line > scoreLine; --line) { + _score[line]._name = _score[line - 1]._name; + _score[line]._score = _score[line - 1]._score; + } + + // Get the name for the new high score for (int strPos = 0; strPos <= 4; strPos++) { displayHiscoreLine(ptr, 9 * strPos + 140, 78, 1); @@ -873,13 +892,15 @@ void ComputerManager::getScoreName() { if ((curChar > '9') && (curChar < 'A')) curChar = ' '; - _score[5]._name.setChar(curChar, strPos); + _score[scoreLine]._name.setChar(curChar, strPos); displayHiscoreLine(ptr, 9 * strPos + 140, 78, curChar); for (int idx = 0; idx < 12; ++idx) _vm->_events->refreshScreenAndEvents(); } - _score[5]._score = " "; + + // Set up the new score + _score[scoreLine]._score = " "; char score[16]; sprintf(score, "%d", _breakoutScore); @@ -888,8 +909,8 @@ void ComputerManager::getScoreName() { ++scoreLen; while (score[scoreLen]); - for (int i = scoreLen, scorePos = 8; i >= 0; i--) { - _score[5]._score.setChar(score[i], scorePos--); + for (int i = scoreLen - 1, scorePos = 8; i >= 0; i--) { + _score[scoreLine]._score.setChar(score[i], scorePos--); } _vm->_graphicsMan->fadeOutBreakout(); _vm->_globals->freeMemory(ptr); @@ -970,10 +991,10 @@ void ComputerManager::saveScore() { } byte *ptr = _vm->_globals->allocMemory(100); - memset(ptr, 0, 99); + memset(ptr, 0, 100); for (int scorePlaceIdx = 0; scorePlaceIdx <= 5; scorePlaceIdx++) { int curBufPtr = 16 * scorePlaceIdx; - for (int namePos = 0; namePos <= 4; namePos++) { + for (int namePos = 0; namePos < 6; namePos++) { char curChar = _score[scorePlace[scorePlaceIdx]]._name[namePos]; if (!curChar) curChar = ' '; @@ -991,7 +1012,7 @@ void ComputerManager::saveScore() { ptr[curBufPtr + 15] = 0; } - _vm->_saveLoad->saveFile("HISCORE.DAT", ptr, 100); + _vm->_saveLoad->saveFile(_vm->getTargetName() + "-highscore.dat", ptr, 100); _vm->_globals->freeMemory(ptr); } diff --git a/engines/hopkins/computer.h b/engines/hopkins/computer.h index cdd653f793..1771bba7d6 100644 --- a/engines/hopkins/computer.h +++ b/engines/hopkins/computer.h @@ -63,7 +63,7 @@ private: bool _ballUpFl; int _breakoutLevelNbr; int _padPositionX; - int _breakoutHiscore; + int _lowestHiScore; int _minBreakoutMoveSpeed; int _maxBreakoutMoveSpeed; int _lastBreakoutMoveSpeed; diff --git a/engines/hopkins/detection.cpp b/engines/hopkins/detection.cpp index 9d16b0ab51..c617a5aacf 100644 --- a/engines/hopkins/detection.cpp +++ b/engines/hopkins/detection.cpp @@ -56,6 +56,10 @@ bool HopkinsEngine::getIsDemo() const { return _gameDescription->desc.flags & ADGF_DEMO; } +const Common::String &HopkinsEngine::getTargetName() const { + return _targetName; +} + } // End of namespace Hopkins static const PlainGameDescriptor hopkinsGames[] = { diff --git a/engines/hopkins/dialogs.cpp b/engines/hopkins/dialogs.cpp index 6cdfbf47d1..3b8fedf0ee 100644 --- a/engines/hopkins/dialogs.cpp +++ b/engines/hopkins/dialogs.cpp @@ -505,7 +505,7 @@ void DialogsManager::inventAnim() { return; if (_vm->_objectsMan->_eraseVisibleCounter && !_vm->_objectsMan->_visibleFl) { - _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, _oldInventX, 27, 48, 38, + _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, _oldInventX, 27, 48, 38, _vm->_graphicsMan->_frontBuffer, _oldInventX, 27); _vm->_graphicsMan->addDirtyRect(_oldInventX, 27, _oldInventX + 48, 65); --_vm->_objectsMan->_eraseVisibleCounter; @@ -691,7 +691,7 @@ void DialogsManager::showSaveLoad(SaveLoadMode mode) { Graphics::Surface thumb8; _vm->_saveLoad->convertThumb16To8(header._thumbnail, &thumb8); - byte *thumb = (byte *)thumb8.pixels; + byte *thumb = (byte *)thumb8.getPixels(); int16 startPosX_ = _vm->_events->_startPos.x; switch (slotNumber) { diff --git a/engines/hopkins/globals.cpp b/engines/hopkins/globals.cpp index 28f22ed99e..a9a0a81f08 100644 --- a/engines/hopkins/globals.cpp +++ b/engines/hopkins/globals.cpp @@ -134,7 +134,7 @@ Globals::~Globals() { void Globals::setConfig() { // CHECKME: Should be in Globals() but it doesn't work // The Polish version is a translation of the English version. The filenames are the same. - // The Russian version looks like a translation of the English version, based on the filenames. + // The Russian version looks like a translation of the English version, based on the filenames. switch (_vm->getLanguage()) { case Common::EN_ANY: case Common::PL_POL: diff --git a/engines/hopkins/graphics.cpp b/engines/hopkins/graphics.cpp index ebc5cfa8da..de9f043763 100644 --- a/engines/hopkins/graphics.cpp +++ b/engines/hopkins/graphics.cpp @@ -325,7 +325,7 @@ void GraphicsManager::loadPCX640(byte *surface, const Common::String &file, byte // Copy out the dimensions and pixels of the decoded surface _largeScreenFl = s->w > SCREEN_WIDTH; - Common::copy((byte *)s->pixels, (byte *)s->pixels + (s->pitch * s->h), surface); + Common::copy((const byte *)s->getPixels(), (const byte *)s->getBasePtr(0, s->h), surface); // Copy out the palette const byte *palSrc = pcxDecoder.getPalette(); @@ -1179,7 +1179,7 @@ void GraphicsManager::displayZones() { Common::Rect r(_vm->_objectsMan->_bob[bobId]._oldX, _vm->_objectsMan->_bob[bobId]._oldY, _vm->_objectsMan->_bob[bobId]._oldX + _vm->_objectsMan->_bob[bobId]._oldWidth, _vm->_objectsMan->_bob[bobId]._oldY + _vm->_objectsMan->_bob[bobId]._oldHeight); - + displayDebugRect(screenSurface, r, 0xff0000); } } @@ -1202,15 +1202,13 @@ void GraphicsManager::displayZones() { void GraphicsManager::displayLines() { Graphics::Surface *screenSurface = g_system->lockScreen(); - uint16* pixels = (uint16*)screenSurface->pixels; - - for (int lineIndex = 0; lineIndex < _vm->_linesMan->_linesNumb; lineIndex++) { + for (int lineIndex = 0; lineIndex < _vm->_linesMan->_linesNumb; lineIndex++) { int i = 0; do { int x = _vm->_linesMan->_lineItem[lineIndex]._lineData[i] - _scrollPosX; int y = _vm->_linesMan->_lineItem[lineIndex]._lineData[i+1]; if (x >= 0 && x < SCREEN_WIDTH && y >= 0 && y < SCREEN_HEIGHT) { - pixels[ y * screenSurface->w + x ] = 0xffff; + WRITE_UINT16(screenSurface->getBasePtr(x, y), 0xffff); } i += 2; } @@ -1230,7 +1228,7 @@ void GraphicsManager::displayDebugRect(Graphics::Surface *surface, const Common: r.top = MAX(r.top, (int16)0); r.right = MIN(r.right, (int16)SCREEN_WIDTH); r.bottom = MIN(r.bottom, (int16)SCREEN_HEIGHT); - + // If there's an on-screen portion, display it if (r.isValidRect()) surface->frameRect(r, color); diff --git a/engines/hopkins/graphics.h b/engines/hopkins/graphics.h index 268db7fc2b..8767f5ec4d 100644 --- a/engines/hopkins/graphics.h +++ b/engines/hopkins/graphics.h @@ -125,7 +125,7 @@ public: public: GraphicsManager(HopkinsEngine *vm); ~GraphicsManager(); - + void clearPalette(); void clearScreen(); void clearVesaScreen(); diff --git a/engines/hopkins/hopkins.cpp b/engines/hopkins/hopkins.cpp index 407f264116..96131f2968 100644 --- a/engines/hopkins/hopkins.cpp +++ b/engines/hopkins/hopkins.cpp @@ -35,12 +35,9 @@ namespace Hopkins { -HopkinsEngine *g_vm; - HopkinsEngine::HopkinsEngine(OSystem *syst, const HopkinsGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc), _randomSource("Hopkins") { DebugMan.addDebugChannel(kDebugPath, "Path", "Pathfinding debug level"); - g_vm = this; _animMan = new AnimationManager(this); _computer = new ComputerManager(this); _dialog = new DialogsManager(this); @@ -95,7 +92,7 @@ bool HopkinsEngine::canLoadGameStateCurrently() { * Returns true if it is currently okay to save the game */ bool HopkinsEngine::canSaveGameStateCurrently() { - return !_globals->_exitId && !_globals->_cityMapEnabledFl && _events->_mouseFl + return !_globals->_exitId && !_globals->_cityMapEnabledFl && _events->_mouseFl && _globals->_curRoomNum != 0 && !isUnderwaterSubScene(); } @@ -114,8 +111,6 @@ Common::Error HopkinsEngine::saveGameState(int slot, const Common::String &desc) } Common::Error HopkinsEngine::run() { - _saveLoad->initSaves(); - _globals->setConfig(); _fileIO->initCensorship(); initializeSystem(); @@ -164,7 +159,7 @@ bool HopkinsEngine::runWin95Demo() { _globals->_speed = 3; if (_startGameSlot == -1) - _graphicsMan->fadeOutLong(); + _graphicsMan->fadeOutShort(); _globals->_eventMode = EVENTMODE_IGNORE; _globals->_characterSpriteBuf = _fileIO->loadFile("PERSO.SPR"); @@ -201,12 +196,15 @@ bool HopkinsEngine::runWin95Demo() { switch (_globals->_exitId) { case 1: + // Handles room: Apartment _linesMan->setMaxLineIdx(40); _globals->_characterMaxPosY = 435; _objectsMan->sceneControl2("IM01", "IM01", "ANIM01", "IM01", 2, true); break; case 3: + // - Displays bank attack when leaving the apartment + // - Handles room: bottom of the apartment if (!_globals->_saveData->_data[svBankAttackAnimPlayedFl]) { _soundMan->playSound(3); if (getPlatform() == Common::kPlatformOS2 || getPlatform() == Common::kPlatformBeOS) @@ -235,7 +233,7 @@ bool HopkinsEngine::runWin95Demo() { _soundMan->removeSample(2); _soundMan->removeSample(3); _soundMan->removeSample(4); - _graphicsMan->fadeOutLong(); + _graphicsMan->fadeOutShort(); _globals->_saveData->_data[svBankAttackAnimPlayedFl] = 1; } _linesMan->setMaxLineIdx(5); @@ -244,12 +242,14 @@ bool HopkinsEngine::runWin95Demo() { break; case 4: + // Handle room: City map _globals->_disableInventFl = true; _objectsMan->handleCityMap(); _globals->_disableInventFl = false; break; case 5: + // Handle room: Outside the bank _linesMan->setMaxLineIdx(5); _globals->_characterMaxPosY = 455; @@ -793,14 +793,14 @@ bool HopkinsEngine::runFull() { if (_startGameSlot == -1) { if (getPlatform() == Common::kPlatformLinux) { - _graphicsMan->loadImage("H2"); - _graphicsMan->fadeInLong(); - _events->delay(500); - _graphicsMan->fadeOutLong(); - _globals->_speed = 2; - _globals->_eventMode = EVENTMODE_IGNORE; - _graphicsMan->_fadingFl = true; - _animMan->playAnim("MP.ANM", "MP.ANM", 10, 16, 200); + _graphicsMan->loadImage("H2"); + _graphicsMan->fadeInLong(); + _events->delay(500); + _graphicsMan->fadeOutLong(); + _globals->_speed = 2; + _globals->_eventMode = EVENTMODE_IGNORE; + _graphicsMan->_fadingFl = true; + _animMan->playAnim("MP.ANM", "MP.ANM", 10, 16, 200); } else { _animMan->playAnim("MP.ANM", "MP.ANM", 10, 16, 200); _graphicsMan->fadeOutLong(); @@ -1133,12 +1133,14 @@ bool HopkinsEngine::runFull() { break; case 30: + // Shooting _linesMan->setMaxLineIdx(15); _globals->_characterMaxPosY = 440; _objectsMan->sceneControl2("IM30", "IM30", "ANIM30", "IM30", 24, false); break; case 31: + // Shooting target _objectsMan->sceneControl("IM31", "IM31", "ANIM31", "IM31", 10, true); break; @@ -1153,6 +1155,7 @@ bool HopkinsEngine::runFull() { break; case 34: + // In the airport, before the flight cut-scene _objectsMan->sceneControl("IM34", "IM34", "ANIM34", "IM34", 2, false); break; @@ -1183,6 +1186,7 @@ bool HopkinsEngine::runFull() { } case 50: + // Flight cut scene playPlaneCutscene(); _globals->_exitId = 51; break; @@ -1904,10 +1908,7 @@ void HopkinsEngine::bombExplosion() { } void HopkinsEngine::restoreSystem() { - // If the game isn't alerady trying to quit, flag that quitting is needed - if (!shouldQuit()) - quitGame(); - + quitGame(); _events->refreshEvents(); } @@ -2232,6 +2233,8 @@ void HopkinsEngine::playPlaneCutscene() { if (!_events->_escKeyFl) { _graphicsMan->_fadingFl = true; _animMan->playAnim("PARA00A.ANM", "PARA00.ANM", 9, 9, 9); + } else { + _graphicsMan->fadeOutShort(); } _events->_escKeyFl = false; diff --git a/engines/hopkins/hopkins.h b/engines/hopkins/hopkins.h index 777fd1c335..d8c30e5004 100644 --- a/engines/hopkins/hopkins.h +++ b/engines/hopkins/hopkins.h @@ -164,6 +164,7 @@ public: Common::Platform getPlatform() const; uint16 getVersion() const; bool getIsDemo() const; + const Common::String &getTargetName() const; int getRandomNumber(int maxNumber); Common::String generateSaveName(int slotNumber); @@ -183,9 +184,6 @@ public: virtual void syncSoundSettings(); }; -// Global reference to the HopkinsEngine object -extern HopkinsEngine *g_vm; - } // End of namespace Hopkins #endif /* HOPKINS_HOPKINS_H */ diff --git a/engines/hopkins/saveload.cpp b/engines/hopkins/saveload.cpp index 45b4885c90..b0dea7e6d1 100644 --- a/engines/hopkins/saveload.cpp +++ b/engines/hopkins/saveload.cpp @@ -43,39 +43,38 @@ SaveLoadManager::SaveLoadManager(HopkinsEngine *vm) { } bool SaveLoadManager::save(const Common::String &file, const void *buf, size_t n) { - Common::OutSaveFile *f = g_system->getSavefileManager()->openForSaving(file); + Common::OutSaveFile *savefile = g_system->getSavefileManager()->openForSaving(file); - if (f) { - size_t bytesWritten = f->write(buf, n); - f->finalize(); - delete f; + if (savefile) { + size_t bytesWritten = savefile->write(buf, n); + savefile->finalize(); + delete savefile; return bytesWritten == n; } else return false; } +bool SaveLoadManager::saveExists(const Common::String &file) { + Common::InSaveFile *savefile = g_system->getSavefileManager()->openForLoading(file); + bool result = savefile != NULL; + delete savefile; + return result; +} + // Save File bool SaveLoadManager::saveFile(const Common::String &file, const void *buf, size_t n) { return save(file, buf, n); } -void SaveLoadManager::initSaves() { - Common::String dataFilename = "HISCORE.DAT"; - byte data[100]; - Common::fill(&data[0], &data[100], 0); - - saveFile(dataFilename, data, 100); -} - void SaveLoadManager::load(const Common::String &file, byte *buf) { - Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(file); - if (f == NULL) - error("Error openinig file - %s", file.c_str()); + Common::InSaveFile *savefile = g_system->getSavefileManager()->openForLoading(file); + if (savefile == NULL) + error("Error opening file - %s", file.c_str()); - int32 filesize = f->size(); - f->read(buf, filesize); - delete f; + int32 filesize = savefile->size(); + savefile->read(buf, filesize); + delete savefile; } bool SaveLoadManager::readSavegameHeader(Common::InSaveFile *in, hopkinsSavegameHeader &header) { @@ -215,13 +214,13 @@ Common::Error SaveLoadManager::loadGame(int slot) { bool SaveLoadManager::readSavegameHeader(int slot, hopkinsSavegameHeader &header) { // Try and open the save file for reading - Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading( - g_vm->generateSaveName(slot)); - if (!saveFile) + Common::InSaveFile *savefile = g_system->getSavefileManager()->openForLoading( + _vm->generateSaveName(slot)); + if (!savefile) return false; - bool result = readSavegameHeader(saveFile, header); - delete saveFile; + bool result = readSavegameHeader(savefile, header); + delete savefile; return result; } @@ -234,14 +233,14 @@ void SaveLoadManager::createThumbnail(Graphics::Surface *s) { Graphics::Surface thumb8; thumb8.create(w, h, Graphics::PixelFormat::createFormatCLUT8()); - _vm->_graphicsMan->reduceScreenPart(_vm->_graphicsMan->_frontBuffer, (byte *)thumb8.pixels, + _vm->_graphicsMan->reduceScreenPart(_vm->_graphicsMan->_frontBuffer, (byte *)thumb8.getPixels(), _vm->_events->_startPos.x, 20, SCREEN_WIDTH, SCREEN_HEIGHT - 40, 80); // Convert the 8-bit pixel to 16 bit surface s->create(w, h, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); - const byte *srcP = (const byte *)thumb8.pixels; - uint16 *destP = (uint16 *)s->pixels; + const byte *srcP = (const byte *)thumb8.getPixels(); + uint16 *destP = (uint16 *)s->getPixels(); for (int yp = 0; yp < h; ++yp) { // Copy over the line, using the source pixels as lookups into the pixels palette @@ -259,6 +258,10 @@ void SaveLoadManager::createThumbnail(Graphics::Surface *s) { } void SaveLoadManager::syncSavegameData(Common::Serializer &s, int version) { + // The brief version 3 had the highscores embedded. They're in a separate file now, so skip + if (version == 3 && s.isLoading()) + s.skip(100); + s.syncBytes(&_vm->_globals->_saveData->_data[0], 2050); syncCharacterLocation(s, _vm->_globals->_saveData->_cloneHopkins); syncCharacterLocation(s, _vm->_globals->_saveData->_realHopkins); @@ -296,8 +299,8 @@ void SaveLoadManager::convertThumb16To8(Graphics::Surface *thumb16, Graphics::Su pixelFormat16.colorToRGB(p, paletteR[palIndex], paletteG[palIndex], paletteB[palIndex]); } - const uint16 *srcP = (const uint16 *)thumb16->pixels; - byte *destP = (byte *)thumb8->pixels; + const uint16 *srcP = (const uint16 *)thumb16->getPixels(); + byte *destP = (byte *)thumb8->getPixels(); for (int yp = 0; yp < thumb16->h; ++yp) { const uint16 *lineSrcP = srcP; diff --git a/engines/hopkins/saveload.h b/engines/hopkins/saveload.h index 221a445fd2..5b77c11f12 100644 --- a/engines/hopkins/saveload.h +++ b/engines/hopkins/saveload.h @@ -35,7 +35,7 @@ namespace Hopkins { class HopkinsEngine; -#define HOPKINS_SAVEGAME_VERSION 2 +#define HOPKINS_SAVEGAME_VERSION 4 struct hopkinsSavegameHeader { uint8 _version; @@ -56,14 +56,14 @@ private: public: SaveLoadManager(HopkinsEngine *vm); - void initSaves(); + bool saveExists(const Common::String &file); bool save(const Common::String &file, const void *buf, size_t n); bool saveFile(const Common::String &file, const void *buf, size_t n); void load(const Common::String &file, byte *buf); static bool readSavegameHeader(Common::InSaveFile *in, hopkinsSavegameHeader &header); void writeSavegameHeader(Common::OutSaveFile *out, hopkinsSavegameHeader &header); - static bool readSavegameHeader(int slot, hopkinsSavegameHeader &header); + bool readSavegameHeader(int slot, hopkinsSavegameHeader &header); Common::Error saveGame(int slot, const Common::String &saveName); Common::Error loadGame(int slot); diff --git a/engines/hopkins/script.cpp b/engines/hopkins/script.cpp index c39273203d..7e150624b8 100644 --- a/engines/hopkins/script.cpp +++ b/engines/hopkins/script.cpp @@ -536,6 +536,7 @@ int ScriptManager::handleOpcode(const byte *dataP) { break; case 12: + // Bank - negotiations between Hopkins and one of the killers _vm->_fontMan->hideText(9); _vm->_events->refreshScreenAndEvents(); _vm->_events->refreshScreenAndEvents(); @@ -543,6 +544,7 @@ int ScriptManager::handleOpcode(const byte *dataP) { break; case 13: + // Bank - after negotiations, Hopkins enters the bank _vm->_events->_mouseButton = _vm->_events->_curMouseButton; _vm->_globals->_disableInventFl = true; _vm->_graphicsMan->fadeOutLong(); @@ -553,9 +555,7 @@ int ScriptManager::handleOpcode(const byte *dataP) { _vm->_graphicsMan->endDisplayBob(); _vm->_objectsMan->clearScreen(); - if ((_vm->getPlatform() == Common::kPlatformWindows) && _vm->getIsDemo()) { - _vm->_graphicsMan->fadeOutLong(); - } else { + if ((_vm->getPlatform() != Common::kPlatformWindows) || !_vm->getIsDemo()) { _vm->_soundMan->playSoundFile("SOUND17.WAV"); _vm->_graphicsMan->_fadingFl = true; _vm->_animMan->playSequence2("HELICO.SEQ", 10, 4, 10); @@ -615,10 +615,6 @@ int ScriptManager::handleOpcode(const byte *dataP) { _vm->_graphicsMan->_fadingFl = true; _vm->_animMan->playSequence2("ASSOM.SEQ", 10, 4, 500); _vm->_soundMan->_specialSoundNum = 0; - - if ((_vm->getPlatform() == Common::kPlatformWindows) && _vm->getIsDemo()) - _vm->_graphicsMan->fadeOutLong(); - _vm->_globals->_disableInventFl = false; _vm->_objectsMan->_helicopterFl = true; break; @@ -1221,6 +1217,7 @@ int ScriptManager::handleOpcode(const byte *dataP) { break; case 88: + // Shooting target - Shooting at target if (_vm->_globals->_saveData->_data[svField183] == 1) { _vm->_objectsMan->setBobAnimDataIdx(1, 0); _vm->_objectsMan->setBobAnimDataIdx(2, 0); @@ -1298,6 +1295,7 @@ int ScriptManager::handleOpcode(const byte *dataP) { break; case 90: + // Shooting target - Using the level _vm->_soundMan->playSoundFile("SOUND52.WAV"); if (!_vm->_globals->_saveData->_data[svField186]) { _vm->_animMan->playSequence("CIB5A.SEQ", 1, 12, 1, false, false); @@ -1984,6 +1982,7 @@ int ScriptManager::handleOpcode(const byte *dataP) { break; case 216: + // Discuss with pilot just before Flight cutscene _vm->_globals->_introSpeechOffFl = true; _vm->_talkMan->startAnimatedCharacterDialogue("aviat1.pe2"); _vm->_globals->_introSpeechOffFl = false; diff --git a/engines/hugo/dialogs.cpp b/engines/hugo/dialogs.cpp index 0f07d52aee..5dcee3ae94 100644 --- a/engines/hugo/dialogs.cpp +++ b/engines/hugo/dialogs.cpp @@ -140,8 +140,8 @@ void TopMenu::loadBmpArr(Common::SeekableReadStream &in) { _arrayBmp[i * 2] = bitmapSrc->convertTo(g_system->getOverlayFormat()); _arrayBmp[i * 2 + 1] = new Graphics::Surface(); _arrayBmp[i * 2 + 1]->create(_arrayBmp[i * 2]->w * 2, _arrayBmp[i * 2]->h * 2, g_system->getOverlayFormat()); - byte *src = (byte *)_arrayBmp[i * 2]->pixels; - byte *dst = (byte *)_arrayBmp[i * 2 + 1]->pixels; + byte *src = (byte *)_arrayBmp[i * 2]->getPixels(); + byte *dst = (byte *)_arrayBmp[i * 2 + 1]->getPixels(); for (int j = 0; j < _arrayBmp[i * 2]->h; j++) { src = (byte *)_arrayBmp[i * 2]->getBasePtr(0, j); diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp index bcf06055f8..b140cfdba2 100644 --- a/engines/hugo/hugo.cpp +++ b/engines/hugo/hugo.cpp @@ -66,7 +66,7 @@ HugoEngine::HugoEngine(OSystem *syst, const HugoGameDescription *gd) : Engine(sy _console = new HugoConsole(this); _rnd = 0; - + _screen = NULL; _mouse = NULL; _inventory = NULL; diff --git a/engines/hugo/intro.cpp b/engines/hugo/intro.cpp index 505e356049..6f314c8774 100644 --- a/engines/hugo/intro.cpp +++ b/engines/hugo/intro.cpp @@ -89,11 +89,7 @@ void intro_v1d::preNewGame() { void intro_v1d::introInit() { _introState = 0; _introTicks = 0; - _surf.w = 320; - _surf.h = 200; - _surf.pixels = _vm->_screen->getFrontBuffer(); - _surf.pitch = 320; - _surf.format = Graphics::PixelFormat::createFormatCLUT8(); + _surf.init(320, 200, 320, _vm->_screen->getFrontBuffer(), Graphics::PixelFormat::createFormatCLUT8()); _vm->_screen->displayList(kDisplayInit); } @@ -243,11 +239,7 @@ void intro_v2d::preNewGame() { void intro_v2d::introInit() { _vm->_screen->displayList(kDisplayInit); _vm->_file->readBackground(_vm->_numScreens - 1); // display splash screen - _surf.w = 320; - _surf.h = 200; - _surf.pixels = _vm->_screen->getFrontBuffer(); - _surf.pitch = 320; - _surf.format = Graphics::PixelFormat::createFormatCLUT8(); + _surf.init(320, 200, 320, _vm->_screen->getFrontBuffer(), Graphics::PixelFormat::createFormatCLUT8()); char buffer[128]; @@ -289,11 +281,7 @@ void intro_v3d::preNewGame() { void intro_v3d::introInit() { _vm->_screen->displayList(kDisplayInit); _vm->_file->readBackground(_vm->_numScreens - 1); // display splash screen - _surf.w = 320; - _surf.h = 200; - _surf.pixels = _vm->_screen->getFrontBuffer(); - _surf.pitch = 320; - _surf.format = Graphics::PixelFormat::createFormatCLUT8(); + _surf.init(320, 200, 320, _vm->_screen->getFrontBuffer(), Graphics::PixelFormat::createFormatCLUT8()); char buffer[128]; if (_vm->_boot._registered) diff --git a/engines/kyra/gui_mr.cpp b/engines/kyra/gui_mr.cpp index bcbfe27b69..ee0303c8c3 100644 --- a/engines/kyra/gui_mr.cpp +++ b/engines/kyra/gui_mr.cpp @@ -737,7 +737,7 @@ void KyraEngine_MR::loadAlbumPageWSA() { if (_album.curPage != 14) { filename = Common::String::format("PAGE%x.WSA", _album.curPage+1); _album.rightPage.wsa->open(filename.c_str(), 1, 0); - _album.rightPage.maxFrame = _album.leftPage.wsa->frames()-1; + _album.rightPage.maxFrame = _album.rightPage.wsa->frames()-1; } } diff --git a/engines/kyra/kyra_rpg.cpp b/engines/kyra/kyra_rpg.cpp index f8eb7d00cd..4f7adcc6e5 100644 --- a/engines/kyra/kyra_rpg.cpp +++ b/engines/kyra/kyra_rpg.cpp @@ -213,7 +213,7 @@ void KyraRpgEngine::drawDialogueButtons() { screen()->printText(_dialogueButtonString[i], (x + 37 - (screen()->getTextWidth(_dialogueButtonString[i])) / 2) & ~3, ((_dialogueButtonYoffs + _dialogueButtonPosY[i]) + 2) & ~7, _dialogueHighlightedButton == i ? 0xC1 : 0xE1, 0); } else { - int sjisYOffset = (_flags.lang == Common::JA_JPN && _dialogueButtonString[i][0] < 0) ? 2 : 0; + int sjisYOffset = (_flags.lang == Common::JA_JPN && (_dialogueButtonString[i][0] & 0x80)) ? 2 : 0; gui_drawBox(x, (_dialogueButtonYoffs + _dialogueButtonPosY[i]), _dialogueButtonWidth, guiSettings()->buttons.height, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill); screen()->printText(_dialogueButtonString[i], x + (_dialogueButtonWidth >> 1) - (screen()->getTextWidth(_dialogueButtonString[i])) / 2, (_dialogueButtonYoffs + _dialogueButtonPosY[i]) + 2 - sjisYOffset, _dialogueHighlightedButton == i ? _dialogueButtonLabelColor1 : _dialogueButtonLabelColor2, 0); diff --git a/engines/kyra/scene_mr.cpp b/engines/kyra/scene_mr.cpp index c9486d9c45..d2b4907b6a 100644 --- a/engines/kyra/scene_mr.cpp +++ b/engines/kyra/scene_mr.cpp @@ -577,6 +577,7 @@ void KyraEngine_MR::initSceneScreen(int unk1) { } updateCharPal(0); + _screen->updateScreen(); if (!_menuDirectlyToLoad) { _emc->start(&_sceneScriptState, 3); diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index 419b630714..8c97e46a8f 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -718,6 +718,13 @@ void Screen::fadePalette(const Palette &pal, int delay, const UpdateFunctor *upF _vm->delay((delayAcc >> 8) * 1000 / 60); delayAcc &= 0xFF; } + + // In case we should quit we setup the final palette here. This avoids + // ugly palette glitches when quitting while fading. This can for example + // be noticed when quitting while viewing the family album in Kyra3. + if (_vm->shouldQuit()) { + setScreenPalette(pal); + } } void Screen::getFadeParams(const Palette &pal, int delay, int &delayInc, int &diff) { @@ -1256,7 +1263,7 @@ int Screen::getTextWidth(const char *str) { while (1) { if (_sjisMixedFontMode) - setFont(*str < 0 ? FID_SJIS_FNT : curFont); + setFont((*str & 0x80) ? FID_SJIS_FNT : curFont); uint c = fetchChar(str); @@ -1296,7 +1303,7 @@ void Screen::printText(const char *str, int x, int y, uint8 color1, uint8 color2 while (1) { if (_sjisMixedFontMode) - setFont(*str < 0 ? FID_SJIS_FNT : curFont); + setFont((*str & 0x80) ? FID_SJIS_FNT : curFont); uint8 charHeightFnt = getFontHeight(); diff --git a/engines/lastexpress/data/animation.cpp b/engines/lastexpress/data/animation.cpp index 7618259e69..832bcc2e26 100644 --- a/engines/lastexpress/data/animation.cpp +++ b/engines/lastexpress/data/animation.cpp @@ -270,7 +270,7 @@ void Animation::play() { draw(s); // XXX: Update the screen - g_system->copyRectToScreen(s->pixels, s->pitch, 0, 0, s->w, s->h); + g_system->copyRectToScreen(s->getPixels(), s->pitch, 0, 0, s->w, s->h); // Free the temporary surface s->free(); diff --git a/engines/lastexpress/data/sequence.cpp b/engines/lastexpress/data/sequence.cpp index a5bcba84cd..c7073b560c 100644 --- a/engines/lastexpress/data/sequence.cpp +++ b/engines/lastexpress/data/sequence.cpp @@ -128,8 +128,8 @@ AnimFrame::~AnimFrame() { } Common::Rect AnimFrame::draw(Graphics::Surface *s) { - byte *inp = (byte *)_image.pixels; - uint16 *outp = (uint16 *)s->pixels; + byte *inp = (byte *)_image.getPixels(); + uint16 *outp = (uint16 *)s->getPixels(); for (int i = 0; i < 640 * 480; i++, inp++, outp++) { if (*inp) *outp = _palette[*inp]; @@ -155,7 +155,7 @@ void AnimFrame::decomp4(Common::SeekableReadStream *in, const FrameInfo &f) { } void AnimFrame::decomp34(Common::SeekableReadStream *in, const FrameInfo &f, byte mask, byte shift) { - byte *p = (byte *)_image.getBasePtr(0, 0); + byte *p = (byte *)_image.getPixels(); uint32 skip = f.initialSkip / 2; uint32 size = f.decompressedEndOffset / 2; @@ -200,7 +200,7 @@ void AnimFrame::decomp34(Common::SeekableReadStream *in, const FrameInfo &f, byt } void AnimFrame::decomp5(Common::SeekableReadStream *in, const FrameInfo &f) { - byte *p = (byte *)_image.getBasePtr(0, 0); + byte *p = (byte *)_image.getPixels(); uint32 skip = f.initialSkip / 2; uint32 size = f.decompressedEndOffset / 2; @@ -235,7 +235,7 @@ void AnimFrame::decomp5(Common::SeekableReadStream *in, const FrameInfo &f) { } void AnimFrame::decomp7(Common::SeekableReadStream *in, const FrameInfo &f) { - byte *p = (byte *)_image.getBasePtr(0, 0); + byte *p = (byte *)_image.getPixels(); uint32 skip = f.initialSkip / 2; uint32 size = f.decompressedEndOffset / 2; @@ -288,7 +288,7 @@ void AnimFrame::decomp7(Common::SeekableReadStream *in, const FrameInfo &f) { } void AnimFrame::decompFF(Common::SeekableReadStream *in, const FrameInfo &f) { - byte *p = (byte *)_image.getBasePtr(0, 0); + byte *p = (byte *)_image.getPixels(); uint32 skip = f.initialSkip / 2; uint32 size = f.decompressedEndOffset / 2; diff --git a/engines/lastexpress/graphics.cpp b/engines/lastexpress/graphics.cpp index 753c3a39e4..9ced38a2e1 100644 --- a/engines/lastexpress/graphics.cpp +++ b/engines/lastexpress/graphics.cpp @@ -131,11 +131,11 @@ void GraphicsManager::mergePlanes() { // Clear screen surface _screen.fillRect(Common::Rect(640, 480), 0); - uint16 *screen = (uint16 *)_screen.pixels; - uint16 *inventory = (uint16 *)_inventory.pixels; - uint16 *overlay = (uint16 *)_overlay.pixels; - uint16 *backgroundC = (uint16 *)_backgroundC.pixels; - uint16 *backgroundA = (uint16 *)_backgroundA.pixels; + uint16 *screen = (uint16 *)_screen.getPixels(); + uint16 *inventory = (uint16 *)_inventory.getPixels(); + uint16 *overlay = (uint16 *)_overlay.getPixels(); + uint16 *backgroundC = (uint16 *)_backgroundC.getPixels(); + uint16 *backgroundA = (uint16 *)_backgroundA.getPixels(); for (int i = 0; i < 640 * 480; i++) { @@ -160,7 +160,7 @@ void GraphicsManager::mergePlanes() { void GraphicsManager::updateScreen() { g_system->fillScreen(0); - g_system->copyRectToScreen(_screen.getBasePtr(0, 0), 640 * 2, 0, 0, 640, 480); + g_system->copyRectToScreen(_screen.getPixels(), 640 * 2, 0, 0, 640, 480); } } // End of namespace LastExpress diff --git a/engines/lure/hotspots.cpp b/engines/lure/hotspots.cpp index 7fab4521f7..d0b439677d 100644 --- a/engines/lure/hotspots.cpp +++ b/engines/lure/hotspots.cpp @@ -260,8 +260,10 @@ void Hotspot::setAnimation(HotspotAnimData *newRecord) { _anim = NULL; _numFrames = 0; _frameNumber = 0; - if (!newRecord) return; - if (!disk.exists(newRecord->animId)) return; + if (!newRecord) + return; + if (!disk.exists(newRecord->animId)) + return; // Scan for any size overrides - some animations get their size set after decoding, but // we want it in advance so we can decode the animation straight to a graphic surface @@ -516,7 +518,8 @@ void Hotspot::endAction() { } void Hotspot::setDirection(Direction dir) { - if ((_numFrames == 0) || (_direction == dir)) return; + if ((_numFrames == 0) || (_direction == dir)) + return; uint8 newFrameNumber = 0; switch (dir) { @@ -634,7 +637,8 @@ void Hotspot::setOccupied(bool occupiedFlag) { if (xp < 0) { xp = -xp; widthVal -= xp; - if (widthVal <= 0) return; + if (widthVal <= 0) + return; xp = 0; } @@ -642,7 +646,8 @@ void Hotspot::setOccupied(bool occupiedFlag) { int x2 = xp + widthVal - ROOM_PATHS_WIDTH - 1; if (x2 >= 0) { widthVal -= (x2 + 1); - if (widthVal <= 0) return; + if (widthVal <= 0) + return; } RoomPathsData &paths = Resources::getReference().getRoom(_roomNumber)->paths; @@ -656,14 +661,16 @@ void Hotspot::setOccupied(bool occupiedFlag) { // walks the character a single step in a sequence defined by the walking list bool Hotspot::walkingStep() { - if (_pathFinder.isEmpty()) return true; + if (_pathFinder.isEmpty()) + return true; // Check to see if the end of the next straight walking slice if (_pathFinder.stepCtr() >= _pathFinder.top().numSteps()) { // Move to next slice in walking sequence _pathFinder.stepCtr() = 0; _pathFinder.pop(); - if (_pathFinder.isEmpty()) return true; + if (_pathFinder.isEmpty()) + return true; } if (_pathFinder.stepCtr() == 0) @@ -782,13 +789,15 @@ void Hotspot::showMessage(uint16 messageId, uint16 destCharacterId) { uint16 *v = (uint16 *) (msgData + READ_LE_UINT16(msgData + idx + sizeof(uint16))); while ((idVal = READ_LE_UINT16(v)) != 0xffff) { ++v; - if (READ_LE_UINT16(v) == messageId) break; + if (READ_LE_UINT16(v) == messageId) + break; ++v; } // default response if a specific response not found - if (idVal == 0xffff) idVal = 0x8c4; + if (idVal == 0xffff) + idVal = 0x8c4; debugC(ERROR_DETAILED, kLureDebugStrings, "Hotspot::showMessage idVal=%xh", idVal); if (idVal == 0x76) { @@ -826,7 +835,8 @@ void Hotspot::handleTalkDialog() { Room &room = Room::getReference(); // Return if no talk dialog is necessary - if (_data->talkCountdown == 0) return; + if (_data->talkCountdown == 0) + return; debugC(ERROR_DETAILED, kLureDebugAnimations, "Talk countdown = %d", _data->talkCountdown); if (_data->talkCountdown == CONVERSE_COUNTDOWN_SIZE) { @@ -933,7 +943,8 @@ static const uint16 validRoomExitHotspots[] = {0x2711, 0x2712, 0x2714, 0x2715, 0 bool Hotspot::isRoomExit(uint16 id) { for (const uint16 *p = &validRoomExitHotspots[0]; *p != 0; ++p) - if (*p == id) return true; + if (*p == id) + return true; return false; } @@ -1043,7 +1054,7 @@ BarPlaceResult Hotspot::getBarPlace() { index = -1; while (++index < NUM_SERVE_CUSTOMERS) { if (barEntry.customers[index].hotspotId == 0) - break; + break; } if (index == NUM_SERVE_CUSTOMERS) @@ -1391,7 +1402,8 @@ void Hotspot::doGet(HotspotData *hotspot) { Resources &res = Resources::getReference(); HotspotPrecheckResult result = actionPrecheck(hotspot); - if (result == PC_WAIT) return; + if (result == PC_WAIT) + return; else if (result != PC_EXECUTE) { endAction(); return; @@ -1409,7 +1421,8 @@ void Hotspot::doGet(HotspotData *hotspot) { if (sequenceOffset != 0) { uint16 execResult = Script::execute(sequenceOffset); - if (execResult == 1) return; + if (execResult == 1) + return; else if (execResult != 0) { showMessage(execResult); return; @@ -1432,7 +1445,8 @@ void Hotspot::doOperate(HotspotData *hotspot) { Action action = currentActions().top().supportData().action(); HotspotPrecheckResult result = actionPrecheck(hotspot); - if (result == PC_WAIT) return; + if (result == PC_WAIT) + return; else if (result != PC_EXECUTE) { endAction(); return; @@ -1467,7 +1481,8 @@ void Hotspot::doOpen(HotspotData *hotspot) { } HotspotPrecheckResult result = actionPrecheck(hotspot); - if (result == PC_WAIT) return; + if (result == PC_WAIT) + return; else if (result != PC_EXECUTE) { endAction(); return; @@ -1487,7 +1502,8 @@ void Hotspot::doOpen(HotspotData *hotspot) { if (sequenceOffset != 0) { sequenceOffset = Script::execute(sequenceOffset); - if (sequenceOffset == 1) return; + if (sequenceOffset == 1) + return; if (sequenceOffset != 0) { if (_exitCtr != 0) _exitCtr = 4; @@ -1522,7 +1538,8 @@ void Hotspot::doClose(HotspotData *hotspot) { } HotspotPrecheckResult result = actionPrecheck(hotspot); - if (result == PC_WAIT) return; + if (result == PC_WAIT) + return; else if (result != PC_EXECUTE) { endAction(); return; @@ -1575,7 +1592,8 @@ void Hotspot::doUse(HotspotData *hotspot) { } HotspotPrecheckResult result = actionPrecheck(hotspot); - if (result == PC_WAIT) return; + if (result == PC_WAIT) + return; else if (result != PC_EXECUTE) { endAction(); return; @@ -1616,7 +1634,8 @@ void Hotspot::doGive(HotspotData *hotspot) { } HotspotPrecheckResult result = actionPrecheck(hotspot); - if (result == PC_WAIT) return; + if (result == PC_WAIT) + return; else if (result != PC_EXECUTE) { endAction(); return; @@ -1662,7 +1681,8 @@ void Hotspot::doTalkTo(HotspotData *hotspot) { (hotspot->hotspotId != BLACKSMITH_ID))) { HotspotPrecheckResult result = actionPrecheck(hotspot); - if (result == PC_WAIT) return; + if (result == PC_WAIT) + return; else if (result != PC_EXECUTE) { endAction(); return; @@ -1706,7 +1726,8 @@ void Hotspot::doTell(HotspotData *hotspot) { assert(character); HotspotPrecheckResult hsResult = actionPrecheck(hotspot); - if (hsResult == PC_WAIT) return; + if (hsResult == PC_WAIT) + return; else if (hsResult != PC_EXECUTE) { endAction(); return; @@ -1800,7 +1821,8 @@ void Hotspot::doAsk(HotspotData *hotspot) { _data->useHotspotId = usedId; HotspotPrecheckResult result = actionPrecheck(hotspot); - if (result == PC_WAIT) return; + if (result == PC_WAIT) + return; else if (result != PC_EXECUTE) { endAction(); return; @@ -1886,14 +1908,17 @@ void Hotspot::doStatus(HotspotData *hotspot) { HotspotData const &rec = **i; if (rec.roomNumber == PLAYER_ID) { - if (numItems++ == 0) strcat(buffer, ": "); - else strcat(buffer, ", "); + if (numItems++ == 0) + strcat(buffer, ": "); + else + strcat(buffer, ", "); strings.getString(rec.nameId, buffer + strlen(buffer)); } } // If there were no items, add in the word 'nothing' - if (numItems == 0) strcat(buffer, stringList.getString(S_INV_NOTHING)); + if (numItems == 0) + strcat(buffer, stringList.getString(S_INV_NOTHING)); // If the player has money, add it in uint16 numGroats = res.fieldList().numGroats(); @@ -1943,7 +1968,8 @@ void Hotspot::doBribe(HotspotData *hotspot) { fields.setField(USE_HOTSPOT_ID, hotspot->hotspotId); HotspotPrecheckResult result = actionPrecheck(hotspot); - if (result == PC_WAIT) return; + if (result == PC_WAIT) + return; else if (result != PC_EXECUTE) { endAction(); return; @@ -1968,7 +1994,8 @@ void Hotspot::doBribe(HotspotData *hotspot) { sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, BRIBE); if (sequenceOffset != 0) { sequenceOffset = Script::execute(sequenceOffset); - if (sequenceOffset != 0) return; + if (sequenceOffset != 0) + return; } uint16 talkIndex = res.fieldList().getField(TALK_INDEX); @@ -2004,7 +2031,8 @@ void Hotspot::doLockUnlock(HotspotData *hotspot) { fields.setField(USE_HOTSPOT_ID, hotspot->hotspotId); HotspotPrecheckResult result = actionPrecheck(hotspot); - if (result == PC_WAIT) return; + if (result == PC_WAIT) + return; else if (result != PC_EXECUTE) { endAction(); return; @@ -2156,7 +2184,8 @@ void Hotspot::npcTalkNpcToNpc(HotspotData *hotspot) { fields.setField(USE_HOTSPOT_ID, hotspot->hotspotId); HotspotPrecheckResult result = actionPrecheck(hotspot); - if (result == PC_WAIT) return; + if (result == PC_WAIT) + return; else if (result != PC_EXECUTE) { endAction(); return; @@ -2594,7 +2623,8 @@ void HotspotTickHandlers::standardCharacterAnimHandler(Hotspot &h) { if (h.characterMode() == CHARMODE_PLAYER_WAIT) { h.updateMovement(); - if (bumpedPlayer) return; + if (bumpedPlayer) + return; } else { // All other character modes if (h.delayCtr() > 0) { @@ -2691,7 +2721,8 @@ void HotspotTickHandlers::standardCharacterAnimHandler(Hotspot &h) { res.pausedList().scan(h); pfResult = pathFinder.process(); - if (pfResult == PF_UNFINISHED) break; + if (pfResult == PF_UNFINISHED) + break; debugC(ERROR_DETAILED, kLureDebugAnimations, "pathFinder done: result = %d", pfResult); @@ -2863,7 +2894,8 @@ void HotspotTickHandlers::roomExitAnimHandler(Hotspot &h) { Room &room = Room::getReference(); RoomExitJoinData *rec = res.getExitJoin(h.hotspotId()); - if (!rec) return; + if (!rec) + return; RoomExitJoinStruct &rs = (rec->hotspots[0].hotspotId == h.hotspotId()) ? rec->hotspots[0] : rec->hotspots[1]; @@ -3036,7 +3068,8 @@ void HotspotTickHandlers::playerAnimHandler(Hotspot &h) { res.pausedList().scan(h); pfResult = pathFinder.process(); - if (pfResult == PF_UNFINISHED) break; + if (pfResult == PF_UNFINISHED) + break; // Pathfinding is now complete buffer = pathFinder.getDebugInfo(); @@ -3474,7 +3507,8 @@ void HotspotTickHandlers::talkAnimHandler(Hotspot &h) { showSelections |= (entry->descId & 0x3fff) != TALK_MAGIC_ID; } - if ((entry->preSequenceId & 0x8000) != 0) break; + if ((entry->preSequenceId & 0x8000) != 0) + break; } if (showSelections && (numLines > 1)) { @@ -3584,7 +3618,8 @@ void HotspotTickHandlers::talkAnimHandler(Hotspot &h) { debugC(ERROR_DETAILED, kLureDebugAnimations, "Character response pre id = %xh", _talkResponse->preSequenceId); - if (!_talkResponse->preSequenceId) break; + if (!_talkResponse->preSequenceId) + break; responseNumber = Script::execute(_talkResponse->preSequenceId); debugC(ERROR_DETAILED, kLureDebugAnimations, "Character response new response = %d", responseNumber); @@ -3680,9 +3715,12 @@ void HotspotTickHandlers::grubAnimHandler(Hotspot &h) { character = ratpouch; } - if (character->x() < 72) frameNumber = 0; - else if (character->x() < 172) frameNumber = 1; - else frameNumber = 2; + if (character->x() < 72) + frameNumber = 0; + else if (character->x() < 172) + frameNumber = 1; + else + frameNumber = 2; h.setActionCtr(frameNumber); h.setFrameNumber(frameNumber); @@ -3782,7 +3820,8 @@ void HotspotTickHandlers::barmanAnimHandler(Hotspot &h) { // Moving right h.setPosition(h.x() + 2, h.y()); h.setActionCtr(h.actionCtr() + 1); - if (h.actionCtr() >= 6) h.setActionCtr(0); + if (h.actionCtr() >= 6) + h.setActionCtr(0); } } else { // Stop the barman moving @@ -4006,6 +4045,7 @@ void HotspotTickHandlers::rackSerfAnimHandler(Hotspot &h) { h.setActionCtr(4); h.setLayer(2); + // Deliberate fall-through case 4: if (HotspotScript::execute(&h)) { h.setLayer(255); @@ -4230,7 +4270,8 @@ PathFinderResult PathFinder::process() { while (1) { // Loop through to process cells in the given area - if (!returnFlag) _yCtr = 0; + if (!returnFlag) + _yCtr = 0; while (returnFlag || (_yCtr < ROOM_PATHS_HEIGHT)) { if (!returnFlag) _xCtr = 0; @@ -4238,7 +4279,8 @@ PathFinderResult PathFinder::process() { if (!returnFlag) { processCell(&_layer[(_yChangeStart + _yCtr * _yChangeInc) * DECODED_PATHS_WIDTH + (_xChangeStart + _xCtr * _xChangeInc)]); - if (breakFlag && (_countdownCtr <= 0)) return PF_UNFINISHED; + if (breakFlag && (_countdownCtr <= 0)) + return PF_UNFINISHED; } else { returnFlag = false; } @@ -4248,7 +4290,8 @@ PathFinderResult PathFinder::process() { } // If the destination cell has been filled in, then break out of loop - if (*_pDest != 0) break; + if (*_pDest != 0) + break; if (_cellPopulated) { // At least one cell populated, so go repeat loop @@ -4306,27 +4349,37 @@ PathFinderResult PathFinder::process() { currDirection = NO_DIRECTION; while (1) { v = *pCurrent - 1; - if (v == 0) break; + if (v == 0) + break; newDirection = NO_DIRECTION; if (!altFlag && (currDirection != LEFT) && (currDirection != RIGHT)) { // Standard order direction checking - if (*(pCurrent - DECODED_PATHS_WIDTH) == v) newDirection = DOWN; - else if (*(pCurrent + DECODED_PATHS_WIDTH) == v) newDirection = UP; - else if (*(pCurrent + 1) == v) newDirection = LEFT; - else if (*(pCurrent - 1) == v) newDirection = RIGHT; + if (*(pCurrent - DECODED_PATHS_WIDTH) == v) + newDirection = DOWN; + else if (*(pCurrent + DECODED_PATHS_WIDTH) == v) + newDirection = UP; + else if (*(pCurrent + 1) == v) + newDirection = LEFT; + else if (*(pCurrent - 1) == v) + newDirection = RIGHT; } else { // Alternate order direction checking - if (*(pCurrent + 1) == v) newDirection = LEFT; - else if (*(pCurrent - 1) == v) newDirection = RIGHT; - else if (*(pCurrent - DECODED_PATHS_WIDTH) == v) newDirection = DOWN; - else if (*(pCurrent + DECODED_PATHS_WIDTH) == v) newDirection = UP; + if (*(pCurrent + 1) == v) + newDirection = LEFT; + else if (*(pCurrent - 1) == v) + newDirection = RIGHT; + else if (*(pCurrent - DECODED_PATHS_WIDTH) == v) + newDirection = DOWN; + else if (*(pCurrent + DECODED_PATHS_WIDTH) == v) + newDirection = UP; } if (newDirection == NO_DIRECTION) error("Path finding process failed"); // Process for the specified direction - if (newDirection != currDirection) add(newDirection, 0); + if (newDirection != currDirection) + add(newDirection, 0); switch (newDirection) { case UP: @@ -4373,8 +4426,10 @@ PathFinderResult PathFinder::process() { } // Final Step - if (_xPos < 0) add(RIGHT, -_xPos); - else if (_xPos > 0) add(LEFT, _xPos); + if (_xPos < 0) + add(RIGHT, -_xPos); + else if (_xPos > 0) + add(LEFT, _xPos); return result; } @@ -4401,16 +4456,20 @@ void PathFinder::processCell(uint16 *p) { // Check the surrounding cells (up,down,left,right) for values // Up vTemp = *(p - DECODED_PATHS_WIDTH); - if ((vTemp != 0) && (vTemp < vMax)) vMax = vTemp; + if ((vTemp != 0) && (vTemp < vMax)) + vMax = vTemp; // Down vTemp = *(p + DECODED_PATHS_WIDTH); - if ((vTemp != 0) && (vTemp < vMax)) vMax = vTemp; + if ((vTemp != 0) && (vTemp < vMax)) + vMax = vTemp; // Left vTemp = *(p - 1); - if ((vTemp != 0) && (vTemp < vMax)) vMax = vTemp; + if ((vTemp != 0) && (vTemp < vMax)) + vMax = vTemp; // Right vTemp = *(p + 1); - if ((vTemp != 0) && (vTemp < vMax)) vMax = vTemp; + if ((vTemp != 0) && (vTemp < vMax)) + vMax = vTemp; if (vMax != 0xffff) { // A surrounding cell with a value was found @@ -4432,7 +4491,8 @@ void PathFinder::scanLine(int numScans, int changeAmount, uint16 *&pEnd, int &v) for (int ctr = 1; ctr <= numScans; ++ctr) { pTemp += changeAmount; if ((*pTemp != 0) && (*pTemp != 0xffff)) { - if ((v < ctr) || ((v == ctr) && (*pTemp >= *pEnd))) return; + if ((v < ctr) || ((v == ctr) && (*pTemp >= *pEnd))) + return; pEnd = pTemp; v = ctr; break; @@ -4447,11 +4507,15 @@ void PathFinder::initVars() { _destX = _hotspot->destX(); _destY = _hotspot->destY(); - if (_destX < 10) _destX -= 50; - if (_destX >= FULL_SCREEN_WIDTH-10) _destX += 50; + if (_destX < 10) + _destX -= 50; + if (_destX >= FULL_SCREEN_WIDTH-10) + _destX += 50; - _xPos = 0; _yPos = 0; - _xDestPos = 0; _yDestPos = 0; + _xPos = 0; + _yPos = 0; + _xDestPos = 0; + _yDestPos = 0; _xCurrent = _hotspot->x(); if (_xCurrent < 0) { @@ -4621,7 +4685,8 @@ void Support::characterChangeRoom(Hotspot &h, uint16 roomNumber, if (h.hotspotId() == PLAYER_ID) { // Room change code for the player - if (room.cursorState() != CS_NONE) return; + if (room.cursorState() != CS_NONE) + return; PlayerNewPosition &p = fields.playerNewPos(); if (checkForIntersectingCharacter(h, newX, newY - 48, roomNumber)) { @@ -4678,7 +4743,8 @@ bool Support::charactersIntersecting(HotspotData *hotspot1, HotspotData *hotspot bool Support::isCharacterInList(uint16 *lst, int numEntries, uint16 charId) { while (numEntries-- > 0) - if (*lst++ == charId) return true; + if (*lst++ == charId) + return true; return false; } diff --git a/engines/made/graphics.cpp b/engines/made/graphics.cpp index 4d3fc7116a..a8e33774f6 100644 --- a/engines/made/graphics.cpp +++ b/engines/made/graphics.cpp @@ -83,7 +83,7 @@ void decompressImage(byte *source, Graphics::Surface &surface, uint16 cmdOffs, u if ((maskFlags != 0) && (maskFlags != 2) && (pixelFlags != 0) && (pixelFlags != 2) && (cmdFlags != 0)) error("decompressImage() Unsupported flags: cmdFlags = %02X; maskFlags = %02X, pixelFlags = %02X", cmdFlags, maskFlags, pixelFlags); - byte *destPtr = (byte *)surface.getBasePtr(0, 0); + byte *destPtr = (byte *)surface.getPixels(); byte lineBuf[640 * 4]; byte bitBuf[40]; @@ -196,7 +196,7 @@ void decompressMovieImage(byte *source, Graphics::Surface &surface, uint16 cmdOf byte *maskBuffer = source + maskOffs; byte *pixelBuffer = source + pixelOffs; - byte *destPtr = (byte *)surface.getBasePtr(0, 0); + byte *destPtr = (byte *)surface.getPixels(); byte bitBuf[40]; diff --git a/engines/made/pmvplayer.cpp b/engines/made/pmvplayer.cpp index cf450f7e25..573ff7faf1 100644 --- a/engines/made/pmvplayer.cpp +++ b/engines/made/pmvplayer.cpp @@ -248,7 +248,7 @@ void PmvPlayer::handleEvents() { } void PmvPlayer::updateScreen() { - _vm->_system->copyRectToScreen(_surface->pixels, _surface->pitch, + _vm->_system->copyRectToScreen(_surface->getPixels(), _surface->pitch, (320 - _surface->w) / 2, (200 - _surface->h) / 2, _surface->w, _surface->h); _vm->_system->updateScreen(); } diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp index ea7d57f82d..30848e8ec1 100644 --- a/engines/made/screen.cpp +++ b/engines/made/screen.cpp @@ -344,12 +344,12 @@ void Screen::drawSpriteChannels(const ClipInfo &clipInfo, int16 includeStateMask void Screen::updateSprites() { // TODO: This needs some more work, dirty rectangles are currently not used - memcpy(_workScreen->pixels, _backgroundScreen->pixels, 64000); + memcpy(_workScreen->getPixels(), _backgroundScreen->getPixels(), 64000); drawSpriteChannels(_backgroundScreenDrawCtx, 3, 0); drawSpriteChannels(_workScreenDrawCtx, 1, 2); - _vm->_system->copyRectToScreen(_workScreen->pixels, _workScreen->pitch, 0, 0, _workScreen->w, _workScreen->h); + _vm->_system->copyRectToScreen(_workScreen->getPixels(), _workScreen->pitch, 0, 0, _workScreen->w, _workScreen->h); _vm->_screen->updateScreenAndWait(10); } @@ -593,7 +593,7 @@ void Screen::show() { return; drawSpriteChannels(_backgroundScreenDrawCtx, 3, 0); - memcpy(_workScreen->pixels, _backgroundScreen->pixels, 64000); + memcpy(_workScreen->getPixels(), _backgroundScreen->getPixels(), 64000); drawSpriteChannels(_workScreenDrawCtx, 1, 2); _fx->run(_visualEffectNum, _workScreen, _palette, _newPalette, _paletteColorCount); @@ -775,7 +775,7 @@ void Screen::unlockScreen() { } void Screen::showWorkScreen() { - _vm->_system->copyRectToScreen(_workScreen->pixels, _workScreen->pitch, 0, 0, _workScreen->w, _workScreen->h); + _vm->_system->copyRectToScreen(_workScreen->getPixels(), _workScreen->pitch, 0, 0, _workScreen->w, _workScreen->h); } void Screen::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) { diff --git a/engines/made/screenfx.cpp b/engines/made/screenfx.cpp index ad71f1fb49..d069308a4b 100644 --- a/engines/made/screenfx.cpp +++ b/engines/made/screenfx.cpp @@ -368,7 +368,7 @@ void ScreenEffects::vfx07(Graphics::Surface *surface, byte *palette, byte *newPa // "Screen slide in" right to left void ScreenEffects::vfx08(Graphics::Surface *surface, byte *palette, byte *newPalette, int colorCount) { for (int x = 8; x <= 320; x += 8) { - _screen->copyRectToScreen(surface->getBasePtr(0, 0), surface->pitch, 320 - x, 0, x, 200); + _screen->copyRectToScreen(surface->getPixels(), surface->pitch, 320 - x, 0, x, 200); _screen->updateScreenAndWait(25); } setPalette(palette); @@ -529,7 +529,7 @@ void ScreenEffects::vfx19(Graphics::Surface *surface, byte *palette, byte *newPa // "Screen slide in" bottom to top void ScreenEffects::vfx20(Graphics::Surface *surface, byte *palette, byte *newPalette, int colorCount) { for (int y = 4; y <= 200; y += 4) { - _screen->copyRectToScreen(surface->getBasePtr(0, 0), surface->pitch, 0, 200 - y, 320, y); + _screen->copyRectToScreen(surface->getPixels(), surface->pitch, 0, 200 - y, 320, y); _screen->updateScreenAndWait(25); } diff --git a/engines/made/scriptfuncs.cpp b/engines/made/scriptfuncs.cpp index c57778fb71..0e3b50aa98 100644 --- a/engines/made/scriptfuncs.cpp +++ b/engines/made/scriptfuncs.cpp @@ -574,7 +574,7 @@ int16 ScriptFunctions::sfLoadMouseCursor(int16 argc, int16 *argv) { PictureResource *flex = _vm->_res->getPicture(argv[2]); if (flex) { Graphics::Surface *surf = flex->getPicture(); - CursorMan.replaceCursor(surf->pixels, surf->w, surf->h, argv[1], argv[0], 0); + CursorMan.replaceCursor(surf->getPixels(), surf->w, surf->h, argv[1], argv[0], 0); _vm->_res->freeResource(flex); } return 0; diff --git a/engines/mohawk/bitmap.cpp b/engines/mohawk/bitmap.cpp index bc19fe2d3e..b321e043d9 100644 --- a/engines/mohawk/bitmap.cpp +++ b/engines/mohawk/bitmap.cpp @@ -580,7 +580,7 @@ void MohawkBitmap::drawRaw(Graphics::Surface *surface) { _data->skip(_header.bytesPerRow - _header.width * 3); } else { - _data->read((byte *)surface->pixels + y * _header.width, _header.width); + _data->read((byte *)surface->getBasePtr(0, y), _header.width); _data->skip(_header.bytesPerRow - _header.width); } } @@ -599,7 +599,7 @@ void MohawkBitmap::drawRLE8(Graphics::Surface *surface, bool isLE) { for (uint16 i = 0; i < _header.height; i++) { uint16 rowByteCount = isLE ? _data->readUint16LE() : _data->readUint16BE(); int32 startPos = _data->pos(); - byte *dst = (byte *)surface->pixels + i * _header.width; + byte *dst = (byte *)surface->getBasePtr(0, i); int16 remaining = _header.width; while (remaining > 0) { @@ -779,7 +779,7 @@ MohawkSurface *DOSBitmap::decodeImage(Common::SeekableReadStream *stream) { } Graphics::Surface *surface = createSurface(_header.width, _header.height); - memset(surface->pixels, 0, _header.width * _header.height); + memset(surface->getPixels(), 0, _header.width * _header.height); // Expand the <8bpp data to one byte per pixel switch (getBitsPerPixel()) { @@ -801,7 +801,7 @@ MohawkSurface *DOSBitmap::decodeImage(Common::SeekableReadStream *stream) { void DOSBitmap::expandMonochromePlane(Graphics::Surface *surface, Common::SeekableReadStream *rawStream) { assert(surface->format.bytesPerPixel == 1); - byte *dst = (byte *)surface->pixels; + byte *dst = (byte *)surface->getPixels(); // Expand the 8 pixels in a byte into a full byte per pixel @@ -830,7 +830,7 @@ void DOSBitmap::expandEGAPlanes(Graphics::Surface *surface, Common::SeekableRead // Note that the image is in EGA planar form and not just standard 4bpp // This seems to contradict the PoP specs which seem to do something else - byte *dst = (byte *)surface->pixels; + byte *dst = (byte *)surface->getPixels(); for (uint32 i = 0; i < surface->h; i++) { uint x = 0; diff --git a/engines/mohawk/cursors.cpp b/engines/mohawk/cursors.cpp index c7bd03678f..f70efde5fb 100644 --- a/engines/mohawk/cursors.cpp +++ b/engines/mohawk/cursors.cpp @@ -121,11 +121,11 @@ void MystCursorManager::setCursor(uint16 id) { // Myst ME stores some cursors as 24bpp images instead of 8bpp if (surface->format.bytesPerPixel == 1) { - CursorMan.replaceCursor(surface->pixels, surface->w, surface->h, hotspotX, hotspotY, 0); + CursorMan.replaceCursor(surface->getPixels(), surface->w, surface->h, hotspotX, hotspotY, 0); CursorMan.replaceCursorPalette(mhkSurface->getPalette(), 0, 256); } else { Graphics::PixelFormat pixelFormat = g_system->getScreenFormat(); - CursorMan.replaceCursor(surface->pixels, surface->w, surface->h, hotspotX, hotspotY, pixelFormat.RGBToColor(255, 255, 255), false, &pixelFormat); + CursorMan.replaceCursor(surface->getPixels(), surface->w, surface->h, hotspotX, hotspotY, pixelFormat.RGBToColor(255, 255, 255), false, &pixelFormat); } _vm->_needsUpdate = true; diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp index efa0dd3fd3..634ff441b6 100644 --- a/engines/mohawk/livingbooks.cpp +++ b/engines/mohawk/livingbooks.cpp @@ -311,8 +311,8 @@ void MohawkEngine_LivingBooks::loadBookInfo(const Common::String &filename) { // - fDebugWindow (always 0?) if (_bookInfoFile.hasSection("Globals")) { - const Common::ConfigFile::SectionKeyList globals = _bookInfoFile.getKeys("Globals"); - for (Common::ConfigFile::SectionKeyList::const_iterator i = globals.begin(); i != globals.end(); i++) { + const Common::INIFile::SectionKeyList globals = _bookInfoFile.getKeys("Globals"); + for (Common::INIFile::SectionKeyList::const_iterator i = globals.begin(); i != globals.end(); i++) { Common::String command = Common::String::format("%s = %s", i->key.c_str(), i->value.c_str()); LBCode tempCode(this, 0); uint offset = tempCode.parseCode(command); diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h index 76da7d8219..615fcd0e16 100644 --- a/engines/mohawk/livingbooks.h +++ b/engines/mohawk/livingbooks.h @@ -28,7 +28,7 @@ #include "mohawk/livingbooks_graphics.h" #include "mohawk/sound.h" -#include "common/config-file.h" +#include "common/ini-file.h" #include "common/rect.h" #include "common/queue.h" #include "common/random.h" @@ -759,7 +759,7 @@ public: private: LivingBooksConsole *_console; - Common::ConfigFile _bookInfoFile; + Common::INIFile _bookInfoFile; Common::String getBookInfoFileName() const; void loadBookInfo(const Common::String &filename); diff --git a/engines/mohawk/livingbooks_lbx.cpp b/engines/mohawk/livingbooks_lbx.cpp index 2b8b22ec81..dcf8caa4a5 100644 --- a/engines/mohawk/livingbooks_lbx.cpp +++ b/engines/mohawk/livingbooks_lbx.cpp @@ -33,7 +33,7 @@ public: bool call(uint callId, const Common::Array<LBValue> ¶ms, LBValue &result); protected: - Common::ConfigFile _dataFile; + Common::INIFile _dataFile; Common::String _curSection; void open(const Common::String &filename); @@ -77,8 +77,8 @@ bool LBXDataFile::call(uint callId, const Common::Array<LBValue> ¶ms, LBValu case kLBXDataFileGetSectionList: { Common::SharedPtr<LBList> list = Common::SharedPtr<LBList>(new LBList); - Common::ConfigFile::SectionList sections = _dataFile.getSections(); - for (Common::List<Common::ConfigFile::Section>::const_iterator i = sections.begin(); i != sections.end(); ++i) + Common::INIFile::SectionList sections = _dataFile.getSections(); + for (Common::List<Common::INIFile::Section>::const_iterator i = sections.begin(); i != sections.end(); ++i) list->array.push_back(LBValue(i->name)); result = LBValue(list); } @@ -103,8 +103,8 @@ bool LBXDataFile::call(uint callId, const Common::Array<LBValue> ¶ms, LBValu error("incorrect number of parameters (%d) to LBXDataFile::loadCurSectionVars", params.size()); { - const Common::ConfigFile::SectionKeyList globals = _dataFile.getKeys(_curSection); - for (Common::ConfigFile::SectionKeyList::const_iterator i = globals.begin(); i != globals.end(); i++) { + const Common::INIFile::SectionKeyList globals = _dataFile.getKeys(_curSection); + for (Common::INIFile::SectionKeyList::const_iterator i = globals.begin(); i != globals.end(); i++) { Common::String command = Common::String::format("%s = %s", i->key.c_str(), i->value.c_str()); LBCode tempCode(_vm, 0); uint offset = tempCode.parseCode(command); diff --git a/engines/mohawk/riven_graphics.cpp b/engines/mohawk/riven_graphics.cpp index 05e66a3924..cd15960b85 100644 --- a/engines/mohawk/riven_graphics.cpp +++ b/engines/mohawk/riven_graphics.cpp @@ -255,7 +255,7 @@ void RivenGraphics::runScheduledTransition() { } // For now, just copy the image to screen without doing any transition. - _vm->_system->copyRectToScreen(_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); + _vm->_system->copyRectToScreen(_mainScreen->getPixels(), _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); _vm->_system->updateScreen(); _scheduledTransition = -1; // Clear scheduled transition @@ -345,7 +345,7 @@ void RivenGraphics::drawInventoryImage(uint16 id, const Common::Rect *rect) { mhkSurface->convertToTrueColor(); Graphics::Surface *surface = mhkSurface->getSurface(); - _vm->_system->copyRectToScreen(surface->pixels, surface->pitch, rect->left, rect->top, surface->w, surface->h); + _vm->_system->copyRectToScreen(surface->getPixels(), surface->pitch, rect->left, rect->top, surface->w, surface->h); delete mhkSurface; } @@ -420,7 +420,7 @@ void RivenGraphics::updateCredits() { } else { // Otheriwse, we're scrolling // Move the screen up one row - memmove(_mainScreen->pixels, _mainScreen->getBasePtr(0, 1), _mainScreen->pitch * (_mainScreen->h - 1)); + memmove(_mainScreen->getPixels(), _mainScreen->getBasePtr(0, 1), _mainScreen->pitch * (_mainScreen->h - 1)); // Only update as long as we're not before the last frame // Otherwise, we're just moving up a row (which we already did) @@ -437,7 +437,7 @@ void RivenGraphics::updateCredits() { } // Now flush the new screen - _vm->_system->copyRectToScreen(_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); + _vm->_system->copyRectToScreen(_mainScreen->getPixels(), _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); _vm->_system->updateScreen(); } } diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index 8b0130d711..b7e06a2b9f 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -245,7 +245,7 @@ bool VideoManager::updateMovies() { // Clip the width/height to make sure we stay on the screen (Myst does this a few times) uint16 width = MIN<int32>(_videoStreams[i]->getWidth(), _vm->_system->getWidth() - _videoStreams[i].x); uint16 height = MIN<int32>(_videoStreams[i]->getHeight(), _vm->_system->getHeight() - _videoStreams[i].y); - _vm->_system->copyRectToScreen(frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height); + _vm->_system->copyRectToScreen(frame->getPixels(), frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height); // We've drawn something to the screen, make sure we update it updateScreen = true; diff --git a/engines/mortevielle/actions.cpp b/engines/mortevielle/actions.cpp new file mode 100644 index 0000000000..c06f19dadc --- /dev/null +++ b/engines/mortevielle/actions.cpp @@ -0,0 +1,1633 @@ +/* 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#include "mortevielle/mortevielle.h" +#include "mortevielle/dialogs.h" +#include "mortevielle/menu.h" +#include "mortevielle/mouse.h" +#include "mortevielle/outtext.h" + +#include "common/scummsys.h" + +namespace Mortevielle { + +/** + * Engine function - Move + * @remarks Originally called 'taller' + */ +void MortevielleEngine::fctMove() { + int oldMenu = (_menu._moveMenu[6]._menuId << 8) | _menu._moveMenu[6]._actionId; + if ((_coreVar._currPlace == ROOM26) && (_currAction == oldMenu)) { + _coreVar._currPlace = LANDING; + _caff = _coreVar._currPlace; + drawPictureWithText(); + handleDescriptionText(2, _coreVar._currPlace); + } + if ((_coreVar._currPlace == LANDING) && (_currAction == oldMenu)) { + if (!_syn) + displayTextInVerbBar(getEngineString(S_GO_TO)); + displayStatusArrow(); + + if (_keyPressedEsc) + _destinationOk = false; + + if ((_anyone) || (_keyPressedEsc)) + return; + + setCoordinates(1); + + if (_num == 0) + return; + + if (_num == 1) { + _coreVar._currPlace = OWN_ROOM; + _menu.setDestinationText(OWN_ROOM); + } else if (_num == 7) { + _coreVar._currPlace = ATTIC; + _menu.setDestinationText(ATTIC); + } else if (_num != 6) + _coreVar._currPlace = ROOM26; + + if ((_num > 1) && (_num < 6)) + _roomDoorId = _num - 1; + else if (_num > 7) + _roomDoorId = _num - 3; + + if (_num != 6) + prepareDisplayText(); + else + showMoveMenuAlert(); + return; + } + exitRoom(); + int menuChoice = 1; + oldMenu = (_menu._moveMenu[menuChoice]._menuId << 8) | _menu._moveMenu[menuChoice]._actionId; + while (oldMenu != _currAction) { + ++menuChoice; + oldMenu = (_menu._moveMenu[menuChoice]._menuId << 8) | _menu._moveMenu[menuChoice]._actionId; + } + + if (_coreVar._currPlace == MOUNTAIN) { + if (menuChoice == 1) + gotoManorFront(); + else if (menuChoice == 2) + checkManorDistance(); + _menu.setDestinationText(_coreVar._currPlace); + return; + } else if (_coreVar._currPlace == INSIDE_WELL) { + if (menuChoice == 1) + floodedInWell(); + else if (menuChoice == 2) + gotoManorBack(); + _menu.setDestinationText(_coreVar._currPlace); + return; + } else if ((_coreVar._currPlace == BUREAU) && (menuChoice == 1)) + menuChoice = 6; + else if (_coreVar._currPlace == KITCHEN) { + if (menuChoice == 2) + menuChoice = 6; + else if (menuChoice == 5) + menuChoice = 16; + } else if ((_coreVar._currPlace == CELLAR) && (menuChoice == 3)) + menuChoice = 6; + else if (((_coreVar._currPlace == LANDING) || (_coreVar._currPlace == ROOM26)) && (menuChoice == 4)) + menuChoice = 6; + + if ((_coreVar._currPlace > MOUNTAIN) && (_coreVar._currPlace != ROOM26)) + menuChoice += 10; + + if ((_coreVar._currPlace == CHAPEL) && (menuChoice == 13)) + menuChoice = 16; + else if (_coreVar._currPlace == MANOR_FRONT) { + if (menuChoice == 12) + menuChoice = 16; + else if (menuChoice > 13) + menuChoice = 15; + } else if ((_coreVar._currPlace == MANOR_BACK) && (menuChoice > 14)) + menuChoice = 15; + else if ((_coreVar._currPlace == WELL) && (menuChoice > 13) && (menuChoice != 17)) + menuChoice = 15; + + if (menuChoice == 1) + _coreVar._currPlace = BUREAU; + else if (menuChoice == 2) + _coreVar._currPlace = KITCHEN; + else if (menuChoice == 3) + _coreVar._currPlace = CELLAR; + else if (menuChoice == 4) + _coreVar._currPlace = LANDING; + else if (menuChoice == 5) + menuChoice = 12; + else if (menuChoice == 6) + menuChoice = 11; + + if (menuChoice == 11) + gotoDiningRoom(); + else if (menuChoice == 12) + gotoManorFront(); + else if (menuChoice == 13) + _coreVar._currPlace = CHAPEL; + else if (menuChoice == 14) + _coreVar._currPlace = WELL; + else if (menuChoice == 15) + checkManorDistance(); + else if (menuChoice == 16) + gotoManorBack(); + else if (menuChoice == 17) { + if ((_coreVar._wellObjectId != 120) && (_coreVar._wellObjectId != 140)) + _crep = 997; + else if (_coreVar._wellObjectId == 120) + _crep = 181; + else if (_coreVar._faithScore > 80) { + _crep = 1505; + loseGame(); + } else { + _coreVar._currPlace = INSIDE_WELL; + prepareDisplayText(); + } + } + if ((menuChoice < 5) || (menuChoice == 13) || (menuChoice == 14)) + prepareDisplayText(); + resetRoomVariables(_coreVar._currPlace); + _menu.setDestinationText(_coreVar._currPlace); +} + +/** + * Engine function - Take + * @remarks Originally called 'tprendre' + */ +void MortevielleEngine::fctTake() { + if (_caff > 99) { + int cx = _caff; + putInHand(cx); + if (_crep != 139) { + if (_currBitIndex > 0) + _coreVar._faithScore += 3; + if (_obpart) { + if (_coreVar._currPlace == PURPLE_ROOM) + _coreVar._purpleRoomObjectId = 0; + if (_coreVar._currPlace == ATTIC) { + if (_coreVar._atticBallHoleObjectId == _caff) + _coreVar._atticBallHoleObjectId = 0; + if (_coreVar._atticRodHoleObjectId == _caff) + _coreVar._atticRodHoleObjectId = 0; + } + if (_coreVar._currPlace == CELLAR) + _coreVar._cellarObjectId = 0; + if (_coreVar._currPlace == CRYPT) + _coreVar._cryptObjectId = 0; + if (_coreVar._currPlace == SECRET_PASSAGE) + _coreVar._secretPassageObjectId = 0; + if (_coreVar._currPlace == WELL) + _coreVar._wellObjectId = 0; + _menu.unsetSearchMenu(); + _obpart = false; + prepareDisplayText(); + } else { + _tabdon[kAcha + ((_curSearchObjId - 1) * 10) + _searchCount - 1] = 0; + prepareNextObject(); + ++_takeObjCount; + if (_takeObjCount > 6) { + _coreVar._faithScore += 2; + _takeObjCount = 0; + } + } + } + return; + } + if (!_syn) + displayTextInVerbBar(getEngineString(S_TAKE)); + displayStatusArrow(); + if ((_anyone) || (_keyPressedEsc)) + return; + if (_caff == 3) { + setCoordinates(2); + if (_num == 1) { + _crep = 152; + return; + } + } + setCoordinates(5); + if ((_num == 0) || ((_num == 1) && (_coreVar._currPlace == CRYPT))) { + setCoordinates(8); + if (_num != 0) { + 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); + } + } + 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; + } + } else { + if ( ((_coreVar._currPlace == OWN_ROOM) && (_num == 3)) + || ((_coreVar._currPlace == GREEN_ROOM) && (_num == 4)) + || ((_coreVar._currPlace == PURPLE_ROOM) && (_num == 1)) + || ((_coreVar._currPlace == DARKBLUE_ROOM) && (_num == 3)) + || ((_coreVar._currPlace == BLUE_ROOM) && (_num == 6)) + || ((_coreVar._currPlace == RED_ROOM) && (_num == 2)) + || ((_coreVar._currPlace == BATHROOM) && (_num == 6)) + || ((_coreVar._currPlace == GREEN_ROOM2) && (_num == 4)) + || ((_coreVar._currPlace == JULIA_ROOM) && (_num == 4)) + || ((_coreVar._currPlace == DINING_ROOM) && (_num > 2)) + || ((_coreVar._currPlace == BUREAU) && (_num == 7)) + || ((_coreVar._currPlace == KITCHEN) && (_num == 6)) + || ((_coreVar._currPlace == ATTIC) && (_num > 4)) + || ((_coreVar._currPlace > ATTIC) && (_coreVar._currPlace != INSIDE_WELL)) ) + _crep = 997; + else if (_coreVar._currPlace == INSIDE_WELL) { + _crep = 1504; + loseGame(); + } else + _crep = 120; + } +} +/** + * Engine function - Inventory / Take + * @remarks Originally called 'tsprendre' + */ +void MortevielleEngine::fctInventoryTake() { + int inventIndex = 0; + int oldMenu = 0; + do { + ++inventIndex; + oldMenu = (_menu._inventoryMenu[inventIndex]._menuId << 8) | _menu._inventoryMenu[inventIndex]._actionId; + } while (oldMenu != _currAction); + int cz = 0; + int cy = 0; + do { + ++cy; + if (_coreVar._inventory[cy] != 0) + ++cz; + } while (cz != inventIndex); + cz = _coreVar._inventory[cy]; + _coreVar._inventory[cy] = 0; + _menu.setInventoryText(); + putInHand(cz); + _crep = 998; + clearDescriptionBar(); +} + +/** + * Engine function - Lift + * @remarks Originally called 'tsoulever' + */ +void MortevielleEngine::fctLift() { + if (!_syn) + displayTextInVerbBar(getEngineString(S_LIFT)); + displayStatusArrow(); + if ((_anyone) || (_keyPressedEsc)) + return; + setCoordinates(3); + if (_num == 0) { + setCoordinates(8); + if (_num != 0) { + if (_currBitIndex > 0) + ++_coreVar._faithScore; + _crep = 997; + if ((_coreVar._currPlace == PURPLE_ROOM) && (_coreVar._purpleRoomObjectId != 0)) + displayLookScreen(_coreVar._purpleRoomObjectId); + } + return; + } + if (_currBitIndex > 0) + ++_coreVar._faithScore; + int tmpPlace = _coreVar._currPlace; + if (_coreVar._currPlace == CRYPT) + tmpPlace = 14; + else if (_coreVar._currPlace == MOUNTAIN) + tmpPlace = 15; + _crep = _tabdon[kAsoul + (tmpPlace << 3) + (_num - 1)]; + if (_crep == 255) + _crep = 997; +} + +/** + * Engine function - Read + * @remarks Originally called 'tlire' + */ +void MortevielleEngine::fctRead() { + if (_caff > 99) + getReadDescription(_caff); + else { + if (!_syn) + displayTextInVerbBar(getEngineString(S_READ)); + displayStatusArrow(); + if (!(_anyone) && !(_keyPressedEsc)) { + setCoordinates(4); + if (_num != 0) + _crep = 107; + } + } +} + +/** + * Engine function - Self / Read + * @remarks Originally called 'tslire' + */ +void MortevielleEngine::fctSelfRead() { + if (_coreVar._selectedObjectId == 0) + _crep = 186; + else + getReadDescription(_coreVar._selectedObjectId); +} + +/** + * Engine function - Look + * @remarks Originally called 'tregarder' + */ +void MortevielleEngine::fctLook() { + if (_caff > 99) { + _crep = 103; + return; + } + if (!_syn) + displayTextInVerbBar(getEngineString(S_LOOK)); + displayStatusArrow(); + if ((_anyone) || (_keyPressedEsc)) + return; + setCoordinates(5); + if (_num == 0) { + setCoordinates(8); + _crep = 131; + if (_num != 0) { + if (_coreVar._currPlace == ATTIC) { + if (_num == 1) { + _crep = 164; + if (_coreVar._atticRodHoleObjectId != 0) + displayLookScreen(_coreVar._atticRodHoleObjectId); + else if (_coreVar._atticBallHoleObjectId != 0) + displayLookScreen(_coreVar._atticBallHoleObjectId); + } else { + _crep = 193; + if (_coreVar._atticRodHoleObjectId != 0) + displayLookScreen(_coreVar._atticRodHoleObjectId); + } + } + if (_coreVar._currPlace == CELLAR) { + _crep = 164; + if (_coreVar._cellarObjectId != 0) + displayLookScreen(_coreVar._cellarObjectId); + } + if (_coreVar._currPlace == SECRET_PASSAGE) { + _crep = 174; + if (_coreVar._secretPassageObjectId != 0) + displayLookScreen(_coreVar._secretPassageObjectId); + } + if (_coreVar._currPlace == WELL) { + _crep = 131; + if (_coreVar._wellObjectId != 0) + displayLookScreen(_coreVar._wellObjectId); + } + } + return; + } + int cx = _coreVar._currPlace; + if (_coreVar._currPlace == CHAPEL) + cx = 17; + if ((_coreVar._currPlace > MANOR_FRONT) && (_coreVar._currPlace < DOOR)) + cx -= 4; + if (_coreVar._currPlace == ROOM26) + cx = 21; + _crep = _tabdon[kArega + (cx * 7) + _num - 1]; + if ((_coreVar._currPlace == ATTIC) && (_num == 8)) + _crep = 126; + if (_coreVar._currPlace == MOUNTAIN) + _crep = 103; + if (_crep == 255) + _crep = 131; + if ((_coreVar._currPlace == GREEN_ROOM) && (_num == 1)) + displayLookScreen(144); + if ((_coreVar._currPlace == BLUE_ROOM) && (_num == 3)) + displayLookScreen(147); + if ((_coreVar._currPlace == GREEN_ROOM2) && (_num == 3)) + displayLookScreen(149); + if ((_coreVar._currPlace == JULIA_ROOM) && (_num == 2)) + displayLookScreen(30); + if ((_coreVar._currPlace == DINING_ROOM) && (_num == 3)) + displayLookScreen(31); +} + +/** + * Engine function - Self / Look + * @remarks Originally called 'tsregarder' + */ +void MortevielleEngine::fctSelftLook() { + if (_coreVar._selectedObjectId != 0) + displayLookScreen(_coreVar._selectedObjectId); + else + _crep = 186; +} + +/** + * Engine function - Search + * @remarks Originally called 'tfouiller' + */ +void MortevielleEngine::fctSearch() { + static const byte answerArr[14] = {123, 104, 123, 131, 131, 123, 104, 131, 123, 123, 106, 123, 123, 107}; + + if (_caff > 99) { + getSearchDescription(_caff); + return; + } + + if (!_syn) + displayTextInVerbBar(getEngineString(S_SEARCH)); + + displayStatusArrow(); + if (_anyone || _keyPressedEsc) + return; + + if (_coreVar._currPlace == INSIDE_WELL) { + _crep = 1504; + loseGame(); + return; + } + + setCoordinates(6); + if (_num == 0) { + setCoordinates(7); + if (_num != 0) { + int i; + for (i = 1; (i <= 6) && (_num != _openObjects[i]); i++) + ; + if (_num == _openObjects[i]) { + if (_currBitIndex > 0) + _coreVar._faithScore += 3; + + _curSearchObjId = getFirstObject(); + if (_curSearchObjId != 0) { + _searchCount = 0; + _heroSearching = true; + _menu.setSearchMenu(); + prepareNextObject(); + } else + _crep = 997; + } else + _crep = 187; + } else { + setCoordinates(8); + _crep = 997; + if (_num != 0) { + if (_currBitIndex > 0) + _coreVar._faithScore += 3; + if ((_coreVar._currPlace != WELL) && (_coreVar._currPlace != SECRET_PASSAGE) && (_coreVar._currPlace != ATTIC)) { + if (_coreVar._currPlace == PURPLE_ROOM) { + _crep = 123; + if (_coreVar._purpleRoomObjectId != 0) + displayLookScreen(_coreVar._purpleRoomObjectId); + } + if (_coreVar._currPlace == CRYPT) { + _crep = 123; + if (_coreVar._cryptObjectId != 0) + displayLookScreen(_coreVar._cryptObjectId); + } + } + } + } + } else { + if (_currBitIndex > 0) + _coreVar._faithScore += 3; + _crep = 997; + if (_coreVar._currPlace < CELLAR) + _crep = answerArr[_coreVar._currPlace]; + + if ((_coreVar._currPlace == TOILETS) && (_num == 2)) + _crep = 162; + + if (_coreVar._currPlace == KITCHEN) { + if ((_num == 3) || (_num == 4)) + _crep = 162; + else if (_num == 5) + _crep = 159; + } + + if (_coreVar._currPlace == MOUNTAIN) + _crep = 104; + else if (_coreVar._currPlace == CRYPT) + _crep = 155; + } +} + +/** + * Engine function - Self / Search + * @remarks Originally called 'tsfouiller' + */ +void MortevielleEngine::fctSelfSearch() { + if (_coreVar._selectedObjectId != 0) + getSearchDescription(_coreVar._selectedObjectId); + else + _crep = 186; +} + +/** + * Engine function - Open + * @remarks Originally called 'touvrir' + */ +void MortevielleEngine::fctOpen() { + if (!_syn) + displayTextInVerbBar(getEngineString(S_OPEN)); + + if (_caff == ROOM26) { + if (_roomDoorId != OWN_ROOM) { + _currAction = _menu._opcodeEnter; + _syn = true; + } else + _crep = 997; + return; + } + + if (_caff == LANDING) { + showMoveMenuAlert(); + return; + } + + displayStatusArrow(); + if ((_anyone) || (_keyPressedEsc)) + return; + + setCoordinates(7); + if (_num != 0) { + if (_currBitIndex > 0) + _coreVar._faithScore += 2; + ++_openObjCount; + int i; + for (i = 1; (i <= 6) && (_openObjects[i] != 0) && (_openObjects[i] != _num); i++) + ; + if (_openObjects[i] != _num) { + if (!( ((_num == 3) && ((_coreVar._currPlace == OWN_ROOM) + || (_coreVar._currPlace == JULIA_ROOM) + || (_coreVar._currPlace == BLUE_ROOM) + || (_coreVar._currPlace == BATHROOM))) + || ((_num == 4) && ((_coreVar._currPlace == GREEN_ROOM) + || (_coreVar._currPlace == PURPLE_ROOM) + || (_coreVar._currPlace == RED_ROOM))) + || ((_coreVar._currPlace == DARKBLUE_ROOM) && (_num == 5)) + || ((_num == 6) && ((_coreVar._currPlace == BATHROOM) + || (_coreVar._currPlace == DINING_ROOM) + || (_coreVar._currPlace == GREEN_ROOM2) + || (_coreVar._currPlace == ATTIC))) + || ((_coreVar._currPlace == GREEN_ROOM2) && (_num == 2)) + || ((_coreVar._currPlace == KITCHEN) && (_num == 7))) ) { + if ( ((_coreVar._currPlace > DINING_ROOM) && (_coreVar._currPlace < CELLAR)) + || ((_coreVar._currPlace > RED_ROOM) && (_coreVar._currPlace < DINING_ROOM)) + || (_coreVar._currPlace == OWN_ROOM) + || (_coreVar._currPlace == PURPLE_ROOM) + || (_coreVar._currPlace == BLUE_ROOM)) { + if (getRandomNumber(1, 4) == 3) + _soundManager.startSpeech(7, 9, 1); + } + _openObjects[i] = _num; + displayAnimFrame(1, _num); + _soundManager.waitSpeech(); + } + int tmpPlace = _coreVar._currPlace; + if (_coreVar._currPlace == CRYPT) + tmpPlace = CELLAR; + _crep = _tabdon[kAouvr + (tmpPlace * 7) + _num - 1]; + if (_crep == 254) + _crep = 999; + } else + // display "Already Opened" + _crep = 18; + } +} + +/** + * Engine function - Place + * @remarks Originally called 'tmettre' + */ +void MortevielleEngine::fctPlace() { + if (_coreVar._selectedObjectId == 0) { + _crep = 186; + return; + } + + if (!_syn) + displayTextInVerbBar(getEngineString(S_PUT)); + + displayStatusArrow(); + if (_keyPressedEsc) + _crep = 998; + + if ((_anyone) || (_keyPressedEsc)) + return; + + setCoordinates(8); + if (_num != 0) { + _crep = 999; + if (_caff == ATTIC) { + if (_num == 1) { + if (_coreVar._atticBallHoleObjectId != 0) { + _crep = 188; + } else { + _coreVar._atticBallHoleObjectId = _coreVar._selectedObjectId; + if (_coreVar._selectedObjectId == 141) + displayAnimFrame(1, 7); + } + } else if (_coreVar._atticRodHoleObjectId != 0) { + _crep = 188; + } else { + _coreVar._atticRodHoleObjectId = _coreVar._selectedObjectId; + if (_coreVar._selectedObjectId == 159) + displayAnimFrame(1, 6); + } + } + + if (_caff == CELLAR) { + if (_coreVar._cellarObjectId != 0) { + _crep = 188; + } else { + _coreVar._cellarObjectId = _coreVar._selectedObjectId; + if (_coreVar._selectedObjectId == 151) { + // Open hidden passage + displayAnimFrame(1, 2); + displayAnimFrame(1, 1); + handleDescriptionText(2, 165); + displayEmptyHand(); + _soundManager.startSpeech(6, -9, 1); + + // Do you want to enter the hidden passage? + int answer = _dialogManager.show(getEngineString(S_YES_NO), 1); + if (answer == 1) { + Common::String alertTxt = getString(582); + _dialogManager.show(alertTxt, 1); + + bool enterPassageFl = _dialogManager.showKnowledgeCheck(); + _mouse.hideMouse(); + clearScreen(); + drawRightFrame(); + clearDescriptionBar(); + clearVerbBar(); + _mouse.showMouse(); + prepareRoom(); + drawClock(); + if (_currBitIndex != 0) + showPeoplePresent(_currBitIndex); + else + displayAloneText(); + + _menu.displayMenu(); + if (enterPassageFl) { + _coreVar._currPlace = SECRET_PASSAGE; + _menu.setDestinationText(SECRET_PASSAGE); + } else { + _menu.setDestinationText(_coreVar._currPlace); + setPal(14); + drawPicture(); + displayAnimFrame(1, 2); + displayAnimFrame(1, 1); + alertTxt = getString(577); + _dialogManager.show(alertTxt, 1); + displayAnimFrame(2, 1); + _crep = 166; + } + prepareDisplayText(); + } else { + displayAnimFrame(2, 1); + _crep = 166; + } + return; + } + } + } + + if (_caff == CRYPT) { + if (_coreVar._cryptObjectId == 0) + _coreVar._cryptObjectId = _coreVar._selectedObjectId; + else + _crep = 188; + } + + if (_caff == SECRET_PASSAGE) { + if (_coreVar._secretPassageObjectId != 0) { + _crep = 188; + } else if (_coreVar._selectedObjectId == 143) { + _coreVar._secretPassageObjectId = 143; + displayAnimFrame(1, 1); + } else { + _crep = 1512; + loseGame(); + } + } + + if (_caff == WELL) { + if (_coreVar._wellObjectId != 0) { + _crep = 188; + } else if ((_coreVar._selectedObjectId == 140) || (_coreVar._selectedObjectId == 120)) { + _coreVar._wellObjectId = _coreVar._selectedObjectId; + displayAnimFrame(1, 1); + } else { + _crep = 185; + } + } + + if (_crep != 188) + displayEmptyHand(); + } +} + +/** + * Engine function - Turn + * @remarks Originally called 'ttourner' + */ +void MortevielleEngine::fctTurn() { + if (_caff > 99) { + _crep = 149; + return; + } + if (!_syn) + displayTextInVerbBar(getEngineString(S_TURN)); + displayStatusArrow(); + if ((_anyone) || (_keyPressedEsc)) + return; + setCoordinates(9); + if (_num != 0) { + _crep = 997; + if ((_coreVar._currPlace == ATTIC) && (_coreVar._atticRodHoleObjectId == 159) && (_coreVar._atticBallHoleObjectId == 141)) { + handleDescriptionText(2, 167); + _soundManager.startSpeech(7, 9, 1); + int answer = _dialogManager.show(getEngineString(S_YES_NO), 1); + if (answer == 1) + _endGame = true; + else + _crep = 168; + } + if ((_coreVar._currPlace == SECRET_PASSAGE) && (_coreVar._secretPassageObjectId == 143)) { + handleDescriptionText(2, 175); + clearVerbBar(); + _soundManager.startSpeech(6, -9, 1); + int answer = _dialogManager.show(getEngineString(S_YES_NO), 1); + if (answer == 1) { + _coreVar._currPlace = CRYPT; + prepareDisplayText(); + } else + _crep = 176; + } + } +} + +/** + * Engine function - Hide Self + * @remarks Originally called 'tcacher' + */ +void MortevielleEngine::fctSelfHide() { + if (!_syn) + displayTextInVerbBar(getEngineString(S_HIDE_SELF)); + displayStatusArrow(); + if (!(_anyone) && !(_keyPressedEsc)) { + setCoordinates(10); + if (_num == 0) + _hiddenHero = false; + else { + _hiddenHero = true; + _crep = 999; + } + } +} + +/** + * Engine function - Attach + * @remarks Originally called 'tattacher' + */ +void MortevielleEngine::fctAttach() { + if (_coreVar._selectedObjectId == 0) + _crep = 186; + else { + if (!_syn) + displayTextInVerbBar(getEngineString(S_TIE)); + displayStatusArrow(); + if (!(_anyone) && !(_keyPressedEsc)) { + setCoordinates(8); + _crep = 997; + if ((_num != 0) && (_coreVar._currPlace == WELL)) { + _crep = 999; + if ((_coreVar._selectedObjectId == 120) || (_coreVar._selectedObjectId == 140)) { + _coreVar._wellObjectId = _coreVar._selectedObjectId; + displayAnimFrame(1, 1); + } else + _crep = 185; + displayEmptyHand(); + } + } + } +} + +/** + * Engine function - Close + * @remarks Originally called 'tfermer' + */ +void MortevielleEngine::fctClose() { + if (!_syn) + displayTextInVerbBar(getEngineString(S_CLOSE)); + + if (_caff < ROOM26) { + displayStatusArrow(); + if (_keyPressedEsc) + _crep = 998; + if ((_anyone) || (_keyPressedEsc)) + return; + setCoordinates(7); + if (_num != 0) { + int i; + for (i = 1; (i <= 6) && (_num != _openObjects[i]); ++i) + ; + if (_num == _openObjects[i]) { + displayAnimFrame(2, _num); + _crep = 998; + _openObjects[i] = 0; + --_openObjCount; + if (_openObjCount < 0) + _openObjCount = 0; + int objId = getFirstObject(); + if (_curSearchObjId == objId) + _curSearchObjId = 0; + } else { + _crep = 187; + } + } + } + if (_caff == ROOM26) + _crep = 999; +} + +/** + * Engine function - Knock + * @remarks Originally called 'tfrapper' + */ +void MortevielleEngine::fctKnock() { + if (!_syn) + displayTextInVerbBar(getEngineString(S_HIT)); + + if (_coreVar._currPlace == LANDING) { + _dialogManager.show(getEngineString(S_BEFORE_USE_DEP_MENU), 1); + return; + } + + if (_coreVar._currPlace < DOOR) { + displayStatusArrow(); + if (!(_anyone) && !(_keyPressedEsc)) { + if ((_coreVar._currPlace < MOUNTAIN) && (_coreVar._currPlace != LANDING)) + _crep = 133; + else + _crep = 997; + } + + return; + } + + if (_coreVar._currPlace == ROOM26) { + int rand = (getRandomNumber(0, 8)) - 4; + _soundManager.startSpeech(11, rand, 1); + int pres = getPresenceStats(rand, _coreVar._faithScore, _roomDoorId); + if (_roomDoorId != OWN_ROOM) { + if (pres != -500) { + if (rand > pres) + _crep = 190; + else { + setPresenceFlags(_roomDoorId); + getKnockAnswer(); + } + } else + getKnockAnswer(); + } + + if (_roomDoorId == GREEN_ROOM2) + _crep = 190; + } +} + +/** + * Engine function - Self / Put + * @remarks Originally called 'tposer' + */ +void MortevielleEngine::fctSelfPut() { + if (!_syn) + displayTextInVerbBar(getEngineString(S_POSE)); + if (_coreVar._selectedObjectId == 0) + _crep = 186; + else { + if (_caff > 99) { + _crep = 999; + putObject(); + if (_crep != 192) + displayEmptyHand(); + return; + } + displayStatusArrow(); + if ((_anyone) || (_keyPressedEsc)) + return; + setCoordinates(7); + _crep = 124; + if (_num != 0) { + int objId = getFirstObject(); + if (objId == 0) + _crep = 997; + else { + int i; + for (i = 1; (i <= 6) && (_num != _openObjects[i]); i++) + ; + if (_num == _openObjects[i]) { + _curSearchObjId = objId; + _crep = 999; + } else + _crep = 187; + } + } else { + setCoordinates(8); + if (_num != 0) { + _crep = 998; + if (_caff == PURPLE_ROOM) { + if (_coreVar._purpleRoomObjectId != 0) + _crep = 188; + else + _coreVar._purpleRoomObjectId = _coreVar._selectedObjectId; + } + + if (_caff == ATTIC) { + if (_num == 1) { + if (_coreVar._atticBallHoleObjectId != 0) + _crep = 188; + else + _coreVar._atticBallHoleObjectId = _coreVar._selectedObjectId; + } else if (_coreVar._atticRodHoleObjectId != 0) { + _crep = 188; + } else { + _coreVar._atticRodHoleObjectId = _coreVar._selectedObjectId; + } + } + + if (_caff == CRYPT) { + if (_coreVar._cryptObjectId != 0) + _crep = 188; + else + _coreVar._cryptObjectId = _coreVar._selectedObjectId; + } + + if (_caff == WELL) + _crep = 185; + if ((_caff == CELLAR) || (_caff == SECRET_PASSAGE)) + _crep = 124; + } else { + _crep = 124; + if (_caff == WELL) { + setCoordinates(5); + if (_num != 0) + _crep = 185; + } + } + } + if (_caff == INSIDE_WELL) + _crep = 185; + if ((_crep == 999) || (_crep == 185) || (_crep == 998)) { + if (_crep == 999) + putObject(); + if (_crep != 192) + displayEmptyHand(); + } + } +} + +/** + * Engine function - Listen + * @remarks Originally called 'tecouter' + */ +void MortevielleEngine::fctListen() { + if (_coreVar._currPlace != ROOM26) + _crep = 101; + else { + if (_currBitIndex != 0) + ++_coreVar._faithScore; + int rand; + int pres = getPresenceStats(rand, _coreVar._faithScore, _roomDoorId); + if (_roomDoorId != OWN_ROOM) { + if (pres != -500) { + if (rand > pres) + _crep = 101; + else { + setPresenceFlags(_roomDoorId); + int day, hour, minute; + updateHour(day, hour, minute); + rand = getRandomNumber(1, 100); + if ((hour >= 0) && (hour < 8)) { + if (rand > 30) + _crep = 101; + else + _crep = 178; + } else if (rand > 70) + _crep = 101; + else + _crep = 178; + } + } else + _crep = 178; + } + } +} + +/** + * Engine function - Eat + * @remarks Originally called 'tmanger' + */ +void MortevielleEngine::fctEat() { + if ((_coreVar._currPlace > LANDING) && (_coreVar._currPlace < ROOM26)) { + _crep = 148; + } else { + exitRoom(); + _coreVar._currPlace = DINING_ROOM; + _caff = DINING_ROOM; + resetRoomVariables(_coreVar._currPlace); + _menu.setDestinationText(_coreVar._currPlace); + + int day, hour, minute; + updateHour(day, hour, minute); + if ((hour == 12) || (hour == 13) || (hour == 19)) { + _coreVar._faithScore -= (_coreVar._faithScore / 7); + if (hour == 12) { + if (minute == 0) + hour = 4; + else + hour = 3; + } + + if ((hour == 13) || (hour == 19)) { + if (minute == 0) + hour = 2; + else + hour = 1; + } + + _currentHourCount += hour; + _crep = 135; + prepareRoom(); + } else { + _crep = 134; + } + } +} + +/** + * Engine function - Enter + * @remarks Originally called 'tentrer' + */ +void MortevielleEngine::fctEnter() { + if ((_coreVar._currPlace == MANOR_FRONT) || (_coreVar._currPlace == MANOR_BACK)) { + gotoDiningRoom(); + _menu.setDestinationText(_coreVar._currPlace); + } else if (_coreVar._currPlace == LANDING) + showMoveMenuAlert(); + else if (_roomDoorId == OWN_ROOM) + _crep = 997; + else if ((_roomDoorId == JULIA_ROOM) && (_coreVar._selectedObjectId != 136)) { + _crep = 189; + _coreVar._availableQuestion[8] = '*'; + } else { + int pres = 0; + if (!_blo) + pres = getPresence(_roomDoorId); + if (pres != 0) { + if ((_roomDoorId == TOILETS) || (_roomDoorId == BATHROOM)) + _crep = 179; + else { + int randVal = (getRandomNumber(0, 10)) - 5; + _soundManager.startSpeech(7, randVal, 1); + displayAnimFrame(1, 1); + _soundManager.waitSpeech(); + + int charIndex = convertBitIndexToCharacterIndex(pres); + ++_coreVar._faithScore; + _coreVar._currPlace = LANDING; + _currMenu = MENU_DISCUSS; + _currAction = (_menu._discussMenu[charIndex]._menuId << 8) | _menu._discussMenu[charIndex]._actionId; + _syn = true; + if (_roomDoorId == JULIA_ROOM) { + _col = true; + _caff = 70; + drawPictureWithText(); + handleDescriptionText(2, _caff); + } else + _col = false; + resetRoomVariables(_roomDoorId); + _roomDoorId = OWN_ROOM; + } + } else { + int randVal = (getRandomNumber(0, 10)) - 5; + _soundManager.startSpeech(7, randVal, 1); + displayAnimFrame(1, 1); + _soundManager.waitSpeech(); + + _coreVar._currPlace = _roomDoorId; + prepareDisplayText(); + resetRoomVariables(_coreVar._currPlace); + _menu.setDestinationText(_coreVar._currPlace); + _roomDoorId = OWN_ROOM; + _savedBitIndex = 0; + _currBitIndex = 0; + } + } +} + +/** + * Engine function - Sleep + * @remarks Originally called 'tdormir' + */ +void MortevielleEngine::fctSleep() { + if ((_coreVar._currPlace > LANDING) && (_coreVar._currPlace < ROOM26)) { + _crep = 148; + return; + } + if (_coreVar._currPlace != OWN_ROOM) { + exitRoom(); + _coreVar._currPlace = OWN_ROOM; + prepareDisplayText(); + drawPictureWithText(); + resetRoomVariables(_coreVar._currPlace); + _menu.setDestinationText(_coreVar._currPlace); + } + clearVerbBar(); + clearDescriptionBar(); + prepareScreenType2(); + displayTextBlock(getEngineString(S_WANT_TO_WAKE_UP)); + int day, hour, minute; + updateHour(day, hour, minute); + + int answer; + do { + if (hour < 8) { + _coreVar._faithScore -= (_coreVar._faithScore / 20); + int z = (7 - hour) * 2; + if (minute == 30) + --z; + _currentHourCount += z; + hour = 7; + } + _currentHourCount += 2; + ++hour; + if (hour > 23) + hour = 0; + prepareRoom(); + answer = _dialogManager.show(getEngineString(S_YES_NO), 1); + _anyone = false; + } while (answer != 1); + _crep = 998; + _num = 0; +} + +/** + * Engine function - Force + * @remarks Originally called 'tdefoncer' + */ +void MortevielleEngine::fctForce() { + if (!_syn) + displayTextInVerbBar(getEngineString(S_SMASH)); + if (_caff < DOOR) + displayStatusArrow(); + + if ((!_anyone) && (!_keyPressedEsc)) { + if (_coreVar._currPlace != ROOM26) + _crep = 997; + else { + _crep = 143; + _coreVar._faithScore += 2; + } + } +} + +/** + * Engine function - Leave + * @remarks Originally called 'tsortir' + */ +void MortevielleEngine::fctLeave() { + exitRoom(); + _crep = 0; + if ((_coreVar._currPlace == MOUNTAIN) || (_coreVar._currPlace == MANOR_FRONT) || (_coreVar._currPlace == MANOR_BACK) || (_coreVar._currPlace == WELL)) + _crep = 997; + else { + int nextPlace = OWN_ROOM; + + if ((_coreVar._currPlace < CRYPT) || (_coreVar._currPlace == ROOM26)) + nextPlace = DINING_ROOM; + else if ((_coreVar._currPlace == DINING_ROOM) || (_coreVar._currPlace == CHAPEL)) + nextPlace = MANOR_FRONT; + else if ((_coreVar._currPlace < DINING_ROOM) || (_coreVar._currPlace == ATTIC)) + nextPlace = LANDING; + else if (_coreVar._currPlace == CRYPT) { + nextPlace = SECRET_PASSAGE; + _crep = 176; + } else if (_coreVar._currPlace == SECRET_PASSAGE) + nextPlace = checkLeaveSecretPassage(); + else if (_coreVar._currPlace == INSIDE_WELL) + nextPlace = WELL; + + if (_crep != 997) + _coreVar._currPlace = nextPlace; + + _caff = nextPlace; + if (_crep == 0) + _crep = nextPlace; + resetRoomVariables(nextPlace); + _menu.setDestinationText(nextPlace); + } +} + +/** + * Engine function - Wait + * @remarks Originally called 'tattendre' + */ +void MortevielleEngine::fctWait() { + _savedBitIndex = 0; + clearVerbBar(); + + int answer; + do { + ++_currentHourCount; + prepareRoom(); + if (!_blo) + getPresence(_coreVar._currPlace); + if ((_currBitIndex != 0) && (_savedBitIndex == 0)) { + _crep = 998; + if ((_coreVar._currPlace == ATTIC) || (_coreVar._currPlace == CELLAR)) + initCaveOrCellar(); + if ((_coreVar._currPlace > OWN_ROOM) && (_coreVar._currPlace < DINING_ROOM)) + _anyone = true; + _savedBitIndex = _currBitIndex; + if (!_anyone) + prepareRoom(); + return; + } + handleDescriptionText(2, 102); + answer = _dialogManager.show(getEngineString(S_YES_NO), 1); + } while (answer != 2); + _crep = 998; + if (!_anyone) + prepareRoom(); +} + +/** + * Engine function - Sound + * @remarks Originally called 'tsonder' + */ +void MortevielleEngine::fctSound() { + if (!_syn) + displayTextInVerbBar(getEngineString(S_PROBE2)); + if (_caff < 27) { + displayStatusArrow(); + if (!(_anyone) && (!_keyPressedEsc)) + _crep = 145; + _num = 0; + } +} + +/** + * Engine function - Discuss + * @remarks Originally called 'tparler' + */ +void MortevielleEngine::fctDiscuss() { + bool questionAsked[47]; + int cy, cx; + int x, y; + Common::String lib[47]; + + int choice; + int displId; + + endSearch(); + if (_col) + displId = 128; + else { + cx = 0; + int oldMenu; + do { + ++cx; + oldMenu = (_menu._discussMenu[cx]._menuId << 8) | _menu._discussMenu[cx]._actionId; + } while (oldMenu != _currAction); + _caff = 69 + cx; + drawPictureWithText(); + handleDescriptionText(2, _caff); + displId = _caff + 60; + } + testKey(false); + menuUp(); + _mouse.hideMouse(); + clearScreen(); + drawDiscussionBox(); + startDialog(displId); + clearScreen(); + for (int ix = 1; ix <= 46; ++ix) + questionAsked[ix] = false; + for (int ix = 1; ix <= 45; ++ix) { + lib[ix] = getString(ix + kQuestionStringIndex); + for (int i = lib[ix].size(); i <= 40; ++i) + lib[ix] = lib[ix] + ' '; + } + lib[46] = lib[45]; + lib[45] = ' '; + _mouse.showMouse(); + do { + choice = 0; + int posX = 0; + int posY = 0; + for (int icm = 1; icm < 43; icm++) { + _screenSurface.putxy(posX, posY); + if (_coreVar._availableQuestion[icm] == '*') { + // If question already asked, write it in reverse video + if (questionAsked[icm]) + displayQuestionText(lib[icm], 1); + else + displayQuestionText(lib[icm], 0); + } + + if (icm == 23) { + posY = 0; + posX = 320; + } else + posY += 8; + } + _screenSurface.putxy(320, 176); + displayQuestionText(lib[46], 0); + char retKey = '\0'; + bool click; + do { + bool dummyFl; + _mouse.moveMouse(dummyFl, retKey); + if (shouldQuit()) + return; + + _mouse.getMousePosition(x, y, click); + x *= (3 - kResolutionScaler); + if (x > 319) + cx = 41; + else + cx = 1; + cy = ((uint)y >> 3) + 1; // 0-199 => 1-25 + if ((cy > 23) || ((cx == 41) && ((cy >= 20) && (cy <= 22)))) { + if (choice != 0) { + posY = ((choice - 1) % 23) << 3; + if (choice > 23) + posX = 320; + else + posX = 0; + _screenSurface.putxy(posX, posY); + if (questionAsked[choice]) + displayQuestionText(lib[choice], 0); + else + displayQuestionText(lib[choice], 1); + questionAsked[choice] = !questionAsked[choice]; + choice = 0; + } + } else { + int ix = cy; + if (cx == 41) + ix += 23; + if (ix != choice) { + if (choice != 0) { + posY = ((choice - 1) % 23) << 3; + if (choice > 23) + posX = 320; + else + posX = 0; + _screenSurface.putxy(posX, posY); + if (questionAsked[choice]) + displayQuestionText(lib[choice], 0); + else + displayQuestionText(lib[choice], 1); + questionAsked[choice] = ! questionAsked[choice]; + } + if ((ix == 46) || (_coreVar._availableQuestion[ix] == '*')) { + posY = ((ix - 1) % 23) << 3; + if (ix > 23) + posX = 320; + else + posX = 0; + _screenSurface.putxy(posX, posY); + if (questionAsked[ix]) + displayQuestionText(lib[ix], 0); + else + displayQuestionText(lib[ix], 1); + questionAsked[ix] = ! questionAsked[ix]; + choice = ix; + } else + choice = 0; + } + } + } while (!((retKey == '\15') || (((click != 0) || getMouseClick()) && (choice != 0)))); + setMouseClick(false); + + // If choice is not "End of Conversation" + if (choice != 46) { + int ix = choice - 1; + if (_col) { + _col = false; + _coreVar._currPlace = 15; + int maxRandVal; + if (_openObjCount > 0) + maxRandVal = 8; + else + maxRandVal = 4; + if (getRandomNumber(1, maxRandVal) == 2) + displId = 129; + else { + displId = 138; + _coreVar._faithScore += (3 * (_coreVar._faithScore / 10)); + } + } else if (_charAnswerCount[_caff - 69] < _charAnswerMax[_caff - 69]) { + displId = _tabdon[kArep + (ix << 3) + (_caff - 70)]; + _coreVar._faithScore += _tabdon[kArcf + ix]; + ++_charAnswerCount[_caff - 69]; + } else { + _coreVar._faithScore += 3; + displId = 139; + } + _mouse.hideMouse(); + clearScreen(); + drawDiscussionBox(); + startDialog(displId); + _mouse.showMouse(); + if ((displId == 84) || (displId == 86)) { + _coreVar._pctHintFound[5] = '*'; + _coreVar._availableQuestion[7] = '*'; + } + if ((displId == 106) || (displId == 108) || (displId == 94)) { + for (int indx = 29; indx <= 31; ++indx) + _coreVar._availableQuestion[indx] = '*'; + _coreVar._pctHintFound[7] = '*'; + } + if (displId == 70) { + _coreVar._pctHintFound[8] = '*'; + _coreVar._availableQuestion[32] = '*'; + } + _mouse.hideMouse(); + clearScreen(); + _mouse.showMouse(); + } + } while ((choice != 46) && (displId != 138)); + if (_col) { + _coreVar._faithScore += (3 * (_coreVar._faithScore / 10)); + _mouse.hideMouse(); + clearScreen(); + drawDiscussionBox(); + startDialog(138); + _mouse.showMouse(); + _col = false; + _coreVar._currPlace = LANDING; + } + _controlMenu = 0; + _mouse.hideMouse(); + clearScreen(); + drawRightFrame(); + _mouse.showMouse(); + showPeoplePresent(_currBitIndex); + prepareRoom(); + drawClock(); + prepareDisplayText(); + /* chech;*/ + _menu.setDestinationText(_coreVar._currPlace); + clearVerbBar(); +} + +/** + * Engine function - Smell + * @remarks Originally called 'tsentir' + */ +void MortevielleEngine::fctSmell() { + _crep = 119; + if (_caff < ROOM26) { + if (!_syn) + displayTextInVerbBar(getEngineString(S_SMELL)); + displayStatusArrow(); + if (!(_anyone) && !(_keyPressedEsc)) + if (_caff == CRYPT) + _crep = 153; + } else if (_caff == 123) + _crep = 110; + _num = 0; +} + +/** + * Engine function - Scratch + * @remarks Originally called 'tgratter' + */ +void MortevielleEngine::fctScratch() { + _crep = 155; + if (_caff < 27) { + if (!_syn) + displayTextInVerbBar(getEngineString(S_SCRATCH)); + displayStatusArrow(); + } + _num = 0; +} + +/** + * The game is over + * @remarks Originally called 'tmaj1' + */ +void MortevielleEngine::endGame() { + _quitGame = true; + displayNarrativePicture(13, 152); + displayEmptyHand(); + clearUpperLeftPart(); + clearDescriptionBar(); + clearVerbBar(); + handleDescriptionText(9, 1509); + testKey(false); + _mouse.hideMouse(); + _caff = 70; + _text.taffich(); + clearScreen(); + drawDiscussionBox(); + startDialog(141); + _mouse.showMouse(); + clearUpperLeftPart(); + handleDescriptionText(9, 1509); + handleDescriptionText(2, 142); + testKey(false); + _caff = 32; + drawPictureWithText(); + handleDescriptionText(6, 34); + handleDescriptionText(2, 35); + startMusicOrSpeech(0); + testKey(false); + // A wait message was displayed. + // testKey (aka tkey1) was called before and after. + // This double call is useless, thus removed + resetVariables(); +} + +/** + * You lost! + * @remarks Originally called 'tencore' + */ +void MortevielleEngine::askRestart() { + clearDescriptionBar(); + startMusicOrSpeech(0); + testKey(false); + displayEmptyHand(); + resetVariables(); + initGame(); + _currHour = 10; + _currHalfHour = 0; + _currDay = 0; + _minute = 0; + _hour = 10; + _day = 0; + handleDescriptionText(2, 180); + + int answer = _dialogManager.show(getEngineString(S_YES_NO), 1); + _quitGame = (answer != 1); +} + +} // End of namespace Mortevielle diff --git a/engines/mortevielle/debugger.cpp b/engines/mortevielle/debugger.cpp new file mode 100644 index 0000000000..4ef5151c81 --- /dev/null +++ b/engines/mortevielle/debugger.cpp @@ -0,0 +1,59 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "mortevielle/mortevielle.h" +#include "mortevielle/debugger.h" + +namespace Mortevielle { + +Debugger::Debugger() : GUI::Debugger() { + DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit)); + DCmd_Register("show_questions", WRAP_METHOD(Debugger, Cmd_showAllQuestions)); + DCmd_Register("reset_parano", WRAP_METHOD(Debugger, Cmd_resetParano)); +} + +bool Debugger::Cmd_showAllQuestions(int argc, const char **argv) { + for (int i = 1; i <= 10; ++i) + _vm->_coreVar._pctHintFound[i] = '*'; + + for (int i = 1; i <= 42; ++i) + _vm->_coreVar._availableQuestion[i] = '*'; + + for (int i = 0; i < 9; i++) { + _vm->_charAnswerCount[i] = 0; + _vm->_charAnswerMax[i] = 999; + } + + return true; +} + +bool Debugger::Cmd_resetParano(int argc, const char **argv) { + _vm->_coreVar._faithScore = 0; + + return true; +} + +void Debugger::setParent(MortevielleEngine *vm) { + _vm = vm; +} + +} // End of namespace Mortevielle diff --git a/backends/platform/bada/application.h b/engines/mortevielle/debugger.h index 2b0d37f1ef..9041d90110 100644 --- a/backends/platform/bada/application.h +++ b/engines/mortevielle/debugger.h @@ -8,47 +8,42 @@ * 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 BADA_APPLICATION_H -#define BADA_APPLICATION_H +#ifndef MORTEVIELLE_DEBUGGER_H +#define MORTEVIELLE_DEBUGGER_H -#include <FBase.h> -#include <FApp.h> -#include <FGraphics.h> -#include <FUi.h> -#include <FSystem.h> +#include "common/scummsys.h" +#include "gui/debugger.h" -#include "backends/platform/bada/system.h" +namespace Mortevielle { -class BadaScummVM : public Osp::App::Application { -public: - BadaScummVM(); - ~BadaScummVM(); +class MortevielleEngine; - static Osp::App::Application *createInstance(void); +class Debugger : public GUI::Debugger { +private: + MortevielleEngine *_vm; - bool OnAppInitializing(Osp::App::AppRegistry &appRegistry); - bool OnAppTerminating(Osp::App::AppRegistry &appRegistry, bool forcedTermination = false); - void OnForeground(void); - void OnBackground(void); - void OnLowMemory(void); - void OnBatteryLevelChanged(Osp::System::BatteryLevel batteryLevel); - void OnUserEventReceivedN(RequestId requestId, Osp::Base::Collection::IList *pArgs); +protected: + bool Cmd_showAllQuestions(int argc, const char **argv); + bool Cmd_resetParano(int argc, const char **argv); -private: - void pauseGame(bool pause); - BadaAppForm *_appForm; +public: + Debugger(); + virtual ~Debugger() {} + void setParent(MortevielleEngine *vm); }; +} // End of namespace Mortevielle + #endif diff --git a/engines/mortevielle/detection.cpp b/engines/mortevielle/detection.cpp new file mode 100644 index 0000000000..8e2eab52b8 --- /dev/null +++ b/engines/mortevielle/detection.cpp @@ -0,0 +1,109 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "base/plugins.h" +#include "engines/advancedDetector.h" + +#include "mortevielle/mortevielle.h" +#include "mortevielle/saveload.h" + +namespace Mortevielle { +struct MortevielleGameDescription { + ADGameDescription desc; + Common::Language originalLanguage; +}; + +uint32 MortevielleEngine::getGameFlags() const { return _gameDescription->desc.flags; } + +Common::Language MortevielleEngine::getLanguage() const { return _gameDescription->desc.language; } + +Common::Language MortevielleEngine::getOriginalLanguage() const { return _gameDescription->originalLanguage; } + +} + +static const PlainGameDescriptor MortevielleGame[] = { + {"mortevielle", "Mortville Manor"}, + {0, 0} +}; + +#include "mortevielle/detection_tables.h" + +class MortevielleMetaEngine : public AdvancedMetaEngine { +public: + MortevielleMetaEngine() : AdvancedMetaEngine(Mortevielle::MortevielleGameDescriptions, sizeof(Mortevielle::MortevielleGameDescription), + MortevielleGame) { + _md5Bytes = 512; + _singleid = "mortevielle"; + } + virtual const char *getName() const { + return "Mortevielle"; + } + + virtual const char *getOriginalCopyright() const { + return "Mortville Manor (C) 1987-89 Lankhor"; + } + + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; + virtual bool hasFeature(MetaEngineFeature f) const; + virtual int getMaximumSaveSlot() const; + virtual SaveStateList listSaves(const char *target) const; + virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; +}; + +bool MortevielleMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + if (desc) { + *engine = new Mortevielle::MortevielleEngine(syst, (const Mortevielle::MortevielleGameDescription *)desc); + } + return desc != 0; +} + +bool MortevielleMetaEngine::hasFeature(MetaEngineFeature f) const { + switch (f) { + case kSupportsListSaves: + case kSupportsDeleteSave: + case kSupportsLoadingDuringStartup: + case kSavesSupportMetaInfo: + case kSavesSupportThumbnail: + case kSavesSupportCreationDate: + return true; + default: + return false; + } +} + +int MortevielleMetaEngine::getMaximumSaveSlot() const { return 99; } + +SaveStateList MortevielleMetaEngine::listSaves(const char *target) const { + return Mortevielle::SavegameManager::listSaves(target); +} + +SaveStateDescriptor MortevielleMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + Common::String filename = Mortevielle::MortevielleEngine::generateSaveFilename(target, slot); + return Mortevielle::SavegameManager::querySaveMetaInfos(filename); +} + + +#if PLUGIN_ENABLED_DYNAMIC(MORTEVIELLE) + REGISTER_PLUGIN_DYNAMIC(MORTEVIELLE, PLUGIN_TYPE_ENGINE, MortevielleMetaEngine); +#else + REGISTER_PLUGIN_STATIC(MORTEVIELLE, PLUGIN_TYPE_ENGINE, MortevielleMetaEngine); +#endif diff --git a/engines/mortevielle/detection_tables.h b/engines/mortevielle/detection_tables.h new file mode 100644 index 0000000000..9bb5fbea87 --- /dev/null +++ b/engines/mortevielle/detection_tables.h @@ -0,0 +1,99 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +namespace Mortevielle { + +static const MortevielleGameDescription MortevielleGameDescriptions[] = { + // French + { + { + "mortevielle", + "", + { + {"menufr.mor", 0, "e413f36b9e14eef16130adc347a9391f", 144}, + {"dxx.mor", 0, "949e68e829ecd5ad29e36a00347a9e7e", 207744}, + AD_LISTEND + }, + Common::FR_FRA, + Common::kPlatformDOS, + ADGF_NO_FLAGS, + GUIO0() + }, Common::FR_FRA + }, + // German + { + { + "mortevielle", + "", + { + {"menual.mor", 0, "792aea282b07a1d74c4a4abeabc90c19", 144}, + {"dxx.mor", 0, "949e68e829ecd5ad29e36a00347a9e7e", 207744}, + AD_LISTEND + }, + Common::DE_DEU, + Common::kPlatformDOS, + ADGF_NO_FLAGS, + GUIO0() + }, Common::DE_DEU + }, + + // DOS English version doesn't exist. Technically, they are French or German versions, + // using English strings stored mort.dat + + // English on top of French version + { + { + "mortevielle", + "", + { + {"menufr.mor", 0, "e413f36b9e14eef16130adc347a9391f", 144}, + {"dxx.mor", 0, "949e68e829ecd5ad29e36a00347a9e7e", 207744}, + AD_LISTEND + }, + Common::EN_ANY, + Common::kPlatformDOS, + ADGF_NO_FLAGS, + GUIO0() + }, Common::FR_FRA + }, + + // English on top of German version + { + { + "mortevielle", + "", + { + {"menual.mor", 0, "792aea282b07a1d74c4a4abeabc90c19", 144}, + {"dxx.mor", 0, "949e68e829ecd5ad29e36a00347a9e7e", 207744}, + AD_LISTEND + }, + Common::EN_ANY, + Common::kPlatformDOS, + ADGF_NO_FLAGS, + GUIO0() + }, Common::DE_DEU + }, + + { AD_TABLE_END_MARKER , Common::EN_ANY} +}; + +} // End of namespace Mortevielle diff --git a/engines/mortevielle/dialogs.cpp b/engines/mortevielle/dialogs.cpp new file mode 100644 index 0000000000..a7bd381603 --- /dev/null +++ b/engines/mortevielle/dialogs.cpp @@ -0,0 +1,472 @@ +/* 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#include "mortevielle/mortevielle.h" + +#include "mortevielle/dialogs.h" +#include "mortevielle/mouse.h" +#include "mortevielle/outtext.h" + +#include "common/str.h" + +namespace Mortevielle { + +/** + * Alert function - Show + * @remarks Originally called 'do_alert' + */ +int DialogManager::show(const Common::String &msg, int n) { + // Make a copy of the current screen surface for later restore + _vm->_backgroundSurface.copyFrom(_vm->_screenSurface); + + _vm->_mouse.hideMouse(); + while (_vm->keyPressed()) + _vm->getChar(); + + _vm->setMouseClick(false); + + int colNumb = 0; + int lignNumb = 0; + int caseNumb = 0; + Common::String alertStr = ""; + Common::String caseStr; + + decodeAlertDetails(msg, caseNumb, lignNumb, colNumb, alertStr, caseStr); + + Common::Point curPos; + if (alertStr == "") { + drawAlertBox(10, 5, colNumb); + } else { + drawAlertBox(8, 7, colNumb); + int i = 0; + _vm->_screenSurface._textPos.y = 70; + do { + curPos.x = 320; + Common::String displayStr = ""; + while ((alertStr[i + 1] != '\174') && (alertStr[i + 1] != '\135')) { + ++i; + displayStr += alertStr[i]; + curPos.x -= 3; + } + _vm->_screenSurface.putxy(curPos.x, _vm->_screenSurface._textPos.y); + _vm->_screenSurface._textPos.y += 6; + _vm->_screenSurface.drawString(displayStr, 4); + ++i; + } while (alertStr[i] != ']'); + } + int esp; + if (caseNumb == 1) + esp = colNumb - 40; + else + esp = (uint)(colNumb - caseNumb * 40) / 2; + + int coldep = 320 - ((uint)colNumb / 2) + ((uint)esp / 2); + Common::String buttonStr[3]; + setButtonText(caseStr, coldep, caseNumb, &buttonStr[0], esp); + + int limit[3][3]; + memset(&limit[0][0], 0, sizeof(int) * 3 * 3); + + limit[1][1] = ((uint)(coldep) / 2) * kResolutionScaler; + limit[1][2] = limit[1][1] + 40; + if (caseNumb == 1) { + limit[2][1] = limit[2][2]; + } else { + limit[2][1] = ((uint)(320 + ((uint)esp >> 1)) / 2) * kResolutionScaler; + limit[2][2] = (limit[2][1]) + 40; + } + _vm->_mouse.showMouse(); + int id = 0; + bool dummyFl = false; + bool test3; + do { + char dummyKey = '\377'; + _vm->_mouse.moveMouse(dummyFl, dummyKey); + if (_vm->shouldQuit()) + return 0; + + curPos = _vm->_mouse._pos; + bool newaff = false; + if ((curPos.y > 95) && (curPos.y < 105)) { + bool test1 = (curPos.x > limit[1][1]) && (curPos.x < limit[1][2]); + bool test2 = test1; + if (caseNumb > 1) + test2 |= ((curPos.x > limit[2][1]) && (curPos.x < limit[2][2])); + if (test2) { + newaff = true; + + int ix; + if (test1) + ix = 1; + else + ix = 2; + if (ix != id) { + _vm->_mouse.hideMouse(); + if (id != 0) { + setPosition(id, coldep, esp); + + Common::String tmpStr(" "); + tmpStr += buttonStr[id]; + tmpStr += " "; + _vm->_screenSurface.drawString(tmpStr, 0); + } + setPosition(ix, coldep, esp); + + Common::String tmp2 = " "; + tmp2 += buttonStr[ix]; + tmp2 += " "; + _vm->_screenSurface.drawString(tmp2, 1); + + id = ix; + _vm->_mouse.showMouse(); + } + } + } + if ((id != 0) && !newaff) { + _vm->_mouse.hideMouse(); + setPosition(id, coldep, esp); + + Common::String tmp3(" "); + tmp3 += buttonStr[id]; + tmp3 += " "; + _vm->_screenSurface.drawString(tmp3, 0); + + id = 0; + _vm->_mouse.showMouse(); + } + test3 = (curPos.y > 95) && (curPos.y < 105) && (((curPos.x > limit[1][1]) && (curPos.x < limit[1][2])) + || ((curPos.x > limit[2][1]) && (curPos.x < limit[2][2]))); + } while (!_vm->getMouseClick()); + _vm->setMouseClick(false); + _vm->_mouse.hideMouse(); + if (!test3) { + id = n; + setPosition(n, coldep, esp); + Common::String tmp4(" "); + tmp4 += buttonStr[n]; + tmp4 += " "; + _vm->_screenSurface.drawString(tmp4, 1); + } + _vm->_mouse.showMouse(); + + /* Restore the background area */ + _vm->_screenSurface.copyFrom(_vm->_backgroundSurface, 0, 0); + + return id; +} + +/** + * Alert function - Decode Alert Details + * @remarks Originally called 'decod' + */ +void DialogManager::decodeAlertDetails(Common::String inputStr, int &choiceNumb, int &lineNumb, int &col, Common::String &choiceStr, Common::String &choiceListStr) { + // The second character of the string contains the number of choices + choiceNumb = atoi(inputStr.c_str() + 1); + + choiceStr = ""; + col = 0; + lineNumb = 0; + + // Originally set to 5, decreased to 4 because strings are 0 based, and not 1 based as in Pascal + int i = 4; + int k = 0; + bool empty = true; + + for (; inputStr[i] != ']'; ++i) { + choiceStr += inputStr[i]; + if ((inputStr[i] == '|') || (inputStr[i + 1] == ']')) { + if (k > col) + col = k; + k = 0; + ++lineNumb; + } else if (inputStr[i] != ' ') + empty = false; + ++k; + } + + if (empty) { + choiceStr = ""; + col = 20; + } else { + choiceStr += ']'; + col += 6; + } + + choiceListStr = Common::String(inputStr.c_str() + i); + col *= 6; +} + +void DialogManager::setPosition(int ji, int coldep, int esp) { + _vm->_screenSurface.putxy(coldep + (40 + esp) * (ji - 1), 98); +} + +/** + * Alert function - Draw Alert Box + * @remarks Originally called 'fait_boite' + */ +void DialogManager::drawAlertBox(int firstLine, int lineNum, int width) { + if (width > 640) + width = 640; + int x = 320 - ((uint)width / 2); + int y = (firstLine - 1) * 8; + int xx = x + width; + int yy = y + (lineNum * 8); + _vm->_screenSurface.fillRect(15, Common::Rect(x, y, xx, yy)); + _vm->_screenSurface.fillRect(0, Common::Rect(x, y + 2, xx, y + 4)); + _vm->_screenSurface.fillRect(0, Common::Rect(x, yy - 4, xx, yy - 2)); +} + +/** + * Alert function - Set Button Text + * @remarks Originally called 'fait_choix' + */ +void DialogManager::setButtonText(Common::String c, int coldep, int nbcase, Common::String *str, int esp) { + int i = 1; + int x = coldep; + for (int l = 1; l <= nbcase; ++l) { + str[l] = ""; + do { + ++i; + char ch = c[i]; + str[l] += ch; + } while (c[i + 1] != ']'); + i += 2; + + while (str[l].size() < 3) + str[l] += ' '; + + _vm->_screenSurface.putxy(x, 98); + + Common::String tmp(" "); + tmp += str[l]; + tmp += " "; + + _vm->_screenSurface.drawString(tmp, 0); + x += esp + 40; + } +} + +/*------------------------------------------------------------------------*/ + +/** + * Questions asked before entering the hidden passage + */ +bool DialogManager::showKnowledgeCheck() { + const int textIndexArr[10] = {511, 516, 524, 531, 545, 552, 559, 563, 570, 576}; + const int correctAnswerArr[10] = {4, 7, 1, 6, 4, 4, 2, 5, 3, 1 }; + + Hotspot coor[kMaxHotspots+1]; + + for (int i = 0; i <= kMaxHotspots; ++i) { + coor[i]._rect = Common::Rect(); + coor[i]._enabled = false; + } + + Common::String choiceArray[15]; + + int currChoice, prevChoice; + int correctCount = 0; + + for (int indx = 0; indx < 10; ++indx) { + _vm->_mouse.hideMouse(); + _vm->clearScreen(); + _vm->_mouse.showMouse(); + int dialogHeight = 23; + _vm->_screenSurface.fillRect(15, Common::Rect(0, 14, 630, dialogHeight)); + Common::String tmpStr = _vm->getString(textIndexArr[indx]); + _vm->_text.displayStr(tmpStr, 20, 15, 100, 2, 0); + + int firstOption; + int lastOption; + + if (indx != 9) { + firstOption = textIndexArr[indx] + 1; + lastOption = textIndexArr[indx + 1] - 1; + } else { + firstOption = 503; + lastOption = 510; + } + int optionPosY = 35; + int maxLength = 0; + + prevChoice = 1; + for (int j = firstOption; j <= lastOption; ++j, ++prevChoice) { + tmpStr = _vm->getString(j); + if ((int) tmpStr.size() > maxLength) + maxLength = tmpStr.size(); + _vm->_text.displayStr(tmpStr, 100, optionPosY, 100, 1, 0); + choiceArray[prevChoice] = tmpStr; + optionPosY += 8; + } + + for (int j = 1; j <= lastOption - firstOption + 1; ++j) { + coor[j]._rect = Common::Rect(45 * kResolutionScaler, 27 + j * 8, (maxLength * 3 + 55) * kResolutionScaler, 34 + j * 8); + coor[j]._enabled = true; + + while ((int)choiceArray[j].size() < maxLength) { + choiceArray[j] += ' '; + } + } + coor[lastOption - firstOption + 2]._enabled = false; + int rep = 6; + _vm->_screenSurface.drawBox(80, 33, 40 + (maxLength * rep), (lastOption - firstOption) * 8 + 16, 15); + rep = 0; + + prevChoice = 0; + warning("Expected answer: %d", correctAnswerArr[indx]); + do { + _vm->setMouseClick(false); + bool flag; + char key; + _vm->_mouse.moveMouse(flag, key); + if (_vm->shouldQuit()) + return false; + + currChoice = 1; + while (coor[currChoice]._enabled && !_vm->_mouse.isMouseIn(coor[currChoice]._rect)) + ++currChoice; + if (coor[currChoice]._enabled) { + if ((prevChoice != 0) && (prevChoice != currChoice)) { + tmpStr = choiceArray[prevChoice] + '$'; + _vm->_text.displayStr(tmpStr, 100, 27 + (prevChoice * 8), 100, 1, 0); + } + if (prevChoice != currChoice) { + tmpStr = choiceArray[currChoice] + '$'; + _vm->_text.displayStr(tmpStr, 100, 27 + (currChoice * 8), 100, 1, 1); + prevChoice = currChoice; + } + } else if (prevChoice != 0) { + tmpStr = choiceArray[prevChoice] + '$'; + _vm->_text.displayStr(tmpStr, 100, 27 + (prevChoice * 8), 100, 1, 0); + prevChoice = 0; + } + } while (!((prevChoice != 0) && _vm->getMouseClick())); + + if (prevChoice == correctAnswerArr[indx]) + // Answer is correct + ++correctCount; + else { + // Skip questions that may give hints on previous wrong answer + if (indx == 4) + ++indx; + else if ((indx == 6) || (indx == 7)) + indx = 9; + } + } + + return (correctCount == 10); +} + +/*------------------------------------------------------------------------*/ + +/** + * Draw the F3/F8 dialog + */ +void DialogManager::drawF3F8() { + Common::String f3 = _vm->getEngineString(S_F3); + Common::String f8 = _vm->getEngineString(S_F8); + + // Write the F3 and F8 text strings + _vm->_screenSurface.putxy(3, 44); + _vm->_screenSurface.drawString(f3, 5); + _vm->_screenSurface._textPos.y = 51; + _vm->_screenSurface.drawString(f8, 5); + + // Get the width of the written text strings + int f3Width = _vm->_screenSurface.getStringWidth(f3); + int f8Width = _vm->_screenSurface.getStringWidth(f8); + + // Write out the bounding box + _vm->_screenSurface.drawBox(0, 42, MAX(f3Width, f8Width) + 6, 18, 7); +} + +/** + * Alert function - Loop until F8 is pressed, update + * Graphical Device if modified + * @remarks Originally called 'diver' + */ +void DialogManager::checkForF8(int SpeechNum, bool drawFrame2Fl) { + _vm->testKeyboard(); + do { + _vm->_soundManager.startSpeech(SpeechNum, 0, 0); + _vm->_key = waitForF3F8(); + if (_vm->shouldQuit()) + return; + } while (_vm->_key != 66); // keycode for F8 +} + +/** + * Alert function - Loop until F3 or F8 is pressed + * @remarks Originally called 'atf3f8' + */ +int DialogManager::waitForF3F8() { + int key; + + do { + key = _vm->gettKeyPressed(); + if (_vm->shouldQuit()) + return key; + } while ((key != 61) && (key != 66)); + + return key; +} + +/** + * Intro function - display intro screen + * @remarks Originally called 'aff50' + */ +void DialogManager::displayIntroScreen(bool drawFrame2Fl) { + _vm->_caff = 50; + _vm->_maff = 0; + _vm->_text.taffich(); + _vm->draw(63, 12); + if (drawFrame2Fl) + displayIntroFrame2(); + else + _vm->handleDescriptionText(2, kDialogStringIndex + 142); + + // Draw the f3/f8 dialog + drawF3F8(); +} + +/** + * Intro function - display 2nd frame of intro + * @remarks Originally called 'ani50' + */ +void DialogManager::displayIntroFrame2() { + _vm->_crep = _vm->getAnimOffset(1, 1); + _vm->displayPicture(&_vm->_curAnim[_vm->_crep], 63, 12); + _vm->_crep = _vm->getAnimOffset(2, 1); + _vm->displayPicture(&_vm->_curAnim[_vm->_crep], 63, 12); + _vm->_largestClearScreen = false; + _vm->handleDescriptionText(2, kDialogStringIndex + 143); +} + +void DialogManager::setParent(MortevielleEngine *vm) { + _vm = vm; +} +} // End of namespace Mortevielle diff --git a/engines/mortevielle/dialogs.h b/engines/mortevielle/dialogs.h new file mode 100644 index 0000000000..ee210a62b2 --- /dev/null +++ b/engines/mortevielle/dialogs.h @@ -0,0 +1,65 @@ +/* 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#ifndef MORTEVIELLE_ALERT_H +#define MORTEVIELLE_ALERT_H + +#include "common/rect.h" +#include "common/str.h" + +namespace Mortevielle { +class MortevielleEngine; + +static const int NUM_LINES = 7; +const int kMaxHotspots = 14; + +struct Hotspot { + Common::Rect _rect; + bool _enabled; +}; + +class DialogManager { +private: + MortevielleEngine *_vm; + + void decodeAlertDetails(Common::String inputStr, int &choiceNumb, int &lineNumb, int &col, Common::String &choiceStr, Common::String &choiceListStr); + void setPosition(int ji, int coldep, int esp); + void drawAlertBox(int firstLine, int lineNum, int width); + void setButtonText(Common::String c, int coldep, int nbcase, Common::String *str, int esp); +public: + void setParent(MortevielleEngine *vm); + int show(const Common::String &msg, int n); + void drawF3F8(); + void checkForF8(int SpeechNum, bool drawFrame2Fl); + int waitForF3F8(); + void displayIntroScreen(bool drawFrame2Fl); + void displayIntroFrame2(); + bool showKnowledgeCheck(); +}; + +} // End of namespace Mortevielle +#endif diff --git a/engines/mortevielle/graphics.cpp b/engines/mortevielle/graphics.cpp new file mode 100644 index 0000000000..daf7926438 --- /dev/null +++ b/engines/mortevielle/graphics.cpp @@ -0,0 +1,1167 @@ +/* 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#include "mortevielle/mortevielle.h" +#include "mortevielle/graphics.h" +#include "mortevielle/mouse.h" + +#include "common/endian.h" +#include "common/system.h" +#include "graphics/palette.h" + +namespace Mortevielle { + +/*-------------------------------------------------------------------------* + * Palette Manager + * + *-------------------------------------------------------------------------*/ + +/** + * Set palette entries from the 64 color available EGA palette + */ +void PaletteManager::setPalette(const int *palette, uint idx, uint size) { + assert((idx + size) <= 16); + + // Build up the EGA palette + byte egaPalette[64 * 3]; + + byte *p = &egaPalette[0]; + for (int i = 0; i < 64; ++i) { + *p++ = (i >> 2 & 1) * 0xaa + (i >> 5 & 1) * 0x55; + *p++ = (i >> 1 & 1) * 0xaa + (i >> 4 & 1) * 0x55; + *p++ = (i & 1) * 0xaa + (i >> 3 & 1) * 0x55; + } + + // Loop through setting palette colors based on the passed indexes + for (; size > 0; --size, ++idx) { + int palIndex = palette[idx]; + assert(palIndex < 64); + + const byte *pRgb = (const byte *)&egaPalette[palIndex * 3]; + g_system->getPaletteManager()->setPalette(pRgb, idx, 1); + } +} + +/** + * Set the default EGA palette + */ +void PaletteManager::setDefaultPalette() { + const int defaultPalette[16] = { 0, 1, 2, 3, 4, 5, 20, 7, 56, 57, 58, 59, 60, 61, 62, 63 }; + setPalette(defaultPalette, 0, 16); +} + +/*-------------------------------------------------------------------------* + * Image decoding + * + * The code in this section is responsible for decoding image resources. + * Images are broken down into rectangular sections, which can use one + * of 18 different encoding methods. + *-------------------------------------------------------------------------*/ + +#define INCR_XSIZE { if (_xSize & 1) ++_xSize; } +#define DEFAULT_WIDTH (SCREEN_WIDTH / 2) +#define BUFFER_SIZE 40000 + +void GfxSurface::decode(const byte *pSrc) { + w = h = 0; + // If no transparency, use invalid (for EGA) palette index of 16. Otherwise get index to use + _transparency = (*pSrc == 0) ? 16 : *(pSrc + 2); + bool offsetFlag = *pSrc++ == 0; + int entryCount = *pSrc++; + pSrc += 2; + + if (offsetFlag) + pSrc += 30; + + // First run through the data to calculate starting offsets + const byte *p = pSrc; + _offset.x = _offset.y = 999; + + assert(entryCount > 0); + for (int idx = 0; idx < entryCount; ++idx) { + _xp = READ_BE_UINT16(p + 4); + if (_xp < _offset.x) + _offset.x = _xp; + + _yp = READ_BE_UINT16(p + 6); + if (_yp < _offset.y) + _offset.y = _yp; + + // Move to next entry + int size = READ_BE_UINT16(p) + READ_BE_UINT16(p + 2); + if ((size % 2) == 1) + ++size; + + p += size + 14; + } + + // Temporary output buffer + byte *outputBuffer = (byte *)malloc(sizeof(byte) * 65536); + memset(outputBuffer, _transparency, 65536); + + byte *pDest = &outputBuffer[0]; + const byte *pSrcStart = pSrc; + const byte *pLookup = NULL; + + byte *lookupTable = (byte *)malloc(sizeof(byte) * BUFFER_SIZE); + byte *srcBuffer = (byte *)malloc(sizeof(byte) * BUFFER_SIZE); + + // Main processing loop + for (int entryIndex = 0; entryIndex < entryCount; ++entryIndex) { + int lookupBytes = READ_BE_UINT16(pSrc); + int srcSize = READ_BE_UINT16(pSrc + 2); + _xp = READ_BE_UINT16(pSrc + 4) - _offset.x; + _yp = READ_BE_UINT16(pSrc + 6) - _offset.y; + assert((_xp >= 0) && (_yp >= 0) && (_xp < SCREEN_WIDTH) && (_yp < SCREEN_ORIG_HEIGHT)); + pSrc += 8; + + int decomCode = READ_BE_UINT16(pSrc); + _xSize = READ_BE_UINT16(pSrc + 2) + 1; + _ySize = READ_BE_UINT16(pSrc + 4) + 1; + majTtxTty(); + + pSrc += 6; + pDest = &outputBuffer[0]; + + _lookupIndex = 0; + _nibbleFlag = false; + + int decomIndex = 0; + if (decomCode >> 8) { + // Build up reference table + int tableOffset = 0; + + if (decomCode & 1) { + // Handle decompression of the pattern lookup table + do { + int outerCount = desanalyse(pSrc); + int innerCount = desanalyse(pSrc); + + const byte *pSrcSaved = pSrc; + bool savedNibbleFlag = _nibbleFlag; + int savedLookupIndex = _lookupIndex; + + do { + pSrc = pSrcSaved; + _nibbleFlag = savedNibbleFlag; + _lookupIndex = savedLookupIndex; + + for (int idx = 0; idx < innerCount; ++idx, ++tableOffset) { + assert(tableOffset < BUFFER_SIZE); + lookupTable[tableOffset] = nextNibble(pSrc); + } + } while (--outerCount > 0); + } while (_lookupIndex < (lookupBytes - 1)); + + } else { + assert(lookupBytes < BUFFER_SIZE); + for (int idx = 0; idx < (lookupBytes * 2); ++idx) + lookupTable[idx] = nextNibble(pSrc); + } + + if (_nibbleFlag) { + ++pSrc; + _nibbleFlag = false; + } + if ((lookupBytes + srcSize) & 1) + ++pSrc; + + tableOffset = 0; + _lookupIndex = 0; + + if (decomCode & 2) { + // Handle decompression of the temporary source buffer + do { + int outerCount = desanalyse(pSrc); + int innerCount = desanalyse(pSrc); + _lookupIndex += innerCount; + + if (_nibbleFlag) { + ++pSrc; + ++_lookupIndex; + _nibbleFlag = false; + } + + const byte *pStart = pSrc; + do { + pSrc = pStart; + for (int idx = 0; idx < innerCount; ++idx) { + assert(tableOffset < BUFFER_SIZE); + srcBuffer[tableOffset++] = *pSrc++; + } + } while (--outerCount > 0); + } while (_lookupIndex < (srcSize - 1)); + } else { + assert(srcSize < BUFFER_SIZE); + for (int idx = 0; idx < srcSize; ++idx) + srcBuffer[idx] = *pSrc++; + } + + if (_nibbleFlag) + ++pSrc; + + // Switch over to using the decompressed source and lookup buffers + pSrcStart = pSrc; + pDest = &outputBuffer[_yp * DEFAULT_WIDTH + _xp]; + pSrc = &srcBuffer[0]; + pLookup = &lookupTable[0] - 1; + + _lookupValue = _lookupIndex = 0; + _nibbleFlag = false; + decomIndex = decomCode >> 8; + } + + // Main decompression switch + switch (decomIndex) { + case 0: + // Draw rect at pos + pDest = &outputBuffer[_yp * DEFAULT_WIDTH + _xp]; + pSrcStart = pSrc; + INCR_XSIZE; + + for (int yCtr = 0; yCtr < _ySize; ++yCtr, pDest += DEFAULT_WIDTH) { + byte *pDestLine = pDest; + for (int xCtr = 0; xCtr < _xSize; ++xCtr) { + *pDestLine++ = nextNibble(pSrc); + } + } + + pSrcStart += lookupBytes + ((lookupBytes & 1) ? 1 : 0); + break; + + case 1: + // Draw rect using horizontal lines alternating left to right, then right to left + INCR_XSIZE; + for (int yCtr = 0; yCtr < _ySize; ++yCtr) { + if ((yCtr % 2) == 0) { + for (int xCtr = 0; xCtr < _xSize; ++xCtr) { + *pDest++ = nextByte(pSrc, pLookup); + } + } else { + for (int xCtr = 0; xCtr < _xSize; ++xCtr) { + *--pDest = nextByte(pSrc, pLookup); + } + } + pDest += DEFAULT_WIDTH; + } + break; + + case 2: + // Draw rect alternating top to bottom, bottom to top + for (int xCtr = 0; xCtr < _xSize; ++xCtr) { + if ((xCtr % 2) == 0) { + for (int yCtr = 0; yCtr < _ySize; ++yCtr, pDest += DEFAULT_WIDTH) { + *pDest = nextByte(pSrc, pLookup); + } + } else { + for (int yCtr = 0; yCtr < _ySize; ++yCtr) { + pDest -= DEFAULT_WIDTH; + *pDest = nextByte(pSrc, pLookup); + } + } + ++pDest; + } + break; + + case 3: + // Draw horizontal area? + _thickness = 2; + horizontal(pSrc, pDest, pLookup); + break; + + case 4: + // Draw vertical area? + _thickness = 2; + vertical(pSrc, pDest, pLookup); + break; + + case 5: + _thickness = 3; + horizontal(pSrc, pDest, pLookup); + break; + + case 6: + _thickness = 4; + vertical(pSrc, pDest, pLookup); + break; + + case 7: + // Draw rect using horizontal lines left to right + INCR_XSIZE; + for (int yCtr = 0; yCtr < _ySize; ++yCtr, pDest += DEFAULT_WIDTH) { + byte *pDestLine = pDest; + for (int xCtr = 0; xCtr < _xSize; ++xCtr) + *pDestLine++ = nextByte(pSrc, pLookup); + } + break; + + case 8: + // Draw box + for (int xCtr = 0; xCtr < _xSize; ++xCtr, ++pDest) { + byte *pDestLine = pDest; + for (int yCtr = 0; yCtr < _ySize; ++yCtr, pDestLine += DEFAULT_WIDTH) + *pDestLine = nextByte(pSrc, pLookup); + } + break; + + case 9: + _thickness = 4; + horizontal(pSrc, pDest, pLookup); + break; + + case 10: + _thickness = 6; + horizontal(pSrc, pDest, pLookup); + break; + + case 11: + decom11(pSrc, pDest, pLookup); + break; + + case 12: + INCR_XSIZE; + _thickness = _xInc = 1; + _yInc = DEFAULT_WIDTH; + _yEnd = _ySize; + _xEnd = _xSize; + diag(pSrc, pDest, pLookup); + break; + + case 13: + INCR_XSIZE; + _thickness = _xSize; + _yInc = 1; + _yEnd = _xSize; + _xInc = DEFAULT_WIDTH; + _xEnd = _ySize; + diag(pSrc, pDest, pLookup); + break; + + case 14: + _thickness = _yInc = 1; + _yEnd = _xSize; + _xInc = DEFAULT_WIDTH; + _xEnd = _ySize; + diag(pSrc, pDest, pLookup); + break; + + case 15: + INCR_XSIZE; + _thickness = 2; + _yInc = DEFAULT_WIDTH; + _yEnd = _ySize; + _xInc = 1; + _xEnd = _xSize; + diag(pSrc, pDest, pLookup); + break; + + case 16: + _thickness = 3; + _yInc = 1; + _yEnd = _xSize; + _xInc = DEFAULT_WIDTH; + _xEnd = _ySize; + diag(pSrc, pDest, pLookup); + break; + + case 17: + INCR_XSIZE; + _thickness = 3; + _yInc = DEFAULT_WIDTH; + _yEnd = _ySize; + _xInc = 1; + _xEnd = _xSize; + diag(pSrc, pDest, pLookup); + break; + + case 18: + INCR_XSIZE; + _thickness = 5; + _yInc = DEFAULT_WIDTH; + _yEnd = _ySize; + _xInc = 1; + _xEnd = _xSize; + diag(pSrc, pDest, pLookup); + break; + + default: + error("Unknown decompression block type %d", decomIndex); + } + + pSrc = pSrcStart; + debugC(2, kMortevielleGraphics, "Decoding image block %d position %d,%d size %d,%d method %d", + entryIndex + 1, _xp, _yp, w, h, decomIndex); + } + + // At this point, the outputBuffer has the data for the image. Initialize the surface + // with the calculated size, and copy the lines to the surface + create(w, h, Graphics::PixelFormat::createFormatCLUT8()); + + for (int yCtr = 0; yCtr < h; ++yCtr) { + const byte *copySrc = &outputBuffer[yCtr * DEFAULT_WIDTH]; + byte *copyDest = (byte *)getBasePtr(0, yCtr); + + Common::copy(copySrc, copySrc + w, copyDest); + } + + ::free(outputBuffer); + ::free(lookupTable); + ::free(srcBuffer); +} + +void GfxSurface::majTtxTty() { + if (!_yp) + w += _xSize; + + if (!_xp) + h += _ySize; +} + +/** + * Decompression Function - get next nibble + * @remarks Originally called 'suiv' + */ +byte GfxSurface::nextNibble(const byte *&pSrc) { + int v = *pSrc; + if (_nibbleFlag) { + ++pSrc; + ++_lookupIndex; + _nibbleFlag = false; + return v & 0xf; + } else { + _nibbleFlag = !_nibbleFlag; + return v >> 4; + } +} + +/** + * Decompression Function - get next byte + * @remarks Originally called 'csuiv' + */ +byte GfxSurface::nextByte(const byte *&pSrc, const byte *&pLookup) { + assert(pLookup); + + while (!_lookupValue) { + int v; + do { + v = nextNibble(pSrc) & 0xff; + _lookupValue += v; + } while (v == 0xf); + ++pLookup; + } + + --_lookupValue; + return *pLookup; +} + +int GfxSurface::desanalyse(const byte *&pSrc) { + int total = 0; + int v = nextNibble(pSrc); + if (v == 0xf) { + int v2; + do { + v2 = nextNibble(pSrc); + total += v2; + } while (v2 == 0xf); + + total *= 15; + v = nextNibble(pSrc); + } + + total += v; + return total; +} + +void GfxSurface::horizontal(const byte *&pSrc, byte *&pDest, const byte *&pLookup) { + INCR_XSIZE; + byte *pDestEnd = pDest + (_ySize - 1) * DEFAULT_WIDTH + _xSize; + + for (;;) { + // If position is past end point, then skip this line + if (((_thickness - 1) * DEFAULT_WIDTH) + pDest >= pDestEnd) { + if (--_thickness == 0) + break; + continue; + } + + bool continueFlag = false; + do { + for (int xIndex = 0; xIndex < _xSize; ++xIndex) { + if ((xIndex % 2) == 0) { + if (xIndex != 0) + ++pDest; + + // Write out vertical slice top to bottom + for (int yIndex = 0; yIndex < _thickness; ++yIndex, pDest += DEFAULT_WIDTH) + *pDest = nextByte(pSrc, pLookup); + + ++pDest; + } else { + // Write out vertical slice bottom to top + for (int yIndex = 0; yIndex < _thickness; ++yIndex) { + pDest -= DEFAULT_WIDTH; + *pDest = nextByte(pSrc, pLookup); + } + } + } + + if ((_xSize % 2) == 0) { + int blockSize = _thickness * DEFAULT_WIDTH; + pDest += blockSize; + blockSize -= DEFAULT_WIDTH; + + if (pDestEnd < (pDest + blockSize)) { + do { + if (--_thickness == 0) + return; + } while ((pDest + (_thickness - 1) * DEFAULT_WIDTH) >= pDestEnd); + } + } else { + while ((pDest + (_thickness - 1) * DEFAULT_WIDTH) >= pDestEnd) { + if (--_thickness == 0) + return; + } + } + + for (int xIndex = 0; xIndex < _xSize; ++xIndex, --pDest) { + if ((xIndex % 2) == 0) { + // Write out vertical slice top to bottom + for (int yIndex = 0; yIndex < _thickness; ++yIndex, pDest += DEFAULT_WIDTH) + *pDest = nextByte(pSrc, pLookup); + } else { + // Write out vertical slice top to bottom + for (int yIndex = 0; yIndex < _thickness; ++yIndex) { + pDest -= DEFAULT_WIDTH; + *pDest = nextByte(pSrc, pLookup); + } + } + } + + if ((_xSize % 2) == 1) { + ++pDest; + + if ((pDest + (_thickness - 1) * DEFAULT_WIDTH) < pDestEnd) { + continueFlag = true; + break; + } + } else { + pDest += _thickness * DEFAULT_WIDTH + 1; + continueFlag = true; + break; + } + + ++pDest; + } while (((_thickness - 1) * DEFAULT_WIDTH + pDest) < pDestEnd); + + if (continueFlag) + continue; + + // Move to next line + if (--_thickness == 0) + break; + } +} + +void GfxSurface::vertical(const byte *&pSrc, byte *&pDest, const byte *&pLookup) { + int drawIndex = 0; + + for (;;) { + // Reduce thickness as necessary + while ((drawIndex + _thickness) > _xSize) { + if (--_thickness == 0) + return; + } + + // Loop + for (int yCtr = 0; yCtr < _ySize; ++yCtr) { + if ((yCtr % 2) == 0) { + if (yCtr > 0) + pDest += DEFAULT_WIDTH; + + drawIndex += _thickness; + for (int xCtr = 0; xCtr < _thickness; ++xCtr) + *pDest++ = nextByte(pSrc, pLookup); + } else { + pDest += DEFAULT_WIDTH; + drawIndex -= _thickness; + for (int xCtr = 0; xCtr < _thickness; ++xCtr) + *--pDest = nextByte(pSrc, pLookup); + } + } + if ((_ySize % 2) == 0) { + pDest += _thickness; + drawIndex += _thickness; + } + + while (_xSize < (drawIndex + _thickness)) { + if (--_thickness == 0) + return; + } + + // Loop + for (int yCtr = 0; yCtr < _ySize; ++yCtr) { + if ((yCtr % 2) == 0) { + if (yCtr > 0) + pDest -= DEFAULT_WIDTH; + + drawIndex += _thickness; + + for (int xCtr = 0; xCtr < _thickness; ++xCtr) + *pDest++ = nextByte(pSrc, pLookup); + } else { + pDest -= DEFAULT_WIDTH; + drawIndex -= _thickness; + + for (int xCtr = 0; xCtr < _thickness; ++xCtr) + *--pDest = nextByte(pSrc, pLookup); + } + } + if ((_ySize % 2) == 0) { + pDest += _thickness; + drawIndex += _thickness; + } + } +} + +void GfxSurface::decom11(const byte *&pSrc, byte *&pDest, const byte *&pLookup) { + int yPos = 0, drawIndex = 0; + _yInc = DEFAULT_WIDTH; + _xInc = -1; + --_xSize; + --_ySize; + + int areaNum = 0; + while (areaNum != -1) { + switch (areaNum) { + case 0: + *pDest = nextByte(pSrc, pLookup); + areaNum = 1; + break; + + case 1: + nextDecompPtr(pDest); + + if (!drawIndex) { + negXInc(); + negYInc(); + + if (yPos == _ySize) { + nextDecompPtr(pDest); + ++drawIndex; + } else { + ++yPos; + } + + *++pDest = nextByte(pSrc, pLookup); + areaNum = 2; + } else if (yPos != _ySize) { + ++yPos; + --drawIndex; + areaNum = 0; + } else { + negXInc(); + negYInc(); + nextDecompPtr(pDest); + ++drawIndex; + + *++pDest = nextByte(pSrc, pLookup); + + if (drawIndex == _xSize) { + areaNum = -1; + } else { + areaNum = 2; + } + } + break; + + case 2: + nextDecompPtr(pDest); + + if (!yPos) { + negXInc(); + negYInc(); + + if (drawIndex == _xSize) { + nextDecompPtr(pDest); + ++yPos; + } else { + ++drawIndex; + } + + pDest += DEFAULT_WIDTH; + areaNum = 0; + } else if (drawIndex != _xSize) { + ++drawIndex; + --yPos; + + *pDest = nextByte(pSrc, pLookup); + areaNum = 2; + } else { + pDest += DEFAULT_WIDTH; + ++yPos; + negXInc(); + negYInc(); + nextDecompPtr(pDest); + + *pDest = nextByte(pSrc, pLookup); + + if (yPos == _ySize) + areaNum = -1; + else + areaNum = 1; + } + break; + } + } +} + +void GfxSurface::diag(const byte *&pSrc, byte *&pDest, const byte *&pLookup) { + int diagIndex = 0, drawIndex = 0; + --_xEnd; + + while (!TFP(diagIndex)) { + for (;;) { + negXInc(); + for (int idx = 0; idx <= _thickness; ++idx) { + *pDest = nextByte(pSrc, pLookup); + negXInc(); + nextDecompPtr(pDest); + } + + negYInc(); + pDest += _yInc; + + for (int idx = 0; idx <= _thickness; ++idx) { + *pDest = nextByte(pSrc, pLookup); + negXInc(); + nextDecompPtr(pDest); + } + + negXInc(); + negYInc(); + nextDecompPtr(pDest); + + ++drawIndex; + if (_xEnd < (drawIndex + 1)) { + TF1(pDest, diagIndex); + break; + } + + pDest += _xInc; + ++drawIndex; + if (_xEnd < (drawIndex + 1)) { + TF2(pSrc, pDest, pLookup, diagIndex); + break; + } + } + + if (TFP(diagIndex)) + break; + + for (;;) { + for (int idx = 0; idx <= _thickness; ++idx) { + *pDest = nextByte(pSrc, pLookup); + negXInc(); + nextDecompPtr(pDest); + } + + negYInc(); + pDest += _yInc; + + for (int idx = 0; idx <= _thickness; ++idx) { + *pDest = nextByte(pSrc, pLookup); + negXInc(); + nextDecompPtr(pDest); + } + + negXInc(); + negYInc(); + nextDecompPtr(pDest); + + if (--drawIndex == 0) { + TF1(pDest, diagIndex); + negXInc(); + break; + } else { + pDest += _xInc; + + if (--drawIndex == 0) { + TF2(pSrc, pDest, pLookup, diagIndex); + negXInc(); + break; + } + } + + negXInc(); + } + } +} + +/** + * Decompression Function - Move pDest ptr to next value to uncompress + * @remarks Originally called 'increments' + */ +void GfxSurface::nextDecompPtr(byte *&pDest) { + pDest += _xInc + _yInc; +} + +/** + * Decompression Function - set xInc to its opposite value + * @remarks Originally called 'NIH' + */ +void GfxSurface::negXInc() { + _xInc = -_xInc; +} + +/** + * Decompression Function - set yInc to its opposite value + * @remarks Originally called 'NIV' + */ +void GfxSurface::negYInc() { + _yInc = -_yInc; +} + +bool GfxSurface::TFP(int v) { + int diff = _yEnd - v; + if (!diff) + // Time to finish loop in outer method + return true; + + if (diff < (_thickness + 1)) + _thickness = diff - 1; + + return false; +} + +void GfxSurface::TF1(byte *&pDest, int &v) { + v += _thickness + 1; + pDest += (_thickness + 1) * _yInc; +} + +void GfxSurface::TF2(const byte *&pSrc, byte *&pDest, const byte *&pLookup, int &v) { + v += _thickness + 1; + + for (int idx = 0; idx <= _thickness; ++idx) { + *pDest = nextByte(pSrc, pLookup); + pDest += _yInc; + } +} + +/*-------------------------------------------------------------------------*/ + +GfxSurface::~GfxSurface() { + free(); +} + +/*-------------------------------------------------------------------------* + * Screen surface + *-------------------------------------------------------------------------*/ + +/** + * Called to populate the font data from the passed file + */ +void ScreenSurface::readFontData(Common::File &f, int dataSize) { + assert(dataSize == (FONT_NUM_CHARS * FONT_HEIGHT)); + f.read(_fontData, FONT_NUM_CHARS * FONT_HEIGHT); +} + +/** + * Returns a graphics surface representing a subset of the screen. The affected area + * is also marked as dirty + */ +Graphics::Surface ScreenSurface::lockArea(const Common::Rect &bounds) { + _dirtyRects.push_back(bounds); + + Graphics::Surface s; + s.init(bounds.width(), bounds.height(), pitch, getBasePtr(bounds.left, bounds.top), format); + return s; +} + +/** + * Updates the affected areas of the surface to the underlying physical screen + */ +void ScreenSurface::updateScreen() { + // Iterate through copying dirty areas to the screen + for (Common::List<Common::Rect>::iterator i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i) { + Common::Rect r = *i; + g_system->copyRectToScreen((const byte *)getBasePtr(r.left, r.top), pitch, + r.left, r.top, r.width(), r.height()); + } + _dirtyRects.clear(); + + // Update the screen + g_system->updateScreen(); +} + +/** + * Draws a decoded picture on the screen + * @remarks - Because the ScummVM surface is using a double height 640x400 surface to + * simulate the original 640x400 surface, all Y values have to be doubled. + * - Image resources are stored at 320x200, so when drawn onto the screen a single pixel + * from the source image is drawn using the two pixels at the given index in the palette map + * - Because the original game supported 320 width resolutions, the X coordinate + * also needs to be doubled for EGA mode + */ +void ScreenSurface::drawPicture(GfxSurface &surface, int x, int y) { + // Adjust the draw position by the draw offset + x += surface._offset.x; + y += surface._offset.y; + + // Lock the affected area of the surface to write to + Graphics::Surface destSurface = lockArea(Common::Rect(x * 2, y * 2, + (x + surface.w) * 2, (y + surface.h) * 2)); + + // Get a lookup for the palette mapping + const byte *paletteMap = &_vm->_curPict[2]; + + // Loop through writing + for (int yp = 0; yp < surface.h; ++yp) { + if (((y + yp) < 0) || ((y + yp) >= 200)) + continue; + + const byte *pSrc = (const byte *)surface.getBasePtr(0, yp); + byte *pDest = (byte *)destSurface.getBasePtr(0, yp * 2); + + for (int xp = 0; xp < surface.w; ++xp, ++pSrc) { + if (*pSrc == surface._transparency) { + // Transparent point, so skip pixels + pDest += 2; + } else { + // Draw the pixel using the specified index in the palette map + *pDest = paletteMap[*pSrc * 2]; + *(pDest + SCREEN_WIDTH) = paletteMap[*pSrc * 2]; + ++pDest; + + // Use the secondary mapping value to draw the secondary column pixel + *pDest = paletteMap[*pSrc * 2 + 1]; + *(pDest + SCREEN_WIDTH) = paletteMap[*pSrc * 2 + 1]; + ++pDest; + } + } + } +} + +/** + * Copys a given surface to the given position + */ +void ScreenSurface::copyFrom(Graphics::Surface &src, int x, int y) { + lockArea(Common::Rect(x, y, x + src.w, y + src.h)); + + // Loop through writing + for (int yp = 0; yp < src.h; ++yp) { + if (((y + yp) < 0) || ((y + yp) >= SCREEN_HEIGHT)) + continue; + + const byte *pSrc = (const byte *)src.getBasePtr(0, yp); + byte *pDest = (byte *)getBasePtr(0, yp); + Common::copy(pSrc, pSrc + src.w, pDest); + } +} + +/** + * Draws a character at the specified co-ordinates + * @remarks Because the ScummVM surface is using a double height 640x400 surface to + * simulate the original 640x400 surface, all Y values have to be doubled + */ +void ScreenSurface::writeCharacter(const Common::Point &pt, unsigned char ch, int palIndex) { + Graphics::Surface destSurface = lockArea(Common::Rect(pt.x, pt.y * 2, + pt.x + FONT_WIDTH, (pt.y + FONT_HEIGHT) * 2)); + + // Get the start of the character to use + assert((ch >= ' ') && (ch <= (unsigned char)(32 + FONT_NUM_CHARS))); + const byte *charData = &_fontData[((int)ch - 32) * FONT_HEIGHT]; + + // Loop through decoding each character's data + for (int yp = 0; yp < FONT_HEIGHT; ++yp) { + byte *lineP = (byte *)destSurface.getBasePtr(0, yp * 2); + byte byteVal = *charData++; + + for (int xp = 0; xp < FONT_WIDTH; ++xp, ++lineP, byteVal <<= 1) { + if (byteVal & 0x80) { + *lineP = palIndex; + *(lineP + SCREEN_WIDTH) = palIndex; + } + } + } +} + +/** + * Draws a box at the specified position and size + * @remarks Because the ScummVM surface is using a double height 640x400 surface to + * simulate the original 640x400 surface, all Y values have to be doubled + */ +void ScreenSurface::drawBox(int x, int y, int dx, int dy, int col) { + Graphics::Surface destSurface = lockArea(Common::Rect(x, y * 2, x + dx, (y + dy) * 2)); + + destSurface.hLine(0, 0, dx, col); + destSurface.hLine(0, 1, dx, col); + destSurface.hLine(0, destSurface.h - 1, dx, col); + destSurface.hLine(0, destSurface.h - 2, dx, col); + destSurface.vLine(0, 2, destSurface.h - 3, col); + destSurface.vLine(1, 2, destSurface.h - 3, col); + destSurface.vLine(dx - 1, 2, destSurface.h - 3, col); + destSurface.vLine(dx - 2, 2, destSurface.h - 3, col); +} + +/** + * Fills an area with the specified color + * @remarks Because the ScummVM surface is using a double height 640x400 surface to + * simulate the original 640x400 surface, all Y values have to be doubled + */ +void ScreenSurface::fillRect(int color, const Common::Rect &bounds) { + Graphics::Surface destSurface = lockArea(Common::Rect(bounds.left, bounds.top * 2, + bounds.right, bounds.bottom * 2)); + + // Fill the area + destSurface.fillRect(Common::Rect(0, 0, destSurface.w, destSurface.h), color); +} + +/** + * Clears the screen + */ +void ScreenSurface::clearScreen() { + Graphics::Surface destSurface = lockArea(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)); + destSurface.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0); +} + +/** + * Sets a single pixel at the specified co-ordinates + * @remarks Because the ScummVM surface is using a double height 640x400 surface to + * simulate the original 640x400 surface, all Y values have to be doubled + */ +void ScreenSurface::setPixel(const Common::Point &pt, int palIndex) { + assert((pt.x >= 0) && (pt.y >= 0) && (pt.x <= SCREEN_WIDTH) && (pt.y <= SCREEN_ORIG_HEIGHT)); + Graphics::Surface destSurface = lockArea(Common::Rect(pt.x, pt.y * 2, pt.x + 1, (pt.y + 1) * 2)); + + byte *destP = (byte *)destSurface.getPixels(); + *destP = palIndex; + *(destP + SCREEN_WIDTH) = palIndex; +} + +/** + * Write out a string + * @remarks Originally called 'writeg' + */ +void ScreenSurface::drawString(const Common::String &l, int command) { + if (l == "") + return; + + _vm->_mouse.hideMouse(); + Common::Point pt = _textPos; + + int charWidth = 6; + + int x = pt.x + charWidth * l.size(); + int color = 0; + + switch (command) { + case 0: + case 2: + color = 15; + _vm->_screenSurface.fillRect(0, Common::Rect(pt.x, pt.y, x, pt.y + 7)); + break; + case 1: + case 3: + _vm->_screenSurface.fillRect(15, Common::Rect(pt.x, pt.y, x, pt.y + 7)); + break; + case 5: + color = 15; + break; + default: + // Default: Color set to zero (already done) + break; + } + + pt.x += 1; + pt.y += 1; + for (x = 1; (x <= (int)l.size()) && (l[x - 1] != 0); ++x) { + _vm->_screenSurface.writeCharacter(Common::Point(pt.x, pt.y), l[x - 1], color); + pt.x += charWidth; + } + _vm->_mouse.showMouse(); +} + +/** + * Gets the width in pixels of the specified string + */ +int ScreenSurface::getStringWidth(const Common::String &s) { + int charWidth = 6; + + return s.size() * charWidth; +} + +void ScreenSurface::drawLine(int x, int y, int xx, int yy, int coul) { + int step, i; + float a, b; + float xr, yr, xro, yro; + + xr = x; + yr = y; + xro = xx; + yro = yy; + + if (abs(y - yy) > abs(x - xx)) { + a = (float)((x - xx)) / (y - yy); + b = (yr * xro - yro * xr) / (y - yy); + i = y; + if (y > yy) + step = -1; + else + step = 1; + do { + _vm->_screenSurface.setPixel(Common::Point(abs((int)(a * i + b)), i), coul); + i += step; + } while (i != yy); + } else { + a = (float)((y - yy)) / (x - xx); + b = ((yro * xr) - (yr * xro)) / (x - xx); + i = x; + if (x > xx) + step = -1; + else + step = 1; + do { + _vm->_screenSurface.setPixel(Common::Point(i, abs((int)(a * i + b))), coul); + i = i + step; + } while (i != xx); + } +} + +/** + * Draw plain rectangle + * @remarks Originally called 'paint_rect' + */ +void ScreenSurface::drawRectangle(int x, int y, int dx, int dy) { + _vm->_screenSurface.fillRect(11, Common::Rect(x, y, x + dx, y + dy)); +} + +void ScreenSurface::setParent(MortevielleEngine *vm) { + _vm = vm; +} + + +} // End of namespace Mortevielle diff --git a/engines/mortevielle/graphics.h b/engines/mortevielle/graphics.h new file mode 100644 index 0000000000..e31f5da29a --- /dev/null +++ b/engines/mortevielle/graphics.h @@ -0,0 +1,117 @@ +/* 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#ifndef MORTEVIELLE_GRAPHICS_H +#define MORTEVIELLE_GRAPHICS_H + +#include "common/file.h" +#include "common/list.h" +#include "common/rect.h" +#include "graphics/surface.h" + +namespace Mortevielle { +class MortevielleEngine; + +class PaletteManager { +private: + void setPalette(const int *palette, uint idx, uint size); + +public: + void setDefaultPalette(); +}; + +#define FONT_WIDTH 8 +#define FONT_HEIGHT 6 +#define FONT_NUM_CHARS 121 + +class GfxSurface : public Graphics::Surface { +private: + int _xp, _yp; + int _xSize, _ySize; + int _lookupIndex, _lookupValue; + bool _nibbleFlag; + int _thickness; + int _yInc, _yEnd, _xInc, _xEnd; + + byte nextNibble(const byte *&pSrc); + byte nextByte(const byte *&pSrc, const byte *&pLookup); + + void majTtxTty(); + int desanalyse(const byte *&pSrc); + void horizontal(const byte *&pSrc, byte *&pDest, const byte *&pLookup); + void vertical(const byte *&pSrc, byte *&pDest, const byte *&pLookup); + void decom11(const byte *&pSrc, byte *&pDest, const byte *&pLookup); + void diag(const byte *&pSrc, byte *&pDest, const byte *&pLookup); + void nextDecompPtr(byte *&pDest); + void negXInc(); + void negYInc(); + bool TFP(int v); + void TF1(byte *&pDest, int &v); + void TF2(const byte *&pSrc, byte *&pDest, const byte *&pLookup, int &v); +public: + // Specifies offset when drawing the image + Common::Point _offset; + // Transparency palette index + int _transparency; + + ~GfxSurface(); + + void decode(const byte *pSrc); +}; + +class ScreenSurface: public Graphics::Surface { +private: + MortevielleEngine *_vm; + + Common::List<Common::Rect> _dirtyRects; + byte _fontData[FONT_NUM_CHARS * FONT_HEIGHT]; + +public: + Common::Point _textPos; // Original called xwhere/ywhere + void readFontData(Common::File &f, int dataSize); + Graphics::Surface lockArea(const Common::Rect &bounds); + void updateScreen(); + void drawPicture(GfxSurface &surface, int x, int y); + void copyFrom(Graphics::Surface &src, int x, int y); + void writeCharacter(const Common::Point &pt, unsigned char ch, int palIndex); + void drawBox(int x, int y, int dx, int dy, int col); + void fillRect(int color, const Common::Rect &bounds); + void clearScreen(); + void putxy(int x, int y) { _textPos = Common::Point(x, y); } + void drawString(const Common::String &l, int command); + int getStringWidth(const Common::String &s); + void drawLine(int x, int y, int xx, int yy, int coul); + void drawRectangle(int x, int y, int dx, int dy); + void setParent(MortevielleEngine *vm); + + // TODO: Refactor code to remove this method, for increased performance + void setPixel(const Common::Point &pt, int palIndex); +}; + +} // End of namespace Mortevielle + +#endif diff --git a/engines/mortevielle/menu.cpp b/engines/mortevielle/menu.cpp new file mode 100644 index 0000000000..1077f66fc2 --- /dev/null +++ b/engines/mortevielle/menu.cpp @@ -0,0 +1,756 @@ +/* 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 re_distribute 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#include "mortevielle/mortevielle.h" + +#include "mortevielle/menu.h" +#include "mortevielle/mouse.h" +#include "mortevielle/outtext.h" + +#include "common/scummsys.h" +#include "common/str.h" +#include "common/textconsole.h" + +namespace Mortevielle { + +const byte menuConstants[8][4] = { + { 7, 37, 23, 8}, + {19, 33, 23, 7}, + {31, 89, 10, 21}, + {43, 25, 11, 5}, + {55, 37, 5, 8}, + {64, 13, 11, 2}, + {62, 42, 13, 9}, + {62, 46, 13, 10} +}; + +Menu::Menu() { + _opcodeAttach = _opcodeWait = _opcodeForce = _opcodeSleep = OPCODE_NONE; + _opcodeListen = _opcodeEnter = _opcodeClose = _opcodeSearch = OPCODE_NONE; + _opcodeKnock = _opcodeScratch = _opcodeRead = _opcodeEat = OPCODE_NONE; + _opcodePlace = _opcodeOpen = _opcodeTake = _opcodeLook = OPCODE_NONE; + _opcodeSmell = _opcodeSound = _opcodeLeave = _opcodeLift = OPCODE_NONE; + _opcodeTurn = _opcodeSHide = _opcodeSSearch = _opcodeSRead = OPCODE_NONE; + _opcodeSPut = _opcodeSLook = OPCODE_NONE; +} + +void Menu::readVerbNums(Common::File &f, int dataSize) { + // Figure out what language Id is needed + byte desiredLanguageId; + switch(_vm->getLanguage()) { + case Common::EN_ANY: + desiredLanguageId = MORTDAT_LANG_ENGLISH; + break; + case Common::FR_FRA: + desiredLanguageId = MORTDAT_LANG_FRENCH; + break; + case Common::DE_DEU: + desiredLanguageId = MORTDAT_LANG_GERMAN; + break; + default: + warning("Language not supported, switching to English"); + desiredLanguageId = MORTDAT_LANG_ENGLISH; + break; + } + // Read in the language + byte languageId = f.readByte(); + --dataSize; + + // If the language isn't correct, then skip the entire block + if (languageId != desiredLanguageId) { + f.skip(dataSize); + return; + } + + assert(dataSize == 52); + _opcodeAttach = f.readUint16LE(); + _opcodeWait = f.readUint16LE(); + _opcodeForce = f.readUint16LE(); + _opcodeSleep = f.readUint16LE(); + _opcodeListen = f.readUint16LE(); + _opcodeEnter = f.readUint16LE(); + _opcodeClose = f.readUint16LE(); + _opcodeSearch = f.readUint16LE(); + _opcodeKnock = f.readUint16LE(); + _opcodeScratch = f.readUint16LE(); + _opcodeRead = f.readUint16LE(); + _opcodeEat = f.readUint16LE(); + _opcodePlace = f.readUint16LE(); + _opcodeOpen = f.readUint16LE(); + _opcodeTake = f.readUint16LE(); + _opcodeLook = f.readUint16LE(); + _opcodeSmell = f.readUint16LE(); + _opcodeSound = f.readUint16LE(); + _opcodeLeave = f.readUint16LE(); + _opcodeLift = f.readUint16LE(); + _opcodeTurn = f.readUint16LE(); + _opcodeSHide = f.readUint16LE(); + _opcodeSSearch = f.readUint16LE(); + _opcodeSRead = f.readUint16LE(); + _opcodeSPut = f.readUint16LE(); + _opcodeSLook = f.readUint16LE(); + + _actionMenu[0]._menuId = OPCODE_NONE >> 8; + _actionMenu[0]._actionId = OPCODE_NONE & 0xFF; + + _actionMenu[1]._menuId = _opcodeSHide >> 8; + _actionMenu[1]._actionId = _opcodeSHide & 0xFF; + + _actionMenu[2]._menuId = _opcodeAttach >> 8; + _actionMenu[2]._actionId = _opcodeAttach & 0xFF; + + _actionMenu[3]._menuId = _opcodeForce >> 8; + _actionMenu[3]._actionId = _opcodeForce & 0xFF; + + _actionMenu[4]._menuId = _opcodeSleep >> 8; + _actionMenu[4]._actionId = _opcodeSleep & 0xFF; + + _actionMenu[5]._menuId = _opcodeEnter >> 8; + _actionMenu[5]._actionId = _opcodeEnter & 0xFF; + + _actionMenu[6]._menuId = _opcodeClose >> 8; + _actionMenu[6]._actionId = _opcodeClose & 0xFF; + + _actionMenu[7]._menuId = _opcodeKnock >> 8; + _actionMenu[7]._actionId = _opcodeKnock & 0xFF; + + _actionMenu[8]._menuId = _opcodeEat >> 8; + _actionMenu[8]._actionId = _opcodeEat & 0xFF; + + _actionMenu[9]._menuId = _opcodePlace >> 8; + _actionMenu[9]._actionId = _opcodePlace & 0xFF; + + _actionMenu[10]._menuId = _opcodeOpen >> 8; + _actionMenu[10]._actionId = _opcodeOpen & 0xFF; + + _actionMenu[11]._menuId = _opcodeLeave >> 8; + _actionMenu[11]._actionId = _opcodeLeave & 0xFF; +} + +/** + * Setup a menu's contents + * @remarks Originally called 'menut' + */ +void Menu::setText(MenuItem item, Common::String name) { + Common::String s = name; + + switch (item._menuId) { + case MENU_INVENTORY: + if (item._actionId != 7) { + while (s.size() < 22) + s += ' '; + + _inventoryStringArray[item._actionId] = s; + _inventoryStringArray[item._actionId].insertChar(' ', 0); + } + break; + case MENU_MOVE: + while (s.size() < 22) + s += ' '; + + _moveStringArray[item._actionId] = s; + break; + case MENU_ACTION: { + // If the first character isn't '*' or ' ' then it's missing a heading space + char c = s[0]; + if (c != '*' && c != ' ') + s = ' ' + s; + + while (s.size() < 10) + s += ' '; + + _actionStringArray[item._actionId] = s; + } + break; + case MENU_SELF: { + // If the first character isn't '*' or ' ' then it's missing a heading space + char c = s[0]; + if (c != '*' && c != ' ') + s = ' ' + s; + + while (s.size() < 10) + s += ' '; + + _selfStringArray[item._actionId] = s; + } + break; + case MENU_DISCUSS: + _discussStringArray[item._actionId] = s; + break; + default: + break; + } +} + +/** + * Init destination menu + * @remarks Originally called 'tmlieu' + */ +void Menu::setDestinationText(int roomId) { + Common::String nomp; + + if (roomId == ROOM26) + roomId = LANDING; + + int destinationId = 0; + for (; (destinationId < 7) && (_vm->_destinationArray[destinationId][roomId]); ++destinationId) { + nomp = _vm->getString(_vm->_destinationArray[destinationId][roomId] + kMenuPlaceStringIndex); + while (nomp.size() < 20) + nomp += ' '; + setText(_moveMenu[destinationId + 1], nomp); + } + nomp = "* "; + for (int i = 7; i >= destinationId + 1; --i) + setText(_moveMenu[i], nomp); +} + +/** + * _disable a menu item + * @param menuId Menu number + * @param actionId Item index + */ +void Menu::disableMenuItem(MenuItem item) { + switch (item._menuId) { + case MENU_INVENTORY: + if (item._actionId > 6) { + _inventoryStringArray[item._actionId].setChar('<', 0); + _inventoryStringArray[item._actionId].setChar('>', 21); + } else + _inventoryStringArray[item._actionId].setChar('*', 0); + break; + case MENU_MOVE: + _moveStringArray[item._actionId].setChar('*', 0); + break; + case MENU_ACTION: + _actionStringArray[item._actionId].setChar('*', 0); + break; + case MENU_SELF: + _selfStringArray[item._actionId].setChar('*', 0); + break; + case MENU_DISCUSS: + _discussStringArray[item._actionId].setChar('*', 0); + break; + default: + break; + } +} + +/** + * Enable a menu item + * @param menuId Menu number + * @param actionId Item index + * @remarks Originally called menu_enable + */ +void Menu::enableMenuItem(MenuItem item) { + switch (item._menuId) { + case MENU_INVENTORY: + _inventoryStringArray[item._actionId].setChar(' ', 0); + _inventoryStringArray[item._actionId].setChar(' ', 21); + break; + case MENU_MOVE: + _moveStringArray[item._actionId].setChar(' ', 0); + break; + case MENU_ACTION: + _actionStringArray[item._actionId].setChar(' ', 0); + break; + case MENU_SELF: + _selfStringArray[item._actionId].setChar(' ', 0); + break; + case MENU_DISCUSS: + _discussStringArray[item._actionId].setChar(' ', 0); + break; + default: + break; + } +} + +void Menu::displayMenu() { + _vm->_mouse.hideMouse(); + _vm->_screenSurface.fillRect(7, Common::Rect(0, 0, 639, 10)); + + int col = 28 * kResolutionScaler; + for (int charNum = 0; charNum < 6; charNum++) { + // One character after the other + int idx = 0; + for (int y = 1; y < 9; ++y) { + // One column after the other + int x = col; + for (int k = 0; k < 3; ++k) { + // One line after the other + uint msk = 0x80; + for (int pt = 0; pt <= 7; ++pt) { + if ((_charArr[charNum][idx] & msk) != 0) { + _vm->_screenSurface.setPixel(Common::Point(x + 1, y + 1), 0); + _vm->_screenSurface.setPixel(Common::Point(x, y + 1), 0); + _vm->_screenSurface.setPixel(Common::Point(x, y), 9); + } + msk >>= 1; + ++x; + } + ++idx; + } + } + col += 48 * kResolutionScaler; + } + _vm->_mouse.showMouse(); +} + +/** + * Show the menu + */ +void Menu::drawMenu() { + displayMenu(); + _menuActive = true; + _msg4 = OPCODE_NONE; + _msg3 = OPCODE_NONE; + _menuSelected = false; + _vm->setMouseClick(false); + _multiTitle = false; +} + +/** + * Menu function - Invert a menu entry + * @remarks Originally called 'invers' + */ +void Menu::invert(int indx) { + if (_msg4 == OPCODE_NONE) + return; + + int menuIndex = _msg4 & 0xFF; + + _vm->_screenSurface.putxy(menuConstants[_msg3 - 1][0] << 3, (menuIndex + 1) << 3); + + Common::String str; + switch (_msg3) { + case MENU_INVENTORY: + str = _inventoryStringArray[menuIndex]; + break; + case MENU_MOVE: + str = _moveStringArray[menuIndex]; + break; + case MENU_ACTION: + str = _actionStringArray[menuIndex]; + break; + case MENU_SELF: + str = _selfStringArray[menuIndex]; + break; + case MENU_DISCUSS: + str = _discussStringArray[menuIndex]; + break; + case MENU_FILE: + str = _vm->getEngineString(S_SAVE_LOAD + menuIndex); + break; + case MENU_SAVE: + str = _vm->getEngineString(S_SAVE_LOAD + 1); + str += ' '; + str += (char)(48 + menuIndex); + break; + case MENU_LOAD: + if (menuIndex == 1) { + str = _vm->getEngineString(S_RESTART); + } else { + str = _vm->getEngineString(S_SAVE_LOAD + 2); + str += ' '; + str += (char)(47 + menuIndex); + } + break; + default: + break; + } + if ((str[0] != '*') && (str[0] != '<')) + _vm->_screenSurface.drawString(str, indx); + else + _msg4 = OPCODE_NONE; +} + +void Menu::util(Common::Point pos) { + + int ymx = (menuConstants[_msg3 - 1][3] << 3) + 16; + int dxcar = menuConstants[_msg3 - 1][2]; + int xmn = (menuConstants[_msg3 - 1][0] << 2) * kResolutionScaler; + + int charWidth = 6; + int xmx = dxcar * charWidth + xmn + 2; + if ((pos.x > xmn) && (pos.x < xmx) && (pos.y < ymx) && (pos.y > 15)) { + int ix = (((uint)pos.y >> 3) - 1) + (_msg3 << 8); + if (ix != _msg4) { + invert(1); + _msg4 = ix; + invert(0); + } + } else if (_msg4 != OPCODE_NONE) { + invert(1); + _msg4 = OPCODE_NONE; + } +} + +/** + * Draw a menu + */ +void Menu::menuDown(int ii) { + // Make a copy of the current screen surface for later restore + _vm->_backgroundSurface.copyFrom(_vm->_screenSurface); + + // Draw the menu + int minX = menuConstants[ii - 1][0] << 3; + int lineNum = menuConstants[ii - 1][3]; + _vm->_mouse.hideMouse(); + int deltaX = 6; + int maxX = minX + (menuConstants[ii - 1][2] * deltaX) + 6; + if ((ii == 4) && (_vm->getLanguage() == Common::EN_ANY)) + // Extra width needed for Self menu in English version + maxX = 435; + + _vm->_screenSurface.fillRect(15, Common::Rect(minX, 12, maxX, 10 + (menuConstants[ii - 1][1] << 1))); + _vm->_screenSurface.fillRect(0, Common::Rect(maxX, 12, maxX + 4, 10 + (menuConstants[ii - 1][1] << 1))); + _vm->_screenSurface.fillRect(0, Common::Rect(minX, 8 + (menuConstants[ii - 1][1] << 1), maxX + 4, 12 + (menuConstants[ii - 1][1] << 1))); + _vm->_screenSurface.putxy(minX, 16); + for (int i = 1; i <= lineNum; i++) { + switch (ii) { + case 1: + if (_inventoryStringArray[i][0] != '*') + _vm->_screenSurface.drawString(_inventoryStringArray[i], 4); + break; + case 2: + if (_moveStringArray[i][0] != '*') + _vm->_screenSurface.drawString(_moveStringArray[i], 4); + break; + case 3: + if (_actionStringArray[i][0] != '*') + _vm->_screenSurface.drawString(_actionStringArray[i], 4); + break; + case 4: + if (_selfStringArray[i][0] != '*') + _vm->_screenSurface.drawString(_selfStringArray[i], 4); + break; + case 5: + if (_discussStringArray[i][0] != '*') + _vm->_screenSurface.drawString(_discussStringArray[i], 4); + break; + case 6: + _vm->_screenSurface.drawString(_vm->getEngineString(S_SAVE_LOAD + i), 4); + break; + case 7: { + Common::String s = _vm->getEngineString(S_SAVE_LOAD + 1); + s += ' '; + s += (char)(48 + i); + _vm->_screenSurface.drawString(s, 4); + } + break; + case 8: + if (i == 1) + _vm->_screenSurface.drawString(_vm->getEngineString(S_RESTART), 4); + else { + Common::String s = _vm->getEngineString(S_SAVE_LOAD + 2); + s += ' '; + s += (char)(47 + i); + _vm->_screenSurface.drawString(s, 4); + } + break; + default: + break; + } + _vm->_screenSurface.putxy(minX, _vm->_screenSurface._textPos.y + 8); + } + _multiTitle = true; + _vm->_mouse.showMouse(); +} + +/** + * Menu is being removed, so restore the previous background area. + */ +void Menu::menuUp(int msgId) { + if (_multiTitle) { + /* Restore the background area */ + assert(_vm->_screenSurface.pitch == _vm->_backgroundSurface.pitch); + + // Get a pointer to the source and destination of the area to restore + const byte *pSrc = (const byte *)_vm->_backgroundSurface.getBasePtr(0, 10); + Graphics::Surface destArea = _vm->_screenSurface.lockArea(Common::Rect(0, 10, SCREEN_WIDTH, SCREEN_HEIGHT)); + byte *pDest = (byte *)destArea.getPixels(); + + // Copy the data + Common::copy(pSrc, pSrc + (400 - 10) * SCREEN_WIDTH, pDest); + + _multiTitle = false; + } +} + +/** + * Erase the menu + */ +void Menu::eraseMenu() { + _menuActive = false; + _vm->setMouseClick(false); + menuUp(_msg3); +} + +/** + * Handle updates to the menu + * @remarks Originally called 'mdn' + */ +void Menu::updateMenu() { + if (!_menuActive) + return; + + Common::Point curPos = _vm->_mouse._pos; + if (!_vm->getMouseClick()) { + if (curPos == _vm->_prevPos) + return; + else + _vm->_prevPos = curPos; + + bool tes = (curPos.y < 11) + && ((curPos.x >= (28 * kResolutionScaler) && curPos.x <= (28 * kResolutionScaler + 24)) + || (curPos.x >= (76 * kResolutionScaler) && curPos.x <= (76 * kResolutionScaler + 24)) + || ((curPos.x > 124 * kResolutionScaler) && (curPos.x < 124 * kResolutionScaler + 24)) + || ((curPos.x > 172 * kResolutionScaler) && (curPos.x < 172 * kResolutionScaler + 24)) + || ((curPos.x > 220 * kResolutionScaler) && (curPos.x < 220 * kResolutionScaler + 24)) + || ((curPos.x > 268 * kResolutionScaler) && (curPos.x < 268 * kResolutionScaler + 24))); + if (tes) { + int ix; + + if (curPos.x < 76 * kResolutionScaler) + ix = MENU_INVENTORY; + else if (curPos.x < 124 * kResolutionScaler) + ix = MENU_MOVE; + else if (curPos.x < 172 * kResolutionScaler) + ix = MENU_ACTION; + else if (curPos.x < 220 * kResolutionScaler) + ix = MENU_SELF; + else if (curPos.x < 268 * kResolutionScaler) + ix = MENU_DISCUSS; + else + ix = MENU_FILE; + + if ((ix != _msg3) || (!_multiTitle)) + if (!((ix == MENU_FILE) && ((_msg3 == MENU_SAVE) || (_msg3 == MENU_LOAD)))) { + menuUp(_msg3); + menuDown(ix); + _msg3 = ix; + _msg4 = OPCODE_NONE; + } + } else { // Not in the MenuTitle line + if ((curPos.y > 11) && (_multiTitle)) + util(curPos); + } + } else { // There was a click + if ((_msg3 == MENU_FILE) && (_msg4 != OPCODE_NONE)) { + // Another menu to be _displayed + _vm->setMouseClick(false); + menuUp(_msg3); + if ((_msg4 & 0xFF) == 1) + _msg3 = MENU_SAVE; + else + _msg3 = MENU_LOAD; + menuDown(_msg3); + + _vm->setMouseClick(false); + } else { + // A menu was clicked on + _menuSelected = (_multiTitle) && (_msg4 != OPCODE_NONE); + menuUp(_msg3); + _vm->_currAction = _msg4; + _vm->_currMenu = _msg3; + _msg3 = OPCODE_NONE; + _msg4 = OPCODE_NONE; + + _vm->setMouseClick(false); + } + } +} + +void Menu::setParent(MortevielleEngine *vm) { + _vm = vm; +} + +void Menu::initMenu() { + Common::File f; + + bool enMenuLoaded = false; + if (_vm->getLanguage() == Common::EN_ANY) { + // Open the mort.dat file + if (!f.open(MORT_DAT)) + warning("File %s not found. Using default menu from game data", MORT_DAT); + else { + // Validate the data file header + char fileId[4]; + f.read(fileId, 4); + // Do not display warnings here. They would already have been displayed in MortevielleEngine::loadMortDat(). + if (strncmp(fileId, "MORT", 4) == 0 && f.readByte() >= MORT_DAT_REQUIRED_VERSION) { + f.readByte(); // Minor version + // Loop to load resources from the data file + while (f.pos() < f.size()) { + // Get the Id and size of the next resource + char dataType[4]; + int dataSize; + f.read(dataType, 4); + dataSize = f.readUint16LE(); + if (!strncmp(dataType, "MENU", 4)) { + // MENU section + if (dataSize <= 7 * 24) { + f.read(_charArr, dataSize); + enMenuLoaded = true; + } else + warning("Wrong size %d for menu data. Expected %d or less", dataSize, 7*24); + break; + } else { + // Other sections + f.skip(dataSize); + } + } + } + // Close the file + f.close(); + if (!enMenuLoaded) + warning("Failed to load English menu. Will use default menu from game data instead"); + } + } + + if (!enMenuLoaded) { + if (_vm->getOriginalLanguage() == Common::FR_FRA) { + if (!f.open("menufr.mor")) + error("Missing file - menufr.mor"); + } else { // Common::DE_DEU + if (!f.open("menual.mor")) + error("Missing file - menual.mor"); + } + f.read(_charArr, 7 * 24); + f.close(); + } + + // Skipped: dialog asking to swap floppy + + for (int i = 1; i <= 8; ++i) + _inventoryStringArray[i] = "* "; + _inventoryStringArray[7] = "< -*-*-*-*-*-*-*-*-*- "; + for (int i = 1; i <= 7; ++i) + _moveStringArray[i] = "* "; + for (int i = 1; i < 22; i++) { + _actionStringArray[i] = _vm->getString(i + kMenuActionStringIndex); + + while (_actionStringArray[i].size() < 10) + _actionStringArray[i] += ' '; + + if (i < 9) { + if (i < 6) { + _selfStringArray[i] = _vm->getString(i + kMenuSelfStringIndex); + while (_selfStringArray[i].size() < 10) + _selfStringArray[i] += ' '; + } + _discussStringArray[i] = _vm->getString(i + kMenuSayStringIndex) + ' '; + } + } + for (int i = 1; i <= 8; ++i) { + _discussMenu[i]._menuId = MENU_DISCUSS; + _discussMenu[i]._actionId = i; + if (i < 8) { + _moveMenu[i]._menuId = MENU_MOVE; + _moveMenu[i]._actionId = i; + } + _inventoryMenu[i]._menuId = MENU_INVENTORY; + _inventoryMenu[i]._actionId = i; + if (i > 6) + disableMenuItem(_inventoryMenu[i]); + } + _msg3 = OPCODE_NONE; + _msg4 = OPCODE_NONE; + _vm->_currMenu = OPCODE_NONE; + _vm->_currAction = OPCODE_NONE; + _vm->setMouseClick(false); +} + +/** + * Engine function - Switch action menu to "Search" mode + * @remarks Originally called 'mfoudi' + */ +void Menu::setSearchMenu() { + for (int i = 1; i <= 7; ++i) + disableMenuItem(_moveMenu[i]); + + for (int i = 1; i <= 11; ++i) + disableMenuItem(_actionMenu[i]); + + MenuItem miSound; + miSound._menuId = _opcodeSound >> 8; + miSound._actionId = _opcodeSound & 0xFF; + + MenuItem miLift; + miLift._menuId = _opcodeLift >> 8; + miLift._actionId = _opcodeLift & 0xFF; + + setText(miSound, _vm->getEngineString(S_SUITE)); + setText(miLift, _vm->getEngineString(S_STOP)); +} + +/** + * Engine function - Switch action menu from "Search" mode back to normal mode + * @remarks Originally called 'mfouen' + */ +void Menu::unsetSearchMenu() { + setDestinationText(_vm->_coreVar._currPlace); + for (int i = 1; i <= 11; ++i) + enableMenuItem(_actionMenu[i]); + + MenuItem miSound; + miSound._menuId = _opcodeSound >> 8; + miSound._actionId = _opcodeSound & 0xFF; + + MenuItem miLift; + miLift._menuId = _opcodeLift >> 8; + miLift._actionId = _opcodeLift & 0xFF; + + setText(miSound, _vm->getEngineString(S_PROBE)); + setText(miLift, _vm->getEngineString(S_RAISE)); +} + +/** + * Set Inventory menu texts + * @remarks Originally called 'modinv' + */ +void Menu::setInventoryText() { + Common::String nomp; + + int cy = 0; + for (int i = 1; i <= 6; ++i) { + if (_vm->_coreVar._inventory[i] != 0) { + ++cy; + int r = _vm->_coreVar._inventory[i] + 400; + nomp = _vm->getString(r - 501 + kInventoryStringIndex); + setText(_inventoryMenu[cy], nomp); + enableMenuItem(_inventoryMenu[i]); + } + } + + if (cy < 6) { + for (int i = cy + 1; i <= 6; ++i) { + setText(_inventoryMenu[i], " "); + disableMenuItem(_inventoryMenu[i]); + } + } +} +} // End of namespace Mortevielle diff --git a/engines/mortevielle/menu.h b/engines/mortevielle/menu.h new file mode 100644 index 0000000000..d1271bca2e --- /dev/null +++ b/engines/mortevielle/menu.h @@ -0,0 +1,125 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#ifndef MORTEVIELLE_MENU_H +#define MORTEVIELLE_MENU_H + +#include "common/rect.h" +#include "common/str.h" + +namespace Mortevielle { +class MortevielleEngine; + +enum { + MENU_NONE = 0, MENU_INVENTORY = 1, MENU_MOVE = 2, MENU_ACTION = 3, + MENU_SELF = 4, MENU_DISCUSS = 5, MENU_FILE = 6, MENU_SAVE = 7, + MENU_LOAD = 8 +}; + +const int OPCODE_NONE = 0; + +struct MenuItem { + int _menuId; + int _actionId; +}; + +class Menu { +private: + MortevielleEngine *_vm; + + byte _charArr[7][24]; + int _msg3; + int _msg4; + + void util(Common::Point pos); + void invert(int indx); + void menuDown(int ii); + +public: + Menu(); + + bool _menuActive; + bool _menuSelected; + bool _multiTitle; + bool _menuDisplayed; + Common::String _inventoryStringArray[9]; + Common::String _moveStringArray[8]; + Common::String _actionStringArray[22]; + Common::String _selfStringArray[7]; + Common::String _discussStringArray[9]; + MenuItem _discussMenu[9]; + MenuItem _inventoryMenu[9]; + MenuItem _moveMenu[8]; + + int _opcodeAttach; + int _opcodeWait; + int _opcodeForce; + int _opcodeSleep; + int _opcodeListen; + int _opcodeEnter; + int _opcodeClose; + int _opcodeSearch; + int _opcodeKnock; + int _opcodeScratch; + int _opcodeRead; + int _opcodeEat; + int _opcodePlace; + int _opcodeOpen; + int _opcodeTake; + int _opcodeLook; + int _opcodeSmell; + int _opcodeSound; + int _opcodeLeave; + int _opcodeLift; + int _opcodeTurn; + int _opcodeSHide; + int _opcodeSSearch; + int _opcodeSRead; + int _opcodeSPut; + int _opcodeSLook; + MenuItem _actionMenu[12]; + + void setParent(MortevielleEngine *vm); + void readVerbNums(Common::File &f, int dataSize); + void setText(MenuItem item, Common::String name); + void setDestinationText(int roomId); + void setInventoryText(); + void disableMenuItem(MenuItem item); + void enableMenuItem(MenuItem item); + void displayMenu(); + void drawMenu(); + void menuUp(int msgId); + void eraseMenu(); + void updateMenu(); + void initMenu(); + + void setSearchMenu(); + void unsetSearchMenu(); +}; + +} // End of namespace Mortevielle +#endif diff --git a/engines/mortevielle/module.mk b/engines/mortevielle/module.mk new file mode 100644 index 0000000000..a9f02c2a67 --- /dev/null +++ b/engines/mortevielle/module.mk @@ -0,0 +1,23 @@ +MODULE := engines/mortevielle + +MODULE_OBJS := \ + actions.o \ + debugger.o \ + detection.o \ + dialogs.o \ + graphics.o \ + menu.o \ + mortevielle.o \ + mouse.o \ + outtext.o \ + saveload.o \ + sound.o \ + utils.o + +# This module can be built as a plugin +ifeq ($(ENABLE_MORTEVIELLE), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/mortevielle/mortevielle.cpp b/engines/mortevielle/mortevielle.cpp new file mode 100644 index 0000000000..7748ce9371 --- /dev/null +++ b/engines/mortevielle/mortevielle.cpp @@ -0,0 +1,435 @@ +/* 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#include "mortevielle/mortevielle.h" + +#include "mortevielle/dialogs.h" +#include "mortevielle/menu.h" +#include "mortevielle/mouse.h" +#include "mortevielle/outtext.h" +#include "mortevielle/saveload.h" +#include "mortevielle/outtext.h" + +#include "common/system.h" +#include "common/config-manager.h" +#include "common/debug-channels.h" +#include "engines/util.h" +#include "engines/engine.h" +#include "graphics/palette.h" +#include "graphics/pixelformat.h" + +namespace Mortevielle { + +MortevielleEngine *g_vm; + +MortevielleEngine::MortevielleEngine(OSystem *system, const MortevielleGameDescription *gameDesc): + Engine(system), _gameDescription(gameDesc), _randomSource("mortevielle"), + _soundManager(_mixer) { + g_vm = this; + _debugger.setParent(this); + _dialogManager.setParent(this); + _screenSurface.setParent(this); + _mouse.setParent(this); + _text.setParent(this); + _soundManager.setParent(this); + _savegameManager.setParent(this); + _menu.setParent(this); + + _lastGameFrame = 0; + _mouseClick = false; + _inMainGameLoop = false; + _quitGame = false; + + _roomPresenceLuc = false; + _roomPresenceIda = false; + _purpleRoomPresenceLeo = false; + _roomPresenceGuy = false; + _roomPresenceEva = false; + _roomPresenceMax = false; + _roomPresenceBob = false; + _roomPresencePat = false; + _toiletsPresenceBobMax = false; + _bathRoomPresenceBobMax = false; + _juliaRoomPresenceLeo = false; + + _soundOff = false; + _largestClearScreen = false; + _hiddenHero = false; + _heroSearching = false; + _keyPressedEsc = false; + _reloadCFIEC = false; + + _blo = false; + _col = false; + _syn = false; + _obpart = false; + _destinationOk = false; + _anyone = false; + _uptodatePresence = false; + + _textColor = 0; + _place = -1; + + _x26KeyCount = -1; + _caff = -1; + _day = 0; + + _curPict = nullptr; + _curAnim = nullptr; + _rightFramePict = nullptr; +} + +MortevielleEngine::~MortevielleEngine() { + free(_curPict); + free(_curAnim); + free(_rightFramePict); +} + +/** + * Specifies whether the engine supports given features + */ +bool MortevielleEngine::hasFeature(EngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsLoadingDuringRuntime) || + (f == kSupportsSavingDuringRuntime); +} + +/** + * Return true if a game can currently be loaded + */ +bool MortevielleEngine::canLoadGameStateCurrently() { + // Saving is only allowed in the main game event loop + return _inMainGameLoop; +} + +/** + * Return true if a game can currently be saved + */ +bool MortevielleEngine::canSaveGameStateCurrently() { + // Loading is only allowed in the main game event loop + return _inMainGameLoop; +} + +/** + * Load in a savegame at the specified slot number + */ +Common::Error MortevielleEngine::loadGameState(int slot) { + return _savegameManager.loadGame(slot); +} + +/** + * Save the current game + */ +Common::Error MortevielleEngine::saveGameState(int slot, const Common::String &desc) { + if (slot == 0) + return Common::kWritingFailed; + + return _savegameManager.saveGame(slot, desc); +} + +/** + * Support method that generates a savegame name + * @param slot Slot number + */ +Common::String MortevielleEngine::generateSaveFilename(const Common::String &target, int slot) { + if (slot == 0) + // Initial game state loaded when the game starts + return "sav0.mor"; + + return Common::String::format("%s.%03d", target.c_str(), slot); +} + +/** + * Initialize the game state + */ +Common::ErrorCode MortevielleEngine::initialize() { + // Initialize graphics mode + initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT, true); + + // Set debug channels + DebugMan.addDebugChannel(kMortevielleCore, "core", "Core debugging"); + DebugMan.addDebugChannel(kMortevielleGraphics, "graphics", "Graphics debugging"); + + // Set up an intermediate screen surface + _screenSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8()); + + _txxFileFl = false; + // Load texts from TXX files + loadTexts(); + + // Load the mort.dat resource + Common::ErrorCode result = loadMortDat(); + if (result != Common::kNoError) { + _screenSurface.free(); + return result; + } + + // Load some error messages (was previously in chartex()) + _hintPctMessage = getString(580); // You should have noticed %d hints + + // Set default EGA palette + _paletteManager.setDefaultPalette(); + + // Setup the mouse cursor + initMouse(); + + loadPalette(); + loadCFIPH(); + loadCFIEC(); + decodeNumber(&_cfiecBuffer[161 * 16], (_cfiecBufferSize - (161 * 16)) / 64); + _x26KeyCount = 1; + initMaxAnswer(); + initMouse(); + + loadPlaces(); + _soundOff = false; + _largestClearScreen = false; + + testKeyboard(); + showConfigScreen(); + testKeyboard(); + clearScreen(); + + _soundManager.loadNoise(); + _soundManager.loadAmbiantSounds(); + + return Common::kNoError; +} + +/** + * Loads the contents of the mort.dat data file + */ +Common::ErrorCode MortevielleEngine::loadMortDat() { + Common::File f; + + // Open the mort.dat file + if (!f.open(MORT_DAT)) { + GUIErrorMessage("Could not locate 'mort.dat'."); + return Common::kReadingFailed; + } + + // Validate the data file header + char fileId[4]; + f.read(fileId, 4); + if (strncmp(fileId, "MORT", 4) != 0) { + GUIErrorMessage("The located mort.dat data file is invalid"); + return Common::kReadingFailed; + } + + // Check the version + if (f.readByte() < MORT_DAT_REQUIRED_VERSION) { + GUIErrorMessage("The located mort.dat data file is too old, please download an updated version on scummvm.org"); + return Common::kReadingFailed; + } + f.readByte(); // Minor version + + // Loop to load resources from the data file + while (f.pos() < f.size()) { + // Get the Id and size of the next resource + char dataType[4]; + int dataSize; + f.read(dataType, 4); + dataSize = f.readUint16LE(); + + if (!strncmp(dataType, "FONT", 4)) { + // Font resource + _screenSurface.readFontData(f, dataSize); + } else if (!strncmp(dataType, "SSTR", 4)) { + readStaticStrings(f, dataSize, kStaticStrings); + } else if ((!strncmp(dataType, "GSTR", 4)) && (!_txxFileFl)) { + readStaticStrings(f, dataSize, kGameStrings); + } else if (!strncmp(dataType, "VERB", 4)) { + _menu.readVerbNums(f, dataSize); + } else { + // Unknown section + f.skip(dataSize); + } + } + + // Close the file + f.close(); + + assert(_engineStrings.size() > 0); + return Common::kNoError; +} + + +/** + * Read in a static strings block, and if the language matches, load up the static strings + */ +void MortevielleEngine::readStaticStrings(Common::File &f, int dataSize, DataType dataType) { + // Figure out what language Id is needed + byte desiredLanguageId; + switch(getLanguage()) { + case Common::EN_ANY: + desiredLanguageId = MORTDAT_LANG_ENGLISH; + break; + case Common::FR_FRA: + desiredLanguageId = MORTDAT_LANG_FRENCH; + break; + case Common::DE_DEU: + desiredLanguageId = MORTDAT_LANG_GERMAN; + break; + default: + warning("Language not supported, switching to English"); + desiredLanguageId = MORTDAT_LANG_ENGLISH; + break; + } + + // Read in the language + byte languageId = f.readByte(); + --dataSize; + + // If the language isn't correct, then skip the entire block + if (languageId != desiredLanguageId) { + f.skip(dataSize); + return; + } + + // Load in each of the strings + while (dataSize > 0) { + Common::String s; + char ch; + while ((ch = (char)f.readByte()) != '\0') + s += ch; + + if (dataType == kStaticStrings) + _engineStrings.push_back(s); + else if (dataType == kGameStrings) + _gameStrings.push_back(s); + + dataSize -= s.size() + 1; + } + assert(dataSize == 0); +} + +/*-------------------------------------------------------------------------*/ + +Common::Error MortevielleEngine::run() { + // Initialize the game + Common::ErrorCode err = initialize(); + if (err != Common::kNoError) + return err; + + // Check for a savegame + int loadSlot = 0; + if (ConfMan.hasKey("save_slot")) { + int gameToLoad = ConfMan.getInt("save_slot"); + if ((gameToLoad >= 1) && (gameToLoad <= 999)) + loadSlot = gameToLoad; + } + + if (loadSlot == 0) + // Show the game introduction + showIntroduction(); + + // Either load the initial game state savegame, or the specified savegame number + adzon(); + if (loadSlot != 0) + _savegameManager.loadSavegame(generateSaveFilename(loadSlot)); + else + resetVariables(); + + // Run the main game loop + mainGame(); + + // Cleanup (allocated in initialize()) + _screenSurface.free(); + free(_soundManager._cfiphBuffer); + free(_cfiecBuffer); + + return Common::kNoError; +} + +/** + * Show the game introduction + */ +void MortevielleEngine::showIntroduction() { + _dialogManager.displayIntroScreen(false); + _dialogManager.checkForF8(142, false); + if (shouldQuit()) + return; + + _dialogManager.displayIntroFrame2(); + _dialogManager.checkForF8(143, true); + if (shouldQuit()) + return; + + showTitleScreen(); + music(); + _mixer->stopAll(); +} + +/** + * Main game loop. Handles potentially playing the game multiple times, such as if the player + * loses, and chooses to start playing the game again. + */ +void MortevielleEngine::mainGame() { + if (_reloadCFIEC) + loadCFIEC(); + + for (_crep = 1; _crep <= _x26KeyCount; ++_crep) + decodeNumber(&_cfiecBuffer[161 * 16], (_cfiecBufferSize - (161 * 16)) / 64); + + _menu.initMenu(); + + charToHour(); + initGame(); + clearScreen(); + drawRightFrame(); + _mouse.showMouse(); + + // Loop to play the game + do { + playGame(); + if (shouldQuit()) + return; + } while (!_quitGame); +} + +/** + * This method handles playing a loaded game + * @remarks Originally called tjouer + */ +void MortevielleEngine::playGame() { + gameLoaded(); + + // Loop handling actions until the game has to be quit, or show the lose or end sequence + do { + handleAction(); + if (shouldQuit()) + return; + } while (!((_quitGame) || (_endGame) || (_loseGame))); + + if (_endGame) + endGame(); + else if (_loseGame) + askRestart(); +} + +} // End of namespace Mortevielle diff --git a/engines/mortevielle/mortevielle.h b/engines/mortevielle/mortevielle.h new file mode 100644 index 0000000000..4c9e57acd1 --- /dev/null +++ b/engines/mortevielle/mortevielle.h @@ -0,0 +1,485 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#ifndef MORTEVIELLE_MORTEVIELLE_H +#define MORTEVIELLE_MORTEVIELLE_H + +#include "common/events.h" +#include "common/file.h" +#include "common/random.h" +#include "common/rect.h" +#include "common/stack.h" +#include "engines/advancedDetector.h" +#include "engines/engine.h" +#include "common/error.h" +#include "graphics/surface.h" +#include "mortevielle/debugger.h" +#include "mortevielle/dialogs.h" +#include "mortevielle/graphics.h" +#include "mortevielle/menu.h" +#include "mortevielle/mouse.h" +#include "mortevielle/saveload.h" +#include "mortevielle/sound.h" +#include "mortevielle/outtext.h" + +namespace Mortevielle { + +// Debug channels +enum { + kMortevielleCore = 1 << 0, + kMortevielleGraphics = 1 << 1, + kMortevielleSounds = 1 << 2 +}; + +// Game languages +enum { + MORTDAT_LANG_FRENCH = 0, + MORTDAT_LANG_ENGLISH = 1, + MORTDAT_LANG_GERMAN = 2 +}; + +// Static string list +enum { + S_YES_NO = 0, S_GO_TO = 1, S_SOMEONE_ENTERS = 2, S_COOL = 3, S_LOURDE = 4, + S_MALSAINE = 5, S_IDEM = 6, S_YOU = 7, S_ARE = 8, S_ALONE = 9, + S_HEAR_NOISE = 10, S_SHOULD_HAVE_NOTICED = 11, S_NUMBER_OF_HINTS = 12, + S_WANT_TO_WAKE_UP = 13, S_OKAY = 14, S_SAVE_LOAD = 15, S_RESTART = 18, S_F3 = 19, + S_F8 = 20, S_HIDE_SELF = 21, S_TAKE = 22, S_PROBE = 23, S_RAISE = 24, S_SUITE = 25, + S_STOP = 26, S_USE_DEP_MENU = 27, S_LIFT = 28, S_READ = 29, + S_LOOK = 30, S_SEARCH = 31, S_OPEN = 32, S_PUT = 33, S_TURN = 34, S_TIE = 35, S_CLOSE = 36, + S_HIT = 37, S_POSE = 38, S_SMASH = 39, + + S_SMELL = 40, S_SCRATCH = 41, S_PROBE2 = 42, S_BEFORE_USE_DEP_MENU = 43, S_DAY = 44 +}; + +enum DataType { + kStaticStrings = 0, + kGameStrings = 1 +}; + +#define SCREEN_WIDTH 640 +#define SCREEN_HEIGHT 400 +#define SCREEN_ORIG_HEIGHT 200 +#define MORT_DAT_REQUIRED_VERSION 1 +#define MORT_DAT "mort.dat" +#define GAME_FRAME_DELAY (1000 / 50) + +const int kTime1 = 410; +const int kTime2 = 250; + +const int kAcha = 492; +const int kFleche = 1758; + +const int kAsoul = 154; +const int kAouvr = 282; +const int kAsearch = 387; +const int kArcf = 1272; +const int kArep = 1314; +const int kAmzon = 1650; +const int kArega = 0; + +const int kMaxDialogIndex = 9000; +const int kMaxDialogHint = 600; + +const int kDescriptionStringIndex = 0; // Unused +const int kInventoryStringIndex = 186; +const int kQuestionStringIndex = 247; +const int kDialogStringIndex = 292; +const int kMenuPlaceStringIndex = 435; +const int kMenuActionStringIndex = 476; +const int kMenuSelfStringIndex = 497; +const int kMenuSayStringIndex = 502; +const int kMaxPatt = 20; + +const int kResolutionScaler = 2; +/* +9 "A glance at the forbidden$", +18 "It's already open$", +26 "A photograph$" +*/ +enum Places { + OWN_ROOM = 0, GREEN_ROOM = 1, PURPLE_ROOM = 2, TOILETS = 3, DARKBLUE_ROOM = 4, + BLUE_ROOM = 5, RED_ROOM = 6, BATHROOM = 7, GREEN_ROOM2 = 8, JULIA_ROOM = 9, + DINING_ROOM = 10, BUREAU = 11, KITCHEN = 12, ATTIC = 13, CELLAR = 14, + LANDING = 15, CRYPT = 16, SECRET_PASSAGE = 17, ROOM18 = 18, MOUNTAIN = 19, + CHAPEL = 20, MANOR_FRONT = 21, MANOR_BACK = 22, INSIDE_WELL = 23, WELL = 24, + 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]; + byte _availableQuestion[43]; + byte _inventory[31]; + int _currPlace; + int _atticBallHoleObjectId; + int _atticRodHoleObjectId; + int _cellarObjectId; + int _secretPassageObjectId; + int _wellObjectId; + int _selectedObjectId; + int _purpleRoomObjectId; + int _cryptObjectId; + bool _alreadyEnteredManor; + byte _fullHour; +}; + +struct Hint { + int _hintId; + byte _point; +}; + +struct MortevielleGameDescription; + +class MortevielleEngine : public Engine { +private: + const MortevielleGameDescription *_gameDescription; + Common::Stack<int> _keypresses; + uint32 _lastGameFrame; + Common::Point _mousePos; + Common::StringArray _engineStrings; + Common::StringArray _gameStrings; + + int _menuOpcode; + + bool _inMainGameLoop; // Flag when the main game loop is active + bool _quitGame; // Quit game flag. Originally called 'arret' + bool _endGame; // End game flag. Originally called 'solu' + bool _loseGame; // Lose game flag. Originally called 'perdu' + bool _txxFileFl; // Flag used to determine if texts are from the original files or from a DAT file + bool _roomPresenceLuc; + bool _roomPresenceIda; + bool _purpleRoomPresenceLeo; + bool _roomPresenceGuy; + bool _roomPresenceEva; + bool _roomPresenceMax; + bool _roomPresenceBob; + bool _roomPresencePat; + bool _toiletsPresenceBobMax; + bool _bathRoomPresenceBobMax; + bool _juliaRoomPresenceLeo; + bool _hiddenHero; + bool _heroSearching; + bool _keyPressedEsc; + bool _reloadCFIEC; + bool _col; + bool _syn; + bool _obpart; + bool _anyone; + bool _uptodatePresence; + + int _textColor; + int _place; + int _manorDistance; + int _currBitIndex; + int _currDay; + int _currHour; + int _currHalfHour; + int _day; + int _hour; + int _minute; + int _curSearchObjId; + int _controlMenu; + int _startHour; + int _endHour; + Common::Point _stdPal[91][17]; + + int _x26KeyCount; + int _roomDoorId; + int _openObjCount; + int _takeObjCount; + int _num; + int _searchCount; + bool _introSpeechPlayed; + int _inGameHourDuration; + int _x; + int _y; + int _currentHourCount; + int _currentDayHour; + + Common::String _hintPctMessage; + byte *_cfiecBuffer; + int _cfiecBufferSize; + int _openObjects[7]; + uint16 _dialogIndexArray[kMaxDialogIndex + 1]; + Hint _dialogHintArray[kMaxDialogHint + 1]; + + Common::ErrorCode initialize(); + Common::ErrorCode loadMortDat(); + void readStaticStrings(Common::File &f, int dataSize, DataType dataType); + void loadFont(Common::File &f); + bool handleEvents(); + void addKeypress(Common::Event &evt); + void initMouse(); + void showIntroduction(); + void mainGame(); + void playGame(); + void handleAction(); + void loadPalette(); + void loadTexts(); + void loadCFIEC(); + void loadCFIPH(); + void showTitleScreen(); + int readclock(); + void palette(int v1); + int checkLeoMaxRandomPresence(); + void interactNPC(); + void initCaveOrCellar(); + void displayControlMenu(); + void displayItemInHand(int objId); + void resetRoomVariables(int roomId); + int getPresenceStats(int &rand, int faithScore, int roomId); + void setPresenceFlags(int roomId); + void testKey(bool d); + void exitRoom(); + void getReadDescription(int objId); + void getSearchDescription(int objId); + int checkLeaveSecretPassage(); + void startDialog(int16 rep); + void endSearch(); + int convertCharacterIndexToBitIndex(int characterIndex); + int convertBitIndexToCharacterIndex(int bitIndex); + void clearUpperLeftPart(); + void clearDescriptionBar(); + void clearVerbBar(); + void clearUpperRightPart(); + int getRandomNumber(int minval, int maxval); + void showMoveMenuAlert(); + void showConfigScreen(); + void decodeNumber(byte *pStart, int count); + void resetVariables(); + void music(); + void drawRightFrame(); + void prepareRoom(); + void drawClock(); + void checkManorDistance(); + void gotoManorFront(); + void gotoManorBack(); + void gotoDiningRoom(); + bool checkInventory(int objectId); + void loseGame(); + void floodedInWell(); + void displayDiningRoom(); + void startMusicOrSpeech(int so); + void setTextColor(int col); + void prepareScreenType1(); + void prepareScreenType2(); + void prepareScreenType3(); + void updateHour(int &day, int &hour, int &minute); + void getKnockAnswer(); + int getPresenceStatsGreenRoom(); + int getPresenceStatsPurpleRoom(); + int getPresenceStatsToilets(); + int getPresenceStatsBlueRoom(); + int getPresenceStatsRedRoom(); + int getPresenceStatsDiningRoom(int &hour); + int getPresenceStatsBureau(int &hour); + int getPresenceStatsKitchen(); + int getPresenceStatsAttic(); + int getPresenceStatsLanding(); + int getPresenceStatsChapel(int &hour); + int getPresenceBitIndex(int roomId); + void setPresenceGreenRoom(int roomId); + void setPresencePurpleRoom(); + void setPresenceBlueRoom(); + void setPresenceRedRoom(int roomId); + int setPresenceDiningRoom(int hour); + int setPresenceBureau(int hour); + int setPresenceKitchen(); + int setPresenceLanding(); + int setPresenceChapel(int hour); + void setRandomPresenceGreenRoom(int faithScore); + void setRandomPresencePurpleRoom(int faithScore); + void setRandomPresenceBlueRoom(int faithScore); + void setRandomPresenceRedRoom(int faithScore); + void setRandomPresenceJuliaRoom(int faithScore); + void setRandomPresenceDiningRoom(int faithScore); + void setRandomPresenceBureau(int faithScore); + void setRandomPresenceKitchen(int faithScore); + void setRandomPresenceAttic(int faithScore); + void setRandomPresenceLanding(int faithScore); + void setRandomPresenceChapel(int faithScore); + void loadPlaces(); + void resetPresenceInRooms(int roomId); + void showPeoplePresent(int bitIndex); + int selectCharacters(int min, int max); + void fctMove(); + void fctTake(); + void fctInventoryTake(); + void fctLift(); + void fctRead(); + void fctSelfRead(); + void fctLook(); + void fctSelftLook(); + void fctSearch(); + void fctSelfSearch(); + void fctOpen(); + void fctPlace(); + void fctTurn(); + void fctSelfHide(); + void fctAttach(); + void fctClose(); + void fctKnock(); + void fctSelfPut(); + void fctListen(); + void fctEat(); + void fctEnter(); + void fctSleep(); + void fctForce(); + void fctLeave(); + void fctWait(); + void fctSound(); + void fctDiscuss(); + void fctSmell(); + void fctScratch(); + void endGame(); + void askRestart(); + void handleOpcode(); + void prepareDisplayText(); + bool decryptNextChar(char &c, int &idx, byte &pt); + void displayStatusArrow(); + void displayStatusInDescriptionBar(char stat); + void displayQuestionText(Common::String s, int cmd); + void displayTextInDescriptionBar(int x, int y, int nb, int mesgId); + void displayTextInVerbBar(Common::String text); + void displayTextBlock(Common::String text); + void mapMessageId(int &mesgId); + void resetOpenObjects(); + void setCoordinates(int sx); + void drawPicture(); + void drawPictureWithText(); + void addObjectToInventory(int objectId); + void putInHand(int &objId); + void initMaxAnswer(); + void displayAnimFrame(int frameNum, int animId); + int getFirstObject(); + void prepareNextObject(); + void putObject(); + void resetObjectPlace(); + void drawDiscussionBox(); + void displayNarrativePicture(int af, int ob); + void menuUp(); + void displayLookScreen(int objId); + + void adzon(); + +public: + Common::Point _prevPos; + int _currMenu; + int _currAction; + int _drawingSizeArr[108]; + int _charAnswerCount[9]; + int _charAnswerMax[9]; + byte _tabdon[4001]; + bool _soundOff; + bool _blo; + bool _destinationOk; + bool _largestClearScreen; + float _addFix; + int _savedBitIndex; + int _numpal; + int _key; + bool _mouseClick; + SaveStruct _coreVar, _saveStruct; + + int _maff; + int _caff; + int _crep; + + byte _destinationArray[7][25]; + + byte *_curPict; + byte *_curAnim; + byte *_rightFramePict; + + Debugger _debugger; + ScreenSurface _screenSurface; + PaletteManager _paletteManager; + GfxSurface _backgroundSurface; + Common::RandomSource _randomSource; + SoundManager _soundManager; + SavegameManager _savegameManager; + Menu _menu; + MouseHandler _mouse; + TextHandler _text; + DialogManager _dialogManager; + + MortevielleEngine(OSystem *system, const MortevielleGameDescription *gameDesc); + ~MortevielleEngine(); + virtual bool hasFeature(EngineFeature f) const; + virtual bool canLoadGameStateCurrently(); + virtual bool canSaveGameStateCurrently(); + virtual Common::Error loadGameState(int slot); + virtual Common::Error saveGameState(int slot, const Common::String &desc); + virtual Common::Error run(); + uint32 getGameFlags() const; + Common::Language getLanguage() const; + Common::Language getOriginalLanguage() const; + static Common::String generateSaveFilename(const Common::String &target, int slot); + Common::String generateSaveFilename(int slot) { return generateSaveFilename(_targetName, slot); } + + int getChar(); + bool keyPressed(); + Common::Point getMousePos() const { return _mousePos; } + void setMousePos(const Common::Point &pt); + bool getMouseClick() const { return _mouseClick; } + void setMouseClick(bool v) { _mouseClick = v; } + Common::String getEngineString(int idx) const { return _engineStrings[idx]; } + Common::String getGameString(int idx) const { return _gameStrings[idx]; } + + void delay(int amount); + void gameLoaded(); + void initGame(); + void displayAloneText(); + void draw(int x, int y); + void charToHour(); + void hourToChar(); + Common::String getString(int num); + void setPal(int n); + Common::String copy(const Common::String &s, int idx, size_t size); + void testKeyboard(); + int getPresence(int roomId); + void displayEmptyHand(); + void displayPicture(const byte *pic, int x, int y); + + int gettKeyPressed(); + void handleDescriptionText(int f, int mesgId); + int getAnimOffset(int frameNum, int animNum); + + void clearScreen(); +}; + +extern MortevielleEngine *g_vm; + +} // End of namespace Mortevielle + +#endif diff --git a/engines/mortevielle/mouse.cpp b/engines/mortevielle/mouse.cpp new file mode 100644 index 0000000000..9eb4e129c0 --- /dev/null +++ b/engines/mortevielle/mouse.cpp @@ -0,0 +1,273 @@ +/* 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#include "mortevielle/mortevielle.h" +#include "mortevielle/mouse.h" + +#include "common/endian.h" +#include "common/rect.h" + +namespace Mortevielle { + +/** + * Initialize the mouse + * @remarks Originally called 'init_mouse' + */ +void MouseHandler::initMouse() { + _counter = 0; + _pos = Common::Point(0, 0); + + _vm->setMouseClick(false); +} + +/** + * Backs up the area behind where the mouse cursor is to be drawn + * @remarks Originally called 'hide_mouse' + */ +void MouseHandler::hideMouse() { + // No implementation needed in ScummVM +} + +/** + * Draws the mouse cursor + * @remarks Originally called 'show_mouse' + */ +void MouseHandler::showMouse() { + // ScummVM implementation uses CursorMan for drawing the cursor +} + +/** + * Set mouse position + * @remarks Originally called 'pos_mouse' + */ +void MouseHandler::setMousePosition(Common::Point newPos) { + if (newPos.x > 314 * kResolutionScaler) + newPos.x = 314 * kResolutionScaler; + else if (newPos.x < 0) + newPos.x = 0; + if (newPos.y > 199) + newPos.y = 199; + else if (newPos.y < 0) + newPos.y = 0; + if (newPos == _pos) + return; + + // Set the new position + _vm->setMousePos(newPos); +} + +/** + * Get mouse poisition + * @remarks Originally called 'read_pos_mouse' + */ +void MouseHandler::getMousePosition(int &x, int &y, bool &click) { + x = _vm->getMousePos().x; + y = _vm->getMousePos().y; + click = _vm->getMouseClick(); +} + +/** + * Move mouse + * @remarks Originally called 'mov_mouse' + */ +void MouseHandler::moveMouse(bool &funct, char &key) { + bool p_key; + char in1, in2; + int cx, cy; + bool click; + + // Set defaults and check pending events + funct = false; + key = '\377'; + p_key = _vm->keyPressed(); + + // If mouse button clicked, return it + if (_vm->getMouseClick()) + return; + + // Handle any pending keypresses + while (p_key) { + if (_vm->shouldQuit()) + return; + + in1 = _vm->getChar(); + getMousePosition(cx, cy, click); + switch (toupper(in1)) { + case '4': + cx -= 8; + break; + case '2': + cy += 8; + break; + case '6': + cx += 8; + break; + case '8': + cy -= 8; + break; + case '7': + cy = 1; + cx = 1; + break; + case '1': + cx = 1; + cy = 190; + break; + case '9': + cx = 315 * kResolutionScaler; + cy = 1; + break; + case '3': + cy = 190; + cx = 315 * kResolutionScaler; + break; + case '5': + cy = 100; + cx = 155 * kResolutionScaler; + break; + case ' ': + case '\15': + _vm->setMouseClick(true); + return; + break; + case '\33': + p_key = _vm->keyPressed(); + + if (p_key) { + in2 = _vm->getChar(); + + if ((in2 >= ';') && (in2 <= 'D')) { + funct = true; + key = in2; + return; + } else { + switch (in2) { + case 'K': + --cx; + break; + case 'P': + ++cy; + break; + case 'M': + cx += 2; + break; + case 'H': + --cy; + break; + case 'G': + --cx; + --cy; + break; + case 'I': + ++cx; + --cy; + break; + case 'O': + --cx; + ++cy; + break; + case 'Q': + ++cx; + ++cy; + break; + default: + break; + } // case + } + } + break; + case 'I': + cx = kResolutionScaler * 32; + cy = 8; + break; + case 'D': + cx = 80 * kResolutionScaler; + cy = 8; + break; + case 'A': + cx = 126 * kResolutionScaler; + cy = 8; + break; + case 'S': + cx = 174 * kResolutionScaler; + cy = 8; + break; + case 'P': + cx = 222 * kResolutionScaler; + cy = 8; + break; + case 'F': + cx = kResolutionScaler * 270; + cy = 8; + break; + case '\23': + _vm->_soundOff = !_vm->_soundOff; + return; + break; + case '\24': // ^T => mode tandy + funct = true; + key = '\11'; + break; + case '\10': // ^H => mode Hercule + funct = true; + key = '\7'; + break; + case '\1': + case '\3': + case '\5': + funct = true; + key = in1; + break; + default: + break; + } + + setMousePosition(Common::Point(cx, cy)); + p_key = _vm->keyPressed(); + } +} + +/** + * Mouse function : Is mouse in a given rect? + * @remarks Originally called 'dans_rect' + */ +bool MouseHandler::isMouseIn(Common::Rect r) { + int x, y; + bool click; + + getMousePosition(x, y, click); + if ((x > r.left) && (x < r.right) && (y > r.top) && (y < r.bottom)) + return true; + + return false; +} + +void MouseHandler::setParent(MortevielleEngine *vm) { + _vm = vm; +} + +} // End of namespace Mortevielle diff --git a/engines/mortevielle/mouse.h b/engines/mortevielle/mouse.h new file mode 100644 index 0000000000..1b9856e2c4 --- /dev/null +++ b/engines/mortevielle/mouse.h @@ -0,0 +1,56 @@ +/* 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#ifndef MORTEVIELLE_MOUSE_H +#define MORTEVIELLE_MOUSE_H + +#include "common/rect.h" + +namespace Mortevielle { +class MortevielleEngine; + +class MouseHandler { +private: + MortevielleEngine *_vm; + + int s_s[12][6]; + int _counter; +public: + Common::Point _pos; + + void setParent(MortevielleEngine *vm); + void initMouse(); + void hideMouse(); + void showMouse(); + void setMousePosition(Common::Point newPos); + void getMousePosition(int &x, int &y, bool &click); + void moveMouse(bool &funct, char &key); + bool isMouseIn(Common::Rect r); +}; + +} // End of namespace Mortevielle +#endif diff --git a/engines/mortevielle/outtext.cpp b/engines/mortevielle/outtext.cpp new file mode 100644 index 0000000000..d50f4005de --- /dev/null +++ b/engines/mortevielle/outtext.cpp @@ -0,0 +1,308 @@ +/* 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#include "mortevielle/mortevielle.h" +#include "mortevielle/mouse.h" +#include "mortevielle/outtext.h" +#include "mortevielle/graphics.h" + +#include "common/file.h" +#include "common/str.h" + +namespace Mortevielle { + +/** + * Next word + * @remarks Originally called 'l_motsuiv' + */ +int TextHandler::nextWord(int p, const char *ch, int &tab) { + int c = p; + + while ((ch[p] != ' ') && (ch[p] != '$') && (ch[p] != '@')) + ++p; + + return tab * (p - c); +} + +/** + * Engine function - Display Text + * @remarks Originally called 'afftex' + */ +void TextHandler::displayStr(Common::String inputStr, int x, int y, int dx, int dy, int typ) { + Common::String s; + int i, j; + + // Safeguard: add $ just in case + inputStr += '$'; + + _vm->_screenSurface.putxy(x, y); + int tab = 6; + dx *= 6; + dy *= 6; + int xc = x; + int yc = y; + int xf = x + dx; + int yf = y + dy; + int p = 0; + bool stringParsed = (inputStr[p] == '$'); + s = ""; + while (!stringParsed) { + switch (inputStr[p]) { + case '@': + _vm->_screenSurface.drawString(s, typ); + s = ""; + ++p; + xc = x; + yc += 6; + _vm->_screenSurface.putxy(xc, yc); + break; + case ' ': + s += ' '; + xc += tab; + ++p; + if (nextWord(p, inputStr.c_str(), tab) + xc > xf) { + _vm->_screenSurface.drawString(s, typ); + s = ""; + xc = x; + yc += 6; + if (yc > yf) { + while (!_vm->keyPressed()) + ; + i = y; + do { + j = x; + do { + _vm->_screenSurface.putxy(j, i); + _vm->_screenSurface.drawString(" ", 0); + j += 6; + } while (j <= xf); + i += 6; + } while (i <= yf); + yc = y; + } + _vm->_screenSurface.putxy(xc, yc); + } + break; + case '$': + stringParsed = true; + _vm->_screenSurface.drawString(s, typ); + break; + default: + s += inputStr[p]; + ++p; + xc += tab; + break; + } + } +} + +/** + * Load DES (picture container) file + * @remarks Originally called 'chardes' + */ +void TextHandler::loadPictureFile(Common::String filename, Common::String altFilename, int32 skipSize, int length) { + Common::File f; + if (!f.open(filename)) { + if (!f.open(altFilename)) + error("Missing file: Either %s or %s", filename.c_str(), altFilename.c_str()); + } + // HACK: The original game contains a bug in the 2nd intro screen, in German DOS version. + // The size specified in the fxx array is wrong (too short). In order to fix it, we are using + // the value -1 to force a variable read length. + if (length == -1) + length = f.size() - skipSize; + + assert(skipSize + length <= f.size()); + + free(_vm->_curPict); + _vm->_curPict = (byte *)malloc(sizeof(byte) * length); + f.seek(skipSize); + f.read(_vm->_curPict, length); + f.close(); +} + +/** + * Load ANI file + * @remarks Originally called 'charani' + */ +void TextHandler::loadAniFile(Common::String filename, int32 skipSize, int length) { + Common::File f; + if (!f.open(filename)) + error("Missing file - %s", filename.c_str()); + + assert(skipSize + length <= f.size()); + + free(_vm->_curAnim); + _vm->_curAnim = (byte *)malloc(sizeof(byte) * length); + f.seek(skipSize); + f.read(_vm->_curAnim, length); + f.close(); +} + +void TextHandler::taffich() { + static const byte tran1[] = { 121, 121, 138, 139, 120 }; + static const byte tran2[] = { 150, 150, 152, 152, 100, 110, 159, 100, 100 }; + + int cx, drawingSize, npal; + int32 drawingStartPos; + + int a = _vm->_caff; + if ((a >= 153) && (a <= 161)) + a = tran2[a - 153]; + else if ((a >= 136) && (a <= 140)) + a = tran1[a - 136]; + int b = a; + if (_vm->_maff == a) + return; + + switch (a) { + case 16: + _vm->_coreVar._pctHintFound[9] = '*'; + _vm->_coreVar._availableQuestion[42] = '*'; + break; + case 20: + _vm->_coreVar._availableQuestion[39] = '*'; + if (_vm->_coreVar._availableQuestion[36] == '*') { + _vm->_coreVar._pctHintFound[3] = '*'; + _vm->_coreVar._availableQuestion[38] = '*'; + } + break; + case 24: + _vm->_coreVar._availableQuestion[37] = '*'; + break; + case 30: + _vm->_coreVar._availableQuestion[9] = '*'; + break; + case 31: // Coat of arms + _vm->_coreVar._pctHintFound[4] = '*'; + _vm->_coreVar._availableQuestion[35] = '*'; + break; + case 118: + _vm->_coreVar._availableQuestion[41] = '*'; + break; + case 143: + _vm->_coreVar._pctHintFound[1] = '*'; + break; + case 150: + _vm->_coreVar._availableQuestion[34] = '*'; + break; + case 151: + _vm->_coreVar._pctHintFound[2] = '*'; + break; + default: + break; + } + + _vm->_destinationOk = true; + _vm->_mouse.hideMouse(); + drawingStartPos = 0; + Common::String filename, altFilename; + + if ((a != 50) && (a != 51)) { + _vm->_maff = a; + if (a == 159) + a = 86; + else if (a > 140) + a -= 67; + else if (a > 137) + a -= 66; + else if (a > 99) + a -= 64; + else if (a > 69) + a -= 42; + else if (a > 29) + a -= 5; + else if (a == 26) + a = 24; + else if (a > 18) + --a; + npal = a; + + for (cx = 0; cx <= (a - 1); ++cx) + drawingStartPos += _vm->_drawingSizeArr[cx]; + drawingSize = _vm->_drawingSizeArr[a]; + + altFilename = filename = "DXX.mor"; + } else { + filename = "DZZ.mor"; + altFilename = "DZZALL"; + + if (a == 50) { + // First intro screen + drawingStartPos = 0; + drawingSize = _vm->_drawingSizeArr[87]; + } else { // a == 51 + // Second intro screen + drawingStartPos = _vm->_drawingSizeArr[87]; + // HACK: Force a variable size in order to fix the wrong size used by the German version + drawingSize = -1; + } + _vm->_maff = a; + npal = a + 37; + } + loadPictureFile(filename, altFilename, drawingStartPos, drawingSize); + _vm->_numpal = npal; + _vm->setPal(npal); + + if ((b < 15) || (b == 16) || (b == 17) || (b == 24) || (b == 26) || (b == 50)) { + drawingStartPos = 0; + if ((b < 15) || (b == 16) || (b == 17) || (b == 24) || (b == 26)) { + if (b == 26) + b = 18; + else if (b == 24) + b = 17; + else if (b > 15) + --b; + for (cx = 0; cx <= (b - 1); ++cx) + drawingStartPos += _vm->_drawingSizeArr[cx + 89]; + drawingSize = _vm->_drawingSizeArr[b + 89]; + filename = "AXX.mor"; + } else { // b == 50 + // CHECKME: the size of AZZ.mor is 1280 for the DOS version + // and 1260 for the Amiga version. Maybe the 20 bytes + // are a filler (to get 10 blocks of 128 bytes), + // or the size should be variable. + drawingSize = 1260; + filename = "AZZ.mor"; + } + loadAniFile(filename, drawingStartPos, drawingSize); + } + _vm->_mouse.showMouse(); + 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) + _vm->getPresence(_vm->_coreVar._currPlace); + _vm->_savedBitIndex = 0; + } +} + +void TextHandler::setParent(MortevielleEngine *vm) { + _vm = vm; +} + +} // End of namespace Mortevielle diff --git a/engines/mortevielle/outtext.h b/engines/mortevielle/outtext.h new file mode 100644 index 0000000000..44868036d5 --- /dev/null +++ b/engines/mortevielle/outtext.h @@ -0,0 +1,49 @@ +/* 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#ifndef MORTEVIELLE_OUTTEXT_H +#define MORTEVIELLE_OUTTEXT_H + +#include "common/str.h" + +namespace Mortevielle { +class MortevielleEngine; + +class TextHandler { +private: + MortevielleEngine *_vm; + int nextWord(int p, const char *ch, int &tab); +public: + void setParent(MortevielleEngine *vm); + void displayStr(Common::String inputStr, int x, int y, int dx, int dy, int typ); + void loadPictureFile(Common::String filename, Common::String altFilename, int32 skipSize, int length); + void loadAniFile(Common::String filename, int32 skipSize, int length); + void taffich(); +}; + +} // End of namespace Mortevielle +#endif diff --git a/engines/mortevielle/saveload.cpp b/engines/mortevielle/saveload.cpp new file mode 100644 index 0000000000..651ed07b65 --- /dev/null +++ b/engines/mortevielle/saveload.cpp @@ -0,0 +1,328 @@ +/* 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#include "mortevielle/mortevielle.h" +#include "mortevielle/dialogs.h" +#include "mortevielle/mouse.h" +#include "mortevielle/saveload.h" + +#include "common/file.h" +#include "common/system.h" + +namespace Mortevielle { + +static const char SAVEGAME_ID[4] = { 'M', 'O', 'R', 'T' }; + +void SavegameManager::setParent(MortevielleEngine *vm) { + _vm = vm; +} + +/** + * Handle saving or loading savegame data + */ +void SavegameManager::sync_save(Common::Serializer &sz) { + sz.syncAsSint16LE(g_vm->_saveStruct._faithScore); + for (int i = 0; i < 11; ++i) + sz.syncAsByte(g_vm->_saveStruct._pctHintFound[i]); + for (int i = 0; i < 43; ++i) + sz.syncAsByte(g_vm->_saveStruct._availableQuestion[i]); + for (int i = 0; i < 31; ++i) + sz.syncAsByte(g_vm->_saveStruct._inventory[i]); + + sz.syncAsSint16LE(g_vm->_saveStruct._currPlace); + sz.syncAsSint16LE(g_vm->_saveStruct._atticBallHoleObjectId); + sz.syncAsSint16LE(g_vm->_saveStruct._atticRodHoleObjectId); + sz.syncAsSint16LE(g_vm->_saveStruct._cellarObjectId); + sz.syncAsSint16LE(g_vm->_saveStruct._secretPassageObjectId); + sz.syncAsSint16LE(g_vm->_saveStruct._wellObjectId); + sz.syncAsSint16LE(g_vm->_saveStruct._selectedObjectId); + sz.syncAsSint16LE(g_vm->_saveStruct._purpleRoomObjectId); + sz.syncAsSint16LE(g_vm->_saveStruct._cryptObjectId); + sz.syncAsByte(g_vm->_saveStruct._alreadyEnteredManor); + sz.syncAsByte(g_vm->_saveStruct._fullHour); + + sz.syncBytes(_tabdonSaveBuffer, 391); +} + +/** + * Inner code for loading a saved game + * @remarks Originally called 'takesav' + */ +void SavegameManager::loadSavegame(const Common::String &filename) { + // Try loading first from the save area + Common::SeekableReadStream *stream = g_system->getSavefileManager()->openForLoading(filename); + + Common::File f; + if (stream == NULL) { + if (!f.open(filename)) + error("Unable to open save file '%s'", filename.c_str()); + + stream = f.readStream(f.size()); + f.close(); + } + + // Check whether it's a ScummVM saved game + char buffer[4]; + stream->read(buffer, 4); + if (!strncmp(&buffer[0], &SAVEGAME_ID[0], 4)) { + // Yes, it is, so skip over the savegame header + SavegameHeader header; + readSavegameHeader(stream, header); + delete header.thumbnail; + } else { + stream->seek(0); + } + + // Read the game contents + Common::Serializer sz(stream, NULL); + sync_save(sz); + + g_vm->_coreVar = g_vm->_saveStruct; + for (int i = 0; i <= 389; ++i) + g_vm->_tabdon[i + kAcha] = _tabdonSaveBuffer[i]; + + // Close the stream + delete stream; +} + +/** + * Load a saved game + */ +Common::Error SavegameManager::loadGame(const Common::String &filename) { + g_vm->_mouse.hideMouse(); + g_vm->displayEmptyHand(); + loadSavegame(filename); + + /* Initialization */ + g_vm->charToHour(); + g_vm->initGame(); + g_vm->gameLoaded(); + g_vm->_mouse.showMouse(); + return Common::kNoError; +} + +/** + * Save the game + */ +Common::Error SavegameManager::saveGame(int n, const Common::String &saveName) { + Common::OutSaveFile *f; + int i; + + g_vm->_mouse.hideMouse(); + g_vm->hourToChar(); + + for (i = 0; i <= 389; ++i) + _tabdonSaveBuffer[i] = g_vm->_tabdon[i + kAcha]; + g_vm->_saveStruct = g_vm->_coreVar; + if (g_vm->_saveStruct._currPlace == ROOM26) + g_vm->_saveStruct._currPlace = LANDING; + + Common::String filename = _vm->generateSaveFilename(n); + f = g_system->getSavefileManager()->openForSaving(filename); + + // Write out the savegame header + f->write(&SAVEGAME_ID[0], 4); + + // Write out the header + SavegameHeader header; + writeSavegameHeader(f, saveName); + + // Write out the savegame contents + Common::Serializer sz(NULL, f); + sync_save(sz); + + // Close the save file + f->finalize(); + delete f; + + // Skipped: dialog asking to swap floppy + + g_vm->_mouse.showMouse(); + return Common::kNoError; +} + +Common::Error SavegameManager::loadGame(int slot) { + return loadGame(_vm->generateSaveFilename(slot)); +} + +Common::Error SavegameManager::saveGame(int slot) { + return saveGame(slot, _vm->generateSaveFilename(slot)); +} + +void SavegameManager::writeSavegameHeader(Common::OutSaveFile *out, const Common::String &saveName) { + // Write out a savegame header + out->writeByte(SAVEGAME_VERSION); + + // Write savegame name + out->writeString(saveName); + out->writeByte(0); + + // Get the active palette + uint8 thumbPalette[256 * 3]; + g_system->getPaletteManager()->grabPalette(thumbPalette, 0, 256); + + // Create a thumbnail and save it + Graphics::Surface *thumb = new Graphics::Surface(); + Graphics::Surface s = g_vm->_screenSurface.lockArea(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)); + + ::createThumbnail(thumb, (const byte *)s.getPixels(), SCREEN_WIDTH, SCREEN_HEIGHT, thumbPalette); + Graphics::saveThumbnail(*out, *thumb); + thumb->free(); + delete thumb; + + // Write out the save date/time + TimeDate td; + g_system->getTimeAndDate(td); + out->writeSint16LE(td.tm_year + 1900); + out->writeSint16LE(td.tm_mon + 1); + out->writeSint16LE(td.tm_mday); + out->writeSint16LE(td.tm_hour); + out->writeSint16LE(td.tm_min); +} + +bool SavegameManager::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) { + header.thumbnail = NULL; + + // Get the savegame version + header.version = in->readByte(); + + // Read in the save name + header.saveName.clear(); + char ch; + while ((ch = (char)in->readByte()) != '\0') + header.saveName += ch; + + // Get the thumbnail + header.thumbnail = Graphics::loadThumbnail(*in); + if (!header.thumbnail) + return false; + + // Read in save date/time + header.saveYear = in->readSint16LE(); + header.saveMonth = in->readSint16LE(); + header.saveDay = in->readSint16LE(); + header.saveHour = in->readSint16LE(); + header.saveMinutes = in->readSint16LE(); + + return true; +} + +SaveStateList SavegameManager::listSaves(const Common::String &target) { + Common::String pattern = target; + pattern += ".???"; + + Common::StringArray files = g_system->getSavefileManager()->listSavefiles(pattern); + sort(files.begin(), files.end()); // Sort (hopefully ensuring we are sorted numerically..) + + SaveStateList saveList; + for (Common::StringArray::const_iterator file = files.begin(); file != files.end(); ++file) { + // Obtain the last 3 digits of the filename, since they correspond to the save slot + const Common::String &fname = *file; + int slotNumber = atoi(fname.c_str() + fname.size() - 3); + + Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fname); + if (in) { + // There can be two types of savegames: original interpreter savegames, and ScummVM savegames. + // Original interpreter savegames are 497 bytes, and still need to be supported because the + // initial game state is stored as a savegame + bool validFlag = false; + Common::String saveDescription; + + char buffer[4]; + in->read(buffer, 4); + if (!strncmp(&buffer[0], &SAVEGAME_ID[0], 4)) { + // ScummVm savegame. Read in the header to get the savegame name + SavegameHeader header; + validFlag = readSavegameHeader(in, header); + + if (validFlag) { + delete header.thumbnail; + saveDescription = header.saveName; + } + } else if (file->size() == 497) { + // Form an appropriate savegame name + saveDescription = (slotNumber == 0) ? "Initial game state" : + Common::String::format("Savegame #%d", slotNumber); + validFlag = true; + } + + if (validFlag) + // Got a valid savegame + saveList.push_back(SaveStateDescriptor(slotNumber, saveDescription)); + + delete in; + } + } + + return saveList; +} + +SaveStateDescriptor SavegameManager::querySaveMetaInfos(const Common::String &fileName) { + Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fileName); + + if (f) { + // Get the slot number + int slot = 1; + if (fileName.size() > 4 && fileName[fileName.size() - 4] == '.') + slot = atoi(fileName.c_str() + fileName.size() - 3); + + // Check to see if it's a ScummVM savegame or not + char buffer[4]; + f->read(buffer, 4); + + bool hasHeader = !strncmp(&buffer[0], &SAVEGAME_ID[0], 4); + + if (!hasHeader) { + // Original savegame perhaps? + delete f; + + SaveStateDescriptor desc(slot, Common::String::format("Savegame - %03d", slot)); + desc.setDeletableFlag(slot != 0); + desc.setWriteProtectedFlag(slot == 0); + return desc; + } else { + // Get the savegame header information + SavegameHeader header; + readSavegameHeader(f, header); + delete f; + + // Create the return descriptor + SaveStateDescriptor desc(slot, header.saveName); + desc.setDeletableFlag(true); + desc.setWriteProtectedFlag(false); + desc.setThumbnail(header.thumbnail); + desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay); + desc.setSaveTime(header.saveHour, header.saveMinutes); + + return desc; + } + } + + return SaveStateDescriptor(); +} + +} // End of namespace Mortevielle diff --git a/engines/mortevielle/saveload.h b/engines/mortevielle/saveload.h new file mode 100644 index 0000000000..0121a04d8e --- /dev/null +++ b/engines/mortevielle/saveload.h @@ -0,0 +1,73 @@ +/* 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#ifndef MORTEVIELLE_SAVELOAD_H +#define MORTEVIELLE_SAVELOAD_H + +#include "common/savefile.h" +#include "common/serializer.h" +#include "graphics/palette.h" +#include "graphics/scaler.h" +#include "graphics/thumbnail.h" + +#define SAVEGAME_VERSION 1 + +namespace Mortevielle { + +struct SavegameHeader { + uint8 version; + Common::String saveName; + Graphics::Surface *thumbnail; + int saveYear, saveMonth, saveDay; + int saveHour, saveMinutes; + int totalFrames; +}; + +class MortevielleEngine; + +class SavegameManager { +private: + MortevielleEngine *_vm; + byte _tabdonSaveBuffer[391]; + + void sync_save(Common::Serializer &sz); +public: + void setParent(MortevielleEngine *vm); + void loadSavegame(const Common::String &filename); + Common::Error loadGame(const Common::String &filename); + Common::Error saveGame(int n, const Common::String &saveName); + Common::Error loadGame(int slot); + Common::Error saveGame(int slot); + + void writeSavegameHeader(Common::OutSaveFile *out, const Common::String &saveName); + static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header); + static SaveStateList listSaves(const Common::String &target); + static SaveStateDescriptor querySaveMetaInfos(const Common::String &fileName); +}; + +} // End of namespace Mortevielle +#endif diff --git a/engines/mortevielle/sound.cpp b/engines/mortevielle/sound.cpp new file mode 100644 index 0000000000..3bea96b92f --- /dev/null +++ b/engines/mortevielle/sound.cpp @@ -0,0 +1,796 @@ +/* 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#include "mortevielle/mortevielle.h" +#include "mortevielle/sound.h" + +#include "audio/decoders/raw.h" +#include "common/scummsys.h" + +namespace Mortevielle { + + const byte _tnocon[364] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + const byte _intcon[26] = {1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}; + const byte _typcon[26] = {0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3}; + const byte _tabdph[16] = {0, 10, 2, 0, 2, 10, 3, 0, 3, 7, 5, 0, 6, 7, 7, 10}; + const byte _tabdbc[18] = {7, 23, 7, 14, 13, 9, 14, 9, 5, 12, 6, 12, 13, 4, 0, 4, 5, 9}; + +SoundManager::SoundManager(Audio::Mixer *mixer) { + _mixer = mixer; + _audioStream = nullptr; + _ambiantNoiseBuf = nullptr; + _noiseBuf = nullptr; + + _soundType = 0; + _phonemeNumb = 0; + + for (int i = 0; i < 3; i++) { + _queue[i]._val = 0; + _queue[i]._code = 0; + _queue[i]._acc = 0; + _queue[i]._freq = 0; + _queue[i]._rep = 0; + } + _buildingSentence = false; +} + +SoundManager::~SoundManager() { + if (_audioStream) + _audioStream->finish(); + free(_ambiantNoiseBuf); + free(_noiseBuf); +} + +/** + * Decode music data + */ +int SoundManager::decodeMusic(const byte *PSrc, byte *PDest, int size) { + static const int tab[16] = { -96, -72, -48, -32, -20, -12, -8, -4, 0, 4, 8, 12, 20, 32, 48, 72 }; + + uint seed = 128; + int v; + int decompSize = 0; + int skipSize = 0; + + for (int idx1 = 0; idx1 < size; ++idx1) { + byte srcByte = *PSrc++; + v = tab[srcByte >> 4]; + seed += v; + *PDest++ = seed & 0xff; + + v = tab[srcByte & 0xf]; + seed += v; + *PDest++ = seed & 0xff; + + if (srcByte == 0) + skipSize += 2; + else { + decompSize += skipSize + 2; + skipSize = 0; + } + } + return decompSize; +} + +/** + * Load sonmus.mor file + * @remarks Originally called 'charge_son' + */ +void SoundManager::loadAmbiantSounds() { + Common::File f; + if (!f.open("sonmus.mor")) + error("Missing file - sonmus.mor"); + + free(_ambiantNoiseBuf); + int size = f.size(); + byte *compMusicBuf1 = (byte *)malloc(sizeof(byte) * size); + _ambiantNoiseBuf = (byte *)malloc(sizeof(byte) * size * 2); + f.read(compMusicBuf1, size); + f.close(); + + decodeMusic(compMusicBuf1, _ambiantNoiseBuf, size); + free(compMusicBuf1); +} + +/** + * Speech function - Load Noise files + * @remarks Originally called 'charge_bruit' and 'charge_bruit5' + */ +void SoundManager::loadNoise() { + Common::File f1, f2; + + if (!f1.open("bruits")) //Translation: "noise" + error("Missing file - bruits"); + if (!f2.open("bruit5")) + error("Missing file - bruit5"); + + _noiseBuf = (byte *)malloc(sizeof(byte) * (f1.size() + f2.size())); + assert(f1.size() > 32000); + + f1.read(_noiseBuf, 32000); // 250 * 128 + f2.read(&_noiseBuf[32000], f2.size()); + f1.read(&_noiseBuf[32000 + f2.size()], f1.size() - 32000); // 19072 + + f1.close(); + f2.close(); +} + +void SoundManager::regenbruit() { + int i = 69876; + for (int j = 0; j < 100; j++) { + _cfiphBuffer[j] = READ_BE_UINT16(&_noiseBuf[i]); + i += 2; + } +} + +void SoundManager::litph(tablint &t, int typ, int tempo) { + // Skip speech + if (_soundType == 0) + return; + + if (!_buildingSentence) { + if (_mixer->isSoundHandleActive(_soundHandle)) + _mixer->stopHandle(_soundHandle); + _buildingSentence = true; + } + int freq = tempo * 252; // 25.2 * 10 + int i = 0; + while (i < _ptr_oct) { + int idx = _troctBuf[i]; + i++; + switch(idx) { + case 0: { + int val = _troctBuf[i]; + i++; + if (_soundType == 0) + warning("TODO: vclas"); + else if (_soundType == 1) { + debugC(5, kMortevielleSounds, "litph - duson"); + const static int noiseAdr[] = {0, 17224, + 17224, 33676, + 33676, 51014, + 51014, 59396, + 59396, 61286, + 61286, 69875}; + if (val > 5) { + warning("unhandled index %d", val); + } else { + if (!_audioStream) + _audioStream = Audio::makeQueuingAudioStream(freq, false); + _audioStream->queueBuffer(&_noiseBuf[noiseAdr[val * 2]], noiseAdr[(val * 2) + 1] - noiseAdr[(val * 2)], DisposeAfterUse::NO, Audio::FLAG_UNSIGNED); + } + } else { // 2 + debugC(5, kMortevielleSounds, "litph - vadson"); + const static int ambiantNoiseAdr[] = {0, 14020, + 14020, 18994, + 18994, 19630, + 19630, 22258, + 22258, 37322, + 37322, 44472, + 44472, 52324, + 52324, 59598, + 59598, 69748}; + if (val > 8) { + warning("unhandled index %d", val); + } else { + if (!_audioStream) + _audioStream = Audio::makeQueuingAudioStream(freq, false); + _audioStream->queueBuffer(&_ambiantNoiseBuf[ambiantNoiseAdr[val * 2]], ambiantNoiseAdr[(val * 2) + 1] - ambiantNoiseAdr[(val * 2)], DisposeAfterUse::NO, Audio::FLAG_UNSIGNED); + } + } + i++; + break; + } + case 2: { + int val = _troctBuf[i]; + i++; + int tmpidx = (val * 12) + 268; + val = _troctBuf[i]; + i++; + warning("TODO: reech %d %d", tmpidx, val); + } + break; + case 4: + if (_soundType) { + i += 2; + } else { + // Speech + warning("TODO: Interphoneme: consonne:%d voyelle:%d", _troctBuf[i], _troctBuf[i + 1]); + i += 2; + } + break; + case 6: + warning("TODO: pari2"); + i += 2; + break; + default: + static byte emptyBuf[19] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + if (idx == 62) + warning("TODO: blab"); + else if (idx == 32) { + if (!_audioStream) + _audioStream = Audio::makeQueuingAudioStream(freq, false); + _audioStream->queueBuffer(emptyBuf, 19, DisposeAfterUse::NO, Audio::FLAG_UNSIGNED); + } else if (idx == 35) { + if (i < _ptr_oct) + warning("unexpected 35 - stop the buffering"); + i = _ptr_oct; + } else if (idx == 46) { + if (!_audioStream) + _audioStream = Audio::makeQueuingAudioStream(freq, false); + for (int j = 0; j < 10; j++) + _audioStream->queueBuffer(emptyBuf, 19, DisposeAfterUse::NO, Audio::FLAG_UNSIGNED); + } else { + warning("Other code: %d - %d %d", idx, _troctBuf[i], _troctBuf[i + 1]); + } + break; + } + } +} + +void SoundManager::playSong(const byte* buf, uint size, uint loops) { + int freq = kTempoMusic * 252; // 25.2 * 10 + Audio::SeekableAudioStream *raw = Audio::makeRawStream(buf, size, freq, Audio::FLAG_UNSIGNED, DisposeAfterUse::NO); + Audio::AudioStream *stream = Audio::makeLoopingAudioStream(raw, loops); + Audio::SoundHandle songHandle; + _mixer->playStream(Audio::Mixer::kSFXSoundType, &songHandle, stream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::YES); + + while (_mixer->isSoundHandleActive(songHandle) && !_vm->keyPressed() && !_vm->_mouseClick && !_vm->shouldQuit()) + ; + // In case the handle is still active, stop it. + _mixer->stopHandle(songHandle); +} + +void SoundManager::setParent(MortevielleEngine *vm) { + _vm = vm; +} + +void SoundManager::spfrac(int wor) { + _queue[2]._rep = (uint)wor >> 12; + if ((_soundType == 0) && (_queue[2]._code != 9)) { + if (((_queue[2]._code > 4) && (_queue[2]._val != 20) && (_queue[2]._rep != 3) && (_queue[2]._rep != 6) && (_queue[2]._rep != 9)) || + ((_queue[2]._code < 5) && ((_queue[2]._val != 19) && (_queue[2]._val != 22) && (_queue[2]._rep != 4) && (_queue[2]._rep != 9)))) { + ++_queue[2]._rep; + } + } + + _queue[2]._freq = ((uint)wor >> 6) & 7; + _queue[2]._acc = ((uint)wor >> 9) & 7; +} + +void SoundManager::charg_car(int &currWordNumb) { + assert(currWordNumb < 1712); + int wor = READ_BE_UINT16(&_wordBuf[currWordNumb]); + int int_ = wor & 0x3f; // 63 + + if ((int_ >= 0) && (int_ <= 13)) { + _queue[2]._val = int_; + _queue[2]._code = 5; + } else if ((int_ >= 14) && (int_ <= 21)) { + _queue[2]._val = int_; + _queue[2]._code = 6; + } else if ((int_ >= 22) && (int_ <= 47)) { + int_ -= 22; + _queue[2]._val = int_; + _queue[2]._code = _typcon[int_]; + } else if ((int_ >= 48) && (int_ <= 56)) { + _queue[2]._val = int_ - 22; + _queue[2]._code = 4; + } else { + switch (int_) { + case 60: + _queue[2]._val = 32; /* " " */ + _queue[2]._code = 9; + break; + case 61: + _queue[2]._val = 46; /* "." */ + _queue[2]._code = 9; + break; + case 62: + _queue[2]._val = 35; /* "#" */ + _queue[2]._code = 9; + default: + break; + } + } + + spfrac(wor); + currWordNumb += 2; +} + + +void SoundManager::entroct(byte o) { + assert(_ptr_oct < 10576); + _troctBuf[_ptr_oct] = o; + ++_ptr_oct; +} + +void SoundManager::cctable(tablint &t) { + float tb[257]; + + tb[0] = 0; + for (int k = 0; k <= 255; ++k) { + tb[k + 1] = _vm->_addFix + tb[k]; + t[255 - k] = abs((int)tb[k] + 1); + } +} + +/** + * Load phoneme sound file + * @remarks Originally called 'charge_phbruit' + */ +void SoundManager::loadPhonemeSounds() { + Common::File f; + + if (!f.open("phbrui.mor")) + error("Missing file - phbrui.mor"); + + for (int i = 1; i <= f.size() / 2; ++i) + _cfiphBuffer[i] = f.readUint16BE(); + + f.close(); +} + +void SoundManager::trait_car() { + byte d3; + int d2, i; + + switch (_queue[1]._code) { + case 9: + if (_queue[1]._val != (int)'#') { + for (i = 0; i <= _queue[1]._rep; ++i) + entroct(_queue[1]._val); + } + break; + case 5: + case 6: + if (_queue[1]._code == 6) + d3 = _tabdph[(_queue[1]._val - 14) << 1]; + else + d3 = kNullValue; + if (_queue[0]._code >= 5) { + if (_queue[0]._code == 9) { + entroct(4); + if (d3 == kNullValue) + entroct(_queue[1]._val); + else + entroct(d3); + entroct(22); + } + } + + switch (_queue[1]._rep) { + case 0: + entroct(0); + entroct(_queue[1]._val); + if (d3 == kNullValue) + if (_queue[2]._code == 9) + entroct(2); + else + entroct(4); + else if (_queue[2]._code == 9) + entroct(0); + else + entroct(1); + break; + case 4: + case 5: + case 6: + if (_queue[1]._rep != 4) { + i = _queue[1]._rep - 5; + do { + --i; + entroct(0); + if (d3 == kNullValue) + entroct(_queue[1]._val); + else + entroct(d3); + entroct(3); + } while (i >= 0); + } + if (d3 == kNullValue) { + entroct(4); + entroct(_queue[1]._val); + entroct(0); + } else { + entroct(0); + entroct(_queue[1]._val); + entroct(3); + } + + break; + case 7: + case 8: + case 9: + if (_queue[1]._rep != 7) { + i = _queue[1]._rep - 8; + do { + --i; + entroct(0); + if (d3 == kNullValue) + entroct(_queue[1]._val); + else + entroct(d3); + entroct(3); + } while (i >= 0); + } + if (d3 == kNullValue) { + entroct(0); + entroct(_queue[1]._val); + entroct(2); + } else { + entroct(0); + entroct(_queue[1]._val); + entroct(0); + } + break; + case 1: + case 2: + case 3: + if (_queue[1]._rep != 1) { + i = _queue[1]._rep - 2; + do { + --i; + entroct(0); + if (d3 == kNullValue) + entroct(_queue[1]._val); + else + entroct(d3); + entroct(3); + } while (i >= 0); + } + entroct(0); + entroct(_queue[1]._val); + if (_queue[2]._code == 9) + entroct(0); + else + entroct(1); + + break; + default: + break; + } // switch c2.rep + break; + + case 2: + case 3: + d3 = _queue[1]._code + 5; // 7 ou 8 => Corresponding vowel + if (_queue[0]._code > 4) { + if (_queue[0]._code == 9) { + entroct(4); + entroct(d3); + entroct(22); + } + } + i = _queue[1]._rep; + assert(i >= 0); + if (i != 0) { + do { + --i; + entroct(0); + entroct(d3); + entroct(3); + } while (i > 0); + } + if (_queue[2]._code == 6) { + entroct(4); + entroct(_tabdph[(_queue[2]._val - 14) << 1]); + entroct(_queue[1]._val); + } else { + entroct(4); + if (_queue[2]._val == 4) + entroct(3); + else + entroct(_queue[2]._val); + entroct(_queue[1]._val); + } + break; + case 0: + case 1: + switch (_queue[2]._code) { + case 2: + d2 = 7; + break; + case 3: + d2 = 8; + break; + case 6: + d2 = _tabdph[(_queue[2]._val - 14) << 1]; + break; + case 5: + d2 = _queue[2]._val; + break; + default: + d2 = 10; + break; + } // switch c3._code + d2 = (d2 * 26) + _queue[1]._val; + if (_tnocon[d2] == 0) + d3 = 2; + else + d3 = 6; + if (_queue[1]._rep >= 5) { + _queue[1]._rep -= 5; + d3 = 8 - d3; // Swap 2 and 6 + } + if (_queue[1]._code == 0) { + i = _queue[1]._rep; + if (i != 0) { + do { + --i; + entroct(d3); + entroct(_queue[1]._val); + entroct(3); + } while (i > 0); + } + entroct(d3); + entroct(_queue[1]._val); + entroct(4); + } else { + entroct(d3); + entroct(_queue[1]._val); + entroct(3); + i = _queue[1]._rep; + if (i != 0) { + do { + --i; + entroct(d3); + entroct(_queue[1]._val); + entroct(4); + } while (i > 0); + } + } + if (_queue[2]._code == 9) { + entroct(d3); + entroct(_queue[1]._val); + entroct(5); + } else if ((_queue[2]._code != 0) && (_queue[2]._code != 1) && (_queue[2]._code != 4)) { + switch (_queue[2]._code) { + case 3: + d2 = 8; + break; + case 6: + d2 = _tabdph[(_queue[2]._val - 14) << 1]; + break; + case 5: + d2 = _queue[2]._val; + break; + default: + d2 = 7; + break; + } // switch c3._code + if (d2 == 4) + d2 = 3; + + if (_intcon[_queue[1]._val] != 0) + ++_queue[1]._val; + + if ((_queue[1]._val == 17) || (_queue[1]._val == 18)) + _queue[1]._val = 16; + + entroct(4); + entroct(d2); + entroct(_queue[1]._val); + } + + break; + case 4: + i = _queue[1]._rep; + if (i != 0) { + do { + --i; + entroct(2); + entroct(_queue[1]._val); + entroct(3); + } while (i > 0); + } + entroct(2); + entroct(_queue[1]._val); + entroct(4); + if (_queue[2]._code == 9) { + entroct(2); + entroct(_queue[1]._val); + entroct(5); + } else if ((_queue[2]._code != 0) && (_queue[2]._code != 1) && (_queue[2]._code != 4)) { + switch (_queue[2]._code) { + case 3: + d2 = 8; + break; + case 6: + d2 = _tabdph[(_queue[2]._val - 14) << 1]; + break; + case 5: + d2 = _queue[2]._val; + break; + default: + d2 = 7; + break; + } // switch c3._code + + if (d2 == 4) + d2 = 3; + + if (_intcon[_queue[1]._val] != 0) + ++_queue[1]._val; + + entroct(4); + entroct(d2); + entroct(_tabdbc[((_queue[1]._val - 26) << 1) + 1]); + } + + break; + default: + break; + } // switch c2.code +} + +/** + * Make the queue evolve by 1 value + * @remarks Originally called 'rot_chariot' + */ +void SoundManager::moveQueue() { + _queue[0] = _queue[1]; + _queue[1] = _queue[2]; + _queue[2]._val = 32; + _queue[2]._code = 9; +} + +/** + * initialize the queue + * @remarks Originally called 'init_chariot' + */ +void SoundManager::initQueue() { + _queue[2]._rep = 0; + _queue[2]._freq = 0; + _queue[2]._acc = 0; + moveQueue(); + moveQueue(); +} + +/** + * Handle a phoneme + * @remarks Originally called 'trait_ph' + */ +void SoundManager::handlePhoneme() { + const uint16 deca[3] = {300, 30, 40}; + + uint16 startPos = _cfiphBuffer[_phonemeNumb - 1] + deca[_soundType]; + uint16 endPos = _cfiphBuffer[_phonemeNumb] + deca[_soundType]; + int wordCount = endPos - startPos; + + startPos /= 2; + endPos /= 2; + assert((endPos - startPos) < 1711); + for (int i = startPos, currWord = 0; i < endPos; i++, currWord += 2) + WRITE_BE_UINT16(&_wordBuf[currWord], _cfiphBuffer[i]); + + _ptr_oct = 0; + int currWord = 0; + initQueue(); + + do { + moveQueue(); + charg_car(currWord); + trait_car(); + } while (currWord < wordCount); + + moveQueue(); + trait_car(); + entroct((int)'#'); + +#ifdef DEBUG + warning("---"); + for (int i = 0; i < _ptr_oct; ) { + if ((_troctBuf[i] == 32) || (_troctBuf[i] == 35) || (_troctBuf[i] == 46)) { + warning("%d", _troctBuf[i]); + i++; + } else { + warning("%d %d %d", _troctBuf[i], _troctBuf[i + 1], _troctBuf[i + 1]); + i += 3; + } + } + warning("---"); +#endif +} + +/** + * Start speech + * @remarks Originally called 'parole' + */ +void SoundManager::startSpeech(int rep, int ht, int typ) { + uint16 savph[501]; + int tempo; + + if (_vm->_soundOff) + return; + + _phonemeNumb = rep; + int haut = ht; + _soundType = typ; + if (_soundType != 0) { + for (int i = 0; i <= 500; ++i) + savph[i] = _cfiphBuffer[i]; + tempo = kTempoNoise; + } else if (haut > 5) + tempo = kTempoF; + else + tempo = kTempoM; + _vm->_addFix = (float)((tempo - 8)) / 256; + cctable(_tbi); + switch (typ) { + case 1: + regenbruit(); + break; + case 2: + loadPhonemeSounds(); + break; + default: + break; + } + handlePhoneme(); + litph(_tbi, typ, tempo); + + _buildingSentence = false; + if (typ != 0) { + _audioStream->finish(); + _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, _audioStream); + _audioStream = nullptr; + } + + if (_soundType != 0) { + for (int i = 0; i <= 500; ++i) + _cfiphBuffer[i] = savph[i]; + } + _vm->setPal(_vm->_numpal); +} + +void SoundManager::waitSpeech() { + while (_mixer->isSoundHandleActive(_soundHandle) && !_vm->keyPressed() && !_vm->_mouseClick && !_vm->shouldQuit()) + ; + // In case the handle is still active, stop it. + _mixer->stopHandle(_soundHandle); + + if (!_vm->keyPressed() && !_vm->_mouseClick && !_vm->shouldQuit()) + g_system->delayMillis(600); +} +} // End of namespace Mortevielle diff --git a/engines/mortevielle/sound.h b/engines/mortevielle/sound.h new file mode 100644 index 0000000000..cc0567fd98 --- /dev/null +++ b/engines/mortevielle/sound.h @@ -0,0 +1,106 @@ +/* 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#ifndef MORTEVIELLE_SOUND_H +#define MORTEVIELLE_SOUND_H + +#include "audio/audiostream.h" +#include "audio/mixer.h" +#include "common/mutex.h" +#include "common/queue.h" + +namespace Mortevielle { +class MortevielleEngine; + +const int kNullValue = 255; +const int kTempoMusic = 71; +const int kTempoNoise = 78; +const int kTempoF = 80; +const int kTempoM = 89; + +struct SpeechQueue { + int _val; + int _code; + int _acc; + int _freq; + int _rep; +}; + +typedef int tablint[256]; + +class SoundManager { +private: + MortevielleEngine *_vm; + + byte *_ambiantNoiseBuf; + byte *_noiseBuf; + int _phonemeNumb; + int _soundType; + SpeechQueue _queue[3]; + byte _wordBuf[1712]; + byte _troctBuf[10576]; + bool _buildingSentence; + int _ptr_oct; + int _tbi[256]; + + Audio::QueuingAudioStream *_audioStream; + + void loadPhonemeSounds(); + void moveQueue(); + void initQueue(); + void handlePhoneme(); + + void spfrac(int wor); + void charg_car(int &currWordNumb); + void entroct(byte o); + void cctable(tablint &t); + void trait_car(); + + void regenbruit(); + void litph(tablint &t, int typ, int tempo); + +public: + SoundManager(Audio::Mixer *mixer); + ~SoundManager(); + + Audio::Mixer *_mixer; + Audio::SoundHandle _soundHandle; + uint16 *_cfiphBuffer; + + void setParent(MortevielleEngine *vm); + + int decodeMusic(const byte *PSrc, byte *PDest, int size); + void playSong(const byte *buf, uint usize, uint loops); + void loadAmbiantSounds(); + void loadNoise(); + void startSpeech(int rep, int ht, int typ); + void waitSpeech(); +}; + +} // End of namespace Mortevielle + +#endif diff --git a/engines/mortevielle/utils.cpp b/engines/mortevielle/utils.cpp new file mode 100644 index 0000000000..f138dde5c5 --- /dev/null +++ b/engines/mortevielle/utils.cpp @@ -0,0 +1,3379 @@ +/* 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 original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#include "mortevielle/mortevielle.h" + +#include "mortevielle/dialogs.h" +#include "mortevielle/menu.h" +#include "mortevielle/mouse.h" +#include "mortevielle/outtext.h" + +#include "common/scummsys.h" +#include "graphics/cursorman.h" + +namespace Mortevielle { + +/** + * Check is a key was pressed + * It also delays the engine and check if the screen has to be updated + * @remarks Originally called 'keypressed' + */ +bool MortevielleEngine::keyPressed() { + // Check for any pending key presses + handleEvents(); + + // Check if it's time to draw the next frame + if (g_system->getMillis() > (_lastGameFrame + GAME_FRAME_DELAY)) { + _lastGameFrame = g_system->getMillis(); + + _screenSurface.updateScreen(); + + _debugger.onFrame(); + } + + // Delay briefly to keep CPU usage down + g_system->delayMillis(5); + + // Return if there are any pending key presses + return !_keypresses.empty(); +} + +/** + * Wait for a keypress + * @remarks Originally called 'get_ch' + */ +int MortevielleEngine::getChar() { + // If there isn't any pending keypress, wait until there is + while (!shouldQuit() && _keypresses.empty()) { + keyPressed(); + } + + // Return the top keypress + return shouldQuit() ? 0 : _keypresses.pop(); +} + +/** + * Handle pending events + * @remarks Since the ScummVM screen surface is double height to handle 640x200 using 640x400, + * the mouse Y position is divided by 2 to keep the game thinking the Y goes from 0 - 199 + */ +bool MortevielleEngine::handleEvents() { + Common::Event event; + if (!g_system->getEventManager()->pollEvent(event)) + return false; + + switch (event.type) { + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_LBUTTONUP: + case Common::EVENT_MOUSEMOVE: + _mousePos = Common::Point(event.mouse.x, event.mouse.y / 2); + _mouse._pos.x = event.mouse.x; + _mouse._pos.y = event.mouse.y / 2; + + if (event.type == Common::EVENT_LBUTTONDOWN) + _mouseClick = true; + else if (event.type == Common::EVENT_LBUTTONUP) + _mouseClick = false; + + break; + case Common::EVENT_KEYDOWN: + addKeypress(event); + break; + default: + break; + } + + return true; +} + +/** + * Add the specified key to the pending keypress stack + */ +void MortevielleEngine::addKeypress(Common::Event &evt) { + // Character to add + char ch = evt.kbd.ascii; + + // Check for debugger + if ((evt.kbd.keycode == Common::KEYCODE_d) && (evt.kbd.flags & Common::KBD_CTRL)) { + // Attach to the debugger + _debugger.attach(); + _debugger.onFrame(); + } else if ((evt.kbd.keycode >= Common::KEYCODE_a) && (evt.kbd.keycode <= Common::KEYCODE_z)) { + // Handle alphabetic keys + if (evt.kbd.hasFlags(Common::KBD_CTRL)) + ch = evt.kbd.keycode - Common::KEYCODE_a + 1; + else + ch = evt.kbd.keycode - Common::KEYCODE_a + 'A'; + } else if ((evt.kbd.keycode >= Common::KEYCODE_F1) && (evt.kbd.keycode <= Common::KEYCODE_F12)) { + // Handle function keys + ch = 59 + evt.kbd.keycode - Common::KEYCODE_F1; + } else { + // Series of special cases + switch (evt.kbd.keycode) { + case Common::KEYCODE_KP4: + case Common::KEYCODE_LEFT: + ch = '4'; + break; + case Common::KEYCODE_KP2: + case Common::KEYCODE_DOWN: + ch = '2'; + break; + case Common::KEYCODE_KP6: + case Common::KEYCODE_RIGHT: + ch = '6'; + break; + case Common::KEYCODE_KP8: + case Common::KEYCODE_UP: + ch = '8'; + break; + case Common::KEYCODE_KP7: + ch = '7'; + break; + case Common::KEYCODE_KP1: + ch = '1'; + break; + case Common::KEYCODE_KP9: + ch = '9'; + break; + case Common::KEYCODE_KP3: + ch = '3'; + break; + case Common::KEYCODE_KP5: + ch = '5'; + break; + case Common::KEYCODE_RETURN: + ch = '\13'; + break; + case Common::KEYCODE_ESCAPE: + ch = '\33'; + break; + default: + break; + } + } + + if (ch != 0) + _keypresses.push(ch); +} + + +static const byte CURSOR_ARROW_DATA[16 * 16] = { + 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x0f, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +/** + * Initialize the mouse + */ +void MortevielleEngine::initMouse() { + CursorMan.replaceCursor(CURSOR_ARROW_DATA, 16, 16, 0, 0, 0xff); + CursorMan.showMouse(true); + + _mouse.initMouse(); +} + +/** + * Sets the mouse position + * @remarks Since the ScummVM screen surface is double height to handle 640x200 using 640x400, + * the mouse Y position is doubled to convert from 0-199 to 0-399 + */ +void MortevielleEngine::setMousePos(const Common::Point &pt) { + // Adjust the passed position from simulated 640x200 to 640x400 co-ordinates + Common::Point newPoint(pt.x, (pt.y == 199) ? 399 : pt.y * 2); + + if (newPoint != _mousePos) + // Warp the mouse to the new position + g_system->warpMouse(newPoint.x, newPoint.y); + + // Save the new position + _mousePos = newPoint; +} + +/** + * Delay by a given amount + */ +void MortevielleEngine::delay(int amount) { + uint32 endTime = g_system->getMillis() + amount; + + while (g_system->getMillis() < endTime) { + if (g_system->getMillis() > (_lastGameFrame + GAME_FRAME_DELAY)) { + _lastGameFrame = g_system->getMillis(); + _screenSurface.updateScreen(); + + _debugger.onFrame(); + } + + g_system->delayMillis(10); + } +} + +/** + * Waits for the user to select an action, and then handles it + * @remarks Originally called tecran + */ +void MortevielleEngine::handleAction() { + const int lim = 20000; + int temps = 0; + char inkey = '\0'; + bool funct = false; + + clearVerbBar(); + + bool handledOpcodeFl = false; + _controlMenu = 0; + if (!_keyPressedEsc) { + _menu.drawMenu(); + _menu._menuDisplayed = true; + temps = 0; + _key = 0; + funct = false; + inkey = '.'; + + _inMainGameLoop = true; + do { + _menu.updateMenu(); + prepareRoom(); + _mouse.moveMouse(funct, inkey); + if (shouldQuit()) + return; + ++temps; + if (keyPressed() || _mouseClick) { + _soundManager._mixer->stopHandle(_soundManager._soundHandle); + } + } while (!((_menu._menuSelected) || (temps > lim) || (funct) || (_anyone))); + _inMainGameLoop = false; + + _menu.eraseMenu(); + _menu._menuDisplayed = false; + if (_menu._menuSelected && (_currMenu == MENU_SAVE)) { + Common::String saveName = Common::String::format("Savegame #%d", _currAction & 15); + _savegameManager.saveGame(_currAction & 15, saveName); + } + if (_menu._menuSelected && (_currMenu == MENU_LOAD)) + _savegameManager.loadGame((_currAction & 15) - 1); + if (inkey == '\103') { /* F9 */ + temps = _dialogManager.show(_hintPctMessage, 1); + return; + } else if (inkey == '\77') { + if ((_menuOpcode != OPCODE_NONE) && ((_currMenu == MENU_ACTION) || (_currMenu == MENU_SELF))) { + _currAction = _menuOpcode; + displayTextInVerbBar(getEngineString(S_IDEM)); + } else + return; + } else if (inkey == '\104') { + if ((_x != 0) && (_y != 0)) + _num = 9999; + return; + } + } + if (inkey == '\73') { + _quitGame = true; + hourToChar(); + } else { + if ((funct) && (inkey != '\77')) + return; + if (temps > lim) { + handleDescriptionText(2, 141); + if (_num == 9999) + _num = 0; + } else { + _menuOpcode = _currMenu; + if ((_currMenu == MENU_ACTION) || (_currMenu == MENU_SELF)) + _menuOpcode = _currAction; + if (!_anyone) { + if ((_heroSearching) || (_obpart)) { + if (_mouse._pos.y < 12) + return; + + if ((_currAction == _menu._opcodeSound) || (_currAction == _menu._opcodeLift)) { + handledOpcodeFl = true; + if ((_currAction == _menu._opcodeLift) || (_obpart)) { + endSearch(); + _caff = _coreVar._currPlace; + _crep = 998; + } else + prepareNextObject(); + menuUp(); + } + } + } + do { + if (!handledOpcodeFl) + handleOpcode(); + + if ((_controlMenu == 0) && (! _loseGame) && (! _endGame)) { + _text.taffich(); + if (_destinationOk) { + _destinationOk = false; + drawPicture(); + } + if ((!_syn) || (_col)) + handleDescriptionText(2, _crep); + } + } while (_syn); + if (_controlMenu != 0) + displayControlMenu(); + } + } +} + +/** + * Engine function - Init Places + * @remarks Originally called 'init_lieu' + */ +void MortevielleEngine::loadPlaces() { + Common::File f; + + if (!f.open("MXX.mor")) + if (!f.open("MFXX.mor")) + error("Missing file - MXX.mor"); + + for (int i = 0; i < 7; ++i) { + for (int j = 0; j < 25; ++j) + _destinationArray[i][j] = f.readByte(); + } + + f.close(); +} + +/** + * Set Text Color + * @remarks Originally called 'text_color' + */ +void MortevielleEngine::setTextColor(int col) { + _textColor = col; +} + +/** + * Prepare screen - Type 1! + * @remarks Originally called 'ecrf1' + */ +void MortevielleEngine::prepareScreenType1() { + // Large drawing + _screenSurface.drawBox(0, 11, 512, 164, 15); +} + +/** + * Prepare room - Type 2! + * @remarks Originally called 'ecrf2' + */ +void MortevielleEngine::prepareScreenType2() { + setTextColor(5); +} + +/** + * Prepare room - Type 3! + * @remarks Originally called 'ecrf7' + */ +void MortevielleEngine::prepareScreenType3() { + setTextColor(4); +} + +/** + * Engine function - Update hour + * @remarks Originally called 'calch' + */ +void MortevielleEngine::updateHour(int &day, int &hour, int &minute) { + int newHour = readclock(); + int th = _currentHourCount + ((newHour - _currentDayHour) / _inGameHourDuration); + minute = ((th % 2) + _currHalfHour) * 30; + hour = ((uint)th >> 1) + _currHour; + if (minute == 60) { + minute = 0; + ++hour; + } + day = (hour / 24) + _currDay; + hour = hour - ((day - _currDay) * 24); +} + +/** + * Engine function - Convert character index to bit index + * @remarks Originally called 'conv' + */ +int MortevielleEngine::convertCharacterIndexToBitIndex(int characterIndex) { + return 128 >> (characterIndex - 1); +} + +/** + * Engine function - Convert bit index to character index + * @remarks Originally called 'tip' + */ +int MortevielleEngine::convertBitIndexToCharacterIndex(int bitIndex) { + int retVal = 0; + + if (bitIndex == 128) + retVal = 1; + else if (bitIndex == 64) + retVal = 2; + else if (bitIndex == 32) + retVal = 3; + else if (bitIndex == 16) + retVal = 4; + else if (bitIndex == 8) + retVal = 5; + else if (bitIndex == 4) + retVal = 6; + else if (bitIndex == 2) + retVal = 7; + else if (bitIndex == 1) + retVal = 8; + + return retVal; +} + +/** + * Engine function - Reset presence in other rooms + * @remarks Originally called 't5' + */ +void MortevielleEngine::resetPresenceInRooms(int roomId) { + if (roomId == DINING_ROOM) + _blo = false; + + if (roomId != GREEN_ROOM) { + _roomPresenceLuc = false; + _roomPresenceIda = false; + } + + if (roomId != PURPLE_ROOM) + _purpleRoomPresenceLeo = false; + + if (roomId != DARKBLUE_ROOM) { + _roomPresenceGuy = false; + _roomPresenceEva = false; + } + + if (roomId != BLUE_ROOM) + _roomPresenceMax = false; + if (roomId != RED_ROOM) + _roomPresenceBob = false; + if (roomId != GREEN_ROOM2) + _roomPresencePat = false; + if (roomId != TOILETS) + _toiletsPresenceBobMax = false; + if (roomId != BATHROOM) + _bathRoomPresenceBobMax = false; + if (roomId != JULIA_ROOM) + _juliaRoomPresenceLeo = false; +} + +/** + * Engine function - Show the people present in the given room + * @remarks Originally called 'affper' + */ +void MortevielleEngine::showPeoplePresent(int bitIndex) { + int xp = 580 - (_screenSurface.getStringWidth("LEO") / 2); + + for (int i = 1; i <= 8; ++i) + _menu.disableMenuItem(_menu._discussMenu[i]); + + clearUpperRightPart(); + if ((bitIndex & 128) == 128) { + _screenSurface.putxy(xp, 24); + _screenSurface.drawString("LEO", 4); + _menu.enableMenuItem(_menu._discussMenu[1]); + } + if ((bitIndex & 64) == 64) { + _screenSurface.putxy(xp, 32); + _screenSurface.drawString("PAT", 4); + _menu.enableMenuItem(_menu._discussMenu[2]); + } + if ((bitIndex & 32) == 32) { + _screenSurface.putxy(xp, 40); + _screenSurface.drawString("GUY", 4); + _menu.enableMenuItem(_menu._discussMenu[3]); + } + if ((bitIndex & 16) == 16) { + _screenSurface.putxy(xp, 48); + _screenSurface.drawString("EVA", 4); + _menu.enableMenuItem(_menu._discussMenu[4]); + } + if ((bitIndex & 8) == 8) { + _screenSurface.putxy(xp, 56); + _screenSurface.drawString("BOB", 4); + _menu.enableMenuItem(_menu._discussMenu[5]); + } + if ((bitIndex & 4) == 4) { + _screenSurface.putxy(xp, 64); + _screenSurface.drawString("LUC", 4); + _menu.enableMenuItem(_menu._discussMenu[6]); + } + if ((bitIndex & 2) == 2) { + _screenSurface.putxy(xp, 72); + _screenSurface.drawString("IDA", 4); + _menu.enableMenuItem(_menu._discussMenu[7]); + } + if ((bitIndex & 1) == 1) { + _screenSurface.putxy(xp, 80); + _screenSurface.drawString("MAX", 4); + _menu.enableMenuItem(_menu._discussMenu[8]); + } + _currBitIndex = bitIndex; +} + +/** + * Engine function - Select random characters + * @remarks Originally called 'choix' + */ +int MortevielleEngine::selectCharacters(int min, int max) { + bool invertSelection = false; + int rand = getRandomNumber(min, max); + + if (rand > 4) { + rand = 8 - rand; + invertSelection = true; + } + + int i = 0; + int retVal = 0; + while (i < rand) { + int charIndex = getRandomNumber(1, 8); + int charBitIndex = convertCharacterIndexToBitIndex(charIndex); + if ((retVal & charBitIndex) != charBitIndex) { + ++i; + retVal |= charBitIndex; + } + } + if (invertSelection) + retVal = 255 - retVal; + + return retVal; +} + +/** + * Engine function - Get Presence Statistics - Green Room + * @remarks Originally called 'cpl1' + */ +int MortevielleEngine::getPresenceStatsGreenRoom() { + int day, hour, minute; + int retVal = 0; + + updateHour(day, hour, minute); + // The original uses an || instead of an &&, resulting + // in an always true condition. Based on the other tests, + // and on other scenes, we use an && instead. + if ((hour > 7) && (hour < 11)) + retVal = 25; + else if ((hour > 10) && (hour < 14)) + retVal = 35; + else if ((hour > 13) && (hour < 16)) + retVal = 50; + else if ((hour > 15) && (hour < 18)) + retVal = 5; + else if ((hour > 17) && (hour < 22)) + retVal = 35; + else if ((hour > 21) && (hour < 24)) + retVal = 50; + else if ((hour >= 0) && (hour < 8)) + retVal = 70; + + _menu.updateMenu(); + + return retVal; +} +/** + * Engine function - Get Presence Statistics - Purple Room + * @remarks Originally called 'cpl2' + */ +int MortevielleEngine::getPresenceStatsPurpleRoom() { + int day, hour, minute; + int retVal = 0; + + updateHour(day, hour, minute); + if ((hour > 7) && (hour < 11)) + retVal = -2; + else if (hour == 11) + retVal = 100; + else if ((hour > 11) && (hour < 23)) + retVal = 10; + else if (hour == 23) + retVal = 20; + else if ((hour >= 0) && (hour < 8)) + retVal = 50; + + return retVal; +} + +/** + * Engine function - Get Presence Statistics - Toilets + * @remarks Originally called 'cpl3' + */ +int MortevielleEngine::getPresenceStatsToilets() { + int day, hour, minute; + int retVal = 0; + + updateHour(day, hour, minute); + if (((hour > 8) && (hour < 10)) || ((hour > 19) && (hour < 24))) + retVal = 34; + else if (((hour > 9) && (hour < 20)) || ((hour >= 0) && (hour < 9))) + retVal = 0; + + return retVal; +} + +/** + * Engine function - Get Presence Statistics - Blue Room + * @remarks Originally called 'cpl5' + */ +int MortevielleEngine::getPresenceStatsBlueRoom() { + int day, hour, minute; + int retVal = 0; + + updateHour(day, hour, minute); + if ((hour > 6) && (hour < 10)) + retVal = 0; + else if (hour == 10) + retVal = 100; + else if ((hour > 10) && (hour < 24)) + retVal = 15; + else if ((hour >= 0) && (hour < 7)) + retVal = 50; + + return retVal; +} + +/** + * Engine function - Get Presence Statistics - Red Room + * @remarks Originally called 'cpl6' + */ +int MortevielleEngine::getPresenceStatsRedRoom() { + int day, hour, minute; + int retVal = 0; + + updateHour(day, hour, minute); + if (((hour > 7) && (hour < 13)) || ((hour > 17) && (hour < 20))) + retVal = -2; + else if (((hour > 12) && (hour < 17)) || ((hour > 19) && (hour < 24))) + retVal = 35; + else if (hour == 17) + retVal = 100; + else if ((hour >= 0) && (hour < 8)) + retVal = 60; + + return retVal; +} + +/** + * Shows the "you are alone" message in the status area + * on the right hand side of the screen + * @remarks Originally called 'person' + */ +void MortevielleEngine::displayAloneText() { + for (int i = 1; i <= 8; ++i) + _menu.disableMenuItem(_menu._discussMenu[i]); + + Common::String sYou = getEngineString(S_YOU); + Common::String sAre = getEngineString(S_ARE); + Common::String sAlone = getEngineString(S_ALONE); + + clearUpperRightPart(); + _screenSurface.putxy(580 - (_screenSurface.getStringWidth(sYou) / 2), 30); + _screenSurface.drawString(sYou, 4); + _screenSurface.putxy(580 - (_screenSurface.getStringWidth(sAre) / 2), 50); + _screenSurface.drawString(sAre, 4); + _screenSurface.putxy(580 - (_screenSurface.getStringWidth(sAlone) / 2), 70); + _screenSurface.drawString(sAlone, 4); + + _currBitIndex = 0; +} + +/** + * Engine function - Get Presence Statistics - Room Bureau + * @remarks Originally called 'cpl10' + */ +int MortevielleEngine::getPresenceStatsDiningRoom(int &hour) { + int day, minute; + + int retVal = 0; + updateHour(day, hour, minute); + if (((hour > 7) && (hour < 11)) || ((hour > 11) && (hour < 14)) || ((hour > 18) && (hour < 21))) + retVal = 100; + else if ((hour == 11) || ((hour > 20) && (hour < 24))) + retVal = 45; + else if (((hour > 13) && (hour < 17)) || (hour == 18)) + retVal = 35; + else if (hour == 17) + retVal = 60; + else if ((hour >= 0) && (hour < 8)) + retVal = 5; + + return retVal; +} + +/** + * Engine function - Get Presence Statistics - Room Bureau + * @remarks Originally called 'cpl11' + */ +int MortevielleEngine::getPresenceStatsBureau(int &hour) { + int day, minute; + int retVal = 0; + + updateHour(day, hour, minute); + if (((hour > 8) && (hour < 12)) || ((hour > 20) && (hour < 24))) + retVal = 25; + else if (((hour > 11) && (hour < 14)) || ((hour > 18) && (hour < 21))) + retVal = 5; + else if ((hour > 13) && (hour < 17)) + retVal = 55; + else if ((hour > 16) && (hour < 19)) + retVal = 45; + else if ((hour >= 0) && (hour < 9)) + retVal = 0; + + return retVal; +} + +/** + * Engine function - Get Presence Statistics - Room Kitchen + * @remarks Originally called 'cpl12' + */ +int MortevielleEngine::getPresenceStatsKitchen() { + int day, hour, minute; + int retVal = 0; + + updateHour(day, hour, minute); + if (((hour > 8) && (hour < 15)) || ((hour > 16) && (hour < 22))) + retVal = 55; + else if (((hour > 14) && (hour < 17)) || ((hour > 21) && (hour < 24))) + retVal = 25; + else if ((hour >= 0) && (hour < 5)) + retVal = 0; + else if ((hour > 4) && (hour < 9)) + retVal = 15; + + return retVal; +} + +/** + * Engine function - Get Presence Statistics - Room Attic + * @remarks Originally called 'cpl13' + */ +int MortevielleEngine::getPresenceStatsAttic() { + return 0; +} + +/** + * Engine function - Get Presence Statistics - Room Landing + * @remarks Originally called 'cpl15' + */ +int MortevielleEngine::getPresenceStatsLanding() { + int day, hour, minute; + int retVal = 0; + + updateHour(day, hour, minute); + if ((hour > 7) && (hour < 12)) + retVal = 25; + else if ((hour > 11) && (hour < 14)) + retVal = 0; + else if ((hour > 13) && (hour < 18)) + retVal = 10; + else if ((hour > 17) && (hour < 20)) + retVal = 55; + else if ((hour > 19) && (hour < 22)) + retVal = 5; + else if ((hour > 21) && (hour < 24)) + retVal = 15; + else if ((hour >= 0) && (hour < 8)) + retVal = -15; + + return retVal; +} + +/** + * Engine function - Get Presence Statistics - Room Chapel + * @remarks Originally called 'cpl20' + */ +int MortevielleEngine::getPresenceStatsChapel(int &hour) { + int day, minute; + int retVal = 0; + + updateHour(day, hour, minute); + if (hour == 10) + retVal = 65; + else if ((hour > 10) && (hour < 21)) + retVal = 5; + else if ((hour > 20) && (hour < 24)) + retVal = -15; + else if ((hour >= 0) && (hour < 5)) + retVal = -300; + else if ((hour > 4) && (hour < 10)) + retVal = -5; + + return retVal; +} + +/** + * Engine function - Check who is in the Green Room + * @remarks Originally called 'quelq1' + */ +void MortevielleEngine::setPresenceGreenRoom(int roomId) { + int rand = getRandomNumber(1, 2); + if (roomId == GREEN_ROOM) { + if (rand == 1) + _roomPresenceLuc = true; + else + _roomPresenceIda = true; + } else if (roomId == DARKBLUE_ROOM) { + if (rand == 1) + _roomPresenceGuy = true; + else + _roomPresenceEva = true; + } + + _currBitIndex = 10; +} + +/** + * Engine function - Check who is in the Purple Room + * @remarks Originally called 'quelq2' + */ +void MortevielleEngine::setPresencePurpleRoom() { + if (_place == PURPLE_ROOM) + _purpleRoomPresenceLeo = true; + else + _juliaRoomPresenceLeo = true; + + _currBitIndex = 10; +} + +/** + * Engine function - Check who is in the Blue Room + * @remarks Originally called 'quelq5' + */ +void MortevielleEngine::setPresenceBlueRoom() { + _roomPresenceMax = true; + _currBitIndex = 10; +} + +/** + * Engine function - Check who is in the Red Room + * @remarks Originally called 'quelq6' + */ +void MortevielleEngine::setPresenceRedRoom(int roomId) { + if (roomId == RED_ROOM) + _roomPresenceBob = true; + else if (roomId == GREEN_ROOM2) + _roomPresencePat = true; + + _currBitIndex = 10; +} + +/** + * Engine function - Check who is in the Dining Room + * @remarks Originally called 'quelq10' + */ +int MortevielleEngine::setPresenceDiningRoom(int hour) { + int retVal = 0; + + if ((hour >= 0) && (hour < 8)) + retVal = checkLeoMaxRandomPresence(); + else { + int min = 0, max = 0; + if ((hour > 7) && (hour < 10)) { + min = 5; + max = 7; + } else if ((hour > 9) && (hour < 12)) { + min = 1; + max = 4; + } else if (((hour > 11) && (hour < 15)) || ((hour > 18) && (hour < 21))) { + min = 6; + max = 8; + } else if (((hour > 14) && (hour < 19)) || ((hour > 20) && (hour < 24))) { + min = 1; + max = 5; + } + retVal = selectCharacters(min, max); + } + showPeoplePresent(retVal); + + return retVal; +} + +/** + * Engine function - Check who is in the Bureau + * @remarks Originally called 'quelq11' + */ +int MortevielleEngine::setPresenceBureau(int hour) { + int retVal = 0; + + if ((hour >= 0) && (hour < 8)) + retVal = checkLeoMaxRandomPresence(); + else { + int min = 0, max = 0; + if (((hour > 7) && (hour < 10)) || ((hour > 20) && (hour < 24))) { + min = 1; + max = 3; + } else if (((hour > 9) && (hour < 12)) || ((hour > 13) && (hour < 19))) { + min = 1; + max = 4; + } else if (((hour > 11) && (hour < 14)) || ((hour > 18) && (hour < 21))) { + min = 1; + max = 2; + } + retVal = selectCharacters(min, max); + } + showPeoplePresent(retVal); + + return retVal; +} + +/** + * Engine function - Check who is in the Kitchen + * @remarks Originally called 'quelq12' + */ +int MortevielleEngine::setPresenceKitchen() { + int retVal = checkLeoMaxRandomPresence(); + showPeoplePresent(retVal); + + return retVal; +} + +/** + * Engine function - Check who is in the Landing + * @remarks Originally called 'quelq15' + */ +int MortevielleEngine::setPresenceLanding() { + bool test = false; + int rand = 0; + do { + rand = getRandomNumber(1, 8); + test = (((rand == 1) && (_purpleRoomPresenceLeo || _juliaRoomPresenceLeo)) || + ((rand == 2) && _roomPresencePat) || + ((rand == 3) && _roomPresenceGuy) || + ((rand == 4) && _roomPresenceEva) || + ((rand == 5) && _roomPresenceBob) || + ((rand == 6) && _roomPresenceLuc) || + ((rand == 7) && _roomPresenceIda) || + ((rand == 8) && _roomPresenceMax)); + } while (test); + + int retVal = convertCharacterIndexToBitIndex(rand); + showPeoplePresent(retVal); + + return retVal; +} + +/** + * Engine function - Check who is in the chapel + * @remarks Originally called 'quelq20' + */ +int MortevielleEngine::setPresenceChapel(int hour) { + int retVal = 0; + + if (((hour >= 0) && (hour < 10)) || ((hour > 18) && (hour < 24))) + retVal = checkLeoMaxRandomPresence(); + else { + int min = 0, max = 0; + if ((hour > 9) && (hour < 12)) { + min = 3; + max = 7; + } else if ((hour > 11) && (hour < 18)) { + min = 1; + max = 2; + } else if (hour == 18) { + min = 2; + max = 4; + } + retVal = selectCharacters(min, max); + } + showPeoplePresent(retVal); + + return retVal; +} + +/** + * Engine function - Get the answer after you known a door + * @remarks Originally called 'frap' + */ +void MortevielleEngine::getKnockAnswer() { + int day, hour, minute; + + updateHour(day, hour, minute); + if ((hour >= 0) && (hour < 8)) + _crep = 190; + else { + if (getRandomNumber(1, 100) > 70) + _crep = 190; + else + _crep = 147; + } +} + +/** + * Engine function - Get Room Presence Bit Index + * @remarks Originally called 'nouvp' + */ +int MortevielleEngine::getPresenceBitIndex(int roomId) { + int bitIndex = 0; + if (roomId == GREEN_ROOM) { + if (_roomPresenceLuc) + bitIndex = 4; // LUC + if (_roomPresenceIda) + bitIndex = 2; // IDA + } else if ( ((roomId == PURPLE_ROOM) && (_purpleRoomPresenceLeo)) + || ((roomId == JULIA_ROOM) && (_juliaRoomPresenceLeo))) + bitIndex = 128; // LEO + else if (roomId == DARKBLUE_ROOM) { + if (_roomPresenceGuy) + bitIndex = 32; // GUY + if (_roomPresenceEva) + bitIndex = 16; // EVA + } else if ((roomId == BLUE_ROOM) && (_roomPresenceMax)) + bitIndex = 1; // MAX + else if ((roomId == RED_ROOM) && (_roomPresenceBob)) + bitIndex = 8; // BOB + else if ((roomId == GREEN_ROOM2) && (_roomPresencePat)) + bitIndex = 64; // PAT + else if ( ((roomId == TOILETS) && (_toiletsPresenceBobMax)) + || ((roomId == BATHROOM) && (_bathRoomPresenceBobMax)) ) + bitIndex = 9; // BOB + MAX + + if (bitIndex != 9) + showPeoplePresent(bitIndex); + + return bitIndex; +} + +/** + * Engine function - initGame + * @remarks Originally called 'dprog' + */ +void MortevielleEngine::initGame() { + _place = MANOR_FRONT; + _currentHourCount = 0; + if (!_coreVar._alreadyEnteredManor) + _blo = true; + _inGameHourDuration = kTime1; + _currentDayHour = readclock(); +} + +/** + * Engine function - Set Random Presence - Green Room + * @remarks Originally called 'pl1' + */ +void MortevielleEngine::setRandomPresenceGreenRoom(int faithScore) { + if ( ((_place == GREEN_ROOM) && (!_roomPresenceLuc) && (!_roomPresenceIda)) + || ((_place == DARKBLUE_ROOM) && (!_roomPresenceGuy) && (!_roomPresenceEva)) ) { + int p = getPresenceStatsGreenRoom(); + p += faithScore; + if (getRandomNumber(1, 100) > p) + displayAloneText(); + else + setPresenceGreenRoom(_place); + } +} + +/** + * Engine function - Set Random Presence - Purple Room + * @remarks Originally called 'pl2' + */ +void MortevielleEngine::setRandomPresencePurpleRoom(int faithScore) { + if (!_purpleRoomPresenceLeo) { + int p = getPresenceStatsPurpleRoom(); + p += faithScore; + if (getRandomNumber(1, 100) > p) + displayAloneText(); + else + setPresencePurpleRoom(); + } +} + +/** + * Engine function - Set Random Presence - Blue Room + * @remarks Originally called 'pl5' + */ +void MortevielleEngine::setRandomPresenceBlueRoom(int faithScore) { + if (!_roomPresenceMax) { + int p = getPresenceStatsBlueRoom(); + p += faithScore; + if (getRandomNumber(1, 100) > p) + displayAloneText(); + else + setPresenceBlueRoom(); + } +} + +/** + * Engine function - Set Random Presence - Red Room + * @remarks Originally called 'pl6' + */ +void MortevielleEngine::setRandomPresenceRedRoom(int faithScore) { + if ( ((_place == RED_ROOM) && (!_roomPresenceBob)) + || ((_place == GREEN_ROOM2) && (!_roomPresencePat)) ) { + int p = getPresenceStatsRedRoom(); + p += faithScore; + if (getRandomNumber(1, 100) > p) + displayAloneText(); + else + setPresenceRedRoom(_place); + } +} + +/** + * Engine function - Set Random Presence - Room 9 + * @remarks Originally called 'pl9' + */ +void MortevielleEngine::setRandomPresenceJuliaRoom(int faithScore) { + if (!_juliaRoomPresenceLeo) { + faithScore = -10; + if (getRandomNumber(1, 100) > faithScore) // always true? + displayAloneText(); + else + setPresencePurpleRoom(); + } +} + +/** + * Engine function - Set Random Presence - Dining Room + * @remarks Originally called 'pl10' + */ +void MortevielleEngine::setRandomPresenceDiningRoom(int faithScore) { + int h; + int p = getPresenceStatsDiningRoom(h); + p += faithScore; + if (getRandomNumber(1, 100) > p) + displayAloneText(); + else + setPresenceDiningRoom(h); +} + +/** + * Engine function - Set Random Presence - Bureau + * @remarks Originally called 'pl11' + */ +void MortevielleEngine::setRandomPresenceBureau(int faithScore) { + int h; + + int p = getPresenceStatsBureau(h); + p += faithScore; + if (getRandomNumber(1, 100) > p) + displayAloneText(); + else + setPresenceBureau(h); +} + +/** + * Engine function - Set Random Presence - Kitchen + * @remarks Originally called 'pl12' + */ +void MortevielleEngine::setRandomPresenceKitchen(int faithScore) { + + int p = getPresenceStatsKitchen(); + p += faithScore; + if (getRandomNumber(1, 100) > p) + displayAloneText(); + else + setPresenceKitchen(); +} + +/** + * Engine function - Set Random Presence - Attic / Cellar + * @remarks Originally called 'pl13' + */ +void MortevielleEngine::setRandomPresenceAttic(int faithScore) { + int p = getPresenceStatsAttic(); + p += faithScore; + if (getRandomNumber(1, 100) > p) + displayAloneText(); + else + setPresenceKitchen(); +} + +/** + * Engine function - Set Random Presence - Landing + * @remarks Originally called 'pl15' + */ +void MortevielleEngine::setRandomPresenceLanding(int faithScore) { + int p = getPresenceStatsLanding(); + p += faithScore; + if (getRandomNumber(1, 100) > p) + displayAloneText(); + else + setPresenceLanding(); +} + +/** + * Engine function - Set Random Presence - Chapel + * @remarks Originally called 'pl20' + */ +void MortevielleEngine::setRandomPresenceChapel(int faithScore) { + int h; + + int p = getPresenceStatsChapel(h); + p += faithScore; + if (getRandomNumber(1, 100) > p) + displayAloneText(); + else + setPresenceChapel(h); +} + +/** + * Start music or speech + * @remarks Originally called 'musique' + */ +void MortevielleEngine::startMusicOrSpeech(int so) { + if (so == 0) { + /* musik(0) */ + ; + } else if ((!_introSpeechPlayed) && (!_coreVar._alreadyEnteredManor)) { + // Type 1: Speech + _soundManager.startSpeech(10, 1, 1); + _introSpeechPlayed = true; + } else { + if (((_coreVar._currPlace == MOUNTAIN) || (_coreVar._currPlace == MANOR_FRONT) || (_coreVar._currPlace == MANOR_BACK)) && (getRandomNumber(1, 3) == 2)) + // Type 1: Speech + _soundManager.startSpeech(9, getRandomNumber(2, 4), 1); + else if ((_coreVar._currPlace == CHAPEL) && (getRandomNumber(1, 2) == 1)) + // Type 1: Speech + _soundManager.startSpeech(8, 1, 1); + else if ((_coreVar._currPlace == WELL) && (getRandomNumber(1, 2) == 2)) + // Type 1: Speech + _soundManager.startSpeech(12, 1, 1); + else if (_coreVar._currPlace == INSIDE_WELL) + // Type 1: Speech + _soundManager.startSpeech(13, 1, 1); + else + // Type 2 : music + _soundManager.startSpeech(getRandomNumber(1, 17), 1, 2); + } +} + +/** + * Engine function - You lose! + * @remarks Originally called 'tperd' + */ +void MortevielleEngine::loseGame() { + resetOpenObjects(); + _roomDoorId = OWN_ROOM; + _curSearchObjId = 0; + _menu.unsetSearchMenu(); + if (!_blo) + getPresence(MANOR_FRONT); + + _loseGame = true; + clearUpperLeftPart(); + _screenSurface.drawBox(60, 35, 400, 50, 15); + handleDescriptionText(9, _crep); + clearDescriptionBar(); + clearVerbBar(); + _col = false; + _syn = false; + _destinationOk = false; +} + +/** + * Engine function - Check inventory for a given object + * @remarks Originally called 'cherjer' + */ +bool MortevielleEngine::checkInventory(int objectId) { + bool retVal = false; + for (int i = 1; i <= 6; ++i) + retVal = (retVal || (_coreVar._inventory[i] == objectId)); + + if (_coreVar._selectedObjectId == objectId) + retVal = true; + + return retVal; +} + +/** + * Engine function - Display Dining Room + * @remarks Originally called 'st1sama' + */ +void MortevielleEngine::displayDiningRoom() { + _coreVar._currPlace = DINING_ROOM; + prepareDisplayText(); +} + +/** + * Engine function - Start non interactive Dialog + * @remarks Originally called 'sparl' + */ +void MortevielleEngine::startDialog(int16 rep) { + const int haut[9] = { 0, 0, 1, -3, 6, -2, 2, 7, -1 }; + int key; + + assert(rep >= 0); + + _mouse.hideMouse(); + Common::String dialogStr = getString(rep + kDialogStringIndex); + _text.displayStr(dialogStr, 230, 4, 65, 24, 5); + _dialogManager.drawF3F8(); + + key = 0; + do { + _soundManager.startSpeech(rep, haut[_caff - 69], 0); + key = _dialogManager.waitForF3F8(); + if (shouldQuit()) + return; + } while (key != 66); + clearScreen(); + _mouse.showMouse(); +} + +/** + * Engine function - End of Search: reset globals + * @remarks Originally called 'finfouill' + */ +void MortevielleEngine::endSearch() { + _heroSearching = false; + _obpart = false; + _searchCount = 0; + _menu.unsetSearchMenu(); +} + +/** + * Engine function - Go to Dining room + * @remarks Originally called 't1sama' + */ +void MortevielleEngine::gotoDiningRoom() { + int day, hour, minute; + + updateHour(day, hour, minute); + if ((hour < 5) && (_coreVar._currPlace > ROOM18)) { + if (!checkInventory(137)) { //You don't have the keys, and it's late + _crep = 1511; + loseGame(); + } else + displayDiningRoom(); + } else if (!_coreVar._alreadyEnteredManor) { //Is it your first time? + _currBitIndex = 255; // Everybody is present + showPeoplePresent(_currBitIndex); + _caff = 77; + drawPictureWithText(); + _screenSurface.drawBox(223, 47, 155, 92, 15); + handleDescriptionText(2, 33); + testKey(false); + menuUp(); + _mouse.hideMouse(); + clearScreen(); + drawDiscussionBox(); + startDialog(140); + drawRightFrame(); + drawClock(); + _mouse.showMouse(); + _coreVar._currPlace = OWN_ROOM; + prepareDisplayText(); + resetPresenceInRooms(DINING_ROOM); + if (!_blo) + getPresence(OWN_ROOM); + _currBitIndex = 0; + _savedBitIndex = 0; + _coreVar._alreadyEnteredManor = true; + } else + displayDiningRoom(); +} + +/** + * Engine function - Check Manor distance (in the mountains) + * @remarks Originally called 't1neig' + */ +void MortevielleEngine::checkManorDistance() { + ++_manorDistance; + if (_manorDistance > 2) { + _crep = 1506; + loseGame(); + } else { + _destinationOk = true; + _coreVar._currPlace = MOUNTAIN; + prepareDisplayText(); + } +} + +/** + * Engine function - Go to Manor front + * @remarks Originally called 't1deva' + */ +void MortevielleEngine::gotoManorFront() { + _manorDistance = 0; + _coreVar._currPlace = MANOR_FRONT; + prepareDisplayText(); +} + +/** + * Engine function - Go to Manor back + * @remarks Originally called 't1derr' + */ +void MortevielleEngine::gotoManorBack() { + _coreVar._currPlace = MANOR_BACK; + prepareDisplayText(); +} + +/** + * Engine function - Dead : Flooded in Well + * @remarks Originally called 't1deau' + */ +void MortevielleEngine::floodedInWell() { + _crep = 1503; + loseGame(); +} + +/** + * Called when a savegame has been loaded. + * @remarks Originally called 'antegame' + */ +void MortevielleEngine::gameLoaded() { + _mouse.hideMouse(); + _menu._menuDisplayed = false; + _loseGame = true; + _anyone = false; + _destinationOk = true; + _col = false; + _hiddenHero = false; + _uptodatePresence = false; + _maff = 68; + _menuOpcode = OPCODE_NONE; + _introSpeechPlayed = false; + _x = 0; + _y = 0; + _num = 0; + _startHour = 0; + _endHour = 0; + _searchCount = 0; + _roomDoorId = OWN_ROOM; + _syn = true; + _heroSearching = true; + _curSearchObjId = 0; + _manorDistance = 0; + resetOpenObjects(); + _takeObjCount = 0; + prepareDisplayText(); + _hintPctMessage = getString(580); + + _destinationOk = false; + _endGame = true; + _loseGame = false; + _heroSearching = false; + + displayAloneText(); + prepareRoom(); + drawClock(); + drawPictureWithText(); + handleDescriptionText(2, _crep); + clearVerbBar(); + _endGame = false; + _menu.setDestinationText(_coreVar._currPlace); + _menu.setInventoryText(); + if (_coreVar._selectedObjectId != 0) + displayItemInHand(_coreVar._selectedObjectId + 400); + _mouse.showMouse(); +} + +/** + * Engine function - Handle OpCodes + * @remarks Originally called 'tsitu' + */ +void MortevielleEngine::handleOpcode() { + if (!_col) + clearDescriptionBar(); + _syn = false; + _keyPressedEsc = false; + if (!_anyone) { + if (_uptodatePresence) { + if ((_currMenu == MENU_MOVE) || (_currAction == _menu._opcodeLeave) || (_currAction == _menu._opcodeSleep) || (_currAction == _menu._opcodeEat)) { + _controlMenu = 4; + menuUp(); + return; + } + } + + if (_currMenu == MENU_MOVE) + fctMove(); + else if (_currMenu == MENU_DISCUSS) + fctDiscuss(); + else if (_currMenu == MENU_INVENTORY) + fctInventoryTake(); + else if (_currAction == _menu._opcodeAttach) + fctAttach(); + else if (_currAction == _menu._opcodeWait) + fctWait(); + else if (_currAction == _menu._opcodeForce) + fctForce(); + else if (_currAction == _menu._opcodeSleep) + fctSleep(); + else if (_currAction == _menu._opcodeListen) + fctListen(); + else if (_currAction == _menu._opcodeEnter) + fctEnter(); + else if (_currAction == _menu._opcodeClose) + fctClose(); + else if (_currAction == _menu._opcodeSearch) + fctSearch(); + else if (_currAction == _menu._opcodeKnock) + fctKnock(); + else if (_currAction == _menu._opcodeScratch) + fctScratch(); + else if (_currAction == _menu._opcodeRead) + fctRead(); + else if (_currAction == _menu._opcodeEat) + fctEat(); + else if (_currAction == _menu._opcodePlace) + fctPlace(); + else if (_currAction == _menu._opcodeOpen) + fctOpen(); + else if (_currAction == _menu._opcodeTake) + fctTake(); + else if (_currAction == _menu._opcodeLook) + fctLook(); + else if (_currAction == _menu._opcodeSmell) + fctSmell(); + else if (_currAction == _menu._opcodeSound) + fctSound(); + else if (_currAction == _menu._opcodeLeave) + fctLeave(); + else if (_currAction == _menu._opcodeLift) + fctLift(); + else if (_currAction == _menu._opcodeTurn) + fctTurn(); + else if (_currAction == _menu._opcodeSSearch) + fctSelfSearch(); + else if (_currAction == _menu._opcodeSRead) + fctSelfRead(); + else if (_currAction == _menu._opcodeSPut) + fctSelfPut(); + else if (_currAction == _menu._opcodeSLook) + fctSelftLook(); + + _hiddenHero = false; + + if (_currAction == _menu._opcodeSHide) + fctSelfHide(); + } else if (_anyone) { + interactNPC(); + _anyone = false; + menuUp(); + return; + } + int hour, day, minute; + updateHour(day, hour, minute); + if ((((hour == 12) || (hour == 13) || (hour == 19)) && (_coreVar._currPlace != DINING_ROOM)) || + ((hour > 0) && (hour < 6) && (_coreVar._currPlace != OWN_ROOM))) + ++_coreVar._faithScore; + if (((_coreVar._currPlace < CRYPT) || (_coreVar._currPlace > MOUNTAIN)) && (_coreVar._currPlace != INSIDE_WELL) + && (_coreVar._currPlace != OWN_ROOM) && (_coreVar._selectedObjectId != 152) && (!_loseGame)) { + if ((_coreVar._faithScore > 99) && (hour > 8) && (hour < 16)) { + _crep = 1501; + loseGame(); + } else if ((_coreVar._faithScore > 99) && (hour > 0) && (hour < 9)) { + _crep = 1508; + loseGame(); + } else if ((day > 1) && (hour > 8) && (!_loseGame)) { + _crep = 1502; + loseGame(); + } + } + menuUp(); +} + +/** + * Engine function - Transform time into a char + * @remarks Originally called 'tmaj3' + */ +void MortevielleEngine::hourToChar() { + int day, hour, minute; + + updateHour(day, hour, minute); + if (minute == 30) + minute = 1; + hour += day * 24; + minute += hour * 2; + _coreVar._fullHour = (unsigned char)minute; +} + +/** + * Engine function - extract time from a char + * @remarks Originally called 'theure' + */ +void MortevielleEngine::charToHour() { + int fullHour = _coreVar._fullHour; + int tmpHour = fullHour % 48; + _currDay = fullHour / 48; + _currHalfHour = tmpHour % 2; + _currHour = tmpHour / 2; + _hour = _currHour; + if (_currHalfHour == 1) + _minute = 30; + else + _minute = 0; +} + +/** + * Engine function - Clear upper left part of Screen - Type 1 + * @remarks Originally called 'clsf1' + */ +void MortevielleEngine::clearUpperLeftPart() { + _mouse.hideMouse(); + _screenSurface.fillRect(0, Common::Rect(0, 11, 514, 175)); + _mouse.showMouse(); +} + +/** + * Engine function - Clear low bar used by description + * @remarks Originally called 'clsf2' + */ +void MortevielleEngine::clearDescriptionBar() { + _mouse.hideMouse(); + if (_largestClearScreen) { + _screenSurface.fillRect(0, Common::Rect(1, 176, 633, 199)); + _screenSurface.drawBox(0, 176, 634, 23, 15); + _largestClearScreen = false; + } else { + _screenSurface.fillRect(0, Common::Rect(1, 176, 633, 190)); + _screenSurface.drawBox(0, 176, 634, 14, 15); + } + _mouse.showMouse(); +} + +/** + * Engine function - Clear lowest bar used by verbs + * @remarks Originally called 'clsf3' + */ +void MortevielleEngine::clearVerbBar() { + _mouse.hideMouse(); + _screenSurface.fillRect(0, Common::Rect(1, 192, 633, 199)); + _screenSurface.drawBox(0, 191, 634, 8, 15); + _mouse.showMouse(); +} + +/** + * Engine function - Clear upper right part of the screen + * @remarks Originally called 'clsf10' + */ +void MortevielleEngine::clearUpperRightPart() { + Common::String st; + + _mouse.hideMouse(); + + // Clear ambiance description + _screenSurface.fillRect(15, Common::Rect(544, 93, 600, 98)); + if (_coreVar._faithScore < 33) + st = getEngineString(S_COOL); + else if (_coreVar._faithScore < 66) + st = getEngineString(S_LOURDE); + else if (_coreVar._faithScore > 65) + st = getEngineString(S_MALSAINE); + + int x1 = 580 - (_screenSurface.getStringWidth(st) / 2); + _screenSurface.putxy(x1, 92); + _screenSurface.drawString(st, 4); + + // Clear person list + _screenSurface.fillRect(15, Common::Rect(560, 24, 610, 86)); + _mouse.showMouse(); +} + +/** + * Engine function - Get a random number between two values + * @remarks Originally called 'get_random_number' and 'hazard' + */ +int MortevielleEngine::getRandomNumber(int minval, int maxval) { + return _randomSource.getRandomNumber(maxval - minval) + minval; +} + +/** + * Engine function - Show alert "use move menu" + * @remarks Originally called 'aldepl' + */ +void MortevielleEngine::showMoveMenuAlert() { + _dialogManager.show(getEngineString(S_USE_DEP_MENU), 1); +} + +/** + * The original engine used this method to display a starting text screen letting the player + * select the graphics mode to use + * @remarks Originally called 'dialpre' + */ +void MortevielleEngine::showConfigScreen() { + _crep = 998; +} + +/** + * Decodes a number of 64 byte blocks + * @param pStart Start of data + * @param count Number of 64 byte blocks + * @remarks Originally called 'zzuul' + */ +void MortevielleEngine::decodeNumber(byte *pStart, int count) { + while (count-- > 0) { + for (int idx = 0; idx < 64; ++pStart, ++idx) { + uint16 v = ((*pStart - 0x80) << 1) + 0x80; + + if (v & 0x8000) + *pStart = 0; + else if (v & 0xff00) + *pStart = 0xff; + else + *pStart = (byte)v; + } + } +} + +const byte cryptoArrDefaultFr[32] = { + 32, 101, 115, 97, 114, 105, 110, + 117, 116, 111, 108, 13, 100, 99, + 112, 109, 46, 118, 130, 39, 102, + 98, 44, 113, 104, 103, 33, 76, + 85, 106, 30, 31 +}; + +const byte cryptoArr30Fr[32] = { + 69, 67, 74, 138, 133, 120, 77, 122, + 121, 68, 65, 63, 73, 80, 83, 82, + 156, 45, 58, 79, 49, 86, 78, 84, + 71, 81, 64, 66, 135, 34, 136, 91 +}; + +const byte cryptoArr31Fr[32]= { + 93, 47, 48, 53, 50, 70, 124, 75, + 72, 147, 140, 150, 151, 57, 56, 51, + 107, 139, 55, 89, 131, 37, 54, 88, + 119, 0, 0, 0, 0, 0, 0, 0 +}; + +const byte cryptoArrDefaultDe[32] = { + 0x20, 0x65, 0x6E, 0x69, 0x73, 0x72, 0x74, + 0x68, 0x61, 0x75, 0x0D, 0x63, 0x6C, 0x64, + 0x6D, 0x6F, 0x67, 0x2E, 0x62, 0x66, 0x53, + 0x2C, 0x77, 0x45, 0x7A, 0x6B, 0x44, 0x76, + 0x9C, 0x47, 0x1E, 0x1F +}; + +const byte cryptoArr30De[32] = { + 0x49, 0x4D, 0x21, 0x42, 0x4C, 0x70, 0x41, 0x52, + 0x57, 0x4E, 0x48, 0x3F, 0x46, 0x50, 0x55, 0x4B, + 0x5A, 0x4A, 0x54, 0x31, 0x4F, 0x56, 0x79, 0x3A, + 0x6A, 0x5B, 0x5D, 0x40, 0x22, 0x2F, 0x30, 0x35 +}; + +const byte cryptoArr31De[32]= { + 0x78, 0x2D, 0x32, 0x82, 0x43, 0x39, 0x33, 0x38, + 0x7C, 0x27, 0x37, 0x3B, 0x25, 0x28, 0x29, 0x36, + 0x51, 0x59, 0x71, 0x81, 0x87, 0x88, 0x93, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const byte *cryptoArrDefault, *cryptoArr30, *cryptoArr31; +uint16 ctrlChar; + +/** + * Decrypt the next character + * @param c OUT, next decrypted char + * @param idx IN/OUT, current buffer index + * @param pt IN/OUT, current encryption point + * @return a boolean specifying if a stop character has been encountered + * @remarks Originally called 'cinq_huit' + */ +bool MortevielleEngine::decryptNextChar(char &c, int &idx, byte &pt) { + uint16 oct, ocd; + + /* 5-8 */ + oct = _dialogIndexArray[idx]; + oct = ((uint16)(oct << (16 - pt))) >> (16 - pt); + if (pt < 6) { + ++idx; + oct = oct << (5 - pt); + pt += 11; + oct = oct | ((uint)_dialogIndexArray[idx] >> pt); + } else { + pt -= 5; + oct = (uint)oct >> pt; + } + + if (oct == ctrlChar) { + c = '$'; + return true; + } else if (oct == 30 || oct == 31) { + ocd = _dialogIndexArray[idx]; + ocd = (uint16)(ocd << (16 - pt)) >> (16 - pt); + if (pt < 6) { + ++idx; + ocd = ocd << (5 - pt); + pt += 11; + ocd = ocd | ((uint)_dialogIndexArray[idx] >> pt); + } else { + pt -= 5; + ocd = (uint)ocd >> pt; + } + + if (oct == 30) + c = (unsigned char)cryptoArr30[ocd]; + else + c = (unsigned char)cryptoArr31[ocd]; + + if (c == '\0') { + c = '#'; + return true; + } + } else { + c = (unsigned char)cryptoArrDefault[oct]; + } + return false; +} + +/** + * Decode and extract the line with the given Id + * @remarks Originally called 'deline' + */ +Common::String MortevielleEngine::getString(int num) { + Common::String wrkStr = ""; + + if (num < 0) { + warning("getString(%d): num < 0! Skipping", num); + } else if (!_txxFileFl) { + wrkStr = getGameString(num); + } else { + int hint = _dialogHintArray[num]._hintId; + byte point = _dialogHintArray[num]._point; + int length = 0; + bool endFl = false; + char let; + do { + endFl = decryptNextChar(let, hint, point); + wrkStr += let; + ++length; + } while (!endFl); + } + + while (wrkStr.lastChar() == '$') + // Remove trailing '$'s + wrkStr.deleteLastChar(); + + return wrkStr; +} + +/** + * Reset object place + * @remarks Originally called 'copcha' + */ +void MortevielleEngine::resetObjectPlace() { + for (int i = kAcha; i < kAcha + 390; i++) + _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; + + for (int i = 2; i <= 6; ++i) + _coreVar._inventory[i] = 0; + + // Only object in inventory: a gun + _coreVar._inventory[1] = 113; + + _coreVar._fullHour = (unsigned char)20; + + for (int i = 1; i <= 10; ++i) + _coreVar._pctHintFound[i] = ' '; + + for (int i = 1; i <= 6; ++i) + _coreVar._availableQuestion[i] = '*'; + + for (int i = 7; i <= 9; ++i) + _coreVar._availableQuestion[i] = ' '; + + for (int i = 10; i <= 28; ++i) + _coreVar._availableQuestion[i] = '*'; + + for (int i = 29; i <= 42; ++i) + _coreVar._availableQuestion[i] = ' '; + + _coreVar._availableQuestion[33] = '*'; + + for (int i = 1; i <= 8; ++i) + _charAnswerCount[i] = 0; + + initMaxAnswer(); +} + +/** + * Engine function - Set the palette + * @remarks Originally called 'writepal' + */ +void MortevielleEngine::setPal(int n) { + for (int i = 1; i <= 16; ++i) { + _curPict[(2 * i)] = _stdPal[n][i].x; + _curPict[(2 * i) + 1] = _stdPal[n][i].y; + } +} + +/** + * Engine function - Load Palette from File + * @remarks Originally called 'charpal' + */ +void MortevielleEngine::loadPalette() { + Common::File f; + + if (!f.open("fxx.mor")) { + if (f.open("mfxx.mor")) + f.seek(7 * 25); + else + error("Missing file - fxx.mor"); + } + + for (int i = 0; i < 108; ++i) + _drawingSizeArr[i] = f.readSint16LE(); + f.close(); + + if (!f.open("plxx.mor")) + error("Missing file - plxx.mor"); + for (int i = 0; i <= 90; ++i) { + for (int j = 1; j <= 16; ++j) { + _stdPal[i][j].x = f.readByte(); + _stdPal[i][j].y = f.readByte(); + } + } + f.close(); + + if (!f.open("cxx.mor")) + error("Missing file - cxx.mor"); + + // Skip CGA Palette and Patterns + + f.close(); +} + +/** + * Engine function - Load Texts from File + * @remarks Originally called 'chartex' + */ +void MortevielleEngine::loadTexts() { + Common::File inpFile; + Common::File ntpFile; + + _txxFileFl = false; + if (getLanguage() == Common::EN_ANY) { + warning("English version expected - Switching to DAT file"); + return; + } + + if (!inpFile.open("TXX.INP")) { + if (!inpFile.open("TXX.MOR")) { + warning("Missing file - TXX.INP or .MOR - Switching to DAT file"); + return; + } + } + if (ntpFile.open("TXX.NTP")) { + cryptoArr30 = cryptoArr30Fr; + cryptoArr31 = cryptoArr31Fr; + cryptoArrDefault = cryptoArrDefaultFr; + ctrlChar = 11; + } else if (ntpFile.open("TXX.IND")) { + cryptoArr30 = cryptoArr30De; + cryptoArr31 = cryptoArr31De; + cryptoArrDefault = cryptoArrDefaultDe; + ctrlChar = 10; + } else { + warning("Missing file - TXX.NTP or .IND - Switching to DAT file"); + return; + } + + if ((inpFile.size() > (kMaxDialogIndex * 2)) || (ntpFile.size() > (kMaxDialogHint * 3))) { + warning("TXX file - Unexpected format - Switching to DAT file"); + return; + } + + for (int i = 0; i < inpFile.size() / 2; ++i) + _dialogIndexArray[i] = inpFile.readUint16LE(); + + inpFile.close(); + _txxFileFl = true; + + for (int i = 0; i < (ntpFile.size() / 3); ++i) { + _dialogHintArray[i]._hintId = ntpFile.readSint16LE(); + _dialogHintArray[i]._point = ntpFile.readByte(); + } + + ntpFile.close(); + +} + +void MortevielleEngine::loadCFIEC() { + Common::File f; + + if (!f.open("cfiec.mor")) { + if (!f.open("alcfiec.mor")) + error("Missing file - *cfiec.mor"); + } + + _cfiecBufferSize = ((f.size() / 128) + 1) * 128; + int32 fileSize = f.size(); + + if (!_reloadCFIEC) + _cfiecBuffer = (byte *)malloc(sizeof(byte) * _cfiecBufferSize); + + for (int32 i = 0; i < fileSize; ++i) + _cfiecBuffer[i] = f.readByte(); + + for (int i = fileSize; i < _cfiecBufferSize; i++) + _cfiecBuffer[i] = 0; + + f.close(); + + _reloadCFIEC = false; +} + + +void MortevielleEngine::loadCFIPH() { + Common::File f; + + if (!f.open("cfiph.mor")) { + if (!f.open("alcfiph.mor")) + error("Missing file - *cfiph.mor"); + } + + _soundManager._cfiphBuffer = (uint16 *)malloc(sizeof(uint16) * (f.size() / 2)); + + for (int i = 0; i < (f.size() / 2); ++i) + _soundManager._cfiphBuffer[i] = f.readUint16BE(); + + f.close(); +} + +/** + * Engine function - Play Music + * @remarks Originally called 'music' + */ +void MortevielleEngine::music() { + if (_soundOff) + return; + + _reloadCFIEC = true; + + Common::File f; + if (!f.open("mort.img")) + error("Missing file - mort.img"); + + int size = f.size(); + byte *compMusicBuf = (byte *)malloc(sizeof(byte) * size); + byte *musicBuf = (byte *)malloc(sizeof(byte) * size * 2); + f.read(compMusicBuf, size); + f.close(); + + int musicSize = _soundManager.decodeMusic(compMusicBuf, musicBuf, size); + free(compMusicBuf); + + _soundManager.playSong(musicBuf, musicSize, 5); + while (keyPressed()) + getChar(); + + free(musicBuf); +} + +/** + * Engine function - Show title screen + * @remarks Originally called 'suite' + */ +void MortevielleEngine::showTitleScreen() { + clearScreen(); + handleDescriptionText(7, 2035); + _caff = 51; + _text.taffich(); + testKeyboard(); + clearScreen(); + draw(0, 0); + + Common::String cpr = "COPYRIGHT 1989 : LANKHOR"; + _screenSurface.putxy(104 + 72 * kResolutionScaler, 185); + _screenSurface.drawString(cpr, 0); +} + +/** + * Draw picture + * @remarks Originally called 'dessine' + */ +void MortevielleEngine::draw(int x, int y) { + _mouse.hideMouse(); + setPal(_numpal); + displayPicture(_curPict, x, y); + _mouse.showMouse(); +} + +/** + * Draw right frame + * @remarks Originally called 'dessine_rouleau' + */ +void MortevielleEngine::drawRightFrame() { + setPal(89); + _mouse.hideMouse(); + displayPicture(_rightFramePict, 0, 0); + _mouse.showMouse(); +} + +/** + * Read the current system time + */ +int MortevielleEngine::readclock() { + TimeDate dateTime; + g_system->getTimeAndDate(dateTime); + + int m = dateTime.tm_min * 60; + int h = dateTime.tm_hour * 3600; + return h + m + dateTime.tm_sec; +} + +/** + * Engine function - Prepare room and hint string + * @remarks Originally called 'tinke' + */ +void MortevielleEngine::prepareRoom() { + int day, hour, minute; + + _anyone = false; + updateHour(day, hour, minute); + if (day != _day) { + _day = day; + for (int i = 0; i < 9; i++) { + if (_charAnswerMax[i] > 0) + --_charAnswerMax[i]; + _charAnswerCount[i] = 0; + } + } + if ((hour > _hour) || ((hour == 0) && (_hour == 23))) { + _hour = hour; + _minute = 0; + drawClock(); + int hintCount = 0; + for (int i = 1; i <= 10; ++i) { + if (_coreVar._pctHintFound[i] == '*') + ++hintCount; + } + + Common::String pctStr; + if (hintCount == 10) + pctStr = "10"; + else + pctStr = (unsigned char)(hintCount + 48); + + _hintPctMessage = "[1]["; + _hintPctMessage += getEngineString(S_SHOULD_HAVE_NOTICED); + _hintPctMessage += pctStr; + _hintPctMessage += '0'; + _hintPctMessage += getEngineString(S_NUMBER_OF_HINTS); + _hintPctMessage += "]["; + _hintPctMessage += getEngineString(S_OKAY); + _hintPctMessage += ']'; + } + if (minute > _minute) { + _minute = 30; + drawClock(); + } + if (_mouse._pos.y < 12) + return; + + if (!_blo) { + if ((hour == 12) || ((hour > 18) && (hour < 21)) || ((hour >= 0) && (hour < 7))) + _inGameHourDuration = kTime2; + else + _inGameHourDuration = kTime1; + if ((_coreVar._faithScore > 33) && (_coreVar._faithScore < 66)) + _inGameHourDuration -= (_inGameHourDuration / 3); + + if (_coreVar._faithScore > 65) + _inGameHourDuration -= ((_inGameHourDuration / 3) * 2); + + int newHour = readclock(); + if ((newHour - _currentDayHour) > _inGameHourDuration) { + bool activeMenu = _menu._menuActive; + _menu.eraseMenu(); + _currentHourCount += ((newHour - _currentDayHour) / _inGameHourDuration); + _currentDayHour = newHour; + switch (_place) { + case GREEN_ROOM: + case DARKBLUE_ROOM: + setRandomPresenceGreenRoom(_coreVar._faithScore); + break; + case PURPLE_ROOM: + setRandomPresencePurpleRoom(_coreVar._faithScore); + break; + case BLUE_ROOM: + setRandomPresenceBlueRoom(_coreVar._faithScore); + break; + case RED_ROOM: + case GREEN_ROOM2: + setRandomPresenceRedRoom(_coreVar._faithScore); + break; + case JULIA_ROOM: + setRandomPresenceJuliaRoom(_coreVar._faithScore); + break; + case DINING_ROOM: + setRandomPresenceDiningRoom(_coreVar._faithScore); + break; + case BUREAU: + setRandomPresenceBureau(_coreVar._faithScore); + break; + case KITCHEN: + setRandomPresenceKitchen(_coreVar._faithScore); + break; + case ATTIC: + case CELLAR: + setRandomPresenceAttic(_coreVar._faithScore); + break; + case LANDING: + case ROOM26: + setRandomPresenceLanding(_coreVar._faithScore); + break; + case CHAPEL: + setRandomPresenceChapel(_coreVar._faithScore); + break; + } + if ((_savedBitIndex != 0) && (_currBitIndex != 10)) + _savedBitIndex = _currBitIndex; + + if ((_savedBitIndex == 0) && (_currBitIndex > 0)) { + if ((_coreVar._currPlace == ATTIC) || (_coreVar._currPlace == CELLAR)) { + initCaveOrCellar(); + } else if (_currBitIndex == 10) { + _currBitIndex = 0; + if (!_uptodatePresence) { + _uptodatePresence = true; + _startHour = readclock(); + if (getRandomNumber(1, 5) < 5) { + clearVerbBar(); + prepareScreenType2(); + displayTextInVerbBar(getEngineString(S_HEAR_NOISE)); + int rand = (getRandomNumber(0, 4)) - 2; + _soundManager.startSpeech(1, rand, 1); + _soundManager.waitSpeech(); + clearVerbBar(); + } + } + } + } + + if (activeMenu) + _menu.drawMenu(); + } + } + _endHour = readclock(); + if ((_uptodatePresence) && ((_endHour - _startHour) > 17)) { + getPresenceBitIndex(_place); + _uptodatePresence = false; + _startHour = 0; + if ((_coreVar._currPlace > OWN_ROOM) && (_coreVar._currPlace < DINING_ROOM)) + _anyone = true; + } +} + +/** + * Engine function - Draw Clock + * @remarks Originally called 'pendule' + */ +void MortevielleEngine::drawClock() { + const int cv[2][12] = { + { 5, 8, 10, 8, 5, 0, -5, -8, -10, -8, -5, 0 }, + { -5, -3, 0, 3, 5, 6, 5, 3, 0, -3, -5, -6 } + }; + const int x = 580; + const int y = 123; + const int rg = 9; + + _mouse.hideMouse(); + + _screenSurface.drawRectangle(570, 118, 20, 10); + _screenSurface.drawRectangle(578, 114, 6, 18); + + if (_minute == 0) + _screenSurface.drawLine(((uint)x >> 1) * kResolutionScaler, y, ((uint)x >> 1) * kResolutionScaler, (y - rg), 1); + else + _screenSurface.drawLine(((uint)x >> 1) * kResolutionScaler, y, ((uint)x >> 1) * kResolutionScaler, (y + rg), 1); + + int hour12 = _hour; + if (hour12 > 12) + hour12 -= 12; + if (hour12 == 0) + hour12 = 12; + + _screenSurface.drawLine(((uint)x >> 1) * kResolutionScaler, y, ((uint)(x + cv[0][hour12 - 1]) >> 1) * kResolutionScaler, y + cv[1][hour12 - 1], 1); + _mouse.showMouse(); + _screenSurface.putxy(568, 154); + + if (_hour > 11) + _screenSurface.drawString("PM ", 1); + else + _screenSurface.drawString("AM ", 1); + + _screenSurface.putxy(550, 160); + if ((_day >= 0) && (_day <= 8)) { + Common::String tmp = getEngineString(S_DAY); + tmp.insertChar((char)(_day + 49), 0); + _screenSurface.drawString(tmp, 1); + } +} + +void MortevielleEngine::palette(int v1) { + warning("TODO: palette"); +} + +/** + * Returns a substring of the given string + * @param s Source string + * @param idx Starting index (1 based) + * @param size Number of characters to return + */ + +Common::String MortevielleEngine::copy(const Common::String &s, int idx, size_t size) { + assert(idx + size < s.size()); + + // Copy the substring into a temporary buffer + char *tmp = new char[size + 1]; + strncpy(tmp, s.c_str() + idx - 1, size); + tmp[size] = '\0'; + + Common::String result(tmp); + delete[] tmp; + return result; +} + +/** + * Clear Screen + * @remarks Originally called 'hirs' + */ +void MortevielleEngine::clearScreen() { + _screenSurface.clearScreen(); +} + +/** + * Init room : Cave or Cellar + * @remarks Originally called 'cavegre' + */ +void MortevielleEngine::initCaveOrCellar() { + _coreVar._faithScore += 2; + if (_coreVar._faithScore > 69) + _coreVar._faithScore += (_coreVar._faithScore / 10); + clearVerbBar(); + prepareScreenType2(); + displayTextInVerbBar(getEngineString(S_SOMEONE_ENTERS)); + int rand = (getRandomNumber(0, 4)) - 2; + _soundManager.startSpeech(2, rand, 1); + _soundManager.waitSpeech(); + // The original was doing here a useless loop. + // It has been removed + + clearVerbBar(); + displayAloneText(); +} + +/** + * Display control menu string + * @remarks Originally called 'tctrm' + */ +void MortevielleEngine::displayControlMenu() { + handleDescriptionText(2, (3000 + _controlMenu)); + _controlMenu = 0; +} + +/** + * Display picture at a given coordinate + * @remarks Originally called 'pictout' + */ +void MortevielleEngine::displayPicture(const byte *pic, int x, int y) { + GfxSurface surface; + surface.decode(pic); + _screenSurface.drawPicture(surface, x, y); +} + +void MortevielleEngine::adzon() { + Common::File f; + + if (!f.open("don.mor")) + error("Missing file - don.mor"); + + f.read(_tabdon, 7 * 256); + f.close(); + + if (!f.open("bmor.mor")) + error("Missing file - bmor.mor"); + + f.read(&_tabdon[kFleche], 1916); + f.close(); + + // Read Right Frame Drawing + if (!f.open("dec.mor")) + error("Missing file - dec.mor"); + + free(_rightFramePict); + _rightFramePict = (byte *)malloc(sizeof(byte) * f.size()); + f.read(_rightFramePict, f.size()); + f.close(); +} + +/** + * Returns the offset within the compressed image data resource of the desired image + * @remarks Originally called 'animof' + */ +int MortevielleEngine::getAnimOffset(int frameNum, int animNum) { + int animCount = _curAnim[1]; + int aux = animNum; + if (frameNum != 1) + aux += animCount; + + return (animCount << 2) + 2 + READ_BE_UINT16(&_curAnim[aux << 1]); +} + +/** + * Display text in description bar + * @remarks Originally called 'text1' + */ +void MortevielleEngine::displayTextInDescriptionBar(int x, int y, int nb, int mesgId) { + Common::String tmpStr = getString(mesgId); + if ((y == 182) && ((int) tmpStr.size() > nb)) + y = 176; + _text.displayStr(tmpStr, x, y, nb, 20, _textColor); +} + +/** + * Display description text + * @remarks Originally called 'repon' + */ +void MortevielleEngine::handleDescriptionText(int f, int mesgId) { + if ((mesgId > 499) && (mesgId < 563)) { + Common::String tmpStr = getString(mesgId - 501 + kInventoryStringIndex); + + if ((int) tmpStr.size() > ((58 + (kResolutionScaler - 1) * 37) << 1)) + _largestClearScreen = true; + else + _largestClearScreen = false; + + clearDescriptionBar(); + _text.displayStr(tmpStr, 8, 176, 85, 3, 5); + } else { + mapMessageId(mesgId); + switch (f) { + case 2: + case 8: + clearDescriptionBar(); + prepareScreenType2(); + displayTextInDescriptionBar(8, 182, 103, mesgId); + if ((mesgId == 68) || (mesgId == 69)) + _coreVar._availableQuestion[40] = '*'; + if ((mesgId == 104) && (_caff == CELLAR)) { + _coreVar._availableQuestion[36] = '*'; + if (_coreVar._availableQuestion[39] == '*') { + _coreVar._pctHintFound[3] = '*'; + _coreVar._availableQuestion[38] = '*'; + } + } + break; + case 1: + case 6: + case 9: { + int i; + if ((f == 1) || (f == 6)) + i = 4; + else + i = 5; + + Common::String tmpStr = getString(mesgId); + _text.displayStr(tmpStr, 80, 40, 60, 25, i); + + if (mesgId == 180) + _coreVar._pctHintFound[6] = '*'; + else if (mesgId == 179) + _coreVar._pctHintFound[10] = '*'; + } + break; + default: + break; + } + } +} + +/** + * Recompute message Id + * @remarks Originally called 'modif' + */ +void MortevielleEngine::mapMessageId(int &mesgId) { + if (mesgId == 26) + mesgId = 25; + else if ((mesgId > 29) && (mesgId < 36)) + mesgId -= 4; + else if ((mesgId > 69) && (mesgId < 78)) + mesgId -= 37; + else if ((mesgId > 99) && (mesgId < 194)) + mesgId -= 59; + else if ((mesgId > 996) && (mesgId < 1000)) + mesgId -= 862; + else if ((mesgId > 1500) && (mesgId < 1507)) + mesgId -= 1363; + else if ((mesgId > 1507) && (mesgId < 1513)) + mesgId -= 1364; + else if ((mesgId > 1999) && (mesgId < 2002)) + mesgId -= 1851; + else if (mesgId == 2010) + mesgId = 151; + else if ((mesgId > 2011) && (mesgId < 2025)) + mesgId -= 1860; + else if (mesgId == 2026) + mesgId = 165; + else if ((mesgId > 2029) && (mesgId < 2037)) + mesgId -= 1864; + else if ((mesgId > 3000) && (mesgId < 3005)) + mesgId -= 2828; + else if (mesgId == 4100) + mesgId = 177; + else if (mesgId == 4150) + mesgId = 178; + else if ((mesgId > 4151) && (mesgId < 4156)) + mesgId -= 3973; + else if (mesgId == 4157) + mesgId = 183; + else if ((mesgId == 4160) || (mesgId == 4161)) + mesgId -= 3976; +} + +/** + * Initialize open objects array + * @remarks Originally called 'initouv' + */ +void MortevielleEngine::resetOpenObjects() { + for (int i = 1; i <= 6; ++i) + _openObjects[i] = 0; + _openObjCount = 0; +} + +/** + * Display Text Block + * @remarks Originally called 'ecr2' + */ +void MortevielleEngine::displayTextBlock(Common::String text) { + // Some dead code was present in the original: removed + _screenSurface.putxy(8, 177); + int tlig = 59 + (kResolutionScaler - 1) * 36; + + if ((int)text.size() < tlig) + _screenSurface.drawString(text, 5); + else if ((int)text.size() < (tlig << 1)) { + _screenSurface.putxy(8, 176); + _screenSurface.drawString(copy(text, 1, (tlig - 1)), 5); + _screenSurface.putxy(8, 182); + _screenSurface.drawString(copy(text, tlig, tlig << 1), 5); + } else { + _largestClearScreen = true; + clearDescriptionBar(); + _screenSurface.putxy(8, 176); + _screenSurface.drawString(copy(text, 1, (tlig - 1)), 5); + _screenSurface.putxy(8, 182); + _screenSurface.drawString(copy(text, tlig, ((tlig << 1) - 1)), 5); + _screenSurface.putxy(8, 190); + _screenSurface.drawString(copy(text, tlig << 1, tlig * 3), 5); + } +} + +void MortevielleEngine::displayTextInVerbBar(Common::String text) { + clearVerbBar(); + _screenSurface.putxy(8, 192); + _screenSurface.drawString(text, 5); +} + +/** + * Display item in hand + * @remarks Originally called 'modobj' + */ +void MortevielleEngine::displayItemInHand(int objId) { + Common::String strp = Common::String(' '); + + if (objId != 500) + strp = getString(objId - 501 + kInventoryStringIndex); + + _menu.setText(_menu._inventoryMenu[8], strp); + _menu.disableMenuItem(_menu._inventoryMenu[8]); +} + +/** + * Display empty hand + * @remarks Originally called 'maivid' + */ +void MortevielleEngine::displayEmptyHand() { + _coreVar._selectedObjectId = 0; + displayItemInHand(500); +} + +/** + * Set a random presence: Leo or Max + * @remarks Originally called 'chlm' + */ +int MortevielleEngine::checkLeoMaxRandomPresence() { + int retval = getRandomNumber(1, 2); + if (retval == 2) + retval = 128; + + return retval; +} + +/** + * Reset room variables + * @remarks Originally called 'debloc' + */ +void MortevielleEngine::resetRoomVariables(int roomId) { + _num = 0; + _x = 0; + _y = 0; + if ((roomId != ROOM26) && (roomId != LANDING)) + resetPresenceInRooms(roomId); + _savedBitIndex = _currBitIndex; +} + +/** + * Compute presence stats + * @remarks Originally called 'ecfren' + */ +int MortevielleEngine::getPresenceStats(int &rand, int faithScore, int roomId) { + if (roomId == OWN_ROOM) + displayAloneText(); + int retVal = -500; + rand = 0; + if ( ((roomId == GREEN_ROOM) && (!_roomPresenceLuc) && (!_roomPresenceIda)) + || ((roomId == DARKBLUE_ROOM) && (!_roomPresenceGuy) && (!_roomPresenceEva)) ) + retVal = getPresenceStatsGreenRoom(); + if ((roomId == PURPLE_ROOM) && (!_purpleRoomPresenceLeo) && (!_juliaRoomPresenceLeo)) + retVal = getPresenceStatsPurpleRoom(); + if ( ((roomId == TOILETS) && (!_toiletsPresenceBobMax)) + || ((roomId == BATHROOM) && (!_bathRoomPresenceBobMax)) ) + retVal = getPresenceStatsToilets(); + if ((roomId == BLUE_ROOM) && (!_roomPresenceMax)) + retVal = getPresenceStatsBlueRoom(); + if ( ((roomId == RED_ROOM) && (!_roomPresenceBob)) + || ((roomId == GREEN_ROOM2) && (!_roomPresencePat))) + retVal = getPresenceStatsRedRoom(); + if ((roomId == JULIA_ROOM) && (!_juliaRoomPresenceLeo) && (!_purpleRoomPresenceLeo)) + retVal = 10; + if ( ((roomId == PURPLE_ROOM) && (_juliaRoomPresenceLeo)) + || ((roomId == JULIA_ROOM) && (_purpleRoomPresenceLeo))) + retVal = -400; + if (retVal != -500) { + retVal += faithScore; + rand = getRandomNumber(1, 100); + } + + return retVal; +} + +/** + * Set presence flags + * @remarks Originally called 'becfren' + */ +void MortevielleEngine::setPresenceFlags(int roomId) { + if ((roomId == GREEN_ROOM) || (roomId == DARKBLUE_ROOM)) { + int rand = getRandomNumber(1, 2); + if (roomId == GREEN_ROOM) { + if (rand == 1) + _roomPresenceLuc = true; + else + _roomPresenceIda = true; + } else { // roomId == DARKBLUE_ROOM + if (rand == 1) + _roomPresenceGuy = true; + else + _roomPresenceEva = true; + } + } else if (roomId == PURPLE_ROOM) + _purpleRoomPresenceLeo = true; + else if (roomId == TOILETS) + _toiletsPresenceBobMax = true; + else if (roomId == BLUE_ROOM) + _roomPresenceMax = true; + else if (roomId == RED_ROOM) + _roomPresenceBob = true; + else if (roomId == BATHROOM) + _bathRoomPresenceBobMax = true; + else if (roomId == GREEN_ROOM2) + _roomPresencePat = true; + else if (roomId == JULIA_ROOM) + _juliaRoomPresenceLeo = true; +} + +/** + * Initialize max answers per character + * @remarks Originally called 'init_nbrepm' + */ +void MortevielleEngine::initMaxAnswer() { + static const byte maxAnswer[9] = { 0, 4, 5, 6, 7, 5, 6, 5, 8 }; + + for (int idx = 0; idx < 9; ++idx) { + _charAnswerMax[idx] = maxAnswer[idx]; + _charAnswerCount[idx] = 0; + } +} + +/** + * Get Presence + * @remarks Originally called 't11' + */ +int MortevielleEngine::getPresence(int roomId) { + int retVal = 0; + int rand; + + int pres = getPresenceStats(rand, _coreVar._faithScore, roomId); + _place = roomId; + if ((roomId > OWN_ROOM) && (roomId < DINING_ROOM)) { + if (pres != -500) { + if (rand > pres) { + displayAloneText(); + retVal = 0; + } else { + setPresenceFlags(_place); + retVal = getPresenceBitIndex(_place); + } + } else + retVal = getPresenceBitIndex(_place); + } + + if (roomId > JULIA_ROOM) { + if ((roomId > LANDING) && (roomId != CHAPEL) && (roomId != ROOM26)) + displayAloneText(); + else { + int h = 0; + if (roomId == DINING_ROOM) + pres = getPresenceStatsDiningRoom(h); + else if (roomId == BUREAU) + pres = getPresenceStatsBureau(h); + else if (roomId == KITCHEN) + pres = getPresenceStatsKitchen(); + else if ((roomId == ATTIC) || (roomId == CELLAR)) + pres = getPresenceStatsAttic(); + else if ((roomId == LANDING) || (roomId == ROOM26)) + pres = getPresenceStatsLanding(); + else if (roomId == CHAPEL) + pres = getPresenceStatsChapel(h); + pres += _coreVar._faithScore; + rand = getRandomNumber(1, 100); + if (rand > pres) { + displayAloneText(); + retVal = 0; + } else { + if (roomId == DINING_ROOM) + pres = setPresenceDiningRoom(h); + else if (roomId == BUREAU) + pres = setPresenceBureau(h); + else if ((roomId == KITCHEN) || (roomId == ATTIC) || (roomId == CELLAR)) + pres = setPresenceKitchen(); + else if ((roomId == LANDING) || (roomId == ROOM26)) + pres = setPresenceLanding(); + else if (roomId == CHAPEL) + pres = setPresenceChapel(h); + retVal = pres; + } + } + } + + return retVal; +} + +/** + * Display Question String + * @remarks Originally called 'writetp' + */ +void MortevielleEngine::displayQuestionText(Common::String s, int cmd) { + _screenSurface.drawString(s, cmd); +} + +/** + * Display animation frame + * @remarks Originally called 'aniof' + */ +void MortevielleEngine::displayAnimFrame(int frameNum, int animId) { + if ((_caff == BATHROOM) && ((animId == 4) || (animId == 5))) + return; + + if ((_caff == DINING_ROOM) && (animId == 7)) + animId = 6; + else if (_caff == KITCHEN) { + if (animId == 3) + animId = 4; + else if (animId == 4) + animId = 3; + } + + int offset = getAnimOffset(frameNum, animId); + + GfxSurface surface; + surface.decode(&_curAnim[offset]); + _screenSurface.drawPicture(surface, 0, 12); + + prepareScreenType1(); +} + +/** + * Draw Picture + * @remarks Originally called 'dessin' + */ +void MortevielleEngine::drawPicture() { + clearUpperLeftPart(); + if (_caff > 99) { + draw(60, 33); + _screenSurface.drawBox(118, 32, 291, 122, 15); // Medium box + } else if (_caff > 69) { + draw(112, 48); // Heads + _screenSurface.drawBox(222, 47, 155, 92, 15); + } else { + draw(0, 12); + prepareScreenType1(); + if ((_caff < 30) || (_caff > 32)) { + for (int i = 1; i <= 6; ++i) { + if (_openObjects[i] != 0) + displayAnimFrame(1, _openObjects[i]); + } + + if (_caff == ATTIC) { + if (_coreVar._atticBallHoleObjectId == 141) + displayAnimFrame(1, 7); + + if (_coreVar._atticRodHoleObjectId == 159) + displayAnimFrame(1, 6); + } else if ((_caff == CELLAR) && (_coreVar._cellarObjectId == 151)) + displayAnimFrame(1, 2); + else if ((_caff == SECRET_PASSAGE) && (_coreVar._secretPassageObjectId == 143)) + displayAnimFrame(1, 1); + else if ((_caff == WELL) && (_coreVar._wellObjectId != 0)) + displayAnimFrame(1, 1); + } + + if (_caff < ROOM26) + startMusicOrSpeech(1); + } +} + +void MortevielleEngine::drawPictureWithText() { + _text.taffich(); + drawPicture(); + _destinationOk = false; +} + +/** + * Engine function - Place + * @remarks Originally called 'tkey1' + */ +void MortevielleEngine::testKey(bool d) { + bool quest = false; + int x, y; + bool click; + + _mouse.hideMouse(); + displayStatusInDescriptionBar('K'); + + // Wait for release from any key or mouse button + while (keyPressed()) + _key = gettKeyPressed(); + + do { + _mouse.getMousePosition(x, y, click); + keyPressed(); + } while (click); + + // Event loop + do { + if (d) + prepareRoom(); + quest = keyPressed(); + _mouse.getMousePosition(x, y, click); + if (shouldQuit()) + return; + } while (!(quest || (click) || (d && _anyone))); + if (quest) + gettKeyPressed(); + setMouseClick(false); + _mouse.showMouse(); +} + +/** + * Display Narrative Picture + * @remarks Originally called 'tlu' + */ +void MortevielleEngine::displayNarrativePicture(int af, int ob) { + _caff = 32; + drawPictureWithText(); + handleDescriptionText(6, ob + 4000); + handleDescriptionText(2, 999); + testKey(true); + _caff = af; + _currMenu = OPCODE_NONE; + _crep = 998; +} + +/** + * Prepare Display Text + * @remarks Originally called 'affrep' + */ +void MortevielleEngine::prepareDisplayText() { + _caff = _coreVar._currPlace; + _crep = _coreVar._currPlace; +} + +/** + * Exit room + * @remarks Originally called 'tsort' + */ +void MortevielleEngine::exitRoom() { + if ((_openObjCount > 0) && (_coreVar._currPlace != OWN_ROOM)) { + if (_coreVar._faithScore < 50) + _coreVar._faithScore += 2; + else + _coreVar._faithScore += (_coreVar._faithScore / 10); + } + + resetOpenObjects(); + + _roomDoorId = OWN_ROOM; + _curSearchObjId = 0; + resetRoomVariables(_coreVar._currPlace); +} + +/** + * get 'read' description + * @remarks Originally called 'st4' + */ +void MortevielleEngine::getReadDescription(int objId) { + _crep = 997; + + switch (objId) { + case 114 : + _crep = 109; + break; + case 110 : + _crep = 107; + break; + case 158 : + _crep = 113; + break; + case 152: + case 153: + case 154: + case 155: + case 156: + case 150: + case 100: + case 157: + case 160: + case 161 : + displayNarrativePicture(_caff, objId); + break; + default: + break; + } +} + +/** + * get 'search' description + * @remarks Originally called 'st7' + */ +void MortevielleEngine::getSearchDescription(int objId) { + switch (objId) { + case 116: + case 144: + _crep = 104; + break; + case 126: + case 111: + _crep = 108; + break; + case 132: + _crep = 111; + break; + case 142: + _crep = 112; + break; + default: + _crep = 183; + getReadDescription(objId); + } +} + +/** + * Menu up + * @remarks Originally called 'mennor' + */ +void MortevielleEngine::menuUp() { + _menu.menuUp(_currMenu); +} + +/** + * Draw discussion box + * @remarks Originally called 'premtet' + */ +void MortevielleEngine::drawDiscussionBox() { + draw(10, 80); + _screenSurface.drawBox(18, 79, 155, 92, 15); +} + +/** + * Try to put an object somewhere + * @remarks Originally called 'ajchai' + */ +void MortevielleEngine::putObject() { + int putId = kAcha + ((_curSearchObjId - 1) * 10) - 1; + int i; + for (i = 1; (i <= 9) && (_tabdon[putId + i] != 0); i++) + ; + + if (_tabdon[putId + i] == 0) + _tabdon[putId + i] = _coreVar._selectedObjectId; + else + _crep = 192; +} + +/** + * Check if inventory is full and, if not, add object in it. + * @remarks Originally called 'ajjer' + */ +void MortevielleEngine::addObjectToInventory(int objectId) { + int i; + + for (i = 1; (i <= 5) && (_coreVar._inventory[i] != 0); i++) + ; + + if (_coreVar._inventory[i] == 0) { + _coreVar._inventory[i] = objectId; + _menu.setInventoryText(); + } else + // Inventory is full + _crep = 139; +} + +/** + * Interact with NPC + * @remarks Originally called 'quelquun' + */ +void MortevielleEngine::interactNPC() { + if (_menu._menuDisplayed) + _menu.eraseMenu(); + + endSearch(); + _crep = 997; +L1: + if (!_hiddenHero) { + if (_crep == 997) + _crep = 138; + handleDescriptionText(2, _crep); + if (_crep == 138) + _soundManager.startSpeech(5, 2, 1); + else + _soundManager.startSpeech(4, 4, 1); + + if (_openObjCount == 0) + _coreVar._faithScore += 2; + else if (_coreVar._faithScore < 50) + _coreVar._faithScore += 4; + else + _coreVar._faithScore += 3 * (_coreVar._faithScore / 10); + exitRoom(); + _menu.setDestinationText(LANDING); + int charIdx = convertBitIndexToCharacterIndex(_currBitIndex); + _caff = 69 + charIdx; + _crep = _caff; + _currMenu = MENU_DISCUSS; + _currAction = (_menu._discussMenu[charIdx]._menuId << 8) | _menu._discussMenu[charIdx]._actionId; + _syn = true; + _col = true; + } else { + if (getRandomNumber(1, 3) == 2) { + _hiddenHero = false; + _crep = 137; + goto L1; + } else { + handleDescriptionText(2, 136); + int rand = (getRandomNumber(0, 4)) - 2; + _soundManager.startSpeech(3, rand, 1); + clearDescriptionBar(); + displayAloneText(); + resetRoomVariables(MANOR_FRONT); + prepareDisplayText(); + } + } + if (_menu._menuDisplayed) + _menu.drawMenu(); +} + +/** + * Search - Prepare next object + * @remarks Originally called 'tsuiv' + */ +void MortevielleEngine::prepareNextObject() { + int objId; + int tabIdx = kAcha + ((_curSearchObjId - 1) * 10) - 1; + int localSeearchCount = 0; + do { + ++localSeearchCount; + ++_searchCount; + objId = _tabdon[tabIdx + _searchCount]; + } while ((objId == 0) && (_searchCount <= 9)); + + if ((objId != 0) && (_searchCount < 11)) { + _caff = objId; + _crep = _caff + 400; + if (_currBitIndex != 0) + // Someone is present in the room + _coreVar._faithScore += 2; + } else { + prepareDisplayText(); + endSearch(); + if (localSeearchCount > 9) + _crep = 131; + } +} + +/** + * Display Arrow status + * @remarks Originally called 'tfleche' + */ +void MortevielleEngine::displayStatusArrow() { + bool qust; + char touch; + + if (_num == 9999) + return; + + displayStatusInDescriptionBar((unsigned char)152); + bool inRect = false; + do { + touch = '\0'; + + do { + _mouse.moveMouse(qust, touch); + if (shouldQuit()) + return; + + if (getMouseClick()) + inRect = (_mouse._pos.x < 256 * kResolutionScaler) && (_mouse._pos.y < 176) && (_mouse._pos.y > 12); + prepareRoom(); + } while (!(qust || inRect || _anyone)); + + if (qust && (touch == '\103')) + _dialogManager.show(_hintPctMessage, 1); + } while (!((touch == '\73') || ((touch == '\104') && (_x != 0) && (_y != 0)) || (_anyone) || (inRect))); + + if (touch == '\73') + _keyPressedEsc = true; + + if (inRect) { + _x = _mouse._pos.x; + _y = _mouse._pos.y; + } +} + +/** + * Set coordinates + * @remarks Originally called 'tcoord' + */ +void MortevielleEngine::setCoordinates(int sx) { + int sy, ix, iy; + int ib; + + + _num = 0; + _crep = 999; + int a = 0; + int atdon = kAmzon + 3; + int cy = 0; + while (cy < _caff) { + a += _tabdon[atdon]; + atdon += 4; + ++cy; + } + + if (_tabdon[atdon] == 0) { + _crep = 997; + return; + } + + a += kFleche; + int cb = 0; + for (cy = 0; cy <= (sx - 2); ++cy) { + ib = (_tabdon[a + cb] << 8) + _tabdon[(a + cb + 1)]; + cb += (ib * 4) + 2; + } + ib = (_tabdon[a + cb] << 8) + _tabdon[(a + cb + 1)]; + if (ib == 0) { + _crep = 997; + return; + } + + cy = 1; + do { + cb += 2; + sx = _tabdon[a + cb] * kResolutionScaler; + sy = _tabdon[(a + cb + 1)]; + cb += 2; + ix = _tabdon[a + cb] * kResolutionScaler; + iy = _tabdon[(a + cb + 1)]; + ++cy; + } while (!(((_x >= sx) && (_x <= ix) && (_y >= sy) && (_y <= iy)) || (cy > ib))); + + if ((_x >= sx) && (_x <= ix) && (_y >= sy) && (_y <= iy)) { + _num = cy - 1; + return; + } + + _crep = 997; +} + +/** + * Display LOOK Screen + * @remarks Originally called 'treg' + */ +void MortevielleEngine::displayLookScreen(int objId) { + int mdes = _caff; + _caff = objId; + + if (((_caff > 29) && (_caff < 33)) || (_caff == 144) || (_caff == 147) || (_caff == 149) || (_currAction == _menu._opcodeSLook)) { + drawPictureWithText(); + if ((_caff > 29) && (_caff < 33)) + handleDescriptionText(2, _caff); + else + handleDescriptionText(2, _caff + 400); + testKey(true); + _caff = mdes; + _currMenu = MENU_NONE; + _crep = 998; + } else { + _obpart = true; + _crep = _caff + 400; + _menu.setSearchMenu(); + } +} + +/** + * Engine function - Put in hand + * @remarks Originally called 'avpoing' + */ +void MortevielleEngine::putInHand(int &objId) { + _crep = 999; + if (_coreVar._selectedObjectId != 0) + addObjectToInventory(_coreVar._selectedObjectId); + + // If inventory wasn't full + if (_crep != 139) { + displayItemInHand(objId + 400); + _coreVar._selectedObjectId = objId; + objId = 0; + } +} + +/** + * Search - Get the first object + * @remarks Originally called 'rechai' + */ +int MortevielleEngine::getFirstObject() { + int tmpPlace = _coreVar._currPlace; + + if (_coreVar._currPlace == CRYPT) + tmpPlace = CELLAR; + + return _tabdon[kAsearch + (tmpPlace * 7) + _num - 1]; +} + +/** + * Check before leaving the secret passage + * @remarks Originally called 't23coul' + */ +int MortevielleEngine::checkLeaveSecretPassage() { + if (!checkInventory(143)) { + _crep = 1512; + loseGame(); + } + + return CELLAR; +} + +/** + * Display status character in description bar + * @remarks Originally called 'fenat' + */ +void MortevielleEngine::displayStatusInDescriptionBar(char stat) { + _mouse.hideMouse(); + _screenSurface.writeCharacter(Common::Point(306, 193), stat, 12); + _screenSurface.drawBox(300, 191, 16, 8, 15); + _mouse.showMouse(); +} + +/** + * Test Keyboard + * @remarks Originally called 'teskbd' + */ +void MortevielleEngine::testKeyboard() { + if (keyPressed()) + gettKeyPressed(); +} + +/** + * Test Key Pressed + * @remarks Originally called 'testou' + */ +int MortevielleEngine::gettKeyPressed() { + char ch = getChar(); + + switch (ch) { + case '\23' : + _soundOff = !_soundOff; + break; + case '\26' : + if ((_x26KeyCount == 1) || (_x26KeyCount == 2)) { + decodeNumber(&_cfiecBuffer[161 * 16], (_cfiecBufferSize - (161 * 16)) / 64); + ++_x26KeyCount; + + return 61; + } + break; + case '\33' : + if (keyPressed()) + ch = getChar(); + break; + default: + break; + } + + return (int)ch; +} + +} // End of namespace Mortevielle diff --git a/engines/neverhood/background.cpp b/engines/neverhood/background.cpp index 0a80bd8390..d6a9900d38 100644 --- a/engines/neverhood/background.cpp +++ b/engines/neverhood/background.cpp @@ -33,11 +33,11 @@ Background::Background(NeverhoodEngine *vm, int objectPriority) Background::Background(NeverhoodEngine *vm, uint32 fileHash, int objectPriority, int surfacePriority) : Entity(vm, objectPriority), _surface(NULL), _spriteResource(vm) { - + _spriteResource.load(fileHash); createSurface(surfacePriority, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height); _surface->drawSpriteResource(_spriteResource); - + } Background::~Background() { @@ -45,7 +45,7 @@ Background::~Background() { } void Background::createSurface(int surfacePriority, int16 width, int16 height) { - _surface = new BaseSurface(_vm, surfacePriority, width, height); + _surface = new BaseSurface(_vm, surfacePriority, width, height, "background"); _surface->setTransparent(false); _spriteResource.getPosition().x = width; _spriteResource.getPosition().y = height; diff --git a/engines/neverhood/blbarchive.cpp b/engines/neverhood/blbarchive.cpp index 9f5f46487c..d730d75718 100644 --- a/engines/neverhood/blbarchive.cpp +++ b/engines/neverhood/blbarchive.cpp @@ -58,8 +58,8 @@ BlbArchive::~BlbArchive() { void BlbArchive::open(const Common::String &filename) { BlbHeader header; uint16 *extDataOffsets; - - _entries.clear(); + + _entries.clear(); if (!_fd.open(filename)) error("BlbArchive::open() Could not open %s", filename.c_str()); @@ -83,16 +83,16 @@ void BlbArchive::open(const Common::String &filename) { entry.fileHash = _fd.readUint32LE(); _entries.push_back(entry); } - + extDataOffsets = new uint16[header.fileCount]; - + // Load file records for (uint i = 0; i < header.fileCount; i++) { BlbArchiveEntry &entry = _entries[i]; entry.type = _fd.readByte(); entry.comprType = _fd.readByte(); entry.extData = NULL; - extDataOffsets[i] = _fd.readUint16LE(); + extDataOffsets[i] = _fd.readUint16LE(); entry.timeStamp = _fd.readUint32LE(); entry.offset = _fd.readUint32LE(); entry.diskSize = _fd.readUint32LE(); @@ -101,7 +101,7 @@ void BlbArchive::open(const Common::String &filename) { entry.fileHash, entry.type, entry.comprType, extDataOffsets[i], entry.timeStamp, entry.offset, entry.diskSize, entry.size); } - + // Load ext data if (header.extDataSize > 0) { _extData = new byte[header.extDataSize]; @@ -120,9 +120,9 @@ void BlbArchive::load(uint index, byte *buffer, uint32 size) { void BlbArchive::load(BlbArchiveEntry *entry, byte *buffer, uint32 size) { Common::StackLock lock(_mutex); - + _fd.seek(entry->offset); - + switch (entry->comprType) { case 1: // Uncompressed if (size == 0) diff --git a/engines/neverhood/console.cpp b/engines/neverhood/console.cpp new file mode 100644 index 0000000000..733d7dd8a4 --- /dev/null +++ b/engines/neverhood/console.cpp @@ -0,0 +1,191 @@ +/* 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 "neverhood/console.h" +#include "gui/debugger.h" +#include "neverhood/neverhood.h" +#include "neverhood/gamemodule.h" +#include "neverhood/scene.h" +#include "neverhood/sound.h" +#include "neverhood/modules/module1600.h" + +namespace Neverhood { + +Console::Console(NeverhoodEngine *vm) : GUI::Debugger(), _vm(vm) { + DCmd_Register("cheat", WRAP_METHOD(Console, Cmd_Cheat)); + DCmd_Register("dumpvars", WRAP_METHOD(Console, Cmd_Dumpvars)); + DCmd_Register("room", WRAP_METHOD(Console, Cmd_Room)); + DCmd_Register("surfaces", WRAP_METHOD(Console, Cmd_Surfaces)); + DCmd_Register("playsound", WRAP_METHOD(Console, Cmd_PlaySound)); +} + +Console::~Console() { +} + +bool Console::Cmd_Room(int argc, const char **argv) { + int currentModule = _vm->_gameModule->getCurrentModuleNum(); + int previousModule = _vm->_gameModule->getPreviousModuleNum(); + int scene = _vm->gameState().sceneNum; + + DebugPrintf("Current module: %d, previous module: %d, scene %d\n", currentModule, previousModule, scene); + + if (argc != 3) { + DebugPrintf("Use room <module> <scene> to change rooms\n"); + DebugPrintf("Modules are incremental by 100, from 1000 to 3000\n"); + } else { + int newModule = atoi(argv[1]); + int newScene = atoi(argv[2]); + + _vm->gameState().sceneNum = newScene; + _vm->_gameModule->createModule(newModule, -1); + } + + return true; +} + +bool Console::Cmd_Surfaces(int argc, const char **argv) { + if (_vm->_gameModule->_childObject) { + ((Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject)->printSurfaces(this); + } + return true; +} + +bool Console::Cmd_Cheat(int argc, const char **argv) { + if (argc < 2) { + DebugPrintf("Cheats for various puzzles in the game\n"); + DebugPrintf("Use %s <cheatname> to use a cheat.\n", argv[0]); + DebugPrintf("Cheats:\n-------\n"); + DebugPrintf(" buttons - enables all 3 buttons on the door in the purple building, module 3000, scene 9\n"); + DebugPrintf(" cannon - sets the correct cannon combination in module 3000, scene 8\n"); + DebugPrintf(" dice - shows the correct dice combination in the teddy bear puzzle, module 1100, scene 6\n"); + DebugPrintf(" memory - solves the memory puzzle, module 1400, scene 4\n"); + DebugPrintf(" music - shows the correct index in the radio music puzzle, module 2800, scene 1\n"); + DebugPrintf(" radio - enables the radio, module 3000, scene 9 - same as pulling the rightmost cord in the flytrap room\n"); + DebugPrintf(" symbols - solves the symbols puzzle, module 1600, scene 8. Only available in that room\n"); + DebugPrintf(" tubes - shows the correct test tube combination in module 2800, scenes 7 and 10\n"); + return true; + } + + Common::String cheatName = argv[1]; + int moduleNum = _vm->_gameModule->getCurrentModuleNum(); + int sceneNum = _vm->gameState().sceneNum; + + if (cheatName == "buttons") { + Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject; + + scene->setSubVar(VA_LOCKS_DISABLED, 0x304008D2, 1); // kScene3010ButtonNameHashes[0] + scene->setSubVar(VA_LOCKS_DISABLED, 0x40119852, 1); // kScene3010ButtonNameHashes[1] + scene->setSubVar(VA_LOCKS_DISABLED, 0x01180951, 1); // kScene3010ButtonNameHashes[2] + + DebugPrintf("All 3 door buttons have been enabled\n"); + } else if (cheatName == "cannon") { + Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject; + + for (int i = 0; i < 3; i++) + scene->setSubVar(VA_CURR_CANNON_SYMBOLS, i, scene->getSubVar(VA_GOOD_CANNON_SYMBOLS_1, i)); + + for (int i = 3; i < 6; i++) + scene->setSubVar(VA_CURR_CANNON_SYMBOLS, i, scene->getSubVar(VA_GOOD_CANNON_SYMBOLS_2, i - 3)); + + DebugPrintf("Puzzle solved\n"); + } else if (cheatName == "dice") { + Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject; + DebugPrintf("Good: (%d %d %d), current: (%d %d %d)\n", + scene->getSubVar(VA_GOOD_DICE_NUMBERS, 0), scene->getSubVar(VA_GOOD_DICE_NUMBERS, 1), scene->getSubVar(VA_GOOD_DICE_NUMBERS, 2), + scene->getSubVar(VA_CURR_DICE_NUMBERS, 0), scene->getSubVar(VA_CURR_DICE_NUMBERS, 1), scene->getSubVar(VA_CURR_DICE_NUMBERS, 2) + ); + } else if (cheatName == "memory") { + Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject; + + // Autosolve all tiles and leave only two matching tiles closed + for (int i = 0; i < 48; i++) + scene->setSubVar(VA_IS_TILE_MATCH, i, 1); + + // Close the top left tile + scene->setSubVar(VA_IS_TILE_MATCH, 0, 0); + + // Find and close the pair of the top left tile + for (int i = 0; i < 48; i++) { + if (i != 0 && scene->getSubVar(VA_TILE_SYMBOLS, i) == scene->getSubVar(VA_TILE_SYMBOLS, 0)) { + scene->setSubVar(VA_IS_TILE_MATCH, i, 0); + break; + } + } + + DebugPrintf("Puzzle solved\n"); + } else if (cheatName == "music") { + Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject; + DebugPrintf("Good music index: %d, current radio music index: %d\n", scene->getGlobalVar(V_CURR_RADIO_MUSIC_INDEX), scene->getGlobalVar(V_GOOD_RADIO_MUSIC_INDEX)); + } else if (cheatName == "radio") { + Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject; + scene->setGlobalVar(V_RADIO_ENABLED, 1); + + DebugPrintf("The radio has been enabled\n"); + } else if (cheatName == "symbols") { + if (moduleNum == 1600 && sceneNum == 8) { + Scene1609 *scene = ((Scene1609 *)((Module1600 *)_vm->_gameModule->_childObject)->_childObject); + + for (int index = 0; index < 12; index++) { + scene->_asSymbols[index]->change((int)scene->getSubVar(VA_CODE_SYMBOLS, index) + 12, index == (int)scene->getSubVar(VA_CODE_SYMBOLS, scene->_noisySymbolIndex)); + } + + scene->_changeCurrentSymbol = false; + scene->_symbolPosition = 11; + scene->_countdown1 = 36; + + DebugPrintf("Puzzle solved\n"); + } else { + DebugPrintf("Only available in module 1600, scene 8\n"); + } + } else if (cheatName == "tubes") { + Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject; + DebugPrintf("Tube set 1: %d %d %d\n", scene->getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 0), scene->getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 1), scene->getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 2)); + DebugPrintf("Tube set 2: %d %d %d\n", scene->getSubVar(VA_GOOD_TEST_TUBES_LEVEL_2, 0), scene->getSubVar(VA_GOOD_TEST_TUBES_LEVEL_2, 1), scene->getSubVar(VA_GOOD_TEST_TUBES_LEVEL_2, 2)); + } + + return true; +} + +bool Console::Cmd_Dumpvars(int argc, const char **argv) { + _vm->_gameVars->dumpVars(this); + + return true; +} + +bool Console::Cmd_PlaySound(int argc, const char **argv) { + if (argc < 2) { + DebugPrintf("Usage: %s <sound hash>\n", argv[0]); + } else { + uint32 soundHash = strtol(argv[1], NULL, 0); + AudioResourceManSoundItem *soundItem = new AudioResourceManSoundItem(_vm, soundHash); + soundItem->setVolume(100); + soundItem->playSound(false); + while (soundItem->isPlaying()) { + _vm->_system->delayMillis(10); + } + delete soundItem; + } + + return true; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/console.h b/engines/neverhood/console.h new file mode 100644 index 0000000000..62d65bd693 --- /dev/null +++ b/engines/neverhood/console.h @@ -0,0 +1,48 @@ +/* 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 NEVERHOOD_CONSOLE_H +#define NEVERHOOD_CONSOLE_H + +#include "gui/debugger.h" + +namespace Neverhood { + +class NeverhoodEngine; + +class Console : public GUI::Debugger { +public: + Console(NeverhoodEngine *vm); + virtual ~Console(void); + +private: + NeverhoodEngine *_vm; + + bool Cmd_Room(int argc, const char **argv); + bool Cmd_Surfaces(int argc, const char **argv); + bool Cmd_Cheat(int argc, const char **argv); + bool Cmd_Dumpvars(int argc, const char **argv); + bool Cmd_PlaySound(int argc, const char **argv); +}; + +} // End of namespace Neverhood +#endif diff --git a/engines/neverhood/detection.cpp b/engines/neverhood/detection.cpp index 5f860f8519..3de087051a 100644 --- a/engines/neverhood/detection.cpp +++ b/engines/neverhood/detection.cpp @@ -24,6 +24,7 @@ #include "engines/advancedDetector.h" #include "common/file.h" +#include "common/translation.h" #include "neverhood/neverhood.h" @@ -143,6 +144,13 @@ static const NeverhoodGameDescription gameDescriptions[] = { } // End of namespace Neverhood +static const ExtraGuiOption neverhoodExtraGuiOption = { + _s("Use original save/load screens"), + _s("Use the original save/load screens, instead of the ScummVM ones"), + "originalsaveload", + false +}; + class NeverhoodMetaEngine : public AdvancedMetaEngine { public: NeverhoodMetaEngine() : AdvancedMetaEngine(Neverhood::gameDescriptions, sizeof(Neverhood::NeverhoodGameDescription), neverhoodGames) { @@ -160,7 +168,7 @@ public: virtual bool hasFeature(MetaEngineFeature f) const; virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; - + virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const; SaveStateList listSaves(const char *target) const; virtual int getMaximumSaveSlot() const; void removeSaveState(const char *target, int slot) const; @@ -194,6 +202,12 @@ bool NeverhoodMetaEngine::createInstance(OSystem *syst, Engine **engine, const A return gd != 0; } +const ExtraGuiOptions NeverhoodMetaEngine::getExtraGuiOptions(const Common::String &target) const { + ExtraGuiOptions options; + options.push_back(neverhoodExtraGuiOption); + return options; +} + SaveStateList NeverhoodMetaEngine::listSaves(const char *target) const { Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); Neverhood::NeverhoodEngine::SaveHeader header; diff --git a/engines/neverhood/diskplayerscene.cpp b/engines/neverhood/diskplayerscene.cpp index d972943759..ef2b856b2f 100644 --- a/engines/neverhood/diskplayerscene.cpp +++ b/engines/neverhood/diskplayerscene.cpp @@ -61,7 +61,7 @@ static const uint32 kDiskplayerSmackerFileHashes[] = { 0x04002810 }; -static const uint32 kDiskplayerSlotFileHashes1[] = { +static const uint32 kDiskplayerSlotFileHashes1[] = { 0x81312280, 0x01312281, 0x01312282, @@ -84,7 +84,7 @@ static const uint32 kDiskplayerSlotFileHashes1[] = { 0x04312281 }; -static const uint32 kDiskplayerSlotFileHashes2[] = { +static const uint32 kDiskplayerSlotFileHashes2[] = { 0x90443A00, 0x90443A18, 0x90443A28, @@ -107,8 +107,8 @@ static const uint32 kDiskplayerSlotFileHashes2[] = { 0xC0443A18 }; -static const uint32 kDiskplayerSlotFileHashes3[] = { - 0x10357320, +static const uint32 kDiskplayerSlotFileHashes3[] = { + 0x10357320, 0x10557320, 0x10957320, 0x11157320, @@ -130,7 +130,7 @@ static const uint32 kDiskplayerSlotFileHashes3[] = { 0x10543320 }; -static const uint32 kDiskplayerSlotFileHashes4[] = { +static const uint32 kDiskplayerSlotFileHashes4[] = { 0xDC8020E4, 0xDC802164, 0xDC802264, @@ -155,7 +155,7 @@ static const uint32 kDiskplayerSlotFileHashes4[] = { AsDiskplayerSceneKey::AsDiskplayerSceneKey(NeverhoodEngine *vm) : AnimatedSprite(vm, 1100) { - + createSurface1(0x100B90B4, 1200); _x = 211; _y = 195; @@ -193,7 +193,7 @@ void AsDiskplayerSceneKey::stDropKeyDone() { DiskplayerPlayButton::DiskplayerPlayButton(NeverhoodEngine *vm, DiskplayerScene *diskplayerScene) : StaticSprite(vm, 1400), _diskplayerScene(diskplayerScene), _isPlaying(false) { - + loadSprite(0x24A4A664, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); setVisible(false); loadSound(0, 0x44043000); @@ -317,10 +317,10 @@ void DiskplayerSlot::stop() { DiskplayerScene::DiskplayerScene(NeverhoodEngine *vm, Module *parentModule, int paletteIndex) : Scene(vm, parentModule), _diskIndex(0), _appearCountdown(0), _tuneInCountdown(0), - _hasAllDisks(false), _dropKey(false), _inputDisabled(true), _updateStatus(kUSStopped) { + _hasAllDisks(false), _dropKey(false), _inputDisabled(true), _updateStatus(kUSStopped) { int availableDisksCount = 0; - + setBackground(0x8A000044); setPalette(kDiskplayerPaletteFileHashes[paletteIndex]); @@ -344,7 +344,7 @@ DiskplayerScene::DiskplayerScene(NeverhoodEngine *vm, Module *parentModule, int } _hasAllDisks = availableDisksCount == 20; - + if (_hasAllDisks && !getGlobalVar(V_HAS_FINAL_KEY)) _dropKey = true; @@ -354,16 +354,14 @@ DiskplayerScene::DiskplayerScene(NeverhoodEngine *vm, Module *parentModule, int insertPuzzleMouse(0x000408A8, 20, 620); showMouse(false); - _diskSmackerPlayer = new SmackerPlayer(_vm, this, 0x08288103, false, true); - addEntity(_diskSmackerPlayer); - addSurface(_diskSmackerPlayer->getSurface()); + _diskSmackerPlayer = addSmackerPlayer(new SmackerPlayer(_vm, this, 0x08288103, false, true)); _diskSmackerPlayer->setDrawPos(154, 86); _vm->_screen->setSmackerDecoder(_diskSmackerPlayer->getSmackerDecoder()); _palette->usePalette(); - SetMessageHandler(&DiskplayerScene::handleMessage); - SetUpdateHandler(&DiskplayerScene::update); + SetMessageHandler(&DiskplayerScene::handleMessage); + SetUpdateHandler(&DiskplayerScene::update); _appearCountdown = 6; } @@ -419,7 +417,7 @@ void DiskplayerScene::update() { } _diskIndex++; while (!_diskAvailable[_diskIndex] && _diskIndex < 19) - _diskIndex++; + _diskIndex++; if (_diskIndex < 20) { _appearCountdown = 1; } else { @@ -450,7 +448,7 @@ uint32 DiskplayerScene::handleMessage(int messageNum, const MessageParam ¶m, } else if (!_dropKey && param.asPoint().x > 38 && param.asPoint().x < 598 && param.asPoint().y > 400 && param.asPoint().y < 460) { - + _diskSlots[_diskIndex]->stop(); _diskIndex = (param.asPoint().x - 38) / 28; _diskSlots[_diskIndex]->activate(); @@ -464,45 +462,43 @@ uint32 DiskplayerScene::handleMessage(int messageNum, const MessageParam ¶m, break; case 0x2000: tuneIn(); - break; + break; case 0x2001: stop(); - break; + break; } } return 0; } -void DiskplayerScene::stop() { - _diskSmackerPlayer->open(0x08288103, true); +void DiskplayerScene::openSmacker(uint32 fileHash, bool keepLastFrame) { + _diskSmackerPlayer->open(fileHash, keepLastFrame); _vm->_screen->setSmackerDecoder(_diskSmackerPlayer->getSmackerDecoder()); _palette->usePalette(); +} + +void DiskplayerScene::stop() { + openSmacker(0x08288103, true); _ssPlayButton->release(); _updateStatus = kUSStopped; _diskSlots[_diskIndex]->activate(); } void DiskplayerScene::tuneIn() { - _diskSmackerPlayer->open(0x900001C1, false); - _vm->_screen->setSmackerDecoder(_diskSmackerPlayer->getSmackerDecoder()); - _palette->usePalette(); + openSmacker(0x900001C1, false); _ssPlayButton->release(); _updateStatus = kUSTuningIn; _diskSlots[_diskIndex]->activate(); } void DiskplayerScene::playDisk() { - _diskSmackerPlayer->open(kDiskplayerSmackerFileHashes[_diskIndex], false); - _vm->_screen->setSmackerDecoder(_diskSmackerPlayer->getSmackerDecoder()); - _palette->usePalette(); + openSmacker(kDiskplayerSmackerFileHashes[_diskIndex], false); _updateStatus = kUSPlaying; _diskSlots[_diskIndex]->play(); } void DiskplayerScene::playStatic() { - _diskSmackerPlayer->open(0x90000101, false); - _vm->_screen->setSmackerDecoder(_diskSmackerPlayer->getSmackerDecoder()); - _palette->usePalette(); + openSmacker(0x90000101, false); _ssPlayButton->release(); _updateStatus = kUSPlaying; _diskSlots[_diskIndex]->activate(); diff --git a/engines/neverhood/diskplayerscene.h b/engines/neverhood/diskplayerscene.h index f3fd9ea874..150d5c58ed 100644 --- a/engines/neverhood/diskplayerscene.h +++ b/engines/neverhood/diskplayerscene.h @@ -36,7 +36,7 @@ class AsDiskplayerSceneKey : public AnimatedSprite { public: AsDiskplayerSceneKey(NeverhoodEngine *vm); void stDropKey(); -protected: +protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); void stDropKeyDone(); }; @@ -47,7 +47,7 @@ public: void press(); void release(); protected: - DiskplayerScene *_diskplayerScene; + DiskplayerScene *_diskplayerScene; bool _isPlaying; uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; @@ -69,7 +69,7 @@ protected: int _blinkCountdown; bool _isLocked; bool _isBlinking; - void update(); + void update(); }; enum { @@ -99,6 +99,7 @@ protected: bool _dropKey; void update(); uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); + void openSmacker(uint32 fileHash, bool keepLastFrame); void stop(); void tuneIn(); void playDisk(); diff --git a/engines/neverhood/entity.cpp b/engines/neverhood/entity.cpp index 8b1298916c..1ebf1dcf6c 100644 --- a/engines/neverhood/entity.cpp +++ b/engines/neverhood/entity.cpp @@ -25,29 +25,29 @@ namespace Neverhood { -uint32 MessageParam::asInteger() const { - assert(_type == mptInteger); - return _integer; +uint32 MessageParam::asInteger() const { + assert(_type == mptInteger); + return _integer; } -NPoint MessageParam::asPoint() const { +NPoint MessageParam::asPoint() const { assert(_type == mptInteger || _type == mptPoint); if (_type == mptInteger) { NPoint pt; pt.x = _integer & 0xFFFF; - pt.y = (_integer >> 16) & 0xFFFF; + pt.y = (_integer >> 16) & 0xFFFF; return pt; - } - return _point; + } + return _point; } Entity *MessageParam::asEntity() const { - assert(_type == mptEntity); - return _entity; + assert(_type == mptEntity); + return _entity; } Entity::Entity(NeverhoodEngine *vm, int priority) - : _vm(vm), _updateHandlerCb(NULL), _messageHandlerCb(NULL), _priority(priority), _soundResources(NULL) { + : _vm(vm), _updateHandlerCb(NULL), _messageHandlerCb(nullptr), _priority(priority), _soundResources(NULL) { } Entity::~Entity() { diff --git a/engines/neverhood/entity.h b/engines/neverhood/entity.h index cba1bb9a7f..5c29bf8a4f 100644 --- a/engines/neverhood/entity.h +++ b/engines/neverhood/entity.h @@ -98,7 +98,7 @@ public: void incGlobalVar(uint32 nameHash, int incrValue); void incSubVar(uint32 nameHash, uint32 subNameHash, int incrValue); int getPriority() const { return _priority; } - bool hasMessageHandler() const { return _messageHandlerCb != NULL; } + bool hasMessageHandler() const { return _messageHandlerCb != nullptr; } protected: void (Entity::*_updateHandlerCb)(); uint32 (Entity::*_messageHandlerCb)(int messageNum, const MessageParam ¶m, Entity *sender); diff --git a/engines/neverhood/gamemodule.cpp b/engines/neverhood/gamemodule.cpp index 49682b0d29..47cc818fea 100644 --- a/engines/neverhood/gamemodule.cpp +++ b/engines/neverhood/gamemodule.cpp @@ -77,7 +77,7 @@ GameModule::GameModule(NeverhoodEngine *vm) : Module(vm, NULL), _moduleNum(-1), _prevChildObject(NULL), _prevModuleNum(-1), _restoreGameRequested(false), _restartGameRequested(false), _canRequestMainMenu(true), _mainMenuRequested(false) { - + // Other initializations moved to actual engine class _vm->_soundMan->playSoundThree(0x002D0031, 0x8861079); SetMessageHandler(&GameModule::handleMessage); @@ -96,7 +96,7 @@ void GameModule::handleMouseMove(int16 x, int16 y) { mousePos.y = y; debug(2, "GameModule::handleMouseMove(%d, %d)", x, y); sendPointMessage(_childObject, 0, mousePos); - } + } } void GameModule::handleMouseDown(int16 x, int16 y) { @@ -106,7 +106,7 @@ void GameModule::handleMouseDown(int16 x, int16 y) { mousePos.y = y; debug(2, "GameModule::handleMouseDown(%d, %d)", x, y); sendPointMessage(_childObject, 0x0001, mousePos); - } + } } void GameModule::handleMouseUp(int16 x, int16 y) { @@ -116,21 +116,21 @@ void GameModule::handleMouseUp(int16 x, int16 y) { mousePos.y = y; debug(2, "GameModule::handleMouseUp(%d, %d)", x, y); sendPointMessage(_childObject, 0x0002, mousePos); - } + } } void GameModule::handleSpaceKey() { if (_childObject) { debug(2, "GameModule::handleSpaceKey()"); sendMessage(_childObject, 0x0009, 0); - } + } } void GameModule::handleAsciiKey(char key) { if (_childObject) { debug(2, "GameModule::handleAsciiKey()"); sendMessage(_childObject, 0x000A, (uint32)key); - } + } } void GameModule::handleKeyDown(Common::KeyCode keyCode) { @@ -141,7 +141,7 @@ void GameModule::handleKeyDown(Common::KeyCode keyCode) { handleSpaceKey(); debug(2, "GameModule::handleKeyDown()"); sendMessage(_childObject, 0x000B, keyCode); - } + } } void GameModule::handleEscapeKey() { @@ -166,7 +166,7 @@ void GameModule::initKeySlotsPuzzle() { void GameModule::initMemoryPuzzle() { if (!getSubVar(VA_IS_PUZZLE_INIT, 0xC8606803)) { - NonRepeatingRandomNumbers diceIndices(_vm->_rnd, 3); + NonRepeatingRandomNumbers diceIndices(_vm->_rnd, 3); NonRepeatingRandomNumbers availableTiles(_vm->_rnd, 48); NonRepeatingRandomNumbers tileSymbols(_vm->_rnd, 10); for (uint32 i = 0; i < 3; i++) @@ -194,21 +194,6 @@ void GameModule::initMemoryPuzzle() { tileSymbolIndex = 0; } setSubVar(VA_IS_PUZZLE_INIT, 0xC8606803, 1); - - // DEBUG Enable to autosolve all tiles and leave only two matching tiles open -#if 0 - for (int i = 0; i < 48; i++) - setSubVar(VA_IS_TILE_MATCH, i, 1); - int debugIndex = 0; - setSubVar(VA_IS_TILE_MATCH, debugIndex, 0); - for (int i = 0; i < 48; i++) { - if (i != debugIndex && getSubVar(VA_TILE_SYMBOLS, i) == getSubVar(VA_TILE_SYMBOLS, debugIndex)) { - setSubVar(VA_IS_TILE_MATCH, i, 0); - break; - } - } -#endif - } } @@ -335,11 +320,11 @@ uint32 GameModule::handleMessage(int messageNum, const MessageParam ¶m, Enti switch (messageNum) { case 0x0800: _canRequestMainMenu = true; - break; + break; case 0x1009: _moduleResult = param.asInteger(); _done = true; - break; + break; } return messageResult; } @@ -426,6 +411,8 @@ void GameModule::checkRequests() { } if (_restoreGameRequested) { _restoreGameRequested = false; + _vm->_audioResourceMan->stopAllSounds(); + _vm->_soundMan->stopAllSounds(); delete _childObject; delete _prevChildObject; _childObject = NULL; @@ -438,8 +425,11 @@ void GameModule::checkRequests() { } void GameModule::createModule(int moduleNum, int which) { - debug("GameModule::createModule(%d, %d)", moduleNum, which); + debug(1, "GameModule::createModule(%d, %d)", moduleNum, which); _moduleNum = moduleNum; + + delete _childObject; + switch (_moduleNum) { case 1000: setGlobalVar(V_MODULE_NAME, 0x03294419); @@ -539,7 +529,7 @@ void GameModule::createModule(int moduleNum, int which) { } void GameModule::createModuleByHash(uint32 nameHash) { - debug("GameModule::createModuleByHash(%08X)", nameHash); + debug(1, "GameModule::createModuleByHash(%08X)", nameHash); switch (nameHash) { case 0x03294419: createModule(1000, -1); @@ -684,7 +674,7 @@ void GameModule::updateModule() { createModule(2300, 1); break; case 2300: - debug("module 23000 _moduleResult : %d", _moduleResult); + debug(1, "module 23000 _moduleResult : %d", _moduleResult); if (_moduleResult == 2) createModule(1200, 0); else if (_moduleResult == 0) @@ -796,6 +786,7 @@ void GameModule::openMainMenu() { createModule(1000, 0); } _vm->_screen->saveParams(); + _vm->_screen->update(); _mainMenuRequested = false; createMenuModule(); } diff --git a/engines/neverhood/gamemodule.h b/engines/neverhood/gamemodule.h index 8101d38009..2f2fecf463 100644 --- a/engines/neverhood/gamemodule.h +++ b/engines/neverhood/gamemodule.h @@ -49,12 +49,16 @@ public: void initWaterPipesPuzzle(); void initRadioPuzzle(); void initTestTubes1Puzzle(); - void initTestTubes2Puzzle(); + void initTestTubes2Puzzle(); void initCannonSymbolsPuzzle(); void initCodeSymbolsPuzzle(); void initCubeSymbolsPuzzle(); void initCrystalColorsPuzzle(); uint32 getCurrRadioMusicFileHash(); + int getCurrentModuleNum() { return _moduleNum; } + int getPreviousModuleNum() { return _moduleNum; } + + void createModule(int moduleNum, int which); protected: int _moduleNum; Entity *_prevChildObject; @@ -64,7 +68,6 @@ protected: bool _canRequestMainMenu; bool _mainMenuRequested; uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); - void createModule(int moduleNum, int which); void createModuleByHash(uint32 nameHash); void updateModule(); void openMainMenu(); diff --git a/engines/neverhood/gamevars.cpp b/engines/neverhood/gamevars.cpp index 87f5fe6dd9..9c080fea24 100644 --- a/engines/neverhood/gamevars.cpp +++ b/engines/neverhood/gamevars.cpp @@ -20,6 +20,7 @@ * */ +#include "neverhood/console.h" #include "neverhood/gamevars.h" namespace Neverhood { @@ -74,7 +75,7 @@ uint32 GameVars::getSubVar(uint32 nameHash, uint32 subNameHash) { int16 subVarIndex = findSubVarIndex(varIndex, subNameHash); if (subVarIndex != -1) value = _vars[subVarIndex].value; - } + } return value; } @@ -123,10 +124,10 @@ int16 GameVars::getSubVarIndex(int16 varIndex, uint32 subNameHash) { return subVarIndex; } -void GameVars::dumpVars() { +void GameVars::dumpVars(Console *con) { for (Common::Array<GameVar>::iterator it = _vars.begin(); it != _vars.end(); ++it) { GameVar gameVar = *it; - debug("%08X %08X %3d %3d", gameVar.nameHash, gameVar.value, gameVar.firstIndex, gameVar.nextIndex); + con->DebugPrintf("hash: %08X, var: %08X, first index: %3d, next index: %3d\n", gameVar.nameHash, gameVar.value, gameVar.firstIndex, gameVar.nextIndex); } } diff --git a/engines/neverhood/gamevars.h b/engines/neverhood/gamevars.h index 5337c13394..3aec4d1da4 100644 --- a/engines/neverhood/gamevars.h +++ b/engines/neverhood/gamevars.h @@ -160,7 +160,7 @@ enum { VA_HAS_KEY = 0x0090EA95, VA_IS_KEY_INSERTED = 0x08D0AB11, VA_LOCKS_DISABLED = 0x14800353, - V_END_ + V_END_ }; struct GameVar { @@ -169,6 +169,8 @@ struct GameVar { int16 firstIndex, nextIndex; }; +class Console; + class GameVars { public: GameVars(); @@ -179,7 +181,7 @@ public: void setGlobalVar(uint32 nameHash, uint32 value); uint32 getSubVar(uint32 nameHash, uint32 subNameHash); void setSubVar(uint32 nameHash, uint32 subNameHash, uint32 value); - void dumpVars(); + void dumpVars(Console *con); protected: Common::Array<GameVar> _vars; int16 addVar(uint32 nameHash, uint32 value); diff --git a/engines/neverhood/graphics.cpp b/engines/neverhood/graphics.cpp index 5099c7a00e..490959020f 100644 --- a/engines/neverhood/graphics.cpp +++ b/engines/neverhood/graphics.cpp @@ -26,10 +26,10 @@ namespace Neverhood { -BaseSurface::BaseSurface(NeverhoodEngine *vm, int priority, int16 width, int16 height) +BaseSurface::BaseSurface(NeverhoodEngine *vm, int priority, int16 width, int16 height, Common::String name) : _vm(vm), _priority(priority), _visible(true), _transparent(true), - _clipRects(NULL), _clipRectsCount(0), _version(0) { - + _clipRects(NULL), _clipRectsCount(0), _version(0), _name(name) { + _drawRect.x = 0; _drawRect.y = 0; _drawRect.width = width; @@ -68,7 +68,7 @@ void BaseSurface::clear() { } void BaseSurface::drawSpriteResource(SpriteResource &spriteResource) { - if (spriteResource.getDimensions().width <= _drawRect.width && + if (spriteResource.getDimensions().width <= _drawRect.width && spriteResource.getDimensions().height <= _drawRect.height) { clear(); spriteResource.draw(_surface, false, false); @@ -77,7 +77,7 @@ void BaseSurface::drawSpriteResource(SpriteResource &spriteResource) { } void BaseSurface::drawSpriteResourceEx(SpriteResource &spriteResource, bool flipX, bool flipY, int16 width, int16 height) { - if (spriteResource.getDimensions().width <= _sysRect.width && + if (spriteResource.getDimensions().width <= _sysRect.width && spriteResource.getDimensions().height <= _sysRect.height) { if (width > 0 && width <= _sysRect.width) _drawRect.width = width; @@ -130,7 +130,7 @@ void BaseSurface::copyFrom(Graphics::Surface *sourceSurface, int16 x, int16 y, N // ShadowSurface ShadowSurface::ShadowSurface(NeverhoodEngine *vm, int priority, int16 width, int16 height, BaseSurface *shadowSurface) - : BaseSurface(vm, priority, width, height), _shadowSurface(shadowSurface) { + : BaseSurface(vm, priority, width, height, "shadow"), _shadowSurface(shadowSurface) { // Empty } @@ -143,18 +143,18 @@ void ShadowSurface::draw() { // FontSurface FontSurface::FontSurface(NeverhoodEngine *vm, NPointArray *tracking, uint charsPerRow, uint16 numRows, byte firstChar, uint16 charWidth, uint16 charHeight) - : BaseSurface(vm, 0, charWidth * charsPerRow, charHeight * numRows), _charsPerRow(charsPerRow), _numRows(numRows), + : BaseSurface(vm, 0, charWidth * charsPerRow, charHeight * numRows, "font"), _charsPerRow(charsPerRow), _numRows(numRows), _firstChar(firstChar), _charWidth(charWidth), _charHeight(charHeight), _tracking(NULL) { - + _tracking = new NPointArray(); *_tracking = *tracking; } FontSurface::FontSurface(NeverhoodEngine *vm, uint32 fileHash, uint charsPerRow, uint16 numRows, byte firstChar, uint16 charWidth, uint16 charHeight) - : BaseSurface(vm, 0, charWidth * charsPerRow, charHeight * numRows), _charsPerRow(charsPerRow), _numRows(numRows), + : BaseSurface(vm, 0, charWidth * charsPerRow, charHeight * numRows, "font"), _charsPerRow(charsPerRow), _numRows(numRows), _firstChar(firstChar), _charWidth(charWidth), _charHeight(charHeight), _tracking(NULL) { - + SpriteResource fontSpriteResource(_vm); fontSpriteResource.load(fileHash, true); drawSpriteResourceEx(fontSpriteResource, false, false, 0, 0); @@ -182,7 +182,7 @@ void FontSurface::drawString(BaseSurface *destSurface, int16 x, int16 y, const b for (; stringLen > 0; --stringLen, ++string) { drawChar(destSurface, x, y, *string); x += _tracking ? (*_tracking)[*string - _firstChar].x : _charWidth; - } + } } @@ -201,7 +201,7 @@ FontSurface *FontSurface::createFontSurface(NeverhoodEngine *vm, uint32 fileHash uint16 charHeight = fontData.getPoint(calcHash("meCharHeight")).x; NPointArray *tracking = fontData.getPointArray(calcHash("meTracking")); fontSprite.load(fileHash, true); - fontSurface = new FontSurface(vm, tracking, 16, numRows, firstChar, charWidth, charHeight); + fontSurface = new FontSurface(vm, tracking, 16, numRows, firstChar, charWidth, charHeight); fontSurface->drawSpriteResourceEx(fontSprite, false, false, 0, 0); return fontSurface; } @@ -219,7 +219,7 @@ enum BitmapFlags { void parseBitmapResource(const byte *sprite, bool *rle, NDimensions *dimensions, NPoint *position, const byte **palette, const byte **pixels) { uint16 flags; - + flags = READ_LE_UINT16(sprite); sprite += 2; @@ -278,7 +278,7 @@ void unpackSpriteRle(const byte *source, int width, int height, byte *dest, int rows = READ_LE_UINT16(source); chunks = READ_LE_UINT16(source + 2); source += 4; - + do { if (chunks == 0) { dest += rows * destPitch; @@ -316,7 +316,7 @@ void unpackSpriteRle(const byte *source, int width, int height, byte *dest, int void unpackSpriteNormal(const byte *source, int width, int height, byte *dest, int destPitch, bool flipX, bool flipY) { const int sourcePitch = (width + 3) & 0xFFFC; - + if (flipY) { dest += destPitch * (height - 1); destPitch = -destPitch; @@ -343,7 +343,7 @@ void unpackSpriteNormal(const byte *source, int width, int height, byte *dest, i int calcDistance(int16 x1, int16 y1, int16 x2, int16 y2) { const int16 deltaX = ABS(x1 - x2); const int16 deltaY = ABS(y1 - y2); - return sqrt((double)(deltaX * deltaX + deltaY * deltaY)); + return (int)sqrt((double)(deltaX * deltaX + deltaY * deltaY)); } } // End of namespace Neverhood diff --git a/engines/neverhood/graphics.h b/engines/neverhood/graphics.h index a0ac1f09d5..b80bd60729 100644 --- a/engines/neverhood/graphics.h +++ b/engines/neverhood/graphics.h @@ -43,9 +43,11 @@ struct NDimensions { struct NRect { int16 x1, y1, x2, y2; - NRect() : x1(0), y1(0), x2(0), y2(0) {} - - NRect(int16 x01, int16 y01, int16 x02, int16 y02) : x1(x01), y1(y01), x2(x02), y2(y02) {} + static NRect make(int16 x01, int16 y01, int16 x02, int16 y02) { + NRect r; + r.set(x01, y01, x02, y02); + return r; + } void set(int16 x01, int16 y01, int16 x02, int16 y02) { x1 = x01; @@ -62,12 +64,12 @@ struct NRect { typedef Common::Array<NRect> NRectArray; -// TODO: Use Common::Rect +// TODO: Use Common::Rect struct NDrawRect { int16 x, y, width, height; NDrawRect() : x(0), y(0), width(0), height(0) {} NDrawRect(int16 x0, int16 y0, int16 width0, int16 height0) : x(x0), y(y0), width(width0), height(height0) {} - int16 x2() { return x + width; } + int16 x2() { return x + width; } int16 y2() { return y + height; } void set(int16 x0, int16 y0, int16 width0, int16 height0) { x = x0; @@ -83,7 +85,7 @@ class MouseCursorResource; class BaseSurface { public: - BaseSurface(NeverhoodEngine *vm, int priority, int16 width, int16 height); + BaseSurface(NeverhoodEngine *vm, int priority, int16 width, int16 height, Common::String name); virtual ~BaseSurface(); virtual void draw(); void clear(); @@ -104,10 +106,12 @@ public: void setVisible(bool value) { _visible = value; } void setTransparent(bool value) { _transparent = value; } Graphics::Surface *getSurface() { return _surface; } + const Common::String getName() const { return _name; } protected: NeverhoodEngine *_vm; int _priority; bool _visible; + Common::String _name; Graphics::Surface *_surface; NDrawRect _drawRect; NDrawRect _sysRect; diff --git a/engines/neverhood/klaymen.cpp b/engines/neverhood/klaymen.cpp index 06d606e18d..8ed27c825a 100644 --- a/engines/neverhood/klaymen.cpp +++ b/engines/neverhood/klaymen.cpp @@ -33,19 +33,19 @@ static const KlaymenIdleTableItem klaymenIdleTable1[] = { {1, kIdleArms}, {1, kIdleChest}, {1, kIdleHeadOff} -}; +}; static const KlaymenIdleTableItem klaymenIdleTable2[] = { {1, kIdlePickEar}, {1, kIdleSpinHead}, {1, kIdleChest}, {1, kIdleHeadOff} -}; +}; static const KlaymenIdleTableItem klaymenIdleTable3[] = { {1, kIdleTeleporterHands}, {1, kIdleTeleporterHands2} -}; +}; static const KlaymenIdleTableItem klaymenIdleTable4[] = { {1, kIdleSpinHead}, @@ -56,7 +56,7 @@ static const KlaymenIdleTableItem klaymenIdleTable4[] = { static const KlaymenIdleTableItem klaymenIdleTable1002[] = { {1, kIdlePickEar}, {2, kIdleWonderAbout} -}; +}; // Klaymen @@ -66,7 +66,7 @@ Klaymen::Klaymen(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRec _attachedSprite(NULL), _isWalking(false), _actionStatus(1), _parentScene(parentScene), _isSneaking(false), _isLargeStep(false), _doYHitIncr(false), _isLeverDown(false), _isSittingInTeleporter(false), _actionStatusChanged(false), _ladderStatus(0), _pathPoints(NULL), _soundFlag(false), _idleTableNum(0), _otherSprite(NULL), _moveObjectCountdown(0), _readyToSpit(false), _walkResumeFrameIncr(0) { - + createSurface(1000, 320, 200); _x = x; _y = y; @@ -434,7 +434,7 @@ void Klaymen::stopWalking() { } void Klaymen::startIdleAnimation(uint32 fileHash, AnimationCb callback) { - debug("startIdleAnimation(%08X)", fileHash); + debug(1, "startIdleAnimation(%08X)", fileHash); NextState(callback); SetUpdateHandler(&Klaymen::upIdleAnimation); } @@ -447,7 +447,7 @@ void Klaymen::upIdleAnimation() { bool Klaymen::stStartActionFromIdle(AnimationCb callback) { if (_busyStatus == 2) { _busyStatus = 1; - _acceptInput = false; + _acceptInput = false; startAnimation(0x9A7020B8, 0, -1); SetUpdateHandler(&Klaymen::update); SetMessageHandler(&Klaymen::hmStartAction); @@ -684,35 +684,35 @@ void Klaymen::suAction() { _x += _deltaX; } _deltaX = 0; - + if (_doDeltaY) { _y -= _deltaY; } else { _y += _deltaY; } _deltaY = 0; - + if (_frameChanged) { if (xdiff > 6) _x += 6; else if (xdiff < -6) _x -= 6; else - _x = _destX; + _x = _destX; } - + updateBounds(); - + } void Klaymen::suSneaking() { - + int16 xdiff = _destX - _x; - + if (_currFrameIndex == 9) { if (xdiff > 26) _deltaX += xdiff - 26; - else if (xdiff < -26) + else if (xdiff < -26) _deltaX -= xdiff + 26; } @@ -720,7 +720,7 @@ void Klaymen::suSneaking() { xdiff = _deltaX; else if (xdiff < -_deltaX) xdiff = -_deltaX; - _deltaX = 0; + _deltaX = 0; if (_destX != _x) { HitRect *hitRectPrev = _parentScene->findHitRectAtPos(_x, _y); @@ -749,7 +749,7 @@ void Klaymen::suSneaking() { } updateBounds(); } - + } void Klaymen::stSneak() { @@ -761,7 +761,7 @@ void Klaymen::stSneak() { SetUpdateHandler(&Klaymen::update); SetMessageHandler(&Klaymen::hmSneaking); SetSpriteUpdate(&Klaymen::suSneaking); - FinalizeState(&Klaymen::evSneakingDone); + FinalizeState(&Klaymen::evSneakingDone); } void Klaymen::evSneakingDone() { @@ -801,7 +801,7 @@ void Klaymen::stStartWalking() { SetMessageHandler(&Klaymen::hmStartWalking); SetSpriteUpdate(&Klaymen::suWalkingTestExit); NextState(&Klaymen::stWalkingFirst); - FinalizeState(&Klaymen::evStartWalkingDone); + FinalizeState(&Klaymen::evStartWalkingDone); } } @@ -832,7 +832,7 @@ void Klaymen::stWalkingFirst() { SetMessageHandler(&Klaymen::hmWalking); SetSpriteUpdate(&Klaymen::suWalkingFirst); NextState(&Klaymen::stUpdateWalkingFirst); - FinalizeState(&Klaymen::evStartWalkingDone); + FinalizeState(&Klaymen::evStartWalkingDone); } void Klaymen::suWalkingFirst() { @@ -882,20 +882,20 @@ void Klaymen::stUpdateWalkingFirst() { SetUpdateHandler(&Klaymen::update); SetMessageHandler(&Klaymen::hmSneaking); SetSpriteUpdate(&Klaymen::suSneaking); - FinalizeState(&Klaymen::evSneakingDone); + FinalizeState(&Klaymen::evSneakingDone); } } void Klaymen::suWalkingTestExit() { int16 xdiff = ABS(_destX - _x); int16 xdelta = _destX - _x; - + if (xdelta > _deltaX) xdelta = _deltaX; else if (xdelta < -_deltaX) xdelta = -_deltaX; - - _deltaX = 0; + + _deltaX = 0; if (xdiff == 0 || (_actionStatus != 2 && _actionStatus != 3 && xdiff <= 42 && _currFrameIndex >= 5 && _currFrameIndex <= 11) || @@ -928,7 +928,7 @@ void Klaymen::suWalkingTestExit() { } updateBounds(); } - + } uint32 Klaymen::hmLever(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -1363,7 +1363,7 @@ void Klaymen::stLargeStep() { SetUpdateHandler(&Klaymen::update); SetMessageHandler(&Klaymen::hmLargeStep); SetSpriteUpdate(&Klaymen::suLargeStep); - FinalizeState(&Klaymen::evLargeStepDone); + FinalizeState(&Klaymen::evLargeStepDone); } void Klaymen::evLargeStepDone() { @@ -1372,11 +1372,11 @@ void Klaymen::evLargeStepDone() { void Klaymen::suLargeStep() { int16 xdiff = _destX - _x; - + if (_doDeltaX) { _deltaX = -_deltaX; } - + if (_currFrameIndex == 7) { _deltaX = xdiff; } @@ -1385,7 +1385,7 @@ void Klaymen::suLargeStep() { xdiff = _deltaX; _deltaX = 0; - + if (_x != _destX) { HitRect *hitRectPrev = _parentScene->findHitRectAtPos(_x, _y); _x += xdiff; @@ -1420,7 +1420,7 @@ uint32 Klaymen::hmLargeStep(int messageNum, const MessageParam ¶m, Entity *s case 0x3002: _x = _destX; gotoNextStateExt(); - break; + break; } return messageResult; } @@ -1681,7 +1681,7 @@ void Klaymen::stStartClimbLadderDown() { _ladderStatus = 2; _acceptInput = true; startAnimation(0x122D1505, 29 - _currFrameIndex, -1); - } + } } } @@ -1979,7 +1979,7 @@ uint32 Klaymen::hmMoveObjectTurn(int messageNum, const MessageParam ¶m, Enti break; case 0x480A: _isMoveObjectRequested = true; - return 0; + return 0; } return hmLowLevelAnimation(messageNum, param, sender); } @@ -2521,7 +2521,7 @@ void Klaymen::stInsertKey() { more = true; } while (more); _keysToInsert++; - } + } } if (_keysToInsert == 0) { GotoState(NULL); @@ -3049,7 +3049,7 @@ void Klaymen::stFallSkipJump() { void Klaymen::upMoveObject() { if (_x >= 380) gotoNextStateExt(); - Klaymen::update(); + Klaymen::update(); } uint32 Klaymen::hmMatch(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -3165,7 +3165,7 @@ void Klaymen::stTumbleHeadless() { void Klaymen::stCloseEyes() { if (!stStartActionFromIdle(AnimationCallback(&Klaymen::stCloseEyes))) { _busyStatus = 1; - _acceptInput = false; + _acceptInput = false; startAnimation(0x5420E254, 0, -1); SetUpdateHandler(&Klaymen::update); SetMessageHandler(&Klaymen::hmLowLevel); @@ -3358,7 +3358,7 @@ uint32 KmScene1001::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x4004: GotoState(&Klaymen::stTryStandIdle); - break; + break; case 0x4804: if (param.asInteger() == 2) GotoState(&Klaymen::stSleeping); @@ -3380,7 +3380,7 @@ uint32 KmScene1001::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481B: if (param.asPoint().y != 0) startWalkToXDistance(param.asPoint().y, param.asPoint().x); @@ -3408,10 +3408,10 @@ uint32 KmScene1001::xHandleMessage(int messageNum, const MessageParam ¶m) { sendMessage(_parentScene, 0x2002, 0); GotoState(&Klaymen::stWakeUp); } - break; + break; case 0x483F: startSpecialWalkRight(param.asInteger()); - break; + break; case 0x4840: startSpecialWalkLeft(param.asInteger()); break; @@ -3423,7 +3423,7 @@ uint32 KmScene1001::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene1002::KmScene1002(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - + setKlaymenIdleTable1(); } @@ -3438,7 +3438,7 @@ void KmScene1002::xUpdate() { _idleTableNum = 0; } } - + uint32 KmScene1002::xHandleMessage(int messageNum, const MessageParam ¶m) { switch (messageNum) { case 0x2001: @@ -3451,7 +3451,7 @@ uint32 KmScene1002::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4800: startWalkToX(param.asPoint().x, false); break; - case 0x4004: + case 0x4004: GotoState(&Klaymen::stTryStandIdle); break; case 0x4803: @@ -3479,42 +3479,42 @@ uint32 KmScene1002::xHandleMessage(int messageNum, const MessageParam ¶m) { break; } break; - case 0x480A: + case 0x480A: GotoState(&Klaymen::stMoveVenusFlyTrap); break; - case 0x480D: + case 0x480D: GotoState(&Klaymen::stJumpToRingVenusFlyTrap); break; - case 0x4816: + case 0x4816: if (param.asInteger() == 0) GotoState(&Klaymen::stPressDoorButton); break; - case 0x4817: + case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); break; - case 0x481B: + case 0x481B: startWalkToAttachedSpriteXDistance(param.asInteger()); break; - case 0x4820: + case 0x4820: sendMessage(_parentScene, 0x2005, 0); - GotoState(&Klaymen::stContinueClimbLadderUp); + GotoState(&Klaymen::stContinueClimbLadderUp); break; - case 0x4821: + case 0x4821: sendMessage(_parentScene, 0x2005, 0); _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderDown); + GotoState(&Klaymen::stStartClimbLadderDown); break; - case 0x4822: + case 0x4822: sendMessage(_parentScene, 0x2005, 0); _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderUp); + GotoState(&Klaymen::stStartClimbLadderUp); break; case 0x4823: sendMessage(_parentScene, 0x2006, 0); - GotoState(&Klaymen::stClimbLadderHalf); + GotoState(&Klaymen::stClimbLadderHalf); break; - case 0x482E: + case 0x482E: if (param.asInteger() == 1) GotoState(&Klaymen::stWalkToFrontNoStep); else @@ -3529,7 +3529,7 @@ uint32 KmScene1002::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x483F: startSpecialWalkRight(param.asInteger()); break; - case 0x4840: + case 0x4840: startSpecialWalkLeft(param.asInteger()); break; } @@ -3540,8 +3540,8 @@ uint32 KmScene1002::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene1004::KmScene1004(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - - _dataResource.load(0x01900A04); + + _dataResource.load(0x01900A04); } uint32 KmScene1004::xHandleMessage(int messageNum, const MessageParam ¶m) { @@ -3606,7 +3606,7 @@ uint32 KmScene1004::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene1109::KmScene1109(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - + // Empty } @@ -3615,7 +3615,7 @@ uint32 KmScene1109::xHandleMessage(int messageNum, const MessageParam ¶m) { switch (messageNum) { case 0x2000: _isSittingInTeleporter = param.asInteger() != 0; - messageResult = 1; + messageResult = 1; break; case 0x4001: case 0x4800: @@ -3653,7 +3653,7 @@ uint32 KmScene1109::xHandleMessage(int messageNum, const MessageParam ¶m) { sendMessage(_parentScene, 0x2000, 1); _isSittingInTeleporter = true; GotoState(&Klaymen::stSitInTeleporter); - break; + break; case 0x4836: sendMessage(_parentScene, 0x2000, 0); _isSittingInTeleporter = false; @@ -3673,7 +3673,7 @@ uint32 KmScene1109::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene1201::KmScene1201(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - + setKlaymenIdleTable(klaymenIdleTable4, ARRAYSIZE(klaymenIdleTable4)); _doYHitIncr = true; } @@ -3741,7 +3741,7 @@ uint32 KmScene1201::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene1303::KmScene1303(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - + // Empty } @@ -3762,8 +3762,8 @@ uint32 KmScene1303::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene1304::KmScene1304(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - - // Empty + + // Empty } uint32 KmScene1304::xHandleMessage(int messageNum, const MessageParam ¶m) { @@ -3774,7 +3774,7 @@ uint32 KmScene1304::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x4004: GotoState(&Klaymen::stTryStandIdle); - break; + break; case 0x4812: if (param.asInteger() == 2) GotoState(&Klaymen::stPickUpNeedle); @@ -3792,7 +3792,7 @@ uint32 KmScene1304::xHandleMessage(int messageNum, const MessageParam ¶m) { startWalkToXDistance(param.asPoint().y, param.asPoint().x); else startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; + break; case 0x481F: if (param.asInteger() == 1) GotoState(&Klaymen::stTurnAwayFromUse); @@ -3803,7 +3803,7 @@ uint32 KmScene1304::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x483F: startSpecialWalkRight(param.asInteger()); - break; + break; case 0x4840: startSpecialWalkLeft(param.asInteger()); break; @@ -3814,7 +3814,7 @@ uint32 KmScene1304::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene1305::KmScene1305(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - // Empty + // Empty } uint32 KmScene1305::xHandleMessage(int messageNum, const MessageParam ¶m) { @@ -3825,10 +3825,10 @@ uint32 KmScene1305::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x4004: GotoState(&Klaymen::stTryStandIdle); - break; + break; case 0x4804: GotoState(&Klaymen::stCrashDown); - break; + break; case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); @@ -3839,7 +3839,7 @@ uint32 KmScene1305::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene1306::KmScene1306(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - + // Empty } @@ -3879,9 +3879,9 @@ uint32 KmScene1306::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481A: - GotoState(&Klaymen::stInsertDisk); + GotoState(&Klaymen::stInsertDisk); break; case 0x481B: if (param.asPoint().y != 0) @@ -3936,7 +3936,7 @@ uint32 KmScene1306::xHandleMessage(int messageNum, const MessageParam ¶m) { sendMessage(_parentScene, 0x2000, 1); _isSittingInTeleporter = true; GotoState(&Klaymen::stSitInTeleporter); - break; + break; case 0x4836: sendMessage(_parentScene, 0x2000, 0); _isSittingInTeleporter = false; @@ -3944,13 +3944,13 @@ uint32 KmScene1306::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x483D: teleporterAppear(0xEE084A04); - break; + break; case 0x483E: teleporterDisappear(0xB86A4274); - break; + break; case 0x483F: startSpecialWalkRight(param.asInteger()); - break; + break; case 0x4840: startSpecialWalkLeft(param.asInteger()); break; @@ -3961,7 +3961,7 @@ uint32 KmScene1306::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene1308::KmScene1308(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - // Empty + // Empty } uint32 KmScene1308::xHandleMessage(int messageNum, const MessageParam ¶m) { @@ -3978,7 +3978,7 @@ uint32 KmScene1308::xHandleMessage(int messageNum, const MessageParam ¶m) { GotoState(&Klaymen::stMoveObjectSkipTurnFaceObject); else GotoState(&Klaymen::stMoveObjectFaceObject); - break; + break; case 0x480D: GotoState(&Klaymen::stUseLever); break; @@ -3993,12 +3993,12 @@ uint32 KmScene1308::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481A: if (param.asInteger() == 1) - GotoState(&Klaymen::stInsertKey); + GotoState(&Klaymen::stInsertKey); else - GotoState(&Klaymen::stInsertDisk); + GotoState(&Klaymen::stInsertDisk); break; case 0x481B: if (param.asPoint().y != 0) @@ -4020,7 +4020,7 @@ uint32 KmScene1308::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x483F: startSpecialWalkRight(param.asInteger()); - break; + break; case 0x4840: startSpecialWalkLeft(param.asInteger()); break; @@ -4032,8 +4032,8 @@ uint32 KmScene1308::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene1401::KmScene1401(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - - // Empty + + // Empty } uint32 KmScene1401::xHandleMessage(int messageNum, const MessageParam ¶m) { @@ -4044,13 +4044,13 @@ uint32 KmScene1401::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x4004: GotoState(&Klaymen::stTryStandIdle); - break; + break; case 0x480A: if (param.asInteger() == 1) GotoState(&Klaymen::stMoveObjectSkipTurnFaceObject); else GotoState(&Klaymen::stMoveObjectFaceObject); - break; + break; case 0x4816: if (param.asInteger() == 1) GotoState(&Klaymen::stPressButton); @@ -4068,7 +4068,7 @@ uint32 KmScene1401::xHandleMessage(int messageNum, const MessageParam ¶m) { startWalkToXDistance(param.asPoint().y, param.asPoint().x); else startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; + break; case 0x481F: if (param.asInteger() == 1) GotoState(&Klaymen::stTurnAwayFromUse); @@ -4101,8 +4101,8 @@ uint32 KmScene1401::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene1402::KmScene1402(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - - SetFilterY(&Sprite::defFilterY); + + SetFilterY(&Sprite::defFilterY); } uint32 KmScene1402::xHandleMessage(int messageNum, const MessageParam ¶m) { @@ -4113,13 +4113,13 @@ uint32 KmScene1402::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x4004: GotoState(&Klaymen::stTryStandIdle); - break; + break; case 0x480A: if (param.asInteger() == 1) GotoState(&Klaymen::stMoveObjectSkipTurnFaceObject); else GotoState(&Klaymen::stMoveObjectFaceObject); - break; + break; case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); @@ -4129,7 +4129,7 @@ uint32 KmScene1402::xHandleMessage(int messageNum, const MessageParam ¶m) { startWalkToXDistance(param.asPoint().y, param.asPoint().x); else startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; + break; case 0x481D: GotoState(&Klaymen::stTurnToUse); break; @@ -4162,7 +4162,7 @@ uint32 KmScene1403::xHandleMessage(int messageNum, const MessageParam ¶m) { GotoState(&Klaymen::stMoveObjectSkipTurnFaceObject); else GotoState(&Klaymen::stMoveObjectFaceObject); - break; + break; case 0x480D: GotoState(&Klaymen::stUseLever); break; @@ -4177,7 +4177,7 @@ uint32 KmScene1403::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481B: if (param.asPoint().y != 0) startWalkToXDistance(param.asPoint().y, param.asPoint().x); @@ -4189,7 +4189,7 @@ uint32 KmScene1403::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x483F: startSpecialWalkRight(param.asInteger()); - break; + break; case 0x4840: startSpecialWalkLeft(param.asInteger()); break; @@ -4202,7 +4202,7 @@ uint32 KmScene1403::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene1404::KmScene1404(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - // Empty + // Empty } uint32 KmScene1404::xHandleMessage(int messageNum, const MessageParam ¶m) { @@ -4219,7 +4219,7 @@ uint32 KmScene1404::xHandleMessage(int messageNum, const MessageParam ¶m) { GotoState(&Klaymen::stMoveObjectSkipTurnFaceObject); else GotoState(&Klaymen::stMoveObjectFaceObject); - break; + break; case 0x4812: if (param.asInteger() == 2) GotoState(&Klaymen::stPickUpNeedle); @@ -4233,7 +4233,7 @@ uint32 KmScene1404::xHandleMessage(int messageNum, const MessageParam ¶m) { gotoNextStateExt(); break; case 0x481A: - GotoState(&Klaymen::stInsertDisk); + GotoState(&Klaymen::stInsertDisk); break; case 0x481B: if (param.asPoint().y != 0) @@ -4307,7 +4307,7 @@ uint32 KmScene1608::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481B: if (param.asPoint().y != 0) startWalkToXDistance(param.asPoint().y, param.asPoint().x); @@ -4345,7 +4345,7 @@ uint32 KmScene1608::xHandleMessage(int messageNum, const MessageParam ¶m) { sendMessage(_parentScene, 0x2032, 1); _isSittingInTeleporter = true; GotoState(&Klaymen::stSitInTeleporter); - break; + break; case 0x4836: sendMessage(_parentScene, 0x2032, 0); _isSittingInTeleporter = false; @@ -4353,7 +4353,7 @@ uint32 KmScene1608::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x483F: startSpecialWalkRight(param.asInteger()); - break; + break; case 0x4840: startSpecialWalkLeft(param.asInteger()); break; @@ -4366,7 +4366,7 @@ uint32 KmScene1608::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene1705::KmScene1705(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - // Empty + // Empty } uint32 KmScene1705::xHandleMessage(int messageNum, const MessageParam ¶m) { @@ -4388,7 +4388,7 @@ uint32 KmScene1705::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x4803: GotoState(&Klaymen::stFallSkipJump); - break; + break; case 0x4812: if (param.asInteger() == 2) GotoState(&Klaymen::stPickUpNeedle); @@ -4435,7 +4435,7 @@ uint32 KmScene1705::xHandleMessage(int messageNum, const MessageParam ¶m) { sendMessage(_parentScene, 0x2000, 1); _isSittingInTeleporter = true; GotoState(&Klaymen::stSitInTeleporter); - break; + break; case 0x4836: sendMessage(_parentScene, 0x2000, 0); _isSittingInTeleporter = false; @@ -4443,10 +4443,10 @@ uint32 KmScene1705::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x483D: teleporterAppear(0x5E0A4905); - break; + break; case 0x483E: teleporterDisappear(0xD86E4477); - break; + break; } return messageResult; } @@ -4454,7 +4454,7 @@ uint32 KmScene1705::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene1901::KmScene1901(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - // Empty + // Empty } uint32 KmScene1901::xHandleMessage(int messageNum, const MessageParam ¶m) { @@ -4469,7 +4469,7 @@ uint32 KmScene1901::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481D: GotoState(&Klaymen::stTurnToUse); break; @@ -4482,7 +4482,7 @@ uint32 KmScene1901::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x483F: startSpecialWalkRight(param.asInteger()); - break; + break; case 0x4840: startSpecialWalkLeft(param.asInteger()); break; @@ -4493,7 +4493,7 @@ uint32 KmScene1901::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene2001::KmScene2001(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - // Empty + // Empty } uint32 KmScene2001::xHandleMessage(int messageNum, const MessageParam ¶m) { @@ -4557,7 +4557,7 @@ uint32 KmScene2001::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene2101::KmScene2101(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - + // Empty } @@ -4600,7 +4600,7 @@ uint32 KmScene2101::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481B: if (param.asPoint().y != 0) startWalkToXDistance(param.asPoint().y, param.asPoint().x); @@ -4622,7 +4622,7 @@ uint32 KmScene2101::xHandleMessage(int messageNum, const MessageParam ¶m) { sendMessage(_parentScene, 0x2000, 1); _isSittingInTeleporter = true; GotoState(&Klaymen::stSitInTeleporter); - break; + break; case 0x4836: sendMessage(_parentScene, 0x2000, 0); _isSittingInTeleporter = false; @@ -4635,7 +4635,7 @@ uint32 KmScene2101::xHandleMessage(int messageNum, const MessageParam ¶m) { teleporterDisappear(0x9A28CA1C); break; } - return messageResult; + return messageResult; } KmScene2201::KmScene2201(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount) @@ -4684,7 +4684,7 @@ uint32 KmScene2201::xHandleMessage(int messageNum, const MessageParam ¶m) { setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); gotoNextStateExt(); break; - case 0x482E: + case 0x482E: if (param.asInteger() == 1) GotoState(&Klaymen::stWalkToFrontNoStep); else @@ -4698,12 +4698,12 @@ uint32 KmScene2201::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x483F: startSpecialWalkRight(param.asInteger()); - break; + break; case 0x4840: startSpecialWalkLeft(param.asInteger()); break; } - return 0; + return 0; } KmScene2203::KmScene2203(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) @@ -4711,7 +4711,7 @@ KmScene2203::KmScene2203(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 // Empty } - + uint32 KmScene2203::xHandleMessage(int messageNum, const MessageParam ¶m) { switch (messageNum) { case 0x4001: @@ -4740,7 +4740,7 @@ uint32 KmScene2203::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x4818: startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); break; @@ -4748,7 +4748,7 @@ uint32 KmScene2203::xHandleMessage(int messageNum, const MessageParam ¶m) { GotoState(&Klaymen::stClayDoorOpen); break; case 0x481A: - GotoState(&Klaymen::stInsertDisk); + GotoState(&Klaymen::stInsertDisk); break; case 0x481B: if (param.asPoint().y != 0) @@ -4768,7 +4768,7 @@ uint32 KmScene2203::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x483F: startSpecialWalkRight(param.asInteger()); - break; + break; case 0x4840: startSpecialWalkLeft(param.asInteger()); break; @@ -4785,7 +4785,7 @@ KmScene2205::KmScene2205(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 void KmScene2205::xUpdate() { setGlobalVar(V_KLAYMEN_FRAMEINDEX, _currFrameIndex); } - + uint32 KmScene2205::xHandleMessage(int messageNum, const MessageParam ¶m) { switch (messageNum) { case 0x4001: @@ -4809,13 +4809,13 @@ uint32 KmScene2205::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x4818: startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); break; case 0x483F: startSpecialWalkRight(param.asInteger()); - break; + break; case 0x4840: startSpecialWalkLeft(param.asInteger()); break; @@ -4837,7 +4837,7 @@ KmScene2206::~KmScene2206() { void KmScene2206::xUpdate() { setGlobalVar(V_KLAYMEN_FRAMEINDEX, _currFrameIndex); } - + uint32 KmScene2206::xHandleMessage(int messageNum, const MessageParam ¶m) { switch (messageNum) { case 0x4001: @@ -4874,7 +4874,7 @@ uint32 KmScene2206::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481B: if (param.asPoint().y != 0) startWalkToXDistance(param.asPoint().y, param.asPoint().x); @@ -4897,7 +4897,7 @@ uint32 KmScene2206::xHandleMessage(int messageNum, const MessageParam ¶m) { setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); gotoNextStateExt(); break; - case 0x482E: + case 0x482E: if (param.asInteger() == 1) GotoState(&Klaymen::stWalkToFrontNoStep); else @@ -4914,7 +4914,7 @@ uint32 KmScene2206::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x483F: startSpecialWalkRight(param.asInteger()); - break; + break; case 0x4840: startSpecialWalkLeft(param.asInteger()); break; @@ -4927,7 +4927,7 @@ KmScene2207::KmScene2207(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 // Empty } - + uint32 KmScene2207::xHandleMessage(int messageNum, const MessageParam ¶m) { switch (messageNum) { case 0x2001: @@ -4961,7 +4961,7 @@ uint32 KmScene2207::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481B: if (param.asPoint().y != 0) startWalkToXDistance(param.asPoint().y, param.asPoint().x); @@ -4977,7 +4977,7 @@ uint32 KmScene2207::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x483F: startSpecialWalkRight(param.asInteger()); - break; + break; case 0x4840: startSpecialWalkLeft(param.asInteger()); break; @@ -5022,7 +5022,7 @@ uint32 KmScene2242::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481B: if (param.asPoint().y != 0) startWalkToXDistance(param.asPoint().y, param.asPoint().x); @@ -5080,7 +5080,7 @@ uint32 KmHallOfRecords::xHandleMessage(int messageNum, const MessageParam ¶m case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481F: if (param.asInteger() == 0) GotoState(&Klaymen::stWonderAboutHalf); @@ -5133,7 +5133,7 @@ uint32 KmScene2247::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481F: if (param.asInteger() == 0) GotoState(&Klaymen::stWonderAboutHalf); @@ -5156,13 +5156,13 @@ uint32 KmScene2247::xHandleMessage(int messageNum, const MessageParam ¶m) { } return 0; } - + KmScene2401::KmScene2401(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { // Empty } - + uint32 KmScene2401::xHandleMessage(int messageNum, const MessageParam ¶m) { uint32 messageResult = 0; switch (messageNum) { @@ -5184,7 +5184,7 @@ uint32 KmScene2401::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481B: if (param.asPoint().y != 0) startWalkToXDistance(param.asPoint().y, param.asPoint().x); @@ -5203,7 +5203,7 @@ uint32 KmScene2401::xHandleMessage(int messageNum, const MessageParam ¶m) { setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); gotoNextStateExt(); break; - case 0x482E: + case 0x482E: if (param.asInteger() == 1) GotoState(&Klaymen::stWalkToFrontNoStep); else @@ -5228,7 +5228,7 @@ uint32 KmScene2401::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x483F: startSpecialWalkRight(param.asInteger()); - break; + break; case 0x4840: startSpecialWalkLeft(param.asInteger()); break; @@ -5357,23 +5357,23 @@ uint32 KmScene2403::xHandleMessage(int messageNum, const MessageParam ¶m) { else GotoState(&Klaymen::stWonderAbout); break; - case 0x4820: + case 0x4820: sendMessage(_parentScene, 0x2000, 0); - GotoState(&Klaymen::stContinueClimbLadderUp); + GotoState(&Klaymen::stContinueClimbLadderUp); break; - case 0x4821: + case 0x4821: sendMessage(_parentScene, 0x2000, 0); _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderDown); + GotoState(&Klaymen::stStartClimbLadderDown); break; - case 0x4822: + case 0x4822: sendMessage(_parentScene, 0x2000, 0); _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderUp); + GotoState(&Klaymen::stStartClimbLadderUp); break; case 0x4823: sendMessage(_parentScene, 0x2001, 0); - GotoState(&Klaymen::stClimbLadderHalf); + GotoState(&Klaymen::stClimbLadderHalf); break; case 0x482D: setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); @@ -5382,16 +5382,16 @@ uint32 KmScene2403::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x483F: startSpecialWalkRight(param.asInteger()); break; - case 0x4840: + case 0x4840: startSpecialWalkLeft(param.asInteger()); break; } return messageResult; } - + KmScene2406::KmScene2406(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount) : Klaymen(vm, parentScene, x, y) { - + _surface->setClipRects(clipRects, clipRectsCount); } @@ -5425,7 +5425,7 @@ uint32 KmScene2406::xHandleMessage(int messageNum, const MessageParam ¶m) { gotoNextStateExt(); break; case 0x481A: - GotoState(&Klaymen::stInsertDisk); + GotoState(&Klaymen::stInsertDisk); break; case 0x481B: if (param.asPoint().y != 0) @@ -5451,40 +5451,40 @@ uint32 KmScene2406::xHandleMessage(int messageNum, const MessageParam ¶m) { else GotoState(&Klaymen::stWonderAbout); break; - case 0x4820: + case 0x4820: sendMessage(_parentScene, 0x2000, 0); - GotoState(&Klaymen::stContinueClimbLadderUp); + GotoState(&Klaymen::stContinueClimbLadderUp); break; - case 0x4821: + case 0x4821: sendMessage(_parentScene, 0x2000, 0); _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderDown); + GotoState(&Klaymen::stStartClimbLadderDown); break; - case 0x4822: + case 0x4822: sendMessage(_parentScene, 0x2000, 0); _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderUp); + GotoState(&Klaymen::stStartClimbLadderUp); break; case 0x4823: sendMessage(_parentScene, 0x2001, 0); - GotoState(&Klaymen::stClimbLadderHalf); + GotoState(&Klaymen::stClimbLadderHalf); break; case 0x483F: startSpecialWalkRight(param.asInteger()); break; - case 0x4840: + case 0x4840: startSpecialWalkLeft(param.asInteger()); break; } return messageResult; } - + KmScene2501::KmScene2501(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { // Empty } - + uint32 KmScene2501::xHandleMessage(int messageNum, const MessageParam ¶m) { uint32 messageResult = 0; switch (messageNum) { @@ -5505,7 +5505,7 @@ uint32 KmScene2501::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481D: if (_isSittingInTeleporter) GotoState(&Klaymen::stTurnToUseInTeleporter); @@ -5521,7 +5521,7 @@ uint32 KmScene2501::xHandleMessage(int messageNum, const MessageParam ¶m) { sendMessage(_parentScene, 0x2000, 1); _isSittingInTeleporter = true; GotoState(&Klaymen::stSitInTeleporter); - break; + break; case 0x4836: sendMessage(_parentScene, 0x2000, 0); _isSittingInTeleporter = false; @@ -5536,7 +5536,7 @@ KmScene2732::KmScene2732(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 // Empty } - + uint32 KmScene2732::xHandleMessage(int messageNum, const MessageParam ¶m) { switch (messageNum) { case 0x4804: @@ -5570,13 +5570,13 @@ uint32 KmScene2801::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481B: if (param.asPoint().y != 0) startWalkToXDistance(param.asPoint().y, param.asPoint().x); else startWalkToAttachedSpriteXDistance(param.asPoint().x); - break; + break; case 0x481D: GotoState(&Klaymen::stTurnToUse); break; @@ -5599,7 +5599,7 @@ uint32 KmScene2801::xHandleMessage(int messageNum, const MessageParam ¶m) { setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); gotoNextStateExt(); break; - case 0x482E: + case 0x482E: if (param.asInteger() == 1) GotoState(&Klaymen::stWalkToFrontNoStep); else @@ -5620,7 +5620,7 @@ uint32 KmScene2801::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene2803::KmScene2803(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount) : Klaymen(vm, parentScene, x, y) { - + _surface->setClipRects(clipRects, clipRectsCount); _dataResource.load(0x00900849); } @@ -5648,7 +5648,7 @@ uint32 KmScene2803::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x4818: startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); break; @@ -5664,7 +5664,7 @@ uint32 KmScene2803::xHandleMessage(int messageNum, const MessageParam ¶m) { else GotoState(&Klaymen::stWonderAboutHalf); break; - case 0x482E: + case 0x482E: GotoState(&Klaymen::stWalkToFront); break; case 0x482F: @@ -5682,7 +5682,7 @@ uint32 KmScene2803::xHandleMessage(int messageNum, const MessageParam ¶m) { KmScene2803Small::KmScene2803Small(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { - + _dataResource.load(0x81120132); } @@ -5759,7 +5759,7 @@ uint32 KmScene2805::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x481D: if (_isSittingInTeleporter) GotoState(&Klaymen::stTurnToUseInTeleporter); @@ -5775,7 +5775,7 @@ uint32 KmScene2805::xHandleMessage(int messageNum, const MessageParam ¶m) { sendMessage(_parentScene, 0x2000, 1); _isSittingInTeleporter = true; GotoState(&Klaymen::stSitInTeleporter); - break; + break; case 0x4836: sendMessage(_parentScene, 0x2000, 0); _isSittingInTeleporter = false; @@ -5805,7 +5805,7 @@ KmScene2806::KmScene2806(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 loadSound(6, 0x166FC6E0); loadSound(7, 0x00018040); } - + _dataResource.load(0x98182003); _surface->setClipRects(clipRects, clipRectsCount); } @@ -5827,12 +5827,12 @@ uint32 KmScene2806::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x4816: if (param.asInteger() == 0) - GotoState(&Klaymen::stPressButtonSide); + GotoState(&Klaymen::stPressButtonSide); break; case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x4818: startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); break; @@ -5885,12 +5885,12 @@ uint32 KmScene2809::xHandleMessage(int messageNum, const MessageParam ¶m) { break; case 0x4816: if (param.asInteger() == 0) - GotoState(&Klaymen::stPressButtonSide); + GotoState(&Klaymen::stPressButtonSide); break; case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x4818: startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); break; @@ -5907,7 +5907,7 @@ uint32 KmScene2809::xHandleMessage(int messageNum, const MessageParam ¶m) { return 0; } -KmScene2810Small::KmScene2810Small(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) +KmScene2810Small::KmScene2810Small(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : Klaymen(vm, parentScene, x, y) { // Empty @@ -5925,7 +5925,7 @@ uint32 KmScene2810Small::xHandleMessage(int messageNum, const MessageParam ¶ case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x4818: startWalkToXSmall(_dataResource.getPoint(param.asInteger()).x); break; @@ -5937,7 +5937,7 @@ uint32 KmScene2810Small::xHandleMessage(int messageNum, const MessageParam ¶ else GotoState(&Klaymen::stWonderAboutSmall); break; - case 0x482E: + case 0x482E: if (param.asInteger() == 1) GotoState(&Klaymen::stWalkToFrontNoStepSmall); else @@ -5961,7 +5961,7 @@ KmScene2810::KmScene2810(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 _surface->setClipRects(clipRects, clipRectsCount); } - + uint32 KmScene2810::xHandleMessage(int messageNum, const MessageParam ¶m) { switch (messageNum) { case 0x4001: @@ -5985,7 +5985,7 @@ uint32 KmScene2810::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x4817: setDoDeltaX(param.asInteger()); gotoNextStateExt(); - break; + break; case 0x4818: startWalkToX(_dataResource.getPoint(param.asInteger()).x, false); break; @@ -6009,23 +6009,23 @@ uint32 KmScene2810::xHandleMessage(int messageNum, const MessageParam ¶m) { else GotoState(&Klaymen::stWonderAbout); break; - case 0x4820: + case 0x4820: sendMessage(_parentScene, 0x2000, 0); - GotoState(&Klaymen::stContinueClimbLadderUp); + GotoState(&Klaymen::stContinueClimbLadderUp); break; - case 0x4821: + case 0x4821: sendMessage(_parentScene, 0x2000, 0); _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderDown); + GotoState(&Klaymen::stStartClimbLadderDown); break; - case 0x4822: + case 0x4822: sendMessage(_parentScene, 0x2000, 0); _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderUp); + GotoState(&Klaymen::stStartClimbLadderUp); break; case 0x4823: sendMessage(_parentScene, 0x2001, 0); - GotoState(&Klaymen::stClimbLadderHalf); + GotoState(&Klaymen::stClimbLadderHalf); break; case 0x4824: sendMessage(_parentScene, 0x2000, 0); @@ -6080,7 +6080,7 @@ uint32 KmScene2812::xHandleMessage(int messageNum, const MessageParam ¶m) { gotoNextStateExt(); break; case 0x481A: - GotoState(&Klaymen::stInsertDisk); + GotoState(&Klaymen::stInsertDisk); break; case 0x481B: if (param.asPoint().y != 0) @@ -6094,29 +6094,29 @@ uint32 KmScene2812::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x481E: GotoState(&Klaymen::stReturnFromUse); break; - case 0x4820: + case 0x4820: sendMessage(_parentScene, 0x2001, 0); - GotoState(&Klaymen::stContinueClimbLadderUp); + GotoState(&Klaymen::stContinueClimbLadderUp); break; - case 0x4821: + case 0x4821: sendMessage(_parentScene, 0x2001, 0); _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderDown); + GotoState(&Klaymen::stStartClimbLadderDown); break; - case 0x4822: + case 0x4822: sendMessage(_parentScene, 0x2001, 0); _destY = param.asInteger(); - GotoState(&Klaymen::stStartClimbLadderUp); + GotoState(&Klaymen::stStartClimbLadderUp); break; case 0x4823: sendMessage(_parentScene, 0x2002, 0); - GotoState(&Klaymen::stClimbLadderHalf); + GotoState(&Klaymen::stClimbLadderHalf); break; case 0x482D: setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0); gotoNextStateExt(); break; - case 0x482E: + case 0x482E: if (param.asInteger() == 1) GotoState(&Klaymen::stWalkToFrontNoStep); else @@ -6131,7 +6131,7 @@ uint32 KmScene2812::xHandleMessage(int messageNum, const MessageParam ¶m) { case 0x483F: startSpecialWalkRight(param.asInteger()); break; - case 0x4840: + case 0x4840: startSpecialWalkLeft(param.asInteger()); break; } diff --git a/engines/neverhood/klaymen.h b/engines/neverhood/klaymen.h index 25443b5a35..9e461a9c9c 100644 --- a/engines/neverhood/klaymen.h +++ b/engines/neverhood/klaymen.h @@ -77,24 +77,24 @@ public: void stIdleArms(); void evIdleArmsDone(); uint32 hmIdleArms(int messageNum, const MessageParam ¶m, Entity *sender); - + void stIdleChest(); uint32 hmIdleChest(int messageNum, const MessageParam ¶m, Entity *sender); - + void stIdleHeadOff(); uint32 hmIdleHeadOff(int messageNum, const MessageParam ¶m, Entity *sender); void stIdleWonderAbout(); void stIdleTeleporterHands(); - + void stIdleTeleporterHands2(); void stTryStandIdle(); void stStandAround(); void upStandIdle(); void stIdleBlink(); - + bool stStartAction(AnimationCb callback3); bool stStartActionFromIdle(AnimationCb callback); uint32 hmStartAction(int messageNum, const MessageParam ¶m, Entity *sender); @@ -134,7 +134,7 @@ public: void stPickUpTube(); uint32 hmPickUpTube(int messageNum, const MessageParam ¶m, Entity *sender); - + void stTurnToUse(); void stTurnToUseHalf(); void stTurnAwayFromUse(); @@ -263,10 +263,10 @@ public: void stJumpToGrabFall(); uint32 hmJumpToGrab(int messageNum, const MessageParam ¶m, Entity *sender); void suJumpToGrab(); - + void stJumpToGrabRelease(); uint32 hmJumpToGrabRelease(int messageNum, const MessageParam ¶m, Entity *sender); - + void stSitInTeleporter(); uint32 hmSitInTeleporter(int messageNum, const MessageParam ¶m, Entity *sender); @@ -326,7 +326,7 @@ public: void stFinishGrow(); uint32 hmFinishGrow(int messageNum, const MessageParam ¶m, Entity *sender); - + void stJumpToRingVenusFlyTrap(); uint32 hmJumpToRingVenusFlyTrap(int messageNum, const MessageParam ¶m, Entity *sender); @@ -363,7 +363,7 @@ public: //////////////////////////////////////////////////////////////////////////// void stopWalking(); - + void suAction(); void suUpdateDestX(); void suWalkingTestExit(); @@ -375,7 +375,7 @@ public: void setKlaymenIdleTable1(); void setKlaymenIdleTable2(); void setKlaymenIdleTable3(); - + void setSoundFlag(bool value) { _soundFlag = value; } void spitIntoPipe(); @@ -416,7 +416,7 @@ protected: NPointArray *_pathPoints; bool _soundFlag; - + int16 _spitOutCountdown; bool _isSittingInTeleporter; @@ -456,16 +456,16 @@ protected: void stStartWalkingSmall(); uint32 hmWalkingSmall(int messageNum, const MessageParam ¶m, Entity *sender); - + void enterIdleAnimation(uint idleAnimation); void walkAlongPathPoints(); - + }; class KmScene1001 : public Klaymen { public: KmScene1001(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); -protected: +protected: uint32 xHandleMessage(int messageNum, const MessageParam ¶m); }; @@ -473,7 +473,7 @@ class KmScene1002 : public Klaymen { public: KmScene1002(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y); protected: - void xUpdate(); + void xUpdate(); uint32 xHandleMessage(int messageNum, const MessageParam ¶m); }; diff --git a/engines/neverhood/menumodule.cpp b/engines/neverhood/menumodule.cpp index a8631cb0d6..7bf64a4602 100644 --- a/engines/neverhood/menumodule.cpp +++ b/engines/neverhood/menumodule.cpp @@ -20,6 +20,11 @@ * */ +#include "common/config-manager.h" +#include "common/translation.h" + +#include "gui/saveload.h" + #include "neverhood/menumodule.h" #include "neverhood/gamemodule.h" @@ -68,17 +73,19 @@ static const uint32 kMakingOfSmackerFileHashList[] = { MenuModule::MenuModule(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule), _savegameList(NULL) { - + SetMessageHandler(&MenuModule::handleMessage); - + _savedPaletteData = _vm->_screen->getPaletteData(); _vm->_mixer->pauseAll(true); + _vm->toggleSoundUpdate(false); createScene(MAIN_MENU, -1); } MenuModule::~MenuModule() { _vm->_mixer->pauseAll(false); + _vm->toggleSoundUpdate(true); _vm->_screen->setPaletteData(_savedPaletteData); } @@ -191,24 +198,26 @@ uint32 MenuModule::handleMessage(int messageNum, const MessageParam ¶m, Enti } void MenuModule::createLoadGameMenu() { - _savegameSlot = -1; - _savegameList = new SavegameList(); - loadSavegameList(); + refreshSaveGameList(); _childObject = new LoadGameMenu(_vm, this, _savegameList); } void MenuModule::createSaveGameMenu() { - _savegameSlot = -1; - _savegameList = new SavegameList(); - loadSavegameList(); + refreshSaveGameList(); _childObject = new SaveGameMenu(_vm, this, _savegameList); } void MenuModule::createDeleteGameMenu() { + refreshSaveGameList(); + _childObject = new DeleteGameMenu(_vm, this, _savegameList); +} + +void MenuModule::refreshSaveGameList() { _savegameSlot = -1; + delete _savegameList; + _savegameList = NULL; _savegameList = new SavegameList(); loadSavegameList(); - _childObject = new DeleteGameMenu(_vm, this, _savegameList); } void MenuModule::handleLoadGameMenuAction(bool doLoad) { @@ -257,7 +266,7 @@ void MenuModule::loadSavegameList() { Neverhood::NeverhoodEngine::SaveHeader header; Common::String pattern = _vm->getTargetName(); pattern += ".???"; - + Common::StringArray filenames; filenames = saveFileMan->listSavefiles(pattern.c_str()); Common::sort(filenames.begin(), filenames.end()); @@ -315,7 +324,7 @@ uint32 MenuButton::handleMessage(int messageNum, const MessageParam ¶m, Enti MainMenu::MainMenu(NeverhoodEngine *vm, Module *parentModule) : Scene(vm, parentModule) { - + static const uint32 kMenuButtonFileHashes[] = { 0x36C62120, 0x56C62120, @@ -327,26 +336,26 @@ MainMenu::MainMenu(NeverhoodEngine *vm, Module *parentModule) 0x16C62130, 0x16C62100 }; - + static const NRect kMenuButtonCollisionBounds[] = { - NRect(52, 121, 110, 156), - NRect(52, 192, 109, 222), - NRect(60, 257, 119, 286), - NRect(67, 326, 120, 354), - NRect(70, 389, 128, 416), - NRect(523, 113, 580, 144), - NRect(525, 176, 577, 206), - NRect(527, 384, 580, 412), - NRect(522, 255, 580, 289) + { 52, 121, 110, 156 }, + { 52, 192, 109, 222 }, + { 60, 257, 119, 286 }, + { 67, 326, 120, 354 }, + { 70, 389, 128, 416 }, + { 523, 113, 580, 144 }, + { 525, 176, 577, 206 }, + { 527, 384, 580, 412 }, + { 522, 255, 580, 289 } }; - + setBackground(0x08C0020C); setPalette(0x08C0020C); insertScreenMouse(0x00208084); - + insertStaticSprite(0x41137051, 100); insertStaticSprite(0xC10B2015, 100); - + // TODO Only if music is enabled _musicOnButton = insertStaticSprite(0x0C24C0EE, 100); @@ -355,9 +364,9 @@ MainMenu::MainMenu(NeverhoodEngine *vm, Module *parentModule) kMenuButtonFileHashes[buttonIndex], kMenuButtonCollisionBounds[buttonIndex]); addCollisionSprite(menuButton); } - - SetUpdateHandler(&Scene::update); - SetMessageHandler(&MainMenu::handleMessage); + + SetUpdateHandler(&Scene::update); + SetMessageHandler(&MainMenu::handleMessage); } @@ -387,18 +396,18 @@ CreditsScene::CreditsScene(NeverhoodEngine *vm, Module *parentModule, bool canAb : Scene(vm, parentModule), _canAbort(canAbort), _screenIndex(0), _ticksDuration(0), _countdown(216) { - SetUpdateHandler(&CreditsScene::update); + SetUpdateHandler(&CreditsScene::update); SetMessageHandler(&CreditsScene::handleMessage); - + setBackground(0x6081128C); setPalette(0x6081128C); _ticksTime = _vm->_system->getMillis() + 202100; - + _musicResource = new MusicResource(_vm); _musicResource->load(0x30812225); _musicResource->play(0); - + } CreditsScene::~CreditsScene() { @@ -460,7 +469,7 @@ Widget::Widget(NeverhoodEngine *vm, int16 x, int16 y, GameStateMenu *parentScene SetUpdateHandler(&Widget::update); SetMessageHandler(&Widget::handleMessage); - + setPosition(x, y); } @@ -523,7 +532,7 @@ TextLabelWidget::TextLabelWidget(NeverhoodEngine *vm, int16 x, int16 y, GameStat const byte *string, int stringLen, BaseSurface *drawSurface, int16 tx, int16 ty, FontSurface *fontSurface) : Widget(vm, x, y, parentScene, baseObjectPriority, baseSurfacePriority), _string(string), _stringLen(stringLen), _drawSurface(drawSurface), _tx(tx), _ty(ty), _fontSurface(fontSurface) { - + } void TextLabelWidget::initialize() { @@ -564,7 +573,7 @@ TextEditWidget::TextEditWidget(NeverhoodEngine *vm, int16 x, int16 y, GameStateM _maxVisibleChars = (_rect.x2 - _rect.x1) / _fontSurface->getCharWidth(); _cursorPos = 0; - + SetUpdateHandler(&TextEditWidget::update); SetMessageHandler(&TextEditWidget::handleMessage); } @@ -608,7 +617,7 @@ void TextEditWidget::initialize() { _textLabelWidget->initialize(); if (_cursorFileHash != 0) { cursorSpriteResource.load(_cursorFileHash, true); - _cursorSurface = new BaseSurface(_vm, 0, cursorSpriteResource.getDimensions().width, cursorSpriteResource.getDimensions().height); + _cursorSurface = new BaseSurface(_vm, 0, cursorSpriteResource.getDimensions().width, cursorSpriteResource.getDimensions().height, "cursor"); _cursorSurface->drawSpriteResourceEx(cursorSpriteResource, false, false, cursorSpriteResource.getDimensions().width, cursorSpriteResource.getDimensions().height); _cursorSurface->setVisible(!_readOnly); } @@ -757,9 +766,7 @@ void SavegameListBox::onClick() { mousePos.y -= _y + _rect.y1; if (mousePos.x >= 0 && mousePos.x <= _rect.x2 - _rect.x1 && mousePos.y >= 0 && mousePos.y <= _rect.y2 - _rect.y1) { - // We add 1 to the char height to ensure that the correct entry is chosen if the - // user clicks at the bottom the text entry - int newIndex = _firstVisibleItem + mousePos.y / (_fontSurface->getCharHeight() + 1); + int newIndex = _firstVisibleItem + mousePos.y / _fontSurface->getCharHeight(); if (newIndex <= _lastVisibleItem) { _currIndex = newIndex; refresh(); @@ -797,7 +804,7 @@ void SavegameListBox::buildItems() { void SavegameListBox::drawItems() { for (int i = 0; i < (int)_textLabelItems.size(); ++i) { - TextLabelWidget *label = _textLabelItems[i]; + TextLabelWidget *label = _textLabelItems[i]; if (i >= _firstVisibleItem && i <= _lastVisibleItem) { label->setY(_rect.y1 + (i - _firstVisibleItem) * _fontSurface->getCharHeight()); label->updateBounds(); @@ -821,7 +828,7 @@ void SavegameListBox::scrollUp() { } void SavegameListBox::scrollDown() { - if (_lastVisibleItem < (int)_textLabelItems.size()) { + if (_lastVisibleItem < (int)_textLabelItems.size() - 1) { ++_firstVisibleItem; ++_lastVisibleItem; refresh(); @@ -838,7 +845,7 @@ void SavegameListBox::pageUp() { } void SavegameListBox::pageDown() { - int amount = MIN((int)_textLabelItems.size() - _lastVisibleItem, _maxVisibleItemsCount); + int amount = MIN((int)_textLabelItems.size() - _lastVisibleItem - 1, _maxVisibleItemsCount); if (amount > 0) { _firstVisibleItem += amount; _lastVisibleItem += amount; @@ -846,17 +853,68 @@ void SavegameListBox::pageDown() { } } +int GameStateMenu::scummVMSaveLoadDialog(bool isSave, Common::String &saveDesc) { + const EnginePlugin *plugin = NULL; + EngineMan.findGame(ConfMan.get("gameid"), &plugin); + GUI::SaveLoadChooser *dialog; + Common::String desc; + int slot; + + if (isSave) { + dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); + + slot = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + desc = dialog->getResultString(); + + if (desc.empty()) + desc = dialog->createDefaultSaveDescription(slot); + + if (desc.size() > 29) + desc = Common::String(desc.c_str(), 29); + + saveDesc = desc; + } else { + dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false); + slot = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + } + + delete dialog; + + return slot; +} + GameStateMenu::GameStateMenu(NeverhoodEngine *vm, Module *parentModule, SavegameList *savegameList, const uint32 *buttonFileHashes, const NRect *buttonCollisionBounds, uint32 backgroundFileHash, uint32 fontFileHash, - uint32 mouseFileHash, const NRect *mouseRect, + uint32 mouseFileHash, const NRect *mouseRect, uint32 listBoxBackgroundFileHash, int16 listBoxX, int16 listBoxY, const NRect &listBoxRect, uint32 textEditBackgroundFileHash, uint32 textEditCursorFileHash, int16 textEditX, int16 textEditY, const NRect &textEditRect, - uint32 textFileHash1, uint32 textFileHash2) + uint32 textFileHash1, uint32 textFileHash2) : Scene(vm, parentModule), _currWidget(NULL), _savegameList(savegameList) { - + + bool isSave = (textEditCursorFileHash != 0); + _fontSurface = new FontSurface(_vm, fontFileHash, 32, 7, 32, 11, 17); - + + if (!ConfMan.getBool("originalsaveload")) { + Common::String saveDesc; + int saveCount = savegameList->size(); + int slot = scummVMSaveLoadDialog(isSave, saveDesc); + + if (slot >= 0) { + if (!isSave) { + ((MenuModule*)_parentModule)->setLoadgameInfo(slot); + } else { + ((MenuModule*)_parentModule)->setSavegameInfo(saveDesc, + slot, slot >= saveCount); + } + leaveScene(0); + } else { + leaveScene(1); + } + return; + } + setBackground(backgroundFileHash); setPalette(backgroundFileHash); insertScreenMouse(mouseFileHash, mouseRect); @@ -869,13 +927,13 @@ GameStateMenu::GameStateMenu(NeverhoodEngine *vm, Module *parentModule, Savegame _textEditWidget = new TextEditWidget(_vm, textEditX, textEditY, this, 29, _fontSurface, textEditBackgroundFileHash, textEditRect); - if (textEditCursorFileHash != 0) + if (isSave) _textEditWidget->setCursor(textEditCursorFileHash, 2, 13); else _textEditWidget->setReadOnly(true); _textEditWidget->initialize(); setCurrWidget(_textEditWidget); - + for (uint buttonIndex = 0; buttonIndex < 6; ++buttonIndex) { Sprite *menuButton = insertSprite<MenuButton>(this, buttonIndex, buttonFileHashes[buttonIndex], buttonCollisionBounds[buttonIndex]); @@ -884,7 +942,6 @@ GameStateMenu::GameStateMenu(NeverhoodEngine *vm, Module *parentModule, Savegame SetUpdateHandler(&Scene::update); SetMessageHandler(&GameStateMenu::handleMessage); - } GameStateMenu::~GameStateMenu() { @@ -969,17 +1026,17 @@ static const uint32 kSaveGameMenuButtonFileHashes[] = { }; static const NRect kSaveGameMenuButtonCollisionBounds[] = { - NRect(518, 106, 602, 160), - NRect(516, 378, 596, 434), - NRect(394, 108, 458, 206), - NRect(400, 204, 458, 276), - NRect(398, 292, 456, 352), - NRect(396, 352, 460, 444) + { 518, 106, 602, 160 }, + { 516, 378, 596, 434 }, + { 394, 108, 458, 206 }, + { 400, 204, 458, 276 }, + { 398, 292, 456, 352 }, + { 396, 352, 460, 444 } }; -static const NRect kSaveGameMenuListBoxRect(0, 0, 320, 272); -static const NRect kSaveGameMenuTextEditRect(0, 0, 377, 17); -static const NRect kSaveGameMenuMouseRect(50, 47, 427, 64); +static const NRect kSaveGameMenuListBoxRect = { 0, 0, 320, 272 }; +static const NRect kSaveGameMenuTextEditRect = { 0, 0, 377, 17 }; +static const NRect kSaveGameMenuMouseRect = { 50, 47, 427, 64 }; SaveGameMenu::SaveGameMenu(NeverhoodEngine *vm, Module *parentModule, SavegameList *savegameList) : GameStateMenu(vm, parentModule, savegameList, kSaveGameMenuButtonFileHashes, kSaveGameMenuButtonCollisionBounds, @@ -1003,17 +1060,17 @@ static const uint32 kLoadGameMenuButtonFileHashes[] = { }; static const NRect kLoadGameMenuButtonCollisionBounds[] = { - NRect( 44, 115, 108, 147), - NRect( 52, 396, 112, 426), - NRect(188, 116, 245, 196), - NRect(189, 209, 239, 269), - NRect(187, 301, 233, 349), - NRect(182, 358, 241, 433) + { 44, 115, 108, 147 }, + { 52, 396, 112, 426 }, + { 188, 116, 245, 196 }, + { 189, 209, 239, 269 }, + { 187, 301, 233, 349 }, + { 182, 358, 241, 433 } }; -static const NRect kLoadGameMenuListBoxRect(0, 0, 320, 271); -static const NRect kLoadGameMenuTextEditRect(0, 0, 320, 17); -static const NRect kLoadGameMenuMouseRect(263, 48, 583, 65); +static const NRect kLoadGameMenuListBoxRect = { 0, 0, 320, 271 }; +static const NRect kLoadGameMenuTextEditRect = { 0, 0, 320, 17 }; +static const NRect kLoadGameMenuMouseRect = { 263, 48, 583, 65 }; LoadGameMenu::LoadGameMenu(NeverhoodEngine *vm, Module *parentModule, SavegameList *savegameList) : GameStateMenu(vm, parentModule, savegameList, kLoadGameMenuButtonFileHashes, kLoadGameMenuButtonCollisionBounds, @@ -1036,21 +1093,21 @@ static const uint32 kDeleteGameMenuButtonFileHashes[] = { }; static const NRect kDeleteGameMenuButtonCollisionBounds[] = { - NRect(518, 46, 595, 91), - NRect(524, 322, 599, 369), - NRect(395, 40, 462, 127), - NRect(405, 126, 460, 185), - NRect(397, 205, 456, 273), - NRect(395, 278, 452, 372) + { 518, 46, 595, 91 }, + { 524, 322, 599, 369 }, + { 395, 40, 462, 127 }, + { 405, 126, 460, 185 }, + { 397, 205, 456, 273 }, + { 395, 278, 452, 372 } }; -static const NRect kDeleteGameMenuListBoxRect(0, 0, 320, 271); -static const NRect kDeleteGameMenuTextEditRect(0, 0, 320, 17); +static const NRect kDeleteGameMenuListBoxRect = { 0, 0, 320, 271 }; +static const NRect kDeleteGameMenuTextEditRect = { 0, 0, 320, 17 }; DeleteGameMenu::DeleteGameMenu(NeverhoodEngine *vm, Module *parentModule, SavegameList *savegameList) : GameStateMenu(vm, parentModule, savegameList, kDeleteGameMenuButtonFileHashes, kDeleteGameMenuButtonCollisionBounds, 0x4080E01C, 0x728523ED, - 0x0E018400, NULL, + 0x0E018400, NULL, 0xA5584211, 61, 64, kDeleteGameMenuListBoxRect, 0x250A3060, 0, 49, 414, kDeleteGameMenuTextEditRect, 0x80083C01, 0x84181E81) { @@ -1071,10 +1128,10 @@ QueryOverwriteMenu::QueryOverwriteMenu(NeverhoodEngine *vm, Module *parentModule }; static const NRect kQueryOverwriteMenuCollisionBounds[] = { - NRect(145, 334, 260, 385), - NRect(365, 340, 477, 388) + { 145, 334, 260, 385 }, + { 365, 340, 477, 388 } }; - + setBackground(0x043692C4); setPalette(0x043692C4); insertScreenMouse(0x692C004B); @@ -1097,7 +1154,7 @@ QueryOverwriteMenu::QueryOverwriteMenu(NeverhoodEngine *vm, Module *parentModule fontSurface->drawString(_background->getSurface(), 106 + (423 - textLines[i].size() * 11) / 2, 127 + 31 + i * 17, (const byte*)textLines[i].c_str()); delete fontSurface; - + SetUpdateHandler(&Scene::update); SetMessageHandler(&QueryOverwriteMenu::handleMessage); } diff --git a/engines/neverhood/menumodule.h b/engines/neverhood/menumodule.h index 08858ad204..f201654ceb 100644 --- a/engines/neverhood/menumodule.h +++ b/engines/neverhood/menumodule.h @@ -45,6 +45,7 @@ public: void setLoadgameInfo(uint index); void setSavegameInfo(const Common::String &description, uint index, bool newSavegame); void setDeletegameInfo(uint index); + void refreshSaveGameList(); protected: int _sceneNum; byte *_savedPaletteData; @@ -123,8 +124,8 @@ protected: class TextLabelWidget : public Widget { public: TextLabelWidget(NeverhoodEngine *vm, int16 x, int16 y, GameStateMenu *parentScene, - int baseObjectPriority, int baseSurfacePriority, - const byte *string, int stringLen, BaseSurface *drawSurface, int16 tx, int16 ty, FontSurface *fontSurface); + int baseObjectPriority, int baseSurfacePriority, + const byte *string, int stringLen, BaseSurface *drawSurface, int16 tx, int16 ty, FontSurface *fontSurface); virtual void initialize(); virtual int16 getWidth(); virtual int16 getHeight(); @@ -205,13 +206,13 @@ protected: uint _currIndex; int _maxVisibleItemsCount; }; - + class GameStateMenu : public Scene { public: GameStateMenu(NeverhoodEngine *vm, Module *parentModule, SavegameList *savegameList, const uint32 *buttonFileHashes, const NRect *buttonCollisionBounds, uint32 backgroundFileHash, uint32 fontFileHash, - uint32 mouseFileHash, const NRect *mouseRect, + uint32 mouseFileHash, const NRect *mouseRect, uint32 listBoxBackgroundFileHash, int16 listBoxX, int16 listBoxY, const NRect &listBoxRect, uint32 textEditBackgroundFileHash, uint32 textEditCursorFileHash, int16 textEditX, int16 textEditY, const NRect &textEditRect, uint32 textFileHash1, uint32 textFileHash2); @@ -229,6 +230,7 @@ protected: Common::String _savegameDescription; uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); virtual void performAction(); + int scummVMSaveLoadDialog(bool isSave, Common::String &saveDesc); }; class SaveGameMenu : public GameStateMenu { diff --git a/engines/neverhood/module.cpp b/engines/neverhood/module.cpp index e384b5a4d2..d1578e680c 100644 --- a/engines/neverhood/module.cpp +++ b/engines/neverhood/module.cpp @@ -31,9 +31,9 @@ namespace Neverhood { Module::Module(NeverhoodEngine *vm, Module *parentModule) : Entity(vm, 0), _parentModule(parentModule), _childObject(NULL), _done(false), _sceneType(kSceneTypeNormal) { - + SetMessageHandler(&Module::handleMessage); - + } Module::~Module() { diff --git a/engines/neverhood/module.h b/engines/neverhood/module.h index e98012cbea..ba1e1fa3db 100644 --- a/engines/neverhood/module.h +++ b/engines/neverhood/module.h @@ -48,9 +48,10 @@ public: Module(NeverhoodEngine *vm, Module *parentModule); virtual ~Module(); virtual void draw(); + + Entity *_childObject; protected: Module *_parentModule; - Entity *_childObject; bool _done; uint32 _moduleResult; SceneType _sceneType; diff --git a/engines/neverhood/module.mk b/engines/neverhood/module.mk index 714fc3079b..030c78a407 100644 --- a/engines/neverhood/module.mk +++ b/engines/neverhood/module.mk @@ -3,6 +3,7 @@ MODULE := engines/neverhood MODULE_OBJS = \ background.o \ blbarchive.o \ + console.o \ detection.o \ diskplayerscene.o \ entity.o \ diff --git a/engines/neverhood/modules/module1000.cpp b/engines/neverhood/modules/module1000.cpp index 415d0f72b1..f65b89899d 100644 --- a/engines/neverhood/modules/module1000.cpp +++ b/engines/neverhood/modules/module1000.cpp @@ -26,10 +26,8 @@ namespace Neverhood { Module1000::Module1000(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - - debug("Create Module1000(%d)", which); - _musicFileHash = getGlobalVar(V_ENTRANCE_OPEN) ? 0x81106480 : 0x00103144; + _musicFileHash = getGlobalVar(V_ENTRANCE_OPEN) ? 0x81106480 : 0x00103144; _vm->_soundMan->addMusic(0x03294419, 0x061880C6); _vm->_soundMan->addMusic(0x03294419, _musicFileHash); @@ -48,7 +46,7 @@ Module1000::~Module1000() { } void Module1000::createScene(int sceneNum, int which) { - debug("Module1000::createScene(%d, %d)", sceneNum, which); + debug(1, "Module1000::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -120,11 +118,11 @@ void Module1000::updateScene() { } } -// Scene1001 +// Scene1001 AsScene1001Door::AsScene1001Door(NeverhoodEngine *vm) : AnimatedSprite(vm, 1100) { - + createSurface(800, 137, 242); _x = 726; _y = 440; @@ -153,16 +151,16 @@ void AsScene1001Door::hammerHitsDoor() { case 1: playSound(0, 0x65482F03); startAnimation(0x624C0498, 1, 3); - NextState(&AsScene1001Door::stShowIdleDoor); + NextState(&AsScene1001Door::stShowIdleDoor); break; case 2: playSound(1); startAnimation(0x624C0498, 6, 6); - NextState(&AsScene1001Door::stBustedDoorMove); + NextState(&AsScene1001Door::stBustedDoorMove); break; default: // Nothing - break; + break; } incGlobalVar(V_DOOR_STATUS, 1); } @@ -198,9 +196,9 @@ void AsScene1001Door::stBustedDoorMove() { void AsScene1001Door::stBustedDoorGone() { playSound(0); stopAnimation(); - setVisible(false); + setVisible(false); } - + AsScene1001Hammer::AsScene1001Hammer(NeverhoodEngine *vm, Sprite *asDoor) : AnimatedSprite(vm, 1100), _asDoor(asDoor) { @@ -264,7 +262,7 @@ uint32 AsScene1001Window::handleMessage(int messageNum, const MessageParam ¶ AsScene1001Lever::AsScene1001Lever(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, int deltaXType) : AnimatedSprite(vm, 1100), _parentScene(parentScene) { - + createSurface(1010, 71, 73); setDoDeltaX(deltaXType); startAnimation(0x04A98C36, 0, -1); @@ -304,22 +302,22 @@ uint32 AsScene1001Lever::handleMessage(int messageNum, const MessageParam ¶m } return messageResult; } - + SsCommonButtonSprite::SsCommonButtonSprite(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash, int surfacePriority, uint32 soundFileHash) : StaticSprite(vm, fileHash, surfacePriority), _parentScene(parentScene), _countdown(0) { _priority = 1100; - _soundFileHash = soundFileHash ? soundFileHash : 0x44141000; + _soundFileHash = soundFileHash ? soundFileHash : 0x44141000; setVisible(false); SetUpdateHandler(&SsCommonButtonSprite::update); SetMessageHandler(&SsCommonButtonSprite::handleMessage); } - + void SsCommonButtonSprite::update() { if (_countdown != 0 && (--_countdown) == 0) setVisible(false); } - + uint32 SsCommonButtonSprite::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); switch (messageNum) { @@ -332,19 +330,19 @@ uint32 SsCommonButtonSprite::handleMessage(int messageNum, const MessageParam &p } return messageResult; } - + Scene1001::Scene1001(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _asDoor(NULL), _asWindow(NULL) { Sprite *tempSprite; SetMessageHandler(&Scene1001::handleMessage); - + setHitRects(0x004B4860); setBackground(0x4086520E); setPalette(0x4086520E); insertScreenMouse(0x6520A400); - + if (which < 0) { // Restoring game setRectList(0x004B49F0); @@ -375,7 +373,7 @@ Scene1001::Scene1001(NeverhoodEngine *vm, Module *parentModule, int which) tempSprite = insertStaticSprite(0x2080A3A8, 1300); _klaymen->setClipRect(0, 0, tempSprite->getDrawRect().x2(), 480); - + if (!getGlobalVar(V_DOOR_BUSTED)) { _asDoor = insertSprite<AsScene1001Door>(); _asDoor->setClipRect(0, 0, tempSprite->getDrawRect().x2(), 480); @@ -447,7 +445,7 @@ AsScene1002Ring::AsScene1002Ring(NeverhoodEngine *vm, Scene *parentScene, bool i : AnimatedSprite(vm, 1100), _parentScene(parentScene), _isSpecial(isSpecial) { SetUpdateHandler(&AsScene1002Ring::update); - + if (_isSpecial) { createSurface(990, 68, 314); if (isRingLow) { @@ -583,7 +581,7 @@ uint32 AsScene1002Ring::hmRingReleased(int messageNum, const MessageParam ¶m AsScene1002Door::AsScene1002Door(NeverhoodEngine *vm, NRect &clipRect) : StaticSprite(vm, 1200) { - + loadSprite(0x1052370F, kSLFDefDrawOffset | kSLFSetPosition, 800, 526, getGlobalVar(V_FLYTRAP_RING_DOOR) ? 49 : 239); setClipRect(clipRect); SetUpdateHandler(&AsScene1002Door::update); @@ -639,7 +637,7 @@ AsScene1002BoxingGloveHitEffect::AsScene1002BoxingGloveHitEffect(NeverhoodEngine createSurface(1025, 88, 165); setVisible(false); SetUpdateHandler(&AnimatedSprite::update); - SetMessageHandler(&AsScene1002BoxingGloveHitEffect::handleMessage); + SetMessageHandler(&AsScene1002BoxingGloveHitEffect::handleMessage); } uint32 AsScene1002BoxingGloveHitEffect::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -718,7 +716,7 @@ void AsScene1002DoorSpy::stDoorSpyBoxingGlove() { NextState(&AsScene1002DoorSpy::stDoorSpyIdle); } -SsCommonPressButton::SsCommonPressButton(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int surfacePriority, uint32 soundFileHash) +SsCommonPressButton::SsCommonPressButton(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int surfacePriority, uint32 soundFileHash) : StaticSprite(vm, 1100), _parentScene(parentScene), _status(0), _countdown(0) { _soundFileHash = soundFileHash != 0 ? soundFileHash : 0x44141000; @@ -790,7 +788,7 @@ AsScene1002VenusFlyTrap::AsScene1002VenusFlyTrap(NeverhoodEngine *vm, Scene *par stRingGrabbed(); } else { stIdle(); - } + } } _flags = 4; SetUpdateHandler(&AsScene1002VenusFlyTrap::update); @@ -852,12 +850,12 @@ uint32 AsScene1002VenusFlyTrap::handleMessage(int messageNum, const MessageParam if (_isSecond) { if (_x >= 154 && _x <= 346) messageResult = 1; - else + else messageResult = 0; } else { if (_x >= 174 && _x <= 430) messageResult = 1; - else + else messageResult = 0; } break; @@ -1025,7 +1023,7 @@ AsScene1002OutsideDoorBackground::AsScene1002OutsideDoorBackground(NeverhoodEngi } else setVisible(false); SetUpdateHandler(&AsScene1002OutsideDoorBackground::update); - SetMessageHandler(&AsScene1002OutsideDoorBackground::handleMessage); + SetMessageHandler(&AsScene1002OutsideDoorBackground::handleMessage); } void AsScene1002OutsideDoorBackground::update() { @@ -1085,7 +1083,7 @@ void AsScene1002OutsideDoorBackground::stDoorClosed() { AsScene1002KlaymenLadderHands::AsScene1002KlaymenLadderHands(NeverhoodEngine *vm, Klaymen *klaymen) : AnimatedSprite(vm, 1200), _klaymen(klaymen) { - + createSurface(1200, 40, 163); setVisible(false); SetUpdateHandler(&AsScene1002KlaymenLadderHands::update); @@ -1097,15 +1095,15 @@ void AsScene1002KlaymenLadderHands::update() { startAnimation(0xBA280522, _klaymen->getFrameIndex(), -1); _newStickFrameIndex = _klaymen->getFrameIndex(); setVisible(true); - _x = _klaymen->getX(); - _y = _klaymen->getY(); + _x = _klaymen->getX(); + _y = _klaymen->getY(); setDoDeltaX(_klaymen->isDoDeltaX() ? 1 : 0); } else if (_klaymen->getCurrAnimFileHash() == 0x122D1505) { startAnimation(0x1319150C, _klaymen->getFrameIndex(), -1); _newStickFrameIndex = _klaymen->getFrameIndex(); setVisible(true); - _x = _klaymen->getX(); - _y = _klaymen->getY(); + _x = _klaymen->getX(); + _y = _klaymen->getY(); setDoDeltaX(_klaymen->isDoDeltaX() ? 1 : 0); } else setVisible(false); @@ -1115,7 +1113,7 @@ void AsScene1002KlaymenLadderHands::update() { AsScene1002KlaymenPeekHand::AsScene1002KlaymenPeekHand(NeverhoodEngine *vm, Scene *parentScene, Klaymen *klaymen) : AnimatedSprite(vm, 1200), _parentScene(parentScene), _klaymen(klaymen), _isClipRectSaved(false) { - + createSurface(1000, 33, 41); setVisible(false); SetUpdateHandler(&AsScene1002KlaymenPeekHand::update); @@ -1247,7 +1245,7 @@ Scene1002::Scene1002(NeverhoodEngine *vm, Module *parentModule, int which) sendEntityMessage(_klaymen, 0x2007, _asVenusFlyTrap); _asOutsideDoorBackground = insertSprite<AsScene1002OutsideDoorBackground>(); - + setRectList(0x004B43A0); loadSound(1, 0x60755842); @@ -1324,11 +1322,11 @@ uint32 Scene1002::handleMessage(int messageNum, const MessageParam ¶m, Entit break; case 0x2002: _messageList = NULL; - break; + break; case 0x2005: _isClimbingLadder = true; setRectList(0x004B4418); - break; + break; case 0x2006: _isClimbingLadder = false; setRectList(0x004B43A0); @@ -1362,11 +1360,11 @@ uint32 Scene1002::handleMessage(int messageNum, const MessageParam ¶m, Entit if (getGlobalVar(V_FLYTRAP_RING_DOOR)) { sendMessage(_asRing3, 0x4807, 0); } - } + } break; case 0x480B: sendEntityMessage(_klaymen, 0x1014, _asDoorSpy); - break; + break; case 0x480F: setGlobalVar(V_RADIO_ENABLED, 0); playSound(1); @@ -1381,7 +1379,7 @@ uint32 Scene1002::handleMessage(int messageNum, const MessageParam ¶m, Entit setSpriteSurfacePriority(_ssCeiling, 1015); setSpriteSurfacePriority(_ssLadderArch, 1015); break; - } + } return messageResult; } @@ -1391,7 +1389,7 @@ StaticScene::StaticScene(NeverhoodEngine *vm, Module *parentModule, uint32 backg : Scene(vm, parentModule) { SetMessageHandler(&StaticScene::handleMessage); - + setBackground(backgroundFileHash); setPalette(backgroundFileHash); insertPuzzleMouse(cursorFileHash, 20, 620); @@ -1444,7 +1442,7 @@ Scene1004::Scene1004(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _paletteAreaStatus(-1) { Sprite *tempSprite; - + SetUpdateHandler(&Scene1004::update); SetMessageHandler(&Scene1004::handleMessage); @@ -1477,16 +1475,16 @@ Scene1004::Scene1004(NeverhoodEngine *vm, Module *parentModule, int which) insertKlaymen<KmScene1004>(_dataResource.getPoint(0x80052A29).x, 27); setMessageList(0x004B7BF0); } - + updatePaletteArea(); - + _asKlaymenLadderHands = insertSprite<AsScene1002KlaymenLadderHands>(_klaymen); insertStaticSprite(0x800034A0, 1100); insertStaticSprite(0x64402020, 1100); insertStaticSprite(0x3060222E, 1300); tempSprite = insertStaticSprite(0x0E002004, 1300); - + _klaymen->setClipRect(0, tempSprite->getDrawRect().y, 640, 480); _asKlaymenLadderHands->setClipRect(_klaymen->getClipRect()); @@ -1520,7 +1518,7 @@ uint32 Scene1004::handleMessage(int messageNum, const MessageParam ¶m, Entit break; } return messageResult; -} +} void Scene1004::updatePaletteArea() { if (_klaymen->getY() < 150) { @@ -1559,7 +1557,7 @@ Scene1005::Scene1005(NeverhoodEngine *vm, Module *parentModule, int which) } drawTextToBackground(); - + } uint32 Scene1005::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -1567,7 +1565,7 @@ uint32 Scene1005::handleMessage(int messageNum, const MessageParam ¶m, Entit switch (messageNum) { case 0x0001: if (param.asPoint().x <= 20 || param.asPoint().x >= 620) - leaveScene(0); + leaveScene(0); break; } return 0; @@ -1616,19 +1614,19 @@ uint32 Scene1005::getTextIndex1() { textIndex = 23; else if (!getSubVar(VA_HAS_KEY, 0) && !getSubVar(VA_IS_KEY_INSERTED, 0)) textIndex = 24; - else if (!getGlobalVar(V_HAS_FINAL_KEY)) + else if (!getGlobalVar(V_HAS_FINAL_KEY)) textIndex = 26; else if (!getSubVar(VA_HAS_KEY, 1) && !getSubVar(VA_IS_KEY_INSERTED, 1)) textIndex = 27; - else if (!getGlobalVar(V_HAS_FINAL_KEY)) + else if (!getGlobalVar(V_HAS_FINAL_KEY)) textIndex = 28; - else + else textIndex = 29; } else if (!getGlobalVar(V_FELL_DOWN_HOLE)) textIndex = 20; else if (!getGlobalVar(V_SEEN_SYMBOLS_NO_LIGHT)) textIndex = 21; - else + else textIndex = 22; } else if (getGlobalVar(V_BOLT_DOOR_UNLOCKED)) { if (!getGlobalVar(V_WALL_BROKEN)) @@ -1643,7 +1641,7 @@ uint32 Scene1005::getTextIndex1() { textIndex = 15; else if (!getGlobalVar(V_BEEN_STATUE_ROOM)) textIndex = 16; - else + else textIndex = 17; } else if (!getGlobalVar(V_FLYTRAP_RING_EATEN)) { textIndex = 0; @@ -1662,7 +1660,7 @@ uint32 Scene1005::getTextIndex1() { textIndex = 9; else if (!getSubVar(VA_LOCKS_DISABLED, 0x01180951)) textIndex = 10; - else + else textIndex = 11; } else if (!getGlobalVar(V_CREATURE_ANGRY)) { textIndex = 1; diff --git a/engines/neverhood/modules/module1000.h b/engines/neverhood/modules/module1000.h index 9977590a6a..8461ecfc6f 100644 --- a/engines/neverhood/modules/module1000.h +++ b/engines/neverhood/modules/module1000.h @@ -85,7 +85,7 @@ protected: Scene *_parentScene; uint32 _soundFileHash; int16 _countdown; - void update(); + void update(); uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; diff --git a/engines/neverhood/modules/module1100.cpp b/engines/neverhood/modules/module1100.cpp index c4d90b5562..faa0516d7e 100644 --- a/engines/neverhood/modules/module1100.cpp +++ b/engines/neverhood/modules/module1100.cpp @@ -40,7 +40,7 @@ static const uint32 kModule1100SoundList[] = { Module1100::Module1100(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - + if (which < 0) { createScene(_vm->gameState().sceneNum, -1); } else if (which == 1) { @@ -64,7 +64,8 @@ Module1100::~Module1100() { void Module1100::createScene(int sceneNum, int which) { static const uint32 kSmackerFileHashList06[] = {0x10880805, 0x1088081D, 0}; static const uint32 kSmackerFileHashList07[] = {0x00290321, 0x01881000, 0}; - debug("Module1100::createScene(%d, %d)", sceneNum, which); + static const byte kNavigationTypes02[] = {1, 0, 4, 1}; + debug(1, "Module1100::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -80,9 +81,9 @@ void Module1100::createScene(int sceneNum, int which) { case 2: _vm->gameState().sceneNum = 2; if (getGlobalVar(V_ROBOT_TARGET)) { - createNavigationScene(0x004B84F0, which); + createNavigationScene(0x004B84F0, which, kNavigationTypes02); } else { - createNavigationScene(0x004B8490, which); + createNavigationScene(0x004B8490, which, kNavigationTypes02); } break; case 3: @@ -270,7 +271,7 @@ static const uint32 kSsScene1105SymbolDieFileHashes[] = { SsScene1105Button::SsScene1105Button(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash, NRect &collisionBounds) : StaticSprite(vm, fileHash, 200), _parentScene(parentScene), _countdown(0) { - + _collisionBounds = collisionBounds; SetMessageHandler(&SsScene1105Button::handleMessage); SetUpdateHandler(&SsScene1105Button::update); @@ -346,7 +347,7 @@ void SsScene1105SymbolDie::hide() { AsScene1105TeddyBear::AsScene1105TeddyBear(NeverhoodEngine *vm, Scene *parentScene) : AnimatedSprite(vm, 1100), _parentScene(parentScene) { - + createSurface(100, 556, 328); _x = 320; _y = 240; @@ -395,7 +396,7 @@ void AsScene1105TeddyBear::hide() { SsScene1105OpenButton::SsScene1105OpenButton(NeverhoodEngine *vm, Scene *parentScene) : StaticSprite(vm, 900), _parentScene(parentScene), _countdown(0), _isClicked(false) { - + loadSprite(0x8228A46C, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); setVisible(false); loadSound(0, 0x44045140); @@ -431,26 +432,26 @@ uint32 SsScene1105OpenButton::handleMessage(int messageNum, const MessageParam & Scene1105::Scene1105(NeverhoodEngine *vm, Module *parentModule) : Scene(vm, parentModule), _countdown(0), _isPanelOpen(false), _isActionButtonClicked(false), _doMoveTeddy(false), _isClosePanelDone(false), _leaveResult(0), _backgroundIndex(0) { - + Sprite *ssOpenButton; - + _vm->gameModule()->initMemoryPuzzle(); - + SetUpdateHandler(&Scene1105::update); SetMessageHandler(&Scene1105::handleMessage); - + setBackground(0x20010002); setPalette(0x20010002); - + _asTeddyBear = insertSprite<AsScene1105TeddyBear>(this); ssOpenButton = insertSprite<SsScene1105OpenButton>(this); addCollisionSprite(ssOpenButton); insertPuzzleMouse(0x10006208, 20, 620); - + loadSound(0, 0x48442057); loadSound(1, 0xC025014F); loadSound(2, 0x68E25540); - + } uint32 Scene1105::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -554,27 +555,27 @@ void Scene1105::createObjects() { _ssSymbolDice[1] = insertSprite<SsScene1105SymbolDie>(1, 339, 304); _ssSymbolDice[2] = insertSprite<SsScene1105SymbolDie>(2, 485, 304); - _ssSymbol1UpButton = insertSprite<SsScene1105Button>(this, 0x08002860, NRect(146, 362, 192, 403)); + _ssSymbol1UpButton = insertSprite<SsScene1105Button>(this, 0x08002860, NRect::make(146, 362, 192, 403)); addCollisionSprite(_ssSymbol1UpButton); - _ssSymbol1DownButton = insertSprite<SsScene1105Button>(this, 0x42012460, NRect(147, 404, 191, 442)); + _ssSymbol1DownButton = insertSprite<SsScene1105Button>(this, 0x42012460, NRect::make(147, 404, 191, 442)); addCollisionSprite(_ssSymbol1DownButton); - _ssSymbol2UpButton = insertSprite<SsScene1105Button>(this, 0x100030A0, NRect(308, 361, 355, 402)); + _ssSymbol2UpButton = insertSprite<SsScene1105Button>(this, 0x100030A0, NRect::make(308, 361, 355, 402)); addCollisionSprite(_ssSymbol2UpButton); - _ssSymbol2DownButton = insertSprite<SsScene1105Button>(this, 0x840228A0, NRect(306, 406, 352, 445)); + _ssSymbol2DownButton = insertSprite<SsScene1105Button>(this, 0x840228A0, NRect::make(306, 406, 352, 445)); addCollisionSprite(_ssSymbol2DownButton); - _ssSymbol3UpButton = insertSprite<SsScene1105Button>(this, 0x20000120, NRect(476, 358, 509, 394)); + _ssSymbol3UpButton = insertSprite<SsScene1105Button>(this, 0x20000120, NRect::make(476, 358, 509, 394)); addCollisionSprite(_ssSymbol3UpButton); - _ssSymbol3DownButton = insertSprite<SsScene1105Button>(this, 0x08043121, NRect(463, 401, 508, 438)); + _ssSymbol3DownButton = insertSprite<SsScene1105Button>(this, 0x08043121, NRect::make(463, 401, 508, 438)); addCollisionSprite(_ssSymbol3DownButton); - _ssActionButton = insertSprite<SsScene1105Button>(this, 0x8248AD35, NRect(280, 170, 354, 245)); + _ssActionButton = insertSprite<SsScene1105Button>(this, 0x8248AD35, NRect::make(280, 170, 354, 245)); addCollisionSprite(_ssActionButton); - + _isPanelOpen = true; - + _asTeddyBear->show(); insertPuzzleMouse(0x18666208, 20, 620); - + } void Scene1105::upOpenPanel() { @@ -625,13 +626,6 @@ void Scene1105::upClosePanel() { } void Scene1105::update() { - - // DEBUG: Show the correct code - debug("(%d, %d) (%d, %d) (%d, %d)", - getSubVar(VA_GOOD_DICE_NUMBERS, 0), getSubVar(VA_CURR_DICE_NUMBERS, 0), - getSubVar(VA_GOOD_DICE_NUMBERS, 1), getSubVar(VA_CURR_DICE_NUMBERS, 1), - getSubVar(VA_GOOD_DICE_NUMBERS, 2), getSubVar(VA_CURR_DICE_NUMBERS, 2)); - Scene::update(); if (_countdown != 0 && (--_countdown == 0)) createObjects(); @@ -645,13 +639,13 @@ void Scene1105::update() { Scene1109::Scene1109(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { - + SetMessageHandler(&Scene1109::handleMessage); - + setBackground(0x8449E02F); setPalette(0x8449E02F); insertScreenMouse(0x9E02B84C); - + _sprite1 = insertStaticSprite(0x600CEF01, 1100); if (which < 0) { diff --git a/engines/neverhood/modules/module1200.cpp b/engines/neverhood/modules/module1200.cpp index 3be3635645..e7766419f9 100644 --- a/engines/neverhood/modules/module1200.cpp +++ b/engines/neverhood/modules/module1200.cpp @@ -26,7 +26,7 @@ namespace Neverhood { Module1200::Module1200(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - + SetMessageHandler(&Module1200::handleMessage); if (which < 0) @@ -45,7 +45,7 @@ Module1200::~Module1200() { } void Module1200::createScene(int sceneNum, int which) { - debug("Module1200::createScene(%d, %d)", sceneNum, which); + debug(1, "Module1200::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -124,7 +124,7 @@ static const uint32 kScene1201TntFileHashList2[] = { 0xB140A1E6, 0x5088A068, 0x5088A068, 0x74C4C866, 0x3192C059, 0x3192C059 }; - + SsScene1201Tnt::SsScene1201Tnt(NeverhoodEngine *vm, uint32 elemIndex, uint32 pointIndex, int16 clipY2) : StaticSprite(vm, 900) { @@ -133,13 +133,13 @@ SsScene1201Tnt::SsScene1201Tnt(NeverhoodEngine *vm, uint32 elemIndex, uint32 poi if (x < 300) loadSprite(kScene1201TntFileHashList1[elemIndex], kSLFDefDrawOffset | kSLFDefPosition, 50); else - loadSprite(kScene1201TntFileHashList2[elemIndex], kSLFCenteredDrawOffset | kSLFSetPosition, 50, x, y); + loadSprite(kScene1201TntFileHashList2[elemIndex], kSLFCenteredDrawOffset | kSLFSetPosition, 50, x, y - 20); setClipRect(0, 0, 640, clipY2); } - + AsScene1201Tape::AsScene1201Tape(NeverhoodEngine *vm, Scene *parentScene, uint32 nameHash, int surfacePriority, int16 x, int16 y, uint32 fileHash) : AnimatedSprite(vm, fileHash, surfacePriority, x, y), _parentScene(parentScene), _nameHash(nameHash) { - + if (!getSubVar(VA_HAS_TAPE, _nameHash) && !getSubVar(VA_IS_TAPE_INSERTED, _nameHash)) { SetMessageHandler(&AsScene1201Tape::handleMessage); } else { @@ -253,10 +253,10 @@ void AsScene1201RightDoor::stCloseDoorDone() { stopAnimation(); setVisible(false); } - + AsScene1201KlaymenHead::AsScene1201KlaymenHead(NeverhoodEngine *vm) : AnimatedSprite(vm, 1200) { - + createSurface(1200, 69, 98); SetUpdateHandler(&AnimatedSprite::update); SetMessageHandler(&AsScene1201KlaymenHead::handleMessage); @@ -301,7 +301,7 @@ AsScene1201TntMan::AsScene1201TntMan(NeverhoodEngine *vm, Scene *parentScene, Sp AsScene1201TntMan::~AsScene1201TntMan() { _vm->_soundMan->deleteSoundGroup(0x01D00560); -} +} uint32 AsScene1201TntMan::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); @@ -396,7 +396,7 @@ void AsScene1201TntManFlame::suUpdate() { AsScene1201Match::AsScene1201Match(NeverhoodEngine *vm, Scene *parentScene) : AnimatedSprite(vm, 1100), _parentScene(parentScene), _countdown(0) { - + createSurface(1100, 57, 60); SetUpdateHandler(&AsScene1201Match::update); SetMessageHandler(&AsScene1201Match::hmOnDoorFrameAboutToMove); @@ -518,7 +518,7 @@ AsScene1201Creature::AsScene1201Creature(NeverhoodEngine *vm, Scene *parentScene : AnimatedSprite(vm, 900), _parentScene(parentScene), _klaymen(klaymen), _klaymenTooClose(false) { // NOTE: _countdown2 and _countdown3 were unused/without effect and thus removed - + createSurface(1100, 203, 199); SetUpdateHandler(&AsScene1201Creature::update); SetMessageHandler(&AsScene1201Creature::hmWaiting); @@ -664,7 +664,7 @@ Scene1201::Scene1201(NeverhoodEngine *vm, Module *parentModule, int which) SetMessageHandler(&Scene1201::handleMessage); setHitRects(0x004AEBD0); - + if (!getSubVar(VA_IS_PUZZLE_INIT, 0xE8058B52)) { setSubVar(VA_IS_PUZZLE_INIT, 0xE8058B52, 1); for (uint32 index = 0; index < 18; index++) @@ -672,25 +672,25 @@ Scene1201::Scene1201(NeverhoodEngine *vm, Module *parentModule, int which) } insertScreenMouse(0x9A2C0409); - + _asTape = insertSprite<AsScene1201Tape>(this, 3, 1100, 243, 340, 0x9148A011); addCollisionSprite(_asTape); - + tempSprite = insertStaticSprite(0x03C82530, 100); - topY1 = tempSprite->getY() + tempSprite->getDrawRect().height; + topY1 = tempSprite->getY() + tempSprite->getDrawRect().height; tempSprite = insertStaticSprite(0x88182069, 200); - topY2 = tempSprite->getY() + tempSprite->getDrawRect().height; + topY2 = tempSprite->getY() + tempSprite->getDrawRect().height; tempSprite = insertStaticSprite(0x476014E0, 300); - topY3 = tempSprite->getY() + tempSprite->getDrawRect().height; + topY3 = tempSprite->getY() + tempSprite->getDrawRect().height; tempSprite = insertStaticSprite(0x04063110, 500); - topY4 = tempSprite->getY() + 1; + topY4 = tempSprite->getY() + 1; _asTntManRope = insertSprite<AsScene1201TntManRope>(getGlobalVar(V_TNT_DUMMY_BUILT) && which != 1); _asTntManRope->setClipRect(0, topY4, 640, 480); - + insertStaticSprite(0x400B04B0, 1200); tempSprite = insertStaticSprite(0x40295462, 1200); @@ -735,7 +735,7 @@ Scene1201::Scene1201(NeverhoodEngine *vm, Module *parentModule, int which) _klaymen->setClipRect(x1, 0, x2, 480); _klaymen->setRepl(64, 0); - + if (getGlobalVar(V_CREATURE_ANGRY) && !getGlobalVar(V_CREATURE_EXPLODED)) { setBackground(0x4019A2C4); setPalette(0x4019A2C4); @@ -756,8 +756,8 @@ Scene1201::Scene1201(NeverhoodEngine *vm, Module *parentModule, int which) tempSprite = insertSprite<AsScene1201TntManFlame>(_asTntMan); tempSprite->setClipRect(x1, 0, x2, 480); } - - uint32 tntIndex = 1; + + uint32 tntIndex = 1; while (tntIndex < 18) { uint32 elemIndex = getSubVar(VA_TNT_POSITIONS, tntIndex); int16 clipY2; @@ -783,10 +783,10 @@ Scene1201::Scene1201(NeverhoodEngine *vm, Module *parentModule, int which) setRectList(0x004AEE58); } else { setRectList(0x004AEDC8); - } - + } + } else { - + insertStaticSprite(0x8E8A1981, 900); uint32 tntIndex = 0; @@ -795,7 +795,7 @@ Scene1201::Scene1201(NeverhoodEngine *vm, Module *parentModule, int which) int16 clipY2; if (kScene1201PointArray[elemIndex].x < 300) { clipY2 = 480; - } else { + } else { if (kScene1201PointArray[elemIndex].y < 175) clipY2 = topY1; else if (kScene1201PointArray[elemIndex].y < 230) @@ -811,7 +811,7 @@ Scene1201::Scene1201(NeverhoodEngine *vm, Module *parentModule, int which) setRectList(0x004AEE18); else setRectList(0x004AED88); - + } tempSprite = insertStaticSprite(0x63D400BC, 900); @@ -875,7 +875,7 @@ uint32 Scene1201::handleMessage(int messageNum, const MessageParam ¶m, Entit setMessageList2(0x004AECC0); } break; - case 0x2002: + case 0x2002: if (getGlobalVar(V_TNT_DUMMY_FUSE_LIT)) { // Move the TNT dummy if the fuse is burning sendEntityMessage(_klaymen, 0x1014, _asTntMan); @@ -903,7 +903,7 @@ uint32 Scene1201::handleMessage(int messageNum, const MessageParam ¶m, Entit break; case 0x8000: sendMessage(_asKlaymenHead, 0x2006, 0); - break; + break; } return messageResult; } @@ -956,7 +956,7 @@ uint32 AsScene1202TntItem::hmShowIdle(int messageNum, const MessageParam ¶m, case 0x2001: _newPosition = (int)param.asInteger(); stChangePositionFadeOut(); - break; + break; } return messageResult; } @@ -998,7 +998,7 @@ void AsScene1202TntItem::stChangePositionDone() { } Scene1202::Scene1202(NeverhoodEngine *vm, Module *parentModule) - : Scene(vm, parentModule), _paletteResource(vm), + : Scene(vm, parentModule), _paletteResource(vm), _soundToggle(true), _isPuzzleSolved(false), _counter(0), _clickedIndex(-1) { SetMessageHandler(&Scene1202::handleMessage); @@ -1093,8 +1093,8 @@ uint32 Scene1202::hmSolved(int messageNum, const MessageParam ¶m, Entity *se } bool Scene1202::isSolved() { - return - getSubVar(VA_TNT_POSITIONS, 0) == 0 && getSubVar(VA_TNT_POSITIONS, 3) == 3 && + return + getSubVar(VA_TNT_POSITIONS, 0) == 0 && getSubVar(VA_TNT_POSITIONS, 3) == 3 && getSubVar(VA_TNT_POSITIONS, 6) == 6 && getSubVar(VA_TNT_POSITIONS, 9) == 9 && getSubVar(VA_TNT_POSITIONS, 12) == 12 && getSubVar(VA_TNT_POSITIONS, 15) == 15; } diff --git a/engines/neverhood/modules/module1300.cpp b/engines/neverhood/modules/module1300.cpp index 8dbfcf616c..c8a561af76 100644 --- a/engines/neverhood/modules/module1300.cpp +++ b/engines/neverhood/modules/module1300.cpp @@ -45,7 +45,7 @@ static const uint32 kModule1300SoundList[] = { Module1300::Module1300(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - + _vm->_soundMan->addMusic(0x61C090, 0x00203197); _vm->_soundMan->addSoundList(0x61C090, kModule1300SoundList); _vm->_soundMan->setSoundListParams(kModule1300SoundList, false, 50, 600, 20, 150); @@ -56,7 +56,7 @@ Module1300::Module1300(NeverhoodEngine *vm, Module *parentModule, int which) if (which < 0) { if (_vm->gameState().sceneNum >= 1 && _vm->gameState().sceneNum <= 17) createScene(_vm->gameState().sceneNum, -1); - else + else createScene(11, 0); } else { switch (which) { @@ -101,7 +101,7 @@ Module1300::Module1300(NeverhoodEngine *vm, Module *parentModule, int which) break; } } - + } Module1300::~Module1300() { @@ -109,7 +109,7 @@ Module1300::~Module1300() { } void Module1300::createScene(int sceneNum, int which) { - debug("Module1300::createScene(%d, %d)", sceneNum, which); + debug(1, "Module1300::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 1: @@ -218,7 +218,7 @@ void Module1300::createScene(int sceneNum, int which) { SetUpdateHandler(&Module1300::updateScene); _childObject->handleUpdate(); } - + void Module1300::updateScene() { if (!updateChild()) { switch (_sceneNum) { @@ -274,7 +274,7 @@ void Module1300::updateScene() { createScene(11, 1); break; case 12: - if (_moduleResult == 0) + if (_moduleResult == 0) createScene(14, 1); else if (_moduleResult == 1) createScene(15, 1); @@ -367,7 +367,7 @@ void AsScene1302Bridge::cbLowerBridgeEvent() { SsScene1302Fence::SsScene1302Fence(NeverhoodEngine *vm) : StaticSprite(vm, 0x11122122, 200) { - + _firstY = _y; if (getGlobalVar(V_FLYTRAP_RING_FENCE)) _y += 152; @@ -459,7 +459,7 @@ Scene1302::Scene1302(NeverhoodEngine *vm, Module *parentModule, int which) addCollisionSprite(_asVenusFlyTrap); sendEntityMessage(_klaymen, 0x2007, _asVenusFlyTrap); - + } uint32 Scene1302::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -513,7 +513,7 @@ uint32 Scene1302::handleMessage(int messageNum, const MessageParam ¶m, Entit case 0x2000: if (_klaymen->getY() > 360) { sendEntityMessage(_klaymen, 0x1014, _asVenusFlyTrap); - setMessageList2(0x004B08F0); + setMessageList2(0x004B08F0); } else setMessageList2(0x004B0920); break; @@ -583,7 +583,7 @@ uint32 Scene1302::handleMessage(int messageNum, const MessageParam ¶m, Entit AsScene1303Balloon::AsScene1303Balloon(NeverhoodEngine *vm, Scene *parentScene) : AnimatedSprite(vm, 1100), _parentScene(parentScene) { - + createSurface(200, 128, 315); _x = 289; _y = 390; @@ -643,7 +643,7 @@ Scene1303::Scene1303(NeverhoodEngine *vm, Module *parentModule) _asBalloon = insertSprite<AsScene1303Balloon>(this); addCollisionSprite(_asBalloon); } - + _sprite1 = insertStaticSprite(0xA014216B, 1100); insertKlaymen<KmScene1303>(207, 332); @@ -671,7 +671,7 @@ uint32 Scene1303::handleMessage(int messageNum, const MessageParam ¶m, Entit AsScene1304Needle::AsScene1304Needle(NeverhoodEngine *vm, Scene *parentScene, int surfacePriority, int16 x, int16 y) : AnimatedSprite(vm, 0x548E9411, surfacePriority, x, y), _parentScene(parentScene) { - // NOTE: Skipped check if Klaymen already has the needle since that's done in the scene itself + // NOTE: Skipped check if Klaymen already has the needle since that's done in the scene itself SetMessageHandler(&AsScene1304Needle::handleMessage); } @@ -693,14 +693,14 @@ uint32 AsScene1304Needle::handleMessage(int messageNum, const MessageParam ¶ Scene1304::Scene1304(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _asNeedle(NULL) { - + SetMessageHandler(&Scene1304::handleMessage); setRectList(0x004B91A8); setBackground(0x062C0214); setPalette(0x062C0214); insertScreenMouse(0xC021006A); - + if (getGlobalVar(V_BALLOON_POPPED)) { _asKey = insertSprite<AsCommonKey>(this, 0, 1100, 278, 347); addCollisionSprite(_asKey); @@ -774,7 +774,7 @@ Scene1305::Scene1305(NeverhoodEngine *vm, Module *parentModule, int which) insertKlaymen<KmScene1305>(212, 441); setMessageList(0x004B6E48); } - + } uint32 Scene1305::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -800,7 +800,7 @@ void AsScene1306Elevator::update() { if (_isUp && _countdown != 0 && (--_countdown == 0)) stGoingDown(); AnimatedSprite::update(); - if (_currFrameIndex == 7) { + if (_currFrameIndex == 7 && _asElevatorDoor->getVisible()) { playSound(1); _asElevatorDoor->setVisible(false); } @@ -868,10 +868,10 @@ void AsScene1306Elevator::cbGoingDownEvent() { Scene1306::Scene1306(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { - + if (getGlobalVar(V_HAS_FINAL_KEY) && getGlobalVar(V_KEY3_LOCATION) == 0) setGlobalVar(V_KEY3_LOCATION, 4); - + SetMessageHandler(&Scene1306::handleMessage); setBackground(0x05303114); @@ -949,7 +949,7 @@ Scene1306::Scene1306(NeverhoodEngine *vm, Module *parentModule, int which) } } - + Scene1306::~Scene1306() { setGlobalVar(V_KLAYMEN_IS_DELTA_X, _klaymen->isDoDeltaX() ? 1 : 0); } @@ -1073,7 +1073,7 @@ static const NPoint kAsScene1307KeyPoints[] = { const uint kAsScene1307KeyFrameIndicesCount = 20; static const int16 kAsScene1307KeyFrameIndices[] = { - 1, 4, 8, 11, 15, 16, 17, 17, 17, 16, + 1, 4, 8, 11, 15, 16, 17, 17, 17, 16, 15, 14, 12, 10, 9, 7, 5, 3, 2, 1 }; @@ -1084,10 +1084,10 @@ const int16 kAsScene1307KeyYDelta = -12; AsScene1307Key::AsScene1307Key(NeverhoodEngine *vm, Scene *parentScene, uint keyIndex, NRect *clipRects) : AnimatedSprite(vm, 1100), _parentScene(parentScene), _keyIndex(keyIndex), _clipRects(clipRects), _isClickable(true) { - + NPoint pt; - const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; - + const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; + _dataResource.load(0x22102142); _pointList = _dataResource.getPointArray(0xAC849240); pt = (*_pointList)[getSubVar(VA_CURR_KEY_SLOT_NUMBERS, _keyIndex)]; @@ -1173,7 +1173,7 @@ void AsScene1307Key::suMoveKey() { } void AsScene1307Key::stRemoveKey() { - const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; + const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; _pointIndex = 0; startAnimation(fileHashes[0], 0, -1); playSound(1); @@ -1199,7 +1199,7 @@ void AsScene1307Key::stMoveKey() { if (newX == _x && newY == _y) { stInsertKey(); } else { - const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; + const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; _pointIndex = 0; _frameIndex = 0; _deltaX = newX - _x; @@ -1210,13 +1210,13 @@ void AsScene1307Key::stMoveKey() { } void AsScene1307Key::stUnlock() { - const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; + const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; startAnimation(fileHashes[1], 0, -1); _newStickFrameIndex = STICK_LAST_FRAME; } void AsScene1307Key::stInsert() { - const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; + const uint32 *fileHashes = kAsScene1307KeyResourceLists[_keyIndex]; startAnimation(fileHashes[2], 0, -1); _newStickFrameIndex = STICK_LAST_FRAME; } @@ -1226,9 +1226,9 @@ Scene1307::Scene1307(NeverhoodEngine *vm, Module *parentModule) _isInsertingKey(false), _doLeaveScene(false), _isPuzzleSolved(false) { Sprite *tempSprite; - + _vm->gameModule()->initKeySlotsPuzzle(); - + _dataResource.load(0x22102142); _keyHolePoints = _dataResource.getPointArray(0xAC849240); @@ -1279,7 +1279,7 @@ void Scene1307::update() { if (_doLeaveScene && !isSoundPlaying(0)) { leaveScene(1); setGlobalVar(V_KEYDOOR_UNLOCKED, 1); - } + } } uint32 Scene1307::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -1294,7 +1294,7 @@ uint32 Scene1307::handleMessage(int messageNum, const MessageParam ¶m, Entit int16 mouseY = param.asPoint().y; uint clickedKeyHoleIndex; for (clickedKeyHoleIndex = 0; clickedKeyHoleIndex < 16; clickedKeyHoleIndex++) { - if (mouseX >= _keyHoleRects[clickedKeyHoleIndex].x1 && mouseX <= _keyHoleRects[clickedKeyHoleIndex].x2 && + if (mouseX >= _keyHoleRects[clickedKeyHoleIndex].x1 && mouseX <= _keyHoleRects[clickedKeyHoleIndex].x2 && mouseY >= _keyHoleRects[clickedKeyHoleIndex].y1 && mouseY <= _keyHoleRects[clickedKeyHoleIndex].y2) break; } @@ -1362,7 +1362,7 @@ static const uint32 kScene1308NumberFileHashes[] = { AsScene1308JaggyDoor::AsScene1308JaggyDoor(NeverhoodEngine *vm, Scene *parentScene) : AnimatedSprite(vm, 0xBA0AE050, 1100, 320, 240), _parentScene(parentScene) { - + setVisible(false); stopAnimation(); SetMessageHandler(&AsScene1308JaggyDoor::handleMessage); @@ -1412,12 +1412,12 @@ void AsScene1308JaggyDoor::stCloseDoorDone() { AsScene1308KeyboardDoor::AsScene1308KeyboardDoor(NeverhoodEngine *vm, Scene *parentScene) : AnimatedSprite(vm, 0xA08A0851, 1100, 320, 240), _parentScene(parentScene) { - + playSound(0, 0x51456049); SetMessageHandler(&AsScene1308KeyboardDoor::handleMessage); NextState(&AsScene1308KeyboardDoor::stFallingKeys); } - + uint32 AsScene1308KeyboardDoor::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); switch (messageNum) { @@ -1443,7 +1443,7 @@ void AsScene1308KeyboardDoor::stFallingKeysDone() { AsScene1308LightWallSymbols::AsScene1308LightWallSymbols(NeverhoodEngine *vm, Scene *parentScene) : AnimatedSprite(vm, 0x80180A10, 100, 320, 240), _parentScene(parentScene) { - + setVisible(false); stopAnimation(); Entity::_priority = 1200; @@ -1486,7 +1486,7 @@ void AsScene1308LightWallSymbols::stFadeOutDone() { SsScene1308Number::SsScene1308Number(NeverhoodEngine *vm, uint32 fileHash, int index) : StaticSprite(vm, fileHash, 100) { - + setVisible(false); _x = _spriteResource.getPosition().x + index * 20; updatePosition(); @@ -1520,11 +1520,11 @@ uint32 AsScene1308Mouse::handleMessage(int messageNum, const MessageParam ¶m Scene1308::Scene1308(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _isProjecting(false), _asProjector(NULL) { - + _vm->gameModule()->initKeySlotsPuzzle(); SetMessageHandler(&Scene1308::handleMessage); - + setBackground(0x41024202); setPalette(0x41024202); insertScreenMouse(0x24206418); @@ -1536,7 +1536,7 @@ Scene1308::Scene1308(NeverhoodEngine *vm, Module *parentModule, int which) insertSprite<AsScene1308Mouse>(); insertSprite<AnimatedSprite>(0x461A1490, 200, 235, 429); } - + _sprite1 = insertStaticSprite(0x0A042060, 1100); _asJaggyDoor = insertSprite<AsScene1308JaggyDoor>(this); _asLightWallSymbols = insertSprite<AsScene1308LightWallSymbols>(this); @@ -1546,7 +1546,7 @@ Scene1308::Scene1308(NeverhoodEngine *vm, Module *parentModule, int which) _sprite2 = insertStaticSprite(0x40043120, 995); _sprite3 = insertStaticSprite(0x43003100, 995); _sprite4 = NULL; - + if (which < 0) { // Restoring game insertKlaymen<KmScene1308>(380, 440); @@ -1698,7 +1698,7 @@ uint32 Scene1308::handleMessage(int messageNum, const MessageParam ¶m, Entit Scene1317::Scene1317(NeverhoodEngine *vm, Module *parentModule) : Scene(vm, parentModule) { - + SetMessageHandler(&Scene1317::handleMessage); _smackerPlayer = addSmackerPlayer(new SmackerPlayer(_vm, this, 0x08982841, true, false)); _vm->_screen->setSmackerDecoder(_smackerPlayer->getSmackerDecoder()); @@ -1711,6 +1711,7 @@ Scene1317::Scene1317(NeverhoodEngine *vm, Module *parentModule) void Scene1317::update() { if (_smackerFileHash) { _smackerPlayer->open(_smackerFileHash, _keepLastSmackerFrame); + _vm->_screen->setSmackerDecoder(_smackerPlayer->getSmackerDecoder()); _smackerFileHash = 0; } Scene::update(); @@ -1719,7 +1720,7 @@ void Scene1317::update() { void Scene1317::upChooseKing() { if (!_klaymenBlinks && _klaymenBlinkCountdown != 0 && (--_klaymenBlinkCountdown == 0)) _klaymenBlinks = true; - + if (!_klaymenBlinks && _smackerPlayer->getFrameNumber() + 1 >= 2) { _smackerPlayer->rewind(); } else if (_klaymenBlinks && _smackerPlayer->getFrameNumber() + 1 >= 6) { @@ -1730,14 +1731,15 @@ void Scene1317::upChooseKing() { if (!_klaymenBlinks && _decisionCountdown != 0 && (--_decisionCountdown == 0)) stNoDecisionYet(); - + if (_smackerFileHash) { _smackerPlayer->open(_smackerFileHash, _keepLastSmackerFrame); + _vm->_screen->setSmackerDecoder(_smackerPlayer->getSmackerDecoder()); _smackerFileHash = 0; } Scene::update(); - + } uint32 Scene1317::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -1749,7 +1751,7 @@ uint32 Scene1317::handleMessage(int messageNum, const MessageParam ¶m, Entit } return messageResult; } - + uint32 Scene1317::hmChooseKing(int messageNum, const MessageParam ¶m, Entity *sender) { uint32 messageResult = Scene::handleMessage(messageNum, param, sender); switch (messageNum) { diff --git a/engines/neverhood/modules/module1400.cpp b/engines/neverhood/modules/module1400.cpp index 4f69637ee0..0a029632b6 100644 --- a/engines/neverhood/modules/module1400.cpp +++ b/engines/neverhood/modules/module1400.cpp @@ -31,7 +31,7 @@ namespace Neverhood { Module1400::Module1400(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - + _vm->_soundMan->addMusic(0x00AD0012, 0x06333232); _vm->_soundMan->addMusic(0x00AD0012, 0x624A220E); @@ -47,7 +47,7 @@ Module1400::~Module1400() { } void Module1400::createScene(int sceneNum, int which) { - debug("Module1400::createScene(%d, %d)", sceneNum, which); + debug(1, "Module1400::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -139,7 +139,7 @@ void Module1400::updateScene() { AsScene1401Pipe::AsScene1401Pipe(NeverhoodEngine *vm) : AnimatedSprite(vm, 1100), _countdown1(0), _countdown2(0) { - + createSurface(900, 152, 147); _x = 454; _y = 217; @@ -179,10 +179,10 @@ uint32 AsScene1401Pipe::handleMessage(int messageNum, const MessageParam ¶m, _countdown1 = 70; _countdown2 = 8; stStartSucking(); - break; + break; case 0x483A: stSuckInProjector(); - break; + break; } return messageResult; } @@ -221,7 +221,7 @@ void AsScene1401Pipe::stSuckInProjector() { AsScene1401Mouse::AsScene1401Mouse(NeverhoodEngine *vm) : AnimatedSprite(vm, 1100) { - + createSurface(100, 71, 41); _x = 478; _y = 433; @@ -243,7 +243,7 @@ uint32 AsScene1401Mouse::handleMessage(int messageNum, const MessageParam ¶m break; case 0x4839: stSuckedIn(); - break; + break; } return messageResult; } @@ -280,7 +280,7 @@ uint32 AsScene1401Cheese::handleMessage(int messageNum, const MessageParam ¶ switch (messageNum) { case 0x4839: stSuckedIn(); - break; + break; } return messageResult; } @@ -332,7 +332,7 @@ uint32 AsScene1401BackDoor::handleMessage(int messageNum, const MessageParam &pa case 0x2001: if (_isOpen) _countdown = 168; - messageResult = _isOpen ? 1 : 0; + messageResult = _isOpen ? 1 : 0; break; case 0x3002: gotoNextState(); @@ -341,7 +341,7 @@ uint32 AsScene1401BackDoor::handleMessage(int messageNum, const MessageParam &pa _countdown = 168; if (!_isOpen) stOpenDoor(); - break; + break; } return messageResult; } @@ -540,7 +540,7 @@ void AsCommonProjector::moveProjector() { playSound(1, 0x5440E474); _lockedInSlot = true; } - + } void AsCommonProjector::stSuckedIn() { @@ -627,8 +627,8 @@ void AsCommonProjector::stStartSuckedIn() { } Scene1401::Scene1401(NeverhoodEngine *vm, Module *parentModule, int which) - : Scene(vm, parentModule), _projectorBorderFlag(false), _ssFloorButton(NULL), _asProjector(NULL), - _asPipe(NULL), _asMouse(NULL), _asCheese(NULL), _asBackDoor(NULL), + : Scene(vm, parentModule), _projectorBorderFlag(false), _ssFloorButton(NULL), _asProjector(NULL), + _asPipe(NULL), _asMouse(NULL), _asCheese(NULL), _asBackDoor(NULL), _sprite1(NULL), _sprite2(NULL), _sprite3(NULL), _ssButton(NULL) { SetMessageHandler(&Scene1401::handleMessage); @@ -638,7 +638,7 @@ Scene1401::Scene1401(NeverhoodEngine *vm, Module *parentModule, int which) setBackground(0x08221FA5); setPalette(0x08221FA5); insertScreenMouse(0x21FA108A); - + _ssFloorButton = insertSprite<SsCommonFloorButton>(this, 0x980F3124, 0x12192892, 100, 0); _asPipe = insertSprite<AsScene1401Pipe>(); @@ -692,7 +692,7 @@ Scene1401::Scene1401(NeverhoodEngine *vm, Module *parentModule, int which) } _asProjector->setClipRect(_sprite3->getDrawRect().x, _sprite2->getDrawRect().y, 640, 480); } - + _klaymen->setClipRect(_sprite3->getDrawRect().x, 0, 640, 480); if (which == 0 && _asProjector) @@ -752,7 +752,7 @@ uint32 Scene1401::handleMessage(int messageNum, const MessageParam ¶m, Entit setMessageList2(0x004B6658); } else setMessageList2(0x004B65F0); - } + } break; case 0x482A: _sprite1->setVisible(true); @@ -772,7 +772,7 @@ uint32 Scene1401::handleMessage(int messageNum, const MessageParam ¶m, Entit SsScene1402BridgePart::SsScene1402BridgePart(NeverhoodEngine *vm, uint32 fileHash, int surfacePriority) : StaticSprite(vm, fileHash, surfacePriority) { - + SetFilterY(&Sprite::defFilterY); SetUpdateHandler(&StaticSprite::updatePosition); } @@ -892,7 +892,7 @@ Scene1402::Scene1402(NeverhoodEngine *vm, Module *parentModule, int which) startShaking(); } } - + if (_asPuzzleBox) _asPuzzleBox->setClipRect(0, 0, 640, _ssBridgePart3->getDrawRect().y2()); @@ -914,7 +914,7 @@ Scene1402::Scene1402(NeverhoodEngine *vm, Module *parentModule, int which) } _klaymen->setClipRect(_ssBridgePart1->getDrawRect().x, 0, _ssBridgePart2->getDrawRect().x2(), _ssBridgePart3->getDrawRect().y2()); - + } void Scene1402::upShaking() { @@ -1082,7 +1082,7 @@ static const struct { AsScene1407Mouse::AsScene1407Mouse(NeverhoodEngine *vm, Scene *parentScene) : AnimatedSprite(vm, 1100), _parentScene(parentScene), _currSectionIndex(0) { - + createSurface(100, 117, 45); _x = 108; _y = 106; @@ -1096,7 +1096,7 @@ void AsScene1407Mouse::suWalkTo() { xdelta = _deltaX; else if (xdelta < -_deltaX) xdelta = -_deltaX; - _deltaX = 0; + _deltaX = 0; if (_walkDestX == _x) sendMessage(this, 0x1019, 0); else { @@ -1231,7 +1231,7 @@ Scene1407::Scene1407(NeverhoodEngine *vm, Module *parentModule) _asMouse = insertSprite<AsScene1407Mouse>(this); _ssResetButton = insertStaticSprite(0x12006600, 100); - _ssResetButton->setVisible(false); + _ssResetButton->setVisible(false); } @@ -1279,9 +1279,9 @@ uint32 Scene1407::handleMessage(int messageNum, const MessageParam ¶m, Entit Scene1403::Scene1403(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _asProjector(NULL), _isProjecting(false) { - + SetMessageHandler(&Scene1403::handleMessage); - + setRectList(0x004B1FF8); setBackground(0x2110A234); setPalette(0x2110A234); @@ -1383,10 +1383,10 @@ uint32 Scene1403::handleMessage(int messageNum, const MessageParam ¶m, Entit Scene1404::Scene1404(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _asProjector(NULL), _asKey(NULL) { - + if (getGlobalVar(V_HAS_FINAL_KEY) && getGlobalVar(V_KEY3_LOCATION) == 0) setGlobalVar(V_KEY3_LOCATION, 5); - + SetMessageHandler(&Scene1404::handleMessage); setRectList(0x004B8D80); @@ -1555,14 +1555,14 @@ Scene1405::Scene1405(NeverhoodEngine *vm, Module *parentModule) : Scene(vm, parentModule), _selectFirstTile(true), _tilesLeft(48), _countdown(0) { _vm->gameModule()->initMemoryPuzzle(); - + SetUpdateHandler(&Scene1405::update); SetMessageHandler(&Scene1405::handleMessage); setBackground(0x0C0C007D); setPalette(0x0C0C007D); insertPuzzleMouse(0xC00790C8, 20, 620); - + for (uint32 tileIndex = 0; tileIndex < 48; tileIndex++) { _tiles[tileIndex] = insertSprite<AsScene1405Tile>(this, tileIndex); addCollisionSprite(_tiles[tileIndex]); diff --git a/engines/neverhood/modules/module1500.cpp b/engines/neverhood/modules/module1500.cpp index 2a9597b1fd..3ce9783b69 100644 --- a/engines/neverhood/modules/module1500.cpp +++ b/engines/neverhood/modules/module1500.cpp @@ -26,7 +26,7 @@ namespace Neverhood { Module1500::Module1500(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - + if (which < 0) createScene(_vm->gameState().sceneNum, -1); else @@ -35,7 +35,7 @@ Module1500::Module1500(NeverhoodEngine *vm, Module *parentModule, int which) } void Module1500::createScene(int sceneNum, int which) { - debug("Module1500::createScene(%d, %d)", sceneNum, which); + debug(1, "Module1500::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -86,7 +86,7 @@ Scene1501::Scene1501(NeverhoodEngine *vm, Module *parentModule, uint32 backgroun SetUpdateHandler(&Scene1501::update); SetMessageHandler(&Scene1501::handleMessage); - + setBackground(backgroundFileHash); setPalette(); addEntity(_palette); @@ -118,7 +118,7 @@ void Scene1501::update() { _countdown1 = 12; _palette->startFadeToBlack(11); } - + } uint32 Scene1501::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { diff --git a/engines/neverhood/modules/module1600.cpp b/engines/neverhood/modules/module1600.cpp index f7e3c37d84..a5a785e130 100644 --- a/engines/neverhood/modules/module1600.cpp +++ b/engines/neverhood/modules/module1600.cpp @@ -34,7 +34,7 @@ static const uint32 kModule1600SoundList[] = { Module1600::Module1600(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - + if (which < 0) createScene(_vm->gameState().sceneNum, -1); else if (which == 1) @@ -59,7 +59,7 @@ Module1600::~Module1600() { } void Module1600::createScene(int sceneNum, int which) { - debug("Module1600::createScene(%d, %d)", sceneNum, which); + debug(1, "Module1600::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -109,7 +109,7 @@ void Module1600::createScene(int sceneNum, int which) { if (getGlobalVar(V_TALK_COUNTING_INDEX) >= 2) setGlobalVar(V_TALK_COUNTING_INDEX, 0); else - incGlobalVar(V_TALK_COUNTING_INDEX, +1); + incGlobalVar(V_TALK_COUNTING_INDEX, +1); break; } SetUpdateHandler(&Module1600::updateScene); @@ -185,11 +185,11 @@ void Module1600::updateScene() { AsCommonCar::AsCommonCar(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : AnimatedSprite(vm, 1000), _parentScene(parentScene) { - + createSurface(200, 556, 328); _x = x; _y = y; - + _inMainArea = false; _exitDirection = 0; _currPointIndex = 0; @@ -207,7 +207,7 @@ AsCommonCar::AsCommonCar(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 _soundCounter = 0; _pathPoints = NULL; _currMoveDirection = 0; - + startAnimation(0xD4220027, 0, -1); setDoDeltaX(getGlobalVar(V_CAR_DELTA_X)); @@ -517,7 +517,7 @@ void AsCommonCar::moveToNextPoint() { if (ABS(nextPt.y - currPt.y) <= ABS(nextPt.x - currPt.x) && ((_currMoveDirection == 2 && nextPt.x < currPt.x) || (_currMoveDirection == 4 && nextPt.x >= currPt.x))) { - if (_currMoveDirection == 2) + if (_currMoveDirection == 2) _currMoveDirection = 4; else if (_currMoveDirection == 4) _currMoveDirection = 2; @@ -605,7 +605,7 @@ void AsCommonCar::moveToPrevPoint() { if (ABS(prevPt.y - currPt.y) <= ABS(prevPt.x - currPt.x) && ((_currMoveDirection == 2 && prevPt.x < currPt.x) || (_currMoveDirection == 4 && prevPt.x >= currPt.x))) { - if (_currMoveDirection == 2) + if (_currMoveDirection == 2) _currMoveDirection = 4; else if (_currMoveDirection == 4) _currMoveDirection = 2; @@ -668,7 +668,7 @@ void AsCommonCar::suMoveToNextPoint() { bool firstTime = true; _ySteps = _steps; int stepsCtr = _steps; - + while (stepsCtr > 0) { NPoint pt1; NPoint pt2 = pathPoint(_currPointIndex); @@ -739,7 +739,7 @@ void AsCommonCar::suMoveToNextPoint() { stepsCtr = 0; } } - firstTime = false; + firstTime = false; } if (_yMoveTotalSteps != 0) { @@ -811,7 +811,7 @@ void AsCommonCar::suMoveToPrevPoint() { bool firstTime = true; _ySteps = _steps; int stepsCtr = _steps; - + while (stepsCtr > 0) { if (_stepError == 0) _currPointIndex--; @@ -884,7 +884,7 @@ void AsCommonCar::suMoveToPrevPoint() { stepsCtr = 0; } } - firstTime = false; + firstTime = false; } if (_yMoveTotalSteps != 0) { @@ -971,7 +971,7 @@ AsCommonIdleCarFull::AsCommonIdleCarFull(NeverhoodEngine *vm, int16 x, int16 y) AsCommonCarConnector::AsCommonCarConnector(NeverhoodEngine *vm, AsCommonCar *asCar) : AnimatedSprite(vm, 1100), _asCar(asCar) { - + createSurface1(0x60281C10, 150); startAnimation(0x60281C10, -1, -1); _newStickFrameIndex = STICK_LAST_FRAME; @@ -1006,9 +1006,9 @@ Scene1608::Scene1608(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _asCar(NULL), _countdown1(0) { setGlobalVar(V_CAR_DELTA_X, 1); - + SetMessageHandler(&Scene1608::hmLowerFloor); - + _asKey = insertSprite<AsCommonKey>(this, 1, 1100, 198, 220); addCollisionSprite(_asKey); @@ -1092,9 +1092,9 @@ Scene1608::Scene1608(NeverhoodEngine *vm, Module *parentModule, int which) _carClipFlag = false; _carStatus = 0; setRectList(0x004B4810); - } + } - // NOTE: Not in the else because 'which' is set to 1 in the true branch + // NOTE: Not in the else because 'which' is set to 1 in the true branch if (which == 1) { // Klaymen riding the car _vm->gameState().which = 1; @@ -1134,9 +1134,9 @@ Scene1608::Scene1608(NeverhoodEngine *vm, Module *parentModule, int which) _carClipFlag = true; _carStatus = 0; } - + _palette->addPalette("paKlayRed", 0, 64, 0); - + } Scene1608::~Scene1608() { @@ -1308,7 +1308,7 @@ uint32 Scene1608::hmCarAtHome(int messageNum, const MessageParam ¶m, Entity } return 0; } - + void Scene1608::updateKlaymenCliprect() { if (_kmScene1608->getX() <= 375) _kmScene1608->setClipRect(_clipRect1); @@ -1321,17 +1321,17 @@ Scene1609::Scene1609(NeverhoodEngine *vm, Module *parentModule) _vm->gameModule()->initCodeSymbolsPuzzle(); _noisySymbolIndex = getGlobalVar(V_NOISY_SYMBOL_INDEX); - + SetMessageHandler(&Scene1609::handleMessage); SetUpdateHandler(&Scene1609::update); - + setBackground(0x92124A14); setPalette(0x92124A14); insertPuzzleMouse(0x24A10929, 20, 620); - + for (int symbolPosition = 0; symbolPosition < 12; symbolPosition++) _asSymbols[symbolPosition] = insertSprite<AsScene3011Symbol>(symbolPosition, false); - + _ssButton = insertSprite<SsScene3011Button>(this, true); addCollisionSprite(_ssButton); loadSound(0, 0x68E25540); @@ -1408,5 +1408,5 @@ bool Scene1609::testVars() { return true; } - + } // End of namespace Neverhood diff --git a/engines/neverhood/modules/module1600.h b/engines/neverhood/modules/module1600.h index 0bf44ff7b8..5f0da528ab 100644 --- a/engines/neverhood/modules/module1600.h +++ b/engines/neverhood/modules/module1600.h @@ -26,6 +26,7 @@ #include "neverhood/neverhood.h" #include "neverhood/module.h" #include "neverhood/scene.h" +#include "neverhood/console.h" #include "neverhood/modules/module3000.h" namespace Neverhood { @@ -162,6 +163,7 @@ protected: }; class Scene1609 : public Scene { + friend class Console; public: Scene1609(NeverhoodEngine *vm, Module *parentModule); protected: diff --git a/engines/neverhood/modules/module1700.cpp b/engines/neverhood/modules/module1700.cpp index 3a6d1f80cb..2aeae466ff 100644 --- a/engines/neverhood/modules/module1700.cpp +++ b/engines/neverhood/modules/module1700.cpp @@ -36,7 +36,7 @@ static const uint32 kModule1700SoundList[] = { Module1700::Module1700(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - + _vm->_soundMan->addMusic(0x04212331, 0x31114225); _vm->_soundMan->addSoundList(0x04212331, kModule1700SoundList); _vm->_soundMan->setSoundListParams(kModule1700SoundList, true, 50, 600, 5, 150); @@ -58,7 +58,7 @@ Module1700::~Module1700() { } void Module1700::createScene(int sceneNum, int which) { - debug("Module1700::createScene(%d, %d)", sceneNum, which); + debug(1, "Module1700::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -125,7 +125,7 @@ void Module1700::updateScene() { } } } - + // Scene1705 static const uint32 kScene1705FileHashes[] = { @@ -137,7 +137,7 @@ static const uint32 kScene1705FileHashes[] = { SsScene1705WallSymbol::SsScene1705WallSymbol(NeverhoodEngine *vm, uint32 fileHash, int symbolIndex) : StaticSprite(vm, fileHash, 100) { - + _x = _spriteResource.getPosition().x + symbolIndex * 30; _y = _spriteResource.getPosition().y + 160; updatePosition(); @@ -171,7 +171,7 @@ uint32 SsScene1705Tape::handleMessage(int messageNum, const MessageParam ¶m, setSubVar(VA_HAS_TAPE, _tapeIndex, 1); setVisible(false); SetMessageHandler(NULL); - break; + break; } return messageResult; } @@ -180,7 +180,7 @@ Scene1705::Scene1705(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _paletteArea(1) { Sprite *tempSprite; - + setGlobalVar(V_FELL_DOWN_HOLE, 1); _vm->gameModule()->initCannonSymbolsPuzzle(); @@ -271,7 +271,7 @@ uint32 Scene1705::handleMessage(int messageNum, const MessageParam ¶m, Entit sendEntityMessage(_klaymen, 0x1014, sender); setMessageList(0x004B6AC0); } - break; + break; } return 0; } diff --git a/engines/neverhood/modules/module1700.h b/engines/neverhood/modules/module1700.h index f57c411a18..deb5573f2b 100644 --- a/engines/neverhood/modules/module1700.h +++ b/engines/neverhood/modules/module1700.h @@ -50,7 +50,7 @@ public: class SsScene1705Tape : public StaticSprite { public: SsScene1705Tape(NeverhoodEngine *vm, Scene *parentScene, uint32 tapeIndex, int surfacePriority, int16 x, int16 y, uint32 fileHash); -protected: +protected: Scene *_parentScene; uint32 _tapeIndex; uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); diff --git a/engines/neverhood/modules/module1800.cpp b/engines/neverhood/modules/module1800.cpp index 2a6057f9c8..b312678467 100644 --- a/engines/neverhood/modules/module1800.cpp +++ b/engines/neverhood/modules/module1800.cpp @@ -38,7 +38,7 @@ static const uint32 kModule1800SoundList[] = { Module1800::Module1800(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - + _vm->_soundMan->addSoundList(0x04A14718, kModule1800SoundList); _vm->_soundMan->setSoundListParams(kModule1800SoundList, true, 50, 600, 10, 150); _vm->_soundMan->playTwoSounds(0x04A14718, 0x8A382B55, 0x0C242F1D, 0); @@ -61,7 +61,7 @@ Module1800::~Module1800() { void Module1800::createScene(int sceneNum, int which) { static const byte kNavigationTypes00[] = {1, 0, 2, 0}; static const byte kNavigationTypes01[] = {5}; - debug("Module1800::createScene(%d, %d)", sceneNum, which); + debug(1, "Module1800::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -177,5 +177,5 @@ void Module1800::updateScene() { } } } - + } // End of namespace Neverhood diff --git a/engines/neverhood/modules/module1900.cpp b/engines/neverhood/modules/module1900.cpp index 1a9ffa127b..29c20083f9 100644 --- a/engines/neverhood/modules/module1900.cpp +++ b/engines/neverhood/modules/module1900.cpp @@ -35,8 +35,8 @@ static const uint32 kModule1900SoundList[] = { Module1900::Module1900(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - // NOTE: The original has a Scene1908 here as well but it's not used here but in another module... - + // NOTE: The original has a Scene1908 here as well but it's not used here but in another module... + if (which < 0) createScene(_vm->gameState().sceneNum, -1); else @@ -52,7 +52,7 @@ Module1900::~Module1900() { } void Module1900::createScene(int sceneNum, int which) { - debug("Module1900::createScene(%d, %d)", sceneNum, which); + debug(1, "Module1900::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -88,7 +88,7 @@ void Module1900::updateScene() { Scene1901::Scene1901(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { - + Sprite *tempSprite; setRectList(0x004B34C8); @@ -98,7 +98,7 @@ Scene1901::Scene1901(NeverhoodEngine *vm, Module *parentModule, int which) insertScreenMouse(0x0322301B); insertStaticSprite(0x42213133, 1100); - + if (!getGlobalVar(V_STAIRS_PUZZLE_SOLVED)) insertStaticSprite(0x40A40168, 100); else if (getGlobalVar(V_STAIRS_DOWN)) { @@ -132,16 +132,16 @@ static const NPoint kAsScene1907SymbolGroundPositions[] = { {400, 375}, {370, 435}, {475, 415} }; -static const NPoint kAsScene1907SymbolPluggedInPositions[] = { +static const NPoint kAsScene1907SymbolPluggedInPositions[] = { {275, 125}, {244, 125}, {238, 131}, {221, 135}, {199, 136}, {168, 149}, {145, 152}, {123, 154}, {103, 157} }; static const NPoint kAsScene1907SymbolGroundHitPositions[] = { - {275, 299}, {244, 299}, {238, 305}, - {221, 309}, {199, 310}, {168, 323}, - {145, 326}, {123, 328}, {103, 331} + {275, 299}, {244, 299}, {238, 305}, + {221, 309}, {199, 310}, {168, 323}, + {145, 326}, {123, 328}, {103, 331} }; static const NPoint kAsScene1907SymbolPluggedInDownPositions[] = { @@ -164,7 +164,7 @@ AsScene1907Symbol::AsScene1907Symbol(NeverhoodEngine *vm, Scene1907 *parentScene _plugInFailed = false; _plugInTryCount = 0; - + if (getGlobalVar(V_STAIRS_PUZZLE_SOLVED)) { _isPluggedIn = true; _currPositionIndex = elementIndex; @@ -289,7 +289,7 @@ void AsScene1907Symbol::suMoveDown() { _y = kAsScene1907SymbolPluggedInDownPositions[_elementIndex].y; _isMoving = false; SetSpriteUpdate(NULL); - } + } } void AsScene1907Symbol::suMoveUp() { @@ -423,7 +423,7 @@ void AsScene1907Symbol::moveDown() { SsScene1907UpDownButton::SsScene1907UpDownButton(NeverhoodEngine *vm, Scene1907 *parentScene, AsScene1907Symbol *asScene1907Symbol) : StaticSprite(vm, 1400), _parentScene(parentScene), _asScene1907Symbol(asScene1907Symbol), _countdown1(0) { - + loadSprite(0x64516424, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 1400); setVisible(false); loadSound(0, 0x44061000); @@ -474,7 +474,7 @@ void SsScene1907UpDownButton::setToDownPosition() { AsScene1907WaterHint::AsScene1907WaterHint(NeverhoodEngine *vm) : AnimatedSprite(vm, 1400) { - + createSurface1(0x110A1061, 1500); _x = 320; _y = 240; @@ -515,10 +515,10 @@ void AsScene1907WaterHint::hide() { SetMessageHandler(&Sprite::handleMessage); } -Scene1907::Scene1907(NeverhoodEngine *vm, Module *parentModule) - : Scene(vm, parentModule), _currMovingSymbolIndex(0), _pluggedInCount(0), +Scene1907::Scene1907(NeverhoodEngine *vm, Module *parentModule) + : Scene(vm, parentModule), _currMovingSymbolIndex(0), _pluggedInCount(0), _moveDownCountdown(0), _moveUpCountdown(0), _countdown3(0), _hasPlugInFailed(false) { - + setBackground(0x20628E05); setPalette(0x20628E05); @@ -529,12 +529,12 @@ Scene1907::Scene1907(NeverhoodEngine *vm, Module *parentModule) _asSymbols[i] = insertSprite<AsScene1907Symbol>(this, i, getRandomPositionIndex()); addCollisionSprite(_asSymbols[i]); } - + _ssUpDownButton = insertSprite<SsScene1907UpDownButton>(this, _asSymbols[8]); addCollisionSprite(_ssUpDownButton); _asWaterHint = insertSprite<AsScene1907WaterHint>(); - + insertPuzzleMouse(0x28E0120E, 20, 620); SetMessageHandler(&Scene1907::handleMessage); @@ -542,7 +542,7 @@ Scene1907::Scene1907(NeverhoodEngine *vm, Module *parentModule) if (getGlobalVar(V_STAIRS_PUZZLE_SOLVED)) _pluggedInCount = 9; - + loadSound(0, 0x72004A10); loadSound(1, 0x22082A12); loadSound(2, 0x21100A10); @@ -552,7 +552,7 @@ Scene1907::Scene1907(NeverhoodEngine *vm, Module *parentModule) void Scene1907::update() { Scene::update(); - + if (_hasPlugInFailed) { int fallOffDelay = 0; _hasPlugInFailed = false; @@ -619,7 +619,7 @@ uint32 Scene1907::handleMessage(int messageNum, const MessageParam ¶m, Entit playSound(3); setGlobalVar(V_STAIRS_PUZZLE_SOLVED, 1); break; - } + } return 0; } diff --git a/engines/neverhood/modules/module2000.cpp b/engines/neverhood/modules/module2000.cpp index 5039da1b01..fcccdefbdd 100644 --- a/engines/neverhood/modules/module2000.cpp +++ b/engines/neverhood/modules/module2000.cpp @@ -28,7 +28,7 @@ namespace Neverhood { Module2000::Module2000(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - + if (which < 0) createScene(_vm->gameState().sceneNum, -1); else if (which == 0) @@ -43,7 +43,7 @@ Module2000::~Module2000() { } void Module2000::createScene(int sceneNum, int which) { - debug("Module2000::createScene(%d, %d)", sceneNum, which); + debug(1, "Module2000::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -137,9 +137,9 @@ Scene2001::Scene2001(NeverhoodEngine *vm, Module *parentModule, int which) sendMessage(this, 0x2000, 0); _klaymen->setDoDeltaX(1); } - + _klaymen->setClipRect(tempSprite->getDrawRect().x, 0, 640, 480); - + } uint32 Scene2001::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -153,7 +153,7 @@ uint32 Scene2001::handleMessage(int messageNum, const MessageParam ¶m, Entit setRectList(0x004B3670); _klaymen->setKlaymenIdleTable1(); } - } + } return 0; } diff --git a/engines/neverhood/modules/module2100.cpp b/engines/neverhood/modules/module2100.cpp index 0d7f3dd22a..bcff9d9d1b 100644 --- a/engines/neverhood/modules/module2100.cpp +++ b/engines/neverhood/modules/module2100.cpp @@ -30,7 +30,7 @@ Module2100::Module2100(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { _vm->_soundMan->addMusic(0x10A10C14, 0x11482B95); - + if (which < 0) createScene(_vm->gameState().sceneNum, -1); else if (which == 1) @@ -47,7 +47,7 @@ Module2100::~Module2100() { } void Module2100::createScene(int sceneNum, int which) { - debug("Module2100::createScene(%d, %d)", sceneNum, which); + debug(1, "Module2100::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -129,7 +129,7 @@ void AsScene2101Door::stCloseDoorDone() { AsScene2101HitByDoorEffect::AsScene2101HitByDoorEffect(NeverhoodEngine *vm, Sprite *klaymen) : AnimatedSprite(vm, 1400), _klaymen(klaymen) { - + SetUpdateHandler(&AnimatedSprite::update); SetMessageHandler(&AsScene2101HitByDoorEffect::handleMessage); createSurface(1200, 88, 165); @@ -176,8 +176,8 @@ void SsCommonFloorButton::update() { else setVisible(false); } -} - +} + uint32 SsCommonFloorButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); switch (messageNum) { @@ -195,12 +195,12 @@ uint32 SsCommonFloorButton::handleMessage(int messageNum, const MessageParam &pa Scene2101::Scene2101(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { - + Sprite *tempSprite; - + SetMessageHandler(&Scene2101::handleMessage); SetUpdateHandler(&Scene2101::update); - + setBackground(0x44242305); setPalette(0x44242305); insertScreenMouse(0x4230144A); @@ -210,9 +210,9 @@ Scene2101::Scene2101(NeverhoodEngine *vm, Module *parentModule, int which) _ssFloorButton = insertSprite<SsCommonFloorButton>(this, 0x72427010, 0x32423010, 200, 0); _asTape1 = insertSprite<AsScene1201Tape>(this, 18, 1100, 412, 443, 0x9148A011); addCollisionSprite(_asTape1); - _asTape2 = insertSprite<AsScene1201Tape>(this, 11, 1100, 441, 443, 0x9148A011); + _asTape2 = insertSprite<AsScene1201Tape>(this, 11, 1100, 441, 443, 0x9048A093); addCollisionSprite(_asTape2); - + if (which < 0) { insertKlaymen<KmScene2101>(380, 438); setMessageList(0x004B8E48); @@ -256,10 +256,10 @@ Scene2101::Scene2101(NeverhoodEngine *vm, Module *parentModule, int which) _doorStatus = 1; _countdown1 = 0; } - + _asHitByDoorEffect = insertSprite<AsScene2101HitByDoorEffect>(_klaymen); _klaymen->setClipRect(0, 0, tempSprite->getDrawRect().x2(), 480); - + } void Scene2101::update() { diff --git a/engines/neverhood/modules/module2100.h b/engines/neverhood/modules/module2100.h index 369f5ac0cc..d76bed0780 100644 --- a/engines/neverhood/modules/module2100.h +++ b/engines/neverhood/modules/module2100.h @@ -68,7 +68,7 @@ protected: uint32 _soundFileHash; uint32 _fileHash1, _fileHash2; int16 _countdown; - void update(); + void update(); uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; diff --git a/engines/neverhood/modules/module2200.cpp b/engines/neverhood/modules/module2200.cpp index 4f2d9e8fd2..99f21cad74 100644 --- a/engines/neverhood/modules/module2200.cpp +++ b/engines/neverhood/modules/module2200.cpp @@ -30,10 +30,8 @@ namespace Neverhood { Module2200::Module2200(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - - debug("Create Module2200(%d)", which); - _vm->_soundMan->addMusic(0x11391412, 0x601C908C); + _vm->_soundMan->addMusic(0x11391412, 0x601C908C); if (which < 0) createScene(_vm->gameState().sceneNum, -1); @@ -47,11 +45,12 @@ Module2200::~Module2200() { } void Module2200::createScene(int sceneNum, int which) { - debug("Module2200::createScene(%d, %d)", sceneNum, which); + debug(1, "Module2200::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: _vm->gameState().sceneNum = 0; + _vm->_soundMan->startMusic(0x601C908C, 0, 2); _childObject = new Scene2201(_vm, this, which); break; case 1: @@ -441,7 +440,7 @@ void Module2200::updateScene() { } #undef HallOfRecordsSceneLink - + void Module2200::createHallOfRecordsScene(int which, uint32 hallOfRecordsInfoId) { _childObject = new HallOfRecordsScene(_vm, this, which, hallOfRecordsInfoId); } @@ -462,7 +461,7 @@ AsScene2201Door::AsScene2201Door(NeverhoodEngine *vm, Klaymen *klaymen, Sprite * : AnimatedSprite(vm, 1100), _klaymen(klaymen), _ssDoorLight(ssDoorLight), _countdown(0), _isOpen(isOpen) { _x = 408; - _y = 290; + _y = 290; createSurface(900, 63, 266); SetUpdateHandler(&AsScene2201Door::update); SetMessageHandler(&AsScene2201Door::handleMessage); @@ -529,7 +528,7 @@ void AsScene2201Door::stCloseDoor() { SsScene2201PuzzleCube::SsScene2201PuzzleCube(NeverhoodEngine *vm, uint32 positionIndex, uint32 cubeIndex) : StaticSprite(vm, 900) { - + createSurface(100, 16, 16); loadSprite(kSsScene2201PuzzleCubeFileHashes[cubeIndex], kSLFCenteredDrawOffset | kSLFSetPosition, 0, kSsScene2201PuzzleCubePoints[positionIndex].x, kSsScene2201PuzzleCubePoints[positionIndex].y); @@ -544,7 +543,7 @@ Scene2201::Scene2201(NeverhoodEngine *vm, Module *parentModule, int which) SetMessageHandler(&Scene2201::handleMessage); SetUpdateHandler(&Scene2201::update); - + loadDataResource(0x04104242); loadHitRectList(); setBackground(0x40008208); @@ -552,9 +551,9 @@ Scene2201::Scene2201(NeverhoodEngine *vm, Module *parentModule, int which) insertScreenMouse(0x0820C408); _asTape = insertSprite<AsScene1201Tape>(this, 7, 1100, 459, 432, 0x9148A011); - addCollisionSprite(_asTape); + addCollisionSprite(_asTape); _ssDoorButton = insertSprite<SsCommonPressButton>(this, 0xE4A43E29, 0xE4A43E29, 100, 0); - + for (uint32 cubeIndex = 0; cubeIndex < 9; cubeIndex++) if ((int16)getSubVar(VA_CUBE_POSITIONS, cubeIndex) >= 0) insertSprite<SsScene2201PuzzleCube>(cubeIndex, (int16)getSubVar(VA_CUBE_POSITIONS, cubeIndex)); @@ -563,10 +562,10 @@ Scene2201::Scene2201(NeverhoodEngine *vm, Module *parentModule, int which) _clipRects[0].x2 = 640; _clipRects[1].x2 = 640; _clipRects[1].y2 = 480; - + if (!getGlobalVar(V_TILE_PUZZLE_SOLVED)) insertStaticSprite(0x00026027, 900); - + tempSprite = insertStaticSprite(0x030326A0, 1100); _clipRects[0].x1 = tempSprite->getDrawRect().x; insertStaticSprite(0x811DA061, 1100); @@ -603,7 +602,7 @@ Scene2201::Scene2201(NeverhoodEngine *vm, Module *parentModule, int which) setMessageList(0x004B8120); _asDoor = insertSprite<AsScene2201Door>(_klaymen, _ssDoorLight, true); } - + insertSprite<AsScene2201CeilingFan>(); _vm->_soundMan->addSound(0x04106220, 0x81212040); @@ -720,7 +719,7 @@ uint32 SsScene2202PuzzleCube::handleMessage(int messageNum, const MessageParam & } return messageResult; } - + void SsScene2202PuzzleCube::suMoveCubeX() { bool done = false; @@ -747,9 +746,9 @@ void SsScene2202PuzzleCube::suMoveCubeX() { if (_x == _xFlagPos) _counterDirection = true; } - + if (done) - stopMoving(); + stopMoving(); updateBounds(); @@ -781,9 +780,9 @@ void SsScene2202PuzzleCube::suMoveCubeY() { if (_x == _xFlagPos) _counterDirection = true; } - + if (done) - stopMoving(); + stopMoving(); updateBounds(); @@ -795,7 +794,7 @@ void SsScene2202PuzzleCube::moveCube(int16 newCubePosition) { setSubVar(VA_CUBE_POSITIONS, _cubePosition, (uint32)-1); setSubVar(VA_CUBE_POSITIONS, newCubePosition, (uint32)_cubeSymbol); - + _cubePosition = newCubePosition; _errValue = 0; _counterDirection = false; @@ -838,7 +837,7 @@ void SsScene2202PuzzleCube::moveCube(int16 newCubePosition) { if (_newX - _x >= 180) _xFlagPos = _newX - 90; else - _xFlagPos = _x + _newX / 2; + _xFlagPos = _x + _newX / 2; } else { if (_x - _newX >= 180) _xFlagPos = _x + 90; @@ -852,7 +851,7 @@ void SsScene2202PuzzleCube::moveCube(int16 newCubePosition) { if (_newY - _y >= 180) _xFlagPos = _newY - 90; else - _xFlagPos = _y + _newY / 2; + _xFlagPos = _y + _newY / 2; } else { if (_y - _newY >= 180) _xFlagPos = _y + 90; @@ -861,7 +860,7 @@ void SsScene2202PuzzleCube::moveCube(int16 newCubePosition) { } playSound(1); } - + } void SsScene2202PuzzleCube::stopMoving() { @@ -940,7 +939,7 @@ void Scene2202::update() { _isSolved = true; } } - + } uint32 Scene2202::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -982,7 +981,7 @@ int16 Scene2202::getFreeCubePosition(int16 cubePosition) { } bool Scene2202::testIsSolved() { - return + return getSubVar(VA_CUBE_POSITIONS, 0) == 0 && getSubVar(VA_CUBE_POSITIONS, 2) == 2 && getSubVar(VA_CUBE_POSITIONS, 3) == 3 && @@ -1147,7 +1146,7 @@ Scene2203::Scene2203(NeverhoodEngine *vm, Module *parentModule, int which) _ssSmallRightDoor->setVisible(false); _klaymen->setClipRect(_leftDoorClipRect); } - + } Scene2203::~Scene2203() { @@ -1221,7 +1220,7 @@ Scene2205::Scene2205(NeverhoodEngine *vm, Module *parentModule, int which) SetMessageHandler(&Scene2205::handleMessage); SetUpdateHandler(&Scene2205::update); - + setHitRects(0x004B0620); if (getGlobalVar(V_LIGHTS_ON)) { _isLightOn = true; @@ -1264,11 +1263,11 @@ Scene2205::Scene2205(NeverhoodEngine *vm, Module *parentModule, int which) _klaymen->setClipRect(_ssDoorFrame->getDrawRect().x, 0, 640, 480); _klaymen->setSoundFlag(true); - + loadDataResource(0x00144822); - + } - + void Scene2205::update() { Scene::update(); if (!_isLightOn && getGlobalVar(V_LIGHTS_ON)) { @@ -1344,7 +1343,7 @@ static const int16 kAsScene2206DoorSpikesXDeltasClose[] = { AsScene2206DoorSpikes::AsScene2206DoorSpikes(NeverhoodEngine *vm, uint32 fileHash) : StaticSprite(vm, fileHash, 200) { - + if (getGlobalVar(V_SPIKES_RETRACTED)) _x -= 63; SetUpdateHandler(&AsScene2206DoorSpikes::update); @@ -1458,10 +1457,10 @@ Scene2206::Scene2206(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { uint32 fileHash; - + SetUpdateHandler(&Scene::update); SetMessageHandler(&Scene2206::handleMessage); - + if (getGlobalVar(V_LIGHTS_ON)) { fileHash = 0x41983216; _sprite1 = insertStaticSprite(0x2201266A, 100); @@ -1496,7 +1495,7 @@ Scene2206::Scene2206(NeverhoodEngine *vm, Module *parentModule, int which) if (!getGlobalVar(V_LIGHTS_ON)) _palette->addPalette(0x0263D144, 0, 65, 0); addCollisionSprite(_ssTestTube); - + if (which < 0) { // Restoring game insertKlaymen<KmScene2206>(200, 430); @@ -1645,7 +1644,7 @@ void AsScene2207Elevator::update() { if (_destPointIndex + _destPointIndexDelta > _pointIndex) { _pointIndex++; startAnimation(getGlobalVar(V_LIGHTS_ON) ? 0xC858CC19 : 0x294B3377, _pointIndex, _pointIndex); - _newStickFrameIndex = _pointIndex; + _newStickFrameIndex = _pointIndex; if (_destPointIndex + _destPointIndexDelta == _pointIndex) { if (_destPointIndexDelta != 0) _destPointIndexDelta = 0; @@ -1661,7 +1660,7 @@ void AsScene2207Elevator::update() { if (_pointIndex == 0) sendMessage(_parentScene, 0x2003, 0); startAnimation(getGlobalVar(V_LIGHTS_ON) ? 0xC858CC19 : 0x294B3377, _pointIndex, _pointIndex); - _newStickFrameIndex = _pointIndex; + _newStickFrameIndex = _pointIndex; if (_destPointIndex + _destPointIndexDelta == _pointIndex) { if (_destPointIndexDelta != 0) _destPointIndexDelta = 0; @@ -1676,14 +1675,14 @@ void AsScene2207Elevator::update() { sendMessage(_parentScene, 0x2002, 900); else if (_pointIndex < 20 && _surface->getPriority() != 1100) sendMessage(_parentScene, 0x2002, 1100); - + AnimatedSprite::update(); - + if (_destPointIndex + _destPointIndexDelta == _pointIndex && _isMoving) { sendMessage(_parentScene, 0x2004, 0); _isMoving = false; } - + } void AsScene2207Elevator::suSetPosition() { @@ -1707,14 +1706,14 @@ void AsScene2207Elevator::moveToY(int16 y) { if (!_pointArray || _pointArray->size() == 0) return; - + for (uint i = 0; i < _pointArray->size(); i++) { int16 distance = ABS(y - (*_pointArray)[i].y); if (distance < minDistance) { minDistance = distance; _destPointIndex = i; } - } + } if (_destPointIndex != _pointIndex) { if (_destPointIndex == 0 || _destPointIndex == (int)_pointArray->size() - 1) @@ -1733,7 +1732,7 @@ void AsScene2207Elevator::moveToY(int16 y) { AsScene2207Lever::AsScene2207Lever(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, int doDeltaX) : AnimatedSprite(vm, 1100), _parentScene(parentScene) { - + _x = x; _y = y; createSurface(1010, 71, 73); @@ -1794,7 +1793,7 @@ void AsScene2207Lever::stLeverUpEvent() { AsScene2207WallRobotAnimation::AsScene2207WallRobotAnimation(NeverhoodEngine *vm, Scene *parentScene) : AnimatedSprite(vm, 1200), _idle(true) { - + _x = 309; _y = 320; createSurface1(0xCCFD6090, 100); @@ -1875,7 +1874,7 @@ void AsScene2207WallRobotAnimation::cbStopAnimation() { AsScene2207WallCannonAnimation::AsScene2207WallCannonAnimation(NeverhoodEngine *vm) : AnimatedSprite(vm, 1200), _idle(true) { - + _x = 309; _y = 320; createSurface1(0x8CAA0099, 100); @@ -1926,7 +1925,7 @@ SsScene2207Symbol::SsScene2207Symbol(NeverhoodEngine *vm, uint32 fileHash, int i _x = 330; _y = 246 + index * 50; - updatePosition(); + updatePosition(); } Scene2207::Scene2207(NeverhoodEngine *vm, Module *parentModule) @@ -1944,7 +1943,7 @@ Scene2207::Scene2207(NeverhoodEngine *vm, Module *parentModule) _klaymen->setRepl(64, 0); setMessageList(0x004B38E8); _asElevator = insertSprite<AsScene2207Elevator>(this); - + if (getGlobalVar(V_LIGHTS_ON)) { setBackground(0x88C00241); setPalette(0x88C00241); @@ -1953,7 +1952,7 @@ Scene2207::Scene2207(NeverhoodEngine *vm, Module *parentModule) _ssMaskPart2 = insertStaticSprite(0x688F62A5, 1100); _ssMaskPart3 = insertStaticSprite(0x0043B038, 1100); _asTape = insertSprite<AsScene1201Tape>(this, 4, 1100, 277, 428, 0x9148A011); - addCollisionSprite(_asTape); + addCollisionSprite(_asTape); _asLever = insertSprite<AsScene2207Lever>(this, 527, 333, 0); addCollisionSprite(_asLever); _asWallRobotAnimation = insertSprite<AsScene2207WallRobotAnimation>(this); @@ -2107,7 +2106,7 @@ static const uint32 kScene2208FileHashes1[] = { 0x041023CB, 0x041020CB, 0x041026CB, 0x04102ACB, 0x041032CB, 0x041002CB }; - + static const uint32 kScene2208FileHashes2[] = { 0x091206C9, 0x091406C9, 0x091806C9, 0x090006C9, 0x093006C9, 0x095006C9 @@ -2123,13 +2122,13 @@ Scene2208::Scene2208(NeverhoodEngine *vm, Module *parentModule, int which) setGlobalVar(V_COLUMN_TEXT_NAME, calcHash("stLineagex")); _textResource.load(getGlobalVar(V_COLUMN_TEXT_NAME)); - + textStart = _textResource.getString(getGlobalVar(V_CLICKED_COLUMN_INDEX), textEnd); while (textStart < textEnd) { _strings.push_back(textStart); textStart += strlen(textStart) + 1; } - + _maxRowIndex = 8 + 10 * (3 - (getGlobalVar(V_COLUMN_TEXT_NAME) == calcHash("stLineagex") ? 1 : 0)); _background = new Background(_vm, 0); @@ -2142,20 +2141,20 @@ Scene2208::Scene2208(NeverhoodEngine *vm, Module *parentModule, int which) _fontSurface = FontSurface::createFontSurface(_vm, 0x0800090C); - _backgroundSurface = new BaseSurface(_vm, 0, 640, 480); + _backgroundSurface = new BaseSurface(_vm, 0, 640, 480, "background"); spriteResource.load(0x08100289, true); _backgroundSurface->drawSpriteResourceEx(spriteResource, false, false, 0, 0); - _topBackgroundSurface = new BaseSurface(_vm, 0, 640, 192); + _topBackgroundSurface = new BaseSurface(_vm, 0, 640, 192, "top background"); spriteResource.load(!getGlobalVar(V_COLUMN_BACK_NAME) ? kScene2208FileHashes1[getGlobalVar(V_CLICKED_COLUMN_INDEX) % 6] : getGlobalVar(V_COLUMN_BACK_NAME), true); _topBackgroundSurface->drawSpriteResourceEx(spriteResource, false, false, 0, 0); - _bottomBackgroundSurface = new BaseSurface(_vm, 0, 640, 192); + _bottomBackgroundSurface = new BaseSurface(_vm, 0, 640, 192, "bottom background"); spriteResource.load(kScene2208FileHashes2[getGlobalVar(V_CLICKED_COLUMN_INDEX) % 6], true); _bottomBackgroundSurface->drawSpriteResourceEx(spriteResource, false, false, 0, 0); - + SetUpdateHandler(&Scene2208::update); SetMessageHandler(&Scene2208::handleMessage); @@ -2166,7 +2165,7 @@ Scene2208::Scene2208(NeverhoodEngine *vm, Module *parentModule, int which) if (_newRowIndex < 6) _newRowIndex = 0; _rowScrollY = 0; - _backgroundScrollY = 48 * _newRowIndex; + _backgroundScrollY = 48 * _newRowIndex; _currRowIndex = _newRowIndex; for (int16 rowIndex = 0; rowIndex < _visibleRowsCount; rowIndex++) @@ -2186,7 +2185,7 @@ Scene2208::~Scene2208() { void Scene2208::update() { int16 mouseY = _vm->getMouseY(); - + if (mouseY < 48) { if (_currRowIndex > 0) _newRowIndex = _currRowIndex - 1; @@ -2236,7 +2235,7 @@ uint32 Scene2208::handleMessage(int messageNum, const MessageParam ¶m, Entit } void Scene2208::drawRow(int16 rowIndex) { - NDrawRect sourceRect; + NDrawRect sourceRect; int16 y = (rowIndex * 48) % 528; if (rowIndex < 4) { sourceRect.x = 0; @@ -2281,7 +2280,7 @@ Scene2242::Scene2242(NeverhoodEngine *vm, Module *parentModule, int which) SetMessageHandler(&Scene2242::handleMessage); SetUpdateHandler(&Scene2242::update); - + if (getGlobalVar(V_LIGHTS_ON)) { setBackground(0x11840E24); setPalette(0x11840E24); @@ -2298,7 +2297,7 @@ Scene2242::Scene2242(NeverhoodEngine *vm, Module *parentModule, int which) } _asTape = insertSprite<AsScene1201Tape>(this, 10, 1100, 464, 435, 0x9148A011); - addCollisionSprite(_asTape); + addCollisionSprite(_asTape); if (which < 0) { // Restoring game @@ -2381,7 +2380,7 @@ void Scene2242::readClickedColumn() { } static const int16 kHallOfRecordsKlaymenXPos[] = { - 68, 157, 246, 335, + 68, 157, 246, 335, 424, 513, 602 }; @@ -2397,7 +2396,7 @@ static const uint32 kHallOfRecordsSceneMessageListIds1[] = { HallOfRecordsScene::HallOfRecordsScene(NeverhoodEngine *vm, Module *parentModule, int which, uint32 hallOfRecordsInfoId) : Scene(vm, parentModule) { - + _hallOfRecordsInfo = _vm->_staticData->getHallOfRecordsInfoItem(hallOfRecordsInfoId); SetMessageHandler(&HallOfRecordsScene::handleMessage); @@ -2488,7 +2487,7 @@ static const uint32 kScene2247MessageListIds1[] = { Scene2247::Scene2247(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { - + SetMessageHandler(&Scene2247::handleMessage); SetUpdateHandler(&Scene::update); @@ -2525,7 +2524,7 @@ Scene2247::Scene2247(NeverhoodEngine *vm, Module *parentModule, int which) } _klaymen->setSoundFlag(true); - + } Scene2247::~Scene2247() { diff --git a/engines/neverhood/modules/module2200.h b/engines/neverhood/modules/module2200.h index af7171dd53..5c19f2a818 100644 --- a/engines/neverhood/modules/module2200.h +++ b/engines/neverhood/modules/module2200.h @@ -100,7 +100,7 @@ class SsScene2202PuzzleCube : public StaticSprite { public: SsScene2202PuzzleCube(NeverhoodEngine *vm, Scene *parentScene, int16 cubePosition, int16 cubeSymbol); protected: - Scene *_parentScene; + Scene *_parentScene; int16 _cubeSymbol; int16 _cubePosition; int16 _newX, _newY; @@ -135,7 +135,7 @@ protected: void update(); uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); int16 getFreeCubePosition(int16 index); - bool testIsSolved(); + bool testIsSolved(); }; class AsCommonKey : public AnimatedSprite { diff --git a/engines/neverhood/modules/module2300.cpp b/engines/neverhood/modules/module2300.cpp index 34eca14bea..2a46df1ee2 100644 --- a/engines/neverhood/modules/module2300.cpp +++ b/engines/neverhood/modules/module2300.cpp @@ -32,12 +32,12 @@ static const uint32 kModule2300SoundList[] = { Module2300::Module2300(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule), _soundVolume(0) { - + _vm->_soundMan->addSoundList(0x1A214010, kModule2300SoundList); _vm->_soundMan->setSoundListParams(kModule2300SoundList, true, 50, 600, 10, 150); _isWallBroken = getGlobalVar(V_WALL_BROKEN) != 0; - + if (_isWallBroken) { _vm->_soundMan->setSoundVolume(0x90F0D1C3, 0); _vm->_soundMan->playSoundLooping(0x90F0D1C3); @@ -68,7 +68,7 @@ Module2300::~Module2300() { } void Module2300::createScene(int sceneNum, int which) { - debug("Module2300::createScene(%d, %d)", sceneNum, which); + debug(1, "Module2300::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -161,12 +161,12 @@ void Module2300::updateScene() { } else { switch (_sceneNum) { case 1: - if (_isWallBroken && navigationScene()->isWalkingForward() && navigationScene()->getNavigationIndex() == 4 && + if (_isWallBroken && navigationScene()->isWalkingForward() && navigationScene()->getNavigationIndex() == 4 && navigationScene()->getFrameNumber() % 2) { _soundVolume++; _vm->_soundMan->setSoundVolume(0x90F0D1C3, _soundVolume); } - if (navigationScene()->isWalkingForward() && navigationScene()->getNavigationIndex() == 0 && + if (navigationScene()->isWalkingForward() && navigationScene()->getNavigationIndex() == 0 && navigationScene()->getFrameNumber() == 50) { _vm->_soundMan->playTwoSounds(0x1A214010, 0x48498E46, 0x50399F64, 0); _vm->_soundMan->setSoundVolume(0x48498E46, 70); @@ -182,5 +182,5 @@ void Module2300::updateScene() { } } } - + } // End of namespace Neverhood diff --git a/engines/neverhood/modules/module2400.cpp b/engines/neverhood/modules/module2400.cpp index 450812a5f3..21ea390ba2 100644 --- a/engines/neverhood/modules/module2400.cpp +++ b/engines/neverhood/modules/module2400.cpp @@ -26,11 +26,11 @@ namespace Neverhood { Module2400::Module2400(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - + _vm->_soundMan->addMusic(0x202D1010, 0xB110382D); if (which < 0) - createScene(_vm->gameState().sceneNum, _vm->gameState().which); + createScene(_vm->gameState().sceneNum, -1); else createScene(0, 0); @@ -41,7 +41,7 @@ Module2400::~Module2400() { } void Module2400::createScene(int sceneNum, int which) { - debug("Module2400::createScene(%d, %d)", sceneNum, which); + debug(1, "Module2400::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -168,11 +168,11 @@ static const uint32 kScene2401FileHashes3[] = { }; static const NRect kScene2401Rects[] = { - NRect(369, 331, 394, 389), - NRect(395, 331, 419, 389), - NRect(420, 331, 441, 389), - NRect(442, 331, 464, 389), - NRect(465, 331, 491, 389) + { 369, 331, 394, 389 }, + { 395, 331, 419, 389 }, + { 420, 331, 441, 389 }, + { 442, 331, 464, 389 }, + { 465, 331, 491, 389 } }; static const uint32 kAsScene2401WaterSpitFileHashes2[] = { @@ -187,7 +187,7 @@ static const uint32 kAsScene2401WaterSpitFileHashes1[] = { AsScene2401WaterSpit::AsScene2401WaterSpit(NeverhoodEngine *vm) : AnimatedSprite(vm, 1200) { - + _x = 240; _y = 447; createSurface(100, 146, 74); @@ -222,7 +222,7 @@ uint32 AsScene2401WaterSpit::handleMessage(int messageNum, const MessageParam &p AsScene2401FlowingWater::AsScene2401FlowingWater(NeverhoodEngine *vm) : AnimatedSprite(vm, 1200), _isWaterFlowing(false) { - + _x = 88; _y = 421; createSurface1(0x10203116, 100); @@ -262,10 +262,10 @@ uint32 AsScene2401FlowingWater::handleMessage(int messageNum, const MessageParam } return messageResult; } - + AsScene2401WaterFlushing::AsScene2401WaterFlushing(NeverhoodEngine *vm, int16 x, int16 y) : AnimatedSprite(vm, 1200), _countdown(0), _flushLoopCount(0) { - + _x = x; _y = y; createSurface1(0xB8596884, 100); @@ -308,7 +308,7 @@ uint32 AsScene2401WaterFlushing::handleMessage(int messageNum, const MessagePara AsScene2401Door::AsScene2401Door(NeverhoodEngine *vm, bool isOpen) : AnimatedSprite(vm, 1100), _countdown(0), _isOpen(isOpen) { - + _x = 320; _y = 240; createSurface1(0x44687810, 100); @@ -398,7 +398,7 @@ Scene2401::Scene2401(NeverhoodEngine *vm, Module *parentModule, int which) _ssWaterPipes[i] = insertStaticSprite(kScene2401FileHashes1[i], 300); _ssWaterPipes[i]->setVisible(false); } - + _asWaterSpit[0] = insertSprite<AsScene2401WaterSpit>(); _asWaterSpit[1] = insertSprite<AsScene2401WaterSpit>(); @@ -461,7 +461,7 @@ void Scene2401::update() { if (_countdown2 != 0 && (--_countdown2) == 0) sendMessage(_asFlowingWater, 0x2003, 0); - + Scene::update(); } @@ -559,7 +559,7 @@ AsScene2402Door::AsScene2402Door(NeverhoodEngine *vm, Scene *parentScene, bool i } else { stopAnimation(); setVisible(false); - } + } SetUpdateHandler(&AsScene2402Door::update); SetMessageHandler(&AsScene2402Door::handleMessage); } @@ -654,7 +654,7 @@ void AsScene2402TV::upFocusKlaymen() { _newStickFrameIndex = _currFrameIndex; if (_countdown2 == 0) { _vm->_soundMan->addSound(0x01520123, 0xC42D4528); - _vm->_soundMan->playSoundLooping(0xC42D4528); + _vm->_soundMan->playSoundLooping(0xC42D4528); } _countdown2 = 5; } else if (_countdown2 != 0 && (--_countdown2 == 0)) @@ -698,7 +698,7 @@ Scene2402::Scene2402(NeverhoodEngine *vm, Module *parentModule, int which) _asTape = insertSprite<AsScene1201Tape>(this, 9, 1100, 286, 409, 0x9148A011); addCollisionSprite(_asTape); _ssButton = insertSprite<SsCommonButtonSprite>(this, 0x15288120, 100, 0); - + if (which < 0) { // Restoring game insertKlaymen<KmScene2402>(198, 404); @@ -779,7 +779,7 @@ uint32 Scene2402::handleMessage(int messageNum, const MessageParam ¶m, Entit } return messageResult; } - + void Scene2402::playPipeSound(uint32 fileHash) { playSound(_soundToggle ? 0 : 1, fileHash); _soundToggle = !_soundToggle; @@ -787,7 +787,7 @@ void Scene2402::playPipeSound(uint32 fileHash) { Scene2403::Scene2403(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { - + Sprite *tempSprite1, *tempSprite2, *tempSprite3; SetMessageHandler(&Scene2403::handleMessage); @@ -799,7 +799,7 @@ Scene2403::Scene2403(NeverhoodEngine *vm, Module *parentModule, int which) addCollisionSprite(_asTape); _asLightCord = insertSprite<AsScene2803LightCord>(this, 0xA1095A10, 0x836D3813, 368, 200); _asLightCord->setClipRect(0, 25, 640, 480); - + if (which < 0) { // Restoring game _isClimbingLadder = false; @@ -828,11 +828,11 @@ Scene2403::Scene2403(NeverhoodEngine *vm, Module *parentModule, int which) } _ssButton = insertSprite<SsCommonButtonSprite>(this, 0x3130B0EB, 100, 0); - tempSprite1 = insertStaticSprite(0x20C24220, 1100); + tempSprite1 = insertStaticSprite(0x20C24220, 1100); tempSprite2 = insertStaticSprite(0x03080900, 1300); tempSprite3 = insertSprite<AsScene1002KlaymenLadderHands>(_klaymen); tempSprite3->setClipRect(tempSprite1->getDrawRect().x, 0, 640, tempSprite2->getDrawRect().y2()); - _klaymen->setClipRect(tempSprite1->getDrawRect().x, 0, 640, tempSprite2->getDrawRect().y2()); + _klaymen->setClipRect(tempSprite1->getDrawRect().x, 0, 640, tempSprite2->getDrawRect().y2()); loadSound(1, calcHash("fxFogHornSoft")); } @@ -887,7 +887,7 @@ Scene2406::Scene2406(NeverhoodEngine *vm, Module *parentModule, int which) setGlobalVar(V_KEY3_LOCATION, 2); SetMessageHandler(&Scene2406::handleMessage); - + setRectList(0x004B78C8); insertScreenMouse(0xB03001A8); @@ -913,7 +913,7 @@ Scene2406::Scene2406(NeverhoodEngine *vm, Module *parentModule, int which) setPalette(0x0A038595); tempSprite1 = insertStaticSprite(0x1712112A, 1100); } - + tempSprite2 = insertStaticSprite(0x22300924, 1300); _clipRects[1].x1 = tempSprite1->getDrawRect().x; _clipRects[1].y1 = tempSprite2->getDrawRect().y; diff --git a/engines/neverhood/modules/module2500.cpp b/engines/neverhood/modules/module2500.cpp index a997b5aab1..46ce2ba4fc 100644 --- a/engines/neverhood/modules/module2500.cpp +++ b/engines/neverhood/modules/module2500.cpp @@ -29,29 +29,29 @@ static const uint32 kScene2505StaticSprites[] = { 0x4000A226, 0 }; -static const NRect kScene2505ClipRect = NRect(0, 0, 564, 480); +static const NRect kScene2505ClipRect = { 0, 0, 564, 480 }; static const uint32 kScene2506StaticSprites[] = { 0x4027AF02, 0 }; -static const NRect kScene2506ClipRect = NRect(0, 0, 640, 441); +static const NRect kScene2506ClipRect = { 0, 0, 640, 441 }; static const uint32 kScene2508StaticSprites1[] = { 0x2F08E610, 0xD844E6A0, 0 }; -static const NRect kScene2508ClipRect1 = NRect(0, 0, 594, 448); +static const NRect kScene2508ClipRect1 = { 0, 0, 594, 448 }; static const uint32 kScene2508StaticSprites2[] = { 0x2F08E610, 0 }; -static const NRect kScene2508ClipRect2 = NRect(0, 0, 594, 448); +static const NRect kScene2508ClipRect2 = { 0, 0, 594, 448 }; Module2500::Module2500(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule), _soundIndex(0) { - + _vm->_soundMan->addMusic(0x29220120, 0x05343184); _vm->_soundMan->startMusic(0x05343184, 0, 0); SetMessageHandler(&Module2500::handleMessage); @@ -73,7 +73,7 @@ Module2500::~Module2500() { } void Module2500::createScene(int sceneNum, int which) { - debug("Module2500::createScene(%d, %d)", sceneNum, which); + debug(1, "Module2500::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -212,14 +212,14 @@ uint32 Module2500::handleMessage(int messageNum, const MessageParam ¶m, Enti } return messageResult; } - + void Module2500::createScene2704(int which, uint32 sceneInfoId, int16 value, const uint32 *staticSprites, const NRect *clipRect) { _childObject = new Scene2704(_vm, this, which, sceneInfoId, value, staticSprites, clipRect); } Scene2501::Scene2501(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { - + _tracks.push_back(_vm->_staticData->getTrackInfo(0x004B2628)); _tracks.push_back(_vm->_staticData->getTrackInfo(0x004B264C)); _tracks.push_back(_vm->_staticData->getTrackInfo(0x004B2670)); @@ -282,7 +282,7 @@ Scene2501::Scene2501(NeverhoodEngine *vm, Module *parentModule, int which) _asCarTrackShadow = insertSprite<AsCommonCarTrackShadow>(_asCar, _ssTrackShadowBackground->getSurface(), 4); _asCarConnectorShadow = insertSprite<AsCommonCarConnectorShadow>(_asCar, _ssTrackShadowBackground->getSurface(), 4); insertSprite<AsCommonCarConnector>(_asCar); - + _newTrackIndex = -1; _dataResource.load(calcHash("Ashooded")); @@ -300,9 +300,9 @@ Scene2501::Scene2501(NeverhoodEngine *vm, Module *parentModule, int which) if (testPoint.x < 0 || testPoint.x >= 640 || testPoint.y < 0 || testPoint.y >= 480) sendMessage(_asCar, 0x2008, 150); } - + _carStatus = 0; - + } Scene2501::~Scene2501() { @@ -391,7 +391,7 @@ uint32 Scene2501::handleMessage(int messageNum, const MessageParam ¶m, Entit } return messageResult; } - + uint32 Scene2501::hmRidingCar(int messageNum, const MessageParam ¶m, Entity *sender) { uint32 messageResult = Scene::handleMessage(messageNum, param, sender); switch (messageNum) { @@ -434,7 +434,7 @@ uint32 Scene2501::hmCarAtHome(int messageNum, const MessageParam ¶m, Entity } return messageResult; } - + void Scene2501::moveCarToPoint(NPoint &pt) { int minMatchTrackIndex, minMatchDistance; _tracks.findTrackPoint(pt, minMatchTrackIndex, minMatchDistance, _dataResource); @@ -472,7 +472,7 @@ void Scene2501::updateKlaymenClipRect() { SsScene2504Button::SsScene2504Button(NeverhoodEngine *vm) : StaticSprite(vm, 1400), _countdown(0), _isSoundPlaying(false) { - + loadSprite(0x070220D9, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); setVisible(false); loadSound(0, 0x4600204C); @@ -520,9 +520,9 @@ uint32 SsScene2504Button::handleMessage(int messageNum, const MessageParam ¶ Scene2504::Scene2504(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { - + Sprite *ssButton; - + setBackground(0x90791B80); setPalette(0x90791B80); ssButton = insertSprite<SsScene2504Button>(); diff --git a/engines/neverhood/modules/module2600.cpp b/engines/neverhood/modules/module2600.cpp index b8dbf7bff1..2fce82b777 100644 --- a/engines/neverhood/modules/module2600.cpp +++ b/engines/neverhood/modules/module2600.cpp @@ -35,7 +35,7 @@ static const uint32 kModule2600SoundList[] = { Module2600::Module2600(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - + if (which < 0) createScene(_vm->gameState().sceneNum, -1); else if (which == 1) @@ -54,7 +54,7 @@ Module2600::~Module2600() { } void Module2600::createScene(int sceneNum, int which) { - debug("Module2600::createScene(%d, %d)", sceneNum, which); + debug(1, "Module2600::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -218,10 +218,10 @@ void Module2600::updateScene() { } } } - + SsScene2609Button::SsScene2609Button(NeverhoodEngine *vm, Scene *parentScene) : StaticSprite(vm, 1400), _parentScene(parentScene), _countdown(0) { - + SetUpdateHandler(&SsScene2609Button::update); SetMessageHandler(&SsScene2609Button::handleMessage); @@ -273,7 +273,7 @@ uint32 SsScene2609Button::handleMessage(int messageNum, const MessageParam ¶ AsScene2609Water::AsScene2609Water(NeverhoodEngine *vm) : AnimatedSprite(vm, 1000) { - + _x = 240; _y = 420; setDoDeltaX(1); @@ -309,7 +309,7 @@ uint32 AsScene2609Water::handleMessage(int messageNum, const MessageParam ¶m Scene2609::Scene2609(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _isBusy(false) { - + SetUpdateHandler(&Scene::update); SetMessageHandler(&Scene2609::handleMessage); diff --git a/engines/neverhood/modules/module2700.cpp b/engines/neverhood/modules/module2700.cpp index 8b69bc050e..7aea82f6b1 100644 --- a/engines/neverhood/modules/module2700.cpp +++ b/engines/neverhood/modules/module2700.cpp @@ -26,14 +26,14 @@ namespace Neverhood { -static const NRect kScene2710ClipRect = NRect(0, 0, 626, 480); +static const NRect kScene2710ClipRect = { 0, 0, 626, 480 }; static const uint32 kScene2710StaticSprites[] = { 0x0D2016C0, 0 }; -static const NRect kScene2711ClipRect = NRect(0, 0, 521, 480); +static const NRect kScene2711ClipRect = { 0, 0, 521, 480 }; static const uint32 kScene2711FileHashes1[] = { 0, @@ -68,14 +68,14 @@ static const uint32 kScene2711FileHashes3[] = { 0 }; -static const NRect kScene2724ClipRect = NRect(0, 141, 640, 480); +static const NRect kScene2724ClipRect = { 0, 141, 640, 480 }; static const uint32 kScene2724StaticSprites[] = { 0xC20D00A5, 0 }; -static const NRect kScene2725ClipRect = NRect(0, 0, 640, 413); +static const NRect kScene2725ClipRect = { 0, 0, 640, 413 }; static const uint32 kScene2725StaticSprites[] = { 0xC20E00A5, @@ -83,8 +83,8 @@ static const uint32 kScene2725StaticSprites[] = { }; Module2700::Module2700(NeverhoodEngine *vm, Module *parentModule, int which) - : Module(vm, parentModule), _soundIndex(0), _raidoMusicInitialized(false) { - + : Module(vm, parentModule), _soundIndex(0), _radioMusicInitialized(false) { + _vm->_soundMan->addMusic(0x42212411, 0x04020210); _vm->_soundMan->startMusic(0x04020210, 24, 2); SetMessageHandler(&Module2700::handleMessage); @@ -111,7 +111,7 @@ Module2700::~Module2700() { } void Module2700::createScene(int sceneNum, int which) { - debug("Module2700::createScene(%d, %d)", sceneNum, which); + debug(1, "Module2700::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -500,7 +500,7 @@ void Module2700::updateScene() { } else { switch (_sceneNum) { case 21: - if (!_raidoMusicInitialized) { + if (!_radioMusicInitialized) { _vm->_soundMan->stopMusic(0x04020210, 0, 1); _vm->gameModule()->initRadioPuzzle(); _musicFileHash = getGlobalVar(V_GOOD_RADIO_MUSIC_NAME); @@ -508,7 +508,7 @@ void Module2700::updateScene() { _vm->_soundMan->startMusic(_musicFileHash, 0, 2); _vm->_soundMan->addSound(0x42212411, 0x44014282); _vm->_soundMan->setSoundParams(0x44014282, true, 120, 360, 72, 0); - _raidoMusicInitialized = true; + _radioMusicInitialized = true; } break; } @@ -527,7 +527,7 @@ uint32 Module2700::handleMessage(int messageNum, const MessageParam ¶m, Enti } return messageResult; } - + void Module2700::createScene2703(int which, uint32 trackInfoId) { _childObject = new Scene2703(_vm, this, which, trackInfoId); } @@ -545,7 +545,7 @@ static const NPoint kCarShadowOffsets[] = { SsCommonTrackShadowBackground::SsCommonTrackShadowBackground(NeverhoodEngine *vm, uint32 fileHash) : StaticSprite(vm, 0) { - + loadSprite(fileHash, kSLFDefDrawOffset | kSLFDefPosition, 0); } @@ -555,7 +555,7 @@ AsCommonCarShadow::AsCommonCarShadow(NeverhoodEngine *vm, AnimatedSprite *asCar, SetUpdateHandler(&AsCommonCarShadow::update); createShadowSurface(shadowSurface, 211, 147, 100); updateShadow(); -} +} void AsCommonCarShadow::update() { updateShadow(); @@ -589,8 +589,8 @@ AsCommonCarConnectorShadow::AsCommonCarConnectorShadow(NeverhoodEngine *vm, Spri SetUpdateHandler(&AsCommonCarConnectorShadow::update); createShadowSurface1(shadowSurface, 0x60281C10, 150); startAnimation(0x60281C10, -1, -1); - _newStickFrameIndex = STICK_LAST_FRAME; -} + _newStickFrameIndex = STICK_LAST_FRAME; +} void AsCommonCarConnectorShadow::update() { _x = _asCar->getX() + kCarShadowOffsets[_index].x; @@ -605,7 +605,7 @@ AsCommonCarTrackShadow::AsCommonCarTrackShadow(NeverhoodEngine *vm, Sprite *asCa createShadowSurface1(shadowSurface, 0x0759129C, 100); startAnimation(0x0759129C, frameIndex, -1); _newStickFrameIndex = frameIndex; -} +} void AsCommonCarTrackShadow::update() { _x = _asCar->getX(); @@ -615,19 +615,19 @@ void AsCommonCarTrackShadow::update() { Scene2701::Scene2701(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { - + Sprite *tempSprite; - + NRect clipRect; TrackInfo *tracks = _vm->_staticData->getTrackInfo(0x004B2240); setGlobalVar(V_CAR_DELTA_X, 1); - + setBackground(tracks->bgFilename); setPalette(tracks->bgFilename); _palette->addPalette(calcHash("paPodFloor"), 65, 31, 65); _palette->addPalette(calcHash("paKlayFloor"), 0, 65, 0); insertScreenMouse(0x08B08180); - + tempSprite = insertStaticSprite(0x1E086325, 1200); clipRect.set(0, 0, 640, tempSprite->getDrawRect().y2()); @@ -661,7 +661,7 @@ Scene2701::Scene2701(NeverhoodEngine *vm, Module *parentModule, int which) if (testPoint.x < 0 || testPoint.x >= 640 || testPoint.y < 0 || testPoint.y >= 480) sendMessage(_asCar, 0x2008, 150); } - + _asCar->setClipRect(clipRect); _asCarConnector->setClipRect(clipRect); @@ -715,10 +715,10 @@ uint32 Scene2701::hmCarAtHome(int messageNum, const MessageParam ¶m, Entity Scene2702::Scene2702(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _isInLight(true), _newTrackIndex(-1) { - + SetMessageHandler(&Scene2702::handleMessage); SetUpdateHandler(&Scene2702::update); - + setBackground(0x18808B00); setPalette(0x18808B00); _palette->addPalette(calcHash("paPodFloor"), 65, 31, 65); @@ -734,7 +734,7 @@ Scene2702::Scene2702(NeverhoodEngine *vm, Module *parentModule, int which) _asCarTrackShadow = insertSprite<AsCommonCarTrackShadow>(_asCar, _ssTrackShadowBackground->getSurface(), 4); _asCarConnectorShadow = insertSprite<AsCommonCarConnectorShadow>(_asCar, _ssTrackShadowBackground->getSurface(), 4); _dataResource.load(0x04310014); - + if (which == 1) { _isUpperTrack = false; _currTrackIndex = 1; @@ -765,11 +765,11 @@ Scene2702::Scene2702(NeverhoodEngine *vm, Module *parentModule, int which) } if (_isUpperTrack) { - _tracks.push_back(_vm->_staticData->getTrackInfo(0x004B5F68)); + _tracks.push_back(_vm->_staticData->getTrackInfo(0x004B5F68)); _tracks.push_back(_vm->_staticData->getTrackInfo(0x004B5F8C)); _tracks.push_back(_vm->_staticData->getTrackInfo(0x004B5FB0)); } else { - _tracks.push_back(_vm->_staticData->getTrackInfo(0x004B5FD8)); + _tracks.push_back(_vm->_staticData->getTrackInfo(0x004B5FD8)); _tracks.push_back(_vm->_staticData->getTrackInfo(0x004B5FFC)); _tracks.push_back(_vm->_staticData->getTrackInfo(0x004B6020)); } @@ -873,19 +873,19 @@ Scene2703::Scene2703(NeverhoodEngine *vm, Module *parentModule, int which, uint3 : Scene(vm, parentModule) { TrackInfo *tracks = _vm->_staticData->getTrackInfo(trackInfoId); - + SetMessageHandler(&Scene2703::handleMessage); SetUpdateHandler(&Scene2703::update); - + setBackground(tracks->bgFilename); setPalette(tracks->bgFilename); _palette->addPalette(calcHash("paPodShade"), 65, 31, 65); _palette->addPalette(calcHash("paKlayShade"), 0, 65, 0); addEntity(_palette); insertScreenMouse(tracks->mouseCursorFilename); - + _palStatus = 2; - + if (tracks->bgShadowFilename) { _ssTrackShadowBackground = createSprite<SsCommonTrackShadowBackground>(tracks->bgShadowFilename); addEntity(_ssTrackShadowBackground); @@ -905,7 +905,7 @@ Scene2703::Scene2703(NeverhoodEngine *vm, Module *parentModule, int which, uint3 _dataResource.load(tracks->dataResourceFilename); _trackPoints = _dataResource.getPointArray(tracks->trackPointsName); _asCar->setPathPoints(_trackPoints); - + if (which == _which2) { NPoint testPoint = (*_trackPoints)[_trackPoints->size() - 1]; sendMessage(_asCar, 0x2002, _trackPoints->size() - 1); @@ -921,7 +921,7 @@ Scene2703::Scene2703(NeverhoodEngine *vm, Module *parentModule, int which, uint3 else sendMessage(_asCar, 0x2008, 150); } - + if (which == 0) { _palette->addPalette(calcHash("paPodShade"), 65, 31, 65); _palette->addPalette(calcHash("paKlayShade"), 0, 65, 0); @@ -931,9 +931,9 @@ Scene2703::Scene2703(NeverhoodEngine *vm, Module *parentModule, int which, uint3 _palette->addPalette(calcHash("paKlayBlack"), 0, 65, 0); _palStatus = 0; } - + _palette->copyBasePalette(0, 256, 0); - + } void Scene2703::update() { @@ -981,16 +981,16 @@ uint32 Scene2703::handleMessage(int messageNum, const MessageParam ¶m, Entit } return 0; } - + Scene2704::Scene2704(NeverhoodEngine *vm, Module *parentModule, int which, uint32 trackInfoId, int16 value, const uint32 *staticSprites, const NRect *clipRect) : Scene(vm, parentModule) { TrackInfo *tracks = _vm->_staticData->getTrackInfo(trackInfoId); - + SetMessageHandler(&Scene2704::handleMessage); SetUpdateHandler(&Scene2704::update); - + setBackground(tracks->bgFilename); setPalette(tracks->bgFilename); @@ -999,12 +999,12 @@ Scene2704::Scene2704(NeverhoodEngine *vm, Module *parentModule, int which, uint3 if (tracks->exPaletteFilename2) _palette->addPalette(tracks->exPaletteFilename2, 65, 31, 65); - + while (staticSprites && *staticSprites) insertStaticSprite(*staticSprites++, 1100); insertScreenMouse(tracks->mouseCursorFilename); - + if (tracks->bgShadowFilename) { _ssTrackShadowBackground = createSprite<SsCommonTrackShadowBackground>(tracks->bgShadowFilename); addEntity(_ssTrackShadowBackground); @@ -1024,7 +1024,7 @@ Scene2704::Scene2704(NeverhoodEngine *vm, Module *parentModule, int which, uint3 _dataResource.load(tracks->dataResourceFilename); _trackPoints = _dataResource.getPointArray(tracks->trackPointsName); _asCar->setPathPoints(_trackPoints); - + if (which == _which2) { NPoint testPoint = (*_trackPoints)[_trackPoints->size() - 1]; sendMessage(_asCar, 0x2002, _trackPoints->size() - 1); @@ -1040,21 +1040,21 @@ Scene2704::Scene2704(NeverhoodEngine *vm, Module *parentModule, int which, uint3 else sendMessage(_asCar, 0x2008, 0); } - + if (clipRect) { _asCar->getClipRect() = *clipRect; if (_asCarShadow) - _asCarShadow->getClipRect() = *clipRect; + _asCarShadow->getClipRect() = *clipRect; if (_asCarTrackShadow) - _asCarTrackShadow->getClipRect() = *clipRect; + _asCarTrackShadow->getClipRect() = *clipRect; if (_asCarConnectorShadow) - _asCarConnectorShadow->getClipRect() = *clipRect; + _asCarConnectorShadow->getClipRect() = *clipRect; if (_asCarConnector) _asCarConnector->getClipRect() = *clipRect; } } - + void Scene2704::update() { Scene::update(); if (_mouseClicked) { @@ -1083,24 +1083,24 @@ uint32 Scene2704::handleMessage(int messageNum, const MessageParam ¶m, Entit Scene2706::Scene2706(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _newTrackIndex(-1) { - + SetMessageHandler(&Scene2706::handleMessage); - _tracks.push_back(_vm->_staticData->getTrackInfo(0x004B22A0)); + _tracks.push_back(_vm->_staticData->getTrackInfo(0x004B22A0)); _tracks.push_back(_vm->_staticData->getTrackInfo(0x004B22C4)); _tracks.push_back(_vm->_staticData->getTrackInfo(0x004B22E8)); - + setBackground(0x18808B88); setPalette(0x18808B88); - + _palette->addPalette(calcHash("paPodShade"), 65, 31, 65); _palette->addPalette(calcHash("paKlayShade"), 0, 65, 0); - + insertScreenMouse(0x08B8C180); _ssTrackShadowBackground = createSprite<SsCommonTrackShadowBackground>(0x18808B88); addEntity(_ssTrackShadowBackground); - + _asCar = insertSprite<AsCommonCar>(this, 320, 240); _asCarShadow = insertSprite<AsCommonCarShadow>(_asCar, _ssTrackShadowBackground->getSurface(), 4); _asCarConnector = insertSprite<AsCommonCarConnector>(_asCar); @@ -1108,10 +1108,10 @@ Scene2706::Scene2706(NeverhoodEngine *vm, Module *parentModule, int which) _asCarConnectorShadow = insertSprite<AsCommonCarConnectorShadow>(_asCar, _ssTrackShadowBackground->getSurface(), 4); _dataResource.load(0x06000162); - + if (which == 5) _currTrackIndex = 2; - else if (which == 6) + else if (which == 6) _currTrackIndex = 1; else _currTrackIndex = 0; @@ -1123,16 +1123,16 @@ Scene2706::Scene2706(NeverhoodEngine *vm, Module *parentModule, int which) sendMessage(_asCar, 0x2002, _trackPoints->size() - 1); if (which == 5) sendMessage(_asCar, 0x2007, 50); - else + else sendMessage(_asCar, 0x2007, 150); } else { sendMessage(_asCar, 0x2002, 0); if (which == 5) sendMessage(_asCar, 0x2008, 50); - else + else sendMessage(_asCar, 0x2008, 150); } - + } uint32 Scene2706::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -1192,7 +1192,7 @@ void Scene2706::changeTrack() { Scene2732::Scene2732(NeverhoodEngine *vm, Module *parentModule) : Scene(vm, parentModule) { - + Sprite *tempSprite; setBackground(0x0220C041); diff --git a/engines/neverhood/modules/module2700.h b/engines/neverhood/modules/module2700.h index 003666bb7f..158bb609e9 100644 --- a/engines/neverhood/modules/module2700.h +++ b/engines/neverhood/modules/module2700.h @@ -39,7 +39,7 @@ public: protected: int _sceneNum; int _soundIndex; - bool _raidoMusicInitialized; + bool _radioMusicInitialized; uint32 _scene2711StaticSprites[6]; uint32 _musicFileHash; void createScene(int sceneNum, int which); diff --git a/engines/neverhood/modules/module2800.cpp b/engines/neverhood/modules/module2800.cpp index 26df0aefa5..1c0f9fc9fb 100644 --- a/engines/neverhood/modules/module2800.cpp +++ b/engines/neverhood/modules/module2800.cpp @@ -36,7 +36,7 @@ Module2800::Module2800(NeverhoodEngine *vm, Module *parentModule, int which) _currentMusicFileHash = 0; _vm->_soundMan->addMusic(0x64210814, 0xD2FA4D14); setGlobalVar(V_RADIO_MOVE_DISH_VIDEO, 1); - + if (which < 0) { createScene(_vm->gameState().sceneNum, which); } else if (which == 2) { @@ -58,7 +58,7 @@ Module2800::~Module2800() { } void Module2800::createScene(int sceneNum, int which) { - debug("Module2800::createScene(%d, %d)", sceneNum, which); + debug(1, "Module2800::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -224,7 +224,7 @@ void Module2800::updateScene() { _musicResource = NULL; } _currentMusicFileHash = 0; - } + } if (_moduleResult == 1) { createScene(2, 0); } else if (_moduleResult == 2) { @@ -251,7 +251,7 @@ void Module2800::updateScene() { createScene(9, 0); else if (_moduleResult == 5) createScene(25, 0); - else + else createScene(0, 1); break; case 3: @@ -318,7 +318,7 @@ void Module2800::updateScene() { createScene(22, 0); else if (_moduleResult == 22) createScene(23, 0); - else + else createScene(2, 4); break; case 10: @@ -331,7 +331,7 @@ void Module2800::updateScene() { createScene(26, 0); else if (_moduleResult == 3) createScene(9, 5); - else + else createScene(9, 1); break; case 12: @@ -401,7 +401,7 @@ void Module2800::updateMusic(bool halfVolume) { if (!_musicResource) _musicResource = new MusicResource(_vm); - + if (newMusicFileHash != _currentMusicFileHash) { _currentMusicFileHash = newMusicFileHash; if (_currentMusicFileHash != 0) { @@ -469,7 +469,7 @@ Scene2801::Scene2801(NeverhoodEngine *vm, Module *parentModule, int which) _klaymen->setClipRect(_sprite1->getDrawRect().x, 0, _sprite2->getDrawRect().x2(), 480); insertScreenMouse(0x0066201C); _asTape = insertSprite<AsScene1201Tape>(this, 8, 1100, 302, 437, 0x9148A011); - addCollisionSprite(_asTape); + addCollisionSprite(_asTape); } else if (getGlobalVar(V_RADIO_ROOM_RIGHT_DOOR)) { setRectList(0x004B6CD0); setBackground(0x11E00684); @@ -480,7 +480,7 @@ Scene2801::Scene2801(NeverhoodEngine *vm, Module *parentModule, int which) _klaymen->setClipRect(0, 0, _sprite2->getDrawRect().x2(), 480); insertScreenMouse(0x00680116); _asTape = insertSprite<SsScene1705Tape>(this, 8, 1100, 302, 437, 0x01142428); - addCollisionSprite(_asTape); + addCollisionSprite(_asTape); } else { setRectList(0x004B6CF0); setBackground(0x030006E6); @@ -491,9 +491,9 @@ Scene2801::Scene2801(NeverhoodEngine *vm, Module *parentModule, int which) _klaymen->setClipRect(0, 0, _sprite2->getDrawRect().x2(), 480); insertScreenMouse(0x006E2038); _asTape = insertSprite<AsScene1201Tape>(this, 8, 1100, 302, 437, 0x9148A011); - addCollisionSprite(_asTape); + addCollisionSprite(_asTape); } - + addEntity(_palette); if (which == 1) { @@ -503,7 +503,7 @@ Scene2801::Scene2801(NeverhoodEngine *vm, Module *parentModule, int which) _palette->addPalette(_paletteHash, 0, 65, 0); _palette->addBasePalette(_paletteHash, 0, 65, 0); } - + } Scene2801::~Scene2801() { @@ -565,7 +565,7 @@ Scene2802::~Scene2802() { } setGlobalVar(V_CURR_RADIO_MUSIC_INDEX, _currRadioMusicIndex); } - + void Scene2802::update() { int prevTuneStatus = _currTuneStatus; uint prevRadioMusicIndex = _currRadioMusicIndex; @@ -577,7 +577,7 @@ void Scene2802::update() { _currTuneStatus = 3; else if (_currTuneStatus == 4) _currTuneStatus = 6; - + switch (_currTuneStatus) { case 2: if (_currRadioMusicIndex < 90) @@ -607,24 +607,20 @@ void Scene2802::update() { } else _currTuneStatus = 0; break; - + } if (prevRadioMusicIndex != _currRadioMusicIndex) _smackerPlayer->gotoFrame(_currRadioMusicIndex); - + if (prevTuneStatus != _currTuneStatus) changeTuneStatus(prevTuneStatus, _currTuneStatus); - - //DEBUG>>> - //debug("_currRadioMusicIndex = %d; V_GOOD_RADIO_MUSIC_INDEX = %d", _currRadioMusicIndex, getGlobalVar(V_GOOD_RADIO_MUSIC_INDEX)); - //DEBUG<<< if (getGlobalVar(V_RADIO_MOVE_DISH_VIDEO) && prevTuneStatus != _currTuneStatus && _currRadioMusicIndex != 0) { setGlobalVar(V_RADIO_MOVE_DISH_VIDEO, 0); leaveScene(1); } - + } uint32 Scene2802::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -762,7 +758,7 @@ void AsScene2803LightCord::setFileHashes(uint32 fileHash1, uint32 fileHash2) { AsScene2803TestTubeOne::AsScene2803TestTubeOne(NeverhoodEngine *vm, uint32 fileHash1, uint32 fileHash2) : AnimatedSprite(vm, 1200), _fileHash1(fileHash1), _fileHash2(fileHash2) { - + createSurface1(fileHash1, 100); SetUpdateHandler(&AnimatedSprite::update); SetMessageHandler(&AsScene2803TestTubeOne::handleMessage); @@ -785,7 +781,7 @@ uint32 AsScene2803TestTubeOne::handleMessage(int messageNum, const MessageParam AsScene2803Rope::AsScene2803Rope(NeverhoodEngine *vm, Scene *parentScene, int16 x) : AnimatedSprite(vm, 1100), _parentScene(parentScene) { - + createSurface(990, 68, 476); SetUpdateHandler(&AnimatedSprite::update); SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); @@ -841,7 +837,7 @@ void AsScene2803Rope::stHide() { Scene2803::Scene2803(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _paletteArea(0) { - + static const uint32 kScene2803FileHashes1[] = { 0, 0x081000F1, @@ -858,20 +854,20 @@ Scene2803::Scene2803(NeverhoodEngine *vm, Module *parentModule, int which) setGlobalVar(V_BEEN_SHRINKING_ROOM, 1); _vm->gameModule()->initTestTubes1Puzzle(); - + SetMessageHandler(&Scene2803::handleMessage); - + loadDataResource(0x00900849); - + _background = new Background(_vm, 0); _background->createSurface(0, 640, 480); addBackground(_background); - + setPalette(0x412A423E); addEntity(_palette); - + insertScreenMouse(0xA423A41A); - + if (getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 0) == 0) { _asTestTubeOne = (StaticSprite*)insertStaticSprite(0x66121222, 100); } else { @@ -879,13 +875,13 @@ Scene2803::Scene2803(NeverhoodEngine *vm, Module *parentModule, int which) kScene2803FileHashes1[getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 0)], kScene2803FileHashes2[getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 0)]); } - + if (getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 1) == 3) _asTestTubeTwo = (StaticSprite*)insertStaticSprite(0x64330236, 100); if (getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 2) == 3) _asTestTubeThree = (StaticSprite*)insertStaticSprite(0x2E4A22A2, 100); - + _asLightCord = insertSprite<AsScene2803LightCord>(this, 0x8FAD5932, 0x276E1A3D, 578, 200); _sprite3 = (StaticSprite*)insertStaticSprite(0xA40EF2FB, 1100); _sprite4 = (StaticSprite*)insertStaticSprite(0x0C03AA23, 1100); @@ -900,7 +896,7 @@ Scene2803::Scene2803(NeverhoodEngine *vm, Module *parentModule, int which) _clipRectsFloor[0].y1 = 0; _clipRectsFloor[0].x2 = 640; _clipRectsFloor[0].y2 = _sprite8->getDrawRect().y2(); - + _clipRectsFloor[1].x1 = _sprite8->getDrawRect().x2(); _clipRectsFloor[1].y1 = _sprite8->getDrawRect().y2(); _clipRectsFloor[1].x2 = 640; @@ -910,12 +906,12 @@ Scene2803::Scene2803(NeverhoodEngine *vm, Module *parentModule, int which) _clipRectsStairs[0].y1 = 0; _clipRectsStairs[0].x2 = _sprite5->getDrawRect().x2(); _clipRectsStairs[0].y2 = _sprite5->getDrawRect().y2(); - + _clipRectsStairs[1].x1 = _sprite6->getDrawRect().x; _clipRectsStairs[1].y1 = 0; _clipRectsStairs[1].x2 = _sprite3->getDrawRect().x; _clipRectsStairs[1].y2 = _sprite6->getDrawRect().y2(); - + _clipRectsStairs[2].x1 = _sprite3->getDrawRect().x; _clipRectsStairs[2].y1 = 0; _clipRectsStairs[2].x2 = _sprite4->getDrawRect().x2(); @@ -1116,7 +1112,7 @@ Scene2803Small::Scene2803Small(NeverhoodEngine *vm, Module *parentModule, int wh static const uint32 kScene2803SmallFileHashes2[] = { 0, 0x286800D4, 0x286806D4, 0x28680AD4 }; - + SetMessageHandler(&Scene2803Small::handleMessage); loadDataResource(0x81120132); @@ -1164,7 +1160,7 @@ Scene2803Small::Scene2803Small(NeverhoodEngine *vm, Module *parentModule, int wh if (getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 2) == 3) insertStaticSprite(0x30022689, 100); } - + _sprite6->setVisible(false); _sprite7->setVisible(false); @@ -1356,7 +1352,7 @@ void Scene2803Small::updatePaletteArea(bool instantly) { SsScene2804RedButton::SsScene2804RedButton(NeverhoodEngine *vm, Scene2804 *parentScene) : StaticSprite(vm, 900), _countdown(0), _parentScene(parentScene) { - + loadSprite(getGlobalVar(V_SHRINK_LIGHTS_ON) ? 0x51A10202 : 0x11814A21, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); setVisible(false); SetUpdateHandler(&SsScene2804RedButton::update); @@ -1389,7 +1385,7 @@ uint32 SsScene2804RedButton::handleMessage(int messageNum, const MessageParam &p SsScene2804LightCoil::SsScene2804LightCoil(NeverhoodEngine *vm) : StaticSprite(vm, 900) { - + loadSprite(0x8889B008, kSLFDefDrawOffset | kSLFDefPosition, 400); setVisible(false); SetMessageHandler(&SsScene2804LightCoil::handleMessage); @@ -1414,7 +1410,7 @@ uint32 SsScene2804LightCoil::handleMessage(int messageNum, const MessageParam &p SsScene2804LightTarget::SsScene2804LightTarget(NeverhoodEngine *vm) : StaticSprite(vm, 900) { - + loadSprite(0x06092132, kSLFDefDrawOffset | kSLFDefPosition, 400); setVisible(false); SetMessageHandler(&SsScene2804LightTarget::handleMessage); @@ -1439,7 +1435,7 @@ uint32 SsScene2804LightTarget::handleMessage(int messageNum, const MessageParam SsScene2804Flash::SsScene2804Flash(NeverhoodEngine *vm) : StaticSprite(vm, 900) { - + loadSprite(0x211003A0, kSLFDefDrawOffset | kSLFDefPosition, 400); setVisible(false); loadSound(0, 0xCB36BA54); @@ -1453,7 +1449,7 @@ void SsScene2804Flash::show() { SsScene2804BeamCoilBody::SsScene2804BeamCoilBody(NeverhoodEngine *vm) : StaticSprite(vm, 900) { - + loadSprite(0x9A816000, kSLFDefDrawOffset | kSLFDefPosition, 400); setVisible(false); } @@ -1589,7 +1585,7 @@ SsScene2804CrystalButton::SsScene2804CrystalButton(NeverhoodEngine *vm, Scene280 0xA8042525, 0x5008292B }; - + loadSprite(getGlobalVar(V_SHRINK_LIGHTS_ON) ? kSsScene2804CrystalButtonFileHashes1[crystalIndex] : kSsScene2804CrystalButtonFileHashes2[crystalIndex], kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); setVisible(false); @@ -1623,7 +1619,7 @@ uint32 SsScene2804CrystalButton::handleMessage(int messageNum, const MessagePara AsScene2804BeamCoil::AsScene2804BeamCoil(NeverhoodEngine *vm, Scene *parentScene, SsScene2804BeamCoilBody *ssBeamCoilBody) : AnimatedSprite(vm, 1400), _parentScene(parentScene), _ssBeamCoilBody(ssBeamCoilBody), _countdown(0) { - + createSurface1(0x00494891, 1000); _x = 125; _y = 184; @@ -1663,7 +1659,7 @@ uint32 AsScene2804BeamCoil::handleMessage(int messageNum, const MessageParam &pa } return messageResult; } - + void AsScene2804BeamCoil::show() { _ssBeamCoilBody->setVisible(true); setVisible(true); @@ -1699,7 +1695,7 @@ uint32 AsScene2804BeamCoil::hmBeaming(int messageNum, const MessageParam ¶m, AsScene2804BeamTarget::AsScene2804BeamTarget(NeverhoodEngine *vm) : AnimatedSprite(vm, 1400) { - + createSurface1(0x03842000, 1000); _x = 475; _y = 278; @@ -1754,7 +1750,7 @@ Scene2804::Scene2804(NeverhoodEngine *vm, Module *parentModule, int which) _asTarget = insertSprite<AsScene2804BeamTarget>(); _ssFlash = insertSprite<SsScene2804Flash>(); } - + _ssRedButton = insertSprite<SsScene2804RedButton>(this); addCollisionSprite(_ssRedButton); @@ -1801,7 +1797,7 @@ uint32 Scene2804::handleMessage(int messageNum, const MessageParam ¶m, Entit void Scene2804::update() { Scene::update(); - + if (_countdown1 != 0 && (--_countdown1) == 0) { leaveScene(0); } @@ -1840,7 +1836,7 @@ void Scene2804::update() { Scene2805::Scene2805(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { - + SetMessageHandler(&Scene2805::handleMessage); setBackground(0x08021E04); @@ -1898,7 +1894,7 @@ uint32 Scene2805::handleMessage(int messageNum, const MessageParam ¶m, Entit AsScene2806Spew::AsScene2806Spew(NeverhoodEngine *vm) : AnimatedSprite(vm, 1200) { - + createSurface1(0x04211490, 1200); _x = 378; _y = 423; @@ -1923,7 +1919,7 @@ uint32 AsScene2806Spew::handleMessage(int messageNum, const MessageParam ¶m, } return messageResult; } - + Scene2806::Scene2806(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { @@ -1931,16 +1927,16 @@ Scene2806::Scene2806(NeverhoodEngine *vm, Module *parentModule, int which) SetMessageHandler(&Scene2806::handleMessage); SetUpdateHandler(&Scene2806::update); - + loadDataResource(0x98182003); loadHitRectList(); - + _pointList = _dataResource.getPointArray(0x3606A422); - insertScreenMouse(0x22114C13); + insertScreenMouse(0x22114C13); setBackground(0xC1B22110); setPalette(0xC1B22110); - + _sprite1 = insertStaticSprite(0xA21F82CB, 1100); _clipRects[0].x1 = _sprite1->getDrawRect().x; _clipRects[0].y1 = _sprite1->getDrawRect().y; @@ -1955,7 +1951,7 @@ Scene2806::Scene2806(NeverhoodEngine *vm, Module *parentModule, int which) _sprite4 = insertStaticSprite(0x72090342, 1100); _clipRects[1].x1 = _sprite4->getDrawRect().x; _clipRects[1].y1 = _sprite4->getDrawRect().y; - + tempSprite = insertStaticSprite(0xD2012C02, 1100); _clipRects[2].x1 = tempSprite->getDrawRect().x; _clipRects[2].y2 = tempSprite->getDrawRect().y2(); @@ -2031,7 +2027,7 @@ void Scene2806::findClosestPoint() { int16 x = MIN<int16>(_klaymen->getX(), 639); int index = 1; - + while (index < (int)_pointList->size() && (*_pointList)[index].x < x) ++index; --index; @@ -2040,12 +2036,12 @@ void Scene2806::findClosestPoint() { _pointIndex = index; _palette->addPalette(kScene2806PaletteFileHashes[index], 0, 64, 0); } - + } Scene2807::Scene2807(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { - + SetMessageHandler(&Scene2807::handleMessage); if (getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 0) == 1) { @@ -2140,7 +2136,7 @@ static const int16 kClass490FrameIndices2[] = { SsScene2808Dispenser::SsScene2808Dispenser(NeverhoodEngine *vm, Scene *parentScene, int testTubeSetNum, int testTubeIndex) : StaticSprite(vm, 900), _parentScene(parentScene), _countdown(0), _testTubeSetNum(testTubeSetNum), _testTubeIndex(testTubeIndex) { - + loadSprite(kClass428FileHashes[testTubeSetNum * 3 + testTubeIndex], kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 1500); setVisible(false); SetUpdateHandler(&SsScene2808Dispenser::update); @@ -2153,7 +2149,7 @@ void SsScene2808Dispenser::update() { setVisible(false); } } - + uint32 SsScene2808Dispenser::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); switch (messageNum) { @@ -2201,16 +2197,16 @@ AsScene2808TestTube::AsScene2808TestTube(NeverhoodEngine *vm, int testTubeSetNum loadSound(7, 0x70A43D2D); loadSound(8, 0xF0601E2D); } - + startAnimation(kClass490FileHashes[testTubeIndex], 0, -1); _newStickFrameIndex = 0; - + SetUpdateHandler(&AnimatedSprite::update); SetMessageHandler(&AsScene2808TestTube::handleMessage); - + if (_fillLevel == 0) setVisible(false); - + } uint32 AsScene2808TestTube::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -2257,7 +2253,7 @@ void AsScene2808TestTube::flush() { AsScene2808Handle::AsScene2808Handle(NeverhoodEngine *vm, Scene *parentScene, int testTubeSetNum) : AnimatedSprite(vm, 1300), _parentScene(parentScene), _testTubeSetNum(testTubeSetNum), _isActivated(false) { - + loadSound(0, 0xE18D1F30); _x = 320; _y = 240; @@ -2329,7 +2325,7 @@ AsScene2808Flow::AsScene2808Flow(NeverhoodEngine *vm, Scene *parentScene, int te SetUpdateHandler(&AnimatedSprite::update); AnimatedSprite::updatePosition(); } - + uint32 AsScene2808Flow::hmFlowing(int messageNum, const MessageParam ¶m, Entity *sender) { uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); switch (messageNum) { @@ -2355,7 +2351,7 @@ void AsScene2808Flow::stKeepFlowing() { AsScene2808LightEffect::AsScene2808LightEffect(NeverhoodEngine *vm, int testTubeSetNum) : AnimatedSprite(vm, 800), _countdown(1) { - + _x = 320; _y = 240; if (testTubeSetNum == 1) @@ -2385,7 +2381,7 @@ Scene2808::Scene2808(NeverhoodEngine *vm, Module *parentModule, int which) _vm->gameModule()->initTestTubes1Puzzle(); else _vm->gameModule()->initTestTubes2Puzzle(); - + SetMessageHandler(&Scene2808::handleMessage); SetUpdateHandler(&Scene2808::update); @@ -2404,7 +2400,7 @@ Scene2808::Scene2808(NeverhoodEngine *vm, Module *parentModule, int which) _asTestTubes[testTubeIndex] = insertSprite<AsScene2808TestTube>(which, testTubeIndex, ssDispenser); addCollisionSprite(_asTestTubes[testTubeIndex]); } - + insertScreenMouse(kScene2808FileHashes2[which]); } @@ -2443,18 +2439,6 @@ uint32 Scene2808::handleMessage(int messageNum, const MessageParam ¶m, Entit } void Scene2808::update() { - - // DEBUG>>> Show correct values - #if 1 - debug("---------------"); - if (_testTubeSetNum == 0) - debug("%03d %03d %03d", getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 0), getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 1), getSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, 2)); - else - debug("%03d %03d %03d", getSubVar(VA_GOOD_TEST_TUBES_LEVEL_2, 0), getSubVar(VA_GOOD_TEST_TUBES_LEVEL_2, 1), getSubVar(VA_GOOD_TEST_TUBES_LEVEL_2, 2)); - debug("%03d %03d %03d", _asTestTubes[0]->getFillLevel(), _asTestTubes[1]->getFillLevel(), _asTestTubes[2]->getFillLevel()); - #endif - // DEBUG<<< - Scene::update(); if (_countdown != 0 && (--_countdown) == 0) { leaveScene(_leaveResult); @@ -2514,13 +2498,13 @@ Scene2809::Scene2809(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule) { Sprite *tempSprite; - + SetMessageHandler(&Scene2809::handleMessage); SetUpdateHandler(&Scene2809::update); - + loadDataResource(0x1830009A); loadHitRectList(); - + _pointList = _dataResource.getPointArray(0x064A310E); setBackground(0xB22116C5); @@ -2551,7 +2535,7 @@ Scene2809::Scene2809(NeverhoodEngine *vm, Module *parentModule, int which) tempSprite = insertStaticSprite(0x877F6252, 1100); _clipRects[3].x2 = tempSprite->getDrawRect().x2(); - + insertStaticSprite(0x01612A22, 1100); insertStaticSprite(0x877F6252, 1100); @@ -2626,7 +2610,7 @@ void Scene2809::findClosestPoint() { _pointIndex = index; _palette->addPalette(kScene2809PaletteFileHashes[index], 0, 64, 0); } - + } AsScene2810Rope::AsScene2810Rope(NeverhoodEngine *vm, Scene *parentScene, int16 x) @@ -2663,7 +2647,7 @@ Scene2810::Scene2810(NeverhoodEngine *vm, Module *parentModule, int which) Sprite *tempSprite; SetMessageHandler(&Scene2810::handleMessage); - + setBackground(0x26508804); setPalette(0x26508804); insertScreenMouse(0x0880026D); @@ -2699,7 +2683,7 @@ Scene2810::Scene2810(NeverhoodEngine *vm, Module *parentModule, int which) } _sprite4->setClipRect(0, _sprite1->getDrawRect().y, 640, 480); } - + if (which < 0) { if (getGlobalVar(V_KLAYMEN_SMALL)) { insertKlaymen<KmScene2810Small>(240, 448); @@ -2880,7 +2864,7 @@ uint32 Scene2810::handleMessage(int messageNum, const MessageParam ¶m, Entit AsScene2812Winch::AsScene2812Winch(NeverhoodEngine *vm) : AnimatedSprite(vm, 1100) { - + createSurface1(0x20DA08A0, 1200); SetUpdateHandler(&AnimatedSprite::update); SetMessageHandler(&AsScene2812Winch::handleMessage); @@ -2911,7 +2895,7 @@ uint32 AsScene2812Winch::handleMessage(int messageNum, const MessageParam ¶m AsScene2812Rope::AsScene2812Rope(NeverhoodEngine *vm, Scene *parentScene) : AnimatedSprite(vm, 1100), _parentScene(parentScene) { - + createSurface(990, 68, 476); SetUpdateHandler(&AnimatedSprite::update); SetMessageHandler(&AsScene2812Rope::handleMessage); @@ -2956,7 +2940,7 @@ void AsScene2812Rope::stRopingDown() { AsScene2812TrapDoor::AsScene2812TrapDoor(NeverhoodEngine *vm) : AnimatedSprite(vm, 0x805D0029, 100, 320, 240) { - + SetMessageHandler(&AsScene2812TrapDoor::handleMessage); _newStickFrameIndex = 0; } @@ -2975,15 +2959,15 @@ uint32 AsScene2812TrapDoor::handleMessage(int messageNum, const MessageParam &pa Scene2812::Scene2812(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _paletteArea(0) { - + if (getGlobalVar(V_HAS_FINAL_KEY) && getGlobalVar(V_KEY3_LOCATION) == 0) setGlobalVar(V_KEY3_LOCATION, 3); SetMessageHandler(&Scene2812::handleMessage); SetUpdateHandler(&Scene2812::update); - + setRectList(0x004AF700); - + setBackground(0x03600606); setPalette(0x03600606); addEntity(_palette); @@ -2999,7 +2983,7 @@ Scene2812::Scene2812(NeverhoodEngine *vm, Module *parentModule, int which) _ssTape = insertSprite<SsScene1705Tape>(this, 6, 1100, 513, 437, 0xA1361863); addCollisionSprite(_ssTape); - + _asWinch = insertSprite<AsScene2812Winch>(); _asTrapDoor = insertSprite<AsScene2812TrapDoor>(); _asRope = insertSprite<AsScene2812Rope>(this); @@ -3039,9 +3023,9 @@ Scene2812::Scene2812(NeverhoodEngine *vm, Module *parentModule, int which) _sprite1->setVisible(false); _klaymen->setClipRect(_sprite4->getDrawRect().x, 0, 640, _sprite3->getDrawRect().y2()); } - + _asRope->setClipRect(0, _sprite2->getDrawRect().y, 640, _sprite3->getDrawRect().y2()); - + } void Scene2812::update() { @@ -3136,7 +3120,7 @@ Scene2822::Scene2822(NeverhoodEngine *vm, Module *parentModule, int which) addBackground(_background); _background->getSurface()->getDrawRect().y = -10; setPalette(0xD542022E); - insertPuzzleMouse(0x0028D089, 20, 620); + insertPuzzleMouse(0x2022AD5C, 20, 620); _ssButton = insertStaticSprite(0x1A4D4120, 1100); _ssButton->setVisible(false); loadSound(2, 0x19044E72); @@ -3156,7 +3140,7 @@ void Scene2822::update() { _ssButton->setVisible(false); _countdownStatus = 1; _countdown = 48; - } else if (_countdownStatus == 1) { + } else if (_countdownStatus == 1 && getGlobalVar(V_LADDER_DOWN_ACTION)) { playSound(0, 0x1384CB60); _countdownStatus = 2; _countdown = 12; diff --git a/engines/neverhood/modules/module2800.h b/engines/neverhood/modules/module2800.h index fe62f11307..54a9daeb16 100644 --- a/engines/neverhood/modules/module2800.h +++ b/engines/neverhood/modules/module2800.h @@ -79,7 +79,7 @@ public: protected: Scene *_parentScene; uint32 _fileHash1, _fileHash2; - bool _isPulled, _isBusy; + bool _isPulled, _isBusy; uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); uint32 hmPulled(int messageNum, const MessageParam ¶m, Entity *sender); }; @@ -323,7 +323,7 @@ protected: Scene *_parentScene; int _countdown; int _testTubeSetNum, _testTubeIndex; - void update(); + void update(); uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; @@ -408,7 +408,7 @@ protected: Sprite *_sprite3; Sprite *_sprite4; Sprite *_asSpew; - void update(); + void update(); uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); void findClosestPoint(); }; diff --git a/engines/neverhood/modules/module2900.cpp b/engines/neverhood/modules/module2900.cpp index bd95b82f4c..9e51001a2e 100644 --- a/engines/neverhood/modules/module2900.cpp +++ b/engines/neverhood/modules/module2900.cpp @@ -36,13 +36,13 @@ Module2900::Module2900(NeverhoodEngine *vm, Module *parentModule, int which) if (which >= 0) setGlobalVar(V_TELEPORTER_WHICH, which); - + createScene(0, 0); } void Module2900::createScene(int sceneNum, int which) { - debug("Module2900::createScene(%d, %d)", sceneNum, which); + debug(1, "Module2900::createScene(%d, %d)", sceneNum, which); _sceneNum = sceneNum; switch (_sceneNum) { case 0: @@ -255,7 +255,7 @@ SsScene2901LocationButton::SsScene2901LocationButton(NeverhoodEngine *vm, Scene : StaticSprite(vm, 900), _parentScene(parentScene), _index(index), _countdown1(0) { const NPoint &pt = kSsScene2901LocationButtonPoints[_index]; - + loadSprite(kSsScene2901LocationButtonFileHashes[which * 6 + index], kSLFDefDrawOffset | kSLFDefPosition, 800); _collisionBounds.set(pt.x - 25, pt.y - 25, pt.x + 25, pt.y + 25); setVisible(false); @@ -263,7 +263,7 @@ SsScene2901LocationButton::SsScene2901LocationButton(NeverhoodEngine *vm, Scene SetUpdateHandler(&SsScene2901LocationButton::update); SetMessageHandler(&SsScene2901LocationButton::handleMessage); } - + void SsScene2901LocationButton::update() { updatePosition(); if (_countdown1 != 0 && (--_countdown1) == 0) { @@ -289,7 +289,7 @@ uint32 SsScene2901LocationButton::handleMessage(int messageNum, const MessagePar SsScene2901LocationButtonLight::SsScene2901LocationButtonLight(NeverhoodEngine *vm, int which, uint index) : StaticSprite(vm, 900), _index(index) { - + loadSprite(kSsScene2901LocationButtonLightFileHashes1[which * 6 + index], kSLFDefDrawOffset | kSLFDefPosition, 900); setVisible(false); loadSound(0, kSsScene2901LocationButtonLightFileHashes2[_index]); @@ -315,7 +315,7 @@ SsScene2901BrokenButton::SsScene2901BrokenButton(NeverhoodEngine *vm, int which) SsScene2901BigButton::SsScene2901BigButton(NeverhoodEngine *vm, Scene *parentScene, int which) : StaticSprite(vm, 900), _parentScene(parentScene), _which(which), _countdown1(0) { - loadSprite(kSsScene2901BigButtonFileHashes[which], kSLFDefDrawOffset | kSLFDefPosition, 400); + loadSprite(kSsScene2901BigButtonFileHashes[which], kSLFDefDrawOffset | kSLFDefPosition, 400); _collisionBounds.set(62, 94, 322, 350); setVisible(false); loadSound(0, 0xF3D420C8); @@ -330,7 +330,7 @@ void SsScene2901BigButton::update() { sendMessage(_parentScene, 0x2000, 0); } } - + uint32 SsScene2901BigButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); switch (messageNum) { @@ -361,7 +361,7 @@ Scene2901::Scene2901(NeverhoodEngine *vm, Module *parentModule, int which) setBackground(kScene2901FileHashes1[_currLocationButtonNum]); setPalette(kScene2901FileHashes1[_currLocationButtonNum]); - + for (uint i = 0; i < 6; ++i) { if (i != 2 || !_isButton2Broken) { _ssLocationButtons[i] = insertSprite<SsScene2901LocationButton>(this, _currLocationButtonNum, i); @@ -369,7 +369,7 @@ Scene2901::Scene2901(NeverhoodEngine *vm, Module *parentModule, int which) _ssLocationButtonLights[i] = insertSprite<SsScene2901LocationButtonLight>(_currLocationButtonNum, i); } } - + if (_isButton2Broken) insertSprite<SsScene2901BrokenButton>(_currLocationButtonNum); @@ -377,10 +377,10 @@ Scene2901::Scene2901(NeverhoodEngine *vm, Module *parentModule, int which) addCollisionSprite(_ssBigButton); insertPuzzleMouse(kScene2901FileHashes2[_currLocationButtonNum], 20, 620); - + SetUpdateHandler(&Scene2901::update); SetMessageHandler(&Scene2901::handleMessage); - + } void Scene2901::update() { diff --git a/engines/neverhood/modules/module2900.h b/engines/neverhood/modules/module2900.h index 75b29567f6..142f39a35c 100644 --- a/engines/neverhood/modules/module2900.h +++ b/engines/neverhood/modules/module2900.h @@ -49,7 +49,7 @@ protected: Scene *_parentScene; uint _index; int _countdown1; - void update(); + void update(); uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; @@ -74,7 +74,7 @@ protected: Scene *_parentScene; int _which; int _countdown1; - void update(); + void update(); uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; diff --git a/engines/neverhood/modules/module3000.cpp b/engines/neverhood/modules/module3000.cpp index 2bdb9f0497..ab3c18d1f4 100644 --- a/engines/neverhood/modules/module3000.cpp +++ b/engines/neverhood/modules/module3000.cpp @@ -39,7 +39,7 @@ static const uint32 kModule3000SoundList[] = { Module3000::Module3000(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule), _soundVolume(0) { - + _vm->_soundMan->addSoundList(0x81293110, kModule3000SoundList); _vm->_soundMan->setSoundListParams(kModule3000SoundList, true, 50, 600, 5, 150); _vm->_soundMan->setSoundParams(0x90F0D1C3, false, 20000, 30000, 20000, 30000); @@ -49,7 +49,7 @@ Module3000::Module3000(NeverhoodEngine *vm, Module *parentModule, int which) _isWallBroken = getGlobalVar(V_WALL_BROKEN) != 0; - if (_isWallBroken) { + if (!_isWallBroken) { _vm->_soundMan->setSoundVolume(0x90F0D1C3, 0); _vm->_soundMan->playSoundLooping(0x90F0D1C3); } @@ -73,15 +73,16 @@ Module3000::~Module3000() { } void Module3000::createScene(int sceneNum, int which) { - static const byte kNavigationTypes05[] = {3, 0}; + static const byte kNavigationTypes05[] = {2, 0}; static const byte kNavigationTypes06[] = {5}; - debug("Module3000::createScene(%d, %d)", sceneNum, which); + debug(1, "Module3000::createScene(%d, %d)", sceneNum, which); _vm->gameState().sceneNum = sceneNum; + _isWallBroken = getGlobalVar(V_WALL_BROKEN) != 0; switch (_vm->gameState().sceneNum) { case 1: if (!getGlobalVar(V_BOLT_DOOR_OPEN)) { createNavigationScene(0x004B7C80, which); - } else if (getGlobalVar(V_WALL_BROKEN)) { + } else if (_isWallBroken) { createNavigationScene(0x004B7CE0, which); } else { createNavigationScene(0x004B7CB0, which); @@ -89,11 +90,11 @@ void Module3000::createScene(int sceneNum, int which) { break; case 2: _vm->_soundMan->playTwoSounds(0x81293110, 0x40030A51, 0xC862CA15, 0); - if (_isWallBroken) { + if (!_isWallBroken) { _soundVolume = 90; _vm->_soundMan->setSoundVolume(0x90F0D1C3, 90); } - if (getGlobalVar(V_WALL_BROKEN)) { + if (_isWallBroken) { createNavigationScene(0x004B7D58, which); } else { createNavigationScene(0x004B7D10, which); @@ -102,7 +103,7 @@ void Module3000::createScene(int sceneNum, int which) { case 3: if (getGlobalVar(V_STAIRS_DOWN)) createNavigationScene(0x004B7E60, which); - else if (getGlobalVar(V_WALL_BROKEN)) + else if (_isWallBroken) createNavigationScene(0x004B7DA0, which); else createNavigationScene(0x004B7E00, which); @@ -150,12 +151,12 @@ void Module3000::createScene(int sceneNum, int which) { // NOTE: Newly introduced sceneNums case 1001: if (!getGlobalVar(V_BOLT_DOOR_OPEN)) - if (getGlobalVar(V_WALL_BROKEN)) + if (_isWallBroken) createSmackerScene(0x00940021, true, true, false); else createSmackerScene(0x01140021, true, true, false); else - if (getGlobalVar(V_WALL_BROKEN)) + if (_isWallBroken) createSmackerScene(0x001011B1, true, true, false); else createSmackerScene(0x001021B1, true, true, false); @@ -299,7 +300,7 @@ void Module3000::updateScene() { } else if (frameNumber == 10) { _vm->_soundMan->playTwoSounds(0x81293110, 0x40030A51, 0xC862CA15, 0); } - if (_isWallBroken && _soundVolume < 90 && frameNumber % 2) { + if (!_isWallBroken && _soundVolume < 90 && frameNumber % 2) { if (frameNumber == 0) _soundVolume = 40; else @@ -313,7 +314,7 @@ void Module3000::updateScene() { if (navigationScene()->isWalkingForward()) { uint32 frameNumber = navigationScene()->getFrameNumber(); int navigationIndex = navigationScene()->getNavigationIndex(); - if (_isWallBroken && _soundVolume > 1 && frameNumber % 2) { + if (!_isWallBroken && _soundVolume > 1 && frameNumber % 2) { _soundVolume--; _vm->_soundMan->setSoundVolume(0x90F0D1C3, _soundVolume); } @@ -338,7 +339,7 @@ void Module3000::updateScene() { if (frameNumber == 40) { _vm->_soundMan->playTwoSounds(0x81293110, 0x40030A51, 0xC862CA15, 0); } - if (_isWallBroken && _soundVolume < 90 && frameNumber % 2) { + if (!_isWallBroken && _soundVolume < 90 && frameNumber % 2) { if (frameNumber == 0) _soundVolume = 40; else @@ -439,7 +440,7 @@ static const uint32 kAsScene3009SymbolFileHashes[] = { }; static const uint32 kSsScene3009SymbolArrowFileHashes1[] = { - 0x24016060, + 0x24016060, 0x21216221, 0x486160A0, 0x42216422, @@ -454,7 +455,7 @@ static const uint32 kSsScene3009SymbolArrowFileHashes1[] = { }; static const uint32 kSsScene3009SymbolArrowFileHashes2[] = { - 0x40092024, + 0x40092024, 0x01636002, 0x8071E028, 0x02A56064, @@ -470,7 +471,7 @@ static const uint32 kSsScene3009SymbolArrowFileHashes2[] = { SsScene3009FireCannonButton::SsScene3009FireCannonButton(NeverhoodEngine *vm, Scene3009 *parentScene) : StaticSprite(vm, 1400), _parentScene(parentScene), _isClicked(false) { - + loadSprite(0x120B24B0, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); setVisible(false); SetUpdateHandler(&SsScene3009FireCannonButton::update); @@ -636,7 +637,7 @@ uint32 AsScene3009VerticalIndicator::handleMessage(int messageNum, const Message AsScene3009HorizontalIndicator::AsScene3009HorizontalIndicator(NeverhoodEngine *vm, Scene3009 *parentScene, uint32 cannonTargetStatus) : AnimatedSprite(vm, 1000), _parentScene(parentScene), _enabled(false) { - + _x = getGlobalVar(V_CANNON_TURNED) ? 533 : 92; _y = 150; createSurface1(0xC0C12954, 1200); @@ -701,7 +702,7 @@ AsScene3009Symbol::AsScene3009Symbol(NeverhoodEngine *vm, Scene3009 *parentScene : AnimatedSprite(vm, 1100), _parentScene(parentScene), _symbolPosition(symbolPosition) { _symbolIndex = getSubVar(VA_CURR_CANNON_SYMBOLS, _symbolPosition); - + _x = kAsScene3009SymbolPoints[_symbolPosition].x; _y = kAsScene3009SymbolPoints[_symbolPosition].y; createSurface1(kAsScene3009SymbolFileHashes[_symbolPosition / 3], 1200); @@ -752,17 +753,17 @@ void AsScene3009Symbol::hide() { } Scene3009::Scene3009(NeverhoodEngine *vm, Module *parentModule, int which) - : Scene(vm, parentModule), _keepVideo(false), _moveCannonLeftFirst(false), + : Scene(vm, parentModule), _keepVideo(false), _moveCannonLeftFirst(false), _isTurning(false), _lockSymbolsPart1Countdown(1), _lockSymbolsPart2Countdown(1) { _cannonTargetStatus = getGlobalVar(V_CANNON_TARGET_STATUS); - + _vm->gameModule()->initCannonSymbolsPuzzle(); - + setGlobalVar(V_CANNON_SMACKER_NAME, 0); - + _vm->_screen->clear(); - + setBackground(0xD000420C); setPalette(0xD000420C); insertPuzzleMouse(0x04208D08, 20, 620); @@ -786,8 +787,8 @@ Scene3009::Scene3009(NeverhoodEngine *vm, Module *parentModule, int which) } } - _smackerPlayer = addSmackerPlayer(new SmackerPlayer(_vm, this, kScene3009CannonScopeVideos[_cannonTargetStatus], false, _keepVideo)); - _smackerPlayer->setDrawPos(89, 37); + _cannonSmackerPlayer = addSmackerPlayer(new SmackerPlayer(_vm, this, kScene3009CannonScopeVideos[_cannonTargetStatus], false, _keepVideo)); + _cannonSmackerPlayer->setDrawPos(89, 37); _palette->usePalette(); // Use it again since the SmackerPlayer overrides the usage insertStaticSprite(0x8540252C, 400); @@ -807,42 +808,39 @@ Scene3009::Scene3009(NeverhoodEngine *vm, Module *parentModule, int which) SetMessageHandler(&Scene3009::handleMessage); SetUpdateHandler(&Scene3009::update); +} - // DEBUG Enable to set the correct code -#if 0 - for (int i = 0; i < 6; i++) - setSubVar(VA_CURR_CANNON_SYMBOLS, i, _correctSymbols[i]); - sendMessage(this, 0x2003, 0); -#endif +Scene3009::~Scene3009() { +} +void Scene3009::openSmacker(uint32 fileHash, bool keepLastFrame) { + _cannonSmackerPlayer->open(fileHash, keepLastFrame); + //_vm->_screen->setSmackerDecoder(_cannonSmackerPlayer->getSmackerDecoder()); + _palette->usePalette(); } void Scene3009::update() { Scene::update(); - - if (!_keepVideo && _smackerPlayer->isDone() && _cannonTargetStatus <= kCTSCount) { + + if (!_keepVideo && _cannonSmackerPlayer->isDone() && _cannonTargetStatus <= kCTSCount) { switch (_cannonTargetStatus) { case kCTSNull: case kCTSLowerCannon: - _smackerPlayer->open(0x340A0049, true); - _palette->usePalette(); + openSmacker(0x340A0049, true); _keepVideo = true; break; case kCTSRightRobotNoTarget: - _smackerPlayer->open(0x0082080D, true); - _palette->usePalette(); + openSmacker(0x0082080D, true); _keepVideo = true; _isTurning = false; break; case kCTSRightRobotIsTarget: - _smackerPlayer->open(0x0282080D, true); - _palette->usePalette(); + openSmacker(0x0282080D, true); _keepVideo = true; _isTurning = false; break; case kCTSRightNoRobot: - _smackerPlayer->open(0x0882080D, true); - _palette->usePalette(); + openSmacker(0x0882080D, true); _keepVideo = true; _isTurning = false; break; @@ -851,12 +849,11 @@ void Scene3009::update() { case kCTSLeftNoRobot: if (_moveCannonLeftFirst) { if (_cannonTargetStatus == kCTSLeftRobotNoTarget) - _smackerPlayer->open(0x110A000F, false); - else if (_cannonTargetStatus == kCTSLeftRobotIsTarget) - _smackerPlayer->open(0x500B004F, false); - else if (_cannonTargetStatus == kCTSLeftNoRobot) - _smackerPlayer->open(0x100B010E, false); - _palette->usePalette(); + openSmacker(0x110A000F, false); + else if (_cannonTargetStatus == kCTSLeftRobotIsTarget) + openSmacker(0x500B004F, false); + else if (_cannonTargetStatus == kCTSLeftNoRobot) + openSmacker(0x100B010E, false); _moveCannonLeftFirst = false; _asHorizontalIndicator->stMoveLeft(); } else { @@ -955,15 +952,14 @@ uint32 Scene3009::handleMessage(int messageNum, const MessageParam ¶m, Entit // Cannon is at the right position if (!getGlobalVar(V_ROBOT_TARGET)) { _cannonTargetStatus = kCTSLeftRobotNoTarget; - _smackerPlayer->open(0x108A000F, false); + openSmacker(0x108A000F, false); } else if (!getGlobalVar(V_ROBOT_HIT)) { _cannonTargetStatus = kCTSLeftRobotIsTarget; - _smackerPlayer->open(0x500B002F, false); + openSmacker(0x500B002F, false); } else { _cannonTargetStatus = kCTSLeftNoRobot; - _smackerPlayer->open(0x100B008E, false); + openSmacker(0x100B008E, false); } - _palette->usePalette(); _moveCannonLeftFirst = true; _isTurning = true; _keepVideo = false; @@ -1123,7 +1119,7 @@ AsScene3010DeadBolt::AsScene3010DeadBolt(NeverhoodEngine *vm, Scene *parentScene loadSound(0, 0x420073DC); loadSound(1, 0x420073DC); } - + setVisible(false); stIdle(); if (initUnlocked) @@ -1131,7 +1127,7 @@ AsScene3010DeadBolt::AsScene3010DeadBolt(NeverhoodEngine *vm, Scene *parentScene _needRefresh = true; AnimatedSprite::updatePosition(); - + } void AsScene3010DeadBolt::update() { @@ -1221,15 +1217,8 @@ void AsScene3010DeadBolt::stDisabledMessage() { Scene3010::Scene3010(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule), _countdown(0), _doorUnlocked(false), _checkUnlocked(false) { - - int initCountdown = 0; - // DEBUG Enable to activate all buttons -#if 0 - setSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[0], 1); - setSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[1], 1); - setSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[2], 1); -#endif + int initCountdown = 0; setBackground(0x80802626); setPalette(0x80802626); @@ -1359,7 +1348,7 @@ static const uint32 kAsScene3011SymbolFileHashes[] = { SsScene3011Button::SsScene3011Button(NeverhoodEngine *vm, Scene *parentScene, bool flag) : StaticSprite(vm, 1400), _parentScene(parentScene), _countdown(0) { - + loadSprite(flag ? 0x11282020 : 0x994D0433, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); setVisible(false); loadSound(0, 0x44061000); @@ -1457,7 +1446,7 @@ Scene3011::Scene3011(NeverhoodEngine *vm, Module *parentModule, int which) SetMessageHandler(&Scene3011::handleMessage); SetUpdateHandler(&Scene3011::update); - + setBackground(0x92124A04); setPalette(0xA4070114); addEntity(_palette); @@ -1469,12 +1458,12 @@ Scene3011::Scene3011(NeverhoodEngine *vm, Module *parentModule, int which) _ssButton = insertSprite<SsScene3011Button>(this, true); addCollisionSprite(_ssButton); - + } void Scene3011::update() { Scene::update(); - + if (_countdown != 0 && (--_countdown == 0)) { switch (_updateStatus) { case 0: diff --git a/engines/neverhood/modules/module3000.h b/engines/neverhood/modules/module3000.h index 7634360d7c..a6cecb227e 100644 --- a/engines/neverhood/modules/module3000.h +++ b/engines/neverhood/modules/module3000.h @@ -128,11 +128,12 @@ protected: class Scene3009 : public Scene { public: Scene3009(NeverhoodEngine *vm, Module *parentModule, int which); + virtual ~Scene3009(); bool isTurning(); protected: int _lockSymbolsPart1Countdown; int _lockSymbolsPart2Countdown; - SmackerPlayer *_smackerPlayer; + SmackerPlayer *_cannonSmackerPlayer; Sprite *_ssFireCannonButton; SsScene3009SymbolEdges *_ssSymbolEdges[2]; SsScene3009TargetLine *_ssTargetLines[2]; @@ -149,6 +150,7 @@ protected: void playActionVideo(); bool isSymbolsPart1Solved(); bool isSymbolsPart2Solved(); + void openSmacker(uint32 fileHash, bool keepLastFrame); }; // Scene3010 @@ -242,7 +244,7 @@ protected: bool _buttonClicked; int _countdown; int _noisySymbolIndex; - int _currentSymbolIndex; + int _currentSymbolIndex; int _noisyRandomSymbolIndex; void update(); uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); diff --git a/engines/neverhood/mouse.cpp b/engines/neverhood/mouse.cpp index 632f56fb74..f11a3f99ea 100644 --- a/engines/neverhood/mouse.cpp +++ b/engines/neverhood/mouse.cpp @@ -26,9 +26,9 @@ namespace Neverhood { Mouse::Mouse(NeverhoodEngine *vm, uint32 fileHash, const NRect &mouseRect) - : StaticSprite(vm, 2000), _mouseType(kMouseType433), + : StaticSprite(vm, 2000), _mouseType(kMouseType433), _mouseCursorResource(vm), _frameNum(0) { - + _mouseRect = mouseRect; init(fileHash); if (_x >= _mouseRect.x1 && _x <= _mouseRect.x2 && @@ -43,7 +43,7 @@ Mouse::Mouse(NeverhoodEngine *vm, uint32 fileHash, const NRect &mouseRect) Mouse::Mouse(NeverhoodEngine *vm, uint32 fileHash, int16 x1, int16 x2) : StaticSprite(vm, 2000), _mouseType(kMouseType435), _mouseCursorResource(vm), _frameNum(0), _x1(x1), _x2(x2) { - + init(fileHash); if (_x <= _x1) { _mouseCursorResource.setCursorNum(6); @@ -69,8 +69,8 @@ Mouse::~Mouse() { void Mouse::init(uint32 fileHash) { _mouseCursorResource.load(fileHash); - _x = _vm->getMouseX(); - _y = _vm->getMouseY(); + _x = _vm->getMouseX(); + _y = _vm->getMouseY(); createSurface(2000, 32, 32); SetUpdateHandler(&Mouse::update); SetMessageHandler(&Mouse::handleMessage); @@ -99,7 +99,7 @@ void Mouse::update() { _frameNum++; if (_frameNum >= 6) _frameNum = 0; - _needRefresh = _frameNum % 2 == 0; + _needRefresh = _frameNum % 2 == 0; } uint32 Mouse::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -113,40 +113,40 @@ uint32 Mouse::handleMessage(int messageNum, const MessageParam ¶m, Entity *s case 1: if (_x >= 320) messageResult = 1; - else + else messageResult = 0; break; case 2: default: if (_x < 100) messageResult = 0; - else if (_x > 540) + else if (_x > 540) messageResult = 1; - else + else messageResult = 2; break; case 3: if (_x < 100) messageResult = 0; - else if (_x > 540) + else if (_x > 540) messageResult = 1; - else + else messageResult = 4; break; case 4: if (_x < 100) messageResult = 0; - else if (_x > 540) + else if (_x > 540) messageResult = 1; - else if (_y >= 150) + else if (_y >= 150) messageResult = 2; - else + else messageResult = 3; break; case 5: if (_y >= 240) messageResult = 4; - else + else messageResult = 3; break; } @@ -162,7 +162,7 @@ uint32 Mouse::handleMessage(int messageNum, const MessageParam ¶m, Entity *s } void Mouse::updateCursor() { - + if (!_surface) return; @@ -183,7 +183,7 @@ void Mouse::updateCursor() { _drawOffset = _mouseCursorResource.getRect(); _surface->drawMouseCursorResource(_mouseCursorResource, _frameNum / 2); Graphics::Surface *cursorSurface = _surface->getSurface(); - CursorMan.replaceCursor((const byte*)cursorSurface->pixels, + CursorMan.replaceCursor((const byte*)cursorSurface->getPixels(), cursorSurface->w, cursorSurface->h, -_drawOffset.x, -_drawOffset.y, 0); } @@ -213,44 +213,44 @@ void Mouse::updateCursorNum() { case 1: if (_x >= 320) _mouseCursorResource.setCursorNum(5); - else + else _mouseCursorResource.setCursorNum(6); break; case 2: default: if (_x < 100) _mouseCursorResource.setCursorNum(6); - else if (_x > 540) + else if (_x > 540) _mouseCursorResource.setCursorNum(5); - else + else _mouseCursorResource.setCursorNum(0); break; case 3: if (_x < 100) _mouseCursorResource.setCursorNum(1); - else if (_x > 540) + else if (_x > 540) _mouseCursorResource.setCursorNum(1); break; case 4: if (_x < 100) _mouseCursorResource.setCursorNum(6); - else if (_x > 540) + else if (_x > 540) _mouseCursorResource.setCursorNum(5); - else if (_y >= 150) + else if (_y >= 150) _mouseCursorResource.setCursorNum(0); - else + else _mouseCursorResource.setCursorNum(3); break; case 5: if (_y >= 240) _mouseCursorResource.setCursorNum(2); - else + else _mouseCursorResource.setCursorNum(3); break; } break; } - + } } // End of namespace Neverhood diff --git a/engines/neverhood/mouse.h b/engines/neverhood/mouse.h index 0b927de4df..d6f42b4071 100644 --- a/engines/neverhood/mouse.h +++ b/engines/neverhood/mouse.h @@ -52,7 +52,7 @@ protected: int16 _x1; int16 _x2; int _type; - void init(uint32 fileHash); + void init(uint32 fileHash); void update(); void updateCursorNum(); uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); diff --git a/engines/neverhood/navigationscene.cpp b/engines/neverhood/navigationscene.cpp index 9752ee618c..51ab96ef37 100644 --- a/engines/neverhood/navigationscene.cpp +++ b/engines/neverhood/navigationscene.cpp @@ -25,33 +25,35 @@ namespace Neverhood { +enum AreaType { + kAreaCanMoveForward = 0, + kAreaCannotMoveForward = 1 +}; + NavigationScene::NavigationScene(NeverhoodEngine *vm, Module *parentModule, uint32 navigationListId, int navigationIndex, const byte *itemsTypes) : Scene(vm, parentModule), _itemsTypes(itemsTypes), _navigationIndex(navigationIndex), _smackerDone(false), _isWalkingForward(false), _isTurning(false), _smackerFileHash(0), _interactive(true), _leaveSceneAfter(false) { _navigationList = _vm->_staticData->getNavigationList(navigationListId); - + if (_navigationIndex < 0) { _navigationIndex = (int)getGlobalVar(V_NAVIGATION_INDEX); if (_navigationIndex >= (int)_navigationList->size()) - _navigationIndex = 0; + _navigationIndex = 0; } setGlobalVar(V_NAVIGATION_INDEX, _navigationIndex); - + SetUpdateHandler(&NavigationScene::update); SetMessageHandler(&NavigationScene::handleMessage); - - _smackerPlayer = new SmackerPlayer(_vm, this, (*_navigationList)[_navigationIndex].fileHash, true, true); - addEntity(_smackerPlayer); - addSurface(_smackerPlayer->getSurface()); - + + _smackerPlayer = addSmackerPlayer(new SmackerPlayer(_vm, this, (*_navigationList)[_navigationIndex].fileHash, true, true)); + createMouseCursor(); _vm->_screen->clear(); _vm->_screen->setSmackerDecoder(_smackerPlayer->getSmackerDecoder()); sendMessage(_parentModule, 0x100A, _navigationIndex); - } NavigationScene::~NavigationScene() { @@ -69,7 +71,7 @@ int NavigationScene::getNavigationAreaType() { void NavigationScene::update() { if (_smackerFileHash != 0) { showMouse(false); - openSmacker(_smackerFileHash, false); + _smackerPlayer->open(_smackerFileHash, false); _vm->_screen->clear(); _vm->_screen->setSmackerDecoder(_smackerPlayer->getSmackerDecoder()); _smackerDone = false; @@ -92,22 +94,15 @@ void NavigationScene::update() { _vm->_soundMan->setTwoSoundsPlayFlag(false); _vm->_soundMan->setSoundThreePlayFlag(false); _smackerDone = false; - openSmacker(navigationItem.fileHash, true); + _smackerPlayer->open(navigationItem.fileHash, true); _vm->_screen->clear(); _vm->_screen->setSmackerDecoder(_smackerPlayer->getSmackerDecoder()); sendMessage(_parentModule, 0x100A, _navigationIndex); } - } + } Scene::update(); } -void NavigationScene::openSmacker(uint32 fileHash, bool keepLastFrame) { - // The old Smacker surface is deleted when a new Smacker is opened. - removeSurface(_smackerPlayer->getSurface()); - _smackerPlayer->open(fileHash, keepLastFrame); - addSurface(_smackerPlayer->getSurface()); -} - uint32 NavigationScene::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { switch (messageNum) { case 0x0000: @@ -130,39 +125,34 @@ uint32 NavigationScene::handleMessage(int messageNum, const MessageParam ¶m, } void NavigationScene::createMouseCursor() { - const NavigationItem &navigationItem = (*_navigationList)[_navigationIndex]; uint32 mouseCursorFileHash; int areaType; - if (_mouseCursor) { + if (_mouseCursor) deleteSprite((Sprite**)&_mouseCursor); - } mouseCursorFileHash = navigationItem.mouseCursorFileHash; if (mouseCursorFileHash == 0) mouseCursorFileHash = 0x63A40028; - - if (_itemsTypes) { + + if (_itemsTypes) areaType = _itemsTypes[_navigationIndex]; - } else if (navigationItem.middleSmackerFileHash != 0 || navigationItem.middleFlag) { - areaType = 0; - } else { - areaType = 1; - } + else if (navigationItem.middleSmackerFileHash != 0 || navigationItem.middleFlag) + areaType = kAreaCanMoveForward; + else + areaType = kAreaCannotMoveForward; insertNavigationMouse(mouseCursorFileHash, areaType); sendPointMessage(_mouseCursor, 0x4002, _vm->getMousePos()); - } void NavigationScene::handleNavigation(const NPoint &mousePos) { - const NavigationItem &navigationItem = (*_navigationList)[_navigationIndex]; bool oldIsWalkingForward = _isWalkingForward; bool oldIsTurning = _isTurning; uint32 direction = sendPointMessage(_mouseCursor, 0x2064, mousePos); - + switch (direction) { case 0: if (navigationItem.leftSmackerFileHash != 0) { @@ -213,13 +203,12 @@ void NavigationScene::handleNavigation(const NPoint &mousePos) { } break; } - + if (oldIsTurning != _isTurning) _vm->_soundMan->setSoundThreePlayFlag(_isTurning); if (oldIsWalkingForward != _isWalkingForward) _vm->_soundMan->setTwoSoundsPlayFlag(_isWalkingForward); - } } // End of namespace Neverhood diff --git a/engines/neverhood/navigationscene.h b/engines/neverhood/navigationscene.h index 767b3f5d20..ebe9a3597c 100644 --- a/engines/neverhood/navigationscene.h +++ b/engines/neverhood/navigationscene.h @@ -50,7 +50,6 @@ protected: bool _leaveSceneAfter; const byte *_itemsTypes; void update(); - void openSmacker(uint32 fileHash, bool keepLastFrame); uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); void createMouseCursor(); void handleNavigation(const NPoint &mousePos); diff --git a/engines/neverhood/neverhood.cpp b/engines/neverhood/neverhood.cpp index 6b27343d03..061e6d1279 100644 --- a/engines/neverhood/neverhood.cpp +++ b/engines/neverhood/neverhood.cpp @@ -22,12 +22,18 @@ #include "common/file.h" #include "common/config-manager.h" +#include "common/textconsole.h" + #include "base/plugins.h" #include "base/version.h" + #include "graphics/cursorman.h" + #include "engines/util.h" + #include "neverhood/neverhood.h" #include "neverhood/blbarchive.h" +#include "neverhood/console.h" #include "neverhood/gamemodule.h" #include "neverhood/gamevars.h" #include "neverhood/graphics.h" @@ -71,12 +77,16 @@ Common::Error NeverhoodEngine::run() { _gameState.sceneNum = 0; _gameState.which = 0; + // Assign default values to the config manager, in case settings are missing + ConfMan.registerDefault("originalsaveload", "false"); + _staticData = new StaticData(); _staticData->load("neverhood.dat"); _gameVars = new GameVars(); _screen = new Screen(this); _res = new ResourceMan(); - + _console = new Console(this); + if (isDemo()) { _res->addArchive("a.blb"); _res->addArchive("nevdemo.blb"); @@ -94,11 +104,12 @@ Common::Error NeverhoodEngine::run() { _soundMan = new SoundMan(this); _audioResourceMan = new AudioResourceMan(this); - + _gameModule = new GameModule(this); - + _isSaveAllowed = true; - + _updateSound = true; + if (isDemo()) { // Adjust this navigation list for the demo version NavigationList *navigationList = _staticData->getNavigationList(0x004B67E8); @@ -111,24 +122,26 @@ Common::Error NeverhoodEngine::run() { (*navigationList)[5].middleSmackerFileHash = 0; (*navigationList)[5].middleFlag = 1; } - - if (ConfMan.hasKey("save_slot")) - loadGameState(ConfMan.getInt("save_slot")); - else + + if (ConfMan.hasKey("save_slot")) { + if (loadGameState(ConfMan.getInt("save_slot")).getCode() != Common::kNoError) + _gameModule->startup(); + } else _gameModule->startup(); - + mainLoop(); - + delete _gameModule; delete _soundMan; delete _audioResourceMan; + delete _console; delete _res; delete _screen; delete _gameVars; delete _staticData; - + return Common::kNoError; } @@ -140,6 +153,11 @@ void NeverhoodEngine::mainLoop() { while (eventMan->pollEvent(event)) { switch (event.type) { case Common::EVENT_KEYDOWN: + if (event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_d) { + // Open debugger console + _console->attach(); + continue; + } _gameModule->handleKeyDown(event.kbd.keycode); _gameModule->handleAsciiKey(event.kbd.ascii); break; @@ -169,11 +187,16 @@ void NeverhoodEngine::mainLoop() { _gameModule->checkRequests(); _gameModule->handleUpdate(); _gameModule->draw(); + _console->onFrame(); _screen->update(); nextFrameTime = _screen->getNextFrameTime(); }; - _soundMan->update(); - _audioResourceMan->updateMusic(); + + if (_updateSound) { + _soundMan->update(); + _audioResourceMan->updateMusic(); + } + _system->updateScreen(); _system->delayMillis(10); } diff --git a/engines/neverhood/neverhood.h b/engines/neverhood/neverhood.h index 577fbd7a66..5643e345ad 100644 --- a/engines/neverhood/neverhood.h +++ b/engines/neverhood/neverhood.h @@ -48,6 +48,7 @@ class Screen; class SoundMan; class AudioResourceMan; class StaticData; +class Console; struct NPoint; struct GameState { @@ -86,12 +87,13 @@ public: ResourceMan *_res; GameModule *_gameModule; StaticData *_staticData; - + Console *_console; + SoundMan *_soundMan; AudioResourceMan *_audioResourceMan; public: - + /* Save/load */ enum kReadSaveHeaderError { @@ -116,12 +118,12 @@ public: bool canLoadGameStateCurrently() { return _isSaveAllowed; } bool canSaveGameStateCurrently() { return _isSaveAllowed; } - + Common::Error loadGameState(int slot); Common::Error saveGameState(int slot, const Common::String &description); Common::Error removeGameState(int slot); - void savegame(const char *filename, const char *description); - void loadgame(const char *filename); + bool savegame(const char *filename, const char *description); + bool loadgame(const char *filename); const char *getSavegameFilename(int num); static Common::String getSavegameFilename(const Common::String &target, int num); static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header); @@ -132,7 +134,10 @@ public: int16 getMouseY() const { return _mouseY; } NPoint getMousePos(); -public: + void toggleSoundUpdate(bool state) { _updateSound = state; } + +private: + bool _updateSound; }; diff --git a/engines/neverhood/palette.cpp b/engines/neverhood/palette.cpp index d4b9b67f53..c381f46671 100644 --- a/engines/neverhood/palette.cpp +++ b/engines/neverhood/palette.cpp @@ -81,7 +81,7 @@ void Palette::addPalette(uint32 fileHash, int toIndex, int count, int fromIndex) if (toIndex + count > 256) count = 256 - toIndex; paletteResource.load(fileHash); - memcpy(_palette + toIndex * 4, paletteResource.palette() + fromIndex * 4, count * 4); + memcpy(_palette + toIndex * 4, paletteResource.palette() + fromIndex * 4, count * 4); _vm->_screen->testPalette(_palette); } @@ -90,20 +90,20 @@ void Palette::addBasePalette(uint32 fileHash, int toIndex, int count, int fromIn if (toIndex + count > 256) count = 256 - toIndex; paletteResource.load(fileHash); - memcpy(_basePalette + toIndex * 4, paletteResource.palette() + fromIndex * 4, count * 4); + memcpy(_basePalette + toIndex * 4, paletteResource.palette() + fromIndex * 4, count * 4); } void Palette::copyPalette(const byte *palette, int toIndex, int count, int fromIndex) { if (toIndex + count > 256) count = 256 - toIndex; - memcpy(_palette + toIndex * 4, palette + fromIndex * 4, count * 4); + memcpy(_palette + toIndex * 4, palette + fromIndex * 4, count * 4); _vm->_screen->testPalette(_palette); } void Palette::copyBasePalette(int toIndex, int count, int fromIndex) { if (toIndex + count > 256) count = 256 - toIndex; - memcpy(_basePalette + toIndex * 4, _palette + fromIndex * 4, count * 4); + memcpy(_basePalette + toIndex * 4, _palette + fromIndex * 4, count * 4); } void Palette::startFadeToBlack(int counter) { @@ -115,7 +115,7 @@ void Palette::startFadeToBlack(int counter) { _fadeToB = 0; _palCounter = counter; _fadeStep = 255 / counter; - _status = 1; + _status = 1; } void Palette::startFadeToWhite(int counter) { @@ -127,7 +127,7 @@ void Palette::startFadeToWhite(int counter) { _fadeToB = 255; _palCounter = counter; _fadeStep = 255 / counter; - _status = 1; + _status = 1; } void Palette::startFadeToPalette(int counter) { @@ -136,7 +136,7 @@ void Palette::startFadeToPalette(int counter) { counter = 1; _palCounter = counter; _fadeStep = 255 / counter; - _status = 2; + _status = 2; } void Palette::fillBaseWhite(int index, int count) { diff --git a/engines/neverhood/resource.cpp b/engines/neverhood/resource.cpp index 442713196e..a1a517f251 100644 --- a/engines/neverhood/resource.cpp +++ b/engines/neverhood/resource.cpp @@ -39,7 +39,7 @@ SpriteResource::~SpriteResource() { void SpriteResource::draw(Graphics::Surface *destSurface, bool flipX, bool flipY) { if (_pixels) { - byte *dest = (byte*)destSurface->pixels; + byte *dest = (byte*)destSurface->getPixels(); const int destPitch = destSurface->pitch; if (_rle) unpackSpriteRle(_pixels, _dimensions.width, _dimensions.height, dest, destPitch, flipX, flipY); @@ -57,7 +57,7 @@ bool SpriteResource::load(uint32 fileHash, bool doLoadPosition) { const byte *spriteData = _resourceHandle.data(); NPoint *position = doLoadPosition ? &_position : NULL; parseBitmapResource(spriteData, &_rle, &_dimensions, position, NULL, &_pixels); - } + } return _pixels != NULL; } @@ -116,7 +116,7 @@ AnimResource::~AnimResource() { void AnimResource::draw(uint frameIndex, Graphics::Surface *destSurface, bool flipX, bool flipY) { const AnimFrameInfo frameInfo = _frames[frameIndex]; - byte *dest = (byte*)destSurface->pixels; + byte *dest = (byte*)destSurface->getPixels(); const int destPitch = destSurface->pitch; _currSpriteData = _spriteData + frameInfo.spriteDataOffs; _width = frameInfo.drawOffset.width; @@ -134,11 +134,11 @@ bool AnimResource::load(uint32 fileHash) { return true; unload(); - + _vm->_res->queryResource(fileHash, _resourceHandle); if (!_resourceHandle.isValid() || _resourceHandle.type() != kResTypeAnimation) return false; - + const byte *resourceData, *animList, *frameList; uint16 animInfoStartOfs, animListIndex, animListCount; uint16 frameListStartOfs, frameCount; @@ -146,20 +146,20 @@ bool AnimResource::load(uint32 fileHash) { _vm->_res->loadResource(_resourceHandle); resourceData = _resourceHandle.data(); - + animListCount = READ_LE_UINT16(resourceData); animInfoStartOfs = READ_LE_UINT16(resourceData + 2); spriteDataOfs = READ_LE_UINT32(resourceData + 4); paletteDataOfs = READ_LE_UINT32(resourceData + 8); - + animList = resourceData + 12; for (animListIndex = 0; animListIndex < animListCount; animListIndex++) { debug(8, "hash: %08X", READ_LE_UINT32(animList)); if (READ_LE_UINT32(animList) == fileHash) break; - animList += 8; + animList += 8; } - + if (animListIndex >= animListCount) { _vm->_res->unloadResource(_resourceHandle); return false; @@ -168,12 +168,12 @@ bool AnimResource::load(uint32 fileHash) { _spriteData = resourceData + spriteDataOfs; if (paletteDataOfs > 0) _paletteData = resourceData + paletteDataOfs; - + frameCount = READ_LE_UINT16(animList + 4); frameListStartOfs = READ_LE_UINT16(animList + 6); - + debug(8, "frameCount = %d; frameListStartOfs = %04X; animInfoStartOfs = %04X", frameCount, frameListStartOfs, animInfoStartOfs); - + frameList = resourceData + animInfoStartOfs + frameListStartOfs; _frames.clear(); @@ -189,13 +189,13 @@ bool AnimResource::load(uint32 fileHash) { frameInfo.drawOffset.height = READ_LE_UINT16(frameList + 12); frameInfo.deltaX = READ_LE_UINT16(frameList + 14); frameInfo.deltaY = READ_LE_UINT16(frameList + 16); - frameInfo.collisionBoundsOffset.x = READ_LE_UINT16(frameList + 18); - frameInfo.collisionBoundsOffset.y = READ_LE_UINT16(frameList + 20); - frameInfo.collisionBoundsOffset.width = READ_LE_UINT16(frameList + 22); + frameInfo.collisionBoundsOffset.x = READ_LE_UINT16(frameList + 18); + frameInfo.collisionBoundsOffset.y = READ_LE_UINT16(frameList + 20); + frameInfo.collisionBoundsOffset.width = READ_LE_UINT16(frameList + 22); frameInfo.collisionBoundsOffset.height = READ_LE_UINT16(frameList + 24); frameInfo.spriteDataOffs = READ_LE_UINT32(frameList + 28); - debug(8, "frameHash = %08X; counter = %d; rect = (%d,%d,%d,%d); deltaX = %d; deltaY = %d; collisionBoundsOffset = (%d,%d,%d,%d); spriteDataOffs = %08X", - frameInfo.frameHash, frameInfo.counter, + debug(8, "frameHash = %08X; counter = %d; rect = (%d,%d,%d,%d); deltaX = %d; deltaY = %d; collisionBoundsOffset = (%d,%d,%d,%d); spriteDataOffs = %08X", + frameInfo.frameHash, frameInfo.counter, frameInfo.drawOffset.x, frameInfo.drawOffset.y, frameInfo.drawOffset.width, frameInfo.drawOffset.height, frameInfo.deltaX, frameInfo.deltaY, frameInfo.collisionBoundsOffset.x, frameInfo.collisionBoundsOffset.y, frameInfo.collisionBoundsOffset.width, frameInfo.collisionBoundsOffset.height, @@ -203,11 +203,11 @@ bool AnimResource::load(uint32 fileHash) { frameList += 32; _frames.push_back(frameInfo); } - + _fileHash = fileHash; return true; - + } void AnimResource::unload() { @@ -229,7 +229,7 @@ int16 AnimResource::getFrameIndex(uint32 frameHash) { break; } debug(2, "AnimResource::getFrameIndex(%08X) -> %d", frameHash, frameIndex); - return frameIndex; + return frameIndex; } void AnimResource::setRepl(byte oldColor, byte newColor) { @@ -254,7 +254,7 @@ NDimensions AnimResource::loadSpriteDimensions(uint32 fileHash) { // MouseCursorResource -MouseCursorResource::MouseCursorResource(NeverhoodEngine *vm) +MouseCursorResource::MouseCursorResource(NeverhoodEngine *vm) : _cursorSprite(vm), _cursorNum(4), _currFileHash(0) { _rect.width = 32; @@ -265,7 +265,7 @@ void MouseCursorResource::load(uint32 fileHash) { if (_currFileHash != fileHash) { if (_cursorSprite.load(fileHash) && !_cursorSprite.isRle() && _cursorSprite.getDimensions().width == 96 && _cursorSprite.getDimensions().height == 224) { - _currFileHash = fileHash; + _currFileHash = fileHash; } else { unload(); } @@ -296,14 +296,14 @@ NDrawRect& MouseCursorResource::getRect() { void MouseCursorResource::draw(int frameNum, Graphics::Surface *destSurface) { if (_cursorSprite.getPixels()) { const int sourcePitch = (_cursorSprite.getDimensions().width + 3) & 0xFFFC; // 4 byte alignment - const int destPitch = destSurface->pitch; + const int destPitch = destSurface->pitch; const byte *source = _cursorSprite.getPixels() + _cursorNum * (sourcePitch * 32) + frameNum * 32; - byte *dest = (byte*)destSurface->pixels; + byte *dest = (byte*)destSurface->getPixels(); for (int16 yc = 0; yc < 32; yc++) { memcpy(dest, source, 32); source += sourcePitch; dest += destPitch; - } + } } } @@ -311,7 +311,7 @@ void MouseCursorResource::draw(int frameNum, Graphics::Surface *destSurface) { TextResource::TextResource(NeverhoodEngine *vm) : _vm(vm), _textData(NULL), _count(0) { - + } TextResource::~TextResource() { @@ -372,7 +372,7 @@ void DataResource::load(uint32 fileHash) { dataS.seek(2 + i * 8); DRDirectoryItem drDirectoryItem; drDirectoryItem.nameHash = dataS.readUint32LE(); - drDirectoryItem.offset = dataS.readUint16LE(); + drDirectoryItem.offset = dataS.readUint16LE(); drDirectoryItem.type = dataS.readUint16LE(); debug(2, "%03d nameHash = %08X; offset = %04X; type = %d", i, drDirectoryItem.nameHash, drDirectoryItem.offset, drDirectoryItem.type); dataS.seek(itemStartOffs + drDirectoryItem.offset); @@ -415,7 +415,7 @@ void DataResource::load(uint32 fileHash) { hitRect.rect.y1 = dataS.readUint16LE(); hitRect.rect.x2 = dataS.readUint16LE(); hitRect.rect.y2 = dataS.readUint16LE(); - hitRect.type = dataS.readUint16LE() + 0x5001; + hitRect.type = dataS.readUint16LE() + 0x5001; debug(3, "(%d, %d, %d, %d) -> %04d", hitRect.rect.x1, hitRect.rect.y1, hitRect.rect.x2, hitRect.rect.y2, hitRect.type); hitRectList->push_back(hitRect); } @@ -491,7 +491,7 @@ void DataResource::load(uint32 fileHash) { break; } } - _directory.push_back(drDirectoryItem); + _directory.push_back(drDirectoryItem); } } } @@ -540,12 +540,12 @@ HitRectList *DataResource::getHitRectList() { MessageList *DataResource::getMessageListAtPos(int16 klaymenX, int16 klaymenY, int16 mouseX, int16 mouseY) { for (uint i = 0; i < _drRects.size(); i++) { - if (klaymenX >= _drRects[i].rect.x1 && klaymenX <= _drRects[i].rect.x2 && + if (klaymenX >= _drRects[i].rect.x1 && klaymenX <= _drRects[i].rect.x2 && klaymenY >= _drRects[i].rect.y1 && klaymenY <= _drRects[i].rect.y2) { - DRSubRectList *drSubRectList = _drSubRectLists[_drRects[i].subRectIndex]; + DRSubRectList *drSubRectList = _drSubRectLists[_drRects[i].subRectIndex]; for (uint j = 0; j < drSubRectList->size(); j++) { DRSubRect &subRect = (*drSubRectList)[j]; - if (mouseX >= subRect.rect.x1 && mouseX <= subRect.rect.x2 && + if (mouseX >= subRect.rect.x1 && mouseX <= subRect.rect.x2 && mouseY >= subRect.rect.y1 && mouseY <= subRect.rect.y2) { return _messageLists[subRect.messageListItemIndex]; } diff --git a/engines/neverhood/resource.h b/engines/neverhood/resource.h index 6a84a69ecd..40236d9d22 100644 --- a/engines/neverhood/resource.h +++ b/engines/neverhood/resource.h @@ -168,7 +168,7 @@ protected: struct DRDirectoryItem { uint32 nameHash; - uint16 offset; + uint16 offset; uint16 type; }; @@ -195,7 +195,7 @@ protected: Common::Array<MessageList*> _messageLists; Common::Array<DRRect> _drRects; Common::Array<DRSubRectList*> _drSubRectLists; - DataResource::DRDirectoryItem *findDRDirectoryItem(uint32 nameHash, uint16 type); + DataResource::DRDirectoryItem *findDRDirectoryItem(uint32 nameHash, uint16 type); }; uint32 calcHash(const char *value); diff --git a/engines/neverhood/resourceman.cpp b/engines/neverhood/resourceman.cpp index d5e7786c17..37089a5bd6 100644 --- a/engines/neverhood/resourceman.cpp +++ b/engines/neverhood/resourceman.cpp @@ -49,7 +49,7 @@ void ResourceMan::addArchive(const Common::String &filename) { if (archiveEntry->timeStamp > entry->archiveEntry->timeStamp) { entry->archive = archive; entry->archiveEntry = archiveEntry; - } + } } else { ResourceFileEntry newEntry; newEntry.resourceHandle = -1; diff --git a/engines/neverhood/saveload.cpp b/engines/neverhood/saveload.cpp index 578d9858ff..01988769e6 100644 --- a/engines/neverhood/saveload.cpp +++ b/engines/neverhood/saveload.cpp @@ -61,12 +61,12 @@ NeverhoodEngine::kReadSaveHeaderError NeverhoodEngine::readSaveHeader(Common::Se return ((in->eos() || in->err()) ? kRSHEIoError : kRSHENoError); } -void NeverhoodEngine::savegame(const char *filename, const char *description) { +bool NeverhoodEngine::savegame(const char *filename, const char *description) { Common::OutSaveFile *out; if (!(out = g_system->getSavefileManager()->openForSaving(filename))) { warning("Can't create file '%s', game not saved", filename); - return; + return false; } TimeDate curTime; @@ -78,7 +78,7 @@ void NeverhoodEngine::savegame(const char *filename, const char *description) { byte descriptionLen = strlen(description); out->writeByte(descriptionLen); out->write(description, descriptionLen); - + Graphics::saveThumbnail(*out); // Not used yet, reserved for future usage @@ -96,50 +96,53 @@ void NeverhoodEngine::savegame(const char *filename, const char *description) { _gameVars->setGlobalVar(V_CURRENT_SCENE_WHICH, _gameState.which); _gameVars->saveState(out); - + out->finalize(); delete out; + return true; } -void NeverhoodEngine::loadgame(const char *filename) { +bool NeverhoodEngine::loadgame(const char *filename) { Common::InSaveFile *in; if (!(in = g_system->getSavefileManager()->openForLoading(filename))) { warning("Can't open file '%s', game not loaded", filename); - return; + return false; } SaveHeader header; kReadSaveHeaderError errorCode = readSaveHeader(in, false, header); - + if (errorCode != kRSHENoError) { warning("Error loading savegame '%s'", filename); delete in; - return; + return false; } - + g_engine->setTotalPlayTime(header.playTime * 1000); _gameVars->loadState(in); - + _gameState.sceneNum = _gameVars->getGlobalVar(V_CURRENT_SCENE); _gameState.which = _gameVars->getGlobalVar(V_CURRENT_SCENE_WHICH); _gameModule->requestRestoreGame(); delete in; - + return true; } Common::Error NeverhoodEngine::loadGameState(int slot) { const char *fileName = getSavegameFilename(slot); - loadgame(fileName); + if (!loadgame(fileName)) + return Common::kReadingFailed; return Common::kNoError; } Common::Error NeverhoodEngine::saveGameState(int slot, const Common::String &description) { const char *fileName = getSavegameFilename(slot); - savegame(fileName, description.c_str()); + if (!savegame(fileName, description.c_str())) + return Common::kWritingFailed; return Common::kNoError; } diff --git a/engines/neverhood/scene.cpp b/engines/neverhood/scene.cpp index 07d41754c9..c8d7490753 100644 --- a/engines/neverhood/scene.cpp +++ b/engines/neverhood/scene.cpp @@ -20,6 +20,7 @@ * */ +#include "neverhood/console.h" #include "neverhood/scene.h" namespace Neverhood { @@ -27,7 +28,7 @@ namespace Neverhood { Scene::Scene(NeverhoodEngine *vm, Module *parentModule) : Entity(vm, 0), _parentModule(parentModule), _dataResource(vm), _hitRects(NULL), _mouseCursorWasVisible(true) { - + _isKlaymenBusy = false; _doConvertMessages = false; _messageList = NULL; @@ -49,15 +50,17 @@ Scene::Scene(NeverhoodEngine *vm, Module *parentModule) _smackerPlayer = NULL; _isMessageListBusy = false; _messageValue = -1; - + SetUpdateHandler(&Scene::update); SetMessageHandler(&Scene::handleMessage); - + _vm->_screen->clearRenderQueue(); } Scene::~Scene() { + _vm->_screen->setSmackerDecoder(NULL); + if (_palette) { removeEntity(_palette); delete _palette; @@ -68,7 +71,7 @@ Scene::~Scene() { delete *iter; // Don't delete surfaces since they always belong to an entity - + // Purge the resources after each scene _vm->_res->purgeResources(); @@ -81,7 +84,7 @@ void Scene::draw() { } else { for (Common::Array<BaseSurface*>::iterator iter = _surfaces.begin(); iter != _surfaces.end(); iter++) (*iter)->draw(); - } + } } void Scene::addEntity(Entity *entity) { @@ -96,7 +99,7 @@ void Scene::addEntity(Entity *entity) { if (insertIndex >= 0) _entities.insert_at(insertIndex, entity); else - _entities.push_back(entity); + _entities.push_back(entity); } bool Scene::removeEntity(Entity *entity) { @@ -105,7 +108,7 @@ bool Scene::removeEntity(Entity *entity) { _entities.remove_at(index); return true; } - return false; + return false; } void Scene::addSurface(BaseSurface *surface) { @@ -121,7 +124,7 @@ void Scene::addSurface(BaseSurface *surface) { if (insertIndex >= 0) _surfaces.insert_at(insertIndex, surface); else - _surfaces.push_back(surface); + _surfaces.push_back(surface); } } @@ -132,7 +135,19 @@ bool Scene::removeSurface(BaseSurface *surface) { return true; } } - return false; + return false; +} + +void Scene::printSurfaces(Console *con) { + for (uint index = 0; index < _surfaces.size(); index++) { + NDrawRect drawRect = _surfaces[index]->getDrawRect(); + NRect clipRect = _surfaces[index]->getClipRect(); + int priority = _surfaces[index]->getPriority(); + con->DebugPrintf("%d ('%s'): Priority %d, draw rect (%d, %d, %d, %d), clip rect (%d, %d, %d, %d)\n", + index, _surfaces[index]->getName().c_str(), priority, + drawRect.x, drawRect.y, drawRect.x2(), drawRect.y2(), + clipRect.x1, clipRect.y1, clipRect.x2, clipRect.y2); + } } Sprite *Scene::addSprite(Sprite *sprite) { @@ -197,7 +212,7 @@ Sprite *Scene::insertStaticSprite(uint32 fileHash, int surfacePriority) { } void Scene::insertScreenMouse(uint32 fileHash, const NRect *mouseRect) { - NRect rect(-1, -1, -1, -1); + NRect rect = NRect::make(-1, -1, -1, -1); if (mouseRect) rect = *mouseRect; insertMouse(new Mouse(_vm, fileHash, rect)); @@ -231,12 +246,12 @@ void Scene::update() { if (_mouseClicked) { if (_klaymen) { if (_canAcceptInput && - _klaymen->hasMessageHandler() && + _klaymen->hasMessageHandler() && sendMessage(_klaymen, 0x1008, 0) != 0 && queryPositionSprite(_mouseClickPos.x, _mouseClickPos.y)) { _mouseClicked = false; } else if (_canAcceptInput && - _klaymen->hasMessageHandler() && + _klaymen->hasMessageHandler() && sendMessage(_klaymen, 0x1008, 0) != 0) { _mouseClicked = !queryPositionRectList(_mouseClickPos.x, _mouseClickPos.y); } @@ -247,7 +262,7 @@ void Scene::update() { processMessageList(); - // Update all entities + // Update all entities for (Common::Array<Entity*>::iterator iter = _entities.begin(); iter != _entities.end(); iter++) (*iter)->handleUpdate(); @@ -268,7 +283,7 @@ uint32 Scene::handleMessage(int messageNum, const MessageParam ¶m, Entity *s _mouseClickPos = param.asPoint(); break; case 0x0006: - sendMessage(_parentModule, 0x1009, param); + sendMessage(_parentModule, 0x1009, param); break; case 0x1006: // Sent by Klaymen when its animation sequence has finished @@ -317,7 +332,7 @@ uint32 Scene::handleMessage(int messageNum, const MessageParam ¶m, Entity *s bool Scene::queryPositionSprite(int16 mouseX, int16 mouseY) { for (uint i = 0; i < _collisionSprites.size(); i++) { Sprite *sprite = _collisionSprites[i]; - if (sprite->hasMessageHandler() && sprite->isPointInside(mouseX, mouseY) && + if (sprite->hasMessageHandler() && sprite->isPointInside(mouseX, mouseY) && sendPointMessage(sprite, 0x1011, _mouseClickPos) != 0) { return true; } @@ -397,8 +412,8 @@ void Scene::processMessageList() { _messageList2 = NULL; _messageListStatus = 0; } - - if (_messageList && _klaymen) { + + if (_messageList && _klaymen) { #if 0 debug("MessageList: %p, %d", (void*)_messageList, _messageList->size()); @@ -408,11 +423,11 @@ void Scene::processMessageList() { } debug("--------------------------------"); #endif - + while (_messageList && _messageListIndex < _messageListCount && !_isKlaymenBusy) { uint32 messageNum = (*_messageList)[_messageListIndex].messageNum; uint32 messageParam = (*_messageList)[_messageListIndex].messageValue; - + ++_messageListIndex; if (_messageListIndex == _messageListCount) sendMessage(_klaymen, 0x1021, 0); @@ -445,7 +460,7 @@ void Scene::processMessageList() { if (_klaymen->hasMessageHandler() && sendMessage(_klaymen, messageNum, messageParam) != 0) { _isKlaymenBusy = false; } - } + } if (_messageListIndex == _messageListCount) { _canAcceptInput = true; _messageList = NULL; @@ -454,7 +469,7 @@ void Scene::processMessageList() { } _isMessageListBusy = false; - + } void Scene::cancelMessageList() { @@ -516,7 +531,7 @@ uint16 Scene::convertMessageNum(uint32 messageNum) { case 0x42002200: return 0x4004; case 0x428D4894: - return 0x101A; + return 0x101A; } return 0x1000; } @@ -531,7 +546,7 @@ HitRect *Scene::findHitRectAtPos(int16 x, int16 y) { for (HitRectList::iterator it = _hitRects->begin(); it != _hitRects->end(); it++) if ((*it).rect.contains(x, y)) return &(*it); - return &kDefaultHitRect; + return &kDefaultHitRect; } void Scene::addCollisionSprite(Sprite *sprite) { @@ -546,7 +561,7 @@ void Scene::addCollisionSprite(Sprite *sprite) { if (insertIndex >= 0) _collisionSprites.insert_at(insertIndex, sprite); else - _collisionSprites.push_back(sprite); + _collisionSprites.push_back(sprite); } void Scene::removeCollisionSprite(Sprite *sprite) { @@ -568,7 +583,7 @@ void Scene::checkCollision(Sprite *sprite, uint16 flags, int messageNum, uint32 if ((sprite->getFlags() & flags) && collSprite->checkCollision(sprite->getCollisionBounds())) { sprite->sendMessage(collSprite, messageNum, messageParam); } - } + } } void Scene::insertMouse(Mouse *mouseCursor) { diff --git a/engines/neverhood/scene.h b/engines/neverhood/scene.h index 1abcbfb964..5e42e34418 100644 --- a/engines/neverhood/scene.h +++ b/engines/neverhood/scene.h @@ -37,6 +37,8 @@ namespace Neverhood { +class Console; + class Scene : public Entity { public: Scene(NeverhoodEngine *vm, Module *parentModule); @@ -46,6 +48,7 @@ public: bool removeEntity(Entity *entity); void addSurface(BaseSurface *surface); bool removeSurface(BaseSurface *surface); + void printSurfaces(Console *con); Sprite *addSprite(Sprite *sprite); void removeSprite(Sprite *sprite); void setSurfacePriority(BaseSurface *surface, int priority); @@ -73,89 +76,89 @@ public: void checkCollision(Sprite *sprite, uint16 flags, int messageNum, uint32 messageParam); // Some crazy templated functions to make the logic code smaller/simpler (imo!) // insertKlaymen - template<class T> + template<class T> void insertKlaymen() { _klaymen = (T*)addSprite(new T(_vm, this)); } - template<class T, class Arg1> + template<class T, class Arg1> void insertKlaymen(Arg1 arg1) { _klaymen = (T*)addSprite(new T(_vm, this, arg1)); } - template<class T, class Arg1, class Arg2> + template<class T, class Arg1, class Arg2> void insertKlaymen(Arg1 arg1, Arg2 arg2) { _klaymen = (T*)addSprite(new T(_vm, this, arg1, arg2)); } - template<class T, class Arg1, class Arg2, class Arg3> + template<class T, class Arg1, class Arg2, class Arg3> void insertKlaymen(Arg1 arg1, Arg2 arg2, Arg3 arg3) { _klaymen = (T*)addSprite(new T(_vm, this, arg1, arg2, arg3)); } - template<class T, class Arg1, class Arg2, class Arg3, class Arg4> + template<class T, class Arg1, class Arg2, class Arg3, class Arg4> void insertKlaymen(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) { _klaymen = (T*)addSprite(new T(_vm, this, arg1, arg2, arg3, arg4)); } - template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5> + template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5> void insertKlaymen(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) { _klaymen = (T*)addSprite(new T(_vm, this, arg1, arg2, arg3, arg4, arg5)); } - template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6> + template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6> void insertKlaymen(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6) { _klaymen = (T*)addSprite(new T(_vm, this, arg1, arg2, arg3, arg4, arg5, arg6)); } // insertSprite - template<class T> + template<class T> T* insertSprite() { return (T*)addSprite(new T(_vm)); } - template<class T, class Arg1> + template<class T, class Arg1> T* insertSprite(Arg1 arg1) { return (T*)addSprite(new T(_vm, arg1)); } - template<class T, class Arg1, class Arg2> + template<class T, class Arg1, class Arg2> T* insertSprite(Arg1 arg1, Arg2 arg2) { return (T*)addSprite(new T(_vm, arg1, arg2)); } - template<class T, class Arg1, class Arg2, class Arg3> + template<class T, class Arg1, class Arg2, class Arg3> T* insertSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3) { return (T*)addSprite(new T(_vm, arg1, arg2, arg3)); } - template<class T, class Arg1, class Arg2, class Arg3, class Arg4> + template<class T, class Arg1, class Arg2, class Arg3, class Arg4> T* insertSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) { return (T*)addSprite(new T(_vm, arg1, arg2, arg3, arg4)); } - template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5> + template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5> T* insertSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) { return (T*)addSprite(new T(_vm, arg1, arg2, arg3, arg4, arg5)); } - template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6> + template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6> T* insertSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6) { return (T*)addSprite(new T(_vm, arg1, arg2, arg3, arg4, arg5, arg6)); } // createSprite - template<class T> + template<class T> T* createSprite() { return new T(_vm); } - template<class T, class Arg1> + template<class T, class Arg1> T* createSprite(Arg1 arg1) { return new T(_vm, arg1); } - template<class T, class Arg1, class Arg2> + template<class T, class Arg1, class Arg2> T* createSprite(Arg1 arg1, Arg2 arg2) { return new T(_vm, arg1, arg2); } - template<class T, class Arg1, class Arg2, class Arg3> + template<class T, class Arg1, class Arg2, class Arg3> T* createSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3) { return new T(_vm, arg1, arg2, arg3); } - template<class T, class Arg1, class Arg2, class Arg3, class Arg4> + template<class T, class Arg1, class Arg2, class Arg3, class Arg4> T* createSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) { return new T(_vm, arg1, arg2, arg3, arg4); } - template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5> + template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5> T* createSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) { return new T(_vm, arg1, arg2, arg3, arg4, arg5); } - template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6> + template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6> T* createSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6) { return new T(_vm, arg1, arg2, arg3, arg4, arg5, arg6); } diff --git a/engines/neverhood/screen.cpp b/engines/neverhood/screen.cpp index 5a748cfab4..4c8dd9add0 100644 --- a/engines/neverhood/screen.cpp +++ b/engines/neverhood/screen.cpp @@ -28,16 +28,16 @@ namespace Neverhood { Screen::Screen(NeverhoodEngine *vm) : _vm(vm), _paletteData(NULL), _paletteChanged(false), _smackerDecoder(NULL), _yOffset(0), _fullRefresh(false) { - + _ticks = _vm->_system->getMillis(); - + _backScreen = new Graphics::Surface(); _backScreen->create(640, 480, Graphics::PixelFormat::createFormatCLUT8()); - + _renderQueue = new RenderQueue(); _prevRenderQueue = new RenderQueue(); _microTiles = new MicroTileArray(640, 480); - + } Screen::~Screen() { @@ -54,7 +54,7 @@ void Screen::update() { if (_fullRefresh) { // NOTE When playing a fullscreen/doubled Smacker video usually a full screen refresh is needed - _vm->_system->copyRectToScreen((const byte*)_backScreen->pixels, _backScreen->pitch, 0, 0, 640, 480); + _vm->_system->copyRectToScreen((const byte*)_backScreen->getPixels(), _backScreen->pitch, 0, 0, 640, 480); _fullRefresh = false; return; } @@ -72,13 +72,13 @@ void Screen::update() { } } } - + for (RenderQueue::iterator jt = _prevRenderQueue->begin(); jt != _prevRenderQueue->end(); ++jt) { RenderItem &prevRenderItem = (*jt); if (prevRenderItem._refresh) _microTiles->addRect(Common::Rect(prevRenderItem._destX, prevRenderItem._destY, prevRenderItem._destX + prevRenderItem._width, prevRenderItem._destY + prevRenderItem._height)); } - + for (RenderQueue::iterator it = _renderQueue->begin(); it != _renderQueue->end(); ++it) { RenderItem &renderItem = (*it); if (renderItem._refresh) @@ -93,7 +93,7 @@ void Screen::update() { for (RectangleList::iterator ri = updateRects->begin(); ri != updateRects->end(); ++ri) blitRenderItem(renderItem, *ri); } - + SWAP(_renderQueue, _prevRenderQueue); _renderQueue->clear(); @@ -174,7 +174,7 @@ void Screen::updatePalette() { } void Screen::clear() { - memset(_backScreen->pixels, 0, _backScreen->pitch * _backScreen->h); + memset(_backScreen->getPixels(), 0, _backScreen->pitch * _backScreen->h); _fullRefresh = true; clearRenderQueue(); } @@ -202,12 +202,12 @@ void Screen::drawSurface2(const Graphics::Surface *surface, NDrawRect &drawRect, destX = drawRect.x; ddRect.x1 = 0; } - + if (drawRect.y + drawRect.height >= clipRect.y2) ddRect.y2 = clipRect.y2 - drawRect.y; else ddRect.y2 = drawRect.height; - + if (drawRect.y < clipRect.y1) { destY = clipRect.y1; ddRect.y1 = clipRect.y1 - drawRect.y; @@ -215,7 +215,7 @@ void Screen::drawSurface2(const Graphics::Surface *surface, NDrawRect &drawRect, destY = drawRect.y; ddRect.y1 = 0; } - + queueBlit(surface, destX, destY, ddRect, transparent, version, shadowSurface); } @@ -224,12 +224,12 @@ void Screen::drawSurface3(const Graphics::Surface *surface, int16 x, int16 y, ND int16 destX, destY; NRect ddRect; - + if (x + drawRect.width >= clipRect.x2) ddRect.x2 = clipRect.x2 - drawRect.x - x; else ddRect.x2 = drawRect.x + drawRect.width; - + if (x < clipRect.x1) { destX = clipRect.x1; ddRect.x1 = clipRect.x1 + drawRect.x - x; @@ -242,7 +242,7 @@ void Screen::drawSurface3(const Graphics::Surface *surface, int16 x, int16 y, ND ddRect.y2 = clipRect.y2 + drawRect.y - y; else ddRect.y2 = drawRect.y + drawRect.height; - + if (y < clipRect.y1) { destY = clipRect.y1; ddRect.y1 = clipRect.y1 + drawRect.y - y; @@ -250,14 +250,14 @@ void Screen::drawSurface3(const Graphics::Surface *surface, int16 x, int16 y, ND destY = y; ddRect.y1 = drawRect.y; } - + queueBlit(surface, destX, destY, ddRect, transparent, version); } void Screen::drawDoubleSurface2(const Graphics::Surface *surface, NDrawRect &drawRect) { - const byte *source = (const byte*)surface->getBasePtr(0, 0); + const byte *source = (const byte*)surface->getPixels(); byte *dest = (byte*)_backScreen->getBasePtr(drawRect.x, drawRect.y); for (int16 yc = 0; yc < surface->h; yc++) { @@ -270,13 +270,13 @@ void Screen::drawDoubleSurface2(const Graphics::Surface *surface, NDrawRect &dra dest += _backScreen->pitch; dest += _backScreen->pitch; } - + _fullRefresh = true; // See Screen::update } void Screen::drawUnk(const Graphics::Surface *surface, NDrawRect &drawRect, NDrawRect &sysRect, NRect &clipRect, bool transparent, byte version) { - + int16 x, y; bool xflag, yflag; NDrawRect newDrawRect; @@ -292,26 +292,26 @@ void Screen::drawUnk(const Graphics::Surface *surface, NDrawRect &drawRect, NDra y = y % sysRect.height; if (y < 0) y += sysRect.height; - + xflag = x <= 0; yflag = y <= 0; - + newDrawRect.x = x; newDrawRect.width = sysRect.width - x; if (drawRect.width < newDrawRect.width) { xflag = true; newDrawRect.width = drawRect.width; } - + newDrawRect.y = y; newDrawRect.height = sysRect.height - y; if (drawRect.height < newDrawRect.height) { yflag = true; newDrawRect.height = drawRect.height; } - + drawSurface3(surface, drawRect.x, drawRect.y, newDrawRect, clipRect, transparent, version); - + if (!xflag) { newDrawRect.x = 0; newDrawRect.y = y; @@ -321,7 +321,7 @@ void Screen::drawUnk(const Graphics::Surface *surface, NDrawRect &drawRect, NDra newDrawRect.height = drawRect.height; drawSurface3(surface, sysRect.width + drawRect.x - x, drawRect.y, newDrawRect, clipRect, transparent, version); } - + if (!yflag) { newDrawRect.x = x; newDrawRect.y = 0; @@ -331,7 +331,7 @@ void Screen::drawUnk(const Graphics::Surface *surface, NDrawRect &drawRect, NDra newDrawRect.width = drawRect.width; drawSurface3(surface, drawRect.x, sysRect.height + drawRect.y - y, newDrawRect, clipRect, transparent, version); } - + if (!xflag && !yflag) { newDrawRect.x = 0; newDrawRect.y = 0; @@ -350,13 +350,13 @@ void Screen::drawSurfaceClipRects(const Graphics::Surface *surface, NDrawRect &d void Screen::queueBlit(const Graphics::Surface *surface, int16 destX, int16 destY, NRect &ddRect, bool transparent, byte version, const Graphics::Surface *shadowSurface) { - + const int width = ddRect.x2 - ddRect.x1; const int height = ddRect.y2 - ddRect.y1; if (width <= 0 || height <= 0) return; - + RenderItem renderItem; renderItem._surface = surface; renderItem._shadowSurface = shadowSurface; @@ -369,7 +369,7 @@ void Screen::queueBlit(const Graphics::Surface *surface, int16 destX, int16 dest renderItem._transparent = transparent; renderItem._version = version; _renderQueue->push_back(renderItem); - + } void Screen::blitRenderItem(const RenderItem &renderItem, const Common::Rect &clipRect) { diff --git a/engines/neverhood/smackerplayer.cpp b/engines/neverhood/smackerplayer.cpp index b67c8db9fc..187939faee 100644 --- a/engines/neverhood/smackerplayer.cpp +++ b/engines/neverhood/smackerplayer.cpp @@ -31,7 +31,7 @@ namespace Neverhood { // SmackerSurface SmackerSurface::SmackerSurface(NeverhoodEngine *vm) - : BaseSurface(vm, 0, 0, 0), _smackerFrame(NULL) { + : BaseSurface(vm, 0, 0, 0, "smacker"), _smackerFrame(NULL) { } void SmackerSurface::draw() { @@ -51,6 +51,18 @@ void SmackerSurface::setSmackerFrame(const Graphics::Surface *smackerFrame) { _smackerFrame = smackerFrame; } +void SmackerSurface::unsetSmackerFrame() { + _drawRect.x = 0; + _drawRect.y = 0; + _drawRect.width = 0; + _drawRect.height = 0; + _sysRect.x = 0; + _sysRect.y = 0; + _sysRect.width = 0; + _sysRect.height = 0; + _smackerFrame = NULL; +} + // SmackerDoubleSurface SmackerDoubleSurface::SmackerDoubleSurface(NeverhoodEngine *vm) @@ -62,25 +74,27 @@ void SmackerDoubleSurface::draw() { _vm->_screen->drawDoubleSurface2(_smackerFrame, _drawRect); } +// NeverhoodSmackerDecoder + void NeverhoodSmackerDecoder::forceSeekToFrame(uint frame) { if (!isVideoLoaded()) return; - + if (frame >= getFrameCount()) error("Can't force Smacker seek to invalid frame %d", frame); - + if (_header.audioInfo[0].hasAudio) error("Can't force Smacker frame seek with audio"); if (!rewind()) error("Failed to rewind"); - + SmackerVideoTrack *videoTrack = (SmackerVideoTrack *)getTrack(0); uint32 offset = 0; for (uint32 i = 0; i < frame; i++) { videoTrack->increaseCurFrame(); offset += _frameSizes[i] & ~3; } - + _fileStream->seek(offset, SEEK_CUR); } @@ -92,40 +106,43 @@ SmackerPlayer::SmackerPlayer(NeverhoodEngine *vm, Scene *scene, uint32 fileHash, _drawX(-1), _drawY(-1) { SetUpdateHandler(&SmackerPlayer::update); + + if (_doubleSurface) { + _smackerSurface = new SmackerDoubleSurface(_vm); + } else { + _smackerSurface = new SmackerSurface(_vm); + } + open(fileHash, flag); } SmackerPlayer::~SmackerPlayer() { close(); + delete _smackerSurface; + _smackerSurface = NULL; } void SmackerPlayer::open(uint32 fileHash, bool keepLastFrame) { debug(0, "SmackerPlayer::open(%08X)", fileHash); - + _fileHash = fileHash; _keepLastFrame = keepLastFrame; close(); - if (_doubleSurface) { - _smackerSurface = new SmackerDoubleSurface(_vm); - } else { - _smackerSurface = new SmackerSurface(_vm); - } - _smackerFirst = true; _stream = _vm->_res->createStream(fileHash); _smackerDecoder = new NeverhoodSmackerDecoder(); _smackerDecoder->loadStream(_stream); - + _palette = new Palette(_vm); _palette->usePalette(); if (!_paused) _smackerDecoder->start(); - + } void SmackerPlayer::close() { @@ -134,11 +151,10 @@ void SmackerPlayer::close() { delete _smackerDecoder; delete _palette; // NOTE The SmackerDecoder deletes the _stream - delete _smackerSurface; _smackerDecoder = NULL; _palette = NULL; _stream = NULL; - _smackerSurface = NULL; + _smackerSurface->unsetSmackerFrame(); } void SmackerPlayer::gotoFrame(int frameNumber) { @@ -196,10 +212,14 @@ void SmackerPlayer::update() { _videoDone = false; } } - + } void SmackerPlayer::updateFrame() { + + if (!_smackerDecoder || !_smackerSurface) + return; + const Graphics::Surface *smackerFrame = _smackerDecoder->decodeNextFrame(); if (_smackerFirst) { @@ -220,7 +240,7 @@ void SmackerPlayer::updateFrame() { if (_smackerDecoder->hasDirtyPalette()) updatePalette(); - + } void SmackerPlayer::updatePalette() { diff --git a/engines/neverhood/smackerplayer.h b/engines/neverhood/smackerplayer.h index 26ebff5d33..dd7199dd6d 100644 --- a/engines/neverhood/smackerplayer.h +++ b/engines/neverhood/smackerplayer.h @@ -37,6 +37,7 @@ public: SmackerSurface(NeverhoodEngine *vm); virtual void draw(); void setSmackerFrame(const Graphics::Surface *smackerFrame); + void unsetSmackerFrame(); protected: const Graphics::Surface *_smackerFrame; }; @@ -61,7 +62,7 @@ public: void close(); void gotoFrame(int frameNumber); uint32 getFrameCount(); - uint32 getFrameNumber(); + uint32 getFrameNumber(); uint getStatus(); void setDrawPos(int16 x, int16 y); void rewind(); diff --git a/engines/neverhood/smackerscene.cpp b/engines/neverhood/smackerscene.cpp index 115aafe5be..d9d032a3b5 100644 --- a/engines/neverhood/smackerscene.cpp +++ b/engines/neverhood/smackerscene.cpp @@ -31,16 +31,16 @@ SmackerScene::SmackerScene(NeverhoodEngine *vm, Module *parentModule, bool doubl debug(0, "SmackerScene::SmackerScene(%d, %d, %d)", doubleSurface, canSkip, canAbort); // NOTE: Merged from SmackerScene::init, maybe split again if needed (incl. parameter flags) - + if (getGlobalVar(V_SMACKER_CAN_ABORT)) { _canSkip = true; _canAbort = true; } - + if (!_doubleSurface) _vm->_screen->clear(); - _fileHash[0] = 0; + _fileHash[0] = 0; _fileHash[1] = 0; SetUpdateHandler(&SmackerScene::update); @@ -67,7 +67,7 @@ void SmackerScene::nextVideo() { debug(0, "SmackerScene::nextVideo()"); _fileHashListIndex++; - + if (_fileHashList && _fileHashList[_fileHashListIndex] != 0) { uint32 smackerFileHash = _fileHashList[_fileHashListIndex]; ResourceHandle resourceHandle; diff --git a/engines/neverhood/sound.cpp b/engines/neverhood/sound.cpp index c84b751e44..c3bc3501b5 100644 --- a/engines/neverhood/sound.cpp +++ b/engines/neverhood/sound.cpp @@ -35,7 +35,7 @@ SoundResource::~SoundResource() { unload(); } -bool SoundResource::isPlaying() { +bool SoundResource::isPlaying() { AudioResourceManSoundItem *soundItem = getSoundItem(); return soundItem ? soundItem->isPlaying() : false; } @@ -94,7 +94,7 @@ MusicResource::MusicResource(NeverhoodEngine *vm) bool MusicResource::isPlaying() { AudioResourceManMusicItem *musicItem = getMusicItem(); - return musicItem && musicItem->isPlaying(); + return musicItem && musicItem->isPlaying(); } void MusicResource::load(uint32 fileHash) { @@ -134,7 +134,7 @@ AudioResourceManMusicItem *MusicResource::getMusicItem() { MusicItem::MusicItem(NeverhoodEngine *vm, uint32 groupNameHash, uint32 musicFileHash) : _vm(vm), _musicResource(NULL) { - + _groupNameHash = groupNameHash; _fileHash = musicFileHash; _play = false; @@ -187,7 +187,7 @@ SoundItem::SoundItem(NeverhoodEngine *vm, uint32 groupNameHash, uint32 soundFile _playOnceAfterRandomCountdown(false), _minCountdown(0), _maxCountdown(0), _playOnceAfterCountdown(playOnceAfterCountdown), _initialCountdown(initialCountdown), _playLooping(false), _currCountdown(currCountdown) { - + _soundResource = new SoundResource(vm); _soundResource->load(soundFileHash); } @@ -200,7 +200,7 @@ SoundItem::~SoundItem() { void SoundItem::setSoundParams(bool playOnceAfterRandomCountdown, int16 minCountdown, int16 maxCountdown, int16 firstMinCountdown, int16 firstMaxCountdown) { - + _playOnceAfterCountdown = false; _playLooping = false; _playOnceAfterRandomCountdown = playOnceAfterRandomCountdown; @@ -254,10 +254,26 @@ SoundMan::SoundMan(NeverhoodEngine *vm) } SoundMan::~SoundMan() { - for (uint i = 0; i < _soundItems.size(); ++i) - delete _soundItems[i]; - for (uint i = 0; i < _musicItems.size(); ++i) - delete _musicItems[i]; + stopAllSounds(); +} + +void SoundMan::stopAllSounds() { + for (uint i = 0; i < _soundItems.size(); ++i) { + if (_soundItems[i]) { + _soundItems[i]->stopSound(); + delete _soundItems[i]; + _soundItems[i] = NULL; + } + } + for (uint i = 0; i < _musicItems.size(); ++i) { + if (_musicItems[i]) { + _musicItems[i]->stopMusic(0, 0); + delete _musicItems[i]; + _musicItems[i] = NULL; + } + } + + _soundIndex1 = _soundIndex2 = _soundIndex3 = -1; } void SoundMan::addMusic(uint32 groupNameHash, uint32 musicFileHash) { @@ -345,7 +361,7 @@ void SoundMan::setSoundVolume(uint32 soundFileHash, int volume) { } void SoundMan::update() { - + for (uint i = 0; i < _soundItems.size(); ++i) { SoundItem *soundItem = _soundItems[i]; if (soundItem) @@ -440,7 +456,7 @@ void SoundMan::playSoundThree(uint32 groupNameHash, uint32 soundFileHash) { SoundItem *soundItem = new SoundItem(_vm, groupNameHash, soundFileHash, false, 0, 0, false, _initialCountdown3, false, 0); _soundIndex3 = addSoundItem(soundItem); } - + } void SoundMan::setTwoSoundsPlayFlag(bool playOnceAfterCountdown) { @@ -514,16 +530,16 @@ NeverhoodAudioStream::~NeverhoodAudioStream() { int NeverhoodAudioStream::readBuffer(int16 *buffer, const int numSamples) { int samplesLeft = numSamples; - + while (samplesLeft > 0 && !_endOfData) { const int maxSamples = MIN<int>(kSampleBufferLength, samplesLeft); const int bytesToRead = maxSamples * (_isCompressed ? 1 : 2); int bytesRead = _stream->read(_buffer, bytesToRead); int samplesRead = bytesRead / (_isCompressed ? 1 : 2); - + samplesLeft -= samplesRead; - + const byte *src = _buffer; if (_isCompressed) { while (samplesRead--) { @@ -678,7 +694,7 @@ void AudioResourceManMusicItem::update() { _start = false; _isPlaying = true; } - + if (_vm->_mixer->isSoundHandleActive(_soundHandle)) { if (_isFadingIn) { _fadeVolume += _fadeVolumeStep; @@ -708,11 +724,25 @@ AudioResourceMan::AudioResourceMan(NeverhoodEngine *vm) : _vm(vm) { } +void AudioResourceMan::stopAllSounds() { + for (uint i = 0; i < _soundItems.size(); ++i) { + if (_soundItems[i]) { + _soundItems[i]->stopSound(); + delete _soundItems[i]; + _soundItems[i] = NULL; + } + } + for (uint i = 0; i < _musicItems.size(); ++i) { + if (_musicItems[i]) { + _musicItems[i]->stopMusic(0); + delete _musicItems[i]; + _musicItems[i] = NULL; + } + } +} + AudioResourceMan::~AudioResourceMan() { - for (uint i = 0; i < _soundItems.size(); ++i) - delete _soundItems[i]; - for (uint i = 0; i < _musicItems.size(); ++i) - delete _musicItems[i]; + stopAllSounds(); } int16 AudioResourceMan::addSound(uint32 fileHash) { @@ -757,11 +787,11 @@ int16 AudioResourceMan::loadMusic(uint32 fileHash) { return i; } } - + int16 musicIndex = _musicItems.size(); _musicItems.push_back(musicItem); return musicIndex; - + } void AudioResourceMan::updateMusic() { diff --git a/engines/neverhood/sound.h b/engines/neverhood/sound.h index d3318998db..0733346daa 100644 --- a/engines/neverhood/sound.h +++ b/engines/neverhood/sound.h @@ -70,7 +70,7 @@ public: void setVolume(int16 volume); protected: NeverhoodEngine *_vm; - int16 _musicIndex; + int16 _musicIndex; AudioResourceManMusicItem *getMusicItem(); }; @@ -83,7 +83,7 @@ public: void update(); uint32 getGroupNameHash() const { return _groupNameHash; } uint32 getFileHash() const { return _fileHash; } -protected: +protected: NeverhoodEngine *_vm; uint32 _groupNameHash; uint32 _fileHash; @@ -110,7 +110,7 @@ public: uint32 getGroupNameHash() const { return _groupNameHash; } uint32 getFileHash() const { return _fileHash; } int16 getCurrCountdown() const { return _currCountdown; } -protected: +protected: NeverhoodEngine *_vm; uint32 _groupNameHash; uint32 _fileHash; @@ -129,12 +129,14 @@ public: SoundMan(NeverhoodEngine *vm); ~SoundMan(); + void stopAllSounds(); + // Music void addMusic(uint32 groupNameHash, uint32 musicFileHash); void deleteMusic(uint32 musicFileHash); void startMusic(uint32 musicFileHash, int16 countdown, int16 fadeVolumeStep); void stopMusic(uint32 musicFileHash, int16 countdown, int16 fadeVolumeStep); - + // Sound void addSound(uint32 groupNameHash, uint32 soundFileHash); void addSoundList(uint32 groupNameHash, const uint32 *soundFileHashList); @@ -146,7 +148,7 @@ public: void playSoundLooping(uint32 soundFileHash); void stopSound(uint32 soundFileHash); void setSoundVolume(uint32 soundFileHash, int volume); - + // Misc void update(); void deleteGroup(uint32 groupNameHash); @@ -159,25 +161,25 @@ public: protected: NeverhoodEngine *_vm; - + // TODO Find out what these special sounds are used for (door sounds?) int _soundIndex1, _soundIndex2; int16 _initialCountdown; bool _playOnceAfterCountdown; - + int _soundIndex3; int16 _initialCountdown3; bool _playOnceAfterCountdown3; Common::Array<MusicItem*> _musicItems; Common::Array<SoundItem*> _soundItems; - + MusicItem *getMusicItemByHash(uint32 musicFileHash); SoundItem *getSoundItemByHash(uint32 soundFileHash); int16 addMusicItem(MusicItem *musicItem); int16 addSoundItem(SoundItem *soundItem); void deleteSoundByIndex(int index); - + }; class NeverhoodAudioStream : public Audio::AudioStream { @@ -207,7 +209,7 @@ private: // TODO Rename these class AudioResourceManSoundItem { -public: +public: AudioResourceManSoundItem(NeverhoodEngine *vm, uint32 fileHash); void loadSound(); void unloadSound(); @@ -216,7 +218,7 @@ public: void playSound(bool looping); void stopSound(); bool isPlaying(); -protected: +protected: NeverhoodEngine *_vm; uint32 _fileHash; ResourceHandle _resourceHandle; @@ -241,7 +243,7 @@ public: bool canRestart() const { return _canRestart; } bool isTerminated() const { return _terminate; } uint32 getFileHash() const { return _fileHash; } -protected: +protected: NeverhoodEngine *_vm; uint32 _fileHash; bool _isPlaying; @@ -261,16 +263,18 @@ class AudioResourceMan { public: AudioResourceMan(NeverhoodEngine *vm); ~AudioResourceMan(); - + + void stopAllSounds(); + int16 addSound(uint32 fileHash); void removeSound(int16 soundIndex); int16 loadMusic(uint32 fileHash); void updateMusic(); - + AudioResourceManSoundItem *getSoundItem(int16 index); AudioResourceManMusicItem *getMusicItem(int16 index); - + protected: NeverhoodEngine *_vm; diff --git a/engines/neverhood/sprite.cpp b/engines/neverhood/sprite.cpp index 45d131fd3c..3c158ff7e3 100644 --- a/engines/neverhood/sprite.cpp +++ b/engines/neverhood/sprite.cpp @@ -28,11 +28,11 @@ namespace Neverhood { // Sprite Sprite::Sprite(NeverhoodEngine *vm, int objectPriority) - : Entity(vm, objectPriority), _x(0), _y(0), _spriteUpdateCb(NULL), _filterXCb(NULL), _filterYCb(NULL), + : Entity(vm, objectPriority), _x(0), _y(0), _spriteUpdateCb(NULL), _filterXCb(NULL), _filterYCb(NULL), _dataResource(vm), _doDeltaX(false), _doDeltaY(false), _needRefresh(false), _flags(0), _surface(NULL) { SetMessageHandler(&Sprite::handleMessage); - + } Sprite::~Sprite() { @@ -71,7 +71,7 @@ bool Sprite::isPointInside(int16 x, int16 y) { } bool Sprite::checkCollision(NRect &rect) { - return (_collisionBounds.x1 < rect.x2) && (rect.x1 < _collisionBounds.x2) && (_collisionBounds.y1 < rect.y2) && (rect.y1 < _collisionBounds.y2); + return (_collisionBounds.x1 < rect.x2) && (rect.x1 < _collisionBounds.x2) && (_collisionBounds.y1 < rect.y2) && (rect.y1 < _collisionBounds.y2); } uint32 Sprite::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -83,7 +83,7 @@ void Sprite::loadDataResource(uint32 fileHash) { } void Sprite::createSurface(int surfacePriority, int16 width, int16 height) { - _surface = new BaseSurface(_vm, surfacePriority, width, height); + _surface = new BaseSurface(_vm, surfacePriority, width, height, "sprite"); } int16 Sprite::defFilterY(int16 y) { @@ -153,13 +153,13 @@ void StaticSprite::updatePosition() { if (!_surface) return; - + if (_doDeltaX) { _surface->getDrawRect().x = filterX(_x - _drawOffset.x - _drawOffset.width + 1); } else { _surface->getDrawRect().x = filterX(_x + _drawOffset.x); } - + if (_doDeltaY) { _surface->getDrawRect().y = filterY(_y - _drawOffset.y - _drawOffset.height + 1); } else { @@ -261,7 +261,7 @@ void AnimatedSprite::updateAnim() { } if (_newAnimFileHash == 0 && _currFrameIndex != _currStickFrameIndex) { if (_currFrameTicks != 0 && (--_currFrameTicks == 0) && _animResource.getFrameCount() != 0) { - + if (_nextAnimFileHash != 0) { if (_animResource.load(_nextAnimFileHash)) { _currAnimFileHash = _nextAnimFileHash; @@ -270,7 +270,7 @@ void AnimatedSprite::updateAnim() { _currAnimFileHash = 0; } if (_replOldColor != _replNewColor) { - _animResource.setRepl(_replOldColor, _replNewColor); + _animResource.setRepl(_replOldColor, _replNewColor); } _nextAnimFileHash = 0; if (_animStatus != 0) { @@ -278,17 +278,17 @@ void AnimatedSprite::updateAnim() { _lastFrameIndex = _plLastFrameHash != 0 ? MAX<int16>(0, _animResource.getFrameIndex(_plLastFrameHash)) : _animResource.getFrameCount() - 1; } else { _currFrameIndex = _plFirstFrameIndex != -1 ? _plFirstFrameIndex : _animResource.getFrameCount() - 1; - _lastFrameIndex = _plLastFrameIndex != -1 ? _plLastFrameIndex : _animResource.getFrameCount() - 1; + _lastFrameIndex = _plLastFrameIndex != -1 ? _plLastFrameIndex : _animResource.getFrameCount() - 1; } } else { updateFrameIndex(); } if (_newAnimFileHash == 0) updateFrameInfo(); - } + } } } - + if (_newAnimFileHash != 0) { if (_animStatus == 2) { _currStickFrameIndex = _currFrameIndex; @@ -301,7 +301,7 @@ void AnimatedSprite::updateAnim() { _currAnimFileHash = 0; } if (_replOldColor != _replNewColor) { - _animResource.setRepl(_replOldColor, _replNewColor); + _animResource.setRepl(_replOldColor, _replNewColor); } _newAnimFileHash = 0; _currFrameIndex = _plFirstFrameHash != 0 ? MAX<int16>(0, _animResource.getFrameIndex(_plFirstFrameHash)) : 0; @@ -314,7 +314,7 @@ void AnimatedSprite::updateAnim() { _currAnimFileHash = 0; } if (_replOldColor != _replNewColor) { - _animResource.setRepl(_replOldColor, _replNewColor); + _animResource.setRepl(_replOldColor, _replNewColor); } _newAnimFileHash = 0; _currFrameIndex = _plFirstFrameIndex != -1 ? _plFirstFrameIndex : _animResource.getFrameCount() - 1; @@ -398,7 +398,7 @@ void AnimatedSprite::updateFrameInfo() { void AnimatedSprite::createSurface1(uint32 fileHash, int surfacePriority) { NDimensions dimensions = _animResource.loadSpriteDimensions(fileHash); - _surface = new BaseSurface(_vm, surfacePriority, dimensions.width, dimensions.height); + _surface = new BaseSurface(_vm, surfacePriority, dimensions.width, dimensions.height, "animated sprite"); } void AnimatedSprite::createShadowSurface1(BaseSurface *shadowSurface, uint32 fileHash, int surfacePriority) { diff --git a/engines/neverhood/staticdata.cpp b/engines/neverhood/staticdata.cpp index 3f89c2236f..006992641a 100644 --- a/engines/neverhood/staticdata.cpp +++ b/engines/neverhood/staticdata.cpp @@ -33,13 +33,13 @@ StaticData::~StaticData() { void StaticData::load(const char *filename) { Common::File fd; - + if (!fd.open(filename)) error("StaticData::load() Could not open %s", filename); - - fd.readUint32LE(); // magic + + fd.readUint32LE(); // magic fd.readUint32LE(); // version - + // Load message lists uint32 messageListsCount = fd.readUint32LE(); debug(3, "messageListsCount: %d", messageListsCount); @@ -84,7 +84,7 @@ void StaticData::load(const char *filename) { } _rectLists[id] = rectList; } - + // Load hit rects uint32 hitRectListsCount = fd.readUint32LE(); debug(3, "hitRectListsCount: %d", hitRectListsCount); diff --git a/engines/neverhood/todo.txt b/engines/neverhood/todo.txt deleted file mode 100644 index 9d781e06ec..0000000000 --- a/engines/neverhood/todo.txt +++ /dev/null @@ -1,45 +0,0 @@ -NOTE: -------- -Some of the TODOs should be done AFTER the whole game logic is implemented -else the game disasm and reimplemtation code become even more different -(unless I decide it's ok to do it :) - -TODOs which can be done any time: ------------------------------------ -- Cleanup -- Clean up staticdata structs to look more like the ones in create_neverhood - (e.g. by using template classes etc.) - - Or use a common base class and manage all stuff in one single table and cast stuff accordingly - -TODOs which should be done only after the game logic is finished: -------------------------------------------------------------------- -- Maybe rework organization of files (e.g. put ALL Sprites into one separate file, same with Modules and Scenes) - - This would solve the problem of how to organize stuff which is used several times, and less headers would have to be included - - The move special scenes (SmackerScene) into the scenes file - -DONE: -------- -- Implement game menus -- Rework sound system (I don't like that SoundResources need to be explicitly initialized in Scene constructors) - - Should be just a handle object which initializes itself - - Play routine should fill the handle so it can be stopped/queried later - - Basically like ScummVM own sound handles -- RE and implement yet unknown music/sound stuff -- Implement clever sprite redrawing code (dirty rectangles, microtiles etc.), only redraw what's neccessary -- Rework the resource system - - The current system can be simplified a lot - - Also resource purging needs to be implemented -- Maybe merge CollisionMan with Scene (since it's so far never used independently) -- Give placeholder stuff (e.g. sub?????, _flag??? etc.) better fitting names -- Use CursorMan for the mouse cursor (instead of using it like a normal sprite) - - This whould make it neccessary to call _system->updateScreen more often else - the mouse movement would be choppy - -TODOs which are experimental: -------------------------------- -NOTE: Since they affect the whole game, they really should be only implemented once the full game logic is implemented. -These are nothing more than wild ideas for now, any might never be implemented. -- Use states instead of separate callback methods -- Try to move more stuff to neverhood.dat -- Try to use more template functions instead of manually creating functions - (Can be coupled with the above to move parameters to the dat and only use IDs) diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 3135c3e8c5..f648f4b9a1 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -225,7 +225,7 @@ void DosDisk_br::loadBitmap(Common::SeekableReadStream &stream, Graphics::Surfac } surf.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); - stream.read(surf.pixels, width * height); + stream.read(surf.getPixels(), width * height); } Frames* DosDisk_br::loadPointer(const char *name) { @@ -449,7 +449,7 @@ void AmigaDisk_br::init() { void AmigaDisk_br::adjustForPalette(Graphics::Surface &surf, int transparentColor) { uint size = surf.w * surf.h; - byte *data = (byte *)surf.pixels; + byte *data = (byte *)surf.getPixels(); for (uint i = 0; i < size; i++, data++) { if (transparentColor == -1 || transparentColor != *data) *data += 16; @@ -552,7 +552,7 @@ MaskBuffer *AmigaDisk_br::loadMask(const char *name, uint32 w, uint32 h) { MaskBuffer *buffer = new MaskBuffer; // surface width was shrunk to 1/4th of the bitmap width due to the pixel packing buffer->create(decoder.getSurface()->w * 4, decoder.getSurface()->h); - memcpy(buffer->data, decoder.getSurface()->pixels, buffer->size); + memcpy(buffer->data, decoder.getSurface()->getPixels(), buffer->size); buffer->bigEndian = true; finalpass(buffer->data, buffer->size); return buffer; @@ -612,7 +612,7 @@ GfxObj* AmigaDisk_br::loadStatic(const char* name) { stream->read(shadow, shadowSize); for (int32 i = 0; i < surf->h; ++i) { byte *src = shadow + shadowWidth * i; - byte *dst = (byte *)surf->pixels + surf->pitch * i; + byte *dst = (byte *)surf->getPixels() + surf->pitch * i; for (int32 j = 0; j < surf->w; ++j, ++dst) { byte bit = src[j/8] & (1 << (7 - (j & 7))); diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp index 4c4893ec61..ae28e864a9 100644 --- a/engines/parallaction/disk_ns.cpp +++ b/engines/parallaction/disk_ns.cpp @@ -482,7 +482,7 @@ void DosDisk_ns::loadBackground(BackgroundInfo& info, const char *filename) { // read bitmap, mask and path data and extract them into the 3 buffers info.bg.create(info.width, info.height, Graphics::PixelFormat::createFormatCLUT8()); createMaskAndPathBuffers(info); - unpackBackground(stream, (byte *)info.bg.pixels, info._mask->data, info._path->data); + unpackBackground(stream, (byte *)info.bg.getPixels(), info._mask->data, info._path->data); delete stream; } @@ -976,7 +976,7 @@ void AmigaDisk_ns::loadMask_internal(BackgroundInfo& info, const char *name) { info._mask = new MaskBuffer; // surface width was shrunk to 1/4th of the bitmap width due to the pixel packing info._mask->create(decoder.getSurface()->w * 4, decoder.getSurface()->h); - memcpy(info._mask->data, decoder.getSurface()->pixels, info._mask->size); + memcpy(info._mask->data, decoder.getSurface()->getPixels(), info._mask->size); info._mask->bigEndian = true; } @@ -998,7 +998,7 @@ void AmigaDisk_ns::loadPath_internal(BackgroundInfo& info, const char *name) { info._path = new PathBuffer; // surface width was shrunk to 1/8th of the bitmap width due to the pixel packing info._path->create(decoder.getSurface()->w * 8, decoder.getSurface()->h); - memcpy(info._path->data, decoder.getSurface()->pixels, info._path->size); + memcpy(info._path->data, decoder.getSurface()->getPixels(), info._path->size); info._path->bigEndian = true; } diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index 3ea4332e50..816f220b1f 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -126,9 +126,7 @@ DECLARE_INSTRUCTION_OPCODE(put) { inst->_a->getFrameRect(r); Graphics::Surface v18; - v18.w = r.width(); - v18.h = r.height(); - v18.pixels = inst->_a->getFrameData(); + v18.init(r.width(), r.height(), r.width(), inst->_a->getFrameData(), Graphics::PixelFormat::createFormatCLUT8()); int16 x = inst->_opA.getValue(); int16 y = inst->_opB.getValue(); diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index b8a8ceb61f..3f36d56420 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -332,7 +332,7 @@ void Gfx::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int void Gfx::clearScreen() { if (_doubleBuffering) { - if (_backBuffer.pixels) { + if (_backBuffer.getPixels()) { Common::Rect r(_backBuffer.w, _backBuffer.h); _backBuffer.fillRect(r, 0); } @@ -419,13 +419,13 @@ void Gfx::updateScreen() { // is needed _overlayMode = false; - bool skipBackground = (_backgroundInfo->bg.pixels == 0); // don't render frame if background is missing + bool skipBackground = (_backgroundInfo->bg.getPixels() == 0); // don't render frame if background is missing if (!skipBackground) { // background may not cover the whole screen, so adjust bulk update size uint w = _backgroundInfo->width; uint h = _backgroundInfo->height; - byte *backgroundData = (byte *)_backgroundInfo->bg.getBasePtr(0, 0); + byte *backgroundData = (byte *)_backgroundInfo->bg.getPixels(); uint16 backgroundPitch = _backgroundInfo->bg.pitch; copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo->_x, _backgroundInfo->_y, w, h); } @@ -450,7 +450,7 @@ void Gfx::applyHalfbriteEffect_NS(Graphics::Surface &surf) { return; } - byte *buf = (byte *)surf.pixels; + byte *buf = (byte *)surf.getPixels(); for (int i = 0; i < surf.w*surf.h; i++) { *buf++ |= 0x20; } @@ -493,7 +493,7 @@ void Gfx::patchBackground(Graphics::Surface &surf, int16 x, int16 y, bool mask) r.moveTo(x, y); uint16 z = (mask) ? _backgroundInfo->getMaskLayer(y) : LAYER_FOREGROUND; - blt(r, (byte *)surf.pixels, &_backgroundInfo->bg, z, 100, 0); + blt(r, (byte *)surf.getPixels(), &_backgroundInfo->bg, z, 100, 0); } void Gfx::fillBackground(const Common::Rect& r, byte color) { @@ -536,12 +536,12 @@ GfxObj *Gfx::renderFloatingLabel(Font *font, char *text) { setupLabelSurface(*cnv, w, h); font->setColor((_gameType == GType_BRA) ? 0 : 7); - font->drawString((byte *)cnv->pixels + 1, cnv->w, text); - font->drawString((byte *)cnv->pixels + 1 + cnv->w * 2, cnv->w, text); - font->drawString((byte *)cnv->pixels + cnv->w, cnv->w, text); - font->drawString((byte *)cnv->pixels + 2 + cnv->w, cnv->w, text); + font->drawString((byte *)cnv->getBasePtr(1, 0), cnv->w, text); + font->drawString((byte *)cnv->getBasePtr(1, 2), cnv->w, text); + font->drawString((byte *)cnv->getBasePtr(0, 1), cnv->w, text); + font->drawString((byte *)cnv->getBasePtr(2, 1), cnv->w, text); font->setColor((_gameType == GType_BRA) ? 11 : 1); - font->drawString((byte *)cnv->pixels + 1 + cnv->w, cnv->w, text); + font->drawString((byte *)cnv->getBasePtr(1, 1), cnv->w, text); } else { w = font->getStringWidth(text); h = font->height(); @@ -704,7 +704,7 @@ void Gfx::unregisterLabel(GfxObj *label) { void Gfx::copyRect(const Common::Rect &r, Graphics::Surface &src, Graphics::Surface &dst) { byte *s = (byte *)src.getBasePtr(r.left, r.top); - byte *d = (byte *)dst.getBasePtr(0, 0); + byte *d = (byte *)dst.getPixels(); for (uint16 i = 0; i < r.height(); i++) { memcpy(d, s, r.width()); diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index bf7cdc439d..a445ce0138 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -499,7 +499,7 @@ void Input::initCursors() { // TODO: scale mouse cursor (see staticres.cpp) Graphics::Surface *surf2 = new Graphics::Surface; surf2->create(32, 16, Graphics::PixelFormat::createFormatCLUT8()); - memcpy(surf2->pixels, _resMouseArrow_BR_Amiga, 32*16); + memcpy(surf2->getPixels(), _resMouseArrow_BR_Amiga, 32*16); _mouseArrow = new SurfaceToFrames(surf2); } break; diff --git a/engines/parallaction/inventory.h b/engines/parallaction/inventory.h index a3b7bf953f..d5cf8badf0 100644 --- a/engines/parallaction/inventory.h +++ b/engines/parallaction/inventory.h @@ -108,7 +108,7 @@ public: void highlightItem(ItemPosition pos, byte color); void drawItem(ItemName name, byte *buffer, uint pitch); - byte* getData() const { return (byte *)_surf.pixels; } + byte *getData() { return (byte *)_surf.getPixels(); } void getRect(Common::Rect &r) const; int16 getNumLines() const; diff --git a/engines/pegasus/cursor.cpp b/engines/pegasus/cursor.cpp index 897d31d7bd..ad0d2c2d7d 100644 --- a/engines/pegasus/cursor.cpp +++ b/engines/pegasus/cursor.cpp @@ -85,9 +85,9 @@ void Cursor::setCurrentFrameIndex(int32 index) { if (_info[index].surface->format.bytesPerPixel == 1) { CursorMan.replaceCursorPalette(_info[index].palette, 0, _info[index].colorCount); - CursorMan.replaceCursor(_info[index].surface->pixels, _info[index].surface->w, _info[index].surface->h, _info[index].hotspot.x, _info[index].hotspot.y, 0); + CursorMan.replaceCursor(_info[index].surface->getPixels(), _info[index].surface->w, _info[index].surface->h, _info[index].hotspot.x, _info[index].hotspot.y, 0); } else { - CursorMan.replaceCursor(_info[index].surface->pixels, _info[index].surface->w, _info[index].surface->h, _info[index].hotspot.x, _info[index].hotspot.y, _info[index].surface->format.RGBToColor(0xFF, 0xFF, 0xFF), false, &_info[index].surface->format); + CursorMan.replaceCursor(_info[index].surface->getPixels(), _info[index].surface->w, _info[index].surface->h, _info[index].hotspot.x, _info[index].hotspot.y, _info[index].surface->format.RGBToColor(0xFF, 0xFF, 0xFF), false, &_info[index].surface->format); } ((PegasusEngine *)g_engine)->_gfx->markCursorAsDirty(); @@ -203,7 +203,7 @@ void Cursor::loadCursorImage(CursorInfo &cursorInfo) { // PixMap data if (pixMap.pixelSize == 8) { cursorInfo.surface->create(pixMap.rowBytes, pixMap.bounds.height(), Graphics::PixelFormat::createFormatCLUT8()); - cicnStream->read(cursorInfo.surface->pixels, pixMap.rowBytes * pixMap.bounds.height()); + cicnStream->read(cursorInfo.surface->getPixels(), pixMap.rowBytes * pixMap.bounds.height()); // While this looks sensible, it actually doesn't work for some cursors // (ie. the 'can grab' hand) diff --git a/engines/pegasus/graphics.cpp b/engines/pegasus/graphics.cpp index 8dbd678809..5475108abd 100644 --- a/engines/pegasus/graphics.cpp +++ b/engines/pegasus/graphics.cpp @@ -318,7 +318,7 @@ void GraphicsManager::shakeTheWorld(TimeValue duration, TimeScale scale) { } if (lastOffset.x != 0 || lastOffset.y != 0) { - g_system->copyRectToScreen((byte *)oldScreen.pixels, oldScreen.pitch, 0, 0, 640, 480); + g_system->copyRectToScreen((byte *)oldScreen.getPixels(), oldScreen.pitch, 0, 0, 640, 480); g_system->updateScreen(); } diff --git a/engines/pegasus/neighborhood/caldoria/caldoria.cpp b/engines/pegasus/neighborhood/caldoria/caldoria.cpp index 9a378a6728..0b3e1ee040 100644 --- a/engines/pegasus/neighborhood/caldoria/caldoria.cpp +++ b/engines/pegasus/neighborhood/caldoria/caldoria.cpp @@ -200,7 +200,7 @@ void Caldoria::start() { const Graphics::Surface *frame = pullbackMovie->decodeNextFrame(); assert(frame); assert(frame->format == g_system->getScreenFormat()); - g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, 64, 112, frame->w, frame->h); + g_system->copyRectToScreen((const byte *)frame->getPixels(), frame->pitch, 64, 112, frame->w, frame->h); _vm->_gfx->doFadeInSync(kTwoSeconds * kFifteenTicksPerSecond, kFifteenTicksPerSecond); bool saveAllowed = _vm->swapSaveAllowed(false); @@ -216,7 +216,7 @@ void Caldoria::start() { frame = pullbackMovie->decodeNextFrame(); if (frame) { - g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, 64, 112, frame->w, frame->h); + g_system->copyRectToScreen((const byte *)frame->getPixels(), frame->pitch, 64, 112, frame->w, frame->h); g_system->updateScreen(); } } diff --git a/engines/pegasus/neighborhood/neighborhood.cpp b/engines/pegasus/neighborhood/neighborhood.cpp index 38366c4ba2..3116bd7978 100644 --- a/engines/pegasus/neighborhood/neighborhood.cpp +++ b/engines/pegasus/neighborhood/neighborhood.cpp @@ -1364,7 +1364,7 @@ void Neighborhood::setUpAIRules() { if (g_AIArea) { g_AIArea->forceAIUnlocked(); - if (!_vm->isDemo() && (getObjectID() == kPrehistoricID || getObjectID() == kNoradAlphaID || + if (!_vm->isOldDemo() && (getObjectID() == kPrehistoricID || getObjectID() == kNoradAlphaID || getObjectID() == kNoradDeltaID || getObjectID() == kMarsID || getObjectID() == kWSCID)) { AIEnergyMonitorCondition *condition50 = new AIEnergyMonitorCondition(kWorriedEnergy); diff --git a/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp b/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp index 169f75f7d2..3491f161c7 100644 --- a/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp +++ b/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp @@ -201,7 +201,7 @@ void NoradAlphaFillingStation::showIntakeInProgress(uint16 numSeconds) { if (item->getObjectID() == kGasCanister) { GameState.setNoradGassed(true); - ((NoradAlpha *)getOwner())->loadAmbientLoops(); + ((NoradAlpha *)getOwner())->checkAirMask(); getOwner()->restoreStriding(kNorad03, kEast, kAltNoradAlphaNormal); } } else { diff --git a/engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp b/engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp index e4a5e26473..6a24113465 100644 --- a/engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp +++ b/engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp @@ -576,7 +576,7 @@ void NoradAlpha::takeItemFromRoom(Item *item) { if (_fillingStationItem == item) { _fillingStationItem = 0; GameState.setNoradGassed(false); - loadAmbientLoops(); + checkAirMask(); ((NoradAlphaFillingStation *)_currentInteraction)->newFillingItem(0); forceStridingStop(kNorad03, kEast, kAltNoradAlphaNormal); } diff --git a/engines/pegasus/neighborhood/norad/norad.cpp b/engines/pegasus/neighborhood/norad/norad.cpp index 578f062dea..53b3ff9add 100644 --- a/engines/pegasus/neighborhood/norad/norad.cpp +++ b/engines/pegasus/neighborhood/norad/norad.cpp @@ -241,7 +241,9 @@ void Norad::setUpAirMask() { } void Norad::checkAirMask() { - if (g_airMask && g_airMask->isAirFilterOn()) { + // WORKAROUND: The original game forgot to handle the case where the canister would + // be removed, leading to the timer remaining active. + if (!GameState.getNoradGassed() || (g_airMask && g_airMask->isAirFilterOn())) { _airMaskTimer.stop(); } else if (GameState.getNoradGassed() && !_airMaskTimer.isRunning()) { _airMaskTimer.setTime(0); diff --git a/engines/pegasus/pegasus.cpp b/engines/pegasus/pegasus.cpp index 463e81e52e..3bd29ce8dd 100644 --- a/engines/pegasus/pegasus.cpp +++ b/engines/pegasus/pegasus.cpp @@ -313,7 +313,7 @@ void PegasusEngine::runIntro() { const Graphics::Surface *frame = video->decodeNextFrame(); if (frame) { - _system->copyRectToScreen((byte *)frame->pixels, frame->pitch, 0, 0, frame->w, frame->h); + _system->copyRectToScreen((const byte *)frame->getPixels(), frame->pitch, 0, 0, frame->w, frame->h); _system->updateScreen(); } } @@ -1367,7 +1367,7 @@ bool PegasusEngine::playMovieScaled(Video::VideoDecoder *video, uint16 x, uint16 if (frame->w <= 320 && frame->h <= 240) { drawScaledFrame(frame, x, y); } else { - _system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h); + _system->copyRectToScreen((const byte *)frame->getPixels(), frame->pitch, x, y, frame->w, frame->h); _system->updateScreen(); } } @@ -2270,11 +2270,11 @@ void PegasusEngine::drawScaledFrame(const Graphics::Surface *frame, uint16 x, ui scaledFrame.create(frame->w * 2, frame->h * 2, frame->format); if (frame->format.bytesPerPixel == 2) - scaleFrame<uint16>((uint16 *)frame->pixels, (uint16 *)scaledFrame.pixels, frame->w, frame->h, frame->pitch); + scaleFrame<uint16>((const uint16 *)frame->getPixels(), (uint16 *)scaledFrame.getPixels(), frame->w, frame->h, frame->pitch); else - scaleFrame<uint32>((uint32 *)frame->pixels, (uint32 *)scaledFrame.pixels, frame->w, frame->h, frame->pitch); + scaleFrame<uint32>((const uint32 *)frame->getPixels(), (uint32 *)scaledFrame.getPixels(), frame->w, frame->h, frame->pitch); - _system->copyRectToScreen((byte *)scaledFrame.pixels, scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h); + _system->copyRectToScreen((byte *)scaledFrame.getPixels(), scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h); _system->updateScreen(); scaledFrame.free(); } diff --git a/engines/pegasus/timers.cpp b/engines/pegasus/timers.cpp index 50cc9bc6d8..8463d866e8 100644 --- a/engines/pegasus/timers.cpp +++ b/engines/pegasus/timers.cpp @@ -115,7 +115,7 @@ void TimeBase::stop() { void TimeBase::pause() { if (isRunning() && !_paused) { _pausedRate = getRate(); - stop(); + _rate = 0; _paused = true; _pauseStart = g_system->getMillis(); } @@ -123,7 +123,7 @@ void TimeBase::pause() { void TimeBase::resume() { if (_paused) { - setRate(_pausedRate); + _rate = _pausedRate; _paused = false; if (isRunning()) diff --git a/engines/pegasus/transition.cpp b/engines/pegasus/transition.cpp index 1ae212df85..b736b115ee 100644 --- a/engines/pegasus/transition.cpp +++ b/engines/pegasus/transition.cpp @@ -70,7 +70,7 @@ void ScreenFader::setFaderValue(const int32 value) { if (value != getFaderValue()) { Fader::setFaderValue(value); - if (_screen->pixels) { + if (_screen->getPixels()) { // The original game does a gamma fade here using the Mac API. In order to do // that, it would require an immense amount of CPU processing. This does a // linear fade instead, which looks fairly well, IMO. diff --git a/engines/plugins_table.h b/engines/plugins_table.h index 6d623e5003..d1519c367f 100644 --- a/engines/plugins_table.h +++ b/engines/plugins_table.h @@ -47,6 +47,9 @@ LINK_PLUGIN(HUGO) #if PLUGIN_ENABLED_STATIC(KYRA) LINK_PLUGIN(KYRA) #endif +#if PLUGIN_ENABLED_STATIC(MORTEVIELLE) +LINK_PLUGIN(MORTEVIELLE) +#endif #if PLUGIN_ENABLED_STATIC(LASTEXPRESS) LINK_PLUGIN(LASTEXPRESS) #endif diff --git a/engines/saga/animation.cpp b/engines/saga/animation.cpp index fd602ff4fb..df8283b4c2 100644 --- a/engines/saga/animation.cpp +++ b/engines/saga/animation.cpp @@ -185,7 +185,7 @@ int Anim::playCutaway(int cut, bool fade) { event.time = (40 / 3) * 1000 / _cutawayList[cut].frameRate; if (fade) - eventColumns = _vm->_events->chain(eventColumns, event); + _vm->_events->chain(eventColumns, event); else _vm->_events->queue(event); } @@ -501,7 +501,7 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) { } anim = getAnimation(animId); - displayBuffer = (byte *)_vm->_render->getBackGroundSurface()->pixels; + displayBuffer = (byte *)_vm->_render->getBackGroundSurface()->getPixels(); if (playing) { anim->state = ANIM_PLAYING; diff --git a/engines/saga/gfx.h b/engines/saga/gfx.h index c677b76324..c68160e907 100644 --- a/engines/saga/gfx.h +++ b/engines/saga/gfx.h @@ -201,7 +201,7 @@ public: // Whenever it gets called, the corresponding caller must take care // to add the corresponding dirty rectangle itself byte *getBackBufferPixels() { - return (byte *)_backBuffer.pixels; + return (byte *)_backBuffer.getPixels(); } uint16 getBackBufferWidth() { diff --git a/engines/saga/introproc_ihnm.cpp b/engines/saga/introproc_ihnm.cpp index 6015e6757a..7922d56425 100644 --- a/engines/saga/introproc_ihnm.cpp +++ b/engines/saga/introproc_ihnm.cpp @@ -212,7 +212,7 @@ bool Scene::playTitle(int title, int time, int mode) { break; case 2: // display background - _vm->_system->copyRectToScreen(backBufferSurface->pixels, backBufferSurface->w, 0, 0, + _vm->_system->copyRectToScreen(backBufferSurface->getPixels(), backBufferSurface->w, 0, 0, backBufferSurface->w, backBufferSurface->h); phase++; startTime = curTime; @@ -247,7 +247,7 @@ bool Scene::playTitle(int title, int time, int mode) { frameTime = curTime; - _vm->_system->copyRectToScreen(backBufferSurface->pixels, backBufferSurface->w, 0, 0, + _vm->_system->copyRectToScreen(backBufferSurface->getPixels(), backBufferSurface->w, 0, 0, backBufferSurface->w, backBufferSurface->h); } @@ -273,8 +273,8 @@ bool Scene::playTitle(int title, int time, int mode) { _vm->_anim->endVideo(); - memset((byte *)backBufferSurface->pixels, 0, backBufferSurface->w * backBufferSurface->h); - _vm->_system->copyRectToScreen(backBufferSurface->pixels, backBufferSurface->w, 0, 0, + memset((byte *)backBufferSurface->getPixels(), 0, backBufferSurface->w * backBufferSurface->h); + _vm->_system->copyRectToScreen(backBufferSurface->getPixels(), backBufferSurface->w, 0, 0, backBufferSurface->w, backBufferSurface->h); return interrupted; diff --git a/engines/saga/introproc_saga2.cpp b/engines/saga/introproc_saga2.cpp index 260eca98e6..e61dfbf161 100644 --- a/engines/saga/introproc_saga2.cpp +++ b/engines/saga/introproc_saga2.cpp @@ -108,7 +108,7 @@ void Scene::playMovie(const char *filename) { if (smkDecoder->needsUpdate()) { const Graphics::Surface *frame = smkDecoder->decodeNextFrame(); if (frame) { - _vm->_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, frame->w, frame->h); + _vm->_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, frame->w, frame->h); if (smkDecoder->hasDirtyPalette()) _vm->_system->getPaletteManager()->setPalette(smkDecoder->getPalette(), 0, 256); diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp index 812d967b9f..3ac89bc2c2 100644 --- a/engines/saga/music.cpp +++ b/engines/saga/music.cpp @@ -364,7 +364,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) { // Load MIDI/XMI resource data if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) { - // Load the external music file for Mac IHNM + // Load the external music file for Mac IHNM _player->playQuickTime(Common::String::format("Music/Music%02x", resourceId), flags & MUSIC_LOOP); } else { if (_currentMusicBuffer == &_musicBuffer[1]) { diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp index 75876b1c90..eff31cf98b 100644 --- a/engines/saga/scene.cpp +++ b/engines/saga/scene.cpp @@ -468,7 +468,7 @@ void Scene::changeScene(int16 sceneNumber, int actorsEntrance, SceneTransitionTy pal = decoder.getPalette(); rect.setWidth(decoder.getSurface()->w); rect.setHeight(decoder.getSurface()->h); - _vm->_gfx->drawRegion(rect, (const byte *)decoder.getSurface()->pixels); + _vm->_gfx->drawRegion(rect, (const byte *)decoder.getSurface()->getPixels()); for (int j = 0; j < PAL_ENTRIES; j++) { cPal[j].red = *pal++; cPal[j].green = *pal++; @@ -1120,9 +1120,9 @@ void Scene::draw() { _vm->_render->getBackGroundSurface()->getRect(rect); rect.bottom = (_sceneClip.bottom < rect.bottom) ? getHeight() : rect.bottom; if (_vm->_render->isFullRefresh()) - _vm->_gfx->drawRegion(rect, (const byte *)_vm->_render->getBackGroundSurface()->pixels); + _vm->_gfx->drawRegion(rect, (const byte *)_vm->_render->getBackGroundSurface()->getPixels()); else - _vm->_gfx->drawBgRegion(rect, (const byte *)_vm->_render->getBackGroundSurface()->pixels); + _vm->_gfx->drawBgRegion(rect, (const byte *)_vm->_render->getBackGroundSurface()->getPixels()); } } diff --git a/engines/saga/shorten.cpp b/engines/saga/shorten.cpp index 69c27b6a6b..619ffc243e 100644 --- a/engines/saga/shorten.cpp +++ b/engines/saga/shorten.cpp @@ -196,11 +196,13 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by break; case kTypeS16LH: flags |= Audio::FLAG_LITTLE_ENDIAN; + // fallthrough case kTypeS16HL: flags |= Audio::FLAG_16BITS; break; case kTypeU16LH: flags |= Audio::FLAG_LITTLE_ENDIAN; + // fallthrough case kTypeU16HL: flags |= Audio::FLAG_16BITS; flags |= Audio::FLAG_UNSIGNED; diff --git a/engines/saga/sndres.cpp b/engines/saga/sndres.cpp index 49d24753a1..ca843af465 100644 --- a/engines/saga/sndres.cpp +++ b/engines/saga/sndres.cpp @@ -249,11 +249,11 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff if (!memcmp(header, "Creative", 8)) { resourceType = kSoundVOC; - } else if (!memcmp(header, "RIFF", 4) != 0) { + } else if (!memcmp(header, "RIFF", 4)) { resourceType = kSoundWAV; - } else if (!memcmp(header, "FORM", 4) != 0) { + } else if (!memcmp(header, "FORM", 4)) { resourceType = kSoundAIFF; - } else if (!memcmp(header, "ajkg", 4) != 0) { + } else if (!memcmp(header, "ajkg", 4)) { resourceType = kSoundShorten; } diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index 66164a1937..7c4638a992 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -1054,6 +1054,23 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformWindows, ADGF_CD, GUIO4(GUIO_MIDIGM, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_FB01_MIDI, GAMEOPTION_JONES_CDAUDIO) }, + // Jones in the Fast Lane - English DOS US CD (alternate version) + // Supplied by collector9 in bug #3614668 + {"jones", "CD", { + {"resource.map", 0, "4344ff3f796707843b992adec2c87663", 4878}, + {"resource.001", 0, "3876da2ce16fb7dea2f5d943d946fa84", 1652062}, + AD_LISTEND}, + Common::EN_ANY, Common::kPlatformDOS, ADGF_CD, GUIO1(GAMEOPTION_JONES_CDAUDIO) }, + + // Jones in the Fast Lane - English DOS US CD (alternate version) + // Same entry as the DOS version above. This one is used for the alternate + // General MIDI music tracks in the Windows version + {"jones", "CD", { + {"resource.map", 0, "4344ff3f796707843b992adec2c87663", 4878}, + {"resource.001", 0, "3876da2ce16fb7dea2f5d943d946fa84", 1652062}, + AD_LISTEND}, + Common::EN_ANY, Common::kPlatformWindows, ADGF_CD, GUIO4(GUIO_MIDIGM, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_FB01_MIDI, GAMEOPTION_JONES_CDAUDIO) }, + // King's Quest 1 SCI Remake - English Amiga (from www.back2roots.org) // Executable scanning reports "1.003.007" // SCI interpreter version 0.001.010 diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp index 64793efa6c..3c223bebbe 100644 --- a/engines/sci/engine/kpathing.cpp +++ b/engines/sci/engine/kpathing.cpp @@ -1966,7 +1966,7 @@ static bool isVertexCovered(const Patch &p, unsigned int wi) { // ---w1--1----p----w2--2---- // ^ \ (inside) if (wi > p.indexw1 && wi <= p.indexw2) - return true; + return true; // v / (outside) // ---w2--2----p----w1--1---- diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp index 15a9f54996..d72b1d1772 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -551,7 +551,7 @@ reg_t kMessage(EngineState *s, int argc, reg_t *argv) { // NOTE: To fix a corrupted jar object, type "send Glass_Jar message 52" // in the debugger. if (g_sci->getGameId() == GID_PEPPER && func == 0 && argc >= 6 && module == 894 && - tuple.noun == 26 && tuple.cond == 0 && tuple.seq == 1 && + tuple.noun == 26 && tuple.cond == 0 && tuple.seq == 1 && !s->_msgState->getMessage(module, tuple, NULL_REG)) tuple.verb = 0; diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index 9b0cb38f51..3964ccc1f8 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -103,10 +103,10 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) { if (frame) { if (scaleBuffer) { // TODO: Probably should do aspect ratio correction in e.g. GK1 Windows - g_sci->_gfxScreen->scale2x((byte *)frame->pixels, scaleBuffer, videoDecoder->getWidth(), videoDecoder->getHeight(), bytesPerPixel); + g_sci->_gfxScreen->scale2x((const byte *)frame->getPixels(), scaleBuffer, videoDecoder->getWidth(), videoDecoder->getHeight(), bytesPerPixel); g_system->copyRectToScreen(scaleBuffer, pitch, x, y, width, height); } else { - g_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, width, height); + g_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, width, height); } if (videoDecoder->hasDirtyPalette()) { diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index bf1ce6da64..76510fa53b 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -532,7 +532,7 @@ void GfxFrameout::showVideo() { if (videoDecoder->needsUpdate()) { const Graphics::Surface *frame = videoDecoder->decodeNextFrame(); if (frame) { - g_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, frame->w, frame->h); + g_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, frame->w, frame->h); if (videoDecoder->hasDirtyPalette()) g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256); @@ -745,7 +745,7 @@ void GfxFrameout::kernelFrameout() { // Process global scaling, if needed. // TODO: Seems like SCI32 always processes global scaling for scaled objects // TODO: We can only process symmetrical scaling for now (i.e. same value for scaleX/scaleY) - if ((itemEntry->scaleSignal & kScaleSignalDoScaling32) && + if ((itemEntry->scaleSignal & kScaleSignalDoScaling32) && !(itemEntry->scaleSignal & kScaleSignalDisableGlobalScaling32) && (itemEntry->scaleX == itemEntry->scaleY) && itemEntry->scaleX != 128) @@ -779,6 +779,14 @@ void GfxFrameout::kernelFrameout() { _coordAdjuster->fromDisplayToScript(nsRect.bottom, nsRect.right); g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect); } + + // TODO: For some reason, the top left nsRect coordinates get + // swapped in the GK1 inventory screen, investigate why. + // HACK: Fix the coordinates by explicitly setting them here. + Common::Rect objNSRect = g_sci->_gfxCompare->getNSRect(itemEntry->object); + if (objNSRect.top == nsRect.left && objNSRect.left == nsRect.top && nsRect.top != 0 && nsRect.left != 0) { + g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect); + } } // Don't attempt to draw sprites that are outside the visible diff --git a/engines/sci/graphics/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp index dfb50b0edb..4df80b289f 100644 --- a/engines/sci/graphics/maciconbar.cpp +++ b/engines/sci/graphics/maciconbar.cpp @@ -129,7 +129,7 @@ void GfxMacIconBar::drawIcon(uint16 iconIndex, bool selected) { void GfxMacIconBar::drawEnabledImage(Graphics::Surface *surface, const Common::Rect &rect) { if (surface) - g_system->copyRectToScreen(surface->pixels, surface->pitch, rect.left, rect.top, rect.width(), rect.height()); + g_system->copyRectToScreen(surface->getPixels(), surface->pitch, rect.left, rect.top, rect.width(), rect.height()); } void GfxMacIconBar::drawDisabledImage(Graphics::Surface *surface, const Common::Rect &rect) { @@ -153,7 +153,7 @@ void GfxMacIconBar::drawDisabledImage(Graphics::Surface *surface, const Common:: *((byte *)newSurf.getBasePtr(j, i)) = 0; } - g_system->copyRectToScreen(newSurf.pixels, newSurf.pitch, rect.left, rect.top, rect.width(), rect.height()); + g_system->copyRectToScreen(newSurf.getPixels(), newSurf.pitch, rect.left, rect.top, rect.width(), rect.height()); newSurf.free(); } @@ -224,7 +224,7 @@ Graphics::Surface *GfxMacIconBar::createImage(uint32 iconIndex, bool isSelected) } void GfxMacIconBar::remapColors(Graphics::Surface *surf, const byte *palette) { - byte *pixels = (byte *)surf->pixels; + byte *pixels = (byte *)surf->getPixels(); // Remap to the screen palette for (uint16 i = 0; i < surf->w * surf->h; i++) { diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp index 527e2ae973..6d9dc03195 100644 --- a/engines/sci/graphics/ports.cpp +++ b/engines/sci/graphics/ports.cpp @@ -116,7 +116,7 @@ void GfxPorts::init(bool usesOldGfxFunctions, GfxPaint16 *paint16, GfxText16 *te setPort(_wmgrPort); // SCI0 games till kq4 (.502 - not including) did not adjust against _wmgrPort in kNewWindow // We leave _wmgrPort top at 0, so the adjustment wont get done - if (!g_sci->_features->usesOldGfxFunctions()) { + if (!_usesOldGfxFunctions) { setOrigin(0, offTop); _wmgrPort->rect.bottom = _screen->getHeight() - offTop; } else { @@ -131,7 +131,7 @@ void GfxPorts::init(bool usesOldGfxFunctions, GfxPaint16 *paint16, GfxText16 *te _picWind = addWindow(Common::Rect(0, offTop, _screen->getWidth(), _screen->getHeight()), 0, 0, SCI_WINDOWMGR_STYLE_TRANSPARENT | SCI_WINDOWMGR_STYLE_NOFRAME, 0, true); // For SCI0 games till kq4 (.502 - not including) we set _picWind top to offTop instead // Because of the menu/status bar - if (g_sci->_features->usesOldGfxFunctions()) + if (_usesOldGfxFunctions) _picWind->top = offTop; kernelInitPriorityBands(); diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp index 74503c0c77..7b92bc89eb 100644 --- a/engines/sci/graphics/screen.cpp +++ b/engines/sci/graphics/screen.cpp @@ -170,14 +170,14 @@ void GfxScreen::copyToScreen() { void GfxScreen::copyFromScreen(byte *buffer) { // TODO this ignores the pitch Graphics::Surface *screen = g_system->lockScreen(); - memcpy(buffer, screen->pixels, _displayPixels); + memcpy(buffer, screen->getPixels(), _displayPixels); g_system->unlockScreen(); } void GfxScreen::kernelSyncWithFramebuffer() { // TODO this ignores the pitch Graphics::Surface *screen = g_system->lockScreen(); - memcpy(_displayScreen, screen->pixels, _displayPixels); + memcpy(_displayScreen, screen->getPixels(), _displayPixels); g_system->unlockScreen(); } diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp index 9546b1503f..9653d9ccff 100644 --- a/engines/sci/sound/midiparser_sci.cpp +++ b/engines/sci/sound/midiparser_sci.cpp @@ -57,6 +57,7 @@ MidiParser_SCI::MidiParser_SCI(SciVersion soundVersion, SciMusic *music) : _signalToSet = 0; _dataincAdd = false; _dataincToAdd = 0; + _jumpToHoldTick = false; _resetOnPause = false; _pSnd = 0; } @@ -452,6 +453,10 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) { debugC(4, kDebugLevelSound, "signal %04x", _signalToSet); } + if (_jumpToHoldTick) { + _jumpToHoldTick = false; + jumpToTick(_loopTick, false, false); + } info.start = _position._playPos; info.delta = 0; @@ -486,6 +491,10 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) { // though, so ignoring these signals in SCI0 games will result // in glitches (e.g. the intro of LB1 Amiga gets stuck - bug // #3297883). Refer to MusicEntry::setSignal() in sound/music.cpp. + // FIXME: SSCI doesn't start playing at the very beginning + // of the stream, but at a fixed location a few commands later. + // That is probably why this signal isn't triggered + // immediately there. if (_soundVersion <= SCI_VERSION_0_LATE || _position._playTick || info.delta) { _signalSet = true; @@ -531,10 +540,15 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) { // Check if the hold ID marker is the same as the hold ID // marker set for that song by cmdSetSoundHold. // If it is, loop back, but don't stop notes when jumping. + // We need to wait for the delta of the current event before + // jumping, thus the jump will be performed on the next + // parseNextEvent() call, like with the signal set events. + // In LSL6, room 360, song 381, this ends up jumping forward + // one tick (the hold marker occurs at playtick 27, with + // _loopTick being 15 and the event itself having a delta of + // 13, total = 28) - bug #3614566. if (info.basic.param2 == _pSnd->hold) { - uint32 extraDelta = info.delta; - jumpToTick(_loopTick, false, false); - _nextEvent.delta += extraDelta; + _jumpToHoldTick = true; } break; case kUpdateCue: @@ -637,7 +651,14 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) { // (e.g. song 110, during the intro). The original interpreter // treats this case as an infinite loop (bug #3311911). if (_pSnd->loop || _pSnd->hold > 0) { - // We need to play it again... + // TODO: this jump is also vulnerable to the same lockup as + // the MIDI hold one above. However, we can't perform the + // jump on the next tick like with the MIDI hold jump above, + // as there aren't any subsequent MIDI events after this one. + // This assert is here to detect cases where the song ends + // up jumping forward, like with bug #3614566 (see above). + assert(_loopTick + info.delta < _position._playTick); + uint32 extraDelta = info.delta; jumpToTick(_loopTick); _nextEvent.delta += extraDelta; diff --git a/engines/sci/sound/midiparser_sci.h b/engines/sci/sound/midiparser_sci.h index d3fd337644..7bd68994c8 100644 --- a/engines/sci/sound/midiparser_sci.h +++ b/engines/sci/sound/midiparser_sci.h @@ -110,6 +110,7 @@ protected: int16 _signalToSet; bool _dataincAdd; int16 _dataincToAdd; + bool _jumpToHoldTick; bool _resetOnPause; bool _channelUsed[16]; diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index daba976f50..b0102a002b 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -530,17 +530,21 @@ void SoundCommandParser::processUpdateCues(reg_t obj) { } reg_t SoundCommandParser::kDoSoundSendMidi(int argc, reg_t *argv, reg_t acc) { + // The 4 parameter variant of this call is used in at least LSL1VGA, room + // 110 (Lefty's bar), to distort the music when Larry is drunk and stands + // up - bug #3614447. reg_t obj = argv[0]; byte channel = argv[1].toUint16() & 0xf; - byte midiCmd = argv[2].toUint16() & 0xff; + byte midiCmd = (argc == 5) ? argv[2].toUint16() & 0xff : 0xB0; // 0xB0: controller + uint16 controller = (argc == 5) ? argv[3].toUint16() : argv[2].toUint16(); + uint16 param = (argc == 5) ? argv[4].toUint16() : argv[3].toUint16(); - // TODO: first there is a 4-parameter variant of this call which needs to get reversed - // second the current code isn't 100% accurate, sierra sci does checks on the 4th parameter - if (argc == 4) - return acc; - - uint16 controller = argv[3].toUint16(); - uint16 param = argv[4].toUint16(); + if (argc == 4 && controller == 0xFF) { + midiCmd = 0xE0; // 0xE0: pitch wheel + uint16 pitch = CLIP<uint16>(argv[3].toSint16() + 0x2000, 0x0000, 0x3FFF); + controller = pitch & 0x7F; + param = pitch >> 7; + } debugC(kDebugLevelSound, "kDoSound(sendMidi): %04x:%04x, %d, %d, %d, %d", PRINT_REG(obj), channel, midiCmd, controller, param); if (channel) diff --git a/engines/sci/video/robot_decoder.cpp b/engines/sci/video/robot_decoder.cpp index 0337a8d306..a567ece2ea 100644 --- a/engines/sci/video/robot_decoder.cpp +++ b/engines/sci/video/robot_decoder.cpp @@ -210,7 +210,7 @@ void RobotDecoder::readNextPacket() { // Copy over the decompressed frame byte *inFrame = decompressedFrame; - byte *outFrame = (byte *)surface->pixels; + byte *outFrame = (byte *)surface->getPixels(); // Black out the surface memset(outFrame, 0, surface->w * surface->h); diff --git a/engines/sci/video/seq_decoder.cpp b/engines/sci/video/seq_decoder.cpp index a7b6346eca..54603ec1f1 100644 --- a/engines/sci/video/seq_decoder.cpp +++ b/engines/sci/video/seq_decoder.cpp @@ -119,7 +119,7 @@ const Graphics::Surface *SEQDecoder::SEQVideoTrack::decodeNextFrame() { _fileStream->seek(offset); if (frameType == kSeqFrameFull) { - byte *dst = (byte *)_surface->pixels + frameTop * SEQ_SCREEN_WIDTH + frameLeft; + byte *dst = (byte *)_surface->getBasePtr(frameLeft, frameTop); byte *linebuf = new byte[frameWidth]; @@ -133,7 +133,7 @@ const Graphics::Surface *SEQDecoder::SEQVideoTrack::decodeNextFrame() { } else { byte *buf = new byte[frameSize]; _fileStream->read(buf, frameSize); - decodeFrame(buf, rleSize, buf + rleSize, frameSize - rleSize, (byte *)_surface->pixels + SEQ_SCREEN_WIDTH * frameTop, frameLeft, frameWidth, frameHeight, colorKey); + decodeFrame(buf, rleSize, buf + rleSize, frameSize - rleSize, (byte *)_surface->getBasePtr(0, frameTop), frameLeft, frameWidth, frameHeight, colorKey); delete[] buf; } diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index 5c148a7b57..4e14473921 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -1485,7 +1485,7 @@ void ScummEngine::playActorSounds() { int sound; for (i = 1; i < _numActors; i++) { - if (_actors[i]->_cost.soundCounter && _actors[i]->isInCurrentRoom() && _actors[i]->_sound) { + if (_actors[i]->_cost.soundCounter && _actors[i]->isInCurrentRoom()) { _currentScript = 0xFF; if (_game.version == 0) { sound = v0ActorSounds[i - 1] & 0x3F; diff --git a/engines/scumm/akos.cpp b/engines/scumm/akos.cpp index b6acf01050..481c4af432 100644 --- a/engines/scumm/akos.cpp +++ b/engines/scumm/akos.cpp @@ -994,7 +994,7 @@ byte AkosRenderer::codec1(int xmoveCur, int ymoveCur) { if (_draw_bottom < rect.bottom) _draw_bottom = rect.bottom; - v1.destptr = (byte *)_out.pixels + v1.y * _out.pitch + v1.x * _vm->_bytesPerPixel; + v1.destptr = (byte *)_out.getBasePtr(v1.x, v1.y); codec1_genericDecode(v1); @@ -1288,7 +1288,7 @@ byte AkosRenderer::codec16(int xmoveCur, int ymoveCur) { int32 numskip_before = skip_x + (skip_y * _width); int32 numskip_after = _width - cur_x; - byte *dst = (byte *)_out.pixels + height_unk * _out.pitch + width_unk * _vm->_bytesPerPixel; + byte *dst = (byte *)_out.getBasePtr(width_unk, height_unk); akos16Decompress(dst, _out.pitch, _srcptr, cur_x, out_height, dir, numskip_before, numskip_after, transparency, clip.left, clip.top, _zbuf); return 0; @@ -1358,7 +1358,7 @@ byte AkosRenderer::codec32(int xmoveCur, int ymoveCur) { palPtr = _vm->_hePalettes + _vm->_hePaletteSlot + 768; } - byte *dstPtr = (byte *)_out.pixels + dst.top * _out.pitch + dst.left * _vm->_bytesPerPixel; + byte *dstPtr = (byte *)_out.getBasePtr(dst.left, dst.top); if (_shadow_mode == 3) { Wiz::decompressWizImage<kWizXMap>(dstPtr, _out.pitch, kDstScreen, _srcptr, src, 0, palPtr, xmap, _vm->_bytesPerPixel); } else { diff --git a/engines/scumm/base-costume.cpp b/engines/scumm/base-costume.cpp index 46c68c81b0..e1a8688bb9 100644 --- a/engines/scumm/base-costume.cpp +++ b/engines/scumm/base-costume.cpp @@ -32,13 +32,15 @@ byte BaseCostumeRenderer::drawCostume(const VirtScreen &vs, int numStrips, const _out = vs; if (drawToBackBuf) - _out.pixels = vs.getBackPixels(0, 0); + _out.setPixels(vs.getBackPixels(0, 0)); else - _out.pixels = vs.getPixels(0, 0); + _out.setPixels(vs.getPixels(0, 0)); _actorX += _vm->_virtscr[kMainVirtScreen].xstart & 7; _out.w = _out.pitch / _vm->_bytesPerPixel; - _out.pixels = (byte *)_out.pixels - (_vm->_virtscr[kMainVirtScreen].xstart & 7); + // We do not use getBasePtr here because the offset to pixels never used + // _vm->_bytesPerPixel, but it seems unclear why. + _out.setPixels((byte *)_out.getPixels() - (_vm->_virtscr[kMainVirtScreen].xstart & 7)); _numStrips = numStrips; diff --git a/engines/scumm/bomp.cpp b/engines/scumm/bomp.cpp index 845cf70722..5b87f3042c 100644 --- a/engines/scumm/bomp.cpp +++ b/engines/scumm/bomp.cpp @@ -231,7 +231,10 @@ void drawBomp(const BompDrawData &bd) { } src = bd.src; - dst = (byte *)bd.dst.pixels + bd.y * bd.dst.pitch + (bd.x + clip.left); + // FIXME: This gets passed a const destination Surface. Intuitively this + // should never get written to. But sadly it does... For now we simply + // cast the const qualifier away. + dst = (byte *)const_cast<void *>(bd.dst.getBasePtr((bd.x + clip.left), bd.y)); const byte maskbit = revBitMask((bd.x + clip.left) & 7); diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp index 9ae75b6683..dd79aff2da 100644 --- a/engines/scumm/charset.cpp +++ b/engines/scumm/charset.cpp @@ -799,7 +799,7 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr, if (ignoreCharsetMask || !vs->hasTwoBuffers) { dstPtr = vs->getPixels(0, 0); } else { - dstPtr = (byte *)_vm->_textSurface.pixels; + dstPtr = (byte *)_vm->_textSurface.getPixels(); } if (_blitAlso && vs->hasTwoBuffers) { @@ -829,7 +829,7 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr, dstPtr = vs->getPixels(_left, drawTop); } else { dstSurface = _vm->_textSurface; - dstPtr = (byte *)_vm->_textSurface.pixels + (_top - _vm->_screenTop) * _vm->_textSurface.pitch * _vm->_textSurfaceMultiplier + _left * _vm->_textSurfaceMultiplier; + dstPtr = (byte *)_vm->_textSurface.getBasePtr(_left * _vm->_textSurfaceMultiplier, (_top - _vm->_screenTop) * _vm->_textSurfaceMultiplier); } if (_blitAlso && vs->hasTwoBuffers) { @@ -907,7 +907,7 @@ bool CharsetRendererClassic::prepareDraw(uint16 chr) { void CharsetRendererClassic::drawChar(int chr, Graphics::Surface &s, int x, int y) { if (!prepareDraw(chr)) return; - byte *dst = (byte *)s.pixels + y * s.pitch + x; + byte *dst = (byte *)s.getBasePtr(x, y); drawBitsN(s, dst, _charPtr, *_fontPtr, y, _width, _height); } @@ -1242,7 +1242,7 @@ void CharsetRendererNut::printChar(int chr, bool ignoreCharsetMask) { if (ignoreCharsetMask) { VirtScreen *vs = &_vm->_virtscr[kMainVirtScreen]; s = *vs; - s.pixels = vs->getPixels(0, 0); + s.setPixels(vs->getPixels(0, 0)); } else { s = _vm->_textSurface; drawTop -= _vm->_screenTop; @@ -1401,7 +1401,7 @@ void CharsetRendererTownsClassic::drawBitsN(const Graphics::Surface&, byte *dst, } bool scale2x = (_vm->_textSurfaceMultiplier == 2); - dst = (byte *)_vm->_textSurface.pixels + (_top - _vm->_screenTop) * _vm->_textSurface.pitch * _vm->_textSurfaceMultiplier + _left * _vm->_textSurfaceMultiplier; + dst = (byte *)_vm->_textSurface.getBasePtr(_left * _vm->_textSurfaceMultiplier, (_top - _vm->_screenTop) * _vm->_textSurfaceMultiplier); int y, x; int color; diff --git a/engines/scumm/costume.cpp b/engines/scumm/costume.cpp index 4ebdd00fdc..85c60f9a40 100644 --- a/engines/scumm/costume.cpp +++ b/engines/scumm/costume.cpp @@ -293,7 +293,7 @@ byte ClassicCostumeRenderer::mainRoutine(int xmoveCur, int ymoveCur) { return 2; } - v1.destptr = (byte *)_out.pixels + v1.y * _out.pitch + v1.x * _vm->_bytesPerPixel; + v1.destptr = (byte *)_out.getBasePtr(v1.x, v1.y); v1.mask_ptr = _vm->getMaskBuffer(0, v1.y, _zbuf); @@ -826,7 +826,7 @@ byte NESCostumeRenderer::drawLimb(const Actor *a, int limb) { int my = _actorY + y + ty; int mx = _actorX + x + tx; if (!(_zbuf && (maskBuf[my * _numStrips + mx / 8] & revBitMask(mx & 7)))) - *((byte *)_out.pixels + my * _out.pitch + mx) = palette[c]; + *((byte *)_out.getBasePtr(mx, my)) = palette[c]; } } } @@ -1238,7 +1238,7 @@ byte V0CostumeRenderer::drawLimb(const Actor *a, int limb) { int destY = ypos + y; if (destY >= 0 && destY < _out.h && destX >= 0 && destX < _out.w) { - byte *dst = (byte *)_out.pixels + destY * _out.pitch + destX; + byte *dst = (byte *)_out.getBasePtr(destX, destY); byte *mask = _vm->getMaskBuffer(0, destY, _zbuf); if (a0->_limb_flipped[limb]) { LINE(0, 0); LINE(2, 2); LINE(4, 4); LINE(6, 6); diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp index 269ae9e10a..721644b554 100644 --- a/engines/scumm/cursor.cpp +++ b/engines/scumm/cursor.cpp @@ -139,7 +139,7 @@ void ScummEngine_v6::grabCursor(int x, int y, int w, int h) { return; } - setCursorFromBuffer((byte *)vs->pixels + (y - vs->topline) * vs->pitch + x, w, h, vs->pitch); + setCursorFromBuffer((byte *)vs->getBasePtr(x, y - vs->topline), w, h, vs->pitch); } void ScummEngine_v6::setDefaultCursor() { @@ -417,13 +417,11 @@ void ScummEngine_v5::redefineBuiltinCursorFromChar(int index, int chr) { Graphics::Surface s; byte buf[16*17]; memset(buf, 123, 16*17); - s.pixels = buf; - s.w = _charset->getCharWidth(chr); - s.h = _charset->getFontHeight(); - s.pitch = s.w; + s.init(_charset->getCharWidth(chr), _charset->getFontHeight(), + _charset->getCharWidth(chr), buf, + Graphics::PixelFormat::createFormatCLUT8()); // s.h = 17 for FM-TOWNS Loom Japanese. Fixes bug #1166917 assert(s.w <= 16 && s.h <= 17); - s.format = Graphics::PixelFormat::createFormatCLUT8(); _charset->drawChar(chr, s, 0, 0); diff --git a/engines/scumm/debugger.cpp b/engines/scumm/debugger.cpp index 9b6dd1e687..872293f821 100644 --- a/engines/scumm/debugger.cpp +++ b/engines/scumm/debugger.cpp @@ -641,7 +641,7 @@ static void hlineColor(ScummEngine *scumm, int x1, int x2, int y, byte color) { x2 = right - 1; - ptr = (byte *)vs->pixels + x1 + y * vs->pitch; + ptr = (byte *)vs->getBasePtr(x1, y); while (x1++ <= x2) { *ptr++ = color; diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h index cb807997e9..6717ea9b06 100644 --- a/engines/scumm/detection_tables.h +++ b/engines/scumm/detection_tables.h @@ -299,7 +299,11 @@ static const GameSettings gameVariantsTable[] = { // Changed o_getResourceSize to cover all resource types {"farm", "", 0, GID_HEGAME, 6, 73, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, - {"puttzoo", "", 0, GID_HEGAME, 6, 73, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"puttzoo", "", 0, GID_PUTTZOO, 6, 73, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"puttzoo", "HE 72", 0, GID_PUTTZOO, 6, 72, MDT_NONE, GF_USE_KEY | GF_HE_985, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"puttzoo", "HE 98.5", 0, GID_PUTTZOO, 6, 98, MDT_NONE, GF_USE_KEY | GF_HE_985, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"puttzoo", "HE 99", 0, GID_PUTTZOO, 6, 99, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"puttzoo", "HE 100", 0, GID_PUTTZOO, 6, 100, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, // Added VAR_PLATFORM variable {"jungle", "", 0, GID_HEGAME, 6, 74, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, @@ -385,7 +389,8 @@ static const GameSettings gameVariantsTable[] = { {"Soccer2004", 0, 0, GID_SOCCER2004, 6, 100, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, // U32 code required, for testing only - {"moonbase", 0, 0, GID_MOONBASE, 6, 100, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"moonbase", "1.0", 0, GID_MOONBASE, 6, 100, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"moonbase", "1.1", 0, GID_MOONBASE, 6, 100, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, {"moonbase", "Demo", 0, GID_MOONBASE, 6, 100, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR | GF_DEMO, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, // HE100 games, which use older o72_debugInput code @@ -758,6 +763,7 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "pajama2", "PYJAMADB", kGenHEPC, Common::DE_DEU, UNK, 0 }, { "pajama2", "PyjamaDBMN", kGenHEPC, Common::DE_DEU, UNK, 0 }, { "pajama2", "PyjamaDBMN", kGenHEMac, Common::DE_DEU, Common::kPlatformMacintosh, 0 }, + { "pajama2", "PyjamaHM", kGenHEPC, Common::FR_FRA, UNK, 0 }, { "pajama2", "PyjamaHM", kGenHEMac, Common::FR_FRA, Common::kPlatformMacintosh, 0 }, { "pajama2", "PYJAMA2", kGenHEPC, Common::DE_DEU, UNK, 0 }, { "pajama2", "Pyjama Pit 2", kGenHEMac, Common::DE_DEU, Common::kPlatformMacintosh, 0 }, @@ -858,6 +864,7 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "puttzoo", "Zoo Demo", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 }, { "puttzoo", "Putt-Putt Saves the Zoo", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 }, { "puttzoo", "game", kGenHEPC, Common::EN_ANY, Common::kPlatformIOS, 0 }, + { "puttzoo", "pp3_unlocked", kGenHEPC, Common::EN_ANY, Common::kPlatformWindows, 0 }, { "SamsFunShop", "SamsFunShop", kGenHEPC, UNK_LANG, UNK, 0 }, { "SamsFunShop", "Sam's FunShop", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 }, diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index 50ff0b3988..4d65ccc88a 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -421,8 +421,8 @@ void ScummEngine::initVirtScreen(VirtScreenNumber slot, int top, int width, int } _res->createResource(rtBuffer, slot + 1, size); - vs->pixels = getResourceAddress(rtBuffer, slot + 1); - memset(vs->pixels, 0, size); // reset background + vs->setPixels(getResourceAddress(rtBuffer, slot + 1)); + memset(vs->getBasePtr(0, 0), 0, size); // reset background if (twobufs) { vs->backBuf = _res->createResource(rtBuffer, slot + 5, size); @@ -612,7 +612,7 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i // Some paranoia checks assert(top >= 0 && bottom <= vs->h); assert(x >= 0 && width <= vs->pitch); - assert(_textSurface.pixels); + assert(_textSurface.getPixels()); // Perform some clipping if (width > vs->w - x) @@ -1135,7 +1135,7 @@ void ScummEngine::clearTextSurface() { _townsScreen->fillLayerRect(1, 0, 0, _textSurface.w, _textSurface.h, 0); #endif - fill((byte *)_textSurface.pixels, _textSurface.pitch, + fill((byte *)_textSurface.getPixels(), _textSurface.pitch, #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE _game.platform == Common::kPlatformFMTowns ? 0 : #endif @@ -1590,7 +1590,7 @@ void GdiV2::prepareDrawBitmap(const byte *ptr, VirtScreen *vs, if (vs->hasTwoBuffers) dst = vs->backBuf + y * vs->pitch + x * 8; else - dst = (byte *)vs->pixels + y * vs->pitch + x * 8; + dst = (byte *)vs->getBasePtr(x * 8, y); mask_ptr = getMaskBuffer(x, y, 1); @@ -1827,7 +1827,7 @@ void Gdi::drawBitmap(const byte *ptr, VirtScreen *vs, int x, const int y, const if (vs->hasTwoBuffers) dstPtr = vs->backBuf + y * vs->pitch + (x * 8 * vs->format.bytesPerPixel); else - dstPtr = (byte *)vs->pixels + y * vs->pitch + (x * 8 * vs->format.bytesPerPixel); + dstPtr = (byte *)vs->getBasePtr(x * 8, y); transpStrip = drawStrip(dstPtr, vs, x, y, width, height, stripnr, smap_ptr); @@ -1836,7 +1836,7 @@ void Gdi::drawBitmap(const byte *ptr, VirtScreen *vs, int x, const int y, const transpStrip = true; if (vs->hasTwoBuffers) { - byte *frontBuf = (byte *)vs->pixels + y * vs->pitch + (x * 8 * vs->format.bytesPerPixel); + byte *frontBuf = (byte *)vs->getBasePtr(x * 8, y); if (lightsOn) copy8Col(frontBuf, vs->pitch, dstPtr, height, vs->format.bytesPerPixel); else @@ -1888,7 +1888,7 @@ bool Gdi::drawStrip(byte *dstPtr, VirtScreen *vs, int x, int y, const int width, if (stripnr * 4 + 4 < smapLen) offset = READ_LE_UINT32(smap_ptr + stripnr * 4 + 4); } else { - smapLen = READ_BE_UINT32(smap_ptr); + smapLen = READ_BE_UINT32(smap_ptr + 4); if (stripnr * 4 + 8 < smapLen) offset = READ_LE_UINT32(smap_ptr + stripnr * 4 + 8); } @@ -2262,7 +2262,7 @@ void Gdi::resetBackground(int top, int bottom, int strip) { vs->bdirty[strip] = bottom; bgbak_ptr = (byte *)vs->backBuf + top * vs->pitch + (strip + vs->xstart/8) * 8 * vs->format.bytesPerPixel; - backbuff_ptr = (byte *)vs->pixels + top * vs->pitch + (strip + vs->xstart/8) * 8 * vs->format.bytesPerPixel; + backbuff_ptr = (byte *)vs->getBasePtr((strip + vs->xstart/8) * 8, top); numLinesToProcess = bottom - top; if (numLinesToProcess) { diff --git a/engines/scumm/gfx_towns.cpp b/engines/scumm/gfx_towns.cpp index f86a4e56d5..0aed181afd 100644 --- a/engines/scumm/gfx_towns.cpp +++ b/engines/scumm/gfx_towns.cpp @@ -34,7 +34,7 @@ void ScummEngine::towns_drawStripToScreen(VirtScreen *vs, int dstX, int dstY, in if (width <= 0 || height <= 0) return; - assert(_textSurface.pixels); + assert(_textSurface.getPixels()); int m = _textSurfaceMultiplier; diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp index be17a3b305..d01b456c8b 100644 --- a/engines/scumm/he/animation_he.cpp +++ b/engines/scumm/he/animation_he.cpp @@ -90,7 +90,7 @@ void MoviePlayer::copyFrameToBuffer(byte *dst, int dstType, uint x, uint y, uint if (!surface) return; - byte *src = (byte *)surface->pixels; + const byte *src = (const byte *)surface->getPixels(); if (_video->hasDirtyPalette()) _vm->setPaletteFromPtr(_video->getPalette(), 256); @@ -119,7 +119,7 @@ void MoviePlayer::copyFrameToBuffer(byte *dst, int dstType, uint x, uint y, uint dst += y * pitch + x * 2; do { for (uint i = 0; i < w; i++) { - uint16 color = *((uint16 *)src + i); + uint16 color = *((const uint16 *)src + i); switch (dstType) { case kDstScreen: WRITE_UINT16(dst + i * 2, color); diff --git a/engines/scumm/he/logic/moonbase.cpp b/engines/scumm/he/logic/moonbase.cpp index fac2ea27ff..5b4618a4ad 100644 --- a/engines/scumm/he/logic/moonbase.cpp +++ b/engines/scumm/he/logic/moonbase.cpp @@ -39,6 +39,8 @@ public: int LogicHEmoonbase::versionID() { if (_vm->_game.features & GF_DEMO) return -100; + else if (strcmp(_vm->_game.variant, "1.1") == 0) + return 110; else return 100; } diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp index b024154c7f..987f74957c 100644 --- a/engines/scumm/he/script_v100he.cpp +++ b/engines/scumm/he/script_v100he.cpp @@ -2148,7 +2148,7 @@ void ScummEngine_v100he::o100_systemOps() { break; case 132: // Confirm shutdown - quitGame(); + confirmExitDialog(); break; case 133: quitGame(); diff --git a/engines/scumm/he/script_v70he.cpp b/engines/scumm/he/script_v70he.cpp index adb2fcac2e..9259e0db2f 100644 --- a/engines/scumm/he/script_v70he.cpp +++ b/engines/scumm/he/script_v70he.cpp @@ -309,7 +309,7 @@ void ScummEngine_v70he::o70_systemOps() { break; case 160: // Confirm shutdown - quitGame(); + confirmExitDialog(); break; case 244: quitGame(); diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp index b9f454de0f..42bf9a4bb6 100644 --- a/engines/scumm/he/script_v72he.cpp +++ b/engines/scumm/he/script_v72he.cpp @@ -158,7 +158,7 @@ int ScummEngine_v72he::readArray(int array, int idx2, int idx1) { ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array)); - if (ah == NULL || ah->data == NULL) + if (!ah) error("readArray: invalid array %d (%d)", array, readVar(array)); if (idx2 < (int)FROM_LE_32(ah->dim2start) || idx2 > (int)FROM_LE_32(ah->dim2end) || @@ -1199,7 +1199,7 @@ void ScummEngine_v72he::o72_systemOps() { break; case 160: // Confirm shutdown - quitGame(); + confirmExitDialog(); break; case 244: quitGame(); @@ -1779,8 +1779,11 @@ void ScummEngine_v72he::copyArray(int array1, int a1_dim2start, int a1_dim2end, copyArrayHelper(ah, a1_dim2start, a1_dim1start, a1_dim1end, &dst, &dstPitch, &rowSize); copyArrayHelper(ah, a2_dim2start, a2_dim1start, a2_dim1end, &src, &srcPitch, &rowSize); } else { + // start at the end, so we copy backwards (in case the indices overlap) copyArrayHelper(ah, a1_dim2end, a1_dim1start, a1_dim1end, &dst, &dstPitch, &rowSize); copyArrayHelper(ah, a2_dim2end, a2_dim1start, a2_dim1end, &src, &srcPitch, &rowSize); + dstPitch = -dstPitch; + srcPitch = -srcPitch; } for (; a1_dim2start <= a1_dim2end; ++a1_dim2start) { memcpy(dst, src, rowSize); diff --git a/engines/scumm/he/script_v80he.cpp b/engines/scumm/he/script_v80he.cpp index eb62b650a4..ae43d714ad 100644 --- a/engines/scumm/he/script_v80he.cpp +++ b/engines/scumm/he/script_v80he.cpp @@ -23,7 +23,7 @@ #ifdef ENABLE_HE #include "common/archive.h" -#include "common/config-file.h" +#include "common/ini-file.h" #include "common/config-manager.h" #include "common/macresman.h" #include "common/savefile.h" @@ -180,7 +180,7 @@ void ScummEngine_v80he::o80_readConfigFile() { } } else { // Normal Windows INI files - Common::ConfigFile confFile; + Common::INIFile confFile; if (!strcmp((char *)filename + r, "map.ini")) confFile.loadFromFile((const char *)filename + r); else @@ -250,7 +250,7 @@ void ScummEngine_v80he::o80_writeConfigFile() { memcpy(section, "BluesTreasureHunt-Disc2\0", 24); } - Common::ConfigFile ConfFile; + Common::INIFile ConfFile; ConfFile.loadFromSaveFile((const char *)filename + r); ConfFile.setKey((char *)option, (char *)section, (char *)string); ConfFile.saveToSaveFile((const char *)filename + r); diff --git a/engines/scumm/imuse/imuse.cpp b/engines/scumm/imuse/imuse.cpp index 12ebfef9b7..0e96952a48 100644 --- a/engines/scumm/imuse/imuse.cpp +++ b/engines/scumm/imuse/imuse.cpp @@ -1483,7 +1483,7 @@ void IMuseInternal::initMT32(MidiDriver *midi) { } void IMuseInternal::initGM(MidiDriver *midi) { - byte buffer[11]; + byte buffer[12]; int i; // General MIDI System On message @@ -1509,7 +1509,7 @@ void IMuseInternal::initGM(MidiDriver *midi) { midi->sysEx(buffer, 9); debug(2, "GS SysEx: GS Reset"); _system->delayMillis(200); - + // Set global Master Tune to 442.0kHz, as on the MT-32 memcpy(&buffer[4], "\x40\x00\x00\x00\x04\x04\x0F\x29", 8); midi->sysEx(buffer, 12); @@ -1540,7 +1540,7 @@ void IMuseInternal::initGM(MidiDriver *midi) { // Set Channels 1-16 Reverb to 64, which is the // equivalent of MT-32 default Reverb Level 5 for (i = 0; i < 16; ++i) - midi->send((64 << 16) | (91 << 8) | (0xB0 | i)); + midi->send((64 << 16) | (91 << 8) | (0xB0 | i)); debug(2, "GM Controller 91 Change: Channels 1-16 Reverb Level is 64"); // Set Channels 1-16 Pitch Bend Sensitivity to diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp index ee2de49475..d1786dfb60 100644 --- a/engines/scumm/input.cpp +++ b/engines/scumm/input.cpp @@ -535,7 +535,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) { openMainMenuDialog(); // Display global main menu - if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0) + if (VAR_SAVELOAD_SCRIPT2 != 0xFF && _currentRoom != 0) runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, 0); } else if (restartKeyEnabled && (lastKeyHit.keycode == Common::KEYCODE_F8 && lastKeyHit.hasFlags(0))) { diff --git a/engines/scumm/insane/insane_enemy.cpp b/engines/scumm/insane/insane_enemy.cpp index fa6d4264ec..d711b63342 100644 --- a/engines/scumm/insane/insane_enemy.cpp +++ b/engines/scumm/insane/insane_enemy.cpp @@ -1519,8 +1519,7 @@ void Insane::chooseEnemyWeaponAnim(int32 buttons) { case INV_BOOT: case INV_HAND: case INV_DUST: - _actor[1].act[2].state = 0; - switchEnemyWeapon(); + // fallthrough default: switchEnemyWeapon(); } @@ -2437,6 +2436,7 @@ void Insane::actor12Reaction(int32 buttons) { smlayer_setActorFacing(1, 2, 6, 180); smlayer_setActorLayer(1, 2, 25); _actor[1].act[2].state = 103; + break; case 103: _actor[1].kicking = false; diff --git a/engines/scumm/nut_renderer.cpp b/engines/scumm/nut_renderer.cpp index 048b29d68b..d9f0b412e1 100644 --- a/engines/scumm/nut_renderer.cpp +++ b/engines/scumm/nut_renderer.cpp @@ -357,7 +357,10 @@ void NutRenderer::drawFrame(byte *dst, int c, int x, int y) { } void NutRenderer::drawChar(const Graphics::Surface &s, byte c, int x, int y, byte color) { - byte *dst = (byte *)s.pixels + y * s.pitch + x; + // FIXME: This gets passed a const destination Surface. Intuitively this + // should never get written to. But sadly it does... For now we simply + // cast the const qualifier away. + byte *dst = (byte *)const_cast<void *>(s.getBasePtr(x, y)); const int width = MIN((int)_chars[c].width, s.w - x); const int height = MIN((int)_chars[c].height, s.h - y); const byte *src = unpackChar(c); @@ -391,7 +394,10 @@ void NutRenderer::drawChar(const Graphics::Surface &s, byte c, int x, int y, byt } void NutRenderer::draw2byte(const Graphics::Surface &s, int c, int x, int y, byte color) { - byte *dst = (byte *)s.pixels + y * s.pitch + x; + // FIXME: This gets passed a const destination Surface. Intuitively this + // should never get written to. But sadly it does... For now we simply + // cast the const qualifier away. + byte *dst = (byte *)const_cast<void *>(s.getBasePtr(x, y)); const int width = _vm->_2byteWidth; const int height = MIN(_vm->_2byteHeight, s.h - y); const byte *src = _vm->get2byteCharPtr(c); diff --git a/engines/scumm/object.cpp b/engines/scumm/object.cpp index ed77a863cd..d266183f85 100644 --- a/engines/scumm/object.cpp +++ b/engines/scumm/object.cpp @@ -1715,7 +1715,7 @@ void ScummEngine_v6::drawBlastObject(BlastObject *eo) { error("object %d is not a blast object", eo->number); bdd.dst = *vs; - bdd.dst.pixels = vs->getPixels(0, 0); + bdd.dst.setPixels(vs->getPixels(0, 0)); bdd.x = eo->rect.left; bdd.y = eo->rect.top; diff --git a/engines/scumm/player_mac.cpp b/engines/scumm/player_mac.cpp index c16c85bff3..a60736df5e 100644 --- a/engines/scumm/player_mac.cpp +++ b/engines/scumm/player_mac.cpp @@ -289,12 +289,16 @@ uint32 Player_Mac::durationToSamples(uint16 duration) { // (duration * 473 * _sampleRate) / (4 * 480 * 480) // // But that's likely to cause integer overflow, so we do it in two - // steps and hope that the rounding error won't be noticeable. + // steps using bitwise operations to perform + // ((duration * 473 * _sampleRate) / 4096) without overflowing, + // then divide this by 225 + // (note that 4 * 480 * 480 == 225 * 4096 == 225 << 12) // // The original code is a bit unclear on if it should be 473 or 437, // but since the comments indicated 473 I'm assuming 437 was a typo. - uint32 samples = (duration * _sampleRate) / (4 * 480); - samples = (samples * 473) / 480; + uint32 samples = (duration * _sampleRate); + samples = (samples >> 12) * 473 + (((samples & 4095) * 473) >> 12); + samples = samples / 225; return samples; } diff --git a/engines/scumm/player_v3m.cpp b/engines/scumm/player_v3m.cpp index 0f222d84fe..bf65ec797f 100644 --- a/engines/scumm/player_v3m.cpp +++ b/engines/scumm/player_v3m.cpp @@ -124,7 +124,7 @@ bool Player_V3M::checkMusicAvailable() { return true; } } - + GUI::MessageDialog dialog(_( "Could not find the 'Loom' Macintosh executable to read the\n" "instruments from. Music will be disabled."), _("OK")); diff --git a/engines/scumm/script_v6.cpp b/engines/scumm/script_v6.cpp index a75e864e7a..6983c51f30 100644 --- a/engines/scumm/script_v6.cpp +++ b/engines/scumm/script_v6.cpp @@ -394,7 +394,7 @@ ScummEngine_v6::ArrayHeader *ScummEngine_v6::getArray(int array) { int ScummEngine_v6::readArray(int array, int idx, int base) { ArrayHeader *ah = getArray(array); - if (ah == NULL || ah->data == NULL) + if (!ah) error("readArray: invalid array %d (%d)", array, readVar(array)); // WORKAROUND bug #645711. This is clearly a script bug, as this script diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index 6aad52578d..979573c5f5 100644 --- a/engines/scumm/scumm-md5.h +++ b/engines/scumm/scumm-md5.h @@ -1,5 +1,5 @@ /* - This file was generated by the md5table tool on Thu May 2 21:27:50 2013 + This file was generated by the md5table tool on Thu Aug 15 12:47:39 2013 DO NOT EDIT MANUALLY! */ @@ -124,6 +124,7 @@ static const MD5Table md5table[] = { { "28d24a33448fab6795850bc9f159a4a2", "atlantis", "FM-TOWNS", "Demo", 11170, Common::JA_JPN, Common::kPlatformFMTowns }, { "28ef68ee3ed76d7e2ee8ee13c15fbd5b", "loom", "EGA", "EGA", 5748, Common::EN_ANY, Common::kPlatformDOS }, { "28f07458f1b6c24e118a1ea056827701", "lost", "HE 99", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, + { "291fb06071e65897f755846611f5ad40", "ft", "", "7-Wolf", 19697, Common::RU_RUS, Common::kPlatformUnknown }, { "2a208ffbcd0e83e86f4356e6f64aa6e1", "loom", "EGA", "EGA", -1, Common::ES_ESP, Common::kPlatformDOS }, { "2a41b53cf1a90b6e6f26c10cc6041084", "tentacle", "", "Demo", 2439158, Common::EN_ANY, Common::kPlatformMacintosh }, { "2a446817ffcabfef8716e0c456ecaf81", "puttzoo", "", "Demo", -1, Common::DE_DEU, Common::kPlatformWindows }, @@ -238,7 +239,7 @@ static const MD5Table md5table[] = { { "53e94115b55dd51d4b8ff0871aa1df1e", "spyfox", "", "Demo", 20103, Common::EN_ANY, Common::kPlatformUnknown }, { "54a936ad06161ff7bfefcb96200f7bff", "monkey", "VGA", "VGA Demo", 7617, Common::EN_ANY, Common::kPlatformAmiga }, { "55518cd73cf9c6d23ea29c51ee06bdfe", "ft", "", "", -1, Common::IT_ITA, Common::kPlatformUnknown }, - { "55e4cc866ff9046824e1c638ba2b8c7f", "ft", "", "", -1, Common::RU_RUS, Common::kPlatformUnknown }, + { "55e4cc866ff9046824e1c638ba2b8c7f", "ft", "", "Akella", -1, Common::RU_RUS, Common::kPlatformUnknown }, { "55f4e9402bec2bded383843123f37c5c", "pajama2", "HE 98.5", "", -1, Common::DE_DEU, Common::kPlatformWindows }, { "566165a7338fa11029e7c14d94fa70d0", "freddi", "HE 73", "Demo", 9800, Common::EN_ANY, Common::kPlatformWindows }, { "56b5922751be7ffd771b38dda56b028b", "freddi", "HE 100", "", 34837, Common::NL_NLD, Common::kPlatformWii }, @@ -327,6 +328,7 @@ static const MD5Table md5table[] = { { "73e5ab7dbb9a8061cc6d25df02dbd1e7", "loom", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformDOS }, { "7410a8ba9795020cd42f171c4320659e", "pajama3", "", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "746e88c172a5b7a1ae89ac0ee3ee681a", "freddi", "HE 90", "Updated", -1, Common::RU_RUS, Common::kPlatformWindows }, + { "7477bc23d0383516c5e310cd8771dcc9", "pajama2", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "74da3494fbe1a7d20213b0afe0954755", "catalog", "HE CUP", "Preview", 10841544, Common::FR_FRA, Common::kPlatformUnknown }, { "754feb59d3bf86b8a00840df74fd7b26", "freddi3", "", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "75ba23fff4fd63fa446c02864f2a5a4b", "zak", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformDOS }, @@ -342,6 +344,7 @@ static const MD5Table md5table[] = { { "78c07ca088526d8d4446a4c2cb501203", "freddi3", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "7974365d3dc0f43a2748c975f91ff042", "monkey2", "", "", -1, Common::ES_ESP, Common::kPlatformDOS }, { "79b05f628586837e7166e82b2279bb50", "loom", "PC-Engine", "", -1, Common::JA_JPN, Common::kPlatformPCEngine }, + { "7b4ee071eecadc2d8cd0c3509110825c", "puttzoo", "HE 100", "Remastered", -1, Common::EN_ANY, Common::kPlatformWindows }, { "7bad72e332a59f9fcc1d437f4edad32a", "puttcircus", "", "", -1, Common::RU_RUS, Common::kPlatformUnknown }, { "7c2e76087027eeee9c8f8985f93a1cc5", "freddi4", "", "Demo", 13584, Common::EN_ANY, Common::kPlatformUnknown }, { "7c8100e360e8ef05f88069d4cfa0afd1", "puttrace", "HE 99", "Demo", 13108, Common::EN_GRB, Common::kPlatformWindows }, @@ -534,7 +537,7 @@ static const MD5Table md5table[] = { { "ce7733f185b838e248927c7ba1a04204", "maniac", "V2", "V2", -1, Common::FR_FRA, Common::kPlatformAmiga }, { "ce7fd0c382389a6791fc3e199c117ef4", "indy3", "EGA", "EGA", -1, Common::ES_ESP, Common::kPlatformDOS }, { "cea91e3dd47f2518ea418e41611aa77f", "spyfox2", "", "", -1, Common::RU_RUS, Common::kPlatformUnknown }, - { "cf400d20769fb70eb21766582f4924f7", "moonbase", "", "", -1, Common::EN_ANY, Common::kPlatformWindows }, + { "cf400d20769fb70eb21766582f4924f7", "moonbase", "1.0", "1.0", -1, Common::EN_ANY, Common::kPlatformWindows }, { "cf4ef315214c7d8cdab6302cdb7e50db", "freddi", "HE 73", "Demo", -1, Common::DE_DEU, Common::kPlatformWindows }, { "cf8d13446ec6cb6222287a925fd47c1d", "baseball", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "cf8ef3a1fb483c5c4b1c584d1167b2c4", "freddi", "HE 73", "", -1, Common::DE_DEU, Common::kPlatformWindows }, @@ -582,6 +585,7 @@ static const MD5Table md5table[] = { { "e03ed1474ec14de78359970e0457a820", "freddi4", "HE 99", "Demo", -1, Common::EN_GRB, Common::kPlatformWindows }, { "e144f5f49d9241d2a9dee2576b3d09cb", "airport", "", "Demo", 51152, Common::EN_ANY, Common::kPlatformWindows }, { "e17db1ddf91b39ca6bbc8ad3ed19e883", "monkey", "FM-TOWNS", "", -1, Common::JA_JPN, Common::kPlatformFMTowns }, + { "e1c9998826ce7fa8bde5cc3a5023edec", "moonbase", "1.1", "1.1", -1, Common::EN_ANY, Common::kPlatformWindows }, { "e246e02db9630533a40d99c9f54a8e01", "monkey2", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "e361a7058ed8e8ebb462663c0a3ae8d6", "puttputt", "HE 62", "", -1, Common::HE_ISR, Common::kPlatformDOS }, { "e41de1c2a15abbcdbf9977e2d7e8a340", "freddi2", "HE 100", "Updated", -1, Common::RU_RUS, Common::kPlatformWindows }, diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index a77c1c0141..ca05c90936 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -240,6 +240,7 @@ enum ScummGameId { GID_FBEAR, GID_PUTTMOON, GID_FUNPACK, + GID_PUTTZOO, GID_FREDDI3, GID_BIRTHDAYRED, GID_BIRTHDAYYELLOW, diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp index 77c7daa0df..9c90d7575d 100644 --- a/engines/scumm/vars.cpp +++ b/engines/scumm/vars.cpp @@ -714,6 +714,12 @@ void ScummEngine_v99he::resetScummVars() { VAR(140) = 0; #endif } + + if (_game.id == GID_PUTTZOO && _game.heversion == 100 && _game.platform == Common::kPlatformWindows) { + // Specific to Nimbus Games version. + VAR(156) = 1; + VAR(157) = 0; + } } #endif diff --git a/engines/sky/sky.cpp b/engines/sky/sky.cpp index fd90015aa3..4c47dfafc7 100644 --- a/engines/sky/sky.cpp +++ b/engines/sky/sky.cpp @@ -187,9 +187,14 @@ Common::Error SkyEngine::go() { } if (!shouldQuit()) { - _skyLogic->initScreen0(); + // restartGame() takes us to the first scene, without showing the + // initial animation where Foster is being chased. initScreen0() + // shows the first scene together with that animation. We can't + // call both, as they both load the same scene. if (introSkipped) _skyControl->restartGame(); + else + _skyLogic->initScreen0(); } } diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index 206bd68b07..742aac1a53 100644 --- a/engines/sword1/animation.cpp +++ b/engines/sword1/animation.cpp @@ -37,7 +37,14 @@ #include "gui/message.h" +#ifdef USE_MPEG2 +#include "video/avi_decoder.h" +#endif + +#ifdef USE_ZLIB #include "video/dxa_decoder.h" +#endif + #include "video/psx_decoder.h" #include "video/smk_decoder.h" @@ -176,27 +183,26 @@ bool MoviePlayer::load(uint32 id) { break; case kVideoDecoderPSX: filename = Common::String::format("%s.str", (_vm->_systemVars.isDemo) ? sequenceList[id] : sequenceListPSX[id]); + break; + case kVideoDecoderMP2: + filename = Common::String::format("%s.mp2", sequenceList[id]); + break; + } - // Need to switch to true color + // Need to switch to true color for PSX/MP2 videos + if (_decoderType == kVideoDecoderPSX || _decoderType == kVideoDecoderMP2) initGraphics(g_system->getWidth(), g_system->getHeight(), true, 0); - // Need to load here in case it fails in which case we'd need - // to go back to paletted mode - if (_decoder->loadFile(filename)) { - _decoder->start(); - return true; - } else { + if (!_decoder->loadFile(filename)) { + // Go back to 8bpp color + if (_decoderType == kVideoDecoderPSX || _decoderType == kVideoDecoderMP2) initGraphics(g_system->getWidth(), g_system->getHeight(), true); - return false; - } - break; - } - if (!_decoder->loadFile(filename)) return false; + } - // For DXA, also add the external sound file - if (_decoderType == kVideoDecoderDXA) + // For DXA/MP2, also add the external sound file + if (_decoderType == kVideoDecoderDXA || _decoderType == kVideoDecoderMP2) _decoder->addStreamFileTrack(sequenceList[id]); _decoder->start(); @@ -224,9 +230,9 @@ void MoviePlayer::play() { } void MoviePlayer::performPostProcessing(byte *screen) { - // TODO: We don't support the PSX stream videos yet + // TODO: We don't support displaying these in true color yet, // nor using the PSX fonts to display subtitles. - if (_vm->isPsx()) + if (_vm->isPsx() || _decoderType == kVideoDecoderMP2) return; if (!_movieTexts.empty()) { @@ -308,7 +314,7 @@ bool MoviePlayer::playVideo() { if (_decoderType == kVideoDecoderPSX) drawFramePSX(frame); else - _vm->_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, frame->w, frame->h); + _vm->_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, frame->w, frame->h); } if (_decoder->hasDirtyPalette()) { @@ -401,7 +407,7 @@ bool MoviePlayer::playVideo() { } Graphics::Surface *screen = _vm->_system->lockScreen(); - performPostProcessing((byte *)screen->pixels); + performPostProcessing((byte *)screen->getPixels()); _vm->_system->unlockScreen(); _vm->_system->updateScreen(); } @@ -414,20 +420,19 @@ bool MoviePlayer::playVideo() { _vm->_system->delayMillis(10); } - if (_decoderType == kVideoDecoderPSX) { - // Need to jump back to paletted color + // Need to jump back to paletted color + if (_decoderType == kVideoDecoderPSX || _decoderType == kVideoDecoderMP2) initGraphics(g_system->getWidth(), g_system->getHeight(), true); - } return !_vm->shouldQuit() && !skipped; } uint32 MoviePlayer::getBlackColor() { - return (_decoderType == kVideoDecoderPSX) ? g_system->getScreenFormat().RGBToColor(0x00, 0x00, 0x00) : _black; + return (_decoderType == kVideoDecoderPSX || _decoderType == kVideoDecoderMP2) ? g_system->getScreenFormat().RGBToColor(0x00, 0x00, 0x00) : _black; } uint32 MoviePlayer::findTextColor() { - if (_decoderType == kVideoDecoderPSX) { + if (_decoderType == kVideoDecoderPSX || _decoderType == kVideoDecoderMP2) { // We're in true color mode, so return the actual colors switch (_textColor) { case 1: @@ -493,7 +498,7 @@ void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) { uint16 x = (g_system->getWidth() - scaledFrame.w) / 2; uint16 y = (g_system->getHeight() - scaledFrame.h) / 2; - _vm->_system->copyRectToScreen(scaledFrame.pixels, scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h); + _vm->_system->copyRectToScreen(scaledFrame.getPixels(), scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h); scaledFrame.free(); } @@ -547,9 +552,16 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * filename = Common::String::format("%s.mp2", sequenceList[id]); if (Common::File::exists(filename)) { - GUI::MessageDialog dialog(_("MPEG2 cutscenes are no longer supported"), _("OK")); +#ifdef USE_MPEG2 + // HACK: Old ScummVM builds ignored the AVI frame rate field and forced the video + // to be played back at 12fps. + Video::VideoDecoder *aviDecoder = new Video::AVIDecoder(12); + return new MoviePlayer(vm, textMan, resMan, system, aviDecoder, kVideoDecoderMP2); +#else + GUI::MessageDialog dialog(_("MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"), _("OK")); dialog.runModal(); return 0; +#endif } if (!vm->isPsx() || scumm_stricmp(sequenceList[id], "enddemo") != 0) { diff --git a/engines/sword1/animation.h b/engines/sword1/animation.h index d0c61f5eb3..2c51a74f71 100644 --- a/engines/sword1/animation.h +++ b/engines/sword1/animation.h @@ -41,7 +41,8 @@ namespace Sword1 { enum DecoderType { kVideoDecoderDXA = 0, kVideoDecoderSMK = 1, - kVideoDecoderPSX = 2 + kVideoDecoderPSX = 2, + kVideoDecoderMP2 = 3 }; class MovieText { diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index 00260f789a..92fa9d0e44 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -42,7 +42,14 @@ #include "gui/message.h" +#ifdef USE_MPEG2 +#include "video/avi_decoder.h" +#endif + +#ifdef USE_ZLIB #include "video/dxa_decoder.h" +#endif + #include "video/smk_decoder.h" #include "video/psx_decoder.h" @@ -88,26 +95,26 @@ bool MoviePlayer::load(const char *name) { break; case kVideoDecoderPSX: filename = Common::String::format("%s.str", name); + break; + case kVideoDecoderMP2: + filename = Common::String::format("%s.mp2", name); + break; + } - // Need to switch to true color - initGraphics(640, 480, true, 0); + // Need to switch to true color for PSX/MP2 videos + if (_decoderType == kVideoDecoderPSX || _decoderType == kVideoDecoderMP2) + initGraphics(g_system->getWidth(), g_system->getHeight(), true, 0); - // Need to load here in case it fails in which case we'd need - // to go back to paletted mode - if (_decoder->loadFile(filename)) { - _decoder->start(); - return true; - } else { - initGraphics(640, 480, true); - return false; - } - } + if (!_decoder->loadFile(filename)) { + // Go back to 8bpp color + if (_decoderType == kVideoDecoderPSX || _decoderType == kVideoDecoderMP2) + initGraphics(g_system->getWidth(), g_system->getHeight(), true); - if (!_decoder->loadFile(filename)) return false; + } - // For DXA, also add the external sound file - if (_decoderType == kVideoDecoderDXA) + // For DXA/MP2, also add the external sound file + if (_decoderType == kVideoDecoderDXA || _decoderType == kVideoDecoderMP2) _decoder->addStreamFileTrack(name); _decoder->start(); @@ -136,10 +143,9 @@ void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadI _vm->_sound->stopSpeech(); } - if (_decoderType == kVideoDecoderPSX) { - // Need to jump back to paletted color + // Need to jump back to paletted color + if (_decoderType == kVideoDecoderPSX || _decoderType == kVideoDecoderMP2) initGraphics(640, 480, true); - } } void MoviePlayer::openTextObject(uint32 index) { @@ -328,7 +334,7 @@ bool MoviePlayer::playVideo() { if (_decoderType == kVideoDecoderPSX) drawFramePSX(frame); else - _vm->_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, frame->w, frame->h); + _vm->_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, frame->w, frame->h); } if (_decoder->hasDirtyPalette()) { @@ -378,11 +384,11 @@ bool MoviePlayer::playVideo() { } uint32 MoviePlayer::getBlackColor() { - return (_decoderType == kVideoDecoderPSX) ? g_system->getScreenFormat().RGBToColor(0x00, 0x00, 0x00) : _black; + return (_decoderType == kVideoDecoderPSX || _decoderType == kVideoDecoderMP2) ? g_system->getScreenFormat().RGBToColor(0x00, 0x00, 0x00) : _black; } uint32 MoviePlayer::getWhiteColor() { - return (_decoderType == kVideoDecoderPSX) ? g_system->getScreenFormat().RGBToColor(0xFF, 0xFF, 0xFF) : _white; + return (_decoderType == kVideoDecoderPSX || _decoderType == kVideoDecoderMP2) ? g_system->getScreenFormat().RGBToColor(0xFF, 0xFF, 0xFF) : _white; } void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) { @@ -397,7 +403,7 @@ void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) { uint16 x = (g_system->getWidth() - scaledFrame.w) / 2; uint16 y = (g_system->getHeight() - scaledFrame.h) / 2; - _vm->_system->copyRectToScreen(scaledFrame.pixels, scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h); + _vm->_system->copyRectToScreen(scaledFrame.getPixels(), scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h); scaledFrame.free(); } @@ -446,9 +452,16 @@ MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, OSystem *system filename = Common::String::format("%s.mp2", name); if (Common::File::exists(filename)) { - GUI::MessageDialog dialog(_("MPEG2 cutscenes are no longer supported"), _("OK")); +#ifdef USE_MPEG2 + // HACK: Old ScummVM builds ignored the AVI frame rate field and forced the video + // to be played back at 12fps. + Video::AVIDecoder *aviDecoder = new Video::AVIDecoder(12); + return new MoviePlayer(vm, system, aviDecoder, kVideoDecoderMP2); +#else + GUI::MessageDialog dialog(_("MPEG-2 cutscenes found but ScummVM has been built without MPEG-2 support"), _("OK")); dialog.runModal(); return NULL; +#endif } // The demo tries to play some cutscenes that aren't there, so make those warnings more discreet. diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h index b2a243b2ca..8669bdc8d8 100644 --- a/engines/sword2/animation.h +++ b/engines/sword2/animation.h @@ -40,7 +40,8 @@ namespace Sword2 { enum DecoderType { kVideoDecoderDXA = 0, kVideoDecoderSMK = 1, - kVideoDecoderPSX = 2 + kVideoDecoderPSX = 2, + kVideoDecoderMP2 = 3 }; struct MovieText { diff --git a/engines/sword25/fmv/movieplayer.cpp b/engines/sword25/fmv/movieplayer.cpp index a95532ec65..3cdce1b493 100644 --- a/engines/sword25/fmv/movieplayer.cpp +++ b/engines/sword25/fmv/movieplayer.cpp @@ -130,10 +130,10 @@ void MoviePlayer::update() { assert(s->format.bytesPerPixel == 4); #ifdef THEORA_INDIRECT_RENDERING - const byte *frameData = (const byte *)s->getBasePtr(0, 0); + const byte *frameData = (const byte *)s->getPixels(); _outputBitmap->setContent(frameData, s->pitch * s->h, 0, s->pitch); #else - g_system->copyRectToScreen(s->getBasePtr(0, 0), s->pitch, _outX, _outY, MIN(s->w, _backSurface->w), MIN(s->h, _backSurface->h)); + g_system->copyRectToScreen(s->getPixels(), s->pitch, _outX, _outY, MIN(s->w, _backSurface->w), MIN(s->h, _backSurface->h)); g_system->updateScreen(); #endif } diff --git a/engines/sword25/gfx/dynamicbitmap.cpp b/engines/sword25/gfx/dynamicbitmap.cpp index 242508bf85..1f3d2d063d 100644 --- a/engines/sword25/gfx/dynamicbitmap.cpp +++ b/engines/sword25/gfx/dynamicbitmap.cpp @@ -53,7 +53,7 @@ DynamicBitmap::DynamicBitmap(InputPersistenceBlock &reader, RenderObjectPtr<Rend bool DynamicBitmap::createRenderedImage(uint width, uint height) { bool result = false; _image.reset(new RenderedImage(width, height, result)); - + _originalWidth = _width = width; _originalHeight = _height = height; @@ -77,7 +77,7 @@ bool DynamicBitmap::doRender(RectangleList *updateRects) { // Get the frame buffer object GraphicEngine *pGfx = Kernel::getInstance()->getGfx(); assert(pGfx); - + // Draw the bitmap bool result; if (_scaleFactorX == 1.0f && _scaleFactorY == 1.0f) { diff --git a/engines/sword25/gfx/image/image.h b/engines/sword25/gfx/image/image.h index 9d7fc43251..8db54e7c54 100644 --- a/engines/sword25/gfx/image/image.h +++ b/engines/sword25/gfx/image/image.h @@ -205,7 +205,7 @@ public: @brief Returns true, if the content of the BS_Image is allowed to be replaced by call of SetContent(). */ virtual bool isSetContentAllowed() const = 0; - + virtual bool isSolid() const { return false; } //@} diff --git a/engines/sword25/gfx/image/imgloader.cpp b/engines/sword25/gfx/image/imgloader.cpp index e103626416..9006a596b4 100644 --- a/engines/sword25/gfx/image/imgloader.cpp +++ b/engines/sword25/gfx/image/imgloader.cpp @@ -50,7 +50,7 @@ bool ImgLoader::decodePNGImage(const byte *fileDataPtr, uint fileSize, byte *&un width = pngSurface->w; height = pngSurface->h; uncompressedDataPtr = new byte[pngSurface->pitch * pngSurface->h]; - memcpy(uncompressedDataPtr, (byte *)pngSurface->pixels, pngSurface->pitch * pngSurface->h); + memcpy(uncompressedDataPtr, (byte *)pngSurface->getPixels(), pngSurface->pitch * pngSurface->h); pngSurface->free(); delete pngSurface; diff --git a/engines/sword25/gfx/image/renderedimage.cpp b/engines/sword25/gfx/image/renderedimage.cpp index c8a6666046..346b46f3b4 100644 --- a/engines/sword25/gfx/image/renderedimage.cpp +++ b/engines/sword25/gfx/image/renderedimage.cpp @@ -41,6 +41,7 @@ #include "sword25/gfx/renderobjectmanager.h" #include "common/system.h" +#include "graphics/thumbnail.h" namespace Sword25 { @@ -250,14 +251,10 @@ bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRe // Create an encapsulating surface for the data Graphics::Surface srcImage; // TODO: Is the data really in the screen format? - srcImage.format = g_system->getScreenFormat(); - srcImage.pitch = _width * 4; - srcImage.w = _width; - srcImage.h = _height; - srcImage.pixels = _data; + srcImage.init(_width, _height, _width * 4, _data, g_system->getScreenFormat()); if (pPartRect) { - srcImage.pixels = &_data[pPartRect->top * srcImage.pitch + pPartRect->left * 4]; + srcImage.setPixels(&_data[pPartRect->top * srcImage.pitch + pPartRect->left * 4]); srcImage.w = pPartRect->right - pPartRect->left; srcImage.h = pPartRect->bottom - pPartRect->top; @@ -286,14 +283,14 @@ bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRe if ((width != srcImage.w) || (height != srcImage.h)) { // Scale the image img = imgScaled = scale(srcImage, width, height); - savedPixels = (byte *)img->pixels; + savedPixels = (byte *)img->getPixels(); } else { img = &srcImage; } for (RectangleList::iterator it = updateRects->begin(); it != updateRects->end(); ++it) { const Common::Rect &clipRect = *it; - + int skipLeft = 0, skipTop = 0; int drawX = posX, drawY = posY; int drawWidth = img->w; @@ -305,7 +302,7 @@ bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRe drawWidth -= skipLeft; drawX = clipRect.left; } - + if (drawY < clipRect.top) { skipTop = clipRect.top - drawY; drawHeight -= skipTop; @@ -314,13 +311,13 @@ bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRe if (drawX + drawWidth >= clipRect.right) drawWidth = clipRect.right - drawX; - + if (drawY + drawHeight >= clipRect.bottom) drawHeight = clipRect.bottom - drawY; - + if ((drawWidth > 0) && (drawHeight > 0)) { int xp = 0, yp = 0; - + int inStep = 4; int inoStep = img->pitch; if (flipping & Image::FLIP_V) { @@ -329,14 +326,14 @@ bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRe } else { xp = skipLeft; } - + if (flipping & Image::FLIP_H) { inoStep = -inoStep; yp = img->h - 1 - skipTop; } else { yp = skipTop; } - + byte *ino = (byte *)img->getBasePtr(xp, yp); byte *outo = (byte *)_backSurface->getBasePtr(drawX, drawY); @@ -350,7 +347,7 @@ bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRe ino += inoStep; } } else -#endif +#endif { byte *in, *out; for (int i = 0; i < drawHeight; i++) { @@ -360,7 +357,7 @@ bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRe uint32 pix = *(uint32 *)in; int a = (pix >> 24) & 0xff; in += inStep; - + if (ca != 255) { a = a * ca >> 8; } @@ -370,11 +367,11 @@ bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRe out += 4; continue; } - + int b = (pix >> 0) & 0xff; int g = (pix >> 8) & 0xff; int r = (pix >> 16) & 0xff; - + if (a == 255) { #if defined(SCUMM_LITTLE_ENDIAN) if (cb != 255) @@ -459,11 +456,11 @@ bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRe } } - + } if (imgScaled) { - imgScaled->pixels = savedPixels; + imgScaled->setPixels(savedPixels); imgScaled->free(); delete imgScaled; } @@ -509,60 +506,4 @@ void RenderedImage::checkForTransparency() { } } -/** - * Scales a passed surface, creating a new surface with the result - * @param srcImage Source image to scale - * @param scaleFactor Scale amount. Must be between 0 and 1.0 (but not zero) - * @remarks Caller is responsible for freeing the returned surface - */ -Graphics::Surface *RenderedImage::scale(const Graphics::Surface &srcImage, int xSize, int ySize) { - Graphics::Surface *s = new Graphics::Surface(); - s->create(xSize, ySize, srcImage.format); - - int *horizUsage = scaleLine(xSize, srcImage.w); - int *vertUsage = scaleLine(ySize, srcImage.h); - - // Loop to create scaled version - for (int yp = 0; yp < ySize; ++yp) { - const byte *srcP = (const byte *)srcImage.getBasePtr(0, vertUsage[yp]); - byte *destP = (byte *)s->getBasePtr(0, yp); - - for (int xp = 0; xp < xSize; ++xp) { - const byte *tempSrcP = srcP + (horizUsage[xp] * srcImage.format.bytesPerPixel); - for (int byteCtr = 0; byteCtr < srcImage.format.bytesPerPixel; ++byteCtr) { - *destP++ = *tempSrcP++; - } - } - } - - // Delete arrays and return surface - delete[] horizUsage; - delete[] vertUsage; - return s; -} - -/** - * Returns an array indicating which pixels of a source image horizontally or vertically get - * included in a scaled image - */ -int *RenderedImage::scaleLine(int size, int srcSize) { - int scale = 100 * size / srcSize; - assert(scale > 0); - int *v = new int[size]; - Common::fill(v, &v[size], 0); - - int distCtr = 0; - int *destP = v; - for (int distIndex = 0; distIndex < srcSize; ++distIndex) { - distCtr += scale; - while (distCtr >= 100) { - assert(destP < &v[size]); - *destP++ = distIndex; - distCtr -= 100; - } - } - - return v; -} - } // End of namespace Sword25 diff --git a/engines/sword25/gfx/image/renderedimage.h b/engines/sword25/gfx/image/renderedimage.h index a25b258592..116f97de26 100644 --- a/engines/sword25/gfx/image/renderedimage.h +++ b/engines/sword25/gfx/image/renderedimage.h @@ -104,8 +104,6 @@ public: return true; } - static Graphics::Surface *scale(const Graphics::Surface &srcImage, int xSize, int ySize); - void setIsTransparent(bool isTransparent) { _isTransparent = isTransparent; } virtual bool isSolid() const { return !_isTransparent; } @@ -119,7 +117,6 @@ private: Graphics::Surface *_backSurface; void checkForTransparency(); - static int *scaleLine(int size, int srcSize); }; } // End of namespace Sword25 diff --git a/engines/sword25/gfx/panel.cpp b/engines/sword25/gfx/panel.cpp index 931b9cdbe7..b9bb8b087d 100644 --- a/engines/sword25/gfx/panel.cpp +++ b/engines/sword25/gfx/panel.cpp @@ -84,7 +84,7 @@ bool Panel::doRender(RectangleList *updateRects) { gfxPtr->fill(&intersectionRect, _color); } } - + return true; } diff --git a/engines/sword25/gfx/renderobject.cpp b/engines/sword25/gfx/renderobject.cpp index 807c1eb64b..1dd6f4590f 100644 --- a/engines/sword25/gfx/renderobject.cpp +++ b/engines/sword25/gfx/renderobject.cpp @@ -183,7 +183,7 @@ bool RenderObject::updateObjectState() { // Die Bounding-Box neu berechnen und Update-Regions registrieren. updateBoxes(); - + ++_version; // Änderungen Validieren diff --git a/engines/sword25/gfx/renderobject.h b/engines/sword25/gfx/renderobject.h index 7e0334ee88..1116c3284c 100644 --- a/engines/sword25/gfx/renderobject.h +++ b/engines/sword25/gfx/renderobject.h @@ -236,7 +236,7 @@ public: @brief Löscht alle Kinderobjekte. */ void deleteAllChildren(); - + // Accessor-Methoden // ----------------- /** @@ -305,11 +305,11 @@ public: int getZ() const { return _z; } - + int getAbsoluteZ() const { return _absoluteZ; } - + /** @brief Gibt die Breite des Objektes zurück. */ @@ -363,11 +363,11 @@ public: return _handle; } - // Get the RenderObjects current version + // Get the RenderObjects current version int getVersion() const { return _version; } - + bool isSolid() const { return _isSolid; } @@ -410,7 +410,7 @@ protected: bool _oldVisible; static int _nextGlobalVersion; - + int _version; // This should be set to true if the RenderObject is NOT alpha-blended to optimize drawing @@ -509,9 +509,9 @@ private: @brief Berechnet die absolute Position des Objektes. */ int calcAbsoluteY() const; - + int calcAbsoluteZ() const; - + /** @brief Sortiert alle Kinderobjekte nach ihrem Renderang. */ diff --git a/engines/sword25/gfx/renderobjectmanager.cpp b/engines/sword25/gfx/renderobjectmanager.cpp index 994d9367ab..77f944c9e0 100644 --- a/engines/sword25/gfx/renderobjectmanager.cpp +++ b/engines/sword25/gfx/renderobjectmanager.cpp @@ -113,7 +113,7 @@ bool RenderObjectManager::render() { RectangleList *updateRects = _uta->getRectangles(); Common::Array<int> updateRectsMinZ; - + updateRectsMinZ.reserve(updateRects->size()); // Calculate the minimum drawing Z value of each update rectangle @@ -144,9 +144,9 @@ bool RenderObjectManager::render() { } delete updateRects; - + SWAP(_currQueue, _prevQueue); - + return true; } diff --git a/engines/sword25/gfx/screenshot.cpp b/engines/sword25/gfx/screenshot.cpp index 0ea4bff906..7b56a6e9f3 100644 --- a/engines/sword25/gfx/screenshot.cpp +++ b/engines/sword25/gfx/screenshot.cpp @@ -40,7 +40,7 @@ namespace Sword25 { bool Screenshot::saveToFile(Graphics::Surface *data, Common::WriteStream *stream) { // Convert the RGBA data to RGB - const byte *pSrc = (const byte *)data->getBasePtr(0, 0); + const byte *pSrc = (const byte *)data->getPixels(); // Write our own custom header stream->writeUint32BE(MKTAG('S','C','R','N')); // SCRN, short for "Screenshot" @@ -85,7 +85,7 @@ Common::SeekableReadStream *Screenshot::createThumbnail(Graphics::Surface *data) uint x, y; x = y = 0; - for (byte *pDest = (byte *)thumbnail.pixels; pDest < ((byte *)thumbnail.pixels + thumbnail.pitch * thumbnail.h); ) { + for (byte *pDest = (byte *)thumbnail.getPixels(); pDest < ((byte *)thumbnail.getBasePtr(0, thumbnail.h)); ) { // Get an average over a 4x4 pixel block in the source image int alpha, red, green, blue; alpha = red = green = blue = 0; diff --git a/engines/sword25/gfx/staticbitmap.cpp b/engines/sword25/gfx/staticbitmap.cpp index 91b93e8910..bb57fa3a03 100644 --- a/engines/sword25/gfx/staticbitmap.cpp +++ b/engines/sword25/gfx/staticbitmap.cpp @@ -71,7 +71,7 @@ bool StaticBitmap::initBitmapResource(const Common::String &filename) { // RenderObject Eigenschaften aktualisieren _originalWidth = _width = bitmapPtr->getWidth(); _originalHeight = _height = bitmapPtr->getHeight(); - + _isSolid = bitmapPtr->isSolid(); // Bild-Resource freigeben diff --git a/engines/sword25/util/pluto/pluto.cpp b/engines/sword25/util/pluto/pluto.cpp index b7f5e30340..b7a8fd3c8b 100644 --- a/engines/sword25/util/pluto/pluto.cpp +++ b/engines/sword25/util/pluto/pluto.cpp @@ -1,6 +1,6 @@ /* $Id$ */ -/* Pluto - Heavy-duty persistence for Lua +/* Tamed Pluto - Heavy-duty persistence for Lua * Copyright (C) 2004 by Ben Sunshine-Hill, and released into the public * domain. People making use of this software as part of an application * are politely requested to email the author at sneftel@gmail.com @@ -14,11 +14,17 @@ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Instrumented by Stefan Reich (info@luaos.net) + * for Mobile Lua (http://luaos.net/pages/mobile-lua.php) */ +#include "config.h" #include "sword25/util/lua/lua.h" #include "pluto.h" +#undef TOTEXT + #define USE_PDEP #ifdef USE_PDEP @@ -42,10 +48,20 @@ #include <string.h> +/* Define this if you want size_t values to be written in 64-bit + (even on 32-bit systems). Should eliminate at least one source of + 32/64 bit incompatibility. */ +#define SIZES64 + /* #define PLUTO_DEBUG */ +#ifdef SIZES64 +#define VERSION "Tamed Pluto 1.0 with SIZES64 flag" +#else +#define VERSION "Tamed Pluto 1.0" +#endif #ifdef PLUTO_DEBUG @@ -56,6 +72,23 @@ #define verify(x) { int v = (int)((x)); v=v; lua_assert(v); } +#define NUMTYPES 9 +static const char* typenames[] = { + "nil", + "boolean", + "lightuserdata", + "number", + "string", + "table", + "function", + "userdata", + "thread" +}; + +static int humanReadable = 0; +#define hrBufSize 200 +static char hrBuf[hrBufSize]; + typedef struct PersistInfo_t { lua_State *L; int counter; @@ -76,6 +109,77 @@ void printindent(int indent) } #endif +/* lua_Chunkwriter signature: (lua_State *L, const void *p, size_t sz, void *ud). + ud is a pointer to the WriterInfo struct (holds the buffer pointer) +*/ + +static void pi_write(PersistInfo *pi, const void *p, size_t size, void *ud) { + if (humanReadable) { + uint i; + snprintf(hrBuf, hrBufSize, " pi_write %d ", (int) size); + pi->writer(pi->L, hrBuf, strlen(hrBuf), ud); + for (i = 0; i < size; i++) { + char b = ((char *)p)[i]; + snprintf(hrBuf, hrBufSize, "%X%X", (b >> 4) & 0xF, b & 0xF); + pi->writer(pi->L, hrBuf, strlen(hrBuf), ud); + } + snprintf(hrBuf, hrBufSize, "\n"); + pi->writer(pi->L, hrBuf, strlen(hrBuf), ud); + } else { + pi->writer(pi->L, p, size, ud); + } +#ifdef TOTEXT + int i; + printf(" pi_write %d ", (int) size); + for (i = 0; i < size; i++) { + char b = ((char *)p)[i]; + printf("%X%X", (b >> 4) & 0xF, b & 0xF); + } + printf("\n"); +#endif +} + +static void hrOut(PersistInfo *pi) { + pi->writer(pi->L, hrBuf, strlen(hrBuf), pi->ud); +} + +static void write_size(PersistInfo *pi, size_t *val) +{ +#ifdef SIZES64 + int64 longval; /* yeah, you really need long long to get 8 bytes on win32... duh. */ + longval = *val; + pi_write(pi, &longval, 8, pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "write_size64 %ld\n", longval); + hrOut(pi); + } +#ifdef TOTEXT + printf("write_size64 %ld\n", longval); +#endif +#else + pi_write(pi, val, sizeof(size_t), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "write_size %ld\n", *((size_t *)val)); + hrOut(pi); + } +#ifdef TOTEXT + printf("write_size %ld\n", *val); +#endif +#endif +} + +static void read_size(ZIO *zio, size_t *val) +{ +#ifdef SIZES64 + int64 longval; + verify(LIF(Z,read)(zio, &longval, 8) == 0); + *val = longval; +#else + verify(LIF(Z,read)(zio, val, sizeof(size_t)) == 0); +#endif +} + + /* Mutual recursion requires prototype */ static void persist(PersistInfo *pi); @@ -107,7 +211,14 @@ static int persistspecialobject(PersistInfo *pi, int defaction) if(defaction) { { int zero = 0; - pi->writer(pi->L, &zero, sizeof(int), pi->ud); + pi_write(pi, &zero, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistspecialobject_write_zero\n"); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistspecialobject_write_zero\n"); +#endif } return 0; } else { @@ -127,7 +238,14 @@ static int persistspecialobject(PersistInfo *pi, int defaction) if(defaction) { { int zero = 0; - pi->writer(pi->L, &zero, sizeof(int), pi->ud); + pi_write(pi, &zero, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistspecialobject_write_zero2\n"); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistspecialobject_write_zero2\n"); +#endif } return 0; } else { @@ -143,7 +261,14 @@ static int persistspecialobject(PersistInfo *pi, int defaction) /* perms reftbl sptbl ... obj */ { int zero = 0; - pi->writer(pi->L, &zero, sizeof(int), pi->ud); + pi_write(pi, &zero, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistspecialobject_write_zero3\n"); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistspecialobject_write_zero3\n"); +#endif } return 0; } else { @@ -176,7 +301,14 @@ static int persistspecialobject(PersistInfo *pi, int defaction) /* perms reftbl ... obj mt func */ { int one = 1; - pi->writer(pi->L, &one, sizeof(int), pi->ud); + pi_write(pi, &one, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistspecialobject_write_one\n"); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistspecialobject_write_one\n"); +#endif } persist(pi); /* perms reftbl ... obj mt func */ @@ -187,6 +319,14 @@ static int persistspecialobject(PersistInfo *pi, int defaction) static void persisttable(PersistInfo *pi) { + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persisttable\n"); + hrOut(pi); + } +#ifdef TOTEXT + printf("persisttable\n"); +#endif + /* perms reftbl ... tbl */ lua_checkstack(pi->L, 3); if(persistspecialobject(pi, 1)) { @@ -235,8 +375,15 @@ static void persistuserdata(PersistInfo *pi) { } else { /* Use literal persistence */ size_t length = uvalue(getobject(pi->L, -1))->len; - pi->writer(pi->L, &length, sizeof(size_t), pi->ud); - pi->writer(pi->L, lua_touserdata(pi->L, -1), length, pi->ud); + write_size(pi, &length); + pi_write(pi, lua_touserdata(pi->L, -1), length, pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistuserdata %ld\n", (long) length); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistuserdata %ld\n", (long) length); +#endif if(!lua_getmetatable(pi->L, -1)) { /* perms reftbl ... udata */ lua_pushnil(pi->L); @@ -269,8 +416,8 @@ static void pushproto(lua_State *L, Proto *proto) #define setuvvalue(L,obj,x) \ { TValue *i_o=(obj); \ - i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUPVAL; \ - checkliveness(G(L),i_o); } + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUPVAL; \ + checkliveness(G(L),i_o); } static void pushupval(lua_State *L, UpVal *upval) { @@ -309,7 +456,14 @@ static void persistfunction(PersistInfo *pi) { /* We don't really _NEED_ the number of upvals, * but it'll simplify things a bit */ - pi->writer(pi->L, &cl->l.p->nups, sizeof(lu_byte), pi->ud); + pi_write(pi, &cl->l.p->nups, sizeof(lu_byte), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistfunction_number_upvalues %d\n", (int) cl->l.p->nups); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistfunction_number_upvalues %d\n", (int) cl->l.p->nups); +#endif } /* Persist prototype */ { @@ -401,7 +555,14 @@ static void persistproto(PersistInfo *pi) /* Persist constant refs */ { int i; - pi->writer(pi->L, &p->sizek, sizeof(int), pi->ud); + pi_write(pi, &p->sizek, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_sizek %d\n", p->sizek); + hrOut(pi); + } + #ifdef TOTEXT + printf("persistproto_sizek %d\n", p->sizek); + #endif for(i=0; i<p->sizek; i++) { LIF(A,pushobject)(pi->L, &p->k[i]); /* perms reftbl ... proto const */ @@ -415,7 +576,14 @@ static void persistproto(PersistInfo *pi) /* serialize inner Proto refs */ { int i; - pi->writer(pi->L, &p->sizep, sizeof(int), pi->ud); + pi_write(pi, &p->sizep, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_sizep %d\n", p->sizep); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistproto_sizep %d\n", p->sizep); +#endif for(i=0; i<p->sizep; i++) { pushproto(pi->L, p->p[i]); @@ -429,14 +597,37 @@ static void persistproto(PersistInfo *pi) /* Serialize code */ { - pi->writer(pi->L, &p->sizecode, sizeof(int), pi->ud); - pi->writer(pi->L, p->code, sizeof(Instruction) * p->sizecode, pi->ud); + int len; + pi_write(pi, &p->sizecode, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_sizecode %d\n", p->sizecode); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistproto_sizecode %d\n", p->sizecode); +#endif + len = sizeof(Instruction) * p->sizecode; + pi_write(pi, p->code, len, pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_code %d\n", len); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistproto_code %d\n", len); +#endif } /* Serialize upvalue names */ { int i; - pi->writer(pi->L, &p->sizeupvalues, sizeof(int), pi->ud); + pi_write(pi, &p->sizeupvalues, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_upvalues %d\n", p->sizeupvalues); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistproto_upvalues %d\n", p->sizeupvalues); +#endif for(i=0; i<p->sizeupvalues; i++) { pushstring(pi->L, p->upvalues[i]); @@ -447,15 +638,36 @@ static void persistproto(PersistInfo *pi) /* Serialize local variable infos */ { int i; - pi->writer(pi->L, &p->sizelocvars, sizeof(int), pi->ud); + pi_write(pi, &p->sizelocvars, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_sizelocvars %d\n", p->sizelocvars); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistproto_sizelocvars %d\n", p->sizelocvars); +#endif for(i=0; i<p->sizelocvars; i++) { pushstring(pi->L, p->locvars[i].varname); persist(pi); lua_pop(pi->L, 1); - pi->writer(pi->L, &p->locvars[i].startpc, sizeof(int), pi->ud); - pi->writer(pi->L, &p->locvars[i].endpc, sizeof(int), pi->ud); + pi_write(pi, &p->locvars[i].startpc, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_startpc %d\n", p->locvars[i].startpc); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistproto_startpc %d\n", p->locvars[i].startpc); +#endif + pi_write(pi, &p->locvars[i].endpc, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_endpc %d\n", p->locvars[i].endpc); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistproto_endpc %d\n", p->locvars[i].endpc); +#endif } } @@ -466,23 +678,81 @@ static void persistproto(PersistInfo *pi) /* Serialize line numbers */ { - pi->writer(pi->L, &p->sizelineinfo, sizeof(int), pi->ud); + pi_write(pi, &p->sizelineinfo, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_sizelineinfo %d\n", p->sizelineinfo); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistproto_sizelineinfo %d\n", p->sizelineinfo); +#endif if (p->sizelineinfo) { - pi->writer(pi->L, p->lineinfo, sizeof(int) * p->sizelineinfo, pi->ud); + int len; + len = sizeof(int) * p->sizelineinfo; + pi_write(pi, p->lineinfo, len, pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_lineinfo %d\n", len); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistproto_lineinfo %d\n", len); +#endif } } /* Serialize linedefined and lastlinedefined */ - pi->writer(pi->L, &p->linedefined, sizeof(int), pi->ud); - pi->writer(pi->L, &p->lastlinedefined, sizeof(int), pi->ud); + pi_write(pi, &p->linedefined, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_linedefined %d\n", p->linedefined); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistproto_linedefined %d\n", p->linedefined); +#endif + pi_write(pi, &p->lastlinedefined, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_lastlinedefined %d\n", p->lastlinedefined); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistproto_lastlinedefined %d\n", p->lastlinedefined); +#endif /* Serialize misc values */ { - pi->writer(pi->L, &p->nups, sizeof(lu_byte), pi->ud); - pi->writer(pi->L, &p->numparams, sizeof(lu_byte), pi->ud); - pi->writer(pi->L, &p->is_vararg, sizeof(lu_byte), pi->ud); - pi->writer(pi->L, &p->maxstacksize, sizeof(lu_byte), pi->ud); + pi_write(pi, &p->nups, sizeof(lu_byte), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_nups %d\n", (int) p->nups); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistproto_nups %d\n", (int) p->nups); +#endif + pi_write(pi, &p->numparams, sizeof(lu_byte), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_numparams %d\n", (int) p->numparams); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistproto_numparams %d\n", (int) p->numparams); +#endif + pi_write(pi, &p->is_vararg, sizeof(lu_byte), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_is_vararg %d\n", (int) p->is_vararg); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistproto_is_vararg %d\n", (int) p->is_vararg); +#endif + pi_write(pi, &p->maxstacksize, sizeof(lu_byte), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistproto_maxstacksize %d\n", (int) p->maxstacksize); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistproto_maxstacksize %d\n", (int) p->maxstacksize); +#endif } /* We do not currently persist upvalue names, local variable names, * variable lifetimes, line info, or source code. */ @@ -518,7 +788,7 @@ static void persistthread(PersistInfo *pi) /* Persist the stack */ posremaining = revappendstack(L2, pi->L); /* perms reftbl ... thr (rev'ed contents of L2) */ - pi->writer(pi->L, &posremaining, sizeof(size_t), pi->ud); + write_size(pi, &posremaining); for(; posremaining > 0; posremaining--) { persist(pi); lua_pop(pi->L, 1); @@ -527,7 +797,7 @@ static void persistthread(PersistInfo *pi) /* Now, persist the CallInfo stack. */ { size_t i, numframes = (L2->ci - L2->base_ci) + 1; - pi->writer(pi->L, &numframes, sizeof(size_t), pi->ud); + write_size(pi, &numframes); for(i=0; i<numframes; i++) { CallInfo *ci = L2->base_ci + i; size_t stackbase = ci->base - L2->stack; @@ -536,11 +806,18 @@ static void persistthread(PersistInfo *pi) size_t savedpc = (ci != L2->base_ci) ? ci->savedpc - ci_func(ci)->l.p->code : 0; - pi->writer(pi->L, &stackbase, sizeof(size_t), pi->ud); - pi->writer(pi->L, &stackfunc, sizeof(size_t), pi->ud); - pi->writer(pi->L, &stacktop, sizeof(size_t), pi->ud); - pi->writer(pi->L, &ci->nresults, sizeof(int), pi->ud); - pi->writer(pi->L, &savedpc, sizeof(size_t), pi->ud); + write_size(pi, &stackbase); + write_size(pi, &stackfunc); + write_size(pi, &stacktop); + pi_write(pi, &ci->nresults, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistthread %d\n", ci->nresults); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistthread %d\n", ci->nresults); +#endif + write_size(pi, &savedpc); } } @@ -549,10 +826,18 @@ static void persistthread(PersistInfo *pi) size_t stackbase = L2->base - L2->stack; size_t stacktop = L2->top - L2->stack; lua_assert(L2->nCcalls <= 1); - pi->writer(pi->L, &L2->status, sizeof(lu_byte), pi->ud); - pi->writer(pi->L, &stackbase, sizeof(size_t), pi->ud); - pi->writer(pi->L, &stacktop, sizeof(size_t), pi->ud); - pi->writer(pi->L, &L2->errfunc, sizeof(ptrdiff_t), pi->ud); + pi_write(pi, &L2->status, sizeof(lu_byte), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistthread_status %d\n", (int) L2->status); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistthread_status %d\n", (int) L2->status); +#endif + write_size(pi, &stackbase); + write_size(pi, &stacktop); + pi_write(pi, &L2->errfunc, sizeof(ptrdiff_t), pi->ud); + //write_size(pi, (size_t *)&L2->errfunc); } /* Finally, record upvalues which need to be reopened */ @@ -573,7 +858,7 @@ static void persistthread(PersistInfo *pi) lua_pop(pi->L, 1); /* perms reftbl ... thr */ stackpos = uv->v - L2->stack; - pi->writer(pi->L, &stackpos, sizeof(size_t), pi->ud); + write_size(pi, &stackpos); } /* perms reftbl ... thr */ lua_pushnil(pi->L); @@ -588,26 +873,62 @@ static void persistthread(PersistInfo *pi) static void persistboolean(PersistInfo *pi) { int b = lua_toboolean(pi->L, -1); - pi->writer(pi->L, &b, sizeof(int), pi->ud); + pi_write(pi, &b, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistboolean %d\n", b); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistboolean %d\n", b); +#endif } static void persistlightuserdata(PersistInfo *pi) { void *p = lua_touserdata(pi->L, -1); - pi->writer(pi->L, &p, sizeof(void *), pi->ud); + pi_write(pi, &p, sizeof(void *), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistlightuserdata %p\n", p); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistlightuserdata %d\n", (int) p); +#endif } static void persistnumber(PersistInfo *pi) { lua_Number n = lua_tonumber(pi->L, -1); - pi->writer(pi->L, &n, sizeof(lua_Number), pi->ud); + pi_write(pi, &n, sizeof(lua_Number), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persistnumber %d (%d)\n", (int) n, (int) sizeof(lua_Number)); + hrOut(pi); + } +#ifdef TOTEXT + printf("persistnumber %d (%d)\n", (int) n, (int) sizeof(lua_Number)); +#endif } static void persiststring(PersistInfo *pi) { + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persiststring\n"); + hrOut(pi); + } +#ifdef TOTEXT + printf("persiststring\n"); +#endif size_t length = lua_strlen(pi->L, -1); - pi->writer(pi->L, &length, sizeof(size_t), pi->ud); - pi->writer(pi->L, lua_tostring(pi->L, -1), length, pi->ud); + write_size(pi, &length); + const char* s = lua_tostring(pi->L, -1); + pi_write(pi, s, length, pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persiststring %d \"%s\"\n", (int)length, s); + hrOut(pi); + } +#ifdef TOTEXT + printf("persiststring %d \"%s\"\n", length, s); +#endif } /* Top-level delegating persist function @@ -630,8 +951,22 @@ static void persist(PersistInfo *pi) // since size_t is supposedly the same size as a pointer on most // (modern) architectures. int ref = (int)(size_t)lua_touserdata(pi->L, -1); - pi->writer(pi->L, &zero, sizeof(int), pi->ud); - pi->writer(pi->L, &ref, sizeof(int), pi->ud); + pi_write(pi, &zero, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persist_seenobject\n"); + hrOut(pi); + } +#ifdef TOTEXT + printf("persist_seenobject\n"); +#endif + pi_write(pi, &ref, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persist_touserdata_ref %d\n", ref); + hrOut(pi); + } +#ifdef TOTEXT + printf("persist_touserdata_ref %d\n", ref); +#endif lua_pop(pi->L, 1); /* perms reftbl ... obj ref */ #ifdef PLUTO_DEBUG @@ -647,9 +982,16 @@ static void persist(PersistInfo *pi) if(lua_isnil(pi->L, -1)) { int zero = 0; /* firsttime */ - pi->writer(pi->L, &zero, sizeof(int), pi->ud); + pi_write(pi, &zero, sizeof(int), pi->ud); /* ref */ - pi->writer(pi->L, &zero, sizeof(int), pi->ud); + pi_write(pi, &zero, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persist_nil (last 2 lines)\n"); + hrOut(pi); + } +#ifdef TOTEXT + printf("persist_nil (last 2 lines)\n"); +#endif #ifdef PLUTO_DEBUG printindent(pi->level); printf("0 0\n"); @@ -659,7 +1001,14 @@ static void persist(PersistInfo *pi) { /* indicate that it's the first time */ int one = 1; - pi->writer(pi->L, &one, sizeof(int), pi->ud); + pi_write(pi, &one, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persist_newobject\n"); + hrOut(pi); + } +#ifdef TOTEXT + printf("persist_newobject\n"); +#endif } lua_pushvalue(pi->L, -1); /* perms reftbl ... obj obj */ @@ -668,7 +1017,14 @@ static void persist(PersistInfo *pi) lua_rawset(pi->L, 2); /* perms reftbl ... obj */ - pi->writer(pi->L, &pi->counter, sizeof(int), pi->ud); + pi_write(pi, &pi->counter, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persist_counter %d\n", pi->counter); + hrOut(pi); + } +#ifdef TOTEXT + printf("persist_counter %d\n", pi->counter); +#endif /* At this point, we'll give the permanents table a chance to play. */ @@ -685,7 +1041,14 @@ static void persist(PersistInfo *pi) printf("1 %d PERM\n", pi->counter); pi->level++; #endif - pi->writer(pi->L, &type, sizeof(int), pi->ud); + pi_write(pi, &type, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persist_permtype %d\n", type); + hrOut(pi); + } +#ifdef TOTEXT + printf("persist_permtype %d\n", type); +#endif persist(pi); lua_pop(pi->L, 1); /* perms reftbl ... obj */ @@ -702,7 +1065,14 @@ static void persist(PersistInfo *pi) } { int type = lua_type(pi->L, -1); - pi->writer(pi->L, &type, sizeof(int), pi->ud); + pi_write(pi, &type, sizeof(int), pi->ud); + if (humanReadable) { + snprintf(hrBuf, hrBufSize, "persist %s\n", type >= 0 && type < NUMTYPES ? typenames[type] : "?"); + hrOut(pi); + } +#ifdef TOTEXT + printf("persist %s\n", type >= 0 && type < NUMTYPES ? typenames[type] : "?"); +#endif #ifdef PLUTO_DEBUG printindent(pi->level); @@ -798,8 +1168,8 @@ typedef struct WriterInfo_t { size_t buflen; } WriterInfo; -static int bufwriter (lua_State *L, const void* p, size_t sz, void* ud) { - const char* cp = (const char*)p; +static int bufwriter (lua_State *L, const void *p, size_t sz, void *ud) { + const char *cp = (const char *)p; WriterInfo *wi = (WriterInfo *)ud; LIF(M,reallocvector)(L, wi->buf, wi->buflen, wi->buflen+sz, char); @@ -819,7 +1189,7 @@ int persist_l(lua_State *L) wi.buf = NULL; wi.buflen = 0; - + lua_settop(L, 2); /* perms? rootobj? */ luaL_checktype(L, 1, LUA_TTABLE); @@ -895,10 +1265,13 @@ static void unpersistnumber(UnpersistInfo *upi) static void unpersiststring(UnpersistInfo *upi) { /* perms reftbl sptbl ref */ + /*int length;*/ size_t length; char* string; lua_checkstack(upi->L, 1); - verify(LIF(Z,read)(&upi->zio, &length, sizeof(size_t)) == 0); + /*verify(LIF(Z,read)(&upi->zio, &length, sizeof(int)) == 0);*/ + /*verify(LIF(Z,read)(&upi->zio, &length, sizeof(size_t)) == 0);*/ + read_size(&upi->zio, &length); string = pdep_newvector(upi->L, length, char); verify(LIF(Z,read)(&upi->zio, string, length) == 0); lua_pushlstring(upi->L, string, length); @@ -1312,7 +1685,7 @@ static void unpersistthread(int ref, UnpersistInfo *upi) /* First, deserialize the object stack. */ { size_t i, stacksize; - verify(LIF(Z,read)(&upi->zio, &stacksize, sizeof(size_t)) == 0); + read_size(&upi->zio, &stacksize); LIF(D,growstack)(L2, (int)stacksize); /* Make sure that the first stack element (a nil, representing * the imaginary top-level C function) is written to the very, @@ -1331,16 +1704,16 @@ static void unpersistthread(int ref, UnpersistInfo *upi) /* Now, deserialize the CallInfo stack. */ { size_t i, numframes; - verify(LIF(Z,read)(&upi->zio, &numframes, sizeof(size_t)) == 0); + read_size(&upi->zio, &numframes); LIF(D,reallocCI)(L2,numframes*2); for(i=0; i<numframes; i++) { CallInfo *ci = L2->base_ci + i; size_t stackbase, stackfunc, stacktop, savedpc; - verify(LIF(Z,read)(&upi->zio, &stackbase, sizeof(size_t)) == 0); - verify(LIF(Z,read)(&upi->zio, &stackfunc, sizeof(size_t)) == 0); - verify(LIF(Z,read)(&upi->zio, &stacktop, sizeof(size_t)) == 0); + read_size(&upi->zio, &stackbase); + read_size(&upi->zio, &stackfunc); + read_size(&upi->zio, &stacktop); verify(LIF(Z,read)(&upi->zio, &ci->nresults, sizeof(int)) == 0); - verify(LIF(Z,read)(&upi->zio, &savedpc, sizeof(size_t)) == 0); + read_size(&upi->zio, &savedpc); if(stacklimit < stacktop) stacklimit = stacktop; @@ -1363,9 +1736,10 @@ static void unpersistthread(int ref, UnpersistInfo *upi) size_t stackbase, stacktop; L2->savedpc = L2->ci->savedpc; verify(LIF(Z,read)(&upi->zio, &L2->status, sizeof(lu_byte)) == 0); - verify(LIF(Z,read)(&upi->zio, &stackbase, sizeof(size_t)) == 0); - verify(LIF(Z,read)(&upi->zio, &stacktop, sizeof(size_t)) == 0); + read_size(&upi->zio, &stackbase); + read_size(&upi->zio, &stacktop); verify(LIF(Z,read)(&upi->zio, &L2->errfunc, sizeof(ptrdiff_t)) == 0); + //read_size(&upi->zio, (size_t *)&L2->errfunc); L2->base = L2->stack + stackbase; L2->top = L2->stack + stacktop; } @@ -1391,7 +1765,7 @@ static void unpersistthread(int ref, UnpersistInfo *upi) lua_pop(upi->L, 1); /* perms reftbl ... thr */ - verify(LIF(Z,read)(&upi->zio, &stackpos, sizeof(size_t)) == 0); + read_size(&upi->zio, &stackpos); uv->v = L2->stack + stackpos; gcunlink(upi->L, (GCObject *)uv); uv->marked = luaC_white(g); @@ -1443,7 +1817,7 @@ static void unpersistuserdata(int ref, UnpersistInfo *upi) /* perms reftbl ... udata */ } else { size_t length; - verify(LIF(Z,read)(&upi->zio, &length, sizeof(size_t)) == 0); + read_size(&upi->zio, &length); lua_newuserdata(upi->L, length); /* perms reftbl ... udata */ @@ -1611,8 +1985,8 @@ void pluto_unpersist(lua_State *L, lua_Chunkreader reader, void *ud) } typedef struct LoadInfo_t { - char *buf; - size_t size; + char *buf; + size_t size; } LoadInfo; @@ -1653,9 +2027,41 @@ int unpersist_l(lua_State *L) return 1; } +/* Stefan's first C function for Lua! :) + Returns a string describing the Pluto version you're using. */ + +int version_l(lua_State *L) +{ + const char *version = VERSION; + + lua_settop(L, 0); + /* (empty) */ + lua_pushlstring(L, version, strlen(version)); + /* str */ + return 1; +} + +/* Set human-readable output on or off. */ +int human_l(lua_State *L) +{ + /* flag? ...? */ + lua_settop(L, 1); + /* flag? */ + /*luaL_checktype(L, 1, LUA_TBOOLEAN);*/ + /* flag */ + + humanReadable = lua_toboolean(L, 1); + + lua_settop(L, 0); + /* (empty) */ + return 0; +} + static luaL_reg pluto_reg[] = { { "persist", persist_l }, { "unpersist", unpersist_l }, + { "version", version_l }, + { "human", human_l }, { NULL, NULL } }; diff --git a/engines/teenagent/callbacks.cpp b/engines/teenagent/callbacks.cpp index 2de81abb37..3e6e40a8fa 100644 --- a/engines/teenagent/callbacks.cpp +++ b/engines/teenagent/callbacks.cpp @@ -294,7 +294,7 @@ bool TeenAgentEngine::fnRobotSafeAlreadyUnlockedCheck() { } void TeenAgentEngine::fnRobotSafeUnlockCheck() { - if (CHECK_FLAG(dsAddr_MansionRobotSafeVoiceTestPassedFlag, 1) && + if (CHECK_FLAG(dsAddr_MansionRobotSafeVoiceTestPassedFlag, 1) && CHECK_FLAG(dsAddr_MansionRobotSafeScentTestPassedFlag, 1) && CHECK_FLAG(dsAddr_MansionRobotSafeViewTestPassedFlag, 1)) { waitLanAnimationFrame(1, 1); @@ -546,7 +546,7 @@ bool TeenAgentEngine::processCallback(uint16 addr) { break; case 0x4056: - // FIXME - This is the bird use callback in the first act at + // FIXME - This is the bird use callback in the first act at // the mudpool. Current Code based on behaviour. Need to analyse cseg data. dialog->popMark(scene, dsAddr_dialogStackMudpoolBird); break; @@ -1603,7 +1603,7 @@ bool TeenAgentEngine::processCallback(uint16 addr) { break; case 0x5b44: - // FIXME - This is the doorbell use callback on House #2 + // FIXME - This is the doorbell use callback on House #2 // i.e. Granny and Anne's House. Need to analyse cseg data properly. // Current code inferred from behaviour. // FIXME - Add animation call for Ego pushing doorbell. diff --git a/engines/teenagent/dialog.cpp b/engines/teenagent/dialog.cpp index 870aca6400..312757a462 100644 --- a/engines/teenagent/dialog.cpp +++ b/engines/teenagent/dialog.cpp @@ -28,7 +28,7 @@ namespace TeenAgent { void Dialog::show(uint16 dialogNum, Scene *scene, uint16 animation1, uint16 animation2, byte color1, byte color2, byte slot1, byte slot2) { uint16 addr = _vm->res->getDialogAddr(dialogNum); - // WORKAROUND: For Dialog 163, The usage of this in the engine overlaps the previous dialog i.e. the + // WORKAROUND: For Dialog 163, The usage of this in the engine overlaps the previous dialog i.e. the // starting offset used is two bytes early, thus implicitly changing the first command of this dialog // from NEW_LINE to CHANGE_CHARACTER. // FIXME: Unsure if this is correct behaviour or if this is a regression from the original. Check this. diff --git a/engines/teenagent/font.cpp b/engines/teenagent/font.cpp index 47f52ff90f..9d85328f20 100644 --- a/engines/teenagent/font.cpp +++ b/engines/teenagent/font.cpp @@ -65,7 +65,7 @@ uint Font::render(Graphics::Surface *surface, int x, int y, char c, byte color) byte *glyph = _data + READ_LE_UINT16(_data + idx * 2); int h = glyph[0], w = glyph[1]; - if (surface == NULL || surface->pixels == NULL || y + h <= 0 || y >= kScreenHeight || x + w <= 0 || x >= kScreenWidth) + if (surface == NULL || surface->getPixels() == NULL || y + h <= 0 || y >= kScreenHeight || x + w <= 0 || x >= kScreenWidth) return w - _widthPack; int i0 = 0, j0 = 0; diff --git a/engines/teenagent/resources.cpp b/engines/teenagent/resources.cpp index 442d0abf16..cdbdcf9655 100644 --- a/engines/teenagent/resources.cpp +++ b/engines/teenagent/resources.cpp @@ -160,7 +160,7 @@ void Resources::loadOff(Graphics::Surface &surface, byte *palette, int id) { off.read(id, buf, bufferSize); byte *src = buf; - byte *dst = (byte *)surface.pixels; + byte *dst = (byte *)surface.getPixels(); memcpy(dst, src, 64000); memcpy(palette, buf + 64000, 768); @@ -206,16 +206,19 @@ Common::SeekableReadStream *Resources::loadLan000(uint32 id) const { if (dseg.get_byte(dsAddr_birdOnBarRadioAntennaFlag) == 1) { return lan500.getStream(380); } + break; case 30: if (dseg.get_byte(dsAddr_birdOnBarRadioAntennaFlag) == 1) { return lan500.getStream(381); } + break; case 42: if (dseg.get_byte(dsAddr_johnNotyOutsideMansionDoorFlag) == 1) { return lan500.getStream(400); } + break; } return lan000.getStream(id); } diff --git a/engines/teenagent/scene.cpp b/engines/teenagent/scene.cpp index bdeb11a841..f36a60932c 100644 --- a/engines/teenagent/scene.cpp +++ b/engines/teenagent/scene.cpp @@ -48,7 +48,6 @@ Scene::Scene(TeenAgentEngine *vm) : _vm(vm), intro(false), _id(0), ons(0), onEnabled = true; memset(palette, 0, sizeof(palette)); - background.pixels = 0; FilePack varia; varia.open("varia.res"); @@ -74,8 +73,7 @@ Scene::Scene(TeenAgentEngine *vm) : _vm(vm), intro(false), _id(0), ons(0), } Scene::~Scene() { - if (background.pixels) - background.free(); + background.free(); delete[] ons; ons = 0; @@ -372,7 +370,7 @@ void Scene::init(int id, const Common::Point &pos) { for (byte i = 0; i < 4; ++i) customAnimation[i].free(); - if (background.pixels == NULL) + if (background.getPixels() == NULL) background.create(kScreenWidth, kScreenHeight, Graphics::PixelFormat::createFormatCLUT8()); warp(pos); @@ -416,7 +414,7 @@ void Scene::init(int id, const Common::Point &pos) { if (nowPlaying != _vm->res->dseg.get_byte(dsAddr_currentMusic)) _vm->music->load(_vm->res->dseg.get_byte(dsAddr_currentMusic)); - _vm->_system->copyRectToScreen(background.pixels, background.pitch, 0, 0, background.w, background.h); + _vm->_system->copyRectToScreen(background.getPixels(), background.pitch, 0, 0, background.w, background.h); setPalette(0); } @@ -642,8 +640,8 @@ bool Scene::render(bool tickGame, bool tickMark, uint32 messageDelta) { return true; } - if (background.pixels && debugFeatures.feature[DebugFeatures::kShowBack]) { - _vm->_system->copyRectToScreen(background.pixels, background.pitch, 0, 0, background.w, background.h); + if (background.getPixels() && debugFeatures.feature[DebugFeatures::kShowBack]) { + _vm->_system->copyRectToScreen(background.getPixels(), background.pitch, 0, 0, background.w, background.h); } else _vm->_system->fillScreen(0); diff --git a/engines/teenagent/teenagent.cpp b/engines/teenagent/teenagent.cpp index 0b48a18b26..e73f1100d6 100644 --- a/engines/teenagent/teenagent.cpp +++ b/engines/teenagent/teenagent.cpp @@ -399,7 +399,7 @@ bool TeenAgentEngine::showLogo() { return true; } - _system->copyRectToScreen(s.pixels, s.w, s.x, s.y, s.w, s.h); + _system->copyRectToScreen(s.getPixels(), s.w, s.x, s.y, s.w, s.h); _system->updateScreen(); _system->delayMillis(100); diff --git a/engines/testbed/config.cpp b/engines/testbed/config.cpp index 6b56616c9b..a40d239ebf 100644 --- a/engines/testbed/config.cpp +++ b/engines/testbed/config.cpp @@ -213,22 +213,22 @@ void TestbedConfigManager::parseConfigFile() { return; } _configFileInterface.loadFromStream(*rs); - Common::ConfigFile::SectionList sections = _configFileInterface.getSections(); + Common::INIFile::SectionList sections = _configFileInterface.getSections(); Testsuite *currTS = 0; - for (Common::ConfigFile::SectionList::const_iterator i = sections.begin(); i != sections.end(); i++) { + for (Common::INIFile::SectionList::const_iterator i = sections.begin(); i != sections.end(); i++) { if (i->name.equalsIgnoreCase("Global")) { // Global params may be directly queried, ignore them } else { // A testsuite, process it. currTS = getTestsuiteByName(i->name); - Common::ConfigFile::SectionKeyList kList = i->getKeys(); + Common::INIFile::SectionKeyList kList = i->getKeys(); if (!currTS) { Testsuite::logPrintf("Warning! Error in config: Testsuite %s not found\n", i->name.c_str()); continue; } - for (Common::ConfigFile::SectionKeyList::const_iterator j = kList.begin(); j != kList.end(); j++) { + for (Common::INIFile::SectionKeyList::const_iterator j = kList.begin(); j != kList.end(); j++) { if (j->key.equalsIgnoreCase("this")) { currTS->enable(stringToBool(j->value)); } else { diff --git a/engines/testbed/config.h b/engines/testbed/config.h index fd5588aa31..d611ae4ec3 100644 --- a/engines/testbed/config.h +++ b/engines/testbed/config.h @@ -24,7 +24,7 @@ #include "common/array.h" -#include "common/config-file.h" +#include "common/ini-file.h" #include "common/str-array.h" #include "common/tokenizer.h" @@ -62,7 +62,7 @@ public: private: Common::Array<Testsuite *> &_testsuiteList; Common::String _configFileName; - Common::ConfigFile _configFileInterface; + Common::INIFile _configFileInterface; void parseConfigFile(); }; diff --git a/engines/testbed/graphics.cpp b/engines/testbed/graphics.cpp index 590e6c6d81..26e073d407 100644 --- a/engines/testbed/graphics.cpp +++ b/engines/testbed/graphics.cpp @@ -927,17 +927,29 @@ TestExitStatus GFXtests::overlayGraphics() { Graphics::PixelFormat pf = g_system->getOverlayFormat(); - OverlayColor buffer[50 * 100]; - OverlayColor value = pf.RGBToColor(0, 255, 0); + byte *buffer = new byte[50 * 100 * pf.bytesPerPixel]; + const uint32 value = pf.RGBToColor(0, 255, 0); - for (int i = 0; i < 50 * 100; i++) { - buffer[i] = value; + if (pf.bytesPerPixel == 2) { + uint16 *dst = (uint16 *)buffer; + for (int i = 50 * 100; i > 0; --i) { + *dst++ = value; + } + } else if (pf.bytesPerPixel == 4) { + uint32 *dst = (uint32 *)buffer; + for (int i = 50 * 100; i > 0; --i) { + *dst++ = value; + } + } else { + error("GFXtests::overlayGraphics: Unsupported color depth: %d", pf.bytesPerPixel); } g_system->showOverlay(); - g_system->copyRectToOverlay(buffer, 200, 270, 175, 100, 50); + g_system->copyRectToOverlay(buffer, 100 * pf.bytesPerPixel, 270, 175, 100, 50); g_system->updateScreen(); + delete[] buffer; + g_system->delayMillis(1000); g_system->hideOverlay(); diff --git a/engines/tinsel/bmv.cpp b/engines/tinsel/bmv.cpp index 106e1542d5..fa66b7ad8e 100644 --- a/engines/tinsel/bmv.cpp +++ b/engines/tinsel/bmv.cpp @@ -1031,7 +1031,7 @@ void BMVPlayer::CopyMovieToScreen() { // The movie surface is slightly less high than the output screen (429 rows versus 432). // Because of this, there's some extra line clearing above and below the displayed area int yStart = (SCREEN_HEIGHT - SCREEN_HIGH) / 2; - memset(_vm->screen().getBasePtr(0, 0), 0, yStart * SCREEN_WIDTH); + memset(_vm->screen().getPixels(), 0, yStart * SCREEN_WIDTH); memcpy(_vm->screen().getBasePtr(0, yStart), ScreenBeg, SCREEN_WIDTH * SCREEN_HIGH); memset(_vm->screen().getBasePtr(0, yStart + SCREEN_HIGH), 0, (SCREEN_HEIGHT - SCREEN_HIGH - yStart) * SCREEN_WIDTH); diff --git a/engines/tinsel/graphics.cpp b/engines/tinsel/graphics.cpp index 5dae984def..c4f341f6fe 100644 --- a/engines/tinsel/graphics.cpp +++ b/engines/tinsel/graphics.cpp @@ -798,7 +798,7 @@ static void PackedWrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, */ void ClearScreen() { byte blackColorIndex = (!TinselV1Mac) ? 0 : 255; - void *pDest = _vm->screen().getBasePtr(0, 0); + void *pDest = _vm->screen().getPixels(); memset(pDest, blackColorIndex, SCREEN_WIDTH * SCREEN_HEIGHT); g_system->fillScreen(blackColorIndex); g_system->updateScreen(); diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp index 3921414b01..104adf72a2 100644 --- a/engines/tinsel/handle.cpp +++ b/engines/tinsel/handle.cpp @@ -300,7 +300,7 @@ void LoadFile(MEMHANDLE *pH) { // discardable - unlock the memory MemoryUnlock(pH->_node); - + // set the loaded flag pH->filesize |= fLoaded; diff --git a/engines/tinsel/rince.cpp b/engines/tinsel/rince.cpp index 3e6334f583..49666c13ca 100644 --- a/engines/tinsel/rince.cpp +++ b/engines/tinsel/rince.cpp @@ -808,7 +808,8 @@ void T2MoverProcess(CORO_PARAM, const void *param) { PokeInPalette(pmi); pMover->actorObj = MultiInitObject(pmi); - pMover->actorID = pMover->actorID; + // FIXME: This is what the original did. A bug, perhaps? + // pMover->actorID = pMover->actorID; pMover->bActive = true; // add it to display list diff --git a/engines/tinsel/scene.cpp b/engines/tinsel/scene.cpp index b652e394a0..43654fc3af 100644 --- a/engines/tinsel/scene.cpp +++ b/engines/tinsel/scene.cpp @@ -130,15 +130,15 @@ const SCENE_STRUC *GetSceneStruc(const byte *pStruc) { const byte *p = pStruc; memset(&g_tempStruc, 0, sizeof(SCENE_STRUC)); - g_tempStruc.numEntrance = FROM_LE_32(READ_32(p)); p += sizeof(uint32); - g_tempStruc.numPoly = FROM_LE_32(READ_32(p)); p += sizeof(uint32); - g_tempStruc.numTaggedActor = FROM_LE_32(READ_32(p)); p += sizeof(uint32); - g_tempStruc.defRefer = FROM_LE_32(READ_32(p)); p += sizeof(uint32); - g_tempStruc.hSceneScript = FROM_LE_32(READ_32(p)); p += sizeof(uint32); - g_tempStruc.hEntrance = FROM_LE_32(READ_32(p)); p += sizeof(uint32); - g_tempStruc.hPoly = FROM_LE_32(READ_32(p)); p += sizeof(uint32); - g_tempStruc.hTaggedActor = FROM_LE_32(READ_32(p)); p += sizeof(uint32); - + g_tempStruc.numEntrance = READ_32(p); p += sizeof(uint32); + g_tempStruc.numPoly = READ_32(p); p += sizeof(uint32); + g_tempStruc.numTaggedActor = READ_32(p); p += sizeof(uint32); + g_tempStruc.defRefer = READ_32(p); p += sizeof(uint32); + g_tempStruc.hSceneScript = READ_32(p); p += sizeof(uint32); + g_tempStruc.hEntrance = READ_32(p); p += sizeof(uint32); + g_tempStruc.hPoly = READ_32(p); p += sizeof(uint32); + g_tempStruc.hTaggedActor = READ_32(p); p += sizeof(uint32); + return &g_tempStruc; } diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index 9075e1adb1..5d410e62c7 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -868,9 +868,6 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc) } TinselEngine::~TinselEngine() { - if (_bmv->MoviePlaying()) - _bmv->FinishBMV(); - _system->getAudioCDManager()->stop(); delete _bmv; delete _sound; @@ -1007,6 +1004,9 @@ Common::Error TinselEngine::run() { g_system->delayMillis(10); } + if (_bmv->MoviePlaying()) + _bmv->FinishBMV(); + // Write configuration _vm->_config->writeToDisk(); diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h index 56fed3007f..5eb3b7d7b8 100644 --- a/engines/tinsel/tinsel.h +++ b/engines/tinsel/tinsel.h @@ -226,7 +226,11 @@ public: Graphics::Surface &screen() { return _screenSurface; } Common::Point getMousePosition() const { return _mousePos; } - void setMousePosition(const Common::Point &pt) { + void setMousePosition(Common::Point pt) { + // Clip mouse position to be within the screen coordinates + pt.x = CLIP<int16>(pt.x, 0, SCREEN_WIDTH - 1); + pt.y = CLIP<int16>(pt.y, 0, SCREEN_HEIGHT - 1); + int yOffset = TinselV2 ? (g_system->getHeight() - _screenSurface.h) / 2 : 0; g_system->warpMouse(pt.x, pt.y + yOffset); _mousePos = pt; diff --git a/engines/toltecs/menu.cpp b/engines/toltecs/menu.cpp index b52d7dad82..0850630c43 100644 --- a/engines/toltecs/menu.cpp +++ b/engines/toltecs/menu.cpp @@ -69,7 +69,7 @@ int MenuSystem::run(MenuID menuId) { _vm->_screen->blastSprite(0x140 + _vm->_cameraX, 0x175 + _vm->_cameraY, 0, 1, 0x4000); shadeRect(60, 39, 520, 247, 225, 229); - memcpy(_background->pixels, _vm->_screen->_frontScreen, 640 * 400); + memcpy(_background->getPixels(), _vm->_screen->_frontScreen, 640 * 400); while (_running) { update(); @@ -229,7 +229,7 @@ void MenuSystem::initMenu(MenuID menuID) { _items.clear(); - memcpy(_vm->_screen->_frontScreen, _background->pixels, 640 * 400); + memcpy(_vm->_screen->_frontScreen, _background->getPixels(), 640 * 400); switch (menuID) { case kMenuIdMain: diff --git a/engines/toltecs/screen.cpp b/engines/toltecs/screen.cpp index 5e12773e1b..1eb2f41fd2 100644 --- a/engines/toltecs/screen.cpp +++ b/engines/toltecs/screen.cpp @@ -651,7 +651,7 @@ void Screen::drawSurface(int16 x, int16 y, Graphics::Surface *surface) { int16 skipX = 0; int16 width = surface->w; int16 height = surface->h; - byte *surfacePixels = (byte *)surface->getBasePtr(0, 0); + byte *surfacePixels = (byte *)surface->getPixels(); byte *frontScreen; // Not on screen, skip diff --git a/engines/toltecs/segmap.cpp b/engines/toltecs/segmap.cpp index b06c0af675..fea40f3277 100644 --- a/engines/toltecs/segmap.cpp +++ b/engines/toltecs/segmap.cpp @@ -373,7 +373,7 @@ void SegmentMap::loadSegmapMaskRectSurface(byte *maskData, SegmapMaskRect &maskR maskRect.surface->create(maskRect.width, maskRect.height, Graphics::PixelFormat::createFormatCLUT8()); byte *backScreen = _vm->_screen->_backScreen + maskRect.x + (maskRect.y * _vm->_sceneWidth); - byte *dest = (byte *)maskRect.surface->getBasePtr(0, 0); + byte *dest = (byte *)maskRect.surface->getPixels(); for (int16 h = 0; h < maskRect.height; h++) { int16 w = maskRect.width; diff --git a/engines/tony/detection.cpp b/engines/tony/detection.cpp index 1094950e2c..d355450153 100644 --- a/engines/tony/detection.cpp +++ b/engines/tony/detection.cpp @@ -154,26 +154,16 @@ void TonyMetaEngine::removeSaveState(const char *target, int slot) const { SaveStateDescriptor TonyMetaEngine::querySaveMetaInfos(const char *target, int slot) const { Common::String saveName; byte difficulty; - byte thumbData[160 * 120 * 2]; - - if (Tony::RMOptionScreen::loadThumbnailFromSaveState(slot, thumbData, saveName, difficulty)) { - // Convert the 565 thumbnail data to the needed overlay format - Common::MemoryReadStream thumbStream(thumbData, 160 * 120 * 2); - Graphics::PixelFormat destFormat = g_system->getOverlayFormat(); - Graphics::Surface *to = new Graphics::Surface(); - to->create(160, 120, destFormat); - - OverlayColor *pixels = (OverlayColor *)to->pixels; - for (int y = 0; y < to->h; ++y) { - for (int x = 0; x < to->w; ++x) { - uint8 r, g, b; - Graphics::colorToRGB<Graphics::ColorMasks<555> >(thumbStream.readUint16LE(), r, g, b); - - // converting to current OSystem Color - *pixels++ = destFormat.RGBToColor(r, g, b); - } - } + Graphics::Surface *to = new Graphics::Surface(); + to->create(160, 120, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)); + + if (Tony::RMOptionScreen::loadThumbnailFromSaveState(slot, (byte *)to->getPixels(), saveName, difficulty)) { +#ifdef SCUMM_BIG_ENDIAN + uint16 *pixels = (uint16 *)to->getPixels(); + for (int i = 0; i < to->w * to->h; ++i) + pixels[i] = READ_LE_UINT16(pixels + i); +#endif // Create the return descriptor SaveStateDescriptor desc(slot, saveName); desc.setDeletableFlag(true); @@ -183,6 +173,7 @@ SaveStateDescriptor TonyMetaEngine::querySaveMetaInfos(const char *target, int s return desc; } + delete to; return SaveStateDescriptor(); } diff --git a/engines/tony/detection_tables.h b/engines/tony/detection_tables.h index ee137927dc..ca16495903 100644 --- a/engines/tony/detection_tables.h +++ b/engines/tony/detection_tables.h @@ -196,6 +196,40 @@ static const TonyGameDescription gameDescriptions[] = { }, }, + { + // Tony Tough English Unpacked + { + "tony", + 0, + { + {"roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071}, + {"roasted.mpc", 0, "57c4a3860cf899443c357e0078ea6f49", 366773}, + AD_LISTEND + }, + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + GUIO1(GUIO_NONE) + }, + }, + + { + // Tony Tough German "Shoe Box", reported in bug #3582420 + { + "tony", + 0, + { + {"roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071}, + {"roasted.mpc", 0, "bc3471f098e591dc509dcad401a8d8a5", 389554}, + AD_LISTEND + }, + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + GUIO1(GUIO_NONE) + }, + }, + { AD_TABLE_END_MARKER } }; diff --git a/engines/tony/game.cpp b/engines/tony/game.cpp index 501a588ff5..ca7c07ad8c 100644 --- a/engines/tony/game.cpp +++ b/engines/tony/game.cpp @@ -508,7 +508,8 @@ void RMOptionScreen::refreshThumbnails() { _curThumb[i] = NULL; _curThumbName[i].clear(); _curThumbDiff[i] = 11; - } + } else + _curThumb[i]->prepareImage(); } } diff --git a/engines/tony/gfxcore.cpp b/engines/tony/gfxcore.cpp index dc82c78ee5..410f9b8971 100644 --- a/engines/tony/gfxcore.cpp +++ b/engines/tony/gfxcore.cpp @@ -1865,7 +1865,7 @@ void RMGfxSourceBuffer8RLEWordAA::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RM CORO_END_CODE; } -int RMGfxSourceBuffer8RLEWordAA::init(byte *buf, int dimx, int dimy, bool bLoadPalette) { +int RMGfxSourceBuffer8RLEWordAA::init(const byte *buf, int dimx, int dimy, bool bLoadPalette) { return RMGfxSourceBuffer8RLE::init(buf, dimx, dimy, bLoadPalette); } diff --git a/engines/tony/gfxcore.h b/engines/tony/gfxcore.h index 1bacf7e5a9..9e8f5225c0 100644 --- a/engines/tony/gfxcore.h +++ b/engines/tony/gfxcore.h @@ -208,8 +208,10 @@ public: * 16-bit color source */ class RMGfxSourceBuffer16 : public RMGfxSourceBuffer { -protected: +public: virtual void prepareImage(); + +protected: bool _bTrasp0; public: @@ -408,7 +410,7 @@ public: // Overloaded initialization methods virtual void init(Common::ReadStream &ds, int dimx, int dimy, bool bLoadPalette = false); - virtual int init(byte *buf, int dimx, int dimy, bool bLoadPalette = false); + virtual int init(const byte *buf, int dimx, int dimy, bool bLoadPalette = false); virtual ~RMGfxSourceBuffer8RLEWordAA(); }; diff --git a/engines/tony/mpal/mpal.cpp b/engines/tony/mpal/mpal.cpp index 1de5c6850c..5e6d44f0a3 100644 --- a/engines/tony/mpal/mpal.cpp +++ b/engines/tony/mpal/mpal.cpp @@ -1876,14 +1876,11 @@ MpalHandle mpalQueryHANDLE(uint16 wQueryType, ...) { * @remarks This is the specialised version of the original single mpalQuery * method that needs to run within a co-routine context. */ -void mpalQueryCORO(CORO_PARAM, uint16 wQueryType, uint32 *dwRet, ...) { +void mpalQueryCORO(CORO_PARAM, uint16 wQueryType, uint32 *dwRet) { CORO_BEGIN_CONTEXT; uint32 dwRet; CORO_END_CONTEXT(_ctx); - va_list v; - va_start(v, dwRet); - CORO_BEGIN_CODE(_ctx); if (wQueryType == MPQ_DIALOG_WAITFORCHOICE) { @@ -1909,8 +1906,6 @@ void mpalQueryCORO(CORO_PARAM, uint16 wQueryType, uint32 *dwRet, ...) { } CORO_END_CODE; - - va_end(v); } /** @@ -2040,7 +2035,13 @@ int mpalGetSaveStateSize() { void mpalSaveState(byte *buf) { lockVar(); WRITE_LE_UINT32(buf, GLOBALS._nVars); - memcpy(buf + 4, (byte *)GLOBALS._lpmvVars, GLOBALS._nVars * sizeof(MpalVar)); + buf += 4; + for (uint i = 0; i < GLOBALS._nVars; ++i) { + LpMpalVar var = &GLOBALS._lpmvVars[i]; + WRITE_LE_UINT32(buf, var->_dwVal); + memcpy(buf + 4, var->_lpszVarName, sizeof(var->_lpszVarName)); + buf += (4 + sizeof(var->_lpszVarName)); + } unlockVar(); } @@ -2055,10 +2056,16 @@ int mpalLoadState(byte *buf) { globalFree(GLOBALS._hVars); GLOBALS._nVars = READ_LE_UINT32(buf); + buf += 4; GLOBALS._hVars = globalAllocate(GMEM_ZEROINIT | GMEM_MOVEABLE, GLOBALS._nVars * sizeof(MpalVar)); lockVar(); - memcpy((byte *)GLOBALS._lpmvVars, buf + 4, GLOBALS._nVars * sizeof(MpalVar)); + for (uint i = 0; i < GLOBALS._nVars; ++i) { + LpMpalVar var = &GLOBALS._lpmvVars[i]; + var->_dwVal = READ_LE_UINT32(buf); + memcpy(var->_lpszVarName, buf + 4, sizeof(var->_lpszVarName)); + buf += (4 + sizeof(var->_lpszVarName)); + } unlockVar(); return GLOBALS._nVars * sizeof(MpalVar) + 4; diff --git a/engines/tony/mpal/mpal.h b/engines/tony/mpal/mpal.h index 779bdd6188..2d22ee8faf 100644 --- a/engines/tony/mpal/mpal.h +++ b/engines/tony/mpal/mpal.h @@ -417,7 +417,7 @@ MpalHandle mpalQueryHANDLE(uint16 wQueryType, ...); * @remarks This is the specialised version of the original single mpalQuery * method that needs to run within a co-routine context. */ -void mpalQueryCORO(CORO_PARAM, uint16 wQueryType, uint32 *dwRet, ...); +void mpalQueryCORO(CORO_PARAM, uint16 wQueryType, uint32 *dwRet); /** * Execute a script. The script runs on multitasking by a thread. diff --git a/engines/tony/sound.cpp b/engines/tony/sound.cpp index 90ae241db0..547f31906e 100644 --- a/engines/tony/sound.cpp +++ b/engines/tony/sound.cpp @@ -500,7 +500,13 @@ bool FPStream::loadFile(const Common::String &fileName, uint32 codec, int bufSiz break; case FPCODEC_ADPCM: +#ifdef __amigaos4__ + // HACK: AmigaOS 4 has weird performance problems with reading in the audio thread, + // so we read the whole stream into memory. + _rewindableStream = Audio::makeADPCMStream(_file.readStream(_size), DisposeAfterUse::YES, 0, Audio::kADPCMDVI, 44100, 2); +#else _rewindableStream = Audio::makeADPCMStream(&_file, DisposeAfterUse::NO, 0, Audio::kADPCMDVI, 44100, 2); +#endif break; default: diff --git a/engines/tony/window.cpp b/engines/tony/window.cpp index 61497a8066..a732862854 100644 --- a/engines/tony/window.cpp +++ b/engines/tony/window.cpp @@ -330,6 +330,14 @@ void RMSnapshot::grabScreenshot(byte *lpBuf, int dezoom, uint16 *lpDestBuf) { src += RM_BBX * dezoom; } } + +#ifdef SCUMM_BIG_ENDIAN + if (lpDestBuf != NULL) { + for (int i = 0; i < dimx * dimy; i++) { + lpDestBuf[i] = SWAP_BYTES_16(lpDestBuf[i]); + } + } +#endif } } // End of namespace Tony diff --git a/engines/toon/anim.cpp b/engines/toon/anim.cpp index a6744568f7..78d3954325 100644 --- a/engines/toon/anim.cpp +++ b/engines/toon/anim.cpp @@ -190,7 +190,7 @@ void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int16 xx, int int32 destPitch = surface.pitch; uint8 *srcRow = _frames[frame]._data + offsX + (_frames[frame]._x2 - _frames[frame]._x1) * offsY; - uint8 *curRow = (uint8 *)surface.pixels + (yy + _frames[frame]._y1 + _y1 + offsY) * destPitch + (xx + _x1 + _frames[frame]._x1 + offsX); + uint8 *curRow = (uint8 *)surface.getBasePtr(xx + _x1 + _frames[frame]._x1 + offsX, yy + _frames[frame]._y1 + _y1 + offsY); for (int16 y = 0; y < rectY; y++) { uint8 *cur = curRow; uint8 *c = srcRow + y * (_frames[frame]._x2 - _frames[frame]._x1); @@ -231,7 +231,7 @@ void Animation::drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 fram int32 destPitch = surface.pitch; int32 destPitchMask = mask->getWidth(); uint8 *c = _frames[frame]._data; - uint8 *curRow = (uint8 *)surface.pixels; + uint8 *curRow = (uint8 *)surface.getPixels(); uint8 *curRowMask = mask->getDataPtr(); bool shadowFlag = false; @@ -341,7 +341,7 @@ void Animation::drawFontFrame(Graphics::Surface &surface, int32 frame, int16 xx, int32 destPitch = surface.pitch; uint8 *c = _frames[frame]._data; - uint8 *curRow = (uint8 *)surface.pixels + (yy + _frames[frame]._y1 + _y1) * destPitch + (xx + _x1 + _frames[frame]._x1); + uint8 *curRow = (uint8 *)surface.getBasePtr(xx + _x1 + _frames[frame]._x1, yy + _frames[frame]._y1 + _y1); for (int16 y = 0; y < rectY; y++) { unsigned char *cur = curRow; for (int16 x = 0; x < rectX; x++) { diff --git a/engines/toon/character.cpp b/engines/toon/character.cpp index 479f4965f3..83c9e3ec70 100644 --- a/engines/toon/character.cpp +++ b/engines/toon/character.cpp @@ -58,6 +58,7 @@ Character::Character(ToonEngine *vm) : _vm(vm) { _animSpecialDefaultId = 0; _currentPathNode = 0; _currentWalkStamp = 0; + _currentFacingStamp = 0; _visible = true; _speed = 150; // 150 = nominal drew speed _lastWalkTime = 0; @@ -99,6 +100,9 @@ void Character::setFacing(int32 facing) { if (_blockingWalk) { _flags |= 2; + _currentFacingStamp++; + int32 localFacingStamp = _currentFacingStamp; + int32 dir = 0; _lastWalkTime = _vm->_system->getMillis(); @@ -127,6 +131,11 @@ void Character::setFacing(int32 facing) { else playWalkAnim(0, 0); _vm->doFrame(); + + if (_currentFacingStamp != localFacingStamp) { + // another setFacing was started in doFrame, we need to cancel this one. + return; + } }; _flags &= ~2; diff --git a/engines/toon/character.h b/engines/toon/character.h index d33c314bf7..b248e7ccf2 100644 --- a/engines/toon/character.h +++ b/engines/toon/character.h @@ -143,6 +143,7 @@ protected: Common::Array<Common::Point> _currentPath; uint32 _currentPathNode; int32 _currentWalkStamp; + int32 _currentFacingStamp; }; } // End of namespace Toon diff --git a/engines/toon/movie.cpp b/engines/toon/movie.cpp index 8c85e20f7c..f0463a52e1 100644 --- a/engines/toon/movie.cpp +++ b/engines/toon/movie.cpp @@ -112,7 +112,7 @@ bool Movie::playVideo(bool isFirstIntroVideo) { } _vm->_system->unlockScreen(); } else { - _vm->_system->copyRectToScreen(frame->pixels, frame->pitch, 0, 0, frame->w, frame->h); + _vm->_system->copyRectToScreen(frame->getPixels(), frame->pitch, 0, 0, frame->w, frame->h); // WORKAROUND: There is an encoding glitch in the first intro video. This hides this using the adjacent pixels. if (isFirstIntroVideo) { diff --git a/engines/toon/picture.cpp b/engines/toon/picture.cpp index f59cdca064..65cc3a70e1 100644 --- a/engines/toon/picture.cpp +++ b/engines/toon/picture.cpp @@ -170,7 +170,7 @@ void Picture::drawMask(Graphics::Surface &surface, int16 x, int16 y, int16 dx, i int32 destPitch = surface.pitch; int32 srcPitch = _width; uint8 *c = _data + _width * dy + dx; - uint8 *curRow = (uint8 *)surface.pixels + y * destPitch + x; + uint8 *curRow = (uint8 *)surface.getBasePtr(x, y); for (int16 yy = 0; yy < ry; yy++) { uint8 *curSrc = c; @@ -205,7 +205,7 @@ void Picture::drawWithRectList(Graphics::Surface& surface, int16 x, int16 y, int int16 fillRy = MIN<int32>(ry, rect.bottom - rect.top); uint8 *c = _data + _width * (dy + rect.top) + (dx + rect.left); - uint8 *curRow = (uint8 *)surface.pixels + (y + rect.top) * destPitch + (x + rect.left); + uint8 *curRow = (uint8 *)surface.getBasePtr(x + rect.left, y + rect.top); for (int16 yy = 0; yy < fillRy; yy++) { uint8 *curSrc = c; @@ -233,7 +233,7 @@ void Picture::draw(Graphics::Surface &surface, int16 x, int16 y, int16 dx, int16 int32 destPitch = surface.pitch; int32 srcPitch = _width; uint8 *c = _data + _width * dy + dx; - uint8 *curRow = (uint8 *)surface.pixels + y * destPitch + x; + uint8 *curRow = (uint8 *)surface.getBasePtr(x, y); for (int16 yy = 0; yy < ry; yy++) { uint8 *curSrc = c; diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp index 7ad29ab8d8..286bcf1941 100644 --- a/engines/toon/toon.cpp +++ b/engines/toon/toon.cpp @@ -466,8 +466,7 @@ void ToonEngine::doMagnifierEffect() { int32 cy = CLIP<int32>(posY + y, 0, TOON_BACKBUFFER_HEIGHT-1); for (int32 x = -12; x <= 12; x++) { int32 cx = CLIP<int32>(posX + x, 0, TOON_BACKBUFFER_WIDTH-1); - int32 destPitch = surface.pitch; - uint8 *curRow = (uint8 *)surface.pixels + cy * destPitch + cx; + uint8 *curRow = (uint8 *)surface.getBasePtr(cx, cy); tempBuffer[(y + 12) * 25 + x + 12] = *curRow; } } @@ -479,8 +478,7 @@ void ToonEngine::doMagnifierEffect() { if (dist > 144) continue; int32 cx = CLIP<int32>(posX + x, 0, TOON_BACKBUFFER_WIDTH-1); - int32 destPitch = surface.pitch; - uint8 *curRow = (uint8 *)surface.pixels + cy * destPitch + cx; + uint8 *curRow = (uint8 *)surface.getBasePtr(cx, cy); int32 lerp = (512 + intSqrt[dist] * 256 / 12); *curRow = tempBuffer[(y * lerp / 1024 + 12) * 25 + x * lerp / 1024 + 12]; } @@ -501,7 +499,7 @@ void ToonEngine::copyToVirtualScreen(bool updateScreen) { if (_dirtyAll || _gameState->_currentScrollValue != lastScroll) { // we have to refresh everything in case of scrolling. - _system->copyRectToScreen((byte *)_mainSurface->pixels + state()->_currentScrollValue, TOON_BACKBUFFER_WIDTH, 0, 0, TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT); + _system->copyRectToScreen((byte *)_mainSurface->getPixels() + state()->_currentScrollValue, TOON_BACKBUFFER_WIDTH, 0, 0, TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT); } else { int32 offX = 0; @@ -517,7 +515,7 @@ void ToonEngine::copyToVirtualScreen(bool updateScreen) { } rect.clip(TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT); if (rect.left >= 0 && rect.top >= 0 && rect.right - rect.left > 0 && rect.bottom - rect.top > 0) { - _system->copyRectToScreen((byte *)_mainSurface->pixels + _oldDirtyRects[i].left + offX + _oldDirtyRects[i].top * TOON_BACKBUFFER_WIDTH, TOON_BACKBUFFER_WIDTH, rect.left , rect.top, rect.right - rect.left, rect.bottom - rect.top); + _system->copyRectToScreen((byte *)_mainSurface->getBasePtr(_oldDirtyRects[i].left + offX, _oldDirtyRects[i].top), TOON_BACKBUFFER_WIDTH, rect.left , rect.top, rect.right - rect.left, rect.bottom - rect.top); } } @@ -533,7 +531,7 @@ void ToonEngine::copyToVirtualScreen(bool updateScreen) { } rect.clip(TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT); if (rect.left >= 0 && rect.top >= 0 && rect.right - rect.left > 0 && rect.bottom - rect.top > 0) { - _system->copyRectToScreen((byte *)_mainSurface->pixels + _dirtyRects[i].left + offX + _dirtyRects[i].top * TOON_BACKBUFFER_WIDTH, TOON_BACKBUFFER_WIDTH, rect.left , rect.top, rect.right - rect.left, rect.bottom - rect.top); + _system->copyRectToScreen((byte *)_mainSurface->getBasePtr(_dirtyRects[i].left + offX, _dirtyRects[i].top), TOON_BACKBUFFER_WIDTH, rect.left , rect.top, rect.right - rect.left, rect.bottom - rect.top); } } } diff --git a/engines/tsage/blue_force/blueforce_scenes9.cpp b/engines/tsage/blue_force/blueforce_scenes9.cpp index 1cb8191640..52115b95fe 100644 --- a/engines/tsage/blue_force/blueforce_scenes9.cpp +++ b/engines/tsage/blue_force/blueforce_scenes9.cpp @@ -705,6 +705,10 @@ void Scene900::process(Event &event) { void Scene900::dispatch() { SceneExt::dispatch(); + // WORKAROUND:: Fix for invalid data in the Blue Force floppy version when opening gate + if (_sceneMode == 9006 && (g_vm->getFeatures() & GF_FLOPPY) && BF_GLOBALS._player._endFrame == 8) + BF_GLOBALS._player._endFrame = 6; + if (BF_GLOBALS.getFlag(fWithLyle) && _lyle.isNoMover()) { _lyle.updateAngle(BF_GLOBALS._player._position); } diff --git a/engines/tsage/converse.cpp b/engines/tsage/converse.cpp index de5ac62425..8ae6a0d97e 100644 --- a/engines/tsage/converse.cpp +++ b/engines/tsage/converse.cpp @@ -416,7 +416,7 @@ SequenceManager *SequenceManager::globalManager() { ConversationChoiceDialog::ConversationChoiceDialog() { _stdColor = 23; _highlightColor = g_globals->_scenePalette._colors.background; - _fontNumber = 1; + _fontNumber = (g_vm->getGameID() == GType_Ringworld2) ? 3 : 1; _savedFgColor = _savedFontNumber = 0; _selectedIndex = 0; } @@ -424,15 +424,15 @@ ConversationChoiceDialog::ConversationChoiceDialog() { int ConversationChoiceDialog::execute(const Common::StringArray &choiceList) { _gfxManager._font.setFontNumber(_fontNumber); - _bounds = Rect(20, 0, 20, 0); + _bounds = Rect(40, 0, 40, 0); _choiceList.clear(); // Set up the list of choices int yp = 0; for (uint idx = 0; idx < choiceList.size(); ++idx) { Rect tempRect; - _gfxManager._font.getStringBounds(choiceList[idx].c_str(), tempRect, 265); - tempRect.moveTo(25, yp + 10); + _gfxManager._font.getStringBounds(choiceList[idx].c_str(), tempRect, textMaxWidth()); + tempRect.moveTo(textLeft(), yp + 10); _choiceList.push_back(ChoiceEntry(choiceList[idx], tempRect)); yp += tempRect.height() + 5; @@ -444,7 +444,8 @@ int ConversationChoiceDialog::execute(const Common::StringArray &choiceList) { _bounds.bottom -= 10; yp = 180 - _bounds.height(); _bounds.translate(0, yp); - _bounds.right = _bounds.left + 280; + _bounds.setWidth(textMaxWidth() + 15); + _bounds.moveTo(160 - (_bounds.width() / 2), _bounds.top); // Draw the dialog draw(); @@ -513,6 +514,7 @@ void ConversationChoiceDialog::draw() { // Fill in the contents of the entire dialog _gfxManager._bounds = Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + drawFrame(); _gfxManager._bounds = tempRect; @@ -524,7 +526,7 @@ void ConversationChoiceDialog::draw() { Common::String strNum = Common::String::format("%d", idx + 1); // Write the choice number - _gfxManager._font.setPosition(13, _choiceList[idx]._bounds.top); + _gfxManager._font.setPosition(numberLeft(), _choiceList[idx]._bounds.top); _gfxManager._font.writeString(strNum.c_str()); _gfxManager._font.writeLines(_choiceList[idx]._msg.c_str(), _choiceList[idx]._bounds, ALIGN_LEFT); @@ -533,6 +535,18 @@ void ConversationChoiceDialog::draw() { _gfxManager.deactivate(); } +int ConversationChoiceDialog::textLeft() const { + return (g_vm->getGameID() == GType_Ringworld2) ? 20 : 25; +} + +int ConversationChoiceDialog::textMaxWidth() const { + return (g_vm->getGameID() == GType_Ringworld2) ? 250 : 265; +} + +int ConversationChoiceDialog::numberLeft() const { + return (g_vm->getGameID() == GType_Ringworld2) ? 8 : 13; +} + /*--------------------------------------------------------------------------*/ void Obj44::load(const byte *dataP) { @@ -542,8 +556,8 @@ void Obj44::load(const byte *dataP) { _mode = s.readSint16LE(); _lookupValue = s.readSint16LE(); _lookupIndex = s.readSint16LE(); - _field6 = s.readSint16LE(); - _field8 = s.readSint16LE(); + _exitMode = s.readSint16LE(); + _speakerMode = s.readSint16LE(); } _id = s.readSint16LE(); @@ -551,8 +565,8 @@ void Obj44::load(const byte *dataP) { _callbackId[idx] = s.readSint16LE(); if (g_vm->getGameID() == GType_Ringworld2) { - _field16 = s.readSint16LE(); - s.skip(20); + for (int i = 0; i < 11; ++i) + _field16[i] = s.readSint16LE(); } else { s.skip(4); } @@ -578,9 +592,11 @@ void Obj44::synchronize(Serializer &s) { s.syncAsSint16LE(_mode); s.syncAsSint16LE(_lookupValue); s.syncAsSint16LE(_lookupIndex); - s.syncAsSint16LE(_field6); - s.syncAsSint16LE(_field8); - s.syncAsSint16LE(_field16); + s.syncAsSint16LE(_exitMode); + s.syncAsSint16LE(_speakerMode); + + for (int i = 0; i < 11; ++i) + s.syncAsSint16LE(_field16[i]); } } @@ -632,6 +648,7 @@ void StripManager::reset() { _activeSpeaker = NULL; _textShown = false; _callbackObject = NULL; + _exitMode = 0; _obj44List.clear(); if (!_script.empty()) { @@ -679,6 +696,8 @@ void StripManager::synchronize(Serializer &s) { s.syncAsByte(_textShown); s.syncAsByte(_field2E6); s.syncAsSint32LE(_field2E8); + if (g_vm->getGameID() == GType_Ringworld2) + s.syncAsSint16LE(_exitMode); // Synchronize the item list int arrSize = _obj44List.size(); @@ -708,14 +727,24 @@ void StripManager::synchronize(Serializer &s) { } void StripManager::remove() { + if (g_vm->getGameID() == GType_Ringworld2) { + for (uint i = 0; i < _speakerList.size(); ++i) { + if (_activeSpeaker != _speakerList[i]) + _speakerList[i]->proc16(); + } + } + if (_textShown) { if (_activeSpeaker) _activeSpeaker->removeText(); _textShown = false; } - if (_activeSpeaker) + if (_activeSpeaker) { + if (g_vm->getGameID() == GType_Ringworld2) + static_cast<Ringworld2::VisualSpeaker *>(_activeSpeaker)->_speakerMode = 0xff; _activeSpeaker->remove(); + } if (_sceneNumber != g_globals->_sceneManager._scene->_screenNumber) { g_globals->_sceneManager._scene->_sceneBounds = _sceneBounds; @@ -725,10 +754,15 @@ void StripManager::remove() { if (_onEnd) _onEnd(); + if (g_vm->getGameID() == GType_Ringworld2) + _endHandler = NULL; + Action::remove(); } void StripManager::signal() { + int strIndex = 0; + if (_textShown) { _activeSpeaker->removeText(); _textShown = false; @@ -760,12 +794,10 @@ void StripManager::signal() { Obj44 &obj44 = _obj44List[_obj44Index]; - if (g_vm->getGameID() != GType_Ringworld2) { - _field2E8 = obj44._id; - } else { + if (g_vm->getGameID() == GType_Ringworld2) { // Return to Ringworld specific handling - if (obj44._field6) - _field2E8 = obj44._field6; + if (obj44._exitMode) + _exitMode = obj44._exitMode; switch (obj44._mode) { case 1: @@ -781,40 +813,91 @@ void StripManager::signal() { break; } } - + + _field2E8 = obj44._id; Common::StringArray choiceList; // Build up a list of script entries int idx; + bool delayFlag = false; - if (g_vm->getGameID() == GType_Ringworld2 && obj44._field16) { + if ((g_vm->getGameID() == GType_Ringworld2) && obj44._field16[0]) { // Special loading mode used in Return to Ringworld for (idx = 0; idx < OBJ44_LIST_SIZE; ++idx) { - int objIndex = _lookupList[obj44._field16 - 1]; - - if (!obj44._list[objIndex]._id) + int f16Index = _lookupList[obj44._field16[0] - 1]; + int entryId = obj44._field16[f16Index]; + + Obj0A &entry = obj44._list[idx]; + if (entry._id == entryId) { + // Get the next one + choiceList.push_back((const char *)&_script[0] + entry._scriptOffset); + strIndex = idx; + delayFlag = true; break; - - // Get the next one - choiceList.push_back((const char *)&_script[0] + obj44._list[objIndex]._scriptOffset); + } } } else { // Standard choices loading - for (idx = 0; idx < OBJ44_LIST_SIZE; ++idx) { + for (idx = 0; idx < OBJ0A_LIST_SIZE; ++idx) { if (!obj44._list[idx]._id) break; // Get the next one - choiceList.push_back((const char *)&_script[0] + obj44._list[idx]._scriptOffset); + const char *choiceStr = (const char *)&_script[0] + obj44._list[idx]._scriptOffset; + + if (!*choiceStr) { + // Choice is empty + assert(g_vm->getGameID() == GType_Ringworld2); + + if (obj44._list[1]._id) { + // it's a reference to another list slot + int listId = obj44._list[idx]._id; + + int obj44Idx = 0; + while (_obj44List[obj44Idx]._id != listId) + ++obj44Idx; + + if (_obj44List[obj44Idx]._field16[0]) { + // WORKAROUND: The _lookupList isn't always correctly initialised. But it always + // seems to be set to the R2_GLOBALS._stripManager_lookupList, so manually set it + if (!_lookupList) + _lookupList = R2_GLOBALS._stripManager_lookupList; + + int f16Index = _lookupList[_obj44List[obj44Idx]._field16[0] - 1]; + listId = _obj44List[obj44Idx]._field16[f16Index]; + + if (_lookupList[_obj44List[obj44Idx]._field16[0] - 1]) { + int listIdx = 0; + while (_obj44List[obj44Idx]._list[listIdx]._id != listId) + ++listIdx; + + choiceStr = (const char *)&_script[0] + _obj44List[obj44Idx]._list[listIdx]._scriptOffset; + } else { + for (int listIdx = idx; listIdx < (OBJ0A_LIST_SIZE - 1); ++listIdx) { + obj44._list[listIdx]._id = obj44._list[listIdx + 1]._id; + obj44._list[listIdx]._scriptOffset = obj44._list[listIdx + 1]._scriptOffset; + + if (!obj44._list[listIdx + 1]._id) + obj44._list[listIdx]._id = 0; + } + + --idx; + continue; + } + } + } + } + + // Add entry to the list + choiceList.push_back(choiceStr); } } - int strIndex = 0; if (choiceList.size() > 1) // Get the user to select a conversation option strIndex = _choiceDialog.execute(choiceList); - if ((choiceList.size() != 1) && !_field2E6) + if ((delayFlag || choiceList.size() != 1) && !_field2E6) _delayFrames = 1; else { Speaker *speakerP = getSpeaker((const char *)&_script[0] + obj44._speakerOffset); @@ -843,11 +926,28 @@ void StripManager::signal() { } } - if ((g_vm->getGameID() == GType_Ringworld2) && (_obj44List.size() > 0)) - static_cast<Ringworld2::VisualSpeaker *>(_activeSpeaker)->proc15(); + if (g_vm->getGameID() == GType_Ringworld2) { + Ringworld2::VisualSpeaker *speaker = static_cast<Ringworld2::VisualSpeaker *>(_activeSpeaker); + + if (speaker) { + speaker->_speakerMode = obj44._speakerMode; + if (!choiceList[strIndex].empty()) + speaker->proc15(); + } - _textShown = true; - _activeSpeaker->setText(choiceList[strIndex]); + if (!choiceList[strIndex].empty()) { + _textShown = true; + _activeSpeaker->setText(choiceList[strIndex]); + } else if (!obj44._speakerMode) { + _delayFrames = 1; + } else { + _delayFrames = 0; + speaker->proc15(); + } + } else { + _textShown = true; + _activeSpeaker->setText(choiceList[strIndex]); + } } _obj44Index = getNewIndex(obj44._list[strIndex]._id); @@ -915,6 +1015,8 @@ Speaker *StripManager::getSpeaker(const char *speakerName) { int StripManager::getNewIndex(int id) { if (id == 10000) return id; + if ((g_vm->getGameID() == GType_Ringworld2) && (id < 0)) + return id; for (uint idx = 0; idx < _obj44List.size(); ++idx) { if (_obj44List[idx]._id == id) { diff --git a/engines/tsage/converse.h b/engines/tsage/converse.h index 0c4eb9539d..5aef0d8a7f 100644 --- a/engines/tsage/converse.h +++ b/engines/tsage/converse.h @@ -94,6 +94,7 @@ public: virtual void proc12(Action *action); virtual void setText(const Common::String &msg); virtual void removeText(); + virtual void proc16() {} void setTextPos(const Common::Point &pt) { _textPos = pt; } }; @@ -145,6 +146,10 @@ public: }; class ConversationChoiceDialog : public ModalDialog { +private: + int textLeft() const; + int textMaxWidth() const; + int numberLeft() const; public: int _stdColor; int _highlightColor; @@ -189,8 +194,9 @@ public: // Return to Ringworld specific field int _mode; - int _lookupValue, _lookupIndex, _field6; - int _field8, _field16; + int _lookupValue, _lookupIndex, _exitMode; + int _speakerMode; + int _field16[11]; public: void load(const byte *dataP); virtual void synchronize(Serializer &s); @@ -217,6 +223,7 @@ public: bool _textShown; bool _field2E6; int _field2E8; + int _exitMode; Common::Array<Obj44> _obj44List; Common::Array<byte> _script; StripProc _onBegin; diff --git a/engines/tsage/core.cpp b/engines/tsage/core.cpp index 4a90e23a33..6b4e2963a5 100644 --- a/engines/tsage/core.cpp +++ b/engines/tsage/core.cpp @@ -2468,10 +2468,10 @@ void SceneObject::postInit(SceneObjectList *OwnerList) { if (!OwnerList) OwnerList = g_globals->_sceneObjects; - if (!OwnerList->contains(this)) { + if (!OwnerList->contains(this) || ((_flags & OBJFLAG_REMOVE) != 0)) { _percent = 100; _priority = 255; - _flags = 4; + _flags = OBJFLAG_ZOOMED; _visage = 0; _strip = 1; _frame = 1; @@ -2724,7 +2724,9 @@ void SceneObject::setup(int visage, int stripFrameNum, int frameNum, int posX, i } void SceneObject::setup(int visage, int stripFrameNum, int frameNum) { - postInit(); + if (g_vm->getGameID() != GType_Ringworld2) + postInit(); + setVisage(visage); setStrip(stripFrameNum); setFrame(frameNum); @@ -2760,8 +2762,8 @@ void BackgroundSceneObject::setup2(int visage, int stripFrameNum, int frameNum, fixPriority(priority); } -void BackgroundSceneObject::proc27() { - warning("STUB: BackgroundSceneObject::proc27()"); +void BackgroundSceneObject::copySceneToBackground() { + GLOBALS._sceneManager._scene->_backSurface.copyFrom(g_globals->gfxManager().getSurface(), 0, 0); } /*--------------------------------------------------------------------------*/ @@ -3103,6 +3105,7 @@ Visage::Visage() { _rlbNum = -1; _data = NULL; _flipHoriz = false; + _flipVert = false; } Visage::Visage(const Visage &v) { @@ -3112,6 +3115,7 @@ Visage::Visage(const Visage &v) { if (_data) g_vm->_memoryManager.incLocks(_data); _flipHoriz = false; + _flipVert = false; } Visage &Visage::operator=(const Visage &s) { @@ -3155,8 +3159,11 @@ void Visage::setVisage(int resNum, int rlbNum) { rlbNum = (int)(v & 0xff); } _flipHoriz = flags & 1; + _flipVert = flags & 2; _data = g_resourceManager->getResource(RES_VISAGE, resNum, rlbNum); + + DEALLOCATE(indexData); } } @@ -3179,7 +3186,9 @@ GfxSurface Visage::getFrame(int frameNum) { byte *frameData = _data + offset; GfxSurface result = surfaceFromRes(frameData); - if (_flipHoriz) flip(result); + if (_flipHoriz) flipHorizontal(result); + if (_flipVert) flipVertical(result); + return result; } @@ -3187,7 +3196,7 @@ int Visage::getFrameCount() const { return READ_LE_UINT16(_data); } -void Visage::flip(GfxSurface &gfxSurface) { +void Visage::flipHorizontal(GfxSurface &gfxSurface) { Graphics::Surface s = gfxSurface.lockSurface(); for (int y = 0; y < s.h; ++y) { @@ -3200,6 +3209,21 @@ void Visage::flip(GfxSurface &gfxSurface) { gfxSurface.unlockSurface(); } +void Visage::flipVertical(GfxSurface &gfxSurface) { + Graphics::Surface s = gfxSurface.lockSurface(); + + for (int y = 0; y < s.h / 2; ++y) { + // Flip the lines1 + byte *line1P = (byte *)s.getBasePtr(0, y); + byte *line2P = (byte *)s.getBasePtr(0, s.h - y - 1); + + for (int x = 0; x < s.w; ++x) + SWAP(line1P[x], line2P[x]); + } + + gfxSurface.unlockSurface(); +} + /*--------------------------------------------------------------------------*/ Player::Player(): SceneObject() { @@ -4267,10 +4291,15 @@ void SceneHandler::dispatch() { GUIErrorMessage(SAVE_ERROR_MSG); } if (_loadGameSlot != -1) { + int priorSceneBeforeLoad = GLOBALS._sceneManager._previousScene; + int currentSceneBeforeLoad = GLOBALS._sceneManager._sceneNumber; + int loadSlot = _loadGameSlot; _loadGameSlot = -1; g_saver->restore(loadSlot); g_globals->_events.setCursorFromFlag(); + + postLoad(priorSceneBeforeLoad, currentSceneBeforeLoad); } g_globals->_soundManager.dispatch(); diff --git a/engines/tsage/core.h b/engines/tsage/core.h index 296754011e..f7a5a43b16 100644 --- a/engines/tsage/core.h +++ b/engines/tsage/core.h @@ -472,11 +472,13 @@ class Visage { private: byte *_data; - void flip(GfxSurface &s); + void flipHorizontal(GfxSurface &s); + void flipVertical(GfxSurface &s); public: int _resNum; int _rlbNum; bool _flipHoriz; + bool _flipVert; public: Visage(); Visage(const Visage &v); @@ -611,7 +613,7 @@ public: virtual void postInit(SceneObjectList *OwnerList = NULL); virtual void draw(); void setup2(int visage, int stripFrameNum, int frameNum, int posX, int posY, int priority, int32 arg10); - void proc27(); + static void copySceneToBackground(); }; class SceneText : public SceneObject { @@ -898,6 +900,7 @@ public: protected: virtual void playerAction(Event &event) {} virtual void processEnd(Event &event) {} + virtual void postLoad(int priorSceneBeforeLoad, int currentSceneBeforeLoad) {} public: SceneHandler(); void registerHandler(); diff --git a/engines/tsage/dialogs.cpp b/engines/tsage/dialogs.cpp index 77ac0a25d7..43833f53b9 100644 --- a/engines/tsage/dialogs.cpp +++ b/engines/tsage/dialogs.cpp @@ -137,43 +137,47 @@ void ModalDialog::drawFrame() { Rect origRect = _bounds; _bounds.collapse(-10, -10); - // Fill the dialog area - g_globals->gfxManager().fillRect(origRect, 54); - - // Draw top line - GfxSurface surface = surfaceFromRes(8, 1, 7); - for (int xp = _bounds.left + 10; xp < (_bounds.right - 20); xp += 10) - surface.draw(Common::Point(xp, _bounds.top)); - surface.draw(Common::Point(_bounds.right - 20, _bounds.top)); - - surface = surfaceFromRes(8, 1, 1); - surface.draw(Common::Point(_bounds.left, _bounds.top)); - - surface = surfaceFromRes(8, 1, 4); - surface.draw(Common::Point(_bounds.right - 10, _bounds.top)); - - // Draw vertical edges - surface = surfaceFromRes(8, 1, 2); - for (int yp = _bounds.top + 10; yp < (_bounds.bottom - 20); yp += 10) - surface.draw(Common::Point(_bounds.left, yp)); - surface.draw(Common::Point(_bounds.left, _bounds.bottom - 20)); - - surface = surfaceFromRes(8, 1, 5); - for (int yp = _bounds.top + 10; yp < (_bounds.bottom - 20); yp += 10) - surface.draw(Common::Point(_bounds.right - 10, yp)); - surface.draw(Common::Point(_bounds.right - 10, _bounds.bottom - 20)); - - // Draw bottom line - surface = surfaceFromRes(8, 1, 8); - for (int xp = _bounds.left + 10; xp < (_bounds.right - 20); xp += 10) - surface.draw(Common::Point(xp, _bounds.bottom - 10)); - surface.draw(Common::Point(_bounds.right - 20, _bounds.bottom - 10)); - - surface = surfaceFromRes(8, 1, 3); - surface.draw(Common::Point(_bounds.left, _bounds.bottom - 10)); - - surface = surfaceFromRes(8, 1, 6); - surface.draw(Common::Point(_bounds.right - 10, _bounds.bottom - 10)); + if (g_vm->getGameID() == GType_Ringworld2) { + GfxElement::drawFrame(); + } else { + // Fill the dialog area + g_globals->gfxManager().fillRect(origRect, 54); + + // Draw top line + GfxSurface surface = surfaceFromRes(8, 1, 7); + for (int xp = _bounds.left + 10; xp < (_bounds.right - 20); xp += 10) + surface.draw(Common::Point(xp, _bounds.top)); + surface.draw(Common::Point(_bounds.right - 20, _bounds.top)); + + surface = surfaceFromRes(8, 1, 1); + surface.draw(Common::Point(_bounds.left, _bounds.top)); + + surface = surfaceFromRes(8, 1, 4); + surface.draw(Common::Point(_bounds.right - 10, _bounds.top)); + + // Draw vertical edges + surface = surfaceFromRes(8, 1, 2); + for (int yp = _bounds.top + 10; yp < (_bounds.bottom - 20); yp += 10) + surface.draw(Common::Point(_bounds.left, yp)); + surface.draw(Common::Point(_bounds.left, _bounds.bottom - 20)); + + surface = surfaceFromRes(8, 1, 5); + for (int yp = _bounds.top + 10; yp < (_bounds.bottom - 20); yp += 10) + surface.draw(Common::Point(_bounds.right - 10, yp)); + surface.draw(Common::Point(_bounds.right - 10, _bounds.bottom - 20)); + + // Draw bottom line + surface = surfaceFromRes(8, 1, 8); + for (int xp = _bounds.left + 10; xp < (_bounds.right - 20); xp += 10) + surface.draw(Common::Point(xp, _bounds.bottom - 10)); + surface.draw(Common::Point(_bounds.right - 20, _bounds.bottom - 10)); + + surface = surfaceFromRes(8, 1, 3); + surface.draw(Common::Point(_bounds.left, _bounds.bottom - 10)); + + surface = surfaceFromRes(8, 1, 6); + surface.draw(Common::Point(_bounds.right - 10, _bounds.bottom - 10)); + } // Set the dialog's manager bounds _gfxManager._bounds = origRect; diff --git a/engines/tsage/events.cpp b/engines/tsage/events.cpp index 8f07a8243b..5ca531fdb9 100644 --- a/engines/tsage/events.cpp +++ b/engines/tsage/events.cpp @@ -277,7 +277,7 @@ void EventsClass::setCursor(CursorType cursorType) { GfxSurface s = surfaceFromRes(cursor); Graphics::Surface surface = s.lockSurface(); - const byte *cursorData = (const byte *)surface.getBasePtr(0, 0); + const byte *cursorData = (const byte *)surface.getPixels(); CursorMan.replaceCursor(cursorData, surface.w, surface.h, s._centroid.x, s._centroid.y, s._transColor); s.unlockSurface(); @@ -333,7 +333,7 @@ void EventsClass::pushCursor(CursorType cursorType) { GfxSurface s = surfaceFromRes(cursor); Graphics::Surface surface = s.lockSurface(); - const byte *cursorData = (const byte *)surface.getBasePtr(0, 0); + const byte *cursorData = (const byte *)surface.getPixels(); CursorMan.pushCursor(cursorData, surface.w, surface.h, s._centroid.x, s._centroid.y, s._transColor); s.unlockSurface(); @@ -346,7 +346,7 @@ void EventsClass::popCursor() { } void EventsClass::setCursor(Graphics::Surface &cursor, int transColor, const Common::Point &hotspot, CursorType cursorId) { - const byte *cursorData = (const byte *)cursor.getBasePtr(0, 0); + const byte *cursorData = (const byte *)cursor.getPixels(); CursorMan.replaceCursor(cursorData, cursor.w, cursor.h, hotspot.x, hotspot.y, transColor); _currentCursor = cursorId; @@ -355,7 +355,7 @@ void EventsClass::setCursor(Graphics::Surface &cursor, int transColor, const Com void EventsClass::setCursor(GfxSurface &cursor) { Graphics::Surface s = cursor.lockSurface(); - const byte *cursorData = (const byte *)s.getBasePtr(0, 0); + const byte *cursorData = (const byte *)s.getPixels(); CursorMan.replaceCursor(cursorData, cursor.getBounds().width(), cursor.getBounds().height(), cursor._centroid.x, cursor._centroid.y, cursor._transColor); diff --git a/engines/tsage/globals.cpp b/engines/tsage/globals.cpp index 4589a926c9..5c4fa967e5 100644 --- a/engines/tsage/globals.cpp +++ b/engines/tsage/globals.cpp @@ -3,7 +3,7 @@ * 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 @@ -366,30 +366,47 @@ bool BlueForceGlobals::removeFlag(int flagNum) { namespace Ringworld2 { +Ringworld2Globals::Ringworld2Globals() { + _scannerDialog = new ScannerDialog(); +} + +Ringworld2Globals::~Ringworld2Globals() { + delete _scannerDialog; +} + void Ringworld2Globals::reset() { Globals::reset(); + if (!_scannerDialog) + _scannerDialog = new ScannerDialog(); + // Reset the inventory R2_INVENTORY.reset(); T2_GLOBALS._uiElements.updateInventory(); T2_GLOBALS._uiElements._active = false; + // Set the screen to track the player + _scrollFollower = &_player; + // Reset fields - Common::fill(&_v1000[0], &_v1000[0x1000], 0); - _v1000Flag = false; + Common::fill(&_fadePaletteMap[0][0], &_fadePaletteMap[10][256], 0); + Common::fill(&_paletteMap[0], &_paletteMap[4096], 0); + + _fadePaletteFlag = false; _v5589E.set(0, 0, 0, 0); _v558B6.set(0, 0, 0, 0); _v558C2 = 0; _animationCtr = 0; _v5657C = 0; - _v565E1 = 0; - _v565E3 = 0; + _electromagnetChangeAmount = 0; + _electromagnetZoom = 0; _v565E5 = 0; _v565E7 = 0; _v565E9 = -5; _v565EB = 26; _v565F5 = 0; _v565F6 = 0; + _v565F8 = 0; _v565FA = 0; _v565AE = 0; _v56605[0] = 0; @@ -463,7 +480,7 @@ void Ringworld2Globals::reset() { _v565EC[2] = 27; _v565EC[3] = 4; _v565EC[4] = 4; - Common::fill(&_v565F1[0], &_v565F1[MAX_CHARACTERS], 1); + Common::fill(&_scannerFrequencies[0], &_scannerFrequencies[MAX_CHARACTERS], 1); _speechSubtitles = SPEECH_VOICE | SPEECH_TEXT; _insetUp = 0; _frameEdgeColour = 2; @@ -496,14 +513,15 @@ void Ringworld2Globals::synchronize(Serializer &s) { s.syncAsSint16LE(_v558C2); s.syncAsSint16LE(_animationCtr); s.syncAsSint16LE(_v5657C); - s.syncAsSint16LE(_v565E1); - s.syncAsSint16LE(_v565E3); + s.syncAsSint16LE(_electromagnetChangeAmount); + s.syncAsSint16LE(_electromagnetZoom); s.syncAsSint16LE(_v565E5); s.syncAsSint16LE(_v565E7); s.syncAsSint16LE(_v565E9); s.syncAsSint16LE(_v565EB); s.syncAsSint16LE(_v565F5); s.syncAsSint16LE(_v565F6); + s.syncAsSint16LE(_v565F8); s.syncAsSint16LE(_v565FA); s.syncAsSint16LE(_v566A3); s.syncAsSint16LE(_v566A6); @@ -525,7 +543,7 @@ void Ringworld2Globals::synchronize(Serializer &s) { s.syncAsByte(_v565EC[i]); for (i = 0; i < MAX_CHARACTERS; ++i) - s.syncAsByte(_v565F1[i]); + s.syncAsByte(_scannerFrequencies[i]); s.syncAsByte(_v565AE); s.syncAsByte(_v566A4); diff --git a/engines/tsage/globals.h b/engines/tsage/globals.h index d190b6a2a4..ed27ff0556 100644 --- a/engines/tsage/globals.h +++ b/engines/tsage/globals.h @@ -247,28 +247,31 @@ namespace Ringworld2 { #define k5A790 18 #define k5A791 17 +class ScannerDialog; + class Ringworld2Globals: public TsAGE2Globals { public: ASoundExt _sound1, _sound2, _sound3, _sound4; PlayStream _playStream; StripProxy _stripProxy; - bool _v1000Flag; - byte _v1000[0x1000]; - byte _palIndexList[10][256]; + bool _fadePaletteFlag; + byte _fadePaletteMap[10][256]; + byte _paletteMap[4096]; int _insetUp; int _frameEdgeColour; // _v421e Rect _v5589E; Rect _v558B6; int _v558C2; int _animationCtr; - int _v565E1; - int _v565E3; + int _electromagnetChangeAmount; + int _electromagnetZoom; int _v565E5; int _v565E7; int _v565E9; int _v565EB; int _v565F5; int _v565F6; + int _v565F8; int _v565FA; int _v5657C; byte _v565AE; @@ -302,9 +305,12 @@ public: int _v57C2C; int _speechSubtitles; byte _v565EC[5]; - byte _v565F1[4]; + byte _scannerFrequencies[4]; byte _stripManager_lookupList[12]; + ScannerDialog *_scannerDialog; + Ringworld2Globals(); + virtual ~Ringworld2Globals(); virtual void reset(); virtual void synchronize(Serializer &s); }; diff --git a/engines/tsage/graphics.cpp b/engines/tsage/graphics.cpp index fb0b0b0cbb..1815c3d751 100644 --- a/engines/tsage/graphics.cpp +++ b/engines/tsage/graphics.cpp @@ -47,7 +47,7 @@ GfxSurface *surfaceGetArea(GfxSurface &src, const Rect &bounds) { Graphics::Surface destSurface = dest->lockSurface(); byte *srcP = (byte *)srcSurface.getBasePtr(bounds.left, bounds.top); - byte *destP = (byte *)destSurface.getBasePtr(0, 0); + byte *destP = (byte *)destSurface.getPixels(); for (int y = bounds.top; y < bounds.bottom; ++y, srcP += srcSurface.pitch, destP += destSurface.pitch) Common::copy(srcP, srcP + destSurface.pitch, destP); @@ -76,7 +76,7 @@ GfxSurface surfaceFromRes(const byte *imgData) { const byte *srcP = imgData + 10; Graphics::Surface destSurface = s.lockSurface(); - byte *destP = (byte *)destSurface.getBasePtr(0, 0); + byte *destP = (byte *)destSurface.getPixels(); if (!rleEncoded) { Common::copy(srcP, srcP + (r.width() * r.height()), destP); @@ -234,9 +234,14 @@ GfxSurface::GfxSurface(const GfxSurface &s) { } GfxSurface::~GfxSurface() { + clear(); +} + +void GfxSurface::clear() { if (_customSurface) { _customSurface->free(); delete _customSurface; + _customSurface = NULL; } } @@ -289,8 +294,11 @@ void GfxSurface::addDirtyRect(const Rect &r) { r2.translate(_bounds.left, _bounds.top); // Add to the dirty rect list - _dirtyRects.push_back(Rect(r2.left, r2.top, - MIN(r2.right + 1, SCREEN_WIDTH), MIN(r2.bottom + 1, SCREEN_HEIGHT))); + r2.right = MIN(r2.right + 1, SCREEN_WIDTH); + r2.bottom = MIN(r2.bottom + 1, SCREEN_HEIGHT); + + if (r2.isValidRect()) + _dirtyRects.push_back(r2); } } @@ -308,7 +316,7 @@ void GfxSurface::create(int width, int height) { } _customSurface = new Graphics::Surface(); _customSurface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); - Common::fill((byte *)_customSurface->pixels, (byte *)_customSurface->pixels + (width * height), 0); + Common::fill((byte *)_customSurface->getPixels(), (byte *)_customSurface->getBasePtr(0, height), 0); _bounds = Rect(0, 0, width, height); } @@ -324,12 +332,7 @@ Graphics::Surface GfxSurface::lockSurface() { // Setup the returned surface either as one pointing to the same pixels as the source, or // as a subset of the source one based on the currently set bounds Graphics::Surface result; - result.w = _bounds.width(); - result.h = _bounds.height(); - result.pitch = src->pitch; - result.format = src->format; - result.pixels = src->getBasePtr(_bounds.left, _bounds.top); - + result.init(_bounds.width(), _bounds.height(), src->pitch, src->getBasePtr(_bounds.left, _bounds.top), src->format); return result; } @@ -355,7 +358,7 @@ void GfxSurface::synchronize(Serializer &s) { if (_customSurface) { s.syncAsSint16LE(_customSurface->w); s.syncAsSint16LE(_customSurface->h); - s.syncBytes((byte *)_customSurface->pixels, _customSurface->w * _customSurface->h); + s.syncBytes((byte *)_customSurface->getPixels(), _customSurface->w * _customSurface->h); } else { int zero = 0; s.syncAsSint16LE(zero); @@ -372,7 +375,7 @@ void GfxSurface::synchronize(Serializer &s) { _customSurface = NULL; } else { create(w, h); - s.syncBytes((byte *)_customSurface->pixels, w * h); + s.syncBytes((byte *)_customSurface->getPixels(), w * h); } } } @@ -409,8 +412,8 @@ GfxSurface &GfxSurface::operator=(const GfxSurface &s) { // Surface owns the internal data, so replicate it so new surface owns it's own _customSurface = new Graphics::Surface(); _customSurface->create(s._customSurface->w, s._customSurface->h, Graphics::PixelFormat::createFormatCLUT8()); - const byte *srcP = (const byte *)s._customSurface->getBasePtr(0, 0); - byte *destP = (byte *)_customSurface->getBasePtr(0, 0); + const byte *srcP = (const byte *)s._customSurface->getPixels(); + byte *destP = (byte *)_customSurface->getPixels(); Common::copy(srcP, srcP + (_bounds.width() * _bounds.height()), destP); } @@ -573,7 +576,7 @@ void GfxSurface::copyFrom(GfxSurface &src, Rect srcBounds, Rect destBounds, Regi Graphics::Surface destSurface = srcImage.lockSurface(); const byte *srcP = (const byte *)srcSurface.getBasePtr(srcBounds.left, srcBounds.top); - byte *destP = (byte *)destSurface.pixels; + byte *destP = (byte *)destSurface.getPixels(); for (int yp = srcBounds.top; yp < srcBounds.bottom; ++yp, srcP += srcSurface.pitch, destP += destSurface.pitch) { Common::copy(srcP, srcP + srcBounds.width(), destP); } @@ -790,35 +793,58 @@ void GfxElement::drawFrame() { lineP++; } } + + // Draw the edge frame + // Outer frame border + surface.hLine(tempRect.left + 2, tempRect.top, tempRect.right - 2, 0); + surface.hLine(tempRect.left + 2, tempRect.bottom, tempRect.right - 2, 0); + surface.vLine(tempRect.left, tempRect.top + 2, tempRect.bottom - 2, 0); + surface.vLine(tempRect.right, tempRect.top + 2, tempRect.bottom - 2, 0); + *((byte *)surface.getBasePtr(tempRect.left + 1, tempRect.top + 1)) = 0; + *((byte *)surface.getBasePtr(tempRect.right - 1, tempRect.top + 1)) = 0; + *((byte *)surface.getBasePtr(tempRect.left + 1, tempRect.bottom - 1)) = 0; + *((byte *)surface.getBasePtr(tempRect.right - 1, tempRect.bottom - 1)) = 0; + + // Inner frame border + surface.hLine(tempRect.left + 2, tempRect.top + 1, tempRect.right - 2, R2_GLOBALS._frameEdgeColour); + surface.hLine(tempRect.left + 2, tempRect.bottom - 1, tempRect.right - 2, R2_GLOBALS._frameEdgeColour); + surface.vLine(tempRect.left + 1, tempRect.top + 2, tempRect.bottom - 2, R2_GLOBALS._frameEdgeColour); + surface.vLine(tempRect.right - 1, tempRect.top + 2, tempRect.bottom - 2, R2_GLOBALS._frameEdgeColour); + *((byte *)surface.getBasePtr(tempRect.left + 2, tempRect.top + 2)) = R2_GLOBALS._frameEdgeColour; + *((byte *)surface.getBasePtr(tempRect.right - 2, tempRect.top + 2)) = R2_GLOBALS._frameEdgeColour; + *((byte *)surface.getBasePtr(tempRect.left + 2, tempRect.bottom - 2)) = R2_GLOBALS._frameEdgeColour; + *((byte *)surface.getBasePtr(tempRect.right - 2, tempRect.bottom - 2)) = R2_GLOBALS._frameEdgeColour; + gfxManager.unlockSurface(); + gfxManager.getSurface().addDirtyRect(tempRect); } else { // Fill dialog content with specified background colour gfxManager.fillRect(tempRect, _colors.background); - } - --tempRect.bottom; --tempRect.right; - gfxManager.fillArea(tempRect.left, tempRect.top, bgColor); - gfxManager.fillArea(tempRect.left, tempRect.bottom, fgColor); - gfxManager.fillArea(tempRect.right, tempRect.top, fgColor); - gfxManager.fillArea(tempRect.right, tempRect.bottom, fgColor); - - tempRect.collapse(-1, -1); - gfxManager.fillRect2(tempRect.left + 1, tempRect.top, tempRect.width() - 1, 1, bgColor); - gfxManager.fillRect2(tempRect.left, tempRect.top + 1, 1, tempRect.height() - 1, bgColor); - gfxManager.fillRect2(tempRect.left + 1, tempRect.bottom, tempRect.width() - 1, 1, fgColor); - gfxManager.fillRect2(tempRect.right, tempRect.top + 1, 1, tempRect.height() - 1, fgColor); - - gfxManager.fillArea(tempRect.left, tempRect.top, 0); - gfxManager.fillArea(tempRect.left, tempRect.bottom, 0); - gfxManager.fillArea(tempRect.right, tempRect.top, 0); - gfxManager.fillArea(tempRect.right, tempRect.bottom, 0); - - tempRect.collapse(-1, -1); - gfxManager.fillRect2(tempRect.left + 2, tempRect.top, tempRect.width() - 3, 1, 0); - gfxManager.fillRect2(tempRect.left, tempRect.top + 2, 1, tempRect.height() - 3, 0); - gfxManager.fillRect2(tempRect.left + 2, tempRect.bottom, tempRect.width() - 3, 1, 0); - gfxManager.fillRect2(tempRect.right, tempRect.top + 2, 1, tempRect.height() - 3, 0); + --tempRect.bottom; --tempRect.right; + gfxManager.fillArea(tempRect.left, tempRect.top, bgColor); + gfxManager.fillArea(tempRect.left, tempRect.bottom, fgColor); + gfxManager.fillArea(tempRect.right, tempRect.top, fgColor); + gfxManager.fillArea(tempRect.right, tempRect.bottom, fgColor); + + tempRect.collapse(-1, -1); + gfxManager.fillRect2(tempRect.left + 1, tempRect.top, tempRect.width() - 1, 1, bgColor); + gfxManager.fillRect2(tempRect.left, tempRect.top + 1, 1, tempRect.height() - 1, bgColor); + gfxManager.fillRect2(tempRect.left + 1, tempRect.bottom, tempRect.width() - 1, 1, fgColor); + gfxManager.fillRect2(tempRect.right, tempRect.top + 1, 1, tempRect.height() - 1, fgColor); + + gfxManager.fillArea(tempRect.left, tempRect.top, 0); + gfxManager.fillArea(tempRect.left, tempRect.bottom, 0); + gfxManager.fillArea(tempRect.right, tempRect.top, 0); + gfxManager.fillArea(tempRect.right, tempRect.bottom, 0); + + tempRect.collapse(-1, -1); + gfxManager.fillRect2(tempRect.left + 2, tempRect.top, tempRect.width() - 3, 1, 0); + gfxManager.fillRect2(tempRect.left, tempRect.top + 2, 1, tempRect.height() - 3, 0); + gfxManager.fillRect2(tempRect.left + 2, tempRect.bottom, tempRect.width() - 3, 1, 0); + gfxManager.fillRect2(tempRect.right, tempRect.top + 2, 1, tempRect.height() - 3, 0); + } gfxManager.unlockSurface(); } @@ -1322,6 +1348,12 @@ void GfxManager::copyFrom(GfxSurface &src, int destX, int destY) { _surface.copyFrom(src, destX, destY); } +void GfxManager::copyFrom(GfxSurface &src, const Rect &srcBounds, const Rect &destBounds) { + _surface.setBounds(_bounds); + + _surface.copyFrom(src, srcBounds, destBounds); +} + /*--------------------------------------------------------------------------*/ diff --git a/engines/tsage/graphics.h b/engines/tsage/graphics.h index 826f2fef6f..7239a99a68 100644 --- a/engines/tsage/graphics.h +++ b/engines/tsage/graphics.h @@ -100,6 +100,7 @@ public: void unlockSurface(); void synchronize(Serializer &s); void create(int width, int height); + void clear(); void setBounds(const Rect &bounds) { _bounds = bounds; } const Rect &getBounds() const { return _bounds; } @@ -302,6 +303,7 @@ public: } void copyFrom(GfxSurface &src, Rect destBounds, Region *priorityRegion = NULL); void copyFrom(GfxSurface &src, int destX, int destY); + void copyFrom(GfxSurface &src, const Rect &srcBounds, const Rect &destBounds); GfxSurface &getSurface() { _surface.setBounds(_bounds); diff --git a/engines/tsage/ringworld/ringworld_scenes1.cpp b/engines/tsage/ringworld/ringworld_scenes1.cpp index 4d9d565705..89c07273fc 100644 --- a/engines/tsage/ringworld/ringworld_scenes1.cpp +++ b/engines/tsage/ringworld/ringworld_scenes1.cpp @@ -2273,6 +2273,7 @@ void Scene60::Item1::doAction(int action) { } else { scene->setAction(&scene->_action2); } + break; default: SceneHotspot::doAction(action); break; diff --git a/engines/tsage/ringworld2/ringworld2_dialogs.cpp b/engines/tsage/ringworld2/ringworld2_dialogs.cpp index 478fdcf5a5..57fdef6405 100644 --- a/engines/tsage/ringworld2/ringworld2_dialogs.cpp +++ b/engines/tsage/ringworld2/ringworld2_dialogs.cpp @@ -236,7 +236,7 @@ void CharacterDialog::show() { // Play a transition sound as the character is changed if (R2_GLOBALS._player._characterScene[0] != 300) { - switch (R2_GLOBALS._v565F1[R2_GLOBALS._player._characterIndex]) { + switch (R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex]) { case 0: R2_GLOBALS._sound4.stop(); break; @@ -255,8 +255,8 @@ void CharacterDialog::show() { default: break; } - } else if (R2_GLOBALS._v565F1[R2_GLOBALS._player._characterIndex] > 1) { - switch (R2_GLOBALS._v565F1[R2_GLOBALS._player._characterIndex]) { + } else if (R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex] > 1) { + switch (R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex]) { case 2: R2_GLOBALS._sound4.play(45); break; @@ -272,8 +272,8 @@ void CharacterDialog::show() { default: break; } - } else if ((R2_GLOBALS._player._characterScene[1] == 300) && (R2_GLOBALS._v565F1[1] != 1)) { - switch (R2_GLOBALS._v565F1[1]) { + } else if ((R2_GLOBALS._player._characterScene[1] == 300) && (R2_GLOBALS._scannerFrequencies[1] != 1)) { + switch (R2_GLOBALS._scannerFrequencies[1]) { case 2: R2_GLOBALS._sound4.play(45); break; @@ -291,10 +291,10 @@ void CharacterDialog::show() { } } else if (R2_GLOBALS._player._characterScene[2] != 300) { R2_GLOBALS._sound4.stop(); - } else if (R2_GLOBALS._v565F1[2] == 1) { + } else if (R2_GLOBALS._scannerFrequencies[2] == 1) { R2_GLOBALS._sound4.stop(); } else { - switch (R2_GLOBALS._v565F1[1]) { + switch (R2_GLOBALS._scannerFrequencies[1]) { case 2: R2_GLOBALS._sound4.play(45); break; diff --git a/engines/tsage/ringworld2/ringworld2_logic.cpp b/engines/tsage/ringworld2/ringworld2_logic.cpp index 97042cb621..2a8e50bd67 100644 --- a/engines/tsage/ringworld2/ringworld2_logic.cpp +++ b/engines/tsage/ringworld2/ringworld2_logic.cpp @@ -21,6 +21,8 @@ */ #include "common/config-manager.h" +#include "common/rect.h" +#include "tsage/graphics.h" #include "tsage/scenes.h" #include "tsage/tsage.h" #include "tsage/staticres.h" @@ -86,8 +88,10 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Cutscene - Walking in hall return new Scene525(); case 600: + // Drive Room return new Scene600(); case 700: + // Lander Bay 2 return new Scene700(); case 800: // Sick bay @@ -99,11 +103,13 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Deck #5 - By Lift return new Scene850(); case 900: + // Lander Bay 2 - Crane Controls return new Scene900(); /* Scene group #1 */ // case 1000: - error("Missing scene %d from group 1", sceneNumber); + // Cutscene scene + return new Scene1000(); case 1010: // Cutscene - trip in space return new Scene1010(); @@ -166,7 +172,7 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Ice Maze: Large empty room return new Scene2400(); case 2425: - // Ice Maze: + // Ice Maze: The Hall of Records return new Scene2425(); case 2430: // Ice Maze: Bedroom @@ -213,7 +219,7 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { case 2900: error("Missing scene %d from group 2", sceneNumber); /* Scene group #3 */ - // + // ARM Base Hanager case 3100: return new Scene3100(); case 3125: @@ -258,16 +264,22 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Cutscene - Ship landing return new Scene3350(); case 3375: + // Outer walkway return new Scene3375(); case 3385: + // Corridor return new Scene3385(); case 3395: + // Walkway return new Scene3395(); case 3400: + // Confrontation return new Scene3400(); case 3500: + // Maze action sequencec return new Scene3500(); case 3600: + // Cutscene - walking at gunpoint return new Scene3600(); case 3700: // Cutscene - Teleport outside @@ -311,6 +323,12 @@ SceneExt::SceneExt(): Scene() { _savedUiEnabled = false; _savedCanWalk = false; _focusObject = NULL; + + // WORKAROUND: In the original, playing animations don't reset the global _animationCtr + // counter as scene changes unless the playing animation explicitly finishes. For now, + // to make inter-scene debugging easier, I'm explicitly resetting the _animationCtr + // on scene start, since scene objects aren't drawn while it's non-zero + R2_GLOBALS._animationCtr = 0; } void SceneExt::postInit(SceneObjectList *OwnerList) { @@ -328,8 +346,7 @@ void SceneExt::postInit(SceneObjectList *OwnerList) { int sceneNumber = R2_GLOBALS._sceneManager._sceneNumber; if (((prevScene == -1) && (sceneNumber != 180) && (sceneNumber != 205) && (sceneNumber != 50)) || (sceneNumber == 50) - || ((prevScene == 205) && (sceneNumber == 100)) - || ((prevScene == 180) && (sceneNumber == 100))) { + || ((sceneNumber == 100) && (prevScene == 0 || prevScene == 180 || prevScene == 205))) { static_cast<SceneHandlerExt *>(R2_GLOBALS._sceneHandler)->setupPaletteMaps(); R2_GLOBALS._uiElements._active = true; R2_GLOBALS._uiElements.show(); @@ -341,6 +358,7 @@ void SceneExt::postInit(SceneObjectList *OwnerList) { void SceneExt::remove() { _sceneAreas.clear(); Scene::remove(); + R2_GLOBALS._uiElements._active = true; } void SceneExt::process(Event &event) { @@ -407,17 +425,19 @@ bool SceneExt::display(CursorType action, Event &event) { SceneItem::display2(5, 0); break; case R2_SONIC_STUNNER: - if ((R2_GLOBALS._v565F1[1] == 2) || ((R2_GLOBALS._v565F1[1] == 1) && - (R2_GLOBALS._v565F1[2] == 2) && (R2_GLOBALS._sceneManager._previousScene == 300))) { + if ((R2_GLOBALS._scannerFrequencies[R2_QUINN] == 2) + || ((R2_GLOBALS._scannerFrequencies[R2_QUINN] == 1) && + (R2_GLOBALS._scannerFrequencies[R2_SEEKER] == 2) && + (R2_GLOBALS._sceneManager._previousScene == 300))) { R2_GLOBALS._sound4.stop(); R2_GLOBALS._sound3.play(46); SceneItem::display2(5, 15); + + R2_GLOBALS._sound4.play(45); } else { R2_GLOBALS._sound3.play(43, 0); - SceneItem::display2(2, 0); + SceneItem::display2(2, R2_SONIC_STUNNER); } - - R2_GLOBALS._sound4.play(45); break; case R2_COM_SCANNER: case R2_COM_SCANNER_2: @@ -509,7 +529,7 @@ void SceneExt::refreshBackground(int xAmount, int yAmount) { assert(screenSize == (s.w * s.h)); // Copy the data - byte *destP = (byte *)s.getBasePtr(0, 0); + byte *destP = (byte *)s.getPixels(); Common::copy(dataP, dataP + (s.w * s.h), destP); _backSurface.unlockSurface(); @@ -557,6 +577,13 @@ void SceneExt::scalePalette(int RFactor, int GFactor, int BFactor) { } } +void SceneExt::loadBlankScene() { + _backSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT * 3 / 2); + _backSurface.fillRect(_backSurface.getBounds(), 0); + + R2_GLOBALS._screenSurface.fillRect(R2_GLOBALS._screenSurface.getBounds(), 0); +} + /*--------------------------------------------------------------------------*/ void SceneHandlerExt::postInit(SceneObjectList *OwnerList) { @@ -573,7 +600,7 @@ void SceneHandlerExt::process(Event &event) { SceneExt *scene = static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene); if (scene && R2_GLOBALS._player._uiEnabled) { // Handle any scene areas that have been registered - SynchronizedList<SceneArea *>::iterator saIter; + SynchronizedList<EventHandler *>::iterator saIter; for (saIter = scene->_sceneAreas.begin(); saIter != scene->_sceneAreas.end() && !event.handled; ++saIter) { (*saIter)->process(event); } @@ -583,11 +610,32 @@ void SceneHandlerExt::process(Event &event) { SceneHandler::process(event); } +void SceneHandlerExt::postLoad(int priorSceneBeforeLoad, int currentSceneBeforeLoad) { + if (priorSceneBeforeLoad == -1 || priorSceneBeforeLoad == 50 + || priorSceneBeforeLoad == 180 || priorSceneBeforeLoad == 205) + setupPaletteMaps(); + + if (currentSceneBeforeLoad == 2900) { + R2_GLOBALS._gfxFontNumber = 50; + R2_GLOBALS._gfxColors.background = 0; + R2_GLOBALS._gfxColors.foreground = 59; + R2_GLOBALS._fontColors.background = 4; + R2_GLOBALS._fontColors.foreground = 15; + R2_GLOBALS._frameEdgeColour = 2; + + R2_GLOBALS._scenePalette.loadPalette(0); + R2_GLOBALS._scenePalette.setEntry(255, 0xff, 0xff, 0xff); + R2_GLOBALS._fadePaletteFlag = false; + setupPaletteMaps(); + } +} + void SceneHandlerExt::setupPaletteMaps() { byte *palP = &R2_GLOBALS._scenePalette._palette[0]; - if (!R2_GLOBALS._v1000Flag) { - R2_GLOBALS._v1000Flag = true; + // Set up the mapping table for giving faded versions of pixels at different fade percentages + if (!R2_GLOBALS._fadePaletteFlag) { + R2_GLOBALS._fadePaletteFlag = true; for (int idx = 0; idx < 10; ++idx) { for (int palIndex = 0; palIndex < 224; ++palIndex) { @@ -637,18 +685,19 @@ void SceneHandlerExt::setupPaletteMaps() { foundIndex = pIndex2; } - R2_GLOBALS._palIndexList[idx][palIndex] = foundIndex; + R2_GLOBALS._fadePaletteMap[idx][palIndex] = foundIndex; } } } for (int palIndex = 0; palIndex < 224; ++palIndex) { - int r = palP[palIndex * 3] >> 2; - int g = palP[palIndex * 3 + 1] >> 2; - int b = palP[palIndex * 3 + 2] >> 2; + int r = palP[palIndex * 3] >> 4; + int g = palP[palIndex * 3 + 1] >> 4; + int b = palP[palIndex * 3 + 2] >> 4; - int idx = (((r << 4) | g) << 4) | b; - R2_GLOBALS._v1000[idx] = palIndex; + int v = (r << 8) | (g << 4) | b; + assert(v < 0x1000); + R2_GLOBALS._paletteMap[v] = palIndex; } int vdx = 0; @@ -656,9 +705,9 @@ void SceneHandlerExt::setupPaletteMaps() { int palIndex = 224; for (int vIndex = 0; vIndex < 4096; ++vIndex) { - int v = R2_GLOBALS._v1000[vIndex]; + int v = R2_GLOBALS._paletteMap[vIndex]; if (!v) { - R2_GLOBALS._v1000[vIndex] = idx; + R2_GLOBALS._paletteMap[vIndex] = idx; } else { idx = v; } @@ -842,6 +891,7 @@ Ringworld2InvObjectList::Ringworld2InvObjectList(): _itemList.push_back(&_inv52); _selectedItem = NULL; + } void Ringworld2InvObjectList::reset() { @@ -904,6 +954,9 @@ void Ringworld2InvObjectList::reset() { setObjectScene(R2_ALCOHOL_LAMP_3, 2435); setObjectScene(R2_BROKEN_DISPLAY, 1580); setObjectScene(R2_TOOLBOX, 3260); + + // Set up the select item handler method + T2_GLOBALS._onSelectItem = SelectItem; } void Ringworld2InvObjectList::setObjectScene(int objectNum, int sceneNumber) { @@ -921,6 +974,127 @@ void Ringworld2InvObjectList::setObjectScene(int objectNum, int sceneNumber) { T2_GLOBALS._uiElements.updateInventory(); } +/** + * When an inventory item is selected, in Return to Ringworld two objects can be combined + */ +bool Ringworld2InvObjectList::SelectItem(int objectNumber) { + // If no existing item selected, don't go any further + int currentItem = R2_GLOBALS._events.getCursor(); + if (currentItem >= 256) + return false; + + switch (objectNumber) { + case R2_NEGATOR_GUN: + switch (currentItem) { + case R2_SENSOR_PROBE: + if (R2_GLOBALS.getFlag(1)) + SceneItem::display2(5, 1); + else if (R2_INVENTORY.getObjectScene(R2_SPENT_POWER_CAPSULE) != 100) + SceneItem::display2(5, 3); + else { + R2_GLOBALS._sound3.play(48); + SceneItem::display2(5, 2); + R2_INVENTORY.setObjectScene(R2_SPENT_POWER_CAPSULE, 1); + } + break; + case R2_COM_SCANNER: + R2_GLOBALS._sound3.play(44); + if (R2_GLOBALS.getFlag(1)) + SceneItem::display2(5, 9); + else if (R2_INVENTORY.getObjectScene(R2_SPENT_POWER_CAPSULE) == 100) + SceneItem::display2(5, 8); + else + SceneItem::display2(5, 10); + + R2_GLOBALS._sound3.stop(); + break; + case R2_CHARGED_POWER_CAPSULE: + if (R2_INVENTORY.getObjectScene(R2_SPENT_POWER_CAPSULE) == 1) { + R2_GLOBALS._sound3.play(49); + R2_INVENTORY.setObjectScene(R2_CHARGED_POWER_CAPSULE, 100); + R2_GLOBALS.setFlag(1); + SceneItem::display2(5, 4); + } else { + SceneItem::display2(5, 5); + } + break; + default: + selectDefault(objectNumber); + break; + } + break; + case R2_STEPPING_DISKS: + switch (currentItem) { + case R2_SENSOR_PROBE: + if (R2_INVENTORY.getObjectScene(R2_CHARGED_POWER_CAPSULE) == 400) { + R2_GLOBALS._sound3.play(48); + SceneItem::display2(5, 6); + R2_INVENTORY.setObjectScene(R2_CHARGED_POWER_CAPSULE, 1); + } else { + SceneItem::display2(5, 7); + } + break; + case R2_COM_SCANNER: + R2_GLOBALS._sound3.play(44); + if (R2_INVENTORY.getObjectScene(R2_CHARGED_POWER_CAPSULE) == 400) + SceneItem::display2(5, 16); + else + SceneItem::display2(5, 17); + R2_GLOBALS._sound3.stop(); + break; + default: + selectDefault(objectNumber); + break; + } + break; + case R2_ATTRACTOR_UNIT: + case R2_CABLE_HARNESS: + if (currentItem == R2_CABLE_HARNESS || + currentItem == R2_ATTRACTOR_UNIT) { + R2_INVENTORY.setObjectScene(R2_CABLE_HARNESS, 0); + R2_INVENTORY.setObjectScene(R2_ATTRACTOR_UNIT, 0); + R2_INVENTORY.setObjectScene(R2_ATTRACTOR_CABLE_HARNESS, 1); + } else { + selectDefault(objectNumber); + } + break; + case R2_TANNER_MASK: + case R2_PURE_GRAIN_ALCOHOL: + if (currentItem == R2_TANNER_MASK || + currentItem == R2_PURE_GRAIN_ALCOHOL) { + R2_INVENTORY.setObjectScene(R2_TANNER_MASK, 0); + R2_INVENTORY.setObjectScene(R2_PURE_GRAIN_ALCOHOL, 0); + R2_INVENTORY.setObjectScene(R2_SOAKED_FACEMASK, 1); + } else { + selectDefault(objectNumber); + } + break; + default: + // Standard item selection + return false; + } + + return true; +} + +void Ringworld2InvObjectList::selectDefault(int objectNumber) { + Common::String msg1 = g_resourceManager->getMessage(4, 53); + Common::String msg2 = g_resourceManager->getMessage(4, R2_GLOBALS._events.getCursor()); + Common::String msg3 = g_resourceManager->getMessage(4, 54); + Common::String msg4 = g_resourceManager->getMessage(4, objectNumber); + Common::String line = Common::String::format("%.5s%.5s%.5s%.5s%s %s %s %s.", + msg1.c_str(), msg2.c_str(), msg3.c_str(), msg4.c_str(), + msg1.c_str() + 5, msg2.c_str() + 5, msg3.c_str() + 5, msg4.c_str() + 5); + + SceneItem::display(-1, -1, line.c_str(), + SET_WIDTH, 280, + SET_X, 160, + SET_Y, 20, + SET_POS_MODE, 1, + SET_EXT_BGCOLOR, 7, + LIST_END); +} + /*--------------------------------------------------------------------------*/ void Ringworld2Game::start() { @@ -1083,6 +1257,14 @@ void SceneActor::postInit(SceneObjectList *OwnerList) { SceneObject::postInit(); } +void SceneActor::remove() { + R2_GLOBALS._sceneItems.remove(this); + _field9C = NULL; + _linkedActor = NULL; + + SceneObject::remove(); +} + bool SceneActor::startAction(CursorType action, Event &event) { bool handled = true; @@ -1115,6 +1297,32 @@ bool SceneActor::startAction(CursorType action, Event &event) { return handled; } +GfxSurface SceneActor::getFrame() { + GfxSurface frame = SceneObject::getFrame(); + + // TODO: Proper effects handling + switch (_effect) { + case 0: + case 5: + // TODO: Figure out purpose of setting image flags to 64, and getting + // scene priorities -1 or _shade + break; + case 1: + // TODO: Transposing using R2_GLOBALS._pixelArrayMap + break; + case 2: + // No effect + break; + case 4: + break; + default: + // TODO: Default effect + break; + } + + return frame; +} + /*--------------------------------------------------------------------------*/ SceneArea::SceneArea(): EventHandler() { @@ -1268,287 +1476,206 @@ void SceneAreaObject::setDetails(int resNum, int lookLineNum, int talkLineNum, i /*****************************************************************************/ -UnkObject1200::UnkObject1200() { - _field16 = _field3A = NULL; - _field12 = _field14 = 0; - _field26 = _field28 = _field2A = _field2C = _field2E = _field30 = 0; - _field32 = _field34 = _field36 = _field38 = _field3E = _field40 = 0; +MazeUI::MazeUI() { + _mapData = NULL; + _cellsVisible.x = _cellsVisible.y = 0; + _mapCells.x = _mapCells.y = 0; + _cellSize.x = _cellSize.y = 0; + _mapOffset.x = _mapOffset.y = 0; + _resNum = _cellsResNum = 0; + _frameCount = _resCount = _mapImagePitch = _unused = 0; } -void UnkObject1200::synchronize(Serializer &s) { - SavedObject::synchronize(s); +MazeUI::~MazeUI() { + DEALLOCATE(_mapData); +} - _rect1.synchronize(s); - _rect2.synchronize(s); +void MazeUI::synchronize(Serializer &s) { + SavedObject::synchronize(s); - // FIXME: syncrhonize _field16 and _field3A + s.syncAsSint16LE(_resNum); + if (s.isLoading()) + load(_resNum); - s.syncAsSint16LE(_field12); - s.syncAsSint16LE(_field14); - s.syncAsSint16LE(_field26); - s.syncAsSint16LE(_field28); - s.syncAsSint16LE(_field2A); - s.syncAsSint16LE(_field2C); - s.syncAsSint16LE(_field2E); - s.syncAsSint16LE(_field30); - s.syncAsSint16LE(_field32); - s.syncAsSint16LE(_field34); - s.syncAsSint16LE(_field36); - s.syncAsSint16LE(_field38); - s.syncAsSint16LE(_field3E); - s.syncAsSint16LE(_field40); + s.syncAsSint16LE(_mapOffset.x); + s.syncAsSint16LE(_mapOffset.y); + s.syncAsSint16LE(_unused); } -void UnkObject1200::sub51AE9(int arg1) { - warning("STUB: UnkObject1200::sub51AE9()"); -} +void MazeUI::load(int resNum) { + postInit(); + clear(); + _resNum = resNum; -int UnkObject1200::sub51AF8(Common::Point pt) { - if (!_rect1.contains(pt)) - return -1; + const byte *header = g_resourceManager->getResource(RT17, resNum, 0); - int tmp1 = (pt.x - _rect1.left + _field2E) / _field2A; - int tmp2 = (pt.y - _rect1.top + _field30) / _field2C; + _cellsResNum = resNum + 1000; + _mapCells.x = READ_LE_UINT16(header + 2); + _mapCells.y = READ_LE_UINT16(header + 4); + _frameCount = 10; + _resCount = _frameCount << 3; - if ((tmp1 >= 0) && (tmp2 >= 0) && (_field26 > tmp1) && (_field28 > tmp2)) - return _field16[(((_field26 * tmp2) + tmp1)* 2)]; + Visage visage; + visage.setVisage(_cellsResNum, 1); - return -1; + GfxSurface frame = visage.getFrame(2); + _cellSize.x = frame.getBounds().width(); + _cellSize.y = frame.getBounds().height(); + + _mapData = g_resourceManager->getResource(RT17, resNum, 1); + + _mapOffset.y = _mapOffset.x = 0; + _cellsVisible.x = (_bounds.width() + _cellSize.x - 1) / _cellSize.x; + _cellsVisible.y = (_bounds.height() + _cellSize.y - 1) / _cellSize.y; + + _mapImagePitch = (_cellsVisible.x + 1) * _cellSize.x; + _mapImage.create(_mapImagePitch, _cellSize.y); + + _mapBounds = Rect(0, 0, _cellSize.x * _mapCells.x, _cellSize.y * _mapCells.y); } -bool UnkObject1200::sub51AFD(Common::Point pt) { - int retval = false; +void MazeUI::clear() { + if (!_resNum) + _resNum = 1; - _field2E = pt.x; - _field30 = pt.y; + if (_mapData) + DEALLOCATE(_mapData); + _mapData = NULL; + + _mapImage.clear(); +} - if (_field2E < _rect2.top) { - _field2E = _rect2.top; +bool MazeUI::setMazePosition(const Common::Point &pt) { + bool retval = false; + + _mapOffset = pt; + + if (_mapOffset.x < _mapBounds.top) { + _mapOffset.x = _mapBounds.top; retval = true; } - if (_field30 < _rect2.left) { - _field30 = _rect2.left; + if (_mapOffset.y < _mapBounds.left) { + _mapOffset.y = _mapBounds.left; retval = true; } - if (_field2E + _rect1.width() > _rect2.right) { - _field2E = _rect2.right - _rect1.width(); + if (_mapOffset.x + _bounds.width() > _mapBounds.right) { + _mapOffset.x = _mapBounds.right - _bounds.width(); retval = true; } - if (_field30 + _rect1.height() > _rect2.bottom) { - _field30 = _rect2.bottom - _rect1.height(); + if (_mapOffset.y + _bounds.height() > _mapBounds.bottom) { + _mapOffset.y = _mapBounds.bottom - _bounds.height(); retval = true; } return retval; } -void UnkObject1200::sub51B02() { - warning("STUB: UnkObject1200::sub51B02()"); +void MazeUI::reposition() { } -void UnkObject1200::sub9EDE8(Rect rect) { - _rect1 = rect; - warning("FIXME: UnkObject1200::sub9EDE8()"); -// _rect1.clip(g_globals->gfxManager()._bounds); -} +void MazeUI::draw() { + int yPos = 0; + int ySize; + Visage visage; -int UnkObject1200::sub9EE22(int &arg1, int &arg2) { - arg1 /= _field2A; - arg2 /= _field2C; + _cellsVisible.y = ((_mapOffset.y % _cellSize.y) + _bounds.height() + + (_cellSize.y - 1)) / _cellSize.y; - if ((arg1 >= 0) && (arg2 >= 0) && (_field26 > arg1) && (_field28 > arg2)) { - return _field16[(((_field26 * arg2) + arg1) * 2)]; - } + // Loop to handle the cell rows of the visible display area one at a time + for (int yCtr = 0; yCtr < _cellsVisible.y; ++yCtr, yPos += ySize) { + int cellY = _mapOffset.y / _cellSize.y + yCtr; - return -1; -} + // Loop to iterate through the horizontal visible cells to build up + // an entire cell high horizontal slice of the map + for (int xCtr = 0; xCtr < _cellsVisible.x; ++xCtr) { + int cellX = _mapOffset.x / _cellSize.x + xCtr; -void Scene1200::sub9DAD6(int indx) { - _object1.sub9EE22(R2_GLOBALS._v56AA2, R2_GLOBALS._v56AA4); + // Get the type of content to display in the cell + int cell = getCellFromCellXY(Common::Point(cellX, cellY)) - 1; + if (cell >= 0) { + int frameNum = (cell % _frameCount) + 1; + int rlbNum = (cell % _resCount) / _frameCount + 1; + int resNum = _cellsResNum + (cell / _resCount); - switch (indx) { - case 0: - if ( ((_object1.sub51AF8(Common::Point(200, 50)) > 36) || (_object1.sub51AF8(Common::Point(200, 88)) > 36)) - && ( ((R2_GLOBALS._v56AA2 == 3) && (R2_GLOBALS._v56AA4 == 33) && (_field418 != 4)) - || ((R2_GLOBALS._v56AA2 == 13) && (R2_GLOBALS._v56AA4 == 21) && (_field418 != 2)) - || ((R2_GLOBALS._v56AA2 == 29) && (R2_GLOBALS._v56AA4 == 17) && (_field418 != 1)) - || ((R2_GLOBALS._v56AA2 == 33) && (R2_GLOBALS._v56AA4 == 41)) ) - ) { - R2_GLOBALS._player.disableControl(); - _sceneMode = 1200; - setAction(&_sequenceManager, this, 1200, &_actor1, NULL); - } else if (_object1.sub51AF8(Common::Point(200, 69)) == 36) { - switch (_field412 - 1) { - case 0: - if (R2_GLOBALS._player._visage == 3155) - _sceneMode = 15; - else - _sceneMode = 10; - break; - case 1: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 76; - else - _sceneMode = 75; - break; - case 2: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 101; - else - _sceneMode = 100; - break; - case 3: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 111; - else - _sceneMode = 110; - break; - default: - break; - } - R2_GLOBALS._player.disableControl(); - _field412 = 1; - signal(); - } - break; - case 1: - if ( ((_object1.sub51AF8(Common::Point(120, 50)) > 36) || (_object1.sub51AF8(Common::Point(120, 88)) > 36)) - && ( ((R2_GLOBALS._v56AA2 == 7) && (R2_GLOBALS._v56AA4 == 33) && (_field418 != 4)) - || ((R2_GLOBALS._v56AA2 == 17) && (R2_GLOBALS._v56AA4 == 21) && (_field418 != 2)) - || ((R2_GLOBALS._v56AA2 == 33) && (R2_GLOBALS._v56AA4 == 17) && (_field418 != 1)) - || ((R2_GLOBALS._v56AA2 == 5) && (R2_GLOBALS._v56AA4 == 5)) ) - ) { - R2_GLOBALS._player.disableControl(); - _sceneMode = 1201; - setAction(&_sequenceManager, this, 1201, &_actor1, NULL); - } else if (_object1.sub51AF8(Common::Point(120, 69)) == 36) { - switch (_field412 - 1) { - case 0: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 56; - else - _sceneMode = 55; - break; - case 1: - if (R2_GLOBALS._player._visage == 3155) - _sceneMode = 25; - else - _sceneMode = 20; - break; - case 2: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 91; - else - _sceneMode = 90; - break; - case 3: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 121; - else - _sceneMode = 120; - break; - default: - break; - } - R2_GLOBALS._player.disableControl(); - _field412 = 2; - signal(); - } - break; - case 2: - if ( ((_object1.sub51AF8(Common::Point(140, 110)) > 36) || (_object1.sub51AF8(Common::Point(178, 110)) > 36)) - && ( ((R2_GLOBALS._v56AA2 == 17) && (R2_GLOBALS._v56AA4 == 5) && (_field418 != 3)) - || ((R2_GLOBALS._v56AA2 == 41) && (R2_GLOBALS._v56AA4 == 21)) ) - ) { - R2_GLOBALS._player.disableControl(); - _sceneMode = 1203; - setAction(&_sequenceManager, this, 1203, &_actor1, NULL); - } else if (_object1.sub51AF8(Common::Point(160, 110)) == 36) { - switch (_field412 - 1) { - case 0: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 51; - else - _sceneMode = 50; - break; - case 1: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 81; - else - _sceneMode = 80; - break; - case 2: - if (R2_GLOBALS._player._visage == 3155) - _sceneMode = 35; - else - _sceneMode = 30; - break; - case 3: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 116; - else - _sceneMode = 115; - break; - default: - break; + visage.setVisage(resNum, rlbNum); + GfxSurface frame = visage.getFrame(frameNum); + + _mapImage.copyFrom(frame, xCtr * _cellSize.x, 0); + } else { + GfxSurface emptyRect; + emptyRect.create(_cellSize.x, _cellSize.y); + + _mapImage.copyFrom(emptyRect, xCtr * _cellSize.x, 0); } - R2_GLOBALS._player.disableControl(); - _field412 = 3; - signal(); } - break; - case 3: - if ( ((_object1.sub51AF8(Common::Point(140, 30)) > 36) || (_object1.sub51AF8(Common::Point(178, 30)) > 36)) - && ( ((R2_GLOBALS._v56AA2 == 17) && (R2_GLOBALS._v56AA4 == 9) && (_field418 != 3)) - || ((R2_GLOBALS._v56AA2 == 35) && (R2_GLOBALS._v56AA4 == 17)) ) - ) { - R2_GLOBALS._player.disableControl(); - _sceneMode = 1202; - setAction(&_sequenceManager, this, 1202, &_actor1, NULL); - } else if (_object1.sub51AF8(Common::Point(160, 30)) == 36) { - switch (_field412 - 1) { - case 0: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 61; - else - _sceneMode = 60; - break; - case 1: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 71; - else - _sceneMode = 70; - break; - case 2: - if (R2_GLOBALS._player._visage == 3156) - _sceneMode = 96; - else - _sceneMode = 95; - break; - case 3: - if (R2_GLOBALS._player._visage == 3155) - _sceneMode = 45; - else - _sceneMode = 40; - break; - default: - _sceneMode = 1; - R2_GLOBALS._player.setup(3156, 4, 6); - break; + + if (yPos == 0) { + // First line of the map to be displayed - only the bottom portion of that + // first cell row may be visible + yPos = _bounds.top; + ySize = _cellSize.y - (_mapOffset.y % _cellSize.y); + + Rect srcBounds(_mapOffset.x % _cellSize.x, _mapOffset.y % _cellSize.y, + (_mapOffset.x % _cellSize.x) + _bounds.width(), _cellSize.y); + Rect destBounds(_bounds.left, yPos, _bounds.right, yPos + ySize); + + R2_GLOBALS.gfxManager().copyFrom(_mapImage, srcBounds, destBounds); + } else { + if ((yPos + _cellSize.y) < _bounds.bottom) { + ySize = _cellSize.y; + } else { + ySize = _bounds.bottom - yPos; } - R2_GLOBALS._player.disableControl(); - _field412 = 4; - signal(); + + Rect srcBounds(_mapOffset.x % _cellSize.x, 0, + (_mapOffset.x % _cellSize.x) + _bounds.width(), ySize); + Rect destBounds(_bounds.left, yPos, _bounds.right, yPos + ySize); + + R2_GLOBALS.gfxManager().copyFrom(_mapImage, srcBounds, destBounds); } - break; - default: - break; } } +int MazeUI::getCellFromPixelXY(const Common::Point &pt) { + if (!_bounds.contains(pt)) + return -1; + + int cellX = (pt.x - _bounds.left + _mapOffset.x) / _cellSize.x; + int cellY = (pt.y - _bounds.top + _mapOffset.y) / _cellSize.y; + + if ((cellX >= 0) && (cellY >= 0) && (cellX < _mapCells.x) && (cellY < _mapCells.y)) + return (int16)READ_LE_UINT16(_mapData + (_mapCells.x * cellY + cellX) * 2); + + return -1; +} + +int MazeUI::getCellFromCellXY(const Common::Point &p) { + if (p.x < 0 || p.y < 0 || p.x >= _mapCells.x || p.y >= _mapCells.y) { + return -1; + } else { + return (int16)READ_LE_UINT16(_mapData + (_mapCells.x * p.y + p.x) * 2); + } +} + +int MazeUI::pixelToCellXY(Common::Point &pt) { + pt.x /= _cellSize.x; + pt.y /= _cellSize.y; + + if ((pt.x >= 0) && (pt.y >= 0) && (pt.x < _mapCells.x) && (pt.y < _mapCells.y)) { + return (int16)READ_LE_UINT16(_mapData + (_mapCells.x * pt.y + pt.x) * 2); + } + + return -1; +} + +void MazeUI::setDisplayBounds(const Rect &r) { + _bounds = r; + _bounds.clip(g_globals->gfxManager()._bounds); +} + /*--------------------------------------------------------------------------*/ void AnimationSlice::load(Common::File &f) { @@ -1637,7 +1764,7 @@ AnimationPlayer::~AnimationPlayer() { void AnimationPlayer::synchronize(Serializer &s) { EventHandler::synchronize(s); - warning("TODO AnimationPlayer::load"); + warning("TODO AnimationPlayer::synchronize"); } void AnimationPlayer::remove() { @@ -2001,6 +2128,349 @@ void AnimationPlayerExt::synchronize(Serializer &s) { s.syncAsSint16LE(_v); } +/*--------------------------------------------------------------------------*/ + +ModalWindow::ModalWindow() { + _field20 = 0; +} + +void ModalWindow::remove() { + R2_GLOBALS._sceneItems.remove(&_object1); + _object1.remove(); + + SceneArea::remove(); + + --R2_GLOBALS._insetUp; +} + +void ModalWindow::synchronize(Serializer &s) { + SceneArea::synchronize(s); + + s.syncAsByte(_field20); +} + +void ModalWindow::process(Event &event) { + if (_field20 != R2_GLOBALS._insetUp) + return; + + CursorType cursor = R2_GLOBALS._events.getCursor(); + + if (_object1._bounds.contains(event.mousePos.x + g_globals->gfxManager()._bounds.left , event.mousePos.y)) { + if (cursor == _cursorNum) { + R2_GLOBALS._events.setCursor(_savedCursorNum); + } + } else if (event.mousePos.y < 168) { + if (cursor != _cursorNum) { + _savedCursorNum = cursor; + R2_GLOBALS._events.setCursor(CURSOR_INVALID); + } + if (event.eventType == EVENT_BUTTON_DOWN) { + event.handled = true; + R2_GLOBALS._events.setCursor(_savedCursorNum); + remove(); + } + } +} + +void ModalWindow::proc12(int visage, int stripFrameNum, int frameNum, int posX, int posY) { + Scene1200 *scene = (Scene1200 *)R2_GLOBALS._sceneManager._scene; + + _object1.postInit(); + _object1.setup(visage, stripFrameNum, frameNum); + _object1.setPosition(Common::Point(posX, posY)); + _object1.fixPriority(250); + _cursorNum = CURSOR_INVALID; + scene->_sceneAreas.push_front(this); + ++R2_GLOBALS._insetUp; + _field20 = R2_GLOBALS._insetUp; +} + +void ModalWindow::proc13(int resNum, int lookLineNum, int talkLineNum, int useLineNum) { + _object1.setDetails(resNum, lookLineNum, talkLineNum, useLineNum, 2, (SceneItem *) NULL); +} + +/*--------------------------------------------------------------------------*/ + +ScannerDialog::Button::Button() { + _buttonId = 0; + _buttonDown = false; +} + +void ScannerDialog::Button::setup(int buttonId) { + _buttonId = buttonId; + _buttonDown = false; + SceneActor::postInit(); + + SceneObject::setup(4, 2, 2); + fixPriority(255); + + if (_buttonId == 1) + setPosition(Common::Point(141, 99)); + else if (_buttonId == 2) + setPosition(Common::Point(141, 108)); + + static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.push_front(this); +} + +void ScannerDialog::Button::synchronize(Serializer &s) { + SceneActor::synchronize(s); + s.syncAsSint16LE(_buttonId); +} + +void ScannerDialog::Button::process(Event &event) { + if (event.eventType == EVENT_BUTTON_DOWN && R2_GLOBALS._events.getCursor() == CURSOR_USE + && _bounds.contains(event.mousePos) && !_buttonDown) { + setFrame(3); + _buttonDown = true; + event.handled = true; + } + + if (event.eventType == EVENT_BUTTON_UP && _buttonDown) { + setFrame(2); + _buttonDown = false; + event.handled = true; + + reset(); + } +} + +bool ScannerDialog::Button::startAction(CursorType action, Event &event) { + if (action == CURSOR_USE) + return false; + + return startAction(action, event); +} + +void ScannerDialog::Button::reset() { + Scene *scene = R2_GLOBALS._sceneManager._scene; + ScannerDialog &scanner = *R2_GLOBALS._scannerDialog; + + switch (_buttonId) { + case 1: + // Talk button + switch (R2_GLOBALS._sceneManager._sceneNumber) { + case 1550: + scene->_sceneMode = 80; + scene->signal(); + break; + case 1700: + scene->_sceneMode = 30; + scene->signal(); + remove(); + break; + default: + break; + } + break; + case 2: + // Scan button + switch (R2_GLOBALS._sceneManager._sceneNumber) { + case 1550: + scanner._obj4.setup(4, 3, 1); + + scanner._obj5.postInit(); + scanner._obj5.setup(4, 4, 1); + scanner._obj5.setPosition(Common::Point(R2_GLOBALS._v565EC[1] + 145, + R2_GLOBALS._v565EC[3] + 59)); + scanner._obj5.fixPriority(257); + + scanner._obj6.postInit(); + scanner._obj6.setup(4, 4, 2); + scanner._obj6.setPosition(Common::Point(R2_GLOBALS._v565EC[2] + 145, + R2_GLOBALS._v565EC[4] + 59)); + scanner._obj6.fixPriority(257); + break; + case 1700: + case 1800: + if (R2_GLOBALS._v565F8 < 0 || (R2_GLOBALS._v565F8 == 0 && R2_GLOBALS._v565F6 < 1201)) + scanner._obj4.setup(4, 3, 3); + else if (R2_GLOBALS._v565F8 > 0 || (R2_GLOBALS._v565F8 == 0 && R2_GLOBALS._v565F6 < 1201)) + scanner._obj4.setup(4, 3, 4); + else + scanner._obj4.setup(4, 3, 5); + break; + case 3800: + case 3900: + if ((R2_GLOBALS._v56A93 + 1) == 0 && R2_GLOBALS._v566A9 == 0) { + do { + R2_GLOBALS._v566A9 = R2_GLOBALS._randomSource.getRandomNumber(3); + } while (R2_GLOBALS._v566A9 == R2_GLOBALS._v566AA); + } + + scanner._obj4.setup(4, 7, R2_GLOBALS._v566A9); + if (!R2_GLOBALS.getFlag(46)) + R2_GLOBALS.setFlag(46); + break; + default: + scanner._obj4.setup(4, 3, 2); + break; + } + break; + default: + break; + } +} + +/*--------------------------------------------------------------------------*/ + +ScannerDialog::Slider::Slider() { + _initial = _xStart = _yp = 0; + _width = _xInc = 0; + _sliderDown = false; +} + +void ScannerDialog::Slider::synchronize(Serializer &s) { + SceneActor::synchronize(s); + + s.syncAsSint16LE(_initial); + s.syncAsSint16LE(_xStart); + s.syncAsSint16LE(_yp); + s.syncAsSint16LE(_width); + s.syncAsSint16LE(_xInc); +} + +void ScannerDialog::Slider::remove() { + static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.remove(this); + SceneActor::remove(); +} + +void ScannerDialog::Slider::process(Event &event) { + if (event.eventType == EVENT_BUTTON_DOWN && R2_GLOBALS._events.getCursor() == CURSOR_USE + && _bounds.contains(event.mousePos)) { + _sliderDown = true; + } + + if (event.eventType == EVENT_BUTTON_UP && _sliderDown) { + _sliderDown = false; + event.handled = true; + update(); + } + + if (_sliderDown) { + event.handled = true; + if (event.mousePos.x < _xStart) { + setPosition(Common::Point(_xStart, _yp)); + } else if (event.mousePos.x >= (_xStart + _width)) { + setPosition(Common::Point(_xStart + _width, _yp)); + } else { + setPosition(Common::Point(event.mousePos.x, _yp)); + } + } +} + +bool ScannerDialog::Slider::startAction(CursorType action, Event &event) { + if (action == CURSOR_USE) + return false; + + return startAction(action, event); +} + +void ScannerDialog::Slider::update() { + int incHalf = (_width / (_xInc - 1)) / 2; + int newFrequency = ((_position.x - _xStart + incHalf) * _xInc) / (_width + incHalf * 2); + setPosition(Common::Point(_xStart + ((_width * newFrequency) / (_xInc - 1)), _yp)); + + R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex] = newFrequency + 1; + + switch (newFrequency) { + case 0: + R2_GLOBALS._sound4.stop(); + break; + case 1: + R2_GLOBALS._sound4.play(45); + break; + case 2: + R2_GLOBALS._sound4.play(4); + break; + case 3: + R2_GLOBALS._sound4.play(5); + break; + case 4: + R2_GLOBALS._sound4.play(6); + break; + default: + break; + } +} + +void ScannerDialog::Slider::setup(int initial, int xStart, int yp, int width, int xInc) { + _initial = initial; + _xStart = xStart; + _yp = yp; + _width = width; + _xInc = xInc; + _sliderDown = false; + SceneActor::postInit(); + SceneObject::setup(4, 2, 1); + fixPriority(255); + setPosition(Common::Point(_width * (_initial - 1) / (_xInc - 1) + _xStart, yp)); + + static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.push_front(this); +} + +/*--------------------------------------------------------------------------*/ + +ScannerDialog::ScannerDialog() { +} + +void ScannerDialog::remove() { + switch (R2_GLOBALS._sceneManager._sceneNumber) { + case 1550: + case 1700: + R2_GLOBALS._events.setCursor(R2_GLOBALS._player._canWalk ? CURSOR_ARROW : CURSOR_USE); + break; + case 3800: + case 3900: { + Scene *scene = R2_GLOBALS._sceneManager._scene; + scene->_sceneMode = 3806; + scene->signal(); + break; + } + default: + break; + } + + SceneExt *scene = static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene); + scene->_sceneAreas.remove(&_talkButton); + scene->_sceneAreas.remove(&_scanButton); + _talkButton.remove(); + _scanButton.remove(); + _slider.remove(); + _obj4.remove(); + _obj5.remove(); + _obj6.remove(); + _obj7.remove(); + + ModalWindow::remove(); +} + +void ScannerDialog::proc12(int visage, int stripFrameNum, int frameNum, int posX, int posY) { + // Stop player moving if currently doing so + if (R2_GLOBALS._player._mover) + R2_GLOBALS._player.addMover(NULL); + + R2_GLOBALS._events.setCursor(CURSOR_USE); + ModalWindow::proc12(visage, stripFrameNum, frameNum, posX, posY); + + proc13(100, -1, -1, -1); + _talkButton.setup(1); + _scanButton.setup(2); + _slider.setup(R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex], 142, 124, 35, 5); + + _obj4.postInit(); + _obj4.setup(4, 3, 2); + _obj4.setPosition(Common::Point(160, 83)); + _obj4.fixPriority(256); + + if (R2_GLOBALS._sceneManager._sceneNumber == 3800 || R2_GLOBALS._sceneManager._sceneNumber == 3900) { + Scene *scene = R2_GLOBALS._sceneManager._scene; + scene->_sceneMode = 3805; + scene->signal(); + } +} + +/*--------------------------------------------------------------------------*/ + } // End of namespace Ringworld2 } // End of namespace TsAGE diff --git a/engines/tsage/ringworld2/ringworld2_logic.h b/engines/tsage/ringworld2/ringworld2_logic.h index 0b573bf7f0..1b4b7fca1f 100644 --- a/engines/tsage/ringworld2/ringworld2_logic.h +++ b/engines/tsage/ringworld2/ringworld2_logic.h @@ -88,7 +88,7 @@ public: SceneObject *_focusObject; Visage _cursorVisage; - SynchronizedList<SceneArea *> _sceneAreas; + SynchronizedList<EventHandler *> _sceneAreas; Rect _v51C34; public: @@ -108,12 +108,14 @@ public: void fadeOut(); void clearScreen(); void scalePalette(int RFactor, int GFactor, int BFactor); + void loadBlankScene(); }; class SceneHandlerExt: public SceneHandler { public: virtual void postInit(SceneObjectList *OwnerList = NULL); virtual void process(Event &event); + virtual void postLoad(int priorSceneBeforeLoad, int currentSceneBeforeLoad); void setupPaletteMaps(); }; @@ -159,6 +161,9 @@ public: /*--------------------------------------------------------------------------*/ class Ringworld2InvObjectList : public InvObjectList { +private: + static bool SelectItem(int objectNumber); + static void selectDefault(int obectNumber); public: InvObject _none; InvObject _inv1; @@ -260,7 +265,9 @@ class SceneActor: public SceneObject { public: virtual Common::String getClassName() { return "SceneActor"; } virtual void postInit(SceneObjectList *OwnerList = NULL); + virtual void remove(); virtual bool startAction(CursorType action, Event &event); + virtual GfxSurface getFrame(); }; class SceneActorExt: public SceneActor { @@ -276,6 +283,49 @@ public: } }; +enum MazeDirection { MAZEDIR_NONE = 0, MAZEDIR_NORTH = 1, MAZEDIR_NORTHEAST = 2, MAZEDIR_EAST = 3, + MAZEDIR_SOUTHEAST = 4, MAZEDIR_SOUTH = 5, MAZEDIR_SOUTHWEST = 6, MAZEDIR_WEST = 7, + MAZEDIR_NORTHWEST = 8 }; + +class MazeUI: public SceneObject { +private: + void clear(); +public: + // The dimensions (in cells) of the entire maze map + Rect _mapBounds; + + // Encoded cell map specifying the features of the maze + byte *_mapData; + // Image surface used to store a line of the map for rendering + GfxSurface _mapImage; + + Common::Point _cellsVisible; + Common::Point _mapCells; + Common::Point _cellSize; + Common::Point _mapOffset; + int _resNum; + int _cellsResNum; + int _frameCount; + int _resCount; + int _mapImagePitch; + int _unused; +public: + MazeUI(); + virtual ~MazeUI(); + + void setDisplayBounds(const Rect &r); + bool setMazePosition(const Common::Point &pt); + void load(int resNum); + int getCellFromPixelXY(const Common::Point &pt); + int getCellFromCellXY(const Common::Point &p); + int pixelToCellXY(Common::Point &pt); + + virtual Common::String getClassName() { return "MazeUI"; } + void synchronize(Serializer &s); + virtual void reposition(); + virtual void draw(); +}; + class SceneAreaObject: public SceneArea { class Object1: public SceneActor { public: @@ -290,41 +340,6 @@ public: void setDetails(int resNum, int lookLineNum, int talkLineNum, int useLineNum); }; -class UnkObject1200 : public SavedObject { -public: - Rect _rect1; - Rect _rect2; - - int *_field16; - int *_field3A; - - int _field12; - int _field14; - int _field26; - int _field28; - int _field2A; - int _field2C; - int _field2E; - int _field30; - int _field32; - int _field34; - int _field36; - int _field38; - int _field3E; - int _field40; - - UnkObject1200(); - void synchronize(Serializer &s); - - void sub51AE9(int arg1); - int sub51AF8(Common::Point pt); - bool sub51AFD(Common::Point pt); - void sub51B02(); - void sub9EDE8(Rect rect); - int sub9EE22(int &arg1, int &arg2); - virtual Common::String getClassName() { return "UnkObject1200"; } -}; - /*--------------------------------------------------------------------------*/ class AnimationSlice { @@ -378,6 +393,8 @@ public: enum AnimationPaletteMode { ANIMPALMODE_REPLACE_PALETTE = 0, ANIMPALMODE_CURR_PALETTE = 1, ANIMPALMODE_NONE = 2 }; +enum AnimationObjectMode { ANIMOBJMODE_1 = 1, ANIMOBJMODE_2 = 2, ANIMOBJMODE_42 = 42 }; + class AnimationPlayer: public EventHandler { private: void rleDecode(const byte *pSrc, byte *pDest, int size); @@ -392,8 +409,9 @@ public: Common::File _resourceFile; Rect _rect1, _screenBounds; int _field38; - int _field3A, _paletteMode; - int _objectMode; + int _field3A; + AnimationPaletteMode _paletteMode; + AnimationObjectMode _objectMode; int _field58, _sliceHeight; byte _palIndexes[256]; ScenePalette _palette; @@ -418,6 +436,7 @@ public: virtual void changePane() {} virtual void closing() {} + bool load(int animId, Action *endAction = NULL); bool isCompleted(); void close(); @@ -432,6 +451,74 @@ public: virtual void synchronize(Serializer &s); }; +class ModalWindow: public SceneArea { +public: + SceneActor _object1; + byte _field20; +public: + ModalWindow(); + + virtual void remove(); + virtual void synchronize(Serializer &s); + virtual Common::String getClassName() { return "ModalWindow"; } + virtual void process(Event &event); + virtual void proc12(int visage, int stripFrameNum, int frameNum, int posX, int posY); + virtual void proc13(int resNum, int lookLineNum, int talkLineNum, int useLineNum); +}; + +class ScannerDialog: public ModalWindow { + + class Button: public SceneActor { + private: + void reset(); + public: + int _buttonId; + bool _buttonDown; + public: + Button(); + void setup(int buttonId); + + virtual void synchronize(Serializer &s); + virtual Common::String getClassName() { return "ScannerButton"; } + virtual void process(Event &event); + virtual bool startAction(CursorType action, Event &event); + }; + class Slider: public SceneActor { + private: + void update(); + public: + int _initial; + int _xStart; + int _yp; + int _width; + int _xInc; + bool _sliderDown; + public: + Slider(); + void setup(int initial, int xStart, int yp, int width, int xInc); + + virtual void synchronize(Serializer &s); + virtual Common::String getClassName() { return "ScannerSlider"; } + virtual void remove(); + virtual void process(Event &event); + virtual bool startAction(CursorType action, Event &event); + }; +public: + Button _talkButton; + Button _scanButton; + Slider _slider; + SceneActor _obj4; + SceneActor _obj5; + SceneActor _obj6; + SceneActor _obj7; +public: + ScannerDialog(); + + virtual Common::String getClassName() { return "ScannerDialog"; } + virtual void remove(); + void proc12(int visage, int stripFrameNum, int frameNum, int posX, int posY); +}; + } // End of namespace Ringworld2 } // End of namespace TsAGE diff --git a/engines/tsage/ringworld2/ringworld2_scenes0.cpp b/engines/tsage/ringworld2/ringworld2_scenes0.cpp index 3b7d283e44..63bb24f384 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes0.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes0.cpp @@ -226,9 +226,9 @@ bool Scene100::Terminal::startAction(CursorType action, Event &event) { /*--------------------------------------------------------------------------*/ void Scene100::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(100); R2_GLOBALS._scenePalette.loadPalette(0); + SceneExt::postInit(); if (R2_GLOBALS._sceneManager._previousScene != 125) R2_GLOBALS._sound1.play(10); @@ -573,23 +573,23 @@ void Scene125::Icon::hideIcon() { /*--------------------------------------------------------------------------*/ -bool Scene125::Item4::startAction(CursorType action, Event &event) { +bool Scene125::DiskSlot::startAction(CursorType action, Event &event) { Scene125 *scene = (Scene125 *)R2_GLOBALS._sceneManager._scene; switch (action) { case CURSOR_USE: if (R2_INVENTORY.getObjectScene(R2_OPTO_DISK) == R2_GLOBALS._player._oldCharacterScene[1]) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 126; - scene->setAction(&scene->_sequenceManager, scene, 126, &scene->_object7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 126, &scene->_infoDisk, NULL); return true; } break; case R2_OPTO_DISK: if (R2_INVENTORY.getObjectScene(R2_OPTO_DISK) == 1) { R2_GLOBALS._player.disableControl(); - scene->_object7.postInit(); + scene->_infoDisk.postInit(); scene->_sceneMode = 125; - scene->setAction(&scene->_sequenceManager, scene, 125, &scene->_object7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 125, &scene->_infoDisk, NULL); return true; } break; @@ -626,16 +626,16 @@ void Scene125::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.disableControl(); if (R2_INVENTORY.getObjectScene(R2_OPTO_DISK) == R2_GLOBALS._player._oldCharacterScene[1]) { - _object7.postInit(); - _object7.setup(160, 3, 5); - _object7.setPosition(Common::Point(47, 167)); + _infoDisk.postInit(); + _infoDisk.setup(160, 3, 5); + _infoDisk.setPosition(Common::Point(47, 167)); } _object6.postInit(); _object6.setup(162, 1, 1); _object6.setPosition(Common::Point(214, 168)); - _item4.setDetails(Rect(27, 145, 81, 159), 126, 9, -1, -1, 1, NULL); + _diskSlot.setDetails(Rect(27, 145, 81, 159), 126, 9, -1, -1, 1, NULL); _item3.setDetails(Rect(144, 119, 286, 167), 126, 6, 7, 8, 1, NULL); _item2.setDetails(1, 126, 3, 4, 5); _background.setDetails(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 126, 0, 1, -1, 1, NULL); @@ -782,10 +782,11 @@ void Scene125::signal() { break; case 125: R2_INVENTORY.setObjectScene(R2_OPTO_DISK, R2_GLOBALS._player._oldCharacterScene[1]); + R2_GLOBALS._player.enableControl(); break; case 126: R2_INVENTORY.setObjectScene(R2_OPTO_DISK, 1); - _object7.remove(); + _infoDisk.remove(); R2_GLOBALS._player.enableControl(); R2_GLOBALS._player._canWalk = false; break; @@ -1553,7 +1554,7 @@ void Scene180::signal() { R2_GLOBALS._sceneManager._hasPalette = true; _animationPlayer._paletteMode = ANIMPALMODE_NONE; _animationPlayer._v = 1; - _animationPlayer._objectMode = 1; + _animationPlayer._objectMode = ANIMOBJMODE_1; R2_GLOBALS._scene180Mode = 1; _animationPlayer.load(1); @@ -1596,7 +1597,7 @@ void Scene180::signal() { case 5: _animationPlayer._paletteMode = ANIMPALMODE_NONE; _animationPlayer._v = 1; - _animationPlayer._objectMode = 1; + _animationPlayer._objectMode = ANIMOBJMODE_1; R2_GLOBALS._scene180Mode = 2; _animationPlayer.load(2); @@ -1701,7 +1702,7 @@ void Scene180::signal() { _field412 = 1; _animationPlayer._paletteMode = ANIMPALMODE_REPLACE_PALETTE; _animationPlayer._v = 1; - _animationPlayer._objectMode = 42; + _animationPlayer._objectMode = ANIMOBJMODE_42; R2_GLOBALS._scene180Mode = 3; _animationPlayer.load(3); break; @@ -1800,7 +1801,7 @@ void Scene180::signal() { case 40: _animationPlayer._paletteMode = ANIMPALMODE_NONE; - _animationPlayer._objectMode = 1; + _animationPlayer._objectMode = ANIMOBJMODE_1; R2_GLOBALS._scene180Mode = 4; if (_animationPlayer.load(4)) { _animationPlayer.dispatch(); @@ -1839,7 +1840,7 @@ void Scene180::signal() { _field412 = 1; _animationPlayer._paletteMode = ANIMPALMODE_NONE; _animationPlayer._v = 1; - _animationPlayer._objectMode = 1; + _animationPlayer._objectMode = ANIMOBJMODE_1; R2_GLOBALS._scene180Mode = 15; _animationPlayer.load(15, NULL); @@ -2025,7 +2026,7 @@ void Scene200::EastExit::changeScene() { Scene200 *scene = (Scene200 *)R2_GLOBALS._sceneManager._scene; _enabled = false; - R2_GLOBALS._player.disableControl(); + R2_GLOBALS._player.disableControl(CURSOR_WALK); scene->_sceneMode = 206; scene->setAction(&scene->_sequenceManager, scene, 206, &R2_GLOBALS._player, NULL); } @@ -2034,7 +2035,7 @@ void Scene200::WestExit::changeScene() { Scene200 *scene = (Scene200 *)R2_GLOBALS._sceneManager._scene; _enabled = false; - R2_GLOBALS._player.disableControl(); + R2_GLOBALS._player.disableControl(CURSOR_WALK); scene->_sceneMode = 208; scene->setAction(&scene->_sequenceManager, scene, 208, &R2_GLOBALS._player, NULL); } @@ -2042,8 +2043,8 @@ void Scene200::WestExit::changeScene() { /*--------------------------------------------------------------------------*/ void Scene200::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(200); + SceneExt::postInit(); _westExit.setDetails(Rect(94, 0, 123, 58), EXITCURSOR_W, 175); _westExit.setDest(Common::Point(125, 52)); @@ -2311,19 +2312,6 @@ void Scene205::Action1::textLoop() { /*--------------------------------------------------------------------------*/ -Scene205::Object::Object(): SceneObject() { - _x100 = _y100 = 0; -} - -void Scene205::Object::synchronize(Serializer &s) { - EventHandler::synchronize(s); - - s.syncAsSint32LE(_x100); - s.syncAsSint32LE(_y100); -} - -/*--------------------------------------------------------------------------*/ - Scene205::Scene205(): SceneExt() { _yp = 0; _textIndex = 1; @@ -2597,8 +2585,8 @@ void Scene250::synchronize(Serializer &s) { } void Scene250::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(250); + SceneExt::postInit(); R2_GLOBALS._player.postInit(); R2_GLOBALS._player.setVisage(10); @@ -2708,6 +2696,8 @@ void Scene250::signal() { case 7: _field418 = 1; if ((_field414 + 12) == _field412) + _sceneMode = 9; + else _sceneMode = 8; signal(); break; @@ -2741,7 +2731,7 @@ void Scene250::signal() { R2_GLOBALS._sceneManager.changeScene(300); break; case 139: - R2_GLOBALS._sceneManager.changeScene(139); + R2_GLOBALS._sceneManager.changeScene(700); break; case 91: R2_GLOBALS._sceneManager.changeScene(850); @@ -2986,7 +2976,7 @@ bool Scene300::Miranda::startAction(CursorType action, Event &event) { } else if (!R2_GLOBALS.getFlag(55)) { R2_GLOBALS._events.setCursor(CURSOR_ARROW); scene->_sceneMode = 10; - scene->_stripManager.start3(scene->_stripId, scene, R2_GLOBALS._stripManager_lookupList); + scene->_stripManager.start3(201, scene, R2_GLOBALS._stripManager_lookupList); } else { scene->_sceneMode = 16; @@ -3048,7 +3038,7 @@ bool Scene300::Seeker::startAction(CursorType action, Event &event) { R2_GLOBALS._player.disableControl(); if (R2_GLOBALS._player._characterIndex == R2_QUINN) { - if (R2_GLOBALS.getFlag(44)) { + if (!R2_GLOBALS.getFlag(44)) { if (!R2_GLOBALS.getFlag(38)) { R2_GLOBALS._sound1.play(69); scene->_stripId = 181; @@ -3090,10 +3080,10 @@ bool Scene300::Seeker::startAction(CursorType action, Event &event) { } else { R2_GLOBALS._player.disableControl(); scene->_stripId = 171; - } - scene->_sceneMode = 310; - scene->setAction(&scene->_sequenceManager1, scene, 310, &R2_GLOBALS._player, NULL); + scene->_sceneMode = 310; + scene->setAction(&scene->_sequenceManager1, scene, 310, &R2_GLOBALS._player, NULL); + } return true; case R2_READER: @@ -3152,7 +3142,7 @@ bool Scene300::Doorway::startAction(CursorType action, Event &event) { if (action == CURSOR_USE) { if ((R2_GLOBALS._player._characterIndex == R2_QUINN) && - (!R2_GLOBALS.getFlag(44) || R2_GLOBALS._player._characterScene[R2_MIRANDA] == 500)) { + (!R2_GLOBALS.getFlag(44) || R2_GLOBALS._player._characterScene[R2_SEEKER] == 500)) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 301; scene->setAction(&scene->_sequenceManager1, scene, 301, &R2_GLOBALS._player, this, NULL); @@ -3171,6 +3161,9 @@ bool Scene300::Doorway::startAction(CursorType action, Event &event) { Scene300::Scene300(): SceneExt() { _stripId = 0; _rotation = NULL; + + _stripManager.setColors(60, 255); + _stripManager.setFontNumber(3); } void Scene300::synchronize(Serializer &s) { @@ -3181,8 +3174,9 @@ void Scene300::synchronize(Serializer &s) { } void Scene300::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(300); + SceneExt::postInit(); + _sound1.play(23); setZoomPercents(75, 93, 120, 100); @@ -3191,8 +3185,6 @@ void Scene300::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._characterIndex = R2_QUINN; } - _stripManager.setColors(60, 255); - _stripManager.setFontNumber(3); _stripManager.addSpeaker(&_mirandaSpeaker); _stripManager.addSpeaker(&_seekerSpeaker); _stripManager.addSpeaker(&_quinnSpeaker); @@ -3233,7 +3225,7 @@ void Scene300::postInit(SceneObjectList *OwnerList) { _protocolDisplay.postInit(); _protocolDisplay.setup(300, 6, 1); _protocolDisplay.setPosition(Common::Point(287, 71)); - _protocolDisplay.animate(ANIM_MODE_7, NULL); + _protocolDisplay.animate(ANIM_MODE_7, 0, NULL); _protocolDisplay._numFrames = 5; _object6.postInit(); @@ -3365,7 +3357,7 @@ void Scene300::postInit(SceneObjectList *OwnerList) { break; case 325: if (!R2_GLOBALS.getFlag(44) || R2_GLOBALS.getFlag(25)) - setAction(&_sequenceManager1, this, 309, &R2_GLOBALS._player, NULL); + setAction(&_sequenceManager1, this, 307, &R2_GLOBALS._player, NULL); else { R2_GLOBALS.setFlag(60); R2_GLOBALS._player.setup(302, 3, 1); @@ -3402,9 +3394,11 @@ void Scene300::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._events.setCursor(CURSOR_ARROW); if (R2_GLOBALS.getFlag(51)) { + // Things don't seem right _sceneMode = 13; _stripManager.start3(300, this, R2_GLOBALS._stripManager_lookupList); } else { + // Back in Ringworld space _sceneMode = 11; _stripManager.start3(200, this, R2_GLOBALS._stripManager_lookupList); } @@ -3484,27 +3478,27 @@ void Scene300::remove() { void Scene300::signal() { switch (_sceneMode) { case 10: - switch (_stripManager._field2E8) { - case 0: + switch (_stripManager._exitMode) { + case 1: R2_GLOBALS._sound1.changeSound(10); R2_GLOBALS.setFlag(38); break; - case 1: + case 2: R2_GLOBALS.setFlag(3); break; - case 2: + case 3: R2_GLOBALS.setFlag(4); break; - case 3: + case 4: R2_GLOBALS.setFlag(13); if (R2_GLOBALS._stripManager_lookupList[1] == 6) R2_GLOBALS.setFlag(40); break; - case 4: + case 5: if (R2_GLOBALS._stripManager_lookupList[1] == 6) R2_GLOBALS.setFlag(40); break; - case 5: + case 6: R2_GLOBALS._sceneManager.changeScene(1000); break; default: @@ -3565,7 +3559,7 @@ void Scene300::signal() { break; case 16: - if (_stripManager._field2E8 == 1) { + if (_stripManager._exitMode == 1) { R2_GLOBALS._player.setAction(NULL); R2_GLOBALS._sceneManager.changeScene(1000); } else { @@ -3624,6 +3618,8 @@ void Scene300::signal() { case 309: signal309(); R2_GLOBALS._events.setCursor(CURSOR_ARROW); + R2_GLOBALS._events._currentCursor = CURSOR_ARROW; + _sceneMode = 10; _stripManager.start3(_stripId, this, R2_GLOBALS._stripManager_lookupList); break; @@ -3891,7 +3887,7 @@ Scene325::Scene325(): SceneExt() { _field412 = 7; _iconFontNumber = 50; _field416 = _field418 = 0; - _field41A = _field41C = _field41E = _field420 = 0; + _field41A = _field41C = _field41E = _scannerLocation = 0; _soundCount = _soundIndex = 0; for (int idx = 0; idx < 10; ++idx) @@ -3899,8 +3895,8 @@ Scene325::Scene325(): SceneExt() { } void Scene325::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(325); + SceneExt::postInit(); R2_GLOBALS.clearFlag(50); _stripManager.addSpeaker(&_quinnSpeaker); @@ -3926,7 +3922,7 @@ void Scene325::synchronize(Serializer &s) { s.syncAsSint16LE(_field41A); s.syncAsSint16LE(_field41C); s.syncAsSint16LE(_field41E); - s.syncAsSint16LE(_field420); + s.syncAsSint16LE(_scannerLocation); s.syncAsSint16LE(_soundCount); s.syncAsSint16LE(_soundIndex); @@ -4027,19 +4023,19 @@ void Scene325::signal() { if (R2_GLOBALS.getFlag(44) && !R2_GLOBALS.getFlag(51)) { if (v != 13) { - setMessage(328, 0); + setMessage(328, v); } else { - _field420 = 864; + _scannerLocation = 864; _object12.postInit(); - _object2.setup(326, 4, 1); + _object12.setup(326, 4, 1); _object12.setPosition(Common::Point(149, 128)); _object12.fixPriority(20); - _object13.postInit(); - _object13.setup(326, 4, 2); - _object13.setPosition(Common::Point(149, (int)(_field420 * ADJUST_FACTOR))); - _object13.fixPriority(21); + _scannerTab.postInit(); + _scannerTab.setup(326, 4, 2); + _scannerTab.setPosition(Common::Point(149, 22 + (int)(_scannerLocation * ADJUST_FACTOR))); + _scannerTab.fixPriority(21); _object10.postInit(); _object10.setup(326, 1, 1); @@ -4049,7 +4045,7 @@ void Scene325::signal() { _object1.postInit(); _object1.setup(326, 1, 1); _object1.setPosition(Common::Point(210, 32)); - _object10.fixPriority(10); + _object1.fixPriority(10); _object2.postInit(); _object2.setup(326, 1, 1); @@ -4099,7 +4095,7 @@ void Scene325::signal() { } else if (R2_GLOBALS.getFlag(51)) { setMessage(329, (v == 12) ? 10 : v); } else { - setMessage(327, (v < 15) ? 1 : v); + setMessage(327, (v >= 15) ? 1 : v); } break; } @@ -4140,12 +4136,12 @@ void Scene325::signal() { setMessage(128, _field416); break; default: - R2_GLOBALS._player.enableControl(); - R2_GLOBALS._player._canWalk = false; - _field416 = 105; - setMessage(128, _field416); + _field416 = 0; break; } + + R2_GLOBALS._player.enableControl(); + R2_GLOBALS._player._canWalk = false; break; case 10: R2_GLOBALS._player.enableControl(); @@ -4227,31 +4223,50 @@ void Scene325::consoleAction(int id) { _icon1.hideIcon(); _icon2.hideIcon(); _icon3.hideIcon(); - // TODO: Finish - break; - case 3: - _icon1.setIcon(5); - _icon2.setIcon(6); - _icon3.setIcon(R2_GLOBALS.getFlag(50) ? 16 : 15); - break; - case 4: - case 5: - _field418 = id; - _icon1.setIcon(17); - _icon2.setIcon(18); - _icon3.setIcon(19); - break; - case 7: - consoleAction(((_field412 == 5) || (_field412 == 6) || (_field412 == 15)) ? 4 : 7); + + if (id == 2 || (id == 19 && _field418 == 5 && R2_GLOBALS.getFlag(50) && + R2_GLOBALS.getFlag(44) && !R2_GLOBALS.getFlag(51))) { + _icon5.setIcon(13); + _icon4.setPosition(Common::Point(52, 107)); + _icon4._sceneRegionId = 9; + _icon4.setIcon(14); + _icon4._object2.hide(); + + } else { + _icon4.hideIcon(); + _icon5.hideIcon(); + } + + _icon6.setIcon(12); + _sceneMode = 10; + _palette.loadPalette(161); + BF_GLOBALS._scenePalette.addFader(&_palette._palette[0], 256, 5, this); break; - case 8: - R2_GLOBALS._sceneManager.changeScene(300); - case 9: - case 10: - _iconFontNumber = (id - 1) == 9 ? 50 : 52; - _text1.remove(); - _icon6.setIcon(7); + + case 22: + case 23: + case 24: + case 25: + R2_GLOBALS._player.disableControl(); + consoleAction(2); + _field412 = id; + _icon1.hideIcon(); + _icon2.hideIcon(); + _icon3.hideIcon(); + _icon4.hideIcon(); + + _icon5.setIcon(13); + _icon4.setPosition(Common::Point(52, 107)); + _icon4._sceneRegionId = 9; + _icon4.setIcon(14); + _icon4._object2.hide(); + + _icon6.setIcon(12); + _sceneMode = 10; + _palette.loadPalette(161); + BF_GLOBALS._scenePalette.addFader(&_palette._palette[0], 256, 5, this); break; + case 11: if (R2_GLOBALS.getFlag(57) && (R2_GLOBALS._player._characterIndex == 1) && !R2_GLOBALS.getFlag(25)) { R2_GLOBALS._player.disableControl(); @@ -4260,6 +4275,7 @@ void Scene325::consoleAction(int id) { _stripManager.start(403, this); } else { R2_GLOBALS._player.disableControl(); + id = 8; _text1.remove(); _icon4.setPosition(Common::Point(80, 62)); @@ -4267,7 +4283,7 @@ void Scene325::consoleAction(int id) { _icon4.hideIcon(); _object12.remove(); - _object13.remove(); + _scannerTab.remove(); _object10.remove(); _object1.remove(); _object2.remove(); @@ -4286,6 +4302,31 @@ void Scene325::consoleAction(int id) { BF_GLOBALS._scenePalette.addFader(&_palette._palette[0], 256, 5, this); } break; + + case 3: + _icon1.setIcon(5); + _icon2.setIcon(6); + _icon3.setIcon(R2_GLOBALS.getFlag(50) ? 16 : 15); + break; + case 4: + case 5: + _field418 = id; + _icon1.setIcon(17); + _icon2.setIcon(18); + _icon3.setIcon(19); + _icon4.setIcon(20); + break; + case 7: + consoleAction(((_field412 == 5) || (_field412 == 6) || (_field412 == 15)) ? 4 : 7); + break; + case 8: + R2_GLOBALS._sceneManager.changeScene(300); + case 9: + case 10: + _iconFontNumber = (id - 1) == 9 ? 50 : 52; + _text1.remove(); + _icon6.setIcon(7); + break; case 12: _icon4.setIcon(14); _icon4._object2.hide(); @@ -4295,7 +4336,7 @@ void Scene325::consoleAction(int id) { case 18: case 19: case 20: - if (_field420) { + if (_scannerLocation) { R2_GLOBALS._player.disableControl(); _field41A = 1296; _field41E = 1; @@ -4315,7 +4356,7 @@ void Scene325::consoleAction(int id) { case 18: case 19: case 20: - if (_field420 < 1620) { + if (_scannerLocation < 1620) { R2_GLOBALS._player.disableControl(); _field41A = 1296; _field41E = -1; @@ -4337,31 +4378,6 @@ void Scene325::consoleAction(int id) { consoleAction(4); id = 4; break; - case 22: - case 23: - case 24: - case 25: - R2_GLOBALS._player.disableControl(); - consoleAction(2); - _field412 = id; - - _icon1.hideIcon(); - _icon2.hideIcon(); - _icon3.hideIcon(); - _icon4.hideIcon(); - - _icon5.setIcon(13); - _icon4.setPosition(Common::Point(52, 107)); - _icon4._sceneRegionId = 9; - _icon4.setIcon(14); - _icon4._object2.hide(); - - _icon6.setIcon(12); - _sceneMode = 10; - _palette.loadPalette(161); - - BF_GLOBALS._scenePalette.addFader(&_palette._palette[0], 256, 5, this); - break; case 6: default: _icon1.setIcon(1); @@ -4436,21 +4452,21 @@ void Scene325::dispatch() { if (yp >= 30) { yp -= 12; - --_field420; + --_scannerLocation; flag = true; } if (yp <= 10) { yp += 12; - ++_field420; + ++_scannerLocation; flag = true; } - _object3.setPosition(Common::Point(149, (int)(_field420 * ADJUST_FACTOR) + 22)); + _scannerTab.setPosition(Common::Point(149, 22 + (int)(_scannerLocation * ADJUST_FACTOR))); for (int idx = 0; idx < 4; ++idx) _objList[idx].remove(); if (flag) { - int v = _field420 - 758; + int v = _scannerLocation - 758; _object10.setFrame((v++ <= 0) ? 1 : v); _object1.setFrame((v++ <= 0) ? 1 : v); _object2.setFrame((v++ <= 0) ? 1 : v); @@ -4490,7 +4506,7 @@ void Scene325::dispatch() { R2_GLOBALS._sound3.stop(); _field41C = 0; - if (_field420 == 756) { + if (_scannerLocation == 756) { R2_GLOBALS._player.disableControl(); R2_GLOBALS._events.setCursor(CURSOR_USE); _sceneMode = 12; @@ -4908,7 +4924,7 @@ bool Scene500::Doorway::startAction(CursorType action, Event &event) { scene->setAction(&scene->_sequenceManager1, scene, 524, &R2_GLOBALS._player, NULL); } else { scene->_sceneMode = 500; - scene->setAction(&scene->_sequenceManager1, scene, 500, &R2_GLOBALS._player, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 500, &R2_GLOBALS._player, this, NULL); } return true; @@ -4986,7 +5002,7 @@ bool Scene500::SonicStunner::startAction(CursorType action, Event &event) { if ((action == CURSOR_USE) && (R2_GLOBALS._player._characterIndex == R2_QUINN)) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = R2_GLOBALS.getFlag(26) ? 520 : 502; - scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, NULL); + scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, this, NULL); return true; } else { return SceneActor::startAction(action, event); @@ -5075,7 +5091,7 @@ void Scene500::postInit(SceneObjectList *OwnerList) { } } - if ((R2_INVENTORY.getObjectScene(R2_REBREATHER_TANK) != 500) && R2_GLOBALS.getFlag(27)) { + if ((R2_INVENTORY.getObjectScene(R2_REBREATHER_TANK) == 500) && R2_GLOBALS.getFlag(27)) { _tanks1.postInit(); _tanks1.setup(502, 7, 1); _tanks1.setPosition(Common::Point(281, 120)); @@ -5230,7 +5246,7 @@ void Scene500::signal() { R2_GLOBALS._sceneManager.changeScene(700); break; case 501: - if (R2_GLOBALS._player._characterScene[R2_QUINN] == 500) { + if (R2_GLOBALS._player._characterScene[R2_MIRANDA] == 500) { _stripNumber = 1100; _sceneMode = 523; setAction(&_sequenceManager1, this, 523, &R2_GLOBALS._player, NULL); @@ -5338,28 +5354,16 @@ void Scene525::signal() { } /*-------------------------------------------------------------------------- - * Scene 600 - + * Scene 600 - Drive Room * *--------------------------------------------------------------------------*/ -Scene600::Scene600() { - _field412 = 0; - for (int i = 0; i < 256; i++) - _fieldAD2[i] = 0; -} - -void Scene600::synchronize(Serializer &s) { - SceneExt::synchronize(s); - s.syncAsSint16LE(_field412); - for (int i = 0; i < 256; i++) - s.syncAsByte(_fieldAD2[i]); -} - -bool Scene600::Item1::startAction(CursorType action, Event &event) { +bool Scene600::CompartmentHotspot::startAction(CursorType action, Event &event) { if ((action != R2_NEGATOR_GUN) || (!R2_GLOBALS.getFlag(5)) || (R2_GLOBALS.getFlag(8))) return SceneHotspot::startAction(action, event); - SceneItem::display(600, 32, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); + SceneItem::display(600, 32, SET_WIDTH, 280, SET_X, 160, SET_POS_MODE, ALIGN_CENTER, + SET_Y, 20, SET_EXT_BGCOLOR, 7, LIST_END); return true; } @@ -5368,12 +5372,14 @@ bool Scene600::Item4::startAction(CursorType action, Event &event) { return SceneHotspot::startAction(action, event); if ((R2_GLOBALS.getFlag(5)) && (!R2_GLOBALS.getFlag(8))) { - SceneItem::display(600, 32, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); + SceneItem::display(600, 32, SET_WIDTH, 280, SET_X, 160, SET_POS_MODE, ALIGN_CENTER, + SET_Y, 20, SET_EXT_BGCOLOR, 7, LIST_END); return true; } - if (R2_GLOBALS.getFlag(5)) { - SceneItem::display(600, 30, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); + if (!R2_GLOBALS.getFlag(5)) { + SceneItem::display(600, 30, SET_WIDTH, 280, SET_X, 160, SET_POS_MODE, ALIGN_CENTER, + SET_Y, 20, SET_EXT_BGCOLOR, 7, LIST_END); return true; } @@ -5389,30 +5395,46 @@ bool Scene600::Item4::startAction(CursorType action, Event &event) { scene->_actor2.postInit(); scene->_sceneMode = 612; - setAction(&scene->_sequenceManager1, this, 612, &scene->_actor3, &scene->_actor2, &R2_GLOBALS._player, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 612, &scene->_actor3, &scene->_actor2, &R2_GLOBALS._player, NULL); return true; } void Scene600::Actor4::signal() { - Common::Point pt(36, 177 + R2_GLOBALS._randomSource.getRandomNumber(5)); + Common::Point pt(177 + R2_GLOBALS._randomSource.getRandomNumber(5), + 108 + R2_GLOBALS._randomSource.getRandomNumber(3)); NpcMover *mover = new NpcMover(); addMover(mover, &pt, this); } bool Scene600::Actor4::startAction(CursorType action, Event &event) { - if ((action >= CURSOR_WALK) && (action < R2CURSORS_START)) + if (action >= CURSOR_WALK) // Only action cursors return SceneActor::startAction(action, event); return false; } -void Scene600::Actor4::draw() { - warning("TODO: Actor4::draw()"); - SceneActor::draw(); +GfxSurface Scene600::Actor4::getFrame() { + GfxSurface frame = SceneActor::getFrame(); + + if (_effect) { + // Translate the frame using the scene's pixel map + byte *pixelMap = static_cast<Scene600 *>(R2_GLOBALS._sceneManager._scene)->_pixelMap; + Graphics::Surface surface = frame.lockSurface(); + byte *srcP = (byte *)surface.getPixels(); + + while (srcP < ((byte *)surface.getBasePtr(0, surface.h))) { + *srcP = pixelMap[*srcP]; + srcP++; + } + + frame.unlockSurface(); + } + + return frame; } -bool Scene600::Actor5::startAction(CursorType action, Event &event) { +bool Scene600::Doorway::startAction(CursorType action, Event &event) { if ((action < CURSOR_WALK) && (action >= R2CURSORS_START)) return false; @@ -5423,10 +5445,10 @@ bool Scene600::Actor5::startAction(CursorType action, Event &event) { if ((R2_INVENTORY.getObjectScene(R2_CLAMP) == 600) && (!R2_GLOBALS.getFlag(6))) { R2_GLOBALS._player.disableControl(); - scene->_actor6.setDetails(600, 11, -1, -1, 3, (SceneItem *) NULL); + scene->_laser.setDetails(600, 11, -1, -1, 3, (SceneItem *) NULL); R2_GLOBALS.setFlag(6); scene->_sceneMode = 609; - scene->setAction(&scene->_sequenceManager1, scene, 609, &R2_GLOBALS._player, &scene->_actor5, &scene->_actor6, &scene->_actor1, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 609, &R2_GLOBALS._player, &scene->_doorway, &scene->_laser, &scene->_actor1, NULL); return true; } @@ -5436,7 +5458,7 @@ bool Scene600::Actor5::startAction(CursorType action, Event &event) { if (!R2_GLOBALS.getFlag(6)) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 616; - scene->setAction(&scene->_sequenceManager1, scene, 616, &R2_GLOBALS._player, &scene->_actor5, &scene->_actor6, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 616, &R2_GLOBALS._player, &scene->_doorway, &scene->_laser, NULL); return true; } @@ -5445,15 +5467,15 @@ bool Scene600::Actor5::startAction(CursorType action, Event &event) { else { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 601; - scene->setAction(&scene->_sequenceManager1, scene, 601, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 601, &R2_GLOBALS._player, &scene->_doorway, NULL); } return true; } -bool Scene600::Actor6::startAction(CursorType action, Event &event) { +bool Scene600::Laser::startAction(CursorType action, Event &event) { Scene600 *scene = (Scene600 *)R2_GLOBALS._sceneManager._scene; - if ((action < CURSOR_WALK) && (action >= R2CURSORS_START)) { + if (action < CURSOR_WALK) { switch (action) { case R2_COM_SCANNER: if (R2_GLOBALS.getFlag(6)) { @@ -5463,7 +5485,7 @@ bool Scene600::Actor6::startAction(CursorType action, Event &event) { } else { R2_GLOBALS._player.disableControl(); scene->_actor8.postInit(); - scene->_actor8.setDetails(600, 20, -1, -1, 4, &scene->_actor6); + scene->_actor8.setDetails(600, 20, -1, -1, 4, &scene->_laser); scene->_sceneMode = 607; scene->setAction(&scene->_sequenceManager1, scene, 607, &R2_GLOBALS._player, &scene->_actor8, NULL); return true; @@ -5478,8 +5500,8 @@ bool Scene600::Actor6::startAction(CursorType action, Event &event) { return true; } else { R2_GLOBALS._player.disableControl(); - scene->_actor7.postInit(); - scene->_actor7.setDetails(600, 27, -1, -1, 5, &scene->_actor6); + scene->_aerosol.postInit(); + scene->_aerosol.setDetails(600, 27, -1, -1, 5, &scene->_laser); scene->_actor4.postInit(); scene->_actor4.setup(601, 3, 1); @@ -5487,11 +5509,11 @@ bool Scene600::Actor6::startAction(CursorType action, Event &event) { scene->_actor4._moveDiff = Common::Point(1, 1); scene->_actor4._moveRate = 2; scene->_actor4._numFrames = 3; - scene->_actor4.setDetails(600, 24, 25, 26, 5, &scene->_actor7); + scene->_actor4.setDetails(600, 24, 25, 26, 5, &scene->_aerosol); scene->_sceneMode = 605; - scene->setAction(&scene->_sequenceManager1, scene, 605, &R2_GLOBALS._player, &scene->_actor7, &scene->_actor4, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 605, &R2_GLOBALS._player, &scene->_aerosol, &scene->_actor4, &scene->_doorway, NULL); return true; } break; @@ -5499,7 +5521,7 @@ bool Scene600::Actor6::startAction(CursorType action, Event &event) { if (R2_GLOBALS.getFlag(5)) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 606; - scene->setAction(&scene->_sequenceManager1, scene, 606, &R2_GLOBALS._player, &scene->_actor6, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 606, &R2_GLOBALS._player, &scene->_laser, NULL); return true; } else { return SceneActor::startAction(action, event); @@ -5509,7 +5531,7 @@ bool Scene600::Actor6::startAction(CursorType action, Event &event) { return false; break; } - } else if (action != CURSOR_USE) { + } else if (action == CURSOR_USE) { if (R2_GLOBALS.getFlag(5)) { return SceneActor::startAction(action, event); } else { @@ -5522,7 +5544,7 @@ bool Scene600::Actor6::startAction(CursorType action, Event &event) { return SceneActor::startAction(action, event); } -bool Scene600::Actor7::startAction(CursorType action, Event &event) { +bool Scene600::Aerosol::startAction(CursorType action, Event &event) { Scene600 *scene = (Scene600 *)R2_GLOBALS._sceneManager._scene; if ((action < CURSOR_WALK) && (action >= R2CURSORS_START)) { @@ -5530,13 +5552,28 @@ bool Scene600::Actor7::startAction(CursorType action, Event &event) { } else if (action == CURSOR_USE) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 614; - scene->setAction(&scene->_sequenceManager1, scene, 614, &R2_GLOBALS._player, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 614, &R2_GLOBALS._player, &scene->_aerosol, NULL); return true; } else { return SceneActor::startAction(action, event); } } +/*--------------------------------------------------------------------------*/ + +Scene600::Scene600() { + _field412 = 0; + Common::fill(&_pixelMap[0], &_pixelMap[256], 0); +} + +void Scene600::synchronize(Serializer &s) { + SceneExt::synchronize(s); + + s.syncAsSint16LE(_field412); + for (int i = 0; i < 256; i++) + s.syncAsByte(_pixelMap[i]); +} + bool Scene600::Actor8::startAction(CursorType action, Event &event) { Scene600 *scene = (Scene600 *)R2_GLOBALS._sceneManager._scene; @@ -5544,7 +5581,7 @@ bool Scene600::Actor8::startAction(CursorType action, Event &event) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 615; scene->setAction(&scene->_sequenceManager1, scene, 615, &R2_GLOBALS._player, &scene->_actor8, NULL); - } else if ((action == R2_SONIC_STUNNER) && (R2_INVENTORY.getObjectScene(9) == 600) && (R2_GLOBALS._v565F1[1] == 2) && (!R2_GLOBALS.getFlag(8))){ + } else if ((action == R2_SONIC_STUNNER) && (R2_INVENTORY.getObjectScene(9) == 600) && (R2_GLOBALS._scannerFrequencies[1] == 2) && (!R2_GLOBALS.getFlag(8))){ R2_GLOBALS._player.disableControl(); scene->_sceneMode = 608; scene->setAction(&scene->_sequenceManager1, scene, 608, &R2_GLOBALS._player, &scene->_actor4, NULL); @@ -5562,23 +5599,31 @@ void Scene600::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._walkRegions.enableRegion(3); _field412 = 0; - warning("FIXME: loop to initialize _fieldAD2[]"); + // Initialise pixel map for the obscuring effect + ScenePalette &pal = R2_GLOBALS._scenePalette; + uint r, g, b; + for (int i = 0; i < 256; ++i) { + pal.getEntry(i, &r, &g, &b); + int av = ((r + g + b) / 48); - _actor5.postInit(); - _actor5.setVisage(600); - _actor5.setPosition(Common::Point(29, 147)); - _actor5.fixPriority(10); - _actor5.setDetails(300, 3, -1, -1, 1, (SceneItem *) NULL); + _pixelMap[i] = R2_GLOBALS._paletteMap[(av << 8) | (av << 4) | av]; + } - _actor6.postInit(); - _actor6.setPosition(Common::Point(246, 41)); + _doorway.postInit(); + _doorway.setVisage(600); + _doorway.setPosition(Common::Point(29, 147)); + _doorway.fixPriority(10); + _doorway.setDetails(300, 3, -1, -1, 1, (SceneItem *) NULL); + + _laser.postInit(); + _laser.setPosition(Common::Point(246, 41)); if (R2_INVENTORY.getObjectScene(9) == 600) { _actor8.postInit(); _actor8.setup(602, 5, 1); _actor8.setPosition(Common::Point(246, 41)); _actor8.setDetails(600, 20, -1, -1, 1, (SceneItem *) NULL); - switch (R2_GLOBALS._v565F1[1] - 2) { + switch (R2_GLOBALS._scannerFrequencies[1] - 2) { case 0: R2_GLOBALS._sound4.play(45); break; @@ -5597,11 +5642,11 @@ void Scene600::postInit(SceneObjectList *OwnerList) { } if (R2_GLOBALS.getFlag(6)) { - _actor6.setup(602, 7, 1); - _actor6.setDetails(600, 11, -1, -1, 1, (SceneItem *) NULL); + _laser.setup(602, 7, 1); + _laser.setDetails(600, 11, -1, -1, 1, (SceneItem *) NULL); } else { - _actor6.setup(600, 2, 1); - _actor6.setDetails(600, 10, -1, -1, 1, (SceneItem *) NULL); + _laser.setup(600, 2, 1); + _laser.setDetails(600, 10, -1, -1, 1, (SceneItem *) NULL); _actor1.postInit(); _actor1.setup(600, 3, 5); @@ -5614,10 +5659,10 @@ void Scene600::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS.getFlag(5)) { if (R2_INVENTORY.getObjectScene(12) == 600) { - _actor7.postInit(); - _actor7.setup(602, 2, 2); - _actor7.setPosition(Common::Point(189, 95)); - _actor7.setDetails(600, 27, -1, -1, 1, (SceneItem *) NULL); + _aerosol.postInit(); + _aerosol.setup(602, 2, 2); + _aerosol.setPosition(Common::Point(189, 95)); + _aerosol.setDetails(600, 27, -1, -1, 1, (SceneItem *) NULL); } if (R2_GLOBALS.getFlag(8)) { @@ -5651,30 +5696,30 @@ void Scene600::postInit(SceneObjectList *OwnerList) { _item3.setDetails(11, 600, 14, -1, -1); if (R2_GLOBALS.getFlag(9)) { - _item1.setDetails(Rect(159, 3, 315, 95), 600, 7, -1, -1, 1, NULL); + _background.setDetails(Rect(159, 3, 315, 95), 600, 7, -1, -1, 1, NULL); } else { _item4.setDetails(Rect(173, 15, 315, 45), 600, 21, -1, 23, 1, NULL); - _item1.setDetails(Rect(159, 3, 315, 95), 600, 6, -1, -1, 1, NULL); + _background.setDetails(Rect(159, 3, 315, 95), 600, 6, -1, -1, 1, NULL); } _item5.setDetails(Rect(0, 0, 320, 200), 600, 0, -1, -1, 1, NULL); _sceneMode = 600; if (R2_GLOBALS._sceneManager._previousScene == 700) { if (R2_GLOBALS.getFlag(6)) { - setAction(&_sequenceManager1, this, 600, &R2_GLOBALS._player, &_actor5, NULL); + setAction(&_sequenceManager1, this, 600, &R2_GLOBALS._player, &_doorway, NULL); } else if (R2_GLOBALS.getFlag(5)) { - setAction(&_sequenceManager1, this, 603, &R2_GLOBALS._player, &_actor5, &_actor6, &_actor1, NULL); + setAction(&_sequenceManager1, this, 603, &R2_GLOBALS._player, &_doorway, &_laser, &_actor1, NULL); } else { - setAction(&_sequenceManager1, this, 602, &R2_GLOBALS._player, &_actor5, &_actor6, &_actor1, NULL); + setAction(&_sequenceManager1, this, 602, &R2_GLOBALS._player, &_doorway, &_laser, &_actor1, NULL); } } else if (R2_GLOBALS.getFlag(5)) { R2_GLOBALS._player.setPosition(Common::Point(50, 140)); R2_GLOBALS._player.setStrip(3); - _actor6.setFrame(_actor6.getFrameCount()); + _laser.setFrame(_laser.getFrameCount()); signal(); } else { - _actor5.setFrame(7); - _actor6.setFrame(7); + _doorway.setFrame(7); + _laser.setFrame(7); R2_GLOBALS._player.setPosition(Common::Point(28, 140)); R2_GLOBALS._player.setStrip(5); signal(); @@ -5703,7 +5748,7 @@ void Scene600::signal() { R2_GLOBALS._walkRegions.enableRegion(9); R2_GLOBALS._walkRegions.enableRegion(10); - R2_INVENTORY.setObjectScene(12, 600); + R2_INVENTORY.setObjectScene(R2_AEROSOL, 600); R2_GLOBALS.setFlag(5); _actor4._effect = 3; @@ -5730,12 +5775,12 @@ void Scene600::signal() { _actor3.remove(); R2_GLOBALS._sceneItems.remove(&_item4); _actor2.setDetails(600, 21, -1, 23, 4, &_item4); - _item1.setDetails(600, 7, -1, -1, 3, (SceneItem *) NULL); + _background.setDetails(600, 7, -1, -1, 3, (SceneItem *) NULL); R2_GLOBALS._player.enableControl(CURSOR_USE); break; case 614: R2_GLOBALS._player.enableControl(); - _actor7.remove(); + _aerosol.remove(); R2_INVENTORY.setObjectScene(12, 1); R2_GLOBALS._walkRegions.disableRegion(7); break; @@ -5753,8 +5798,9 @@ void Scene600::signal() { } void Scene600::process(Event &event) { - if ((!R2_GLOBALS._player._canWalk) && (!R2_GLOBALS.getFlag(6)) && (event.eventType == EVENT_BUTTON_DOWN) && (R2_GLOBALS._events.getCursor() == R2_NEGATOR_GUN)) { - if (!_actor5.contains(event.mousePos) || (_actor5._frame <= 1)) { + if (R2_GLOBALS._player._canWalk && (!R2_GLOBALS.getFlag(6)) && (event.eventType == EVENT_BUTTON_DOWN) + && (R2_GLOBALS._events.getCursor() == CURSOR_WALK)) { + if (!_doorway.contains(event.mousePos) || (_doorway._frame <= 1)) { if (R2_GLOBALS.getFlag(5)) { _field412 += 10; } else { @@ -5766,7 +5812,7 @@ void Scene600::process(Event &event) { } else { R2_GLOBALS._player.disableControl(); _sceneMode = 613; - setAction(&_sequenceManager1, this, 613, &R2_GLOBALS._player, &_actor6, NULL); + setAction(&_sequenceManager1, this, 613, &R2_GLOBALS._player, &_laser, NULL); event.handled = true; } } else if ((!R2_GLOBALS.getFlag(6)) && (R2_GLOBALS._player._mover) && (_field412 < 10)){ @@ -5778,9 +5824,9 @@ void Scene600::process(Event &event) { void Scene600::dispatch() { if ((_field412 != 0) && (_sceneMode != 600) && (_sceneMode != 603) && (_sceneMode != 602)) { - if ( ((_actor6._strip == 4) && (_actor6._frame > 1)) + if ( ((_laser._strip == 4) && (_laser._frame > 1)) || (_sceneMode == 601) - || ((_sceneMode == 616) && (_actor5._frame > 1)) ) + || ((_sceneMode == 616) && (_doorway._frame > 1)) ) _field412 = 0; else { _field412--; @@ -5803,7 +5849,7 @@ void Scene600::dispatch() { } /*-------------------------------------------------------------------------- - * Scene 700 - + * Scene 700 - Lander Bay 2 * *--------------------------------------------------------------------------*/ Scene700::Scene700() { @@ -5849,7 +5895,7 @@ bool Scene700::Item12::startAction(CursorType action, Event &event) { break; } - scene->setAction(&scene->_sequenceManager, this, 707, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager, scene, 707, &R2_GLOBALS._player, &scene->_actor5, NULL); return true; } @@ -5910,7 +5956,7 @@ bool Scene700::Actor5::startAction(CursorType action, Event &event) { case 0: if ((_strip == 2) && (_frame == 1)) { R2_GLOBALS._player.disableControl(); - if (R2_GLOBALS._player._position.x <= 100) { + if (R2_GLOBALS._player._position.y <= 100) { scene->_sceneMode = 710; scene->setAction(&scene->_sequenceManager, scene, 710, &R2_GLOBALS._player, this, NULL); } else { @@ -5969,10 +6015,10 @@ bool Scene700::Actor6::startAction(CursorType action, Event &event) { } void Scene700::postInit(SceneObjectList *OwnerList) { + loadScene(700); if (R2_GLOBALS._sceneManager._previousScene == 900) - g_globals->gfxManager()._bounds.moveTo(Common::Point(160, 0)); + _sceneBounds = Rect(160, 0, 480, 200); - loadScene(700); R2_GLOBALS._v558B6.set(60, 0, 260, 200); SceneExt::postInit(); @@ -5994,7 +6040,7 @@ void Scene700::postInit(SceneObjectList *OwnerList) { _actor1.postInit(); _actor1.setup(700, 4, 1); - _actor1.setPosition(Common::Point(355 - ((R2_GLOBALS._v565E3 * 8) / 5), ((R2_GLOBALS._v565E1 + 20 ) / 5) - 12)); + _actor1.setPosition(Common::Point(355 - ((R2_GLOBALS._electromagnetZoom * 8) / 5), ((R2_GLOBALS._electromagnetChangeAmount + 20 ) / 5) - 12)); _actor1.fixPriority(10); _actor1.setDetails(700, 12, -1, 14, 1, (SceneItem *) NULL); @@ -6041,7 +6087,7 @@ void Scene700::postInit(SceneObjectList *OwnerList) { case 700: switch (R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS)) { case 0: - if ((R2_GLOBALS._v565E5 != 0) && (R2_GLOBALS._v565E1 == 20) && (R2_GLOBALS._v565E3 == 70)) + if ((R2_GLOBALS._v565E5 != 0) && (R2_GLOBALS._electromagnetChangeAmount == 20) && (R2_GLOBALS._electromagnetZoom == 70)) _actor5.setup(701, 2, 1); else _actor5.setup(701, 2, 8); @@ -6158,9 +6204,7 @@ void Scene700::signal() { } break; case 3: - R2_INVENTORY.setObjectScene(5, 600); - R2_INVENTORY.setObjectScene(16, 700); - R2_GLOBALS._player.enableControl(); + R2_GLOBALS._sceneManager.changeScene(600); break; case 4: _sceneMode = 5; @@ -6206,7 +6250,7 @@ void Scene700::signal() { _sceneMode = 17; _actor5.setup(701, 1, 8); _actor5.setDetails(700, 38, -1, -1, 3, (SceneItem *) NULL); - if ((R2_GLOBALS._v565E5 != 0) && (_actor5._position.x == _actor1._position.x + 1) && (_actor5._position.x == 148 - (((R2_GLOBALS._v565E1 + 10) / 5) * 4))) { + if ((R2_GLOBALS._v565E5 != 0) && (_actor5._position.x == _actor1._position.x + 1) && (_actor5._position.x == 148 - (((R2_GLOBALS._electromagnetChangeAmount + 10) / 5) * 4))) { _actor5.animate(ANIM_MODE_6, NULL); Common::Point pt(_actor5._position.x, _actor1._position.y + 120); NpcMover *mover = new NpcMover(); @@ -6231,7 +6275,7 @@ void Scene700::signal() { break; case 21: _actor5.fixPriority(77); - if ((R2_GLOBALS._v565E5 != 0) && (R2_GLOBALS._v565E1 == 20) && (R2_GLOBALS._v565E3 == 70)) + if ((R2_GLOBALS._v565E5 != 0) && (R2_GLOBALS._electromagnetChangeAmount == 20) && (R2_GLOBALS._electromagnetZoom == 70)) _actor5.animate(ANIM_MODE_6, NULL); R2_INVENTORY.setObjectScene(R2_ATTRACTOR_CABLE_HARNESS, 700); @@ -6249,7 +6293,7 @@ void Scene700::signal() { case 706: _actor5.setDetails(700, 38, -1, -1, 3, (SceneItem *) NULL); _actor5.fixPriority(77); - if ((R2_GLOBALS._v565E5 != 0) && (R2_GLOBALS._v565E1 == 20) && (R2_GLOBALS._v565E3 == 70)) + if ((R2_GLOBALS._v565E5 != 0) && (R2_GLOBALS._electromagnetChangeAmount == 20) && (R2_GLOBALS._electromagnetZoom == 70)) _actor5.animate(ANIM_MODE_6, NULL); R2_INVENTORY.setObjectScene(R2_ATTRACTOR_UNIT, 0); R2_INVENTORY.setObjectScene(R2_ATTRACTOR_CABLE_HARNESS, 700); @@ -6317,12 +6361,26 @@ bool Scene800::DeviceSlot::startAction(CursorType action, Event &event) { break; R2_GLOBALS._player.disableControl(); - scene->_reader.postInit(); + _lookLineNum = 27; + scene->_sceneMode = 809; if (R2_INVENTORY.getObjectScene(R2_OPTICAL_FIBRE) == 800) - scene->setAction(&scene->_sequenceManager1, scene, 814, &R2_GLOBALS._player, &scene->_reader, &scene->_opticalFibre, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 815, &R2_GLOBALS._player, &scene->_reader, &scene->_opticalFibre, NULL); else - scene->setAction(&scene->_sequenceManager1, scene, 804, &R2_GLOBALS._player, &scene->_reader, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 809, &R2_GLOBALS._player, &scene->_reader, NULL); + return true; + case R2_READER: + R2_GLOBALS._player.disableControl(); + scene->_reader.postInit(); + scene->_sceneMode = 804; + + if (R2_INVENTORY.getObjectScene(R2_OPTICAL_FIBRE) == 800) { + scene->setAction(&scene->_sequenceManager1, scene, 814, &R2_GLOBALS._player, + &scene->_reader, &scene->_opticalFibre, NULL); + } else { + scene->setAction(&scene->_sequenceManager1, scene, 804, &R2_GLOBALS._player, + &scene->_reader, NULL); + } return true; default: break; @@ -6416,8 +6474,8 @@ bool Scene800::Cabinet::startAction(CursorType action, Event &event) { /*--------------------------------------------------------------------------*/ void Scene800::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(800); + SceneExt::postInit(); _door.postInit(); _door.setVisage(800); @@ -6826,8 +6884,9 @@ void Scene825::doButtonPress(int buttonId) { _sceneText.setup(NO_TREATMENT_REQUIRED); } else { _button6._buttonId = 5; - + _sceneMode = 827; _object5.postInit(); + setAction(&_sequenceManager1, this, 827, &_object5, NULL); } } else { @@ -7006,8 +7065,8 @@ bool Scene850::Panel::startAction(CursorType action, Event &event) { /*--------------------------------------------------------------------------*/ void Scene850::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); loadScene(850); + SceneExt::postInit(); _liftDoor.postInit(); _liftDoor.setup(850, 2, 1); @@ -7103,44 +7162,47 @@ void Scene850::signal() { } /*-------------------------------------------------------------------------- - * Scene 900 - + * Scene 900 - Lander Bay 2 - Crane Controls * *--------------------------------------------------------------------------*/ -Scene900::Actor4::Actor4() { - _fieldA4 = 0; + +Scene900::Button::Button() { + _buttonId = 0; } -void Scene900::Actor4::synchronize(Serializer &s) { +void Scene900::Button::synchronize(Serializer &s) { SceneActor::synchronize(s); - s.syncAsSint16LE(_fieldA4); + s.syncAsSint16LE(_buttonId); } -void Scene900::Actor4::sub96135(int arg1) { - _fieldA4 = arg1; + +void Scene900::Button::initButton(int buttonId) { + _buttonId = buttonId; + postInit(); setDetails(900, -1, -1, -1, 2, (SceneItem *) NULL); } Scene900::Scene900() { _field412 = 0; - _field414 = 0; - _field416 = 0; + _magnetChangeAmount.x = 0; + _magnetChangeAmount.y = 0; } void Scene900::synchronize(Serializer &s) { SceneExt::synchronize(s); s.syncAsSint16LE(_field412); - s.syncAsSint16LE(_field414); - s.syncAsSint16LE(_field416); + s.syncAsSint16LE(_magnetChangeAmount.x); + s.syncAsSint16LE(_magnetChangeAmount.y); } -bool Scene900::Actor4::startAction(CursorType action, Event &event) { +bool Scene900::Button::startAction(CursorType action, Event &event) { Scene900 *scene = (Scene900 *)R2_GLOBALS._sceneManager._scene; if (action == CURSOR_USE) { R2_GLOBALS._sound2.play(14); - switch (_fieldA4) { + switch (_buttonId) { case 2: if (scene->_field412 == 1) { scene->_sceneMode = 2; @@ -7150,15 +7212,15 @@ bool Scene900::Actor4::startAction(CursorType action, Event &event) { scene->_aSound1.play(30); setup(900, 3, 11); R2_GLOBALS._v565E5 = 1; - if ((R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 0) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS == 700)) && (R2_GLOBALS._v565E1 == 20) && (R2_GLOBALS._v565E3 == 70) && (scene->_actor2._animateMode != ANIM_MODE_6)) { + if ((R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 0) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS == 700)) && (R2_GLOBALS._electromagnetChangeAmount == 20) && (R2_GLOBALS._electromagnetZoom == 70) && (scene->_actor2._animateMode != ANIM_MODE_6)) { scene->_actor2.animate(ANIM_MODE_6, NULL); } else { - if (((scene->_actor3._percent * 49) / 100) + scene->_actor3._position.x == scene->_actor2._position.x) { - if (scene->_actor2._position.x == 166 - (R2_GLOBALS._v565E3 / 15)) { + if (((scene->_electromagnet._percent * 49) / 100) + scene->_electromagnet._position.x == scene->_actor2._position.x) { + if (scene->_actor2._position.x == 166 - (R2_GLOBALS._electromagnetZoom / 15)) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 4; - scene->_actor2._moveDiff.y = (scene->_actor2._position.y - (scene->_actor3._position.y + ((scene->_actor3._percent * 3) / 10) - 2)) / 9; - Common::Point pt(scene->_actor3._position.x + ((scene->_actor3._percent * 49) / 100), scene->_actor3._position.y + ((scene->_actor3._percent * 3) / 10) - 2); + scene->_actor2._moveDiff.y = (scene->_actor2._position.y - (scene->_electromagnet._position.y + ((scene->_electromagnet._percent * 3) / 10) - 2)) / 9; + Common::Point pt(scene->_electromagnet._position.x + ((scene->_electromagnet._percent * 49) / 100), scene->_electromagnet._position.y + ((scene->_electromagnet._percent * 3) / 10) - 2); NpcMover *mover = new NpcMover(); scene->_actor2.addMover(mover, &pt, this); scene->_actor2.animate(ANIM_MODE_6, NULL); @@ -7179,7 +7241,7 @@ bool Scene900::Actor4::startAction(CursorType action, Event &event) { scene->_sceneMode = 5; scene->_actor2.animate(ANIM_MODE_5, NULL); scene->_actor2._moveDiff.y = (166 - scene->_actor2._position.y) / 9; - Common::Point pt(scene->_actor2._position.x, 166 - (R2_GLOBALS._v565E3 / 15)); + Common::Point pt(scene->_actor2._position.x, 166 - (R2_GLOBALS._electromagnetZoom / 15)); NpcMover *mover = new NpcMover(); scene->_actor2.addMover(mover, &pt, this); } @@ -7196,30 +7258,30 @@ bool Scene900::Actor4::startAction(CursorType action, Event &event) { return true; break; case 4: - if ((scene->_field416 == 0) && (scene->_field414 == 0) && (R2_GLOBALS._v565E3 != 0)) { + if ((scene->_magnetChangeAmount.y == 0) && (scene->_magnetChangeAmount.x == 0) && (R2_GLOBALS._electromagnetZoom != 0)) { scene->_aSound1.play(38); - scene->_field416 = -5; + scene->_magnetChangeAmount.y = -5; } return true; break; case 5: - if ((scene->_field416 == 0) && (scene->_field414 == 0) && (R2_GLOBALS._v565E3 < 135)) { + if ((scene->_magnetChangeAmount.y == 0) && (scene->_magnetChangeAmount.x == 0) && (R2_GLOBALS._electromagnetZoom < 135)) { scene->_aSound1.play(38); - scene->_field416 = 5; + scene->_magnetChangeAmount.y = 5; } return true; break; case 6: - if ((scene->_field416 == 0) && (scene->_field414 == 0) && (R2_GLOBALS._v565E1 > -10)) { + if ((scene->_magnetChangeAmount.y == 0) && (scene->_magnetChangeAmount.x == 0) && (R2_GLOBALS._electromagnetChangeAmount > -10)) { scene->_aSound1.play(38); - scene->_field414 = -5; + scene->_magnetChangeAmount.x = -5; } return true; break; case 7: - if ((scene->_field416 == 0) && (scene->_field414 == 0) && (R2_GLOBALS._v565E1 < 20)) { + if ((scene->_magnetChangeAmount.y == 0) && (scene->_magnetChangeAmount.x == 0) && (R2_GLOBALS._electromagnetChangeAmount < 20)) { scene->_aSound1.play(38); - scene->_field414 = 5; + scene->_magnetChangeAmount.x = 5; } return true; break; @@ -7234,12 +7296,12 @@ bool Scene900::Actor4::startAction(CursorType action, Event &event) { default: if (scene->_field412 == 1) { R2_GLOBALS._player.disableControl(); - scene->_actor5.remove(); - scene->_actor6.remove(); - scene->_actor7.remove(); - scene->_actor8.remove(); - scene->_actor9.remove(); - scene->_actor10.remove(); + scene->_button2.remove(); + scene->_button3.remove(); + scene->_button4.remove(); + scene->_button5.remove(); + scene->_button6.remove(); + scene->_button7.remove(); R2_GLOBALS._sound2.play(37); scene->_sceneMode = 901; scene->setAction(&scene->_sequenceManager1, scene, 901, &scene->_actor1, this ,NULL); @@ -7252,10 +7314,8 @@ bool Scene900::Actor4::startAction(CursorType action, Event &event) { break; } } else if (action == CURSOR_LOOK) { - if ((_fieldA4 == 2) && (scene->_field412 == 2)) - SceneItem::display(900, 21, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); - else - SceneItem::display(900, _fieldA4, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); + SceneItem::display(900, ((_buttonId == 2) && (scene->_field412 == 2)) ? 21 : _buttonId + 11, + SET_WIDTH, 280, SET_X, 160, SET_POS_MODE, 1, SET_Y, 20, SET_EXT_BGCOLOR, 7, -999); return true; } else { return SceneActor::startAction(action, event); @@ -7275,16 +7335,15 @@ void Scene900::postInit(SceneObjectList *OwnerList) { _actor1.postInit(); _actor1.setDetails(900, 3, -1, -1, 1, (SceneItem *) NULL); - _field414 = 0; - _field416 = 0; + _magnetChangeAmount.x = 0; + _magnetChangeAmount.y = 0; - _actor3.postInit(); - _actor3.fixPriority(1); - // useless, the original use it for debugging purposes: strcpy(_actor3._actorName, "Crane"); - _actor3.setup(900, 1, 2); - _actor3.setPosition(Common::Point(89, 0)); - _actor3._effect = 1; - _actor3.setDetails(900, 6, -1, 8, 1, (SceneItem *) NULL); + _electromagnet.postInit(); + _electromagnet.fixPriority(1); + _electromagnet.setup(900, 1, 2); + _electromagnet.setPosition(Common::Point(89, 0)); + _electromagnet._effect = 1; + _electromagnet.setDetails(900, 6, -1, 8, 1, (SceneItem *) NULL); if ((R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) != 1) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS) != 1)) { _actor2.postInit(); @@ -7294,7 +7353,7 @@ void Scene900::postInit(SceneObjectList *OwnerList) { if (R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 0) { if (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS) != 700) { _actor2.setup(901, 3, 2); - } else if ((R2_GLOBALS._v565E5 != 0) && (R2_GLOBALS._v565E1 == 20) && (R2_GLOBALS._v565E3 == 70)) { + } else if ((R2_GLOBALS._v565E5 != 0) && (R2_GLOBALS._electromagnetChangeAmount == 20) && (R2_GLOBALS._electromagnetZoom == 70)) { _actor2.setup(901, 2, 1); } else { _actor2.setup(901, 2, 8); @@ -7306,7 +7365,7 @@ void Scene900::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS._v565E7 == 0) { _actor2.setup(901, 1, 8); // Original set two times the same values: skipped - _actor2.setPosition(Common::Point((((100 - ((R2_GLOBALS._v565EB * 350) / 100)) * 49) / 100) + ((R2_GLOBALS._v565E9 * _actor3._percent * 6) / 100) + 89, 166 - (R2_GLOBALS._v565EB / 3))); + _actor2.setPosition(Common::Point((((100 - ((R2_GLOBALS._v565EB * 350) / 100)) * 49) / 100) + ((R2_GLOBALS._v565E9 * _electromagnet._percent * 6) / 100) + 89, 166 - (R2_GLOBALS._v565EB / 3))); _actor2.changeZoom(((100 - ((R2_GLOBALS._v565EB * 350) / 100) + 52) / 10) * 10); } } @@ -7329,68 +7388,68 @@ void Scene900::signal() { _field412 = 1; R2_GLOBALS._sound2.play(37); - _actor5.remove(); - _actor6.remove(); - _actor7.remove(); - _actor8.remove(); - _actor9.remove(); - _actor10.remove(); + _button2.remove(); + _button3.remove(); + _button4.remove(); + _button5.remove(); + _button6.remove(); + _button7.remove(); - _actor5.sub96135(2); - _actor5.setup(900, 2, 1); - _actor5.setPosition(Common::Point(36, 166)); + _button2.initButton(2); + _button2.setup(900, 2, 1); + _button2.setPosition(Common::Point(36, 166)); - _actor6.sub96135(3); - _actor6.setup(900, 2, 5); - _actor6.setPosition(Common::Point(117, 166)); + _button3.initButton(3); + _button3.setup(900, 2, 5); + _button3.setPosition(Common::Point(117, 166)); break; case 2: _field412 = 2; - _actor5.remove(); - _actor6.remove(); + _button2.remove(); + _button3.remove(); - _actor5.sub96135(2); + _button2.initButton(2); if (R2_GLOBALS._v565E5 == 0) - _actor5.setup(900, 3, 9); + _button2.setup(900, 3, 9); else - _actor5.setup(900, 3, 11); - _actor5.setPosition(Common::Point(36, 166)); + _button2.setup(900, 3, 11); + _button2.setPosition(Common::Point(36, 166)); - _actor7.sub96135(5); - _actor7.setup(900, 3, 3); - _actor7.setPosition(Common::Point(76, 134)); + _button4.initButton(5); + _button4.setup(900, 3, 3); + _button4.setPosition(Common::Point(76, 134)); - _actor8.sub96135(4); - _actor8.setup(900, 3, 7); - _actor8.setPosition(Common::Point(76, 156)); + _button5.initButton(4); + _button5.setup(900, 3, 7); + _button5.setPosition(Common::Point(76, 156)); - _actor9.sub96135(6); - _actor9.setup(900, 3, 1); - _actor9.setPosition(Common::Point(55, 144)); + _button6.initButton(6); + _button6.setup(900, 3, 1); + _button6.setPosition(Common::Point(55, 144)); - _actor10.sub96135(7); - _actor10.setup(900, 3, 5); - _actor10.setPosition(Common::Point(99, 144)); + _button7.initButton(7); + _button7.setup(900, 3, 5); + _button7.setPosition(Common::Point(99, 144)); break; case 3: _field412 = 3; - _actor5.remove(); - _actor6.remove(); - _actor7.remove(); - _actor8.remove(); - _actor9.remove(); - _actor10.remove(); + _button2.remove(); + _button3.remove(); + _button4.remove(); + _button5.remove(); + _button6.remove(); + _button7.remove(); - _actor5.sub96135(8); - _actor5.setup(900, 4, 1); - _actor5.setPosition(Common::Point(36, 166)); + _button2.initButton(8); + _button2.setup(900, 4, 1); + _button2.setPosition(Common::Point(36, 166)); - _actor6.sub96135(9); - _actor6.setup(900, 4, 5); - _actor6.setPosition(Common::Point(117, 166)); + _button3.initButton(9); + _button3.setup(900, 4, 5); + _button3.setPosition(Common::Point(117, 166)); break; case 4: _sceneMode = 0; @@ -7404,9 +7463,9 @@ void Scene900::signal() { _actor1.setup(900, 1, 1); - _actor4.sub96135(1); - _actor4.setup(900, 1, 3); - _actor4.setPosition(Common::Point(77, 168)); + _button1.initButton(1); + _button1.setup(900, 1, 3); + _button1.setPosition(Common::Point(77, 168)); _sceneMode = 1; signal(); @@ -7425,26 +7484,28 @@ void Scene900::signal() { } void Scene900::dispatch() { - if (_field416 != 0) { - if (_field416 < 0) { - R2_GLOBALS._v565E3--; - ++_field416; + if (_magnetChangeAmount.y != 0) { + if (_magnetChangeAmount.y < 0) { + R2_GLOBALS._electromagnetZoom--; + ++_magnetChangeAmount.y; } else { - ++R2_GLOBALS._v565E3; - _field416--; + ++R2_GLOBALS._electromagnetZoom; + _magnetChangeAmount.y--; } } - if (_field414 != 0) { - R2_GLOBALS._v565E1--; - ++_field414; - } else { - ++R2_GLOBALS._v565E1; - _field414++; + if (_magnetChangeAmount.x != 0) { + if (_magnetChangeAmount.x < 0) { + R2_GLOBALS._electromagnetChangeAmount--; + ++_magnetChangeAmount.x; + } else { + ++R2_GLOBALS._electromagnetChangeAmount; + _magnetChangeAmount.x--; + } } if (R2_GLOBALS._sceneObjects->contains(&_actor2)) { - if ((R2_GLOBALS._v565E5 != 0) && (R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 0) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS) == 700) && (R2_GLOBALS._v565E1 == 20) && (R2_GLOBALS._v565E3 == 70)) { + if ((R2_GLOBALS._v565E5 != 0) && (R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 0) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS) == 700) && (R2_GLOBALS._electromagnetChangeAmount == 20) && (R2_GLOBALS._electromagnetZoom == 70)) { if ((_actor2._frame > 1) && (_actor2._animateMode != ANIM_MODE_6)) _actor2.animate(ANIM_MODE_6, NULL); } else { @@ -7453,17 +7514,17 @@ void Scene900::dispatch() { } } - _actor3.changeZoom(100 - ((R2_GLOBALS._v565E3 * 70) / 100)); - _actor3.setPosition(Common::Point(((_actor3._percent * R2_GLOBALS._v565E1 * 6) / 100) + 89, R2_GLOBALS._v565E3)); + _electromagnet.changeZoom(100 - ((R2_GLOBALS._electromagnetZoom * 70) / 100)); + _electromagnet.setPosition(Common::Point(((_electromagnet._percent * R2_GLOBALS._electromagnetChangeAmount * 6) / 100) + 89, R2_GLOBALS._electromagnetZoom)); if ((R2_GLOBALS._sceneObjects->contains(&_actor2)) && (R2_GLOBALS._v565E7 != 0) && (!_actor2._mover) && (_actor2._animateMode == ANIM_MODE_NONE)) { - _actor2.setPosition(Common::Point(_actor3._position.x + ((_actor3._percent * 49) / 100), _actor3._position.y + ((_actor3._percent * 3) / 10))); - if (R2_GLOBALS._v565E3 >= 75) { + _actor2.setPosition(Common::Point(_electromagnet._position.x + ((_electromagnet._percent * 49) / 100), _electromagnet._position.y + ((_electromagnet._percent * 3) / 10))); + if (R2_GLOBALS._electromagnetZoom >= 75) { _actor2.setup(901, 1, 1); - _actor2.changeZoom(((_actor3._percent + 52) / 10) * 10); + _actor2.changeZoom(((_electromagnet._percent + 52) / 10) * 10); } else { _actor2.setup(901, 5, 1); - _actor2.changeZoom(((_actor3._percent / 10) * 10) + 30); + _actor2.changeZoom(((_electromagnet._percent / 10) * 10) + 30); } } Scene::dispatch(); diff --git a/engines/tsage/ringworld2/ringworld2_scenes0.h b/engines/tsage/ringworld2/ringworld2_scenes0.h index 2f52f9578f..bc30743aca 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes0.h +++ b/engines/tsage/ringworld2/ringworld2_scenes0.h @@ -126,7 +126,7 @@ class Scene125: public SceneExt { }; /* Items */ - class Item4: public NamedHotspot { + class DiskSlot: public NamedHotspot { public: virtual bool startAction(CursorType action, Event &event); }; @@ -135,8 +135,8 @@ public: ScenePalette _palette; ASoundExt _sound1; NamedHotspot _background, _item2, _item3; - Item4 _item4; - SceneActor _object1, _object2, _object3, _object4, _object5, _object6, _object7; + DiskSlot _diskSlot; + SceneActor _object1, _object2, _object3, _object4, _object5, _object6, _infoDisk; Icon _icon1, _icon2, _icon3, _icon4, _icon5, _icon6; SequenceManager _sequenceManager; SceneText _sceneText; @@ -277,9 +277,7 @@ class Scene205: public SceneExt { public: int _x100, _y100; public: - Object(); - - virtual void synchronize(Serializer &s); + // TODO: Check if this derives from DataManager? and flesh out }; private: void setup(); @@ -453,7 +451,7 @@ private: Common::String parseMessage(const Common::String &msg); public: int _field412, _iconFontNumber, _field416, _field418; - int _field41A, _field41C, _field41E, _field420; + int _field41A, _field41C, _field41E, _scannerLocation; int _soundCount, _soundIndex; int _soundQueue[10]; SpeakerQuinn _quinnSpeaker; @@ -461,7 +459,7 @@ public: SceneHotspot _background, _item2; SceneObject _object1, _object2, _object3, _object4, _object5; SceneObject _object6, _object7, _object8, _object9, _object10; - SceneObject _object11, _object12, _object13; + SceneObject _object11, _object12, _scannerTab; SceneObject _objList[4]; Icon _icon1, _icon2, _icon3, _icon4, _icon5, _icon6; ASoundExt _sound1; @@ -615,7 +613,7 @@ public: }; class Scene600 : public SceneExt { - class Item1 : public NamedHotspot { + class CompartmentHotspot : public NamedHotspot { public: virtual bool startAction(CursorType action, Event &event); }; @@ -628,17 +626,17 @@ class Scene600 : public SceneExt { public: virtual void signal(); virtual bool startAction(CursorType action, Event &event); - virtual void draw(); + virtual GfxSurface getFrame(); }; - class Actor5 : public SceneActor { + class Doorway : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor6 : public SceneActor { + class Laser : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor7 : public SceneActor { + class Aerosol : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -648,24 +646,24 @@ class Scene600 : public SceneExt { }; public: int _field412; - Item1 _item1; - Item1 _item2; - Item1 _item3; + CompartmentHotspot _background; + CompartmentHotspot _item2; + CompartmentHotspot _item3; Item4 _item4; - Item1 _item5; + CompartmentHotspot _item5; BackgroundSceneObject _object1; SceneActor _actor1; SceneActor _actor2; SceneActor _actor3; Actor4 _actor4; - Actor5 _actor5; - Actor6 _actor6; - Actor7 _actor7; + Doorway _doorway; + Laser _laser; + Aerosol _aerosol; Actor8 _actor8; ASoundExt _aSound1; SequenceManager _sequenceManager1; SequenceManager _sequenceManager2; - byte _fieldAD2[256]; + byte _pixelMap[256]; Scene600(); virtual void postInit(SceneObjectList *OwnerList = NULL); @@ -865,30 +863,29 @@ public: }; class Scene900 : public SceneExt { - class Actor4 : public SceneActor { + class Button : public SceneActor { public: - int _fieldA4; + int _buttonId; - Actor4(); - void sub96135(int arg1); + Button(); + void initButton(int buttonId); virtual void synchronize(Serializer &s); virtual bool startAction(CursorType action, Event &event); }; public: int _field412; - int _field414; - int _field416; + Common::Point _magnetChangeAmount; NamedHotspot _item1; SceneActor _actor1; SceneActor _actor2; - SceneActor _actor3; - Actor4 _actor4; - Actor4 _actor5; - Actor4 _actor6; - Actor4 _actor7; - Actor4 _actor8; - Actor4 _actor9; - Actor4 _actor10; + SceneActor _electromagnet; + Button _button1; + Button _button2; + Button _button3; + Button _button4; + Button _button5; + Button _button6; + Button _button7; ASoundExt _aSound1; SequenceManager _sequenceManager1; diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.cpp b/engines/tsage/ringworld2/ringworld2_scenes1.cpp index af62ab6916..4e9d019f01 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes1.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes1.cpp @@ -30,9 +30,452 @@ namespace TsAGE { namespace Ringworld2 { /*-------------------------------------------------------------------------- + * Scene 1000 - Cutscene scene + * + *--------------------------------------------------------------------------*/ + +Scene1000::Scene1000(): SceneExt() { + R2_GLOBALS._sceneManager._hasPalette = false; + R2_GLOBALS._uiElements._active = false; + _gameTextSpeaker._displayMode = 9; + _fieldD2E = 0; +} + +void Scene1000::postInit(SceneObjectList *OwnerList) { + loadBlankScene(); + SceneExt::postInit(); + + _stripManager.addSpeaker(&_gameTextSpeaker); + R2_GLOBALS._player.postInit(); + R2_GLOBALS._player.hide(); + R2_GLOBALS._player.disableControl(); + + switch (R2_GLOBALS._sceneManager._previousScene) { + case 300: + _sceneMode = R2_GLOBALS.getFlag(57) ? 40 : 0; + break; + case 1010: + _sceneMode = 30; + break; + case 1100: + _sceneMode = 10; + break; + case 1530: + _sceneMode = 20; + break; + case 2500: + _sceneMode = 100; + break; + case 2800: + _sceneMode = 2800; + break; + case 3100: + if (R2_GLOBALS._player._oldCharacterScene[R2_QUINN] == 1000) + _sceneMode = 90; + else + _sceneMode = 80; + break; + case 3500: + _sceneMode = 50; + break; + case 3700: + _sceneMode = 60; + break; + default: + _sceneMode = 999; + break; + } + + R2_GLOBALS._uiElements._active = false; + setAction(&_sequenceManager1, this, 1, &R2_GLOBALS._player, NULL); +} + +void Scene1000::remove() { + R2_GLOBALS._scenePalette.loadPalette(0); + R2_GLOBALS._scenePalette.setEntry(255, 0xff, 0xff, 0xff); + SceneExt::remove(); +} + +void Scene1000::signal() { + ScenePalette scenePalette1, scenePalette2; + uint32 black = 0; + + switch (_sceneMode++) { + case 0: + // TODO: Sort out values + R2_GLOBALS._gfxColors.foreground = 191; + R2_GLOBALS._gfxColors.background = 144; + R2_GLOBALS._fontColors.background = 224; + R2_GLOBALS._fontColors.foreground = 119; + + _animationPlayer._objectMode = ANIMOBJMODE_2; + _animationPlayer._paletteMode = ANIMPALMODE_NONE; + _animationPlayer.load(5, this); + R2_GLOBALS._scenePalette.loadPalette(_animationPlayer._subData._palData, 0, 256); + R2_GLOBALS._sceneManager._hasPalette = false; + + _animationPlayer.dispatch(); + _fieldD2E = 1; + + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, 0); + for (int percent = 0; percent < 100; percent += 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + + R2_GLOBALS._sound1.play(67); + break; + + case 1: + R2_GLOBALS._sound1.fadeOut2(NULL); + + // TODO: Sort out values + R2_GLOBALS._gfxColors.foreground = 191; + R2_GLOBALS._gfxColors.background = 144; + R2_GLOBALS._fontColors.background = 224; + R2_GLOBALS._fontColors.foreground = 119; + + R2_GLOBALS._scenePalette.loadPalette(0); + loadScene(9999); + + R2_GLOBALS._player.setup(1140, 1, 1); + R2_GLOBALS._player.setPosition(Common::Point(160, 100)); + R2_GLOBALS._player.show(); + + _field412 = 0; + _stripManager.start(29, this); + break; + + case 2: + if (R2_GLOBALS._speechSubtitles & SPEECH_TEXT) { + setAction(&_sequenceManager1, this, 1, &R2_GLOBALS._player, NULL); + } else { + if (++_field412 < 3) + _sceneMode = 2; + + setAction(&_sequenceManager1, this, 2, &R2_GLOBALS._player, NULL); + } + break; + + case 3: + // TODO: Sort out values + R2_GLOBALS._gfxColors.foreground = 191; + R2_GLOBALS._gfxColors.background = 144; + R2_GLOBALS._fontColors.background = 224; + R2_GLOBALS._fontColors.foreground = 119; + + for (int percent = 100; percent >= 0; percent -= 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + + _animationPlayer._paletteMode = ANIMPALMODE_NONE; + _animationPlayer._objectMode = ANIMOBJMODE_2; + _animationPlayer.load(7, this); + R2_GLOBALS._scenePalette.loadPalette(_animationPlayer._subData._palData, 0, 256); + R2_GLOBALS._sceneManager._hasPalette = false; + + _animationPlayer.dispatch(); + + _fieldD2E = 1; + R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); + for (int percent = 0; percent < 100; percent += 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + + R2_GLOBALS._sound2.play(81); + R2_GLOBALS._sound1.play(80); + break; + + case 4: + // TODO: Sort out values + R2_GLOBALS._gfxColors.foreground = 191; + R2_GLOBALS._gfxColors.background = 144; + R2_GLOBALS._fontColors.background = 224; + R2_GLOBALS._fontColors.foreground = 119; + + R2_GLOBALS._sound2.fadeOut2(NULL); + R2_GLOBALS._sound1.fadeOut2(NULL); + R2_GLOBALS._sceneManager.changeScene(1100); + break; + + case 10: + _animationPlayer._paletteMode = ANIMPALMODE_NONE; + _animationPlayer._objectMode = ANIMOBJMODE_2; + _animationPlayer.load(6, this); + + R2_GLOBALS._scenePalette.loadPalette(_animationPlayer._subData._palData, 0, 256); + R2_GLOBALS._sceneManager._hasPalette = false; + _animationPlayer.dispatch(); + + _fieldD2E = 1; + R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); + for (int percent = 0; percent < 100; percent += 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + + R2_GLOBALS._sound1.play(55); + break; + + case 11: + R2_GLOBALS._scenePalette.loadPalette(0); + R2_GLOBALS._sceneManager.changeScene(300); + break; + + case 20: + _animationPlayer._paletteMode = ANIMPALMODE_NONE; + _animationPlayer._objectMode = ANIMOBJMODE_2; + _animationPlayer.load(8, this); + + R2_GLOBALS._scenePalette.loadPalette(_animationPlayer._subData._palData, 0, 256); + R2_GLOBALS._sceneManager._hasPalette = false; + _animationPlayer.dispatch(); + + _fieldD2E = 1; + R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); + for (int percent = 0; percent < 100; percent += 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + break; + + case 21: + R2_GLOBALS._scenePalette.loadPalette(0); + R2_GLOBALS._sceneManager.changeScene(1530); + break; + + case 30: + _animationPlayer._paletteMode = ANIMPALMODE_NONE; + _animationPlayer._objectMode = ANIMOBJMODE_2; + _animationPlayer.load(17, this); + + R2_GLOBALS._scenePalette.loadPalette(_animationPlayer._subData._palData, 0, 256); + R2_GLOBALS._sceneManager._hasPalette = false; + _animationPlayer.dispatch(); + + _fieldD2E = 1; + R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); + for (int percent = 0; percent < 100; percent += 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + + R2_GLOBALS._sound2.play(91); + break; + + case 31: + R2_GLOBALS._sound2.fadeOut2(NULL); + R2_GLOBALS._sound1.fadeOut2(NULL); + R2_GLOBALS._scenePalette.loadPalette(0); + R2_GLOBALS.setFlag(51); + R2_GLOBALS._sceneManager.changeScene(300); + break; + + case 40: + _animationPlayer._paletteMode = ANIMPALMODE_NONE; + _animationPlayer._objectMode = ANIMOBJMODE_2; + _animationPlayer.load(18, this); + + R2_GLOBALS._scenePalette.loadPalette(_animationPlayer._subData._palData, 0, 256); + R2_GLOBALS._sceneManager._hasPalette = false; + _animationPlayer.dispatch(); + + _fieldD2E = 1; + R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); + for (int percent = 0; percent < 100; percent += 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + + R2_GLOBALS._sound2.play(90); + break; + + case 41: + R2_GLOBALS._scenePalette.loadPalette(0); + R2_GLOBALS._sceneManager.changeScene(1010); + break; + + case 50: + R2_GLOBALS._sound2.play(306); + for (int percent = 100; percent >= 0; percent -= 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + + _animationPlayer._paletteMode = ANIMPALMODE_NONE; + _animationPlayer._objectMode = ANIMOBJMODE_2; + _animationPlayer.load(13, this); + + R2_GLOBALS._scenePalette.loadPalette(_animationPlayer._subData._palData, 0, 256); + R2_GLOBALS._sceneManager._hasPalette = false; + _animationPlayer.dispatch(); + + _fieldD2E = 1; + R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); + for (int percent = 0; percent < 100; percent += 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + break; + + case 51: + R2_GLOBALS._sound2.stop(); + R2_GLOBALS._sound2.play(307); + R2_GLOBALS._sound1.play(308); + + for (int percent = 100; percent >= 0; percent -= 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + + _animationPlayer._paletteMode = ANIMPALMODE_NONE; + _animationPlayer._objectMode = ANIMOBJMODE_2; + _animationPlayer.load(14, this); + + R2_GLOBALS._scenePalette.loadPalette(_animationPlayer._subData._palData, 0, 256); + R2_GLOBALS._sceneManager._hasPalette = false; + _animationPlayer.dispatch(); + + _fieldD2E = 1; + R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); + for (int percent = 0; percent < 100; percent += 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + break; + + case 52: + R2_GLOBALS._sound2.fadeOut2(NULL); + R2_GLOBALS._sound1.fadeOut2(NULL); + R2_GLOBALS._scenePalette.loadPalette(0); + R2_GLOBALS._sceneManager.changeScene(3350); + break; + + case 60: + R2_GLOBALS._sound1.play(333); + + for (int percent = 100; percent >= 0; percent -= 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + + _animationPlayer._paletteMode = ANIMPALMODE_NONE; + _animationPlayer._objectMode = ANIMOBJMODE_2; + _animationPlayer.load(12, this); + + R2_GLOBALS._scenePalette.loadPalette(_animationPlayer._subData._palData, 0, 256); + R2_GLOBALS._sceneManager._hasPalette = false; + _animationPlayer.dispatch(); + + _fieldD2E = 1; + R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); + for (int percent = 0; percent < 100; percent += 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + break; + + case 61: + R2_GLOBALS._sound1.fadeOut2(NULL); + R2_GLOBALS._scenePalette.loadPalette(0); + R2_GLOBALS._sceneManager.changeScene(160); + break; + + case 70: + R2_GLOBALS._sound2.play(113); + for (int percent = 100; percent >= 0; percent -= 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + + _animationPlayer._paletteMode = ANIMPALMODE_NONE; + _animationPlayer._objectMode = ANIMOBJMODE_2; + _animationPlayer.load(9, this); + + R2_GLOBALS._scenePalette.loadPalette(_animationPlayer._subData._palData, 0, 256); + R2_GLOBALS._sceneManager._hasPalette = false; + _animationPlayer.dispatch(); + + _fieldD2E = 1; + R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); + for (int percent = 0; percent < 100; percent += 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + break; + + case 71: + case 81: + R2_GLOBALS._sound1.fadeOut2(NULL); + R2_GLOBALS._sound2.fadeOut2(NULL); + R2_GLOBALS._scenePalette.loadPalette(0); + R2_GLOBALS._sceneManager.changeScene(3100); + break; + + case 80: + _animationPlayer._paletteMode = ANIMPALMODE_NONE; + _animationPlayer._objectMode = ANIMOBJMODE_2; + _animationPlayer.load(10, this); + + R2_GLOBALS._scenePalette.loadPalette(_animationPlayer._subData._palData, 0, 256); + R2_GLOBALS._sceneManager._hasPalette = false; + _animationPlayer.dispatch(); + + _fieldD2E = 1; + R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); + for (int percent = 0; percent < 100; percent += 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + + R2_GLOBALS._sound1.play(242); + R2_GLOBALS._sound2.play(286); + break; + + case 90: + _animationPlayer._paletteMode = ANIMPALMODE_NONE; + _animationPlayer._objectMode = ANIMOBJMODE_2; + _animationPlayer.load(11, this); + + R2_GLOBALS._scenePalette.loadPalette(_animationPlayer._subData._palData, 0, 256); + R2_GLOBALS._sceneManager._hasPalette = false; + _animationPlayer.dispatch(); + + _fieldD2E = 1; + R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); + for (int percent = 0; percent < 100; percent += 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + + R2_GLOBALS._sound1.play(277); + break; + + case 91: + R2_GLOBALS._sound1.fadeOut2(NULL); + R2_GLOBALS._player._characterIndex = R2_SEEKER; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 3100; + R2_GLOBALS._sceneManager.changeScene(2500); + break; + + case 100: + R2_GLOBALS._sound1.play(304); + R2_GLOBALS._sound2.play(82); + + _animationPlayer._paletteMode = ANIMPALMODE_NONE; + _animationPlayer._objectMode = ANIMOBJMODE_2; + _animationPlayer.load(19, this); + + R2_GLOBALS._scenePalette.loadPalette(_animationPlayer._subData._palData, 0, 256); + R2_GLOBALS._sceneManager._hasPalette = false; + _animationPlayer.dispatch(); + + _fieldD2E = 1; + R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); + for (int percent = 0; percent < 100; percent += 5) + R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); + break; + + case 101: + R2_GLOBALS._sound1.fadeOut2(NULL); + R2_GLOBALS._sound2.fadeOut2(NULL); + R2_GLOBALS._scenePalette.loadPalette(0); + R2_GLOBALS._sceneManager.changeScene(3500); + break; + } +} + +void Scene1000::dispatch() { + if (_fieldD2E) { + if (_animationPlayer.isCompleted()) { + _fieldD2E = 0; + _animationPlayer.close(); + _animationPlayer.remove(); + + if (_sceneMode == 52) + _endHandler = this; + } else { + _animationPlayer.dispatch(); + } + } + + Scene::dispatch(); +} + + +/*-------------------------------------------------------------------------- * Scene 1010 - Cutscene: A pixel lost in space! * *--------------------------------------------------------------------------*/ + void Scene1010::postInit(SceneObjectList *OwnerList) { SceneExt::postInit(); loadScene(1010); @@ -229,7 +672,7 @@ void Scene1100::synchronize(Serializer &s) { s.syncAsSint16LE(_field414); } -bool Scene1100::Actor16::startAction(CursorType action, Event &event) { +bool Scene1100::Seeker::startAction(CursorType action, Event &event) { Scene1100 *scene = (Scene1100 *)R2_GLOBALS._sceneManager._scene; if (action != CURSOR_TALK) @@ -263,7 +706,7 @@ bool Scene1100::Actor16::startAction(CursorType action, Event &event) { return true; } -bool Scene1100::Actor17::startAction(CursorType action, Event &event) { +bool Scene1100::Trooper::startAction(CursorType action, Event &event) { Scene1100 *scene = (Scene1100 *)R2_GLOBALS._sceneManager._scene; switch (action) { @@ -271,7 +714,7 @@ bool Scene1100::Actor17::startAction(CursorType action, Event &event) { if (_visage == 1105) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1114; - scene->setAction(&scene->_sequenceManager1, scene, 1114, &R2_GLOBALS._player, &scene->_actor17, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1114, &R2_GLOBALS._player, &scene->_trooper, NULL); return true; } else { return SceneActor::startAction(action, event); @@ -284,19 +727,19 @@ bool Scene1100::Actor17::startAction(CursorType action, Event &event) { R2_GLOBALS._player.disableControl(); if (R2_GLOBALS._player._characterIndex == 1) { scene->_sceneMode = 1112; - scene->setAction(&scene->_sequenceManager1, scene, 1112, &R2_GLOBALS._player, &scene->_actor17, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1112, &R2_GLOBALS._player, &scene->_trooper, NULL); } else { scene->_sceneMode = 1115; - scene->setAction(&scene->_sequenceManager1, scene, 1115, &R2_GLOBALS._player, &scene->_actor17, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1115, &R2_GLOBALS._player, &scene->_trooper, NULL); } return true; } else if (_strip == 2) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1113; if (R2_GLOBALS._player._characterIndex == 1) { - scene->setAction(&scene->_sequenceManager1, scene, 1113, &R2_GLOBALS._player, &scene->_actor17, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1113, &R2_GLOBALS._player, &scene->_trooper, NULL); } else { - scene->setAction(&scene->_sequenceManager1, scene, 1118, &R2_GLOBALS._player, &scene->_actor17, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1118, &R2_GLOBALS._player, &scene->_trooper, NULL); } return true; } else { @@ -309,7 +752,7 @@ bool Scene1100::Actor17::startAction(CursorType action, Event &event) { } } -bool Scene1100::Actor18::startAction(CursorType action, Event &event) { +bool Scene1100::Chief::startAction(CursorType action, Event &event) { Scene1100 *scene = (Scene1100 *)R2_GLOBALS._sceneManager._scene; if ((action == CURSOR_TALK) && (!R2_GLOBALS.getFlag(54)) && (R2_GLOBALS.getFlag(52))) { @@ -381,28 +824,28 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.hide(); R2_GLOBALS._player.disableControl(); - _actor16.postInit(); - _actor16.hide(); + _seeker.postInit(); + _seeker.hide(); if (R2_GLOBALS._player._characterIndex == 1) - _actor16.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); + _seeker.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); else - _actor16.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); + _seeker.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); - _actor18.postInit(); - _actor18.setup(1113, 3, 1); - _actor18.setPosition(Common::Point(181, 125)); - _actor18.fixPriority(110); + _chief.postInit(); + _chief.setup(1113, 3, 1); + _chief.setPosition(Common::Point(181, 125)); + _chief.fixPriority(110); if (R2_GLOBALS.getFlag(54)) - _actor18.setDetails(1100, 4, -1, -1, 1, (SceneItem *) NULL); + _chief.setDetails(1100, 4, -1, -1, 1, (SceneItem *) NULL); else - _actor18.setDetails(1100, 3, -1, -1, 1, (SceneItem *) NULL); + _chief.setDetails(1100, 3, -1, -1, 1, (SceneItem *) NULL); - _actor17.postInit(); - _actor17.setup(1105, 3, 1); - _actor17.setPosition(Common::Point(312, 165)); - _actor17._numFrames = 5; - _actor17.setDetails(1100, 22, 23, 24, 1, (SceneItem *) NULL); + _trooper.postInit(); + _trooper.setup(1105, 3, 1); + _trooper.setPosition(Common::Point(312, 165)); + _trooper._numFrames = 5; + _trooper.setDetails(1100, 22, 23, 24, 1, (SceneItem *) NULL); _actor1.postInit(); _actor1.setup(1512, 1, 1); @@ -464,66 +907,66 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.postInit(); R2_GLOBALS._player.animate(ANIM_MODE_1, NULL); - _actor16.postInit(); + _seeker.postInit(); if (R2_GLOBALS.getFlag(52)) { if (R2_GLOBALS._player._characterIndex == 1) { R2_GLOBALS._player.setup(19, 7, 1); - _actor16.setup(29, 6, 1); + _seeker.setup(29, 6, 1); } else { R2_GLOBALS._player.setup(29, 7, 1); - _actor16.setup(19, 6, 1); + _seeker.setup(19, 6, 1); } R2_GLOBALS._player.setPosition(Common::Point(140, 124)); - _actor16.setPosition(Common::Point(237, 134)); + _seeker.setPosition(Common::Point(237, 134)); R2_GLOBALS._player.enableControl(); } else { if (R2_GLOBALS._player._characterIndex == 1) { R2_GLOBALS._player.setup(1107, 2, 1); - _actor16.setup(1107, 4, 1); + _seeker.setup(1107, 4, 1); R2_GLOBALS._player.setPosition(Common::Point(247, 169)); - _actor16.setPosition(Common::Point(213, 169)); + _seeker.setPosition(Common::Point(213, 169)); } else { R2_GLOBALS._player.setup(1107, 4, 1); - _actor16.setup(1107, 2, 1); + _seeker.setup(1107, 2, 1); R2_GLOBALS._player.setPosition(Common::Point(213, 169)); - _actor16.setPosition(Common::Point(247, 169)); + _seeker.setPosition(Common::Point(247, 169)); } R2_GLOBALS._player.enableControl(); R2_GLOBALS._player._canWalk = false; } if (R2_GLOBALS._player._characterIndex == 1) - _actor16.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); + _seeker.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); else - _actor16.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); + _seeker.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); - _actor18.postInit(); - _actor18.setup(1113, 3, 1); - _actor18.setPosition(Common::Point(181, 125)); - _actor18.fixPriority(110); + _chief.postInit(); + _chief.setup(1113, 3, 1); + _chief.setPosition(Common::Point(181, 125)); + _chief.fixPriority(110); if (R2_GLOBALS.getFlag(54)) - _actor18.setDetails(1100, 4, -1, -1, 1, (SceneItem *) NULL); + _chief.setDetails(1100, 4, -1, -1, 1, (SceneItem *) NULL); else - _actor18.setDetails(1100, 3, -1, -1, 1, (SceneItem *) NULL); + _chief.setDetails(1100, 3, -1, -1, 1, (SceneItem *) NULL); if (!R2_GLOBALS.getFlag(52)) { - _actor17.postInit(); + _trooper.postInit(); if (R2_GLOBALS.getFlag(53)) - _actor17.setup(1106, 2, 4); + _trooper.setup(1106, 2, 4); else - _actor17.setup(1105, 4, 4); + _trooper.setup(1105, 4, 4); - _actor17.setPosition(Common::Point(17, 54)); - _actor17._numFrames = 5; + _trooper.setPosition(Common::Point(17, 54)); + _trooper._numFrames = 5; if (R2_GLOBALS.getFlag(53)) - _actor17.setDetails(1100, 28, -1, -1, 1, (SceneItem *) NULL); + _trooper.setDetails(1100, 28, -1, -1, 1, (SceneItem *) NULL); else - _actor17.setDetails(1100, 22, 23, 24, 1, (SceneItem *) NULL); + _trooper.setDetails(1100, 22, 23, 24, 1, (SceneItem *) NULL); - _actor17.fixPriority(200); + _trooper.fixPriority(200); } _actor1.postInit(); _actor1.setup(1512, 1, 1); @@ -583,9 +1026,9 @@ void Scene1100::signal() { } break; case 4: - _actor18.postInit(); - _actor18.show(); - setAction(&_sequenceManager1, this, 1101, &_actor18, &_actor10, NULL); + _chief.postInit(); + _chief.show(); + setAction(&_sequenceManager1, this, 1101, &_chief, &_actor10, NULL); break; case 5: _actor13.postInit(); @@ -611,15 +1054,15 @@ void Scene1100::signal() { } break; case 7: - setAction(&_sequenceManager1, this, 1103, &_actor18, &_actor10); + setAction(&_sequenceManager1, this, 1103, &_chief, &_actor10); break; case 8: R2_GLOBALS._player._effect = 0; _actor11.postInit(); - setAction(&_sequenceManager1, this, 1105, &R2_GLOBALS._player, &_actor10, &_actor11, &_actor18, NULL); + setAction(&_sequenceManager1, this, 1105, &R2_GLOBALS._player, &_actor10, &_actor11, &_chief, NULL); break; case 9: - _object1.proc27(); + _object1.copySceneToBackground(); _actor15.postInit(); _actor15.setup(1103, 2, 1); @@ -633,7 +1076,7 @@ void Scene1100::signal() { _actor13.setAction(&_sequenceManager2, this, 1108, &_actor13, NULL); break; case 11: { - setAction(&_sequenceManager1, this, 1116, &_actor11, &_actor10, &_actor12, NULL); + setAction(&_sequenceManager1, this, 1106, &_actor11, &_actor10, &_actor12, NULL); R2_GLOBALS._player._effect = 5; R2_GLOBALS._player.setup(1102, 3, 2); R2_GLOBALS._player.setPosition(Common::Point(-50, 131)); @@ -647,8 +1090,8 @@ void Scene1100::signal() { // Really nothing break; case 13: - _actor17.postInit(); - R2_GLOBALS._scrollFollower = &_actor17; + _trooper.postInit(); + R2_GLOBALS._scrollFollower = &_trooper; _actor11.setup(1100, 2, 1); _actor11.setPosition(Common::Point(408, 121)); @@ -656,7 +1099,7 @@ void Scene1100::signal() { _actor10.setup(1100, 3, 5); _actor10.setPosition(Common::Point(409, 121)); - setAction(&_sequenceManager1, this, 1104, &_actor17, NULL); + setAction(&_sequenceManager1, this, 1104, &_trooper, NULL); break; case 14: setAction(&_sequenceManager1, this, 1100, &_actor11, &_actor10, NULL); @@ -672,14 +1115,14 @@ void Scene1100::signal() { break; case 21: { R2_GLOBALS._sound2.play(92); - _actor17.animate(ANIM_MODE_5, NULL); + _trooper.animate(ANIM_MODE_5, NULL); Common::Point pt(187, 45); NpcMover *mover = new NpcMover(); _actor1.addMover(mover, &pt, this); } break; case 22: - setAction(&_sequenceManager1, this, 1110, &_actor16, &R2_GLOBALS._player, NULL); + setAction(&_sequenceManager1, this, 1110, &_seeker, &R2_GLOBALS._player, NULL); break; case 23: R2_GLOBALS._player.disableControl(); @@ -693,34 +1136,37 @@ void Scene1100::signal() { break; case 25: R2_GLOBALS._player.disableControl(); - _stripManager._lookupList[9] = 1; - _stripManager._lookupList[10] = 1; - _stripManager._lookupList[11] = 1; + R2_GLOBALS._stripManager_lookupList[9] = 1; + R2_GLOBALS._stripManager_lookupList[10] = 1; + R2_GLOBALS._stripManager_lookupList[11] = 1; R2_GLOBALS._sound1.play(95); - setAction(&_sequenceManager1, this, 1111, &_actor17, &R2_GLOBALS._player, &_actor16, NULL); + setAction(&_sequenceManager1, this, 1111, &_trooper, &R2_GLOBALS._player, &_seeker, NULL); break; case 26: R2_GLOBALS._player.disableControl(); - R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); + R2_GLOBALS._events.setCursor(CURSOR_ARROW); _stripManager.start(302, this); break; case 27: R2_GLOBALS._player.disableControl(); - setAction(&_sequenceManager1, this, 1120, &_actor16, &R2_GLOBALS._player, NULL); + setAction(&_sequenceManager1, this, 1120, &_seeker, &R2_GLOBALS._player, NULL); break; case 28: R2_GLOBALS._player.disableControl(); - R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); + R2_GLOBALS._events.setCursor(CURSOR_ARROW); _stripManager.start(303, this); break; + case 29: + case 50: + R2_GLOBALS._player.enableControl(CURSOR_USE); + R2_GLOBALS._player._canWalk = false; + break; case 51: R2_GLOBALS.setFlag(53); - _actor17.setDetails(1100, 28, -1, -1, 3, (SceneItem *) NULL); - // No break on purpose - case 50: - // No break on purpose - case 29: + _trooper.setDetails(1100, 28, -1, -1, 3, (SceneItem *) NULL); + R2_GLOBALS._player.enableControl(CURSOR_USE); + R2_GLOBALS._player._canWalk = false; break; case 52: R2_GLOBALS._sound1.play(98); @@ -729,10 +1175,10 @@ void Scene1100::signal() { _sceneMode = 1116; if (R2_GLOBALS._player._characterIndex == 1) { setAction(&_sequenceManager1, this, 1116, &R2_GLOBALS._player, NULL); - _actor16.setAction(&_sequenceManager2, NULL, 1123, &_actor16, NULL); + _seeker.setAction(&_sequenceManager2, NULL, 1123, &_seeker, NULL); } else { setAction(&_sequenceManager1, this, 1124, &R2_GLOBALS._player, NULL); - _actor16.setAction(&_sequenceManager2, NULL, 1117, &_actor16, NULL); + _seeker.setAction(&_sequenceManager2, NULL, 1117, &_seeker, NULL); } break; case 53: @@ -757,10 +1203,10 @@ void Scene1100::signal() { } break; case 54: - if (_stripManager._field2E8 == 1) { + if (_stripManager._exitMode == 1) { R2_GLOBALS._player.disableControl(); _sceneMode = 1125; - setAction(&_sequenceManager1, this, 1125, &R2_GLOBALS._player, &_actor16, NULL); + setAction(&_sequenceManager1, this, 1125, &R2_GLOBALS._player, &_seeker, NULL); } else R2_GLOBALS._player.enableControl(CURSOR_TALK); break; @@ -801,9 +1247,9 @@ void Scene1100::signal() { break; case 1116: R2_GLOBALS._player.enableControl(CURSOR_ARROW); - _stripManager._lookupList[9] = 1; - _stripManager._lookupList[10] = 1; - _stripManager._lookupList[11] = 1; + R2_GLOBALS._stripManager_lookupList[9] = 1; + R2_GLOBALS._stripManager_lookupList[10] = 1; + R2_GLOBALS._stripManager_lookupList[11] = 1; break; case 1125: { _sceneMode = 99; @@ -858,16 +1304,17 @@ void Scene1100::saveCharacter(int characterIndex) { } /*-------------------------------------------------------------------------- - * Scene 1200 - + * Scene 1200 - Air Ducts Maze * *--------------------------------------------------------------------------*/ + Scene1200::Scene1200() { _field412 = 0; _field414 = 0; _field416 = 0; _field418 = 0; _field41A = 0; - _field41C = 1; //CHECKME: Only if fixup_flag == 6?? + _fixupMaze = false; } void Scene1200::synchronize(Serializer &s) { @@ -878,20 +1325,13 @@ void Scene1200::synchronize(Serializer &s) { s.syncAsSint16LE(_field416); s.syncAsSint16LE(_field418); s.syncAsSint16LE(_field41A); - s.syncAsSint16LE(_field41C); + s.syncAsSint16LE(_fixupMaze); } -Scene1200::Area1::Area1() { - _field20 = 0; -} - -void Scene1200::Area1::synchronize(Serializer &s) { - SceneArea::synchronize(s); - - s.syncAsByte(_field20); +Scene1200::LaserPanel::LaserPanel() { } -void Scene1200::Area1::Actor3::init(int state) { +void Scene1200::LaserPanel::Jumper::init(int state) { _state = state; SceneActor::postInit(); @@ -912,6 +1352,7 @@ void Scene1200::Area1::Actor3::init(int state) { default: break; } + break; case 2: switch (R2_GLOBALS._v56AA7) { case 1: @@ -929,6 +1370,7 @@ void Scene1200::Area1::Actor3::init(int state) { default: break; } + break; case 3: switch (R2_GLOBALS._v56AA8) { case 1: @@ -942,6 +1384,7 @@ void Scene1200::Area1::Actor3::init(int state) { default: break; } + break; default: break; } @@ -949,7 +1392,7 @@ void Scene1200::Area1::Actor3::init(int state) { setDetails(1200, 12, -1, -1, 2, (SceneItem *) NULL); } -bool Scene1200::Area1::Actor3::startAction(CursorType action, Event &event) { +bool Scene1200::LaserPanel::Jumper::startAction(CursorType action, Event &event) { if (action != CURSOR_USE) return SceneActor::startAction(action, event); @@ -1018,7 +1461,7 @@ bool Scene1200::Area1::Actor3::startAction(CursorType action, Event &event) { return true; } -void Scene1200::Area1::postInit(SceneObjectList *OwnerList) { +void Scene1200::LaserPanel::postInit(SceneObjectList *OwnerList) { Scene1200 *scene = (Scene1200 *)R2_GLOBALS._sceneManager._scene; scene->_field41A = 1; @@ -1026,81 +1469,35 @@ void Scene1200::Area1::postInit(SceneObjectList *OwnerList) { proc12(1003, 1, 1, 100, 40); proc13(1200, 11, -1, -1); R2_GLOBALS._sound2.play(259); - _actor3.init(1); - _actor4.init(2); - _actor5.init(3); + _jumper1.init(1); + _jumper2.init(2); + _jumper3.init(3); R2_GLOBALS._player._canWalk = false; } -void Scene1200::Area1::remove() { +void Scene1200::LaserPanel::remove() { Scene1200 *scene = (Scene1200 *)R2_GLOBALS._sceneManager._scene; scene->_field41A = 0; warning("Unexpected _sceneAreas.remove() call"); -// scene->_sceneAreas.remove(&_actor3); -// scene->_sceneAreas.remove(&_actor4); -// scene->_sceneAreas.remove(&_actor5); - _actor3.remove(); - _actor4.remove(); - _actor5.remove(); +// scene->_sceneAreas.remove(&_jumper1); +// scene->_sceneAreas.remove(&_jumper2); +// scene->_sceneAreas.remove(&_jumper3); + _jumper1.remove(); + _jumper2.remove(); + _jumper3.remove(); // sub201EA R2_GLOBALS._sceneItems.remove((SceneItem *)this); - _actor2.remove(); + _object1.remove(); SceneArea::remove(); R2_GLOBALS._insetUp--; - // R2_GLOBALS._player._canWalk = true; } -void Scene1200::Area1::process(Event &event) { - if (_field20 != R2_GLOBALS._insetUp) - return; - - CursorType cursor = R2_GLOBALS._events.getCursor(); - - if (_actor2._bounds.contains(event.mousePos.x + g_globals->gfxManager()._bounds.left , event.mousePos.y)) { - if (cursor == _cursorNum) { - warning("TODO: _cursorState = ???"); - R2_GLOBALS._events.setCursor(_savedCursorNum); //, _cursorState); - } - } else if (event.mousePos.y < 168) { - if (cursor != _cursorNum) { - _savedCursorNum = cursor; - warning("TODO: _cursorState = ???"); - R2_GLOBALS._events.setCursor(CURSOR_INVALID); - } - if (event.eventType == EVENT_BUTTON_DOWN) { - event.handled = true; - warning("TODO: _cursorState = ???"); - R2_GLOBALS._events.setCursor(_savedCursorNum); //, _cursorState); - remove(); - } - } -} - -void Scene1200::Area1::proc12(int visage, int stripFrameNum, int frameNum, int posX, int posY) { - Scene1200 *scene = (Scene1200 *)R2_GLOBALS._sceneManager._scene; - - _actor2.postInit(); - _actor2.setup(visage, stripFrameNum, frameNum); - _actor2.setPosition(Common::Point(posX, posY)); - _actor2.fixPriority(250); - _cursorNum = CURSOR_INVALID; - scene->_sceneAreas.push_front(this); - ++R2_GLOBALS._insetUp; - _field20 = R2_GLOBALS._insetUp; -} - -void Scene1200::Area1::proc13(int resNum, int lookLineNum, int talkLineNum, int useLineNum) { - _actor2.setDetails(resNum, lookLineNum, talkLineNum, useLineNum, 2, (SceneItem *) NULL); -} - void Scene1200::postInit(SceneObjectList *OwnerList) { - Rect tmpRect; - loadScene(1200); SceneExt::postInit(); @@ -1112,7 +1509,6 @@ void Scene1200::postInit(SceneObjectList *OwnerList) { _field416 = 0; _field418 = 0; _field41A = 0; - _field41C = 0; if ((R2_GLOBALS._v56AA6 == 1) && (R2_GLOBALS._v56AA7 == 1) && (R2_GLOBALS._v56AA8 == 1)) _field418 = 1; @@ -1133,14 +1529,10 @@ void Scene1200::postInit(SceneObjectList *OwnerList) { _actor1.postInit(); _actor1.hide(); - tmpRect.set(110, 20, 210, 120); - _object1.sub9EDE8(tmpRect); + _mazeUI.setDisplayBounds(Rect(110, 20, 210, 120)); - _object1.sub51AE9(1); - _object1.sub51AFD(Common::Point(R2_GLOBALS._v56AA2, R2_GLOBALS._v56AA4)); - warning("int unk = set_pane_p(_paneNumber);"); - _object1.sub51B02(); - warning("set_pane_p(unk);"); + _mazeUI.load(1); + _mazeUI.setMazePosition(Common::Point(R2_GLOBALS._v56AA2, R2_GLOBALS._v56AA4)); R2_GLOBALS._player.enableControl(); _item1.setDetails(Rect(0, 0, 320, 200), 1200, 0, 1, 2, 1, NULL); @@ -1337,7 +1729,7 @@ void Scene1200::signal() { case 111: // No break on purpose case 116: - R2_GLOBALS._player.setup(3157, 3, 1); + R2_GLOBALS._player.setup(3157, 4, 1); R2_GLOBALS._player.animate(ANIM_MODE_5, this); break; case 78: @@ -1396,50 +1788,52 @@ void Scene1200::process(Event &event) { return; if (event.eventType == EVENT_BUTTON_DOWN) { - _object1.sub9EE22(R2_GLOBALS._v56AA2, R2_GLOBALS._v56AA4); - int unk = _object1.sub51AF8(event.mousePos); + Common::Point cellPos(R2_GLOBALS._v56AA2, R2_GLOBALS._v56AA4); + _mazeUI.pixelToCellXY(cellPos); + + int cellId = _mazeUI.getCellFromPixelXY(event.mousePos); switch (R2_GLOBALS._events.getCursor()) { - case CURSOR_ARROW: + case CURSOR_WALK: event.handled = true; if ((event.mousePos.x > 179) && (event.mousePos.x < 210) && (event.mousePos.y > 50) && (event.mousePos.y < 89)) - sub9DAD6(1); + startCrawling(CRAWL_EAST); if ((event.mousePos.x > 109) && (event.mousePos.x < 140) && (event.mousePos.y > 50) && (event.mousePos.y < 89)) - sub9DAD6(2); + startCrawling(CRAWL_WEST); if ((event.mousePos.x > 140) && (event.mousePos.x < 179) && (event.mousePos.y > 89) && (event.mousePos.y < 120)) - sub9DAD6(3); + startCrawling(CRAWL_SOUTH); if ((event.mousePos.x > 140) && (event.mousePos.x < 179) && (event.mousePos.y > 19) && (event.mousePos.y < 50)) - sub9DAD6(4); + startCrawling(CRAWL_NORTH); break; case CURSOR_USE: - if (unk > 36) { - if ( ((R2_GLOBALS._v56AA2 == 3) && (R2_GLOBALS._v56AA4 == 33)) - || ((R2_GLOBALS._v56AA2 == 7) && (R2_GLOBALS._v56AA4 == 33)) - || ((R2_GLOBALS._v56AA2 == 33) && (R2_GLOBALS._v56AA4 == 41)) - || ((R2_GLOBALS._v56AA2 == 5) && (R2_GLOBALS._v56AA4 == 5)) - || ((R2_GLOBALS._v56AA2 == 13) && (R2_GLOBALS._v56AA4 == 21)) - || ((R2_GLOBALS._v56AA2 == 17) && (R2_GLOBALS._v56AA4 == 21)) - || ((R2_GLOBALS._v56AA2 == 17) && (R2_GLOBALS._v56AA4 == 5)) - || ((R2_GLOBALS._v56AA2 == 17) && (R2_GLOBALS._v56AA4 == 9)) - || ((R2_GLOBALS._v56AA2 == 29) && (R2_GLOBALS._v56AA4 == 17)) - || ((R2_GLOBALS._v56AA2 == 33) && (R2_GLOBALS._v56AA4 == 17)) - || ((R2_GLOBALS._v56AA2 == 35) && (R2_GLOBALS._v56AA4 == 17)) - || ((R2_GLOBALS._v56AA2 == 41) && (R2_GLOBALS._v56AA4 == 21)) ) { - _area1.postInit(); + if (cellId > 36) { + if ( ((cellPos.x == 3) && (cellPos.y == 33)) + || ((cellPos.x == 7) && (cellPos.y == 33)) + || ((cellPos.x == 33) && (cellPos.y == 41)) + || ((cellPos.x == 5) && (cellPos.y == 5)) + || ((cellPos.x == 13) && (cellPos.y == 21)) + || ((cellPos.x == 17) && (cellPos.y == 21)) + || ((cellPos.x == 17) && (cellPos.y == 5)) + || ((cellPos.x == 17) && (cellPos.y == 9)) + || ((cellPos.x == 29) && (cellPos.y == 17)) + || ((cellPos.x == 33) && (cellPos.y == 17)) + || ((cellPos.x == 35) && (cellPos.y == 17)) + || ((cellPos.x == 41) && (cellPos.y == 21)) ) { + _laserPanel.postInit(); event.handled = true; } } - if ((unk == 1) || (unk == 4) || (unk == 11) || (unk == 14)) { - if ( ((R2_GLOBALS._v56AA2 == 3) && (R2_GLOBALS._v56AA4 == 9)) - || ((R2_GLOBALS._v56AA2 == 11) && (R2_GLOBALS._v56AA4 == 27)) - || ((R2_GLOBALS._v56AA2 == 17) && (R2_GLOBALS._v56AA4 == 7)) - || ((R2_GLOBALS._v56AA2 == 17) && (R2_GLOBALS._v56AA4 == 27)) - || ((R2_GLOBALS._v56AA2 == 17) && (R2_GLOBALS._v56AA4 == 33)) - || (R2_GLOBALS._v56AA2 == 33) ) { - switch (R2_GLOBALS._v56AA2) { + if ((cellId == 1) || (cellId == 4) || (cellId == 11) || (cellId == 14)) { + if ( ((cellPos.x == 3) && (cellPos.y == 9)) + || ((cellPos.x == 11) && (cellPos.y == 27)) + || ((cellPos.x == 17) && (cellPos.y == 7)) + || ((cellPos.x == 17) && (cellPos.y == 27)) + || ((cellPos.x == 17) && (cellPos.y == 33)) + || (cellPos.x == 33) ) { + switch (cellPos.x) { case 3: R2_GLOBALS._sceneManager.changeScene(3150); break; @@ -1458,23 +1852,25 @@ void Scene1200::process(Event &event) { } break; case CURSOR_LOOK: - if ((unk == 1) || (unk == 4) || (unk == 11) || (unk == 14)) { + if ((cellId == 1) || (cellId == 4) || (cellId == 11) || (cellId == 14)) { event.handled = true; - switch (R2_GLOBALS._v56AA2) { + switch (cellPos.x) { case 3: + // It was your cell. SceneItem::display(1200, 8, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); break; case 9: R2_GLOBALS._sceneManager.changeScene(3240); break; case 11: - if (R2_GLOBALS._v56AA4 == 27) + if (cellPos.y == 27) R2_GLOBALS._sceneManager.changeScene(3210); else + // A vent grill SceneItem::display(1200, 10, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); break; case 17: - switch (R2_GLOBALS._v56AA4) { + switch (cellPos.y) { case 5: R2_GLOBALS._sceneManager.changeScene(3230); break; @@ -1485,6 +1881,7 @@ void Scene1200::process(Event &event) { R2_GLOBALS._sceneManager.changeScene(3200); break; default: + // A vent grill SceneItem::display(1200, 10, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); break; } @@ -1496,7 +1893,8 @@ void Scene1200::process(Event &event) { break; } } - if (unk > 36) { + if (cellId > 36) { + // "An anti-pest laser" event.handled = true; SceneItem::display(1200, 9, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); } @@ -1516,19 +1914,19 @@ void Scene1200::process(Event &event) { switch (event.kbd.keycode) { case Common::KEYCODE_1: warning("FIXME: keycode = 0x4800"); - sub9DAD6(4); + startCrawling(CRAWL_NORTH); break; case Common::KEYCODE_2: warning("FIXME: keycode = 0x4B00"); - sub9DAD6(2); + startCrawling(CRAWL_WEST); break; case Common::KEYCODE_3: warning("FIXME: keycode = 0x4D00"); - sub9DAD6(1); + startCrawling(CRAWL_EAST); break; case Common::KEYCODE_4: warning("FIXME: keycode = 0x5000"); - sub9DAD6(3); + startCrawling(CRAWL_SOUTH); break; default: event.handled = false; @@ -1543,13 +1941,13 @@ void Scene1200::process(Event &event) { void Scene1200::dispatch() { Rect tmpRect; Scene::dispatch(); - if (_field41C != 0) { - _object1.sub51AFD(Common::Point(R2_GLOBALS._v56AA2, R2_GLOBALS._v56AA4)); - warning("int unk = set_pane_p(_paneNumber);"); - _object1.sub51B02(); + + if (_fixupMaze) { + _mazeUI.setMazePosition(Common::Point(R2_GLOBALS._v56AA2, R2_GLOBALS._v56AA4)); + warning("_gfxManager.sub294AC(unk);"); warning("tmpRect.sub14DF3();"); - _field41C = 0; + _fixupMaze = false; } if (_field414 != 0) { @@ -1571,11 +1969,10 @@ void Scene1200::dispatch() { default: break; } - _object1.sub51AFD(Common::Point(R2_GLOBALS._v56AA2, R2_GLOBALS._v56AA4)); - warning("int unk = set_pane_p(_paneNumber);"); - _object1.sub51B02(); - warning("_gfxManager.sub294AC(unk);"); - warning("tmpRect.sub14DF3();"); + _mazeUI.setMazePosition(Common::Point(R2_GLOBALS._v56AA2, R2_GLOBALS._v56AA4)); + + debug("_gfxManager.sub294AC(unk);"); + debug("tmpRect.sub14DF3();"); if (_field416 != 0) { switch(_field412 - 1) { @@ -1608,6 +2005,190 @@ void Scene1200::saveCharacter(int characterIndex) { SceneExt::saveCharacter(characterIndex); } +void Scene1200::startCrawling(CrawlDirection dir) { + Common::Point cellPos = Common::Point(R2_GLOBALS._v56AA2, R2_GLOBALS._v56AA4); + _mazeUI.pixelToCellXY(cellPos); + + switch (dir) { + case CRAWL_EAST: + if ( ((_mazeUI.getCellFromPixelXY(Common::Point(200, 50)) > 36) || (_mazeUI.getCellFromPixelXY(Common::Point(200, 88)) > 36)) + && ( ((cellPos.x == 3) && (cellPos.y == 33) && (_field418 != 4)) + || ((cellPos.x == 13) && (cellPos.y == 21) && (_field418 != 2)) + || ((cellPos.x == 29) && (cellPos.y == 17) && (_field418 != 1)) + || ((cellPos.x == 33) && (cellPos.y == 41)) ) + ) { + R2_GLOBALS._player.disableControl(); + _sceneMode = 1200; + setAction(&_sequenceManager, this, 1200, &_actor1, NULL); + } else if (_mazeUI.getCellFromPixelXY(Common::Point(200, 69)) == 36) { + switch (_field412 - 1) { + case 0: + if (R2_GLOBALS._player._visage == 3155) + _sceneMode = 15; + else + _sceneMode = 10; + break; + case 1: + if (R2_GLOBALS._player._visage == 3156) + _sceneMode = 76; + else + _sceneMode = 75; + break; + case 2: + if (R2_GLOBALS._player._visage == 3156) + _sceneMode = 101; + else + _sceneMode = 100; + break; + case 3: + if (R2_GLOBALS._player._visage == 3156) + _sceneMode = 111; + else + _sceneMode = 110; + break; + default: + break; + } + R2_GLOBALS._player.disableControl(); + _field412 = 1; + signal(); + } + break; + case CRAWL_WEST: + if ( ((_mazeUI.getCellFromPixelXY(Common::Point(120, 50)) > 36) || (_mazeUI.getCellFromPixelXY(Common::Point(120, 88)) > 36)) + && ( ((cellPos.x == 7) && (cellPos.y == 33) && (_field418 != 4)) + || ((cellPos.x == 17) && (cellPos.y == 21) && (_field418 != 2)) + || ((cellPos.x == 33) && (cellPos.y == 17) && (_field418 != 1)) + || ((cellPos.x == 5) && (cellPos.y == 5)) ) + ) { + R2_GLOBALS._player.disableControl(); + _sceneMode = 1201; + setAction(&_sequenceManager, this, 1201, &_actor1, NULL); + } else if (_mazeUI.getCellFromPixelXY(Common::Point(120, 69)) == 36) { + switch (_field412 - 1) { + case 0: + if (R2_GLOBALS._player._visage == 3156) + _sceneMode = 56; + else + _sceneMode = 55; + break; + case 1: + if (R2_GLOBALS._player._visage == 3155) + _sceneMode = 25; + else + _sceneMode = 20; + break; + case 2: + if (R2_GLOBALS._player._visage == 3156) + _sceneMode = 91; + else + _sceneMode = 90; + break; + case 3: + if (R2_GLOBALS._player._visage == 3156) + _sceneMode = 121; + else + _sceneMode = 120; + break; + default: + break; + } + R2_GLOBALS._player.disableControl(); + _field412 = 2; + signal(); + } + break; + case CRAWL_SOUTH: + if ( ((_mazeUI.getCellFromPixelXY(Common::Point(140, 110)) > 36) || (_mazeUI.getCellFromPixelXY(Common::Point(178, 110)) > 36)) + && ( ((cellPos.x == 17) && (cellPos.y == 5) && (_field418 != 3)) + || ((cellPos.x == 41) && (cellPos.y == 21)) ) + ) { + R2_GLOBALS._player.disableControl(); + _sceneMode = 1203; + setAction(&_sequenceManager, this, 1203, &_actor1, NULL); + } else if (_mazeUI.getCellFromPixelXY(Common::Point(160, 110)) == 36) { + switch (_field412 - 1) { + case 0: + if (R2_GLOBALS._player._visage == 3156) + _sceneMode = 51; + else + _sceneMode = 50; + break; + case 1: + if (R2_GLOBALS._player._visage == 3156) + _sceneMode = 81; + else + _sceneMode = 80; + break; + case 2: + if (R2_GLOBALS._player._visage == 3155) + _sceneMode = 35; + else + _sceneMode = 30; + break; + case 3: + if (R2_GLOBALS._player._visage == 3156) + _sceneMode = 116; + else + _sceneMode = 115; + break; + default: + break; + } + R2_GLOBALS._player.disableControl(); + _field412 = 3; + signal(); + } + break; + case CRAWL_NORTH: + if ( ((_mazeUI.getCellFromPixelXY(Common::Point(140, 30)) > 36) || (_mazeUI.getCellFromPixelXY(Common::Point(178, 30)) > 36)) + && ( ((cellPos.x == 17) && (cellPos.y == 9) && (_field418 != 3)) + || ((cellPos.x == 35) && (cellPos.y == 17)) ) + ) { + R2_GLOBALS._player.disableControl(); + _sceneMode = 1202; + setAction(&_sequenceManager, this, 1202, &_actor1, NULL); + } else if (_mazeUI.getCellFromPixelXY(Common::Point(160, 30)) == 36) { + switch (_field412 - 1) { + case 0: + if (R2_GLOBALS._player._visage == 3156) + _sceneMode = 61; + else + _sceneMode = 60; + break; + case 1: + if (R2_GLOBALS._player._visage == 3156) + _sceneMode = 71; + else + _sceneMode = 70; + break; + case 2: + if (R2_GLOBALS._player._visage == 3156) + _sceneMode = 96; + else + _sceneMode = 95; + break; + case 3: + if (R2_GLOBALS._player._visage == 3155) + _sceneMode = 45; + else + _sceneMode = 40; + break; + default: + _sceneMode = 1; + R2_GLOBALS._player.setup(3156, 4, 6); + break; + } + R2_GLOBALS._player.disableControl(); + _field412 = 4; + signal(); + } + break; + default: + break; + } +} + /*-------------------------------------------------------------------------- * Scene 1337 - Card game * @@ -6924,7 +7505,7 @@ void Scene1550::UnkArea1550::remove() { } void Scene1550::UnkArea1550::process(Event &event) { -// This is a copy of Scene1200::Area1::process +// This is a copy of Scene1200::LaserPanel::process if (_field20 != R2_GLOBALS._insetUp) return; @@ -6988,7 +7569,7 @@ void Scene1550::UnkArea1550::proc12(int visage, int stripFrameNum, int frameNum, } void Scene1550::UnkArea1550::proc13(int resNum, int lookLineNum, int talkLineNum, int useLineNum) { - // Copy of Scene1200::Area1::proc13 + // Copy of Scene1200::LaserPanel::proc13 _areaActor.setDetails(resNum, lookLineNum, talkLineNum, useLineNum, 2, (SceneItem *) NULL); } @@ -8751,7 +9332,7 @@ void Scene1575::Hotspot1::process(Event &event) { di -= 2; scene->_field41A -= 2; - for (int i = 0; i < 178; i++) + for (int i = 0; i < 17; i++) scene->_arrActor[i].setPosition(Common::Point(scene->_arrActor[i]._position.x - 2, scene->_arrActor[i]._position.y)); scene->_actor13.setPosition(Common::Point(scene->_actor13._position.x - 2, scene->_actor13._position.y)); @@ -12947,7 +13528,7 @@ void Scene1950::Area1::remove() { } void Scene1950::Area1::process(Event &event) { -// This is a copy of Scene1200::Area1::process +// This is a copy of Scene1200::LaserPanel::process if (_field20 != R2_GLOBALS._insetUp) return; @@ -13000,7 +13581,7 @@ void Scene1950::Area1::proc12(int visage, int stripFrameNum, int frameNum, int p } void Scene1950::Area1::proc13(int resNum, int lookLineNum, int talkLineNum, int useLineNum) { - // Copy of Scene1200::Area1::proc13() + // Copy of Scene1200::LaserPanel::proc13() _areaActor.setDetails(resNum, lookLineNum, talkLineNum, useLineNum, 2, (SceneItem *) NULL); } diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.h b/engines/tsage/ringworld2/ringworld2_scenes1.h index f65a89972d..eaca667377 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes1.h +++ b/engines/tsage/ringworld2/ringworld2_scenes1.h @@ -39,6 +39,24 @@ namespace Ringworld2 { using namespace TsAGE; +class Scene1000 : public SceneExt { +public: + SequenceManager _sequenceManager1; + SequenceManager _sequenceManager2; + SpeakerGameText _gameTextSpeaker; + AnimationPlayer _animationPlayer; + + int _field412; + int _fieldD2E; +public: + Scene1000(); + + virtual void postInit(SceneObjectList *OwnerList = NULL); + virtual void remove(); + virtual void signal(); + virtual void dispatch(); +}; + class Scene1010 : public SceneExt { public: SequenceManager _sequenceManager; @@ -57,15 +75,15 @@ public: }; class Scene1100 : public SceneExt { - class Actor16 : public SceneActor { + class Seeker : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor17 : public SceneActor { + class Trooper : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor18 : public SceneActor { + class Chief : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -100,9 +118,9 @@ public: SceneActor _actor15; BackgroundSceneObject _object1; BackgroundSceneObject _object2; - Actor16 _actor16; - Actor17 _actor17; - Actor18 _actor18; + Seeker _seeker; + Trooper _trooper; + Chief _chief; SequenceManager _sequenceManager1; SequenceManager _sequenceManager2; SequenceManager _sequenceManager3; @@ -118,36 +136,31 @@ public: }; class Scene1200 : public SceneExt { - class Area1: public SceneArea { + enum CrawlDirection { CRAWL_EAST = 1, CRAWL_WEST = 2, CRAWL_SOUTH = 3, CRAWL_NORTH = 4 }; + + class LaserPanel: public ModalWindow { public: - class Actor3 : public SceneActorExt { + class Jumper : public SceneActorExt { public: void init(int state); virtual bool startAction(CursorType action, Event &event); }; - SceneActor _actor2; - Actor3 _actor3; - Actor3 _actor4; - Actor3 _actor5; + Jumper _jumper1; + Jumper _jumper2; + Jumper _jumper3; - byte _field20; - - Area1(); - void synchronize(Serializer &s); + LaserPanel(); virtual void postInit(SceneObjectList *OwnerList = NULL); virtual void remove(); - virtual void process(Event &event); - virtual void proc12(int visage, int stripFrameNum, int frameNum, int posX, int posY); - virtual void proc13(int resNum, int lookLineNum, int talkLineNum, int useLineNum); }; public: NamedHotspot _item1; SceneActor _actor1; - Area1 _area1; - UnkObject1200 _object1; + LaserPanel _laserPanel; + MazeUI _mazeUI; SequenceManager _sequenceManager; int _field412; @@ -155,12 +168,12 @@ public: int _field416; int _field418; int _field41A; - int _field41C; + bool _fixupMaze; Scene1200(); void synchronize(Serializer &s); - void sub9DAD6(int indx); + void startCrawling(CrawlDirection dir); virtual void postInit(SceneObjectList *OwnerList = NULL); virtual void signal(); diff --git a/engines/tsage/ringworld2/ringworld2_scenes2.cpp b/engines/tsage/ringworld2/ringworld2_scenes2.cpp index 6a030e5b44..9246c4b6a4 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes2.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes2.cpp @@ -630,6 +630,7 @@ void Scene2000::Exit3::changeScene() { break; } } + void Scene2000::Exit4::changeScene() { Scene2000 *scene = (Scene2000 *)R2_GLOBALS._sceneManager._scene; @@ -756,19 +757,21 @@ void Scene2000::Exit5::changeScene() { } } -void Scene2000::postInit(SceneObjectList *OwnerList) { - SceneExt::postInit(); - loadScene(2000); - +Scene2000::Scene2000(): SceneExt() { if (R2_GLOBALS._sceneManager._previousScene != -1) { R2_GLOBALS._v56605[1] = 21; R2_GLOBALS._v56605[2] = 21; } - if ((R2_GLOBALS._player._characterScene[R2_GLOBALS._player._characterIndex] != R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex]) && (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] != 2350)) { + if ((R2_GLOBALS._player._characterScene[R2_GLOBALS._player._characterIndex] + != R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex]) + && (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] != 2350)) { R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] = 0; } + _exitingFlag = false; +} +void Scene2000::postInit(SceneObjectList *OwnerList) { _exit1.setDetails(Rect(0, 100, 14, 140), EXITCURSOR_W, 2000); _exit1.setDest(Common::Point(14, 129)); _exit2.setDetails(Rect(305, 100, 320, 140), EXITCURSOR_E, 2000); @@ -917,6 +920,8 @@ void Scene2000::postInit(SceneObjectList *OwnerList) { initPlayer(); _item1.setDetails(Rect(0, 0, 320, 200), 2000, 0, -1, 23, 1, NULL); + + SceneExt::postInit(); } void Scene2000::remove() { @@ -998,6 +1003,8 @@ void Scene2000::signal() { g_globals->_sceneManager.changeScene(2350); break; default: + R2_GLOBALS._v56AAB = 0; + R2_GLOBALS._player.enableControl(); break; } } diff --git a/engines/tsage/ringworld2/ringworld2_scenes2.h b/engines/tsage/ringworld2/ringworld2_scenes2.h index 281d1da366..feceaa1537 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes2.h +++ b/engines/tsage/ringworld2/ringworld2_scenes2.h @@ -80,6 +80,7 @@ public: Action1 _action1, _action2, _action3, _action4, _action5; SequenceManager _sequenceManager; + Scene2000(); virtual void postInit(SceneObjectList *OwnerList = NULL); virtual void remove(); virtual void signal(); diff --git a/engines/tsage/ringworld2/ringworld2_scenes3.cpp b/engines/tsage/ringworld2/ringworld2_scenes3.cpp index 61711d0a4f..6af2a0cad4 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes3.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes3.cpp @@ -2885,9 +2885,10 @@ void Scene3400::signal() { } /*-------------------------------------------------------------------------- - * Scene 3500 - + * Scene 3500 - Cavern Maze * *--------------------------------------------------------------------------*/ + Scene3500::Action1::Action1() { _field1E = 0; _field20 = 0; @@ -2919,9 +2920,10 @@ void Scene3500::Action1::sub108670(int arg1) { else scene->_actor5.show(); - if (scene->_actor1._frame % 2 == 0) - scene->_actor1._frameChange = _field1E; - scene->_actor1.setFrame(scene->_actor1.changeFrame()); + if (scene->_actor1._frame % 2 == 0) { + scene->_actor1._frameChange = _field1E; + scene->_actor1.setFrame(scene->_actor1.changeFrame()); + } setActionIndex(0); } @@ -2977,219 +2979,6 @@ void Scene3500::Action1::sub108732(int arg1) { } } -Scene3500::Action2::Action2() { - _field1E = 0; -} - -void Scene3500::Action2::synchronize(Serializer &s) { - Action::synchronize(s); - - s.syncAsSint16LE(_field1E); -} - -Scene3500::Item4::Item4() { - _field34 = 0; -} - -void Scene3500::Item4::synchronize(Serializer &s) { - NamedHotspot::synchronize(s); - - s.syncAsSint16LE(_field34); -} - -Scene3500::Actor7::Actor7() { - _fieldA4 = 0; - _fieldA6 = 0; - _fieldA8 = 0; - _fieldAA = 0; - _fieldAC = 0; - _fieldAE = 0; -} - -void Scene3500::Actor7::synchronize(Serializer &s) { - SceneActor::synchronize(s); - - s.syncAsSint16LE(_fieldA4); - s.syncAsSint16LE(_fieldA6); - s.syncAsSint16LE(_fieldA8); - s.syncAsSint16LE(_fieldAA); - s.syncAsSint16LE(_fieldAC); - s.syncAsSint16LE(_fieldAE); -} - -void Scene3500::Actor7::sub109466(int arg1, int arg2, int arg3, int arg4, int arg5) { - _fieldAE = 0; - _fieldA4 = arg1; - _fieldA6 = arg2; - _fieldA8 = arg3; - _fieldAA = arg4; - _fieldAC = _fieldAA / _fieldA8; - - postInit(); - setup(10501, 3, 1); - fixPriority(255); - sub109663(arg5); -} - -void Scene3500::Actor7::sub1094ED() { - Scene3500 *scene = (Scene3500 *)R2_GLOBALS._sceneManager._scene; - - scene->_field1270 = _position.x - _fieldA4; -} - -void Scene3500::Actor7::sub109663(int arg1){ - sub109693(Common::Point(_fieldA4 + arg1, _fieldA6 - (_fieldAC * arg1))); -} - -void Scene3500::Actor7::sub109693(Common::Point Pt) { - setPosition(Pt); -} - -int Scene3500::UnkObject3500::sub1097C9(int arg1) { - return (_field2A / 2) + arg1 - (arg1 % _field2A); -} - -int Scene3500::UnkObject3500::sub1097EF(int arg1) { - return (_field2C / 2) + arg1 - (arg1 % _field2C); -} - -int Scene3500::UnkObject3500::sub109C09(Common::Point pt) { - int vx = pt.x / _field2A; - int vy = pt.y / _field2C; - - if ((vx >= 0) && (_field26 > vx) && (_field28 > vy)) { - return _field16[((_field26 * vy) + vx) * 2]; - } else - return -1; -} - -int Scene3500::UnkObject3500::sub109C5E(int &x, int &y) { - int retVal = sub51AFD(Common::Point(x, y)); - x = _field2E; - y = _field30; - - return retVal; -} - -Scene3500::Scene3500() { - _fieldAF8 = 0; - _fieldB9E = 0; - _rotation = NULL; - _field126E = 0; - _field1270 = 0; - _field1272 = 0; - _field1274 = 0; - _field1276 = 0; - _field1278 = 0; - _field127A = 0; - _field127C = 0; - _field127E = 0; - _field1280 = 0; - _field1282 = 0; - _field1284 = 0; - _field1286 = 0; -} - -void Scene3500::synchronize(Serializer &s) { - SceneExt::synchronize(s); - SYNC_POINTER(_rotation); - - s.syncAsSint16LE(_fieldAF8); - s.syncAsSint16LE(_fieldB9E); - s.syncAsSint16LE(_field126E); - s.syncAsSint16LE(_field1270); - s.syncAsSint16LE(_field1272); - s.syncAsSint16LE(_field1274); - s.syncAsSint16LE(_field1276); - s.syncAsSint16LE(_field1278); - s.syncAsSint16LE(_field127A); - s.syncAsSint16LE(_field127C); - s.syncAsSint16LE(_field127E); - s.syncAsSint16LE(_field1280); - s.syncAsSint16LE(_field1282); - s.syncAsSint16LE(_field1284); - s.syncAsSint16LE(_field1286); -} - -void Scene3500::sub107F71(int arg1) { - switch (arg1) { - case -1: - _actor7.sub1094ED(); - if (_field1270 != 0) { - _field1270--; - _actor7.sub109663(_field1270); - } - if (_action1._field24 != 0) - _field1270 = 0; - break; - case 1: - _actor7.sub1094ED(); - if (_field1270 < 16) { - ++_field1270; - _actor7.sub109663(_field1270); - } - if (_action1._field24 != 0) - _field1270 = 0; - break; - case 88: - if ((_action == 0) || (_action1._field24 == 0)) { - // The original makes a second useless check on action, skipped - _action2.sub10831F(2); - if ((_action) && ((_action2.getActionIndex() != 0) || (_action2._field1E != 2))) { - _action2.signal(); - } else { - _actor9.setAction(&_action2, &_actor9, NULL); - } - } - break; - case 96: - if ((_action) && (_action1._field24 != 0) && (_action2._field1E != 1)) { - _field1278 = 0; - _action1.sub108732(0); - } else if ((_action) && (_field1278 == 0) && (_action1._field24 != 0)) { - _field1278 = arg1; - } else if ((_action) && (_action1._field24 == 0)) { - _action1.sub108670(1); - _action1.signal(); - } else if (_action == 0) { - _action1.sub108670(1); - setAction(&_action1, &_actor1, NULL); - } - break; - case 104: - if ((_action == 0) || (_action1._field24 == 0)) { - _action2.sub10831F(-1); - if ((_action) && ((_action2.getActionIndex() != 0) || (_action2._field1E != -1))) { - _action2.signal(); - } else { - _actor9.setAction(&_action2, &_actor9, NULL); - } - } - break; - case 112: - if ((_action) && (_action1._field24 != 0) && (_action2._field1E != -1)) { - _field1278 = 0; - _action1.sub108732(0); - } else if ((_action) && (_field1278 == 0) && (_action1._field24 != 0)) { - _field1278 = arg1; - } else if ((_action) && (_action1._field24 == 0)) { - _action1.sub108670(-1); - _action1.signal(); - } else if (_action == 0) { - _action1.sub108670(-1); - setAction(&_action1, &_actor1, NULL); - } - break; - default: - _field1270 = arg1; - _actor7.sub109663(arg1); - if (_action1._field24 != 0) { - _field1270 = 0; - } - break; - } -} - void Scene3500::Action1::signal() { Scene3500 *scene = (Scene3500 *)R2_GLOBALS._sceneManager._scene; @@ -3199,13 +2988,13 @@ void Scene3500::Action1::signal() { scene->_field1286 = 0; if (scene->_field1270 != 0) { scene->_field1270 = 0; - scene->_field126E = 0; + scene->_mazeChangeAmount = 0; scene->_field1272 = 0; scene->_rotation->_idxChange = 0; } break; case 1: - if ((scene->_actor1._frame % 2) == 0) { + if ((scene->_actor1._frame % 2) == 1) { setDelay(1); return; } @@ -3216,25 +3005,28 @@ void Scene3500::Action1::signal() { setDelay(1); break; case 4: { - int si = scene->_unkObj1.sub109C09(Common::Point(scene->_field127A + 70, scene->_field127C + 46)); - int var2 = scene->_unkObj1.sub1097C9(scene->_field127A + 70) - 70; - int var4 = scene->_unkObj1.sub1097EF(scene->_field127C + 46) - 46; - int di = abs(var2 - scene->_field127A); - int var6 = abs(var4 - scene->_field127C); + int si = scene->_mazeUI.getCellFromMapXY(Common::Point(scene->_mazePosition.x + 70, scene->_mazePosition.y + 46)); + int var2 = scene->_mazeUI.cellFromX(scene->_mazePosition.x + 70) - 70; + int var4 = scene->_mazeUI.cellFromY(scene->_mazePosition.y + 46) - 46; + int di = abs(var2 - scene->_mazePosition.x); + int var6 = abs(var4 - scene->_mazePosition.y); if ((scene->_actor1._frame % 2) != 0) { scene->_actor1._frameChange = _field1E; scene->_actor1.setFrame(scene->_actor1.changeFrame()); } - int var8 = (scene->_action1._field1E * 2 + scene->_field1276); - if (var8 > 7) - var8 = 1; - else if (var8 < 1) - var8 = 7; + // Get the new direction starting on + int var8 = (scene->_action1._field1E * 2 + scene->_mazeDirection); + if (var8 > MAZEDIR_NORTHWEST) + var8 = MAZEDIR_NORTH; + else if (var8 < MAZEDIR_NORTH) + var8 = MAZEDIR_WEST; + // Check whether movement is allowed in that direction. If so, then + // movement is started again switch (var8) { - case 0: + case MAZEDIR_NORTH: if ( ((si != 2) && (si != 3) && (si != 6) && (si != 1) && (si != 23) && (si != 24) && (si != 4) && (si != 11)) || (var6 != 0)) { if ((si != 25) && (si != 26) && (si != 5) && (si != 14) && (si != 15)) @@ -3246,7 +3038,7 @@ void Scene3500::Action1::signal() { } else _field20 = 1; break; - case 2: + case MAZEDIR_EAST: if ( ((si != 12) && (si != 13) && (si != 11) && (si != 16) && (si != 26) && (si != 24) && (si != 15) && (si != 6) && (si != 31)) || (di != 0)) { if ((si != 25) && (si != 23) && (si != 14) && (si != 5) && (si != 4)) @@ -3258,7 +3050,7 @@ void Scene3500::Action1::signal() { } else _field20 = 1; break; - case 4: + case MAZEDIR_SOUTH: if ( ((si != 2) && (si != 3) && (si != 6) && (si != 1) && (si != 25) && (si != 26) && (si != 5) && (si != 16) && (si != 31)) || (var6 != 0)) { if ((si != 23) && (si != 24) && (si != 4) && (si != 14) && (si != 15)) @@ -3270,7 +3062,7 @@ void Scene3500::Action1::signal() { } else _field20 = 1; break; - case 6: + case MAZEDIR_WEST: if ( ((si != 12) && (si != 13) && (si != 11) && (si != 16) && (si != 25) && (si != 23) && (si != 14) && (si != 1) && (si != 31)) || (var6 != 0)) { if ((si != 26) && (si != 24) && (si != 15) && (si != 5) && (si != 4)) @@ -3288,14 +3080,14 @@ void Scene3500::Action1::signal() { // No break on purpose case 2: { scene->_actor8.setPosition(Common::Point(160, 73)); - scene->_actor8._moveDiff.x = 160 - scene->_field126E; + scene->_actor8._moveDiff.x = 160 - scene->_mazeChangeAmount; scene->_fieldAF8 = 160 - ((_field1E * 2) * 160); Common::Point pt(scene->_fieldAF8, 73); NpcMover *mover = new NpcMover(); scene->_actor8.addMover(mover, &pt, this); scene->_actor9.setPosition(Common::Point(160 + ((_field1E * 2) * 160), 73)); - scene->_actor9._moveDiff.x = 160 - scene->_field126E; + scene->_actor9._moveDiff.x = 160 - scene->_mazeChangeAmount; scene->_fieldB9E = 160; Common::Point pt2(scene->_fieldB9E, 73); NpcMover *mover2 = new NpcMover(); @@ -3304,8 +3096,8 @@ void Scene3500::Action1::signal() { break; case 5: scene->_actor1._frameChange = _field1E; - scene->_field1276 = scene->_actor1.changeFrame(); - scene->_actor1.setFrame(scene->_field1276); + scene->_mazeDirection = scene->_actor1.changeFrame(); + scene->_actor1.setFrame(scene->_mazeDirection); setDelay(1); break; case 6: @@ -3325,8 +3117,8 @@ void Scene3500::Action1::signal() { case 7: if ((scene->_actor1._frame % 2) == 0) { scene->_actor1._frameChange = _field1E; - scene->_field1276 = scene->_actor1.changeFrame(); - scene->_actor1.setFrame(scene->_field1276); + scene->_mazeDirection = scene->_actor1.changeFrame(); + scene->_actor1.setFrame(scene->_mazeDirection); } setDelay(1); break; @@ -3342,7 +3134,7 @@ void Scene3500::Action1::signal() { // but it's clearly a cut and paste error from case 4. // The following code allows the switch to work properly. warning("Checkme: fix for dead code"); - int var_8 = (_field1E * 2 + scene->_field1276); + int var_8 = (_field1E * 2 + scene->_mazeDirection); if (var_8 > 7) var_8 = 1; else if (var_8 < 1) @@ -3353,12 +3145,12 @@ void Scene3500::Action1::signal() { case 0: // No break on purpose case 4: - scene->_field127A = scene->_unkObj1.sub1097C9(scene->_field127A + 70) - 70; + scene->_mazePosition.x = scene->_mazeUI.cellFromX(scene->_mazePosition.x + 70) - 70; break; case 2: // No break on purpose case 6: - scene->_field127C = scene->_unkObj1.sub1097EF(scene->_field127C + 46) - 46; + scene->_mazePosition.y = scene->_mazeUI.cellFromY(scene->_mazePosition.y + 46) - 46; break; default: break; @@ -3368,7 +3160,7 @@ void Scene3500::Action1::signal() { _field24 = 0; if (_field20 == 0) { scene->_actor7.sub1094ED(); - if (scene->_field126E == scene->_field1270) + if (scene->_mazeChangeAmount == scene->_field1270) scene->_aSound1.play(276); } break; @@ -3416,12 +3208,232 @@ void Scene3500::Action1::dispatch() { Scene3500 *scene = (Scene3500 *)R2_GLOBALS._sceneManager._scene; Action::dispatch(); - if ((_actionIndex == 1) && (scene->_field126E <= 4)) { + if ((_actionIndex == 1) && (scene->_mazeChangeAmount <= 4)) { scene->_rotation->_idxChange = 0; signal(); } } +/*--------------------------------------------------------------------------*/ + +Scene3500::Action2::Action2() { + _field1E = 0; +} + +void Scene3500::Action2::synchronize(Serializer &s) { + Action::synchronize(s); + + s.syncAsSint16LE(_field1E); +} + +/*--------------------------------------------------------------------------*/ + +Scene3500::Item4::Item4() { + _field34 = 0; +} + +void Scene3500::Item4::synchronize(Serializer &s) { + NamedHotspot::synchronize(s); + + s.syncAsSint16LE(_field34); +} + +/*--------------------------------------------------------------------------*/ + +Scene3500::Actor7::Actor7() { + _fieldA4 = 0; + _fieldA6 = 0; + _fieldA8 = 0; + _fieldAA = 0; + _fieldAC = 0; + _fieldAE = 0; +} + +void Scene3500::Actor7::synchronize(Serializer &s) { + SceneActor::synchronize(s); + + s.syncAsSint16LE(_fieldA4); + s.syncAsSint16LE(_fieldA6); + s.syncAsSint16LE(_fieldA8); + s.syncAsSint16LE(_fieldAA); + s.syncAsSint16LE(_fieldAC); + s.syncAsSint16LE(_fieldAE); +} + +void Scene3500::Actor7::sub109466(int arg1, int arg2, int arg3, int arg4, int arg5) { + _fieldAE = 0; + _fieldA4 = arg1; + _fieldA6 = arg2; + _fieldA8 = arg3; + _fieldAA = arg4; + _fieldAC = _fieldAA / _fieldA8; + + postInit(); + setup(1050, 3, 1); + fixPriority(255); + sub109663(arg5); +} + +void Scene3500::Actor7::sub1094ED() { + Scene3500 *scene = (Scene3500 *)R2_GLOBALS._sceneManager._scene; + + scene->_field1270 = _position.x - _fieldA4; +} + +void Scene3500::Actor7::sub109663(int arg1){ + sub109693(Common::Point(_fieldA4 + arg1, _fieldA6 - (_fieldAC * arg1))); +} + +void Scene3500::Actor7::sub109693(Common::Point Pt) { + setPosition(Pt); +} + +/*--------------------------------------------------------------------------*/ + +int Scene3500::MazeUI3500::cellFromX(int x) { + return (_cellSize.x / 2) + x - (x % _cellSize.x); +} + +int Scene3500::MazeUI3500::cellFromY(int y) { + return (_cellSize.y / 2) + y - (y % _cellSize.y) - 1; +} + +int Scene3500::MazeUI3500::getCellFromMapXY(Common::Point pt) { + int cellX = pt.x / _cellSize.x; + int cellY = pt.y / _cellSize.y; + + if ((cellX >= 0) && (cellY >= 0) && (cellX < _mapCells.x) && (cellY < _mapCells.y)) { + return (int16)READ_LE_UINT16(_mapData + (_mapCells.x * cellY + cellX) * 2); + } else + return -1; +} + +bool Scene3500::MazeUI3500::setMazePosition2(Common::Point &p) { + bool retVal = setMazePosition(p); + p = _mapOffset; + + return retVal; +} + +Scene3500::Scene3500() { + _fieldAF8 = 0; + _fieldB9E = 0; + _rotation = NULL; + _mazeChangeAmount = 0; + _field1270 = 0; + _field1272 = 0; + _field1274 = 0; + _mazeDirection = MAZEDIR_NONE; + _field1278 = 0; + _mazePosition.x = 0; + _mazePosition.y = 0; + _field127E = 0; + _field1280 = 0; + _field1282 = 0; + _field1284 = 0; + _field1286 = 0; +} + +void Scene3500::synchronize(Serializer &s) { + SceneExt::synchronize(s); + SYNC_POINTER(_rotation); + + s.syncAsSint16LE(_fieldAF8); + s.syncAsSint16LE(_fieldB9E); + s.syncAsSint16LE(_mazeChangeAmount); + s.syncAsSint16LE(_field1270); + s.syncAsSint16LE(_field1272); + s.syncAsSint16LE(_field1274); + s.syncAsSint16LE(_mazeDirection); + s.syncAsSint16LE(_field1278); + s.syncAsSint16LE(_mazePosition.x); + s.syncAsSint16LE(_mazePosition.y); + s.syncAsSint16LE(_field127E); + s.syncAsSint16LE(_field1280); + s.syncAsSint16LE(_field1282); + s.syncAsSint16LE(_field1284); + s.syncAsSint16LE(_field1286); +} + +void Scene3500::sub107F71(int arg1) { + switch (arg1) { + case -1: + _actor7.sub1094ED(); + if (_field1270 != 0) { + _field1270--; + _actor7.sub109663(_field1270); + } + if (_action1._field24 != 0) + _field1270 = 0; + break; + case 1: + _actor7.sub1094ED(); + if (_field1270 < 16) { + ++_field1270; + _actor7.sub109663(_field1270); + } + if (_action1._field24 != 0) + _field1270 = 0; + break; + case 88: + if ((_action == 0) || (_action1._field24 == 0)) { + // The original makes a second useless check on action, skipped + _action2.sub10831F(2); + if ((_action) && ((_action2.getActionIndex() != 0) || (_action2._field1E != 2))) { + _action2.signal(); + } else { + _actor9.setAction(&_action2, &_actor9, NULL); + } + } + break; + case 96: + if ((_action) && (_action1._field24 != 0) && (_action2._field1E != 1)) { + _field1278 = 0; + _action1.sub108732(0); + } else if ((_action) && (_field1278 == 0) && (_action1._field24 != 0)) { + _field1278 = arg1; + } else if ((_action) && (_action1._field24 == 0)) { + _action1.sub108670(1); + _action1.signal(); + } else if (_action == 0) { + _action1.sub108670(1); + setAction(&_action1, &_actor1, NULL); + } + break; + case 104: + if ((_action == 0) || (_action1._field24 == 0)) { + _action2.sub10831F(-1); + if ((_action) && ((_action2.getActionIndex() != 0) || (_action2._field1E != -1))) { + _action2.signal(); + } else { + _actor9.setAction(&_action2, &_actor9, NULL); + } + } + break; + case 112: + if ((_action) && (_action1._field24 != 0) && (_action2._field1E != -1)) { + _field1278 = 0; + _action1.sub108732(0); + } else if ((_action) && (_field1278 == 0) && (_action1._field24 != 0)) { + _field1278 = arg1; + } else if ((_action) && (_action1._field24 == 0)) { + _action1.sub108670(-1); + _action1.signal(); + } else if (_action == 0) { + _action1.sub108670(-1); + setAction(&_action1, &_actor1, NULL); + } + break; + default: + _field1270 = arg1; + _actor7.sub109663(arg1); + if (_action1._field24 != 0) { + _field1270 = 0; + } + break; + } +} + void Scene3500::Action2::sub10831F(int arg1) { Scene3500 *scene = (Scene3500 *)R2_GLOBALS._sceneManager._scene; @@ -3452,17 +3464,17 @@ void Scene3500::Action2::signal() { di = scene->_fieldB9E; } - scene->_actor8._moveDiff.y = 9 - (scene->_field126E / 2); + scene->_actor8._moveDiff.y = 9 - (scene->_mazeChangeAmount / 2); Common::Point pt(si, 73 - (_field1E * 12)); NpcMover *mover = new NpcMover(); scene->_actor8.addMover(mover, &pt, NULL); - scene->_actor9._moveDiff.y = 9 - (scene->_field126E / 2); + scene->_actor9._moveDiff.y = 9 - (scene->_mazeChangeAmount / 2); Common::Point pt2(di, 73 - (_field1E * 12)); NpcMover *mover2 = new NpcMover(); scene->_actor9.addMover(mover2, &pt2, NULL); - scene->_field126E = (scene->_field126E / 2) + (scene->_field126E % 2); - setDelay(17 - scene->_field126E); + scene->_mazeChangeAmount = (scene->_mazeChangeAmount / 2) + (scene->_mazeChangeAmount % 2); + setDelay(17 - scene->_mazeChangeAmount); } break; case 1: { @@ -3477,12 +3489,12 @@ void Scene3500::Action2::signal() { scene->_actor7.sub1094ED(); - scene->_actor8._moveDiff.y = 9 - (scene->_field126E / 2); + scene->_actor8._moveDiff.y = 9 - (scene->_mazeChangeAmount / 2); Common::Point pt(si, 73); NpcMover *mover = new NpcMover(); scene->_actor8.addMover(mover, &pt, NULL); - scene->_actor9._moveDiff.y = 9 - (scene->_field126E / 2); + scene->_actor9._moveDiff.y = 9 - (scene->_mazeChangeAmount / 2); Common::Point pt2(di, 73); NpcMover *mover2 = new NpcMover(); scene->_actor9.addMover(mover2, &pt2, NULL); @@ -3559,7 +3571,6 @@ bool Scene3500::Actor7::startAction(CursorType action, Event &event) { void Scene3500::postInit(SceneObjectList *OwnerList) { byte tmpPal[768]; - Rect tmpRect; loadScene(1050); R2_GLOBALS._uiElements._active = false; @@ -3574,9 +3585,8 @@ void Scene3500::postInit(SceneObjectList *OwnerList) { _field1278 = 0; _field1272 = 1; _field1270 = 4; - _field126E = 4; - _field127A = 860; - _field127C = 891; + _mazeChangeAmount = 4; + _mazePosition = Common::Point(860, 891); _rotation = R2_GLOBALS._scenePalette.addRotation(240, 254, -1); _rotation->setDelay(0); _rotation->_idxChange = 1; @@ -3615,7 +3625,7 @@ void Scene3500::postInit(SceneObjectList *OwnerList) { _item7.setDetails(96, 3500, 12, 10, -1); _actor8.postInit(); - _actor8.setup(10501, 1, 1); + _actor8.setup(1050, 1, 1); _actor8.setPosition(Common::Point(160, 73)); _actor8.fixPriority(1); @@ -3630,8 +3640,8 @@ void Scene3500::postInit(SceneObjectList *OwnerList) { _item1.setDetails(Rect(0, 0, 320, 200), 3500, 0, -1, 2, 1, NULL); _actor1.postInit(); - _field1276 = 1; - _actor1.setup(1004, 1, _field1276); + _mazeDirection = MAZEDIR_NORTH; + _actor1.setup(1004, 1, _mazeDirection); _actor1.setPosition(Common::Point(230, 135)); _actor1.fixPriority(200); _actor1._frameChange = 1; @@ -3654,7 +3664,7 @@ void Scene3500::postInit(SceneObjectList *OwnerList) { _actor6.hide(); _actor2.postInit(); - _actor2.setup(1004, 4, _field126E + 1); + _actor2.setup(1004, 4, _mazeChangeAmount + 1); _actor2.setPosition(Common::Point(126, 137)); _actor2.fixPriority(200); @@ -3663,15 +3673,12 @@ void Scene3500::postInit(SceneObjectList *OwnerList) { _actor3.setPosition(Common::Point(126, 108)); _actor3.fixPriority(200); - tmpRect.set(160, 89, 299, 182); - _unkObj1.sub9EDE8(tmpRect); - _unkObj1.sub51AE9(2); - _unkObj1.sub51AFD(Common::Point(_field127A, _field127C)); + _mazeUI.setDisplayBounds(Rect(160, 89, 299, 182)); + _mazeUI.load(2); + _mazeUI.setMazePosition(_mazePosition); _action1._field24 = 0; - warning("gfx_set_pane_p()"); - _unkObj1.sub51B02(); - warning("gfx_set_pane_p()"); + _mazeUI.draw(); _field1286 = 1; R2_GLOBALS._player.postInit(); @@ -3682,7 +3689,6 @@ void Scene3500::postInit(SceneObjectList *OwnerList) { } void Scene3500::remove() { - _rotation->remove(); R2_GLOBALS._sound2.fadeOut2(NULL); SceneExt::remove(); } @@ -3699,64 +3705,58 @@ void Scene3500::process(Event &event) { if (event.eventType == EVENT_KEYPRESS) { switch (event.kbd.keycode) { - case Common::KEYCODE_1: - warning("FIXME: keycode = 0x4700"); + case Common::KEYCODE_KP7: R2_GLOBALS._sound2.play(338); sub107F71(16); event.handled = true; break; - case Common::KEYCODE_2: - warning("FIXME: keycode = 0x4800"); + case Common::KEYCODE_UP: + case Common::KEYCODE_KP8: R2_GLOBALS._sound2.play(14, NULL, 63); sub107F71(88); event.handled = true; break; - case Common::KEYCODE_3: - warning("FIXME: keycode = 0x4900"); + case Common::KEYCODE_KP9: if (_field1270 < 16) R2_GLOBALS._sound2.play(338); sub107F71(1); event.handled = true; break; - case Common::KEYCODE_4: - warning("FIXME: keycode = 0x4B00"); + case Common::KEYCODE_KP4: + case Common::KEYCODE_LEFT: R2_GLOBALS._sound2.play(14, NULL, 63); sub107F71(112); event.handled = true; break; - case Common::KEYCODE_5: - warning("FIXME: keycode = 0x4D00"); + case Common::KEYCODE_KP6: + case Common::KEYCODE_RIGHT: R2_GLOBALS._sound2.play(14, NULL, 63); sub107F71(96); event.handled = true; break; - case Common::KEYCODE_6: - warning("FIXME: keycode = 0x4F00"); + case Common::KEYCODE_KP1: R2_GLOBALS._sound2.play(338); sub107F71(0); event.handled = true; break; - case Common::KEYCODE_7: - warning("FIXME: keycode = 0x5000"); + case Common::KEYCODE_KP2: + case Common::KEYCODE_DOWN: R2_GLOBALS._sound2.play(14, NULL, 63); sub107F71(104); event.handled = true; break; - case Common::KEYCODE_8: - warning("FIXME: keycode = 0x5100"); + case Common::KEYCODE_KP3: if (_field1270 != 0) R2_GLOBALS._sound2.play(338); sub107F71(-1); event.handled = true; break; - case Common::KEYCODE_9: - warning("FIXME: keycode = 0x5200"); + case Common::KEYCODE_KP0: R2_GLOBALS._sound2.play(338); sub107F71(8); event.handled = true; break; - case Common::KEYCODE_0: - warning("FIXME: keycode = 0x5300"); + case Common::KEYCODE_KP_PERIOD: R2_GLOBALS._sound2.play(338); sub107F71(4); event.handled = true; @@ -3787,9 +3787,10 @@ void Scene3500::process(Event &event) { void Scene3500::dispatch() { Rect tmpRect; Scene::dispatch(); + if (((_actor1._frame % 2) == 0) && (_action1._field24 == 0)) { _actor1.setFrame(_actor1.changeFrame()); - _field1276 = _actor1._frame; + _mazeDirection = _actor1._frame; } int oldField1278; if ((_field1278 != 0) && (_action1._field24 == 0)) { @@ -3801,90 +3802,90 @@ void Scene3500::dispatch() { if (!_rotation) return; - int var_field127A = 0; - int di = 0; + int newMazeX = 0; + int newMazeY = 0; int var_4 = 0; int var_6 = 0; int var_8 = 0; int var_a = 0; int dx = 0; - int tmpVar = 0; + int cellId = 0; - if ((_field126E == 0) && (_field1282 == 0)) { + if ((_mazeChangeAmount == 0) && (_field1282 == 0)) { if (_field1284 == 2) R2_GLOBALS._sceneManager.changeScene(1000); } else { _field1282 = 0; tmpRect.set(160, 89, 299, 182); - var_field127A = _field127A; - di = _field127C; - var_4 = _unkObj1.sub1097C9(70) - 70; - var_6 = _unkObj1.sub1097EF(_field127C + 46) - 46; - var_8 = abs(var_4 - var_field127A); - var_a = abs(var_6 - di); + newMazeX = _mazePosition.x; + newMazeY = _mazePosition.y; + var_4 = _mazeUI.cellFromX(newMazeX + 70) - 70; + var_6 = _mazeUI.cellFromY(_mazePosition.y + 46) - 46; + var_8 = abs(var_4 - newMazeX); + var_a = abs(var_6 - newMazeY); dx = 0; - switch (_field1276) { - case 0: - tmpVar = _unkObj1.sub109C09(Common::Point(var_field127A + 70, 46)); - if ( ((tmpVar == 2) || (tmpVar == 3) || (tmpVar == 6) || (tmpVar == 1)) - || (((tmpVar == 25) || (tmpVar == 26) || (tmpVar == 5) || (tmpVar == 14) || (tmpVar == 15)) && (var_8 > 3)) ) { + switch (_mazeDirection) { + case MAZEDIR_NORTH: + cellId = _mazeUI.getCellFromMapXY(Common::Point(newMazeX + 70, newMazeY + 46)); + if (((cellId == 2) || (cellId == 3) || (cellId == 6) || (cellId == 1)) || + ((cellId == 25 || cellId == 26 || cellId == 5 || cellId == 14 || cellId == 15) && var_8 > 3)) { R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); } else { - var_6 = _unkObj1.sub1097EF(di + 46) - 46; - di = _field127C - _field126E; - dx = _unkObj1.sub109C09(Common::Point(var_field127A + 70, di + 46)); - if (((tmpVar == 23) || (tmpVar == 24) || (tmpVar == 4)) && (tmpVar != dx)) { - di = var_6; + var_6 = _mazeUI.cellFromY(newMazeY + 46) - 46; + newMazeY = _mazePosition.y - _mazeChangeAmount; + dx = _mazeUI.getCellFromMapXY(Common::Point(newMazeX + 70, newMazeY + 46)); + if (((cellId == 23) || (cellId == 24) || (cellId == 4)) && (cellId != dx)) { + newMazeY = var_6; R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); - } else if ((tmpVar == 11) && (tmpVar != dx)) { - di = var_6 + 3; + } else if ((cellId == 11) && (cellId != dx)) { + newMazeY = var_6 + 3; R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); } else { - var_6 = _unkObj1.sub1097EF(di + 46) - 46; - var_a = abs(var_6 - di); - tmpVar = _unkObj1.sub109C09(Common::Point(var_field127A + 70, di + 46)); - - if ( (((tmpVar == 23) || (tmpVar == 24) || (tmpVar == 4)) && (di <= var_6) && (_field127C>= var_6)) - || (((tmpVar == 25) || (tmpVar == 26) || (tmpVar == 5) || (tmpVar == 14) || (tmpVar == 15)) && (_field126E >= var_a) && (_field126E > 3) && (_action1._field24 != 0)) ) { - di = var_6; - if ((tmpVar != 25) && (tmpVar != 26) && (tmpVar != 5) && (tmpVar != 14) && (tmpVar == 15)) + var_6 = _mazeUI.cellFromY(newMazeY + 46) - 46; + var_a = abs(var_6 - newMazeY); + cellId = _mazeUI.getCellFromMapXY(Common::Point(newMazeX + 70, newMazeY + 46)); + + if ( (((cellId == 23) || (cellId == 24) || (cellId == 4)) && (newMazeY <= var_6) && (_mazePosition.y>= var_6)) + || (((cellId == 25) || (cellId == 26) || (cellId == 5) || (cellId == 14) || (cellId == 15)) && (_mazeChangeAmount >= var_a) && (_mazeChangeAmount > 3) && (_action1._field24 != 0)) ) { + newMazeY = var_6; + if ((cellId != 25) && (cellId != 26) && (cellId != 5) && (cellId != 14) && (cellId == 15)) R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); - } else if ((tmpVar == 11) && (var_6 + 3 >= di) && (_field127C >= var_6 + 3)) { + } else if ((cellId == 11) && (var_6 + 3 >= newMazeY) && (_mazePosition.y >= var_6 + 3)) { R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); - } else if (((tmpVar == 25) || (tmpVar == 26) || (tmpVar == 5) || (tmpVar == 14) || (tmpVar == 15)) && (var_8 != 0) && (var_8 <= 3)) { - var_field127A = var_4; + } else if (((cellId == 25) || (cellId == 26) || (cellId == 5) || (cellId == 14) || (cellId == 15)) && (var_8 != 0) && (var_8 <= 3)) { + newMazeX = var_4; R2_GLOBALS._sound2.play(339); } else { // Nothing @@ -3892,65 +3893,65 @@ void Scene3500::dispatch() { } } break; - case 2: - tmpVar = _unkObj1.sub109C09(Common::Point(var_field127A + 70, di + 46)); - if ( ((tmpVar == 12) || (tmpVar == 13) || (tmpVar == 11) || (tmpVar == 16) || (tmpVar == 31)) - || (((tmpVar == 25) || (tmpVar == 23) || (tmpVar == 14) || (tmpVar == 5) || (tmpVar == 4)) && (var_a > 3)) ) { + case MAZEDIR_EAST: + cellId = _mazeUI.getCellFromMapXY(Common::Point(newMazeX + 70, newMazeY + 46)); + if ( ((cellId == 12) || (cellId == 13) || (cellId == 11) || (cellId == 16) || (cellId == 31)) + || (((cellId == 25) || (cellId == 23) || (cellId == 14) || (cellId == 5) || (cellId == 4)) && (var_a > 3)) ) { R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); } else { - var_4 = _unkObj1.sub1097C9(var_field127A + 70) - 70; - var_field127A = _field127A + _field126E; - dx = _unkObj1.sub109C09(Common::Point(var_field127A + 70, di + 46)); - if (((tmpVar == 26) || (tmpVar == 24) || (tmpVar == 15)) && (tmpVar != dx)) { - var_field127A = var_4; + var_4 = _mazeUI.cellFromX(newMazeX + 70) - 70; + newMazeX = _mazePosition.x + _mazeChangeAmount; + dx = _mazeUI.getCellFromMapXY(Common::Point(newMazeX + 70, newMazeY + 46)); + if (((cellId == 26) || (cellId == 24) || (cellId == 15)) && (cellId != dx)) { + newMazeX = var_4; R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); - } else if ((tmpVar == 6) && (tmpVar != dx)) { - var_field127A = var_4 - 5; + } else if ((cellId == 6) && (cellId != dx)) { + newMazeX = var_4 - 5; R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); } else { - var_4 = _unkObj1.sub1097C9(var_field127A + 70) - 70; - var_8 = abs(var_field127A - var_4); - tmpVar = _unkObj1.sub109C09(Common::Point(var_field127A + 70, tmpVar + 46)); - if ( (((tmpVar == 26) || (tmpVar == 24) || (tmpVar == 15)) && (var_field127A >= var_4) && (_field127A <= var_4)) - || (((tmpVar == 25) || (tmpVar == 23) || (tmpVar == 14) || (tmpVar == 5) || (tmpVar == 4)) && (_field126E >= var_8) && (_field126E <= 3) && (_action1._field24 != 0)) ) { - var_field127A = var_4; - if ((tmpVar == 25) || (tmpVar == 23) || (tmpVar == 14) || (tmpVar == 5) || (tmpVar == 4)) + var_4 = _mazeUI.cellFromX(newMazeX + 70) - 70; + var_8 = abs(newMazeX - var_4); + cellId = _mazeUI.getCellFromMapXY(Common::Point(newMazeX + 70, newMazeY + 46)); + if ( (((cellId == 26) || (cellId == 24) || (cellId == 15)) && (newMazeX >= var_4) && (_mazePosition.x <= var_4)) + || (((cellId == 25) || (cellId == 23) || (cellId == 14) || (cellId == 5) || (cellId == 4)) && (_mazeChangeAmount >= var_8) && (_mazeChangeAmount <= 3) && (_action1._field24 != 0)) ) { + newMazeX = var_4; + if ((cellId == 25) || (cellId == 23) || (cellId == 14) || (cellId == 5) || (cellId == 4)) R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); - } else if ((tmpVar == 6) && (var_4 - 5 <= var_field127A) && (_field127A <= var_4 - 5)) { - var_field127A = var_4 - 5; + } else if ((cellId == 6) && (var_4 - 5 <= newMazeX) && (_mazePosition.x <= var_4 - 5)) { + newMazeX = var_4 - 5; R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); - } else if (((tmpVar == 25) || (tmpVar == 23) || (tmpVar == 14) || (tmpVar == 5) || (tmpVar == 4)) && (var_a != 0) && (var_a <= 3)) { - di = var_6; + } else if (((cellId == 25) || (cellId == 23) || (cellId == 14) || (cellId == 5) || (cellId == 4)) && (var_a != 0) && (var_a <= 3)) { + newMazeY = var_6; R2_GLOBALS._sound2.play(339); } else { // Nothing @@ -3958,84 +3959,87 @@ void Scene3500::dispatch() { } } break; - case 4: - tmpVar = _unkObj1.sub109C09(Common::Point(var_field127A + 70, di + 46)); - if ( ((tmpVar == 2) || (tmpVar == 3) || (tmpVar == 6) || (tmpVar == 1)) - || (((tmpVar == 23) || (tmpVar == 24) || (tmpVar == 4) || (tmpVar == 14) || (tmpVar == 15)) && (var_8 > 3)) ) { + case MAZEDIR_SOUTH: + cellId = _mazeUI.getCellFromMapXY(Common::Point(newMazeX + 70, newMazeY + 46)); + if ( ((cellId == 2) || (cellId == 3) || (cellId == 6) || (cellId == 1)) + || (((cellId == 23) || (cellId == 24) || (cellId == 4) || (cellId == 14) || (cellId == 15)) && (var_8 > 3)) ) { R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); } else { - var_6 = _unkObj1.sub1097EF(di + 46) - 46; - di = _field127C + _field126E; - dx = _unkObj1.sub109C09(Common::Point(var_field127A + 70, di + 46)); - if (((tmpVar == 25) || (tmpVar == 26) || (tmpVar == 5)) && (tmpVar == dx)) { + var_6 = _mazeUI.cellFromY(newMazeY + 46) - 46; + newMazeY = _mazePosition.y + _mazeChangeAmount; + dx = _mazeUI.getCellFromMapXY(Common::Point(newMazeX + 70, newMazeY + 46)); + + if (((cellId == 25) || (cellId == 26) || (cellId == 5)) && (cellId != dx)) { R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); - } else if ((tmpVar == 16) && (tmpVar == dx)) { - di = var_6 - 3; + } else if ((cellId == 16) && (cellId != dx)) { + newMazeY = var_6 - 3; R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); - } else if ((tmpVar == 31) && (tmpVar == dx)) { - di = var_6 + 4; + } else if ((cellId == 31) && (cellId != dx)) { + newMazeY = var_6 + 4; R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); } else { - var_6 = _unkObj1.sub1097EF(di + 46) - 46; - var_a = abs(di - var_6); - tmpVar = _unkObj1.sub109C09(Common::Point(var_field127A + 70, di + 46)); - if ( (((tmpVar == 25) || (tmpVar == 26) || (tmpVar == 5)) && (di >= var_6) && (_field127C <= var_6)) - || (((tmpVar == 23) || (tmpVar == 24) || (tmpVar == 4) || (tmpVar == 14) || (tmpVar == 15)) && (_field126E >= var_a) && (_field126E <= 3) && (_action1._field24 != 0)) ){ - if ((tmpVar != 23) && (tmpVar != 24) && (tmpVar != 4) && (tmpVar != 14) && (tmpVar != 15)) + var_6 = _mazeUI.cellFromY(newMazeY + 46) - 46; + var_a = abs(newMazeY - var_6); + cellId = _mazeUI.getCellFromMapXY(Common::Point(newMazeX + 70, newMazeY + 46)); + if ( (((cellId == 25) || (cellId == 26) || (cellId == 5)) && (newMazeY >= var_6) && (_mazePosition.y <= var_6)) + || (((cellId == 23) || (cellId == 24) || (cellId == 4) || (cellId == 14) || (cellId == 15)) && (_mazeChangeAmount >= var_a) && (_mazeChangeAmount <= 3) && (_action1._field24 != 0)) ){ + newMazeY = var_6; + + if ((cellId != 23) && (cellId != 24) && (cellId != 4) && (cellId != 14) && (cellId != 15)) R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); - } else if ((tmpVar == 16) && (var_6 - 3 <= di) && (_field127C <= var_6 - 3)) { - di = var_6 - 3; + } else if ((cellId == 16) && (var_6 - 3 <= newMazeY) && (_mazePosition.y <= var_6 - 3)) { + newMazeY = var_6 - 3; R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); - } else if ((tmpVar == 31) && (var_6 + 4 <= di) && (_field127C <= var_6 + 4)) { - di = var_6 + 4; + } else if ((cellId == 31) && (var_6 + 4 <= newMazeY) && (_mazePosition.y <= var_6 + 4)) { + newMazeY = var_6 + 4; _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); - if ((var_field127A == 660) && (_field126E + 306 <= di) && (di <= 307)) + if ((newMazeX == 660) && (_mazeChangeAmount + 306 <= newMazeY) && (newMazeY <= 307)) ++_field1284; else R2_GLOBALS._sound2.play(339); - } else if (((tmpVar == 23) || (tmpVar == 24) || (tmpVar == 4) || (tmpVar == 14) || (tmpVar == 15)) && (var_8 != 0) && (var_8 <= 3)) { - var_field127A = var_4; + } else if (((cellId == 23) || (cellId == 24) || (cellId == 4) || (cellId == 14) || (cellId == 15)) && (var_8 != 0) && (var_8 <= 3)) { + newMazeX = var_4; R2_GLOBALS._sound2.play(339); } else { // Nothing @@ -4043,65 +4047,65 @@ void Scene3500::dispatch() { } } break; - case 6: - tmpVar = _unkObj1.sub109C09(Common::Point(var_field127A + 70, di + 46)); - if ( ((tmpVar == 12) || (tmpVar == 13) || (tmpVar == 11) || (tmpVar == 16) || (tmpVar == 31)) - || (((tmpVar == 26) || (tmpVar == 24) || (tmpVar == 15) || (tmpVar == 5) || (tmpVar == 4)) && (var_a > 3)) ) { + case MAZEDIR_WEST: + cellId = _mazeUI.getCellFromMapXY(Common::Point(newMazeX + 70, newMazeY + 46)); + if ( ((cellId == 12) || (cellId == 13) || (cellId == 11) || (cellId == 16) || (cellId == 31)) + || (((cellId == 26) || (cellId == 24) || (cellId == 15) || (cellId == 5) || (cellId == 4)) && (var_a > 3)) ) { R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); } else { - var_4 = _unkObj1.sub1097C9(var_field127A + 70) - 70; - var_field127A = _field127A - _field126E; - dx = _unkObj1.sub109C09(Common::Point(var_field127A + 70, di + 46)); - if (((tmpVar == 25) || (tmpVar == 23) || (tmpVar == 14)) && (tmpVar != dx)) { - var_field127A = var_4; + var_4 = _mazeUI.cellFromX(newMazeX + 70) - 70; + newMazeX = _mazePosition.x - _mazeChangeAmount; + dx = _mazeUI.getCellFromMapXY(Common::Point(newMazeX + 70, newMazeY + 46)); + if (((cellId == 25) || (cellId == 23) || (cellId == 14)) && (cellId != dx)) { + newMazeX = var_4; R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); - } else if ((tmpVar == 1) && (tmpVar != dx)) { - var_field127A = var_4 + 5; + } else if ((cellId == 1) && (cellId != dx)) { + newMazeX = var_4 + 5; R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); } else { - var_4 = _unkObj1.sub1097C9(var_field127A + 70) - 70; - var_8 = abs(var_4 - var_field127A); - tmpVar = _unkObj1.sub109C09(Common::Point(var_field127A + 70, di + 46)); - if ( (((tmpVar == 25) || (tmpVar == 23) || (tmpVar == 14)) && (var_field127A <= var_4) && (_field127A >= var_4)) - || (((tmpVar == 26) || (tmpVar == 24) || (tmpVar == 15) || (tmpVar == 5) || (tmpVar == 4)) && (_field126E >= var_8) && (_field126E <= 3) && (_action1._field24 != 0)) ) { - var_field127A = var_4; - if ((tmpVar == 26) || (tmpVar == 24) || (tmpVar == 15) || (tmpVar == 5) || (tmpVar == 4)) + var_4 = _mazeUI.cellFromX(newMazeX + 70) - 70; + var_8 = abs(var_4 - newMazeX); + cellId = _mazeUI.getCellFromMapXY(Common::Point(newMazeX + 70, newMazeY + 46)); + if ( (((cellId == 25) || (cellId == 23) || (cellId == 14)) && (newMazeX <= var_4) && (_mazePosition.x >= var_4)) + || (((cellId == 26) || (cellId == 24) || (cellId == 15) || (cellId == 5) || (cellId == 4)) && (_mazeChangeAmount >= var_8) && (_mazeChangeAmount <= 3) && (_action1._field24 != 0)) ) { + newMazeX = var_4; + if ((cellId == 26) || (cellId == 24) || (cellId == 15) || (cellId == 5) || (cellId == 4)) R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); - } else if ((tmpVar == 1) && (var_field127A >= var_4 + 5) && (_field127A >= var_4 + 5)) { - var_field127A = var_4 + 5; + } else if ((cellId == 1) && (newMazeX >= var_4 + 5) && (_mazePosition.x >= var_4 + 5)) { + newMazeX = var_4 + 5; R2_GLOBALS._sound2.play(339); _rotation->_idxChange = 0; _field1270 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1272 = 0; if (_action1._field24 == 0) _actor8.hide(); - } else if (((tmpVar == 26) || (tmpVar == 24) || (tmpVar == 15) || (tmpVar == 5) || (tmpVar == 4)) && (var_a != 0) && (var_a <= 3)) { - di = var_6; + } else if (((cellId == 26) || (cellId == 24) || (cellId == 15) || (cellId == 5) || (cellId == 4)) && (var_a != 0) && (var_a <= 3)) { + newMazeY = var_6; R2_GLOBALS._sound2.play(339); } else { // Nothing @@ -4114,49 +4118,49 @@ void Scene3500::dispatch() { } if (_field1284 < 2) { - _field127A = var_field127A; - _field127C = di; - if (_unkObj1.sub109C5E(_field127A, _field127C) != 0) { + _mazePosition.x = newMazeX; + _mazePosition.y = newMazeY; + if (_mazeUI.setMazePosition2(_mazePosition) != 0) { _field1272 = 0; - _field126E = 0; + _mazeChangeAmount = 0; _field1270 = 0; _rotation->setDelay(0); _rotation->_idxChange = 0; } - warning("gfx_set_pane_p"); - _unkObj1.sub51B02(); + + _mazeUI.draw(); if (_field1284 != 0) ++_field1284; } } if (_field1272 == 0) { - if (_field126E != _field1270) { - if (_field126E >= _field1270) { - if (_field126E == 1) { + if (_mazeChangeAmount != _field1270) { + if (_mazeChangeAmount >= _field1270) { + if (_mazeChangeAmount == 1) { if (_action1._field24 != 0) { - if ( ((_field1276 == 1) && (var_8 == 0) && (var_a != 0) && (var_a <= 3) && ((tmpVar == 25) || (tmpVar == 26) || (tmpVar == 5) || (tmpVar == 14) || (tmpVar == 15))) - || ((_field1276 == 3) && (var_a == 0) && (var_8 != 0) && (var_8 <= 3) && ((tmpVar == 25) || (tmpVar == 23) || (tmpVar == 14) || (tmpVar == 5) || (tmpVar == 4))) - || ((_field1276 == 5) && (var_8 == 0) && (var_a != 0) && (var_a <= 3) && ((tmpVar == 23) || (tmpVar == 24) || (tmpVar == 4) || (tmpVar == 14) || (tmpVar == 15))) - || ((_field1276 == 7) && (var_a == 0) && (var_8 != 0) && (var_8 <= 3) && ((tmpVar == 26) || (tmpVar == 24) || (tmpVar == 15) || (tmpVar == 5) || (tmpVar == 4))) ){ - _field126E = 1; + if ( ((_mazeDirection == 1) && (var_8 == 0) && (var_a != 0) && (var_a <= 3) && ((cellId == 25) || (cellId == 26) || (cellId == 5) || (cellId == 14) || (cellId == 15))) + || ((_mazeDirection == 3) && (var_a == 0) && (var_8 != 0) && (var_8 <= 3) && ((cellId == 25) || (cellId == 23) || (cellId == 14) || (cellId == 5) || (cellId == 4))) + || ((_mazeDirection == 5) && (var_8 == 0) && (var_a != 0) && (var_a <= 3) && ((cellId == 23) || (cellId == 24) || (cellId == 4) || (cellId == 14) || (cellId == 15))) + || ((_mazeDirection == 7) && (var_a == 0) && (var_8 != 0) && (var_8 <= 3) && ((cellId == 26) || (cellId == 24) || (cellId == 15) || (cellId == 5) || (cellId == 4))) ){ + _mazeChangeAmount = 1; } else - _field126E--; + _mazeChangeAmount--; } else - _field126E--; + _mazeChangeAmount--; } else - _field126E--; + _mazeChangeAmount--; } else - ++_field126E; + ++_mazeChangeAmount; _field1272 = 1; } - _actor2.setFrame2(_field126E); + _actor2.setFrame2(_mazeChangeAmount + 1); } if (_field1272 == 1) { - if (_field126E == 0) + if (_mazeChangeAmount == 0) _rotation->_idxChange = 0; - else if (_field126E > 8) + else if (_mazeChangeAmount > 8) _rotation->_idxChange = 2; else _rotation->_idxChange = 1; @@ -4165,9 +4169,9 @@ void Scene3500::dispatch() { if (_field1272 != 0) _field1272--; - if (_field126E != 0) { - R2_GLOBALS._player._uiEnabled = false; - if (_field126E != _field1270) + if (_mazeChangeAmount != 0) { + R2_GLOBALS._player._uiEnabled = false; + if (_mazeChangeAmount != _field1270) _aSound1.play(276); } else { R2_GLOBALS._player._uiEnabled = true; diff --git a/engines/tsage/ringworld2/ringworld2_scenes3.h b/engines/tsage/ringworld2/ringworld2_scenes3.h index 44787b9eef..85e5674433 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes3.h +++ b/engines/tsage/ringworld2/ringworld2_scenes3.h @@ -633,12 +633,12 @@ class Scene3500 : public SceneExt { // TODO: double check if nothing specific is present, then remove this class }; - class UnkObject3500 : public UnkObject1200 { + class MazeUI3500 : public MazeUI { public: - int sub1097C9(int arg1); - int sub1097EF(int arg1); - int sub109C09(Common::Point pt); - int sub109C5E(int &x, int &y); + int cellFromX(int arg1); + int cellFromY(int arg1); + int getCellFromMapXY(Common::Point pt); + bool setMazePosition2(Common::Point &p); }; public: Action1 _action1; @@ -650,6 +650,7 @@ public: Item4 _item5; Item4 _item6; Item4 _item7; + // Glyph of vessel on top of the maze ui SceneActor _actor1; SceneActor _actor2; SceneActor _actor3; @@ -660,20 +661,19 @@ public: Actor8 _actor8; Actor8 _actor9; ASoundExt _aSound1; - UnkObject3500 _unkObj1; + MazeUI3500 _mazeUI; SequenceManager _sequenceManager; int _fieldAF8; int _fieldB9E; PaletteRotation *_rotation; - int _field126E; + int _mazeChangeAmount; int _field1270; int _field1272; int _field1274; - int _field1276; + int _mazeDirection; int _field1278; - int _field127A; - int _field127C; + Common::Point _mazePosition; int _field127E; int _field1280; int _field1282; diff --git a/engines/tsage/ringworld2/ringworld2_speakers.cpp b/engines/tsage/ringworld2/ringworld2_speakers.cpp index da1449efdf..8d91787272 100644 --- a/engines/tsage/ringworld2/ringworld2_speakers.cpp +++ b/engines/tsage/ringworld2/ringworld2_speakers.cpp @@ -40,7 +40,7 @@ VisualSpeaker::VisualSpeaker(): Speaker() { _color1 = 8; _color2 = 0; _displayMode = 0; - _fieldF6 = 0; + _speakerMode = 0; } void VisualSpeaker::remove() { @@ -49,27 +49,104 @@ void VisualSpeaker::remove() { _fieldF8 = 0; _object1.setStrip(_object1._strip - 1); _object1.setFrame(_object1.getFrameCount()); - _object1.animate(ANIM_MODE_6, (_fieldF6 == 0xff) ? this : NULL); + _object1.animate(ANIM_MODE_6, (_speakerMode == 0xff) ? this : NULL); } else { - _object1.animate(ANIM_MODE_6, (_fieldF6 == 0xff) ? this : NULL); + _object1.animate(ANIM_MODE_6, (_speakerMode == 0xff) ? this : NULL); } } Speaker::remove(); } +void VisualSpeaker::signal() { + // TODO: _action->_field18 = 1; + if (_speakerMode == 0xff) + proc16(); + + _speakerMode = 0; + if (_numFrames) { + if (_object2) { + _object1.setStrip(_object1._strip + 1); + _object1.animate(ANIM_MODE_2, NULL); + _fieldF8 = 1; + } + + if ((R2_GLOBALS._speechSubtitles & SPEECH_TEXT) || _soundId) + _sceneText.show(); + + if ((R2_GLOBALS._speechSubtitles & SPEECH_VOICE) && _soundId) { + // TODO: Check global that is passed + setFrame2(/* word_55F90 */ 1); + } + } else if (_action && _object2) { + _action->setDelay(1); + _sceneText.remove(); + + R2_GLOBALS._playStream.stop(); + } +} + +void VisualSpeaker::dispatch() { + uint32 frameNumber = R2_GLOBALS._events.getFrameNumber(); + + // Delay check for character animation + if (_delayAmount) { + if (frameNumber >= _frameNumber) { + _delayAmount = _delayAmount - (_frameNumber - frameNumber); + _frameNumber = frameNumber; + + if (_delayAmount <= 0) { + _delayAmount = 0; + _object1.animate(ANIM_MODE_NONE, NULL); + _object1.setFrame(1); + } + } + } + + // Delay check for voice + if (_delayAmount2) { + if (frameNumber >= _frameNumber2) { + _delayAmount2 = _delayAmount2 - (_frameNumber2 - frameNumber); + _frameNumber2 = frameNumber; + + if (_delayAmount2 <= 0) { + _delayAmount2 = 0; + if (R2_GLOBALS._playStream.play(0, NULL)) { + _numFrames = 2; + _soundId = 0; + } else { + _sceneText.show(); + } + } + } + } + + if ((R2_GLOBALS._speechSubtitles & SPEECH_VOICE) && (_numFrames == 2) && + !R2_GLOBALS._playStream.isPlaying()) { + _numFrames = 0; + _object1.animate(ANIM_MODE_NONE); + _object1.setFrame(1); + + if (!(R2_GLOBALS._speechSubtitles & SPEECH_TEXT)) { + _action->setDelay(1); + } + } +} + void VisualSpeaker::synchronize(Serializer &s) { Speaker::synchronize(s); SYNC_POINTER(_object2); - s.syncAsSint16LE(_fieldF6); + s.syncAsSint16LE(_speakerMode); s.syncAsSint16LE(_fieldF8); s.syncAsSint16LE(_displayMode); s.syncAsSint16LE(_soundId); - s.syncAsSint16LE(_delayAmount); s.syncAsByte(_removeObject); - s.syncAsSint32LE(_frameNumber); s.syncAsSint16LE(_numFrames); + s.syncAsSint16LE(_delayAmount); + s.syncAsUint32LE(_frameNumber); + s.syncAsSint16LE(_delayAmount2); + s.syncAsUint32LE(_frameNumber2); } void VisualSpeaker::setText(const Common::String &msg) { @@ -159,8 +236,7 @@ void VisualSpeaker::setText(const Common::String &msg) { if (s.empty()) _numFrames = 0; - - if (_fieldF6) { + if (_speakerMode) { if ((R2_GLOBALS._speechSubtitles & SPEECH_TEXT) || !_soundId) _sceneText.hide(); } else { @@ -173,11 +249,11 @@ void VisualSpeaker::setText(const Common::String &msg) { void VisualSpeaker::proc16() { R2_GLOBALS._playStream.stop(); - _fieldF6 = 0; + _speakerMode = 0; _object1.remove(); - assert(_object2); - _object2->show(); + if (_object2) + _object2->show(); _object2 = NULL; _fieldF8 = 0; } @@ -187,6 +263,11 @@ void VisualSpeaker::setFrame(int numFrames) { _frameNumber = R2_GLOBALS._events.getFrameNumber(); } +void VisualSpeaker::setFrame2(int numFrames) { + _delayAmount2 = numFrames; + _frameNumber2 = R2_GLOBALS._events.getFrameNumber(); +} + void VisualSpeaker::setDelay(int delay) { _delayAmount = delay; _frameNumber = R2_GLOBALS._events.getFrameNumber(); @@ -211,7 +292,7 @@ SpeakerCaptain3210::SpeakerCaptain3210() { _speakerName = "Captain"; _color1 = 5; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -220,7 +301,7 @@ SpeakerCaptain3210::SpeakerCaptain3210() { } void SpeakerCaptain3210::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene3210 *scene = (Scene3210 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -250,7 +331,7 @@ SpeakerCaretaker2450::SpeakerCaretaker2450() { _speakerName = "CARETAKER"; _color1 = 43; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -266,7 +347,7 @@ SpeakerChief1100::SpeakerChief1100() { _speakerName = "CHIEF"; _color1 = 8; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -275,11 +356,11 @@ SpeakerChief1100::SpeakerChief1100() { } void SpeakerChief1100::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene1100 *scene = (Scene1100 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { - _object2 = &scene->_actor18; + _object2 = &scene->_chief; _object2->hide(); _object1.postInit(); _object1.setPosition(_object2->_position); @@ -324,7 +405,7 @@ SpeakerGuard::SpeakerGuard() { _speakerName = "GUARD"; _color1 = 5; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -333,7 +414,7 @@ SpeakerGuard::SpeakerGuard() { } void SpeakerGuard2800::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene2750 *scene = (Scene2750 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -364,7 +445,7 @@ SpeakerJocko::SpeakerJocko() { _speakerName = "Jocko"; _color1 = 45; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -373,7 +454,7 @@ SpeakerJocko::SpeakerJocko() { } void SpeakerJocko3200::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene3200 *scene = (Scene3200 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -396,7 +477,7 @@ void SpeakerJocko3200::proc15() { } void SpeakerJocko3220::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene3220 *scene = (Scene3220 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -419,7 +500,7 @@ void SpeakerJocko3220::proc15() { } void SpeakerJocko3230::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene3230 *scene = (Scene3230 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -449,7 +530,7 @@ SpeakerMiranda::SpeakerMiranda(): VisualSpeaker() { _speakerName = "MIRANDA"; _color1 = 154; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -458,7 +539,7 @@ SpeakerMiranda::SpeakerMiranda(): VisualSpeaker() { } void SpeakerMiranda300::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 3) { @@ -498,7 +579,7 @@ void SpeakerMiranda300::proc15() { } void SpeakerMiranda1625::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { Scene1625 *scene = (Scene1625 *)R2_GLOBALS._sceneManager._scene; @@ -521,7 +602,7 @@ void SpeakerMiranda1625::proc15() { } void SpeakerMiranda3255::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { _object2 = &R2_GLOBALS._player; @@ -544,7 +625,7 @@ void SpeakerMiranda3255::proc15() { void SpeakerMiranda3375::proc15() { Scene3375 *scene = (Scene3375 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 3) @@ -594,7 +675,7 @@ void SpeakerMiranda3375::proc15() { void SpeakerMiranda3385::proc15() { Scene3385 *scene = (Scene3385 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 3) @@ -643,7 +724,7 @@ void SpeakerMiranda3385::proc15() { void SpeakerMiranda3395::proc15() { Scene3395 *scene = (Scene3395 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 3) @@ -693,7 +774,7 @@ void SpeakerMiranda3395::proc15() { void SpeakerMiranda3400::proc15() { Scene3400 *scene = (Scene3400 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 3) @@ -737,7 +818,7 @@ void SpeakerMiranda3400::proc15() { void SpeakerMiranda3600::proc15() { Scene3600 *scene = (Scene3600 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 3) @@ -783,7 +864,7 @@ void SpeakerMiranda3600::proc15() { void SpeakerMiranda3700::proc15() { Scene3700 *scene = (Scene3700 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { _object2 = &scene->_actor3; @@ -840,7 +921,7 @@ SpeakerNej::SpeakerNej() { _speakerName = "NEJ"; _color1 = 171; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -849,7 +930,7 @@ SpeakerNej::SpeakerNej() { } void SpeakerNej2700::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene2700 *scene = (Scene2700 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -884,7 +965,7 @@ void SpeakerNej2700::proc15() { } void SpeakerNej2750::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene2750 *scene = (Scene2750 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -916,7 +997,7 @@ void SpeakerNej2750::proc15() { } void SpeakerNej2800::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene2750 *scene = (Scene2750 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -948,7 +1029,7 @@ SpeakerPharisha::SpeakerPharisha(): VisualSpeaker() { _speakerName = "PHARISHA"; _color1 = 151; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -957,7 +1038,7 @@ SpeakerPharisha::SpeakerPharisha(): VisualSpeaker() { } void SpeakerPharisha2435::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene2435 *scene = (Scene2435 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -984,7 +1065,7 @@ SpeakerPrivate3210::SpeakerPrivate3210() { _speakerName = "Private"; _color1 = 45; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -993,7 +1074,7 @@ SpeakerPrivate3210::SpeakerPrivate3210() { } void SpeakerPrivate3210::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene3210 *scene = (Scene3210 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -1023,7 +1104,7 @@ SpeakerProtector3600::SpeakerProtector3600() { _speakerName = "Protector"; _color1 = 170; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -1032,7 +1113,7 @@ SpeakerProtector3600::SpeakerProtector3600() { } void SpeakerProtector3600::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene3600 *scene = (Scene3600 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -1084,7 +1165,7 @@ SpeakerQuinn::SpeakerQuinn(): VisualSpeaker() { _speakerName = "QUINN"; _color1 = 60; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -1093,7 +1174,7 @@ SpeakerQuinn::SpeakerQuinn(): VisualSpeaker() { } void SpeakerQuinn300::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 3) { @@ -1140,7 +1221,7 @@ void SpeakerQuinn300::proc15() { } void SpeakerQuinn1100::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (v == 0) @@ -1150,7 +1231,7 @@ void SpeakerQuinn1100::proc15() { _object2 = &R2_GLOBALS._player; } else { Scene1100 *scene = (Scene1100 *)R2_GLOBALS._sceneManager._scene; - _object2 = &scene->_actor16; + _object2 = &scene->_seeker; } _object2->hide(); @@ -1188,7 +1269,7 @@ void SpeakerQuinn1100::proc15() { } void SpeakerQuinn2435::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 1) { @@ -1214,7 +1295,7 @@ void SpeakerQuinn2435::proc15() { } void SpeakerQuinn2450::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 1) { @@ -1242,7 +1323,7 @@ void SpeakerQuinn2450::proc15() { } void SpeakerQuinn2700::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { _object2 = &R2_GLOBALS._player; @@ -1273,7 +1354,7 @@ void SpeakerQuinn2700::proc15() { } void SpeakerQuinn2750::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { _object2 = &R2_GLOBALS._player; @@ -1304,7 +1385,7 @@ void SpeakerQuinn2750::proc15() { } void SpeakerQuinn2800::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { _object2 = &R2_GLOBALS._player; @@ -1345,7 +1426,7 @@ void SpeakerQuinn2800::proc15() { void SpeakerQuinn3255::proc15() { Scene3255 *scene = (Scene3255 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { _object2 = &scene->_actor4; @@ -1368,7 +1449,7 @@ void SpeakerQuinn3255::proc15() { void SpeakerQuinn3375::proc15() { Scene3375 *scene = (Scene3375 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 1) @@ -1419,7 +1500,7 @@ void SpeakerQuinn3375::proc15() { void SpeakerQuinn3385::proc15() { Scene3385 *scene = (Scene3385 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 1) @@ -1474,7 +1555,7 @@ void SpeakerQuinn3385::proc15() { void SpeakerQuinn3395::proc15() { Scene3395 *scene = (Scene3395 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 1) @@ -1529,7 +1610,7 @@ void SpeakerQuinn3395::proc15() { void SpeakerQuinn3400::proc15() { Scene3400 *scene = (Scene3400 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 1) @@ -1578,7 +1659,7 @@ void SpeakerQuinn3400::proc15() { void SpeakerQuinn3600::proc15() { Scene3600 *scene = (Scene3600 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 1) @@ -1626,7 +1707,7 @@ void SpeakerQuinn3600::proc15() { void SpeakerQuinn3700::setText(const Common::String &msg) { Scene3700 *scene = (Scene3700 *)R2_GLOBALS._sceneManager._scene; - switch (_fieldF6) { + switch (_speakerMode) { case 2: scene->_actor3.setup(30, 1, 1); R2_GLOBALS._sound2.play(44); @@ -1644,7 +1725,7 @@ void SpeakerQuinn3700::setText(const Common::String &msg) { void SpeakerQuinn3700::proc15() { Scene3700 *scene = (Scene3700 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { _object2 = &scene->_actor1; @@ -1701,7 +1782,7 @@ SpeakerQuinnL::SpeakerQuinnL(): VisualSpeaker() { _speakerName = "QUINNL"; _color1 = 35; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -1718,7 +1799,7 @@ SpeakerRalf3245::SpeakerRalf3245() { _speakerName = "Ralf"; _color1 = 5; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -1727,7 +1808,7 @@ SpeakerRalf3245::SpeakerRalf3245() { } void SpeakerRalf3245::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene3245 *scene = (Scene3245 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -1770,7 +1851,7 @@ SpeakerRocko::SpeakerRocko() { _speakerName = "Rocko"; _color1 = 5; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -1779,7 +1860,7 @@ SpeakerRocko::SpeakerRocko() { } void SpeakerRocko3200::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene3200 *scene = (Scene3200 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -1802,7 +1883,7 @@ void SpeakerRocko3200::proc15() { } void SpeakerRocko3220::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene3220 *scene = (Scene3220 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -1825,7 +1906,7 @@ void SpeakerRocko3220::proc15() { } void SpeakerRocko3230::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene3230 *scene = (Scene3230 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -1855,7 +1936,7 @@ SpeakerSeeker::SpeakerSeeker(): VisualSpeaker() { _speakerName = "SEEKER"; _color1 = 35; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -1864,10 +1945,10 @@ SpeakerSeeker::SpeakerSeeker(): VisualSpeaker() { } void SpeakerSeeker300::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { - if (R2_GLOBALS._player._characterIndex == 3) { + if (R2_GLOBALS._player._characterIndex == 2) { _object2 = &R2_GLOBALS._player; } else { Scene300 *scene = (Scene300 *)R2_GLOBALS._sceneManager._scene; @@ -1900,7 +1981,7 @@ void SpeakerSeeker300::proc15() { } void SpeakerSeeker1100::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (v == 0) @@ -1910,7 +1991,7 @@ void SpeakerSeeker1100::proc15() { _object2 = &R2_GLOBALS._player; } else { Scene1100 *scene = (Scene1100 *)R2_GLOBALS._sceneManager._scene; - _object2 = &scene->_actor16; + _object2 = &scene->_seeker; } _object2->hide(); @@ -1959,7 +2040,7 @@ void SpeakerSeeker1100::proc15() { } void SpeakerSeeker1900::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 2) { @@ -1989,7 +2070,7 @@ void SpeakerSeeker1900::proc15() { } void SpeakerSeeker2435::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 2) { @@ -2015,7 +2096,7 @@ void SpeakerSeeker2435::proc15() { } void SpeakerSeeker2450::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 2) { @@ -2042,7 +2123,7 @@ void SpeakerSeeker2450::proc15() { void SpeakerSeeker3375::proc15() { Scene3375 *scene = (Scene3375 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 2) @@ -2091,7 +2172,7 @@ void SpeakerSeeker3375::proc15() { void SpeakerSeeker3385::proc15() { Scene3385 *scene = (Scene3385 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 2) @@ -2140,7 +2221,7 @@ void SpeakerSeeker3385::proc15() { void SpeakerSeeker3395::proc15() { Scene3395 *scene = (Scene3395 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 2) @@ -2189,7 +2270,7 @@ void SpeakerSeeker3395::proc15() { void SpeakerSeeker3400::proc15() { Scene3400 *scene = (Scene3400 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 2) @@ -2248,7 +2329,7 @@ void SpeakerSeeker3400::proc15() { void SpeakerSeeker3600::proc15() { Scene3600 *scene = (Scene3600 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { if (R2_GLOBALS._player._characterIndex == 2) @@ -2295,7 +2376,7 @@ void SpeakerSeeker3600::proc15() { void SpeakerSeeker3700::setText(const Common::String &msg) { Scene3700 *scene = (Scene3700 *)R2_GLOBALS._sceneManager._scene; - if (_fieldF6 == 1) { + if (_speakerMode == 1) { R2_GLOBALS._sound2.play(44); scene->_actor3.setup(30, 8, 1); } else { @@ -2307,7 +2388,7 @@ void SpeakerSeeker3700::setText(const Common::String &msg) { void SpeakerSeeker3700::proc15() { Scene3700 *scene = (Scene3700 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { _object2 = &scene->_actor2; @@ -2359,7 +2440,7 @@ SpeakerSeekerL::SpeakerSeekerL(): VisualSpeaker() { _speakerName = "SEEKERL"; _color1 = 35; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -2376,7 +2457,7 @@ SpeakerSocko3200::SpeakerSocko3200() { _speakerName = "Socko"; _color1 = 10; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -2385,7 +2466,7 @@ SpeakerSocko3200::SpeakerSocko3200() { } void SpeakerSocko3200::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene3200 *scene = (Scene3200 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -2415,7 +2496,7 @@ SpeakerSoldier::SpeakerSoldier(int colour) { _speakerName = "SOLDIER"; _color1 = colour; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -2424,7 +2505,7 @@ SpeakerSoldier::SpeakerSoldier(int colour) { } void SpeakerSoldier300::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { Scene300 *scene = (Scene300 *)R2_GLOBALS._sceneManager._scene; @@ -2455,7 +2536,7 @@ SpeakerTeal::SpeakerTeal(): VisualSpeaker() { _speakerName = "TEAL"; _color1 = 22; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -2468,7 +2549,7 @@ SpeakerTealMode7::SpeakerTealMode7(): SpeakerTeal() { } void SpeakerTeal300::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { Scene300 *scene = (Scene300 *)R2_GLOBALS._sceneManager._scene; @@ -2492,7 +2573,7 @@ void SpeakerTeal300::proc15() { } void SpeakerTeal1625::proc15() { - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { Scene1625 *scene = (Scene1625 *)R2_GLOBALS._sceneManager._scene; @@ -2516,7 +2597,7 @@ void SpeakerTeal1625::proc15() { } void SpeakerTeal3240::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene3240 *scene = (Scene3240 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -2541,7 +2622,7 @@ void SpeakerTeal3240::proc15() { void SpeakerTeal3400::proc15() { Scene3400 *scene = (Scene3400 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { _object2 = &scene->_actor4; @@ -2598,7 +2679,7 @@ void SpeakerTeal3400::proc15() { void SpeakerTeal3600::proc15() { Scene3600 *scene = (Scene3600 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { _object2 = &scene->_actor5; @@ -2659,7 +2740,7 @@ SpeakerTomko3245::SpeakerTomko3245() { _speakerName = "Tomko"; _color1 = 10; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -2668,7 +2749,7 @@ SpeakerTomko3245::SpeakerTomko3245() { } void SpeakerTomko3245::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene3245 *scene = (Scene3245 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -2711,7 +2792,7 @@ SpeakerWebbster::SpeakerWebbster(int colour) { _speakerName = "WEBBSTER"; _color1 = colour; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -2720,7 +2801,7 @@ SpeakerWebbster::SpeakerWebbster(int colour) { } void SpeakerWebbster3240::proc15() { - int v = _fieldF6; + int v = _speakerMode; Scene3240 *scene = (Scene3240 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { @@ -2745,7 +2826,7 @@ void SpeakerWebbster3240::proc15() { void SpeakerWebbster3375::proc15() { Scene3375 *scene = (Scene3375 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { _object2 = &scene->_actor3; @@ -2789,7 +2870,7 @@ void SpeakerWebbster3375::proc15() { void SpeakerWebbster3385::proc15() { Scene3385 *scene = (Scene3385 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { _object2 = &scene->_actor3; @@ -2833,7 +2914,7 @@ void SpeakerWebbster3385::proc15() { void SpeakerWebbster3395::proc15() { Scene3395 *scene = (Scene3395 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { _object2 = &scene->_actor3; @@ -2877,7 +2958,7 @@ void SpeakerWebbster3395::proc15() { void SpeakerWebbster3400::proc15() { Scene3400 *scene = (Scene3400 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { _object2 = &scene->_actor3; @@ -2925,7 +3006,7 @@ SpeakerDutyOfficer::SpeakerDutyOfficer(): VisualSpeaker() { _speakerName = "DUTYOFFICER"; _color1 = 5; _color2 = 0; - _fieldF6 = 0; + _speakerMode = 0; _textWidth = 300; _hideObjects = false; _object2 = NULL; @@ -2936,7 +3017,7 @@ SpeakerDutyOfficer::SpeakerDutyOfficer(): VisualSpeaker() { void SpeakerDutyOfficer::proc15() { Scene180 *scene = (Scene180 *)R2_GLOBALS._sceneManager._scene; - int v = _fieldF6; + int v = _speakerMode; if (!_object2) { _object2 = &scene->_object2; diff --git a/engines/tsage/ringworld2/ringworld2_speakers.h b/engines/tsage/ringworld2/ringworld2_speakers.h index fa2946d56c..532e02576c 100644 --- a/engines/tsage/ringworld2/ringworld2_speakers.h +++ b/engines/tsage/ringworld2/ringworld2_speakers.h @@ -41,21 +41,27 @@ class VisualSpeaker : public Speaker { public: SceneActor _object1; SceneObject *_object2; - int _fieldF6, _fieldF8; + int _speakerMode; + int _fieldF8; int _displayMode; int _soundId; int _delayAmount; bool _removeObject; - int _frameNumber; + uint32 _frameNumber; int _numFrames; + int _delayAmount2; + uint32 _frameNumber2; private: void setFrame(int numFrames); + void setFrame2(int numFrames); public: VisualSpeaker(); virtual Common::String getClassName() { return "VisualSpeaker"; } virtual void synchronize(Serializer &s); virtual void remove(); + virtual void signal(); + virtual void dispatch(); virtual void setText(const Common::String &msg); virtual void proc15() {} virtual void proc16(); diff --git a/engines/tsage/saveload.cpp b/engines/tsage/saveload.cpp index af2f3566ad..7143305586 100644 --- a/engines/tsage/saveload.cpp +++ b/engines/tsage/saveload.cpp @@ -289,7 +289,7 @@ void Saver::writeSavegameHeader(Common::OutSaveFile *out, tSageSavegameHeader &h // Create a thumbnail and save it Graphics::Surface *thumb = new Graphics::Surface(); Graphics::Surface s = g_globals->_screenSurface.lockSurface(); - ::createThumbnail(thumb, (const byte *)s.pixels, SCREEN_WIDTH, SCREEN_HEIGHT, thumbPalette); + ::createThumbnail(thumb, (const byte *)s.getPixels(), SCREEN_WIDTH, SCREEN_HEIGHT, thumbPalette); Graphics::saveThumbnail(*out, *thumb); g_globals->_screenSurface.unlockSurface(); thumb->free(); diff --git a/engines/tsage/saveload.h b/engines/tsage/saveload.h index 4126e31822..d43ef792bc 100644 --- a/engines/tsage/saveload.h +++ b/engines/tsage/saveload.h @@ -150,6 +150,16 @@ public: if (i != this->end()) ++i; this->insert(i, newItem); } + + bool contains(T item) { + typename SynchronizedList<T>::iterator i = this->begin(); + for (; i != this->end(); ++i) { + if (*i == item) + return true; + } + + return false; + } }; /** diff --git a/engines/tsage/user_interface.cpp b/engines/tsage/user_interface.cpp index 4bd9e49875..c0ebb804d2 100644 --- a/engines/tsage/user_interface.cpp +++ b/engines/tsage/user_interface.cpp @@ -84,7 +84,10 @@ void UIQuestion::showDescription(CursorType cursor) { case GType_Ringworld2: if ((cursor == R2_COM_SCANNER) || (cursor == R2_COM_SCANNER_2)) { // Show communicator - warning("TODO: Communicator"); + Ringworld2::SceneExt *scene = static_cast<Ringworld2::SceneExt *> + (R2_GLOBALS._sceneManager._scene); + if (!scene->_sceneAreas.contains(R2_GLOBALS._scannerDialog)) + R2_GLOBALS._scannerDialog->proc12(4, 1, 1, 160, 125); } else { // Show object description SceneItem::display2(3, (int)cursor); @@ -399,7 +402,7 @@ void UIElements::setup(const Common::Point &pt) { } // Setup bottom-right hand buttons - xp += 62; + xp = (g_vm->getGameID() == GType_Ringworld2) ? 255 : 253; int yp = (g_vm->getGameID() == GType_BlueForce) ? 16 : 17; _question.setup(1, 4, 7, xp, yp, 255); _question.setEnabled(false); @@ -410,7 +413,7 @@ void UIElements::setup(const Common::Point &pt) { add(&_scrollLeft); _scrollLeft._isLeft = true; - xp += 22; + xp += (g_vm->getGameID() == GType_Ringworld2) ? 21 : 22; _scrollRight.setup(1, 4, 4, xp, yp, 255); add(&_scrollRight); _scrollRight._isLeft = false; diff --git a/engines/tucker/sequences.cpp b/engines/tucker/sequences.cpp index 16c4f4f6f0..bd03eed00b 100644 --- a/engines/tucker/sequences.cpp +++ b/engines/tucker/sequences.cpp @@ -763,7 +763,7 @@ bool AnimationSequencePlayer::decodeNextAnimationFrame(int index, bool copyDirty if (!copyDirtyRects) { for (uint16 y = 0; (y < surface->h) && (y < kScreenHeight); y++) - memcpy(_offscreenBuffer + y * kScreenWidth, (byte *)surface->pixels + y * surface->pitch, surface->w); + memcpy(_offscreenBuffer + y * kScreenWidth, (const byte *)surface->getBasePtr(0, y), surface->w); } else { _flicPlayer[index].copyDirtyRectsToBuffer(_offscreenBuffer, kScreenWidth); } @@ -811,7 +811,7 @@ void AnimationSequencePlayer::playIntroSeq19_20() { if (surface) for (int i = 0; i < kScreenWidth * kScreenHeight; ++i) if (_offscreenBuffer[i] == 0) - _offscreenBuffer[i] = *((byte *)surface->pixels + i); + _offscreenBuffer[i] = *((const byte *)surface->getPixels() + i); if (!framesLeft) _changeToNextSequence = true; diff --git a/engines/tucker/tucker.cpp b/engines/tucker/tucker.cpp index 2bd7c47b62..04e83efbe5 100644 --- a/engines/tucker/tucker.cpp +++ b/engines/tucker/tucker.cpp @@ -941,7 +941,7 @@ void TuckerEngine::fadeOutPalette(int colorsCount) { _system->getPaletteManager()->grabPalette(pal, 0, colorsCount); for (int color = 0; color < colorsCount; ++color) { for (int i = 0; i < 3; ++i) { - const int c = int(pal[color * 3 + i]) + kFadePaletteStep * 3; + const int c = int(pal[color * 3 + i]) + kFadePaletteStep * 4; pal[color * 3 + i] = MIN<int>(c, _currentPalette[color * 3 + i]); } } @@ -954,7 +954,7 @@ void TuckerEngine::fadeInPalette(int colorsCount) { _system->getPaletteManager()->grabPalette(pal, 0, colorsCount); for (int color = 0; color < colorsCount; ++color) { for (int i = 0; i < 3; ++i) { - const int c = int(pal[color * 3 + i]) - kFadePaletteStep * 3; + const int c = int(pal[color * 3 + i]) - kFadePaletteStep * 4; pal[color * 3 + i] = MAX<int>(c, 0); } } @@ -2991,6 +2991,7 @@ enum TableInstructionCode { kCode_gfg, kCode_gv, kCode_loc, + kCode_mof, kCode_opt, kCode_opf, kCode_ofg, @@ -3041,6 +3042,7 @@ static const struct { { "gfg", kCode_gfg }, { "gv", kCode_gv }, { "loc", kCode_loc }, + { "mof", kCode_mof }, { "opt", kCode_opt }, { "opf", kCode_opf }, { "ofg", kCode_ofg }, @@ -3062,8 +3064,9 @@ static const struct { int TuckerEngine::readTableInstructionCode(int *index) { bool match = false; + int nameLen = 0; for (int i = 0; _instructions[i].name; ++i) { - const int nameLen = strlen(_instructions[i].name); + nameLen = strlen(_instructions[i].name); if (_instructions[i].name[1] == '0') { if (_instructions[i].name[0] == _tableInstructionsPtr[0] && _instructions[i].name[2] == _tableInstructionsPtr[2]) { const char digit = _tableInstructionsPtr[1]; @@ -3083,6 +3086,7 @@ int TuckerEngine::readTableInstructionCode(int *index) { } } warning("Unhandled instruction '%c%c%c'", _tableInstructionsPtr[0], _tableInstructionsPtr[1], _tableInstructionsPtr[2]); + _tableInstructionsPtr += nameLen + 1; return kCode_invalid; } @@ -3232,6 +3236,9 @@ int TuckerEngine::executeTableInstruction() { case kCode_loc: _nextLocationNum = readTableInstructionParam(2); return 1; + case kCode_mof: + // TODO: Unknown opcode in Spanish version. Identify if this has any function. + return 0; case kCode_opt: _conversationOptionsCount = readTableInstructionParam(2); for (i = 0; i < _conversationOptionsCount; ++i) { diff --git a/engines/wintermute/ad/ad_actor.cpp b/engines/wintermute/ad/ad_actor.cpp index e4c18d6287..94df17c543 100644 --- a/engines/wintermute/ad/ad_actor.cpp +++ b/engines/wintermute/ad/ad_actor.cpp @@ -1457,4 +1457,4 @@ bool AdActor::playAnim(const char *filename) { return AdTalkHolder::playAnim(filename); } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_actor.h b/engines/wintermute/ad/ad_actor.h index 3630c6665b..582b41b8b0 100644 --- a/engines/wintermute/ad/ad_actor.h +++ b/engines/wintermute/ad/ad_actor.h @@ -103,6 +103,6 @@ private: int32 _pFCount; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_entity.cpp b/engines/wintermute/ad/ad_entity.cpp index c43f74b620..388accf34f 100644 --- a/engines/wintermute/ad/ad_entity.cpp +++ b/engines/wintermute/ad/ad_entity.cpp @@ -1134,4 +1134,4 @@ bool AdEntity::setSprite(const char *filename) { } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_entity.h b/engines/wintermute/ad/ad_entity.h index c23b37366d..bdbd271667 100644 --- a/engines/wintermute/ad/ad_entity.h +++ b/engines/wintermute/ad/ad_entity.h @@ -68,6 +68,6 @@ private: TEntityType _subtype; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_game.cpp b/engines/wintermute/ad/ad_game.cpp index ead68f7729..d5799e851b 100644 --- a/engines/wintermute/ad/ad_game.cpp +++ b/engines/wintermute/ad/ad_game.cpp @@ -2282,4 +2282,4 @@ bool AdGame::onScriptShutdown(ScScript *script) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_game.h b/engines/wintermute/ad/ad_game.h index 2032a1723f..cb5147501d 100644 --- a/engines/wintermute/ad/ad_game.h +++ b/engines/wintermute/ad/ad_game.h @@ -158,6 +158,6 @@ private: AdInventoryBox *_inventoryBox; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_inventory.cpp b/engines/wintermute/ad/ad_inventory.cpp index e9b6e56f16..544d8310d0 100644 --- a/engines/wintermute/ad/ad_inventory.cpp +++ b/engines/wintermute/ad/ad_inventory.cpp @@ -133,4 +133,4 @@ bool AdInventory::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_inventory.h b/engines/wintermute/ad/ad_inventory.h index 999200b465..9de831b2a0 100644 --- a/engines/wintermute/ad/ad_inventory.h +++ b/engines/wintermute/ad/ad_inventory.h @@ -47,6 +47,6 @@ public: int32 _scrollOffset; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_inventory_box.cpp b/engines/wintermute/ad/ad_inventory_box.cpp index 110359917b..d703de1714 100644 --- a/engines/wintermute/ad/ad_inventory_box.cpp +++ b/engines/wintermute/ad/ad_inventory_box.cpp @@ -386,4 +386,4 @@ bool AdInventoryBox::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_inventory_box.h b/engines/wintermute/ad/ad_inventory_box.h index 9792b1ea66..f65bd8d8f0 100644 --- a/engines/wintermute/ad/ad_inventory_box.h +++ b/engines/wintermute/ad/ad_inventory_box.h @@ -60,6 +60,6 @@ private: int32 _itemWidth; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_item.cpp b/engines/wintermute/ad/ad_item.cpp index 1a46eb783b..7d05461169 100644 --- a/engines/wintermute/ad/ad_item.cpp +++ b/engines/wintermute/ad/ad_item.cpp @@ -810,4 +810,4 @@ bool AdItem::getExtendedFlag(const char *flagName) { } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_item.h b/engines/wintermute/ad/ad_item.h index b8351448a7..dd7039db43 100644 --- a/engines/wintermute/ad/ad_item.h +++ b/engines/wintermute/ad/ad_item.h @@ -64,6 +64,6 @@ private: char *_amountString; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_layer.cpp b/engines/wintermute/ad/ad_layer.cpp index 7bf79e4ae5..c833b59163 100644 --- a/engines/wintermute/ad/ad_layer.cpp +++ b/engines/wintermute/ad/ad_layer.cpp @@ -561,4 +561,4 @@ bool AdLayer::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_layer.h b/engines/wintermute/ad/ad_layer.h index 8fe4d4f91e..b260b919fd 100644 --- a/engines/wintermute/ad/ad_layer.h +++ b/engines/wintermute/ad/ad_layer.h @@ -53,6 +53,6 @@ public: virtual const char *scToString() override; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_node_state.cpp b/engines/wintermute/ad/ad_node_state.cpp index d52201a08d..876c5a8bb4 100644 --- a/engines/wintermute/ad/ad_node_state.cpp +++ b/engines/wintermute/ad/ad_node_state.cpp @@ -192,4 +192,4 @@ bool AdNodeState::transferEntity(AdEntity *entity, bool includingSprites, bool s return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_node_state.h b/engines/wintermute/ad/ad_node_state.h index e2050815a7..4b5b46ee60 100644 --- a/engines/wintermute/ad/ad_node_state.h +++ b/engines/wintermute/ad/ad_node_state.h @@ -55,6 +55,6 @@ private: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_object.cpp b/engines/wintermute/ad/ad_object.cpp index 741d6e6fc6..0d5011f92d 100644 --- a/engines/wintermute/ad/ad_object.cpp +++ b/engines/wintermute/ad/ad_object.cpp @@ -1299,4 +1299,4 @@ bool AdObject::updatePartEmitter() { return _partEmitter->update(); } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_object.h b/engines/wintermute/ad/ad_object.h index c6573315da..9e30f69855 100644 --- a/engines/wintermute/ad/ad_object.h +++ b/engines/wintermute/ad/ad_object.h @@ -123,6 +123,6 @@ private: AdInventory *_inventory; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_path.cpp b/engines/wintermute/ad/ad_path.cpp index 5b36ed6471..91a24cbf7d 100644 --- a/engines/wintermute/ad/ad_path.cpp +++ b/engines/wintermute/ad/ad_path.cpp @@ -117,4 +117,4 @@ bool AdPath::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_path.h b/engines/wintermute/ad/ad_path.h index 3f38355b94..9de0bcad2c 100644 --- a/engines/wintermute/ad/ad_path.h +++ b/engines/wintermute/ad/ad_path.h @@ -51,6 +51,6 @@ public: bool _ready; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_path_point.cpp b/engines/wintermute/ad/ad_path_point.cpp index be4b487466..d5108ad8c1 100644 --- a/engines/wintermute/ad/ad_path_point.cpp +++ b/engines/wintermute/ad/ad_path_point.cpp @@ -72,4 +72,4 @@ bool AdPathPoint::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_path_point.h b/engines/wintermute/ad/ad_path_point.h index 04648b1733..5e6b8c61ea 100644 --- a/engines/wintermute/ad/ad_path_point.h +++ b/engines/wintermute/ad/ad_path_point.h @@ -45,6 +45,6 @@ public: int32 _distance; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_region.cpp b/engines/wintermute/ad/ad_region.cpp index acd5f13397..bc9ac903c6 100644 --- a/engines/wintermute/ad/ad_region.cpp +++ b/engines/wintermute/ad/ad_region.cpp @@ -404,9 +404,9 @@ bool AdRegion::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_alpha)); persistMgr->transfer(TMEMBER(_blocked)); persistMgr->transfer(TMEMBER(_decoration)); - persistMgr->transfer(TMEMBER(_zoom)); + persistMgr->transferFloat(TMEMBER(_zoom)); return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_region.h b/engines/wintermute/ad/ad_region.h index bc9eab085e..637c742c9c 100644 --- a/engines/wintermute/ad/ad_region.h +++ b/engines/wintermute/ad/ad_region.h @@ -59,6 +59,6 @@ private: bool _decoration; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_response.cpp b/engines/wintermute/ad/ad_response.cpp index 4483bbc667..fa05224b06 100644 --- a/engines/wintermute/ad/ad_response.cpp +++ b/engines/wintermute/ad/ad_response.cpp @@ -166,7 +166,7 @@ BaseFont *AdResponse::getFont() const { int32 AdResponse::getID() const { return _iD; } - + const char *AdResponse::getText() const { return _text; } @@ -175,4 +175,4 @@ const char *AdResponse::getTextOrig() const { return _textOrig; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_response.h b/engines/wintermute/ad/ad_response.h index 57cd302e9d..00ebafbdb0 100644 --- a/engines/wintermute/ad/ad_response.h +++ b/engines/wintermute/ad/ad_response.h @@ -68,6 +68,6 @@ private: char *_textOrig; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_response_box.cpp b/engines/wintermute/ad/ad_response_box.cpp index a589bf3a30..9d7c17ac74 100644 --- a/engines/wintermute/ad/ad_response_box.cpp +++ b/engines/wintermute/ad/ad_response_box.cpp @@ -737,4 +737,4 @@ bool AdResponseBox::getObjects(BaseArray<UIObject *> &objects, bool interactiveO return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_response_box.h b/engines/wintermute/ad/ad_response_box.h index cb57b98924..7598e8b569 100644 --- a/engines/wintermute/ad/ad_response_box.h +++ b/engines/wintermute/ad/ad_response_box.h @@ -94,6 +94,6 @@ private: UIWindow *_window; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_response_context.cpp b/engines/wintermute/ad/ad_response_context.cpp index 663ef49a24..0b58f5ba0c 100644 --- a/engines/wintermute/ad/ad_response_context.cpp +++ b/engines/wintermute/ad/ad_response_context.cpp @@ -68,4 +68,4 @@ void AdResponseContext::setContext(const char *context) { } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_response_context.h b/engines/wintermute/ad/ad_response_context.h index dd0008a728..bc30b4a1c9 100644 --- a/engines/wintermute/ad/ad_response_context.h +++ b/engines/wintermute/ad/ad_response_context.h @@ -47,6 +47,6 @@ private: char *_context; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_rot_level.cpp b/engines/wintermute/ad/ad_rot_level.cpp index 4d7f27aec7..d925b0d57a 100644 --- a/engines/wintermute/ad/ad_rot_level.cpp +++ b/engines/wintermute/ad/ad_rot_level.cpp @@ -153,9 +153,9 @@ bool AdRotLevel::persist(BasePersistenceManager *persistMgr) { BaseObject::persist(persistMgr); - persistMgr->transfer(TMEMBER(_rotation)); + persistMgr->transferFloat(TMEMBER(_rotation)); return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_rot_level.h b/engines/wintermute/ad/ad_rot_level.h index 3466e46ba5..fe2d1691cd 100644 --- a/engines/wintermute/ad/ad_rot_level.h +++ b/engines/wintermute/ad/ad_rot_level.h @@ -45,6 +45,6 @@ public: bool loadBuffer(byte *buffer, bool complete = true); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_scale_level.cpp b/engines/wintermute/ad/ad_scale_level.cpp index e80f38bd0f..59e6d57787 100644 --- a/engines/wintermute/ad/ad_scale_level.cpp +++ b/engines/wintermute/ad/ad_scale_level.cpp @@ -154,9 +154,9 @@ bool AdScaleLevel::persist(BasePersistenceManager *persistMgr) { BaseObject::persist(persistMgr); - persistMgr->transfer(TMEMBER(_scale)); + persistMgr->transferFloat(TMEMBER(_scale)); return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_scale_level.h b/engines/wintermute/ad/ad_scale_level.h index 516f507a5a..b2dd7aa91f 100644 --- a/engines/wintermute/ad/ad_scale_level.h +++ b/engines/wintermute/ad/ad_scale_level.h @@ -47,6 +47,6 @@ private: float _scale; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_scene.cpp b/engines/wintermute/ad/ad_scene.cpp index 4d0068fad1..668b39853b 100644 --- a/engines/wintermute/ad/ad_scene.cpp +++ b/engines/wintermute/ad/ad_scene.cpp @@ -2989,4 +2989,4 @@ bool AdScene::getRegionObjects(AdRegion *region, BaseArray<AdObject *> &objects, return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_scene.h b/engines/wintermute/ad/ad_scene.h index cd144b77ef..5beb10e546 100644 --- a/engines/wintermute/ad/ad_scene.h +++ b/engines/wintermute/ad/ad_scene.h @@ -176,6 +176,6 @@ private: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_scene_node.cpp b/engines/wintermute/ad/ad_scene_node.cpp index e9b80b3cc8..8548da91db 100644 --- a/engines/wintermute/ad/ad_scene_node.cpp +++ b/engines/wintermute/ad/ad_scene_node.cpp @@ -79,4 +79,4 @@ bool AdSceneNode::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_scene_state.cpp b/engines/wintermute/ad/ad_scene_state.cpp index 8e022ab115..58cb5f514a 100644 --- a/engines/wintermute/ad/ad_scene_state.cpp +++ b/engines/wintermute/ad/ad_scene_state.cpp @@ -95,4 +95,4 @@ AdNodeState *AdSceneState::getNodeState(const char *name, bool saving) { } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_scene_state.h b/engines/wintermute/ad/ad_scene_state.h index 600aa4b581..067c737b2e 100644 --- a/engines/wintermute/ad/ad_scene_state.h +++ b/engines/wintermute/ad/ad_scene_state.h @@ -48,6 +48,6 @@ private: BaseArray<AdNodeState *> _nodeStates; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_sentence.cpp b/engines/wintermute/ad/ad_sentence.cpp index 70a57a624d..d5baa8291f 100644 --- a/engines/wintermute/ad/ad_sentence.cpp +++ b/engines/wintermute/ad/ad_sentence.cpp @@ -358,4 +358,4 @@ bool AdSentence::canSkip() { return (_gameRef->getTimer()->getTime() - _startTime) > 300; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_sentence.h b/engines/wintermute/ad/ad_sentence.h index 6f255578f7..c491ad99a2 100644 --- a/engines/wintermute/ad/ad_sentence.h +++ b/engines/wintermute/ad/ad_sentence.h @@ -80,6 +80,6 @@ private: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_sprite_set.cpp b/engines/wintermute/ad/ad_sprite_set.cpp index 6c802c4863..9eb3bd0686 100644 --- a/engines/wintermute/ad/ad_sprite_set.cpp +++ b/engines/wintermute/ad/ad_sprite_set.cpp @@ -353,4 +353,4 @@ bool AdSpriteSet::containsSprite(BaseSprite *sprite) { return false; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_sprite_set.h b/engines/wintermute/ad/ad_sprite_set.h index 61043aa3d6..ef5ef3a94f 100644 --- a/engines/wintermute/ad/ad_sprite_set.h +++ b/engines/wintermute/ad/ad_sprite_set.h @@ -48,6 +48,6 @@ public: BaseSprite *_sprites[NUM_DIRECTIONS]; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_talk_def.cpp b/engines/wintermute/ad/ad_talk_def.cpp index bf72b2916b..f10a0e2fb9 100644 --- a/engines/wintermute/ad/ad_talk_def.cpp +++ b/engines/wintermute/ad/ad_talk_def.cpp @@ -282,4 +282,4 @@ BaseSprite *AdTalkDef::getDefaultSprite(TDirection dir) { } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_talk_def.h b/engines/wintermute/ad/ad_talk_def.h index 2375360d89..726eefbe4c 100644 --- a/engines/wintermute/ad/ad_talk_def.h +++ b/engines/wintermute/ad/ad_talk_def.h @@ -53,6 +53,6 @@ public: virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent = 0) override; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_talk_holder.cpp b/engines/wintermute/ad/ad_talk_holder.cpp index 33deab7805..6041105b93 100644 --- a/engines/wintermute/ad/ad_talk_holder.cpp +++ b/engines/wintermute/ad/ad_talk_holder.cpp @@ -399,4 +399,4 @@ bool AdTalkHolder::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_talk_holder.h b/engines/wintermute/ad/ad_talk_holder.h index 501acbc885..ab48c3aaf4 100644 --- a/engines/wintermute/ad/ad_talk_holder.h +++ b/engines/wintermute/ad/ad_talk_holder.h @@ -52,6 +52,6 @@ public: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_talk_node.cpp b/engines/wintermute/ad/ad_talk_node.cpp index f03c24ea94..ce86dccd8e 100644 --- a/engines/wintermute/ad/ad_talk_node.cpp +++ b/engines/wintermute/ad/ad_talk_node.cpp @@ -292,4 +292,4 @@ BaseSprite *AdTalkNode::getSprite(TDirection dir) { } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_talk_node.h b/engines/wintermute/ad/ad_talk_node.h index 012fa2133e..01dfb6b4ff 100644 --- a/engines/wintermute/ad/ad_talk_node.h +++ b/engines/wintermute/ad/ad_talk_node.h @@ -58,6 +58,6 @@ public: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_types.h b/engines/wintermute/ad/ad_types.h index ae5882f4ee..dc1a54b91d 100644 --- a/engines/wintermute/ad/ad_types.h +++ b/engines/wintermute/ad/ad_types.h @@ -102,6 +102,6 @@ typedef enum { GEOM_GENERIC } TGeomNodeType; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ad/ad_waypoint_group.cpp b/engines/wintermute/ad/ad_waypoint_group.cpp index 96dece34b8..cc7982cb9d 100644 --- a/engines/wintermute/ad/ad_waypoint_group.cpp +++ b/engines/wintermute/ad/ad_waypoint_group.cpp @@ -196,7 +196,7 @@ bool AdWaypointGroup::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_active)); persistMgr->transfer(TMEMBER(_editorSelectedPoint)); - persistMgr->transfer(TMEMBER(_lastMimicScale)); + persistMgr->transferFloat(TMEMBER(_lastMimicScale)); persistMgr->transfer(TMEMBER(_lastMimicX)); persistMgr->transfer(TMEMBER(_lastMimicY)); _points.persist(persistMgr); @@ -267,4 +267,4 @@ bool AdWaypointGroup::mimic(AdWaypointGroup *wpt, float scale, int argX, int arg return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_waypoint_group.h b/engines/wintermute/ad/ad_waypoint_group.h index 79b28e0d22..af97a21290 100644 --- a/engines/wintermute/ad/ad_waypoint_group.h +++ b/engines/wintermute/ad/ad_waypoint_group.h @@ -56,6 +56,6 @@ private: int32 _lastMimicY; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base.cpp b/engines/wintermute/base/base.cpp index d01972b82f..a64770c577 100644 --- a/engines/wintermute/base/base.cpp +++ b/engines/wintermute/base/base.cpp @@ -183,4 +183,4 @@ bool BaseClass::saveAsText(BaseDynamicBuffer *buffer, int indent) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base.h b/engines/wintermute/base/base.h index 7f2796c6e0..48ebe49a97 100644 --- a/engines/wintermute/base/base.h +++ b/engines/wintermute/base/base.h @@ -57,6 +57,6 @@ protected: Common::HashMap<Common::String, Common::String>::iterator _editorPropsIter; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_active_rect.cpp b/engines/wintermute/base/base_active_rect.cpp index 7a91854c57..abeaa18d54 100644 --- a/engines/wintermute/base/base_active_rect.cpp +++ b/engines/wintermute/base/base_active_rect.cpp @@ -109,4 +109,4 @@ void BaseActiveRect::clipRect() { BasePlatform::intersectRect(&_rect, &_rect, &rc); } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_active_rect.h b/engines/wintermute/base/base_active_rect.h index 982a0902d0..a3c0746618 100644 --- a/engines/wintermute/base/base_active_rect.h +++ b/engines/wintermute/base/base_active_rect.h @@ -55,6 +55,6 @@ public: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_dynamic_buffer.cpp b/engines/wintermute/base/base_dynamic_buffer.cpp index f684420b1e..5334ae46c4 100644 --- a/engines/wintermute/base/base_dynamic_buffer.cpp +++ b/engines/wintermute/base/base_dynamic_buffer.cpp @@ -201,4 +201,4 @@ void BaseDynamicBuffer::putTextForm(const char *format, va_list argptr) { putBytes((byte *)buff, strlen(buff)); } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_dynamic_buffer.h b/engines/wintermute/base/base_dynamic_buffer.h index ad78ebad00..2804d78895 100644 --- a/engines/wintermute/base/base_dynamic_buffer.h +++ b/engines/wintermute/base/base_dynamic_buffer.h @@ -60,6 +60,6 @@ private: void putTextForm(const char *format, va_list argptr); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_engine.cpp b/engines/wintermute/base/base_engine.cpp index d4b17a0a64..acb12bbe5f 100644 --- a/engines/wintermute/base/base_engine.cpp +++ b/engines/wintermute/base/base_engine.cpp @@ -44,10 +44,11 @@ BaseEngine::BaseEngine() { _classReg = nullptr; _rnd = nullptr; _gameId = ""; + _language = Common::UNK_LANG; } -void BaseEngine::init(Common::Language lang) { - _fileManager = new BaseFileManager(lang); +void BaseEngine::init() { + _fileManager = new BaseFileManager(_language); // Don't forget to register your random source _rnd = new Common::RandomSource("Wintermute"); _classReg = new SystemClassRegistry(); @@ -60,9 +61,11 @@ BaseEngine::~BaseEngine() { delete _classReg; } -void BaseEngine::createInstance(const Common::String &gameid, Common::Language lang) { - instance()._gameId = gameid; - instance().init(lang); +void BaseEngine::createInstance(const Common::String &targetName, const Common::String &gameId, Common::Language lang) { + instance()._targetName = targetName; + instance()._gameId = gameId; + instance()._language = lang; + instance().init(); } void BaseEngine::LOG(bool res, const char *fmt, ...) { @@ -122,4 +125,4 @@ const Timer *BaseEngine::getLiveTimer() { } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_engine.h b/engines/wintermute/base/base_engine.h index d972e6ebbc..a5eafd3597 100644 --- a/engines/wintermute/base/base_engine.h +++ b/engines/wintermute/base/base_engine.h @@ -44,17 +44,19 @@ class BaseRenderer; class SystemClassRegistry; class Timer; class BaseEngine : public Common::Singleton<Wintermute::BaseEngine> { - void init(Common::Language lang); + void init(); BaseFileManager *_fileManager; Common::String _gameId; + Common::String _targetName; BaseGame *_gameRef; // We need random numbers Common::RandomSource *_rnd; SystemClassRegistry *_classReg; + Common::Language _language; public: BaseEngine(); ~BaseEngine(); - static void createInstance(const Common::String &gameid, Common::Language lang); + static void createInstance(const Common::String &targetName, const Common::String &gameId, Common::Language lang); void setGameRef(BaseGame *gameRef) { _gameRef = gameRef; } Common::RandomSource *getRandomSource() { return _rnd; } @@ -68,9 +70,11 @@ public: static const Timer *getTimer(); static const Timer *getLiveTimer(); static void LOG(bool res, const char *fmt, ...); - const char *getGameId() { return _gameId.c_str(); } + const char *getGameTargetName() const { return _targetName.c_str(); } + Common::String getGameId() const { return _gameId; } + Common::Language getLanguage() const { return _language; } }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_fader.cpp b/engines/wintermute/base/base_fader.cpp index 0d17b07a9d..7978230964 100644 --- a/engines/wintermute/base/base_fader.cpp +++ b/engines/wintermute/base/base_fader.cpp @@ -193,4 +193,4 @@ bool BaseFader::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_fader.h b/engines/wintermute/base/base_fader.h index 845ce2f244..087b19bc44 100644 --- a/engines/wintermute/base/base_fader.h +++ b/engines/wintermute/base/base_fader.h @@ -58,6 +58,6 @@ private: uint32 _startTime; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_file_manager.cpp b/engines/wintermute/base/base_file_manager.cpp index 7d59b03684..bea7e53445 100644 --- a/engines/wintermute/base/base_file_manager.cpp +++ b/engines/wintermute/base/base_file_manager.cpp @@ -269,7 +269,7 @@ Common::SeekableReadStream *BaseFileManager::openPkgFile(const Common::String &f bool BaseFileManager::hasFile(const Common::String &filename) { if (scumm_strnicmp(filename.c_str(), "savegame:", 9) == 0) { - BasePersistenceManager pm(BaseEngine::instance().getGameId()); + BasePersistenceManager pm(BaseEngine::instance().getGameTargetName()); if (filename.size() <= 9) { return false; } @@ -360,4 +360,4 @@ BaseFileManager *BaseFileManager::getEngineInstance() { return nullptr; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_file_manager.h b/engines/wintermute/base/base_file_manager.h index 7ed3a6c7cb..8c2876f681 100644 --- a/engines/wintermute/base/base_file_manager.h +++ b/engines/wintermute/base/base_file_manager.h @@ -74,6 +74,6 @@ private: // the detector too, without launching the entire engine: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_frame.cpp b/engines/wintermute/base/base_frame.cpp index 9fb5770f79..eaad024120 100644 --- a/engines/wintermute/base/base_frame.cpp +++ b/engines/wintermute/base/base_frame.cpp @@ -764,4 +764,4 @@ const char *BaseFrame::scToString() { return "[frame]"; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_frame.h b/engines/wintermute/base/base_frame.h index 954851c77f..bf1e40daa1 100644 --- a/engines/wintermute/base/base_frame.h +++ b/engines/wintermute/base/base_frame.h @@ -70,6 +70,6 @@ private: BaseSound *_sound; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_game.cpp b/engines/wintermute/base/base_game.cpp index 4d8e79b5c2..b2c05d271d 100644 --- a/engines/wintermute/base/base_game.cpp +++ b/engines/wintermute/base/base_game.cpp @@ -81,7 +81,7 @@ IMPLEMENT_PERSISTENT(BaseGame, true) ////////////////////////////////////////////////////////////////////// -BaseGame::BaseGame(const Common::String &gameId) : BaseObject(this), _gameId(gameId), _timerNormal(), _timerLive() { +BaseGame::BaseGame(const Common::String &targetName) : BaseObject(this), _targetName(targetName), _timerNormal(), _timerLive() { _shuttingDown = false; _state = GAME_RUNNING; @@ -212,7 +212,7 @@ BaseGame::BaseGame(const Common::String &gameId) : BaseObject(this), _gameId(gam #else*/ _touchInterface = false; _constrainedMemory = false; - + _settings = new BaseGameSettings(this); //#endif @@ -1276,11 +1276,7 @@ bool BaseGame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack stack->correctParams(2); const char *key = stack->pop()->getString(); const char *initVal = stack->pop()->getString(); - Common::String privKey = "wme_" + StringUtil::encodeSetting(key); - Common::String result = initVal; - if (ConfMan.hasKey(privKey)) { - result = StringUtil::decodeSetting(ConfMan.get(key)); - } + Common::String result = readRegistryString(key, initVal); stack->pushString(result.c_str()); return STATUS_OK; } @@ -3072,8 +3068,8 @@ bool BaseGame::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_offsetX)); persistMgr->transfer(TMEMBER(_offsetY)); - persistMgr->transfer(TMEMBER(_offsetPercentX)); - persistMgr->transfer(TMEMBER(_offsetPercentY)); + persistMgr->transferFloat(TMEMBER(_offsetPercentX)); + persistMgr->transferFloat(TMEMBER(_offsetPercentY)); persistMgr->transfer(TMEMBER(_origInteractive)); persistMgr->transfer(TMEMBER_INT(_origState)); @@ -3734,7 +3730,7 @@ bool BaseGame::onWindowClose() { bool BaseGame::displayDebugInfo() { const uint32 strLength = 100; char str[strLength]; - + if (_debugShowFPS) { sprintf(str, "FPS: %d", _gameRef->_fps); _systemFont->drawText((byte *)str, 0, 0, 100, TAL_LEFT); @@ -3902,4 +3898,26 @@ char *BaseGame::getKeyFromStringTable(const char *str) const { return _settings->getKeyFromStringTable(str); } -} // end of namespace Wintermute +Common::String BaseGame::readRegistryString(const Common::String &key, const Common::String &initValue) const { + // Game specific hacks: + Common::String result = initValue; + // James Peris: + if (BaseEngine::instance().getGameId() == "jamesperis" && key == "Language") { + Common::Language language = BaseEngine::instance().getLanguage(); + if (language == Common::EN_ANY) { + result = "english"; + } else if (language == Common::ES_ESP) { + result = "spanish"; + } else { + error("Invalid language set for James Peris"); + } + } else { // Just fallback to using ConfMan for now + Common::String privKey = "wme_" + StringUtil::encodeSetting(key); + if (ConfMan.hasKey(privKey)) { + result = StringUtil::decodeSetting(ConfMan.get(key)); + } + } + return result; +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_game.h b/engines/wintermute/base/base_game.h index d51255d013..d295bb6b1a 100644 --- a/engines/wintermute/base/base_game.h +++ b/engines/wintermute/base/base_game.h @@ -137,7 +137,7 @@ public: bool initialize2(); bool initialize3(); BaseTransitionMgr *_transMgr; - + // String Table void expandStringByStringTable(char **str) const; char *getKeyFromStringTable(const char *str) const; @@ -150,7 +150,7 @@ public: BaseScriptable *_mathClass; BaseSurfaceStorage *_surfaceStorage; BaseFontStorage *_fontStorage; - BaseGame(const Common::String &gameId); + BaseGame(const Common::String &targetName); virtual ~BaseGame(); bool _debugDebugMode; @@ -173,8 +173,8 @@ public: // compatibility bits bool _compatKillMethodThreads; - const char* getGameId() const { return _gameId.c_str(); } - void setGameId(const Common::String& gameId) { _gameId = gameId; } + const char* getGameTargetName() const { return _targetName.c_str(); } + void setGameTargetName(const Common::String& targetName) { _targetName = targetName; } uint32 _surfaceGCCycleTime; bool _smartCache; // RO bool _subtitles; // RO @@ -275,7 +275,7 @@ private: bool _mouseRightDown; bool _mouseMidlleDown; - + BaseGameSettings *_settings; int32 _soundBufferSizeSec; @@ -295,7 +295,7 @@ private: uint32 _lastTime; uint32 _fpsTime; uint32 _framesRendered; - Common::String _gameId; + Common::String _targetName; void setEngineLogCallback(ENGINE_LOG_CALLBACK callback = nullptr, void *data = nullptr); ENGINE_LOG_CALLBACK _engineLogCallback; @@ -343,6 +343,8 @@ private: bool isDoubleClick(int32 buttonIndex); uint32 _usedMem; +// TODO: This should be expanded into a proper class eventually: + Common::String readRegistryString(const Common::String &key, const Common::String &initValue) const; protected: @@ -356,6 +358,6 @@ public: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_game_music.cpp b/engines/wintermute/base/base_game_music.cpp index ac23801e4c..c50969df76 100644 --- a/engines/wintermute/base/base_game_music.cpp +++ b/engines/wintermute/base/base_game_music.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -65,10 +65,10 @@ bool BaseGameMusic::playMusic(int channel, const char *filename, bool looping, u BaseEngine::LOG(0, "**Error** Attempting to use music channel %d (max num channels: %d)", channel, NUM_MUSIC_CHANNELS); return STATUS_FAILED; } - + delete _music[channel]; _music[channel] = nullptr; - + _music[channel] = new BaseSound(_gameRef); if (_music[channel] && DID_SUCCEED(_music[channel]->setSound(filename, Audio::Mixer::kMusicSoundType, true))) { if (_musicStartTime[channel]) { @@ -93,7 +93,7 @@ bool BaseGameMusic::stopMusic(int channel) { BaseEngine::LOG(0, "**Error** Attempting to use music channel %d (max num channels: %d)", channel, NUM_MUSIC_CHANNELS); return STATUS_FAILED; } - + if (_music[channel]) { _music[channel]->stop(); delete _music[channel]; @@ -111,7 +111,7 @@ bool BaseGameMusic::pauseMusic(int channel) { BaseEngine::LOG(0, "**Error** Attempting to use music channel %d (max num channels: %d)", channel, NUM_MUSIC_CHANNELS); return STATUS_FAILED; } - + if (_music[channel]) { return _music[channel]->pause(); } else { @@ -126,7 +126,7 @@ bool BaseGameMusic::resumeMusic(int channel) { BaseEngine::LOG(0, "**Error** Attempting to use music channel %d (max num channels: %d)", channel, NUM_MUSIC_CHANNELS); return STATUS_FAILED; } - + if (_music[channel]) { return _music[channel]->resume(); } else { @@ -141,7 +141,7 @@ bool BaseGameMusic::setMusicStartTime(int channel, uint32 time) { BaseEngine::LOG(0, "**Error** Attempting to use music channel %d (max num channels: %d)", channel, NUM_MUSIC_CHANNELS); return STATUS_FAILED; } - + _musicStartTime[channel] = time; if (_music[channel] && _music[channel]->isPlaying()) { return _music[channel]->setPositionTime(time); @@ -153,14 +153,14 @@ bool BaseGameMusic::setMusicStartTime(int channel, uint32 time) { ////////////////////////////////////////////////////////////////////////// bool BaseGameMusic::updateMusicCrossfade() { /* byte globMusicVol = _soundMgr->getVolumePercent(SOUND_MUSIC); */ - + if (!_musicCrossfadeRunning) { return STATUS_OK; } if (_gameRef->_state == GAME_FROZEN) { return STATUS_OK; } - + if (_musicCrossfadeChannel1 < 0 || _musicCrossfadeChannel1 >= NUM_MUSIC_CHANNELS || !_music[_musicCrossfadeChannel1]) { _musicCrossfadeRunning = false; return STATUS_OK; @@ -169,34 +169,34 @@ bool BaseGameMusic::updateMusicCrossfade() { _musicCrossfadeRunning = false; return STATUS_OK; } - + if (!_music[_musicCrossfadeChannel1]->isPlaying()) { _music[_musicCrossfadeChannel1]->play(); } if (!_music[_musicCrossfadeChannel2]->isPlaying()) { _music[_musicCrossfadeChannel2]->play(); } - + uint32 currentTime = _gameRef->getLiveTimer()->getTime() - _musicCrossfadeStartTime; - + if (currentTime >= _musicCrossfadeLength) { _musicCrossfadeRunning = false; //_music[_musicCrossfadeChannel2]->setVolume(GlobMusicVol); _music[_musicCrossfadeChannel2]->setVolumePercent(100); - + _music[_musicCrossfadeChannel1]->stop(); //_music[_musicCrossfadeChannel1]->setVolume(GlobMusicVol); _music[_musicCrossfadeChannel1]->setVolumePercent(100); - - + + if (_musicCrossfadeSwap) { // swap channels BaseSound *dummy = _music[_musicCrossfadeChannel1]; int dummyInt = _musicStartTime[_musicCrossfadeChannel1]; - + _music[_musicCrossfadeChannel1] = _music[_musicCrossfadeChannel2]; _musicStartTime[_musicCrossfadeChannel1] = _musicStartTime[_musicCrossfadeChannel2]; - + _music[_musicCrossfadeChannel2] = dummy; _musicStartTime[_musicCrossfadeChannel2] = dummyInt; } @@ -205,10 +205,10 @@ bool BaseGameMusic::updateMusicCrossfade() { //_music[_musicCrossfadeChannel2]->setVolume((float)CurrentTime / (float)_musicCrossfadeLength * GlobMusicVol); _music[_musicCrossfadeChannel1]->setVolumePercent((int)(100.0f - (float)currentTime / (float)_musicCrossfadeLength * 100.0f)); _music[_musicCrossfadeChannel2]->setVolumePercent((int)((float)currentTime / (float)_musicCrossfadeLength * 100.0f)); - + //_gameRef->QuickMessageForm("%d %d", _music[_musicCrossfadeChannel1]->GetVolume(), _music[_musicCrossfadeChannel2]->GetVolume()); } - + return STATUS_OK; } @@ -242,15 +242,15 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this stack->correctParams(4); channel = stack->pop()->getInt(); } - + const char *filename = stack->pop()->getString(); ScValue *valLooping = stack->pop(); bool looping = valLooping->isNULL() ? true : valLooping->getBool(); - + ScValue *valLoopStart = stack->pop(); uint32 loopStart = (uint32)(valLoopStart->isNULL() ? 0 : valLoopStart->getInt()); - - + + if (DID_FAIL(playMusic(channel, filename, looping, loopStart))) { stack->pushBool(false); } else { @@ -258,20 +258,20 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this } return STATUS_OK; } - + ////////////////////////////////////////////////////////////////////////// // StopMusic / StopMusicChannel ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "StopMusic") == 0 || strcmp(name, "StopMusicChannel") == 0) { int channel = 0; - + if (strcmp(name, "StopMusic") == 0) { stack->correctParams(0); } else { stack->correctParams(1); channel = stack->pop()->getInt(); } - + if (DID_FAIL(stopMusic(channel))) { stack->pushBool(false); } else { @@ -279,20 +279,20 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this } return STATUS_OK; } - + ////////////////////////////////////////////////////////////////////////// // PauseMusic / PauseMusicChannel ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "PauseMusic") == 0 || strcmp(name, "PauseMusicChannel") == 0) { int channel = 0; - + if (strcmp(name, "PauseMusic") == 0) { stack->correctParams(0); } else { stack->correctParams(1); channel = stack->pop()->getInt(); } - + if (DID_FAIL(pauseMusic(channel))) { stack->pushBool(false); } else { @@ -300,7 +300,7 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this } return STATUS_OK; } - + ////////////////////////////////////////////////////////////////////////// // ResumeMusic / ResumeMusicChannel ////////////////////////////////////////////////////////////////////////// @@ -312,7 +312,7 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this stack->correctParams(1); channel = stack->pop()->getInt(); } - + if (DID_FAIL(resumeMusic(channel))) { stack->pushBool(false); } else { @@ -320,7 +320,7 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this } return STATUS_OK; } - + ////////////////////////////////////////////////////////////////////////// // GetMusic / GetMusicChannel ////////////////////////////////////////////////////////////////////////// @@ -343,7 +343,7 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this } return STATUS_OK; } - + ////////////////////////////////////////////////////////////////////////// // SetMusicPosition / SetMusicChannelPosition ////////////////////////////////////////////////////////////////////////// @@ -355,18 +355,18 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this stack->correctParams(2); channel = stack->pop()->getInt(); } - + uint32 time = stack->pop()->getInt(); - + if (DID_FAIL(setMusicStartTime(channel, time))) { stack->pushBool(false); } else { stack->pushBool(true); } - + return STATUS_OK; } - + ////////////////////////////////////////////////////////////////////////// // GetMusicPosition / GetMusicChannelPosition ////////////////////////////////////////////////////////////////////////// @@ -378,7 +378,7 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this stack->correctParams(1); channel = stack->pop()->getInt(); } - + if (channel < 0 || channel >= NUM_MUSIC_CHANNELS || !_music[channel]) { stack->pushInt(0); } else { @@ -386,7 +386,7 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this } return STATUS_OK; } - + ////////////////////////////////////////////////////////////////////////// // IsMusicPlaying / IsMusicChannelPlaying ////////////////////////////////////////////////////////////////////////// @@ -398,7 +398,7 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this stack->correctParams(1); channel = stack->pop()->getInt(); } - + if (channel < 0 || channel >= NUM_MUSIC_CHANNELS || !_music[channel]) { stack->pushBool(false); } else { @@ -406,7 +406,7 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this } return STATUS_OK; } - + ////////////////////////////////////////////////////////////////////////// // SetMusicVolume / SetMusicChannelVolume ////////////////////////////////////////////////////////////////////////// @@ -418,7 +418,7 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this stack->correctParams(2); channel = stack->pop()->getInt(); } - + int volume = stack->pop()->getInt(); if (channel < 0 || channel >= NUM_MUSIC_CHANNELS || !_music[channel]) { stack->pushBool(false); @@ -431,7 +431,7 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this } return STATUS_OK; } - + ////////////////////////////////////////////////////////////////////////// // GetMusicVolume / GetMusicChannelVolume ////////////////////////////////////////////////////////////////////////// @@ -443,16 +443,16 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this stack->correctParams(1); channel = stack->pop()->getInt(); } - + if (channel < 0 || channel >= NUM_MUSIC_CHANNELS || !_music[channel]) { stack->pushInt(0); } else { stack->pushInt(_music[channel]->getVolumePercent()); } - + return STATUS_OK; } - + ////////////////////////////////////////////////////////////////////////// // MusicCrossfade ////////////////////////////////////////////////////////////////////////// @@ -462,34 +462,34 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this int channel2 = stack->pop()->getInt(0); uint32 fadeLength = (uint32)stack->pop()->getInt(0); bool swap = stack->pop()->getBool(true); - + if (_musicCrossfadeRunning) { script->runtimeError("Game.MusicCrossfade: Music crossfade is already in progress."); stack->pushBool(false); return STATUS_OK; } - + _musicCrossfadeStartTime = _gameRef->getLiveTimer()->getTime(); _musicCrossfadeChannel1 = channel1; _musicCrossfadeChannel2 = channel2; _musicCrossfadeLength = fadeLength; _musicCrossfadeSwap = swap; - + _musicCrossfadeRunning = true; - + stack->pushBool(true); return STATUS_OK; - } + } ////////////////////////////////////////////////////////////////////////// // GetSoundLength ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetSoundLength") == 0) { stack->correctParams(1); - + int length = 0; const char *filename = stack->pop()->getString(); - + BaseSound *sound = new BaseSound(_gameRef); if (sound && DID_SUCCEED(sound->setSound(filename, Audio::Mixer::kMusicSoundType, true))) { length = sound->getLength(); @@ -503,4 +503,4 @@ bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *this } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_game_music.h b/engines/wintermute/base/base_game_music.h index 0ac904b8c1..72c7a171a6 100644 --- a/engines/wintermute/base/base_game_music.h +++ b/engines/wintermute/base/base_game_music.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -53,7 +53,7 @@ public: bool stopMusic(int channel); bool playMusic(int channel, const char *filename, bool looping = true, uint32 loopStart = 0); bool updateMusicCrossfade(); - + bool persistChannels(BasePersistenceManager *persistMgr); bool persistCrossfadeSettings(BasePersistenceManager *persistMgr); private: @@ -68,6 +68,6 @@ private: int32 _musicCrossfadeChannel2; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_game_settings.cpp b/engines/wintermute/base/base_game_settings.cpp index 55fbe39fd2..1de8b31ca7 100644 --- a/engines/wintermute/base/base_game_settings.cpp +++ b/engines/wintermute/base/base_game_settings.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -47,7 +47,7 @@ BaseGameSettings::BaseGameSettings(BaseGame *gameRef) { _allowAccessTab = true; _allowAboutTab = true; _allowDesktopRes = false; - + _compressedSavegames = true; _richSavedGames = false; _savedGameExt = "dsv"; @@ -101,21 +101,21 @@ bool BaseGameSettings::loadSettings(const char *filename) { TOKEN_TABLE(SAVED_GAME_EXT) TOKEN_TABLE(GUID) TOKEN_TABLE_END - - + + byte *origBuffer = BaseFileManager::getEngineInstance()->readWholeFile(filename); if (origBuffer == nullptr) { BaseEngine::LOG(0, "BaseGame::LoadSettings failed for file '%s'", filename); return STATUS_FAILED; } - + bool ret = STATUS_OK; - + byte *buffer = origBuffer; byte *params; int cmd; BaseParser parser; - + if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_SETTINGS) { BaseEngine::LOG(0, "'SETTINGS' keyword expected in game settings file."); return STATUS_FAILED; @@ -130,61 +130,61 @@ bool BaseGameSettings::loadSettings(const char *filename) { strcpy(_gameFile, (char *)params); } break; - + case TOKEN_STRING_TABLE: if (DID_FAIL(_stringTable->loadFile((char *)params))) { cmd = PARSERR_GENERIC; } break; - + case TOKEN_RESOLUTION: parser.scanStr((char *)params, "%d,%d", &_resWidth, &_resHeight); break; - + case TOKEN_REQUIRE_3D_ACCELERATION: parser.scanStr((char *)params, "%b", &_requireAcceleration); break; - + case TOKEN_REQUIRE_SOUND: parser.scanStr((char *)params, "%b", &_requireSound); break; - + case TOKEN_HWTL_MODE: parser.scanStr((char *)params, "%d", &_TLMode); break; - + case TOKEN_ALLOW_WINDOWED_MODE: parser.scanStr((char *)params, "%b", &_allowWindowed); break; - + case TOKEN_ALLOW_DESKTOP_RES: parser.scanStr((char *)params, "%b", &_allowDesktopRes); break; - + case TOKEN_ALLOW_ADVANCED: parser.scanStr((char *)params, "%b", &_allowAdvanced); break; - + case TOKEN_ALLOW_ACCESSIBILITY_TAB: parser.scanStr((char *)params, "%b", &_allowAccessTab); break; - + case TOKEN_ALLOW_ABOUT_TAB: parser.scanStr((char *)params, "%b", &_allowAboutTab); break; - + case TOKEN_REGISTRY_PATH: //BaseEngine::instance().getRegistry()->setBasePath((char *)params); break; - + case TOKEN_RICH_SAVED_GAMES: parser.scanStr((char *)params, "%b", &_richSavedGames); break; - + case TOKEN_SAVED_GAME_EXT: _savedGameExt = (char *)params; break; - + case TOKEN_GUID: break; } @@ -197,12 +197,12 @@ bool BaseGameSettings::loadSettings(const char *filename) { BaseEngine::LOG(0, "Error loading game settings '%s'", filename); ret = STATUS_FAILED; } - + _allowWindowed = true; // TODO: These two settings should probably be cleaned out altogether. _compressedSavegames = true; - + delete[] origBuffer; - + return ret; } @@ -219,4 +219,4 @@ char *BaseGameSettings::getKeyFromStringTable(const char *str) const { return _stringTable->getKey(str); } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_game_settings.h b/engines/wintermute/base/base_game_settings.h index 1dfb0b50cc..38a2fd1042 100644 --- a/engines/wintermute/base/base_game_settings.h +++ b/engines/wintermute/base/base_game_settings.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -66,6 +66,6 @@ private: bool _richSavedGames; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_keyboard_state.cpp b/engines/wintermute/base/base_keyboard_state.cpp index 072a1bb71b..aeb56ad282 100644 --- a/engines/wintermute/base/base_keyboard_state.cpp +++ b/engines/wintermute/base/base_keyboard_state.cpp @@ -310,4 +310,4 @@ Common::KeyCode BaseKeyboardState::vKeyToKeyCode(uint32 vkey) { } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_keyboard_state.h b/engines/wintermute/base/base_keyboard_state.h index b62ece02b7..14a57ee7b8 100644 --- a/engines/wintermute/base/base_keyboard_state.h +++ b/engines/wintermute/base/base_keyboard_state.h @@ -61,7 +61,7 @@ private: bool _currentPrintable; uint32 _currentKeyData; uint32 _currentCharCode; - + bool _currentShift; bool _currentAlt; bool _currentControl; @@ -71,6 +71,6 @@ private: Common::KeyCode vKeyToKeyCode(uint32 vkey); //TODO, reimplement using ScummVM-backend }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_named_object.cpp b/engines/wintermute/base/base_named_object.cpp index f99ec2f5db..3d1df5ab84 100644 --- a/engines/wintermute/base/base_named_object.cpp +++ b/engines/wintermute/base/base_named_object.cpp @@ -68,4 +68,4 @@ void BaseNamedObject::setName(const char *name) { } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_named_object.h b/engines/wintermute/base/base_named_object.h index d25fec4a82..ee4a3bba6a 100644 --- a/engines/wintermute/base/base_named_object.h +++ b/engines/wintermute/base/base_named_object.h @@ -46,6 +46,6 @@ public: void setName(const char *name); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_object.cpp b/engines/wintermute/base/base_object.cpp index ad181b922e..ea754f8f23 100644 --- a/engines/wintermute/base/base_object.cpp +++ b/engines/wintermute/base/base_object.cpp @@ -968,9 +968,9 @@ bool BaseObject::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_movable)); persistMgr->transfer(TMEMBER(_posX)); persistMgr->transfer(TMEMBER(_posY)); - persistMgr->transfer(TMEMBER(_relativeScale)); + persistMgr->transferFloat(TMEMBER(_relativeScale)); persistMgr->transfer(TMEMBER(_rotatable)); - persistMgr->transfer(TMEMBER(_scale)); + persistMgr->transferFloat(TMEMBER(_scale)); persistMgr->transferPtr(TMEMBER_PTR(_sFX)); persistMgr->transfer(TMEMBER(_sFXStart)); persistMgr->transfer(TMEMBER(_sFXVolume)); @@ -982,21 +982,21 @@ bool BaseObject::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_soundEvent)); persistMgr->transfer(TMEMBER(_zoomable)); - persistMgr->transfer(TMEMBER(_scaleX)); - persistMgr->transfer(TMEMBER(_scaleY)); + persistMgr->transferFloat(TMEMBER(_scaleX)); + persistMgr->transferFloat(TMEMBER(_scaleY)); - persistMgr->transfer(TMEMBER(_rotate)); + persistMgr->transferFloat(TMEMBER(_rotate)); persistMgr->transfer(TMEMBER(_rotateValid)); - persistMgr->transfer(TMEMBER(_relativeRotate)); + persistMgr->transferFloat(TMEMBER(_relativeRotate)); persistMgr->transfer(TMEMBER(_saveState)); persistMgr->transfer(TMEMBER(_nonIntMouseEvents)); persistMgr->transfer(TMEMBER_INT(_sFXType)); - persistMgr->transfer(TMEMBER(_sFXParam1)); - persistMgr->transfer(TMEMBER(_sFXParam2)); - persistMgr->transfer(TMEMBER(_sFXParam3)); - persistMgr->transfer(TMEMBER(_sFXParam4)); + persistMgr->transferFloat(TMEMBER(_sFXParam1)); + persistMgr->transferFloat(TMEMBER(_sFXParam2)); + persistMgr->transferFloat(TMEMBER(_sFXParam3)); + persistMgr->transferFloat(TMEMBER(_sFXParam4)); persistMgr->transfer(TMEMBER_INT(_blendMode)); @@ -1242,4 +1242,4 @@ bool BaseObject::afterMove() { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_object.h b/engines/wintermute/base/base_object.h index 7afe9cf94c..42041c5e3c 100644 --- a/engines/wintermute/base/base_object.h +++ b/engines/wintermute/base/base_object.h @@ -142,6 +142,6 @@ public: virtual const char *scToString() override; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_parser.cpp b/engines/wintermute/base/base_parser.cpp index a7e3bd5efb..0b677b6cb2 100644 --- a/engines/wintermute/base/base_parser.cpp +++ b/engines/wintermute/base/base_parser.cpp @@ -464,4 +464,4 @@ int32 BaseParser::scanStr(const char *in, const char *format, ...) { return num; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_parser.h b/engines/wintermute/base/base_parser.h index 4953ac3c0b..4bf48cc016 100644 --- a/engines/wintermute/base/base_parser.h +++ b/engines/wintermute/base/base_parser.h @@ -83,6 +83,6 @@ private: char *_whiteSpace; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_persistence_manager.cpp b/engines/wintermute/base/base_persistence_manager.cpp index 5dbacb157b..2e2726f361 100644 --- a/engines/wintermute/base/base_persistence_manager.cpp +++ b/engines/wintermute/base/base_persistence_manager.cpp @@ -94,7 +94,7 @@ BasePersistenceManager::BasePersistenceManager(const char *savePrefix, bool dele if (savePrefix) { _savePrefix = savePrefix; } else if (_gameRef) { - _savePrefix = _gameRef->getGameId(); + _savePrefix = _gameRef->getGameTargetName(); } else { _savePrefix = "wmesav"; } @@ -282,7 +282,7 @@ bool BasePersistenceManager::initSave(const char *desc) { } else { _saveStream->writeUint32LE(0); } - + thumbnailOK = true; } } @@ -637,7 +637,7 @@ bool BasePersistenceManager::transfer(const char *name, uint32 *val) { ////////////////////////////////////////////////////////////////////////// // float -bool BasePersistenceManager::transfer(const char *name, float *val) { +bool BasePersistenceManager::transferFloat(const char *name, float *val) { if (_saving) { putFloat(*val); if (_saveStream->err()) { @@ -887,4 +887,4 @@ bool BasePersistenceManager::checkVersion(byte verMajor, byte verMinor, byte ver return true; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_persistence_manager.h b/engines/wintermute/base/base_persistence_manager.h index 7b578085ba..c09b3345b7 100644 --- a/engines/wintermute/base/base_persistence_manager.h +++ b/engines/wintermute/base/base_persistence_manager.h @@ -76,7 +76,7 @@ public: bool transferPtr(const char *name, void *val); bool transfer(const char *name, int32 *val); bool transfer(const char *name, uint32 *val); - bool transfer(const char *name, float *val); + bool transferFloat(const char *name, float *val); bool transfer(const char *name, double *val); bool transfer(const char *name, bool *val); bool transfer(const char *name, byte *val); @@ -115,6 +115,6 @@ private: BaseGame *_gameRef; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_point.cpp b/engines/wintermute/base/base_point.cpp index fbd8960894..fe6ca941f3 100644 --- a/engines/wintermute/base/base_point.cpp +++ b/engines/wintermute/base/base_point.cpp @@ -60,4 +60,4 @@ bool BasePoint::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_point.h b/engines/wintermute/base/base_point.h index 26568d5d0b..cf8a5be336 100644 --- a/engines/wintermute/base/base_point.h +++ b/engines/wintermute/base/base_point.h @@ -45,6 +45,6 @@ public: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_quick_msg.cpp b/engines/wintermute/base/base_quick_msg.cpp index 9f19dfd74a..ac0c107d3b 100644 --- a/engines/wintermute/base/base_quick_msg.cpp +++ b/engines/wintermute/base/base_quick_msg.cpp @@ -52,4 +52,4 @@ uint32 BaseQuickMsg::getStartTime() const { return _startTime; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_quick_msg.h b/engines/wintermute/base/base_quick_msg.h index 377f7733fd..b706424c18 100644 --- a/engines/wintermute/base/base_quick_msg.h +++ b/engines/wintermute/base/base_quick_msg.h @@ -44,6 +44,6 @@ private: uint32 _startTime; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_region.cpp b/engines/wintermute/base/base_region.cpp index 2dabe6ae44..36036a1f18 100644 --- a/engines/wintermute/base/base_region.cpp +++ b/engines/wintermute/base/base_region.cpp @@ -432,7 +432,7 @@ bool BaseRegion::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_active)); persistMgr->transfer(TMEMBER(_editorSelectedPoint)); - persistMgr->transfer(TMEMBER(_lastMimicScale)); + persistMgr->transferFloat(TMEMBER(_lastMimicScale)); persistMgr->transfer(TMEMBER(_lastMimicX)); persistMgr->transfer(TMEMBER(_lastMimicY)); _points.persist(persistMgr); @@ -532,4 +532,4 @@ bool BaseRegion::mimic(BaseRegion *region, float scale, int x, int y) { return createRegion() ? STATUS_OK : STATUS_FAILED; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_region.h b/engines/wintermute/base/base_region.h index 67ca158897..93ad6a6fbe 100644 --- a/engines/wintermute/base/base_region.h +++ b/engines/wintermute/base/base_region.h @@ -65,6 +65,6 @@ private: int32 _lastMimicY; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_script_holder.cpp b/engines/wintermute/base/base_script_holder.cpp index 036bac1dd8..25b8775a98 100644 --- a/engines/wintermute/base/base_script_holder.cpp +++ b/engines/wintermute/base/base_script_holder.cpp @@ -500,4 +500,4 @@ bool BaseScriptHolder::sendEvent(const char *eventName) { return DID_SUCCEED(applyEvent(eventName)); } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_script_holder.h b/engines/wintermute/base/base_script_holder.h index 38a3f935d3..c34b0378a1 100644 --- a/engines/wintermute/base/base_script_holder.h +++ b/engines/wintermute/base/base_script_holder.h @@ -71,6 +71,6 @@ public: virtual bool sendEvent(const char *eventName); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_scriptable.cpp b/engines/wintermute/base/base_scriptable.cpp index 5753b0482b..be1e18c2c4 100644 --- a/engines/wintermute/base/base_scriptable.cpp +++ b/engines/wintermute/base/base_scriptable.cpp @@ -188,4 +188,4 @@ ScScript *BaseScriptable::invokeMethodThread(const char *methodName) { return nullptr; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_scriptable.h b/engines/wintermute/base/base_scriptable.h index f23d7faa5b..08fd32081a 100644 --- a/engines/wintermute/base/base_scriptable.h +++ b/engines/wintermute/base/base_scriptable.h @@ -78,6 +78,6 @@ BaseScriptable *makeSXObject(BaseGame *inGame, ScStack *stack); BaseScriptable *makeSXStore(BaseGame *inGame); BaseScriptable *makeSXString(BaseGame *inGame, ScStack *stack); -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_sprite.cpp b/engines/wintermute/base/base_sprite.cpp index c920da9ee9..ab78c5ac7c 100644 --- a/engines/wintermute/base/base_sprite.cpp +++ b/engines/wintermute/base/base_sprite.cpp @@ -817,4 +817,4 @@ bool BaseSprite::killAllSounds() { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_sprite.h b/engines/wintermute/base/base_sprite.h index 05cb9fc936..1387796895 100644 --- a/engines/wintermute/base/base_sprite.h +++ b/engines/wintermute/base/base_sprite.h @@ -32,6 +32,7 @@ #include "engines/wintermute/coll_templ.h" #include "engines/wintermute/base/base_script_holder.h" +#include "engines/wintermute/graphics/transform_tools.h" namespace Wintermute { class BaseFrame; @@ -44,17 +45,17 @@ public: void setDefaults(); DECLARE_PERSISTENT(BaseSprite, BaseScriptHolder) - bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = 100, float scaleY = 100); + bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = kDefaultZoomX, float scaleY = kDefaultZoomY); int32 _moveY; int32 _moveX; - bool display(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = 100, float zoomY = 100, uint32 alpha = 0xFFFFFFFF, float rotate = 0.0f, TSpriteBlendMode blendMode = BLEND_NORMAL); - bool getCurrentFrame(float zoomX = 100, float zoomY = 100); + bool display(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY, uint32 alpha = kDefaultRgbaMod, float rotate = kDefaultAngle, TSpriteBlendMode blendMode = BLEND_NORMAL); + bool getCurrentFrame(float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY); void reset(); bool isChanged(); bool isFinished(); bool loadBuffer(byte *buffer, bool compete = true, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL); bool loadFile(const Common::String &filename, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL); - bool draw(int x, int y, BaseObject *Register = nullptr, float zoomX = 100, float zoomY = 100, uint32 alpha = 0xFFFFFFFF); + bool draw(int x, int y, BaseObject *Register = nullptr, float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY, uint32 alpha = kDefaultRgbaMod); bool _looping; int32 _currentFrame; bool addFrame(const char *filename, uint32 delay = 0, int hotspotX = 0, int hotspotY = 0, Rect32 *rect = nullptr); @@ -88,6 +89,6 @@ private: bool killAllSounds(); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_string_table.cpp b/engines/wintermute/base/base_string_table.cpp index 8207c32244..3d9cc4f8b3 100644 --- a/engines/wintermute/base/base_string_table.cpp +++ b/engines/wintermute/base/base_string_table.cpp @@ -253,4 +253,4 @@ bool BaseStringTable::loadFile(const char *filename, bool clearOld) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_string_table.h b/engines/wintermute/base/base_string_table.h index 128807bd1a..f8808f5b27 100644 --- a/engines/wintermute/base/base_string_table.h +++ b/engines/wintermute/base/base_string_table.h @@ -50,6 +50,6 @@ private: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_sub_frame.cpp b/engines/wintermute/base/base_sub_frame.cpp index d93cf667f1..8a8f63240b 100644 --- a/engines/wintermute/base/base_sub_frame.cpp +++ b/engines/wintermute/base/base_sub_frame.cpp @@ -38,6 +38,8 @@ #include "engines/wintermute/base/gfx/base_renderer.h" #include "engines/wintermute/base/scriptables/script_value.h" #include "engines/wintermute/base/scriptables/script_stack.h" +#include "engines/wintermute/graphics/transform_tools.h" +#include "engines/wintermute/graphics/transform_struct.h" namespace Wintermute { @@ -46,8 +48,9 @@ IMPLEMENT_PERSISTENT(BaseSubFrame, false) ////////////////////////////////////////////////////////////////////////// BaseSubFrame::BaseSubFrame(BaseGame *inGame) : BaseScriptable(inGame, true) { _surface = nullptr; - _hotspotX = _hotspotY = 0; - _alpha = 0xFFFFFFFF; + _hotspotX = kDefaultHotspotX; + _hotspotY = kDefaultHotspotY; + _alpha = kDefaultRgbaMod; _transparent = 0xFFFF00FF; _wantsDefaultRect = false; @@ -233,12 +236,18 @@ const char* BaseSubFrame::getSurfaceFilename() { ////////////////////////////////////////////////////////////////////// bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, float zoomY, bool precise, uint32 alpha, float rotate, TSpriteBlendMode blendMode) { + + rotate = fmod(rotate, 360.0f); + if (rotate < 0) { + rotate += 360.0f; + } + if (!_surface) { return STATUS_OK; } if (registerOwner != nullptr && !_decoration) { - if (zoomX == 100 && zoomY == 100) { + if (zoomX == kDefaultZoomX && zoomY == kDefaultZoomY) { BaseEngine::getRenderer()->addRectToList(new BaseActiveRect(_gameRef, registerOwner, this, x - _hotspotX + getRect().left, y - _hotspotY + getRect().top, getRect().right - getRect().left, getRect().bottom - getRect().top, zoomX, zoomY, precise)); } else { BaseEngine::getRenderer()->addRectToList(new BaseActiveRect(_gameRef, registerOwner, this, (int)(x - (_hotspotX + getRect().left) * (zoomX / 100)), (int)(y - (_hotspotY + getRect().top) * (zoomY / 100)), (int)((getRect().right - getRect().left) * (zoomX / 100)), (int)((getRect().bottom - getRect().top) * (zoomY / 100)), zoomX, zoomY, precise)); @@ -251,17 +260,24 @@ bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, fl bool res; //if (Alpha==0xFFFFFFFF) Alpha = _alpha; // TODO: better (combine owner's and self alpha) - if (_alpha != 0xFFFFFFFF) { + if (_alpha != kDefaultRgbaMod) { alpha = _alpha; } - if (rotate != 0.0f) { - res = _surface->displayTransform((int)(x - _hotspotX * (zoomX / 100)), (int)(y - _hotspotY * (zoomY / 100)), _hotspotX, _hotspotY, getRect(), zoomX, zoomY, alpha, rotate, blendMode, _mirrorX, _mirrorY); + if (rotate != kDefaultAngle) { + Point32 boxOffset, rotatedHotspot, hotspotOffset, newOrigin; + Point32 origin(x, y); + Rect32 oldRect = getRect(); + Point32 newHotspot; + TransformStruct transform = TransformStruct(zoomX, zoomY, rotate, _hotspotX, _hotspotY, blendMode, alpha, _mirrorX, _mirrorY, 0, 0); + Rect32 newRect = TransformTools::newRect (oldRect, transform, &newHotspot); + newOrigin = origin - newHotspot; + res = _surface->displayTransform(newOrigin.x, newOrigin.y, oldRect, newRect, transform); } else { - if (zoomX == 100 && zoomY == 100) { + if (zoomX == kDefaultZoomX && zoomY == kDefaultZoomY) { res = _surface->displayTrans(x - _hotspotX, y - _hotspotY, getRect(), alpha, blendMode, _mirrorX, _mirrorY); } else { - res = _surface->displayTransZoom((int)(x - _hotspotX * (zoomX / 100)), (int)(y - _hotspotY * (zoomY / 100)), getRect(), zoomX, zoomY, alpha, blendMode, _mirrorX, _mirrorY); + res = _surface->displayTransZoom((int)(x - _hotspotX * (zoomX / kDefaultZoomX)), (int)(y - _hotspotY * (zoomY / kDefaultZoomY)), getRect(), zoomX, zoomY, alpha, blendMode, _mirrorX, _mirrorY); } } @@ -657,4 +673,4 @@ bool BaseSubFrame::setSurfaceSimple() { } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_sub_frame.h b/engines/wintermute/base/base_sub_frame.h index 37ba34b748..ba3d5b955a 100644 --- a/engines/wintermute/base/base_sub_frame.h +++ b/engines/wintermute/base/base_sub_frame.h @@ -88,6 +88,6 @@ public: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_surface_storage.cpp b/engines/wintermute/base/base_surface_storage.cpp index 8dbd6a6d2a..f1d068674b 100644 --- a/engines/wintermute/base/base_surface_storage.cpp +++ b/engines/wintermute/base/base_surface_storage.cpp @@ -203,4 +203,4 @@ bool BaseSurfaceStorage::surfaceSortCB(const BaseSurface *s1, const BaseSurface } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_surface_storage.h b/engines/wintermute/base/base_surface_storage.h index 61738e69a2..c0049d676c 100644 --- a/engines/wintermute/base/base_surface_storage.h +++ b/engines/wintermute/base/base_surface_storage.h @@ -52,6 +52,6 @@ public: Common::Array<BaseSurface *> _surfaces; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_transition_manager.cpp b/engines/wintermute/base/base_transition_manager.cpp index 1c869e6a2b..eee5f1aae7 100644 --- a/engines/wintermute/base/base_transition_manager.cpp +++ b/engines/wintermute/base/base_transition_manager.cpp @@ -135,4 +135,4 @@ bool BaseTransitionMgr::update() { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_transition_manager.h b/engines/wintermute/base/base_transition_manager.h index edb3045a58..82edb9ff88 100644 --- a/engines/wintermute/base/base_transition_manager.h +++ b/engines/wintermute/base/base_transition_manager.h @@ -49,6 +49,6 @@ public: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/base_viewport.cpp b/engines/wintermute/base/base_viewport.cpp index f79e5c9f13..09ac80e9de 100644 --- a/engines/wintermute/base/base_viewport.cpp +++ b/engines/wintermute/base/base_viewport.cpp @@ -97,4 +97,4 @@ int BaseViewport::getHeight() const { return _rect.bottom - _rect.top; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/base_viewport.h b/engines/wintermute/base/base_viewport.h index 584e5a78f9..0225c02c7c 100644 --- a/engines/wintermute/base/base_viewport.h +++ b/engines/wintermute/base/base_viewport.h @@ -52,6 +52,6 @@ private: Rect32 _rect; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/file/base_disk_file.cpp b/engines/wintermute/base/file/base_disk_file.cpp index 3c1ecc7a73..7391d819fc 100644 --- a/engines/wintermute/base/file/base_disk_file.cpp +++ b/engines/wintermute/base/file/base_disk_file.cpp @@ -66,12 +66,6 @@ static Common::FSNode getNodeForRelativePath(const Common::String &filename) { const Common::FSNode gameDataDir(ConfMan.get("path")); Common::FSNode curNode = gameDataDir; - Common::String fixedPath = ""; - while (!path.empty()) { - fixedPath += path.nextToken() + "/"; - } - fixedPath.deleteLastChar(); - // Parse all path-elements while (!path.empty()) { // Get the next path-component by slicing on '\\' @@ -198,4 +192,4 @@ Common::SeekableReadStream *openDiskFile(const Common::String &filename) { return nullptr; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/file/base_disk_file.h b/engines/wintermute/base/file/base_disk_file.h index c9f93b80d9..81cc22b86d 100644 --- a/engines/wintermute/base/file/base_disk_file.h +++ b/engines/wintermute/base/file/base_disk_file.h @@ -36,6 +36,6 @@ namespace Wintermute { Common::SeekableReadStream *openDiskFile(const Common::String &filename); bool diskFileExists(const Common::String &filename); -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/file/base_file.cpp b/engines/wintermute/base/file/base_file.cpp index f52a13211e..42eea69824 100644 --- a/engines/wintermute/base/file/base_file.cpp +++ b/engines/wintermute/base/file/base_file.cpp @@ -65,4 +65,4 @@ Common::SeekableReadStream *BaseFile::getMemStream() { } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/file/base_file.h b/engines/wintermute/base/file/base_file.h index 8eda6d51d9..9acda7ffce 100644 --- a/engines/wintermute/base/file/base_file.h +++ b/engines/wintermute/base/file/base_file.h @@ -62,6 +62,6 @@ public: virtual Common::SeekableReadStream *getMemStream(); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/file/base_file_entry.cpp b/engines/wintermute/base/file/base_file_entry.cpp index 1968da6f47..846f56b55c 100644 --- a/engines/wintermute/base/file/base_file_entry.cpp +++ b/engines/wintermute/base/file/base_file_entry.cpp @@ -70,4 +70,4 @@ BaseFileEntry::~BaseFileEntry() { _package = nullptr; // ref only } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/file/base_file_entry.h b/engines/wintermute/base/file/base_file_entry.h index 6e4823d994..9d738c8c11 100644 --- a/engines/wintermute/base/file/base_file_entry.h +++ b/engines/wintermute/base/file/base_file_entry.h @@ -55,6 +55,6 @@ public: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/file/base_package.cpp b/engines/wintermute/base/file/base_package.cpp index 73f767c3ef..512279b72c 100644 --- a/engines/wintermute/base/file/base_package.cpp +++ b/engines/wintermute/base/file/base_package.cpp @@ -273,4 +273,4 @@ Common::SeekableReadStream *PackageSet::createReadStreamForMember(const Common:: return nullptr; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/file/base_package.h b/engines/wintermute/base/file/base_package.h index bcf088aaea..18156c4f65 100644 --- a/engines/wintermute/base/file/base_package.h +++ b/engines/wintermute/base/file/base_package.h @@ -85,6 +85,6 @@ private: Common::HashMap<Common::String, Common::ArchiveMemberPtr>::iterator _filesIter; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/file/base_save_thumb_file.cpp b/engines/wintermute/base/file/base_save_thumb_file.cpp index 2c4ddf4875..bb172ca66a 100644 --- a/engines/wintermute/base/file/base_save_thumb_file.cpp +++ b/engines/wintermute/base/file/base_save_thumb_file.cpp @@ -150,4 +150,4 @@ bool BaseSaveThumbFile::seek(uint32 pos, int whence) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/file/base_save_thumb_file.h b/engines/wintermute/base/file/base_save_thumb_file.h index 3b217525fd..faf1af9255 100644 --- a/engines/wintermute/base/file/base_save_thumb_file.h +++ b/engines/wintermute/base/file/base_save_thumb_file.h @@ -47,6 +47,6 @@ private: byte *_data; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/file/dcpackage.h b/engines/wintermute/base/file/dcpackage.h index 2234139408..a2ec5d28d5 100644 --- a/engines/wintermute/base/file/dcpackage.h +++ b/engines/wintermute/base/file/dcpackage.h @@ -75,6 +75,6 @@ v2: uint32 TimeDate1 */ -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/font/base_font.cpp b/engines/wintermute/base/font/base_font.cpp index 596f9fb5c6..26bc0e7985 100644 --- a/engines/wintermute/base/font/base_font.cpp +++ b/engines/wintermute/base/font/base_font.cpp @@ -137,4 +137,4 @@ bool BaseFont::isTrueType(BaseGame *gameRef, const Common::String &filename) { return ret; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/font/base_font.h b/engines/wintermute/base/font/base_font.h index 50587fa7eb..d75d3f4fb5 100644 --- a/engines/wintermute/base/font/base_font.h +++ b/engines/wintermute/base/font/base_font.h @@ -56,6 +56,6 @@ private: static bool isTrueType(BaseGame *game, const Common::String &filename); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/font/base_font_bitmap.cpp b/engines/wintermute/base/font/base_font_bitmap.cpp index 03bd471636..890a9a2f83 100644 --- a/engines/wintermute/base/font/base_font_bitmap.cpp +++ b/engines/wintermute/base/font/base_font_bitmap.cpp @@ -587,4 +587,4 @@ int BaseFontBitmap::getLetterHeight() { return _tileHeight; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/font/base_font_bitmap.h b/engines/wintermute/base/font/base_font_bitmap.h index 0bdac64026..c810777446 100644 --- a/engines/wintermute/base/font/base_font_bitmap.h +++ b/engines/wintermute/base/font/base_font_bitmap.h @@ -66,6 +66,6 @@ private: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/font/base_font_storage.cpp b/engines/wintermute/base/font/base_font_storage.cpp index 3286742478..8abd368b70 100644 --- a/engines/wintermute/base/font/base_font_storage.cpp +++ b/engines/wintermute/base/font/base_font_storage.cpp @@ -138,4 +138,4 @@ bool BaseFontStorage::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/font/base_font_storage.h b/engines/wintermute/base/font/base_font_storage.h index 60874167e7..f4ac490324 100644 --- a/engines/wintermute/base/font/base_font_storage.h +++ b/engines/wintermute/base/font/base_font_storage.h @@ -50,6 +50,6 @@ public: bool initLoop(); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/font/base_font_truetype.cpp b/engines/wintermute/base/font/base_font_truetype.cpp index 2fcdebc117..3059a69047 100644 --- a/engines/wintermute/base/font/base_font_truetype.cpp +++ b/engines/wintermute/base/font/base_font_truetype.cpp @@ -644,4 +644,4 @@ void BaseFontTT::measureText(const WideString &text, int maxWidth, int maxHeight }*/ } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/font/base_font_truetype.h b/engines/wintermute/base/font/base_font_truetype.h index f93505921f..fdbae30684 100644 --- a/engines/wintermute/base/font/base_font_truetype.h +++ b/engines/wintermute/base/font/base_font_truetype.h @@ -148,6 +148,6 @@ public: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/gfx/base_image.cpp b/engines/wintermute/base/gfx/base_image.cpp index 75de95128f..d0dbae352e 100644 --- a/engines/wintermute/base/gfx/base_image.cpp +++ b/engines/wintermute/base/gfx/base_image.cpp @@ -228,4 +228,4 @@ bool BaseImage::copyFrom(BaseImage *origImage, int newWidth, int newHeight) { return true; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/gfx/base_image.h b/engines/wintermute/base/gfx/base_image.h index 017305e5d0..4b04fd1252 100644 --- a/engines/wintermute/base/gfx/base_image.h +++ b/engines/wintermute/base/gfx/base_image.h @@ -67,6 +67,6 @@ private: BaseFileManager *_fileManager; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/gfx/base_renderer.cpp b/engines/wintermute/base/gfx/base_renderer.cpp index c20881e425..1f171209d7 100644 --- a/engines/wintermute/base/gfx/base_renderer.cpp +++ b/engines/wintermute/base/gfx/base_renderer.cpp @@ -113,15 +113,21 @@ void BaseRenderer::setIndicatorVal(int value) { } void BaseRenderer::setLoadingScreen(const char *filename, int x, int y) { - // TODO: Handle NULL - _loadImageName = filename; + if (filename == nullptr) { + _saveImageName = ""; + } else { + _loadImageName = filename; + } _loadImageX = x; _loadImageY = y; } void BaseRenderer::setSaveImage(const char *filename, int x, int y) { - // TODO: Handle NULL - _saveImageName = filename; + if (filename == nullptr) { + _saveImageName = ""; + } else { + _saveImageName = filename; + } _saveImageX = x; _saveImageY = y; } @@ -395,4 +401,4 @@ bool BaseRenderer::displayIndicator() { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/gfx/base_renderer.h b/engines/wintermute/base/gfx/base_renderer.h index bfef29a5ed..31dc2a022d 100644 --- a/engines/wintermute/base/gfx/base_renderer.h +++ b/engines/wintermute/base/gfx/base_renderer.h @@ -228,6 +228,6 @@ private: BaseRenderer *makeOSystemRenderer(BaseGame *inGame); // Implemented in BRenderSDL.cpp -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/gfx/base_surface.cpp b/engines/wintermute/base/gfx/base_surface.cpp index 2002463ea4..19639c0c33 100644 --- a/engines/wintermute/base/gfx/base_surface.cpp +++ b/engines/wintermute/base/gfx/base_surface.cpp @@ -75,8 +75,8 @@ bool BaseSurface::displayHalfTrans(int x, int y, Rect32 rect) { } ////////////////////////////////////////////////////////////////////////// -bool BaseSurface::displayTransform(int x, int y, int hotX, int hotY, Rect32 rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { - return displayTransZoom(x, y, rect, zoomX, zoomY, alpha, blendMode, mirrorX, mirrorY); +bool BaseSurface::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) { + return displayTransform(x, y, rect, newRect, transform); } ////////////////////////////////////////////////////////////////////////// @@ -146,4 +146,4 @@ void BaseSurface::setSize(int width, int height) { _height = height; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/gfx/base_surface.h b/engines/wintermute/base/gfx/base_surface.h index b83efa0bb8..8a0603734e 100644 --- a/engines/wintermute/base/gfx/base_surface.h +++ b/engines/wintermute/base/gfx/base_surface.h @@ -32,6 +32,7 @@ #include "engines/wintermute/base/base.h" #include "engines/wintermute/math/rect32.h" #include "graphics/surface.h" +#include "engines/wintermute/graphics/transform_struct.h" namespace Wintermute { @@ -49,12 +50,12 @@ public: virtual bool displayHalfTrans(int x, int y, Rect32 rect); virtual bool isTransparentAt(int x, int y); - virtual bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; + virtual bool displayTransZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; virtual bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; virtual bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) = 0; virtual bool display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; - virtual bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; - virtual bool displayTransform(int x, int y, int hotX, int hotY, Rect32 rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; + virtual bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) = 0; + virtual bool displayZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha = 0xFFFFFFFF, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; virtual bool repeatLastDisplayOp(int offsetX, int offsetY, int numTimesX, int numTimesY) = 0; virtual bool restore(); virtual bool create(const Common::String &filename, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime = -1, bool keepLoaded = false) = 0; @@ -95,6 +96,6 @@ protected: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp index e1424cea87..668105457f 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp @@ -60,8 +60,7 @@ BaseRenderOSystem::BaseRenderOSystem(BaseGame *inGame) : BaseRenderer(inGame) { _borderLeft = _borderRight = _borderTop = _borderBottom = 0; _ratioX = _ratioY = 1.0f; - setAlphaMod(255); - setColorMod(255, 255, 255); + _colorMod = kDefaultRgbaMod; _dirtyRect = nullptr; _disableDirtyRects = false; _tempDisableDirtyRects = 0; @@ -150,18 +149,6 @@ bool BaseRenderOSystem::initRenderer(int width, int height, bool windowed) { return STATUS_OK; } -void BaseRenderOSystem::setAlphaMod(byte alpha) { - byte r = RGBCOLGetR(_colorMod); - byte g = RGBCOLGetB(_colorMod); - byte b = RGBCOLGetB(_colorMod); - _colorMod = BS_ARGB(alpha, r, g, b); -} - -void BaseRenderOSystem::setColorMod(byte r, byte g, byte b) { - byte alpha = RGBCOLGetA(_colorMod); - _colorMod = BS_ARGB(alpha, r, g, b); -} - bool BaseRenderOSystem::indicatorFlip() { g_system->copyRectToScreen((byte *)_renderSurface->getBasePtr(_indicatorX, _indicatorY), _renderSurface->pitch, _indicatorX, _indicatorY, _indicatorWidthDrawn, _indicatorHeight); g_system->updateScreen(); @@ -200,9 +187,9 @@ bool BaseRenderOSystem::flip() { } if (_needsFlip || _disableDirtyRects || _tempDisableDirtyRects) { if (_disableDirtyRects || _tempDisableDirtyRects) { - g_system->copyRectToScreen((byte *)_renderSurface->pixels, _renderSurface->pitch, 0, 0, _renderSurface->w, _renderSurface->h); + g_system->copyRectToScreen((byte *)_renderSurface->getPixels(), _renderSurface->pitch, 0, 0, _renderSurface->w, _renderSurface->h); } - // g_system->copyRectToScreen((byte *)_renderSurface->pixels, _renderSurface->pitch, _dirtyRect->left, _dirtyRect->top, _dirtyRect->width(), _dirtyRect->height()); + // g_system->copyRectToScreen((byte *)_renderSurface->getPixels(), _renderSurface->pitch, _dirtyRect->left, _dirtyRect->top, _dirtyRect->width(), _dirtyRect->height()); delete _dirtyRect; _dirtyRect = nullptr; g_system->updateScreen(); @@ -256,7 +243,6 @@ void BaseRenderOSystem::fade(uint16 alpha) { return fadeToColor(0, 0, 0, dwAlpha); } - ////////////////////////////////////////////////////////////////////////// void BaseRenderOSystem::fadeToColor(byte r, byte g, byte b, byte a, Common::Rect *rect) { Common::Rect fillRect; @@ -279,14 +265,14 @@ void BaseRenderOSystem::fadeToColor(byte r, byte g, byte b, byte a, Common::Rect //TODO: This is only here until I'm sure about the final pixelformat uint32 col = _renderSurface->format.ARGBToColor(a, r, g, b); - setAlphaMod(255); - setColorMod(255, 255, 255); Graphics::Surface surf; surf.create((uint16)fillRect.width(), (uint16)fillRect.height(), _renderSurface->format); Common::Rect sizeRect(fillRect); sizeRect.translate(-fillRect.top, -fillRect.left); surf.fillRect(fillRect, col); - drawSurface(nullptr, &surf, &sizeRect, &fillRect, false, false); + TransformStruct temp = TransformStruct(); + temp._alphaDisable = false; + drawSurface(nullptr, &surf, &sizeRect, &fillRect, temp); surf.free(); //SDL_SetRenderDrawColor(_renderer, r, g, b, a); @@ -298,16 +284,18 @@ Graphics::PixelFormat BaseRenderOSystem::getPixelFormat() const { return _renderSurface->format; } -void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY, bool disableAlpha) { +void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform) { + if (_tempDisableDirtyRects || _disableDirtyRects) { - RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, mirrorX, mirrorY, disableAlpha); - ticket->_colorMod = _colorMod; + RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform); + ticket->_transform._rgbaMod = _colorMod; ticket->_wantsDraw = true; _renderQueue.push_back(ticket); _previousTicket = ticket; drawFromSurface(ticket); return; } + // Start searching from the beginning for the first and second items (since it's empty the first time around // then keep incrementing the start-position, to avoid comparing against already used tickets. if (_drawNum == 0 || _drawNum == 1) { @@ -320,12 +308,11 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S } if (owner) { // Fade-tickets are owner-less - RenderTicket compare(owner, nullptr, srcRect, dstRect, mirrorX, mirrorY, disableAlpha); + RenderTicket compare(owner, nullptr, srcRect, dstRect, transform); compare._batchNum = _batchNum; if (_spriteBatch) { _batchNum++; } - compare._colorMod = _colorMod; RenderQueueIterator it; // Avoid calling end() and operator* every time, when potentially going through // LOTS of tickets. @@ -334,7 +321,7 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S for (it = _lastAddedTicket; it != endIterator; ++it) { compareTicket = *it; if (*(compareTicket) == compare && compareTicket->_isValid) { - compareTicket->_colorMod = _colorMod; + compareTicket->_transform._rgbaMod = transform._rgbaMod; if (_disableDirtyRects) { drawFromSurface(compareTicket); } else { @@ -349,8 +336,7 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S } } } - RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, mirrorX, mirrorY, disableAlpha); - ticket->_colorMod = _colorMod; + RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform); if (!_disableDirtyRects) { drawFromTicket(ticket); _previousTicket = ticket; @@ -385,12 +371,14 @@ void BaseRenderOSystem::repeatLastDraw(int offsetX, int offsetY, int numTimesX, int initLeft = dstRect.left; int initRight = dstRect.right; + TransformStruct temp = TransformStruct(kDefaultZoomX, kDefaultZoomY, kDefaultAngle, kDefaultHotspotX, kDefaultHotspotY, BLEND_NORMAL, kDefaultRgbaMod, false, false, kDefaultOffsetX, kDefaultOffsetY); + for (int i = 0; i < numTimesY; i++) { if (i == 0) { dstRect.translate(offsetX, 0); } for (int j = (i == 0 ? 1 : 0); j < numTimesX; j++) { - drawSurface(origTicket->_owner, origTicket->getSurface(), &srcRect, &dstRect, false, false); + drawSurface(origTicket->_owner, origTicket->getSurface(), &srcRect, &dstRect, temp); dstRect.translate(offsetX, 0); } dstRect.left = initLeft; @@ -535,7 +523,7 @@ void BaseRenderOSystem::drawTickets() { // convert from screen-coords to surface-coords. dstClip.translate(-offsetX, -offsetY); - _colorMod = ticket->_colorMod; + _colorMod = ticket->_transform._rgbaMod; drawFromSurface(ticket, &pos, &dstClip); _needsFlip = true; } @@ -546,7 +534,7 @@ void BaseRenderOSystem::drawTickets() { // Revert the colorMod-state. _colorMod = oldColorMod; - + it = _renderQueue.begin(); // Clean out the old tickets decrement = 0; @@ -625,8 +613,8 @@ bool BaseRenderOSystem::setViewport(int left, int top, int right, int bottom) { // TODO: Hopefully this is the same logic that ScummVM uses. rect.left = (int16)(left + _borderLeft); rect.top = (int16)(top + _borderTop); - rect.right = (int16)((right - left) * _ratioX); - rect.bottom = (int16)((bottom - top) * _ratioY); + rect.setWidth((int16)((right - left) * _ratioX)); + rect.setHeight((int16)((bottom - top) * _ratioY)); _renderRect = rect; return STATUS_OK; @@ -643,15 +631,13 @@ Rect32 BaseRenderOSystem::getViewPort() { ////////////////////////////////////////////////////////////////////////// void BaseRenderOSystem::modTargetRect(Common::Rect *rect) { - // FIXME: This is wrong in quite a few ways right now, and ends up - // breaking the notebook in Dirty Split, so we disable the correction - // for now, this will need fixing when a game with odd aspect-ratios - // show up. return; - rect->left = (int16)MathUtil::round(rect->left * _ratioX + _borderLeft - _renderRect.left); - rect->top = (int16)MathUtil::round(rect->top * _ratioY + _borderTop - _renderRect.top); - rect->setWidth((int16)MathUtil::roundUp(rect->width() * _ratioX)); - rect->setHeight((int16)MathUtil::roundUp(rect->height() * _ratioY)); + int newWidth = (int16)MathUtil::roundUp(rect->width() * _ratioX); + int newHeight = (int16)MathUtil::roundUp(rect->height() * _ratioY); + rect->left = (int16)MathUtil::round(rect->left * _ratioX + _borderLeft); + rect->top = (int16)MathUtil::round(rect->top * _ratioY + _borderTop); + rect->setWidth(newWidth); + rect->setHeight(newHeight); } ////////////////////////////////////////////////////////////////////////// @@ -694,7 +680,7 @@ void BaseRenderOSystem::endSaveLoad() { _drawNum = 1; _renderSurface->fillRect(Common::Rect(0, 0, _renderSurface->h, _renderSurface->w), _renderSurface->format.ARGBToColor(255, 0, 0, 0)); - g_system->copyRectToScreen((byte *)_renderSurface->pixels, _renderSurface->pitch, 0, 0, _renderSurface->w, _renderSurface->h); + g_system->copyRectToScreen((byte *)_renderSurface->getPixels(), _renderSurface->pitch, 0, 0, _renderSurface->w, _renderSurface->h); g_system->updateScreen(); } @@ -710,4 +696,4 @@ bool BaseRenderOSystem::endSpriteBatch() { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.h b/engines/wintermute/base/gfx/osystem/base_render_osystem.h index 3cb0fa82a3..928a52d4fc 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.h +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.h @@ -33,10 +33,30 @@ #include "common/rect.h" #include "graphics/surface.h" #include "common/list.h" +#include "engines/wintermute/graphics/transform_struct.h" namespace Wintermute { class BaseSurfaceOSystem; class RenderTicket; +/** + * A 2D-renderer implementation for WME. + * This renderer makes use of a "ticket"-system, where all draw-calls + * are stored as tickets until flip() is called, and compared against the tickets + * from last frame, to determine which calls were the same as last round + * (i.e. in the exact same order, with the exact same arguments), and thus + * figure out which parts of the screen need to be redrawn. + * + * Important concepts to handle here, is the ordered number of any ticket + * which is called the "drawNum", every frame this starts from scratch, and + * then the incoming tickets created from the draw-calls are checked to see whether + * they came before, on, or after the drawNum they had last frame. Everything else + * being equal, this information is then used to check whether the draw order changed, + * which will then create a need for redrawing, as we draw with an alpha-channel here. + * + * There is also a draw path that draws without tickets, for debugging purposes, + * as well as to accomodate situations with large enough amounts of draw calls, + * that there will be too much overhead involved with comparing the generated tickets. + */ class BaseRenderOSystem : public BaseRenderer { public: BaseRenderOSystem(BaseGame *inGame); @@ -56,10 +76,13 @@ public: BaseImage *takeScreenshot() override; - void setAlphaMod(byte alpha); - void setColorMod(byte r, byte g, byte b); void invalidateTicket(RenderTicket *renderTicket); void invalidateTicketsFromSurface(BaseSurfaceOSystem *surf); + /** + * Insert a ticket into the queue, adding a dirty rect if it's + * new, or out-of-order from last draw from the ticket. + * param renderTicket the ticket to be added. + */ void drawFromTicket(RenderTicket *renderTicket); bool setViewport(int left, int top, int right, int bottom) override; @@ -80,11 +103,18 @@ public: virtual bool startSpriteBatch() override; virtual bool endSpriteBatch() override; void endSaveLoad(); - void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY, bool disableAlpha = false) ; + void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform); void repeatLastDraw(int offsetX, int offsetY, int numTimesX, int numTimesY); BaseSurface *createSurface() override; private: - void addDirtyRect(const Common::Rect &rect) ; + /** + * Mark a specified rect of the screen as dirty. + * @param rect the region to be marked as dirty + */ + void addDirtyRect(const Common::Rect &rect); + /** + * Traverse the tickets that are dirty, and draw them + */ void drawTickets(); // Non-dirty-rects: void drawFromSurface(RenderTicket *ticket); @@ -97,7 +127,7 @@ private: RenderTicket *_previousTicket; bool _needsFlip; - uint32 _drawNum; + uint32 _drawNum; ///< The global number of the current draw-operation. Common::Rect _renderRect; Graphics::Surface *_renderSurface; Graphics::Surface *_blankSurface; @@ -119,6 +149,6 @@ private: bool _skipThisFrame; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp index 0572ef2f6e..d4c5905c4b 100644 --- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp @@ -52,6 +52,7 @@ BaseSurfaceOSystem::BaseSurfaceOSystem(BaseGame *inGame) : BaseSurface(inGame) { _lockPixels = nullptr; _lockPitch = 0; _loaded = false; + _rotation = 0; } ////////////////////////////////////////////////////////////////////////// @@ -163,7 +164,7 @@ bool BaseSurfaceOSystem::finishLoad() { needsColorKey = true; } } - + if (needsColorKey) { TransparentSurface trans(*_surface); trans.applyColorKey(_ckRed, _ckGreen, _ckBlue, replaceAlpha); @@ -233,7 +234,7 @@ uint32 BaseSurfaceOSystem::getPixelAt(Graphics::Surface *surface, int x, int y) warning("BaseSurfaceOSystem::GetPixel - Not ported yet"); int bpp = surface->format.bytesPerPixel; /* Here p is the address to the pixel we want to retrieve */ - uint8 *p = (uint8 *)surface->pixels + y * surface->pitch + x * bpp; + uint8 *p = (uint8 *)surface->getBasePtr(x, y); switch (bpp) { case 1: @@ -319,39 +320,56 @@ bool BaseSurfaceOSystem::endPixelOp() { ////////////////////////////////////////////////////////////////////////// bool BaseSurfaceOSystem::display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { - return drawSprite(x, y, &rect, 100, 100, 0xFFFFFFFF, true, blendMode, mirrorX, mirrorY); + _rotation = 0; + return drawSprite(x, y, &rect, nullptr, TransformStruct(kDefaultZoomX, kDefaultZoomY, mirrorX, mirrorY)); } ////////////////////////////////////////////////////////////////////////// bool BaseSurfaceOSystem::displayTrans(int x, int y, Rect32 rect, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { - return drawSprite(x, y, &rect, 100, 100, alpha, false, blendMode, mirrorX, mirrorY); + _rotation = 0; + return drawSprite(x, y, &rect, nullptr, TransformStruct(kDefaultZoomX, kDefaultZoomY, blendMode, alpha, mirrorX, mirrorY)); } ////////////////////////////////////////////////////////////////////////// bool BaseSurfaceOSystem::displayTransOffset(int x, int y, Rect32 rect, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) { - return drawSprite(x, y, &rect, 100, 100, alpha, false, blendMode, mirrorX, mirrorY, offsetX, offsetY); + _rotation = 0; + return drawSprite(x, y, &rect, nullptr, TransformStruct(kDefaultZoomX, kDefaultZoomY, kDefaultAngle, kDefaultHotspotX, kDefaultHotspotY, blendMode, alpha, mirrorX, mirrorY, offsetX, offsetY)); } ////////////////////////////////////////////////////////////////////////// -bool BaseSurfaceOSystem::displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { - return drawSprite(x, y, &rect, zoomX, zoomY, alpha, false, blendMode, mirrorX, mirrorY); +bool BaseSurfaceOSystem::displayTransZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { + _rotation = 0; + return drawSprite(x, y, &rect, nullptr, TransformStruct(zoomX, zoomY, blendMode, alpha, mirrorX, mirrorY)); } ////////////////////////////////////////////////////////////////////////// -bool BaseSurfaceOSystem::displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, bool transparent, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { - return drawSprite(x, y, &rect, zoomX, zoomY, alpha, !transparent, blendMode, mirrorX, mirrorY); +bool BaseSurfaceOSystem::displayZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha, bool transparent, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { + _rotation = 0; + TransformStruct transform; + if (transparent) { + transform = TransformStruct(zoomX, zoomY, kDefaultAngle, kDefaultHotspotX, kDefaultHotspotY, blendMode, alpha, mirrorX, mirrorY); + } else { + transform = TransformStruct(zoomX, zoomY, mirrorX, mirrorY); + } + return drawSprite(x, y, &rect, nullptr, transform); } ////////////////////////////////////////////////////////////////////////// -bool BaseSurfaceOSystem::displayTransform(int x, int y, int hotX, int hotY, Rect32 rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { - return drawSprite(x, y, &rect, zoomX, zoomY, alpha, false, blendMode, mirrorX, mirrorY); +bool BaseSurfaceOSystem::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) { + _rotation = (uint32)transform._angle; + if (transform._angle < 0.0f) { + warning("Negative rotation: %d %d", transform._angle, _rotation); + _rotation = (uint32)(360.0f + transform._angle); + warning("Negative post rotation: %d %d", transform._angle, _rotation); + } + return drawSprite(x, y, &rect, &newRect, transform); } ////////////////////////////////////////////////////////////////////////// -bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, float zoomX, float zoomY, uint32 alpha, bool alphaDisable, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) { +bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, TransformStruct transform) { BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_gameRef->_renderer); if (!_loaded) { @@ -359,17 +377,9 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, float zoomX, flo } if (renderer->_forceAlphaColor != 0) { - alpha = renderer->_forceAlphaColor; + transform._rgbaMod = renderer->_forceAlphaColor; } - byte r = RGBCOLGetR(alpha); - byte g = RGBCOLGetG(alpha); - byte b = RGBCOLGetB(alpha); - byte a = RGBCOLGetA(alpha); - - renderer->setAlphaMod(a); - renderer->setColorMod(r, g, b); - #if 0 // These are kept for reference if BlendMode is reimplemented at some point. if (alphaDisable) { SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_NONE); @@ -386,8 +396,8 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, float zoomX, flo srcRect.setHeight(rect->bottom - rect->top); Common::Rect position; - position.left = x + offsetX; - position.top = y + offsetY; + position.left = x + transform._offset.x; + position.top = y + transform._offset.y; // Crop off-by-ones: if (position.left == -1) { @@ -396,31 +406,34 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, float zoomX, flo if (position.top == -1) { position.top = 0; // TODO: Something is wrong } - - position.setWidth((int16)((float)srcRect.width() * zoomX / 100.f)); - position.setHeight((int16)((float)srcRect.height() * zoomX / 100.f)); - + if (newRect) { + position.top = y; + position.left = x; + position.right = x + newRect->width(); + position.bottom = y + newRect->height(); + position.setWidth(newRect->width()); + position.setHeight(newRect->height()); + } else { + position.setWidth((int16)((float)srcRect.width() * transform._zoom.x / kDefaultZoomX)); + position.setHeight((int16)((float)srcRect.height() * transform._zoom.y / kDefaultZoomY)); + } renderer->modTargetRect(&position); - /* position.left += offsetX; - position.top += offsetY;*/ - // TODO: This actually requires us to have the SAME source-offsets every time, // But no checking is in place for that yet. // TODO: Optimize by not doing alpha-blits if we lack or disable alpha - bool hasAlpha; - if (_hasAlpha && !alphaDisable) { + + bool hasAlpha = false; + + if (_hasAlpha && !transform._alphaDisable) { hasAlpha = true; - } else { - hasAlpha = false; - } - if (alphaDisable) { + } + + if (transform._alphaDisable) { warning("BaseSurfaceOSystem::drawSprite - AlphaDisable ignored"); } - - renderer->drawSurface(this, _surface, &srcRect, &position, mirrorX, mirrorY, !hasAlpha); - + renderer->drawSurface(this, _surface, &srcRect, &position, transform); return STATUS_OK; } @@ -441,4 +454,4 @@ bool BaseSurfaceOSystem::putSurface(const Graphics::Surface &surface, bool hasAl return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h index 9091ec65b1..da86833517 100644 --- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h @@ -51,12 +51,12 @@ public: bool endPixelOp() override; - bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; - bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; - bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) override; + bool displayTransZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha = kDefaultRgbaMod, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; + bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = kDefaultRgbaMod, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; + bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = kDefaultRgbaMod, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) override; bool display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; - bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; - bool displayTransform(int x, int y, int hotX, int hotY, Rect32 Rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; + bool displayZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha = kDefaultRgbaMod, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; + bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) override; bool repeatLastDisplayOp(int offsetX, int offsetY, int numTimesX, int numTimesY) override; virtual bool putSurface(const Graphics::Surface &surface, bool hasAlpha = false) override; /* static unsigned DLL_CALLCONV ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle); @@ -85,16 +85,17 @@ private: Graphics::Surface *_surface; bool _loaded; bool finishLoad(); - bool drawSprite(int x, int y, Rect32 *rect, float zoomX, float zoomY, uint32 alpha, bool alphaDisable, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX = 0, int offsetY = 0); + bool drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, TransformStruct transformStruct); void genAlphaMask(Graphics::Surface *surface); uint32 getPixelAt(Graphics::Surface *surface, int x, int y); + uint32 _rotation; bool _hasAlpha; void *_lockPixels; int _lockPitch; byte *_alphaMask; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.cpp b/engines/wintermute/base/gfx/osystem/render_ticket.cpp index 36c5d7b740..98739e0778 100644 --- a/engines/wintermute/base/gfx/osystem/render_ticket.cpp +++ b/engines/wintermute/base/gfx/osystem/render_ticket.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -26,22 +26,22 @@ * Copyright (c) 2011 Jan Nedoma */ -#include "engines/wintermute/graphics/transparent_surface.h" + #include "engines/wintermute/base/gfx/osystem/render_ticket.h" +#include "engines/wintermute/graphics/transform_tools.h" +#include "common/textconsole.h" namespace Wintermute { -RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY, bool disableAlpha) : _owner(owner), -_srcRect(*srcRect), _dstRect(*dstRect), _drawNum(0), _isValid(true), _wantsDraw(true), _hasAlpha(!disableAlpha) { - _colorMod = 0; +RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct transform) : + _owner(owner), + _srcRect(*srcRect), + _dstRect(*dstRect), + _drawNum(0), + _isValid(true), + _wantsDraw(true), + _transform(transform) { _batchNum = 0; - _mirror = TransparentSurface::FLIP_NONE; - if (mirrorX) { - _mirror |= TransparentSurface::FLIP_V; - } - if (mirrorY) { - _mirror |= TransparentSurface::FLIP_H; - } if (surf) { _surface = new Graphics::Surface(); _surface->create((uint16)srcRect->width(), (uint16)srcRect->height(), surf->format); @@ -51,7 +51,13 @@ _srcRect(*srcRect), _dstRect(*dstRect), _drawNum(0), _isValid(true), _wantsDraw( memcpy(_surface->getBasePtr(0, i), surf->getBasePtr(srcRect->left, srcRect->top + i), srcRect->width() * _surface->format.bytesPerPixel); } // Then scale it if necessary - if (dstRect->width() != srcRect->width() || dstRect->height() != srcRect->height()) { + if (_transform._angle != kDefaultAngle) { + TransparentSurface src(*_surface, false); + Graphics::Surface *temp = src.rotoscale(transform); + _surface->free(); + delete _surface; + _surface = temp; + } else if (dstRect->width() != srcRect->width() || dstRect->height() != srcRect->height()) { TransparentSurface src(*_surface, false); Graphics::Surface *temp = src.scale(dstRect->width(), dstRect->height()); _surface->free(); @@ -60,6 +66,14 @@ _srcRect(*srcRect), _dstRect(*dstRect), _drawNum(0), _isValid(true), _wantsDraw( } } else { _surface = nullptr; + + if (transform._angle != kDefaultAngle) { // Make sure comparison-tickets get the correct width + Rect32 newDstRect; + Point32 newHotspot; + newDstRect = TransformTools::newRect(_srcRect, transform, &newHotspot); + _dstRect.setWidth(newDstRect.right - newDstRect.left); + _dstRect.setHeight(newDstRect.bottom - newDstRect.top); + } } } @@ -70,32 +84,31 @@ RenderTicket::~RenderTicket() { } } -bool RenderTicket::operator==(RenderTicket &t) { +bool RenderTicket::operator==(const RenderTicket &t) const { if ((t._owner != _owner) || (t._batchNum != _batchNum) || - (t._hasAlpha != _hasAlpha) || - (t._mirror != _mirror) || - (t._colorMod != _colorMod) || + (t._transform != _transform) || (t._dstRect != _dstRect) || - (t._srcRect != _srcRect)) { + (t._srcRect != _srcRect) + ) { return false; } return true; } // Replacement for SDL2's SDL_RenderCopy -void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) { +void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) const { TransparentSurface src(*getSurface(), false); Common::Rect clipRect; clipRect.setWidth(getSurface()->w); clipRect.setHeight(getSurface()->h); - src._enableAlphaBlit = _hasAlpha; - src.blit(*_targetSurface, _dstRect.left, _dstRect.top, _mirror, &clipRect, _colorMod, clipRect.width(), clipRect.height()); + src._enableAlphaBlit = !_transform._alphaDisable; + src.blit(*_targetSurface, _dstRect.left, _dstRect.top, _transform._flip, &clipRect, _transform._rgbaMod, clipRect.width(), clipRect.height()); } -void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) { +void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const { TransparentSurface src(*getSurface(), false); bool doDelete = false; if (!clipRect) { @@ -105,11 +118,11 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect clipRect->setHeight(getSurface()->h); } - src._enableAlphaBlit = _hasAlpha; - src.blit(*_targetSurface, dstRect->left, dstRect->top, _mirror, clipRect, _colorMod, clipRect->width(), clipRect->height()); + src._enableAlphaBlit = !_transform._alphaDisable; + src.blit(*_targetSurface, dstRect->left, dstRect->top, _transform._flip, clipRect, _transform._rgbaMod, clipRect->width(), clipRect->height()); if (doDelete) { delete clipRect; } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.h b/engines/wintermute/base/gfx/osystem/render_ticket.h index 968b42b5e1..875102d01c 100644 --- a/engines/wintermute/base/gfx/osystem/render_ticket.h +++ b/engines/wintermute/base/gfx/osystem/render_ticket.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -29,22 +29,36 @@ #ifndef WINTERMUTE_RENDER_TICKET_H #define WINTERMUTE_RENDER_TICKET_H +#include "engines/wintermute/graphics/transparent_surface.h" #include "graphics/surface.h" #include "common/rect.h" namespace Wintermute { class BaseSurfaceOSystem; +/** + * A single RenderTicket. + * A render ticket is a collection of the data and draw specifications made + * for a single draw-call in the OSystem-backend for WME. The ticket additionally + * holds the order in which this call was made, so that it can be detected if + * the same call is done in the following frame. Thus allowing us to potentially + * skip drawing the same region again, unless anything has changed. Since a surface + * can have a potentially large amount of draw-calls made to it, at varying rotation, + * zoom, and crop-levels we also need to hold a copy of the necessary data. + * (Video-surfaces may even change their data). The promise that is made when a ticket + * is created is that what the state was of the surface at THAT point, is what will end + * up on screen at flip() time. + */ class RenderTicket { public: - RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, bool mirrorX = false, bool mirrorY = false, bool disableAlpha = false); - RenderTicket() : _isValid(true), _wantsDraw(false), _drawNum(0) {} + RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, TransformStruct transform); + RenderTicket() : _isValid(true), _wantsDraw(false), _drawNum(0), _transform(TransformStruct()) {} ~RenderTicket(); - const Graphics::Surface *getSurface() { return _surface; } + const Graphics::Surface *getSurface() const { return _surface; } // Non-dirty-rects: - void drawToSurface(Graphics::Surface *_targetSurface); + void drawToSurface(Graphics::Surface *_targetSurface) const; // Dirty-rects: - void drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect); + void drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const; Common::Rect _dstRect; uint32 _batchNum; @@ -52,18 +66,17 @@ public: bool _isValid; bool _wantsDraw; uint32 _drawNum; - uint32 _colorMod; + TransformStruct _transform; + BaseSurfaceOSystem *_owner; - bool operator==(RenderTicket &a); - const Common::Rect *getSrcRect() { return &_srcRect; } + bool operator==(const RenderTicket &a) const; + const Common::Rect *getSrcRect() const { return &_srcRect; } private: Graphics::Surface *_surface; Common::Rect _srcRect; - bool _hasAlpha; - uint32 _mirror; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/particles/part_emitter.cpp b/engines/wintermute/base/particles/part_emitter.cpp index c86e1ce369..aaffa0965a 100644 --- a/engines/wintermute/base/particles/part_emitter.cpp +++ b/engines/wintermute/base/particles/part_emitter.cpp @@ -1163,12 +1163,12 @@ bool PartEmitter::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_angle1)); persistMgr->transfer(TMEMBER(_angle2)); - persistMgr->transfer(TMEMBER(_velocity1)); - persistMgr->transfer(TMEMBER(_velocity2)); + persistMgr->transferFloat(TMEMBER(_velocity1)); + persistMgr->transferFloat(TMEMBER(_velocity2)); persistMgr->transfer(TMEMBER(_velocityZBased)); - persistMgr->transfer(TMEMBER(_scale1)); - persistMgr->transfer(TMEMBER(_scale2)); + persistMgr->transferFloat(TMEMBER(_scale1)); + persistMgr->transferFloat(TMEMBER(_scale2)); persistMgr->transfer(TMEMBER(_scaleZBased)); persistMgr->transfer(TMEMBER(_maxParticles)); @@ -1196,14 +1196,14 @@ bool PartEmitter::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_alpha2)); persistMgr->transfer(TMEMBER(_alphaTimeBased)); - persistMgr->transfer(TMEMBER(_angVelocity1)); - persistMgr->transfer(TMEMBER(_angVelocity2)); + persistMgr->transferFloat(TMEMBER(_angVelocity1)); + persistMgr->transferFloat(TMEMBER(_angVelocity2)); - persistMgr->transfer(TMEMBER(_rotation1)); - persistMgr->transfer(TMEMBER(_rotation2)); + persistMgr->transferFloat(TMEMBER(_rotation1)); + persistMgr->transferFloat(TMEMBER(_rotation2)); - persistMgr->transfer(TMEMBER(_growthRate1)); - persistMgr->transfer(TMEMBER(_growthRate2)); + persistMgr->transferFloat(TMEMBER(_growthRate1)); + persistMgr->transferFloat(TMEMBER(_growthRate2)); persistMgr->transfer(TMEMBER(_exponentialGrowth)); persistMgr->transfer(TMEMBER(_useRegion)); @@ -1252,4 +1252,4 @@ bool PartEmitter::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/particles/part_emitter.h b/engines/wintermute/base/particles/part_emitter.h index a0d701f338..94b4dc8126 100644 --- a/engines/wintermute/base/particles/part_emitter.h +++ b/engines/wintermute/base/particles/part_emitter.h @@ -135,6 +135,6 @@ private: BaseArray<char *> _sprites; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/particles/part_force.cpp b/engines/wintermute/base/particles/part_force.cpp index df84162504..122cdf1afe 100644 --- a/engines/wintermute/base/particles/part_force.cpp +++ b/engines/wintermute/base/particles/part_force.cpp @@ -62,4 +62,4 @@ bool PartForce::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/particles/part_force.h b/engines/wintermute/base/particles/part_force.h index 27f4cb7d90..cdb1ce40f9 100644 --- a/engines/wintermute/base/particles/part_force.h +++ b/engines/wintermute/base/particles/part_force.h @@ -52,6 +52,6 @@ public: bool persist(BasePersistenceManager *PersistMgr); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/particles/part_particle.cpp b/engines/wintermute/base/particles/part_particle.cpp index f1aba114de..86cacacb5c 100644 --- a/engines/wintermute/base/particles/part_particle.cpp +++ b/engines/wintermute/base/particles/part_particle.cpp @@ -234,9 +234,9 @@ bool PartParticle::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_alpha2)); persistMgr->transfer(TMEMBER(_border)); persistMgr->transfer(TMEMBER(_pos)); - persistMgr->transfer(TMEMBER(_posZ)); + persistMgr->transferFloat(TMEMBER(_posZ)); persistMgr->transfer(TMEMBER(_velocity)); - persistMgr->transfer(TMEMBER(_scale)); + persistMgr->transferFloat(TMEMBER(_scale)); persistMgr->transfer(TMEMBER(_creationTime)); persistMgr->transfer(TMEMBER(_lifeTime)); persistMgr->transfer(TMEMBER(_isDead)); @@ -244,9 +244,9 @@ bool PartParticle::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_fadeStart)); persistMgr->transfer(TMEMBER(_fadeTime)); persistMgr->transfer(TMEMBER(_currentAlpha)); - persistMgr->transfer(TMEMBER(_angVelocity)); - persistMgr->transfer(TMEMBER(_rotation)); - persistMgr->transfer(TMEMBER(_growthRate)); + persistMgr->transferFloat(TMEMBER(_angVelocity)); + persistMgr->transferFloat(TMEMBER(_rotation)); + persistMgr->transferFloat(TMEMBER(_growthRate)); persistMgr->transfer(TMEMBER(_exponentialGrowth)); persistMgr->transfer(TMEMBER(_fadeStartAlpha)); @@ -266,4 +266,4 @@ bool PartParticle::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/particles/part_particle.h b/engines/wintermute/base/particles/part_particle.h index 8cca6b4057..281d87cf72 100644 --- a/engines/wintermute/base/particles/part_particle.h +++ b/engines/wintermute/base/particles/part_particle.h @@ -85,6 +85,6 @@ private: int32 _fadeStartAlpha; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/save_thumb_helper.cpp b/engines/wintermute/base/save_thumb_helper.cpp index bab29c5cf8..77514849a6 100644 --- a/engines/wintermute/base/save_thumb_helper.cpp +++ b/engines/wintermute/base/save_thumb_helper.cpp @@ -56,23 +56,23 @@ BaseImage *SaveThumbHelper::storeThumb(bool doFlip, int width, int height) { // works normally for direct3d _gameRef->displayContent(false); _gameRef->_renderer->flip(); - + _gameRef->displayContent(false); _gameRef->_renderer->flip(); } - + BaseImage *screenshot = _gameRef->_renderer->takeScreenshot(); if (!screenshot) { return nullptr; } - + // normal thumbnail if (_gameRef->getSaveThumbWidth() > 0 && _gameRef->getSaveThumbHeight() > 0) { thumbnail = new BaseImage(); thumbnail->copyFrom(screenshot, width, height); } - - + + delete screenshot; screenshot = nullptr; } @@ -99,7 +99,7 @@ bool SaveThumbHelper::storeThumbnail(bool doFlip) { bool SaveThumbHelper::storeScummVMThumbNail(bool doFlip) { delete _scummVMThumb; _scummVMThumb = nullptr; - + _scummVMThumb = storeThumb(doFlip, kThumbnailWidth, kThumbnailHeight2); if (!_scummVMThumb) { return STATUS_FAILED; @@ -107,4 +107,4 @@ bool SaveThumbHelper::storeScummVMThumbNail(bool doFlip) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/save_thumb_helper.h b/engines/wintermute/base/save_thumb_helper.h index d3bc5f5523..44792e3d75 100644 --- a/engines/wintermute/base/save_thumb_helper.h +++ b/engines/wintermute/base/save_thumb_helper.h @@ -47,6 +47,6 @@ private: BaseGame *_gameRef; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/saveload.cpp b/engines/wintermute/base/saveload.cpp index 1b7dfd42ed..8d37909bb4 100644 --- a/engines/wintermute/base/saveload.cpp +++ b/engines/wintermute/base/saveload.cpp @@ -201,4 +201,4 @@ bool SaveLoad::emptySaveSlot(int slot) { } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/saveload.h b/engines/wintermute/base/saveload.h index 722f7a89b6..15d4d86b26 100644 --- a/engines/wintermute/base/saveload.h +++ b/engines/wintermute/base/saveload.h @@ -52,6 +52,6 @@ private: static void afterLoadScript(void *script, void *data); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/scriptables/dcscript.h b/engines/wintermute/base/scriptables/dcscript.h index 4aae897dc2..d6bb3cd176 100644 --- a/engines/wintermute/base/scriptables/dcscript.h +++ b/engines/wintermute/base/scriptables/dcscript.h @@ -136,6 +136,6 @@ typedef enum { ELEMENT_STRING = 0 } TElementType; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/scriptables/script.cpp b/engines/wintermute/base/scriptables/script.cpp index 1b945c2e1c..5aeff78c50 100644 --- a/engines/wintermute/base/scriptables/script.cpp +++ b/engines/wintermute/base/scriptables/script.cpp @@ -461,6 +461,7 @@ void ScScript::cleanup() { _parentScript = nullptr; // ref only delete _scriptStream; + _scriptStream = nullptr; } @@ -1464,4 +1465,4 @@ void ScScript::afterLoad() { } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/scriptables/script.h b/engines/wintermute/base/scriptables/script.h index ee9f45e204..488ff63606 100644 --- a/engines/wintermute/base/scriptables/script.h +++ b/engines/wintermute/base/scriptables/script.h @@ -169,6 +169,6 @@ public: virtual const char *dbgGetFilename(); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/scriptables/script_engine.cpp b/engines/wintermute/base/scriptables/script_engine.cpp index f83fb36843..dd24457d6c 100644 --- a/engines/wintermute/base/scriptables/script_engine.cpp +++ b/engines/wintermute/base/scriptables/script_engine.cpp @@ -605,4 +605,4 @@ void ScEngine::dumpStats() { }*/ } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/scriptables/script_engine.h b/engines/wintermute/base/scriptables/script_engine.h index 639875ffb6..622b3c4b94 100644 --- a/engines/wintermute/base/scriptables/script_engine.h +++ b/engines/wintermute/base/scriptables/script_engine.h @@ -130,6 +130,6 @@ private: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/scriptables/script_ext_array.cpp b/engines/wintermute/base/scriptables/script_ext_array.cpp index a466d361ec..7f1c769ec5 100644 --- a/engines/wintermute/base/scriptables/script_ext_array.cpp +++ b/engines/wintermute/base/scriptables/script_ext_array.cpp @@ -249,4 +249,4 @@ bool SXArray::push(ScValue *val) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/scriptables/script_ext_array.h b/engines/wintermute/base/scriptables/script_ext_array.h index 68f808641e..e6381a011e 100644 --- a/engines/wintermute/base/scriptables/script_ext_array.h +++ b/engines/wintermute/base/scriptables/script_ext_array.h @@ -51,6 +51,6 @@ private: Common::String _strRep; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/scriptables/script_ext_date.cpp b/engines/wintermute/base/scriptables/script_ext_date.cpp index afca0c4bbf..d88bfc5851 100644 --- a/engines/wintermute/base/scriptables/script_ext_date.cpp +++ b/engines/wintermute/base/scriptables/script_ext_date.cpp @@ -307,4 +307,4 @@ int SXDate::scCompare(BaseScriptable *Value) { } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/scriptables/script_ext_date.h b/engines/wintermute/base/scriptables/script_ext_date.h index 062b7c55c7..0ccf093a7b 100644 --- a/engines/wintermute/base/scriptables/script_ext_date.h +++ b/engines/wintermute/base/scriptables/script_ext_date.h @@ -49,6 +49,6 @@ private: Common::String _strRep; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/scriptables/script_ext_file.cpp b/engines/wintermute/base/scriptables/script_ext_file.cpp index 29e032a759..18f7b8213a 100644 --- a/engines/wintermute/base/scriptables/script_ext_file.cpp +++ b/engines/wintermute/base/scriptables/script_ext_file.cpp @@ -825,4 +825,4 @@ Common::WriteStream *SXFile::openForAppend(const Common::String &filename, bool error("SXFile::openForAppend - WriteFiles not supported"); } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/scriptables/script_ext_file.h b/engines/wintermute/base/scriptables/script_ext_file.h index fa2384109f..a1298929f2 100644 --- a/engines/wintermute/base/scriptables/script_ext_file.h +++ b/engines/wintermute/base/scriptables/script_ext_file.h @@ -61,6 +61,6 @@ private: Common::WriteStream *openForAppend(const Common::String &filename, bool binary); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/scriptables/script_ext_math.cpp b/engines/wintermute/base/scriptables/script_ext_math.cpp index d816fbec65..ec53b983e7 100644 --- a/engines/wintermute/base/scriptables/script_ext_math.cpp +++ b/engines/wintermute/base/scriptables/script_ext_math.cpp @@ -31,7 +31,6 @@ #include "engines/wintermute/base/scriptables/script_value.h" #include "engines/wintermute/persistent.h" #include "common/math.h" -#include <math.h> namespace Wintermute { @@ -292,4 +291,4 @@ bool SXMath::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/scriptables/script_ext_math.h b/engines/wintermute/base/scriptables/script_ext_math.h index 48c43ea7e8..1aa274a96f 100644 --- a/engines/wintermute/base/scriptables/script_ext_math.h +++ b/engines/wintermute/base/scriptables/script_ext_math.h @@ -48,6 +48,6 @@ private: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/scriptables/script_ext_mem_buffer.cpp b/engines/wintermute/base/scriptables/script_ext_mem_buffer.cpp index 9de9905fea..6a47c09136 100644 --- a/engines/wintermute/base/scriptables/script_ext_mem_buffer.cpp +++ b/engines/wintermute/base/scriptables/script_ext_mem_buffer.cpp @@ -526,4 +526,4 @@ int SXMemBuffer::scCompare(BaseScriptable *val) { } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/scriptables/script_ext_mem_buffer.h b/engines/wintermute/base/scriptables/script_ext_mem_buffer.h index 6700a03f50..4aad8b6484 100644 --- a/engines/wintermute/base/scriptables/script_ext_mem_buffer.h +++ b/engines/wintermute/base/scriptables/script_ext_mem_buffer.h @@ -55,6 +55,6 @@ private: bool checkBounds(ScScript *script, int start, int length); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/scriptables/script_ext_object.cpp b/engines/wintermute/base/scriptables/script_ext_object.cpp index b87aac81f9..a72b244f0a 100644 --- a/engines/wintermute/base/scriptables/script_ext_object.cpp +++ b/engines/wintermute/base/scriptables/script_ext_object.cpp @@ -64,4 +64,4 @@ bool SXObject::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/scriptables/script_ext_object.h b/engines/wintermute/base/scriptables/script_ext_object.h index c85d16d44e..566111292a 100644 --- a/engines/wintermute/base/scriptables/script_ext_object.h +++ b/engines/wintermute/base/scriptables/script_ext_object.h @@ -41,6 +41,6 @@ public: virtual ~SXObject(); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/scriptables/script_ext_string.cpp b/engines/wintermute/base/scriptables/script_ext_string.cpp index 7cb3b9360b..2f2422cdf9 100644 --- a/engines/wintermute/base/scriptables/script_ext_string.cpp +++ b/engines/wintermute/base/scriptables/script_ext_string.cpp @@ -430,4 +430,4 @@ int SXString::scCompare(BaseScriptable *val) { return strcmp(_string, ((SXString *)val)->_string); } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/scriptables/script_ext_string.h b/engines/wintermute/base/scriptables/script_ext_string.h index 50b61deba4..7a95c59b4c 100644 --- a/engines/wintermute/base/scriptables/script_ext_string.h +++ b/engines/wintermute/base/scriptables/script_ext_string.h @@ -53,6 +53,6 @@ private: int32 _capacity; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/scriptables/script_stack.cpp b/engines/wintermute/base/scriptables/script_stack.cpp index b53457c81b..801ac6ab52 100644 --- a/engines/wintermute/base/scriptables/script_stack.cpp +++ b/engines/wintermute/base/scriptables/script_stack.cpp @@ -192,4 +192,4 @@ bool ScStack::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/scriptables/script_stack.h b/engines/wintermute/base/scriptables/script_stack.h index 82c3debefa..ee04485a51 100644 --- a/engines/wintermute/base/scriptables/script_stack.h +++ b/engines/wintermute/base/scriptables/script_stack.h @@ -61,6 +61,6 @@ public: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/scriptables/script_value.cpp b/engines/wintermute/base/scriptables/script_value.cpp index 5e2923e029..3532e127d0 100644 --- a/engines/wintermute/base/scriptables/script_value.cpp +++ b/engines/wintermute/base/scriptables/script_value.cpp @@ -992,4 +992,4 @@ bool ScValue::setProperty(const char *propName) { return ret; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/scriptables/script_value.h b/engines/wintermute/base/scriptables/script_value.h index a8e815023e..90ad9f182a 100644 --- a/engines/wintermute/base/scriptables/script_value.h +++ b/engines/wintermute/base/scriptables/script_value.h @@ -108,6 +108,6 @@ public: bool setProperty(const char *propName); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/sound/base_sound.cpp b/engines/wintermute/base/sound/base_sound.cpp index d027c03c8b..c1923b3ca8 100644 --- a/engines/wintermute/base/sound/base_sound.cpp +++ b/engines/wintermute/base/sound/base_sound.cpp @@ -289,4 +289,4 @@ bool BaseSound::applyFX(TSFXType type, float param1, float param2, float param3, return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/sound/base_sound.h b/engines/wintermute/base/sound/base_sound.h index 3412e6c3a3..0a984d240a 100644 --- a/engines/wintermute/base/sound/base_sound.h +++ b/engines/wintermute/base/sound/base_sound.h @@ -82,6 +82,6 @@ private: BaseSoundBuffer *_sound; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/sound/base_sound_buffer.cpp b/engines/wintermute/base/sound/base_sound_buffer.cpp index 9c919abac6..7666a441a3 100644 --- a/engines/wintermute/base/sound/base_sound_buffer.cpp +++ b/engines/wintermute/base/sound/base_sound_buffer.cpp @@ -292,4 +292,4 @@ bool BaseSoundBuffer::applyFX(TSFXType type, float param1, float param2, float p return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/sound/base_sound_buffer.h b/engines/wintermute/base/sound/base_sound_buffer.h index e78d062cd4..53b86f64c6 100644 --- a/engines/wintermute/base/sound/base_sound_buffer.h +++ b/engines/wintermute/base/sound/base_sound_buffer.h @@ -95,6 +95,6 @@ private: int32 _volume; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/sound/base_sound_manager.cpp b/engines/wintermute/base/sound/base_sound_manager.cpp index f3e7bfb408..68e62f25b0 100644 --- a/engines/wintermute/base/sound/base_sound_manager.cpp +++ b/engines/wintermute/base/sound/base_sound_manager.cpp @@ -287,4 +287,4 @@ float BaseSoundMgr::posToPan(int x, int y) { return minPan + relPos * (maxPan - minPan); } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/base/sound/base_sound_manager.h b/engines/wintermute/base/sound/base_sound_manager.h index 602571765f..5993a05001 100644 --- a/engines/wintermute/base/sound/base_sound_manager.h +++ b/engines/wintermute/base/sound/base_sound_manager.h @@ -64,6 +64,6 @@ private: bool setMasterVolume(byte percent); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/base/timer.cpp b/engines/wintermute/base/timer.cpp index 5dfc117f48..96097c10d5 100644 --- a/engines/wintermute/base/timer.cpp +++ b/engines/wintermute/base/timer.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. diff --git a/engines/wintermute/base/timer.h b/engines/wintermute/base/timer.h index ec5477ba2e..4099c6c825 100644 --- a/engines/wintermute/base/timer.h +++ b/engines/wintermute/base/timer.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -51,7 +51,7 @@ public: void persist(BasePersistenceManager *persistMgr); }; - + } // End of namespace Wintermute #endif diff --git a/engines/wintermute/coll_templ.h b/engines/wintermute/coll_templ.h index 4a8e92c121..a3df92d6c8 100644 --- a/engines/wintermute/coll_templ.h +++ b/engines/wintermute/coll_templ.h @@ -138,6 +138,6 @@ public: } }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/dctypes.h b/engines/wintermute/dctypes.h index bd4966eb6b..b40322147f 100644 --- a/engines/wintermute/dctypes.h +++ b/engines/wintermute/dctypes.h @@ -220,6 +220,6 @@ enum TShadowType { SHADOW_STENCIL = 3 }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/debugger.cpp b/engines/wintermute/debugger.cpp index 92b8e6251f..8c8b8255ab 100644 --- a/engines/wintermute/debugger.cpp +++ b/engines/wintermute/debugger.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 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. @@ -81,4 +81,4 @@ bool Console::Cmd_DumpFile(int argc, const char **argv) { return true; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/debugger.h b/engines/wintermute/debugger.h index 588b81af97..6fbbb084f0 100644 --- a/engines/wintermute/debugger.h +++ b/engines/wintermute/debugger.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 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. @@ -32,7 +32,7 @@ class Console : public GUI::Debugger { public: Console(WintermuteEngine *vm); virtual ~Console(); - + bool Cmd_ShowFps(int argc, const char **argv); bool Cmd_DumpFile(int argc, const char **argv); private: diff --git a/engines/wintermute/detection.cpp b/engines/wintermute/detection.cpp index 1bf2c76a50..ac21d78ef5 100644 --- a/engines/wintermute/detection.cpp +++ b/engines/wintermute/detection.cpp @@ -181,7 +181,7 @@ public: } }; -} // end of namespace Wintermute +} // End of namespace Wintermute #if PLUGIN_ENABLED_DYNAMIC(WINTERMUTE) REGISTER_PLUGIN_DYNAMIC(WINTERMUTE, PLUGIN_TYPE_ENGINE, Wintermute::WintermuteMetaEngine); diff --git a/engines/wintermute/detection_tables.h b/engines/wintermute/detection_tables.h index 00ec51a715..702c0b28ba 100644 --- a/engines/wintermute/detection_tables.h +++ b/engines/wintermute/detection_tables.h @@ -27,6 +27,7 @@ namespace Wintermute { static const PlainGameDescriptor wintermuteGames[] = { {"5ld", "Five Lethal Demons"}, {"5ma", "Five Magical Amulets"}, + {"bthreshold", "Beyond the Threshold"}, {"actualdest", "Actual Destination"}, {"carolreed4", "Carol Reed 4 - East Side Story"}, {"carolreed5", "Carol Reed 5 - The Colour of Murder"}, @@ -36,17 +37,22 @@ static const PlainGameDescriptor wintermuteGames[] = { {"carolreed9", "Carol Reed 9 - Cold Case Summer"}, {"chivalry", "Chivalry is Not Dead"}, {"deadcity", "Dead City"}, + {"dreaming", "Des Reves Elastiques Avec Mille Insectes Nommes Georges"}, {"dirtysplit", "Dirty Split"}, {"dreamscape", "Dreamscape"}, {"ghostsheet", "Ghost in the Sheet"}, {"hamlet", "Hamlet or the last game without MMORPS features, shaders and product placement"}, + {"jamesperis", "James Peris: No License Nor Control"}, {"julia", "J.U.L.I.A."}, {"mirage", "Mirage"}, {"pigeons", "Pigeons in the Park"}, {"reversion1", "Reversion: The Escape"}, - {"reversion2", "Reversion: The Meeting"}, + {"reversion2", "Reversion: The Meeting"}, {"rosemary", "Rosemary"}, + {"shinestar", "The Shine of a Star"}, {"thebox", "The Box"}, + {"tib", "Fairy Tales About Toshechka and Boshechka"}, + {"tradestory", "The Trader of Stories"}, {"twc", "the white chamber"}, {"wintermute", "Wintermute engine game"}, {0, 0} @@ -83,6 +89,16 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO0() }, + // Beyond the Threshold + { + "bthreshold", + "", + AD_ENTRY1s("data.dcp", "d49bf9ccb2e74507447c82d6ad3e2bc4", 12773712), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, // Carol Reed 4 - East Side Story (Demo) { "carolreed4", @@ -125,6 +141,17 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO0() }, + // Carol Reed 7 - Blue Madonna (Demo) + { + "carolreed7", + "Demo", + AD_ENTRY1s("data.dcp", "0372ad0c775266f6355e9e8ae397a2f1", 103719442), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE | + ADGF_DEMO, + GUIO0() + }, // Carol Reed 7 - Blue Madonna { "carolreed7", @@ -237,6 +264,16 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO0() }, + // Des Reves Elastiques Avec Mille Insectes Nommes Georges + { + "dreaming", + "", + AD_ENTRY1s("data.dcp", "4af26d97ea063fc1277ce30ae431de90", 8804073), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, // Dreamscape { "dreamscape", @@ -268,6 +305,48 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO0() }, + // James Peris: No License Nor Control (English) + { + "jamesperis", + "", + AD_ENTRY1s("data.dcp", "a420961e170cb7d168a0d2bae2fe5218", 225294032), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, + // James Peris: No License Nor Control (Spanish) + { + "jamesperis", + "", + AD_ENTRY1s("data.dcp", "a420961e170cb7d168a0d2bae2fe5218", 225294032), + Common::ES_ESP, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, + // James Peris: No License Nor Control (Demo) (English) + { + "jamesperis", + "Demo", + AD_ENTRY1s("data.dcp", "edb9f9c7a08993c1e28f4e477b5f9830", 116113507), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE | + ADGF_DEMO, + GUIO0() + }, + // James Peris: No License Nor Control (Demo) (Spanish) + { + "jamesperis", + "Demo", + AD_ENTRY1s("data.dcp", "edb9f9c7a08993c1e28f4e477b5f9830", 116113507), + Common::ES_ESP, + Common::kPlatformWindows, + ADGF_UNSTABLE | + ADGF_DEMO, + GUIO0() + }, // J.U.L.I.A. (English) { "julia", @@ -289,6 +368,17 @@ static const ADGameDescription gameDescriptions[] = { ADGF_DEMO, GUIO0() }, + // J.U.L.I.A. (English) (Greenlight Demo) + { + "julia", + "Greenlight Demo", + AD_ENTRY1s("data.dcp", "4befd448d36b0dae9c3ab1aa7cb8b78d", 7271886), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE | + ADGF_DEMO, + GUIO0() + }, // Mirage { "mirage", @@ -535,6 +625,16 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO0() }, + // The Shine of a Star + { + "shinestar", + "", + AD_ENTRY1s("data.dcp", "f05abe9e2427a5e4f73648fa09c4ba8e", 94113060), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, // The Box { "thebox", @@ -545,6 +645,27 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO0() }, + // Fairy Tales About Toshechka and Boshechka + { + "tib", + "", + AD_ENTRY1s("data.dcp", "87d296ef3f46570ed18f000d3885db77", 340264526), + Common::RU_RUS, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, + // The Trader of Stories + { + "tradestory", + "Demo", + AD_ENTRY1s("data.dcp", "0a0b51191636cc8ead89b905281c3218", 40401902), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE | + ADGF_DEMO, + GUIO0() + }, // the white chamber (multi-language) { "twc", diff --git a/engines/wintermute/graphics/transform_struct.cpp b/engines/wintermute/graphics/transform_struct.cpp new file mode 100644 index 0000000000..8edbf765b5 --- /dev/null +++ b/engines/wintermute/graphics/transform_struct.cpp @@ -0,0 +1,93 @@ +/* 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 "engines/wintermute/graphics/transform_struct.h" +#include "engines/wintermute/graphics/transparent_surface.h" + +namespace Wintermute { +void TransformStruct::init(Point32 zoom, uint32 angle, Point32 hotspot, bool alphaDisable, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, Point32 offset) { + _zoom = zoom; + _angle = angle; + _hotspot = hotspot; + _blendMode = blendMode; + _rgbaMod = rgbaMod; + _alphaDisable = alphaDisable; + _flip = 0; + _flip += TransparentSurface::FLIP_H * mirrorX; + _flip += TransparentSurface::FLIP_V * mirrorY; + _offset = offset; +} + + +TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, int32 offsetX, int32 offsetY) { + init(Point32(zoomX, zoomY), + angle, + Point32(hotspotX, hotspotY), + false, + blendMode, + rgbaMod, + mirrorX, mirrorY, + Point32(offsetX, offsetY)); +} + +TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY) { + init(Point32(zoomX, zoomY), + kDefaultAngle, + Point32(kDefaultHotspotX, kDefaultHotspotY), + false, + blendMode, + rgbaMod, + mirrorX, + mirrorY, + Point32(kDefaultOffsetX, kDefaultOffsetY)); +} + +TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY) { + init(Point32(zoomX, zoomY), + angle, + Point32(hotspotX, hotspotY), + true, + BLEND_NORMAL, + kDefaultRgbaMod, + false, false, + Point32(kDefaultOffsetX, kDefaultOffsetY)); +} + +TransformStruct::TransformStruct() { + init(Point32(kDefaultZoomX, kDefaultZoomY), + kDefaultAngle, + Point32(kDefaultHotspotX, kDefaultHotspotY), + true, + BLEND_NORMAL, + kDefaultRgbaMod, + false, false, + Point32(kDefaultOffsetX, kDefaultOffsetY)); +} + +bool TransformStruct::getMirrorX() const { + return (bool)(_flip & TransparentSurface::FLIP_H); +} + +bool TransformStruct::getMirrorY() const { + return (bool)(_flip & TransparentSurface::FLIP_V); +} +} // End of namespace Wintermute diff --git a/engines/wintermute/graphics/transform_struct.h b/engines/wintermute/graphics/transform_struct.h new file mode 100644 index 0000000000..a54c4cc5d0 --- /dev/null +++ b/engines/wintermute/graphics/transform_struct.h @@ -0,0 +1,83 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef WINTERMUTE_TRANSFORM_STRUCT_H +#define WINTERMUTE_TRANSFORM_STRUCT_H + +#include "engines/wintermute/math/rect32.h" +#include "engines/wintermute/dctypes.h" + +namespace Wintermute { +/** + * Contains all the required information that define a transform. + * Same source sprite + same TransformStruct = Same resulting sprite. + * Has a number of overloaded constructors to accomodate various argument lists. + */ + +const uint32 kDefaultZoomX = 100; +const uint32 kDefaultZoomY = 100; +const uint32 kDefaultRgbaMod = 0xFFFFFFFF; +const int32 kDefaultHotspotX = 0; +const int32 kDefaultHotspotY = 0; +const int32 kDefaultOffsetX = 0; +const int32 kDefaultOffsetY = 0; +const int32 kDefaultAngle = 0; + +struct TransformStruct { +private: + void init(Point32 zoom, uint32 angle, Point32 hotspot, bool alphaDisable, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX, bool mirrorY, Point32 offset); + +public: + TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false, int32 offsetX = 0, int32 offsetY = 0); + TransformStruct(int32 zoomX, int32 zoomY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false); + TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX = 0, int32 hotspotY = 0); + TransformStruct(); + + Point32 _zoom; ///< Zoom; 100 = no zoom + Point32 _hotspot; ///< Position of the hotspot + uint32 _angle; ///< Rotation angle, in degrees + byte _flip; ///< Bitflag: see TransparentSurface::FLIP_XXX + bool _alphaDisable; + TSpriteBlendMode _blendMode; + uint32 _rgbaMod; ///< RGBa + Point32 _offset; + + bool getMirrorX() const; + bool getMirrorY() const; + + bool operator==(const TransformStruct &compare) const { + return (compare._angle == _angle && + compare._flip == _flip && + compare._zoom == _zoom && + compare._offset == _offset && + compare._alphaDisable == _alphaDisable && + compare._rgbaMod == _rgbaMod && + compare._blendMode == _blendMode + ); + } + + bool operator!=(const TransformStruct &compare) const { + return !(compare == *this); + } +}; +} // End of namespace Wintermute +#endif diff --git a/engines/wintermute/graphics/transform_tools.cpp b/engines/wintermute/graphics/transform_tools.cpp new file mode 100644 index 0000000000..ebf9092aaa --- /dev/null +++ b/engines/wintermute/graphics/transform_tools.cpp @@ -0,0 +1,73 @@ +/* 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 "engines/wintermute/graphics/transform_tools.h" +#include <math.h> + +namespace Wintermute { + +FloatPoint TransformTools::transformPoint(const FloatPoint &point, const float rotate, const Point32 &zoom, const bool mirrorX, const bool mirrorY) { + float rotateRad = rotate * M_PI / 180.0f; + FloatPoint newPoint; + newPoint.x = (point.x * cos(rotateRad) - point.y * sin(rotateRad)) * zoom.x / kDefaultZoomX; + newPoint.y = (point.x * sin(rotateRad) + point.y * cos(rotateRad)) * zoom.y / kDefaultZoomY; + if (mirrorX) { + newPoint.x *= -1; + } + if (mirrorY) { + newPoint.y *= -1; + } + return newPoint; +} + +Rect32 TransformTools::newRect(const Rect32 &oldRect, const TransformStruct &transform, Point32 *newHotspot) { + Point32 nw(oldRect.left, oldRect.top); + Point32 ne(oldRect.right, oldRect.top); + Point32 sw(oldRect.left, oldRect.bottom); + Point32 se(oldRect.right, oldRect.bottom); + + FloatPoint nw1, ne1, sw1, se1; + + nw1 = transformPoint(nw - transform._hotspot, transform._angle, transform._zoom); + ne1 = transformPoint(ne - transform._hotspot, transform._angle, transform._zoom); + sw1 = transformPoint(sw - transform._hotspot, transform._angle, transform._zoom); + se1 = transformPoint(se - transform._hotspot, transform._angle, transform._zoom); + + float top = MIN(nw1.y, MIN(ne1.y, MIN(sw1.y, se1.y))); + float bottom = MAX(nw1.y, MAX(ne1.y, MAX(sw1.y, se1.y))); + float left = MIN(nw1.x, MIN(ne1.x, MIN(sw1.x, se1.x))); + float right = MAX(nw1.x, MAX(ne1.x, MAX(sw1.x, se1.x))); + + Rect32 res; + newHotspot->y = (uint32)(-floor(top)); + newHotspot->x = (uint32)(-floor(left)); + + res.top = (int32)(floor(top)) + transform._hotspot.y; + res.bottom = (int32)(ceil(bottom)) + transform._hotspot.y; + res.left = (int32)(floor(left)) + transform._hotspot.x; + res.right = (int32)(ceil(right)) + transform._hotspot.x; + + return res; +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/graphics/transform_tools.h b/engines/wintermute/graphics/transform_tools.h new file mode 100644 index 0000000000..c92b81fd11 --- /dev/null +++ b/engines/wintermute/graphics/transform_tools.h @@ -0,0 +1,53 @@ +/* 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 WINTERMUTE_TRANSFORM_TOOLS_H +#define WINTERMUTE_TRANSFORM_TOOLS_H + +#include "engines/wintermute/math/rect32.h" +#include "engines/wintermute/math/floatpoint.h" +#include "engines/wintermute/graphics/transform_struct.h" + +namespace Wintermute { + +class TransformTools { +public: + /** + * Basic transform (scale + rotate) for a single point + */ + static FloatPoint transformPoint(const FloatPoint &point, const float rotate, const Point32 &zoom, const bool mirrorX = false, const bool mirrorY = false); + + /** + * @param &point the point on which the transform is to be applied + * @param rotate the angle in degrees + * @param &zoom zoom x,y in percent + * @param mirrorX flip along the vertical axis? + * @param mirrorY flip along the horizontal axis? + * @return the smallest rect that can contain the transformed sprite + * and, as a side-effect, "newHotspot" will tell you where the hotspot will + * have ended up in the new rect, for centering. + */ + static Rect32 newRect(const Rect32 &oldRect, const TransformStruct &transform, Point32 *newHotspot); +}; + +} // End of namespace Wintermute +#endif diff --git a/engines/wintermute/graphics/transparent_surface.cpp b/engines/wintermute/graphics/transparent_surface.cpp index dcdcbf247e..e375322ae9 100644 --- a/engines/wintermute/graphics/transparent_surface.cpp +++ b/engines/wintermute/graphics/transparent_surface.cpp @@ -23,12 +23,123 @@ #include "common/endian.h" #include "common/util.h" #include "common/rect.h" +#include "common/math.h" #include "common/textconsole.h" #include "graphics/primitives.h" #include "engines/wintermute/graphics/transparent_surface.h" +#include "engines/wintermute/graphics/transform_tools.h" namespace Wintermute { + +#if ENABLE_BILINEAR +void TransparentSurface::copyPixelBilinear(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst) { + int srcW = srcRect.width(); + int srcH = srcRect.height(); + int dstW = dstRect.width(); + int dstH = dstRect.height(); + + assert(dstX >= 0 && dstX < dstW); + assert(dstY >= 0 && dstY < dstH); + + float x1 = floor(projX); + float x2 = ceil(projX); + float y1 = floor(projY); + float y2 = ceil(projY); + + uint32 Q11, Q12, Q21, Q22; + + if (x1 >= srcW || x1 < 0 || y1 >= srcH || y1 < 0) { + Q11 = 0; + } else { + Q11 = READ_UINT32((const byte *)src->getBasePtr((int)(x1 + srcRect.left), (int)(y1 + srcRect.top))); + } + + if (x1 >= srcW || x1 < 0 || y2 >= srcH || y2 < 0) { + Q12 = 0; + } else { + Q12 = READ_UINT32((const byte *)src->getBasePtr((int)(x1 + srcRect.left), (int)(y2 + srcRect.top))); + } + + if (x2 >= srcW || x2 < 0 || y1 >= srcH || y1 < 0) { + Q21 = 0; + } else { + Q21 = READ_UINT32((const byte *)src->getBasePtr((int)(x2 + srcRect.left), (int)(y1 + srcRect.top))); + } + + if (x2 >= srcW || x2 < 0 || y2 >= srcH || y2 < 0) { + Q22 = 0; + } else { + Q22 = READ_UINT32((const byte *)src->getBasePtr((int)(x2 + srcRect.left), (int)(y2 + srcRect.top))); + } + + byte *Q11s = (byte *)&Q11; + byte *Q12s = (byte *)&Q12; + byte *Q21s = (byte *)&Q21; + byte *Q22s = (byte *)&Q22; + + uint32 color; + byte *dest = (byte *)&color; + + float q11x = (x2 - projX); + float q11y = (y2 - projY); + float q21x = (projX - x1); + float q21y = (y2 - projY); + float q12x = (x2 - projX); + float q12y = (projY - y1); + + if (x1 == x2 && y1 == y2) { + for (int c = 0; c < 4; c++) { + dest[c] = ((float)Q11s[c]); + } + } else { + + if (x1 == x2) { + q11x = 0.5; + q12x = 0.5; + q21x = 0.5; + } else if (y1 == y2) { + q11y = 0.5; + q12y = 0.5; + q21y = 0.5; + } + + for (int c = 0; c < 4; c++) { + dest[c] = (byte)( + ((float)Q11s[c]) * q11x * q11y + + ((float)Q21s[c]) * q21x * q21y + + ((float)Q12s[c]) * q12x * q12y + + ((float)Q22s[c]) * (1.0 - + q11x * q11y - + q21x * q21y - + q12x * q12y) + ); + } + } + WRITE_UINT32((byte *)dst->getBasePtr(dstX + dstRect.left, dstY + dstRect.top), color); +} +#else +void TransparentSurface::copyPixelNearestNeighbor(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst) { + int srcW = srcRect.width(); + int srcH = srcRect.height(); + int dstW = dstRect.width(); + int dstH = dstRect.height(); + + assert(dstX >= 0 && dstX < dstW); + assert(dstY >= 0 && dstY < dstH); + + uint32 color; + + if (projX >= srcW || projX < 0 || projY >= srcH || projY < 0) { + color = 0; + } else { + color = READ_UINT32((const byte *)src->getBasePtr((int)projX, (int)projY)); + } + + WRITE_UINT32((byte *)dst->getBasePtr(dstX, dstY), color); +} +#endif + byte *TransparentSurface::_lookup = nullptr; void TransparentSurface::destroyLookup() { @@ -46,11 +157,14 @@ TransparentSurface::TransparentSurface(const Surface &surf, bool copyData) : Sur h = surf.h; pitch = surf.pitch; format = surf.format; - pixels = surf.pixels; + // We need to cast the const qualifier away here because 'pixels' + // always needs to be writable. 'surf' however is a constant Surface, + // thus getPixels will always return const pixel data. + pixels = const_cast<void *>(surf.getPixels()); } } -void doBlitOpaque(byte *ino, byte* outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { +void doBlitOpaque(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { byte *in, *out; #ifdef SCUMM_LITTLE_ENDIAN @@ -81,7 +195,7 @@ void TransparentSurface::generateLookup() { } } -void TransparentSurface::doBlitAlpha(byte *ino, byte* outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { +void TransparentSurface::doBlitAlpha(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { byte *in, *out; if (!_lookup) { @@ -195,16 +309,28 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p } if (pPartRect) { - srcImage.pixels = &((char *)pixels)[pPartRect->top * srcImage.pitch + pPartRect->left * 4]; + + int xOffset = pPartRect->left; + int yOffset = pPartRect->top; + + if (flipping & FLIP_V) { + yOffset = srcImage.h - pPartRect->bottom; + } + + if (flipping & FLIP_H) { + xOffset = srcImage.w - pPartRect->right; + } + + srcImage.pixels = getBasePtr(xOffset, yOffset); srcImage.w = pPartRect->width(); srcImage.h = pPartRect->height(); debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, - pPartRect->left, pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height); + pPartRect->left, pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height); } else { debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, 0, 0, - srcImage.w, srcImage.h, color, width, height); + srcImage.w, srcImage.h, color, width, height); } if (width == -1) @@ -224,7 +350,7 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p if ((width != srcImage.w) || (height != srcImage.h)) { // Scale the image img = imgScaled = srcImage.scale(width, height); - savedPixels = (byte *)img->pixels; + savedPixels = (byte *)img->getPixels(); } else { img = &srcImage; } @@ -232,13 +358,13 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p // Handle off-screen clipping if (posY < 0) { img->h = MAX(0, (int)img->h - -posY); - img->pixels = (byte *)img->pixels + img->pitch * -posY; + img->setPixels((byte *)img->getBasePtr(0, -posY)); posY = 0; } if (posX < 0) { img->w = MAX(0, (int)img->w - -posX); - img->pixels = (byte *)img->pixels + (-posX * 4); + img->setPixels((byte *)img->getBasePtr(-posX, 0)); posX = 0; } @@ -250,12 +376,12 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p int inStep = 4; int inoStep = img->pitch; - if (flipping & TransparentSurface::FLIP_V) { + if (flipping & TransparentSurface::FLIP_H) { inStep = -inStep; xp = img->w - 1; } - if (flipping & TransparentSurface::FLIP_H) { + if (flipping & TransparentSurface::FLIP_V) { inoStep = -inoStep; yp = img->h - 1; } @@ -375,7 +501,7 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p retSize.setHeight(img->h); if (imgScaled) { - imgScaled->pixels = savedPixels; + imgScaled->setPixels(savedPixels); imgScaled->free(); delete imgScaled; } @@ -383,16 +509,54 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p return retSize; } +TransparentSurface *TransparentSurface::rotoscale(const TransformStruct &transform) const { + + assert(transform._angle != 0); // This would not be ideal; rotoscale() should never be called in conditional branches where angle = 0 anyway. + + Point32 newHotspot; + Common::Rect srcRect(0, 0, (int16)w, (int16)h); + Rect32 rect = TransformTools::newRect(Rect32(srcRect), transform, &newHotspot); + Common::Rect dstRect(0, 0, (int16)(rect.right - rect.left), (int16)(rect.bottom - rect.top)); + + TransparentSurface *target = new TransparentSurface(); + assert(format.bytesPerPixel == 4); + + int dstW = dstRect.width(); + int dstH = dstRect.height(); + + target->create((uint16)dstW, (uint16)dstH, this->format); + + uint32 invAngle = 360 - (transform._angle % 360); + float invCos = cos(invAngle * M_PI / 180.0); + float invSin = sin(invAngle * M_PI / 180.0); + float targX; + float targY; + + for (int y = 0; y < dstH; y++) { + for (int x = 0; x < dstW; x++) { + int x1 = x - newHotspot.x; + int y1 = y - newHotspot.y; + + targX = ((x1 * invCos - y1 * invSin)) * kDefaultZoomX / transform._zoom.x + srcRect.left; + targY = ((x1 * invSin + y1 * invCos)) * kDefaultZoomY / transform._zoom.y + srcRect.top; + + targX += transform._hotspot.x; + targY += transform._hotspot.y; + +#if ENABLE_BILINEAR + copyPixelBilinear(targX, targY, x, y, srcRect, dstRect, this, target); +#else + copyPixelNearestNeighbor(targX, targY, x, y, srcRect, dstRect, this, target); +#endif + } + } + return target; +} + TransparentSurface *TransparentSurface::scale(uint16 newWidth, uint16 newHeight) const { Common::Rect srcRect(0, 0, (int16)w, (int16)h); Common::Rect dstRect(0, 0, (int16)newWidth, (int16)newHeight); - return scale(srcRect, dstRect); -} -// Copied from clone2727's https://github.com/clone2727/scummvm/blob/pegasus/engines/pegasus/surface.cpp#L247 -TransparentSurface *TransparentSurface::scale(const Common::Rect &srcRect, const Common::Rect &dstRect) const { - // I'm doing simple linear scaling here - // dstRect(x, y) = srcRect(x * srcW / dstW, y * srcH / dstH); TransparentSurface *target = new TransparentSurface(); assert(format.bytesPerPixel == 4); @@ -404,11 +568,18 @@ TransparentSurface *TransparentSurface::scale(const Common::Rect &srcRect, const target->create((uint16)dstW, (uint16)dstH, this->format); + + float projX; + float projY; for (int y = 0; y < dstH; y++) { for (int x = 0; x < dstW; x++) { - uint32 color = READ_UINT32((const byte *)getBasePtr(x * srcW / dstW + srcRect.left, - y * srcH / dstH + srcRect.top)); - WRITE_UINT32((byte *)target->getBasePtr(x + dstRect.left, y + dstRect.top), color); + projX = x / (float)dstW * srcW; + projY = y / (float)dstH * srcH; +#if ENABLE_BILINEAR + copyPixelBilinear(projX, projY, x, y, srcRect, dstRect, this, target); +#else + copyPixelNearestNeighbor(projX, projY, x, y, srcRect, dstRect, this, target); +#endif } } return target; @@ -440,4 +611,4 @@ void TransparentSurface::applyColorKey(uint8 rKey, uint8 gKey, uint8 bKey, bool } } -} // End of namespace Graphics +} // End of namespace Wintermute diff --git a/engines/wintermute/graphics/transparent_surface.h b/engines/wintermute/graphics/transparent_surface.h index dc079a1fbc..9d06f3e006 100644 --- a/engines/wintermute/graphics/transparent_surface.h +++ b/engines/wintermute/graphics/transparent_surface.h @@ -23,6 +23,10 @@ #define GRAPHICS_TRANSPARENTSURFACE_H #include "graphics/surface.h" +#include "engines/wintermute/graphics/transform_struct.h" + +#define ENABLE_BILINEAR 0 + /* * This code is based on Broken Sword 2.5 engine @@ -49,21 +53,26 @@ struct TransparentSurface : public Graphics::Surface { void setColorKey(char r, char g, char b); void disableColorKey(); +#if ENABLE_BILINEAR + static void copyPixelBilinear(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst); +#else + static void copyPixelNearestNeighbor(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst); +#endif // Enums /** @brief The possible flipping parameters for the blit methode. */ enum FLIP_FLAGS { - /// The image will not be flipped. - FLIP_NONE = 0, - /// The image will be flipped at the horizontal axis. - FLIP_H = 1, - /// The image will be flipped at the vertical axis. - FLIP_V = 2, - /// The image will be flipped at the horizontal and vertical axis. - FLIP_HV = FLIP_H | FLIP_V, - /// The image will be flipped at the horizontal and vertical axis. - FLIP_VH = FLIP_H | FLIP_V + /// The image will not be flipped. + FLIP_NONE = 0, + /// The image will be flipped at the horizontal axis. + FLIP_H = 1, + /// The image will be flipped at the vertical axis. + FLIP_V = 2, + /// The image will be flipped at the horizontal and vertical axis. + FLIP_HV = FLIP_H | FLIP_V, + /// The image will be flipped at the horizontal and vertical axis. + FLIP_VH = FLIP_H | FLIP_V }; bool _enableAlphaBlit; @@ -102,13 +111,13 @@ struct TransparentSurface : public Graphics::Surface { uint color = BS_ARGB(255, 255, 255, 255), int width = -1, int height = -1); void applyColorKey(uint8 r, uint8 g, uint8 b, bool overwriteAlpha = false); - // The following scale-code supports arbitrary scaling (i.e. no repeats of column 0 at the end of lines) + TransparentSurface *scale(uint16 newWidth, uint16 newHeight) const; - TransparentSurface *scale(const Common::Rect &srcRect, const Common::Rect &dstRect) const; + TransparentSurface *rotoscale(const TransformStruct &transform) const; static byte *_lookup; static void destroyLookup(); private: - static void doBlitAlpha(byte *ino, byte* outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep); + static void doBlitAlpha(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep); static void generateLookup(); }; @@ -125,7 +134,7 @@ private: };*/ -} // End of namespace Graphics +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/math/floatpoint.h b/engines/wintermute/math/floatpoint.h new file mode 100644 index 0000000000..0c47ef09d7 --- /dev/null +++ b/engines/wintermute/math/floatpoint.h @@ -0,0 +1,52 @@ +/* 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 WINTERMUTE_FLOATPOINT_H +#define WINTERMUTE_FLOATPOINT_H + +namespace Wintermute { + +struct FloatPoint { + float x; + float y; + FloatPoint() : x(0), y(0) {} + FloatPoint(float x1, float y1) : x(x1), y(y1) {} + bool operator==(const FloatPoint &p) const { return x == p.x && y == p.y; } + bool operator!=(const FloatPoint &p) const { return x != p.x || y != p.y; } + FloatPoint operator+(const FloatPoint &delta) const { return FloatPoint (x + delta.x, y + delta.y); } + FloatPoint operator-(const FloatPoint &delta) const { return FloatPoint (x - delta.x, y - delta.y); } + + FloatPoint& operator+=(const FloatPoint &delta) { + x += delta.x; + y += delta.y; + return *this; + } + FloatPoint& operator-=(const FloatPoint &delta) { + x -= delta.x; + y -= delta.y; + return *this; + } +}; + +} // End of namespace Wintermute + +#endif diff --git a/engines/wintermute/math/math_util.cpp b/engines/wintermute/math/math_util.cpp index 31af77538a..903cea6d39 100644 --- a/engines/wintermute/math/math_util.cpp +++ b/engines/wintermute/math/math_util.cpp @@ -27,7 +27,7 @@ */ #include "engines/wintermute/math/math_util.h" -#include <math.h> +#include "common/scummsys.h" namespace Wintermute { @@ -49,4 +49,4 @@ float MathUtil::roundUp(float val) { return result; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/math/math_util.h b/engines/wintermute/math/math_util.h index 38b6d9abf9..41a7a43e2e 100644 --- a/engines/wintermute/math/math_util.h +++ b/engines/wintermute/math/math_util.h @@ -37,6 +37,6 @@ public: static float roundUp(float val); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/math/matrix4.cpp b/engines/wintermute/math/matrix4.cpp index ca1eae8813..011766f510 100644 --- a/engines/wintermute/math/matrix4.cpp +++ b/engines/wintermute/math/matrix4.cpp @@ -28,7 +28,7 @@ #include "engines/wintermute/math/matrix4.h" #include "engines/wintermute/math/vector2.h" -#include <math.h> +#include "common/scummsys.h" namespace Wintermute { @@ -83,4 +83,4 @@ void Matrix4::transformVector2(Vector2 &vec) { vec.y = y; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/math/matrix4.h b/engines/wintermute/math/matrix4.h index 273633f723..4198b50484 100644 --- a/engines/wintermute/math/matrix4.h +++ b/engines/wintermute/math/matrix4.h @@ -45,6 +45,6 @@ public: float m[4][4]; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/math/rect32.h b/engines/wintermute/math/rect32.h index 190c1135cf..f522ab3a35 100644 --- a/engines/wintermute/math/rect32.h +++ b/engines/wintermute/math/rect32.h @@ -24,12 +24,38 @@ #define WINTERMUTE_RECT32_H #include "common/system.h" +#include "engines/wintermute/math/floatpoint.h" +#include "common/rect.h" namespace Wintermute { struct Point32 { int32 x; int32 y; + Point32() : x(0), y(0) {} + Point32(int32 x1, int32 y1) : x(x1), y(y1) {} + bool operator==(const Point32 &p) const { return x == p.x && y == p.y; } + bool operator!=(const Point32 &p) const { return x != p.x || y != p.y; } + Point32 operator+(const Point32 &delta) const { return Point32(x + delta.x, y + delta.y); } + Point32 operator-(const Point32 &delta) const { return Point32(x - delta.x, y - delta.y); } + + Point32 &operator+=(const Point32 &delta) { + x += delta.x; + y += delta.y; + return *this; + } + + Point32 &operator-=(const Point32 &delta) { + x -= delta.x; + y -= delta.y; + return *this; + } + + operator FloatPoint() { + return FloatPoint(x,y); + } + + }; struct Rect32 { @@ -38,6 +64,7 @@ struct Rect32 { Rect32() : top(0), left(0), bottom(0), right(0) {} Rect32(int32 w, int32 h) : top(0), left(0), bottom(h), right(w) {} + Rect32(const Common::Rect &rect) : top(rect.top), left(rect.left), bottom(rect.bottom), right(rect.right) {} Rect32(int32 x1, int32 y1, int32 x2, int32 y2) : top(y1), left(x1), bottom(y2), right(x2) { assert(isValidRect()); } @@ -89,6 +116,6 @@ struct Rect32 { } }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/math/vector2.cpp b/engines/wintermute/math/vector2.cpp index 74c5586d62..618ee9bda9 100644 --- a/engines/wintermute/math/vector2.cpp +++ b/engines/wintermute/math/vector2.cpp @@ -27,7 +27,7 @@ */ #include "engines/wintermute/math/vector2.h" -#include <math.h> +#include "common/scummsys.h" namespace Wintermute { @@ -52,4 +52,4 @@ float Vector2::length() const { return (float)sqrt(x * x + y * y); } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/math/vector2.h b/engines/wintermute/math/vector2.h index 31f31daaa0..e4ba97c517 100644 --- a/engines/wintermute/math/vector2.h +++ b/engines/wintermute/math/vector2.h @@ -70,6 +70,6 @@ public: float y; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk index 32931bf05f..95f9ba2ffb 100644 --- a/engines/wintermute/module.mk +++ b/engines/wintermute/module.mk @@ -89,6 +89,8 @@ MODULE_OBJS := \ base/save_thumb_helper.o \ base/timer.o \ detection.o \ + graphics/transform_struct.o \ + graphics/transform_tools.o \ graphics/transparent_surface.o \ math/math_util.o \ math/matrix4.o \ diff --git a/engines/wintermute/persistent.h b/engines/wintermute/persistent.h index 1464ae0fd6..ddc0791054 100644 --- a/engines/wintermute/persistent.h +++ b/engines/wintermute/persistent.h @@ -37,7 +37,7 @@ class BasePersistenceManager; typedef void *(*PERSISTBUILD)(void); typedef bool(*PERSISTLOAD)(void *, BasePersistenceManager *); typedef void(*SYS_INSTANCE_CALLBACK)(void *instance, void *data); -} // end of namespace Wintermute +} // End of namespace Wintermute #include "engines/wintermute/system/sys_class_registry.h" namespace Wintermute { @@ -85,6 +85,6 @@ namespace Wintermute { #define TMEMBER_PTR(memberName) #memberName, &memberName #define TMEMBER_INT(memberName) #memberName, (int32*)&memberName -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/platform_osystem.cpp b/engines/wintermute/platform_osystem.cpp index 362c0da624..87a127d001 100644 --- a/engines/wintermute/platform_osystem.cpp +++ b/engines/wintermute/platform_osystem.cpp @@ -125,9 +125,12 @@ void BasePlatform::handleEvent(Common::Event *event) { // _gameRef->AutoSaveOnExit(); // _gameRef->_quitting = true; // } - if (_gameRef) { - _gameRef->onWindowClose(); - } + +// The engine CAN query for closing, but we disable it for now, as the EVENT_QUIT-event +// can't be stopped. +// if (_gameRef) { +// _gameRef->onWindowClose(); +// } break; default: // TODO: Do we care about any other events? @@ -272,4 +275,4 @@ char *BasePlatform::strlwr(char *string) { return string; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/platform_osystem.h b/engines/wintermute/platform_osystem.h index 8c39b29ea9..46c86df909 100644 --- a/engines/wintermute/platform_osystem.h +++ b/engines/wintermute/platform_osystem.h @@ -70,6 +70,6 @@ private: static WintermuteEngine *_engineRef; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/system/sys_class.cpp b/engines/wintermute/system/sys_class.cpp index cda58bbb48..0577f29e2c 100644 --- a/engines/wintermute/system/sys_class.cpp +++ b/engines/wintermute/system/sys_class.cpp @@ -217,4 +217,4 @@ void SystemClass::instanceCallback(SYS_INSTANCE_CALLBACK lpCallback, void *lpDat } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/system/sys_class.h b/engines/wintermute/system/sys_class.h index 3f91723ed8..9fb3f70696 100644 --- a/engines/wintermute/system/sys_class.h +++ b/engines/wintermute/system/sys_class.h @@ -125,6 +125,6 @@ private: InstanceMap _instanceMap; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/system/sys_class_registry.cpp b/engines/wintermute/system/sys_class_registry.cpp index 8a6aae754f..20e4661efb 100644 --- a/engines/wintermute/system/sys_class_registry.cpp +++ b/engines/wintermute/system/sys_class_registry.cpp @@ -333,4 +333,4 @@ void SystemClassRegistry::dumpClasses(Common::WriteStream *stream) { } } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/system/sys_class_registry.h b/engines/wintermute/system/sys_class_registry.h index ef7218c7c1..48a6738ffb 100644 --- a/engines/wintermute/system/sys_class_registry.h +++ b/engines/wintermute/system/sys_class_registry.h @@ -101,6 +101,6 @@ public: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/system/sys_instance.cpp b/engines/wintermute/system/sys_instance.cpp index d106119dba..b8e5c9b50a 100644 --- a/engines/wintermute/system/sys_instance.cpp +++ b/engines/wintermute/system/sys_instance.cpp @@ -46,4 +46,4 @@ SystemInstance::SystemInstance(void *instance, int id, SystemClass *sysClass) { SystemInstance::~SystemInstance() { } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/system/sys_instance.h b/engines/wintermute/system/sys_instance.h index 215a6d1437..115de28094 100644 --- a/engines/wintermute/system/sys_instance.h +++ b/engines/wintermute/system/sys_instance.h @@ -63,6 +63,6 @@ private: SystemClass *_class; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ui/ui_button.cpp b/engines/wintermute/ui/ui_button.cpp index 9db1f4f4b4..b2e6c3953b 100644 --- a/engines/wintermute/ui/ui_button.cpp +++ b/engines/wintermute/ui/ui_button.cpp @@ -1206,4 +1206,4 @@ bool UIButton::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ui/ui_button.h b/engines/wintermute/ui/ui_button.h index 5db9356ef9..b5002f3166 100644 --- a/engines/wintermute/ui/ui_button.h +++ b/engines/wintermute/ui/ui_button.h @@ -75,6 +75,6 @@ public: virtual const char *scToString() override; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ui/ui_edit.cpp b/engines/wintermute/ui/ui_edit.cpp index 91ca7326cb..caed157e0b 100644 --- a/engines/wintermute/ui/ui_edit.cpp +++ b/engines/wintermute/ui/ui_edit.cpp @@ -949,4 +949,4 @@ bool UIEdit::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ui/ui_edit.h b/engines/wintermute/ui/ui_edit.h index ac626f0f06..a057be9ead 100644 --- a/engines/wintermute/ui/ui_edit.h +++ b/engines/wintermute/ui/ui_edit.h @@ -67,6 +67,6 @@ public: virtual const char *scToString() override; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ui/ui_entity.cpp b/engines/wintermute/ui/ui_entity.cpp index 1872400cdd..6d4cfdb7eb 100644 --- a/engines/wintermute/ui/ui_entity.cpp +++ b/engines/wintermute/ui/ui_entity.cpp @@ -363,4 +363,4 @@ bool UIEntity::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ui/ui_entity.h b/engines/wintermute/ui/ui_entity.h index 3bd3ec9888..1b6e8a10d6 100644 --- a/engines/wintermute/ui/ui_entity.h +++ b/engines/wintermute/ui/ui_entity.h @@ -54,6 +54,6 @@ public: virtual const char *scToString(); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ui/ui_object.cpp b/engines/wintermute/ui/ui_object.cpp index 07efc5e4cb..c32ae75c20 100644 --- a/engines/wintermute/ui/ui_object.cpp +++ b/engines/wintermute/ui/ui_object.cpp @@ -648,4 +648,4 @@ bool UIObject::saveAsText(BaseDynamicBuffer *buffer, int indent) { return STATUS_FAILED; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ui/ui_object.h b/engines/wintermute/ui/ui_object.h index 935c27613c..5d9508c2cf 100644 --- a/engines/wintermute/ui/ui_object.h +++ b/engines/wintermute/ui/ui_object.h @@ -80,6 +80,6 @@ public: virtual const char *scToString() override; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ui/ui_text.cpp b/engines/wintermute/ui/ui_text.cpp index 98d70b770e..5dc25f5852 100644 --- a/engines/wintermute/ui/ui_text.cpp +++ b/engines/wintermute/ui/ui_text.cpp @@ -519,4 +519,4 @@ bool UIText::sizeToFit() { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ui/ui_text.h b/engines/wintermute/ui/ui_text.h index be074755ba..29ed62a5ef 100644 --- a/engines/wintermute/ui/ui_text.h +++ b/engines/wintermute/ui/ui_text.h @@ -55,6 +55,6 @@ public: virtual const char *scToString() override; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ui/ui_tiled_image.cpp b/engines/wintermute/ui/ui_tiled_image.cpp index abccdd6c39..de4b86a6dd 100644 --- a/engines/wintermute/ui/ui_tiled_image.cpp +++ b/engines/wintermute/ui/ui_tiled_image.cpp @@ -388,4 +388,4 @@ bool UITiledImage::persist(BasePersistenceManager *persistMgr) { return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ui/ui_tiled_image.h b/engines/wintermute/ui/ui_tiled_image.h index a6cd22d53d..39bc6495a9 100644 --- a/engines/wintermute/ui/ui_tiled_image.h +++ b/engines/wintermute/ui/ui_tiled_image.h @@ -59,6 +59,6 @@ private: Rect32 _downRight; }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/ui/ui_window.cpp b/engines/wintermute/ui/ui_window.cpp index 2ce9f68605..9066ee9f5b 100644 --- a/engines/wintermute/ui/ui_window.cpp +++ b/engines/wintermute/ui/ui_window.cpp @@ -1442,4 +1442,4 @@ bool UIWindow::getWindowObjects(BaseArray<UIObject *> &objects, bool interactive return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/ui/ui_window.h b/engines/wintermute/ui/ui_window.h index 70799cea25..8a726fdff8 100644 --- a/engines/wintermute/ui/ui_window.h +++ b/engines/wintermute/ui/ui_window.h @@ -89,6 +89,6 @@ public: virtual const char *scToString(); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/utils/crc.cpp b/engines/wintermute/utils/crc.cpp index e7ec45511b..a9781500fa 100644 --- a/engines/wintermute/utils/crc.cpp +++ b/engines/wintermute/utils/crc.cpp @@ -234,4 +234,4 @@ crc crc_finalize(crc remainder) { return (REFLECT_REMAINDER(remainder) ^ FINAL_XOR_VALUE); } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/utils/path_util.cpp b/engines/wintermute/utils/path_util.cpp index 298f0c268f..ee8b298562 100644 --- a/engines/wintermute/utils/path_util.cpp +++ b/engines/wintermute/utils/path_util.cpp @@ -98,4 +98,4 @@ AnsiString PathUtil::getExtension(const AnsiString &path) { return Common::lastPathComponent(path, '.'); } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/utils/path_util.h b/engines/wintermute/utils/path_util.h index 7358c2aba0..2c7dfa99d1 100644 --- a/engines/wintermute/utils/path_util.h +++ b/engines/wintermute/utils/path_util.h @@ -44,6 +44,6 @@ public: static AnsiString getExtension(const AnsiString &path); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/utils/string_util.cpp b/engines/wintermute/utils/string_util.cpp index 9fffad85cd..23abb5d579 100644 --- a/engines/wintermute/utils/string_util.cpp +++ b/engines/wintermute/utils/string_util.cpp @@ -231,4 +231,4 @@ AnsiString StringUtil::toString(int val) { } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/utils/string_util.h b/engines/wintermute/utils/string_util.h index e419e2bca8..3ae5e47493 100644 --- a/engines/wintermute/utils/string_util.h +++ b/engines/wintermute/utils/string_util.h @@ -51,6 +51,6 @@ public: static AnsiString toString(int val); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/utils/utils.cpp b/engines/wintermute/utils/utils.cpp index 6e0d69edbe..8fa6313ba6 100644 --- a/engines/wintermute/utils/utils.cpp +++ b/engines/wintermute/utils/utils.cpp @@ -258,4 +258,4 @@ float BaseUtils::Hue2RGB(float v1, float v2, float vH) { return (v1); } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/utils/utils.h b/engines/wintermute/utils/utils.h index d6a603ec72..6c804ff01e 100644 --- a/engines/wintermute/utils/utils.h +++ b/engines/wintermute/utils/utils.h @@ -59,6 +59,6 @@ private: static float Hue2RGB(float v1, float v2, float vH); }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/video/video_player.cpp b/engines/wintermute/video/video_player.cpp index 42857b5c1b..f18311c3e1 100644 --- a/engines/wintermute/video/video_player.cpp +++ b/engines/wintermute/video/video_player.cpp @@ -106,4 +106,4 @@ bool VideoPlayer::loadSubtitles(const char *filename, const char *subtitleFile) return STATUS_OK; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/video/video_player.h b/engines/wintermute/video/video_player.h index 033ab50dfa..51c6bf41d3 100644 --- a/engines/wintermute/video/video_player.h +++ b/engines/wintermute/video/video_player.h @@ -85,6 +85,6 @@ public: BaseArray<CVidSubtitle *, CVidSubtitle *> _subtitles;*/ }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/video/video_theora_player.cpp b/engines/wintermute/video/video_theora_player.cpp index 8f9db8392f..f3317684b5 100644 --- a/engines/wintermute/video/video_theora_player.cpp +++ b/engines/wintermute/video/video_theora_player.cpp @@ -163,14 +163,14 @@ bool VideoTheoraPlayer::resetStream() { if (!_file) { return STATUS_FAILED; } - + #if defined (USE_THEORADEC) _theoraDecoder = new Video::TheoraDecoder(); #else return STATUS_FAILED; #endif _theoraDecoder->loadStream(_file); - + if (!_theoraDecoder->isVideoLoaded()) { return STATUS_FAILED; } @@ -369,14 +369,14 @@ void VideoTheoraPlayer::writeAlpha() { if (_alphaImage && _surface.w == _alphaImage->getSurface()->w && _surface.h == _alphaImage->getSurface()->h) { assert(_alphaImage->getSurface()->format.bytesPerPixel == 4); assert(_surface.format.bytesPerPixel == 4); - const byte *alphaData = (const byte *)_alphaImage->getSurface()->getBasePtr(0, 0); + const byte *alphaData = (const byte *)_alphaImage->getSurface()->getPixels(); #ifdef SCUMM_LITTLE_ENDIAN int alphaPlace = (_alphaImage->getSurface()->format.aShift / 8); #else int alphaPlace = 3 - (_alphaImage->getSurface()->format.aShift / 8); #endif alphaData += alphaPlace; - byte *imgData = (byte *)_surface.getBasePtr(0, 0); + byte *imgData = (byte *)_surface.getPixels(); #ifdef SCUMM_LITTLE_ENDIAN imgData += (_surface.format.aShift / 8); #else @@ -417,7 +417,7 @@ bool VideoTheoraPlayer::display(uint32 alpha) { bool VideoTheoraPlayer::setAlphaImage(const Common::String &filename) { delete _alphaImage; _alphaImage = new BaseImage(); - if (!_alphaImage || DID_FAIL(_alphaImage->loadFile(filename))) { + if (filename == "" || !_alphaImage || DID_FAIL(_alphaImage->loadFile(filename))) { delete _alphaImage; _alphaImage = nullptr; _alphaFilename = ""; @@ -498,7 +498,7 @@ bool VideoTheoraPlayer::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_alphaFilename)); persistMgr->transfer(TMEMBER(_posX)); persistMgr->transfer(TMEMBER(_posY)); - persistMgr->transfer(TMEMBER(_playZoom)); + persistMgr->transferFloat(TMEMBER(_playZoom)); persistMgr->transfer(TMEMBER_INT(_playbackType)); persistMgr->transfer(TMEMBER(_looping)); persistMgr->transfer(TMEMBER(_volume)); @@ -529,4 +529,4 @@ BaseSurface *VideoTheoraPlayer::getTexture() const { return _texture; } -} // end of namespace Wintermute +} // End of namespace Wintermute diff --git a/engines/wintermute/video/video_theora_player.h b/engines/wintermute/video/video_theora_player.h index 364509a080..ddeba48bbc 100644 --- a/engines/wintermute/video/video_theora_player.h +++ b/engines/wintermute/video/video_theora_player.h @@ -101,7 +101,7 @@ public: // video properties int32 _posX; int32 _posY; - + bool _dontDropFrames; private: int32 _state; @@ -142,6 +142,6 @@ private: }; -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp index 92381742de..a878944661 100644 --- a/engines/wintermute/wintermute.cpp +++ b/engines/wintermute/wintermute.cpp @@ -26,7 +26,6 @@ #include "common/debug.h" #include "common/debug-channels.h" #include "common/error.h" -#include "common/EventRecorder.h" #include "common/file.h" #include "common/fs.h" #include "common/tokenizer.h" @@ -134,7 +133,7 @@ Common::Error WintermuteEngine::run() { } int WintermuteEngine::init() { - BaseEngine::createInstance(_targetName, _gameDescription->language); + BaseEngine::createInstance(_targetName, _gameDescription->gameid, _gameDescription->language); _game = new AdGame(_targetName); if (!_game) { return 1; @@ -148,7 +147,7 @@ int WintermuteEngine::init() { _game->initialize1(); // set gameId, for savegame-naming: - _game->setGameId(_targetName); + _game->setGameTargetName(_targetName); if (DID_FAIL(_game->loadSettings("startup.settings"))) { _game->LOG(0, "Error loading game settings."); @@ -251,6 +250,9 @@ int WintermuteEngine::messageLoop() { } prevTime = time; } + if (shouldQuit()) { + break; + } if (_game && _game->_quitting) { break; } @@ -292,6 +294,7 @@ bool WintermuteEngine::getGameInfo(const Common::FSList &fslist, Common::String Common::SeekableReadStream *stream = nullptr; // Quick-fix, instead of possibly breaking the persistence-system, let's just roll with it BaseFileManager *fileMan = new BaseFileManager(Common::UNK_LANG, true); + fileMan->registerPackages(fslist); stream = fileMan->openFile("startup.settings", false, false); // The process is as follows: Check the "GAME=" tag in startup.settings, to decide where the diff --git a/engines/wintermute/wintypes.h b/engines/wintermute/wintypes.h index c7723808ea..1288ac1a65 100644 --- a/engines/wintermute/wintypes.h +++ b/engines/wintermute/wintypes.h @@ -48,6 +48,6 @@ namespace Wintermute { #define MAX_PATH_LENGTH 512 -} // end of namespace Wintermute +} // End of namespace Wintermute #endif diff --git a/graphics/VectorRenderer.h b/graphics/VectorRenderer.h index 0467cac946..5d6369c08f 100644 --- a/graphics/VectorRenderer.h +++ b/graphics/VectorRenderer.h @@ -278,7 +278,7 @@ public: * Clears the active surface. */ virtual void clearSurface() { - byte *src = (byte *)_activeSurface->pixels; + byte *src = (byte *)_activeSurface->getPixels(); memset(src, 0, _activeSurface->pitch * _activeSurface->h); } diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp index 6a3ee306a5..e4843ba78b 100644 --- a/graphics/VectorRendererSpec.cpp +++ b/graphics/VectorRendererSpec.cpp @@ -277,16 +277,22 @@ void colorFill(PixelType *first, PixelType *last, PixelType color) { VectorRenderer *createRenderer(int mode) { #ifdef DISABLE_FANCY_THEMES - assert(mode == GUI::ThemeEngine::kGfxStandard16bit); + assert(mode == GUI::ThemeEngine::kGfxStandard); #endif PixelFormat format = g_system->getOverlayFormat(); switch (mode) { - case GUI::ThemeEngine::kGfxStandard16bit: - return new VectorRendererSpec<OverlayColor>(format); + case GUI::ThemeEngine::kGfxStandard: + if (g_system->getOverlayFormat().bytesPerPixel == 4) + return new VectorRendererSpec<uint32>(format); + else if (g_system->getOverlayFormat().bytesPerPixel == 2) + return new VectorRendererSpec<uint16>(format); #ifndef DISABLE_FANCY_THEMES - case GUI::ThemeEngine::kGfxAntialias16bit: - return new VectorRendererAA<OverlayColor>(format); + case GUI::ThemeEngine::kGfxAntialias: + if (g_system->getOverlayFormat().bytesPerPixel == 4) + return new VectorRendererAA<uint32>(format); + else if (g_system->getOverlayFormat().bytesPerPixel == 2) + return new VectorRendererAA<uint16>(format); #endif default: break; @@ -317,9 +323,15 @@ setGradientColors(uint8 r1, uint8 g1, uint8 b1, uint8 r2, uint8 g2, uint8 b2) { _gradientEnd = _format.RGBToColor(r2, g2, b2); _gradientStart = _format.RGBToColor(r1, g1, b1); - _gradientBytes[0] = (_gradientEnd & _redMask) - (_gradientStart & _redMask); - _gradientBytes[1] = (_gradientEnd & _greenMask) - (_gradientStart & _greenMask); - _gradientBytes[2] = (_gradientEnd & _blueMask) - (_gradientStart & _blueMask); + if (sizeof(PixelType) == 4) { + _gradientBytes[0] = ((_gradientEnd & _redMask) >> _format.rShift) - ((_gradientStart & _redMask) >> _format.rShift); + _gradientBytes[1] = ((_gradientEnd & _greenMask) >> _format.gShift) - ((_gradientStart & _greenMask) >> _format.gShift); + _gradientBytes[2] = ((_gradientEnd & _blueMask) >> _format.bShift) - ((_gradientStart & _blueMask) >> _format.bShift); + } else { + _gradientBytes[0] = (_gradientEnd & _redMask) - (_gradientStart & _redMask); + _gradientBytes[1] = (_gradientEnd & _greenMask) - (_gradientStart & _greenMask); + _gradientBytes[2] = (_gradientEnd & _blueMask) - (_gradientStart & _blueMask); + } } template<typename PixelType> @@ -328,9 +340,15 @@ calcGradient(uint32 pos, uint32 max) { PixelType output = 0; pos = (MIN(pos * Base::_gradientFactor, max) << 12) / max; - output |= ((_gradientStart & _redMask) + ((_gradientBytes[0] * pos) >> 12)) & _redMask; - output |= ((_gradientStart & _greenMask) + ((_gradientBytes[1] * pos) >> 12)) & _greenMask; - output |= ((_gradientStart & _blueMask) + ((_gradientBytes[2] * pos) >> 12)) & _blueMask; + if (sizeof(PixelType) == 4) { + output |= ((_gradientStart & _redMask) + (((_gradientBytes[0] * pos) >> 12) << _format.rShift)) & _redMask; + output |= ((_gradientStart & _greenMask) + (((_gradientBytes[1] * pos) >> 12) << _format.gShift)) & _greenMask; + output |= ((_gradientStart & _blueMask) + (((_gradientBytes[2] * pos) >> 12) << _format.bShift)) & _blueMask; + } else { + output |= ((_gradientStart & _redMask) + ((_gradientBytes[0] * pos) >> 12)) & _redMask; + output |= ((_gradientStart & _greenMask) + ((_gradientBytes[1] * pos) >> 12)) & _greenMask; + output |= ((_gradientStart & _blueMask) + ((_gradientBytes[2] * pos) >> 12)) & _blueMask; + } output |= _alphaMask; return output; @@ -397,7 +415,7 @@ gradientFill(PixelType *ptr, int width, int x, int y) { template<typename PixelType> void VectorRendererSpec<PixelType>:: fillSurface() { - byte *ptr = (byte *)_activeSurface->getBasePtr(0, 0); + byte *ptr = (byte *)_activeSurface->getPixels(); int h = _activeSurface->h; int pitch = _activeSurface->pitch; @@ -453,7 +471,7 @@ template<typename PixelType> void VectorRendererSpec<PixelType>:: blitSubSurface(const Graphics::Surface *source, const Common::Rect &r) { byte *dst_ptr = (byte *)_activeSurface->getBasePtr(r.left, r.top); - const byte *src_ptr = (const byte *)source->getBasePtr(0, 0); + const byte *src_ptr = (const byte *)source->getPixels(); const int dst_pitch = _activeSurface->pitch; const int src_pitch = source->pitch; @@ -481,7 +499,7 @@ blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r) { y = y + (r.height() >> 1) - (source->h >> 1); PixelType *dst_ptr = (PixelType *)_activeSurface->getBasePtr(x, y); - const PixelType *src_ptr = (const PixelType *)source->getBasePtr(0, 0); + const PixelType *src_ptr = (const PixelType *)source->getPixels(); int dst_pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; int src_pitch = source->pitch / source->format.bytesPerPixel; @@ -508,7 +526,7 @@ template<typename PixelType> void VectorRendererSpec<PixelType>:: applyScreenShading(GUI::ThemeEngine::ShadingStyle shadingStyle) { int pixels = _activeSurface->w * _activeSurface->h; - PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(0, 0); + PixelType *ptr = (PixelType *)_activeSurface->getPixels(); uint8 r, g, b; uint lum; @@ -537,20 +555,41 @@ applyScreenShading(GUI::ThemeEngine::ShadingStyle shadingStyle) { template<typename PixelType> inline void VectorRendererSpec<PixelType>:: blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha) { - int idst = *ptr; - int isrc = color; - - *ptr = (PixelType)( - (_redMask & ((idst & _redMask) + - ((int)(((int)(isrc & _redMask) - - (int)(idst & _redMask)) * alpha) >> 8))) | - (_greenMask & ((idst & _greenMask) + - ((int)(((int)(isrc & _greenMask) - - (int)(idst & _greenMask)) * alpha) >> 8))) | - (_blueMask & ((idst & _blueMask) + - ((int)(((int)(isrc & _blueMask) - - (int)(idst & _blueMask)) * alpha) >> 8))) | - (idst & _alphaMask)); + if (sizeof(PixelType) == 4) { + const byte sR = (color & _redMask) >> _format.rShift; + const byte sG = (color & _greenMask) >> _format.gShift; + const byte sB = (color & _blueMask) >> _format.bShift; + + byte dR = (*ptr & _redMask) >> _format.rShift; + byte dG = (*ptr & _greenMask) >> _format.gShift; + byte dB = (*ptr & _blueMask) >> _format.bShift; + + dR += ((sR - dR) * alpha) >> 8; + dG += ((sG - dG) * alpha) >> 8; + dB += ((sB - dB) * alpha) >> 8; + + *ptr = ((dR << _format.rShift) & _redMask) + | ((dG << _format.gShift) & _greenMask) + | ((dB << _format.bShift) & _blueMask) + | (*ptr & _alphaMask); + } else if (sizeof(PixelType) == 2) { + int idst = *ptr; + int isrc = color; + + *ptr = (PixelType)( + (_redMask & ((idst & _redMask) + + ((int)(((int)(isrc & _redMask) - + (int)(idst & _redMask)) * alpha) >> 8))) | + (_greenMask & ((idst & _greenMask) + + ((int)(((int)(isrc & _greenMask) - + (int)(idst & _greenMask)) * alpha) >> 8))) | + (_blueMask & ((idst & _blueMask) + + ((int)(((int)(isrc & _blueMask) - + (int)(idst & _blueMask)) * alpha) >> 8))) | + (idst & _alphaMask)); + } else { + error("Unsupported BPP format: %u", (uint)sizeof(PixelType)); + } } template<typename PixelType> diff --git a/graphics/cursorman.cpp b/graphics/cursorman.cpp index c818101645..6825767dfd 100644 --- a/graphics/cursorman.cpp +++ b/graphics/cursorman.cpp @@ -48,6 +48,9 @@ bool CursorManager::isVisible() { bool CursorManager::showMouse(bool visible) { if (_cursorStack.empty()) return false; + if (_locked) { + return false; + } _cursorStack.top()->_visible = visible; @@ -225,6 +228,10 @@ void CursorManager::replaceCursorPalette(const byte *colors, uint start, uint nu } } +void CursorManager::lock(bool locked) { + _locked = locked; +} + CursorManager::Cursor::Cursor(const void *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { #ifdef USE_RGB_COLOR if (!format) diff --git a/graphics/cursorman.h b/graphics/cursorman.h index 66e8d1ba56..b4d8ad94ce 100644 --- a/graphics/cursorman.h +++ b/graphics/cursorman.h @@ -160,12 +160,15 @@ public: */ void replaceCursorPalette(const byte *colors, uint start, uint num); + void lock(bool locked); private: friend class Common::Singleton<SingletonBaseType>; // Even though this is basically the default constructor we implement it // ourselves, so it is private and thus there is no way to create this class // except from the Singleton code. - CursorManager() {} + CursorManager() { + _locked = false; + } ~CursorManager(); struct Cursor { @@ -198,6 +201,7 @@ private: }; Common::Stack<Cursor *> _cursorStack; Common::Stack<Palette *> _cursorPaletteStack; + bool _locked; }; } // End of namespace Graphics diff --git a/graphics/decoders/bmp.cpp b/graphics/decoders/bmp.cpp index bcfd0abbda..2eabbb7631 100644 --- a/graphics/decoders/bmp.cpp +++ b/graphics/decoders/bmp.cpp @@ -130,14 +130,14 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { const int extraDataLength = (srcPitch % 4) ? 4 - (srcPitch % 4) : 0; if (bitsPerPixel == 8) { - byte *dst = (byte *)_surface->pixels; + byte *dst = (byte *)_surface->getPixels(); for (int32 i = 0; i < height; i++) { stream.read(dst + (height - i - 1) * width, width); stream.skip(extraDataLength); } } else if (bitsPerPixel == 24) { - byte *dst = (byte *)_surface->pixels + (height - 1) * _surface->pitch; + byte *dst = (byte *)_surface->getBasePtr(0, height - 1); for (int32 i = 0; i < height; i++) { for (uint32 j = 0; j < width; j++) { @@ -154,7 +154,7 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { dst -= _surface->pitch * 2; } } else { // 32 bpp - byte *dst = (byte *)_surface->pixels + (height - 1) * _surface->pitch; + byte *dst = (byte *)_surface->getBasePtr(0, height - 1); for (int32 i = 0; i < height; i++) { for (uint32 j = 0; j < width; j++) { diff --git a/graphics/decoders/iff.cpp b/graphics/decoders/iff.cpp index 50c7b4f7de..7b37969fc1 100644 --- a/graphics/decoders/iff.cpp +++ b/graphics/decoders/iff.cpp @@ -170,7 +170,7 @@ void IFFDecoder::loadBitmap(Common::SeekableReadStream &stream) { if (_type == TYPE_ILBM) { uint32 scanlinePitch = ((_header.width + 15) >> 4) << 1; byte *scanlines = new byte[scanlinePitch * _header.numPlanes]; - byte *data = (byte *)_surface->pixels; + byte *data = (byte *)_surface->getPixels(); for (uint16 i = 0; i < _header.height; ++i) { byte *scanline = scanlines; @@ -194,7 +194,7 @@ void IFFDecoder::loadBitmap(Common::SeekableReadStream &stream) { delete[] scanlines; } else if (_type == TYPE_PBM) { - byte *data = (byte *)_surface->pixels; + byte *data = (byte *)_surface->getPixels(); uint32 outSize = _header.width * _header.height; if (_header.compression) { diff --git a/graphics/decoders/jpeg.cpp b/graphics/decoders/jpeg.cpp index 75fdcd6e5a..ff018c799a 100644 --- a/graphics/decoders/jpeg.cpp +++ b/graphics/decoders/jpeg.cpp @@ -81,7 +81,7 @@ const Surface *JPEGDecoder::getSurface() const { const Graphics::Surface *uComponent = getComponent(2); const Graphics::Surface *vComponent = getComponent(3); - YUVToRGBMan.convert444(_rgbSurface, Graphics::YUVToRGBManager::kScaleFull, (byte *)yComponent->pixels, (byte *)uComponent->pixels, (byte *)vComponent->pixels, yComponent->w, yComponent->h, yComponent->pitch, uComponent->pitch); + YUVToRGBMan.convert444(_rgbSurface, Graphics::YUVToRGBManager::kScaleFull, (const byte *)yComponent->getPixels(), (const byte *)uComponent->getPixels(), (const byte *)vComponent->getPixels(), yComponent->w, yComponent->h, yComponent->pitch, uComponent->pitch); return _rgbSurface; } diff --git a/graphics/decoders/pcx.cpp b/graphics/decoders/pcx.cpp index 1250398c73..eb9b4c997d 100644 --- a/graphics/decoders/pcx.cpp +++ b/graphics/decoders/pcx.cpp @@ -117,7 +117,7 @@ bool PCXDecoder::loadStream(Common::SeekableReadStream &stream) { if (nPlanes == 3 && bitsPerPixel == 8) { // 24bpp Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); _surface->create(width, height, format); - dst = (byte *)_surface->pixels; + dst = (byte *)_surface->getPixels(); _paletteColorCount = 0; for (y = 0; y < height; y++) { @@ -135,7 +135,7 @@ bool PCXDecoder::loadStream(Common::SeekableReadStream &stream) { } } else if (nPlanes == 1 && bitsPerPixel == 8) { // 8bpp indexed _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); - dst = (byte *)_surface->pixels; + dst = (byte *)_surface->getPixels(); _paletteColorCount = 16; for (y = 0; y < height; y++, dst += _surface->pitch) { @@ -163,7 +163,7 @@ bool PCXDecoder::loadStream(Common::SeekableReadStream &stream) { } } else if ((nPlanes == 2 || nPlanes == 3 || nPlanes == 4) && bitsPerPixel == 1) { // planar, 4, 8 or 16 colors _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); - dst = (byte *)_surface->pixels; + dst = (byte *)_surface->getPixels(); _paletteColorCount = 16; for (y = 0; y < height; y++, dst += _surface->pitch) { diff --git a/graphics/decoders/pict.cpp b/graphics/decoders/pict.cpp index b1d408ebc3..f3e17b33e2 100644 --- a/graphics/decoders/pict.cpp +++ b/graphics/decoders/pict.cpp @@ -364,7 +364,7 @@ void PICTDecoder::unpackBitsRect(Common::SeekableReadStream &stream, bool withPa case 1: // Just copy to the image _outputSurface->create(width, height, PixelFormat::createFormatCLUT8()); - memcpy(_outputSurface->pixels, buffer, _outputSurface->w * _outputSurface->h); + memcpy(_outputSurface->getPixels(), buffer, _outputSurface->w * _outputSurface->h); break; case 2: // We have a 16-bit surface diff --git a/graphics/decoders/png.cpp b/graphics/decoders/png.cpp index 11e26162eb..505475213f 100644 --- a/graphics/decoders/png.cpp +++ b/graphics/decoders/png.cpp @@ -164,7 +164,7 @@ bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { png_set_packing(pngPtr); } else { _outputSurface->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); - if (!_outputSurface->pixels) { + if (!_outputSurface->getPixels()) { error("Could not allocate memory for output image."); } if (bitDepth == 16) diff --git a/graphics/decoders/tga.cpp b/graphics/decoders/tga.cpp index c3b9d84055..a9f136d238 100644 --- a/graphics/decoders/tga.cpp +++ b/graphics/decoders/tga.cpp @@ -272,7 +272,7 @@ bool TGADecoder::readData(Common::SeekableReadStream &tga, byte imageType, byte } else if (imageType == TYPE_BW) { _surface.create(_surface.w, _surface.h, _format); - byte *data = (byte *)_surface.pixels; + byte *data = (byte *)_surface.getPixels(); uint32 count = _surface.w * _surface.h; while (count-- > 0) { @@ -318,7 +318,7 @@ bool TGADecoder::readDataRLE(Common::SeekableReadStream &tga, byte imageType, by if (imageType == TYPE_RLE_TRUECOLOR || imageType == TYPE_RLE_BW || imageType == TYPE_RLE_CMAP) { _surface.create(_surface.w, _surface.h, _format); uint32 count = _surface.w * _surface.h; - byte *data = (byte *)_surface.pixels; + byte *data = (byte *)_surface.getPixels(); while (count > 0) { uint32 header = tga.readByte(); diff --git a/graphics/fonts/bdf.cpp b/graphics/fonts/bdf.cpp index 6d4befa37c..e523a36ad5 100644 --- a/graphics/fonts/bdf.cpp +++ b/graphics/fonts/bdf.cpp @@ -102,7 +102,7 @@ void BdfFont::drawChar(Surface *dst, byte chr, const int tx, const int ty, const // equal to 50 and the decision of the theme designer? // asserting _data.maxAdvance <= 50: let the theme designer decide what looks best assert(_data.maxAdvance <= 50); - assert(dst->format.bytesPerPixel == 1 || dst->format.bytesPerPixel == 2); + assert(dst->format.bytesPerPixel == 1 || dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4); const int idx = mapToIndex(chr); if (idx < 0) @@ -165,6 +165,8 @@ void BdfFont::drawChar(Surface *dst, byte chr, const int tx, const int ty, const drawCharIntern<byte>(ptr, dst->pitch, src, height, originalWidth, xStart, xEnd, color); else if (dst->format.bytesPerPixel == 2) drawCharIntern<uint16>(ptr, dst->pitch, src, height, originalWidth, xStart, xEnd, color); + else if (dst->format.bytesPerPixel == 4) + drawCharIntern<uint32>(ptr, dst->pitch, src, height, originalWidth, xStart, xEnd, color); } namespace { diff --git a/graphics/fonts/ttf.cpp b/graphics/fonts/ttf.cpp index 2b1dca1eae..b9e9610d77 100644 --- a/graphics/fonts/ttf.cpp +++ b/graphics/fonts/ttf.cpp @@ -322,7 +322,7 @@ void TTFFont::drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const int w = glyph.image.w; int h = glyph.image.h; - const uint8 *srcPos = (const uint8 *)glyph.image.getBasePtr(0, 0); + const uint8 *srcPos = (const uint8 *)glyph.image.getPixels(); // Make sure we are not drawing outside the screen bounds if (x < 0) { @@ -422,7 +422,7 @@ bool TTFFont::cacheGlyph(Glyph &glyph, FT_UInt &slot, uint chr) { srcPitch = -srcPitch; } - uint8 *dst = (uint8 *)glyph.image.getBasePtr(0, 0); + uint8 *dst = (uint8 *)glyph.image.getPixels(); memset(dst, 0, glyph.image.h * glyph.image.pitch); switch (bitmap.pixel_mode) { diff --git a/graphics/scaler/thumbnail_intern.cpp b/graphics/scaler/thumbnail_intern.cpp index 88f3cc2077..c30fc3b6fd 100644 --- a/graphics/scaler/thumbnail_intern.cpp +++ b/graphics/scaler/thumbnail_intern.cpp @@ -42,8 +42,10 @@ uint16 quadBlockInterpolate(const uint8 *src, uint32 srcPitch) { template<int bitFormat> void createThumbnail_2(const uint8 *src, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { - assert(width % 2 == 0); - assert(height % 2 == 0); + // Make sure the width and height is a multiple of 2. + width &= ~1; + height &= ~1; + for (int y = 0; y < height; y += 2) { for (int x = 0; x < width; x += 2, dstPtr += 2) { *((uint16 *)dstPtr) = quadBlockInterpolate<bitFormat>(src + 2 * x, srcPitch); @@ -55,8 +57,10 @@ void createThumbnail_2(const uint8 *src, uint32 srcPitch, uint8 *dstPtr, uint32 template<int bitFormat> void createThumbnail_4(const uint8 *src, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { - assert(width % 4 == 0); - assert(height % 4 == 0); + // Make sure the width and height is a multiple of 4 + width &= ~3; + height &= ~3; + for (int y = 0; y < height; y += 4) { for (int x = 0; x < width; x += 4, dstPtr += 2) { uint16 upleft = quadBlockInterpolate<bitFormat>(src + 2 * x, srcPitch); @@ -71,17 +75,87 @@ void createThumbnail_4(const uint8 *src, uint32 srcPitch, uint8 *dstPtr, uint32 } } -static void createThumbnail(const uint8 *src, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { - // only 1/2 and 1/4 downscale supported - if (width != 320 && width != 640) - return; +static void scaleThumbnail(Graphics::Surface &in, Graphics::Surface &out) { + while (in.w / out.w >= 4 || in.h / out.h >= 4) { + createThumbnail_4<565>((const uint8 *)in.getPixels(), in.pitch, (uint8 *)in.getPixels(), in.pitch, in.w, in.h); + in.w /= 4; + in.h /= 4; + } + + while (in.w / out.w >= 2 || in.h / out.h >= 2) { + createThumbnail_2<565>((const uint8 *)in.getPixels(), in.pitch, (uint8 *)in.getPixels(), in.pitch, in.w, in.h); + in.w /= 2; + in.h /= 2; + } + + if ((in.w == out.w && in.h < out.h) || (in.w < out.w && in.h == out.h)) { + // In this case we simply center the input surface in the output + uint8 *dst = (uint8 *)out.getBasePtr((out.w - in.w) / 2, (out.h - in.h) / 2); + const uint8 *src = (const uint8 *)in.getPixels(); - int downScaleMode = (width == 320) ? 2 : 4; + for (int y = 0; y < in.h; ++y) { + memcpy(dst, src, in.w * in.format.bytesPerPixel); + src += in.pitch; + dst += out.pitch; + } + } else { + // Assure the aspect of the scaled image still matches the original. + int targetWidth = out.w, targetHeight = out.h; - if (downScaleMode == 2) { - createThumbnail_2<565>(src, srcPitch, dstPtr, dstPitch, width, height); - } else if (downScaleMode == 4) { - createThumbnail_4<565>(src, srcPitch, dstPtr, dstPitch, width, height); + const float inputAspect = (float)in.w / in.h; + const float outputAspect = (float)out.w / out.h; + + if (inputAspect > outputAspect) { + targetHeight = int(targetWidth / inputAspect); + } else if (inputAspect < outputAspect) { + targetWidth = int(targetHeight * inputAspect); + } + + // Make sure we are still in the bounds of the output + assert(targetWidth <= out.w); + assert(targetHeight <= out.h); + + // Center the image on the output surface + byte *dst = (byte *)out.getBasePtr((out.w - targetWidth) / 2, (out.h - targetHeight) / 2); + const uint dstLineIncrease = out.pitch - targetWidth * out.format.bytesPerPixel; + + const float scaleFactorX = (float)targetWidth / in.w; + const float scaleFactorY = (float)targetHeight / in.h; + + for (int y = 0; y < targetHeight; ++y) { + const float yFrac = (y / scaleFactorY); + const int y1 = (int)yFrac; + const int y2 = (y1 + 1 < in.h) ? (y1 + 1) : (in.h - 1); + + for (int x = 0; x < targetWidth; ++x) { + const float xFrac = (x / scaleFactorX); + const int x1 = (int)xFrac; + const int x2 = (x1 + 1 < in.w) ? (x1 + 1) : (in.w - 1); + + // Look up colors at the points + uint8 p1R, p1G, p1B; + Graphics::colorToRGB<Graphics::ColorMasks<565> >(READ_UINT16(in.getBasePtr(x1, y1)), p1R, p1G, p1B); + uint8 p2R, p2G, p2B; + Graphics::colorToRGB<Graphics::ColorMasks<565> >(READ_UINT16(in.getBasePtr(x2, y1)), p2R, p2G, p2B); + uint8 p3R, p3G, p3B; + Graphics::colorToRGB<Graphics::ColorMasks<565> >(READ_UINT16(in.getBasePtr(x1, y2)), p3R, p3G, p3B); + uint8 p4R, p4G, p4B; + Graphics::colorToRGB<Graphics::ColorMasks<565> >(READ_UINT16(in.getBasePtr(x2, y2)), p4R, p4G, p4B); + + const float xDiff = xFrac - x1; + const float yDiff = yFrac - y1; + + uint8 pR = (uint8)((1 - yDiff) * ((1 - xDiff) * p1R + xDiff * p2R) + yDiff * ((1 - xDiff) * p3R + xDiff * p4R)); + uint8 pG = (uint8)((1 - yDiff) * ((1 - xDiff) * p1G + xDiff * p2G) + yDiff * ((1 - xDiff) * p3G + xDiff * p4G)); + uint8 pB = (uint8)((1 - yDiff) * ((1 - xDiff) * p1B + xDiff * p2B) + yDiff * ((1 - xDiff) * p3B + xDiff * p4B)); + + WRITE_UINT16(dst, Graphics::RGBToColor<Graphics::ColorMasks<565> >(pR, pG, pB)); + dst += 2; + } + + // Move to the next line + dst = (byte *)dst + dstLineIncrease; + } } } @@ -90,7 +164,7 @@ static void createThumbnail(const uint8 *src, uint32 srcPitch, uint8 *dstPtr, ui * Copies the current screen contents to a new surface, using RGB565 format. * WARNING: surf->free() must be called by the user to avoid leaking. * - * @param surf the surface to store the data in it + * @param surf the surface to store the data in it */ static bool grabScreen565(Graphics::Surface *surf) { Graphics::Surface *screen = g_system->lockScreen(); @@ -98,7 +172,7 @@ static bool grabScreen565(Graphics::Surface *surf) { return false; assert(screen->format.bytesPerPixel == 1 || screen->format.bytesPerPixel == 2); - assert(screen->pixels != 0); + assert(screen->getPixels() != 0); Graphics::PixelFormat screenFormat = g_system->getScreenFormat(); @@ -116,15 +190,16 @@ static bool grabScreen565(Graphics::Surface *surf) { byte r = 0, g = 0, b = 0; if (screenFormat.bytesPerPixel == 1) { - r = palette[((uint8 *)screen->pixels)[y * screen->pitch + x] * 3]; - g = palette[((uint8 *)screen->pixels)[y * screen->pitch + x] * 3 + 1]; - b = palette[((uint8 *)screen->pixels)[y * screen->pitch + x] * 3 + 2]; + uint8 pixel = *(uint8 *)screen->getBasePtr(x, y); + r = palette[pixel * 3 + 0]; + g = palette[pixel * 3 + 1]; + b = palette[pixel * 3 + 2]; } else if (screenFormat.bytesPerPixel == 2) { uint16 col = READ_UINT16(screen->getBasePtr(x, y)); screenFormat.colorToRGB(col, r, g, b); } - ((uint16 *)surf->pixels)[y * surf->w + x] = Graphics::RGBToColor<Graphics::ColorMasks<565> >(r, g, b); + *((uint16 *)surf->getBasePtr(x, y)) = Graphics::RGBToColor<Graphics::ColorMasks<565> >(r, g, b); } } @@ -135,78 +210,20 @@ static bool grabScreen565(Graphics::Surface *surf) { } static bool createThumbnail(Graphics::Surface &out, Graphics::Surface &in) { - uint16 width = in.w; - uint16 inHeight = in.h; - - if (width < 320) { - // Special case to handle MM NES (uses a screen width of 256) - width = 320; - - // center MM NES screen - Graphics::Surface newscreen; - newscreen.create(width, in.h, in.format); - - uint8 *dst = (uint8 *)newscreen.getBasePtr((320 - in.w) / 2, 0); - const uint8 *src = (const uint8 *)in.getBasePtr(0, 0); - uint16 height = in.h; - - while (height--) { - memcpy(dst, src, in.pitch); - dst += newscreen.pitch; - src += in.pitch; - } - - in.free(); - in = newscreen; - } else if (width == 720) { - // Special case to handle Hercules mode - // - // NOTE: This code is pretty SCUMM specific. - // For other games this code might cut off - // not only the menu, but also other graphics. - width = 640; - inHeight = 400; - - // cut off menu and so on.. - Graphics::Surface newscreen; - newscreen.create(width, 400, in.format); - - uint8 *dst = (uint8 *)newscreen.getBasePtr(0, (400 - 240) / 2); - const uint8 *src = (const uint8 *)in.getBasePtr(41, 28); - - for (int y = 0; y < 240; ++y) { - memcpy(dst, src, 640 * in.format.bytesPerPixel); - dst += newscreen.pitch; - src += in.pitch; - } - - in.free(); - in = newscreen; - } else if (width == 640 && inHeight == 440) { - // Special case to handle KQ6 Windows: resize the screen to 640x480, - // adding a black band in the bottom. - inHeight = 480; - - Graphics::Surface newscreen; - newscreen.create(width, 480, in.format); - - memcpy(newscreen.getBasePtr(0, 0), in.getBasePtr(0, 0), width * 440 * in.format.bytesPerPixel); - - in.free(); - in = newscreen; + int height; + if ((in.w == 320 && in.h == 200) || (in.w == 640 && in.h == 400)) { + height = kThumbnailHeight1; + } else { + height = kThumbnailHeight2; } - uint16 newHeight = !(inHeight % 240) ? kThumbnailHeight2 : kThumbnailHeight1; - - out.create(kThumbnailWidth, newHeight, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); - createThumbnail((const uint8 *)in.pixels, width * sizeof(uint16), (uint8 *)out.pixels, out.pitch, width, inHeight); - + out.create(kThumbnailWidth, height, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); + scaleThumbnail(in, out); in.free(); - return true; } -bool createThumbnailFromScreen(Graphics::Surface* surf) { +bool createThumbnailFromScreen(Graphics::Surface *surf) { assert(surf); Graphics::Surface screen; @@ -230,9 +247,37 @@ bool createThumbnail(Graphics::Surface *surf, const uint8 *pixels, int w, int h, g = palette[pixels[y * w + x] * 3 + 1]; b = palette[pixels[y * w + x] * 3 + 2]; - ((uint16 *)screen.pixels)[y * screen.w + x] = Graphics::RGBToColor<Graphics::ColorMasks<565> >(r, g, b); + *((uint16 *)screen.getBasePtr(x, y)) = Graphics::RGBToColor<Graphics::ColorMasks<565> >(r, g, b); } } return createThumbnail(*surf, screen); } + +// this is somewhat awkward, but createScreenShot should logically be in graphics, +// but moving other functions in this file into that namespace breaks several engines +namespace Graphics { +bool createScreenShot(Graphics::Surface &surf) { + Graphics::PixelFormat screenFormat = g_system->getScreenFormat(); + //convert surface to 2 bytes pixel format to avoid problems with palette saving and loading + if ((screenFormat.bytesPerPixel == 1) || (screenFormat.bytesPerPixel == 2)) { + return grabScreen565(&surf); + } else { + Graphics::Surface *screen = g_system->lockScreen(); + if (!screen) { + return false; + } + surf.create(screen->w, screen->h, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); + for (uint y = 0; y < screen->h; ++y) { + for (uint x = 0; x < screen->w; ++x) { + byte r = 0, g = 0, b = 0, a = 0; + uint32 col = READ_UINT32(screen->getBasePtr(x, y)); + screenFormat.colorToARGB(col, a, r, g, b); + *((uint32 *)surf.getBasePtr(x, y)) = Graphics::ARGBToColor<Graphics::ColorMasks<8888> >(a, r, g, b); + } + } + g_system->unlockScreen(); + return true; + } +} +} // End of namespace Graphics diff --git a/graphics/surface.cpp b/graphics/surface.cpp index 41ae8dcebb..929157203e 100644 --- a/graphics/surface.cpp +++ b/graphics/surface.cpp @@ -82,9 +82,55 @@ void Surface::free() { format = PixelFormat(); } +void Surface::init(uint16 width, uint16 height, uint16 newPitch, void *newPixels, const PixelFormat &f) { + w = width; + h = height; + pitch = newPitch; + pixels = newPixels; + format = f; +} + void Surface::copyFrom(const Surface &surf) { create(surf.w, surf.h, surf.format); - memcpy(pixels, surf.pixels, h * pitch); + if (surf.pitch == pitch) { + memcpy(pixels, surf.pixels, h * pitch); + } else { + const byte *src = (const byte *)surf.pixels; + byte *dst = (byte *)pixels; + for (int y = h; y > 0; --y) { + memcpy(dst, src, w * format.bytesPerPixel); + src += surf.pitch; + dst += pitch; + } + } +} + +Surface Surface::getSubArea(const Common::Rect &area) { + Common::Rect effectiveArea(area); + effectiveArea.clip(w, h); + + Surface subSurface; + subSurface.w = effectiveArea.width(); + subSurface.h = effectiveArea.height(); + subSurface.pitch = pitch; + subSurface.pixels = getBasePtr(area.left, area.top); + subSurface.format = format; + return subSurface; +} + +const Surface Surface::getSubArea(const Common::Rect &area) const { + Common::Rect effectiveArea(area); + effectiveArea.clip(w, h); + + Surface subSurface; + subSurface.w = effectiveArea.width(); + subSurface.h = effectiveArea.height(); + subSurface.pitch = pitch; + // We need to cast the const away here because a Surface always has a + // pointer to modifiable pixel data. + subSurface.pixels = const_cast<void *>(getBasePtr(area.left, area.top)); + subSurface.format = format; + return subSurface; } void Surface::hLine(int x, int y, int x2, uint32 color) { diff --git a/graphics/surface.h b/graphics/surface.h index 6c9e464657..b08d4a5cb7 100644 --- a/graphics/surface.h +++ b/graphics/surface.h @@ -61,11 +61,13 @@ struct Surface { */ uint16 pitch; +protected: /** * The surface's pixel data. */ void *pixels; +public: /** * The pixel format of the surface. */ @@ -78,6 +80,33 @@ struct Surface { } /** + * Return a pointer to the pixel data. + * + * @return Pointer to the pixel data. + */ + inline const void *getPixels() const { + return pixels; + } + + /** + * Return a pointer to the pixel data. + * + * @return Pointer to the pixel data. + */ + inline void *getPixels() { + return pixels; + } + + /** + * Sets the pixel data. + * + * Note that this is a simply a setter. Be careful what you are doing! + * + * @param newPixels The new pixel data. + */ + void setPixels(void *newPixels) { pixels = newPixels; } + + /** * Return a pointer to the pixel at the specified point. * * @param x The x coordinate of the pixel. @@ -122,6 +151,20 @@ struct Surface { void free(); /** + * Set up the Surface with user specified data. + * + * Note that this simply sets the 'internal' attributes of the Surface. It + * will not take care of freeing old data via free or similar! + * + * @param width Width of the pixel data. + * @param height Height of the pixel data. + * @param pitch The pitch of the pixel data. + * @param pixels The pixel data itself. + * @param format The pixel format of the pixel data. + */ + void init(uint16 width, uint16 height, uint16 pitch, void *pixels, const PixelFormat &format); + + /** * Copy the data from another Surface. * * Note that this calls free on the current surface, to assure it being @@ -135,10 +178,42 @@ struct Surface { void copyFrom(const Surface &surf); /** + * Creates a Surface which represents a sub-area of this Surface object. + * + * The pixel (0, 0) of the returned Surface will be the same as Pixel + * (area.x, area.y) of this Surface. Changes to any of the Surface objects + * will change the shared pixel data. + * + * Note that the Surface returned is only valid as long as this Surface + * object is still alive (i.e. its pixel data is not destroyed or + * reallocated). Do *never* try to free the returned Surface. + * + * @param area The area which should be represented. Note that the area + * will get clipped in case it does not fit! + */ + Surface getSubArea(const Common::Rect &area); + + /** + * Creates a Surface which represents a sub-area of this Surface object. + * + * The pixel (0, 0) of the returned Surface will be the same as Pixel + * (area.x, area.y) of this Surface. + * + * Note that the Surface returned is only valid as long as this Surface + * object is still alive (i.e. its pixel data is not destroyed or + * reallocated). Do *never* try to free the returned Surface. + * + * @param area The area which should be represented. Note that the area + * will get clipped in case it does not fit! + */ + const Surface getSubArea(const Common::Rect &area) const; + + /** * Convert the data to another pixel format. * * This works in-place. This means it will not create an additional buffer - * for the conversion process. The value of pixels might change though. + * for the conversion process. The value of 'pixels' might change though + * (that means it might realloc the pixel data). * * Note that you should only use this, when you created the Surface data via * create! Otherwise this function has undefined behavior. diff --git a/graphics/thumbnail.cpp b/graphics/thumbnail.cpp index ddb377306d..e3f368dffa 100644 --- a/graphics/thumbnail.cpp +++ b/graphics/thumbnail.cpp @@ -23,6 +23,7 @@ #include "graphics/scaler.h" #include "graphics/colormasks.h" #include "common/endian.h" +#include "common/algorithm.h" #include "common/system.h" #include "common/stream.h" #include "common/textconsole.h" @@ -42,7 +43,16 @@ struct ThumbnailHeader { #define ThumbnailHeaderSize (4+4+1+2+2+(1+4+4)) -bool loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header, bool outputWarnings) { +enum HeaderState { + /// There is no header present + kHeaderNone, + /// The header present only has reliable values for version and size + kHeaderUnsupported, + /// The header is present and the version is supported + kHeaderPresent +}; + +HeaderState loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header, bool outputWarnings) { header.type = in.readUint32BE(); // We also accept the bad 'BMHT' header here, for the sake of compatibility // with some older savegames which were written incorrectly due to a bug in @@ -50,16 +60,28 @@ bool loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header, bool ou if (header.type != MKTAG('T','H','M','B') && header.type != MKTAG('B','M','H','T')) { if (outputWarnings) warning("couldn't find thumbnail header type"); - return false; + return kHeaderNone; } header.size = in.readUint32BE(); header.version = in.readByte(); + // Do a check whether any read errors had occured. If so we cannot use the + // values obtained for size and version because they might be bad. + if (in.err() || in.eos()) { + // TODO: We fake that there is no header. This is actually not quite + // correct since we found the start of the header and then things + // started to break. Right no we leave detection of this to the client. + // Since this case is caused by broken files, the client code should + // catch it anyway... If there is a nicer solution here, we should + // implement it. + return kHeaderNone; + } + if (header.version > THMB_VERSION) { if (outputWarnings) warning("trying to load a newer thumbnail version: %d instead of %d", header.version, THMB_VERSION); - return false; + return kHeaderUnsupported; } header.width = in.readUint16BE(); @@ -81,7 +103,15 @@ bool loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header, bool ou header.format = createPixelFormat<565>(); } - return true; + if (in.err() || in.eos()) { + // When we reached this point we know that at least the size and + // version field was loaded successfully, thus we tell this header + // is not supported and silently hope that the client code is + // prepared to handle read errors. + return kHeaderUnsupported; + } else { + return kHeaderPresent; + } } } // end of anonymous namespace @@ -89,7 +119,12 @@ bool checkThumbnailHeader(Common::SeekableReadStream &in) { uint32 position = in.pos(); ThumbnailHeader header; - bool hasHeader = loadHeader(in, header, false); + // TODO: It is not clear whether this is the best semantics. Now + // checkThumbnailHeader will return true even when the thumbnail header + // found is actually not usable. However, most engines seem to use this + // to detect the presence of any header and if there is none it wont even + // try to skip it. Thus, this looks like the best solution for now... + bool hasHeader = (loadHeader(in, header, false) != kHeaderNone); in.seek(position, SEEK_SET); @@ -100,7 +135,9 @@ bool skipThumbnail(Common::SeekableReadStream &in) { uint32 position = in.pos(); ThumbnailHeader header; - if (!loadHeader(in, header, false)) { + // We can skip unsupported and supported headers. So we only seek back + // to the old position in case there is no header at all. + if (loadHeader(in, header, false) == kHeaderNone) { in.seek(position, SEEK_SET); return false; } @@ -110,10 +147,23 @@ bool skipThumbnail(Common::SeekableReadStream &in) { } Graphics::Surface *loadThumbnail(Common::SeekableReadStream &in) { + const uint32 position = in.pos(); ThumbnailHeader header; - - if (!loadHeader(in, header, true)) + HeaderState headerState = loadHeader(in, header, true); + + // Try to handle unsupported/broken headers gracefully. If there is no + // header at all, we seek back and return at this point. If there is an + // unsupported/broken header, we skip the actual data and return. The + // downside is that we might reset the end of stream flag with this and + // the client code would not be able to notice a read past the end of the + // stream at this point then. + if (headerState == kHeaderNone) { + in.seek(position, SEEK_SET); + return 0; + } else if (headerState == kHeaderUnsupported) { + in.seek(header.size - (in.pos() - position), SEEK_CUR); return 0; + } if (header.format.bytesPerPixel != 2 && header.format.bytesPerPixel != 4) { warning("trying to load thumbnail with unsupported bit depth %d", header.format.bytesPerPixel); @@ -143,7 +193,6 @@ Graphics::Surface *loadThumbnail(Common::SeekableReadStream &in) { assert(0); } } - return to; } @@ -216,4 +265,55 @@ bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb) { return true; } + +/** + * Returns an array indicating which pixels of a source image horizontally or vertically get + * included in a scaled image + */ +int *scaleLine(int size, int srcSize) { + int scale = 100 * size / srcSize; + assert(scale > 0); + int *v = new int[size]; + Common::fill(v, &v[size], 0); + + int distCtr = 0; + int *destP = v; + for (int distIndex = 0; distIndex < srcSize; ++distIndex) { + distCtr += scale; + while (distCtr >= 100) { + assert(destP < &v[size]); + *destP++ = distIndex; + distCtr -= 100; + } + } + + return v; +} + +Graphics::Surface *scale(const Graphics::Surface &srcImage, int xSize, int ySize) { + Graphics::Surface *s = new Graphics::Surface(); + s->create(xSize, ySize, srcImage.format); + + int *horizUsage = scaleLine(xSize, srcImage.w); + int *vertUsage = scaleLine(ySize, srcImage.h); + + // Loop to create scaled version + for (int yp = 0; yp < ySize; ++yp) { + const byte *srcP = (const byte *)srcImage.getBasePtr(0, vertUsage[yp]); + byte *destP = (byte *)s->getBasePtr(0, yp); + + for (int xp = 0; xp < xSize; ++xp) { + const byte *tempSrcP = srcP + (horizUsage[xp] * srcImage.format.bytesPerPixel); + for (int byteCtr = 0; byteCtr < srcImage.format.bytesPerPixel; ++byteCtr) { + *destP++ = *tempSrcP++; + } + } + } + + // Delete arrays and return surface + delete[] horizUsage; + delete[] vertUsage; + return s; +} + } // End of namespace Graphics diff --git a/graphics/thumbnail.h b/graphics/thumbnail.h index 45a0fdbf07..c857809c91 100644 --- a/graphics/thumbnail.h +++ b/graphics/thumbnail.h @@ -64,6 +64,24 @@ bool saveThumbnail(Common::WriteStream &out); */ bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb); +/** + * Grabs framebuffer into surface + * + * @param surf a surface + * @return false if a error occurred + */ +bool createScreenShot(Graphics::Surface &surf); + +/** + * Scales a passed surface, creating a new surface with the result + * @param srcImage Source image to scale + * @param xSize New surface width + * @param ySize New surface height + * @remarks Caller is responsible for freeing the returned surface + */ +Graphics::Surface *scale(const Graphics::Surface &srcImage, int xSize, int ySize); + + } // End of namespace Graphics #endif diff --git a/graphics/yuv_to_rgb.cpp b/graphics/yuv_to_rgb.cpp index 6043315a13..2a485fa664 100644 --- a/graphics/yuv_to_rgb.cpp +++ b/graphics/yuv_to_rgb.cpp @@ -229,7 +229,7 @@ void convertYUV444ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup void YUVToRGBManager::convert444(Graphics::Surface *dst, YUVToRGBManager::LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Sanity checks - assert(dst && dst->pixels); + assert(dst && dst->getPixels()); assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4); assert(ySrc && uSrc && vSrc); @@ -237,9 +237,9 @@ void YUVToRGBManager::convert444(Graphics::Surface *dst, YUVToRGBManager::Lumina // Use a templated function to avoid an if check on every pixel if (dst->format.bytesPerPixel == 2) - convertYUV444ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); + convertYUV444ToRGB<uint16>((byte *)dst->getPixels(), dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); else - convertYUV444ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); + convertYUV444ToRGB<uint32>((byte *)dst->getPixels(), dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); } template<typename PixelInt> @@ -283,7 +283,7 @@ void convertYUV420ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup void YUVToRGBManager::convert420(Graphics::Surface *dst, YUVToRGBManager::LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Sanity checks - assert(dst && dst->pixels); + assert(dst && dst->getPixels()); assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4); assert(ySrc && uSrc && vSrc); assert((yWidth & 1) == 0); @@ -293,9 +293,9 @@ void YUVToRGBManager::convert420(Graphics::Surface *dst, YUVToRGBManager::Lumina // Use a templated function to avoid an if check on every pixel if (dst->format.bytesPerPixel == 2) - convertYUV420ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); + convertYUV420ToRGB<uint16>((byte *)dst->getPixels(), dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); else - convertYUV420ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); + convertYUV420ToRGB<uint32>((byte *)dst->getPixels(), dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); } #define READ_QUAD(ptr, prefix) \ @@ -368,7 +368,7 @@ void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup void YUVToRGBManager::convert410(Graphics::Surface *dst, YUVToRGBManager::LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Sanity checks - assert(dst && dst->pixels); + assert(dst && dst->getPixels()); assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4); assert(ySrc && uSrc && vSrc); assert((yWidth & 3) == 0); @@ -378,9 +378,9 @@ void YUVToRGBManager::convert410(Graphics::Surface *dst, YUVToRGBManager::Lumina // Use a templated function to avoid an if check on every pixel if (dst->format.bytesPerPixel == 2) - convertYUV410ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); + convertYUV410ToRGB<uint16>((byte *)dst->getPixels(), dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); else - convertYUV410ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); + convertYUV410ToRGB<uint32>((byte *)dst->getPixels(), dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); } } // End of namespace Graphics diff --git a/graphics/yuv_to_rgb.h b/graphics/yuv_to_rgb.h index f785422c5a..a1e61ec705 100644 --- a/graphics/yuv_to_rgb.h +++ b/graphics/yuv_to_rgb.h @@ -22,10 +22,17 @@ /** * @file - * YUV to RGB conversion used in engines: - * - mohawk - * - scumm (he) - * - sword25 + * YUV to RGB conversion. + * + * Used in graphics: + * - JPEGDecoder + * + * Used in video: + * - BinkDecoder + * - Indeo3Decoder + * - PSXStreamDecoder + * - TheoraDecoder + * - SVQ1Decoder */ #ifndef GRAPHICS_YUV_TO_RGB_H diff --git a/gui/EventRecorder.cpp b/gui/EventRecorder.cpp new file mode 100644 index 0000000000..21152dd079 --- /dev/null +++ b/gui/EventRecorder.cpp @@ -0,0 +1,678 @@ +/* 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 "gui/EventRecorder.h" + +#ifdef ENABLE_EVENTRECORDER + +namespace Common { +DECLARE_SINGLETON(GUI::EventRecorder); +} + +#include "common/debug-channels.h" +#include "backends/timer/sdl/sdl-timer.h" +#include "backends/mixer/sdl/sdl-mixer.h" +#include "common/config-manager.h" +#include "common/md5.h" +#include "gui/gui-manager.h" +#include "gui/widget.h" +#include "gui/onscreendialog.h" +#include "common/random.h" +#include "common/savefile.h" +#include "common/textconsole.h" +#include "graphics/thumbnail.h" +#include "graphics/surface.h" +#include "graphics/scaler.h" + +namespace GUI { + + +const int kMaxRecordsNames = 0x64; +const int kDefaultScreenshotPeriod = 60000; +const int kDefaultBPP = 2; + +uint32 readTime(Common::ReadStream *inFile) { + uint32 d = inFile->readByte(); + if (d == 0xff) { + d = inFile->readUint32LE(); + } + + return d; +} + +void writeTime(Common::WriteStream *outFile, uint32 d) { + //Simple RLE compression + if (d >= 0xff) { + outFile->writeByte(0xff); + outFile->writeUint32LE(d); + } else { + outFile->writeByte(d); + } +} + +EventRecorder::EventRecorder() { + _timerManager = NULL; + _recordMode = kPassthrough; + _fakeMixerManager = NULL; + _initialized = false; + _needRedraw = false; + _fastPlayback = false; + + _fakeTimer = 0; + _savedState = false; + _needcontinueGame = false; + _temporarySlot = 0; + _realSaveManager = 0; + _realMixerManager = 0; + _controlPanel = 0; + _lastMillis = 0; + _lastScreenshotTime = 0; + _screenshotPeriod = 0; + _playbackFile = 0; + + DebugMan.addDebugChannel(kDebugLevelEventRec, "EventRec", "Event recorder debug level"); +} + +EventRecorder::~EventRecorder() { + if (_timerManager != NULL) { + delete _timerManager; + } +} + +void EventRecorder::deinit() { + if (!_initialized) { + return; + } + setFileHeader(); + _needRedraw = false; + _initialized = false; + _recordMode = kPassthrough; + delete _fakeMixerManager; + _fakeMixerManager = NULL; + _controlPanel->close(); + delete _controlPanel; + debugC(1, kDebugLevelEventRec, "playback:action=stopplayback"); + g_system->getEventManager()->getEventDispatcher()->unregisterSource(this); + _recordMode = kPassthrough; + _playbackFile->close(); + delete _playbackFile; + switchMixer(); + switchTimerManagers(); + DebugMan.disableDebugChannel("EventRec"); +} + +void EventRecorder::processMillis(uint32 &millis, bool skipRecord) { + if (!_initialized) { + return; + } + if (skipRecord) { + millis = _fakeTimer; + return; + } + if (_recordMode == kRecorderPlaybackPause) { + millis = _fakeTimer; + } + uint32 millisDelay; + Common::RecorderEvent timerEvent; + switch (_recordMode) { + case kRecorderRecord: + updateSubsystems(); + millisDelay = millis - _lastMillis; + _lastMillis = millis; + _fakeTimer += millisDelay; + _controlPanel->setReplayedTime(_fakeTimer); + timerEvent.recordedtype = Common::kRecorderEventTypeTimer; + timerEvent.time = _fakeTimer; + _playbackFile->writeEvent(timerEvent); + takeScreenshot(); + _timerManager->handler(); + break; + case kRecorderPlayback: + updateSubsystems(); + if (_nextEvent.recordedtype == Common::kRecorderEventTypeTimer) { + _fakeTimer = _nextEvent.time; + _nextEvent = _playbackFile->getNextEvent(); + _timerManager->handler(); + } else { + if (_nextEvent.type == Common::EVENT_RTL) { + error("playback:action=stopplayback"); + } else { + uint32 seconds = _fakeTimer / 1000; + Common::String screenTime = Common::String::format("%.2d:%.2d:%.2d", seconds / 3600 % 24, seconds / 60 % 60, seconds % 60); + error("playback:action=error reason=\"synchronization error\" time = %s", screenTime.c_str()); + } + } + millis = _fakeTimer; + _controlPanel->setReplayedTime(_fakeTimer); + break; + case kRecorderPlaybackPause: + millis = _fakeTimer; + break; + default: + break; + } +} + +bool EventRecorder::processDelayMillis() { + return _fastPlayback; +} + +void EventRecorder::checkForKeyCode(const Common::Event &event) { + if ((event.type == Common::EVENT_KEYDOWN) && (event.kbd.flags & Common::KBD_CTRL) && (event.kbd.keycode == Common::KEYCODE_p) && (!event.synthetic)) { + togglePause(); + } +} + +bool EventRecorder::pollEvent(Common::Event &ev) { + if ((_recordMode != kRecorderPlayback) || !_initialized) + return false; + + if ((_nextEvent.recordedtype == Common::kRecorderEventTypeTimer) || (_nextEvent.type == Common::EVENT_INVALID)) { + return false; + } + + switch (_nextEvent.type) { + case Common::EVENT_MOUSEMOVE: + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONDOWN: + case Common::EVENT_RBUTTONUP: + case Common::EVENT_WHEELUP: + case Common::EVENT_WHEELDOWN: + g_system->warpMouse(_nextEvent.mouse.x, _nextEvent.mouse.y); + break; + default: + break; + } + ev = _nextEvent; + _nextEvent = _playbackFile->getNextEvent(); + return true; +} + +void EventRecorder::switchFastMode() { + if (_recordMode == kRecorderPlaybackPause) { + _fastPlayback = !_fastPlayback; + } +} + +void EventRecorder::togglePause() { + RecordMode oldState; + switch (_recordMode) { + case kRecorderPlayback: + case kRecorderRecord: + oldState = _recordMode; + _recordMode = kRecorderPlaybackPause; + _controlPanel->runModal(); + _recordMode = oldState; + _initialized = true; + break; + case kRecorderPlaybackPause: + _controlPanel->close(); + break; + default: + break; + } +} + +void EventRecorder::RegisterEventSource() { + g_system->getEventManager()->getEventDispatcher()->registerMapper(this, false); +} + +uint32 EventRecorder::getRandomSeed(const Common::String &name) { + uint32 result = g_system->getMillis(); + if (_recordMode == kRecorderRecord) { + _playbackFile->getHeader().randomSourceRecords[name] = result; + } else if (_recordMode == kRecorderPlayback) { + result = _playbackFile->getHeader().randomSourceRecords[name]; + } + return result; +} + +Common::String EventRecorder::generateRecordFileName(const Common::String &target) { + Common::String pattern(target+".r??"); + Common::StringArray files = g_system->getSavefileManager()->listSavefiles(pattern); + for (int i = 0; i < kMaxRecordsNames; ++i) { + Common::String recordName = Common::String::format("%s.r%02d", target.c_str(), i); + if (find(files.begin(), files.end(), recordName) != files.end()) { + continue; + } + return recordName; + } + return ""; +} + + +void EventRecorder::init(Common::String recordFileName, RecordMode mode) { + _fakeMixerManager = new NullSdlMixerManager(); + _fakeMixerManager->init(); + _fakeMixerManager->suspendAudio(); + _fakeTimer = 0; + _lastMillis = g_system->getMillis(); + _playbackFile = new Common::PlaybackFile(); + _lastScreenshotTime = 0; + _recordMode = mode; + _needcontinueGame = false; + if (ConfMan.hasKey("disable_display")) { + DebugMan.enableDebugChannel("EventRec"); + gDebugLevel = 1; + } + if (_recordMode == kRecorderPlayback) { + debugC(1, kDebugLevelEventRec, "playback:action=\"Load file\" filename=%s", recordFileName.c_str()); + } + g_system->getEventManager()->getEventDispatcher()->registerSource(this, false); + _screenshotPeriod = ConfMan.getInt("screenshot_period"); + if (_screenshotPeriod == 0) { + _screenshotPeriod = kDefaultScreenshotPeriod; + } + if (!openRecordFile(recordFileName)) { + deinit(); + error("playback:action=error reason=\"Record file loading error\""); + return; + } + if (_recordMode != kPassthrough) { + _controlPanel = new GUI::OnScreenDialog(_recordMode == kRecorderRecord); + } + if (_recordMode == kRecorderPlayback) { + applyPlaybackSettings(); + _nextEvent = _playbackFile->getNextEvent(); + } + if (_recordMode == kRecorderRecord) { + getConfig(); + } + + switchMixer(); + switchTimerManagers(); + _needRedraw = true; + _initialized = true; +} + + +/** + * Opens or creates file depend of recording mode. + * + *@param id of recording or playing back game + *@return true in case of success, false in case of error + * + */ +bool EventRecorder::openRecordFile(const Common::String &fileName) { + bool result; + switch (_recordMode) { + case kRecorderRecord: + return _playbackFile->openWrite(fileName); + case kRecorderPlayback: + _recordMode = kPassthrough; + result = _playbackFile->openRead(fileName); + _recordMode = kRecorderPlayback; + return result; + default: + return false; + } + return true; +} + +bool EventRecorder::checkGameHash(const ADGameDescription *gameDesc) { + if (_playbackFile->getHeader().hashRecords.size() != 0) { + warning("Engine doesn't contain description table"); + return false; + } + for (const ADGameFileDescription *fileDesc = gameDesc->filesDescriptions; fileDesc->fileName; fileDesc++) { + if (_playbackFile->getHeader().hashRecords.find(fileDesc->fileName) == _playbackFile->getHeader().hashRecords.end()) { + warning("MD5 hash for file %s not found in record file", fileDesc->fileName); + debugC(1, kDebugLevelEventRec, "playback:action=\"Check game hash\" filename=%s filehash=%s storedhash=\"\" result=different", fileDesc->fileName, fileDesc->md5); + return false; + } + if (_playbackFile->getHeader().hashRecords[fileDesc->fileName] != fileDesc->md5) { + warning("Incorrect version of game file %s. Stored MD5 is %s. MD5 of loaded game is %s", fileDesc->fileName, _playbackFile->getHeader().hashRecords[fileDesc->fileName].c_str(), fileDesc->md5); + debugC(1, kDebugLevelEventRec, "playback:action=\"Check game hash\" filename=%s filehash=%s storedhash=%s result=different", fileDesc->fileName, fileDesc->md5, _playbackFile->getHeader().hashRecords[fileDesc->fileName].c_str()); + return false; + } + debugC(1, kDebugLevelEventRec, "playback:action=\"Check game hash\" filename=%s filehash=%s storedhash=%s result=equal", fileDesc->fileName, fileDesc->md5, _playbackFile->getHeader().hashRecords[fileDesc->fileName].c_str()); + } + return true; +} + +void EventRecorder::registerMixerManager(SdlMixerManager *mixerManager) { + _realMixerManager = mixerManager; +} + +void EventRecorder::switchMixer() { + if (_recordMode == kPassthrough) { + _realMixerManager->resumeAudio(); + } else { + _realMixerManager->suspendAudio(); + _fakeMixerManager->resumeAudio(); + } +} + +SdlMixerManager *EventRecorder::getMixerManager() { + if (_recordMode == kPassthrough) { + return _realMixerManager; + } else { + return _fakeMixerManager; + } +} + +void EventRecorder::getConfigFromDomain(const Common::ConfigManager::Domain *domain) { + for (Common::ConfigManager::Domain::const_iterator entry = domain->begin(); entry!= domain->end(); ++entry) { + _playbackFile->getHeader().settingsRecords[entry->_key] = entry->_value; + } +} + +void EventRecorder::getConfig() { + getConfigFromDomain(ConfMan.getDomain(ConfMan.kApplicationDomain)); + getConfigFromDomain(ConfMan.getActiveDomain()); + _playbackFile->getHeader().settingsRecords["save_slot"] = ConfMan.get("save_slot"); +} + + +void EventRecorder::applyPlaybackSettings() { + for (Common::StringMap::const_iterator i = _playbackFile->getHeader().settingsRecords.begin(); i != _playbackFile->getHeader().settingsRecords.end(); ++i) { + Common::String currentValue = ConfMan.get(i->_key); + if (currentValue != i->_value) { + ConfMan.set(i->_key, i->_value, ConfMan.kTransientDomain); + debugC(1, kDebugLevelEventRec, "playback:action=\"Apply settings\" key=%s storedvalue=%s currentvalue=%s result=different", i->_key.c_str(), i->_value.c_str(), currentValue.c_str()); + } else { + debugC(1, kDebugLevelEventRec, "playback:action=\"Apply settings\" key=%s storedvalue=%s currentvalue=%s result=equal", i->_key.c_str(), i->_value.c_str(), currentValue.c_str()); + } + } + removeDifferentEntriesInDomain(ConfMan.getDomain(ConfMan.kApplicationDomain)); + removeDifferentEntriesInDomain(ConfMan.getActiveDomain()); +} + +void EventRecorder::removeDifferentEntriesInDomain(Common::ConfigManager::Domain *domain) { + for (Common::ConfigManager::Domain::const_iterator entry = domain->begin(); entry!= domain->end(); ++entry) { + if (_playbackFile->getHeader().settingsRecords.find(entry->_key) == _playbackFile->getHeader().settingsRecords.end()) { + debugC(1, kDebugLevelEventRec, "playback:action=\"Apply settings\" checksettings:key=%s storedvalue=%s currentvalue="" result=different", entry->_key.c_str(), entry->_value.c_str()); + domain->erase(entry->_key); + } + } +} + +DefaultTimerManager *EventRecorder::getTimerManager() { + return _timerManager; +} + +void EventRecorder::registerTimerManager(DefaultTimerManager *timerManager) { + _timerManager = timerManager; +} + +void EventRecorder::switchTimerManagers() { + delete _timerManager; + if (_recordMode == kPassthrough) { + _timerManager = new SdlTimerManager(); + } else { + _timerManager = new DefaultTimerManager(); + } +} + +void EventRecorder::updateSubsystems() { + if (_recordMode == kPassthrough) { + return; + } + RecordMode oldRecordMode = _recordMode; + _recordMode = kPassthrough; + _fakeMixerManager->update(); + _recordMode = oldRecordMode; +} + +Common::List<Common::Event> EventRecorder::mapEvent(const Common::Event &ev, Common::EventSource *source) { + if ((!_initialized) && (_recordMode != kRecorderPlaybackPause)) { + return DefaultEventMapper::mapEvent(ev, source); + } + + checkForKeyCode(ev); + Common::Event evt = ev; + evt.mouse.x = evt.mouse.x * (g_system->getOverlayWidth() / g_system->getWidth()); + evt.mouse.y = evt.mouse.y * (g_system->getOverlayHeight() / g_system->getHeight()); + switch (_recordMode) { + case kRecorderPlayback: + if (ev.synthetic != true) { + return Common::List<Common::Event>(); + } + return Common::DefaultEventMapper::mapEvent(ev, source); + break; + case kRecorderRecord: + g_gui.processEvent(evt, _controlPanel); + if (((evt.type == Common::EVENT_LBUTTONDOWN) || (evt.type == Common::EVENT_LBUTTONUP) || (evt.type == Common::EVENT_MOUSEMOVE)) && _controlPanel->isMouseOver()) { + return Common::List<Common::Event>(); + } else { + Common::RecorderEvent e; + memcpy(&e, &ev, sizeof(ev)); + e.recordedtype = Common::kRecorderEventTypeNormal; + e.time = _fakeTimer; + _playbackFile->writeEvent(e); + return DefaultEventMapper::mapEvent(ev, source); + } + break; + case kRecorderPlaybackPause: { + Common::Event dialogEvent; + if (_controlPanel->isEditDlgVisible()) { + dialogEvent = ev; + } else { + dialogEvent = evt; + } + g_gui.processEvent(dialogEvent, _controlPanel->getActiveDlg()); + if (((dialogEvent.type == Common::EVENT_LBUTTONDOWN) || (dialogEvent.type == Common::EVENT_LBUTTONUP) || (dialogEvent.type == Common::EVENT_MOUSEMOVE)) && _controlPanel->isMouseOver()) { + return Common::List<Common::Event>(); + } + return Common::DefaultEventMapper::mapEvent(dialogEvent, source); + } + break; + default: + return Common::DefaultEventMapper::mapEvent(ev, source); + } +} + +void EventRecorder::setGameMd5(const ADGameDescription *gameDesc) { + for (const ADGameFileDescription *fileDesc = gameDesc->filesDescriptions; fileDesc->fileName; fileDesc++) { + if (fileDesc->md5 != NULL) { + _playbackFile->getHeader().hashRecords[fileDesc->fileName] = fileDesc->md5; + } + } +} + +void EventRecorder::processGameDescription(const ADGameDescription *desc) { + if (_recordMode == kRecorderRecord) { + setGameMd5(desc); + } + if ((_recordMode == kRecorderPlayback) && !checkGameHash(desc)) { + deinit(); + error("playback:action=error reason=\"\""); + } +} + +void EventRecorder::deleteRecord(const Common::String& fileName) { + g_system->getSavefileManager()->removeSavefile(fileName); +} + +void EventRecorder::takeScreenshot() { + if ((_fakeTimer - _lastScreenshotTime) > _screenshotPeriod) { + Graphics::Surface screen; + uint8 md5[16]; + if (grabScreenAndComputeMD5(screen, md5)) { + _lastScreenshotTime = _fakeTimer; + _playbackFile->saveScreenShot(screen, md5); + screen.free(); + } + } +} + +bool EventRecorder::grabScreenAndComputeMD5(Graphics::Surface &screen, uint8 md5[16]) { + if (!createScreenShot(screen)) { + warning("Can't save screenshot"); + return false; + } + Common::MemoryReadStream bitmapStream((const byte*)screen.getPixels(), screen.w * screen.h * screen.format.bytesPerPixel); + computeStreamMD5(bitmapStream, md5); + return true; +} + +Common::SeekableReadStream *EventRecorder::processSaveStream(const Common::String &fileName) { + Common::InSaveFile *saveFile; + switch (_recordMode) { + case kRecorderPlayback: + debugC(1, kDebugLevelEventRec, "playback:action=\"Process save file\" filename=%s len=%d", fileName.c_str(), _playbackFile->getHeader().saveFiles[fileName].size); + return new Common::MemoryReadStream(_playbackFile->getHeader().saveFiles[fileName].buffer, _playbackFile->getHeader().saveFiles[fileName].size); + case kRecorderRecord: + saveFile = _realSaveManager->openForLoading(fileName); + if (saveFile != NULL) { + _playbackFile->addSaveFile(fileName, saveFile); + saveFile->seek(0); + } + return saveFile; + default: + return NULL; + break; + } +} + +Common::SaveFileManager *EventRecorder::getSaveManager(Common::SaveFileManager *realSaveManager) { + _realSaveManager = realSaveManager; + if (_recordMode != kPassthrough) { + return &_fakeSaveManager; + } else { + return realSaveManager; + } +} + +void EventRecorder::preDrawOverlayGui() { + if ((_initialized) || (_needRedraw)) { + RecordMode oldMode = _recordMode; + _recordMode = kPassthrough; + g_system->showOverlay(); + g_gui.theme()->clearAll(); + g_gui.theme()->openDialog(true, GUI::ThemeEngine::kShadingNone); + _controlPanel->drawDialog(); + g_gui.theme()->finishBuffering(); + g_gui.theme()->updateScreen(); + _recordMode = oldMode; + } +} + +void EventRecorder::postDrawOverlayGui() { + if ((_initialized) || (_needRedraw)) { + RecordMode oldMode = _recordMode; + _recordMode = kPassthrough; + g_system->hideOverlay(); + _recordMode = oldMode; + } +} + +Common::StringArray EventRecorder::listSaveFiles(const Common::String &pattern) { + if (_recordMode == kRecorderPlayback) { + Common::StringArray result; + for (Common::HashMap<Common::String, Common::PlaybackFile::SaveFileBuffer>::iterator i = _playbackFile->getHeader().saveFiles.begin(); i != _playbackFile->getHeader().saveFiles.end(); ++i) { + if (i->_key.matchString(pattern, false, true)) { + result.push_back(i->_key); + } + } + return result; + } else { + return _realSaveManager->listSavefiles(pattern); + } +} + +void EventRecorder::setFileHeader() { + if (_recordMode != kRecorderRecord) { + return; + } + TimeDate t; + const EnginePlugin *plugin = 0; + GameDescriptor desc = EngineMan.findGame(ConfMan.getActiveDomainName(), &plugin); + g_system->getTimeAndDate(t); + if (_author.empty()) { + setAuthor("Unknown Author"); + } + if (_name.empty()) { + g_eventRec.setName(Common::String::format("%.2d.%.2d.%.4d ", t.tm_mday, t.tm_mon, 1900 + t.tm_year) + desc.description()); + } + _playbackFile->getHeader().author = _author; + _playbackFile->getHeader().notes = _desc; + _playbackFile->getHeader().name = _name; +} + +SDL_Surface *EventRecorder::getSurface(int width, int height) { + // Create a RGB565 surface of the requested dimensions. + return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 16, 0xF800, 0x07E0, 0x001F, 0x0000); +} + +bool EventRecorder::switchMode() { + const Common::String gameId = ConfMan.get("gameid"); + const EnginePlugin *plugin = 0; + EngineMan.findGame(gameId, &plugin); + bool metaInfoSupport = (*plugin)->hasFeature(MetaEngine::kSavesSupportMetaInfo); + bool featuresSupport = metaInfoSupport && + g_engine->canSaveGameStateCurrently() && + (*plugin)->hasFeature(MetaEngine::kSupportsListSaves) && + (*plugin)->hasFeature(MetaEngine::kSupportsDeleteSave); + if (!featuresSupport) { + return false; + } + + int emptySlot = 1; + SaveStateList saveList = (*plugin)->listSaves(gameId.c_str()); + for (SaveStateList::const_iterator x = saveList.begin(); x != saveList.end(); ++x) { + int saveSlot = x->getSaveSlot(); + if (saveSlot == 0) { + continue; + } + if (emptySlot != saveSlot) { + break; + } + emptySlot++; + } + Common::String saveName; + if (emptySlot >= 0) { + saveName = Common::String::format("Save %d", emptySlot + 1); + Common::Error status = g_engine->saveGameState(emptySlot, saveName); + if (status.getCode() == Common::kNoError) { + Common::Event eventRTL; + eventRTL.type = Common::EVENT_RTL; + g_system->getEventManager()->pushEvent(eventRTL); + } + } + ConfMan.set("record_mode", "", Common::ConfigManager::kTransientDomain); + ConfMan.setInt("save_slot", emptySlot, Common::ConfigManager::kTransientDomain); + _needcontinueGame = true; + return true; +} + +bool EventRecorder::checkForContinueGame() { + bool result = _needcontinueGame; + _needcontinueGame = false; + return result; +} + +void EventRecorder::deleteTemporarySave() { + if (_temporarySlot == -1) return; + const Common::String gameId = ConfMan.get("gameid"); + const EnginePlugin *plugin = 0; + EngineMan.findGame(gameId, &plugin); + (*plugin)->removeSaveState(gameId.c_str(), _temporarySlot); + _temporarySlot = -1; +} + +} // End of namespace GUI + +#endif // ENABLE_EVENTRECORDER + diff --git a/gui/EventRecorder.h b/gui/EventRecorder.h new file mode 100644 index 0000000000..b2a549ece8 --- /dev/null +++ b/gui/EventRecorder.h @@ -0,0 +1,238 @@ +/* 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 GUI_EVENTRECORDER_H +#define GUI_EVENTRECORDER_H + +#include "common/system.h" + +#include "common/events.h" +#include "common/savefile.h" +#include "common/singleton.h" + +#include "engines/advancedDetector.h" + +#ifdef ENABLE_EVENTRECORDER + +#include "common/mutex.h" +#include "common/array.h" +#include "common/memstream.h" +#include "backends/keymapper/keymapper.h" +#include "backends/mixer/sdl/sdl-mixer.h" +#include "common/hashmap.h" +#include "common/hash-str.h" +#include "backends/timer/sdl/sdl-timer.h" +#include "common/config-manager.h" +#include "common/recorderfile.h" +#include "backends/saves/recorder/recorder-saves.h" +#include "backends/mixer/nullmixer/nullsdl-mixer.h" +#include "backends/saves/default/default-saves.h" + + +#define g_eventRec (GUI::EventRecorder::instance()) + +namespace GUI { + class OnScreenDialog; +} + +namespace GUI { +class RandomSource; +class SeekableReadStream; +class WriteStream; + + +/** + * Our generic event recorder. + * + * TODO: Add more documentation. + */ +class EventRecorder : private Common::EventSource, public Common::Singleton<EventRecorder>, private Common::DefaultEventMapper { + friend class Common::Singleton<SingletonBaseType>; + EventRecorder(); + ~EventRecorder(); +public: + /** Specify operation mode of Event Recorder */ + enum RecordMode { + kPassthrough = 0, /**< kPassthrough, do nothing */ + kRecorderRecord = 1, /**< kRecorderRecord, do the recording */ + kRecorderPlayback = 2, /**< kRecorderPlayback, playback existing recording */ + kRecorderPlaybackPause = 3 /**< kRecordetPlaybackPause, interal state when user pauses the playback */ + }; + + void init(Common::String recordFileName, RecordMode mode); + void deinit(); + bool processDelayMillis(); + uint32 getRandomSeed(const Common::String &name); + void processMillis(uint32 &millis, bool skipRecord); + bool processAudio(uint32 &samples, bool paused); + void processGameDescription(const ADGameDescription *desc); + Common::SeekableReadStream *processSaveStream(const Common::String & fileName); + + /** Hooks for intercepting into GUI processing, so required events could be shoot + * or filtered out */ + void preDrawOverlayGui(); + void postDrawOverlayGui(); + + /** Set recording author + * + * @see getAuthor + */ + void setAuthor(const Common::String &author) { + _author = author; + } + + /** Set recording notes + * + * @see getNotes + */ + void setNotes(const Common::String &desc){ + _desc = desc; + } + + /** Set descriptive name of the recording + * + * @see getName + */ + void setName(const Common::String &name) { + _name = name; + } + + /** Get recording author + * + * @see getAuthor + */ + const Common::String getAuthor() { + return _author; + } + + /** Get recording notes + * + * @see setNotes + */ + const Common::String getNotes() { + return _desc; + } + + /** Get recording name + * + * @see setName + */ + const Common::String getName() { + return _name; + } + void setRedraw(bool redraw) { + _needRedraw = redraw; + } + + void registerMixerManager(SdlMixerManager *mixerManager); + void registerTimerManager(DefaultTimerManager *timerManager); + + SdlMixerManager *getMixerManager(); + DefaultTimerManager *getTimerManager(); + + void deleteRecord(const Common::String& fileName); + bool checkForContinueGame(); + + void suspendRecording() { + _savedState = _initialized; + _initialized = false; + } + + void resumeRecording() { + _initialized = _savedState; + } + + Common::StringArray listSaveFiles(const Common::String &pattern); + Common::String generateRecordFileName(const Common::String &target); + + Common::SaveFileManager *getSaveManager(Common::SaveFileManager *realSaveManager); + SDL_Surface *getSurface(int width, int height); + void RegisterEventSource(); + + /** Retrieve game screenshot and compute its checksum for comparison */ + bool grabScreenAndComputeMD5(Graphics::Surface &screen, uint8 md5[16]); + + void updateSubsystems(); + bool switchMode(); + void switchFastMode(); + +private: + virtual Common::List<Common::Event> mapEvent(const Common::Event &ev, Common::EventSource *source); + bool notifyPoll(); + bool pollEvent(Common::Event &ev); + bool _initialized; + volatile uint32 _fakeTimer; + bool _savedState; + bool _needcontinueGame; + int _temporarySlot; + Common::String _author; + Common::String _desc; + Common::String _name; + + Common::SaveFileManager *_realSaveManager; + SdlMixerManager *_realMixerManager; + DefaultTimerManager *_timerManager; + RecorderSaveFileManager _fakeSaveManager; + NullSdlMixerManager *_fakeMixerManager; + GUI::OnScreenDialog *_controlPanel; + Common::RecorderEvent _nextEvent; + + void setFileHeader(); + void setGameMd5(const ADGameDescription *gameDesc); + void getConfig(); + void getConfigFromDomain(const Common::ConfigManager::Domain *domain); + void removeDifferentEntriesInDomain(Common::ConfigManager::Domain *domain); + void applyPlaybackSettings(); + + void switchMixer(); + void switchTimerManagers(); + + void togglePause(); + + void takeScreenshot(); + + bool openRecordFile(const Common::String &fileName); + + bool checkGameHash(const ADGameDescription *desc); + + void checkForKeyCode(const Common::Event &event); + bool allowMapping() const { return false; } + + volatile uint32 _lastMillis; + uint32 _lastScreenshotTime; + uint32 _screenshotPeriod; + Common::PlaybackFile *_playbackFile; + + void saveScreenShot(); + void checkRecordedMD5(); + void deleteTemporarySave(); + volatile RecordMode _recordMode; + Common::String _recordFileName; + bool _fastPlayback; + bool _needRedraw; +}; + +} // End of namespace GUI + +#endif // ENABLE_EVENTRECORDER + +#endif diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp index e2fa2580f5..561c0244a2 100644 --- a/gui/ThemeEngine.cpp +++ b/gui/ThemeEngine.cpp @@ -50,6 +50,14 @@ const char * const ThemeEngine::kImageEraser = "eraser.bmp"; const char * const ThemeEngine::kImageDelbtn = "delbtn.bmp"; const char * const ThemeEngine::kImageList = "list.bmp"; const char * const ThemeEngine::kImageGrid = "grid.bmp"; +const char * const ThemeEngine::kImageStopbtn = "stopbtn.bmp"; +const char * const ThemeEngine::kImageEditbtn = "editbtn.bmp"; +const char * const ThemeEngine::kImageSwitchModebtn = "switchbtn.bmp"; +const char * const ThemeEngine::kImageFastReplaybtn = "fastreplay.bmp"; +const char * const ThemeEngine::kImageStopSmallbtn = "stopbtn_small.bmp"; +const char * const ThemeEngine::kImageEditSmallbtn = "editbtn_small.bmp"; +const char * const ThemeEngine::kImageSwitchModeSmallbtn = "switchbtn_small.bmp"; +const char * const ThemeEngine::kImageFastReplaySmallbtn = "fastreplay_small.bmp"; struct TextDrawData { const Graphics::Font *_fontPtr; @@ -335,9 +343,9 @@ ThemeEngine::~ThemeEngine() { *********************************************************/ const ThemeEngine::Renderer ThemeEngine::_rendererModes[] = { { _s("Disabled GFX"), _sc("Disabled GFX", "lowres"), "none", kGfxDisabled }, - { _s("Standard Renderer (16bpp)"), _s("Standard (16bpp)"), "normal_16bpp", kGfxStandard16bit }, + { _s("Standard Renderer"), _s("Standard"), "normal", kGfxStandard }, #ifndef DISABLE_FANCY_THEMES - { _s("Antialiased Renderer (16bpp)"), _s("Antialiased (16bpp)"), "aa_16bpp", kGfxAntialias16bit } + { _s("Antialiased Renderer"), _s("Antialiased"), "antialias", kGfxAntialias } #endif }; @@ -345,9 +353,9 @@ const uint ThemeEngine::_rendererModesSize = ARRAYSIZE(ThemeEngine::_rendererMod const ThemeEngine::GraphicsMode ThemeEngine::_defaultRendererMode = #ifndef DISABLE_FANCY_THEMES - ThemeEngine::kGfxAntialias16bit; + ThemeEngine::kGfxAntialias; #else - ThemeEngine::kGfxStandard16bit; + ThemeEngine::kGfxStandard; #endif ThemeEngine::GraphicsMode ThemeEngine::findMode(const Common::String &cfg) { @@ -381,7 +389,7 @@ bool ThemeEngine::init() { _overlayFormat = _system->getOverlayFormat(); setGraphicsMode(_graphicsMode); - if (_screen.pixels && _backBuffer.pixels) { + if (_screen.getPixels() && _backBuffer.getPixels()) { _initOk = true; } @@ -431,7 +439,7 @@ bool ThemeEngine::init() { void ThemeEngine::clearAll() { if (_initOk) { _system->clearOverlay(); - _system->grabOverlay(_screen.pixels, _screen.pitch); + _system->grabOverlay(_screen.getPixels(), _screen.pitch); } } @@ -465,11 +473,7 @@ void ThemeEngine::enable() { if (_enabled) return; - if (_useCursor) { - CursorMan.pushCursorPalette(_cursorPal, 0, _cursorPalSize); - CursorMan.pushCursor(_cursor, _cursorWidth, _cursorHeight, _cursorHotspotX, _cursorHotspotY, 255, true); - CursorMan.showMouse(true); - } + showCursor(); _system->showOverlay(); clearAll(); @@ -482,23 +486,25 @@ void ThemeEngine::disable() { _system->hideOverlay(); - if (_useCursor) { - CursorMan.popCursorPalette(); - CursorMan.popCursor(); - } + hideCursor(); + _enabled = false; } void ThemeEngine::setGraphicsMode(GraphicsMode mode) { switch (mode) { - case kGfxStandard16bit: + case kGfxStandard: #ifndef DISABLE_FANCY_THEMES - case kGfxAntialias16bit: + case kGfxAntialias: #endif - _bytesPerPixel = sizeof(uint16); - break; - + if (g_system->getOverlayFormat().bytesPerPixel == 4) { + _bytesPerPixel = sizeof(uint32); + break; + } else if (g_system->getOverlayFormat().bytesPerPixel == 2) { + _bytesPerPixel = sizeof(uint16); + break; + } default: error("Invalid graphics mode"); } @@ -1217,7 +1223,7 @@ void ThemeEngine::updateScreen(bool render) { } _vectorRenderer->setSurface(&_screen); - memcpy(_screen.getBasePtr(0, 0), _backBuffer.getBasePtr(0, 0), _screen.pitch * _screen.h); + memcpy(_screen.getPixels(), _backBuffer.getPixels(), _screen.pitch * _screen.h); _bufferQueue.clear(); } @@ -1285,7 +1291,7 @@ void ThemeEngine::openDialog(bool doBuffer, ShadingStyle style) { addDirtyRect(Common::Rect(0, 0, _screen.w, _screen.h)); } - memcpy(_backBuffer.getBasePtr(0, 0), _screen.getBasePtr(0, 0), _screen.pitch * _screen.h); + memcpy(_backBuffer.getPixels(), _screen.getPixels(), _screen.pitch * _screen.h); _vectorRenderer->setSurface(&_screen); } @@ -1318,22 +1324,31 @@ bool ThemeEngine::createCursor(const Common::String &filename, int hotspotX, int memset(_cursor, 0xFF, sizeof(byte) * _cursorWidth * _cursorHeight); // the transparent color is 0xFF00FF - const int colTransparent = _overlayFormat.RGBToColor(0xFF, 0, 0xFF); + const uint32 colTransparent = _overlayFormat.RGBToColor(0xFF, 0, 0xFF); // Now, scan the bitmap. We have to convert it from 16 bit color mode // to 8 bit mode, and have to create a suitable palette on the fly. uint colorsFound = 0; Common::HashMap<int, int> colorToIndex; - const OverlayColor *src = (const OverlayColor *)cursor->pixels; + const byte *src = (const byte *)cursor->getPixels(); for (uint y = 0; y < _cursorHeight; ++y) { for (uint x = 0; x < _cursorWidth; ++x) { + uint32 color = colTransparent; byte r, g, b; + if (cursor->format.bytesPerPixel == 2) { + color = READ_UINT16(src); + } else if (cursor->format.bytesPerPixel == 4) { + color = READ_UINT32(src); + } + + src += cursor->format.bytesPerPixel; + // Skip transparency - if (src[x] == colTransparent) + if (color == colTransparent) continue; - _overlayFormat.colorToRGB(src[x], r, g, b); + cursor->format.colorToRGB(color, r, g, b); const int col = (r << 16) | (g << 8) | b; // If there is no entry yet for this color in the palette: Add one @@ -1355,7 +1370,6 @@ bool ThemeEngine::createCursor(const Common::String &filename, int hotspotX, int const int index = colorToIndex[col]; _cursor[y * _cursorWidth + x] = index; } - src += _cursorWidth; } _useCursor = true; @@ -1787,5 +1801,20 @@ Common::String ThemeEngine::getThemeId(const Common::String &filename) { } } +void ThemeEngine::showCursor() { + if (_useCursor) { + CursorMan.pushCursorPalette(_cursorPal, 0, _cursorPalSize); + CursorMan.pushCursor(_cursor, _cursorWidth, _cursorHeight, _cursorHotspotX, _cursorHotspotY, 255, true); + CursorMan.showMouse(true); + } +} + +void ThemeEngine::hideCursor() { + if (_useCursor) { + CursorMan.popCursorPalette(); + CursorMan.popCursor(); + } +} + } // End of namespace GUI. diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h index 6e5fd291b7..c0e47a19e6 100644 --- a/gui/ThemeEngine.h +++ b/gui/ThemeEngine.h @@ -234,6 +234,14 @@ public: static const char *const kImageDelbtn; ///< Delete characters in the predictive dialog static const char *const kImageList; ///< List image used in save/load chooser selection static const char *const kImageGrid; ///< Grid image used in save/load chooser selection + static const char *const kImageStopbtn; ///< Stop recording button in recorder onscreen dialog + static const char *const kImageEditbtn; ///< Edit recording metadata in recorder onscreen dialog + static const char *const kImageSwitchModebtn; ///< Switch mode button in recorder onscreen dialog + static const char *const kImageFastReplaybtn; ///< Fast playback mode button in recorder onscreen dialog + static const char *const kImageStopSmallbtn; ///< Stop recording button in recorder onscreen dialog (for 320xY) + static const char *const kImageEditSmallbtn; ///< Edit recording metadata in recorder onscreen dialog (for 320xY) + static const char *const kImageSwitchModeSmallbtn; ///< Switch mode button in recorder onscreen dialog (for 320xY) + static const char *const kImageFastReplaySmallbtn; ///< Fast playback mode button in recorder onscreen dialog (for 320xY) /** * Graphics mode enumeration. @@ -242,8 +250,8 @@ public: */ enum GraphicsMode { kGfxDisabled = 0, ///< No GFX - kGfxStandard16bit, ///< 2BPP with the standard (aliased) renderer. - kGfxAntialias16bit ///< 2BPP with the optimized AA renderer. + kGfxStandard, ///< Standard (aliased) renderer. + kGfxAntialias ///< Optimized AA renderer. }; /** Constant value to expand dirty rectangles, to make sure they are fully copied */ @@ -275,8 +283,13 @@ public: void refresh(); void enable(); + + void showCursor(); + void hideCursor(); + void disable(); + /** * Query the set up pixel format. */ diff --git a/gui/about.cpp b/gui/about.cpp index 088971f273..20145886c6 100644 --- a/gui/about.cpp +++ b/gui/about.cpp @@ -46,7 +46,7 @@ enum { // 0 - 2 -- set a custom color: // 0 normal text // 1 highlighted text -// 2 disabled text +// 2 disabled text // TODO: Maybe add a tab/indent feature; that is, make it possible to specify // an amount by which that line shall be indented (the indent of course would have // to be considered while performing any word wrapping, too). @@ -139,7 +139,7 @@ void AboutDialog::addLine(const char *str) { } else { Common::String format(str, 2); str += 2; - + static Common::String asciiStr; if (format[0] == 'A') { bool useAscii = false; diff --git a/gui/chooser.cpp b/gui/chooser.cpp index 6ae08161df..c195e94c9b 100644 --- a/gui/chooser.cpp +++ b/gui/chooser.cpp @@ -67,6 +67,7 @@ void ChooserDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data break; case kCloseCmd: setResult(-1); + // Fall through default: Dialog::handleCommand(sender, cmd, data); } diff --git a/gui/credits.h b/gui/credits.h index 81d46b2b73..70f79ac9a5 100644 --- a/gui/credits.h +++ b/gui/credits.h @@ -294,9 +294,6 @@ static const char *credits[] = { "C0""Andre Heider", "C0""Angus Lees", "", -"C1""BADA", -"C0""Chris Warren-Smith", -"", "C1""Dreamcast", "C0""Marcus Comstedt", "", @@ -352,6 +349,9 @@ static const char *credits[] = { "C0""Jurgen Braam", "C0""Lars Persson", "", +"C1""Tizen / BADA", +"C0""Chris Warren-Smith", +"", "C1""WebOS", "C0""Klaus Reimer", "", diff --git a/gui/dialog.h b/gui/dialog.h index 1773c6633e..d269a2f645 100644 --- a/gui/dialog.h +++ b/gui/dialog.h @@ -37,6 +37,8 @@ struct Event; namespace GUI { +class EventRecorder; + class Widget; // Some "common" commands sent to handleCommand() @@ -47,6 +49,7 @@ enum { class Dialog : public GuiObject { friend class GuiManager; + friend class EventRecorder; friend class Tooltip; protected: Widget *_mouseWidget; diff --git a/gui/editrecorddialog.cpp b/gui/editrecorddialog.cpp new file mode 100644 index 0000000000..cfcc747121 --- /dev/null +++ b/gui/editrecorddialog.cpp @@ -0,0 +1,87 @@ +/* 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 "editrecorddialog.h" +#include "gui/widgets/edittext.h" +#include "common/translation.h" + + +namespace GUI { + +const Common::String EditRecordDialog::getAuthor() { + return _authorEdit->getEditString(); +} + +void EditRecordDialog::setAuthor(const Common::String &author) { + _authorEdit->setEditString(author); +} + +const Common::String EditRecordDialog::getNotes() { + return _notesEdit->getEditString(); +} + +void EditRecordDialog::setNotes(const Common::String &desc) { + _notesEdit->setEditString(desc); +} + +const Common::String EditRecordDialog::getName() { + return _nameEdit->getEditString(); +} + +void EditRecordDialog::setName(const Common::String &name) { + _nameEdit->setEditString(name); +} + +EditRecordDialog::~EditRecordDialog() { +} + +EditRecordDialog::EditRecordDialog(const Common::String author, const Common::String name, const Common::String notes) : Dialog("EditRecordDialog") { + new StaticTextWidget(this,"EditRecordDialog.AuthorLabel",_("Author:")); + new StaticTextWidget(this,"EditRecordDialog.NameLabel",_("Name:")); + new StaticTextWidget(this,"EditRecordDialog.NotesLabel",_("Notes:")); + _authorEdit = new EditTextWidget(this, "EditRecordDialog.AuthorEdit",""); + _notesEdit = new EditTextWidget(this, "EditRecordDialog.NotesEdit",""); + _nameEdit = new EditTextWidget(this, "EditRecordDialog.NameEdit",""); + _authorEdit->setEditString(author); + _notesEdit->setEditString(notes); + _nameEdit->setEditString(name); + new GUI::ButtonWidget(this, "EditRecordDialog.Cancel", _("Cancel"), 0, kCloseCmd); + new GUI::ButtonWidget(this, "EditRecordDialog.OK", _("Ok"), 0, kOKCmd); +} + +void EditRecordDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) { + switch(cmd) { + case kCloseCmd: + setResult(kCloseCmd); + close(); + break; + case kOKCmd: + setResult(kOKCmd); + close(); + break; + default: + Dialog::handleCommand(sender, cmd, data); + break; + } +} + +} diff --git a/gui/editrecorddialog.h b/gui/editrecorddialog.h new file mode 100644 index 0000000000..c8da4521ca --- /dev/null +++ b/gui/editrecorddialog.h @@ -0,0 +1,56 @@ +/* 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 GUI_EDITRECORDDIALOG_H +#define GUI_EDITRECORDDIALOG_H + +#include "gui/dialog.h" + +namespace GUI { + +class EditTextWidget; +class StaticTextWidget; + +class EditRecordDialog : public Dialog { +private: + EditTextWidget *_notesEdit; + EditTextWidget *_nameEdit; + EditTextWidget *_authorEdit; + EditRecordDialog() : Dialog("EditRecordDialog") {}; +public: + EditRecordDialog(const Common::String author, const Common::String name, const Common::String notes); + ~EditRecordDialog(); + + const Common::String getAuthor(); + const Common::String getNotes(); + const Common::String getName(); + + void setAuthor(const Common::String &author); + void setNotes(const Common::String &desc); + void setName(const Common::String &name); + + virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); +}; + +}// End of namespace GUI + +#endif diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp index a0ef4216aa..1505c8c707 100644 --- a/gui/gui-manager.cpp +++ b/gui/gui-manager.cpp @@ -27,6 +27,7 @@ #include "common/rect.h" #include "common/textconsole.h" #include "common/translation.h" +#include "gui/EventRecorder.h" #include "backends/keymapper/keymapper.h" @@ -253,12 +254,15 @@ Dialog *GuiManager::getTopDialog() const { void GuiManager::runLoop() { Dialog * const activeDialog = getTopDialog(); bool didSaveState = false; - int button; - uint32 time; if (activeDialog == 0) return; +#ifdef ENABLE_EVENTRECORDER + // Suspend recording while GUI is shown + g_eventRec.suspendRecording(); +#endif + if (!_stateIsSaved) { saveState(); _theme->enable(); @@ -296,10 +300,10 @@ void GuiManager::runLoop() { // _theme->updateScreen(); // _system->updateScreen(); - if (lastRedraw + waitTime < _system->getMillis()) { + if (lastRedraw + waitTime < _system->getMillis(true)) { _theme->updateScreen(); _system->updateScreen(); - lastRedraw = _system->getMillis(); + lastRedraw = _system->getMillis(true); } Common::Event event; @@ -314,72 +318,21 @@ void GuiManager::runLoop() { if (activeDialog != getTopDialog() && event.type != Common::EVENT_SCREEN_CHANGED) continue; - Common::Point mouse(event.mouse.x - activeDialog->_x, event.mouse.y - activeDialog->_y); - - switch (event.type) { - case Common::EVENT_KEYDOWN: - activeDialog->handleKeyDown(event.kbd); - break; - case Common::EVENT_KEYUP: - activeDialog->handleKeyUp(event.kbd); - break; - case Common::EVENT_MOUSEMOVE: - activeDialog->handleMouseMoved(mouse.x, mouse.y, 0); - - if (mouse.x != _lastMousePosition.x || mouse.y != _lastMousePosition.y) { - _lastMousePosition.x = mouse.x; - _lastMousePosition.y = mouse.y; - _lastMousePosition.time = _system->getMillis(); - } + processEvent(event, activeDialog); + if (event.type == Common::EVENT_MOUSEMOVE) { tooltipCheck = true; - break; - // We don't distinguish between mousebuttons (for now at least) - case Common::EVENT_LBUTTONDOWN: - case Common::EVENT_RBUTTONDOWN: - button = (event.type == Common::EVENT_LBUTTONDOWN ? 1 : 2); - time = _system->getMillis(); - if (_lastClick.count && (time < _lastClick.time + kDoubleClickDelay) - && ABS(_lastClick.x - event.mouse.x) < 3 - && ABS(_lastClick.y - event.mouse.y) < 3) { - _lastClick.count++; - } else { - _lastClick.x = event.mouse.x; - _lastClick.y = event.mouse.y; - _lastClick.count = 1; - } - _lastClick.time = time; - activeDialog->handleMouseDown(mouse.x, mouse.y, button, _lastClick.count); - break; - case Common::EVENT_LBUTTONUP: - case Common::EVENT_RBUTTONUP: - button = (event.type == Common::EVENT_LBUTTONUP ? 1 : 2); - activeDialog->handleMouseUp(mouse.x, mouse.y, button, _lastClick.count); - break; - case Common::EVENT_WHEELUP: - activeDialog->handleMouseWheel(mouse.x, mouse.y, -1); - break; - case Common::EVENT_WHEELDOWN: - activeDialog->handleMouseWheel(mouse.x, mouse.y, 1); - break; - case Common::EVENT_SCREEN_CHANGED: - screenChange(); - break; - default: -#ifdef ENABLE_KEYMAPPER - activeDialog->handleOtherEvent(event); -#endif - break; } - if (lastRedraw + waitTime < _system->getMillis()) { + + if (lastRedraw + waitTime < _system->getMillis(true)) { _theme->updateScreen(); _system->updateScreen(); - lastRedraw = _system->getMillis(); + lastRedraw = _system->getMillis(true); } } - if (tooltipCheck && _lastMousePosition.time + kTooltipDelay < _system->getMillis()) { + if (tooltipCheck && _lastMousePosition.time + kTooltipDelay < _system->getMillis(true)) { Widget *wdg = activeDialog->findWidget(_lastMousePosition.x, _lastMousePosition.y); if (wdg && wdg->hasTooltip() && !(wdg->getFlags() & WIDGET_PRESSED)) { Tooltip *tooltip = new Tooltip(); @@ -409,6 +362,11 @@ void GuiManager::runLoop() { restoreState(); _useStdCursor = false; } + +#ifdef ENABLE_EVENTRECORDER + // Resume recording once GUI is shown + g_eventRec.resumeRecording(); +#endif } #pragma mark - @@ -492,7 +450,7 @@ void GuiManager::setupCursor() { // very much. We could plug in a different cursor here if we like to. void GuiManager::animateCursor() { - int time = _system->getMillis(); + int time = _system->getMillis(true); if (time > _cursorAnimateTimer + kCursorAnimateDelay) { for (int i = 0; i < 15; i++) { if ((i < 6) || (i > 8)) { @@ -537,4 +495,64 @@ void GuiManager::screenChange() { _system->updateScreen(); } +void GuiManager::processEvent(const Common::Event &event, Dialog *const activeDialog) { + int button; + uint32 time; + Common::Point mouse(event.mouse.x - activeDialog->_x, event.mouse.y - activeDialog->_y); + switch (event.type) { + case Common::EVENT_KEYDOWN: + activeDialog->handleKeyDown(event.kbd); + break; + case Common::EVENT_KEYUP: + activeDialog->handleKeyUp(event.kbd); + break; + case Common::EVENT_MOUSEMOVE: + activeDialog->handleMouseMoved(mouse.x, mouse.y, 0); + + if (mouse.x != _lastMousePosition.x || mouse.y != _lastMousePosition.y) { + _lastMousePosition.x = mouse.x; + _lastMousePosition.y = mouse.y; + _lastMousePosition.time = _system->getMillis(true); + } + + break; + // We don't distinguish between mousebuttons (for now at least) + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_RBUTTONDOWN: + button = (event.type == Common::EVENT_LBUTTONDOWN ? 1 : 2); + time = _system->getMillis(true); + if (_lastClick.count && (time < _lastClick.time + kDoubleClickDelay) + && ABS(_lastClick.x - event.mouse.x) < 3 + && ABS(_lastClick.y - event.mouse.y) < 3) { + _lastClick.count++; + } else { + _lastClick.x = event.mouse.x; + _lastClick.y = event.mouse.y; + _lastClick.count = 1; + } + _lastClick.time = time; + activeDialog->handleMouseDown(mouse.x, mouse.y, button, _lastClick.count); + break; + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONUP: + button = (event.type == Common::EVENT_LBUTTONUP ? 1 : 2); + activeDialog->handleMouseUp(mouse.x, mouse.y, button, _lastClick.count); + break; + case Common::EVENT_WHEELUP: + activeDialog->handleMouseWheel(mouse.x, mouse.y, -1); + break; + case Common::EVENT_WHEELDOWN: + activeDialog->handleMouseWheel(mouse.x, mouse.y, 1); + break; + case Common::EVENT_SCREEN_CHANGED: + screenChange(); + break; + default: + #ifdef ENABLE_KEYMAPPER + activeDialog->handleOtherEvent(event); + #endif + break; + } +} + } // End of namespace GUI diff --git a/gui/gui-manager.h b/gui/gui-manager.h index 49542fd001..b52d91ba08 100644 --- a/gui/gui-manager.h +++ b/gui/gui-manager.h @@ -35,6 +35,10 @@ namespace Graphics { class Font; } +namespace Common { + struct Event; +} + namespace GUI { class Dialog; @@ -67,6 +71,8 @@ public: // until no dialogs are active anymore. void runLoop(); + void processEvent(const Common::Event &event, Dialog *const activeDialog); + bool isActive() const { return ! _dialogStack.empty(); } bool loadNewTheme(Common::String id, ThemeEngine::GraphicsMode gfx = ThemeEngine::kGfxDisabled, bool force = false); diff --git a/gui/launcher.cpp b/gui/launcher.cpp index 4e35b54db8..77d4cce794 100644 --- a/gui/launcher.cpp +++ b/gui/launcher.cpp @@ -37,6 +37,11 @@ #include "gui/message.h" #include "gui/gui-manager.h" #include "gui/options.h" +#ifdef ENABLE_EVENTRECORDER +#include "gui/onscreendialog.h" +#include "gui/recorderdialog.h" +#include "gui/EventRecorder.h" +#endif #include "gui/saveload.h" #include "gui/widgets/edittext.h" #include "gui/widgets/list.h" @@ -596,7 +601,6 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat LauncherDialog::LauncherDialog() : Dialog(0, 0, 320, 200) { _backgroundType = GUI::ThemeEngine::kDialogBackgroundMain; - const int screenW = g_system->getOverlayWidth(); const int screenH = g_system->getOverlayHeight(); @@ -779,10 +783,9 @@ void LauncherDialog::updateListing() { } void LauncherDialog::addGame() { - int modifiers = g_system->getEventManager()->getModifierState(); #ifndef DISABLE_MASS_ADD - const bool massAdd = (modifiers & Common::KBD_SHIFT) != 0; + const bool massAdd = checkModifier(Common::KBD_SHIFT); if (massAdd) { MessageDialog alert(_("Do you really want to run the mass game detector? " @@ -975,6 +978,49 @@ void LauncherDialog::editGame(int item) { } } +void LauncherDialog::loadGameButtonPressed(int item) { +#ifdef ENABLE_EVENTRECORDER + const bool shiftPressed = checkModifier(Common::KBD_SHIFT); + if (shiftPressed) { + recordGame(item); + } else { + loadGame(item); + } + updateButtons(); +#else + loadGame(item); +#endif +} + +#ifdef ENABLE_EVENTRECORDER +void LauncherDialog::recordGame(int item) { + RecorderDialog recorderDialog; + MessageDialog alert(_("Do you want to load savegame?"), + _("Yes"), _("No")); + switch(recorderDialog.runModal(_domains[item])) { + case RecorderDialog::kRecordDialogClose: + break; + case RecorderDialog::kRecordDialogPlayback: + ConfMan.setActiveDomain(_domains[item]); + close(); + ConfMan.set("record_mode", "playback", ConfigManager::kTransientDomain); + ConfMan.set("record_file_name", recorderDialog.getFileName(), ConfigManager::kTransientDomain); + break; + case RecorderDialog::kRecordDialogRecord: + ConfMan.setActiveDomain(_domains[item]); + if (alert.runModal() == GUI::kMessageOK) { + loadGame(item); + } + close(); + g_eventRec.setAuthor(recorderDialog._author); + g_eventRec.setName(recorderDialog._name); + g_eventRec.setNotes(recorderDialog._notes); + ConfMan.set("record_mode", "record", ConfigManager::kTransientDomain); + break; + } +} +#endif + void LauncherDialog::loadGame(int item) { String gameId = ConfMan.get("gameid", _domains[item]); if (gameId.empty()) @@ -1039,7 +1085,7 @@ void LauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat editGame(item); break; case kLoadGameCmd: - loadGame(item); + loadGameButtonPressed(item); break; case kOptionsCmd: { GlobalOptionsDialog options; @@ -1109,20 +1155,28 @@ void LauncherDialog::updateButtons() { _loadButton->setEnabled(en); _loadButton->draw(); } + switchButtonsText(_addButton, "~A~dd Game...", "Mass Add..."); +#ifdef ENABLE_EVENTRECORDER + switchButtonsText(_loadButton, "~L~oad...", "Record..."); +#endif +} - // Update the label of the "Add" button depending on whether shift is pressed or not - int modifiers = g_system->getEventManager()->getModifierState(); - const bool massAdd = (modifiers & Common::KBD_SHIFT) != 0; +// Update the label of the button depending on whether shift is pressed or not +void LauncherDialog::switchButtonsText(ButtonWidget *button, const char *normalText, const char *shiftedText) { + const bool shiftPressed = checkModifier(Common::KBD_SHIFT); const bool lowRes = g_system->getOverlayWidth() <= 320; - const char *newAddButtonLabel = massAdd - ? (lowRes ? _c("Mass Add...", "lowres") : _("Mass Add...")) - : (lowRes ? _c("~A~dd Game...", "lowres") : _("~A~dd Game...")); + const char *newAddButtonLabel = shiftPressed + ? (lowRes ? _c(shiftedText, "lowres") : _(shiftedText)) + : (lowRes ? _c(normalText, "lowres") : _(normalText)); - if (_addButton->getLabel() != newAddButtonLabel) - _addButton->setLabel(newAddButtonLabel); + if (button->getLabel() != newAddButtonLabel) + button->setLabel(newAddButtonLabel); } + + + void LauncherDialog::reflowLayout() { #ifndef DISABLE_FANCY_THEMES if (g_gui.xmlEval()->getVar("Globals.ShowLauncherLogo") == 1 && g_gui.theme()->supportsImages()) { @@ -1186,4 +1240,9 @@ void LauncherDialog::reflowLayout() { Dialog::reflowLayout(); } +bool LauncherDialog::checkModifier(int checkedModifier) { + int modifiers = g_system->getEventManager()->getModifierState(); + return (modifiers & checkedModifier) != 0; +} + } // End of namespace GUI diff --git a/gui/launcher.h b/gui/launcher.h index fc0484350a..2ab47be98d 100644 --- a/gui/launcher.h +++ b/gui/launcher.h @@ -56,7 +56,7 @@ protected: ListWidget *_list; ButtonWidget *_addButton; Widget *_startButton; - Widget *_loadButton; + ButtonWidget *_loadButton; Widget *_editButton; Widget *_removeButton; #ifndef DISABLE_FANCY_THEMES @@ -80,6 +80,7 @@ protected: void updateListing(); void updateButtons(); + void switchButtonsText(ButtonWidget *button, const char *normalText, const char *shiftedText); void open(); void close(); @@ -100,6 +101,16 @@ protected: void editGame(int item); /** + * Facade for "Load..."/"Record..." buttons. + */ + void loadGameButtonPressed(int item); + + /** + * Handle "Record..." button. + */ + void recordGame(int item); + + /** * Handle "Load..." button. */ void loadGame(int item); @@ -111,6 +122,8 @@ protected: * @target name of target to select */ void selectTarget(const String &target); +private: + bool checkModifier(int modifier); }; } // End of namespace GUI diff --git a/gui/module.mk b/gui/module.mk index bda3c88cd5..338e43c6a4 100644 --- a/gui/module.mk +++ b/gui/module.mk @@ -7,6 +7,7 @@ MODULE_OBJS := \ debugger.o \ dialog.o \ error.o \ + EventRecorder.o \ gui-manager.o \ launcher.o \ massadd.o \ @@ -38,6 +39,13 @@ MODULE_OBJS += \ browser.o endif +ifdef ENABLE_EVENTRECORDER +MODULE_OBJS += \ + editrecorddialog.o \ + onscreendialog.o \ + recorderdialog.o +endif + ifdef USE_FLUIDSYNTH MODULE_OBJS += \ fluidsynth-dialog.o diff --git a/gui/onscreendialog.cpp b/gui/onscreendialog.cpp new file mode 100644 index 0000000000..03a6f26ec0 --- /dev/null +++ b/gui/onscreendialog.cpp @@ -0,0 +1,233 @@ +/* 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 "gui/gui-manager.h" + +#include "gui/EventRecorder.h" + +#include "common/events.h" +#include "common/rect.h" +#include "common/translation.h" + +#include "graphics/cursorman.h" + +#include "gui/editrecorddialog.h" +#include "gui/ThemeEval.h" + +#include "gui/onscreendialog.h" + +namespace GUI { + +bool OnScreenDialog::isVisible() const { + return true; +} + +enum { + kStopCmd = 'STOP', + kEditCmd = 'EDIT', + kSwitchModeCmd = 'MODE', + kFastModeCmd = 'FAST' +}; + +void OnScreenDialog::reflowLayout() { + GuiObject::reflowLayout(); +} + +void OnScreenDialog::releaseFocus() { +} + +OnScreenDialog::OnScreenDialog(bool isRecord) : Dialog("OnScreenDialog") { + _x = _y = 0; + +#ifndef DISABLE_FANCY_THEMES + if (g_gui.xmlEval()->getVar("Globals.OnScreenDialog.ShowPics") == 1 && g_gui.theme()->supportsImages()) { + GUI::PicButtonWidget *btn; + btn = new PicButtonWidget(this, "OnScreenDialog.StopButton", 0, kStopCmd, 0); + btn->useThemeTransparency(true); + + if (g_system->getOverlayWidth() > 320) + btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageStopbtn)); + else + btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageStopSmallbtn)); + + if (isRecord) { + btn = new PicButtonWidget(this, "OnScreenDialog.EditButton", 0, kEditCmd, 0); + btn->useThemeTransparency(true); + + if (g_system->getOverlayWidth() > 320) + btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageEditbtn)); + else + btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageEditSmallbtn)); + } else { + btn = new PicButtonWidget(this, "OnScreenDialog.SwitchModeButton", 0, kSwitchModeCmd, 0); + btn->useThemeTransparency(true); + if (g_system->getOverlayWidth() > 320) + btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageSwitchModebtn)); + else + btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageSwitchModeSmallbtn)); + + btn = new PicButtonWidget(this, "OnScreenDialog.FastReplayButton", 0, kFastModeCmd, 0); + btn->useThemeTransparency(true); + if (g_system->getOverlayWidth() > 320) + btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageFastReplaybtn)); + else + btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageFastReplaySmallbtn)); + } + } else +#endif + { + if (g_system->getOverlayWidth() > 320) + new ButtonWidget(this, "OnScreenDialog.StopButton", "[ ]", _("Stop"), kStopCmd); + else + new ButtonWidget(this, "OnScreenDialog.StopButton", "[]", _("Stop"), kStopCmd); + + if (isRecord) { + new ButtonWidget(this, "OnScreenDialog.EditButton", "E", _("Edit record description"), kEditCmd); + } else { + new ButtonWidget(this, "OnScreenDialog.SwitchModeButton", "G", _("Switch to Game"), kSwitchModeCmd); + + new ButtonWidget(this, "OnScreenDialog.FastReplayButton", ">>", _("Fast replay"), kFastModeCmd); + } + } + + + _text = new GUI::StaticTextWidget(this, "OnScreenDialog.TimeLabel", "00:00:00"); + _enableDrag = false; + _mouseOver = false; + _editDlgShown = false; + + _lastTime = 0; + _dlg = 0; +} + +void OnScreenDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { + Common::Event eventRTL; + switch (cmd) { + case kStopCmd: + eventRTL.type = Common::EVENT_RTL; + g_system->getEventManager()->pushEvent(eventRTL); + close(); + break; + case kEditCmd: + _dlg = new EditRecordDialog(g_eventRec.getAuthor(), g_eventRec.getName(), g_eventRec.getNotes()); + CursorMan.lock(false); + g_eventRec.setRedraw(false); + g_system->showOverlay(); + _editDlgShown = true; + _dlg->runModal(); + _editDlgShown = false; + g_system->hideOverlay(); + g_eventRec.setRedraw(true); + CursorMan.lock(true); + g_eventRec.setAuthor(((EditRecordDialog *)_dlg)->getAuthor()); + g_eventRec.setName(((EditRecordDialog *)_dlg)->getName()); + g_eventRec.setNotes(((EditRecordDialog *)_dlg)->getNotes()); + delete _dlg; + break; + case kSwitchModeCmd: + if (g_eventRec.switchMode()) { + close(); + } + break; + case kFastModeCmd: + g_eventRec.switchFastMode(); + break; + } +} + +void OnScreenDialog::setReplayedTime(uint32 newTime) { + if (newTime - _lastTime > 1000) { + uint32 seconds = newTime / 1000; + _text->setLabel(Common::String::format("%.2d:%.2d:%.2d", seconds / 3600 % 24, seconds / 60 % 60, seconds % 60)); + _lastTime = newTime; + } +} + +OnScreenDialog::~OnScreenDialog() { +} + +void OnScreenDialog::handleMouseMoved(int x, int y, int button) { + if (_enableDrag) { + _x = _x + x - _dragPoint.x; + _y = _y + y - _dragPoint.y; + } + Dialog::handleMouseMoved(x, y, button); + if (isMouseOver(x, y)) { + if (_mouseOver == false) { + g_gui.theme()->showCursor(); + CursorMan.lock(true); + } + _mouseOver = true; + } else { + if (_mouseOver == true) { + CursorMan.lock(false); + g_gui.theme()->hideCursor(); + } + _mouseOver = false; + } +} + +void OnScreenDialog::handleMouseDown(int x, int y, int button, int clickCount) { + if (isMouseOver(x, y)) { + _dragPoint.x = x; + _dragPoint.y = y; + _enableDrag = true; + } + Dialog::handleMouseDown(x, y, button, clickCount); +} + +void OnScreenDialog::handleMouseUp(int x, int y, int button, int clickCount) { + if (isMouseOver(x, y)) { + + } + _enableDrag = false; + Dialog::handleMouseUp(x, y, button, clickCount); +} + +bool OnScreenDialog::isMouseOver(int x, int y) { + return (x >= 0 && x < _w && y >= 0 && y < _h); +} + +bool OnScreenDialog::isMouseOver() { + return _mouseOver; +} + +void OnScreenDialog::close() { + CursorMan.lock(false); + Dialog::close(); +} + +Dialog *OnScreenDialog::getActiveDlg() { + if (_editDlgShown) { + return _dlg; + } else { + return this; + } +} + +bool OnScreenDialog::isEditDlgVisible() { + return _editDlgShown; +} + +} diff --git a/gui/onscreendialog.h b/gui/onscreendialog.h new file mode 100644 index 0000000000..2fae14cbc6 --- /dev/null +++ b/gui/onscreendialog.h @@ -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. + * + */ + +#ifndef GUI_ONSCREENDIALOG_H +#define GUI_ONSCREENDIALOG_H + +#include "gui/dialog.h" +#include "gui/widget.h" + +namespace GUI { + +class OnScreenDialog : public Dialog { +private: + uint32 _lastTime; + bool _enableDrag; + bool _mouseOver; + bool _editDlgShown; + Common::Point _dragPoint; + GUI::StaticTextWidget *_text; + Dialog *_dlg; + + bool isMouseOver(int x, int y); + +public: + OnScreenDialog(bool recordingMode); + ~OnScreenDialog(); + virtual void close(); + virtual bool isVisible() const; + virtual void reflowLayout(); + + void setReplayedTime(uint32 newTime); + + virtual void handleMouseMoved(int x, int y, int button); + virtual void handleMouseDown(int x, int y, int button, int clickCount); + virtual void handleMouseUp(int x, int y, int button, int clickCount); + void handleCommand(CommandSender *sender, uint32 cmd, uint32 data); + + bool isMouseOver(); + bool isEditDlgVisible(); + Dialog *getActiveDlg(); +protected: + virtual void releaseFocus(); +}; + +} // End of namespace GUI + +#endif diff --git a/gui/recorderdialog.cpp b/gui/recorderdialog.cpp new file mode 100644 index 0000000000..1a11dbac65 --- /dev/null +++ b/gui/recorderdialog.cpp @@ -0,0 +1,298 @@ +/* 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/algorithm.h" +#include "common/bufferedstream.h" +#include "common/savefile.h" +#include "common/system.h" +#include "graphics/colormasks.h" +#include "graphics/palette.h" +#include "graphics/scaler.h" +#include "graphics/thumbnail.h" +#include "common/translation.h" +#include "gui/widgets/list.h" +#include "gui/editrecorddialog.h" +#include "gui/EventRecorder.h" +#include "gui/message.h" +#include "gui/saveload.h" +#include "common/system.h" +#include "gui/ThemeEval.h" +#include "gui/gui-manager.h" +#include "recorderdialog.h" + +#define MAX_RECORDS_NAMES 0xFF + +namespace GUI { + +enum { + kRecordCmd = 'RCRD', + kPlaybackCmd = 'PBCK', + kDeleteCmd = 'DEL ', + kNextScreenshotCmd = 'NEXT', + kPrevScreenshotCmd = 'PREV', + kEditRecordCmd = 'EDIT' +}; + +RecorderDialog::RecorderDialog() : Dialog("RecorderDialog"), _list(0), _currentScreenshot(0) { + _firstScreenshotUpdate = false; + _screenShotsCount = 0; + _currentScreenshotText = 0; + _authorText = 0; + _notesText = 0; + + _backgroundType = ThemeEngine::kDialogBackgroundSpecial; + + new StaticTextWidget(this, "SaveLoadChooser.Title", _("Recorder or Playback Gameplay")); + + _list = new GUI::ListWidget(this, "RecorderDialog.List"); + _list->setNumberingMode(GUI::kListNumberingOff); + + _deleteButton = new GUI::ButtonWidget(this, "RecorderDialog.Delete", _("Delete"), 0, kDeleteCmd); + new GUI::ButtonWidget(this, "RecorderDialog.Cancel", _("Cancel"), 0, kCloseCmd); + new GUI::ButtonWidget(this, "RecorderDialog.Record", _("Record"), 0, kRecordCmd); + _playbackButton = new GUI::ButtonWidget(this, "RecorderDialog.Playback", _("Playback"), 0, kPlaybackCmd); + + _editButton = new GUI::ButtonWidget(this, "RecorderDialog.Edit", _("Edit"), 0, kEditRecordCmd); + + _editButton->setEnabled(false); + _deleteButton->setEnabled(false); + _playbackButton->setEnabled(false); + + _gfxWidget = new GUI::GraphicsWidget(this, 0, 0, 10, 10); + _container = new GUI::ContainerWidget(this, 0, 0, 10, 10); + if (g_gui.xmlEval()->getVar("Globals.RecorderDialog.ExtInfo.Visible") == 1) { + new GUI::ButtonWidget(this,"RecorderDialog.NextScreenShotButton", "<", 0, kPrevScreenshotCmd); + new GUI::ButtonWidget(this, "RecorderDialog.PreviousScreenShotButton", ">", 0, kNextScreenshotCmd); + _currentScreenshotText = new StaticTextWidget(this, "RecorderDialog.currentScreenshot", "0/0"); + _authorText = new StaticTextWidget(this, "RecorderDialog.Author", _("Author: ")); + _notesText = new StaticTextWidget(this, "RecorderDialog.Notes", _("Notes: ")); + } + if (_gfxWidget) + _gfxWidget->setGfx(0); +} + + +void RecorderDialog::reflowLayout() { + if (g_gui.xmlEval()->getVar("Globals.RecorderDialog.ExtInfo.Visible") == 1) { + int16 x, y; + uint16 w, h; + + if (!g_gui.xmlEval()->getWidgetData("RecorderDialog.Thumbnail", x, y, w, h)) { + error("Error when loading position data for Recorder Thumbnails"); + } + + int thumbW = kThumbnailWidth; + int thumbH = kThumbnailHeight2; + int thumbX = x + (w >> 1) - (thumbW >> 1); + int thumbY = y + kLineHeight; + + _container->resize(x, y, w, h); + _gfxWidget->resize(thumbX, thumbY, thumbW, thumbH); + + _container->setVisible(true); + _gfxWidget->setVisible(true); + updateSelection(false); + } else { + _container->setVisible(false); + _gfxWidget->setVisible(false); + } + Dialog::reflowLayout(); +} + + + +void RecorderDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { + switch(cmd) { + case kEditRecordCmd: { + if (_list->getSelected() >= 0) { + EditRecordDialog editDlg(_fileHeaders[_list->getSelected()].author, _fileHeaders[_list->getSelected()].name, _fileHeaders[_list->getSelected()].notes); + if (editDlg.runModal() != kOKCmd) { + return; + } + _playbackFile.openRead(_fileHeaders[_list->getSelected()].fileName); + _playbackFile.getHeader().author = editDlg.getAuthor(); + _playbackFile.getHeader().name = editDlg.getName(); + _playbackFile.getHeader().notes = editDlg.getNotes(); + _playbackFile.updateHeader(); + _fileHeaders[_list->getSelected()] = _playbackFile.getHeader(); + int oldselection = _list->getSelected(); + updateList(); + _list->setSelected(oldselection); + updateSelection(true); + _playbackFile.close(); + } + } + break; + case kNextScreenshotCmd: + ++_currentScreenshot; + updateScreenshot(); + break; + case kPrevScreenshotCmd: + --_currentScreenshot; + updateScreenshot(); + break; + case kDeleteCmd: + if (_list->getSelected() >= 0) { + MessageDialog alert(_("Do you really want to delete this record?"), + _("Delete"), _("Cancel")); + if (alert.runModal() == GUI::kMessageOK) { + _playbackFile.close(); + g_eventRec.deleteRecord(_fileHeaders[_list->getSelected()].fileName); + _list->setSelected(-1); + updateList(); + } + } + break; + case GUI::kListSelectionChangedCmd: + updateSelection(true); + break; + case kRecordCmd: { + TimeDate t; + Common::String gameId = ConfMan.get("gameid", _target); + const EnginePlugin *plugin = 0; + GameDescriptor desc = EngineMan.findGame(gameId, &plugin); + g_system->getTimeAndDate(t); + EditRecordDialog editDlg("Unknown Author", Common::String::format("%.2d.%.2d.%.4d ", t.tm_mday, t.tm_mon, 1900 + t.tm_year) + desc.description(), ""); + if (editDlg.runModal() != kOKCmd) { + return; + } + _author = editDlg.getAuthor(); + _name = editDlg.getName(); + _notes = editDlg.getNotes(); + _filename = g_eventRec.generateRecordFileName(_target); + setResult(kRecordDialogRecord); + close(); + } + break; + case kPlaybackCmd: + if (_list->getSelected() >= 0) { + _filename = _fileHeaders[_list->getSelected()].fileName; + setResult(kRecordDialogPlayback); + close(); + } + break; + case kCloseCmd: + setResult(kRecordDialogClose); + // Fall through + default: + Dialog::handleCommand(sender, cmd, data); + } +} + +void RecorderDialog::updateList() { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::String pattern(_target+".r??"); + Common::StringArray files = saveFileMan->listSavefiles(pattern); + Common::PlaybackFile file; + Common::StringArray namesList; + _fileHeaders.clear(); + for (Common::StringArray::iterator i = files.begin(); i != files.end(); ++i) { + if (file.openRead(*i)) { + namesList.push_back(file.getHeader().name); + _fileHeaders.push_back(file.getHeader()); + } + file.close(); + } + _list->setList(namesList); + _list->draw(); +} + +int RecorderDialog::runModal(Common::String &target) { + _target = target; + updateList(); + return Dialog::runModal(); +} + +RecorderDialog::~RecorderDialog() { +} + +void RecorderDialog::updateSelection(bool redraw) { + if (_list->getSelected() >= 0) { + _editButton->setEnabled(true); + _deleteButton->setEnabled(true); + _playbackButton->setEnabled(true); + } + + if (g_gui.xmlEval()->getVar("Globals.RecorderDialog.ExtInfo.Visible") != 1) + return; + + _gfxWidget->setGfx(-1, -1, 0, 0, 0); + _screenShotsCount = 0; + _currentScreenshot = 0; + updateScreenShotsText(); + if (_list->getSelected() >= 0) { + _authorText->setLabel(_("Author: ") + _fileHeaders[_list->getSelected()].author); + _notesText->setLabel(_("Notes: ") + _fileHeaders[_list->getSelected()].notes); + + _firstScreenshotUpdate = true; + updateScreenshot(); + if ((_screenShotsCount) > 0) { + _currentScreenshot = 1; + } + updateScreenshot(); + } else { + _authorText->setLabel(_("Author: ")); + _notesText->setLabel(_("Notes: ")); + _screenShotsCount = -1; + _currentScreenshot = 0; + _gfxWidget->setGfx(-1, -1, 0, 0, 0); + _gfxWidget->draw(); + updateScreenShotsText(); + } +} + +void RecorderDialog::updateScreenshot() { + if (_list->getSelected() == -1) { + return; + } + if (_currentScreenshot < 1) { + _currentScreenshot = _screenShotsCount; + } + if (_currentScreenshot > _screenShotsCount) { + _currentScreenshot = 1; + } + if (_firstScreenshotUpdate) { + _playbackFile.openRead(_fileHeaders[_list->getSelected()].fileName); + _screenShotsCount = _playbackFile.getScreensCount(); + _firstScreenshotUpdate = false; + } + Graphics::Surface *srcsf = _playbackFile.getScreenShot(_currentScreenshot); + if (srcsf != NULL) { + Graphics::Surface *destsf = Graphics::scale(*srcsf, _gfxWidget->getWidth(), _gfxWidget->getHeight()); + _gfxWidget->setGfx(destsf); + updateScreenShotsText(); + delete destsf; + delete srcsf; + } else { + _gfxWidget->setGfx(-1, -1, 0, 0, 0); + } + _gfxWidget->draw(); +} + +void RecorderDialog::updateScreenShotsText() { + if (_screenShotsCount == -1) { + _currentScreenshotText->setLabel(Common::String::format("%d / ?", _currentScreenshot)); + } else { + _currentScreenshotText->setLabel(Common::String::format("%d / %d", _currentScreenshot, _screenShotsCount)); + } +} + +} // End of namespace GUI diff --git a/gui/recorderdialog.h b/gui/recorderdialog.h new file mode 100644 index 0000000000..eb690a4f38 --- /dev/null +++ b/gui/recorderdialog.h @@ -0,0 +1,81 @@ +/* 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 GUI_RECORDER_DIALOG_H +#define GUI_RECORDER_DIALOG_H +#include "common/stream.h" +#include "common/recorderfile.h" +#include "gui/dialog.h" +namespace GUI { + +class ListWidget; +class GraphicsWidget; +class ButtonWidget; +class CommandSender; +class ContainerWidget; +class StaticTextWidget; + +class RecorderDialog : public GUI::Dialog { +private: + bool _firstScreenshotUpdate; + Common::PlaybackFile _playbackFile; + Common::String _target; + Common::String _filename; + int _currentScreenshot; + int _screenShotsCount; + Common::Array<Common::PlaybackFile::PlaybackFileHeader> _fileHeaders; + GUI::ListWidget *_list; + GUI::ContainerWidget *_container; + GUI::GraphicsWidget *_gfxWidget; + GUI::StaticTextWidget *_currentScreenshotText; + GUI::StaticTextWidget *_authorText; + GUI::StaticTextWidget *_notesText; + GUI::ButtonWidget *_editButton; + GUI::ButtonWidget *_deleteButton; + GUI::ButtonWidget *_playbackButton; + + void updateList(); + void updateScreenShotsText(); + void updateSelection(bool redraw); + void updateScreenshot(); +public: + Common::String _author; + Common::String _name; + Common::String _notes; + enum DialogResult { + kRecordDialogClose, + kRecordDialogRecord, + kRecordDialogPlayback + }; + RecorderDialog(); + ~RecorderDialog(); + + virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); + virtual void reflowLayout(); + + int runModal(Common::String &target); + const Common::String getFileName() {return _filename;} +}; + +} // End of namespace GUI + + +#endif diff --git a/gui/saveload-dialog.cpp b/gui/saveload-dialog.cpp index c7dd62b6c6..585117fba4 100644 --- a/gui/saveload-dialog.cpp +++ b/gui/saveload-dialog.cpp @@ -286,6 +286,7 @@ void SaveLoadChooserSimple::handleCommand(CommandSender *sender, uint32 cmd, uin break; case kCloseCmd: setResult(-1); + // Fall through default: SaveLoadChooserDialog::handleCommand(sender, cmd, data); } @@ -595,6 +596,7 @@ void SaveLoadChooserGrid::handleCommand(CommandSender *sender, uint32 cmd, uint3 case kCloseCmd: setResult(-1); + // Fall through default: SaveLoadChooserDialog::handleCommand(sender, cmd, data); } diff --git a/gui/themes/default.inc b/gui/themes/default.inc index 6d8e6baac7..352cc86852 100644 --- a/gui/themes/default.inc +++ b/gui/themes/default.inc @@ -1,142 +1,142 @@ "<?xml version = '1.0'?>" -"<render_info> " -"<palette> " +"<render_info>" +"<palette>" "<color name='black' " "rgb='0,0,0' " -"/> " +"/>" "<color name='lightgrey' " "rgb='104,104,104' " -"/> " +"/>" "<color name='darkgrey' " "rgb='64,64,64' " -"/> " +"/>" "<color name='green' " "rgb='32,160,32' " -"/> " +"/>" "<color name='green2' " "rgb='0,255,0' " -"/> " -"</palette> " -"<fonts> " +"/>" +"</palette>" +"<fonts>" "<font id='text_default' " "file='helvb12.bdf' " -"/> " +"/>" "<font resolution='y<400' " "id='text_default' " "file='clR6x12.bdf' " -"/> " +"/>" "<font id='text_button' " "file='helvb12.bdf' " -"/> " +"/>" "<font resolution='y<400' " "id='text_button' " "file='clR6x12.bdf' " -"/> " +"/>" "<font id='text_normal' " "file='helvb12.bdf' " -"/> " +"/>" "<font resolution='y<400' " "id='text_normal' " "file='clR6x12.bdf' " -"/> " +"/>" "<font id='tooltip_normal' " "file='fixed5x8.bdf' " -"/> " +"/>" "<text_color id='color_normal' " "color='green' " -"/> " +"/>" "<text_color id='color_normal_inverted' " "color='black' " -"/> " +"/>" "<text_color id='color_normal_hover' " "color='green2' " -"/> " +"/>" "<text_color id='color_normal_disabled' " "color='lightgrey' " -"/> " +"/>" "<text_color id='color_alternative' " "color='lightgrey' " -"/> " +"/>" "<text_color id='color_alternative_inverted' " "color='255,255,255' " -"/> " +"/>" "<text_color id='color_alternative_hover' " "color='176,176,176' " -"/> " +"/>" "<text_color id='color_alternative_disabled' " "color='darkgrey' " -"/> " +"/>" "<text_color id='color_button' " "color='green' " -"/> " +"/>" "<text_color id='color_button_hover' " "color='green2' " -"/> " +"/>" "<text_color id='color_button_disabled' " "color='lightgrey' " -"/> " -"</fonts> " -"<defaults fill='foreground' fg_color='darkgrey' bg_color='black' shadow='0' bevel_color='lightgrey'/> " -"<drawdata id='text_selection' cache='false'> " +"/>" +"</fonts>" +"<defaults fill='foreground' fg_color='darkgrey' bg_color='black' shadow='0' bevel_color='lightgrey'/>" +"<drawdata id='text_selection' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='lightgrey' " -"/> " -"</drawdata> " -"<drawdata id='text_selection_focus' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='text_selection_focus' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='green' " -"/> " -"</drawdata> " -"<drawdata id='mainmenu_bg' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='mainmenu_bg' cache='false'>" "<drawstep func='fill' " "fill='foreground' " "fg_color='black' " -"/> " -"</drawdata> " -"<drawdata id='special_bg' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='special_bg' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " -"/> " -"</drawdata> " -"<drawdata id='tooltip_bg' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='tooltip_bg' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='foreground' " "fg_color='black' " -"/> " -"</drawdata> " -"<drawdata id='separator' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='separator' cache='false'>" "<drawstep func='square' " "fill='foreground' " "height='2' " "ypos='center' " "fg_color='lightgrey' " -"/> " -"</drawdata> " -"<drawdata id='scrollbar_base' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='scrollbar_base' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " -"/> " -"</drawdata> " -"<drawdata id='scrollbar_handle_hover' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='scrollbar_handle_hover' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='green2' " -"/> " -"</drawdata> " -"<drawdata id='scrollbar_handle_idle' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='scrollbar_handle_idle' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='green' " -"/> " -"</drawdata> " -"<drawdata id='scrollbar_button_idle' cache='false' resolution='y>399'> " +"/>" +"</drawdata>" +"<drawdata id='scrollbar_button_idle' cache='false' resolution='y>399'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -146,13 +146,13 @@ "ypos='center' " "padding='0,0,3,0' " "orientation='top' " -"/> " -"</drawdata> " -"<drawdata id='scrollbar_button_idle' cache='false' resolution='y<400'> " +"/>" +"</drawdata>" +"<drawdata id='scrollbar_button_idle' cache='false' resolution='y<400'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -162,13 +162,13 @@ "ypos='center' " "padding='0,0,2,0' " "orientation='top' " -"/> " -"</drawdata> " -"<drawdata id='scrollbar_button_hover' cache='false' resolution='y>399'> " +"/>" +"</drawdata>" +"<drawdata id='scrollbar_button_hover' cache='false' resolution='y>399'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -178,13 +178,13 @@ "ypos='center' " "padding='0,0,3,0' " "orientation='top' " -"/> " -"</drawdata> " -"<drawdata id='scrollbar_button_hover' cache='false' resolution='y<400'> " +"/>" +"</drawdata>" +"<drawdata id='scrollbar_button_hover' cache='false' resolution='y<400'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -194,69 +194,69 @@ "ypos='center' " "padding='0,0,2,0' " "orientation='top' " -"/> " -"</drawdata> " -"<drawdata id='tab_active' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='tab_active' cache='false'>" "<text font='text_default' " "text_color='color_normal_hover' " "vertical_align='center' " "horizontal_align='center' " -"/> " +"/>" "<drawstep func='tab' " "bevel='2' " "radius='0' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='tab_inactive' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='tab_inactive' cache='false'>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " "horizontal_align='center' " -"/> " +"/>" "<drawstep func='tab' " "bevel='2' " "radius='0' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='tab_background' cache='false'> " -"</drawdata> " -"<drawdata id='widget_slider' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='tab_background' cache='false'>" +"</drawdata>" +"<drawdata id='widget_slider' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='slider_disabled' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='slider_disabled' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='lightgrey' " -"/> " -"</drawdata> " -"<drawdata id='slider_full' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='slider_full' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='green' " -"/> " -"</drawdata> " -"<drawdata id='slider_hover' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='slider_hover' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='green2' " -"/> " -"</drawdata> " -"<drawdata id='widget_small' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='widget_small' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='popup_idle' cache='false' resolution='y>399'> " +"/>" +"</drawdata>" +"<drawdata id='popup_idle' cache='false' resolution='y>399'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -266,7 +266,7 @@ "ypos='10' " "padding='0,0,7,0' " "orientation='bottom' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -276,18 +276,18 @@ "ypos='4' " "padding='0,0,7,0' " "orientation='top' " -"/> " +"/>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " "horizontal_align='left' " -"/> " -"</drawdata> " -"<drawdata id='popup_idle' cache='false' resolution='y<400'> " +"/>" +"</drawdata>" +"<drawdata id='popup_idle' cache='false' resolution='y<400'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -297,7 +297,7 @@ "ypos='9' " "padding='0,0,3,0' " "orientation='bottom' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -307,18 +307,18 @@ "ypos='4' " "padding='0,0,3,0' " "orientation='top' " -"/> " +"/>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " "horizontal_align='left' " -"/> " -"</drawdata> " -"<drawdata id='popup_disabled' cache='false' resolution='y>399'> " +"/>" +"</drawdata>" +"<drawdata id='popup_disabled' cache='false' resolution='y>399'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -328,7 +328,7 @@ "ypos='10' " "padding='0,0,7,0' " "orientation='bottom' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -338,18 +338,18 @@ "ypos='4' " "padding='0,0,7,0' " "orientation='top' " -"/> " +"/>" "<text font='text_default' " "text_color='color_normal_disabled' " "vertical_align='center' " "horizontal_align='left' " -"/> " -"</drawdata> " -"<drawdata id='popup_disabled' cache='false' resolution='y<400'> " +"/>" +"</drawdata>" +"<drawdata id='popup_disabled' cache='false' resolution='y<400'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -359,7 +359,7 @@ "ypos='9' " "padding='0,0,3,0' " "orientation='bottom' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -369,18 +369,18 @@ "ypos='4' " "padding='0,0,3,0' " "orientation='top' " -"/> " +"/>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " "horizontal_align='left' " -"/> " -"</drawdata> " -"<drawdata id='popup_hover' cache='false' resolution='y>399'> " +"/>" +"</drawdata>" +"<drawdata id='popup_hover' cache='false' resolution='y>399'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -390,7 +390,7 @@ "ypos='10' " "padding='0,0,7,0' " "orientation='bottom' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -400,18 +400,18 @@ "ypos='4' " "padding='0,0,7,0' " "orientation='top' " -"/> " +"/>" "<text font='text_default' " "text_color='color_normal_hover' " "vertical_align='center' " "horizontal_align='left' " -"/> " -"</drawdata> " -"<drawdata id='popup_hover' cache='false' resolution='y<400'> " +"/>" +"</drawdata>" +"<drawdata id='popup_hover' cache='false' resolution='y<400'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -421,7 +421,7 @@ "ypos='9' " "padding='0,0,3,0' " "orientation='bottom' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -431,123 +431,123 @@ "ypos='4' " "padding='0,0,3,0' " "orientation='top' " -"/> " +"/>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " "horizontal_align='left' " -"/> " -"</drawdata> " -"<drawdata id='widget_textedit' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='widget_textedit' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='plain_bg' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='plain_bg' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " -"/> " -"</drawdata> " -"<drawdata id='caret' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='caret' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='lightgrey' " -"/> " -"</drawdata> " -"<drawdata id='default_bg' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='default_bg' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " -"/> " -"</drawdata> " -"<drawdata id='button_pressed' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='button_pressed' cache='false'>" "<text font='text_button' " "text_color='color_alternative_inverted' " "vertical_align='center' " "horizontal_align='center' " -"/> " +"/>" "<drawstep func='square' " "fill='foreground' " "fg_color='green' " -"/> " -"</drawdata> " -"<drawdata id='button_idle' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='button_idle' cache='false'>" "<text font='text_button' " "text_color='color_button' " "vertical_align='center' " "horizontal_align='center' " -"/> " +"/>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='button_hover' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='button_hover' cache='false'>" "<text font='text_button' " "text_color='color_button_hover' " "vertical_align='center' " "horizontal_align='center' " -"/> " +"/>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='button_disabled' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='button_disabled' cache='false'>" "<text font='text_button' " "text_color='color_button_disabled' " "vertical_align='center' " "horizontal_align='center' " -"/> " +"/>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='checkbox_disabled' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='checkbox_disabled' cache='false'>" "<text font='text_default' " "text_color='color_normal_disabled' " "vertical_align='top' " "horizontal_align='left' " -"/> " +"/>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='checkbox_selected' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='checkbox_selected' cache='false'>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='top' " "horizontal_align='left' " -"/> " +"/>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='cross' " "fill='foreground' " "stroke='2' " "fg_color='green' " -"/> " -"</drawdata> " -"<drawdata id='checkbox_default' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='checkbox_default' cache='false'>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='top' " "horizontal_align='left' " -"/> " +"/>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='radiobutton_default' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='radiobutton_default' cache='false'>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " "horizontal_align='left' " -"/> " +"/>" "<drawstep func='circle' " "width='7' " "height='7' " @@ -556,14 +556,14 @@ "bg_color='darkgrey' " "xpos='0' " "ypos='0' " -"/> " -"</drawdata> " -"<drawdata id='radiobutton_selected' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='radiobutton_selected' cache='false'>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " "horizontal_align='left' " -"/> " +"/>" "<drawstep func='circle' " "width='7' " "height='7' " @@ -572,7 +572,7 @@ "fill='none' " "xpos='0' " "ypos='0' " -"/> " +"/>" "<drawstep func='circle' " "width='7' " "height='7' " @@ -581,14 +581,14 @@ "fill='foreground' " "xpos='2' " "ypos='2' " -"/> " -"</drawdata> " -"<drawdata id='radiobutton_disabled' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='radiobutton_disabled' cache='false'>" "<text font='text_default' " "text_color='color_normal_disabled' " "vertical_align='center' " "horizontal_align='left' " -"/> " +"/>" "<drawstep func='circle' " "width='7' " "height='7' " @@ -597,2286 +597,2510 @@ "fill='background' " "xpos='0' " "ypos='0' " -"/> " -"</drawdata> " -"<drawdata id='widget_default' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='widget_default' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " -"/> " -"</drawdata> " -"<drawdata id='widget_small' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='widget_small' cache='false'>" "<drawstep func='square' " "stroke='0' " -"/> " -"</drawdata> " -"</render_info> " -"<layout_info resolution='y<400'> " -"<globals> " -"<def var='Line.Height' value='12' /> " -"<def var='Font.Height' value='10' /> " -"<def var='About.OuterBorder' value='10'/> " -"<def var='Layout.Spacing' value='8'/> " -"<def var='ShowLauncherLogo' value='0'/> " -"<def var='ShowGlobalMenuLogo' value='0'/> " -"<def var='ShowSearchPic' value='0'/> " -"<def var='ShowChooserPics' value='0'/> " -"<def var='ShowChooserPageDisplay' value='0'/> " -"<def var='SaveLoadChooser.ExtInfo.Visible' value='0'/> " -"<def var='KeyMapper.Spacing' value='5'/> " -"<def var='KeyMapper.LabelWidth' value='80'/> " -"<def var='KeyMapper.ButtonWidth' value='60'/> " -"<def var='Tooltip.MaxWidth' value='70'/> " -"<def var='Tooltip.XDelta' value='8'/> " -"<def var='Tooltip.YDelta' value='8'/> " -"<def var='Predictive.Button.Width' value='45' /> " -"<def var='Predictive.Button.Height' value='15' /> " -"<widget name='Button' " -"size='72,16' " -"/> " -"<widget name='Slider' " -"size='85,12' " -"/> " +"/>" +"</drawdata>" +"</render_info>" +"<layout_info resolution='y>399'>" +"<globals>" +"<def var='Line.Height' value='16' />" +"<def var='Font.Height' value='16' />" +"<def var='About.OuterBorder' value='80'/>" +"<def var='Layout.Spacing' value='8' />" +"<def var='ShowLauncherLogo' value='0'/>" +"<def var='ShowGlobalMenuLogo' value='0'/>" +"<def var='ShowSearchPic' value='0'/>" +"<def var='ShowChooserPics' value='0'/>" +"<def var='ShowChooserPageDisplay' value='1'/>" +"<def var='SaveLoadChooser.ExtInfo.Visible' value='1'/>" +"<def var='RecorderDialog.ExtInfo.Visible' value='1'/>" +"<def var='OnScreenDialog.ShowPics' value='0'/>" +"<def var='KeyMapper.Spacing' value='10'/>" +"<def var='KeyMapper.LabelWidth' value='100'/>" +"<def var='KeyMapper.ButtonWidth' value='80'/>" +"<def var='Tooltip.MaxWidth' value='200'/>" +"<def var='Tooltip.XDelta' value='16'/> " +"<def var='Tooltip.YDelta' value='16'/>" +"<def var='Predictive.Button.Width' value='60' />" "<widget name='OptionsLabel' " "size='110,Globals.Line.Height' " "textalign='right' " -"/> " +"/>" "<widget name='SmallLabel' " -"size='18,Globals.Line.Height' " -"/> " +"size='24,Globals.Line.Height' " +"/>" +"<widget name='ShortOptionsLabel' " +"size='60,Globals.Line.Height' " +"/>" +"<widget name='Button' " +"size='108,24' " +"/>" +"<widget name='Slider' " +"size='128,18' " +"/>" "<widget name='PopUp' " -"size='-1,15' " -"/> " +"size='-1,19' " +"/>" "<widget name='Checkbox' " -"size='-1,Globals.Line.Height' " -"/> " +"size='-1,14' " +"/>" "<widget name='Radiobutton' " "size='-1,Globals.Line.Height' " -"/> " +"/>" "<widget name='ListWidget' " -"padding='5,0,0,0' " -"/> " +"padding='5,0,8,0' " +"/>" "<widget name='PopUpWidget' " "padding='7,5,0,0' " -"/> " +"/>" "<widget name='EditTextWidget' " "padding='5,5,0,0' " -"/> " +"/>" "<widget name='Console' " "padding='7,5,5,5' " -"/> " +"/>" "<widget name='Scrollbar' " -"size='9,0' " -"/> " +"size='15,0' " +"/>" "<widget name='TabWidget.Tab' " -"size='45,16' " -"padding='0,0,2,0' " -"/> " +"size='75,27' " +"padding='0,0,8,0' " +"/>" "<widget name='TabWidget.Body' " -"padding='0,0,0,-8' " -"/> " +"padding='0,0,0,0' " +"/>" "<widget name='TabWidget.NavButton' " -"size='32,18' " -"padding='0,0,1,0' " -"/> " -"</globals> " -"<dialog name='Launcher' overlays='screen'> " -"<layout type='vertical' center='true' padding='6,6,2,2'> " +"size='15,18' " +"padding='0,3,4,0' " +"/>" +"<widget name='EditRecordLabel' " +"size='60,25' " +"/>" +"<widget name='EditRecord' " +"size='240,25' " +"/>" +"</globals>" +"<dialog name='Launcher' overlays='screen'>" +"<layout type='vertical' center='true' padding='16,16,8,8'>" "<widget name='Version' " "height='Globals.Line.Height' " "textalign='center' " -"/> " -"<layout type='horizontal' spacing='5' padding='0,0,0,0'> " +"/>" +"<layout type='horizontal' spacing='5' padding='10,0,0,0'>" "<widget name='SearchDesc' " -"width='50' " +"width='60' " "height='Globals.Line.Height' " "textalign='right' " -"/> " +"/>" "<widget name='Search' " "width='150' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='SearchClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"<space /> " -"</layout> " -"<widget name='GameList'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='8'> " +"/>" +"<space />" +"</layout>" +"<widget name='GameList'/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10'>" "<widget name='LoadGameButton' " -"height='12' " -"/> " +"height='20' " +"/>" "<widget name='AddGameButton' " -"height='12' " -"/> " +"height='20' " +"/>" "<widget name='EditGameButton' " -"height='12' " -"/> " +"height='20' " +"/>" "<widget name='RemoveGameButton' " -"height='12' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='8'> " +"height='20' " +"/>" +"</layout>" +"<space size='4'/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10'>" "<widget name='QuitButton' " -"height='12' " -"/> " +"height='20' " +"/>" "<widget name='AboutButton' " -"height='12' " -"/> " +"height='20' " +"/>" "<widget name='OptionsButton' " -"height='12' " -"/> " +"height='20' " +"/>" "<widget name='StartButton' " -"height='12' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='Browser' overlays='screen' inset='8' shading='dim'> " -"<layout type='vertical' padding='8,8,0,4'> " +"height='20' " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='Browser' overlays='Dialog.Launcher.GameList' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8'>" "<widget name='Headline' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Path' " "height='Globals.Line.Height' " -"/> " -"<widget name='List'/> " -"<layout type='vertical' padding='0,0,8,0'> " +"/>" +"<widget name='List'/>" +"<layout type='vertical' padding='0,0,16,0'>" "<widget name='Hidden' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='Up' " "type='Button' " -"/> " -"<space/> " +"/>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Choose' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions' overlays='screen' inset='16' shading='dim'> " -"<layout type='vertical' padding='0,0,0,0'> " -"<widget name='TabWidget'/> " -"<layout type='horizontal' padding='8,8,8,8'> " -"<space/> " +"/>" +"</layout>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions' overlays='Dialog.Launcher.GameList' shading='dim'>" +"<layout type='vertical' padding='0,0,0,0'>" +"<widget name='TabWidget'/>" +"<layout type='horizontal' padding='16,16,16,16'>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='grModePopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='grModePopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='grRenderPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='grRenderPopup' " "type='PopUp' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='grAspectCheckbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='grFullscreenCheckbox' " "type='Checkbox' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='auMidiPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auMidiPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='auOPLPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auOPLPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='auSampleRatePopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auSampleRatePopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='3' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10'>" "<widget name='subToggleDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='subToggleSpeechOnly' " "type='Radiobutton' " -"/> " +"/>" "<widget name='subToggleSubOnly' " "type='Radiobutton' " -"/> " +"/>" "<widget name='subToggleSubBoth' " "type='Radiobutton' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10'>" "<widget name='subSubtitleSpeedDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='subSubtitleSpeedSlider' " "type='Slider' " -"/> " +"/>" "<widget name='subSubtitleSpeedLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='horizontal' padding='16,16,16,16' spacing='8'>" +"<layout type='vertical' padding='0,0,0,0' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='vcMusicText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcMusicSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcMusicLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='vcSfxText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSfxSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSfxLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='vcSpeechText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSpeechSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSpeechLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " -"<space size='110' /> " +"/>" +"</layout>" +"</layout>" +"<layout type='vertical' padding='24,0,24,0' center='true'>" "<widget name='vcMuteCheckbox' " "type='Checkbox' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='6'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='auPrefGmPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auPrefGmPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='mcFontButton' " "type='Button' " -"/> " +"/>" "<widget name='mcFontPath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='mcFontClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='mcMixedCheckbox' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='mcMidiGainText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='mcMidiGainSlider' " "type='Slider' " -"/> " +"/>" "<widget name='mcMidiGainLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='mcFluidSynthSettings' " -"width='150' " +"width='200' " "height='Globals.Button.Height' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='auPrefMt32PopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auPrefMt32Popup' " "type='PopUp' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='mcMt32Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='mcGSCheckbox' " "type='Checkbox' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Paths' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Paths' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='SaveButton' " "type='Button' " -"/> " +"/>" "<widget name='SavePath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='SavePathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='ThemeButton' " "type='Button' " -"/> " +"/>" "<widget name='ThemePath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='ThemePathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='ExtraButton' " "type='Button' " -"/> " +"/>" "<widget name='ExtraPath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='ExtraPathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16'>" "<widget name='PluginsButton' " "type='Button' " -"/> " +"/>" "<widget name='PluginsPath' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Misc' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Misc' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='ThemeButton' " "type='Button' " -"/> " +"/>" "<widget name='CurTheme' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='RendererPopupDesc' " -"width='80' " -"height='Globals.Line.Height' " -"textalign='right' " -"/> " +"type='OptionsLabel' " +"/>" "<widget name='RendererPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='AutosavePeriodPopupDesc' " -"width='80' " -"height='Globals.Line.Height' " -"textalign='right' " -"/> " +"type='OptionsLabel' " +"/>" "<widget name='AutosavePeriodPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='GuiLanguagePopupDesc' " -"width='80' " -"height='Globals.Line.Height' " -"textalign='right' " -"/> " +"type='OptionsLabel' " +"/>" "<widget name='GuiLanguagePopup' " "type='PopUp' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='KeysButton' " "type='Button' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='KeysDialog' overlays='Dialog.GlobalOptions' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='KeysDialog' overlays='Dialog.GlobalOptions' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" "<widget name='Action' " "height='Globals.Line.Height' " -"/> " -"<widget name='List'/> " +"/>" +"<widget name='List'/>" "<widget name='Mapping' " "height='Globals.Line.Height' " -"/> " -"<space size='Globals.Line.Height'/> " -"<layout type='horizontal'> " +"/>" +"<space size='Globals.Line.Height'/>" +"<layout type='horizontal'>" "<widget name='Map' " "type='Button' " -"/> " -"<space/> " +"/>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions' overlays='screen' inset='16' shading='dim'> " -"<layout type='vertical' padding='0,0,0,0' spacing='16'> " -"<widget name='TabWidget'/> " -"<layout type='horizontal' padding='8,8,8,8'> " -"<space/> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions' overlays='Dialog.Launcher.GameList' shading='dim'>" +"<layout type='vertical' padding='0,0,0,0' spacing='16'>" +"<widget name='TabWidget'/>" +"<layout type='horizontal' padding='16,16,16,4'>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_Graphics' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"/>" +"<import layout='Dialog.GlobalOptions_Graphics' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_Audio' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"/>" +"<import layout='Dialog.GlobalOptions_Audio' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_MIDI' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"/>" +"<import layout='Dialog.GlobalOptions_MIDI' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_MT32' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"/>" +"<import layout='Dialog.GlobalOptions_MT32' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_Volume' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Game' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"<import layout='Dialog.GlobalOptions_Volume' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Game' overlays='Dialog.GameOptions.TabWidget' shading='dim'>" +"<layout type='vertical' padding='16,16,16,16'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='Id' " -"width='35' " -"height='Globals.Line.Height' " -"textalign='right' " -"/> " +"type='OptionsLabel' " +"/>" "<widget name='Domain' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='Name' " -"width='35' " -"height='Globals.Line.Height' " -"textalign='right' " -"/> " +"type='OptionsLabel' " +"/>" "<widget name='Desc' " "type='PopUp' " -"/> " -"</layout> " -"<space size='8'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='LangPopupDesc' " -"width='60' " -"height='Globals.Line.Height' " -"textalign='right' " -"/> " +"type='OptionsLabel' " +"/>" "<widget name='LangPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='PlatformPopupDesc' " -"width='60' " -"height='Globals.Line.Height' " -"textalign='right' " -"/> " +"type='OptionsLabel' " +"/>" "<widget name='PlatformPopup' " "type='PopUp' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Paths' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Paths' overlays='Dialog.GameOptions.TabWidget' shading='dim'>" +"<layout type='vertical' padding='16,16,16,16'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='Savepath' " "type='Button' " -"/> " +"/>" "<widget name='SavepathText' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='SavePathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='Extrapath' " "type='Button' " -"/> " +"/>" "<widget name='ExtrapathText' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='ExtraPathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='Gamepath' " "type='Button' " -"/> " +"/>" "<widget name='GamepathText' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Engine' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Engine' overlays='Dialog.GameOptions.TabWidget' shading='dim'>" +"<layout type='vertical' padding='16,16,16,16'>" "<widget name='customOption1Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption2Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption3Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption4Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption5Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption6Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption7Checkbox' " "type='Checkbox' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalMenu' overlays='screen_center'> " -"<layout type='vertical' padding='2,2,4,6' center='true' spacing='6'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalMenu' overlays='screen_center'>" +"<layout type='vertical' padding='16,16,16,16' center='true'>" "<widget name='Title' " -"width='160' " -"height='4' " -"/> " +"width='210' " +"height='Globals.Line.Height' " +"/>" "<widget name='Version' " -"width='160' " -"height='4' " -"/> " -"<space size='1'/> " +"width='210' " +"height='Globals.Line.Height' " +"/>" +"<widget name='Resume' " +"width='150' " +"height='Globals.Button.Height' " +"/>" +"<space size='10'/>" "<widget name='Load' " -"width='120' " -"height='12' " -"/> " +"width='150' " +"height='Globals.Button.Height' " +"/>" "<widget name='Save' " -"width='120' " -"height='12' " -"/> " -"<space size='1'/> " +"width='150' " +"height='Globals.Button.Height' " +"/>" +"<space size='10'/>" "<widget name='Options' " -"width='120' " -"height='12' " -"/> " +"width='150' " +"height='Globals.Button.Height' " +"/>" "<widget name='Help' " -"width='120' " -"height='12' " -"/> " +"width='150' " +"height='Globals.Button.Height' " +"/>" "<widget name='About' " -"width='120' " -"height='12' " -"/> " -"<space size='1'/> " -"<widget name='Resume' " -"width='120' " -"height='12' " -"/> " +"width='150' " +"height='Globals.Button.Height' " +"/>" +"<space size='10'/>" "<widget name='RTL' " -"width='120' " -"height='12' " -"/> " +"width='150' " +"height='Globals.Button.Height' " +"/>" "<widget name='Quit' " -"width='120' " -"height='12' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalConfig' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"width='150' " +"height='Globals.Button.Height' " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalConfig' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8'>" +"<layout type='horizontal' padding='0,0,0,0'>" +"<layout type='vertical' padding='0,0,0,0' center='true'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='8'>" "<widget name='vcMusicText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcMusicSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcMusicLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='8'>" "<widget name='vcSfxText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSfxSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSfxLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='8'>" "<widget name='vcSpeechText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSpeechSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSpeechLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " -"<space size='110' /> " +"/>" +"</layout>" +"</layout>" +"<layout type='vertical' padding='24,24,24,24' center='true'>" "<widget name='vcMuteCheckbox' " "type='Checkbox' " -"width='80' " -"/> " -"</layout> " -"<layout type='vertical' padding='0,0,0,0' spacing='1' center='true'> " +"width='80' " +"/>" +"</layout>" +"</layout>" +"<space size='8' />" +"<layout type='horizontal' padding='0,0,0,0' spacing='10'>" "<widget name='subToggleDesc' " "type='OptionsLabel' " -"/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" "<widget name='subToggleSpeechOnly' " "type='Radiobutton' " -"width='90' " -"/> " +"width='100' " +"/>" "<widget name='subToggleSubOnly' " "type='Radiobutton' " -"width='90' " -"/> " +"width='100' " +"/>" "<widget name='subToggleSubBoth' " "type='Radiobutton' " -"width='90' " -"/> " -"</layout> " -"</layout> " -"<space size='2' /> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"width='100' " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10'>" "<widget name='subSubtitleSpeedDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='subSubtitleSpeedSlider' " "type='Slider' " -"/> " +"/>" "<widget name='subSubtitleSpeedLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<space size='16'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='4'> " +"/>" +"</layout>" +"<space size='60'/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10'>" "<widget name='Keys' " "type='Button' " -"/> " -"<space size='Globals.Button.Width' /> " +"/>" +"<space size='Globals.Button.Width' />" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings' overlays='GlobalOptions' shading='dim'> " -"<layout type='vertical' padding='0,0,0,0'> " -"<widget name='TabWidget'/> " -"<layout type='horizontal' padding='8,8,8,8'> " -"<space/> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings' overlays='GlobalOptions' shading='dim'>" +"<layout type='vertical' padding='0,0,0,0'>" +"<widget name='TabWidget'/>" +"<layout type='horizontal' padding='16,16,16,16'>" +"<space/>" "<widget name='ResetSettings' " "type='Button' " -"/> " +"/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings_Chorus' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings_Chorus' overlays='Dialog.FluidSynthSettings.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='VoiceCountText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='VoiceCountSlider' " "type='Slider' " -"/> " +"/>" "<widget name='VoiceCountLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='LevelText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='LevelSlider' " "type='Slider' " -"/> " +"/>" "<widget name='LevelLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='SpeedText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='SpeedSlider' " "type='Slider' " -"/> " +"/>" "<widget name='SpeedLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='DepthText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='DepthSlider' " "type='Slider' " -"/> " +"/>" "<widget name='DepthLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='WaveFormTypeText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='WaveFormType' " "type='PopUp' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings_Reverb' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings_Reverb' overlays='Dialog.FluidSynthSettings.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='RoomSizeText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='RoomSizeSlider' " "type='Slider' " -"/> " +"/>" "<widget name='RoomSizeLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='DampingText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='DampingSlider' " "type='Slider' " -"/> " +"/>" "<widget name='DampingLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='WidthText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='WidthSlider' " "type='Slider' " -"/> " +"/>" "<widget name='WidthLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='LevelText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='LevelSlider' " "type='Slider' " -"/> " +"/>" "<widget name='LevelLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings_Misc' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings_Misc' overlays='Dialog.FluidSynthSettings.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='InterpolationText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='Interpolation' " "type='PopUp' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='SaveLoadChooser' overlays='screen' inset='8' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8' center='true'> " -"<widget name='Title' height='Globals.Line.Height'/> " -"<widget name='List' /> " -"<layout type='horizontal' padding='0,0,16,0'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='SaveLoadChooser' overlays='screen' inset='8' shading='dim'>" +"<layout type='vertical' padding='8,8,8,32' center='true'>" +"<layout type='horizontal' padding='0,0,0,0'>" +"<widget name='Title' " +"height='Globals.Line.Height' " +"/>" +"<space/>" +"<widget name='PageDisplay' " +"width='200' " +"height='Globals.Line.Height' " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,16' spacing='16'>" +"<widget name='List' />" +"<widget name='Thumbnail' " +"width='180' " +"height='200' " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='ListSwitch' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " +"/>" "<widget name='GridSwitch' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"<space/> " +"/>" +"<space/>" "<widget name='Delete' " "type='Button' " -"/> " -"<space size='16'/> " +"/>" +"<space size='32'/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Choose' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='SavenameDialog' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='SavenameDialog' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8'>" "<widget name='DescriptionText' " -"width='180' " +"width='320' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Description' " "height='19' " -"/> " -"<layout type='horizontal' padding='0,0,16,0'> " +"/>" +"<layout type='horizontal' padding='0,0,16,0'>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" +"<space size='96'/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='ScummHelp' overlays='screen'> " -"<layout type='vertical' padding='8,8,8,8'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='RecorderDialog' overlays='screen' inset='8' shading='dim'>" +"<layout type='vertical' padding='8,8,8,32' center='true'>" "<widget name='Title' " +"height='Globals.Line.Height' " +"/>" +"<layout type='horizontal' padding='0,0,0,16' spacing='16'>" +"<widget name='List' />" +"<layout type='vertical' padding='0,0,0,0'>" +"<widget name='Thumbnail' " "width='180' " +"height='170' " +"/>" +"<layout type='horizontal' padding='0,0,0,0'>" +"<widget name='NextScreenShotButton' " +"width='25' " +"height='25' " +"/>" +"<widget name='currentScreenshot' " +"width='125' " +"height='25' " +"textalign='center' " +"/>" +"<widget name='PreviousScreenShotButton' " +"width='25' " +"height='25' " +"/>" +"</layout>" +"<widget name='Author' height='Globals.Line.Height' />" +"<widget name='Notes' height='Globals.Line.Height' />" +"</layout>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0'>" +"<widget name='Delete' " +"type='Button' " +"/>" +"<space size='16'/>" +"<widget name='Cancel' " +"type='Button' " +"/>" +"<space size='16'/>" +"<widget name='Edit' " +"type='Button' " +"/>" +"<widget name='Record' " +"type='Button' " +"/>" +"<widget name='Playback' " +"type='Button' " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='OnScreenDialog' overlays='screen_center'>" +"<layout type='horizontal' spacing='5' padding='5,3,5,3' center='true'>" +"<widget name='StopButton' " +"width='32' " +"height='32' " +"/>" +"<widget name='EditButton' " +"width='32' " +"height='32' " +"/>" +"<widget name='SwitchModeButton' " +"width='32' " +"height='32' " +"/>" +"<widget name='FastReplayButton' " +"width='32' " +"height='32' " +"/>" +"<widget name='TimeLabel' " +"width='50' " +"height='30' " +"/>" +"</layout>" +"</dialog>" +"<dialog name='EditRecordDialog' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" +"<widget name='Title' " +"width='320' " "height='Globals.Line.Height' " -"/> " +"/>" +"<layout type='horizontal' spacing='5' padding='0,0,0,10'>" +"<widget name='AuthorLabel' " +"type='EditRecordLabel' " +"/>" +"<widget name='AuthorEdit' " +"type='EditRecord' " +"/>" +"</layout>" +"<layout type='horizontal' spacing='5' padding='0,0,0,10'>" +"<widget name='NameLabel' " +"type='EditRecordLabel' " +"/>" +"<widget name='NameEdit' " +"type='EditRecord' " +"/>" +"</layout>" +"<layout type='horizontal' spacing='5' padding='0,0,0,10'>" +"<widget name='NotesLabel' " +"type='EditRecordLabel' " +"/>" +"<widget name='NotesEdit' " +"type='EditRecord' " +"/>" +"</layout>" +"<layout type='horizontal' spacing='5' padding='0,0,0,10'>" +"<widget name='Cancel' " +"type='Button' " +"/>" +"<widget name='OK' " +"type='Button' " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='ScummHelp' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" +"<widget name='Title' " +"width='320' " +"height='Globals.Line.Height' " +"/>" "<widget name='HelpText' " -"height='140' " -"/> " -"<layout type='horizontal' padding='0,0,0,0'> " +"height='200' " +"/>" +"<layout type='horizontal' padding='0,0,16,0'>" "<widget name='Prev' " "type='Button' " -"/> " +"/>" "<widget name='Next' " "type='Button' " -"/> " -"<space size='32'/> " +"/>" +"<space size='32'/>" "<widget name='Close' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='LoomTownsDifficultyDialog' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='LoomTownsDifficultyDialog' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" "<widget name='Description1' " -"width='280' " +"width='320' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Description2' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Standard' " "type='Button' " -"/> " +"/>" "<widget name='Practice' " "type='Button' " -"/> " +"/>" "<widget name='Expert' " "type='Button' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='MassAdd' overlays='screen_center' shading='dim'> " -"<layout type='vertical' padding='4,4,16,4' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='MassAdd' overlays='screen_center' shading='dim'>" +"<layout type='vertical' padding='8,8,32,8' center='true'>" "<widget name='DirProgressText' " -"width='280' " +"width='480' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='GameProgressText' " -"width='280' " +"width='480' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='GameList' " -"width='280' " -"height='100' " -"/> " -"<layout type='horizontal' padding='4,4,4,4'> " +"width='480' " +"height='250' " +"/>" +"<layout type='horizontal' padding='8,8,8,8'>" "<widget name='Ok' " "type='Button' " -"/> " +"/>" "<widget name='Cancel' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='KeyMapper' overlays='screen_center' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8' spacing='10' center='true'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='KeyMapper' overlays='screen_center' shading='dim'>" +"<layout type='vertical' padding='8,8,32,8' spacing='10' center='true'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='PopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='Popup' " "type='PopUp' " -"width='150' " +"width='400' " "height='Globals.Line.Height' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='KeymapArea' " -"width='300' " -"height='120' " -"/> " +"width='600' " +"height='280' " +"/>" "<widget name='Close' " "type='Button' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='Predictive' overlays='screen_center'> " -"<layout type='vertical' padding='1,1,1,1' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='Predictive' overlays='screen_center'>" +"<layout type='vertical' padding='5,5,5,5' center='true'>" "<widget name='Headline' " "height='Globals.Line.Height' " -"width='150' " +"width='210' " "textalign='center' " -"/> " -"<layout type='horizontal' padding='3,3,3,3'> " +"/>" +"<layout type='horizontal' padding='5,5,5,5'>" "<widget name='Word' " -"width='120' " +"width='190' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='Delete' " "width='20' " -"height='Globals.Predictive.Button.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='3,3,3,3'> " +"height='Globals.Button.Height' " +"/>" +"</layout>" +"<space size='5' />" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Button1' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " -"/> " +"height='Globals.Button.Height' " +"/>" "<widget name='Button2' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " -"/> " +"height='Globals.Button.Height' " +"/>" "<widget name='Button3' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='3,3,3,3'> " +"height='Globals.Button.Height' " +"/>" +"</layout>" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Button4' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " -"/> " +"height='Globals.Button.Height' " +"/>" "<widget name='Button5' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " -"/> " +"height='Globals.Button.Height' " +"/>" "<widget name='Button6' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='3,3,3,3'> " +"height='Globals.Button.Height' " +"/>" +"</layout>" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Button7' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " -"/> " +"height='Globals.Button.Height' " +"/>" "<widget name='Button8' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " -"/> " +"height='Globals.Button.Height' " +"/>" "<widget name='Button9' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='3,3,3,0'> " +"height='Globals.Button.Height' " +"/>" +"</layout>" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Pre' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " -"/> " +"height='Globals.Button.Height' " +"/>" "<widget name='Button0' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " -"/> " +"height='Globals.Button.Height' " +"/>" "<widget name='Next' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " -"/> " -"</layout> " -"<space size='3' /> " -"<layout type='horizontal' padding='3,3,0,3'> " +"height='Globals.Button.Height' " +"/>" +"</layout>" +"<space size='5' />" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Add' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " -"/> " +"height='Globals.Button.Height' " +"/>" +"<space size='22'/>" "<widget name='Cancel' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " -"/> " +"height='Globals.Button.Height' " +"/>" "<widget name='OK' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"</layout_info> " -"<layout_info resolution='y>399'> " -"<globals> " -"<def var='Line.Height' value='16' /> " -"<def var='Font.Height' value='16' /> " -"<def var='About.OuterBorder' value='80'/> " -"<def var='Layout.Spacing' value='8' /> " -"<def var='ShowLauncherLogo' value='0'/> " -"<def var='ShowGlobalMenuLogo' value='0'/> " -"<def var='ShowSearchPic' value='0'/> " -"<def var='ShowChooserPics' value='0'/> " -"<def var='ShowChooserPageDisplay' value='1'/> " -"<def var='SaveLoadChooser.ExtInfo.Visible' value='1'/> " -"<def var='KeyMapper.Spacing' value='10'/> " -"<def var='KeyMapper.LabelWidth' value='100'/> " -"<def var='KeyMapper.ButtonWidth' value='80'/> " -"<def var='Tooltip.MaxWidth' value='200'/> " -"<def var='Tooltip.XDelta' value='16'/> " -"<def var='Tooltip.YDelta' value='16'/> " -"<def var='Predictive.Button.Width' value='60' /> " +"height='Globals.Button.Height' " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"</layout_info>" +"<layout_info resolution='y<400'>" +"<globals>" +"<def var='Line.Height' value='12' />" +"<def var='Font.Height' value='10' />" +"<def var='About.OuterBorder' value='10'/>" +"<def var='Layout.Spacing' value='8'/>" +"<def var='ShowLauncherLogo' value='0'/>" +"<def var='ShowGlobalMenuLogo' value='0'/>" +"<def var='ShowSearchPic' value='0'/>" +"<def var='ShowChooserPics' value='0'/>" +"<def var='ShowChooserPageDisplay' value='0'/>" +"<def var='SaveLoadChooser.ExtInfo.Visible' value='0'/>" +"<def var='RecorderDialog.ExtInfo.Visible' value='0'/>" +"<def var='OnScreenDialog.ShowPics' value='0'/>" +"<def var='KeyMapper.Spacing' value='5'/>" +"<def var='KeyMapper.LabelWidth' value='80'/>" +"<def var='KeyMapper.ButtonWidth' value='60'/>" +"<def var='Tooltip.MaxWidth' value='70'/>" +"<def var='Tooltip.XDelta' value='8'/> " +"<def var='Tooltip.YDelta' value='8'/>" +"<def var='Predictive.Button.Width' value='45' />" +"<def var='Predictive.Button.Height' value='15' />" +"<widget name='Button' " +"size='72,16' " +"/>" +"<widget name='Slider' " +"size='85,12' " +"/>" "<widget name='OptionsLabel' " "size='110,Globals.Line.Height' " "textalign='right' " -"/> " +"/>" "<widget name='SmallLabel' " -"size='24,Globals.Line.Height' " -"/> " -"<widget name='ShortOptionsLabel' " -"size='60,Globals.Line.Height' " -"/> " -"<widget name='Button' " -"size='108,24' " -"/> " -"<widget name='Slider' " -"size='128,18' " -"/> " +"size='18,Globals.Line.Height' " +"/>" "<widget name='PopUp' " -"size='-1,19' " -"/> " +"size='-1,15' " +"/>" "<widget name='Checkbox' " -"size='-1,14' " -"/> " +"size='-1,Globals.Line.Height' " +"/>" "<widget name='Radiobutton' " "size='-1,Globals.Line.Height' " -"/> " +"/>" "<widget name='ListWidget' " -"padding='5,0,8,0' " -"/> " +"padding='5,0,0,0' " +"/>" "<widget name='PopUpWidget' " "padding='7,5,0,0' " -"/> " +"/>" "<widget name='EditTextWidget' " "padding='5,5,0,0' " -"/> " +"/>" "<widget name='Console' " "padding='7,5,5,5' " -"/> " +"/>" "<widget name='Scrollbar' " -"size='15,0' " -"/> " +"size='9,0' " +"/>" "<widget name='TabWidget.Tab' " -"size='75,27' " -"padding='0,0,8,0' " -"/> " +"size='45,16' " +"padding='0,0,2,0' " +"/>" "<widget name='TabWidget.Body' " -"padding='0,0,0,0' " -"/> " +"padding='0,0,0,-8' " +"/>" "<widget name='TabWidget.NavButton' " -"size='15,18' " -"padding='0,3,4,0' " -"/> " -"</globals> " -"<dialog name='Launcher' overlays='screen'> " -"<layout type='vertical' center='true' padding='16,16,8,8'> " +"size='32,18' " +"padding='0,0,1,0' " +"/>" +"<widget name='EditRecordLabel' " +"size='60,Globals.Line.Height' " +"/>" +"<widget name='EditRecord' " +"size='120,15' " +"/>" +"</globals>" +"<dialog name='Launcher' overlays='screen'>" +"<layout type='vertical' center='true' padding='6,6,2,2'>" "<widget name='Version' " "height='Globals.Line.Height' " "textalign='center' " -"/> " -"<layout type='horizontal' spacing='5' padding='10,0,0,0'> " +"/>" +"<layout type='horizontal' spacing='5' padding='0,0,0,0'>" "<widget name='SearchDesc' " -"width='60' " +"width='50' " "height='Globals.Line.Height' " "textalign='right' " -"/> " +"/>" "<widget name='Search' " "width='150' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='SearchClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"<space /> " -"</layout> " -"<widget name='GameList'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"/>" +"<space />" +"</layout>" +"<widget name='GameList'/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='8'>" "<widget name='LoadGameButton' " -"height='20' " -"/> " +"height='12' " +"/>" "<widget name='AddGameButton' " -"height='20' " -"/> " +"height='12' " +"/>" "<widget name='EditGameButton' " -"height='20' " -"/> " +"height='12' " +"/>" "<widget name='RemoveGameButton' " -"height='20' " -"/> " -"</layout> " -"<space size='4'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"height='12' " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='8'>" "<widget name='QuitButton' " -"height='20' " -"/> " +"height='12' " +"/>" "<widget name='AboutButton' " -"height='20' " -"/> " +"height='12' " +"/>" "<widget name='OptionsButton' " -"height='20' " -"/> " +"height='12' " +"/>" "<widget name='StartButton' " -"height='20' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='Browser' overlays='Dialog.Launcher.GameList' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8'> " +"height='12' " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='Browser' overlays='screen' inset='8' shading='dim'>" +"<layout type='vertical' padding='8,8,0,4'>" "<widget name='Headline' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Path' " "height='Globals.Line.Height' " -"/> " -"<widget name='List'/> " -"<layout type='vertical' padding='0,0,16,0'> " +"/>" +"<widget name='List'/>" +"<layout type='vertical' padding='0,0,8,0'>" "<widget name='Hidden' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='Up' " "type='Button' " -"/> " -"<space/> " +"/>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Choose' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions' overlays='Dialog.Launcher.GameList' shading='dim'> " -"<layout type='vertical' padding='0,0,0,0'> " -"<widget name='TabWidget'/> " -"<layout type='horizontal' padding='16,16,16,16'> " -"<space/> " +"/>" +"</layout>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions' overlays='screen' inset='16' shading='dim'>" +"<layout type='vertical' padding='0,0,0,0'>" +"<widget name='TabWidget'/>" +"<layout type='horizontal' padding='8,8,8,8'>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='grModePopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='grModePopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='grRenderPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='grRenderPopup' " "type='PopUp' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='grAspectCheckbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='grFullscreenCheckbox' " "type='Checkbox' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='auMidiPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auMidiPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='auOPLPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auOPLPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='auSampleRatePopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auSampleRatePopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='3' center='true'>" "<widget name='subToggleDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='subToggleSpeechOnly' " "type='Radiobutton' " -"/> " +"/>" "<widget name='subToggleSubOnly' " "type='Radiobutton' " -"/> " +"/>" "<widget name='subToggleSubBoth' " "type='Radiobutton' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='subSubtitleSpeedDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='subSubtitleSpeedSlider' " "type='Slider' " -"/> " +"/>" "<widget name='subSubtitleSpeedLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='horizontal' padding='16,16,16,16' spacing='8'> " -"<layout type='vertical' padding='0,0,0,0' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='vcMusicText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcMusicSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcMusicLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='vcSfxText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSfxSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSfxLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='vcSpeechText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSpeechSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSpeechLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"</layout> " -"<layout type='vertical' padding='24,0,24,0' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" +"<space size='110' />" "<widget name='vcMuteCheckbox' " "type='Checkbox' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='6'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='auPrefGmPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auPrefGmPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'>" "<widget name='mcFontButton' " "type='Button' " -"/> " +"/>" "<widget name='mcFontPath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='mcFontClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='mcMixedCheckbox' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='mcMidiGainText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='mcMidiGainSlider' " "type='Slider' " -"/> " +"/>" "<widget name='mcMidiGainLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='mcFluidSynthSettings' " -"width='200' " +"width='150' " "height='Globals.Button.Height' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='auPrefMt32PopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auPrefMt32Popup' " "type='PopUp' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='mcMt32Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='mcGSCheckbox' " "type='Checkbox' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Paths' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Paths' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16'>" "<widget name='SaveButton' " "type='Button' " -"/> " +"/>" "<widget name='SavePath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='SavePathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16'>" "<widget name='ThemeButton' " "type='Button' " -"/> " +"/>" "<widget name='ThemePath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='ThemePathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16'>" "<widget name='ExtraButton' " "type='Button' " -"/> " +"/>" "<widget name='ExtraPath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='ExtraPathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16'>" "<widget name='PluginsButton' " "type='Button' " -"/> " +"/>" "<widget name='PluginsPath' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Misc' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Misc' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16'>" "<widget name='ThemeButton' " "type='Button' " -"/> " +"/>" "<widget name='CurTheme' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='RendererPopupDesc' " -"type='OptionsLabel' " -"/> " +"width='80' " +"height='Globals.Line.Height' " +"textalign='right' " +"/>" "<widget name='RendererPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='AutosavePeriodPopupDesc' " -"type='OptionsLabel' " -"/> " +"width='80' " +"height='Globals.Line.Height' " +"textalign='right' " +"/>" "<widget name='AutosavePeriodPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='GuiLanguagePopupDesc' " -"type='OptionsLabel' " -"/> " +"width='80' " +"height='Globals.Line.Height' " +"textalign='right' " +"/>" "<widget name='GuiLanguagePopup' " "type='PopUp' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='KeysButton' " "type='Button' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='KeysDialog' overlays='Dialog.GlobalOptions' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='KeysDialog' overlays='Dialog.GlobalOptions' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" "<widget name='Action' " "height='Globals.Line.Height' " -"/> " -"<widget name='List'/> " +"/>" +"<widget name='List'/>" "<widget name='Mapping' " "height='Globals.Line.Height' " -"/> " -"<space size='Globals.Line.Height'/> " -"<layout type='horizontal'> " +"/>" +"<space size='Globals.Line.Height'/>" +"<layout type='horizontal'>" "<widget name='Map' " "type='Button' " -"/> " -"<space/> " +"/>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions' overlays='Dialog.Launcher.GameList' shading='dim'> " -"<layout type='vertical' padding='0,0,0,0' spacing='16'> " -"<widget name='TabWidget'/> " -"<layout type='horizontal' padding='16,16,16,4'> " -"<space/> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions' overlays='screen' inset='16' shading='dim'>" +"<layout type='vertical' padding='0,0,0,0' spacing='16'>" +"<widget name='TabWidget'/>" +"<layout type='horizontal' padding='8,8,8,8'>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_Graphics' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"/>" +"<import layout='Dialog.GlobalOptions_Graphics' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_Audio' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"/>" +"<import layout='Dialog.GlobalOptions_Audio' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_MIDI' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"/>" +"<import layout='Dialog.GlobalOptions_MIDI' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_MT32' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"/>" +"<import layout='Dialog.GlobalOptions_MT32' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_Volume' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Game' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='16,16,16,16'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"<import layout='Dialog.GlobalOptions_Volume' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Game' overlays='Dialog.GameOptions.TabWidget' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='Id' " -"type='OptionsLabel' " -"/> " +"width='35' " +"height='Globals.Line.Height' " +"textalign='right' " +"/>" "<widget name='Domain' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='Name' " -"type='OptionsLabel' " -"/> " +"width='35' " +"height='Globals.Line.Height' " +"textalign='right' " +"/>" "<widget name='Desc' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<space size='8'/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='LangPopupDesc' " -"type='OptionsLabel' " -"/> " +"width='60' " +"height='Globals.Line.Height' " +"textalign='right' " +"/>" "<widget name='LangPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='PlatformPopupDesc' " -"type='OptionsLabel' " -"/> " +"width='60' " +"height='Globals.Line.Height' " +"textalign='right' " +"/>" "<widget name='PlatformPopup' " "type='PopUp' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Paths' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='16,16,16,16'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Paths' overlays='Dialog.GameOptions.TabWidget' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'>" "<widget name='Savepath' " "type='Button' " -"/> " +"/>" "<widget name='SavepathText' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='SavePathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'>" "<widget name='Extrapath' " "type='Button' " -"/> " +"/>" "<widget name='ExtrapathText' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='ExtraPathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'>" "<widget name='Gamepath' " "type='Button' " -"/> " +"/>" "<widget name='GamepathText' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Engine' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='16,16,16,16'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Engine' overlays='Dialog.GameOptions.TabWidget' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8'>" "<widget name='customOption1Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption2Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption3Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption4Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption5Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption6Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption7Checkbox' " "type='Checkbox' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalMenu' overlays='screen_center'> " -"<layout type='vertical' padding='16,16,16,16' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalMenu' overlays='screen_center'>" +"<layout type='vertical' padding='2,2,4,6' center='true' spacing='6'>" "<widget name='Title' " -"width='210' " -"height='Globals.Line.Height' " -"/> " +"width='160' " +"height='4' " +"/>" "<widget name='Version' " -"width='210' " -"height='Globals.Line.Height' " -"/> " -"<widget name='Resume' " -"width='150' " -"height='Globals.Button.Height' " -"/> " -"<space size='10'/> " +"width='160' " +"height='4' " +"/>" +"<space size='1'/>" "<widget name='Load' " -"width='150' " -"height='Globals.Button.Height' " -"/> " +"width='120' " +"height='12' " +"/>" "<widget name='Save' " -"width='150' " -"height='Globals.Button.Height' " -"/> " -"<space size='10'/> " +"width='120' " +"height='12' " +"/>" +"<space size='1'/>" "<widget name='Options' " -"width='150' " -"height='Globals.Button.Height' " -"/> " +"width='120' " +"height='12' " +"/>" "<widget name='Help' " -"width='150' " -"height='Globals.Button.Height' " -"/> " +"width='120' " +"height='12' " +"/>" "<widget name='About' " -"width='150' " -"height='Globals.Button.Height' " -"/> " -"<space size='10'/> " +"width='120' " +"height='12' " +"/>" +"<space size='1'/>" +"<widget name='Resume' " +"width='120' " +"height='12' " +"/>" "<widget name='RTL' " -"width='150' " -"height='Globals.Button.Height' " -"/> " +"width='120' " +"height='12' " +"/>" "<widget name='Quit' " -"width='150' " -"height='Globals.Button.Height' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalConfig' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8'> " -"<layout type='horizontal' padding='0,0,0,0'> " -"<layout type='vertical' padding='0,0,0,0' center='true'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='8'> " +"width='120' " +"height='12' " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalConfig' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='vcMusicText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcMusicSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcMusicLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='8'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='vcSfxText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSfxSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSfxLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='8'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='vcSpeechText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSpeechSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSpeechLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"</layout> " -"<layout type='vertical' padding='24,24,24,24' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" +"<space size='110' />" "<widget name='vcMuteCheckbox' " "type='Checkbox' " -"width='80' " -"/> " -"</layout> " -"</layout> " -"<space size='8' /> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"width='80' " +"/>" +"</layout>" +"<layout type='vertical' padding='0,0,0,0' spacing='1' center='true'>" "<widget name='subToggleDesc' " "type='OptionsLabel' " -"/> " +"/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='subToggleSpeechOnly' " "type='Radiobutton' " -"width='100' " -"/> " +"width='90' " +"/>" "<widget name='subToggleSubOnly' " "type='Radiobutton' " -"width='100' " -"/> " +"width='90' " +"/>" "<widget name='subToggleSubBoth' " "type='Radiobutton' " -"width='100' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"width='90' " +"/>" +"</layout>" +"</layout>" +"<space size='2' />" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='subSubtitleSpeedDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='subSubtitleSpeedSlider' " "type='Slider' " -"/> " +"/>" "<widget name='subSubtitleSpeedLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<space size='60'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"/>" +"</layout>" +"<space size='16'/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='4'>" "<widget name='Keys' " "type='Button' " -"/> " -"<space size='Globals.Button.Width' /> " +"/>" +"<space size='Globals.Button.Width' />" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings' overlays='GlobalOptions' shading='dim'> " -"<layout type='vertical' padding='0,0,0,0'> " -"<widget name='TabWidget'/> " -"<layout type='horizontal' padding='16,16,16,16'> " -"<space/> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings' overlays='GlobalOptions' shading='dim'>" +"<layout type='vertical' padding='0,0,0,0'>" +"<widget name='TabWidget'/>" +"<layout type='horizontal' padding='8,8,8,8'>" +"<space/>" "<widget name='ResetSettings' " "type='Button' " -"/> " +"/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings_Chorus' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings_Chorus' overlays='Dialog.FluidSynthSettings.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='VoiceCountText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='VoiceCountSlider' " "type='Slider' " -"/> " +"/>" "<widget name='VoiceCountLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='LevelText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='LevelSlider' " "type='Slider' " -"/> " +"/>" "<widget name='LevelLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='SpeedText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='SpeedSlider' " "type='Slider' " -"/> " +"/>" "<widget name='SpeedLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='DepthText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='DepthSlider' " "type='Slider' " -"/> " +"/>" "<widget name='DepthLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='WaveFormTypeText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='WaveFormType' " "type='PopUp' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings_Reverb' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings_Reverb' overlays='Dialog.FluidSynthSettings.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='RoomSizeText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='RoomSizeSlider' " "type='Slider' " -"/> " +"/>" "<widget name='RoomSizeLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='DampingText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='DampingSlider' " "type='Slider' " -"/> " +"/>" "<widget name='DampingLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='WidthText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='WidthSlider' " "type='Slider' " -"/> " +"/>" "<widget name='WidthLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='LevelText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='LevelSlider' " "type='Slider' " -"/> " +"/>" "<widget name='LevelLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings_Misc' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings_Misc' overlays='Dialog.FluidSynthSettings.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='InterpolationText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='Interpolation' " "type='PopUp' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='SaveLoadChooser' overlays='screen' inset='8' shading='dim'> " -"<layout type='vertical' padding='8,8,8,32' center='true'> " -"<layout type='horizontal' padding='0,0,0,0'> " -"<widget name='Title' " -"height='Globals.Line.Height' " -"/> " -"<space/> " -"<widget name='PageDisplay' " -"width='200' " -"height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,16' spacing='16'> " -"<widget name='List' /> " -"<widget name='Thumbnail' " -"width='180' " -"height='200' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='SaveLoadChooser' overlays='screen' inset='8' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" +"<widget name='Title' height='Globals.Line.Height'/>" +"<widget name='List' />" +"<layout type='horizontal' padding='0,0,16,0'>" "<widget name='ListSwitch' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " +"/>" "<widget name='GridSwitch' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"<space/> " +"/>" +"<space/>" "<widget name='Delete' " "type='Button' " -"/> " -"<space size='32'/> " +"/>" +"<space size='16'/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Choose' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='SavenameDialog' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='SavenameDialog' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8'>" "<widget name='DescriptionText' " -"width='320' " +"width='180' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Description' " "height='19' " -"/> " -"<layout type='horizontal' padding='0,0,16,0'> " +"/>" +"<layout type='horizontal' padding='0,0,16,0'>" "<widget name='Cancel' " "type='Button' " -"/> " -"<space size='96'/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='ScummHelp' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='RecorderDialog' overlays='screen' inset='8' shading='dim'>" +"<layout type='vertical' padding='8,8,8,4' center='true'>" "<widget name='Title' " -"width='320' " "height='Globals.Line.Height' " -"/> " +"/>" +"<widget name='List' />" +"<layout type='horizontal' padding='0,0,0,0' spacing='2'>" +"<widget name='Edit' " +"type='Button' " +"/>" +"<space />" +"<widget name='Record' " +"type='Button' " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='2'>" +"<widget name='Delete' " +"type='Button' " +"/>" +"<space />" +"<widget name='Cancel' " +"type='Button' " +"/>" +"<widget name='Playback' " +"type='Button' " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='OnScreenDialog' overlays='screen_center'>" +"<layout type='horizontal' spacing='5' padding='3,2,3,2' center='true'>" +"<widget name='StopButton' " +"width='16' " +"height='16' " +"/>" +"<widget name='EditButton' " +"width='16' " +"height='16' " +"/>" +"<widget name='SwitchModeButton' " +"width='16' " +"height='16' " +"/>" +"<widget name='FastReplayButton' " +"width='16' " +"height='16' " +"/>" +"<widget name='TimeLabel' " +"width='50' " +"height='16' " +"/>" +"</layout>" +"</dialog>" +"<dialog name='EditRecordDialog' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" +"<widget name='Title' " +"height='Globals.Line.Height' " +"/>" +"<layout type='horizontal' spacing='5' padding='0,0,0,10'>" +"<widget name='AuthorLabel' " +"type='EditRecordLabel' " +"/>" +"<widget name='AuthorEdit' " +"type='EditRecord' " +"/>" +"</layout>" +"<layout type='horizontal' spacing='5' padding='0,0,0,10'>" +"<widget name='NameLabel' " +"type='EditRecordLabel' " +"/>" +"<widget name='NameEdit' " +"type='EditRecord' " +"/>" +"</layout>" +"<layout type='horizontal' spacing='5' padding='0,0,0,10'>" +"<widget name='NotesLabel' " +"type='EditRecordLabel' " +"/>" +"<widget name='NotesEdit' " +"type='EditRecord' " +"/>" +"</layout>" +"<layout type='horizontal' spacing='5' padding='0,0,0,0'>" +"<widget name='Cancel' " +"type='Button' " +"/>" +"<widget name='OK' " +"type='Button' " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='ScummHelp' overlays='screen'>" +"<layout type='vertical' padding='8,8,8,8'>" +"<widget name='Title' " +"width='180' " +"height='Globals.Line.Height' " +"/>" "<widget name='HelpText' " -"height='200' " -"/> " -"<layout type='horizontal' padding='0,0,16,0'> " +"height='140' " +"/>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='Prev' " "type='Button' " -"/> " +"/>" "<widget name='Next' " "type='Button' " -"/> " -"<space size='32'/> " +"/>" +"<space size='32'/>" "<widget name='Close' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='LoomTownsDifficultyDialog' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='LoomTownsDifficultyDialog' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" "<widget name='Description1' " -"width='320' " +"width='280' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Description2' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Standard' " "type='Button' " -"/> " +"/>" "<widget name='Practice' " "type='Button' " -"/> " +"/>" "<widget name='Expert' " "type='Button' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='MassAdd' overlays='screen_center' shading='dim'> " -"<layout type='vertical' padding='8,8,32,8' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='MassAdd' overlays='screen_center' shading='dim'>" +"<layout type='vertical' padding='4,4,16,4' center='true'>" "<widget name='DirProgressText' " -"width='480' " +"width='280' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='GameProgressText' " -"width='480' " +"width='280' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='GameList' " -"width='480' " -"height='250' " -"/> " -"<layout type='horizontal' padding='8,8,8,8'> " +"width='280' " +"height='100' " +"/>" +"<layout type='horizontal' padding='4,4,4,4'>" "<widget name='Ok' " "type='Button' " -"/> " +"/>" "<widget name='Cancel' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='KeyMapper' overlays='screen_center' shading='dim'> " -"<layout type='vertical' padding='8,8,32,8' spacing='10' center='true'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='KeyMapper' overlays='screen_center' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8' spacing='10' center='true'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='PopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='Popup' " "type='PopUp' " -"width='400' " +"width='150' " "height='Globals.Line.Height' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='KeymapArea' " -"width='600' " -"height='280' " -"/> " +"width='300' " +"height='120' " +"/>" "<widget name='Close' " "type='Button' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='Predictive' overlays='screen_center'> " -"<layout type='vertical' padding='5,5,5,5' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='Predictive' overlays='screen_center'>" +"<layout type='vertical' padding='1,1,1,1' center='true'>" "<widget name='Headline' " "height='Globals.Line.Height' " -"width='210' " +"width='150' " "textalign='center' " -"/> " -"<layout type='horizontal' padding='5,5,5,5'> " +"/>" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Word' " -"width='190' " +"width='120' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='Delete' " "width='20' " -"height='Globals.Button.Height' " -"/> " -"</layout> " -"<space size='5' /> " -"<layout type='horizontal' padding='3,3,3,3'> " +"height='Globals.Predictive.Button.Height' " +"/>" +"</layout>" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Button1' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " -"/> " +"height='Globals.Predictive.Button.Height' " +"/>" "<widget name='Button2' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " -"/> " +"height='Globals.Predictive.Button.Height' " +"/>" "<widget name='Button3' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='3,3,3,3'> " +"height='Globals.Predictive.Button.Height' " +"/>" +"</layout>" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Button4' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " -"/> " +"height='Globals.Predictive.Button.Height' " +"/>" "<widget name='Button5' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " -"/> " +"height='Globals.Predictive.Button.Height' " +"/>" "<widget name='Button6' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='3,3,3,3'> " +"height='Globals.Predictive.Button.Height' " +"/>" +"</layout>" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Button7' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " -"/> " +"height='Globals.Predictive.Button.Height' " +"/>" "<widget name='Button8' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " -"/> " +"height='Globals.Predictive.Button.Height' " +"/>" "<widget name='Button9' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='3,3,3,3'> " +"height='Globals.Predictive.Button.Height' " +"/>" +"</layout>" +"<layout type='horizontal' padding='3,3,3,0'>" "<widget name='Pre' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " -"/> " +"height='Globals.Predictive.Button.Height' " +"/>" "<widget name='Button0' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " -"/> " +"height='Globals.Predictive.Button.Height' " +"/>" "<widget name='Next' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " -"/> " -"</layout> " -"<space size='5' /> " -"<layout type='horizontal' padding='3,3,3,3'> " +"height='Globals.Predictive.Button.Height' " +"/>" +"</layout>" +"<space size='3' />" +"<layout type='horizontal' padding='3,3,0,3'>" "<widget name='Add' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " -"/> " -"<space size='22'/> " +"height='Globals.Predictive.Button.Height' " +"/>" "<widget name='Cancel' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " -"/> " +"height='Globals.Predictive.Button.Height' " +"/>" "<widget name='OK' " "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"</layout_info> " +"height='Globals.Predictive.Button.Height' " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"</layout_info>" diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip Binary files differindex 297ff20344..4154c6c33a 100644 --- a/gui/themes/scummclassic.zip +++ b/gui/themes/scummclassic.zip diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx index 180e8fba74..5fd2d6f835 100644 --- a/gui/themes/scummclassic/classic_layout.stx +++ b/gui/themes/scummclassic/classic_layout.stx @@ -36,6 +36,9 @@ <def var = 'ShowChooserPageDisplay' value = '1'/> <def var = 'SaveLoadChooser.ExtInfo.Visible' value = '1'/> + <def var = 'RecorderDialog.ExtInfo.Visible' value = '1'/> + + <def var = 'OnScreenDialog.ShowPics' value = '0'/> <def var = 'KeyMapper.Spacing' value = '10'/> <def var = 'KeyMapper.LabelWidth' value = '100'/> @@ -101,6 +104,12 @@ size = '15, 18' padding = '0, 3, 4, 0' /> + <widget name = 'EditRecordLabel' + size = '60, 25' + /> + <widget name = 'EditRecord' + size = '240, 25' + /> </globals> <dialog name = 'Launcher' overlays = 'screen'> @@ -1019,6 +1028,125 @@ </layout> </dialog> + <dialog name = 'RecorderDialog' overlays = 'screen' inset = '8' shading = 'dim'> + <layout type = 'vertical' padding = '8, 8, 8, 32' center = 'true'> + <widget name = 'Title' + height = 'Globals.Line.Height' + /> + <layout type = 'horizontal' padding = '0, 0, 0, 16' spacing = '16'> + <widget name = 'List' /> + <layout type = 'vertical' padding = '0, 0, 0, 0'> + <widget name = 'Thumbnail' + width = '180' + height = '170' + /> + <layout type = 'horizontal' padding = '0, 0, 0, 0'> + <widget name = 'NextScreenShotButton' + width = '25' + height = '25' + /> + <widget name = 'currentScreenshot' + width = '125' + height = '25' + textalign = 'center' + /> + <widget name = 'PreviousScreenShotButton' + width = '25' + height = '25' + /> + </layout> + <widget name = 'Author' height = 'Globals.Line.Height' /> + <widget name = 'Notes' height = 'Globals.Line.Height' /> + </layout> + </layout> + <layout type = 'horizontal' padding = '0, 0, 0, 0'> + <widget name = 'Delete' + type = 'Button' + /> + <space size = '16'/> + <widget name = 'Cancel' + type = 'Button' + /> + <space size = '16'/> + <widget name = 'Edit' + type = 'Button' + /> + <widget name = 'Record' + type = 'Button' + /> + <widget name = 'Playback' + type = 'Button' + /> + </layout> + </layout> + </dialog> + + <dialog name = 'OnScreenDialog' overlays = 'screen_center'> + <layout type = 'horizontal' spacing = '5' padding = '5, 3, 5, 3' center = 'true'> + <widget name = 'StopButton' + width = '32' + height = '32' + /> + <widget name = 'EditButton' + width = '32' + height = '32' + /> + <widget name = 'SwitchModeButton' + width = '32' + height = '32' + /> + <widget name = 'FastReplayButton' + width = '32' + height = '32' + /> + <widget name = 'TimeLabel' + width = '50' + height = '30' + /> + </layout> + </dialog> + + <dialog name = 'EditRecordDialog' overlays = 'screen_center'> + <layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'> + <widget name = 'Title' + width = '320' + height = 'Globals.Line.Height' + /> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'> + <widget name = 'AuthorLabel' + type = 'EditRecordLabel' + /> + <widget name = 'AuthorEdit' + type = 'EditRecord' + /> + </layout> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'> + <widget name = 'NameLabel' + type = 'EditRecordLabel' + /> + <widget name = 'NameEdit' + type = 'EditRecord' + /> + </layout> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'> + <widget name = 'NotesLabel' + type = 'EditRecordLabel' + /> + <widget name = 'NotesEdit' + type = 'EditRecord' + /> + </layout> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'> + <widget name = 'Cancel' + type = 'Button' + /> + <widget name = 'OK' + type = 'Button' + /> + </layout> + </layout> + </dialog> + <dialog name = 'ScummHelp' overlays = 'screen_center'> <layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'> <widget name = 'Title' diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx index 8bb03dea17..802998df3c 100644 --- a/gui/themes/scummclassic/classic_layout_lowres.stx +++ b/gui/themes/scummclassic/classic_layout_lowres.stx @@ -37,6 +37,9 @@ <def var = 'ShowChooserPageDisplay' value = '0'/> <def var = 'SaveLoadChooser.ExtInfo.Visible' value = '0'/> + <def var = 'RecorderDialog.ExtInfo.Visible' value = '0'/> + + <def var = 'OnScreenDialog.ShowPics' value = '0'/> <def var = 'KeyMapper.Spacing' value = '5'/> <def var = 'KeyMapper.LabelWidth' value = '80'/> @@ -99,6 +102,12 @@ size = '32, 18' padding = '0, 0, 1, 0' /> + <widget name = 'EditRecordLabel' + size = '60, Globals.Line.Height' + /> + <widget name = 'EditRecord' + size = '120, 15' + /> </globals> <dialog name = 'Launcher' overlays = 'screen'> @@ -1013,6 +1022,101 @@ </layout> </dialog> + <dialog name = 'RecorderDialog' overlays = 'screen' inset = '8' shading = 'dim'> + <layout type = 'vertical' padding = '8, 8, 8, 4' center = 'true'> + <widget name = 'Title' + height = 'Globals.Line.Height' + /> + <widget name = 'List' /> + <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '2'> + <widget name = 'Edit' + type = 'Button' + /> + <space /> + <widget name = 'Record' + type = 'Button' + /> + </layout> + <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '2'> + <widget name = 'Delete' + type = 'Button' + /> + <space /> + <widget name = 'Cancel' + type = 'Button' + /> + <widget name = 'Playback' + type = 'Button' + /> + </layout> + </layout> + </dialog> + + <dialog name = 'OnScreenDialog' overlays = 'screen_center'> + <layout type = 'horizontal' spacing = '5' padding = '3, 2, 3, 2' center = 'true'> + <widget name = 'StopButton' + width = '16' + height = '16' + /> + <widget name = 'EditButton' + width = '16' + height = '16' + /> + <widget name = 'SwitchModeButton' + width = '16' + height = '16' + /> + <widget name = 'FastReplayButton' + width = '16' + height = '16' + /> + <widget name = 'TimeLabel' + width = '50' + height = '16' + /> + </layout> + </dialog> + + <dialog name = 'EditRecordDialog' overlays = 'screen_center'> + <layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'> + <widget name = 'Title' + height = 'Globals.Line.Height' + /> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'> + <widget name = 'AuthorLabel' + type = 'EditRecordLabel' + /> + <widget name = 'AuthorEdit' + type = 'EditRecord' + /> + </layout> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'> + <widget name = 'NameLabel' + type = 'EditRecordLabel' + /> + <widget name = 'NameEdit' + type = 'EditRecord' + /> + </layout> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'> + <widget name = 'NotesLabel' + type = 'EditRecordLabel' + /> + <widget name = 'NotesEdit' + type = 'EditRecord' + /> + </layout> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 0'> + <widget name = 'Cancel' + type = 'Button' + /> + <widget name = 'OK' + type = 'Button' + /> + </layout> + </layout> + </dialog> + <dialog name = 'ScummHelp' overlays = 'screen'> <layout type = 'vertical' padding = '8, 8, 8, 8'> <widget name = 'Title' diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip Binary files differindex dbd84992e6..0f10003e94 100644 --- a/gui/themes/scummmodern.zip +++ b/gui/themes/scummmodern.zip diff --git a/gui/themes/scummmodern/editbtn.bmp b/gui/themes/scummmodern/editbtn.bmp Binary files differnew file mode 100644 index 0000000000..49eb4035b5 --- /dev/null +++ b/gui/themes/scummmodern/editbtn.bmp diff --git a/gui/themes/scummmodern/editbtn_small.bmp b/gui/themes/scummmodern/editbtn_small.bmp Binary files differnew file mode 100644 index 0000000000..8a0357fc2e --- /dev/null +++ b/gui/themes/scummmodern/editbtn_small.bmp diff --git a/gui/themes/scummmodern/fastreplay.bmp b/gui/themes/scummmodern/fastreplay.bmp Binary files differnew file mode 100644 index 0000000000..35ad2b4444 --- /dev/null +++ b/gui/themes/scummmodern/fastreplay.bmp diff --git a/gui/themes/scummmodern/fastreplay_small.bmp b/gui/themes/scummmodern/fastreplay_small.bmp Binary files differnew file mode 100644 index 0000000000..8ef004c3bf --- /dev/null +++ b/gui/themes/scummmodern/fastreplay_small.bmp diff --git a/gui/themes/scummmodern/scummmodern_gfx.stx b/gui/themes/scummmodern/scummmodern_gfx.stx index 4d449f50ec..1b3bcea0d6 100644 --- a/gui/themes/scummmodern/scummmodern_gfx.stx +++ b/gui/themes/scummmodern/scummmodern_gfx.stx @@ -103,6 +103,14 @@ <bitmap filename = 'delbtn.bmp'/> <bitmap filename = 'list.bmp'/> <bitmap filename = 'grid.bmp'/> + <bitmap filename = 'stopbtn.bmp'/> + <bitmap filename = 'editbtn.bmp'/> + <bitmap filename = 'switchbtn.bmp'/> + <bitmap filename = 'fastreplay.bmp'/> + <bitmap filename = 'stopbtn_small.bmp'/> + <bitmap filename = 'editbtn_small.bmp'/> + <bitmap filename = 'switchbtn_small.bmp'/> + <bitmap filename = 'fastreplay_small.bmp'/> </bitmaps> <fonts> diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx index 49c13cf1b0..b760e15919 100644 --- a/gui/themes/scummmodern/scummmodern_layout.stx +++ b/gui/themes/scummmodern/scummmodern_layout.stx @@ -43,6 +43,9 @@ <def var = 'ShowChooserPageDisplay' value = '1'/> <def var = 'SaveLoadChooser.ExtInfo.Visible' value = '1'/> + <def var = 'RecorderDialog.ExtInfo.Visible' value = '1'/> + + <def var = 'OnScreenDialog.ShowPics' value = '1'/> <def var = 'KeyMapper.Spacing' value = '10'/> <def var = 'KeyMapper.LabelWidth' value = '100'/> @@ -106,6 +109,13 @@ size = '15, 18' padding = '0, 3, 4, 0' /> + + <widget name = 'EditRecordLabel' + size = '60, 25' + /> + <widget name = 'EditRecord' + size = '220, 25' + /> </globals> <dialog name = 'Launcher' overlays = 'screen'> @@ -1032,6 +1042,126 @@ </layout> </dialog> + <dialog name = 'RecorderDialog' overlays = 'screen' inset = '8' shading = 'dim'> + <layout type = 'vertical' padding = '8, 8, 8, 32' center = 'true'> + <widget name = 'Title' + height = 'Globals.Line.Height' + /> + <layout type = 'horizontal' padding = '0, 0, 0, 16' spacing = '16'> + <widget name = 'List' /> + <layout type = 'vertical' padding = '0, 0, 0, 0'> + <widget name = 'Thumbnail' + width = '180' + height = '170' + /> + <layout type = 'horizontal' padding = '0, 0, 0, 0'> + <widget name = 'NextScreenShotButton' + width = '25' + height = '25' + /> + <widget name = 'currentScreenshot' + width = '125' + height = '25' + textalign = 'center' + /> + <widget name = 'PreviousScreenShotButton' + width = '25' + height = '25' + /> + </layout> + <widget name = 'Author' height = 'Globals.Line.Height' /> + <widget name = 'Notes' height = 'Globals.Line.Height' /> + </layout> + </layout> + <layout type = 'horizontal' padding = '0, 0, 0, 0'> + <space/> + <widget name = 'Delete' + type = 'Button' + /> + <space size = '16'/> + <widget name = 'Cancel' + type = 'Button' + /> + <space size = '16'/> + <widget name = 'Edit' + type = 'Button' + /> + <widget name = 'Record' + type = 'Button' + /> + <widget name = 'Playback' + type = 'Button' + /> + </layout> + </layout> + </dialog> + + <dialog name = 'OnScreenDialog' overlays = 'screen_center'> + <layout type = 'horizontal' spacing = '5' padding = '5, 3, 5, 3' center = 'true'> + <widget name = 'StopButton' + width = '32' + height = '32' + /> + <widget name = 'EditButton' + width = '32' + height = '32' + /> + <widget name = 'SwitchModeButton' + width = '32' + height = '32' + /> + <widget name = 'FastReplayButton' + width = '32' + height = '32' + /> + <widget name = 'TimeLabel' + width = '50' + height = '30' + /> + </layout> + </dialog> + + <dialog name = 'EditRecordDialog' overlays = 'screen_center'> + <layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'> + <widget name = 'Title' + width = '320' + height = 'Globals.Line.Height' + /> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'> + <widget name = 'AuthorLabel' + type = 'EditRecordLabel' + /> + <widget name = 'AuthorEdit' + type = 'EditRecord' + /> + </layout> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'> + <widget name = 'NameLabel' + type = 'EditRecordLabel' + /> + <widget name = 'NameEdit' + type = 'EditRecord' + /> + </layout> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'> + <widget name = 'NotesLabel' + type = 'EditRecordLabel' + /> + <widget name = 'NotesEdit' + type = 'EditRecord' + /> + </layout> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'> + <widget name = 'Cancel' + type = 'Button' + /> + <widget name = 'OK' + type = 'Button' + /> + </layout> + </layout> + </dialog> + <dialog name = 'ScummHelp' overlays = 'screen_center'> <layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'> <widget name = 'Title' diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx index 9658402f82..cee1e4af2b 100644 --- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx +++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx @@ -35,6 +35,9 @@ <def var = 'ShowChooserPageDisplay' value = '0'/> <def var = 'SaveLoadChooser.ExtInfo.Visible' value = '0'/> + <def var = 'RecorderDialog.ExtInfo.Visible' value = '0'/> + + <def var = 'OnScreenDialog.ShowPics' value = '1'/> <def var = 'Predictive.Button.Width' value = '45' /> <def var = 'Predictive.Button.Height' value = '15' /> @@ -97,6 +100,12 @@ size = '32, 18' padding = '0, 0, 2, 0' /> + <widget name = 'EditRecordLabel' + size = '60, Globals.Line.Height' + /> + <widget name = 'EditRecord' + size = '120, 15' + /> </globals> <dialog name = 'Launcher' overlays = 'screen'> @@ -1012,6 +1021,122 @@ </layout> </dialog> + <dialog name = 'SavenameDialog' overlays = 'screen_center'> + <layout type = 'vertical' padding = '8, 8, 8, 8'> + <widget name = 'DescriptionText' + width = '320' + height = 'Globals.Line.Height' + /> + <widget name = 'Description' + height = '19' + /> + <layout type = 'horizontal' padding = '0, 0, 16, 0'> + <widget name = 'Cancel' + type = 'Button' + /> + <space size = '96'/> + <widget name = 'Ok' + type = 'Button' + /> + </layout> + </layout> + </dialog> + + <dialog name = 'RecorderDialog' overlays = 'screen' inset = '8' shading = 'dim'> + <layout type = 'vertical' padding = '8, 8, 8, 4' center = 'true'> + <widget name = 'Title' + height = 'Globals.Line.Height' + /> + <widget name = 'List' /> + <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '2'> + <widget name = 'Edit' + type = 'Button' + /> + <space /> + <widget name = 'Record' + type = 'Button' + /> + </layout> + <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '2'> + <widget name = 'Delete' + type = 'Button' + /> + <space /> + <widget name = 'Cancel' + type = 'Button' + /> + <widget name = 'Playback' + type = 'Button' + /> + </layout> + </layout> + </dialog> + + <dialog name = 'OnScreenDialog' overlays = 'screen_center'> + <layout type = 'horizontal' spacing = '5' padding = '3, 2, 3, 2' center = 'true'> + <widget name = 'StopButton' + width = '16' + height = '16' + /> + <widget name = 'EditButton' + width = '16' + height = '16' + /> + <widget name = 'SwitchModeButton' + width = '16' + height = '16' + /> + <widget name = 'FastReplayButton' + width = '16' + height = '16' + /> + <widget name = 'TimeLabel' + width = '50' + height = '16' + /> + </layout> + </dialog> + + <dialog name = 'EditRecordDialog' overlays = 'screen_center'> + <layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'> + <widget name = 'Title' + height = 'Globals.Line.Height' + /> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'> + <widget name = 'AuthorLabel' + type = 'EditRecordLabel' + /> + <widget name = 'AuthorEdit' + type = 'EditRecord' + /> + </layout> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'> + <widget name = 'NameLabel' + type = 'EditRecordLabel' + /> + <widget name = 'NameEdit' + type = 'EditRecord' + /> + </layout> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 10'> + <widget name = 'NotesLabel' + type = 'EditRecordLabel' + /> + <widget name = 'NotesEdit' + type = 'EditRecord' + /> + </layout> + <layout type = 'horizontal' spacing = '5' padding = '0, 0, 0, 0'> + <widget name = 'Cancel' + type = 'Button' + /> + <widget name = 'OK' + type = 'Button' + /> + </layout> + </layout> + </dialog> + <dialog name = 'ScummHelp' overlays = 'screen' inset = '8'> <layout type = 'vertical' padding = '8, 8, 8, 8'> <widget name = 'Title' diff --git a/gui/themes/scummmodern/stopbtn.bmp b/gui/themes/scummmodern/stopbtn.bmp Binary files differnew file mode 100644 index 0000000000..3575956694 --- /dev/null +++ b/gui/themes/scummmodern/stopbtn.bmp diff --git a/gui/themes/scummmodern/stopbtn_small.bmp b/gui/themes/scummmodern/stopbtn_small.bmp Binary files differnew file mode 100644 index 0000000000..ffd5025279 --- /dev/null +++ b/gui/themes/scummmodern/stopbtn_small.bmp diff --git a/gui/themes/scummmodern/switchbtn.bmp b/gui/themes/scummmodern/switchbtn.bmp Binary files differnew file mode 100644 index 0000000000..6bafa4a998 --- /dev/null +++ b/gui/themes/scummmodern/switchbtn.bmp diff --git a/gui/themes/scummmodern/switchbtn_small.bmp b/gui/themes/scummmodern/switchbtn_small.bmp Binary files differnew file mode 100644 index 0000000000..929b128884 --- /dev/null +++ b/gui/themes/scummmodern/switchbtn_small.bmp diff --git a/gui/themes/scummtheme.py b/gui/themes/scummtheme.py index 4c55fd79de..524e91468e 100755 --- a/gui/themes/scummtheme.py +++ b/gui/themes/scummtheme.py @@ -37,9 +37,13 @@ def parseSTX(theme_file, def_file): comm = re.compile("<!--(.*?)-->", re.DOTALL) head = re.compile("<\?(.*?)\?>") + strlitcount = 0 output = "" for line in theme_file: - output += line.rstrip("\r\n\t ").lstrip() + " \n" + output += line.rstrip("\r\n\t ").lstrip() + if not output.endswith('>'): + output += ' ' + output += "\n" output = re.sub(comm, "", output) output = re.sub(head, "", output) @@ -48,7 +52,9 @@ def parseSTX(theme_file, def_file): for line in output.splitlines(): if line and not line.isspace(): + strlitcount += len(line) def_file.write("\"" + line + "\"\n") + return strlitcount def buildDefTheme(themeName): def_file = open("default.inc", "w") @@ -57,16 +63,23 @@ def buildDefTheme(themeName): print ("Cannot open default theme dir.") def_file.write(""" "<?xml version = '1.0'?>"\n""") + strlitcount = 24 for filename in os.listdir(themeName): filename = os.path.join(themeName, filename) if os.path.isfile(filename) and filename.endswith(".stx"): theme_file = open(filename, "r") - parseSTX(theme_file, def_file) + strlitcount += parseSTX(theme_file, def_file) theme_file.close() def_file.close() + if strlitcount > 65535: + print("WARNING: default.inc string literal is of length %d which exceeds the" % strlitcount) + print(" maximum length of 65536 that C++ compilers are required to support.") + print(" It is likely that bugs will occur dependent on compiler behaviour.") + print(" To avoid this, reduce the size of the theme.") + def printUsage(): print ("===============================") print ("ScummVM Theme Generation Script") diff --git a/gui/widget.cpp b/gui/widget.cpp index c3f10a861f..e96b62e359 100644 --- a/gui/widget.cpp +++ b/gui/widget.cpp @@ -287,7 +287,7 @@ ButtonWidget::ButtonWidget(GuiObject *boss, int x, int y, int w, int h, const Co ButtonWidget::ButtonWidget(GuiObject *boss, const Common::String &name, const Common::String &label, const char *tooltip, uint32 cmd, uint8 hotkey) : StaticTextWidget(boss, name, cleanupHotkey(label), tooltip), CommandSender(boss), - _cmd(cmd), _lastTime(0) { + _cmd(cmd), _hotkey(hotkey), _lastTime(0) { if (hotkey == 0) _hotkey = parseHotkey(label); setFlags(WIDGET_ENABLED/* | WIDGET_BORDER*/ | WIDGET_CLEARBG); @@ -396,7 +396,7 @@ PicButtonWidget::~PicButtonWidget() { void PicButtonWidget::setGfx(const Graphics::Surface *gfx) { _gfx.free(); - if (!gfx || !gfx->pixels) + if (!gfx || !gfx->getPixels()) return; if (gfx->format.bytesPerPixel == 1) { @@ -429,7 +429,7 @@ void PicButtonWidget::setGfx(int w, int h, int r, int g, int b) { void PicButtonWidget::drawWidget() { g_gui.theme()->drawButton(Common::Rect(_x, _y, _x+_w, _y+_h), "", _state, getFlags()); - if (_gfx.pixels) { + if (_gfx.getPixels()) { // Check whether the set up surface needs to be converted to the GUI // color format. const Graphics::PixelFormat &requiredFormat = g_gui.theme()->getPixelFormat(); @@ -646,7 +646,7 @@ GraphicsWidget::~GraphicsWidget() { void GraphicsWidget::setGfx(const Graphics::Surface *gfx) { _gfx.free(); - if (!gfx || !gfx->pixels) + if (!gfx || !gfx->getPixels()) return; if (gfx->format.bytesPerPixel == 1) { @@ -676,7 +676,7 @@ void GraphicsWidget::setGfx(int w, int h, int r, int g, int b) { } void GraphicsWidget::drawWidget() { - if (_gfx.pixels) { + if (_gfx.getPixels()) { // Check whether the set up surface needs to be converted to the GUI // color format. const Graphics::PixelFormat &requiredFormat = g_gui.theme()->getPixelFormat(); diff --git a/gui/widgets/edittext.cpp b/gui/widgets/edittext.cpp index 4b266e8194..3677f02e47 100644 --- a/gui/widgets/edittext.cpp +++ b/gui/widgets/edittext.cpp @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "common/system.h" #include "gui/widgets/edittext.h" #include "gui/gui-manager.h" @@ -79,8 +80,13 @@ void EditTextWidget::handleMouseDown(int x, int y, int button, int clickCount) { } if (setCaretPos(i)) draw(); -} +#ifdef TIZEN + // Display the virtual keypad to allow text entry. Samsung app-store testers expected + // the keypad to be displayed when clicking the filter edit control in the laucher gui. + g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); +#endif +} void EditTextWidget::drawWidget() { g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), 0, ThemeEngine::kWidgetBackgroundEditText); diff --git a/po/POTFILES b/po/POTFILES index c2f67e288b..869323b8f3 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -48,6 +48,8 @@ engines/groovie/script.cpp engines/kyra/detection.cpp engines/kyra/lol.cpp engines/kyra/sound_midi.cpp +engines/neverhood/detection.cpp +engines/neverhood/menumodule.cpp engines/queen/queen.cpp engines/sky/compact.cpp engines/sky/detection.cpp @@ -97,5 +99,5 @@ backends/events/default/default-events.cpp backends/events/gph/gph-events.cpp backends/events/openpandora/op-events.cpp backends/updates/macosx/macosx-updates.mm -backends/platform/bada/form.cpp +backends/platform/tizen/form.cpp backends/events/maemosdl/maemosdl-events.cpp @@ -139,6 +139,10 @@ ifdef USE_FAAD OSX_STATIC_LIBS += $(STATICLIBPATH)/lib/libfaad.a endif +ifdef USE_MPEG2 +OSX_STATIC_LIBS += $(STATICLIBPATH)/lib/libmpeg2.a +endif + ifdef USE_ZLIB OSX_ZLIB ?= $(STATICLIBPATH)/lib/libz.a endif diff --git a/test/audio/raw.h b/test/audio/raw.h index e7cb42ac44..3792f82674 100644 --- a/test/audio/raw.h +++ b/test/audio/raw.h @@ -1,6 +1,7 @@ #include <cxxtest/TestSuite.h> #include "audio/decoders/raw.h" +#include "audio/audiostream.h" #include "helper.h" diff --git a/test/common/hash-str.h b/test/common/hash-str.h new file mode 100644 index 0000000000..0391e7167f --- /dev/null +++ b/test/common/hash-str.h @@ -0,0 +1,164 @@ +#include <cxxtest/TestSuite.h> +#include "common/hash-str.h" + +/** + * Test suite for common/hash-str.h + * We test a number of case sensitive/insensitive hash and compare functions + * using example strings and known hashes, trying to tackle + * as much edge cases as possible. + */ +class HashStrTestSuite : public CxxTest::TestSuite { + + public: + void test_case_sensitive_string_equal_to() { + + // Name says it all. + // This verifies that the function returns true + // for exactly the same string, false for the same + // string in mixed case and false for some edge cases + // with various spacings plus one character replaced + // by itself+128 (if there's some processing done after + // conversion to 7-bit ASCII this might yield funny results). + + const Common::String lower("test"); + const Common::String lower1("test"); + const Common::String mixed("tESt"); + const Common::String spaced("test "); + const Common::String doublespaced("test "); + const Common::String tabbed("test\t"); + const Common::String plus128("t\345est"); + // 'e'+128 = 0xE5 = 0o345 + + Common::CaseSensitiveString_EqualTo css_et; + TS_ASSERT_EQUALS(css_et(lower, mixed), false); + TS_ASSERT_EQUALS(css_et(lower, lower1), true); + TS_ASSERT_EQUALS(css_et(lower, lower), true); + + // Different sorts of whitespace are to be treated differently. + TS_ASSERT_EQUALS(css_et(lower, spaced), false); + TS_ASSERT_EQUALS(css_et(lower, tabbed), false); + TS_ASSERT_EQUALS(css_et(spaced, tabbed), false); + TS_ASSERT_EQUALS(css_et(spaced, doublespaced), false); + TS_ASSERT_EQUALS(css_et(lower, plus128), false); + } + + void test_ignore_case_equal_to() { + + // This should be probably called case_insensitive_string_equal_to + // or something,but it's basically the same thing as + // test_case_sensitive_string_equal_to, only it's case + // insensitive. + + const Common::String lower("test"); + const Common::String lower1("test"); + const Common::String mixed("tESt"); + const Common::String spaced("test "); + const Common::String mixedspaced("tESt "); + const Common::String doublespaced("test "); + const Common::String tabbed("test\t"); + const Common::String plus128("t\345est"); + + Common::IgnoreCase_EqualTo ic_et; + TS_ASSERT_EQUALS(ic_et(lower, mixed), true); + TS_ASSERT_EQUALS(ic_et(lower, lower1), true); + TS_ASSERT_EQUALS(ic_et(lower, lower), true); + // Edge case: + TS_ASSERT_EQUALS(ic_et(spaced, mixedspaced), true); + + // Different sorts of whitespace are to be treated differently. + TS_ASSERT_EQUALS(ic_et(lower, spaced), false); + TS_ASSERT_EQUALS(ic_et(lower, tabbed), false); + TS_ASSERT_EQUALS(ic_et(spaced, tabbed), false); + TS_ASSERT_EQUALS(ic_et(spaced, doublespaced), false); + TS_ASSERT_EQUALS(ic_et(lower, plus128), false); + } + + void test_case_sensitive_string_hash() { + + // Here we compute string hashes for different + // strings and see that the functor is case sensitive + // and does not ignore spaces. + + const Common::String lower("test"); + const Common::String lower1("test"); + const Common::String mixed("tESt"); + const Common::String spaced("test "); + const Common::String mixedspaced("tESt "); + const Common::String doublespaced("test "); + const Common::String tabbed("test\t"); + + Common::CaseSensitiveString_Hash css_h; + TS_ASSERT_EQUALS(css_h(lower), css_h(lower1)); + TS_ASSERT_DIFFERS(css_h(mixed), css_h(lower)); + TS_ASSERT_DIFFERS(css_h(spaced), css_h(lower)); + TS_ASSERT_DIFFERS(css_h(tabbed), css_h(spaced)); + TS_ASSERT_DIFFERS(css_h(spaced), css_h(doublespaced)); + } + + void test_ignore_case_hash() { + // Same as test_case_sensitive_string_hash, but case insensitive. + const Common::String lower("test"); + const Common::String lower1("test"); + const Common::String mixed("tESt"); + const Common::String spaced("test "); + const Common::String mixedspaced("tESt "); + const Common::String doublespaced("test "); + const Common::String tabbed("test\t"); + + Common::IgnoreCase_Hash ic_h; + TS_ASSERT_EQUALS(ic_h(lower), ic_h(lower1)); + TS_ASSERT_EQUALS(ic_h(mixed), ic_h(lower)); + TS_ASSERT_EQUALS(ic_h(spaced), ic_h(mixedspaced)); + TS_ASSERT_DIFFERS(ic_h(tabbed), ic_h(lower)); + TS_ASSERT_DIFFERS(ic_h(spaced), ic_h(doublespaced)); + } + + void test_cpp_string_hash() + { + // We run the same tests with Hash<String>, + // a template specialization of Hash, also a functor. + // It is supposed to be case sensitive. + + const Common::String lower("test"); + const Common::String lower1("test"); + const Common::String mixed("tESt"); + const Common::String spaced("test "); + const Common::String mixedspaced("tESt "); + const Common::String doublespaced("test "); + const Common::String tabbed("test\t"); + + Common::Hash<Common::String> h; + TS_ASSERT_EQUALS(h(lower), h(lower1)); + TS_ASSERT_DIFFERS(h(mixed), h(lower)); + TS_ASSERT_DIFFERS(h(spaced), h(lower)); + TS_ASSERT_DIFFERS(h(tabbed), h(spaced)); + TS_ASSERT_DIFFERS(h(spaced), h(doublespaced)); + } + + void test_c_style_string_hash() + { + // Same as test_cpp_string_hash but with Hash<const char*>, + // a template specialization of Hash, also a functor, + // that works with C-Style strings. + // It is supposed to be case sensitive. + + char lower[] = "test"; + char lower1[] = "test"; + char mixed[] = "tESt"; + char spaced[] = "test "; + char mixedspaced[] = "tESt "; + char doublespaced[] = "test "; + char tabbed[] = "test\t"; + + Common::Hash<const char *> h; + TS_ASSERT_EQUALS(h(lower), h(lower1)); + TS_ASSERT_DIFFERS(h(mixed), h(lower)); + TS_ASSERT_DIFFERS(h(spaced), h(lower)); + TS_ASSERT_DIFFERS(h(spaced), h(mixedspaced)); + TS_ASSERT_DIFFERS(h(tabbed), h(spaced)); + TS_ASSERT_DIFFERS(h(spaced), h(doublespaced)); + + } + + +}; diff --git a/test/common/huffman.h b/test/common/huffman.h new file mode 100644 index 0000000000..53353aaa60 --- /dev/null +++ b/test/common/huffman.h @@ -0,0 +1,144 @@ +#include <cxxtest/TestSuite.h> +#include "common/huffman.h" +#include "common/bitstream.h" +#include "common/memstream.h" + +/** +* A test suite for the Huffman decoder in common/huffman.h +* The encoding used comes from the example on the Wikipedia page +* for Huffman. +* TODO: It could be improved by generating one at runtime. +*/ +class HuffmanTestSuite : public CxxTest::TestSuite { + public: + void test_get_with_full_symbols() { + + /* + * The class can be initialized with or without providing + * a max_length and a symbol table. + * We test with a table. + * + * Encoding (arbitrary, for testing purpouses): + * 0xA=010 + * 0xB=011 + * 0xC=11 + * 0xD=00 + * 0xE=10 + */ + + uint32 codeCount = 5; + uint8 maxLength = 3; + const uint8 lengths[] = {3,3,2,2,2}; + const uint32 codes[] = {0x2, 0x3, 0x3, 0x0, 0x2}; + const uint32 symbols[] = {0xA, 0xB, 0xC, 0xD, 0xE}; + + Common::Huffman h(maxLength, codeCount, codes, lengths, symbols); + + byte input[] = {0x4F, 0x20}; + // Provided input... + uint32 expected[] = {0xA, 0xB, 0xC, 0xD, 0xE, 0xD, 0xD}; + // ..and expected output. + + /* + * What should be going on: + * 010 011 11 00 10 00 00 = A B C D E D D + * = 0100 1111 0010 0000 = 0x4F20 + */ + + Common::MemoryReadStream ms(input, sizeof(input)); + Common::BitStream8MSB bs(ms); + + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[0]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[1]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[2]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[3]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[4]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[5]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[6]); + } + + void test_get_without_symbols() { + + /* + * This is basically the same as test_get_with_full_symbols, but + * I only pass the minimal required arguments. + * Specifically, I avoid passing the symbols table, so that + * array indices are used instead. + * + * Encoding becomes: + * + * 0=010 + * 1=011 + * 2=11 + * 3=00 + * 4=10 + */ + + uint32 codeCount = 5; + const uint8 lengths[] = {3,3,2,2,2}; + const uint32 codes[] = {0x2, 0x3, 0x3, 0x0, 0x2}; + + Common::Huffman h(0, codeCount, codes, lengths, 0); + + byte input[] = {0x4F, 0x20}; + uint32 expected[] = {0, 1, 2, 3, 4, 3 ,3}; + + Common::MemoryReadStream ms(input, sizeof(input)); + Common::BitStream8MSB bs(ms); + + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[0]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[1]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[2]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[3]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[4]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[5]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[6]); + } + + void test_get_after_set_symbols() { + + /* + * Another variation of test_get_with_full_symbols. + * I use the setSymbols method to define, a posteriori, + * an alphabet to be used in place of array indices. + * The encoding is, at first, + * 0=010 + * 1=011 + * 2=11 + * 3=00 + * 4=10 + * (=array indices). + */ + + uint32 codeCount = 5; + const uint8 lengths[] = {3,3,2,2,2}; + const uint32 codes[] = {0x2, 0x3, 0x3, 0x0, 0x2}; + + Common::Huffman h(0, codeCount, codes, lengths, 0); + + const uint32 symbols[] = {0xA, 0xB, 0xC, 0xD, 0xE}; + h.setSymbols(symbols); + + byte input[] = {0x4F, 0x20}; + uint32 expected[] = {0xA, 0xB, 0xC, 0xD, 0xE, 0xD, 0xD}; + + Common::MemoryReadStream ms(input, sizeof(input)); + Common::BitStream8MSB bs(ms); + + /* New symbols: + * A=010 + * B=011 + * C=11 + * D=00 + * E=10 + */ + + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[0]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[1]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[2]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[3]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[4]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[5]); + TS_ASSERT_EQUALS(h.getSymbol(bs), expected[6]); + } +}; diff --git a/test/common/rendermode.h b/test/common/rendermode.h new file mode 100644 index 0000000000..e5e277f16b --- /dev/null +++ b/test/common/rendermode.h @@ -0,0 +1,84 @@ +#include <cxxtest/TestSuite.h> +#include "common/rendermode.h" +#include "common/gui_options.h" +#include "common/str.h" + +class RenderModeTestSuite : public CxxTest::TestSuite { + public: + void test_parse_render_mode_good() { + /* + * Tests for parseRenderMode. + * It takes a code (case-insensitive) and spits a RenderMode back at you. + * These cases should work - the inputs are standard, there's just some + * fun with caps being had in here. + */ + TS_ASSERT_EQUALS(Common::parseRenderMode("fMTOwNs"), Common::kRenderFMTowns); + TS_ASSERT_EQUALS(Common::parseRenderMode("hercGrEen"), Common::kRenderHercG); + TS_ASSERT_EQUALS(Common::parseRenderMode("hercAmbeR"), Common::kRenderHercA); + TS_ASSERT_EQUALS(Common::parseRenderMode("CgA"), Common::kRenderCGA); + TS_ASSERT_EQUALS(Common::parseRenderMode("ega"), Common::kRenderEGA); + TS_ASSERT_EQUALS(Common::parseRenderMode("Vga"), Common::kRenderVGA); + TS_ASSERT_EQUALS(Common::parseRenderMode("AmigA"), Common::kRenderAmiga); + TS_ASSERT_EQUALS(Common::parseRenderMode("pc9821"), Common::kRenderPC9821); + TS_ASSERT_EQUALS(Common::parseRenderMode("PC9801"), Common::kRenderPC9801); + TS_ASSERT_EQUALS(Common::parseRenderMode("0"), Common::kRenderDefault); + } + + + void test_parse_render_mode_bad() { + /* + * These cases, according to the specification, should return the default. + * It is only mentioned that the function must be case insensitive. + * Whitespaces, in particular, should not be automatically trimmed. + */ + TS_ASSERT_EQUALS(Common::parseRenderMode("fmtowns "), Common::kRenderDefault); + TS_ASSERT_EQUALS(Common::parseRenderMode("FM-TOWNS "), Common::kRenderDefault); + TS_ASSERT_EQUALS(Common::parseRenderMode(" cga"), Common::kRenderDefault); + TS_ASSERT_EQUALS(Common::parseRenderMode("\tC g A"), Common::kRenderDefault); + TS_ASSERT_EQUALS(Common::parseRenderMode("\t"), Common::kRenderDefault); + // This is the only interesting bit: if the function was really, really + // broken it could be tempted to test for +-0x20. + TS_ASSERT_EQUALS(Common::parseRenderMode("pc Y8 21 "), Common::kRenderDefault); + TS_ASSERT_EQUALS(Common::parseRenderMode(" PC\t9801 "), Common::kRenderDefault); + TS_ASSERT_EQUALS(Common::parseRenderMode("0"), Common::kRenderDefault); + } + + void test_get_render_mode_code_back_and_forth() { + /* + * What does getRenderModeCode return? + * Notably, the output should not be in mixed case. + */ + TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("FMTOWNS")), "fmtowns", 7); + TS_ASSERT_DIFFERS(Common::getRenderModeCode(Common::parseRenderMode("FMTOWNS")), "fmtowns"); + TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("CGA")), "cga", 3); + TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("vga")), "vga", 3); + TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("Ega")), "ega", 3); + TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("AmiGa")), "amiga", 5); + TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("PC9821")), "pc9821", 6); + TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("PC9801")), "pc9801", 6); + // Slightly more interesting: + // Make sure that we get a null pointer for 0 (and not the "0" string or stuff) + char *null_p = 0; + TS_ASSERT_EQUALS(Common::getRenderModeCode(Common::kRenderDefault), null_p); + } + + void test_render_2_guio() { + /* + * Verify that a rendermode is taken and the corresponding + * GUIO_xxxxx is returned. + */ + TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderHercG), GUIO_RENDERHERCGREEN); + TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderHercA), GUIO_RENDERHERCAMBER); + TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderCGA), GUIO_RENDERCGA); + TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderEGA), GUIO_RENDEREGA); + TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderVGA), GUIO_RENDERVGA); + TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderAmiga), GUIO_RENDERAMIGA); + TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderFMTowns), GUIO_RENDERFMTOWNS); + TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderPC9821), GUIO_RENDERPC9821); + TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderPC9801), GUIO_RENDERPC9801); + // renderMode2GUIO is supposed to return an empty string + // if given kRenderDefault as an argument + Common::String empty; + TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderDefault), empty); + } +}; diff --git a/test/common/str.h b/test/common/str.h index 2c563f3132..adc6a099e4 100644 --- a/test/common/str.h +++ b/test/common/str.h @@ -243,6 +243,14 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS(str, "012345678923456789012345678901"); } + void test_erase() { + Common::String str("01234567890123456789012345678901"); + str.erase(18); + TS_ASSERT_EQUALS(str, "012345678901234567"); + str.erase(7, 5); + TS_ASSERT_EQUALS(str, "0123456234567"); + } + void test_sharing() { Common::String str("01234567890123456789012345678901"); Common::String str2(str); diff --git a/test/common/util.h b/test/common/util.h new file mode 100644 index 0000000000..cd65307612 --- /dev/null +++ b/test/common/util.h @@ -0,0 +1,237 @@ +#include <cxxtest/TestSuite.h> +#include "common/util.h" + +/** + * Test suite for the functions in common/util.h + */ +class UtilTestSuite : public CxxTest::TestSuite { + public: + void test_parsebool_yesno() { + + // First test for the parseBool function. + // These are the mixed case yes/no cases that must work + + bool valasbool; + bool success; + + Common::String string_1("Yes"); + success = Common::parseBool(string_1, valasbool); + TS_ASSERT_EQUALS(success, 1); + TS_ASSERT_EQUALS(valasbool, 1); + + Common::String string_2("nO"); + success = Common::parseBool(string_2, valasbool); + TS_ASSERT_EQUALS(success, 1); + TS_ASSERT_EQUALS(valasbool, 0); + } + + void test_parsebool_truefalse() { + + // First test for the parseBool function. + // These are the mixed case true/false cases that must work + + bool valasbool; + bool success; + + Common::String string_3("tRuE"); + success = Common::parseBool(string_3, valasbool); + TS_ASSERT_EQUALS(success, 1); + TS_ASSERT_EQUALS(valasbool, 1); + + Common::String string_4("fAlSe"); + success = Common::parseBool(string_4, valasbool); + TS_ASSERT_EQUALS(success, 1); + TS_ASSERT_EQUALS(valasbool, 0); + } + + void test_parsebool_onezero() { + + // Third test for the parseBool function. + // These are the 1/0 cases that must work. + // Note that while 'a-z'+0x20 must work just fine, + // '0-1'+0x20 should NOT; this is addressed in + // parsebool_bad + + bool valasbool; + bool success; + + Common::String string_5("1"); + success = Common::parseBool(string_5, valasbool); + TS_ASSERT_EQUALS(success, 1); + TS_ASSERT_EQUALS(valasbool, 1); + + Common::String string_6("0"); + success = Common::parseBool(string_6, valasbool); + TS_ASSERT_EQUALS(success, 1); + TS_ASSERT_EQUALS(valasbool, 0); + + } + + void test_parsebool_bad() { + + bool valasbool; + bool success; + + // Bad cases that should not return success #1: + // Random string + Common::String string_1("u_f1ght_l1k3_a_c0w"); + success = Common::parseBool(string_1, valasbool); + TS_ASSERT_EQUALS(success, 0); + + // Bad cases that should not return success #2, #3: + // The function should NOT accept trailing whitespaces: + Common::String string_2(" yes"); + success = Common::parseBool(string_2, valasbool); + TS_ASSERT_EQUALS(success, 0); + + Common::String string_3("yes "); + success = Common::parseBool(string_3, valasbool); + TS_ASSERT_EQUALS(success, 0); + + // While 'a-z'+0x20 must work just fine, + // '0-1'+0x20 should NOT. '2' is not good either. + + Common::String string_4("\x50"); + success = Common::parseBool(string_4, valasbool); + TS_ASSERT_EQUALS(success, 0); + + Common::String string_5("\x51"); + success = Common::parseBool(string_5, valasbool); + TS_ASSERT_EQUALS(success, 0); + + Common::String string_6("2"); + success = Common::parseBool(string_6, valasbool); + TS_ASSERT_EQUALS(success, 0); + } + + void test_is_al_num() { + + // Test the isAlnum function + // Should return true if and only if the input is an alphanumeric char + + TS_ASSERT_EQUALS(Common::isAlnum('a'), 1); + TS_ASSERT_EQUALS(Common::isAlnum('A'), 1); + TS_ASSERT_EQUALS(Common::isAlnum('z'), 1); + TS_ASSERT_EQUALS(Common::isAlnum('Z'), 1); + TS_ASSERT_EQUALS(Common::isAlnum('1'), 1); + TS_ASSERT_EQUALS(Common::isAlnum('0'), 1); + TS_ASSERT_EQUALS(Common::isAlnum('§'), 0); + TS_ASSERT_EQUALS(Common::isAlnum('$'), 0); + TS_ASSERT_EQUALS(Common::isAlnum(' '), 0); + TS_ASSERT_EQUALS(Common::isAlnum('\n'), 0); + TS_ASSERT_EQUALS(Common::isAlnum('\b'), 0); + TS_ASSERT_EQUALS(Common::isAlnum(0), 0); + TS_ASSERT_EQUALS(Common::isAlnum(255), 0); + + } + + void test_is_alpha() { + + // Test the isAlpha function + // Should return true if and only if the input is an alphanumeric char + + TS_ASSERT_EQUALS(Common::isAlpha('a'), 1); + TS_ASSERT_EQUALS(Common::isAlpha('A'), 1); + TS_ASSERT_EQUALS(Common::isAlpha('z'), 1); + TS_ASSERT_EQUALS(Common::isAlpha('Z'), 1); + TS_ASSERT_EQUALS(Common::isAlpha('1'), 0); + TS_ASSERT_EQUALS(Common::isAlpha('0'), 0); + TS_ASSERT_EQUALS(Common::isAlpha('§'), 0); + TS_ASSERT_EQUALS(Common::isAlpha('$'), 0); + TS_ASSERT_EQUALS(Common::isAlpha(' '), 0); + TS_ASSERT_EQUALS(Common::isAlpha('\n'), 0); + TS_ASSERT_EQUALS(Common::isAlpha('\b'), 0); + TS_ASSERT_EQUALS(Common::isAlpha(0), 0); + TS_ASSERT_EQUALS(Common::isAlpha(255), 0); + + } + + void test_is_digit() { + + // Test the isDigit function + // Should return true if and only if the input is a single digit + + TS_ASSERT_EQUALS(Common::isDigit('a'), 0); + TS_ASSERT_EQUALS(Common::isDigit('A'), 0); + TS_ASSERT_EQUALS(Common::isDigit('z'), 0); + TS_ASSERT_EQUALS(Common::isDigit('Z'), 0); + TS_ASSERT_EQUALS(Common::isDigit('1'), 1); + TS_ASSERT_EQUALS(Common::isDigit('0'), 1); + TS_ASSERT_EQUALS(Common::isDigit('§'), 0); + TS_ASSERT_EQUALS(Common::isDigit('$'), 0); + TS_ASSERT_EQUALS(Common::isDigit(' '), 0); + TS_ASSERT_EQUALS(Common::isDigit('\n'), 0); + TS_ASSERT_EQUALS(Common::isDigit('\b'), 0); + TS_ASSERT_EQUALS(Common::isDigit(0), 0); + TS_ASSERT_EQUALS(Common::isDigit(255), 0); + + } + + void test_is_lower() { + + // Test the isLower function + // Should return true if and only if the input is a lowercase char + + TS_ASSERT_EQUALS(Common::isLower('a'), 1); + TS_ASSERT_EQUALS(Common::isLower('A'), 0); + TS_ASSERT_EQUALS(Common::isLower('z'), 1); + TS_ASSERT_EQUALS(Common::isLower('Z'), 0); + TS_ASSERT_EQUALS(Common::isLower('1'), 0); + TS_ASSERT_EQUALS(Common::isLower('0'), 0); + TS_ASSERT_EQUALS(Common::isLower('§'), 0); + TS_ASSERT_EQUALS(Common::isLower('$'), 0); + TS_ASSERT_EQUALS(Common::isLower(' '), 0); + TS_ASSERT_EQUALS(Common::isLower('\n'), 0); + TS_ASSERT_EQUALS(Common::isLower('\b'), 0); + TS_ASSERT_EQUALS(Common::isLower(0), 0); + TS_ASSERT_EQUALS(Common::isLower(255), 0); + + } + + + void test_is_upper() { + + // Test the isUpper function + // Should return true if and only if the input is an uppercase char + + TS_ASSERT_EQUALS(Common::isUpper('a'), 0); + TS_ASSERT_EQUALS(Common::isUpper('A'), 1); + TS_ASSERT_EQUALS(Common::isUpper('z'), 0); + TS_ASSERT_EQUALS(Common::isUpper('Z'), 1); + TS_ASSERT_EQUALS(Common::isUpper('1'), 0); + TS_ASSERT_EQUALS(Common::isUpper('0'), 0); + TS_ASSERT_EQUALS(Common::isUpper('§'), 0); + TS_ASSERT_EQUALS(Common::isUpper('$'), 0); + TS_ASSERT_EQUALS(Common::isUpper(' '), 0); + TS_ASSERT_EQUALS(Common::isUpper('\n'), 0); + TS_ASSERT_EQUALS(Common::isUpper('\b'), 0); + TS_ASSERT_EQUALS(Common::isUpper(0), 0); + TS_ASSERT_EQUALS(Common::isUpper(255), 0); + + } + void test_is_space() { + // isSpace should return true iff the character is some kind of whitespace + // or tab character + for (int c = 0; c < 255; c++) { + if (c == ' ' || c == '\t' || + c == '\r' || c == '\n' || + c == '\v' || c == '\f') { + TS_ASSERT_EQUALS(Common::isSpace(c), 1); + } else { + TS_ASSERT_EQUALS(Common::isSpace(c), 0); + } + } + } + + void test_is_print() { + // isPrint should return true iff the input is a printable ascii char. + // That is to say, 0x20 to 0x7E. + for (int c = 0; c < 255; c++) { + if (c >= 0x20 && c <= 0x7E) { + TS_ASSERT_EQUALS(Common::isPrint(c), 1); + } else { + TS_ASSERT_EQUALS(Common::isPrint(c), 0); + } + } + } +}; diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index 6fe9c773b8..34bc8c4a7a 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/mpeg.h" #include "video/codecs/msvideo1.h" #include "video/codecs/msrle.h" #include "video/codecs/truemotion1.h" @@ -64,8 +65,10 @@ namespace Video { #define ID_VEDT MKTAG('v','e','d','t') #define ID_IDX1 MKTAG('i','d','x','1') #define ID_STRD MKTAG('s','t','r','d') -#define ID_00AM MKTAG('0','0','A','M') -//#define ID_INFO MKTAG('I','N','F','O') +#define ID_INFO MKTAG('I','N','F','O') +#define ID_ISFT MKTAG('I','S','F','T') +#define ID_DISP MKTAG('D','I','S','P') +#define ID_PRMI MKTAG('P','R','M','I') // Codec tags #define ID_RLE MKTAG('R','L','E',' ') @@ -75,49 +78,45 @@ namespace Video { #define ID_CVID MKTAG('c','v','i','d') #define ID_IV32 MKTAG('i','v','3','2') #define ID_DUCK MKTAG('D','U','C','K') +#define ID_MPG2 MKTAG('m','p','g','2') -static byte char2num(char c) { - c = tolower((byte)c); - return (c >= 'a' && c <= 'f') ? c - 'a' + 10 : c - '0'; + +AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType) : _frameRateOverride(0), _soundType(soundType) { + initCommon(); } -static byte getStreamIndex(uint32 tag) { - return char2num((tag >> 24) & 0xFF) << 4 | char2num((tag >> 16) & 0xFF); +AVIDecoder::AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType) + : _frameRateOverride(frameRateOverride), _soundType(soundType) { + initCommon(); } -static uint16 getStreamType(uint32 tag) { - return tag & 0xffff; +AVIDecoder::~AVIDecoder() { + close(); } -AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType) : _soundType(soundType) { +void AVIDecoder::initCommon() { _decodedHeader = false; + _foundMovieList = false; + _movieListStart = 0; _fileStream = 0; - memset(&_ixInfo, 0, sizeof(_ixInfo)); memset(&_header, 0, sizeof(_header)); } -AVIDecoder::~AVIDecoder() { - close(); -} +bool AVIDecoder::parseNextChunk() { + uint32 tag = _fileStream->readUint32BE(); + uint32 size = _fileStream->readUint32LE(); -void AVIDecoder::runHandle(uint32 tag) { - assert(_fileStream); if (_fileStream->eos()) - return; + return false; debug(3, "Decoding tag %s", tag2str(tag)); switch (tag) { - case ID_RIFF: - /*_filesize = */_fileStream->readUint32LE(); - if (_fileStream->readUint32BE() != ID_AVI) - error("RIFF file is not an AVI video"); - break; case ID_LIST: - handleList(); + handleList(size); break; case ID_AVIH: - _header.size = _fileStream->readUint32LE(); + _header.size = size; _header.microSecondsPerFrame = _fileStream->readUint32LE(); _header.maxBytesPerSecond = _fileStream->readUint32LE(); _header.padding = _fileStream->readUint32LE(); @@ -132,50 +131,74 @@ void AVIDecoder::runHandle(uint32 tag) { _fileStream->skip(16); break; case ID_STRH: - handleStreamHeader(); + handleStreamHeader(size); break; case ID_STRD: // Extra stream info, safe to ignore case ID_VEDT: // Unknown, safe to ignore case ID_JUNK: // Alignment bytes, should be ignored - { - uint32 junkSize = _fileStream->readUint32LE(); - _fileStream->skip(junkSize + (junkSize & 1)); // Alignment - } break; + case ID_ISFT: // Metadata, safe to ignore + case ID_DISP: // Metadata, should be safe to ignore + skipChunk(size); + break; case ID_IDX1: - _ixInfo.size = _fileStream->readUint32LE(); - _ixInfo.indices = new OldIndex::Index[_ixInfo.size / 16]; - debug(0, "%d Indices", (_ixInfo.size / 16)); - for (uint32 i = 0; i < (_ixInfo.size / 16); i++) { - _ixInfo.indices[i].id = _fileStream->readUint32BE(); - _ixInfo.indices[i].flags = _fileStream->readUint32LE(); - _ixInfo.indices[i].offset = _fileStream->readUint32LE(); - _ixInfo.indices[i].size = _fileStream->readUint32LE(); - debug(0, "Index %d == Tag \'%s\', Offset = %d, Size = %d", i, tag2str(_ixInfo.indices[i].id), _ixInfo.indices[i].offset, _ixInfo.indices[i].size); + debug(0, "%d Indices", size / 16); + for (uint32 i = 0; i < size / 16; i++) { + OldIndex indexEntry; + indexEntry.id = _fileStream->readUint32BE(); + indexEntry.flags = _fileStream->readUint32LE(); + indexEntry.offset = _fileStream->readUint32LE(); + indexEntry.size = _fileStream->readUint32LE(); + _indexEntries.push_back(indexEntry); + debug(0, "Index %d == Tag \'%s\', Offset = %d, Size = %d", i, tag2str(indexEntry.id), indexEntry.offset, indexEntry.size); } break; default: error("Unknown tag \'%s\' found", tag2str(tag)); } + + return true; +} + +void AVIDecoder::skipChunk(uint32 size) { + // Make sure we're aligned on a word boundary + _fileStream->skip(size + (size & 1)); } -void AVIDecoder::handleList() { - uint32 listSize = _fileStream->readUint32LE() - 4; // Subtract away listType's 4 bytes +void AVIDecoder::handleList(uint32 listSize) { uint32 listType = _fileStream->readUint32BE(); + listSize -= 4; // Subtract away listType's 4 bytes uint32 curPos = _fileStream->pos(); debug(0, "Found LIST of type %s", tag2str(listType)); - while ((_fileStream->pos() - curPos) < listSize) - runHandle(_fileStream->readUint32BE()); - - // We now have all the header data - if (listType == ID_HDRL) + switch (listType) { + case ID_MOVI: // Movie List + // We found the movie block + _foundMovieList = true; + _movieListStart = curPos; + _fileStream->skip(listSize); + return; + case ID_HDRL: // Header List + // Mark the header as decoded _decodedHeader = true; + break; + case ID_INFO: // Metadata + case ID_PRMI: // Unknown metadata, should be safe to ignore + // Ignore metadata + _fileStream->skip(listSize); + return; + case ID_STRL: // Stream list + default: // (Just hope we can parse it!) + break; + } + + while ((_fileStream->pos() - curPos) < listSize) + parseNextChunk(); } -void AVIDecoder::handleStreamHeader() { +void AVIDecoder::handleStreamHeader(uint32 size) { AVIStreamHeader sHeader; - sHeader.size = _fileStream->readUint32LE(); + sHeader.size = size; sHeader.streamType = _fileStream->readUint32BE(); if (sHeader.streamType == ID_MIDS || sHeader.streamType == ID_TXTS) @@ -203,6 +226,11 @@ void AVIDecoder::handleStreamHeader() { uint32 startPos = _fileStream->pos(); if (sHeader.streamType == ID_VIDS) { + if (_frameRateOverride != 0) { + sHeader.rate = _frameRateOverride.getNumerator(); + sHeader.scale = _frameRateOverride.getDenominator(); + } + BitmapInfoHeader bmInfo; bmInfo.size = _fileStream->readUint32LE(); bmInfo.width = _fileStream->readUint32LE(); @@ -261,30 +289,41 @@ void AVIDecoder::handleStreamHeader() { bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) { close(); - _fileStream = stream; - _decodedHeader = false; + uint32 riffTag = stream->readUint32BE(); + if (riffTag != ID_RIFF) { + warning("Failed to find RIFF header"); + return false; + } - // Read chunks until we have decoded the header - while (!_decodedHeader) - runHandle(_fileStream->readUint32BE()); + /* uint32 fileSize = */ stream->readUint32LE(); + uint32 riffType = stream->readUint32BE(); - uint32 nextTag = _fileStream->readUint32BE(); + if (riffType != ID_AVI) { + warning("RIFF not an AVI file"); + return false; + } - // Throw out any JUNK section - if (nextTag == ID_JUNK) { - runHandle(ID_JUNK); - nextTag = _fileStream->readUint32BE(); + _fileStream = stream; + + // Go through all chunks in the file + while (parseNextChunk()) + ; + + if (!_decodedHeader) { + warning("Failed to parse AVI header"); + close(); + return false; } - // Ignore the 'movi' LIST - if (nextTag == ID_LIST) { - _fileStream->readUint32BE(); // Skip size - if (_fileStream->readUint32BE() != ID_MOVI) - error("Expected 'movi' LIST"); - } else { - error("Expected 'movi' LIST"); + if (!_foundMovieList) { + warning("Failed to find 'MOVI' list"); + close(); + return false; } + // Seek back to the start of the MOVI list + _fileStream->seek(_movieListStart); + return true; } @@ -294,33 +333,36 @@ void AVIDecoder::close() { delete _fileStream; _fileStream = 0; _decodedHeader = false; + _foundMovieList = false; + _movieListStart = 0; - delete[] _ixInfo.indices; - memset(&_ixInfo, 0, sizeof(_ixInfo)); + _indexEntries.clear(); memset(&_header, 0, sizeof(_header)); } void AVIDecoder::readNextPacket() { uint32 nextTag = _fileStream->readUint32BE(); + uint32 size = _fileStream->readUint32LE(); if (_fileStream->eos()) return; if (nextTag == ID_LIST) { // A list of audio/video chunks - uint32 listSize = _fileStream->readUint32LE() - 4; int32 startPos = _fileStream->pos(); if (_fileStream->readUint32BE() != ID_REC) error("Expected 'rec ' LIST"); + size -= 4; // subtract list type + // Decode chunks in the list - while (_fileStream->pos() < startPos + (int32)listSize) + while (_fileStream->pos() < startPos + (int32)size) readNextPacket(); return; } else if (nextTag == ID_JUNK || nextTag == ID_IDX1) { - runHandle(nextTag); + skipChunk(size); return; } @@ -329,12 +371,11 @@ void AVIDecoder::readNextPacket() { if (!track) error("Cannot get track from tag '%s'", tag2str(nextTag)); - uint32 chunkSize = _fileStream->readUint32LE(); Common::SeekableReadStream *chunk = 0; - if (chunkSize != 0) { - chunk = _fileStream->readStream(chunkSize); - _fileStream->skip(chunkSize & 1); + if (size != 0) { + chunk = _fileStream->readStream(size); + _fileStream->skip(size & 1); } if (track->getTrackType() == Track::kTrackTypeAudio) { @@ -379,6 +420,13 @@ void AVIDecoder::readNextPacket() { } } +byte AVIDecoder::getStreamIndex(uint32 tag) const { + char string[3]; + WRITE_BE_UINT16(string, tag >> 16); + string[2] = 0; + return strtol(string, 0, 16); +} + AVIDecoder::AVIVideoTrack::AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader) : _frameCount(frameCount), _vidsHeader(streamHeader), _bmInfo(bitmapInfoHeader) { memset(_palette, 0, sizeof(_palette)); @@ -428,6 +476,10 @@ Codec *AVIDecoder::AVIVideoTrack::createCodec() { case ID_DUCK: return new TrueMotion1Decoder(_bmInfo.width, _bmInfo.height); #endif +#ifdef USE_MPEG2 + case ID_MPG2: + return new MPEGDecoder(); +#endif default: warning("Unknown/Unhandled compression format \'%s\'", tag2str(_vidsHeader.streamHandler)); } diff --git a/video/avi_decoder.h b/video/avi_decoder.h index 34a67f4c28..5d52c7c797 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -20,10 +20,10 @@ * */ -#ifndef VIDEO_AVI_PLAYER_H -#define VIDEO_AVI_PLAYER_H +#ifndef VIDEO_AVI_DECODER_H +#define VIDEO_AVI_DECODER_H -#include "common/endian.h" +#include "common/array.h" #include "common/rational.h" #include "common/rect.h" #include "common/str.h" @@ -52,10 +52,13 @@ class Codec; * * Video decoder used in engines: * - sci + * - sword1 + * - sword2 */ class AVIDecoder : public VideoDecoder { public: AVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); + AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); virtual ~AVIDecoder(); bool loadStream(Common::SeekableReadStream *stream); @@ -99,13 +102,10 @@ private: }; struct OldIndex { + uint32 id; + uint32 flags; + uint32 offset; uint32 size; - struct Index { - uint32 id; - uint32 flags; - uint32 offset; - uint32 size; - } *indices; }; // Index Flags @@ -215,17 +215,24 @@ private: Audio::QueuingAudioStream *createAudioStream(); }; - OldIndex _ixInfo; + Common::Array<OldIndex> _indexEntries; AVIHeader _header; Common::SeekableReadStream *_fileStream; bool _decodedHeader; + bool _foundMovieList; + uint32 _movieListStart; Audio::Mixer::SoundType _soundType; - - void runHandle(uint32 tag); - void handleList(); - void handleStreamHeader(); + Common::Rational _frameRateOverride; + void initCommon(); + + bool parseNextChunk(); + void skipChunk(uint32 size); + void handleList(uint32 listSize); + void handleStreamHeader(uint32 size); + uint16 getStreamType(uint32 tag) const { return tag & 0xFFFF; } + byte getStreamIndex(uint32 tag) const; }; } // End of namespace Video diff --git a/video/codecs/cdtoons.cpp b/video/codecs/cdtoons.cpp index 528cee8094..68925ed0db 100644 --- a/video/codecs/cdtoons.cpp +++ b/video/codecs/cdtoons.cpp @@ -298,7 +298,7 @@ Graphics::Surface *CDToonsDecoder::decodeImage(Common::SeekableReadStream *strea for (uint i = 0; i < actions.size(); i++) { CDToonsAction &action = actions[i]; if (i == 0 && action.blockId == 0) - memset(_surface->pixels, backgroundColor, _surface->w * _surface->h); + memset(_surface->getPixels(), backgroundColor, _surface->w * _surface->h); if (!_blocks.contains(action.blockId)) continue; if (!action.rect.right) diff --git a/video/codecs/cinepak.cpp b/video/codecs/cinepak.cpp index bcf0cf1180..a7782f4192 100644 --- a/video/codecs/cinepak.cpp +++ b/video/codecs/cinepak.cpp @@ -41,11 +41,11 @@ namespace Video { byte b = _clipTable[lum + (u << 1)]; \ \ if (_pixelFormat.bytesPerPixel == 2) \ - *((uint16 *)_curFrame.surface->pixels + offset) = _pixelFormat.RGBToColor(r, g, b); \ + *((uint16 *)_curFrame.surface->getPixels() + offset) = _pixelFormat.RGBToColor(r, g, b); \ else \ - *((uint32 *)_curFrame.surface->pixels + offset) = _pixelFormat.RGBToColor(r, g, b); \ + *((uint32 *)_curFrame.surface->getPixels() + offset) = _pixelFormat.RGBToColor(r, g, b); \ } else \ - *((byte *)_curFrame.surface->pixels + offset) = lum + *((byte *)_curFrame.surface->getPixels() + offset) = lum CinepakDecoder::CinepakDecoder(int bitsPerPixel) : Codec() { _curFrame.surface = NULL; diff --git a/video/codecs/codec.h b/video/codecs/codec.h index c1194e461b..a4ad786bb0 100644 --- a/video/codecs/codec.h +++ b/video/codecs/codec.h @@ -51,7 +51,7 @@ public: * containing the decoded frame. * * @return a pointer to the decoded frame - * @note stream is not deleted + * @note stream is not deleted */ virtual const Graphics::Surface *decodeImage(Common::SeekableReadStream *stream) = 0; diff --git a/video/codecs/indeo3.cpp b/video/codecs/indeo3.cpp index 7bf7fc8235..28e1a9c620 100644 --- a/video/codecs/indeo3.cpp +++ b/video/codecs/indeo3.cpp @@ -32,8 +32,9 @@ #include "common/endian.h" #include "common/stream.h" #include "common/textconsole.h" +#include "common/util.h" -#include "graphics/conversion.h" +#include "graphics/yuv_to_rgb.h" #include "video/codecs/indeo3.h" @@ -260,91 +261,61 @@ const Graphics::Surface *Indeo3Decoder::decodeImage(Common::SeekableReadStream * delete[] inData; - // Blit the frame onto the surface const byte *srcY = _cur_frame->Ybuf; const byte *srcU = _cur_frame->Ubuf; const byte *srcV = _cur_frame->Vbuf; - byte *dest = (byte *)_surface->pixels; - - const byte *srcUP = srcU; - const byte *srcVP = srcV; - const byte *srcUN = srcU + chromaWidth; - const byte *srcVN = srcV + chromaWidth; - - uint32 scaleWidth = _surface->w / fWidth; - uint32 scaleHeight = _surface->h / fHeight; - for (uint32 y = 0; y < fHeight; y++) { - byte *rowDest = dest; - - for (uint32 sH = 0; sH < scaleHeight; sH++) { - for (uint32 x = 0; x < fWidth; x++) { - uint32 xP = MAX<int32>((x >> 2) - 1, 0); - uint32 xN = MIN<int32>((x >> 2) + 1, chromaWidth - 1); - - byte cY = srcY[x]; - byte cU = srcU[x >> 2]; - byte cV = srcV[x >> 2]; - - if (((x % 4) == 0) && ((y % 4) == 0)) { - cU = (((uint32) cU) + ((uint32) srcUP[xP])) / 2; - cV = (((uint32) cV) + ((uint32) srcVP[xP])) / 2; - } else if (((x % 4) == 3) && ((y % 4) == 0)) { - cU = (((uint32) cU) + ((uint32) srcUP[xN])) / 2; - cV = (((uint32) cV) + ((uint32) srcVP[xN])) / 2; - } else if (((x % 4) == 0) && ((y % 4) == 3)) { - cU = (((uint32) cU) + ((uint32) srcUN[xP])) / 2; - cV = (((uint32) cV) + ((uint32) srcVN[xP])) / 2; - } else if (((x % 4) == 3) && ((y % 4) == 3)) { - cU = (((uint32) cU) + ((uint32) srcUN[xN])) / 2; - cV = (((uint32) cV) + ((uint32) srcVN[xN])) / 2; - } else if ( (x % 4) == 0) { - cU = (((uint32) cU) + ((uint32) srcU[xP])) / 2; - cV = (((uint32) cV) + ((uint32) srcV[xP])) / 2; - } else if ( (x % 4) == 3) { - cU = (((uint32) cU) + ((uint32) srcU[xN])) / 2; - cV = (((uint32) cV) + ((uint32) srcV[xN])) / 2; - } else if ( (y % 4) == 0) { - cU = (((uint32) cU) + ((uint32) srcUP[x >> 2])) / 2; - cV = (((uint32) cV) + ((uint32) srcVP[x >> 2])) / 2; - } else if ( (y % 4) == 3) { - cU = (((uint32) cU) + ((uint32) srcUN[x >> 2])) / 2; - cV = (((uint32) cV) + ((uint32) srcVN[x >> 2])) / 2; - } + // Create buffers for U/V with an extra row/column copied from the second-to-last + // row/column. + byte *tempU = new byte[(chromaWidth + 1) * (chromaHeight + 1)]; + byte *tempV = new byte[(chromaWidth + 1) * (chromaHeight + 1)]; - byte r = 0, g = 0, b = 0; - Graphics::YUV2RGB(cY, cU, cV, r, g, b); + for (uint i = 0; i < chromaHeight; i++) { + memcpy(tempU + (chromaWidth + 1) * i, srcU + chromaWidth * i, chromaWidth); + memcpy(tempV + (chromaWidth + 1) * i, srcV + chromaWidth * i, chromaWidth); + tempU[(chromaWidth + 1) * i + chromaWidth] = srcU[chromaWidth * (i + 1) - 1]; + tempV[(chromaWidth + 1) * i + chromaWidth] = srcV[chromaWidth * (i + 1) - 1]; + } - const uint32 color = _pixelFormat.RGBToColor(r, g, b); + memcpy(tempU + (chromaWidth + 1) * chromaHeight, tempU + (chromaWidth + 1) * (chromaHeight - 1), + chromaWidth + 1); + memcpy(tempV + (chromaWidth + 1) * chromaHeight, tempV + (chromaWidth + 1) * (chromaHeight - 1), + chromaWidth + 1); - for (uint32 sW = 0; sW < scaleWidth; sW++, rowDest += _surface->format.bytesPerPixel) { - if (_surface->format.bytesPerPixel == 1) - *((uint8 *)rowDest) = (uint8)color; - else if (_surface->format.bytesPerPixel == 2) - *((uint16 *)rowDest) = (uint16)color; - } - } + // Blit the frame onto the surface + uint32 scaleWidth = _surface->w / fWidth; + uint32 scaleHeight = _surface->h / fHeight; - dest += _surface->pitch; + if (scaleWidth == 1 && scaleHeight == 1) { + // Shortcut: Don't need to scale so we can decode straight to the surface + YUVToRGBMan.convert410(_surface, Graphics::YUVToRGBManager::kScaleITU, srcY, tempU, tempV, + fWidth, fHeight, fWidth, chromaWidth + 1); + } else { + // Need to upscale, so decode to a temp surface first + Graphics::Surface tempSurface; + tempSurface.create(fWidth, fHeight, _surface->format); + + YUVToRGBMan.convert410(&tempSurface, Graphics::YUVToRGBManager::kScaleITU, srcY, tempU, tempV, + fWidth, fHeight, fWidth, chromaWidth + 1); + + // Upscale + for (int y = 0; y < _surface->h; y++) { + for (int x = 0; x < _surface->w; x++) { + if (_surface->format.bytesPerPixel == 1) + *((byte *)_surface->getBasePtr(x, y)) = *((byte *)tempSurface.getBasePtr(x / scaleWidth, y / scaleHeight)); + else if (_surface->format.bytesPerPixel == 2) + *((uint16 *)_surface->getBasePtr(x, y)) = *((uint16 *)tempSurface.getBasePtr(x / scaleWidth, y / scaleHeight)); + else if (_surface->format.bytesPerPixel == 4) + *((uint32 *)_surface->getBasePtr(x, y)) = *((uint32 *)tempSurface.getBasePtr(x / scaleWidth, y / scaleHeight)); + } } - srcY += fWidth; - - if ((y & 3) == 3) { - srcU += chromaWidth; - srcV += chromaWidth; - - if (y > 0) { - srcUP += chromaWidth; - srcVP += chromaWidth; - } - if (y < (fHeight - 4U)) { - srcUN += chromaWidth; - srcVN += chromaWidth; - } - } + tempSurface.free(); } + delete[] tempU; + delete[] tempV; + return _surface; } diff --git a/video/codecs/mpeg.cpp b/video/codecs/mpeg.cpp new file mode 100644 index 0000000000..4540b4182e --- /dev/null +++ b/video/codecs/mpeg.cpp @@ -0,0 +1,107 @@ +/* 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/debug.h" +#include "common/stream.h" +#include "common/system.h" +#include "common/textconsole.h" +#include "graphics/surface.h" +#include "graphics/yuv_to_rgb.h" + +#include "video/codecs/mpeg.h" + +namespace Video { + +MPEGDecoder::MPEGDecoder() : Codec() { + _pixelFormat = g_system->getScreenFormat(); + _surface = 0; + + _mpegDecoder = mpeg2_init(); + + if (!_mpegDecoder) + error("Could not initialize libmpeg2"); + + _mpegInfo = mpeg2_info(_mpegDecoder); +} + +MPEGDecoder::~MPEGDecoder() { + mpeg2_close(_mpegDecoder); + + if (_surface) { + _surface->free(); + delete _surface; + } +} + +const Graphics::Surface *MPEGDecoder::decodeImage(Common::SeekableReadStream *stream) { + uint32 framePeriod; + decodePacket(stream, framePeriod); + return _surface; +} + +bool MPEGDecoder::decodePacket(Common::SeekableReadStream *packet, uint32 &framePeriod, Graphics::Surface *dst) { + // Decode as much as we can out of this packet + uint32 size = 0xFFFFFFFF; + mpeg2_state_t state; + bool foundFrame = false; + framePeriod = 0; + + do { + state = mpeg2_parse(_mpegDecoder); + + switch (state) { + case STATE_BUFFER: + size = packet->read(_buffer, BUFFER_SIZE); + mpeg2_buffer(_mpegDecoder, _buffer, _buffer + size); + break; + case STATE_SLICE: + case STATE_END: + if (_mpegInfo->display_fbuf) { + foundFrame = true; + const mpeg2_sequence_t *sequence = _mpegInfo->sequence; + + framePeriod += sequence->frame_period; + + if (!dst) { + // If no destination is specified, use our internal storage + if (!_surface) { + _surface = new Graphics::Surface(); + _surface->create(sequence->picture_width, sequence->picture_height, _pixelFormat); + } + + dst = _surface; + } + + YUVToRGBMan.convert420(dst, Graphics::YUVToRGBManager::kScaleITU, _mpegInfo->display_fbuf->buf[0], + _mpegInfo->display_fbuf->buf[1], _mpegInfo->display_fbuf->buf[2], sequence->picture_width, + sequence->picture_height, sequence->width, sequence->chroma_width); + } + break; + default: + break; + } + } while (size != 0); + + return foundFrame; +} + +} // End of namespace Video diff --git a/video/codecs/mpeg.h b/video/codecs/mpeg.h new file mode 100644 index 0000000000..0082844537 --- /dev/null +++ b/video/codecs/mpeg.h @@ -0,0 +1,98 @@ +/* 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. + * + */ + +#ifdef USE_MPEG2 + +#ifndef VIDEO_CODECS_MPEG_H +#define VIDEO_CODECS_MPEG_H + +#include "video/codecs/codec.h" +#include "graphics/pixelformat.h" + +#if defined(__PLAYSTATION2__) + typedef uint8 uint8_t; + typedef uint16 uint16_t; + typedef uint32 uint32_t; +#elif defined(_WIN32_WCE) + typedef signed char int8_t; + typedef signed short int16_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; +#elif defined(_MSC_VER) + typedef signed char int8_t; + typedef signed short int16_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + #if !defined(SDL_COMPILEDVERSION) || (SDL_COMPILEDVERSION < 1210) + typedef signed long int32_t; + typedef unsigned long uint32_t; + #endif +#else +# include <inttypes.h> +#endif + +extern "C" { + #include <mpeg2dec/mpeg2.h> +} + +namespace Common { +class SeekableReadStream; +} + +namespace Graphics { +struct Surface; +} + +namespace Video { + +// MPEG 1/2 video decoder + +class MPEGDecoder : public Codec { +public: + MPEGDecoder(); + ~MPEGDecoder(); + + // Codec interface + const Graphics::Surface *decodeImage(Common::SeekableReadStream *stream); + Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; } + + // MPEGPSDecoder call + bool decodePacket(Common::SeekableReadStream *packet, uint32 &framePeriod, Graphics::Surface *dst = 0); + +private: + Graphics::PixelFormat _pixelFormat; + Graphics::Surface *_surface; + + enum { + BUFFER_SIZE = 4096 + }; + + byte _buffer[BUFFER_SIZE]; + mpeg2dec_t *_mpegDecoder; + const mpeg2_info_t *_mpegInfo; +}; + +} // End of namespace Video + +#endif // VIDEO_CODECS_MPEG_H + +#endif // USE_MPEG2 diff --git a/video/codecs/msrle.cpp b/video/codecs/msrle.cpp index fa03a59efd..2f2ac0334f 100644 --- a/video/codecs/msrle.cpp +++ b/video/codecs/msrle.cpp @@ -53,7 +53,7 @@ void MSRLEDecoder::decode8(Common::SeekableReadStream *stream) { int x = 0; int y = _surface->h - 1; - byte *data = (byte *) _surface->pixels; + byte *data = (byte *) _surface->getPixels(); uint16 width = _surface->w; uint16 height = _surface->h; diff --git a/video/codecs/msvideo1.cpp b/video/codecs/msvideo1.cpp index 06e4640025..409d588ddf 100644 --- a/video/codecs/msvideo1.cpp +++ b/video/codecs/msvideo1.cpp @@ -48,7 +48,7 @@ MSVideo1Decoder::~MSVideo1Decoder() { void MSVideo1Decoder::decode8(Common::SeekableReadStream *stream) { byte colors[8]; - byte *pixels = (byte *)_surface->pixels; + byte *pixels = (byte *)_surface->getPixels(); uint16 stride = _surface->w; int skipBlocks = 0; diff --git a/video/codecs/qtrle.cpp b/video/codecs/qtrle.cpp index d2cdea27de..1f1fee7997 100644 --- a/video/codecs/qtrle.cpp +++ b/video/codecs/qtrle.cpp @@ -61,7 +61,7 @@ QTRLEDecoder::QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel) : Cod void QTRLEDecoder::decode1(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) { uint32 pixelPtr = 0; - byte *rgb = (byte *)_surface->pixels; + byte *rgb = (byte *)_surface->getPixels(); while (linesToChange) { CHECK_STREAM_PTR(2); @@ -105,7 +105,7 @@ void QTRLEDecoder::decode1(Common::SeekableReadStream *stream, uint32 rowPtr, ui void QTRLEDecoder::decode2_4(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange, byte bpp) { uint32 pixelPtr = 0; - byte *rgb = (byte *)_surface->pixels; + byte *rgb = (byte *)_surface->getPixels(); byte numPixels = (bpp == 4) ? 8 : 16; while (linesToChange--) { @@ -165,7 +165,7 @@ void QTRLEDecoder::decode2_4(Common::SeekableReadStream *stream, uint32 rowPtr, void QTRLEDecoder::decode8(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) { uint32 pixelPtr = 0; - byte *rgb = (byte *)_surface->pixels; + byte *rgb = (byte *)_surface->getPixels(); while (linesToChange--) { CHECK_STREAM_PTR(2); @@ -210,7 +210,7 @@ void QTRLEDecoder::decode8(Common::SeekableReadStream *stream, uint32 rowPtr, ui void QTRLEDecoder::decode16(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) { uint32 pixelPtr = 0; - uint16 *rgb = (uint16 *)_surface->pixels; + uint16 *rgb = (uint16 *)_surface->getPixels(); while (linesToChange--) { CHECK_STREAM_PTR(2); @@ -248,7 +248,7 @@ void QTRLEDecoder::decode16(Common::SeekableReadStream *stream, uint32 rowPtr, u void QTRLEDecoder::decode24(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) { uint32 pixelPtr = 0; - uint32 *rgb = (uint32 *)_surface->pixels; + uint32 *rgb = (uint32 *)_surface->getPixels(); while (linesToChange--) { CHECK_STREAM_PTR(2); @@ -294,7 +294,7 @@ void QTRLEDecoder::decode24(Common::SeekableReadStream *stream, uint32 rowPtr, u void QTRLEDecoder::decode32(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) { uint32 pixelPtr = 0; - uint32 *rgb = (uint32 *)_surface->pixels; + uint32 *rgb = (uint32 *)_surface->getPixels(); while (linesToChange--) { CHECK_STREAM_PTR(2); diff --git a/video/codecs/rpza.cpp b/video/codecs/rpza.cpp index 0a9f87747e..17a2c53d9b 100644 --- a/video/codecs/rpza.cpp +++ b/video/codecs/rpza.cpp @@ -58,7 +58,7 @@ RPZADecoder::~RPZADecoder() { #define PUT_PIXEL(color) \ if ((int32)blockPtr < _surface->w * _surface->h) \ - WRITE_UINT16((uint16 *)_surface->pixels + blockPtr, color); \ + WRITE_UINT16((uint16 *)_surface->getPixels() + blockPtr, color); \ blockPtr++ const Graphics::Surface *RPZADecoder::decodeImage(Common::SeekableReadStream *stream) { diff --git a/video/codecs/smc.cpp b/video/codecs/smc.cpp index 2eedb62a0f..c0f8152547 100644 --- a/video/codecs/smc.cpp +++ b/video/codecs/smc.cpp @@ -56,7 +56,7 @@ SMCDecoder::~SMCDecoder() { } const Graphics::Surface *SMCDecoder::decodeImage(Common::SeekableReadStream *stream) { - byte *pixels = (byte *)_surface->pixels; + byte *pixels = (byte *)_surface->getPixels(); uint32 numBlocks = 0; uint32 colorFlags = 0; diff --git a/video/coktel_decoder.cpp b/video/coktel_decoder.cpp index d24a021f3b..024e479bf7 100644 --- a/video/coktel_decoder.cpp +++ b/video/coktel_decoder.cpp @@ -97,12 +97,8 @@ void CoktelDecoder::setSurfaceMemory(void *mem, uint16 width, uint16 height, uin assert(bpp == getPixelFormat().bytesPerPixel); // Create a surface over this memory - _surface.w = width; - _surface.h = height; - _surface.pitch = width * bpp; - _surface.pixels = mem; // TODO: Check whether it is fine to assume we want the setup PixelFormat. - _surface.format = getPixelFormat(); + _surface.init(width, height, width * bpp, mem, getPixelFormat()); _ownSurface = false; } @@ -122,7 +118,7 @@ const Graphics::Surface *CoktelDecoder::getSurface() const { } bool CoktelDecoder::hasSurface() { - return _surface.pixels != 0; + return _surface.getPixels(); } void CoktelDecoder::createSurface() { @@ -143,7 +139,7 @@ void CoktelDecoder::freeSurface() { _surface.w = 0; _surface.h = 0; _surface.pitch = 0; - _surface.pixels = 0; + _surface.setPixels(0); _surface.format = Graphics::PixelFormat(); } else _surface.free(); @@ -473,7 +469,7 @@ void CoktelDecoder::renderBlockWhole(Graphics::Surface &dstSurf, const byte *src rect.clip(dstSurf.w, dstSurf.h); - byte *dst = (byte *)dstSurf.pixels + (rect.top * dstSurf.pitch) + rect.left * dstSurf.format.bytesPerPixel; + byte *dst = (byte *)dstSurf.getBasePtr(rect.left, rect.top); for (int i = 0; i < rect.height(); i++) { memcpy(dst, src, rect.width() * dstSurf.format.bytesPerPixel); @@ -488,7 +484,7 @@ void CoktelDecoder::renderBlockWhole4X(Graphics::Surface &dstSurf, const byte *s rect.clip(dstSurf.w, dstSurf.h); - byte *dst = (byte *)dstSurf.pixels + (rect.top * dstSurf.pitch) + rect.left; + byte *dst = (byte *)dstSurf.getBasePtr(rect.left, rect.top); for (int i = 0; i < rect.height(); i++) { byte *dstRow = dst; const byte *srcRow = src; @@ -515,7 +511,7 @@ void CoktelDecoder::renderBlockWhole2Y(Graphics::Surface &dstSurf, const byte *s int16 height = rect.height(); - byte *dst = (byte *)dstSurf.pixels + (rect.top * dstSurf.pitch) + rect.left; + byte *dst = (byte *)dstSurf.getBasePtr(rect.left, rect.top); while (height > 1) { memcpy(dst , src, rect.width()); memcpy(dst + dstSurf.pitch, src, rect.width()); @@ -535,7 +531,7 @@ void CoktelDecoder::renderBlockSparse(Graphics::Surface &dstSurf, const byte *sr rect.clip(dstSurf.w, dstSurf.h); - byte *dst = (byte *)dstSurf.pixels + (rect.top * dstSurf.pitch) + rect.left; + byte *dst = (byte *)dstSurf.getBasePtr(rect.left, rect.top); for (int i = 0; i < rect.height(); i++) { byte *dstRow = dst; int16 pixWritten = 0; @@ -572,7 +568,7 @@ void CoktelDecoder::renderBlockSparse2Y(Graphics::Surface &dstSurf, const byte * rect.clip(dstSurf.w, dstSurf.h); - byte *dst = (byte *)dstSurf.pixels + (rect.top * dstSurf.pitch) + rect.left; + byte *dst = (byte *)dstSurf.getBasePtr(rect.left, rect.top); for (int i = 0; i < rect.height(); i += 2) { byte *dstRow = dst; int16 pixWritten = 0; @@ -604,7 +600,7 @@ void CoktelDecoder::renderBlockRLE(Graphics::Surface &dstSurf, const byte *src, rect.clip(dstSurf.w, dstSurf.h); - byte *dst = (byte *)dstSurf.pixels + (rect.top * dstSurf.pitch) + rect.left; + byte *dst = (byte *)dstSurf.getBasePtr(rect.left, rect.top); for (int i = 0; i < rect.height(); i++) { byte *dstRow = dst; int16 pixWritten = 0; @@ -865,7 +861,7 @@ void PreIMDDecoder::renderFrame() { uint16 h = CLIP<int32>(_surface.h - _y, 0, _height); const byte *src = _videoBuffer; - byte *dst = (byte *)_surface.pixels + (_y * _surface.pitch) + _x; + byte *dst = (byte *)_surface.getBasePtr(_x, _y); uint32 frameDataSize = _videoBufferSize; @@ -1458,7 +1454,7 @@ bool IMDDecoder::renderFrame(Common::Rect &rect) { const int offsetY = (_y + rect.top) * _surface.pitch; const int offset = offsetX + offsetY; - if (deLZ77((byte *)_surface.pixels + offset, dataPtr, dataSize, + if (deLZ77((byte *)_surface.getPixels() + offset, dataPtr, dataSize, _surface.w * _surface.h * _surface.format.bytesPerPixel - offset)) return true; } @@ -1879,11 +1875,8 @@ bool VMDDecoder::assessVideoProperties() { _videoBuffer[i] = new byte[_videoBufferSize]; memset(_videoBuffer[i], 0, _videoBufferSize); - _8bppSurface[i].w = _width * _bytesPerPixel; - _8bppSurface[i].h = _height; - _8bppSurface[i].pitch = _width * _bytesPerPixel; - _8bppSurface[i].pixels = _videoBuffer[i]; - _8bppSurface[i].format = Graphics::PixelFormat::createFormatCLUT8(); + _8bppSurface[i].init(_width * _bytesPerPixel, _height, _width * _bytesPerPixel, + _videoBuffer[i], Graphics::PixelFormat::createFormatCLUT8()); } } @@ -2277,7 +2270,7 @@ bool VMDDecoder::renderFrame(Common::Rect &rect) { rect = Common::Rect(_x, _y, _x + codecSurf->w, _y + codecSurf->h); rect.clip(Common::Rect(_x, _y, _x + _width, _y + _height)); - renderBlockWhole(_surface, (const byte *) codecSurf->pixels, rect); + renderBlockWhole(_surface, (const byte *)codecSurf->getPixels(), rect); return true; } @@ -2298,7 +2291,7 @@ bool VMDDecoder::renderFrame(Common::Rect &rect) { const int offsetY = (_y + rect.top) * _surface.pitch; const int offset = offsetX + offsetY; - if (deLZ77((byte *)_surface.pixels + offset, dataPtr, dataSize, + if (deLZ77((byte *)_surface.getPixels() + offset, dataPtr, dataSize, _surface.w * _surface.h * _surface.format.bytesPerPixel - offset)) return true; } @@ -2406,10 +2399,11 @@ void VMDDecoder::blit16(const Graphics::Surface &srcSurf, Common::Rect &rect) { Graphics::PixelFormat pixelFormat = getPixelFormat(); - const byte *src = (byte *)srcSurf.pixels + + // We cannot use getBasePtr here because srcSurf.format.bytesPerPixel is + // different from _bytesPerPixel. + const byte *src = (const byte *)srcSurf.getPixels() + (srcRect.top * srcSurf.pitch) + srcRect.left * _bytesPerPixel; - byte *dst = (byte *)_surface.pixels + - ((_y + rect.top) * _surface.pitch) + (_x + rect.left) * _surface.format.bytesPerPixel; + byte *dst = (byte *)_surface.getBasePtr(_x + rect.left, _y + rect.top); for (int i = 0; i < rect.height(); i++) { const byte *srcRow = src; @@ -2426,8 +2420,10 @@ void VMDDecoder::blit16(const Graphics::Surface &srcSurf, Common::Rect &rect) { if ((r == 0) && (g == 0) && (b == 0)) c = 0; - if (_surface.format.bytesPerPixel == 2) + if (_surface.format.bytesPerPixel == 2) *((uint16 *)dstRow) = (uint16) c; + else if (_surface.format.bytesPerPixel == 4) + *((uint32 *)dstRow) = (uint32) c; } src += srcSurf .pitch; @@ -2444,10 +2440,11 @@ void VMDDecoder::blit24(const Graphics::Surface &srcSurf, Common::Rect &rect) { Graphics::PixelFormat pixelFormat = getPixelFormat(); - const byte *src = (byte *)srcSurf.pixels + + // We cannot use getBasePtr here because srcSurf.format.bytesPerPixel is + // different from _bytesPerPixel. + const byte *src = (const byte *)srcSurf.getPixels() + (srcRect.top * srcSurf.pitch) + srcRect.left * _bytesPerPixel; - byte *dst = (byte *)_surface.pixels + - ((_y + rect.top) * _surface.pitch) + (_x + rect.left) * _surface.format.bytesPerPixel; + byte *dst = (byte *)_surface.getBasePtr(_x + rect.left, _y + rect.top); for (int i = 0; i < rect.height(); i++) { const byte *srcRow = src; @@ -2462,8 +2459,10 @@ void VMDDecoder::blit24(const Graphics::Surface &srcSurf, Common::Rect &rect) { if ((r == 0) && (g == 0) && (b == 0)) c = 0; - if (_surface.format.bytesPerPixel == 2) + if (_surface.format.bytesPerPixel == 2) *((uint16 *)dstRow) = (uint16) c; + else if (_surface.format.bytesPerPixel == 4) + *((uint32 *)dstRow) = (uint32) c; } src += srcSurf .pitch; diff --git a/video/dxa_decoder.cpp b/video/dxa_decoder.cpp index 5ac9bd2088..27b1664b07 100644 --- a/video/dxa_decoder.cpp +++ b/video/dxa_decoder.cpp @@ -521,17 +521,17 @@ const Graphics::Surface *DXADecoder::DXAVideoTrack::decodeNextFrame() { memcpy(&_scaledBuffer[2 * cy * _width], &_frameBuffer1[cy * _width], _width); memset(&_scaledBuffer[((2 * cy) + 1) * _width], 0, _width); } - _surface->pixels = _scaledBuffer; + _surface->setPixels(_scaledBuffer); break; case S_DOUBLE: for (int cy = 0; cy < _curHeight; cy++) { memcpy(&_scaledBuffer[2 * cy * _width], &_frameBuffer1[cy * _width], _width); memcpy(&_scaledBuffer[((2 * cy) + 1) * _width], &_frameBuffer1[cy * _width], _width); } - _surface->pixels = _scaledBuffer; + _surface->setPixels(_scaledBuffer); break; case S_NONE: - _surface->pixels = _frameBuffer1; + _surface->setPixels(_frameBuffer1); break; } diff --git a/video/flic_decoder.cpp b/video/flic_decoder.cpp index de545366b1..317dc14691 100644 --- a/video/flic_decoder.cpp +++ b/video/flic_decoder.cpp @@ -244,7 +244,7 @@ void FlicDecoder::FlicVideoTrack::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) for (Common::List<Common::Rect>::const_iterator it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) { for (int y = (*it).top; y < (*it).bottom; ++y) { const int x = (*it).left; - memcpy(dst + y * pitch + x, (byte *)_surface->pixels + y * getWidth() + x, (*it).right - x); + memcpy(dst + y * pitch + x, (byte *)_surface->getBasePtr(x, y), (*it).right - x); } } @@ -252,7 +252,7 @@ void FlicDecoder::FlicVideoTrack::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) } void FlicDecoder::FlicVideoTrack::copyFrame(uint8 *data) { - memcpy((byte *)_surface->pixels, data, getWidth() * getHeight()); + memcpy((byte *)_surface->getPixels(), data, getWidth() * getHeight()); // Redraw _dirtyRects.clear(); @@ -260,8 +260,8 @@ void FlicDecoder::FlicVideoTrack::copyFrame(uint8 *data) { } void FlicDecoder::FlicVideoTrack::decodeByteRun(uint8 *data) { - byte *ptr = (byte *)_surface->pixels; - while ((int32)(ptr - (byte *)_surface->pixels) < (getWidth() * getHeight())) { + byte *ptr = (byte *)_surface->getPixels(); + while ((int32)(ptr - (byte *)_surface->getPixels()) < (getWidth() * getHeight())) { int chunks = *data++; while (chunks--) { int count = (int8)*data++; @@ -305,7 +305,7 @@ void FlicDecoder::FlicVideoTrack::decodeDeltaFLC(uint8 *data) { case OP_UNDEFINED: break; case OP_LASTPIXEL: - *((byte *)_surface->pixels + currentLine * getWidth() + getWidth() - 1) = (opcode & 0xFF); + *((byte *)_surface->getBasePtr(getWidth() - 1, currentLine)) = (opcode & 0xFF); _dirtyRects.push_back(Common::Rect(getWidth() - 1, currentLine, getWidth(), currentLine + 1)); break; case OP_LINESKIPCOUNT: @@ -321,14 +321,14 @@ void FlicDecoder::FlicVideoTrack::decodeDeltaFLC(uint8 *data) { column += *data++; int rleCount = (int8)*data++; if (rleCount > 0) { - memcpy((byte *)_surface->pixels + (currentLine * getWidth()) + column, data, rleCount * 2); + memcpy((byte *)_surface->getBasePtr(column, currentLine), data, rleCount * 2); data += rleCount * 2; _dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1)); } else if (rleCount < 0) { rleCount = -rleCount; uint16 dataWord = READ_UINT16(data); data += 2; for (int i = 0; i < rleCount; ++i) { - WRITE_UINT16((byte *)_surface->pixels + currentLine * getWidth() + column + i * 2, dataWord); + WRITE_UINT16((byte *)_surface->getBasePtr(column + i * 2, currentLine), dataWord); } _dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1)); } else { // End of cutscene ? diff --git a/video/module.mk b/video/module.mk index 287e14ce18..a491947aaf 100644 --- a/video/module.mk +++ b/video/module.mk @@ -31,5 +31,10 @@ MODULE_OBJS += \ theora_decoder.o endif +ifdef USE_MPEG2 +MODULE_OBJS += \ + codecs/mpeg.o +endif + # Include common rules include $(srcdir)/rules.mk diff --git a/video/smk_decoder.cpp b/video/smk_decoder.cpp index b622a0ab61..3dbcebcde4 100644 --- a/video/smk_decoder.cpp +++ b/video/smk_decoder.cpp @@ -580,7 +580,7 @@ void SmackerDecoder::SmackerVideoTrack::decodeFrame(Common::BitStream &bs) { while (run-- && block < blocks) { clr = _MClrTree->getCode(bs); map = _MMapTree->getCode(bs); - out = (byte *)_surface->pixels + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4; + out = (byte *)_surface->getPixels() + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4; hi = clr >> 8; lo = clr & 0xff; for (i = 0; i < 4; i++) { @@ -613,7 +613,7 @@ void SmackerDecoder::SmackerVideoTrack::decodeFrame(Common::BitStream &bs) { } while (run-- && block < blocks) { - out = (byte *)_surface->pixels + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4; + out = (byte *)_surface->getPixels() + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4; switch (mode) { case 0: for (i = 0; i < 4; ++i) { @@ -679,7 +679,7 @@ void SmackerDecoder::SmackerVideoTrack::decodeFrame(Common::BitStream &bs) { uint32 col; mode = type >> 8; while (run-- && block < blocks) { - out = (byte *)_surface->pixels + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4; + out = (byte *)_surface->getPixels() + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4; col = mode * 0x01010101; for (i = 0; i < 4 * doubleY; ++i) { out[0] = out[1] = out[2] = out[3] = col; diff --git a/video/theora_decoder.cpp b/video/theora_decoder.cpp index 63aa93e2f5..a0ee0a36b4 100644 --- a/video/theora_decoder.cpp +++ b/video/theora_decoder.cpp @@ -262,11 +262,8 @@ TheoraDecoder::TheoraVideoTrack::TheoraVideoTrack(const Graphics::PixelFormat &f _surface.create(theoraInfo.frame_width, theoraInfo.frame_height, format); // Set up a display surface - _displaySurface.pixels = _surface.getBasePtr(theoraInfo.pic_x, theoraInfo.pic_y); - _displaySurface.w = theoraInfo.pic_width; - _displaySurface.h = theoraInfo.pic_height; - _displaySurface.format = format; - _displaySurface.pitch = _surface.pitch; + _displaySurface.init(theoraInfo.pic_width, theoraInfo.pic_height, _surface.pitch, + _surface.getBasePtr(theoraInfo.pic_x, theoraInfo.pic_y), format); // Set the frame rate _frameRate = Common::Rational(theoraInfo.fps_numerator, theoraInfo.fps_denominator); @@ -280,7 +277,7 @@ TheoraDecoder::TheoraVideoTrack::~TheoraVideoTrack() { th_decode_free(_theoraDecode); _surface.free(); - _displaySurface.pixels = 0; + _displaySurface.setPixels(0); } bool TheoraDecoder::TheoraVideoTrack::decodePacket(ogg_packet &oggPacket) { @@ -338,7 +335,7 @@ TheoraDecoder::VorbisAudioTrack::VorbisAudioTrack(Audio::Mixer::SoundType soundT vorbis_block_init(&_vorbisDSP, &_vorbisBlock); info = &vorbisInfo; - _audStream = Audio::makeQueuingAudioStream(vorbisInfo.rate, vorbisInfo.channels); + _audStream = Audio::makeQueuingAudioStream(vorbisInfo.rate, vorbisInfo.channels != 1); _audioBufferFill = 0; _audioBuffer = 0; diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 5df811008c..a512a49fac 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -336,9 +336,9 @@ bool VideoDecoder::seek(const Audio::Timestamp &time) { if (isPlaying()) stopAudio(); - for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) - if (!(*it)->seek(time)) - return false; + // Do the actual seeking + if (!seekIntern(time)) + return false; _lastTimeChange = time; @@ -471,6 +471,14 @@ Audio::Timestamp VideoDecoder::getDuration() const { return maxDuration; } +bool VideoDecoder::seekIntern(const Audio::Timestamp &time) { + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + if (!(*it)->seek(time)) + return false; + + return true; +} + VideoDecoder::Track::Track() { _paused = false; } diff --git a/video/video_decoder.h b/video/video_decoder.h index d0a6e08005..7811734dd5 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -168,14 +168,15 @@ public: /** * Seek to a given time in the video. * - * If the video is playing, it will continue to play. The default - * implementation will seek each track and must still be called - * from any other implementation. + * If the video is playing, it will continue to play. This calls + * seekIntern(), which can be overriden. By default, seekIntern() + * will call Track::seek() on all tracks with the time passed to + * this function. * * @param time The time to seek to * @return true on success, false otherwise */ - virtual bool seek(const Audio::Timestamp &time); + bool seek(const Audio::Timestamp &time); /** * Seek to a given frame. @@ -820,6 +821,15 @@ protected: */ TrackListIterator getTrackListEnd() { return _tracks.end(); } + /** + * The internal seek function that does the actual seeking. + * + * @see seek() + * + * @return true on success, false otherwise + */ + virtual bool seekIntern(const Audio::Timestamp &time); + private: // Tracks owned by this VideoDecoder TrackList _tracks; |