diff options
author | Benjamin Haisch | 2009-01-22 13:04:29 +0000 |
---|---|---|
committer | Benjamin Haisch | 2009-01-22 13:04:29 +0000 |
commit | 5b8105afb3a345cfd66efa795726329f509572c3 (patch) | |
tree | 4ff90316c9dee6be8bda8a0c3f8413ab5d8178a5 /engines/made | |
parent | d5d7175691ea3cde7aa941886e3197763c1398c6 (diff) | |
download | scummvm-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/made')
-rw-r--r-- | engines/made/database.cpp | 94 | ||||
-rw-r--r-- | engines/made/database.h | 5 | ||||
-rw-r--r-- | engines/made/detection.cpp | 2 | ||||
-rw-r--r-- | engines/made/graphics.cpp | 33 | ||||
-rw-r--r-- | engines/made/graphics.h | 3 | ||||
-rw-r--r-- | engines/made/pmvplayer.cpp | 16 | ||||
-rw-r--r-- | engines/made/pmvplayer.h | 5 | ||||
-rw-r--r-- | engines/made/resource.cpp | 99 | ||||
-rw-r--r-- | engines/made/resource.h | 2 | ||||
-rw-r--r-- | engines/made/screen.cpp | 5 | ||||
-rw-r--r-- | engines/made/scriptfuncs.cpp | 37 | ||||
-rw-r--r-- | engines/made/sound.cpp | 9 |
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; } |