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