[Scummvm-git-logs] scummvm master -> 125fd9d80cfa46e2ae834281304654856ce42aec
sev-
sev at scummvm.org
Fri Oct 23 22:59:08 UTC 2020
This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
f3f0d0228a IMAGE: Add decoder for CEL 3DO format
ce6eb34121 VIDEO: uplift 3do movie decoder from sherlock engine
3c97ebd4f9 VIDEO: support multi-track audios in 3DO videos
125fd9d80c PLUMBERS: support for 3DO version
Commit: f3f0d0228a3dfe6b4a255079f0753522cbebd2f3
https://github.com/scummvm/scummvm/commit/f3f0d0228a3dfe6b4a255079f0753522cbebd2f3
Author: Vladimir Serbinenko (phcoder at google.com)
Date: 2020-10-24T00:59:01+02:00
Commit Message:
IMAGE: Add decoder for CEL 3DO format
This format is used by 3DO version of Plumbers Don't Wear Ties
but it's a generic format on 3DO similar to BMP on windows.
Changed paths:
A image/cel_3do.cpp
A image/cel_3do.h
image/module.mk
diff --git a/image/cel_3do.cpp b/image/cel_3do.cpp
new file mode 100644
index 0000000000..5d9c96e6f7
--- /dev/null
+++ b/image/cel_3do.cpp
@@ -0,0 +1,165 @@
+/* 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 "image/cel_3do.h"
+
+#include "common/file.h"
+#include "common/stream.h"
+#include "common/substream.h"
+#include "common/textconsole.h"
+#include "graphics/pixelformat.h"
+#include "graphics/surface.h"
+#include "image/bmp.h"
+
+namespace Image {
+
+enum CCBFlags {
+ kCCBPacked = 1 << 9,
+ kCCBNoPre0 = 1 << 22
+};
+
+Cel3DODecoder::Cel3DODecoder() {
+ _surface = 0;
+ _palette = 0;
+ _paletteColorCount = 0;
+}
+
+Cel3DODecoder::~Cel3DODecoder() {
+ destroy();
+}
+
+void Cel3DODecoder::destroy() {
+ _surface = 0;
+
+ delete[] _palette;
+ _palette = 0;
+
+ _paletteColorCount = 0;
+}
+
+bool Cel3DODecoder::loadStream(Common::SeekableReadStream &stream) {
+ destroy();
+
+ // This is not a full implementaion of CEL support,
+ // just what is currently needed for following games:
+ // * Plumbers don't wear ties
+ // TODO: support paletted
+
+ if (stream.readUint32BE() != MKTAG('C', 'C', 'B', ' '))
+ return false;
+
+ if (stream.readUint32BE() != 0x50) // block size
+ return false;
+
+ if (stream.readUint32BE() != 0) // CCB version
+ return false;
+
+ uint32 flags = stream.readUint32BE();
+
+ stream.skip(0x30);
+ uint32 pre0 = stream.readUint32BE();
+ /* pre1 = */ stream.readUint32BE();
+ uint32 width = stream.readUint32BE();
+ uint32 height = stream.readUint32BE();
+
+ while (!stream.eos()) {
+ if (stream.readUint32BE() == MKTAG('P', 'D', 'A', 'T'))
+ break;
+ stream.skip(stream.readUint32BE() - 8);
+ }
+
+ if (stream.eos())
+ return false;
+
+ if (width == 0 || height == 0)
+ return false;
+
+ /* pdat_size = */ stream.readUint32BE();
+
+ Graphics::PixelFormat format(2, 5, 5, 5, 1, 10, 5, 0, 15);
+ Graphics::Surface *surface = new Graphics::Surface();
+ surface->create(width, height, format);
+
+ uint16 *dst = (uint16 *)surface->getBasePtr(0, 0);
+
+ if(!(flags & kCCBNoPre0)) {
+ pre0 = stream.readUint32BE();
+ if(!(flags & kCCBPacked)) {
+ /* pre1 = */ stream.readUint32BE();
+ }
+ }
+
+ // Only RGB555 is supported
+ if ((pre0 & 0x17) != 0x16)
+ return false;
+
+ if(!(flags & kCCBPacked)) {
+ // RAW
+ // TODO: this can be optimized, especially on BE systems, but do we care?
+ for (uint xy = 0; xy < width * height; xy++)
+ *dst++ = stream.readUint16BE();
+ } else {
+ // RLE
+ for (uint y = 0; y < height; y++) {
+ int linecomprem = (stream.readUint16BE() + 2) * 4 - 2;
+ int linerem = width;
+ bool stopLine = false;
+ while (linerem > 0 && linecomprem > 0 && !stopLine) {
+ byte lead = stream.readByte();
+ linecomprem--;
+ switch (lead >> 6) {
+ case 0: // end of the line
+ stopLine = true;
+ break;
+ case 1: // copy
+ for (uint i = 0; i <= (lead & 0x3f) && linerem > 0 && linecomprem > 0;
+ i++, linerem--, linecomprem -= 2)
+ *dst++ = stream.readUint16BE();
+ break;
+ case 2: // black
+ for (uint i = 0; i <= (lead & 0x3f) && linerem > 0; i++, linerem--)
+ *dst++ = 0;
+ break;
+ case 3: { // RLE multiply
+ uint16 rleval = stream.readUint16BE();
+ linecomprem -= 2;
+ for (uint i = 0; i <= (lead & 0x3f) && linerem > 0; i++, linerem--)
+ *dst++ = rleval;
+ break;
+ }
+ }
+ }
+ if (linecomprem > 0)
+ stream.skip(linecomprem);
+ if (linerem > 0) {
+ memset(dst, 0, 2 * linerem);
+ dst += linerem;
+ }
+ }
+ }
+
+ _surface = surface;
+
+ return true;
+}
+
+} // End of namespace Image
diff --git a/image/cel_3do.h b/image/cel_3do.h
new file mode 100644
index 0000000000..41c999ae9b
--- /dev/null
+++ b/image/cel_3do.h
@@ -0,0 +1,63 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef IMAGE_CEL_3DO_H
+#define IMAGE_CEL_3DO_H
+
+#include "common/scummsys.h"
+#include "common/str.h"
+#include "image/image_decoder.h"
+
+namespace Common {
+class SeekableReadStream;
+class WriteStream;
+}
+
+namespace Graphics {
+struct Surface;
+}
+
+namespace Image {
+
+class Codec;
+
+class Cel3DODecoder : public ImageDecoder {
+public:
+ Cel3DODecoder();
+ virtual ~Cel3DODecoder();
+
+ // ImageDecoder API
+ void destroy();
+ virtual bool loadStream(Common::SeekableReadStream &stream);
+ virtual const Graphics::Surface *getSurface() const { return _surface; }
+ const byte *getPalette() const { return _palette; }
+ uint16 getPaletteColorCount() const { return _paletteColorCount; }
+
+private:
+ const Graphics::Surface *_surface;
+ byte *_palette;
+ uint16 _paletteColorCount;
+};
+
+} // End of namespace Image
+
+#endif
diff --git a/image/module.mk b/image/module.mk
index 21566dd602..2100f3093c 100644
--- a/image/module.mk
+++ b/image/module.mk
@@ -2,6 +2,7 @@ MODULE := image
MODULE_OBJS := \
bmp.o \
+ cel_3do.o \
iff.o \
jpeg.o \
pcx.o \
Commit: ce6eb341215b5624eac7df9f148b64fd8941288c
https://github.com/scummvm/scummvm/commit/ce6eb341215b5624eac7df9f148b64fd8941288c
Author: Vladimir Serbinenko (phcoder at google.com)
Date: 2020-10-24T00:59:01+02:00
Commit Message:
VIDEO: uplift 3do movie decoder from sherlock engine
The format is generic to 3DO and is also used by plumbers.
I think it's also accelerated on 3DO so probably is used by
a lot of 3DO titles
Changed paths:
A video/3do_decoder.cpp
A video/3do_decoder.h
R engines/sherlock/scalpel/3do/movie_decoder.cpp
R engines/sherlock/scalpel/3do/movie_decoder.h
engines/sherlock/module.mk
engines/sherlock/scalpel/scalpel.cpp
engines/sherlock/scalpel/scalpel_talk.cpp
video/module.mk
diff --git a/engines/sherlock/module.mk b/engines/sherlock/module.mk
index 265053a080..e2b2e65245 100644
--- a/engines/sherlock/module.mk
+++ b/engines/sherlock/module.mk
@@ -2,7 +2,6 @@ MODULE := engines/sherlock
MODULE_OBJS = \
scalpel/scalpel.o \
- scalpel/3do/movie_decoder.o \
scalpel/3do/scalpel_3do_screen.o \
scalpel/drivers/adlib.o \
scalpel/drivers/mt32.o \
diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp
index 351d55a436..3469372d37 100644
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@ -34,7 +34,7 @@
#include "sherlock/sherlock.h"
#include "sherlock/music.h"
#include "sherlock/animation.h"
-#include "sherlock/scalpel/3do/movie_decoder.h"
+#include "video/3do_decoder.h"
namespace Sherlock {
@@ -1272,7 +1272,7 @@ void ScalpelEngine::showScummVMRestoreDialog() {
bool ScalpelEngine::play3doMovie(const Common::String &filename, const Common::Point &pos, bool isPortrait) {
Scalpel3DOScreen &screen = *(Scalpel3DOScreen *)_screen;
- Scalpel3DOMovieDecoder *videoDecoder = new Scalpel3DOMovieDecoder();
+ Video::ThreeDOMovieDecoder *videoDecoder = new Video::ThreeDOMovieDecoder();
Graphics::ManagedSurface tempSurface;
Common::Point framePos(pos.x, pos.y);
diff --git a/engines/sherlock/scalpel/scalpel_talk.cpp b/engines/sherlock/scalpel/scalpel_talk.cpp
index f1460fd01d..55cf820726 100644
--- a/engines/sherlock/scalpel/scalpel_talk.cpp
+++ b/engines/sherlock/scalpel/scalpel_talk.cpp
@@ -30,7 +30,6 @@
#include "sherlock/scalpel/scalpel_user_interface.h"
#include "sherlock/scalpel/scalpel.h"
#include "sherlock/screen.h"
-#include "sherlock/scalpel/3do/movie_decoder.h"
namespace Sherlock {
diff --git a/engines/sherlock/scalpel/3do/movie_decoder.cpp b/video/3do_decoder.cpp
similarity index 84%
rename from engines/sherlock/scalpel/3do/movie_decoder.cpp
rename to video/3do_decoder.cpp
index d14c46e56b..ab6df337fd 100644
--- a/engines/sherlock/scalpel/3do/movie_decoder.cpp
+++ b/video/3do_decoder.cpp
@@ -27,7 +27,7 @@
#include "audio/audiostream.h"
#include "audio/decoders/3do.h"
-#include "sherlock/scalpel/3do/movie_decoder.h"
+#include "video/3do_decoder.h"
#include "image/codecs/cinepak.h"
// for Test-Code
@@ -40,19 +40,19 @@
#include "graphics/pixelformat.h"
#include "graphics/surface.h"
-namespace Sherlock {
+namespace Video {
-Scalpel3DOMovieDecoder::Scalpel3DOMovieDecoder()
+ThreeDOMovieDecoder::ThreeDOMovieDecoder()
: _stream(0), _videoTrack(0), _audioTrack(0) {
_streamVideoOffset = 0;
_streamAudioOffset = 0;
}
-Scalpel3DOMovieDecoder::~Scalpel3DOMovieDecoder() {
+ThreeDOMovieDecoder::~ThreeDOMovieDecoder() {
close();
}
-bool Scalpel3DOMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
+bool ThreeDOMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
uint32 videoSubType = 0;
uint32 videoCodecTag = 0;
uint32 videoHeight = 0;
@@ -92,7 +92,7 @@ bool Scalpel3DOMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
case MKTAG('F', 'H', 'D', 'R'):
// FILM header found
if (_videoTrack) {
- warning("Sherlock 3DO movie: Multiple FILM headers found");
+ warning("3DO movie: Multiple FILM headers found");
close();
return false;
}
@@ -111,7 +111,7 @@ bool Scalpel3DOMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
break;
default:
- warning("Sherlock 3DO movie: Unknown subtype inside FILM packet");
+ warning("3DO movie: Unknown subtype inside FILM packet");
close();
return false;
}
@@ -128,7 +128,7 @@ bool Scalpel3DOMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
// Bail if we already have a track
if (_audioTrack) {
- warning("Sherlock 3DO movie: Multiple SNDS headers found");
+ warning("3DO movie: Multiple SNDS headers found");
close();
return false;
}
@@ -154,7 +154,7 @@ bool Scalpel3DOMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
// Audio data
break;
default:
- warning("Sherlock 3DO movie: Unknown subtype inside FILM packet");
+ warning("3DO movie: Unknown subtype inside FILM packet");
close();
return false;
}
@@ -173,7 +173,7 @@ bool Scalpel3DOMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
break;
default:
- warning("Unknown chunk-tag '%s' inside Sherlock 3DO movie", tag2str(chunkTag));
+ warning("Unknown chunk-tag '%s' inside 3DO movie", tag2str(chunkTag));
close();
return false;
}
@@ -197,7 +197,7 @@ bool Scalpel3DOMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
return true;
}
-void Scalpel3DOMovieDecoder::close() {
+void ThreeDOMovieDecoder::close() {
Video::VideoDecoder::close();
delete _stream; _stream = 0;
@@ -206,7 +206,7 @@ void Scalpel3DOMovieDecoder::close() {
// We try to at least decode 1 frame
// and also try to get at least 0.5 seconds of audio queued up
-void Scalpel3DOMovieDecoder::readNextPacket() {
+void ThreeDOMovieDecoder::readNextPacket() {
uint32 currentMovieTime = getTime();
uint32 wantedAudioQueued = currentMovieTime + 500; // always try to be 0.500 seconds in front of movie time
@@ -300,7 +300,7 @@ void Scalpel3DOMovieDecoder::readNextPacket() {
break;
default:
- error("Sherlock 3DO movie: Unknown subtype inside FILM packet");
+ error("3DO movie: Unknown subtype inside FILM packet");
break;
}
break;
@@ -332,7 +332,7 @@ void Scalpel3DOMovieDecoder::readNextPacket() {
break;
default:
- error("Sherlock 3DO movie: Unknown subtype inside SNDS packet");
+ error("3DO movie: Unknown subtype inside SNDS packet");
break;
}
break;
@@ -349,7 +349,7 @@ void Scalpel3DOMovieDecoder::readNextPacket() {
break;
default:
- error("Unknown chunk-tag '%s' inside Sherlock 3DO movie", tag2str(chunkTag));
+ error("Unknown chunk-tag '%s' inside 3DO movie", tag2str(chunkTag));
}
// Always seek to end of chunk
@@ -362,7 +362,7 @@ void Scalpel3DOMovieDecoder::readNextPacket() {
}
}
-Scalpel3DOMovieDecoder::StreamVideoTrack::StreamVideoTrack(uint32 width, uint32 height, uint32 codecTag, uint32 frameCount) {
+ThreeDOMovieDecoder::StreamVideoTrack::StreamVideoTrack(uint32 width, uint32 height, uint32 codecTag, uint32 frameCount) {
_width = width;
_height = height;
_frameCount = frameCount;
@@ -373,27 +373,27 @@ Scalpel3DOMovieDecoder::StreamVideoTrack::StreamVideoTrack(uint32 width, uint32
if (codecTag == MKTAG('c', 'v', 'i', 'd'))
_codec = new Image::CinepakDecoder();
else
- error("Unsupported Sherlock 3DO movie video codec tag '%s'", tag2str(codecTag));
+ error("Unsupported 3DO movie video codec tag '%s'", tag2str(codecTag));
}
-Scalpel3DOMovieDecoder::StreamVideoTrack::~StreamVideoTrack() {
+ThreeDOMovieDecoder::StreamVideoTrack::~StreamVideoTrack() {
delete _codec;
}
-bool Scalpel3DOMovieDecoder::StreamVideoTrack::endOfTrack() const {
+bool ThreeDOMovieDecoder::StreamVideoTrack::endOfTrack() const {
return getCurFrame() >= getFrameCount() - 1;
}
-Graphics::PixelFormat Scalpel3DOMovieDecoder::StreamVideoTrack::getPixelFormat() const {
+Graphics::PixelFormat ThreeDOMovieDecoder::StreamVideoTrack::getPixelFormat() const {
return _codec->getPixelFormat();
}
-void Scalpel3DOMovieDecoder::StreamVideoTrack::decodeFrame(Common::SeekableReadStream *stream, uint32 videoTimeStamp) {
+void ThreeDOMovieDecoder::StreamVideoTrack::decodeFrame(Common::SeekableReadStream *stream, uint32 videoTimeStamp) {
_surface = _codec->decodeFrame(*stream);
_curFrame++;
}
-Scalpel3DOMovieDecoder::StreamAudioTrack::StreamAudioTrack(uint32 codecTag, uint32 sampleRate, uint32 channels, Audio::Mixer::SoundType soundType) :
+ThreeDOMovieDecoder::StreamAudioTrack::StreamAudioTrack(uint32 codecTag, uint32 sampleRate, uint32 channels, Audio::Mixer::SoundType soundType) :
AudioTrack(soundType) {
switch (codecTag) {
case MKTAG('A','D','P','4'):
@@ -402,7 +402,7 @@ Scalpel3DOMovieDecoder::StreamAudioTrack::StreamAudioTrack(uint32 codecTag, uint
break;
default:
- error("Unsupported Sherlock 3DO movie audio codec tag '%s'", tag2str(codecTag));
+ error("Unsupported 3DO movie audio codec tag '%s'", tag2str(codecTag));
}
_totalAudioQueued = 0; // currently 0 milliseconds queued
@@ -417,7 +417,7 @@ Scalpel3DOMovieDecoder::StreamAudioTrack::StreamAudioTrack(uint32 codecTag, uint
_stereo = true;
break;
default:
- error("Unsupported Sherlock 3DO movie audio channels %d", channels);
+ error("Unsupported 3DO movie audio channels %d", channels);
}
_audioStream = Audio::makeQueuingAudioStream(sampleRate, _stereo);
@@ -427,13 +427,13 @@ Scalpel3DOMovieDecoder::StreamAudioTrack::StreamAudioTrack(uint32 codecTag, uint
memset(&_SDX2_PersistentSpace, 0, sizeof(_SDX2_PersistentSpace));
}
-Scalpel3DOMovieDecoder::StreamAudioTrack::~StreamAudioTrack() {
+ThreeDOMovieDecoder::StreamAudioTrack::~StreamAudioTrack() {
delete _audioStream;
// free(_ADP4_PersistentSpace);
// free(_SDX2_PersistentSpace);
}
-void Scalpel3DOMovieDecoder::StreamAudioTrack::queueAudio(Common::SeekableReadStream *stream, uint32 size) {
+void ThreeDOMovieDecoder::StreamAudioTrack::queueAudio(Common::SeekableReadStream *stream, uint32 size) {
Common::SeekableReadStream *compressedAudioStream = 0;
Audio::RewindableAudioStream *audioStream = 0;
uint32 audioLengthMSecs = 0;
@@ -460,8 +460,8 @@ void Scalpel3DOMovieDecoder::StreamAudioTrack::queueAudio(Common::SeekableReadSt
}
}
-Audio::AudioStream *Scalpel3DOMovieDecoder::StreamAudioTrack::getAudioStream() const {
+Audio::AudioStream *ThreeDOMovieDecoder::StreamAudioTrack::getAudioStream() const {
return _audioStream;
}
-} // End of namespace Sherlock
+} // End of namespace Video
diff --git a/engines/sherlock/scalpel/3do/movie_decoder.h b/video/3do_decoder.h
similarity index 93%
rename from engines/sherlock/scalpel/3do/movie_decoder.h
rename to video/3do_decoder.h
index b54c424315..e03bd8a1ed 100644
--- a/engines/sherlock/scalpel/3do/movie_decoder.h
+++ b/video/3do_decoder.h
@@ -39,12 +39,19 @@ namespace Image {
class Codec;
}
-namespace Sherlock {
+namespace Video {
-class Scalpel3DOMovieDecoder : public Video::VideoDecoder {
+/**
+ * Decoder for 3DO videos.
+ *
+ * Video decoder used in engines:
+ * - sherlock
+ * - plumbers
+ */
+class ThreeDOMovieDecoder : public Video::VideoDecoder {
public:
- Scalpel3DOMovieDecoder();
- ~Scalpel3DOMovieDecoder() override;
+ ThreeDOMovieDecoder();
+ ~ThreeDOMovieDecoder() override;
bool loadStream(Common::SeekableReadStream *stream) override;
void close() override;
diff --git a/video/module.mk b/video/module.mk
index c1fb79256e..875b141672 100644
--- a/video/module.mk
+++ b/video/module.mk
@@ -1,6 +1,7 @@
MODULE := video
MODULE_OBJS := \
+ 3do_decoder.o \
avi_decoder.o \
coktel_decoder.o \
dxa_decoder.o \
Commit: 3c97ebd4f955882bd554870fbfaf7c9ae2a97090
https://github.com/scummvm/scummvm/commit/3c97ebd4f955882bd554870fbfaf7c9ae2a97090
Author: Vladimir Serbinenko (phcoder at google.com)
Date: 2020-10-24T00:59:01+02:00
Commit Message:
VIDEO: support multi-track audios in 3DO videos
It's used in plumbers with first track being speech and second track
being music
Changed paths:
video/3do_decoder.cpp
video/3do_decoder.h
diff --git a/video/3do_decoder.cpp b/video/3do_decoder.cpp
index ab6df337fd..b1297c576e 100644
--- a/video/3do_decoder.cpp
+++ b/video/3do_decoder.cpp
@@ -43,7 +43,7 @@
namespace Video {
ThreeDOMovieDecoder::ThreeDOMovieDecoder()
- : _stream(0), _videoTrack(0), _audioTrack(0) {
+ : _stream(0), _videoTrack(0) {
_streamVideoOffset = 0;
_streamAudioOffset = 0;
}
@@ -52,6 +52,10 @@ ThreeDOMovieDecoder::~ThreeDOMovieDecoder() {
close();
}
+VideoDecoder::AudioTrack* ThreeDOMovieDecoder::getAudioTrack(int index) {
+ return _audioTracks[index];
+}
+
bool ThreeDOMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
uint32 videoSubType = 0;
uint32 videoCodecTag = 0;
@@ -62,6 +66,7 @@ bool ThreeDOMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
uint32 audioCodecTag = 0;
uint32 audioChannels = 0;
uint32 audioSampleRate = 0;
+ uint32 audioTrackId = 0;
close();
@@ -119,20 +124,14 @@ bool ThreeDOMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
}
case MKTAG('S','N','D','S'): {
- _stream->skip(8);
+ _stream->readUint32BE(); // Unknown
+ audioTrackId = _stream->readUint32BE();
audioSubType = _stream->readUint32BE();
switch (audioSubType) {
- case MKTAG('S', 'H', 'D', 'R'):
+ case MKTAG('S', 'H', 'D', 'R'): {
// Audio header
- // Bail if we already have a track
- if (_audioTrack) {
- warning("3DO movie: Multiple SNDS headers found");
- close();
- return false;
- }
-
// OK, this is the start of a audio stream
_stream->readUint32BE(); // Version, always 0x00000000
_stream->readUint32BE(); // Unknown 0x00000008 ?!
@@ -146,9 +145,12 @@ bool ThreeDOMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
_stream->readUint32BE(); // Unknown 0x00000004 compression ratio?
_stream->readUint32BE(); // Unknown 0x00000A2C
- _audioTrack = new StreamAudioTrack(audioCodecTag, audioSampleRate, audioChannels, getSoundType());
- addTrack(_audioTrack);
+ StreamAudioTrack *track = new StreamAudioTrack(audioCodecTag, audioSampleRate, audioChannels,
+ getSoundType(), audioTrackId);
+ addTrack(track);
+ _audioTracks.push_back(track);
break;
+ }
case MKTAG('S', 'S', 'M', 'P'):
// Audio data
@@ -178,7 +180,7 @@ bool ThreeDOMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
return false;
}
- if ((_videoTrack) && (_audioTrack))
+ if ((_videoTrack) && (!_audioTracks.empty()))
break;
// Seek to next chunk
@@ -186,7 +188,7 @@ bool ThreeDOMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
}
// Bail if we didn't find video + audio
- if ((!_videoTrack) || (!_audioTrack)) {
+ if ((!_videoTrack) || (_audioTracks.empty())) {
close();
return false;
}
@@ -221,6 +223,7 @@ void ThreeDOMovieDecoder::readNextPacket() {
uint32 videoFrameSize = 0;
uint32 audioSubType = 0;
uint32 audioBytes = 0;
+ uint32 audioTrackId = 0;
bool videoGotFrame = false;
bool videoDone = false;
bool audioDone = false;
@@ -232,7 +235,7 @@ void ThreeDOMovieDecoder::readNextPacket() {
_stream->seek(_streamAudioOffset);
}
- if (wantedAudioQueued <= _audioTrack->getTotalAudioQueued()) {
+ if (wantedAudioQueued <= _audioTracks[0]->getTotalAudioQueued()) {
// already got enough audio queued up
audioDone = true;
}
@@ -306,7 +309,8 @@ void ThreeDOMovieDecoder::readNextPacket() {
break;
case MKTAG('S','N','D','S'):
- _stream->skip(8);
+ _stream->readUint32BE();
+ audioTrackId = _stream->readUint32BE();
audioSubType = _stream->readUint32BE();
switch (audioSubType) {
@@ -319,11 +323,16 @@ void ThreeDOMovieDecoder::readNextPacket() {
if (_streamAudioOffset <= chunkOffset) {
// We are at an offset that is still relevant to audio decoding
if (!audioDone) {
+ uint queued = 0;
audioBytes = _stream->readUint32BE();
- _audioTrack->queueAudio(_stream, audioBytes);
+ for (uint i = 0; i < _audioTracks.size(); i++)
+ if (_audioTracks[i]->matchesId(audioTrackId)) {
+ _audioTracks[i]->queueAudio(_stream, audioBytes);
+ queued = _audioTracks[i]->getTotalAudioQueued();
+ }
_streamAudioOffset = nextChunkOffset;
- if (wantedAudioQueued <= _audioTrack->getTotalAudioQueued()) {
+ if (wantedAudioQueued <= queued) {
// Got enough audio
audioDone = true;
}
@@ -393,7 +402,7 @@ void ThreeDOMovieDecoder::StreamVideoTrack::decodeFrame(Common::SeekableReadStre
_curFrame++;
}
-ThreeDOMovieDecoder::StreamAudioTrack::StreamAudioTrack(uint32 codecTag, uint32 sampleRate, uint32 channels, Audio::Mixer::SoundType soundType) :
+ThreeDOMovieDecoder::StreamAudioTrack::StreamAudioTrack(uint32 codecTag, uint32 sampleRate, uint32 channels, Audio::Mixer::SoundType soundType, uint32 trackId) :
AudioTrack(soundType) {
switch (codecTag) {
case MKTAG('A','D','P','4'):
@@ -409,6 +418,7 @@ ThreeDOMovieDecoder::StreamAudioTrack::StreamAudioTrack(uint32 codecTag, uint32
_codecTag = codecTag;
_sampleRate = sampleRate;
+ _trackId = trackId;
switch (channels) {
case 1:
_stereo = false;
@@ -433,6 +443,10 @@ ThreeDOMovieDecoder::StreamAudioTrack::~StreamAudioTrack() {
// free(_SDX2_PersistentSpace);
}
+bool ThreeDOMovieDecoder::StreamAudioTrack::matchesId(uint tid) {
+ return _trackId == tid;
+}
+
void ThreeDOMovieDecoder::StreamAudioTrack::queueAudio(Common::SeekableReadStream *stream, uint32 size) {
Common::SeekableReadStream *compressedAudioStream = 0;
Audio::RewindableAudioStream *audioStream = 0;
diff --git a/video/3do_decoder.h b/video/3do_decoder.h
index e03bd8a1ed..908bcdcc36 100644
--- a/video/3do_decoder.h
+++ b/video/3do_decoder.h
@@ -58,6 +58,8 @@ public:
protected:
void readNextPacket() override;
+ bool supportsAudioTrackSwitching() const override { return true; }
+ AudioTrack *getAudioTrack(int index) override;
private:
int32 _streamVideoOffset; /* current stream offset for video decoding */
@@ -95,11 +97,13 @@ private:
class StreamAudioTrack : public AudioTrack {
public:
- StreamAudioTrack(uint32 codecTag, uint32 sampleRate, uint32 channels, Audio::Mixer::SoundType soundType);
+ StreamAudioTrack(uint32 codecTag, uint32 sampleRate, uint32 channels, Audio::Mixer::SoundType soundType, uint32 trackId);
~StreamAudioTrack() override;
void queueAudio(Common::SeekableReadStream *stream, uint32 size);
+ bool matchesId(uint trackId);
+
protected:
Audio::AudioStream *getAudioStream() const override;
@@ -116,6 +120,7 @@ private:
uint32 _codecTag;
uint16 _sampleRate;
bool _stereo;
+ uint32 _trackId;
Audio::audio_3DO_ADP4_PersistentSpace _ADP4_PersistentSpace;
Audio::audio_3DO_SDX2_PersistentSpace _SDX2_PersistentSpace;
@@ -123,7 +128,7 @@ private:
Common::SeekableReadStream *_stream;
StreamVideoTrack *_videoTrack;
- StreamAudioTrack *_audioTrack;
+ Common::Array<StreamAudioTrack *> _audioTracks;
};
} // End of namespace Sherlock
Commit: 125fd9d80cfa46e2ae834281304654856ce42aec
https://github.com/scummvm/scummvm/commit/125fd9d80cfa46e2ae834281304654856ce42aec
Author: Vladimir Serbinenko (phcoder at google.com)
Date: 2020-10-24T00:59:01+02:00
Commit Message:
PLUMBERS: support for 3DO version
It was fun to reverse engineer but the game is garbage, so I didn't test
it a lot, please report bugs.
Currently missing parts:
* effect when changing between scenes
* 3DO boot logo
* return to previous scene
* hide cursor
Changed paths:
engines/plumbers/detection.cpp
engines/plumbers/plumbers.cpp
engines/plumbers/plumbers.h
diff --git a/engines/plumbers/detection.cpp b/engines/plumbers/detection.cpp
index 101a3cba41..635b343279 100644
--- a/engines/plumbers/detection.cpp
+++ b/engines/plumbers/detection.cpp
@@ -44,7 +44,6 @@ static const ADGameDescription gameDescriptions[] = {
GUIO1(GUIO_NOMIDI)
},
- /*
// Plumbers 3DO version
{
"plumbers",
@@ -55,7 +54,6 @@ static const ADGameDescription gameDescriptions[] = {
ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
- */
AD_TABLE_END_MARKER
};
diff --git a/engines/plumbers/plumbers.cpp b/engines/plumbers/plumbers.cpp
index 149d9b29b9..1b1c7ce974 100644
--- a/engines/plumbers/plumbers.cpp
+++ b/engines/plumbers/plumbers.cpp
@@ -23,6 +23,7 @@
#include "plumbers/plumbers.h"
#include "plumbers/console.h"
+#include "audio/decoders/aiff.h"
#include "audio/decoders/wave.h"
#include "audio/audiostream.h"
@@ -43,9 +44,32 @@
#include "graphics/surface.h"
#include "image/bmp.h"
+#include "image/cel_3do.h"
+
+#include "video/3do_decoder.h"
namespace Plumbers {
+static const Common::KeyCode cheatKbd[] = {
+ Common::KEYCODE_UP,
+ Common::KEYCODE_DOWN,
+ Common::KEYCODE_RIGHT,
+ Common::KEYCODE_LEFT,
+ Common::KEYCODE_DOWN,
+ Common::KEYCODE_RIGHT,
+ Common::KEYCODE_RETURN
+};
+
+static const Common::JoystickButton cheatJoy[] = {
+ Common::JOYSTICK_BUTTON_DPAD_UP,
+ Common::JOYSTICK_BUTTON_DPAD_DOWN,
+ Common::JOYSTICK_BUTTON_DPAD_RIGHT,
+ Common::JOYSTICK_BUTTON_DPAD_LEFT,
+ Common::JOYSTICK_BUTTON_DPAD_DOWN,
+ Common::JOYSTICK_BUTTON_DPAD_RIGHT,
+ Common::JOYSTICK_BUTTON_X
+};
+
PlumbersGame::PlumbersGame(OSystem *syst, const ADGameDescription *gameDesc) :
Engine(syst), _gameDescription(gameDesc), _console(0), _image(0) {
_timerInstalled = false;
@@ -59,6 +83,8 @@ PlumbersGame::PlumbersGame(OSystem *syst, const ADGameDescription *gameDesc) :
_curChoice = 0;
_totScene = -1;
_totScore = 0;
+ _cheatEnabled = false;
+ _cheatFSM = 0;
DebugMan.addDebugChannel(kDebugGeneral, "general", "General debug level");
}
@@ -93,9 +119,83 @@ static const byte cursorPalette[] = {
0xff, 0xff, 0xff // White
};
+// TODO(3do):
+// * effect when changing between scenes
+// * 3do boot logo
+// * return to previous scene
+// * hide cursor
+
+void PlumbersGame::updateHiLite() {
+ _actions.push(Redraw);
+ if (_hiLite < 0)
+ return;
+ if (_scenes[_curSceneIdx]._style == Scene::STYLE_DECISION_MIKE) {
+ playSound(Common::String::format("%s/%s%dS.Aiff",
+ _scenes[_curSceneIdx]._sceneName.c_str(),
+ _scenes[_curSceneIdx]._decisionBitmap.c_str(), _hiLite + 1));
+ } else if (_scenes[_curSceneIdx]._style == Scene::STYLE_DECISION_TUN) {
+ playSound(Common::String::format("%s%c.aiff", _scenes[_curSceneIdx]._sceneName.c_str(), _hiLite + 'a'));
+ }
+}
+
+void PlumbersGame::joyUp() {
+ int decNum = _scenes[_curSceneIdx]._decisionChoices;
+ if (!_leftButtonDownFl || !_hiLiteEnabled)
+ return;
+ _kbdHiLite = _kbdHiLite < 0 ? 0 : (_kbdHiLite + decNum - 1) % decNum;
+ _hiLite = _kbdHiLite;
+ updateHiLite();
+}
+
+void PlumbersGame::joyDown() {
+ if (!_leftButtonDownFl || !_hiLiteEnabled)
+ return;
+ int decNum = _scenes[_curSceneIdx]._decisionChoices;
+ _kbdHiLite = _kbdHiLite < 0 ? 0 : (_kbdHiLite + 1) % decNum;
+ _hiLite = _kbdHiLite;
+ updateHiLite();
+}
+
+void PlumbersGame::joyA() {
+ if (_kbdHiLite < 0 || !_leftButtonDownFl || !_hiLiteEnabled)
+ return;
+ debugC(5, kDebugGeneral, "Accepting enter press with choice = %d", _kbdHiLite);
+ _curChoice = _kbdHiLite;
+ _totScore += _scenes[_curSceneIdx]._choices[_kbdHiLite]._points;
+ _actions.push(ChangeScene);
+ _leftButtonDownFl = false;
+}
+
+void PlumbersGame::skipVideo() {
+ if (_scenes[_curSceneIdx]._sceneName == "janp1weaver"
+ || _scenes[_curSceneIdx]._sceneName == "janp2weaver") {
+ // Skip janp2weaver and janp3weaver
+ _curSceneIdx = getSceneNumb("titleweaver");
+ _actions.push(ShowScene);
+ } else {
+ _actions.push(ChangeScene);
+ }
+ _videoDecoder->close();
+ delete _videoDecoder;
+ _videoDecoder = nullptr;
+}
+
+
Common::Error PlumbersGame::run() {
- initGraphics(640, 480);
- _image = new Image::BitmapDecoder();
+ if (getPlatform() == Common::kPlatform3DO) {
+ _image = new Image::Cel3DODecoder();
+ _ctrlHelpImage = new Image::Cel3DODecoder();
+ _screenW = 320;
+ _screenH = 240;
+ Graphics::PixelFormat pf(2, 5, 5, 5, 1, 10, 5, 0, 15);
+ initGraphics(_screenW, _screenH, &pf);
+ } else {
+ _image = new Image::BitmapDecoder();
+ _screenW = 640;
+ _screenH = 480;
+ initGraphics(_screenW, _screenH);
+ }
+
_console = new Console();
setDebugger(_console);
@@ -103,14 +203,26 @@ Common::Error PlumbersGame::run() {
CursorMan.replaceCursorPalette(cursorPalette, 0, 3);
CursorMan.showMouse(true);
- readTables("game.bin");
+ if (getPlatform() == Common::kPlatform3DO)
+ readTables3DO("launchme");
+ else
+ readTablesPC("game.bin");
_showScoreFl = false;
_leftButtonDownFl = false;
_endGameFl = false;
+ // PC uses a palette, so we don't do highlighting.
+ // Original does the same
+ _hiLiteEnabled = getPlatform() == Common::kPlatform3DO;
_totScore = 0;
_curSceneIdx = _prvSceneIdx = 0;
_curChoice = 0;
+ _kbdHiLite = -1;
+ _mouseHiLite = -1;
+ _hiLite = -1;
+ _mouseHiLite = -1;
+ _kbdHiLite = -1;
+ _leftShoulderPressed = false;
_actions.clear();
_actions.push(ShowScene);
@@ -127,13 +239,10 @@ Common::Error PlumbersGame::run() {
case Common::EVENT_LBUTTONDOWN:
if (_leftButtonDownFl) {
- Common::Point mousePos = g_system->getEventManager()->getMousePos();
- for (_curChoice = 0; _curChoice < _scenes[_curSceneIdx]._decisionChoices; _curChoice++) {
- if (_scenes[_curSceneIdx]._choices[_curChoice]._region.contains(mousePos))
- break;
- }
- if (_curChoice < kMaxChoice) {
- debugC(5, kDebugGeneral, "Accepting mouse click at %d : %d , choice = %d", mousePos.x, mousePos.y, _curChoice);
+ _curChoice = getMouseHiLite();
+
+ if (_curChoice >= 0 && _curChoice < _scenes[_curSceneIdx]._decisionChoices) {
+ debugC(5, kDebugGeneral, "Accepting mouse click with choice = %d", _curChoice);
_totScore += _scenes[_curSceneIdx]._choices[_curChoice]._points;
_actions.push(ChangeScene);
_leftButtonDownFl = false;
@@ -143,11 +252,94 @@ Common::Error PlumbersGame::run() {
onTimer(this);
}
break;
+ case Common::EVENT_JOYBUTTON_DOWN:
+ if (_videoDecoder) {
+ if (_cheatFSM < ARRAYSIZE(cheatJoy) && event.joystick.button == cheatJoy[_cheatFSM]) {
+ _cheatFSM++;
+ if (_cheatFSM == ARRAYSIZE(cheatJoy)) {
+ debugC(1, kDebugGeneral, "Cheat enabled");
+ _cheatEnabled = true;
+ }
+ } else if (event.joystick.button == cheatJoy[0])
+ _cheatFSM = 1;
+ else
+ _cheatFSM = 0;
+ }
+ if (_videoDecoder && (event.joystick.button == Common::JOYSTICK_BUTTON_A ||
+ event.joystick.button == Common::JOYSTICK_BUTTON_B ||
+ event.joystick.button == Common::JOYSTICK_BUTTON_X)) {
+ skipVideo();
+ } else if (event.joystick.button == Common::JOYSTICK_BUTTON_DPAD_UP ||
+ event.joystick.button == Common::JOYSTICK_BUTTON_DPAD_LEFT) {
+ joyUp();
+ } else if (event.joystick.button == Common::JOYSTICK_BUTTON_DPAD_DOWN ||
+ event.joystick.button == Common::JOYSTICK_BUTTON_DPAD_RIGHT) {
+ joyDown();
+ } else if (event.joystick.button == Common::JOYSTICK_BUTTON_A) {
+ joyA();
+ } else if (event.joystick.button == Common::JOYSTICK_BUTTON_LEFT_SHOULDER) {
+ _leftShoulderPressed = true;
+ if (_leftButtonDownFl && _ctrlHelpImage)
+ _actions.push(Redraw);
+ }
+ break;
+ case Common::EVENT_JOYBUTTON_UP:
+ if (event.joystick.button == Common::JOYSTICK_BUTTON_LEFT_SHOULDER) {
+ _leftShoulderPressed = false;
+ if (_leftButtonDownFl && _ctrlHelpImage)
+ _actions.push(Redraw);
+ }
+ break;
+ case Common::EVENT_KEYDOWN:
+ if (_videoDecoder) {
+ if (_cheatFSM < ARRAYSIZE(cheatKbd) && event.kbd.keycode == cheatKbd[_cheatFSM]) {
+ _cheatFSM++;
+ if (_cheatFSM == ARRAYSIZE(cheatKbd)) {
+ debugC(1, kDebugGeneral, "Cheat enabled");
+ _cheatEnabled = true;
+ }
+ } else if (event.kbd.keycode == cheatKbd[0])
+ _cheatFSM = 1;
+ else
+ _cheatFSM = 0;
+ }
+ if (event.kbd.keycode == Common::KEYCODE_SPACE && _videoDecoder) {
+ skipVideo();
+ } else if ((event.kbd.keycode == Common::KEYCODE_UP ||
+ event.kbd.keycode == Common::KEYCODE_LEFT)) {
+ joyUp();
+ } else if ((event.kbd.keycode == Common::KEYCODE_DOWN ||
+ event.kbd.keycode == Common::KEYCODE_RIGHT)) {
+ joyDown();
+ } else if (event.kbd.keycode == Common::KEYCODE_RETURN) {
+ joyA();
+ } else if (event.kbd.keycode == Common::KEYCODE_q) {
+ _leftShoulderPressed = true;
+ if (_leftButtonDownFl && _ctrlHelpImage)
+ _actions.push(Redraw);
+ }
+ break;
+ case Common::EVENT_KEYUP:
+ if (event.kbd.keycode == Common::KEYCODE_q) {
+ _leftShoulderPressed = false;
+ if (_leftButtonDownFl && _ctrlHelpImage)
+ _actions.push(Redraw);
+ }
+ break;
default:
break;
}
}
+ if (_leftButtonDownFl) {
+ int nh = getMouseHiLite();
+ if (nh != _mouseHiLite) {
+ _mouseHiLite = nh;
+ _hiLite = _mouseHiLite;
+ updateHiLite();
+ }
+ }
+
while (!_actions.empty()) {
switch (_actions.pop()) {
case Redraw:
@@ -163,15 +355,26 @@ Common::Error PlumbersGame::run() {
changeScene();
break;
case PlaySound:
- playSound();
+ playSound(_scenes[_curSceneIdx]._sceneName + "/" + _scenes[_curSceneIdx]._waveFilename);
break;
default:
break;
}
}
+ if (_videoDecoder) {
+ if (_videoDecoder->endOfVideo()) {
+ _actions.push(ChangeScene);
+ _videoDecoder->close();
+ delete _videoDecoder;
+ _videoDecoder = nullptr;
+ } else if (_videoDecoder->needsUpdate()) {
+ drawScreen();
+ }
+ }
+
g_system->updateScreen();
- g_system->delayMillis(10);
+ g_system->delayMillis(_videoDecoder ? (1000 / 60) : 10);
}
g_system->getTimerManager()->removeTimerProc(onTimer);
@@ -180,22 +383,75 @@ Common::Error PlumbersGame::run() {
return Common::kNoError;
}
-void PlumbersGame::loadImage(const Common::String &dirname, const Common::String &filename) {
- Common::String name = dirname + "/" + filename;
+void PlumbersGame::loadImage(const Common::String &name) {
debugC(1, kDebugGeneral, "%s : %s", __FUNCTION__, name.c_str());
Common::File file;
if (!file.open(name))
error("unable to load image %s", name.c_str());
_image->loadStream(file);
+ delete _compositeSurface;
+ _compositeSurface = nullptr;
+}
+
+// TODO: discover correct offsets
+Common::Point getMikeStart(uint num, uint total) {
+ if (total == 2)
+ return Common::Point(140 * num + 10, 120 * num + 10);
+ return Common::Point(60 * num + 20, 70 * num + 20);
+}
+
+// TODO: discover correct offsets
+Common::Point getMikeSize(uint total) {
+ if (total == 2)
+ return Common::Point(80, 100);
+ return Common::Point(80, 60);
+}
+
+void PlumbersGame::loadMikeDecision(const Common::String &dirname, const Common::String &baseFilename, uint num) {
+ Common::String baseName = dirname + "/" + baseFilename;
+ debugC(1, kDebugGeneral, "%s : %s", __FUNCTION__, baseName.c_str());
+ Graphics::Surface *surf = new Graphics::Surface();
+ surf->create(_screenW, _screenH, Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15));
+
+ delete _compositeSurface;
+ _compositeSurface = nullptr;
+
+ for (uint i = 0; i < num; i++) {
+ Common::Point p = getMikeStart(i, num);
+ Common::Point sz = getMikeSize(num);
+ Common::File fileP;
+ Common::String nameP = Common::String::format("%s%dP.CEL", baseName.c_str(), i + 1);
+ if (!fileP.open(nameP))
+ error("unable to load image %s", nameP.c_str());
+
+ _image->loadStream(fileP);
+ surf->copyRectToSurface(*_image->getSurface(), p.x, p.y,
+ Common::Rect(0, 0, sz.x, sz.y));
+
+ Common::File fileW;
+ Common::String nameW = Common::String::format("%s%dW.CEL", baseName.c_str(), i + 1);
+ if (!fileW.open(nameW))
+ error("unable to load image %s", nameW.c_str());
+
+ _image->loadStream(fileW);
+ surf->copyRectToSurface(*_image->getSurface(), p.x + sz.x, p.y,
+ Common::Rect(0, 0, sz.x, sz.y));
+ }
+
+ _compositeSurface = surf;
+
+ Common::File fileCtrl;
+ if (fileCtrl.open(dirname + "/CONTROLHELP.CEL"))
+ _ctrlHelpImage->loadStream(fileCtrl);
}
void PlumbersGame::drawScreen() {
- debugC(1, kDebugGeneral, "%s : %s", __FUNCTION__, _image ? "YES" : "NO");
- if (_image) {
+ debugC(_videoDecoder ? 10 : 1, kDebugGeneral, "%s : %s", __FUNCTION__, _image ? "YES" : "NO");
+ if (_videoDecoder ? _videoDecoder->needsUpdate() : _image || _compositeSurface) {
if (_setDurationFl) {
g_system->getTimerManager()->removeTimerProc(onTimer);
- g_system->getTimerManager()->installTimerProc(onTimer, _bitmaps[_curBitmapIdx]._duration * 100 * 1000, this, "timer");
+ g_system->getTimerManager()->installTimerProc(onTimer, _bitmaps[_curBitmapIdx]._duration * 1000, this, "timer");
_timerInstalled = true;
_actions.push(UpdateScene);
}
@@ -203,40 +459,85 @@ void PlumbersGame::drawScreen() {
Graphics::Surface *screen = g_system->lockScreen();
screen->fillRect(Common::Rect(0, 0, g_system->getWidth(), g_system->getHeight()), 0);
- const Graphics::Surface *surface = _image->getSurface();
+ const Graphics::Surface *surface;
+ bool ctrlHelp = false;
+ if (_leftShoulderPressed && _leftButtonDownFl && _ctrlHelpImage) {
+ surface = _ctrlHelpImage->getSurface();
+ ctrlHelp = true;
+ } else if (_videoDecoder)
+ surface = _videoDecoder->decodeNextFrame();
+ else if (_compositeSurface)
+ surface = _compositeSurface;
+ else
+ surface = _image->getSurface();
+
+ Graphics::Surface modSurf;
+ bool modded = false;
+
+ if (_hiLiteEnabled && _hiLite >= 0 && _leftButtonDownFl && !ctrlHelp) {
+ Graphics::PixelFormat pf(2, 5, 5, 5, 1, 10, 5, 0, 15);
+ modSurf.create(surface->w, surface->h, pf);
+ modSurf.copyRectToSurface(*surface, 0, 0, Common::Rect(0, 0, surface->w, surface->h));
+ const Common::Rect rec = _scenes[_curSceneIdx]._choices[_hiLite]._region;
+
+ for (int y = rec.top; y <= rec.bottom; y++) {
+ uint16 *p = (uint16 *) modSurf.getPixels() + modSurf.w * y + rec.left;
+ for (int x = rec.left; x < rec.right; x++, p++) {
+ uint r, g, b;
+ r = (*p >> 10) & 0x1f;
+ g = (*p >> 5) & 0x1f;
+ b = (*p >> 0) & 0x1f;
+ // TODO: figure out the correct multipliers
+ r = MIN<int>(3 * r / 2, 0x1f);
+ g = MIN<int>(3 * g / 2, 0x1f);
+ b = MIN<int>(3 * b / 2, 0x1f);
+ *p = (*p & 0x8000) | (r << 10) | (g << 5) | (b);
+ }
+ }
+ modded = true;
+ }
- int w = CLIP<int>(surface->w, 0, 640);
- int h = CLIP<int>(surface->h, 0, 480);
+ int w = CLIP<int>(surface->w, 0, _screenW);
+ int h = CLIP<int>(surface->h, 0, _screenH);
- int x = (640 - w) / 2;
- int y = (480 - h) / 2;
+ int x = (_screenW - w) / 2;
+ int y = (_screenH - h) / 2;
- screen->copyRectToSurface(*surface, x, y, Common::Rect(0, 0, w, h));
+ screen->copyRectToSurface(modded ? modSurf : *surface, x, y, Common::Rect(0, 0, w, h));
if (_showScoreFl) {
Common::String score = Common::String::format("Your Score is: %ld", _totScore);
- const Graphics::Font &font(*FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont));
- Common::Rect rect(10, 440, 200, 440 + font.getFontHeight());
- screen->fillRect(rect, 0);
- font.drawString(screen, score, rect.left, rect.top, 190, 255, Graphics::kTextAlignCenter);
+ const Graphics::Font &font(*FontMan.getFontByUsage(
+ _screenW >= 640 ? Graphics::FontManager::kBigGUIFont : Graphics::FontManager::kGUIFont));
+ int scoreTop = _screenH - _screenH / 12;
+ int scoreMaxWidth = _screenW >= 640 ? 200 : 150;
+ uint scoreColor = screen->format.bytesPerPixel == 1 ? 0xff : screen->format.RGBToColor(0xff, 0xff, 0xff);
+ Common::Rect rect(10, scoreTop, scoreMaxWidth, scoreTop + font.getFontHeight());
+ if (getPlatform() != Common::kPlatform3DO)
+ screen->fillRect(rect, 0);
+ font.drawString(screen, score, rect.left, rect.top, scoreMaxWidth - 10,
+ scoreColor, Graphics::kTextAlignCenter);
_showScoreFl = false;
}
g_system->unlockScreen();
- g_system->getPaletteManager()->setPalette(_image->getPalette(), 0, 256);
+ if (_image->getPalette() != nullptr)
+ g_system->getPaletteManager()->setPalette(_image->getPalette(), 0, 256);
g_system->updateScreen();
}
}
-void PlumbersGame::playSound() {
- Common::String name = _scenes[_curSceneIdx]._sceneName + "/" + _scenes[_curSceneIdx]._waveFilename;
+void PlumbersGame::playSound(const Common::String &name) {
debugC(3, kDebugGeneral, "%s : %s", __FUNCTION__, name.c_str());
Common::File *file = new Common::File();
if (!file->open(name))
error("unable to load sound %s", name.c_str());
- Audio::RewindableAudioStream *audioStream = Audio::makeWAVStream(file, DisposeAfterUse::YES);
- Audio::AudioStream *stream = audioStream;
+ Audio::AudioStream *stream;
+ if (name.hasSuffix(".aiff") || name.hasSuffix(".Aiff"))
+ stream = Audio::makeAIFFStream(file, DisposeAfterUse::YES);
+ else
+ stream = Audio::makeWAVStream(file, DisposeAfterUse::YES);
stopSound();
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, stream, -1, Audio::Mixer::kMaxChannelVolume);
}
@@ -249,53 +550,97 @@ void PlumbersGame::stopSound() {
void PlumbersGame::showScene() {
debugC(1, kDebugGeneral, "%s : %d", __FUNCTION__, _curSceneIdx);
- _curBitmapIdx = _scenes[_curSceneIdx]._startBitmap;
- loadImage(_scenes[_curSceneIdx]._sceneName, _bitmaps[_curBitmapIdx]._filename);
+ _curBitmapIdx = _scenes[_curSceneIdx]._startBitmap - 1;
+ updateScene();
+ if (_scenes[_curSceneIdx]._waveFilename != "")
+ _actions.push(PlaySound);
_actions.push(Redraw);
- _setDurationFl = true;
- _actions.push(PlaySound);
+}
+
+int PlumbersGame::getMouseHiLite() {
+ Common::Point mousePos = g_system->getEventManager()->getMousePos();
+ for (int i = 0; i < _scenes[_curSceneIdx]._decisionChoices && i < kMaxChoice; i++) {
+ if (_scenes[_curSceneIdx]._choices[i]._region.contains(mousePos))
+ return i;
+ }
+
+ return -1;
}
void PlumbersGame::updateScene() {
debugC(2, kDebugGeneral, "%s : %d", __FUNCTION__, _curBitmapIdx);
_curBitmapIdx++;
if (_curBitmapIdx >= _scenes[_curSceneIdx]._startBitmap + _scenes[_curSceneIdx]._bitmapNum) {
- if (_scenes[_curSceneIdx]._decisionChoices == 1) {
+ if (_scenes[_curSceneIdx]._style == Scene::STYLE_VIDEO) {
+ _videoDecoder = new Video::ThreeDOMovieDecoder();
+ _curChoice = 0;
+ if (!_videoDecoder->loadFile(_scenes[_curSceneIdx]._sceneName)) {
+ _actions.push(ChangeScene);
+ return;
+ }
+ _videoDecoder->start();
+ } else if (_scenes[_curSceneIdx]._decisionChoices == 1) {
_curChoice = 0;
_actions.push(ChangeScene);
} else {
_showScoreFl = true;
_leftButtonDownFl = true;
_setDurationFl = false;
- loadImage(_scenes[_curSceneIdx]._sceneName, _scenes[_curSceneIdx]._decisionBitmap);
+ if (_scenes[_curSceneIdx]._style == Scene::STYLE_DECISION_MIKE) {
+ loadMikeDecision(_scenes[_curSceneIdx]._sceneName, _scenes[_curSceneIdx]._decisionBitmap,
+ _scenes[_curSceneIdx]._decisionChoices);
+ _hiLite = 0;
+ _kbdHiLite = 0;
+ updateHiLite();
+ } else if (_scenes[_curSceneIdx]._style == Scene::STYLE_DECISION_TUN) {
+ loadImage(_scenes[_curSceneIdx]._sceneName + ".cel");
+ _hiLite = 0;
+ _kbdHiLite = 0;
+ updateHiLite();
+ Common::File fileCtrl;
+ if (fileCtrl.open("tuntest/dec/controlhelp.cel"))
+ _ctrlHelpImage->loadStream(fileCtrl);
+ } else {
+ loadImage(_scenes[_curSceneIdx]._sceneName + "/" + _scenes[_curSceneIdx]._decisionBitmap);
+ _hiLite = -1;
+ _kbdHiLite = -1;
+ }
+
+ _mouseHiLite = getMouseHiLite();
}
} else {
- loadImage(_scenes[_curSceneIdx]._sceneName, _bitmaps[_curBitmapIdx]._filename);
+ loadImage(_scenes[_curSceneIdx]._sceneName + "/" + _bitmaps[_curBitmapIdx]._filename);
_setDurationFl = true;
}
}
void PlumbersGame::changeScene() {
debugC(1, kDebugGeneral, "%s : %d", __FUNCTION__, _curChoice);
- if (_scenes[_curSceneIdx]._choices[_curChoice]._sceneIdx == -1) {
+ if (_scenes[_curSceneIdx]._choices[_curChoice]._sceneName == "SC-1") {
_curSceneIdx = _prvSceneIdx;
_curBitmapIdx = 9999;
_actions.push(UpdateScene);
_actions.push(Redraw);
- } else if (_scenes[_curSceneIdx]._choices[_curChoice]._sceneIdx == 32767) {
+ } else if (_scenes[_curSceneIdx]._choices[_curChoice]._sceneName == "restart") {
+ _curSceneIdx = 0;
+ _totScore = 0;
+ _actions.push(UpdateScene);
+ _actions.push(Redraw);
+ } else if (_scenes[_curSceneIdx]._choices[_curChoice]._sceneName == "SC32767"
+ || _scenes[_curSceneIdx]._choices[_curChoice]._sceneName == "end") {
_endGameFl = true;
} else {
if (_scenes[_curSceneIdx]._decisionChoices > 1)
_prvSceneIdx = _curSceneIdx;
if (_scenes[_curSceneIdx]._choices[_curChoice]._skipScene) {
- _curSceneIdx = getSceneNumb(_scenes[_curSceneIdx]._choices[_curChoice]._sceneIdx);
+ _curSceneIdx = getSceneNumb(_scenes[_curSceneIdx]._choices[_curChoice]._sceneName);
_curBitmapIdx = 9999;
_actions.push(UpdateScene);
_actions.push(Redraw);
g_system->getTimerManager()->removeTimerProc(onTimer);
_timerInstalled = false;
} else {
- _curSceneIdx = getSceneNumb(_scenes[_curSceneIdx]._choices[_curChoice]._sceneIdx);
+ _curSceneIdx = getSceneNumb(_scenes[_curSceneIdx]._choices[_curChoice]._sceneName);
_actions.push(ShowScene);
}
}
@@ -318,7 +663,7 @@ void PlumbersGame::initTables() {
memset(_bitmaps, 0, sizeof(_bitmaps));
}
-void PlumbersGame::readTables(const Common::String &fileName) {
+void PlumbersGame::readTablesPC(const Common::String &fileName) {
Common::File file;
if (!file.open(fileName))
error("sReadTables(): Error reading BIN file");
@@ -341,10 +686,11 @@ void PlumbersGame::readTables(const Common::String &fileName) {
_scenes[i]._waveFilename = Common::String(buf);
file.read(buf, kMaxName);
_scenes[i]._decisionBitmap = Common::String(buf);
+ _scenes[i]._style = Scene::STYLE_PC;
for (int j = 0; j < kMaxChoice; j++) {
_scenes[i]._choices[j]._points = file.readSint32LE();
- _scenes[i]._choices[j]._sceneIdx = file.readSint16LE();
+ _scenes[i]._choices[j]._sceneName = Common::String::format("SC%02d", file.readSint16LE());
_scenes[i]._choices[j]._skipScene = file.readSint16LE();
int left = file.readSint16LE();
int top = file.readSint16LE();
@@ -355,18 +701,317 @@ void PlumbersGame::readTables(const Common::String &fileName) {
}
for (int i = 0; i < kMaxBitmaps; i++) {
- _bitmaps[i]._duration = file.readSint16LE();
+ _bitmaps[i]._duration = file.readSint16LE() * 100;
file.read(buf, kMaxName);
_bitmaps[i]._filename = Common::String(buf);
}
}
-int PlumbersGame::getSceneNumb(int sNo) {
- debugC(1, kDebugGeneral, "%s : %d", __FUNCTION__, sNo);
- Common::String testString = Common::String::format("SC%02d", sNo);
+static void makeMikeDecision(Scene &scene, uint num) {
+ scene._bitmapNum = 0;
+ scene._startBitmap = 0;
+ scene._decisionChoices = num;
+ scene._waveFilename = "";
+ scene._style = Scene::STYLE_DECISION_MIKE;
+
+ Common::Point sz = getMikeSize(num);
+
+ for (uint i = 0; i < num; i++) {
+ Common::Point ms = getMikeStart(i, num);
+ scene._choices[i]._region = Common::Rect(ms.x, ms.y, ms.x + 2 * sz.x, ms.y + sz.y);
+ }
+}
+
+static void makeVideo(Scene &scene, const Common::String &videoName, const Common::String &nextScene) {
+ scene._bitmapNum = 0;
+ scene._startBitmap = 0;
+ scene._decisionChoices = 1;
+ scene._waveFilename = "";
+ scene._style = Scene::STYLE_VIDEO;
+ scene._sceneName = videoName;
+ scene._decisionBitmap = "";
+ scene._choices[0]._sceneName = nextScene;
+}
+
+static const struct {
+ const char *from;
+ struct {
+ const char *scene;
+ int points;
+ } to[kMaxChoice];
+} tungraph[] = {
+ {
+ "dec13",
+ {
+ {"sc15", -10000},
+ {"sc17", -10000},
+ {"sc20", -50000}
+ }
+ },
+ {
+ "dec16",
+ {
+ {"dec13", -20000},
+ {"restart", 0}
+ }
+ },
+ {
+
+ "dec18",
+ {
+ {"dec13", -30000},
+ {"restart", 0}
+ }
+ },
+ {
+ "dec20",
+ {
+ {"sc21", -90000},
+ {"sc22", -90000}
+ }
+ },
+ {
+ "dec22",
+ {
+ {"dec20", -90000},
+ {"restart", 0}
+ }
+ },
+ {
+ "dec23",
+ {
+ {"sc24", 50000},
+ {"sc28", -50000}
+ }
+ },
+ {
+ "dec25",
+ {
+ {"sc26", -75000},
+ {"sc27", -90000}
+ }
+ },
+ {
+ "dec26",
+ {
+ {"dec25", -75000},
+ {"restart", 0}
+ }
+ },
+ {
+ "dec28",
+ {
+ {"dec23", -75000},
+ {"restart", 0}
+ }
+ },
+ {
+ "dec29",
+ {
+ {"sc30", -20000},
+ {"sc31", 90000}
+ }
+ },
+ {
+ "dec30",
+ {
+ {"sc32", 0},
+ {"restart", 0},
+ {"end", 0}
+ }
+ },
+ {
+ "dec31",
+ {
+ {"dec29", -20000},
+ {"end", 0}
+ }
+
+ }
+};
+
+void PlumbersGame::readTables3DO(const Common::String &fileName) {
+ Common::File file;
+ if (!file.open(fileName))
+ error("sReadTables(): Error reading launchme file");
+
+ initTables();
+
+ file.seek(0x1ec08);
+
+ Common::HashMap<Common::String, int> imgCounter, firstImg;
+
+ uint bitmapCtr = 0;
+
+ for (; bitmapCtr < 287; bitmapCtr++) {
+ char buf[16];
+ file.read(buf, 16);
+ _bitmaps[bitmapCtr]._filename = Common::String(buf);
+ _bitmaps[bitmapCtr]._duration = (file.readSint32BE() * 1000) / 60;
+ Common::String scene = Common::String(buf).substr(0, 4);
+ scene.toLowercase();
+ imgCounter[scene]++;
+ if (!firstImg.contains(scene))
+ firstImg[scene] = bitmapCtr;
+ }
+
+ file.seek(0x205d0);
+
+ for (; bitmapCtr < 704; bitmapCtr++) {
+ char buf[16];
+ file.read(buf, 16);
+ _bitmaps[bitmapCtr]._filename = Common::String(buf);
+ _bitmaps[bitmapCtr]._duration = (file.readSint32BE() * 1000) / 60;
+ Common::String scene = Common::String(buf).substr(0, 4);
+ scene.toLowercase();
+ imgCounter[scene]++;
+ if (!firstImg.contains(scene))
+ firstImg[scene] = bitmapCtr;
+ }
+
+ uint scPtr = 0;
+ makeVideo(_scenes[scPtr++], "kirinweaver", "janp1weaver");
+ makeVideo(_scenes[scPtr++], "janp1weaver", "janp2weaver");
+ makeVideo(_scenes[scPtr++], "janp2weaver", "janp3weaver");
+ makeVideo(_scenes[scPtr++], "janp3weaver", "titleweaver");
+ makeVideo(_scenes[scPtr++], "titleweaver", "miketest/sc00");
+
+ makeMikeDecision(_scenes[scPtr], 2);
+ _scenes[scPtr]._sceneName = "miketest/sc00";
+ _scenes[scPtr]._decisionBitmap = "DEC00";
+ _scenes[scPtr]._choices[0]._sceneName = "miketest/sc01";
+ _scenes[scPtr++]._choices[1]._sceneName = "miketest/sc07a";
+
+ for (uint scNo = 1; scNo <= 13; scNo++, scPtr++) {
+ Common::String imgScene = scNo == 5 ?
+ "sc44" : Common::String::format("sc%02d", scNo);
+ _scenes[scPtr]._bitmapNum = imgCounter[imgScene];
+ _scenes[scPtr]._startBitmap = firstImg[imgScene];
+ _scenes[scPtr]._sceneName = scNo == 5 ? "miketest/sc04a" : Common::String::format("miketest/sc%02d", scNo);
+ _scenes[scPtr]._waveFilename = Common::String::format("DIA%02d.aiff", scNo == 5 ? 4 : scNo);
+ _scenes[scPtr]._style = Scene::STYLE_PC;
+ _scenes[scPtr]._decisionChoices = 1;
+ switch(scNo) {
+ case 4:
+ case 5:
+ _scenes[scPtr]._choices[0]._sceneName = "miketest/sc06";
+ break;
+ case 11:
+ _scenes[scPtr]._choices[0]._sceneName = "miketest/sc13";
+ break;
+ case 13:
+ _scenes[scPtr]._choices[0]._sceneName = "tuntest/dec/dec13";
+ break;
+ case 7:
+ case 8:
+ case 12:
+ _scenes[scPtr]._choices[0]._sceneName = Common::String::format("miketest/sc%02da", scNo);
+ break;
+ default:
+ _scenes[scPtr]._choices[0]._sceneName = Common::String::format("miketest/sc%02d", scNo + 1);
+ break;
+ }
+ }
+
+ makeMikeDecision(_scenes[scPtr], 3);
+ _scenes[scPtr]._sceneName = "miketest/sc07a";
+ _scenes[scPtr]._decisionBitmap = "DEC07";
+ _scenes[scPtr]._choices[0]._sceneName = "miketest/sc08";
+ _scenes[scPtr]._choices[0]._points = -10000;
+ _scenes[scPtr]._choices[1]._sceneName = "miketest/sc11";
+ _scenes[scPtr]._choices[1]._points = 10000;
+ _scenes[scPtr]._choices[2]._sceneName = "miketest/sc12";
+ _scenes[scPtr]._choices[2]._points = -20000;
+ scPtr++;
+
+ makeMikeDecision(_scenes[scPtr], 2);
+ _scenes[scPtr]._sceneName = "miketest/sc08a";
+ _scenes[scPtr]._decisionBitmap = "DEC08";
+ _scenes[scPtr]._choices[0]._sceneName = "miketest/sc09";
+ _scenes[scPtr]._choices[0]._points = 0;
+ _scenes[scPtr]._choices[1]._sceneName = "miketest/sc09";
+ _scenes[scPtr]._choices[1]._points = 10000;
+ scPtr++;
+
+ makeMikeDecision(_scenes[scPtr], 2);
+ _scenes[scPtr]._sceneName = "miketest/sc12a";
+ _scenes[scPtr]._decisionBitmap = "DEC12";
+ _scenes[scPtr]._choices[0]._sceneName = "miketest/sc07a";
+ _scenes[scPtr]._choices[0]._points = 0;
+ _scenes[scPtr]._choices[1]._sceneName = "restart";
+ _scenes[scPtr]._choices[1]._points = 0;
+ scPtr++;
+
+ for (uint scNo = 15; scNo <= 32; scNo++) {
+ // there is no sc19
+ if (scNo == 19)
+ continue;
+ Common::String imgScene = Common::String::format("sc%02d", scNo);
+ _scenes[scPtr]._bitmapNum = imgCounter[imgScene];
+ _scenes[scPtr]._startBitmap = firstImg[imgScene];
+ _scenes[scPtr]._sceneName = Common::String::format("tuntest/sc%02d", scNo);
+ _scenes[scPtr]._waveFilename = Common::String::format("sc%02d.aiff", scNo);
+ _scenes[scPtr]._style = Scene::STYLE_PC;
+ _scenes[scPtr]._decisionChoices = 1;
+ if (scNo == 32)
+ _scenes[scPtr]._choices[0]._sceneName = "end";
+ else if (scNo == 16 || scNo == 18 || scNo == 20 || scNo == 22 || scNo == 23 || scNo == 25
+ || scNo == 26 || scNo == 28 || scNo == 29 || scNo == 30 || scNo == 31)
+ _scenes[scPtr]._choices[0]._sceneName = Common::String::format("tuntest/dec/dec%02d", scNo);
+ else
+ _scenes[scPtr]._choices[0]._sceneName = Common::String::format("tuntest/sc%02d", scNo + 1);
+ scPtr++;
+ }
+
+ file.seek(0x20290);
+
+ for (int i = 0; i < 26; i++) {
+ char buf[16];
+ file.read(buf, 16);
+ uint32 x = file.readUint32BE();
+ uint32 y = file.readUint32BE();
+ uint32 w = file.readUint32BE();
+ uint32 h = file.readUint32BE();
+ Common::String shortName = Common::String(buf).substr(0, 5);
+ Common::String sceneName = "tuntest/dec/" + shortName;
+ if (i == 0 || _scenes[scPtr - 1]._sceneName != sceneName) {
+ _scenes[scPtr]._bitmapNum = 0;
+ _scenes[scPtr]._startBitmap = 0;
+ _scenes[scPtr]._decisionChoices = 0;
+ _scenes[scPtr]._waveFilename = "";
+ _scenes[scPtr]._style = Scene::STYLE_DECISION_TUN;
+ _scenes[scPtr]._sceneName = sceneName;
+ _scenes[scPtr]._decisionBitmap = shortName;
+ scPtr++;
+ }
+
+ Scene &scene = _scenes[scPtr - 1];
+ assert(scene._decisionChoices < kMaxChoice);
+ scene._choices[scene._decisionChoices]._region = Common::Rect(x, y, x + w, y + h);
+ for (uint j = 0 ; j < ARRAYSIZE(tungraph); j++) {
+ if (shortName == tungraph[j].from) {
+ Common::String target = tungraph[j].to[scene._decisionChoices].scene;
+ if (target[0] == 's')
+ scene._choices[scene._decisionChoices]._sceneName = "tuntest/" + target;
+ else
+ scene._choices[scene._decisionChoices]._sceneName = "tuntest/dec/" + target;
+ scene._choices[scene._decisionChoices]._points = tungraph[j].to[scene._decisionChoices].points;
+ break;
+ }
+ }
+ scene._decisionChoices++;
+ }
+
+ _totScene = scPtr;
+}
+
+int PlumbersGame::getSceneNumb(const Common::String &sName) {
+ debugC(1, kDebugGeneral, "%s : %s", __FUNCTION__, sName.c_str());
+ if (sName == "miketest/sc04" && _cheatEnabled)
+ return getSceneNumb("miketest/sc04a");
for (int sCurScene = 0; sCurScene < _totScene; sCurScene++) {
- if (testString == _scenes[sCurScene]._sceneName)
+ if (sName == _scenes[sCurScene]._sceneName)
return sCurScene;
}
return 0;
diff --git a/engines/plumbers/plumbers.h b/engines/plumbers/plumbers.h
index 0a38e938f7..8c15822911 100644
--- a/engines/plumbers/plumbers.h
+++ b/engines/plumbers/plumbers.h
@@ -32,12 +32,18 @@
#include "audio/mixer.h"
+#include "video/3do_decoder.h"
+
struct ADGameDescription;
namespace Image {
class ImageDecoder;
}
+namespace Graphics {
+class Surface;
+}
+
namespace Plumbers {
class Console;
@@ -46,6 +52,31 @@ enum PlumbersDebugChannels {
kDebugGeneral = 1 << 0
};
+static const int kMaxChoice = 3;
+
+struct Choice {
+ long _points;
+ int _skipScene;
+ Common::Rect _region;
+ Common::String _sceneName;
+};
+
+struct Scene {
+ int _bitmapNum;
+ int _startBitmap;
+ int _decisionChoices;
+ Common::String _sceneName;
+ Common::String _waveFilename;
+ Common::String _decisionBitmap;
+ enum {
+ STYLE_PC = 0,
+ STYLE_DECISION_MIKE = 1,
+ STYLE_DECISION_TUN = 2,
+ STYLE_VIDEO = 3
+ } _style;
+ Choice _choices[kMaxChoice];
+};
+
class PlumbersGame : public Engine {
public:
PlumbersGame(OSystem *syst, const ADGameDescription *gameDesc);
@@ -61,7 +92,6 @@ public:
private:
static const int kMaxName = 13 + 1;
static const int kMaxBitmaps = 2000;
- static const int kMaxChoice = 3;
static const int kMaxScene = 100;
struct {
@@ -69,22 +99,10 @@ private:
Common::String _filename;
} _bitmaps[kMaxBitmaps];
- struct {
- int _bitmapNum;
- int _startBitmap;
- int _decisionChoices;
- Common::String _sceneName;
- Common::String _waveFilename;
- Common::String _decisionBitmap;
- struct {
- long _points;
- int _sceneIdx;
- int _skipScene;
- Common::Rect _region;
- } _choices[kMaxChoice];
- } _scenes[kMaxScene];
+ Scene _scenes[kMaxScene];
Image::ImageDecoder *_image;
+ Image::ImageDecoder *_ctrlHelpImage;
Console *_console;
bool _showScoreFl;
@@ -97,6 +115,14 @@ private:
int _curChoice;
int _totScene;
long _totScore;
+ int _screenW, _screenH;
+ int _kbdHiLite;
+ int _mouseHiLite;
+ int _hiLite;
+ bool _hiLiteEnabled;
+ bool _cheatEnabled;
+ int _cheatFSM;
+ bool _leftShoulderPressed;
enum Action {
Redraw,
@@ -107,13 +133,17 @@ private:
};
Common::Queue<Action> _actions;
+ Graphics::Surface *_compositeSurface;
- void loadImage(const Common::String &dirname, const Common::String &filename);
+ void loadImage(const Common::String &name);
+ void loadMikeDecision(const Common::String &dirname, const Common::String &baseFilename, uint num);
void drawScreen();
+ void updateHiLite();
Audio::SoundHandle _soundHandle;
+ Video::ThreeDOMovieDecoder *_videoDecoder;
- void playSound();
+ void playSound(const Common::String &name);
void stopSound();
void showScene();
@@ -124,8 +154,15 @@ private:
static void onTimer(void *arg);
void initTables();
- void readTables(const Common::String &fileName);
- int getSceneNumb(int sNo);
+ void readTablesPC(const Common::String &fileName);
+ void readTables3DO(const Common::String &fileName);
+ int getSceneNumb(const Common::String &sName);
+ int getMouseHiLite();
+
+ void joyUp();
+ void joyDown();
+ void joyA();
+ void skipVideo();
};
} // End of namespace Plumbers
More information about the Scummvm-git-logs
mailing list