aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorBenjamin Haisch2009-01-22 13:04:29 +0000
committerBenjamin Haisch2009-01-22 13:04:29 +0000
commit5b8105afb3a345cfd66efa795726329f509572c3 (patch)
tree4ff90316c9dee6be8bda8a0c3f8413ab5d8178a5 /engines
parentd5d7175691ea3cde7aa941886e3197763c1398c6 (diff)
downloadscummvm-rg350-5b8105afb3a345cfd66efa795726329f509572c3.tar.gz
scummvm-rg350-5b8105afb3a345cfd66efa795726329f509572c3.tar.bz2
scummvm-rg350-5b8105afb3a345cfd66efa795726329f509572c3.zip
- Added support for The Manhole EGA version
- Support for 'chunked' picture resources and EGA pictures - Improved the mouth sync in RtZ (still not perfect, though) - Removed obsolete TODOs - Fixed sfPlayMovie to return if the movie playback was aborted or not; this is used by RtZ to determine if it should display the credits screen after the intro movie svn-id: r35997
Diffstat (limited to 'engines')
-rw-r--r--engines/made/database.cpp94
-rw-r--r--engines/made/database.h5
-rw-r--r--engines/made/detection.cpp2
-rw-r--r--engines/made/graphics.cpp33
-rw-r--r--engines/made/graphics.h3
-rw-r--r--engines/made/pmvplayer.cpp16
-rw-r--r--engines/made/pmvplayer.h5
-rw-r--r--engines/made/resource.cpp99
-rw-r--r--engines/made/resource.h2
-rw-r--r--engines/made/screen.cpp5
-rw-r--r--engines/made/scriptfuncs.cpp37
-rw-r--r--engines/made/sound.cpp9
12 files changed, 235 insertions, 75 deletions
diff --git a/engines/made/database.cpp b/engines/made/database.cpp
index d8f9800ef6..f541047ca9 100644
--- a/engines/made/database.cpp
+++ b/engines/made/database.cpp
@@ -179,6 +179,13 @@ byte *ObjectV2::getData() {
return _objData + 4;
}
+int ObjectV1::load(Common::SeekableReadStream &source) {
+ ObjectV2::load(source);
+ // Manhole EGA has the two property counts reversed
+ SWAP(_objData[2], _objData[3]);
+ return _objSize;
+}
+
int ObjectV3::load(Common::SeekableReadStream &source) {
_freeData = true;
@@ -382,23 +389,37 @@ void GameDatabaseV2::load(Common::SeekableReadStream &sourceS) {
if (strncmp(header, "ADVSYS", 6))
warning ("Unexpected database header, expected ADVSYS");
- /*uint32 unk = */sourceS.readUint16LE();
+ uint32 textOffs, objectsOffs, objectsSize, textSize;
+ uint16 objectCount, varObjectCount;
+
+ sourceS.readUint16LE(); // skip sub-version
+ sourceS.skip(18); // skip program name
+
+ if (version == 40) {
+ sourceS.readUint16LE(); // skip unused
+ objectCount = sourceS.readUint16LE();
+ _gameStateSize = sourceS.readUint16LE() * 2;
+ objectsOffs = sourceS.readUint16LE() * 512;
+ textOffs = sourceS.readUint16LE() * 512;
+ _mainCodeObjectIndex = sourceS.readUint16LE();
+ varObjectCount = 0; // unused in V1
+ objectsSize = 0; // unused in V1
+ } else if (version == 54) {
+ textOffs = sourceS.readUint16LE() * 512;
+ objectCount = sourceS.readUint16LE();
+ varObjectCount = sourceS.readUint16LE();
+ _gameStateSize = sourceS.readUint16LE() * 2;
+ sourceS.readUint16LE(); // unknown
+ objectsOffs = sourceS.readUint16LE() * 512;
+ sourceS.readUint16LE(); // unknown
+ _mainCodeObjectIndex = sourceS.readUint16LE();
+ sourceS.readUint16LE(); // unknown
+ objectsSize = sourceS.readUint32LE() * 2;
+ }
- sourceS.skip(18);
+ textSize = objectsOffs - textOffs;
- uint32 textOffs = sourceS.readUint16LE() * 512;
- uint16 objectCount = sourceS.readUint16LE();
- uint16 varObjectCount = sourceS.readUint16LE();
- _gameStateSize = sourceS.readUint16LE() * 2;
- sourceS.readUint16LE(); // unknown
- uint32 objectsOffs = sourceS.readUint16LE() * 512;
- sourceS.readUint16LE(); // unknown
- _mainCodeObjectIndex = sourceS.readUint16LE();
- sourceS.readUint16LE(); // unknown
- uint32 objectsSize = sourceS.readUint32LE() * 2;
- uint32 textSize = objectsOffs - textOffs;
-
- debug(2, "textOffs = %08X; textSize = %08X; objectCount = %d; varObjectCount = %d; gameStateSize = %d; objectsOffs = %08X; objectsSize = %d\n", textOffs, textSize, objectCount, varObjectCount, _gameStateSize, objectsOffs, objectsSize);
+ debug(0, "textOffs = %08X; textSize = %08X; objectCount = %d; varObjectCount = %d; gameStateSize = %d; objectsOffs = %08X; objectsSize = %d; _mainCodeObjectIndex = %04X\n", textOffs, textSize, objectCount, varObjectCount, _gameStateSize, objectsOffs, objectsSize, _mainCodeObjectIndex);
_gameState = new byte[_gameStateSize + 2];
memset(_gameState, 0, _gameStateSize + 2);
@@ -410,15 +431,35 @@ void GameDatabaseV2::load(Common::SeekableReadStream &sourceS) {
// "Decrypt" the text data
for (uint32 i = 0; i < textSize; i++)
_gameText[i] += 0x1E;
-
+
sourceS.seek(objectsOffs);
- for (uint32 i = 0; i < objectCount; i++) {
- Object *obj = new ObjectV2();
- int objSize = obj->load(sourceS);
- // objects are aligned on 2-byte-boundaries, skip unused bytes
- sourceS.skip(objSize % 2);
- _objects.push_back(obj);
+ if (version == 40) {
+ // Initialize the object array
+ for (uint32 i = 0; i < objectCount; i++)
+ _objects.push_back(NULL);
+ // Read two "sections" of objects
+ // It seems the first section is data while the second one is code.
+ // The interpreter however doesn't care which section the objects come from.
+ for (int section = 0; section < 2; section++) {
+ while (!sourceS.eos()) {
+ int16 objIndex = sourceS.readUint16LE();
+ debug("objIndex = %04X; section = %d", objIndex, section);
+ if (objIndex == 0)
+ break;
+ Object *obj = new ObjectV1();
+ obj->load(sourceS);
+ _objects[objIndex - 1] = obj;
+ }
+ }
+ } else if (version == 54) {
+ for (uint32 i = 0; i < objectCount; i++) {
+ Object *obj = new ObjectV2();
+ int objSize = obj->load(sourceS);
+ // Objects are aligned on 2-byte-boundaries, skip unused bytes
+ sourceS.skip(objSize % 2);
+ _objects.push_back(obj);
+ }
}
}
@@ -464,7 +505,11 @@ int16 GameDatabaseV2::loadgame(const char *filename, int16 version) {
}
int16 *GameDatabaseV2::findObjectProperty(int16 objectIndex, int16 propertyId, int16 &propertyFlag) {
+
Object *obj = getObject(objectIndex);
+ if (obj->getClass() >= 0x7FFE) {
+ error("GameDatabaseV2::findObjectProperty(%04X, %04X) Not an object", objectIndex, propertyId);
+ }
int16 *prop = (int16*)obj->getData();
byte count1 = obj->getCount1();
@@ -568,11 +613,9 @@ void GameDatabaseV3::load(Common::SeekableReadStream &sourceS) {
for (uint32 i = 0; i < objectCount; i++) {
Object *obj = new ObjectV3();
-
// The LSB indicates if it's a constant or variable object.
// Constant objects are loaded from disk, while variable objects exist
// in the _gameState buffer.
-
if (objectOffsets[i] & 1) {
sourceS.seek(objectsOffs + objectOffsets[i] - 1);
obj->load(sourceS);
@@ -682,6 +725,9 @@ int16 GameDatabaseV3::loadgame(const char *filename, int16 version) {
int16 *GameDatabaseV3::findObjectProperty(int16 objectIndex, int16 propertyId, int16 &propertyFlag) {
Object *obj = getObject(objectIndex);
+ if (obj->getClass() >= 0x7FFE) {
+ error("GameDatabaseV2::findObjectProperty(%04X, %04X) Not an object", objectIndex, propertyId);
+ }
int16 *prop = (int16*)obj->getData();
byte count1 = obj->getCount1();
diff --git a/engines/made/database.h b/engines/made/database.h
index bceed50109..cf5dd31225 100644
--- a/engines/made/database.h
+++ b/engines/made/database.h
@@ -39,6 +39,7 @@ namespace Made {
class Object {
public:
+
Object();
virtual ~Object();
@@ -86,7 +87,11 @@ public:
bool isConstant() {
return false;
}
+};
+class ObjectV1 : public ObjectV2 {
+public:
+ int load(Common::SeekableReadStream &source);
};
class ObjectV3 : public Object {
diff --git a/engines/made/detection.cpp b/engines/made/detection.cpp
index 17bad6af12..e59bc2ef7f 100644
--- a/engines/made/detection.cpp
+++ b/engines/made/detection.cpp
@@ -261,7 +261,6 @@ static const MadeGameDescription gameDescriptions[] = {
2,
},
-#if 0
{
// The Manhole (EGA, 5.25")
{
@@ -277,7 +276,6 @@ static const MadeGameDescription gameDescriptions[] = {
GF_FLOPPY,
1,
},
-#endif
{
// Leather Goddesses of Phobos 2
diff --git a/engines/made/graphics.cpp b/engines/made/graphics.cpp
index 35b00b466c..89ec7b20a4 100644
--- a/engines/made/graphics.cpp
+++ b/engines/made/graphics.cpp
@@ -46,6 +46,22 @@ byte ValueReader::readPixel() {
return value;
}
+uint16 ValueReader::readUint16() {
+ uint16 value = READ_LE_UINT16(_buffer);
+ _buffer += 2;
+ return value;
+}
+
+uint32 ValueReader::readUint32() {
+ uint32 value = READ_LE_UINT32(_buffer);
+ _buffer += 4;
+ return value;
+}
+
+void ValueReader::resetNibbleSwitch() {
+ _nibbleSwitch = false;
+}
+
void decompressImage(byte *source, Graphics::Surface &surface, uint16 cmdOffs, uint16 pixelOffs, uint16 maskOffs, uint16 lineSize, byte cmdFlags, byte pixelFlags, byte maskFlags, bool deltaFrame) {
const int offsets[] = {
@@ -59,8 +75,11 @@ void decompressImage(byte *source, Graphics::Surface &surface, uint16 cmdOffs, u
uint16 height = surface.h;
byte *cmdBuffer = source + cmdOffs;
- byte *maskBuffer = source + maskOffs;
+ ValueReader maskReader(source + maskOffs, (maskFlags & 2) != 0);
ValueReader pixelReader(source + pixelOffs, (pixelFlags & 2) != 0);
+
+ if ((maskFlags != 0) && (maskFlags != 2) && (pixelFlags != 0) && (pixelFlags != 2) && (cmdFlags != 0))
+ error("decompressImage() Unsupported flags: cmdFlags = %02X; maskFlags = %02X, pixelFlags = %02X", cmdFlags, maskFlags, pixelFlags);
byte *destPtr = (byte*)surface.getBasePtr(0, 0);
@@ -109,8 +128,7 @@ void decompressImage(byte *source, Graphics::Surface &surface, uint16 cmdOffs, u
case 1:
pixels[0] = pixelReader.readPixel();
pixels[1] = pixelReader.readPixel();
- mask = READ_LE_UINT16(maskBuffer);
- maskBuffer += 2;
+ mask = maskReader.readUint16();
for (int i = 0; i < 16; i++) {
lineBuf[drawDestOfs + offsets[i]] = pixels[mask & 1];
mask >>= 1;
@@ -122,8 +140,7 @@ void decompressImage(byte *source, Graphics::Surface &surface, uint16 cmdOffs, u
pixels[1] = pixelReader.readPixel();
pixels[2] = pixelReader.readPixel();
pixels[3] = pixelReader.readPixel();
- mask = READ_LE_UINT32(maskBuffer);
- maskBuffer += 4;
+ mask = maskReader.readUint32();
for (int i = 0; i < 16; i++) {
lineBuf[drawDestOfs + offsets[i]] = pixels[mask & 3];
mask >>= 2;
@@ -132,9 +149,11 @@ void decompressImage(byte *source, Graphics::Surface &surface, uint16 cmdOffs, u
case 3:
if (!deltaFrame) {
- // Yes, it reads from maskBuffer here
+ // For EGA pictures: Pixels are read starting from a new byte
+ maskReader.resetNibbleSwitch();
+ // Yes, it reads from maskReader here
for (int i = 0; i < 16; i++)
- lineBuf[drawDestOfs + offsets[i]] = *maskBuffer++;
+ lineBuf[drawDestOfs + offsets[i]] = maskReader.readPixel();
}
break;
diff --git a/engines/made/graphics.h b/engines/made/graphics.h
index 1a5cf72677..bf5ec288ff 100644
--- a/engines/made/graphics.h
+++ b/engines/made/graphics.h
@@ -37,6 +37,9 @@ class ValueReader {
public:
ValueReader(byte *source, bool nibbleMode) : _buffer(source), _nibbleBuf(0), _nibbleMode(nibbleMode), _nibbleSwitch(false) {}
byte readPixel();
+ uint16 readUint16();
+ uint32 readUint32();
+ void resetNibbleSwitch();
protected:
byte _nibbleBuf;
bool _nibbleMode, _nibbleSwitch;
diff --git a/engines/made/pmvplayer.cpp b/engines/made/pmvplayer.cpp
index c3f5879f53..5240a3980d 100644
--- a/engines/made/pmvplayer.cpp
+++ b/engines/made/pmvplayer.cpp
@@ -34,15 +34,15 @@ PmvPlayer::PmvPlayer(MadeEngine *vm, Audio::Mixer *mixer) : _fd(NULL), _vm(vm),
PmvPlayer::~PmvPlayer() {
}
-void PmvPlayer::play(const char *filename) {
+bool PmvPlayer::play(const char *filename) {
- _abort = false;
+ _aborted = false;
_surface = NULL;
_fd = new Common::File();
if (!_fd->open(filename)) {
delete _fd;
- return;
+ return false;
}
uint32 chunkType, chunkSize;
@@ -51,14 +51,14 @@ void PmvPlayer::play(const char *filename) {
if (chunkType != MKID_BE('MOVE')) {
warning("Unexpected PMV video header, expected 'MOVE'");
delete _fd;
- return;
+ return false;
}
readChunk(chunkType, chunkSize); // "MHED"
if (chunkType != MKID_BE('MHED')) {
warning("Unexpected PMV video header, expected 'MHED'");
delete _fd;
- return;
+ return false;
}
uint frameDelay = _fd->readUint16LE();
@@ -108,7 +108,7 @@ void PmvPlayer::play(const char *filename) {
// get it to work well?
_audioStream = Audio::makeAppendableAudioStream(soundFreq, Audio::Mixer::FLAG_UNSIGNED);
- while (!_vm->shouldQuit() && !_abort && !_fd->eos()) {
+ while (!_vm->shouldQuit() && !_aborted && !_fd->eos()) {
int32 frameTime = _vm->_system->getMillis();
@@ -208,6 +208,8 @@ void PmvPlayer::play(const char *filename) {
delete _fd;
delete _surface;
+ return !_aborted;
+
}
void PmvPlayer::readChunk(uint32 &chunkType, uint32 &chunkSize) {
@@ -227,7 +229,7 @@ void PmvPlayer::handleEvents() {
switch (event.type) {
case Common::EVENT_KEYDOWN:
if (event.kbd.keycode == Common::KEYCODE_ESCAPE)
- _abort = true;
+ _aborted = true;
break;
default:
break;
diff --git a/engines/made/pmvplayer.h b/engines/made/pmvplayer.h
index 35712f1932..e20aff12e1 100644
--- a/engines/made/pmvplayer.h
+++ b/engines/made/pmvplayer.h
@@ -44,7 +44,8 @@ class PmvPlayer {
public:
PmvPlayer(MadeEngine *vm, Audio::Mixer *mixer);
~PmvPlayer();
- void play(const char *filename);
+ // Returns true if the movie was played till the end
+ bool play(const char *filename);
protected:
MadeEngine *_vm;
Audio::Mixer *_mixer;
@@ -53,7 +54,7 @@ protected:
Audio::SoundHandle _audioStreamHandle;
byte _paletteRGB[768];
Graphics::Surface *_surface;
- bool _abort;
+ bool _aborted;
void readChunk(uint32 &chunkType, uint32 &chunkSize);
void handleEvents();
void updateScreen();
diff --git a/engines/made/resource.cpp b/engines/made/resource.cpp
index 3086e71edd..d2f5bc9a07 100644
--- a/engines/made/resource.cpp
+++ b/engines/made/resource.cpp
@@ -55,7 +55,16 @@ PictureResource::~PictureResource() {
}
void PictureResource::load(byte *source, int size) {
+ if (READ_BE_UINT32(source) == MKID_BE('Flex')) {
+ loadChunked(source, size);
+ } else {
+ loadRaw(source, size);
+ }
+}
+void PictureResource::loadRaw(byte *source, int size) {
+ // Loads a "raw" picture as used in RtZ, LGoP2, Manhole:N&E and Rodney's Funscreen
+
Common::MemoryReadStream *sourceS = new Common::MemoryReadStream(source, size);
_hasPalette = (sourceS->readByte() != 0);
@@ -71,7 +80,7 @@ void PictureResource::load(byte *source, int size) {
uint16 height = sourceS->readUint16LE();
if (cmdFlags || pixelFlags || maskFlags) {
- warning("PictureResource::load() Graphic has flags set");
+ warning("PictureResource::loadRaw() Graphic has flags set (%d, %d, %d)", cmdFlags, pixelFlags, maskFlags);
}
_paletteColorCount = (cmdOffs - 18) / 3; // 18 = sizeof header
@@ -92,6 +101,84 @@ void PictureResource::load(byte *source, int size) {
}
+void PictureResource::loadChunked(byte *source, int size) {
+ // Loads a "chunked" picture as used in Manhole EGA
+
+ Common::MemoryReadStream *sourceS = new Common::MemoryReadStream(source, size);
+
+ byte cmdFlags, pixelFlags, maskFlags;
+ uint16 cmdOffs = 0, pixelOffs = 0, maskOffs = 0;
+ uint16 lineSize = 0, width = 0, height = 0;
+
+ sourceS->skip(36); // skip the "Flex" header
+
+ _hasPalette = false;
+
+ int i = 0;
+
+ while (!sourceS->eos()) {
+
+ uint32 chunkType = sourceS->readUint32BE();
+ uint32 chunkSize = sourceS->readUint32BE();
+
+ if (sourceS->eos())
+ break;
+
+ debug(0, "chunkType = %08X; chunkSize = %d", chunkType, chunkSize);
+
+ if (chunkType == MKID_BE('Rect')) {
+ debug(0, "Rect");
+ sourceS->skip(4);
+ height = sourceS->readUint16BE();
+ width = sourceS->readUint16BE();
+ debug(0, "width = %d; height = %d", width, height);
+ } else if (chunkType == MKID_BE('fMap')) {
+ debug(0, "fMap");
+ lineSize = sourceS->readUint16BE();
+ sourceS->skip(11);
+ cmdFlags = sourceS->readByte();
+ cmdOffs = sourceS->pos();
+ sourceS->skip(chunkSize - 14);
+ debug(0, "lineSize = %d; cmdFlags = %d; cmdOffs = %04X", lineSize, cmdFlags, cmdOffs);
+ } else if (chunkType == MKID_BE('fLCo')) {
+ debug(0, "fLCo");
+ sourceS->skip(9);
+ pixelFlags = sourceS->readByte();
+ pixelOffs = sourceS->pos();
+ sourceS->skip(chunkSize - 10);
+ debug(0, "pixelFlags = %d; pixelOffs = %04X", pixelFlags, pixelOffs);
+ } else if (chunkType == MKID_BE('fPix')) {
+ debug(0, "fPix");
+ sourceS->skip(9);
+ maskFlags = sourceS->readByte();
+ maskOffs = sourceS->pos();
+ sourceS->skip(chunkSize - 10);
+ debug(0, "maskFlags = %d; maskOffs = %04X", maskFlags, maskOffs);
+ } else if (chunkType == MKID_BE('fGCo')) {
+ debug(0, "fGCo");
+ _hasPalette = true;
+ _paletteColorCount = chunkSize / 3;
+ _picturePalette = new byte[_paletteColorCount * 3];
+ sourceS->read(_picturePalette, _paletteColorCount * 3);
+ } else {
+ error("PictureResource::loadChunked() Invalid chunk %08X at %08X", chunkType, sourceS->pos());
+ }
+
+ }
+
+ if (!cmdOffs || !pixelOffs /*|| !maskOffs*/ || !lineSize || !width || !height) {
+ error("PictureResource::loadChunked() Error parsing the picture data, one or more chunks/parameters are missing");
+ }
+
+ _picture = new Graphics::Surface();
+ _picture->create(width, height, 1);
+
+ decompressImage(source, *_picture, cmdOffs, pixelOffs, maskOffs, lineSize, cmdFlags, pixelFlags, maskFlags);
+
+ delete sourceS;
+
+}
+
/* AnimationResource */
AnimationResource::AnimationResource() {
@@ -182,9 +269,14 @@ Audio::AudioStream *SoundResource::getAudioStream(int soundRate, bool loop) {
void SoundResourceV1::load(byte *source, int size) {
// TODO: This is all wrong. Seems like the sound is compressed
// but where is the compression info? (chunks, chunk size)
+
_soundSize = size;
_soundData = new byte[_soundSize];
- memcpy(_soundData, source, _soundSize);
+
+ // TODO: We set the audio to silent for now
+ //memcpy(_soundData, source, _soundSize);
+ memset(_soundData, 0x80, _soundSize);
+
}
/* MenuResource */
@@ -364,6 +456,9 @@ void ResourceReader::openResourceBlock(const char *filename, Common::File *block
_resSlots[resType] = new ResourceSlots();
+ // Add dummy entry since the resources are 1-based
+ _resSlots[resType]->push_back(ResourceSlot(0, 0));
+
for (uint16 i = 0; i < count; i++) {
uint32 offset = blockFile->readUint32LE();
blockFile->readUint32LE();
diff --git a/engines/made/resource.h b/engines/made/resource.h
index a57c9d5cc9..a291268e60 100644
--- a/engines/made/resource.h
+++ b/engines/made/resource.h
@@ -75,6 +75,8 @@ protected:
byte *_picturePalette;
int _paletteColorCount;
bool _hasPalette;
+ void loadRaw(byte *source, int size);
+ void loadChunked(byte *source, int size);
};
class AnimationResource : public Resource {
diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp
index e3e56381e6..dfcda3f95b 100644
--- a/engines/made/screen.cpp
+++ b/engines/made/screen.cpp
@@ -447,7 +447,6 @@ uint16 Screen::placeSprite(uint16 channelIndex, uint16 flexIndex, int16 x, int16
y1 = y;
x2 = x + surf->w + 1;
y2 = y + surf->h + 1;
- //TODO: clipRect(x1, y1, x2, y2);
if (_ground == 0)
state |= 2;
@@ -498,7 +497,6 @@ uint16 Screen::placeAnim(uint16 channelIndex, uint16 animIndex, int16 x, int16 y
y1 = y;
x2 = x + anim->getWidth();
y2 = y + anim->getHeight();
- //TODO: clipRect(x1, y1, x2, y2);
if (anim->getFlags() == 1 || _ground == 0)
state |= 2;
@@ -576,7 +574,6 @@ uint16 Screen::placeText(uint16 channelIndex, uint16 textObjectIndex, int16 x, i
y1 = y;
x2 = x + textWidth;
y2 = y + textHeight;
- //TODO: clipRect(x1, y1, x2, y2);
if (textWidth > 0 && outlineColor != -1) {
x++;
@@ -610,8 +607,6 @@ uint16 Screen::placeText(uint16 channelIndex, uint16 textObjectIndex, int16 x, i
void Screen::show() {
- // TODO
-
if (_screenLock)
return;
diff --git a/engines/made/scriptfuncs.cpp b/engines/made/scriptfuncs.cpp
index 3f9d757cc4..01ddcfcc04 100644
--- a/engines/made/scriptfuncs.cpp
+++ b/engines/made/scriptfuncs.cpp
@@ -263,7 +263,6 @@ int16 ScriptFunctions::sfPlayMusic(int16 argc, int16 *argv) {
// FIXME: Remove this hack and handle this file properly
if (_vm->getGameID() == GID_LGOP2 && musicNum == 2)
return 0;
-
if (musicNum > 0) {
_musicRes = _vm->_res->getMidi(musicNum);
if (_musicRes)
@@ -292,7 +291,6 @@ int16 ScriptFunctions::sfIsMusicPlaying(int16 argc, int16 *argv) {
int16 ScriptFunctions::sfSetTextPos(int16 argc, int16 *argv) {
// Used in Manhole:NE
- //warning("Unimplemented opcode: sfSetTextPos");
// This seems to be some kind of low-level opcode.
// The original engine calls int 10h to set the VGA cursor position.
// Since this seems to be used for debugging purposes only it's left out.
@@ -305,25 +303,25 @@ int16 ScriptFunctions::sfFlashScreen(int16 argc, int16 *argv) {
}
int16 ScriptFunctions::sfPlayNote(int16 argc, int16 *argv) {
- // TODO: Used in Manhole:NE
+ // TODO: Used in Manhole:NE, Manhole EGA
warning("Unimplemented opcode: sfPlayNote");
return 0;
}
int16 ScriptFunctions::sfStopNote(int16 argc, int16 *argv) {
- // TODO: Used in Manhole:NE
+ // TODO: Used in Manhole:NE, Manhole EGA
warning("Unimplemented opcode: sfStopNote");
return 0;
}
int16 ScriptFunctions::sfPlayTele(int16 argc, int16 *argv) {
- // TODO: Used in Manhole:NE
+ // TODO: Used in Manhole:NE, Manhole EGA
warning("Unimplemented opcode: sfPlayTele");
return 0;
}
int16 ScriptFunctions::sfStopTele(int16 argc, int16 *argv) {
- // TODO: Used in Manhole:NE
+ // TODO: Used in Manhole:NE, Manhole EGA
warning("Unimplemented opcode: sfStopTele");
return 0;
}
@@ -618,21 +616,19 @@ int16 ScriptFunctions::sfClearMono(int16 argc, int16 *argv) {
int16 ScriptFunctions::sfGetSoundEnergy(int16 argc, int16 *argv) {
// This is called while in-game voices are played to animate
// mouths when NPCs are talking
-
int result = 0;
-
- if (_vm->_mixer->isSoundHandleActive(_audioStreamHandle) && _vm->_soundEnergyArray &&
- _vm->_soundEnergyIndex < _vm->_soundEnergyArray->size()) {
-
- uint32 position = (_vm->_soundRate / 1000) * _vm->_mixer->getSoundElapsedTime(_audioStreamHandle);
- SoundEnergyItem *soundEnergyItem = &_vm->_soundEnergyArray->operator[](_vm->_soundEnergyIndex);
-
- result = soundEnergyItem->energy;
-
- if (position >= soundEnergyItem->position)
+ if (_vm->_mixer->isSoundHandleActive(_audioStreamHandle) && _vm->_soundEnergyArray) {
+ while (_vm->_soundEnergyIndex < _vm->_soundEnergyArray->size()) {
+ SoundEnergyItem *soundEnergyItem = &_vm->_soundEnergyArray->operator[](_vm->_soundEnergyIndex);
+ if (((_vm->_soundRate / 1000) * _vm->_mixer->getSoundElapsedTime(_audioStreamHandle)) < soundEnergyItem->position) {
+ result = soundEnergyItem->energy;
+ break;
+ }
_vm->_soundEnergyIndex++;
+ }
+ if (_vm->_soundEnergyIndex >= _vm->_soundEnergyArray->size())
+ result = 0;
}
-
return result;
}
@@ -660,9 +656,10 @@ int16 ScriptFunctions::sfGetTextWidth(int16 argc, int16 *argv) {
int16 ScriptFunctions::sfPlayMovie(int16 argc, int16 *argv) {
const char *movieName = _vm->_dat->getObjectString(argv[1]);
_vm->_system->showMouse(false);
- _vm->_pmvPlayer->play(movieName);
+ bool completed = _vm->_pmvPlayer->play(movieName);
_vm->_system->showMouse(true);
- return 0;
+ // Return true/false according to if the movie was canceled or not
+ return completed ? -1 : 0;
}
int16 ScriptFunctions::sfLoadSound(int16 argc, int16 *argv) {
diff --git a/engines/made/sound.cpp b/engines/made/sound.cpp
index 2ad1d98254..9c59232dd2 100644
--- a/engines/made/sound.cpp
+++ b/engines/made/sound.cpp
@@ -70,6 +70,8 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
workSample = prevSample;
+ soundEnergyItem.position += chunkSize;
+
switch (type) {
case 0:
@@ -77,10 +79,6 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
workSample = 0;
soundEnergyItem.energy = 0;
- // FIXME: I believe that this should be added in a different manner than the
- // rest of the values. 0 means "mouth shut", but it seems to be occuring too
- // often. Removing this bit makes the mouth of the lighthouse keeper move
- // without going too much off-sync. If I'm wrong here, please remove this.
if (soundEnergyArray)
soundEnergyArray->push_back(soundEnergyItem);
@@ -121,7 +119,7 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
soundBuffer[i] = *source++;
workSample = soundBuffer[workChunkSize - 1] - 128;
- soundEnergyItem.energy = type - 1;
+ soundEnergyItem.energy = 4;
if (soundEnergyArray)
soundEnergyArray->push_back(soundEnergyItem);
@@ -155,7 +153,6 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
prevSample = workSample;
memcpy(dest, soundBuffer, chunkSize);
dest += chunkSize;
- soundEnergyItem.position += chunkSize;
}